summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--Makefile.builds.in164
-rw-r--r--NEWS10
-rw-r--r--configure.ac8
-rw-r--r--contrib/theoryskel/theory_DIR.cpp3
-rwxr-xr-xcontrib/update-copyright.pl25
-rw-r--r--doc/SmtEngine.3cvc_template.in4
-rw-r--r--doc/options.3cvc_template.in4
-rw-r--r--examples/sets-translate/sets_translate.cpp2
-rw-r--r--library_versions1
-rwxr-xr-xproofs/signatures/ex_bv.plf57
-rwxr-xr-xproofs/signatures/smt.plf3
-rwxr-xr-xproofs/signatures/th_bv.plf145
-rw-r--r--src/Makefile.am7
-rw-r--r--src/bindings/Makefile.am32
-rw-r--r--src/bindings/compat/c/Makefile.am4
-rw-r--r--src/bindings/compat/java/Makefile.am4
-rw-r--r--src/compat/Makefile.am4
-rw-r--r--src/compat/cvc3_compat.cpp7
-rw-r--r--src/decision/decision_engine.cpp10
-rw-r--r--src/decision/decision_engine.h10
-rw-r--r--src/decision/decision_strategy.h4
-rw-r--r--src/decision/justification_heuristic.cpp34
-rw-r--r--src/decision/justification_heuristic.h8
-rw-r--r--src/expr/attribute.cpp37
-rw-r--r--src/expr/attribute.h173
-rw-r--r--src/expr/command.cpp120
-rw-r--r--src/expr/command.h45
-rw-r--r--src/expr/expr_manager_template.cpp16
-rw-r--r--src/expr/expr_manager_template.h13
-rw-r--r--src/expr/expr_template.cpp21
-rw-r--r--src/expr/expr_template.h2
-rw-r--r--src/expr/node.h2
-rw-r--r--src/expr/node_manager.cpp24
-rw-r--r--src/expr/node_manager.h10
-rw-r--r--src/expr/options6
-rw-r--r--src/expr/symbol_table.cpp7
-rw-r--r--src/expr/symbol_table.h3
-rw-r--r--src/main/command_executor.cpp33
-rw-r--r--src/main/command_executor_portfolio.cpp16
-rw-r--r--src/main/driver_unified.cpp30
-rw-r--r--src/main/interactive_shell.cpp6
-rw-r--r--src/main/main.cpp3
-rw-r--r--src/main/options4
-rwxr-xr-xsrc/options/mkoptions4
-rw-r--r--src/options/options.h2
-rw-r--r--src/options/options_template.cpp24
-rw-r--r--src/parser/Makefile.am2
-rw-r--r--src/parser/antlr_input.cpp5
-rw-r--r--src/parser/cvc/Cvc.g56
-rw-r--r--src/parser/options3
-rw-r--r--src/parser/parser.cpp17
-rw-r--r--src/parser/parser.h14
-rw-r--r--src/parser/parser_builder.cpp3
-rw-r--r--src/parser/smt2/Smt2.g434
-rw-r--r--src/parser/smt2/smt2.cpp19
-rw-r--r--src/parser/smt2/smt2.h50
-rw-r--r--src/parser/smt2/smt2_input.cpp12
-rw-r--r--src/parser/smt2/smt2_input.h11
-rw-r--r--src/printer/ast/ast_printer.cpp10
-rw-r--r--src/printer/cvc/cvc_printer.cpp22
-rw-r--r--src/printer/printer.cpp18
-rw-r--r--src/printer/printer.h9
-rw-r--r--src/printer/smt1/smt1_printer.cpp10
-rw-r--r--src/printer/smt2/smt2_printer.cpp120
-rw-r--r--src/printer/smt2/smt2_printer.h6
-rw-r--r--src/printer/tptp/tptp_printer.cpp10
-rw-r--r--src/proof/cnf_proof.cpp128
-rw-r--r--src/proof/cnf_proof.h40
-rw-r--r--src/proof/proof.h6
-rw-r--r--src/proof/proof_manager.cpp119
-rw-r--r--src/proof/proof_manager.h63
-rw-r--r--src/proof/sat_proof.cpp77
-rw-r--r--src/proof/sat_proof.h16
-rw-r--r--src/prop/bvminisat/bvminisat.cpp9
-rw-r--r--src/prop/bvminisat/bvminisat.h6
-rw-r--r--src/prop/cnf_stream.cpp28
-rw-r--r--src/prop/cnf_stream.h28
-rw-r--r--src/prop/minisat/core/Solver.cc40
-rw-r--r--src/prop/minisat/core/Solver.h46
-rw-r--r--src/prop/minisat/minisat.cpp14
-rw-r--r--src/prop/minisat/minisat.h3
-rw-r--r--src/prop/minisat/simp/SimpSolver.cc8
-rw-r--r--src/prop/minisat/simp/SimpSolver.h26
-rw-r--r--src/prop/prop_engine.cpp24
-rw-r--r--src/prop/prop_engine.h3
-rw-r--r--src/prop/sat_solver.h9
-rw-r--r--src/prop/theory_proxy.cpp2
-rw-r--r--src/smt/boolean_terms.cpp1
-rw-r--r--src/smt/options20
-rw-r--r--src/smt/options_handlers.h17
-rw-r--r--src/smt/simplification_mode.cpp3
-rw-r--r--src/smt/simplification_mode.h2
-rw-r--r--src/smt/smt_engine.cpp774
-rw-r--r--src/smt/smt_engine.h63
-rw-r--r--src/smt/smt_engine_scope.h7
-rw-r--r--src/theory/arith/theory_arith_private.cpp2
-rw-r--r--src/theory/arrays/array_info.cpp24
-rw-r--r--src/theory/arrays/array_info.h6
-rw-r--r--src/theory/arrays/options11
-rw-r--r--src/theory/arrays/theory_arrays.cpp378
-rw-r--r--src/theory/arrays/theory_arrays.h37
-rw-r--r--src/theory/booleans/circuit_propagator.h2
-rw-r--r--src/theory/booleans/theory_bool_type_rules.h20
-rw-r--r--src/theory/builtin/kinds4
-rw-r--r--src/theory/builtin/theory_builtin_type_rules.h21
-rw-r--r--src/theory/bv/aig_bitblaster.cpp2
-rw-r--r--src/theory/bv/bitblaster_template.h83
-rw-r--r--src/theory/bv/bv_quick_check.cpp3
-rw-r--r--src/theory/bv/bv_subtheory_bitblast.cpp78
-rw-r--r--src/theory/bv/bv_subtheory_bitblast.h2
-rw-r--r--src/theory/bv/eager_bitblaster.cpp31
-rw-r--r--src/theory/bv/lazy_bitblaster.cpp108
-rw-r--r--src/theory/bv/theory_bv.cpp7
-rw-r--r--src/theory/bv/theory_bv.h3
-rw-r--r--src/theory/bv/theory_bv_rewrite_rules.h7
-rw-r--r--src/theory/bv/theory_bv_rewrite_rules_normalization.h45
-rw-r--r--src/theory/bv/theory_bv_rewriter.cpp4
-rw-r--r--src/theory/datatypes/datatypes_rewriter.h51
-rw-r--r--src/theory/datatypes/kinds10
-rw-r--r--src/theory/datatypes/options4
-rw-r--r--src/theory/datatypes/theory_datatypes.cpp483
-rw-r--r--src/theory/datatypes/theory_datatypes.h12
-rw-r--r--src/theory/datatypes/theory_datatypes_type_rules.h58
-rw-r--r--src/theory/datatypes/type_enumerator.h288
-rw-r--r--src/theory/idl/theory_idl.cpp4
-rw-r--r--src/theory/quantifiers/ambqi_builder.cpp2
-rw-r--r--src/theory/quantifiers/bounded_integers.cpp42
-rw-r--r--src/theory/quantifiers/bounded_integers.h10
-rw-r--r--src/theory/quantifiers/candidate_generator.cpp8
-rw-r--r--src/theory/quantifiers/candidate_generator.h4
-rw-r--r--src/theory/quantifiers/ce_guided_instantiation.cpp370
-rw-r--r--src/theory/quantifiers/ce_guided_instantiation.h117
-rwxr-xr-xsrc/theory/quantifiers/conjecture_generator.cpp2168
-rwxr-xr-xsrc/theory/quantifiers/conjecture_generator.h434
-rw-r--r--src/theory/quantifiers/first_order_model.cpp44
-rw-r--r--src/theory/quantifiers/first_order_model.h15
-rw-r--r--src/theory/quantifiers/first_order_reasoning.cpp1
-rw-r--r--src/theory/quantifiers/full_model_check.cpp12
-rw-r--r--src/theory/quantifiers/fun_def_process.cpp197
-rw-r--r--src/theory/quantifiers/fun_def_process.h54
-rw-r--r--src/theory/quantifiers/inst_gen.cpp6
-rw-r--r--src/theory/quantifiers/inst_match_generator.cpp181
-rw-r--r--src/theory/quantifiers/inst_match_generator.h47
-rw-r--r--src/theory/quantifiers/inst_strategy_cbqi.cpp44
-rw-r--r--src/theory/quantifiers/inst_strategy_cbqi.h23
-rw-r--r--src/theory/quantifiers/inst_strategy_e_matching.cpp146
-rw-r--r--src/theory/quantifiers/inst_strategy_e_matching.h26
-rw-r--r--src/theory/quantifiers/instantiation_engine.cpp91
-rw-r--r--src/theory/quantifiers/instantiation_engine.h4
-rw-r--r--src/theory/quantifiers/kinds4
-rw-r--r--src/theory/quantifiers/macros.cpp5
-rw-r--r--src/theory/quantifiers/model_builder.cpp9
-rw-r--r--src/theory/quantifiers/model_builder.h2
-rw-r--r--src/theory/quantifiers/model_engine.cpp204
-rw-r--r--src/theory/quantifiers/model_engine.h9
-rw-r--r--src/theory/quantifiers/modes.h36
-rw-r--r--src/theory/quantifiers/options54
-rw-r--r--src/theory/quantifiers/options_handlers.h108
-rw-r--r--src/theory/quantifiers/qinterval_builder.cpp2
-rwxr-xr-x[-rw-r--r--]src/theory/quantifiers/quant_conflict_find.cpp4753
-rwxr-xr-x[-rw-r--r--]src/theory/quantifiers/quant_conflict_find.h550
-rw-r--r--src/theory/quantifiers/quantifiers_attributes.cpp54
-rw-r--r--src/theory/quantifiers/quantifiers_attributes.h10
-rw-r--r--src/theory/quantifiers/quantifiers_rewriter.cpp54
-rw-r--r--src/theory/quantifiers/rewrite_engine.cpp13
-rw-r--r--src/theory/quantifiers/rewrite_engine.h3
-rw-r--r--src/theory/quantifiers/term_database.cpp564
-rw-r--r--src/theory/quantifiers/term_database.h116
-rw-r--r--src/theory/quantifiers/theory_quantifiers.cpp13
-rw-r--r--src/theory/quantifiers/theory_quantifiers.h2
-rw-r--r--src/theory/quantifiers/theory_quantifiers_type_rules.h18
-rw-r--r--src/theory/quantifiers/trigger.cpp228
-rw-r--r--src/theory/quantifiers/trigger.h16
-rw-r--r--src/theory/quantifiers_engine.cpp379
-rw-r--r--src/theory/quantifiers_engine.h79
-rw-r--r--src/theory/rep_set.cpp12
-rw-r--r--src/theory/rep_set.h2
-rw-r--r--src/theory/sets/normal_form.h52
-rw-r--r--src/theory/sets/options6
-rw-r--r--src/theory/sets/scrutinize.h4
-rw-r--r--src/theory/sets/theory_sets.cpp11
-rw-r--r--src/theory/sets/theory_sets.h4
-rw-r--r--src/theory/sets/theory_sets_private.cpp278
-rw-r--r--src/theory/sets/theory_sets_private.h23
-rw-r--r--src/theory/sets/theory_sets_rewriter.cpp22
-rw-r--r--src/theory/sets/theory_sets_type_enumerator.h21
-rw-r--r--src/theory/sets/theory_sets_type_rules.h2
-rw-r--r--src/theory/strings/kinds5
-rw-r--r--src/theory/strings/regexp_operation.cpp240
-rw-r--r--src/theory/strings/regexp_operation.h7
-rw-r--r--src/theory/strings/theory_strings.cpp17
-rw-r--r--src/theory/strings/theory_strings.h3
-rw-r--r--src/theory/strings/theory_strings_preprocess.cpp2
-rw-r--r--src/theory/strings/theory_strings_rewriter.cpp43
-rw-r--r--src/theory/strings/theory_strings_rewriter.h1
-rw-r--r--src/theory/strings/theory_strings_type_rules.h15
-rw-r--r--src/theory/theory.h4
-rw-r--r--src/theory/theory_engine.cpp69
-rw-r--r--src/theory/theory_engine.h7
-rw-r--r--src/theory/theory_model.cpp71
-rw-r--r--src/theory/theory_model.h1
-rw-r--r--src/theory/uf/options4
-rw-r--r--src/theory/uf/options_handlers.h41
-rw-r--r--src/theory/uf/theory_uf.cpp6
-rw-r--r--src/theory/uf/theory_uf_strong_solver.cpp46
-rw-r--r--src/theory/uf/theory_uf_strong_solver.h6
-rw-r--r--src/theory/uf/theory_uf_type_rules.h4
-rw-r--r--src/theory/valuation.cpp12
-rw-r--r--src/theory/valuation.h3
-rw-r--r--src/util/Makefile.am7
-rw-r--r--src/util/datatype.cpp8
-rw-r--r--src/util/ite_removal.cpp13
-rw-r--r--src/util/ite_removal.h5
-rw-r--r--src/util/language.cpp22
-rw-r--r--src/util/language.h28
-rw-r--r--src/util/language.i4
-rw-r--r--src/util/regexp.h57
-rw-r--r--src/util/sort_inference.cpp5
-rw-r--r--src/util/unsat_core.cpp49
-rw-r--r--src/util/unsat_core.h66
-rw-r--r--src/util/unsat_core.i51
-rw-r--r--test/regress/regress0/Makefile.am9
-rw-r--r--test/regress/regress0/arrays/Makefile.am15
-rw-r--r--test/regress/regress0/arrays/constarr.cvc7
-rw-r--r--test/regress/regress0/arrays/constarr.smt29
-rw-r--r--test/regress/regress0/arrays/constarr2.cvc7
-rw-r--r--test/regress/regress0/arrays/constarr2.smt210
-rw-r--r--test/regress/regress0/arrays/constarr3.cvc12
-rw-r--r--test/regress/regress0/arrays/constarr3.smt216
-rw-r--r--test/regress/regress0/arrays/parsing_ringer.cvc35
-rw-r--r--test/regress/regress0/bug421.smt22
-rw-r--r--test/regress/regress0/bug421b.smt22
-rw-r--r--test/regress/regress0/bug567.smt22
-rw-r--r--test/regress/regress0/bug590.smt261
-rw-r--r--test/regress/regress0/bug590.smt2.expect2
-rw-r--r--test/regress/regress0/crash_burn_locusts.smt229
-rw-r--r--test/regress/regress0/datatypes/Makefile.am3
-rw-r--r--test/regress/regress0/datatypes/tenum-bug.smt211
-rw-r--r--test/regress/regress0/fmf/Makefile.am6
-rw-r--r--test/regress/regress0/fmf/lst-no-self-rev-exp.smt235
-rw-r--r--test/regress/regress0/parser/Makefile.am4
-rw-r--r--test/regress/regress0/parser/strings20.smt215
-rw-r--r--test/regress/regress0/parser/strings25.smt215
-rw-r--r--test/regress/regress0/quantifiers/Makefile.am3
-rw-r--r--test/regress/regress0/quantifiers/macros-int-real.smt29
-rw-r--r--test/regress/regress0/simplification_bug3.cvc7
-rw-r--r--test/regress/regress0/strings/Makefile.am3
-rw-r--r--test/regress/regress0/strings/escchar.smt21
-rw-r--r--test/regress/regress0/strings/escchar_25.smt212
-rwxr-xr-xtest/regress/run_regression12
-rw-r--r--test/unit/context/stacking_map_black.h4
-rw-r--r--test/unit/context/stacking_vector_black.h4
-rw-r--r--test/unit/expr/attribute_black.h20
-rw-r--r--test/unit/expr/attribute_white.h41
-rw-r--r--test/unit/expr/node_black.h6
-rw-r--r--test/unit/expr/node_builder_black.h7
-rw-r--r--test/unit/expr/node_manager_black.h7
-rw-r--r--test/unit/expr/node_manager_white.h7
-rw-r--r--test/unit/expr/node_self_iterator_black.h7
-rw-r--r--test/unit/expr/node_white.h7
-rw-r--r--test/unit/prop/cnf_stream_white.h30
-rw-r--r--test/unit/theory/type_enumerator_white.h30
-rw-r--r--test/unit/util/boolean_simplification_black.h7
263 files changed, 12977 insertions, 5596 deletions
diff --git a/Makefile.builds.in b/Makefile.builds.in
index 296e5a974..265556f4d 100644
--- a/Makefile.builds.in
+++ b/Makefile.builds.in
@@ -6,14 +6,8 @@
#
# Its main purposes are to:
# 1. build the current build profile
-# 2. install into "builds/$(CURRENT_BUILD)/$(prefix)"
-# 3. set up "builds/$(CURRENT_BUILD)/{bin,lib}" symlinks
-# 4. install into "builds/$(prefix)"
-# 5. set up "builds/bin" and "builds/lib"
-#
-# Steps 2 and 4 require libtool-relinking for dynamically-linked
-# executables and libraries, since build/bin is not the final
-# installation path.
+# 2. set up builds/$(CURRENT_BUILD)/{bin,lib} symlinks
+# 3. set up builds/bin and builds/lib symlinks
# Include the "current" build profile.
include current
@@ -40,12 +34,6 @@ LIBTOOL = $(CURRENT_BUILD)/libtool
# Are we building the libcvc4compat library ?
CVC4_BUILD_LIBCOMPAT = @CVC4_BUILD_LIBCOMPAT@
-# Are we building static/dynamic libraries/binaries? One or the other can be
-# on, or both.
-BUILDING_STATIC = @BUILDING_STATIC@
-BUILDING_SHARED = @BUILDING_SHARED@
-STATIC_BINARY = @STATIC_BINARY@
-
# @
AM_V_at = $(am__v_at_$(V))
am__v_at_ = $(am__v_at_$(AM_DEFAULT_VERBOSITY))
@@ -61,21 +49,6 @@ AM_V_mkdir = $(am__v_mkdir_$(V))
am__v_mkdir_ = $(am__v_mkdir_$(AM_DEFAULT_VERBOSITY))
am__v_mkdir_0 = @$(am__v_mkdir_noat_0)
am__v_mkdir_1 = $(am__v_mkdir_noat_1)
-# libtool --mode=install $(install_sh)
-AM_V_ltinstall = $(am__v_ltinstall_$(V))
-am__v_ltinstall_ = $(am__v_ltinstall_$(AM_DEFAULT_VERBOSITY))
-am__v_ltinstall_0 = @$(SHELL) -c 'echo " LTINS $$1"; $(LIBTOOL) --silent --mode=install $(install_sh) "$$@"' bash
-am__v_ltinstall_1 = $(LIBTOOL) --mode=install $(install_sh)
-# install_sh (never prefix with @)
-AM_V_install_sh_noat = $(am__v_install_sh_noat_$(V))
-am__v_install_sh_noat_ = $(am__v_install_sh_noat_$(AM_DEFAULT_VERBOSITY))
-am__v_install_sh_noat_0 = $(SHELL) -c 'echo " INSTL $$1"; $(install_sh) "$$@"' bash
-am__v_install_sh_noat_1 = $(install_sh)
-# relinking
-AM_V_relink = $(am__v_relink_$(V))
-am__v_relink_ = $(am__v_relink_$(AM_DEFAULT_VERBOSITY))
-am__v_relink_0 = echo " RELNK"
-am__v_relink_1 = :
# all the binaries that might need to be installed
# (it's not a fatal error for one/some don't exist in a given build
@@ -87,108 +60,47 @@ _default_build_: all
all:
# build the current build profile
$(AM_V_at)(cd $(CURRENT_BUILD) && $(MAKE) $@)
-# set up builds/$(CURRENT_BUILD)/...prefix.../bin
-# and builds/$(CURRENT_BUILD)/...prefix.../lib
- $(AM_V_mkdir) "$(CURRENT_BUILD)$(bindir)"
- $(AM_V_mkdir) "$(CURRENT_BUILD)$(libdir)"
-# install libcvc4
- $(AM_V_ltinstall) $(CURRENT_BUILD)/src/libcvc4.la \
- "$(abs_builddir)$(libdir)"
-# install libcvc4parser
- $(AM_V_ltinstall) $(CURRENT_BUILD)/src/parser/libcvc4parser.la \
- "$(abs_builddir)$(libdir)"
+# set up builds/$(CURRENT_BUILD)/{bin,lib}
+ $(AM_V_mkdir) $(CURRENT_BUILD)/bin
+ $(AM_V_mkdir) $(CURRENT_BUILD)/lib
+# symlink libcvc4, libcvc4parser
+ $(AM_V_at)cd $(CURRENT_BUILD)/lib && \
+ ln -sf ../src/libcvc4.* \
+ ../src/parser/libcvc4parser.* \
+ .
+ -$(AM_V_at)cd $(CURRENT_BUILD)/lib && \
+ test -d ../src/.libs && \
+ ln -sf ../src/.libs/libcvc4.* \
+ .
+ -$(AM_V_at)cd $(CURRENT_BUILD)/lib && \
+ test -d ../src/parser/.libs && \
+ ln -sf ../src/parser/.libs/libcvc4parser.* \
+ .
ifeq ($(CVC4_BUILD_LIBCOMPAT),yes)
-# install libcvc4compat
- $(CURRENT_BUILD)/libtool --mode=install $(install_sh) \
- $(CURRENT_BUILD)/src/compat/libcvc4compat.la \
- "$(abs_builddir)$(libdir)"
+# symlink libcvc4compat
+ $(AM_V_at)cd $(CURRENT_BUILD)/lib && \
+ ln -sf ../src/compat/libcvc4compat.* \
+ .
+ -$(AM_V_at)cd $(CURRENT_BUILD)/lib && \
+ test -d ../src/compat/.libs && \
+ ln -sf ../src/compat/.libs/libcvc4compat.* \
+ .
endif
-ifeq ($(BUILDING_SHARED)$(STATIC_BINARY),10)
-# if we're building shared libs and the binary is not static, relink
-# the handling with empty $relink_command is a hack for Mac OS
- $(AM_V_at)thelibdir="$(abs_builddir)$(libdir)"; \
- progdir="$(abs_builddir)$(bindir)"; for file in $(CVC4_BINARIES); do \
- if test -r $(CURRENT_BUILD)/src/main/$$file; then \
- eval `grep '^relink_command=' $(CURRENT_BUILD)/src/main/$$file | sed 's:-Wl,-rpath:-Wl,-rpath -Wl,\\\\$$thelibdir -Wl,-rpath:'`; \
- if test -z "$$relink_command"; then \
- $(AM_V_mkdir_noat) "$(CURRENT_BUILD)$(bindir)/.libs"; \
- $(AM_V_install_sh_noat) \
- $(CURRENT_BUILD)/src/main/.libs/$$file \
- "$(abs_builddir)$(bindir)/.libs"; \
- $(AM_V_install_sh_noat) \
- $(CURRENT_BUILD)/src/main/$$file \
- "$(abs_builddir)$(bindir)"; \
- else \
- $(AM_V_relink) "$$file"; eval "(cd $(CURRENT_BUILD)/src/main && $$relink_command)"; \
- fi; \
- else \
- rm -f "$(abs_builddir)$(bindir)/$$file"; \
- fi; \
- done
-else
-# if we're building static libs only, just install the driver binary directly
- $(AM_V_at)for file in $(CVC4_BINARIES); do \
- if test -r $(CURRENT_BUILD)/src/main/$$file; then \
- $(AM_V_install_sh_noat) \
- $(CURRENT_BUILD)/src/main/$$file \
- "$(abs_builddir)$(bindir)"; \
+# symlink the binaries
+ $(AM_V_at)cd $(CURRENT_BUILD)/bin && \
+ for binary in $(CVC4_BINARIES); do \
+ if test -x ../src/main/$$binary; then \
+ ln -sf ../src/main/$$binary \
+ . ; \
else \
- rm -f "$(abs_builddir)$(bindir)/$$file"; \
+ rm -f "$$binary"; \
fi; \
done
-endif
-# set up builds/$(CURRENT_BUILD)/bin and builds/$(CURRENT_BUILD)/lib
- rm -f $(CURRENT_BUILD)/lib; ln -sf "$(abs_builddir)$(libdir)" $(CURRENT_BUILD)/lib
- rm -f $(CURRENT_BUILD)/bin; ln -sf "$(abs_builddir)$(bindir)" $(CURRENT_BUILD)/bin
-# set up builds/...prefix.../bin and builds/...prefix.../lib
- $(AM_V_mkdir) ".$(bindir)"
- $(AM_V_mkdir) ".$(libdir)"
-# install libcvc4
- $(AM_V_ltinstall) $(CURRENT_BUILD)/src/libcvc4.la "`pwd`$(libdir)"
-# install libcvc4parser
- $(AM_V_ltinstall) $(CURRENT_BUILD)/src/parser/libcvc4parser.la "`pwd`$(libdir)"
-ifeq ($(CVC4_BUILD_LIBCOMPAT),yes)
-# install libcvc4compat
- $(CURRENT_BUILD)/libtool --mode=install $(install_sh) $(CURRENT_BUILD)/src/compat/libcvc4compat.la "`pwd`$(libdir)"
-endif
-ifeq ($(BUILDING_SHARED)$(STATIC_BINARY),10)
-# if we're building shared libs and the binary is not static, relink
-# the handling with empty $relink_command is a hack for Mac OS
- $(AM_V_at)thelibdir="`pwd`$(libdir)"; progdir="`pwd`$(bindir)"; for file in $(CVC4_BINARIES); do \
- if test -r $(CURRENT_BUILD)/src/main/$$file; then \
- eval `grep '^relink_command=' $(CURRENT_BUILD)/src/main/$$file | sed 's:-Wl,-rpath:-Wl,-rpath -Wl,\\\\$$thelibdir -Wl,-rpath:'`; \
- if test -z "$$relink_command"; then \
- $(AM_V_mkdir_noat) ".$(bindir)/.libs"; \
- $(AM_V_install_sh_noat) \
- $(CURRENT_BUILD)/src/main/.libs/$$file \
- "`pwd`$(bindir)/.libs"; \
- $(AM_V_install_sh_noat) \
- $(CURRENT_BUILD)/src/main/$$file \
- "`pwd`$(bindir)"; \
- else \
- $(AM_V_relink) "$$file"; eval "(cd $(CURRENT_BUILD)/src/main && $$relink_command)"; \
- fi; \
- else \
- rm -f "`pwd`$(bindir)/$$file"; \
- fi; \
- done
-else
-# if we're building static libs only, just install the driver binary directly
- $(AM_V_at)for file in $(CVC4_BINARIES); do \
- if test -r $(CURRENT_BUILD)/src/main/$$file; then \
- $(AM_V_install_sh_noat) \
- $(CURRENT_BUILD)/src/main/$$file \
- "`pwd`$(bindir)"; \
- else \
- rm -f "`pwd`$(bindir)/$$file"; \
- fi; \
- done
-endif
-# set up builds/bin and builds/lib
- rm -f lib; ln -sf ".$(libdir)" lib
- rm -f bin; ln -sf ".$(bindir)" bin
- rm -f doc; ln -sf "$(CURRENT_BUILD)/doc" doc
- rm -f examples; ln -sf "$(CURRENT_BUILD)/examples" examples
+# set up builds/doc and builds/examples
+ $(AM_V_at)rm -f bin; ln -sf $(CURRENT_BUILD)/bin bin
+ $(AM_V_at)rm -f lib; ln -sf $(CURRENT_BUILD)/lib lib
+ $(AM_V_at)rm -f doc; ln -sf $(CURRENT_BUILD)/doc doc
+ $(AM_V_at)rm -f examples; ln -sf $(CURRENT_BUILD)/examples examples
# The descent into "src" with target "check" is to build check
# prerequisites (e.g. CHECK_PROGRAMS, CHECK_LTLIBRARIES, ...).
diff --git a/NEWS b/NEWS
index 4c0de2ce3..89ea1c265 100644
--- a/NEWS
+++ b/NEWS
@@ -3,6 +3,16 @@ This file contains a summary of important user-visible changes.
Changes since 1.4
=================
+* Support for unsat cores.
+* Simplification mode "incremental" no longer supported.
+* Support for array constants in constraints.
+* Syntax for array models have changed in some language front-ends.
+* New input/output languages supported: "smt2.0" and "smtlib2.0" to
+ force SMT-LIB v2.0; "smt2.5" and "smtlib2.5" to force SMT-LIB v2.5.
+ "smt", "smtlib", "smt2", and "smtlib2" all refer to the current standard
+ version 2.0. If an :smt-lib-version is set in the input, that overrides
+ the command line.
+* Abstract values in SMT-LIB models are now ascribed types (with "as").
* In SMT-LIB model output, real-sorted but integer-valued constants are
now printed in accordance with the standard (e.g. "1.0").
diff --git a/configure.ac b/configure.ac
index 1ae4dbe21..d83293079 100644
--- a/configure.ac
+++ b/configure.ac
@@ -2,8 +2,8 @@
# Process this file with autoconf to produce a configure script.
m4_define(_CVC4_MAJOR, 1) dnl version (major)
-m4_define(_CVC4_MINOR, 4) dnl version (minor)
-m4_define(_CVC4_RELEASE, 1) dnl version (alpha)
+m4_define(_CVC4_MINOR, 5) dnl version (minor)
+m4_define(_CVC4_RELEASE, 0) dnl version (alpha)
m4_define(_CVC4_EXTRAVERSION, [-prerelease]) dnl version (extra)
m4_define(_CVC4_RELEASE_STRING, _CVC4_MAJOR[.]_CVC4_MINOR[]m4_if(_CVC4_RELEASE,[0],,[.]_CVC4_RELEASE)_CVC4_EXTRAVERSION) dnl version string
@@ -126,6 +126,10 @@ if test -n "${enable_optimized+set}"; then
btargs="$btargs nooptimized"
fi
fi
+# --enable-staticbinary is an alias for --enable-static-binary
+if test -n "${enable_staticbinary+set}"; then
+ enable_static_binary="$enable_staticbinary"
+fi
if test -n "${enable_static_binary+set}"; then
if test "$enable_static_binary" = yes; then
btargs="$btargs staticbinary"
diff --git a/contrib/theoryskel/theory_DIR.cpp b/contrib/theoryskel/theory_DIR.cpp
index 72101a5a6..535a54fd7 100644
--- a/contrib/theoryskel/theory_DIR.cpp
+++ b/contrib/theoryskel/theory_DIR.cpp
@@ -16,6 +16,9 @@ Theory$camel::Theory$camel(context::Context* c,
}/* Theory$camel::Theory$camel() */
void Theory$camel::check(Effort level) {
+ if (done() && !fullEffort(level)) {
+ return;
+ }
while(!done()) {
// Get all the assertions
diff --git a/contrib/update-copyright.pl b/contrib/update-copyright.pl
index f3c4248ac..2a581698c 100755
--- a/contrib/update-copyright.pl
+++ b/contrib/update-copyright.pl
@@ -48,13 +48,6 @@ my $standard_template = <<EOF;
** information.\\endverbatim
EOF
-my $public_template = <<EOF;
- ** This file is part of the CVC4 project.
- ** Copyright (c) $years New York University and The University of Iowa
- ** See the file COPYING in the top-level source directory for licensing
- ** information.\\endverbatim
-EOF
-
## end config ##
use strict;
@@ -164,17 +157,25 @@ sub handleFile {
print $OUT " ** Original author: $author\n";
print $OUT " ** Major contributors: $major_contributors\n";
print $OUT " ** Minor contributors (to current version): $minor_contributors\n";
- print $OUT $standard_template;
- print $OUT " **\n";
+ my $comment_stub = "";
while(my $line = <$IN>) {
+ if($line =~ /\b[Cc]opyright\b/ && $line !~ /\bNew York University and The University of Iowa\b/) {
+ # someone else holds this copyright
+ print $OUT $line;
+ }
last if $line =~ /^ \*\*\s*$/;
if($line =~ /\*\//) {
- print $OUT " ** [[ Add lengthier description here ]]\n";
- print $OUT " ** \\todo document this file\n";
- print $OUT $line;
+ $comment_stub = " ** [[ Add lengthier description here ]]\n\
+ ** \\todo document this file\n\
+$line";
last;
}
}
+ print $OUT $standard_template;
+ print $OUT " **\n";
+ if($comment_stub) {
+ print $OUT $comment_stub;
+ }
} else {
my $line = $_;
print "adding\n";
diff --git a/doc/SmtEngine.3cvc_template.in b/doc/SmtEngine.3cvc_template.in
index 3a876fefc..d741fd33f 100644
--- a/doc/SmtEngine.3cvc_template.in
+++ b/doc/SmtEngine.3cvc_template.in
@@ -19,6 +19,8 @@ and
.I SmtEngine::getOption()
use the following option keys.
+.ad l
+
.RS
.TP 10
.I "COMMON OPTIONS"
@@ -28,6 +30,8 @@ ${remaining_manpage_smt_documentation}
.PD
.RE
+.ad b
+
.SH VERSION
This manual page refers to
.B CVC4
diff --git a/doc/options.3cvc_template.in b/doc/options.3cvc_template.in
index a0d6c1640..f92faf47f 100644
--- a/doc/options.3cvc_template.in
+++ b/doc/options.3cvc_template.in
@@ -7,6 +7,8 @@ options \- the options infrastructure
.SH AVAILABLE INTERNAL OPTIONS
+.ad l
+
.RS
.TP 10
.I "COMMON OPTIONS"
@@ -16,6 +18,8 @@ ${remaining_manpage_internals_documentation}
.PD
.RE
+.ad b
+
.SH VERSION
This manual page refers to
.B CVC4
diff --git a/examples/sets-translate/sets_translate.cpp b/examples/sets-translate/sets_translate.cpp
index d214b6ab8..fbec42829 100644
--- a/examples/sets-translate/sets_translate.cpp
+++ b/examples/sets-translate/sets_translate.cpp
@@ -159,7 +159,7 @@ class Mapper {
em->mkFunctionType( t_t, t ) );
if(!enableAxioms)
- sout << "(define-fun in" << elementTypeAsString << " "
+ sout << "(define-fun member" << elementTypeAsString << " "
<< " ( (x " << elementType << ")" << " (s " << name << "))"
<< " Bool"
<< " (select s x) )" << endl;
diff --git a/library_versions b/library_versions
index 13bdad78e..a487695d7 100644
--- a/library_versions
+++ b/library_versions
@@ -58,3 +58,4 @@
1\.4-prerelease libcvc4:2:0:0 libcvc4parser:2:0:0 libcvc4compat:2:0:0 libcvc4bindings:2:0:0
1\.4 libcvc4:3:0:0 libcvc4parser:3:0:0 libcvc4compat:3:0:0 libcvc4bindings:3:0:0
1\.4\.1-prerelease libcvc4:3:0:0 libcvc4parser:3:0:0 libcvc4compat:3:0:0 libcvc4bindings:3:0:0
+1\.5-prerelease libcvc4:3:0:0 libcvc4parser:3:0:0 libcvc4compat:3:0:0 libcvc4bindings:3:0:0
diff --git a/proofs/signatures/ex_bv.plf b/proofs/signatures/ex_bv.plf
new file mode 100755
index 000000000..02cadaeab
--- /dev/null
+++ b/proofs/signatures/ex_bv.plf
@@ -0,0 +1,57 @@
+; a = b ^ a = 00000 ^ b = 11111 is UNSAT
+
+(check
+(% a var_bv
+(% b var_bv
+(% f1 (th_holds (= BitVec (a_var_bv a) (a_var_bv b)))
+(% f2 (th_holds (= BitVec (a_var_bv a) (a_bv (bvc b0 (bvc b0 (bvc b0 (bvc b0 (bvc b0 bvn))))))))
+(% f3 (th_holds (= BitVec (a_var_bv b) (a_bv (bvc b1 (bvc b1 (bvc b1 (bvc b1 (bvc b1 bvn))))))))
+(: (holds cln)
+
+(decl_bv_atom_var 5 a (\ ba1
+(decl_bv_atom_var 5 b (\ ba2
+(decl_bv_atom_const _ (bvc b0 (bvc b0 (bvc b0 (bvc b0 (bvc b0 bvn))))) (\ c (\ ba3
+(decl_bv_atom_const _ (bvc b1 (bvc b1 (bvc b1 (bvc b1 (bvc b1 bvn))))) (\ d (\ ba4
+
+(decl_atom (bblast a 4) (\ v1 (\ a1
+(decl_atom (bblast b 4) (\ v2 (\ a2
+
+; bitblasting terms
+(th_let_pf _ (bv_bbl_var _ _ _ ba1) (\ bt1
+(th_let_pf _ (bv_bbl_var _ _ _ ba2) (\ bt2
+(th_let_pf _ (bv_bbl_const _ _ _ _ ba3) (\ bt3
+(th_let_pf _ (bv_bbl_const _ _ _ _ ba4) (\ bt4
+
+; bitblasting formulas
+(th_let_pf _ (bv_bbl_eq _ _ _ _ _ bt1 bt2) (\ bf1
+(th_let_pf _ (bv_bbl_eq _ _ _ _ _ bt1 bt3) (\ bf2
+(th_let_pf _ (bv_bbl_eq _ _ _ _ _ bt2 bt4) (\ bf3
+
+; CNFication
+; a.4 V ~b.4
+(satlem _ _
+(asf _ _ _ a1 (\ l1
+(ast _ _ _ a2 (\ l2
+(clausify_false
+ (contra _ (impl_elim _ _ l2 (iff_elim_2 _ _ (and_elim_1 _ _ (impl_elim _ _ f1 bf1)))) l1) ; notice at the intermost we impl_elim, which converts from atom to bit-blasting representation
+))))) (\ C2
+
+; ~a.4
+(satlem _ _
+(ast _ _ _ a1 (\ l1
+(clausify_false
+ (impl_elim _ _ l1 (iff_elim_1 _ _ (and_elim_1 _ _ (impl_elim _ _ f2 bf2))))
+))) (\ C3
+
+; b.4
+(satlem _ _
+(asf _ _ _ a2 (\ l2
+(clausify_false
+ (contra _ (impl_elim _ _ truth (iff_elim_2 _ _ (and_elim_1 _ _ (impl_elim _ _ f3 bf3)))) l2)
+))) (\ C6
+
+
+(satlem_simplify _ _ _
+(R _ _ (R _ _ C6 C2 v2) C3 v1) (\ x x))
+
+))))))))))))))))))))))))))))))))))))))))))) \ No newline at end of file
diff --git a/proofs/signatures/smt.plf b/proofs/signatures/smt.plf
index bbee2d49b..942e17df0 100755
--- a/proofs/signatures/smt.plf
+++ b/proofs/signatures/smt.plf
@@ -104,6 +104,9 @@
(! r2 (th_holds (not f))
(th_holds false)))))
+; truth
+(declare truth (th_holds true))
+
;; not not
(declare not_not_intro
diff --git a/proofs/signatures/th_bv.plf b/proofs/signatures/th_bv.plf
new file mode 100755
index 000000000..3fb9d1356
--- /dev/null
+++ b/proofs/signatures/th_bv.plf
@@ -0,0 +1,145 @@
+; "bitvec" is a term of type "sort"
+(declare BitVec sort)
+
+; bit type
+(declare bit type)
+(declare b0 bit)
+(declare b1 bit)
+
+; bit vector type
+(declare bv type)
+(declare bvn bv)
+(declare bvc (! b bit (! v bv bv)))
+; a bv constant term
+(declare a_bv (! v bv (term BitVec)))
+
+; calculate the length of a bitvector
+(program bv_len ((v bv)) mpz
+ (match v
+ (bvn 0)
+ ((bvc b v') (mp_add (bv_len v') 1))))
+
+; a bv variable
+(declare var_bv type)
+; a bv variable term
+(declare a_var_bv (! v var_bv (term BitVec)))
+
+
+; bit vector operators
+(define bvoper (! x (term BitVec)
+ (! y (term BitVec)
+ (term BitVec))))
+(declare bvand bvoper)
+(declare bvadd bvoper)
+;....
+
+; all bit-vector terms are mapped with "bv_atom" to:
+; - a simply-typed term of type "var_bv", which is necessary for bit-blasting
+; - a integer size
+(declare bv_atom (! x (term BitVec) (! y var_bv (! n mpz type))))
+
+(declare decl_bv_atom_var (! n mpz ; must be specified
+ (! x var_bv
+ (! p (! u (bv_atom (a_var_bv x) x n)
+ (holds cln))
+ (holds cln)))))
+
+(declare decl_bv_atom_const (! n mpz
+ (! v bv
+ (! s (^ (bv_len v) n)
+ (! p (! w var_bv
+ (! u (bv_atom (a_bv v) w n)
+ (holds cln)))
+ (holds cln))))))
+
+
+; other terms here?
+
+
+; bit blasted terms
+(declare bblt type)
+(declare bbltn bblt)
+(declare bbltc (! f formula (! v bblt bblt)))
+
+; (bblast_term x y) means term x corresponds to bit level interpretation y
+(declare bblast_term (! x (term BitVec) (! y bblt formula)))
+
+; a predicate to represent the n^th bit of a bitvector term
+(declare bblast (! x var_bv (! n mpz formula)))
+
+
+; bit blast constant
+(program bblast_const ((v bv) (n mpz)) bblt
+ (mp_ifneg n (match v (bvn bbltn)
+ (default (fail bblt)))
+ (match v ((bvc b v') (bbltc (match b (b0 false) (b1 true)) (bblast_const v' (mp_add n (~ 1)))))
+ (default (fail bblt)))))
+
+(declare bv_bbl_const (! n mpz
+ (! v bv
+ (! x var_bv
+ (! f bblt
+ (! u (bv_atom (a_bv v) x n)
+ (! c (^ (bblast_const v (mp_add n (~ 1))) f)
+ (th_holds (bblast_term (a_bv v) f)))))))))
+
+; bit blast variable
+(program bblast_var ((x var_bv) (n mpz)) bblt
+ (mp_ifneg n bbltn
+ (bbltc (bblast x n) (bblast_var x (mp_add n (~ 1))))))
+
+(declare bv_bbl_var (! n mpz
+ (! x var_bv
+ (! f bblt
+ (! u (bv_atom (a_var_bv x) x n)
+ (! c (^ (bblast_var x (mp_add n (~ 1))) f)
+ (th_holds (bblast_term (a_var_bv x) f))))))))
+
+; bit blast x = y
+; for x,y of size n, it will return a conjuction (x.{n-1} = y.{n-1} ^ ( ... ^ (x.0 = y.0 ^ true)))
+(program bblast_eq ((x bblt) (y bblt)) formula
+ (match x
+ (bbltn (match y (bbltn true) (default (fail formula))))
+ ((bbltc fx x') (match y
+ (bbltn (fail formula))
+ ((bbltc fy y') (and (iff fx fy) (bblast_eq x' y')))))))
+
+(declare bv_bbl_eq (! x (term BitVec)
+ (! y (term BitVec)
+ (! fx bblt
+ (! fy bblt
+ (! f formula
+ (! ux (th_holds (bblast_term x fx))
+ (! uy (th_holds (bblast_term y fy))
+ (! c (^ (bblast_eq fx fy) f)
+ (th_holds (impl (= BitVec x y) f)))))))))))
+
+
+; rewrite rule :
+; x + y = y + x
+(declare bvadd_symm (! x (term BitVec)
+ (! y (term BitVec)
+ (! x' var_bv
+ (! y' var_bv
+ (! n mpz
+ (! ux (bv_atom x x' n)
+ (! uy (bv_atom y y' n)
+ (th_holds (= BitVec (bvadd x y) (bvadd y x)))))))))))
+
+
+
+; necessary?
+(program calc_bvand ((a bv) (b bv)) bv
+ (match a
+ (bvn (match b (bvn bvn) (default (fail bv))))
+ ((bvc ba a') (match b
+ ((bvc bb b') (bvc (match ba (b0 b0) (b1 bb)) (calc_bvand a' b')))
+ (default (fail bv))))))
+
+; rewrite rule (w constants) :
+; a & b = c
+(declare bvand_const (! c bv
+ (! a bv
+ (! b bv
+ (! u (^ (calc_bvand a b) c)
+ (th_holds (= BitVec (bvand (a_bv a) (a_bv b)) (a_bv c)))))))) \ No newline at end of file
diff --git a/src/Makefile.am b/src/Makefile.am
index 805ed6cb7..a04b86bee 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -239,6 +239,7 @@ libcvc4_la_SOURCES = \
theory/datatypes/datatypes_rewriter.h \
theory/datatypes/theory_datatypes.cpp \
theory/sets/expr_patterns.h \
+ theory/sets/normal_form.h \
theory/sets/options_handlers.h \
theory/sets/scrutinize.h \
theory/sets/term_info.h \
@@ -327,6 +328,12 @@ libcvc4_la_SOURCES = \
theory/quantifiers/ambqi_builder.cpp \
theory/quantifiers/quant_conflict_find.h \
theory/quantifiers/quant_conflict_find.cpp \
+ theory/quantifiers/conjecture_generator.h \
+ theory/quantifiers/conjecture_generator.cpp \
+ theory/quantifiers/ce_guided_instantiation.h \
+ theory/quantifiers/ce_guided_instantiation.cpp \
+ theory/quantifiers/fun_def_process.h \
+ theory/quantifiers/fun_def_process.cpp \
theory/quantifiers/options_handlers.h \
theory/arith/theory_arith_type_rules.h \
theory/arith/type_enumerator.h \
diff --git a/src/bindings/Makefile.am b/src/bindings/Makefile.am
index 2214d9b88..e7548bbe1 100644
--- a/src/bindings/Makefile.am
+++ b/src/bindings/Makefile.am
@@ -63,8 +63,8 @@ java_libcvc4jni_la_LDFLAGS = \
-shrext $(CVC4_JAVA_MODULE_EXT) \
-version-info $(LIBCVC4BINDINGS_VERSION)
java_libcvc4jni_la_LIBADD = \
- -L@builddir@/.. -lcvc4 \
- -L@builddir@/../parser -lcvc4parser
+ @builddir@/../libcvc4.la \
+ @builddir@/../parser/libcvc4parser.la
endif
if CVC4_LANGUAGE_BINDING_CSHARP
csharplib_LTLIBRARIES += csharp/CVC4.la
@@ -72,8 +72,8 @@ csharp_CVC4_la_LDFLAGS = \
-module \
-version-info $(LIBCVC4BINDINGS_VERSION)
csharp_CVC4_la_LIBADD = \
- -L@builddir@/.. -lcvc4 \
- -L@builddir@/../parser -lcvc4parser
+ @builddir@/../libcvc4.la \
+ @builddir@/../parser/libcvc4parser.la
endif
if CVC4_LANGUAGE_BINDING_PERL
perllib_LTLIBRARIES += perl/CVC4.la
@@ -81,8 +81,8 @@ perl_CVC4_la_LDFLAGS = \
-module \
-version-info $(LIBCVC4BINDINGS_VERSION)
perl_CVC4_la_LIBADD = \
- -L@builddir@/.. -lcvc4 \
- -L@builddir@/../parser -lcvc4parser
+ @builddir@/../libcvc4.la \
+ @builddir@/../parser/libcvc4parser.la
perldata_DATA += perl/CVC4.pm
endif
if CVC4_LANGUAGE_BINDING_PHP
@@ -91,8 +91,8 @@ php_CVC4_la_LDFLAGS = \
-module \
-version-info $(LIBCVC4BINDINGS_VERSION)
php_CVC4_la_LIBADD = \
- -L@builddir@/.. -lcvc4 \
- -L@builddir@/../parser -lcvc4parser
+ @builddir@/../libcvc4.la \
+ @builddir@/../parser/libcvc4parser.la
phpdata_DATA += php/CVC4.php
endif
if CVC4_LANGUAGE_BINDING_PYTHON
@@ -102,8 +102,8 @@ python_CVC4_la_LDFLAGS = \
-module \
-version-info $(LIBCVC4BINDINGS_VERSION)
python_CVC4_la_LIBADD = \
- -L@builddir@/.. -lcvc4 \
- -L@builddir@/../parser -lcvc4parser
+ @builddir@/../libcvc4.la \
+ @builddir@/../parser/libcvc4parser.la
pythondata_DATA += python/CVC4.py
endif
if CVC4_LANGUAGE_BINDING_OCAML
@@ -117,8 +117,8 @@ ocaml_CVC4_la_LDFLAGS = \
-module \
-version-info $(LIBCVC4BINDINGS_VERSION)
ocaml_CVC4_la_LIBADD = \
- -L@builddir@/.. -lcvc4 \
- -L@builddir@/../parser -lcvc4parser
+ @builddir@/../libcvc4.la \
+ @builddir@/../parser/libcvc4parser.la
endif
if CVC4_LANGUAGE_BINDING_RUBY
rubylib_LTLIBRARIES += ruby/CVC4.la
@@ -126,8 +126,8 @@ ruby_CVC4_la_LDFLAGS = \
-module \
-version-info $(LIBCVC4BINDINGS_VERSION)
ruby_CVC4_la_LIBADD = \
- -L@builddir@/.. -lcvc4 \
- -L@builddir@/../parser -lcvc4parser
+ @builddir@/../libcvc4.la \
+ @builddir@/../parser/libcvc4parser.la
endif
if CVC4_LANGUAGE_BINDING_TCL
tcllib_LTLIBRARIES += tcl/CVC4.la
@@ -135,8 +135,8 @@ tcl_CVC4_la_LDFLAGS = \
-module \
-version-info $(LIBCVC4BINDINGS_VERSION)
tcl_CVC4_la_LIBADD = \
- -L@builddir@/.. -lcvc4 \
- -L@builddir@/../parser -lcvc4parser
+ @builddir@/../libcvc4.la \
+ @builddir@/../parser/libcvc4parser.la
endif
# this endif matches the "if CVC4_HAS_SWIG" above
endif
diff --git a/src/bindings/compat/c/Makefile.am b/src/bindings/compat/c/Makefile.am
index 5a788f2bf..4ec4626c6 100644
--- a/src/bindings/compat/c/Makefile.am
+++ b/src/bindings/compat/c/Makefile.am
@@ -25,8 +25,8 @@ lib_LTLIBRARIES += libcvc4bindings_c_compat.la
libcvc4bindings_c_compat_la_LDFLAGS = \
-version-info $(LIBCVC4BINDINGS_VERSION)
libcvc4bindings_c_compat_la_LIBADD = \
- -L@builddir@/../../../compat -lcvc4compat \
- -L@builddir@/../../.. -lcvc4
+ @builddir@/../../../compat/libcvc4compat.la \
+ @builddir@/../../../libcvc4.la
endif
diff --git a/src/bindings/compat/java/Makefile.am b/src/bindings/compat/java/Makefile.am
index 9eb985822..5b052568d 100644
--- a/src/bindings/compat/java/Makefile.am
+++ b/src/bindings/compat/java/Makefile.am
@@ -33,8 +33,8 @@ libcvc4compatjni_la_LDFLAGS = \
-shrext $(CVC4_JAVA_MODULE_EXT) \
-version-info $(LIBCVC4BINDINGS_VERSION)
libcvc4compatjni_la_LIBADD = \
- -L@builddir@/../../../compat -lcvc4compat \
- -L@builddir@/../../.. -lcvc4
+ @builddir@/../../../compat/libcvc4compat.la \
+ @builddir@/../../../libcvc4.la
BUILT_SOURCES += $(JNI_CPP_FILES)
endif
diff --git a/src/compat/Makefile.am b/src/compat/Makefile.am
index 5a8bd454e..ebb13426d 100644
--- a/src/compat/Makefile.am
+++ b/src/compat/Makefile.am
@@ -25,8 +25,8 @@ libcvc4compat_la_LDFLAGS = \
-version-info $(LIBCVC4COMPAT_VERSION)
libcvc4compat_la_LIBADD = \
- -L@builddir@/.. -lcvc4 \
- -L@builddir@/../parser -lcvc4parser
+ @builddir@/../libcvc4.la \
+ @builddir@/../parser/libcvc4parser.la
if CVC4_NEEDS_REPLACEMENT_FUNCTIONS
libcvc4compat_la_LIBADD += \
diff --git a/src/compat/cvc3_compat.cpp b/src/compat/cvc3_compat.cpp
index 51b0c6083..08146760f 100644
--- a/src/compat/cvc3_compat.cpp
+++ b/src/compat/cvc3_compat.cpp
@@ -2468,7 +2468,12 @@ Context* ValidityChecker::getCurrentContext() {
}
void ValidityChecker::reset() {
- Unimplemented("This CVC3 compatibility function not yet implemented (sorry!)");
+ // reset everything, forget everything
+ d_smt->reset();
+ delete d_parserContext;
+ d_parserContext = CVC4::parser::ParserBuilder(d_em, "<internal>").withInputLanguage(CVC4::language::input::LANG_CVC4).withStringInput("").build();
+ s_typeToExpr.clear();
+ s_exprToType.clear();
}
void ValidityChecker::logAnnotation(const Expr& annot) {
diff --git a/src/decision/decision_engine.cpp b/src/decision/decision_engine.cpp
index c3b2f28ac..d7d463d79 100644
--- a/src/decision/decision_engine.cpp
+++ b/src/decision/decision_engine.cpp
@@ -49,14 +49,14 @@ void DecisionEngine::init()
d_engineState = 1;
Trace("decision-init") << "DecisionEngine::init()" << std::endl;
- Trace("decision-init") << " * options->decisionMode: "
+ Trace("decision-init") << " * options->decisionMode: "
<< options::decisionMode() << std:: endl;
Trace("decision-init") << " * options->decisionStopOnly: "
<< options::decisionStopOnly() << std::endl;
if(options::decisionMode() == decision::DECISION_STRATEGY_INTERNAL) { }
if(options::decisionMode() == decision::DECISION_STRATEGY_JUSTIFICATION) {
- ITEDecisionStrategy* ds =
+ ITEDecisionStrategy* ds =
new decision::JustificationHeuristic(this, d_userContext, d_satContext);
enableStrategy(ds);
d_needIteSkolemMap.push_back(ds);
@@ -107,7 +107,7 @@ void DecisionEngine::addAssertions(const vector<Node> &assertions)
// d_result = SAT_VALUE_UNKNOWN;
// d_assertions.reserve(assertions.size());
// for(unsigned i = 0; i < assertions.size(); ++i)
- // d_assertions.push_back(assertions[i]);
+ // d_assertions.push_back(assertions[i]);
}
void DecisionEngine::addAssertions(const vector<Node> &assertions,
@@ -116,11 +116,11 @@ void DecisionEngine::addAssertions(const vector<Node> &assertions,
{
// new assertions, reset whatever result we knew
d_result = SAT_VALUE_UNKNOWN;
-
+
// d_assertions.reserve(assertions.size());
for(unsigned i = 0; i < assertions.size(); ++i)
d_assertions.push_back(assertions[i]);
-
+
for(unsigned i = 0; i < d_needIteSkolemMap.size(); ++i)
d_needIteSkolemMap[i]->
addAssertions(assertions, assertionsEnd, iteSkolemMap);
diff --git a/src/decision/decision_engine.h b/src/decision/decision_engine.h
index bfd28e113..39ed89a68 100644
--- a/src/decision/decision_engine.h
+++ b/src/decision/decision_engine.h
@@ -71,7 +71,7 @@ public:
~DecisionEngine() {
Trace("decision") << "Destroying decision engine" << std::endl;
}
-
+
// void setPropEngine(PropEngine* pe) {
// // setPropEngine should not be called more than once
// Assert(d_propEngine == NULL);
@@ -123,8 +123,8 @@ public:
"Forgot to set satSolver for decision engine?");
SatLiteral ret = undefSatLiteral;
- for(unsigned i = 0;
- i < d_enabledStrategies.size()
+ for(unsigned i = 0;
+ i < d_enabledStrategies.size()
and ret == undefSatLiteral
and stopSearch == false; ++i) {
ret = d_enabledStrategies[i]->getNext(stopSearch);
@@ -137,7 +137,7 @@ public:
/**
* Try to get tell SAT solver what polarity to try for a
- * decision. Return SAT_VALUE_UNKNOWN if it can't help
+ * decision. Return SAT_VALUE_UNKNOWN if it can't help
*/
SatValue getPolarity(SatVariable var);
@@ -193,7 +193,7 @@ public:
// (which was possibly requested by them on initialization)
/**
- * Get the assertions. Strategies are notified when these are available.
+ * Get the assertions. Strategies are notified when these are available.
*/
AssertionsList& getAssertions() {
return d_assertions;
diff --git a/src/decision/decision_strategy.h b/src/decision/decision_strategy.h
index e4df8d4af..94db110c2 100644
--- a/src/decision/decision_strategy.h
+++ b/src/decision/decision_strategy.h
@@ -43,9 +43,9 @@ public:
virtual ~DecisionStrategy() { }
virtual prop::SatLiteral getNext(bool&) = 0;
-
+
virtual bool needIteSkolemMap() { return false; }
-
+
virtual void notifyAssertionsAvailable() { return; }
};/* class DecisionStrategy */
diff --git a/src/decision/justification_heuristic.cpp b/src/decision/justification_heuristic.cpp
index ffff6952f..c9a6b7e1b 100644
--- a/src/decision/justification_heuristic.cpp
+++ b/src/decision/justification_heuristic.cpp
@@ -108,6 +108,7 @@ CVC4::prop::SatLiteral JustificationHeuristic::getNextThresh(bool &stopSearch, D
if(litDecision != undefSatLiteral) {
setPrvsIndex(i);
Trace("decision") << "jh: splitting on " << litDecision << std::endl;
+ ++d_helfulness;
return litDecision;
}
}
@@ -124,7 +125,7 @@ CVC4::prop::SatLiteral JustificationHeuristic::getNextThresh(bool &stopSearch, D
if(Debug.isOn("decision")) {
if(!checkJustified(curass))
- Debug("decision") << "****** Not justified [i="<<i<<"]: "
+ Debug("decision") << "****** Not justified [i="<<i<<"]: "
<< d_assertions[i] << std::endl;
}
}
@@ -169,7 +170,7 @@ void JustificationHeuristic::addAssertions
IteSkolemMap iteSkolemMap) {
Trace("decision")
- << "JustificationHeuristic::addAssertions()"
+ << "JustificationHeuristic::addAssertions()"
<< " size = " << assertions.size()
<< " assertionsEnd = " << assertionsEnd
<< std::endl;
@@ -182,7 +183,7 @@ void JustificationHeuristic::addAssertions
for(IteSkolemMap::iterator i = iteSkolemMap.begin();
i != iteSkolemMap.end(); ++i) {
- Trace("decision::jh::ite")
+ Trace("decision::jh::ite")
<< " jh-ite: " << (i->first) << " maps to "
<< assertions[(i->second)] << std::endl;
Assert(i->second >= assertionsEnd && i->second < assertions.size());
@@ -197,9 +198,7 @@ SatLiteral JustificationHeuristic::findSplitter(TNode node,
SatValue desiredVal)
{
d_curDecision = undefSatLiteral;
- if(findSplitterRec(node, desiredVal)) {
- ++d_helfulness;
- }
+ findSplitterRec(node, desiredVal);
return d_curDecision;
}
@@ -405,9 +404,9 @@ JustificationHeuristic::findSplitterRec(TNode node, SatValue desiredVal)
* children to be true. this is done recursively.
*/
- Trace("decision::jh")
- << "findSplitterRec(" << node << ", "
- << desiredVal << ", .. )" << std::endl;
+ Trace("decision::jh")
+ << "findSplitterRec(" << node << ", "
+ << desiredVal << ", .. )" << std::endl;
/* Handle NOT as a special case */
while (node.getKind() == kind::NOT) {
@@ -417,7 +416,7 @@ JustificationHeuristic::findSplitterRec(TNode node, SatValue desiredVal)
/* Base case */
if (checkJustified(node)) {
- Debug("decision::jh") << " justified, returning" << std::endl;
+ Debug("decision::jh") << " justified, returning" << std::endl;
return NO_SPLITTER;
}
if (getExploredThreshold(node) < d_curThreshold) {
@@ -449,7 +448,7 @@ JustificationHeuristic::findSplitterRec(TNode node, SatValue desiredVal)
// "invariant violated");
/* What type of node is this */
- Kind k = node.getKind();
+ Kind k = node.getKind();
theory::TheoryId tId = theory::kindToTheoryId(k);
/* Some debugging stuff */
@@ -470,14 +469,17 @@ JustificationHeuristic::findSplitterRec(TNode node, SatValue desiredVal)
Assert(litVal == desiredVal);
setJustified(node);
return NO_SPLITTER;
- }
+ }
else {
Assert(d_decisionEngine->hasSatLiteral(node));
if(d_curThreshold != 0 && getWeightPolarized(node, desiredVal) >= d_curThreshold)
return DONT_KNOW;
SatVariable v =
d_decisionEngine->getSatLiteral(node).getSatVariable();
- d_curDecision = SatLiteral(v, desiredVal != SAT_VALUE_TRUE );
+ d_curDecision = SatLiteral(v, /* negated = */ desiredVal != SAT_VALUE_TRUE );
+ Trace("decision-node") << "[decision-node] requesting split on " << d_curDecision
+ << ", node: " << node
+ << ", polarity: " << (desiredVal == SAT_VALUE_TRUE ? "true" : "false") << std::endl;
return FOUND_SPLITTER;
}
}
@@ -548,7 +550,7 @@ JustificationHeuristic::findSplitterRec(TNode node, SatValue desiredVal)
JustificationHeuristic::SearchResult
JustificationHeuristic::handleAndOrEasy(TNode node, SatValue desiredVal)
{
- Assert( (node.getKind() == kind::AND and desiredVal == SAT_VALUE_FALSE) or
+ Assert( (node.getKind() == kind::AND and desiredVal == SAT_VALUE_FALSE) or
(node.getKind() == kind::OR and desiredVal == SAT_VALUE_TRUE) );
int numChildren = node.getNumChildren();
@@ -575,7 +577,7 @@ void JustificationHeuristic::saveStartIndex(TNode node, int val) {
JustificationHeuristic::SearchResult JustificationHeuristic::handleAndOrHard(TNode node,
SatValue desiredVal) {
- Assert( (node.getKind() == kind::AND and desiredVal == SAT_VALUE_TRUE) or
+ Assert( (node.getKind() == kind::AND and desiredVal == SAT_VALUE_TRUE) or
(node.getKind() == kind::OR and desiredVal == SAT_VALUE_FALSE) );
int numChildren = node.getNumChildren();
@@ -671,7 +673,7 @@ JustificationHeuristic::SearchResult JustificationHeuristic::handleITE(TNode nod
if(findSplitterRec(node[0], ifDesiredVal) == FOUND_SPLITTER)
return FOUND_SPLITTER;
-
+
Assert(d_curThreshold != 0, "No controlling input found (6)");
return DONT_KNOW;
} else {
diff --git a/src/decision/justification_heuristic.h b/src/decision/justification_heuristic.h
index a6bc68ce5..9177ba44d 100644
--- a/src/decision/justification_heuristic.h
+++ b/src/decision/justification_heuristic.h
@@ -127,10 +127,10 @@ private:
prop::SatLiteral getNextThresh(bool &stopSearch, DecisionWeight threshold);
SatLiteral findSplitter(TNode node, SatValue desiredVal);
-
- /**
- * Do all the hard work.
- */
+
+ /**
+ * Do all the hard work.
+ */
SearchResult findSplitterRec(TNode node, SatValue value);
/* Helper functions */
diff --git a/src/expr/attribute.cpp b/src/expr/attribute.cpp
index 2cd884bba..63ea770ca 100644
--- a/src/expr/attribute.cpp
+++ b/src/expr/attribute.cpp
@@ -17,6 +17,7 @@
#include "expr/attribute.h"
#include "expr/node_value.h"
#include "util/output.h"
+#include "smt/smt_engine.h"
#include <utility>
@@ -26,13 +27,16 @@ namespace CVC4 {
namespace expr {
namespace attr {
-AttributeManager::AttributeManager(context::Context* ctxt) :
+SmtAttributes::SmtAttributes(context::Context* ctxt) :
d_cdbools(ctxt),
d_cdints(ctxt),
d_cdtnodes(ctxt),
d_cdnodes(ctxt),
d_cdstrings(ctxt),
- d_cdptrs(ctxt),
+ d_cdptrs(ctxt) {
+}
+
+AttributeManager::AttributeManager() :
d_inGarbageCollection(false)
{}
@@ -40,6 +44,15 @@ bool AttributeManager::inGarbageCollection() const {
return d_inGarbageCollection;
}
+SmtAttributes& AttributeManager::getSmtAttributes(SmtEngine* smt) {
+ Assert(smt != NULL);
+ return *smt->d_smtAttributes;
+}
+
+const SmtAttributes& AttributeManager::getSmtAttributes(SmtEngine* smt) const {
+ return *smt->d_smtAttributes;
+}
+
void AttributeManager::debugHook(int debugFlag) {
/* DO NOT CHECK IN ANY CODE INTO THE DEBUG HOOKS!
* debugHook() is an empty function for the purpose of debugging
@@ -57,6 +70,10 @@ void AttributeManager::deleteAllAttributes(NodeValue* nv) {
deleteFromTable(d_types, nv);
deleteFromTable(d_strings, nv);
deleteFromTable(d_ptrs, nv);
+}
+
+void SmtAttributes::deleteAllAttributes(TNode n) {
+ NodeValue* nv = n.d_nv;
d_cdbools.erase(nv);
deleteFromTable(d_cdints, nv);
@@ -74,32 +91,25 @@ void AttributeManager::deleteAllAttributes() {
deleteAllFromTable(d_types);
deleteAllFromTable(d_strings);
deleteAllFromTable(d_ptrs);
-
- d_cdbools.clear();
- d_cdints.clear();
- d_cdtnodes.clear();
- d_cdnodes.clear();
- d_cdstrings.clear();
- d_cdptrs.clear();
}
-void AttributeManager::deleteAttributes(const AttrIdVec& atids){
+void AttributeManager::deleteAttributes(const AttrIdVec& atids) {
typedef std::map<uint64_t, std::vector< uint64_t> > AttrToVecMap;
AttrToVecMap perTableIds;
- for(AttrIdVec::const_iterator it = atids.begin(), it_end = atids.end(); it != it_end; ++it){
+ for(AttrIdVec::const_iterator it = atids.begin(), it_end = atids.end(); it != it_end; ++it) {
const AttributeUniqueId& pair = *(*it);
std::vector< uint64_t>& inTable = perTableIds[pair.getTableId()];
inTable.push_back(pair.getWithinTypeId());
}
AttrToVecMap::iterator it = perTableIds.begin(), it_end = perTableIds.end();
- for(; it != it_end; ++it){
+ for(; it != it_end; ++it) {
Assert(((*it).first) <= LastAttrTable);
AttrTableId tableId = (AttrTableId) ((*it).first);
std::vector< uint64_t>& ids = (*it).second;
std::sort(ids.begin(), ids.end());
- switch(tableId){
+ switch(tableId) {
case AttrTableBool:
Unimplemented("delete attributes is unimplemented for bools");
break;
@@ -130,6 +140,7 @@ void AttributeManager::deleteAttributes(const AttrIdVec& atids){
case AttrTableCDPointer:
Unimplemented("CDAttributes cannot be deleted. Contact Tim/Morgan if this behavior is desired.");
break;
+
case LastAttrTable:
default:
Unreachable();
diff --git a/src/expr/attribute.h b/src/expr/attribute.h
index 0bca760ef..432fbbac9 100644
--- a/src/expr/attribute.h
+++ b/src/expr/attribute.h
@@ -20,6 +20,7 @@
* attributes and nodes due to template use */
#include "expr/node.h"
#include "expr/type_node.h"
+#include "context/context.h"
#ifndef __CVC4__EXPR__ATTRIBUTE_H
#define __CVC4__EXPR__ATTRIBUTE_H
@@ -34,34 +35,20 @@
#undef CVC4_ATTRIBUTE_H__INCLUDING__ATTRIBUTE_INTERNALS_H
namespace CVC4 {
+
+class SmtEngine;
+
+namespace smt {
+ extern CVC4_THREADLOCAL(SmtEngine*) s_smtEngine_current;
+}/* CVC4::smt namespace */
+
namespace expr {
namespace attr {
// ATTRIBUTE MANAGER ===========================================================
-/**
- * A container for the main attribute tables of the system. There's a
- * one-to-one NodeManager : AttributeManager correspondence.
- */
-class AttributeManager {
-
- // IF YOU ADD ANY TABLES, don't forget to add them also to the
- // implementation of deleteAllAttributes().
-
- /** Underlying hash table for boolean-valued attributes */
- AttrHash<bool> d_bools;
- /** Underlying hash table for integral-valued attributes */
- AttrHash<uint64_t> d_ints;
- /** Underlying hash table for node-valued attributes */
- AttrHash<TNode> d_tnodes;
- /** Underlying hash table for node-valued attributes */
- AttrHash<Node> d_nodes;
- /** Underlying hash table for types attributes */
- AttrHash<TypeNode> d_types;
- /** Underlying hash table for string-valued attributes */
- AttrHash<std::string> d_strings;
- /** Underlying hash table for pointer-valued attributes */
- AttrHash<void*> d_ptrs;
+struct SmtAttributes {
+ SmtAttributes(context::Context*);
// IF YOU ADD ANY TABLES, don't forget to add them also to the
// implementation of deleteAllAttributes().
@@ -79,12 +66,23 @@ class AttributeManager {
/** Underlying hash table for context-dependent pointer-valued attributes */
CDAttrHash<void*> d_cdptrs;
- template <class T>
- void deleteFromTable(AttrHash<T>& table, NodeValue* nv);
+ /** Delete all attributes of given node */
+ void deleteAllAttributes(TNode n);
template <class T>
void deleteFromTable(CDAttrHash<T>& table, NodeValue* nv);
+};/* struct SmtAttributes */
+
+/**
+ * A container for the main attribute tables of the system. There's a
+ * one-to-one NodeManager : AttributeManager correspondence.
+ */
+class AttributeManager {
+
+ template <class T>
+ void deleteFromTable(AttrHash<T>& table, NodeValue* nv);
+
template <class T>
void deleteAllFromTable(AttrHash<T>& table);
@@ -105,10 +103,31 @@ class AttributeManager {
void clearDeleteAllAttributesBuffer();
+ SmtAttributes& getSmtAttributes(SmtEngine*);
+ const SmtAttributes& getSmtAttributes(SmtEngine*) const;
+
public:
/** Construct an attribute manager. */
- AttributeManager(context::Context* ctxt);
+ AttributeManager();
+
+ // IF YOU ADD ANY TABLES, don't forget to add them also to the
+ // implementation of deleteAllAttributes().
+
+ /** Underlying hash table for boolean-valued attributes */
+ AttrHash<bool> d_bools;
+ /** Underlying hash table for integral-valued attributes */
+ AttrHash<uint64_t> d_ints;
+ /** Underlying hash table for node-valued attributes */
+ AttrHash<TNode> d_tnodes;
+ /** Underlying hash table for node-valued attributes */
+ AttrHash<Node> d_nodes;
+ /** Underlying hash table for types attributes */
+ AttrHash<TypeNode> d_types;
+ /** Underlying hash table for string-valued attributes */
+ AttrHash<std::string> d_strings;
+ /** Underlying hash table for pointer-valued attributes */
+ AttrHash<void*> d_ptrs;
/**
* Get a particular attribute on a particular node.
@@ -220,10 +239,10 @@ template <>
struct getTable<bool, false> {
static const AttrTableId id = AttrTableBool;
typedef AttrHash<bool> table_type;
- static inline table_type& get(AttributeManager& am) {
+ static inline table_type& get(AttributeManager& am, SmtEngine* smt) {
return am.d_bools;
}
- static inline const table_type& get(const AttributeManager& am) {
+ static inline const table_type& get(const AttributeManager& am, SmtEngine* smt) {
return am.d_bools;
}
};
@@ -233,10 +252,10 @@ template <>
struct getTable<uint64_t, false> {
static const AttrTableId id = AttrTableUInt64;
typedef AttrHash<uint64_t> table_type;
- static inline table_type& get(AttributeManager& am) {
+ static inline table_type& get(AttributeManager& am, SmtEngine* smt) {
return am.d_ints;
}
- static inline const table_type& get(const AttributeManager& am) {
+ static inline const table_type& get(const AttributeManager& am, SmtEngine* smt) {
return am.d_ints;
}
};
@@ -246,10 +265,10 @@ template <>
struct getTable<TNode, false> {
static const AttrTableId id = AttrTableTNode;
typedef AttrHash<TNode> table_type;
- static inline table_type& get(AttributeManager& am) {
+ static inline table_type& get(AttributeManager& am, SmtEngine* smt) {
return am.d_tnodes;
}
- static inline const table_type& get(const AttributeManager& am) {
+ static inline const table_type& get(const AttributeManager& am, SmtEngine* smt) {
return am.d_tnodes;
}
};
@@ -259,10 +278,10 @@ template <>
struct getTable<Node, false> {
static const AttrTableId id = AttrTableNode;
typedef AttrHash<Node> table_type;
- static inline table_type& get(AttributeManager& am) {
+ static inline table_type& get(AttributeManager& am, SmtEngine* smt) {
return am.d_nodes;
}
- static inline const table_type& get(const AttributeManager& am) {
+ static inline const table_type& get(const AttributeManager& am, SmtEngine* smt) {
return am.d_nodes;
}
};
@@ -272,10 +291,10 @@ template <>
struct getTable<TypeNode, false> {
static const AttrTableId id = AttrTableTypeNode;
typedef AttrHash<TypeNode> table_type;
- static inline table_type& get(AttributeManager& am) {
+ static inline table_type& get(AttributeManager& am, SmtEngine* smt) {
return am.d_types;
}
- static inline const table_type& get(const AttributeManager& am) {
+ static inline const table_type& get(const AttributeManager& am, SmtEngine* smt) {
return am.d_types;
}
};
@@ -285,10 +304,10 @@ template <>
struct getTable<std::string, false> {
static const AttrTableId id = AttrTableString;
typedef AttrHash<std::string> table_type;
- static inline table_type& get(AttributeManager& am) {
+ static inline table_type& get(AttributeManager& am, SmtEngine* smt) {
return am.d_strings;
}
- static inline const table_type& get(const AttributeManager& am) {
+ static inline const table_type& get(const AttributeManager& am, SmtEngine* smt) {
return am.d_strings;
}
};
@@ -298,10 +317,10 @@ template <class T>
struct getTable<T*, false> {
static const AttrTableId id = AttrTablePointer;
typedef AttrHash<void*> table_type;
- static inline table_type& get(AttributeManager& am) {
+ static inline table_type& get(AttributeManager& am, SmtEngine* smt) {
return am.d_ptrs;
}
- static inline const table_type& get(const AttributeManager& am) {
+ static inline const table_type& get(const AttributeManager& am, SmtEngine* smt) {
return am.d_ptrs;
}
};
@@ -311,10 +330,10 @@ template <class T>
struct getTable<const T*, false> {
static const AttrTableId id = AttrTablePointer;
typedef AttrHash<void*> table_type;
- static inline table_type& get(AttributeManager& am) {
+ static inline table_type& get(AttributeManager& am, SmtEngine* smt) {
return am.d_ptrs;
}
- static inline const table_type& get(const AttributeManager& am) {
+ static inline const table_type& get(const AttributeManager& am, SmtEngine* smt) {
return am.d_ptrs;
}
};
@@ -324,11 +343,11 @@ template <>
struct getTable<bool, true> {
static const AttrTableId id = AttrTableCDBool;
typedef CDAttrHash<bool> table_type;
- static inline table_type& get(AttributeManager& am) {
- return am.d_cdbools;
+ static inline table_type& get(AttributeManager& am, SmtEngine* smt) {
+ return am.getSmtAttributes(smt).d_cdbools;
}
- static inline const table_type& get(const AttributeManager& am) {
- return am.d_cdbools;
+ static inline const table_type& get(const AttributeManager& am, SmtEngine* smt) {
+ return am.getSmtAttributes(smt).d_cdbools;
}
};
@@ -337,11 +356,11 @@ template <>
struct getTable<uint64_t, true> {
static const AttrTableId id = AttrTableCDUInt64;
typedef CDAttrHash<uint64_t> table_type;
- static inline table_type& get(AttributeManager& am) {
- return am.d_cdints;
+ static inline table_type& get(AttributeManager& am, SmtEngine* smt) {
+ return am.getSmtAttributes(smt).d_cdints;
}
- static inline const table_type& get(const AttributeManager& am) {
- return am.d_cdints;
+ static inline const table_type& get(const AttributeManager& am, SmtEngine* smt) {
+ return am.getSmtAttributes(smt).d_cdints;
}
};
@@ -350,11 +369,11 @@ template <>
struct getTable<TNode, true> {
static const AttrTableId id = AttrTableCDTNode;
typedef CDAttrHash<TNode> table_type;
- static inline table_type& get(AttributeManager& am) {
- return am.d_cdtnodes;
+ static inline table_type& get(AttributeManager& am, SmtEngine* smt) {
+ return am.getSmtAttributes(smt).d_cdtnodes;
}
- static inline const table_type& get(const AttributeManager& am) {
- return am.d_cdtnodes;
+ static inline const table_type& get(const AttributeManager& am, SmtEngine* smt) {
+ return am.getSmtAttributes(smt).d_cdtnodes;
}
};
@@ -363,11 +382,11 @@ template <>
struct getTable<Node, true> {
static const AttrTableId id = AttrTableCDNode;
typedef CDAttrHash<Node> table_type;
- static inline table_type& get(AttributeManager& am) {
- return am.d_cdnodes;
+ static inline table_type& get(AttributeManager& am, SmtEngine* smt) {
+ return am.getSmtAttributes(smt).d_cdnodes;
}
- static inline const table_type& get(const AttributeManager& am) {
- return am.d_cdnodes;
+ static inline const table_type& get(const AttributeManager& am, SmtEngine* smt) {
+ return am.getSmtAttributes(smt).d_cdnodes;
}
};
@@ -376,11 +395,11 @@ template <>
struct getTable<std::string, true> {
static const AttrTableId id = AttrTableCDString;
typedef CDAttrHash<std::string> table_type;
- static inline table_type& get(AttributeManager& am) {
- return am.d_cdstrings;
+ static inline table_type& get(AttributeManager& am, SmtEngine* smt) {
+ return am.getSmtAttributes(smt).d_cdstrings;
}
- static inline const table_type& get(const AttributeManager& am) {
- return am.d_cdstrings;
+ static inline const table_type& get(const AttributeManager& am, SmtEngine* smt) {
+ return am.getSmtAttributes(smt).d_cdstrings;
}
};
@@ -389,11 +408,11 @@ template <class T>
struct getTable<T*, true> {
static const AttrTableId id = AttrTableCDPointer;
typedef CDAttrHash<void*> table_type;
- static inline table_type& get(AttributeManager& am) {
- return am.d_cdptrs;
+ static inline table_type& get(AttributeManager& am, SmtEngine* smt) {
+ return am.getSmtAttributes(smt).d_cdptrs;
}
- static inline const table_type& get(const AttributeManager& am) {
- return am.d_cdptrs;
+ static inline const table_type& get(const AttributeManager& am, SmtEngine* smt) {
+ return am.getSmtAttributes(smt).d_cdptrs;
}
};
@@ -402,11 +421,11 @@ template <class T>
struct getTable<const T*, true> {
static const AttrTableId id = AttrTableCDPointer;
typedef CDAttrHash<void*> table_type;
- static inline table_type& get(AttributeManager& am) {
- return am.d_cdptrs;
+ static inline table_type& get(AttributeManager& am, SmtEngine* smt) {
+ return am.getSmtAttributes(smt).d_cdptrs;
}
- static inline const table_type& get(const AttributeManager& am) {
- return am.d_cdptrs;
+ static inline const table_type& get(const AttributeManager& am, SmtEngine* smt) {
+ return am.getSmtAttributes(smt).d_cdptrs;
}
};
@@ -426,7 +445,7 @@ AttributeManager::getAttribute(NodeValue* nv, const AttrKind&) const {
table_type table_type;
const table_type& ah =
- getTable<value_type, AttrKind::context_dependent>::get(*this);
+ getTable<value_type, AttrKind::context_dependent>::get(*this, smt::s_smtEngine_current);
typename table_type::const_iterator i =
ah.find(std::make_pair(AttrKind::getId(), nv));
@@ -469,7 +488,7 @@ struct HasAttribute<true, AttrKind> {
table_type;
const table_type& ah =
- getTable<value_type, AttrKind::context_dependent>::get(*am);
+ getTable<value_type, AttrKind::context_dependent>::get(*am, smt::s_smtEngine_current);
typename table_type::const_iterator i =
ah.find(std::make_pair(AttrKind::getId(), nv));
@@ -497,7 +516,7 @@ struct HasAttribute<false, AttrKind> {
table_type table_type;
const table_type& ah =
- getTable<value_type, AttrKind::context_dependent>::get(*am);
+ getTable<value_type, AttrKind::context_dependent>::get(*am, smt::s_smtEngine_current);
typename table_type::const_iterator i =
ah.find(std::make_pair(AttrKind::getId(), nv));
@@ -517,7 +536,7 @@ struct HasAttribute<false, AttrKind> {
table_type table_type;
const table_type& ah =
- getTable<value_type, AttrKind::context_dependent>::get(*am);
+ getTable<value_type, AttrKind::context_dependent>::get(*am, smt::s_smtEngine_current);
typename table_type::const_iterator i =
ah.find(std::make_pair(AttrKind::getId(), nv));
@@ -557,7 +576,7 @@ AttributeManager::setAttribute(NodeValue* nv,
table_type table_type;
table_type& ah =
- getTable<value_type, AttrKind::context_dependent>::get(*this);
+ getTable<value_type, AttrKind::context_dependent>::get(*this, smt::s_smtEngine_current);
ah[std::make_pair(AttrKind::getId(), nv)] = mapping::convert(value);
}
@@ -590,8 +609,8 @@ inline void AttributeManager::deleteFromTable(AttrHash<T>& table,
* Obliterate a NodeValue from a (context-dependent) attribute table.
*/
template <class T>
-inline void AttributeManager::deleteFromTable(CDAttrHash<T>& table,
- NodeValue* nv) {
+inline void SmtAttributes::deleteFromTable(CDAttrHash<T>& table,
+ NodeValue* nv) {
for(unsigned id = 0; id < attr::LastAttributeId<T, true>::getId(); ++id) {
table.obliterate(std::make_pair(id, nv));
}
diff --git a/src/expr/command.cpp b/src/expr/command.cpp
index 69bdd704b..be1b06cb8 100644
--- a/src/expr/command.cpp
+++ b/src/expr/command.cpp
@@ -189,8 +189,8 @@ std::string EchoCommand::getCommandName() const throw() {
/* class AssertCommand */
-AssertCommand::AssertCommand(const Expr& e) throw() :
- d_expr(e) {
+AssertCommand::AssertCommand(const Expr& e, bool inUnsatCore) throw() :
+ d_expr(e), d_inUnsatCore(inUnsatCore) {
}
Expr AssertCommand::getExpr() const throw() {
@@ -199,7 +199,7 @@ Expr AssertCommand::getExpr() const throw() {
void AssertCommand::invoke(SmtEngine* smtEngine) throw() {
try {
- smtEngine->assertFormula(d_expr);
+ smtEngine->assertFormula(d_expr, d_inUnsatCore);
d_commandStatus = CommandSuccess::instance();
} catch(exception& e) {
d_commandStatus = new CommandFailure(e.what());
@@ -207,18 +207,17 @@ void AssertCommand::invoke(SmtEngine* smtEngine) throw() {
}
Command* AssertCommand::exportTo(ExprManager* exprManager, ExprManagerMapCollection& variableMap) {
- return new AssertCommand(d_expr.exportTo(exprManager, variableMap));
+ return new AssertCommand(d_expr.exportTo(exprManager, variableMap), d_inUnsatCore);
}
Command* AssertCommand::clone() const {
- return new AssertCommand(d_expr);
+ return new AssertCommand(d_expr, d_inUnsatCore);
}
std::string AssertCommand::getCommandName() const throw() {
return "assert";
}
-
/* class PushCommand */
void PushCommand::invoke(SmtEngine* smtEngine) throw() {
@@ -271,8 +270,8 @@ CheckSatCommand::CheckSatCommand() throw() :
d_expr() {
}
-CheckSatCommand::CheckSatCommand(const Expr& expr) throw() :
- d_expr(expr) {
+CheckSatCommand::CheckSatCommand(const Expr& expr, bool inUnsatCore) throw() :
+ d_expr(expr), d_inUnsatCore(inUnsatCore) {
}
Expr CheckSatCommand::getExpr() const throw() {
@@ -301,13 +300,13 @@ void CheckSatCommand::printResult(std::ostream& out, uint32_t verbosity) const t
}
Command* CheckSatCommand::exportTo(ExprManager* exprManager, ExprManagerMapCollection& variableMap) {
- CheckSatCommand* c = new CheckSatCommand(d_expr.exportTo(exprManager, variableMap));
+ CheckSatCommand* c = new CheckSatCommand(d_expr.exportTo(exprManager, variableMap), d_inUnsatCore);
c->d_result = d_result;
return c;
}
Command* CheckSatCommand::clone() const {
- CheckSatCommand* c = new CheckSatCommand(d_expr);
+ CheckSatCommand* c = new CheckSatCommand(d_expr, d_inUnsatCore);
c->d_result = d_result;
return c;
}
@@ -318,8 +317,8 @@ std::string CheckSatCommand::getCommandName() const throw() {
/* class QueryCommand */
-QueryCommand::QueryCommand(const Expr& e) throw() :
- d_expr(e) {
+QueryCommand::QueryCommand(const Expr& e, bool inUnsatCore) throw() :
+ d_expr(e), d_inUnsatCore(inUnsatCore) {
}
Expr QueryCommand::getExpr() const throw() {
@@ -348,13 +347,13 @@ void QueryCommand::printResult(std::ostream& out, uint32_t verbosity) const thro
}
Command* QueryCommand::exportTo(ExprManager* exprManager, ExprManagerMapCollection& variableMap) {
- QueryCommand* c = new QueryCommand(d_expr.exportTo(exprManager, variableMap));
+ QueryCommand* c = new QueryCommand(d_expr.exportTo(exprManager, variableMap), d_inUnsatCore);
c->d_result = d_result;
return c;
}
Command* QueryCommand::clone() const {
- QueryCommand* c = new QueryCommand(d_expr);
+ QueryCommand* c = new QueryCommand(d_expr, d_inUnsatCore);
c->d_result = d_result;
return c;
}
@@ -363,11 +362,54 @@ std::string QueryCommand::getCommandName() const throw() {
return "query";
}
-/* class QuitCommand */
+/* class ResetCommand */
+
+void ResetCommand::invoke(SmtEngine* smtEngine) throw() {
+ try {
+ smtEngine->reset();
+ d_commandStatus = CommandSuccess::instance();
+ } catch(exception& e) {
+ d_commandStatus = new CommandFailure(e.what());
+ }
+}
+
+Command* ResetCommand::exportTo(ExprManager* exprManager, ExprManagerMapCollection& variableMap) {
+ return new ResetCommand();
+}
+
+Command* ResetCommand::clone() const {
+ return new ResetCommand();
+}
+
+std::string ResetCommand::getCommandName() const throw() {
+ return "reset";
+}
+
+/* class ResetAssertionsCommand */
+
+void ResetAssertionsCommand::invoke(SmtEngine* smtEngine) throw() {
+ try {
+ smtEngine->resetAssertions();
+ d_commandStatus = CommandSuccess::instance();
+ } catch(exception& e) {
+ d_commandStatus = new CommandFailure(e.what());
+ }
+}
+
+Command* ResetAssertionsCommand::exportTo(ExprManager* exprManager, ExprManagerMapCollection& variableMap) {
+ return new ResetAssertionsCommand();
+}
-QuitCommand::QuitCommand() throw() {
+Command* ResetAssertionsCommand::clone() const {
+ return new ResetAssertionsCommand();
}
+std::string ResetAssertionsCommand::getCommandName() const throw() {
+ return "reset-assertions";
+}
+
+/* class QuitCommand */
+
void QuitCommand::invoke(SmtEngine* smtEngine) throw() {
Dump("benchmark") << *this;
d_commandStatus = CommandSuccess::instance();
@@ -744,22 +786,22 @@ Command* DefineNamedFunctionCommand::clone() const {
SetUserAttributeCommand::SetUserAttributeCommand( const std::string& attr, Expr expr ) throw() :
d_attr( attr ), d_expr( expr ){
}
-/*
-SetUserAttributeCommand::SetUserAttributeCommand( const std::string& id, Expr expr,
+
+SetUserAttributeCommand::SetUserAttributeCommand( const std::string& attr, Expr expr,
std::vector<Expr>& values ) throw() :
- d_id( id ), d_expr( expr ){
+ d_attr( attr ), d_expr( expr ){
d_expr_values.insert( d_expr_values.begin(), values.begin(), values.end() );
}
-SetUserAttributeCommand::SetUserAttributeCommand( const std::string& id, Expr expr,
- std::string& value ) throw() :
- d_id( id ), d_expr( expr ), d_str_value( value ){
+SetUserAttributeCommand::SetUserAttributeCommand( const std::string& attr, Expr expr,
+ const std::string& value ) throw() :
+ d_attr( attr ), d_expr( expr ), d_str_value( value ){
}
-*/
+
void SetUserAttributeCommand::invoke(SmtEngine* smtEngine) throw(){
try {
if(!d_expr.isNull()) {
- smtEngine->setUserAttribute( d_attr, d_expr );
+ smtEngine->setUserAttribute( d_attr, d_expr, d_expr_values, d_str_value );
}
d_commandStatus = CommandSuccess::instance();
} catch(exception& e) {
@@ -769,11 +811,15 @@ void SetUserAttributeCommand::invoke(SmtEngine* smtEngine) throw(){
Command* SetUserAttributeCommand::exportTo(ExprManager* exprManager, ExprManagerMapCollection& variableMap){
Expr expr = d_expr.exportTo(exprManager, variableMap);
- return new SetUserAttributeCommand( d_attr, expr );
+ SetUserAttributeCommand * c = new SetUserAttributeCommand( d_attr, expr, d_str_value );
+ c->d_expr_values.insert( c->d_expr_values.end(), d_expr_values.begin(), d_expr_values.end() );
+ return c;
}
Command* SetUserAttributeCommand::clone() const{
- return new SetUserAttributeCommand( d_attr, d_expr );
+ SetUserAttributeCommand * c = new SetUserAttributeCommand( d_attr, d_expr, d_str_value );
+ c->d_expr_values.insert( c->d_expr_values.end(), d_expr_values.begin(), d_expr_values.end() );
+ return c;
}
std::string SetUserAttributeCommand::getCommandName() const throw() {
@@ -1125,36 +1171,40 @@ std::string GetInstantiationsCommand::getCommandName() const throw() {
GetUnsatCoreCommand::GetUnsatCoreCommand() throw() {
}
+GetUnsatCoreCommand::GetUnsatCoreCommand(const std::map<Expr, std::string>& names) throw() : d_names(names) {
+}
+
void GetUnsatCoreCommand::invoke(SmtEngine* smtEngine) throw() {
- /*
try {
d_result = smtEngine->getUnsatCore();
d_commandStatus = CommandSuccess::instance();
} catch(exception& e) {
d_commandStatus = new CommandFailure(e.what());
}
- */
- d_commandStatus = new CommandUnsupported();
}
void GetUnsatCoreCommand::printResult(std::ostream& out, uint32_t verbosity) const throw() {
if(! ok()) {
this->Command::printResult(out, verbosity);
} else {
- //do nothing -- unsat cores not yet supported
- // d_result->toStream(out);
+ d_result.toStream(out, d_names);
}
}
+const UnsatCore& GetUnsatCoreCommand::getUnsatCore() const throw() {
+ // of course, this will be empty if the command hasn't been invoked yet
+ return d_result;
+}
+
Command* GetUnsatCoreCommand::exportTo(ExprManager* exprManager, ExprManagerMapCollection& variableMap) {
- GetUnsatCoreCommand* c = new GetUnsatCoreCommand();
- //c->d_result = d_result;
+ GetUnsatCoreCommand* c = new GetUnsatCoreCommand(d_names);
+ c->d_result = d_result;
return c;
}
Command* GetUnsatCoreCommand::clone() const {
- GetUnsatCoreCommand* c = new GetUnsatCoreCommand();
- //c->d_result = d_result;
+ GetUnsatCoreCommand* c = new GetUnsatCoreCommand(d_names);
+ c->d_result = d_result;
return c;
}
diff --git a/src/expr/command.h b/src/expr/command.h
index 606618d21..c4f2fc1bc 100644
--- a/src/expr/command.h
+++ b/src/expr/command.h
@@ -35,6 +35,7 @@
#include "util/sexpr.h"
#include "util/datatype.h"
#include "util/proof.h"
+#include "util/unsat_core.h"
namespace CVC4 {
@@ -309,8 +310,9 @@ public:
class CVC4_PUBLIC AssertCommand : public Command {
protected:
Expr d_expr;
+ bool d_inUnsatCore;
public:
- AssertCommand(const Expr& e) throw();
+ AssertCommand(const Expr& e, bool inUnsatCore = true) throw();
~AssertCommand() throw() {}
Expr getExpr() const throw();
void invoke(SmtEngine* smtEngine) throw();
@@ -439,12 +441,12 @@ class CVC4_PUBLIC SetUserAttributeCommand : public Command {
protected:
std::string d_attr;
Expr d_expr;
- //std::vector<Expr> d_expr_values;
- //std::string d_str_value;
+ std::vector<Expr> d_expr_values;
+ std::string d_str_value;
public:
SetUserAttributeCommand( const std::string& attr, Expr expr ) throw();
- //SetUserAttributeCommand( const std::string& id, Expr expr, std::vector<Expr>& values ) throw();
- //SetUserAttributeCommand( const std::string& id, Expr expr, std::string& value ) throw();
+ SetUserAttributeCommand( const std::string& attr, Expr expr, std::vector<Expr>& values ) throw();
+ SetUserAttributeCommand( const std::string& attr, Expr expr, const std::string& value ) throw();
~SetUserAttributeCommand() throw() {}
void invoke(SmtEngine* smtEngine) throw();
Command* exportTo(ExprManager* exprManager, ExprManagerMapCollection& variableMap);
@@ -452,14 +454,14 @@ public:
std::string getCommandName() const throw();
};/* class SetUserAttributeCommand */
-
class CVC4_PUBLIC CheckSatCommand : public Command {
protected:
Expr d_expr;
Result d_result;
+ bool d_inUnsatCore;
public:
CheckSatCommand() throw();
- CheckSatCommand(const Expr& expr) throw();
+ CheckSatCommand(const Expr& expr, bool inUnsatCore = true) throw();
~CheckSatCommand() throw() {}
Expr getExpr() const throw();
void invoke(SmtEngine* smtEngine) throw();
@@ -474,8 +476,9 @@ class CVC4_PUBLIC QueryCommand : public Command {
protected:
Expr d_expr;
Result d_result;
+ bool d_inUnsatCore;
public:
- QueryCommand(const Expr& e) throw();
+ QueryCommand(const Expr& e, bool inUnsatCore = true) throw();
~QueryCommand() throw() {}
Expr getExpr() const throw();
void invoke(SmtEngine* smtEngine) throw();
@@ -597,12 +600,15 @@ public:
class CVC4_PUBLIC GetUnsatCoreCommand : public Command {
protected:
- //UnsatCore* d_result;
+ UnsatCore d_result;
+ std::map<Expr, std::string> d_names;
public:
GetUnsatCoreCommand() throw();
+ GetUnsatCoreCommand(const std::map<Expr, std::string>& names) throw();
~GetUnsatCoreCommand() throw() {}
void invoke(SmtEngine* smtEngine) throw();
void printResult(std::ostream& out, uint32_t verbosity = 2) const throw();
+ const UnsatCore& getUnsatCore() const throw();
Command* exportTo(ExprManager* exprManager, ExprManagerMapCollection& variableMap);
Command* clone() const;
std::string getCommandName() const throw();
@@ -791,10 +797,29 @@ public:
std::string getCommandName() const throw();
};/* class PropagateRuleCommand */
+class CVC4_PUBLIC ResetCommand : public Command {
+public:
+ ResetCommand() throw() {}
+ ~ResetCommand() throw() {}
+ void invoke(SmtEngine* smtEngine) throw();
+ Command* exportTo(ExprManager* exprManager, ExprManagerMapCollection& variableMap);
+ Command* clone() const;
+ std::string getCommandName() const throw();
+};/* class ResetCommand */
+
+class CVC4_PUBLIC ResetAssertionsCommand : public Command {
+public:
+ ResetAssertionsCommand() throw() {}
+ ~ResetAssertionsCommand() throw() {}
+ void invoke(SmtEngine* smtEngine) throw();
+ Command* exportTo(ExprManager* exprManager, ExprManagerMapCollection& variableMap);
+ Command* clone() const;
+ std::string getCommandName() const throw();
+};/* class ResetAssertionsCommand */
class CVC4_PUBLIC QuitCommand : public Command {
public:
- QuitCommand() throw();
+ QuitCommand() throw() {}
~QuitCommand() throw() {}
void invoke(SmtEngine* smtEngine) throw();
Command* exportTo(ExprManager* exprManager, ExprManagerMapCollection& variableMap);
diff --git a/src/expr/expr_manager_template.cpp b/src/expr/expr_manager_template.cpp
index 8bcfd58ba..fb9da3e37 100644
--- a/src/expr/expr_manager_template.cpp
+++ b/src/expr/expr_manager_template.cpp
@@ -17,7 +17,6 @@
#include "expr/node_manager.h"
#include "expr/expr_manager.h"
#include "expr/variable_type_map.h"
-#include "context/context.h"
#include "options/options.h"
#include "util/statistics_registry.h"
@@ -29,7 +28,7 @@ ${includes}
// compiler directs the user to the template file instead of the
// generated one. We don't want the user to modify the generated one,
// since it'll get overwritten on a later build.
-#line 33 "${template}"
+#line 32 "${template}"
#ifdef CVC4_STATISTICS_ON
#define INC_STAT(kind) \
@@ -64,14 +63,12 @@ ${includes}
#endif
using namespace std;
-using namespace CVC4::context;
using namespace CVC4::kind;
namespace CVC4 {
ExprManager::ExprManager() :
- d_ctxt(new Context()),
- d_nodeManager(new NodeManager(d_ctxt, this)) {
+ d_nodeManager(new NodeManager(this)) {
#ifdef CVC4_STATISTICS_ON
for (unsigned i = 0; i < kind::LAST_KIND; ++ i) {
d_exprStatistics[i] = NULL;
@@ -83,8 +80,7 @@ ExprManager::ExprManager() :
}
ExprManager::ExprManager(const Options& options) :
- d_ctxt(new Context()),
- d_nodeManager(new NodeManager(d_ctxt, this, options)) {
+ d_nodeManager(new NodeManager(this, options)) {
#ifdef CVC4_STATISTICS_ON
for (unsigned i = 0; i < LAST_TYPE; ++ i) {
d_exprStatisticsVars[i] = NULL;
@@ -119,8 +115,6 @@ ExprManager::~ExprManager() throw() {
delete d_nodeManager;
d_nodeManager = NULL;
- delete d_ctxt;
- d_ctxt = NULL;
} catch(Exception& e) {
Warning() << "CVC4 threw an exception during cleanup." << std::endl
@@ -962,10 +956,6 @@ NodeManager* ExprManager::getNodeManager() const {
return d_nodeManager;
}
-Context* ExprManager::getContext() const {
- return d_ctxt;
-}
-
Statistics ExprManager::getStatistics() const throw() {
return Statistics(*d_nodeManager->getStatisticsRegistry());
}
diff --git a/src/expr/expr_manager_template.h b/src/expr/expr_manager_template.h
index 49094c593..deb2f6918 100644
--- a/src/expr/expr_manager_template.h
+++ b/src/expr/expr_manager_template.h
@@ -52,19 +52,12 @@ namespace expr {
}/* CVC4::expr::pickle namespace */
}/* CVC4::expr namespace */
-namespace context {
- class Context;
-}/* CVC4::context namespace */
-
namespace stats {
StatisticsRegistry* getStatisticsRegistry(ExprManager*);
}/* CVC4::stats namespace */
class CVC4_PUBLIC ExprManager {
private:
- /** The context */
- context::Context* d_ctxt;
-
/** The internal node manager */
NodeManager* d_nodeManager;
@@ -79,12 +72,6 @@ private:
NodeManager* getNodeManager() const;
/**
- * Returns the internal Context. Used by internal users, i.e. the
- * friend classes.
- */
- context::Context* getContext() const;
-
- /**
* Check some things about a newly-created DatatypeType.
*/
void checkResolvedDatatype(DatatypeType dtt) const;
diff --git a/src/expr/expr_template.cpp b/src/expr/expr_template.cpp
index 809064413..47042b458 100644
--- a/src/expr/expr_template.cpp
+++ b/src/expr/expr_template.cpp
@@ -114,7 +114,7 @@ ExprManager* Expr::getExprManager() const {
namespace expr {
-static Node exportConstant(TNode n, NodeManager* to);
+static Node exportConstant(TNode n, NodeManager* to, ExprManagerMapCollection& vmap);
class ExportPrivate {
private:
@@ -139,7 +139,7 @@ public:
Type type = from->exportType(n.getConst< ::CVC4::EmptySet >().getType(), to, vmap);
return to->mkConst(::CVC4::EmptySet(type));
}
- return exportConstant(n, NodeManager::fromExprManager(to));
+ return exportConstant(n, NodeManager::fromExprManager(to), vmap);
} else if(n.isVar()) {
Expr from_e(from, new Node(n));
Expr& to_e = vmap.d_typeMap[from_e];
@@ -574,14 +574,29 @@ ${getConst_implementations}
namespace expr {
-static Node exportConstant(TNode n, NodeManager* to) {
+static Node exportConstant(TNode n, NodeManager* to, ExprManagerMapCollection& vmap) {
Assert(n.isConst());
Debug("export") << "constant: " << n << std::endl;
+
+ if(n.getKind() == kind::STORE_ALL) {
+ // Special export for ArrayStoreAll.
+ //
+ // Ultimately we'll need special cases also for RecordUpdate,
+ // TupleUpdate, AscriptionType, and other constant-metakinded
+ // expressions that embed types. For now datatypes aren't supported
+ // for export so those don't matter.
+ ExprManager* toEm = to->toExprManager();
+ const ArrayStoreAll& asa = n.getConst<ArrayStoreAll>();
+ return to->mkConst(ArrayStoreAll(asa.getType().exportTo(toEm, vmap),
+ asa.getExpr().exportTo(toEm, vmap)));
+ }
+
switch(n.getKind()) {
${exportConstant_cases}
default: Unhandled(n.getKind());
}
+
}/* exportConstant() */
}/* CVC4::expr namespace */
diff --git a/src/expr/expr_template.h b/src/expr/expr_template.h
index c5e8e77de..d769ed109 100644
--- a/src/expr/expr_template.h
+++ b/src/expr/expr_template.h
@@ -985,7 +985,7 @@ inline std::ostream& operator<<(std::ostream& out, ExprDag d) {
* Use like this:
*
* // let out be an ostream, e an Expr
- * out << Expr::setlanguage(LANG_SMTLIB_V2) << e << endl;
+ * out << Expr::setlanguage(LANG_SMTLIB_V2_5) << e << endl;
*
* The setting stays permanently (until set again) with the stream.
*/
diff --git a/src/expr/node.h b/src/expr/node.h
index 35f94b9e3..080034e70 100644
--- a/src/expr/node.h
+++ b/src/expr/node.h
@@ -149,6 +149,7 @@ class NodeValue;
namespace attr {
class AttributeManager;
+ struct SmtAttributes;
}/* CVC4::expr::attr namespace */
class ExprSetDepth;
@@ -214,6 +215,7 @@ class NodeTemplate {
friend class NodeBuilder;
friend class ::CVC4::expr::attr::AttributeManager;
+ friend struct ::CVC4::expr::attr::SmtAttributes;
friend struct ::CVC4::kind::metakind::NodeValueConstPrinter;
diff --git a/src/expr/node_manager.cpp b/src/expr/node_manager.cpp
index fb1284d0d..31b17ccda 100644
--- a/src/expr/node_manager.cpp
+++ b/src/expr/node_manager.cpp
@@ -80,12 +80,11 @@ struct NVReclaim {
}
};
-NodeManager::NodeManager(context::Context* ctxt,
- ExprManager* exprManager) :
+NodeManager::NodeManager(ExprManager* exprManager) :
d_options(new Options()),
d_statisticsRegistry(new StatisticsRegistry()),
next_id(0),
- d_attrManager(new expr::attr::AttributeManager(ctxt)),
+ d_attrManager(new expr::attr::AttributeManager()),
d_exprManager(exprManager),
d_nodeUnderDeletion(NULL),
d_inReclaimZombies(false),
@@ -94,13 +93,12 @@ NodeManager::NodeManager(context::Context* ctxt,
init();
}
-NodeManager::NodeManager(context::Context* ctxt,
- ExprManager* exprManager,
+NodeManager::NodeManager(ExprManager* exprManager,
const Options& options) :
d_options(new Options(options)),
d_statisticsRegistry(new StatisticsRegistry()),
next_id(0),
- d_attrManager(new expr::attr::AttributeManager(ctxt)),
+ d_attrManager(new expr::attr::AttributeManager()),
d_exprManager(exprManager),
d_nodeUnderDeletion(NULL),
d_inReclaimZombies(false),
@@ -129,6 +127,8 @@ NodeManager::~NodeManager() {
{
ScopedBool dontGC(d_inReclaimZombies);
+ // hopefully by this point all SmtEngines have been deleted
+ // already, along with all their attributes
d_attrManager->deleteAllAttributes();
}
@@ -229,6 +229,18 @@ void NodeManager::reclaimZombies() {
d_nodeUnderDeletion = nv;
// remove attributes
+ { // notify listeners of deleted node
+ TNode n;
+ n.d_nv = nv;
+ nv->d_rc = 1; // so that TNode doesn't assert-fail
+ for(vector<NodeManagerListener*>::iterator i = d_listeners.begin(); i != d_listeners.end(); ++i) {
+ (*i)->nmNotifyDeleteNode(n);
+ }
+ // this would mean that one of the listeners stowed away
+ // a reference to this node!
+ Assert(nv->d_rc == 1);
+ }
+ nv->d_rc = 0;
d_attrManager->deleteAllAttributes(nv);
// decr ref counts of children
diff --git a/src/expr/node_manager.h b/src/expr/node_manager.h
index 0aa222294..d4d89109c 100644
--- a/src/expr/node_manager.h
+++ b/src/expr/node_manager.h
@@ -35,7 +35,6 @@
#include "expr/kind.h"
#include "expr/metakind.h"
#include "expr/node_value.h"
-#include "context/context.h"
#include "util/subrange_bound.h"
#include "util/tls.h"
#include "options/options.h"
@@ -66,6 +65,11 @@ public:
virtual void nmNotifyNewDatatypes(const std::vector<DatatypeType>& datatypes) { }
virtual void nmNotifyNewVar(TNode n, uint32_t flags) { }
virtual void nmNotifyNewSkolem(TNode n, const std::string& comment, uint32_t flags) { }
+ /**
+ * Notify a listener of a Node that's being GCed. If this function stores a reference
+ * to the Node somewhere, very bad things will happen.
+ */
+ virtual void nmNotifyDeleteNode(TNode n) { }
};/* class NodeManagerListener */
class NodeManager {
@@ -307,8 +311,8 @@ class NodeManager {
public:
- explicit NodeManager(context::Context* ctxt, ExprManager* exprManager);
- explicit NodeManager(context::Context* ctxt, ExprManager* exprManager, const Options& options);
+ explicit NodeManager(ExprManager* exprManager);
+ explicit NodeManager(ExprManager* exprManager, const Options& options);
~NodeManager();
/** The node manager in the current public-facing CVC4 library context */
diff --git a/src/expr/options b/src/expr/options
index ee4d40b2c..b4608832f 100644
--- a/src/expr/options
+++ b/src/expr/options
@@ -7,12 +7,12 @@ module EXPR "expr/options.h" Expression package
option defaultExprDepth --default-expr-depth=N int :default 0 :predicate CVC4::expr::setDefaultExprDepth :predicate-include "expr/options_handlers.h"
print exprs to depth N (0 == default, -1 == no limit)
-undocumented-alias --expr-depth = --default-expr-depth
+undocumented-alias --expr-depth=N = --default-expr-depth=N
option defaultDagThresh default-dag-thresh --default-dag-thresh=N int :default 1 :predicate CVC4::expr::setDefaultDagThresh :predicate-include "expr/options_handlers.h"
dagify common subexprs appearing > N times (1 == default, 0 == don't dagify)
-undocumented-alias --dag-thresh = --default-dag-thresh
-undocumented-alias --dag-threshold = --default-dag-thresh
+undocumented-alias --dag-thresh=N = --default-dag-thresh=N
+undocumented-alias --dag-threshold=N = --default-dag-thresh=N
option - --print-expr-types void :handler CVC4::expr::setPrintExprTypes :handler-include "expr/options_handlers.h"
print types with variables when printing exprs
diff --git a/src/expr/symbol_table.cpp b/src/expr/symbol_table.cpp
index ce7d571db..3d53f2e44 100644
--- a/src/expr/symbol_table.cpp
+++ b/src/expr/symbol_table.cpp
@@ -34,7 +34,7 @@ using namespace std;
namespace CVC4 {
SymbolTable::SymbolTable() :
- d_context(new Context),
+ d_context(new Context()),
d_exprMap(new(true) CDHashMap<std::string, Expr, StringHashFunction>(d_context)),
d_typeMap(new(true) CDHashMap<std::string, pair<vector<Type>, Type>, StringHashFunction>(d_context)),
d_functions(new(true) CDHashSet<Expr, ExprHashFunction>(d_context)) {
@@ -206,4 +206,9 @@ size_t SymbolTable::getLevel() const throw() {
return d_context->getLevel();
}
+void SymbolTable::reset() {
+ this->SymbolTable::~SymbolTable();
+ new(this) SymbolTable();
+}
+
}/* CVC4 namespace */
diff --git a/src/expr/symbol_table.h b/src/expr/symbol_table.h
index a9ab43cfe..451a482dc 100644
--- a/src/expr/symbol_table.h
+++ b/src/expr/symbol_table.h
@@ -198,6 +198,9 @@ public:
/** Get the current level of this symbol table. */
size_t getLevel() const throw();
+ /** Reset everything. */
+ void reset();
+
};/* class SymbolTable */
}/* CVC4 namespace */
diff --git a/src/main/command_executor.cpp b/src/main/command_executor.cpp
index 5b90ca14f..52522d591 100644
--- a/src/main/command_executor.cpp
+++ b/src/main/command_executor.cpp
@@ -22,6 +22,7 @@
#include "main/options.h"
#include "smt/options.h"
+#include "printer/options.h"
#ifndef __WIN32__
# include <sys/resource.h>
@@ -46,7 +47,6 @@ void setNoLimitCPU() {
#endif /* ! __WIN32__ */
}
-
void printStatsIncremental(std::ostream& out, const std::string& prvsStatsString, const std::string& curStatsString);
CommandExecutor::CommandExecutor(ExprManager &exprMgr, Options &options) :
@@ -119,24 +119,31 @@ bool CommandExecutor::doCommandSingleton(Command* cmd)
d_lastStatistics = ossCurStats.str();
}
- // dump the model/proof if option is set
+ // dump the model/proof/unsat core if option is set
if(status) {
- Command * g = NULL;
+ Command* g = NULL;
if( d_options[options::produceModels] &&
d_options[options::dumpModels] &&
( res.asSatisfiabilityResult() == Result::SAT ||
(res.isUnknown() && res.whyUnknown() == Result::INCOMPLETE) ) ) {
g = new GetModelCommand();
- } else if( d_options[options::proof] &&
- d_options[options::dumpProofs] &&
- res.asSatisfiabilityResult() == Result::UNSAT ) {
+ }
+ if( d_options[options::proof] &&
+ d_options[options::dumpProofs] &&
+ res.asSatisfiabilityResult() == Result::UNSAT ) {
g = new GetProofCommand();
- } else if( d_options[options::dumpInstantiations] &&
- res.asSatisfiabilityResult() == Result::UNSAT ) {
+ }
+ if( d_options[options::dumpInstantiations] &&
+ ( ( d_options[options::instFormatMode] != INST_FORMAT_MODE_SZS &&
+ ( res.asSatisfiabilityResult() == Result::SAT || (res.isUnknown() && res.whyUnknown() == Result::INCOMPLETE) ) ) ||
+ res.asSatisfiabilityResult() == Result::UNSAT ) ) {
g = new GetInstantiationsCommand();
}
- if( g ){
- //set no time limit during dumping if applicable
+ if( d_options[options::dumpUnsatCores] && res.asSatisfiabilityResult() == Result::UNSAT ) {
+ g = new GetUnsatCoreCommand();
+ }
+ if(g != NULL) {
+ // set no time limit during dumping if applicable
if( d_options[options::forceNoLimitCpuWhileDump] ){
setNoLimitCPU();
}
@@ -162,12 +169,12 @@ bool smtEngineInvoke(SmtEngine* smt, Command* cmd, std::ostream *out)
void printStatsIncremental(std::ostream& out, const std::string& prvsStatsString, const std::string& curStatsString) {
if(prvsStatsString == "") {
- out << curStatsString;
- return;
+ out << curStatsString;
+ return;
}
// read each line
- // if a number, subtract and add that to parantheses
+ // if a number, subtract and add that to parentheses
std::istringstream issPrvs(prvsStatsString);
std::istringstream issCur(curStatsString);
diff --git a/src/main/command_executor_portfolio.cpp b/src/main/command_executor_portfolio.cpp
index 36f2abdd2..610902270 100644
--- a/src/main/command_executor_portfolio.cpp
+++ b/src/main/command_executor_portfolio.cpp
@@ -11,7 +11,7 @@
**
** \brief An additional layer between commands and invoking them.
**
- ** The portfolio executer branches check-sat queries to several
+ ** The portfolio executor branches check-sat queries to several
** threads.
**/
@@ -29,6 +29,7 @@
#include "main/portfolio.h"
#include "options/options.h"
#include "smt/options.h"
+#include "printer/options.h"
#include "cvc4autoconfig.h"
@@ -62,7 +63,7 @@ CommandExecutorPortfolio::CommandExecutorPortfolio
d_stats.registerStat_(&d_statLastWinner);
d_stats.registerStat_(&d_statWaitTime);
- /* Duplication, Individualisation */
+ /* Duplication, individualization */
d_exprMgrs.push_back(&d_exprMgr);
for(unsigned i = 1; i < d_numThreads; ++i) {
d_exprMgrs.push_back(new ExprManager(d_threadOptions[i]));
@@ -201,6 +202,7 @@ bool CommandExecutorPortfolio::doCommandSingleton(Command* cmd)
dynamic_cast<GetAssignmentCommand*>(cmd) != NULL ||
dynamic_cast<GetModelCommand*>(cmd) != NULL ||
dynamic_cast<GetProofCommand*>(cmd) != NULL ||
+ dynamic_cast<GetInstantiationsCommand*>(cmd) != NULL ||
dynamic_cast<GetUnsatCoreCommand*>(cmd) != NULL ||
dynamic_cast<GetAssertionsCommand*>(cmd) != NULL ||
dynamic_cast<GetInfoCommand*>(cmd) != NULL ||
@@ -357,7 +359,7 @@ bool CommandExecutorPortfolio::doCommandSingleton(Command* cmd)
bool status = portfolioReturn.second;
- // dump the model/proof if option is set
+ // dump the model/proof/unsat core if option is set
if(status) {
if( d_options[options::produceModels] &&
d_options[options::dumpModels] &&
@@ -371,9 +373,15 @@ bool CommandExecutorPortfolio::doCommandSingleton(Command* cmd)
Command* gp = new GetProofCommand();
status = doCommandSingleton(gp);
} else if( d_options[options::dumpInstantiations] &&
- d_result.asSatisfiabilityResult() == Result::UNSAT ) {
+ ( ( d_options[options::instFormatMode]!=INST_FORMAT_MODE_SZS &&
+ ( d_result.asSatisfiabilityResult() == Result::SAT || (d_result.isUnknown() && d_result.whyUnknown() == Result::INCOMPLETE) ) ) ||
+ d_result.asSatisfiabilityResult() == Result::UNSAT ) ) {
Command* gi = new GetInstantiationsCommand();
status = doCommandSingleton(gi);
+ } else if( d_options[options::dumpUnsatCores] &&
+ d_result.asSatisfiabilityResult() == Result::UNSAT ) {
+ Command* guc = new GetUnsatCoreCommand();
+ status = doCommandSingleton(guc);
}
}
diff --git a/src/main/driver_unified.cpp b/src/main/driver_unified.cpp
index 1f3988753..f9b222b2b 100644
--- a/src/main/driver_unified.cpp
+++ b/src/main/driver_unified.cpp
@@ -35,9 +35,11 @@
#include "util/configuration.h"
#include "options/options.h"
#include "main/command_executor.h"
-# ifdef PORTFOLIO_BUILD
-# include "main/command_executor_portfolio.h"
-# endif
+
+#ifdef PORTFOLIO_BUILD
+# include "main/command_executor_portfolio.h"
+#endif
+
#include "main/options.h"
#include "smt/options.h"
#include "util/output.h"
@@ -185,7 +187,7 @@ int runCvc4(int argc, char* argv[], Options& opts) {
} else {
unsigned len = strlen(filename);
if(len >= 5 && !strcmp(".smt2", filename + len - 5)) {
- opts.set(options::inputLanguage, language::input::LANG_SMTLIB_V2);
+ opts.set(options::inputLanguage, language::input::LANG_SMTLIB_V2_5);
} else if(len >= 4 && !strcmp(".smt", filename + len - 4)) {
opts.set(options::inputLanguage, language::input::LANG_SMTLIB_V1);
} else if(len >= 5 && !strcmp(".smt1", filename + len - 5)) {
@@ -267,15 +269,8 @@ int runCvc4(int argc, char* argv[], Options& opts) {
Command* cmd;
bool status = true;
if(opts[options::interactive] && inputFromStdin) {
- if(opts[options::tearDownIncremental] && opts[options::incrementalSolving]) {
- if(opts.wasSetByUser(options::incrementalSolving)) {
- throw OptionException("--tear-down-incremental incompatible with --incremental");
- }
-
- cmd = new SetOptionCommand("incremental", false);
- cmd->setMuted(true);
- pExecutor->doCommand(cmd);
- delete cmd;
+ if(opts[options::tearDownIncremental]) {
+ throw OptionException("--tear-down-incremental doesn't work in interactive mode");
}
#ifndef PORTFOLIO_BUILD
if(!opts.wasSetByUser(options::incrementalSolving)) {
@@ -380,6 +375,10 @@ int runCvc4(int argc, char* argv[], Options& opts) {
}
status = pExecutor->doCommand(cmd);
needReset = true;
+ } else if(dynamic_cast<ResetCommand*>(cmd) != NULL) {
+ pExecutor->doCommand(cmd);
+ allCommands.clear();
+ allCommands.push_back(vector<Command*>());
} else {
// We shouldn't copy certain commands, because they can cause
// an error on replay since there's no associated sat/unsat check
@@ -389,7 +388,10 @@ int runCvc4(int argc, char* argv[], Options& opts) {
dynamic_cast<GetValueCommand*>(cmd) == NULL &&
dynamic_cast<GetModelCommand*>(cmd) == NULL &&
dynamic_cast<GetAssignmentCommand*>(cmd) == NULL &&
- dynamic_cast<GetInstantiationsCommand*>(cmd) == NULL) {
+ dynamic_cast<GetInstantiationsCommand*>(cmd) == NULL &&
+ dynamic_cast<GetAssertionsCommand*>(cmd) == NULL &&
+ dynamic_cast<GetInfoCommand*>(cmd) == NULL &&
+ dynamic_cast<GetOptionCommand*>(cmd) == NULL) {
Command* copy = cmd->clone();
allCommands.back().push_back(copy);
}
diff --git a/src/main/interactive_shell.cpp b/src/main/interactive_shell.cpp
index bdc956535..0aee195e4 100644
--- a/src/main/interactive_shell.cpp
+++ b/src/main/interactive_shell.cpp
@@ -123,7 +123,8 @@ InteractiveShell::InteractiveShell(ExprManager& exprManager,
commandsBegin = smt1_commands;
commandsEnd = smt1_commands + sizeof(smt1_commands) / sizeof(*smt1_commands);
break;
- case output::LANG_SMTLIB_V2:
+ case output::LANG_SMTLIB_V2_0:
+ case output::LANG_SMTLIB_V2_5:
d_historyFilename = string(getenv("HOME")) + "/.cvc4_history_smtlib2";
commandsBegin = smt2_commands;
commandsEnd = smt2_commands + sizeof(smt2_commands) / sizeof(*smt2_commands);
@@ -323,7 +324,8 @@ restart:
line += "\n";
goto restart;
} catch(ParserException& pe) {
- if(d_options[options::outputLanguage] == output::LANG_SMTLIB_V2) {
+ if(d_options[options::outputLanguage] == output::LANG_SMTLIB_V2_0 ||
+ d_options[options::outputLanguage] == output::LANG_SMTLIB_V2_5) {
d_out << "(error \"" << pe << "\")" << endl;
} else {
d_out << pe << endl;
diff --git a/src/main/main.cpp b/src/main/main.cpp
index ca7266b59..a70c3c7c3 100644
--- a/src/main/main.cpp
+++ b/src/main/main.cpp
@@ -65,7 +65,8 @@ int main(int argc, char* argv[]) {
#ifdef CVC4_COMPETITION_MODE
*opts[options::out] << "unknown" << endl;
#endif
- if(opts[options::outputLanguage] == output::LANG_SMTLIB_V2) {
+ if(opts[options::outputLanguage] == output::LANG_SMTLIB_V2_0 ||
+ opts[options::outputLanguage] == output::LANG_SMTLIB_V2_5) {
*opts[options::err] << "(error \"" << e << "\")" << endl;
} else {
*opts[options::err] << "CVC4 Error:" << endl << e << endl;
diff --git a/src/main/options b/src/main/options
index b9262bfa4..18cc08ed7 100644
--- a/src/main/options
+++ b/src/main/options
@@ -41,6 +41,8 @@ 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 interactive : --interactive bool :read-write
+ force interactive/non-interactive mode
undocumented-option interactivePrompt /--no-interactive-prompt bool :default true
turn off interactive prompting while in interactive mode
@@ -52,7 +54,7 @@ option segvSpin --segv-spin bool :default false
spin on segfault/other crash waiting for gdb
undocumented-alias --segv-nospin = --no-segv-spin
-expert-option tearDownIncremental --tear-down-incremental bool :default false
+expert-option tearDownIncremental : --tear-down-incremental bool :default false
implement PUSH/POP/multi-query by destroying and recreating SmtEngine
expert-option waitToJoin --wait-to-join bool :default true
diff --git a/src/options/mkoptions b/src/options/mkoptions
index a3a1571ec..03d7837ac 100755
--- a/src/options/mkoptions
+++ b/src/options/mkoptions
@@ -352,6 +352,10 @@ function handle_option {
WARN "$internal is inaccessible via SmtEngine (no smt name for option) but can be set via command-line: $long_option $short_option $long_option_alternate $short_option_alternate"
fi
fi
+ # in options files, use an smt name of ":" to force there not to be one
+ if [ "$smtname" = : ]; then
+ smtname=
+ fi
# check for duplicates
if [ "$internal" != - ]; then
diff --git a/src/options/options.h b/src/options/options.h
index b41c9a66e..092fbe507 100644
--- a/src/options/options.h
+++ b/src/options/options.h
@@ -69,6 +69,8 @@ public:
Options(const Options& options);
~Options();
+ Options& operator=(const Options& options);
+
/**
* Set the value of the given option. Use of this default
* implementation causes a compile-time error; write-able
diff --git a/src/options/options_template.cpp b/src/options/options_template.cpp
index bd723e380..f6c6846e5 100644
--- a/src/options/options_template.cpp
+++ b/src/options/options_template.cpp
@@ -226,6 +226,14 @@ Options::~Options() {
delete d_holder;
}
+Options& Options::operator=(const Options& options) {
+ if(this != &options) {
+ delete d_holder;
+ d_holder = new options::OptionsHolder(*options.d_holder);
+ }
+ return *this;
+}
+
options::OptionsHolder::OptionsHolder() : ${all_modules_defaults}
{
}
@@ -253,7 +261,9 @@ Languages currently supported as arguments to the -L / --lang option:\n\
auto attempt to automatically determine language\n\
cvc4 | presentation | pl CVC4 presentation language\n\
smt1 | smtlib1 SMT-LIB format 1.2\n\
- smt | smtlib | smt2 | smtlib2 SMT-LIB format 2.0\n\
+ smt | smtlib | smt2 |\n\
+ smt2.0 | smtlib2 | smtlib2.0 SMT-LIB format 2.0\n\
+ smt2.5 | smtlib2.5 SMT-LIB format 2.5\n\
tptp TPTP format (cnf and fof)\n\
\n\
Languages currently supported as arguments to the --output-lang option:\n\
@@ -261,7 +271,9 @@ Languages currently supported as arguments to the --output-lang option:\n\
cvc4 | presentation | pl CVC4 presentation language\n\
cvc3 CVC3 presentation language\n\
smt1 | smtlib1 SMT-LIB format 1.2\n\
- smt | smtlib | smt2 | smtlib2 SMT-LIB format 2.0\n\
+ smt | smtlib | smt2 |\n\
+ smt2.0 | smtlib2.0 | smtlib2 SMT-LIB format 2.0\n\
+ smt2.5 | smtlib2.5 SMT-LIB format 2.5\n\
z3str SMT-LIB 2.0 with Z3-str string constraints\n\
tptp TPTP format\n\
ast internal format (simple syntax trees)\n\
@@ -314,7 +326,7 @@ static struct option cmdlineOptions[] = {${all_modules_long_options}
{ NULL, no_argument, NULL, '\0' }
};/* cmdlineOptions */
-#line 318 "${template}"
+#line 322 "${template}"
static void preemptGetopt(int& argc, char**& argv, const char* opt) {
const size_t maxoptlen = 128;
@@ -507,7 +519,7 @@ std::vector<std::string> Options::parseOptions(int argc, char* main_argv[]) thro
switch(c) {
${all_modules_option_handlers}
-#line 511 "${template}"
+#line 515 "${template}"
case ':':
// This can be a long or short option, and the way to get at the
@@ -576,7 +588,7 @@ std::string Options::suggestCommandLineOptions(const std::string& optionName) th
static const char* smtOptions[] = {
${all_modules_smt_options},
-#line 580 "${template}"
+#line 584 "${template}"
NULL
};/* smtOptions[] */
@@ -598,7 +610,7 @@ SExpr Options::getOptions() const throw() {
${all_modules_get_options}
-#line 602 "${template}"
+#line 606 "${template}"
return SExpr(opts);
}
diff --git a/src/parser/Makefile.am b/src/parser/Makefile.am
index a178f8dd5..c8a8cc941 100644
--- a/src/parser/Makefile.am
+++ b/src/parser/Makefile.am
@@ -29,7 +29,7 @@ libcvc4parser_la_LIBADD = \
@builddir@/smt2/libparsersmt2.la \
@builddir@/tptp/libparsertptp.la \
@builddir@/cvc/libparsercvc.la \
- -L@builddir@/.. -lcvc4
+ @builddir@/../libcvc4.la
if CVC4_NEEDS_REPLACEMENT_FUNCTIONS
libcvc4parser_la_LIBADD += \
diff --git a/src/parser/antlr_input.cpp b/src/parser/antlr_input.cpp
index aa431ef42..f8730e372 100644
--- a/src/parser/antlr_input.cpp
+++ b/src/parser/antlr_input.cpp
@@ -201,8 +201,9 @@ AntlrInput* AntlrInput::newInput(InputLanguage lang, AntlrInputStream& inputStre
input = new Smt1Input(inputStream);
break;
- case LANG_SMTLIB_V2:
- input = new Smt2Input(inputStream);
+ case LANG_SMTLIB_V2_0:
+ case LANG_SMTLIB_V2_5:
+ input = new Smt2Input(inputStream, lang);
break;
case LANG_TPTP:
diff --git a/src/parser/cvc/Cvc.g b/src/parser/cvc/Cvc.g
index 79db2b629..2b442015a 100644
--- a/src/parser/cvc/Cvc.g
+++ b/src/parser/cvc/Cvc.g
@@ -65,6 +65,7 @@ tokens {
EXIT_TOK = 'EXIT';
INCLUDE_TOK = 'INCLUDE';
DUMP_PROOF_TOK = 'DUMP_PROOF';
+ DUMP_UNSAT_CORE_TOK = 'DUMP_UNSAT_CORE';
DUMP_ASSUMPTIONS_TOK = 'DUMP_ASSUMPTIONS';
DUMP_SIG_TOK = 'DUMP_SIG';
DUMP_TCC_TOK = 'DUMP_TCC';
@@ -697,7 +698,14 @@ mainCommand[CVC4::Command*& cmd]
{ UNSUPPORTED("POPTO_SCOPE command"); }
| RESET_TOK
- { UNSUPPORTED("RESET command"); }
+ { cmd = new ResetCommand();
+ PARSER_STATE->reset();
+ }
+
+ | RESET_TOK ASSERTIONS_TOK
+ { cmd = new ResetAssertionsCommand();
+ PARSER_STATE->reset();
+ }
// Datatypes can be mututally-recursive if they're in the same
// definition block, separated by a comma. So we parse everything
@@ -793,6 +801,9 @@ mainCommand[CVC4::Command*& cmd]
| DUMP_PROOF_TOK
{ cmd = new GetProofCommand(); }
+ | DUMP_UNSAT_CORE_TOK
+ { cmd = new GetUnsatCoreCommand(); }
+
| ( DUMP_ASSUMPTIONS_TOK
| DUMP_SIG_TOK
| DUMP_TCC_TOK
@@ -1375,14 +1386,6 @@ prefixFormula[CVC4::Expr& f]
PARSER_STATE->preemptCommand(cmd);
f = func;
}
-
- /* array literals */
- | ARRAY_TOK { PARSER_STATE->pushScope(); } LPAREN
- 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()), ExprManager::VAR_FLAG_GLOBAL);
- }
;
instantiationPatterns[ CVC4::Expr& expr ]
@@ -1467,10 +1470,6 @@ arithmeticBinop[unsigned& op]
| EXP_TOK
;
-moreArrayStores[CVC4::Expr& f]
- : COMMA arrayStore[f]
- ;
-
/** Parses an array/tuple/record assignment term. */
term[CVC4::Expr& f]
@init {
@@ -1904,7 +1903,7 @@ simpleTerm[CVC4::Expr& f]
std::vector<std::string> names;
Expr e;
Debug("parser-extra") << "term: " << AntlrInput::tokenText(LT(1)) << std::endl;
- Type t;
+ Type t, t2;
}
/* if-then-else */
: iteTerm[f]
@@ -1934,7 +1933,6 @@ simpleTerm[CVC4::Expr& f]
f = MK_EXPR(kind::RECORD, MK_CONST(t.getRecord()), std::vector<Expr>());
}
-
/* empty set literal */
| LBRACE RBRACE
{ f = MK_CONST(EmptySet(Type())); }
@@ -1948,6 +1946,32 @@ simpleTerm[CVC4::Expr& f]
}
}
+ /* array literals */
+ | ARRAY_TOK /* { PARSER_STATE->pushScope(); } */ LPAREN
+ restrictedType[t, CHECK_DECLARED] OF_TOK restrictedType[t2, CHECK_DECLARED]
+ RPAREN COLON simpleTerm[f]
+ { /* Eventually if we support a bound var (like a lambda) for array
+ * literals, we can use the push/pop scope. */
+ /* PARSER_STATE->popScope(); */
+ t = EXPR_MANAGER->mkArrayType(t, t2);
+ if(!f.isConst()) {
+ std::stringstream ss;
+ ss << "expected constant term inside array constant, but found "
+ << "nonconstant term" << std::endl
+ << "the term: " << f;
+ PARSER_STATE->parseError(ss.str());
+ }
+ if(!t2.isComparableTo(f.getType())) {
+ std::stringstream ss;
+ ss << "type mismatch inside array constant term:" << std::endl
+ << "array type: " << t << std::endl
+ << "expected const type: " << t2 << std::endl
+ << "computed const type: " << f.getType();
+ PARSER_STATE->parseError(ss.str());
+ }
+ f = MK_CONST( ArrayStoreAll(t, f) );
+ }
+
/* boolean literals */
| TRUE_TOK { f = MK_CONST(bool(true)); }
| FALSE_TOK { f = MK_CONST(bool(false)); }
@@ -1992,7 +2016,7 @@ simpleTerm[CVC4::Expr& f]
;
/**
- * Matches (and performs) a type ascription.
+ * Matches a type ascription.
* The f arg is the term to check (it is an input-only argument).
*/
typeAscription[const CVC4::Expr& f, CVC4::Type& t]
diff --git a/src/parser/options b/src/parser/options
index c80914596..66e95889f 100644
--- a/src/parser/options
+++ b/src/parser/options
@@ -14,6 +14,9 @@ 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
+option globalDeclarations global-declarations bool :default false
+ force all declarations and definitions to be global
+
# this is to support security in the online version, and in other similar contexts
# (--no-include-file disables filesystem access in TPTP and SMT2 parsers)
# the name --no-include-file is legacy: it also now limits any filesystem access
diff --git a/src/parser/parser.cpp b/src/parser/parser.cpp
index 064379cf3..045cd4ae1 100644
--- a/src/parser/parser.cpp
+++ b/src/parser/parser.cpp
@@ -29,7 +29,6 @@
#include "expr/kind.h"
#include "expr/type.h"
#include "util/output.h"
-#include "options/options.h"
using namespace std;
using namespace CVC4::kind;
@@ -43,6 +42,7 @@ Parser::Parser(ExprManager* exprManager, Input* input, bool strictMode, bool par
d_symtabAllocated(),
d_symtab(&d_symtabAllocated),
d_assertionLevel(0),
+ d_globalDeclarations(false),
d_anonymousFunctionCount(0),
d_done(false),
d_checksEnabled(true),
@@ -142,6 +142,9 @@ bool Parser::isPredicate(const std::string& name) {
Expr
Parser::mkVar(const std::string& name, const Type& type, uint32_t flags) {
+ if(d_globalDeclarations) {
+ flags |= ExprManager::VAR_FLAG_GLOBAL;
+ }
Debug("parser") << "mkVar(" << name << ", " << type << ")" << std::endl;
Expr expr = d_exprManager->mkVar(name, type, flags);
defineVar(name, expr, flags & ExprManager::VAR_FLAG_GLOBAL);
@@ -158,6 +161,9 @@ Parser::mkBoundVar(const std::string& name, const Type& type) {
Expr
Parser::mkFunction(const std::string& name, const Type& type, uint32_t flags) {
+ if(d_globalDeclarations) {
+ flags |= ExprManager::VAR_FLAG_GLOBAL;
+ }
Debug("parser") << "mkVar(" << name << ", " << type << ")" << std::endl;
Expr expr = d_exprManager->mkVar(name, type, flags);
defineFunction(name, expr, flags & ExprManager::VAR_FLAG_GLOBAL);
@@ -166,6 +172,9 @@ Parser::mkFunction(const std::string& name, const Type& type, uint32_t flags) {
Expr
Parser::mkAnonymousFunction(const std::string& prefix, const Type& type, uint32_t flags) {
+ if(d_globalDeclarations) {
+ flags |= ExprManager::VAR_FLAG_GLOBAL;
+ }
stringstream name;
name << prefix << "_anon_" << ++d_anonymousFunctionCount;
return d_exprManager->mkVar(name.str(), type, flags);
@@ -173,6 +182,9 @@ Parser::mkAnonymousFunction(const std::string& prefix, const Type& type, uint32_
std::vector<Expr>
Parser::mkVars(const std::vector<std::string> names, const Type& type, uint32_t flags) {
+ if(d_globalDeclarations) {
+ flags |= ExprManager::VAR_FLAG_GLOBAL;
+ }
std::vector<Expr> vars;
for(unsigned i = 0; i < names.size(); ++i) {
vars.push_back(mkVar(names[i], type, flags));
@@ -234,6 +246,9 @@ Parser::defineParameterizedType(const std::string& name,
SortType
Parser::mkSort(const std::string& name, uint32_t flags) {
+ if(d_globalDeclarations) {
+ flags |= ExprManager::VAR_FLAG_GLOBAL;
+ }
Debug("parser") << "newSort(" << name << ")" << std::endl;
Type type = d_exprManager->mkSort(name, flags);
defineType(name, type);
diff --git a/src/parser/parser.h b/src/parser/parser.h
index 87a331711..ffe33a980 100644
--- a/src/parser/parser.h
+++ b/src/parser/parser.h
@@ -134,6 +134,12 @@ class CVC4_PUBLIC Parser {
size_t d_assertionLevel;
/**
+ * Whether we're in global declarations mode (all definitions and
+ * declarations are global).
+ */
+ bool d_globalDeclarations;
+
+ /**
* 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
@@ -561,6 +567,14 @@ public:
}
}
+ virtual void reset() {
+ d_symtab->reset();
+ }
+
+ void setGlobalDeclarations(bool flag) {
+ d_globalDeclarations = flag;
+ }
+
/**
* Set the current symbol table used by this parser.
* From now on, this parser will perform its definitions and
diff --git a/src/parser/parser_builder.cpp b/src/parser/parser_builder.cpp
index b467acfeb..241c9c815 100644
--- a/src/parser/parser_builder.cpp
+++ b/src/parser/parser_builder.cpp
@@ -89,7 +89,8 @@ Parser* ParserBuilder::build()
case language::input::LANG_SMTLIB_V1:
parser = new Smt1(d_exprManager, input, d_strictMode, d_parseOnly);
break;
- case language::input::LANG_SMTLIB_V2:
+ case language::input::LANG_SMTLIB_V2_0:
+ case language::input::LANG_SMTLIB_V2_5:
parser = new Smt2(d_exprManager, input, d_strictMode, d_parseOnly);
break;
case language::input::LANG_TPTP:
diff --git a/src/parser/smt2/Smt2.g b/src/parser/smt2/Smt2.g
index 6964e6069..a8d42a740 100644
--- a/src/parser/smt2/Smt2.g
+++ b/src/parser/smt2/Smt2.g
@@ -133,7 +133,7 @@ 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) {
+static bool isClosed(const Expr& e, std::set<Expr>& free, std::hash_set<Expr, ExprHashFunction>& closedCache) {
if(closedCache.find(e) != closedCache.end()) {
return true;
}
@@ -163,7 +163,7 @@ static bool isClosed(Expr e, std::set<Expr>& free, std::hash_set<Expr, ExprHashF
}
}
-static inline bool isClosed(Expr e, std::set<Expr>& free) {
+static inline bool isClosed(const Expr& e, std::set<Expr>& free) {
std::hash_set<Expr, ExprHashFunction> cache;
return isClosed(e, free, cache);
}
@@ -224,7 +224,6 @@ command returns [CVC4::Command* cmd = NULL]
std::vector<Expr> terms;
std::vector<Type> sorts;
std::vector<std::pair<std::string, Type> > sortedVarNames;
- SExpr sexpr;
}
: /* set the logic */
SET_LOGIC_TOK symbol[name,CHECK_NONE,SYM_SORT]
@@ -234,20 +233,13 @@ command returns [CVC4::Command* cmd = NULL]
}
PARSER_STATE->setLogic(name);
$cmd = new SetBenchmarkLogicCommand(name); }
- | SET_INFO_TOK KEYWORD symbolicExpr[sexpr]
- { name = AntlrInput::tokenText($KEYWORD);
- if(name == ":cvc4-logic" || name == ":cvc4_logic") {
- PARSER_STATE->setLogic(sexpr.getValue());
- }
- PARSER_STATE->setInfo(name.c_str() + 1, sexpr);
- cmd = new SetInfoCommand(name.c_str() + 1, sexpr); }
+ | /* set-info */
+ SET_INFO_TOK metaInfoInternal[cmd]
| /* get-info */
GET_INFO_TOK KEYWORD
{ cmd = new GetInfoCommand(AntlrInput::tokenText($KEYWORD).c_str() + 1); }
| /* set-option */
- SET_OPTION_TOK keyword[name] symbolicExpr[sexpr]
- { PARSER_STATE->setOption(name.c_str() + 1, sexpr);
- cmd = new SetOptionCommand(name.c_str() + 1, sexpr); }
+ SET_OPTION_TOK setOptionInternal[cmd]
| /* get-option */
GET_OPTION_TOK KEYWORD
{ cmd = new GetOptionCommand(AntlrInput::tokenText($KEYWORD).c_str() + 1); }
@@ -344,28 +336,6 @@ command returns [CVC4::Command* cmd = NULL]
Expr func = PARSER_STATE->mkFunction(name, t, ExprManager::VAR_FLAG_DEFINED);
$cmd = new DefineFunctionCommand(name, func, terms, expr);
}
- | DEFINE_CONST_TOK { PARSER_STATE->checkThatLogicIsSet(); }
- symbol[name,CHECK_UNDECLARED,SYM_VARIABLE]
- { PARSER_STATE->checkUserSymbol(name); }
- sortSymbol[t,CHECK_DECLARED]
- { /* add variables to parser state before parsing term */
- Debug("parser") << "define const: '" << name << "'" << std::endl;
- PARSER_STATE->pushScope(true);
- for(std::vector<std::pair<std::string, CVC4::Type> >::const_iterator i =
- sortedVarNames.begin(), iend = sortedVarNames.end();
- i != iend;
- ++i) {
- terms.push_back(PARSER_STATE->mkBoundVar((*i).first, (*i).second));
- }
- }
- term[expr, expr2]
- { PARSER_STATE->popScope();
- // 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, ExprManager::VAR_FLAG_DEFINED);
- $cmd = new DefineFunctionCommand(name, func, terms, expr);
- }
| /* value query */
GET_VALUE_TOK { PARSER_STATE->checkThatLogicIsSet(); }
( LPAREN_TOK termList[terms,expr] RPAREN_TOK
@@ -377,8 +347,14 @@ command returns [CVC4::Command* cmd = NULL]
{ cmd = new GetAssignmentCommand(); }
| /* assertion */
ASSERT_TOK { PARSER_STATE->checkThatLogicIsSet(); }
+ { PARSER_STATE->clearLastNamedTerm(); }
term[expr, expr2]
- { cmd = new AssertCommand(expr); }
+ { bool inUnsatCore = PARSER_STATE->lastNamedTerm().first == expr;
+ cmd = new AssertCommand(expr, inUnsatCore);
+ if(inUnsatCore) {
+ PARSER_STATE->registerUnsatCoreName(PARSER_STATE->lastNamedTerm());
+ }
+ }
| /* check-sat */
CHECKSAT_TOK { PARSER_STATE->checkThatLogicIsSet(); }
( term[expr, expr2]
@@ -396,7 +372,7 @@ command returns [CVC4::Command* cmd = NULL]
{ cmd = new GetProofCommand(); }
| /* get-unsat-core */
GET_UNSAT_CORE_TOK { PARSER_STATE->checkThatLogicIsSet(); }
- { cmd = new GetUnsatCoreCommand(); }
+ { cmd = new GetUnsatCoreCommand(PARSER_STATE->getUnsatCoreNames()); }
| /* push */
PUSH_TOK { PARSER_STATE->checkThatLogicIsSet(); }
( k=INTEGER_LITERAL
@@ -405,11 +381,13 @@ command returns [CVC4::Command* cmd = NULL]
cmd = new EmptyCommand();
} else if(n == 1) {
PARSER_STATE->pushScope();
+ PARSER_STATE->pushUnsatCoreNameScope();
cmd = new PushCommand();
} else {
CommandSequence* seq = new CommandSequence();
do {
PARSER_STATE->pushScope();
+ PARSER_STATE->pushUnsatCoreNameScope();
Command* c = new PushCommand();
c->setMuted(n > 1);
seq->addCommand(c);
@@ -421,6 +399,7 @@ command returns [CVC4::Command* cmd = NULL]
PARSER_STATE->parseError("Strict compliance mode demands an integer to be provided to PUSH. Maybe you want (push 1)?");
} else {
PARSER_STATE->pushScope();
+ PARSER_STATE->pushUnsatCoreNameScope();
cmd = new PushCommand();
}
} )
@@ -433,11 +412,13 @@ command returns [CVC4::Command* cmd = NULL]
if(n == 0) {
cmd = new EmptyCommand();
} else if(n == 1) {
+ PARSER_STATE->popUnsatCoreNameScope();
PARSER_STATE->popScope();
cmd = new PopCommand();
} else {
CommandSequence* seq = new CommandSequence();
do {
+ PARSER_STATE->popUnsatCoreNameScope();
PARSER_STATE->popScope();
Command* c = new PopCommand();
c->setMuted(n > 1);
@@ -449,13 +430,23 @@ 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 {
+ PARSER_STATE->popUnsatCoreNameScope();
PARSER_STATE->popScope();
cmd = new PopCommand();
}
} )
+
+ /* exit */
| EXIT_TOK
{ cmd = new QuitCommand(); }
+ /* New SMT-LIB 2.5 command set */
+ | smt25Command[cmd]
+ { if(PARSER_STATE->v2_0() && PARSER_STATE->strictModeEnabled()) {
+ PARSER_STATE->parseError("SMT-LIB 2.5 commands are not permitted while operating in strict compliance mode and in SMT-LIB 2.0 mode.");
+ }
+ }
+
/* CVC4-extended SMT-LIB commands */
| extendedCommand[cmd]
{ if(PARSER_STATE->strictModeEnabled()) {
@@ -474,25 +465,73 @@ command returns [CVC4::Command* cmd = NULL]
}
;
-extendedCommand[CVC4::Command*& cmd]
+// Separate this into its own rule (can be invoked by set-info or meta-info)
+metaInfoInternal[CVC4::Command*& cmd]
@declarations {
- std::vector<CVC4::Datatype> dts;
- Type t;
- Expr e, e2;
+ std::string name;
SExpr sexpr;
+}
+ : KEYWORD symbolicExpr[sexpr]
+ { name = AntlrInput::tokenText($KEYWORD);
+ if(name == ":cvc4-logic" || name == ":cvc4_logic") {
+ PARSER_STATE->setLogic(sexpr.getValue());
+ } else if(name == ":smt-lib-version") {
+ // if we don't recognize the revision name, just keep the current mode
+ if( (sexpr.isRational() && sexpr.getRationalValue() == Rational(2)) ||
+ sexpr.getValue() == "2" ||
+ sexpr.getValue() == "2.0" ) {
+ PARSER_STATE->setLanguage(language::input::LANG_SMTLIB_V2_0);
+ } else if( (sexpr.isRational() && sexpr.getRationalValue() == Rational(5, 2)) ||
+ sexpr.getValue() == "2.5" ) {
+ PARSER_STATE->setLanguage(language::input::LANG_SMTLIB_V2_5);
+ }
+ }
+ PARSER_STATE->setInfo(name.c_str() + 1, sexpr);
+ cmd = new SetInfoCommand(name.c_str() + 1, sexpr);
+ }
+ ;
+
+setOptionInternal[CVC4::Command*& cmd]
+@init {
std::string name;
- std::vector<std::string> names;
- std::vector<Expr> terms;
- std::vector<Type> sorts;
+ SExpr sexpr;
+}
+ : keyword[name] symbolicExpr[sexpr]
+ { PARSER_STATE->setOption(name.c_str() + 1, sexpr);
+ cmd = new SetOptionCommand(name.c_str() + 1, sexpr);
+ // Ugly that this changes the state of the parser; but
+ // global-declarations affects parsing, so we can't hold off
+ // on this until some SmtEngine eventually (if ever) executes it.
+ if(name == ":global-declarations") {
+ PARSER_STATE->setGlobalDeclarations(sexpr.getValue() == "true");
+ }
+ }
+ ;
+
+smt25Command[CVC4::Command*& cmd]
+@declarations {
+ std::string name;
+ Expr expr, expr2;
std::vector<std::pair<std::string, Type> > sortedVarNames;
+ SExpr sexpr;
+ Type t;
}
- /* Extended SMT-LIB set of commands syntax, not permitted in
- * --smtlib2 compliance mode. */
- : DECLARE_DATATYPES_TOK datatypesDefCommand[false, cmd]
- | DECLARE_CODATATYPES_TOK datatypesDefCommand[true, cmd]
- | /* get model */
- GET_MODEL_TOK { PARSER_STATE->checkThatLogicIsSet(); }
+ /* meta-info */
+ : META_INFO_TOK metaInfoInternal[cmd]
+
+ /* declare-const */
+ | DECLARE_CONST_TOK { PARSER_STATE->checkThatLogicIsSet(); }
+ symbol[name,CHECK_UNDECLARED,SYM_VARIABLE]
+ { PARSER_STATE->checkUserSymbol(name); }
+ sortSymbol[t,CHECK_DECLARED]
+ { Expr c = PARSER_STATE->mkVar(name, t);
+ $cmd = new DeclareFunctionCommand(name, c, t); }
+
+ /* get model */
+ | GET_MODEL_TOK { PARSER_STATE->checkThatLogicIsSet(); }
{ cmd = new GetModelCommand(); }
+
+ /* echo */
| ECHO_TOK
( simpleSymbolicExpr[sexpr]
{ std::stringstream ss;
@@ -501,17 +540,77 @@ extendedCommand[CVC4::Command*& cmd]
}
| { cmd = new EchoCommand(); }
)
+
+ /* reset: reset everything, returning solver to initial state.
+ * Logic and options must be set again. */
+ | RESET_TOK
+ { cmd = new ResetCommand();
+ PARSER_STATE->reset();
+ }
+ /* reset-assertions: reset assertions, assertion stack, declarations,
+ * etc., but the logic and options remain as they were. */
+ | RESET_ASSERTIONS_TOK
+ { cmd = new ResetAssertionsCommand();
+ PARSER_STATE->resetAssertions();
+ }
+
+ | /* recursive function definition */
+ DEFINE_FUN_REC_TOK { PARSER_STATE->checkThatLogicIsSet(); } LPAREN_TOK
+ { PARSER_STATE->pushScope(true); }
+ ( LPAREN_TOK symbol[name,CHECK_UNDECLARED,SYM_VARIABLE]
+ { PARSER_STATE->checkUserSymbol(name); }
+ LPAREN_TOK sortedVarList[sortedVarNames] RPAREN_TOK
+ sortSymbol[t,CHECK_DECLARED]
+ { /* add variables to parser state before parsing term */
+ Debug("parser") << "define fun rec: '" << name << "'" << std::endl;
+ if( sortedVarNames.size() > 0 ) {
+ std::vector<CVC4::Type> sorts;
+ sorts.reserve(sortedVarNames.size());
+ for(std::vector<std::pair<std::string, CVC4::Type> >::const_iterator i =
+ sortedVarNames.begin(), iend = sortedVarNames.end();
+ i != iend;
+ ++i) {
+ sorts.push_back((*i).second);
+ }
+ t = EXPR_MANAGER->mkFunctionType(sorts, t);
+ }
+ PARSER_STATE->mkFunction(name, t, ExprManager::VAR_FLAG_DEFINED);
+ PARSER_STATE->pushScope(true);
+ for(std::vector<std::pair<std::string, CVC4::Type> >::const_iterator i =
+ sortedVarNames.begin(), iend = sortedVarNames.end();
+ i != iend;
+ ++i) {
+ PARSER_STATE->mkBoundVar((*i).first, (*i).second);
+ }
+ }
+ term[expr, expr2]
+ { PARSER_STATE->popScope(); }
+ RPAREN_TOK )+ RPAREN_TOK
+ { PARSER_STATE->popScope(); }
+
+ // CHECK_SAT_ASSUMING still being discussed
+ // GET_UNSAT_ASSUMPTIONS
+ ;
+
+extendedCommand[CVC4::Command*& cmd]
+@declarations {
+ std::vector<CVC4::Datatype> dts;
+ Expr e, e2;
+ Type t;
+ std::string name;
+ std::vector<std::string> names;
+ std::vector<Expr> terms;
+ std::vector<Type> sorts;
+ std::vector<std::pair<std::string, Type> > sortedVarNames;
+}
+ /* Extended SMT-LIB set of commands syntax, not permitted in
+ * --smtlib2 compliance mode. */
+ : DECLARE_DATATYPES_TOK datatypesDefCommand[false, cmd]
+ | DECLARE_CODATATYPES_TOK datatypesDefCommand[true, cmd]
| rewriterulesCommand[cmd]
/* Support some of Z3's extended SMT-LIB commands */
- | DECLARE_CONST_TOK { PARSER_STATE->checkThatLogicIsSet(); }
- symbol[name,CHECK_UNDECLARED,SYM_VARIABLE]
- { PARSER_STATE->checkUserSymbol(name); }
- sortSymbol[t,CHECK_DECLARED]
- { Expr c = PARSER_STATE->mkVar(name, t);
- $cmd = new DeclareFunctionCommand(name, c, t); }
-
| DECLARE_SORTS_TOK { PARSER_STATE->checkThatLogicIsSet(); }
{ if(!PARSER_STATE->isTheoryEnabled(Smt2::THEORY_UF) &&
!PARSER_STATE->isTheoryEnabled(Smt2::THEORY_ARRAYS) &&
@@ -612,6 +711,28 @@ extendedCommand[CVC4::Command*& cmd]
$cmd = new DefineFunctionCommand(name, func, terms, e);
}
)
+ | DEFINE_CONST_TOK { PARSER_STATE->checkThatLogicIsSet(); }
+ symbol[name,CHECK_UNDECLARED,SYM_VARIABLE]
+ { PARSER_STATE->checkUserSymbol(name); }
+ sortSymbol[t,CHECK_DECLARED]
+ { /* add variables to parser state before parsing term */
+ Debug("parser") << "define const: '" << name << "'" << std::endl;
+ PARSER_STATE->pushScope(true);
+ for(std::vector<std::pair<std::string, CVC4::Type> >::const_iterator i =
+ sortedVarNames.begin(), iend = sortedVarNames.end();
+ i != iend;
+ ++i) {
+ terms.push_back(PARSER_STATE->mkBoundVar((*i).first, (*i).second));
+ }
+ }
+ term[e, e2]
+ { PARSER_STATE->popScope();
+ // 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, ExprManager::VAR_FLAG_DEFINED);
+ $cmd = new DefineFunctionCommand(name, func, terms, e);
+ }
| SIMPLIFY_TOK { PARSER_STATE->checkThatLogicIsSet(); }
term[e,e2]
@@ -686,7 +807,7 @@ rewriterulesCommand[CVC4::Command*& cmd]
};
args.push_back(expr);
expr = MK_EXPR(CVC4::kind::REWRITE_RULE, args);
- cmd = new AssertCommand(expr); }
+ cmd = new AssertCommand(expr, false); }
/* propagation rule */
| rewritePropaKind[kind]
LPAREN_TOK sortedVarList[sortedVarNames] RPAREN_TOK
@@ -737,12 +858,11 @@ rewriterulesCommand[CVC4::Command*& cmd]
};
args.push_back(expr);
expr = MK_EXPR(CVC4::kind::REWRITE_RULE, args);
- cmd = new AssertCommand(expr); }
+ cmd = new AssertCommand(expr, false); }
;
rewritePropaKind[CVC4::Kind& kind]
- :
- REDUCTION_RULE_TOK { $kind = CVC4::kind::RR_REDUCTION; }
+ : REDUCTION_RULE_TOK { $kind = CVC4::kind::RR_REDUCTION; }
| PROPAGATION_RULE_TOK { $kind = CVC4::kind::RR_DEDUCTION; }
;
@@ -787,11 +907,11 @@ simpleSymbolicExprNoKeyword[CVC4::SExpr& sexpr]
// }
| 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)
+ | tok=(ASSERT_TOK | CHECKSAT_TOK | DECLARE_FUN_TOK | DECLARE_SORT_TOK | DEFINE_FUN_TOK | DEFINE_FUN_REC_TOK | DEFINE_SORT_TOK | GET_VALUE_TOK | GET_ASSIGNMENT_TOK | GET_ASSERTIONS_TOK | GET_PROOF_TOK | GET_UNSAT_CORE_TOK | EXIT_TOK | RESET_TOK | RESET_ASSERTIONS_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);
+ ss << Expr::setlanguage(CVC4::language::output::LANG_SMTLIB_V2_5) << EXPR_MANAGER->mkConst(k);
sexpr = SExpr(ss.str());
}
;
@@ -828,7 +948,6 @@ term[CVC4::Expr& expr, CVC4::Expr& expr2]
Expr op;
std::string name;
std::vector<Expr> args;
- SExpr sexpr;
std::vector< std::pair<std::string, Type> > sortedVarNames;
Expr f, f2;
std::string attr;
@@ -987,11 +1106,40 @@ term[CVC4::Expr& expr, CVC4::Expr& expr2]
}
expr = MK_EXPR(kind, args); }
- | /* An indexed function application */
- LPAREN_TOK indexedFunctionName[op] termList[args,expr] RPAREN_TOK
- { expr = MK_EXPR(op, args);
- PARSER_STATE->checkOperator(expr.getKind(), args.size());
- }
+ | LPAREN_TOK
+ ( /* An indexed function application */
+ indexedFunctionName[op] termList[args,expr] RPAREN_TOK
+ { expr = MK_EXPR(op, args);
+ PARSER_STATE->checkOperator(expr.getKind(), args.size());
+ }
+ | /* Array constant (in Z3 syntax) */
+ LPAREN_TOK AS_TOK CONST_TOK sortSymbol[type, CHECK_DECLARED]
+ RPAREN_TOK term[f, f2] RPAREN_TOK
+ {
+ if(!type.isArray()) {
+ std::stringstream ss;
+ ss << "expected array constant term, but cast is not of array type" << std::endl
+ << "cast type: " << type;
+ PARSER_STATE->parseError(ss.str());
+ }
+ if(!f.isConst()) {
+ std::stringstream ss;
+ ss << "expected constant term inside array constant, but found "
+ << "nonconstant term:" << std::endl
+ << "the term: " << f;
+ PARSER_STATE->parseError(ss.str());
+ }
+ if(!ArrayType(type).getConstituentType().isComparableTo(f.getType())) {
+ std::stringstream ss;
+ ss << "type mismatch inside array constant term:" << std::endl
+ << "array type: " << type << std::endl
+ << "expected const type: " << ArrayType(type).getConstituentType() << std::endl
+ << "computed const type: " << f.getType();
+ PARSER_STATE->parseError(ss.str());
+ }
+ expr = MK_CONST( ::CVC4::ArrayStoreAll(type, f) );
+ }
+ )
| /* a let binding */
LPAREN_TOK LET_TOK LPAREN_TOK
{ PARSER_STATE->pushScope(true); }
@@ -1037,8 +1185,8 @@ term[CVC4::Expr& expr, CVC4::Expr& expr2]
/* attributed expressions */
| LPAREN_TOK ATTRIBUTE_TOK term[expr, f2]
- ( attribute[expr, attexpr,attr]
- { if( attr == ":pattern" && ! attexpr.isNull()) {
+ ( attribute[expr, attexpr, attr]
+ { if( ! attexpr.isNull()) {
patexprs.push_back( attexpr );
}
}
@@ -1072,11 +1220,17 @@ term[CVC4::Expr& expr, CVC4::Expr& expr2]
} else if(! patexprs.empty()) {
if( !f2.isNull() && f2.getKind()==kind::INST_PATTERN_LIST ){
for( size_t i=0; i<f2.getNumChildren(); i++ ){
- patexprs.push_back( f2[i] );
+ if( f2[i].getKind()==kind::INST_PATTERN ){
+ patexprs.push_back( f2[i] );
+ }else{
+ std::stringstream ss;
+ ss << "warning: rewrite rules do not support " << f2[i] << " within instantiation pattern list";
+ PARSER_STATE->warning(ss.str());
+ }
}
}
expr2 = MK_EXPR(kind::INST_PATTERN_LIST, patexprs);
- }else{
+ } else {
expr2 = f2;
}
}
@@ -1144,17 +1298,49 @@ attribute[CVC4::Expr& expr,CVC4::Expr& retExpr, std::string& attr]
PARSER_STATE->warning(ss.str());
}
// do nothing
- } else if(attr == ":axiom" || attr == ":conjecture") {
+ } else if(attr==":axiom" || attr==":conjecture" || attr==":fun-def" || attr==":sygus" || attr==":synthesis") {
if(hasValue) {
std::stringstream ss;
ss << "warning: Attribute " << attr << " does not take a value (ignoring)";
PARSER_STATE->warning(ss.str());
}
- std::string attr_name = attr;
- attr_name.erase( attr_name.begin() );
- Command* c = new SetUserAttributeCommand( attr_name, expr );
- c->setMuted(true);
- PARSER_STATE->preemptCommand(c);
+ bool success = true;
+ if( attr==":fun-def" ){
+ if( ( expr.getKind()!=kind::EQUAL && expr.getKind()!=kind::IFF ) || expr[0].getKind()!=kind::APPLY_UF ){
+ success = false;
+ }else{
+ FunctionType t = (FunctionType)expr[0].getOperator().getType();
+ for( unsigned i=0; i<expr[0].getNumChildren(); i++ ){
+ if( expr[0][i].getKind()!=kind::BOUND_VARIABLE || expr[0][i].getType()!=t.getArgTypes()[i] ){
+ success = false;
+ break;
+ }else{
+ for( unsigned j=0; j<i; j++ ){
+ if( expr[0][j]==expr[0][i] ){
+ success = false;
+ break;
+ }
+ }
+ }
+ }
+ }
+ if( !success ){
+ std::stringstream ss;
+ ss << "warning: Function definition should be an equality whose LHS is an uninterpreted function applied to unique variables.";
+ PARSER_STATE->warning(ss.str());
+ }
+ }
+ if( success ){
+ std::string attr_name = attr;
+ attr_name.erase( attr_name.begin() );
+ //will set the attribute on auxiliary var (preserves attribute on formula through rewriting)
+ Type t = EXPR_MANAGER->booleanType();
+ Expr avar = PARSER_STATE->mkVar(attr_name, t);
+ retExpr = MK_EXPR(kind::INST_ATTRIBUTE, avar);
+ Command* c = new SetUserAttributeCommand( attr_name, avar );
+ c->setMuted(true);
+ PARSER_STATE->preemptCommand(c);
+ }
} else {
PARSER_STATE->attributeNotSupported(attr);
}
@@ -1164,10 +1350,24 @@ attribute[CVC4::Expr& expr,CVC4::Expr& retExpr, std::string& attr]
attr = std::string(":pattern");
retExpr = MK_EXPR(kind::INST_PATTERN, patexprs);
}
- | ATTRIBUTE_NO_PATTERN_TOK LPAREN_TOK term[patexpr, e2]+ RPAREN_TOK
+ | ATTRIBUTE_NO_PATTERN_TOK term[patexpr, e2]
{
attr = std::string(":no-pattern");
- PARSER_STATE->attributeNotSupported(attr);
+ retExpr = MK_EXPR(kind::INST_NO_PATTERN, patexpr);
+ }
+ | tok=( ATTRIBUTE_INST_LEVEL | ATTRIBUTE_RR_PRIORITY ) INTEGER_LITERAL
+ {
+ Expr n = MK_CONST( AntlrInput::tokenToInteger($INTEGER_LITERAL) );
+ std::vector<Expr> values;
+ values.push_back( n );
+ std::string attr_name(AntlrInput::tokenText($tok));
+ attr_name.erase( attr_name.begin() );
+ Type t = EXPR_MANAGER->booleanType();
+ Expr avar = PARSER_STATE->mkVar(attr_name, t);
+ retExpr = MK_EXPR(kind::INST_ATTRIBUTE, avar);
+ Command* c = new SetUserAttributeCommand( attr_name, avar, values );
+ c->setMuted(true);
+ PARSER_STATE->preemptCommand(c);
}
| ATTRIBUTE_NAMED_TOK symbolicExpr[sexpr]
{
@@ -1192,6 +1392,8 @@ attribute[CVC4::Expr& expr,CVC4::Expr& retExpr, std::string& attr]
PARSER_STATE->reserveSymbolAtAssertionLevel(name);
// define it
Expr func = PARSER_STATE->mkFunction(name, expr.getType());
+ // remember the last term to have been given a :named attribute
+ PARSER_STATE->setLastNamedTerm(expr, name);
// bind name to expr with define-fun
Command* c =
new DefineNamedFunctionCommand(name, func, std::vector<Expr>(), expr);
@@ -1261,15 +1463,15 @@ termList[std::vector<CVC4::Expr>& formulas, CVC4::Expr& expr]
* Matches a string, and strips off the quotes.
*/
str[std::string& s, bool fsmtlib]
- : STRING_LITERAL
- { s = AntlrInput::tokenText($STRING_LITERAL);
+ : STRING_LITERAL_2_0
+ { s = AntlrInput::tokenText($STRING_LITERAL_2_0);
/* strip off the quotes */
s = s.substr(1, s.size() - 2);
- for(size_t i=0; i<s.size(); i++) {
- if((unsigned)s[i] > 127) {
- PARSER_STATE->parseError("Extended characters are not part of SMT-LIB, and they must be encoded as esacped sequences");
- }
- }
+ for(size_t i=0; i<s.size(); i++) {
+ if((unsigned)s[i] > 127) {
+ PARSER_STATE->parseError("Extended characters are not part of SMT-LIB, and they must be encoded as esacped sequences");
+ }
+ }
if(fsmtlib) {
/* handle SMT-LIB standard escapes '\\' and '\"' */
char* p_orig = strdup(s.c_str());
@@ -1293,6 +1495,29 @@ str[std::string& s, bool fsmtlib]
free(p_orig);
}
}
+ | STRING_LITERAL_2_5
+ { s = AntlrInput::tokenText($STRING_LITERAL_2_5);
+ /* strip off the quotes */
+ s = s.substr(1, s.size() - 2);
+ for(size_t i=0; i<s.size(); i++) {
+ if((unsigned)s[i] > 127) {
+ PARSER_STATE->parseError("Extended characters are not part of SMT-LIB, and they must be encoded as esacped sequences");
+ }
+ }
+ // In the 2.5 version, always handle escapes (regardless of fsmtlib flag).
+ char* p_orig = strdup(s.c_str());
+ char *p = p_orig, *q = p_orig;
+ while(*q != '\0') {
+ if(*q == '"') {
+ ++q;
+ assert(*q == '"');
+ }
+ *p++ = *q++;
+ }
+ *p = '\0';
+ s = p_orig;
+ free(p_orig);
+ }
;
/**
@@ -1392,6 +1617,8 @@ builtinOp[CVC4::Kind& kind]
| RERANGE_TOK { $kind = CVC4::kind::REGEXP_RANGE; }
| RELOOP_TOK { $kind = CVC4::kind::REGEXP_LOOP; }
+ | DTSIZE_TOK { $kind = CVC4::kind::DT_SIZE; }
+
| FMFCARD_TOK { $kind = CVC4::kind::CARDINALITY_CONSTRAINT; }
// NOTE: Theory operators go here
@@ -1649,6 +1876,7 @@ CHECKSAT_TOK : 'check-sat';
DECLARE_FUN_TOK : 'declare-fun';
DECLARE_SORT_TOK : 'declare-sort';
DEFINE_FUN_TOK : 'define-fun';
+DEFINE_FUN_REC_TOK : 'define-fun-rec';
DEFINE_SORT_TOK : 'define-sort';
GET_VALUE_TOK : 'get-value';
GET_ASSIGNMENT_TOK : 'get-assignment';
@@ -1656,6 +1884,8 @@ GET_ASSERTIONS_TOK : 'get-assertions';
GET_PROOF_TOK : 'get-proof';
GET_UNSAT_CORE_TOK : 'get-unsat-core';
EXIT_TOK : 'exit';
+RESET_TOK : 'reset';
+RESET_ASSERTIONS_TOK : 'reset-assertions';
ITE_TOK : 'ite';
LET_TOK : 'let';
ATTRIBUTE_TOK : '!';
@@ -1664,12 +1894,14 @@ RPAREN_TOK : ')';
INDEX_TOK : '_';
SET_LOGIC_TOK : 'set-logic';
SET_INFO_TOK : 'set-info';
+META_INFO_TOK : 'meta-info';
GET_INFO_TOK : 'get-info';
SET_OPTION_TOK : 'set-option';
GET_OPTION_TOK : 'get-option';
PUSH_TOK : 'push';
POP_TOK : 'pop';
AS_TOK : 'as';
+CONST_TOK : 'const';
// extended commands
DECLARE_DATATYPES_TOK : 'declare-datatypes';
@@ -1692,6 +1924,8 @@ INCLUDE_TOK : 'include';
ATTRIBUTE_PATTERN_TOK : ':pattern';
ATTRIBUTE_NO_PATTERN_TOK : ':no-pattern';
ATTRIBUTE_NAMED_TOK : ':named';
+ATTRIBUTE_INST_LEVEL : ':quant-inst-max-level';
+ATTRIBUTE_RR_PRIORITY : ':rr-priority';
// operators (NOTE: theory symbols go here)
AMPERSAND_TOK : '&';
@@ -1788,6 +2022,8 @@ RELOOP_TOK : 're.loop';
RENOSTR_TOK : 're.nostr';
REALLCHAR_TOK : 're.allchar';
+DTSIZE_TOK : 'dt.size';
+
FMFCARD_TOK : 'fmf.card';
EMPTYSET_TOK: { PARSER_STATE->isTheoryEnabled(Smt2::THEORY_SETS) }? 'emptyset';
@@ -1886,14 +2122,28 @@ BINARY_LITERAL
;
/**
- * Matches a double quoted string literal. Escaping is supported, and
- * escape character '\' has to be escaped.
+ * Matches a double-quoted string literal from SMT-LIB 2.0.
+ * Escaping is supported, and * escape character '\' has to be escaped.
+ *
+ * You shouldn't generally use this in parser rules, as the quotes
+ * will be part of the token text. Use the str[] parser rule instead.
+ */
+STRING_LITERAL_2_0
+ : { PARSER_STATE->v2_0() }?=>
+ '"' ('\\' . | ~('\\' | '"'))* '"'
+ ;
+
+/**
+ * Matches a double-quoted string literal from SMT-LIB 2.5.
+ * You escape a double-quote inside the string with "", e.g.,
+ * "This is a string literal with "" a single, embedded double quote."
*
* You shouldn't generally use this in parser rules, as the quotes
* will be part of the token text. Use the str[] parser rule instead.
*/
-STRING_LITERAL
- : '"' ('\\' . | ~('\\' | '"'))* '"'
+STRING_LITERAL_2_5
+ : { PARSER_STATE->v2_5() }?=>
+ '"' (~('"') | '""')* '"'
;
/**
diff --git a/src/parser/smt2/smt2.cpp b/src/parser/smt2/smt2.cpp
index fecccfa44..62814ca25 100644
--- a/src/parser/smt2/smt2.cpp
+++ b/src/parser/smt2/smt2.cpp
@@ -31,6 +31,7 @@ namespace parser {
Smt2::Smt2(ExprManager* exprManager, Input* input, bool strictMode, bool parseOnly) :
Parser(exprManager,input,strictMode,parseOnly),
d_logicSet(false) {
+ d_unsatCoreNames.push(std::map<Expr, std::string>());
if( !strictModeEnabled() ) {
addTheory(Smt2::THEORY_CORE);
}
@@ -232,6 +233,24 @@ bool Smt2::logicIsSet() {
return d_logicSet;
}
+void Smt2::reset() {
+ d_logicSet = false;
+ d_logic = LogicInfo();
+ operatorKindMap.clear();
+ d_lastNamedTerm = std::pair<Expr, std::string>();
+ d_unsatCoreNames = std::stack< std::map<Expr, std::string> >();
+ this->Parser::reset();
+
+ d_unsatCoreNames.push(std::map<Expr, std::string>());
+ if( !strictModeEnabled() ) {
+ addTheory(Smt2::THEORY_CORE);
+ }
+}
+
+void Smt2::resetAssertions() {
+ this->Parser::reset();
+}
+
void Smt2::setLogic(const std::string& name) {
d_logicSet = true;
if(logicIsForced()) {
diff --git a/src/parser/smt2/smt2.h b/src/parser/smt2/smt2.h
index 71161be94..8c23c8657 100644
--- a/src/parser/smt2/smt2.h
+++ b/src/parser/smt2/smt2.h
@@ -23,8 +23,12 @@
#include "parser/smt1/smt1.h"
#include "theory/logic_info.h"
#include "util/abstract_value.h"
+#include "parser/smt2/smt2_input.h"
+#include <string>
#include <sstream>
+#include <utility>
+#include <stack>
namespace CVC4 {
@@ -54,6 +58,9 @@ private:
bool d_logicSet;
LogicInfo d_logic;
std::hash_map<std::string, Kind, StringHashFunction> operatorKindMap;
+ std::pair<Expr, std::string> d_lastNamedTerm;
+ // this is a user-context stack
+ std::stack< std::map<Expr, std::string> > d_unsatCoreNames;
protected:
Smt2(ExprManager* exprManager, Input* input, bool strictMode = false, bool parseOnly = false);
@@ -76,6 +83,10 @@ public:
bool logicIsSet();
+ void reset();
+
+ void resetAssertions();
+
/**
* Sets the logic for the current benchmark. Declares any logic and
* theory symbols.
@@ -89,6 +100,17 @@ public:
*/
const LogicInfo& getLogic() const { return d_logic; }
+ bool v2_0() const {
+ return getInput()->getLanguage() == language::input::LANG_SMTLIB_V2_0;
+ }
+ bool v2_5() const {
+ return getInput()->getLanguage() == language::input::LANG_SMTLIB_V2_5;
+ }
+
+ void setLanguage(InputLanguage lang) {
+ ((Smt2Input*) getInput())->setLanguage(lang);
+ }
+
void setInfo(const std::string& flag, const SExpr& sexpr);
void setOption(const std::string& flag, const SExpr& sexpr);
@@ -105,6 +127,34 @@ public:
void includeFile(const std::string& filename);
+ void setLastNamedTerm(Expr e, std::string name) {
+ d_lastNamedTerm = std::make_pair(e, name);
+ }
+
+ void clearLastNamedTerm() {
+ d_lastNamedTerm = std::make_pair(Expr(), "");
+ }
+
+ std::pair<Expr, std::string> lastNamedTerm() {
+ return d_lastNamedTerm;
+ }
+
+ void pushUnsatCoreNameScope() {
+ d_unsatCoreNames.push(d_unsatCoreNames.top());
+ }
+
+ void popUnsatCoreNameScope() {
+ d_unsatCoreNames.pop();
+ }
+
+ void registerUnsatCoreName(std::pair<Expr, std::string> name) {
+ d_unsatCoreNames.top().insert(name);
+ }
+
+ std::map<Expr, std::string> getUnsatCoreNames() {
+ return d_unsatCoreNames.top();
+ }
+
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;
diff --git a/src/parser/smt2/smt2_input.cpp b/src/parser/smt2/smt2_input.cpp
index c1e177dc4..22c2fd9a7 100644
--- a/src/parser/smt2/smt2_input.cpp
+++ b/src/parser/smt2/smt2_input.cpp
@@ -29,8 +29,9 @@ namespace CVC4 {
namespace parser {
/* Use lookahead=2 */
-Smt2Input::Smt2Input(AntlrInputStream& inputStream) :
+Smt2Input::Smt2Input(AntlrInputStream& inputStream, InputLanguage lang) :
AntlrInput(inputStream, 2) {
+
pANTLR3_INPUT_STREAM input = inputStream.getAntlr3InputStream();
assert( input != NULL );
@@ -50,14 +51,21 @@ Smt2Input::Smt2Input(AntlrInputStream& inputStream) :
}
setAntlr3Parser(d_pSmt2Parser->pParser);
-}
+ setLanguage(lang);
+}
Smt2Input::~Smt2Input() {
d_pSmt2Lexer->free(d_pSmt2Lexer);
d_pSmt2Parser->free(d_pSmt2Parser);
}
+void Smt2Input::setLanguage(InputLanguage lang) {
+ CheckArgument(lang == language::input::LANG_SMTLIB_V2_0 ||
+ lang == language::input::LANG_SMTLIB_V2_5, lang);
+ d_lang = lang;
+}
+
Command* Smt2Input::parseCommand() {
return d_pSmt2Parser->parseCommand(d_pSmt2Parser);
}
diff --git a/src/parser/smt2/smt2_input.h b/src/parser/smt2/smt2_input.h
index b2244db4d..c6a94f07a 100644
--- a/src/parser/smt2/smt2_input.h
+++ b/src/parser/smt2/smt2_input.h
@@ -44,6 +44,9 @@ class Smt2Input : public AntlrInput {
/** The ANTLR3 SMT2 parser for the input. */
pSmt2Parser d_pSmt2Parser;
+ /** Which (variant of the) input language we're using */
+ InputLanguage d_lang;
+
/**
* Initialize the class. Called from the constructors once the input
* stream is initialized.
@@ -57,16 +60,20 @@ public:
*
* @param inputStream the input stream to use
*/
- Smt2Input(AntlrInputStream& inputStream);
+ Smt2Input(AntlrInputStream& inputStream,
+ InputLanguage lang = language::input::LANG_SMTLIB_V2_5);
/** Destructor. Frees the lexer and the parser. */
virtual ~Smt2Input();
/** Get the language that this Input is reading. */
InputLanguage getLanguage() const throw() {
- return language::input::LANG_SMTLIB_V2;
+ return d_lang;
}
+ /** Set the language that this Input is reading. */
+ void setLanguage(InputLanguage);
+
protected:
/**
diff --git a/src/printer/ast/ast_printer.cpp b/src/printer/ast/ast_printer.cpp
index 9b60c8942..94ca46257 100644
--- a/src/printer/ast/ast_printer.cpp
+++ b/src/printer/ast/ast_printer.cpp
@@ -140,6 +140,8 @@ void AstPrinter::toStream(std::ostream& out, const Command* c,
tryToStream<PopCommand>(out, c) ||
tryToStream<CheckSatCommand>(out, c) ||
tryToStream<QueryCommand>(out, c) ||
+ tryToStream<ResetCommand>(out, c) ||
+ tryToStream<ResetAssertionsCommand>(out, c) ||
tryToStream<QuitCommand>(out, c) ||
tryToStream<DeclarationSequence>(out, c) ||
tryToStream<CommandSequence>(out, c) ||
@@ -224,6 +226,14 @@ static void toStream(std::ostream& out, const QueryCommand* c) throw() {
out << "Query(" << c->getExpr() << ')';
}
+static void toStream(std::ostream& out, const ResetCommand* c) throw() {
+ out << "Reset()";
+}
+
+static void toStream(std::ostream& out, const ResetAssertionsCommand* c) throw() {
+ out << "ResetAssertions()";
+}
+
static void toStream(std::ostream& out, const QuitCommand* c) throw() {
out << "Quit()";
}
diff --git a/src/printer/cvc/cvc_printer.cpp b/src/printer/cvc/cvc_printer.cpp
index 3f93106a0..f8df9d906 100644
--- a/src/printer/cvc/cvc_printer.cpp
+++ b/src/printer/cvc/cvc_printer.cpp
@@ -169,6 +169,13 @@ void CvcPrinter::toStream(std::ostream& out, TNode n, int depth, bool types, boo
out << "{} :: " << n.getConst<EmptySet>().getType();
break;
+ case kind::STORE_ALL: {
+ const ArrayStoreAll& asa = n.getConst<ArrayStoreAll>();
+ out << "ARRAY(" << asa.getType().getIndexType() << " OF "
+ << asa.getType().getConstituentType() << ") : " << asa.getExpr();
+ break;
+ }
+
default:
// Fall back to whatever operator<< does on underlying type; we
// might luck out and print something reasonable.
@@ -852,6 +859,8 @@ void CvcPrinter::toStream(std::ostream& out, const Command* c,
tryToStream<PopCommand>(out, c, d_cvc3Mode) ||
tryToStream<CheckSatCommand>(out, c, d_cvc3Mode) ||
tryToStream<QueryCommand>(out, c, d_cvc3Mode) ||
+ tryToStream<ResetCommand>(out, c, d_cvc3Mode) ||
+ tryToStream<ResetAssertionsCommand>(out, c, d_cvc3Mode) ||
tryToStream<QuitCommand>(out, c, d_cvc3Mode) ||
tryToStream<DeclarationSequence>(out, c, d_cvc3Mode) ||
tryToStream<CommandSequence>(out, c, d_cvc3Mode) ||
@@ -866,6 +875,7 @@ void CvcPrinter::toStream(std::ostream& out, const Command* c,
tryToStream<GetAssignmentCommand>(out, c, d_cvc3Mode) ||
tryToStream<GetAssertionsCommand>(out, c, d_cvc3Mode) ||
tryToStream<GetProofCommand>(out, c, d_cvc3Mode) ||
+ tryToStream<GetUnsatCoreCommand>(out, c, d_cvc3Mode) ||
tryToStream<SetBenchmarkStatusCommand>(out, c, d_cvc3Mode) ||
tryToStream<SetBenchmarkLogicCommand>(out, c, d_cvc3Mode) ||
tryToStream<SetInfoCommand>(out, c, d_cvc3Mode) ||
@@ -1038,6 +1048,14 @@ static void toStream(std::ostream& out, const QueryCommand* c, bool cvc3Mode) th
}
}
+static void toStream(std::ostream& out, const ResetCommand* c, bool cvc3Mode) throw() {
+ out << "RESET;";
+}
+
+static void toStream(std::ostream& out, const ResetAssertionsCommand* c, bool cvc3Mode) throw() {
+ out << "RESET ASSERTIONS;";
+}
+
static void toStream(std::ostream& out, const QuitCommand* c, bool cvc3Mode) throw() {
//out << "EXIT;";
}
@@ -1137,6 +1155,10 @@ static void toStream(std::ostream& out, const GetProofCommand* c, bool cvc3Mode)
out << "DUMP_PROOF;";
}
+static void toStream(std::ostream& out, const GetUnsatCoreCommand* c, bool cvc3Mode) throw() {
+ out << "DUMP_UNSAT_CORE;";
+}
+
static void toStream(std::ostream& out, const SetBenchmarkStatusCommand* c, bool cvc3Mode) throw() {
out << "% (set-info :status " << c->getStatus() << ")";
}
diff --git a/src/printer/printer.cpp b/src/printer/printer.cpp
index 8f0f50daa..a8e2534dc 100644
--- a/src/printer/printer.cpp
+++ b/src/printer/printer.cpp
@@ -40,7 +40,10 @@ Printer* Printer::makePrinter(OutputLanguage lang) throw() {
case LANG_SMTLIB_V1: // TODO the printer
return new printer::smt1::Smt1Printer();
- case LANG_SMTLIB_V2:
+ case LANG_SMTLIB_V2_0:
+ return new printer::smt2::Smt2Printer(printer::smt2::smt2_0_variant);
+
+ case LANG_SMTLIB_V2_5:
return new printer::smt2::Smt2Printer();
case LANG_TPTP:
@@ -153,4 +156,17 @@ void Printer::toStream(std::ostream& out, const Model& m) const throw() {
}
}/* Printer::toStream(Model) */
+void Printer::toStream(std::ostream& out, const UnsatCore& core) const throw() {
+ std::map<Expr, std::string> names;
+ toStream(out, core, names);
+}/* Printer::toStream(UnsatCore) */
+
+void Printer::toStream(std::ostream& out, const UnsatCore& core, const std::map<Expr, std::string>& names) const throw() {
+ for(UnsatCore::iterator i = core.begin(); i != core.end(); ++i) {
+ AssertCommand cmd(*i);
+ toStream(out, &cmd, -1, false, -1);
+ out << std::endl;
+ }
+}/* Printer::toStream(UnsatCore, std::map<Expr, std::string>) */
+
}/* CVC4 namespace */
diff --git a/src/printer/printer.h b/src/printer/printer.h
index beb2438e2..e0b80ddfc 100644
--- a/src/printer/printer.h
+++ b/src/printer/printer.h
@@ -19,6 +19,9 @@
#ifndef __CVC4__PRINTER__PRINTER_H
#define __CVC4__PRINTER__PRINTER_H
+#include <map>
+#include <string>
+
#include "util/language.h"
#include "util/sexpr.h"
#include "util/model.h"
@@ -103,6 +106,12 @@ public:
/** Write a Model out to a stream with this Printer. */
virtual void toStream(std::ostream& out, const Model& m) const throw();
+ /** Write an UnsatCore out to a stream with this Printer. */
+ virtual void toStream(std::ostream& out, const UnsatCore& core) const throw();
+
+ /** Write an UnsatCore out to a stream with this Printer. */
+ virtual void toStream(std::ostream& out, const UnsatCore& core, const std::map<Expr, std::string>& names) const throw();
+
};/* class Printer */
/**
diff --git a/src/printer/smt1/smt1_printer.cpp b/src/printer/smt1/smt1_printer.cpp
index 474fe58dc..05714fbce 100644
--- a/src/printer/smt1/smt1_printer.cpp
+++ b/src/printer/smt1/smt1_printer.cpp
@@ -33,24 +33,24 @@ namespace smt1 {
void Smt1Printer::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);
+ n.toStream(out, toDepth, types, dag, language::output::LANG_SMTLIB_V2_5);
}/* Smt1Printer::toStream() */
void Smt1Printer::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);
+ c->toStream(out, toDepth, types, dag, language::output::LANG_SMTLIB_V2_5);
}/* Smt1Printer::toStream() */
void Smt1Printer::toStream(std::ostream& out, const CommandStatus* s) const throw() {
- s->toStream(out, language::output::LANG_SMTLIB_V2);
+ s->toStream(out, language::output::LANG_SMTLIB_V2_5);
}/* Smt1Printer::toStream() */
void Smt1Printer::toStream(std::ostream& out, const SExpr& sexpr) const throw() {
- Printer::getPrinter(language::output::LANG_SMTLIB_V2)->toStream(out, sexpr);
+ Printer::getPrinter(language::output::LANG_SMTLIB_V2_5)->toStream(out, sexpr);
}/* Smt1Printer::toStream() */
void Smt1Printer::toStream(std::ostream& out, const Model& m) const throw() {
- Printer::getPrinter(language::output::LANG_SMTLIB_V2)->toStream(out, m);
+ Printer::getPrinter(language::output::LANG_SMTLIB_V2_5)->toStream(out, m);
}
void Smt1Printer::toStream(std::ostream& out, const Model& m, const Command* c) const throw() {
diff --git a/src/printer/smt2/smt2_printer.cpp b/src/printer/smt2/smt2_printer.cpp
index 903a1e6e3..88bcce5ae 100644
--- a/src/printer/smt2/smt2_printer.cpp
+++ b/src/printer/smt2/smt2_printer.cpp
@@ -125,7 +125,7 @@ void Smt2Printer::toStream(std::ostream& out, TNode n,
if(types) {
// print the whole type, but not *its* type
out << ":";
- n.getType().toStream(out, language::output::LANG_SMTLIB_V2);
+ n.getType().toStream(out, language::output::LANG_SMTLIB_V2_5);
}
return;
@@ -192,9 +192,30 @@ void Smt2Printer::toStream(std::ostream& out, TNode n,
break;
}
+ case kind::CONST_STRING: {
+ const String& s = n.getConst<String>();
+ out << '"';
+ for(size_t i = 0; i < s.size(); ++i) {
+ char c = String::convertUnsignedIntToChar(s[i]);
+ if(c == '"') {
+ if(d_variant == z3str_variant || d_variant == smt2_0_variant) {
+ out << "\\\"";
+ } else {
+ out << "\"\"";
+ }
+ } else if(c == '\\' && (d_variant == z3str_variant || d_variant == smt2_0_variant)) {
+ out << "\\\\";
+ } else {
+ out << c;
+ }
+ }
+ out << '"';
+ break;
+ }
+
case kind::STORE_ALL: {
ArrayStoreAll asa = n.getConst<ArrayStoreAll>();
- out << "(__array_store_all__ " << asa.getType() << " " << asa.getExpr() << ")";
+ out << "((as const " << asa.getType() << ") " << asa.getExpr() << ")";
break;
}
@@ -483,7 +504,7 @@ void Smt2Printer::toStream(std::ostream& out, TNode n,
out << (*i).getType();
// The following code do stange things
// (*i).getType().toStream(out, toDepth < 0 ? toDepth : toDepth - 1,
- // false, language::output::LANG_SMTLIB_V2);
+ // false, language::output::LANG_SMTLIB_V2_5);
out << ')';
if(++i != iend) {
out << ' ';
@@ -588,7 +609,6 @@ static string smtKindString(Kind k) throw() {
// 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
@@ -699,6 +719,8 @@ void Smt2Printer::toStream(std::ostream& out, const Command* c,
tryToStream<PopCommand>(out, c) ||
tryToStream<CheckSatCommand>(out, c) ||
tryToStream<QueryCommand>(out, c) ||
+ tryToStream<ResetCommand>(out, c) ||
+ tryToStream<ResetAssertionsCommand>(out, c) ||
tryToStream<QuitCommand>(out, c) ||
tryToStream<DeclarationSequence>(out, c) ||
tryToStream<CommandSequence>(out, c) ||
@@ -713,16 +735,17 @@ void Smt2Printer::toStream(std::ostream& out, const Command* c,
tryToStream<GetAssignmentCommand>(out, c) ||
tryToStream<GetAssertionsCommand>(out, c) ||
tryToStream<GetProofCommand>(out, c) ||
- tryToStream<SetBenchmarkStatusCommand>(out, c) ||
+ tryToStream<GetUnsatCoreCommand>(out, c) ||
+ tryToStream<SetBenchmarkStatusCommand>(out, c, d_variant) ||
tryToStream<SetBenchmarkLogicCommand>(out, c, d_variant) ||
- tryToStream<SetInfoCommand>(out, c) ||
+ tryToStream<SetInfoCommand>(out, c, d_variant) ||
tryToStream<GetInfoCommand>(out, c) ||
tryToStream<SetOptionCommand>(out, c) ||
tryToStream<GetOptionCommand>(out, c) ||
tryToStream<DatatypeDeclarationCommand>(out, c) ||
- tryToStream<CommentCommand>(out, c) ||
+ tryToStream<CommentCommand>(out, c, d_variant) ||
tryToStream<EmptyCommand>(out, c) ||
- tryToStream<EchoCommand>(out, c)) {
+ tryToStream<EchoCommand>(out, c, d_variant)) {
return;
}
@@ -732,7 +755,7 @@ void Smt2Printer::toStream(std::ostream& out, const Command* c,
}/* Smt2Printer::toStream(Command*) */
static inline void toStream(std::ostream& out, const SExpr& sexpr) throw() {
- Printer::getPrinter(language::output::LANG_SMTLIB_V2)->toStream(out, sexpr);
+ Printer::getPrinter(language::output::LANG_SMTLIB_V2_5)->toStream(out, sexpr);
}
// SMT-LIB quoting for symbols
@@ -752,7 +775,7 @@ static std::string quoteSymbol(std::string s) {
static std::string quoteSymbol(TNode n) {
std::stringstream ss;
- ss << Expr::setlanguage(language::output::LANG_SMTLIB_V2);
+ ss << Expr::setlanguage(language::output::LANG_SMTLIB_V2_5);
return quoteSymbol(ss.str());
}
@@ -765,13 +788,13 @@ void Smt2Printer::toStream(std::ostream& out, const SExpr& sexpr) const throw()
}
template <class T>
-static bool tryToStream(std::ostream& out, const CommandStatus* s) throw();
+static bool tryToStream(std::ostream& out, const CommandStatus* s, Variant v) throw();
void Smt2Printer::toStream(std::ostream& out, const CommandStatus* s) const throw() {
- if(tryToStream<CommandSuccess>(out, s) ||
- tryToStream<CommandFailure>(out, s) ||
- tryToStream<CommandUnsupported>(out, s)) {
+ if(tryToStream<CommandSuccess>(out, s, d_variant) ||
+ tryToStream<CommandFailure>(out, s, d_variant) ||
+ tryToStream<CommandUnsupported>(out, s, d_variant)) {
return;
}
@@ -781,6 +804,20 @@ void Smt2Printer::toStream(std::ostream& out, const CommandStatus* s) const thro
}/* Smt2Printer::toStream(CommandStatus*) */
+void Smt2Printer::toStream(std::ostream& out, const UnsatCore& core, const std::map<Expr, std::string>& names) const throw() {
+ out << "(" << std::endl;
+ for(UnsatCore::const_iterator i = core.begin(); i != core.end(); ++i) {
+ map<Expr, string>::const_iterator j = names.find(*i);
+ if(j == names.end()) {
+ out << *i << endl;
+ } else {
+ out << (*j).second << endl;
+ }
+ }
+ out << ")" << endl;
+}/* Smt2Printer::toStream(UnsatCore, map<Expr, string>) */
+
+
void Smt2Printer::toStream(std::ostream& out, const Model& m) const throw() {
out << "(model" << endl;
this->Printer::toStream(out, m);
@@ -925,6 +962,14 @@ static void toStream(std::ostream& out, const QueryCommand* c) throw() {
}
}
+static void toStream(std::ostream& out, const ResetCommand* c) throw() {
+ out << "(reset)";
+}
+
+static void toStream(std::ostream& out, const ResetAssertionsCommand* c) throw() {
+ out << "(reset-assertions)";
+}
+
static void toStream(std::ostream& out, const QuitCommand* c) throw() {
out << "(exit)";
}
@@ -1042,8 +1087,16 @@ static void toStream(std::ostream& out, const GetProofCommand* c) throw() {
out << "(get-proof)";
}
-static void toStream(std::ostream& out, const SetBenchmarkStatusCommand* c) throw() {
- out << "(set-info :status " << c->getStatus() << ")";
+static void toStream(std::ostream& out, const GetUnsatCoreCommand* c) throw() {
+ out << "(get-unsat-core)";
+}
+
+static void toStream(std::ostream& out, const SetBenchmarkStatusCommand* c, Variant v) throw() {
+ if(v == z3str_variant || v == smt2_0_variant) {
+ out << "(set-info :status " << c->getStatus() << ")";
+ } else {
+ out << "(meta-info :status " << c->getStatus() << ")";
+ }
}
static void toStream(std::ostream& out, const SetBenchmarkLogicCommand* c, Variant v) throw() {
@@ -1055,8 +1108,12 @@ static void toStream(std::ostream& out, const SetBenchmarkLogicCommand* c, Varia
}
}
-static void toStream(std::ostream& out, const SetInfoCommand* c) throw() {
- out << "(set-info :" << c->getFlag() << " ";
+static void toStream(std::ostream& out, const SetInfoCommand* c, Variant v) throw() {
+ if(v == z3str_variant || v == smt2_0_variant) {
+ out << "(set-info :" << c->getFlag() << " ";
+ } else {
+ out << "(meta-info :" << c->getFlag() << " ";
+ }
toStream(out, c->getSExpr());
out << ")";
}
@@ -1103,11 +1160,11 @@ static void toStream(std::ostream& out, const DatatypeDeclarationCommand* c) thr
out << "))";
}
-static void toStream(std::ostream& out, const CommentCommand* c) throw() {
+static void toStream(std::ostream& out, const CommentCommand* c, Variant v) throw() {
string s = c->getComment();
size_t pos = 0;
while((pos = s.find_first_of('"', pos)) != string::npos) {
- s.replace(pos, 1, "\\\"");
+ s.replace(pos, 1, (v == z3str_variant || v == smt2_0_variant) ? "\\\"" : "\"\"");
pos += 2;
}
out << "(set-info :notes \"" << s << "\")";
@@ -1116,8 +1173,15 @@ static void toStream(std::ostream& out, const CommentCommand* c) throw() {
static void toStream(std::ostream& out, const EmptyCommand* c) throw() {
}
-static void toStream(std::ostream& out, const EchoCommand* c) throw() {
- out << "(echo \"" << c->getOutput() << "\")";
+static void toStream(std::ostream& out, const EchoCommand* c, Variant v) throw() {
+ std::string s = c->getOutput();
+ // escape all double-quotes
+ size_t pos = 0;
+ while((pos = s.find('"', pos)) != string::npos) {
+ s.replace(pos, 1, (v == z3str_variant || v == smt2_0_variant) ? "\\\"" : "\"\"");
+ pos += 2;
+ }
+ out << "(echo \"" << s << "\")";
}
template <class T>
@@ -1138,13 +1202,13 @@ static bool tryToStream(std::ostream& out, const Command* c, Variant v) throw()
return false;
}
-static void toStream(std::ostream& out, const CommandSuccess* s) throw() {
+static void toStream(std::ostream& out, const CommandSuccess* s, Variant v) throw() {
if(Command::printsuccess::getPrintSuccess(out)) {
out << "success" << endl;
}
}
-static void toStream(std::ostream& out, const CommandUnsupported* s) throw() {
+static void toStream(std::ostream& out, const CommandUnsupported* s, Variant v) throw() {
#ifdef CVC4_COMPETITION_MODE
// if in competition mode, lie and say we're ok
// (we have nothing to lose by saying success, and everything to lose
@@ -1155,21 +1219,21 @@ static void toStream(std::ostream& out, const CommandUnsupported* s) throw() {
#endif /* CVC4_COMPETITION_MODE */
}
-static void toStream(std::ostream& out, const CommandFailure* s) throw() {
+static void toStream(std::ostream& out, const CommandFailure* s, Variant v) throw() {
string message = s->getMessage();
// escape all double-quotes
size_t pos = 0;
while((pos = message.find('"', pos)) != string::npos) {
- message = message.replace(pos, 1, "\\\"");
+ message.replace(pos, 1, (v == z3str_variant || v == smt2_0_variant) ? "\\\"" : "\"\"");
pos += 2;
}
out << "(error \"" << message << "\")" << endl;
}
template <class T>
-static bool tryToStream(std::ostream& out, const CommandStatus* s) throw() {
+static bool tryToStream(std::ostream& out, const CommandStatus* s, Variant v) throw() {
if(typeid(*s) == typeid(T)) {
- toStream(out, dynamic_cast<const T*>(s));
+ toStream(out, dynamic_cast<const T*>(s), v);
return true;
}
return false;
diff --git a/src/printer/smt2/smt2_printer.h b/src/printer/smt2/smt2_printer.h
index e86b3cb2b..4455a053c 100644
--- a/src/printer/smt2/smt2_printer.h
+++ b/src/printer/smt2/smt2_printer.h
@@ -29,7 +29,8 @@ namespace smt2 {
enum Variant {
no_variant,
- z3str_variant
+ smt2_0_variant, // old-style 2.0 syntax, when it makes a difference
+ z3str_variant // old-style 2.0 and also z3str syntax
};/* enum Variant */
class Smt2Printer : public CVC4::Printer {
@@ -37,7 +38,6 @@ class Smt2Printer : public CVC4::Printer {
void toStream(std::ostream& out, TNode n, int toDepth, bool types) 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:
Smt2Printer(Variant variant = no_variant) : d_variant(variant) { }
using CVC4::Printer::toStream;
@@ -46,6 +46,8 @@ public:
void toStream(std::ostream& out, const CommandStatus* s) const throw();
void toStream(std::ostream& out, const Result& r) 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 UnsatCore& core, const std::map<Expr, std::string>& names) const throw();
};/* class Smt2Printer */
}/* CVC4::printer::smt2 namespace */
diff --git a/src/printer/tptp/tptp_printer.cpp b/src/printer/tptp/tptp_printer.cpp
index cce48ae47..3c46a5849 100644
--- a/src/printer/tptp/tptp_printer.cpp
+++ b/src/printer/tptp/tptp_printer.cpp
@@ -33,26 +33,26 @@ 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);
+ n.toStream(out, toDepth, types, dag, language::output::LANG_SMTLIB_V2_5);
}/* 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);
+ c->toStream(out, toDepth, types, dag, language::output::LANG_SMTLIB_V2_5);
}/* TptpPrinter::toStream() */
void TptpPrinter::toStream(std::ostream& out, const CommandStatus* s) const throw() {
- s->toStream(out, language::output::LANG_SMTLIB_V2);
+ s->toStream(out, language::output::LANG_SMTLIB_V2_5);
}/* TptpPrinter::toStream() */
void TptpPrinter::toStream(std::ostream& out, const SExpr& sexpr) const throw() {
- Printer::getPrinter(language::output::LANG_SMTLIB_V2)->toStream(out, sexpr);
+ Printer::getPrinter(language::output::LANG_SMTLIB_V2_5)->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));
+ this->Printer::toStreamUsing(language::output::LANG_SMTLIB_V2_5, out, m, m.getCommand(i));
}
out << "% SZS output end FiniteModel for " << m.getInputName() << endl;
}
diff --git a/src/proof/cnf_proof.cpp b/src/proof/cnf_proof.cpp
index 3dfb61428..22a40ff69 100644
--- a/src/proof/cnf_proof.cpp
+++ b/src/proof/cnf_proof.cpp
@@ -30,6 +30,8 @@ CnfProof::CnfProof(CnfStream* stream)
: d_cnfStream(stream)
{}
+CnfProof::~CnfProof() {
+}
Expr CnfProof::getAtom(prop::SatVariable var) {
prop::SatLiteral lit (var);
@@ -38,34 +40,33 @@ Expr CnfProof::getAtom(prop::SatVariable var) {
return atom;
}
-CnfProof::~CnfProof() {
-}
-
-LFSCCnfProof::iterator LFSCCnfProof::begin_atom_mapping() {
- return iterator(*this, ProofManager::currentPM()->begin_vars());
+prop::SatLiteral CnfProof::getLiteral(TNode atom) {
+ return d_cnfStream->getLiteral(atom);
}
-LFSCCnfProof::iterator LFSCCnfProof::end_atom_mapping() {
- return iterator(*this, ProofManager::currentPM()->end_vars());
+Expr CnfProof::getAssertion(uint64_t id) {
+ return d_cnfStream->getAssertion(id).toExpr();
}
-void LFSCCnfProof::printAtomMapping(std::ostream& os, std::ostream& paren) {
- ProofManager::var_iterator it = ProofManager::currentPM()->begin_vars();
- ProofManager::var_iterator end = ProofManager::currentPM()->end_vars();
-
- for (;it != end; ++it) {
- os << "(decl_atom ";
-
- if (ProofManager::currentPM()->getLogic().compare("QF_UF") == 0) {
- Expr atom = getAtom(*it);
- LFSCTheoryProof::printTerm(atom, os);
- } else {
- // print fake atoms for all other logics
- os << "true ";
+void LFSCCnfProof::printAtomMapping(const prop::SatClause* clause, std::ostream& os, std::ostream& paren) {
+ for (unsigned i = 0; i < clause->size(); ++i) {
+ prop::SatLiteral lit = clause->operator[](i);
+ if(d_atomsDeclared.find(lit.getSatVariable()) == d_atomsDeclared.end()) {
+ d_atomsDeclared.insert(lit.getSatVariable());
+ os << "(decl_atom ";
+ if (ProofManager::currentPM()->getLogic().compare("QF_UF") == 0 ||
+ ProofManager::currentPM()->getLogic().compare("QF_AX") == 0 ||
+ ProofManager::currentPM()->getLogic().compare("QF_SAT") == 0) {
+ Expr atom = getAtom(lit.getSatVariable());
+ LFSCTheoryProof::printTerm(atom, os);
+ } else {
+ // print fake atoms for all other logics (for now)
+ os << "true ";
+ }
+
+ os << " (\\ " << ProofManager::getVarName(lit.getSatVariable()) << " (\\ " << ProofManager::getAtomName(lit.getSatVariable()) << "\n";
+ paren << ")))";
}
-
- os << " (\\ " << ProofManager::getVarName(*it) << " (\\ " << ProofManager::getAtomName(*it) << "\n";
- paren << ")))";
}
}
@@ -75,36 +76,93 @@ void LFSCCnfProof::printClauses(std::ostream& os, std::ostream& paren) {
}
void LFSCCnfProof::printInputClauses(std::ostream& os, std::ostream& paren) {
- os << " ;; Input Clauses \n";
+ os << " ;; Clauses\n";
ProofManager::clause_iterator it = ProofManager::currentPM()->begin_input_clauses();
ProofManager::clause_iterator end = ProofManager::currentPM()->end_input_clauses();
for (; it != end; ++it) {
ClauseId id = it->first;
const prop::SatClause* clause = it->second;
+ printAtomMapping(clause, os, paren);
os << "(satlem _ _ ";
std::ostringstream clause_paren;
printClause(*clause, os, clause_paren);
- os << " (clausify_false trust)" << clause_paren.str();
- os << "( \\ " << ProofManager::getInputClauseName(id) << "\n";
+ os << "(clausify_false trust)" << clause_paren.str()
+ << " (\\ " << ProofManager::getInputClauseName(id) << "\n";
paren << "))";
}
}
-
void LFSCCnfProof::printTheoryLemmas(std::ostream& os, std::ostream& paren) {
- os << " ;; Theory Lemmas \n";
- ProofManager::clause_iterator it = ProofManager::currentPM()->begin_lemmas();
- ProofManager::clause_iterator end = ProofManager::currentPM()->end_lemmas();
+ os << " ;; Theory Lemmas\n";
+ ProofManager::ordered_clause_iterator it = ProofManager::currentPM()->begin_lemmas();
+ ProofManager::ordered_clause_iterator end = ProofManager::currentPM()->end_lemmas();
+
+ for(size_t n = 0; it != end; ++it, ++n) {
+ if(n % 100 == 0) {
+ Chat() << "proving theory conflicts...(" << n << "/" << ProofManager::currentPM()->num_lemmas() << ")" << std::endl;
+ }
- for (; it != end; ++it) {
ClauseId id = it->first;
const prop::SatClause* clause = it->second;
+ NodeBuilder<> c(kind::AND);
+ for(unsigned i = 0; i < clause->size(); ++i) {
+ prop::SatLiteral lit = (*clause)[i];
+ prop::SatVariable var = lit.getSatVariable();
+ if(lit.isNegated()) {
+ c << Node::fromExpr(getAtom(var));
+ } else {
+ c << Node::fromExpr(getAtom(var)).notNode();
+ }
+ }
+ Node cl = c;
+ if(ProofManager::getSatProof()->d_lemmaClauses.find(id) != ProofManager::getSatProof()->d_lemmaClauses.end()) {
+ uint64_t proof_id = ProofManager::getSatProof()->d_lemmaClauses[id];
+ TNode orig = d_cnfStream->getAssertion(proof_id & 0xffffffff);
+ if(((proof_id >> 32) & 0xffffffff) == RULE_ARRAYS_EXT) {
+ Debug("cores") << "; extensional lemma!" << std::endl;
+ Assert(cl.getKind() == kind::AND && cl.getNumChildren() == 2 && cl[0].getKind() == kind::EQUAL && cl[0][0].getKind() == kind::SELECT);
+ TNode myk = cl[0][0][1];
+ Debug("cores") << "; so my skolemized k is " << myk << std::endl;
+ os << "(ext _ _ " << orig[0][0] << " " << orig[0][1] << " (\\ " << myk << " (\\ " << ProofManager::getLemmaName(id) << "\n";
+ paren << ")))";
+ }
+ }
+ printAtomMapping(clause, os, paren);
os << "(satlem _ _ ";
std::ostringstream clause_paren;
printClause(*clause, os, clause_paren);
- os << " (clausify_false trust)" << clause_paren.str();
- os << "( \\ " << ProofManager::getLemmaClauseName(id) <<"\n";
+
+ Debug("cores") << "\n;id is " << id << std::endl;
+ if(ProofManager::getSatProof()->d_lemmaClauses.find(id) != ProofManager::getSatProof()->d_lemmaClauses.end()) {
+ uint64_t proof_id = ProofManager::getSatProof()->d_lemmaClauses[id];
+ Debug("cores") << ";getting id " << int32_t(proof_id & 0xffffffff) << std::endl;
+ Assert(int32_t(proof_id & 0xffffffff) != -1);
+ TNode orig = d_cnfStream->getAssertion(proof_id & 0xffffffff);
+ Debug("cores") << "; ID is " << id << " and that's a lemma with " << ((proof_id >> 32) & 0xffffffff) << " / " << (proof_id & 0xffffffff) << std::endl;
+ Debug("cores") << "; that means the lemma was " << orig << std::endl;
+ if(((proof_id >> 32) & 0xffffffff) == RULE_ARRAYS_EXT) {
+ Debug("cores") << "; extensional" << std::endl;
+ os << "(clausify_false trust)\n";
+ } else if(proof_id == 0) {
+ // theory propagation caused conflict
+ //ProofManager::currentPM()->printProof(os, cl);
+ os << "(clausify_false trust)\n";
+ } else if(((proof_id >> 32) & 0xffffffff) == RULE_CONFLICT) {
+ os << "\n;; need to generate a (conflict) proof of " << cl << "\n";
+ //ProofManager::currentPM()->printProof(os, cl);
+ os << "(clausify_false trust)\n";
+ } else {
+ os << "\n;; need to generate a (lemma) proof of " << cl;
+ os << "\n;; DON'T KNOW HOW !!\n";
+ os << "(clausify_false trust)\n";
+ }
+ } else {
+ os << "\n;; need to generate a (conflict) proof of " << cl << "\n";
+ ProofManager::currentPM()->printProof(os, cl);
+ }
+ os << clause_paren.str()
+ << " (\\ " << ProofManager::getLemmaClauseName(id) << "\n";
paren << "))";
}
}
@@ -114,10 +172,10 @@ void LFSCCnfProof::printClause(const prop::SatClause& clause, std::ostream& os,
prop::SatLiteral lit = clause[i];
prop::SatVariable var = lit.getSatVariable();
if (lit.isNegated()) {
- os << "(ast _ _ _ " << ProofManager::getAtomName(var) <<" (\\ " << ProofManager::getLitName(lit) << " ";
+ os << "(ast _ _ _ " << ProofManager::getAtomName(var) << " (\\ " << ProofManager::getLitName(lit) << " ";
paren << "))";
} else {
- os << "(asf _ _ _ " << ProofManager::getAtomName(var) <<" (\\ " << ProofManager::getLitName(lit) << " ";
+ os << "(asf _ _ _ " << ProofManager::getAtomName(var) << " (\\ " << ProofManager::getLitName(lit) << " ";
paren << "))";
}
}
diff --git a/src/proof/cnf_proof.h b/src/proof/cnf_proof.h
index b2c35c4f7..459815e60 100644
--- a/src/proof/cnf_proof.h
+++ b/src/proof/cnf_proof.h
@@ -30,62 +30,38 @@
namespace CVC4 {
namespace prop {
class CnfStream;
-}
+}/* CVC4::prop namespace */
class CnfProof;
-class AtomIterator {
- CnfProof& d_cnf;
- ProofManager::var_iterator d_it;
-
-public:
- AtomIterator(CnfProof& cnf, const ProofManager::var_iterator& it)
- : d_cnf(cnf), d_it(it)
- {}
- inline Expr operator*();
- AtomIterator& operator++() { ++d_it; return *this; }
- AtomIterator operator++(int) { AtomIterator x = *this; ++d_it; return x; }
- bool operator==(const AtomIterator& it) const { return &d_cnf == &it.d_cnf && d_it == it.d_it; }
- bool operator!=(const AtomIterator& it) const { return !(*this == it); }
-};/* class AtomIterator */
-
class CnfProof {
protected:
CVC4::prop::CnfStream* d_cnfStream;
- Expr getAtom(prop::SatVariable var);
- friend class AtomIterator;
+ VarSet d_atomsDeclared;
public:
CnfProof(CVC4::prop::CnfStream* cnfStream);
- typedef AtomIterator iterator;
- virtual iterator begin_atom_mapping() = 0;
- virtual iterator end_atom_mapping() = 0;
+ Expr getAtom(prop::SatVariable var);
+ Expr getAssertion(uint64_t id);
+ prop::SatLiteral getLiteral(TNode atom);
- virtual void printAtomMapping(std::ostream& os, std::ostream& paren) = 0;
virtual void printClauses(std::ostream& os, std::ostream& paren) = 0;
virtual ~CnfProof();
-};
+};/* class CnfProof */
class LFSCCnfProof : public CnfProof {
void printInputClauses(std::ostream& os, std::ostream& paren);
void printTheoryLemmas(std::ostream& os, std::ostream& paren);
void printClause(const prop::SatClause& clause, std::ostream& os, std::ostream& paren);
+ virtual void printAtomMapping(const prop::SatClause* clause, std::ostream& os, std::ostream& paren);
public:
LFSCCnfProof(CVC4::prop::CnfStream* cnfStream)
: CnfProof(cnfStream)
{}
- virtual iterator begin_atom_mapping();
- virtual iterator end_atom_mapping();
-
- virtual void printAtomMapping(std::ostream& os, std::ostream& paren);
virtual void printClauses(std::ostream& os, std::ostream& paren);
-};
-
-inline Expr AtomIterator::operator*() {
- return d_cnf.getAtom(*d_it);
-}
+};/* class LFSCCnfProof */
} /* CVC4 namespace */
diff --git a/src/proof/proof.h b/src/proof/proof.h
index 174913755..440279dbc 100644
--- a/src/proof/proof.h
+++ b/src/proof/proof.h
@@ -22,9 +22,9 @@
#include "smt/options.h"
#ifdef CVC4_PROOF
-# define PROOF(x) if(options::proof()) { x; }
-# define NULLPROOF(x) (options::proof()) ? x : NULL
-# define PROOF_ON() options::proof()
+# define PROOF(x) if(options::proof() || options::unsatCores()) { x; }
+# define NULLPROOF(x) (options::proof() || options::unsatCores()) ? x : NULL
+# define PROOF_ON() (options::proof() || options::unsatCores())
#else /* CVC4_PROOF */
# define PROOF(x)
# define NULLPROOF(x) NULL
diff --git a/src/proof/proof_manager.cpp b/src/proof/proof_manager.cpp
index 680e57d39..87eded8e6 100644
--- a/src/proof/proof_manager.cpp
+++ b/src/proof/proof_manager.cpp
@@ -23,6 +23,15 @@
#include "util/cvc4_assert.h"
#include "smt/smt_engine.h"
#include "smt/smt_engine_scope.h"
+#include "theory/output_channel.h"
+#include "theory/valuation.h"
+#include "util/node_visitor.h"
+#include "theory/term_registration_visitor.h"
+#include "theory/uf/theory_uf.h"
+#include "theory/uf/equality_engine.h"
+#include "theory/arrays/theory_arrays.h"
+#include "context/context.h"
+#include "util/hash.h"
namespace CVC4 {
@@ -37,7 +46,8 @@ ProofManager::ProofManager(ProofFormat format):
d_cnfProof(NULL),
d_theoryProof(NULL),
d_fullProof(NULL),
- d_format(format)
+ d_format(format),
+ d_deps()
{
}
@@ -53,7 +63,7 @@ ProofManager::~ProofManager() {
delete it->second;
}
- for(IdToClause::iterator it = d_theoryLemmas.begin();
+ for(OrderedIdToClause::iterator it = d_theoryLemmas.begin();
it != d_theoryLemmas.end();
++it) {
delete it->second;
@@ -91,11 +101,10 @@ CnfProof* ProofManager::getCnfProof() {
}
TheoryProof* ProofManager::getTheoryProof() {
- Assert (currentPM()->d_theoryProof);
+ //Assert (currentPM()->d_theoryProof);
return currentPM()->d_theoryProof;
}
-
void ProofManager::initSatProof(Minisat::Solver* solver) {
Assert (currentPM()->d_satProof == NULL);
Assert(currentPM()->d_format == LFSC);
@@ -114,35 +123,101 @@ void ProofManager::initTheoryProof() {
currentPM()->d_theoryProof = new LFSCTheoryProof();
}
-
-std::string ProofManager::getInputClauseName(ClauseId id) {return append("pb", id); }
-std::string ProofManager::getLemmaClauseName(ClauseId id) { return append("lem", id); }
+std::string ProofManager::getInputClauseName(ClauseId id) { return append("pb", id); }
+std::string ProofManager::getLemmaName(ClauseId id) { return append("lem", id); }
+std::string ProofManager::getLemmaClauseName(ClauseId id) { return append("lemc", id); }
std::string ProofManager::getLearntClauseName(ClauseId id) { return append("cl", id); }
-std::string ProofManager::getVarName(prop::SatVariable var) { return append("v", var); }
-std::string ProofManager::getAtomName(prop::SatVariable var) { return append("a", var); }
-std::string ProofManager::getLitName(prop::SatLiteral lit) {return append("l", lit.toInt()); }
+std::string ProofManager::getVarName(prop::SatVariable var) { return append("var", var); }
+std::string ProofManager::getAtomName(prop::SatVariable var) { return append("atom", var); }
+std::string ProofManager::getLitName(prop::SatLiteral lit) { return append("lit", lit.toInt()); }
+
+std::string ProofManager::getAtomName(TNode atom) {
+ prop::SatLiteral lit = currentPM()->d_cnfProof->getLiteral(atom);
+ Assert(!lit.isNegated());
+ return getAtomName(lit.getSatVariable());
+}
+std::string ProofManager::getLitName(TNode lit) {
+ return getLitName(currentPM()->d_cnfProof->getLiteral(lit));
+}
+
+void ProofManager::traceDeps(TNode n) {
+ Debug("cores") << "trace deps " << n << std::endl;
+ if(d_inputCoreFormulas.find(n.toExpr()) != d_inputCoreFormulas.end()) {
+ // originating formula was in core set
+ Debug("cores") << " -- IN INPUT CORE LIST!" << std::endl;
+ d_outputCoreFormulas.insert(n.toExpr());
+ } else {
+ Debug("cores") << " -- NOT IN INPUT CORE LIST!" << std::endl;
+ if(d_deps.find(n) == d_deps.end()) {
+ InternalError("Cannot trace dependence information back to input assertion:\n`%s'", n.toString().c_str());
+ }
+ Assert(d_deps.find(n) != d_deps.end());
+ std::vector<Node> deps = (*d_deps.find(n)).second;
+ for(std::vector<Node>::const_iterator i = deps.begin(); i != deps.end(); ++i) {
+ Debug("cores") << " + tracing deps: " << n << " -deps-on- " << *i << std::endl;
+ traceDeps(*i);
+ }
+ }
+}
void ProofManager::addClause(ClauseId id, const prop::SatClause* clause, ClauseKind kind) {
- for (unsigned i = 0; i < clause->size(); ++i) {
+ /*for (unsigned i = 0; i < clause->size(); ++i) {
prop::SatLiteral lit = clause->operator[](i);
d_propVars.insert(lit.getSatVariable());
- }
+ }*/
if (kind == INPUT) {
d_inputClauses.insert(std::make_pair(id, clause));
- return;
+ Assert(d_satProof->d_inputClauses.find(id) != d_satProof->d_inputClauses.end());
+ Debug("cores") << "core id is " << d_satProof->d_inputClauses[id] << std::endl;
+ if(d_satProof->d_inputClauses[id] == uint64_t(-1)) {
+ Debug("cores") << " + constant unit (true or false)" << std::endl;
+ } else if(options::unsatCores()) {
+ Expr e = d_cnfProof->getAssertion(d_satProof->d_inputClauses[id] & 0xffffffff);
+ Debug("cores") << "core input assertion from CnfStream is " << e << std::endl;
+ Debug("cores") << "with proof rule " << ((d_satProof->d_inputClauses[id] & 0xffffffff00000000llu) >> 32) << std::endl;
+ // Invalid proof rules are currently used for parts of CVC4 that don't
+ // support proofs (these are e.g. unproven theory lemmas) or don't need
+ // proofs (e.g. split lemmas). We can ignore these safely when
+ // constructing unsat cores.
+ if(((d_satProof->d_inputClauses[id] & 0xffffffff00000000llu) >> 32) != RULE_INVALID) {
+ // trace dependences back to actual assertions
+ traceDeps(Node::fromExpr(e));
+ }
+ }
+ } else {
+ Assert(kind == THEORY_LEMMA);
+ d_theoryLemmas.insert(std::make_pair(id, clause));
}
- Assert (kind == THEORY_LEMMA);
- d_theoryLemmas.insert(std::make_pair(id, clause));
}
-void ProofManager::addAssertion(Expr formula) {
+void ProofManager::addAssertion(Expr formula, bool inUnsatCore) {
+ Debug("cores") << "assert: " << formula << std::endl;
d_inputFormulas.insert(formula);
+ d_deps[Node::fromExpr(formula)]; // empty vector of deps
+ if(inUnsatCore || options::dumpUnsatCores()) {
+ Debug("cores") << "adding to input core forms: " << formula << std::endl;
+ d_inputCoreFormulas.insert(formula);
+ }
}
-void ProofManager::setLogic(const std::string& logic_string) {
- d_logic = logic_string;
+void ProofManager::addDependence(TNode n, TNode dep) {
+ if(dep != n) {
+ Debug("cores") << "dep: " << n << " : " << dep << std::endl;
+ if(d_deps.find(dep) == d_deps.end()) {
+ Debug("cores") << "WHERE DID " << dep << " come from ??" << std::endl;
+ }
+ //Assert(d_deps.find(dep) != d_deps.end());
+ d_deps[n].push_back(dep);
+ }
+}
+
+void ProofManager::setLogic(const LogicInfo& logic) {
+ d_logic = logic;
}
+void ProofManager::printProof(std::ostream& os, TNode n) {
+ // no proofs here yet
+}
LFSCProof::LFSCProof(SmtEngine* smtEngine, LFSCSatProof* sat, LFSCCnfProof* cnf, LFSCTheoryProof* theory)
: d_satProof(sat)
@@ -157,17 +232,18 @@ void LFSCProof::toStream(std::ostream& out) {
smt::SmtScope scope(d_smtEngine);
std::ostringstream paren;
out << "(check\n";
+ out << " ;; Declarations\n";
if (d_theoryProof == NULL) {
d_theoryProof = new LFSCTheoryProof();
}
- for(LFSCCnfProof::iterator i = d_cnfProof->begin_atom_mapping();
+ /*for(LFSCCnfProof::iterator i = d_cnfProof->begin_atom_mapping();
i != d_cnfProof->end_atom_mapping();
++i) {
d_theoryProof->addDeclaration(*i);
- }
+ }*/
d_theoryProof->printAssertions(out, paren);
+ out << " ;; Proof of empty clause follows\n";
out << "(: (holds cln)\n";
- d_cnfProof->printAtomMapping(out, paren);
d_cnfProof->printClauses(out, paren);
d_satProof->printResolutions(out, paren);
paren <<")))\n;;";
@@ -175,5 +251,4 @@ void LFSCProof::toStream(std::ostream& out) {
out << "\n";
}
-
} /* CVC4 namespace */
diff --git a/src/proof/proof_manager.h b/src/proof/proof_manager.h
index f428de36d..d60a3f6e3 100644
--- a/src/proof/proof_manager.h
+++ b/src/proof/proof_manager.h
@@ -20,9 +20,12 @@
#define __CVC4__PROOF_MANAGER_H
#include <iostream>
+#include <map>
#include "proof/proof.h"
#include "util/proof.h"
-
+#include "expr/node.h"
+#include "theory/logic_info.h"
+#include "theory/substitutions.h"
// forward declarations
namespace Minisat {
@@ -63,6 +66,7 @@ enum ProofFormat {
std::string append(const std::string& str, uint64_t num);
typedef __gnu_cxx::hash_map < ClauseId, const prop::SatClause* > IdToClause;
+typedef std::map < ClauseId, const prop::SatClause* > OrderedIdToClause;
typedef __gnu_cxx::hash_set<prop::SatVariable > VarSet;
typedef __gnu_cxx::hash_set<Expr, ExprHashFunction > ExprSet;
@@ -74,6 +78,18 @@ enum ClauseKind {
LEARNT
};/* enum ClauseKind */
+enum ProofRule {
+ RULE_GIVEN, /* input assertion */
+ RULE_DERIVED, /* a "macro" rule */
+ RULE_RECONSTRUCT, /* prove equivalence using another method */
+ RULE_TRUST, /* trust without evidence (escape hatch until proofs are fully supported) */
+ RULE_INVALID, /* assert-fail if this is ever needed in proof; use e.g. for split lemmas */
+ RULE_CONFLICT, /* re-construct as a conflict */
+
+ RULE_ARRAYS_EXT, /* arrays, extensional */
+ RULE_ARRAYS_ROW, /* arrays, read-over-write */
+};/* enum ProofRules */
+
class ProofManager {
SatProof* d_satProof;
CnfProof* d_cnfProof;
@@ -81,15 +97,25 @@ class ProofManager {
// information that will need to be shared across proofs
IdToClause d_inputClauses;
- IdToClause d_theoryLemmas;
+ OrderedIdToClause d_theoryLemmas;
+ IdToClause d_theoryPropagations;
ExprSet d_inputFormulas;
- VarSet d_propVars;
+ ExprSet d_inputCoreFormulas;
+ ExprSet d_outputCoreFormulas;
+ //VarSet d_propVars;
+
+ int d_nextId;
Proof* d_fullProof;
ProofFormat d_format; // used for now only in debug builds
+ __gnu_cxx::hash_map< Node, std::vector<Node>, NodeHashFunction > d_deps;
+
+ // trace dependences back to unsat core
+ void traceDeps(TNode n);
+
protected:
- std::string d_logic;
+ LogicInfo d_logic;
public:
ProofManager(ProofFormat format = LFSC);
@@ -109,35 +135,50 @@ public:
// iterators over data shared by proofs
typedef IdToClause::const_iterator clause_iterator;
+ typedef OrderedIdToClause::const_iterator ordered_clause_iterator;
typedef ExprSet::const_iterator assertions_iterator;
typedef VarSet::const_iterator var_iterator;
clause_iterator begin_input_clauses() const { return d_inputClauses.begin(); }
clause_iterator end_input_clauses() const { return d_inputClauses.end(); }
+ size_t num_input_clauses() const { return d_inputClauses.size(); }
- clause_iterator begin_lemmas() const { return d_theoryLemmas.begin(); }
- clause_iterator end_lemmas() const { return d_theoryLemmas.end(); }
+ ordered_clause_iterator begin_lemmas() const { return d_theoryLemmas.begin(); }
+ ordered_clause_iterator end_lemmas() const { return d_theoryLemmas.end(); }
+ size_t num_lemmas() const { return d_theoryLemmas.size(); }
assertions_iterator begin_assertions() const { return d_inputFormulas.begin(); }
assertions_iterator end_assertions() const { return d_inputFormulas.end(); }
+ size_t num_assertions() const { return d_inputFormulas.size(); }
- var_iterator begin_vars() const { return d_propVars.begin(); }
- var_iterator end_vars() const { return d_propVars.end(); }
+ void printProof(std::ostream& os, TNode n);
- void addAssertion(Expr formula);
+ void addAssertion(Expr formula, bool inUnsatCore);
void addClause(ClauseId id, const prop::SatClause* clause, ClauseKind kind);
+ // note that n depends on dep (for cores)
+ void addDependence(TNode n, TNode dep);
+
+ assertions_iterator begin_unsat_core() const { return d_outputCoreFormulas.begin(); }
+ assertions_iterator end_unsat_core() const { return d_outputCoreFormulas.end(); }
+ size_t size_unsat_core() const { return d_outputCoreFormulas.size(); }
+
+ int nextId() { return d_nextId++; }
// variable prefixes
static std::string getInputClauseName(ClauseId id);
+ static std::string getLemmaName(ClauseId id);
static std::string getLemmaClauseName(ClauseId id);
static std::string getLearntClauseName(ClauseId id);
static std::string getVarName(prop::SatVariable var);
static std::string getAtomName(prop::SatVariable var);
+ static std::string getAtomName(TNode atom);
static std::string getLitName(prop::SatLiteral lit);
+ static std::string getLitName(TNode lit);
+
+ void setLogic(const LogicInfo& logic);
+ const std::string getLogic() const { return d_logic.getLogicString(); }
- void setLogic(const std::string& logic_string);
- const std::string getLogic() const { return d_logic; }
};/* class ProofManager */
class LFSCProof : public Proof {
diff --git a/src/proof/sat_proof.cpp b/src/proof/sat_proof.cpp
index 0ace84b4d..f7b9c4889 100644
--- a/src/proof/sat_proof.cpp
+++ b/src/proof/sat_proof.cpp
@@ -57,9 +57,6 @@ void printDebug (Minisat::Clause& c) {
Debug("proof:sat") << endl;
}
-
-int SatProof::d_idCounter = 0;
-
/**
* Converts the clause associated to id to a set of literals
*
@@ -274,7 +271,7 @@ ClauseId SatProof::getClauseId(::Minisat::Lit lit) {
Minisat::CRef SatProof::getClauseRef(ClauseId id) {
if (d_idClause.find(id) == d_idClause.end()) {
- Debug("proof:sat") << "proof:getClauseRef cannot find clause "<<id<<" "
+ Debug("proof:sat") << "proof:getClauseRef cannot find clause " << id << " "
<< ((d_deleted.find(id) != d_deleted.end()) ? "deleted" : "")
<< (isUnit(id)? "Unit" : "") << endl;
}
@@ -318,16 +315,14 @@ bool SatProof::isLemmaClause(ClauseId id) {
return (d_lemmaClauses.find(id) != d_lemmaClauses.end());
}
-
void SatProof::print(ClauseId id) {
if (d_deleted.find(id) != d_deleted.end()) {
- Debug("proof:sat") << "del"<<id;
+ Debug("proof:sat") << "del" << id;
} else if (isUnit(id)) {
printLit(getUnit(id));
} else if (id == d_emptyClauseId) {
- Debug("proof:sat") << "empty "<< endl;
- }
- else {
+ Debug("proof:sat") << "empty " << endl;
+ } else {
CRef ref = getClauseRef(id);
printClause(getClause(ref));
}
@@ -335,7 +330,7 @@ void SatProof::print(ClauseId id) {
void SatProof::printRes(ClauseId id) {
Assert(hasResolution(id));
- Debug("proof:sat") << "id "<< id <<": ";
+ Debug("proof:sat") << "id " << id << ": ";
printRes(d_resChains[id]);
}
@@ -364,42 +359,44 @@ void SatProof::printRes(ResChain* res) {
/// registration methods
-ClauseId SatProof::registerClause(::Minisat::CRef clause, ClauseKind kind) {
+ClauseId SatProof::registerClause(::Minisat::CRef clause, ClauseKind kind, uint64_t proof_id) {
+ Debug("cores") << "registerClause " << proof_id << std::endl;
Assert(clause != CRef_Undef);
ClauseIdMap::iterator it = d_clauseId.find(clause);
if (it == d_clauseId.end()) {
- ClauseId newId = d_idCounter++;
+ ClauseId newId = ProofManager::currentPM()->nextId();
d_clauseId[clause] = newId;
d_idClause[newId] = clause;
if (kind == INPUT) {
Assert(d_inputClauses.find(newId) == d_inputClauses.end());
- d_inputClauses.insert(newId);
+ d_inputClauses[newId] = proof_id;
}
if (kind == THEORY_LEMMA) {
Assert(d_lemmaClauses.find(newId) == d_lemmaClauses.end());
- d_lemmaClauses.insert(newId);
+ d_lemmaClauses[newId] = proof_id;
}
}
- Debug("proof:sat:detailed") <<"registerClause CRef:" << clause <<" id:" << d_clauseId[clause] << " " << kind << "\n";
+ Debug("proof:sat:detailed") << "registerClause CRef:" << clause << " id:" << d_clauseId[clause] << " " << kind << " " << int32_t((proof_id >> 32) & 0xffffffff) << "\n";
return d_clauseId[clause];
}
-ClauseId SatProof::registerUnitClause(::Minisat::Lit lit, ClauseKind kind) {
+ClauseId SatProof::registerUnitClause(::Minisat::Lit lit, ClauseKind kind, uint64_t proof_id) {
+ Debug("cores") << "registerUnitClause " << kind << " " << proof_id << std::endl;
UnitIdMap::iterator it = d_unitId.find(toInt(lit));
if (it == d_unitId.end()) {
- ClauseId newId = d_idCounter++;
+ ClauseId newId = ProofManager::currentPM()->nextId();
d_unitId[toInt(lit)] = newId;
d_idUnit[newId] = lit;
if (kind == INPUT) {
Assert(d_inputClauses.find(newId) == d_inputClauses.end());
- d_inputClauses.insert(newId);
+ d_inputClauses[newId] = proof_id;
}
if (kind == THEORY_LEMMA) {
Assert(d_lemmaClauses.find(newId) == d_lemmaClauses.end());
- d_lemmaClauses.insert(newId);
+ d_lemmaClauses[newId] = proof_id;
}
}
- Debug("proof:sat:detailed") <<"registerUnitClause " << d_unitId[toInt(lit)] << " " << kind <<"\n";
+ Debug("proof:sat:detailed") << "registerUnitClause " << d_unitId[toInt(lit)] << " " << kind << "\n";
return d_unitId[toInt(lit)];
}
@@ -445,7 +442,7 @@ void SatProof::removeRedundantFromRes(ResChain* res, ClauseId id) {
removedDfs(*it, removed, removeStack, inClause, seen);
}
- for (int i = removeStack.size()-1; i >= 0; --i) {
+ for (int i = removeStack.size() - 1; i >= 0; --i) {
Lit lit = removeStack[i];
CRef reason_ref = d_solver->reason(var(lit));
ClauseId reason_id;
@@ -454,7 +451,7 @@ void SatProof::removeRedundantFromRes(ResChain* res, ClauseId id) {
Assert(isUnit(~lit));
reason_id = getUnitId(~lit);
} else {
- reason_id = registerClause(reason_ref);
+ reason_id = registerClause(reason_ref, LEARNT, uint64_t(-1));
}
res->addStep(lit, reason_id, !sign(lit));
}
@@ -486,14 +483,14 @@ void SatProof::startResChain(::Minisat::CRef start) {
}
void SatProof::addResolutionStep(::Minisat::Lit lit, ::Minisat::CRef clause, bool sign) {
- ClauseId id = registerClause(clause);
+ ClauseId id = registerClause(clause, LEARNT, uint64_t(-1));
ResChain* res = d_resStack.back();
res->addStep(lit, id, sign);
}
void SatProof::endResChain(CRef clause) {
Assert(d_resStack.size() > 0);
- ClauseId id = registerClause(clause);
+ ClauseId id = registerClause(clause, LEARNT, uint64_t(-1));
ResChain* res = d_resStack.back();
registerResolution(id, res);
d_resStack.pop_back();
@@ -502,7 +499,7 @@ void SatProof::endResChain(CRef clause) {
void SatProof::endResChain(::Minisat::Lit lit) {
Assert(d_resStack.size() > 0);
- ClauseId id = registerUnitClause(lit);
+ ClauseId id = registerUnitClause(lit, LEARNT, uint64_t(-1));
ResChain* res = d_resStack.back();
registerResolution(id, res);
d_resStack.pop_back();
@@ -523,6 +520,7 @@ void SatProof::resolveOutUnit(::Minisat::Lit lit) {
}
void SatProof::storeUnitResolution(::Minisat::Lit lit) {
+ Debug("cores") << "STORE UNIT RESOLUTION" << std::endl;
resolveUnit(lit);
}
@@ -536,7 +534,7 @@ ClauseId SatProof::resolveUnit(::Minisat::Lit lit) {
CRef reason_ref = d_solver->reason(var(lit));
Assert(reason_ref != CRef_Undef);
- ClauseId reason_id = registerClause(reason_ref);
+ ClauseId reason_id = registerClause(reason_ref, LEARNT, uint64_t(-1));
ResChain* res = new ResChain(reason_id);
// Here, the call to resolveUnit() can reallocate memory in the
@@ -551,7 +549,7 @@ ClauseId SatProof::resolveUnit(::Minisat::Lit lit) {
res->addStep(l, res_id, !sign(l));
}
}
- ClauseId unit_id = registerUnitClause(lit);
+ ClauseId unit_id = registerUnitClause(lit, LEARNT, uint64_t(-1));
registerResolution(unit_id, res);
return unit_id;
}
@@ -561,11 +559,12 @@ void SatProof::toStream(std::ostream& out) {
Unimplemented("native proof printing not supported yet");
}
-void SatProof::storeUnitConflict(::Minisat::Lit conflict_lit, ClauseKind kind) {
+void SatProof::storeUnitConflict(::Minisat::Lit conflict_lit, ClauseKind kind, uint64_t proof_id) {
+ Debug("cores") << "STORE UNIT CONFLICT" << std::endl;
Assert(!d_storedUnitConflict);
- d_unitConflictId = registerUnitClause(conflict_lit, kind);
+ d_unitConflictId = registerUnitClause(conflict_lit, kind, proof_id);
d_storedUnitConflict = true;
- Debug("proof:sat:detailed") <<"storeUnitConflict " << d_unitConflictId << "\n";
+ Debug("proof:sat:detailed") << "storeUnitConflict " << d_unitConflictId << "\n";
}
void SatProof::finalizeProof(::Minisat::CRef conflict_ref) {
@@ -586,7 +585,7 @@ void SatProof::finalizeProof(::Minisat::CRef conflict_ref) {
return;
} else {
Assert(!d_storedUnitConflict);
- conflict_id = registerClause(conflict_ref); //FIXME
+ conflict_id = registerClause(conflict_ref, LEARNT, uint64_t(-1)); //FIXME
}
if(Debug.isOn("proof:sat")) {
@@ -652,11 +651,10 @@ std::string SatProof::clauseName(ClauseId id) {
if (isInputClause(id)) {
os << ProofManager::getInputClauseName(id);
return os.str();
- } else
- if (isLemmaClause(id)) {
+ } else if (isLemmaClause(id)) {
os << ProofManager::getLemmaClauseName(id);
return os.str();
- }else {
+ } else {
os << ProofManager::getLearntClauseName(id);
return os.str();
}
@@ -728,10 +726,9 @@ void LFSCSatProof::printResolution(ClauseId id, std::ostream& out, std::ostream&
ResChain* res = d_resChains[id];
ResSteps& steps = res->getSteps();
- for (int i = steps.size()-1; i >= 0; i--) {
+ for (int i = steps.size() - 1; i >= 0; --i) {
out << "(";
out << (steps[i].sign? "R" : "Q") << " _ _ ";
-
}
ClauseId start_id = res->getStart();
@@ -742,11 +739,13 @@ void LFSCSatProof::printResolution(ClauseId id, std::ostream& out, std::ostream&
out << clauseName(start_id) << " ";
for(unsigned i = 0; i < steps.size(); i++) {
- out << clauseName(steps[i].id) << " "<<ProofManager::getVarName(MinisatSatSolver::toSatVariable(var(steps[i].lit))) <<")";
+ out << clauseName(steps[i].id) << " "
+ << ProofManager::getVarName(MinisatSatSolver::toSatVariable(var(steps[i].lit)))
+ << ") ";
}
if (id == d_emptyClauseId) {
- out <<"(\\empty empty)";
+ out << "(\\empty empty)";
return;
}
@@ -763,6 +762,4 @@ void LFSCSatProof::printResolutions(std::ostream& out, std::ostream& paren) {
printResolution(d_emptyClauseId, out, paren);
}
-
} /* CVC4 namespace */
-
diff --git a/src/proof/sat_proof.h b/src/proof/sat_proof.h
index 7795dfa9c..ef4e7a5aa 100644
--- a/src/proof/sat_proof.h
+++ b/src/proof/sat_proof.h
@@ -86,6 +86,7 @@ typedef std::hash_map < ClauseId, ::Minisat::Lit> IdUnitMap;
typedef std::hash_map < int, ClauseId> UnitIdMap; //FIXME
typedef std::hash_map < ClauseId, ResChain*> IdResMap;
typedef std::hash_set < ClauseId > IdHashSet;
+typedef std::hash_map < ClauseId, uint64_t > IdProofRuleMap;
typedef std::vector < ResChain* > ResStack;
typedef std::hash_map <ClauseId, prop::SatClause* > IdToSatClause;
typedef std::set < ClauseId > IdSet;
@@ -115,14 +116,15 @@ protected:
UnitIdMap d_unitId;
IdHashSet d_deleted;
IdToSatClause d_deletedTheoryLemmas;
- IdHashSet d_inputClauses;
- IdHashSet d_lemmaClauses;
+public:
+ IdProofRuleMap d_inputClauses;
+ IdProofRuleMap d_lemmaClauses;
+protected:
// resolutions
IdResMap d_resChains;
ResStack d_resStack;
bool d_checkRes;
- static ClauseId d_idCounter;
const ClauseId d_emptyClauseId;
const ClauseId d_nullId;
// proxy class to break circular dependencies
@@ -144,6 +146,7 @@ protected:
void printRes(ResChain* res);
bool isInputClause(ClauseId id);
+ bool isTheoryConflict(ClauseId id);
bool isLemmaClause(ClauseId id);
bool isUnit(ClauseId id);
bool isUnit(::Minisat::Lit lit);
@@ -207,10 +210,10 @@ public:
void finalizeProof(::Minisat::CRef conflict);
/// clause registration methods
- ClauseId registerClause(const ::Minisat::CRef clause, ClauseKind kind = LEARNT);
- ClauseId registerUnitClause(const ::Minisat::Lit lit, ClauseKind kind = LEARNT);
+ ClauseId registerClause(const ::Minisat::CRef clause, ClauseKind kind, uint64_t proof_id);
+ ClauseId registerUnitClause(const ::Minisat::Lit lit, ClauseKind kind, uint64_t proof_id);
- void storeUnitConflict(::Minisat::Lit lit, ClauseKind kind = LEARNT);
+ void storeUnitConflict(::Minisat::Lit lit, ClauseKind kind, uint64_t proof_id);
/**
* Marks the deleted clauses as deleted. Note we may still use them in the final
@@ -242,6 +245,7 @@ public:
protected:
IdSet d_seenLearnt;
IdHashSet d_seenInput;
+ IdHashSet d_seenTheoryConflicts;
IdHashSet d_seenLemmas;
inline std::string varName(::Minisat::Lit lit);
diff --git a/src/prop/bvminisat/bvminisat.cpp b/src/prop/bvminisat/bvminisat.cpp
index 7322cd0fa..71b8eb69d 100644
--- a/src/prop/bvminisat/bvminisat.cpp
+++ b/src/prop/bvminisat/bvminisat.cpp
@@ -5,7 +5,7 @@
** Major contributors:
** Minor contributors (to current version):
** This file is part of the CVC4 prototype.
- ** Copyright (c) 2009, 2010, 2011 The Analysis of Computer Systems Group (ACSys)
+ ** Copyright (c) 2009-2014 The Analysis of Computer Systems Group (ACSys)
** Courant Institute of Mathematical Sciences
** New York University
** See the file COPYING in the top-level source directory for licensing
@@ -45,7 +45,7 @@ void BVMinisatSatSolver::setNotify(Notify* notify) {
d_minisat->setNotify(d_minisatNotify);
}
-void BVMinisatSatSolver::addClause(SatClause& clause, bool removable) {
+void BVMinisatSatSolver::addClause(SatClause& clause, bool removable, uint64_t proof_id) {
Debug("sat::minisat") << "Add clause " << clause <<"\n";
BVMinisat::vec<BVMinisat::Lit> minisat_clause;
toMinisatClause(clause, minisat_clause);
@@ -97,6 +97,11 @@ void BVMinisatSatSolver::markUnremovable(SatLiteral lit){
d_minisat->setFrozen(BVMinisat::var(toMinisatLit(lit)), true);
}
+bool BVMinisatSatSolver::spendResource(){
+ // Do nothing for the BV solver.
+ return false;
+}
+
void BVMinisatSatSolver::interrupt(){
d_minisat->interrupt();
}
diff --git a/src/prop/bvminisat/bvminisat.h b/src/prop/bvminisat/bvminisat.h
index f9d0fbd6a..c7ee2e0b7 100644
--- a/src/prop/bvminisat/bvminisat.h
+++ b/src/prop/bvminisat/bvminisat.h
@@ -5,7 +5,7 @@
** Major contributors:
** Minor contributors (to current version):
** This file is part of the CVC4 prototype.
- ** Copyright (c) 2009, 2010, 2011 The Analysis of Computer Systems Group (ACSys)
+ ** Copyright (c) 2009-2014 The Analysis of Computer Systems Group (ACSys)
** Courant Institute of Mathematical Sciences
** New York University
** See the file COPYING in the top-level source directory for licensing
@@ -76,7 +76,7 @@ public:
void setNotify(Notify* notify);
- void addClause(SatClause& clause, bool removable);
+ void addClause(SatClause& clause, bool removable, uint64_t proof_id);
SatValue propagate();
@@ -87,6 +87,8 @@ public:
void markUnremovable(SatLiteral lit);
+ bool spendResource();
+
void interrupt();
SatValue solve();
diff --git a/src/prop/cnf_stream.cpp b/src/prop/cnf_stream.cpp
index e0697735f..ad187aa46 100644
--- a/src/prop/cnf_stream.cpp
+++ b/src/prop/cnf_stream.cpp
@@ -44,7 +44,6 @@ using namespace CVC4::kind;
namespace CVC4 {
namespace prop {
-
CnfStream::CnfStream(SatSolver *satSolver, Registrar* registrar, context::Context* context, bool fullLitToNodeMap) :
d_satSolver(satSolver),
d_booleanVariables(context),
@@ -52,6 +51,7 @@ CnfStream::CnfStream(SatSolver *satSolver, Registrar* registrar, context::Contex
d_literalToNodeMap(context),
d_fullLitToNodeMap(fullLitToNodeMap),
d_registrar(registrar),
+ d_assertionTable(context),
d_removable(false) {
}
@@ -74,7 +74,7 @@ void CnfStream::assertClause(TNode node, SatClause& c) {
Dump("clauses") << AssertCommand(Expr(n.toExpr()));
}
}
- d_satSolver->addClause(c, d_removable);
+ d_satSolver->addClause(c, d_removable, d_proofId);
}
void CnfStream::assertClause(TNode node, SatLiteral a) {
@@ -104,9 +104,9 @@ bool CnfStream::hasLiteral(TNode n) const {
}
void TseitinCnfStream::ensureLiteral(TNode n) {
-
- // These are not removable
+ // These are not removable and have no proof ID
d_removable = false;
+ d_proofId = uint64_t(-1);
Debug("cnf") << "ensureLiteral(" << n << ")" << endl;
if(hasLiteral(n)) {
@@ -188,9 +188,12 @@ SatLiteral CnfStream::newLiteral(TNode node, bool isTheoryAtom, bool preRegister
// If a theory literal, we pre-register it
if (preRegister) {
- bool backup = d_removable;
+ // In case we are re-entered due to lemmas, save our state
+ bool backupRemovable = d_removable;
+ uint64_t backupProofId= d_proofId;
d_registrar->preRegister(node);
- d_removable = backup;
+ d_removable = backupRemovable;
+ d_proofId = backupProofId;
}
// Here, you can have it
@@ -642,9 +645,20 @@ void TseitinCnfStream::convertAndAssertIte(TNode node, bool negated) {
// At the top level we must ensure that all clauses that are asserted are
// not unit, except for the direct assertions. This allows us to remove the
// clauses later when they are not needed anymore (lemmas for example).
-void TseitinCnfStream::convertAndAssert(TNode node, bool removable, bool negated) {
+void TseitinCnfStream::convertAndAssert(TNode node, bool removable, bool negated, ProofRule proof_id, TNode from) {
Debug("cnf") << "convertAndAssert(" << node << ", removable = " << (removable ? "true" : "false") << ", negated = " << (negated ? "true" : "false") << ")" << endl;
d_removable = removable;
+ if(options::proof() || options::unsatCores()) {
+ // Encode the assertion ID in the proof_id to store with generated clauses.
+ uint64_t assertionTableIndex = d_assertionTable.size();
+ Assert((uint64_t(proof_id) & 0xffffffff00000000llu) == 0 && (assertionTableIndex & 0xffffffff00000000llu) == 0, "proof_id/table_index collision");
+ d_proofId = assertionTableIndex | (uint64_t(proof_id) << 32);
+ d_assertionTable.push_back(from.isNull() ? node : from);
+ Debug("cores") << "cnf ix " << assertionTableIndex << " asst " << node << " proof_id " << proof_id << " from " << from << endl;
+ } else {
+ // We aren't producing proofs or unsat cores; use an invalid proof id.
+ d_proofId = uint64_t(-1);
+ }
convertAndAssert(node, negated);
}
diff --git a/src/prop/cnf_stream.h b/src/prop/cnf_stream.h
index 266362ef5..b76051279 100644
--- a/src/prop/cnf_stream.h
+++ b/src/prop/cnf_stream.h
@@ -28,6 +28,7 @@
#include "expr/node.h"
#include "prop/theory_proxy.h"
#include "prop/registrar.h"
+#include "proof/proof_manager.h"
#include "context/cdlist.h"
#include "context/cdinsert_hashmap.h"
@@ -36,7 +37,6 @@
namespace CVC4 {
namespace prop {
-
class PropEngine;
/**
@@ -77,6 +77,9 @@ protected:
/** The "registrar" for pre-registration of terms */
Registrar* d_registrar;
+ /** A table of assertions, used for regenerating proofs. */
+ context::CDList<Node> d_assertionTable;
+
/**
* How many literals were already mapped at the top-level when we
* tried to convertAndAssert() something. This
@@ -104,10 +107,18 @@ protected:
}
/**
+ * A reference into the assertion table, used to map clauses back to
+ * their "original" input assertion/lemma. This variable is manipulated
+ * by the top-level convertAndAssert(). This is needed in proofs-enabled
+ * runs, to justify where the SAT solver's clauses came from.
+ */
+ uint64_t d_proofId;
+
+ /**
* Are we asserting a removable clause (true) or a permanent clause (false).
* This is set at the beginning of convertAndAssert so that it doesn't
- * need to be passed on over the stack. Only pure clauses can be asserted as
- * removable.
+ * need to be passed on over the stack. Only pure clauses can be asserted
+ * as removable.
*/
bool d_removable;
@@ -190,7 +201,7 @@ public:
* @param removable whether the sat solver can choose to remove the clauses
* @param negated whether we are asserting the node negated
*/
- virtual void convertAndAssert(TNode node, bool removable, bool negated) = 0;
+ virtual void convertAndAssert(TNode node, bool removable, bool negated, ProofRule proof_id, TNode from = TNode::null()) = 0;
/**
* Get the node that is represented by the given SatLiteral.
@@ -223,6 +234,13 @@ public:
SatLiteral getLiteral(TNode node);
/**
+ * Get the assertion with a given ID. (Used for reconstructing proofs.)
+ */
+ TNode getAssertion(uint64_t id) {
+ return d_assertionTable[id];
+ }
+
+ /**
* Returns the Boolean variables from the input problem.
*/
void getBooleanVariables(std::vector<TNode>& outputVariables) const;
@@ -258,7 +276,7 @@ public:
* @param removable is this something that can be erased
* @param negated true if negated
*/
- void convertAndAssert(TNode node, bool removable, bool negated);
+ void convertAndAssert(TNode node, bool removable, bool negated, ProofRule proof_id, TNode from = TNode::null());
/**
* Constructs the stream to use the given sat solver.
diff --git a/src/prop/minisat/core/Solver.cc b/src/prop/minisat/core/Solver.cc
index 610023b70..e5e28bb0b 100644
--- a/src/prop/minisat/core/Solver.cc
+++ b/src/prop/minisat/core/Solver.cc
@@ -106,7 +106,7 @@ Solver::Solver(CVC4::prop::TheoryProxy* proxy, CVC4::context::Context* context,
// Statistics: (formerly in 'SolverStats')
//
- , solves(0), starts(0), decisions(0), rnd_decisions(0), propagations(0), conflicts(0)
+ , solves(0), starts(0), decisions(0), rnd_decisions(0), propagations(0), conflicts(0), resources_consumed(0)
, dec_vars(0), clauses_literals(0), learnts_literals(0), max_literals(0), tot_literals(0)
, ok (true)
@@ -135,8 +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), INPUT); )
- PROOF( ProofManager::getSatProof()->registerUnitClause(mkLit(varFalse, true), INPUT); )
+ PROOF( ProofManager::getSatProof()->registerUnitClause(mkLit(varTrue, false), INPUT, uint64_t(-1)); )
+ PROOF( ProofManager::getSatProof()->registerUnitClause(mkLit(varFalse, true), INPUT, uint64_t(-1)); )
}
@@ -263,7 +263,7 @@ CRef Solver::reason(Var x) {
// Construct the reason
CRef real_reason = ca.alloc(explLevel, explanation, true);
- PROOF (ProofManager::getSatProof()->registerClause(real_reason, THEORY_LEMMA); );
+ PROOF (ProofManager::getSatProof()->registerClause(real_reason, THEORY_LEMMA, (uint64_t(RULE_CONFLICT) << 32)); );
vardata[x] = VarData(real_reason, level(x), user_level(x), intro_level(x), trail_index(x));
clauses_removable.push(real_reason);
attachClause(real_reason);
@@ -271,7 +271,7 @@ CRef Solver::reason(Var x) {
return real_reason;
}
-bool Solver::addClause_(vec<Lit>& ps, bool removable)
+bool Solver::addClause_(vec<Lit>& ps, bool removable, uint64_t proof_id)
{
if (!ok) return false;
@@ -321,6 +321,8 @@ bool Solver::addClause_(vec<Lit>& ps, bool removable)
lemmas.push();
ps.copyTo(lemmas.last());
lemmas_removable.push(removable);
+ Debug("cores") << "lemma push " << proof_id << " " << (proof_id & 0xffffffff) << std::endl;
+ lemmas_proof_id.push(proof_id);
} else {
// If all false, we're in conflict
if (ps.size() == falseLiteralsCount) {
@@ -329,7 +331,7 @@ bool Solver::addClause_(vec<Lit>& ps, bool removable)
// construct the clause below to give to the proof manager
// as the final conflict.
if(falseLiteralsCount == 1) {
- PROOF( ProofManager::getSatProof()->storeUnitConflict(ps[0], INPUT); )
+ PROOF( ProofManager::getSatProof()->storeUnitConflict(ps[0], INPUT, proof_id); )
PROOF( ProofManager::getSatProof()->finalizeProof(::Minisat::CRef_Lazy); )
return ok = false;
}
@@ -351,7 +353,7 @@ bool Solver::addClause_(vec<Lit>& ps, bool removable)
attachClause(cr);
if(PROOF_ON()) {
- PROOF( ProofManager::getSatProof()->registerClause(cr, INPUT); )
+ PROOF( ProofManager::getSatProof()->registerClause(cr, INPUT, proof_id); )
if(ps.size() == falseLiteralsCount) {
PROOF( ProofManager::getSatProof()->finalizeProof(cr); )
return ok = false;
@@ -364,11 +366,12 @@ bool Solver::addClause_(vec<Lit>& ps, bool removable)
if(assigns[var(ps[0])] == l_Undef) {
assert(assigns[var(ps[0])] != l_False);
uncheckedEnqueue(ps[0], cr);
- PROOF( if(ps.size() == 1) { ProofManager::getSatProof()->registerUnitClause(ps[0], INPUT); } );
+ Debug("cores") << "i'm registering a unit clause, input, proof id " << proof_id << std::endl;
+ PROOF( if(ps.size() == 1) { ProofManager::getSatProof()->registerUnitClause(ps[0], INPUT, proof_id); } );
CRef confl = propagate(CHECK_WITHOUT_THEORY);
if(! (ok = (confl == CRef_Undef)) ) {
if(ca[confl].size() == 1) {
- PROOF( ProofManager::getSatProof()->storeUnitConflict(ca[confl][0], LEARNT); );
+ PROOF( ProofManager::getSatProof()->storeUnitConflict(ca[confl][0], LEARNT, proof_id); );
PROOF( ProofManager::getSatProof()->finalizeProof(::Minisat::CRef_Lazy); )
} else {
PROOF( ProofManager::getSatProof()->finalizeProof(confl); );
@@ -812,7 +815,8 @@ CRef Solver::propagate(TheoryCheckType type)
if (type == CHECK_FINAL) {
// Do the theory check
theoryCheck(CVC4::theory::Theory::EFFORT_FULL);
- // Pick up the theory propagated literals (there could be some, if new lemmas are added)
+ // Pick up the theory propagated literals (there could be some,
+ // if new lemmas are added)
propagateTheory();
// If there are lemmas (or conflicts) update them
if (lemmas.size() > 0) {
@@ -842,7 +846,7 @@ CRef Solver::propagate(TheoryCheckType type)
propagateTheory();
// If there are lemmas (or conflicts) update them
if (lemmas.size() > 0) {
- confl = updateLemmas();
+ confl = updateLemmas();
}
} else {
// Even though in conflict, we still need to discharge the lemmas
@@ -891,7 +895,7 @@ void Solver::propagateTheory() {
proxy->explainPropagation(MinisatSatSolver::toSatLiteral(p), explanation_cl);
vec<Lit> explanation;
MinisatSatSolver::toMinisatClause(explanation_cl, explanation);
- addClause(explanation, true);
+ addClause(explanation, true, 0);
}
}
}
@@ -1588,6 +1592,9 @@ CRef Solver::updateLemmas() {
Debug("minisat::lemmas") << "Solver::updateLemmas() begin" << std::endl;
+ // Avoid adding lemmas indefinitely without resource-out
+ spendResource();
+
CRef conflict = CRef_Undef;
// Decision level to backtrack to
@@ -1642,6 +1649,8 @@ CRef Solver::updateLemmas() {
// The current lemma
vec<Lit>& lemma = lemmas[i];
bool removable = lemmas_removable[i];
+ uint64_t proof_id = lemmas_proof_id[i];
+ Debug("cores") << "pulled lemma proof id " << proof_id << " " << (proof_id & 0xffffffff) << std::endl;
// Attach it if non-unit
CRef lemma_ref = CRef_Undef;
@@ -1656,7 +1665,7 @@ CRef Solver::updateLemmas() {
}
lemma_ref = ca.alloc(clauseLevel, lemma, removable);
- PROOF( ProofManager::getSatProof()->registerClause(lemma_ref, THEORY_LEMMA); );
+ PROOF( ProofManager::getSatProof()->registerClause(lemma_ref, THEORY_LEMMA, proof_id); );
if (removable) {
clauses_removable.push(lemma_ref);
} else {
@@ -1664,7 +1673,7 @@ CRef Solver::updateLemmas() {
}
attachClause(lemma_ref);
} else {
- PROOF( ProofManager::getSatProof()->registerUnitClause(lemma[0], THEORY_LEMMA); );
+ PROOF( ProofManager::getSatProof()->registerUnitClause(lemma[0], THEORY_LEMMA, proof_id); );
}
// If the lemma is propagating enqueue its literal (or set the conflict)
@@ -1678,7 +1687,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]); );
+ PROOF( ProofManager::getSatProof()->storeUnitConflict(lemma[0], LEARNT, proof_id); );
}
} else {
Debug("minisat::lemmas") << "lemma size is " << lemma.size() << std::endl;
@@ -1691,6 +1700,7 @@ CRef Solver::updateLemmas() {
// Clear the lemmas
lemmas.clear();
lemmas_removable.clear();
+ lemmas_proof_id.clear();
if (conflict != CRef_Undef) {
theoryConflict = true;
diff --git a/src/prop/minisat/core/Solver.h b/src/prop/minisat/core/Solver.h
index 30d72ac75..6d9fd538f 100644
--- a/src/prop/minisat/core/Solver.h
+++ b/src/prop/minisat/core/Solver.h
@@ -37,12 +37,11 @@ OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWA
#include "expr/command.h"
namespace CVC4 {
-class SatProof;
-
-namespace prop {
- class TheoryProxy;
-}/* CVC4::prop namespace */
+ class SatProof;
+ namespace prop {
+ class TheoryProxy;
+ }/* CVC4::prop namespace */
}/* CVC4 namespace */
namespace Minisat {
@@ -85,6 +84,9 @@ protected:
/** Is the lemma removable */
vec<bool> lemmas_removable;
+ /** Proof IDs for lemmas */
+ vec<uint64_t> lemmas_proof_id;
+
/** Do a another check if FULL_EFFORT was the last one */
bool recheck;
@@ -154,12 +156,14 @@ public:
void push ();
void pop ();
- bool addClause (const vec<Lit>& ps, bool removable); // Add a clause to the solver.
+ // CVC4 adds the "proof_id" here to refer to the input assertion/lemma
+ // that produced this clause
+ bool addClause (const vec<Lit>& ps, bool removable, uint64_t proof_id); // Add a clause to the solver.
bool addEmptyClause(bool removable); // Add the empty clause, making the solver contradictory.
- bool addClause (Lit p, bool removable); // Add a unit clause to the solver.
- bool addClause (Lit p, Lit q, bool removable); // Add a binary clause to the solver.
- bool addClause (Lit p, Lit q, Lit r, bool removable); // Add a ternary clause to the solver.
- bool addClause_( vec<Lit>& ps, bool removable); // Add a clause to the solver without making superflous internal copy. Will
+ bool addClause (Lit p, bool removable, uint64_t proof_id); // Add a unit clause to the solver.
+ bool addClause (Lit p, Lit q, bool removable, uint64_t proof_id); // Add a binary clause to the solver.
+ bool addClause (Lit p, Lit q, Lit r, bool removable, uint64_t proof_id); // Add a ternary clause to the solver.
+ bool addClause_( vec<Lit>& ps, bool removable, uint64_t proof_id); // Add a clause to the solver without making superflous internal copy. Will
// change the passed vector 'ps'.
// Solving:
@@ -215,6 +219,7 @@ public:
void budgetOff();
void interrupt(); // Trigger a (potentially asynchronous) interruption of the solver.
void clearInterrupt(); // Clear interrupt indicator flag.
+ void spendResource();
// Memory managment:
//
@@ -252,7 +257,7 @@ public:
// Statistics: (read-only member variable)
//
- uint64_t solves, starts, decisions, rnd_decisions, propagations, conflicts;
+ uint64_t solves, starts, decisions, rnd_decisions, propagations, conflicts, resources_consumed;
uint64_t dec_vars, clauses_literals, learnts_literals, max_literals, tot_literals;
protected:
@@ -418,7 +423,9 @@ protected:
int intro_level (Var x) const; // User level at which this variable was created
int trail_index (Var x) const; // Index in the trail
double progressEstimate () const; // DELETE THIS ?? IT'S NOT VERY USEFUL ...
+public:
bool withinBudget () const;
+protected:
// Static helpers:
//
@@ -488,11 +495,15 @@ inline void Solver::checkGarbage(double gf){
// NOTE: enqueue does not set the ok flag! (only public methods do)
inline bool Solver::enqueue (Lit p, CRef from) { return value(p) != l_Undef ? value(p) != l_False : (uncheckedEnqueue(p, from), true); }
-inline bool Solver::addClause (const vec<Lit>& ps, bool removable) { ps.copyTo(add_tmp); return addClause_(add_tmp, removable); }
-inline bool Solver::addEmptyClause (bool removable) { add_tmp.clear(); return addClause_(add_tmp, removable); }
-inline bool Solver::addClause (Lit p, bool removable) { add_tmp.clear(); add_tmp.push(p); return addClause_(add_tmp, removable); }
-inline bool Solver::addClause (Lit p, Lit q, bool removable) { add_tmp.clear(); add_tmp.push(p); add_tmp.push(q); return addClause_(add_tmp, removable); }
-inline bool Solver::addClause (Lit p, Lit q, Lit r, bool removable) { add_tmp.clear(); add_tmp.push(p); add_tmp.push(q); add_tmp.push(r); return addClause_(add_tmp, removable); }
+inline bool Solver::addClause (const vec<Lit>& ps, bool removable, uint64_t proof_id)
+ { ps.copyTo(add_tmp); return addClause_(add_tmp, removable, proof_id); }
+inline bool Solver::addEmptyClause (bool removable) { add_tmp.clear(); return addClause_(add_tmp, removable, uint64_t(-1)); }
+inline bool Solver::addClause (Lit p, bool removable, uint64_t proof_id)
+ { add_tmp.clear(); add_tmp.push(p); return addClause_(add_tmp, removable, proof_id); }
+inline bool Solver::addClause (Lit p, Lit q, bool removable, uint64_t proof_id)
+ { add_tmp.clear(); add_tmp.push(p); add_tmp.push(q); return addClause_(add_tmp, removable, proof_id); }
+inline bool Solver::addClause (Lit p, Lit q, Lit r, bool removable, uint64_t proof_id)
+ { add_tmp.clear(); add_tmp.push(p); add_tmp.push(q); add_tmp.push(r); return addClause_(add_tmp, removable, proof_id); }
inline bool Solver::locked (const Clause& c) const { return value(c[0]) == l_True && isPropagatedBy(var(c[0]), c); }
inline void Solver::newDecisionLevel() { trail_lim.push(trail.size()); flipped.push(false); context->push(); if(Dump.isOn("state")) { Dump("state") << CVC4::PushCommand(); } }
@@ -526,8 +537,9 @@ inline void Solver::clearInterrupt(){ asynch_interrupt = false; }
inline void Solver::budgetOff(){ conflict_budget = propagation_budget = -1; }
inline bool Solver::withinBudget() const {
return !asynch_interrupt &&
- (conflict_budget < 0 || conflicts < (uint64_t)conflict_budget) &&
+ (conflict_budget < 0 || conflicts + resources_consumed < (uint64_t)conflict_budget) &&
(propagation_budget < 0 || propagations < (uint64_t)propagation_budget); }
+inline void Solver::spendResource() { ++resources_consumed; }
// FIXME: after the introduction of asynchronous interrruptions the solve-versions that return a
// pure bool do not give a safe interface. Either interrupts must be possible to turn off here, or
diff --git a/src/prop/minisat/minisat.cpp b/src/prop/minisat/minisat.cpp
index e4956ecc8..99341455c 100644
--- a/src/prop/minisat/minisat.cpp
+++ b/src/prop/minisat/minisat.cpp
@@ -149,10 +149,10 @@ void MinisatSatSolver::setupOptions() {
d_minisat->restart_inc = options::satRestartInc();
}
-void MinisatSatSolver::addClause(SatClause& clause, bool removable) {
+void MinisatSatSolver::addClause(SatClause& clause, bool removable, uint64_t proof_id) {
Minisat::vec<Minisat::Lit> minisat_clause;
toMinisatClause(clause, minisat_clause);
- d_minisat->addClause(minisat_clause, removable);
+ d_minisat->addClause(minisat_clause, removable, proof_id);
}
SatVariable MinisatSatSolver::newVar(bool isTheoryAtom, bool preRegister, bool canErase) {
@@ -168,10 +168,10 @@ SatValue MinisatSatSolver::solve(unsigned long& resource) {
d_minisat->setConfBudget(resource);
}
Minisat::vec<Minisat::Lit> empty;
- unsigned long conflictsBefore = d_minisat->conflicts;
+ unsigned long conflictsBefore = d_minisat->conflicts + d_minisat->resources_consumed;
SatValue result = toSatLiteralValue(d_minisat->solveLimited(empty));
d_minisat->clearInterrupt();
- resource = d_minisat->conflicts - conflictsBefore;
+ resource = d_minisat->conflicts + d_minisat->resources_consumed - conflictsBefore;
Trace("limit") << "SatSolver::solve(): it took " << resource << " conflicts" << std::endl;
return result;
}
@@ -182,6 +182,10 @@ SatValue MinisatSatSolver::solve() {
return toSatLiteralValue(d_minisat->solve());
}
+bool MinisatSatSolver::spendResource() {
+ d_minisat->spendResource();
+ return !d_minisat->withinBudget();
+}
void MinisatSatSolver::interrupt() {
d_minisat->interrupt();
@@ -225,7 +229,7 @@ void MinisatSatSolver::push() {
d_minisat->push();
}
-void MinisatSatSolver::pop(){
+void MinisatSatSolver::pop() {
d_minisat->pop();
}
diff --git a/src/prop/minisat/minisat.h b/src/prop/minisat/minisat.h
index a919bbcc4..3d3cea356 100644
--- a/src/prop/minisat/minisat.h
+++ b/src/prop/minisat/minisat.h
@@ -53,7 +53,7 @@ public:
static void toSatClause (const Minisat::Clause& clause, SatClause& sat_clause);
void initialize(context::Context* context, TheoryProxy* theoryProxy);
- void addClause(SatClause& clause, bool removable);
+ void addClause(SatClause& clause, bool removable, uint64_t proof_id);
SatVariable newVar(bool isTheoryAtom, bool preRegister, bool canErase);
SatVariable trueVar() { return d_minisat->trueVar(); }
@@ -62,6 +62,7 @@ public:
SatValue solve();
SatValue solve(long unsigned int&);
+ bool spendResource();
void interrupt();
SatValue value(SatLiteral l);
diff --git a/src/prop/minisat/simp/SimpSolver.cc b/src/prop/minisat/simp/SimpSolver.cc
index 6dcdb76c7..71e747f72 100644
--- a/src/prop/minisat/simp/SimpSolver.cc
+++ b/src/prop/minisat/simp/SimpSolver.cc
@@ -159,7 +159,7 @@ lbool SimpSolver::solve_(bool do_simp, bool turn_off_simp)
-bool SimpSolver::addClause_(vec<Lit>& ps, bool removable)
+bool SimpSolver::addClause_(vec<Lit>& ps, bool removable, uint64_t proof_id)
{
#ifndef NDEBUG
if (use_simplification) {
@@ -173,7 +173,7 @@ bool SimpSolver::addClause_(vec<Lit>& ps, bool removable)
if (use_rcheck && implied(ps))
return true;
- if (!Solver::addClause_(ps, removable))
+ if (!Solver::addClause_(ps, removable, proof_id))
return false;
if (use_simplification && clauses_persistent.size() == nclauses + 1){
@@ -545,7 +545,7 @@ bool SimpSolver::eliminateVar(Var v)
for (int i = 0; i < pos.size(); i++)
for (int j = 0; j < neg.size(); j++) {
bool removable = ca[pos[i]].removable() && ca[pos[neg[j]]].removable();
- if (merge(ca[pos[i]], ca[neg[j]], v, resolvent) && !addClause_(resolvent, removable)) {
+ if (merge(ca[pos[i]], ca[neg[j]], v, resolvent) && !addClause_(resolvent, removable, uint64_t(-1))) {
return false;
}
}
@@ -585,7 +585,7 @@ bool SimpSolver::substitute(Var v, Lit x)
removeClause(cls[i]);
- if (!addClause_(subst_clause, c.removable())) {
+ if (!addClause_(subst_clause, c.removable(), uint64_t(-1))) {
return ok = false;
}
}
diff --git a/src/prop/minisat/simp/SimpSolver.h b/src/prop/minisat/simp/SimpSolver.h
index 878d799a5..041309546 100644
--- a/src/prop/minisat/simp/SimpSolver.h
+++ b/src/prop/minisat/simp/SimpSolver.h
@@ -47,12 +47,12 @@ class SimpSolver : public Solver {
// Problem specification:
//
Var newVar (bool polarity = true, bool dvar = true, bool isTheoryAtom = false, bool preRegister = false, bool canErase = true);
- bool addClause (const vec<Lit>& ps, bool removable);
- bool addEmptyClause(bool removable); // Add the empty clause to the solver.
- bool addClause (Lit p, bool removable); // Add a unit clause to the solver.
- bool addClause (Lit p, Lit q, bool removable); // Add a binary clause to the solver.
- bool addClause (Lit p, Lit q, Lit r, bool removable); // Add a ternary clause to the solver.
- bool addClause_(vec<Lit>& ps, bool removable);
+ bool addClause (const vec<Lit>& ps, bool removable, uint64_t proof_id);
+ bool addEmptyClause(bool removable, uint64_t proof_id); // Add the empty clause to the solver.
+ bool addClause (Lit p, bool removable, uint64_t proof_id); // Add a unit clause to the solver.
+ bool addClause (Lit p, Lit q, bool removable, uint64_t proof_id); // Add a binary clause to the solver.
+ bool addClause (Lit p, Lit q, Lit r, bool removable, uint64_t proof_id); // Add a ternary clause to the solver.
+ bool addClause_(vec<Lit>& ps, bool removable, uint64_t proof_id);
bool substitute(Var v, Lit x); // Replace all occurences of v with x (may cause a contradiction).
// Variable mode:
@@ -182,11 +182,15 @@ inline void SimpSolver::updateElimHeap(Var v) {
elim_heap.update(v); }
-inline bool SimpSolver::addClause (const vec<Lit>& ps, bool removable) { ps.copyTo(add_tmp); return addClause_(add_tmp, removable); }
-inline bool SimpSolver::addEmptyClause(bool removable) { add_tmp.clear(); return addClause_(add_tmp, removable); }
-inline bool SimpSolver::addClause (Lit p, bool removable) { add_tmp.clear(); add_tmp.push(p); return addClause_(add_tmp, removable); }
-inline bool SimpSolver::addClause (Lit p, Lit q, bool removable) { add_tmp.clear(); add_tmp.push(p); add_tmp.push(q); return addClause_(add_tmp, removable); }
-inline bool SimpSolver::addClause (Lit p, Lit q, Lit r, bool removable) { add_tmp.clear(); add_tmp.push(p); add_tmp.push(q); add_tmp.push(r); return addClause_(add_tmp, removable); }
+inline bool SimpSolver::addClause (const vec<Lit>& ps, bool removable, uint64_t proof_id)
+ { ps.copyTo(add_tmp); return addClause_(add_tmp, removable, proof_id); }
+inline bool SimpSolver::addEmptyClause(bool removable, uint64_t proof_id) { add_tmp.clear(); return addClause_(add_tmp, removable, proof_id); }
+inline bool SimpSolver::addClause (Lit p, bool removable, uint64_t proof_id)
+ { add_tmp.clear(); add_tmp.push(p); return addClause_(add_tmp, removable, proof_id); }
+inline bool SimpSolver::addClause (Lit p, Lit q, bool removable, uint64_t proof_id)
+ { add_tmp.clear(); add_tmp.push(p); add_tmp.push(q); return addClause_(add_tmp, removable, proof_id); }
+inline bool SimpSolver::addClause (Lit p, Lit q, Lit r, bool removable, uint64_t proof_id)
+ { add_tmp.clear(); add_tmp.push(p); add_tmp.push(q); add_tmp.push(r); return addClause_(add_tmp, removable, proof_id); }
inline void SimpSolver::setFrozen (Var v, bool b) { frozen[v] = (char)b; if (use_simplification && !b) { updateElimHeap(v); } }
inline bool SimpSolver::solve ( bool do_simp, bool turn_off_simp) { budgetOff(); assumptions.clear(); return solve_(do_simp, turn_off_simp) == l_True; }
diff --git a/src/prop/prop_engine.cpp b/src/prop/prop_engine.cpp
index 82c0bae1a..a998d4240 100644
--- a/src/prop/prop_engine.cpp
+++ b/src/prop/prop_engine.cpp
@@ -25,6 +25,7 @@
#include "decision/options.h"
#include "theory/theory_engine.h"
#include "theory/theory_registrar.h"
+#include "proof/proof_manager.h"
#include "util/cvc4_assert.h"
#include "options/options.h"
#include "smt/options.h"
@@ -78,14 +79,14 @@ PropEngine::PropEngine(TheoryEngine* te, DecisionEngine *de, Context* satContext
Debug("prop") << "Constructing the PropEngine" << endl;
- d_satSolver = SatSolverFactory::createDPLLMinisat();
+ d_satSolver = SatSolverFactory::createDPLLMinisat();
d_registrar = new theory::TheoryRegistrar(d_theoryEngine);
d_cnfStream = new CVC4::prop::TseitinCnfStream
(d_satSolver, d_registrar,
userContext,
- // fullLitToNode Map =
- options::threads() > 1 ||
+ // fullLitToNode Map =
+ options::threads() > 1 ||
options::decisionMode() == decision::DECISION_STRATEGY_RELEVANCY
);
@@ -94,7 +95,7 @@ PropEngine::PropEngine(TheoryEngine* te, DecisionEngine *de, Context* satContext
d_decisionEngine->setSatSolver(d_satSolver);
d_decisionEngine->setCnfStream(d_cnfStream);
- PROOF (ProofManager::currentPM()->initCnfProof(d_cnfStream); );
+ PROOF (ProofManager::currentPM()->initCnfProof(d_cnfStream); );
}
PropEngine::~PropEngine() {
@@ -109,15 +110,15 @@ void PropEngine::assertFormula(TNode node) {
Assert(!d_inCheckSat, "Sat solver in solve()!");
Debug("prop") << "assertFormula(" << node << ")" << endl;
// Assert as non-removable
- d_cnfStream->convertAndAssert(node, false, false);
+ d_cnfStream->convertAndAssert(node, false, false, RULE_GIVEN);
}
-void PropEngine::assertLemma(TNode node, bool negated, bool removable) {
+void PropEngine::assertLemma(TNode node, bool negated, bool removable, ProofRule rule, TNode from) {
//Assert(d_inCheckSat, "Sat solver should be in solve()!");
Debug("prop::lemmas") << "assertLemma(" << node << ")" << endl;
- // Assert as removable
- d_cnfStream->convertAndAssert(node, removable, negated);
+ // Assert as (possibly) removable
+ d_cnfStream->convertAndAssert(node, removable, negated, rule, from);
}
void PropEngine::requirePhase(TNode n, bool phase) {
@@ -278,12 +279,15 @@ void PropEngine::interrupt() throw(ModalException) {
d_interrupted = true;
d_satSolver->interrupt();
- d_theoryEngine->interrupt();
+ d_theoryEngine->interrupt();
Debug("prop") << "interrupt()" << endl;
}
void PropEngine::spendResource() throw() {
- // TODO implement me
+ if(d_satSolver->spendResource()) {
+ d_satSolver->interrupt();
+ d_theoryEngine->interrupt();
+ }
checkTime();
}
diff --git a/src/prop/prop_engine.h b/src/prop/prop_engine.h
index a5132e3da..ed022a64f 100644
--- a/src/prop/prop_engine.h
+++ b/src/prop/prop_engine.h
@@ -25,6 +25,7 @@
#include "options/options.h"
#include "util/result.h"
#include "smt/modal_exception.h"
+#include "proof/proof_manager.h"
#include <sys/time.h>
namespace CVC4 {
@@ -199,7 +200,7 @@ public:
* @param removable whether this lemma can be quietly removed based
* on an activity heuristic (or not)
*/
- void assertLemma(TNode node, bool negated, bool removable);
+ void assertLemma(TNode node, bool negated, bool removable, ProofRule rule, TNode from = TNode::null());
/**
* If ever n is decided upon, it must be in the given phase. This
diff --git a/src/prop/sat_solver.h b/src/prop/sat_solver.h
index 929b867c9..adf6dfd07 100644
--- a/src/prop/sat_solver.h
+++ b/src/prop/sat_solver.h
@@ -24,6 +24,7 @@
#include "util/statistics_registry.h"
#include "context/cdlist.h"
#include "prop/sat_solver_types.h"
+#include "expr/node.h"
namespace CVC4 {
namespace prop {
@@ -38,7 +39,7 @@ public:
virtual ~SatSolver() { }
/** Assert a clause in the solver. */
- virtual void addClause(SatClause& clause, bool removable) = 0;
+ virtual void addClause(SatClause& clause, bool removable, uint64_t proof_id) = 0;
/**
* Create a new boolean variable in the solver.
@@ -61,6 +62,12 @@ public:
/** Check the satisfiability of the added clauses */
virtual SatValue solve(long unsigned int&) = 0;
+ /**
+ * Instruct the solver that it should bump its consumed resource count.
+ * Returns true if resources are exhausted.
+ */
+ virtual bool spendResource() = 0;
+
/** Interrupt the solver */
virtual void interrupt() = 0;
diff --git a/src/prop/theory_proxy.cpp b/src/prop/theory_proxy.cpp
index 67325cb18..2bcd48099 100644
--- a/src/prop/theory_proxy.cpp
+++ b/src/prop/theory_proxy.cpp
@@ -122,7 +122,7 @@ void TheoryProxy::notifyRestart() {
if(lemmaCount % 1 == 0) {
Debug("shared") << "=) " << asNode << std::endl;
}
- d_propEngine->assertLemma(d_theoryEngine->preprocess(asNode), false, true);
+ d_propEngine->assertLemma(d_theoryEngine->preprocess(asNode), false, true, RULE_INVALID);
} else {
Debug("shared") << "=(" << asNode << std::endl;
}
diff --git a/src/smt/boolean_terms.cpp b/src/smt/boolean_terms.cpp
index 89f35bf05..6ce8efef9 100644
--- a/src/smt/boolean_terms.cpp
+++ b/src/smt/boolean_terms.cpp
@@ -724,6 +724,7 @@ Node BooleanTermConverter::rewriteBooleanTermsRec(TNode top, theory::TheoryId pa
goto next_worklist;
}
switch(k) {
+ case kind::INST_ATTRIBUTE:
case kind::BOUND_VAR_LIST:
result.top() << top;
worklist.pop();
diff --git a/src/smt/options b/src/smt/options
index 9c7eea12f..0dc416474 100644
--- a/src/smt/options
+++ b/src/smt/options
@@ -25,7 +25,7 @@ option expandDefinitions expand-definitions bool :default false
always expand symbol definitions in output
common-option produceModels produce-models -m --produce-models bool :default false :predicate CVC4::smt::beforeSearch :predicate-include "smt/smt_engine.h"
support the get-value and get-model commands
-option checkModels check-models --check-models bool :link --produce-models --interactive :link-smt produce-models :link-smt interactive-mode :predicate CVC4::smt::beforeSearch :predicate-include "smt/options_handlers.h"
+option checkModels check-models --check-models bool :link --produce-models --produce-assertions :link-smt produce-models :link-smt produce-assertions :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 :link --produce-models
output models after every SAT/INVALID/UNKNOWN response
@@ -37,16 +37,18 @@ option dumpProofs --dump-proofs bool :default false :link --proof
output proofs after every UNSAT/VALID response
option dumpInstantiations --dump-instantiations bool :default false
output instantiations of quantified formulas after every UNSAT/VALID response
-# this is just a placeholder for later; it doesn't show up in command-line options listings
-undocumented-option unsatCores produce-unsat-cores --produce-unsat-cores bool :predicate CVC4::smt::unsatCoresEnabledBuild CVC4::smt::beforeSearch :predicate-include "smt/options_handlers.h"
- turn on unsat core generation (NOT YET SUPPORTED)
+option unsatCores produce-unsat-cores --produce-unsat-cores bool :predicate CVC4::smt::proofEnabledBuild CVC4::smt::beforeSearch :predicate-include "smt/options_handlers.h"
+ turn on unsat core generation
+option dumpUnsatCores --dump-unsat-cores bool :default false :link --produce-unsat-cores :link-smt produce-unsat-cores :predicate CVC4::smt::beforeSearch :predicate-include "smt/options_handlers.h"
+ output unsat cores after every UNSAT/VALID response
+
option produceAssignments produce-assignments --produce-assignments bool :default false :predicate CVC4::smt::beforeSearch :predicate-include "smt/options_handlers.h"
support the get-assignment command
-# This could go in src/main/options, but by SMT-LIBv2 spec, "interactive"
-# is a mode in which the assertion list must be kept. So it belongs here.
-common-option interactive interactive-mode --interactive bool :predicate CVC4::smt::beforeSearch :predicate-include "smt/options_handlers.h" :read-write
- force interactive mode
+undocumented-option interactiveMode interactive-mode bool :predicate CVC4::smt::beforeSearch CVC4::smt::setProduceAssertions :predicate-include "smt/options_handlers.h" :read-write
+ deprecated name for produce-assertions
+common-option produceAssertions produce-assertions --produce-assertions bool :predicate CVC4::smt::beforeSearch CVC4::smt::setProduceAssertions :predicate-include "smt/options_handlers.h" :read-write
+ keep an assertions list (enables get-assertions command)
option doITESimp --ite-simp bool :read-write
turn on ite simplification (Kim (and Somenzi) et al., SAT 2009)
@@ -91,7 +93,7 @@ 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 (currently, roughly the number of SAT conflicts)
-common-option perCallResourceLimit rlimit-per --rlimit-per=N "unsigned long"
+common-option perCallResourceLimit reproducible-resource-limit --rlimit-per=N "unsigned long"
enable resource limiting per query
expert-option rewriteApplyToConst rewrite-apply-to-const --rewrite-apply-to-const bool :default false
diff --git a/src/smt/options_handlers.h b/src/smt/options_handlers.h
index 61e17801d..d02b88fd2 100644
--- a/src/smt/options_handlers.h
+++ b/src/smt/options_handlers.h
@@ -153,10 +153,6 @@ batch (default) \n\
(MiniSat) propagation for all of them only after reaching a querying command\n\
(CHECKSAT or QUERY or predicate SUBTYPE declaration)\n\
\n\
-incremental\n\
-+ run nonclausal simplification and clausal propagation at each ASSERT\n\
- (and at CHECKSAT/QUERY/SUBTYPE)\n\
-\n\
none\n\
+ do not perform nonclausal simplification\n\
";
@@ -283,8 +279,6 @@ inline LogicInfo stringToLogicInfo(std::string option, std::string optarg, SmtEn
inline SimplificationMode stringToSimplificationMode(std::string option, std::string optarg, SmtEngine* smt) throw(OptionException) {
if(optarg == "batch") {
return SIMPLIFICATION_MODE_BATCH;
- } else if(optarg == "incremental") {
- return SIMPLIFICATION_MODE_INCREMENTAL;
} else if(optarg == "none") {
return SIMPLIFICATION_MODE_NONE;
} else if(optarg == "help") {
@@ -305,6 +299,11 @@ inline void beforeSearch(std::string option, bool value, SmtEngine* smt) throw(M
}
}
+inline void setProduceAssertions(std::string option, bool value, SmtEngine* smt) throw() {
+ options::produceAssertions.set(value);
+ options::interactiveMode.set(value);
+}
+
// ensure we are a proof-enabled build of CVC4
inline void proofEnabledBuild(std::string option, bool value, SmtEngine* smt) throw(OptionException) {
#ifndef CVC4_PROOF
@@ -316,12 +315,6 @@ inline void proofEnabledBuild(std::string option, bool value, SmtEngine* smt) th
#endif /* CVC4_PROOF */
}
-inline void unsatCoresEnabledBuild(std::string option, bool value, SmtEngine* smt) throw(OptionException) {
- if(value) {
- throw UnrecognizedOptionException("CVC4 does not yet have support for unsatisfiable cores");
- }
-}
-
// This macro is used for setting :regular-output-channel and :diagnostic-output-channel
// to redirect a stream. It maintains all attributes set on the stream.
#define __CVC4__SMT__OUTPUTCHANNELS__SETSTREAM__(__channel_get, __channel_set) \
diff --git a/src/smt/simplification_mode.cpp b/src/smt/simplification_mode.cpp
index f728fa862..be46badfc 100644
--- a/src/smt/simplification_mode.cpp
+++ b/src/smt/simplification_mode.cpp
@@ -21,9 +21,6 @@ namespace CVC4 {
std::ostream& operator<<(std::ostream& out, SimplificationMode mode) {
switch(mode) {
- case SIMPLIFICATION_MODE_INCREMENTAL:
- out << "SIMPLIFICATION_MODE_INCREMENTAL";
- break;
case SIMPLIFICATION_MODE_BATCH:
out << "SIMPLIFICATION_MODE_BATCH";
break;
diff --git a/src/smt/simplification_mode.h b/src/smt/simplification_mode.h
index 2242e8bdf..b0b78d318 100644
--- a/src/smt/simplification_mode.h
+++ b/src/smt/simplification_mode.h
@@ -26,8 +26,6 @@ namespace CVC4 {
/** Enumeration of simplification modes (when to simplify). */
typedef enum {
- /** Simplify the assertions as they come in */
- SIMPLIFICATION_MODE_INCREMENTAL,
/** Simplify the assertions all together once a check is requested */
SIMPLIFICATION_MODE_BATCH,
/** Don't do simplification */
diff --git a/src/smt/smt_engine.cpp b/src/smt/smt_engine.cpp
index ea52f43a7..921d75315 100644
--- a/src/smt/smt_engine.cpp
+++ b/src/smt/smt_engine.cpp
@@ -37,6 +37,7 @@
#include "expr/node_builder.h"
#include "expr/node.h"
#include "expr/node_self_iterator.h"
+#include "expr/attribute.h"
#include "prop/prop_engine.h"
#include "proof/theory_proof.h"
#include "smt/modal_exception.h"
@@ -48,6 +49,7 @@
#include "theory/bv/theory_bv_rewriter.h"
#include "proof/proof_manager.h"
#include "main/options.h"
+#include "util/unsat_core.h"
#include "util/proof.h"
#include "proof/proof.h"
#include "proof/proof_manager.h"
@@ -81,6 +83,7 @@
#include "util/sort_inference.h"
#include "theory/quantifiers/quant_conflict_find.h"
#include "theory/quantifiers/macros.h"
+#include "theory/quantifiers/fun_def_process.h"
#include "theory/quantifiers/first_order_reasoning.h"
#include "theory/quantifiers/quantifiers_rewriter.h"
#include "theory/quantifiers/options.h"
@@ -137,6 +140,30 @@ public:
Node getFormula() const { return d_formula; }
};/* class DefinedFunction */
+class AssertionPipeline {
+ vector<Node> d_nodes;
+
+public:
+
+ size_t size() const { return d_nodes.size(); }
+
+ void resize(size_t n) { d_nodes.resize(n); }
+ void clear() { d_nodes.clear(); }
+
+ Node& operator[](size_t i) { return d_nodes[i]; }
+ const Node& operator[](size_t i) const { return d_nodes[i]; }
+ void push_back(Node n) { d_nodes.push_back(n); }
+
+ vector<Node>& ref() { return d_nodes; }
+ const vector<Node>& ref() const { return d_nodes; }
+
+ void replace(size_t i, Node n) {
+ PROOF( ProofManager::currentPM()->addDependence(n, d_nodes[i]); );
+ d_nodes[i] = n;
+ }
+
+};/* class AssertionPipeline */
+
struct SmtEngineStatistics {
/** time spent in definition-expansion */
TimerStat d_definitionExpansionTime;
@@ -160,6 +187,8 @@ struct SmtEngineStatistics {
TimerStat d_iteRemovalTime;
/** time spent in theory preprocessing */
TimerStat d_theoryPreprocessTime;
+ /** time spent in theory preprocessing */
+ TimerStat d_rewriteApplyToConstTime;
/** time spent converting to CNF */
TimerStat d_cnfConversionTime;
/** Num of assertions before ite removal */
@@ -192,6 +221,7 @@ struct SmtEngineStatistics {
d_unconstrainedSimpTime("smt::SmtEngine::unconstrainedSimpTime"),
d_iteRemovalTime("smt::SmtEngine::iteRemovalTime"),
d_theoryPreprocessTime("smt::SmtEngine::theoryPreprocessTime"),
+ d_rewriteApplyToConstTime("smt::SmtEngine::rewriteApplyToConstTime"),
d_cnfConversionTime("smt::SmtEngine::cnfConversionTime"),
d_numAssertionsPre("smt::SmtEngine::numAssertionsPreITERemoval", 0),
d_numAssertionsPost("smt::SmtEngine::numAssertionsPostITERemoval", 0),
@@ -214,10 +244,12 @@ struct SmtEngineStatistics {
StatisticsRegistry::registerStat(&d_unconstrainedSimpTime);
StatisticsRegistry::registerStat(&d_iteRemovalTime);
StatisticsRegistry::registerStat(&d_theoryPreprocessTime);
+ StatisticsRegistry::registerStat(&d_rewriteApplyToConstTime);
StatisticsRegistry::registerStat(&d_cnfConversionTime);
StatisticsRegistry::registerStat(&d_numAssertionsPre);
StatisticsRegistry::registerStat(&d_numAssertionsPost);
StatisticsRegistry::registerStat(&d_checkModelTime);
+ StatisticsRegistry::registerStat(&d_checkProofTime);
StatisticsRegistry::registerStat(&d_solveTime);
StatisticsRegistry::registerStat(&d_pushPopTime);
StatisticsRegistry::registerStat(&d_processAssertionsTime);
@@ -236,10 +268,12 @@ struct SmtEngineStatistics {
StatisticsRegistry::unregisterStat(&d_unconstrainedSimpTime);
StatisticsRegistry::unregisterStat(&d_iteRemovalTime);
StatisticsRegistry::unregisterStat(&d_theoryPreprocessTime);
+ StatisticsRegistry::unregisterStat(&d_rewriteApplyToConstTime);
StatisticsRegistry::unregisterStat(&d_cnfConversionTime);
StatisticsRegistry::unregisterStat(&d_numAssertionsPre);
StatisticsRegistry::unregisterStat(&d_numAssertionsPost);
StatisticsRegistry::unregisterStat(&d_checkModelTime);
+ StatisticsRegistry::unregisterStat(&d_checkProofTime);
StatisticsRegistry::unregisterStat(&d_solveTime);
StatisticsRegistry::unregisterStat(&d_pushPopTime);
StatisticsRegistry::unregisterStat(&d_processAssertionsTime);
@@ -264,9 +298,6 @@ struct SmtEngineStatistics {
class SmtEnginePrivate : public NodeManagerListener {
SmtEngine& d_smt;
- /** The assertions yet to be preprocessed */
- vector<Node> d_assertionsToPreprocess;
-
/** Learned literals */
vector<Node> d_nonClausalLearnedLiterals;
@@ -281,8 +312,8 @@ class SmtEnginePrivate : public NodeManagerListener {
bool d_propagatorNeedsFinish;
std::vector<Node> d_boolVars;
- /** Assertions to push to sat */
- vector<Node> d_assertionsToCheck;
+ /** Assertions in the preprocessing pipeline */
+ AssertionPipeline d_assertions;
/** Whether any assertions have been processed */
CDO<bool> d_assertionsProcessed;
@@ -319,7 +350,7 @@ class SmtEnginePrivate : public NodeManagerListener {
public:
/**
- * Map from skolem variables to index in d_assertionsToCheck containing
+ * Map from skolem variables to index in d_assertions containing
* corresponding introduced Boolean ite
*/
IteSkolemMap d_iteSkolemMap;
@@ -375,7 +406,7 @@ private:
bool simpITE();
// Simplify based on unconstrained values
- void unconstrainedSimp(std::vector<Node>& assertions);
+ void unconstrainedSimp();
// Ensures the assertions asserted after before now
// effectively come before d_realAssertionsEnd
@@ -386,7 +417,7 @@ private:
* (predicate subtype or integer subrange type) must be constrained
* to be in that type.
*/
- void constrainSubtypes(TNode n, std::vector<Node>& assertions)
+ void constrainSubtypes(TNode n, AssertionPipeline& assertions)
throw();
// trace nodes back to their assertions using CircuitPropagator's BackEdgesMap
@@ -410,13 +441,12 @@ public:
SmtEnginePrivate(SmtEngine& smt) :
d_smt(smt),
- d_assertionsToPreprocess(),
d_nonClausalLearnedLiterals(),
d_realAssertionsEnd(0),
d_booleanTermConverter(NULL),
d_propagator(d_nonClausalLearnedLiterals, true, true),
d_propagatorNeedsFinish(false),
- d_assertionsToCheck(),
+ d_assertions(),
d_assertionsProcessed(smt.d_userContext, false),
d_substitutionsIndex(smt.d_userContext, 0),
d_fakeContext(),
@@ -493,6 +523,10 @@ public:
}
}
+ void nmNotifyDeleteNode(TNode n) {
+ d_smt.d_smtAttributes->deleteAllAttributes(n);
+ }
+
Node applySubstitutions(TNode node) const {
return Rewriter::rewrite(d_topLevelSubstitutions.apply(node));
}
@@ -508,9 +542,8 @@ public:
* someone does a push-assert-pop without a check-sat.
*/
void notifyPop() {
- d_assertionsToPreprocess.clear();
+ d_assertions.clear();
d_nonClausalLearnedLiterals.clear();
- d_assertionsToCheck.clear();
d_realAssertionsEnd = 0;
d_iteSkolemMap.clear();
}
@@ -546,7 +579,7 @@ public:
hash_map<Node, Node, NodeHashFunction> cache;
Node n = expandDefinitions(in, cache).toExpr();
// Make sure we've done all preprocessing, etc.
- Assert(d_assertionsToCheck.size() == 0 && d_assertionsToPreprocess.size() == 0);
+ Assert(d_assertions.size() == 0);
return applySubstitutions(n).toExpr();
}
@@ -571,7 +604,9 @@ public:
val = d_smt.d_nodeManager->mkAbstractValue(n.getType());
d_abstractValueMap.addSubstitution(val, n);
}
- return val;
+ // We are supposed to ascribe types to all abstract values that go out.
+ Node retval = d_smt.d_nodeManager->mkNode(kind::APPLY_TYPE_ASCRIPTION, d_smt.d_nodeManager->mkConst(AscriptionType(n.getType().toType())), val);
+ return retval;
}
std::hash_map<Node, Node, NodeHashFunction> rewriteApplyToConstCache;
@@ -627,7 +662,7 @@ public:
}/* namespace CVC4::smt */
SmtEngine::SmtEngine(ExprManager* em) throw() :
- d_context(em->getContext()),
+ d_context(new Context()),
d_userLevels(),
d_userContext(new UserContext()),
d_exprManager(em),
@@ -643,6 +678,7 @@ SmtEngine::SmtEngine(ExprManager* em) throw() :
d_modelCommands(NULL),
d_dumpCommands(),
d_logic(),
+ d_originalOptions(em->getOptions()),
d_pendingPops(0),
d_fullyInited(false),
d_problemExtended(false),
@@ -657,16 +693,16 @@ SmtEngine::SmtEngine(ExprManager* em) throw() :
d_cumulativeResourceUsed(0),
d_status(),
d_private(NULL),
+ d_smtAttributes(NULL),
d_statisticsRegistry(NULL),
d_stats(NULL) {
SmtScope smts(this);
+ d_smtAttributes = new expr::attr::SmtAttributes(d_context);
d_private = new smt::SmtEnginePrivate(*this);
d_statisticsRegistry = new StatisticsRegistry();
d_stats = new SmtEngineStatistics();
- PROOF( d_proofManager = new ProofManager(); );
-
// We have mutual dependency here, so we add the prop engine to the theory
// engine later (it is non-essential there)
d_theoryEngine = new TheoryEngine(d_context, d_userContext, d_private->d_iteRemover, const_cast<const LogicInfo&>(d_logic));
@@ -689,6 +725,9 @@ void SmtEngine::finishInit() {
// ensure that our heuristics are properly set up
setDefaults();
+ Assert(d_proofManager == NULL);
+ PROOF( d_proofManager = new ProofManager(); );
+
d_decisionEngine = new DecisionEngine(d_context, d_userContext);
d_decisionEngine->init(); // enable appropriate strategies
@@ -702,7 +741,7 @@ void SmtEngine::finishInit() {
// cleanup ordering issue and Nodes/TNodes. If SAT is popped
// first, some user-context-dependent TNodes might still exist
// with rc == 0.
- if(options::interactive() ||
+ if(options::produceAssertions() ||
options::incrementalSolving()) {
// In the case of incremental solving, we appear to need these to
// ensure the relevant Nodes remain live.
@@ -834,8 +873,13 @@ SmtEngine::~SmtEngine() throw() {
delete d_private;
d_private = NULL;
+ delete d_smtAttributes;
+ d_smtAttributes = NULL;
+
delete d_userContext;
d_userContext = NULL;
+ delete d_context;
+ d_context = NULL;
} catch(Exception& e) {
Warning() << "CVC4 threw an exception during cleanup." << endl
@@ -921,9 +965,67 @@ void SmtEngine::setDefaults() {
}
if(options::checkModels()) {
- if(! options::interactive()) {
- Notice() << "SmtEngine: turning on interactive-mode to support check-models" << endl;
- setOption("interactive-mode", SExpr("true"));
+ if(! options::produceAssertions()) {
+ Notice() << "SmtEngine: turning on produce-assertions to support check-models" << endl;
+ setOption("produce-assertions", SExpr("true"));
+ }
+ }
+
+ if(options::unsatCores()) {
+ if(options::simplificationMode() != SIMPLIFICATION_MODE_NONE) {
+ if(options::simplificationMode.wasSetByUser()) {
+ throw OptionException("simplification not supported with unsat cores");
+ }
+ Notice() << "SmtEngine: turning off simplification to support unsat-cores" << endl;
+ options::simplificationMode.set(SIMPLIFICATION_MODE_NONE);
+ }
+
+ if(options::unconstrainedSimp()) {
+ if(options::unconstrainedSimp.wasSetByUser()) {
+ throw OptionException("unconstrained simplification not supported with unsat cores");
+ }
+ Notice() << "SmtEngine: turning off unconstrained simplification to support unsat-cores" << endl;
+ options::unconstrainedSimp.set(false);
+ }
+
+ if(options::pbRewrites()) {
+ if(options::pbRewrites.wasSetByUser()) {
+ throw OptionException("pseudoboolean rewrites not supported with unsat cores");
+ }
+ Notice() << "SmtEngine: turning off pseudoboolean rewrites to support unsat-cores" << endl;
+ setOption("pb-rewrites", false);
+ }
+
+ if(options::sortInference()) {
+ if(options::sortInference.wasSetByUser()) {
+ throw OptionException("sort inference not supported with unsat cores");
+ }
+ Notice() << "SmtEngine: turning off sort inference to support unsat-cores" << endl;
+ options::sortInference.set(false);
+ }
+
+ if(options::preSkolemQuant()) {
+ if(options::preSkolemQuant.wasSetByUser()) {
+ throw OptionException("pre-skolemization not supported with unsat cores");
+ }
+ Notice() << "SmtEngine: turning off pre-skolemization to support unsat-cores" << endl;
+ options::preSkolemQuant.set(false);
+ }
+
+ if(options::bitvectorToBool()) {
+ if(options::bitvectorToBool.wasSetByUser()) {
+ throw OptionException("bv-to-bool not supported with unsat cores");
+ }
+ Notice() << "SmtEngine: turning off bitvector-to-bool support unsat-cores" << endl;
+ options::bitvectorToBool.set(false);
+ }
+
+ if(options::bvIntroducePow2()) {
+ if(options::bvIntroducePow2.wasSetByUser()) {
+ throw OptionException("bv-intro-pow2 not supported with unsat cores");
+ }
+ Notice() << "SmtEngine: turning off bv-introduce-pow2 to support unsat-cores" << endl;
+ setOption("bv-intro-pow2", false);
}
}
@@ -1119,10 +1221,8 @@ void SmtEngine::setDefaults() {
if (options::arithRewriteEq()) {
d_earlyTheoryPP = false;
}
- // Turn on justification heuristic of the decision engine for QF_BV and QF_AUFBV
- // and also use it in stop-only mode for QF_AUFLIA, QF_LRA and Quantifiers
- // BUT use neither in ALL_SUPPORTED mode (since it doesn't yet work well
- // with incrementality)
+
+ // Set decision mode based on logic (if not set by user)
if(!options::decisionMode.wasSetByUser()) {
decision::DecisionMode decMode =
// ALL_SUPPORTED
@@ -1215,6 +1315,49 @@ void SmtEngine::setDefaults() {
if( options::qcfMode.wasSetByUser() || options::qcfTConstraint() ){
options::quantConflictFind.set( true );
}
+ //for induction techniques
+ if( options::quantInduction() ){
+ if( !options::dtStcInduction.wasSetByUser() ){
+ options::dtStcInduction.set( true );
+ }
+ if( !options::intWfInduction.wasSetByUser() ){
+ options::intWfInduction.set( true );
+ }
+ }
+ if( options::dtStcInduction() ){
+ //leads to unfairness FIXME
+ if( !options::dtForceAssignment.wasSetByUser() ){
+ options::dtForceAssignment.set( true );
+ }
+ }
+ if( options::intWfInduction() ){
+ if( !options::purifyTriggers.wasSetByUser() ){
+ options::purifyTriggers.set( true );
+ }
+ }
+ if( options::conjectureNoFilter() ){
+ if( !options::conjectureFilterActiveTerms.wasSetByUser() ){
+ options::conjectureFilterActiveTerms.set( false );
+ }
+ if( !options::conjectureFilterCanonical.wasSetByUser() ){
+ options::conjectureFilterCanonical.set( false );
+ }
+ if( !options::conjectureFilterModel.wasSetByUser() ){
+ options::conjectureFilterModel.set( false );
+ }
+ }
+ if( options::conjectureGenPerRound.wasSetByUser() ){
+ if( options::conjectureGenPerRound()>0 ){
+ options::conjectureGen.set( true );
+ }else{
+ options::conjectureGen.set( false );
+ }
+ }
+ if( options::fmfFunWellDefined() ){
+ if( !options::finiteModelFind.wasSetByUser() ){
+ options::finiteModelFind.set( true );
+ }
+ }
//until bugs 371,431 are fixed
if( ! options::minisatUseElim.wasSetByUser()){
@@ -1260,17 +1403,10 @@ void SmtEngine::setDefaults() {
}
}
- if (options::incrementalSolving() && options::proof()) {
- Warning() << "SmtEngine: turning off incremental solving mode (not yet supported with --proof" << endl;
+ if(options::incrementalSolving() && (options::proof() || options::unsatCores())) {
+ Warning() << "SmtEngine: turning off incremental solving mode (not yet supported with --proof or --produce-unsat-cores, try --tear-down-incremental instead)" << endl;
setOption("incremental", SExpr("false"));
}
-
- // datatypes theory should assign values to all datatypes terms if logic is quantified
- if (d_logic.isQuantified() && d_logic.isTheoryEnabled(THEORY_DATATYPES)) {
- if( !options::dtForceAssignment.wasSetByUser() ){
- options::dtForceAssignment.set(true);
- }
- }
}
void SmtEngine::setInfo(const std::string& key, const CVC4::SExpr& value)
@@ -1323,8 +1459,23 @@ void SmtEngine::setInfo(const std::string& key, const CVC4::SExpr& value)
} else if(key == "smt-lib-version") {
if( (value.isInteger() && value.getIntegerValue() == Integer(2)) ||
(value.isRational() && value.getRationalValue() == Rational(2)) ||
- (value.getValue() == "2") ) {
+ value.getValue() == "2" ||
+ value.getValue() == "2.0" ) {
+ // supported SMT-LIB version
+ if(!options::outputLanguage.wasSetByUser() &&
+ options::outputLanguage() == language::output::LANG_SMTLIB_V2_5) {
+ options::outputLanguage.set(language::output::LANG_SMTLIB_V2_0);
+ *options::out() << Expr::setlanguage(language::output::LANG_SMTLIB_V2_0);
+ }
+ return;
+ } else if( (value.isRational() && value.getRationalValue() == Rational(5, 2)) ||
+ value.getValue() == "2.5" ) {
// supported SMT-LIB version
+ if(!options::outputLanguage.wasSetByUser() &&
+ options::outputLanguage() == language::output::LANG_SMTLIB_V2_0) {
+ options::outputLanguage.set(language::output::LANG_SMTLIB_V2_5);
+ *options::out() << Expr::setlanguage(language::output::LANG_SMTLIB_V2_5);
+ }
return;
}
Warning() << "Warning: unsupported smt-lib-version: " << value << endl;
@@ -1403,6 +1554,8 @@ 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 == "assertion-stack-levels") {
+ return SExpr(d_userLevels.size());
} else if(key == "all-options") {
// get the options, like all-statistics
return Options::current().getOptions();
@@ -1636,11 +1789,10 @@ void SmtEnginePrivate::removeITEs() {
Trace("simplify") << "SmtEnginePrivate::removeITEs()" << endl;
// Remove all of the ITE occurrences and normalize
- d_iteRemover.run(d_assertionsToCheck, d_iteSkolemMap);
- for (unsigned i = 0; i < d_assertionsToCheck.size(); ++ i) {
- d_assertionsToCheck[i] = Rewriter::rewrite(d_assertionsToCheck[i]);
+ d_iteRemover.run(d_assertions.ref(), d_iteSkolemMap, true);
+ for (unsigned i = 0; i < d_assertions.size(); ++ i) {
+ d_assertions.replace(i, Rewriter::rewrite(d_assertions[i]));
}
-
}
void SmtEnginePrivate::staticLearning() {
@@ -1650,22 +1802,21 @@ void SmtEnginePrivate::staticLearning() {
Trace("simplify") << "SmtEnginePrivate::staticLearning()" << endl;
- for (unsigned i = 0; i < d_assertionsToCheck.size(); ++ i) {
+ for (unsigned i = 0; i < d_assertions.size(); ++ i) {
NodeBuilder<> learned(kind::AND);
- learned << d_assertionsToCheck[i];
- d_smt.d_theoryEngine->ppStaticLearn(d_assertionsToCheck[i], learned);
+ learned << d_assertions[i];
+ d_smt.d_theoryEngine->ppStaticLearn(d_assertions[i], learned);
if(learned.getNumChildren() == 1) {
learned.clear();
} else {
- d_assertionsToCheck[i] = learned;
+ d_assertions.replace(i, learned);
}
}
}
// do dumping (before/after any preprocessing pass)
-static void dumpAssertions(const char* key,
- const std::vector<Node>& assertionList) {
+static void dumpAssertions(const char* key, const AssertionPipeline& assertionList) {
if( Dump.isOn("assertions") &&
Dump.isOn(string("assertions:") + key) ) {
// Push the simplified assertions to the dump output stream
@@ -1680,8 +1831,11 @@ static void dumpAssertions(const char* key,
bool SmtEnginePrivate::nonClausalSimplify() {
d_smt.finalOptionsAreSet();
- TimerStat::CodeTimer nonclausalTimer(d_smt.d_stats->d_nonclausalSimplificationTime);
+ if(options::unsatCores()) {
+ return true;
+ }
+ TimerStat::CodeTimer nonclausalTimer(d_smt.d_stats->d_nonclausalSimplificationTime);
Trace("simplify") << "SmtEnginePrivate::nonClausalSimplify()" << endl;
@@ -1694,14 +1848,15 @@ bool SmtEnginePrivate::nonClausalSimplify() {
// Assert all the assertions to the propagator
Trace("simplify") << "SmtEnginePrivate::nonClausalSimplify(): "
<< "asserting to propagator" << endl;
- for (unsigned i = 0; i < d_assertionsToPreprocess.size(); ++ i) {
- Assert(Rewriter::rewrite(d_assertionsToPreprocess[i]) == d_assertionsToPreprocess[i]);
+ for (unsigned i = 0; i < d_assertions.size(); ++ i) {
+ Assert(Rewriter::rewrite(d_assertions[i]) == d_assertions[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]);
+ Trace("simplify") << "SmtEnginePrivate::nonClausalSimplify(): asserting " << d_assertions[i] << endl;
+ Debug("cores") << "d_propagator assertTrue: " << d_assertions[i] << std::endl;
+ d_propagator.assertTrue(d_assertions[i]);
}
Trace("simplify") << "SmtEnginePrivate::nonClausalSimplify(): "
@@ -1710,8 +1865,10 @@ bool SmtEnginePrivate::nonClausalSimplify() {
// If in conflict, just return false
Trace("simplify") << "SmtEnginePrivate::nonClausalSimplify(): "
<< "conflict in non-clausal propagation" << endl;
- d_assertionsToPreprocess.clear();
- d_assertionsToCheck.push_back(NodeManager::currentNM()->mkConst<bool>(false));
+ Node falseNode = NodeManager::currentNM()->mkConst<bool>(false);
+ Assert(!options::unsatCores());
+ d_assertions.clear();
+ d_assertions.push_back(falseNode);
d_propagatorNeedsFinish = true;
return false;
}
@@ -1748,8 +1905,9 @@ bool SmtEnginePrivate::nonClausalSimplify() {
Trace("simplify") << "SmtEnginePrivate::nonClausalSimplify(): "
<< "conflict with "
<< d_nonClausalLearnedLiterals[i] << endl;
- d_assertionsToPreprocess.clear();
- d_assertionsToCheck.push_back(NodeManager::currentNM()->mkConst<bool>(false));
+ Assert(!options::unsatCores());
+ d_assertions.clear();
+ d_assertions.push_back(NodeManager::currentNM()->mkConst<bool>(false));
d_propagatorNeedsFinish = true;
return false;
}
@@ -1783,8 +1941,9 @@ bool SmtEnginePrivate::nonClausalSimplify() {
Trace("simplify") << "SmtEnginePrivate::nonClausalSimplify(): "
<< "conflict while solving "
<< learnedLiteral << endl;
- d_assertionsToPreprocess.clear();
- d_assertionsToCheck.push_back(NodeManager::currentNM()->mkConst<bool>(false));
+ Assert(!options::unsatCores());
+ d_assertions.clear();
+ d_assertions.push_back(NodeManager::currentNM()->mkConst<bool>(false));
d_propagatorNeedsFinish = true;
return false;
default:
@@ -1809,8 +1968,8 @@ bool SmtEnginePrivate::nonClausalSimplify() {
// constantPropagations.simplifyLHS(t, c, equations, true);
// if (!equations.empty()) {
// Assert(equations[0].first.isConst() && equations[0].second.isConst() && equations[0].first != equations[0].second);
- // d_assertionsToPreprocess.clear();
- // d_assertionsToCheck.push_back(NodeManager::currentNM()->mkConst<bool>(false));
+ // d_assertions.clear();
+ // d_assertions.push_back(NodeManager::currentNM()->mkConst<bool>(false));
// return;
// }
// d_topLevelSubstitutions.simplifyRHS(constantPropagations);
@@ -1859,8 +2018,8 @@ bool SmtEnginePrivate::nonClausalSimplify() {
hash_set<TNode, TNodeHashFunction> s;
Trace("debugging") << "NonClausal simplify pre-preprocess\n";
- for (unsigned i = 0; i < d_assertionsToPreprocess.size(); ++ i) {
- Node assertion = d_assertionsToPreprocess[i];
+ for (unsigned i = 0; i < d_assertions.size(); ++ i) {
+ Node assertion = d_assertions[i];
Node assertionNew = newSubstitutions.apply(assertion);
Trace("debugging") << "assertion = " << assertion << endl;
Trace("debugging") << "assertionNew = " << assertionNew << endl;
@@ -1881,17 +2040,16 @@ bool SmtEnginePrivate::nonClausalSimplify() {
}
Trace("debugging") << "\n";
s.insert(assertion);
- d_assertionsToCheck.push_back(assertion);
+ d_assertions.replace(i, assertion);
Trace("simplify") << "SmtEnginePrivate::nonClausalSimplify(): "
<< "non-clausal preprocessed: "
<< assertion << endl;
}
- d_assertionsToPreprocess.clear();
// If in incremental mode, add substitutions to the list of assertions
if (d_substitutionsIndex > 0) {
NodeBuilder<> substitutionsBuilder(kind::AND);
- substitutionsBuilder << d_assertionsToCheck[d_substitutionsIndex];
+ substitutionsBuilder << d_assertions[d_substitutionsIndex];
pos = newSubstitutions.begin();
for (; pos != newSubstitutions.end(); ++pos) {
// Add back this substitution as an assertion
@@ -1901,8 +2059,8 @@ bool SmtEnginePrivate::nonClausalSimplify() {
Trace("simplify") << "SmtEnginePrivate::nonClausalSimplify(): will notify SAT layer of substitution: " << n << endl;
}
if (substitutionsBuilder.getNumChildren() > 1) {
- d_assertionsToCheck[d_substitutionsIndex] =
- Rewriter::rewrite(Node(substitutionsBuilder));
+ d_assertions.replace(d_substitutionsIndex,
+ Rewriter::rewrite(Node(substitutionsBuilder)));
}
} else {
// If not in incremental mode, must add substitutions to model
@@ -1918,8 +2076,8 @@ bool SmtEnginePrivate::nonClausalSimplify() {
}
NodeBuilder<> learnedBuilder(kind::AND);
- Assert(d_realAssertionsEnd <= d_assertionsToCheck.size());
- learnedBuilder << d_assertionsToCheck[d_realAssertionsEnd - 1];
+ Assert(d_realAssertionsEnd <= d_assertions.size());
+ learnedBuilder << d_assertions[d_realAssertionsEnd - 1];
for (unsigned i = 0; i < d_nonClausalLearnedLiterals.size(); ++ i) {
Node learned = d_nonClausalLearnedLiterals[i];
@@ -1948,7 +2106,6 @@ bool SmtEnginePrivate::nonClausalSimplify() {
}
d_nonClausalLearnedLiterals.clear();
-
for (pos = constantPropagations.begin(); pos != constantPropagations.end(); ++pos) {
Node cProp = (*pos).first.eqNode((*pos).second);
Assert(d_topLevelSubstitutions.apply(cProp) == cProp);
@@ -1973,8 +2130,8 @@ bool SmtEnginePrivate::nonClausalSimplify() {
d_topLevelSubstitutions.addSubstitutions(newSubstitutions);
if(learnedBuilder.getNumChildren() > 1) {
- d_assertionsToCheck[d_realAssertionsEnd - 1] =
- Rewriter::rewrite(Node(learnedBuilder));
+ d_assertions.replace(d_realAssertionsEnd - 1,
+ Rewriter::rewrite(Node(learnedBuilder)));
}
d_propagatorNeedsFinish = true;
@@ -1984,9 +2141,9 @@ bool SmtEnginePrivate::nonClausalSimplify() {
void SmtEnginePrivate::bvAbstraction() {
Trace("bv-abstraction") << "SmtEnginePrivate::bvAbstraction()" << endl;
std::vector<Node> new_assertions;
- bool changed = d_smt.d_theoryEngine->ppBvAbstraction(d_assertionsToPreprocess, new_assertions);
- for (unsigned i = 0; i < d_assertionsToPreprocess.size(); ++ i) {
- d_assertionsToPreprocess[i] = Rewriter::rewrite(new_assertions[i]);
+ bool changed = d_smt.d_theoryEngine->ppBvAbstraction(d_assertions.ref(), new_assertions);
+ for (unsigned i = 0; i < d_assertions.size(); ++ i) {
+ d_assertions.replace(i, Rewriter::rewrite(new_assertions[i]));
}
// if we are using the lazy solver and the abstraction
// applies, then UF symbols were introduced
@@ -2001,9 +2158,9 @@ void SmtEnginePrivate::bvAbstraction() {
void SmtEnginePrivate::bvToBool() {
Trace("bv-to-bool") << "SmtEnginePrivate::bvToBool()" << endl;
std::vector<Node> new_assertions;
- d_smt.d_theoryEngine->ppBvToBool(d_assertionsToPreprocess, new_assertions);
- for (unsigned i = 0; i < d_assertionsToPreprocess.size(); ++ i) {
- d_assertionsToPreprocess[i] = Rewriter::rewrite(new_assertions[i]);
+ d_smt.d_theoryEngine->ppBvToBool(d_assertions.ref(), new_assertions);
+ for (unsigned i = 0; i < d_assertions.size(); ++ i) {
+ d_assertions.replace(i, Rewriter::rewrite(new_assertions[i]));
}
}
@@ -2012,23 +2169,23 @@ bool SmtEnginePrivate::simpITE() {
Trace("simplify") << "SmtEnginePrivate::simpITE()" << endl;
- unsigned numAssertionOnEntry = d_assertionsToCheck.size();
- for (unsigned i = 0; i < d_assertionsToCheck.size(); ++i) {
- Node result = d_smt.d_theoryEngine->ppSimpITE(d_assertionsToCheck[i]);
- d_assertionsToCheck[i] = result;
+ unsigned numAssertionOnEntry = d_assertions.size();
+ for (unsigned i = 0; i < d_assertions.size(); ++i) {
+ Node result = d_smt.d_theoryEngine->ppSimpITE(d_assertions[i]);
+ d_assertions.replace(i, result);
if(result.isConst() && !result.getConst<bool>()){
return false;
}
}
- bool result = d_smt.d_theoryEngine->donePPSimpITE(d_assertionsToCheck);
- if(numAssertionOnEntry < d_assertionsToCheck.size()){
+ bool result = d_smt.d_theoryEngine->donePPSimpITE(d_assertions.ref());
+ if(numAssertionOnEntry < d_assertions.size()){
compressBeforeRealAssertions(numAssertionOnEntry);
}
return result;
}
void SmtEnginePrivate::compressBeforeRealAssertions(size_t before){
- size_t curr = d_assertionsToCheck.size();
+ size_t curr = d_assertions.size();
if(before >= curr ||
d_realAssertionsEnd <= 0 ||
d_realAssertionsEnd >= curr){
@@ -2048,24 +2205,24 @@ void SmtEnginePrivate::compressBeforeRealAssertions(size_t before){
std::vector<Node> intoConjunction;
for(size_t i = before; i<curr; ++i){
- intoConjunction.push_back(d_assertionsToCheck[i]);
+ intoConjunction.push_back(d_assertions[i]);
}
- d_assertionsToCheck.resize(before);
+ d_assertions.resize(before);
size_t lastBeforeItes = d_realAssertionsEnd - 1;
- intoConjunction.push_back(d_assertionsToCheck[lastBeforeItes]);
+ intoConjunction.push_back(d_assertions[lastBeforeItes]);
Node newLast = util::NaryBuilder::mkAssoc(kind::AND, intoConjunction);
- d_assertionsToCheck[lastBeforeItes] = newLast;
- Assert(d_assertionsToCheck.size() == before);
+ d_assertions.replace(lastBeforeItes, newLast);
+ Assert(d_assertions.size() == before);
}
-void SmtEnginePrivate::unconstrainedSimp(std::vector<Node>& assertions) {
+void SmtEnginePrivate::unconstrainedSimp() {
TimerStat::CodeTimer unconstrainedSimpTimer(d_smt.d_stats->d_unconstrainedSimpTime);
Trace("simplify") << "SmtEnginePrivate::unconstrainedSimp()" << endl;
- d_smt.d_theoryEngine->ppUnconstrainedSimp(assertions);
+ d_smt.d_theoryEngine->ppUnconstrainedSimp(d_assertions.ref());
}
-void SmtEnginePrivate::constrainSubtypes(TNode top, std::vector<Node>& assertions)
+void SmtEnginePrivate::constrainSubtypes(TNode top, AssertionPipeline& assertions)
throw() {
Trace("constrainSubtypes") << "constrainSubtypes(): looking at " << top << endl;
@@ -2187,8 +2344,7 @@ size_t SmtEnginePrivate::removeFromConjunction(Node& n, const std::hash_set<unsi
}
void SmtEnginePrivate::doMiplibTrick() {
- Assert(d_assertionsToPreprocess.empty());
- Assert(d_realAssertionsEnd == d_assertionsToCheck.size());
+ Assert(d_realAssertionsEnd == d_assertions.size());
Assert(!options::incrementalSolving());
const booleans::CircuitPropagator::BackEdgesMap& backEdges = d_propagator.getBackEdges();
@@ -2419,7 +2575,7 @@ void SmtEnginePrivate::doMiplibTrick() {
Node newVar = nm->mkSkolem(ss.str(), nm->integerType(), "a variable introduced due to scrubbing a miplib encoding", NodeManager::SKOLEM_EXACT_NAME);
Node geq = Rewriter::rewrite(nm->mkNode(kind::GEQ, newVar, zero));
Node leq = Rewriter::rewrite(nm->mkNode(kind::LEQ, newVar, one));
- d_assertionsToCheck.push_back(Rewriter::rewrite(geq.andNode(leq)));
+ d_assertions.push_back(Rewriter::rewrite(geq.andNode(leq)));
SubstitutionMap nullMap(&d_fakeContext);
Theory::PPAssertStatus status CVC4_UNUSED; // just for assertions
status = d_smt.d_theoryEngine->solve(geq, nullMap);
@@ -2470,7 +2626,7 @@ void SmtEnginePrivate::doMiplibTrick() {
}
newAssertion = Rewriter::rewrite(newAssertion);
Debug("miplib") << " " << newAssertion << endl;
- d_assertionsToCheck.push_back(newAssertion);
+ d_assertions.push_back(newAssertion);
Debug("miplib") << " assertions to remove: " << endl;
for(vector<TNode>::const_iterator k = asserts[pos_var].begin(), k_end = asserts[pos_var].end(); k != k_end; ++k) {
Debug("miplib") << " " << *k << endl;
@@ -2483,26 +2639,26 @@ void SmtEnginePrivate::doMiplibTrick() {
if(!removeAssertions.empty()) {
Debug("miplib") << "SmtEnginePrivate::simplify(): scrubbing miplib encoding..." << endl;
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] = d_true;
+ if(removeAssertions.find(d_assertions[i].getId()) != removeAssertions.end()) {
+ Debug("miplib") << "SmtEnginePrivate::simplify(): - removing " << d_assertions[i] << endl;
+ d_assertions[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);
+ } else if(d_assertions[i].getKind() == kind::AND) {
+ size_t removals = removeFromConjunction(d_assertions[i], removeAssertions);
if(removals > 0) {
- Debug("miplib") << "SmtEnginePrivate::simplify(): - reduced " << d_assertionsToCheck[i] << endl;
+ Debug("miplib") << "SmtEnginePrivate::simplify(): - reduced " << d_assertions[i] << endl;
Debug("miplib") << "SmtEnginePrivate::simplify(): - by " << removals << " conjuncts" << endl;
d_smt.d_stats->d_numMiplibAssertionsRemoved += removals;
}
}
- Debug("miplib") << "had: " << d_assertionsToCheck[i] << endl;
- d_assertionsToCheck[i] = Rewriter::rewrite(d_topLevelSubstitutions.apply(d_assertionsToCheck[i]));
- Debug("miplib") << "now: " << d_assertionsToCheck[i] << endl;
+ Debug("miplib") << "had: " << d_assertions[i] << endl;
+ d_assertions[i] = Rewriter::rewrite(d_topLevelSubstitutions.apply(d_assertions[i]));
+ Debug("miplib") << "now: " << d_assertions[i] << endl;
}
} else {
Debug("miplib") << "SmtEnginePrivate::simplify(): miplib pass found nothing." << endl;
}
- d_realAssertionsEnd = d_assertionsToCheck.size();
+ d_realAssertionsEnd = d_assertions.size();
}
@@ -2536,7 +2692,7 @@ bool SmtEnginePrivate::simplifyAssertions()
// we add new assertions and need this (in practice, this
// restriction only disables miplib processing during
// re-simplification, which we don't expect to be useful anyway)
- d_realAssertionsEnd == d_assertionsToCheck.size() ) {
+ d_realAssertionsEnd == d_assertions.size() ) {
Chat() << "...fixing miplib encodings..." << endl;
Trace("simplify") << "SmtEnginePrivate::simplify(): "
<< "looking for miplib pseudobooleans..." << endl;
@@ -2548,18 +2704,16 @@ bool SmtEnginePrivate::simplifyAssertions()
Trace("simplify") << "SmtEnginePrivate::simplify(): "
<< "skipping miplib pseudobooleans pass (either incrementalSolving is on, or miplib pbs are turned off)..." << endl;
}
- } else {
- Assert(d_assertionsToCheck.empty());
- d_assertionsToCheck.swap(d_assertionsToPreprocess);
}
- dumpAssertions("post-nonclausal", d_assertionsToCheck);
+ dumpAssertions("post-nonclausal", d_assertions);
Trace("smt") << "POST nonClausalSimplify" << endl;
- Debug("smt") << " d_assertionsToPreprocess: " << d_assertionsToPreprocess.size() << endl;
- Debug("smt") << " d_assertionsToCheck : " << d_assertionsToCheck.size() << endl;
+ Debug("smt") << " d_assertions : " << d_assertions.size() << endl;
// before ppRewrite check if only core theory for BV theory
- d_smt.d_theoryEngine->staticInitializeBVOptions(d_assertionsToCheck);
+ d_smt.d_theoryEngine->staticInitializeBVOptions(d_assertions.ref());
+
+ dumpAssertions("pre-theorypp", d_assertions);
// Theory preprocessing
if (d_smt.d_earlyTheoryPP) {
@@ -2567,17 +2721,16 @@ bool SmtEnginePrivate::simplifyAssertions()
TimerStat::CodeTimer codeTimer(d_smt.d_stats->d_theoryPreprocessTime);
// Call the theory preprocessors
d_smt.d_theoryEngine->preprocessStart();
- for (unsigned i = 0; i < d_assertionsToCheck.size(); ++ i) {
- Assert(Rewriter::rewrite(d_assertionsToCheck[i]) == d_assertionsToCheck[i]);
- d_assertionsToCheck[i] = d_smt.d_theoryEngine->preprocess(d_assertionsToCheck[i]);
- Assert(Rewriter::rewrite(d_assertionsToCheck[i]) == d_assertionsToCheck[i]);
+ for (unsigned i = 0; i < d_assertions.size(); ++ i) {
+ Assert(Rewriter::rewrite(d_assertions[i]) == d_assertions[i]);
+ d_assertions.replace(i, d_smt.d_theoryEngine->preprocess(d_assertions[i]));
+ Assert(Rewriter::rewrite(d_assertions[i]) == d_assertions[i]);
}
}
- dumpAssertions("post-theorypp", d_assertionsToCheck);
+ dumpAssertions("post-theorypp", d_assertions);
Trace("smt") << "POST theoryPP" << endl;
- Debug("smt") << " d_assertionsToPreprocess: " << d_assertionsToPreprocess.size() << endl;
- Debug("smt") << " d_assertionsToCheck : " << d_assertionsToCheck.size() << endl;
+ Debug("smt") << " d_assertions : " << d_assertions.size() << endl;
// ITE simplification
if(options::doITESimp() &&
@@ -2590,38 +2743,33 @@ bool SmtEnginePrivate::simplifyAssertions()
}
}
- dumpAssertions("post-itesimp", d_assertionsToCheck);
+ dumpAssertions("post-itesimp", d_assertions);
Trace("smt") << "POST iteSimp" << endl;
- Debug("smt") << " d_assertionsToPreprocess: " << d_assertionsToPreprocess.size() << endl;
- Debug("smt") << " d_assertionsToCheck : " << d_assertionsToCheck.size() << endl;
+ Debug("smt") << " d_assertions : " << d_assertions.size() << endl;
// Unconstrained simplification
if(options::unconstrainedSimp()) {
Chat() << "...doing unconstrained simplification..." << endl;
- unconstrainedSimp(d_assertionsToCheck);
+ unconstrainedSimp();
}
- dumpAssertions("post-unconstrained", d_assertionsToCheck);
+ dumpAssertions("post-unconstrained", d_assertions);
Trace("smt") << "POST unconstrainedSimp" << endl;
- Debug("smt") << " d_assertionsToPreprocess: " << d_assertionsToPreprocess.size() << endl;
- Debug("smt") << " d_assertionsToCheck : " << d_assertionsToCheck.size() << endl;
+ Debug("smt") << " d_assertions : " << d_assertions.size() << endl;
if(options::repeatSimp() && options::simplificationMode() != SIMPLIFICATION_MODE_NONE) {
Chat() << "...doing another round of nonclausal simplification..." << endl;
Trace("simplify") << "SmtEnginePrivate::simplify(): "
<< " doing repeated simplification" << endl;
- d_assertionsToCheck.swap(d_assertionsToPreprocess);
- Assert(d_assertionsToCheck.empty());
bool noConflict = nonClausalSimplify();
if(!noConflict) {
return false;
}
}
- dumpAssertions("post-repeatsimp", d_assertionsToCheck);
+ dumpAssertions("post-repeatsimp", d_assertions);
Trace("smt") << "POST repeatSimp" << endl;
- Debug("smt") << " d_assertionsToPreprocess: " << d_assertionsToPreprocess.size() << endl;
- Debug("smt") << " d_assertionsToCheck : " << d_assertionsToCheck.size() << endl;
+ Debug("smt") << " d_assertions : " << d_assertions.size() << endl;
} catch(TypeCheckingExceptionPrivate& tcep) {
// Calls to this function should have already weeded out any
@@ -2807,52 +2955,45 @@ void SmtEnginePrivate::processAssertions() {
Assert(d_smt.d_pendingPops == 0);
// Dump the assertions
- dumpAssertions("pre-everything", d_assertionsToPreprocess);
+ dumpAssertions("pre-everything", d_assertions);
Trace("smt") << "SmtEnginePrivate::processAssertions()" << endl;
- Debug("smt") << " d_assertionsToPreprocess: " << d_assertionsToPreprocess.size() << endl;
- Debug("smt") << " d_assertionsToCheck : " << d_assertionsToCheck.size() << endl;
+ Debug("smt") << " d_assertions : " << d_assertions.size() << endl;
- Assert(d_assertionsToCheck.size() == 0);
-
- if (d_assertionsToPreprocess.size() == 0) {
+ if (d_assertions.size() == 0) {
// nothing to do
return;
}
- if (d_assertionsProcessed &&
- ( options::incrementalSolving() ||
- options::simplificationMode() == SIMPLIFICATION_MODE_INCREMENTAL )) {
+ if (d_assertionsProcessed && options::incrementalSolving()) {
// Placeholder for storing substitutions
- d_substitutionsIndex = d_assertionsToPreprocess.size();
- d_assertionsToPreprocess.push_back(NodeManager::currentNM()->mkConst<bool>(true));
+ d_substitutionsIndex = d_assertions.size();
+ d_assertions.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));
+ d_assertions.push_back(NodeManager::currentNM()->mkConst<bool>(true));
// any assertions added beyond realAssertionsEnd must NOT affect the
// equisatisfiability
- d_realAssertionsEnd = d_assertionsToPreprocess.size();
+ d_realAssertionsEnd = d_assertions.size();
// Assertions are NOT guaranteed to be rewritten by this point
- dumpAssertions("pre-definition-expansion", d_assertionsToPreprocess);
+ dumpAssertions("pre-definition-expansion", d_assertions);
{
Chat() << "expanding definitions..." << endl;
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) {
- d_assertionsToPreprocess[i] =
- expandDefinitions(d_assertionsToPreprocess[i], cache);
+ for(unsigned i = 0; i < d_assertions.size(); ++ i) {
+ d_assertions.replace(i, expandDefinitions(d_assertions[i], cache));
}
}
- dumpAssertions("post-definition-expansion", d_assertionsToPreprocess);
+ dumpAssertions("post-definition-expansion", d_assertions);
- Debug("smt") << " d_assertionsToPreprocess: " << d_assertionsToPreprocess.size() << endl;
- Debug("smt") << " d_assertionsToCheck : " << d_assertionsToCheck.size() << endl;
+ Debug("smt") << " d_assertions : " << d_assertions.size() << endl;
if (options::bitblastMode() == theory::bv::BITBLAST_MODE_EAGER &&
!d_smt.d_logic.isPure(THEORY_BV)) {
@@ -2862,146 +3003,157 @@ void SmtEnginePrivate::processAssertions() {
}
if (options::bitblastMode() == theory::bv::BITBLAST_MODE_EAGER) {
- d_smt.d_theoryEngine->mkAckermanizationAsssertions(d_assertionsToPreprocess);
+ d_smt.d_theoryEngine->mkAckermanizationAsssertions(d_assertions.ref());
}
if ( options::bvAbstraction() &&
!options::incrementalSolving()) {
- dumpAssertions("pre-bv-abstraction", d_assertionsToPreprocess);
+ dumpAssertions("pre-bv-abstraction", d_assertions);
bvAbstraction();
- dumpAssertions("post-bv-abstraction", d_assertionsToPreprocess);
+ dumpAssertions("post-bv-abstraction", d_assertions);
}
- dumpAssertions("pre-boolean-terms", d_assertionsToPreprocess);
+ dumpAssertions("pre-boolean-terms", d_assertions);
{
Chat() << "rewriting Boolean terms..." << endl;
- for(unsigned i = 0, i_end = d_assertionsToPreprocess.size(); i != i_end; ++i) {
- d_assertionsToPreprocess[i] = rewriteBooleanTerms(d_assertionsToPreprocess[i]);
+ for(unsigned i = 0, i_end = d_assertions.size(); i != i_end; ++i) {
+ d_assertions.replace(i, rewriteBooleanTerms(d_assertions[i]));
}
}
- dumpAssertions("post-boolean-terms", d_assertionsToPreprocess);
+ dumpAssertions("post-boolean-terms", d_assertions);
- Debug("smt") << " d_assertionsToPreprocess: " << d_assertionsToPreprocess.size() << endl;
- Debug("smt") << " d_assertionsToCheck : " << d_assertionsToCheck.size() << endl;
+ Debug("smt") << " d_assertions : " << d_assertions.size() << endl;
- dumpAssertions("pre-constrain-subtypes", d_assertionsToPreprocess);
+ dumpAssertions("pre-constrain-subtypes", d_assertions);
{
// Any variables of subtype types need to be constrained properly.
// Careful, here: constrainSubtypes() adds to the back of
- // d_assertionsToPreprocess, but we don't need to reprocess those.
+ // d_assertions, but we don't need to reprocess those.
// We also can't use an iterator, because the vector may be moved in
// memory during this loop.
Chat() << "constraining subtypes..." << endl;
- for(unsigned i = 0, i_end = d_assertionsToPreprocess.size(); i != i_end; ++i) {
- constrainSubtypes(d_assertionsToPreprocess[i], d_assertionsToPreprocess);
+ for(unsigned i = 0, i_end = d_assertions.size(); i != i_end; ++i) {
+ constrainSubtypes(d_assertions[i], d_assertions);
}
}
- dumpAssertions("post-constrain-subtypes", d_assertionsToPreprocess);
+ dumpAssertions("post-constrain-subtypes", d_assertions);
- Debug("smt") << " d_assertionsToPreprocess: " << d_assertionsToPreprocess.size() << endl;
- Debug("smt") << " d_assertionsToCheck : " << d_assertionsToCheck.size() << endl;
+ Debug("smt") << " d_assertions : " << d_assertions.size() << endl;
+ bool noConflict = true;
// Unconstrained simplification
if(options::unconstrainedSimp()) {
- dumpAssertions("pre-unconstrained-simp", d_assertionsToPreprocess);
+ dumpAssertions("pre-unconstrained-simp", d_assertions);
Chat() << "...doing unconstrained simplification..." << endl;
- unconstrainedSimp(d_assertionsToPreprocess);
- dumpAssertions("post-unconstrained-simp", d_assertionsToPreprocess);
+ unconstrainedSimp();
+ dumpAssertions("post-unconstrained-simp", d_assertions);
}
if(options::bvIntroducePow2()){
- theory::bv::BVIntroducePow2::pow2Rewrite(d_assertionsToPreprocess);
+ theory::bv::BVIntroducePow2::pow2Rewrite(d_assertions.ref());
}
- dumpAssertions("pre-substitution", d_assertionsToPreprocess);
+ dumpAssertions("pre-substitution", d_assertions);
- // Apply the substitutions we already have, and normalize
- Chat() << "applying substitutions..." << endl;
- Trace("simplify") << "SmtEnginePrivate::nonClausalSimplify(): "
- << "applying substitutions" << endl;
- for (unsigned i = 0; i < d_assertionsToPreprocess.size(); ++ i) {
- Trace("simplify") << "applying to " << d_assertionsToPreprocess[i] << endl;
- d_assertionsToPreprocess[i] =
- Rewriter::rewrite(d_topLevelSubstitutions.apply(d_assertionsToPreprocess[i]));
- Trace("simplify") << " got " << d_assertionsToPreprocess[i] << endl;
+ if(options::unsatCores()) {
+ // special rewriting pass for unsat cores, since many of the passes below are skipped
+ for (unsigned i = 0; i < d_assertions.size(); ++ i) {
+ d_assertions.replace(i, Rewriter::rewrite(d_assertions[i]));
+ }
+ } else {
+ // Apply the substitutions we already have, and normalize
+ if(!options::unsatCores()) {
+ Chat() << "applying substitutions..." << endl;
+ Trace("simplify") << "SmtEnginePrivate::nonClausalSimplify(): "
+ << "applying substitutions" << endl;
+ for (unsigned i = 0; i < d_assertions.size(); ++ i) {
+ Trace("simplify") << "applying to " << d_assertions[i] << endl;
+ d_assertions.replace(i, Rewriter::rewrite(d_topLevelSubstitutions.apply(d_assertions[i])));
+ Trace("simplify") << " got " << d_assertions[i] << endl;
+ }
+ }
}
- dumpAssertions("post-substitution", d_assertionsToPreprocess);
- // Assertions ARE guaranteed to be rewritten by this point
+ dumpAssertions("post-substitution", d_assertions);
+ // Assertions ARE guaranteed to be rewritten by this point
// Lift bit-vectors of size 1 to bool
if(options::bitvectorToBool()) {
- dumpAssertions("pre-bv-to-bool", d_assertionsToPreprocess);
+ dumpAssertions("pre-bv-to-bool", d_assertions);
Chat() << "...doing bvToBool..." << endl;
bvToBool();
- dumpAssertions("post-bv-to-bool", d_assertionsToPreprocess);
+ dumpAssertions("post-bv-to-bool", d_assertions);
}
if( d_smt.d_logic.isTheoryEnabled(THEORY_STRINGS) ) {
- dumpAssertions("pre-strings-pp", d_assertionsToPreprocess);
+ dumpAssertions("pre-strings-pp", d_assertions);
CVC4::theory::strings::StringsPreprocess sp;
std::vector<Node> newNodes;
- newNodes.push_back(d_assertionsToPreprocess[d_realAssertionsEnd - 1]);
- sp.simplify( d_assertionsToPreprocess, newNodes );
+ newNodes.push_back(d_assertions[d_realAssertionsEnd - 1]);
+ sp.simplify( d_assertions.ref(), newNodes );
if(newNodes.size() > 1) {
- d_assertionsToPreprocess[d_realAssertionsEnd - 1] = NodeManager::currentNM()->mkNode(kind::AND, newNodes);
+ d_assertions[d_realAssertionsEnd - 1] = NodeManager::currentNM()->mkNode(kind::AND, newNodes);
}
- for (unsigned i = 0; i < d_assertionsToPreprocess.size(); ++ i) {
- d_assertionsToPreprocess[i] = Rewriter::rewrite( d_assertionsToPreprocess[i] );
+ for (unsigned i = 0; i < d_assertions.size(); ++ i) {
+ d_assertions[i] = Rewriter::rewrite( d_assertions[i] );
}
- dumpAssertions("post-strings-pp", d_assertionsToPreprocess);
+ dumpAssertions("post-strings-pp", d_assertions);
}
if( d_smt.d_logic.isQuantified() ){
//remove rewrite rules
- for( unsigned i=0; i < d_assertionsToPreprocess.size(); i++ ) {
- if( d_assertionsToPreprocess[i].getKind() == kind::REWRITE_RULE ){
- Node prev = d_assertionsToPreprocess[i];
+ for( unsigned i=0; i < d_assertions.size(); i++ ) {
+ if( d_assertions[i].getKind() == kind::REWRITE_RULE ){
+ Node prev = d_assertions[i];
Trace("quantifiers-rewrite-debug") << "Rewrite rewrite rule " << prev << "..." << std::endl;
- d_assertionsToPreprocess[i] = Rewriter::rewrite( quantifiers::QuantifiersRewriter::rewriteRewriteRule( d_assertionsToPreprocess[i] ) );
+ d_assertions[i] = Rewriter::rewrite( quantifiers::QuantifiersRewriter::rewriteRewriteRule( d_assertions[i] ) );
Trace("quantifiers-rewrite") << "*** rr-rewrite " << prev << endl;
- Trace("quantifiers-rewrite") << " ...got " << d_assertionsToPreprocess[i] << endl;
+ Trace("quantifiers-rewrite") << " ...got " << d_assertions[i] << endl;
}
}
- dumpAssertions("pre-skolem-quant", d_assertionsToPreprocess);
+ dumpAssertions("pre-skolem-quant", d_assertions);
if( options::preSkolemQuant() ){
//apply pre-skolemization to existential quantifiers
- for (unsigned i = 0; i < d_assertionsToPreprocess.size(); ++ i) {
- Node prev = d_assertionsToPreprocess[i];
+ for (unsigned i = 0; i < d_assertions.size(); ++ i) {
+ Node prev = d_assertions[i];
Trace("quantifiers-rewrite-debug") << "Pre-skolemize " << prev << "..." << std::endl;
vector< TypeNode > fvTypes;
vector< TNode > fvs;
- d_assertionsToPreprocess[i] = quantifiers::QuantifiersRewriter::preSkolemizeQuantifiers( prev, true, fvTypes, fvs );
- if( prev!=d_assertionsToPreprocess[i] ){
- d_assertionsToPreprocess[i] = Rewriter::rewrite( d_assertionsToPreprocess[i] );
+ d_assertions.replace(i, quantifiers::QuantifiersRewriter::preSkolemizeQuantifiers( prev, true, fvTypes, fvs ));
+ if( prev!=d_assertions[i] ){
+ d_assertions.replace(i, Rewriter::rewrite( d_assertions[i] ));
Trace("quantifiers-rewrite") << "*** Pre-skolemize " << prev << endl;
- Trace("quantifiers-rewrite") << " ...got " << d_assertionsToPreprocess[i] << endl;
+ Trace("quantifiers-rewrite") << " ...got " << d_assertions[i] << endl;
}
}
}
- dumpAssertions("post-skolem-quant", d_assertionsToPreprocess);
+ dumpAssertions("post-skolem-quant", d_assertions);
if( options::macrosQuant() ){
//quantifiers macro expansion
bool success;
do{
quantifiers::QuantifierMacros qm;
- success = qm.simplify( d_assertionsToPreprocess, true );
+ success = qm.simplify( d_assertions.ref(), true );
}while( success );
}
+ if( options::fmfFunWellDefined() ){
+ quantifiers::FunDefFmf fdf;
+ fdf.simplify( d_assertions.ref() );
+ }
Trace("fo-rsn-enable") << std::endl;
if( options::foPropQuant() ){
quantifiers::FirstOrderPropagation fop;
- fop.simplify( d_assertionsToPreprocess );
+ fop.simplify( d_assertions.ref() );
}
}
if( options::sortInference() ){
//sort inference technique
SortInference * si = d_smt.d_theoryEngine->getSortInference();
- si->simplify( d_assertionsToPreprocess );
+ si->simplify( d_assertions.ref() );
for( std::map< Node, Node >::iterator it = si->d_model_replace_f.begin(); it != si->d_model_replace_f.end(); ++it ){
d_smt.setPrintFuncInModel( it->first.toExpr(), false );
d_smt.setPrintFuncInModel( it->second.toExpr(), true );
@@ -3009,25 +3161,25 @@ void SmtEnginePrivate::processAssertions() {
}
//if( options::quantConflictFind() ){
- // d_smt.d_theoryEngine->getQuantConflictFind()->registerAssertions( d_assertionsToPreprocess );
+ // d_smt.d_theoryEngine->getQuantConflictFind()->registerAssertions( d_assertions );
//}
if( options::pbRewrites() ){
- d_pbsProcessor.learn(d_assertionsToPreprocess);
+ d_pbsProcessor.learn(d_assertions.ref());
if(d_pbsProcessor.likelyToHelp()){
- d_pbsProcessor.applyReplacements(d_assertionsToPreprocess);
+ d_pbsProcessor.applyReplacements(d_assertions.ref());
}
}
- dumpAssertions("pre-simplify", d_assertionsToPreprocess);
+ dumpAssertions("pre-simplify", d_assertions);
Chat() << "simplifying assertions..." << endl;
- bool noConflict = simplifyAssertions();
+ noConflict = simplifyAssertions();
if(!noConflict){
++(d_smt.d_stats->d_simplifiedToFalse);
}
- dumpAssertions("post-simplify", d_assertionsToCheck);
+ dumpAssertions("post-simplify", d_assertions);
- dumpAssertions("pre-static-learning", d_assertionsToCheck);
+ dumpAssertions("pre-static-learning", d_assertions);
if(options::doStaticLearning()) {
// Perform static learning
Chat() << "doing static learning..." << endl;
@@ -3035,27 +3187,25 @@ void SmtEnginePrivate::processAssertions() {
<< "performing static learning" << endl;
staticLearning();
}
- dumpAssertions("post-static-learning", d_assertionsToCheck);
+ dumpAssertions("post-static-learning", d_assertions);
Trace("smt") << "POST bvToBool" << endl;
- Debug("smt") << " d_assertionsToPreprocess: " << d_assertionsToPreprocess.size() << endl;
- Debug("smt") << " d_assertionsToCheck : " << d_assertionsToCheck.size() << endl;
+ Debug("smt") << " d_assertions : " << d_assertions.size() << endl;
- dumpAssertions("pre-ite-removal", d_assertionsToCheck);
+ dumpAssertions("pre-ite-removal", d_assertions);
{
Chat() << "removing term ITEs..." << endl;
TimerStat::CodeTimer codeTimer(d_smt.d_stats->d_iteRemovalTime);
// Remove ITEs, updating d_iteSkolemMap
- d_smt.d_stats->d_numAssertionsPre += d_assertionsToCheck.size();
+ d_smt.d_stats->d_numAssertionsPre += d_assertions.size();
removeITEs();
- d_smt.d_stats->d_numAssertionsPost += d_assertionsToCheck.size();
+ d_smt.d_stats->d_numAssertionsPost += d_assertions.size();
}
- dumpAssertions("post-ite-removal", d_assertionsToCheck);
+ dumpAssertions("post-ite-removal", d_assertions);
- dumpAssertions("pre-repeat-simplify", d_assertionsToCheck);
+ dumpAssertions("pre-repeat-simplify", d_assertions);
if(options::repeatSimp()) {
- d_assertionsToCheck.swap(d_assertionsToPreprocess);
Chat() << "re-simplifying assertions..." << endl;
ScopeCounter depth(d_simplifyAssertionsDepth);
noConflict &= simplifyAssertions();
@@ -3084,11 +3234,11 @@ void SmtEnginePrivate::processAssertions() {
IteSkolemMap::iterator it = d_iteSkolemMap.begin();
IteSkolemMap::iterator iend = d_iteSkolemMap.end();
NodeBuilder<> builder(kind::AND);
- builder << d_assertionsToCheck[d_realAssertionsEnd - 1];
+ builder << d_assertions[d_realAssertionsEnd - 1];
vector<TNode> toErase;
for (; it != iend; ++it) {
if (skolemSet.find((*it).first) == skolemSet.end()) {
- TNode iteExpr = d_assertionsToCheck[(*it).second];
+ TNode iteExpr = d_assertions[(*it).second];
if (iteExpr.getKind() == kind::ITE &&
iteExpr[1].getKind() == kind::EQUAL &&
iteExpr[1][0] == (*it).first &&
@@ -3104,8 +3254,8 @@ void SmtEnginePrivate::processAssertions() {
}
}
// Move this iteExpr into the main assertions
- builder << d_assertionsToCheck[(*it).second];
- d_assertionsToCheck[(*it).second] = NodeManager::currentNM()->mkConst<bool>(true);
+ builder << d_assertions[(*it).second];
+ d_assertions[(*it).second] = NodeManager::currentNM()->mkConst<bool>(true);
toErase.push_back((*it).first);
}
if(builder.getNumChildren() > 1) {
@@ -3113,60 +3263,58 @@ void SmtEnginePrivate::processAssertions() {
d_iteSkolemMap.erase(toErase.back());
toErase.pop_back();
}
- d_assertionsToCheck[d_realAssertionsEnd - 1] =
+ d_assertions[d_realAssertionsEnd - 1] =
Rewriter::rewrite(Node(builder));
}
// For some reason this is needed for some benchmarks, such as
// 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());
+ // Assert(iteRewriteAssertionsEnd == d_assertions.size());
}
}
- dumpAssertions("post-repeat-simplify", d_assertionsToCheck);
+ dumpAssertions("post-repeat-simplify", d_assertions);
- dumpAssertions("pre-rewrite-apply-to-const", d_assertionsToCheck);
+ dumpAssertions("pre-rewrite-apply-to-const", d_assertions);
if(options::rewriteApplyToConst()) {
Chat() << "Rewriting applies to constants..." << endl;
- TimerStat::CodeTimer codeTimer(d_smt.d_stats->d_theoryPreprocessTime);
- for (unsigned i = 0; i < d_assertionsToCheck.size(); ++ i) {
- d_assertionsToCheck[i] = Rewriter::rewrite(rewriteApplyToConst(d_assertionsToCheck[i]));
+ TimerStat::CodeTimer codeTimer(d_smt.d_stats->d_rewriteApplyToConstTime);
+ for (unsigned i = 0; i < d_assertions.size(); ++ i) {
+ d_assertions[i] = Rewriter::rewrite(rewriteApplyToConst(d_assertions[i]));
}
}
- dumpAssertions("post-rewrite-apply-to-const", d_assertionsToCheck);
+ dumpAssertions("post-rewrite-apply-to-const", d_assertions);
// begin: INVARIANT to maintain: no reordering of assertions or
// introducing new ones
#ifdef CVC4_ASSERTIONS
- unsigned iteRewriteAssertionsEnd = d_assertionsToCheck.size();
+ unsigned iteRewriteAssertionsEnd = d_assertions.size();
#endif
- Debug("smt") << " d_assertionsToPreprocess: " << d_assertionsToPreprocess.size() << endl;
- Debug("smt") << " d_assertionsToCheck : " << d_assertionsToCheck.size() << endl;
+ Debug("smt") << " d_assertions : " << d_assertions.size() << endl;
Debug("smt") << "SmtEnginePrivate::processAssertions() POST SIMPLIFICATION" << endl;
- Debug("smt") << " d_assertionsToPreprocess: " << d_assertionsToPreprocess.size() << endl;
- Debug("smt") << " d_assertionsToCheck : " << d_assertionsToCheck.size() << endl;
+ Debug("smt") << " d_assertions : " << d_assertions.size() << endl;
- dumpAssertions("pre-theory-preprocessing", d_assertionsToCheck);
+ dumpAssertions("pre-theory-preprocessing", d_assertions);
{
Chat() << "theory preprocessing..." << endl;
TimerStat::CodeTimer codeTimer(d_smt.d_stats->d_theoryPreprocessTime);
// Call the theory preprocessors
d_smt.d_theoryEngine->preprocessStart();
- for (unsigned i = 0; i < d_assertionsToCheck.size(); ++ i) {
- d_assertionsToCheck[i] = d_smt.d_theoryEngine->preprocess(d_assertionsToCheck[i]);
+ for (unsigned i = 0; i < d_assertions.size(); ++ i) {
+ d_assertions.replace(i, d_smt.d_theoryEngine->preprocess(d_assertions[i]));
}
}
- dumpAssertions("post-theory-preprocessing", d_assertionsToCheck);
+ dumpAssertions("post-theory-preprocessing", d_assertions);
// If we are using eager bit-blasting wrap assertions in fake atom so that
// everything gets bit-blasted to internal SAT solver
if (options::bitblastMode() == theory::bv::BITBLAST_MODE_EAGER) {
- for (unsigned i = 0; i < d_assertionsToCheck.size(); ++i) {
- TNode atom = d_assertionsToCheck[i];
+ for (unsigned i = 0; i < d_assertions.size(); ++i) {
+ TNode atom = d_assertions[i];
Node eager_atom = NodeManager::currentNM()->mkNode(kind::BITVECTOR_EAGER_ATOM, atom);
- d_assertionsToCheck[i] = eager_atom;
+ d_assertions.replace(i, eager_atom);
TheoryModel* m = d_smt.d_theoryEngine->getModel();
m->addSubstitution(eager_atom, atom);
}
@@ -3175,28 +3323,36 @@ void SmtEnginePrivate::processAssertions() {
// Push the formula to decision engine
if(noConflict) {
Chat() << "pushing to decision engine..." << endl;
- Assert(iteRewriteAssertionsEnd == d_assertionsToCheck.size());
+ Assert(iteRewriteAssertionsEnd == d_assertions.size());
d_smt.d_decisionEngine->addAssertions
- (d_assertionsToCheck, d_realAssertionsEnd, d_iteSkolemMap);
+ (d_assertions.ref(), d_realAssertionsEnd, d_iteSkolemMap);
}
// end: INVARIANT to maintain: no reordering of assertions or
// introducing new ones
- dumpAssertions("post-everything", d_assertionsToCheck);
-
+ dumpAssertions("post-everything", d_assertions);
+
+ //set instantiation level of everything to zero
+ if( options::instLevelInputOnly() && options::instMaxLevel()!=-1 ){
+ for( unsigned i=0; i < d_assertions.size(); i++ ) {
+ theory::QuantifiersEngine::setInstantiationLevelAttr( d_assertions[i], 0 );
+ }
+ }
+
// Push the formula to SAT
{
Chat() << "converting to CNF..." << endl;
TimerStat::CodeTimer codeTimer(d_smt.d_stats->d_cnfConversionTime);
- for (unsigned i = 0; i < d_assertionsToCheck.size(); ++ i) {
- d_smt.d_propEngine->assertFormula(d_assertionsToCheck[i]);
+ for (unsigned i = 0; i < d_assertions.size(); ++ i) {
+ Chat() << "+ " << d_assertions[i] << std::endl;
+ d_smt.d_propEngine->assertFormula(d_assertions[i]);
}
}
d_assertionsProcessed = true;
- d_assertionsToCheck.clear();
+ d_assertions.clear();
d_iteSkolemMap.clear();
}
@@ -3211,13 +3367,8 @@ void SmtEnginePrivate::addFormula(TNode n)
Trace("smt") << "SmtEnginePrivate::addFormula(" << n << ")" << endl;
// Add the normalized formula to the queue
- d_assertionsToPreprocess.push_back(n);
- //d_assertionsToPreprocess.push_back(Rewriter::rewrite(n));
-
- // If the mode of processing is incremental prepreocess and assert immediately
- if (options::simplificationMode() == SIMPLIFICATION_MODE_INCREMENTAL) {
- processAssertions();
- }
+ d_assertions.push_back(n);
+ //d_assertions.push_back(Rewriter::rewrite(n));
}
void SmtEngine::ensureBoolean(const Expr& e) throw(TypeCheckingException) {
@@ -3232,7 +3383,7 @@ void SmtEngine::ensureBoolean(const Expr& e) throw(TypeCheckingException) {
}
}
-Result SmtEngine::checkSat(const Expr& ex) throw(TypeCheckingException, ModalException, LogicException) {
+Result SmtEngine::checkSat(const Expr& ex, bool inUnsatCore) throw(TypeCheckingException, ModalException, LogicException) {
Assert(ex.isNull() || ex.getExprManager() == d_exprManager);
SmtScope smts(this);
finalOptionsAreSet();
@@ -3253,7 +3404,7 @@ Result SmtEngine::checkSat(const Expr& ex) throw(TypeCheckingException, ModalExc
// Ensure expr is type-checked at this point.
ensureBoolean(e);
// Give it to proof manager
- PROOF( ProofManager::currentPM()->addAssertion(e); );
+ PROOF( ProofManager::currentPM()->addAssertion(e, inUnsatCore); );
}
// check to see if a postsolve() is pending
@@ -3315,7 +3466,7 @@ Result SmtEngine::checkSat(const Expr& ex) throw(TypeCheckingException, ModalExc
return r;
}/* SmtEngine::checkSat() */
-Result SmtEngine::query(const Expr& ex) throw(TypeCheckingException, ModalException, LogicException) {
+Result SmtEngine::query(const Expr& ex, bool inUnsatCore) throw(TypeCheckingException, ModalException, LogicException) {
Assert(!ex.isNull());
Assert(ex.getExprManager() == d_exprManager);
SmtScope smts(this);
@@ -3334,7 +3485,7 @@ Result SmtEngine::query(const Expr& ex) throw(TypeCheckingException, ModalExcept
// Ensure that the expression is type-checked at this point, and Boolean
ensureBoolean(e);
// Give it to proof manager
- PROOF( ProofManager::currentPM()->addAssertion(e.notExpr()); );
+ PROOF( ProofManager::currentPM()->addAssertion(e.notExpr(), inUnsatCore); );
// check to see if a postsolve() is pending
if(d_needPostsolve) {
@@ -3393,13 +3544,13 @@ Result SmtEngine::query(const Expr& ex) throw(TypeCheckingException, ModalExcept
return r;
}/* SmtEngine::query() */
-Result SmtEngine::assertFormula(const Expr& ex) throw(TypeCheckingException, LogicException) {
+Result SmtEngine::assertFormula(const Expr& ex, bool inUnsatCore) throw(TypeCheckingException, LogicException) {
Assert(ex.getExprManager() == d_exprManager);
SmtScope smts(this);
finalOptionsAreSet();
doPendingPops();
- PROOF( ProofManager::currentPM()->addAssertion(ex); );
+ PROOF( ProofManager::currentPM()->addAssertion(ex, inUnsatCore); );
Trace("smt") << "SmtEngine::assertFormula(" << ex << ")" << endl;
@@ -3412,7 +3563,7 @@ Result SmtEngine::assertFormula(const Expr& ex) throw(TypeCheckingException, Log
}
d_private->addFormula(e.getNode());
return quickCheck().asValidityResult();
-}
+}/* SmtEngine::assertFormula() */
Node SmtEngine::postprocess(TNode node, TypeNode expectedType) const {
ModelPostprocessor mpost;
@@ -3540,6 +3691,7 @@ Expr SmtEngine::getValue(const Expr& ex) const throw(ModalException, TypeCheckin
if(options::abstractValues() && resultNode.getType().isArray()) {
resultNode = d_private->mkAbstractValue(resultNode);
+ Trace("smt") << "--- abstract value >> " << resultNode << endl;
}
return resultNode.toExpr();
@@ -3704,8 +3856,8 @@ Model* SmtEngine::getModel() throw(ModalException) {
}
void SmtEngine::checkModel(bool hardFailure) {
- // --check-model implies --interactive, which enables the assertion list,
- // so we should be ok.
+ // --check-model implies --produce-assertions, which enables the
+ // assertion list, so we should be ok.
Assert(d_assertionList != NULL, "don't have an assertion list to check in SmtEngine::checkModel()");
TimerStat::CodeTimer checkModelTimer(d_stats->d_checkModelTime);
@@ -3883,6 +4035,30 @@ void SmtEngine::checkModel(bool hardFailure) {
Notice() << "SmtEngine::checkModel(): all assertions checked out OK !" << endl;
}
+UnsatCore SmtEngine::getUnsatCore() throw(ModalException) {
+ Trace("smt") << "SMT getUnsatCore()" << endl;
+ SmtScope smts(this);
+ finalOptionsAreSet();
+ if(Dump.isOn("benchmark")) {
+ Dump("benchmark") << GetUnsatCoreCommand();
+ }
+#ifdef CVC4_PROOF
+ if(!options::unsatCores()) {
+ throw ModalException("Cannot get an unsat core when produce-unsat-cores option is off.");
+ }
+ if(d_status.isNull() ||
+ d_status.asSatisfiabilityResult() != Result::UNSAT ||
+ d_problemExtended) {
+ throw ModalException("Cannot get an unsat core unless immediately preceded by UNSAT/VALID response.");
+ }
+
+ d_proofManager->getProof(this);// just to trigger core creation
+ return UnsatCore(this, d_proofManager->begin_unsat_core(), d_proofManager->end_unsat_core());
+#else /* CVC4_PROOF */
+ throw ModalException("This build of CVC4 doesn't have proof support (required for unsat cores).");
+#endif /* CVC4_PROOF */
+}
+
Proof* SmtEngine::getProof() throw(ModalException) {
Trace("smt") << "SMT getProof()" << endl;
SmtScope smts(this);
@@ -3892,16 +4068,12 @@ Proof* SmtEngine::getProof() throw(ModalException) {
}
#ifdef CVC4_PROOF
if(!options::proof()) {
- const char* msg =
- "Cannot get a proof when produce-proofs option is off.";
- throw ModalException(msg);
+ throw ModalException("Cannot get a proof when produce-proofs option is off.");
}
if(d_status.isNull() ||
d_status.asSatisfiabilityResult() != Result::UNSAT ||
d_problemExtended) {
- const char* msg =
- "Cannot get a proof unless immediately preceded by UNSAT/VALID response.";
- throw ModalException(msg);
+ throw ModalException("Cannot get a proof unless immediately preceded by UNSAT/VALID response.");
}
return ProofManager::getProof(this);
@@ -3930,9 +4102,9 @@ vector<Expr> SmtEngine::getAssertions() throw(ModalException) {
Dump("benchmark") << GetAssertionsCommand();
}
Trace("smt") << "SMT getAssertions()" << endl;
- if(!options::interactive()) {
+ if(!options::produceAssertions()) {
const char* msg =
- "Cannot query the current assertion list when not in interactive mode.";
+ "Cannot query the current assertion list when not in produce-assertions mode.";
throw ModalException(msg);
}
Assert(d_assertionList != NULL);
@@ -4049,6 +4221,40 @@ void SmtEngine::doPendingPops() {
}
}
+void SmtEngine::reset() throw() {
+ SmtScope smts(this);
+ ExprManager *em = d_exprManager;
+ Trace("smt") << "SMT reset()" << endl;
+ if(Dump.isOn("benchmark")) {
+ Dump("benchmark") << ResetCommand();
+ }
+ Options opts = d_originalOptions;
+ this->~SmtEngine();
+ NodeManager::fromExprManager(em)->getOptions() = opts;
+ new(this) SmtEngine(em);
+}
+
+void SmtEngine::resetAssertions() throw() {
+ SmtScope smts(this);
+
+ Trace("smt") << "SMT resetAssertions()" << endl;
+ if(Dump.isOn("benchmark")) {
+ Dump("benchmark") << ResetAssertionsCommand();
+ }
+
+ while(!d_userLevels.empty()) {
+ pop();
+ }
+
+ // Also remember the global push/pop around everything.
+ Assert(d_userLevels.size() == 0 && d_userContext->getLevel() == 1);
+ d_context->popto(0);
+ d_userContext->popto(0);
+ d_modelGlobalCommands.clear();
+ d_userContext->push();
+ d_context->push();
+}
+
void SmtEngine::interrupt() throw(ModalException) {
if(!d_fullyInited) {
return;
@@ -4111,9 +4317,13 @@ SExpr SmtEngine::getStatistic(std::string name) const throw() {
return d_statisticsRegistry->getStatistic(name);
}
-void SmtEngine::setUserAttribute(const std::string& attr, Expr expr) {
+void SmtEngine::setUserAttribute(const std::string& attr, Expr expr, std::vector<Expr> expr_values, std::string str_value) {
SmtScope smts(this);
- d_theoryEngine->setUserAttribute(attr, expr.getNode());
+ std::vector<Node> node_values;
+ for( unsigned i=0; i<expr_values.size(); i++ ){
+ node_values.push_back( expr_values[i].getNode() );
+ }
+ d_theoryEngine->setUserAttribute(attr, expr.getNode(), node_values, str_value);
}
void SmtEngine::setPrintFuncInModel(Expr f, bool p) {
diff --git a/src/smt/smt_engine.h b/src/smt/smt_engine.h
index 71b42534a..489d34d79 100644
--- a/src/smt/smt_engine.h
+++ b/src/smt/smt_engine.h
@@ -28,6 +28,7 @@
#include "expr/expr.h"
#include "expr/expr_manager.h"
#include "util/proof.h"
+#include "util/unsat_core.h"
#include "smt/modal_exception.h"
#include "smt/logic_exception.h"
#include "options/options.h"
@@ -70,6 +71,13 @@ namespace prop {
class PropEngine;
}/* CVC4::prop namespace */
+namespace expr {
+ namespace attr {
+ class AttributeManager;
+ struct SmtAttributes;
+ }/* CVC4::expr::attr namespace */
+}/* CVC4::expr namespace */
+
namespace smt {
/**
* Representation of a defined function. We keep these around in
@@ -182,6 +190,11 @@ class CVC4_PUBLIC SmtEngine {
LogicInfo d_logic;
/**
+ * Keep a copy of the original option settings (for reset()).
+ */
+ Options d_originalOptions;
+
+ /**
* Number of internal pops that have been deferred.
*/
unsigned d_pendingPops;
@@ -255,7 +268,7 @@ class CVC4_PUBLIC SmtEngine {
smt::SmtEnginePrivate* d_private;
/**
- * Check that a generated Proof (via getProof()) checks.
+ * Check that a generated proof (via getProof()) checks.
*/
void checkProof();
@@ -341,9 +354,20 @@ class CVC4_PUBLIC SmtEngine {
// to access d_modelCommands
friend class ::CVC4::Model;
friend class ::CVC4::theory::TheoryModel;
+ // to access SmtAttributes
+ friend class expr::attr::AttributeManager;
// to access getModel(), which is private (for now)
friend class GetModelCommand;
+ /**
+ * There's something of a handshake between the expr package's
+ * AttributeManager and the SmtEngine because the expr package
+ * doesn't have a Context on its own (that's owned by the
+ * SmtEngine). Thus all context-dependent attributes are stored
+ * here.
+ */
+ expr::attr::SmtAttributes* d_smtAttributes;
+
StatisticsRegistry* d_statisticsRegistry;
smt::SmtEngineStatistics* d_stats;
@@ -424,8 +448,8 @@ public:
/**
* Add a formula to the current context: preprocess, do per-theory
* setup, use processAssertionList(), asserting to T-solver for
- * literals and conjunction of literals. Returns false iff
- * inconsistent.
+ * literals and conjunction of literals. Returns false if
+ * immediately determined to be inconsistent.
*/
void defineFunction(Expr func,
const std::vector<Expr>& formals,
@@ -434,23 +458,25 @@ public:
/**
* Add a formula to the current context: preprocess, do per-theory
* setup, use processAssertionList(), asserting to T-solver for
- * literals and conjunction of literals. Returns false iff
- * inconsistent.
+ * literals and conjunction of literals. Returns false if
+ * immediately determined to be inconsistent. This version
+ * takes a Boolean flag to determine whether to include this asserted
+ * formula in an unsat core (if one is later requested).
*/
- Result assertFormula(const Expr& e) throw(TypeCheckingException, LogicException);
+ Result assertFormula(const Expr& e, bool inUnsatCore = true) throw(TypeCheckingException, LogicException);
/**
* Check validity of an expression with respect to the current set
* of assertions by asserting the query expression's negation and
* calling check(). Returns valid, invalid, or unknown result.
*/
- Result query(const Expr& e) throw(TypeCheckingException, ModalException, LogicException);
+ Result query(const Expr& e, bool inUnsatCore = true) throw(TypeCheckingException, ModalException, LogicException);
/**
* Assert a formula (if provided) to the current context and call
* check(). Returns sat, unsat, or unknown result.
*/
- Result checkSat(const Expr& e = Expr()) throw(TypeCheckingException, ModalException, LogicException);
+ Result checkSat(const Expr& e = Expr(), bool inUnsatCore = true) throw(TypeCheckingException, ModalException, LogicException);
/**
* Simplify a formula without doing "much" work. Does not involve
@@ -507,6 +533,13 @@ public:
void printInstantiations( std::ostream& out );
/**
+ * Get an unsatisfiable core (only if immediately preceded by an
+ * UNSAT or VALID query). Only permitted if CVC4 was built with
+ * unsat-core support and produce-unsat-cores is on.
+ */
+ UnsatCore getUnsatCore() throw(ModalException);
+
+ /**
* Get the current set of assertions. Only permitted if the
* SmtEngine is set to operate interactively.
*/
@@ -523,6 +556,18 @@ public:
void pop() throw(ModalException);
/**
+ * Completely reset the state of the solver, as though destroyed and
+ * recreated. The result is as if newly constructed (so it still
+ * retains the same options structure and ExprManager).
+ */
+ void reset() throw();
+
+ /**
+ * Reset all assertions, global declarations, etc.
+ */
+ void resetAssertions() throw();
+
+ /**
* Interrupt a running query. This can be called from another thread
* or from a signal handler. Throws a ModalException if the SmtEngine
* isn't currently in a query.
@@ -651,7 +696,7 @@ public:
* This function is called when an attribute is set by a user.
* In SMT-LIBv2 this is done via the syntax (! expr :attr)
*/
- void setUserAttribute(const std::string& attr, Expr expr);
+ void setUserAttribute(const std::string& attr, Expr expr, std::vector<Expr> expr_values, std::string str_value);
/**
* Set print function in model
diff --git a/src/smt/smt_engine_scope.h b/src/smt/smt_engine_scope.h
index 54b9fa1d0..fb5810fd5 100644
--- a/src/smt/smt_engine_scope.h
+++ b/src/smt/smt_engine_scope.h
@@ -40,9 +40,14 @@ inline SmtEngine* currentSmtEngine() {
}
inline ProofManager* currentProofManager() {
- Assert(PROOF_ON());
+#ifdef CVC4_PROOF
+ Assert(options::proof() || options::unsatCores());
Assert(s_smtEngine_current != NULL);
return s_smtEngine_current->d_proofManager;
+#else /* CVC4_PROOF */
+ InternalError("proofs/unsat cores are not on, but ProofManager requested");
+ return NULL;
+#endif /* CVC4_PROOF */
}
class SmtScope : public NodeManagerScope {
diff --git a/src/theory/arith/theory_arith_private.cpp b/src/theory/arith/theory_arith_private.cpp
index 220737d2e..c657796ee 100644
--- a/src/theory/arith/theory_arith_private.cpp
+++ b/src/theory/arith/theory_arith_private.cpp
@@ -335,7 +335,7 @@ TheoryArithPrivate::Statistics::Statistics()
, d_unsatPivots("theory::arith::pivots::unsat")
, d_unknownPivots("theory::arith::pivots::unkown")
, d_solveIntModelsAttempts("theory::arith::z::solveInt::models::attempts", 0)
- , d_solveIntModelsSuccessful("zzz::solveInt::models::successful", 0)
+ , d_solveIntModelsSuccessful("theory::arith::zzz::solveInt::models::successful", 0)
, d_mipTimer("theory::arith::z::approx::mip::timer")
, d_lpTimer("theory::arith::z::approx::lp::timer")
, d_mipProofsAttempted("theory::arith::z::mip::proofs::attempted", 0)
diff --git a/src/theory/arrays/array_info.cpp b/src/theory/arrays/array_info.cpp
index dc907ba0b..9b2d3647e 100644
--- a/src/theory/arrays/array_info.cpp
+++ b/src/theory/arrays/array_info.cpp
@@ -181,6 +181,20 @@ void ArrayInfo::setModelRep(const TNode a, const TNode b) {
}
+void ArrayInfo::setConstArr(const TNode a, const TNode constArr) {
+ Assert(a.getType().isArray());
+ Info* temp_info;
+ CNodeInfoMap::iterator it = info_map.find(a);
+ if(it == info_map.end()) {
+ temp_info = new Info(ct, bck);
+ temp_info->constArr = constArr;
+ info_map[a] = temp_info;
+ } else {
+ (*it).second->constArr = constArr;
+ }
+
+}
+
/**
* Returns the information associated with TNode a
*/
@@ -224,6 +238,16 @@ const TNode ArrayInfo::getModelRep(const TNode a) const
return TNode();
}
+const TNode ArrayInfo::getConstArr(const TNode a) const
+{
+ CNodeInfoMap::const_iterator it = info_map.find(a);
+
+ if(it!= info_map.end()) {
+ return (*it).second->constArr;
+ }
+ return TNode();
+}
+
const CTNodeList* ArrayInfo::getIndices(const TNode a) const{
CNodeInfoMap::const_iterator it = info_map.find(a);
if(it!= info_map.end()) {
diff --git a/src/theory/arrays/array_info.h b/src/theory/arrays/array_info.h
index 09230bba7..f3c6385e5 100644
--- a/src/theory/arrays/array_info.h
+++ b/src/theory/arrays/array_info.h
@@ -64,11 +64,12 @@ public:
context::CDO<bool> isNonLinear;
context::CDO<bool> rIntro1Applied;
context::CDO<TNode> modelRep;
+ context::CDO<TNode> constArr;
CTNodeList* indices;
CTNodeList* stores;
CTNodeList* in_stores;
- Info(context::Context* c, Backtracker<TNode>* bck) : isNonLinear(c, false), rIntro1Applied(c, false), modelRep(c,TNode()) {
+ Info(context::Context* c, Backtracker<TNode>* bck) : isNonLinear(c, false), rIntro1Applied(c, false), modelRep(c,TNode()), constArr(c,TNode()) {
indices = new(true)CTNodeList(c);
stores = new(true)CTNodeList(c);
in_stores = new(true)CTNodeList(c);
@@ -210,6 +211,7 @@ public:
void setRIntro1Applied(const TNode a);
void setModelRep(const TNode a, const TNode rep);
+ void setConstArr(const TNode a, const TNode constArr);
/**
* Returns the information associated with TNode a
*/
@@ -222,6 +224,8 @@ public:
const TNode getModelRep(const TNode a) const;
+ const TNode getConstArr(const TNode a) const;
+
const CTNodeList* getIndices(const TNode a) const;
const CTNodeList* getStores(const TNode a) const;
diff --git a/src/theory/arrays/options b/src/theory/arrays/options
index 15220fbc2..8ed80c1f1 100644
--- a/src/theory/arrays/options
+++ b/src/theory/arrays/options
@@ -12,7 +12,7 @@ option arraysLazyRIntro1 --arrays-lazy-rintro1 bool :default true :read-write
turn on optimization to only perform RIntro1 rule lazily (see Jovanovic/Barrett 2012: Being Careful with Theory Combination)
option arraysModelBased --arrays-model-based bool :default false :read-write
- turn on model-based arrray solver
+ turn on model-based array solver
option arraysEagerIndexSplitting --arrays-eager-index bool :default true :read-write
turn on eager index splitting for generated array lemmas
@@ -20,4 +20,13 @@ option arraysEagerIndexSplitting --arrays-eager-index bool :default true :read-w
option arraysEagerLemmas --arrays-eager-lemmas bool :default false :read-write
turn on eager lemma generation for arrays
+option arraysConfig --arrays-config int :default 0 :read-write
+ set different array option configurations - for developers only
+
+option arraysReduceSharing --arrays-reduce-sharing bool :default false :read-write
+ use model information to reduce size of care graph for arrays
+
+option arraysPropagate --arrays-prop int :default 2 :read-write
+ propagation effort for arrays: 0 is none, 1 is some, 2 is full
+
endmodule
diff --git a/src/theory/arrays/theory_arrays.cpp b/src/theory/arrays/theory_arrays.cpp
index e73c059d4..9a661ab0c 100644
--- a/src/theory/arrays/theory_arrays.cpp
+++ b/src/theory/arrays/theory_arrays.cpp
@@ -40,11 +40,11 @@ namespace arrays {
const bool d_ccStore = false;
const bool d_useArrTable = false;
//const bool d_eagerLemmas = false;
-const bool d_propagateLemmas = true;
const bool d_preprocess = true;
const bool d_solveWrite = true;
const bool d_solveWrite2 = false;
// These are now options
+ //const bool d_propagateLemmas = true;
//bool d_useNonLinearOpt = true;
//bool d_lazyRIntro1 = true;
//bool d_eagerIndexSplitting = false;
@@ -82,11 +82,15 @@ TheoryArrays::TheoryArrays(context::Context* c, context::UserContext* u, OutputC
d_sharedOther(c),
d_sharedTerms(c, false),
d_reads(c),
+ d_constReadsList(c),
+ d_constReadsContext(new context::Context()),
+ d_contextPopper(c, d_constReadsContext),
d_skolemIndex(c, 0),
d_decisionRequests(c),
d_permRef(c),
d_modelConstraints(c),
d_lemmasSaved(c),
+ d_defValues(c),
d_inCheckModel(false)
{
StatisticsRegistry::registerStat(&d_numRow);
@@ -123,7 +127,11 @@ TheoryArrays::TheoryArrays(context::Context* c, context::UserContext* u, OutputC
}
TheoryArrays::~TheoryArrays() {
-
+ CNodeNListMap::iterator it = d_constReads.begin();
+ for( ; it != d_constReads.end(); ++it ) {
+ (*it).second->deleteSelf();
+ }
+ delete d_constReadsContext;
StatisticsRegistry::unregisterStat(&d_numRow);
StatisticsRegistry::unregisterStat(&d_numExt);
StatisticsRegistry::unregisterStat(&d_numProp);
@@ -135,7 +143,6 @@ TheoryArrays::~TheoryArrays() {
StatisticsRegistry::unregisterStat(&d_numSetModelValSplits);
StatisticsRegistry::unregisterStat(&d_numSetModelValConflicts);
StatisticsRegistry::unregisterStat(&d_checkTimer);
-
}
void TheoryArrays::setMasterEqualityEngine(eq::EqualityEngine* eq) {
@@ -448,6 +455,7 @@ void TheoryArrays::preRegisterTermInternal(TNode node)
}
if (node.getType().isArray()) {
+ d_mayEqualEqualityEngine.addTerm(node);
d_equalityEngine.addTriggerTerm(node, THEORY_ARRAY);
}
else {
@@ -462,13 +470,37 @@ void TheoryArrays::preRegisterTermInternal(TNode node)
Assert(d_equalityEngine.getRepresentative(store) == store);
d_infoMap.addIndex(store, node[1]);
- d_reads.push_back(node);
+
+ // Synchronize d_constReadsContext with SAT context
+ Assert(d_constReadsContext->getLevel() <= getSatContext()->getLevel());
+ while (d_constReadsContext->getLevel() < getSatContext()->getLevel()) {
+ d_constReadsContext->push();
+ }
+
+ // Record read in sharing data structure
+ TNode index = d_equalityEngine.getRepresentative(node[1]);
+ if (index.isConst()) {
+ CTNodeList* temp;
+ CNodeNListMap::iterator it = d_constReads.find(index);
+ if (it == d_constReads.end()) {
+ temp = new(true) CTNodeList(d_constReadsContext);
+ d_constReads[index] = temp;
+ }
+ else {
+ temp = (*it).second;
+ }
+ temp->push_back(node);
+ d_constReadsList.push_back(node);
+ }
+ else {
+ d_reads.push_back(node);
+ }
+
Assert((d_isPreRegistered.insert(node), true));
checkRowForIndex(node[1], store);
break;
}
case kind::STORE: {
- // Invariant: array terms should be preregistered before being added to the equality engine
if (d_equalityEngine.hasTerm(node)) {
break;
}
@@ -476,7 +508,21 @@ void TheoryArrays::preRegisterTermInternal(TNode node)
TNode a = d_equalityEngine.getRepresentative(node[0]);
- d_mayEqualEqualityEngine.assertEquality(node.eqNode(a), true, d_true);
+ if (node.isConst()) {
+ // Can't use d_mayEqualEqualityEngine to merge node with a because they are both constants,
+ // so just set the default value manually for node.
+ Assert(a == node[0]);
+ d_mayEqualEqualityEngine.addTerm(node);
+ Assert(d_mayEqualEqualityEngine.getRepresentative(node) == node);
+ Assert(d_mayEqualEqualityEngine.getRepresentative(a) == a);
+ DefValMap::iterator it = d_defValues.find(a);
+ Assert(it != d_defValues.end());
+ d_defValues[node] = (*it).second;
+ }
+ else {
+ d_mayEqualEqualityEngine.assertEquality(node.eqNode(a), true, d_true);
+ Assert(d_mayEqualEqualityEngine.consistent());
+ }
if (!options::arraysLazyRIntro1()) {
TNode i = node[1];
@@ -499,11 +545,26 @@ void TheoryArrays::preRegisterTermInternal(TNode node)
break;
}
case kind::STORE_ALL: {
- throw LogicException("Array theory solver does not yet support assertions using constant array value");
+ if (d_equalityEngine.hasTerm(node)) {
+ break;
+ }
+ ArrayStoreAll storeAll = node.getConst<ArrayStoreAll>();
+ Node defaultValue = Node::fromExpr(storeAll.getExpr());
+ if (!defaultValue.isConst()) {
+ throw LogicException("Array theory solver does not yet support non-constant default values for arrays");
+ }
+ d_infoMap.setConstArr(node, node);
+ d_mayEqualEqualityEngine.addTerm(node);
+ Assert(d_mayEqualEqualityEngine.getRepresentative(node) == node);
+ d_equalityEngine.addTriggerTerm(node, THEORY_ARRAY);
+ d_defValues[node] = defaultValue;
+ break;
}
default:
// Variables etc
if (node.getType().isArray()) {
+ // The may equal needs the node
+ d_mayEqualEqualityEngine.addTerm(node);
d_equalityEngine.addTriggerTerm(node, THEORY_ARRAY);
Assert(d_equalityEngine.getSize(node) == 1);
}
@@ -566,12 +627,81 @@ EqualityStatus TheoryArrays::getEqualityStatus(TNode a, TNode b) {
// The terms are implied to be equal
return EQUALITY_TRUE;
}
- if (d_equalityEngine.areDisequal(a, b, false)) {
+ else if (d_equalityEngine.areDisequal(a, b, false)) {
// The terms are implied to be dis-equal
return EQUALITY_FALSE;
}
- //TODO: can we be more precise sometimes?
- return EQUALITY_UNKNOWN;
+ return EQUALITY_UNKNOWN;//FALSE_IN_MODEL;
+}
+
+
+void TheoryArrays::checkPair(TNode r1, TNode r2)
+{
+ Debug("arrays::sharing") << "TheoryArrays::computeCareGraph(): checking reads " << r1 << " and " << r2 << std::endl;
+
+ TNode x = r1[1];
+ TNode y = r2[1];
+ Assert(d_equalityEngine.isTriggerTerm(x, THEORY_ARRAY));
+
+ if (d_equalityEngine.hasTerm(x) && d_equalityEngine.hasTerm(y) &&
+ (d_equalityEngine.areEqual(x,y) || d_equalityEngine.areDisequal(x,y,false))) {
+ Debug("arrays::sharing") << "TheoryArrays::computeCareGraph(): equality known, skipping" << std::endl;
+ return;
+ }
+
+ // If the terms are already known to be equal, we are also in good shape
+ if (d_equalityEngine.areEqual(r1, r2)) {
+ Debug("arrays::sharing") << "TheoryArrays::computeCareGraph(): equal, skipping" << std::endl;
+ return;
+ }
+
+ if (r1[0] != r2[0]) {
+ // If arrays are known to be disequal, or cannot become equal, we can continue
+ Assert(d_mayEqualEqualityEngine.hasTerm(r1[0]) && d_mayEqualEqualityEngine.hasTerm(r2[0]));
+ if (r1[0].getType() != r2[0].getType() ||
+ d_equalityEngine.areDisequal(r1[0], r2[0], false)) {
+ Debug("arrays::sharing") << "TheoryArrays::computeCareGraph(): arrays can't be equal, skipping" << std::endl;
+ return;
+ }
+ else if (!d_mayEqualEqualityEngine.areEqual(r1[0], r2[0])) {
+ return;
+ }
+ }
+
+ if (!d_equalityEngine.isTriggerTerm(y, THEORY_ARRAY)) {
+ Debug("arrays::sharing") << "TheoryArrays::computeCareGraph(): not connected to shared terms, skipping" << std::endl;
+ return;
+ }
+
+ // Get representative trigger terms
+ TNode x_shared = d_equalityEngine.getTriggerTermRepresentative(x, THEORY_ARRAY);
+ TNode y_shared = d_equalityEngine.getTriggerTermRepresentative(y, THEORY_ARRAY);
+ EqualityStatus eqStatusDomain = d_valuation.getEqualityStatus(x_shared, y_shared);
+ switch (eqStatusDomain) {
+ case EQUALITY_TRUE_AND_PROPAGATED:
+ // Should have been propagated to us
+ Assert(false);
+ break;
+ case EQUALITY_TRUE:
+ // Missed propagation - need to add the pair so that theory engine can force propagation
+ Debug("arrays::sharing") << "TheoryArrays::computeCareGraph(): missed propagation" << std::endl;
+ break;
+ case EQUALITY_FALSE_AND_PROPAGATED:
+ // Should have been propagated to us
+ Assert(false);
+ case EQUALITY_FALSE:
+ case EQUALITY_FALSE_IN_MODEL:
+ // This is unlikely, but I think it could happen
+ Debug("arrays::sharing") << "TheoryArrays::computeCareGraph(): checkPair called when false in model" << std::endl;
+ return;
+ default:
+ // Covers EQUALITY_TRUE_IN_MODEL (common case) and EQUALITY_UNKNOWN
+ break;
+ }
+
+ // Add this pair
+ Debug("arrays::sharing") << "TheoryArrays::computeCareGraph(): adding to care-graph" << std::endl;
+ addCarePair(x_shared, y_shared);
}
@@ -601,92 +731,69 @@ void TheoryArrays::computeCareGraph()
}
if (d_sharedTerms) {
- vector< pair<TNode, TNode> > currentPairs;
+ // Synchronize d_constReadsContext with SAT context
+ Assert(d_constReadsContext->getLevel() <= getSatContext()->getLevel());
+ while (d_constReadsContext->getLevel() < getSatContext()->getLevel()) {
+ d_constReadsContext->push();
+ }
// Go through the read terms and see if there are any to split on
+
+ // Give constReadsContext a push so that all the work it does here is erased - models can change if context changes at all
+ // The context is popped at the end. If this loop is interrupted for some reason, we have to make sure the context still
+ // gets popped or the solver will be in an inconsistent state
+ d_constReadsContext->push();
unsigned size = d_reads.size();
for (unsigned i = 0; i < size; ++ i) {
TNode r1 = d_reads[i];
- // Make sure shared terms were identified correctly
- // Assert(theoryOf(r1[0]) == THEORY_ARRAY || isShared(r1[0]));
- // Assert(theoryOf(r1[1]) == THEORY_ARRAY ||
- // d_sharedOther.find(r1[1]) != d_sharedOther.end());
-
- for (unsigned j = i + 1; j < size; ++ j) {
- TNode r2 = d_reads[j];
+ Debug("arrays::sharing") << "TheoryArrays::computeCareGraph(): checking read " << r1 << std::endl;
+ Assert(d_equalityEngine.hasTerm(r1));
+ TNode x = r1[1];
- Debug("arrays::sharing") << "TheoryArrays::computeCareGraph(): checking reads " << r1 << " and " << r2 << std::endl;
+ if (!d_equalityEngine.isTriggerTerm(x, THEORY_ARRAY)) {
+ Debug("arrays::sharing") << "TheoryArrays::computeCareGraph(): not connected to shared terms, skipping" << std::endl;
+ continue;
+ }
+ Node x_shared = d_equalityEngine.getTriggerTermRepresentative(x, THEORY_ARRAY);
- // If the terms are already known to be equal, we are also in good shape
- if (d_equalityEngine.hasTerm(r1) && d_equalityEngine.hasTerm(r2) && d_equalityEngine.areEqual(r1, r2)) {
- Debug("arrays::sharing") << "TheoryArrays::computeCareGraph(): equal, skipping" << std::endl;
- continue;
+ // Get the model value of index and find all reads that read from that same model value: these are the pairs we have to check
+ // Also, insert this read in the list at the proper index
+
+ if (!x_shared.isConst()) {
+ x_shared = d_valuation.getModelValue(x_shared);
+ }
+ if (!x_shared.isNull()) {
+ CTNodeList* temp;
+ CNodeNListMap::iterator it = d_constReads.find(x_shared);
+ if (it == d_constReads.end()) {
+ // This is the only x_shared with this model value - no need to create any splits
+ temp = new(true) CTNodeList(d_constReadsContext);
+ d_constReads[x_shared] = temp;
}
-
- if (r1[0] != r2[0]) {
- // If arrays are known to be disequal, or cannot become equal, we can continue
- Assert(d_mayEqualEqualityEngine.hasTerm(r1[0]) && d_mayEqualEqualityEngine.hasTerm(r2[0]));
- if (r1[0].getType() != r2[0].getType() ||
- d_equalityEngine.areDisequal(r1[0], r2[0], false)) {
- Debug("arrays::sharing") << "TheoryArrays::computeCareGraph(): arrays can't be equal, skipping" << std::endl;
- continue;
- }
- else if (!d_mayEqualEqualityEngine.areEqual(r1[0], r2[0])) {
- if (r2.getType().getCardinality().isInfinite()) {
- continue;
- }
- // TODO: add a disequality split for these two arrays
- continue;
+ else {
+ temp = (*it).second;
+ for (size_t j = 0; j < temp->size(); ++j) {
+ checkPair(r1, (*temp)[j]);
}
}
-
- TNode x = r1[1];
- TNode y = r2[1];
-
- if (!d_equalityEngine.isTriggerTerm(x, THEORY_ARRAY) || !d_equalityEngine.isTriggerTerm(y, THEORY_ARRAY)) {
- Debug("arrays::sharing") << "TheoryArrays::computeCareGraph(): not connected to shared terms, skipping" << std::endl;
- continue;
- }
-
- EqualityStatus eqStatus = getEqualityStatus(x, y);
-
- if (eqStatus != EQUALITY_UNKNOWN) {
- Debug("arrays::sharing") << "TheoryArrays::computeCareGraph(): equality status known, skipping" << std::endl;
- continue;
+ temp->push_back(r1);
+ }
+ else {
+ // We don't know the model value for x. Just do brute force examination of all pairs of reads
+ for (unsigned j = 0; j < size; ++j) {
+ TNode r2 = d_reads[j];
+ Assert(d_equalityEngine.hasTerm(r2));
+ checkPair(r1,r2);
}
-
- // Get representative trigger terms
- TNode x_shared = d_equalityEngine.getTriggerTermRepresentative(x, THEORY_ARRAY);
- TNode y_shared = d_equalityEngine.getTriggerTermRepresentative(y, THEORY_ARRAY);
- EqualityStatus eqStatusDomain = d_valuation.getEqualityStatus(x_shared, y_shared);
- switch (eqStatusDomain) {
- case EQUALITY_TRUE_AND_PROPAGATED:
- // Should have been propagated to us
- Assert(false);
- break;
- case EQUALITY_FALSE_AND_PROPAGATED:
- // Should have been propagated to us
- Assert(false);
- break;
- case EQUALITY_FALSE:
- case EQUALITY_TRUE:
- // Missed propagation - need to add the pair so that theory engine can force propagation
- Debug("arrays::sharing") << "TheoryArrays::computeCareGraph(): missed propagation" << std::endl;
- break;
- case EQUALITY_FALSE_IN_MODEL:
- Debug("arrays::sharing") << "TheoryArrays::computeCareGraph(): false in model" << std::endl;
- break;
- default:
- break;
+ for (unsigned j = 0; j < d_constReadsList.size(); ++j) {
+ TNode r2 = d_constReadsList[j];
+ Assert(d_equalityEngine.hasTerm(r2));
+ checkPair(r1,r2);
}
-
-
- // Otherwise, add this pair
- Debug("arrays::sharing") << "TheoryArrays::computeCareGraph(): adding to care-graph" << std::endl;
- addCarePair(x_shared, y_shared);
}
}
+ d_constReadsContext->pop();
}
}
@@ -811,10 +918,22 @@ void TheoryArrays::collectModelInfo( TheoryModel* m, bool fullModel )
}
Node rep;
- map<Node, Node> defValues;
- map<Node, Node>::iterator it;
+ DefValMap::iterator it;
TypeSet defaultValuesSet;
+ // Compute all default values already in use
+ if (fullModel) {
+ for (size_t i=0; i<arrays.size(); ++i) {
+ TNode nrep = d_equalityEngine.getRepresentative(arrays[i]);
+ d_mayEqualEqualityEngine.addTerm(nrep); // add the term in case it isn't there already
+ TNode mayRep = d_mayEqualEqualityEngine.getRepresentative(nrep);
+ it = d_defValues.find(mayRep);
+ if (it != d_defValues.end()) {
+ defaultValuesSet.add(nrep.getType().getArrayConstituentType(), (*it).second);
+ }
+ }
+ }
+
// Loop through all array equivalence classes that need a representative computed
for (size_t i=0; i<arrays.size(); ++i) {
TNode n = arrays[i];
@@ -822,11 +941,10 @@ void TheoryArrays::collectModelInfo( TheoryModel* m, bool fullModel )
if (fullModel) {
// Compute default value for this array - there is one default value for every mayEqual equivalence class
- d_mayEqualEqualityEngine.addTerm(nrep); // add the term in case it isn't there already
TNode mayRep = d_mayEqualEqualityEngine.getRepresentative(nrep);
- it = defValues.find(mayRep);
+ it = d_defValues.find(mayRep);
// If this mayEqual EC doesn't have a default value associated, get the next available default value for the associated array element type
- if (it == defValues.end()) {
+ if (it == d_defValues.end()) {
TypeNode valueType = nrep.getType().getArrayConstituentType();
rep = defaultValuesSet.nextTypeEnum(valueType);
if (rep.isNull()) {
@@ -834,7 +952,7 @@ void TheoryArrays::collectModelInfo( TheoryModel* m, bool fullModel )
rep = *(defaultValuesSet.getSet(valueType)->begin());
}
Trace("arrays-models") << "New default value = " << rep << endl;
- defValues[mayRep] = rep;
+ d_defValues[mayRep] = rep;
}
else {
rep = (*it).second;
@@ -860,7 +978,9 @@ void TheoryArrays::collectModelInfo( TheoryModel* m, bool fullModel )
rep = nm->mkNode(kind::STORE, rep, reads[j][1], reads[j]);
}
m->assertEquality(n, rep, true);
- m->assertRepresentative(rep);
+ if (!n.isConst()) {
+ m->assertRepresentative(rep);
+ }
}
}
@@ -992,7 +1112,11 @@ void TheoryArrays::check(Effort e) {
if(!options::arraysEagerLemmas() && fullEffort(e) && !d_conflict && !options::arraysModelBased()) {
// generate the lemmas on the worklist
Trace("arrays-lem")<<"Arrays::discharging lemmas: "<<d_RowQueue.size()<<"\n";
- dischargeLemmas();
+ while (d_RowQueue.size() > 0 && !d_conflict) {
+ if (dischargeLemmas()) {
+ break;
+ }
+ }
}
Trace("arrays") << spaces(getSatContext()->getLevel()) << "Arrays::check(): done" << endl;
@@ -2036,7 +2160,43 @@ void TheoryArrays::mergeArrays(TNode a, TNode b)
}
}
+ TNode constArrA = d_infoMap.getConstArr(a);
+ TNode constArrB = d_infoMap.getConstArr(b);
+ if (constArrA.isNull()) {
+ if (!constArrB.isNull()) {
+ d_infoMap.setConstArr(a,constArrB);
+ }
+ }
+ else if (!constArrB.isNull()) {
+ if (constArrA != constArrB) {
+ conflict(constArrA,constArrB);
+ }
+ }
+
+ // If a and b have different default values associated with their mayequal equivalence classes,
+ // things get complicated - disallow this for now. -Clark
+ TNode mayRepA = d_mayEqualEqualityEngine.getRepresentative(a);
+ TNode mayRepB = d_mayEqualEqualityEngine.getRepresentative(b);
+
+ DefValMap::iterator it = d_defValues.find(mayRepA);
+ DefValMap::iterator it2 = d_defValues.find(mayRepB);
+ TNode defValue;
+
+ if (it != d_defValues.end()) {
+ defValue = (*it).second;
+ if (it2 != d_defValues.end() && (defValue != (*it2).second)) {
+ throw LogicException("Array theory solver does not yet support write-chains connecting two different constant arrays");
+ }
+ }
+ else if (it2 != d_defValues.end()) {
+ defValue = (*it2).second;
+ }
d_mayEqualEqualityEngine.assertEquality(a.eqNode(b), true, d_true);
+ Assert(d_mayEqualEqualityEngine.consistent());
+ if (!defValue.isNull()) {
+ mayRepA = d_mayEqualEqualityEngine.getRepresentative(a);
+ d_defValues[mayRepA] = defValue;
+ }
checkRowLemmas(a,b);
checkRowLemmas(b,a);
@@ -2168,6 +2328,17 @@ void TheoryArrays::checkRowForIndex(TNode i, TNode a)
Assert(a.getType().isArray());
Assert(d_equalityEngine.getRepresentative(a) == a);
+ TNode constArr = d_infoMap.getConstArr(a);
+ if (!constArr.isNull()) {
+ ArrayStoreAll storeAll = constArr.getConst<ArrayStoreAll>();
+ Node defValue = Node::fromExpr(storeAll.getExpr());
+ Node selConst = NodeManager::currentNM()->mkNode(kind::SELECT, constArr, i);
+ if (!d_equalityEngine.hasTerm(selConst)) {
+ preRegisterTermInternal(selConst);
+ }
+ d_equalityEngine.assertEquality(selConst.eqNode(defValue), true, d_true);
+ }
+
const CTNodeList* stores = d_infoMap.getStores(a);
const CTNodeList* instores = d_infoMap.getInStores(a);
size_t it = 0;
@@ -2211,15 +2382,25 @@ void TheoryArrays::checkRowLemmas(TNode a, TNode b)
d_infoMap.getInfo(b)->print();
const CTNodeList* i_a = d_infoMap.getIndices(a);
+ size_t it = 0;
+ TNode constArr = d_infoMap.getConstArr(b);
+ if (!constArr.isNull()) {
+ for( ; it < i_a->size(); ++it) {
+ TNode i = (*i_a)[it];
+ Node selConst = NodeManager::currentNM()->mkNode(kind::SELECT, constArr, i);
+ if (!d_equalityEngine.hasTerm(selConst)) {
+ preRegisterTermInternal(selConst);
+ }
+ }
+ }
+
const CTNodeList* st_b = d_infoMap.getStores(b);
const CTNodeList* inst_b = d_infoMap.getInStores(b);
-
- size_t it = 0;
size_t its;
RowLemmaType lem;
- for( ; it < i_a->size(); ++it) {
+ for(it = 0 ; it < i_a->size(); ++it) {
TNode i = (*i_a)[it];
its = 0;
for ( ; its < st_b->size(); ++its) {
@@ -2277,8 +2458,9 @@ void TheoryArrays::queueRowLemma(RowLemmaType lem)
bool bothExist = ajExists && bjExists;
// If propagating, check propagations
- if (d_propagateLemmas) {
- if (d_equalityEngine.areDisequal(i,j,true)) {
+ int prop = options::arraysPropagate();
+ if (prop > 0) {
+ if (d_equalityEngine.areDisequal(i,j,true) && (bothExist || prop > 1)) {
Trace("arrays-lem") << spaces(getSatContext()->getLevel()) <<"Arrays::queueRowLemma: propagating aj = bj ("<<aj<<", "<<bj<<")\n";
Node aj_eq_bj = aj.eqNode(bj);
Node i_eq_j = i.eqNode(j);
@@ -2395,8 +2577,9 @@ Node TheoryArrays::getNextDecisionRequest() {
}
-void TheoryArrays::dischargeLemmas()
+bool TheoryArrays::dischargeLemmas()
{
+ bool lemmasAdded = false;
size_t sz = d_RowQueue.size();
for (unsigned count = 0; count < sz; ++count) {
RowLemmaType l = d_RowQueue.front();
@@ -2477,7 +2660,12 @@ void TheoryArrays::dischargeLemmas()
d_RowAlreadyAdded.insert(l);
d_out->lemma(lem);
++d_numRow;
+ lemmasAdded = true;
+ if (options::arraysReduceSharing()) {
+ return true;
+ }
}
+ return lemmasAdded;
}
void TheoryArrays::conflict(TNode a, TNode b) {
diff --git a/src/theory/arrays/theory_arrays.h b/src/theory/arrays/theory_arrays.h
index 9e9d3c890..371b00b0c 100644
--- a/src/theory/arrays/theory_arrays.h
+++ b/src/theory/arrays/theory_arrays.h
@@ -215,6 +215,9 @@ class TheoryArrays : public Theory {
/** Equaltity engine for determining if two arrays might be equal */
eq::EqualityEngine d_mayEqualEqualityEngine;
+ // Helper for computeCareGraph
+ void checkPair(TNode r1, TNode r2);
+
public:
void addSharedTerm(TNode t);
@@ -347,7 +350,35 @@ class TheoryArrays : public Theory {
CDNodeSet d_sharedArrays;
CDNodeSet d_sharedOther;
context::CDO<bool> d_sharedTerms;
+
+ // Map from constant values to read terms that read from that values equal to that constant value in the current model
+ // When a new read term is created, we check the index to see if we know the model value. If so, we add it to d_constReads (and d_constReadsList)
+ // If not, we push it onto d_reads and figure out where it goes at computeCareGraph time.
+ // d_constReadsList is used as a backup in case we can't compute the model at computeCareGraph time.
+ typedef std::hash_map<Node, CTNodeList*, NodeHashFunction> CNodeNListMap;
+ CNodeNListMap d_constReads;
context::CDList<TNode> d_reads;
+ context::CDList<TNode> d_constReadsList;
+ context::Context* d_constReadsContext;
+ /** Helper class to keep d_constReadsContext in sync with satContext */
+ class ContextPopper : public context::ContextNotifyObj {
+ context::Context* d_satContext;
+ context::Context* d_contextToPop;
+ protected:
+ void contextNotifyPop() {
+ if (d_contextToPop->getLevel() > d_satContext->getLevel()) {
+ d_contextToPop->pop();
+ }
+ }
+ public:
+ ContextPopper(context::Context* context, context::Context* contextToPop)
+ :context::ContextNotifyObj(context), d_satContext(context),
+ d_contextToPop(contextToPop)
+ {}
+
+ };/* class ContextPopper */
+ ContextPopper d_contextPopper;
+
std::hash_map<Node, Node, NodeHashFunction> d_skolemCache;
context::CDO<unsigned> d_skolemIndex;
std::vector<Node> d_skolemAssertions;
@@ -361,6 +392,10 @@ class TheoryArrays : public Theory {
context::CDHashSet<Node, NodeHashFunction > d_lemmasSaved;
std::vector<Node> d_lemmas;
+ // Default values for each mayEqual equivalence class
+ typedef context::CDHashMap<Node,Node,NodeHashFunction> DefValMap;
+ DefValMap d_defValues;
+
Node getSkolem(TNode ref, const std::string& name, const TypeNode& type, const std::string& comment, bool makeEqual = true);
Node mkAnd(std::vector<TNode>& conjunctions, bool invert = false, unsigned startIndex = 0);
void setNonLinear(TNode a);
@@ -372,7 +407,7 @@ class TheoryArrays : public Theory {
void checkRowForIndex(TNode i, TNode a);
void checkRowLemmas(TNode a, TNode b);
void queueRowLemma(RowLemmaType lem);
- void dischargeLemmas();
+ bool dischargeLemmas();
std::vector<Node> d_decisions;
bool d_inCheckModel;
diff --git a/src/theory/booleans/circuit_propagator.h b/src/theory/booleans/circuit_propagator.h
index 7dbef4041..169ac6fa7 100644
--- a/src/theory/booleans/circuit_propagator.h
+++ b/src/theory/booleans/circuit_propagator.h
@@ -144,7 +144,7 @@ private:
}
}
- // Get the current assignement
+ // Get the current assignment
AssignmentStatus state = d_state[n];
if(state != UNASSIGNED) {
diff --git a/src/theory/booleans/theory_bool_type_rules.h b/src/theory/booleans/theory_bool_type_rules.h
index d2836c85e..9d12e1bb1 100644
--- a/src/theory/booleans/theory_bool_type_rules.h
+++ b/src/theory/booleans/theory_bool_type_rules.h
@@ -42,10 +42,10 @@ public:
}
return booleanType;
}
-};
+};/* class BooleanTypeRule */
class IteTypeRule {
- public:
+public:
inline static TypeNode computeType(NodeManager* nodeManager, TNode n, bool check)
throw (TypeCheckingExceptionPrivate, AssertionException) {
TypeNode thenType = n[1].getType(check);
@@ -57,15 +57,21 @@ class IteTypeRule {
throw TypeCheckingExceptionPrivate(n, "condition of ITE is not Boolean");
}
if (iteType.isNull()) {
- throw TypeCheckingExceptionPrivate(n, "both branches of the ITE must be a subtype of a common type.");
+ std::stringstream ss;
+ ss << "Both branches of the ITE must be a subtype of a common type." << std::endl
+ << "then branch: " << n[1] << std::endl
+ << "its type : " << thenType << std::endl
+ << "else branch: " << n[2] << std::endl
+ << "its type : " << elseType << std::endl;
+ throw TypeCheckingExceptionPrivate(n, ss.str());
}
}
return iteType;
}
-};
+};/* class IteTypeRule */
-}/* namespace CVC4::theory::boolean */
-}/* namespace CVC4::theory */
-}/* namespace CVC4 */
+}/* CVC4::theory::boolean namespace */
+}/* CVC4::theory namespace */
+}/* CVC4 namespace */
#endif /* __CVC4__THEORY_BOOL_TYPE_RULES_H */
diff --git a/src/theory/builtin/kinds b/src/theory/builtin/kinds
index 508106106..44474c18a 100644
--- a/src/theory/builtin/kinds
+++ b/src/theory/builtin/kinds
@@ -302,9 +302,6 @@ operator SEXPR 0: "a symbolic expression (any arity)"
operator LAMBDA 2 "a lambda expression; first parameter is a BOUND_VAR_LIST, second is lambda body"
-## for co-datatypes, not yet supported
-# operator MU 2 "mu"
-
parameterized CHAIN CHAIN_OP 2: "chained operator (N-ary), turned into a conjuction of binary applications of the operator on adjoining parameters; first parameter is a CHAIN_OP representing a binary operator, rest are arguments to that operator"
constant CHAIN_OP \
::CVC4::Chain \
@@ -336,7 +333,6 @@ 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 MU ::CVC4::theory::builtin::MuTypeRule
typerule CHAIN ::CVC4::theory::builtin::ChainTypeRule
typerule CHAIN_OP ::CVC4::theory::builtin::ChainedOperatorTypeRule
diff --git a/src/theory/builtin/theory_builtin_type_rules.h b/src/theory/builtin/theory_builtin_type_rules.h
index 045f440e6..977a097d0 100644
--- a/src/theory/builtin/theory_builtin_type_rules.h
+++ b/src/theory/builtin/theory_builtin_type_rules.h
@@ -164,27 +164,6 @@ public:
}
};/* class LambdaTypeRule */
-/* For co-datatypes, not yet supported--
-**
-class MuTypeRule {
-public:
- inline static TypeNode computeType(NodeManager* nodeManager, TNode n, bool check) {
- if( n[0].getType(check) != nodeManager->boundVarListType() ) {
- std::stringstream ss;
- ss << "expected a bound var list for MU expression, got `"
- << n[0].getType().toString() << "'";
- throw TypeCheckingExceptionPrivate(n, ss.str());
- }
- std::vector<TypeNode> argTypes;
- for(TNode::iterator i = n[0].begin(); i != n[0].end(); ++i) {
- argTypes.push_back((*i).getType());
- }
- TypeNode rangeType = n[1].getType(check);
- return nodeManager->mkFunctionType(argTypes, rangeType);
- }
-};
-**/
-
class ChainTypeRule {
public:
inline static TypeNode computeType(NodeManager* nodeManager, TNode n, bool check) {
diff --git a/src/theory/bv/aig_bitblaster.cpp b/src/theory/bv/aig_bitblaster.cpp
index ce775874f..6270995ef 100644
--- a/src/theory/bv/aig_bitblaster.cpp
+++ b/src/theory/bv/aig_bitblaster.cpp
@@ -402,7 +402,7 @@ void AigBitblaster::assertToSatSolver(Cnf_Dat_t* pCnf) {
prop::SatLiteral lit(sat_variables[index-1], int_lit < 0);
clause.push_back(lit);
}
- d_satSolver->addClause(clause, false);
+ d_satSolver->addClause(clause, false, RULE_INVALID);
}
}
diff --git a/src/theory/bv/bitblaster_template.h b/src/theory/bv/bitblaster_template.h
index ecd7013c7..ea31e3821 100644
--- a/src/theory/bv/bitblaster_template.h
+++ b/src/theory/bv/bitblaster_template.h
@@ -74,19 +74,22 @@ protected:
typedef std::vector<T> Bits;
typedef __gnu_cxx::hash_map <Node, Bits, NodeHashFunction> TermDefMap;
typedef __gnu_cxx::hash_set<TNode, TNodeHashFunction> TNodeSet;
+ typedef __gnu_cxx::hash_map<Node, Node, NodeHashFunction> ModelCache;
typedef void (*TermBBStrategy) (TNode, Bits&, TBitblaster<T>*);
typedef T (*AtomBBStrategy) (TNode, TBitblaster<T>*);
// caches and mappings
- TermDefMap d_termCache;
-
+ TermDefMap d_termCache;
+ ModelCache d_modelCache;
+
void initAtomBBStrategies();
void initTermBBStrategies();
protected:
/// function tables for the various bitblasting strategies indexed by node kind
TermBBStrategy d_termBBStrategies[kind::LAST_KIND];
AtomBBStrategy d_atomBBStrategies[kind::LAST_KIND];
+ virtual Node getModelFromSatSolver(TNode node, bool fullModel) = 0;
public:
TBitblaster();
virtual ~TBitblaster() {}
@@ -97,9 +100,18 @@ public:
virtual bool hasBBAtom(TNode atom) const = 0;
virtual void storeBBAtom(TNode atom, T atom_bb) = 0;
+
bool hasBBTerm(TNode node) const;
void getBBTerm(TNode node, Bits& bits) const;
- void storeBBTerm(TNode term, const Bits& bits);
+ void storeBBTerm(TNode term, const Bits& bits);
+ /**
+ * Return a constant representing the value of a in the model.
+ * If fullModel is true set unconstrained bits to 0. If not return
+ * NullNode() for a fully or partially unconstrained.
+ *
+ */
+ Node getTermModel(TNode node, bool fullModel);
+ void invalidateModelCache();
};
@@ -109,7 +121,6 @@ class TLazyBitblaster : public TBitblaster<Node> {
typedef std::vector<Node> Bits;
typedef context::CDList<prop::SatLiteral> AssertionList;
typedef context::CDHashMap<prop::SatLiteral, std::vector<prop::SatLiteral> , prop::SatLiteralHashFunction> ExplanationMap;
-
/** This class gets callbacks from minisat on propagations */
class MinisatNotify : public prop::BVSatSolverInterface::Notify {
prop::CnfStream* d_cnf;
@@ -143,9 +154,12 @@ class TLazyBitblaster : public TBitblaster<Node> {
TNodeSet d_bbAtoms;
AbstractionModule* d_abstraction;
bool d_emptyNotify;
+
+ context::CDO<bool> d_satSolverFullModel;
void addAtom(TNode atom);
bool hasValue(TNode a);
+ Node getModelFromSatSolver(TNode a, bool fullModel);
public:
void bbTerm(TNode node, Bits& bits);
void bbAtom(TNode node);
@@ -172,14 +186,7 @@ public:
void setAbstraction(AbstractionModule* abs);
theory::EqualityStatus getEqualityStatus(TNode a, TNode b);
- /**
- * Return a constant Node representing the value of a variable
- * in the current model.
- * @param a
- *
- * @return
- */
- Node getVarValue(TNode a, bool fullModel=true);
+
/**
* Adds a constant value for each bit-blasted variable in the model.
*
@@ -245,7 +252,7 @@ class EagerBitblaster : public TBitblaster<Node> {
TNodeSet d_bbAtoms;
TNodeSet d_variables;
- Node getVarValue(TNode a, bool fullModel);
+ Node getModelFromSatSolver(TNode a, bool fullModel);
bool isSharedTerm(TNode node);
public:
@@ -299,7 +306,7 @@ class AigBitblaster : public TBitblaster<Abc_Obj_t*> {
bool hasInput(TNode input);
void convertToCnfAndAssert();
void assertToSatSolver(Cnf_Dat_t* pCnf);
-
+ Node getModelFromSatSolver(TNode a, bool fullModel) { Unreachable(); }
public:
AigBitblaster();
~AigBitblaster();
@@ -387,6 +394,7 @@ template <class T> void TBitblaster<T>::initTermBBStrategies() {
template <class T>
TBitblaster<T>::TBitblaster()
: d_termCache()
+ , d_modelCache()
{
initAtomBBStrategies();
initTermBBStrategies();
@@ -407,6 +415,53 @@ void TBitblaster<T>::storeBBTerm(TNode node, const Bits& bits) {
d_termCache.insert(std::make_pair(node, bits));
}
+template <class T>
+void TBitblaster<T>::invalidateModelCache() {
+ d_modelCache.clear();
+}
+
+template <class T>
+Node TBitblaster<T>::getTermModel(TNode node, bool fullModel) {
+ if (d_modelCache.find(node) != d_modelCache.end())
+ return d_modelCache[node];
+
+ if (node.isConst())
+ return node;
+
+ Node value = getModelFromSatSolver(node, false);
+ if (!value.isNull()) {
+ Debug("bv-equality-status")<< "TLazyBitblaster::getTermModel from SatSolver" << node <<" => " << value <<"\n";
+ d_modelCache[node] = value;
+ Assert (value.isConst());
+ return value;
+ }
+
+ if (Theory::isLeafOf(node, theory::THEORY_BV)) {
+ // if it is a leaf may ask for fullModel
+ value = getModelFromSatSolver(node, fullModel);
+ Debug("bv-equality-status")<< "TLazyBitblaster::getTermModel from VarValue" << node <<" => " << value <<"\n";
+ Assert (!value.isNull());
+ d_modelCache[node] = value;
+ return value;
+ }
+ Assert (node.getType().isBitVector());
+
+ NodeBuilder<> nb(node.getKind());
+ if (node.getMetaKind() == kind::metakind::PARAMETERIZED) {
+ nb << node.getOperator();
+ }
+
+ for (unsigned i = 0; i < node.getNumChildren(); ++i) {
+ nb << getTermModel(node[i], fullModel);
+ }
+ value = nb;
+ value = Rewriter::rewrite(value);
+ Assert (value.isConst());
+ d_modelCache[node] = value;
+ Debug("bv-term-model")<< "TLazyBitblaster::getTermModel Building Value" << node <<" => " << value <<"\n";
+ return value;
+}
+
} /* bv namespace */
diff --git a/src/theory/bv/bv_quick_check.cpp b/src/theory/bv/bv_quick_check.cpp
index 5f35f95e3..cc294306a 100644
--- a/src/theory/bv/bv_quick_check.cpp
+++ b/src/theory/bv/bv_quick_check.cpp
@@ -115,7 +115,7 @@ BVQuickCheck::vars_iterator BVQuickCheck::endVars() {
}
Node BVQuickCheck::getVarValue(TNode var) {
- return d_bitblaster->getVarValue(var);
+ return d_bitblaster->getTermModel(var, true);
}
@@ -141,6 +141,7 @@ void BVQuickCheck::collectModelInfo(theory::TheoryModel* model, bool fullModel)
BVQuickCheck::~BVQuickCheck() {
delete d_bitblaster;
+ delete d_ctx;
}
QuickXPlain::QuickXPlain(const std::string& name, BVQuickCheck* solver, unsigned long budget)
diff --git a/src/theory/bv/bv_subtheory_bitblast.cpp b/src/theory/bv/bv_subtheory_bitblast.cpp
index a2a6e19ac..d0b99f869 100644
--- a/src/theory/bv/bv_subtheory_bitblast.cpp
+++ b/src/theory/bv/bv_subtheory_bitblast.cpp
@@ -103,6 +103,7 @@ void BitblastSolver::bitblastQueue() {
// don't bit-blast lemma atoms
continue;
}
+ Debug("bitblast-queue") << "Bitblasting atom " << atom <<"\n";
d_bitblaster->bbAtom(atom);
}
}
@@ -218,48 +219,49 @@ void BitblastSolver::collectModelInfo(TheoryModel* m, bool fullModel) {
Node BitblastSolver::getModelValue(TNode node)
{
- if (!d_validModelCache) {
- d_modelCache.clear();
- d_validModelCache = true;
+ if (d_bv->d_invalidateModelCache.get()) {
+ d_bitblaster->invalidateModelCache();
}
- return getModelValueRec(node);
-}
-
-Node BitblastSolver::getModelValueRec(TNode node)
-{
- Node val;
- if (node.isConst()) {
- return node;
- }
- NodeMap::iterator it = d_modelCache.find(node);
- if (it != d_modelCache.end()) {
- val = (*it).second;
- Debug("bitvector-model") << node << " => (cached) " << val <<"\n";
- return val;
- }
- if (d_bv->isLeaf(node)) {
- val = d_bitblaster->getVarValue(node);
- if (val == Node()) {
- // If no value in model, just set to 0
- val = utils::mkConst(utils::getSize(node), (unsigned)0);
- }
- } else {
- NodeBuilder<> valBuilder(node.getKind());
- if (node.getMetaKind() == kind::metakind::PARAMETERIZED) {
- valBuilder << node.getOperator();
- }
- for (unsigned i = 0; i < node.getNumChildren(); ++i) {
- valBuilder << getModelValueRec(node[i]);
- }
- val = valBuilder;
- val = Rewriter::rewrite(val);
- }
- Assert(val.isConst());
- d_modelCache[node] = val;
- Debug("bitvector-model") << node << " => " << val <<"\n";
+ d_bv->d_invalidateModelCache.set(false);
+ Node val = d_bitblaster->getTermModel(node, true);
return val;
}
+// Node BitblastSolver::getModelValueRec(TNode node)
+// {
+// Node val;
+// if (node.isConst()) {
+// return node;
+// }
+// NodeMap::iterator it = d_modelCache.find(node);
+// if (it != d_modelCache.end()) {
+// val = (*it).second;
+// Debug("bitvector-model") << node << " => (cached) " << val <<"\n";
+// return val;
+// }
+// if (d_bv->isLeaf(node)) {
+// val = d_bitblaster->getVarValue(node);
+// if (val == Node()) {
+// // If no value in model, just set to 0
+// val = utils::mkConst(utils::getSize(node), (unsigned)0);
+// }
+// } else {
+// NodeBuilder<> valBuilder(node.getKind());
+// if (node.getMetaKind() == kind::metakind::PARAMETERIZED) {
+// valBuilder << node.getOperator();
+// }
+// for (unsigned i = 0; i < node.getNumChildren(); ++i) {
+// valBuilder << getModelValueRec(node[i]);
+// }
+// val = valBuilder;
+// val = Rewriter::rewrite(val);
+// }
+// Assert(val.isConst());
+// d_modelCache[node] = val;
+// Debug("bitvector-model") << node << " => " << val <<"\n";
+// return val;
+// }
+
void BitblastSolver::setConflict(TNode conflict) {
Node final_conflict = conflict;
diff --git a/src/theory/bv/bv_subtheory_bitblast.h b/src/theory/bv/bv_subtheory_bitblast.h
index 414abdcce..77461163c 100644
--- a/src/theory/bv/bv_subtheory_bitblast.h
+++ b/src/theory/bv/bv_subtheory_bitblast.h
@@ -57,7 +57,7 @@ class BitblastSolver : public SubtheorySolver {
AbstractionModule* d_abstractionModule;
BVQuickCheck* d_quickCheck;
QuickXPlain* d_quickXplain;
- Node getModelValueRec(TNode node);
+ // Node getModelValueRec(TNode node);
void setConflict(TNode conflict);
public:
BitblastSolver(context::Context* c, TheoryBV* bv);
diff --git a/src/theory/bv/eager_bitblaster.cpp b/src/theory/bv/eager_bitblaster.cpp
index e8fee00f5..877baec4e 100644
--- a/src/theory/bv/eager_bitblaster.cpp
+++ b/src/theory/bv/eager_bitblaster.cpp
@@ -56,7 +56,7 @@ EagerBitblaster::~EagerBitblaster() {
}
void EagerBitblaster::bbFormula(TNode node) {
- d_cnfStream->convertAndAssert(node, false, false);
+ d_cnfStream->convertAndAssert(node, false, false, RULE_INVALID, TNode::null());
}
/**
@@ -85,7 +85,7 @@ void EagerBitblaster::bbAtom(TNode node) {
AlwaysAssert (options::bitblastMode() == theory::bv::BITBLAST_MODE_EAGER);
storeBBAtom(node, atom_definition);
- d_cnfStream->convertAndAssert(atom_definition, false, false);
+ d_cnfStream->convertAndAssert(atom_definition, false, false, RULE_INVALID, TNode::null());
}
void EagerBitblaster::storeBBAtom(TNode atom, Node atom_bb) {
@@ -156,11 +156,11 @@ bool EagerBitblaster::solve() {
*
* @return
*/
-Node EagerBitblaster::getVarValue(TNode a, bool fullModel) {
+Node EagerBitblaster::getModelFromSatSolver(TNode a, bool fullModel) {
if (!hasBBTerm(a)) {
- Assert(isSharedTerm(a));
- return Node();
+ return fullModel? utils::mkConst(utils::getSize(a), 0u) : Node();
}
+
Bits bits;
getBBTerm(a, bits);
Integer value(0);
@@ -171,7 +171,8 @@ Node EagerBitblaster::getVarValue(TNode a, bool fullModel) {
bit_value = d_satSolver->value(bit);
Assert (bit_value != prop::SAT_VALUE_UNKNOWN);
} else {
- // the bit is unconstrainted so we can give it an arbitrary value
+ if (!fullModel) return Node();
+ // unconstrained bits default to false
bit_value = prop::SAT_VALUE_FALSE;
}
Integer bit_int = bit_value == prop::SAT_VALUE_TRUE ? Integer(1) : Integer(0);
@@ -182,19 +183,17 @@ Node EagerBitblaster::getVarValue(TNode a, bool fullModel) {
void EagerBitblaster::collectModelInfo(TheoryModel* m, bool fullModel) {
- TNodeSet::const_iterator it = d_variables.begin();
+ TNodeSet::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, fullModel);
- if(const_value == Node()) {
- if( fullModel ){
- // if the value is unassigned just set it to zero
- const_value = utils::mkConst(BitVector(utils::getSize(var), 0u));
- }
- }
+ if (d_bv->isLeaf(var) || isSharedTerm(var)) {
+ // only shared terms could not have been bit-blasted
+ Assert (hasBBTerm(var) || isSharedTerm(var));
+
+ Node const_value = getModelFromSatSolver(var, fullModel);
+
if(const_value != Node()) {
- Debug("bitvector-model") << "TLazyBitblaster::collectModelInfo (assert (= "
+ Debug("bitvector-model") << "EagerBitblaster::collectModelInfo (assert (= "
<< var << " "
<< const_value << "))\n";
m->assertEquality(var, const_value, true);
diff --git a/src/theory/bv/lazy_bitblaster.cpp b/src/theory/bv/lazy_bitblaster.cpp
index f721a22f0..f8927284f 100644
--- a/src/theory/bv/lazy_bitblaster.cpp
+++ b/src/theory/bv/lazy_bitblaster.cpp
@@ -41,6 +41,7 @@ TLazyBitblaster::TLazyBitblaster(context::Context* c, bv::TheoryBV* bv, const st
, d_bbAtoms()
, d_abstraction(NULL)
, d_emptyNotify(emptyNotify)
+ , d_satSolverFullModel(c, false)
, d_name(name)
, d_statistics(name) {
d_satSolver = prop::SatSolverFactory::createMinisat(c, name);
@@ -113,7 +114,7 @@ void TLazyBitblaster::bbAtom(TNode node) {
Assert (!atom_bb.isNull());
Node atom_definition = utils::mkNode(kind::IFF, node, atom_bb);
storeBBAtom(node, atom_bb);
- d_cnfStream->convertAndAssert(atom_definition, false, false);
+ d_cnfStream->convertAndAssert(atom_definition, false, false, RULE_INVALID, TNode::null());
return;
}
@@ -125,7 +126,7 @@ void TLazyBitblaster::bbAtom(TNode node) {
// asserting that the atom is true iff the definition holds
Node atom_definition = utils::mkNode(kind::IFF, node, atom_bb);
storeBBAtom(node, atom_bb);
- d_cnfStream->convertAndAssert(atom_definition, false, false);
+ d_cnfStream->convertAndAssert(atom_definition, false, false, RULE_INVALID, TNode::null());
}
void TLazyBitblaster::storeBBAtom(TNode atom, Node atom_bb) {
@@ -258,6 +259,7 @@ bool TLazyBitblaster::solve() {
}
}
Debug("bitvector") << "TLazyBitblaster::solve() asserted atoms " << d_assertedAtoms->size() <<"\n";
+ d_satSolverFullModel.set(true);
return prop::SAT_VALUE_TRUE == d_satSolver->solve();
}
@@ -354,42 +356,38 @@ void TLazyBitblaster::MinisatNotify::safePoint() {
d_bv->d_out->safePoint();
}
+
EqualityStatus TLazyBitblaster::getEqualityStatus(TNode a, TNode b) {
+ Debug("bv-equality-status")<< "TLazyBitblaster::getEqualityStatus " << a <<" = " << b <<"\n";
+ Debug("bv-equality-status")<< "BVSatSolver has full model? " << d_satSolverFullModel.get() <<"\n";
- // We don't want to bit-blast every possibly expensive term for the sake of equality checking
- if (hasBBTerm(a) && hasBBTerm(b)) {
-
- Bits a_bits, b_bits;
- getBBTerm(a, a_bits);
- getBBTerm(b, b_bits);
- theory::EqualityStatus status = theory::EQUALITY_TRUE_IN_MODEL;
- for (unsigned i = 0; i < a_bits.size(); ++ i) {
- if (d_cnfStream->hasLiteral(a_bits[i]) && d_cnfStream->hasLiteral(b_bits[i])) {
- prop::SatLiteral a_lit = d_cnfStream->getLiteral(a_bits[i]);
- prop::SatValue a_lit_value = d_satSolver->value(a_lit);
- if (a_lit_value != prop::SAT_VALUE_UNKNOWN) {
- prop::SatLiteral b_lit = d_cnfStream->getLiteral(b_bits[i]);
- prop::SatValue b_lit_value = d_satSolver->value(b_lit);
- if (b_lit_value != prop::SAT_VALUE_UNKNOWN) {
- if (a_lit_value != b_lit_value) {
- return theory::EQUALITY_FALSE_IN_MODEL;
- }
- } else {
- status = theory::EQUALITY_UNKNOWN;
- }
- } {
- status = theory::EQUALITY_UNKNOWN;
- }
- } else {
- status = theory::EQUALITY_UNKNOWN;
- }
- }
+ // First check if it trivially rewrites to false/true
+ Node a_eq_b = Rewriter::rewrite(utils::mkNode(kind::EQUAL, a, b));
- return status;
+ if (a_eq_b == utils::mkFalse()) return theory::EQUALITY_FALSE;
+ if (a_eq_b == utils::mkTrue()) return theory::EQUALITY_TRUE;
- } else {
- return theory::EQUALITY_UNKNOWN;
+ if (!d_satSolverFullModel.get())
+ return theory::EQUALITY_UNKNOWN;
+
+ // Check if cache is valid (invalidated in check and pops)
+ if (d_bv->d_invalidateModelCache.get()) {
+ invalidateModelCache();
}
+ d_bv->d_invalidateModelCache.set(false);
+
+ Node a_value = getTermModel(a, true);
+ Node b_value = getTermModel(b, true);
+
+ Assert (a_value.isConst() &&
+ b_value.isConst());
+
+ if (a_value == b_value) {
+ Debug("bv-equality-status")<< "theory::EQUALITY_TRUE_IN_MODEL\n";
+ return theory::EQUALITY_TRUE_IN_MODEL;
+ }
+ Debug("bv-equality-status")<< "theory::EQUALITY_FALSE_IN_MODEL\n";
+ return theory::EQUALITY_FALSE_IN_MODEL;
}
@@ -424,11 +422,11 @@ bool TLazyBitblaster::hasValue(TNode a) {
*
* @return
*/
-Node TLazyBitblaster::getVarValue(TNode a, bool fullModel) {
+Node TLazyBitblaster::getModelFromSatSolver(TNode a, bool fullModel) {
if (!hasBBTerm(a)) {
- Assert(isSharedTerm(a));
- return Node();
+ return fullModel? utils::mkConst(utils::getSize(a), 0u) : Node();
}
+
Bits bits;
getBBTerm(a, bits);
Integer value(0);
@@ -439,7 +437,8 @@ Node TLazyBitblaster::getVarValue(TNode a, bool fullModel) {
bit_value = d_satSolver->value(bit);
Assert (bit_value != prop::SAT_VALUE_UNKNOWN);
} else {
- // the bit is unconstrainted so we can give it an arbitrary value
+ if (!fullModel) return Node();
+ // unconstrained bits default to false
bit_value = prop::SAT_VALUE_FALSE;
}
Integer bit_int = bit_value == prop::SAT_VALUE_TRUE ? Integer(1) : Integer(0);
@@ -449,23 +448,26 @@ Node TLazyBitblaster::getVarValue(TNode a, bool fullModel) {
}
void TLazyBitblaster::collectModelInfo(TheoryModel* m, bool fullModel) {
- TNodeSet::iterator it = d_variables.begin();
- for (; it!= d_variables.end(); ++it) {
+ std::set<Node> termSet;
+ d_bv->computeRelevantTerms(termSet);
+
+ for (std::set<Node>::const_iterator it = termSet.begin(); it != termSet.end(); ++it) {
TNode var = *it;
- if (Theory::theoryOf(var) == theory::THEORY_BV || isSharedTerm(var)) {
- Node const_value = getVarValue(var, fullModel);
- if(const_value == Node()) {
- 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") << "TLazyBitblaster::collectModelInfo (assert (= "
- << var << " "
- << const_value << "))\n";
+ // not actually a leaf of the bit-vector theory
+ if (d_variables.find(var) == d_variables.end())
+ continue;
+
+ Assert (Theory::theoryOf(var) == theory::THEORY_BV || isSharedTerm(var));
+ // only shared terms could not have been bit-blasted
+ Assert (hasBBTerm(var) || isSharedTerm(var));
+
+ Node const_value = getModelFromSatSolver(var, fullModel);
+ Assert (const_value.isNull() || const_value.isConst());
+ if(const_value != Node()) {
+ Debug("bitvector-model") << "TLazyBitblaster::collectModelInfo (assert (= "
+ << var << " "
+ << const_value << "))\n";
m->assertEquality(var, const_value, true);
- }
}
}
}
@@ -481,7 +483,7 @@ void TLazyBitblaster::clearSolver() {
d_bbAtoms.clear();
d_variables.clear();
d_termCache.clear();
-
+
// recreate sat solver
d_satSolver = prop::SatSolverFactory::createMinisat(d_ctx);
d_cnfStream = new prop::TseitinCnfStream(d_satSolver,
diff --git a/src/theory/bv/theory_bv.cpp b/src/theory/bv/theory_bv.cpp
index 4abf25bb1..91150f663 100644
--- a/src/theory/bv/theory_bv.cpp
+++ b/src/theory/bv/theory_bv.cpp
@@ -49,6 +49,7 @@ TheoryBV::TheoryBV(context::Context* c, context::UserContext* u, OutputChannel&
d_staticLearnCache(),
d_lemmasAdded(c, false),
d_conflict(c, false),
+ d_invalidateModelCache(c, true),
d_literalsToPropagate(c),
d_literalsToPropagateIndex(c, 0),
d_propagatedBy(c),
@@ -356,8 +357,12 @@ void TheoryBV::checkForLemma(TNode fact) {
void TheoryBV::check(Effort e)
{
+ if (done() && !fullEffort(e)) {
+ return;
+ }
Debug("bitvector") << "TheoryBV::check(" << e << ")" << std::endl;
-
+ // we may be getting new assertions so the model cache may not be sound
+ d_invalidateModelCache.set(true);
// if we are using the eager solver
if (options::bitblastMode() == theory::bv::BITBLAST_MODE_EAGER) {
// this can only happen on an empty benchmark
diff --git a/src/theory/bv/theory_bv.h b/src/theory/bv/theory_bv.h
index 22d9f6775..a37a4019e 100644
--- a/src/theory/bv/theory_bv.h
+++ b/src/theory/bv/theory_bv.h
@@ -141,6 +141,9 @@ private:
// Are we in conflict?
context::CDO<bool> d_conflict;
+ // Invalidate the model cache if check was called
+ context::CDO<bool> d_invalidateModelCache;
+
/** The conflict node */
Node d_conflictNode;
diff --git a/src/theory/bv/theory_bv_rewrite_rules.h b/src/theory/bv/theory_bv_rewrite_rules.h
index bc9095f03..3cc1c323c 100644
--- a/src/theory/bv/theory_bv_rewrite_rules.h
+++ b/src/theory/bv/theory_bv_rewrite_rules.h
@@ -152,6 +152,7 @@ enum RewriteRuleId {
NotOr, // not sure why this would help (not done)
NotXor, // not sure why this would help (not done)
FlattenAssocCommut,
+ FlattenAssocCommutNoDuplicates,
PlusCombineLikeTerms,
MultSimplify,
MultDistribConst,
@@ -270,7 +271,8 @@ inline std::ostream& operator << (std::ostream& out, RewriteRuleId ruleId) {
case SignExtendEliminate : out << "SignExtendEliminate"; return out;
case NotIdemp : out << "NotIdemp"; return out;
case UleSelf: out << "UleSelf"; return out;
- case FlattenAssocCommut: out << "FlattenAssocCommut"; return out;
+ case FlattenAssocCommut: out << "FlattenAssocCommut"; return out;
+ case FlattenAssocCommutNoDuplicates: out << "FlattenAssocCommutNoDuplicates"; return out;
case PlusCombineLikeTerms: out << "PlusCombineLikeTerms"; return out;
case MultSimplify: out << "MultSimplify"; return out;
case MultDistribConst: out << "MultDistribConst"; return out;
@@ -485,8 +487,9 @@ struct AllRewriteRules {
RewriteRule<SubEliminate> rule82;
RewriteRule<XorOne> rule83;
RewriteRule<XorZero> rule84;
- RewriteRule<MultPow2> rule87;
RewriteRule<MultSlice> rule85;
+ RewriteRule<FlattenAssocCommutNoDuplicates> rule86;
+ RewriteRule<MultPow2> rule87;
RewriteRule<ExtractMultLeadingBit> rule88;
RewriteRule<NegIdemp> rule91;
RewriteRule<UdivPow2> rule92;
diff --git a/src/theory/bv/theory_bv_rewrite_rules_normalization.h b/src/theory/bv/theory_bv_rewrite_rules_normalization.h
index 21b59fa8c..bc1b92dce 100644
--- a/src/theory/bv/theory_bv_rewrite_rules_normalization.h
+++ b/src/theory/bv/theory_bv_rewrite_rules_normalization.h
@@ -996,6 +996,51 @@ Node RewriteRule<AndSimplify>::apply(TNode node) {
}
template<> inline
+bool RewriteRule<FlattenAssocCommutNoDuplicates>::applies(TNode node) {
+ Kind kind = node.getKind();
+ if (kind != kind::BITVECTOR_OR &&
+ kind != kind::BITVECTOR_AND)
+ return false;
+ TNode::iterator child_it = node.begin();
+ for(; child_it != node.end(); ++child_it) {
+ if ((*child_it).getKind() == kind) {
+ return true;
+ }
+ }
+ return false;
+}
+
+template<> inline
+Node RewriteRule<FlattenAssocCommutNoDuplicates>::apply(TNode node) {
+ Debug("bv-rewrite") << "RewriteRule<FlattenAssocCommut>(" << node << ")" << std::endl;
+ std::vector<Node> processingStack;
+ processingStack.push_back(node);
+ __gnu_cxx::hash_set<TNode, TNodeHashFunction> processed;
+ std::vector<Node> children;
+ Kind kind = node.getKind();
+
+ while (! processingStack.empty()) {
+ TNode current = processingStack.back();
+ processingStack.pop_back();
+ if (processed.count(current))
+ continue;
+
+ processed.insert(current);
+
+ // flatten expression
+ if (current.getKind() == kind) {
+ for (unsigned i = 0; i < current.getNumChildren(); ++i) {
+ processingStack.push_back(current[i]);
+ }
+ } else {
+ children.push_back(current);
+ }
+ }
+ return utils::mkSortedNode(kind, children);
+}
+
+
+template<> inline
bool RewriteRule<OrSimplify>::applies(TNode node) {
return (node.getKind() == kind::BITVECTOR_OR);
}
diff --git a/src/theory/bv/theory_bv_rewriter.cpp b/src/theory/bv/theory_bv_rewriter.cpp
index 306a3bd97..dc91c338b 100644
--- a/src/theory/bv/theory_bv_rewriter.cpp
+++ b/src/theory/bv/theory_bv_rewriter.cpp
@@ -214,7 +214,7 @@ RewriteResponse TheoryBVRewriter::RewriteConcat(TNode node, bool prerewrite) {
RewriteResponse TheoryBVRewriter::RewriteAnd(TNode node, bool prerewrite) {
Node resultNode = node;
resultNode = LinearRewriteStrategy
- < RewriteRule<FlattenAssocCommut>,
+ < RewriteRule<FlattenAssocCommutNoDuplicates>,
RewriteRule<AndSimplify>
>::apply(node);
@@ -234,7 +234,7 @@ RewriteResponse TheoryBVRewriter::RewriteAnd(TNode node, bool prerewrite) {
RewriteResponse TheoryBVRewriter::RewriteOr(TNode node, bool prerewrite){
Node resultNode = node;
resultNode = LinearRewriteStrategy
- < RewriteRule<FlattenAssocCommut>,
+ < RewriteRule<FlattenAssocCommutNoDuplicates>,
RewriteRule<OrSimplify>
>::apply(node);
diff --git a/src/theory/datatypes/datatypes_rewriter.h b/src/theory/datatypes/datatypes_rewriter.h
index 37e64ca88..0bbb97076 100644
--- a/src/theory/datatypes/datatypes_rewriter.h
+++ b/src/theory/datatypes/datatypes_rewriter.h
@@ -159,6 +159,23 @@ public:
return RewriteResponse(REWRITE_DONE,gt );
}
}
+ if(in.getKind() == kind::DT_SIZE && in[0].getKind()==kind::APPLY_CONSTRUCTOR ){
+ std::vector< Node > children;
+ for( unsigned i=0; i<in[0].getNumChildren(); i++ ){
+ if( in[0][i].getType().isDatatype() ){
+ children.push_back( NodeManager::currentNM()->mkNode( kind::DT_SIZE, in[0][i] ) );
+ }
+ }
+ Node res;
+ if( !children.empty() ){
+ children.push_back( NodeManager::currentNM()->mkConst( Rational(1) ) );
+ res = children.size()==1 ? children[0] : NodeManager::currentNM()->mkNode( kind::PLUS, children );
+ }else{
+ res = NodeManager::currentNM()->mkConst( Rational(0) );
+ }
+ Trace("datatypes-rewrite") << "DatatypesRewriter::postRewrite: rewrite " << in << " to " << res << std::endl;
+ return RewriteResponse(REWRITE_AGAIN_FULL, res );
+ }
if(in.getKind() == kind::TUPLE_SELECT &&
in[0].getKind() == kind::TUPLE) {
return RewriteResponse(REWRITE_DONE, in[0][in.getOperator().getConst<TupleSelect>().getIndex()]);
@@ -243,7 +260,7 @@ public:
}
}else if( n1!=n2 ){
if( n1.isConst() && n2.isConst() ){
- return true;
+ return true;
}else{
Node eq = NodeManager::currentNM()->mkNode( n1.getType().isBoolean() ? kind::IFF : kind::EQUAL, n1, n2 );
rew.push_back( eq );
@@ -252,7 +269,7 @@ public:
return false;
}
/** get instantiate cons */
- static Node getInstCons( Node n, const Datatype& dt, int index, bool mkVar = false ) {
+ static Node getInstCons( Node n, const Datatype& dt, int index ) {
Type tspec;
if( dt.isParametric() ){
tspec = dt[index].getSpecializedConstructorType(n.getType().toType());
@@ -261,13 +278,6 @@ public:
children.push_back( Node::fromExpr( dt[index].getConstructor() ) );
for( int i=0; i<(int)dt[index].getNumArgs(); i++ ){
Node nc = NodeManager::currentNM()->mkNode( kind::APPLY_SELECTOR_TOTAL, Node::fromExpr( dt[index][i].getSelector() ), n );
- if( mkVar ){
- TypeNode tn = nc.getType();
- if( dt.isParametric() ){
- tn = TypeNode::fromType( tspec )[i];
- }
- nc = NodeManager::currentNM()->mkSkolem( "m", tn, "created for inst cons" );
- }
children.push_back( nc );
}
Node n_ic = NodeManager::currentNM()->mkNode( kind::APPLY_CONSTRUCTOR, children );
@@ -302,6 +312,29 @@ public:
}
return false;
}
+ static Node mkTester( Node n, int i, const Datatype& dt ){
+ //Node ret = n.eqNode( DatatypesRewriter::getInstCons( n, dt, i ) );
+ //Assert( isTester( ret )==i );
+ Node ret = NodeManager::currentNM()->mkNode( kind::APPLY_TESTER, Node::fromExpr( dt[i].getTester() ), n );
+ return ret;
+ }
+ static bool isNullaryApplyConstructor( Node n ){
+ Assert( n.getKind()==kind::APPLY_CONSTRUCTOR );
+ for( unsigned i=0; i<n.getNumChildren(); i++ ){
+ if( n[i].getType().isDatatype() ){
+ return false;
+ }
+ }
+ return true;
+ }
+ static bool isNullaryConstructor( const DatatypeConstructor& c ){
+ for( unsigned j=0; j<c.getNumArgs(); j++ ){
+ if( c[j].getType().getRangeType().isDatatype() ){
+ return false;
+ }
+ }
+ return true;
+ }
/** is this term a datatype */
static bool isTermDatatype( TNode n ){
diff --git a/src/theory/datatypes/kinds b/src/theory/datatypes/kinds
index d8b42111c..8c25e2a86 100644
--- a/src/theory/datatypes/kinds
+++ b/src/theory/datatypes/kinds
@@ -89,6 +89,12 @@ 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
+## for co-datatypes
+operator MU 2 "a mu operator, first argument is a bound variable, second argument is body"
+typerule MU ::CVC4::theory::datatypes::DatatypeMuTypeRule
+# mu applications are constant expressions
+construle MU ::CVC4::theory::datatypes::DatatypeMuTypeRule
+
operator TUPLE_TYPE 0: "tuple type"
cardinality TUPLE_TYPE \
"::CVC4::theory::datatypes::TupleProperties::computeCardinality(%TYPE%)" \
@@ -157,4 +163,8 @@ constant RECORD_UPDATE_OP \
parameterized RECORD_UPDATE RECORD_UPDATE_OP 2 "record update; first parameter is a RECORD_UPDATE_OP (which references a field), second is a record term to update, third is the element to store in the record in the given field"
typerule RECORD_UPDATE ::CVC4::theory::datatypes::RecordUpdateTypeRule
+
+operator DT_SIZE 1 "datatypes size"
+typerule DT_SIZE ::CVC4::theory::datatypes::DtSizeTypeRule
+
endtheory
diff --git a/src/theory/datatypes/options b/src/theory/datatypes/options
index 5fc59b549..bc7552862 100644
--- a/src/theory/datatypes/options
+++ b/src/theory/datatypes/options
@@ -13,5 +13,9 @@ expert-option dtRewriteErrorSel --dt-rewrite-error-sel bool :default false
rewrite incorrectly applied selectors to arbitrary ground term
option dtForceAssignment --dt-force-assignment bool :default false :read-write
force the datatypes solver to give specific values to all datatypes terms before answering sat
+option dtBinarySplit --dt-binary-split bool :default false
+ do binary splits for datatype constructor types
+option cdtBisimilar --cdt-bisimilar bool :default true
+ do bisimilarity check for co-datatypes
endmodule
diff --git a/src/theory/datatypes/theory_datatypes.cpp b/src/theory/datatypes/theory_datatypes.cpp
index 544589306..72d0c6b2b 100644
--- a/src/theory/datatypes/theory_datatypes.cpp
+++ b/src/theory/datatypes/theory_datatypes.cpp
@@ -58,10 +58,12 @@ TheoryDatatypes::TheoryDatatypes(Context* c, UserContext* u, OutputChannel& out,
// The kinds we are treating as function application in congruence
d_equalityEngine.addFunctionKind(kind::APPLY_CONSTRUCTOR);
d_equalityEngine.addFunctionKind(kind::APPLY_SELECTOR_TOTAL);
+ d_equalityEngine.addFunctionKind(kind::DT_SIZE);
d_equalityEngine.addFunctionKind(kind::APPLY_TESTER);
- d_equalityEngine.addFunctionKind(kind::APPLY_UF);
+ //d_equalityEngine.addFunctionKind(kind::APPLY_UF);
d_true = NodeManager::currentNM()->mkConst( true );
+ d_dtfCounter = 0;
}
TheoryDatatypes::~TheoryDatatypes() {
@@ -118,6 +120,10 @@ TNode TheoryDatatypes::getEqcConstructor( TNode r ) {
}
void TheoryDatatypes::check(Effort e) {
+ if (done() && !fullEffort(e)) {
+ return;
+ }
+
Trace("datatypes-debug") << "Check effort " << e << std::endl;
while(!done() && !d_conflict) {
// Get all the assertions
@@ -142,7 +148,7 @@ void TheoryDatatypes::check(Effort e) {
flushPendingFacts();
}
- if( e == EFFORT_FULL ) {
+ if( e == EFFORT_FULL && !d_conflict && !d_valuation.needCheck() ) {
//check for cycles
bool addedFact;
do {
@@ -164,9 +170,9 @@ void TheoryDatatypes::check(Effort e) {
TypeNode tn = n.getType();
if( DatatypesRewriter::isTypeDatatype( tn ) ){
Trace("datatypes-debug") << "Process equivalence class " << n << std::endl;
- EqcInfo* eqc = getOrMakeEqcInfo( n, true );
+ EqcInfo* eqc = getOrMakeEqcInfo( n );
//if there are more than 1 possible constructors for eqc
- if( eqc->d_constructor.get().isNull() && !hasLabel( eqc, n ) ) {
+ if( !hasLabel( eqc, n ) ){
Trace("datatypes-debug") << "No constructor..." << std::endl;
const Datatype& dt = ((DatatypeType)(tn).toType()).getDatatype();
@@ -185,42 +191,57 @@ void TheoryDatatypes::check(Effort e) {
if( consIndex==-1 ){
consIndex = j;
}
- if( !dt[ j ].isFinite() && !eqc->d_selectors ) {
+ if( !dt[ j ].isFinite() && ( !eqc || !eqc->d_selectors ) ) {
needSplit = false;
}
}
}
- /*
- if( !needSplit && mustSpecifyAssignment() ){
+ //d_dtfCounter++;
+ if( !needSplit && options::dtForceAssignment() && d_dtfCounter%2==0 ){
//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( !n.getType().isRecord() ){ //FIXME
+ Node groundTerm = n.getType().mkGroundTerm();
+ if( groundTerm.getOperator().getType().isConstructor() ){ //FIXME
+ int index = Datatype::indexOf( groundTerm.getOperator().toExpr() );
+ if( pcons[index] ){
+ consIndex = index;
+ }
+ needSplit = true;
+ }
}
- needSplit = true;
}
- */
+
if( needSplit && consIndex!=-1 ) {
//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 );
+ Node t = DatatypesRewriter::mkTester( n, 0, dt );
d_pending.push_back( t );
d_pending_exp[ t ] = d_true;
Trace("datatypes-infer") << "DtInfer : 1-cons : " << t << std::endl;
d_infer.push_back( t );
}else{
- 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;
+ if( options::dtBinarySplit() ){
+ Node test = DatatypesRewriter::mkTester( n, consIndex, dt );
+ 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") << "*************Split for constructors on " << n << endl;
+ std::vector< Node > children;
+ for( unsigned i=0; i<dt.getNumConstructors(); i++ ){
+ Node test = DatatypesRewriter::mkTester( n, i, dt );
+ children.push_back( test );
+ }
+ Node lemma = NodeManager::currentNM()->mkNode( kind::OR, children );
+ d_out->lemma( lemma );
+ }
+ return;
}
}else{
Trace("dt-split-debug") << "Do not split constructor for " << n << " : " << n.getType() << " " << dt.getNumConstructors() << std::endl;
@@ -277,7 +298,7 @@ void TheoryDatatypes::flushPendingFacts(){
Trace("dt-lemma-debug") << "Get explanation..." << std::endl;
Node ee_exp = explain( exp );
Trace("dt-lemma-debug") << "Explanation : " << ee_exp << std::endl;
- lem = NodeManager::currentNM()->mkNode( IMPLIES, ee_exp, fact );
+ lem = NodeManager::currentNM()->mkNode( OR, ee_exp.negate(), fact );
lem = Rewriter::rewrite( lem );
}
Trace("dt-lemma") << "Datatypes lemma : " << lem << std::endl;
@@ -511,11 +532,11 @@ Node TheoryDatatypes::ppRewrite(TNode in) {
void TheoryDatatypes::addSharedTerm(TNode t) {
Debug("datatypes") << "TheoryDatatypes::addSharedTerm(): "
<< t << " " << t.getType().isBoolean() << endl;
- if( t.getType().isBoolean() ){
+ //if( t.getType().isBoolean() ){
//d_equalityEngine.addTriggerPredicate(t, THEORY_DATATYPES);
- }else{
- d_equalityEngine.addTriggerTerm(t, THEORY_DATATYPES);
- }
+ //}else{
+ d_equalityEngine.addTriggerTerm(t, THEORY_DATATYPES);
+ //}
Debug("datatypes") << "TheoryDatatypes::addSharedTerm() finished" << std::endl;
}
@@ -570,7 +591,12 @@ void TheoryDatatypes::explain(TNode literal, std::vector<TNode>& assumptions){
TNode atom = polarity ? literal : literal[0];
if (atom.getKind() == kind::EQUAL || atom.getKind() == kind::IFF) {
explainEquality( atom[0], atom[1], polarity, assumptions );
+ } else if( atom.getKind() == kind::AND && polarity ){
+ for( unsigned i=0; i<atom.getNumChildren(); i++ ){
+ explain( atom[i], assumptions );
+ }
} else {
+ Assert( atom.getKind()!=kind::AND );
explainPredicate( atom, polarity, assumptions );
}
}
@@ -670,7 +696,7 @@ void TheoryDatatypes::merge( Node t1, Node t2 ){
for( unsigned i=0; i<deq_cand.size(); i++ ){
if( d_equalityEngine.areDisequal( deq_cand[i].first, deq_cand[i].second, true ) ){
conf = true;
- Node eq = NodeManager::currentNM()->mkNode( deq_cand[i].first.getType().isBoolean() ? kind::IFF : kind::EQUAL,
+ Node eq = NodeManager::currentNM()->mkNode( deq_cand[i].first.getType().isBoolean() ? kind::IFF : kind::EQUAL,
deq_cand[i].first, deq_cand[i].second );
exp.push_back( eq.negate() );
}
@@ -806,7 +832,7 @@ d_inst( c, false ), d_constructor( c, Node::null() ), d_selectors( c, false ){
}
bool TheoryDatatypes::hasLabel( EqcInfo* eqc, Node n ){
- return !eqc->d_constructor.get().isNull() || !getLabel( n ).isNull();
+ return ( eqc && !eqc->d_constructor.get().isNull() ) || !getLabel( n ).isNull();
}
Node TheoryDatatypes::getLabel( Node n ) {
@@ -821,13 +847,22 @@ Node TheoryDatatypes::getLabel( Node n ) {
}
int TheoryDatatypes::getLabelIndex( EqcInfo* eqc, Node n ){
- if( !eqc->d_constructor.get().isNull() ){
+ if( eqc && !eqc->d_constructor.get().isNull() ){
return Datatype::indexOf( eqc->d_constructor.get().getOperator().toExpr() );
}else{
return Datatype::indexOf( getLabel( n ).getOperator().toExpr() );
}
}
+bool TheoryDatatypes::hasTester( Node n ) {
+ NodeListMap::iterator lbl_i = d_labels.find( n );
+ if( lbl_i != d_labels.end() ){
+ return !(*(*lbl_i).second).empty();
+ }else{
+ return false;
+ }
+}
+
void TheoryDatatypes::getPossibleCons( EqcInfo* eqc, Node n, std::vector< bool >& pcons ){
const Datatype& dt = ((DatatypeType)(n.getType()).toType()).getDatatype();
pcons.resize( dt.getNumConstructors(), !hasLabel( eqc, n ) );
@@ -928,7 +963,7 @@ void TheoryDatatypes::addTester( Node t, EqcInfo* eqc, Node n ){
}
}
}
- Node t_concl = NodeManager::currentNM()->mkNode( APPLY_TESTER, Node::fromExpr( dt[unsigned(testerIndex)].getTester() ), tt[0] );
+ Node t_concl = DatatypesRewriter::mkTester( tt[0], testerIndex, dt );
Node t_concl_exp = ( nb.getNumChildren() == 1 ) ? nb.getChild( 0 ) : nb;
d_pending.push_back( t_concl );
d_pending_exp[ t_concl ] = t_concl_exp;
@@ -1013,40 +1048,70 @@ void TheoryDatatypes::addConstructor( Node c, EqcInfo* eqc, Node n ){
}
void TheoryDatatypes::collapseSelector( Node s, Node c ) {
- Node r = NodeManager::currentNM()->mkNode( kind::APPLY_SELECTOR_TOTAL, s.getOperator(), c );
+ Node r;
+ if( s.getKind()==kind::APPLY_SELECTOR_TOTAL ){
+ r = NodeManager::currentNM()->mkNode( kind::APPLY_SELECTOR_TOTAL, s.getOperator(), c );
+ }else if( s.getKind()==kind::DT_SIZE ){
+ r = NodeManager::currentNM()->mkNode( kind::DT_SIZE, c );
+ }
Node rr = Rewriter::rewrite( r );
- //if( r!=rr ){
- //Node eq_exp = NodeManager::currentNM()->mkConst(true);
- //Node eq = r.getType().isBoolean() ? r.iffNode( rr ) : r.eqNode( rr );
- if( s!=rr ){::
+ if( s!=rr ){
Node eq_exp = c.eqNode( s[0] );
Node eq = rr.getType().isBoolean() ? s.iffNode( rr ) : s.eqNode( rr );
-
+ Trace("datatypes-infer") << "DtInfer : collapse sel : " << eq << " by " << eq_exp << std::endl;
d_pending.push_back( eq );
d_pending_exp[ eq ] = eq_exp;
- Trace("datatypes-infer") << "DtInfer : collapse sel : " << eq << " by " << eq_exp << std::endl;
d_infer.push_back( eq );
d_infer_exp.push_back( eq_exp );
}
}
EqualityStatus TheoryDatatypes::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;
- }
+ Assert(d_equalityEngine.hasTerm(a) && d_equalityEngine.hasTerm(b));
+ if (d_equalityEngine.areEqual(a, b)) {
+ // The terms are implied to be equal
+ return EQUALITY_TRUE;
}
- return EQUALITY_UNKNOWN;
+ if (d_equalityEngine.areDisequal(a, b, false)) {
+ // The terms are implied to be dis-equal
+ return EQUALITY_FALSE;
+ }
+ return EQUALITY_FALSE_IN_MODEL;
}
void TheoryDatatypes::computeCareGraph(){
Trace("dt-cg") << "Compute graph for dt..." << std::endl;
+ /*
+ Trace("dt-cg") << "Look at shared terms..." << std::endl;
+ for (unsigned i = 0; i < d_sharedTerms.size(); ++ i) {
+ TNode a = d_sharedTerms[i];
+ if( a.getKind()!=APPLY_CONSTRUCTOR && a.getKind()!=APPLY_SELECTOR_TOTAL ){
+ TypeNode aType = a.getType();
+ for (unsigned j = i + 1; j < d_sharedTerms.size(); ++ j) {
+ TNode b = d_sharedTerms[j];
+ if( b.getKind()!=APPLY_CONSTRUCTOR && b.getKind()!=APPLY_SELECTOR_TOTAL ){
+ if (b.getType() != aType) {
+ // We don't care about the terms of different types
+ continue;
+ }
+ switch (d_valuation.getEqualityStatus(a, b)) {
+ case EQUALITY_TRUE_AND_PROPAGATED:
+ case EQUALITY_FALSE_AND_PROPAGATED:
+ // If we know about it, we should have propagated it, so we can skip
+ break;
+ default:
+ // Let's split on it
+ addCarePair(a, b);
+ break;
+ }
+ }
+ }
+ }
+ }
+ */
+
+ Trace("dt-cg") << "Look at theory terms..." << std::endl;
vector< pair<TNode, TNode> > currentPairs;
for( unsigned r=0; r<2; r++ ){
unsigned functionTerms = r==0 ? d_consTerms.size() : d_selTerms.size();
@@ -1061,30 +1126,19 @@ void TheoryDatatypes::computeCareGraph(){
for (unsigned k = 0; k < f1.getNumChildren(); ++ k) {
TNode x = f1[k];
TNode y = f2[k];
+ Assert(d_equalityEngine.hasTerm(x));
+ Assert(d_equalityEngine.hasTerm(y));
if( areDisequal(x, y) ){
somePairIsDisequal = true;
break;
- }else if( !areEqual( x, y ) ){
+ }else if( !d_equalityEngine.areEqual( x, y ) ){
Trace("dt-cg") << "Arg #" << k << " is " << x << " " << y << std::endl;
- //check if they are definately disequal
- bool defDiseq = false;
-/*
- TNode rx = getRepresentative( x );
- EqcInfo* eix = getOrMakeEqcInfo( rx, false );
- if( eix ){
- TNode ry = getRepresentative( y );
- EqcInfo* eiy = getOrMakeEqcInfo( ry, false );
- if( eiy ){
- if( !eix->d_constructor.get().isNull() && !eiy->d_constructor.get().isNull() ){
- defDiseq = eix->d_constructor.get().getOperator()!=eiy->d_constructor.get().getOperator();
- }else{
- }
- }
- }
-*/
- if( !defDiseq && d_equalityEngine.isTriggerTerm(x, THEORY_UF) && d_equalityEngine.isTriggerTerm(y, THEORY_UF) ){
+ if( d_equalityEngine.isTriggerTerm(x, THEORY_DATATYPES) && d_equalityEngine.isTriggerTerm(y, THEORY_DATATYPES) ){
EqualityStatus eqStatus = d_valuation.getEqualityStatus(x, y);
- if( eqStatus!=EQUALITY_UNKNOWN ){
+ if( eqStatus==EQUALITY_FALSE_AND_PROPAGATED || eqStatus==EQUALITY_FALSE || eqStatus==EQUALITY_FALSE_IN_MODEL ){
+ somePairIsDisequal = true;
+ break;
+ }else{
TNode x_shared = d_equalityEngine.getTriggerTermRepresentative(x, THEORY_DATATYPES);
TNode y_shared = d_equalityEngine.getTriggerTermRepresentative(y, THEORY_DATATYPES);
Trace("dt-cg") << "Arg #" << k << " shared term is " << x_shared << " " << y_shared << std::endl;
@@ -1112,43 +1166,9 @@ void TheoryDatatypes::collectModelInfo( TheoryModel* m, bool fullModel ){
printModelDebug( "dt-model" );
Trace("dt-model") << std::endl;
- /*
- bool eq_merged = false;
- std::vector< Node > all_eqc;
- eq::EqClassesIterator eqcs1_i = eq::EqClassesIterator( &d_equalityEngine );
- while( !eqcs1_i.isFinished() ){
- Node eqc = (*eqcs1_i);
- all_eqc.push_back( eqc );
- ++eqcs1_i;
- }
- //check if equivalence classes have merged
- for( unsigned i=0; i<all_eqc.size(); i++ ){
- for( unsigned j=(i+1); j<all_eqc.size(); j++ ){
- if( m->areEqual( all_eqc[i], all_eqc[j] ) ){
- Trace("dt-cmi") << "Pre-already forced equal : " << all_eqc[i] << " = " << all_eqc[j] << std::endl;
- eq_merged = true;
- }
- }
- }
- Assert( !eq_merged );
- */
-
//combine the equality engine
m->assertEqualityEngine( &d_equalityEngine );
- /*
- //check again if equivalence classes have merged
- for( unsigned i=0; i<all_eqc.size(); i++ ){
- for( unsigned j=(i+1); j<all_eqc.size(); j++ ){
- if( m->areEqual( all_eqc[i], all_eqc[j] ) ){
- Trace("dt-cmi") << "Already forced equal : " << all_eqc[i] << " = " << all_eqc[j] << std::endl;
- eq_merged = true;
- }
- }
- }
- Assert( !eq_merged );
- */
-
//get all constructors
eq::EqClassesIterator eqccs_i = eq::EqClassesIterator( &d_equalityEngine );
std::vector< Node > cons;
@@ -1159,11 +1179,32 @@ void TheoryDatatypes::collectModelInfo( TheoryModel* m, bool fullModel ){
//for all equivalence classes that are datatypes
if( DatatypesRewriter::isTermDatatype( eqc ) ){
EqcInfo* ei = getOrMakeEqcInfo( eqc );
- if( !ei->d_constructor.get().isNull() ){
- cons.push_back( ei->d_constructor.get() );
- eqc_cons[ eqc ] = ei->d_constructor.get();
+ if( ei && !ei->d_constructor.get().isNull() ){
+ Node c = ei->d_constructor.get();
+ cons.push_back( c );
+ eqc_cons[ eqc ] = c;
+ m->assertRepresentative( c );
}else{
- nodes.push_back( eqc );
+ //if eqc contains a symbol known to datatypes (a selector), then we must assign
+#if 0
+ bool shouldConsider = false;
+ eq::EqClassIterator eqc_i = eq::EqClassIterator( eqc, &d_equalityEngine );
+ while( !eqc_i.isFinished() ){
+ Node n = *eqc_i;
+ Trace("dt-cmi-debug") << n << " has kind " << n.getKind() << ", isVar = " << n.isVar() << std::endl;
+ if( n.isVar() || n.getKind()==APPLY_SELECTOR_TOTAL ){
+ shouldConsider = true;
+ break;
+ }
+ ++eqc_i;
+ }
+#else
+ //should assign constructors to EQC if they have a selector or a tester
+ bool shouldConsider = ( ei && ei->d_selectors ) || hasTester( eqc );
+#endif
+ if( shouldConsider ){
+ nodes.push_back( eqc );
+ }
}
}
++eqccs_i;
@@ -1179,11 +1220,14 @@ void TheoryDatatypes::collectModelInfo( TheoryModel* m, bool fullModel ){
bool addCons = false;
const Datatype& dt = ((DatatypeType)(eqc.getType()).toType()).getDatatype();
if( !d_equalityEngine.hasTerm( eqc ) ){
+ Assert( false );
+ /*
if( !dt.isCodatatype() ){
Trace("dt-cmi") << "NOTICE : Datatypes: need to assign constructor for " << eqc << std::endl;
Trace("dt-cmi") << " Type : " << eqc.getType() << std::endl;
TypeNode tn = eqc.getType();
//if it is infinite, make sure it is fresh
+ // this ensures that the term that this is an argument of is distinct.
if( eqc.getType().getCardinality().isInfinite() ){
std::map< TypeNode, int >::iterator it = typ_enum_map.find( tn );
int teIndex;
@@ -1224,6 +1268,7 @@ void TheoryDatatypes::collectModelInfo( TheoryModel* m, bool fullModel ){
neqc = *te;
}
}
+ */
}else{
Trace("dt-cmi") << "NOTICE : Datatypes: no constructor in equivalence class " << eqc << std::endl;
Trace("dt-cmi") << " Type : " << eqc.getType() << std::endl;
@@ -1235,34 +1280,18 @@ void TheoryDatatypes::collectModelInfo( TheoryModel* m, bool fullModel ){
Trace("dt-cmi") << pcons[i] << " ";
}
Trace("dt-cmi") << std::endl;
- /*
- std::map< int, std::map< int, bool > > sels;
- Trace("dt-cmi") << "Existing selectors : ";
- NodeListMap::iterator sel_i = d_selector_apps.find( eqc );
- if( sel_i != d_selector_apps.end() ){
- NodeList* sel = (*sel_i).second;
- for( NodeList::const_iterator j = sel->begin(); j != sel->end(); j++ ){
- Expr selectorExpr = (*j).getOperator().toExpr();
- unsigned cindex = Datatype::cindexOf( selectorExpr );
- unsigned index = Datatype::indexOf( selectorExpr );
- sels[cindex][index] = true;
- Trace("dt-cmi") << (*j) << " (" << cindex << ", " << index << ") ";
- }
- }
- Trace("dt-cmi") << std::endl;
- */
for( unsigned r=0; r<2; r++ ){
if( neqc.isNull() ){
for( unsigned i=0; i<pcons.size(); i++ ){
//must try the infinite ones first
if( pcons[i] && (r==1)==dt[ i ].isFinite() ){
- neqc = getInstantiateCons( eqc, dt, i, false, false );
- for( unsigned j=0; j<neqc.getNumChildren(); j++ ){
- //if( sels[i].find( j )==sels[i].end() && DatatypesRewriter::isTermDatatype( neqc[j] ) ){
- if( !d_equalityEngine.hasTerm( neqc[j] ) && DatatypesRewriter::isTermDatatype( neqc[j] ) ){
- nodes.push_back( neqc[j] );
- }
- }
+ neqc = DatatypesRewriter::getInstCons( eqc, dt, i );
+ //for( unsigned j=0; j<neqc.getNumChildren(); j++ ){
+ // //if( sels[i].find( j )==sels[i].end() && DatatypesRewriter::isTermDatatype( neqc[j] ) ){
+ // if( !d_equalityEngine.hasTerm( neqc[j] ) && DatatypesRewriter::isTermDatatype( neqc[j] ) ){
+ // nodes.push_back( neqc[j] );
+ // }
+ //}
break;
}
}
@@ -1274,25 +1303,8 @@ void TheoryDatatypes::collectModelInfo( TheoryModel* m, bool fullModel ){
Trace("dt-cmi") << "Assign : " << neqc << std::endl;
m->assertEquality( eqc, neqc, true );
eqc_cons[ eqc ] = neqc;
+ m->assertRepresentative( neqc );
}
- /*
- for( unsigned kk=0; kk<all_eqc.size(); kk++ ){
- for( unsigned ll=(kk+1); ll<all_eqc.size(); ll++ ){
- if( m->areEqual( all_eqc[kk], all_eqc[ll] ) ){
- Trace("dt-cmi") << "Forced equal : " << kk << " " << ll << " : " << all_eqc[kk] << " = " << all_eqc[ll] << std::endl;
- Node r = m->getRepresentative( all_eqc[kk] );
- Trace("dt-cmi") << " { ";
- eq::EqClassIterator eqc_i = eq::EqClassIterator( r, m->d_equalityEngine );
- while( !eqc_i.isFinished() ){
- Trace("dt-cmi") << (*eqc_i) << " ";
- ++eqc_i;
- }
- Trace("dt-cmi") << "} " << std::endl;
- }
- Assert( !m->areEqual( all_eqc[kk], all_eqc[ll] ) );
- }
- }
- */
//m->assertRepresentative( neqc );
if( addCons ){
cons.push_back( neqc );
@@ -1307,32 +1319,44 @@ void TheoryDatatypes::collectModelInfo( TheoryModel* m, bool fullModel ){
const Datatype& dt = ((DatatypeType)(eqc.getType()).toType()).getDatatype();
if( dt.isCodatatype() ){
std::map< Node, Node > vmap;
- Node v = getCodatatypesValue( it->first, eqc_cons, eqc_mu, vmap );
- Trace("dt-cmi-cod") << " EQC(" << it->first << "), constructor is " << it->second << ", value is " << v << std::endl;
+ std::vector< Node > fv;
+ Node v = getCodatatypesValue( it->first, eqc_cons, eqc_mu, vmap, fv );
+ Trace("dt-cmi-cdt") << " EQC(" << it->first << "), constructor is " << it->second << ", value is " << v << ", const = " << v.isConst() << std::endl;
+ m->assertEquality( eqc, v, true );
}
}
}
-Node TheoryDatatypes::getCodatatypesValue( Node n, std::map< Node, Node >& eqc_cons, std::map< Node, Node >& eqc_mu, std::map< Node, Node >& vmap ){
+Node TheoryDatatypes::getCodatatypesValue( Node n, std::map< Node, Node >& eqc_cons, std::map< Node, Node >& eqc_mu, std::map< Node, Node >& vmap, std::vector< Node >& fv ){
std::map< Node, Node >::iterator itv = vmap.find( n );
if( itv!=vmap.end() ){
+ if( std::find( fv.begin(), fv.end(), itv->second )==fv.end() ){
+ fv.push_back( itv->second );
+ }
return itv->second;
}else if( DatatypesRewriter::isTermDatatype( n ) ){
- Node nv = NodeManager::currentNM()->mkBoundVar( n.getType() );
+ std::stringstream ss;
+ ss << "$x" << vmap.size();
+ Node nv = NodeManager::currentNM()->mkBoundVar( ss.str().c_str(), n.getType() );
vmap[n] = nv;
- Trace("dt-cmi-cod-debug") << " map " << n << " -> " << nv << std::endl;
+ Trace("dt-cmi-cdt-debug") << " map " << n << " -> " << nv << std::endl;
Node nc = eqc_cons[n];
Assert( nc.getKind()==APPLY_CONSTRUCTOR );
std::vector< Node > children;
children.push_back( nc.getOperator() );
for( unsigned i=0; i<nc.getNumChildren(); i++ ){
Node r = getRepresentative( nc[i] );
- Node rv = getCodatatypesValue( r, eqc_cons, eqc_mu, vmap );
+ Node rv = getCodatatypesValue( r, eqc_cons, eqc_mu, vmap, fv );
children.push_back( rv );
}
vmap.erase( n );
- return NodeManager::currentNM()->mkNode( APPLY_CONSTRUCTOR, children );
+ Node v = NodeManager::currentNM()->mkNode( APPLY_CONSTRUCTOR, children );
+ //add mu if we found a circular reference
+ if( std::find( fv.begin(), fv.end(), nv )!=fv.end() ){
+ v = NodeManager::currentNM()->mkNode( MU, nv, v );
+ }
+ return v;
}else{
return n;
}
@@ -1346,21 +1370,7 @@ void TheoryDatatypes::collectTerms( Node n ) {
}
if( n.getKind() == APPLY_CONSTRUCTOR ){
d_consTerms.push_back( n );
- /*
- //we must take into account subterm relation when checking for cycles
- for( int i=0; i<(int)n.getNumChildren(); i++ ) {
- bool result = d_cycle_check.addEdgeNode( n, n[i] );
- Debug("datatypes-cycles") << "DtCyc: Subterm " << n << " -> " << n[i] << " " << result << endl;
- if( result && !d_hasSeenCycle.get() ){
- Debug("datatypes-cycles") << "FOUND CYCLE" << std::endl;
- }
- d_hasSeenCycle.set( d_hasSeenCycle.get() || result );
- //Node r = getRepresentative( n[i] );
- //EqcInfo* eqc = getOrMakeEqcInfo( r, true );
- //eqc->d_selectors = true;
- }
- */
- }else if( n.getKind() == APPLY_SELECTOR_TOTAL ){
+ }else if( n.getKind() == APPLY_SELECTOR_TOTAL || n.getKind() == DT_SIZE ){
d_selTerms.push_back( n );
//we must also record which selectors exist
Debug("datatypes") << " Found selector " << n << endl;
@@ -1374,6 +1384,32 @@ void TheoryDatatypes::collectTerms( Node n ) {
EqcInfo* eqc = getOrMakeEqcInfo( rep, true );
//add it to the eqc info
addSelector( n, eqc, rep );
+
+ if( n.getKind() == DT_SIZE ){
+ Node conc = NodeManager::currentNM()->mkNode( LEQ, NodeManager::currentNM()->mkConst( Rational(0) ), n );
+ //must be non-negative
+ Trace("datatypes-infer") << "DtInfer : non-negative size : " << conc << std::endl;
+ d_pending.push_back( conc );
+ d_pending_exp[ conc ] = d_true;
+ d_infer.push_back( conc );
+
+ //add size = 0 lemma
+ Node nn = n.eqNode( NodeManager::currentNM()->mkConst( Rational(0) ) );
+ std::vector< Node > children;
+ children.push_back( nn.negate() );
+ const Datatype& dt = ((DatatypeType)(n[0].getType()).toType()).getDatatype();
+ for( unsigned i=0; i<dt.getNumConstructors(); i++ ){
+ if( DatatypesRewriter::isNullaryConstructor( dt[i] ) ){
+ Node test = DatatypesRewriter::mkTester( n[0], i, dt );
+ children.push_back( test );
+ }
+ }
+ conc = children.size()==1 ? children[0] : NodeManager::currentNM()->mkNode( OR, children );
+ Trace("datatypes-infer") << "DtInfer : zero size : " << conc << std::endl;
+ d_pending.push_back( conc );
+ d_pending_exp[ conc ] = d_true;
+ d_infer.push_back( conc );
+ }
}
}
}
@@ -1391,20 +1427,24 @@ void TheoryDatatypes::processNewTerm( Node n ){
}
}
-Node TheoryDatatypes::getInstantiateCons( Node n, const Datatype& dt, int index, bool mkVar, bool isActive ){
+Node TheoryDatatypes::getInstantiateCons( Node n, const Datatype& dt, int index ){
std::map< int, Node >::iterator it = d_inst_map[n].find( index );
if( it!=d_inst_map[n].end() ){
return it->second;
}else{
//add constructor to equivalence class
- Node n_ic = DatatypesRewriter::getInstCons( n, dt, index, mkVar );
- if( isActive ){
- for( unsigned i = 0; i<n_ic.getNumChildren(); i++ ){
- processNewTerm( n_ic[i] );
- }
- collectTerms( n_ic );
+ Node k = n;
+ if( n.getKind()==APPLY_CONSTRUCTOR ){
+ //must construct variable to refer to n, add lemma immediately
+ k = NodeManager::currentNM()->mkSkolem( "k", n.getType(), "for dt instantiation" );
+ Node eq = k.eqNode( n );
+ Trace("datatypes-infer") << "DtInfer : instantiation ref : " << eq << std::endl;
+ d_out->lemma( eq );
}
+ Node n_ic = DatatypesRewriter::getInstCons( k, dt, index );
+ //Assert( n_ic==Rewriter::rewrite( n_ic ) );
n_ic = Rewriter::rewrite( n_ic );
+ collectTerms( n_ic );
Debug("dt-enum") << "Made instantiate cons " << n_ic << std::endl;
d_inst_map[n][index] = n_ic;
return n_ic;
@@ -1429,7 +1469,7 @@ void TheoryDatatypes::instantiate( EqcInfo* eqc, Node n ){
//if( eqc->d_selectors || dt[ index ].isFinite() ){ // || mustSpecifyAssignment()
//instantiate this equivalence class
eqc->d_inst = true;
- Node tt_cons = getInstantiateCons( tt, dt, index, false, true );
+ Node tt_cons = getInstantiateCons( tt, dt, index );
Node eq;
if( tt!=tt_cons ){
eq = tt.eqNode( tt_cons );
@@ -1450,7 +1490,7 @@ void TheoryDatatypes::instantiate( EqcInfo* eqc, Node n ){
void TheoryDatatypes::checkCycles() {
Debug("datatypes-cycle-check") << "Check cycles" << std::endl;
- std::vector< Node > cod_eqc;
+ std::vector< Node > cdt_eqc;
eq::EqClassesIterator eqcs_i = eq::EqClassesIterator( &d_equalityEngine );
while( !eqcs_i.isFinished() ){
Node eqc = (*eqcs_i);
@@ -1481,27 +1521,30 @@ void TheoryDatatypes::checkCycles() {
}
}else{
//indexing
- cod_eqc.push_back( eqc );
+ cdt_eqc.push_back( eqc );
}
}
++eqcs_i;
}
//process codatatypes
- if( cod_eqc.size()>1 ){
+ if( cdt_eqc.size()>1 && options::cdtBisimilar() ){
+ Trace("dt-cdt-debug") << "Process " << cdt_eqc.size() << " co-datatypes" << std::endl;
std::vector< std::vector< Node > > part_out;
std::vector< TNode > exp;
std::map< Node, Node > cn;
std::map< Node, std::map< Node, int > > dni;
- for( unsigned i=0; i<cod_eqc.size(); i++ ){
- cn[cod_eqc[i]] = cod_eqc[i];
+ for( unsigned i=0; i<cdt_eqc.size(); i++ ){
+ cn[cdt_eqc[i]] = cdt_eqc[i];
}
- separateBisimilar( cod_eqc, part_out, exp, cn, dni, 0, false );
+ separateBisimilar( cdt_eqc, part_out, exp, cn, dni, 0, false );
+ Trace("dt-cdt-debug") << "Done separate bisimilar." << std::endl;
if( !part_out.empty() ){
+ Trace("dt-cdt-debug") << "Process partition size " << part_out.size() << std::endl;
for( unsigned i=0; i<part_out.size(); i++ ){
std::vector< Node > part;
part.push_back( part_out[i][0] );
for( unsigned j=1; j<part_out[i].size(); j++ ){
- Trace("dt-cod") << "Codatatypes : " << part_out[i][0] << " and " << part_out[i][j] << " must be equal!!" << std::endl;
+ Trace("dt-cdt") << "Codatatypes : " << part_out[i][0] << " and " << part_out[i][j] << " must be equal!!" << std::endl;
part.push_back( part_out[i][j] );
std::vector< std::vector< Node > > tpart_out;
exp.clear();
@@ -1513,16 +1556,16 @@ void TheoryDatatypes::checkCycles() {
Assert( tpart_out.size()==1 && tpart_out[0].size()==2 );
part.pop_back();
//merge based on explanation
- Trace("dt-cod") << " exp is : ";
+ Trace("dt-cdt") << " exp is : ";
for( unsigned k=0; k<exp.size(); k++ ){
- Trace("dt-cod") << exp[k] << " ";
+ Trace("dt-cdt") << exp[k] << " ";
}
- Trace("dt-cod") << std::endl;
+ Trace("dt-cdt") << std::endl;
Node eq = part_out[i][0].eqNode( part_out[i][j] );
Node eqExp = mkAnd( exp );
d_pending.push_back( eq );
d_pending_exp[ eq ] = eqExp;
- Trace("datatypes-infer") << "DtInfer : cod-bisimilar : " << eq << " by " << eqExp << std::endl;
+ Trace("datatypes-infer") << "DtInfer : cdt-bisimilar : " << eq << " by " << eqExp << std::endl;
d_infer.push_back( eq );
d_infer_exp.push_back( eqExp );
}
@@ -1537,9 +1580,9 @@ void TheoryDatatypes::separateBisimilar( std::vector< Node >& part, std::vector<
std::map< Node, Node >& cn,
std::map< Node, std::map< Node, int > >& dni, int dniLvl, bool mkExp ){
if( !mkExp ){
- Trace("dt-cod-debug") << "Separate bisimilar : " << std::endl;
+ Trace("dt-cdt-debug") << "Separate bisimilar : " << std::endl;
for( unsigned i=0; i<part.size(); i++ ){
- Trace("dt-cod-debug") << " " << part[i] << ", current = " << cn[part[i]] << std::endl;
+ Trace("dt-cdt-debug") << " " << part[i] << ", current = " << cn[part[i]] << std::endl;
}
}
Assert( part.size()>1 );
@@ -1553,7 +1596,7 @@ void TheoryDatatypes::separateBisimilar( std::vector< Node >& part, std::vector<
std::map< Node, int >::iterator it_rec = dni[part[j]].find( c );
if( it_rec!=dni[part[j]].end() ){
//looped
- if( !mkExp ){ Trace("dt-cod-debug") << " - " << part[j] << " is looping at index " << it_rec->second << std::endl; }
+ if( !mkExp ){ Trace("dt-cdt-debug") << " - " << part[j] << " is looping at index " << it_rec->second << std::endl; }
new_part_rec[ it_rec->second ].push_back( part[j] );
}else{
if( DatatypesRewriter::isTermDatatype( c ) ){
@@ -1565,14 +1608,14 @@ void TheoryDatatypes::separateBisimilar( std::vector< Node >& part, std::vector<
explainEquality( c, ncons, true, exp );
}
new_part[cc].push_back( part[j] );
- if( !mkExp ){ Trace("dt-cod-debug") << " - " << part[j] << " is datatype " << ncons << "." << std::endl; }
+ if( !mkExp ){ Trace("dt-cdt-debug") << " - " << part[j] << " is datatype " << ncons << "." << std::endl; }
}else{
new_part_c[c].push_back( part[j] );
- if( !mkExp ){ Trace("dt-cod-debug") << " - " << part[j] << " is unspecified datatype." << std::endl; }
+ if( !mkExp ){ Trace("dt-cdt-debug") << " - " << part[j] << " is unspecified datatype." << std::endl; }
}
}else{
//add equivalences
- if( !mkExp ){ Trace("dt-cod-debug") << " - " << part[j] << " is term " << c << "." << std::endl; }
+ if( !mkExp ){ Trace("dt-cdt-debug") << " - " << part[j] << " is term " << c << "." << std::endl; }
new_part_c[c].push_back( part[j] );
}
}
@@ -1614,7 +1657,7 @@ void TheoryDatatypes::separateBisimilar( std::vector< Node >& part, std::vector<
//for each child of constructor
unsigned cindex = 0;
while( cindex<nChildren && !split_new_part.empty() ){
- if( !mkExp ){ Trace("dt-cod-debug") << "Split argument #" << cindex << " of " << it->first << "..." << std::endl; }
+ if( !mkExp ){ Trace("dt-cdt-debug") << "Split argument #" << cindex << " of " << it->first << "..." << std::endl; }
std::vector< std::vector< Node > > next_split_new_part;
for( unsigned j=0; j<split_new_part.size(); j++ ){
//set current node
@@ -1702,35 +1745,51 @@ bool TheoryDatatypes::mustSpecifyAssignment(){
}
bool TheoryDatatypes::mustCommunicateFact( Node n, Node exp ){
- //the datatypes decision procedure makes 3 "internal" inferences apart from the equality engine :
+ //the datatypes decision procedure makes "internal" inferences apart from the equality engine :
// (1) Unification : C( t1...tn ) = C( s1...sn ) => ti = si
// (2) Label : ~is_C1( t ) ... ~is_C{i-1}( t ) ~is_C{i+1}( t ) ... ~is_Cn( t ) => is_Ci( t )
// (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
+ // (4) collapse selector : S( C( t1...tn ) ) = t'
+ // (5) collapse term size : size( C( t1...tn ) ) = 1 + size( t1 ) + ... + size( tn )
+ // (6) non-negative size : 0 <= size( t )
+ //We may need to communicate outwards if the conclusions involve other theories. Also communicate (6) and OR conclusions.
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 ){
-#if 1
- const Datatype& dt = ((DatatypeType)(n[1].getType()).toType()).getDatatype();
- addLemma = dt.involvesExternalType();
-#else
- for( int j=0; j<(int)n[1].getNumChildren(); j++ ){
- if( !DatatypesRewriter::isTermDatatype( n[1][j] ) ){
+ if( n.getKind()==EQUAL || n.getKind()==IFF ){
+ /*
+ for( unsigned i=0; i<2; i++ ){
+ if( n[i].getKind()!=APPLY_SELECTOR_TOTAL && n[i].getKind()!=APPLY_CONSTRUCTOR ){
addLemma = true;
- break;
}
}
-#endif
- if( addLemma ){
- //check if we have already added this lemma
- if( std::find( d_inst_lemmas[ n[0] ].begin(), d_inst_lemmas[ n[0] ].end(), n[1] )==d_inst_lemmas[ n[0] ].end() ){
- d_inst_lemmas[ n[0] ].push_back( n[1] );
- Trace("dt-lemma-debug") << "Communicate " << n << std::endl;
- return true;
- }else{
- Trace("dt-lemma-debug") << "Already communicated " << n << std::endl;
- return false;
- }
+ */
+ TypeNode tn = n[0].getType();
+ if( !DatatypesRewriter::isTypeDatatype( tn ) ){
+ addLemma = true;
+ }else{
+ const Datatype& dt = ((DatatypeType)(tn).toType()).getDatatype();
+ addLemma = dt.involvesExternalType();
+ }
+ //for( int j=0; j<(int)n[1].getNumChildren(); j++ ){
+ // if( !DatatypesRewriter::isTermDatatype( n[1][j] ) ){
+ // addLemma = true;
+ // break;
+ // }
+ //}
+ }else if( n.getKind()==LEQ ){
+ addLemma = true;
+ }else if( n.getKind()==OR ){
+ addLemma = true;
+ }
+ if( addLemma ){
+ //check if we have already added this lemma
+ if( std::find( d_inst_lemmas[ n[0] ].begin(), d_inst_lemmas[ n[0] ].end(), n[1] )==d_inst_lemmas[ n[0] ].end() ){
+ d_inst_lemmas[ n[0] ].push_back( n[1] );
+ Trace("dt-lemma-debug") << "Communicate " << n << std::endl;
+ return true;
+ }else{
+ Trace("dt-lemma-debug") << "Already communicated " << n << std::endl;
+ return false;
}
}
//else if( exp.getKind()==APPLY_TESTER ){
@@ -1793,7 +1852,9 @@ void TheoryDatatypes::printModelDebug( const char* c ){
//add terms to model
eq::EqClassIterator eqc_i = eq::EqClassIterator( eqc, &d_equalityEngine );
while( !eqc_i.isFinished() ){
- Trace( c ) << (*eqc_i) << " ";
+ if( (*eqc_i)!=eqc ){
+ Trace( c ) << (*eqc_i) << " ";
+ }
++eqc_i;
}
Trace( c ) << "}" << std::endl;
diff --git a/src/theory/datatypes/theory_datatypes.h b/src/theory/datatypes/theory_datatypes.h
index 132077e29..2777e775a 100644
--- a/src/theory/datatypes/theory_datatypes.h
+++ b/src/theory/datatypes/theory_datatypes.h
@@ -123,12 +123,14 @@ private:
//all selectors whose argument is this eqc
context::CDO< bool > d_selectors;
};
- /** does eqc of n have a label? */
+ /** does eqc of n have a label (do we know its constructor)? */
bool hasLabel( EqcInfo* eqc, Node n );
/** get the label associated to n */
Node getLabel( Node n );
/** get the index of the label associated to n */
int getLabelIndex( EqcInfo* eqc, Node n );
+ /** does eqc of n have any testers? */
+ bool hasTester( Node n );
/** get the possible constructors for n */
void getPossibleCons( EqcInfo* eqc, Node n, std::vector< bool >& cons );
private:
@@ -138,8 +140,6 @@ private:
eq::EqualityEngine d_equalityEngine;
/** information necessary for equivalence classes */
std::map< Node, EqcInfo* > d_eqc_info;
- /** selector applications */
- //BoolMap d_selector_apps;
/** map from nodes to their instantiated equivalent for each constructor type */
std::map< Node, std::map< int, Node > > d_inst_map;
/** which instantiation lemmas we have sent */
@@ -174,6 +174,8 @@ private:
context::CDList<TNode> d_consTerms;
/** All the selector terms that the theory has seen */
context::CDList<TNode> d_selTerms;
+ /** counter for forcing assignments (ensures fairness) */
+ unsigned d_dtfCounter;
private:
/** assert fact */
void assertFact( Node fact, Node exp );
@@ -254,11 +256,11 @@ private:
std::map< Node, Node >& cn,
std::map< Node, std::map< Node, int > >& dni, int dniLvl, bool mkExp );
/** build model */
- Node getCodatatypesValue( Node n, std::map< Node, Node >& eqc_cons, std::map< Node, Node >& eqc_mu, std::map< Node, Node >& vmap );
+ Node getCodatatypesValue( Node n, std::map< Node, Node >& eqc_cons, std::map< Node, Node >& eqc_mu, std::map< Node, Node >& vmap, std::vector< Node >& fv );
/** collect terms */
void collectTerms( Node n );
/** get instantiate cons */
- Node getInstantiateCons( Node n, const Datatype& dt, int index, bool mkVar, bool isActive );
+ Node getInstantiateCons( Node n, const Datatype& dt, int index );
/** process new term that was created internally */
void processNewTerm( Node n );
/** check instantiate */
diff --git a/src/theory/datatypes/theory_datatypes_type_rules.h b/src/theory/datatypes/theory_datatypes_type_rules.h
index ddad913fe..84be5238d 100644
--- a/src/theory/datatypes/theory_datatypes_type_rules.h
+++ b/src/theory/datatypes/theory_datatypes_type_rules.h
@@ -209,6 +209,49 @@ struct DatatypeAscriptionTypeRule {
}
};/* struct DatatypeAscriptionTypeRule */
+/* For co-datatypes */
+class DatatypeMuTypeRule {
+private:
+ //a Mu-expression is constant iff its body is composed of constructors applied to constant expr and bound variables only
+ inline static bool computeIsConstNode(TNode n, std::vector< TNode >& fv ){
+ if( n.getKind()==kind::MU ){
+ fv.push_back( n[0] );
+ bool ret = computeIsConstNode( n[1], fv );
+ fv.pop_back();
+ return ret;
+ }else if( n.isConst() || std::find( fv.begin(), fv.end(), n )!=fv.end() ){
+ return true;
+ }else if( n.getKind()==kind::APPLY_CONSTRUCTOR ){
+ for( unsigned i=0; i<n.getNumChildren(); i++ ){
+ if( !computeIsConstNode( n[i], fv ) ){
+ return false;
+ }
+ }
+ return true;
+ }else{
+ return false;
+ }
+ }
+public:
+ inline static TypeNode computeType(NodeManager* nodeManager, TNode n, bool check) {
+ if( n[0].getKind()!=kind::BOUND_VARIABLE ) {
+ std::stringstream ss;
+ ss << "expected a bound var for MU expression, got `"
+ << n[0] << "'";
+ throw TypeCheckingExceptionPrivate(n, ss.str());
+ }
+ return n[1].getType(check);
+ }
+ inline static bool computeIsConst(NodeManager* nodeManager, TNode n)
+ throw(AssertionException) {
+ Assert(n.getKind() == kind::MU);
+ NodeManagerScope nms(nodeManager);
+ std::vector< TNode > fv;
+ return computeIsConstNode( n, fv );
+ }
+};
+
+
struct ConstructorProperties {
inline static Cardinality computeCardinality(TypeNode type) {
// Constructors aren't exactly functions, they're like
@@ -508,6 +551,21 @@ struct RecordProperties {
}
};/* struct RecordProperties */
+class DtSizeTypeRule {
+public:
+ inline static TypeNode computeType(NodeManager* nodeManager, TNode n, bool check)
+ throw (TypeCheckingExceptionPrivate, AssertionException) {
+ if( check ) {
+ TypeNode t = n[0].getType(check);
+ if (!t.isDatatype()) {
+ throw TypeCheckingExceptionPrivate(n, "expecting datatype size term to have datatype argument.");
+ }
+ }
+ return nodeManager->integerType();
+ }
+};/* class DtSizeTypeRule */
+
+
}/* CVC4::theory::datatypes namespace */
}/* CVC4::theory namespace */
}/* CVC4 namespace */
diff --git a/src/theory/datatypes/type_enumerator.h b/src/theory/datatypes/type_enumerator.h
index 256dcaef2..dc2a83841 100644
--- a/src/theory/datatypes/type_enumerator.h
+++ b/src/theory/datatypes/type_enumerator.h
@@ -28,168 +28,254 @@ namespace CVC4 {
namespace theory {
namespace datatypes {
+
class DatatypesEnumerator : public TypeEnumeratorBase<DatatypesEnumerator> {
/** The datatype we're enumerating */
const Datatype& d_datatype;
- /** The datatype constructor we're currently enumerating */
- size_t d_ctor;
- /** The "first" constructor to consider; it's non-recursive */
- size_t d_zeroCtor;
- /** Delegate enumerators for the arguments of the current constructor */
- TypeEnumerator** d_argEnumerators;
/** type */
TypeNode d_type;
-
- /** Allocate and initialize the delegate enumerators */
- void newEnumerators() {
- d_argEnumerators = new TypeEnumerator*[d_datatype[d_ctor].getNumArgs()];
- for(size_t a = 0; a < d_datatype[d_ctor].getNumArgs(); ++a) {
- d_argEnumerators[a] = NULL;
+ /** The datatype constructor we're currently enumerating */
+ unsigned d_ctor;
+ /** The "first" constructor to consider; it's non-recursive */
+ unsigned d_zeroCtor;
+ /** list of type enumerators (one for each type in a selector argument) */
+ std::map< TypeNode, unsigned > d_te_index;
+ std::vector< TypeEnumerator > d_children;
+ /** terms produced for types */
+ std::map< TypeNode, std::vector< Node > > d_terms;
+ /** arg type of each selector, for each constructor */
+ std::vector< std::vector< TypeNode > > d_sel_types;
+ /** current index for each argument, for each constructor */
+ std::vector< std::vector< unsigned > > d_sel_index;
+ /** current sum of argument indicies for each constructor */
+ std::vector< int > d_sel_sum;
+ /** current bound on the number of times we can iterate argument enumerators */
+ unsigned d_size_limit;
+
+ Node getTermEnum( TypeNode tn, unsigned i ){
+ if( i<d_terms[tn].size() ){
+ return d_terms[tn][i];
+ }else{
+ Debug("dt-enum-debug") << "get term enum " << tn << " " << i << std::endl;
+ std::map< TypeNode, unsigned >::iterator it = d_te_index.find( tn );
+ unsigned tei;
+ if( it==d_te_index.end() ){
+ //initialize child enumerator for type
+ tei = d_children.size();
+ d_te_index[tn] = tei;
+ d_children.push_back( TypeEnumerator( tn ) );
+ d_terms[tn].push_back( *d_children[tei] );
+ }else{
+ tei = it->second;
+ }
+ //enumerate terms until index is reached
+ while( i>=d_terms[tn].size() ){
+ ++d_children[tei];
+ if( d_children[tei].isFinished() ){
+ Debug("dt-enum-debug") << "...fail term enum " << tn << " " << i << std::endl;
+ return Node::null();
+ }
+ d_terms[tn].push_back( *d_children[tei] );
+ }
+ Debug("dt-enum-debug") << "...return term enum " << tn << " " << i << " : " << d_terms[tn][i] << std::endl;
+ return d_terms[tn][i];
}
}
- /** Delete the delegate enumerators */
- void deleteEnumerators() {
- if(d_argEnumerators != NULL) {
- for(size_t a = 0; a < d_datatype[d_ctor].getNumArgs(); ++a) {
- delete d_argEnumerators[a];
+ bool increment( unsigned index ){
+ Debug("dt-enum") << "Incrementing " << d_type << " " << d_ctor << " at size " << d_sel_sum[index] << "/" << d_size_limit << std::endl;
+ if( d_sel_sum[index]==-1 ){
+ //first time
+ d_sel_sum[index] = 0;
+ //special case: no children to iterate
+ if( d_sel_types[index].size()==0 ){
+ Debug("dt-enum") << "...success (nc) = " << (d_size_limit==0) << std::endl;
+ return d_size_limit==0;
+ }else{
+ Debug("dt-enum") << "...success" << std::endl;
+ return true;
+ }
+ }else{
+ unsigned i = 0;
+ while( i < d_sel_index[index].size() ){
+ //increment if the sum of iterations on arguments is less than the limit
+ if( d_sel_sum[index]<(int)d_size_limit ){
+ //also check if child enumerator has enough terms
+ if( !getTermEnum( d_sel_types[index][i], d_sel_index[index][i]+1 ).isNull() ){
+ Debug("dt-enum") << "...success increment child " << i << std::endl;
+ d_sel_index[index][i]++;
+ d_sel_sum[index]++;
+ return true;
+ }
+ }
+ Debug("dt-enum") << "......failed increment child " << i << std::endl;
+ //reset child, iterate next
+ d_sel_sum[index] -= d_sel_index[index][i];
+ d_sel_index[index][i] = 0;
+ i++;
}
- delete [] d_argEnumerators;
- d_argEnumerators = NULL;
+ Debug("dt-enum") << "...failure." << std::endl;
+ return false;
}
}
+ Node getCurrentTerm( unsigned index ){
+ Debug("dt-enum-debug") << "Get current term at " << index << " " << d_type << "..." << std::endl;
+ DatatypeConstructor ctor = d_datatype[index];
+ Debug("dt-enum-debug") << "Check last term..." << std::endl;
+ //we first check if the last argument (which is forced to make sum of iterated arguments equal to d_size_limit) is defined
+ Node lc;
+ if( ctor.getNumArgs()>0 ){
+ lc = getTermEnum( d_sel_types[index][ctor.getNumArgs()-1], d_size_limit - d_sel_sum[index] );
+ if( lc.isNull() ){
+ Debug("dt-enum-debug") << "Current infeasible." << std::endl;
+ return Node::null();
+ }
+ }
+ Debug("dt-enum-debug") << "Get constructor..." << std::endl;
+ NodeBuilder<> b(kind::APPLY_CONSTRUCTOR);
+ Type typ;
+ if( d_datatype.isParametric() ){
+ typ = ctor.getSpecializedConstructorType(d_type.toType());
+ b << NodeManager::currentNM()->mkNode(kind::APPLY_TYPE_ASCRIPTION,
+ NodeManager::currentNM()->mkConst(AscriptionType(typ)), Node::fromExpr( ctor.getConstructor() ) );
+ }else{
+ b << ctor.getConstructor();
+ }
+ Debug("dt-enum-debug") << "Get arguments..." << std::endl;
+ if( ctor.getNumArgs()>0 ){
+ Assert( index<d_sel_types.size() );
+ Assert( index<d_sel_index.size() );
+ Assert( d_sel_types[index].size()==ctor.getNumArgs() );
+ Assert( d_sel_index[index].size()==ctor.getNumArgs()-1 );
+ for( int i=0; i<(int)(ctor.getNumArgs()-1); i++ ){
+ Node c = getTermEnum( d_sel_types[index][i], d_sel_index[index][i] );
+ Assert( !c.isNull() );
+ b << c;
+ }
+ b << lc;
+ }
+ Node nnn = Node(b);
+ Debug("dt-enum-debug") << "Return... " << nnn << std::endl;
+ return nnn;
+ }
public:
DatatypesEnumerator(TypeNode type) throw() :
TypeEnumeratorBase<DatatypesEnumerator>(type),
d_datatype(DatatypeType(type.toType()).getDatatype()),
+ d_type(type),
d_ctor(0),
- d_zeroCtor(0),
- d_argEnumerators(NULL),
- d_type(type) {
+ d_zeroCtor(0) {
//Assert(type.isDatatype());
Debug("te") << "datatype is datatype? " << type.isDatatype() << std::endl;
Debug("te") << "datatype is kind " << type.getKind() << std::endl;
Debug("te") << "datatype is " << type << std::endl;
- /* find the "zero" constructor (the first non-recursive one) */
- /* FIXME: this isn't sufficient for mutually-recursive datatypes! */
- while(d_zeroCtor < d_datatype.getNumConstructors()) {
- bool recursive = false;
+ /* find the "zero" constructor via mkGroundTerm */
+ Node t = type.mkGroundTerm();
+ Assert( t.getKind()==kind::APPLY_CONSTRUCTOR );
+ d_zeroCtor = Datatype::indexOf( t.getOperator().toExpr() );
+ /* start with the constructor for which a ground term is constructed */
+ d_ctor = d_zeroCtor;
+
+ for( unsigned i=0; i<d_datatype.getNumConstructors(); ++i ){
+ d_sel_types.push_back( std::vector< TypeNode >() );
+ d_sel_index.push_back( std::vector< unsigned >() );
+ d_sel_sum.push_back( -1 );
+ DatatypeConstructor ctor = d_datatype[i];
+ Type typ;
if( d_datatype.isParametric() ){
- TypeNode tn = TypeNode::fromType( d_datatype[d_zeroCtor].getSpecializedConstructorType(d_type.toType()) );
- for( unsigned i=0; i<tn.getNumChildren()-1; i++ ){
- if( tn[i]==type ){
- recursive = true;
- break;
- }
- }
- }else{
- for(size_t a = 0; a < d_datatype[d_zeroCtor].getNumArgs() && !recursive; ++a) {
- if(Node::fromExpr(d_datatype[d_zeroCtor][a].getSelector()).getType()[1] == type) {
- recursive = true;
- break;
- }
+ typ = ctor.getSpecializedConstructorType(d_type.toType());
+ }
+ for( unsigned a = 0; a < ctor.getNumArgs(); ++a ){
+ TypeNode tn;
+ if( d_datatype.isParametric() ){
+ tn = TypeNode::fromType( typ )[a];
+ }else{
+ tn = Node::fromExpr(ctor[a].getSelector()).getType()[1];
}
+ d_sel_types[i].push_back( tn );
+ d_sel_index[i].push_back( 0 );
}
- if(!recursive) {
- break;
+ if( !d_sel_index[i].empty() ){
+ d_sel_index[i].pop_back();
}
- ++d_zeroCtor;
}
-
- /* start with the non-recursive constructor */
- d_ctor = d_zeroCtor;
-
- /* allocate space for the enumerators */
- newEnumerators();
+ d_size_limit = 0;
+ //set up initial conditions (should always succeed)
+ bool init_inc = increment( d_ctor );
+ AlwaysAssert( init_inc );
}
DatatypesEnumerator(const DatatypesEnumerator& de) throw() :
TypeEnumeratorBase<DatatypesEnumerator>(de.getType()),
d_datatype(de.d_datatype),
+ d_type(de.d_type),
d_ctor(de.d_ctor),
- d_zeroCtor(de.d_zeroCtor),
- d_argEnumerators(NULL),
- d_type(de.d_type) {
+ d_zeroCtor(de.d_zeroCtor) {
- if(de.d_argEnumerators != NULL) {
- newEnumerators();
- for(size_t a = 0; a < d_datatype[d_ctor].getNumArgs(); ++a) {
- if(de.d_argEnumerators[a] != NULL) {
- d_argEnumerators[a] = new TypeEnumerator(*de.d_argEnumerators[a]);
- }
- }
+ for( std::map< TypeNode, unsigned >::const_iterator it = de.d_te_index.begin(); it != de.d_te_index.end(); ++it ){
+ d_te_index[it->first] = it->second;
+ }
+ for( std::map< TypeNode, std::vector< Node > >::const_iterator it = de.d_terms.begin(); it != de.d_terms.end(); ++it ){
+ d_terms[it->first].insert( d_terms[it->first].end(), it->second.begin(), it->second.end() );
+ }
+ for( unsigned i=0; i<de.d_sel_types.size(); i++ ){
+ d_sel_types.push_back( std::vector< TypeNode >() );
+ d_sel_types[i].insert( d_sel_types[i].end(), de.d_sel_types[i].begin(), de.d_sel_types[i].end() );
}
+ for( unsigned i=0; i<de.d_sel_index.size(); i++ ){
+ d_sel_index.push_back( std::vector< unsigned >() );
+ d_sel_index[i].insert( d_sel_index[i].end(), de.d_sel_index[i].begin(), de.d_sel_index[i].end() );
+ }
+
+ d_children.insert( d_children.end(), de.d_children.begin(), de.d_children.end() );
+ d_sel_sum.insert( d_sel_sum.end(), de.d_sel_sum.begin(), de.d_sel_sum.end() );
+ d_size_limit = de.d_size_limit;
}
~DatatypesEnumerator() throw() {
- deleteEnumerators();
}
Node operator*() throw(NoMoreValuesException) {
+ Debug("dt-enum-debug") << ": get term " << this << std::endl;
if(d_ctor < d_datatype.getNumConstructors()) {
- DatatypeConstructor ctor = d_datatype[d_ctor];
- NodeBuilder<> b(kind::APPLY_CONSTRUCTOR);
- Type typ;
- if( d_datatype.isParametric() ){
- typ = d_datatype[d_ctor].getSpecializedConstructorType(d_type.toType());
- b << NodeManager::currentNM()->mkNode(kind::APPLY_TYPE_ASCRIPTION,
- NodeManager::currentNM()->mkConst(AscriptionType(typ)), Node::fromExpr( ctor.getConstructor() ) );
- }else{
- b << ctor.getConstructor();
- }
- try {
- for(size_t a = 0; a < d_datatype[d_ctor].getNumArgs(); ++a) {
- if(d_argEnumerators[a] == NULL) {
- if( d_datatype.isParametric() ){
- d_argEnumerators[a] = new TypeEnumerator(TypeNode::fromType( typ )[a]);
- }else{
- d_argEnumerators[a] = new TypeEnumerator(Node::fromExpr(d_datatype[d_ctor][a].getSelector()).getType()[1]);
- }
- }
- b << **d_argEnumerators[a];
- }
- } catch(NoMoreValuesException&) {
- InternalError();
- }
- Node nnn = Node(b);
- //if( nnn.getType()!=d_type || !nnn.getType().isComparableTo(d_type) ){
- // Debug("dt-warn") << "WARNING : Enum : " << nnn << " bad type : " << nnn.getType() << " " << d_type << std::endl;
- //}
- return nnn;
+ return getCurrentTerm( d_ctor );
} else {
throw NoMoreValuesException(getType());
}
}
DatatypesEnumerator& operator++() throw() {
- if(d_ctor < d_datatype.getNumConstructors()) {
- for(size_t a = d_datatype[d_ctor].getNumArgs(); a > 0; --a) {
- if((++*d_argEnumerators[a - 1]).isFinished()) {
- *d_argEnumerators[a - 1] = TypeEnumerator(Node::fromExpr(d_datatype[d_ctor][a - 1].getSelector()).getType()[1]);
- } else {
+ Debug("dt-enum-debug") << ": increment " << this << std::endl;
+ unsigned prevSize = d_size_limit;
+ while(d_ctor < d_datatype.getNumConstructors()) {
+ //increment at index
+ while( increment( d_ctor ) ){
+ Node n = getCurrentTerm( d_ctor );
+ if( !n.isNull() ){
return *this;
}
}
-
// Here, we need to step from the current constructor to the next one
- // first, delete the current delegate enumerators
- deleteEnumerators();
-
// Find the next constructor (only complicated by the notion of the "zero" constructor
d_ctor = (d_ctor == d_zeroCtor) ? 0 : d_ctor + 1;
if(d_ctor == d_zeroCtor) {
++d_ctor;
}
-
- // If we aren't out of constructors, allocate space for the new delegate enumerators
- if(d_ctor < d_datatype.getNumConstructors()) {
- newEnumerators();
+ if( d_ctor>=d_datatype.getNumConstructors() ){
+ //try next size limit as long as new terms were generated at last size
+ if( prevSize==d_size_limit ){
+ d_size_limit++;
+ d_ctor = d_zeroCtor;
+ for( unsigned i=0; i<d_sel_sum.size(); i++ ){
+ d_sel_sum[i] = -1;
+ }
+ }
}
}
return *this;
diff --git a/src/theory/idl/theory_idl.cpp b/src/theory/idl/theory_idl.cpp
index 8597c117d..9e402f430 100644
--- a/src/theory/idl/theory_idl.cpp
+++ b/src/theory/idl/theory_idl.cpp
@@ -49,6 +49,10 @@ Node TheoryIdl::ppRewrite(TNode atom) {
}
void TheoryIdl::check(Effort level) {
+ //// Not needed for now, as no code outside while() loop below.
+ // if (done() && !fullEffort(e)) {
+ // return;
+ // }
while(!done()) {
diff --git a/src/theory/quantifiers/ambqi_builder.cpp b/src/theory/quantifiers/ambqi_builder.cpp
index d6dac6f14..353b6d1c4 100644
--- a/src/theory/quantifiers/ambqi_builder.cpp
+++ b/src/theory/quantifiers/ambqi_builder.cpp
@@ -740,7 +740,7 @@ void AbsMbqiBuilder::processBuildModel(TheoryModel* m, bool fullModel) {
//debug the model
debugModel( fm );
}else{
- fm->initialize( d_considerAxioms );
+ fm->initialize();
//process representatives
fm->d_rep_id.clear();
fm->d_domain.clear();
diff --git a/src/theory/quantifiers/bounded_integers.cpp b/src/theory/quantifiers/bounded_integers.cpp
index d6f9704b3..91c04bc80 100644
--- a/src/theory/quantifiers/bounded_integers.cpp
+++ b/src/theory/quantifiers/bounded_integers.cpp
@@ -28,8 +28,8 @@ using namespace CVC4::theory::quantifiers;
using namespace CVC4::kind;
-BoundedIntegers::RangeModel::RangeModel(BoundedIntegers * bi, Node r, context::Context* c, bool isProxy) : d_bi(bi),
- d_range(r), d_curr_max(-1), d_range_assertions(c), d_has_range(c,false), d_curr_range(c,-1) {
+BoundedIntegers::RangeModel::RangeModel(BoundedIntegers * bi, Node r, context::Context* c, context::Context* u, bool isProxy) : d_bi(bi),
+ d_range(r), d_curr_max(-1), d_lit_to_range(u), d_range_assertions(c), d_has_range(c,false), d_curr_range(c,-1), d_ranges_proxied(u) {
if( options::fmfBoundIntLazy() ){
d_proxy_range = isProxy ? r : NodeManager::currentNM()->mkSkolem( "pbir", r.getType() );
}else{
@@ -59,17 +59,18 @@ 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() ){
+ int vrange = d_lit_to_range[nlit];
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;
+ Trace("bound-int-assert") << ", it is bound literal " << vrange << " 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() ){
- Trace("bound-int-debug") << "Does not need range because of " << it->first << std::endl;
+ for( NodeIntMap::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() ){
+ Trace("bound-int-debug") << "Does not need range because of " << (*it).first << std::endl;
needsRange = false;
break;
}
@@ -79,9 +80,9 @@ void BoundedIntegers::RangeModel::assertNode(Node n) {
}
}
}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];
+ if (!d_has_range || vrange<d_curr_range ){
+ Trace("bound-int-bound") << "Successfully bound " << d_range << " to " << vrange << std::endl;
+ d_curr_range = vrange;
}
//set the range
d_has_range = true;
@@ -111,13 +112,13 @@ void BoundedIntegers::RangeModel::allocateRange() {
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;
+ for( NodeIntMap::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;
+ Node rn = (*it).first;
Assert( !rn.isNull() );
if( d_range_assertions.find( rn )==d_range_assertions.end() ){
- if (!d_lit_to_pol[it->first]) {
+ if (!d_lit_to_pol[rn]) {
rn = rn.negate();
}
Trace("bound-int-dec-debug") << "For " << d_range << ", make decision " << rn << " to make range " << i << std::endl;
@@ -243,8 +244,13 @@ void BoundedIntegers::process( Node f, Node n, bool pol,
}
}
-void BoundedIntegers::check( Theory::Effort e ) {
- if( e==Theory::EFFORT_LAST_CALL ){
+bool BoundedIntegers::needsCheck( Theory::Effort e ) {
+ return e==Theory::EFFORT_LAST_CALL;
+}
+
+void BoundedIntegers::check( Theory::Effort e, unsigned quant_e ) {
+ if( quant_e==QuantifiersEngine::QEFFORT_STANDARD ){
+ Trace("bint-engine") << "---Bounded Integers---" << std::endl;
bool addedLemma = false;
//make sure proxies are up-to-date with range
for( unsigned i=0; i<d_ranges.size(); i++) {
@@ -252,9 +258,7 @@ void BoundedIntegers::check( Theory::Effort e ) {
addedLemma = true;
}
}
- if( addedLemma ){
- d_quantEngine->flushLemmas( &d_quantEngine->getOutputChannel() );
- }
+ Trace("bint-engine") << " addedLemma = " << addedLemma << std::endl;
}
}
@@ -332,7 +336,7 @@ void BoundedIntegers::registerQuantifier( Node f ) {
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(), isProxy );
+ d_rms[r] = new RangeModel(this, r, d_quantEngine->getSatContext(), d_quantEngine->getUserContext(), isProxy );
d_rms[r]->initialize();
}
}
diff --git a/src/theory/quantifiers/bounded_integers.h b/src/theory/quantifiers/bounded_integers.h
index ac188ca65..c09527f89 100644
--- a/src/theory/quantifiers/bounded_integers.h
+++ b/src/theory/quantifiers/bounded_integers.h
@@ -38,6 +38,7 @@ 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;
+ typedef context::CDHashMap<int, bool> IntBoolMap;
private:
//for determining bounds
bool isBound( Node f, Node v );
@@ -62,16 +63,16 @@ private:
void allocateRange();
Node d_proxy_range;
public:
- RangeModel(BoundedIntegers * bi, Node r, context::Context* c, bool isProxy);
+ RangeModel(BoundedIntegers * bi, Node r, context::Context* c, context::Context* u, bool isProxy);
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;
+ NodeIntMap d_lit_to_range;
NodeBoolMap d_range_assertions;
context::CDO< bool > d_has_range;
context::CDO< int > d_curr_range;
- std::map< int, bool > d_ranges_proxied;
+ IntBoolMap d_ranges_proxied;
void initialize();
void assertNode(Node n);
Node getNextDecisionRequest();
@@ -110,7 +111,8 @@ private:
public:
BoundedIntegers( context::Context* c, QuantifiersEngine* qe );
- void check( Theory::Effort e );
+ bool needsCheck( Theory::Effort e );
+ void check( Theory::Effort e, unsigned quant_e );
void registerQuantifier( Node f );
void assertNode( Node n );
Node getNextDecisionRequest();
diff --git a/src/theory/quantifiers/candidate_generator.cpp b/src/theory/quantifiers/candidate_generator.cpp
index 9ce79c301..0f2adf3b4 100644
--- a/src/theory/quantifiers/candidate_generator.cpp
+++ b/src/theory/quantifiers/candidate_generator.cpp
@@ -213,7 +213,10 @@ Node CandidateGeneratorQELitDeq::getNextCandidate(){
CandidateGeneratorQEAll::CandidateGeneratorQEAll( QuantifiersEngine* qe, Node mpat ) :
d_match_pattern( mpat ), d_qe( qe ){
-
+ d_match_pattern_type = mpat.getType();
+ Assert( mpat.getKind()==INST_CONSTANT );
+ d_f = quantifiers::TermDb::getInstConstAttr( mpat );
+ d_index = mpat.getAttribute(InstVarNumAttribute());
}
void CandidateGeneratorQEAll::resetInstantiationRound() {
@@ -227,6 +230,9 @@ void CandidateGeneratorQEAll::reset( Node eqc ) {
Node CandidateGeneratorQEAll::getNextCandidate() {
while( !d_eq.isFinished() ){
Node n = (*d_eq);
+ if( options::instMaxLevel()!=-1 ){
+ n = d_qe->getEqualityQuery()->getInternalRepresentative( n, d_f, d_index );
+ }
++d_eq;
if( n.getType().isSubtypeOf( d_match_pattern.getType() ) ){
//an equivalence class with the same type as the pattern, return it
diff --git a/src/theory/quantifiers/candidate_generator.h b/src/theory/quantifiers/candidate_generator.h
index 4569c2335..011e2924d 100644
--- a/src/theory/quantifiers/candidate_generator.h
+++ b/src/theory/quantifiers/candidate_generator.h
@@ -144,8 +144,12 @@ private:
eq::EqClassesIterator d_eq;
//equality you are trying to match equalities for
Node d_match_pattern;
+ TypeNode d_match_pattern_type;
//einstantiator pointer
QuantifiersEngine* d_qe;
+ // quantifier/index for the variable we are matching
+ Node d_f;
+ unsigned d_index;
public:
CandidateGeneratorQEAll( QuantifiersEngine* qe, Node mpat );
~CandidateGeneratorQEAll(){}
diff --git a/src/theory/quantifiers/ce_guided_instantiation.cpp b/src/theory/quantifiers/ce_guided_instantiation.cpp
new file mode 100644
index 000000000..ffe64beba
--- /dev/null
+++ b/src/theory/quantifiers/ce_guided_instantiation.cpp
@@ -0,0 +1,370 @@
+/********************* */
+/*! \file ce_guided_instantiation.cpp
+ ** \verbatim
+ ** Original author: Andrew Reynolds
+ ** Major contributors: none
+ ** Minor contributors (to current version): none
+ ** This file is part of the CVC4 project.
+ ** Copyright (c) 2009-2014 New York University and The University of Iowa
+ ** See the file COPYING in the top-level source directory for licensing
+ ** information.\endverbatim
+ **
+ ** \brief counterexample guided instantiation class
+ **
+ **/
+
+#include "theory/quantifiers/ce_guided_instantiation.h"
+#include "theory/theory_engine.h"
+#include "theory/quantifiers/options.h"
+#include "theory/quantifiers/term_database.h"
+#include "theory/quantifiers/first_order_model.h"
+
+using namespace CVC4;
+using namespace CVC4::kind;
+using namespace CVC4::theory;
+using namespace CVC4::theory::quantifiers;
+using namespace std;
+
+namespace CVC4 {
+
+CegInstantiation::CegConjecture::CegConjecture( context::Context* c ) : d_active( c, false ), d_infeasible( c, false ), d_curr_lit( c, 0 ){
+
+}
+
+void CegInstantiation::CegConjecture::assign( Node q ) {
+ Assert( d_quant.isNull() );
+ Assert( q.getKind()==FORALL );
+ d_quant = q;
+ for( unsigned i=0; i<q[0].getNumChildren(); i++ ){
+ d_candidates.push_back( NodeManager::currentNM()->mkSkolem( "e", q[0][i].getType() ) );
+ }
+}
+
+void CegInstantiation::CegConjecture::initializeGuard( QuantifiersEngine * qe ){
+ if( d_guard.isNull() ){
+ d_guard = Rewriter::rewrite( NodeManager::currentNM()->mkSkolem( "G", NodeManager::currentNM()->booleanType() ) );
+ //specify guard behavior
+ d_guard = qe->getValuation().ensureLiteral( d_guard );
+ AlwaysAssert( !d_guard.isNull() );
+ qe->getOutputChannel().requirePhase( d_guard, true );
+ if( !d_syntax_guided ){
+ //add immediate lemma
+ Node lem = NodeManager::currentNM()->mkNode( OR, d_guard.negate(), d_base_inst.negate() );
+ Trace("cegqi") << "Add candidate lemma : " << lem << std::endl;
+ qe->getOutputChannel().lemma( lem );
+ }
+ }
+}
+
+Node CegInstantiation::CegConjecture::getLiteral( QuantifiersEngine * qe, int i ) {
+ if( d_measure_term.isNull() ){
+ return Node::null();
+ }else{
+ std::map< int, Node >::iterator it = d_lits.find( i );
+ if( it==d_lits.end() ){
+ Node lit = NodeManager::currentNM()->mkNode( LEQ, d_measure_term, NodeManager::currentNM()->mkConst( Rational( i ) ) );
+ lit = Rewriter::rewrite( lit );
+ d_lits[i] = lit;
+
+ Node lem = NodeManager::currentNM()->mkNode( kind::OR, lit, lit.negate() );
+ Trace("cegqi-lemma") << "Fairness split : " << lem << std::endl;
+ qe->getOutputChannel().lemma( lem );
+ qe->getOutputChannel().requirePhase( lit, true );
+ return lit;
+ }else{
+ return it->second;
+ }
+ }
+}
+
+CegInstantiation::CegInstantiation( QuantifiersEngine * qe, context::Context* c ) : QuantifiersModule( qe ){
+ d_conj = new CegConjecture( d_quantEngine->getSatContext() );
+}
+
+bool CegInstantiation::needsCheck( Theory::Effort e ) {
+ return e>=Theory::EFFORT_LAST_CALL;
+}
+
+bool CegInstantiation::needsModel( Theory::Effort e ) {
+ return true;
+}
+bool CegInstantiation::needsFullModel( Theory::Effort e ) {
+ return false;
+}
+
+void CegInstantiation::check( Theory::Effort e, unsigned quant_e ) {
+ if( quant_e==QuantifiersEngine::QEFFORT_MODEL ){
+ Trace("cegqi-engine") << "---Counterexample Guided Instantiation Engine---" << std::endl;
+ Trace("cegqi-engine-debug") << std::endl;
+ Trace("cegqi-engine-debug") << "Current conjecture status : active : " << d_conj->d_active << " feasible : " << !d_conj->d_infeasible << std::endl;
+ if( d_conj->d_active && !d_conj->d_infeasible ){
+ checkCegConjecture( d_conj );
+ }
+ Trace("cegqi-engine") << "Finished Counterexample Guided Instantiation engine." << std::endl;
+ }
+}
+
+void CegInstantiation::registerQuantifier( Node q ) {
+ if( d_quantEngine->getOwner( q )==this ){
+ if( !d_conj->isAssigned() ){
+ Trace("cegqi") << "Register conjecture : " << q << std::endl;
+ d_conj->assign( q );
+ //construct base instantiation
+ d_conj->d_base_inst = Rewriter::rewrite( d_quantEngine->getInstantiation( q, d_conj->d_candidates ) );
+ Trace("cegqi") << "Base instantiation is : " << d_conj->d_base_inst << std::endl;
+ if( getTermDatabase()->isQAttrSygus( q ) ){
+ Assert( d_conj->d_base_inst.getKind()==NOT );
+ Assert( d_conj->d_base_inst[0].getKind()==FORALL );
+ for( unsigned j=0; j<d_conj->d_base_inst[0][0].getNumChildren(); j++ ){
+ d_conj->d_inner_vars.push_back( d_conj->d_base_inst[0][0][j] );
+ }
+ d_conj->d_syntax_guided = true;
+ }else if( getTermDatabase()->isQAttrSynthesis( q ) ){
+ d_conj->d_syntax_guided = false;
+ }else{
+ Assert( false );
+ }
+ //fairness
+ if( options::ceGuidedInstFair()!=CEGQI_FAIR_NONE ){
+ std::vector< Node > mc;
+ for( unsigned j=0; j<d_conj->d_candidates.size(); j++ ){
+ TypeNode tn = d_conj->d_candidates[j].getType();
+ if( options::ceGuidedInstFair()==CEGQI_FAIR_DT_SIZE ){
+ if( tn.isDatatype() ){
+ mc.push_back( NodeManager::currentNM()->mkNode( DT_SIZE, d_conj->d_candidates[j] ) );
+ }
+ }else if( options::ceGuidedInstFair()==CEGQI_FAIR_UF_DT_SIZE ){
+ registerMeasuredType( tn );
+ std::map< TypeNode, Node >::iterator it = d_uf_measure.find( tn );
+ if( it!=d_uf_measure.end() ){
+ mc.push_back( NodeManager::currentNM()->mkNode( APPLY_UF, it->second, d_conj->d_candidates[j] ) );
+ }
+ }
+ }
+ if( !mc.empty() ){
+ d_conj->d_measure_term = mc.size()==1 ? mc[0] : NodeManager::currentNM()->mkNode( PLUS, mc );
+ Trace("cegqi") << "Measure term is : " << d_conj->d_measure_term << std::endl;
+ }
+ }
+ }else{
+ Assert( d_conj->d_quant==q );
+ }
+ }
+}
+
+void CegInstantiation::assertNode( Node n ) {
+ Trace("cegqi-debug") << "Cegqi : Assert : " << n << std::endl;
+ bool pol = n.getKind()!=NOT;
+ Node lit = n.getKind()==NOT ? n[0] : n;
+ if( lit==d_conj->d_guard ){
+ //d_guard_assertions[lit] = pol;
+ d_conj->d_infeasible = !pol;
+ }
+ if( lit==d_conj->d_quant ){
+ d_conj->d_active = true;
+ }
+}
+
+Node CegInstantiation::getNextDecisionRequest() {
+ d_conj->initializeGuard( d_quantEngine );
+ bool value;
+ if( !d_quantEngine->getValuation().hasSatValue( d_conj->d_guard, value ) ) {
+ if( d_conj->d_guard_split.isNull() ){
+ Node lem = NodeManager::currentNM()->mkNode( OR, d_conj->d_guard.negate(), d_conj->d_guard );
+ d_quantEngine->getOutputChannel().lemma( lem );
+ }
+ Trace("cegqi-debug") << "CEGQI : Decide next on : " << d_conj->d_guard << "..." << std::endl;
+ return d_conj->d_guard;
+ }
+ //enforce fairness
+ if( d_conj->isAssigned() && options::ceGuidedInstFair()!=CEGQI_FAIR_NONE ){
+ Node lit = d_conj->getLiteral( d_quantEngine, d_conj->d_curr_lit.get() );
+ if( d_quantEngine->getValuation().hasSatValue( lit, value ) ) {
+ if( !value ){
+ d_conj->d_curr_lit.set( d_conj->d_curr_lit.get() + 1 );
+ lit = d_conj->getLiteral( d_quantEngine, d_conj->d_curr_lit.get() );
+ Trace("cegqi-debug") << "CEGQI : Decide on next lit : " << lit << "..." << std::endl;
+ return lit;
+ }
+ }else{
+ Trace("cegqi-debug") << "CEGQI : Decide on current lit : " << lit << "..." << std::endl;
+ return lit;
+ }
+ }
+
+ return Node::null();
+}
+
+void CegInstantiation::checkCegConjecture( CegConjecture * conj ) {
+ Node q = conj->d_quant;
+ Trace("cegqi-engine") << "Synthesis conjecture : " << q << std::endl;
+ Trace("cegqi-engine") << " * Candidate program/output symbol : ";
+ for( unsigned i=0; i<conj->d_candidates.size(); i++ ){
+ Trace("cegqi-engine") << conj->d_candidates[i] << " ";
+ }
+ Trace("cegqi-engine") << std::endl;
+ if( options::ceGuidedInstFair()!=CEGQI_FAIR_NONE ){
+ Trace("cegqi-engine") << " * Current term size : " << conj->d_curr_lit.get() << std::endl;
+ }
+
+ if( conj->d_ce_sk.empty() ){
+ Trace("cegqi-engine") << " *** Check candidate phase..." << std::endl;
+ if( getTermDatabase()->isQAttrSygus( q ) ){
+
+ std::vector< Node > model_values;
+ if( getModelValues( conj->d_candidates, model_values ) ){
+ //check if we must apply fairness lemmas
+ std::vector< Node > lems;
+ if( options::ceGuidedInstFair()==CEGQI_FAIR_UF_DT_SIZE ){
+ for( unsigned j=0; j<conj->d_candidates.size(); j++ ){
+ getMeasureLemmas( conj->d_candidates[j], model_values[j], lems );
+ }
+ }
+ if( !lems.empty() ){
+ for( unsigned j=0; j<lems.size(); j++ ){
+ Trace("cegqi-lemma") << "Measure lemma : " << lems[j] << std::endl;
+ d_quantEngine->addLemma( lems[j] );
+ }
+ Trace("cegqi-engine") << " ...refine size." << std::endl;
+ }else{
+ //must get a counterexample to the value of the current candidate
+ Node inst = conj->d_base_inst.substitute( conj->d_candidates.begin(), conj->d_candidates.end(), model_values.begin(), model_values.end() );
+ inst = Rewriter::rewrite( inst );
+ //body should be an existential
+ Assert( inst.getKind()==NOT );
+ Assert( inst[0].getKind()==FORALL );
+ //immediately skolemize
+ Node inst_sk = getTermDatabase()->getSkolemizedBody( inst[0] );
+ Trace("cegqi-lemma") << "Counterexample lemma : " << inst_sk << std::endl;
+ d_quantEngine->addLemma( NodeManager::currentNM()->mkNode( OR, q.negate(), inst_sk.negate() ) );
+ conj->d_ce_sk.push_back( inst[0] );
+ Trace("cegqi-engine") << " ...find counterexample." << std::endl;
+ }
+ }
+
+ }else if( getTermDatabase()->isQAttrSynthesis( q ) ){
+ Trace("cegqi-engine") << " * Value is : ";
+ std::vector< Node > model_terms;
+ for( unsigned i=0; i<conj->d_candidates.size(); i++ ){
+ Node t = getModelTerm( conj->d_candidates[i] );
+ model_terms.push_back( t );
+ Trace("cegqi-engine") << t << " ";
+ }
+ Trace("cegqi-engine") << std::endl;
+ d_quantEngine->addInstantiation( q, model_terms, false );
+ }
+ }else{
+ Trace("cegqi-engine") << " *** Refine candidate phase..." << std::endl;
+ for( unsigned j=0; j<conj->d_ce_sk.size(); j++ ){
+ Node ce_q = conj->d_ce_sk[j];
+ Assert( conj->d_inner_vars.size()==getTermDatabase()->d_skolem_constants[ce_q].size() );
+ std::vector< Node > model_values;
+ if( getModelValues( getTermDatabase()->d_skolem_constants[ce_q], model_values ) ){
+ //candidate refinement : the next candidate must satisfy the counterexample found for the current model of the candidate
+ Node inst_ce_refine = conj->d_base_inst[0][1].substitute( conj->d_inner_vars.begin(), conj->d_inner_vars.end(),
+ model_values.begin(), model_values.end() );
+ Node lem = NodeManager::currentNM()->mkNode( OR, conj->d_guard.negate(), inst_ce_refine );
+ Trace("cegqi-lemma") << "Candidate refinement lemma : " << lem << std::endl;
+ Trace("cegqi-engine") << " ...refine candidate." << std::endl;
+ d_quantEngine->addLemma( lem );
+ }
+ }
+ conj->d_ce_sk.clear();
+ }
+}
+
+bool CegInstantiation::getModelValues( std::vector< Node >& n, std::vector< Node >& v ) {
+ bool success = true;
+ Trace("cegqi-engine") << " * Value is : ";
+ for( unsigned i=0; i<n.size(); i++ ){
+ Node nv = getModelValue( n[i] );
+ v.push_back( nv );
+ Trace("cegqi-engine") << nv << " ";
+ if( nv.isNull() ){
+ success = false;
+ }
+ }
+ Trace("cegqi-engine") << std::endl;
+ return success;
+}
+
+Node CegInstantiation::getModelValue( Node n ) {
+ Trace("cegqi-mv") << "getModelValue for : " << n << std::endl;
+ return d_quantEngine->getModel()->getValue( n );
+}
+
+Node CegInstantiation::getModelTerm( Node n ){
+ //TODO
+ return getModelValue( n );
+}
+
+void CegInstantiation::registerMeasuredType( TypeNode tn ) {
+ std::map< TypeNode, Node >::iterator it = d_uf_measure.find( tn );
+ if( it==d_uf_measure.end() ){
+ if( tn.isDatatype() ){
+ TypeNode op_tn = NodeManager::currentNM()->mkFunctionType( tn, NodeManager::currentNM()->integerType() );
+ Node op = NodeManager::currentNM()->mkSkolem( "tsize", op_tn, "was created by ceg instantiation to enforce fairness." );
+ d_uf_measure[tn] = op;
+ }
+ }
+}
+
+Node CegInstantiation::getSizeTerm( Node n, TypeNode tn, std::vector< Node >& lems ) {
+ std::map< Node, Node >::iterator itt = d_size_term.find( n );
+ if( itt==d_size_term.end() ){
+ registerMeasuredType( tn );
+ Node sn = NodeManager::currentNM()->mkNode( APPLY_UF, d_uf_measure[tn], n );
+ lems.push_back( NodeManager::currentNM()->mkNode( LEQ, NodeManager::currentNM()->mkConst( Rational(0) ), sn ) );
+ d_size_term[n] = sn;
+ return sn;
+ }else{
+ return itt->second;
+ }
+}
+
+void CegInstantiation::getMeasureLemmas( Node n, Node v, std::vector< Node >& lems ) {
+ Trace("cegqi-lemma-debug") << "Get measure lemma " << n << " " << v << std::endl;
+ Assert( n.getType()==v.getType() );
+ TypeNode tn = n.getType();
+ if( tn.isDatatype() ){
+ Assert( v.getKind()==APPLY_CONSTRUCTOR );
+ const Datatype& dt = ((DatatypeType)(tn).toType()).getDatatype();
+ int index = Datatype::indexOf( v.getOperator().toExpr() );
+ std::map< int, Node >::iterator it = d_size_term_lemma[n].find( index );
+ if( it==d_size_term_lemma[n].end() ){
+ Node lhs = getSizeTerm( n, tn, lems );
+ //add measure lemma
+ std::vector< Node > sumc;
+ for( unsigned j=0; j<dt[index].getNumArgs(); j++ ){
+ TypeNode tnc = v[j].getType();
+ if( tnc.isDatatype() ){
+ Node seln = NodeManager::currentNM()->mkNode( APPLY_SELECTOR_TOTAL, Node::fromExpr( dt[index][j].getSelector() ), n );
+ sumc.push_back( getSizeTerm( seln, tnc, lems ) );
+ }
+ }
+ Node rhs;
+ if( !sumc.empty() ){
+ sumc.push_back( NodeManager::currentNM()->mkConst( Rational(1) ) );
+ rhs = NodeManager::currentNM()->mkNode( PLUS, sumc );
+ }else{
+ rhs = NodeManager::currentNM()->mkConst( Rational(0) );
+ }
+ Node lem = lhs.eqNode( rhs );
+ Node cond = NodeManager::currentNM()->mkNode( APPLY_TESTER, Node::fromExpr( dt[index].getTester() ), n );
+ lem = NodeManager::currentNM()->mkNode( OR, cond.negate(), lem );
+
+ d_size_term_lemma[n][index] = lem;
+ Trace("cegqi-lemma-debug") << "...constructed lemma " << lem << std::endl;
+ lems.push_back( lem );
+ //return;
+ }
+ //get lemmas for children
+ for( unsigned i=0; i<v.getNumChildren(); i++ ){
+ Node nn = NodeManager::currentNM()->mkNode( APPLY_SELECTOR_TOTAL, Node::fromExpr( dt[index][i].getSelector() ), n );
+ getMeasureLemmas( nn, v[i], lems );
+ }
+
+ }
+}
+
+}
diff --git a/src/theory/quantifiers/ce_guided_instantiation.h b/src/theory/quantifiers/ce_guided_instantiation.h
new file mode 100644
index 000000000..235f2b01c
--- /dev/null
+++ b/src/theory/quantifiers/ce_guided_instantiation.h
@@ -0,0 +1,117 @@
+/********************* */
+/*! \file ce_guided_instantiation.h
+ ** \verbatim
+ ** Original author: Andrew Reynolds
+ ** Major contributors: none
+ ** Minor contributors (to current version): none
+ ** This file is part of the CVC4 project.
+ ** Copyright (c) 2009-2014 New York University and The University of Iowa
+ ** See the file COPYING in the top-level source directory for licensing
+ ** information.\endverbatim
+ **
+ ** \brief counterexample guided instantiation class
+ **/
+
+#include "cvc4_private.h"
+
+#ifndef CE_GUIDED_INSTANTIATION_H
+#define CE_GUIDED_INSTANTIATION_H
+
+#include "context/cdhashmap.h"
+#include "context/cdchunk_list.h"
+#include "theory/quantifiers_engine.h"
+
+namespace CVC4 {
+namespace theory {
+namespace quantifiers {
+
+class CegInstantiation : public QuantifiersModule
+{
+ typedef context::CDHashMap<Node, bool, NodeHashFunction> NodeBoolMap;
+private:
+ class CegConjecture {
+ public:
+ CegConjecture( context::Context* c );
+ /** is conjecture active */
+ context::CDO< bool > d_active;
+ /** is conjecture infeasible */
+ context::CDO< bool > d_infeasible;
+ /** quantified formula */
+ Node d_quant;
+ /** guard */
+ Node d_guard;
+ /** base instantiation */
+ Node d_base_inst;
+ /** guard split */
+ Node d_guard_split;
+ /** is syntax-guided */
+ bool d_syntax_guided;
+ /** list of constants for quantified formula */
+ std::vector< Node > d_candidates;
+ /** list of variables on inner quantification */
+ std::vector< Node > d_inner_vars;
+ /** initialize guard */
+ void initializeGuard( QuantifiersEngine * qe );
+ /** measure term */
+ Node d_measure_term;
+ /** measure sum size */
+ int d_measure_term_size;
+ /** assign */
+ void assign( Node q );
+ /** is assigned */
+ bool isAssigned() { return !d_quant.isNull(); }
+ /** current extential quantifeirs whose couterexamples we must refine */
+ std::vector< Node > d_ce_sk;
+ public: //for fairness
+ /** the cardinality literals */
+ std::map< int, Node > d_lits;
+ /** current cardinality */
+ context::CDO< int > d_curr_lit;
+ /** allocate literal */
+ Node getLiteral( QuantifiersEngine * qe, int i );
+ };
+ /** the quantified formula stating the synthesis conjecture */
+ CegConjecture * d_conj;
+private: //for enforcing fairness
+ /** measure functions */
+ std::map< TypeNode, Node > d_uf_measure;
+ /** register measured type */
+ void registerMeasuredType( TypeNode tn );
+ /** term -> size term */
+ std::map< Node, Node > d_size_term;
+ /** get size term */
+ Node getSizeTerm( Node n, TypeNode tn, std::vector< Node >& lems );
+ /** term x constructor -> lemma */
+ std::map< Node, std::map< int, Node > > d_size_term_lemma;
+ /** get measure lemmas */
+ void getMeasureLemmas( Node n, Node v, std::vector< Node >& lems );
+private:
+ /** check conjecture */
+ void checkCegConjecture( CegConjecture * conj );
+ /** get model values */
+ bool getModelValues( std::vector< Node >& n, std::vector< Node >& v );
+ /** get model value */
+ Node getModelValue( Node n );
+ /** get model term */
+ Node getModelTerm( Node n );
+public:
+ CegInstantiation( QuantifiersEngine * qe, context::Context* c );
+public:
+ bool needsCheck( Theory::Effort e );
+ bool needsModel( Theory::Effort e );
+ bool needsFullModel( Theory::Effort e );
+ /* Call during quantifier engine's check */
+ void check( Theory::Effort e, unsigned quant_e );
+ /* Called for new quantifiers */
+ void registerQuantifier( Node q );
+ void assertNode( Node n );
+ Node getNextDecisionRequest();
+ /** Identify this module (for debugging, dynamic configuration, etc..) */
+ std::string identify() const { return "CegInstantiation"; }
+};
+
+}
+}
+}
+
+#endif
diff --git a/src/theory/quantifiers/conjecture_generator.cpp b/src/theory/quantifiers/conjecture_generator.cpp
new file mode 100755
index 000000000..871d4ddc6
--- /dev/null
+++ b/src/theory/quantifiers/conjecture_generator.cpp
@@ -0,0 +1,2168 @@
+/********************* */
+/*! \file conjecture_generator.cpp
+ ** \verbatim
+ ** Original author: Andrew Reynolds
+ ** Major contributors: none
+ ** Minor contributors (to current version): none
+ ** This file is part of the CVC4 project.
+ ** Copyright (c) 2009-2014 New York University and The University of Iowa
+ ** See the file COPYING in the top-level source directory for licensing
+ ** information.\endverbatim
+ **
+ ** \brief conjecture generator class
+ **
+ **/
+
+#include "theory/quantifiers/conjecture_generator.h"
+#include "theory/theory_engine.h"
+#include "theory/quantifiers/options.h"
+#include "theory/quantifiers/term_database.h"
+#include "theory/quantifiers/trigger.h"
+#include "theory/quantifiers/first_order_model.h"
+
+using namespace CVC4;
+using namespace CVC4::kind;
+using namespace CVC4::theory;
+using namespace CVC4::theory::quantifiers;
+using namespace std;
+
+namespace CVC4 {
+
+struct sortConjectureScore {
+ std::vector< int > d_scores;
+ bool operator() (unsigned i, unsigned j) { return d_scores[i]>d_scores[j]; }
+};
+
+
+void OpArgIndex::addTerm( ConjectureGenerator * s, TNode n, unsigned index ){
+ if( index==n.getNumChildren() ){
+ Assert( n.hasOperator() );
+ if( std::find( d_ops.begin(), d_ops.end(), n.getOperator() )==d_ops.end() ){
+ d_ops.push_back( n.getOperator() );
+ d_op_terms.push_back( n );
+ }
+ }else{
+ d_child[s->getTermDatabase()->d_arg_reps[n][index]].addTerm( s, n, index+1 );
+ }
+}
+
+Node OpArgIndex::getGroundTerm( ConjectureGenerator * s, std::vector< TNode >& args ) {
+ if( d_ops.empty() ){
+ for( std::map< TNode, OpArgIndex >::iterator it = d_child.begin(); it != d_child.end(); ++it ){
+ std::map< TNode, Node >::iterator itf = s->d_ground_eqc_map.find( it->first );
+ if( itf!=s->d_ground_eqc_map.end() ){
+ args.push_back( itf->second );
+ Node n = it->second.getGroundTerm( s, args );
+ args.pop_back();
+ if( !n.isNull() ){
+ return n;
+ }
+ }
+ }
+ return Node::null();
+ }else{
+ std::vector< TNode > args2;
+ args2.push_back( d_ops[0] );
+ args2.insert( args2.end(), args.begin(), args.end() );
+ return NodeManager::currentNM()->mkNode( d_op_terms[0].getKind(), args2 );
+ }
+}
+
+void OpArgIndex::getGroundTerms( ConjectureGenerator * s, std::vector< TNode >& terms ) {
+ terms.insert( terms.end(), d_op_terms.begin(), d_op_terms.end() );
+ for( std::map< TNode, OpArgIndex >::iterator it = d_child.begin(); it != d_child.end(); ++it ){
+ if( s->isGroundEqc( it->first ) ){
+ it->second.getGroundTerms( s, terms );
+ }
+ }
+}
+
+
+
+ConjectureGenerator::ConjectureGenerator( QuantifiersEngine * qe, context::Context* c ) : QuantifiersModule( qe ),
+d_notify( *this ),
+d_uequalityEngine(d_notify, c, "ConjectureGenerator::ee"),
+d_ee_conjectures( c ){
+ d_fullEffortCount = 0;
+ d_uequalityEngine.addFunctionKind( kind::APPLY_UF );
+ d_uequalityEngine.addFunctionKind( kind::APPLY_CONSTRUCTOR );
+
+}
+
+void ConjectureGenerator::eqNotifyNewClass( TNode t ){
+ Trace("thm-ee-debug") << "UEE : new equivalence class " << t << std::endl;
+ d_upendingAdds.push_back( t );
+}
+
+void ConjectureGenerator::eqNotifyPreMerge(TNode t1, TNode t2) {
+ //get maintained representatives
+ TNode rt1 = t1;
+ TNode rt2 = t2;
+ std::map< Node, EqcInfo* >::iterator it1 = d_eqc_info.find( t1 );
+ if( it1!=d_eqc_info.end() && !it1->second->d_rep.get().isNull() ){
+ rt1 = it1->second->d_rep.get();
+ }
+ std::map< Node, EqcInfo* >::iterator it2 = d_eqc_info.find( t2 );
+ if( it2!=d_eqc_info.end() && !it2->second->d_rep.get().isNull() ){
+ rt2 = it2->second->d_rep.get();
+ }
+ Trace("thm-ee-debug") << "UEE : equality holds : " << t1 << " == " << t2 << std::endl;
+ Trace("thm-ee-debug") << " ureps : " << rt1 << " == " << rt2 << std::endl;
+ Trace("thm-ee-debug") << " relevant : " << d_pattern_is_relevant[rt1] << " " << d_pattern_is_relevant[rt2] << std::endl;
+ Trace("thm-ee-debug") << " normal : " << d_pattern_is_normal[rt1] << " " << d_pattern_is_normal[rt2] << std::endl;
+ Trace("thm-ee-debug") << " size : " << d_pattern_fun_sum[rt1] << " " << d_pattern_fun_sum[rt2] << std::endl;
+
+ if( isUniversalLessThan( rt2, rt1 ) ){
+ EqcInfo * ei;
+ if( it1==d_eqc_info.end() ){
+ ei = getOrMakeEqcInfo( t1, true );
+ }else{
+ ei = it1->second;
+ }
+ ei->d_rep = t2;
+ }
+}
+
+void ConjectureGenerator::eqNotifyPostMerge(TNode t1, TNode t2) {
+
+}
+
+void ConjectureGenerator::eqNotifyDisequal(TNode t1, TNode t2, TNode reason) {
+ Trace("thm-ee-debug") << "UEE : disequality holds : " << t1 << " != " << t2 << std::endl;
+
+}
+
+
+ConjectureGenerator::EqcInfo::EqcInfo( context::Context* c ) : d_rep( c, Node::null() ){
+
+}
+
+ConjectureGenerator::EqcInfo* ConjectureGenerator::getOrMakeEqcInfo( TNode n, bool doMake ) {
+ //Assert( getUniversalRepresentative( n )==n );
+ std::map< Node, EqcInfo* >::iterator eqc_i = d_eqc_info.find( n );
+ if( eqc_i!=d_eqc_info.end() ){
+ return eqc_i->second;
+ }else if( doMake ){
+ EqcInfo* ei = new EqcInfo( d_quantEngine->getSatContext() );
+ d_eqc_info[n] = ei;
+ return ei;
+ }else{
+ return NULL;
+ }
+}
+
+void ConjectureGenerator::setUniversalRelevant( TNode n ) {
+ //add pattern information
+ registerPattern( n, n.getType() );
+ d_urelevant_terms[n] = true;
+ for( unsigned i=0; i<n.getNumChildren(); i++ ){
+ setUniversalRelevant( n[i] );
+ }
+}
+
+bool ConjectureGenerator::isUniversalLessThan( TNode rt1, TNode rt2 ) {
+ //prefer the one that is (normal, smaller) lexographically
+ Assert( d_pattern_is_relevant.find( rt1 )!=d_pattern_is_relevant.end() );
+ Assert( d_pattern_is_relevant.find( rt2 )!=d_pattern_is_relevant.end() );
+ Assert( d_pattern_is_normal.find( rt1 )!=d_pattern_is_normal.end() );
+ Assert( d_pattern_is_normal.find( rt2 )!=d_pattern_is_normal.end() );
+ Assert( d_pattern_fun_sum.find( rt1 )!=d_pattern_fun_sum.end() );
+ Assert( d_pattern_fun_sum.find( rt2 )!=d_pattern_fun_sum.end() );
+
+ if( d_pattern_is_relevant[rt1] && !d_pattern_is_relevant[rt2] ){
+ Trace("thm-ee-debug") << "UEE : LT due to relevant." << std::endl;
+ return true;
+ }else if( d_pattern_is_relevant[rt1]==d_pattern_is_relevant[rt2] ){
+ if( d_pattern_is_normal[rt1] && !d_pattern_is_normal[rt2] ){
+ Trace("thm-ee-debug") << "UEE : LT due to normal." << std::endl;
+ return true;
+ }else if( d_pattern_is_normal[rt1]==d_pattern_is_normal[rt2] ){
+ if( d_pattern_fun_sum[rt1]<d_pattern_fun_sum[rt2] ){
+ Trace("thm-ee-debug") << "UEE : LT due to size." << std::endl;
+ //decide which representative to use : based on size of the term
+ return true;
+ }else if( d_pattern_fun_sum[rt1]==d_pattern_fun_sum[rt2] ){
+ //same size : tie goes to term that has already been reported
+ return isReportedCanon( rt1 ) && !isReportedCanon( rt2 );
+ }
+ }
+ }
+ return false;
+}
+
+
+bool ConjectureGenerator::isReportedCanon( TNode n ) {
+ return std::find( d_ue_canon.begin(), d_ue_canon.end(), n )==d_ue_canon.end();
+}
+
+void ConjectureGenerator::markReportedCanon( TNode n ) {
+ if( !isReportedCanon( n ) ){
+ d_ue_canon.push_back( n );
+ }
+}
+
+bool ConjectureGenerator::areUniversalEqual( TNode n1, TNode n2 ) {
+ return n1==n2 || ( d_uequalityEngine.hasTerm( n1 ) && d_uequalityEngine.hasTerm( n2 ) && d_uequalityEngine.areEqual( n1, n2 ) );
+}
+
+bool ConjectureGenerator::areUniversalDisequal( TNode n1, TNode n2 ) {
+ return n1!=n2 && d_uequalityEngine.hasTerm( n1 ) && d_uequalityEngine.hasTerm( n2 ) && d_uequalityEngine.areDisequal( n1, n2, false );
+}
+
+TNode ConjectureGenerator::getUniversalRepresentative( TNode n, bool add ) {
+ if( add ){
+ if( d_urelevant_terms.find( n )==d_urelevant_terms.end() ){
+ setUniversalRelevant( n );
+ //add term to universal equality engine
+ d_uequalityEngine.addTerm( n );
+ // addding this term to equality engine will lead to a set of new terms (the new subterms of n)
+ // now, do instantiation-based merging for each of these terms
+ Trace("thm-ee-debug") << "Merge equivalence classes based on instantiations of terms..." << std::endl;
+ //merge all pending equalities
+ while( !d_upendingAdds.empty() ){
+ Trace("sg-pending") << "Add " << d_upendingAdds.size() << " pending terms..." << std::endl;
+ std::vector< Node > pending;
+ pending.insert( pending.end(), d_upendingAdds.begin(), d_upendingAdds.end() );
+ d_upendingAdds.clear();
+ for( unsigned i=0; i<pending.size(); i++ ){
+ Node t = pending[i];
+ TypeNode tn = t.getType();
+ Trace("thm-ee-add") << "UEE : Add universal term " << t << std::endl;
+ std::vector< Node > eq_terms;
+ //if occurs modulo equality at ground level, it is equivalent to representative of ground equality engine
+ TNode gt = getTermDatabase()->evaluateTerm( t );
+ if( !gt.isNull() && gt!=t ){
+ eq_terms.push_back( gt );
+ }
+ //get all equivalent terms based on theorem database
+ d_thm_index.getEquivalentTerms( t, eq_terms );
+ if( !eq_terms.empty() ){
+ Trace("thm-ee-add") << "UEE : Based on ground EE/theorem DB, it is equivalent to " << eq_terms.size() << " terms : " << std::endl;
+ //add equivalent terms as equalities to universal engine
+ for( unsigned i=0; i<eq_terms.size(); i++ ){
+ Trace("thm-ee-add") << " " << eq_terms[i] << std::endl;
+ bool assertEq = false;
+ if( d_urelevant_terms.find( eq_terms[i] )!=d_urelevant_terms.end() ){
+ assertEq = true;
+ }else{
+ Assert( eq_terms[i].getType()==tn );
+ registerPattern( eq_terms[i], tn );
+ if( isUniversalLessThan( eq_terms[i], t ) || ( options::conjectureUeeIntro() && d_pattern_fun_sum[t]>=d_pattern_fun_sum[eq_terms[i]] ) ){
+ setUniversalRelevant( eq_terms[i] );
+ assertEq = true;
+ }
+ }
+ if( assertEq ){
+ Node exp;
+ d_uequalityEngine.assertEquality( t.eqNode( eq_terms[i] ), true, exp );
+ }else{
+ Trace("thm-ee-no-add") << "Do not add : " << t << " == " << eq_terms[i] << std::endl;
+ }
+ }
+ }else{
+ Trace("thm-ee-add") << "UEE : No equivalent terms." << std::endl;
+ }
+ }
+ }
+ }
+ }
+
+ if( d_uequalityEngine.hasTerm( n ) ){
+ Node r = d_uequalityEngine.getRepresentative( n );
+ EqcInfo * ei = getOrMakeEqcInfo( r );
+ if( ei && !ei->d_rep.get().isNull() ){
+ return ei->d_rep.get();
+ }else{
+ return r;
+ }
+ }else{
+ return n;
+ }
+}
+
+Node ConjectureGenerator::getFreeVar( TypeNode tn, unsigned i ) {
+ Assert( !tn.isNull() );
+ while( d_free_var[tn].size()<=i ){
+ std::stringstream oss;
+ oss << tn;
+ std::stringstream os;
+ os << oss.str()[0] << i;
+ Node x = NodeManager::currentNM()->mkBoundVar( os.str().c_str(), tn );
+ d_free_var_num[x] = d_free_var[tn].size();
+ d_free_var[tn].push_back( x );
+ }
+ return d_free_var[tn][i];
+}
+
+
+
+Node ConjectureGenerator::getCanonicalTerm( TNode n, std::map< TypeNode, unsigned >& var_count, std::map< TNode, TNode >& subs ) {
+ if( n.getKind()==BOUND_VARIABLE ){
+ std::map< TNode, TNode >::iterator it = subs.find( n );
+ if( it==subs.end() ){
+ TypeNode tn = n.getType();
+ //allocate variable
+ unsigned vn = var_count[tn];
+ var_count[tn]++;
+ subs[n] = getFreeVar( tn, vn );
+ return subs[n];
+ }else{
+ return it->second;
+ }
+ }else{
+ std::vector< Node > children;
+ if( n.getKind()!=EQUAL ){
+ if( n.hasOperator() ){
+ TNode op = n.getOperator();
+ if( !d_tge.isRelevantFunc( op ) ){
+ return Node::null();
+ }
+ children.push_back( op );
+ }else{
+ return Node::null();
+ }
+ }
+ for( unsigned i=0; i<n.getNumChildren(); i++ ){
+ Node cn = getCanonicalTerm( n[i], var_count, subs );
+ if( cn.isNull() ){
+ return Node::null();
+ }else{
+ children.push_back( cn );
+ }
+ }
+ return NodeManager::currentNM()->mkNode( n.getKind(), children );
+ }
+}
+
+bool ConjectureGenerator::isHandledTerm( TNode n ){
+ return !n.getAttribute(NoMatchAttribute()) && inst::Trigger::isAtomicTrigger( n ) && ( n.getKind()!=APPLY_UF || n.getOperator().getKind()!=SKOLEM );
+}
+
+Node ConjectureGenerator::getGroundEqc( TNode r ) {
+ std::map< TNode, Node >::iterator it = d_ground_eqc_map.find( r );
+ return it!=d_ground_eqc_map.end() ? it->second : Node::null();
+}
+
+bool ConjectureGenerator::isGroundEqc( TNode r ) {
+ return d_ground_eqc_map.find( r )!=d_ground_eqc_map.end();
+}
+
+bool ConjectureGenerator::isGroundTerm( TNode n ) {
+ return std::find( d_ground_terms.begin(), d_ground_terms.end(), n )!=d_ground_terms.end();
+}
+
+bool ConjectureGenerator::needsCheck( Theory::Effort e ) {
+ return e==Theory::EFFORT_FULL;
+}
+
+bool ConjectureGenerator::hasEnumeratedUf( Node n ) {
+ if( options::conjectureGenGtEnum()>0 ){
+ std::map< Node, bool >::iterator it = d_uf_enum.find( n.getOperator() );
+ if( it==d_uf_enum.end() ){
+ d_uf_enum[n.getOperator()] = true;
+ std::vector< Node > lem;
+ getEnumeratePredUfTerm( n, options::conjectureGenGtEnum(), lem );
+ if( !lem.empty() ){
+ for( unsigned j=0; j<lem.size(); j++ ){
+ d_quantEngine->addLemma( lem[j], false );
+ d_hasAddedLemma = true;
+ }
+ return false;
+ }
+ }
+ }
+ return true;
+}
+
+void ConjectureGenerator::reset_round( Theory::Effort e ) {
+
+}
+
+void ConjectureGenerator::check( Theory::Effort e, unsigned quant_e ) {
+ if( quant_e==QuantifiersEngine::QEFFORT_STANDARD ){
+ d_fullEffortCount++;
+ if( d_fullEffortCount%optFullCheckFrequency()==0 ){
+ d_hasAddedLemma = false;
+ d_tge.d_cg = this;
+ double clSet = 0;
+ if( Trace.isOn("sg-engine") ){
+ clSet = double(clock())/double(CLOCKS_PER_SEC);
+ Trace("sg-engine") << "---Conjecture Engine Round, effort = " << e << "---" << std::endl;
+ }
+ eq::EqualityEngine * ee = getEqualityEngine();
+ d_conj_count = 0;
+
+ Trace("sg-proc") << "Get eq classes..." << std::endl;
+ d_op_arg_index.clear();
+ d_ground_eqc_map.clear();
+ d_bool_eqc[0] = Node::null();
+ d_bool_eqc[1] = Node::null();
+ std::vector< TNode > eqcs;
+ d_em.clear();
+ eq::EqClassesIterator eqcs_i = eq::EqClassesIterator( ee );
+ while( !eqcs_i.isFinished() ){
+ TNode r = (*eqcs_i);
+ eqcs.push_back( r );
+ if( r.getType().isBoolean() ){
+ if( areEqual( r, getTermDatabase()->d_true ) ){
+ d_ground_eqc_map[r] = getTermDatabase()->d_true;
+ d_bool_eqc[0] = r;
+ }else if( areEqual( r, getTermDatabase()->d_false ) ){
+ d_ground_eqc_map[r] = getTermDatabase()->d_false;
+ d_bool_eqc[1] = r;
+ }
+ }
+ d_em[r] = eqcs.size();
+ eq::EqClassIterator ieqc_i = eq::EqClassIterator( r, ee );
+ while( !ieqc_i.isFinished() ){
+ TNode n = (*ieqc_i);
+ if( isHandledTerm( n ) ){
+ d_op_arg_index[r].addTerm( this, n );
+ }
+ ++ieqc_i;
+ }
+ ++eqcs_i;
+ }
+ Assert( !d_bool_eqc[0].isNull() );
+ Assert( !d_bool_eqc[1].isNull() );
+ d_urelevant_terms.clear();
+ Trace("sg-proc") << "...done get eq classes" << std::endl;
+
+ Trace("sg-proc") << "Determine ground EQC..." << std::endl;
+ bool success;
+ do{
+ success = false;
+ for( unsigned i=0; i<eqcs.size(); i++ ){
+ TNode r = eqcs[i];
+ if( d_ground_eqc_map.find( r )==d_ground_eqc_map.end() ){
+ std::vector< TNode > args;
+ Trace("sg-pat-debug") << "******* Get ground term for " << r << std::endl;
+ Node n;
+ if( getTermDatabase()->isInductionTerm( r ) ){
+ n = d_op_arg_index[r].getGroundTerm( this, args );
+ }else{
+ n = r;
+ }
+ if( !n.isNull() ){
+ Trace("sg-pat") << "Ground term for eqc " << r << " : " << std::endl;
+ Trace("sg-pat") << " " << n << std::endl;
+ d_ground_eqc_map[r] = n;
+ success = true;
+ }else{
+ Trace("sg-pat-debug") << "...could not find ground term." << std::endl;
+ }
+ }
+ }
+ }while( success );
+ //also get ground terms
+ d_ground_terms.clear();
+ for( unsigned i=0; i<eqcs.size(); i++ ){
+ TNode r = eqcs[i];
+ d_op_arg_index[r].getGroundTerms( this, d_ground_terms );
+ }
+ Trace("sg-proc") << "...done determine ground EQC" << std::endl;
+
+ //debug printing
+ if( Trace.isOn("sg-gen-eqc") ){
+ for( unsigned i=0; i<eqcs.size(); i++ ){
+ TNode r = eqcs[i];
+ //print out members
+ bool firstTime = true;
+ bool isFalse = areEqual( r, getTermDatabase()->d_false );
+ eq::EqClassIterator eqc_i = eq::EqClassIterator( r, ee );
+ while( !eqc_i.isFinished() ){
+ TNode n = (*eqc_i);
+ if( !n.getAttribute(NoMatchAttribute()) && ( n.getKind()!=EQUAL || isFalse ) ){
+ if( firstTime ){
+ Trace("sg-gen-eqc") << "e" << d_em[r] << " : { " << std::endl;
+ firstTime = false;
+ }
+ if( n.hasOperator() ){
+ Trace("sg-gen-eqc") << " (" << n.getOperator();
+ getTermDatabase()->computeArgReps( n );
+ for( unsigned i=0; i<getTermDatabase()->d_arg_reps[n].size(); i++ ){
+ Trace("sg-gen-eqc") << " e" << d_em[getTermDatabase()->d_arg_reps[n][i]];
+ }
+ Trace("sg-gen-eqc") << ") :: " << n << std::endl;
+ }else{
+ Trace("sg-gen-eqc") << " " << n << std::endl;
+ }
+ }
+ ++eqc_i;
+ }
+ if( !firstTime ){
+ Trace("sg-gen-eqc") << "}" << std::endl;
+ //print out ground term
+ std::map< TNode, Node >::iterator it = d_ground_eqc_map.find( r );
+ if( it!=d_ground_eqc_map.end() ){
+ Trace("sg-gen-eqc") << "- Ground term : " << it->second << std::endl;
+ }
+ }
+ }
+ }
+
+ Trace("sg-proc") << "Compute relevant eqc..." << std::endl;
+ d_tge.d_relevant_eqc[0].clear();
+ d_tge.d_relevant_eqc[1].clear();
+ for( unsigned i=0; i<eqcs.size(); i++ ){
+ TNode r = eqcs[i];
+ std::map< TNode, Node >::iterator it = d_ground_eqc_map.find( r );
+ unsigned index = 1;
+ if( it==d_ground_eqc_map.end() ){
+ index = 0;
+ }
+ //based on unproven conjectures? TODO
+ d_tge.d_relevant_eqc[index].push_back( r );
+ }
+ Trace("sg-gen-tg-debug") << "Initial relevant eqc : ";
+ for( unsigned i=0; i<d_tge.d_relevant_eqc[0].size(); i++ ){
+ Trace("sg-gen-tg-debug") << "e" << d_em[d_tge.d_relevant_eqc[0][i]] << " ";
+ }
+ Trace("sg-gen-tg-debug") << std::endl;
+ Trace("sg-proc") << "...done compute relevant eqc" << std::endl;
+
+
+ Trace("sg-proc") << "Collect signature information..." << std::endl;
+ d_tge.collectSignatureInformation();
+ if( d_hasAddedLemma ){
+ Trace("sg-proc") << "...added enumeration lemmas." << std::endl;
+ }
+ Trace("sg-proc") << "...done collect signature information" << std::endl;
+
+
+
+ Trace("sg-proc") << "Build theorem index..." << std::endl;
+ d_ue_canon.clear();
+ d_thm_index.clear();
+ std::vector< Node > provenConj;
+ quantifiers::FirstOrderModel* m = d_quantEngine->getModel();
+ for( int i=0; i<m->getNumAssertedQuantifiers(); i++ ){
+ Node q = m->getAssertedQuantifier( i );
+ Trace("thm-db-debug") << "Is " << q << " a relevant theorem?" << std::endl;
+ Node conjEq;
+ if( q[1].getKind()==EQUAL ){
+ bool isSubsume = false;
+ bool inEe = false;
+ for( unsigned r=0; r<2; r++ ){
+ TNode nl = q[1][r==0 ? 0 : 1];
+ TNode nr = q[1][r==0 ? 1 : 0];
+ Node eq = nl.eqNode( nr );
+ if( r==1 || std::find( d_conjectures.begin(), d_conjectures.end(), q )==d_conjectures.end() ){
+ //must make it canonical
+ std::map< TypeNode, unsigned > var_count;
+ std::map< TNode, TNode > subs;
+ Trace("sg-proc-debug") << "get canonical " << eq << std::endl;
+ eq = getCanonicalTerm( eq, var_count, subs );
+ }
+ if( !eq.isNull() ){
+ if( r==0 ){
+ inEe = d_ee_conjectures.find( q[1] )!=d_ee_conjectures.end();
+ if( !inEe ){
+ //add to universal equality engine
+ Node nl = getUniversalRepresentative( eq[0], true );
+ Node nr = getUniversalRepresentative( eq[1], true );
+ if( areUniversalEqual( nl, nr ) ){
+ isSubsume = true;
+ //set inactive (will be ignored by other modules)
+ d_quantEngine->getModel()->setQuantifierActive( q, false );
+ }else{
+ Node exp;
+ d_ee_conjectures[q[1]] = true;
+ d_uequalityEngine.assertEquality( nl.eqNode( nr ), true, exp );
+ }
+ }
+ Trace("sg-conjecture") << "*** CONJECTURE : currently proven" << (isSubsume ? " and subsumed" : "");
+ Trace("sg-conjecture") << " : " << q[1] << std::endl;
+ provenConj.push_back( q );
+ }
+ if( !isSubsume ){
+ Trace("thm-db-debug") << "Adding theorem to database " << eq[0] << " == " << eq[1] << std::endl;
+ d_thm_index.addTheorem( eq[0], eq[1] );
+ }else{
+ break;
+ }
+ }else{
+ break;
+ }
+ }
+ }
+ }
+ //examine status of other conjectures
+ for( unsigned i=0; i<d_conjectures.size(); i++ ){
+ Node q = d_conjectures[i];
+ if( std::find( provenConj.begin(), provenConj.end(), q )==provenConj.end() ){
+ //check each skolem variable
+ bool disproven = true;
+ //std::vector< Node > sk;
+ //getTermDatabase()->getSkolemConstants( q, sk, true );
+ Trace("sg-conjecture") << " CONJECTURE : ";
+ std::vector< Node > ce;
+ for( unsigned j=0; j<getTermDatabase()->d_skolem_constants[q].size(); j++ ){
+ TNode k = getTermDatabase()->d_skolem_constants[q][j];
+ TNode rk = getRepresentative( k );
+ std::map< TNode, Node >::iterator git = d_ground_eqc_map.find( rk );
+ //check if it is a ground term
+ if( git==d_ground_eqc_map.end() ){
+ Trace("sg-conjecture") << "ACTIVE : " << q;
+ if( Trace.isOn("sg-gen-eqc") ){
+ Trace("sg-conjecture") << " { ";
+ for( unsigned k=0; k<getTermDatabase()->d_skolem_constants[q].size(); k++ ){ Trace("sg-conjecture") << getTermDatabase()->d_skolem_constants[q][k] << ( j==k ? "*" : "" ) << " "; }
+ Trace("sg-conjecture") << "}";
+ }
+ Trace("sg-conjecture") << std::endl;
+ disproven = false;
+ break;
+ }else{
+ ce.push_back( git->second );
+ }
+ }
+ if( disproven ){
+ Trace("sg-conjecture") << "disproven : " << q << " : ";
+ for( unsigned i=0; i<ce.size(); i++ ){
+ Trace("sg-conjecture") << q[0][i] << " -> " << ce[i] << " ";
+ }
+ Trace("sg-conjecture") << std::endl;
+ }
+ }
+ }
+ Trace("thm-db") << "Theorem database is : " << std::endl;
+ d_thm_index.debugPrint( "thm-db" );
+ Trace("thm-db") << std::endl;
+ Trace("sg-proc") << "...done build theorem index" << std::endl;
+
+
+ //clear patterns
+ d_patterns.clear();
+ d_pattern_var_id.clear();
+ d_pattern_var_duplicate.clear();
+ d_pattern_is_normal.clear();
+ d_pattern_is_relevant.clear();
+ d_pattern_fun_id.clear();
+ d_pattern_fun_sum.clear();
+ d_rel_patterns.clear();
+ d_rel_pattern_var_sum.clear();
+ d_rel_pattern_typ_index.clear();
+ d_rel_pattern_subs_index.clear();
+
+ unsigned rel_term_count = 0;
+ std::map< TypeNode, unsigned > rt_var_max;
+ std::vector< TypeNode > rt_types;
+ std::map< TypeNode, std::map< int, std::vector< Node > > > conj_lhs;
+ unsigned addedLemmas = 0;
+ for( unsigned depth=1; depth<=3; depth++ ){
+ Trace("sg-proc") << "Generate relevant LHS at depth " << depth << "..." << std::endl;
+ Trace("sg-rel-term") << "Relevant terms of depth " << depth << " : " << std::endl;
+ //set up environment
+ d_tge.d_var_id.clear();
+ d_tge.d_var_limit.clear();
+ d_tge.reset( depth, true, TypeNode::null() );
+ while( d_tge.getNextTerm() ){
+ //construct term
+ Node nn = d_tge.getTerm();
+ if( !options::conjectureFilterCanonical() || considerTermCanon( nn, true ) ){
+ rel_term_count++;
+ Trace("sg-rel-term") << "*** Relevant term : ";
+ d_tge.debugPrint( "sg-rel-term", "sg-rel-term-debug2" );
+ Trace("sg-rel-term") << std::endl;
+
+ for( unsigned r=0; r<2; r++ ){
+ Trace("sg-rel-term-debug") << "...from equivalence classes (" << r << ") : ";
+ int index = d_tge.d_ccand_eqc[r].size()-1;
+ for( unsigned j=0; j<d_tge.d_ccand_eqc[r][index].size(); j++ ){
+ Trace("sg-rel-term-debug") << "e" << d_em[d_tge.d_ccand_eqc[r][index][j]] << " ";
+ }
+ Trace("sg-rel-term-debug") << std::endl;
+ }
+ TypeNode tnn = nn.getType();
+ Trace("sg-gen-tg-debug") << "...term is " << nn << std::endl;
+ conj_lhs[tnn][depth].push_back( nn );
+
+ //add information about pattern
+ Trace("sg-gen-tg-debug") << "Collect pattern information..." << std::endl;
+ Assert( std::find( d_rel_patterns[tnn].begin(), d_rel_patterns[tnn].end(), nn )==d_rel_patterns[tnn].end() );
+ d_rel_patterns[tnn].push_back( nn );
+ //build information concerning the variables in this pattern
+ unsigned sum = 0;
+ std::map< TypeNode, unsigned > typ_to_subs_index;
+ std::vector< TNode > gsubs_vars;
+ for( std::map< TypeNode, unsigned >::iterator it = d_tge.d_var_id.begin(); it != d_tge.d_var_id.end(); ++it ){
+ if( it->second>0 ){
+ typ_to_subs_index[it->first] = sum;
+ sum += it->second;
+ for( unsigned i=0; i<it->second; i++ ){
+ gsubs_vars.push_back( getFreeVar( it->first, i ) );
+ }
+ }
+ }
+ d_rel_pattern_var_sum[nn] = sum;
+ //register the pattern
+ registerPattern( nn, tnn );
+ Assert( d_pattern_is_normal[nn] );
+ Trace("sg-gen-tg-debug") << "...done collect pattern information" << std::endl;
+
+ //record information about types
+ Trace("sg-gen-tg-debug") << "Collect type information..." << std::endl;
+ PatternTypIndex * pti = &d_rel_pattern_typ_index;
+ for( std::map< TypeNode, unsigned >::iterator it = d_tge.d_var_id.begin(); it != d_tge.d_var_id.end(); ++it ){
+ pti = &pti->d_children[it->first][it->second];
+ //record maximum
+ if( rt_var_max.find( it->first )==rt_var_max.end() || it->second>rt_var_max[it->first] ){
+ rt_var_max[it->first] = it->second;
+ }
+ }
+ if( std::find( rt_types.begin(), rt_types.end(), tnn )==rt_types.end() ){
+ rt_types.push_back( tnn );
+ }
+ pti->d_terms.push_back( nn );
+ Trace("sg-gen-tg-debug") << "...done collect type information" << std::endl;
+
+ Trace("sg-gen-tg-debug") << "Build substitutions for ground EQC..." << std::endl;
+ std::vector< TNode > gsubs_terms;
+ gsubs_terms.resize( gsubs_vars.size() );
+ int index = d_tge.d_ccand_eqc[1].size()-1;
+ for( unsigned j=0; j<d_tge.d_ccand_eqc[1][index].size(); j++ ){
+ TNode r = d_tge.d_ccand_eqc[1][index][j];
+ Trace("sg-rel-term-debug") << " Matches for e" << d_em[r] << ", which is ground term " << d_ground_eqc_map[r] << ":" << std::endl;
+ std::map< TypeNode, std::map< unsigned, TNode > > subs;
+ std::map< TNode, bool > rev_subs;
+ //only get ground terms
+ unsigned mode = 2;
+ d_tge.resetMatching( r, mode );
+ while( d_tge.getNextMatch( r, subs, rev_subs ) ){
+ //we will be building substitutions
+ bool firstTime = true;
+ for( std::map< TypeNode, std::map< unsigned, TNode > >::iterator it = subs.begin(); it != subs.end(); ++it ){
+ unsigned tindex = typ_to_subs_index[it->first];
+ for( std::map< unsigned, TNode >::iterator it2 = it->second.begin(); it2 != it->second.end(); ++it2 ){
+ if( !firstTime ){
+ Trace("sg-rel-term-debug") << ", ";
+ }else{
+ firstTime = false;
+ Trace("sg-rel-term-debug") << " ";
+ }
+ Trace("sg-rel-term-debug") << it->first << ":x" << it2->first << " -> " << it2->second;
+ Assert( tindex+it2->first<gsubs_terms.size() );
+ gsubs_terms[tindex+it2->first] = it2->second;
+ }
+ }
+ Trace("sg-rel-term-debug") << std::endl;
+ d_rel_pattern_subs_index[nn].addSubstitution( r, gsubs_vars, gsubs_terms );
+ }
+ }
+ Trace("sg-gen-tg-debug") << "...done build substitutions for ground EQC" << std::endl;
+ }else{
+ Trace("sg-gen-tg-debug") << "> not canonical : " << nn << std::endl;
+ }
+ }
+ Trace("sg-proc") << "...done generate terms at depth " << depth << std::endl;
+ Trace("sg-stats") << "--------> Total LHS of depth " << depth << " : " << rel_term_count << std::endl;
+ //Trace("conjecture-count") << "Total LHS of depth " << depth << " : " << conj_lhs[depth].size() << std::endl;
+
+ /* test...
+ for( unsigned i=0; i<rt_types.size(); i++ ){
+ Trace("sg-term-enum") << "Term enumeration for " << rt_types[i] << " : " << std::endl;
+ Trace("sg-term-enum") << "Ground term : " << rt_types[i].mkGroundTerm() << std::endl;
+ for( unsigned j=0; j<150; j++ ){
+ Trace("sg-term-enum") << " " << getEnumerateTerm( rt_types[i], j ) << std::endl;
+ }
+ }
+ */
+
+ //consider types from relevant terms
+ for( unsigned rdepth=0; rdepth<=depth; rdepth++ ){
+ //set up environment
+ d_tge.d_var_id.clear();
+ d_tge.d_var_limit.clear();
+ for( std::map< TypeNode, unsigned >::iterator it = rt_var_max.begin(); it != rt_var_max.end(); ++it ){
+ d_tge.d_var_id[ it->first ] = it->second;
+ d_tge.d_var_limit[ it->first ] = it->second;
+ }
+ std::random_shuffle( rt_types.begin(), rt_types.end() );
+ std::map< TypeNode, std::vector< Node > > conj_rhs;
+ for( unsigned i=0; i<rt_types.size(); i++ ){
+
+ Trace("sg-proc") << "Generate relevant RHS terms of type " << rt_types[i] << " at depth " << rdepth << "..." << std::endl;
+ d_tge.reset( rdepth, false, rt_types[i] );
+
+ while( d_tge.getNextTerm() ){
+ Node rhs = d_tge.getTerm();
+ if( considerTermCanon( rhs, false ) ){
+ Trace("sg-rel-prop") << "Relevant RHS : " << rhs << std::endl;
+ //register pattern
+ Assert( rhs.getType()==rt_types[i] );
+ registerPattern( rhs, rt_types[i] );
+ if( rdepth<depth ){
+ //consider against all LHS at depth
+ for( unsigned j=0; j<conj_lhs[rt_types[i]][depth].size(); j++ ){
+ processCandidateConjecture( conj_lhs[rt_types[i]][depth][j], rhs, depth, rdepth );
+ }
+ }else{
+ conj_rhs[rt_types[i]].push_back( rhs );
+ }
+ }
+ }
+ }
+ flushWaitingConjectures( addedLemmas, depth, rdepth );
+ //consider against all LHS up to depth
+ if( rdepth==depth ){
+ for( unsigned lhs_depth = 1; lhs_depth<=depth; lhs_depth++ ){
+ if( (int)addedLemmas<options::conjectureGenPerRound() ){
+ Trace("sg-proc") << "Consider conjectures at depth (" << lhs_depth << ", " << rdepth << ")..." << std::endl;
+ for( std::map< TypeNode, std::vector< Node > >::iterator it = conj_rhs.begin(); it != conj_rhs.end(); ++it ){
+ for( unsigned j=0; j<it->second.size(); j++ ){
+ for( unsigned k=0; k<conj_lhs[it->first][lhs_depth].size(); k++ ){
+ processCandidateConjecture( conj_lhs[it->first][lhs_depth][k], it->second[j], lhs_depth, rdepth );
+ }
+ }
+ }
+ flushWaitingConjectures( addedLemmas, lhs_depth, depth );
+ }
+ }
+ }
+ if( (int)addedLemmas>=options::conjectureGenPerRound() ){
+ break;
+ }
+ }
+ if( (int)addedLemmas>=options::conjectureGenPerRound() ){
+ break;
+ }
+ }
+ Trace("sg-stats") << "Total conjectures considered : " << d_conj_count << std::endl;
+ if( Trace.isOn("thm-ee") ){
+ Trace("thm-ee") << "Universal equality engine is : " << std::endl;
+ eq::EqClassesIterator ueqcs_i = eq::EqClassesIterator( &d_uequalityEngine );
+ while( !ueqcs_i.isFinished() ){
+ TNode r = (*ueqcs_i);
+ bool firstTime = true;
+ TNode rr = getUniversalRepresentative( r );
+ Trace("thm-ee") << " " << rr;
+ Trace("thm-ee") << " : { ";
+ eq::EqClassIterator ueqc_i = eq::EqClassIterator( r, &d_uequalityEngine );
+ while( !ueqc_i.isFinished() ){
+ TNode n = (*ueqc_i);
+ if( rr!=n ){
+ if( firstTime ){
+ Trace("thm-ee") << std::endl;
+ firstTime = false;
+ }
+ Trace("thm-ee") << " " << n << std::endl;
+ }
+ ++ueqc_i;
+ }
+ if( !firstTime ){ Trace("thm-ee") << " "; }
+ Trace("thm-ee") << "}" << std::endl;
+ ++ueqcs_i;
+ }
+ Trace("thm-ee") << std::endl;
+ }
+ if( Trace.isOn("sg-engine") ){
+ double clSet2 = double(clock())/double(CLOCKS_PER_SEC);
+ Trace("sg-engine") << "Finished conjecture generator, time = " << (clSet2-clSet) << std::endl;
+ }
+ }
+ }
+}
+
+unsigned ConjectureGenerator::flushWaitingConjectures( unsigned& addedLemmas, int ldepth, int rdepth ) {
+ if( !d_waiting_conjectures_lhs.empty() ){
+ Trace("sg-proc") << "Generated " << d_waiting_conjectures_lhs.size() << " conjectures at depth " << ldepth << "/" << rdepth << "." << std::endl;
+ if( (int)addedLemmas<options::conjectureGenPerRound() ){
+ /*
+ std::vector< unsigned > indices;
+ for( unsigned i=0; i<d_waiting_conjectures_lhs.size(); i++ ){
+ indices.push_back( i );
+ }
+ bool doSort = false;
+ if( doSort ){
+ //sort them based on score
+ sortConjectureScore scs;
+ scs.d_scores.insert( scs.d_scores.begin(), d_waiting_conjectures_score.begin(), d_waiting_conjectures_score.end() );
+ std::sort( indices.begin(), indices.end(), scs );
+ }
+ //if( doSort && d_waiting_conjectures_score[indices[0]]<optFilterScoreThreshold() ){
+ */
+ unsigned prevCount = d_conj_count;
+ for( unsigned i=0; i<d_waiting_conjectures_lhs.size(); i++ ){
+ if( d_waiting_conjectures_score[i]>=optFilterScoreThreshold() ){
+ //we have determined a relevant subgoal
+ Node lhs = d_waiting_conjectures_lhs[i];
+ Node rhs = d_waiting_conjectures_rhs[i];
+ if( options::conjectureFilterCanonical() && ( getUniversalRepresentative( lhs )!=lhs || getUniversalRepresentative( rhs )!=rhs ) ){
+ //skip
+ }else{
+ Trace("sg-engine") << "*** Consider conjecture : " << lhs << " == " << rhs << std::endl;
+ Trace("sg-engine-debug") << " score : " << d_waiting_conjectures_score[i] << std::endl;
+ if( optStatsOnly() ){
+ d_conj_count++;
+ }else{
+ std::vector< Node > bvs;
+ for( std::map< TypeNode, unsigned >::iterator it = d_pattern_var_id[lhs].begin(); it != d_pattern_var_id[lhs].end(); ++it ){
+ for( unsigned i=0; i<=it->second; i++ ){
+ bvs.push_back( getFreeVar( it->first, i ) );
+ }
+ }
+ Node rsg;
+ if( !bvs.empty() ){
+ Node bvl = NodeManager::currentNM()->mkNode( BOUND_VAR_LIST, bvs );
+ rsg = NodeManager::currentNM()->mkNode( FORALL, bvl, lhs.eqNode( rhs ) );
+ }else{
+ rsg = lhs.eqNode( rhs );
+ }
+ rsg = Rewriter::rewrite( rsg );
+ d_conjectures.push_back( rsg );
+ d_eq_conjectures[lhs].push_back( rhs );
+ d_eq_conjectures[rhs].push_back( lhs );
+
+ Node lem = NodeManager::currentNM()->mkNode( OR, rsg.negate(), rsg );
+ d_quantEngine->addLemma( lem, false );
+ d_quantEngine->addRequirePhase( rsg, false );
+ addedLemmas++;
+ if( (int)addedLemmas>=options::conjectureGenPerRound() ){
+ break;
+ }
+ }
+ }
+ }
+ }
+ Trace("sg-proc") << "...have now added " << addedLemmas << " conjecture lemmas." << std::endl;
+ if( optStatsOnly() ){
+ Trace("sg-stats") << "Generated " << (d_conj_count-prevCount) << " conjectures at depth " << ldepth << "/" << rdepth << "." << std::endl;
+ }
+ }
+ d_waiting_conjectures_lhs.clear();
+ d_waiting_conjectures_rhs.clear();
+ d_waiting_conjectures_score.clear();
+ d_waiting_conjectures.clear();
+ }
+ return addedLemmas;
+}
+
+void ConjectureGenerator::registerQuantifier( Node q ) {
+
+}
+
+void ConjectureGenerator::assertNode( Node n ) {
+
+}
+
+bool ConjectureGenerator::considerTermCanon( Node ln, bool genRelevant ){
+ if( !ln.isNull() ){
+ //do not consider if it is non-canonical, and either:
+ // (1) we are not generating relevant terms, or
+ // (2) its canonical form is a generalization.
+ TNode lnr = getUniversalRepresentative( ln, true );
+ if( lnr==ln ){
+ markReportedCanon( ln );
+ }else if( !genRelevant || isGeneralization( lnr, ln ) ){
+ Trace("sg-gen-consider-term") << "Do not consider term, " << ln << " is not canonical representation (which is " << lnr << ")." << std::endl;
+ return false;
+ }
+ }
+ Trace("sg-gen-tg-debug") << "Will consider term canon " << ln << std::endl;
+ Trace("sg-gen-consider-term-debug") << std::endl;
+ return true;
+}
+
+unsigned ConjectureGenerator::collectFunctions( TNode opat, TNode pat, std::map< TNode, unsigned >& funcs,
+ std::map< TypeNode, unsigned >& mnvn, std::map< TypeNode, unsigned >& mxvn ){
+ if( pat.hasOperator() ){
+ funcs[pat.getOperator()]++;
+ if( !d_tge.isRelevantFunc( pat.getOperator() ) ){
+ d_pattern_is_relevant[opat] = false;
+ }
+ unsigned sum = 1;
+ for( unsigned i=0; i<pat.getNumChildren(); i++ ){
+ sum += collectFunctions( opat, pat[i], funcs, mnvn, mxvn );
+ }
+ return sum;
+ }else{
+ Assert( pat.getNumChildren()==0 );
+ funcs[pat]++;
+ //for variables
+ if( pat.getKind()==BOUND_VARIABLE ){
+ if( funcs[pat]>1 ){
+ //duplicate variable
+ d_pattern_var_duplicate[opat]++;
+ }else{
+ //check for max/min
+ TypeNode tn = pat.getType();
+ unsigned vn = d_free_var_num[pat];
+ std::map< TypeNode, unsigned >::iterator it = mnvn.find( tn );
+ if( it!=mnvn.end() ){
+ if( vn<it->second ){
+ d_pattern_is_normal[opat] = false;
+ mnvn[tn] = vn;
+ }else if( vn>mxvn[tn] ){
+ if( vn!=mxvn[tn]+1 ){
+ d_pattern_is_normal[opat] = false;
+ }
+ mxvn[tn] = vn;
+ }
+ }else{
+ //first variable of this type
+ mnvn[tn] = vn;
+ mxvn[tn] = vn;
+ }
+ }
+ }else{
+ d_pattern_is_relevant[opat] = false;
+ }
+ return 1;
+ }
+}
+
+void ConjectureGenerator::registerPattern( Node pat, TypeNode tpat ) {
+ if( std::find( d_patterns[tpat].begin(), d_patterns[tpat].end(), pat )==d_patterns[tpat].end() ){
+ d_patterns[TypeNode::null()].push_back( pat );
+ d_patterns[tpat].push_back( pat );
+
+ Assert( d_pattern_fun_id.find( pat )==d_pattern_fun_id.end() );
+ Assert( d_pattern_var_id.find( pat )==d_pattern_var_id.end() );
+
+ //collect functions
+ std::map< TypeNode, unsigned > mnvn;
+ d_pattern_fun_sum[pat] = collectFunctions( pat, pat, d_pattern_fun_id[pat], mnvn, d_pattern_var_id[pat] );
+ if( d_pattern_is_normal.find( pat )==d_pattern_is_normal.end() ){
+ d_pattern_is_normal[pat] = true;
+ }
+ if( d_pattern_is_relevant.find( pat )==d_pattern_is_relevant.end() ){
+ d_pattern_is_relevant[pat] = true;
+ }
+ }
+}
+
+bool ConjectureGenerator::isGeneralization( TNode patg, TNode pat, std::map< TNode, TNode >& subs ) {
+ if( patg.getKind()==BOUND_VARIABLE ){
+ std::map< TNode, TNode >::iterator it = subs.find( patg );
+ if( it!=subs.end() ){
+ return it->second==pat;
+ }else{
+ subs[patg] = pat;
+ return true;
+ }
+ }else{
+ Assert( patg.hasOperator() );
+ if( !pat.hasOperator() || patg.getOperator()!=pat.getOperator() ){
+ return false;
+ }else{
+ Assert( patg.getNumChildren()==pat.getNumChildren() );
+ for( unsigned i=0; i<patg.getNumChildren(); i++ ){
+ if( !isGeneralization( patg[i], pat[i], subs ) ){
+ return false;
+ }
+ }
+ return true;
+ }
+ }
+}
+
+int ConjectureGenerator::calculateGeneralizationDepth( TNode n, std::vector< TNode >& fv ) {
+ if( n.getKind()==BOUND_VARIABLE ){
+ if( std::find( fv.begin(), fv.end(), n )==fv.end() ){
+ fv.push_back( n );
+ return 0;
+ }else{
+ return 1;
+ }
+ }else{
+ int depth = 1;
+ for( unsigned i=0; i<n.getNumChildren(); i++ ){
+ depth += calculateGeneralizationDepth( n[i], fv );
+ }
+ return depth;
+ }
+}
+
+Node ConjectureGenerator::getPredicateForType( TypeNode tn ) {
+ std::map< TypeNode, Node >::iterator it = d_typ_pred.find( tn );
+ if( it==d_typ_pred.end() ){
+ TypeNode op_tn = NodeManager::currentNM()->mkFunctionType( tn, NodeManager::currentNM()->booleanType() );
+ Node op = NodeManager::currentNM()->mkSkolem( "PE", op_tn, "was created by conjecture ground term enumerator." );
+ d_typ_pred[tn] = op;
+ return op;
+ }else{
+ return it->second;
+ }
+}
+
+void ConjectureGenerator::getEnumerateUfTerm( Node n, unsigned num, std::vector< Node >& terms ) {
+ if( n.getNumChildren()>0 ){
+ std::vector< int > vec;
+ for( unsigned i=0; i<n.getNumChildren(); i++ ){
+ vec.push_back( 0 );
+ }
+ vec.pop_back();
+ int size_limit = 0;
+ int vec_sum = -1;
+ unsigned index = 0;
+ unsigned last_size = terms.size();
+ while( terms.size()<num ){
+ bool success = true;
+ if( vec_sum==-1 ){
+ vec_sum = 0;
+ vec.push_back( size_limit );
+ }else{
+ //see if we can iterate current
+ if( vec_sum<size_limit && !getTermDatabase()->getEnumerateTerm( n[index].getType(), vec[index]+1 ).isNull() ){
+ vec[index]++;
+ vec_sum++;
+ vec.push_back( size_limit - vec_sum );
+ }else{
+ vec_sum -= vec[index];
+ vec[index] = 0;
+ index++;
+ if( index==n.getNumChildren() ){
+ success = false;
+ }
+ }
+ }
+ if( success ){
+ if( vec.size()==n.getNumChildren() ){
+ Node lc = getTermDatabase()->getEnumerateTerm( n[vec.size()-1].getType(), vec[vec.size()-1] );
+ if( !lc.isNull() ){
+ for( unsigned i=0; i<vec.size(); i++ ){
+ Trace("sg-gt-enum-debug") << vec[i] << " ";
+ }
+ Trace("sg-gt-enum-debug") << " / " << size_limit << std::endl;
+ for( unsigned i=0; i<n.getNumChildren(); i++ ){
+ Trace("sg-gt-enum-debug") << n[i].getType() << " ";
+ }
+ Trace("sg-gt-enum-debug") << std::endl;
+ std::vector< Node > children;
+ children.push_back( n.getOperator() );
+ for( unsigned i=0; i<(vec.size()-1); i++ ){
+ Node nn = getTermDatabase()->getEnumerateTerm( n[i].getType(), vec[i] );
+ Assert( !nn.isNull() );
+ Assert( nn.getType()==n[i].getType() );
+ children.push_back( nn );
+ }
+ children.push_back( lc );
+ Node n = NodeManager::currentNM()->mkNode( APPLY_UF, children );
+ Trace("sg-gt-enum") << "Ground term enumerate : " << n << std::endl;
+ terms.push_back( n );
+ }
+ vec.pop_back();
+ index = 0;
+ }
+ }else{
+ if( terms.size()>last_size ){
+ last_size = terms.size();
+ size_limit++;
+ for( unsigned i=0; i<vec.size(); i++ ){
+ vec[i] = 0;
+ }
+ vec_sum = -1;
+ }
+ }
+ }
+ }else{
+ terms.push_back( n );
+ }
+}
+
+void ConjectureGenerator::getEnumeratePredUfTerm( Node n, unsigned num, std::vector< Node >& terms ) {
+ std::vector< Node > uf_terms;
+ getEnumerateUfTerm( n, num, uf_terms );
+ Node p = getPredicateForType( n.getType() );
+ for( unsigned i=0; i<uf_terms.size(); i++ ){
+ terms.push_back( NodeManager::currentNM()->mkNode( APPLY_UF, p, uf_terms[i] ) );
+ }
+}
+
+void ConjectureGenerator::processCandidateConjecture( TNode lhs, TNode rhs, unsigned lhs_depth, unsigned rhs_depth ) {
+ int score = considerCandidateConjecture( lhs, rhs );
+ if( score>0 ){
+ Trace("sg-conjecture") << "* Candidate conjecture : " << lhs << " == " << rhs << std::endl;
+ Trace("sg-conjecture-debug") << " LHS, RHS generalization depth : " << lhs_depth << ", " << rhs_depth << std::endl;
+ Trace("sg-conjecture-debug") << " confirmed = " << d_subs_confirmCount << ", #witnesses range = " << d_subs_confirmWitnessRange.size() << "." << std::endl;
+ Trace("sg-conjecture-debug") << " #witnesses for ";
+ bool firstTime = true;
+ for( std::map< TNode, std::vector< TNode > >::iterator it = d_subs_confirmWitnessDomain.begin(); it != d_subs_confirmWitnessDomain.end(); ++it ){
+ if( !firstTime ){
+ Trace("sg-conjecture-debug") << ", ";
+ }
+ Trace("sg-conjecture-debug") << it->first << " : " << it->second.size();
+ //if( it->second.size()==1 ){
+ // Trace("sg-conjecture-debug") << " (" << it->second[0] << ")";
+ //}
+ Trace("sg-conjecture-debug2") << " (";
+ for( unsigned j=0; j<it->second.size(); j++ ){
+ if( j>0 ){ Trace("sg-conjecture-debug2") << " "; }
+ Trace("sg-conjecture-debug2") << d_ground_eqc_map[it->second[j]];
+ }
+ Trace("sg-conjecture-debug2") << ")";
+ firstTime = false;
+ }
+ Trace("sg-conjecture-debug") << std::endl;
+ Trace("sg-conjecture-debug") << " unknown = " << d_subs_unkCount << std::endl;
+ //Assert( getUniversalRepresentative( rhs )==rhs );
+ //Assert( getUniversalRepresentative( lhs )==lhs );
+ d_waiting_conjectures_lhs.push_back( lhs );
+ d_waiting_conjectures_rhs.push_back( rhs );
+ d_waiting_conjectures_score.push_back( score );
+ d_waiting_conjectures[lhs].push_back( rhs );
+ d_waiting_conjectures[rhs].push_back( lhs );
+ }
+}
+
+int ConjectureGenerator::considerCandidateConjecture( TNode lhs, TNode rhs ) {
+ Assert( lhs.getType()==rhs.getType() );
+
+ Trace("sg-cconj-debug") << "Consider candidate conjecture : " << lhs << " == " << rhs << "?" << std::endl;
+ if( lhs==rhs ){
+ Trace("sg-cconj-debug") << " -> trivial." << std::endl;
+ return -1;
+ }else{
+ if( lhs.getKind()==APPLY_CONSTRUCTOR && rhs.getKind()==APPLY_CONSTRUCTOR ){
+ Trace("sg-cconj-debug") << " -> irrelevant by syntactic analysis." << std::endl;
+ return -1;
+ }
+ //variables of LHS must subsume variables of RHS
+ for( std::map< TypeNode, unsigned >::iterator it = d_pattern_var_id[rhs].begin(); it != d_pattern_var_id[rhs].end(); ++it ){
+ std::map< TypeNode, unsigned >::iterator itl = d_pattern_var_id[lhs].find( it->first );
+ if( itl!=d_pattern_var_id[lhs].end() ){
+ if( itl->second<it->second ){
+ Trace("sg-cconj-debug") << " -> variables of sort " << it->first << " are not subsumed." << std::endl;
+ return -1;
+ }else{
+ Trace("sg-cconj-debug2") << " variables of sort " << it->first << " are : " << itl->second << " vs " << it->second << std::endl;
+ }
+ }else{
+ Trace("sg-cconj-debug") << " -> has no variables of sort " << it->first << "." << std::endl;
+ return -1;
+ }
+ }
+
+ //currently active conjecture?
+ std::map< Node, std::vector< Node > >::iterator iteq = d_eq_conjectures.find( lhs );
+ if( iteq!=d_eq_conjectures.end() ){
+ if( std::find( iteq->second.begin(), iteq->second.end(), rhs )!=iteq->second.end() ){
+ Trace("sg-cconj-debug") << " -> this conjecture is already active." << std::endl;
+ return -1;
+ }
+ }
+ //current a waiting conjecture?
+ std::map< Node, std::vector< Node > >::iterator itw = d_waiting_conjectures.find( lhs );
+ if( itw!=d_waiting_conjectures.end() ){
+ if( std::find( itw->second.begin(), itw->second.end(), rhs )!=itw->second.end() ){
+ Trace("sg-cconj-debug") << " -> already are considering this conjecture." << std::endl;
+ return -1;
+ }
+ }
+ //check if canonical representation (should be, but for efficiency this is not guarenteed)
+ //if( options::conjectureFilterCanonical() && ( getUniversalRepresentative( lhs )!=lhs || getUniversalRepresentative( rhs )!=rhs ) ){
+ // Trace("sg-cconj") << " -> after processing, not canonical." << std::endl;
+ // return -1;
+ //}
+
+ int score;
+ bool scoreSet = false;
+
+ Trace("sg-cconj") << "Consider possible candidate conjecture : " << lhs << " == " << rhs << "?" << std::endl;
+ //find witness for counterexample, if possible
+ if( options::conjectureFilterModel() ){
+ Assert( d_rel_pattern_var_sum.find( lhs )!=d_rel_pattern_var_sum.end() );
+ Trace("sg-cconj-debug") << "Notify substitutions over " << d_rel_pattern_var_sum[lhs] << " variables." << std::endl;
+ std::map< TNode, TNode > subs;
+ d_subs_confirmCount = 0;
+ d_subs_confirmWitnessRange.clear();
+ d_subs_confirmWitnessDomain.clear();
+ d_subs_unkCount = 0;
+ if( !d_rel_pattern_subs_index[lhs].notifySubstitutions( this, subs, rhs, d_rel_pattern_var_sum[lhs] ) ){
+ Trace("sg-cconj") << " -> found witness that falsifies the conjecture." << std::endl;
+ return -1;
+ }
+ //score is the minimum number of distinct substitutions for a variable
+ for( std::map< TNode, std::vector< TNode > >::iterator it = d_subs_confirmWitnessDomain.begin(); it != d_subs_confirmWitnessDomain.end(); ++it ){
+ int num = (int)it->second.size();
+ if( !scoreSet || num<score ){
+ score = num;
+ scoreSet = true;
+ }
+ }
+ if( !scoreSet ){
+ score = 0;
+ }
+ Trace("sg-cconj") << " confirmed = " << d_subs_confirmCount << ", #witnesses range = " << d_subs_confirmWitnessRange.size() << "." << std::endl;
+ for( std::map< TNode, std::vector< TNode > >::iterator it = d_subs_confirmWitnessDomain.begin(); it != d_subs_confirmWitnessDomain.end(); ++it ){
+ Trace("sg-cconj") << " #witnesses for " << it->first << " : " << it->second.size() << std::endl;
+ }
+ }else{
+ score = 1;
+ }
+
+ Trace("sg-cconj") << " -> SUCCESS." << std::endl;
+ Trace("sg-cconj") << " score : " << score << std::endl;
+
+ return score;
+ }
+}
+
+bool ConjectureGenerator::notifySubstitution( TNode glhs, std::map< TNode, TNode >& subs, TNode rhs ) {
+ if( Trace.isOn("sg-cconj-debug") ){
+ Trace("sg-cconj-debug") << "Ground eqc for LHS : " << glhs << ", based on substituion: " << std::endl;
+ for( std::map< TNode, TNode >::iterator it = subs.begin(); it != subs.end(); ++it ){
+ Assert( getRepresentative( it->second )==it->second );
+ Trace("sg-cconj-debug") << " " << it->first << " -> " << it->second << std::endl;
+ }
+ }
+ Trace("sg-cconj-debug") << "Evaluate RHS : : " << rhs << std::endl;
+ //get the representative of rhs with substitution subs
+ TNode grhs = getTermDatabase()->evaluateTerm( rhs, subs, true );
+ Trace("sg-cconj-debug") << "...done evaluating term, got : " << grhs << std::endl;
+ if( !grhs.isNull() ){
+ if( glhs!=grhs ){
+ Trace("sg-cconj-debug") << "Ground eqc for RHS : " << grhs << std::endl;
+ //check based on ground terms
+ std::map< TNode, Node >::iterator itl = d_ground_eqc_map.find( glhs );
+ if( itl!=d_ground_eqc_map.end() ){
+ std::map< TNode, Node >::iterator itr = d_ground_eqc_map.find( grhs );
+ if( itr!=d_ground_eqc_map.end() ){
+ Trace("sg-cconj-debug") << "We have ground terms " << itl->second << " and " << itr->second << "." << std::endl;
+ if( itl->second.isConst() && itr->second.isConst() ){
+ Trace("sg-cconj-debug") << "...disequal constants." << std::endl;
+ Trace("sg-cconj-witness") << " Witness of falsification : " << itl->second << " != " << itr->second << ", substutition is : " << std::endl;
+ for( std::map< TNode, TNode >::iterator it = subs.begin(); it != subs.end(); ++it ){
+ Trace("sg-cconj-witness") << " " << it->first << " -> " << it->second << std::endl;
+ }
+ return false;
+ }
+ }
+ }
+ }
+ Trace("sg-cconj-debug") << "RHS is identical." << std::endl;
+ bool isGroundSubs = true;
+ for( std::map< TNode, TNode >::iterator it = subs.begin(); it != subs.end(); ++it ){
+ std::map< TNode, Node >::iterator git = d_ground_eqc_map.find( it->second );
+ if( git==d_ground_eqc_map.end() ){
+ isGroundSubs = false;
+ break;
+ }
+ }
+ if( isGroundSubs ){
+ if( glhs==grhs ){
+ Trace("sg-cconj-witness") << " Witnessed " << glhs << " == " << grhs << ", substutition is : " << std::endl;
+ for( std::map< TNode, TNode >::iterator it = subs.begin(); it != subs.end(); ++it ){
+ Trace("sg-cconj-witness") << " " << it->first << " -> " << it->second << std::endl;
+ if( std::find( d_subs_confirmWitnessDomain[it->first].begin(), d_subs_confirmWitnessDomain[it->first].end(), it->second )==d_subs_confirmWitnessDomain[it->first].end() ){
+ d_subs_confirmWitnessDomain[it->first].push_back( it->second );
+ }
+ }
+ d_subs_confirmCount++;
+ if( std::find( d_subs_confirmWitnessRange.begin(), d_subs_confirmWitnessRange.end(), glhs )==d_subs_confirmWitnessRange.end() ){
+ d_subs_confirmWitnessRange.push_back( glhs );
+ }
+ }else{
+ if( optFilterUnknown() ){
+ Trace("sg-cconj-debug") << "...ground substitution giving terms that are neither equal nor disequal." << std::endl;
+ return false;
+ }
+ }
+ }
+ }else{
+ Trace("sg-cconj-debug") << "(could not ground eqc for RHS)." << std::endl;
+ }
+ return true;
+}
+
+
+
+
+
+
+void TermGenerator::reset( TermGenEnv * s, TypeNode tn ) {
+ Assert( d_children.empty() );
+ d_typ = tn;
+ d_status = 0;
+ d_status_num = 0;
+ d_children.clear();
+ Trace("sg-gen-tg-debug2") << "...add to context " << this << std::endl;
+ d_id = s->d_tg_id;
+ s->changeContext( true );
+}
+
+bool TermGenerator::getNextTerm( TermGenEnv * s, unsigned depth ) {
+ if( Trace.isOn("sg-gen-tg-debug2") ){
+ Trace("sg-gen-tg-debug2") << this << " getNextTerm depth " << depth << " : status = " << d_status << ", num = " << d_status_num;
+ if( d_status==5 ){
+ TNode f = s->getTgFunc( d_typ, d_status_num );
+ Trace("sg-gen-tg-debug2") << ", f = " << f;
+ Trace("sg-gen-tg-debug2") << ", #args = " << s->d_func_args[f].size();
+ Trace("sg-gen-tg-debug2") << ", childNum = " << d_status_child_num;
+ Trace("sg-gen-tg-debug2") << ", #children = " << d_children.size();
+ }
+ Trace("sg-gen-tg-debug2") << std::endl;
+ }
+
+ if( d_status==0 ){
+ d_status++;
+ if( !d_typ.isNull() ){
+ if( s->allowVar( d_typ ) ){
+ //allocate variable
+ d_status_num = s->d_var_id[d_typ];
+ s->addVar( d_typ );
+ Trace("sg-gen-tg-debug2") << this << " ...return unique var #" << d_status_num << std::endl;
+ return s->considerCurrentTerm() ? true : getNextTerm( s, depth );
+ }else{
+ //check allocating new variable
+ d_status++;
+ d_status_num = -1;
+ if( s->d_gen_relevant_terms ){
+ s->d_tg_gdepth++;
+ }
+ return getNextTerm( s, depth );
+ }
+ }else{
+ d_status = 4;
+ d_status_num = -1;
+ return getNextTerm( s, depth );
+ }
+ }else if( d_status==2 ){
+ //cleanup previous information
+ //if( d_status_num>=0 ){
+ // s->d_var_eq_tg[d_status_num].pop_back();
+ //}
+ //check if there is another variable
+ if( (d_status_num+1)<(int)s->getNumTgVars( d_typ ) ){
+ d_status_num++;
+ //we have equated two variables
+ //s->d_var_eq_tg[d_status_num].push_back( d_id );
+ Trace("sg-gen-tg-debug2") << this << "...consider other var #" << d_status_num << std::endl;
+ return s->considerCurrentTerm() ? true : getNextTerm( s, depth );
+ }else{
+ if( s->d_gen_relevant_terms ){
+ s->d_tg_gdepth--;
+ }
+ d_status++;
+ return getNextTerm( s, depth );
+ }
+ }else if( d_status==4 ){
+ d_status++;
+ if( depth>0 && (d_status_num+1)<(int)s->getNumTgFuncs( d_typ ) ){
+ d_status_num++;
+ d_status_child_num = 0;
+ Trace("sg-gen-tg-debug2") << this << "...consider function " << s->getTgFunc( d_typ, d_status_num ) << std::endl;
+ s->d_tg_gdepth++;
+ if( !s->considerCurrentTerm() ){
+ s->d_tg_gdepth--;
+ //don't consider this function
+ d_status--;
+ }else{
+ //we have decided on a function application
+ }
+ return getNextTerm( s, depth );
+ }else{
+ //do not choose function applications at depth 0
+ d_status++;
+ return getNextTerm( s, depth );
+ }
+ }else if( d_status==5 ){
+ //iterating over arguments
+ TNode f = s->getTgFunc( d_typ, d_status_num );
+ if( d_status_child_num<0 ){
+ //no more arguments
+ s->d_tg_gdepth--;
+ d_status--;
+ return getNextTerm( s, depth );
+ }else if( d_status_child_num==(int)s->d_func_args[f].size() ){
+ d_status_child_num--;
+ return s->considerCurrentTermCanon( d_id ) ? true : getNextTerm( s, depth );
+ //return true;
+ }else{
+ Assert( d_status_child_num<(int)s->d_func_args[f].size() );
+ if( d_status_child_num==(int)d_children.size() ){
+ d_children.push_back( s->d_tg_id );
+ Assert( s->d_tg_alloc.find( s->d_tg_id )==s->d_tg_alloc.end() );
+ s->d_tg_alloc[d_children[d_status_child_num]].reset( s, s->d_func_args[f][d_status_child_num] );
+ return getNextTerm( s, depth );
+ }else{
+ Assert( d_status_child_num+1==(int)d_children.size() );
+ if( s->d_tg_alloc[d_children[d_status_child_num]].getNextTerm( s, depth-1 ) ){
+ d_status_child_num++;
+ return getNextTerm( s, depth );
+ }else{
+ d_children.pop_back();
+ d_status_child_num--;
+ return getNextTerm( s, depth );
+ }
+ }
+ }
+ }else if( d_status==1 || d_status==3 ){
+ if( d_status==1 ){
+ s->removeVar( d_typ );
+ Assert( d_status_num==(int)s->d_var_id[d_typ] );
+ //check if there is only one feasible equivalence class. if so, don't make pattern any more specific.
+ //unsigned i = s->d_ccand_eqc[0].size()-1;
+ //if( s->d_ccand_eqc[0][i].size()==1 && s->d_ccand_eqc[1][i].empty() ){
+ // d_status = 6;
+ // return getNextTerm( s, depth );
+ //}
+ s->d_tg_gdepth++;
+ }
+ d_status++;
+ d_status_num = -1;
+ return getNextTerm( s, depth );
+ }else{
+ //clean up
+ Assert( d_children.empty() );
+ Trace("sg-gen-tg-debug2") << "...remove from context " << this << std::endl;
+ s->changeContext( false );
+ Assert( d_id==s->d_tg_id );
+ return false;
+ }
+}
+
+void TermGenerator::resetMatching( TermGenEnv * s, TNode eqc, unsigned mode ) {
+ d_match_status = 0;
+ d_match_status_child_num = 0;
+ d_match_children.clear();
+ d_match_children_end.clear();
+ d_match_mode = mode;
+ //if this term generalizes, it must generalize a non-ground term
+ //if( (d_match_mode & ( 1 << 2 ))!=0 && s->isGroundEqc( eqc ) && d_status==5 ){
+ // d_match_status = -1;
+ //}
+}
+
+bool TermGenerator::getNextMatch( TermGenEnv * s, TNode eqc, std::map< TypeNode, std::map< unsigned, TNode > >& subs, std::map< TNode, bool >& rev_subs ) {
+ if( d_match_status<0 ){
+ return false;
+ }
+ if( Trace.isOn("sg-gen-tg-match") ){
+ Trace("sg-gen-tg-match") << "Matching ";
+ debugPrint( s, "sg-gen-tg-match", "sg-gen-tg-match" );
+ Trace("sg-gen-tg-match") << " with eqc e" << s->d_cg->d_em[eqc] << "..." << std::endl;
+ Trace("sg-gen-tg-match") << " mstatus = " << d_match_status;
+ if( d_status==5 ){
+ TNode f = s->getTgFunc( d_typ, d_status_num );
+ Trace("sg-gen-tg-debug2") << ", f = " << f;
+ Trace("sg-gen-tg-debug2") << ", #args = " << s->d_func_args[f].size();
+ Trace("sg-gen-tg-debug2") << ", mchildNum = " << d_match_status_child_num;
+ Trace("sg-gen-tg-debug2") << ", #mchildren = " << d_match_children.size();
+ }
+ Trace("sg-gen-tg-debug2") << ", current substitution : {";
+ for( std::map< TypeNode, std::map< unsigned, TNode > >::iterator itt = subs.begin(); itt != subs.end(); ++itt ){
+ for( std::map< unsigned, TNode >::iterator it = itt->second.begin(); it != itt->second.end(); ++it ){
+ Trace("sg-gen-tg-debug2") << " " << it->first << " -> e" << s->d_cg->d_em[it->second];
+ }
+ }
+ Trace("sg-gen-tg-debug2") << " } " << std::endl;
+ }
+ if( d_status==1 ){
+ //a variable
+ if( d_match_status==0 ){
+ d_match_status++;
+ if( (d_match_mode & ( 1 << 1 ))!=0 ){
+ //only ground terms
+ if( !s->isGroundEqc( eqc ) ){
+ return false;
+ }
+ }else if( (d_match_mode & ( 1 << 2 ))!=0 ){
+ //only non-ground terms
+ //if( s->isGroundEqc( eqc ) ){
+ // return false;
+ //}
+ }
+ //store the match : restricted if match_mode.0 = 1
+ if( (d_match_mode & ( 1 << 0 ))!=0 ){
+ std::map< TNode, bool >::iterator it = rev_subs.find( eqc );
+ if( it==rev_subs.end() ){
+ rev_subs[eqc] = true;
+ }else{
+ return false;
+ }
+ }
+ Assert( subs[d_typ].find( d_status_num )==subs[d_typ].end() );
+ subs[d_typ][d_status_num] = eqc;
+ return true;
+ }else{
+ //clean up
+ subs[d_typ].erase( d_status_num );
+ if( (d_match_mode & ( 1 << 0 ))!=0 ){
+ rev_subs.erase( eqc );
+ }
+ return false;
+ }
+ }else if( d_status==2 ){
+ if( d_match_status==0 ){
+ d_match_status++;
+ Assert( d_status_num<(int)s->getNumTgVars( d_typ ) );
+ std::map< unsigned, TNode >::iterator it = subs[d_typ].find( d_status_num );
+ Assert( it!=subs[d_typ].end() );
+ return it->second==eqc;
+ }else{
+ return false;
+ }
+ }else if( d_status==5 ){
+ //Assert( d_match_children.size()<=d_children.size() );
+ //enumerating over f-applications in eqc
+ if( d_match_status_child_num<0 ){
+ return false;
+ }else if( d_match_status==0 ){
+ //set up next binding
+ if( d_match_status_child_num==(int)d_match_children.size() ){
+ if( d_match_status_child_num==0 ){
+ //initial binding
+ TNode f = s->getTgFunc( d_typ, d_status_num );
+ std::map< TNode, TermArgTrie >::iterator it = s->getTermDatabase()->d_func_map_eqc_trie[f].d_data.find( eqc );
+ if( it!=s->getTermDatabase()->d_func_map_eqc_trie[f].d_data.end() ){
+ d_match_children.push_back( it->second.d_data.begin() );
+ d_match_children_end.push_back( it->second.d_data.end() );
+ }else{
+ d_match_status++;
+ d_match_status_child_num--;
+ return getNextMatch( s, eqc, subs, rev_subs );
+ }
+ }else{
+ d_match_children.push_back( d_match_children[d_match_status_child_num-1]->second.d_data.begin() );
+ d_match_children_end.push_back( d_match_children[d_match_status_child_num-1]->second.d_data.end() );
+ }
+ }
+ d_match_status++;
+ Assert( d_match_status_child_num+1==(int)d_match_children.size() );
+ if( d_match_children[d_match_status_child_num]==d_match_children_end[d_match_status_child_num] ){
+ //no more arguments to bind
+ d_match_children.pop_back();
+ d_match_children_end.pop_back();
+ d_match_status_child_num--;
+ return getNextMatch( s, eqc, subs, rev_subs );
+ }else{
+ if( d_match_status_child_num==(int)d_children.size() ){
+ //successfully matched all children
+ d_match_children.pop_back();
+ d_match_children_end.pop_back();
+ d_match_status_child_num--;
+ return true;//return d_match_children[d_match_status]!=d_match_children_end[d_match_status];
+ }else{
+ //do next binding
+ s->d_tg_alloc[d_children[d_match_status_child_num]].resetMatching( s, d_match_children[d_match_status_child_num]->first, d_match_mode );
+ return getNextMatch( s, eqc, subs, rev_subs );
+ }
+ }
+ }else{
+ Assert( d_match_status==1 );
+ Assert( d_match_status_child_num+1==(int)d_match_children.size() );
+ Assert( d_match_children[d_match_status_child_num]!=d_match_children_end[d_match_status_child_num] );
+ d_match_status--;
+ if( s->d_tg_alloc[d_children[d_match_status_child_num]].getNextMatch( s, d_match_children[d_match_status_child_num]->first, subs, rev_subs ) ){
+ d_match_status_child_num++;
+ return getNextMatch( s, eqc, subs, rev_subs );
+ }else{
+ //iterate
+ d_match_children[d_match_status_child_num]++;
+ return getNextMatch( s, eqc, subs, rev_subs );
+ }
+ }
+ }
+ Assert( false );
+ return false;
+}
+
+unsigned TermGenerator::getDepth( TermGenEnv * s ) {
+ if( d_status==5 ){
+ unsigned maxd = 0;
+ for( unsigned i=0; i<d_children.size(); i++ ){
+ unsigned d = s->d_tg_alloc[d_children[i]].getDepth( s );
+ if( d>maxd ){
+ maxd = d;
+ }
+ }
+ return 1+maxd;
+ }else{
+ return 0;
+ }
+}
+
+unsigned TermGenerator::calculateGeneralizationDepth( TermGenEnv * s, std::map< TypeNode, std::vector< int > >& fvs ) {
+ if( d_status==5 ){
+ unsigned sum = 1;
+ for( unsigned i=0; i<d_children.size(); i++ ){
+ sum += s->d_tg_alloc[d_children[i]].calculateGeneralizationDepth( s, fvs );
+ }
+ return sum;
+ }else{
+ Assert( d_status==2 || d_status==1 );
+ std::map< TypeNode, std::vector< int > >::iterator it = fvs.find( d_typ );
+ if( it!=fvs.end() ){
+ if( std::find( it->second.begin(), it->second.end(), d_status_num )!=it->second.end() ){
+ return 1;
+ }
+ }
+ fvs[d_typ].push_back( d_status_num );
+ return 0;
+ }
+}
+
+unsigned TermGenerator::getGeneralizationDepth( TermGenEnv * s ) {
+ //if( s->d_gen_relevant_terms ){
+ // return s->d_tg_gdepth;
+ //}else{
+ std::map< TypeNode, std::vector< int > > fvs;
+ return calculateGeneralizationDepth( s, fvs );
+ //}
+}
+
+Node TermGenerator::getTerm( TermGenEnv * s ) {
+ if( d_status==1 || d_status==2 ){
+ Assert( !d_typ.isNull() );
+ return s->getFreeVar( d_typ, d_status_num );
+ }else if( d_status==5 ){
+ Node f = s->getTgFunc( d_typ, d_status_num );
+ if( d_children.size()==s->d_func_args[f].size() ){
+ std::vector< Node > children;
+ children.push_back( f );
+ for( unsigned i=0; i<d_children.size(); i++ ){
+ Node nc = s->d_tg_alloc[d_children[i]].getTerm( s );
+ if( nc.isNull() ){
+ return Node::null();
+ }else{
+ //Assert( nc.getType()==s->d_func_args[f][i] );
+ children.push_back( nc );
+ }
+ }
+ return NodeManager::currentNM()->mkNode( s->d_func_kind[f], children );
+ }
+ }else{
+ Assert( false );
+ }
+ return Node::null();
+}
+
+void TermGenerator::debugPrint( TermGenEnv * s, const char * c, const char * cd ) {
+ Trace(cd) << "[*" << d_id << "," << d_status << "]:";
+ if( d_status==1 || d_status==2 ){
+ Trace(c) << s->getFreeVar( d_typ, d_status_num );
+ }else if( d_status==5 ){
+ TNode f = s->getTgFunc( d_typ, d_status_num );
+ Trace(c) << "(" << f;
+ for( unsigned i=0; i<d_children.size(); i++ ){
+ Trace(c) << " ";
+ s->d_tg_alloc[d_children[i]].debugPrint( s, c, cd );
+ }
+ if( d_children.size()<s->d_func_args[f].size() ){
+ Trace(c) << " ...";
+ }
+ Trace(c) << ")";
+ }else{
+ Trace(c) << "???";
+ }
+}
+
+void TermGenEnv::collectSignatureInformation() {
+ d_typ_tg_funcs.clear();
+ d_funcs.clear();
+ d_func_kind.clear();
+ d_func_args.clear();
+ TypeNode tnull;
+ for( std::map< Node, TermArgTrie >::iterator it = getTermDatabase()->d_func_map_trie.begin(); it != getTermDatabase()->d_func_map_trie.end(); ++it ){
+ if( !getTermDatabase()->d_op_map[it->first].empty() ){
+ Node nn = getTermDatabase()->d_op_map[it->first][0];
+ if( d_cg->isHandledTerm( nn ) && nn.getKind()!=APPLY_SELECTOR_TOTAL && !nn.getType().isBoolean() ){
+ bool do_enum = true;
+ //check if we have enumerated ground terms
+ if( nn.getKind()==APPLY_UF ){
+ if( !d_cg->hasEnumeratedUf( nn ) ){
+ do_enum = false;
+ }
+ }
+ if( do_enum ){
+ d_funcs.push_back( it->first );
+ for( unsigned i=0; i<nn.getNumChildren(); i++ ){
+ d_func_args[it->first].push_back( nn[i].getType() );
+ }
+ d_func_kind[it->first] = nn.getKind();
+ d_typ_tg_funcs[tnull].push_back( it->first );
+ d_typ_tg_funcs[nn.getType()].push_back( it->first );
+ Trace("sg-rel-sig") << "Will enumerate function applications of : " << it->first << ", #args = " << d_func_args[it->first].size() << ", kind = " << nn.getKind() << std::endl;
+ getTermDatabase()->computeUfEqcTerms( it->first );
+ }
+ }
+ }
+ }
+ //shuffle functions
+ for( std::map< TypeNode, std::vector< TNode > >::iterator it = d_typ_tg_funcs.begin(); it != d_typ_tg_funcs.end(); ++it ){
+ std::random_shuffle( it->second.begin(), it->second.end() );
+ if( it->first.isNull() ){
+ Trace("sg-gen-tg-debug") << "In this order : ";
+ for( unsigned i=0; i<it->second.size(); i++ ){
+ Trace("sg-gen-tg-debug") << it->second[i] << " ";
+ }
+ Trace("sg-gen-tg-debug") << std::endl;
+ }
+ }
+}
+
+void TermGenEnv::reset( unsigned depth, bool genRelevant, TypeNode tn ) {
+ Assert( d_tg_alloc.empty() );
+ d_tg_alloc.clear();
+
+ if( genRelevant ){
+ for( unsigned i=0; i<2; i++ ){
+ d_ccand_eqc[i].clear();
+ d_ccand_eqc[i].push_back( d_relevant_eqc[i] );
+ }
+ }
+
+ d_tg_id = 0;
+ d_tg_gdepth = 0;
+ d_tg_gdepth_limit = depth;
+ d_gen_relevant_terms = genRelevant;
+ d_tg_alloc[0].reset( this, tn );
+}
+
+bool TermGenEnv::getNextTerm() {
+ if( d_tg_alloc[0].getNextTerm( this, d_tg_gdepth_limit ) ){
+ Assert( (int)d_tg_alloc[0].getGeneralizationDepth( this )<=d_tg_gdepth_limit );
+ if( (int)d_tg_alloc[0].getGeneralizationDepth( this )!=d_tg_gdepth_limit ){
+ return getNextTerm();
+ }else{
+ return true;
+ }
+ }else{
+ return false;
+ }
+}
+
+//reset matching
+void TermGenEnv::resetMatching( TNode eqc, unsigned mode ) {
+ d_tg_alloc[0].resetMatching( this, eqc, mode );
+}
+
+//get next match
+bool TermGenEnv::getNextMatch( TNode eqc, std::map< TypeNode, std::map< unsigned, TNode > >& subs, std::map< TNode, bool >& rev_subs ) {
+ return d_tg_alloc[0].getNextMatch( this, eqc, subs, rev_subs );
+}
+
+//get term
+Node TermGenEnv::getTerm() {
+ return d_tg_alloc[0].getTerm( this );
+}
+
+void TermGenEnv::debugPrint( const char * c, const char * cd ) {
+ d_tg_alloc[0].debugPrint( this, c, cd );
+}
+
+unsigned TermGenEnv::getNumTgVars( TypeNode tn ) {
+ return d_var_id[tn];
+}
+
+bool TermGenEnv::allowVar( TypeNode tn ) {
+ std::map< TypeNode, unsigned >::iterator it = d_var_limit.find( tn );
+ if( it==d_var_limit.end() ){
+ return true;
+ }else{
+ return d_var_id[tn]<it->second;
+ }
+}
+
+void TermGenEnv::addVar( TypeNode tn ) {
+ d_var_id[tn]++;
+}
+
+void TermGenEnv::removeVar( TypeNode tn ) {
+ d_var_id[tn]--;
+ //d_var_eq_tg.pop_back();
+ //d_var_tg.pop_back();
+}
+
+unsigned TermGenEnv::getNumTgFuncs( TypeNode tn ) {
+ return d_typ_tg_funcs[tn].size();
+}
+
+TNode TermGenEnv::getTgFunc( TypeNode tn, unsigned i ) {
+ return d_typ_tg_funcs[tn][i];
+}
+
+Node TermGenEnv::getFreeVar( TypeNode tn, unsigned i ) {
+ return d_cg->getFreeVar( tn, i );
+}
+
+bool TermGenEnv::considerCurrentTerm() {
+ Assert( !d_tg_alloc.empty() );
+
+ //if generalization depth is too large, don't consider it
+ unsigned i = d_tg_alloc.size();
+ Trace("sg-gen-tg-debug") << "Consider term ";
+ d_tg_alloc[0].debugPrint( this, "sg-gen-tg-debug", "sg-gen-tg-debug" );
+ Trace("sg-gen-tg-debug") << "? curr term size = " << d_tg_alloc.size() << ", last status = " << d_tg_alloc[i-1].d_status;
+ Trace("sg-gen-tg-debug") << std::endl;
+
+ if( d_tg_gdepth_limit>=0 && d_tg_alloc[0].getGeneralizationDepth( this )>(unsigned)d_tg_gdepth_limit ){
+ Trace("sg-gen-consider-term") << "-> generalization depth of ";
+ d_tg_alloc[0].debugPrint( this, "sg-gen-consider-term", "sg-gen-tg-debug" );
+ Trace("sg-gen-consider-term") << " is too high " << d_tg_gdepth << " " << d_tg_alloc[0].getGeneralizationDepth( this ) << ", do not consider." << std::endl;
+ return false;
+ }
+
+ //----optimizations
+ /*
+ if( d_tg_alloc[i-1].d_status==1 ){
+ }else if( d_tg_alloc[i-1].d_status==2 ){
+ }else if( d_tg_alloc[i-1].d_status==5 ){
+ }else{
+ Trace("sg-gen-tg-debug") << "Bad tg: " << &d_tg_alloc[i-1] << std::endl;
+ Assert( false );
+ }
+ */
+ //if equated two variables, first check if context-independent TODO
+ //----end optimizations
+
+
+ //check based on which candidate equivalence classes match
+ if( d_gen_relevant_terms ){
+ Trace("sg-gen-tg-debug") << "Filter based on relevant ground EQC";
+ Trace("sg-gen-tg-debug") << ", #eqc to try = " << d_ccand_eqc[0][i-1].size() << "/" << d_ccand_eqc[1][i-1].size() << std::endl;
+
+ Assert( d_ccand_eqc[0].size()>=2 );
+ Assert( d_ccand_eqc[0].size()==d_ccand_eqc[1].size() );
+ Assert( d_ccand_eqc[0].size()==d_tg_id+1 );
+ Assert( d_tg_id==d_tg_alloc.size() );
+ for( unsigned r=0; r<2; r++ ){
+ d_ccand_eqc[r][i].clear();
+ }
+
+ //re-check feasibility of EQC
+ for( unsigned r=0; r<2; r++ ){
+ for( unsigned j=0; j<d_ccand_eqc[r][i-1].size(); j++ ){
+ std::map< TypeNode, std::map< unsigned, TNode > > subs;
+ std::map< TNode, bool > rev_subs;
+ unsigned mode;
+ if( r==0 ){
+ mode = d_cg->optReqDistinctVarPatterns() ? ( 1 << 0 ) : 0;
+ mode = mode | (1 << 2 );
+ }else{
+ mode = 1 << 1;
+ }
+ d_tg_alloc[0].resetMatching( this, d_ccand_eqc[r][i-1][j], mode );
+ if( d_tg_alloc[0].getNextMatch( this, d_ccand_eqc[r][i-1][j], subs, rev_subs ) ){
+ d_ccand_eqc[r][i].push_back( d_ccand_eqc[r][i-1][j] );
+ }
+ }
+ }
+ for( unsigned r=0; r<2; r++ ){
+ Trace("sg-gen-tg-debug") << "Current eqc of type " << r << " : ";
+ for( unsigned j=0; j<d_ccand_eqc[r][i].size(); j++ ){
+ Trace("sg-gen-tg-debug") << "e" << d_cg->d_em[d_ccand_eqc[r][i][j]] << " ";
+ }
+ Trace("sg-gen-tg-debug") << std::endl;
+ }
+ if( options::conjectureFilterActiveTerms() && d_ccand_eqc[0][i].empty() ){
+ Trace("sg-gen-consider-term") << "Do not consider term of form ";
+ d_tg_alloc[0].debugPrint( this, "sg-gen-consider-term", "sg-gen-consider-term-debug" );
+ Trace("sg-gen-consider-term") << " since no relevant EQC matches it." << std::endl;
+ return false;
+ }
+ if( options::conjectureFilterModel() && d_ccand_eqc[1][i].empty() ){
+ Trace("sg-gen-consider-term") << "Do not consider term of form ";
+ d_tg_alloc[0].debugPrint( this, "sg-gen-consider-term", "sg-gen-consider-term-debug" );
+ Trace("sg-gen-consider-term") << " since no ground EQC matches it." << std::endl;
+ return false;
+ }
+ }
+ Trace("sg-gen-tg-debug") << "Will consider term ";
+ d_tg_alloc[0].debugPrint( this, "sg-gen-tg-debug", "sg-gen-tg-debug" );
+ Trace("sg-gen-tg-debug") << std::endl;
+ Trace("sg-gen-consider-term-debug") << std::endl;
+ return true;
+}
+
+void TermGenEnv::changeContext( bool add ) {
+ if( add ){
+ for( unsigned r=0; r<2; r++ ){
+ d_ccand_eqc[r].push_back( std::vector< TNode >() );
+ }
+ d_tg_id++;
+ }else{
+ for( unsigned r=0; r<2; r++ ){
+ d_ccand_eqc[r].pop_back();
+ }
+ d_tg_id--;
+ Assert( d_tg_alloc.find( d_tg_id )!=d_tg_alloc.end() );
+ d_tg_alloc.erase( d_tg_id );
+ }
+}
+
+bool TermGenEnv::considerCurrentTermCanon( unsigned tg_id ){
+ Assert( tg_id<d_tg_alloc.size() );
+ if( options::conjectureFilterCanonical() ){
+ //check based on a canonicity of the term (if there is one)
+ Trace("sg-gen-tg-debug") << "Consider term canon ";
+ d_tg_alloc[0].debugPrint( this, "sg-gen-tg-debug", "sg-gen-tg-debug" );
+ Trace("sg-gen-tg-debug") << ", tg is [" << tg_id << "]..." << std::endl;
+
+ Node ln = d_tg_alloc[tg_id].getTerm( this );
+ Trace("sg-gen-tg-debug") << "Term is " << ln << std::endl;
+ return d_cg->considerTermCanon( ln, d_gen_relevant_terms );
+ }
+ return true;
+}
+
+bool TermGenEnv::isRelevantFunc( Node f ) {
+ return std::find( d_funcs.begin(), d_funcs.end(), f )!=d_funcs.end();
+}
+TermDb * TermGenEnv::getTermDatabase() {
+ return d_cg->getTermDatabase();
+}
+Node TermGenEnv::getGroundEqc( TNode r ) {
+ return d_cg->getGroundEqc( r );
+}
+bool TermGenEnv::isGroundEqc( TNode r ){
+ return d_cg->isGroundEqc( r );
+}
+bool TermGenEnv::isGroundTerm( TNode n ){
+ return d_cg->isGroundTerm( n );
+}
+
+
+void SubstitutionIndex::addSubstitution( TNode eqc, std::vector< TNode >& vars, std::vector< TNode >& terms, unsigned i ) {
+ if( i==vars.size() ){
+ d_var = eqc;
+ }else{
+ Assert( d_var.isNull() || d_var==vars[i] );
+ d_var = vars[i];
+ d_children[terms[i]].addSubstitution( eqc, vars, terms, i+1 );
+ }
+}
+
+bool SubstitutionIndex::notifySubstitutions( ConjectureGenerator * s, std::map< TNode, TNode >& subs, TNode rhs, unsigned numVars, unsigned i ) {
+ if( i==numVars ){
+ Assert( d_children.empty() );
+ return s->notifySubstitution( d_var, subs, rhs );
+ }else{
+ Assert( i==0 || !d_children.empty() );
+ for( std::map< TNode, SubstitutionIndex >::iterator it = d_children.begin(); it != d_children.end(); ++it ){
+ Trace("sg-cconj-debug2") << "Try " << d_var << " -> " << it->first << " (" << i << "/" << numVars << ")" << std::endl;
+ subs[d_var] = it->first;
+ if( !it->second.notifySubstitutions( s, subs, rhs, numVars, i+1 ) ){
+ return false;
+ }
+ }
+ return true;
+ }
+}
+
+
+void TheoremIndex::addTheorem( std::vector< TNode >& lhs_v, std::vector< unsigned >& lhs_arg, TNode rhs ){
+ if( lhs_v.empty() ){
+ if( std::find( d_terms.begin(), d_terms.end(), rhs )==d_terms.end() ){
+ d_terms.push_back( rhs );
+ }
+ }else{
+ unsigned index = lhs_v.size()-1;
+ if( lhs_arg[index]==lhs_v[index].getNumChildren() ){
+ lhs_v.pop_back();
+ lhs_arg.pop_back();
+ addTheorem( lhs_v, lhs_arg, rhs );
+ }else{
+ lhs_arg[index]++;
+ addTheoremNode( lhs_v[index][lhs_arg[index]-1], lhs_v, lhs_arg, rhs );
+ }
+ }
+}
+
+void TheoremIndex::addTheoremNode( TNode curr, std::vector< TNode >& lhs_v, std::vector< unsigned >& lhs_arg, TNode rhs ){
+ Trace("thm-db-debug") << "Adding conjecture for subterm " << curr << "..." << std::endl;
+ if( curr.hasOperator() ){
+ lhs_v.push_back( curr );
+ lhs_arg.push_back( 0 );
+ d_children[curr.getOperator()].addTheorem( lhs_v, lhs_arg, rhs );
+ }else{
+ Assert( curr.getKind()==kind::BOUND_VARIABLE );
+ TypeNode tn = curr.getType();
+ Assert( d_var[tn].isNull() || d_var[tn]==curr );
+ d_var[tn] = curr;
+ d_children[curr].addTheorem( lhs_v, lhs_arg, rhs );
+ }
+}
+
+void TheoremIndex::getEquivalentTerms( std::vector< TNode >& n_v, std::vector< unsigned >& n_arg,
+ std::map< TNode, TNode >& smap, std::vector< TNode >& vars, std::vector< TNode >& subs,
+ std::vector< Node >& terms ) {
+ Trace("thm-db-debug") << "Get equivalent terms " << n_v.size() << " " << n_arg.size() << std::endl;
+ if( n_v.empty() ){
+ Trace("thm-db-debug") << "Number of terms : " << d_terms.size() << std::endl;
+ //apply substutitions to RHS's
+ for( unsigned i=0; i<d_terms.size(); i++ ){
+ Node n = d_terms[i].substitute( vars.begin(), vars.end(), subs.begin(), subs.end() );
+ terms.push_back( n );
+ }
+ }else{
+ unsigned index = n_v.size()-1;
+ if( n_arg[index]==n_v[index].getNumChildren() ){
+ n_v.pop_back();
+ n_arg.pop_back();
+ getEquivalentTerms( n_v, n_arg, smap, vars, subs, terms );
+ }else{
+ n_arg[index]++;
+ getEquivalentTermsNode( n_v[index][n_arg[index]-1], n_v, n_arg, smap, vars, subs, terms );
+ }
+ }
+}
+
+void TheoremIndex::getEquivalentTermsNode( Node curr, std::vector< TNode >& n_v, std::vector< unsigned >& n_arg,
+ std::map< TNode, TNode >& smap, std::vector< TNode >& vars, std::vector< TNode >& subs,
+ std::vector< Node >& terms ) {
+ Trace("thm-db-debug") << "Get equivalent based on subterm " << curr << "..." << std::endl;
+ if( curr.hasOperator() ){
+ Trace("thm-db-debug") << "Check based on operator..." << std::endl;
+ std::map< TNode, TheoremIndex >::iterator it = d_children.find( curr.getOperator() );
+ if( it!=d_children.end() ){
+ n_v.push_back( curr );
+ n_arg.push_back( 0 );
+ it->second.getEquivalentTerms( n_v, n_arg, smap, vars, subs, terms );
+ }
+ Trace("thm-db-debug") << "...done check based on operator" << std::endl;
+ }
+ TypeNode tn = curr.getType();
+ std::map< TypeNode, TNode >::iterator itt = d_var.find( tn );
+ if( itt!=d_var.end() ){
+ Trace("thm-db-debug") << "Check for substitution with " << itt->second << "..." << std::endl;
+ Assert( curr.getType()==itt->second.getType() );
+ //add to substitution if possible
+ bool success = false;
+ std::map< TNode, TNode >::iterator it = smap.find( itt->second );
+ if( it==smap.end() ){
+ smap[itt->second] = curr;
+ vars.push_back( itt->second );
+ subs.push_back( curr );
+ success = true;
+ }else if( it->second==curr ){
+ success = true;
+ }else{
+ //also check modulo equality (in universal equality engine)
+ }
+ Trace("thm-db-debug") << "...check for substitution with " << itt->second << ", success = " << success << "." << std::endl;
+ if( success ){
+ d_children[itt->second].getEquivalentTerms( n_v, n_arg, smap, vars, subs, terms );
+ }
+ }
+}
+
+void TheoremIndex::debugPrint( const char * c, unsigned ind ) {
+ for( std::map< TNode, TheoremIndex >::iterator it = d_children.begin(); it != d_children.end(); ++it ){
+ for( unsigned i=0; i<ind; i++ ){ Trace(c) << " "; }
+ Trace(c) << it->first << std::endl;
+ it->second.debugPrint( c, ind+1 );
+ }
+ if( !d_terms.empty() ){
+ for( unsigned i=0; i<ind; i++ ){ Trace(c) << " "; }
+ Trace(c) << "{";
+ for( unsigned i=0; i<d_terms.size(); i++ ){
+ Trace(c) << " " << d_terms[i];
+ }
+ Trace(c) << " }" << std::endl;
+ }
+ //if( !d_var.isNull() ){
+ // for( unsigned i=0; i<ind; i++ ){ Trace(c) << " "; }
+ // Trace(c) << "var:" << d_var << std::endl;
+ //}
+}
+
+bool ConjectureGenerator::optReqDistinctVarPatterns() { return false; }
+bool ConjectureGenerator::optFilterUnknown() { return true; } //may change
+int ConjectureGenerator::optFilterScoreThreshold() { return 1; }
+unsigned ConjectureGenerator::optFullCheckFrequency() { return 1; }
+
+bool ConjectureGenerator::optStatsOnly() { return false; }
+
+}
diff --git a/src/theory/quantifiers/conjecture_generator.h b/src/theory/quantifiers/conjecture_generator.h
new file mode 100755
index 000000000..462fadfce
--- /dev/null
+++ b/src/theory/quantifiers/conjecture_generator.h
@@ -0,0 +1,434 @@
+/********************* */
+/*! \file conjecture_generator.h
+ ** \verbatim
+ ** Original author: Andrew Reynolds
+ ** Major contributors: none
+ ** Minor contributors (to current version): none
+ ** This file is part of the CVC4 project.
+ ** Copyright (c) 2009-2014 New York University and The University of Iowa
+ ** See the file COPYING in the top-level source directory for licensing
+ ** information.\endverbatim
+ **
+ ** \brief conjecture generator class
+ **/
+
+#include "cvc4_private.h"
+
+#ifndef CONJECTURE_GENERATOR_H
+#define CONJECTURE_GENERATOR_H
+
+#include "context/cdhashmap.h"
+#include "context/cdchunk_list.h"
+#include "theory/quantifiers_engine.h"
+#include "theory/type_enumerator.h"
+
+namespace CVC4 {
+namespace theory {
+namespace quantifiers {
+
+class TermArgTrie;
+
+//algorithm for computing candidate subgoals
+
+class ConjectureGenerator;
+
+// operator independent index of arguments for an EQC
+class OpArgIndex
+{
+public:
+ std::map< TNode, OpArgIndex > d_child;
+ std::vector< TNode > d_ops;
+ std::vector< TNode > d_op_terms;
+ void addTerm( ConjectureGenerator * s, TNode n, unsigned index = 0 );
+ Node getGroundTerm( ConjectureGenerator * s, std::vector< TNode >& args );
+ void getGroundTerms( ConjectureGenerator * s, std::vector< TNode >& terms );
+};
+
+class PatternTypIndex
+{
+public:
+ std::vector< TNode > d_terms;
+ std::map< TypeNode, std::map< unsigned, PatternTypIndex > > d_children;
+ void clear() {
+ d_terms.clear();
+ d_children.clear();
+ }
+};
+
+class SubstitutionIndex
+{
+public:
+ //current variable, or ground EQC if d_children.empty()
+ TNode d_var;
+ std::map< TNode, SubstitutionIndex > d_children;
+ //add substitution
+ void addSubstitution( TNode eqc, std::vector< TNode >& vars, std::vector< TNode >& terms, unsigned i = 0 );
+ //notify substitutions
+ bool notifySubstitutions( ConjectureGenerator * s, std::map< TNode, TNode >& subs, TNode rhs, unsigned numVars, unsigned i = 0 );
+};
+
+class TermGenEnv;
+
+class TermGenerator
+{
+private:
+ unsigned calculateGeneralizationDepth( TermGenEnv * s, std::map< TypeNode, std::vector< int > >& fvs );
+public:
+ TermGenerator(){}
+ TypeNode d_typ;
+ unsigned d_id;
+ //1 : consider as unique variable
+ //2 : consider equal to another variable
+ //5 : consider a function application
+ unsigned d_status;
+ int d_status_num;
+ //for function applications: the number of children you have built
+ int d_status_child_num;
+ //children (pointers to TermGenerators)
+ std::vector< unsigned > d_children;
+
+ //match status
+ int d_match_status;
+ int d_match_status_child_num;
+ //match mode bits
+ //0 : different variables must have different matches
+ //1 : variables must map to ground terms
+ //2 : variables must map to non-ground terms
+ unsigned d_match_mode;
+ //children
+ std::vector< std::map< TNode, TermArgTrie >::iterator > d_match_children;
+ std::vector< std::map< TNode, TermArgTrie >::iterator > d_match_children_end;
+
+ void reset( TermGenEnv * s, TypeNode tn );
+ bool getNextTerm( TermGenEnv * s, unsigned depth );
+ void resetMatching( TermGenEnv * s, TNode eqc, unsigned mode );
+ bool getNextMatch( TermGenEnv * s, TNode eqc, std::map< TypeNode, std::map< unsigned, TNode > >& subs, std::map< TNode, bool >& rev_subs );
+
+ unsigned getDepth( TermGenEnv * s );
+ unsigned getGeneralizationDepth( TermGenEnv * s );
+ Node getTerm( TermGenEnv * s );
+
+ void debugPrint( TermGenEnv * s, const char * c, const char * cd );
+};
+
+
+class TermGenEnv
+{
+public:
+ //collect signature information
+ void collectSignatureInformation();
+ //reset function
+ void reset( unsigned gdepth, bool genRelevant, TypeNode tgen );
+ //get next term
+ bool getNextTerm();
+ //reset matching
+ void resetMatching( TNode eqc, unsigned mode );
+ //get next match
+ bool getNextMatch( TNode eqc, std::map< TypeNode, std::map< unsigned, TNode > >& subs, std::map< TNode, bool >& rev_subs );
+ //get term
+ Node getTerm();
+ //debug print
+ void debugPrint( const char * c, const char * cd );
+
+ //conjecture generation
+ ConjectureGenerator * d_cg;
+ //the current number of enumerated variables per type
+ std::map< TypeNode, unsigned > d_var_id;
+ //the limit of number of variables per type to enumerate
+ std::map< TypeNode, unsigned > d_var_limit;
+ //the functions we can currently generate
+ std::map< TypeNode, std::vector< TNode > > d_typ_tg_funcs;
+ //the equivalence classes (if applicable) that match the currently generated term
+ bool d_gen_relevant_terms;
+ //relevant equivalence classes
+ std::vector< TNode > d_relevant_eqc[2];
+ //candidate equivalence classes
+ std::vector< std::vector< TNode > > d_ccand_eqc[2];
+ //the term generation objects
+ unsigned d_tg_id;
+ std::map< unsigned, TermGenerator > d_tg_alloc;
+ unsigned d_tg_gdepth;
+ int d_tg_gdepth_limit;
+
+ //all functions
+ std::vector< TNode > d_funcs;
+ //function to kind map
+ std::map< TNode, Kind > d_func_kind;
+ //type of each argument of the function
+ std::map< TNode, std::vector< TypeNode > > d_func_args;
+
+ //access functions
+ unsigned getNumTgVars( TypeNode tn );
+ bool allowVar( TypeNode tn );
+ void addVar( TypeNode tn );
+ void removeVar( TypeNode tn );
+ unsigned getNumTgFuncs( TypeNode tn );
+ TNode getTgFunc( TypeNode tn, unsigned i );
+ Node getFreeVar( TypeNode tn, unsigned i );
+ bool considerCurrentTerm();
+ bool considerCurrentTermCanon( unsigned tg_id );
+ void changeContext( bool add );
+ bool isRelevantFunc( Node f );
+ //carry
+ TermDb * getTermDatabase();
+ Node getGroundEqc( TNode r );
+ bool isGroundEqc( TNode r );
+ bool isGroundTerm( TNode n );
+};
+
+
+
+class TheoremIndex
+{
+private:
+ void addTheorem( std::vector< TNode >& lhs_v, std::vector< unsigned >& lhs_arg, TNode rhs );
+ void addTheoremNode( TNode curr, std::vector< TNode >& lhs_v, std::vector< unsigned >& lhs_arg, TNode rhs );
+ void getEquivalentTerms( std::vector< TNode >& n_v, std::vector< unsigned >& n_arg,
+ std::map< TNode, TNode >& smap, std::vector< TNode >& vars, std::vector< TNode >& subs,
+ std::vector< Node >& terms );
+ void getEquivalentTermsNode( Node curr, std::vector< TNode >& n_v, std::vector< unsigned >& n_arg,
+ std::map< TNode, TNode >& smap, std::vector< TNode >& vars, std::vector< TNode >& subs,
+ std::vector< Node >& terms );
+public:
+ std::map< TypeNode, TNode > d_var;
+ std::map< TNode, TheoremIndex > d_children;
+ std::vector< Node > d_terms;
+
+ void addTheorem( TNode lhs, TNode rhs ) {
+ std::vector< TNode > v;
+ std::vector< unsigned > a;
+ addTheoremNode( lhs, v, a, rhs );
+ }
+ void getEquivalentTerms( TNode n, std::vector< Node >& terms ) {
+ std::vector< TNode > nv;
+ std::vector< unsigned > na;
+ std::map< TNode, TNode > smap;
+ std::vector< TNode > vars;
+ std::vector< TNode > subs;
+ getEquivalentTermsNode( n, nv, na, smap, vars, subs, terms );
+ }
+ void clear(){
+ d_var.clear();
+ d_children.clear();
+ d_terms.clear();
+ }
+ void debugPrint( const char * c, unsigned ind = 0 );
+};
+
+
+
+class ConjectureGenerator : public QuantifiersModule
+{
+ friend class OpArgIndex;
+ friend class PatGen;
+ friend class PatternGenEqc;
+ friend class PatternGen;
+ friend class SubsEqcIndex;
+ friend class TermGenerator;
+ friend class TermGenEnv;
+ typedef context::CDChunkList<Node> NodeList;
+ typedef context::CDHashMap< Node, Node, NodeHashFunction > NodeMap;
+ typedef context::CDHashMap< Node, bool, NodeHashFunction > BoolMap;
+//this class maintains a congruence closure for *universal* facts
+private:
+ //notification class for equality engine
+ class NotifyClass : public eq::EqualityEngineNotify {
+ ConjectureGenerator& d_sg;
+ public:
+ NotifyClass(ConjectureGenerator& sg): d_sg(sg) {}
+ bool eqNotifyTriggerEquality(TNode equality, bool value) { return true; }
+ bool eqNotifyTriggerPredicate(TNode predicate, bool value) { return true; }
+ bool eqNotifyTriggerTermEquality(TheoryId tag, TNode t1, TNode t2, bool value) { return true; }
+ void eqNotifyConstantTermMerge(TNode t1, TNode t2) { }
+ void eqNotifyNewClass(TNode t) { d_sg.eqNotifyNewClass(t); }
+ void eqNotifyPreMerge(TNode t1, TNode t2) { d_sg.eqNotifyPreMerge(t1, t2); }
+ void eqNotifyPostMerge(TNode t1, TNode t2) { d_sg.eqNotifyPostMerge(t1, t2); }
+ void eqNotifyDisequal(TNode t1, TNode t2, TNode reason) {d_sg.eqNotifyDisequal(t1, t2, reason); }
+ };/* class ConjectureGenerator::NotifyClass */
+ /** The notify class */
+ NotifyClass d_notify;
+ class EqcInfo{
+ public:
+ EqcInfo( context::Context* c );
+ //representative
+ context::CDO< Node > d_rep;
+ };
+ /** get or make eqc info */
+ EqcInfo* getOrMakeEqcInfo( TNode n, bool doMake = false );
+ /** (universal) equaltity engine */
+ eq::EqualityEngine d_uequalityEngine;
+ /** pending adds */
+ std::vector< Node > d_upendingAdds;
+ /** relevant terms */
+ std::map< Node, bool > d_urelevant_terms;
+ /** information necessary for equivalence classes */
+ std::map< Node, EqcInfo* > d_eqc_info;
+ /** 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);
+ /** are universal equal */
+ bool areUniversalEqual( TNode n1, TNode n2 );
+ /** are universal disequal */
+ bool areUniversalDisequal( TNode n1, TNode n2 );
+ /** get universal representative */
+ TNode getUniversalRepresentative( TNode n, bool add = false );
+ /** set relevant */
+ void setUniversalRelevant( TNode n );
+ /** ordering for universal terms */
+ bool isUniversalLessThan( TNode rt1, TNode rt2 );
+
+ /** the nodes we have reported as canonical representative */
+ std::vector< TNode > d_ue_canon;
+ /** is reported canon */
+ bool isReportedCanon( TNode n );
+ /** mark that term has been reported as canonical rep */
+ void markReportedCanon( TNode n );
+
+private: //information regarding the conjectures
+ /** list of all conjectures */
+ std::vector< Node > d_conjectures;
+ /** list of all waiting conjectures */
+ std::vector< Node > d_waiting_conjectures_lhs;
+ std::vector< Node > d_waiting_conjectures_rhs;
+ std::vector< int > d_waiting_conjectures_score;
+ /** map of currently considered equality conjectures */
+ std::map< Node, std::vector< Node > > d_waiting_conjectures;
+ /** map of equality conjectures */
+ std::map< Node, std::vector< Node > > d_eq_conjectures;
+ /** currently existing conjectures in equality engine */
+ BoolMap d_ee_conjectures;
+ /** conjecture index */
+ TheoremIndex d_thm_index;
+private: //free variable list
+ //free variables
+ std::map< TypeNode, std::vector< Node > > d_free_var;
+ //map from free variable to FV#
+ std::map< TNode, unsigned > d_free_var_num;
+ // get canonical free variable #i of type tn
+ Node getFreeVar( TypeNode tn, unsigned i );
+ // get canonical term, return null if it contains a term apart from handled signature
+ Node getCanonicalTerm( TNode n, std::map< TypeNode, unsigned >& var_count, std::map< TNode, TNode >& subs );
+private: //information regarding the terms
+ //relevant patterns (the LHS's)
+ std::map< TypeNode, std::vector< Node > > d_rel_patterns;
+ //total number of unique variables
+ std::map< TNode, unsigned > d_rel_pattern_var_sum;
+ //by types
+ PatternTypIndex d_rel_pattern_typ_index;
+ // substitution to ground EQC index
+ std::map< TNode, SubstitutionIndex > d_rel_pattern_subs_index;
+ //patterns (the RHS's)
+ std::map< TypeNode, std::vector< Node > > d_patterns;
+ //patterns to # variables per type
+ std::map< TNode, std::map< TypeNode, unsigned > > d_pattern_var_id;
+ // # duplicated variables
+ std::map< TNode, unsigned > d_pattern_var_duplicate;
+ // is normal pattern? (variables allocated in canonical way left to right)
+ std::map< TNode, int > d_pattern_is_normal;
+ std::map< TNode, int > d_pattern_is_relevant;
+ // patterns to a count of # operators (variables and functions)
+ std::map< TNode, std::map< TNode, unsigned > > d_pattern_fun_id;
+ // term size
+ std::map< TNode, unsigned > d_pattern_fun_sum;
+ // collect functions
+ unsigned collectFunctions( TNode opat, TNode pat, std::map< TNode, unsigned >& funcs,
+ std::map< TypeNode, unsigned >& mnvn, std::map< TypeNode, unsigned >& mxvn );
+ // add pattern
+ void registerPattern( Node pat, TypeNode tpat );
+private: //for debugging
+ std::map< TNode, unsigned > d_em;
+ unsigned d_conj_count;
+public:
+ //term generation environment
+ TermGenEnv d_tge;
+ //consider term canon
+ bool considerTermCanon( Node ln, bool genRelevant );
+public: //for generalization
+ //generalizations
+ bool isGeneralization( TNode patg, TNode pat ) {
+ std::map< TNode, TNode > subs;
+ return isGeneralization( patg, pat, subs );
+ }
+ bool isGeneralization( TNode patg, TNode pat, std::map< TNode, TNode >& subs );
+ // get generalization depth
+ int calculateGeneralizationDepth( TNode n, std::vector< TNode >& fv );
+private:
+ //predicate for type
+ std::map< TypeNode, Node > d_typ_pred;
+ //get predicate for type
+ Node getPredicateForType( TypeNode tn );
+ //
+ void getEnumerateUfTerm( Node n, unsigned num, std::vector< Node >& terms );
+ //
+ void getEnumeratePredUfTerm( Node n, unsigned num, std::vector< Node >& terms );
+ // uf operators enumerated
+ std::map< Node, bool > d_uf_enum;
+public: //for property enumeration
+ //process this candidate conjecture
+ void processCandidateConjecture( TNode lhs, TNode rhs, unsigned lhs_depth, unsigned rhs_depth );
+ //whether it should be considered, negative : no, positive returns score
+ int considerCandidateConjecture( TNode lhs, TNode rhs );
+ //notified of a substitution
+ bool notifySubstitution( TNode glhs, std::map< TNode, TNode >& subs, TNode rhs );
+ //confirmation count
+ unsigned d_subs_confirmCount;
+ //individual witnesses (for range)
+ std::vector< TNode > d_subs_confirmWitnessRange;
+ //individual witnesses (for domain)
+ std::map< TNode, std::vector< TNode > > d_subs_confirmWitnessDomain;
+ //number of ground substitutions whose equality is unknown
+ unsigned d_subs_unkCount;
+private: //information about ground equivalence classes
+ TNode d_bool_eqc[2];
+ std::map< TNode, Node > d_ground_eqc_map;
+ std::vector< TNode > d_ground_terms;
+ //operator independent term index
+ std::map< TNode, OpArgIndex > d_op_arg_index;
+ //is handled term
+ bool isHandledTerm( TNode n );
+ Node getGroundEqc( TNode r );
+ bool isGroundEqc( TNode r );
+ bool isGroundTerm( TNode n );
+ //has enumerated UF
+ bool hasEnumeratedUf( Node n );
+ // count of full effort checks
+ unsigned d_fullEffortCount;
+ // has added lemma
+ bool d_hasAddedLemma;
+ //flush the waiting conjectures
+ unsigned flushWaitingConjectures( unsigned& addedLemmas, int ldepth, int rdepth );
+public:
+ ConjectureGenerator( QuantifiersEngine * qe, context::Context* c );
+ /* needs check */
+ bool needsCheck( Theory::Effort e );
+ /* reset at a round */
+ void reset_round( Theory::Effort e );
+ /* Call during quantifier engine's check */
+ void check( Theory::Effort e, unsigned quant_e );
+ /* Called for new quantifiers */
+ void registerQuantifier( Node q );
+ void assertNode( Node n );
+ /** Identify this module (for debugging, dynamic configuration, etc..) */
+ std::string identify() const { return "ConjectureGenerator"; }
+//options
+private:
+ bool optReqDistinctVarPatterns();
+ bool optFilterUnknown();
+ int optFilterScoreThreshold();
+ unsigned optFullCheckFrequency();
+ unsigned optFullCheckConjectures();
+
+ bool optStatsOnly();
+};
+
+
+}
+}
+}
+
+#endif
diff --git a/src/theory/quantifiers/first_order_model.cpp b/src/theory/quantifiers/first_order_model.cpp
index 1421c639f..1570ba306 100644
--- a/src/theory/quantifiers/first_order_model.cpp
+++ b/src/theory/quantifiers/first_order_model.cpp
@@ -74,7 +74,7 @@ Node FirstOrderModel::getCurrentModelValue( Node n, bool partial ) {
}
}
-void FirstOrderModel::initialize( bool considerAxioms ) {
+void FirstOrderModel::initialize() {
processInitialize( true );
//this is called after representatives have been chosen and the equality engine has been built
//for each quantifier, collect all operators we care about
@@ -86,10 +86,8 @@ void FirstOrderModel::initialize( bool considerAxioms ) {
}
}
processInitializeQuantifier( f );
- if( considerAxioms || !f.hasAttribute(AxiomAttribute()) ){
- //initialize relevant models within bodies of all quantifiers
- initializeModelForTerm( f[1] );
- }
+ //initialize relevant models within bodies of all quantifiers
+ initializeModelForTerm( f[1] );
}
processInitialize( false );
}
@@ -115,6 +113,24 @@ Node FirstOrderModel::getSomeDomainElement(TypeNode tn){
return d_rep_set.d_type_reps[tn][0];
}
+void FirstOrderModel::reset_round() {
+ d_quant_active.clear();
+}
+
+void FirstOrderModel::setQuantifierActive( TNode q, bool active ) {
+ d_quant_active[q] = active;
+}
+
+bool FirstOrderModel::isQuantifierActive( TNode q ) {
+ std::map< TNode, bool >::iterator it = d_quant_active.find( q );
+ if( it==d_quant_active.end() ){
+ return true;
+ }else{
+ return it->second;
+ }
+}
+
+
FirstOrderModelIG::FirstOrderModelIG(QuantifiersEngine * qe, context::Context* c, std::string name) :
FirstOrderModel(qe, c,name) {
@@ -661,18 +677,24 @@ Node FirstOrderModelFmc::getFunctionValue(Node op, const char* argPrefix ) {
Node curr;
for( int i=(d_models[op]->d_cond.size()-1); i>=0; i--) {
Node v = d_models[op]->d_value[i];
+ Trace("fmc-model-func") << "Value is : " << v << std::endl;
if( !hasTerm( v ) ){
//can happen when the model basis term does not exist in ground assignment
TypeNode tn = v.getType();
- if( d_rep_set.d_type_reps.find( tn )!=d_rep_set.d_type_reps.end() && !d_rep_set.d_type_reps[ tn ].empty() ){
- //see full_model_check.cpp line 366
- v = d_rep_set.d_type_reps[tn][ d_rep_set.d_type_reps[tn].size()-1 ];
- }else{
- Assert( false );
+ //check if it is a constant introduced as a representative not existing in the model's equality engine
+ if( !d_rep_set.hasRep( tn, v ) ){
+ if( d_rep_set.d_type_reps.find( tn )!=d_rep_set.d_type_reps.end() && !d_rep_set.d_type_reps[ tn ].empty() ){
+ //see full_model_check.cpp line 366
+ v = d_rep_set.d_type_reps[tn][ d_rep_set.d_type_reps[tn].size()-1 ];
+ }else{
+ Assert( false );
+ }
+ Trace("fmc-model-func") << "No term, assign " << v << std::endl;
}
}
v = getRepresentative( v );
if( curr.isNull() ){
+ Trace("fmc-model-func") << "base : " << v << std::endl;
curr = v;
}else{
//make the condition
@@ -695,6 +717,8 @@ Node FirstOrderModelFmc::getFunctionValue(Node op, const char* argPrefix ) {
}
Assert( !children.empty() );
Node cc = children.size()==1 ? children[0] : NodeManager::currentNM()->mkNode( AND, children );
+
+ Trace("fmc-model-func") << "condition : " << cc << ", value : " << v << std::endl;
curr = NodeManager::currentNM()->mkNode( ITE, cc, v, curr );
}
}
diff --git a/src/theory/quantifiers/first_order_model.h b/src/theory/quantifiers/first_order_model.h
index 76c3946ce..0b282d5a5 100644
--- a/src/theory/quantifiers/first_order_model.h
+++ b/src/theory/quantifiers/first_order_model.h
@@ -78,7 +78,7 @@ public:
virtual FirstOrderModelQInt * asFirstOrderModelQInt() { return NULL; }
virtual FirstOrderModelAbs * asFirstOrderModelAbs() { return NULL; }
// initialize the model
- void initialize( bool considerAxioms = true );
+ void initialize();
virtual void processInitialize( bool ispre ) = 0;
/** mark model set */
void markModelSet() { d_isModelSet = true; }
@@ -92,6 +92,19 @@ public:
}
/** get some domain element */
Node getSomeDomainElement(TypeNode tn);
+private:
+ //list of inactive quantified formulas
+ std::map< TNode, bool > d_quant_active;
+public:
+ /** reset round */
+ void reset_round();
+ /** set quantified formula active/inactive
+ * a quantified formula may be set inactive if for instance:
+ * - it is entailed by other quantified formulas
+ */
+ void setQuantifierActive( TNode q, bool active );
+ /** is quantified formula active */
+ bool isQuantifierActive( TNode q );
};/* class FirstOrderModel */
diff --git a/src/theory/quantifiers/first_order_reasoning.cpp b/src/theory/quantifiers/first_order_reasoning.cpp
index df60bbc33..5435fba34 100644
--- a/src/theory/quantifiers/first_order_reasoning.cpp
+++ b/src/theory/quantifiers/first_order_reasoning.cpp
@@ -23,7 +23,6 @@ using namespace std;
using namespace CVC4::theory;
using namespace CVC4::theory::quantifiers;
using namespace CVC4::kind;
-using namespace CVC4::context;
void FirstOrderPropagation::collectLits( Node n, std::vector<Node> & lits ){
diff --git a/src/theory/quantifiers/full_model_check.cpp b/src/theory/quantifiers/full_model_check.cpp
index d5ed5589b..3148901da 100644
--- a/src/theory/quantifiers/full_model_check.cpp
+++ b/src/theory/quantifiers/full_model_check.cpp
@@ -335,7 +335,7 @@ 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 );
+ fm->initialize();
d_quant_models.clear();
d_rep_ids.clear();
d_star_insts.clear();
@@ -811,9 +811,11 @@ bool FullModelChecker::exhaustiveInstantiate(FirstOrderModelFmc * fm, Node f, No
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 );
+ if( !riter.isFinished() ){
+ 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;
@@ -871,7 +873,7 @@ void FullModelChecker::doCheck(FirstOrderModelFmc * fm, Node f, Def & d, Node n
Trace("fmc-debug") << "Can't process base array " << r << std::endl;
//can't process this array
d.reset();
- d.addEntry(fm, defC, Node::null());
+ d.addEntry(fm, mkCondDefault(fm, f), Node::null());
}
}
else if( n.getNumChildren()==0 ){
diff --git a/src/theory/quantifiers/fun_def_process.cpp b/src/theory/quantifiers/fun_def_process.cpp
new file mode 100644
index 000000000..cb772a31f
--- /dev/null
+++ b/src/theory/quantifiers/fun_def_process.cpp
@@ -0,0 +1,197 @@
+/********************* */
+/*! \file fun_def_process.cpp
+ ** \verbatim
+ ** Original author: Andrew Reynolds
+ ** Major contributors: Morgan Deters
+ ** Minor contributors (to current version): Kshitij Bansal
+ ** This file is part of the CVC4 project.
+ ** Copyright (c) 2009-2014 New York University and The University of Iowa
+ ** See the file COPYING in the top-level source directory for licensing
+ ** information.\endverbatim
+ **
+ ** \brief Sort inference module
+ **
+ ** This class implements pre-process steps for well-defined functions
+ **/
+
+#include <vector>
+
+#include "theory/quantifiers/fun_def_process.h"
+#include "theory/rewriter.h"
+#include "theory/quantifiers/term_database.h"
+#include "theory/quantifiers/quant_util.h"
+
+using namespace CVC4;
+using namespace std;
+using namespace CVC4::theory;
+using namespace CVC4::theory::quantifiers;
+using namespace CVC4::kind;
+
+
+void FunDefFmf::simplify( std::vector< Node >& assertions, bool doRewrite ) {
+ std::vector< int > fd_assertions;
+ //first pass : find defined functions, transform quantifiers
+ for( unsigned i=0; i<assertions.size(); i++ ){
+ if( assertions[i].getKind()==FORALL ){
+ if( quantifiers::TermDb::isFunDef( assertions[i] ) ){
+ Assert( assertions[i][1].getKind()==EQUAL || assertions[i][1].getKind()==IFF );
+ Node n = assertions[i][1][0];
+ Assert( n.getKind()==APPLY_UF );
+ Node f = n.getOperator();
+
+ //check if already defined, if so, throw error
+ if( d_sorts.find( f )!=d_sorts.end() ){
+ Message() << "Cannot define function " << f << " more than once." << std::endl;
+ exit( 0 );
+ }
+
+ //create a sort S that represents the inputs of the function
+ std::stringstream ss;
+ ss << "I_" << f;
+ TypeNode iType = NodeManager::currentNM()->mkSort( ss.str() );
+ d_sorts[f] = iType;
+
+ //create functions f1...fn mapping from this sort to concrete elements
+ for( unsigned j=0; j<n.getNumChildren(); j++ ){
+ TypeNode typ = NodeManager::currentNM()->mkFunctionType( iType, n[j].getType() );
+ std::stringstream ss;
+ ss << f << "_arg_" << j;
+ d_input_arg_inj[f].push_back( NodeManager::currentNM()->mkSkolem( ss.str(), typ, "op created during fun def fmf" ) );
+ }
+
+ //construct new quantifier forall S. F[f1(S)/x1....fn(S)/xn]
+ std::vector< Node > children;
+ Node bv = NodeManager::currentNM()->mkBoundVar("?i", iType );
+ Node bvl = NodeManager::currentNM()->mkNode( kind::BOUND_VAR_LIST, bv );
+ std::vector< Node > subs;
+ std::vector< Node > vars;
+ for( unsigned j=0; j<n.getNumChildren(); j++ ){
+ vars.push_back( n[j] );
+ subs.push_back( NodeManager::currentNM()->mkNode( APPLY_UF, d_input_arg_inj[f][j], bv ) );
+ }
+ Node bd = assertions[i][1].substitute( vars.begin(), vars.end(), subs.begin(), subs.end() );
+
+ Trace("fmf-fun-def") << "FMF fun def: rewrite " << assertions[i] << std::endl;
+ Trace("fmf-fun-def") << " to " << std::endl;
+ assertions[i] = NodeManager::currentNM()->mkNode( FORALL, bvl, bd );
+ Trace("fmf-fun-def") << " " << assertions[i] << std::endl;
+ fd_assertions.push_back( i );
+ }
+ }
+ }
+ //second pass : rewrite assertions
+ for( unsigned i=0; i<assertions.size(); i++ ){
+ bool is_fd = std::find( fd_assertions.begin(), fd_assertions.end(), i )!=fd_assertions.end();
+ std::vector< Node > constraints;
+ Node n = simplify( assertions[i], true, true, constraints, is_fd );
+ Assert( constraints.empty() );
+ if( n!=assertions[i] ){
+ n = Rewriter::rewrite( n );
+ Trace("fmf-fun-def-rewrite") << "FMF fun def : rewrite " << assertions[i] << std::endl;
+ Trace("fmf-fun-def-rewrite") << " to " << std::endl;
+ Trace("fmf-fun-def-rewrite") << " " << n << std::endl;
+ assertions[i] = n;
+ }
+ }
+}
+
+Node FunDefFmf::simplify( Node n, bool pol, bool hasPol, std::vector< Node >& constraints, bool is_fun_def ) {
+ Trace("fmf-fun-def-debug") << "Simplify " << n << " " << pol << " " << hasPol << " " << is_fun_def << std::endl;
+ if( n.getKind()==FORALL ){
+ Node c = simplify( n[1], pol, hasPol, constraints, is_fun_def );
+ if( c!=n[1] ){
+ return NodeManager::currentNM()->mkNode( FORALL, n[0], c );
+ }else{
+ return n;
+ }
+ }else if( n.getType().isBoolean() && n.getKind()!=APPLY_UF ){
+ std::vector< Node > children;
+ bool childChanged = false;
+ for( unsigned i=0; i<n.getNumChildren(); i++ ){
+ Node c = n[i];
+ //do not process LHS of definition
+ if( !is_fun_def || i!=0 ){
+ bool newHasPol;
+ bool newPol;
+ QuantPhaseReq::getPolarity( n, i, hasPol, pol, newHasPol, newPol );
+ //get child constraints
+ std::vector< Node > cconstraints;
+ c = simplify( n[i], newPol, newHasPol, cconstraints );
+ constraints.insert( constraints.end(), cconstraints.begin(), cconstraints.end() );
+ }
+ children.push_back( c );
+ childChanged = c!=n[i] || childChanged;
+ }
+ if( !constraints.empty() || childChanged ){
+ std::vector< Node > c;
+ if( childChanged ){
+ c.push_back( NodeManager::currentNM()->mkNode( n.getKind(), children ) );
+ }else{
+ c.push_back( n );
+ }
+ if( hasPol ){
+ //conjoin with current
+ for( unsigned i=0; i<constraints.size(); i++ ){
+ if( pol ){
+ c.push_back( constraints[i] );
+ }else{
+ c.push_back( constraints[i].negate() );
+ }
+ }
+ constraints.clear();
+ }else{
+ //must add at higher level
+ }
+ return c.size()==1 ? c[0] : NodeManager::currentNM()->mkNode( pol ? AND : OR, c );
+ }
+ }else{
+ //simplify term
+ simplifyTerm( n, constraints );
+ }
+ return n;
+}
+
+void FunDefFmf::simplifyTerm( Node n, std::vector< Node >& constraints ) {
+ Trace("fmf-fun-def-debug") << "Simplify term " << n << std::endl;
+ if( n.getKind()==ITE ){
+ simplifyTerm( n[0], constraints );
+ std::vector< Node > ccons1;
+ std::vector< Node > ccons2;
+ simplifyTerm( n[1], ccons1 );
+ simplifyTerm( n[2], ccons2 );
+ if( !ccons1.empty() || !ccons2.empty() ){
+ Node n1 = ccons1.empty() ? NodeManager::currentNM()->mkConst( true ) : ( ccons1.size()==1 ? ccons1[0] : NodeManager::currentNM()->mkNode( AND, ccons1 ) );
+ Node n2 = ccons2.empty() ? NodeManager::currentNM()->mkConst( true ) : ( ccons2.size()==1 ? ccons2[0] : NodeManager::currentNM()->mkNode( AND, ccons2 ) );
+ constraints.push_back( NodeManager::currentNM()->mkNode( ITE, n[0], n1, n2 ) );
+ }
+ }else{
+ if( n.getKind()==APPLY_UF ){
+ //check if f is defined, if so, we must enforce domain constraints for this f-application
+ Node f = n.getOperator();
+ std::map< Node, TypeNode >::iterator it = d_sorts.find( f );
+ if( it!=d_sorts.end() ){
+ //create existential
+ Node z = NodeManager::currentNM()->mkBoundVar("?z", it->second );
+ Node bvl = NodeManager::currentNM()->mkNode( BOUND_VAR_LIST, z );
+ std::vector< Node > children;
+ for( unsigned j=0; j<n.getNumChildren(); j++ ){
+ Node uz = NodeManager::currentNM()->mkNode( APPLY_UF, d_input_arg_inj[f][j], z );
+ if( !n[j].getType().isBoolean() ){
+ children.push_back( uz.eqNode( n[j] ) );
+ }else{
+ children.push_back( uz.iffNode( n[j] ) );
+ }
+ }
+ Node bd = children.size()==1 ? children[0] : NodeManager::currentNM()->mkNode( AND, children );
+ bd = bd.negate();
+ Node ex = NodeManager::currentNM()->mkNode( FORALL, bvl, bd );
+ ex = ex.negate();
+ constraints.push_back( ex );
+ Trace("fmf-fun-def-debug") << "---> add constraint " << ex << std::endl;
+ }
+ }
+ for( unsigned i=0; i<n.getNumChildren(); i++ ){
+ simplifyTerm( n[i], constraints );
+ }
+ }
+}
diff --git a/src/theory/quantifiers/fun_def_process.h b/src/theory/quantifiers/fun_def_process.h
new file mode 100644
index 000000000..40364eeb7
--- /dev/null
+++ b/src/theory/quantifiers/fun_def_process.h
@@ -0,0 +1,54 @@
+/********************* */
+/*! \file fun_def_process.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-2014 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 steps for well-defined functions
+ **/
+
+#include "cvc4_private.h"
+
+#ifndef __CVC4__QUANTIFIERS_FUN_DEF_PROCESS_H
+#define __CVC4__QUANTIFIERS_FUN_DEF_PROCESS_H
+
+#include <iostream>
+#include <string>
+#include <vector>
+#include <map>
+#include "expr/node.h"
+#include "expr/type_node.h"
+
+namespace CVC4 {
+namespace theory {
+namespace quantifiers {
+
+//find finite models for well-defined functions
+class FunDefFmf {
+private:
+ //defined functions to input sort
+ std::map< Node, TypeNode > d_sorts;
+ //defined functions to injections input -> argument elements
+ std::map< Node, std::vector< Node > > d_input_arg_inj;
+ //simplify
+ Node simplify( Node n, bool pol, bool hasPol, std::vector< Node >& constraints, bool is_fun_def = false );
+ //simplify term
+ void simplifyTerm( Node n, std::vector< Node >& constraints );
+public:
+ FunDefFmf(){}
+ ~FunDefFmf(){}
+
+ void simplify( std::vector< Node >& assertions, bool doRewrite = false );
+};
+
+
+}
+}
+}
+
+#endif
diff --git a/src/theory/quantifiers/inst_gen.cpp b/src/theory/quantifiers/inst_gen.cpp
index 971b3a5ee..33fcaa27a 100644
--- a/src/theory/quantifiers/inst_gen.cpp
+++ b/src/theory/quantifiers/inst_gen.cpp
@@ -51,7 +51,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 ) );
- ((QModelBuilderIG*)qe->getModelEngine()->getModelBuilder())->d_instGenMatches++;
+ ((QModelBuilderIG*)qe->getModelBuilder())->d_instGenMatches++;
}
}
}
@@ -96,7 +96,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 = ((QModelBuilderIG*)qe->getModelEngine()->getModelBuilder())->isTermSelected( n );
+ bool isSelected = ((QModelBuilderIG*)qe->getModelBuilder())->isTermSelected( n );
bool hadSuccess CVC4_UNUSED = false;
for( int t=(isSelected ? 0 : 1); t<2; t++ ){
if( t==0 || !n.getAttribute(NoMatchAttribute()) ){
@@ -197,7 +197,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 = ((QModelBuilderIG*)qe->getModelEngine()->getModelBuilder())->isTermSelected( n );
+ bool isSelected = ((QModelBuilderIG*)qe->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_generator.cpp b/src/theory/quantifiers/inst_match_generator.cpp
index c024d0bab..c78ea7b01 100644
--- a/src/theory/quantifiers/inst_match_generator.cpp
+++ b/src/theory/quantifiers/inst_match_generator.cpp
@@ -30,14 +30,21 @@ namespace CVC4 {
namespace theory {
namespace inst {
-
-InstMatchGenerator::InstMatchGenerator( Node pat, int matchPolicy ) : d_matchPolicy( matchPolicy ){
+InstMatchGenerator::InstMatchGenerator( Node pat ){
d_needsReset = true;
d_active_add = false;
Assert( quantifiers::TermDb::hasInstConstAttr(pat) );
d_pattern = pat;
d_match_pattern = pat;
d_next = NULL;
+ d_matchPolicy = MATCH_GEN_DEFAULT;
+}
+
+InstMatchGenerator::InstMatchGenerator() {
+ d_needsReset = true;
+ d_active_add = false;
+ d_next = NULL;
+ d_matchPolicy = MATCH_GEN_DEFAULT;
}
void InstMatchGenerator::setActiveAdd(bool val){
@@ -89,24 +96,31 @@ void InstMatchGenerator::initialize( QuantifiersEngine* qe, std::vector< InstMat
d_match_pattern_op = qe->getTermDatabase()->getOperator( d_match_pattern );
//now, collect children of d_match_pattern
- int childMatchPolicy = MATCH_GEN_DEFAULT;
+ //int childMatchPolicy = MATCH_GEN_DEFAULT;
for( int i=0; i<(int)d_match_pattern.getNumChildren(); i++ ){
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 );
+ InstMatchGenerator * cimg = Trigger::getInstMatchGenerator( d_match_pattern[i] );
+ if( cimg ){
d_children.push_back( cimg );
d_children_index.push_back( i );
gens.push_back( cimg );
+ d_children_types.push_back( 1 );
+ }else{
+ d_var_num[i] = d_match_pattern[i].getAttribute(InstVarNumAttribute());
+ d_children_types.push_back( 0 );
}
+ }else{
+ d_children_types.push_back( -1 );
}
}
+ if( d_match_pattern.getKind()==INST_CONSTANT ){
+ d_var_num[0] = d_match_pattern.getAttribute(InstVarNumAttribute());
+ }
//create candidate generator
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 );
+ }else if( d_match_pattern.getKind()==EQUAL || d_match_pattern.getKind()==IFF ){
//we will be producing candidates via literal matching heuristics
if( d_pattern.getKind()!=NOT ){
//candidates will be all equalities
@@ -139,15 +153,6 @@ void InstMatchGenerator::initialize( QuantifiersEngine* qe, std::vector< InstMat
Trace("inst-match-gen-warn") << "(?) Unknown matching pattern is " << d_match_pattern << std::endl;
d_matchPolicy = MATCH_GEN_INTERNAL_ERROR;
}
- for( int i=0; i<(int)d_match_pattern.getNumChildren(); i++ ){
- if( d_match_pattern[i].getKind()==INST_CONSTANT || Trigger::isBooleanTermTrigger( d_match_pattern[i] ) ){
- Node vv = d_match_pattern[i];
- if( Trigger::isBooleanTermTrigger( d_match_pattern[i] ) ){
- vv = d_match_pattern[i][0];
- }
- d_var_num[i] = vv.getAttribute(InstVarNumAttribute());
- }
- }
}
}
@@ -157,6 +162,7 @@ bool InstMatchGenerator::getMatch( Node f, Node t, InstMatch& m, QuantifiersEngi
<< m << ")" << ", " << d_children.size() << ", pattern is " << d_pattern << std::endl;
Assert( !d_match_pattern.isNull() );
if( d_matchPolicy==MATCH_GEN_INTERNAL_ERROR ){
+ Trace("matching-fail") << "Internal error for match generator." << std::endl;
return false;
}else{
EqualityQuery* q = qe->getEqualityQuery();
@@ -167,27 +173,23 @@ bool InstMatchGenerator::getMatch( Node f, Node t, InstMatch& m, QuantifiersEngi
//if t is null
Assert( !t.isNull() );
Assert( !quantifiers::TermDb::hasInstConstAttr(t) );
- Assert( t.getKind()==d_match_pattern.getKind() );
+ Assert( d_match_pattern.getKind()==INST_CONSTANT || 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( quantifiers::TermDb::hasInstConstAttr(d_match_pattern[i]) ){
- if( d_match_pattern[i].getKind()==INST_CONSTANT || Trigger::isBooleanTermTrigger( d_match_pattern[i] ) ){
- Node tt = t[i];
- if( Trigger::isBooleanTermTrigger( d_match_pattern[i] ) ){
- tt = NodeManager::currentNM()->mkConst(q->areEqual( tt, d_match_pattern[i][1] ));
- }
- bool addToPrev = m.get( d_var_num[i] ).isNull();
- if( !m.set( qe, d_var_num[i], tt ) ){
- //match is in conflict
- Trace("matching-fail") << "Match fail: " << m.get(d_var_num[i]) << " and " << tt << std::endl;
- success = false;
- break;
- }else if( addToPrev ){
- prev.push_back( d_var_num[i] );
- }
+ if( d_children_types[i]==0 ){
+ Trace("matching-debug2") << "Setting " << d_var_num[i] << " to " << t[i] << "..." << std::endl;
+ bool addToPrev = m.get( d_var_num[i] ).isNull();
+ if( !m.set( qe, d_var_num[i], t[i] ) ){
+ //match is in conflict
+ Trace("matching-fail") << "Match fail: " << m.get(d_var_num[i]) << " and " << t[i] << std::endl;
+ success = false;
+ break;
+ }else if( addToPrev ){
+ Trace("matching-debug2") << "Success." << std::endl;
+ prev.push_back( d_var_num[i] );
}
- }else{
+ }else if( d_children_types[i]==-1 ){
if( !q->areEqual( d_match_pattern[i], t[i] ) ){
Trace("matching-fail") << "Match fail arg: " << d_match_pattern[i] << " and " << t[i] << std::endl;
//ground arguments are not equal
@@ -196,8 +198,18 @@ bool InstMatchGenerator::getMatch( Node f, Node t, InstMatch& m, QuantifiersEngi
}
}
}
+ //for variable matching
+ if( d_match_pattern.getKind()==INST_CONSTANT ){
+ bool addToPrev = m.get( d_var_num[0] ).isNull();
+ if( !m.set( qe, d_var_num[0], t ) ){
+ success = false;
+ }else{
+ if( addToPrev ){
+ prev.push_back( d_var_num[0] );
+ }
+ }
//for relational matching
- if( !d_eq_class.isNull() && d_eq_class.getKind()==INST_CONSTANT ){
+ }else if( !d_eq_class.isNull() && d_eq_class.getKind()==INST_CONSTANT ){
int v = d_eq_class.getAttribute(InstVarNumAttribute());
//also must fit match to equivalence class
bool pol = d_pattern.getKind()!=NOT;
@@ -236,18 +248,9 @@ bool InstMatchGenerator::getMatch( Node f, Node t, InstMatch& m, QuantifiersEngi
//now, fit children into match
//we will be requesting candidates for matching terms for each child
for( int i=0; i<(int)d_children.size(); i++ ){
- Node rep = q->getRepresentative( t[ d_children_index[i] ] );
- d_children[i]->reset( rep, qe );
- }
- if( d_next!=NULL ){
- success = d_next->getNextMatch( f, m, qe );
- }else{
- if( d_active_add ){
- Trace("active-add") << "Active Adding instantiation " << m << std::endl;
- success = qe->addInstantiation( f, m, false );
- Trace("active-add") << "Success = " << success << std::endl;
- }
+ d_children[i]->reset( t[ d_children_index[i] ], qe );
}
+ success = continueNextMatch( f, m, qe );
}
if( !success ){
//m = InstMatch( &prev );
@@ -259,6 +262,18 @@ bool InstMatchGenerator::getMatch( Node f, Node t, InstMatch& m, QuantifiersEngi
}
}
+bool InstMatchGenerator::continueNextMatch( Node f, InstMatch& m, QuantifiersEngine* qe ){
+ if( d_next!=NULL ){
+ return d_next->getNextMatch( f, m, qe );
+ }else{
+ if( d_active_add ){
+ return qe->addInstantiation( f, m, false );
+ }else{
+ return true;
+ }
+ }
+}
+
/** reset instantiation round */
void InstMatchGenerator::resetInstantiationRound( QuantifiersEngine* qe ){
if( !d_match_pattern.isNull() ){
@@ -274,6 +289,7 @@ void InstMatchGenerator::resetInstantiationRound( QuantifiersEngine* qe ){
}
void InstMatchGenerator::reset( Node eqc, QuantifiersEngine* qe ){
+ eqc = qe->getEqualityQuery()->getRepresentative( eqc );
Trace("matching-debug2") << this << " reset " << eqc << "." << std::endl;
if( !eqc.isNull() ){
d_eq_class = eqc;
@@ -321,7 +337,7 @@ int InstMatchGenerator::addInstantiations( Node f, InstMatch& baseMatch, Quantif
while( getNextMatch( f, m, qe ) ){
if( !d_active_add ){
m.add( baseMatch );
- if( qe->addInstantiation( f, m ) ){
+ if( qe->addInstantiation( f, m, false ) ){
addedLemmas++;
}
}else{
@@ -338,7 +354,7 @@ int InstMatchGenerator::addTerm( Node f, Node t, QuantifiersEngine* qe ){
if( !d_match_pattern.isNull() ){
InstMatch m( f );
if( getMatch( f, t, m, qe ) ){
- if( qe->addInstantiation( f, m ) ){
+ if( qe->addInstantiation( f, m, false ) ){
return 1;
}
}
@@ -384,6 +400,59 @@ InstMatchGenerator* InstMatchGenerator::mkInstMatchGenerator( std::vector< Node
return oinit;
}
+VarMatchGeneratorBooleanTerm::VarMatchGeneratorBooleanTerm( Node var, Node comp ) :
+ InstMatchGenerator(), d_comp( comp ), d_rm_prev( false ) {
+ d_var_num[0] = var.getAttribute(InstVarNumAttribute());
+}
+
+bool VarMatchGeneratorBooleanTerm::getNextMatch( Node f, InstMatch& m, QuantifiersEngine* qe ) {
+ if( !d_eq_class.isNull() ){
+ Node s = NodeManager::currentNM()->mkConst(qe->getEqualityQuery()->areEqual( d_eq_class, d_pattern ));
+ d_eq_class = Node::null();
+ d_rm_prev = m.get( d_var_num[0] ).isNull();
+ if( !m.set( qe, d_var_num[0], s ) ){
+ return false;
+ }else{
+ if( continueNextMatch( f, m, qe ) ){
+ return true;
+ }
+ }
+ }
+ if( d_rm_prev ){
+ m.d_vals[d_var_num[0]] = Node::null();
+ d_rm_prev = false;
+ }
+ return false;
+}
+
+VarMatchGeneratorTermSubs::VarMatchGeneratorTermSubs( Node var, Node subs ) :
+ InstMatchGenerator(), d_var( var ), d_subs( subs ), d_rm_prev( false ){
+ d_var_num[0] = d_var.getAttribute(InstVarNumAttribute());
+}
+
+bool VarMatchGeneratorTermSubs::getNextMatch( Node f, InstMatch& m, QuantifiersEngine* qe ) {
+ if( !d_eq_class.isNull() ){
+ Trace("var-trigger-matching") << "Matching " << d_eq_class << " against " << d_var << " in " << d_subs << std::endl;
+ Node s = d_subs.substitute( d_var, d_eq_class );
+ s = Rewriter::rewrite( s );
+ Trace("var-trigger-matching") << "...got " << s << std::endl;
+ d_eq_class = Node::null();
+ d_rm_prev = m.get( d_var_num[0] ).isNull();
+ if( !m.set( qe, d_var_num[0], s ) ){
+ return false;
+ }else{
+ if( continueNextMatch( f, m, qe ) ){
+ return true;
+ }
+ }
+ }
+ if( d_rm_prev ){
+ m.d_vals[d_var_num[0]] = Node::null();
+ d_rm_prev = false;
+ }
+ return false;
+}
+
/** constructors */
InstMatchGeneratorMulti::InstMatchGeneratorMulti( Node f, std::vector< Node >& pats, QuantifiersEngine* qe, int matchOption ) :
d_f( f ){
@@ -578,7 +647,7 @@ void InstMatchGeneratorMulti::processNewInstantiations2( QuantifiersEngine* qe,
}
}else{
//m is an instantiation
- if( qe->addInstantiation( d_f, m ) ){
+ if( qe->addInstantiation( d_f, m, false ) ){
addedLemmas++;
Debug("smart-multi-trigger") << "-> Produced instantiation " << m << std::endl;
}
@@ -618,13 +687,7 @@ int InstMatchGeneratorSimple::addInstantiations( Node f, InstMatch& baseMatch, Q
m.add( baseMatch );
int addedLemmas = 0;
- if( d_match_pattern.getType()==NodeManager::currentNM()->booleanType() ){
- for( int i=0; i<2; i++ ){
- addInstantiations( m, qe, addedLemmas, 0, &(qe->getTermDatabase()->d_pred_map_trie[i][ d_op ]) );
- }
- }else{
- addInstantiations( m, qe, addedLemmas, 0, &(qe->getTermDatabase()->d_func_map_trie[ d_op ]) );
- }
+ addInstantiations( m, qe, addedLemmas, 0, &(qe->getTermDatabase()->d_func_map_trie[ d_op ]) );
return addedLemmas;
}
@@ -646,7 +709,7 @@ void InstMatchGeneratorSimple::addInstantiations( InstMatch& m, QuantifiersEngin
}else{
if( d_match_pattern[argIndex].getKind()==INST_CONSTANT ){
int v = d_var_num[argIndex];
- for( std::map< Node, quantifiers::TermArgTrie >::iterator it = tat->d_data.begin(); it != tat->d_data.end(); ++it ){
+ for( std::map< TNode, quantifiers::TermArgTrie >::iterator it = tat->d_data.begin(); it != tat->d_data.end(); ++it ){
Node t = it->first;
Node prev = m.get( v );
//using representatives, just check if equal
@@ -658,7 +721,7 @@ void InstMatchGeneratorSimple::addInstantiations( InstMatch& m, QuantifiersEngin
}
}else{
Node r = qe->getEqualityQuery()->getRepresentative( d_match_pattern[argIndex] );
- std::map< Node, quantifiers::TermArgTrie >::iterator it = tat->d_data.find( r );
+ std::map< TNode, quantifiers::TermArgTrie >::iterator it = tat->d_data.find( r );
if( it!=tat->d_data.end() ){
addInstantiations( m, qe, addedLemmas, argIndex+1, &(it->second) );
}
@@ -676,7 +739,7 @@ int InstMatchGeneratorSimple::addTerm( Node f, Node t, QuantifiersEngine* qe ){
return 0;
}
}
- return qe->addInstantiation( f, m ) ? 1 : 0;
+ return qe->addInstantiation( f, m, false ) ? 1 : 0;
}
}/* CVC4::theory::inst namespace */
diff --git a/src/theory/quantifiers/inst_match_generator.h b/src/theory/quantifiers/inst_match_generator.h
index 56eaf2c17..aa5d37713 100644
--- a/src/theory/quantifiers/inst_match_generator.h
+++ b/src/theory/quantifiers/inst_match_generator.h
@@ -42,7 +42,7 @@ public:
/** add instantiations directly */
virtual int addInstantiations( Node f, InstMatch& baseMatch, QuantifiersEngine* qe ) = 0;
/** add ground term t, called when t is added to term db */
- virtual int addTerm( Node f, Node t, QuantifiersEngine* qe ) = 0;
+ virtual int addTerm( Node f, Node t, QuantifiersEngine* qe ) { return 0; }
/** set active add */
virtual void setActiveAdd( bool val ) {}
};/* class IMGenerator */
@@ -50,7 +50,7 @@ public:
class CandidateGenerator;
class InstMatchGenerator : public IMGenerator {
-private:
+protected:
bool d_needsReset;
/** candidate generator */
CandidateGenerator* d_cg;
@@ -63,17 +63,18 @@ private:
InstMatchGenerator* d_next;
/** eq class */
Node d_eq_class;
- /** for arithmetic matching */
- std::map< Node, Node > d_arith_coeffs;
/** variable numbers */
std::map< int, int > d_var_num;
/** initialize pattern */
void initialize( QuantifiersEngine* qe, std::vector< InstMatchGenerator * > & gens );
+ /** children types 0 : variable, 1 : child term, -1 : ground term */
+ std::vector< int > d_children_types;
+ /** continue */
+ bool continueNextMatch( Node f, InstMatch& m, QuantifiersEngine* qe );
public:
enum {
//options for producing matches
MATCH_GEN_DEFAULT = 0,
- MATCH_GEN_EFFICIENT_E_MATCH, //generate matches via Efficient E-matching for SMT solvers
//others (internally used)
MATCH_GEN_INTERNAL_ERROR,
};
@@ -85,7 +86,8 @@ public:
bool getMatch( Node f, Node t, InstMatch& m, QuantifiersEngine* qe );
/** constructors */
- InstMatchGenerator( Node pat, int matchOption = 0 );
+ InstMatchGenerator( Node pat );
+ InstMatchGenerator();
/** destructor */
~InstMatchGenerator(){}
/** The pattern we are producing matches for.
@@ -115,6 +117,39 @@ public:
static InstMatchGenerator* mkInstMatchGenerator( std::vector< Node >& pats, QuantifiersEngine* qe );
};/* class InstMatchGenerator */
+//match generator for boolean term ITEs
+class VarMatchGeneratorBooleanTerm : public InstMatchGenerator {
+public:
+ VarMatchGeneratorBooleanTerm( Node var, Node comp );
+ Node d_comp;
+ bool d_rm_prev;
+ /** reset instantiation round (call this at beginning of instantiation round) */
+ void resetInstantiationRound( QuantifiersEngine* qe ){}
+ /** reset, eqc is the equivalence class to search in (any if eqc=null) */
+ void reset( Node eqc, QuantifiersEngine* qe ){ d_eq_class = eqc; }
+ /** get the next match. must call reset( eqc ) before this function. */
+ bool getNextMatch( Node f, InstMatch& m, QuantifiersEngine* qe );
+ /** add instantiations directly */
+ int addInstantiations( Node f, InstMatch& baseMatch, QuantifiersEngine* qe ){ return 0; }
+};
+
+//match generator for purified terms (matched term is substituted into d_subs)
+class VarMatchGeneratorTermSubs : public InstMatchGenerator {
+public:
+ VarMatchGeneratorTermSubs( Node var, Node subs );
+ TNode d_var;
+ Node d_subs;
+ bool d_rm_prev;
+ /** reset instantiation round (call this at beginning of instantiation round) */
+ void resetInstantiationRound( QuantifiersEngine* qe ){}
+ /** reset, eqc is the equivalence class to search in (any if eqc=null) */
+ void reset( Node eqc, QuantifiersEngine* qe ){ d_eq_class = eqc; }
+ /** get the next match. must call reset( eqc ) before this function. */
+ bool getNextMatch( Node f, InstMatch& m, QuantifiersEngine* qe );
+ /** add instantiations directly */
+ int addInstantiations( Node f, InstMatch& baseMatch, QuantifiersEngine* qe ) { return 0; }
+};
+
/** smart multi-trigger implementation */
class InstMatchGeneratorMulti : public IMGenerator {
private:
diff --git a/src/theory/quantifiers/inst_strategy_cbqi.cpp b/src/theory/quantifiers/inst_strategy_cbqi.cpp
index 25f15cd78..6a2bd5e2e 100644
--- a/src/theory/quantifiers/inst_strategy_cbqi.cpp
+++ b/src/theory/quantifiers/inst_strategy_cbqi.cpp
@@ -347,47 +347,3 @@ Node InstStrategySimplex::getTableauxValue( ArithVar v, bool minus_delta ){
Rational qmodel = drv.substituteDelta( minus_delta ? -delta : delta );
return mkRationalNode(qmodel);
}
-
-
-InstStrategyDatatypesValue::InstStrategyDatatypesValue( TheoryDatatypes* th, QuantifiersEngine* qe ) :
- InstStrategy( qe ), d_th( th ){
-
-}
-
-bool InstStrategyDatatypesValue::calculateShouldProcess( Node f ){
- //DO_THIS
- return false;
-}
-
-void InstStrategyDatatypesValue::processResetInstantiationRound( Theory::Effort effort ){
-
-}
-
-int InstStrategyDatatypesValue::process( Node f, Theory::Effort effort, int e ){
- Debug("quant-datatypes") << "Datatypes: Try to solve (" << e << ") for " << f << "... " << std::endl;
- if( e<2 ){
- return InstStrategy::STATUS_UNFINISHED;
- }else if( e==2 ){
- InstMatch m( f );
- for( int j = 0; j<(int)d_quantEngine->getTermDatabase()->getNumInstantiationConstants( f ); j++ ){
- Node i = d_quantEngine->getTermDatabase()->getInstantiationConstant( f, j );
- if( i.getType().isDatatype() ){
- Node n = getValueFor( i );
- Debug("quant-datatypes-debug") << "Value for " << i << " is " << n << std::endl;
- m.setValue( j, n);
- }
- }
- //d_quantEngine->addInstantiation( f, m );
- }
- return InstStrategy::STATUS_UNKNOWN;
-}
-
-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( !TermDb::hasInstConstAttr(n) ){
- return n;
- }else{
- return n;
- }
-}
diff --git a/src/theory/quantifiers/inst_strategy_cbqi.h b/src/theory/quantifiers/inst_strategy_cbqi.h
index 9196b9703..bfc0501dc 100644
--- a/src/theory/quantifiers/inst_strategy_cbqi.h
+++ b/src/theory/quantifiers/inst_strategy_cbqi.h
@@ -81,29 +81,6 @@ public:
};
-class InstStrategyDatatypesValue : public InstStrategy
-{
-protected:
- /** calculate if we should process this quantifier */
- bool calculateShouldProcess( Node f );
-private:
- /** reference to theory datatypes */
- datatypes::TheoryDatatypes* d_th;
- /** get value function */
- Node getValueFor( Node n );
-public:
- //constructor
- InstStrategyDatatypesValue( datatypes::TheoryDatatypes* th, QuantifiersEngine* qe );
- ~InstStrategyDatatypesValue(){}
- /** reset instantiation */
- void processResetInstantiationRound( Theory::Effort effort );
- /** process method, returns a status */
- int process( Node f, Theory::Effort effort, int e );
- /** identify */
- std::string identify() const { return std::string("InstStrategyDatatypesValue"); }
-
-};/* class InstStrategy */
-
}
}
}
diff --git a/src/theory/quantifiers/inst_strategy_e_matching.cpp b/src/theory/quantifiers/inst_strategy_e_matching.cpp
index 5b0fade71..02536eb99 100644
--- a/src/theory/quantifiers/inst_strategy_e_matching.cpp
+++ b/src/theory/quantifiers/inst_strategy_e_matching.cpp
@@ -59,48 +59,82 @@ void InstStrategyUserPatterns::processResetInstantiationRound( Theory::Effort ef
int InstStrategyUserPatterns::process( Node f, Theory::Effort effort, int e ){
if( e==0 ){
return STATUS_UNFINISHED;
- }else if( e==1 ){
- d_counter[f]++;
+ }else{
+ int peffort = options::userPatternsQuant()==USER_PAT_MODE_RESORT ? 2 : 1;
+ if( e<peffort ){
+ return STATUS_UNFINISHED;
+ }else if( e==peffort ){
+ d_counter[f]++;
+
Trace("inst-alg") << "-> User-provided instantiate " << f << "..." << std::endl;
+ if( options::userPatternsQuant()==USER_PAT_MODE_RESORT ){
+ int matchOption = 0;
+ for( unsigned i=0; i<d_user_gen_wait[f].size(); i++ ){
+ Trigger * t = Trigger::mkTrigger( d_quantEngine, f, d_user_gen_wait[f][i], matchOption, true, Trigger::TR_RETURN_NULL, options::smartTriggers() );
+ if( t ){
+ d_user_gen[f].push_back( t );
+ }
+ }
+ d_user_gen_wait[f].clear();
+ }
- Debug("quant-uf-strategy") << "Try user-provided patterns..." << std::endl;
- //Notice() << "Try user-provided patterns..." << std::endl;
- for( int i=0; i<(int)d_user_gen[f].size(); i++ ){
- bool processTrigger = true;
- if( processTrigger ){
- //if( d_user_gen[f][i]->isMultiTrigger() )
- Trace("process-trigger") << " Process (user) " << (*d_user_gen[f][i]) << "..." << std::endl;
- InstMatch baseMatch( f );
- int numInst = d_user_gen[f][i]->addInstantiations( baseMatch );
- //if( d_user_gen[f][i]->isMultiTrigger() )
+ for( unsigned i=0; i<d_user_gen[f].size(); i++ ){
+ bool processTrigger = true;
+ if( processTrigger ){
+ Trace("process-trigger") << " Process (user) ";
+ d_user_gen[f][i]->debugPrint("process-trigger");
+ Trace("process-trigger") << "..." << std::endl;
+ InstMatch baseMatch( f );
+ int numInst = d_user_gen[f][i]->addInstantiations( baseMatch );
Trace("process-trigger") << " Done, numInst = " << numInst << "." << std::endl;
- d_quantEngine->getInstantiationEngine()->d_statistics.d_instantiations_user_patterns += numInst;
- if( d_user_gen[f][i]->isMultiTrigger() ){
- d_quantEngine->d_statistics.d_multi_trigger_instantiations += numInst;
+ d_quantEngine->getInstantiationEngine()->d_statistics.d_instantiations_user_patterns += numInst;
+ if( d_user_gen[f][i]->isMultiTrigger() ){
+ d_quantEngine->d_statistics.d_multi_trigger_instantiations += numInst;
+ }
+ //d_quantEngine->d_hasInstantiated[f] = true;
}
- //d_quantEngine->d_hasInstantiated[f] = true;
}
}
- Debug("quant-uf-strategy") << "done." << std::endl;
- //Notice() << "done" << std::endl;
}
return STATUS_UNKNOWN;
}
void InstStrategyUserPatterns::addUserPattern( Node f, Node pat ){
+ Assert( pat.getKind()==INST_PATTERN );
//add to generators
+ bool usable = true;
std::vector< Node > nodes;
for( int i=0; i<(int)pat.getNumChildren(); i++ ){
nodes.push_back( pat[i] );
+ if( pat[i].getKind()!=INST_CONSTANT && !Trigger::isUsableTrigger( pat[i], f ) ){
+ Trace("trigger-warn") << "User-provided trigger is not usable : " << pat << " because of " << pat[i] << std::endl;
+ usable = false;
+ break;
+ }
}
- if( Trigger::isUsableTrigger( nodes, f ) ){
+ if( usable ){
+ Trace("user-pat") << "Add user pattern: " << pat << " for " << f << std::endl;
//extend to literal matching
d_quantEngine->getPhaseReqTerms( f, nodes );
//check match option
int matchOption = 0;
- d_user_gen[f].push_back( Trigger::mkTrigger( d_quantEngine, f, nodes, matchOption, true, Trigger::TR_MAKE_NEW,
- options::smartTriggers() ) );
+ if( options::userPatternsQuant()==USER_PAT_MODE_RESORT ){
+ d_user_gen_wait[f].push_back( nodes );
+ }else{
+ d_user_gen[f].push_back( Trigger::mkTrigger( d_quantEngine, f, nodes, matchOption, true, Trigger::TR_MAKE_NEW, options::smartTriggers() ) );
+ }
+ }
+}
+
+InstStrategyAutoGenTriggers::InstStrategyAutoGenTriggers( QuantifiersEngine* qe, int tstrt, int rgfr ) :
+ InstStrategy( qe ), d_tr_strategy( tstrt ){
+ if( rgfr<0 ){
+ d_regenerate = false;
+ }else{
+ d_regenerate_frequency = rgfr;
+ d_regenerate = true;
}
+ d_generate_additional = true;
}
void InstStrategyAutoGenTriggers::processResetInstantiationRound( Theory::Effort effort ){
@@ -115,14 +149,14 @@ void InstStrategyAutoGenTriggers::processResetInstantiationRound( Theory::Effort
}
int InstStrategyAutoGenTriggers::process( Node f, Theory::Effort effort, int e ){
- if( f.getNumChildren()==3 && options::userPatternsQuant()==USER_PAT_MODE_TRUST ){
+ if( hasUserPatterns( f ) && options::userPatternsQuant()==USER_PAT_MODE_TRUST ){
return STATUS_UNKNOWN;
}else{
- int peffort = ( f.getNumChildren()==3 && options::userPatternsQuant()!=USER_PAT_MODE_IGNORE ) ? 2 : 1;
- //int peffort = 1;
+ int peffort = ( hasUserPatterns( f ) && options::userPatternsQuant()!=USER_PAT_MODE_IGNORE && options::userPatternsQuant()!=USER_PAT_MODE_RESORT ) ? 2 : 1;
if( e<peffort ){
return STATUS_UNFINISHED;
}else{
+ Trace("inst-alg") << "-> Auto-gen instantiate " << f << "..." << std::endl;
int status = STATUS_UNKNOWN;
bool gen = false;
if( e==peffort ){
@@ -142,28 +176,23 @@ int InstStrategyAutoGenTriggers::process( Node f, Theory::Effort effort, int e )
Trace("no-trigger") << "Could not find trigger for " << f << std::endl;
}
}
- Trace("inst-alg") << "-> Auto-gen instantiate " << f << "..." << std::endl;
//if( e==4 ){
// d_processed_trigger.clear();
// d_quantEngine->getEqualityQuery()->setLiberal( true );
//}
- Debug("quant-uf-strategy") << "Try auto-generated triggers... " << d_tr_strategy << " " << e << std::endl;
- //Notice() << "Try auto-generated triggers..." << std::endl;
for( std::map< Trigger*, bool >::iterator itt = d_auto_gen_trigger[f].begin(); itt != d_auto_gen_trigger[f].end(); ++itt ){
Trigger* tr = itt->first;
if( tr ){
bool processTrigger = itt->second;
if( processTrigger && d_processed_trigger[f].find( tr )==d_processed_trigger[f].end() ){
d_processed_trigger[f][tr] = true;
- //if( tr->isMultiTrigger() )
- Trace("process-trigger") << " Process ";
- tr->debugPrint("process-trigger");
- Trace("process-trigger") << "..." << std::endl;
+ Trace("process-trigger") << " Process ";
+ tr->debugPrint("process-trigger");
+ Trace("process-trigger") << "..." << std::endl;
InstMatch baseMatch( f );
int numInst = tr->addInstantiations( baseMatch );
- //if( tr->isMultiTrigger() )
- Trace("process-trigger") << " Done, numInst = " << numInst << "." << std::endl;
+ Trace("process-trigger") << " Done, numInst = " << numInst << "." << std::endl;
if( d_tr_strategy==Trigger::TS_MIN_TRIGGER ){
d_quantEngine->getInstantiationEngine()->d_statistics.d_instantiations_auto_gen_min += numInst;
}else{
@@ -179,8 +208,6 @@ int InstStrategyAutoGenTriggers::process( Node f, Theory::Effort effort, int e )
//if( e==4 ){
// d_quantEngine->getEqualityQuery()->setLiberal( false );
//}
- Debug("quant-uf-strategy") << "done." << std::endl;
- //Notice() << "done" << std::endl;
return status;
}
}
@@ -193,8 +220,15 @@ void InstStrategyAutoGenTriggers::generateTriggers( Node f, Theory::Effort effor
d_patTerms[0][f].clear();
d_patTerms[1][f].clear();
std::vector< Node > patTermsF;
- Trigger::collectPatTerms( d_quantEngine, f, d_quantEngine->getTermDatabase()->getInstConstantBody( f ), patTermsF, d_tr_strategy, true );
- Trace("auto-gen-trigger") << "Collected pat terms for " << d_quantEngine->getTermDatabase()->getInstConstantBody( f ) << std::endl;
+ if( d_quantEngine->getTermDatabase()->isQAttrFunDef( f ) && options::quantFunWellDefined() ){
+ Node bd = d_quantEngine->getTermDatabase()->getInstConstantBody( f );
+ Assert( bd.getKind()==EQUAL || bd.getKind()==IFF );
+ Assert( bd[0].getKind()==APPLY_UF );
+ patTermsF.push_back( bd[0] );
+ }else{
+ Trigger::collectPatTerms( d_quantEngine, f, d_quantEngine->getTermDatabase()->getInstConstantBody( f ), patTermsF, d_tr_strategy, d_user_no_gen[f], true );
+ }
+ Trace("auto-gen-trigger") << "Collected pat terms for " << d_quantEngine->getTermDatabase()->getInstConstantBody( f ) << ", no-patterns : " << d_user_no_gen[f].size() << std::endl;
Trace("auto-gen-trigger") << " ";
for( int i=0; i<(int)patTermsF.size(); i++ ){
Trace("auto-gen-trigger") << patTermsF[i] << " ";
@@ -206,7 +240,7 @@ void InstStrategyAutoGenTriggers::generateTriggers( Node f, Theory::Effort effor
std::map< Node, std::vector< Node > > varContains;
d_quantEngine->getTermDatabase()->getVarContains( f, patTermsF, varContains );
for( std::map< Node, std::vector< Node > >::iterator it = varContains.begin(); it != varContains.end(); ++it ){
- if( it->second.size()==f[0].getNumChildren() ){
+ if( it->second.size()==f[0].getNumChildren() && !Trigger::isPureTheoryTrigger( it->first ) ){
d_patTerms[0][f].push_back( it->first );
d_is_single_trigger[ it->first ] = true;
}else{
@@ -233,12 +267,12 @@ void InstStrategyAutoGenTriggers::generateTriggers( Node f, Theory::Effort effor
std::vector< Node > patTerms;
//try to add single triggers first
for( int i=0; i<(int)d_patTerms[0][f].size(); i++ ){
- if( !d_single_trigger_gen[d_patTerms[0][f][i]] ){
+ if( d_single_trigger_gen.find( d_patTerms[0][f][i] )==d_single_trigger_gen.end() ){
patTerms.push_back( d_patTerms[0][f][i] );
}
}
//if no single triggers exist, add multi trigger terms
- if( patTerms.empty() ){
+ if( patTerms.empty() && ( options::multiTriggerWhenSingle() || d_single_trigger_gen.empty() ) ){
patTerms.insert( patTerms.begin(), d_patTerms[1][f].begin(), d_patTerms[1][f].end() );
}
@@ -265,8 +299,7 @@ void InstStrategyAutoGenTriggers::generateTriggers( Node f, Theory::Effort effor
int matchOption = 0;
Trigger* tr = NULL;
if( d_is_single_trigger[ patTerms[0] ] ){
- tr = Trigger::mkTrigger( d_quantEngine, f, patTerms[0], matchOption, false, Trigger::TR_RETURN_NULL,
- options::smartTriggers() );
+ tr = Trigger::mkTrigger( d_quantEngine, f, patTerms[0], matchOption, false, Trigger::TR_RETURN_NULL, options::smartTriggers() );
d_single_trigger_gen[ patTerms[0] ] = true;
}else{
//only generate multi trigger if effort level > 5, or if no single triggers exist
@@ -342,6 +375,35 @@ void InstStrategyAutoGenTriggers::generateTriggers( Node f, Theory::Effort effor
}
}
+bool InstStrategyAutoGenTriggers::hasUserPatterns( Node f ) {
+ if( f.getNumChildren()==3 ){
+ std::map< Node, bool >::iterator it = d_hasUserPatterns.find( f );
+ if( it==d_hasUserPatterns.end() ){
+ bool hasPat = false;
+ for( unsigned i=0; i<f[2].getNumChildren(); i++ ){
+ if( f[2][i].getKind()==INST_PATTERN ){
+ hasPat = true;
+ break;
+ }
+ }
+ d_hasUserPatterns[f] = hasPat;
+ return hasPat;
+ }else{
+ return it->second;
+ }
+ }else{
+ return false;
+ }
+}
+
+void InstStrategyAutoGenTriggers::addUserNoPattern( Node f, Node pat ) {
+ Assert( pat.getKind()==INST_NO_PATTERN && pat.getNumChildren()==1 );
+ if( std::find( d_user_no_gen[f].begin(), d_user_no_gen[f].end(), pat[0] )==d_user_no_gen[f].end() ){
+ Trace("user-pat") << "Add user no-pattern: " << pat[0] << " for " << f << std::endl;
+ d_user_no_gen[f].push_back( pat[0] );
+ }
+}
+
void InstStrategyFreeVariable::processResetInstantiationRound( Theory::Effort effort ){
}
diff --git a/src/theory/quantifiers/inst_strategy_e_matching.h b/src/theory/quantifiers/inst_strategy_e_matching.h
index 968194e49..dd4486803 100644
--- a/src/theory/quantifiers/inst_strategy_e_matching.h
+++ b/src/theory/quantifiers/inst_strategy_e_matching.h
@@ -36,6 +36,8 @@ class InstStrategyUserPatterns : public InstStrategy{
private:
/** explicitly provided patterns */
std::map< Node, std::vector< inst::Trigger* > > d_user_gen;
+ /** waiting to be generated patterns */
+ std::map< Node, std::vector< std::vector< Node > > > d_user_gen_wait;
/** counter for quantifiers */
std::map< Node, int > d_counter;
/** process functions */
@@ -80,37 +82,31 @@ private:
std::map< Node, bool > d_made_multi_trigger;
//processed trigger this round
std::map< Node, std::map< inst::Trigger*, bool > > d_processed_trigger;
+ //instantiation no patterns
+ std::map< Node, std::vector< Node > > d_user_no_gen;
private:
/** process functions */
void processResetInstantiationRound( Theory::Effort effort );
int process( Node f, Theory::Effort effort, int e );
/** generate triggers */
void generateTriggers( Node f, Theory::Effort effort, int e, int & status );
+ /** has user patterns */
+ bool hasUserPatterns( Node f );
+ /** has user patterns */
+ std::map< Node, bool > d_hasUserPatterns;
public:
/** tstrt is the type of triggers to use (maximum depth, minimum depth, or all)
rstrt is the relevance setting for trigger (use only relevant triggers vs. use all)
rgfr is the frequency at which triggers are generated */
- InstStrategyAutoGenTriggers( QuantifiersEngine* qe, int tstrt, int rgfr = -1 ) :
- InstStrategy( qe ), d_tr_strategy( tstrt ), d_generate_additional( false ){
- setRegenerateFrequency( rgfr );
- }
+ InstStrategyAutoGenTriggers( QuantifiersEngine* qe, int tstrt, int rgfr = -1 );
~InstStrategyAutoGenTriggers(){}
public:
/** get auto-generated trigger */
inst::Trigger* getAutoGenTrigger( Node f );
/** identify */
std::string identify() const { return std::string("AutoGenTriggers"); }
- /** set regenerate frequency, if fr<0, turn off regenerate */
- void setRegenerateFrequency( int fr ){
- if( fr<0 ){
- d_regenerate = false;
- }else{
- d_regenerate_frequency = fr;
- d_regenerate = true;
- }
- }
- /** set generate additional */
- void setGenerateAdditional( bool val ) { d_generate_additional = val; }
+ /** add pattern */
+ void addUserNoPattern( Node f, Node pat );
};/* class InstStrategyAutoGenTriggers */
class InstStrategyFreeVariable : public InstStrategy{
diff --git a/src/theory/quantifiers/instantiation_engine.cpp b/src/theory/quantifiers/instantiation_engine.cpp
index 3dd4423de..1cb86e32f 100644
--- a/src/theory/quantifiers/instantiation_engine.cpp
+++ b/src/theory/quantifiers/instantiation_engine.cpp
@@ -31,7 +31,7 @@ using namespace CVC4::theory::quantifiers;
using namespace CVC4::theory::inst;
InstantiationEngine::InstantiationEngine( QuantifiersEngine* qe, bool setIncomplete ) :
-QuantifiersModule( qe ), d_isup(NULL), d_i_ag(NULL), d_setIncomplete( setIncomplete ), d_ierCounter( 0 ), d_performCheck( false ){
+QuantifiersModule( qe ), d_isup(NULL), d_i_ag(NULL), d_setIncomplete( setIncomplete ), d_ierCounter( 0 ){
}
@@ -41,41 +41,44 @@ InstantiationEngine::~InstantiationEngine() {
}
void InstantiationEngine::finishInit(){
- //for UF terms
if( !options::finiteModelFind() || options::fmfInstEngine() ){
- //if( options::cbqi() ){
- // addInstStrategy( new InstStrategyCheckCESolved( this, d_quantEngine ) );
- //}
- //these are the instantiation strategies for basic E-matching
+
+ //these are the instantiation strategies for E-matching
+
+ //user-provided patterns
if( options::userPatternsQuant()!=USER_PAT_MODE_IGNORE ){
d_isup = new InstStrategyUserPatterns( d_quantEngine );
addInstStrategy( d_isup );
}else{
d_isup = NULL;
}
- d_i_ag = new InstStrategyAutoGenTriggers( d_quantEngine, Trigger::TS_ALL, 3 );
- d_i_ag->setGenerateAdditional( true );
+
+ //auto-generated patterns
+ int tstrt = Trigger::TS_ALL;
+ if( options::triggerSelMode()==TRIGGER_SEL_MIN ){
+ tstrt = Trigger::TS_MIN_TRIGGER;
+ }else if( options::triggerSelMode()==TRIGGER_SEL_MAX ){
+ tstrt = Trigger::TS_MAX_TRIGGER;
+ }
+ d_i_ag = new InstStrategyAutoGenTriggers( d_quantEngine, tstrt, 3 );
addInstStrategy( d_i_ag );
- //addInstStrategy( new InstStrategyAddFailSplits( this, ie ) );
+
+ //full saturation : instantiate from relevant domain, then arbitrary terms
if( !options::finiteModelFind() && options::fullSaturateQuant() ){
addInstStrategy( new InstStrategyFreeVariable( d_quantEngine ) );
}
- //d_isup->setPriorityOver( d_i_ag );
- //d_isup->setPriorityOver( i_agm );
- //i_ag->setPriorityOver( i_agm );
}
- //for arithmetic
+
+ //counterexample-based quantifier instantiation
if( options::cbqi() ){
addInstStrategy( new InstStrategySimplex( (arith::TheoryArith*)d_quantEngine->getTheoryEngine()->theoryOf( THEORY_ARITH ), d_quantEngine ) );
- }
- //for datatypes
- //if( options::cbqi() ){
// addInstStrategy( new InstStrategyDatatypesValue( d_quantEngine ) );
- //}
+ }
}
bool InstantiationEngine::doInstantiationRound( Theory::Effort effort ){
+ unsigned lastWaiting = d_quantEngine->d_lemmas_waiting.size();
//if counterexample-based quantifier instantiation is active
if( options::cbqi() ){
//check if any cbqi lemma has not been added yet
@@ -149,7 +152,7 @@ bool InstantiationEngine::doInstantiationRound( Theory::Effort effort ){
}
}
//do not consider another level if already added lemma at this level
- if( d_quantEngine->hasAddedLemma() ){
+ if( d_quantEngine->d_lemmas_waiting.size()>lastWaiting ){
d_inst_round_status = InstStrategy::STATUS_UNKNOWN;
}
e++;
@@ -158,14 +161,11 @@ bool InstantiationEngine::doInstantiationRound( Theory::Effort effort ){
Debug("inst-engine") << (int)d_quantEngine->d_lemmas_waiting.size() << std::endl;
//Notice() << "All instantiators finished, # added lemmas = " << (int)d_lemmas_waiting.size() << std::endl;
if( !d_quantEngine->hasAddedLemma() ){
- Debug("inst-engine-stuck") << "No instantiations produced at this state." << std::endl;
Debug("inst-engine-ctrl") << "---Fail." << std::endl;
return false;
}else{
- Debug("inst-engine-ctrl") << "---Done. " << (int)d_quantEngine->d_lemmas_waiting.size() << std::endl;
- Trace("inst-engine") << "Added lemmas = " << (int)d_quantEngine->d_lemmas_waiting.size() << std::endl;
- //flush lemmas to output channel
- d_quantEngine->flushLemmas( &d_quantEngine->getOutputChannel() );
+ Debug("inst-engine-ctrl") << "---Done. " << (int)(d_quantEngine->d_lemmas_waiting.size()-lastWaiting) << std::endl;
+ Trace("inst-engine") << "Added lemmas = " << (int)(d_quantEngine->d_lemmas_waiting.size()-lastWaiting) << std::endl;
return true;
}
}
@@ -175,17 +175,17 @@ bool InstantiationEngine::needsCheck( Theory::Effort e ){
d_ierCounter++;
}
//determine if we should perform check, based on instWhenMode
- d_performCheck = false;
+ bool performCheck = false;
if( options::instWhenMode()==INST_WHEN_FULL ){
- d_performCheck = ( e >= Theory::EFFORT_FULL );
+ performCheck = ( e >= Theory::EFFORT_FULL );
}else if( options::instWhenMode()==INST_WHEN_FULL_DELAY ){
- d_performCheck = ( e >= Theory::EFFORT_FULL ) && !d_quantEngine->getTheoryEngine()->needCheck();
+ performCheck = ( e >= Theory::EFFORT_FULL ) && !d_quantEngine->getTheoryEngine()->needCheck();
}else if( options::instWhenMode()==INST_WHEN_FULL_LAST_CALL ){
- d_performCheck = ( ( e==Theory::EFFORT_FULL && d_ierCounter%2==0 ) || e==Theory::EFFORT_LAST_CALL );
+ performCheck = ( ( e==Theory::EFFORT_FULL && d_ierCounter%2==0 ) || e==Theory::EFFORT_LAST_CALL );
}else if( options::instWhenMode()==INST_WHEN_LAST_CALL ){
- d_performCheck = ( e >= Theory::EFFORT_LAST_CALL );
+ performCheck = ( e >= Theory::EFFORT_LAST_CALL );
}else{
- d_performCheck = true;
+ performCheck = true;
}
static int ierCounter2 = 0;
if( e==Theory::EFFORT_LAST_CALL ){
@@ -193,15 +193,14 @@ bool InstantiationEngine::needsCheck( Theory::Effort e ){
//with bounded integers, skip every other last call,
// since matching loops may occur with infinite quantification
if( ierCounter2%2==0 && options::fmfBoundInt() ){
- d_performCheck = false;
+ performCheck = false;
}
}
-
- return d_performCheck;
+ return performCheck;
}
-void InstantiationEngine::check( Theory::Effort e ){
- if( d_performCheck && !d_quantEngine->hasAddedLemma() ){
+void InstantiationEngine::check( Theory::Effort e, unsigned quant_e ){
+ if( quant_e==QuantifiersEngine::QEFFORT_STANDARD ){
Debug("inst-engine") << "IE: Check " << e << " " << d_ierCounter << std::endl;
double clSet = 0;
if( Trace.isOn("inst-engine") ){
@@ -211,12 +210,15 @@ void InstantiationEngine::check( Theory::Effort e ){
++(d_statistics.d_instantiation_rounds);
bool quantActive = false;
Debug("quantifiers") << "quantifiers: check: asserted quantifiers size="
- << d_quantEngine->getModel()->getNumAssertedQuantifiers() << std::endl;
+ << d_quantEngine->getModel()->getNumAssertedQuantifiers() << std::endl;
for( int i=0; i<(int)d_quantEngine->getModel()->getNumAssertedQuantifiers(); i++ ){
Node n = d_quantEngine->getModel()->getAssertedQuantifier( i );
- //it is not active if we have found the skolemized negation is unsat
- if( TermDb::isRewriteRule( n ) ){
+ //it is not active if it corresponds to a rewrite rule: we will process in rewrite engine
+ if( !d_quantEngine->hasOwnership( n, this ) ){
+ d_quant_active[n] = false;
+ }else if( !d_quantEngine->getModel()->isQuantifierActive( n ) ){
d_quant_active[n] = false;
+ //it is not active if we have found the skolemized negation is unsat
}else if( options::cbqi() && hasAddedCbqiLemma( n ) ){
Node cel = d_quantEngine->getTermDatabase()->getCounterexampleLiteral( n );
bool active, value;
@@ -248,7 +250,6 @@ 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;
if( !TermDb::hasInstConstAttr(n) ){
@@ -298,7 +299,7 @@ void InstantiationEngine::check( Theory::Effort e ){
}
void InstantiationEngine::registerQuantifier( Node f ){
- if( !TermDb::isRewriteRule( f ) ){
+ if( d_quantEngine->hasOwnership( f, this ) ){
//Notice() << "do cbqi " << f << " ? " << std::endl;
if( options::cbqi() ){
Node ceBody = d_quantEngine->getTermDatabase()->getInstConstantBody( f );
@@ -313,7 +314,11 @@ void InstantiationEngine::registerQuantifier( Node f ){
//add patterns
for( int i=0; i<(int)subsPat.getNumChildren(); i++ ){
//Notice() << "Add pattern " << subsPat[i] << " for " << f << std::endl;
- addUserPattern( f, subsPat[i] );
+ if( subsPat[i].getKind()==INST_PATTERN ){
+ addUserPattern( f, subsPat[i] );
+ }else if( subsPat[i].getKind()==INST_NO_PATTERN ){
+ addUserNoPattern( f, subsPat[i] );
+ }
}
}
}
@@ -430,6 +435,12 @@ void InstantiationEngine::addUserPattern( Node f, Node pat ){
}
}
+void InstantiationEngine::addUserNoPattern( Node f, Node pat ){
+ if( d_i_ag ){
+ d_i_ag->addUserNoPattern( f, pat );
+ }
+}
+
InstantiationEngine::Statistics::Statistics():
d_instantiations_user_patterns("InstantiationEngine::Instantiations_User_Patterns", 0),
d_instantiations_auto_gen("InstantiationEngine::Instantiations_Auto_Gen", 0),
diff --git a/src/theory/quantifiers/instantiation_engine.h b/src/theory/quantifiers/instantiation_engine.h
index 7a3528217..bf0bb03e1 100644
--- a/src/theory/quantifiers/instantiation_engine.h
+++ b/src/theory/quantifiers/instantiation_engine.h
@@ -99,7 +99,6 @@ private:
bool d_setIncomplete;
/** inst round counter */
int d_ierCounter;
- bool d_performCheck;
/** whether each quantifier is active */
std::map< Node, bool > d_quant_active;
/** whether we have added cbqi lemma */
@@ -131,13 +130,14 @@ public:
void finishInit();
bool needsCheck( Theory::Effort e );
- void check( Theory::Effort e );
+ void check( Theory::Effort e, unsigned quant_e );
void registerQuantifier( Node f );
void assertNode( Node f );
Node explain(TNode n){ return Node::null(); }
Node getNextDecisionRequest();
/** add user pattern */
void addUserPattern( Node f, Node pat );
+ void addUserNoPattern( Node f, Node pat );
public:
/** statistics class */
class Statistics {
diff --git a/src/theory/quantifiers/kinds b/src/theory/quantifiers/kinds
index 6fb480c3d..a8774440e 100644
--- a/src/theory/quantifiers/kinds
+++ b/src/theory/quantifiers/kinds
@@ -33,6 +33,8 @@ sort INST_PATTERN_TYPE \
# This node is used for specifying hints for quantifier instantiation.
# An instantiation pattern may have more than 1 child, in which case it specifies a multi-trigger.
operator INST_PATTERN 1: "instantiation pattern"
+operator INST_NO_PATTERN 1 "instantiation no-pattern"
+operator INST_ATTRIBUTE 1 "instantiation attribute"
sort INST_PATTERN_LIST_TYPE \
Cardinality::INTEGERS \
@@ -46,6 +48,8 @@ typerule FORALL ::CVC4::theory::quantifiers::QuantifierForallTypeRule
typerule EXISTS ::CVC4::theory::quantifiers::QuantifierExistsTypeRule
typerule BOUND_VAR_LIST ::CVC4::theory::quantifiers::QuantifierBoundVarListTypeRule
typerule INST_PATTERN ::CVC4::theory::quantifiers::QuantifierInstPatternTypeRule
+typerule INST_NO_PATTERN ::CVC4::theory::quantifiers::QuantifierInstNoPatternTypeRule
+typerule INST_ATTRIBUTE ::CVC4::theory::quantifiers::QuantifierInstAttributeTypeRule
typerule INST_PATTERN_LIST ::CVC4::theory::quantifiers::QuantifierInstPatternListTypeRule
# for rewrite rules
diff --git a/src/theory/quantifiers/macros.cpp b/src/theory/quantifiers/macros.cpp
index 11734c43f..81cd5948a 100644
--- a/src/theory/quantifiers/macros.cpp
+++ b/src/theory/quantifiers/macros.cpp
@@ -24,7 +24,6 @@ using namespace std;
using namespace CVC4::theory;
using namespace CVC4::theory::quantifiers;
using namespace CVC4::kind;
-using namespace CVC4::context;
bool QuantifierMacros::simplify( std::vector< Node >& assertions, bool doRewrite ){
@@ -98,10 +97,14 @@ bool QuantifierMacros::isMacroLiteral( Node n, bool pol ){
bool QuantifierMacros::isBoundVarApplyUf( Node n ) {
Assert( n.getKind()==APPLY_UF );
+ TypeNode tn = n.getOperator().getType();
for( unsigned i=0; i<n.getNumChildren(); i++ ){
if( n[i].getKind()!=BOUND_VARIABLE ){
return false;
}
+ if( n[i].getType()!=tn[i] ){
+ return false;
+ }
for( unsigned j=0; j<i; j++ ){
if( n[j]==n[i] ){
return false;
diff --git a/src/theory/quantifiers/model_builder.cpp b/src/theory/quantifiers/model_builder.cpp
index 4179dcbf5..f6392a0b2 100644
--- a/src/theory/quantifiers/model_builder.cpp
+++ b/src/theory/quantifiers/model_builder.cpp
@@ -36,11 +36,11 @@ 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 !TermDb::isRewriteRule( f );
+ return d_qe->hasOwnership( f );
}
@@ -161,7 +161,7 @@ void QModelBuilderIG::processBuildModel( TheoryModel* m, bool fullModel ) {
Trace("model-engine") << "Initialize, Added Lemmas = " << d_addedLemmas << std::endl;
}else{
//initialize model
- fm->initialize( d_considerAxioms );
+ fm->initialize();
//analyze the functions
Trace("model-engine-debug") << "Analyzing model..." << std::endl;
analyzeModel( fm );
@@ -382,8 +382,7 @@ QModelBuilderIG::Statistics::~Statistics(){
}
bool QModelBuilderIG::isQuantifierActive( Node f ){
- return !TermDb::isRewriteRule( f ) &&
- ( d_considerAxioms || !f.getAttribute(AxiomAttribute()) ) && d_quant_sat.find( f )==d_quant_sat.end();
+ return d_qe->hasOwnership( f ) && d_quant_sat.find( f )==d_quant_sat.end();
}
bool QModelBuilderIG::isTermActive( Node n ){
diff --git a/src/theory/quantifiers/model_builder.h b/src/theory/quantifiers/model_builder.h
index 4b0046089..3e4471fa4 100644
--- a/src/theory/quantifiers/model_builder.h
+++ b/src/theory/quantifiers/model_builder.h
@@ -44,8 +44,6 @@ public:
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;
diff --git a/src/theory/quantifiers/model_engine.cpp b/src/theory/quantifiers/model_engine.cpp
index d68c66535..6ec347031 100644
--- a/src/theory/quantifiers/model_engine.cpp
+++ b/src/theory/quantifiers/model_engine.cpp
@@ -35,112 +35,73 @@ using namespace CVC4::theory::inst;
//Model Engine constructor
ModelEngine::ModelEngine( context::Context* c, QuantifiersEngine* qe ) :
-QuantifiersModule( qe ){
+QuantifiersModule( qe ),
+d_incomplete_check(false),
+d_addedLemmas(0),
+d_triedLemmas(0),
+d_totalLemmas(0)
+{
- Trace("model-engine-debug") << "Initialize model engine, mbqi : " << options::mbqiMode() << " " << options::fmfBoundInt() << std::endl;
- if( options::mbqiMode()==MBQI_FMC || options::mbqiMode()==quantifiers::MBQI_FMC_INTERVAL ||
- options::mbqiMode()==MBQI_TRUST || options::fmfBoundInt() ){
- Trace("model-engine-debug") << "...make fmc builder." << std::endl;
- d_builder = new fmcheck::FullModelChecker( c, qe );
- }else if( options::mbqiMode()==MBQI_INTERVAL ){
- Trace("model-engine-debug") << "...make interval builder." << std::endl;
- d_builder = new QIntervalBuilder( c, qe );
- }else if( options::mbqiMode()==MBQI_ABS ){
- Trace("model-engine-debug") << "...make abs mbqi builder." << std::endl;
- d_builder = new AbsMbqiBuilder( c, qe );
- }else if( options::mbqiMode()==MBQI_INST_GEN ){
- Trace("model-engine-debug") << "...make inst-gen builder." << std::endl;
- d_builder = new QModelBuilderInstGen( c, qe );
- }else{
- Trace("model-engine-debug") << "...make default model builder." << std::endl;
- d_builder = new QModelBuilderDefault( c, qe );
- }
}
ModelEngine::~ModelEngine() {
- delete d_builder;
+
+}
+
+bool ModelEngine::needsCheck( Theory::Effort e ) {
+ return e==Theory::EFFORT_LAST_CALL;
+}
+
+bool ModelEngine::needsModel( Theory::Effort e ) {
+ return true;
}
-void ModelEngine::check( Theory::Effort e ){
- if( e==Theory::EFFORT_LAST_CALL && !d_quantEngine->hasAddedLemma() ){
+void ModelEngine::check( Theory::Effort e, unsigned quant_e ){
+ if( quant_e==QuantifiersEngine::QEFFORT_MODEL ){
int addedLemmas = 0;
- bool needsBuild = true;
FirstOrderModel* fm = d_quantEngine->getModel();
- if( fm->getNumAssertedQuantifiers()>0 ){
- //the following will attempt to build a model and test that it satisfies all asserted universal quantifiers
- //quantifiers are initialized, we begin an instantiation round
- double clSet = 0;
- if( Trace.isOn("model-engine") ){
- clSet = double(clock())/double(CLOCKS_PER_SEC);
- }
- ++(d_statistics.d_inst_rounds);
- bool buildAtFullModel = d_builder->optBuildAtFullModel();
- needsBuild = !buildAtFullModel;
- //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++ ){
- // for effort = 0, we only instantiate non-axioms
- // for effort = 1, we instantiate everything
- if( addedLemmas==0 ){
- Trace("model-engine") << "---Model Engine Round---" << std::endl;
- //initialize the model
- Trace("model-engine-debug") << "Build model..." << std::endl;
- 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 ){
- Trace("model-engine-debug") << "Verify uf ss is minimal..." << std::endl;
- //let the strong solver verify that the model is minimal
- //for debugging, this will if there are terms in the model that the strong solver was not notified of
- if( ((uf::TheoryUF*)d_quantEngine->getTheoryEngine()->theoryOf( THEORY_UF ))->getStrongSolver()->debugModel( fm ) ){
- Trace("model-engine-debug") << "Check model..." << std::endl;
- d_incomplete_check = false;
- //print debug
- Debug("fmf-model-complete") << std::endl;
- debugPrint("fmf-model-complete");
- //successfully built an acceptable model, now check it
- addedLemmas += checkModel();
- }else{
- addedLemmas++;
- }
- }
- }
- if( addedLemmas==0 ){
- //if we have not added lemmas yet and axiomInstMode=trust, then we are done
- if( options::axiomInstMode()==AXIOM_INST_MODE_TRUST ){
- //we must return unknown if an axiom is asserted
- if( effort==0 ){
- d_incomplete_check = true;
- }
- break;
- }
- }
- }
- if( Trace.isOn("model-engine") ){
- double clSet2 = double(clock())/double(CLOCKS_PER_SEC);
- Trace("model-engine") << "Finished model engine, time = " << (clSet2-clSet) << std::endl;
- }
+
+ //the following will test that the model satisfies all asserted universal quantifiers by
+ // (model-based) exhaustive instantiation.
+ double clSet = 0;
+ if( Trace.isOn("model-engine") ){
+ Trace("model-engine") << "---Model Engine Round---" << std::endl;
+ clSet = double(clock())/double(CLOCKS_PER_SEC);
+ }
+ ++(d_statistics.d_inst_rounds);
+
+ Trace("model-engine-debug") << "Verify uf ss is minimal..." << std::endl;
+ //let the strong solver verify that the model is minimal
+ //for debugging, this will if there are terms in the model that the strong solver was not notified of
+ uf::StrongSolverTheoryUF * ufss = ((uf::TheoryUF*)d_quantEngine->getTheoryEngine()->theoryOf( THEORY_UF ))->getStrongSolver();
+ if( !ufss || ufss->debugModel( fm ) ){
+ Trace("model-engine-debug") << "Check model..." << std::endl;
+ d_incomplete_check = false;
+ //print debug
+ Debug("fmf-model-complete") << std::endl;
+ debugPrint("fmf-model-complete");
+ //successfully built an acceptable model, now check it
+ addedLemmas += checkModel();
}else{
- Trace("model-engine-debug") << "No quantified formulas asserted." << std::endl;
+ addedLemmas++;
+ }
+
+ if( Trace.isOn("model-engine") ){
+ double clSet2 = double(clock())/double(CLOCKS_PER_SEC);
+ Trace("model-engine") << "Finished model engine, time = " << (clSet2-clSet) << std::endl;
}
+
if( addedLemmas==0 ){
Trace("model-engine-debug") << "No lemmas added, incomplete = " << d_incomplete_check << std::endl;
//CVC4 will answer SAT or unknown
Trace("fmf-consistent") << std::endl;
debugPrint("fmf-consistent");
- if( options::produceModels() && needsBuild ){
- // finish building the model
- d_builder->buildModel( fm, true );
- }
//if the check was incomplete, we must set incomplete flag
if( d_incomplete_check ){
d_quantEngine->getOutputChannel().setIncomplete();
}
}else{
//otherwise, the search will continue
- d_quantEngine->flushLemmas( &d_quantEngine->getOutputChannel() );
}
}
}
@@ -179,6 +140,8 @@ bool ModelEngine::optOneQuantPerRound(){
int ModelEngine::checkModel(){
FirstOrderModel* fm = d_quantEngine->getModel();
+ quantifiers::QModelBuilder * mb = d_quantEngine->getModelBuilder();
+ Assert( mb!=NULL );
//flatten the representatives
//Trace("model-engine-debug") << "Flattening representatives...." << std::endl;
@@ -222,32 +185,46 @@ int ModelEngine::checkModel(){
}
Trace("model-engine-debug") << "Do exhaustive instantiation..." << std::endl;
- int e_max = options::mbqiMode()==MBQI_FMC || options::mbqiMode()==MBQI_FMC_INTERVAL ? 2 : ( options::mbqiMode()==MBQI_TRUST ? 0 : 1 );
- for( int e=0; e<e_max; e++) {
- 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 );
+ //default : 1 : conj,axiom
+ //priority : 0 : conj, 1 : axiom
+ //trust : 0 : conj
+ int startEffort = ( !fm->isAxiomAsserted() || options::axiomInstMode()==AXIOM_INST_MODE_DEFAULT ) ? 1 : 0;
+ for( int effort=startEffort; effort<2; effort++ ){
+ // FMC uses two sub-effort levels
+ int e_max = options::mbqiMode()==MBQI_FMC || options::mbqiMode()==MBQI_FMC_INTERVAL ? 2 : ( options::mbqiMode()==MBQI_TRUST ? 0 : 1 );
+ for( int e=0; e<e_max; e++) {
+ if (d_addedLemmas==0) {
+ for( int i=0; i<fm->getNumAssertedQuantifiers(); i++ ){
+ Node f = fm->getAssertedQuantifier( i );
+ bool isAx = getTermDatabase()->isQAttrAxiom( f );
+ //determine if we should check this quantifier
+ if( ( ( effort==1 && ( options::axiomInstMode()==AXIOM_INST_MODE_DEFAULT || isAx ) ) || ( effort==0 && !isAx ) ) && mb->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;
+ }
+ }else{
+ Trace("inst-fmf-ei") << "-> Inactive : " << f << std::endl;
}
- if( optOneQuantPerRound() && d_addedLemmas>0 ){
- break;
- }
- }else{
- Trace("inst-fmf-ei") << "-> Inactive : " << f << std::endl;
}
}
}
+ if( d_addedLemmas==0 && options::axiomInstMode()==AXIOM_INST_MODE_TRUST ){
+ //set incomplete
+ if( effort==0 ){
+ d_quantEngine->getOutputChannel().setIncomplete();
+ }
+ break;
+ }
}
//print debug information
- Trace("model-engine-debug") << "Instantiate axioms : " << ( d_builder->d_considerAxioms ? "yes" : "no" ) << std::endl;
Trace("model-engine") << "Added Lemmas = " << d_addedLemmas << " / " << d_triedLemmas << " / ";
Trace("model-engine") << d_totalLemmas << std::endl;
return d_addedLemmas;
@@ -255,15 +232,16 @@ int ModelEngine::checkModel(){
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 ) ){
+ quantifiers::QModelBuilder * mb = d_quantEngine->getModelBuilder();
+ mb->d_triedLemmas = 0;
+ mb->d_addedLemmas = 0;
+ mb->d_incomplete_check = false;
+ if( mb->doExhaustiveInstantiation( d_quantEngine->getModel(), f, effort ) ){
Trace("inst-fmf-ei") << "-> Builder determined instantiation(s)." << std::endl;
- d_triedLemmas += d_builder->d_triedLemmas;
- d_addedLemmas += d_builder->d_addedLemmas;
- d_incomplete_check = d_incomplete_check || d_builder->d_incomplete_check;
- d_statistics.d_mbqi_inst_lemmas += d_builder->d_addedLemmas;
+ d_triedLemmas += mb->d_triedLemmas;
+ d_addedLemmas += mb->d_addedLemmas;
+ d_incomplete_check = d_incomplete_check || mb->d_incomplete_check;
+ d_statistics.d_mbqi_inst_lemmas += mb->d_addedLemmas;
}else{
Trace("inst-fmf-ei") << "-> Exhaustive instantiate " << f << ", effort = " << effort << "..." << std::endl;
Debug("inst-fmf-ei") << " Instantiation Constants: ";
@@ -307,7 +285,7 @@ void ModelEngine::debugPrint( const char* c ){
for( int i=0; i<(int)d_quantEngine->getModel()->getNumAssertedQuantifiers(); i++ ){
Node f = d_quantEngine->getModel()->getAssertedQuantifier( i );
Trace( c ) << " ";
- if( !d_builder->isQuantifierActive( f ) ){
+ if( !d_quantEngine->getModelBuilder()->isQuantifierActive( f ) ){
Trace( c ) << "*Inactive* ";
}else{
Trace( c ) << " ";
diff --git a/src/theory/quantifiers/model_engine.h b/src/theory/quantifiers/model_engine.h
index caf27f691..8c53084f0 100644
--- a/src/theory/quantifiers/model_engine.h
+++ b/src/theory/quantifiers/model_engine.h
@@ -29,9 +29,6 @@ class ModelEngine : public QuantifiersModule
{
friend class RepSetIterator;
private:
- /** builder class */
- QModelBuilder* d_builder;
-private:
//options
bool optOneQuantPerRound();
private:
@@ -49,10 +46,10 @@ private:
public:
ModelEngine( context::Context* c, QuantifiersEngine* qe );
virtual ~ModelEngine();
- //get the builder
- QModelBuilder* getModelBuilder() { return d_builder; }
public:
- void check( Theory::Effort e );
+ bool needsCheck( Theory::Effort e );
+ bool needsModel( Theory::Effort e );
+ void check( Theory::Effort e, unsigned quant_e );
void registerQuantifier( Node f );
void assertNode( Node f );
Node explain(TNode n){ return Node::null(); }
diff --git a/src/theory/quantifiers/modes.h b/src/theory/quantifiers/modes.h
index 112e052c2..acc883f2a 100644
--- a/src/theory/quantifiers/modes.h
+++ b/src/theory/quantifiers/modes.h
@@ -99,14 +99,44 @@ typedef enum {
} QcfMode;
typedef enum {
- /** default, use but do not trust */
- USER_PAT_MODE_DEFAULT,
- /** if patterns are supplied for a quantifier, use only those */
+ /** use but do not trust */
+ USER_PAT_MODE_USE,
+ /** default, if patterns are supplied for a quantifier, use only those */
USER_PAT_MODE_TRUST,
+ /** resort to user patterns only when necessary */
+ USER_PAT_MODE_RESORT,
/** ignore user patterns */
USER_PAT_MODE_IGNORE,
} UserPatMode;
+typedef enum {
+ /** default for trigger selection */
+ TRIGGER_SEL_DEFAULT,
+ /** only consider minimal terms for triggers */
+ TRIGGER_SEL_MIN,
+ /** only consider maximal terms for triggers */
+ TRIGGER_SEL_MAX,
+} TriggerSelMode;
+
+typedef enum {
+ /** default : prenex quantifiers without user patterns */
+ PRENEX_NO_USER_PAT,
+ /** prenex all */
+ PRENEX_ALL,
+ /** prenex none */
+ PRENEX_NONE,
+} PrenexQuantMode;
+
+typedef enum {
+ /** enforce fairness by UF corresponding to datatypes size */
+ CEGQI_FAIR_UF_DT_SIZE,
+ /** enforce fairness by datatypes size */
+ CEGQI_FAIR_DT_SIZE,
+ /** do not use fair strategy for CEGQI */
+ CEGQI_FAIR_NONE,
+} CegqiFairMode;
+
+
}/* CVC4::theory::quantifiers namespace */
}/* CVC4::theory namespace */
diff --git a/src/theory/quantifiers/options b/src/theory/quantifiers/options
index 1cdf5e8bd..8cb693117 100644
--- a/src/theory/quantifiers/options
+++ b/src/theory/quantifiers/options
@@ -18,7 +18,7 @@ option miniscopeQuantFreeVar /--disable-miniscope-quant-fv bool :default true
disable miniscope quantifiers for ground subformulas
# Whether to prenex (nested universal) quantifiers
-option prenexQuant /--disable-prenex-quant bool :default true
+option prenexQuant --prenex-quant=MODE CVC4::theory::quantifiers::PrenexQuantMode :default CVC4::theory::quantifiers::PRENEX_NO_USER_PAT :include "theory/quantifiers/modes.h" :handler CVC4::theory::quantifiers::stringToPrenexQuantMode :handler-include "theory/quantifiers/options_handlers.h"
disable prenexing of quantified formulas
# Whether to variable-eliminate quantifiers.
@@ -26,6 +26,8 @@ option prenexQuant /--disable-prenex-quant bool :default true
# forall y. P( c, y )
option varElimQuant /--disable-var-elim-quant bool :default true
disable simple variable elimination for quantified formulas
+option dtVarExpandQuant --dt-var-exp-quant bool :default true
+ expand datatype variables bound to one constructor in quantifiers
option simpleIteLiftQuant /--disable-ite-lift-quant bool :default true
disable simple ite lifting for quantified formulas
@@ -63,7 +65,18 @@ option relevantTriggers --relevant-triggers bool :default false
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)
-
+option purifyTriggers --purify-triggers bool :default false :read-write
+ purify triggers, e.g. f( x+1 ) becomes f( y ), x mapsto y-1
+option multiTriggerWhenSingle --multi-trigger-when-single bool :default true
+ never select multi-triggers when single triggers exist
+option triggerSelMode --trigger-sel CVC4::theory::quantifiers::TriggerSelMode :default CVC4::theory::quantifiers::TRIGGER_SEL_DEFAULT :read-write :include "theory/quantifiers/modes.h" :handler CVC4::theory::quantifiers::stringToTriggerSelMode :handler-include "theory/quantifiers/options_handlers.h"
+ selection mode for triggers
+
+option quantFunWellDefined --quant-fun-wd bool :default false
+ assume that function defined by quantifiers are well defined
+option fmfFunWellDefined --fmf-fun bool :default false
+ find models for finite runs of defined functions, assumes functions are well-defined
+
# Whether to consider terms in the bodies of quantifiers for matching
option registerQuantBodyTerms --register-quant-body-terms bool :default false
consider ground terms within bodies of quantified formulas for matching
@@ -72,10 +85,15 @@ option instWhenMode --inst-when=MODE CVC4::theory::quantifiers::InstWhenMode :de
when to apply instantiation
option instMaxLevel --inst-max-level=N int :default -1
maximum inst level of terms used to instantiate quantified formulas with (-1 == no limit, default)
+option instLevelInputOnly --inst-level-input-only bool :default true
+ only input terms are assigned instantiation level zero
option eagerInstQuant --eager-inst-quant bool :default false
apply quantifier instantiation eagerly
+option instNoEntail --inst-no-entail bool :read-write :default false
+ do not consider instances of quantified formulas that are currently entailed
+
option fullSaturateQuant --full-saturate-quant bool :default false
when all other quantifier instantiation strategies fail, instantiate with ground terms from relevant domain, then arbitrary ground terms before answering unknown
@@ -88,7 +106,7 @@ option cbqi --enable-cbqi bool :read-write :default false
option recurseCbqi --cbqi-recurse bool :default false
turns on recursive counterexample-based quantifier instantiation
-option userPatternsQuant --user-pat=MODE CVC4::theory::quantifiers::UserPatMode :default CVC4::theory::quantifiers::USER_PAT_MODE_DEFAULT :include "theory/quantifiers/modes.h" :handler CVC4::theory::quantifiers::stringToUserPatMode :handler-include "theory/quantifiers/options_handlers.h"
+option userPatternsQuant --user-pat=MODE CVC4::theory::quantifiers::UserPatMode :default CVC4::theory::quantifiers::USER_PAT_MODE_TRUST :include "theory/quantifiers/modes.h" :handler CVC4::theory::quantifiers::stringToUserPatMode :handler-include "theory/quantifiers/options_handlers.h"
policy for handling user-provided patterns for quantifier instantiation
option flipDecision --flip-decision/ bool :default false
@@ -139,7 +157,33 @@ option quantRewriteRules --rewrite-rules bool :default true
option rrOneInstPerRound --rr-one-inst-per-round bool :default false
add one instance of rewrite rule per round
-option dtStcInduction --dt-stc-ind bool :default false
+option quantInduction --quant-ind bool :default false
+ use all available techniques for inductive reasoning
+option dtStcInduction --dt-stc-ind bool :read-write :default false
apply strengthening for existential quantification over datatypes based on structural induction
-
+option intWfInduction --int-wf-ind bool :read-write :default false
+ apply strengthening for integers based on well-founded induction
+option conjectureGen --conjecture-gen bool :read-write :default false
+ generate candidate conjectures for inductive proofs
+
+option conjectureGenPerRound --conjecture-gen-per-round=N int :default 1
+ number of conjectures to generate per instantiation round
+option conjectureNoFilter --conjecture-no-filter bool :default false
+ do not filter conjectures
+option conjectureFilterActiveTerms --conjecture-filter-active-terms bool :read-write :default true
+ filter based on active terms
+option conjectureFilterCanonical --conjecture-filter-canonical bool :read-write :default true
+ filter based on canonicity
+option conjectureFilterModel --conjecture-filter-model bool :read-write :default true
+ filter based on model
+option conjectureGenGtEnum --conjecture-gen-gt-enum=N int :default 0
+ number of ground terms to generate for model filtering
+option conjectureUeeIntro --conjecture-gen-uee-intro bool :default false
+ more aggressive merging for universal equality engine, introduces terms
+
+option ceGuidedInst --cegqi bool :default false
+ counterexample guided quantifier instantiation
+option ceGuidedInstFair --cegqi-fair=MODE CVC4::theory::quantifiers::CegqiFairMode :default CVC4::theory::quantifiers::CEGQI_FAIR_DT_SIZE :include "theory/quantifiers/modes.h" :handler CVC4::theory::quantifiers::stringToCegqiFairMode :handler-include "theory/quantifiers/options_handlers.h"
+ if and how to apply fairness for cegqi
+
endmodule
diff --git a/src/theory/quantifiers/options_handlers.h b/src/theory/quantifiers/options_handlers.h
index 38567d166..c2afbbd3e 100644
--- a/src/theory/quantifiers/options_handlers.h
+++ b/src/theory/quantifiers/options_handlers.h
@@ -141,17 +141,60 @@ mc \n\
static const std::string userPatModeHelp = "\
User pattern modes currently supported by the --user-pat option:\n\
\n\
-default \n\
-+ Default, use both user-provided and auto-generated patterns when patterns\n\
- are provided for a quantified formula.\n\
-\n\
trust \n\
+ When provided, use only user-provided patterns for a quantified formula.\n\
\n\
+use \n\
++ Use both user-provided and auto-generated patterns when patterns\n\
+ are provided for a quantified formula.\n\
+\n\
+resort \n\
++ Use user-provided patterns only after auto-generated patterns saturate.\n\
+\n\
ignore \n\
+ Ignore user-provided patterns. \n\
\n\
";
+static const std::string triggerSelModeHelp = "\
+Trigger selection modes currently supported by the --trigger-sel option:\n\
+\n\
+default \n\
++ Default, consider all subterms of quantified formulas for trigger selection.\n\
+\n\
+min \n\
++ Consider only minimal subterms that meet criteria for triggers.\n\
+\n\
+max \n\
++ Consider only maximal subterms that meet criteria for triggers. \n\
+\n\
+";
+static const std::string prenexQuantModeHelp = "\
+Prenex quantifiers modes currently supported by the --prenex-quant option:\n\
+\n\
+default \n\
++ Default, prenex all nested quantifiers except those with user patterns.\n\
+\n\
+all \n\
++ Prenex all nested quantifiers.\n\
+\n\
+none \n\
++ Do no prenex nested quantifiers. \n\
+\n\
+";
+static const std::string cegqiFairModeHelp = "\
+Modes for enforcing fairness for counterexample guided quantifier instantion, supported by --cegqi-fair:\n\
+\n\
+uf-dt-size \n\
++ Enforce fairness using an uninterpreted function for datatypes size.\n\
+\n\
+default | dt-size \n\
++ Default, enforce fairness using size theory operator.\n\
+\n\
+none \n\
++ Do not enforce fairness. \n\
+\n\
+";
+
inline InstWhenMode stringToInstWhenMode(std::string option, std::string optarg, SmtEngine* smt) throw(OptionException) {
if(optarg == "pre-full") {
return INST_WHEN_PRE_FULL;
@@ -282,10 +325,12 @@ inline QcfMode stringToQcfMode(std::string option, std::string optarg, SmtEngine
}
inline UserPatMode stringToUserPatMode(std::string option, std::string optarg, SmtEngine* smt) throw(OptionException) {
- if(optarg == "default") {
- return USER_PAT_MODE_DEFAULT;
- } else if(optarg == "trust") {
+ if(optarg == "use") {
+ return USER_PAT_MODE_USE;
+ } else if(optarg == "default" || optarg == "trust") {
return USER_PAT_MODE_TRUST;
+ } else if(optarg == "resort") {
+ return USER_PAT_MODE_RESORT;
} else if(optarg == "ignore") {
return USER_PAT_MODE_IGNORE;
} else if(optarg == "help") {
@@ -296,6 +341,55 @@ inline UserPatMode stringToUserPatMode(std::string option, std::string optarg, S
optarg + "'. Try --user-pat help.");
}
}
+
+inline TriggerSelMode stringToTriggerSelMode(std::string option, std::string optarg, SmtEngine* smt) throw(OptionException) {
+ if(optarg == "default" || optarg == "all" ) {
+ return TRIGGER_SEL_DEFAULT;
+ } else if(optarg == "min") {
+ return TRIGGER_SEL_MIN;
+ } else if(optarg == "max") {
+ return TRIGGER_SEL_MAX;
+ } else if(optarg == "help") {
+ puts(triggerSelModeHelp.c_str());
+ exit(1);
+ } else {
+ throw OptionException(std::string("unknown option for --trigger-sel: `") +
+ optarg + "'. Try --trigger-sel help.");
+ }
+}
+
+inline PrenexQuantMode stringToPrenexQuantMode(std::string option, std::string optarg, SmtEngine* smt) throw(OptionException) {
+ if(optarg == "default" ) {
+ return PRENEX_NO_USER_PAT;
+ } else if(optarg == "all") {
+ return PRENEX_ALL;
+ } else if(optarg == "none") {
+ return PRENEX_NONE;
+ } else if(optarg == "help") {
+ puts(prenexQuantModeHelp.c_str());
+ exit(1);
+ } else {
+ throw OptionException(std::string("unknown option for --prenex-quant: `") +
+ optarg + "'. Try --prenex-quant help.");
+ }
+}
+
+inline CegqiFairMode stringToCegqiFairMode(std::string option, std::string optarg, SmtEngine* smt) throw(OptionException) {
+ if(optarg == "uf-dt-size" ) {
+ return CEGQI_FAIR_UF_DT_SIZE;
+ } else if(optarg == "default" || optarg == "dt-size") {
+ return CEGQI_FAIR_DT_SIZE;
+ } else if(optarg == "none") {
+ return CEGQI_FAIR_NONE;
+ } else if(optarg == "help") {
+ puts(cegqiFairModeHelp.c_str());
+ exit(1);
+ } else {
+ throw OptionException(std::string("unknown option for --cegqi-fair: `") +
+ optarg + "'. Try --cegqi-fair help.");
+ }
+}
+
}/* CVC4::theory::quantifiers namespace */
}/* CVC4::theory namespace */
}/* CVC4 namespace */
diff --git a/src/theory/quantifiers/qinterval_builder.cpp b/src/theory/quantifiers/qinterval_builder.cpp
index fd3a76a52..5dd6316b3 100644
--- a/src/theory/quantifiers/qinterval_builder.cpp
+++ b/src/theory/quantifiers/qinterval_builder.cpp
@@ -943,7 +943,7 @@ void QIntervalBuilder::processBuildModel(TheoryModel* m, bool fullModel) {
//debug the model
debugModel( fm );
}else{
- fm->initialize( d_considerAxioms );
+ fm->initialize();
//process representatives
fm->d_rep_id.clear();
fm->d_max.clear();
diff --git a/src/theory/quantifiers/quant_conflict_find.cpp b/src/theory/quantifiers/quant_conflict_find.cpp
index c6e881986..f976a0dbf 100644..100755
--- a/src/theory/quantifiers/quant_conflict_find.cpp
+++ b/src/theory/quantifiers/quant_conflict_find.cpp
@@ -1,2529 +1,2224 @@
-/********************* */
-/*! \file quant_conflict_find.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-2014 New York University and The University of Iowa
- ** See the file COPYING in the top-level source directory for licensing
- ** information.\endverbatim
- **
- ** \brief quant conflict find class
- **
- **/
-
-#include <vector>
-
-#include "theory/quantifiers/quant_conflict_find.h"
-#include "theory/quantifiers/quant_util.h"
-#include "theory/theory_engine.h"
-#include "theory/quantifiers/options.h"
-#include "theory/quantifiers/term_database.h"
-#include "theory/quantifiers/trigger.h"
-
-using namespace CVC4;
-using namespace CVC4::kind;
-using namespace CVC4::theory;
-using namespace CVC4::theory::quantifiers;
-using namespace std;
-
-namespace CVC4 {
-
-Node QcfNodeIndex::existsTerm( TNode n, std::vector< TNode >& reps, int index ) {
- if( index==(int)reps.size() ){
- if( d_children.empty() ){
- return Node::null();
- }else{
- return d_children.begin()->first;
- }
- }else{
- std::map< TNode, QcfNodeIndex >::iterator it = d_children.find( reps[index] );
- if( it==d_children.end() ){
- return Node::null();
- }else{
- return it->second.existsTerm( n, reps, index+1 );
- }
- }
-}
-
-Node QcfNodeIndex::addTerm( TNode n, std::vector< TNode >& reps, int index ) {
- if( index==(int)reps.size() ){
- if( d_children.empty() ){
- d_children[ n ].clear();
- return n;
- }else{
- return d_children.begin()->first;
- }
- }else{
- return d_children[reps[index]].addTerm( n, reps, index+1 );
- }
-}
-
-
-void QcfNodeIndex::debugPrint( const char * c, int t ) {
- for( std::map< TNode, QcfNodeIndex >::iterator it = d_children.begin(); it != d_children.end(); ++it ){
- if( !it->first.isNull() ){
- for( int j=0; j<t; j++ ){ Trace(c) << " "; }
- Trace(c) << it->first << " : " << std::endl;
- it->second.debugPrint( c, t+1 );
- }
- }
-}
-
-
-void QuantInfo::initialize( Node q, Node qn ) {
- d_q = q;
- for( unsigned i=0; i<q[0].getNumChildren(); i++ ){
- d_match.push_back( TNode::null() );
- d_match_term.push_back( TNode::null() );
- }
-
- //register the variables
- for( unsigned i=0; i<q[0].getNumChildren(); i++ ){
- d_var_num[q[0][i]] = i;
- d_vars.push_back( q[0][i] );
- }
-
- registerNode( qn, true, true );
-
-
- Trace("qcf-qregister") << "- Make match gen structure..." << std::endl;
- d_mg = new MatchGen( this, qn );
-
- if( d_mg->isValid() ){
- /*
- for( unsigned j=0; j<q[0].getNumChildren(); j++ ){
- if( d_inMatchConstraint.find( q[0][j] )==d_inMatchConstraint.end() ){
- Trace("qcf-invalid") << "QCF invalid : variable " << q[0][j] << " does not exist in a matching constraint." << std::endl;
- d_mg->setInvalid();
- break;
- }
- }
- */
- if( d_mg->isValid() ){
- for( unsigned j=q[0].getNumChildren(); j<d_vars.size(); j++ ){
- if( d_vars[j].getKind()!=BOUND_VARIABLE ){
- d_var_mg[j] = NULL;
- bool is_tsym = false;
- if( !MatchGen::isHandledUfTerm( d_vars[j] ) && d_vars[j].getKind()!=ITE ){
- is_tsym = true;
- d_tsym_vars.push_back( j );
- }
- if( !is_tsym || options::qcfTConstraint() ){
- d_var_mg[j] = new MatchGen( this, d_vars[j], true );
- }
- if( !d_var_mg[j] || !d_var_mg[j]->isValid() ){
- Trace("qcf-invalid") << "QCF invalid : cannot match for " << d_vars[j] << std::endl;
- d_mg->setInvalid();
- break;
- }else{
- std::vector< int > bvars;
- d_var_mg[j]->determineVariableOrder( this, bvars );
- }
- }
- }
- if( d_mg->isValid() ){
- std::vector< int > bvars;
- d_mg->determineVariableOrder( this, bvars );
- }
- }
- }else{
- Trace("qcf-invalid") << "QCF invalid : body of formula cannot be processed." << std::endl;
- }
- Trace("qcf-qregister-summary") << "QCF register : " << ( d_mg->isValid() ? "VALID " : "INVALID" ) << " : " << q << std::endl;
-}
-
-void QuantInfo::registerNode( Node n, bool hasPol, bool pol, bool beneathQuant ) {
- Trace("qcf-qregister-debug2") << "Register : " << n << std::endl;
- if( n.getKind()==FORALL ){
- registerNode( n[1], hasPol, pol, true );
- }else{
- if( !MatchGen::isHandledBoolConnective( n ) ){
- if( n.hasBoundVar() ){
- //literals
- if( n.getKind()==EQUAL ){
- for( unsigned i=0; i<n.getNumChildren(); i++ ){
- flatten( n[i], beneathQuant );
- }
- }else if( MatchGen::isHandledUfTerm( n ) ){
- flatten( n, beneathQuant );
- }else if( n.getKind()==ITE ){
- for( unsigned i=1; i<=2; i++ ){
- flatten( n[i], beneathQuant );
- }
- registerNode( n[0], false, pol, beneathQuant );
- }else if( options::qcfTConstraint() ){
- //a theory-specific predicate
- for( unsigned i=0; i<n.getNumChildren(); i++ ){
- flatten( n[i], beneathQuant );
- }
- }
- }
- }else{
- for( unsigned i=0; i<n.getNumChildren(); i++ ){
- bool newHasPol;
- bool newPol;
- QuantPhaseReq::getPolarity( n, i, hasPol, pol, newHasPol, newPol );
- //QcfNode * qcfc = new QcfNode( d_c );
- //qcfc->d_parent = qcf;
- //qcf->d_child[i] = qcfc;
- registerNode( n[i], newHasPol, newPol, beneathQuant );
- }
- }
- }
-}
-
-void QuantInfo::flatten( Node n, bool beneathQuant ) {
- Trace("qcf-qregister-debug2") << "Flatten : " << n << std::endl;
- if( n.hasBoundVar() ){
- if( n.getKind()==BOUND_VARIABLE ){
- d_inMatchConstraint[n] = true;
- }
- //if( MatchGen::isHandledUfTerm( n ) || n.getKind()==ITE ){
- if( d_var_num.find( n )==d_var_num.end() ){
- Trace("qcf-qregister-debug2") << "Add FLATTEN VAR : " << n << std::endl;
- d_var_num[n] = d_vars.size();
- d_vars.push_back( n );
- d_match.push_back( TNode::null() );
- d_match_term.push_back( TNode::null() );
- if( n.getKind()==ITE ){
- registerNode( n, false, false );
- }else{
- for( unsigned i=0; i<n.getNumChildren(); i++ ){
- flatten( n[i], beneathQuant );
- }
- }
- }else{
- Trace("qcf-qregister-debug2") << "...already processed" << std::endl;
- }
- }else{
- Trace("qcf-qregister-debug2") << "...is ground." << std::endl;
- }
-}
-
-
-void QuantInfo::reset_round( QuantConflictFind * p ) {
- for( unsigned i=0; i<d_match.size(); i++ ){
- d_match[i] = TNode::null();
- d_match_term[i] = TNode::null();
- }
- d_curr_var_deq.clear();
- d_tconstraints.clear();
- //add built-in variable constraints
- for( unsigned r=0; r<2; r++ ){
- for( std::map< int, std::vector< Node > >::iterator it = d_var_constraint[r].begin();
- it != d_var_constraint[r].end(); ++it ){
- for( unsigned j=0; j<it->second.size(); j++ ){
- Node rr = it->second[j];
- if( !isVar( rr ) ){
- rr = p->getRepresentative( rr );
- }
- if( addConstraint( p, it->first, rr, r==0 )==-1 ){
- d_var_constraint[0].clear();
- d_var_constraint[1].clear();
- //quantified formula is actually equivalent to true
- Trace("qcf-qregister") << "Quantifier is equivalent to true!!!" << std::endl;
- d_mg->d_children.clear();
- d_mg->d_n = NodeManager::currentNM()->mkConst( true );
- d_mg->d_type = MatchGen::typ_ground;
- return;
- }
- }
- }
- }
- d_mg->reset_round( p );
- for( std::map< int, MatchGen * >::iterator it = d_var_mg.begin(); it != d_var_mg.end(); ++it ){
- it->second->reset_round( p );
- }
- //now, reset for matching
- d_mg->reset( p, false, this );
-}
-
-int QuantInfo::getCurrentRepVar( int v ) {
- if( v!=-1 && !d_match[v].isNull() ){
- int vn = getVarNum( d_match[v] );
- if( vn!=-1 ){
- //int vr = getCurrentRepVar( vn );
- //d_match[v] = d_vars[vr];
- //return vr;
- return getCurrentRepVar( vn );
- }
- }
- return v;
-}
-
-TNode QuantInfo::getCurrentValue( TNode n ) {
- int v = getVarNum( n );
- if( v==-1 ){
- return n;
- }else{
- if( d_match[v].isNull() ){
- return n;
- }else{
- Assert( getVarNum( d_match[v] )!=v );
- return getCurrentValue( d_match[v] );
- }
- }
-}
-
-TNode QuantInfo::getCurrentExpValue( TNode n ) {
- int v = getVarNum( n );
- if( v==-1 ){
- return n;
- }else{
- if( d_match[v].isNull() ){
- return n;
- }else{
- Assert( getVarNum( d_match[v] )!=v );
- if( d_match_term[v].isNull() ){
- return getCurrentValue( d_match[v] );
- }else{
- return d_match_term[v];
- }
- }
- }
-}
-
-bool QuantInfo::getCurrentCanBeEqual( QuantConflictFind * p, int v, TNode n, bool chDiseq ) {
- //check disequalities
- std::map< int, std::map< TNode, int > >::iterator itd = d_curr_var_deq.find( v );
- if( itd!=d_curr_var_deq.end() ){
- for( std::map< TNode, int >::iterator it = itd->second.begin(); it != itd->second.end(); ++it ){
- Node cv = getCurrentValue( it->first );
- Debug("qcf-ccbe") << "compare " << cv << " " << n << std::endl;
- if( cv==n ){
- return false;
- }else if( chDiseq && !isVar( n ) && !isVar( cv ) ){
- //they must actually be disequal if we are looking for conflicts
- if( !p->areDisequal( n, cv ) ){
- //TODO : check for entailed disequal
-
- return false;
- }
- }
- }
- }
- return true;
-}
-
-int QuantInfo::addConstraint( QuantConflictFind * p, int v, TNode n, bool polarity ) {
- v = getCurrentRepVar( v );
- int vn = getVarNum( n );
- vn = vn==-1 ? -1 : getCurrentRepVar( vn );
- n = getCurrentValue( n );
- return addConstraint( p, v, n, vn, polarity, false );
-}
-
-int QuantInfo::addConstraint( QuantConflictFind * p, int v, TNode n, int vn, bool polarity, bool doRemove ) {
- //for handling equalities between variables, and disequalities involving variables
- Debug("qcf-match-debug") << "- " << (doRemove ? "un" : "" ) << "constrain : " << v << " -> " << n << " (cv=" << getCurrentValue( n ) << ")";
- Debug("qcf-match-debug") << ", (vn=" << vn << "), polarity = " << polarity << std::endl;
- Assert( doRemove || n==getCurrentValue( n ) );
- Assert( doRemove || v==getCurrentRepVar( v ) );
- Assert( doRemove || vn==getCurrentRepVar( getVarNum( n ) ) );
- if( polarity ){
- if( vn!=v ){
- if( doRemove ){
- if( vn!=-1 ){
- //if set to this in the opposite direction, clean up opposite instead
- // std::map< int, TNode >::iterator itmn = d_match.find( vn );
- if( d_match[vn]==d_vars[v] ){
- return addConstraint( p, vn, d_vars[v], v, true, true );
- }else{
- //unsetting variables equal
- std::map< int, std::map< TNode, int > >::iterator itd = d_curr_var_deq.find( vn );
- if( itd!=d_curr_var_deq.end() ){
- //remove disequalities owned by this
- std::vector< TNode > remDeq;
- for( std::map< TNode, int >::iterator it = itd->second.begin(); it != itd->second.end(); ++it ){
- if( it->second==v ){
- remDeq.push_back( it->first );
- }
- }
- for( unsigned i=0; i<remDeq.size(); i++ ){
- d_curr_var_deq[vn].erase( remDeq[i] );
- }
- }
- }
- }
- d_match[v] = TNode::null();
- return 1;
- }else{
- //std::map< int, TNode >::iterator itm = d_match.find( v );
-
- if( vn!=-1 ){
- Debug("qcf-match-debug") << " ...Variable bound to variable" << std::endl;
- //std::map< int, TNode >::iterator itmn = d_match.find( vn );
- if( d_match[v].isNull() ){
- //setting variables equal
- bool alreadySet = false;
- if( !d_match[vn].isNull() ){
- alreadySet = true;
- Assert( !isVar( d_match[vn] ) );
- }
-
- //copy or check disequalities
- std::map< int, std::map< TNode, int > >::iterator itd = d_curr_var_deq.find( v );
- if( itd!=d_curr_var_deq.end() ){
- for( std::map< TNode, int >::iterator it = itd->second.begin(); it != itd->second.end(); ++it ){
- Node dv = getCurrentValue( it->first );
- if( !alreadySet ){
- if( d_curr_var_deq[vn].find( dv )==d_curr_var_deq[vn].end() ){
- d_curr_var_deq[vn][dv] = v;
- }
- }else{
- if( !p->areMatchDisequal( d_match[vn], dv ) ){
- Debug("qcf-match-debug") << " -> fail, conflicting disequality" << std::endl;
- return -1;
- }
- }
- }
- }
- if( alreadySet ){
- n = getCurrentValue( n );
- }
- }else{
- if( d_match[vn].isNull() ){
- Debug("qcf-match-debug") << " ...Reverse direction" << std::endl;
- //set the opposite direction
- return addConstraint( p, vn, d_vars[v], v, true, false );
- }else{
- Debug("qcf-match-debug") << " -> Both variables bound, compare" << std::endl;
- //are they currently equal
- return p->areMatchEqual( d_match[v], d_match[vn] ) ? 0 : -1;
- }
- }
- }else{
- Debug("qcf-match-debug") << " ...Variable bound to ground" << std::endl;
- if( d_match[v].isNull() ){
- }else{
- //compare ground values
- Debug("qcf-match-debug") << " -> Ground value, compare " << d_match[v] << " "<< n << std::endl;
- return p->areMatchEqual( d_match[v], n ) ? 0 : -1;
- }
- }
- if( setMatch( p, v, n ) ){
- Debug("qcf-match-debug") << " -> success" << std::endl;
- return 1;
- }else{
- Debug("qcf-match-debug") << " -> fail, conflicting disequality" << std::endl;
- return -1;
- }
- }
- }else{
- Debug("qcf-match-debug") << " -> redundant, variable identity" << std::endl;
- return 0;
- }
- }else{
- if( vn==v ){
- Debug("qcf-match-debug") << " -> fail, variable identity" << std::endl;
- return -1;
- }else{
- if( doRemove ){
- Assert( d_curr_var_deq[v].find( n )!=d_curr_var_deq[v].end() );
- d_curr_var_deq[v].erase( n );
- return 1;
- }else{
- if( d_curr_var_deq[v].find( n )==d_curr_var_deq[v].end() ){
- //check if it respects equality
- //std::map< int, TNode >::iterator itm = d_match.find( v );
- if( !d_match[v].isNull() ){
- TNode nv = getCurrentValue( n );
- if( !p->areMatchDisequal( nv, d_match[v] ) ){
- Debug("qcf-match-debug") << " -> fail, conflicting disequality" << std::endl;
- return -1;
- }
- }
- d_curr_var_deq[v][n] = v;
- Debug("qcf-match-debug") << " -> success" << std::endl;
- return 1;
- }else{
- Debug("qcf-match-debug") << " -> redundant disequality" << std::endl;
- return 0;
- }
- }
- }
- }
-}
-
-bool QuantInfo::isConstrainedVar( int v ) {
- if( d_curr_var_deq.find( v )!=d_curr_var_deq.end() && !d_curr_var_deq[v].empty() ){
- return true;
- }else{
- Node vv = getVar( v );
- //for( std::map< int, TNode >::iterator it = d_match.begin(); it != d_match.end(); ++it ){
- for( unsigned i=0; i<d_match.size(); i++ ){
- if( d_match[i]==vv ){
- return true;
- }
- }
- for( std::map< int, std::map< TNode, int > >::iterator it = d_curr_var_deq.begin(); it != d_curr_var_deq.end(); ++it ){
- for( std::map< TNode, int >::iterator it2 = it->second.begin(); it2 != it->second.end(); ++it2 ){
- if( it2->first==vv ){
- return true;
- }
- }
- }
- return false;
- }
-}
-
-bool QuantInfo::setMatch( QuantConflictFind * p, int v, TNode n ) {
- if( getCurrentCanBeEqual( p, v, n ) ){
- Debug("qcf-match-debug") << "-- bind : " << v << " -> " << n << ", checked " << d_curr_var_deq[v].size() << " disequalities" << std::endl;
- d_match[v] = n;
- return true;
- }else{
- return false;
- }
-}
-
-bool QuantInfo::isMatchSpurious( QuantConflictFind * p ) {
- for( int i=0; i<getNumVars(); i++ ){
- //std::map< int, TNode >::iterator it = d_match.find( i );
- if( !d_match[i].isNull() ){
- if( !getCurrentCanBeEqual( p, i, d_match[i], p->d_effort==QuantConflictFind::effort_conflict ) ){
- return true;
- }
- }
- }
- return false;
-}
-
-bool QuantInfo::isTConstraintSpurious( QuantConflictFind * p, std::vector< Node >& terms ) {
- if( !d_tconstraints.empty() ){
- //check constraints
- for( std::map< Node, bool >::iterator it = d_tconstraints.begin(); it != d_tconstraints.end(); ++it ){
- //apply substitution to the tconstraint
- Node cons = it->first.substitute( p->getQuantifiersEngine()->getTermDatabase()->d_vars[d_q].begin(),
- p->getQuantifiersEngine()->getTermDatabase()->d_vars[d_q].end(),
- terms.begin(), terms.end() );
- cons = it->second ? cons : cons.negate();
- if( !entailmentTest( p, cons, p->d_effort==QuantConflictFind::effort_conflict ) ){
- return true;
- }
- }
- }
- return false;
-}
-
-bool QuantInfo::entailmentTest( QuantConflictFind * p, Node lit, bool chEnt ) {
- Trace("qcf-tconstraint-debug") << "Check : " << lit << std::endl;
- Node rew = Rewriter::rewrite( lit );
- if( rew==p->d_false ){
- Trace("qcf-tconstraint-debug") << "...constraint " << lit << " is disentailed (rewrites to false)." << std::endl;
- return false;
- }else if( rew!=p->d_true ){
- //if checking for conflicts, we must be sure that the constraint is entailed
- if( chEnt ){
- //check if it is entailed
- Trace("qcf-tconstraint-debug") << "Check entailment of " << rew << "..." << std::endl;
- std::pair<bool, Node> et = p->getQuantifiersEngine()->getTheoryEngine()->entailmentCheck(THEORY_OF_TYPE_BASED, rew );
- ++(p->d_statistics.d_entailment_checks);
- Trace("qcf-tconstraint-debug") << "ET result : " << et.first << " " << et.second << std::endl;
- if( !et.first ){
- Trace("qcf-tconstraint-debug") << "...cannot show entailment of " << rew << "." << std::endl;
- return false;
- }else{
- return true;
- }
- }else{
- Trace("qcf-tconstraint-debug") << "...does not need to be entailed." << std::endl;
- return true;
- }
- }else{
- Trace("qcf-tconstraint-debug") << "...rewrites to true." << std::endl;
- return true;
- }
-}
-
-bool QuantInfo::completeMatch( QuantConflictFind * p, std::vector< int >& assigned, bool doContinue ) {
- //assign values for variables that were unassigned (usually not necessary, but handles corner cases)
- bool doFail = false;
- bool success = true;
- if( doContinue ){
- doFail = true;
- success = false;
- }else{
- //solve for interpreted symbol matches
- // this breaks the invariant that all introduced constraints are over existing terms
- for( int i=(int)(d_tsym_vars.size()-1); i>=0; i-- ){
- int index = d_tsym_vars[i];
- TNode v = getCurrentValue( d_vars[index] );
- int slv_v = -1;
- if( v==d_vars[index] ){
- slv_v = index;
- }
- Trace("qcf-tconstraint-debug") << "Solve " << d_vars[index] << " = " << v << " " << d_vars[index].getKind() << std::endl;
- if( d_vars[index].getKind()==PLUS || d_vars[index].getKind()==MULT ){
- Kind k = d_vars[index].getKind();
- std::vector< TNode > children;
- for( unsigned j=0; j<d_vars[index].getNumChildren(); j++ ){
- int vn = getVarNum( d_vars[index][j] );
- if( vn!=-1 ){
- TNode vv = getCurrentValue( d_vars[index][j] );
- if( vv==d_vars[index][j] ){
- //we will assign this
- if( slv_v==-1 ){
- Trace("qcf-tconstraint-debug") << "...will solve for var #" << vn << std::endl;
- slv_v = vn;
- if( p->d_effort!=QuantConflictFind::effort_conflict ){
- break;
- }
- }else{
- Node z = p->getZero( k );
- if( !z.isNull() ){
- Trace("qcf-tconstraint-debug") << "...set " << d_vars[vn] << " = " << z << std::endl;
- assigned.push_back( vn );
- if( !setMatch( p, vn, z ) ){
- success = false;
- break;
- }
- }
- }
- }else{
- Trace("qcf-tconstraint-debug") << "...sum value " << vv << std::endl;
- children.push_back( vv );
- }
- }else{
- Trace("qcf-tconstraint-debug") << "...sum " << d_vars[index][j] << std::endl;
- children.push_back( d_vars[index][j] );
- }
- }
- if( success ){
- if( slv_v!=-1 ){
- Node lhs;
- if( children.empty() ){
- lhs = p->getZero( k );
- }else if( children.size()==1 ){
- lhs = children[0];
- }else{
- lhs = NodeManager::currentNM()->mkNode( k, children );
- }
- Node sum;
- if( v==d_vars[index] ){
- sum = lhs;
- }else{
- if( p->d_effort==QuantConflictFind::effort_conflict ){
- Kind kn = k;
- if( d_vars[index].getKind()==PLUS ){
- kn = MINUS;
- }
- if( kn!=k ){
- sum = NodeManager::currentNM()->mkNode( kn, v, lhs );
- }
- }
- }
- if( !sum.isNull() ){
- assigned.push_back( slv_v );
- Trace("qcf-tconstraint-debug") << "...set " << d_vars[slv_v] << " = " << sum << std::endl;
- if( !setMatch( p, slv_v, sum ) ){
- success = false;
- }
- p->d_tempCache.push_back( sum );
- }
- }else{
- //must show that constraint is met
- Node sum = NodeManager::currentNM()->mkNode( k, children );
- Node eq = sum.eqNode( v );
- if( !entailmentTest( p, eq ) ){
- success = false;
- }
- p->d_tempCache.push_back( sum );
- }
- }
- }
-
- if( !success ){
- break;
- }
- }
- if( success ){
- //check what is left to assign
- d_unassigned.clear();
- d_unassigned_tn.clear();
- std::vector< int > unassigned[2];
- std::vector< TypeNode > unassigned_tn[2];
- for( int i=0; i<getNumVars(); i++ ){
- if( d_match[i].isNull() ){
- int rindex = d_var_mg.find( i )==d_var_mg.end() ? 1 : 0;
- unassigned[rindex].push_back( i );
- unassigned_tn[rindex].push_back( getVar( i ).getType() );
- assigned.push_back( i );
- }
- }
- d_unassigned_nvar = unassigned[0].size();
- for( unsigned i=0; i<2; i++ ){
- d_unassigned.insert( d_unassigned.end(), unassigned[i].begin(), unassigned[i].end() );
- d_unassigned_tn.insert( d_unassigned_tn.end(), unassigned_tn[i].begin(), unassigned_tn[i].end() );
- }
- d_una_eqc_count.clear();
- d_una_index = 0;
- }
- }
-
- if( !d_unassigned.empty() && ( success || doContinue ) ){
- Trace("qcf-check") << "Assign to unassigned..." << std::endl;
- do {
- if( doFail ){
- Trace("qcf-check-unassign") << "Failure, try again..." << std::endl;
- }
- bool invalidMatch = false;
- while( ( d_una_index>=0 && (int)d_una_index<(int)d_unassigned.size() ) || invalidMatch || doFail ){
- invalidMatch = false;
- if( !doFail && d_una_index==(int)d_una_eqc_count.size() ){
- //check if it has now been assigned
- if( d_una_index<d_unassigned_nvar ){
- if( !isConstrainedVar( d_unassigned[d_una_index] ) ){
- d_una_eqc_count.push_back( -1 );
- }else{
- d_var_mg[ d_unassigned[d_una_index] ]->reset( p, true, this );
- d_una_eqc_count.push_back( 0 );
- }
- }else{
- d_una_eqc_count.push_back( 0 );
- }
- }else{
- bool failed = false;
- if( !doFail ){
- if( d_una_index<d_unassigned_nvar ){
- if( !isConstrainedVar( d_unassigned[d_una_index] ) ){
- Trace("qcf-check-unassign") << "Succeeded, variable unconstrained at " << d_una_index << std::endl;
- d_una_index++;
- }else if( d_var_mg[d_unassigned[d_una_index]]->getNextMatch( p, this ) ){
- Trace("qcf-check-unassign") << "Succeeded match with mg at " << d_una_index << std::endl;
- d_una_index++;
- }else{
- failed = true;
- Trace("qcf-check-unassign") << "Failed match with mg at " << d_una_index << std::endl;
- }
- }else{
- Assert( doFail || d_una_index==(int)d_una_eqc_count.size()-1 );
- if( d_una_eqc_count[d_una_index]<(int)p->d_eqcs[d_unassigned_tn[d_una_index]].size() ){
- int currIndex = d_una_eqc_count[d_una_index];
- d_una_eqc_count[d_una_index]++;
- Trace("qcf-check-unassign") << d_unassigned[d_una_index] << "->" << p->d_eqcs[d_unassigned_tn[d_una_index]][currIndex] << std::endl;
- if( setMatch( p, d_unassigned[d_una_index], p->d_eqcs[d_unassigned_tn[d_una_index]][currIndex] ) ){
- d_match_term[d_unassigned[d_una_index]] = TNode::null();
- Trace("qcf-check-unassign") << "Succeeded match " << d_una_index << std::endl;
- d_una_index++;
- }else{
- Trace("qcf-check-unassign") << "Failed match " << d_una_index << std::endl;
- invalidMatch = true;
- }
- }else{
- failed = true;
- Trace("qcf-check-unassign") << "No more matches " << d_una_index << std::endl;
- }
- }
- }
- if( doFail || failed ){
- do{
- if( !doFail ){
- d_una_eqc_count.pop_back();
- }else{
- doFail = false;
- }
- d_una_index--;
- }while( d_una_index>=0 && d_una_eqc_count[d_una_index]==-1 );
- }
- }
- }
- success = d_una_index>=0;
- if( success ){
- doFail = true;
- Trace("qcf-check-unassign") << " Try: " << std::endl;
- for( unsigned i=0; i<d_unassigned.size(); i++ ){
- int ui = d_unassigned[i];
- if( !d_match[ui].isNull() ){
- Trace("qcf-check-unassign") << " Assigned #" << ui << " : " << d_vars[ui] << " -> " << d_match[ui] << std::endl;
- }
- }
- }
- }while( success && isMatchSpurious( p ) );
- }
- if( success ){
- for( unsigned i=0; i<d_unassigned.size(); i++ ){
- int ui = d_unassigned[i];
- if( !d_match[ui].isNull() ){
- Trace("qcf-check") << " Assigned #" << ui << " : " << d_vars[ui] << " -> " << d_match[ui] << std::endl;
- }
- }
- return true;
- }else{
- for( unsigned i=0; i<assigned.size(); i++ ){
- d_match[ assigned[i] ] = TNode::null();
- }
- assigned.clear();
- return false;
- }
-}
-
-void QuantInfo::getMatch( std::vector< Node >& terms ){
- for( unsigned i=0; i<d_q[0].getNumChildren(); i++ ){
- //Node cv = qi->getCurrentValue( qi->d_match[i] );
- int repVar = getCurrentRepVar( i );
- Node cv;
- //std::map< int, TNode >::iterator itmt = qi->d_match_term.find( repVar );
- if( !d_match_term[repVar].isNull() ){
- cv = d_match_term[repVar];
- }else{
- cv = d_match[repVar];
- }
- Debug("qcf-check-inst") << "INST : " << i << " -> " << cv << ", from " << d_match[i] << std::endl;
- terms.push_back( cv );
- }
-}
-
-void QuantInfo::revertMatch( std::vector< int >& assigned ) {
- for( unsigned i=0; i<assigned.size(); i++ ){
- d_match[ assigned[i] ] = TNode::null();
- }
-}
-
-void QuantInfo::debugPrintMatch( const char * c ) {
- for( int i=0; i<getNumVars(); i++ ){
- Trace(c) << " " << d_vars[i] << " -> ";
- if( !d_match[i].isNull() ){
- Trace(c) << d_match[i];
- }else{
- Trace(c) << "(unassigned) ";
- }
- if( !d_curr_var_deq[i].empty() ){
- Trace(c) << ", DEQ{ ";
- for( std::map< TNode, int >::iterator it = d_curr_var_deq[i].begin(); it != d_curr_var_deq[i].end(); ++it ){
- Trace(c) << it->first << " ";
- }
- Trace(c) << "}";
- }
- if( !d_match_term[i].isNull() && d_match_term[i]!=d_match[i] ){
- Trace(c) << ", EXP : " << d_match_term[i];
- }
- Trace(c) << std::endl;
- }
- if( !d_tconstraints.empty() ){
- Trace(c) << "ADDITIONAL CONSTRAINTS : " << std::endl;
- for( std::map< Node, bool >::iterator it = d_tconstraints.begin(); it != d_tconstraints.end(); ++it ){
- Trace(c) << " " << it->first << " -> " << it->second << std::endl;
- }
- }
-}
-
-MatchGen::MatchGen( QuantInfo * qi, Node n, bool isVar ){
- Trace("qcf-qregister-debug") << "Make match gen for " << n << ", isVar = " << isVar << std::endl;
- std::vector< Node > qni_apps;
- d_qni_size = 0;
- if( isVar ){
- Assert( qi->d_var_num.find( n )!=qi->d_var_num.end() );
- if( n.getKind()==ITE ){
- d_type = typ_ite_var;
- d_type_not = false;
- d_n = n;
- d_children.push_back( MatchGen( qi, d_n[0] ) );
- if( d_children[0].isValid() ){
- d_type = typ_ite_var;
- for( unsigned i=1; i<=2; i++ ){
- Node nn = n.eqNode( n[i] );
- d_children.push_back( MatchGen( qi, nn ) );
- d_children[d_children.size()-1].d_qni_bound_except.push_back( 0 );
- if( !d_children[d_children.size()-1].isValid() ){
- setInvalid();
- break;
- }
- }
- }else{
- d_type = typ_invalid;
- }
- }else{
- d_type = isHandledUfTerm( n ) ? typ_var : typ_tsym;
- d_qni_var_num[0] = qi->getVarNum( n );
- d_qni_size++;
- d_type_not = false;
- d_n = n;
- //Node f = getOperator( n );
- for( unsigned j=0; j<d_n.getNumChildren(); j++ ){
- Node nn = d_n[j];
- Trace("qcf-qregister-debug") << " " << d_qni_size;
- if( qi->isVar( nn ) ){
- int v = qi->d_var_num[nn];
- Trace("qcf-qregister-debug") << " is var #" << v << std::endl;
- d_qni_var_num[d_qni_size] = v;
- //qi->addFuncParent( v, f, j );
- }else{
- Trace("qcf-qregister-debug") << " is gterm " << nn << std::endl;
- d_qni_gterm[d_qni_size] = nn;
- }
- d_qni_size++;
- }
- }
- }else{
- if( n.hasBoundVar() ){
- d_type_not = false;
- d_n = n;
- if( d_n.getKind()==NOT ){
- d_n = d_n[0];
- d_type_not = !d_type_not;
- }
-
- if( isHandledBoolConnective( d_n ) ){
- //non-literals
- d_type = typ_formula;
- for( unsigned i=0; i<d_n.getNumChildren(); i++ ){
- if( d_n.getKind()!=FORALL || i==1 ){
- d_children.push_back( MatchGen( qi, d_n[i], false ) );
- if( !d_children[d_children.size()-1].isValid() ){
- setInvalid();
- break;
- }
- }
- /*
- else if( isTop && n.getKind()==OR && d_children[d_children.size()-1].d_type==typ_var_eq ){
- Trace("qcf-qregister-debug") << "Remove child, make built-in constraint" << std::endl;
- //if variable equality/disequality at top level, remove immediately
- bool cIsNot = d_children[d_children.size()-1].d_type_not;
- Node cn = d_children[d_children.size()-1].d_n;
- Assert( cn.getKind()==EQUAL );
- Assert( p->d_qinfo[q].isVar( cn[0] ) || p->d_qinfo[q].isVar( cn[1] ) );
- //make it a built-in constraint instead
- for( unsigned i=0; i<2; i++ ){
- if( p->d_qinfo[q].isVar( cn[i] ) ){
- int v = p->d_qinfo[q].getVarNum( cn[i] );
- Node cno = cn[i==0 ? 1 : 0];
- p->d_qinfo[q].d_var_constraint[ cIsNot ? 0 : 1 ][v].push_back( cno );
- break;
- }
- }
- d_children.pop_back();
- }
- */
- }
- }else{
- d_type = typ_invalid;
- //literals
- if( isHandledUfTerm( d_n ) ){
- Assert( qi->isVar( d_n ) );
- d_type = typ_pred;
- }else if( d_n.getKind()==BOUND_VARIABLE ){
- Assert( d_n.getType().isBoolean() );
- d_type = typ_bool_var;
- }else if( d_n.getKind()==EQUAL || options::qcfTConstraint() ){
- for( unsigned i=0; i<d_n.getNumChildren(); i++ ){
- if( d_n[i].hasBoundVar() ){
- if( !qi->isVar( d_n[i] ) ){
- Trace("qcf-qregister-debug") << "ERROR : not var " << d_n[i] << std::endl;
- }
- Assert( qi->isVar( d_n[i] ) );
- if( d_n.getKind()!=EQUAL && qi->isVar( d_n[i] ) ){
- d_qni_var_num[i+1] = qi->d_var_num[d_n[i]];
- }
- }else{
- d_qni_gterm[i] = d_n[i];
- }
- }
- d_type = d_n.getKind()==EQUAL ? typ_eq : typ_tconstraint;
- Trace("qcf-tconstraint") << "T-Constraint : " << d_n << std::endl;
- }
- }
- }else{
- //we will just evaluate
- d_n = n;
- d_type = typ_ground;
- }
- //if( d_type!=typ_invalid ){
- //determine an efficient children ordering
- //if( !d_children.empty() ){
- //for( unsigned i=0; i<d_children.size(); i++ ){
- // d_children_order.push_back( i );
- //}
- //if( !d_n.isNull() && ( d_n.getKind()==OR || d_n.getKind()==AND || d_n.getKind()==IFF ) ){
- //sort based on the type of the constraint : ground comes first, then literals, then others
- //MatchGenSort mgs;
- //mgs.d_mg = this;
- //std::sort( d_children_order.begin(), d_children_order.end(), mgs );
- //}
- //}
- //}
- }
- Trace("qcf-qregister-debug") << "Done make match gen " << n << ", type = ";
- debugPrintType( "qcf-qregister-debug", d_type, true );
- Trace("qcf-qregister-debug") << std::endl;
- //Assert( d_children.size()==d_children_order.size() );
-
-}
-
-void MatchGen::collectBoundVar( QuantInfo * qi, Node n, std::vector< int >& cbvars ) {
- int v = qi->getVarNum( n );
- if( v!=-1 && std::find( cbvars.begin(), cbvars.end(), v )==cbvars.end() ){
- cbvars.push_back( v );
- }
- for( unsigned i=0; i<n.getNumChildren(); i++ ){
- collectBoundVar( qi, n[i], cbvars );
- }
-}
-
-void MatchGen::determineVariableOrder( QuantInfo * qi, std::vector< int >& bvars ) {
- Trace("qcf-qregister-debug") << "Determine variable order " << d_n << std::endl;
- bool isCom = d_type==typ_formula && ( d_n.getKind()==OR || d_n.getKind()==AND || d_n.getKind()==IFF );
- std::map< int, std::vector< int > > c_to_vars;
- std::map< int, std::vector< int > > vars_to_c;
- std::map< int, int > vb_count;
- std::map< int, int > vu_count;
- std::vector< bool > assigned;
- Trace("qcf-qregister-debug") << "Calculate bound variables..." << std::endl;
- for( unsigned i=0; i<d_children.size(); i++ ){
- collectBoundVar( qi, d_children[i].d_n, c_to_vars[i] );
- assigned.push_back( false );
- vb_count[i] = 0;
- vu_count[i] = 0;
- for( unsigned j=0; j<c_to_vars[i].size(); j++ ){
- int v = c_to_vars[i][j];
- vars_to_c[v].push_back( i );
- if( std::find( bvars.begin(), bvars.end(), v )==bvars.end() ){
- vu_count[i]++;
- if( !isCom ){
- bvars.push_back( v );
- }
- }else{
- vb_count[i]++;
- }
- }
- }
- if( isCom ){
- //children that bind the least number of unbound variables go first
- do {
- int min_score = -1;
- int min_score_index = -1;
- for( unsigned i=0; i<d_children.size(); i++ ){
- if( !assigned[i] ){
- int score = vu_count[i];
- if( min_score==-1 || score<min_score ){
- min_score = score;
- min_score_index = i;
- }
- }
- }
- Trace("qcf-qregister-debug") << "...assign child " << min_score_index << "/" << d_children.size() << std::endl;
- Assert( min_score_index!=-1 );
- //add to children order
- d_children_order.push_back( min_score_index );
- assigned[min_score_index] = true;
- //if( vb_count[min_score_index]==0 ){
- // d_independent.push_back( min_score_index );
- //}
- //determine order internal to children
- d_children[min_score_index].determineVariableOrder( qi, bvars );
- Trace("qcf-qregister-debug") << "...bind variables" << std::endl;
- //now, make it a bound variable
- for( unsigned i=0; i<c_to_vars[min_score_index].size(); i++ ){
- int v = c_to_vars[min_score_index][i];
- if( std::find( bvars.begin(), bvars.end(), v )==bvars.end() ){
- for( unsigned j=0; j<vars_to_c[v].size(); j++ ){
- int vc = vars_to_c[v][j];
- vu_count[vc]--;
- vb_count[vc]++;
- }
- bvars.push_back( v );
- }
- }
- Trace("qcf-qregister-debug") << "...done assign child " << min_score_index << std::endl;
- }while( d_children_order.size()!=d_children.size() );
- Trace("qcf-qregister-debug") << "Done assign variable ordering for " << d_n << std::endl;
- }else{
- for( unsigned i=0; i<d_children.size(); i++ ){
- d_children_order.push_back( i );
- d_children[i].determineVariableOrder( qi, bvars );
- }
- }
-}
-
-
-void MatchGen::reset_round( QuantConflictFind * p ) {
- d_wasSet = false;
- for( unsigned i=0; i<d_children.size(); i++ ){
- d_children[i].reset_round( p );
- }
- for( std::map< int, TNode >::iterator it = d_qni_gterm.begin(); it != d_qni_gterm.end(); ++it ){
- d_qni_gterm_rep[it->first] = p->getRepresentative( it->second );
- }
- if( d_type==typ_ground ){
- int e = p->evaluate( d_n );
- if( e==1 ){
- d_ground_eval[0] = p->d_true;
- }else if( e==-1 ){
- d_ground_eval[0] = p->d_false;
- }
- }else if( d_type==typ_eq ){
- for( unsigned i=0; i<d_n.getNumChildren(); i++ ){
- if( !d_n[i].hasBoundVar() ){
- d_ground_eval[i] = p->evaluateTerm( d_n[i] );
- }
- }
- }
- d_qni_bound_cons.clear();
- d_qni_bound_cons_var.clear();
- d_qni_bound.clear();
-}
-
-void MatchGen::reset( QuantConflictFind * p, bool tgt, QuantInfo * qi ) {
- d_tgt = d_type_not ? !tgt : tgt;
- Debug("qcf-match") << " Reset for : " << d_n << ", type : ";
- debugPrintType( "qcf-match", d_type );
- Debug("qcf-match") << ", tgt = " << d_tgt << ", children = " << d_children.size() << " " << d_children_order.size() << std::endl;
- d_qn.clear();
- d_qni.clear();
- d_qni_bound.clear();
- d_child_counter = -1;
- d_tgt_orig = d_tgt;
-
- //set up processing matches
- if( d_type==typ_invalid ){
- //do nothing
- }else if( d_type==typ_ground ){
- if( d_ground_eval[0]==( d_tgt ? p->d_true : p->d_false ) ){
- d_child_counter = 0;
- }
- }else if( d_type==typ_bool_var ){
- //get current value of the variable
- TNode n = qi->getCurrentValue( d_n );
- int vn = qi->getCurrentRepVar( qi->getVarNum( n ) );
- if( vn==-1 ){
- //evaluate the value, see if it is compatible
- int e = p->evaluate( n );
- if( ( e==1 && d_tgt ) || ( e==0 && !d_tgt ) ){
- d_child_counter = 0;
- }
- }else{
- //unassigned, set match to true/false
- d_qni_bound[0] = vn;
- qi->setMatch( p, vn, d_tgt ? p->d_true : p->d_false );
- d_child_counter = 0;
- }
- if( d_child_counter==0 ){
- d_qn.push_back( NULL );
- }
- }else if( d_type==typ_var ){
- Assert( isHandledUfTerm( d_n ) );
- Node f = getOperator( p, d_n );
- Debug("qcf-match-debug") << " reset: Var will match operators of " << f << std::endl;
- QcfNodeIndex * qni = p->getQcfNodeIndex( Node::null(), f );
- if( qni!=NULL ){
- d_qn.push_back( qni );
- }
- d_matched_basis = false;
- }else if( d_type==typ_tsym || d_type==typ_tconstraint ){
- for( std::map< int, int >::iterator it = d_qni_var_num.begin(); it != d_qni_var_num.end(); ++it ){
- int repVar = qi->getCurrentRepVar( it->second );
- if( qi->d_match[repVar].isNull() ){
- Debug("qcf-match-debug") << "Force matching on child #" << it->first << ", which is var #" << repVar << std::endl;
- d_qni_bound[it->first] = repVar;
- }
- }
- d_qn.push_back( NULL );
- }else if( d_type==typ_pred || d_type==typ_eq ){
- //add initial constraint
- Node nn[2];
- int vn[2];
- if( d_type==typ_pred ){
- nn[0] = qi->getCurrentValue( d_n );
- vn[0] = qi->getCurrentRepVar( qi->getVarNum( nn[0] ) );
- nn[1] = p->getRepresentative( d_tgt ? p->d_true : p->d_false );
- vn[1] = -1;
- d_tgt = true;
- }else{
- for( unsigned i=0; i<2; i++ ){
- TNode nc;
- std::map< int, TNode >::iterator it = d_qni_gterm_rep.find( i );
- if( it!=d_qni_gterm_rep.end() ){
- nc = it->second;
- }else{
- nc = d_n[i];
- }
- nn[i] = qi->getCurrentValue( nc );
- vn[i] = qi->getCurrentRepVar( qi->getVarNum( nn[i] ) );
- }
- }
- bool success;
- if( vn[0]==-1 && vn[1]==-1 ){
- //Trace("qcf-explain") << " reset : " << d_n << " check ground values " << nn[0] << " " << nn[1] << " (tgt=" << d_tgt << ")" << std::endl;
- Debug("qcf-match-debug") << " reset: check ground values " << nn[0] << " " << nn[1] << " (" << d_tgt << ")" << std::endl;
- //just compare values
- if( d_tgt ){
- success = p->areMatchEqual( nn[0], nn[1] );
- }else{
- if( p->d_effort==QuantConflictFind::effort_conflict ){
- success = p->areDisequal( nn[0], nn[1] );
- }else{
- success = p->areMatchDisequal( nn[0], nn[1] );
- }
- }
- }else{
- //otherwise, add a constraint to a variable
- if( vn[1]!=-1 && vn[0]==-1 ){
- //swap
- Node t = nn[1];
- nn[1] = nn[0];
- nn[0] = t;
- vn[0] = vn[1];
- vn[1] = -1;
- }
- Debug("qcf-match-debug") << " reset: add constraint " << vn[0] << " -> " << nn[1] << " (vn=" << vn[1] << ")" << std::endl;
- //add some constraint
- int addc = qi->addConstraint( p, vn[0], nn[1], vn[1], d_tgt, false );
- success = addc!=-1;
- //if successful and non-redundant, store that we need to cleanup this
- if( addc==1 ){
- //Trace("qcf-explain") << " reset: " << d_n << " add constraint " << vn[0] << " -> " << nn[1] << " (vn=" << vn[1] << ")" << ", d_tgt = " << d_tgt << std::endl;
- for( unsigned i=0; i<2; i++ ){
- if( vn[i]!=-1 && std::find( d_qni_bound_except.begin(), d_qni_bound_except.end(), i )==d_qni_bound_except.end() ){
- d_qni_bound[vn[i]] = vn[i];
- }
- }
- d_qni_bound_cons[vn[0]] = nn[1];
- d_qni_bound_cons_var[vn[0]] = vn[1];
- }
- }
- //if successful, we will bind values to variables
- if( success ){
- d_qn.push_back( NULL );
- }
- }else{
- if( d_children.empty() ){
- //add dummy
- d_qn.push_back( NULL );
- }else{
- if( d_tgt && d_n.getKind()==FORALL ){
- //do nothing
- }else{
- //reset the first child to d_tgt
- d_child_counter = 0;
- getChild( d_child_counter )->reset( p, d_tgt, qi );
- }
- }
- }
- d_binding = false;
- d_wasSet = true;
- Debug("qcf-match") << " reset: Finished reset for " << d_n << ", success = " << ( !d_qn.empty() || d_child_counter!=-1 ) << std::endl;
-}
-
-bool MatchGen::getNextMatch( QuantConflictFind * p, QuantInfo * qi ) {
- Debug("qcf-match") << " Get next match for : " << d_n << ", type = ";
- debugPrintType( "qcf-match", d_type );
- Debug("qcf-match") << ", children = " << d_children.size() << ", binding = " << d_binding << std::endl;
- if( d_type==typ_invalid || d_type==typ_ground ){
- if( d_child_counter==0 ){
- d_child_counter = -1;
- return true;
- }else{
- d_wasSet = false;
- return false;
- }
- }else if( d_type==typ_var || d_type==typ_eq || d_type==typ_pred || d_type==typ_bool_var || d_type==typ_tconstraint || d_type==typ_tsym ){
- bool success = false;
- bool terminate = false;
- do {
- bool doReset = false;
- bool doFail = false;
- if( !d_binding ){
- if( doMatching( p, qi ) ){
- Debug("qcf-match-debug") << " - Matching succeeded" << std::endl;
- d_binding = true;
- d_binding_it = d_qni_bound.begin();
- doReset = true;
- //for tconstraint, add constraint
- if( d_type==typ_tconstraint ){
- std::map< Node, bool >::iterator it = qi->d_tconstraints.find( d_n );
- if( it==qi->d_tconstraints.end() ){
- qi->d_tconstraints[d_n] = d_tgt;
- //store that we added this constraint
- d_qni_bound_cons[0] = d_n;
- }else if( d_tgt!=it->second ){
- success = false;
- terminate = true;
- }
- }
- }else{
- Debug("qcf-match-debug") << " - Matching failed" << std::endl;
- success = false;
- terminate = true;
- }
- }else{
- doFail = true;
- }
- if( d_binding ){
- //also need to create match for each variable we bound
- success = true;
- Debug("qcf-match-debug") << " Produce matches for bound variables by " << d_n << ", type = ";
- debugPrintType( "qcf-match-debug", d_type );
- Debug("qcf-match-debug") << "..." << std::endl;
-
- while( ( success && d_binding_it!=d_qni_bound.end() ) || doFail ){
- std::map< int, MatchGen * >::iterator itm;
- if( !doFail ){
- Debug("qcf-match-debug") << " check variable " << d_binding_it->second << std::endl;
- itm = qi->d_var_mg.find( d_binding_it->second );
- }
- if( doFail || ( d_binding_it->first!=0 && itm!=qi->d_var_mg.end() ) ){
- Debug("qcf-match-debug") << " we had bound variable " << d_binding_it->second << ", reset = " << doReset << std::endl;
- if( doReset ){
- itm->second->reset( p, true, qi );
- }
- if( doFail || !itm->second->getNextMatch( p, qi ) ){
- do {
- if( d_binding_it==d_qni_bound.begin() ){
- Debug("qcf-match-debug") << " failed." << std::endl;
- success = false;
- }else{
- --d_binding_it;
- Debug("qcf-match-debug") << " decrement..." << std::endl;
- }
- }while( success && ( d_binding_it->first==0 || qi->d_var_mg.find( d_binding_it->second )==qi->d_var_mg.end() ) );
- doReset = false;
- doFail = false;
- }else{
- Debug("qcf-match-debug") << " increment..." << std::endl;
- ++d_binding_it;
- doReset = true;
- }
- }else{
- Debug("qcf-match-debug") << " skip..." << d_binding_it->second << std::endl;
- ++d_binding_it;
- doReset = true;
- }
- }
- if( !success ){
- d_binding = false;
- }else{
- terminate = true;
- if( d_binding_it==d_qni_bound.begin() ){
- d_binding = false;
- }
- }
- }
- }while( !terminate );
- //if not successful, clean up the variables you bound
- if( !success ){
- if( d_type==typ_eq || d_type==typ_pred ){
- //clean up the constraints you added
- for( std::map< int, TNode >::iterator it = d_qni_bound_cons.begin(); it != d_qni_bound_cons.end(); ++it ){
- if( !it->second.isNull() ){
- Debug("qcf-match") << " Clean up bound var " << it->first << (d_tgt ? "!" : "") << " = " << it->second << std::endl;
- std::map< int, int >::iterator itb = d_qni_bound_cons_var.find( it->first );
- int vn = itb!=d_qni_bound_cons_var.end() ? itb->second : -1;
- //Trace("qcf-explain") << " cleanup: " << d_n << " remove constraint " << it->first << " -> " << it->second << " (vn=" << vn << ")" << ", d_tgt = " << d_tgt << std::endl;
- qi->addConstraint( p, it->first, it->second, vn, d_tgt, true );
- }
- }
- d_qni_bound_cons.clear();
- d_qni_bound_cons_var.clear();
- d_qni_bound.clear();
- }else{
- //clean up the matches you set
- for( std::map< int, int >::iterator it = d_qni_bound.begin(); it != d_qni_bound.end(); ++it ){
- Debug("qcf-match") << " Clean up bound var " << it->second << std::endl;
- Assert( it->second<qi->getNumVars() );
- qi->d_match[ it->second ] = TNode::null();
- qi->d_match_term[ it->second ] = TNode::null();
- }
- d_qni_bound.clear();
- }
- if( d_type==typ_tconstraint ){
- //remove constraint if applicable
- if( d_qni_bound_cons.find( 0 )!=d_qni_bound_cons.end() ){
- qi->d_tconstraints.erase( d_n );
- d_qni_bound_cons.clear();
- }
- }
- /*
- if( d_type==typ_var && p->d_effort==QuantConflictFind::effort_mc && !d_matched_basis ){
- d_matched_basis = true;
- Node f = getOperator( d_n );
- TNode mbo = p->getQuantifiersEngine()->getTermDatabase()->getModelBasisOpTerm( f );
- if( qi->setMatch( p, d_qni_var_num[0], mbo ) ){
- success = true;
- d_qni_bound[0] = d_qni_var_num[0];
- }
- }
- */
- }
- Debug("qcf-match") << " ...finished matching for " << d_n << ", success = " << success << std::endl;
- d_wasSet = success;
- return success;
- }else if( d_type==typ_formula || d_type==typ_ite_var ){
- bool success = false;
- if( d_child_counter<0 ){
- if( d_child_counter<-1 ){
- success = true;
- d_child_counter = -1;
- }
- }else{
- while( !success && d_child_counter>=0 ){
- //transition system based on d_child_counter
- if( d_n.getKind()==OR || d_n.getKind()==AND ){
- if( (d_n.getKind()==AND)==d_tgt ){
- //all children must match simultaneously
- if( getChild( d_child_counter )->getNextMatch( p, qi ) ){
- if( d_child_counter<(int)(getNumChildren()-1) ){
- d_child_counter++;
- Debug("qcf-match-debug") << " Reset child " << d_child_counter << " of " << d_n << std::endl;
- getChild( d_child_counter )->reset( p, d_tgt, qi );
- }else{
- success = true;
- }
- }else{
- //if( std::find( d_independent.begin(), d_independent.end(), d_child_counter )!=d_independent.end() ){
- // d_child_counter--;
- //}else{
- d_child_counter--;
- //}
- }
- }else{
- //one child must match
- if( !getChild( d_child_counter )->getNextMatch( p, qi ) ){
- if( d_child_counter<(int)(getNumChildren()-1) ){
- d_child_counter++;
- Debug("qcf-match-debug") << " Reset child " << d_child_counter << " of " << d_n << ", one match" << std::endl;
- getChild( d_child_counter )->reset( p, d_tgt, qi );
- }else{
- d_child_counter = -1;
- }
- }else{
- success = true;
- }
- }
- }else if( d_n.getKind()==IFF ){
- //construct match based on both children
- if( d_child_counter%2==0 ){
- if( getChild( 0 )->getNextMatch( p, qi ) ){
- d_child_counter++;
- getChild( 1 )->reset( p, d_child_counter==1, qi );
- }else{
- if( d_child_counter==0 ){
- d_child_counter = 2;
- getChild( 0 )->reset( p, !d_tgt, qi );
- }else{
- d_child_counter = -1;
- }
- }
- }
- if( d_child_counter>=0 && d_child_counter%2==1 ){
- if( getChild( 1 )->getNextMatch( p, qi ) ){
- success = true;
- }else{
- d_child_counter--;
- }
- }
- }else if( d_n.getKind()==ITE ){
- if( d_child_counter%2==0 ){
- int index1 = d_child_counter==4 ? 1 : 0;
- if( getChild( index1 )->getNextMatch( p, qi ) ){
- d_child_counter++;
- getChild( d_child_counter==5 ? 2 : (d_tgt==(d_child_counter==1) ? 1 : 2) )->reset( p, d_tgt, qi );
- }else{
- if( d_child_counter==4 || ( d_type==typ_ite_var && d_child_counter==2 ) ){
- d_child_counter = -1;
- }else{
- d_child_counter +=2;
- getChild( d_child_counter==2 ? 0 : 1 )->reset( p, d_child_counter==2 ? !d_tgt : d_tgt, qi );
- }
- }
- }
- if( d_child_counter>=0 && d_child_counter%2==1 ){
- int index2 = d_child_counter==5 ? 2 : (d_tgt==(d_child_counter==1) ? 1 : 2);
- if( getChild( index2 )->getNextMatch( p, qi ) ){
- success = true;
- }else{
- d_child_counter--;
- }
- }
- }else if( d_n.getKind()==FORALL ){
- if( getChild( d_child_counter )->getNextMatch( p, qi ) ){
- success = true;
- }else{
- d_child_counter = -1;
- }
- }
- }
- d_wasSet = success;
- Debug("qcf-match") << " ...finished construct match for " << d_n << ", success = " << success << std::endl;
- return success;
- }
- }
- Debug("qcf-match") << " ...already finished for " << d_n << std::endl;
- return false;
-}
-
-bool MatchGen::getExplanation( QuantConflictFind * p, QuantInfo * qi, std::vector< Node >& exp ) {
- if( d_type==typ_eq ){
- Node n[2];
- for( unsigned i=0; i<2; i++ ){
- Trace("qcf-explain") << "Explain term " << d_n[i] << "..." << std::endl;
- n[i] = getExplanationTerm( p, qi, d_n[i], exp );
- }
- Node eq = n[0].eqNode( n[1] );
- if( !d_tgt_orig ){
- eq = eq.negate();
- }
- exp.push_back( eq );
- Trace("qcf-explain") << "Explanation for " << d_n << " (tgt=" << d_tgt_orig << ") is " << eq << ", set = " << d_wasSet << std::endl;
- return true;
- }else if( d_type==typ_pred ){
- Trace("qcf-explain") << "Explain term " << d_n << "..." << std::endl;
- Node n = getExplanationTerm( p, qi, d_n, exp );
- if( !d_tgt_orig ){
- n = n.negate();
- }
- exp.push_back( n );
- Trace("qcf-explain") << "Explanation for " << d_n << " (tgt=" << d_tgt_orig << ") is " << n << ", set = " << d_wasSet << std::endl;
- return true;
- }else if( d_type==typ_formula ){
- Trace("qcf-explain") << "Explanation get for " << d_n << ", counter = " << d_child_counter << ", tgt = " << d_tgt_orig << ", set = " << d_wasSet << std::endl;
- if( d_n.getKind()==OR || d_n.getKind()==AND ){
- if( (d_n.getKind()==AND)==d_tgt ){
- for( unsigned i=0; i<getNumChildren(); i++ ){
- if( !getChild( i )->getExplanation( p, qi, exp ) ){
- return false;
- }
- }
- }else{
- return getChild( d_child_counter )->getExplanation( p, qi, exp );
- }
- }else if( d_n.getKind()==IFF ){
- for( unsigned i=0; i<2; i++ ){
- if( !getChild( i )->getExplanation( p, qi, exp ) ){
- return false;
- }
- }
- }else if( d_n.getKind()==ITE ){
- for( unsigned i=0; i<3; i++ ){
- bool isActive = ( ( i==0 && d_child_counter!=5 ) ||
- ( i==1 && d_child_counter!=( d_tgt ? 3 : 1 ) ) ||
- ( i==2 && d_child_counter!=( d_tgt ? 1 : 3 ) ) );
- if( isActive ){
- if( !getChild( i )->getExplanation( p, qi, exp ) ){
- return false;
- }
- }
- }
- }else{
- return false;
- }
- return true;
- }else{
- return false;
- }
-}
-
-Node MatchGen::getExplanationTerm( QuantConflictFind * p, QuantInfo * qi, Node t, std::vector< Node >& exp ) {
- Node v = qi->getCurrentExpValue( t );
- if( isHandledUfTerm( t ) ){
- for( unsigned i=0; i<t.getNumChildren(); i++ ){
- Node vi = getExplanationTerm( p, qi, t[i], exp );
- if( vi!=v[i] ){
- Node eq = vi.eqNode( v[i] );
- if( std::find( exp.begin(), exp.end(), eq )==exp.end() ){
- Trace("qcf-explain") << " add : " << eq << "." << std::endl;
- exp.push_back( eq );
- }
- }
- }
- }
- return v;
-}
-
-bool MatchGen::doMatching( QuantConflictFind * p, QuantInfo * qi ) {
- if( !d_qn.empty() ){
- if( d_qn[0]==NULL ){
- d_qn.clear();
- return true;
- }else{
- Assert( d_type==typ_var );
- Assert( d_qni_size>0 );
- bool invalidMatch;
- do {
- invalidMatch = false;
- Debug("qcf-match-debug") << " Do matching " << d_n << " " << d_qn.size() << " " << d_qni.size() << std::endl;
- if( d_qn.size()==d_qni.size()+1 ) {
- int index = (int)d_qni.size();
- //initialize
- TNode val;
- std::map< int, int >::iterator itv = d_qni_var_num.find( index );
- if( itv!=d_qni_var_num.end() ){
- //get the representative variable this variable is equal to
- int repVar = qi->getCurrentRepVar( itv->second );
- Debug("qcf-match-debug") << " Match " << index << " is a variable " << itv->second << ", which is repVar " << repVar << std::endl;
- //get the value the rep variable
- //std::map< int, TNode >::iterator itm = qi->d_match.find( repVar );
- if( !qi->d_match[repVar].isNull() ){
- val = qi->d_match[repVar];
- Debug("qcf-match-debug") << " Variable is already bound to " << val << std::endl;
- }else{
- //binding a variable
- d_qni_bound[index] = repVar;
- std::map< TNode, QcfNodeIndex >::iterator it = d_qn[index]->d_children.begin();
- if( it != d_qn[index]->d_children.end() ) {
- d_qni.push_back( it );
- //set the match
- if( qi->setMatch( p, d_qni_bound[index], it->first ) ){
- Debug("qcf-match-debug") << " Binding variable" << std::endl;
- if( d_qn.size()<d_qni_size ){
- d_qn.push_back( &it->second );
- }
- }else{
- Debug("qcf-match") << " Binding variable, currently fail." << std::endl;
- invalidMatch = true;
- }
- }else{
- Debug("qcf-match-debug") << " Binding variable, fail, no more variables to bind" << std::endl;
- d_qn.pop_back();
- }
- }
- }else{
- Debug("qcf-match-debug") << " Match " << index << " is ground term" << std::endl;
- Assert( d_qni_gterm.find( index )!=d_qni_gterm.end() );
- Assert( d_qni_gterm_rep.find( index )!=d_qni_gterm_rep.end() );
- val = d_qni_gterm_rep[index];
- Assert( !val.isNull() );
- }
- if( !val.isNull() ){
- //constrained by val
- std::map< TNode, QcfNodeIndex >::iterator it = d_qn[index]->d_children.find( val );
- if( it!=d_qn[index]->d_children.end() ){
- Debug("qcf-match-debug") << " Match" << std::endl;
- d_qni.push_back( it );
- if( d_qn.size()<d_qni_size ){
- d_qn.push_back( &it->second );
- }
- }else{
- Debug("qcf-match-debug") << " Failed to match" << std::endl;
- d_qn.pop_back();
- }
- }
- }else{
- Assert( d_qn.size()==d_qni.size() );
- int index = d_qni.size()-1;
- //increment if binding this variable
- bool success = false;
- std::map< int, int >::iterator itb = d_qni_bound.find( index );
- if( itb!=d_qni_bound.end() ){
- d_qni[index]++;
- if( d_qni[index]!=d_qn[index]->d_children.end() ){
- success = true;
- if( qi->setMatch( p, itb->second, d_qni[index]->first ) ){
- Debug("qcf-match-debug") << " Bind next variable" << std::endl;
- if( d_qn.size()<d_qni_size ){
- d_qn.push_back( &d_qni[index]->second );
- }
- }else{
- Debug("qcf-match-debug") << " Bind next variable, currently fail" << std::endl;
- invalidMatch = true;
- }
- }else{
- qi->d_match[ itb->second ] = TNode::null();
- qi->d_match_term[ itb->second ] = TNode::null();
- Debug("qcf-match-debug") << " Bind next variable, no more variables to bind" << std::endl;
- }
- }else{
- //TODO : if it equal to something else, also try that
- }
- //if not incrementing, move to next
- if( !success ){
- d_qn.pop_back();
- d_qni.pop_back();
- }
- }
- }while( ( !d_qn.empty() && d_qni.size()!=d_qni_size ) || invalidMatch );
- if( d_qni.size()==d_qni_size ){
- //Assert( !d_qni[d_qni.size()-1]->second.d_children.empty() );
- //Debug("qcf-match-debug") << " We matched " << d_qni[d_qni.size()-1]->second.d_children.begin()->first << std::endl;
- Assert( !d_qni[d_qni.size()-1]->second.d_children.empty() );
- TNode t = d_qni[d_qni.size()-1]->second.d_children.begin()->first;
- Debug("qcf-match-debug") << " " << d_n << " matched " << t << std::endl;
- qi->d_match_term[d_qni_var_num[0]] = t;
- //set the match terms
- for( std::map< int, int >::iterator it = d_qni_bound.begin(); it != d_qni_bound.end(); ++it ){
- Debug("qcf-match-debug") << " position " << it->first << " bounded " << it->second << " / " << qi->d_q[0].getNumChildren() << std::endl;
- //if( it->second<(int)qi->d_q[0].getNumChildren() ){ //if it is an actual variable, we are interested in knowing the actual term
- if( it->first>0 ){
- Assert( !qi->d_match[ it->second ].isNull() );
- Assert( p->areEqual( t[it->first-1], qi->d_match[ it->second ] ) );
- qi->d_match_term[it->second] = t[it->first-1];
- }
- //}
- }
- }
- }
- }
- return !d_qn.empty();
-}
-
-void MatchGen::debugPrintType( const char * c, short typ, bool isTrace ) {
- if( isTrace ){
- switch( typ ){
- case typ_invalid: Trace(c) << "invalid";break;
- case typ_ground: Trace(c) << "ground";break;
- case typ_eq: Trace(c) << "eq";break;
- case typ_pred: Trace(c) << "pred";break;
- case typ_formula: Trace(c) << "formula";break;
- case typ_var: Trace(c) << "var";break;
- case typ_ite_var: Trace(c) << "ite_var";break;
- case typ_bool_var: Trace(c) << "bool_var";break;
- }
- }else{
- switch( typ ){
- case typ_invalid: Debug(c) << "invalid";break;
- case typ_ground: Debug(c) << "ground";break;
- case typ_eq: Debug(c) << "eq";break;
- case typ_pred: Debug(c) << "pred";break;
- case typ_formula: Debug(c) << "formula";break;
- case typ_var: Debug(c) << "var";break;
- case typ_ite_var: Debug(c) << "ite_var";break;
- case typ_bool_var: Debug(c) << "bool_var";break;
- }
- }
-}
-
-void MatchGen::setInvalid() {
- d_type = typ_invalid;
- d_children.clear();
-}
-
-bool MatchGen::isHandledBoolConnective( TNode n ) {
- return n.getType().isBoolean() && ( n.getKind()==OR || n.getKind()==AND || n.getKind()==IFF || n.getKind()==ITE || n.getKind()==FORALL || n.getKind()==NOT );
-}
-
-bool MatchGen::isHandledUfTerm( TNode n ) {
- //return n.getKind()==APPLY_UF || n.getKind()==STORE || n.getKind()==SELECT ||
- // n.getKind()==APPLY_CONSTRUCTOR || n.getKind()==APPLY_SELECTOR_TOTAL || n.getKind()==APPLY_TESTER;
- return inst::Trigger::isAtomicTriggerKind( n.getKind() );
-}
-
-Node MatchGen::getOperator( QuantConflictFind * p, Node n ) {
- if( isHandledUfTerm( n ) ){
- return p->getQuantifiersEngine()->getTermDatabase()->getOperator( n );
- }else{
- return Node::null();
- }
-}
-
-bool MatchGen::isHandled( TNode n ) {
- if( n.getKind()!=BOUND_VARIABLE && n.hasBoundVar() ){
- if( !isHandledBoolConnective( n ) && !isHandledUfTerm( n ) && n.getKind()!=EQUAL && n.getKind()!=ITE ){
- return false;
- }
- for( unsigned i=0; i<n.getNumChildren(); i++ ){
- if( !isHandled( n[i] ) ){
- return false;
- }
- }
- }
- return true;
-}
-
-
-QuantConflictFind::QuantConflictFind( QuantifiersEngine * qe, context::Context* c ) :
-QuantifiersModule( qe ),
-d_c( c ),
-d_conflict( c, false ),
-d_qassert( c ) {
- d_fid_count = 0;
- d_true = NodeManager::currentNM()->mkConst<bool>(true);
- d_false = NodeManager::currentNM()->mkConst<bool>(false);
-}
-
-Node QuantConflictFind::mkEqNode( Node a, Node b ) {
- if( a.getType().isBoolean() ){
- return a.iffNode( b );
- }else{
- return a.eqNode( b );
- }
-}
-
-//-------------------------------------------------- registration
-
-void QuantConflictFind::registerQuantifier( Node q ) {
- if( !TermDb::isRewriteRule( q ) ){
- d_quants.push_back( q );
- d_quant_id[q] = d_quants.size();
- Trace("qcf-qregister") << "Register ";
- debugPrintQuant( "qcf-qregister", q );
- Trace("qcf-qregister") << " : " << q << std::endl;
- //make QcfNode structure
- Trace("qcf-qregister") << "- Get relevant equality/disequality pairs, calculate flattening..." << std::endl;
- d_qinfo[q].initialize( q, q[1] );
-
- //debug print
- Trace("qcf-qregister") << "- Flattened structure is :" << std::endl;
- Trace("qcf-qregister") << " ";
- debugPrintQuantBody( "qcf-qregister", q, q[1] );
- Trace("qcf-qregister") << std::endl;
- if( d_qinfo[q].d_vars.size()>q[0].getNumChildren() ){
- Trace("qcf-qregister") << " with additional constraints : " << std::endl;
- for( unsigned j=q[0].getNumChildren(); j<d_qinfo[q].d_vars.size(); j++ ){
- Trace("qcf-qregister") << " ?x" << j << " = ";
- debugPrintQuantBody( "qcf-qregister", q, d_qinfo[q].d_vars[j], false );
- Trace("qcf-qregister") << std::endl;
- }
- }
-
- Trace("qcf-qregister") << "Done registering quantifier." << std::endl;
- }
-}
-
-int QuantConflictFind::evaluate( Node n, bool pref, bool hasPref ) {
- int ret = 0;
- if( n.getKind()==EQUAL ){
- Node n1 = evaluateTerm( n[0] );
- Node n2 = evaluateTerm( n[1] );
- Debug("qcf-eval") << "Evaluate : Normalize " << n << " to " << n1 << " = " << n2 << std::endl;
- if( areEqual( n1, n2 ) ){
- ret = 1;
- }else if( areDisequal( n1, n2 ) ){
- ret = -1;
- }
- //else if( d_effort>QuantConflictFind::effort_conflict ){
- // ret = -1;
- //}
- }else if( MatchGen::isHandledUfTerm( n ) ){ //predicate
- Node nn = evaluateTerm( n );
- Debug("qcf-eval") << "Evaluate : Normalize " << nn << " to " << n << std::endl;
- if( areEqual( nn, d_true ) ){
- ret = 1;
- }else if( areEqual( nn, d_false ) ){
- ret = -1;
- }
- //else if( d_effort>QuantConflictFind::effort_conflict ){
- // ret = -1;
- //}
- }else if( n.getKind()==NOT ){
- return -evaluate( n[0] );
- }else if( n.getKind()==ITE ){
- int cev1 = evaluate( n[0] );
- int cevc[2] = { 0, 0 };
- for( unsigned i=0; i<2; i++ ){
- if( ( i==0 && cev1!=-1 ) || ( i==1 && cev1!=1 ) ){
- cevc[i] = evaluate( n[i+1] );
- if( cev1!=0 ){
- ret = cevc[i];
- break;
- }else if( cevc[i]==0 ){
- break;
- }
- }
- }
- if( ret==0 && cevc[0]!=0 && cevc[0]==cevc[1] ){
- ret = cevc[0];
- }
- }else if( n.getKind()==IFF ){
- int cev1 = evaluate( n[0] );
- if( cev1!=0 ){
- int cev2 = evaluate( n[1] );
- if( cev2!=0 ){
- ret = cev1==cev2 ? 1 : -1;
- }
- }
-
- }else{
- int ssval = 0;
- if( n.getKind()==OR ){
- ssval = 1;
- }else if( n.getKind()==AND ){
- ssval = -1;
- }
- bool isUnk = false;
- for( unsigned i=0; i<n.getNumChildren(); i++ ){
- int cev = evaluate( n[i] );
- if( cev==ssval ){
- ret = ssval;
- break;
- }else if( cev==0 ){
- isUnk = true;
- }
- }
- if( ret==0 && !isUnk ){
- ret = -ssval;
- }
- }
- Debug("qcf-eval") << "Evaluate " << n << " to " << ret << std::endl;
- return ret;
-}
-
-short QuantConflictFind::getMaxQcfEffort() {
- if( options::qcfMode()==QCF_CONFLICT_ONLY ){
- return effort_conflict;
- }else if( options::qcfMode()==QCF_PROP_EQ ){
- return effort_prop_eq;
- }else if( options::qcfMode()==QCF_MC ){
- return effort_mc;
- }else{
- return 0;
- }
-}
-
-bool QuantConflictFind::areMatchEqual( TNode n1, TNode n2 ) {
- //if( d_effort==QuantConflictFind::effort_mc ){
- // return n1==n2 || !areDisequal( n1, n2 );
- //}else{
- return n1==n2;
- //}
-}
-
-bool QuantConflictFind::areMatchDisequal( TNode n1, TNode n2 ) {
- //if( d_effort==QuantConflictFind::effort_conflict ){
- // return areDisequal( n1, n2 );
- //}else{
- return n1!=n2;
- //}
-}
-
-//-------------------------------------------------- handling assertions / eqc
-
-void QuantConflictFind::assertNode( Node q ) {
- if( !TermDb::isRewriteRule( q ) ){
- Trace("qcf-proc") << "QCF : assertQuantifier : ";
- debugPrintQuant("qcf-proc", q);
- Trace("qcf-proc") << std::endl;
- d_qassert.push_back( q );
- //set the eqRegistries that this depends on to true
- //for( std::map< EqRegistry *, bool >::iterator it = d_qinfo[q].d_rel_eqr.begin(); it != d_qinfo[q].d_rel_eqr.end(); ++it ){
- // it->first->d_active.set( true );
- //}
- }
-}
-
-eq::EqualityEngine * QuantConflictFind::getEqualityEngine() {
- //return ((uf::TheoryUF*)d_quantEngine->getTheoryEngine()->theoryOf( theory::THEORY_UF ))->getEqualityEngine();
- return d_quantEngine->getTheoryEngine()->getMasterEqualityEngine();
-}
-bool QuantConflictFind::areEqual( Node n1, Node n2 ) {
- return getEqualityEngine()->hasTerm( n1 ) && getEqualityEngine()->hasTerm( n2 ) && getEqualityEngine()->areEqual( n1,n2 );
-}
-bool QuantConflictFind::areDisequal( Node n1, Node n2 ) {
- return n1!=n2 && getEqualityEngine()->hasTerm( n1 ) && getEqualityEngine()->hasTerm( n2 ) && getEqualityEngine()->areDisequal( n1,n2, false );
-}
-Node QuantConflictFind::getRepresentative( Node n ) {
- if( getEqualityEngine()->hasTerm( n ) ){
- return getEqualityEngine()->getRepresentative( n );
- }else{
- return n;
- }
-}
-Node QuantConflictFind::evaluateTerm( Node n ) {
- if( MatchGen::isHandledUfTerm( n ) ){
- Node f = MatchGen::getOperator( this, n );
- Node nn;
- computeUfTerms( f );
- if( getEqualityEngine()->hasTerm( n ) ){
- computeArgReps( n );
- nn = d_uf_terms[f].existsTerm( n, d_arg_reps[n] );
- }else{
- std::vector< TNode > args;
- for( unsigned i=0; i<n.getNumChildren(); i++ ){
- Node c = evaluateTerm( n[i] );
- args.push_back( c );
- }
- nn = d_uf_terms[f].existsTerm( n, args );
- }
- if( !nn.isNull() ){
- Debug("qcf-eval") << "GT: Term " << nn << " for " << n << " hasTerm = " << getEqualityEngine()->hasTerm( n ) << std::endl;
- return getRepresentative( nn );
- }else{
- Debug("qcf-eval") << "GT: No term for " << n << " hasTerm = " << getEqualityEngine()->hasTerm( n ) << std::endl;
- return n;
- }
- }else if( n.getKind()==ITE ){
- int v = evaluate( n[0], false, false );
- if( v==1 ){
- return evaluateTerm( n[1] );
- }else if( v==-1 ){
- return evaluateTerm( n[2] );
- }
- }
- return getRepresentative( n );
-}
-
-/*
-QuantConflictFind::EqcInfo * QuantConflictFind::getEqcInfo( Node n, bool doCreate ) {
- std::map< Node, EqcInfo * >::iterator it2 = d_eqc_info.find( n );
- if( it2==d_eqc_info.end() ){
- if( doCreate ){
- EqcInfo * eqci = new EqcInfo( d_c );
- d_eqc_info[n] = eqci;
- return eqci;
- }else{
- return NULL;
- }
- }
- return it2->second;
-}
-*/
-
-QcfNodeIndex * QuantConflictFind::getQcfNodeIndex( Node eqc, Node f ) {
- computeUfTerms( f );
- std::map< TNode, QcfNodeIndex >::iterator itut = d_eqc_uf_terms.find( f );
- if( itut==d_eqc_uf_terms.end() ){
- return NULL;
- }else{
- if( eqc.isNull() ){
- return &itut->second;
- }else{
- std::map< TNode, QcfNodeIndex >::iterator itute = itut->second.d_children.find( eqc );
- if( itute!=itut->second.d_children.end() ){
- return &itute->second;
- }else{
- return NULL;
- }
- }
- }
-}
-
-QcfNodeIndex * QuantConflictFind::getQcfNodeIndex( Node f ) {
- computeUfTerms( f );
- std::map< TNode, QcfNodeIndex >::iterator itut = d_uf_terms.find( f );
- if( itut!=d_uf_terms.end() ){
- return &itut->second;
- }else{
- return NULL;
- }
-}
-
-/** new node */
-void QuantConflictFind::newEqClass( Node n ) {
- //Trace("qcf-proc-debug") << "QCF : newEqClass : " << n << std::endl;
- //Trace("qcf-proc2-debug") << "QCF : finished newEqClass : " << n << std::endl;
-}
-
-/** merge */
-void QuantConflictFind::merge( Node a, Node b ) {
- /*
- if( b.getKind()==EQUAL ){
- if( a==d_true ){
- //will merge anyways
- //merge( b[0], b[1] );
- }else if( a==d_false ){
- assertDisequal( b[0], b[1] );
- }
- }else{
- Trace("qcf-proc") << "QCF : merge : " << a << " " << b << std::endl;
- EqcInfo * eqc_b = getEqcInfo( b, false );
- EqcInfo * eqc_a = NULL;
- if( eqc_b ){
- eqc_a = getEqcInfo( a );
- //move disequalities of b into a
- for( NodeBoolMap::iterator it = eqc_b->d_diseq.begin(); it != eqc_b->d_diseq.end(); ++it ){
- if( (*it).second ){
- Node n = (*it).first;
- EqcInfo * eqc_n = getEqcInfo( n, false );
- Assert( eqc_n );
- if( !eqc_n->isDisequal( a ) ){
- Assert( !eqc_a->isDisequal( n ) );
- eqc_n->setDisequal( a );
- eqc_a->setDisequal( n );
- //setEqual( eqc_a, eqc_b, a, n, false );
- }
- eqc_n->setDisequal( b, false );
- }
- }
- ////move all previous EqcRegistry's regarding equalities within b
- //for( NodeBoolMap::iterator it = eqc_b->d_rel_eqr_e.begin(); it != eqc_b->d_rel_eqr_e.end(); ++it ){
- // if( (*it).second ){
- // eqc_a->d_rel_eqr_e[(*it).first] = true;
- // }
- //}
- }
- //process new equalities
- //setEqual( eqc_a, eqc_b, a, b, true );
- Trace("qcf-proc2") << "QCF : finished merge : " << a << " " << b << std::endl;
- }
- */
-}
-
-/** assert disequal */
-void QuantConflictFind::assertDisequal( Node a, Node b ) {
- /*
- a = getRepresentative( a );
- b = getRepresentative( b );
- Trace("qcf-proc") << "QCF : assert disequal : " << a << " " << b << std::endl;
- EqcInfo * eqc_a = getEqcInfo( a );
- EqcInfo * eqc_b = getEqcInfo( b );
- if( !eqc_a->isDisequal( b ) ){
- Assert( !eqc_b->isDisequal( a ) );
- eqc_b->setDisequal( a );
- eqc_a->setDisequal( b );
- //setEqual( eqc_a, eqc_b, a, b, false );
- }
- Trace("qcf-proc2") << "QCF : finished assert disequal : " << a << " " << b << std::endl;
- */
-}
-
-//-------------------------------------------------- check function
-
-void QuantConflictFind::reset_round( Theory::Effort level ) {
- d_needs_computeRelEqr = true;
-}
-
-/** check */
-void QuantConflictFind::check( Theory::Effort level ) {
- Trace("qcf-check") << "QCF : check : " << level << std::endl;
- if( d_conflict ){
- Trace("qcf-check2") << "QCF : finished check : already in conflict." << std::endl;
- if( level>=Theory::EFFORT_FULL ){
- Trace("qcf-warn") << "ALREADY IN CONFLICT? " << level << std::endl;
- //Assert( false );
- }
- }else{
- int addedLemmas = 0;
- if( d_performCheck ){
- ++(d_statistics.d_inst_rounds);
- double clSet = 0;
- int prevEt = 0;
- if( Trace.isOn("qcf-engine") ){
- prevEt = d_statistics.d_entailment_checks.getData();
- clSet = double(clock())/double(CLOCKS_PER_SEC);
- Trace("qcf-engine") << "---Conflict Find Engine Round, effort = " << level << "---" << std::endl;
- }
- computeRelevantEqr();
-
- //determine order for quantified formulas
- std::vector< Node > qorder;
- std::map< Node, bool > qassert;
- //mark which are asserted
- for( unsigned i=0; i<d_qassert.size(); i++ ){
- qassert[d_qassert[i]] = true;
- }
- //add which ones are specified in the order
- for( unsigned i=0; i<d_quant_order.size(); i++ ){
- Node n = d_quant_order[i];
- if( std::find( qorder.begin(), qorder.end(), n )==qorder.end() && qassert.find( n )!=qassert.end() ){
- qorder.push_back( n );
- }
- }
- d_quant_order.clear();
- d_quant_order.insert( d_quant_order.begin(), qorder.begin(), qorder.end() );
- //add remaining
- for( unsigned i=0; i<d_qassert.size(); i++ ){
- Node n = d_qassert[i];
- if( std::find( qorder.begin(), qorder.end(), n )==qorder.end() ){
- qorder.push_back( n );
- }
- }
-
- if( Trace.isOn("qcf-debug") ){
- Trace("qcf-debug") << std::endl;
- debugPrint("qcf-debug");
- Trace("qcf-debug") << std::endl;
- }
- short end_e = getMaxQcfEffort();
- for( short e = effort_conflict; e<=end_e; e++ ){
- d_effort = e;
- Trace("qcf-check") << "Checking quantified formulas at effort " << e << "..." << std::endl;
- for( unsigned j=0; j<qorder.size(); j++ ){
- Node q = qorder[j];
- QuantInfo * qi = &d_qinfo[q];
-
- Assert( d_qinfo.find( q )!=d_qinfo.end() );
- if( qi->d_mg->isValid() ){
- Trace("qcf-check") << "Check quantified formula ";
- debugPrintQuant("qcf-check", q);
- Trace("qcf-check") << " : " << q << "..." << std::endl;
-
- Trace("qcf-check-debug") << "Reset round..." << std::endl;
- qi->reset_round( this );
- //try to make a matches making the body false
- Trace("qcf-check-debug") << "Get next match..." << std::endl;
- while( qi->d_mg->getNextMatch( this, qi ) ){
- Trace("qcf-check") << "*** Produced match at effort " << e << " : " << std::endl;
- qi->debugPrintMatch("qcf-check");
- Trace("qcf-check") << std::endl;
- std::vector< int > assigned;
- if( !qi->isMatchSpurious( this ) ){
- if( qi->completeMatch( this, assigned ) ){
- /*
- if( options::qcfExp() && d_effort==effort_conflict ){
- std::vector< Node > exp;
- if( qi->d_mg->getExplanation( this, qi, exp ) ){
- Trace("qcf-check-exp") << "Base explanation is : " << std::endl;
- for( unsigned c=0; c<exp.size(); c++ ){
- Trace("qcf-check-exp") << " " << exp[c] << std::endl;
- }
- std::vector< TNode > c_exp;
- eq::EqualityEngine* ee = ((uf::TheoryUF*)d_quantEngine->getTheoryEngine()->theoryOf( THEORY_UF ))->getEqualityEngine() ;
- for( unsigned c=0; c<exp.size(); c++ ){
- bool pol = exp[c].getKind()!=NOT;
- TNode lit = pol ? exp[c] : exp[c][0];
- Trace("qcf-check-exp") << "Explain " << lit << ", polarity " << pol << std::endl;
- if( lit.getKind()==EQUAL ){
- if( !pol && !ee->areDisequal( lit[0], lit[1], true ) ){
- exit( 98 );
- }else if( pol && !ee->areEqual( lit[0], lit[1] ) ){
- exit( 99 );
- }
- ee->explainEquality( lit[0], lit[1], pol, c_exp );
- }else{
- if( !ee->areEqual( lit, pol ? d_true : d_false ) ){
- exit( pol ? 96 : 97 );
- }
- ee->explainPredicate( lit, pol, c_exp );
- }
- }
- std::vector< Node > c_lem;
- Trace("qcf-check-exp") << "Actual explanation is : " << std::endl;
- for( unsigned c=0; c<c_exp.size(); c++ ){
- Trace("qcf-check-exp") << " " << c_exp[c] << std::endl;
- Node ccc = c_exp[c].negate();
- if( std::find( c_lem.begin(), c_lem.end(), ccc )==c_lem.end() ){
- c_lem.push_back( ccc );
- }
- }
-
- c_lem.push_back( q.negate() );
- Node conf = NodeManager::currentNM()->mkNode( OR, c_lem );
- Trace("qcf-conflict") << "QCF conflict : " << conf << std::endl;
- d_quantEngine->addLemma( conf, false );
- d_conflict.set( true );
- ++(d_statistics.d_conflict_inst);
- ++addedLemmas;
- break;
- }
- }
- */
- std::vector< Node > terms;
- qi->getMatch( terms );
- if( !qi->isTConstraintSpurious( this, terms ) ){
- if( Debug.isOn("qcf-check-inst") ){
- //if( e==effort_conflict ){
- Node inst = d_quantEngine->getInstantiation( q, terms );
- Debug("qcf-check-inst") << "Check instantiation " << inst << "..." << std::endl;
- Assert( evaluate( inst )!=1 );
- Assert( evaluate( inst )==-1 || e>effort_conflict );
- //}
- }
- if( d_quantEngine->addInstantiation( q, terms, false ) ){
- Trace("qcf-check") << " ... Added instantiation" << std::endl;
- Trace("qcf-inst") << "*** Was from effort " << e << " : " << std::endl;
- qi->debugPrintMatch("qcf-inst");
- Trace("qcf-inst") << std::endl;
- ++addedLemmas;
- if( e==effort_conflict ){
- d_quant_order.insert( d_quant_order.begin(), q );
- d_conflict.set( true );
- ++(d_statistics.d_conflict_inst);
- break;
- }else if( e==effort_prop_eq ){
- ++(d_statistics.d_prop_inst);
- }
- }else{
- Trace("qcf-check") << " ... Failed to add instantiation" << std::endl;
- //Assert( false );
- }
- }
- //clean up assigned
- qi->revertMatch( assigned );
- d_tempCache.clear();
- }else{
- Trace("qcf-check") << " ... Spurious instantiation (cannot assign unassigned variables)" << std::endl;
- }
- }else{
- Trace("qcf-check") << " ... Spurious instantiation (match is inconsistent)" << std::endl;
- }
- }
- if( d_conflict ){
- break;
- }
- }
- }
- if( addedLemmas>0 ){
- d_quantEngine->flushLemmas();
- break;
- }
- }
- if( Trace.isOn("qcf-engine") ){
- double clSet2 = double(clock())/double(CLOCKS_PER_SEC);
- Trace("qcf-engine") << "Finished conflict find engine, time = " << (clSet2-clSet);
- if( addedLemmas>0 ){
- Trace("qcf-engine") << ", effort = " << ( d_effort==effort_conflict ? "conflict" : ( d_effort==effort_prop_eq ? "prop_eq" : "mc" ) );
- Trace("qcf-engine") << ", addedLemmas = " << addedLemmas;
- }
- Trace("qcf-engine") << std::endl;
- int currEt = d_statistics.d_entailment_checks.getData();
- if( currEt!=prevEt ){
- Trace("qcf-engine") << " Entailment checks = " << ( currEt - prevEt ) << std::endl;
- }
- }
- }
- Trace("qcf-check2") << "QCF : finished check : " << level << std::endl;
- }
-}
-
-bool QuantConflictFind::needsCheck( Theory::Effort level ) {
- d_performCheck = false;
- if( options::quantConflictFind() && !d_conflict ){
- if( level==Theory::EFFORT_LAST_CALL ){
- d_performCheck = options::qcfWhenMode()==QCF_WHEN_MODE_LAST_CALL;
- }else if( level==Theory::EFFORT_FULL ){
- d_performCheck = options::qcfWhenMode()==QCF_WHEN_MODE_DEFAULT;
- }else if( level==Theory::EFFORT_STANDARD ){
- d_performCheck = options::qcfWhenMode()==QCF_WHEN_MODE_STD;
- }
- }
- return d_performCheck;
-}
-
-void QuantConflictFind::computeRelevantEqr() {
- if( d_needs_computeRelEqr ){
- d_needs_computeRelEqr = false;
- Trace("qcf-check") << "Compute relevant equalities..." << std::endl;
- d_uf_terms.clear();
- d_eqc_uf_terms.clear();
- d_eqcs.clear();
- d_model_basis.clear();
- d_arg_reps.clear();
- //double clSet = 0;
- //if( Trace.isOn("qcf-opt") ){
- // clSet = double(clock())/double(CLOCKS_PER_SEC);
- //}
-
- //long nTermst = 0;
- //long nTerms = 0;
- //long nEqc = 0;
-
- //which nodes are irrelevant for disequality matches
- std::map< TNode, bool > irrelevant_dnode;
- //now, store matches
- eq::EqClassesIterator eqcs_i = eq::EqClassesIterator( getEqualityEngine() );
- while( !eqcs_i.isFinished() ){
- //nEqc++;
- Node r = (*eqcs_i);
- TypeNode rtn = r.getType();
- if( options::qcfMode()==QCF_MC ){
- std::map< TypeNode, std::vector< TNode > >::iterator itt = d_eqcs.find( rtn );
- if( itt==d_eqcs.end() ){
- Node mb = getQuantifiersEngine()->getTermDatabase()->getModelBasisTerm( rtn );
- if( !getEqualityEngine()->hasTerm( mb ) ){
- Trace("qcf-warn") << "WARNING: Model basis term does not exist!" << std::endl;
- Assert( false );
- }
- Node mbr = getRepresentative( mb );
- if( mbr!=r ){
- d_eqcs[rtn].push_back( mbr );
- }
- d_eqcs[rtn].push_back( r );
- d_model_basis[rtn] = mb;
- }else{
- itt->second.push_back( r );
- }
- }else{
- d_eqcs[rtn].push_back( r );
- }
- /*
- eq::EqClassIterator eqc_i = eq::EqClassIterator( r, getEqualityEngine() );
- while( !eqc_i.isFinished() ){
- TNode n = (*eqc_i);
- if( n.hasBoundVar() ){
- std::cout << "BAD TERM IN DB : " << n << std::endl;
- exit( 199 );
- }
- ++eqc_i;
- }
-
- */
-
- //if( r.getType().isInteger() ){
- // Trace("qcf-mv") << "Model value for eqc(" << r << ") : " << d_quantEngine->getValuation().getModelValue( r ) << std::endl;
- //}
- //EqcInfo * eqcir = getEqcInfo( r, false );
- //get relevant nodes that we are disequal from
- /*
- std::vector< Node > deqc;
- if( eqcir ){
- for( NodeBoolMap::iterator it = eqcir->d_diseq.begin(); it != eqcir->d_diseq.end(); ++it ){
- if( (*it).second ){
- //Node rd = (*it).first;
- //if( rd!=getRepresentative( rd ) ){
- // std::cout << "Bad rep!" << std::endl;
- // exit( 0 );
- //}
- deqc.push_back( (*it).first );
- }
- }
- }
- */
- //process disequalities
- /*
- eq::EqClassIterator eqc_i = eq::EqClassIterator( r, getEqualityEngine() );
- while( !eqc_i.isFinished() ){
- TNode n = (*eqc_i);
- if( n.getKind()!=EQUAL ){
- nTermst++;
- //node_to_rep[n] = r;
- //if( n.getNumChildren()>0 ){
- // if( n.getKind()!=APPLY_UF ){
- // std::cout << n.getKind() << " " << n.getOperator() << " " << n << std::endl;
- // }
- //}
- if( !quantifiers::TermDb::hasBoundVarAttr( n ) ){ //temporary
-
- bool isRedundant;
- std::map< TNode, std::vector< TNode > >::iterator it_na;
- TNode fn;
- if( MatchGen::isHandledUfTerm( n ) ){
- Node f = MatchGen::getOperator( this, n );
- computeArgReps( n );
- it_na = d_arg_reps.find( n );
- Assert( it_na!=d_arg_reps.end() );
- Node nadd = d_eqc_uf_terms[f].d_children[r].addTerm( n, d_arg_reps[n] );
- isRedundant = (nadd!=n);
- d_uf_terms[f].addTerm( n, d_arg_reps[n] );
- }else{
- isRedundant = false;
- }
- nTerms += isRedundant ? 0 : 1;
- }else{
- if( Debug.isOn("qcf-nground") ){
- Debug("qcf-nground") << "Non-ground term in eqc : " << n << std::endl;
- Assert( false );
- }
- }
- }
- ++eqc_i;
- }
- */
- ++eqcs_i;
- }
- /*
- if( Trace.isOn("qcf-opt") ){
- double clSet2 = double(clock())/double(CLOCKS_PER_SEC);
- Trace("qcf-opt") << "Compute rel eqc : " << std::endl;
- Trace("qcf-opt") << " " << nEqc << " equivalence classes. " << std::endl;
- Trace("qcf-opt") << " " << nTerms << " / " << nTermst << " terms." << std::endl;
- Trace("qcf-opt") << " Time : " << (clSet2-clSet) << std::endl;
- }
- */
- }
-}
-
-void QuantConflictFind::computeArgReps( TNode n ) {
- if( d_arg_reps.find( n )==d_arg_reps.end() ){
- Assert( MatchGen::isHandledUfTerm( n ) );
- for( unsigned j=0; j<n.getNumChildren(); j++ ){
- d_arg_reps[n].push_back( getRepresentative( n[j] ) );
- }
- }
-}
-
-void QuantConflictFind::computeUfTerms( TNode f ) {
- if( d_uf_terms.find( f )==d_uf_terms.end() ){
- d_uf_terms[f].clear();
- unsigned nt = d_quantEngine->getTermDatabase()->getNumGroundTerms( f );
- for( unsigned i=0; i<nt; i++ ){
- Node n = d_quantEngine->getTermDatabase()->d_op_map[f][i];
- if( getEqualityEngine()->hasTerm( n ) && !n.getAttribute(NoMatchAttribute()) ){
- Node r = getRepresentative( n );
- computeArgReps( n );
- d_eqc_uf_terms[f].d_children[r].addTerm( n, d_arg_reps[n] );
- d_uf_terms[f].addTerm( n, d_arg_reps[n] );
- }
- }
- }
-}
-
-//-------------------------------------------------- debugging
-
-
-void QuantConflictFind::debugPrint( const char * c ) {
- //print the equivalance classes
- Trace(c) << "----------EQ classes" << std::endl;
- eq::EqClassesIterator eqcs_i = eq::EqClassesIterator( getEqualityEngine() );
- while( !eqcs_i.isFinished() ){
- Node n = (*eqcs_i);
- //if( !n.getType().isInteger() ){
- Trace(c) << " - " << n << " : {";
- eq::EqClassIterator eqc_i = eq::EqClassIterator( n, getEqualityEngine() );
- bool pr = false;
- while( !eqc_i.isFinished() ){
- Node nn = (*eqc_i);
- if( nn.getKind()!=EQUAL && nn!=n ){
- Trace(c) << (pr ? "," : "" ) << " " << nn;
- pr = true;
- }
- ++eqc_i;
- }
- Trace(c) << (pr ? " " : "" ) << "}" << std::endl;
- /*
- EqcInfo * eqcn = getEqcInfo( n, false );
- if( eqcn ){
- Trace(c) << " DEQ : {";
- pr = false;
- for( NodeBoolMap::iterator it = eqcn->d_diseq.begin(); it != eqcn->d_diseq.end(); ++it ){
- if( (*it).second ){
- Trace(c) << (pr ? "," : "" ) << " " << (*it).first;
- pr = true;
- }
- }
- Trace(c) << (pr ? " " : "" ) << "}" << std::endl;
- }
- //}
- */
- ++eqcs_i;
- }
-}
-
-void QuantConflictFind::debugPrintQuant( const char * c, Node q ) {
- Trace(c) << "Q" << d_quant_id[q];
-}
-
-void QuantConflictFind::debugPrintQuantBody( const char * c, Node q, Node n, bool doVarNum ) {
- if( n.getNumChildren()==0 ){
- Trace(c) << n;
- }else if( doVarNum && d_qinfo[q].d_var_num.find( n )!=d_qinfo[q].d_var_num.end() ){
- Trace(c) << "?x" << d_qinfo[q].d_var_num[n];
- }else{
- Trace(c) << "(";
- if( n.getKind()==APPLY_UF ){
- Trace(c) << n.getOperator();
- }else{
- Trace(c) << n.getKind();
- }
- for( unsigned i=0; i<n.getNumChildren(); i++ ){
- Trace(c) << " ";
- debugPrintQuantBody( c, q, n[i] );
- }
- Trace(c) << ")";
- }
-}
-
-QuantConflictFind::Statistics::Statistics():
- d_inst_rounds("QuantConflictFind::Inst_Rounds", 0),
- d_conflict_inst("QuantConflictFind::Instantiations_Conflict_Find", 0 ),
- d_prop_inst("QuantConflictFind::Instantiations_Prop", 0 ),
- d_entailment_checks("QuantConflictFind::Entailment_Checks",0)
-{
- StatisticsRegistry::registerStat(&d_inst_rounds);
- StatisticsRegistry::registerStat(&d_conflict_inst);
- StatisticsRegistry::registerStat(&d_prop_inst);
- StatisticsRegistry::registerStat(&d_entailment_checks);
-}
-
-QuantConflictFind::Statistics::~Statistics(){
- StatisticsRegistry::unregisterStat(&d_inst_rounds);
- StatisticsRegistry::unregisterStat(&d_conflict_inst);
- StatisticsRegistry::unregisterStat(&d_prop_inst);
- StatisticsRegistry::unregisterStat(&d_entailment_checks);
-}
-
-TNode QuantConflictFind::getZero( Kind k ) {
- std::map< Kind, Node >::iterator it = d_zero.find( k );
- if( it==d_zero.end() ){
- Node nn;
- if( k==PLUS ){
- nn = NodeManager::currentNM()->mkConst( Rational(0) );
- }
- d_zero[k] = nn;
- return nn;
- }else{
- return it->second;
- }
-}
-
-
-}
+/********************* */
+/*! \file quant_conflict_find.cpp
+ ** \verbatim
+ ** Original author: Andrew Reynolds
+ ** Major contributors: none
+ ** Minor contributors (to current version): none
+ ** This file is part of the CVC4 project.
+ ** Copyright (c) 2009-2014 New York University and The University of Iowa
+ ** See the file COPYING in the top-level source directory for licensing
+ ** information.\endverbatim
+ **
+ ** \brief quant conflict find class
+ **
+ **/
+
+#include <vector>
+
+#include "theory/quantifiers/quant_conflict_find.h"
+#include "theory/quantifiers/quant_util.h"
+#include "theory/theory_engine.h"
+#include "theory/quantifiers/options.h"
+#include "theory/quantifiers/term_database.h"
+#include "theory/quantifiers/trigger.h"
+
+using namespace CVC4;
+using namespace CVC4::kind;
+using namespace CVC4::theory;
+using namespace CVC4::theory::quantifiers;
+using namespace std;
+
+namespace CVC4 {
+
+
+
+void QuantInfo::initialize( Node q, Node qn ) {
+ d_q = q;
+ for( unsigned i=0; i<q[0].getNumChildren(); i++ ){
+ d_match.push_back( TNode::null() );
+ d_match_term.push_back( TNode::null() );
+ }
+
+ //register the variables
+ for( unsigned i=0; i<q[0].getNumChildren(); i++ ){
+ d_var_num[q[0][i]] = i;
+ d_vars.push_back( q[0][i] );
+ }
+
+ registerNode( qn, true, true );
+
+
+ Trace("qcf-qregister") << "- Make match gen structure..." << std::endl;
+ d_mg = new MatchGen( this, qn );
+
+ if( d_mg->isValid() ){
+ /*
+ for( unsigned j=0; j<q[0].getNumChildren(); j++ ){
+ if( d_inMatchConstraint.find( q[0][j] )==d_inMatchConstraint.end() ){
+ Trace("qcf-invalid") << "QCF invalid : variable " << q[0][j] << " does not exist in a matching constraint." << std::endl;
+ d_mg->setInvalid();
+ break;
+ }
+ }
+ */
+ if( d_mg->isValid() ){
+ for( unsigned j=q[0].getNumChildren(); j<d_vars.size(); j++ ){
+ if( d_vars[j].getKind()!=BOUND_VARIABLE ){
+ d_var_mg[j] = NULL;
+ bool is_tsym = false;
+ if( !MatchGen::isHandledUfTerm( d_vars[j] ) && d_vars[j].getKind()!=ITE ){
+ is_tsym = true;
+ d_tsym_vars.push_back( j );
+ }
+ if( !is_tsym || options::qcfTConstraint() ){
+ d_var_mg[j] = new MatchGen( this, d_vars[j], true );
+ }
+ if( !d_var_mg[j] || !d_var_mg[j]->isValid() ){
+ Trace("qcf-invalid") << "QCF invalid : cannot match for " << d_vars[j] << std::endl;
+ d_mg->setInvalid();
+ break;
+ }else{
+ std::vector< int > bvars;
+ d_var_mg[j]->determineVariableOrder( this, bvars );
+ }
+ }
+ }
+ if( d_mg->isValid() ){
+ std::vector< int > bvars;
+ d_mg->determineVariableOrder( this, bvars );
+ }
+ }
+ }else{
+ Trace("qcf-invalid") << "QCF invalid : body of formula cannot be processed." << std::endl;
+ }
+ Trace("qcf-qregister-summary") << "QCF register : " << ( d_mg->isValid() ? "VALID " : "INVALID" ) << " : " << q << std::endl;
+}
+
+void QuantInfo::registerNode( Node n, bool hasPol, bool pol, bool beneathQuant ) {
+ Trace("qcf-qregister-debug2") << "Register : " << n << std::endl;
+ if( n.getKind()==FORALL ){
+ registerNode( n[1], hasPol, pol, true );
+ }else{
+ if( !MatchGen::isHandledBoolConnective( n ) ){
+ if( n.hasBoundVar() ){
+ //literals
+ if( n.getKind()==EQUAL ){
+ for( unsigned i=0; i<n.getNumChildren(); i++ ){
+ flatten( n[i], beneathQuant );
+ }
+ }else if( MatchGen::isHandledUfTerm( n ) ){
+ flatten( n, beneathQuant );
+ }else if( n.getKind()==ITE ){
+ for( unsigned i=1; i<=2; i++ ){
+ flatten( n[i], beneathQuant );
+ }
+ registerNode( n[0], false, pol, beneathQuant );
+ }else if( options::qcfTConstraint() ){
+ //a theory-specific predicate
+ for( unsigned i=0; i<n.getNumChildren(); i++ ){
+ flatten( n[i], beneathQuant );
+ }
+ }
+ }
+ }else{
+ for( unsigned i=0; i<n.getNumChildren(); i++ ){
+ bool newHasPol;
+ bool newPol;
+ QuantPhaseReq::getPolarity( n, i, hasPol, pol, newHasPol, newPol );
+ //QcfNode * qcfc = new QcfNode( d_c );
+ //qcfc->d_parent = qcf;
+ //qcf->d_child[i] = qcfc;
+ registerNode( n[i], newHasPol, newPol, beneathQuant );
+ }
+ }
+ }
+}
+
+void QuantInfo::flatten( Node n, bool beneathQuant ) {
+ Trace("qcf-qregister-debug2") << "Flatten : " << n << std::endl;
+ if( n.hasBoundVar() ){
+ if( n.getKind()==BOUND_VARIABLE ){
+ d_inMatchConstraint[n] = true;
+ }
+ //if( MatchGen::isHandledUfTerm( n ) || n.getKind()==ITE ){
+ if( d_var_num.find( n )==d_var_num.end() ){
+ Trace("qcf-qregister-debug2") << "Add FLATTEN VAR : " << n << std::endl;
+ d_var_num[n] = d_vars.size();
+ d_vars.push_back( n );
+ d_match.push_back( TNode::null() );
+ d_match_term.push_back( TNode::null() );
+ if( n.getKind()==ITE ){
+ registerNode( n, false, false );
+ }else{
+ for( unsigned i=0; i<n.getNumChildren(); i++ ){
+ flatten( n[i], beneathQuant );
+ }
+ }
+ }else{
+ Trace("qcf-qregister-debug2") << "...already processed" << std::endl;
+ }
+ }else{
+ Trace("qcf-qregister-debug2") << "...is ground." << std::endl;
+ }
+}
+
+
+void QuantInfo::reset_round( QuantConflictFind * p ) {
+ for( unsigned i=0; i<d_match.size(); i++ ){
+ d_match[i] = TNode::null();
+ d_match_term[i] = TNode::null();
+ }
+ d_curr_var_deq.clear();
+ d_tconstraints.clear();
+ //add built-in variable constraints
+ for( unsigned r=0; r<2; r++ ){
+ for( std::map< int, std::vector< Node > >::iterator it = d_var_constraint[r].begin();
+ it != d_var_constraint[r].end(); ++it ){
+ for( unsigned j=0; j<it->second.size(); j++ ){
+ Node rr = it->second[j];
+ if( !isVar( rr ) ){
+ rr = p->getRepresentative( rr );
+ }
+ if( addConstraint( p, it->first, rr, r==0 )==-1 ){
+ d_var_constraint[0].clear();
+ d_var_constraint[1].clear();
+ //quantified formula is actually equivalent to true
+ Trace("qcf-qregister") << "Quantifier is equivalent to true!!!" << std::endl;
+ d_mg->d_children.clear();
+ d_mg->d_n = NodeManager::currentNM()->mkConst( true );
+ d_mg->d_type = MatchGen::typ_ground;
+ return;
+ }
+ }
+ }
+ }
+ d_mg->reset_round( p );
+ for( std::map< int, MatchGen * >::iterator it = d_var_mg.begin(); it != d_var_mg.end(); ++it ){
+ it->second->reset_round( p );
+ }
+ //now, reset for matching
+ d_mg->reset( p, false, this );
+}
+
+int QuantInfo::getCurrentRepVar( int v ) {
+ if( v!=-1 && !d_match[v].isNull() ){
+ int vn = getVarNum( d_match[v] );
+ if( vn!=-1 ){
+ //int vr = getCurrentRepVar( vn );
+ //d_match[v] = d_vars[vr];
+ //return vr;
+ return getCurrentRepVar( vn );
+ }
+ }
+ return v;
+}
+
+TNode QuantInfo::getCurrentValue( TNode n ) {
+ int v = getVarNum( n );
+ if( v==-1 ){
+ return n;
+ }else{
+ if( d_match[v].isNull() ){
+ return n;
+ }else{
+ Assert( getVarNum( d_match[v] )!=v );
+ return getCurrentValue( d_match[v] );
+ }
+ }
+}
+
+TNode QuantInfo::getCurrentExpValue( TNode n ) {
+ int v = getVarNum( n );
+ if( v==-1 ){
+ return n;
+ }else{
+ if( d_match[v].isNull() ){
+ return n;
+ }else{
+ Assert( getVarNum( d_match[v] )!=v );
+ if( d_match_term[v].isNull() ){
+ return getCurrentValue( d_match[v] );
+ }else{
+ return d_match_term[v];
+ }
+ }
+ }
+}
+
+bool QuantInfo::getCurrentCanBeEqual( QuantConflictFind * p, int v, TNode n, bool chDiseq ) {
+ //check disequalities
+ std::map< int, std::map< TNode, int > >::iterator itd = d_curr_var_deq.find( v );
+ if( itd!=d_curr_var_deq.end() ){
+ for( std::map< TNode, int >::iterator it = itd->second.begin(); it != itd->second.end(); ++it ){
+ Node cv = getCurrentValue( it->first );
+ Debug("qcf-ccbe") << "compare " << cv << " " << n << std::endl;
+ if( cv==n ){
+ return false;
+ }else if( chDiseq && !isVar( n ) && !isVar( cv ) ){
+ //they must actually be disequal if we are looking for conflicts
+ if( !p->areDisequal( n, cv ) ){
+ //TODO : check for entailed disequal
+
+ return false;
+ }
+ }
+ }
+ }
+ return true;
+}
+
+int QuantInfo::addConstraint( QuantConflictFind * p, int v, TNode n, bool polarity ) {
+ v = getCurrentRepVar( v );
+ int vn = getVarNum( n );
+ vn = vn==-1 ? -1 : getCurrentRepVar( vn );
+ n = getCurrentValue( n );
+ return addConstraint( p, v, n, vn, polarity, false );
+}
+
+int QuantInfo::addConstraint( QuantConflictFind * p, int v, TNode n, int vn, bool polarity, bool doRemove ) {
+ //for handling equalities between variables, and disequalities involving variables
+ Debug("qcf-match-debug") << "- " << (doRemove ? "un" : "" ) << "constrain : " << v << " -> " << n << " (cv=" << getCurrentValue( n ) << ")";
+ Debug("qcf-match-debug") << ", (vn=" << vn << "), polarity = " << polarity << std::endl;
+ Assert( doRemove || n==getCurrentValue( n ) );
+ Assert( doRemove || v==getCurrentRepVar( v ) );
+ Assert( doRemove || vn==getCurrentRepVar( getVarNum( n ) ) );
+ if( polarity ){
+ if( vn!=v ){
+ if( doRemove ){
+ if( vn!=-1 ){
+ //if set to this in the opposite direction, clean up opposite instead
+ // std::map< int, TNode >::iterator itmn = d_match.find( vn );
+ if( d_match[vn]==d_vars[v] ){
+ return addConstraint( p, vn, d_vars[v], v, true, true );
+ }else{
+ //unsetting variables equal
+ std::map< int, std::map< TNode, int > >::iterator itd = d_curr_var_deq.find( vn );
+ if( itd!=d_curr_var_deq.end() ){
+ //remove disequalities owned by this
+ std::vector< TNode > remDeq;
+ for( std::map< TNode, int >::iterator it = itd->second.begin(); it != itd->second.end(); ++it ){
+ if( it->second==v ){
+ remDeq.push_back( it->first );
+ }
+ }
+ for( unsigned i=0; i<remDeq.size(); i++ ){
+ d_curr_var_deq[vn].erase( remDeq[i] );
+ }
+ }
+ }
+ }
+ d_match[v] = TNode::null();
+ return 1;
+ }else{
+ //std::map< int, TNode >::iterator itm = d_match.find( v );
+
+ if( vn!=-1 ){
+ Debug("qcf-match-debug") << " ...Variable bound to variable" << std::endl;
+ //std::map< int, TNode >::iterator itmn = d_match.find( vn );
+ if( d_match[v].isNull() ){
+ //setting variables equal
+ bool alreadySet = false;
+ if( !d_match[vn].isNull() ){
+ alreadySet = true;
+ Assert( !isVar( d_match[vn] ) );
+ }
+
+ //copy or check disequalities
+ std::map< int, std::map< TNode, int > >::iterator itd = d_curr_var_deq.find( v );
+ if( itd!=d_curr_var_deq.end() ){
+ for( std::map< TNode, int >::iterator it = itd->second.begin(); it != itd->second.end(); ++it ){
+ Node dv = getCurrentValue( it->first );
+ if( !alreadySet ){
+ if( d_curr_var_deq[vn].find( dv )==d_curr_var_deq[vn].end() ){
+ d_curr_var_deq[vn][dv] = v;
+ }
+ }else{
+ if( !p->areMatchDisequal( d_match[vn], dv ) ){
+ Debug("qcf-match-debug") << " -> fail, conflicting disequality" << std::endl;
+ return -1;
+ }
+ }
+ }
+ }
+ if( alreadySet ){
+ n = getCurrentValue( n );
+ }
+ }else{
+ if( d_match[vn].isNull() ){
+ Debug("qcf-match-debug") << " ...Reverse direction" << std::endl;
+ //set the opposite direction
+ return addConstraint( p, vn, d_vars[v], v, true, false );
+ }else{
+ Debug("qcf-match-debug") << " -> Both variables bound, compare" << std::endl;
+ //are they currently equal
+ return p->areMatchEqual( d_match[v], d_match[vn] ) ? 0 : -1;
+ }
+ }
+ }else{
+ Debug("qcf-match-debug") << " ...Variable bound to ground" << std::endl;
+ if( d_match[v].isNull() ){
+ }else{
+ //compare ground values
+ Debug("qcf-match-debug") << " -> Ground value, compare " << d_match[v] << " "<< n << std::endl;
+ return p->areMatchEqual( d_match[v], n ) ? 0 : -1;
+ }
+ }
+ if( setMatch( p, v, n ) ){
+ Debug("qcf-match-debug") << " -> success" << std::endl;
+ return 1;
+ }else{
+ Debug("qcf-match-debug") << " -> fail, conflicting disequality" << std::endl;
+ return -1;
+ }
+ }
+ }else{
+ Debug("qcf-match-debug") << " -> redundant, variable identity" << std::endl;
+ return 0;
+ }
+ }else{
+ if( vn==v ){
+ Debug("qcf-match-debug") << " -> fail, variable identity" << std::endl;
+ return -1;
+ }else{
+ if( doRemove ){
+ Assert( d_curr_var_deq[v].find( n )!=d_curr_var_deq[v].end() );
+ d_curr_var_deq[v].erase( n );
+ return 1;
+ }else{
+ if( d_curr_var_deq[v].find( n )==d_curr_var_deq[v].end() ){
+ //check if it respects equality
+ //std::map< int, TNode >::iterator itm = d_match.find( v );
+ if( !d_match[v].isNull() ){
+ TNode nv = getCurrentValue( n );
+ if( !p->areMatchDisequal( nv, d_match[v] ) ){
+ Debug("qcf-match-debug") << " -> fail, conflicting disequality" << std::endl;
+ return -1;
+ }
+ }
+ d_curr_var_deq[v][n] = v;
+ Debug("qcf-match-debug") << " -> success" << std::endl;
+ return 1;
+ }else{
+ Debug("qcf-match-debug") << " -> redundant disequality" << std::endl;
+ return 0;
+ }
+ }
+ }
+ }
+}
+
+bool QuantInfo::isConstrainedVar( int v ) {
+ if( d_curr_var_deq.find( v )!=d_curr_var_deq.end() && !d_curr_var_deq[v].empty() ){
+ return true;
+ }else{
+ Node vv = getVar( v );
+ //for( std::map< int, TNode >::iterator it = d_match.begin(); it != d_match.end(); ++it ){
+ for( unsigned i=0; i<d_match.size(); i++ ){
+ if( d_match[i]==vv ){
+ return true;
+ }
+ }
+ for( std::map< int, std::map< TNode, int > >::iterator it = d_curr_var_deq.begin(); it != d_curr_var_deq.end(); ++it ){
+ for( std::map< TNode, int >::iterator it2 = it->second.begin(); it2 != it->second.end(); ++it2 ){
+ if( it2->first==vv ){
+ return true;
+ }
+ }
+ }
+ return false;
+ }
+}
+
+bool QuantInfo::setMatch( QuantConflictFind * p, int v, TNode n ) {
+ if( getCurrentCanBeEqual( p, v, n ) ){
+ Debug("qcf-match-debug") << "-- bind : " << v << " -> " << n << ", checked " << d_curr_var_deq[v].size() << " disequalities" << std::endl;
+ d_match[v] = n;
+ return true;
+ }else{
+ return false;
+ }
+}
+
+bool QuantInfo::isMatchSpurious( QuantConflictFind * p ) {
+ for( int i=0; i<getNumVars(); i++ ){
+ //std::map< int, TNode >::iterator it = d_match.find( i );
+ if( !d_match[i].isNull() ){
+ if( !getCurrentCanBeEqual( p, i, d_match[i], p->d_effort==QuantConflictFind::effort_conflict ) ){
+ return true;
+ }
+ }
+ }
+ return false;
+}
+
+bool QuantInfo::isTConstraintSpurious( QuantConflictFind * p, std::vector< Node >& terms ) {
+ if( !d_tconstraints.empty() ){
+ //check constraints
+ for( std::map< Node, bool >::iterator it = d_tconstraints.begin(); it != d_tconstraints.end(); ++it ){
+ //apply substitution to the tconstraint
+ Node cons = it->first.substitute( p->getQuantifiersEngine()->getTermDatabase()->d_vars[d_q].begin(),
+ p->getQuantifiersEngine()->getTermDatabase()->d_vars[d_q].end(),
+ terms.begin(), terms.end() );
+ cons = it->second ? cons : cons.negate();
+ if( !entailmentTest( p, cons, p->d_effort==QuantConflictFind::effort_conflict ) ){
+ return true;
+ }
+ }
+ }
+ return false;
+}
+
+bool QuantInfo::entailmentTest( QuantConflictFind * p, Node lit, bool chEnt ) {
+ Trace("qcf-tconstraint-debug") << "Check : " << lit << std::endl;
+ Node rew = Rewriter::rewrite( lit );
+ if( rew==p->d_false ){
+ Trace("qcf-tconstraint-debug") << "...constraint " << lit << " is disentailed (rewrites to false)." << std::endl;
+ return false;
+ }else if( rew!=p->d_true ){
+ //if checking for conflicts, we must be sure that the constraint is entailed
+ if( chEnt ){
+ //check if it is entailed
+ Trace("qcf-tconstraint-debug") << "Check entailment of " << rew << "..." << std::endl;
+ std::pair<bool, Node> et = p->getQuantifiersEngine()->getTheoryEngine()->entailmentCheck(THEORY_OF_TYPE_BASED, rew );
+ ++(p->d_statistics.d_entailment_checks);
+ Trace("qcf-tconstraint-debug") << "ET result : " << et.first << " " << et.second << std::endl;
+ if( !et.first ){
+ Trace("qcf-tconstraint-debug") << "...cannot show entailment of " << rew << "." << std::endl;
+ return false;
+ }else{
+ return true;
+ }
+ }else{
+ Trace("qcf-tconstraint-debug") << "...does not need to be entailed." << std::endl;
+ return true;
+ }
+ }else{
+ Trace("qcf-tconstraint-debug") << "...rewrites to true." << std::endl;
+ return true;
+ }
+}
+
+bool QuantInfo::completeMatch( QuantConflictFind * p, std::vector< int >& assigned, bool doContinue ) {
+ //assign values for variables that were unassigned (usually not necessary, but handles corner cases)
+ bool doFail = false;
+ bool success = true;
+ if( doContinue ){
+ doFail = true;
+ success = false;
+ }else{
+ //solve for interpreted symbol matches
+ // this breaks the invariant that all introduced constraints are over existing terms
+ for( int i=(int)(d_tsym_vars.size()-1); i>=0; i-- ){
+ int index = d_tsym_vars[i];
+ TNode v = getCurrentValue( d_vars[index] );
+ int slv_v = -1;
+ if( v==d_vars[index] ){
+ slv_v = index;
+ }
+ Trace("qcf-tconstraint-debug") << "Solve " << d_vars[index] << " = " << v << " " << d_vars[index].getKind() << std::endl;
+ if( d_vars[index].getKind()==PLUS || d_vars[index].getKind()==MULT ){
+ Kind k = d_vars[index].getKind();
+ std::vector< TNode > children;
+ for( unsigned j=0; j<d_vars[index].getNumChildren(); j++ ){
+ int vn = getVarNum( d_vars[index][j] );
+ if( vn!=-1 ){
+ TNode vv = getCurrentValue( d_vars[index][j] );
+ if( vv==d_vars[index][j] ){
+ //we will assign this
+ if( slv_v==-1 ){
+ Trace("qcf-tconstraint-debug") << "...will solve for var #" << vn << std::endl;
+ slv_v = vn;
+ if( p->d_effort!=QuantConflictFind::effort_conflict ){
+ break;
+ }
+ }else{
+ Node z = p->getZero( k );
+ if( !z.isNull() ){
+ Trace("qcf-tconstraint-debug") << "...set " << d_vars[vn] << " = " << z << std::endl;
+ assigned.push_back( vn );
+ if( !setMatch( p, vn, z ) ){
+ success = false;
+ break;
+ }
+ }
+ }
+ }else{
+ Trace("qcf-tconstraint-debug") << "...sum value " << vv << std::endl;
+ children.push_back( vv );
+ }
+ }else{
+ Trace("qcf-tconstraint-debug") << "...sum " << d_vars[index][j] << std::endl;
+ children.push_back( d_vars[index][j] );
+ }
+ }
+ if( success ){
+ if( slv_v!=-1 ){
+ Node lhs;
+ if( children.empty() ){
+ lhs = p->getZero( k );
+ }else if( children.size()==1 ){
+ lhs = children[0];
+ }else{
+ lhs = NodeManager::currentNM()->mkNode( k, children );
+ }
+ Node sum;
+ if( v==d_vars[index] ){
+ sum = lhs;
+ }else{
+ if( p->d_effort==QuantConflictFind::effort_conflict ){
+ Kind kn = k;
+ if( d_vars[index].getKind()==PLUS ){
+ kn = MINUS;
+ }
+ if( kn!=k ){
+ sum = NodeManager::currentNM()->mkNode( kn, v, lhs );
+ }
+ }
+ }
+ if( !sum.isNull() ){
+ assigned.push_back( slv_v );
+ Trace("qcf-tconstraint-debug") << "...set " << d_vars[slv_v] << " = " << sum << std::endl;
+ if( !setMatch( p, slv_v, sum ) ){
+ success = false;
+ }
+ p->d_tempCache.push_back( sum );
+ }
+ }else{
+ //must show that constraint is met
+ Node sum = NodeManager::currentNM()->mkNode( k, children );
+ Node eq = sum.eqNode( v );
+ if( !entailmentTest( p, eq ) ){
+ success = false;
+ }
+ p->d_tempCache.push_back( sum );
+ }
+ }
+ }
+
+ if( !success ){
+ break;
+ }
+ }
+ if( success ){
+ //check what is left to assign
+ d_unassigned.clear();
+ d_unassigned_tn.clear();
+ std::vector< int > unassigned[2];
+ std::vector< TypeNode > unassigned_tn[2];
+ for( int i=0; i<getNumVars(); i++ ){
+ if( d_match[i].isNull() ){
+ int rindex = d_var_mg.find( i )==d_var_mg.end() ? 1 : 0;
+ unassigned[rindex].push_back( i );
+ unassigned_tn[rindex].push_back( getVar( i ).getType() );
+ assigned.push_back( i );
+ }
+ }
+ d_unassigned_nvar = unassigned[0].size();
+ for( unsigned i=0; i<2; i++ ){
+ d_unassigned.insert( d_unassigned.end(), unassigned[i].begin(), unassigned[i].end() );
+ d_unassigned_tn.insert( d_unassigned_tn.end(), unassigned_tn[i].begin(), unassigned_tn[i].end() );
+ }
+ d_una_eqc_count.clear();
+ d_una_index = 0;
+ }
+ }
+
+ if( !d_unassigned.empty() && ( success || doContinue ) ){
+ Trace("qcf-check") << "Assign to unassigned..." << std::endl;
+ do {
+ if( doFail ){
+ Trace("qcf-check-unassign") << "Failure, try again..." << std::endl;
+ }
+ bool invalidMatch = false;
+ while( ( d_una_index>=0 && (int)d_una_index<(int)d_unassigned.size() ) || invalidMatch || doFail ){
+ invalidMatch = false;
+ if( !doFail && d_una_index==(int)d_una_eqc_count.size() ){
+ //check if it has now been assigned
+ if( d_una_index<d_unassigned_nvar ){
+ if( !isConstrainedVar( d_unassigned[d_una_index] ) ){
+ d_una_eqc_count.push_back( -1 );
+ }else{
+ d_var_mg[ d_unassigned[d_una_index] ]->reset( p, true, this );
+ d_una_eqc_count.push_back( 0 );
+ }
+ }else{
+ d_una_eqc_count.push_back( 0 );
+ }
+ }else{
+ bool failed = false;
+ if( !doFail ){
+ if( d_una_index<d_unassigned_nvar ){
+ if( !isConstrainedVar( d_unassigned[d_una_index] ) ){
+ Trace("qcf-check-unassign") << "Succeeded, variable unconstrained at " << d_una_index << std::endl;
+ d_una_index++;
+ }else if( d_var_mg[d_unassigned[d_una_index]]->getNextMatch( p, this ) ){
+ Trace("qcf-check-unassign") << "Succeeded match with mg at " << d_una_index << std::endl;
+ d_una_index++;
+ }else{
+ failed = true;
+ Trace("qcf-check-unassign") << "Failed match with mg at " << d_una_index << std::endl;
+ }
+ }else{
+ Assert( doFail || d_una_index==(int)d_una_eqc_count.size()-1 );
+ if( d_una_eqc_count[d_una_index]<(int)p->d_eqcs[d_unassigned_tn[d_una_index]].size() ){
+ int currIndex = d_una_eqc_count[d_una_index];
+ d_una_eqc_count[d_una_index]++;
+ Trace("qcf-check-unassign") << d_unassigned[d_una_index] << "->" << p->d_eqcs[d_unassigned_tn[d_una_index]][currIndex] << std::endl;
+ if( setMatch( p, d_unassigned[d_una_index], p->d_eqcs[d_unassigned_tn[d_una_index]][currIndex] ) ){
+ d_match_term[d_unassigned[d_una_index]] = TNode::null();
+ Trace("qcf-check-unassign") << "Succeeded match " << d_una_index << std::endl;
+ d_una_index++;
+ }else{
+ Trace("qcf-check-unassign") << "Failed match " << d_una_index << std::endl;
+ invalidMatch = true;
+ }
+ }else{
+ failed = true;
+ Trace("qcf-check-unassign") << "No more matches " << d_una_index << std::endl;
+ }
+ }
+ }
+ if( doFail || failed ){
+ do{
+ if( !doFail ){
+ d_una_eqc_count.pop_back();
+ }else{
+ doFail = false;
+ }
+ d_una_index--;
+ }while( d_una_index>=0 && d_una_eqc_count[d_una_index]==-1 );
+ }
+ }
+ }
+ success = d_una_index>=0;
+ if( success ){
+ doFail = true;
+ Trace("qcf-check-unassign") << " Try: " << std::endl;
+ for( unsigned i=0; i<d_unassigned.size(); i++ ){
+ int ui = d_unassigned[i];
+ if( !d_match[ui].isNull() ){
+ Trace("qcf-check-unassign") << " Assigned #" << ui << " : " << d_vars[ui] << " -> " << d_match[ui] << std::endl;
+ }
+ }
+ }
+ }while( success && isMatchSpurious( p ) );
+ }
+ if( success ){
+ for( unsigned i=0; i<d_unassigned.size(); i++ ){
+ int ui = d_unassigned[i];
+ if( !d_match[ui].isNull() ){
+ Trace("qcf-check") << " Assigned #" << ui << " : " << d_vars[ui] << " -> " << d_match[ui] << std::endl;
+ }
+ }
+ return true;
+ }else{
+ for( unsigned i=0; i<assigned.size(); i++ ){
+ d_match[ assigned[i] ] = TNode::null();
+ }
+ assigned.clear();
+ return false;
+ }
+}
+
+void QuantInfo::getMatch( std::vector< Node >& terms ){
+ for( unsigned i=0; i<d_q[0].getNumChildren(); i++ ){
+ //Node cv = qi->getCurrentValue( qi->d_match[i] );
+ int repVar = getCurrentRepVar( i );
+ Node cv;
+ //std::map< int, TNode >::iterator itmt = qi->d_match_term.find( repVar );
+ if( !d_match_term[repVar].isNull() ){
+ cv = d_match_term[repVar];
+ }else{
+ cv = d_match[repVar];
+ }
+ Debug("qcf-check-inst") << "INST : " << i << " -> " << cv << ", from " << d_match[i] << std::endl;
+ terms.push_back( cv );
+ }
+}
+
+void QuantInfo::revertMatch( std::vector< int >& assigned ) {
+ for( unsigned i=0; i<assigned.size(); i++ ){
+ d_match[ assigned[i] ] = TNode::null();
+ }
+}
+
+void QuantInfo::debugPrintMatch( const char * c ) {
+ for( int i=0; i<getNumVars(); i++ ){
+ Trace(c) << " " << d_vars[i] << " -> ";
+ if( !d_match[i].isNull() ){
+ Trace(c) << d_match[i];
+ }else{
+ Trace(c) << "(unassigned) ";
+ }
+ if( !d_curr_var_deq[i].empty() ){
+ Trace(c) << ", DEQ{ ";
+ for( std::map< TNode, int >::iterator it = d_curr_var_deq[i].begin(); it != d_curr_var_deq[i].end(); ++it ){
+ Trace(c) << it->first << " ";
+ }
+ Trace(c) << "}";
+ }
+ if( !d_match_term[i].isNull() && d_match_term[i]!=d_match[i] ){
+ Trace(c) << ", EXP : " << d_match_term[i];
+ }
+ Trace(c) << std::endl;
+ }
+ if( !d_tconstraints.empty() ){
+ Trace(c) << "ADDITIONAL CONSTRAINTS : " << std::endl;
+ for( std::map< Node, bool >::iterator it = d_tconstraints.begin(); it != d_tconstraints.end(); ++it ){
+ Trace(c) << " " << it->first << " -> " << it->second << std::endl;
+ }
+ }
+}
+
+MatchGen::MatchGen( QuantInfo * qi, Node n, bool isVar ){
+ Trace("qcf-qregister-debug") << "Make match gen for " << n << ", isVar = " << isVar << std::endl;
+ std::vector< Node > qni_apps;
+ d_qni_size = 0;
+ if( isVar ){
+ Assert( qi->d_var_num.find( n )!=qi->d_var_num.end() );
+ if( n.getKind()==ITE ){
+ d_type = typ_ite_var;
+ d_type_not = false;
+ d_n = n;
+ d_children.push_back( MatchGen( qi, d_n[0] ) );
+ if( d_children[0].isValid() ){
+ d_type = typ_ite_var;
+ for( unsigned i=1; i<=2; i++ ){
+ Node nn = n.eqNode( n[i] );
+ d_children.push_back( MatchGen( qi, nn ) );
+ d_children[d_children.size()-1].d_qni_bound_except.push_back( 0 );
+ if( !d_children[d_children.size()-1].isValid() ){
+ setInvalid();
+ break;
+ }
+ }
+ }else{
+ d_type = typ_invalid;
+ }
+ }else{
+ d_type = isHandledUfTerm( n ) ? typ_var : typ_tsym;
+ d_qni_var_num[0] = qi->getVarNum( n );
+ d_qni_size++;
+ d_type_not = false;
+ d_n = n;
+ //Node f = getOperator( n );
+ for( unsigned j=0; j<d_n.getNumChildren(); j++ ){
+ Node nn = d_n[j];
+ Trace("qcf-qregister-debug") << " " << d_qni_size;
+ if( qi->isVar( nn ) ){
+ int v = qi->d_var_num[nn];
+ Trace("qcf-qregister-debug") << " is var #" << v << std::endl;
+ d_qni_var_num[d_qni_size] = v;
+ //qi->addFuncParent( v, f, j );
+ }else{
+ Trace("qcf-qregister-debug") << " is gterm " << nn << std::endl;
+ d_qni_gterm[d_qni_size] = nn;
+ }
+ d_qni_size++;
+ }
+ }
+ }else{
+ if( n.hasBoundVar() ){
+ d_type_not = false;
+ d_n = n;
+ if( d_n.getKind()==NOT ){
+ d_n = d_n[0];
+ d_type_not = !d_type_not;
+ }
+
+ if( isHandledBoolConnective( d_n ) ){
+ //non-literals
+ d_type = typ_formula;
+ for( unsigned i=0; i<d_n.getNumChildren(); i++ ){
+ if( d_n.getKind()!=FORALL || i==1 ){
+ d_children.push_back( MatchGen( qi, d_n[i], false ) );
+ if( !d_children[d_children.size()-1].isValid() ){
+ setInvalid();
+ break;
+ }
+ }
+ /*
+ else if( isTop && n.getKind()==OR && d_children[d_children.size()-1].d_type==typ_var_eq ){
+ Trace("qcf-qregister-debug") << "Remove child, make built-in constraint" << std::endl;
+ //if variable equality/disequality at top level, remove immediately
+ bool cIsNot = d_children[d_children.size()-1].d_type_not;
+ Node cn = d_children[d_children.size()-1].d_n;
+ Assert( cn.getKind()==EQUAL );
+ Assert( p->d_qinfo[q].isVar( cn[0] ) || p->d_qinfo[q].isVar( cn[1] ) );
+ //make it a built-in constraint instead
+ for( unsigned i=0; i<2; i++ ){
+ if( p->d_qinfo[q].isVar( cn[i] ) ){
+ int v = p->d_qinfo[q].getVarNum( cn[i] );
+ Node cno = cn[i==0 ? 1 : 0];
+ p->d_qinfo[q].d_var_constraint[ cIsNot ? 0 : 1 ][v].push_back( cno );
+ break;
+ }
+ }
+ d_children.pop_back();
+ }
+ */
+ }
+ }else{
+ d_type = typ_invalid;
+ //literals
+ if( isHandledUfTerm( d_n ) ){
+ Assert( qi->isVar( d_n ) );
+ d_type = typ_pred;
+ }else if( d_n.getKind()==BOUND_VARIABLE ){
+ Assert( d_n.getType().isBoolean() );
+ d_type = typ_bool_var;
+ }else if( d_n.getKind()==EQUAL || options::qcfTConstraint() ){
+ for( unsigned i=0; i<d_n.getNumChildren(); i++ ){
+ if( d_n[i].hasBoundVar() ){
+ if( !qi->isVar( d_n[i] ) ){
+ Trace("qcf-qregister-debug") << "ERROR : not var " << d_n[i] << std::endl;
+ }
+ Assert( qi->isVar( d_n[i] ) );
+ if( d_n.getKind()!=EQUAL && qi->isVar( d_n[i] ) ){
+ d_qni_var_num[i+1] = qi->d_var_num[d_n[i]];
+ }
+ }else{
+ d_qni_gterm[i] = d_n[i];
+ }
+ }
+ d_type = d_n.getKind()==EQUAL ? typ_eq : typ_tconstraint;
+ Trace("qcf-tconstraint") << "T-Constraint : " << d_n << std::endl;
+ }
+ }
+ }else{
+ //we will just evaluate
+ d_n = n;
+ d_type = typ_ground;
+ }
+ //if( d_type!=typ_invalid ){
+ //determine an efficient children ordering
+ //if( !d_children.empty() ){
+ //for( unsigned i=0; i<d_children.size(); i++ ){
+ // d_children_order.push_back( i );
+ //}
+ //if( !d_n.isNull() && ( d_n.getKind()==OR || d_n.getKind()==AND || d_n.getKind()==IFF ) ){
+ //sort based on the type of the constraint : ground comes first, then literals, then others
+ //MatchGenSort mgs;
+ //mgs.d_mg = this;
+ //std::sort( d_children_order.begin(), d_children_order.end(), mgs );
+ //}
+ //}
+ //}
+ }
+ Trace("qcf-qregister-debug") << "Done make match gen " << n << ", type = ";
+ debugPrintType( "qcf-qregister-debug", d_type, true );
+ Trace("qcf-qregister-debug") << std::endl;
+ //Assert( d_children.size()==d_children_order.size() );
+
+}
+
+void MatchGen::collectBoundVar( QuantInfo * qi, Node n, std::vector< int >& cbvars ) {
+ int v = qi->getVarNum( n );
+ if( v!=-1 && std::find( cbvars.begin(), cbvars.end(), v )==cbvars.end() ){
+ cbvars.push_back( v );
+ }
+ for( unsigned i=0; i<n.getNumChildren(); i++ ){
+ collectBoundVar( qi, n[i], cbvars );
+ }
+}
+
+void MatchGen::determineVariableOrder( QuantInfo * qi, std::vector< int >& bvars ) {
+ Trace("qcf-qregister-debug") << "Determine variable order " << d_n << std::endl;
+ bool isCom = d_type==typ_formula && ( d_n.getKind()==OR || d_n.getKind()==AND || d_n.getKind()==IFF );
+ std::map< int, std::vector< int > > c_to_vars;
+ std::map< int, std::vector< int > > vars_to_c;
+ std::map< int, int > vb_count;
+ std::map< int, int > vu_count;
+ std::vector< bool > assigned;
+ Trace("qcf-qregister-debug") << "Calculate bound variables..." << std::endl;
+ for( unsigned i=0; i<d_children.size(); i++ ){
+ collectBoundVar( qi, d_children[i].d_n, c_to_vars[i] );
+ assigned.push_back( false );
+ vb_count[i] = 0;
+ vu_count[i] = 0;
+ for( unsigned j=0; j<c_to_vars[i].size(); j++ ){
+ int v = c_to_vars[i][j];
+ vars_to_c[v].push_back( i );
+ if( std::find( bvars.begin(), bvars.end(), v )==bvars.end() ){
+ vu_count[i]++;
+ if( !isCom ){
+ bvars.push_back( v );
+ }
+ }else{
+ vb_count[i]++;
+ }
+ }
+ }
+ if( isCom ){
+ //children that bind the least number of unbound variables go first
+ do {
+ int min_score = -1;
+ int min_score_index = -1;
+ for( unsigned i=0; i<d_children.size(); i++ ){
+ if( !assigned[i] ){
+ int score = vu_count[i];
+ if( min_score==-1 || score<min_score ){
+ min_score = score;
+ min_score_index = i;
+ }
+ }
+ }
+ Trace("qcf-qregister-debug") << "...assign child " << min_score_index << "/" << d_children.size() << std::endl;
+ Assert( min_score_index!=-1 );
+ //add to children order
+ d_children_order.push_back( min_score_index );
+ assigned[min_score_index] = true;
+ //if( vb_count[min_score_index]==0 ){
+ // d_independent.push_back( min_score_index );
+ //}
+ //determine order internal to children
+ d_children[min_score_index].determineVariableOrder( qi, bvars );
+ Trace("qcf-qregister-debug") << "...bind variables" << std::endl;
+ //now, make it a bound variable
+ for( unsigned i=0; i<c_to_vars[min_score_index].size(); i++ ){
+ int v = c_to_vars[min_score_index][i];
+ if( std::find( bvars.begin(), bvars.end(), v )==bvars.end() ){
+ for( unsigned j=0; j<vars_to_c[v].size(); j++ ){
+ int vc = vars_to_c[v][j];
+ vu_count[vc]--;
+ vb_count[vc]++;
+ }
+ bvars.push_back( v );
+ }
+ }
+ Trace("qcf-qregister-debug") << "...done assign child " << min_score_index << std::endl;
+ }while( d_children_order.size()!=d_children.size() );
+ Trace("qcf-qregister-debug") << "Done assign variable ordering for " << d_n << std::endl;
+ }else{
+ for( unsigned i=0; i<d_children.size(); i++ ){
+ d_children_order.push_back( i );
+ d_children[i].determineVariableOrder( qi, bvars );
+ }
+ }
+}
+
+
+void MatchGen::reset_round( QuantConflictFind * p ) {
+ d_wasSet = false;
+ for( unsigned i=0; i<d_children.size(); i++ ){
+ d_children[i].reset_round( p );
+ }
+ for( std::map< int, TNode >::iterator it = d_qni_gterm.begin(); it != d_qni_gterm.end(); ++it ){
+ d_qni_gterm_rep[it->first] = p->getRepresentative( it->second );
+ }
+ if( d_type==typ_ground ){
+ int e = p->evaluate( d_n );
+ if( e==1 ){
+ d_ground_eval[0] = p->d_true;
+ }else if( e==-1 ){
+ d_ground_eval[0] = p->d_false;
+ }
+ }else if( d_type==typ_eq ){
+ for( unsigned i=0; i<d_n.getNumChildren(); i++ ){
+ if( !d_n[i].hasBoundVar() ){
+ d_ground_eval[i] = p->evaluateTerm( d_n[i] );
+ }
+ }
+ }
+ d_qni_bound_cons.clear();
+ d_qni_bound_cons_var.clear();
+ d_qni_bound.clear();
+}
+
+void MatchGen::reset( QuantConflictFind * p, bool tgt, QuantInfo * qi ) {
+ d_tgt = d_type_not ? !tgt : tgt;
+ Debug("qcf-match") << " Reset for : " << d_n << ", type : ";
+ debugPrintType( "qcf-match", d_type );
+ Debug("qcf-match") << ", tgt = " << d_tgt << ", children = " << d_children.size() << " " << d_children_order.size() << std::endl;
+ d_qn.clear();
+ d_qni.clear();
+ d_qni_bound.clear();
+ d_child_counter = -1;
+ d_tgt_orig = d_tgt;
+
+ //set up processing matches
+ if( d_type==typ_invalid ){
+ //do nothing
+ }else if( d_type==typ_ground ){
+ if( d_ground_eval[0]==( d_tgt ? p->d_true : p->d_false ) ){
+ d_child_counter = 0;
+ }
+ }else if( d_type==typ_bool_var ){
+ //get current value of the variable
+ TNode n = qi->getCurrentValue( d_n );
+ int vn = qi->getCurrentRepVar( qi->getVarNum( n ) );
+ if( vn==-1 ){
+ //evaluate the value, see if it is compatible
+ int e = p->evaluate( n );
+ if( ( e==1 && d_tgt ) || ( e==0 && !d_tgt ) ){
+ d_child_counter = 0;
+ }
+ }else{
+ //unassigned, set match to true/false
+ d_qni_bound[0] = vn;
+ qi->setMatch( p, vn, d_tgt ? p->d_true : p->d_false );
+ d_child_counter = 0;
+ }
+ if( d_child_counter==0 ){
+ d_qn.push_back( NULL );
+ }
+ }else if( d_type==typ_var ){
+ Assert( isHandledUfTerm( d_n ) );
+ Node f = getOperator( p, d_n );
+ Debug("qcf-match-debug") << " reset: Var will match operators of " << f << std::endl;
+ TermArgTrie * qni = p->getTermDatabase()->getTermArgTrie( Node::null(), f );
+ if( qni!=NULL ){
+ d_qn.push_back( qni );
+ }
+ d_matched_basis = false;
+ }else if( d_type==typ_tsym || d_type==typ_tconstraint ){
+ for( std::map< int, int >::iterator it = d_qni_var_num.begin(); it != d_qni_var_num.end(); ++it ){
+ int repVar = qi->getCurrentRepVar( it->second );
+ if( qi->d_match[repVar].isNull() ){
+ Debug("qcf-match-debug") << "Force matching on child #" << it->first << ", which is var #" << repVar << std::endl;
+ d_qni_bound[it->first] = repVar;
+ }
+ }
+ d_qn.push_back( NULL );
+ }else if( d_type==typ_pred || d_type==typ_eq ){
+ //add initial constraint
+ Node nn[2];
+ int vn[2];
+ if( d_type==typ_pred ){
+ nn[0] = qi->getCurrentValue( d_n );
+ vn[0] = qi->getCurrentRepVar( qi->getVarNum( nn[0] ) );
+ nn[1] = p->getRepresentative( d_tgt ? p->d_true : p->d_false );
+ vn[1] = -1;
+ d_tgt = true;
+ }else{
+ for( unsigned i=0; i<2; i++ ){
+ TNode nc;
+ std::map< int, TNode >::iterator it = d_qni_gterm_rep.find( i );
+ if( it!=d_qni_gterm_rep.end() ){
+ nc = it->second;
+ }else{
+ nc = d_n[i];
+ }
+ nn[i] = qi->getCurrentValue( nc );
+ vn[i] = qi->getCurrentRepVar( qi->getVarNum( nn[i] ) );
+ }
+ }
+ bool success;
+ if( vn[0]==-1 && vn[1]==-1 ){
+ //Trace("qcf-explain") << " reset : " << d_n << " check ground values " << nn[0] << " " << nn[1] << " (tgt=" << d_tgt << ")" << std::endl;
+ Debug("qcf-match-debug") << " reset: check ground values " << nn[0] << " " << nn[1] << " (" << d_tgt << ")" << std::endl;
+ //just compare values
+ if( d_tgt ){
+ success = p->areMatchEqual( nn[0], nn[1] );
+ }else{
+ if( p->d_effort==QuantConflictFind::effort_conflict ){
+ success = p->areDisequal( nn[0], nn[1] );
+ }else{
+ success = p->areMatchDisequal( nn[0], nn[1] );
+ }
+ }
+ }else{
+ //otherwise, add a constraint to a variable
+ if( vn[1]!=-1 && vn[0]==-1 ){
+ //swap
+ Node t = nn[1];
+ nn[1] = nn[0];
+ nn[0] = t;
+ vn[0] = vn[1];
+ vn[1] = -1;
+ }
+ Debug("qcf-match-debug") << " reset: add constraint " << vn[0] << " -> " << nn[1] << " (vn=" << vn[1] << ")" << std::endl;
+ //add some constraint
+ int addc = qi->addConstraint( p, vn[0], nn[1], vn[1], d_tgt, false );
+ success = addc!=-1;
+ //if successful and non-redundant, store that we need to cleanup this
+ if( addc==1 ){
+ //Trace("qcf-explain") << " reset: " << d_n << " add constraint " << vn[0] << " -> " << nn[1] << " (vn=" << vn[1] << ")" << ", d_tgt = " << d_tgt << std::endl;
+ for( unsigned i=0; i<2; i++ ){
+ if( vn[i]!=-1 && std::find( d_qni_bound_except.begin(), d_qni_bound_except.end(), i )==d_qni_bound_except.end() ){
+ d_qni_bound[vn[i]] = vn[i];
+ }
+ }
+ d_qni_bound_cons[vn[0]] = nn[1];
+ d_qni_bound_cons_var[vn[0]] = vn[1];
+ }
+ }
+ //if successful, we will bind values to variables
+ if( success ){
+ d_qn.push_back( NULL );
+ }
+ }else{
+ if( d_children.empty() ){
+ //add dummy
+ d_qn.push_back( NULL );
+ }else{
+ if( d_tgt && d_n.getKind()==FORALL ){
+ //do nothing
+ }else{
+ //reset the first child to d_tgt
+ d_child_counter = 0;
+ getChild( d_child_counter )->reset( p, d_tgt, qi );
+ }
+ }
+ }
+ d_binding = false;
+ d_wasSet = true;
+ Debug("qcf-match") << " reset: Finished reset for " << d_n << ", success = " << ( !d_qn.empty() || d_child_counter!=-1 ) << std::endl;
+}
+
+bool MatchGen::getNextMatch( QuantConflictFind * p, QuantInfo * qi ) {
+ Debug("qcf-match") << " Get next match for : " << d_n << ", type = ";
+ debugPrintType( "qcf-match", d_type );
+ Debug("qcf-match") << ", children = " << d_children.size() << ", binding = " << d_binding << std::endl;
+ if( d_type==typ_invalid || d_type==typ_ground ){
+ if( d_child_counter==0 ){
+ d_child_counter = -1;
+ return true;
+ }else{
+ d_wasSet = false;
+ return false;
+ }
+ }else if( d_type==typ_var || d_type==typ_eq || d_type==typ_pred || d_type==typ_bool_var || d_type==typ_tconstraint || d_type==typ_tsym ){
+ bool success = false;
+ bool terminate = false;
+ do {
+ bool doReset = false;
+ bool doFail = false;
+ if( !d_binding ){
+ if( doMatching( p, qi ) ){
+ Debug("qcf-match-debug") << " - Matching succeeded" << std::endl;
+ d_binding = true;
+ d_binding_it = d_qni_bound.begin();
+ doReset = true;
+ //for tconstraint, add constraint
+ if( d_type==typ_tconstraint ){
+ std::map< Node, bool >::iterator it = qi->d_tconstraints.find( d_n );
+ if( it==qi->d_tconstraints.end() ){
+ qi->d_tconstraints[d_n] = d_tgt;
+ //store that we added this constraint
+ d_qni_bound_cons[0] = d_n;
+ }else if( d_tgt!=it->second ){
+ success = false;
+ terminate = true;
+ }
+ }
+ }else{
+ Debug("qcf-match-debug") << " - Matching failed" << std::endl;
+ success = false;
+ terminate = true;
+ }
+ }else{
+ doFail = true;
+ }
+ if( d_binding ){
+ //also need to create match for each variable we bound
+ success = true;
+ Debug("qcf-match-debug") << " Produce matches for bound variables by " << d_n << ", type = ";
+ debugPrintType( "qcf-match-debug", d_type );
+ Debug("qcf-match-debug") << "..." << std::endl;
+
+ while( ( success && d_binding_it!=d_qni_bound.end() ) || doFail ){
+ std::map< int, MatchGen * >::iterator itm;
+ if( !doFail ){
+ Debug("qcf-match-debug") << " check variable " << d_binding_it->second << std::endl;
+ itm = qi->d_var_mg.find( d_binding_it->second );
+ }
+ if( doFail || ( d_binding_it->first!=0 && itm!=qi->d_var_mg.end() ) ){
+ Debug("qcf-match-debug") << " we had bound variable " << d_binding_it->second << ", reset = " << doReset << std::endl;
+ if( doReset ){
+ itm->second->reset( p, true, qi );
+ }
+ if( doFail || !itm->second->getNextMatch( p, qi ) ){
+ do {
+ if( d_binding_it==d_qni_bound.begin() ){
+ Debug("qcf-match-debug") << " failed." << std::endl;
+ success = false;
+ }else{
+ --d_binding_it;
+ Debug("qcf-match-debug") << " decrement..." << std::endl;
+ }
+ }while( success && ( d_binding_it->first==0 || qi->d_var_mg.find( d_binding_it->second )==qi->d_var_mg.end() ) );
+ doReset = false;
+ doFail = false;
+ }else{
+ Debug("qcf-match-debug") << " increment..." << std::endl;
+ ++d_binding_it;
+ doReset = true;
+ }
+ }else{
+ Debug("qcf-match-debug") << " skip..." << d_binding_it->second << std::endl;
+ ++d_binding_it;
+ doReset = true;
+ }
+ }
+ if( !success ){
+ d_binding = false;
+ }else{
+ terminate = true;
+ if( d_binding_it==d_qni_bound.begin() ){
+ d_binding = false;
+ }
+ }
+ }
+ }while( !terminate );
+ //if not successful, clean up the variables you bound
+ if( !success ){
+ if( d_type==typ_eq || d_type==typ_pred ){
+ //clean up the constraints you added
+ for( std::map< int, TNode >::iterator it = d_qni_bound_cons.begin(); it != d_qni_bound_cons.end(); ++it ){
+ if( !it->second.isNull() ){
+ Debug("qcf-match") << " Clean up bound var " << it->first << (d_tgt ? "!" : "") << " = " << it->second << std::endl;
+ std::map< int, int >::iterator itb = d_qni_bound_cons_var.find( it->first );
+ int vn = itb!=d_qni_bound_cons_var.end() ? itb->second : -1;
+ //Trace("qcf-explain") << " cleanup: " << d_n << " remove constraint " << it->first << " -> " << it->second << " (vn=" << vn << ")" << ", d_tgt = " << d_tgt << std::endl;
+ qi->addConstraint( p, it->first, it->second, vn, d_tgt, true );
+ }
+ }
+ d_qni_bound_cons.clear();
+ d_qni_bound_cons_var.clear();
+ d_qni_bound.clear();
+ }else{
+ //clean up the matches you set
+ for( std::map< int, int >::iterator it = d_qni_bound.begin(); it != d_qni_bound.end(); ++it ){
+ Debug("qcf-match") << " Clean up bound var " << it->second << std::endl;
+ Assert( it->second<qi->getNumVars() );
+ qi->d_match[ it->second ] = TNode::null();
+ qi->d_match_term[ it->second ] = TNode::null();
+ }
+ d_qni_bound.clear();
+ }
+ if( d_type==typ_tconstraint ){
+ //remove constraint if applicable
+ if( d_qni_bound_cons.find( 0 )!=d_qni_bound_cons.end() ){
+ qi->d_tconstraints.erase( d_n );
+ d_qni_bound_cons.clear();
+ }
+ }
+ /*
+ if( d_type==typ_var && p->d_effort==QuantConflictFind::effort_mc && !d_matched_basis ){
+ d_matched_basis = true;
+ Node f = getOperator( d_n );
+ TNode mbo = p->getQuantifiersEngine()->getTermDatabase()->getModelBasisOpTerm( f );
+ if( qi->setMatch( p, d_qni_var_num[0], mbo ) ){
+ success = true;
+ d_qni_bound[0] = d_qni_var_num[0];
+ }
+ }
+ */
+ }
+ Debug("qcf-match") << " ...finished matching for " << d_n << ", success = " << success << std::endl;
+ d_wasSet = success;
+ return success;
+ }else if( d_type==typ_formula || d_type==typ_ite_var ){
+ bool success = false;
+ if( d_child_counter<0 ){
+ if( d_child_counter<-1 ){
+ success = true;
+ d_child_counter = -1;
+ }
+ }else{
+ while( !success && d_child_counter>=0 ){
+ //transition system based on d_child_counter
+ if( d_n.getKind()==OR || d_n.getKind()==AND ){
+ if( (d_n.getKind()==AND)==d_tgt ){
+ //all children must match simultaneously
+ if( getChild( d_child_counter )->getNextMatch( p, qi ) ){
+ if( d_child_counter<(int)(getNumChildren()-1) ){
+ d_child_counter++;
+ Debug("qcf-match-debug") << " Reset child " << d_child_counter << " of " << d_n << std::endl;
+ getChild( d_child_counter )->reset( p, d_tgt, qi );
+ }else{
+ success = true;
+ }
+ }else{
+ //if( std::find( d_independent.begin(), d_independent.end(), d_child_counter )!=d_independent.end() ){
+ // d_child_counter--;
+ //}else{
+ d_child_counter--;
+ //}
+ }
+ }else{
+ //one child must match
+ if( !getChild( d_child_counter )->getNextMatch( p, qi ) ){
+ if( d_child_counter<(int)(getNumChildren()-1) ){
+ d_child_counter++;
+ Debug("qcf-match-debug") << " Reset child " << d_child_counter << " of " << d_n << ", one match" << std::endl;
+ getChild( d_child_counter )->reset( p, d_tgt, qi );
+ }else{
+ d_child_counter = -1;
+ }
+ }else{
+ success = true;
+ }
+ }
+ }else if( d_n.getKind()==IFF ){
+ //construct match based on both children
+ if( d_child_counter%2==0 ){
+ if( getChild( 0 )->getNextMatch( p, qi ) ){
+ d_child_counter++;
+ getChild( 1 )->reset( p, d_child_counter==1, qi );
+ }else{
+ if( d_child_counter==0 ){
+ d_child_counter = 2;
+ getChild( 0 )->reset( p, !d_tgt, qi );
+ }else{
+ d_child_counter = -1;
+ }
+ }
+ }
+ if( d_child_counter>=0 && d_child_counter%2==1 ){
+ if( getChild( 1 )->getNextMatch( p, qi ) ){
+ success = true;
+ }else{
+ d_child_counter--;
+ }
+ }
+ }else if( d_n.getKind()==ITE ){
+ if( d_child_counter%2==0 ){
+ int index1 = d_child_counter==4 ? 1 : 0;
+ if( getChild( index1 )->getNextMatch( p, qi ) ){
+ d_child_counter++;
+ getChild( d_child_counter==5 ? 2 : (d_tgt==(d_child_counter==1) ? 1 : 2) )->reset( p, d_tgt, qi );
+ }else{
+ if( d_child_counter==4 || ( d_type==typ_ite_var && d_child_counter==2 ) ){
+ d_child_counter = -1;
+ }else{
+ d_child_counter +=2;
+ getChild( d_child_counter==2 ? 0 : 1 )->reset( p, d_child_counter==2 ? !d_tgt : d_tgt, qi );
+ }
+ }
+ }
+ if( d_child_counter>=0 && d_child_counter%2==1 ){
+ int index2 = d_child_counter==5 ? 2 : (d_tgt==(d_child_counter==1) ? 1 : 2);
+ if( getChild( index2 )->getNextMatch( p, qi ) ){
+ success = true;
+ }else{
+ d_child_counter--;
+ }
+ }
+ }else if( d_n.getKind()==FORALL ){
+ if( getChild( d_child_counter )->getNextMatch( p, qi ) ){
+ success = true;
+ }else{
+ d_child_counter = -1;
+ }
+ }
+ }
+ d_wasSet = success;
+ Debug("qcf-match") << " ...finished construct match for " << d_n << ", success = " << success << std::endl;
+ return success;
+ }
+ }
+ Debug("qcf-match") << " ...already finished for " << d_n << std::endl;
+ return false;
+}
+
+bool MatchGen::getExplanation( QuantConflictFind * p, QuantInfo * qi, std::vector< Node >& exp ) {
+ if( d_type==typ_eq ){
+ Node n[2];
+ for( unsigned i=0; i<2; i++ ){
+ Trace("qcf-explain") << "Explain term " << d_n[i] << "..." << std::endl;
+ n[i] = getExplanationTerm( p, qi, d_n[i], exp );
+ }
+ Node eq = n[0].eqNode( n[1] );
+ if( !d_tgt_orig ){
+ eq = eq.negate();
+ }
+ exp.push_back( eq );
+ Trace("qcf-explain") << "Explanation for " << d_n << " (tgt=" << d_tgt_orig << ") is " << eq << ", set = " << d_wasSet << std::endl;
+ return true;
+ }else if( d_type==typ_pred ){
+ Trace("qcf-explain") << "Explain term " << d_n << "..." << std::endl;
+ Node n = getExplanationTerm( p, qi, d_n, exp );
+ if( !d_tgt_orig ){
+ n = n.negate();
+ }
+ exp.push_back( n );
+ Trace("qcf-explain") << "Explanation for " << d_n << " (tgt=" << d_tgt_orig << ") is " << n << ", set = " << d_wasSet << std::endl;
+ return true;
+ }else if( d_type==typ_formula ){
+ Trace("qcf-explain") << "Explanation get for " << d_n << ", counter = " << d_child_counter << ", tgt = " << d_tgt_orig << ", set = " << d_wasSet << std::endl;
+ if( d_n.getKind()==OR || d_n.getKind()==AND ){
+ if( (d_n.getKind()==AND)==d_tgt ){
+ for( unsigned i=0; i<getNumChildren(); i++ ){
+ if( !getChild( i )->getExplanation( p, qi, exp ) ){
+ return false;
+ }
+ }
+ }else{
+ return getChild( d_child_counter )->getExplanation( p, qi, exp );
+ }
+ }else if( d_n.getKind()==IFF ){
+ for( unsigned i=0; i<2; i++ ){
+ if( !getChild( i )->getExplanation( p, qi, exp ) ){
+ return false;
+ }
+ }
+ }else if( d_n.getKind()==ITE ){
+ for( unsigned i=0; i<3; i++ ){
+ bool isActive = ( ( i==0 && d_child_counter!=5 ) ||
+ ( i==1 && d_child_counter!=( d_tgt ? 3 : 1 ) ) ||
+ ( i==2 && d_child_counter!=( d_tgt ? 1 : 3 ) ) );
+ if( isActive ){
+ if( !getChild( i )->getExplanation( p, qi, exp ) ){
+ return false;
+ }
+ }
+ }
+ }else{
+ return false;
+ }
+ return true;
+ }else{
+ return false;
+ }
+}
+
+Node MatchGen::getExplanationTerm( QuantConflictFind * p, QuantInfo * qi, Node t, std::vector< Node >& exp ) {
+ Node v = qi->getCurrentExpValue( t );
+ if( isHandledUfTerm( t ) ){
+ for( unsigned i=0; i<t.getNumChildren(); i++ ){
+ Node vi = getExplanationTerm( p, qi, t[i], exp );
+ if( vi!=v[i] ){
+ Node eq = vi.eqNode( v[i] );
+ if( std::find( exp.begin(), exp.end(), eq )==exp.end() ){
+ Trace("qcf-explain") << " add : " << eq << "." << std::endl;
+ exp.push_back( eq );
+ }
+ }
+ }
+ }
+ return v;
+}
+
+bool MatchGen::doMatching( QuantConflictFind * p, QuantInfo * qi ) {
+ if( !d_qn.empty() ){
+ if( d_qn[0]==NULL ){
+ d_qn.clear();
+ return true;
+ }else{
+ Assert( d_type==typ_var );
+ Assert( d_qni_size>0 );
+ bool invalidMatch;
+ do {
+ invalidMatch = false;
+ Debug("qcf-match-debug") << " Do matching " << d_n << " " << d_qn.size() << " " << d_qni.size() << std::endl;
+ if( d_qn.size()==d_qni.size()+1 ) {
+ int index = (int)d_qni.size();
+ //initialize
+ TNode val;
+ std::map< int, int >::iterator itv = d_qni_var_num.find( index );
+ if( itv!=d_qni_var_num.end() ){
+ //get the representative variable this variable is equal to
+ int repVar = qi->getCurrentRepVar( itv->second );
+ Debug("qcf-match-debug") << " Match " << index << " is a variable " << itv->second << ", which is repVar " << repVar << std::endl;
+ //get the value the rep variable
+ //std::map< int, TNode >::iterator itm = qi->d_match.find( repVar );
+ if( !qi->d_match[repVar].isNull() ){
+ val = qi->d_match[repVar];
+ Debug("qcf-match-debug") << " Variable is already bound to " << val << std::endl;
+ }else{
+ //binding a variable
+ d_qni_bound[index] = repVar;
+ std::map< TNode, TermArgTrie >::iterator it = d_qn[index]->d_data.begin();
+ if( it != d_qn[index]->d_data.end() ) {
+ d_qni.push_back( it );
+ //set the match
+ if( qi->setMatch( p, d_qni_bound[index], it->first ) ){
+ Debug("qcf-match-debug") << " Binding variable" << std::endl;
+ if( d_qn.size()<d_qni_size ){
+ d_qn.push_back( &it->second );
+ }
+ }else{
+ Debug("qcf-match") << " Binding variable, currently fail." << std::endl;
+ invalidMatch = true;
+ }
+ }else{
+ Debug("qcf-match-debug") << " Binding variable, fail, no more variables to bind" << std::endl;
+ d_qn.pop_back();
+ }
+ }
+ }else{
+ Debug("qcf-match-debug") << " Match " << index << " is ground term" << std::endl;
+ Assert( d_qni_gterm.find( index )!=d_qni_gterm.end() );
+ Assert( d_qni_gterm_rep.find( index )!=d_qni_gterm_rep.end() );
+ val = d_qni_gterm_rep[index];
+ Assert( !val.isNull() );
+ }
+ if( !val.isNull() ){
+ //constrained by val
+ std::map< TNode, TermArgTrie >::iterator it = d_qn[index]->d_data.find( val );
+ if( it!=d_qn[index]->d_data.end() ){
+ Debug("qcf-match-debug") << " Match" << std::endl;
+ d_qni.push_back( it );
+ if( d_qn.size()<d_qni_size ){
+ d_qn.push_back( &it->second );
+ }
+ }else{
+ Debug("qcf-match-debug") << " Failed to match" << std::endl;
+ d_qn.pop_back();
+ }
+ }
+ }else{
+ Assert( d_qn.size()==d_qni.size() );
+ int index = d_qni.size()-1;
+ //increment if binding this variable
+ bool success = false;
+ std::map< int, int >::iterator itb = d_qni_bound.find( index );
+ if( itb!=d_qni_bound.end() ){
+ d_qni[index]++;
+ if( d_qni[index]!=d_qn[index]->d_data.end() ){
+ success = true;
+ if( qi->setMatch( p, itb->second, d_qni[index]->first ) ){
+ Debug("qcf-match-debug") << " Bind next variable" << std::endl;
+ if( d_qn.size()<d_qni_size ){
+ d_qn.push_back( &d_qni[index]->second );
+ }
+ }else{
+ Debug("qcf-match-debug") << " Bind next variable, currently fail" << std::endl;
+ invalidMatch = true;
+ }
+ }else{
+ qi->d_match[ itb->second ] = TNode::null();
+ qi->d_match_term[ itb->second ] = TNode::null();
+ Debug("qcf-match-debug") << " Bind next variable, no more variables to bind" << std::endl;
+ }
+ }else{
+ //TODO : if it equal to something else, also try that
+ }
+ //if not incrementing, move to next
+ if( !success ){
+ d_qn.pop_back();
+ d_qni.pop_back();
+ }
+ }
+ }while( ( !d_qn.empty() && d_qni.size()!=d_qni_size ) || invalidMatch );
+ if( d_qni.size()==d_qni_size ){
+ //Assert( !d_qni[d_qni.size()-1]->second.d_data.empty() );
+ //Debug("qcf-match-debug") << " We matched " << d_qni[d_qni.size()-1]->second.d_children.begin()->first << std::endl;
+ Assert( !d_qni[d_qni.size()-1]->second.d_data.empty() );
+ TNode t = d_qni[d_qni.size()-1]->second.d_data.begin()->first;
+ Debug("qcf-match-debug") << " " << d_n << " matched " << t << std::endl;
+ qi->d_match_term[d_qni_var_num[0]] = t;
+ //set the match terms
+ for( std::map< int, int >::iterator it = d_qni_bound.begin(); it != d_qni_bound.end(); ++it ){
+ Debug("qcf-match-debug") << " position " << it->first << " bounded " << it->second << " / " << qi->d_q[0].getNumChildren() << std::endl;
+ //if( it->second<(int)qi->d_q[0].getNumChildren() ){ //if it is an actual variable, we are interested in knowing the actual term
+ if( it->first>0 ){
+ Assert( !qi->d_match[ it->second ].isNull() );
+ Assert( p->areEqual( t[it->first-1], qi->d_match[ it->second ] ) );
+ qi->d_match_term[it->second] = t[it->first-1];
+ }
+ //}
+ }
+ }
+ }
+ }
+ return !d_qn.empty();
+}
+
+void MatchGen::debugPrintType( const char * c, short typ, bool isTrace ) {
+ if( isTrace ){
+ switch( typ ){
+ case typ_invalid: Trace(c) << "invalid";break;
+ case typ_ground: Trace(c) << "ground";break;
+ case typ_eq: Trace(c) << "eq";break;
+ case typ_pred: Trace(c) << "pred";break;
+ case typ_formula: Trace(c) << "formula";break;
+ case typ_var: Trace(c) << "var";break;
+ case typ_ite_var: Trace(c) << "ite_var";break;
+ case typ_bool_var: Trace(c) << "bool_var";break;
+ }
+ }else{
+ switch( typ ){
+ case typ_invalid: Debug(c) << "invalid";break;
+ case typ_ground: Debug(c) << "ground";break;
+ case typ_eq: Debug(c) << "eq";break;
+ case typ_pred: Debug(c) << "pred";break;
+ case typ_formula: Debug(c) << "formula";break;
+ case typ_var: Debug(c) << "var";break;
+ case typ_ite_var: Debug(c) << "ite_var";break;
+ case typ_bool_var: Debug(c) << "bool_var";break;
+ }
+ }
+}
+
+void MatchGen::setInvalid() {
+ d_type = typ_invalid;
+ d_children.clear();
+}
+
+bool MatchGen::isHandledBoolConnective( TNode n ) {
+ return n.getType().isBoolean() && ( n.getKind()==OR || n.getKind()==AND || n.getKind()==IFF || n.getKind()==ITE || n.getKind()==FORALL || n.getKind()==NOT );
+}
+
+bool MatchGen::isHandledUfTerm( TNode n ) {
+ //return n.getKind()==APPLY_UF || n.getKind()==STORE || n.getKind()==SELECT ||
+ // n.getKind()==APPLY_CONSTRUCTOR || n.getKind()==APPLY_SELECTOR_TOTAL || n.getKind()==APPLY_TESTER;
+ return inst::Trigger::isAtomicTriggerKind( n.getKind() );
+}
+
+Node MatchGen::getOperator( QuantConflictFind * p, Node n ) {
+ if( isHandledUfTerm( n ) ){
+ return p->getQuantifiersEngine()->getTermDatabase()->getOperator( n );
+ }else{
+ return Node::null();
+ }
+}
+
+bool MatchGen::isHandled( TNode n ) {
+ if( n.getKind()!=BOUND_VARIABLE && n.hasBoundVar() ){
+ if( !isHandledBoolConnective( n ) && !isHandledUfTerm( n ) && n.getKind()!=EQUAL && n.getKind()!=ITE ){
+ return false;
+ }
+ for( unsigned i=0; i<n.getNumChildren(); i++ ){
+ if( !isHandled( n[i] ) ){
+ return false;
+ }
+ }
+ }
+ return true;
+}
+
+
+QuantConflictFind::QuantConflictFind( QuantifiersEngine * qe, context::Context* c ) :
+QuantifiersModule( qe ),
+d_conflict( c, false ),
+d_qassert( c ) {
+ d_fid_count = 0;
+ d_true = NodeManager::currentNM()->mkConst<bool>(true);
+ d_false = NodeManager::currentNM()->mkConst<bool>(false);
+}
+
+Node QuantConflictFind::mkEqNode( Node a, Node b ) {
+ if( a.getType().isBoolean() ){
+ return a.iffNode( b );
+ }else{
+ return a.eqNode( b );
+ }
+}
+
+//-------------------------------------------------- registration
+
+void QuantConflictFind::registerQuantifier( Node q ) {
+ if( d_quantEngine->hasOwnership( q, this ) ){
+ d_quants.push_back( q );
+ d_quant_id[q] = d_quants.size();
+ Trace("qcf-qregister") << "Register ";
+ debugPrintQuant( "qcf-qregister", q );
+ Trace("qcf-qregister") << " : " << q << std::endl;
+ //make QcfNode structure
+ Trace("qcf-qregister") << "- Get relevant equality/disequality pairs, calculate flattening..." << std::endl;
+ d_qinfo[q].initialize( q, q[1] );
+
+ //debug print
+ Trace("qcf-qregister") << "- Flattened structure is :" << std::endl;
+ Trace("qcf-qregister") << " ";
+ debugPrintQuantBody( "qcf-qregister", q, q[1] );
+ Trace("qcf-qregister") << std::endl;
+ if( d_qinfo[q].d_vars.size()>q[0].getNumChildren() ){
+ Trace("qcf-qregister") << " with additional constraints : " << std::endl;
+ for( unsigned j=q[0].getNumChildren(); j<d_qinfo[q].d_vars.size(); j++ ){
+ Trace("qcf-qregister") << " ?x" << j << " = ";
+ debugPrintQuantBody( "qcf-qregister", q, d_qinfo[q].d_vars[j], false );
+ Trace("qcf-qregister") << std::endl;
+ }
+ }
+
+ Trace("qcf-qregister") << "Done registering quantifier." << std::endl;
+ }
+}
+
+int QuantConflictFind::evaluate( Node n, bool pref, bool hasPref ) {
+ int ret = 0;
+ if( n.getKind()==EQUAL ){
+ Node n1 = evaluateTerm( n[0] );
+ Node n2 = evaluateTerm( n[1] );
+ Debug("qcf-eval") << "Evaluate : Normalize " << n << " to " << n1 << " = " << n2 << std::endl;
+ if( areEqual( n1, n2 ) ){
+ ret = 1;
+ }else if( areDisequal( n1, n2 ) ){
+ ret = -1;
+ }
+ //else if( d_effort>QuantConflictFind::effort_conflict ){
+ // ret = -1;
+ //}
+ }else if( MatchGen::isHandledUfTerm( n ) ){ //predicate
+ Node nn = evaluateTerm( n );
+ Debug("qcf-eval") << "Evaluate : Normalize " << nn << " to " << n << std::endl;
+ if( areEqual( nn, d_true ) ){
+ ret = 1;
+ }else if( areEqual( nn, d_false ) ){
+ ret = -1;
+ }
+ //else if( d_effort>QuantConflictFind::effort_conflict ){
+ // ret = -1;
+ //}
+ }else if( n.getKind()==NOT ){
+ return -evaluate( n[0] );
+ }else if( n.getKind()==ITE ){
+ int cev1 = evaluate( n[0] );
+ int cevc[2] = { 0, 0 };
+ for( unsigned i=0; i<2; i++ ){
+ if( ( i==0 && cev1!=-1 ) || ( i==1 && cev1!=1 ) ){
+ cevc[i] = evaluate( n[i+1] );
+ if( cev1!=0 ){
+ ret = cevc[i];
+ break;
+ }else if( cevc[i]==0 ){
+ break;
+ }
+ }
+ }
+ if( ret==0 && cevc[0]!=0 && cevc[0]==cevc[1] ){
+ ret = cevc[0];
+ }
+ }else if( n.getKind()==IFF ){
+ int cev1 = evaluate( n[0] );
+ if( cev1!=0 ){
+ int cev2 = evaluate( n[1] );
+ if( cev2!=0 ){
+ ret = cev1==cev2 ? 1 : -1;
+ }
+ }
+
+ }else{
+ int ssval = 0;
+ if( n.getKind()==OR ){
+ ssval = 1;
+ }else if( n.getKind()==AND ){
+ ssval = -1;
+ }
+ bool isUnk = false;
+ for( unsigned i=0; i<n.getNumChildren(); i++ ){
+ int cev = evaluate( n[i] );
+ if( cev==ssval ){
+ ret = ssval;
+ break;
+ }else if( cev==0 ){
+ isUnk = true;
+ }
+ }
+ if( ret==0 && !isUnk ){
+ ret = -ssval;
+ }
+ }
+ Debug("qcf-eval") << "Evaluate " << n << " to " << ret << std::endl;
+ return ret;
+}
+
+short QuantConflictFind::getMaxQcfEffort() {
+ if( options::qcfMode()==QCF_CONFLICT_ONLY ){
+ return effort_conflict;
+ }else if( options::qcfMode()==QCF_PROP_EQ ){
+ return effort_prop_eq;
+ }else if( options::qcfMode()==QCF_MC ){
+ return effort_mc;
+ }else{
+ return 0;
+ }
+}
+
+bool QuantConflictFind::areMatchEqual( TNode n1, TNode n2 ) {
+ //if( d_effort==QuantConflictFind::effort_mc ){
+ // return n1==n2 || !areDisequal( n1, n2 );
+ //}else{
+ return n1==n2;
+ //}
+}
+
+bool QuantConflictFind::areMatchDisequal( TNode n1, TNode n2 ) {
+ //if( d_effort==QuantConflictFind::effort_conflict ){
+ // return areDisequal( n1, n2 );
+ //}else{
+ return n1!=n2;
+ //}
+}
+
+//-------------------------------------------------- handling assertions / eqc
+
+void QuantConflictFind::assertNode( Node q ) {
+ if( d_quantEngine->hasOwnership( q, this ) ){
+ Trace("qcf-proc") << "QCF : assertQuantifier : ";
+ debugPrintQuant("qcf-proc", q);
+ Trace("qcf-proc") << std::endl;
+ d_qassert.push_back( q );
+ //set the eqRegistries that this depends on to true
+ //for( std::map< EqRegistry *, bool >::iterator it = d_qinfo[q].d_rel_eqr.begin(); it != d_qinfo[q].d_rel_eqr.end(); ++it ){
+ // it->first->d_active.set( true );
+ //}
+ }
+}
+
+Node QuantConflictFind::evaluateTerm( Node n ) {
+ if( MatchGen::isHandledUfTerm( n ) ){
+ Node f = MatchGen::getOperator( this, n );
+ Node nn;
+ if( getEqualityEngine()->hasTerm( n ) ){
+ nn = getTermDatabase()->existsTerm( f, n );
+ }else{
+ std::vector< TNode > args;
+ for( unsigned i=0; i<n.getNumChildren(); i++ ){
+ Node c = evaluateTerm( n[i] );
+ args.push_back( c );
+ }
+ nn = getTermDatabase()->d_func_map_trie[f].existsTerm( args );
+ }
+ if( !nn.isNull() ){
+ Debug("qcf-eval") << "GT: Term " << nn << " for " << n << " hasTerm = " << getEqualityEngine()->hasTerm( n ) << std::endl;
+ return getRepresentative( nn );
+ }else{
+ Debug("qcf-eval") << "GT: No term for " << n << " hasTerm = " << getEqualityEngine()->hasTerm( n ) << std::endl;
+ return n;
+ }
+ }else if( n.getKind()==ITE ){
+ int v = evaluate( n[0], false, false );
+ if( v==1 ){
+ return evaluateTerm( n[1] );
+ }else if( v==-1 ){
+ return evaluateTerm( n[2] );
+ }
+ }
+ return getRepresentative( n );
+}
+
+/** new node */
+void QuantConflictFind::newEqClass( Node n ) {
+ //Trace("qcf-proc-debug") << "QCF : newEqClass : " << n << std::endl;
+ //Trace("qcf-proc2-debug") << "QCF : finished newEqClass : " << n << std::endl;
+}
+
+/** merge */
+void QuantConflictFind::merge( Node a, Node b ) {
+
+}
+
+/** assert disequal */
+void QuantConflictFind::assertDisequal( Node a, Node b ) {
+
+}
+
+//-------------------------------------------------- check function
+
+bool QuantConflictFind::needsCheck( Theory::Effort level ) {
+ bool performCheck = false;
+ if( options::quantConflictFind() && !d_conflict ){
+ if( level==Theory::EFFORT_LAST_CALL ){
+ performCheck = options::qcfWhenMode()==QCF_WHEN_MODE_LAST_CALL;
+ }else if( level==Theory::EFFORT_FULL ){
+ performCheck = options::qcfWhenMode()==QCF_WHEN_MODE_DEFAULT;
+ }else if( level==Theory::EFFORT_STANDARD ){
+ performCheck = options::qcfWhenMode()==QCF_WHEN_MODE_STD;
+ }
+ }
+ return performCheck;
+}
+
+void QuantConflictFind::reset_round( Theory::Effort level ) {
+ d_needs_computeRelEqr = true;
+}
+
+/** check */
+void QuantConflictFind::check( Theory::Effort level, unsigned quant_e ) {
+ if( quant_e==QuantifiersEngine::QEFFORT_CONFLICT ){
+ Trace("qcf-check") << "QCF : check : " << level << std::endl;
+ if( d_conflict ){
+ Trace("qcf-check2") << "QCF : finished check : already in conflict." << std::endl;
+ if( level>=Theory::EFFORT_FULL ){
+ Trace("qcf-warn") << "ALREADY IN CONFLICT? " << level << std::endl;
+ //Assert( false );
+ }
+ }else{
+ int addedLemmas = 0;
+ ++(d_statistics.d_inst_rounds);
+ double clSet = 0;
+ int prevEt = 0;
+ if( Trace.isOn("qcf-engine") ){
+ prevEt = d_statistics.d_entailment_checks.getData();
+ clSet = double(clock())/double(CLOCKS_PER_SEC);
+ Trace("qcf-engine") << "---Conflict Find Engine Round, effort = " << level << "---" << std::endl;
+ }
+ computeRelevantEqr();
+
+ //determine order for quantified formulas
+ std::vector< Node > qorder;
+ std::map< Node, bool > qassert;
+ //mark which are asserted
+ for( unsigned i=0; i<d_qassert.size(); i++ ){
+ qassert[d_qassert[i]] = true;
+ }
+ //add which ones are specified in the order
+ for( unsigned i=0; i<d_quant_order.size(); i++ ){
+ Node n = d_quant_order[i];
+ if( std::find( qorder.begin(), qorder.end(), n )==qorder.end() && qassert.find( n )!=qassert.end() ){
+ qorder.push_back( n );
+ }
+ }
+ d_quant_order.clear();
+ d_quant_order.insert( d_quant_order.begin(), qorder.begin(), qorder.end() );
+ //add remaining
+ for( unsigned i=0; i<d_qassert.size(); i++ ){
+ Node n = d_qassert[i];
+ if( std::find( qorder.begin(), qorder.end(), n )==qorder.end() ){
+ qorder.push_back( n );
+ }
+ }
+
+ if( Trace.isOn("qcf-debug") ){
+ Trace("qcf-debug") << std::endl;
+ debugPrint("qcf-debug");
+ Trace("qcf-debug") << std::endl;
+ }
+ short end_e = getMaxQcfEffort();
+ for( short e = effort_conflict; e<=end_e; e++ ){
+ d_effort = e;
+ Trace("qcf-check") << "Checking quantified formulas at effort " << e << "..." << std::endl;
+ for( unsigned j=0; j<qorder.size(); j++ ){
+ Node q = qorder[j];
+ QuantInfo * qi = &d_qinfo[q];
+
+ Assert( d_qinfo.find( q )!=d_qinfo.end() );
+ if( qi->d_mg->isValid() ){
+ Trace("qcf-check") << "Check quantified formula ";
+ debugPrintQuant("qcf-check", q);
+ Trace("qcf-check") << " : " << q << "..." << std::endl;
+
+ Trace("qcf-check-debug") << "Reset round..." << std::endl;
+ qi->reset_round( this );
+ //try to make a matches making the body false
+ Trace("qcf-check-debug") << "Get next match..." << std::endl;
+ while( qi->d_mg->getNextMatch( this, qi ) ){
+ Trace("qcf-inst") << "*** Produced match at effort " << e << " : " << std::endl;
+ qi->debugPrintMatch("qcf-inst");
+ Trace("qcf-inst") << std::endl;
+ std::vector< int > assigned;
+ if( !qi->isMatchSpurious( this ) ){
+ if( qi->completeMatch( this, assigned ) ){
+ std::vector< Node > terms;
+ qi->getMatch( terms );
+ if( !qi->isTConstraintSpurious( this, terms ) ){
+ if( Debug.isOn("qcf-check-inst") ){
+ //if( e==effort_conflict ){
+ Node inst = d_quantEngine->getInstantiation( q, terms );
+ Debug("qcf-check-inst") << "Check instantiation " << inst << "..." << std::endl;
+ Assert( evaluate( inst )!=1 );
+ Assert( evaluate( inst )==-1 || e>effort_conflict );
+ //}
+ }
+ if( d_quantEngine->addInstantiation( q, terms, false ) ){
+ Trace("qcf-check") << " ... Added instantiation" << std::endl;
+ Trace("qcf-inst") << "*** Was from effort " << e << " : " << std::endl;
+ qi->debugPrintMatch("qcf-inst");
+ Trace("qcf-inst") << std::endl;
+ ++addedLemmas;
+ if( e==effort_conflict ){
+ d_quant_order.insert( d_quant_order.begin(), q );
+ d_conflict.set( true );
+ ++(d_statistics.d_conflict_inst);
+ break;
+ }else if( e==effort_prop_eq ){
+ ++(d_statistics.d_prop_inst);
+ }
+ }else{
+ Trace("qcf-inst") << " ... Failed to add instantiation" << std::endl;
+ //Assert( false );
+ }
+ }
+ //clean up assigned
+ qi->revertMatch( assigned );
+ d_tempCache.clear();
+ }else{
+ Trace("qcf-inst") << " ... Spurious instantiation (cannot assign unassigned variables)" << std::endl;
+ }
+ }else{
+ Trace("qcf-inst") << " ... Spurious instantiation (match is inconsistent)" << std::endl;
+ }
+ }
+ if( d_conflict ){
+ break;
+ }
+ }
+ }
+ if( addedLemmas>0 ){
+ break;
+ }
+ }
+ if( Trace.isOn("qcf-engine") ){
+ double clSet2 = double(clock())/double(CLOCKS_PER_SEC);
+ Trace("qcf-engine") << "Finished conflict find engine, time = " << (clSet2-clSet);
+ if( addedLemmas>0 ){
+ Trace("qcf-engine") << ", effort = " << ( d_effort==effort_conflict ? "conflict" : ( d_effort==effort_prop_eq ? "prop_eq" : "mc" ) );
+ Trace("qcf-engine") << ", addedLemmas = " << addedLemmas;
+ }
+ Trace("qcf-engine") << std::endl;
+ int currEt = d_statistics.d_entailment_checks.getData();
+ if( currEt!=prevEt ){
+ Trace("qcf-engine") << " Entailment checks = " << ( currEt - prevEt ) << std::endl;
+ }
+ }
+ Trace("qcf-check2") << "QCF : finished check : " << level << std::endl;
+ }
+ }
+}
+
+void QuantConflictFind::computeRelevantEqr() {
+ if( d_needs_computeRelEqr ){
+ d_needs_computeRelEqr = false;
+ Trace("qcf-check") << "Compute relevant equalities..." << std::endl;
+ //d_uf_terms.clear();
+ //d_eqc_uf_terms.clear();
+ d_eqcs.clear();
+ d_model_basis.clear();
+ //d_arg_reps.clear();
+ //double clSet = 0;
+ //if( Trace.isOn("qcf-opt") ){
+ // clSet = double(clock())/double(CLOCKS_PER_SEC);
+ //}
+
+ //long nTermst = 0;
+ //long nTerms = 0;
+ //long nEqc = 0;
+
+ //which nodes are irrelevant for disequality matches
+ std::map< TNode, bool > irrelevant_dnode;
+ //now, store matches
+ eq::EqClassesIterator eqcs_i = eq::EqClassesIterator( getEqualityEngine() );
+ while( !eqcs_i.isFinished() ){
+ //nEqc++;
+ Node r = (*eqcs_i);
+ TypeNode rtn = r.getType();
+ if( options::qcfMode()==QCF_MC ){
+ std::map< TypeNode, std::vector< TNode > >::iterator itt = d_eqcs.find( rtn );
+ if( itt==d_eqcs.end() ){
+ Node mb = getQuantifiersEngine()->getTermDatabase()->getModelBasisTerm( rtn );
+ if( !getEqualityEngine()->hasTerm( mb ) ){
+ Trace("qcf-warn") << "WARNING: Model basis term does not exist!" << std::endl;
+ Assert( false );
+ }
+ Node mbr = getRepresentative( mb );
+ if( mbr!=r ){
+ d_eqcs[rtn].push_back( mbr );
+ }
+ d_eqcs[rtn].push_back( r );
+ d_model_basis[rtn] = mb;
+ }else{
+ itt->second.push_back( r );
+ }
+ }else{
+ d_eqcs[rtn].push_back( r );
+ }
+ ++eqcs_i;
+ }
+ /*
+ if( Trace.isOn("qcf-opt") ){
+ double clSet2 = double(clock())/double(CLOCKS_PER_SEC);
+ Trace("qcf-opt") << "Compute rel eqc : " << std::endl;
+ Trace("qcf-opt") << " " << nEqc << " equivalence classes. " << std::endl;
+ Trace("qcf-opt") << " " << nTerms << " / " << nTermst << " terms." << std::endl;
+ Trace("qcf-opt") << " Time : " << (clSet2-clSet) << std::endl;
+ }
+ */
+ }
+}
+
+
+//-------------------------------------------------- debugging
+
+
+void QuantConflictFind::debugPrint( const char * c ) {
+ //print the equivalance classes
+ Trace(c) << "----------EQ classes" << std::endl;
+ eq::EqClassesIterator eqcs_i = eq::EqClassesIterator( getEqualityEngine() );
+ while( !eqcs_i.isFinished() ){
+ Node n = (*eqcs_i);
+ //if( !n.getType().isInteger() ){
+ Trace(c) << " - " << n << " : {";
+ eq::EqClassIterator eqc_i = eq::EqClassIterator( n, getEqualityEngine() );
+ bool pr = false;
+ while( !eqc_i.isFinished() ){
+ Node nn = (*eqc_i);
+ if( nn.getKind()!=EQUAL && nn!=n ){
+ Trace(c) << (pr ? "," : "" ) << " " << nn;
+ pr = true;
+ }
+ ++eqc_i;
+ }
+ Trace(c) << (pr ? " " : "" ) << "}" << std::endl;
+ /*
+ EqcInfo * eqcn = getEqcInfo( n, false );
+ if( eqcn ){
+ Trace(c) << " DEQ : {";
+ pr = false;
+ for( NodeBoolMap::iterator it = eqcn->d_diseq.begin(); it != eqcn->d_diseq.end(); ++it ){
+ if( (*it).second ){
+ Trace(c) << (pr ? "," : "" ) << " " << (*it).first;
+ pr = true;
+ }
+ }
+ Trace(c) << (pr ? " " : "" ) << "}" << std::endl;
+ }
+ //}
+ */
+ ++eqcs_i;
+ }
+}
+
+void QuantConflictFind::debugPrintQuant( const char * c, Node q ) {
+ Trace(c) << "Q" << d_quant_id[q];
+}
+
+void QuantConflictFind::debugPrintQuantBody( const char * c, Node q, Node n, bool doVarNum ) {
+ if( n.getNumChildren()==0 ){
+ Trace(c) << n;
+ }else if( doVarNum && d_qinfo[q].d_var_num.find( n )!=d_qinfo[q].d_var_num.end() ){
+ Trace(c) << "?x" << d_qinfo[q].d_var_num[n];
+ }else{
+ Trace(c) << "(";
+ if( n.getKind()==APPLY_UF ){
+ Trace(c) << n.getOperator();
+ }else{
+ Trace(c) << n.getKind();
+ }
+ for( unsigned i=0; i<n.getNumChildren(); i++ ){
+ Trace(c) << " ";
+ debugPrintQuantBody( c, q, n[i] );
+ }
+ Trace(c) << ")";
+ }
+}
+
+QuantConflictFind::Statistics::Statistics():
+ d_inst_rounds("QuantConflictFind::Inst_Rounds", 0),
+ d_conflict_inst("QuantConflictFind::Instantiations_Conflict_Find", 0 ),
+ d_prop_inst("QuantConflictFind::Instantiations_Prop", 0 ),
+ d_entailment_checks("QuantConflictFind::Entailment_Checks",0)
+{
+ StatisticsRegistry::registerStat(&d_inst_rounds);
+ StatisticsRegistry::registerStat(&d_conflict_inst);
+ StatisticsRegistry::registerStat(&d_prop_inst);
+ StatisticsRegistry::registerStat(&d_entailment_checks);
+}
+
+QuantConflictFind::Statistics::~Statistics(){
+ StatisticsRegistry::unregisterStat(&d_inst_rounds);
+ StatisticsRegistry::unregisterStat(&d_conflict_inst);
+ StatisticsRegistry::unregisterStat(&d_prop_inst);
+ StatisticsRegistry::unregisterStat(&d_entailment_checks);
+}
+
+TNode QuantConflictFind::getZero( Kind k ) {
+ std::map< Kind, Node >::iterator it = d_zero.find( k );
+ if( it==d_zero.end() ){
+ Node nn;
+ if( k==PLUS ){
+ nn = NodeManager::currentNM()->mkConst( Rational(0) );
+ }
+ d_zero[k] = nn;
+ return nn;
+ }else{
+ return it->second;
+ }
+}
+
+
+}
diff --git a/src/theory/quantifiers/quant_conflict_find.h b/src/theory/quantifiers/quant_conflict_find.h
index 0464c04e5..93e1f72a6 100644..100755
--- a/src/theory/quantifiers/quant_conflict_find.h
+++ b/src/theory/quantifiers/quant_conflict_find.h
@@ -1,297 +1,253 @@
-/********************* */
-/*! \file quant_conflict_find.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-2014 New York University and The University of Iowa
- ** See the file COPYING in the top-level source directory for licensing
- ** information.\endverbatim
- **
- ** \brief quantifiers conflict find class
- **/
-
-#include "cvc4_private.h"
-
-#ifndef QUANT_CONFLICT_FIND
-#define QUANT_CONFLICT_FIND
-
-#include "context/cdhashmap.h"
-#include "context/cdchunk_list.h"
-#include "theory/quantifiers_engine.h"
-
-namespace CVC4 {
-namespace theory {
-namespace quantifiers {
-
-class QcfNode;
-
-class QuantConflictFind;
-
-class QcfNodeIndex {
-public:
- std::map< TNode, QcfNodeIndex > d_children;
- void clear() { d_children.clear(); }
- void debugPrint( const char * c, int t );
- Node existsTerm( TNode n, std::vector< TNode >& reps, int index = 0 );
- Node addTerm( TNode n, std::vector< TNode >& reps, int index = 0 );
-};
-
-class QuantInfo;
-
-//match generator
-class MatchGen {
- friend class QuantInfo;
-private:
- //current children information
- int d_child_counter;
- //children of this object
- std::vector< int > d_children_order;
- unsigned getNumChildren() { return d_children.size(); }
- MatchGen * getChild( int i ) { return &d_children[d_children_order[i]]; }
- //MatchGen * getChild( int i ) { return &d_children[i]; }
- //current matching information
- std::vector< QcfNodeIndex * > d_qn;
- std::vector< std::map< TNode, QcfNodeIndex >::iterator > d_qni;
- bool doMatching( QuantConflictFind * p, QuantInfo * qi );
- //for matching : each index is either a variable or a ground term
- unsigned d_qni_size;
- std::map< int, int > d_qni_var_num;
- std::map< int, TNode > d_qni_gterm;
- std::map< int, TNode > d_qni_gterm_rep;
- std::map< int, int > d_qni_bound;
- std::vector< int > d_qni_bound_except;
- std::map< int, TNode > d_qni_bound_cons;
- std::map< int, int > d_qni_bound_cons_var;
- std::map< int, int >::iterator d_binding_it;
- //std::vector< int > d_independent;
- bool d_matched_basis;
- bool d_binding;
- //int getVarBindingVar();
- std::map< int, Node > d_ground_eval;
- //determine variable order
- void determineVariableOrder( QuantInfo * qi, std::vector< int >& bvars );
- void collectBoundVar( QuantInfo * qi, Node n, std::vector< int >& cbvars );
-public:
- //type of the match generator
- enum {
- typ_invalid,
- typ_ground,
- typ_pred,
- typ_eq,
- typ_formula,
- typ_var,
- typ_ite_var,
- typ_bool_var,
- typ_tconstraint,
- typ_tsym,
- };
- void debugPrintType( const char * c, short typ, bool isTrace = false );
-public:
- MatchGen() : d_type( typ_invalid ){}
- MatchGen( QuantInfo * qi, Node n, bool isVar = false );
- bool d_tgt;
- bool d_tgt_orig;
- bool d_wasSet;
- Node d_n;
- std::vector< MatchGen > d_children;
- short d_type;
- bool d_type_not;
- void reset_round( QuantConflictFind * p );
- void reset( QuantConflictFind * p, bool tgt, QuantInfo * qi );
- bool getNextMatch( QuantConflictFind * p, QuantInfo * qi );
- bool getExplanation( QuantConflictFind * p, QuantInfo * qi, std::vector< Node >& exp );
- Node getExplanationTerm( QuantConflictFind * p, QuantInfo * qi, Node t, std::vector< Node >& exp );
- bool isValid() { return d_type!=typ_invalid; }
- void setInvalid();
-
- // is this term treated as UF application?
- static bool isHandledBoolConnective( TNode n );
- static bool isHandledUfTerm( TNode n );
- static Node getOperator( QuantConflictFind * p, Node n );
- //can this node be handled by the algorithm
- static bool isHandled( TNode n );
-};
-
-//info for quantifiers
-class QuantInfo {
-private:
- void registerNode( Node n, bool hasPol, bool pol, bool beneathQuant = false );
- void flatten( Node n, bool beneathQuant );
-private: //for completing match
- std::vector< int > d_unassigned;
- std::vector< TypeNode > d_unassigned_tn;
- int d_unassigned_nvar;
- int d_una_index;
- std::vector< int > d_una_eqc_count;
-public:
- QuantInfo() : d_mg( NULL ) {}
- ~QuantInfo() { delete d_mg; }
- std::vector< TNode > d_vars;
- std::map< TNode, int > d_var_num;
- std::vector< int > d_tsym_vars;
- std::map< TNode, bool > d_inMatchConstraint;
- std::map< int, std::vector< Node > > d_var_constraint[2];
- int getVarNum( TNode v ) { return d_var_num.find( v )!=d_var_num.end() ? d_var_num[v] : -1; }
- bool isVar( TNode v ) { return d_var_num.find( v )!=d_var_num.end(); }
- int getNumVars() { return (int)d_vars.size(); }
- TNode getVar( int i ) { return d_vars[i]; }
-
- MatchGen * d_mg;
- Node d_q;
- std::map< int, MatchGen * > d_var_mg;
- void reset_round( QuantConflictFind * p );
-public:
- //initialize
- void initialize( Node q, Node qn );
- //current constraints
- std::vector< TNode > d_match;
- std::vector< TNode > d_match_term;
- std::map< int, std::map< TNode, int > > d_curr_var_deq;
- std::map< Node, bool > d_tconstraints;
- int getCurrentRepVar( int v );
- TNode getCurrentValue( TNode n );
- TNode getCurrentExpValue( TNode n );
- bool getCurrentCanBeEqual( QuantConflictFind * p, int v, TNode n, bool chDiseq = false );
- int addConstraint( QuantConflictFind * p, int v, TNode n, bool polarity );
- int addConstraint( QuantConflictFind * p, int v, TNode n, int vn, bool polarity, bool doRemove );
- bool setMatch( QuantConflictFind * p, int v, TNode n );
- bool isMatchSpurious( QuantConflictFind * p );
- bool isTConstraintSpurious( QuantConflictFind * p, std::vector< Node >& terms );
- bool entailmentTest( QuantConflictFind * p, Node lit, bool chEnt = true );
- bool completeMatch( QuantConflictFind * p, std::vector< int >& assigned, bool doContinue = false );
- void revertMatch( std::vector< int >& assigned );
- void debugPrintMatch( const char * c );
- bool isConstrainedVar( int v );
-public:
- void getMatch( std::vector< Node >& terms );
-};
-
-class QuantConflictFind : public QuantifiersModule
-{
- friend class QcfNodeIndex;
- friend class MatchGen;
- friend class QuantInfo;
- typedef context::CDChunkList<Node> NodeList;
- typedef context::CDHashMap<Node, bool, NodeHashFunction> NodeBoolMap;
-private:
- context::Context* d_c;
- context::CDO< bool > d_conflict;
- bool d_performCheck;
- std::vector< Node > d_quant_order;
- std::map< Kind, Node > d_zero;
- //for storing nodes created during t-constraint solving (prevents memory leaks)
- std::vector< Node > d_tempCache;
-private:
- std::map< Node, Node > d_op_node;
- int d_fid_count;
- std::map< Node, int > d_fid;
- Node mkEqNode( Node a, Node b );
-public: //for ground terms
- Node d_true;
- Node d_false;
- TNode getZero( Kind k );
-private:
- Node evaluateTerm( Node n );
- int evaluate( Node n, bool pref = false, bool hasPref = false );
-private:
- //currently asserted quantifiers
- NodeList d_qassert;
- std::map< Node, QuantInfo > d_qinfo;
-private: //for equivalence classes
- eq::EqualityEngine * getEqualityEngine();
- bool areDisequal( Node n1, Node n2 );
- bool areEqual( Node n1, Node n2 );
- Node getRepresentative( Node n );
-
-/*
- class EqcInfo {
- public:
- EqcInfo( context::Context* c ) : d_diseq( c ) {}
- NodeBoolMap d_diseq;
- bool isDisequal( Node n ) { return d_diseq.find( n )!=d_diseq.end() && d_diseq[n]; }
- void setDisequal( Node n, bool val = true ) { d_diseq[n] = val; }
- //NodeBoolMap& getRelEqr( int index ) { return index==0 ? d_rel_eqr_e : d_rel_eqr_d; }
- };
- std::map< Node, EqcInfo * > d_eqc_info;
- EqcInfo * getEqcInfo( Node n, bool doCreate = true );
-*/
- // operator -> index(terms)
- std::map< TNode, QcfNodeIndex > d_uf_terms;
- // operator -> index(eqc -> terms)
- std::map< TNode, QcfNodeIndex > d_eqc_uf_terms;
- //get qcf node index
- QcfNodeIndex * getQcfNodeIndex( Node eqc, Node f );
- QcfNodeIndex * getQcfNodeIndex( Node f );
- // type -> list(eqc)
- std::map< TypeNode, std::vector< TNode > > d_eqcs;
- std::map< TypeNode, Node > d_model_basis;
- //mapping from UF terms to representatives of their arguments
- std::map< TNode, std::vector< TNode > > d_arg_reps;
- //compute arg reps
- void computeArgReps( TNode n );
- //compute
- void computeUfTerms( TNode f );
-public:
- enum {
- effort_conflict,
- effort_prop_eq,
- effort_mc,
- };
- short d_effort;
- void setEffort( int e ) { d_effort = e; }
- static short getMaxQcfEffort();
- bool areMatchEqual( TNode n1, TNode n2 );
- bool areMatchDisequal( TNode n1, TNode n2 );
-public:
- QuantConflictFind( QuantifiersEngine * qe, context::Context* c );
- /** register quantifier */
- void registerQuantifier( Node q );
-public:
- /** assert quantifier */
- void assertNode( Node q );
- /** new node */
- void newEqClass( Node n );
- /** merge */
- void merge( Node a, Node b );
- /** assert disequal */
- void assertDisequal( Node a, Node b );
- /** reset round */
- void reset_round( Theory::Effort level );
- /** check */
- void check( Theory::Effort level );
- /** needs check */
- bool needsCheck( Theory::Effort level );
-private:
- bool d_needs_computeRelEqr;
-public:
- void computeRelevantEqr();
-private:
- void debugPrint( const char * c );
- //for debugging
- std::vector< Node > d_quants;
- std::map< Node, int > d_quant_id;
- void debugPrintQuant( const char * c, Node q );
- void debugPrintQuantBody( const char * c, Node q, Node n, bool doVarNum = true );
-public:
- /** statistics class */
- class Statistics {
- public:
- IntStat d_inst_rounds;
- IntStat d_conflict_inst;
- IntStat d_prop_inst;
- IntStat d_entailment_checks;
- Statistics();
- ~Statistics();
- };
- Statistics d_statistics;
- /** Identify this module */
- std::string identify() const { return "QcfEngine"; }
-};
-
-}
-}
-}
-
-#endif
+/********************* */
+/*! \file quant_conflict_find.h
+ ** \verbatim
+ ** Original author: Andrew Reynolds
+ ** Major contributors: none
+ ** Minor contributors (to current version): none
+ ** This file is part of the CVC4 project.
+ ** Copyright (c) 2009-2014 New York University and The University of Iowa
+ ** See the file COPYING in the top-level source directory for licensing
+ ** information.\endverbatim
+ **
+ ** \brief quantifiers conflict find class
+ **/
+
+#include "cvc4_private.h"
+
+#ifndef QUANT_CONFLICT_FIND
+#define QUANT_CONFLICT_FIND
+
+#include "context/cdhashmap.h"
+#include "context/cdchunk_list.h"
+#include "theory/quantifiers_engine.h"
+#include "theory/quantifiers/term_database.h"
+
+namespace CVC4 {
+namespace theory {
+namespace quantifiers {
+
+class QuantConflictFind;
+class QuantInfo;
+
+//match generator
+class MatchGen {
+ friend class QuantInfo;
+private:
+ //current children information
+ int d_child_counter;
+ //children of this object
+ std::vector< int > d_children_order;
+ unsigned getNumChildren() { return d_children.size(); }
+ MatchGen * getChild( int i ) { return &d_children[d_children_order[i]]; }
+ //MatchGen * getChild( int i ) { return &d_children[i]; }
+ //current matching information
+ std::vector< TermArgTrie * > d_qn;
+ std::vector< std::map< TNode, TermArgTrie >::iterator > d_qni;
+ bool doMatching( QuantConflictFind * p, QuantInfo * qi );
+ //for matching : each index is either a variable or a ground term
+ unsigned d_qni_size;
+ std::map< int, int > d_qni_var_num;
+ std::map< int, TNode > d_qni_gterm;
+ std::map< int, TNode > d_qni_gterm_rep;
+ std::map< int, int > d_qni_bound;
+ std::vector< int > d_qni_bound_except;
+ std::map< int, TNode > d_qni_bound_cons;
+ std::map< int, int > d_qni_bound_cons_var;
+ std::map< int, int >::iterator d_binding_it;
+ //std::vector< int > d_independent;
+ bool d_matched_basis;
+ bool d_binding;
+ //int getVarBindingVar();
+ std::map< int, Node > d_ground_eval;
+ //determine variable order
+ void determineVariableOrder( QuantInfo * qi, std::vector< int >& bvars );
+ void collectBoundVar( QuantInfo * qi, Node n, std::vector< int >& cbvars );
+public:
+ //type of the match generator
+ enum {
+ typ_invalid,
+ typ_ground,
+ typ_pred,
+ typ_eq,
+ typ_formula,
+ typ_var,
+ typ_ite_var,
+ typ_bool_var,
+ typ_tconstraint,
+ typ_tsym,
+ };
+ void debugPrintType( const char * c, short typ, bool isTrace = false );
+public:
+ MatchGen() : d_type( typ_invalid ){}
+ MatchGen( QuantInfo * qi, Node n, bool isVar = false );
+ bool d_tgt;
+ bool d_tgt_orig;
+ bool d_wasSet;
+ Node d_n;
+ std::vector< MatchGen > d_children;
+ short d_type;
+ bool d_type_not;
+ void reset_round( QuantConflictFind * p );
+ void reset( QuantConflictFind * p, bool tgt, QuantInfo * qi );
+ bool getNextMatch( QuantConflictFind * p, QuantInfo * qi );
+ bool getExplanation( QuantConflictFind * p, QuantInfo * qi, std::vector< Node >& exp );
+ Node getExplanationTerm( QuantConflictFind * p, QuantInfo * qi, Node t, std::vector< Node >& exp );
+ bool isValid() { return d_type!=typ_invalid; }
+ void setInvalid();
+
+ // is this term treated as UF application?
+ static bool isHandledBoolConnective( TNode n );
+ static bool isHandledUfTerm( TNode n );
+ static Node getOperator( QuantConflictFind * p, Node n );
+ //can this node be handled by the algorithm
+ static bool isHandled( TNode n );
+};
+
+//info for quantifiers
+class QuantInfo {
+private:
+ void registerNode( Node n, bool hasPol, bool pol, bool beneathQuant = false );
+ void flatten( Node n, bool beneathQuant );
+private: //for completing match
+ std::vector< int > d_unassigned;
+ std::vector< TypeNode > d_unassigned_tn;
+ int d_unassigned_nvar;
+ int d_una_index;
+ std::vector< int > d_una_eqc_count;
+public:
+ QuantInfo() : d_mg( NULL ) {}
+ ~QuantInfo() { delete d_mg; }
+ std::vector< TNode > d_vars;
+ std::map< TNode, int > d_var_num;
+ std::vector< int > d_tsym_vars;
+ std::map< TNode, bool > d_inMatchConstraint;
+ std::map< int, std::vector< Node > > d_var_constraint[2];
+ int getVarNum( TNode v ) { return d_var_num.find( v )!=d_var_num.end() ? d_var_num[v] : -1; }
+ bool isVar( TNode v ) { return d_var_num.find( v )!=d_var_num.end(); }
+ int getNumVars() { return (int)d_vars.size(); }
+ TNode getVar( int i ) { return d_vars[i]; }
+
+ MatchGen * d_mg;
+ Node d_q;
+ std::map< int, MatchGen * > d_var_mg;
+ void reset_round( QuantConflictFind * p );
+public:
+ //initialize
+ void initialize( Node q, Node qn );
+ //current constraints
+ std::vector< TNode > d_match;
+ std::vector< TNode > d_match_term;
+ std::map< int, std::map< TNode, int > > d_curr_var_deq;
+ std::map< Node, bool > d_tconstraints;
+ int getCurrentRepVar( int v );
+ TNode getCurrentValue( TNode n );
+ TNode getCurrentExpValue( TNode n );
+ bool getCurrentCanBeEqual( QuantConflictFind * p, int v, TNode n, bool chDiseq = false );
+ int addConstraint( QuantConflictFind * p, int v, TNode n, bool polarity );
+ int addConstraint( QuantConflictFind * p, int v, TNode n, int vn, bool polarity, bool doRemove );
+ bool setMatch( QuantConflictFind * p, int v, TNode n );
+ bool isMatchSpurious( QuantConflictFind * p );
+ bool isTConstraintSpurious( QuantConflictFind * p, std::vector< Node >& terms );
+ bool entailmentTest( QuantConflictFind * p, Node lit, bool chEnt = true );
+ bool completeMatch( QuantConflictFind * p, std::vector< int >& assigned, bool doContinue = false );
+ void revertMatch( std::vector< int >& assigned );
+ void debugPrintMatch( const char * c );
+ bool isConstrainedVar( int v );
+public:
+ void getMatch( std::vector< Node >& terms );
+};
+
+class QuantConflictFind : public QuantifiersModule
+{
+ friend class MatchGen;
+ friend class QuantInfo;
+ typedef context::CDChunkList<Node> NodeList;
+ typedef context::CDHashMap<Node, bool, NodeHashFunction> NodeBoolMap;
+private:
+ context::CDO< bool > d_conflict;
+ std::vector< Node > d_quant_order;
+ std::map< Kind, Node > d_zero;
+ //for storing nodes created during t-constraint solving (prevents memory leaks)
+ std::vector< Node > d_tempCache;
+private:
+ std::map< Node, Node > d_op_node;
+ int d_fid_count;
+ std::map< Node, int > d_fid;
+ Node mkEqNode( Node a, Node b );
+public: //for ground terms
+ Node d_true;
+ Node d_false;
+ TNode getZero( Kind k );
+private:
+ Node evaluateTerm( Node n );
+ int evaluate( Node n, bool pref = false, bool hasPref = false );
+private:
+ //currently asserted quantifiers
+ NodeList d_qassert;
+ std::map< Node, QuantInfo > d_qinfo;
+private: //for equivalence classes
+ // type -> list(eqc)
+ std::map< TypeNode, std::vector< TNode > > d_eqcs;
+ std::map< TypeNode, Node > d_model_basis;
+public:
+ enum {
+ effort_conflict,
+ effort_prop_eq,
+ effort_mc,
+ };
+ short d_effort;
+ void setEffort( int e ) { d_effort = e; }
+ static short getMaxQcfEffort();
+ bool areMatchEqual( TNode n1, TNode n2 );
+ bool areMatchDisequal( TNode n1, TNode n2 );
+public:
+ QuantConflictFind( QuantifiersEngine * qe, context::Context* c );
+ /** register quantifier */
+ void registerQuantifier( Node q );
+public:
+ /** assert quantifier */
+ void assertNode( Node q );
+ /** new node */
+ void newEqClass( Node n );
+ /** merge */
+ void merge( Node a, Node b );
+ /** assert disequal */
+ void assertDisequal( Node a, Node b );
+ /** needs check */
+ bool needsCheck( Theory::Effort level );
+ /** reset round */
+ void reset_round( Theory::Effort level );
+ /** check */
+ void check( Theory::Effort level, unsigned quant_e );
+private:
+ bool d_needs_computeRelEqr;
+public:
+ void computeRelevantEqr();
+private:
+ void debugPrint( const char * c );
+ //for debugging
+ std::vector< Node > d_quants;
+ std::map< Node, int > d_quant_id;
+ void debugPrintQuant( const char * c, Node q );
+ void debugPrintQuantBody( const char * c, Node q, Node n, bool doVarNum = true );
+public:
+ /** statistics class */
+ class Statistics {
+ public:
+ IntStat d_inst_rounds;
+ IntStat d_conflict_inst;
+ IntStat d_prop_inst;
+ IntStat d_entailment_checks;
+ Statistics();
+ ~Statistics();
+ };
+ Statistics d_statistics;
+ /** Identify this module */
+ std::string identify() const { return "QcfEngine"; }
+};
+
+}
+}
+}
+
+#endif
diff --git a/src/theory/quantifiers/quantifiers_attributes.cpp b/src/theory/quantifiers/quantifiers_attributes.cpp
index a5de6ffa9..ef5b71f9d 100644
--- a/src/theory/quantifiers/quantifiers_attributes.cpp
+++ b/src/theory/quantifiers/quantifiers_attributes.cpp
@@ -14,6 +14,7 @@
#include "theory/quantifiers/quantifiers_attributes.h"
#include "theory/quantifiers/options.h"
+#include "theory/quantifiers/term_database.h"
using namespace std;
using namespace CVC4;
@@ -22,24 +23,39 @@ using namespace CVC4::context;
using namespace CVC4::theory;
using namespace CVC4::theory::quantifiers;
-void QuantifiersAttributes::setUserAttribute( const std::string& attr, Node n ){
- if( n.getKind()==FORALL ){
- if( attr=="axiom" ){
- Trace("quant-attr") << "Set axiom " << n << std::endl;
- AxiomAttribute aa;
- n.setAttribute( aa, true );
- }else if( attr=="conjecture" ){
- 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++ ){
- setUserAttribute( attr, n[i] );
- }
+void QuantifiersAttributes::setUserAttribute( const std::string& attr, Node n, std::vector<Node> node_values, std::string str_value ){
+ Trace("quant-attr-debug") << "Set " << attr << " " << n << std::endl;
+ if( attr=="axiom" ){
+ Trace("quant-attr-debug") << "Set axiom " << n << std::endl;
+ AxiomAttribute aa;
+ n.setAttribute( aa, true );
+ }else if( attr=="conjecture" ){
+ Trace("quant-attr-debug") << "Set conjecture " << n << std::endl;
+ ConjectureAttribute ca;
+ n.setAttribute( ca, true );
+ }else if( attr=="fun-def" ){
+ Trace("quant-attr-debug") << "Set function definition " << n << std::endl;
+ FunDefAttribute fda;
+ n.setAttribute( fda, true );
+ }else if( attr=="sygus" ){
+ Trace("quant-attr-debug") << "Set sygus " << n << std::endl;
+ SygusAttribute ca;
+ n.setAttribute( ca, true );
+ }else if( attr=="synthesis" ){
+ Trace("quant-attr-debug") << "Set synthesis " << n << std::endl;
+ SynthesisAttribute ca;
+ n.setAttribute( ca, true );
+ }else if( attr=="quant-inst-max-level" ){
+ Assert( node_values.size()==1 );
+ uint64_t lvl = node_values[0].getConst<Rational>().getNumerator().getLong();
+ Trace("quant-attr-debug") << "Set instantiation level " << n << " to " << lvl << std::endl;
+ QuantInstLevelAttribute qila;
+ n.setAttribute( qila, lvl );
+ }else if( attr=="rr-priority" ){
+ Assert( node_values.size()==1 );
+ uint64_t lvl = node_values[0].getConst<Rational>().getNumerator().getLong();
+ Trace("quant-attr-debug") << "Set rewrite rule priority " << n << " to " << lvl << std::endl;
+ RrPriorityAttribute rrpa;
+ n.setAttribute( rrpa, lvl );
}
}
diff --git a/src/theory/quantifiers/quantifiers_attributes.h b/src/theory/quantifiers/quantifiers_attributes.h
index cf9620a07..bad58eef8 100644
--- a/src/theory/quantifiers/quantifiers_attributes.h
+++ b/src/theory/quantifiers/quantifiers_attributes.h
@@ -26,14 +26,6 @@ namespace CVC4 {
namespace theory {
namespace quantifiers {
-/** Attribute true for quantifiers that are axioms */
-struct AxiomAttributeId {};
-typedef expr::Attribute< AxiomAttributeId, bool > AxiomAttribute;
-
-/** Attribute true for quantifiers that are conjecture */
-struct ConjectureAttributeId {};
-typedef expr::Attribute< ConjectureAttributeId, bool > ConjectureAttribute;
-
/** Attribute priority for rewrite rules */
//struct RrPriorityAttributeId {};
//typedef expr::Attribute< RrPriorityAttributeId, uint64_t > RrPriorityAttribute;
@@ -44,7 +36,7 @@ struct QuantifiersAttributes
* This function will apply a custom set of attributes to all top-level universal
* quantifiers contained in n
*/
- static void setUserAttribute( const std::string& attr, Node n );
+ static void setUserAttribute( const std::string& attr, Node n, std::vector<Node> node_values, std::string str_value );
};
diff --git a/src/theory/quantifiers/quantifiers_rewriter.cpp b/src/theory/quantifiers/quantifiers_rewriter.cpp
index eb14b0abe..fb7ff679b 100644
--- a/src/theory/quantifiers/quantifiers_rewriter.cpp
+++ b/src/theory/quantifiers/quantifiers_rewriter.cpp
@@ -159,7 +159,13 @@ RewriteResponse QuantifiersRewriter::preRewrite(TNode in) {
}
Node body = in[1];
bool doRewrite = false;
+ std::vector< Node > ipl;
while( body.getNumChildren()>=2 && body.getKind()==in.getKind() ){
+ if( body.getNumChildren()==3 ){
+ for( unsigned i=0; i<body[2].getNumChildren(); i++ ){
+ ipl.push_back( body[2][i] );
+ }
+ }
for( int i=0; i<(int)body[0].getNumChildren(); i++ ){
args.push_back( body[0][i] );
}
@@ -171,7 +177,12 @@ RewriteResponse QuantifiersRewriter::preRewrite(TNode in) {
children.push_back( NodeManager::currentNM()->mkNode(kind::BOUND_VAR_LIST,args) );
children.push_back( body );
if( in.getNumChildren()==3 ){
- children.push_back( in[2] );
+ for( unsigned i=0; i<in[2].getNumChildren(); i++ ){
+ ipl.push_back( in[2][i] );
+ }
+ }
+ if( !ipl.empty() ){
+ children.push_back( NodeManager::currentNM()->mkNode( INST_PATTERN_LIST, ipl ) );
}
Node n = NodeManager::currentNM()->mkNode( in.getKind(), children );
if( in!=n ){
@@ -357,7 +368,7 @@ Node QuantifiersRewriter::computeVarElimination( Node body, std::vector< Node >&
for( std::map< Node, bool >::iterator it = qpr.d_phase_reqs.begin(); it != qpr.d_phase_reqs.end(); ++it ){
//Notice() << " " << it->first << " -> " << ( it->second ? "true" : "false" ) << std::endl;
if( it->first.getKind()==EQUAL ){
- if( it->second ){
+ if( it->second && options::varElimQuant() ){
for( int i=0; i<2; i++ ){
int j = i==0 ? 1 : 0;
std::vector< Node >::iterator ita = std::find( args.begin(), args.end(), it->first[i] );
@@ -377,6 +388,33 @@ Node QuantifiersRewriter::computeVarElimination( Node body, std::vector< Node >&
}
}
}
+ else if( it->first.getKind()==APPLY_TESTER ){
+ if( options::dtVarExpandQuant() && it->second && it->first[0].getKind()==BOUND_VARIABLE ){
+ Trace("dt-var-expand") << "Expand datatype variable based on : " << it->first << std::endl;
+ std::vector< Node >::iterator ita = std::find( args.begin(), args.end(), it->first[0] );
+ if( ita!=args.end() ){
+ vars.push_back( it->first[0] );
+ Expr testerExpr = it->first.getOperator().toExpr();
+ int index = Datatype::indexOf( testerExpr );
+ const Datatype& dt = Datatype::datatypeOf(testerExpr);
+ const DatatypeConstructor& c = dt[index];
+ std::vector< Node > newChildren;
+ newChildren.push_back( Node::fromExpr( c.getConstructor() ) );
+ std::vector< Node > newVars;
+ for( unsigned j=0; j<c.getNumArgs(); j++ ){
+ TypeNode tn = TypeNode::fromType( c[j].getSelector().getType() );
+ tn = tn[1];
+ Node v = NodeManager::currentNM()->mkBoundVar( tn );
+ newChildren.push_back( v );
+ newVars.push_back( v );
+ }
+ subs.push_back( NodeManager::currentNM()->mkNode( APPLY_CONSTRUCTOR, newChildren ) );
+ Trace("dt-var-expand") << "...apply substitution " << subs[0] << "/" << vars[0] << std::endl;
+ args.erase( ita );
+ args.insert( args.end(), newVars.begin(), newVars.end() );
+ }
+ }
+ }
}
if( !vars.empty() ){
Trace("var-elim-quant") << "VE " << vars.size() << "/" << args.size() << std::endl;
@@ -539,7 +577,7 @@ Node QuantifiersRewriter::computeCNF( Node n, std::vector< Node >& args, NodeBui
Node QuantifiersRewriter::computePrenex( Node body, std::vector< Node >& args, bool pol ){
if( body.getKind()==FORALL ){
- if( pol ){
+ if( pol && ( options::prenexQuant()==PRENEX_ALL || body.getNumChildren()==2 ) ){
std::vector< Node > terms;
std::vector< Node > subs;
//for doing prenexing of same-signed quantifiers
@@ -912,9 +950,9 @@ bool QuantifiersRewriter::doOperation( Node f, bool isNested, int computeOption
}else if( computeOption==COMPUTE_SIMPLE_ITE_LIFT ){
return options::simpleIteLiftQuant();
}else if( computeOption==COMPUTE_PRENEX ){
- return options::prenexQuant() && !options::aggressiveMiniscopeQuant();
+ return options::prenexQuant()!=PRENEX_NONE && !options::aggressiveMiniscopeQuant();
}else if( computeOption==COMPUTE_VAR_ELIMINATION ){
- return options::varElimQuant();
+ return options::varElimQuant() || options::dtVarExpandQuant();
}else if( computeOption==COMPUTE_CNF ){
return false;//return options::cnfQuant() ; FIXME
}else if( computeOption==COMPUTE_SPLIT ){
@@ -1079,7 +1117,7 @@ Node QuantifiersRewriter::rewriteRewriteRule( Node r ) {
NodeBuilder<> patternListB(kind::INST_PATTERN_LIST);
//the entire rewrite rule is the first pattern
if( options::quantRewriteRules() ){
- patternListB << NodeManager::currentNM()->mkNode( INST_PATTERN, r );
+ patternListB << NodeManager::currentNM()->mkNode( INST_ATTRIBUTE, r );
}
patternListB << static_cast<Node>(patternB);
forallB << static_cast<Node>(patternListB);
@@ -1142,8 +1180,10 @@ Node QuantifiersRewriter::preSkolemizeQuantifiers( Node n, bool polarity, std::v
//process body
Node nn = preSkolemizeQuantifiers( n[1], polarity, fvTypes, fvs );
std::vector< Node > sk;
+ Node sub;
+ std::vector< unsigned > sub_vars;
//return skolemized body
- return TermDb::mkSkolemizedBody( n, nn, fvTypes, fvs, sk );
+ return TermDb::mkSkolemizedBody( n, nn, fvTypes, fvs, sk, sub, sub_vars );
}
}else{
//check if it contains a quantifier as a subterm
diff --git a/src/theory/quantifiers/rewrite_engine.cpp b/src/theory/quantifiers/rewrite_engine.cpp
index 1b13d772e..05e33c7b2 100644
--- a/src/theory/quantifiers/rewrite_engine.cpp
+++ b/src/theory/quantifiers/rewrite_engine.cpp
@@ -39,7 +39,7 @@ struct PrioritySort {
RewriteEngine::RewriteEngine( context::Context* c, QuantifiersEngine* qe ) : QuantifiersModule(qe) {
d_true = NodeManager::currentNM()->mkConst( true );
- d_needsSort = true;
+ d_needsSort = false;
}
double RewriteEngine::getPriority( Node f ) {
@@ -61,8 +61,14 @@ double RewriteEngine::getPriority( Node f ) {
//return deterministic ? 0.0 : 1.0;
}
-void RewriteEngine::check( Theory::Effort e ) {
- if( e==Theory::EFFORT_FULL ){
+bool RewriteEngine::needsCheck( Theory::Effort e ){
+ return e==Theory::EFFORT_FULL;
+ //return e>=Theory::EFFORT_LAST_CALL;
+}
+
+void RewriteEngine::check( Theory::Effort e, unsigned quant_e ) {
+ if( quant_e==QuantifiersEngine::QEFFORT_STANDARD ){
+ //if( e==Theory::EFFORT_FULL ){
Trace("rewrite-engine") << "---Rewrite Engine Round, effort = " << e << "---" << std::endl;
//if( e==Theory::EFFORT_LAST_CALL ){
// if( !d_quantEngine->getModel()->isModelSet() ){
@@ -102,7 +108,6 @@ void RewriteEngine::check( Theory::Effort e ) {
}else{
//otherwise, the search will continue
- d_quantEngine->flushLemmas( &d_quantEngine->getOutputChannel() );
}
}
}
diff --git a/src/theory/quantifiers/rewrite_engine.h b/src/theory/quantifiers/rewrite_engine.h
index d2108bf3e..1703a9bfc 100644
--- a/src/theory/quantifiers/rewrite_engine.h
+++ b/src/theory/quantifiers/rewrite_engine.h
@@ -54,7 +54,8 @@ private:
public:
RewriteEngine( context::Context* c, QuantifiersEngine* qe );
- void check( Theory::Effort e );
+ bool needsCheck( Theory::Effort e );
+ void check( Theory::Effort e, unsigned quant_e );
void registerQuantifier( Node f );
void assertNode( Node n );
/** Identify this module */
diff --git a/src/theory/quantifiers/term_database.cpp b/src/theory/quantifiers/term_database.cpp
index 9ea9ee962..392fc269a 100644
--- a/src/theory/quantifiers/term_database.cpp
+++ b/src/theory/quantifiers/term_database.cpp
@@ -21,6 +21,8 @@
#include "theory/quantifiers/theory_quantifiers.h"
#include "util/datatype.h"
#include "theory/datatypes/datatypes_rewriter.h"
+#include "theory/quantifiers/ce_guided_instantiation.h"
+#include "theory/quantifiers/rewrite_engine.h"
using namespace std;
using namespace CVC4;
@@ -31,25 +33,39 @@ using namespace CVC4::theory::quantifiers;
using namespace CVC4::theory::inst;
-bool TermArgTrie::addTerm2( QuantifiersEngine* qe, Node n, int argIndex ){
- if( argIndex<(int)n.getNumChildren() ){
- Node r = qe->getEqualityQuery()->getRepresentative( n[ argIndex ] );
- std::map< Node, TermArgTrie >::iterator it = d_data.find( r );
+TNode TermArgTrie::existsTerm( std::vector< TNode >& reps, int argIndex ) {
+ if( argIndex==(int)reps.size() ){
+ if( d_data.empty() ){
+ return Node::null();
+ }else{
+ return d_data.begin()->first;
+ }
+ }else{
+ std::map< TNode, TermArgTrie >::iterator it = d_data.find( reps[argIndex] );
if( it==d_data.end() ){
- d_data[r].addTerm2( qe, n, argIndex+1 );
+ return Node::null();
+ }else{
+ return it->second.existsTerm( reps, argIndex+1 );
+ }
+ }
+}
+
+bool TermArgTrie::addTerm( TNode n, std::vector< TNode >& reps, int argIndex ){
+ if( argIndex==(int)reps.size() ){
+ if( d_data.empty() ){
+ //store n in d_data (this should be interpretted as the "data" and not as a reference to a child)
+ d_data[n].clear();
return true;
}else{
- return it->second.addTerm2( qe, n, argIndex+1 );
+ return false;
}
}else{
- //store n in d_data (this should be interpretted as the "data" and not as a reference to a child)
- d_data[n].d_data.clear();
- return false;
+ return d_data[reps[argIndex]].addTerm( n, reps, argIndex+1 );
}
}
void TermArgTrie::debugPrint( const char * c, Node n, unsigned depth ) {
- for( std::map< Node, TermArgTrie >::iterator it = d_data.begin(); it != d_data.end(); ++it ){
+ for( std::map< TNode, TermArgTrie >::iterator it = d_data.begin(); it != d_data.end(); ++it ){
for( unsigned i=0; i<depth; i++ ){ Debug(c) << " "; }
Debug(c) << it->first << std::endl;
it->second.debugPrint( c, n, depth+1 );
@@ -57,7 +73,8 @@ void TermArgTrie::debugPrint( const char * c, Node n, unsigned depth ) {
}
TermDb::TermDb( context::Context* c, context::UserContext* u, QuantifiersEngine* qe ) : d_quantEngine( qe ), d_op_ccount( u ) {
-
+ d_true = NodeManager::currentNM()->mkConst( true );
+ d_false = NodeManager::currentNM()->mkConst( false );
}
/** ground terms */
@@ -129,8 +146,6 @@ void TermDb::addTerm( Node n, std::set< Node >& added, bool withinQuant ){
for( size_t i=0; i<d_op_triggers[op].size(); i++ ){
addedLemmas += d_op_triggers[op][i]->addTerm( n );
}
- //Message() << "Terms, added lemmas: " << addedLemmas << std::endl;
- d_quantEngine->flushLemmas( &d_quantEngine->getOutputChannel() );
}
}
}
@@ -143,65 +158,193 @@ void TermDb::addTerm( Node n, std::set< Node >& added, bool withinQuant ){
}
}
- void TermDb::reset( Theory::Effort effort ){
+void TermDb::computeArgReps( TNode n ) {
+ if( d_arg_reps.find( n )==d_arg_reps.end() ){
+ eq::EqualityEngine * ee = d_quantEngine->getTheoryEngine()->getMasterEqualityEngine();
+ for( unsigned j=0; j<n.getNumChildren(); j++ ){
+ TNode r = ee->hasTerm( n[j] ) ? ee->getRepresentative( n[j] ) : n[j];
+ d_arg_reps[n].push_back( r );
+ }
+ }
+}
+
+void TermDb::computeUfEqcTerms( TNode f ) {
+ if( d_func_map_eqc_trie.find( f )==d_func_map_eqc_trie.end() ){
+ d_func_map_eqc_trie[f].clear();
+ eq::EqualityEngine * ee = d_quantEngine->getTheoryEngine()->getMasterEqualityEngine();
+ for( unsigned i=0; i<d_op_map[f].size(); i++ ){
+ TNode n = d_op_map[f][i];
+ if( !n.getAttribute(NoMatchAttribute()) ){
+ computeArgReps( n );
+ TNode r = ee->hasTerm( n ) ? ee->getRepresentative( n ) : n;
+ d_func_map_eqc_trie[f].d_data[r].addTerm( n, d_arg_reps[n] );
+ }
+ }
+ }
+}
+
+TNode TermDb::evaluateTerm( TNode n, std::map< TNode, TNode >& subs, bool subsRep ) {
+ Trace("term-db-eval") << "evaluate term : " << n << std::endl;
+ eq::EqualityEngine * ee = d_quantEngine->getTheoryEngine()->getMasterEqualityEngine();
+ if( ee->hasTerm( n ) ){
+ Trace("term-db-eval") << "...exists in ee, return rep " << std::endl;
+ return ee->getRepresentative( n );
+ }else if( n.getKind()==BOUND_VARIABLE ){
+ Assert( subs.find( n )!=subs.end() );
+ Trace("term-db-eval") << "...substitution is : " << subs[n] << std::endl;
+ if( subsRep ){
+ Assert( ee->hasTerm( subs[n] ) );
+ Assert( ee->getRepresentative( subs[n] )==subs[n] );
+ return subs[n];
+ }else{
+ return evaluateTerm( subs[n], subs, subsRep );
+ }
+ }else{
+ if( n.hasOperator() ){
+ TNode f = getOperator( n );
+ if( !f.isNull() ){
+ std::vector< TNode > args;
+ for( unsigned i=0; i<n.getNumChildren(); i++ ){
+ TNode c = evaluateTerm( n[i], subs, subsRep );
+ if( c.isNull() ){
+ return TNode::null();
+ }
+ Trace("term-db-eval") << "Got child : " << c << std::endl;
+ args.push_back( c );
+ }
+ Trace("term-db-eval") << "Get term from DB" << std::endl;
+ TNode nn = d_func_map_trie[f].existsTerm( args );
+ Trace("term-db-eval") << "Got term " << nn << std::endl;
+ if( !nn.isNull() ){
+ if( ee->hasTerm( nn ) ){
+ Trace("term-db-eval") << "return rep " << std::endl;
+ return ee->getRepresentative( nn );
+ }else{
+ //Assert( false );
+ }
+ }
+ }
+ }
+ return TNode::null();
+ }
+}
+
+TNode TermDb::evaluateTerm( TNode n ) {
+ eq::EqualityEngine * ee = d_quantEngine->getTheoryEngine()->getMasterEqualityEngine();
+ if( ee->hasTerm( n ) ){
+ return ee->getRepresentative( n );
+ }else if( n.getKind()!=BOUND_VARIABLE ){
+ if( n.hasOperator() ){
+ TNode f = getOperator( n );
+ if( !f.isNull() ){
+ std::vector< TNode > args;
+ for( unsigned i=0; i<n.getNumChildren(); i++ ){
+ TNode c = evaluateTerm( n[i] );
+ if( c.isNull() ){
+ return TNode::null();
+ }
+ args.push_back( c );
+ }
+ TNode nn = d_func_map_trie[f].existsTerm( args );
+ if( !nn.isNull() ){
+ if( ee->hasTerm( nn ) ){
+ return ee->getRepresentative( nn );
+ }else{
+ //Assert( false );
+ }
+ }
+ }
+ }
+ }
+ return TNode::null();
+}
+
+bool TermDb::isEntailed( TNode n, std::map< TNode, TNode >& subs, bool subsRep, bool pol ) {
+ Trace("term-db-eval") << "Check entailed : " << n << ", pol = " << pol << std::endl;
+ Assert( n.getType().isBoolean() );
+ if( n.getKind()==EQUAL ){
+ TNode n1 = evaluateTerm( n[0], subs, subsRep );
+ if( !n1.isNull() ){
+ TNode n2 = evaluateTerm( n[1], subs, subsRep );
+ if( !n2.isNull() ){
+ eq::EqualityEngine * ee = d_quantEngine->getTheoryEngine()->getMasterEqualityEngine();
+ Assert( ee->hasTerm( n1 ) );
+ Assert( ee->hasTerm( n2 ) );
+ if( pol ){
+ return n1==n2 || ee->areEqual( n1, n2 );
+ }else{
+ return n1!=n2 && ee->areDisequal( n1, n2, false );
+ }
+ }
+ }
+ }else if( n.getKind()==APPLY_UF ){
+ TNode n1 = evaluateTerm( n, subs, subsRep );
+ if( !n1.isNull() ){
+ eq::EqualityEngine * ee = d_quantEngine->getTheoryEngine()->getMasterEqualityEngine();
+ Assert( ee->hasTerm( n1 ) );
+ TNode n2 = pol ? d_true : d_false;
+ if( ee->hasTerm( n2 ) ){
+ return ee->areEqual( n1, n2 );
+ }
+ }
+ }else if( n.getKind()==NOT ){
+ return isEntailed( n[0], subs, subsRep, !pol );
+ }else if( n.getKind()==OR || n.getKind()==AND ){
+ bool simPol = ( pol && n.getKind()==OR ) || ( !pol && n.getKind()==AND );
+ for( unsigned i=0; i<n.getNumChildren(); i++ ){
+ if( isEntailed( n[i], subs, subsRep, pol ) ){
+ if( simPol ){
+ return true;
+ }
+ }else{
+ if( !simPol ){
+ return false;
+ }
+ }
+ }
+ return !simPol;
+ }else if( n.getKind()==IFF || n.getKind()==ITE ){
+ for( unsigned i=0; i<2; i++ ){
+ if( isEntailed( n[0], subs, subsRep, i==0 ) ){
+ unsigned ch = ( n.getKind()==IFF || i==0 ) ? 1 : 2;
+ bool reqPol = ( n.getKind()==ITE || i==0 ) ? pol : !pol;
+ return isEntailed( n[ch], subs, subsRep, reqPol );
+ }
+ }
+ }
+ return false;
+}
+
+void TermDb::reset( Theory::Effort effort ){
int nonCongruentCount = 0;
int congruentCount = 0;
int alreadyCongruentCount = 0;
+ d_op_nonred_count.clear();
+ d_arg_reps.clear();
+ d_func_map_trie.clear();
+ d_func_map_eqc_trie.clear();
//rebuild d_func/pred_map_trie for each operation, this will calculate all congruent terms
for( std::map< Node, std::vector< Node > >::iterator it = d_op_map.begin(); it != d_op_map.end(); ++it ){
d_op_nonred_count[ it->first ] = 0;
if( !it->second.empty() ){
- if( it->second[0].getType().isBoolean() ){
- d_pred_map_trie[ 0 ][ it->first ].d_data.clear();
- d_pred_map_trie[ 1 ][ it->first ].d_data.clear();
- }else{
- d_func_map_trie[ it->first ].d_data.clear();
- for( int i=0; i<(int)it->second.size(); i++ ){
- Node n = it->second[i];
- computeModelBasisArgAttribute( n );
- if( !n.getAttribute(NoMatchAttribute()) ){
- if( !d_func_map_trie[ it->first ].addTerm( d_quantEngine, n ) ){
- NoMatchAttribute nma;
- n.setAttribute(nma,true);
- Debug("term-db-cong") << n << " is redundant." << std::endl;
- congruentCount++;
- }else{
- nonCongruentCount++;
- d_op_nonred_count[ it->first ]++;
- }
- }else{
+ for( unsigned i=0; i<it->second.size(); i++ ){
+ Node n = it->second[i];
+ computeModelBasisArgAttribute( n );
+ if( !n.getAttribute(NoMatchAttribute()) ){
+ computeArgReps( n );
+ if( !d_func_map_trie[ it->first ].addTerm( n, d_arg_reps[n] ) ){
+ NoMatchAttribute nma;
+ n.setAttribute(nma,true);
+ Debug("term-db-cong") << n << " is redundant." << std::endl;
congruentCount++;
- alreadyCongruentCount++;
- }
- }
- }
- }
- }
- for( int i=0; i<2; i++ ){
- Node n = NodeManager::currentNM()->mkConst( i==1 );
- if( d_quantEngine->getEqualityQuery()->getEngine()->hasTerm( n ) ){
- eq::EqClassIterator eqc( d_quantEngine->getEqualityQuery()->getEngine()->getRepresentative( n ),
- d_quantEngine->getEqualityQuery()->getEngine() );
- while( !eqc.isFinished() ){
- Node en = (*eqc);
- computeModelBasisArgAttribute( en );
- if( en.getKind()==APPLY_UF && !TermDb::hasInstConstAttr(en) ){
- if( !en.getAttribute(NoMatchAttribute()) ){
- Node op = getOperator( en );
- if( !d_pred_map_trie[i][op].addTerm( d_quantEngine, en ) ){
- NoMatchAttribute nma;
- en.setAttribute(nma,true);
- Debug("term-db-cong") << en << " is redundant." << std::endl;
- congruentCount++;
- }else{
- nonCongruentCount++;
- d_op_nonred_count[ op ]++;
- }
}else{
- alreadyCongruentCount++;
+ nonCongruentCount++;
+ d_op_nonred_count[ it->first ]++;
}
+ }else{
+ congruentCount++;
+ alreadyCongruentCount++;
}
- ++eqc;
}
}
}
@@ -219,6 +362,39 @@ void TermDb::addTerm( Node n, std::set< Node >& added, bool withinQuant ){
}
}
+TermArgTrie * TermDb::getTermArgTrie( Node f ) {
+ std::map< Node, TermArgTrie >::iterator itut = d_func_map_trie.find( f );
+ if( itut!=d_func_map_trie.end() ){
+ return &itut->second;
+ }else{
+ return NULL;
+ }
+}
+
+TermArgTrie * TermDb::getTermArgTrie( Node eqc, Node f ) {
+ computeUfEqcTerms( f );
+ std::map< Node, TermArgTrie >::iterator itut = d_func_map_eqc_trie.find( f );
+ if( itut==d_func_map_eqc_trie.end() ){
+ return NULL;
+ }else{
+ if( eqc.isNull() ){
+ return &itut->second;
+ }else{
+ std::map< TNode, TermArgTrie >::iterator itute = itut->second.d_data.find( eqc );
+ if( itute!=itut->second.d_data.end() ){
+ return &itute->second;
+ }else{
+ return NULL;
+ }
+ }
+ }
+}
+
+TNode TermDb::existsTerm( Node f, Node n ) {
+ computeArgReps( n );
+ return d_func_map_trie[f].existsTerm( d_arg_reps[n] );
+}
+
Node TermDb::getModelBasisTerm( TypeNode tn, int i ){
if( d_model_basis_term.find( tn )==d_model_basis_term.end() ){
Node mbt;
@@ -448,14 +624,15 @@ void getSelfSel( const DatatypeConstructor& dc, Node n, TypeNode ntn, std::vecto
Node TermDb::mkSkolemizedBody( Node f, Node n, std::vector< TypeNode >& argTypes, std::vector< TNode >& fvs,
- std::vector< Node >& sk ) {
+ std::vector< Node >& sk, Node& sub, std::vector< unsigned >& sub_vars ) {
+ Assert( sk.empty() || sk.size()==f[0].getNumChildren() );
//calculate the variables and substitution
std::vector< TNode > ind_vars;
std::vector< unsigned > ind_var_indicies;
std::vector< TNode > vars;
std::vector< unsigned > var_indicies;
for( unsigned i=0; i<f[0].getNumChildren(); i++ ){
- if( options::dtStcInduction() && datatypes::DatatypesRewriter::isTermDatatype( f[0][i] ) ){
+ if( isInductionTerm( f[0][i] ) ){
ind_vars.push_back( f[0][i] );
ind_var_indicies.push_back( i );
}else{
@@ -463,19 +640,23 @@ Node TermDb::mkSkolemizedBody( Node f, Node n, std::vector< TypeNode >& argTypes
var_indicies.push_back( i );
}
Node s;
- //make the new function symbol
- if( argTypes.empty() ){
- s = NodeManager::currentNM()->mkSkolem( "skv", f[0][i].getType(), "created during skolemization" );
+ //make the new function symbol or use existing
+ if( i>=sk.size() ){
+ if( argTypes.empty() ){
+ s = NodeManager::currentNM()->mkSkolem( "skv", f[0][i].getType(), "created during skolemization" );
+ }else{
+ TypeNode typ = NodeManager::currentNM()->mkFunctionType( argTypes, f[0][i].getType() );
+ Node op = NodeManager::currentNM()->mkSkolem( "skop", typ, "op created during pre-skolemization" );
+ //DOTHIS: set attribute on op, marking that it should not be selected as trigger
+ std::vector< Node > funcArgs;
+ funcArgs.push_back( op );
+ funcArgs.insert( funcArgs.end(), fvs.begin(), fvs.end() );
+ s = NodeManager::currentNM()->mkNode( kind::APPLY_UF, funcArgs );
+ }
+ sk.push_back( s );
}else{
- TypeNode typ = NodeManager::currentNM()->mkFunctionType( argTypes, f[0][i].getType() );
- Node op = NodeManager::currentNM()->mkSkolem( "skop", typ, "op created during pre-skolemization" );
- //DOTHIS: set attribute on op, marking that it should not be selected as trigger
- std::vector< Node > funcArgs;
- funcArgs.push_back( op );
- funcArgs.insert( funcArgs.end(), fvs.begin(), fvs.end() );
- s = NodeManager::currentNM()->mkNode( kind::APPLY_UF, funcArgs );
+ Assert( sk[i].getType()==f[0][i].getType() );
}
- sk.push_back( s );
}
Node ret;
if( vars.empty() ){
@@ -489,44 +670,57 @@ Node TermDb::mkSkolemizedBody( Node f, Node n, std::vector< TypeNode >& argTypes
ret = n.substitute( vars.begin(), vars.end(), var_sk.begin(), var_sk.end() );
}
if( !ind_vars.empty() ){
- Trace("stc-ind") << "Ind strengthen : (not " << f << ")" << std::endl;
- Trace("stc-ind") << "Skolemized is : " << ret << std::endl;
- Node nret;
+ Trace("sk-ind") << "Ind strengthen : (not " << f << ")" << std::endl;
+ Trace("sk-ind") << "Skolemized is : " << ret << std::endl;
Node n_str_ind;
TypeNode tn = ind_vars[0].getType();
- if( datatypes::DatatypesRewriter::isTypeDatatype(tn) ){
- Node k = sk[ind_var_indicies[0]];
+ Node k = sk[ind_var_indicies[0]];
+ Node nret = ret.substitute( ind_vars[0], k );
+ //note : everything is under a negation
+ //the following constructs ~( R( x, k ) => ~P( x ) )
+ if( options::dtStcInduction() && datatypes::DatatypesRewriter::isTypeDatatype(tn) ){
const Datatype& dt = ((DatatypeType)(tn).toType()).getDatatype();
std::vector< Node > disj;
for( unsigned i=0; i<dt.getNumConstructors(); i++ ){
- std::vector< Node > selfSel;
- getSelfSel( dt[i], k, tn, selfSel );
- std::vector< Node > conj;
- conj.push_back( NodeManager::currentNM()->mkNode( APPLY_TESTER, Node::fromExpr( dt[i].getTester() ), k ).negate() );
- for( unsigned j=0; j<selfSel.size(); j++ ){
- conj.push_back( ret.substitute( ind_vars[0], selfSel[j] ).negate() );
- }
- disj.push_back( conj.size()==1 ? conj[0] : NodeManager::currentNM()->mkNode( OR, conj ) );
+ std::vector< Node > selfSel;
+ getSelfSel( dt[i], k, tn, selfSel );
+ std::vector< Node > conj;
+ conj.push_back( NodeManager::currentNM()->mkNode( APPLY_TESTER, Node::fromExpr( dt[i].getTester() ), k ).negate() );
+ for( unsigned j=0; j<selfSel.size(); j++ ){
+ conj.push_back( ret.substitute( ind_vars[0], selfSel[j] ).negate() );
+ }
+ disj.push_back( conj.size()==1 ? conj[0] : NodeManager::currentNM()->mkNode( OR, conj ) );
}
Assert( !disj.empty() );
n_str_ind = disj.size()==1 ? disj[0] : NodeManager::currentNM()->mkNode( AND, disj );
- Trace("stc-ind") << "Strengthening is : " << n_str_ind << std::endl;
- nret = ret.substitute( ind_vars[0], k );
+ }else if( options::intWfInduction() && tn.isInteger() ){
+ Node icond = NodeManager::currentNM()->mkNode( GEQ, k, NodeManager::currentNM()->mkConst( Rational(0) ) );
+ Node iret = ret.substitute( ind_vars[0], NodeManager::currentNM()->mkNode( MINUS, k, NodeManager::currentNM()->mkConst( Rational(1) ) ) ).negate();
+ n_str_ind = NodeManager::currentNM()->mkNode( OR, icond.negate(), iret );
+ n_str_ind = NodeManager::currentNM()->mkNode( AND, icond, n_str_ind );
}else{
- Trace("stc-ind") << "Unknown induction for term : " << ind_vars[0] << ", type = " << tn << std::endl;
+ Trace("sk-ind") << "Unknown induction for term : " << ind_vars[0] << ", type = " << tn << std::endl;
Assert( false );
}
-
+ Trace("sk-ind") << "Strengthening is : " << n_str_ind << std::endl;
+
std::vector< Node > rem_ind_vars;
rem_ind_vars.insert( rem_ind_vars.end(), ind_vars.begin()+1, ind_vars.end() );
if( !rem_ind_vars.empty() ){
Node bvl = NodeManager::currentNM()->mkNode( BOUND_VAR_LIST, rem_ind_vars );
nret = NodeManager::currentNM()->mkNode( FORALL, bvl, nret );
+ nret = Rewriter::rewrite( nret );
+ sub = nret;
+ sub_vars.insert( sub_vars.end(), ind_var_indicies.begin()+1, ind_var_indicies.end() );
n_str_ind = NodeManager::currentNM()->mkNode( FORALL, bvl, n_str_ind.negate() ).negate();
}
ret = NodeManager::currentNM()->mkNode( OR, nret, n_str_ind );
}
Trace("quantifiers-sk") << "mkSkolem body for " << f << " returns : " << ret << std::endl;
+ //if it has an instantiation level, set the skolemized body to that level
+ if( f.hasAttribute(InstLevelAttribute()) ){
+ theory::QuantifiersEngine::setInstantiationLevelAttr( ret, f.getAttribute(InstLevelAttribute()) );
+ }
return ret;
}
@@ -535,7 +729,17 @@ Node TermDb::getSkolemizedBody( Node f ){
if( d_skolem_body.find( f )==d_skolem_body.end() ){
std::vector< TypeNode > fvTypes;
std::vector< TNode > fvs;
- d_skolem_body[ f ] = mkSkolemizedBody( f, f[1], fvTypes, fvs, d_skolem_constants[f] );
+ Node sub;
+ std::vector< unsigned > sub_vars;
+ d_skolem_body[ f ] = mkSkolemizedBody( f, f[1], fvTypes, fvs, d_skolem_constants[f], sub, sub_vars );
+ //store sub quantifier information
+ if( !sub.isNull() ){
+ //if we are skolemizing one at a time, we already know the skolem constants of the sub-quantified formula, store them
+ Assert( d_skolem_constants[sub].empty() );
+ for( unsigned i=0; i<sub_vars.size(); i++ ){
+ d_skolem_constants[sub].push_back( d_skolem_constants[f][sub_vars[i]] );
+ }
+ }
Assert( d_skolem_constants[f].size()==f[0].getNumChildren() );
if( options::sortInference() ){
for( unsigned i=0; i<d_skolem_constants[f].size(); i++ ){
@@ -547,6 +751,27 @@ Node TermDb::getSkolemizedBody( Node f ){
return d_skolem_body[ f ];
}
+Node TermDb::getEnumerateTerm( TypeNode tn, unsigned index ) {
+ std::map< TypeNode, unsigned >::iterator it = d_typ_enum_map.find( tn );
+ unsigned teIndex;
+ if( it==d_typ_enum_map.end() ){
+ teIndex = (int)d_typ_enum.size();
+ d_typ_enum_map[tn] = teIndex;
+ d_typ_enum.push_back( TypeEnumerator(tn) );
+ }else{
+ teIndex = it->second;
+ }
+ while( index>=d_enum_terms[tn].size() ){
+ if( d_typ_enum[teIndex].isFinished() ){
+ return Node::null();
+ }
+ d_enum_terms[tn].push_back( *d_typ_enum[teIndex] );
+ ++d_typ_enum[teIndex];
+ }
+ return d_enum_terms[tn][index];
+}
+
+
Node TermDb::getFreeVariableForInstConstant( Node n ){
TypeNode tn = n.getType();
if( d_free_vars.find( tn )==d_free_vars.end() ){
@@ -752,6 +977,17 @@ void TermDb::registerTrigger( theory::inst::Trigger* tr, Node op ){
}
}
+bool TermDb::isInductionTerm( Node n ) {
+ if( options::dtStcInduction() && datatypes::DatatypesRewriter::isTermDatatype( n ) ){
+ return true;
+ }
+ if( options::intWfInduction() && n.getType().isInteger() ){
+ return true;
+ }
+ return false;
+}
+
+
bool TermDb::isRewriteRule( Node q ) {
return !getRewriteRule( q ).isNull();
}
@@ -763,3 +999,147 @@ Node TermDb::getRewriteRule( Node q ) {
return Node::null();
}
}
+
+bool TermDb::isFunDef( Node q ) {
+ if( q.getKind()==FORALL && ( q[1].getKind()==EQUAL || q[1].getKind()==IFF ) && q[1][0].getKind()==APPLY_UF && q.getNumChildren()==3 ){
+ for( unsigned i=0; i<q[2].getNumChildren(); i++ ){
+ if( q[2][i].getKind()==INST_ATTRIBUTE ){
+ if( q[2][i][0].getAttribute(FunDefAttribute()) ){
+ return true;
+ }
+ }
+ }
+ }
+ return false;
+}
+
+
+void TermDb::computeAttributes( Node q ) {
+ if( q.getNumChildren()==3 ){
+ for( unsigned i=0; i<q[2].getNumChildren(); i++ ){
+ Trace("quant-attr-debug") << "Check : " << q[2][i] << " " << q[2][i].getKind() << std::endl;
+ if( q[2][i].getKind()==INST_ATTRIBUTE ){
+ Node avar = q[2][i][0];
+ if( avar.getAttribute(AxiomAttribute()) ){
+ Trace("quant-attr") << "Attribute : axiom : " << q << std::endl;
+ d_qattr_axiom[q] = true;
+ }
+ if( avar.getAttribute(ConjectureAttribute()) ){
+ Trace("quant-attr") << "Attribute : conjecture : " << q << std::endl;
+ d_qattr_conjecture[q] = true;
+ }
+ if( avar.getAttribute(FunDefAttribute()) ){
+ Trace("quant-attr") << "Attribute : function definition : " << q << std::endl;
+ d_qattr_fundef[q] = true;
+ Assert( q[1].getKind()==EQUAL || q[1].getKind()==IFF );
+ Assert( q[1][0].getKind()==APPLY_UF );
+ Node f = q[1][0].getOperator();
+ if( d_fun_defs.find( f )!=d_fun_defs.end() ){
+ Message() << "Cannot define function " << f << " more than once." << std::endl;
+ exit( 0 );
+ }
+ d_fun_defs[f] = true;
+ }
+ if( avar.getAttribute(SygusAttribute()) ){
+ //should be nested existential
+ Assert( q[1].getKind()==NOT );
+ Assert( q[1][0].getKind()==FORALL );
+ Trace("quant-attr") << "Attribute : sygus : " << q << std::endl;
+ d_qattr_sygus[q] = true;
+ if( d_quantEngine->getCegInstantiation()==NULL ){
+ Trace("quant-warn") << "WARNING : ceg instantiation is null, and we have : " << q << std::endl;
+ }
+ d_quantEngine->setOwner( q, d_quantEngine->getCegInstantiation() );
+ }
+ if( avar.getAttribute(SynthesisAttribute()) ){
+ Trace("quant-attr") << "Attribute : synthesis : " << q << std::endl;
+ d_qattr_synthesis[q] = true;
+ if( d_quantEngine->getCegInstantiation()==NULL ){
+ Trace("quant-warn") << "WARNING : ceg instantiation is null, and we have : " << q << std::endl;
+ }
+ d_quantEngine->setOwner( q, d_quantEngine->getCegInstantiation() );
+ }
+ if( avar.hasAttribute(QuantInstLevelAttribute()) ){
+ d_qattr_qinstLevel[q] = avar.getAttribute(QuantInstLevelAttribute());
+ Trace("quant-attr") << "Attribute : quant inst level " << d_qattr_qinstLevel[q] << " : " << q << std::endl;
+ }
+ if( avar.hasAttribute(RrPriorityAttribute()) ){
+ d_qattr_rr_priority[q] = avar.getAttribute(RrPriorityAttribute());
+ Trace("quant-attr") << "Attribute : rr priority " << d_qattr_rr_priority[q] << " : " << q << std::endl;
+ }
+ if( avar.getKind()==REWRITE_RULE ){
+ Trace("quant-attr") << "Attribute : rewrite rule : " << q << std::endl;
+ Assert( i==0 );
+ if( d_quantEngine->getRewriteEngine()==NULL ){
+ Trace("quant-warn") << "WARNING : rewrite engine is null, and we have : " << q << std::endl;
+ }
+ //set rewrite engine as owner
+ d_quantEngine->setOwner( q, d_quantEngine->getRewriteEngine() );
+ }
+ }
+ }
+ }
+}
+
+bool TermDb::isQAttrConjecture( Node q ) {
+ std::map< Node, bool >::iterator it = d_qattr_conjecture.find( q );
+ if( it==d_qattr_conjecture.end() ){
+ return false;
+ }else{
+ return it->second;
+ }
+}
+
+bool TermDb::isQAttrAxiom( Node q ) {
+ std::map< Node, bool >::iterator it = d_qattr_axiom.find( q );
+ if( it==d_qattr_axiom.end() ){
+ return false;
+ }else{
+ return it->second;
+ }
+}
+
+bool TermDb::isQAttrFunDef( Node q ) {
+ std::map< Node, bool >::iterator it = d_qattr_fundef.find( q );
+ if( it==d_qattr_fundef.end() ){
+ return false;
+ }else{
+ return it->second;
+ }
+}
+
+bool TermDb::isQAttrSygus( Node q ) {
+ std::map< Node, bool >::iterator it = d_qattr_sygus.find( q );
+ if( it==d_qattr_sygus.end() ){
+ return false;
+ }else{
+ return it->second;
+ }
+}
+
+bool TermDb::isQAttrSynthesis( Node q ) {
+ std::map< Node, bool >::iterator it = d_qattr_synthesis.find( q );
+ if( it==d_qattr_synthesis.end() ){
+ return false;
+ }else{
+ return it->second;
+ }
+}
+
+int TermDb::getQAttrQuantInstLevel( Node q ) {
+ std::map< Node, int >::iterator it = d_qattr_qinstLevel.find( q );
+ if( it==d_qattr_qinstLevel.end() ){
+ return -1;
+ }else{
+ return it->second;
+ }
+}
+
+int TermDb::getQAttrRewriteRulePriority( Node q ) {
+ std::map< Node, int >::iterator it = d_qattr_rr_priority.find( q );
+ if( it==d_qattr_rr_priority.end() ){
+ return -1;
+ }else{
+ return it->second;
+ }
+}
diff --git a/src/theory/quantifiers/term_database.h b/src/theory/quantifiers/term_database.h
index c839d08d7..e40635d4e 100644
--- a/src/theory/quantifiers/term_database.h
+++ b/src/theory/quantifiers/term_database.h
@@ -19,12 +19,33 @@
#include "expr/attribute.h"
#include "theory/theory.h"
+#include "theory/type_enumerator.h"
#include <map>
namespace CVC4 {
namespace theory {
+/** Attribute true for quantifiers that are axioms */
+struct AxiomAttributeId {};
+typedef expr::Attribute< AxiomAttributeId, bool > AxiomAttribute;
+
+/** Attribute true for quantifiers that are conjecture */
+struct ConjectureAttributeId {};
+typedef expr::Attribute< ConjectureAttributeId, bool > ConjectureAttribute;
+
+/** Attribute true for function definition quantifiers */
+struct FunDefAttributeId {};
+typedef expr::Attribute< FunDefAttributeId, bool > FunDefAttribute;
+
+/** Attribute true for quantifiers that are SyGus conjectures */
+struct SygusAttributeId {};
+typedef expr::Attribute< SygusAttributeId, bool > SygusAttribute;
+
+/** Attribute true for quantifiers that are synthesis conjectures */
+struct SynthesisAttributeId {};
+typedef expr::Attribute< SynthesisAttributeId, bool > SynthesisAttribute;
+
/** Attribute true for nodes that should not be used for matching */
struct NoMatchAttributeId {};
/** use the special for boolean flag */
@@ -55,6 +76,13 @@ typedef expr::Attribute<ModelBasisArgAttributeId, uint64_t> ModelBasisArgAttribu
struct BoundIntLitAttributeId {};
typedef expr::Attribute<BoundIntLitAttributeId, uint64_t> BoundIntLitAttribute;
+//for quantifier instantiation level
+struct QuantInstLevelAttributeId {};
+typedef expr::Attribute<QuantInstLevelAttributeId, uint64_t> QuantInstLevelAttribute;
+
+//rewrite-rule priority
+struct RrPriorityAttributeId {};
+typedef expr::Attribute<RrPriorityAttributeId, uint64_t> RrPriorityAttribute;
class QuantifiersEngine;
@@ -69,14 +97,14 @@ namespace rrinst{
namespace quantifiers {
class TermArgTrie {
-private:
- bool addTerm2( QuantifiersEngine* qe, Node n, int argIndex );
public:
/** the data */
- std::map< Node, TermArgTrie > d_data;
+ std::map< TNode, TermArgTrie > d_data;
public:
- bool addTerm( QuantifiersEngine* qe, Node n ) { return addTerm2( qe, n, 0 ); }
+ TNode existsTerm( std::vector< TNode >& reps, int argIndex = 0 );
+ bool addTerm( TNode n, std::vector< TNode >& reps, int argIndex = 0 );
void debugPrint( const char * c, Node n, unsigned depth = 0 );
+ void clear() { d_data.clear(); }
};/* class TermArgTrie */
@@ -103,6 +131,9 @@ private:
public:
TermDb( context::Context* c, context::UserContext* u, QuantifiersEngine* qe );
~TermDb(){}
+ /** boolean terms */
+ Node d_true;
+ Node d_false;
/** ground terms */
unsigned getNumGroundTerms( Node f );
/** count number of non-redundant ground terms per operator */
@@ -111,16 +142,34 @@ public:
std::map< Node, std::vector< Node > > d_op_map;
/** map from APPLY_UF functions to trie */
std::map< Node, TermArgTrie > d_func_map_trie;
- /** map from APPLY_UF predicates to trie */
- std::map< Node, TermArgTrie > d_pred_map_trie[2];
+ std::map< Node, TermArgTrie > d_func_map_eqc_trie;
+ /**mapping from UF terms to representatives of their arguments */
+ std::map< TNode, std::vector< TNode > > d_arg_reps;
/** map from type nodes to terms of that type */
std::map< TypeNode, std::vector< Node > > d_type_map;
/** add a term to the database */
void addTerm( Node n, std::set< Node >& added, bool withinQuant = false );
/** reset (calculate which terms are active) */
void reset( Theory::Effort effort );
- /** get operation */
+ /** get operator*/
Node getOperator( Node n );
+ /** get term arg index */
+ TermArgTrie * getTermArgTrie( Node f );
+ TermArgTrie * getTermArgTrie( Node eqc, Node f );
+ /** exists term */
+ TNode existsTerm( Node f, Node n );
+ /** compute arg reps */
+ void computeArgReps( TNode n );
+ /** compute uf eqc terms */
+ void computeUfEqcTerms( TNode f );
+ /** evaluate a term under a substitution. Return representative in EE if possible.
+ * subsRep is whether subs contains only representatives
+ */
+ TNode evaluateTerm( TNode n, std::map< TNode, TNode >& subs, bool subsRep );
+ /** same as above, but without substitution */
+ TNode evaluateTerm( TNode n );
+ /** is entailed (incomplete check) */
+ bool isEntailed( TNode n, std::map< TNode, TNode >& subs, bool subsRep, bool pol );
public:
/** parent structure (for efficient E-matching):
n -> op -> index -> L
@@ -197,6 +246,8 @@ public:
public:
//get bound variables in n
static void getBoundVars( Node n, std::vector< Node >& bvs);
+
+
//for skolem
private:
/** map from universal quantifiers to their skolemized body */
@@ -206,10 +257,23 @@ public:
std::map< Node, std::vector< Node > > d_skolem_constants;
/** make the skolemized body f[e/x] */
static Node mkSkolemizedBody( Node f, Node n, std::vector< TypeNode >& fvTypes, std::vector< TNode >& fvs,
- std::vector< Node >& sk );
+ std::vector< Node >& sk, Node& sub, std::vector< unsigned >& sub_vars );
/** get the skolemized body */
Node getSkolemizedBody( Node f);
-
+ /** is induction variable */
+ static bool isInductionTerm( Node n );
+
+//for ground term enumeration
+private:
+ /** ground terms enumerated for types */
+ std::map< TypeNode, std::vector< Node > > d_enum_terms;
+ //type enumerators
+ std::map< TypeNode, unsigned > d_typ_enum_map;
+ std::vector< TypeEnumerator > d_typ_enum;
+public:
+ //get nth term for type
+ Node getEnumerateTerm( TypeNode tn, unsigned index );
+
//miscellaneous
public:
/** map from universal quantifiers to the list of variables */
@@ -245,11 +309,43 @@ public:
int isInstanceOf( Node n1, Node n2 );
/** filter all nodes that have instances */
void filterInstances( std::vector< Node >& nodes );
-public:
+
+private:
+ std::map< Node, bool > d_fun_defs;
+public: //general queries concerning quantified formulas wrt modules
/** is quantifier treated as a rewrite rule? */
static bool isRewriteRule( Node q );
/** get the rewrite rule associated with the quanfied formula */
static Node getRewriteRule( Node q );
+ /** is fun def */
+ static bool isFunDef( Node q );
+//attributes
+private:
+ std::map< Node, bool > d_qattr_conjecture;
+ std::map< Node, bool > d_qattr_axiom;
+ std::map< Node, bool > d_qattr_fundef;
+ std::map< Node, bool > d_qattr_sygus;
+ std::map< Node, bool > d_qattr_synthesis;
+ std::map< Node, int > d_qattr_rr_priority;
+ std::map< Node, int > d_qattr_qinstLevel;
+ //record attributes
+ void computeAttributes( Node q );
+public:
+ /** is conjecture */
+ bool isQAttrConjecture( Node q );
+ /** is axiom */
+ bool isQAttrAxiom( Node q );
+ /** is function definition */
+ bool isQAttrFunDef( Node q );
+ /** is sygus conjecture */
+ bool isQAttrSygus( Node q );
+ /** is synthesis conjecture */
+ bool isQAttrSynthesis( Node q );
+ /** get instantiation level */
+ int getQAttrQuantInstLevel( Node q );
+ /** get rewrite rule priority */
+ int getQAttrRewriteRulePriority( Node q );
+
};/* class TermDb */
}/* CVC4::theory::quantifiers namespace */
diff --git a/src/theory/quantifiers/theory_quantifiers.cpp b/src/theory/quantifiers/theory_quantifiers.cpp
index 4ba3c499d..6dac8a72d 100644
--- a/src/theory/quantifiers/theory_quantifiers.cpp
+++ b/src/theory/quantifiers/theory_quantifiers.cpp
@@ -42,6 +42,11 @@ TheoryQuantifiers::TheoryQuantifiers(Context* c, context::UserContext* u, Output
d_baseDecLevel = -1;
out.handleUserAttribute( "axiom", this );
out.handleUserAttribute( "conjecture", this );
+ out.handleUserAttribute( "fun-def", this );
+ out.handleUserAttribute( "sygus", this );
+ out.handleUserAttribute( "synthesis", this );
+ out.handleUserAttribute( "quant-inst-max-level", this );
+ out.handleUserAttribute( "rr-priority", this );
}
TheoryQuantifiers::~TheoryQuantifiers() {
@@ -107,6 +112,10 @@ void TheoryQuantifiers::collectModelInfo(TheoryModel* m, bool fullModel) {
}
void TheoryQuantifiers::check(Effort e) {
+ if (done() && !fullEffort(e)) {
+ return;
+ }
+
CodeTimer codeTimer(d_theoryTime);
Trace("quantifiers-check") << "quantifiers::check(" << e << ")" << std::endl;
@@ -193,6 +202,6 @@ bool TheoryQuantifiers::restart(){
}
}
-void TheoryQuantifiers::setUserAttribute( const std::string& attr, Node n ){
- QuantifiersAttributes::setUserAttribute( attr, n );
+void TheoryQuantifiers::setUserAttribute(const std::string& attr, Node n, std::vector<Node> node_values, std::string str_value){
+ QuantifiersAttributes::setUserAttribute( attr, n, node_values, str_value );
}
diff --git a/src/theory/quantifiers/theory_quantifiers.h b/src/theory/quantifiers/theory_quantifiers.h
index ffd3c4c59..6febc8417 100644
--- a/src/theory/quantifiers/theory_quantifiers.h
+++ b/src/theory/quantifiers/theory_quantifiers.h
@@ -69,7 +69,7 @@ public:
void shutdown() { }
std::string identify() const { return std::string("TheoryQuantifiers"); }
bool flipDecision();
- void setUserAttribute( const std::string& attr, Node n );
+ void setUserAttribute(const std::string& attr, Node n, std::vector<Node> node_values, std::string str_value);
eq::EqualityEngine* getMasterEqualityEngine() { return d_masterEqualityEngine; }
bool ppDontRewriteSubterm(TNode atom) { return atom.getKind() == kind::FORALL || atom.getKind() == kind::EXISTS; }
private:
diff --git a/src/theory/quantifiers/theory_quantifiers_type_rules.h b/src/theory/quantifiers/theory_quantifiers_type_rules.h
index e4b1732dd..5d86c29c0 100644
--- a/src/theory/quantifiers/theory_quantifiers_type_rules.h
+++ b/src/theory/quantifiers/theory_quantifiers_type_rules.h
@@ -88,6 +88,21 @@ struct QuantifierInstPatternTypeRule {
}
};/* struct QuantifierInstPatternTypeRule */
+struct QuantifierInstNoPatternTypeRule {
+ inline static TypeNode computeType(NodeManager* nodeManager, TNode n, bool check)
+ throw(TypeCheckingExceptionPrivate) {
+ Assert(n.getKind() == kind::INST_NO_PATTERN );
+ return nodeManager->instPatternType();
+ }
+};/* struct QuantifierInstNoPatternTypeRule */
+
+struct QuantifierInstAttributeTypeRule {
+ inline static TypeNode computeType(NodeManager* nodeManager, TNode n, bool check)
+ throw(TypeCheckingExceptionPrivate) {
+ Assert(n.getKind() == kind::INST_ATTRIBUTE );
+ return nodeManager->instPatternType();
+ }
+};/* struct QuantifierInstAttributeTypeRule */
struct QuantifierInstPatternListTypeRule {
inline static TypeNode computeType(NodeManager* nodeManager, TNode n, bool check)
@@ -95,7 +110,7 @@ struct QuantifierInstPatternListTypeRule {
Assert(n.getKind() == kind::INST_PATTERN_LIST );
if( check ){
for( int i=0; i<(int)n.getNumChildren(); i++ ){
- if( n[i].getKind()!=kind::INST_PATTERN ){
+ if( n[i].getKind()!=kind::INST_PATTERN && n[i].getKind()!=kind::INST_NO_PATTERN && n[i].getKind()!=kind::INST_ATTRIBUTE ){
throw TypeCheckingExceptionPrivate(n, "argument of inst pattern list is not inst pattern");
}
}
@@ -141,7 +156,6 @@ public:
}
};/* class RewriteRuleTypeRule */
-
class RRRewriteTypeRule {
public:
diff --git a/src/theory/quantifiers/trigger.cpp b/src/theory/quantifiers/trigger.cpp
index c6ee48057..511103019 100644
--- a/src/theory/quantifiers/trigger.cpp
+++ b/src/theory/quantifiers/trigger.cpp
@@ -188,19 +188,7 @@ Trigger* Trigger::mkTrigger( QuantifiersEngine* qe, Node f, std::vector< Node >&
}
//check for duplicate?
- if( trOption==TR_MAKE_NEW ){
- //static int trNew = 0;
- //static int trOld = 0;
- //Trigger* t = qe->getTermDatabase()->getTrigger( trNodes );
- //if( t ){
- // trOld++;
- //}else{
- // trNew++;
- //}
- //if( (trNew+trOld)%100==0 ){
- // Notice() << "Trigger new old = " << trNew << " " << trOld << std::endl;
- //}
- }else{
+ if( trOption!=TR_MAKE_NEW ){
Trigger* t = qe->getTriggerDatabase()->getTrigger( trNodes );
if( t ){
if( trOption==TR_GET_OLD ){
@@ -215,21 +203,13 @@ Trigger* Trigger::mkTrigger( QuantifiersEngine* qe, Node f, std::vector< Node >&
qe->getTriggerDatabase()->addTrigger( trNodes, t );
return t;
}
+
Trigger* Trigger::mkTrigger( QuantifiersEngine* qe, Node f, Node n, int matchOption, bool keepAll, int trOption, bool smartTriggers ){
std::vector< Node > nodes;
nodes.push_back( n );
return mkTrigger( qe, f, nodes, matchOption, keepAll, trOption, smartTriggers );
}
-bool Trigger::isUsableTrigger( std::vector< Node >& nodes, Node f ){
- for( int i=0; i<(int)nodes.size(); i++ ){
- if( !isUsableTrigger( nodes[i], f ) ){
- return false;
- }
- }
- return true;
-}
-
bool Trigger::isUsable( Node n, Node f ){
if( quantifiers::TermDb::getInstConstAttr(n)==f ){
if( isAtomicTrigger( n ) ){
@@ -243,9 +223,7 @@ bool Trigger::isUsable( Node n, Node f ){
return true;
}else{
std::map< Node, Node > coeffs;
- if( isArithmeticTrigger( f, n, coeffs ) ){
- return true;
- }else if( isBooleanTermTrigger( n ) ){
+ if( isBooleanTermTrigger( n ) ){
return true;
}
}
@@ -324,7 +302,7 @@ bool Trigger::isUsableTrigger( Node n, Node f ){
bool Trigger::isAtomicTrigger( Node n ){
Kind k = n.getKind();
- return ( k==APPLY_UF && !n.getOperator().getAttribute(NoMatchAttribute()) ) ||
+ return ( k==APPLY_UF && !n.getOperator().getAttribute(NoMatchAttribute()) ) ||
( k!=APPLY_UF && isAtomicTriggerKind( k ) );
}
bool Trigger::isAtomicTriggerKind( Kind k ) {
@@ -347,7 +325,7 @@ bool Trigger::isSimpleTrigger( Node n ){
}
-bool Trigger::collectPatTerms2( QuantifiersEngine* qe, Node f, Node n, std::map< Node, bool >& patMap, int tstrt, bool pol, bool hasPol ){
+bool Trigger::collectPatTerms2( QuantifiersEngine* qe, Node f, Node n, std::map< Node, bool >& patMap, int tstrt, std::vector< Node >& exclude, bool pol, bool hasPol ){
if( patMap.find( n )==patMap.end() ){
patMap[ n ] = false;
bool newHasPol = n.getKind()==IFF ? false : hasPol;
@@ -359,14 +337,17 @@ bool Trigger::collectPatTerms2( QuantifiersEngine* qe, Node f, Node n, std::map<
bool retVal = false;
for( int i=0; i<(int)n.getNumChildren(); i++ ){
bool newHasPol2 = (n.getKind()==ITE && i==0) ? false : newHasPol;
- if( collectPatTerms2( qe, f, n[i], patMap, tstrt, newPol, newHasPol2 ) ){
+ if( collectPatTerms2( qe, f, n[i], patMap, tstrt, exclude, newPol, newHasPol2 ) ){
retVal = true;
}
}
if( retVal ){
return true;
}else{
- Node nu = getIsUsableTrigger( n, f, pol, hasPol );
+ Node nu;
+ if( std::find( exclude.begin(), exclude.end(), n )==exclude.end() ){
+ nu = getIsUsableTrigger( n, f, pol, hasPol );
+ }
if( !nu.isNull() ){
patMap[ nu ] = true;
return true;
@@ -377,7 +358,10 @@ bool Trigger::collectPatTerms2( QuantifiersEngine* qe, Node f, Node n, std::map<
}
}else{
bool retVal = false;
- Node nu = getIsUsableTrigger( n, f, pol, hasPol );
+ Node nu;
+ if( std::find( exclude.begin(), exclude.end(), n )==exclude.end() ){
+ nu = getIsUsableTrigger( n, f, pol, hasPol );
+ }
if( !nu.isNull() ){
patMap[ nu ] = true;
if( tstrt==TS_MAX_TRIGGER ){
@@ -389,7 +373,7 @@ bool Trigger::collectPatTerms2( QuantifiersEngine* qe, Node f, Node n, std::map<
if( n.getKind()!=FORALL ){
for( int i=0; i<(int)n.getNumChildren(); i++ ){
bool newHasPol2 = (n.getKind()==ITE && i==0) ? false : newHasPol;
- if( collectPatTerms2( qe, f, n[i], patMap, tstrt, newPol, newHasPol2 ) ){
+ if( collectPatTerms2( qe, f, n[i], patMap, tstrt, exclude, newPol, newHasPol2 ) ){
retVal = true;
}
}
@@ -401,12 +385,70 @@ bool Trigger::collectPatTerms2( QuantifiersEngine* qe, Node f, Node n, std::map<
}
}
-void Trigger::collectPatTerms( QuantifiersEngine* qe, Node f, Node n, std::vector< Node >& patTerms, int tstrt, bool filterInst ){
+bool Trigger::isLocalTheoryExt2( Node n, std::vector< Node >& var_found, std::vector< Node >& patTerms ) {
+ if( !n.getType().isBoolean() && n.getKind()==APPLY_UF ){
+ bool hasVar = false;
+ for( unsigned i=0; i<n.getNumChildren(); i++ ){
+ if( n[i].getKind()==APPLY_UF ){
+ return false;
+ }else if( n[i].getKind()==INST_CONSTANT ){
+ hasVar = true;
+ //if( std::find( var_found.begin(), var_found.end(), n[i]
+ }
+ }
+ if( hasVar ){
+ patTerms.push_back( n );
+ }
+ }else{
+ for( unsigned i=0; i<n.getNumChildren(); i++ ){
+ if( !isLocalTheoryExt2( n, var_found, patTerms ) ){
+ return false;
+ }
+ }
+ }
+ return true;
+}
+
+bool Trigger::isBooleanTermTrigger( Node n ) {
+ if( n.getKind()==ITE ){
+ //check for boolean term converted to ITE
+ if( n[0].getKind()==INST_CONSTANT &&
+ n[1].getKind()==CONST_BITVECTOR &&
+ n[2].getKind()==CONST_BITVECTOR ){
+ if( ((BitVectorType)n[1].getType().toType()).getSize()==1 &&
+ n[1].getConst<BitVector>().toInteger()==1 &&
+ n[2].getConst<BitVector>().toInteger()==0 ){
+ return true;
+ }
+ }
+ }
+ return false;
+}
+
+bool Trigger::isPureTheoryTrigger( Node n ) {
+ if( n.getKind()==APPLY_UF || n.getKind()==VARIABLE || n.getKind()==SKOLEM ){ //|| !quantifiers::TermDb::hasInstConstAttr( n ) ){
+ return false;
+ }else{
+ for( unsigned i=0; i<n.getNumChildren(); i++ ){
+ if( !isPureTheoryTrigger( n[i] ) ){
+ return false;
+ }
+ }
+ return true;
+ }
+}
+
+bool Trigger::isLocalTheoryExt( Node n, std::vector< Node >& patTerms ) {
+ std::vector< Node > var_found;
+ return isLocalTheoryExt2( n, var_found, patTerms );
+}
+
+void Trigger::collectPatTerms( QuantifiersEngine* qe, Node f, Node n, std::vector< Node >& patTerms, int tstrt, std::vector< Node >& exclude, bool filterInst ){
std::map< Node, bool > patMap;
if( filterInst ){
//immediately do not consider any term t for which another term is an instance of t
std::vector< Node > patTerms2;
- collectPatTerms( qe, f, n, patTerms2, TS_ALL, false );
+ collectPatTerms( qe, f, n, patTerms2, TS_ALL, exclude, false );
std::vector< Node > temp;
temp.insert( temp.begin(), patTerms2.begin(), patTerms2.end() );
qe->getTermDatabase()->filterInstances( temp );
@@ -434,7 +476,7 @@ void Trigger::collectPatTerms( QuantifiersEngine* qe, Node f, Node n, std::vecto
}
}
}
- collectPatTerms2( qe, f, n, patMap, tstrt, true, true );
+ collectPatTerms2( qe, f, n, patMap, tstrt, exclude, true, true );
for( std::map< Node, bool >::iterator it = patMap.begin(); it != patMap.end(); ++it ){
if( it->second ){
patTerms.push_back( it->first );
@@ -442,65 +484,91 @@ void Trigger::collectPatTerms( QuantifiersEngine* qe, Node f, Node n, std::vecto
}
}
-bool Trigger::isArithmeticTrigger( Node f, Node n, std::map< Node, Node >& coeffs ){
- if( n.getKind()==PLUS ){
- Assert( coeffs.empty() );
- NodeBuilder<> t(kind::PLUS);
- for( int i=0; i<(int)n.getNumChildren(); i++ ){
+Node Trigger::getInversionVariable( Node n ) {
+ if( n.getKind()==INST_CONSTANT ){
+ return n;
+ }else if( n.getKind()==PLUS || n.getKind()==MULT ){
+ Node ret;
+ for( unsigned i=0; i<n.getNumChildren(); i++ ){
if( quantifiers::TermDb::hasInstConstAttr(n[i]) ){
- if( n[i].getKind()==INST_CONSTANT ){
- if( quantifiers::TermDb::getInstConstAttr(n[i])==f ){
- coeffs[ n[i] ] = Node::null();
- }else{
- coeffs.clear();
- return false;
+ if( ret.isNull() ){
+ ret = getInversionVariable( n[i] );
+ if( ret.isNull() ){
+ Trace("var-trigger-debug") << "No : multiple variables " << n << std::endl;
+ return Node::null();
+ }
+ }else{
+ return Node::null();
+ }
+ }else if( n.getKind()==MULT ){
+ if( !n[i].isConst() ){
+ Trace("var-trigger-debug") << "No : non-linear coefficient " << n << std::endl;
+ return Node::null();
+ }else if( n.getType().isInteger() ){
+ Rational r = n[i].getConst<Rational>();
+ if( r!=Rational(-1) && r!=Rational(1) ){
+ Trace("var-trigger-debug") << "No : not integer coefficient " << n << std::endl;
+ return Node::null();
}
- }else if( !isArithmeticTrigger( f, n[i], coeffs ) ){
- coeffs.clear();
- return false;
}
- }else{
- t << n[i];
}
}
- if( t.getNumChildren()==0 ){
- coeffs[ Node::null() ] = NodeManager::currentNM()->mkConst( Rational(0) );
- }else if( t.getNumChildren()==1 ){
- coeffs[ Node::null() ] = t.getChild( 0 );
- }else{
- coeffs[ Node::null() ] = t;
- }
- return true;
- }else if( n.getKind()==MULT ){
- 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 && quantifiers::TermDb::getInstConstAttr(n[1])==f ){
- if( !quantifiers::TermDb::hasInstConstAttr(n[0]) ){
- coeffs[ n[1] ] = n[0];
- return true;
+ return ret;
+ }else{
+ Trace("var-trigger-debug") << "No : unsupported operator " << n << "." << std::endl;
+ }
+ return Node::null();
+}
+
+Node Trigger::getInversion( Node n, Node x ) {
+ if( n.getKind()==INST_CONSTANT ){
+ return x;
+ }else if( n.getKind()==PLUS || n.getKind()==MULT ){
+ int cindex = -1;
+ for( unsigned i=0; i<n.getNumChildren(); i++ ){
+ if( !quantifiers::TermDb::hasInstConstAttr(n[i]) ){
+ if( n.getKind()==PLUS ){
+ x = NodeManager::currentNM()->mkNode( MINUS, x, n[i] );
+ }else if( n.getKind()==MULT ){
+ Assert( n[i].isConst() );
+ Node coeff = NodeManager::currentNM()->mkConst( Rational(1) / n[i].getConst<Rational>() );
+ x = NodeManager::currentNM()->mkNode( MULT, x, coeff );
+ }
+ }else{
+ Assert( cindex==-1 );
+ cindex = i;
}
}
+ Assert( cindex!=-1 );
+ return getInversion( n[cindex], x );
}
- return false;
+ return Node::null();
}
-bool Trigger::isBooleanTermTrigger( Node n ) {
- if( n.getKind()==ITE ){
- //check for boolean term converted to ITE
- if( n[0].getKind()==INST_CONSTANT &&
- n[1].getKind()==CONST_BITVECTOR &&
- n[2].getKind()==CONST_BITVECTOR ){
- if( ((BitVectorType)n[1].getType().toType()).getSize()==1 &&
- n[1].getConst<BitVector>().toInteger()==1 &&
- n[2].getConst<BitVector>().toInteger()==0 ){
- return true;
+InstMatchGenerator* Trigger::getInstMatchGenerator( Node n ) {
+ if( n.getKind()==INST_CONSTANT ){
+ return NULL;
+ }else{
+ Trace("var-trigger-debug") << "Is " << n << " a variable trigger?" << std::endl;
+ if( isBooleanTermTrigger( n ) ){
+ VarMatchGeneratorBooleanTerm* vmg = new VarMatchGeneratorBooleanTerm( n[0], n[1] );
+ Trace("var-trigger") << "Boolean term trigger : " << n << ", var = " << n[0] << std::endl;
+ return vmg;
+ }else{
+ Node x;
+ if( options::purifyTriggers() ){
+ x = getInversionVariable( n );
+ }
+ if( !x.isNull() ){
+ Node s = getInversion( n, x );
+ VarMatchGeneratorTermSubs* vmg = new VarMatchGeneratorTermSubs( x, s );
+ Trace("var-trigger") << "Term substitution trigger : " << n << ", var = " << x << ", subs = " << s << std::endl;
+ return vmg;
+ }else{
+ return new InstMatchGenerator( n );
}
}
}
- return false;
}
Trigger* TriggerTrie::getTrigger2( std::vector< Node >& nodes ){
diff --git a/src/theory/quantifiers/trigger.h b/src/theory/quantifiers/trigger.h
index 17da6f0d5..482701a82 100644
--- a/src/theory/quantifiers/trigger.h
+++ b/src/theory/quantifiers/trigger.h
@@ -30,6 +30,7 @@ class QuantifiersEngine;
namespace inst {
class IMGenerator;
+class InstMatchGenerator;
//a collect of nodes representing a trigger
class Trigger {
@@ -93,7 +94,9 @@ private:
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, bool pol, bool hasPol );
+ static bool collectPatTerms2( QuantifiersEngine* qe, Node f, Node n, std::map< Node, bool >& patMap, int tstrt, std::vector< Node >& exclude, bool pol, bool hasPol );
+ /** is local theory extensions term */
+ static bool isLocalTheoryExt2( Node n, std::vector< Node >& var_found, std::vector< Node >& patTerms );
public:
//different strategies for choosing trigger terms
enum {
@@ -101,17 +104,20 @@ public:
TS_MIN_TRIGGER,
TS_ALL,
};
- static void collectPatTerms( QuantifiersEngine* qe, Node f, Node n, std::vector< Node >& patTerms, int tstrt, bool filterInst = false );
+ static void collectPatTerms( QuantifiersEngine* qe, Node f, Node n, std::vector< Node >& patTerms, int tstrt, std::vector< Node >& exclude, bool filterInst = false );
public:
/** is usable trigger */
- static bool isUsableTrigger( std::vector< Node >& nodes, Node f );
static bool isUsableTrigger( Node n, Node f );
static bool isAtomicTrigger( Node n );
static bool isAtomicTriggerKind( Kind k );
static bool isSimpleTrigger( Node n );
- /** get pattern arithmetic */
- static bool isArithmeticTrigger( Node f, Node n, std::map< Node, Node >& coeffs );
static bool isBooleanTermTrigger( Node n );
+ static bool isPureTheoryTrigger( Node n );
+ static bool isLocalTheoryExt( Node n, std::vector< Node >& patTerms );
+ /** return data structure for producing matches for this trigger. */
+ static InstMatchGenerator* getInstMatchGenerator( Node n );
+ static Node getInversionVariable( Node n );
+ static Node getInversion( Node n, Node x );
inline void toStream(std::ostream& out) const {
/*
diff --git a/src/theory/quantifiers_engine.cpp b/src/theory/quantifiers_engine.cpp
index c55ffa2a6..46995653f 100644
--- a/src/theory/quantifiers_engine.cpp
+++ b/src/theory/quantifiers_engine.cpp
@@ -25,14 +25,17 @@
#include "theory/quantifiers/first_order_model.h"
#include "theory/quantifiers/term_database.h"
#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/quantifiers/quant_conflict_find.h"
+#include "theory/quantifiers/conjecture_generator.h"
+#include "theory/quantifiers/ce_guided_instantiation.h"
#include "theory/quantifiers/relevant_domain.h"
#include "theory/uf/options.h"
#include "theory/uf/theory_uf.h"
+#include "theory/quantifiers/full_model_check.h"
+#include "theory/quantifiers/qinterval_builder.h"
+#include "theory/quantifiers/ambqi_builder.h"
using namespace std;
using namespace CVC4;
@@ -41,6 +44,34 @@ using namespace CVC4::context;
using namespace CVC4::theory;
using namespace CVC4::theory::inst;
+
+eq::EqualityEngine * QuantifiersModule::getEqualityEngine() {
+ return d_quantEngine->getMasterEqualityEngine();
+}
+
+bool QuantifiersModule::areEqual( TNode n1, TNode n2 ) {
+ eq::EqualityEngine * ee = getEqualityEngine();
+ return n1==n2 || ( ee->hasTerm( n1 ) && ee->hasTerm( n2 ) && ee->areEqual( n1, n2 ) );
+}
+
+bool QuantifiersModule::areDisequal( TNode n1, TNode n2 ) {
+ eq::EqualityEngine * ee = getEqualityEngine();
+ return n1!=n2 && ee->hasTerm( n1 ) && ee->hasTerm( n2 ) && ee->areDisequal( n1, n2, false );
+}
+
+TNode QuantifiersModule::getRepresentative( TNode n ) {
+ eq::EqualityEngine * ee = getEqualityEngine();
+ if( ee->hasTerm( n ) ){
+ return ee->getRepresentative( n );
+ }else{
+ return n;
+ }
+}
+
+quantifiers::TermDb * QuantifiersModule::getTermDatabase() {
+ return d_quantEngine->getTermDatabase();
+}
+
QuantifiersEngine::QuantifiersEngine(context::Context* c, context::UserContext* u, TheoryEngine* te):
d_te( te ),
d_lemmas_produced_c(u){
@@ -50,7 +81,9 @@ d_lemmas_produced_c(u){
//d_rr_tr_trie = new rrinst::TriggerTrie;
//d_eem = new EfficientEMatcher( this );
d_hasAddedLemma = false;
-
+
+ bool needsBuilder = false;
+
Trace("quant-engine-debug") << "Initialize model, mbqi : " << options::mbqiMode() << std::endl;
//the model object
@@ -83,6 +116,12 @@ d_lemmas_produced_c(u){
}else{
d_qcf = NULL;
}
+ if( options::conjectureGen() ){
+ d_sg_gen = new quantifiers::ConjectureGenerator( this, c );
+ d_modules.push_back( d_sg_gen );
+ }else{
+ d_sg_gen = NULL;
+ }
if( !options::finiteModelFind() || options::fmfInstEngine() ){
//the instantiation must set incomplete flag unless finite model finding is turned on
d_inst_engine = new quantifiers::InstantiationEngine( this, !options::finiteModelFind() );
@@ -99,6 +138,7 @@ d_lemmas_produced_c(u){
}
d_model_engine = new quantifiers::ModelEngine( c, this );
d_modules.push_back( d_model_engine );
+ needsBuilder = true;
}else{
d_model_engine = NULL;
d_bint = NULL;
@@ -109,12 +149,43 @@ d_lemmas_produced_c(u){
}else{
d_rr_engine = NULL;
}
+ if( options::ceGuidedInst() ){
+ d_ceg_inst = new quantifiers::CegInstantiation( this, c );
+ d_modules.push_back( d_ceg_inst );
+ needsBuilder = true;
+ }else{
+ d_ceg_inst = NULL;
+ }
+
+ if( needsBuilder ){
+ Trace("quant-engine-debug") << "Initialize model engine, mbqi : " << options::mbqiMode() << " " << options::fmfBoundInt() << std::endl;
+ if( options::mbqiMode()==quantifiers::MBQI_FMC || options::mbqiMode()==quantifiers::MBQI_FMC_INTERVAL ||
+ options::mbqiMode()==quantifiers::MBQI_TRUST || options::fmfBoundInt() ){
+ Trace("quant-engine-debug") << "...make fmc builder." << std::endl;
+ d_builder = new quantifiers::fmcheck::FullModelChecker( c, this );
+ }else if( options::mbqiMode()==quantifiers::MBQI_INTERVAL ){
+ Trace("quant-engine-debug") << "...make interval builder." << std::endl;
+ d_builder = new quantifiers::QIntervalBuilder( c, this );
+ }else if( options::mbqiMode()==quantifiers::MBQI_ABS ){
+ Trace("quant-engine-debug") << "...make abs mbqi builder." << std::endl;
+ d_builder = new quantifiers::AbsMbqiBuilder( c, this );
+ }else if( options::mbqiMode()==quantifiers::MBQI_INST_GEN ){
+ Trace("quant-engine-debug") << "...make inst-gen builder." << std::endl;
+ d_builder = new quantifiers::QModelBuilderInstGen( c, this );
+ }else{
+ Trace("quant-engine-debug") << "...make default model builder." << std::endl;
+ d_builder = new quantifiers::QModelBuilderDefault( c, this );
+ }
+ }else{
+ d_builder = NULL;
+ }
//options
d_total_inst_count_debug = 0;
}
QuantifiersEngine::~QuantifiersEngine(){
+ delete d_builder;
delete d_rr_engine;
delete d_bint;
delete d_model_engine;
@@ -126,6 +197,8 @@ QuantifiersEngine::~QuantifiersEngine(){
delete d_tr_trie;
delete d_term_db;
delete d_eq_query;
+ delete d_sg_gen;
+ delete d_ceg_inst;
for(std::map< Node, QuantPhaseReq* >::iterator i = d_phase_reqs.begin(); i != d_phase_reqs.end(); ++i) {
delete (*i).second;
}
@@ -157,58 +230,141 @@ void QuantifiersEngine::finishInit(){
}
}
+QuantifiersModule * QuantifiersEngine::getOwner( Node q ) {
+ std::map< Node, QuantifiersModule * >::iterator it = d_owner.find( q );
+ if( it==d_owner.end() ){
+ return NULL;
+ }else{
+ return it->second;
+ }
+}
+
+void QuantifiersEngine::setOwner( Node q, QuantifiersModule * m ) {
+ QuantifiersModule * mo = getOwner( q );
+ if( mo!=m ){
+ if( mo!=NULL ){
+ Trace("quant-warn") << "WARNING: setting owner of " << q << " to " << ( m ? m->identify() : "null" ) << ", but already has owner " << mo->identify() << "!" << std::endl;
+ }
+ d_owner[q] = m;
+ }
+}
+
+bool QuantifiersEngine::hasOwnership( Node q, QuantifiersModule * m ) {
+ QuantifiersModule * mo = getOwner( q );
+ return mo==m || mo==NULL;
+}
+
void QuantifiersEngine::check( Theory::Effort e ){
CodeTimer codeTimer(d_time);
- bool needsCheck = e>=Theory::EFFORT_LAST_CALL; //always need to check at or above last call
- for( int i=0; i<(int)d_modules.size(); i++ ){
- if( d_modules[i]->needsCheck( e ) ){
- needsCheck = true;
+ bool needsCheck = false;
+ bool needsModel = false;
+ bool needsFullModel = false;
+ std::vector< QuantifiersModule* > qm;
+ if( d_model->getNumAssertedQuantifiers()>0 ){
+ needsCheck = e>=Theory::EFFORT_LAST_CALL; //always need to check at or above last call
+ for( int i=0; i<(int)d_modules.size(); i++ ){
+ if( d_modules[i]->needsCheck( e ) ){
+ qm.push_back( d_modules[i] );
+ needsCheck = true;
+ if( d_modules[i]->needsModel( e ) ){
+ needsModel = true;
+ if( d_modules[i]->needsFullModel( e ) ){
+ needsFullModel = true;
+ }
+ }
+ }
}
}
+ bool defaultBuildModel = false;
if( needsCheck ){
Trace("quant-engine") << "Quantifiers Engine check, level = " << e << std::endl;
+ Trace("quant-engine-debug") << " modules to check : ";
+ for( unsigned i=0; i<qm.size(); i++ ){
+ Trace("quant-engine-debug") << qm[i]->identify() << " ";
+ }
+ Trace("quant-engine-debug") << std::endl;
+ Trace("quant-engine-debug") << " # quantified formulas = " << d_model->getNumAssertedQuantifiers() << std::endl;
+ Trace("quant-engine-debug") << " Theory engine finished : " << !d_te->needCheck() << std::endl;
+
+ Trace("quant-engine-ee") << "Equality engine : " << std::endl;
+ debugPrintEqualityEngine( "quant-engine-ee" );
+
if( !getMasterEqualityEngine()->consistent() ){
Trace("quant-engine") << "Master equality engine not consistent, return." << std::endl;
return;
}
- Trace("quant-engine-debug") << "Resetting modules..." << std::endl;
+ Trace("quant-engine-debug") << "Resetting all modules..." << std::endl;
//reset relevant information
+ d_conflict = false;
d_hasAddedLemma = false;
+
+ //flush previous lemmas (for instance, if was interupted)
+ flushLemmas();
+ if( d_hasAddedLemma ){
+ return;
+ }
+
d_term_db->reset( e );
d_eq_query->reset();
if( d_rel_dom ){
d_rel_dom->reset();
}
+ d_model->reset_round();
for( int i=0; i<(int)d_modules.size(); i++ ){
d_modules[i]->reset_round( e );
}
- Trace("quant-engine-debug") << "Done resetting modules." << std::endl;
+ Trace("quant-engine-debug") << "Done resetting all modules." << std::endl;
if( e==Theory::EFFORT_LAST_CALL ){
- //if effort is last call, try to minimize model first
- if( options::finiteModelFind() ){
- //first, check if we can minimize the model further
- if( !((uf::TheoryUF*)getTheoryEngine()->theoryOf( THEORY_UF ))->getStrongSolver()->minimize() ){
- return;
- }
+ //if effort is last call, try to minimize model first FIXME: remove?
+ uf::StrongSolverTheoryUF * ufss = ((uf::TheoryUF*)getTheoryEngine()->theoryOf( THEORY_UF ))->getStrongSolver();
+ if( ufss && !ufss->minimize() ){
+ return;
}
++(d_statistics.d_instantiation_rounds_lc);
}else if( e==Theory::EFFORT_FULL ){
++(d_statistics.d_instantiation_rounds);
}
- Trace("quant-engine-debug") << "Check with modules..." << std::endl;
- for( int i=0; i<(int)d_modules.size(); i++ ){
- Trace("quant-engine-debug") << "Check " << d_modules[i]->identify().c_str() << "..." << std::endl;
- d_modules[i]->check( e );
+
+ Trace("quant-engine-debug") << "Check modules that needed check..." << std::endl;
+ for( unsigned quant_e = QEFFORT_CONFLICT; quant_e<=QEFFORT_MODEL; quant_e++ ){
+ bool success = true;
+ //build the model if any module requested it
+ if( quant_e==QEFFORT_MODEL && needsModel ){
+ Assert( d_builder!=NULL );
+ Trace("quant-engine-debug") << "Build model, fullModel = " << ( needsFullModel || d_builder->optBuildAtFullModel() ) << "..." << std::endl;
+ d_builder->d_addedLemmas = 0;
+ d_builder->buildModel( d_model, needsFullModel || d_builder->optBuildAtFullModel() );
+ //we are done if model building was unsuccessful
+ if( d_builder->d_addedLemmas>0 ){
+ success = false;
+ }
+ }
+ if( success ){
+ //check each module
+ for( int i=0; i<(int)qm.size(); i++ ){
+ Trace("quant-engine-debug") << "Check " << qm[i]->identify().c_str() << " at effort " << quant_e << "..." << std::endl;
+ qm[i]->check( e, quant_e );
+ }
+ }
+ //flush all current lemmas
+ flushLemmas();
+ //if we have added one, stop
+ if( d_hasAddedLemma ){
+ break;
+ //otherwise, complete the model generation if necessary
+ }else if( quant_e==QEFFORT_MODEL && needsModel && options::produceModels() && !needsFullModel && !d_builder->optBuildAtFullModel() ){
+ Trace("quant-engine-debug") << "Build completed model..." << std::endl;
+ d_builder->buildModel( d_model, true );
+ }
}
- Trace("quant-engine-debug") << "Done check with modules." << std::endl;
+ Trace("quant-engine-debug") << "Done check modules that needed check." << std::endl;
+
//build the model if not done so already
// this happens if no quantifiers are currently asserted and no model-building module is enabled
if( e==Theory::EFFORT_LAST_CALL && !d_hasAddedLemma ){
if( options::produceModels() && !d_model->isModelSet() ){
- Trace("quant-engine-debug") << "Build the model..." << std::endl;
- d_te->getModelBuilder()->buildModel( d_model, true );
- Trace("quant-engine-debug") << "Done building the model." << std::endl;
+ defaultBuildModel = true;
}
if( Trace.isOn("inst-per-quant") ){
for( std::map< Node, int >::iterator it = d_total_inst_debug.begin(); it != d_total_inst_debug.end(); ++it ){
@@ -224,15 +380,22 @@ void QuantifiersEngine::check( Theory::Effort e ){
}
}
Trace("quant-engine") << "Finished quantifiers engine check." << std::endl;
+ }else{
+ if( e==Theory::EFFORT_LAST_CALL && options::produceModels() ){
+ defaultBuildModel = true;
+ }
+ }
+
+ if( defaultBuildModel ){
+ Trace("quant-engine-debug") << "Build the model..." << std::endl;
+ d_te->getModelBuilder()->buildModel( d_model, true );
+ Trace("quant-engine-debug") << "Done building the model." << std::endl;
}
}
void QuantifiersEngine::registerQuantifier( Node f ){
if( std::find( d_quants.begin(), d_quants.end(), f )==d_quants.end() ){
Trace("quant") << "QuantifiersEngine : Register quantifier ";
- if( d_term_db->isRewriteRule( f ) ){
- Trace("quant") << " (rewrite rule)";
- }
Trace("quant") << " : " << f << std::endl;
d_quants.push_back( f );
@@ -240,6 +403,11 @@ void QuantifiersEngine::registerQuantifier( Node f ){
Assert( f.getKind()==FORALL );
//make instantiation constants for f
d_term_db->makeInstantiationConstantsFor( f );
+ d_term_db->computeAttributes( f );
+ QuantifiersModule * qm = getOwner( f );
+ if( qm!=NULL ){
+ Trace("quant") << " Owner : " << qm->identify() << std::endl;
+ }
//register with quantifier relevance
if( d_quant_rel ){
d_quant_rel->registerQuantifier( f );
@@ -261,7 +429,7 @@ void QuantifiersEngine::registerQuantifier( Node f ){
void QuantifiersEngine::registerPattern( std::vector<Node> & pattern) {
for(std::vector<Node>::iterator p = pattern.begin(); p != pattern.end(); ++p){
std::set< Node > added;
- getTermDatabase()->addTerm(*p,added);
+ getTermDatabase()->addTerm( *p, added );
}
}
@@ -314,6 +482,10 @@ Node QuantifiersEngine::getNextDecisionRequest(){
void QuantifiersEngine::addTermToDatabase( Node n, bool withinQuant ){
std::set< Node > added;
getTermDatabase()->addTerm( n, added, withinQuant );
+ //maybe have triggered instantiations if we are doing eager instantiation
+ if( options::eagerInstQuant() ){
+ flushLemmas();
+ }
//added contains also the Node that just have been asserted in this branch
if( d_quant_rel ){
for( std::set< Node >::iterator i=added.begin(), end=added.end(); i!=end; i++ ){
@@ -338,6 +510,7 @@ bool QuantifiersEngine::addInstantiation( Node f, std::vector< Node >& vars, std
Assert( f.getKind()==FORALL );
Assert( vars.size()==terms.size() );
Node body = getInstantiation( f, vars, terms );
+ Trace("inst-assert") << "(assert " << body << ")" << std::endl;
//make the lemma
NodeBuilder<> nb(kind::OR);
nb << f.notNode() << body;
@@ -372,7 +545,7 @@ bool QuantifiersEngine::addInstantiation( Node f, std::vector< Node >& vars, std
}
}
}
- setInstantiationLevelAttr( body, f[1], maxInstLevel+1, terms );
+ setInstantiationLevelAttr( body, f[1], maxInstLevel+1 );
}
Trace("inst-debug") << "*** Lemma is " << lem << std::endl;
++(d_statistics.d_instantiations);
@@ -383,22 +556,54 @@ bool QuantifiersEngine::addInstantiation( Node f, std::vector< Node >& vars, std
}
}
-void QuantifiersEngine::setInstantiationLevelAttr( Node n, Node qn, uint64_t level, std::vector< Node >& inst_terms ){
+void QuantifiersEngine::setInstantiationLevelAttr( Node n, Node qn, uint64_t level ){
+ Trace("inst-level-debug2") << "IL : " << n << " " << qn << " " << level << std::endl;
//if not from the vector of terms we instantiatied
- if( std::find( inst_terms.begin(), inst_terms.end(), n )==inst_terms.end() ){
+ if( qn.getKind()!=BOUND_VARIABLE && n!=qn ){
//if this is a new term, without an instantiation level
- if( n!=qn && !n.hasAttribute(InstLevelAttribute()) ){
+ if( !n.hasAttribute(InstLevelAttribute()) ){
InstLevelAttribute ila;
n.setAttribute(ila,level);
+ Trace("inst-level-debug") << "Set instantiation level " << n << " to " << level << std::endl;
}
- Assert( qn.getKind()!=BOUND_VARIABLE );
Assert( n.getNumChildren()==qn.getNumChildren() );
for( int i=0; i<(int)n.getNumChildren(); i++ ){
- setInstantiationLevelAttr( n[i], qn[i], level, inst_terms );
+ setInstantiationLevelAttr( n[i], qn[i], level );
}
}
}
+void QuantifiersEngine::setInstantiationLevelAttr( Node n, uint64_t level ){
+ if( !n.hasAttribute(InstLevelAttribute()) ){
+ InstLevelAttribute ila;
+ n.setAttribute(ila,level);
+ Trace("inst-level-debug") << "Set instantiation level " << n << " to " << level << std::endl;
+ }
+ for( int i=0; i<(int)n.getNumChildren(); i++ ){
+ setInstantiationLevelAttr( n[i], level );
+ }
+}
+
+bool QuantifiersEngine::isTermEligibleForInstantiation( Node n, Node f, bool print ) {
+ if( n.hasAttribute(InstLevelAttribute()) ){
+ int fml = d_term_db->getQAttrQuantInstLevel( f );
+ unsigned ml = fml>=0 ? fml : options::instMaxLevel();
+
+ if( n.getAttribute(InstLevelAttribute())>ml ){
+ Trace("inst-add-debug") << "Term " << n << " has instantiation level " << n.getAttribute(InstLevelAttribute());
+ Trace("inst-add-debug") << ", which is more than maximum allowed level " << ml << " for this quantified formula." << std::endl;
+ return false;
+ }
+ }else{
+ if( options::instLevelInputOnly() ){
+ Trace("inst-add-debug") << "Term " << n << " does not have an instantiation level." << std::endl;
+ return false;
+ }
+ }
+ return true;
+}
+
+
Node QuantifiersEngine::getSubstitute( Node n, std::vector< Node >& terms ){
if( n.getKind()==INST_CONSTANT ){
Debug("check-inst") << "Substitute inst constant : " << n << std::endl;
@@ -484,8 +689,8 @@ bool QuantifiersEngine::existsInstantiation( Node f, InstMatch& m, bool modEq, b
}
}
}
- //also check model engine (it may contain instantiations internally)
- if( d_model_engine->getModelBuilder()->existsInstantiation( f, m, modEq, modInst ) ){
+ //also check model builder (it may contain instantiations internally)
+ if( d_builder && d_builder->existsInstantiation( f, m, modEq, modInst ) ){
return true;
}
return false;
@@ -511,7 +716,14 @@ bool QuantifiersEngine::addLemma( Node lem, bool doCache ){
}
}
+void QuantifiersEngine::addRequirePhase( Node lit, bool req ){
+ d_phase_req_waiting[lit] = req;
+}
+
bool QuantifiersEngine::addInstantiation( Node f, InstMatch& m, bool mkRep, bool modEq, bool modInst ){
+ // For resource-limiting (also does a time check).
+ getOutputChannel().safePoint();
+
std::vector< Node > terms;
//make sure there are values for each variable we are instantiating
for( size_t i=0; i<f[0].getNumChildren(); i++ ){
@@ -536,24 +748,32 @@ bool QuantifiersEngine::addInstantiation( Node f, std::vector< Node >& terms, bo
if( mkRep ){
//pick the best possible representative for instantiation, based on past use and simplicity of term
terms[i] = d_eq_query->getInternalRepresentative( terms[i], f, i );
- //Trace("inst-add-debug") << " (" << terms[i] << ")";
+ Trace("inst-add-debug2") << " (" << terms[i] << ")";
}
}
Trace("inst-add-debug") << std::endl;
+ //check based on instantiation level
if( options::instMaxLevel()!=-1 ){
for( unsigned i=0; i<terms.size(); i++ ){
- if( terms[i].hasAttribute(InstLevelAttribute()) &&
- (int)terms[i].getAttribute(InstLevelAttribute())>options::instMaxLevel() ){
- Trace("inst-add-debug") << "Term " << terms[i] << " has instantiation level " << terms[i].getAttribute(InstLevelAttribute());
- Trace("inst-add-debug") << ", which is more than maximum allowed level " << options::instMaxLevel() << std::endl;
+ if( !isTermEligibleForInstantiation( terms[i], f, true ) ){
return false;
}
}
}
+ //check for entailment
+ if( options::instNoEntail() ){
+ std::map< TNode, TNode > subs;
+ for( unsigned i=0; i<terms.size(); i++ ){
+ subs[f[0][i]] = terms[i];
+ }
+ if( d_term_db->isEntailed( f[1], subs, false, true ) ){
+ Trace("inst-add-debug") << " -> Currently entailed." << std::endl;
+ return false;
+ }
+ }
//check for duplication
- ///*
bool alreadyExists = false;
if( options::incrementalSolving() ){
Trace("inst-add-debug") << "Adding into context-dependent inst trie, modEq = " << modEq << ", modInst = " << modInst << std::endl;
@@ -575,9 +795,10 @@ bool QuantifiersEngine::addInstantiation( Node f, std::vector< Node >& terms, bo
++(d_statistics.d_inst_duplicate_eq);
return false;
}
- //*/
+
//add the instantiation
+ Trace("inst-add-debug") << "Constructing instantiation..." << std::endl;
bool addedInst = addInstantiation( f, d_term_db->d_vars[f], terms );
//report the result
if( addedInst ){
@@ -608,18 +829,21 @@ bool QuantifiersEngine::addSplitEquality( Node n1, Node n2, bool reqPhase, bool
return addSplit( fm );
}
-void QuantifiersEngine::flushLemmas( OutputChannel* out ){
+void QuantifiersEngine::flushLemmas(){
if( !d_lemmas_waiting.empty() ){
- if( !out ){
- out = &getOutputChannel();
- }
//take default output channel if none is provided
d_hasAddedLemma = true;
for( int i=0; i<(int)d_lemmas_waiting.size(); i++ ){
- out->lemma( d_lemmas_waiting[i], false, true );
+ getOutputChannel().lemma( d_lemmas_waiting[i], false, true );
}
d_lemmas_waiting.clear();
}
+ if( !d_phase_req_waiting.empty() ){
+ for( std::map< Node, bool >::iterator it = d_phase_req_waiting.begin(); it != d_phase_req_waiting.end(); ++it ){
+ getOutputChannel().requirePhase( it->first, it->second );
+ }
+ d_phase_req_waiting.clear();
+ }
}
void QuantifiersEngine::getPhaseReqTerms( Node f, std::vector< Node >& nodes ){
@@ -718,7 +942,34 @@ QuantifiersEngine::Statistics::~Statistics(){
}
eq::EqualityEngine* QuantifiersEngine::getMasterEqualityEngine(){
- return ((quantifiers::TheoryQuantifiers*)getTheoryEngine()->theoryOf( THEORY_QUANTIFIERS ))->getMasterEqualityEngine();
+ return getTheoryEngine()->getMasterEqualityEngine();
+}
+
+void QuantifiersEngine::debugPrintEqualityEngine( const char * c ) {
+ eq::EqualityEngine* ee = getMasterEqualityEngine();
+ eq::EqClassesIterator eqcs_i = eq::EqClassesIterator( ee );
+ while( !eqcs_i.isFinished() ){
+ TNode r = (*eqcs_i);
+ bool firstTime = true;
+ Trace(c) << " " << r;
+ Trace(c) << " : { ";
+ eq::EqClassIterator eqc_i = eq::EqClassIterator( r, ee );
+ while( !eqc_i.isFinished() ){
+ TNode n = (*eqc_i);
+ if( r!=n ){
+ if( firstTime ){
+ Trace(c) << std::endl;
+ firstTime = false;
+ }
+ Trace(c) << " " << n << std::endl;
+ }
+ ++eqc_i;
+ }
+ if( !firstTime ){ Trace(c) << " "; }
+ Trace(c) << "}" << std::endl;
+ ++eqcs_i;
+ }
+ Trace(c) << std::endl;
}
void EqualityQueryQuantifiersEngine::reset(){
@@ -793,7 +1044,6 @@ Node EqualityQueryQuantifiersEngine::getInternalRepresentative( Node a, Node f,
//if cbqi is active, do not choose instantiation constant terms
if( !options::cbqi() || !quantifiers::TermDb::hasInstConstAttr(eqc[i]) ){
int score = getRepScore( eqc[i], f, index );
- //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;
@@ -809,7 +1059,8 @@ Node EqualityQueryQuantifiersEngine::getInternalRepresentative( Node a, Node f,
}
}
//now, make sure that no other member of the class is an instance
- r_best = getInstance( r_best, eqc );
+ std::hash_map<TNode, Node, TNodeHashFunction> cache;
+ r_best = getInstance( r_best, eqc, cache );
//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;
@@ -916,17 +1167,20 @@ void EqualityQueryQuantifiersEngine::getEquivalenceClass( Node a, std::vector< N
//helper functions
-Node EqualityQueryQuantifiersEngine::getInstance( Node n, std::vector< Node >& eqc ){
+Node EqualityQueryQuantifiersEngine::getInstance( Node n, const std::vector< Node >& eqc, std::hash_map<TNode, Node, TNodeHashFunction>& cache ){
+ if(cache.find(n) != cache.end()) {
+ return cache[n];
+ }
for( size_t i=0; i<n.getNumChildren(); i++ ){
- Node nn = getInstance( n[i], eqc );
+ Node nn = getInstance( n[i], eqc, cache );
if( !nn.isNull() ){
- return nn;
+ return cache[n] = nn;
}
}
if( std::find( eqc.begin(), eqc.end(), n )!=eqc.end() ){
- return n;
+ return cache[n] = n;
}else{
- return Node::null();
+ return cache[n] = Node::null();
}
}
@@ -945,8 +1199,21 @@ int getDepth( Node n ){
}
}
+//smaller the score, the better
int EqualityQueryQuantifiersEngine::getRepScore( Node n, Node f, int index ){
- return d_rep_score.find( n )==d_rep_score.end() ? -1 : d_rep_score[n]; //initial
+ int s;
+ if( options::instMaxLevel()!=-1 ){
+ //score prefer lowest instantiation level
+ if( n.hasAttribute(InstLevelAttribute()) ){
+ s = n.getAttribute(InstLevelAttribute());
+ }else{
+ s = options::instLevelInputOnly() ? -1 : 0;
+ }
+ }else{
+ //score prefers earliest use of this term as a representative
+ s = d_rep_score.find( n )==d_rep_score.end() ? -1 : d_rep_score[n];
+ }
+ return s;
//return ( d_rep_score.find( n )==d_rep_score.end() ? 100 : 0 ) + getDepth( n ); //term depth
}
diff --git a/src/theory/quantifiers_engine.h b/src/theory/quantifiers_engine.h
index 7786e0b70..f56cd0d19 100644
--- a/src/theory/quantifiers_engine.h
+++ b/src/theory/quantifiers_engine.h
@@ -37,6 +37,10 @@ namespace theory {
class QuantifiersEngine;
+namespace quantifiers {
+ class TermDb;
+}
+
class QuantifiersModule {
protected:
QuantifiersEngine* d_quantEngine;
@@ -49,10 +53,14 @@ public:
virtual void finishInit() {}
/* whether this module needs to check this round */
virtual bool needsCheck( Theory::Effort e ) { return e>=Theory::EFFORT_LAST_CALL; }
+ /* whether this module needs a model built */
+ virtual bool needsModel( Theory::Effort e ) { return false; }
+ /* whether this module needs a model built */
+ virtual bool needsFullModel( Theory::Effort e ) { return false; }
/* reset at a round */
virtual void reset_round( Theory::Effort e ){}
/* Call during quantifier engine's check */
- virtual void check( Theory::Effort e ) = 0;
+ virtual void check( Theory::Effort e, unsigned quant_e ) = 0;
/* Called for new quantifiers */
virtual void registerQuantifier( Node q ) = 0;
virtual void assertNode( Node n ) = 0;
@@ -61,10 +69,15 @@ public:
virtual Node explain(TNode n) { return TNode::null(); }
/** Identify this module (for debugging, dynamic configuration, etc..) */
virtual std::string identify() const = 0;
+public:
+ eq::EqualityEngine * getEqualityEngine();
+ bool areDisequal( TNode n1, TNode n2 );
+ bool areEqual( TNode n1, TNode n2 );
+ TNode getRepresentative( TNode n );
+ quantifiers::TermDb * getTermDatabase();
};/* class QuantifiersModule */
namespace quantifiers {
- class TermDb;
class FirstOrderModel;
//modules
class InstantiationEngine;
@@ -73,6 +86,9 @@ namespace quantifiers {
class QuantConflictFind;
class RewriteEngine;
class RelevantDomain;
+ class QModelBuilder;
+ class ConjectureGenerator;
+ class CegInstantiation;
}/* CVC4::theory::quantifiers */
namespace inst {
@@ -100,6 +116,8 @@ private:
QuantRelevance * d_quant_rel;
/** relevant domain */
quantifiers::RelevantDomain* d_rel_dom;
+ /** model builder */
+ quantifiers::QModelBuilder* d_builder;
/** phase requirements for each quantifier for each instantiation literal */
std::map< Node, QuantPhaseReq* > d_phase_reqs;
/** instantiation engine */
@@ -112,6 +130,16 @@ private:
quantifiers::QuantConflictFind* d_qcf;
/** rewrite rules utility */
quantifiers::RewriteEngine * d_rr_engine;
+ /** subgoal generator */
+ quantifiers::ConjectureGenerator * d_sg_gen;
+ /** ceg instantiation */
+ quantifiers::CegInstantiation * d_ceg_inst;
+public: //effort levels
+ enum {
+ QEFFORT_CONFLICT,
+ QEFFORT_STANDARD,
+ QEFFORT_MODEL,
+ };
private:
/** list of all quantifiers seen */
std::vector< Node > d_quants;
@@ -120,8 +148,12 @@ private:
BoolMap d_lemmas_produced_c;
/** lemmas waiting */
std::vector< Node > d_lemmas_waiting;
+ /** phase requirements waiting */
+ std::map< Node, bool > d_phase_req_waiting;
/** has added lemma this round */
bool d_hasAddedLemma;
+ /** has a conflict been found */
+ bool d_conflict;
/** list of all instantiations produced for each quantifier */
std::map< Node, inst::InstMatchTrie > d_inst_match_trie;
std::map< Node, inst::CDInstMatchTrie* > d_c_inst_match_trie;
@@ -147,10 +179,6 @@ public:
/** get equality query object for the given type. The default is the
generic one */
EqualityQueryQuantifiersEngine* getEqualityQuery();
- /** get instantiation engine */
- quantifiers::InstantiationEngine* getInstantiationEngine() { return d_inst_engine; }
- /** get model engine */
- quantifiers::ModelEngine* getModelEngine() { return d_model_engine; }
/** get default sat context for quantifiers engine */
context::Context* getSatContext();
/** get default sat context for quantifiers engine */
@@ -163,14 +191,37 @@ public:
quantifiers::RelevantDomain* getRelevantDomain() { return d_rel_dom; }
/** get quantifier relevance */
QuantRelevance* getQuantifierRelevance() { return d_quant_rel; }
+ /** get the model builder */
+ quantifiers::QModelBuilder* getModelBuilder() { return d_builder; }
/** get phase requirement information */
QuantPhaseReq* getPhaseRequirements( Node f ) { return d_phase_reqs.find( f )==d_phase_reqs.end() ? NULL : d_phase_reqs[f]; }
/** get phase requirement terms */
void getPhaseReqTerms( Node f, std::vector< Node >& nodes );
+public: //modules
+ /** get instantiation engine */
+ quantifiers::InstantiationEngine* getInstantiationEngine() { return d_inst_engine; }
+ /** get model engine */
+ quantifiers::ModelEngine* getModelEngine() { return d_model_engine; }
/** get bounded integers utility */
quantifiers::BoundedIntegers * getBoundedIntegers() { return d_bint; }
/** Conflict find mechanism for quantifiers */
quantifiers::QuantConflictFind* getConflictFind() { return d_qcf; }
+ /** rewrite rules utility */
+ quantifiers::RewriteEngine * getRewriteEngine() { return d_rr_engine; }
+ /** subgoal generator */
+ quantifiers::ConjectureGenerator * getConjectureGenerator() { return d_sg_gen; }
+ /** ceg instantiation */
+ quantifiers::CegInstantiation * getCegInstantiation() { return d_ceg_inst; }
+private:
+ /** owner of quantified formulas */
+ std::map< Node, QuantifiersModule * > d_owner;
+public:
+ /** get owner */
+ QuantifiersModule * getOwner( Node q );
+ /** set owner */
+ void setOwner( Node q, QuantifiersModule * m );
+ /** considers */
+ bool hasOwnership( Node q, QuantifiersModule * m = NULL );
public:
/** initialize */
void finishInit();
@@ -192,7 +243,9 @@ private:
/** instantiate f with arguments terms */
bool addInstantiation( Node f, std::vector< Node >& vars, std::vector< Node >& terms );
/** set instantiation level attr */
- void setInstantiationLevelAttr( Node n, Node qn, uint64_t level, std::vector< Node >& inst_terms );
+ static void setInstantiationLevelAttr( Node n, Node qn, uint64_t level );
+ /** flush lemmas */
+ void flushLemmas();
public:
/** get instantiation */
Node getInstantiation( Node f, std::vector< Node >& vars, std::vector< Node >& terms );
@@ -206,6 +259,8 @@ public:
bool existsInstantiation( Node f, InstMatch& m, bool modEq = true, bool modInst = false );
/** add lemma lem */
bool addLemma( Node lem, bool doCache = true );
+ /** add require phase */
+ void addRequirePhase( Node lit, bool req );
/** do instantiation specified by m */
bool addInstantiation( Node f, InstMatch& m, bool mkRep = true, bool modEq = false, bool modInst = false );
/** add instantiation */
@@ -216,10 +271,12 @@ public:
bool addSplitEquality( Node n1, Node n2, bool reqPhase = false, bool reqPhasePol = true );
/** has added lemma */
bool hasAddedLemma() { return !d_lemmas_waiting.empty() || d_hasAddedLemma; }
- /** flush lemmas */
- void flushLemmas( OutputChannel* out = NULL );
/** get number of waiting lemmas */
int getNumLemmasWaiting() { return (int)d_lemmas_waiting.size(); }
+ /** set instantiation level attr */
+ static void setInstantiationLevelAttr( Node n, uint64_t level );
+ /** is term eligble for instantiation? */
+ bool isTermEligibleForInstantiation( Node n, Node f, bool print = false );
public:
/** get number of quantifiers */
int getNumQuantifiers() { return (int)d_quants.size(); }
@@ -236,6 +293,8 @@ public:
void addTermToDatabase( Node n, bool withinQuant = false );
/** get the master equality engine */
eq::EqualityEngine* getMasterEqualityEngine() ;
+ /** debug print equality engine */
+ void debugPrintEqualityEngine( const char * c );
public:
/** print instantiations */
void printInstantiations( std::ostream& out );
@@ -278,7 +337,7 @@ private:
bool d_liberal;
private:
/** node contains */
- Node getInstance( Node n, std::vector< Node >& eqc );
+ Node getInstance( Node n, const std::vector< Node >& eqc, std::hash_map<TNode, Node, TNodeHashFunction>& cache );
/** get score */
int getRepScore( Node n, Node f, int index );
public:
diff --git a/src/theory/rep_set.cpp b/src/theory/rep_set.cpp
index 954272549..db0524034 100644
--- a/src/theory/rep_set.cpp
+++ b/src/theory/rep_set.cpp
@@ -28,6 +28,15 @@ void RepSet::clear(){
d_tmap.clear();
}
+bool RepSet::hasRep( TypeNode tn, Node n ) {
+ std::map< TypeNode, std::vector< Node > >::iterator it = d_type_reps.find( tn );
+ if( it==d_type_reps.end() ){
+ return false;
+ }else{
+ return std::find( it->second.begin(), it->second.end(), n )!=it->second.end();
+ }
+}
+
int RepSet::getNumRepresentatives( TypeNode tn ) const{
std::map< TypeNode, std::vector< Node > >::const_iterator it = d_type_reps.find( tn );
if( it!=d_type_reps.end() ){
@@ -38,8 +47,9 @@ int RepSet::getNumRepresentatives( TypeNode tn ) const{
}
void RepSet::add( TypeNode tn, Node n ){
- d_tmap[ n ] = (int)d_type_reps[tn].size();
Trace("rsi-debug") << "Add rep #" << d_type_reps[tn].size() << " for " << tn << " : " << n << std::endl;
+ Assert( n.getType().isSubtypeOf( tn ) );
+ d_tmap[ n ] = (int)d_type_reps[tn].size();
d_type_reps[tn].push_back( n );
}
diff --git a/src/theory/rep_set.h b/src/theory/rep_set.h
index 23db36ead..19bb6d3d3 100644
--- a/src/theory/rep_set.h
+++ b/src/theory/rep_set.h
@@ -37,6 +37,8 @@ public:
void clear();
/** has type */
bool hasType( TypeNode tn ) const { return d_type_reps.find( tn )!=d_type_reps.end(); }
+ /** has rep */
+ bool hasRep( TypeNode tn, Node n );
/** get cardinality for type */
int getNumRepresentatives( TypeNode tn ) const;
/** add representative for type */
diff --git a/src/theory/sets/normal_form.h b/src/theory/sets/normal_form.h
new file mode 100644
index 000000000..bc34ea6f1
--- /dev/null
+++ b/src/theory/sets/normal_form.h
@@ -0,0 +1,52 @@
+/********************* */
+/*! \file normal_form.h
+ ** \verbatim
+ ** Original author: Kshitij Bansal
+ ** Major contributors: none
+ ** Minor contributors (to current version): none
+ ** This file is part of the CVC4 project.
+ ** Copyright (c) 2009-2014 New York University and The University of Iowa
+ ** See the file COPYING in the top-level source directory for licensing
+ ** information.\endverbatim
+ **
+ ** \brief Normal form for set constants.
+ **
+ ** Normal form for set constants.
+ **/
+
+#include "cvc4_private.h"
+
+#ifndef __CVC4__THEORY__SETS__NORMAL_FORM_H
+#define __CVC4__THEORY__SETS__NORMAL_FORM_H
+
+namespace CVC4 {
+namespace theory {
+namespace sets {
+
+class NormalForm {
+public:
+
+ static Node elementsToSet(std::set<TNode> elements, TypeNode setType)
+ {
+ NodeManager* nm = NodeManager::currentNM();
+
+ if(elements.size() == 0) {
+ return nm->mkConst(EmptySet(nm->toType(setType)));
+ } else {
+ typeof(elements.begin()) it = elements.begin();
+ Node cur = nm->mkNode(kind::SINGLETON, *it);
+ while( ++it != elements.end() ) {
+ cur = nm->mkNode(kind::UNION, cur,
+ nm->mkNode(kind::SINGLETON, *it));
+ }
+ return cur;
+ }
+ }
+
+};
+
+}
+}
+}
+
+#endif
diff --git a/src/theory/sets/options b/src/theory/sets/options
index 1c95e78e4..6f4b5129d 100644
--- a/src/theory/sets/options
+++ b/src/theory/sets/options
@@ -11,4 +11,10 @@ option setsPropagate --sets-propagate bool :default true
option setsEagerLemmas --sets-eager-lemmas bool :default true
add lemmas even at regular effort
+expert-option setsCare1 --sets-care1 bool :default false
+ generate one lemma at a time for care graph
+
+option setsPropFull --sets-prop-full bool :default true
+ additional propagation at full effort
+
endmodule
diff --git a/src/theory/sets/scrutinize.h b/src/theory/sets/scrutinize.h
index a4f3f6a6d..dc5feecda 100644
--- a/src/theory/sets/scrutinize.h
+++ b/src/theory/sets/scrutinize.h
@@ -35,11 +35,11 @@ public:
}
void postCheckInvariants() const {
Debug("sets-scrutinize") << "[sets-scrutinize] postCheckInvariants()" << std::endl;
-
+
// assume not in conflict, and complete:
// - try building model
// - check it
-
+
TheorySetsPrivate::SettermElementsMap settermElementsMap;
TNode true_atom = NodeManager::currentNM()->mkConst<bool>(true);
std::set<Node> terms;
diff --git a/src/theory/sets/theory_sets.cpp b/src/theory/sets/theory_sets.cpp
index b59beac8d..106ad6e56 100644
--- a/src/theory/sets/theory_sets.cpp
+++ b/src/theory/sets/theory_sets.cpp
@@ -39,6 +39,9 @@ void TheorySets::addSharedTerm(TNode n) {
}
void TheorySets::check(Effort e) {
+ if (done() && !fullEffort(e)) {
+ return;
+ }
d_internal->check(e);
}
@@ -54,6 +57,14 @@ Node TheorySets::explain(TNode node) {
return d_internal->explain(node);
}
+EqualityStatus TheorySets::getEqualityStatus(TNode a, TNode b) {
+ return d_internal->getEqualityStatus(a, b);
+}
+
+Node TheorySets::getModelValue(TNode node) {
+ return d_internal->getModelValue(node);
+}
+
void TheorySets::preRegisterTerm(TNode node) {
d_internal->preRegisterTerm(node);
}
diff --git a/src/theory/sets/theory_sets.h b/src/theory/sets/theory_sets.h
index a16832389..6136fc8f8 100644
--- a/src/theory/sets/theory_sets.h
+++ b/src/theory/sets/theory_sets.h
@@ -58,6 +58,10 @@ public:
Node explain(TNode);
+ EqualityStatus getEqualityStatus(TNode a, TNode b);
+
+ Node getModelValue(TNode);
+
std::string identify() const { return "THEORY_SETS"; }
void preRegisterTerm(TNode node);
diff --git a/src/theory/sets/theory_sets_private.cpp b/src/theory/sets/theory_sets_private.cpp
index cae606409..57b761500 100644
--- a/src/theory/sets/theory_sets_private.cpp
+++ b/src/theory/sets/theory_sets_private.cpp
@@ -418,32 +418,192 @@ void TheorySetsPrivate::addSharedTerm(TNode n) {
d_equalityEngine.addTriggerTerm(n, THEORY_SETS);
}
+void TheorySetsPrivate::dumpAssertionsHumanified() const
+{
+ std::string tag = "sets-assertions";
+
+ if(Trace.isOn(tag)) { /* condition can't be !Trace.isOn, that's why this empty block */ }
+ else { return; }
+
+ context::CDList<Assertion>::const_iterator it = d_external.facts_begin(), it_end = d_external.facts_end();
+
+ std::map<TNode, std::set<TNode> > equalities;
+ std::set< pair<TNode, TNode> > disequalities;
+ std::map<TNode, std::pair<std::set<TNode>, std::set<TNode> > > members;
+ static std::map<TNode, int> numbering;
+ static int number = 0;
+
+ for (unsigned i = 0; it != it_end; ++ it, ++i) {
+ TNode ass = (*it).assertion;
+ // Trace("sets-care-dump") << AssertCommand(ass.toExpr()) << endl;
+ bool polarity = ass.getKind() != kind::NOT;
+ ass = polarity ? ass : ass[0];
+ Assert( ass.getNumChildren() == 2);
+ TNode left = d_equalityEngine.getRepresentative(ass[0]);
+ TNode right = d_equalityEngine.getRepresentative(ass[1]);
+ if(numbering[left] == 0) numbering[left] = ++number;
+ if(numbering[right] == 0) numbering[right] = ++number;
+ equalities[left].insert(ass[0]);
+ equalities[right].insert(ass[1]);
+ if(ass.getKind() == kind::EQUAL) {
+ if(polarity) {
+ Assert(left == right);
+ } else {
+ if(left > right) std::swap(left, right);
+ disequalities.insert(make_pair(left, right));
+ }
+ } else if(ass.getKind() == kind::MEMBER) {
+ (polarity ? members[right].first : members[right].second).insert(left);
+ }
+ }
+#define FORIT(it, container) for(typeof((container).begin()) it=(container).begin(); (it) != (container).end(); ++(it))
+ FORIT(kt, equalities) {
+ Trace(tag) << " Eq class of t" << numbering[(*kt).first] << ": " << std::endl;
+ FORIT(jt, (*kt).second) {
+ TNode S = (*jt);
+ if( S.getKind() != kind::UNION && S.getKind() != kind::INTERSECTION && S.getKind() != kind::SETMINUS) {
+ Trace(tag) << " " << *jt << ((*jt).getType().isSet() ? "\n": " ");
+ } else {
+ Trace(tag) << " ";
+ if(S[0].isConst() || numbering.find(d_equalityEngine.getRepresentative(S[0])) == numbering.end()) {
+ Trace(tag) << S[0];
+ } else {
+ Trace(tag) << "t" << numbering[d_equalityEngine.getRepresentative(S[0])];
+ }
+ Trace(tag) << " " << (S.getKind() == kind::UNION ? "|" : (S.getKind() == kind::INTERSECTION ? "&" : "-")) << " ";
+ if(S[1].isConst() || numbering.find(d_equalityEngine.getRepresentative(S[1])) == numbering.end()) {
+ Trace(tag) << S[1];
+ } else {
+ Trace(tag) << "t" << numbering[d_equalityEngine.getRepresentative(S[1])];
+ }
+ Trace(tag) << std::endl;
+ }
+ }
+ Trace(tag) << std::endl;
+ }
+ FORIT(kt, disequalities) Trace(tag) << "NOT(t"<<numbering[(*kt).first]<<" = t" <<numbering[(*kt).second] <<")"<< std::endl;
+ FORIT(kt, members) {
+ if( (*kt).second.first.size() > 0) {
+ Trace(tag) << "IN t" << numbering[(*kt).first] << ": ";
+ FORIT(jt, (*kt).second.first) {
+ TNode x = (*jt);
+ if(x.isConst() || numbering.find(d_equalityEngine.getRepresentative(x)) == numbering.end()) {
+ Trace(tag) << x << ", ";
+ } else {
+ Trace(tag) << "t" << numbering[d_equalityEngine.getRepresentative(x)] << ", ";
+ }
+ }
+ Trace(tag) << std::endl;
+ }
+ if( (*kt).second.second.size() > 0) {
+ Trace(tag) << "NOT IN t" << numbering[(*kt).first] << ": ";
+ FORIT(jt, (*kt).second.second) {
+ TNode x = (*jt);
+ if(x.isConst() || numbering.find(d_equalityEngine.getRepresentative(x)) == numbering.end()) {
+ Trace(tag) << x << ", ";
+ } else {
+ Trace(tag) << "t" << numbering[d_equalityEngine.getRepresentative(x)] << ", ";
+ }
+ }
+ Trace(tag) << std::endl;
+ }
+ }
+ Trace(tag) << std::endl;
+#undef FORIT
+}
void TheorySetsPrivate::computeCareGraph() {
Debug("sharing") << "Theory::computeCareGraph<" << d_external.identify() << ">()" << endl;
- for (unsigned i = 0; i < d_external.d_sharedTerms.size(); ++ i) {
+
+ if(Trace.isOn("sets-assertions")) {
+ // dump our understanding of assertions
+ dumpAssertionsHumanified();
+ }
+
+ CVC4_UNUSED unsigned edgesAddedCnt = 0;
+
+ unsigned i_st = 0;
+ if(options::setsCare1()) { i_st = d_ccg_i; }
+ for (unsigned i = i_st; i < d_external.d_sharedTerms.size(); ++ i) {
TNode a = d_external.d_sharedTerms[i];
TypeNode aType = a.getType();
- for (unsigned j = i + 1; j < d_external.d_sharedTerms.size(); ++ j) {
+
+ unsigned j_st = i + 1;
+ if(options::setsCare1()) { if(i == d_ccg_i) j_st = d_ccg_j + 1; }
+
+ for (unsigned j = j_st; j < d_external.d_sharedTerms.size(); ++ j) {
TNode b = d_external.d_sharedTerms[j];
if (b.getType() != aType) {
// We don't care about the terms of different types
continue;
}
+
switch (d_external.d_valuation.getEqualityStatus(a, b)) {
case EQUALITY_TRUE_AND_PROPAGATED:
+ // If we know about it, we should have propagated it, so we can skip
+ Trace("sets-care") << "[sets-care] Know: " << EQUAL(a, b) << std::endl;
+ break;
case EQUALITY_FALSE_AND_PROPAGATED:
// If we know about it, we should have propagated it, so we can skip
+ Trace("sets-care") << "[sets-care] Know: " << NOT(EQUAL(a, b)) << std::endl;
break;
- default:
+ case EQUALITY_FALSE:
+ case EQUALITY_TRUE:
+ Assert(false, "ERROR: Equality status true/false but not propagated (sets care graph computation).");
+ break;
+ case EQUALITY_TRUE_IN_MODEL:
+ d_external.addCarePair(a, b);
+ if(Trace.isOn("sharing")) {
+ ++edgesAddedCnt;
+ }
+ if(Debug.isOn("sets-care")) {
+ Debug("sets-care") << "[sets-care] Requesting split between" << a << " and "
+ << b << "." << std::endl << "[sets-care] "
+ << " Both current have value "
+ << d_external.d_valuation.getModelValue(a) << std::endl;
+ }
+ case EQUALITY_FALSE_IN_MODEL:
+ if(Trace.isOn("sets-care-performance-test")) {
+ // TODO: delete these lines, only for performance testing for now
+ d_external.addCarePair(a, b);
+ }
+ break;
+ case EQUALITY_UNKNOWN:
// Let's split on it
d_external.addCarePair(a, b);
+ if(options::setsCare1()) {
+ d_ccg_i = i;
+ d_ccg_j = j;
+ return;
+ }
break;
+ default:
+ Unreachable();
}
}
}
+ Trace("sharing") << "TheorySetsPrivate::computeCareGraph(): size = " << edgesAddedCnt << std::endl;
}
+EqualityStatus TheorySetsPrivate::getEqualityStatus(TNode a, TNode b) {
+ Assert(d_equalityEngine.hasTerm(a) && d_equalityEngine.hasTerm(b));
+ if (d_equalityEngine.areEqual(a, b)) {
+ // The terms are implied to be equal
+ return EQUALITY_TRUE;
+ }
+ if (d_equalityEngine.areDisequal(a, b, false)) {
+ // The terms are implied to be dis-equal
+ return EQUALITY_FALSE;
+ }
+ if( d_external.d_valuation.getModelValue(a) == d_external.d_valuation.getModelValue(b) ) {
+ // Ther term are true in current model
+ return EQUALITY_TRUE_IN_MODEL;
+ }
+ return EQUALITY_FALSE_IN_MODEL;
+ // }
+ // //TODO: can we be more precise sometimes?
+ // return EQUALITY_UNKNOWN;
+}
/******************** Model generation ********************/
/******************** Model generation ********************/
@@ -584,6 +744,21 @@ Node TheorySetsPrivate::elementsToShape(Elements elements, TypeNode setType) con
return cur;
}
}
+Node TheorySetsPrivate::elementsToShape(set<Node> elements, TypeNode setType) const
+{
+ NodeManager* nm = NodeManager::currentNM();
+
+ if(elements.size() == 0) {
+ return nm->mkConst(EmptySet(nm->toType(setType)));
+ } else {
+ typeof(elements.begin()) it = elements.begin();
+ Node cur = SINGLETON(*it);
+ while( ++it != elements.end() ) {
+ cur = nm->mkNode(kind::UNION, cur, SINGLETON(*it));
+ }
+ return cur;
+ }
+}
void TheorySetsPrivate::collectModelInfo(TheoryModel* m, bool fullModel)
{
@@ -690,6 +865,11 @@ void TheorySetsPrivate::collectModelInfo(TheoryModel* m, bool fullModel)
#endif
}
+Node TheorySetsPrivate::getModelValue(TNode n)
+{
+ CodeTimer codeTimer(d_statistics.d_getModelValueTime);
+ return d_termInfoManager->getModelValue(n);
+}
/********************** Helper functions ***************************/
/********************** Helper functions ***************************/
@@ -736,14 +916,23 @@ Node mkAnd(const std::vector<TNode>& conjunctions) {
TheorySetsPrivate::Statistics::Statistics() :
- d_checkTime("theory::sets::time") {
-
+ d_checkTime("theory::sets::time")
+ , d_getModelValueTime("theory::sets::getModelValueTime")
+ , d_memberLemmas("theory::sets::lemmas::member", 0)
+ , d_disequalityLemmas("theory::sets::lemmas::disequality", 0)
+{
StatisticsRegistry::registerStat(&d_checkTime);
+ StatisticsRegistry::registerStat(&d_getModelValueTime);
+ StatisticsRegistry::registerStat(&d_memberLemmas);
+ StatisticsRegistry::registerStat(&d_disequalityLemmas);
}
TheorySetsPrivate::Statistics::~Statistics() {
StatisticsRegistry::unregisterStat(&d_checkTime);
+ StatisticsRegistry::unregisterStat(&d_getModelValueTime);
+ StatisticsRegistry::unregisterStat(&d_memberLemmas);
+ StatisticsRegistry::unregisterStat(&d_disequalityLemmas);
}
@@ -813,11 +1002,13 @@ void TheorySetsPrivate::addToPending(Node n) {
if(n.getKind() == kind::MEMBER) {
Debug("sets-pending") << "[sets-pending] \u2514 added to member queue"
<< std::endl;
+ ++d_statistics.d_memberLemmas;
d_pending.push(n);
} else {
Debug("sets-pending") << "[sets-pending] \u2514 added to equality queue"
<< std::endl;
Assert(n.getKind() == kind::EQUAL);
+ ++d_statistics.d_disequalityLemmas;
d_pendingDisequal.push(n);
}
d_external.d_out->lemma(getLemma());
@@ -882,6 +1073,9 @@ TheorySetsPrivate::TheorySetsPrivate(TheorySets& external,
d_pending(c),
d_pendingDisequal(c),
d_pendingEverInserted(u),
+ d_modelCache(c),
+ d_ccg_i(c),
+ d_ccg_j(c),
d_scrutinize(NULL)
{
d_termInfoManager = new TermInfoManager(*this, c, &d_equalityEngine);
@@ -906,8 +1100,44 @@ TheorySetsPrivate::~TheorySetsPrivate()
Assert(d_scrutinize != NULL);
delete d_scrutinize;
}
-}
+}/* TheorySetsPrivate::~TheorySetsPrivate() */
+
+void TheorySetsPrivate::propagate(Theory::Effort effort) {
+ if(effort != Theory::EFFORT_FULL || !options::setsPropFull()) {
+ return;
+ }
+
+ // build a model
+ Trace("sets-prop-full") << "[sets-prop-full] propagate(FULL_EFFORT)" << std::endl;
+ if(Trace.isOn("sets-assertions")) {
+ dumpAssertionsHumanified();
+ }
+
+ const CDNodeSet& terms = (d_termInfoManager->d_terms);
+ for(typeof(terms.begin()) it = terms.begin(); it != terms.end(); ++it) {
+ Node node = (*it);
+ Kind k = node.getKind();
+ if(k == kind::UNION && node[0].getKind() == kind::SINGLETON ) {
+
+ if(holds(MEMBER(node[0][0], node[1]))) {
+ Trace("sets-prop-full") << "[sets-prop-full] " << MEMBER(node[0][0], node[1])
+ << " => " << EQUAL(node[1], node) << std::endl;
+ learnLiteral(EQUAL(node[1], node), MEMBER(node[0][0], node[1]));
+ }
+
+ } else if(k == kind::UNION && node[1].getKind() == kind::SINGLETON ) {
+
+ if(holds(MEMBER(node[1][0], node[0]))) {
+ Trace("sets-prop-full") << "[sets-prop-full] " << MEMBER(node[1][0], node[0])
+ << " => " << EQUAL(node[0], node) << std::endl;
+ learnLiteral(EQUAL(node[0], node), MEMBER(node[1][0], node[0]));
+ }
+
+ }
+ }
+ finishPropagation();
+}
bool TheorySetsPrivate::propagate(TNode literal) {
Debug("sets-prop") << " propagate(" << literal << ")" << std::endl;
@@ -925,13 +1155,14 @@ bool TheorySetsPrivate::propagate(TNode literal) {
}
return ok;
-}/* TheorySetsPropagate::propagate(TNode) */
+}/* TheorySetsPrivate::propagate(TNode) */
void TheorySetsPrivate::setMasterEqualityEngine(eq::EqualityEngine* eq) {
d_equalityEngine.setMasterEqualityEngine(eq);
}
+
void TheorySetsPrivate::conflict(TNode a, TNode b)
{
if (a.getKind() == kind::CONST_BOOLEAN) {
@@ -970,6 +1201,7 @@ Node TheorySetsPrivate::explain(TNode literal)
return mkAnd(assumptions);
}
+
void TheorySetsPrivate::preRegisterTerm(TNode node)
{
Debug("sets") << "TheorySetsPrivate::preRegisterTerm(" << node << ")"
@@ -1112,6 +1344,8 @@ void TheorySetsPrivate::TermInfoManager::notifyMembership(TNode fact) {
d_info[S]->addToElementList(x, polarity);
d_info[x]->addToSetList(S, polarity);
+
+ d_theory.d_modelCache.clear();
}
const CDTNodeList* TheorySetsPrivate::TermInfoManager::getParents(TNode x) {
@@ -1265,8 +1499,38 @@ void TheorySetsPrivate::TermInfoManager::mergeTerms(TNode a, TNode b) {
(*itb).second->setsContainingThisElement );
mergeLists( (*ita).second->setsNotContainingThisElement,
(*itb).second->setsNotContainingThisElement );
+
+ d_theory.d_modelCache.clear();
}
+Node TheorySetsPrivate::TermInfoManager::getModelValue(TNode n)
+{
+ if(d_terms.find(n) == d_terms.end()) {
+ return Node();
+ }
+ Assert(n.getType().isSet());
+ set<Node> elements, elements_const;
+ Node S = d_eqEngine->getRepresentative(n);
+ typeof(d_theory.d_modelCache.begin()) it = d_theory.d_modelCache.find(S);
+ if(it != d_theory.d_modelCache.end()) {
+ return (*it).second;
+ }
+ const CDTNodeList* l = getMembers(S);
+ for(typeof(l->begin()) it = l->begin(); it != l->end(); ++it) {
+ TNode n = *it;
+ elements.insert(d_eqEngine->getRepresentative(n));
+ }
+ BOOST_FOREACH(TNode e, elements) {
+ if(e.isConst()) {
+ elements_const.insert(e);
+ } else {
+ elements_const.insert(d_theory.d_external.d_valuation.getModelValue(e));
+ }
+ }
+ Node v = d_theory.elementsToShape(elements_const, n.getType());
+ d_theory.d_modelCache[n] = v;
+ return v;
+}
}/* CVC4::theory::sets namespace */
}/* CVC4::theory namespace */
diff --git a/src/theory/sets/theory_sets_private.h b/src/theory/sets/theory_sets_private.h
index 78a415529..536987073 100644
--- a/src/theory/sets/theory_sets_private.h
+++ b/src/theory/sets/theory_sets_private.h
@@ -47,7 +47,7 @@ public:
context::UserContext* u);
~TheorySetsPrivate();
-
+
void setMasterEqualityEngine(eq::EqualityEngine* eq);
void addSharedTerm(TNode);
@@ -60,9 +60,13 @@ public:
Node explain(TNode);
+ EqualityStatus getEqualityStatus(TNode a, TNode b);
+
+ Node getModelValue(TNode);
+
void preRegisterTerm(TNode node);
- void propagate(Theory::Effort) { /* we don't depend on this call */ }
+ void propagate(Theory::Effort);
private:
TheorySets& d_external;
@@ -70,6 +74,9 @@ private:
class Statistics {
public:
TimerStat d_checkTime;
+ TimerStat d_getModelValueTime;
+ IntStat d_memberLemmas;
+ IntStat d_disequalityLemmas;
Statistics();
~Statistics();
@@ -107,8 +114,9 @@ private:
TheorySetsPrivate& d_theory;
context::Context* d_context;
eq::EqualityEngine* d_eqEngine;
-
+ public:
CDNodeSet d_terms;
+ private:
std::hash_map<TNode, TheorySetsTermInfo*, TNodeHashFunction> d_info;
void mergeLists(CDTNodeList* la, const CDTNodeList* lb) const;
@@ -123,6 +131,7 @@ private:
void notifyMembership(TNode fact);
const CDTNodeList* getParents(TNode x);
const CDTNodeList* getMembers(TNode S);
+ Node getModelValue(TNode n);
const CDTNodeList* getNonMembers(TNode S);
void addTerm(TNode n);
void mergeTerms(TNode a, TNode b);
@@ -174,11 +183,19 @@ private:
typedef std::hash_map<TNode, Elements, TNodeHashFunction> SettermElementsMap;
const Elements& getElements(TNode setterm, SettermElementsMap& settermElementsMap) const;
Node elementsToShape(Elements elements, TypeNode setType) const;
+ Node elementsToShape(std::set<Node> elements, TypeNode setType) const;
bool checkModel(const SettermElementsMap& settermElementsMap, TNode S) const;
+ context::CDHashMap <Node, Node, NodeHashFunction> d_modelCache;
+
+
+ // sharing related
+ context::CDO<unsigned> d_ccg_i, d_ccg_j;
+
// more debugging stuff
friend class TheorySetsScrutinize;
TheorySetsScrutinize* d_scrutinize;
+ void dumpAssertionsHumanified() const; /** do some formatting to make them more readable */
};/* class TheorySetsPrivate */
diff --git a/src/theory/sets/theory_sets_rewriter.cpp b/src/theory/sets/theory_sets_rewriter.cpp
index 01ad51733..226eca62b 100644
--- a/src/theory/sets/theory_sets_rewriter.cpp
+++ b/src/theory/sets/theory_sets_rewriter.cpp
@@ -15,6 +15,7 @@
**/
#include "theory/sets/theory_sets_rewriter.h"
+#include "theory/sets/normal_form.h"
namespace CVC4 {
namespace theory {
@@ -210,25 +211,6 @@ const Elements& collectConstantElements(TNode setterm, SettermElementsMap& sette
return it->second;
}
-Node elementsToNormalConstant(Elements elements,
- TypeNode setType)
-{
- NodeManager* nm = NodeManager::currentNM();
-
- if(elements.size() == 0) {
- return nm->mkConst(EmptySet(nm->toType(setType)));
- } else {
-
- Elements::iterator it = elements.begin();
- Node cur = nm->mkNode(kind::SINGLETON, *it);
- while( ++it != elements.end() ) {
- cur = nm->mkNode(kind::UNION, cur,
- nm->mkNode(kind::SINGLETON, *it));
- }
- return cur;
- }
-}
-
// static
RewriteResponse TheorySetsRewriter::preRewrite(TNode node) {
@@ -252,7 +234,7 @@ RewriteResponse TheorySetsRewriter::preRewrite(TNode node) {
//rewrite set to normal form
SettermElementsMap setTermElementsMap; // cache
const Elements& elements = collectConstantElements(node, setTermElementsMap);
- RewriteResponse response(REWRITE_DONE, elementsToNormalConstant(elements, node.getType()));
+ RewriteResponse response(REWRITE_DONE, NormalForm::elementsToSet(elements, node.getType()));
Debug("sets-rewrite-constant") << "[sets-rewrite-constant] Rewriting " << node << std::endl
<< "[sets-rewrite-constant] to " << response.node << std::endl;
return response;
diff --git a/src/theory/sets/theory_sets_type_enumerator.h b/src/theory/sets/theory_sets_type_enumerator.h
index 5d14006bb..718c329fd 100644
--- a/src/theory/sets/theory_sets_type_enumerator.h
+++ b/src/theory/sets/theory_sets_type_enumerator.h
@@ -25,6 +25,7 @@
#include "expr/type_node.h"
#include "expr/kind.h"
#include "theory/rewriter.h"
+#include "theory/sets/normal_form.h"
namespace CVC4 {
namespace theory {
@@ -87,21 +88,17 @@ public:
if (d_finished) {
throw NoMoreValuesException(getType());
}
- Node n = d_setConst;
- // For now only support only sets of size 1
- Assert(d_index == 0 || d_index == 1);
-
- if(d_index == 1) {
- n = d_nm->mkNode(kind::SINGLETON, *(*(d_constituentVec[0])));
+ std::vector<Node> elements;
+ for(unsigned i = 0; i < d_constituentVec.size(); ++i) {
+ elements.push_back(*(*(d_constituentVec[i])));
}
- // for (unsigned i = 0; i < d_indexVec.size(); ++i) {
- // n = d_nm->mkNode(kind::STORE, n, d_indexVec[d_indexVec.size() - 1 - i], *(*(d_constituentVec[i])));
- // }
- Trace("set-type-enum") << "operator * prerewrite: " << n << std::endl;
- n = Rewriter::rewrite(n);
- Trace("set-type-enum") << "operator * returning: " << n << std::endl;
+ Node n = NormalForm::elementsToSet(std::set<TNode>(elements.begin(), elements.end()),
+ getType());
+
+ Assert(n == Rewriter::rewrite(n));
+
return n;
}
diff --git a/src/theory/sets/theory_sets_type_rules.h b/src/theory/sets/theory_sets_type_rules.h
index eb270202a..6754bbb9e 100644
--- a/src/theory/sets/theory_sets_type_rules.h
+++ b/src/theory/sets/theory_sets_type_rules.h
@@ -100,7 +100,7 @@ struct MemberTypeRule {
}
TypeNode elementType = n[0].getType(check);
if(elementType != setType.getSetElementType()) {
- throw TypeCheckingExceptionPrivate(n, "set in operating on sets of different types");
+ throw TypeCheckingExceptionPrivate(n, "member operating on sets of different types");
}
}
return nodeManager->booleanType();
diff --git a/src/theory/strings/kinds b/src/theory/strings/kinds
index 4266c02f5..0f68d1207 100644
--- a/src/theory/strings/kinds
+++ b/src/theory/strings/kinds
@@ -88,6 +88,11 @@ operator REGEXP_LOOP 2:3 "regexp loop"
operator REGEXP_EMPTY 0 "regexp empty"
operator REGEXP_SIGMA 0 "regexp all characters"
+#internal
+operator REGEXP_RV 1 "regexp rv (internal use only)"
+typerule REGEXP_RV ::CVC4::theory::strings::RegExpRVTypeRule
+
+#typerules
typerule REGEXP_CONCAT ::CVC4::theory::strings::RegExpConcatTypeRule
typerule REGEXP_UNION ::CVC4::theory::strings::RegExpUnionTypeRule
typerule REGEXP_INTER ::CVC4::theory::strings::RegExpInterTypeRule
diff --git a/src/theory/strings/regexp_operation.cpp b/src/theory/strings/regexp_operation.cpp
index 369278994..69b089c84 100644
--- a/src/theory/strings/regexp_operation.cpp
+++ b/src/theory/strings/regexp_operation.cpp
@@ -21,18 +21,20 @@ namespace CVC4 {
namespace theory {
namespace strings {
-RegExpOpr::RegExpOpr() {
+RegExpOpr::RegExpOpr()
+ : d_card( 256 ),
+ RMAXINT( LONG_MAX )
+{
d_emptyString = NodeManager::currentNM()->mkConst( ::CVC4::String("") );
d_true = NodeManager::currentNM()->mkConst( true );
d_false = NodeManager::currentNM()->mkConst( false );
+ d_emptySingleton = NodeManager::currentNM()->mkNode( kind::STRING_TO_REGEXP, d_emptyString );
d_zero = NodeManager::currentNM()->mkConst( ::CVC4::Rational(0) );
d_one = NodeManager::currentNM()->mkConst( ::CVC4::Rational(1) );
- d_emptySingleton = NodeManager::currentNM()->mkNode( kind::STRING_TO_REGEXP, d_emptyString );
std::vector< Node > nvec;
d_emptyRegexp = NodeManager::currentNM()->mkNode( kind::REGEXP_EMPTY, nvec );
d_sigma = NodeManager::currentNM()->mkNode( kind::REGEXP_SIGMA, nvec );
d_sigma_star = NodeManager::currentNM()->mkNode( kind::REGEXP_STAR, d_sigma );
- d_card = 256;
}
int RegExpOpr::gcd ( int a, int b ) {
@@ -1183,8 +1185,19 @@ void RegExpOpr::getCharSet( Node r, std::set<unsigned> &pcset, SetNodes &pvset )
}
}
+bool RegExpOpr::isPairNodesInSet(std::set< PairNodes > &s, Node n1, Node n2) {
+ for(std::set< PairNodes >::const_iterator itr = s.begin();
+ itr != s.end(); ++itr) {
+ if(itr->first == n1 && itr->second == n2 ||
+ itr->first == n2 && itr->second == n1) {
+ return true;
+ }
+ }
+ return false;
+}
Node RegExpOpr::intersectInternal( Node r1, Node r2, std::map< unsigned, std::set< PairNodes > > cache, bool &spflag ) {
+ Trace("regexp-intersect") << "Starting INTERSECT:\n "<< mkString(r1) << ",\n " << mkString(r2) << std::endl;
if(spflag) {
//TODO: var
return Node::null();
@@ -1230,11 +1243,18 @@ Node RegExpOpr::intersectInternal( Node r1, Node r2, std::map< unsigned, std::se
spflag = true;
}
}
+ if(Trace.isOn("regexp-debug")) {
+ Trace("regexp-debug") << "Try CSET( " << cset.size() << " ) = ";
+ for(std::set<unsigned>::const_iterator itr = cset.begin();
+ itr != cset.end(); itr++) {
+ Trace("regexp-debug") << *itr << ", ";
+ }
+ Trace("regexp-debug") << std::endl;
+ }
for(std::set<unsigned>::const_iterator itr = cset.begin();
itr != cset.end(); itr++) {
CVC4::String c( CVC4::String::convertUnsignedIntToChar(*itr) );
- std::pair< Node, Node > p(r1, r2);
- if(cache[ *itr ].find(p) == cache[ *itr ].end()) {
+ if(!isPairNodesInSet(cache[ *itr ], r1, r2)) {
Node r1l = derivativeSingle(r1, c);
Node r2l = derivativeSingle(r2, c);
std::map< unsigned, std::set< PairNodes > > cache2(cache);
@@ -1263,10 +1283,210 @@ Node RegExpOpr::intersectInternal( Node r1, Node r2, std::map< unsigned, std::se
Trace("regexp-intersect") << "INTERSECT( " << mkString(r1) << ", " << mkString(r2) << " ) = " << mkString(rNode) << std::endl;
return rNode;
}
+
+bool RegExpOpr::containC2(unsigned cnt, Node n) {
+ if(n.getKind() == kind::REGEXP_RV) {
+ Assert(n[0].getConst<Rational>() <= RMAXINT, "Exceeded LONG_MAX in RegExpOpr::containC2");
+ unsigned y = n[0].getConst<Rational>().getNumerator().toUnsignedInt();
+ return cnt == y;
+ } else if(n.getKind() == kind::REGEXP_CONCAT) {
+ for( unsigned i=0; i<n.getNumChildren(); i++ ) {
+ if(containC2(cnt, n[i])) {
+ return true;
+ }
+ }
+ } else if(n.getKind() == kind::REGEXP_STAR) {
+ return containC2(cnt, n[0]);
+ } else if(n.getKind() == kind::REGEXP_UNION) {
+ for( unsigned i=0; i<n.getNumChildren(); i++ ) {
+ if(containC2(cnt, n[i])) {
+ return true;
+ }
+ }
+ }
+ return false;
+}
+Node RegExpOpr::convert1(unsigned cnt, Node n) {
+ Trace("regexp-debug") << "Converting " << n << " at " << cnt << "... " << std::endl;
+ Node r1, r2;
+ convert2(cnt, n, r1, r2);
+ Trace("regexp-debug") << "... getting r1=" << r1 << ", and r2=" << r2 << std::endl;
+ Node ret = NodeManager::currentNM()->mkNode(kind::REGEXP_CONCAT,
+ NodeManager::currentNM()->mkNode(kind::REGEXP_STAR, r1), r2);
+ ret = Rewriter::rewrite( ret );
+ Trace("regexp-debug") << "... done convert at " << cnt << ", with return " << ret << std::endl;
+ return ret;
+}
+void RegExpOpr::convert2(unsigned cnt, Node n, Node &r1, Node &r2) {
+ if(n == d_emptyRegexp) {
+ r1 = d_emptyRegexp;
+ r2 = d_emptyRegexp;
+ } else if(n == d_emptySingleton) {
+ r1 = d_emptySingleton;
+ r2 = d_emptySingleton;
+ } else if(n.getKind() == kind::REGEXP_RV) {
+ Assert(n[0].getConst<Rational>() <= RMAXINT, "Exceeded LONG_MAX in RegExpOpr::containC2");
+ unsigned y = n[0].getConst<Rational>().getNumerator().toUnsignedInt();
+ r1 = d_emptySingleton;
+ if(cnt == y) {
+ r2 = d_emptyRegexp;
+ } else {
+ r2 = n;
+ }
+ } else if(n.getKind() == kind::REGEXP_CONCAT) {
+ //TODO
+ //convert2 x (r@(Seq l r1))
+ // | contains x r1 = let (r2,r3) = convert2 x r1
+ // in (Seq l r2, r3)
+ // | otherwise = (Empty, r)
+ bool flag = true;
+ std::vector<Node> vr1, vr2;
+ for( unsigned i=0; i<n.getNumChildren(); i++ ) {
+ if(containC2(cnt, n[i])) {
+ Node t1, t2;
+ convert2(cnt, n[i], t1, t2);
+ vr1.push_back(t1);
+ r1 = vr1.size()==0 ? d_emptyRegexp : vr1.size()==1 ? vr1[0] :
+ NodeManager::currentNM()->mkNode(kind::REGEXP_CONCAT, vr1);
+ vr2.push_back(t2);
+ for( unsigned j=i+1; j<n.getNumChildren(); j++ ) {
+ vr2.push_back(n[j]);
+ }
+ r2 = vr2.size()==0 ? d_emptyRegexp : vr2.size()==1 ? vr2[0] :
+ NodeManager::currentNM()->mkNode(kind::REGEXP_CONCAT, vr2);
+ flag = false;
+ break;
+ } else {
+ vr1.push_back(n[i]);
+ }
+ }
+ if(flag) {
+ r1 = d_emptySingleton;
+ r2 = n;
+ }
+ } else if(n.getKind() == kind::REGEXP_UNION) {
+ std::vector<Node> vr1, vr2;
+ for( unsigned i=0; i<n.getNumChildren(); i++ ) {
+ Node t1, t2;
+ convert2(cnt, n[i], t1, t2);
+ vr1.push_back(t1);
+ vr2.push_back(t2);
+ }
+ r1 = NodeManager::currentNM()->mkNode(kind::REGEXP_UNION, vr1);
+ r2 = NodeManager::currentNM()->mkNode(kind::REGEXP_UNION, vr2);
+ } else if(n.getKind() == kind::STRING_TO_REGEXP) {
+ r1 = d_emptySingleton;
+ r2 = n;
+ } else {
+ //is it possible?
+ }
+}
+Node RegExpOpr::intersectInternal2( Node r1, Node r2, std::map< PairNodes, Node > cache, bool &spflag, unsigned cnt ) {
+ Trace("regexp-intersect") << "Starting INTERSECT:\n "<< mkString(r1) << ",\n " << mkString(r2) << std::endl;
+ //if(Trace.isOn("regexp-debug")) {
+ // Trace("regexp-debug") << "... with cache:\n";
+ // for(std::map< PairNodes, Node >::const_iterator itr=cache.begin();
+ // itr!=cache.end();itr++) {
+ // Trace("regexp-debug") << "(" << itr->first.first << "," << itr->first.second << ")->" << itr->second << std::endl;
+ // }
+ //}
+ if(spflag) {
+ //TODO: var
+ return Node::null();
+ }
+ std::pair < Node, Node > p(r1, r2);
+ std::map < std::pair< Node, Node >, Node >::const_iterator itr = d_inter_cache.find(p);
+ Node rNode;
+ if(itr != d_inter_cache.end()) {
+ rNode = itr->second;
+ } else {
+ if(r1 == d_emptyRegexp || r2 == d_emptyRegexp) {
+ rNode = d_emptyRegexp;
+ } else if(r1 == d_emptySingleton || r2 == d_emptySingleton) {
+ Node exp;
+ int r = delta((r1 == d_emptySingleton ? r2 : r1), exp);
+ if(r == 0) {
+ //TODO: variable
+ spflag = true;
+ } else if(r == 1) {
+ rNode = d_emptySingleton;
+ } else {
+ rNode = d_emptyRegexp;
+ }
+ } else if(r1 == r2) {
+ rNode = convert1(cnt, r1);
+ } else {
+ PairNodes p(r1, r2);
+ std::map< PairNodes, Node >::const_iterator itrcache = cache.find(p);
+ if(itrcache != cache.end()) {
+ rNode = itrcache->second;
+ } else {
+ if(checkConstRegExp(r1) && checkConstRegExp(r2)) {
+ std::vector< unsigned > cset;
+ std::set< unsigned > cset1, cset2;
+ std::set< Node > vset1, vset2;
+ firstChars(r1, cset1, vset1);
+ firstChars(r2, cset2, vset2);
+ std::set_intersection(cset1.begin(), cset1.end(), cset2.begin(), cset1.end(),
+ std::inserter(cset, cset.begin()));
+ std::vector< Node > vec_nodes;
+ Node delta_exp;
+ int flag = delta(r1, delta_exp);
+ int flag2 = delta(r2, delta_exp);
+ if(flag != 2 && flag2 != 2) {
+ if(flag == 1 && flag2 == 1) {
+ vec_nodes.push_back(d_emptySingleton);
+ } else {
+ //TODO
+ spflag = true;
+ }
+ }
+ if(Trace.isOn("regexp-debug")) {
+ Trace("regexp-debug") << "Try CSET( " << cset.size() << " ) = ";
+ for(std::vector<unsigned>::const_iterator itr = cset.begin();
+ itr != cset.end(); itr++) {
+ CVC4::String c( CVC4::String::convertUnsignedIntToChar(*itr) );
+ Trace("regexp-debug") << c << ", ";
+ }
+ Trace("regexp-debug") << std::endl;
+ }
+ for(std::vector<unsigned>::const_iterator itr = cset.begin();
+ itr != cset.end(); itr++) {
+ CVC4::String c( CVC4::String::convertUnsignedIntToChar(*itr) );
+ Node r1l = derivativeSingle(r1, c);
+ Node r2l = derivativeSingle(r2, c);
+ std::map< PairNodes, Node > cache2(cache);
+ PairNodes p(r1, r2);
+ cache2[ p ] = NodeManager::currentNM()->mkNode(kind::REGEXP_RV, NodeManager::currentNM()->mkConst(CVC4::Rational(cnt)));
+ Node rt = intersectInternal2(r1l, r2l, cache2, spflag, cnt+1);
+ rt = convert1(cnt, rt);
+ if(spflag) {
+ //TODO:
+ return Node::null();
+ }
+ rt = Rewriter::rewrite( NodeManager::currentNM()->mkNode(kind::REGEXP_CONCAT,
+ NodeManager::currentNM()->mkNode(kind::STRING_TO_REGEXP, NodeManager::currentNM()->mkConst(c)), rt) );
+ vec_nodes.push_back(rt);
+ }
+ rNode = vec_nodes.size()==0 ? d_emptyRegexp : vec_nodes.size()==1 ? vec_nodes[0] :
+ NodeManager::currentNM()->mkNode(kind::REGEXP_UNION, vec_nodes);
+ rNode = Rewriter::rewrite( rNode );
+ } else {
+ //TODO: non-empty var set
+ spflag = true;
+ }
+ }
+ }
+ d_inter_cache[p] = rNode;
+ }
+ Trace("regexp-intersect") << "End of INTERSECT( " << mkString(r1) << ", " << mkString(r2) << " ) = " << mkString(rNode) << std::endl;
+ return rNode;
+}
Node RegExpOpr::intersect(Node r1, Node r2, bool &spflag) {
- std::map< unsigned, std::set< PairNodes > > cache;
+ //std::map< unsigned, std::set< PairNodes > > cache;
+ std::map< PairNodes, Node > cache;
if(checkConstRegExp(r1) && checkConstRegExp(r2)) {
- return intersectInternal(r1, r2, cache, spflag);
+ return intersectInternal2(r1, r2, cache, spflag, 1);
} else {
spflag = true;
return Node::null();
@@ -1516,6 +1736,12 @@ std::string RegExpOpr::mkString( Node r ) {
retStr += "]";
break;
}
+ case kind::REGEXP_RV: {
+ retStr += "<";
+ retStr += r[0].getConst<Rational>().getNumerator().toString();
+ retStr += ">";
+ break;
+ }
default:
Trace("strings-error") << "Unsupported term: " << r << " in RegExp." << std::endl;
//Assert( false );
diff --git a/src/theory/strings/regexp_operation.h b/src/theory/strings/regexp_operation.h
index e4ae1208d..ce3093528 100644
--- a/src/theory/strings/regexp_operation.h
+++ b/src/theory/strings/regexp_operation.h
@@ -22,6 +22,7 @@
#include <vector>
#include <set>
#include <algorithm>
+#include <climits>
#include "util/hash.h"
#include "util/regexp.h"
#include "theory/theory.h"
@@ -46,6 +47,7 @@ private:
Node d_emptyRegexp;
Node d_zero;
Node d_one;
+ CVC4::Rational RMAXINT;
char d_char_start;
char d_char_end;
@@ -69,9 +71,14 @@ private:
std::string niceChar( Node r );
int gcd ( int a, int b );
Node mkAllExceptOne( char c );
+ bool isPairNodesInSet(std::set< PairNodes > &s, Node n1, Node n2);
void getCharSet( Node r, std::set<unsigned> &pcset, SetNodes &pvset );
Node intersectInternal( Node r1, Node r2, std::map< unsigned, std::set< PairNodes > > cache, bool &spflag );
+ bool containC2(unsigned cnt, Node n);
+ Node convert1(unsigned cnt, Node n);
+ void convert2(unsigned cnt, Node n, Node &r1, Node &r2);
+ Node intersectInternal2( Node r1, Node r2, std::map< PairNodes, Node > cache, bool &spflag, unsigned cnt );
void firstChars( Node r, std::set<unsigned> &pcset, SetNodes &pvset );
//TODO: for intersection
diff --git a/src/theory/strings/theory_strings.cpp b/src/theory/strings/theory_strings.cpp
index 2856ce1e0..e8bf87a17 100644
--- a/src/theory/strings/theory_strings.cpp
+++ b/src/theory/strings/theory_strings.cpp
@@ -35,6 +35,7 @@ namespace strings {
TheoryStrings::TheoryStrings(context::Context* c, context::UserContext* u, OutputChannel& out, Valuation valuation, const LogicInfo& logicInfo)
: Theory(THEORY_STRINGS, c, u, out, valuation, logicInfo),
+ RMAXINT(LONG_MAX),
d_notify( *this ),
d_equalityEngine(d_notify, c, "theory::strings::TheoryStrings"),
d_conflict(c, false),
@@ -284,6 +285,7 @@ void TheoryStrings::collectModelInfo( TheoryModel* m, bool fullModel ) {
Trace("strings-model") << " } (length is " << lts[i] << ")" << std::endl;
if( lts[i].isConst() ) {
lts_values.push_back( lts[i] );
+ Assert(lts[i].getConst<Rational>() <= RMAXINT, "Exceeded LONG_MAX in string model");
unsigned lvalue = lts[i].getConst<Rational>().getNumerator().toUnsignedInt();
values_used[ lvalue ] = true;
}else{
@@ -292,6 +294,7 @@ void TheoryStrings::collectModelInfo( TheoryModel* m, bool fullModel ) {
Node v = d_valuation.getModelValue(lts[i]);
Trace("strings-model") << "Model value for " << lts[i] << " is " << v << std::endl;
lts_values.push_back( v );
+ Assert(v.getConst<Rational>() <= RMAXINT, "Exceeded LONG_MAX in string model");
unsigned lvalue = v.getConst<Rational>().getNumerator().toUnsignedInt();
values_used[ lvalue ] = true;
}else{
@@ -346,6 +349,7 @@ void TheoryStrings::collectModelInfo( TheoryModel* m, bool fullModel ) {
//use type enumerator
+ Assert(lts_values[i].getConst<Rational>() <= RMAXINT, "Exceeded LONG_MAX in string model");
StringEnumeratorLength sel(lts_values[i].getConst<Rational>().getNumerator().toUnsignedInt());
for( unsigned j=0; j<pure_eq.size(); j++ ){
Assert( !sel.isFinished() );
@@ -550,6 +554,10 @@ Node TheoryStrings::expandDefinition(LogicRequest &logicRequest, Node node) {
void TheoryStrings::check(Effort e) {
+ if (done() && !fullEffort(e)) {
+ return;
+ }
+
bool polarity;
TNode atom;
@@ -596,7 +604,7 @@ void TheoryStrings::check(Effort e) {
bool addedLemma = false;
- if( e == EFFORT_FULL && !d_conflict ) {
+ if( e == EFFORT_FULL && !d_conflict && !d_valuation.needCheck() ) {
//addedLemma = checkSimple();
//Trace("strings-process") << "Done simple checking, addedLemma = " << addedLemma << ", d_conflict = " << d_conflict << std::endl;
//if( !addedLemma ) {
@@ -2500,6 +2508,7 @@ bool TheoryStrings::checkMemberships() {
std::vector< Node > processed;
std::vector< Node > cprocessed;
+ Trace("regexp-debug") << "Checking Memberships ... " << std::endl;
//if(options::stringEIT()) {
//TODO: Opt for normal forms
for(NodeListMap::const_iterator itr_xr = d_str_re_map.begin();
@@ -2507,6 +2516,7 @@ bool TheoryStrings::checkMemberships() {
bool spflag = false;
Node x = (*itr_xr).first;
NodeList* lst = (*itr_xr).second;
+ Trace("regexp-debug") << "Checking Memberships for " << x << std::endl;
if(d_inter_index.find(x) == d_inter_index.end()) {
d_inter_index[x] = 0;
}
@@ -2515,6 +2525,7 @@ bool TheoryStrings::checkMemberships() {
if(lst->size() == 1) {
d_inter_cache[x] = (*lst)[0];
d_inter_index[x] = 1;
+ Trace("regexp-debug") << "... only one choice " << std::endl;
} else if(lst->size() > 1) {
Node r;
if(d_inter_cache.find(x) != d_inter_cache.end()) {
@@ -2528,6 +2539,7 @@ bool TheoryStrings::checkMemberships() {
for(int i=0; i<cur_inter_idx; i++) {
++itr_lst;
}
+ Trace("regexp-debug") << "... staring from : " << cur_inter_idx << ", we have " << lst->size() << std::endl;
for(;itr_lst != lst->end(); ++itr_lst) {
Node r2 = *itr_lst;
r = d_regexp_opr.intersect(r, r2, spflag);
@@ -2561,6 +2573,7 @@ bool TheoryStrings::checkMemberships() {
}
//}
+ Trace("regexp-debug") << "... No Intersec Conflict in Memberships " << std::endl;
if(!addedLemma) {
for( unsigned i=0; i<d_regexp_memberships.size(); i++ ) {
//check regular expression membership
@@ -3325,4 +3338,4 @@ TheoryStrings::Statistics::~Statistics(){
}/* CVC4::theory::strings namespace */
}/* CVC4::theory namespace */
-}/* CVC4 namespace */ \ No newline at end of file
+}/* CVC4 namespace */
diff --git a/src/theory/strings/theory_strings.h b/src/theory/strings/theory_strings.h
index 797c1bd29..95eba27bc 100644
--- a/src/theory/strings/theory_strings.h
+++ b/src/theory/strings/theory_strings.h
@@ -27,6 +27,8 @@
#include "context/cdchunk_list.h"
#include "context/cdhashset.h"
+#include <climits>
+
namespace CVC4 {
namespace theory {
namespace strings {
@@ -125,6 +127,7 @@ private:
Node d_false;
Node d_zero;
Node d_one;
+ CVC4::Rational RMAXINT;
// Options
bool d_opt_fmf;
bool d_opt_regexp_gcd;
diff --git a/src/theory/strings/theory_strings_preprocess.cpp b/src/theory/strings/theory_strings_preprocess.cpp
index 6e7ca6d95..71db11fe1 100644
--- a/src/theory/strings/theory_strings_preprocess.cpp
+++ b/src/theory/strings/theory_strings_preprocess.cpp
@@ -126,7 +126,7 @@ int StringsPreprocess::checkFixLenVar( Node t ) {
}
}
if(ret != 2) {
- int len = t[ret].getConst<Rational>().getNumerator().toUnsignedInt();
+ unsigned len = t[ret].getConst<Rational>().getNumerator().toUnsignedInt();
if(len < 2) {
ret = 2;
}
diff --git a/src/theory/strings/theory_strings_rewriter.cpp b/src/theory/strings/theory_strings_rewriter.cpp
index 12ff92b5e..c952a7b3c 100644
--- a/src/theory/strings/theory_strings_rewriter.cpp
+++ b/src/theory/strings/theory_strings_rewriter.cpp
@@ -164,8 +164,12 @@ Node TheoryStringsRewriter::prerewriteOrRegExp(TNode node) {
for(unsigned i=0; i<node.getNumChildren(); ++i) {
if(node[i].getKind() == kind::REGEXP_UNION) {
Node tmpNode = prerewriteOrRegExp( node[i] );
- for(unsigned int j=0; j<tmpNode.getNumChildren(); ++j) {
- node_vec.push_back( tmpNode[j] );
+ if(tmpNode.getKind() == kind::REGEXP_UNION) {
+ for(unsigned int j=0; j<tmpNode.getNumChildren(); ++j) {
+ node_vec.push_back( tmpNode[j] );
+ }
+ } else {
+ node_vec.push_back( tmpNode );
}
flag = true;
} else if(node[i].getKind() == kind::REGEXP_EMPTY) {
@@ -200,6 +204,7 @@ bool TheoryStringsRewriter::checkConstRegExp( TNode t ) {
bool TheoryStringsRewriter::testConstStringInRegExp( CVC4::String &s, unsigned int index_start, TNode r ) {
Assert( index_start <= s.size() );
+ Trace("regexp-debug") << "Checking " << s << " in " << r << ", starting at " << index_start << std::endl;
int k = r.getKind();
switch( k ) {
case kind::STRING_TO_REGEXP: {
@@ -278,7 +283,7 @@ bool TheoryStringsRewriter::testConstStringInRegExp( CVC4::String &s, unsigned i
return false;
}
case kind::REGEXP_SIGMA: {
- if(s.size() == 1) {
+ if(s.size() == index_start + 1) {
return true;
} else {
return false;
@@ -302,7 +307,7 @@ Node TheoryStringsRewriter::rewriteMembership(TNode node) {
if(node[1].getKind() == kind::REGEXP_EMPTY) {
retNode = NodeManager::currentNM()->mkConst( false );
- } else if( x.getKind() == kind::CONST_STRING && checkConstRegExp(node[1]) ) {
+ } else if(x.getKind()==kind::CONST_STRING && checkConstRegExp(node[1])) {
//test whether x in node[1]
CVC4::String s = x.getConst<String>();
retNode = NodeManager::currentNM()->mkConst( testConstStringInRegExp( s, 0, node[1] ) );
@@ -311,10 +316,12 @@ Node TheoryStringsRewriter::rewriteMembership(TNode node) {
retNode = one.eqNode(NodeManager::currentNM()->mkNode(kind::STRING_LENGTH, x));
} else if(node[1].getKind() == kind::REGEXP_STAR && node[1][0].getKind() == kind::REGEXP_SIGMA) {
retNode = NodeManager::currentNM()->mkConst( true );
- } else if( x != node[0] ) {
+ } else if(node[1].getKind() == kind::STRING_TO_REGEXP) {
+ retNode = x.eqNode(node[1][0]);
+ } else if(x != node[0]) {
retNode = NodeManager::currentNM()->mkNode( kind::STRING_IN_REGEXP, x, node[1] );
}
- return retNode;
+ return retNode;
}
RewriteResponse TheoryStringsRewriter::postRewrite(TNode node) {
@@ -375,16 +382,23 @@ RewriteResponse TheoryStringsRewriter::postRewrite(TNode node) {
retNode = NodeManager::currentNM()->mkConst( ::CVC4::String("") );
} else if( node[1].isConst() && node[2].isConst() ) {
if(node[1].getConst<Rational>().sgn()>=0 && node[2].getConst<Rational>().sgn()>=0) {
- int i = node[1].getConst<Rational>().getNumerator().toUnsignedInt();
- int j = node[2].getConst<Rational>().getNumerator().toUnsignedInt();
+ CVC4::Rational sum(node[1].getConst<Rational>() + node[2].getConst<Rational>());
if( node[0].isConst() ) {
- if( node[0].getConst<String>().size() >= (unsigned) (i + j) ) {
+ CVC4::Rational size(node[0].getConst<String>().size());
+ if( size >= sum ) {
+ //because size is smaller than MAX_INT
+ size_t i = node[1].getConst<Rational>().getNumerator().toUnsignedInt();
+ size_t j = node[2].getConst<Rational>().getNumerator().toUnsignedInt();
retNode = NodeManager::currentNM()->mkConst( node[0].getConst<String>().substr(i, j) );
} else {
retNode = NodeManager::currentNM()->mkConst( ::CVC4::String("") );
}
} else if(node[0].getKind() == kind::STRING_CONCAT && node[0][0].isConst()) {
- if( node[0][0].getConst<String>().size() >= (unsigned) (i + j) ) {
+ CVC4::Rational size2(node[0][0].getConst<String>().size());
+ if( size2 >= sum ) {
+ //because size2 is smaller than MAX_INT
+ size_t i = node[1].getConst<Rational>().getNumerator().toUnsignedInt();
+ size_t j = node[2].getConst<Rational>().getNumerator().toUnsignedInt();
retNode = NodeManager::currentNM()->mkConst( node[0][0].getConst<String>().substr(i, j) );
}
}
@@ -444,10 +458,12 @@ RewriteResponse TheoryStringsRewriter::postRewrite(TNode node) {
if( node[0].isConst() && node[1].isConst() && node[2].isConst() ) {
CVC4::String s = node[0].getConst<String>();
CVC4::String t = node[1].getConst<String>();
- int i = node[2].getConst<Rational>().getNumerator().toUnsignedInt();
+ CVC4::Rational RMAXINT(LONG_MAX);
+ Assert(node[2].getConst<Rational>() <= RMAXINT, "Number exceeds LONG_MAX in string index_of");
+ std::size_t i = node[2].getConst<Rational>().getNumerator().toUnsignedInt();
std::size_t ret = s.find(t, i);
if( ret != std::string::npos ) {
- retNode = NodeManager::currentNM()->mkConst( ::CVC4::Rational((int) ret) );
+ retNode = NodeManager::currentNM()->mkConst( ::CVC4::Rational((unsigned) ret) );
} else {
retNode = NodeManager::currentNM()->mkConst( ::CVC4::Rational(-1) );
}
@@ -627,6 +643,8 @@ RewriteResponse TheoryStringsRewriter::preRewrite(TNode node) {
if(r.getKind() == kind::REGEXP_STAR) {
retNode = r;
} else {
+ CVC4::Rational RMAXINT(LONG_MAX);
+ Assert(node[1].getConst<Rational>() <= RMAXINT, "Exceeded LONG_MAX in string REGEXP_LOOP (1)");
unsigned l = node[1].getConst<Rational>().getNumerator().toUnsignedInt();
std::vector< Node > vec_nodes;
for(unsigned i=0; i<l; i++) {
@@ -635,6 +653,7 @@ RewriteResponse TheoryStringsRewriter::preRewrite(TNode node) {
if(node.getNumChildren() == 3) {
Node n = vec_nodes.size()==0 ? NodeManager::currentNM()->mkNode(kind::STRING_TO_REGEXP, NodeManager::currentNM()->mkConst(CVC4::String("")))
: vec_nodes.size()==1 ? r : prerewriteConcatRegExp(NodeManager::currentNM()->mkNode(kind::REGEXP_CONCAT, vec_nodes));
+ Assert(node[2].getConst<Rational>() <= RMAXINT, "Exceeded LONG_MAX in string REGEXP_LOOP (2)");
unsigned u = node[2].getConst<Rational>().getNumerator().toUnsignedInt();
if(u <= l) {
retNode = n;
diff --git a/src/theory/strings/theory_strings_rewriter.h b/src/theory/strings/theory_strings_rewriter.h
index d33254e1b..9d04f107f 100644
--- a/src/theory/strings/theory_strings_rewriter.h
+++ b/src/theory/strings/theory_strings_rewriter.h
@@ -23,6 +23,7 @@
#include "theory/rewriter.h"
#include "theory/type_enumerator.h"
#include "expr/attribute.h"
+#include <climits>
namespace CVC4 {
namespace theory {
diff --git a/src/theory/strings/theory_strings_type_rules.h b/src/theory/strings/theory_strings_type_rules.h
index 6d1bb1c98..8a51ea36c 100644
--- a/src/theory/strings/theory_strings_type_rules.h
+++ b/src/theory/strings/theory_strings_type_rules.h
@@ -466,6 +466,21 @@ public:
}
};
+class RegExpRVTypeRule {
+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 in RV");
+ }
+ }
+ return nodeManager->regexpType();
+ }
+};
+
+
}/* CVC4::theory::strings namespace */
}/* CVC4::theory namespace */
}/* CVC4 namespace */
diff --git a/src/theory/theory.h b/src/theory/theory.h
index 7bfc7051f..867dd7c31 100644
--- a/src/theory/theory.h
+++ b/src/theory/theory.h
@@ -377,7 +377,7 @@ public:
/**
* Returns true if the assertFact queue is empty
*/
- bool done() throw() {
+ bool done() const throw() {
return d_factsHead == d_facts.size();
}
@@ -678,7 +678,7 @@ public:
* This function is called when an attribute is set by a user. In SMT-LIBv2 this is done
* via the syntax (! n :attr)
*/
- virtual void setUserAttribute(const std::string& attr, Node n) {
+ virtual void setUserAttribute(const std::string& attr, Node n, std::vector<Node> node_values, std::string str_value) {
Unimplemented("Theory %s doesn't support Theory::setUserAttribute interface",
identify().c_str());
}
diff --git a/src/theory/theory_engine.cpp b/src/theory/theory_engine.cpp
index eb1da84b2..7fb989a5a 100644
--- a/src/theory/theory_engine.cpp
+++ b/src/theory/theory_engine.cpp
@@ -34,6 +34,8 @@
#include "smt/logic_exception.h"
+#include "proof/proof_manager.h"
+
#include "util/node_visitor.h"
#include "util/ite_removal.h"
@@ -63,6 +65,8 @@ using namespace CVC4;
using namespace CVC4::theory;
void TheoryEngine::finishInit() {
+ PROOF (ProofManager::initTheoryProof(); );
+
// initialize the quantifiers engine
d_quantEngine = new QuantifiersEngine(d_context, d_userContext, this);
@@ -153,7 +157,7 @@ TheoryEngine::TheoryEngine(context::Context* context,
d_sharedTermsVisitor(d_sharedTerms),
d_unconstrainedSimp(new UnconstrainedSimplifier(context, logicInfo)),
d_bvToBoolPreprocessor(),
- d_arithSubstitutionsAdded("zzz::arith::substitutions", 0)
+ d_arithSubstitutionsAdded("theory::arith::zzz::arith::substitutions", 0)
{
for(TheoryId theoryId = theory::THEORY_FIRST; theoryId != theory::THEORY_LAST; ++ theoryId) {
d_theoryTable[theoryId] = NULL;
@@ -168,8 +172,6 @@ TheoryEngine::TheoryEngine(context::Context* context,
d_true = NodeManager::currentNM()->mkConst<bool>(true);
d_false = NodeManager::currentNM()->mkConst<bool>(false);
- PROOF (ProofManager::currentPM()->initTheoryProof(); );
-
d_iteUtilities = new ITEUtilities(d_iteRemover.getContainsVisitor());
StatisticsRegistry::registerStat(&d_arithSubstitutionsAdded);
@@ -403,7 +405,7 @@ void TheoryEngine::check(Theory::Effort effort) {
propagate(effort);
// We do combination if all has been processed and we are in fullcheck
- if (Theory::fullEffort(effort) && d_logicInfo.isSharingEnabled() && !d_factsAsserted && !d_lemmasAdded) {
+ if (Theory::fullEffort(effort) && d_logicInfo.isSharingEnabled() && !d_factsAsserted && !d_lemmasAdded && !d_inConflict) {
// Do the combination
Debug("theory") << "TheoryEngine::check(" << effort << "): running combination" << endl;
combineTheories();
@@ -451,7 +453,7 @@ void TheoryEngine::check(Theory::Effort effort) {
void TheoryEngine::combineTheories() {
- Debug("sharing") << "TheoryEngine::combineTheories()" << endl;
+ Trace("combineTheories") << "TheoryEngine::combineTheories()" << endl;
TimerStat::CodeTimer combineTheoriesTimer(d_combineTheoriesTime);
@@ -469,25 +471,48 @@ 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() << endl;
+ Trace("combineTheories") << "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();
CareGraph::const_iterator care_it_end = careGraph.end();
+
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 << endl;
+ Debug("combineTheories") << "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());
// The equality in question (order for no repetition)
Node equality = carePair.a.eqNode(carePair.b);
+ // EqualityStatus es = getEqualityStatus(carePair.a, carePair.b);
+ // Debug("combineTheories") << "TheoryEngine::combineTheories(): " <<
+ // (es == EQUALITY_TRUE_AND_PROPAGATED ? "EQUALITY_TRUE_AND_PROPAGATED" :
+ // es == EQUALITY_FALSE_AND_PROPAGATED ? "EQUALITY_FALSE_AND_PROPAGATED" :
+ // es == EQUALITY_TRUE ? "EQUALITY_TRUE" :
+ // es == EQUALITY_FALSE ? "EQUALITY_FALSE" :
+ // es == EQUALITY_TRUE_IN_MODEL ? "EQUALITY_TRUE_IN_MODEL" :
+ // es == EQUALITY_FALSE_IN_MODEL ? "EQUALITY_FALSE_IN_MODEL" :
+ // es == EQUALITY_UNKNOWN ? "EQUALITY_UNKNOWN" :
+ // "Unexpected case") << endl;
// We need to split on it
- Debug("sharing") << "TheoryEngine::combineTheories(): requesting a split " << endl;
+ Debug("combineTheories") << "TheoryEngine::combineTheories(): requesting a split " << endl;
lemma(equality.orNode(equality.notNode()), false, false, false, carePair.theory);
+ // This code is supposed to force preference to follow what the theory models already have
+ // but it doesn't seem to make a big difference - need to explore more -Clark
+ // if (true) {
+ // if (es == EQUALITY_TRUE || es == EQUALITY_TRUE_IN_MODEL) {
+ Node e = ensureLiteral(equality);
+ d_propEngine->requirePhase(e, true);
+ // }
+ // else if (es == EQUALITY_FALSE_IN_MODEL) {
+ // Node e = ensureLiteral(equality);
+ // d_propEngine->requirePhase(e, false);
+ // }
+ // }
}
}
@@ -1180,6 +1205,18 @@ Node TheoryEngine::getModelValue(TNode var) {
return theoryOf(Theory::theoryOf(var.getType()))->getModelValue(var);
}
+
+Node TheoryEngine::ensureLiteral(TNode n) {
+ Debug("ensureLiteral") << "rewriting: " << n << std::endl;
+ Node rewritten = Rewriter::rewrite(n);
+ Debug("ensureLiteral") << " got: " << rewritten << std::endl;
+ Node preprocessed = preprocess(rewritten);
+ Debug("ensureLiteral") << "preprocessed: " << preprocessed << std::endl;
+ d_propEngine->ensureLiteral(preprocessed);
+ return preprocessed;
+}
+
+
void TheoryEngine::printInstantiations( std::ostream& out ) {
if( d_quantEngine ){
d_quantEngine->printInstantiations( out );
@@ -1339,6 +1376,8 @@ void TheoryEngine::ensureLemmaAtoms(const std::vector<TNode>& atoms, theory::The
}
theory::LemmaStatus TheoryEngine::lemma(TNode node, bool negated, bool removable, bool preprocess, theory::TheoryId atomsTo) {
+ // For resource-limiting (also does a time check).
+ spendResource();
// Do we need to check atoms
if (atomsTo != theory::THEORY_LAST) {
@@ -1385,23 +1424,17 @@ theory::LemmaStatus TheoryEngine::lemma(TNode node, bool negated, bool removable
}
// assert to prop engine
- d_propEngine->assertLemma(additionalLemmas[0], negated, removable);
+ d_propEngine->assertLemma(additionalLemmas[0], negated, removable, RULE_INVALID, node);
for (unsigned i = 1; i < additionalLemmas.size(); ++ i) {
additionalLemmas[i] = theory::Rewriter::rewrite(additionalLemmas[i]);
- d_propEngine->assertLemma(additionalLemmas[i], false, removable);
+ d_propEngine->assertLemma(additionalLemmas[i], false, removable, RULE_INVALID, node);
}
// WARNING: Below this point don't assume additionalLemmas[0] to be not negated.
- // WARNING: Below this point don't assume additionalLemmas[0] to be not negated.
if(negated) {
- // Can't we just get rid of passing around this 'negated' stuff?
- // Is it that hard for the propEngine to figure that out itself?
- // (I like the use of triple negation <evil laugh>.) --K
additionalLemmas[0] = additionalLemmas[0].notNode();
negated = false;
}
- // WARNING: Below this point don't assume additionalLemmas[0] to be not negated.
- // WARNING: Below this point don't assume additionalLemmas[0] to be not negated.
// assert to decision engine
if(!removable) {
@@ -1668,11 +1701,11 @@ void TheoryEngine::ppUnconstrainedSimp(vector<Node>& assertions)
}
-void TheoryEngine::setUserAttribute(const std::string& attr, Node n) {
+void TheoryEngine::setUserAttribute(const std::string& attr, Node n, std::vector<Node> node_values, std::string str_value) {
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);
+ d_attr_handle[attr][i]->setUserAttribute(attr, n, node_values, str_value);
}
} else {
//unhandled exception?
diff --git a/src/theory/theory_engine.h b/src/theory/theory_engine.h
index e6684d56e..e589e8f87 100644
--- a/src/theory/theory_engine.h
+++ b/src/theory/theory_engine.h
@@ -759,6 +759,11 @@ public:
Node getModelValue(TNode var);
/**
+ * Takes a literal and returns an equivalent literal that is guaranteed to be a SAT literal
+ */
+ Node ensureLiteral(TNode n);
+
+ /**
* Print all instantiations made by the quantifiers module.
*/
void printInstantiations( std::ostream& out );
@@ -820,7 +825,7 @@ public:
* This function is called when an attribute is set by a user. In SMT-LIBv2 this is done
* via the syntax (! n :attr)
*/
- void setUserAttribute(const std::string& attr, Node n);
+ void setUserAttribute(const std::string& attr, Node n, std::vector<Node> node_values, std::string str_value);
/**
* Handle user attribute.
diff --git a/src/theory/theory_model.cpp b/src/theory/theory_model.cpp
index 70ae2c03b..b67140db8 100644
--- a/src/theory/theory_model.cpp
+++ b/src/theory/theory_model.cpp
@@ -53,6 +53,7 @@ TheoryModel::~TheoryModel() {
}
void TheoryModel::reset(){
+ d_modelCache.clear();
d_reps.clear();
d_rep_set.clear();
d_uf_terms.clear();
@@ -98,6 +99,11 @@ Cardinality TheoryModel::getCardinality( Type t ) const{
Node TheoryModel::getModelValue(TNode n, bool hasBoundVars) const
{
+ std::hash_map<Node, Node, NodeHashFunction>::iterator it = d_modelCache.find(n);
+ if (it != d_modelCache.end()) {
+ return (*it).second;
+ }
+ Node ret = n;
if(n.getKind() == kind::EXISTS || n.getKind() == kind::FORALL) {
// We should have terms, thanks to TheoryQuantifiers::collectModelInfo().
// However, if the Decision Engine stops us early, there might be a
@@ -114,19 +120,23 @@ Node TheoryModel::getModelValue(TNode n, bool hasBoundVars) const
// checkModel(), and the quantifier actually matters, we'll get an
// assert-fail since the quantifier isn't a constant.
if(!d_equalityEngine->hasTerm(Rewriter::rewrite(n))) {
- return n;
+ d_modelCache[n] = ret;
+ return ret;
} else {
- n = Rewriter::rewrite(n);
+ ret = Rewriter::rewrite(n);
}
} else {
if(n.getKind() == kind::LAMBDA) {
NodeManager* nm = NodeManager::currentNM();
Node body = getModelValue(n[1], true);
body = Rewriter::rewrite(body);
- return nm->mkNode(kind::LAMBDA, n[0], body);
+ ret = nm->mkNode(kind::LAMBDA, n[0], body);
+ d_modelCache[n] = ret;
+ return ret;
}
if(n.isConst() || (hasBoundVars && n.getKind() == kind::BOUND_VARIABLE)) {
- return n;
+ d_modelCache[n] = ret;
+ return ret;
}
TypeNode t = n.getType();
@@ -135,7 +145,9 @@ Node TheoryModel::getModelValue(TNode n, bool hasBoundVars) const
std::map< Node, Node >::const_iterator it = d_uf_models.find(n);
if (it != d_uf_models.end()) {
// Existing function
- return it->second;
+ ret = it->second;
+ d_modelCache[n] = ret;
+ return ret;
}
// Unknown function symbol: return LAMBDA x. c, where c is the first constant in the enumeration of the range type
vector<TypeNode> argTypes = t.getArgTypes();
@@ -146,7 +158,9 @@ Node TheoryModel::getModelValue(TNode n, bool hasBoundVars) const
}
Node boundVarList = nm->mkNode(kind::BOUND_VAR_LIST, args);
TypeEnumerator te(t.getRangeType());
- return nm->mkNode(kind::LAMBDA, boundVarList, *te);
+ ret = nm->mkNode(kind::LAMBDA, boundVarList, *te);
+ d_modelCache[n] = ret;
+ return ret;
}
// TODO: if func models not enabled, throw an error?
Unreachable();
@@ -155,9 +169,11 @@ Node TheoryModel::getModelValue(TNode n, bool hasBoundVars) const
if (n.getNumChildren() > 0 &&
n.getKind() != kind::BITVECTOR_ACKERMANIZE_UDIV &&
n.getKind() != kind::BITVECTOR_ACKERMANIZE_UREM) {
+ Debug("model-getvalue-debug") << "Get model value children " << n << std::endl;
std::vector<Node> children;
if (n.getKind() == APPLY_UF) {
Node op = getModelValue(n.getOperator(), hasBoundVars);
+ Debug("model-getvalue-debug") << " operator : " << op << std::endl;
children.push_back(op);
}
else if (n.getMetaKind() == kind::metakind::PARAMETERIZED) {
@@ -165,34 +181,40 @@ Node TheoryModel::getModelValue(TNode n, bool hasBoundVars) const
}
//evaluate the children
for (unsigned i = 0; i < n.getNumChildren(); ++i) {
- Node val = getModelValue(n[i], hasBoundVars);
- children.push_back(val);
+ ret = getModelValue(n[i], hasBoundVars);
+ Debug("model-getvalue-debug") << " " << n << "[" << i << "] is " << ret << std::endl;
+ children.push_back(ret);
}
- Node val = Rewriter::rewrite(NodeManager::currentNM()->mkNode(n.getKind(), children));
- if(val.getKind() == kind::CARDINALITY_CONSTRAINT) {
- val = NodeManager::currentNM()->mkConst(getCardinality(val[0].getType().toType()).getFiniteCardinality() <= val[1].getConst<Rational>().getNumerator());
+ ret = Rewriter::rewrite(NodeManager::currentNM()->mkNode(n.getKind(), children));
+ if(ret.getKind() == kind::CARDINALITY_CONSTRAINT) {
+ ret = NodeManager::currentNM()->mkConst(getCardinality(ret[0].getType().toType()).getFiniteCardinality() <= ret[1].getConst<Rational>().getNumerator());
}
- if(val.getKind() == kind::COMBINED_CARDINALITY_CONSTRAINT ){
+ if(ret.getKind() == kind::COMBINED_CARDINALITY_CONSTRAINT ){
//FIXME
- val = NodeManager::currentNM()->mkConst(false);
+ ret = NodeManager::currentNM()->mkConst(false);
}
- return val;
+ d_modelCache[n] = ret;
+ return ret;
}
if (!d_equalityEngine->hasTerm(n)) {
// Unknown term - return first enumerated value for this type
TypeEnumerator te(n.getType());
- return *te;
+ ret = *te;
+ d_modelCache[n] = ret;
+ return ret;
}
}
- Node val = d_equalityEngine->getRepresentative(n);
- Assert(d_reps.find(val) != d_reps.end());
- std::map< Node, Node >::const_iterator it = d_reps.find( val );
- if( it!=d_reps.end() ){
- return it->second;
- }else{
- return Node::null();
+ ret = d_equalityEngine->getRepresentative(ret);
+ Assert(d_reps.find(ret) != d_reps.end());
+ std::map< Node, Node >::const_iterator it2 = d_reps.find( ret );
+ if (it2 != d_reps.end()) {
+ ret = it2->second;
+ } else {
+ ret = Node::null();
}
+ d_modelCache[n] = ret;
+ return ret;
}
Node TheoryModel::getDomainValue( TypeNode tn, std::vector< Node >& exclude ){
@@ -659,7 +681,10 @@ void TheoryEngineModelBuilder::buildModel(Model* m, bool fullModel)
continue;
}
TypeNode t = TypeSet::getType(it);
- TypeNode tb = t.getBaseType();
+ if(t.isTuple() || t.isRecord()) {
+ t = NodeManager::currentNM()->getDatatypeForTupleRecord(t);
+ }
+ TypeNode tb = t.getBaseType();
if (!assignOne) {
set<Node>* repSet = typeRepSet.getSet(tb);
if (repSet != NULL && !repSet->empty()) {
diff --git a/src/theory/theory_model.h b/src/theory/theory_model.h
index 2eb33b0fb..eeaf3c8da 100644
--- a/src/theory/theory_model.h
+++ b/src/theory/theory_model.h
@@ -52,6 +52,7 @@ public:
Node d_true;
Node d_false;
context::CDO<bool> d_modelBuilt;
+ mutable std::hash_map<Node, Node, NodeHashFunction> d_modelCache;
protected:
/** reset the model */
diff --git a/src/theory/uf/options b/src/theory/uf/options
index 26f87da79..d9e4c9477 100644
--- a/src/theory/uf/options
+++ b/src/theory/uf/options
@@ -29,8 +29,8 @@ 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 ufssMode --uf-ss=MODE CVC4::theory::uf::UfssMode :default CVC4::theory::uf::UF_SS_FULL :include "theory/uf/options_handlers.h" :handler CVC4::theory::uf::stringToUfssMode :handler-include "theory/uf/options_handlers.h"
+ mode of operation for uf strong solver.
option ufssCliqueSplits --uf-ss-clique-splits bool :default false
use cliques instead of splitting on demand to shrink model
diff --git a/src/theory/uf/options_handlers.h b/src/theory/uf/options_handlers.h
index a885a10d2..8c072e232 100644
--- a/src/theory/uf/options_handlers.h
+++ b/src/theory/uf/options_handlers.h
@@ -2,7 +2,7 @@
/*! \file options_handlers.h
** \verbatim
** Original author: Morgan Deters
- ** Major contributors: none
+ ** Major contributors: Andrew Reynolds
** Minor contributors (to current version): none
** This file is part of the CVC4 project.
** Copyright (c) 2009-2014 New York University and The University of Iowa
@@ -22,6 +22,45 @@
namespace CVC4 {
namespace theory {
namespace uf {
+
+typedef enum {
+ /** default, use uf strong solver to find minimal models for uninterpreted sorts */
+ UF_SS_FULL,
+ /** use uf strong solver to shrink model sizes, but do no enforce minimality */
+ UF_SS_NO_MINIMAL,
+ /** do not use uf strong solver */
+ UF_SS_NONE,
+} UfssMode;
+
+static const std::string ufssModeHelp = "\
+UF strong solver options currently supported by the --uf-ss option:\n\
+\n\
+full \n\
++ Default, use uf strong solver to find minimal models for uninterpreted sorts.\n\
+\n\
+no-minimal \n\
++ Use uf strong solver to shrink model sizes, but do no enforce minimality.\n\
+\n\
+none \n\
++ Do not use uf strong solver to shrink model sizes. \n\
+\n\
+";
+
+inline UfssMode stringToUfssMode(std::string option, std::string optarg, SmtEngine* smt) throw(OptionException) {
+ if(optarg == "default" || optarg == "full" ) {
+ return UF_SS_FULL;
+ } else if(optarg == "no-minimal") {
+ return UF_SS_NO_MINIMAL;
+ } else if(optarg == "none") {
+ return UF_SS_NONE;
+ } else if(optarg == "help") {
+ puts(ufssModeHelp.c_str());
+ exit(1);
+ } else {
+ throw OptionException(std::string("unknown option for --uf-ss: `") +
+ optarg + "'. Try --uf-ss help.");
+ }
+}
}/* CVC4::theory::uf namespace */
}/* CVC4::theory namespace */
diff --git a/src/theory/uf/theory_uf.cpp b/src/theory/uf/theory_uf.cpp
index 0da8e8c32..2b9fc3daf 100644
--- a/src/theory/uf/theory_uf.cpp
+++ b/src/theory/uf/theory_uf.cpp
@@ -61,7 +61,7 @@ void TheoryUF::setMasterEqualityEngine(eq::EqualityEngine* eq) {
void TheoryUF::finishInit() {
// initialize the strong solver
- if (options::finiteModelFind()) {
+ if (options::finiteModelFind() && options::ufssMode()!=UF_SS_NONE) {
d_thss = new StrongSolverTheoryUF(getSatContext(), getUserContext(), *d_out, this);
}
}
@@ -89,6 +89,10 @@ static Node mkAnd(const std::vector<TNode>& conjunctions) {
}/* mkAnd() */
void TheoryUF::check(Effort level) {
+ if (done() && !fullEffort(level)) {
+ return;
+ }
+
while (!done() && !d_conflict)
{
// Get all the assertions
diff --git a/src/theory/uf/theory_uf_strong_solver.cpp b/src/theory/uf/theory_uf_strong_solver.cpp
index 001b21d0a..cddaace3e 100644
--- a/src/theory/uf/theory_uf_strong_solver.cpp
+++ b/src/theory/uf/theory_uf_strong_solver.cpp
@@ -339,16 +339,6 @@ bool StrongSolverTheoryUF::SortModel::Region::getCandidateClique( int cardinalit
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;
- if( rni->d_valid ){
- reps.push_back( it->first );
- }
- }
-}
-
void StrongSolverTheoryUF::SortModel::Region::getNumExternalDisequalities( std::map< Node, int >& num_ext_disequalities ){
for( std::map< Node, RegionNodeInfo* >::iterator it = d_nodes.begin(); it != d_nodes.end(); ++it ){
RegionNodeInfo* rni = it->second;
@@ -624,7 +614,7 @@ 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 ) ){
- if( options::ufssMinimalModel() ){
+ if( options::ufssMode()==UF_SS_FULL ){
//add clique lemma
addCliqueLemma( clique, out );
return;
@@ -695,7 +685,7 @@ void StrongSolverTheoryUF::SortModel::check( Theory::Effort level, OutputChannel
if( d_regions[i]->d_valid ){
int fcr = forceCombineRegion( i, false );
Trace("uf-ss-debug") << "Combined regions " << i << " " << fcr << std::endl;
- if( options::ufssMinimalModel() || fcr!=-1 ){
+ if( options::ufssMode()==UF_SS_FULL || fcr!=-1 ){
recheck = true;
break;
}
@@ -921,7 +911,7 @@ 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 ) ){
- if( options::ufssMinimalModel() ){
+ if( options::ufssMode()==UF_SS_FULL ){
//explain clique
addCliqueLemma( clique, &d_thss->getOutputChannel() );
}
@@ -1085,7 +1075,7 @@ int StrongSolverTheoryUF::SortModel::addSplit( Region* r, OutputChannel* out ){
}
Assert( s!=Node::null() );
}else{
- if( !options::ufssMinimalModel() ){
+ if( options::ufssMode()!=UF_SS_FULL ){
//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 ){
@@ -1480,19 +1470,6 @@ int StrongSolverTheoryUF::SortModel::getNumRegions(){
return count;
}
-void StrongSolverTheoryUF::SortModel::getRepresentatives( std::vector< Node >& reps ){
- 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 );
- }
- }
-}
-
Node StrongSolverTheoryUF::SortModel::getCardinalityLiteral( int c ) {
if( d_cardinality_literal.find( c )==d_cardinality_literal.end() ){
d_cardinality_literal[c] = NodeManager::currentNM()->mkNode( CARDINALITY_CONSTRAINT, d_cardinality_term,
@@ -1661,7 +1638,7 @@ bool StrongSolverTheoryUF::areDisequal( Node a, Node b ) {
void StrongSolverTheoryUF::check( Theory::Effort level ){
if( !d_conflict ){
Trace("uf-ss-solver") << "StrongSolverTheoryUF: check " << level << std::endl;
- if( level==Theory::EFFORT_FULL ){
+ if( level==Theory::EFFORT_FULL && Debug.isOn( "uf-ss-debug" ) ){
debugPrint( "uf-ss-debug" );
}
for( std::map< TypeNode, SortModel* >::iterator it = d_rep_model.begin(); it != d_rep_model.end(); ++it ){
@@ -1801,19 +1778,6 @@ int StrongSolverTheoryUF::getCardinality( TypeNode tn ) {
return -1;
}
-/*
-void StrongSolverTheoryUF::getRepresentatives( Node n, std::vector< Node >& reps ){
- SortModel* c = getSortModel( n );
- if( c ){
- c->getRepresentatives( reps );
- if( (int)reps.size()!=c->getCardinality() ){
- Trace("uf-ss-warn") << "Sort " << n.getType() << " has cardinality " << c->getCardinality();
- Trace("uf-ss-warn") << ", but provided " << reps.size() << " representatives!!!" << std::endl;
- }
- }
-}
-*/
-
bool StrongSolverTheoryUF::minimize( TheoryModel* m ){
for( std::map< TypeNode, SortModel* >::iterator it = d_rep_model.begin(); it != d_rep_model.end(); ++it ){
if( !it->second->minimize( d_out, m ) ){
diff --git a/src/theory/uf/theory_uf_strong_solver.h b/src/theory/uf/theory_uf_strong_solver.h
index 1e5a361a7..333f1717e 100644
--- a/src/theory/uf/theory_uf_strong_solver.h
+++ b/src/theory/uf/theory_uf_strong_solver.h
@@ -146,8 +146,6 @@ public:
bool getMustCombine( int cardinality );
/** has splits */
bool hasSplits() { return d_splitsSize>0; }
- /** get representatives */
- void getRepresentatives( std::vector< Node >& reps );
/** get external disequalities */
void getNumExternalDisequalities( std::map< Node, int >& num_ext_disequalities );
public:
@@ -280,8 +278,6 @@ public:
bool isConflict() { return d_conflict; }
/** get cardinality */
int getCardinality() { return d_cardinality; }
- /** get representatives */
- void getRepresentatives( std::vector< Node >& reps );
/** has cardinality */
bool hasCardinalityAsserted() { return d_hasCard; }
/** get cardinality term */
@@ -381,8 +377,6 @@ public:
int getCardinality( Node n );
/** get cardinality for type */
int getCardinality( TypeNode tn );
- /** get representatives */
- //void getRepresentatives( Node n, std::vector< Node >& reps );
/** minimize */
bool minimize( TheoryModel* m = NULL );
diff --git a/src/theory/uf/theory_uf_type_rules.h b/src/theory/uf/theory_uf_type_rules.h
index c30742ac5..93fd1dc6f 100644
--- a/src/theory/uf/theory_uf_type_rules.h
+++ b/src/theory/uf/theory_uf_type_rules.h
@@ -91,8 +91,8 @@ public:
if( n[0].getKind()!=kind::CONST_RATIONAL ){
throw TypeCheckingExceptionPrivate(n, "combined cardinality constraint must be a constant");
}
- if( n[0].getConst<Rational>().getNumerator().sgn()!=1 ){
- throw TypeCheckingExceptionPrivate(n, "combined cardinality constraint must be positive");
+ if( n[0].getConst<Rational>().getNumerator().sgn()==-1 ){
+ throw TypeCheckingExceptionPrivate(n, "combined cardinality constraint must be non-negative");
}
}
return nodeManager->booleanType();
diff --git a/src/theory/valuation.cpp b/src/theory/valuation.cpp
index 72d878782..7407086c2 100644
--- a/src/theory/valuation.cpp
+++ b/src/theory/valuation.cpp
@@ -88,13 +88,7 @@ Node Valuation::getModelValue(TNode var) {
}
Node Valuation::ensureLiteral(TNode n) {
- Debug("ensureLiteral") << "rewriting: " << n << std::endl;
- Node rewritten = Rewriter::rewrite(n);
- Debug("ensureLiteral") << " got: " << rewritten << std::endl;
- Node preprocessed = d_engine->preprocess(rewritten);
- Debug("ensureLiteral") << "preproced: " << preprocessed << std::endl;
- d_engine->getPropEngine()->ensureLiteral(preprocessed);
- return preprocessed;
+ return d_engine->ensureLiteral(n);
}
bool Valuation::isDecision(Node lit) const {
@@ -109,5 +103,9 @@ std::pair<bool, Node> Valuation::entailmentCheck(theory::TheoryOfMode mode, TNod
return d_engine->entailmentCheck(mode, lit, params, out);
}
+bool Valuation::needCheck() const{
+ return d_engine->needCheck();
+}
+
}/* CVC4::theory namespace */
}/* CVC4 namespace */
diff --git a/src/theory/valuation.h b/src/theory/valuation.h
index 448d055d4..540ebd8fc 100644
--- a/src/theory/valuation.h
+++ b/src/theory/valuation.h
@@ -135,6 +135,9 @@ public:
*/
std::pair<bool, Node> entailmentCheck(theory::TheoryOfMode mode, TNode lit, const theory::EntailmentCheckParameters* params = NULL, theory::EntailmentCheckSideEffects* out = NULL);
+ /** need check ? */
+ bool needCheck() const;
+
};/* class Valuation */
}/* CVC4::theory namespace */
diff --git a/src/util/Makefile.am b/src/util/Makefile.am
index 5cf5da1e0..fc9192dd9 100644
--- a/src/util/Makefile.am
+++ b/src/util/Makefile.am
@@ -97,7 +97,9 @@ libutil_la_SOURCES = \
regexp.cpp \
bin_heap.h \
didyoumean.h \
- didyoumean.cpp
+ didyoumean.cpp \
+ unsat_core.h \
+ unsat_core.cpp
libstatistics_la_SOURCES = \
statistics_registry.h \
@@ -156,7 +158,8 @@ EXTRA_DIST = \
uninterpreted_constant.i \
chain.i \
regexp.i \
- proof.i
+ proof.i \
+ unsat_core.i
DISTCLEANFILES = \
integer.h.tmp \
diff --git a/src/util/datatype.cpp b/src/util/datatype.cpp
index 9e07c746a..f0704520a 100644
--- a/src/util/datatype.cpp
+++ b/src/util/datatype.cpp
@@ -299,8 +299,12 @@ Expr Datatype::mkGroundTerm( Type t ) const throw(IllegalArgumentException) {
}
}
if( groundTerm.isNull() ){
- // if we get all the way here, we aren't well-founded
- CheckArgument(false, *this, "this datatype is not well-founded, cannot construct a ground term!");
+ if( !d_isCo ){
+ // if we get all the way here, we aren't well-founded
+ CheckArgument(false, *this, "this datatype is not well-founded, cannot construct a ground term!");
+ }else{
+ return groundTerm;
+ }
}else{
return groundTerm;
}
diff --git a/src/util/ite_removal.cpp b/src/util/ite_removal.cpp
index 68d7d9a34..97a6338ce 100644
--- a/src/util/ite_removal.cpp
+++ b/src/util/ite_removal.cpp
@@ -19,6 +19,7 @@
#include "util/ite_removal.h"
#include "expr/command.h"
#include "theory/ite_utilities.h"
+#include "proof/proof_manager.h"
using namespace CVC4;
using namespace std;
@@ -47,13 +48,23 @@ size_t RemoveITE::collectedCacheSizes() const{
return d_containsVisitor->cache_size() + d_iteCache.size();
}
-void RemoveITE::run(std::vector<Node>& output, IteSkolemMap& iteSkolemMap)
+void RemoveITE::run(std::vector<Node>& output, IteSkolemMap& iteSkolemMap, bool reportDeps)
{
+ size_t n = output.size();
for (unsigned i = 0, i_end = output.size(); i < i_end; ++ i) {
// 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, false);
+ // In some calling contexts, not necessary to report dependence information.
+ if(reportDeps && options::unsatCores()) {
+ // new assertions have a dependence on the node
+ PROOF( ProofManager::currentPM()->addDependence(itesRemoved, output[i]); )
+ while(n < output.size()) {
+ PROOF( ProofManager::currentPM()->addDependence(output[n], output[i]); )
+ ++n;
+ }
+ }
output[i] = itesRemoved;
}
}
diff --git a/src/util/ite_removal.h b/src/util/ite_removal.h
index 83c55dab7..d71f9b13d 100644
--- a/src/util/ite_removal.h
+++ b/src/util/ite_removal.h
@@ -50,8 +50,11 @@ public:
* contains a map from introduced skolem variables to the index in
* assertions containing the new Boolean ite created in conjunction
* with that skolem variable.
+ *
+ * With reportDeps true, report reasoning dependences to the proof
+ * manager (for unsat cores).
*/
- void run(std::vector<Node>& assertions, IteSkolemMap& iteSkolemMap);
+ void run(std::vector<Node>& assertions, IteSkolemMap& iteSkolemMap, bool reportDeps = false);
/**
* Removes the ITE from the node by introducing skolem
diff --git a/src/util/language.cpp b/src/util/language.cpp
index f19f20c03..ca611f729 100644
--- a/src/util/language.cpp
+++ b/src/util/language.cpp
@@ -22,7 +22,8 @@ namespace language {
InputLanguage toInputLanguage(OutputLanguage language) {
switch(language) {
case output::LANG_SMTLIB_V1:
- case output::LANG_SMTLIB_V2:
+ case output::LANG_SMTLIB_V2_0:
+ case output::LANG_SMTLIB_V2_5:
case output::LANG_TPTP:
case output::LANG_CVC4:
case output::LANG_Z3STR:
@@ -41,7 +42,8 @@ InputLanguage toInputLanguage(OutputLanguage language) {
OutputLanguage toOutputLanguage(InputLanguage language) {
switch(language) {
case input::LANG_SMTLIB_V1:
- case input::LANG_SMTLIB_V2:
+ case input::LANG_SMTLIB_V2_0:
+ case input::LANG_SMTLIB_V2_5:
case input::LANG_TPTP:
case input::LANG_CVC4:
case input::LANG_Z3STR:
@@ -75,8 +77,12 @@ OutputLanguage toOutputLanguage(std::string language) {
return output::LANG_SMTLIB_V1;
} else if(language == "smtlib" || language == "smt" ||
language == "smtlib2" || language == "smt2" ||
- language == "LANG_SMTLIB_V2") {
- return output::LANG_SMTLIB_V2;
+ language == "smtlib2.0" || language == "smt2.0" ||
+ language == "LANG_SMTLIB_V2_0" || language == "LANG_SMTLIB_V2") {
+ return output::LANG_SMTLIB_V2_0;
+ } else if(language == "smtlib2.5" || language == "smt2.5" ||
+ language == "LANG_SMTLIB_V2_5") {
+ return output::LANG_SMTLIB_V2_5;
} else if(language == "tptp" || language == "LANG_TPTP") {
return output::LANG_TPTP;
} else if(language == "z3str" || language == "z3-str" ||
@@ -101,8 +107,12 @@ InputLanguage toInputLanguage(std::string language) {
return input::LANG_SMTLIB_V1;
} else if(language == "smtlib" || language == "smt" ||
language == "smtlib2" || language == "smt2" ||
- language == "LANG_SMTLIB_V2") {
- return input::LANG_SMTLIB_V2;
+ language == "smtlib2.0" || language == "smt2.0" ||
+ language == "LANG_SMTLIB_V2_0" || language == "LANG_SMTLIB_V2") {
+ return input::LANG_SMTLIB_V2_0;
+ } else if(language == "smtlib2.5" || language == "smt2.5" ||
+ language == "LANG_SMTLIB_V2_5") {
+ return input::LANG_SMTLIB_V2_5;
} else if(language == "tptp" || language == "LANG_TPTP") {
return input::LANG_TPTP;
} else if(language == "z3str" || language == "z3-str" ||
diff --git a/src/util/language.h b/src/util/language.h
index be962bf3e..abde0b509 100644
--- a/src/util/language.h
+++ b/src/util/language.h
@@ -45,8 +45,12 @@ enum CVC4_PUBLIC Language {
/** The SMTLIB v1 input language */
LANG_SMTLIB_V1 = 0,
- /** The SMTLIB v2 input language */
- LANG_SMTLIB_V2,
+ /** The SMTLIB v2.0 input language */
+ LANG_SMTLIB_V2_0,
+ /** The SMTLIB v2.5 input language */
+ LANG_SMTLIB_V2_5,
+ /** Backward-compatibility for enumeration naming */
+ LANG_SMTLIB_V2 = LANG_SMTLIB_V2_5,
/** The TPTP input language */
LANG_TPTP,
/** The CVC4 input language */
@@ -70,8 +74,11 @@ inline std::ostream& operator<<(std::ostream& out, Language lang) {
case LANG_SMTLIB_V1:
out << "LANG_SMTLIB_V1";
break;
- case LANG_SMTLIB_V2:
- out << "LANG_SMTLIB_V2";
+ case LANG_SMTLIB_V2_0:
+ out << "LANG_SMTLIB_V2_0";
+ break;
+ case LANG_SMTLIB_V2_5:
+ out << "LANG_SMTLIB_V2_5";
break;
case LANG_TPTP:
out << "LANG_TPTP";
@@ -107,7 +114,11 @@ enum CVC4_PUBLIC Language {
/** The SMTLIB v1 output language */
LANG_SMTLIB_V1 = input::LANG_SMTLIB_V1,
- /** The SMTLIB v2 output language */
+ /** The SMTLIB v2.0 output language */
+ LANG_SMTLIB_V2_0 = input::LANG_SMTLIB_V2_0,
+ /** The SMTLIB v2.5 output language */
+ LANG_SMTLIB_V2_5 = input::LANG_SMTLIB_V2_5,
+ /** Backward-compatibility for enumeration naming */
LANG_SMTLIB_V2 = input::LANG_SMTLIB_V2,
/** The TPTP output language */
LANG_TPTP = input::LANG_TPTP,
@@ -134,8 +145,11 @@ inline std::ostream& operator<<(std::ostream& out, Language lang) {
case LANG_SMTLIB_V1:
out << "LANG_SMTLIB_V1";
break;
- case LANG_SMTLIB_V2:
- out << "LANG_SMTLIB_V2";
+ case LANG_SMTLIB_V2_0:
+ out << "LANG_SMTLIB_V2_0";
+ break;
+ case LANG_SMTLIB_V2_5:
+ out << "LANG_SMTLIB_V2_5";
break;
case LANG_TPTP:
out << "LANG_TPTP";
diff --git a/src/util/language.i b/src/util/language.i
index 4cbe01df3..3ffc518ac 100644
--- a/src/util/language.i
+++ b/src/util/language.i
@@ -21,6 +21,8 @@ namespace CVC4 {
%rename(INPUT_LANG_AUTO) CVC4::language::input::LANG_AUTO;
%rename(INPUT_LANG_SMTLIB_V1) CVC4::language::input::LANG_SMTLIB_V1;
%rename(INPUT_LANG_SMTLIB_V2) CVC4::language::input::LANG_SMTLIB_V2;
+%rename(INPUT_LANG_SMTLIB_V2_0) CVC4::language::input::LANG_SMTLIB_V2_0;
+%rename(INPUT_LANG_SMTLIB_V2_5) CVC4::language::input::LANG_SMTLIB_V2_5;
%rename(INPUT_LANG_TPTP) CVC4::language::input::LANG_TPTP;
%rename(INPUT_LANG_CVC4) CVC4::language::input::LANG_CVC4;
%rename(INPUT_LANG_MAX) CVC4::language::input::LANG_MAX;
@@ -29,6 +31,8 @@ namespace CVC4 {
%rename(OUTPUT_LANG_AUTO) CVC4::language::output::LANG_AUTO;
%rename(OUTPUT_LANG_SMTLIB_V1) CVC4::language::output::LANG_SMTLIB_V1;
%rename(OUTPUT_LANG_SMTLIB_V2) CVC4::language::output::LANG_SMTLIB_V2;
+%rename(OUTPUT_LANG_SMTLIB_V2_0) CVC4::language::output::LANG_SMTLIB_V2_0;
+%rename(OUTPUT_LANG_SMTLIB_V2_5) CVC4::language::output::LANG_SMTLIB_V2_5;
%rename(OUTPUT_LANG_TPTP) CVC4::language::output::LANG_TPTP;
%rename(OUTPUT_LANG_CVC4) CVC4::language::output::LANG_CVC4;
%rename(OUTPUT_LANG_AST) CVC4::language::output::LANG_AST;
diff --git a/src/util/regexp.h b/src/util/regexp.h
index e75ca1fad..2b7bfa303 100644
--- a/src/util/regexp.h
+++ b/src/util/regexp.h
@@ -24,8 +24,9 @@
#include <string>
#include <set>
#include <sstream>
-#include "util/exception.h"
+#include <cassert>
//#include "util/integer.h"
+#include "util/exception.h"
#include "util/hash.h"
namespace CVC4 {
@@ -65,7 +66,7 @@ private:
} else if (c >= 'a' && c <= 'f') {
return c - 'a' + 10;
} else {
- //Assert(c >= 'A' && c <= 'F');
+ assert(c >= 'A' && c <= 'F');
return c - 'A' + 10;
}
}
@@ -151,14 +152,34 @@ public:
}
}
- bool strncmp(const String &y, unsigned int n) const {
- for(unsigned int i=0; i<n; ++i)
+ bool strncmp(const String &y, const std::size_t np) const {
+ std::size_t n = np;
+ std::size_t b = (d_str.size() >= y.d_str.size()) ? d_str.size() : y.d_str.size();
+ std::size_t s = (d_str.size() <= y.d_str.size()) ? d_str.size() : y.d_str.size();
+ if(n > s) {
+ if(b == s) {
+ n = s;
+ } else {
+ return false;
+ }
+ }
+ for(std::size_t i=0; i<n; ++i)
if(d_str[i] != y.d_str[i]) return false;
return true;
}
- bool rstrncmp(const String &y, unsigned int n) const {
- for(unsigned int i=0; i<n; ++i)
+ bool rstrncmp(const String &y, const std::size_t np) const {
+ std::size_t n = np;
+ std::size_t b = (d_str.size() >= y.d_str.size()) ? d_str.size() : y.d_str.size();
+ std::size_t s = (d_str.size() <= y.d_str.size()) ? d_str.size() : y.d_str.size();
+ if(n > s) {
+ if(b == s) {
+ n = s;
+ } else {
+ return false;
+ }
+ }
+ for(std::size_t i=0; i<n; ++i)
if(d_str[d_str.size() - i - 1] != y.d_str[y.d_str.size() - i - 1]) return false;
return true;
}
@@ -167,8 +188,8 @@ public:
return ( d_str.size() == 0 );
}
- unsigned int operator[] (const unsigned int i) const {
- //Assert( i < d_str.size() && i >= 0);
+ unsigned int operator[] (const std::size_t i) const {
+ assert( i < d_str.size() );
return d_str[i];
}
/*
@@ -208,19 +229,19 @@ public:
return true;
}
- std::size_t find(const String &y, const int start = 0) const {
- if(d_str.size() < y.d_str.size() + (std::size_t) start) return std::string::npos;
- if(y.d_str.size() == 0) return (std::size_t) start;
+ std::size_t find(const String &y, const std::size_t start = 0) const {
+ if(d_str.size() < y.d_str.size() + start) return std::string::npos;
+ if(y.d_str.size() == 0) return start;
if(d_str.size() == 0) return std::string::npos;
std::size_t ret = std::string::npos;
- for(int i = start; i <= (int) d_str.size() - (int) y.d_str.size(); i++) {
+ for(std::size_t i = start; i <= d_str.size() - y.d_str.size(); i++) {
if(d_str[i] == y.d_str[0]) {
std::size_t j=0;
for(; j<y.d_str.size(); j++) {
if(d_str[i+j] != y.d_str[j]) break;
}
if(j == y.d_str.size()) {
- ret = (std::size_t) i;
+ ret = i;
break;
}
}
@@ -241,23 +262,25 @@ public:
}
}
- String substr(unsigned i) const {
+ String substr(std::size_t i) const {
+ assert(i <= d_str.size());
std::vector<unsigned int> ret_vec;
std::vector<unsigned int>::const_iterator itr = d_str.begin() + i;
ret_vec.insert(ret_vec.end(), itr, d_str.end());
return String(ret_vec);
}
- String substr(unsigned i, unsigned j) const {
+ String substr(std::size_t i, std::size_t j) const {
+ assert(i+j <= d_str.size());
std::vector<unsigned int> ret_vec;
std::vector<unsigned int>::const_iterator itr = d_str.begin() + i;
ret_vec.insert( ret_vec.end(), itr, itr + j );
return String(ret_vec);
}
- String prefix(unsigned i) const {
+ String prefix(std::size_t i) const {
return substr(0, i);
}
- String suffix(unsigned i) const {
+ String suffix(std::size_t i) const {
return substr(d_str.size() - i, i);
}
std::size_t overlap(String &y) const;
diff --git a/src/util/sort_inference.cpp b/src/util/sort_inference.cpp
index 179bb1a23..066ba6103 100644
--- a/src/util/sort_inference.cpp
+++ b/src/util/sort_inference.cpp
@@ -23,6 +23,7 @@
#include "theory/uf/options.h"
#include "smt/options.h"
#include "theory/rewriter.h"
+#include "theory/quantifiers/options.h"
using namespace CVC4;
using namespace std;
@@ -333,7 +334,7 @@ int SortInference::process( Node n, std::map< Node, Node >& var_bound ){
for( size_t i=0; i<n.getNumChildren(); i++ ){
bool processChild = true;
if( n.getKind()==kind::FORALL || n.getKind()==kind::EXISTS ){
- processChild = i==1;
+ processChild = options::userPatternsQuant()==theory::quantifiers::USER_PAT_MODE_IGNORE ? i==1 : i>=1;
}
if( processChild ){
children.push_back( n[i] );
@@ -531,7 +532,7 @@ Node SortInference::simplify( Node n, std::map< Node, Node >& var_bound ){
for( size_t i=0; i<n.getNumChildren(); i++ ){
bool processChild = true;
if( n.getKind()==kind::FORALL || n.getKind()==kind::EXISTS ){
- processChild = i>=1;
+ processChild = options::userPatternsQuant()==theory::quantifiers::USER_PAT_MODE_IGNORE ? i==1 : i>=1;
}
if( processChild ){
children.push_back( simplify( n[i], var_bound ) );
diff --git a/src/util/unsat_core.cpp b/src/util/unsat_core.cpp
new file mode 100644
index 000000000..929d5e909
--- /dev/null
+++ b/src/util/unsat_core.cpp
@@ -0,0 +1,49 @@
+/********************* */
+/*! \file unsat_core.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-2014 New York University and The University of Iowa
+ ** See the file COPYING in the top-level source directory for licensing
+ ** information.\endverbatim
+ **
+ ** \brief Representation of unsat cores
+ **
+ ** Representation of unsat cores.
+ **/
+
+#include "util/unsat_core.h"
+#include "expr/command.h"
+#include "smt/smt_engine_scope.h"
+#include "printer/printer.h"
+
+namespace CVC4 {
+
+UnsatCore::const_iterator UnsatCore::begin() const {
+ return d_core.begin();
+}
+
+UnsatCore::const_iterator UnsatCore::end() const {
+ return d_core.end();
+}
+
+void UnsatCore::toStream(std::ostream& out) const {
+ smt::SmtScope smts(d_smt);
+ Expr::dag::Scope scope(out, false);
+ Printer::getPrinter(options::outputLanguage())->toStream(out, *this);
+}
+
+void UnsatCore::toStream(std::ostream& out, const std::map<Expr, std::string>& names) const {
+ smt::SmtScope smts(d_smt);
+ Expr::dag::Scope scope(out, false);
+ Printer::getPrinter(options::outputLanguage())->toStream(out, *this, names);
+}
+
+std::ostream& operator<<(std::ostream& out, const UnsatCore& core) {
+ core.toStream(out);
+ return out;
+}
+
+}/* CVC4 namespace */
diff --git a/src/util/unsat_core.h b/src/util/unsat_core.h
new file mode 100644
index 000000000..27cf86488
--- /dev/null
+++ b/src/util/unsat_core.h
@@ -0,0 +1,66 @@
+/********************* */
+/*! \file unsat_core.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-2014 New York University and The University of Iowa
+ ** See the file COPYING in the top-level source directory for licensing
+ ** information.\endverbatim
+ **
+ ** \brief [[ Add one-line brief description here ]]
+ **
+ ** [[ Add lengthier description here ]]
+ ** \todo document this file
+ **/
+
+#include "cvc4_public.h"
+
+#ifndef __CVC4__UNSAT_CORE_H
+#define __CVC4__UNSAT_CORE_H
+
+#include <iostream>
+#include <vector>
+#include "expr/expr.h"
+
+namespace CVC4 {
+
+class SmtEngine;
+class UnsatCore;
+
+std::ostream& operator<<(std::ostream& out, const UnsatCore& core) CVC4_PUBLIC;
+
+class CVC4_PUBLIC UnsatCore {
+ friend std::ostream& operator<<(std::ostream&, const UnsatCore&);
+
+ /** The SmtEngine we're associated with */
+ SmtEngine* d_smt;
+
+ std::vector<Expr> d_core;
+
+public:
+ UnsatCore() : d_smt(NULL) {}
+
+ template <class T>
+ UnsatCore(SmtEngine* smt, T begin, T end) : d_smt(smt), d_core(begin, end) {}
+
+ ~UnsatCore() {}
+
+ /** get the smt engine that this unsat core is hooked up to */
+ SmtEngine* getSmtEngine() { return d_smt; }
+
+ typedef std::vector<Expr>::const_iterator iterator;
+ typedef std::vector<Expr>::const_iterator const_iterator;
+
+ const_iterator begin() const;
+ const_iterator end() const;
+
+ void toStream(std::ostream& out) const;
+ void toStream(std::ostream& out, const std::map<Expr, std::string>& names) const;
+
+};/* class UnsatCore */
+
+}/* CVC4 namespace */
+
+#endif /* __CVC4__UNSAT_CORE_H */
diff --git a/src/util/unsat_core.i b/src/util/unsat_core.i
new file mode 100644
index 000000000..9fc0dcda6
--- /dev/null
+++ b/src/util/unsat_core.i
@@ -0,0 +1,51 @@
+%{
+#include "util/unsat_core.h"
+%}
+
+#ifdef SWIGJAVA
+
+// Instead of UnsatCore::begin() and end(), create an
+// iterator() method on the Java side that returns a Java-style
+// Iterator.
+%ignore CVC4::UnsatCore::begin();
+%ignore CVC4::UnsatCore::end();
+%ignore CVC4::UnsatCore::begin() const;
+%ignore CVC4::UnsatCore::end() const;
+%extend CVC4::UnsatCore {
+ CVC4::JavaIteratorAdapter<CVC4::UnsatCore> iterator() {
+ return CVC4::JavaIteratorAdapter<CVC4::UnsatCore>(*$self);
+ }
+}
+
+// UnsatCore is "iterable" on the Java side
+%typemap(javainterfaces) CVC4::UnsatCore "java.lang.Iterable<edu.nyu.acsys.CVC4.Expr>";
+
+// the JavaIteratorAdapter should not be public, and implements Iterator
+%typemap(javaclassmodifiers) CVC4::JavaIteratorAdapter<CVC4::UnsatCore> "class";
+%typemap(javainterfaces) CVC4::JavaIteratorAdapter<CVC4::UnsatCore> "java.util.Iterator<edu.nyu.acsys.CVC4.Expr>";
+// add some functions to the Java side (do it here because there's no way to do these in C++)
+%typemap(javacode) CVC4::JavaIteratorAdapter<CVC4::UnsatCore> "
+ public void remove() {
+ throw new java.lang.UnsupportedOperationException();
+ }
+
+ public edu.nyu.acsys.CVC4.Expr next() {
+ if(hasNext()) {
+ return getNext();
+ } else {
+ throw new java.util.NoSuchElementException();
+ }
+ }
+"
+// getNext() just allows C++ iterator access from Java-side next(), make it private
+%javamethodmodifiers CVC4::JavaIteratorAdapter<CVC4::UnsatCore>::getNext() "private";
+
+// map the types appropriately
+%typemap(jni) CVC4::UnsatCore::const_iterator::value_type "jobject";
+%typemap(jtype) CVC4::UnsatCore::const_iterator::value_type "edu.nyu.acsys.CVC4.Expr";
+%typemap(jstype) CVC4::UnsatCore::const_iterator::value_type "edu.nyu.acsys.CVC4.Expr";
+%typemap(javaout) CVC4::UnsatCore::const_iterator::value_type { return $jnicall; }
+
+#endif /* SWIGJAVA */
+
+%include "util/unsat_core.h"
diff --git a/test/regress/regress0/Makefile.am b/test/regress/regress0/Makefile.am
index 15888fbce..ab58b3b6f 100644
--- a/test/regress/regress0/Makefile.am
+++ b/test/regress/regress0/Makefile.am
@@ -105,10 +105,9 @@ CVC_TESTS = \
wiki.19.cvc \
wiki.20.cvc \
wiki.21.cvc \
- simplification_bug3.cvc \
queries0.cvc \
- print_lambda.cvc \
- trim.cvc
+ trim.cvc \
+ print_lambda.cvc
# Regression tests for TPTP inputs
TPTP_TESTS =
@@ -167,6 +166,7 @@ BUG_TESTS = \
bug578.smt2 \
bug585.cvc \
bug586.cvc \
+ bug590.smt2 \
bug595.cvc
TESTS = $(SMT_TESTS) $(SMT2_TESTS) $(CVC_TESTS) $(TPTP_TESTS) $(BUG_TESTS)
@@ -178,7 +178,8 @@ DISABLED_TESTS = \
EXTRA_DIST = $(TESTS) \
simplification_bug4.smt2.expect \
- bug216.smt2.expect
+ bug216.smt2.expect \
+ bug590.smt2.expect
if CVC4_BUILD_PROFILE_COMPETITION
else
diff --git a/test/regress/regress0/arrays/Makefile.am b/test/regress/regress0/arrays/Makefile.am
index c11d68780..a1232196e 100644
--- a/test/regress/regress0/arrays/Makefile.am
+++ b/test/regress/regress0/arrays/Makefile.am
@@ -40,11 +40,16 @@ TESTS = \
swap_t1_np_nf_ai_00005_007.cvc.smt \
x2.smt \
x3.smt \
- parsing_ringer.cvc
-
-EXTRA_DIST = $(TESTS) \
bug272.smt \
- bug272.minimized.smt
+ bug272.minimized.smt \
+ constarr.smt2 \
+ constarr2.smt2 \
+ constarr3.smt2 \
+ constarr.cvc \
+ constarr2.cvc \
+ constarr3.cvc
+
+EXTRA_DIST = $(TESTS)
#if CVC4_BUILD_PROFILE_COMPETITION
#else
@@ -55,6 +60,8 @@ EXTRA_DIST = $(TESTS) \
# and make sure to distribute it
#EXTRA_DIST += \
# error.cvc
+# disabled for now (problem is related to records in model):
+# parsing_ringer.cvc
# synonyms for "check"
.PHONY: regress regress0 test
diff --git a/test/regress/regress0/arrays/constarr.cvc b/test/regress/regress0/arrays/constarr.cvc
new file mode 100644
index 000000000..406a1ce2b
--- /dev/null
+++ b/test/regress/regress0/arrays/constarr.cvc
@@ -0,0 +1,7 @@
+% EXPECT: unsat
+all1 : ARRAY INT OF INT;
+a, i : INT;
+ASSERT all1 = ARRAY(INT OF INT) : 1;
+ASSERT a = all1[i];
+ASSERT a /= 1;
+CHECKSAT TRUE;
diff --git a/test/regress/regress0/arrays/constarr.smt2 b/test/regress/regress0/arrays/constarr.smt2
new file mode 100644
index 000000000..b1fb02bed
--- /dev/null
+++ b/test/regress/regress0/arrays/constarr.smt2
@@ -0,0 +1,9 @@
+(set-logic QF_ALIA)
+(set-info :status unsat)
+(declare-const all1 (Array Int Int))
+(declare-const a Int)
+(declare-const i Int)
+(assert (= all1 ((as const (Array Int Int)) 1)))
+(assert (= a (select all1 i)))
+(assert (not (= a 1)))
+(check-sat)
diff --git a/test/regress/regress0/arrays/constarr2.cvc b/test/regress/regress0/arrays/constarr2.cvc
new file mode 100644
index 000000000..90ff11430
--- /dev/null
+++ b/test/regress/regress0/arrays/constarr2.cvc
@@ -0,0 +1,7 @@
+% EXPECT: unsat
+all1, all2 : ARRAY INT OF INT;
+a, i : INT;
+ASSERT all1 = ARRAY(INT OF INT) : 1;
+ASSERT all2 = ARRAY(INT OF INT) : 2;
+ASSERT all1 = all2;
+CHECKSAT;
diff --git a/test/regress/regress0/arrays/constarr2.smt2 b/test/regress/regress0/arrays/constarr2.smt2
new file mode 100644
index 000000000..c84e6781a
--- /dev/null
+++ b/test/regress/regress0/arrays/constarr2.smt2
@@ -0,0 +1,10 @@
+(set-logic QF_ALIA)
+(set-info :status unsat)
+(declare-const all1 (Array Int Int))
+(declare-const all2 (Array Int Int))
+(declare-const a Int)
+(declare-const i Int)
+(assert (= all1 ((as const (Array Int Int)) 1)))
+(assert (= all2 ((as const (Array Int Int)) 2)))
+(assert (= all1 all2))
+(check-sat)
diff --git a/test/regress/regress0/arrays/constarr3.cvc b/test/regress/regress0/arrays/constarr3.cvc
new file mode 100644
index 000000000..bf5cf961c
--- /dev/null
+++ b/test/regress/regress0/arrays/constarr3.cvc
@@ -0,0 +1,12 @@
+% EXIT: 1
+% EXPECT: Array theory solver does not yet support write-chains connecting two different constant arrays
+% should be unsat
+all1, all2 : ARRAY INT OF INT;
+aa, bb : ARRAY INT OF INT;
+a, i : INT;
+ASSERT all1 = ARRAY(INT OF INT) : 1;
+ASSERT aa = all1 WITH [i] := 0;
+ASSERT all2 = ARRAY(INT OF INT) : 2;
+ASSERT bb = all2 WITH [i] := 0;
+ASSERT aa = bb;
+CHECKSAT;
diff --git a/test/regress/regress0/arrays/constarr3.smt2 b/test/regress/regress0/arrays/constarr3.smt2
new file mode 100644
index 000000000..d514fff70
--- /dev/null
+++ b/test/regress/regress0/arrays/constarr3.smt2
@@ -0,0 +1,16 @@
+; EXIT: 1
+; EXPECT: (error "Array theory solver does not yet support write-chains connecting two different constant arrays")
+(set-logic QF_ALIA)
+(set-info :status unsat)
+(declare-const all1 (Array Int Int))
+(declare-const all2 (Array Int Int))
+(declare-const aa (Array Int Int))
+(declare-const bb (Array Int Int))
+(declare-const a Int)
+(declare-const i Int)
+(assert (= all1 ((as const (Array Int Int)) 1)))
+(assert (= aa (store all1 i 0)))
+(assert (= all2 ((as const (Array Int Int)) 2)))
+(assert (= bb (store all2 i 0)))
+(assert (= aa bb))
+(check-sat)
diff --git a/test/regress/regress0/arrays/parsing_ringer.cvc b/test/regress/regress0/arrays/parsing_ringer.cvc
index c9f8c9e22..2c2018ecd 100644
--- a/test/regress/regress0/arrays/parsing_ringer.cvc
+++ b/test/regress/regress0/arrays/parsing_ringer.cvc
@@ -9,6 +9,11 @@
% EXPECT: sat
% EXPECT: sat
% EXPECT: sat
+% EXPECT: sat
+% EXPECT: sat
+% EXPECT: unsat
+% EXPECT: unsat
+% EXPECT: sat
PUSH;
@@ -57,3 +62,33 @@ b : ARRAY INT OF INT;
ASSERT a = a WITH [0]:=b WITH [1]:=1,[2]:=2;
CHECKSAT;
+
+RESET;
+
+% more mixed stores, this time with constant arrays
+z : [# x:ARRAY INT OF [# x:INT #], y:[ARRAY INT OF INT, ARRAY INT OF INT] #];
+
+ASSERT z.y.1[1] /= 1;
+ASSERT (# x:=ARRAY(INT OF [# x:INT #]):(# x:=0 #), y:=(ARRAY(INT OF INT):1, ARRAY(INT OF INT):5) #) = z;
+
+CHECKSAT;
+
+ASSERT z.x[0].x /= z.y.0[5];
+
+CHECKSAT;
+
+ASSERT z.y.0[1] = z.x[5].x;
+
+CHECKSAT;
+
+ASSERT z.y.0[5] = z.x[-2].x;
+
+CHECKSAT;
+
+RESET;
+
+a : ARRAY INT OF INT;
+
+ASSERT a = a WITH [0]:=0, [1]:=1;
+
+CHECKSAT;
diff --git a/test/regress/regress0/bug421.smt2 b/test/regress/regress0/bug421.smt2
index 5a5886940..fd7b4a7cc 100644
--- a/test/regress/regress0/bug421.smt2
+++ b/test/regress/regress0/bug421.smt2
@@ -1,6 +1,6 @@
; COMMAND-LINE: --incremental --abstract-values
; EXPECT: sat
-; EXPECT: ((a @1) (b @2))
+; EXPECT: ((a (as @1 (Array Int Int))) (b (as @2 (Array Int Int))))
(set-logic QF_AUFLIA)
(set-option :produce-models true)
(declare-fun a () (Array Int Int))
diff --git a/test/regress/regress0/bug421b.smt2 b/test/regress/regress0/bug421b.smt2
index 82f566a64..aed7f7c05 100644
--- a/test/regress/regress0/bug421b.smt2
+++ b/test/regress/regress0/bug421b.smt2
@@ -4,7 +4,7 @@
;
; COMMAND-LINE: --incremental --abstract-values --check-models
; EXPECT: sat
-; EXPECT: ((a @1) (b @2))
+; EXPECT: ((a (as @1 (Array Int Int))) (b (as @2 (Array Int Int))))
(set-logic QF_AUFLIA)
(set-option :produce-models true)
(declare-fun a () (Array Int Int))
diff --git a/test/regress/regress0/bug567.smt2 b/test/regress/regress0/bug567.smt2
index 109940090..37403d8a3 100644
--- a/test/regress/regress0/bug567.smt2
+++ b/test/regress/regress0/bug567.smt2
@@ -1,7 +1,7 @@
(set-logic ALL_SUPPORTED)
; COMMAND-LINE: --incremental
; EXPECT: unknown
-; EXPECT: unknown
+; EXPECT: unsat
; EXPECT: unknown
(declare-datatypes () ((OptInt0 (Some (value0 Int)) (None))))
(declare-datatypes () ((List0 (Cons (head0 Int) (tail0 List0)) (Nil))))
diff --git a/test/regress/regress0/bug590.smt2 b/test/regress/regress0/bug590.smt2
new file mode 100644
index 000000000..68665f629
--- /dev/null
+++ b/test/regress/regress0/bug590.smt2
@@ -0,0 +1,61 @@
+(set-logic QF_ALL_SUPPORTED)
+(set-option :strings-exp true)
+(set-option :produce-models true)
+(set-info :smt-lib-version 2.0)
+(set-info :status unknown)
+
+(declare-fun text () String)
+(declare-fun output () String)
+
+; html_escape_table = {
+; "&": "&amp;",
+; '"': "&quot;",
+; "'": "&apos;",
+; ">": "&gt;",
+; "<": "&lt;",
+; }
+(declare-fun html_escape_table () (Array String String))
+(assert (= html_escape_table
+ (store (store (store (store (store ((as const (Array String String)) "A")
+ "&" "&amp;")
+ "\"" "&quot;")
+ "'" "&apos;")
+ ">" "&gt;")
+ "<" "&lt;")))
+(declare-fun html_escape_table_keys () (Array Int String))
+(assert (= html_escape_table_keys
+ (store (store (store (store (store ((as const (Array Int String)) "B")
+ 0 "&")
+ 1 "\"")
+ 2 "'")
+ 3 ">")
+ 4 "<")))
+
+; charlst = [c for c in text]
+(declare-fun charlst () (Array Int String))
+(declare-fun charlstlen () Int)
+(assert (= charlstlen (str.len text)))
+(assert (forall ((i Int))
+ (= (select charlst i) (str.at text i))
+))
+
+; charlst2 = [html_escape_table.get(c, c) for c in charlst]
+(declare-fun charlst2 () (Array Int String))
+(declare-fun charlstlen2 () Int)
+(assert (= charlstlen2 charlstlen))
+(assert (forall ((i Int))
+ (or (or (< i 0) (>= i charlstlen2))
+ (and (exists ((j Int))
+ (= (select html_escape_table_keys j) (select charlst i))
+ )
+ (= (select charlst2 i) (select html_escape_table (select charlst i)))
+ )
+ (and (not (exists ((j Int))
+ (= (select html_escape_table_keys j) (select charlst i))
+ ))
+ (= (select charlst2 i) (select charlst i))
+ )
+ )
+))
+(check-sat)
+(get-value (charlst2))
diff --git a/test/regress/regress0/bug590.smt2.expect b/test/regress/regress0/bug590.smt2.expect
new file mode 100644
index 000000000..3d57288cf
--- /dev/null
+++ b/test/regress/regress0/bug590.smt2.expect
@@ -0,0 +1,2 @@
+% EXPECT: unknown
+% EXPECT: ((charlst2 (store ((as const (Array Int String)) "C") 0 "&lt;")))
diff --git a/test/regress/regress0/crash_burn_locusts.smt2 b/test/regress/regress0/crash_burn_locusts.smt2
new file mode 100644
index 000000000..313d6f79c
--- /dev/null
+++ b/test/regress/regress0/crash_burn_locusts.smt2
@@ -0,0 +1,29 @@
+;; This is a nasty parsing test for define-fun-rec
+
+(set-logic UFLIRA)
+(set-info :smt-lib-version 2.5)
+(define-fun-rec (
+ (f ((x Int)) Int 5) ;; ok, f : Int -> Int
+ (g ((x Int)) Int (h 4)) ;; um, ok, so g : Int -> Int and h : Int -> Int?
+ (h ((x Real)) Int 4) ;; oops no we were wrong, **CRASH**
+))
+
+(reset)
+
+(set-logic UFLIRA)
+(set-info :smt-lib-version 2.5)
+(define-fun-rec (
+ (f ((x Int)) Int (g (h 4) 5)) ;; ok, f : Int -> Int and g : Int -> X -> Int and h : Int -> X ??! What the F?! (pun intended)
+ (g ((x Int)) Int 5) ;; wait, now g has wrong arity?!! **BURN**
+ (h ((x Int)) Int 2)
+))
+
+(reset)
+
+(set-logic UFLIRA)
+(set-info :smt-lib-version 2.5)
+(declare-const g Int 2)
+(define-fun-rec (
+ (f () Int g) ;; wait, which g does this refer to?! **LOCUSTS**
+ (g () Int 5)
+))
diff --git a/test/regress/regress0/datatypes/Makefile.am b/test/regress/regress0/datatypes/Makefile.am
index c02a70819..05eb710df 100644
--- a/test/regress/regress0/datatypes/Makefile.am
+++ b/test/regress/regress0/datatypes/Makefile.am
@@ -59,7 +59,8 @@ TESTS = \
bug286.cvc \
bug438.cvc \
bug438b.cvc \
- wrong-sel-simp.cvc
+ wrong-sel-simp.cvc \
+ tenum-bug.smt2
FAILING_TESTS = \
datatype-dump.cvc
diff --git a/test/regress/regress0/datatypes/tenum-bug.smt2 b/test/regress/regress0/datatypes/tenum-bug.smt2
new file mode 100644
index 000000000..bf82c7b8c
--- /dev/null
+++ b/test/regress/regress0/datatypes/tenum-bug.smt2
@@ -0,0 +1,11 @@
+(set-logic QF_ALL_SUPPORTED)
+(set-info :status sat)
+
+(declare-datatypes () ((DNat (dnat (data Nat)))
+ (Nat (succ (pred DNat)) (zero))))
+
+(declare-fun x () Nat)
+
+(assert (not (= x zero)))
+
+(check-sat) \ No newline at end of file
diff --git a/test/regress/regress0/fmf/Makefile.am b/test/regress/regress0/fmf/Makefile.am
index e3bfd39b8..ca3907b0b 100644
--- a/test/regress/regress0/fmf/Makefile.am
+++ b/test/regress/regress0/fmf/Makefile.am
@@ -34,12 +34,12 @@ TESTS = \
fc-unsat-tot-2.smt2 \
fc-unsat-pent.smt2 \
fc-pigeonhole19.smt2 \
- Hoare-z3.931718.smt
+ Hoare-z3.931718.smt \
+ bug0909.smt2 \
+ lst-no-self-rev-exp.smt2
EXTRA_DIST = $(TESTS)
-# disabled for now :
-# bug0909.smt2
#if CVC4_BUILD_PROFILE_COMPETITION
#else
diff --git a/test/regress/regress0/fmf/lst-no-self-rev-exp.smt2 b/test/regress/regress0/fmf/lst-no-self-rev-exp.smt2
new file mode 100644
index 000000000..5e1f3de30
--- /dev/null
+++ b/test/regress/regress0/fmf/lst-no-self-rev-exp.smt2
@@ -0,0 +1,35 @@
+; COMMAND-LINE: --finite-model-find --dt-rewrite-error-sel
+; EXPECT: sat
+(set-logic ALL_SUPPORTED)
+(declare-datatypes () ((Nat (succ (pred Nat)) (zero)) (Lst (cons (hd Nat) (tl Lst)) (nil))))
+
+(declare-fun app (Lst Lst) Lst)
+(declare-fun rev (Lst) Lst)
+
+(declare-sort I_app 0)
+(declare-sort I_rev 0)
+
+(declare-fun a () I_app)
+(declare-fun b () I_app)
+(assert (not (= a b)))
+
+(declare-fun app_0_3 (I_app) Lst)
+(declare-fun app_1_4 (I_app) Lst)
+(declare-fun rev_0_5 (I_rev) Lst)
+
+(declare-fun xs () Lst)
+
+(assert (and
+
+(forall ((?i I_app)) (= (app (app_0_3 ?i) (app_1_4 ?i)) (ite (is-cons (app_0_3 ?i)) (cons (hd (app_0_3 ?i)) (app (tl (app_0_3 ?i)) (app_1_4 ?i))) (app_1_4 ?i))) )
+
+(forall ((?i I_rev)) (= (rev (rev_0_5 ?i)) (ite (is-cons (rev_0_5 ?i)) (app (rev (tl (rev_0_5 ?i))) (cons (hd (rev_0_5 ?i)) nil)) nil)) )
+
+(forall ((?i I_rev)) (or (not (is-cons (rev_0_5 ?i))) (and (not (forall ((?z I_app)) (not (and (= (app_0_3 ?z) (rev (tl (rev_0_5 ?i)))) (= (app_1_4 ?z) (cons (hd (rev_0_5 ?i)) nil)))) )) (not (forall ((?z I_rev)) (not (= (rev_0_5 ?z) (tl (rev_0_5 ?i)) )) )))) )
+
+(not (or (= xs (rev xs)) (forall ((?z I_rev)) (not (= (rev_0_5 ?z) xs)) )))
+
+))
+
+(check-sat)
+
diff --git a/test/regress/regress0/parser/Makefile.am b/test/regress/regress0/parser/Makefile.am
index 389c80e09..eb27e797b 100644
--- a/test/regress/regress0/parser/Makefile.am
+++ b/test/regress/regress0/parser/Makefile.am
@@ -19,7 +19,9 @@ MAKEFLAGS = -k
# If a test shouldn't be run in e.g. competition mode,
# put it below in "TESTS +="
TESTS = \
- declarefun-emptyset-uf.smt2
+ declarefun-emptyset-uf.smt2 \
+ strings20.smt2 \
+ strings25.smt2
EXTRA_DIST = $(TESTS)
diff --git a/test/regress/regress0/parser/strings20.smt2 b/test/regress/regress0/parser/strings20.smt2
new file mode 100644
index 000000000..6e9ea4434
--- /dev/null
+++ b/test/regress/regress0/parser/strings20.smt2
@@ -0,0 +1,15 @@
+; EXPECT: sat
+; EXPECT: (model
+; EXPECT: (define-fun s () String "\"")
+; EXPECT: )
+
+(set-logic QF_S)
+(set-info :smt-lib-version 2.0)
+(set-option :produce-models true)
+
+(declare-fun s () String)
+
+(assert (= s "\""))
+
+(check-sat)
+(get-model)
diff --git a/test/regress/regress0/parser/strings25.smt2 b/test/regress/regress0/parser/strings25.smt2
new file mode 100644
index 000000000..90602e67d
--- /dev/null
+++ b/test/regress/regress0/parser/strings25.smt2
@@ -0,0 +1,15 @@
+; EXPECT: sat
+; EXPECT: (model
+; EXPECT: (define-fun s () String """")
+; EXPECT: )
+
+(set-logic QF_S)
+(set-info :smt-lib-version 2.5)
+(set-option :produce-models true)
+
+(declare-fun s () String)
+
+(assert (= s """"))
+
+(check-sat)
+(get-model)
diff --git a/test/regress/regress0/quantifiers/Makefile.am b/test/regress/regress0/quantifiers/Makefile.am
index 7e8e1ea99..41f66f92f 100644
--- a/test/regress/regress0/quantifiers/Makefile.am
+++ b/test/regress/regress0/quantifiers/Makefile.am
@@ -43,7 +43,8 @@ TESTS = \
javafe.ast.StmtVec.009.smt2 \
ARI176e1.smt2 \
bi-artm-s.smt2 \
- simp-typ-test.smt2
+ simp-typ-test.smt2 \
+ macros-int-real.smt2
# regression can be solved with --finite-model-find --fmf-inst-engine
# set3.smt2
diff --git a/test/regress/regress0/quantifiers/macros-int-real.smt2 b/test/regress/regress0/quantifiers/macros-int-real.smt2
new file mode 100644
index 000000000..d29ddfe8f
--- /dev/null
+++ b/test/regress/regress0/quantifiers/macros-int-real.smt2
@@ -0,0 +1,9 @@
+; COMMAND-LINE: --macros-quant
+; EXPECT: unknown
+(set-logic AUFLIRA)
+
+(declare-fun round2 (Real) Int)
+(assert (forall ((i Int)) (= (round2 (to_real i)) i)))
+
+(assert (= (round2 1.5) 1))
+(check-sat) \ No newline at end of file
diff --git a/test/regress/regress0/simplification_bug3.cvc b/test/regress/regress0/simplification_bug3.cvc
deleted file mode 100644
index 3f0ddc537..000000000
--- a/test/regress/regress0/simplification_bug3.cvc
+++ /dev/null
@@ -1,7 +0,0 @@
-% COMMAND-LINE: --simplification=incremental
-x, y: BOOLEAN;
-ASSERT x OR y;
-ASSERT NOT x;
-ASSERT NOT y;
-% EXPECT: unsat
-CHECKSAT;
diff --git a/test/regress/regress0/strings/Makefile.am b/test/regress/regress0/strings/Makefile.am
index ddc0eae7c..bd8e9ea93 100644
--- a/test/regress/regress0/strings/Makefile.am
+++ b/test/regress/regress0/strings/Makefile.am
@@ -23,6 +23,7 @@ TESTS = \
bug001.smt2 \
cardinality.smt2 \
escchar.smt2 \
+ escchar_25.smt2 \
str001.smt2 \
str002.smt2 \
str003.smt2 \
@@ -30,7 +31,6 @@ TESTS = \
str005.smt2 \
str006.smt2 \
str007.smt2 \
- fmf001.smt2 \
fmf002.smt2 \
type001.smt2 \
type003.smt2 \
@@ -53,6 +53,7 @@ TESTS = \
FAILING_TESTS =
EXTRA_DIST = $(TESTS) \
+ fmf001.smt2 \
regexp002.smt2 \
type002.smt2
diff --git a/test/regress/regress0/strings/escchar.smt2 b/test/regress/regress0/strings/escchar.smt2
index 508d7f3c1..aa2afb7e4 100644
--- a/test/regress/regress0/strings/escchar.smt2
+++ b/test/regress/regress0/strings/escchar.smt2
@@ -1,5 +1,6 @@
(set-logic QF_S)
(set-info :status sat)
+(set-info :smt-lib-version 2.0)
(declare-fun x () String)
(declare-const I Int)
diff --git a/test/regress/regress0/strings/escchar_25.smt2 b/test/regress/regress0/strings/escchar_25.smt2
new file mode 100644
index 000000000..f48995344
--- /dev/null
+++ b/test/regress/regress0/strings/escchar_25.smt2
@@ -0,0 +1,12 @@
+(set-logic QF_S)
+(set-info :status sat)
+(set-info :smt-lib-version 2.5)
+
+(declare-fun x () String)
+(declare-const I Int)
+
+(assert (= x "\0\1\2\3\04\005\x06\7\8\9ABC\\""\t\a\b"))
+(assert (= I (str.len x)))
+
+
+(check-sat)
diff --git a/test/regress/run_regression b/test/regress/run_regression
index f0ffd765d..d234153a3 100755
--- a/test/regress/run_regression
+++ b/test/regress/run_regression
@@ -41,6 +41,10 @@ while [ $# -gt 2 ]; do
shift
done
+[[ "$VALGRIND" = "1" ]] && {
+ wrapper="libtool --mode=execute valgrind $wrapper"
+}
+
cvc4=$1
benchmark_orig=$2
benchmark="$benchmark_orig"
@@ -250,7 +254,15 @@ fi
# we have to actual error file same treatment as other files. differences in
# versions of echo/bash were causing failure on some platforms and not on others
+# (also grep out valgrind output, if 0 errors reported by valgrind)
actual_error=$(cat $errfile)
+if [[ "$VALGRIND" = "1" ]]; then
+ #valgrind_output=$(cat $errfile|grep -E "^==[0-9]+== "|)
+ valgrind_num_errors=$(cat $errfile|grep -E "^==[0-9]+== "|tail -n1|awk '{print $4}')
+ echo "valgrind errors (not suppressed): $valgrind_num_errors" 1>&2
+
+ ((valgrind_num_errors == 0)) && actual_error=$(echo "$actual_error"|grep -vE "^==[0-9]+== ")
+fi
if [ -z "$actual_error" ]; then
# in case expected stderr output is empty, make sure we don't differ
# by a newline, which we would if we echo "" >"$experrfile"
diff --git a/test/unit/context/stacking_map_black.h b/test/unit/context/stacking_map_black.h
index 91e12a25e..4daab5cce 100644
--- a/test/unit/context/stacking_map_black.h
+++ b/test/unit/context/stacking_map_black.h
@@ -39,8 +39,8 @@ class StackingMapBlack : public CxxTest::TestSuite {
public:
void setUp() {
- d_ctxt = new Context;
- d_nm = new NodeManager(d_ctxt, NULL);
+ d_ctxt = new Context();
+ d_nm = new NodeManager(NULL);
d_scope = new NodeManagerScope(d_nm);
d_mapPtr = new StackingMap<TNode, TNode, TNodeHashFunction>(d_ctxt);
diff --git a/test/unit/context/stacking_vector_black.h b/test/unit/context/stacking_vector_black.h
index c7e185735..35305e469 100644
--- a/test/unit/context/stacking_vector_black.h
+++ b/test/unit/context/stacking_vector_black.h
@@ -39,8 +39,8 @@ class StackingVectorBlack : public CxxTest::TestSuite {
public:
void setUp() {
- d_ctxt = new Context;
- d_nm = new NodeManager(d_ctxt, NULL);
+ d_ctxt = new Context();
+ d_nm = new NodeManager(NULL);
d_scope = new NodeManagerScope(d_nm);
d_vectorPtr = new StackingVector<TNode>(d_ctxt);
diff --git a/test/unit/expr/attribute_black.h b/test/unit/expr/attribute_black.h
index 8fee6571d..5f9a7ebce 100644
--- a/test/unit/expr/attribute_black.h
+++ b/test/unit/expr/attribute_black.h
@@ -26,31 +26,35 @@
#include "expr/node_manager.h"
#include "expr/node.h"
#include "expr/attribute.h"
+#include "smt/smt_engine.h"
+#include "smt/smt_engine_scope.h"
using namespace CVC4;
using namespace CVC4::kind;
-using namespace CVC4::context;
+using namespace CVC4::smt;
using namespace std;
class AttributeBlack : public CxxTest::TestSuite {
private:
- Context* d_ctxt;
+ ExprManager* d_exprManager;
NodeManager* d_nodeManager;
- NodeManagerScope* d_scope;
+ SmtEngine* d_smtEngine;
+ SmtScope* d_scope;
public:
void setUp() {
- d_ctxt = new Context;
- d_nodeManager = new NodeManager(d_ctxt, NULL);
- d_scope = new NodeManagerScope(d_nodeManager);
+ d_exprManager = new ExprManager();
+ d_nodeManager = NodeManager::fromExprManager(d_exprManager);
+ d_smtEngine = new SmtEngine(d_exprManager);
+ d_scope = new SmtScope(d_smtEngine);
}
void tearDown() {
delete d_scope;
- delete d_nodeManager;
- delete d_ctxt;
+ delete d_smtEngine;
+ delete d_exprManager;
}
class MyData {
diff --git a/test/unit/expr/attribute_white.h b/test/unit/expr/attribute_white.h
index 11063cd1b..00ebc8b8d 100644
--- a/test/unit/expr/attribute_white.h
+++ b/test/unit/expr/attribute_white.h
@@ -18,7 +18,6 @@
#include <string>
-#include "context/context.h"
#include "expr/node_value.h"
#include "expr/node_builder.h"
#include "expr/node_manager.h"
@@ -29,10 +28,12 @@
#include "theory/theory_engine.h"
#include "theory/uf/theory_uf.h"
#include "util/cvc4_assert.h"
+#include "smt/smt_engine.h"
+#include "smt/smt_engine_scope.h"
using namespace CVC4;
using namespace CVC4::kind;
-using namespace CVC4::context;
+using namespace CVC4::smt;
using namespace CVC4::expr;
using namespace CVC4::expr::attr;
using namespace std;
@@ -60,26 +61,27 @@ typedef CDAttribute<Test2, bool> TestFlag2cd;
class AttributeWhite : public CxxTest::TestSuite {
- Context* d_ctxt;
+ ExprManager* d_em;
NodeManager* d_nm;
- NodeManagerScope* d_scope;
+ SmtScope* d_scope;
TypeNode* d_booleanType;
+ SmtEngine* d_smtEngine;
public:
void setUp() {
- d_ctxt = new Context;
- d_nm = new NodeManager(d_ctxt, NULL);
- d_scope = new NodeManagerScope(d_nm);
-
+ d_em = new ExprManager();
+ d_nm = NodeManager::fromExprManager(d_em);
+ d_smtEngine = new SmtEngine(d_em);
+ d_scope = new SmtScope(d_smtEngine);
d_booleanType = new TypeNode(d_nm->booleanType());
}
void tearDown() {
delete d_booleanType;
delete d_scope;
- delete d_nm;
- delete d_ctxt;
+ delete d_smtEngine;
+ delete d_em;
}
void testAttributeIds() {
@@ -145,7 +147,6 @@ public:
lastId = attr::LastAttributeId<TypeNode, false>::getId();
TS_ASSERT_LESS_THAN(TypeAttr::s_id, lastId);
-
}
void testCDAttributes() {
@@ -162,7 +163,7 @@ public:
Debug("cdboolattr") << "get flag 1 on c (should be F)\n";
TS_ASSERT(! c.getAttribute(TestFlag1cd()));
- d_ctxt->push(); // level 1
+ d_smtEngine->push(); // level 1
// test that all boolean flags are FALSE to start
Debug("cdboolattr") << "get flag 1 on a (should be F)\n";
@@ -204,7 +205,7 @@ public:
Debug("cdboolattr") << "get flag 1 on c (should be F)\n";
TS_ASSERT(! c.getAttribute(TestFlag1cd()));
- d_ctxt->push(); // level 2
+ d_smtEngine->push(); // level 2
Debug("cdboolattr") << "get flag 1 on a (should be T)\n";
TS_ASSERT(a.getAttribute(TestFlag1cd()));
@@ -225,7 +226,7 @@ public:
Debug("cdboolattr") << "get flag 1 on c (should be F)\n";
TS_ASSERT(! c.getAttribute(TestFlag1cd()));
- d_ctxt->push(); // level 3
+ d_smtEngine->push(); // level 3
Debug("cdboolattr") << "get flag 1 on a (should be F)\n";
TS_ASSERT(! a.getAttribute(TestFlag1cd()));
@@ -244,7 +245,7 @@ public:
Debug("cdboolattr") << "get flag 1 on c (should be T)\n";
TS_ASSERT(c.getAttribute(TestFlag1cd()));
- d_ctxt->pop(); // level 2
+ d_smtEngine->pop(); // level 2
Debug("cdboolattr") << "get flag 1 on a (should be F)\n";
TS_ASSERT(! a.getAttribute(TestFlag1cd()));
@@ -253,7 +254,7 @@ public:
Debug("cdboolattr") << "get flag 1 on c (should be F)\n";
TS_ASSERT(! c.getAttribute(TestFlag1cd()));
- d_ctxt->pop(); // level 1
+ d_smtEngine->pop(); // level 1
Debug("cdboolattr") << "get flag 1 on a (should be T)\n";
TS_ASSERT(a.getAttribute(TestFlag1cd()));
@@ -262,7 +263,7 @@ public:
Debug("cdboolattr") << "get flag 1 on c (should be F)\n";
TS_ASSERT(! c.getAttribute(TestFlag1cd()));
- d_ctxt->pop(); // level 0
+ d_smtEngine->pop(); // level 0
Debug("cdboolattr") << "get flag 1 on a (should be F)\n";
TS_ASSERT(! a.getAttribute(TestFlag1cd()));
@@ -271,13 +272,11 @@ public:
Debug("cdboolattr") << "get flag 1 on c (should be F)\n";
TS_ASSERT(! c.getAttribute(TestFlag1cd()));
-#ifdef CVC4_ASSERTIONS
- TS_ASSERT_THROWS( d_ctxt->pop(), AssertionException );
-#endif /* CVC4_ASSERTIONS */
+ TS_ASSERT_THROWS( d_smtEngine->pop(), ModalException );
}
void testAttributes() {
- //Debug.on("bootattr");
+ //Debug.on("boolattr");
Node a = d_nm->mkVar(*d_booleanType);
Node b = d_nm->mkVar(*d_booleanType);
diff --git a/test/unit/expr/node_black.h b/test/unit/expr/node_black.h
index 9f8ecb69e..7d6ee523a 100644
--- a/test/unit/expr/node_black.h
+++ b/test/unit/expr/node_black.h
@@ -28,14 +28,12 @@
using namespace CVC4;
using namespace CVC4::kind;
-using namespace CVC4::context;
using namespace std;
class NodeBlack : public CxxTest::TestSuite {
private:
Options opts;
- Context* d_ctxt;
NodeManager* d_nodeManager;
NodeManagerScope* d_scope;
TypeNode* d_booleanType;
@@ -51,8 +49,7 @@ public:
free(argv[0]);
free(argv[1]);
- d_ctxt = new Context();
- d_nodeManager = new NodeManager(d_ctxt, NULL, opts);
+ d_nodeManager = new NodeManager(NULL, opts);
d_scope = new NodeManagerScope(d_nodeManager);
d_booleanType = new TypeNode(d_nodeManager->booleanType());
d_realType = new TypeNode(d_nodeManager->realType());
@@ -62,7 +59,6 @@ public:
delete d_booleanType;
delete d_scope;
delete d_nodeManager;
- delete d_ctxt;
}
bool imp(bool a, bool b) const {
diff --git a/test/unit/expr/node_builder_black.h b/test/unit/expr/node_builder_black.h
index c71ba48c5..9bac0d818 100644
--- a/test/unit/expr/node_builder_black.h
+++ b/test/unit/expr/node_builder_black.h
@@ -25,19 +25,16 @@
#include "expr/node_manager.h"
#include "expr/node.h"
#include "expr/kind.h"
-#include "context/context.h"
#include "util/cvc4_assert.h"
#include "util/rational.h"
using namespace CVC4;
using namespace CVC4::kind;
-using namespace CVC4::context;
using namespace std;
class NodeBuilderBlack : public CxxTest::TestSuite {
private:
- Context* d_ctxt;
NodeManager* d_nm;
NodeManagerScope* d_scope;
TypeNode* d_booleanType;
@@ -47,8 +44,7 @@ private:
public:
void setUp() {
- d_ctxt = new Context;
- d_nm = new NodeManager(d_ctxt, NULL);
+ d_nm = new NodeManager(NULL);
d_scope = new NodeManagerScope(d_nm);
specKind = AND;
@@ -63,7 +59,6 @@ public:
delete d_realType;
delete d_scope;
delete d_nm;
- delete d_ctxt;
}
diff --git a/test/unit/expr/node_manager_black.h b/test/unit/expr/node_manager_black.h
index 9ca086d06..b94e6a691 100644
--- a/test/unit/expr/node_manager_black.h
+++ b/test/unit/expr/node_manager_black.h
@@ -21,7 +21,6 @@
#include "expr/node_manager.h"
#include "expr/node_manager_attributes.h"
-#include "context/context.h"
#include "util/rational.h"
#include "util/integer.h"
@@ -29,26 +28,22 @@
using namespace CVC4;
using namespace CVC4::expr;
using namespace CVC4::kind;
-using namespace CVC4::context;
class NodeManagerBlack : public CxxTest::TestSuite {
- Context* d_context;
NodeManager* d_nodeManager;
NodeManagerScope* d_scope;
public:
void setUp() {
- d_context = new Context;
- d_nodeManager = new NodeManager(d_context, NULL);
+ d_nodeManager = new NodeManager(NULL);
d_scope = new NodeManagerScope(d_nodeManager);
}
void tearDown() {
delete d_scope;
delete d_nodeManager;
- delete d_context;
}
void testMkNodeNot() {
diff --git a/test/unit/expr/node_manager_white.h b/test/unit/expr/node_manager_white.h
index 7bc279f47..aaa3256dd 100644
--- a/test/unit/expr/node_manager_white.h
+++ b/test/unit/expr/node_manager_white.h
@@ -19,33 +19,28 @@
#include <string>
#include "expr/node_manager.h"
-#include "context/context.h"
#include "util/rational.h"
#include "util/integer.h"
using namespace CVC4;
using namespace CVC4::expr;
-using namespace CVC4::context;
class NodeManagerWhite : public CxxTest::TestSuite {
- Context* d_ctxt;
NodeManager* d_nm;
NodeManagerScope* d_scope;
public:
void setUp() {
- d_ctxt = new Context();
- d_nm = new NodeManager(d_ctxt, NULL);
+ d_nm = new NodeManager(NULL);
d_scope = new NodeManagerScope(d_nm);
}
void tearDown() {
delete d_scope;
delete d_nm;
- delete d_ctxt;
}
void testMkConstRational() {
diff --git a/test/unit/expr/node_self_iterator_black.h b/test/unit/expr/node_self_iterator_black.h
index 9f90bd1b0..7240deed5 100644
--- a/test/unit/expr/node_self_iterator_black.h
+++ b/test/unit/expr/node_self_iterator_black.h
@@ -16,14 +16,12 @@
#include <cxxtest/TestSuite.h>
-#include "context/context.h"
#include "expr/node.h"
#include "expr/node_self_iterator.h"
#include "expr/node_builder.h"
#include "expr/convenience_node_builders.h"
using namespace CVC4;
-using namespace CVC4::context;
using namespace CVC4::kind;
using namespace CVC4::expr;
using namespace std;
@@ -31,7 +29,6 @@ using namespace std;
class NodeSelfIteratorBlack : public CxxTest::TestSuite {
private:
- Context* d_ctxt;
NodeManager* d_nodeManager;
NodeManagerScope* d_scope;
TypeNode* d_booleanType;
@@ -40,8 +37,7 @@ private:
public:
void setUp() {
- d_ctxt = new Context;
- d_nodeManager = new NodeManager(d_ctxt, NULL);
+ d_nodeManager = new NodeManager(NULL);
d_scope = new NodeManagerScope(d_nodeManager);
d_booleanType = new TypeNode(d_nodeManager->booleanType());
d_realType = new TypeNode(d_nodeManager->realType());
@@ -51,7 +47,6 @@ public:
delete d_booleanType;
delete d_scope;
delete d_nodeManager;
- delete d_ctxt;
}
void testSelfIteration() {
diff --git a/test/unit/expr/node_white.h b/test/unit/expr/node_white.h
index bcb3155e1..8a68db269 100644
--- a/test/unit/expr/node_white.h
+++ b/test/unit/expr/node_white.h
@@ -22,33 +22,28 @@
#include "expr/node_builder.h"
#include "expr/node_manager.h"
#include "expr/node.h"
-#include "context/context.h"
#include "util/cvc4_assert.h"
using namespace CVC4;
using namespace CVC4::kind;
-using namespace CVC4::context;
using namespace CVC4::expr;
using namespace std;
class NodeWhite : public CxxTest::TestSuite {
- Context* d_ctxt;
NodeManager* d_nm;
NodeManagerScope* d_scope;
public:
void setUp() {
- d_ctxt = new Context();
- d_nm = new NodeManager(d_ctxt, NULL);
+ d_nm = new NodeManager(NULL);
d_scope = new NodeManagerScope(d_nm);
}
void tearDown() {
delete d_scope;
delete d_nm;
- delete d_ctxt;
}
void testNull() {
diff --git a/test/unit/prop/cnf_stream_white.h b/test/unit/prop/cnf_stream_white.h
index 665126059..db49e2521 100644
--- a/test/unit/prop/cnf_stream_white.h
+++ b/test/unit/prop/cnf_stream_white.h
@@ -67,7 +67,7 @@ public:
return d_nextVar++;
}
- void addClause(SatClause& c, bool lemma) {
+ void addClause(SatClause& c, bool lemma, uint64_t) {
d_addClauseCalled = true;
}
@@ -93,6 +93,10 @@ public:
void renewVar(SatLiteral lit, int level = -1) {
}
+ bool spendResource() {
+ return false;
+ }
+
void interrupt() {
}
@@ -179,7 +183,7 @@ public:
Node a = d_nodeManager->mkVar(d_nodeManager->booleanType());
Node b = d_nodeManager->mkVar(d_nodeManager->booleanType());
Node c = d_nodeManager->mkVar(d_nodeManager->booleanType());
- d_cnfStream->convertAndAssert(d_nodeManager->mkNode(kind::AND, a, b, c), false, false);
+ d_cnfStream->convertAndAssert(d_nodeManager->mkNode(kind::AND, a, b, c), false, false, RULE_INVALID, Node::null());
TS_ASSERT( d_satSolver->addClauseCalled() );
}
@@ -196,19 +200,19 @@ public:
d_nodeManager->mkNode(kind::IFF,
d_nodeManager->mkNode(kind::OR, c, d),
d_nodeManager->mkNode(kind::NOT,
- d_nodeManager->mkNode(kind::XOR, e, f)))), false, false );
+ d_nodeManager->mkNode(kind::XOR, e, f)))), false, false, RULE_INVALID, Node::null());
TS_ASSERT( d_satSolver->addClauseCalled() );
}
void testTrue() {
NodeManagerScope nms(d_nodeManager);
- d_cnfStream->convertAndAssert( d_nodeManager->mkConst(true), false, false );
+ d_cnfStream->convertAndAssert( d_nodeManager->mkConst(true), false, false, RULE_INVALID, Node::null() );
TS_ASSERT( d_satSolver->addClauseCalled() );
}
void testFalse() {
NodeManagerScope nms(d_nodeManager);
- d_cnfStream->convertAndAssert( d_nodeManager->mkConst(false), false, false );
+ d_cnfStream->convertAndAssert( d_nodeManager->mkConst(false), false, false, RULE_INVALID, Node::null() );
TS_ASSERT( d_satSolver->addClauseCalled() );
}
@@ -216,7 +220,7 @@ public:
NodeManagerScope nms(d_nodeManager);
Node a = d_nodeManager->mkVar(d_nodeManager->booleanType());
Node b = d_nodeManager->mkVar(d_nodeManager->booleanType());
- d_cnfStream->convertAndAssert( d_nodeManager->mkNode(kind::IFF, a, b), false, false );
+ d_cnfStream->convertAndAssert( d_nodeManager->mkNode(kind::IFF, a, b), false, false, RULE_INVALID, Node::null() );
TS_ASSERT( d_satSolver->addClauseCalled() );
}
@@ -224,7 +228,7 @@ public:
NodeManagerScope nms(d_nodeManager);
Node a = d_nodeManager->mkVar(d_nodeManager->booleanType());
Node b = d_nodeManager->mkVar(d_nodeManager->booleanType());
- d_cnfStream->convertAndAssert( d_nodeManager->mkNode(kind::IMPLIES, a, b), false, false );
+ d_cnfStream->convertAndAssert( d_nodeManager->mkNode(kind::IMPLIES, a, b), false, false, RULE_INVALID, Node::null() );
TS_ASSERT( d_satSolver->addClauseCalled() );
}
@@ -241,14 +245,14 @@ public:
// d_nodeManager->mkVar(d_nodeManager->integerType())
// ),
// d_nodeManager->mkVar(d_nodeManager->integerType())
- // ), false, false);
+ // ), false, false, RULE_INVALID, Node::null());
//
//}
void testNot() {
NodeManagerScope nms(d_nodeManager);
Node a = d_nodeManager->mkVar(d_nodeManager->booleanType());
- d_cnfStream->convertAndAssert( d_nodeManager->mkNode(kind::NOT, a), false, false );
+ d_cnfStream->convertAndAssert( d_nodeManager->mkNode(kind::NOT, a), false, false, RULE_INVALID, Node::null() );
TS_ASSERT( d_satSolver->addClauseCalled() );
}
@@ -257,7 +261,7 @@ public:
Node a = d_nodeManager->mkVar(d_nodeManager->booleanType());
Node b = d_nodeManager->mkVar(d_nodeManager->booleanType());
Node c = d_nodeManager->mkVar(d_nodeManager->booleanType());
- d_cnfStream->convertAndAssert( d_nodeManager->mkNode(kind::OR, a, b, c), false, false );
+ d_cnfStream->convertAndAssert( d_nodeManager->mkNode(kind::OR, a, b, c), false, false, RULE_INVALID, Node::null() );
TS_ASSERT( d_satSolver->addClauseCalled() );
}
@@ -265,10 +269,10 @@ public:
NodeManagerScope nms(d_nodeManager);
Node a = d_nodeManager->mkVar(d_nodeManager->booleanType());
Node b = d_nodeManager->mkVar(d_nodeManager->booleanType());
- d_cnfStream->convertAndAssert(a, false, false);
+ d_cnfStream->convertAndAssert(a, false, false, RULE_INVALID, Node::null());
TS_ASSERT( d_satSolver->addClauseCalled() );
d_satSolver->reset();
- d_cnfStream->convertAndAssert(b, false, false);
+ d_cnfStream->convertAndAssert(b, false, false, RULE_INVALID, Node::null());
TS_ASSERT( d_satSolver->addClauseCalled() );
}
@@ -276,7 +280,7 @@ public:
NodeManagerScope nms(d_nodeManager);
Node a = d_nodeManager->mkVar(d_nodeManager->booleanType());
Node b = d_nodeManager->mkVar(d_nodeManager->booleanType());
- d_cnfStream->convertAndAssert( d_nodeManager->mkNode(kind::XOR, a, b), false, false );
+ d_cnfStream->convertAndAssert( d_nodeManager->mkNode(kind::XOR, a, b), false, false, RULE_INVALID, Node::null() );
TS_ASSERT( d_satSolver->addClauseCalled() );
}
diff --git a/test/unit/theory/type_enumerator_white.h b/test/unit/theory/type_enumerator_white.h
index 3dcb2db85..d9963f78c 100644
--- a/test/unit/theory/type_enumerator_white.h
+++ b/test/unit/theory/type_enumerator_white.h
@@ -218,41 +218,27 @@ std::cout<<"here\n";
Node cons = Node::fromExpr(DatatypeType(listColorsType.toType()).getDatatype().getConstructor("cons"));
Node nil = d_nm->mkNode(APPLY_CONSTRUCTOR, DatatypeType(listColorsType.toType()).getDatatype().getConstructor("nil"));
Node red = d_nm->mkNode(APPLY_CONSTRUCTOR, DatatypeType(colorsType.toType()).getDatatype().getConstructor("red"));
+ Node orange = d_nm->mkNode(APPLY_CONSTRUCTOR, DatatypeType(colorsType.toType()).getDatatype().getConstructor("orange"));
+ Node yellow = d_nm->mkNode(APPLY_CONSTRUCTOR, DatatypeType(colorsType.toType()).getDatatype().getConstructor("yellow"));
TS_ASSERT_EQUALS(*te, nil);
TS_ASSERT_EQUALS(*++te, d_nm->mkNode(APPLY_CONSTRUCTOR, cons, red, nil));
TS_ASSERT( ! te.isFinished() );
TS_ASSERT_EQUALS(*++te, d_nm->mkNode(APPLY_CONSTRUCTOR, cons, red,
d_nm->mkNode(APPLY_CONSTRUCTOR, cons, red, nil)));
TS_ASSERT( ! te.isFinished() );
- TS_ASSERT_EQUALS(*++te, d_nm->mkNode(APPLY_CONSTRUCTOR, cons, red,
- d_nm->mkNode(APPLY_CONSTRUCTOR, cons, red,
- d_nm->mkNode(APPLY_CONSTRUCTOR, cons, red, nil))));
+ TS_ASSERT_EQUALS(*++te, d_nm->mkNode(APPLY_CONSTRUCTOR, cons, orange, nil));
TS_ASSERT( ! te.isFinished() );
TS_ASSERT_EQUALS(*++te, d_nm->mkNode(APPLY_CONSTRUCTOR, cons, red,
d_nm->mkNode(APPLY_CONSTRUCTOR, cons, red,
- d_nm->mkNode(APPLY_CONSTRUCTOR, cons, red,
- d_nm->mkNode(APPLY_CONSTRUCTOR, cons, red, nil)))));
+ d_nm->mkNode(APPLY_CONSTRUCTOR, cons, red, nil))));
TS_ASSERT( ! te.isFinished() );
- TS_ASSERT_EQUALS(*++te, d_nm->mkNode(APPLY_CONSTRUCTOR, cons, red,
- d_nm->mkNode(APPLY_CONSTRUCTOR, cons, red,
- d_nm->mkNode(APPLY_CONSTRUCTOR, cons, red,
- d_nm->mkNode(APPLY_CONSTRUCTOR, cons, red,
- d_nm->mkNode(APPLY_CONSTRUCTOR, cons, red, nil))))));
+ TS_ASSERT_EQUALS(*++te, d_nm->mkNode(APPLY_CONSTRUCTOR, cons, orange,
+ d_nm->mkNode(APPLY_CONSTRUCTOR, cons, red, nil)));
TS_ASSERT( ! te.isFinished() );
- TS_ASSERT_EQUALS(*++te, d_nm->mkNode(APPLY_CONSTRUCTOR, cons, red,
- d_nm->mkNode(APPLY_CONSTRUCTOR, cons, red,
- d_nm->mkNode(APPLY_CONSTRUCTOR, cons, red,
- d_nm->mkNode(APPLY_CONSTRUCTOR, cons, red,
- d_nm->mkNode(APPLY_CONSTRUCTOR, cons, red,
- d_nm->mkNode(APPLY_CONSTRUCTOR, cons, red, nil)))))));
+ TS_ASSERT_EQUALS(*++te, d_nm->mkNode(APPLY_CONSTRUCTOR, cons, yellow, nil));
TS_ASSERT( ! te.isFinished() );
TS_ASSERT_EQUALS(*++te, d_nm->mkNode(APPLY_CONSTRUCTOR, cons, red,
- d_nm->mkNode(APPLY_CONSTRUCTOR, cons, red,
- d_nm->mkNode(APPLY_CONSTRUCTOR, cons, red,
- d_nm->mkNode(APPLY_CONSTRUCTOR, cons, red,
- d_nm->mkNode(APPLY_CONSTRUCTOR, cons, red,
- d_nm->mkNode(APPLY_CONSTRUCTOR, cons, red,
- d_nm->mkNode(APPLY_CONSTRUCTOR, cons, red, nil))))))));
+ d_nm->mkNode(APPLY_CONSTRUCTOR, cons, orange, nil)));
TS_ASSERT( ! te.isFinished() );
}
diff --git a/test/unit/util/boolean_simplification_black.h b/test/unit/util/boolean_simplification_black.h
index e2937ccb2..db02ce207 100644
--- a/test/unit/util/boolean_simplification_black.h
+++ b/test/unit/util/boolean_simplification_black.h
@@ -14,7 +14,6 @@
** Black box testing of CVC4::BooleanSimplification.
**/
-#include "context/context.h"
#include "util/language.h"
#include "expr/node.h"
#include "expr/kind.h"
@@ -26,12 +25,10 @@
#include <set>
using namespace CVC4;
-using namespace CVC4::context;
using namespace std;
class BooleanSimplificationBlack : public CxxTest::TestSuite {
- Context* d_context;
NodeManager* d_nm;
NodeManagerScope* d_scope;
@@ -70,8 +67,7 @@ class BooleanSimplificationBlack : public CxxTest::TestSuite {
public:
void setUp() {
- d_context = new Context();
- d_nm = new NodeManager(d_context, NULL);
+ d_nm = new NodeManager(NULL);
d_scope = new NodeManagerScope(d_nm);
a = d_nm->mkSkolem("a", d_nm->booleanType());
@@ -116,7 +112,6 @@ public:
delete d_scope;
delete d_nm;
- delete d_context;
}
void testNegate() {
generated by cgit on debian on lair
contact matthew@masot.net with questions or feedback