#
# 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
# 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))
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
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, ...).
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.
* In SMT-LIB model output, real-sorted but integer-valued constants are
now printed in accordance with the standard (e.g. "1.0").
# 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
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"
}/* Theory$camel::Theory$camel() */
void Theory$camel::check(Effort level) {
+ if (done() && !fullEffort(level)) {
+ return;
+ }
while(!done()) {
// Get all the assertions
** 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;
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";
.I SmtEngine::getOption()
use the following option keys.
+.ad l
+
.RS
.TP 10
.I "COMMON OPTIONS"
.PD
.RE
+.ad b
+
.SH VERSION
This manual page refers to
.B CVC4
.SH AVAILABLE INTERNAL OPTIONS
+.ad l
+
.RS
.TP 10
.I "COMMON OPTIONS"
.PD
.RE
+.ad b
+
.SH VERSION
This manual page refers to
.B CVC4
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;
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
--- /dev/null
+; a = b ^ a = 00000 ^ b = 11111 is UNSAT\r
+\r
+(check\r
+(% a var_bv\r
+(% b var_bv\r
+(% f1 (th_holds (= BitVec (a_var_bv a) (a_var_bv b)))\r
+(% f2 (th_holds (= BitVec (a_var_bv a) (a_bv (bvc b0 (bvc b0 (bvc b0 (bvc b0 (bvc b0 bvn))))))))\r
+(% f3 (th_holds (= BitVec (a_var_bv b) (a_bv (bvc b1 (bvc b1 (bvc b1 (bvc b1 (bvc b1 bvn))))))))\r
+(: (holds cln)\r
+\r
+(decl_bv_atom_var 5 a (\ ba1\r
+(decl_bv_atom_var 5 b (\ ba2\r
+(decl_bv_atom_const _ (bvc b0 (bvc b0 (bvc b0 (bvc b0 (bvc b0 bvn))))) (\ c (\ ba3\r
+(decl_bv_atom_const _ (bvc b1 (bvc b1 (bvc b1 (bvc b1 (bvc b1 bvn))))) (\ d (\ ba4\r
+\r
+(decl_atom (bblast a 4) (\ v1 (\ a1\r
+(decl_atom (bblast b 4) (\ v2 (\ a2\r
+\r
+; bitblasting terms\r
+(th_let_pf _ (bv_bbl_var _ _ _ ba1) (\ bt1\r
+(th_let_pf _ (bv_bbl_var _ _ _ ba2) (\ bt2\r
+(th_let_pf _ (bv_bbl_const _ _ _ _ ba3) (\ bt3\r
+(th_let_pf _ (bv_bbl_const _ _ _ _ ba4) (\ bt4\r
+\r
+; bitblasting formulas\r
+(th_let_pf _ (bv_bbl_eq _ _ _ _ _ bt1 bt2) (\ bf1\r
+(th_let_pf _ (bv_bbl_eq _ _ _ _ _ bt1 bt3) (\ bf2\r
+(th_let_pf _ (bv_bbl_eq _ _ _ _ _ bt2 bt4) (\ bf3\r
+\r
+; CNFication\r
+; a.4 V ~b.4\r
+(satlem _ _\r
+(asf _ _ _ a1 (\ l1\r
+(ast _ _ _ a2 (\ l2\r
+(clausify_false\r
+ (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\r
+))))) (\ C2\r
+\r
+; ~a.4\r
+(satlem _ _\r
+(ast _ _ _ a1 (\ l1\r
+(clausify_false\r
+ (impl_elim _ _ l1 (iff_elim_1 _ _ (and_elim_1 _ _ (impl_elim _ _ f2 bf2))))\r
+))) (\ C3\r
+\r
+; b.4 \r
+(satlem _ _\r
+(asf _ _ _ a2 (\ l2\r
+(clausify_false\r
+ (contra _ (impl_elim _ _ truth (iff_elim_2 _ _ (and_elim_1 _ _ (impl_elim _ _ f3 bf3)))) l2)\r
+))) (\ C6\r
+\r
+\r
+(satlem_simplify _ _ _ \r
+(R _ _ (R _ _ C6 C2 v2) C3 v1) (\ x x))\r
+\r
+)))))))))))))))))))))))))))))))))))))))))))
\ No newline at end of file
(! r2 (th_holds (not f))
(th_holds false)))))
+; truth
+(declare truth (th_holds true))
+
;; not not
(declare not_not_intro
--- /dev/null
+; "bitvec" is a term of type "sort"\r
+(declare BitVec sort)\r
+\r
+; bit type\r
+(declare bit type)\r
+(declare b0 bit)\r
+(declare b1 bit)\r
+\r
+; bit vector type\r
+(declare bv type)\r
+(declare bvn bv)\r
+(declare bvc (! b bit (! v bv bv)))\r
+; a bv constant term\r
+(declare a_bv (! v bv (term BitVec)))\r
+\r
+; calculate the length of a bitvector\r
+(program bv_len ((v bv)) mpz \r
+ (match v\r
+ (bvn 0)\r
+ ((bvc b v') (mp_add (bv_len v') 1))))\r
+\r
+; a bv variable\r
+(declare var_bv type)\r
+; a bv variable term\r
+(declare a_var_bv (! v var_bv (term BitVec)))\r
+\r
+\r
+; bit vector operators\r
+(define bvoper (! x (term BitVec) \r
+ (! y (term BitVec) \r
+ (term BitVec))))\r
+(declare bvand bvoper)\r
+(declare bvadd bvoper)\r
+;....\r
+\r
+; all bit-vector terms are mapped with "bv_atom" to:\r
+; - a simply-typed term of type "var_bv", which is necessary for bit-blasting\r
+; - a integer size\r
+(declare bv_atom (! x (term BitVec) (! y var_bv (! n mpz type))))\r
+\r
+(declare decl_bv_atom_var (! n mpz ; must be specified\r
+ (! x var_bv\r
+ (! p (! u (bv_atom (a_var_bv x) x n)\r
+ (holds cln))\r
+ (holds cln)))))\r
+\r
+(declare decl_bv_atom_const (! n mpz\r
+ (! v bv\r
+ (! s (^ (bv_len v) n)\r
+ (! p (! w var_bv\r
+ (! u (bv_atom (a_bv v) w n)\r
+ (holds cln)))\r
+ (holds cln))))))\r
+\r
+\r
+; other terms here?\r
+\r
+\r
+; bit blasted terms\r
+(declare bblt type)\r
+(declare bbltn bblt)\r
+(declare bbltc (! f formula (! v bblt bblt)))\r
+\r
+; (bblast_term x y) means term x corresponds to bit level interpretation y\r
+(declare bblast_term (! x (term BitVec) (! y bblt formula)))\r
+\r
+; a predicate to represent the n^th bit of a bitvector term\r
+(declare bblast (! x var_bv (! n mpz formula)))\r
+\r
+\r
+; bit blast constant\r
+(program bblast_const ((v bv) (n mpz)) bblt\r
+ (mp_ifneg n (match v (bvn bbltn) \r
+ (default (fail bblt)))\r
+ (match v ((bvc b v') (bbltc (match b (b0 false) (b1 true)) (bblast_const v' (mp_add n (~ 1)))))\r
+ (default (fail bblt)))))\r
+ \r
+(declare bv_bbl_const (! n mpz\r
+ (! v bv\r
+ (! x var_bv\r
+ (! f bblt\r
+ (! u (bv_atom (a_bv v) x n)\r
+ (! c (^ (bblast_const v (mp_add n (~ 1))) f)\r
+ (th_holds (bblast_term (a_bv v) f)))))))))\r
+\r
+; bit blast variable\r
+(program bblast_var ((x var_bv) (n mpz)) bblt\r
+ (mp_ifneg n bbltn \r
+ (bbltc (bblast x n) (bblast_var x (mp_add n (~ 1))))))\r
+\r
+(declare bv_bbl_var (! n mpz\r
+ (! x var_bv\r
+ (! f bblt \r
+ (! u (bv_atom (a_var_bv x) x n)\r
+ (! c (^ (bblast_var x (mp_add n (~ 1))) f)\r
+ (th_holds (bblast_term (a_var_bv x) f))))))))\r
+\r
+; bit blast x = y\r
+; for x,y of size n, it will return a conjuction (x.{n-1} = y.{n-1} ^ ( ... ^ (x.0 = y.0 ^ true)))\r
+(program bblast_eq ((x bblt) (y bblt)) formula\r
+ (match x \r
+ (bbltn (match y (bbltn true) (default (fail formula))))\r
+ ((bbltc fx x') (match y \r
+ (bbltn (fail formula))\r
+ ((bbltc fy y') (and (iff fx fy) (bblast_eq x' y')))))))\r
+\r
+(declare bv_bbl_eq (! x (term BitVec)\r
+ (! y (term BitVec)\r
+ (! fx bblt\r
+ (! fy bblt\r
+ (! f formula\r
+ (! ux (th_holds (bblast_term x fx))\r
+ (! uy (th_holds (bblast_term y fy))\r
+ (! c (^ (bblast_eq fx fy) f)\r
+ (th_holds (impl (= BitVec x y) f)))))))))))\r
+\r
+\r
+; rewrite rule :\r
+; x + y = y + x\r
+(declare bvadd_symm (! x (term BitVec)\r
+ (! y (term BitVec)\r
+ (! x' var_bv\r
+ (! y' var_bv\r
+ (! n mpz\r
+ (! ux (bv_atom x x' n)\r
+ (! uy (bv_atom y y' n)\r
+ (th_holds (= BitVec (bvadd x y) (bvadd y x)))))))))))\r
+\r
+\r
+\r
+; necessary? \r
+(program calc_bvand ((a bv) (b bv)) bv\r
+ (match a\r
+ (bvn (match b (bvn bvn) (default (fail bv))))\r
+ ((bvc ba a') (match b\r
+ ((bvc bb b') (bvc (match ba (b0 b0) (b1 bb)) (calc_bvand a' b')))\r
+ (default (fail bv))))))\r
+\r
+; rewrite rule (w constants) :\r
+; a & b = c \r
+(declare bvand_const (! c bv\r
+ (! a bv\r
+ (! b bv\r
+ (! u (^ (calc_bvand a b) c)\r
+ (th_holds (= BitVec (bvand (a_bv a) (a_bv b)) (a_bv c))))))))
\ No newline at end of file
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/options_handlers.h \
theory/arith/theory_arith_type_rules.h \
theory/arith/type_enumerator.h \
-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
-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
-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
-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
-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
-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
-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
-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
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
-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
-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 += \
}
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) {
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);
// 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,
{
// 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);
~DecisionEngine() {
Trace("decision") << "Destroying decision engine" << std::endl;
}
-
+
// void setPropEngine(PropEngine* pe) {
// // setPropEngine should not be called more than once
// Assert(d_propEngine == NULL);
"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);
/**
* 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);
// (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;
virtual ~DecisionStrategy() { }
virtual prop::SatLiteral getNext(bool&) = 0;
-
+
virtual bool needIteSkolemMap() { return false; }
-
+
virtual void notifyAssertionsAvailable() { return; }
};/* class DecisionStrategy */
if(Debug.isOn("decision")) {
if(!checkJustified(curass))
- Debug("decision") << "****** Not justified [i="<<i<<"]: "
+ Debug("decision") << "****** Not justified [i="<<i<<"]: "
<< d_assertions[i] << std::endl;
}
}
IteSkolemMap iteSkolemMap) {
Trace("decision")
- << "JustificationHeuristic::addAssertions()"
+ << "JustificationHeuristic::addAssertions()"
<< " size = " << assertions.size()
<< " assertionsEnd = " << assertionsEnd
<< std::endl;
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());
d_curDecision = undefSatLiteral;
if(findSplitterRec(node, desiredVal)) {
++d_helfulness;
- }
+ }
return d_curDecision;
}
* 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) {
/* 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) {
// "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 */
Assert(litVal == desiredVal);
setJustified(node);
return NO_SPLITTER;
- }
+ }
else {
Assert(d_decisionEngine->hasSatLiteral(node));
if(d_curThreshold != 0 && getWeightPolarized(node, desiredVal) >= d_curThreshold)
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();
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();
if(findSplitterRec(node[0], ifDesiredVal) == FOUND_SPLITTER)
return FOUND_SPLITTER;
-
+
Assert(d_curThreshold != 0, "No controlling input found (6)");
return DONT_KNOW;
} else {
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 */
/* 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() {
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());
}
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() {
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() {
}
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;
}
/* 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() {
}
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;
}
return "query";
}
-/* class QuitCommand */
+/* class ResetCommand */
-QuitCommand::QuitCommand() throw() {
+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 QuitCommand */
+
void QuitCommand::invoke(SmtEngine* smtEngine) throw() {
Dump("benchmark") << *this;
d_commandStatus = CommandSuccess::instance();
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) {
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() {
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;
}
#include "util/sexpr.h"
#include "util/datatype.h"
#include "util/proof.h"
+#include "util/unsat_core.h"
namespace CVC4 {
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();
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);
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();
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();
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();
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 QuitCommand : public Command {
public:
- QuitCommand() throw();
+ QuitCommand() throw() {}
~QuitCommand() throw() {}
void invoke(SmtEngine* smtEngine) throw();
Command* exportTo(ExprManager* exprManager, ExprManagerMapCollection& variableMap);
namespace expr {
-static Node exportConstant(TNode n, NodeManager* to);
+static Node exportConstant(TNode n, NodeManager* to, ExprManagerMapCollection& vmap);
class ExportPrivate {
private:
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];
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 */
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
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)) {
return d_context->getLevel();
}
+void SymbolTable::reset() {
+ this->SymbolTable::~SymbolTable();
+ new(this) SymbolTable();
+}
+
}/* CVC4 namespace */
/** Get the current level of this symbol table. */
size_t getLevel() const throw();
+ /** Reset everything. */
+ void reset();
+
};/* class SymbolTable */
}/* CVC4 namespace */
#include "main/options.h"
#include "smt/options.h"
+#include "printer/options.h"
#ifndef __WIN32__
# include <sys/resource.h>
#endif /* ! __WIN32__ */
}
-
void printStatsIncremental(std::ostream& out, const std::string& prvsStatsString, const std::string& curStatsString);
CommandExecutor::CommandExecutor(ExprManager &exprMgr, Options &options) :
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();
}
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);
**
** \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.
**/
#include "main/portfolio.h"
#include "options/options.h"
#include "smt/options.h"
+#include "printer/options.h"
#include "cvc4autoconfig.h"
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] &&
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);
}
}
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)) {
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
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
@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 += \
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';
{ UNSUPPORTED("POPTO_SCOPE command"); }
| RESET_TOK
- { UNSUPPORTED("RESET command"); }
+ { cmd = new ResetCommand();
+ PARSER_STATE->reset();
+ }
// Datatypes can be mututally-recursive if they're in the same
// definition block, separated by a comma. So we parse everything
| DUMP_PROOF_TOK
{ cmd = new GetProofCommand(); }
+ | DUMP_UNSAT_CORE_TOK
+ { cmd = new GetUnsatCoreCommand(); }
+
| ( DUMP_ASSUMPTIONS_TOK
| DUMP_SIG_TOK
| DUMP_TCC_TOK
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 ]
| EXP_TOK
;
-moreArrayStores[CVC4::Expr& f]
- : COMMA arrayStore[f]
- ;
-
/** Parses an array/tuple/record assignment term. */
term[CVC4::Expr& f]
@init {
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]
f = MK_EXPR(kind::RECORD, MK_CONST(t.getRecord()), std::vector<Expr>());
}
-
/* empty set literal */
| LBRACE RBRACE
{ f = MK_CONST(EmptySet(Type())); }
}
}
+ /* 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)); }
;
/**
- * 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]
}
}
+ inline void reset() {
+ d_symtab->reset();
+ }
+
/**
* Set the current symbol table used by this parser.
* From now on, this parser will perform its definitions and
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
{ 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]
{ 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
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);
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();
}
} )
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);
| { 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();
}
$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]
};
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
};
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]
}
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); }
/* 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 );
}
}
} 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;
}
}
PARSER_STATE->warning(ss.str());
}
// do nothing
- } else if(attr == ":axiom" || attr == ":conjecture") {
+ } else if(attr==":axiom" || attr==":conjecture" || attr==":sygus" || attr==":synthesis") {
if(hasValue) {
std::stringstream ss;
ss << "warning: Attribute " << attr << " does not take a value (ignoring)";
}
std::string attr_name = attr;
attr_name.erase( attr_name.begin() );
- Command* c = new SetUserAttributeCommand( attr_name, expr );
+ //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 {
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]
{
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);
PUSH_TOK : 'push';
POP_TOK : 'pop';
AS_TOK : 'as';
+CONST_TOK : 'const';
// extended commands
DECLARE_DATATYPES_TOK : 'declare-datatypes';
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 : '&';
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);
}
#include "theory/logic_info.h"
#include "util/abstract_value.h"
+#include <string>
#include <sstream>
+#include <utility>
+#include <stack>
namespace CVC4 {
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);
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;
tryToStream<PopCommand>(out, c) ||
tryToStream<CheckSatCommand>(out, c) ||
tryToStream<QueryCommand>(out, c) ||
+ tryToStream<ResetCommand>(out, c) ||
tryToStream<QuitCommand>(out, c) ||
tryToStream<DeclarationSequence>(out, c) ||
tryToStream<CommandSequence>(out, c) ||
out << "Query(" << c->getExpr() << ')';
}
+static void toStream(std::ostream& out, const ResetCommand* c) throw() {
+ out << "Reset()";
+}
+
static void toStream(std::ostream& out, const QuitCommand* c) throw() {
out << "Quit()";
}
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.
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<QuitCommand>(out, c, d_cvc3Mode) ||
tryToStream<DeclarationSequence>(out, c, d_cvc3Mode) ||
tryToStream<CommandSequence>(out, c, d_cvc3Mode) ||
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) ||
}
}
+static void toStream(std::ostream& out, const ResetCommand* c, bool cvc3Mode) throw() {
+ out << "RESET;";
+}
+
static void toStream(std::ostream& out, const QuitCommand* c, bool cvc3Mode) throw() {
//out << "EXIT;";
}
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() << ")";
}
}
}/* 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 */
#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"
/** 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 */
/**
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;
}
// 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
tryToStream<PopCommand>(out, c) ||
tryToStream<CheckSatCommand>(out, c) ||
tryToStream<QueryCommand>(out, c) ||
+ tryToStream<ResetCommand>(out, c) ||
tryToStream<QuitCommand>(out, c) ||
tryToStream<DeclarationSequence>(out, c) ||
tryToStream<CommandSequence>(out, c) ||
tryToStream<GetAssignmentCommand>(out, c) ||
tryToStream<GetAssertionsCommand>(out, c) ||
tryToStream<GetProofCommand>(out, c) ||
+ tryToStream<GetUnsatCoreCommand>(out, c) ||
tryToStream<SetBenchmarkStatusCommand>(out, c) ||
tryToStream<SetBenchmarkLogicCommand>(out, c, d_variant) ||
tryToStream<SetInfoCommand>(out, c) ||
}/* 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);
}
}
+static void toStream(std::ostream& out, const ResetCommand* c) throw() {
+ out << "(reset)";
+}
+
static void toStream(std::ostream& out, const QuitCommand* c) throw() {
out << "(exit)";
}
out << "(get-proof)";
}
+static void toStream(std::ostream& out, const GetUnsatCoreCommand* c) throw() {
+ out << "(get-unsat-core)";
+}
+
static void toStream(std::ostream& out, const SetBenchmarkStatusCommand* c) throw() {
out << "(set-info :status " << c->getStatus() << ")";
}
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;
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 */
: d_cnfStream(stream)
{}
+CnfProof::~CnfProof() {
+}
Expr CnfProof::getAtom(prop::SatVariable var) {
prop::SatLiteral lit (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 << ")))";
}
}
}
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 << "))";
}
}
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 << "))";
}
}
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 */
#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
#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 {
d_cnfProof(NULL),
d_theoryProof(NULL),
d_fullProof(NULL),
- d_format(format)
+ d_format(format),
+ d_deps()
{
}
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;
}
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);
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)
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;;";
out << "\n";
}
-
} /* CVC4 namespace */
#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 {
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;
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;
// 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);
// 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 {
Debug("proof:sat") << endl;
}
-
-int SatProof::d_idCounter = 0;
-
/**
* Converts the clause associated to id to a set of literals
*
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;
}
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));
}
void SatProof::printRes(ClauseId id) {
Assert(hasResolution(id));
- Debug("proof:sat") << "id "<< id <<": ";
+ Debug("proof:sat") << "id " << id << ": ";
printRes(d_resChains[id]);
}
/// 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)];
}
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;
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));
}
}
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();
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();
}
void SatProof::storeUnitResolution(::Minisat::Lit lit) {
+ Debug("cores") << "STORE UNIT RESOLUTION" << std::endl;
resolveUnit(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
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;
}
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) {
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")) {
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();
}
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();
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;
}
printResolution(d_emptyClauseId, out, paren);
}
-
} /* CVC4 namespace */
-
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;
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
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);
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
protected:
IdSet d_seenLearnt;
IdHashSet d_seenInput;
+ IdHashSet d_seenTheoryConflicts;
IdHashSet d_seenLemmas;
inline std::string varName(::Minisat::Lit lit);
** 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
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);
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();
}
** 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
void setNotify(Notify* notify);
- void addClause(SatClause& clause, bool removable);
+ void addClause(SatClause& clause, bool removable, uint64_t proof_id);
SatValue propagate();
void markUnremovable(SatLiteral lit);
+ bool spendResource();
+
void interrupt();
SatValue solve();
namespace CVC4 {
namespace prop {
-
CnfStream::CnfStream(SatSolver *satSolver, Registrar* registrar, context::Context* context, bool fullLitToNodeMap) :
d_satSolver(satSolver),
d_booleanVariables(context),
d_literalToNodeMap(context),
d_fullLitToNodeMap(fullLitToNodeMap),
d_registrar(registrar),
+ d_assertionTable(context),
d_removable(false) {
}
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) {
}
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)) {
// 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
// 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);
}
#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"
namespace CVC4 {
namespace prop {
-
class PropEngine;
/**
/** 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
return node;
}
+ /**
+ * 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;
* @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.
*/
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.
*/
* @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.
// 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)
// 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)); )
}
// 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);
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;
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) {
// 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;
}
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;
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); );
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) {
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
proxy->explainPropagation(MinisatSatSolver::toSatLiteral(p), explanation_cl);
vec<Lit> explanation;
MinisatSatSolver::toMinisatClause(explanation_cl, explanation);
- addClause(explanation, true);
+ addClause(explanation, true, 0);
}
}
}
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
// 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;
}
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 {
}
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)
} 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;
// Clear the lemmas
lemmas.clear();
lemmas_removable.clear();
+ lemmas_proof_id.clear();
if (conflict != CRef_Undef) {
theoryConflict = true;
#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 {
/** 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;
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:
void budgetOff();
void interrupt(); // Trigger a (potentially asynchronous) interruption of the solver.
void clearInterrupt(); // Clear interrupt indicator flag.
+ void spendResource();
// Memory managment:
//
// 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:
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:
//
// 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(); } }
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
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) {
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;
}
return toSatLiteralValue(d_minisat->solve());
}
+bool MinisatSatSolver::spendResource() {
+ d_minisat->spendResource();
+ return !d_minisat->withinBudget();
+}
void MinisatSatSolver::interrupt() {
d_minisat->interrupt();
d_minisat->push();
}
-void MinisatSatSolver::pop(){
+void MinisatSatSolver::pop() {
d_minisat->pop();
}
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(); }
SatValue solve();
SatValue solve(long unsigned int&);
+ bool spendResource();
void interrupt();
SatValue value(SatLiteral l);
-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) {
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){
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;
}
}
removeClause(cls[i]);
- if (!addClause_(subst_clause, c.removable())) {
+ if (!addClause_(subst_clause, c.removable(), uint64_t(-1))) {
return ok = false;
}
}
// 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:
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; }
#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"
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
);
d_decisionEngine->setSatSolver(d_satSolver);
d_decisionEngine->setCnfStream(d_cnfStream);
- PROOF (ProofManager::currentPM()->initCnfProof(d_cnfStream); );
+ PROOF (ProofManager::currentPM()->initCnfProof(d_cnfStream); );
}
PropEngine::~PropEngine() {
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) {
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();
}
#include "options/options.h"
#include "util/result.h"
#include "smt/modal_exception.h"
+#include "proof/proof_manager.h"
#include <sys/time.h>
namespace CVC4 {
* @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
#include "util/statistics_registry.h"
#include "context/cdlist.h"
#include "prop/sat_solver_types.h"
+#include "expr/node.h"
namespace CVC4 {
namespace prop {
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.
/** 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;
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;
}
goto next_worklist;
}
switch(k) {
+ case kind::INST_ATTRIBUTE:
case kind::BOUND_VAR_LIST:
result.top() << top;
worklist.pop();
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
(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\
";
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") {
#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) \
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;
/** 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 */
#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"
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;
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 */
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),
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);
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);
class SmtEnginePrivate : public NodeManagerListener {
SmtEngine& d_smt;
- /** The assertions yet to be preprocessed */
- vector<Node> d_assertionsToPreprocess;
-
/** Learned literals */
vector<Node> d_nonClausalLearnedLiterals;
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;
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;
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
* (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
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(),
* 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();
}
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();
}
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));
// 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
}
}
+ 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);
+ }
+ }
+
if(options::produceAssignments() && !options::produceModels()) {
Notice() << "SmtEngine: turning on produce-models to support produce-assignments" << endl;
setOption("produce-models", SExpr("true"));
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
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 );
+ }
+ }
//until bugs 371,431 are fixed
if( ! options::minisatUseElim.wasSetByUser()){
}
}
- 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)
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() {
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
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;
// 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(): "
// 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;
}
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;
}
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:
// 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);
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;
}
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
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
}
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];
}
d_nonClausalLearnedLiterals.clear();
-
for (pos = constantPropagations.begin(); pos != constantPropagations.end(); ++pos) {
Node cProp = (*pos).first.eqNode((*pos).second);
Assert(d_topLevelSubstitutions.apply(cProp) == cProp);
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;
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
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]));
}
}
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){
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;
}
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();
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);
}
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;
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();
}
// 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;
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) {
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() &&
}
}
- 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
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;
-
- Assert(d_assertionsToCheck.size() == 0);
+ Debug("smt") << " d_assertions : " << d_assertions.size() << endl;
- 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)) {
}
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 );
}
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 );
}
//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;
<< "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();
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 &&
}
}
// 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) {
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);
}
// 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();
}
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) {
}
}
-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();
// 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
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);
// 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) {
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;
}
d_private->addFormula(e.getNode());
return quickCheck().asValidityResult();
-}
+}/* SmtEngine::assertFormula() */
Node SmtEngine::postprocess(TNode node, TypeNode expectedType) const {
ModelPostprocessor mpost;
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);
}
#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);
}
}
+void SmtEngine::reset() throw() {
+ SmtScope smts(this);
+ ExprManager *em = d_exprManager;
+ Trace("smt") << "SMT reset()" << endl;
+ if(Dump.isOn("benchmark")) {
+ Dump("benchmark") << ResetCommand();
+ }
+ this->~SmtEngine();
+ new(this) SmtEngine(em);
+}
+
+void SmtEngine::resetAssertions() throw() {
+ SmtScope smts(this);
+
+ 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;
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) {
#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"
smt::SmtEnginePrivate* d_private;
/**
- * Check that a generated Proof (via getProof()) checks.
+ * Check that a generated proof (via getProof()) checks.
*/
void checkProof();
/**
* 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,
/**
* 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
*/
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.
*/
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
* 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
}
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 {
, 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)
}
+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
*/
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()) {
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);
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
*/
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;
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
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
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;
d_permRef(c),
d_modelConstraints(c),
d_lemmasSaved(c),
+ d_defValues(c),
d_inCheckModel(false)
{
StatisticsRegistry::registerStat(&d_numRow);
if (node.getType().isArray()) {
d_equalityEngine.addTriggerTerm(node, THEORY_ARRAY);
+ d_mayEqualEqualityEngine.addTerm(node);
}
else {
d_equalityEngine.addTerm(node);
break;
}
case kind::STORE: {
- // Invariant: array terms should be preregistered before being added to the equality engine
if (d_equalityEngine.hasTerm(node)) {
break;
}
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_equalityEngine.addTriggerTerm(node, THEORY_ARRAY);
+ d_mayEqualEqualityEngine.addTerm(node);
+ Assert(d_mayEqualEqualityEngine.getRepresentative(node) == node);
+ d_defValues[node] = defaultValue;
+ break;
}
default:
// Variables etc
if (node.getType().isArray()) {
d_equalityEngine.addTriggerTerm(node, THEORY_ARRAY);
Assert(d_equalityEngine.getSize(node) == 1);
+ // The may equal needs the node
+ d_mayEqualEqualityEngine.addTerm(node);
}
else {
d_equalityEngine.addTerm(node);
// 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;
}
// 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_AND_PROPAGATED:
+ // Should have been propagated to us
+ Assert(false);
+ case EQUALITY_FALSE:
case EQUALITY_FALSE_IN_MODEL:
- Debug("arrays::sharing") << "TheoryArrays::computeCareGraph(): false in model" << std::endl;
- break;
+ // Don't need to include this pair
+ if (options::arraysReduceSharing()) {
+ continue;
+ }
default:
break;
}
}
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];
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()) {
rep = *(defaultValuesSet.getSet(valueType)->begin());
}
Trace("arrays-models") << "New default value = " << rep << endl;
- defValues[mayRep] = rep;
+ d_defValues[mayRep] = rep;
}
else {
rep = (*it).second;
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) {
+ dischargeLemmas();
+ }
}
Trace("arrays") << spaces(getSatContext()->getLevel()) << "Arrays::check(): done" << endl;
}
}
+ 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);
+ if (!defValue.isNull()) {
+ mayRepA = d_mayEqualEqualityEngine.getRepresentative(a);
+ d_defValues[mayRepA] = defValue;
+ }
checkRowLemmas(a,b);
checkRowLemmas(b,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;
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) {
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);
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);
}
}
- // Get the current assignement
+ // Get the current assignment
AssignmentStatus state = d_state[n];
if(state != UNASSIGNED) {
}
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);
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 */
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 \
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
}
};/* 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) {
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);
}
}
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() {}
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();
};
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;
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);
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.
*
TNodeSet d_bbAtoms;
TNodeSet d_variables;
- Node getVarValue(TNode a, bool fullModel);
+ Node getModelFromSatSolver(TNode a, bool fullModel);
bool isSharedTerm(TNode node);
public:
bool hasInput(TNode input);
void convertToCnfAndAssert();
void assertToSatSolver(Cnf_Dat_t* pCnf);
-
+ Node getModelFromSatSolver(TNode a, bool fullModel) { Unreachable(); }
public:
AigBitblaster();
~AigBitblaster();
template <class T>
TBitblaster<T>::TBitblaster()
: d_termCache()
+ , d_modelCache()
{
initAtomBBStrategies();
initTermBBStrategies();
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 */
}
Node BVQuickCheck::getVarValue(TNode var) {
- return d_bitblaster->getVarValue(var);
+ return d_bitblaster->getTermModel(var, true);
}
// don't bit-blast lemma atoms
continue;
}
+ Debug("bitblast-queue") << "Bitblasting atom " << atom <<"\n";
d_bitblaster->bbAtom(atom);
}
}
Node BitblastSolver::getModelValue(TNode node)
{
- if (!d_validModelCache) {
- d_modelCache.clear();
- d_validModelCache = true;
- }
- 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";
+ Node val = d_bitblaster->getTermModel(node, false);
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;
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);
}
void EagerBitblaster::bbFormula(TNode node) {
- d_cnfStream->convertAndAssert(node, false, false);
+ d_cnfStream->convertAndAssert(node, false, false, RULE_INVALID, TNode::null());
}
/**
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) {
*
* @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);
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);
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);
, 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);
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;
}
// 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) {
}
}
Debug("bitvector") << "TLazyBitblaster::solve() asserted atoms " << d_assertedAtoms->size() <<"\n";
+ d_satSolverFullModel.set(true);
return prop::SAT_VALUE_TRUE == d_satSolver->solve();
}
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;
}
*
* @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);
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);
}
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);
- }
}
}
}
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,
d_staticLearnCache(),
d_lemmasAdded(c, false),
d_conflict(c, false),
+ d_invalidateModelCache(c, true),
d_literalsToPropagate(c),
d_literalsToPropagateIndex(c, 0),
d_propagatedBy(c),
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
// 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;
# 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%)" \
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 cdtBisimilar --cdt-bisimilar bool :default true
+ do bisimilarity check for co-datatypes
endmodule
d_equalityEngine.addFunctionKind(kind::APPLY_UF);
d_true = NodeManager::currentNM()->mkConst( true );
+ d_dtfCounter = 0;
}
TheoryDatatypes::~TheoryDatatypes() {
}
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
flushPendingFacts();
}
- if( e == EFFORT_FULL ) {
+ if( e == EFFORT_FULL && !d_conflict ) {
//check for cycles
bool addedFact;
do {
}
}
}
- /*
- 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 ){
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 );
}
}
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() );
}
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;
}
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);
}
}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();
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 );
}
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 );
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 ) ){
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] );
}
}
//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
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 );
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 */
}
};/* 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
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;
}
void TheoryIdl::check(Effort level) {
+ //// Not needed for now, as no code outside while() loop below.
+ // if (done() && !fullEffort(e)) {
+ // return;
+ // }
while(!done()) {
}
}
-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++) {
addedLemma = true;
}
}
- if( addedLemma ){
- d_quantEngine->flushLemmas( &d_quantEngine->getOutputChannel() );
- }
+ Trace("bint-engine") << " addedLemma = " << addedLemma << std::endl;
}
}
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();
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() {
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
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(){}
--- /dev/null
+/********************* */
+/*! \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() {
+}
+
+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
+ qe->getValuation().ensureLiteral( d_guard );
+ qe->getOutputChannel().requirePhase( d_guard, true );
+ }
+}
+
+CegInstantiation::CegInstantiation( QuantifiersEngine * qe, context::Context* c ) : QuantifiersModule( qe ), d_conj_active( c, false ), d_conj_infeasible( c, false ), d_guard_assertions( c ) {
+
+}
+
+bool CegInstantiation::needsCheck( Theory::Effort e ) {
+ return e>=Theory::EFFORT_LAST_CALL;
+}
+
+void CegInstantiation::check( Theory::Effort e, unsigned quant_e ) {
+ if( quant_e==QuantifiersEngine::QEFFORT_STANDARD ){
+ Trace("cegqi-engine") << "---Countexample Guided Instantiation Engine---" << std::endl;
+ Trace("cegqi-debug") << "Current conjecture status : " << d_conj_active << " " << d_conj_infeasible << std::endl;
+ if( d_conj_active && !d_conj_infeasible ){
+ checkCegConjecture( &d_conj );
+ }
+ Trace("cegqi-engine") << "Finished Countexample 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] );
+ }
+ }else if( getTermDatabase()->isQAttrSynthesis( q ) ){
+ //add immediate lemma
+ Node lem = NodeManager::currentNM()->mkNode( OR, d_conj.d_guard.negate(), d_conj.d_base_inst );
+ }
+ }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_infeasible = !pol;
+ }
+ if( lit==d_conj.d_quant ){
+ d_conj_active = true;
+ }
+}
+
+Node CegInstantiation::getNextDecisionRequest() {
+ d_conj.initializeGuard( d_quantEngine );
+ bool value;
+ if( !d_quantEngine->getValuation().hasSatValue( d_conj.d_guard, value ) ) {
+ if( d_guard_assertions.find( d_conj.d_guard )==d_guard_assertions.end() ){
+ 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") << "Decide next on : " << d_conj.d_guard << "..." << std::endl;
+ return d_conj.d_guard;
+ }
+ }
+ return Node::null();
+}
+
+void CegInstantiation::checkCegConjecture( CegConjecture * conj ) {
+ Node q = conj->d_quant;
+ Trace("cegqi-engine-debug") << "Synthesis conjecture : " << q << std::endl;
+ Trace("cegqi-engine-debug") << " * Candidate program/output : ";
+ for( unsigned i=0; i<conj->d_candidates.size(); i++ ){
+ Trace("cegqi-engine-debug") << conj->d_candidates[i] << " ";
+ }
+ Trace("cegqi-engine-debug") << std::endl;
+
+ if( getTermDatabase()->isQAttrSygus( q ) ){
+ Trace("cegqi-engine-debug") << " * Values are : ";
+ bool success = true;
+ std::vector< Node > model_values;
+ for( unsigned i=0; i<conj->d_candidates.size(); i++ ){
+ Node v = getModelValue( conj->d_candidates[i] );
+ model_values.push_back( v );
+ Trace("cegqi-engine-debug") << v << " ";
+ if( v.isNull() ){
+ success = false;
+ }
+ }
+ Trace("cegqi-engine-debug") << std::endl;
+
+ if( success ){
+ //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 ) );
+
+ //candidate refinement : the next candidate must satisfy the counterexample found for the current model of the candidate
+ Assert( conj->d_inner_vars.size()==getTermDatabase()->d_skolem_constants[inst[0]].size() );
+ Node inst_ce_refine = conj->d_base_inst[0][1].substitute( conj->d_inner_vars.begin(), conj->d_inner_vars.end(),
+ getTermDatabase()->d_skolem_constants[inst[0]].begin(), getTermDatabase()->d_skolem_constants[inst[0]].end() );
+ Node lem = NodeManager::currentNM()->mkNode( OR, conj->d_guard.negate(), inst_ce_refine.negate() );
+ Trace("cegqi-lemma") << "Candidate refinement lemma : " << lem << std::endl;
+ d_quantEngine->addLemma( lem );
+ }
+
+ }else if( getTermDatabase()->isQAttrSynthesis( q ) ){
+ 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 );
+ }
+ d_quantEngine->addInstantiation( q, model_terms, false );
+ }
+}
+
+Node CegInstantiation::getModelValue( Node n ) {
+ Trace("cegqi-mv") << "getModelValue for : " << n << std::endl;
+ //return d_quantEngine->getTheoryEngine()->getModelValue( n );
+ TypeNode tn = n.getType();
+ if( getEqualityEngine()->hasTerm( n ) ){
+ Node r = getRepresentative( n );
+ Node v;
+ eq::EqClassIterator eqc_i = eq::EqClassIterator( r, getEqualityEngine() );
+ while( !eqc_i.isFinished() ){
+ TNode nn = (*eqc_i);
+ if( nn.isConst() ){
+ Trace("cegqi-mv") << "..constant : " << nn << std::endl;
+ return nn;
+ }else if( nn.getKind()==APPLY_CONSTRUCTOR ){
+ v = nn;
+ }
+ ++eqc_i;
+ }
+ if( !v.isNull() ){
+ std::vector< Node > children;
+ if( v.hasOperator() ){
+ children.push_back( v.getOperator() );
+ }
+ for( unsigned i=0; i<v.getNumChildren(); i++ ){
+ children.push_back( getModelValue( v[i] ) );
+ }
+ Node vv = NodeManager::currentNM()->mkNode( v.getKind(), children );
+ Trace("cegqi-mv") << "...value : " << vv << std::endl;
+ return vv;
+ }
+ }
+ Node e = getTermDatabase()->getEnumerateTerm( tn, 0 );
+ Trace("cegqi-mv") << "...enumerate : " << e << std::endl;
+ return e;
+}
+
+Node CegInstantiation::getModelTerm( Node n ){
+ return getModelValue( n );
+}
+
+}
\ No newline at end of file
--- /dev/null
+/********************* */
+/*! \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();
+ /** quantified formula */
+ Node d_quant;
+ /** guard */
+ Node d_guard;
+ /** base instantiation */
+ Node d_base_inst;
+ /** guard split */
+ Node d_guard_split;
+ /** list of constants for quantified formula */
+ std::vector< Node > d_candidates;
+ /** list of variables on inner quantification */
+ std::vector< Node > d_inner_vars;
+ /** is assigned */
+ bool isAssigned() { return !d_quant.isNull(); }
+ /** assign */
+ void assign( Node q );
+ /** initialize guard */
+ void initializeGuard( QuantifiersEngine * qe );
+ };
+ /** the quantified formula stating the synthesis conjecture */
+ CegConjecture d_conj;
+ /** is conjecture active */
+ context::CDO< bool > d_conj_active;
+ /** is conjecture infeasible */
+ context::CDO< bool > d_conj_infeasible;
+ /** assertions for guards */
+ NodeBoolMap d_guard_assertions;
+private:
+ /** check conjecture */
+ void checkCegConjecture( CegConjecture * conj );
+ /** 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 );
+ /* 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
--- /dev/null
+/********************* */\r
+/*! \file conjecture_generator.cpp\r
+ ** \verbatim\r
+ ** Original author: Andrew Reynolds\r
+ ** Major contributors: none\r
+ ** Minor contributors (to current version): none\r
+ ** This file is part of the CVC4 project.\r
+ ** Copyright (c) 2009-2014 New York University and The University of Iowa\r
+ ** See the file COPYING in the top-level source directory for licensing\r
+ ** information.\endverbatim\r
+ **\r
+ ** \brief conjecture generator class\r
+ **\r
+ **/\r
+\r
+#include "theory/quantifiers/conjecture_generator.h"\r
+#include "theory/theory_engine.h"\r
+#include "theory/quantifiers/options.h"\r
+#include "theory/quantifiers/term_database.h"\r
+#include "theory/quantifiers/trigger.h"\r
+#include "theory/quantifiers/first_order_model.h"\r
+\r
+using namespace CVC4;\r
+using namespace CVC4::kind;\r
+using namespace CVC4::theory;\r
+using namespace CVC4::theory::quantifiers;\r
+using namespace std;\r
+\r
+namespace CVC4 {\r
+\r
+struct sortConjectureScore {\r
+ std::vector< int > d_scores;\r
+ bool operator() (unsigned i, unsigned j) { return d_scores[i]>d_scores[j]; }\r
+};\r
+\r
+\r
+void OpArgIndex::addTerm( ConjectureGenerator * s, TNode n, unsigned index ){\r
+ if( index==n.getNumChildren() ){\r
+ Assert( n.hasOperator() );\r
+ if( std::find( d_ops.begin(), d_ops.end(), n.getOperator() )==d_ops.end() ){\r
+ d_ops.push_back( n.getOperator() );\r
+ d_op_terms.push_back( n );\r
+ }\r
+ }else{\r
+ d_child[s->getTermDatabase()->d_arg_reps[n][index]].addTerm( s, n, index+1 );\r
+ }\r
+}\r
+\r
+Node OpArgIndex::getGroundTerm( ConjectureGenerator * s, std::vector< TNode >& args ) {\r
+ if( d_ops.empty() ){\r
+ for( std::map< TNode, OpArgIndex >::iterator it = d_child.begin(); it != d_child.end(); ++it ){\r
+ std::map< TNode, Node >::iterator itf = s->d_ground_eqc_map.find( it->first );\r
+ if( itf!=s->d_ground_eqc_map.end() ){\r
+ args.push_back( itf->second );\r
+ Node n = it->second.getGroundTerm( s, args );\r
+ args.pop_back();\r
+ if( !n.isNull() ){\r
+ return n;\r
+ }\r
+ }\r
+ }\r
+ return Node::null();\r
+ }else{\r
+ std::vector< TNode > args2;\r
+ args2.push_back( d_ops[0] );\r
+ args2.insert( args2.end(), args.begin(), args.end() );\r
+ return NodeManager::currentNM()->mkNode( d_op_terms[0].getKind(), args2 );\r
+ }\r
+}\r
+\r
+void OpArgIndex::getGroundTerms( ConjectureGenerator * s, std::vector< TNode >& terms ) {\r
+ terms.insert( terms.end(), d_op_terms.begin(), d_op_terms.end() );\r
+ for( std::map< TNode, OpArgIndex >::iterator it = d_child.begin(); it != d_child.end(); ++it ){\r
+ if( s->isGroundEqc( it->first ) ){\r
+ it->second.getGroundTerms( s, terms );\r
+ }\r
+ }\r
+}\r
+\r
+\r
+\r
+ConjectureGenerator::ConjectureGenerator( QuantifiersEngine * qe, context::Context* c ) : QuantifiersModule( qe ),\r
+d_notify( *this ),\r
+d_uequalityEngine(d_notify, c, "ConjectureGenerator::ee"),\r
+d_ee_conjectures( c ){\r
+ d_fullEffortCount = 0;\r
+ d_uequalityEngine.addFunctionKind( kind::APPLY_UF );\r
+ d_uequalityEngine.addFunctionKind( kind::APPLY_CONSTRUCTOR );\r
+\r
+}\r
+\r
+void ConjectureGenerator::eqNotifyNewClass( TNode t ){\r
+ Trace("thm-ee-debug") << "UEE : new equivalence class " << t << std::endl;\r
+ d_upendingAdds.push_back( t );\r
+}\r
+\r
+void ConjectureGenerator::eqNotifyPreMerge(TNode t1, TNode t2) {\r
+ //get maintained representatives\r
+ TNode rt1 = t1;\r
+ TNode rt2 = t2;\r
+ std::map< Node, EqcInfo* >::iterator it1 = d_eqc_info.find( t1 );\r
+ if( it1!=d_eqc_info.end() && !it1->second->d_rep.get().isNull() ){\r
+ rt1 = it1->second->d_rep.get();\r
+ }\r
+ std::map< Node, EqcInfo* >::iterator it2 = d_eqc_info.find( t2 );\r
+ if( it2!=d_eqc_info.end() && !it2->second->d_rep.get().isNull() ){\r
+ rt2 = it2->second->d_rep.get();\r
+ }\r
+ Trace("thm-ee-debug") << "UEE : equality holds : " << t1 << " == " << t2 << std::endl;\r
+ Trace("thm-ee-debug") << " ureps : " << rt1 << " == " << rt2 << std::endl;\r
+ Trace("thm-ee-debug") << " relevant : " << d_pattern_is_relevant[rt1] << " " << d_pattern_is_relevant[rt2] << std::endl;\r
+ Trace("thm-ee-debug") << " normal : " << d_pattern_is_normal[rt1] << " " << d_pattern_is_normal[rt2] << std::endl;\r
+ Trace("thm-ee-debug") << " size : " << d_pattern_fun_sum[rt1] << " " << d_pattern_fun_sum[rt2] << std::endl;\r
+\r
+ if( isUniversalLessThan( rt2, rt1 ) ){\r
+ EqcInfo * ei;\r
+ if( it1==d_eqc_info.end() ){\r
+ ei = getOrMakeEqcInfo( t1, true );\r
+ }else{\r
+ ei = it1->second;\r
+ }\r
+ ei->d_rep = t2;\r
+ }\r
+}\r
+\r
+void ConjectureGenerator::eqNotifyPostMerge(TNode t1, TNode t2) {\r
+\r
+}\r
+\r
+void ConjectureGenerator::eqNotifyDisequal(TNode t1, TNode t2, TNode reason) {\r
+ Trace("thm-ee-debug") << "UEE : disequality holds : " << t1 << " != " << t2 << std::endl;\r
+\r
+}\r
+\r
+\r
+ConjectureGenerator::EqcInfo::EqcInfo( context::Context* c ) : d_rep( c, Node::null() ){\r
+\r
+}\r
+\r
+ConjectureGenerator::EqcInfo* ConjectureGenerator::getOrMakeEqcInfo( TNode n, bool doMake ) {\r
+ //Assert( getUniversalRepresentative( n )==n );\r
+ std::map< Node, EqcInfo* >::iterator eqc_i = d_eqc_info.find( n );\r
+ if( eqc_i!=d_eqc_info.end() ){\r
+ return eqc_i->second;\r
+ }else if( doMake ){\r
+ EqcInfo* ei = new EqcInfo( d_quantEngine->getSatContext() );\r
+ d_eqc_info[n] = ei;\r
+ return ei;\r
+ }else{\r
+ return NULL;\r
+ }\r
+}\r
+\r
+void ConjectureGenerator::setUniversalRelevant( TNode n ) {\r
+ //add pattern information\r
+ registerPattern( n, n.getType() );\r
+ d_urelevant_terms[n] = true;\r
+ for( unsigned i=0; i<n.getNumChildren(); i++ ){\r
+ setUniversalRelevant( n[i] );\r
+ }\r
+}\r
+\r
+bool ConjectureGenerator::isUniversalLessThan( TNode rt1, TNode rt2 ) {\r
+ //prefer the one that is (normal, smaller) lexographically\r
+ Assert( d_pattern_is_relevant.find( rt1 )!=d_pattern_is_relevant.end() );\r
+ Assert( d_pattern_is_relevant.find( rt2 )!=d_pattern_is_relevant.end() );\r
+ Assert( d_pattern_is_normal.find( rt1 )!=d_pattern_is_normal.end() );\r
+ Assert( d_pattern_is_normal.find( rt2 )!=d_pattern_is_normal.end() );\r
+ Assert( d_pattern_fun_sum.find( rt1 )!=d_pattern_fun_sum.end() );\r
+ Assert( d_pattern_fun_sum.find( rt2 )!=d_pattern_fun_sum.end() );\r
+\r
+ if( d_pattern_is_relevant[rt1] && !d_pattern_is_relevant[rt2] ){\r
+ Trace("thm-ee-debug") << "UEE : LT due to relevant." << std::endl;\r
+ return true;\r
+ }else if( d_pattern_is_relevant[rt1]==d_pattern_is_relevant[rt2] ){\r
+ if( d_pattern_is_normal[rt1] && !d_pattern_is_normal[rt2] ){\r
+ Trace("thm-ee-debug") << "UEE : LT due to normal." << std::endl;\r
+ return true;\r
+ }else if( d_pattern_is_normal[rt1]==d_pattern_is_normal[rt2] ){\r
+ if( d_pattern_fun_sum[rt1]<d_pattern_fun_sum[rt2] ){\r
+ Trace("thm-ee-debug") << "UEE : LT due to size." << std::endl;\r
+ //decide which representative to use : based on size of the term\r
+ return true;\r
+ }else if( d_pattern_fun_sum[rt1]==d_pattern_fun_sum[rt2] ){\r
+ //same size : tie goes to term that has already been reported\r
+ return isReportedCanon( rt1 ) && !isReportedCanon( rt2 );\r
+ }\r
+ }\r
+ }\r
+ return false;\r
+}\r
+\r
+\r
+bool ConjectureGenerator::isReportedCanon( TNode n ) {\r
+ return std::find( d_ue_canon.begin(), d_ue_canon.end(), n )==d_ue_canon.end();\r
+}\r
+\r
+void ConjectureGenerator::markReportedCanon( TNode n ) {\r
+ if( !isReportedCanon( n ) ){\r
+ d_ue_canon.push_back( n );\r
+ }\r
+}\r
+\r
+bool ConjectureGenerator::areUniversalEqual( TNode n1, TNode n2 ) {\r
+ return n1==n2 || ( d_uequalityEngine.hasTerm( n1 ) && d_uequalityEngine.hasTerm( n2 ) && d_uequalityEngine.areEqual( n1, n2 ) );\r
+}\r
+\r
+bool ConjectureGenerator::areUniversalDisequal( TNode n1, TNode n2 ) {\r
+ return n1!=n2 && d_uequalityEngine.hasTerm( n1 ) && d_uequalityEngine.hasTerm( n2 ) && d_uequalityEngine.areDisequal( n1, n2, false );\r
+}\r
+\r
+TNode ConjectureGenerator::getUniversalRepresentative( TNode n, bool add ) {\r
+ if( add ){\r
+ if( d_urelevant_terms.find( n )==d_urelevant_terms.end() ){\r
+ setUniversalRelevant( n );\r
+ //add term to universal equality engine\r
+ d_uequalityEngine.addTerm( n );\r
+ // addding this term to equality engine will lead to a set of new terms (the new subterms of n)\r
+ // now, do instantiation-based merging for each of these terms\r
+ Trace("thm-ee-debug") << "Merge equivalence classes based on instantiations of terms..." << std::endl;\r
+ //merge all pending equalities\r
+ while( !d_upendingAdds.empty() ){\r
+ Trace("sg-pending") << "Add " << d_upendingAdds.size() << " pending terms..." << std::endl;\r
+ std::vector< Node > pending;\r
+ pending.insert( pending.end(), d_upendingAdds.begin(), d_upendingAdds.end() );\r
+ d_upendingAdds.clear();\r
+ for( unsigned i=0; i<pending.size(); i++ ){\r
+ Node t = pending[i];\r
+ TypeNode tn = t.getType();\r
+ Trace("thm-ee-add") << "UEE : Add universal term " << t << std::endl;\r
+ std::vector< Node > eq_terms;\r
+ //if occurs modulo equality at ground level, it is equivalent to representative of ground equality engine\r
+ TNode gt = getTermDatabase()->evaluateTerm( t );\r
+ if( !gt.isNull() && gt!=t ){\r
+ eq_terms.push_back( gt );\r
+ }\r
+ //get all equivalent terms based on theorem database\r
+ d_thm_index.getEquivalentTerms( t, eq_terms );\r
+ if( !eq_terms.empty() ){\r
+ Trace("thm-ee-add") << "UEE : Based on ground EE/theorem DB, it is equivalent to " << eq_terms.size() << " terms : " << std::endl;\r
+ //add equivalent terms as equalities to universal engine\r
+ for( unsigned i=0; i<eq_terms.size(); i++ ){\r
+ Trace("thm-ee-add") << " " << eq_terms[i] << std::endl;\r
+ bool assertEq = false;\r
+ if( d_urelevant_terms.find( eq_terms[i] )!=d_urelevant_terms.end() ){\r
+ assertEq = true;\r
+ }else{\r
+ Assert( eq_terms[i].getType()==tn );\r
+ registerPattern( eq_terms[i], tn );\r
+ if( isUniversalLessThan( eq_terms[i], t ) || ( options::conjectureUeeIntro() && d_pattern_fun_sum[t]>=d_pattern_fun_sum[eq_terms[i]] ) ){\r
+ setUniversalRelevant( eq_terms[i] );\r
+ assertEq = true;\r
+ }\r
+ }\r
+ if( assertEq ){\r
+ Node exp;\r
+ d_uequalityEngine.assertEquality( t.eqNode( eq_terms[i] ), true, exp );\r
+ }else{\r
+ Trace("thm-ee-no-add") << "Do not add : " << t << " == " << eq_terms[i] << std::endl;\r
+ }\r
+ }\r
+ }else{\r
+ Trace("thm-ee-add") << "UEE : No equivalent terms." << std::endl;\r
+ }\r
+ }\r
+ }\r
+ }\r
+ }\r
+\r
+ if( d_uequalityEngine.hasTerm( n ) ){\r
+ Node r = d_uequalityEngine.getRepresentative( n );\r
+ EqcInfo * ei = getOrMakeEqcInfo( r );\r
+ if( ei && !ei->d_rep.get().isNull() ){\r
+ return ei->d_rep.get();\r
+ }else{\r
+ return r;\r
+ }\r
+ }else{\r
+ return n;\r
+ }\r
+}\r
+\r
+Node ConjectureGenerator::getFreeVar( TypeNode tn, unsigned i ) {\r
+ Assert( !tn.isNull() );\r
+ while( d_free_var[tn].size()<=i ){\r
+ std::stringstream oss;\r
+ oss << tn;\r
+ std::stringstream os;\r
+ os << oss.str()[0] << i;\r
+ Node x = NodeManager::currentNM()->mkBoundVar( os.str().c_str(), tn );\r
+ d_free_var_num[x] = d_free_var[tn].size();\r
+ d_free_var[tn].push_back( x );\r
+ }\r
+ return d_free_var[tn][i];\r
+}\r
+\r
+\r
+\r
+Node ConjectureGenerator::getCanonicalTerm( TNode n, std::map< TypeNode, unsigned >& var_count, std::map< TNode, TNode >& subs ) {\r
+ if( n.getKind()==BOUND_VARIABLE ){\r
+ std::map< TNode, TNode >::iterator it = subs.find( n );\r
+ if( it==subs.end() ){\r
+ TypeNode tn = n.getType();\r
+ //allocate variable\r
+ unsigned vn = var_count[tn];\r
+ var_count[tn]++;\r
+ subs[n] = getFreeVar( tn, vn );\r
+ return subs[n];\r
+ }else{\r
+ return it->second;\r
+ }\r
+ }else{\r
+ std::vector< Node > children;\r
+ if( n.getKind()!=EQUAL ){\r
+ if( n.hasOperator() ){\r
+ TNode op = n.getOperator();\r
+ if( !d_tge.isRelevantFunc( op ) ){\r
+ return Node::null();\r
+ }\r
+ children.push_back( op );\r
+ }else{\r
+ return Node::null();\r
+ }\r
+ }\r
+ for( unsigned i=0; i<n.getNumChildren(); i++ ){\r
+ Node cn = getCanonicalTerm( n[i], var_count, subs );\r
+ if( cn.isNull() ){\r
+ return Node::null();\r
+ }else{\r
+ children.push_back( cn );\r
+ }\r
+ }\r
+ return NodeManager::currentNM()->mkNode( n.getKind(), children );\r
+ }\r
+}\r
+\r
+bool ConjectureGenerator::isHandledTerm( TNode n ){\r
+ return !n.getAttribute(NoMatchAttribute()) && inst::Trigger::isAtomicTrigger( n ) && ( n.getKind()!=APPLY_UF || n.getOperator().getKind()!=SKOLEM );\r
+}\r
+\r
+Node ConjectureGenerator::getGroundEqc( TNode r ) {\r
+ std::map< TNode, Node >::iterator it = d_ground_eqc_map.find( r );\r
+ return it!=d_ground_eqc_map.end() ? it->second : Node::null();\r
+}\r
+\r
+bool ConjectureGenerator::isGroundEqc( TNode r ) {\r
+ return d_ground_eqc_map.find( r )!=d_ground_eqc_map.end();\r
+}\r
+\r
+bool ConjectureGenerator::isGroundTerm( TNode n ) {\r
+ return std::find( d_ground_terms.begin(), d_ground_terms.end(), n )!=d_ground_terms.end();\r
+}\r
+\r
+bool ConjectureGenerator::needsCheck( Theory::Effort e ) {\r
+ return e==Theory::EFFORT_FULL;\r
+}\r
+\r
+bool ConjectureGenerator::hasEnumeratedUf( Node n ) {\r
+ if( options::conjectureGenGtEnum()>0 ){\r
+ std::map< Node, bool >::iterator it = d_uf_enum.find( n.getOperator() );\r
+ if( it==d_uf_enum.end() ){\r
+ d_uf_enum[n.getOperator()] = true;\r
+ std::vector< Node > lem;\r
+ getEnumeratePredUfTerm( n, options::conjectureGenGtEnum(), lem );\r
+ if( !lem.empty() ){\r
+ for( unsigned j=0; j<lem.size(); j++ ){\r
+ d_quantEngine->addLemma( lem[j], false );\r
+ d_hasAddedLemma = true;\r
+ }\r
+ return false;\r
+ }\r
+ }\r
+ }\r
+ return true;\r
+}\r
+\r
+void ConjectureGenerator::reset_round( Theory::Effort e ) {\r
+\r
+}\r
+\r
+void ConjectureGenerator::check( Theory::Effort e, unsigned quant_e ) {\r
+ if( quant_e==QuantifiersEngine::QEFFORT_STANDARD ){\r
+ d_fullEffortCount++;\r
+ if( d_fullEffortCount%optFullCheckFrequency()==0 ){\r
+ d_hasAddedLemma = false;\r
+ d_tge.d_cg = this;\r
+ double clSet = 0;\r
+ if( Trace.isOn("sg-engine") ){\r
+ clSet = double(clock())/double(CLOCKS_PER_SEC);\r
+ Trace("sg-engine") << "---Conjecture Engine Round, effort = " << e << "---" << std::endl;\r
+ }\r
+ eq::EqualityEngine * ee = getEqualityEngine();\r
+\r
+ Trace("sg-proc") << "Get eq classes..." << std::endl;\r
+ d_op_arg_index.clear();\r
+ d_ground_eqc_map.clear();\r
+ d_bool_eqc[0] = Node::null();\r
+ d_bool_eqc[1] = Node::null();\r
+ std::vector< TNode > eqcs;\r
+ d_em.clear();\r
+ eq::EqClassesIterator eqcs_i = eq::EqClassesIterator( ee );\r
+ while( !eqcs_i.isFinished() ){\r
+ TNode r = (*eqcs_i);\r
+ eqcs.push_back( r );\r
+ if( r.getType().isBoolean() ){\r
+ if( areEqual( r, getTermDatabase()->d_true ) ){\r
+ d_ground_eqc_map[r] = getTermDatabase()->d_true;\r
+ d_bool_eqc[0] = r;\r
+ }else if( areEqual( r, getTermDatabase()->d_false ) ){\r
+ d_ground_eqc_map[r] = getTermDatabase()->d_false;\r
+ d_bool_eqc[1] = r;\r
+ }\r
+ }\r
+ d_em[r] = eqcs.size();\r
+ eq::EqClassIterator ieqc_i = eq::EqClassIterator( r, ee );\r
+ while( !ieqc_i.isFinished() ){\r
+ TNode n = (*ieqc_i);\r
+ if( isHandledTerm( n ) ){\r
+ d_op_arg_index[r].addTerm( this, n );\r
+ }\r
+ ++ieqc_i;\r
+ }\r
+ ++eqcs_i;\r
+ }\r
+ Assert( !d_bool_eqc[0].isNull() );\r
+ Assert( !d_bool_eqc[1].isNull() );\r
+ d_urelevant_terms.clear();\r
+ Trace("sg-proc") << "...done get eq classes" << std::endl;\r
+\r
+ Trace("sg-proc") << "Determine ground EQC..." << std::endl;\r
+ bool success;\r
+ do{\r
+ success = false;\r
+ for( unsigned i=0; i<eqcs.size(); i++ ){\r
+ TNode r = eqcs[i];\r
+ if( d_ground_eqc_map.find( r )==d_ground_eqc_map.end() ){\r
+ std::vector< TNode > args;\r
+ Trace("sg-pat-debug") << "******* Get ground term for " << r << std::endl;\r
+ Node n;\r
+ if( getTermDatabase()->isInductionTerm( r ) ){\r
+ n = d_op_arg_index[r].getGroundTerm( this, args );\r
+ }else{\r
+ n = r;\r
+ }\r
+ if( !n.isNull() ){\r
+ Trace("sg-pat") << "Ground term for eqc " << r << " : " << std::endl;\r
+ Trace("sg-pat") << " " << n << std::endl;\r
+ d_ground_eqc_map[r] = n;\r
+ success = true;\r
+ }else{\r
+ Trace("sg-pat-debug") << "...could not find ground term." << std::endl;\r
+ }\r
+ }\r
+ }\r
+ }while( success );\r
+ //also get ground terms\r
+ d_ground_terms.clear();\r
+ for( unsigned i=0; i<eqcs.size(); i++ ){\r
+ TNode r = eqcs[i];\r
+ d_op_arg_index[r].getGroundTerms( this, d_ground_terms );\r
+ }\r
+ Trace("sg-proc") << "...done determine ground EQC" << std::endl;\r
+\r
+ //debug printing\r
+ if( Trace.isOn("sg-gen-eqc") ){\r
+ for( unsigned i=0; i<eqcs.size(); i++ ){\r
+ TNode r = eqcs[i];\r
+ //print out members\r
+ bool firstTime = true;\r
+ bool isFalse = areEqual( r, getTermDatabase()->d_false );\r
+ eq::EqClassIterator eqc_i = eq::EqClassIterator( r, ee );\r
+ while( !eqc_i.isFinished() ){\r
+ TNode n = (*eqc_i);\r
+ if( !n.getAttribute(NoMatchAttribute()) && ( n.getKind()!=EQUAL || isFalse ) ){\r
+ if( firstTime ){\r
+ Trace("sg-gen-eqc") << "e" << d_em[r] << " : { " << std::endl;\r
+ firstTime = false;\r
+ }\r
+ if( n.hasOperator() ){\r
+ Trace("sg-gen-eqc") << " (" << n.getOperator();\r
+ getTermDatabase()->computeArgReps( n );\r
+ for( unsigned i=0; i<getTermDatabase()->d_arg_reps[n].size(); i++ ){\r
+ Trace("sg-gen-eqc") << " e" << d_em[getTermDatabase()->d_arg_reps[n][i]];\r
+ }\r
+ Trace("sg-gen-eqc") << ") :: " << n << std::endl;\r
+ }else{\r
+ Trace("sg-gen-eqc") << " " << n << std::endl;\r
+ }\r
+ }\r
+ ++eqc_i;\r
+ }\r
+ if( !firstTime ){\r
+ Trace("sg-gen-eqc") << "}" << std::endl;\r
+ //print out ground term\r
+ std::map< TNode, Node >::iterator it = d_ground_eqc_map.find( r );\r
+ if( it!=d_ground_eqc_map.end() ){\r
+ Trace("sg-gen-eqc") << "- Ground term : " << it->second << std::endl;\r
+ }\r
+ }\r
+ }\r
+ }\r
+\r
+ Trace("sg-proc") << "Compute relevant eqc..." << std::endl;\r
+ d_tge.d_relevant_eqc[0].clear();\r
+ d_tge.d_relevant_eqc[1].clear();\r
+ for( unsigned i=0; i<eqcs.size(); i++ ){\r
+ TNode r = eqcs[i];\r
+ std::map< TNode, Node >::iterator it = d_ground_eqc_map.find( r );\r
+ unsigned index = 1;\r
+ if( it==d_ground_eqc_map.end() ){\r
+ index = 0;\r
+ }\r
+ //based on unproven conjectures? TODO\r
+ d_tge.d_relevant_eqc[index].push_back( r );\r
+ }\r
+ Trace("sg-gen-tg-debug") << "Initial relevant eqc : ";\r
+ for( unsigned i=0; i<d_tge.d_relevant_eqc[0].size(); i++ ){\r
+ Trace("sg-gen-tg-debug") << "e" << d_em[d_tge.d_relevant_eqc[0][i]] << " ";\r
+ }\r
+ Trace("sg-gen-tg-debug") << std::endl;\r
+ Trace("sg-proc") << "...done compute relevant eqc" << std::endl;\r
+\r
+\r
+ Trace("sg-proc") << "Collect signature information..." << std::endl;\r
+ d_tge.collectSignatureInformation();\r
+ if( d_hasAddedLemma ){\r
+ Trace("sg-proc") << "...added enumeration lemmas." << std::endl;\r
+ }\r
+ Trace("sg-proc") << "...done collect signature information" << std::endl;\r
+\r
+\r
+\r
+ Trace("sg-proc") << "Build theorem index..." << std::endl;\r
+ d_ue_canon.clear();\r
+ d_thm_index.clear();\r
+ std::vector< Node > provenConj;\r
+ quantifiers::FirstOrderModel* m = d_quantEngine->getModel();\r
+ for( int i=0; i<m->getNumAssertedQuantifiers(); i++ ){\r
+ Node q = m->getAssertedQuantifier( i );\r
+ Trace("thm-db-debug") << "Is " << q << " a relevant theorem?" << std::endl;\r
+ Node conjEq;\r
+ if( q[1].getKind()==EQUAL ){\r
+ bool isSubsume = false;\r
+ bool inEe = false;\r
+ for( unsigned r=0; r<2; r++ ){\r
+ TNode nl = q[1][r==0 ? 0 : 1];\r
+ TNode nr = q[1][r==0 ? 1 : 0];\r
+ Node eq = nl.eqNode( nr );\r
+ if( r==1 || std::find( d_conjectures.begin(), d_conjectures.end(), q )==d_conjectures.end() ){\r
+ //must make it canonical\r
+ std::map< TypeNode, unsigned > var_count;\r
+ std::map< TNode, TNode > subs;\r
+ Trace("sg-proc-debug") << "get canonical " << eq << std::endl;\r
+ eq = getCanonicalTerm( eq, var_count, subs );\r
+ }\r
+ if( !eq.isNull() ){\r
+ if( r==0 ){\r
+ inEe = d_ee_conjectures.find( q[1] )!=d_ee_conjectures.end();\r
+ if( !inEe ){\r
+ //add to universal equality engine\r
+ Node nl = getUniversalRepresentative( eq[0], true );\r
+ Node nr = getUniversalRepresentative( eq[1], true );\r
+ if( areUniversalEqual( nl, nr ) ){\r
+ isSubsume = true;\r
+ //set inactive (will be ignored by other modules)\r
+ d_quantEngine->getModel()->setQuantifierActive( q, false );\r
+ }else{\r
+ Node exp;\r
+ d_ee_conjectures[q[1]] = true;\r
+ d_uequalityEngine.assertEquality( nl.eqNode( nr ), true, exp );\r
+ }\r
+ }\r
+ Trace("sg-conjecture") << "*** CONJECTURE : currently proven" << (isSubsume ? " and subsumed" : "");\r
+ Trace("sg-conjecture") << " : " << q[1] << std::endl;\r
+ provenConj.push_back( q );\r
+ }\r
+ if( !isSubsume ){\r
+ Trace("thm-db-debug") << "Adding theorem to database " << eq[0] << " == " << eq[1] << std::endl;\r
+ d_thm_index.addTheorem( eq[0], eq[1] );\r
+ }else{\r
+ break;\r
+ }\r
+ }else{\r
+ break;\r
+ }\r
+ }\r
+ }\r
+ }\r
+ //examine status of other conjectures\r
+ for( unsigned i=0; i<d_conjectures.size(); i++ ){\r
+ Node q = d_conjectures[i];\r
+ if( std::find( provenConj.begin(), provenConj.end(), q )==provenConj.end() ){\r
+ //check each skolem variable\r
+ bool disproven = true;\r
+ //std::vector< Node > sk;\r
+ //getTermDatabase()->getSkolemConstants( q, sk, true );\r
+ Trace("sg-conjecture") << " CONJECTURE : ";\r
+ std::vector< Node > ce;\r
+ for( unsigned j=0; j<getTermDatabase()->d_skolem_constants[q].size(); j++ ){\r
+ TNode k = getTermDatabase()->d_skolem_constants[q][j];\r
+ TNode rk = getRepresentative( k );\r
+ std::map< TNode, Node >::iterator git = d_ground_eqc_map.find( rk );\r
+ //check if it is a ground term\r
+ if( git==d_ground_eqc_map.end() ){\r
+ Trace("sg-conjecture") << "ACTIVE : " << q;\r
+ if( Trace.isOn("sg-gen-eqc") ){\r
+ Trace("sg-conjecture") << " { ";\r
+ for( unsigned k=0; k<getTermDatabase()->d_skolem_constants[q].size(); k++ ){ Trace("sg-conjecture") << getTermDatabase()->d_skolem_constants[q][k] << ( j==k ? "*" : "" ) << " "; }\r
+ Trace("sg-conjecture") << "}";\r
+ }\r
+ Trace("sg-conjecture") << std::endl;\r
+ disproven = false;\r
+ break;\r
+ }else{\r
+ ce.push_back( git->second );\r
+ }\r
+ }\r
+ if( disproven ){\r
+ Trace("sg-conjecture") << "disproven : " << q << " : ";\r
+ for( unsigned i=0; i<ce.size(); i++ ){\r
+ Trace("sg-conjecture") << q[0][i] << " -> " << ce[i] << " ";\r
+ }\r
+ Trace("sg-conjecture") << std::endl;\r
+ }\r
+ }\r
+ }\r
+ Trace("thm-db") << "Theorem database is : " << std::endl;\r
+ d_thm_index.debugPrint( "thm-db" );\r
+ Trace("thm-db") << std::endl;\r
+ Trace("sg-proc") << "...done build theorem index" << std::endl;\r
+\r
+\r
+ //clear patterns\r
+ d_patterns.clear();\r
+ d_pattern_var_id.clear();\r
+ d_pattern_var_duplicate.clear();\r
+ d_pattern_is_normal.clear();\r
+ d_pattern_is_relevant.clear();\r
+ d_pattern_fun_id.clear();\r
+ d_pattern_fun_sum.clear();\r
+ d_rel_patterns.clear();\r
+ d_rel_pattern_var_sum.clear();\r
+ d_rel_pattern_typ_index.clear();\r
+ d_rel_pattern_subs_index.clear();\r
+\r
+ unsigned rel_term_count = 0;\r
+ std::map< TypeNode, unsigned > rt_var_max;\r
+ std::vector< TypeNode > rt_types;\r
+ std::map< TypeNode, std::map< int, std::vector< Node > > > conj_lhs;\r
+ unsigned addedLemmas = 0;\r
+ for( unsigned depth=1; depth<=3; depth++ ){\r
+ Trace("sg-proc") << "Generate relevant LHS at depth " << depth << "..." << std::endl;\r
+ Trace("sg-rel-term") << "Relevant terms of depth " << depth << " : " << std::endl;\r
+ //set up environment\r
+ d_tge.d_var_id.clear();\r
+ d_tge.d_var_limit.clear();\r
+ d_tge.reset( depth, true, TypeNode::null() );\r
+ while( d_tge.getNextTerm() ){\r
+ //construct term\r
+ Node nn = d_tge.getTerm();\r
+ if( !options::conjectureFilterCanonical() || considerTermCanon( nn, true ) ){\r
+ rel_term_count++;\r
+ Trace("sg-rel-term") << "*** Relevant term : ";\r
+ d_tge.debugPrint( "sg-rel-term", "sg-rel-term-debug2" );\r
+ Trace("sg-rel-term") << std::endl;\r
+\r
+ for( unsigned r=0; r<2; r++ ){\r
+ Trace("sg-rel-term-debug") << "...from equivalence classes (" << r << ") : ";\r
+ int index = d_tge.d_ccand_eqc[r].size()-1;\r
+ for( unsigned j=0; j<d_tge.d_ccand_eqc[r][index].size(); j++ ){\r
+ Trace("sg-rel-term-debug") << "e" << d_em[d_tge.d_ccand_eqc[r][index][j]] << " ";\r
+ }\r
+ Trace("sg-rel-term-debug") << std::endl;\r
+ }\r
+ TypeNode tnn = nn.getType();\r
+ Trace("sg-gen-tg-debug") << "...term is " << nn << std::endl;\r
+ conj_lhs[tnn][depth].push_back( nn );\r
+\r
+ //add information about pattern\r
+ Trace("sg-gen-tg-debug") << "Collect pattern information..." << std::endl;\r
+ Assert( std::find( d_rel_patterns[tnn].begin(), d_rel_patterns[tnn].end(), nn )==d_rel_patterns[tnn].end() );\r
+ d_rel_patterns[tnn].push_back( nn );\r
+ //build information concerning the variables in this pattern\r
+ unsigned sum = 0;\r
+ std::map< TypeNode, unsigned > typ_to_subs_index;\r
+ std::vector< TNode > gsubs_vars;\r
+ for( std::map< TypeNode, unsigned >::iterator it = d_tge.d_var_id.begin(); it != d_tge.d_var_id.end(); ++it ){\r
+ if( it->second>0 ){\r
+ typ_to_subs_index[it->first] = sum;\r
+ sum += it->second;\r
+ for( unsigned i=0; i<it->second; i++ ){\r
+ gsubs_vars.push_back( getFreeVar( it->first, i ) );\r
+ }\r
+ }\r
+ }\r
+ d_rel_pattern_var_sum[nn] = sum;\r
+ //register the pattern\r
+ registerPattern( nn, tnn );\r
+ Assert( d_pattern_is_normal[nn] );\r
+ Trace("sg-gen-tg-debug") << "...done collect pattern information" << std::endl;\r
+\r
+ //record information about types\r
+ Trace("sg-gen-tg-debug") << "Collect type information..." << std::endl;\r
+ PatternTypIndex * pti = &d_rel_pattern_typ_index;\r
+ for( std::map< TypeNode, unsigned >::iterator it = d_tge.d_var_id.begin(); it != d_tge.d_var_id.end(); ++it ){\r
+ pti = &pti->d_children[it->first][it->second];\r
+ //record maximum\r
+ if( rt_var_max.find( it->first )==rt_var_max.end() || it->second>rt_var_max[it->first] ){\r
+ rt_var_max[it->first] = it->second;\r
+ }\r
+ }\r
+ if( std::find( rt_types.begin(), rt_types.end(), tnn )==rt_types.end() ){\r
+ rt_types.push_back( tnn );\r
+ }\r
+ pti->d_terms.push_back( nn );\r
+ Trace("sg-gen-tg-debug") << "...done collect type information" << std::endl;\r
+\r
+ Trace("sg-gen-tg-debug") << "Build substitutions for ground EQC..." << std::endl;\r
+ std::vector< TNode > gsubs_terms;\r
+ gsubs_terms.resize( gsubs_vars.size() );\r
+ int index = d_tge.d_ccand_eqc[1].size()-1;\r
+ for( unsigned j=0; j<d_tge.d_ccand_eqc[1][index].size(); j++ ){\r
+ TNode r = d_tge.d_ccand_eqc[1][index][j];\r
+ Trace("sg-rel-term-debug") << " Matches for e" << d_em[r] << ", which is ground term " << d_ground_eqc_map[r] << ":" << std::endl;\r
+ std::map< TypeNode, std::map< unsigned, TNode > > subs;\r
+ std::map< TNode, bool > rev_subs;\r
+ //only get ground terms\r
+ unsigned mode = 2;\r
+ d_tge.resetMatching( r, mode );\r
+ while( d_tge.getNextMatch( r, subs, rev_subs ) ){\r
+ //we will be building substitutions\r
+ bool firstTime = true;\r
+ for( std::map< TypeNode, std::map< unsigned, TNode > >::iterator it = subs.begin(); it != subs.end(); ++it ){\r
+ unsigned tindex = typ_to_subs_index[it->first];\r
+ for( std::map< unsigned, TNode >::iterator it2 = it->second.begin(); it2 != it->second.end(); ++it2 ){\r
+ if( !firstTime ){\r
+ Trace("sg-rel-term-debug") << ", ";\r
+ }else{\r
+ firstTime = false;\r
+ Trace("sg-rel-term-debug") << " ";\r
+ }\r
+ Trace("sg-rel-term-debug") << it->first << ":x" << it2->first << " -> " << it2->second;\r
+ Assert( tindex+it2->first<gsubs_terms.size() );\r
+ gsubs_terms[tindex+it2->first] = it2->second;\r
+ }\r
+ }\r
+ Trace("sg-rel-term-debug") << std::endl;\r
+ d_rel_pattern_subs_index[nn].addSubstitution( r, gsubs_vars, gsubs_terms );\r
+ }\r
+ }\r
+ Trace("sg-gen-tg-debug") << "...done build substitutions for ground EQC" << std::endl;\r
+ }else{\r
+ Trace("sg-gen-tg-debug") << "> not canonical : " << nn << std::endl;\r
+ }\r
+ }\r
+ Trace("sg-proc") << "...done generate terms at depth " << depth << std::endl;\r
+ Trace("sg-stats") << "--------> Total LHS of depth " << depth << " : " << rel_term_count << std::endl;\r
+ //Trace("conjecture-count") << "Total LHS of depth " << depth << " : " << conj_lhs[depth].size() << std::endl;\r
+\r
+ /* test...\r
+ for( unsigned i=0; i<rt_types.size(); i++ ){\r
+ Trace("sg-term-enum") << "Term enumeration for " << rt_types[i] << " : " << std::endl;\r
+ Trace("sg-term-enum") << "Ground term : " << rt_types[i].mkGroundTerm() << std::endl;\r
+ for( unsigned j=0; j<150; j++ ){\r
+ Trace("sg-term-enum") << " " << getEnumerateTerm( rt_types[i], j ) << std::endl;\r
+ }\r
+ }\r
+ */\r
+\r
+ //consider types from relevant terms\r
+ for( unsigned rdepth=0; rdepth<=depth; rdepth++ ){\r
+ //set up environment\r
+ d_tge.d_var_id.clear();\r
+ d_tge.d_var_limit.clear();\r
+ for( std::map< TypeNode, unsigned >::iterator it = rt_var_max.begin(); it != rt_var_max.end(); ++it ){\r
+ d_tge.d_var_id[ it->first ] = it->second;\r
+ d_tge.d_var_limit[ it->first ] = it->second;\r
+ }\r
+ std::random_shuffle( rt_types.begin(), rt_types.end() );\r
+ std::map< TypeNode, std::vector< Node > > conj_rhs;\r
+ for( unsigned i=0; i<rt_types.size(); i++ ){\r
+\r
+ Trace("sg-proc") << "Generate relevant RHS terms of type " << rt_types[i] << " at depth " << rdepth << "..." << std::endl;\r
+ d_tge.reset( rdepth, false, rt_types[i] );\r
+\r
+ while( d_tge.getNextTerm() ){\r
+ Node rhs = d_tge.getTerm();\r
+ if( considerTermCanon( rhs, false ) ){\r
+ Trace("sg-rel-prop") << "Relevant RHS : " << rhs << std::endl;\r
+ //register pattern\r
+ Assert( rhs.getType()==rt_types[i] );\r
+ registerPattern( rhs, rt_types[i] );\r
+ if( rdepth<depth ){\r
+ //consider against all LHS at depth\r
+ for( unsigned j=0; j<conj_lhs[rt_types[i]][depth].size(); j++ ){\r
+ processCandidateConjecture( conj_lhs[rt_types[i]][depth][j], rhs, depth, rdepth );\r
+ }\r
+ }else{\r
+ conj_rhs[rt_types[i]].push_back( rhs );\r
+ }\r
+ }\r
+ }\r
+ }\r
+ flushWaitingConjectures( addedLemmas, depth, rdepth );\r
+ //consider against all LHS up to depth\r
+ if( rdepth==depth ){\r
+ for( unsigned lhs_depth = 1; lhs_depth<=depth; lhs_depth++ ){\r
+ if( (int)addedLemmas<options::conjectureGenPerRound() ){\r
+ Trace("sg-proc") << "Consider conjectures at depth (" << lhs_depth << ", " << rdepth << ")..." << std::endl;\r
+ for( std::map< TypeNode, std::vector< Node > >::iterator it = conj_rhs.begin(); it != conj_rhs.end(); ++it ){\r
+ for( unsigned j=0; j<it->second.size(); j++ ){\r
+ for( unsigned k=0; k<conj_lhs[it->first][lhs_depth].size(); k++ ){\r
+ processCandidateConjecture( conj_lhs[it->first][lhs_depth][k], it->second[j], lhs_depth, rdepth );\r
+ }\r
+ }\r
+ }\r
+ flushWaitingConjectures( addedLemmas, lhs_depth, depth );\r
+ }\r
+ }\r
+ }\r
+ if( (int)addedLemmas>=options::conjectureGenPerRound() ){\r
+ break;\r
+ }\r
+ }\r
+ if( (int)addedLemmas>=options::conjectureGenPerRound() ){\r
+ break;\r
+ }\r
+ }\r
+\r
+ if( Trace.isOn("thm-ee") ){\r
+ Trace("thm-ee") << "Universal equality engine is : " << std::endl;\r
+ eq::EqClassesIterator ueqcs_i = eq::EqClassesIterator( &d_uequalityEngine );\r
+ while( !ueqcs_i.isFinished() ){\r
+ TNode r = (*ueqcs_i);\r
+ bool firstTime = true;\r
+ TNode rr = getUniversalRepresentative( r );\r
+ Trace("thm-ee") << " " << rr;\r
+ Trace("thm-ee") << " : { ";\r
+ eq::EqClassIterator ueqc_i = eq::EqClassIterator( r, &d_uequalityEngine );\r
+ while( !ueqc_i.isFinished() ){\r
+ TNode n = (*ueqc_i);\r
+ if( rr!=n ){\r
+ if( firstTime ){\r
+ Trace("thm-ee") << std::endl;\r
+ firstTime = false;\r
+ }\r
+ Trace("thm-ee") << " " << n << std::endl;\r
+ }\r
+ ++ueqc_i;\r
+ }\r
+ if( !firstTime ){ Trace("thm-ee") << " "; }\r
+ Trace("thm-ee") << "}" << std::endl;\r
+ ++ueqcs_i;\r
+ }\r
+ Trace("thm-ee") << std::endl;\r
+ }\r
+ if( Trace.isOn("sg-engine") ){\r
+ double clSet2 = double(clock())/double(CLOCKS_PER_SEC);\r
+ Trace("sg-engine") << "Finished conjecture generator, time = " << (clSet2-clSet) << std::endl;\r
+ }\r
+ }\r
+ }\r
+}\r
+\r
+unsigned ConjectureGenerator::flushWaitingConjectures( unsigned& addedLemmas, int ldepth, int rdepth ) {\r
+ if( !d_waiting_conjectures_lhs.empty() ){\r
+ Trace("sg-proc") << "Generated " << d_waiting_conjectures_lhs.size() << " conjectures at depth " << ldepth << "/" << rdepth << "." << std::endl;\r
+ if( !optStatsOnly() && (int)addedLemmas<options::conjectureGenPerRound() ){\r
+ std::vector< unsigned > indices;\r
+ for( unsigned i=0; i<d_waiting_conjectures_lhs.size(); i++ ){\r
+ indices.push_back( i );\r
+ }\r
+ bool doSort = false;\r
+ if( doSort ){\r
+ //sort them based on score\r
+ sortConjectureScore scs;\r
+ scs.d_scores.insert( scs.d_scores.begin(), d_waiting_conjectures_score.begin(), d_waiting_conjectures_score.end() );\r
+ std::sort( indices.begin(), indices.end(), scs );\r
+ }\r
+ if( doSort && d_waiting_conjectures_score[indices[0]]<optFilterScoreThreshold() ){\r
+ //do splitting on demand (TODO)\r
+\r
+ }else{\r
+ for( unsigned i=0; i<indices.size(); i++ ){\r
+ //if( d_waiting_conjectures_score[indices[i]]<optFilterScoreThreshold() ){\r
+ if( d_waiting_conjectures_score[indices[i]]>=optFilterScoreThreshold() ){\r
+ //we have determined a relevant subgoal\r
+ Node lhs = d_waiting_conjectures_lhs[indices[i]];\r
+ Node rhs = d_waiting_conjectures_rhs[indices[i]];\r
+ if( options::conjectureFilterCanonical() && ( getUniversalRepresentative( lhs )!=lhs || getUniversalRepresentative( rhs )!=rhs ) ){\r
+ //skip\r
+ }else{\r
+ Trace("sg-engine") << "*** Consider conjecture : " << lhs << " == " << rhs << std::endl;\r
+ Trace("sg-engine-debug") << " score : " << d_waiting_conjectures_score[indices[i]] << std::endl;\r
+ std::vector< Node > bvs;\r
+ for( std::map< TypeNode, unsigned >::iterator it = d_pattern_var_id[lhs].begin(); it != d_pattern_var_id[lhs].end(); ++it ){\r
+ for( unsigned i=0; i<=it->second; i++ ){\r
+ bvs.push_back( getFreeVar( it->first, i ) );\r
+ }\r
+ }\r
+ Node rsg;\r
+ if( !bvs.empty() ){\r
+ Node bvl = NodeManager::currentNM()->mkNode( BOUND_VAR_LIST, bvs );\r
+ rsg = NodeManager::currentNM()->mkNode( FORALL, bvl, lhs.eqNode( rhs ) );\r
+ }else{\r
+ rsg = lhs.eqNode( rhs );\r
+ }\r
+ rsg = Rewriter::rewrite( rsg );\r
+ d_conjectures.push_back( rsg );\r
+ d_eq_conjectures[lhs].push_back( rhs );\r
+ d_eq_conjectures[rhs].push_back( lhs );\r
+\r
+ Node lem = NodeManager::currentNM()->mkNode( OR, rsg.negate(), rsg );\r
+ d_quantEngine->addLemma( lem, false );\r
+ d_quantEngine->addRequirePhase( rsg, false );\r
+ addedLemmas++;\r
+ if( (int)addedLemmas>=options::conjectureGenPerRound() ){\r
+ break;\r
+ }\r
+ }\r
+ }else{\r
+ if( doSort ){\r
+ break;\r
+ }\r
+ }\r
+ }\r
+ }\r
+ Trace("sg-proc") << "...have now added " << addedLemmas << " conjecture lemmas." << std::endl;\r
+ }\r
+ d_waiting_conjectures_lhs.clear();\r
+ d_waiting_conjectures_rhs.clear();\r
+ d_waiting_conjectures_score.clear();\r
+ d_waiting_conjectures.clear();\r
+ }\r
+ return addedLemmas;\r
+}\r
+\r
+void ConjectureGenerator::registerQuantifier( Node q ) {\r
+\r
+}\r
+\r
+void ConjectureGenerator::assertNode( Node n ) {\r
+\r
+}\r
+\r
+bool ConjectureGenerator::considerTermCanon( Node ln, bool genRelevant ){\r
+ if( !ln.isNull() ){\r
+ //do not consider if it is non-canonical, and either:\r
+ // (1) we are not generating relevant terms, or\r
+ // (2) its canonical form is a generalization.\r
+ TNode lnr = getUniversalRepresentative( ln, true );\r
+ if( lnr==ln ){\r
+ markReportedCanon( ln );\r
+ }else if( !genRelevant || isGeneralization( lnr, ln ) ){\r
+ Trace("sg-gen-consider-term") << "Do not consider term, " << ln << " is not canonical representation (which is " << lnr << ")." << std::endl;\r
+ return false;\r
+ }\r
+ }\r
+ Trace("sg-gen-tg-debug") << "Will consider term canon " << ln << std::endl;\r
+ Trace("sg-gen-consider-term-debug") << std::endl;\r
+ return true;\r
+}\r
+\r
+unsigned ConjectureGenerator::collectFunctions( TNode opat, TNode pat, std::map< TNode, unsigned >& funcs,\r
+ std::map< TypeNode, unsigned >& mnvn, std::map< TypeNode, unsigned >& mxvn ){\r
+ if( pat.hasOperator() ){\r
+ funcs[pat.getOperator()]++;\r
+ if( !d_tge.isRelevantFunc( pat.getOperator() ) ){\r
+ d_pattern_is_relevant[opat] = false;\r
+ }\r
+ unsigned sum = 1;\r
+ for( unsigned i=0; i<pat.getNumChildren(); i++ ){\r
+ sum += collectFunctions( opat, pat[i], funcs, mnvn, mxvn );\r
+ }\r
+ return sum;\r
+ }else{\r
+ Assert( pat.getNumChildren()==0 );\r
+ funcs[pat]++;\r
+ //for variables\r
+ if( pat.getKind()==BOUND_VARIABLE ){\r
+ if( funcs[pat]>1 ){\r
+ //duplicate variable\r
+ d_pattern_var_duplicate[opat]++;\r
+ }else{\r
+ //check for max/min\r
+ TypeNode tn = pat.getType();\r
+ unsigned vn = d_free_var_num[pat];\r
+ std::map< TypeNode, unsigned >::iterator it = mnvn.find( tn );\r
+ if( it!=mnvn.end() ){\r
+ if( vn<it->second ){\r
+ d_pattern_is_normal[opat] = false;\r
+ mnvn[tn] = vn;\r
+ }else if( vn>mxvn[tn] ){\r
+ if( vn!=mxvn[tn]+1 ){\r
+ d_pattern_is_normal[opat] = false;\r
+ }\r
+ mxvn[tn] = vn;\r
+ }\r
+ }else{\r
+ //first variable of this type\r
+ mnvn[tn] = vn;\r
+ mxvn[tn] = vn;\r
+ }\r
+ }\r
+ }else{\r
+ d_pattern_is_relevant[opat] = false;\r
+ }\r
+ return 1;\r
+ }\r
+}\r
+\r
+void ConjectureGenerator::registerPattern( Node pat, TypeNode tpat ) {\r
+ if( std::find( d_patterns[tpat].begin(), d_patterns[tpat].end(), pat )==d_patterns[tpat].end() ){\r
+ d_patterns[TypeNode::null()].push_back( pat );\r
+ d_patterns[tpat].push_back( pat );\r
+\r
+ Assert( d_pattern_fun_id.find( pat )==d_pattern_fun_id.end() );\r
+ Assert( d_pattern_var_id.find( pat )==d_pattern_var_id.end() );\r
+\r
+ //collect functions\r
+ std::map< TypeNode, unsigned > mnvn;\r
+ d_pattern_fun_sum[pat] = collectFunctions( pat, pat, d_pattern_fun_id[pat], mnvn, d_pattern_var_id[pat] );\r
+ if( d_pattern_is_normal.find( pat )==d_pattern_is_normal.end() ){\r
+ d_pattern_is_normal[pat] = true;\r
+ }\r
+ if( d_pattern_is_relevant.find( pat )==d_pattern_is_relevant.end() ){\r
+ d_pattern_is_relevant[pat] = true;\r
+ }\r
+ }\r
+}\r
+\r
+bool ConjectureGenerator::isGeneralization( TNode patg, TNode pat, std::map< TNode, TNode >& subs ) {\r
+ if( patg.getKind()==BOUND_VARIABLE ){\r
+ std::map< TNode, TNode >::iterator it = subs.find( patg );\r
+ if( it!=subs.end() ){\r
+ return it->second==pat;\r
+ }else{\r
+ subs[patg] = pat;\r
+ return true;\r
+ }\r
+ }else{\r
+ Assert( patg.hasOperator() );\r
+ if( !pat.hasOperator() || patg.getOperator()!=pat.getOperator() ){\r
+ return false;\r
+ }else{\r
+ Assert( patg.getNumChildren()==pat.getNumChildren() );\r
+ for( unsigned i=0; i<patg.getNumChildren(); i++ ){\r
+ if( !isGeneralization( patg[i], pat[i], subs ) ){\r
+ return false;\r
+ }\r
+ }\r
+ return true;\r
+ }\r
+ }\r
+}\r
+\r
+int ConjectureGenerator::calculateGeneralizationDepth( TNode n, std::vector< TNode >& fv ) {\r
+ if( n.getKind()==BOUND_VARIABLE ){\r
+ if( std::find( fv.begin(), fv.end(), n )==fv.end() ){\r
+ fv.push_back( n );\r
+ return 0;\r
+ }else{\r
+ return 1;\r
+ }\r
+ }else{\r
+ int depth = 1;\r
+ for( unsigned i=0; i<n.getNumChildren(); i++ ){\r
+ depth += calculateGeneralizationDepth( n[i], fv );\r
+ }\r
+ return depth;\r
+ }\r
+}\r
+\r
+Node ConjectureGenerator::getPredicateForType( TypeNode tn ) {\r
+ std::map< TypeNode, Node >::iterator it = d_typ_pred.find( tn );\r
+ if( it==d_typ_pred.end() ){\r
+ TypeNode op_tn = NodeManager::currentNM()->mkFunctionType( tn, NodeManager::currentNM()->booleanType() );\r
+ Node op = NodeManager::currentNM()->mkSkolem( "PE", op_tn, "was created by conjecture ground term enumerator." );\r
+ d_typ_pred[tn] = op;\r
+ return op;\r
+ }else{\r
+ return it->second;\r
+ }\r
+}\r
+\r
+void ConjectureGenerator::getEnumerateUfTerm( Node n, unsigned num, std::vector< Node >& terms ) {\r
+ if( n.getNumChildren()>0 ){\r
+ std::vector< int > vec;\r
+ for( unsigned i=0; i<n.getNumChildren(); i++ ){\r
+ vec.push_back( 0 );\r
+ }\r
+ vec.pop_back();\r
+ int size_limit = 0;\r
+ int vec_sum = -1;\r
+ unsigned index = 0;\r
+ unsigned last_size = terms.size();\r
+ while( terms.size()<num ){\r
+ bool success = true;\r
+ if( vec_sum==-1 ){\r
+ vec_sum = 0;\r
+ vec.push_back( size_limit );\r
+ }else{\r
+ //see if we can iterate current\r
+ if( vec_sum<size_limit && !getTermDatabase()->getEnumerateTerm( n[index].getType(), vec[index]+1 ).isNull() ){\r
+ vec[index]++;\r
+ vec_sum++;\r
+ vec.push_back( size_limit - vec_sum );\r
+ }else{\r
+ vec_sum -= vec[index];\r
+ vec[index] = 0;\r
+ index++;\r
+ if( index==n.getNumChildren() ){\r
+ success = false;\r
+ }\r
+ }\r
+ }\r
+ if( success ){\r
+ if( vec.size()==n.getNumChildren() ){\r
+ Node lc = getTermDatabase()->getEnumerateTerm( n[vec.size()-1].getType(), vec[vec.size()-1] );\r
+ if( !lc.isNull() ){\r
+ for( unsigned i=0; i<vec.size(); i++ ){\r
+ Trace("sg-gt-enum-debug") << vec[i] << " ";\r
+ }\r
+ Trace("sg-gt-enum-debug") << " / " << size_limit << std::endl;\r
+ for( unsigned i=0; i<n.getNumChildren(); i++ ){\r
+ Trace("sg-gt-enum-debug") << n[i].getType() << " ";\r
+ }\r
+ Trace("sg-gt-enum-debug") << std::endl;\r
+ std::vector< Node > children;\r
+ children.push_back( n.getOperator() );\r
+ for( unsigned i=0; i<(vec.size()-1); i++ ){\r
+ Node nn = getTermDatabase()->getEnumerateTerm( n[i].getType(), vec[i] );\r
+ Assert( !nn.isNull() );\r
+ Assert( nn.getType()==n[i].getType() );\r
+ children.push_back( nn );\r
+ }\r
+ children.push_back( lc );\r
+ Node n = NodeManager::currentNM()->mkNode( APPLY_UF, children );\r
+ Trace("sg-gt-enum") << "Ground term enumerate : " << n << std::endl;\r
+ terms.push_back( n );\r
+ }\r
+ vec.pop_back();\r
+ index = 0;\r
+ }\r
+ }else{\r
+ if( terms.size()>last_size ){\r
+ last_size = terms.size();\r
+ size_limit++;\r
+ for( unsigned i=0; i<vec.size(); i++ ){\r
+ vec[i] = 0;\r
+ }\r
+ vec_sum = -1;\r
+ }\r
+ }\r
+ }\r
+ }else{\r
+ terms.push_back( n );\r
+ }\r
+}\r
+\r
+void ConjectureGenerator::getEnumeratePredUfTerm( Node n, unsigned num, std::vector< Node >& terms ) {\r
+ std::vector< Node > uf_terms;\r
+ getEnumerateUfTerm( n, num, uf_terms );\r
+ Node p = getPredicateForType( n.getType() );\r
+ for( unsigned i=0; i<uf_terms.size(); i++ ){\r
+ terms.push_back( NodeManager::currentNM()->mkNode( APPLY_UF, p, uf_terms[i] ) );\r
+ }\r
+}\r
+\r
+void ConjectureGenerator::processCandidateConjecture( TNode lhs, TNode rhs, unsigned lhs_depth, unsigned rhs_depth ) {\r
+ int score = considerCandidateConjecture( lhs, rhs );\r
+ if( score>0 ){\r
+ Trace("sg-conjecture") << "* Candidate conjecture : " << lhs << " == " << rhs << std::endl;\r
+ Trace("sg-conjecture-debug") << " LHS, RHS generalization depth : " << lhs_depth << ", " << rhs_depth << std::endl;\r
+ Trace("sg-conjecture-debug") << " confirmed = " << d_subs_confirmCount << ", #witnesses range = " << d_subs_confirmWitnessRange.size() << "." << std::endl;\r
+ Trace("sg-conjecture-debug") << " #witnesses for ";\r
+ bool firstTime = true;\r
+ for( std::map< TNode, std::vector< TNode > >::iterator it = d_subs_confirmWitnessDomain.begin(); it != d_subs_confirmWitnessDomain.end(); ++it ){\r
+ if( !firstTime ){\r
+ Trace("sg-conjecture-debug") << ", ";\r
+ }\r
+ Trace("sg-conjecture-debug") << it->first << " : " << it->second.size();\r
+ //if( it->second.size()==1 ){\r
+ // Trace("sg-conjecture-debug") << " (" << it->second[0] << ")";\r
+ //}\r
+ Trace("sg-conjecture-debug2") << " (";\r
+ for( unsigned j=0; j<it->second.size(); j++ ){\r
+ if( j>0 ){ Trace("sg-conjecture-debug2") << " "; }\r
+ Trace("sg-conjecture-debug2") << d_ground_eqc_map[it->second[j]];\r
+ }\r
+ Trace("sg-conjecture-debug2") << ")";\r
+ firstTime = false;\r
+ }\r
+ Trace("sg-conjecture-debug") << std::endl;\r
+ Trace("sg-conjecture-debug") << " unknown = " << d_subs_unkCount << std::endl;\r
+ //Assert( getUniversalRepresentative( rhs )==rhs );\r
+ //Assert( getUniversalRepresentative( lhs )==lhs );\r
+ d_waiting_conjectures_lhs.push_back( lhs );\r
+ d_waiting_conjectures_rhs.push_back( rhs );\r
+ d_waiting_conjectures_score.push_back( score );\r
+ d_waiting_conjectures[lhs].push_back( rhs );\r
+ d_waiting_conjectures[rhs].push_back( lhs );\r
+ }\r
+}\r
+\r
+int ConjectureGenerator::considerCandidateConjecture( TNode lhs, TNode rhs ) {\r
+ Assert( lhs.getType()==rhs.getType() );\r
+\r
+ Trace("sg-cconj-debug") << "Consider candidate conjecture : " << lhs << " == " << rhs << "?" << std::endl;\r
+ if( lhs==rhs ){\r
+ Trace("sg-cconj-debug") << " -> trivial." << std::endl;\r
+ return -1;\r
+ }else{\r
+ if( lhs.getKind()==APPLY_CONSTRUCTOR && rhs.getKind()==APPLY_CONSTRUCTOR ){\r
+ Trace("sg-cconj-debug") << " -> irrelevant by syntactic analysis." << std::endl;\r
+ return -1;\r
+ }\r
+ //variables of LHS must subsume variables of RHS\r
+ for( std::map< TypeNode, unsigned >::iterator it = d_pattern_var_id[rhs].begin(); it != d_pattern_var_id[rhs].end(); ++it ){\r
+ std::map< TypeNode, unsigned >::iterator itl = d_pattern_var_id[lhs].find( it->first );\r
+ if( itl!=d_pattern_var_id[lhs].end() ){\r
+ if( itl->second<it->second ){\r
+ Trace("sg-cconj-debug") << " -> variables of sort " << it->first << " are not subsumed." << std::endl;\r
+ return -1;\r
+ }else{\r
+ Trace("sg-cconj-debug2") << " variables of sort " << it->first << " are : " << itl->second << " vs " << it->second << std::endl;\r
+ }\r
+ }else{\r
+ Trace("sg-cconj-debug") << " -> has no variables of sort " << it->first << "." << std::endl;\r
+ return -1;\r
+ }\r
+ }\r
+\r
+ //currently active conjecture?\r
+ std::map< Node, std::vector< Node > >::iterator iteq = d_eq_conjectures.find( lhs );\r
+ if( iteq!=d_eq_conjectures.end() ){\r
+ if( std::find( iteq->second.begin(), iteq->second.end(), rhs )!=iteq->second.end() ){\r
+ Trace("sg-cconj-debug") << " -> this conjecture is already active." << std::endl;\r
+ return -1;\r
+ }\r
+ }\r
+ //current a waiting conjecture?\r
+ std::map< Node, std::vector< Node > >::iterator itw = d_waiting_conjectures.find( lhs );\r
+ if( itw!=d_waiting_conjectures.end() ){\r
+ if( std::find( itw->second.begin(), itw->second.end(), rhs )!=itw->second.end() ){\r
+ Trace("sg-cconj-debug") << " -> already are considering this conjecture." << std::endl;\r
+ return -1;\r
+ }\r
+ }\r
+ //check if canonical representation (should be, but for efficiency this is not guarenteed)\r
+ //if( options::conjectureFilterCanonical() && ( getUniversalRepresentative( lhs )!=lhs || getUniversalRepresentative( rhs )!=rhs ) ){\r
+ // Trace("sg-cconj") << " -> after processing, not canonical." << std::endl;\r
+ // return -1;\r
+ //}\r
+\r
+ int score;\r
+ bool scoreSet = false;\r
+\r
+ Trace("sg-cconj") << "Consider possible candidate conjecture : " << lhs << " == " << rhs << "?" << std::endl;\r
+ //find witness for counterexample, if possible\r
+ if( options::conjectureFilterModel() ){\r
+ Assert( d_rel_pattern_var_sum.find( lhs )!=d_rel_pattern_var_sum.end() );\r
+ Trace("sg-cconj-debug") << "Notify substitutions over " << d_rel_pattern_var_sum[lhs] << " variables." << std::endl;\r
+ std::map< TNode, TNode > subs;\r
+ d_subs_confirmCount = 0;\r
+ d_subs_confirmWitnessRange.clear();\r
+ d_subs_confirmWitnessDomain.clear();\r
+ d_subs_unkCount = 0;\r
+ if( !d_rel_pattern_subs_index[lhs].notifySubstitutions( this, subs, rhs, d_rel_pattern_var_sum[lhs] ) ){\r
+ Trace("sg-cconj") << " -> found witness that falsifies the conjecture." << std::endl;\r
+ return -1;\r
+ }\r
+ //score is the minimum number of distinct substitutions for a variable\r
+ for( std::map< TNode, std::vector< TNode > >::iterator it = d_subs_confirmWitnessDomain.begin(); it != d_subs_confirmWitnessDomain.end(); ++it ){\r
+ int num = (int)it->second.size();\r
+ if( !scoreSet || num<score ){\r
+ score = num;\r
+ scoreSet = true;\r
+ }\r
+ }\r
+ if( !scoreSet ){\r
+ score = 0;\r
+ }\r
+ Trace("sg-cconj") << " confirmed = " << d_subs_confirmCount << ", #witnesses range = " << d_subs_confirmWitnessRange.size() << "." << std::endl;\r
+ for( std::map< TNode, std::vector< TNode > >::iterator it = d_subs_confirmWitnessDomain.begin(); it != d_subs_confirmWitnessDomain.end(); ++it ){\r
+ Trace("sg-cconj") << " #witnesses for " << it->first << " : " << it->second.size() << std::endl;\r
+ }\r
+ }else{\r
+ score = 0;\r
+ }\r
+\r
+ Trace("sg-cconj") << " -> SUCCESS." << std::endl;\r
+ Trace("sg-cconj") << " score : " << score << std::endl;\r
+\r
+ return score;\r
+ }\r
+}\r
+\r
+bool ConjectureGenerator::notifySubstitution( TNode glhs, std::map< TNode, TNode >& subs, TNode rhs ) {\r
+ if( Trace.isOn("sg-cconj-debug") ){\r
+ Trace("sg-cconj-debug") << "Ground eqc for LHS : " << glhs << ", based on substituion: " << std::endl;\r
+ for( std::map< TNode, TNode >::iterator it = subs.begin(); it != subs.end(); ++it ){\r
+ Assert( getRepresentative( it->second )==it->second );\r
+ Trace("sg-cconj-debug") << " " << it->first << " -> " << it->second << std::endl;\r
+ }\r
+ }\r
+ Trace("sg-cconj-debug") << "Evaluate RHS : : " << rhs << std::endl;\r
+ //get the representative of rhs with substitution subs\r
+ TNode grhs = getTermDatabase()->evaluateTerm( rhs, subs, true );\r
+ Trace("sg-cconj-debug") << "...done evaluating term, got : " << grhs << std::endl;\r
+ if( !grhs.isNull() ){\r
+ if( glhs!=grhs ){\r
+ Trace("sg-cconj-debug") << "Ground eqc for RHS : " << grhs << std::endl;\r
+ //check based on ground terms\r
+ std::map< TNode, Node >::iterator itl = d_ground_eqc_map.find( glhs );\r
+ if( itl!=d_ground_eqc_map.end() ){\r
+ std::map< TNode, Node >::iterator itr = d_ground_eqc_map.find( grhs );\r
+ if( itr!=d_ground_eqc_map.end() ){\r
+ Trace("sg-cconj-debug") << "We have ground terms " << itl->second << " and " << itr->second << "." << std::endl;\r
+ if( itl->second.isConst() && itr->second.isConst() ){\r
+ Trace("sg-cconj-debug") << "...disequal constants." << std::endl;\r
+ Trace("sg-cconj-witness") << " Witness of falsification : " << itl->second << " != " << itr->second << ", substutition is : " << std::endl;\r
+ for( std::map< TNode, TNode >::iterator it = subs.begin(); it != subs.end(); ++it ){\r
+ Trace("sg-cconj-witness") << " " << it->first << " -> " << it->second << std::endl;\r
+ }\r
+ return false;\r
+ }\r
+ }\r
+ }\r
+ }\r
+ Trace("sg-cconj-debug") << "RHS is identical." << std::endl;\r
+ bool isGroundSubs = true;\r
+ for( std::map< TNode, TNode >::iterator it = subs.begin(); it != subs.end(); ++it ){\r
+ std::map< TNode, Node >::iterator git = d_ground_eqc_map.find( it->second );\r
+ if( git==d_ground_eqc_map.end() ){\r
+ isGroundSubs = false;\r
+ break;\r
+ }\r
+ }\r
+ if( isGroundSubs ){\r
+ if( glhs==grhs ){\r
+ Trace("sg-cconj-witness") << " Witnessed " << glhs << " == " << grhs << ", substutition is : " << std::endl;\r
+ for( std::map< TNode, TNode >::iterator it = subs.begin(); it != subs.end(); ++it ){\r
+ Trace("sg-cconj-witness") << " " << it->first << " -> " << it->second << std::endl;\r
+ if( std::find( d_subs_confirmWitnessDomain[it->first].begin(), d_subs_confirmWitnessDomain[it->first].end(), it->second )==d_subs_confirmWitnessDomain[it->first].end() ){\r
+ d_subs_confirmWitnessDomain[it->first].push_back( it->second );\r
+ }\r
+ }\r
+ d_subs_confirmCount++;\r
+ if( std::find( d_subs_confirmWitnessRange.begin(), d_subs_confirmWitnessRange.end(), glhs )==d_subs_confirmWitnessRange.end() ){\r
+ d_subs_confirmWitnessRange.push_back( glhs );\r
+ }\r
+ }else{\r
+ if( optFilterUnknown() ){\r
+ Trace("sg-cconj-debug") << "...ground substitution giving terms that are neither equal nor disequal." << std::endl;\r
+ return false;\r
+ }\r
+ }\r
+ }\r
+ }else{\r
+ Trace("sg-cconj-debug") << "(could not ground eqc for RHS)." << std::endl;\r
+ }\r
+ return true;\r
+}\r
+\r
+\r
+\r
+\r
+\r
+\r
+void TermGenerator::reset( TermGenEnv * s, TypeNode tn ) {\r
+ Assert( d_children.empty() );\r
+ d_typ = tn;\r
+ d_status = 0;\r
+ d_status_num = 0;\r
+ d_children.clear();\r
+ Trace("sg-gen-tg-debug2") << "...add to context " << this << std::endl;\r
+ d_id = s->d_tg_id;\r
+ s->changeContext( true );\r
+}\r
+\r
+bool TermGenerator::getNextTerm( TermGenEnv * s, unsigned depth ) {\r
+ if( Trace.isOn("sg-gen-tg-debug2") ){\r
+ Trace("sg-gen-tg-debug2") << this << " getNextTerm depth " << depth << " : status = " << d_status << ", num = " << d_status_num;\r
+ if( d_status==5 ){\r
+ TNode f = s->getTgFunc( d_typ, d_status_num );\r
+ Trace("sg-gen-tg-debug2") << ", f = " << f;\r
+ Trace("sg-gen-tg-debug2") << ", #args = " << s->d_func_args[f].size();\r
+ Trace("sg-gen-tg-debug2") << ", childNum = " << d_status_child_num;\r
+ Trace("sg-gen-tg-debug2") << ", #children = " << d_children.size();\r
+ }\r
+ Trace("sg-gen-tg-debug2") << std::endl;\r
+ }\r
+\r
+ if( d_status==0 ){\r
+ d_status++;\r
+ if( !d_typ.isNull() ){\r
+ if( s->allowVar( d_typ ) ){\r
+ //allocate variable\r
+ d_status_num = s->d_var_id[d_typ];\r
+ s->addVar( d_typ );\r
+ Trace("sg-gen-tg-debug2") << this << " ...return unique var #" << d_status_num << std::endl;\r
+ return s->considerCurrentTerm() ? true : getNextTerm( s, depth );\r
+ }else{\r
+ //check allocating new variable\r
+ d_status++;\r
+ d_status_num = -1;\r
+ if( s->d_gen_relevant_terms ){\r
+ s->d_tg_gdepth++;\r
+ }\r
+ return getNextTerm( s, depth );\r
+ }\r
+ }else{\r
+ d_status = 4;\r
+ d_status_num = -1;\r
+ return getNextTerm( s, depth );\r
+ }\r
+ }else if( d_status==2 ){\r
+ //cleanup previous information\r
+ //if( d_status_num>=0 ){\r
+ // s->d_var_eq_tg[d_status_num].pop_back();\r
+ //}\r
+ //check if there is another variable\r
+ if( (d_status_num+1)<(int)s->getNumTgVars( d_typ ) ){\r
+ d_status_num++;\r
+ //we have equated two variables\r
+ //s->d_var_eq_tg[d_status_num].push_back( d_id );\r
+ Trace("sg-gen-tg-debug2") << this << "...consider other var #" << d_status_num << std::endl;\r
+ return s->considerCurrentTerm() ? true : getNextTerm( s, depth );\r
+ }else{\r
+ if( s->d_gen_relevant_terms ){\r
+ s->d_tg_gdepth--;\r
+ }\r
+ d_status++;\r
+ return getNextTerm( s, depth );\r
+ }\r
+ }else if( d_status==4 ){\r
+ d_status++;\r
+ if( depth>0 && (d_status_num+1)<(int)s->getNumTgFuncs( d_typ ) ){\r
+ d_status_num++;\r
+ d_status_child_num = 0;\r
+ Trace("sg-gen-tg-debug2") << this << "...consider function " << s->getTgFunc( d_typ, d_status_num ) << std::endl;\r
+ s->d_tg_gdepth++;\r
+ if( !s->considerCurrentTerm() ){\r
+ s->d_tg_gdepth--;\r
+ //don't consider this function\r
+ d_status--;\r
+ }else{\r
+ //we have decided on a function application\r
+ }\r
+ return getNextTerm( s, depth );\r
+ }else{\r
+ //do not choose function applications at depth 0\r
+ d_status++;\r
+ return getNextTerm( s, depth );\r
+ }\r
+ }else if( d_status==5 ){\r
+ //iterating over arguments\r
+ TNode f = s->getTgFunc( d_typ, d_status_num );\r
+ if( d_status_child_num<0 ){\r
+ //no more arguments\r
+ s->d_tg_gdepth--;\r
+ d_status--;\r
+ return getNextTerm( s, depth );\r
+ }else if( d_status_child_num==(int)s->d_func_args[f].size() ){\r
+ d_status_child_num--;\r
+ return s->considerCurrentTermCanon( d_id ) ? true : getNextTerm( s, depth );\r
+ //return true;\r
+ }else{\r
+ Assert( d_status_child_num<(int)s->d_func_args[f].size() );\r
+ if( d_status_child_num==(int)d_children.size() ){\r
+ d_children.push_back( s->d_tg_id );\r
+ Assert( s->d_tg_alloc.find( s->d_tg_id )==s->d_tg_alloc.end() );\r
+ s->d_tg_alloc[d_children[d_status_child_num]].reset( s, s->d_func_args[f][d_status_child_num] );\r
+ return getNextTerm( s, depth );\r
+ }else{\r
+ Assert( d_status_child_num+1==(int)d_children.size() );\r
+ if( s->d_tg_alloc[d_children[d_status_child_num]].getNextTerm( s, depth-1 ) ){\r
+ d_status_child_num++;\r
+ return getNextTerm( s, depth );\r
+ }else{\r
+ d_children.pop_back();\r
+ d_status_child_num--;\r
+ return getNextTerm( s, depth );\r
+ }\r
+ }\r
+ }\r
+ }else if( d_status==1 || d_status==3 ){\r
+ if( d_status==1 ){\r
+ s->removeVar( d_typ );\r
+ Assert( d_status_num==(int)s->d_var_id[d_typ] );\r
+ //check if there is only one feasible equivalence class. if so, don't make pattern any more specific.\r
+ //unsigned i = s->d_ccand_eqc[0].size()-1;\r
+ //if( s->d_ccand_eqc[0][i].size()==1 && s->d_ccand_eqc[1][i].empty() ){\r
+ // d_status = 6;\r
+ // return getNextTerm( s, depth );\r
+ //}\r
+ s->d_tg_gdepth++;\r
+ }\r
+ d_status++;\r
+ d_status_num = -1;\r
+ return getNextTerm( s, depth );\r
+ }else{\r
+ //clean up\r
+ Assert( d_children.empty() );\r
+ Trace("sg-gen-tg-debug2") << "...remove from context " << this << std::endl;\r
+ s->changeContext( false );\r
+ Assert( d_id==s->d_tg_id );\r
+ return false;\r
+ }\r
+}\r
+\r
+void TermGenerator::resetMatching( TermGenEnv * s, TNode eqc, unsigned mode ) {\r
+ d_match_status = 0;\r
+ d_match_status_child_num = 0;\r
+ d_match_children.clear();\r
+ d_match_children_end.clear();\r
+ d_match_mode = mode;\r
+ //if this term generalizes, it must generalize a non-ground term\r
+ //if( (d_match_mode & ( 1 << 2 ))!=0 && s->isGroundEqc( eqc ) && d_status==5 ){\r
+ // d_match_status = -1;\r
+ //}\r
+}\r
+\r
+bool TermGenerator::getNextMatch( TermGenEnv * s, TNode eqc, std::map< TypeNode, std::map< unsigned, TNode > >& subs, std::map< TNode, bool >& rev_subs ) {\r
+ if( d_match_status<0 ){\r
+ return false;\r
+ }\r
+ if( Trace.isOn("sg-gen-tg-match") ){\r
+ Trace("sg-gen-tg-match") << "Matching ";\r
+ debugPrint( s, "sg-gen-tg-match", "sg-gen-tg-match" );\r
+ Trace("sg-gen-tg-match") << " with eqc e" << s->d_cg->d_em[eqc] << "..." << std::endl;\r
+ Trace("sg-gen-tg-match") << " mstatus = " << d_match_status;\r
+ if( d_status==5 ){\r
+ TNode f = s->getTgFunc( d_typ, d_status_num );\r
+ Trace("sg-gen-tg-debug2") << ", f = " << f;\r
+ Trace("sg-gen-tg-debug2") << ", #args = " << s->d_func_args[f].size();\r
+ Trace("sg-gen-tg-debug2") << ", mchildNum = " << d_match_status_child_num;\r
+ Trace("sg-gen-tg-debug2") << ", #mchildren = " << d_match_children.size();\r
+ }\r
+ Trace("sg-gen-tg-debug2") << ", current substitution : {";\r
+ for( std::map< TypeNode, std::map< unsigned, TNode > >::iterator itt = subs.begin(); itt != subs.end(); ++itt ){\r
+ for( std::map< unsigned, TNode >::iterator it = itt->second.begin(); it != itt->second.end(); ++it ){\r
+ Trace("sg-gen-tg-debug2") << " " << it->first << " -> e" << s->d_cg->d_em[it->second];\r
+ }\r
+ }\r
+ Trace("sg-gen-tg-debug2") << " } " << std::endl;\r
+ }\r
+ if( d_status==1 ){\r
+ //a variable\r
+ if( d_match_status==0 ){\r
+ d_match_status++;\r
+ if( (d_match_mode & ( 1 << 1 ))!=0 ){\r
+ //only ground terms\r
+ if( !s->isGroundEqc( eqc ) ){\r
+ return false;\r
+ }\r
+ }else if( (d_match_mode & ( 1 << 2 ))!=0 ){\r
+ //only non-ground terms\r
+ //if( s->isGroundEqc( eqc ) ){\r
+ // return false;\r
+ //}\r
+ }\r
+ //store the match : restricted if match_mode.0 = 1\r
+ if( (d_match_mode & ( 1 << 0 ))!=0 ){\r
+ std::map< TNode, bool >::iterator it = rev_subs.find( eqc );\r
+ if( it==rev_subs.end() ){\r
+ rev_subs[eqc] = true;\r
+ }else{\r
+ return false;\r
+ }\r
+ }\r
+ Assert( subs[d_typ].find( d_status_num )==subs[d_typ].end() );\r
+ subs[d_typ][d_status_num] = eqc;\r
+ return true;\r
+ }else{\r
+ //clean up\r
+ subs[d_typ].erase( d_status_num );\r
+ if( (d_match_mode & ( 1 << 0 ))!=0 ){\r
+ rev_subs.erase( eqc );\r
+ }\r
+ return false;\r
+ }\r
+ }else if( d_status==2 ){\r
+ if( d_match_status==0 ){\r
+ d_match_status++;\r
+ Assert( d_status_num<(int)s->getNumTgVars( d_typ ) );\r
+ std::map< unsigned, TNode >::iterator it = subs[d_typ].find( d_status_num );\r
+ Assert( it!=subs[d_typ].end() );\r
+ return it->second==eqc;\r
+ }else{\r
+ return false;\r
+ }\r
+ }else if( d_status==5 ){\r
+ //Assert( d_match_children.size()<=d_children.size() );\r
+ //enumerating over f-applications in eqc\r
+ if( d_match_status_child_num<0 ){\r
+ return false;\r
+ }else if( d_match_status==0 ){\r
+ //set up next binding\r
+ if( d_match_status_child_num==(int)d_match_children.size() ){\r
+ if( d_match_status_child_num==0 ){\r
+ //initial binding\r
+ TNode f = s->getTgFunc( d_typ, d_status_num );\r
+ std::map< TNode, TermArgTrie >::iterator it = s->getTermDatabase()->d_func_map_eqc_trie[f].d_data.find( eqc );\r
+ if( it!=s->getTermDatabase()->d_func_map_eqc_trie[f].d_data.end() ){\r
+ d_match_children.push_back( it->second.d_data.begin() );\r
+ d_match_children_end.push_back( it->second.d_data.end() );\r
+ }else{\r
+ d_match_status++;\r
+ d_match_status_child_num--;\r
+ return getNextMatch( s, eqc, subs, rev_subs );\r
+ }\r
+ }else{\r
+ d_match_children.push_back( d_match_children[d_match_status_child_num-1]->second.d_data.begin() );\r
+ d_match_children_end.push_back( d_match_children[d_match_status_child_num-1]->second.d_data.end() );\r
+ }\r
+ }\r
+ d_match_status++;\r
+ Assert( d_match_status_child_num+1==(int)d_match_children.size() );\r
+ if( d_match_children[d_match_status_child_num]==d_match_children_end[d_match_status_child_num] ){\r
+ //no more arguments to bind\r
+ d_match_children.pop_back();\r
+ d_match_children_end.pop_back();\r
+ d_match_status_child_num--;\r
+ return getNextMatch( s, eqc, subs, rev_subs );\r
+ }else{\r
+ if( d_match_status_child_num==(int)d_children.size() ){\r
+ //successfully matched all children\r
+ d_match_children.pop_back();\r
+ d_match_children_end.pop_back();\r
+ d_match_status_child_num--;\r
+ return true;//return d_match_children[d_match_status]!=d_match_children_end[d_match_status];\r
+ }else{\r
+ //do next binding\r
+ 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 );\r
+ return getNextMatch( s, eqc, subs, rev_subs );\r
+ }\r
+ }\r
+ }else{\r
+ Assert( d_match_status==1 );\r
+ Assert( d_match_status_child_num+1==(int)d_match_children.size() );\r
+ Assert( d_match_children[d_match_status_child_num]!=d_match_children_end[d_match_status_child_num] );\r
+ d_match_status--;\r
+ 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 ) ){\r
+ d_match_status_child_num++;\r
+ return getNextMatch( s, eqc, subs, rev_subs );\r
+ }else{\r
+ //iterate\r
+ d_match_children[d_match_status_child_num]++;\r
+ return getNextMatch( s, eqc, subs, rev_subs );\r
+ }\r
+ }\r
+ }\r
+ Assert( false );\r
+ return false;\r
+}\r
+\r
+unsigned TermGenerator::getDepth( TermGenEnv * s ) {\r
+ if( d_status==5 ){\r
+ unsigned maxd = 0;\r
+ for( unsigned i=0; i<d_children.size(); i++ ){\r
+ unsigned d = s->d_tg_alloc[d_children[i]].getDepth( s );\r
+ if( d>maxd ){\r
+ maxd = d;\r
+ }\r
+ }\r
+ return 1+maxd;\r
+ }else{\r
+ return 0;\r
+ }\r
+}\r
+\r
+unsigned TermGenerator::calculateGeneralizationDepth( TermGenEnv * s, std::map< TypeNode, std::vector< int > >& fvs ) {\r
+ if( d_status==5 ){\r
+ unsigned sum = 1;\r
+ for( unsigned i=0; i<d_children.size(); i++ ){\r
+ sum += s->d_tg_alloc[d_children[i]].calculateGeneralizationDepth( s, fvs );\r
+ }\r
+ return sum;\r
+ }else{\r
+ Assert( d_status==2 || d_status==1 );\r
+ std::map< TypeNode, std::vector< int > >::iterator it = fvs.find( d_typ );\r
+ if( it!=fvs.end() ){\r
+ if( std::find( it->second.begin(), it->second.end(), d_status_num )!=it->second.end() ){\r
+ return 1;\r
+ }\r
+ }\r
+ fvs[d_typ].push_back( d_status_num );\r
+ return 0;\r
+ }\r
+}\r
+\r
+unsigned TermGenerator::getGeneralizationDepth( TermGenEnv * s ) {\r
+ //if( s->d_gen_relevant_terms ){\r
+ // return s->d_tg_gdepth;\r
+ //}else{\r
+ std::map< TypeNode, std::vector< int > > fvs;\r
+ return calculateGeneralizationDepth( s, fvs );\r
+ //}\r
+}\r
+\r
+Node TermGenerator::getTerm( TermGenEnv * s ) {\r
+ if( d_status==1 || d_status==2 ){\r
+ Assert( !d_typ.isNull() );\r
+ return s->getFreeVar( d_typ, d_status_num );\r
+ }else if( d_status==5 ){\r
+ Node f = s->getTgFunc( d_typ, d_status_num );\r
+ if( d_children.size()==s->d_func_args[f].size() ){\r
+ std::vector< Node > children;\r
+ children.push_back( f );\r
+ for( unsigned i=0; i<d_children.size(); i++ ){\r
+ Node nc = s->d_tg_alloc[d_children[i]].getTerm( s );\r
+ if( nc.isNull() ){\r
+ return Node::null();\r
+ }else{\r
+ //Assert( nc.getType()==s->d_func_args[f][i] );\r
+ children.push_back( nc );\r
+ }\r
+ }\r
+ return NodeManager::currentNM()->mkNode( s->d_func_kind[f], children );\r
+ }\r
+ }else{\r
+ Assert( false );\r
+ }\r
+ return Node::null();\r
+}\r
+\r
+void TermGenerator::debugPrint( TermGenEnv * s, const char * c, const char * cd ) {\r
+ Trace(cd) << "[*" << d_id << "," << d_status << "]:";\r
+ if( d_status==1 || d_status==2 ){\r
+ Trace(c) << s->getFreeVar( d_typ, d_status_num );\r
+ }else if( d_status==5 ){\r
+ TNode f = s->getTgFunc( d_typ, d_status_num );\r
+ Trace(c) << "(" << f;\r
+ for( unsigned i=0; i<d_children.size(); i++ ){\r
+ Trace(c) << " ";\r
+ s->d_tg_alloc[d_children[i]].debugPrint( s, c, cd );\r
+ }\r
+ if( d_children.size()<s->d_func_args[f].size() ){\r
+ Trace(c) << " ...";\r
+ }\r
+ Trace(c) << ")";\r
+ }else{\r
+ Trace(c) << "???";\r
+ }\r
+}\r
+\r
+void TermGenEnv::collectSignatureInformation() {\r
+ d_typ_tg_funcs.clear();\r
+ d_funcs.clear();\r
+ d_func_kind.clear();\r
+ d_func_args.clear();\r
+ TypeNode tnull;\r
+ for( std::map< Node, TermArgTrie >::iterator it = getTermDatabase()->d_func_map_trie.begin(); it != getTermDatabase()->d_func_map_trie.end(); ++it ){\r
+ if( !getTermDatabase()->d_op_map[it->first].empty() ){\r
+ Node nn = getTermDatabase()->d_op_map[it->first][0];\r
+ if( d_cg->isHandledTerm( nn ) && nn.getKind()!=APPLY_SELECTOR_TOTAL && !nn.getType().isBoolean() ){\r
+ bool do_enum = true;\r
+ //check if we have enumerated ground terms\r
+ if( nn.getKind()==APPLY_UF ){\r
+ if( !d_cg->hasEnumeratedUf( nn ) ){\r
+ do_enum = false;\r
+ }\r
+ }\r
+ if( do_enum ){\r
+ d_funcs.push_back( it->first );\r
+ for( unsigned i=0; i<nn.getNumChildren(); i++ ){\r
+ d_func_args[it->first].push_back( nn[i].getType() );\r
+ }\r
+ d_func_kind[it->first] = nn.getKind();\r
+ d_typ_tg_funcs[tnull].push_back( it->first );\r
+ d_typ_tg_funcs[nn.getType()].push_back( it->first );\r
+ Trace("sg-rel-sig") << "Will enumerate function applications of : " << it->first << ", #args = " << d_func_args[it->first].size() << ", kind = " << nn.getKind() << std::endl;\r
+ getTermDatabase()->computeUfEqcTerms( it->first );\r
+ }\r
+ }\r
+ }\r
+ }\r
+ //shuffle functions\r
+ for( std::map< TypeNode, std::vector< TNode > >::iterator it = d_typ_tg_funcs.begin(); it != d_typ_tg_funcs.end(); ++it ){\r
+ std::random_shuffle( it->second.begin(), it->second.end() );\r
+ if( it->first.isNull() ){\r
+ Trace("sg-gen-tg-debug") << "In this order : ";\r
+ for( unsigned i=0; i<it->second.size(); i++ ){\r
+ Trace("sg-gen-tg-debug") << it->second[i] << " ";\r
+ }\r
+ Trace("sg-gen-tg-debug") << std::endl;\r
+ }\r
+ }\r
+}\r
+\r
+void TermGenEnv::reset( unsigned depth, bool genRelevant, TypeNode tn ) {\r
+ Assert( d_tg_alloc.empty() );\r
+ d_tg_alloc.clear();\r
+\r
+ if( genRelevant ){\r
+ for( unsigned i=0; i<2; i++ ){\r
+ d_ccand_eqc[i].clear();\r
+ d_ccand_eqc[i].push_back( d_relevant_eqc[i] );\r
+ }\r
+ }\r
+\r
+ d_tg_id = 0;\r
+ d_tg_gdepth = 0;\r
+ d_tg_gdepth_limit = depth;\r
+ d_gen_relevant_terms = genRelevant;\r
+ d_tg_alloc[0].reset( this, tn );\r
+}\r
+\r
+bool TermGenEnv::getNextTerm() {\r
+ if( d_tg_alloc[0].getNextTerm( this, d_tg_gdepth_limit ) ){\r
+ Assert( (int)d_tg_alloc[0].getGeneralizationDepth( this )<=d_tg_gdepth_limit );\r
+ if( (int)d_tg_alloc[0].getGeneralizationDepth( this )!=d_tg_gdepth_limit ){\r
+ return getNextTerm();\r
+ }else{\r
+ return true;\r
+ }\r
+ }else{\r
+ return false;\r
+ }\r
+}\r
+\r
+//reset matching\r
+void TermGenEnv::resetMatching( TNode eqc, unsigned mode ) {\r
+ d_tg_alloc[0].resetMatching( this, eqc, mode );\r
+}\r
+\r
+//get next match\r
+bool TermGenEnv::getNextMatch( TNode eqc, std::map< TypeNode, std::map< unsigned, TNode > >& subs, std::map< TNode, bool >& rev_subs ) {\r
+ return d_tg_alloc[0].getNextMatch( this, eqc, subs, rev_subs );\r
+}\r
+\r
+//get term\r
+Node TermGenEnv::getTerm() {\r
+ return d_tg_alloc[0].getTerm( this );\r
+}\r
+\r
+void TermGenEnv::debugPrint( const char * c, const char * cd ) {\r
+ d_tg_alloc[0].debugPrint( this, c, cd );\r
+}\r
+\r
+unsigned TermGenEnv::getNumTgVars( TypeNode tn ) {\r
+ return d_var_id[tn];\r
+}\r
+\r
+bool TermGenEnv::allowVar( TypeNode tn ) {\r
+ std::map< TypeNode, unsigned >::iterator it = d_var_limit.find( tn );\r
+ if( it==d_var_limit.end() ){\r
+ return true;\r
+ }else{\r
+ return d_var_id[tn]<it->second;\r
+ }\r
+}\r
+\r
+void TermGenEnv::addVar( TypeNode tn ) {\r
+ d_var_id[tn]++;\r
+}\r
+\r
+void TermGenEnv::removeVar( TypeNode tn ) {\r
+ d_var_id[tn]--;\r
+ //d_var_eq_tg.pop_back();\r
+ //d_var_tg.pop_back();\r
+}\r
+\r
+unsigned TermGenEnv::getNumTgFuncs( TypeNode tn ) {\r
+ return d_typ_tg_funcs[tn].size();\r
+}\r
+\r
+TNode TermGenEnv::getTgFunc( TypeNode tn, unsigned i ) {\r
+ return d_typ_tg_funcs[tn][i];\r
+}\r
+\r
+Node TermGenEnv::getFreeVar( TypeNode tn, unsigned i ) {\r
+ return d_cg->getFreeVar( tn, i );\r
+}\r
+\r
+bool TermGenEnv::considerCurrentTerm() {\r
+ Assert( !d_tg_alloc.empty() );\r
+\r
+ //if generalization depth is too large, don't consider it\r
+ unsigned i = d_tg_alloc.size();\r
+ Trace("sg-gen-tg-debug") << "Consider term ";\r
+ d_tg_alloc[0].debugPrint( this, "sg-gen-tg-debug", "sg-gen-tg-debug" );\r
+ Trace("sg-gen-tg-debug") << "? curr term size = " << d_tg_alloc.size() << ", last status = " << d_tg_alloc[i-1].d_status;\r
+ Trace("sg-gen-tg-debug") << std::endl;\r
+\r
+ if( d_tg_gdepth_limit>=0 && d_tg_alloc[0].getGeneralizationDepth( this )>(unsigned)d_tg_gdepth_limit ){\r
+ Trace("sg-gen-consider-term") << "-> generalization depth of ";\r
+ d_tg_alloc[0].debugPrint( this, "sg-gen-consider-term", "sg-gen-tg-debug" );\r
+ Trace("sg-gen-consider-term") << " is too high " << d_tg_gdepth << " " << d_tg_alloc[0].getGeneralizationDepth( this ) << ", do not consider." << std::endl;\r
+ return false;\r
+ }\r
+\r
+ //----optimizations\r
+ /*\r
+ if( d_tg_alloc[i-1].d_status==1 ){\r
+ }else if( d_tg_alloc[i-1].d_status==2 ){\r
+ }else if( d_tg_alloc[i-1].d_status==5 ){\r
+ }else{\r
+ Trace("sg-gen-tg-debug") << "Bad tg: " << &d_tg_alloc[i-1] << std::endl;\r
+ Assert( false );\r
+ }\r
+ */\r
+ //if equated two variables, first check if context-independent TODO\r
+ //----end optimizations\r
+\r
+\r
+ //check based on which candidate equivalence classes match\r
+ if( d_gen_relevant_terms ){\r
+ Trace("sg-gen-tg-debug") << "Filter based on relevant ground EQC";\r
+ Trace("sg-gen-tg-debug") << ", #eqc to try = " << d_ccand_eqc[0][i-1].size() << "/" << d_ccand_eqc[1][i-1].size() << std::endl;\r
+\r
+ Assert( d_ccand_eqc[0].size()>=2 );\r
+ Assert( d_ccand_eqc[0].size()==d_ccand_eqc[1].size() );\r
+ Assert( d_ccand_eqc[0].size()==d_tg_id+1 );\r
+ Assert( d_tg_id==d_tg_alloc.size() );\r
+ for( unsigned r=0; r<2; r++ ){\r
+ d_ccand_eqc[r][i].clear();\r
+ }\r
+\r
+ //re-check feasibility of EQC\r
+ for( unsigned r=0; r<2; r++ ){\r
+ for( unsigned j=0; j<d_ccand_eqc[r][i-1].size(); j++ ){\r
+ std::map< TypeNode, std::map< unsigned, TNode > > subs;\r
+ std::map< TNode, bool > rev_subs;\r
+ unsigned mode;\r
+ if( r==0 ){\r
+ mode = d_cg->optReqDistinctVarPatterns() ? ( 1 << 0 ) : 0;\r
+ mode = mode | (1 << 2 );\r
+ }else{\r
+ mode = 1 << 1;\r
+ }\r
+ d_tg_alloc[0].resetMatching( this, d_ccand_eqc[r][i-1][j], mode );\r
+ if( d_tg_alloc[0].getNextMatch( this, d_ccand_eqc[r][i-1][j], subs, rev_subs ) ){\r
+ d_ccand_eqc[r][i].push_back( d_ccand_eqc[r][i-1][j] );\r
+ }\r
+ }\r
+ }\r
+ for( unsigned r=0; r<2; r++ ){\r
+ Trace("sg-gen-tg-debug") << "Current eqc of type " << r << " : ";\r
+ for( unsigned j=0; j<d_ccand_eqc[r][i].size(); j++ ){\r
+ Trace("sg-gen-tg-debug") << "e" << d_cg->d_em[d_ccand_eqc[r][i][j]] << " ";\r
+ }\r
+ Trace("sg-gen-tg-debug") << std::endl;\r
+ }\r
+ if( options::conjectureFilterActiveTerms() && d_ccand_eqc[0][i].empty() ){\r
+ Trace("sg-gen-consider-term") << "Do not consider term of form ";\r
+ d_tg_alloc[0].debugPrint( this, "sg-gen-consider-term", "sg-gen-consider-term-debug" );\r
+ Trace("sg-gen-consider-term") << " since no relevant EQC matches it." << std::endl;\r
+ return false;\r
+ }\r
+ if( options::conjectureFilterModel() && d_ccand_eqc[1][i].empty() ){\r
+ Trace("sg-gen-consider-term") << "Do not consider term of form ";\r
+ d_tg_alloc[0].debugPrint( this, "sg-gen-consider-term", "sg-gen-consider-term-debug" );\r
+ Trace("sg-gen-consider-term") << " since no ground EQC matches it." << std::endl;\r
+ return false;\r
+ }\r
+ }\r
+ Trace("sg-gen-tg-debug") << "Will consider term ";\r
+ d_tg_alloc[0].debugPrint( this, "sg-gen-tg-debug", "sg-gen-tg-debug" );\r
+ Trace("sg-gen-tg-debug") << std::endl;\r
+ Trace("sg-gen-consider-term-debug") << std::endl;\r
+ return true;\r
+}\r
+\r
+void TermGenEnv::changeContext( bool add ) {\r
+ if( add ){\r
+ for( unsigned r=0; r<2; r++ ){\r
+ d_ccand_eqc[r].push_back( std::vector< TNode >() );\r
+ }\r
+ d_tg_id++;\r
+ }else{\r
+ for( unsigned r=0; r<2; r++ ){\r
+ d_ccand_eqc[r].pop_back();\r
+ }\r
+ d_tg_id--;\r
+ Assert( d_tg_alloc.find( d_tg_id )!=d_tg_alloc.end() );\r
+ d_tg_alloc.erase( d_tg_id );\r
+ }\r
+}\r
+\r
+bool TermGenEnv::considerCurrentTermCanon( unsigned tg_id ){\r
+ Assert( tg_id<d_tg_alloc.size() );\r
+ if( options::conjectureFilterCanonical() ){\r
+ //check based on a canonicity of the term (if there is one)\r
+ Trace("sg-gen-tg-debug") << "Consider term canon ";\r
+ d_tg_alloc[0].debugPrint( this, "sg-gen-tg-debug", "sg-gen-tg-debug" );\r
+ Trace("sg-gen-tg-debug") << ", tg is [" << tg_id << "]..." << std::endl;\r
+\r
+ Node ln = d_tg_alloc[tg_id].getTerm( this );\r
+ Trace("sg-gen-tg-debug") << "Term is " << ln << std::endl;\r
+ return d_cg->considerTermCanon( ln, d_gen_relevant_terms );\r
+ }\r
+ return true;\r
+}\r
+\r
+bool TermGenEnv::isRelevantFunc( Node f ) {\r
+ return std::find( d_funcs.begin(), d_funcs.end(), f )!=d_funcs.end();\r
+}\r
+TermDb * TermGenEnv::getTermDatabase() {\r
+ return d_cg->getTermDatabase();\r
+}\r
+Node TermGenEnv::getGroundEqc( TNode r ) {\r
+ return d_cg->getGroundEqc( r );\r
+}\r
+bool TermGenEnv::isGroundEqc( TNode r ){\r
+ return d_cg->isGroundEqc( r );\r
+}\r
+bool TermGenEnv::isGroundTerm( TNode n ){\r
+ return d_cg->isGroundTerm( n );\r
+}\r
+\r
+\r
+void SubstitutionIndex::addSubstitution( TNode eqc, std::vector< TNode >& vars, std::vector< TNode >& terms, unsigned i ) {\r
+ if( i==vars.size() ){\r
+ d_var = eqc;\r
+ }else{\r
+ Assert( d_var.isNull() || d_var==vars[i] );\r
+ d_var = vars[i];\r
+ d_children[terms[i]].addSubstitution( eqc, vars, terms, i+1 );\r
+ }\r
+}\r
+\r
+bool SubstitutionIndex::notifySubstitutions( ConjectureGenerator * s, std::map< TNode, TNode >& subs, TNode rhs, unsigned numVars, unsigned i ) {\r
+ if( i==numVars ){\r
+ Assert( d_children.empty() );\r
+ return s->notifySubstitution( d_var, subs, rhs );\r
+ }else{\r
+ Assert( i==0 || !d_children.empty() );\r
+ for( std::map< TNode, SubstitutionIndex >::iterator it = d_children.begin(); it != d_children.end(); ++it ){\r
+ Trace("sg-cconj-debug2") << "Try " << d_var << " -> " << it->first << " (" << i << "/" << numVars << ")" << std::endl;\r
+ subs[d_var] = it->first;\r
+ if( !it->second.notifySubstitutions( s, subs, rhs, numVars, i+1 ) ){\r
+ return false;\r
+ }\r
+ }\r
+ return true;\r
+ }\r
+}\r
+\r
+\r
+void TheoremIndex::addTheorem( std::vector< TNode >& lhs_v, std::vector< unsigned >& lhs_arg, TNode rhs ){\r
+ if( lhs_v.empty() ){\r
+ if( std::find( d_terms.begin(), d_terms.end(), rhs )==d_terms.end() ){\r
+ d_terms.push_back( rhs );\r
+ }\r
+ }else{\r
+ unsigned index = lhs_v.size()-1;\r
+ if( lhs_arg[index]==lhs_v[index].getNumChildren() ){\r
+ lhs_v.pop_back();\r
+ lhs_arg.pop_back();\r
+ addTheorem( lhs_v, lhs_arg, rhs );\r
+ }else{\r
+ lhs_arg[index]++;\r
+ addTheoremNode( lhs_v[index][lhs_arg[index]-1], lhs_v, lhs_arg, rhs );\r
+ }\r
+ }\r
+}\r
+\r
+void TheoremIndex::addTheoremNode( TNode curr, std::vector< TNode >& lhs_v, std::vector< unsigned >& lhs_arg, TNode rhs ){\r
+ Trace("thm-db-debug") << "Adding conjecture for subterm " << curr << "..." << std::endl;\r
+ if( curr.hasOperator() ){\r
+ lhs_v.push_back( curr );\r
+ lhs_arg.push_back( 0 );\r
+ d_children[curr.getOperator()].addTheorem( lhs_v, lhs_arg, rhs );\r
+ }else{\r
+ Assert( curr.getKind()==kind::BOUND_VARIABLE );\r
+ TypeNode tn = curr.getType();\r
+ Assert( d_var[tn].isNull() || d_var[tn]==curr );\r
+ d_var[tn] = curr;\r
+ d_children[curr].addTheorem( lhs_v, lhs_arg, rhs );\r
+ }\r
+}\r
+\r
+void TheoremIndex::getEquivalentTerms( std::vector< TNode >& n_v, std::vector< unsigned >& n_arg,\r
+ std::map< TNode, TNode >& smap, std::vector< TNode >& vars, std::vector< TNode >& subs,\r
+ std::vector< Node >& terms ) {\r
+ Trace("thm-db-debug") << "Get equivalent terms " << n_v.size() << " " << n_arg.size() << std::endl;\r
+ if( n_v.empty() ){\r
+ Trace("thm-db-debug") << "Number of terms : " << d_terms.size() << std::endl;\r
+ //apply substutitions to RHS's\r
+ for( unsigned i=0; i<d_terms.size(); i++ ){\r
+ Node n = d_terms[i].substitute( vars.begin(), vars.end(), subs.begin(), subs.end() );\r
+ terms.push_back( n );\r
+ }\r
+ }else{\r
+ unsigned index = n_v.size()-1;\r
+ if( n_arg[index]==n_v[index].getNumChildren() ){\r
+ n_v.pop_back();\r
+ n_arg.pop_back();\r
+ getEquivalentTerms( n_v, n_arg, smap, vars, subs, terms );\r
+ }else{\r
+ n_arg[index]++;\r
+ getEquivalentTermsNode( n_v[index][n_arg[index]-1], n_v, n_arg, smap, vars, subs, terms );\r
+ }\r
+ }\r
+}\r
+\r
+void TheoremIndex::getEquivalentTermsNode( Node curr, std::vector< TNode >& n_v, std::vector< unsigned >& n_arg,\r
+ std::map< TNode, TNode >& smap, std::vector< TNode >& vars, std::vector< TNode >& subs,\r
+ std::vector< Node >& terms ) {\r
+ Trace("thm-db-debug") << "Get equivalent based on subterm " << curr << "..." << std::endl;\r
+ if( curr.hasOperator() ){\r
+ Trace("thm-db-debug") << "Check based on operator..." << std::endl;\r
+ std::map< TNode, TheoremIndex >::iterator it = d_children.find( curr.getOperator() );\r
+ if( it!=d_children.end() ){\r
+ n_v.push_back( curr );\r
+ n_arg.push_back( 0 );\r
+ it->second.getEquivalentTerms( n_v, n_arg, smap, vars, subs, terms );\r
+ }\r
+ Trace("thm-db-debug") << "...done check based on operator" << std::endl;\r
+ }\r
+ TypeNode tn = curr.getType();\r
+ std::map< TypeNode, TNode >::iterator itt = d_var.find( tn );\r
+ if( itt!=d_var.end() ){\r
+ Trace("thm-db-debug") << "Check for substitution with " << itt->second << "..." << std::endl;\r
+ Assert( curr.getType()==itt->second.getType() );\r
+ //add to substitution if possible\r
+ bool success = false;\r
+ std::map< TNode, TNode >::iterator it = smap.find( itt->second );\r
+ if( it==smap.end() ){\r
+ smap[itt->second] = curr;\r
+ vars.push_back( itt->second );\r
+ subs.push_back( curr );\r
+ success = true;\r
+ }else if( it->second==curr ){\r
+ success = true;\r
+ }else{\r
+ //also check modulo equality (in universal equality engine)\r
+ }\r
+ Trace("thm-db-debug") << "...check for substitution with " << itt->second << ", success = " << success << "." << std::endl;\r
+ if( success ){\r
+ d_children[itt->second].getEquivalentTerms( n_v, n_arg, smap, vars, subs, terms );\r
+ }\r
+ }\r
+}\r
+\r
+void TheoremIndex::debugPrint( const char * c, unsigned ind ) {\r
+ for( std::map< TNode, TheoremIndex >::iterator it = d_children.begin(); it != d_children.end(); ++it ){\r
+ for( unsigned i=0; i<ind; i++ ){ Trace(c) << " "; }\r
+ Trace(c) << it->first << std::endl;\r
+ it->second.debugPrint( c, ind+1 );\r
+ }\r
+ if( !d_terms.empty() ){\r
+ for( unsigned i=0; i<ind; i++ ){ Trace(c) << " "; }\r
+ Trace(c) << "{";\r
+ for( unsigned i=0; i<d_terms.size(); i++ ){\r
+ Trace(c) << " " << d_terms[i];\r
+ }\r
+ Trace(c) << " }" << std::endl;\r
+ }\r
+ //if( !d_var.isNull() ){\r
+ // for( unsigned i=0; i<ind; i++ ){ Trace(c) << " "; }\r
+ // Trace(c) << "var:" << d_var << std::endl;\r
+ //}\r
+}\r
+\r
+bool ConjectureGenerator::optReqDistinctVarPatterns() { return false; }\r
+bool ConjectureGenerator::optFilterUnknown() { return true; } //may change\r
+int ConjectureGenerator::optFilterScoreThreshold() { return 1; }\r
+unsigned ConjectureGenerator::optFullCheckFrequency() { return 1; }\r
+\r
+bool ConjectureGenerator::optStatsOnly() { return false; }\r
+\r
+}\r
--- /dev/null
+/********************* */\r
+/*! \file conjecture_generator.h\r
+ ** \verbatim\r
+ ** Original author: Andrew Reynolds\r
+ ** Major contributors: none\r
+ ** Minor contributors (to current version): none\r
+ ** This file is part of the CVC4 project.\r
+ ** Copyright (c) 2009-2014 New York University and The University of Iowa\r
+ ** See the file COPYING in the top-level source directory for licensing\r
+ ** information.\endverbatim\r
+ **\r
+ ** \brief conjecture generator class\r
+ **/\r
+\r
+#include "cvc4_private.h"\r
+\r
+#ifndef CONJECTURE_GENERATOR_H\r
+#define CONJECTURE_GENERATOR_H\r
+\r
+#include "context/cdhashmap.h"\r
+#include "context/cdchunk_list.h"\r
+#include "theory/quantifiers_engine.h"\r
+#include "theory/type_enumerator.h"\r
+\r
+namespace CVC4 {\r
+namespace theory {\r
+namespace quantifiers {\r
+\r
+class TermArgTrie;\r
+\r
+//algorithm for computing candidate subgoals\r
+\r
+class ConjectureGenerator;\r
+\r
+// operator independent index of arguments for an EQC\r
+class OpArgIndex\r
+{\r
+public:\r
+ std::map< TNode, OpArgIndex > d_child;\r
+ std::vector< TNode > d_ops;\r
+ std::vector< TNode > d_op_terms;\r
+ void addTerm( ConjectureGenerator * s, TNode n, unsigned index = 0 );\r
+ Node getGroundTerm( ConjectureGenerator * s, std::vector< TNode >& args );\r
+ void getGroundTerms( ConjectureGenerator * s, std::vector< TNode >& terms );\r
+};\r
+\r
+class PatternTypIndex\r
+{\r
+public:\r
+ std::vector< TNode > d_terms;\r
+ std::map< TypeNode, std::map< unsigned, PatternTypIndex > > d_children;\r
+ void clear() {\r
+ d_terms.clear();\r
+ d_children.clear();\r
+ }\r
+};\r
+\r
+class SubstitutionIndex\r
+{\r
+public:\r
+ //current variable, or ground EQC if d_children.empty()\r
+ TNode d_var;\r
+ std::map< TNode, SubstitutionIndex > d_children;\r
+ //add substitution\r
+ void addSubstitution( TNode eqc, std::vector< TNode >& vars, std::vector< TNode >& terms, unsigned i = 0 );\r
+ //notify substitutions\r
+ bool notifySubstitutions( ConjectureGenerator * s, std::map< TNode, TNode >& subs, TNode rhs, unsigned numVars, unsigned i = 0 );\r
+};\r
+\r
+class TermGenEnv;\r
+\r
+class TermGenerator\r
+{\r
+private:\r
+ unsigned calculateGeneralizationDepth( TermGenEnv * s, std::map< TypeNode, std::vector< int > >& fvs );\r
+public:\r
+ TermGenerator(){}\r
+ TypeNode d_typ;\r
+ unsigned d_id;\r
+ //1 : consider as unique variable\r
+ //2 : consider equal to another variable\r
+ //5 : consider a function application\r
+ unsigned d_status;\r
+ int d_status_num;\r
+ //for function applications: the number of children you have built\r
+ int d_status_child_num;\r
+ //children (pointers to TermGenerators)\r
+ std::vector< unsigned > d_children;\r
+\r
+ //match status\r
+ int d_match_status;\r
+ int d_match_status_child_num;\r
+ //match mode bits\r
+ //0 : different variables must have different matches\r
+ //1 : variables must map to ground terms\r
+ //2 : variables must map to non-ground terms\r
+ unsigned d_match_mode;\r
+ //children\r
+ std::vector< std::map< TNode, TermArgTrie >::iterator > d_match_children;\r
+ std::vector< std::map< TNode, TermArgTrie >::iterator > d_match_children_end;\r
+\r
+ void reset( TermGenEnv * s, TypeNode tn );\r
+ bool getNextTerm( TermGenEnv * s, unsigned depth );\r
+ void resetMatching( TermGenEnv * s, TNode eqc, unsigned mode );\r
+ bool getNextMatch( TermGenEnv * s, TNode eqc, std::map< TypeNode, std::map< unsigned, TNode > >& subs, std::map< TNode, bool >& rev_subs );\r
+\r
+ unsigned getDepth( TermGenEnv * s );\r
+ unsigned getGeneralizationDepth( TermGenEnv * s );\r
+ Node getTerm( TermGenEnv * s );\r
+\r
+ void debugPrint( TermGenEnv * s, const char * c, const char * cd );\r
+};\r
+\r
+\r
+class TermGenEnv\r
+{\r
+public:\r
+ //collect signature information\r
+ void collectSignatureInformation();\r
+ //reset function\r
+ void reset( unsigned gdepth, bool genRelevant, TypeNode tgen );\r
+ //get next term\r
+ bool getNextTerm();\r
+ //reset matching\r
+ void resetMatching( TNode eqc, unsigned mode );\r
+ //get next match\r
+ bool getNextMatch( TNode eqc, std::map< TypeNode, std::map< unsigned, TNode > >& subs, std::map< TNode, bool >& rev_subs );\r
+ //get term\r
+ Node getTerm();\r
+ //debug print\r
+ void debugPrint( const char * c, const char * cd );\r
+\r
+ //conjecture generation\r
+ ConjectureGenerator * d_cg;\r
+ //the current number of enumerated variables per type\r
+ std::map< TypeNode, unsigned > d_var_id;\r
+ //the limit of number of variables per type to enumerate\r
+ std::map< TypeNode, unsigned > d_var_limit;\r
+ //the functions we can currently generate\r
+ std::map< TypeNode, std::vector< TNode > > d_typ_tg_funcs;\r
+ //the equivalence classes (if applicable) that match the currently generated term\r
+ bool d_gen_relevant_terms;\r
+ //relevant equivalence classes\r
+ std::vector< TNode > d_relevant_eqc[2];\r
+ //candidate equivalence classes\r
+ std::vector< std::vector< TNode > > d_ccand_eqc[2];\r
+ //the term generation objects\r
+ unsigned d_tg_id;\r
+ std::map< unsigned, TermGenerator > d_tg_alloc;\r
+ unsigned d_tg_gdepth;\r
+ int d_tg_gdepth_limit;\r
+\r
+ //all functions\r
+ std::vector< TNode > d_funcs;\r
+ //function to kind map\r
+ std::map< TNode, Kind > d_func_kind;\r
+ //type of each argument of the function\r
+ std::map< TNode, std::vector< TypeNode > > d_func_args;\r
+\r
+ //access functions\r
+ unsigned getNumTgVars( TypeNode tn );\r
+ bool allowVar( TypeNode tn );\r
+ void addVar( TypeNode tn );\r
+ void removeVar( TypeNode tn );\r
+ unsigned getNumTgFuncs( TypeNode tn );\r
+ TNode getTgFunc( TypeNode tn, unsigned i );\r
+ Node getFreeVar( TypeNode tn, unsigned i );\r
+ bool considerCurrentTerm();\r
+ bool considerCurrentTermCanon( unsigned tg_id );\r
+ void changeContext( bool add );\r
+ bool isRelevantFunc( Node f );\r
+ //carry\r
+ TermDb * getTermDatabase();\r
+ Node getGroundEqc( TNode r );\r
+ bool isGroundEqc( TNode r );\r
+ bool isGroundTerm( TNode n );\r
+};\r
+\r
+\r
+\r
+class TheoremIndex\r
+{\r
+private:\r
+ void addTheorem( std::vector< TNode >& lhs_v, std::vector< unsigned >& lhs_arg, TNode rhs );\r
+ void addTheoremNode( TNode curr, std::vector< TNode >& lhs_v, std::vector< unsigned >& lhs_arg, TNode rhs );\r
+ void getEquivalentTerms( std::vector< TNode >& n_v, std::vector< unsigned >& n_arg,\r
+ std::map< TNode, TNode >& smap, std::vector< TNode >& vars, std::vector< TNode >& subs,\r
+ std::vector< Node >& terms );\r
+ void getEquivalentTermsNode( Node curr, std::vector< TNode >& n_v, std::vector< unsigned >& n_arg,\r
+ std::map< TNode, TNode >& smap, std::vector< TNode >& vars, std::vector< TNode >& subs,\r
+ std::vector< Node >& terms );\r
+public:\r
+ std::map< TypeNode, TNode > d_var;\r
+ std::map< TNode, TheoremIndex > d_children;\r
+ std::vector< Node > d_terms;\r
+\r
+ void addTheorem( TNode lhs, TNode rhs ) {\r
+ std::vector< TNode > v;\r
+ std::vector< unsigned > a;\r
+ addTheoremNode( lhs, v, a, rhs );\r
+ }\r
+ void getEquivalentTerms( TNode n, std::vector< Node >& terms ) {\r
+ std::vector< TNode > nv;\r
+ std::vector< unsigned > na;\r
+ std::map< TNode, TNode > smap;\r
+ std::vector< TNode > vars;\r
+ std::vector< TNode > subs;\r
+ getEquivalentTermsNode( n, nv, na, smap, vars, subs, terms );\r
+ }\r
+ void clear(){\r
+ d_var.clear();\r
+ d_children.clear();\r
+ d_terms.clear();\r
+ }\r
+ void debugPrint( const char * c, unsigned ind = 0 );\r
+};\r
+\r
+\r
+\r
+class ConjectureGenerator : public QuantifiersModule\r
+{\r
+ friend class OpArgIndex;\r
+ friend class PatGen;\r
+ friend class PatternGenEqc;\r
+ friend class PatternGen;\r
+ friend class SubsEqcIndex;\r
+ friend class TermGenerator;\r
+ friend class TermGenEnv;\r
+ typedef context::CDChunkList<Node> NodeList;\r
+ typedef context::CDHashMap< Node, Node, NodeHashFunction > NodeMap;\r
+ typedef context::CDHashMap< Node, bool, NodeHashFunction > BoolMap;\r
+//this class maintains a congruence closure for *universal* facts\r
+private:\r
+ //notification class for equality engine\r
+ class NotifyClass : public eq::EqualityEngineNotify {\r
+ ConjectureGenerator& d_sg;\r
+ public:\r
+ NotifyClass(ConjectureGenerator& sg): d_sg(sg) {}\r
+ bool eqNotifyTriggerEquality(TNode equality, bool value) { return true; }\r
+ bool eqNotifyTriggerPredicate(TNode predicate, bool value) { return true; }\r
+ bool eqNotifyTriggerTermEquality(TheoryId tag, TNode t1, TNode t2, bool value) { return true; }\r
+ void eqNotifyConstantTermMerge(TNode t1, TNode t2) { }\r
+ void eqNotifyNewClass(TNode t) { d_sg.eqNotifyNewClass(t); }\r
+ void eqNotifyPreMerge(TNode t1, TNode t2) { d_sg.eqNotifyPreMerge(t1, t2); }\r
+ void eqNotifyPostMerge(TNode t1, TNode t2) { d_sg.eqNotifyPostMerge(t1, t2); }\r
+ void eqNotifyDisequal(TNode t1, TNode t2, TNode reason) {d_sg.eqNotifyDisequal(t1, t2, reason); }\r
+ };/* class ConjectureGenerator::NotifyClass */\r
+ /** The notify class */\r
+ NotifyClass d_notify;\r
+ class EqcInfo{\r
+ public:\r
+ EqcInfo( context::Context* c );\r
+ //representative\r
+ context::CDO< Node > d_rep;\r
+ };\r
+ /** get or make eqc info */\r
+ EqcInfo* getOrMakeEqcInfo( TNode n, bool doMake = false );\r
+ /** (universal) equaltity engine */\r
+ eq::EqualityEngine d_uequalityEngine;\r
+ /** pending adds */\r
+ std::vector< Node > d_upendingAdds;\r
+ /** relevant terms */\r
+ std::map< Node, bool > d_urelevant_terms;\r
+ /** information necessary for equivalence classes */\r
+ std::map< Node, EqcInfo* > d_eqc_info;\r
+ /** called when a new equivalance class is created */\r
+ void eqNotifyNewClass(TNode t);\r
+ /** called when two equivalance classes will merge */\r
+ void eqNotifyPreMerge(TNode t1, TNode t2);\r
+ /** called when two equivalance classes have merged */\r
+ void eqNotifyPostMerge(TNode t1, TNode t2);\r
+ /** called when two equivalence classes are made disequal */\r
+ void eqNotifyDisequal(TNode t1, TNode t2, TNode reason);\r
+ /** are universal equal */\r
+ bool areUniversalEqual( TNode n1, TNode n2 );\r
+ /** are universal disequal */\r
+ bool areUniversalDisequal( TNode n1, TNode n2 );\r
+ /** get universal representative */\r
+ TNode getUniversalRepresentative( TNode n, bool add = false );\r
+ /** set relevant */\r
+ void setUniversalRelevant( TNode n );\r
+ /** ordering for universal terms */\r
+ bool isUniversalLessThan( TNode rt1, TNode rt2 );\r
+\r
+ /** the nodes we have reported as canonical representative */\r
+ std::vector< TNode > d_ue_canon;\r
+ /** is reported canon */\r
+ bool isReportedCanon( TNode n );\r
+ /** mark that term has been reported as canonical rep */\r
+ void markReportedCanon( TNode n );\r
+\r
+private: //information regarding the conjectures\r
+ /** list of all conjectures */\r
+ std::vector< Node > d_conjectures;\r
+ /** list of all waiting conjectures */\r
+ std::vector< Node > d_waiting_conjectures_lhs;\r
+ std::vector< Node > d_waiting_conjectures_rhs;\r
+ std::vector< int > d_waiting_conjectures_score;\r
+ /** map of currently considered equality conjectures */\r
+ std::map< Node, std::vector< Node > > d_waiting_conjectures;\r
+ /** map of equality conjectures */\r
+ std::map< Node, std::vector< Node > > d_eq_conjectures;\r
+ /** currently existing conjectures in equality engine */\r
+ BoolMap d_ee_conjectures;\r
+ /** conjecture index */\r
+ TheoremIndex d_thm_index;\r
+private: //free variable list\r
+ //free variables\r
+ std::map< TypeNode, std::vector< Node > > d_free_var;\r
+ //map from free variable to FV#\r
+ std::map< TNode, unsigned > d_free_var_num;\r
+ // get canonical free variable #i of type tn\r
+ Node getFreeVar( TypeNode tn, unsigned i );\r
+ // get canonical term, return null if it contains a term apart from handled signature\r
+ Node getCanonicalTerm( TNode n, std::map< TypeNode, unsigned >& var_count, std::map< TNode, TNode >& subs );\r
+private: //information regarding the terms\r
+ //relevant patterns (the LHS's)\r
+ std::map< TypeNode, std::vector< Node > > d_rel_patterns;\r
+ //total number of unique variables\r
+ std::map< TNode, unsigned > d_rel_pattern_var_sum;\r
+ //by types\r
+ PatternTypIndex d_rel_pattern_typ_index;\r
+ // substitution to ground EQC index\r
+ std::map< TNode, SubstitutionIndex > d_rel_pattern_subs_index;\r
+ //patterns (the RHS's)\r
+ std::map< TypeNode, std::vector< Node > > d_patterns;\r
+ //patterns to # variables per type\r
+ std::map< TNode, std::map< TypeNode, unsigned > > d_pattern_var_id;\r
+ // # duplicated variables\r
+ std::map< TNode, unsigned > d_pattern_var_duplicate;\r
+ // is normal pattern? (variables allocated in canonical way left to right)\r
+ std::map< TNode, int > d_pattern_is_normal;\r
+ std::map< TNode, int > d_pattern_is_relevant;\r
+ // patterns to a count of # operators (variables and functions)\r
+ std::map< TNode, std::map< TNode, unsigned > > d_pattern_fun_id;\r
+ // term size\r
+ std::map< TNode, unsigned > d_pattern_fun_sum;\r
+ // collect functions\r
+ unsigned collectFunctions( TNode opat, TNode pat, std::map< TNode, unsigned >& funcs,\r
+ std::map< TypeNode, unsigned >& mnvn, std::map< TypeNode, unsigned >& mxvn );\r
+ // add pattern\r
+ void registerPattern( Node pat, TypeNode tpat );\r
+private: //for debugging\r
+ std::map< TNode, unsigned > d_em;\r
+public:\r
+ //term generation environment\r
+ TermGenEnv d_tge;\r
+ //consider term canon\r
+ bool considerTermCanon( Node ln, bool genRelevant );\r
+public: //for generalization\r
+ //generalizations\r
+ bool isGeneralization( TNode patg, TNode pat ) {\r
+ std::map< TNode, TNode > subs;\r
+ return isGeneralization( patg, pat, subs );\r
+ }\r
+ bool isGeneralization( TNode patg, TNode pat, std::map< TNode, TNode >& subs );\r
+ // get generalization depth\r
+ int calculateGeneralizationDepth( TNode n, std::vector< TNode >& fv );\r
+private:\r
+ //predicate for type\r
+ std::map< TypeNode, Node > d_typ_pred;\r
+ //get predicate for type\r
+ Node getPredicateForType( TypeNode tn );\r
+ //\r
+ void getEnumerateUfTerm( Node n, unsigned num, std::vector< Node >& terms );\r
+ //\r
+ void getEnumeratePredUfTerm( Node n, unsigned num, std::vector< Node >& terms );\r
+ // uf operators enumerated\r
+ std::map< Node, bool > d_uf_enum;\r
+public: //for property enumeration\r
+ //process this candidate conjecture\r
+ void processCandidateConjecture( TNode lhs, TNode rhs, unsigned lhs_depth, unsigned rhs_depth );\r
+ //whether it should be considered, negative : no, positive returns score\r
+ int considerCandidateConjecture( TNode lhs, TNode rhs );\r
+ //notified of a substitution\r
+ bool notifySubstitution( TNode glhs, std::map< TNode, TNode >& subs, TNode rhs );\r
+ //confirmation count\r
+ unsigned d_subs_confirmCount;\r
+ //individual witnesses (for range)\r
+ std::vector< TNode > d_subs_confirmWitnessRange;\r
+ //individual witnesses (for domain)\r
+ std::map< TNode, std::vector< TNode > > d_subs_confirmWitnessDomain;\r
+ //number of ground substitutions whose equality is unknown\r
+ unsigned d_subs_unkCount;\r
+private: //information about ground equivalence classes\r
+ TNode d_bool_eqc[2];\r
+ std::map< TNode, Node > d_ground_eqc_map;\r
+ std::vector< TNode > d_ground_terms;\r
+ //operator independent term index\r
+ std::map< TNode, OpArgIndex > d_op_arg_index;\r
+ //is handled term\r
+ bool isHandledTerm( TNode n );\r
+ Node getGroundEqc( TNode r );\r
+ bool isGroundEqc( TNode r );\r
+ bool isGroundTerm( TNode n );\r
+ //has enumerated UF\r
+ bool hasEnumeratedUf( Node n );\r
+ // count of full effort checks\r
+ unsigned d_fullEffortCount;\r
+ // has added lemma\r
+ bool d_hasAddedLemma;\r
+ //flush the waiting conjectures\r
+ unsigned flushWaitingConjectures( unsigned& addedLemmas, int ldepth, int rdepth );\r
+public:\r
+ ConjectureGenerator( QuantifiersEngine * qe, context::Context* c );\r
+ /* needs check */\r
+ bool needsCheck( Theory::Effort e );\r
+ /* reset at a round */\r
+ void reset_round( Theory::Effort e );\r
+ /* Call during quantifier engine's check */\r
+ void check( Theory::Effort e, unsigned quant_e );\r
+ /* Called for new quantifiers */\r
+ void registerQuantifier( Node q );\r
+ void assertNode( Node n );\r
+ /** Identify this module (for debugging, dynamic configuration, etc..) */\r
+ std::string identify() const { return "ConjectureGenerator"; }\r
+//options\r
+private:\r
+ bool optReqDistinctVarPatterns();\r
+ bool optFilterUnknown();\r
+ int optFilterScoreThreshold();\r
+ unsigned optFullCheckFrequency();\r
+ unsigned optFullCheckConjectures();\r
+\r
+ bool optStatsOnly();\r
+};\r
+\r
+\r
+}\r
+}\r
+}\r
+\r
+#endif\r
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) {
}
/** 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 */
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;
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 ){
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){
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
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());
- }
- }
}
}
<< 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();
//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
}
}
}
+ //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;
//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 );
}
}
+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() ){
}
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;
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{
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;
}
}
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 ){
}
}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;
}
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;
}
}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
}
}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) );
}
return 0;
}
}
- return qe->addInstantiation( f, m ) ? 1 : 0;
+ return qe->addInstantiation( f, m, false ) ? 1 : 0;
}
}/* CVC4::theory::inst namespace */
/** 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 */
class CandidateGenerator;
class InstMatchGenerator : public IMGenerator {
-private:
+protected:
bool d_needsReset;
/** candidate generator */
CandidateGenerator* d_cg;
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,
};
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.
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:
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;
- }
-}
};
-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 */
-
}
}
}
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;
+ 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 );
- //if( d_user_gen[f][i]->isMultiTrigger() )
- Trace("process-trigger") << " Done, numInst = " << numInst << "." << std::endl;
+ 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;
}
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() ) );
+ d_user_gen[f].push_back( Trigger::mkTrigger( d_quantEngine, f, nodes, matchOption, true, Trigger::TR_MAKE_NEW, options::smartTriggers() ) );
}
}
}
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 = ( hasUserPatterns( f ) && options::userPatternsQuant()!=USER_PAT_MODE_IGNORE ) ? 2 : 1;
//int peffort = 1;
if( e<peffort ){
return STATUS_UNFINISHED;
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{
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;
+ 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.size() << std::endl;
Trace("auto-gen-trigger") << " ";
for( int i=0; i<(int)patTermsF.size(); i++ ){
Trace("auto-gen-trigger") << patTermsF[i] << " ";
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{
}
}
+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 ){
}
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)
}
/** 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{
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 ){
}
}
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 );
+
+ //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 );
d_i_ag->setGenerateAdditional( true );
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
}
}
//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++;
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;
}
}
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 ){
//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") ){
++(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;
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) ){
}
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 );
//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] );
+ }
}
}
}
}
}
+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),
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 */
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 {
# 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 \
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
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;
}
bool QModelBuilder::isQuantifierActive( Node f ) {
- return !TermDb::isRewriteRule( f );
+ return d_qe->hasOwnership( f );
}
}
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_considerAxioms || !d_qe->getTermDatabase()->isQAttrAxiom( f ) ) && d_quant_sat.find( f )==d_quant_sat.end();
}
bool QModelBuilderIG::isTermActive( Node n ){
//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 ||
delete d_builder;
}
-void ModelEngine::check( Theory::Effort e ){
- if( e==Theory::EFFORT_LAST_CALL && !d_quantEngine->hasAddedLemma() ){
+bool ModelEngine::needsCheck( Theory::Effort e ) {
+ return e==Theory::EFFORT_LAST_CALL;
+}
+
+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();
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 ) ){
+ 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
}
}else{
//otherwise, the search will continue
- d_quantEngine->flushLemmas( &d_quantEngine->getOutputChannel() );
}
}
}
//get the builder
QModelBuilder* getModelBuilder() { return d_builder; }
public:
- 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 f );
Node explain(TNode n){ return Node::null(); }
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;
+
+
}/* CVC4::theory::quantifiers namespace */
}/* CVC4::theory namespace */
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.
# 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
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 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
# Whether to consider terms in the bodies of quantifiers for matching
option registerQuantBodyTerms --register-quant-body-terms bool :default false
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
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
+
endmodule
+ 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\
+";
inline InstWhenMode stringToInstWhenMode(std::string option, std::string optarg, SmtEngine* smt) throw(OptionException) {
if(optarg == "pre-full") {
return INST_WHEN_PRE_FULL;
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.");
+ }
+}
+
}/* CVC4::theory::quantifiers namespace */
}/* CVC4::theory namespace */
}/* CVC4 namespace */
-/********************* */
-/*! \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;
- }
-}
-
-
-}
+/********************* */\r
+/*! \file quant_conflict_find.cpp\r
+ ** \verbatim\r
+ ** Original author: Andrew Reynolds\r
+ ** Major contributors: none\r
+ ** Minor contributors (to current version): none\r
+ ** This file is part of the CVC4 project.\r
+ ** Copyright (c) 2009-2014 New York University and The University of Iowa\r
+ ** See the file COPYING in the top-level source directory for licensing\r
+ ** information.\endverbatim\r
+ **\r
+ ** \brief quant conflict find class\r
+ **\r
+ **/\r
+\r
+#include <vector>\r
+\r
+#include "theory/quantifiers/quant_conflict_find.h"\r
+#include "theory/quantifiers/quant_util.h"\r
+#include "theory/theory_engine.h"\r
+#include "theory/quantifiers/options.h"\r
+#include "theory/quantifiers/term_database.h"\r
+#include "theory/quantifiers/trigger.h"\r
+\r
+using namespace CVC4;\r
+using namespace CVC4::kind;\r
+using namespace CVC4::theory;\r
+using namespace CVC4::theory::quantifiers;\r
+using namespace std;\r
+\r
+namespace CVC4 {\r
+\r
+\r
+\r
+void QuantInfo::initialize( Node q, Node qn ) {\r
+ d_q = q;\r
+ for( unsigned i=0; i<q[0].getNumChildren(); i++ ){\r
+ d_match.push_back( TNode::null() );\r
+ d_match_term.push_back( TNode::null() );\r
+ }\r
+\r
+ //register the variables\r
+ for( unsigned i=0; i<q[0].getNumChildren(); i++ ){\r
+ d_var_num[q[0][i]] = i;\r
+ d_vars.push_back( q[0][i] );\r
+ }\r
+\r
+ registerNode( qn, true, true );\r
+\r
+\r
+ Trace("qcf-qregister") << "- Make match gen structure..." << std::endl;\r
+ d_mg = new MatchGen( this, qn );\r
+\r
+ if( d_mg->isValid() ){\r
+ /*\r
+ for( unsigned j=0; j<q[0].getNumChildren(); j++ ){\r
+ if( d_inMatchConstraint.find( q[0][j] )==d_inMatchConstraint.end() ){\r
+ Trace("qcf-invalid") << "QCF invalid : variable " << q[0][j] << " does not exist in a matching constraint." << std::endl;\r
+ d_mg->setInvalid();\r
+ break;\r
+ }\r
+ }\r
+ */\r
+ if( d_mg->isValid() ){\r
+ for( unsigned j=q[0].getNumChildren(); j<d_vars.size(); j++ ){\r
+ if( d_vars[j].getKind()!=BOUND_VARIABLE ){\r
+ d_var_mg[j] = NULL;\r
+ bool is_tsym = false;\r
+ if( !MatchGen::isHandledUfTerm( d_vars[j] ) && d_vars[j].getKind()!=ITE ){\r
+ is_tsym = true;\r
+ d_tsym_vars.push_back( j );\r
+ }\r
+ if( !is_tsym || options::qcfTConstraint() ){\r
+ d_var_mg[j] = new MatchGen( this, d_vars[j], true );\r
+ }\r
+ if( !d_var_mg[j] || !d_var_mg[j]->isValid() ){\r
+ Trace("qcf-invalid") << "QCF invalid : cannot match for " << d_vars[j] << std::endl;\r
+ d_mg->setInvalid();\r
+ break;\r
+ }else{\r
+ std::vector< int > bvars;\r
+ d_var_mg[j]->determineVariableOrder( this, bvars );\r
+ }\r
+ }\r
+ }\r
+ if( d_mg->isValid() ){\r
+ std::vector< int > bvars;\r
+ d_mg->determineVariableOrder( this, bvars );\r
+ }\r
+ }\r
+ }else{\r
+ Trace("qcf-invalid") << "QCF invalid : body of formula cannot be processed." << std::endl;\r
+ }\r
+ Trace("qcf-qregister-summary") << "QCF register : " << ( d_mg->isValid() ? "VALID " : "INVALID" ) << " : " << q << std::endl;\r
+}\r
+\r
+void QuantInfo::registerNode( Node n, bool hasPol, bool pol, bool beneathQuant ) {\r
+ Trace("qcf-qregister-debug2") << "Register : " << n << std::endl;\r
+ if( n.getKind()==FORALL ){\r
+ registerNode( n[1], hasPol, pol, true );\r
+ }else{\r
+ if( !MatchGen::isHandledBoolConnective( n ) ){\r
+ if( n.hasBoundVar() ){\r
+ //literals\r
+ if( n.getKind()==EQUAL ){\r
+ for( unsigned i=0; i<n.getNumChildren(); i++ ){\r
+ flatten( n[i], beneathQuant );\r
+ }\r
+ }else if( MatchGen::isHandledUfTerm( n ) ){\r
+ flatten( n, beneathQuant );\r
+ }else if( n.getKind()==ITE ){\r
+ for( unsigned i=1; i<=2; i++ ){\r
+ flatten( n[i], beneathQuant );\r
+ }\r
+ registerNode( n[0], false, pol, beneathQuant );\r
+ }else if( options::qcfTConstraint() ){\r
+ //a theory-specific predicate\r
+ for( unsigned i=0; i<n.getNumChildren(); i++ ){\r
+ flatten( n[i], beneathQuant );\r
+ }\r
+ }\r
+ }\r
+ }else{\r
+ for( unsigned i=0; i<n.getNumChildren(); i++ ){\r
+ bool newHasPol;\r
+ bool newPol;\r
+ QuantPhaseReq::getPolarity( n, i, hasPol, pol, newHasPol, newPol );\r
+ //QcfNode * qcfc = new QcfNode( d_c );\r
+ //qcfc->d_parent = qcf;\r
+ //qcf->d_child[i] = qcfc;\r
+ registerNode( n[i], newHasPol, newPol, beneathQuant );\r
+ }\r
+ }\r
+ }\r
+}\r
+\r
+void QuantInfo::flatten( Node n, bool beneathQuant ) {\r
+ Trace("qcf-qregister-debug2") << "Flatten : " << n << std::endl;\r
+ if( n.hasBoundVar() ){\r
+ if( n.getKind()==BOUND_VARIABLE ){\r
+ d_inMatchConstraint[n] = true;\r
+ }\r
+ //if( MatchGen::isHandledUfTerm( n ) || n.getKind()==ITE ){\r
+ if( d_var_num.find( n )==d_var_num.end() ){\r
+ Trace("qcf-qregister-debug2") << "Add FLATTEN VAR : " << n << std::endl;\r
+ d_var_num[n] = d_vars.size();\r
+ d_vars.push_back( n );\r
+ d_match.push_back( TNode::null() );\r
+ d_match_term.push_back( TNode::null() );\r
+ if( n.getKind()==ITE ){\r
+ registerNode( n, false, false );\r
+ }else{\r
+ for( unsigned i=0; i<n.getNumChildren(); i++ ){\r
+ flatten( n[i], beneathQuant );\r
+ }\r
+ }\r
+ }else{\r
+ Trace("qcf-qregister-debug2") << "...already processed" << std::endl;\r
+ }\r
+ }else{\r
+ Trace("qcf-qregister-debug2") << "...is ground." << std::endl;\r
+ }\r
+}\r
+\r
+\r
+void QuantInfo::reset_round( QuantConflictFind * p ) {\r
+ for( unsigned i=0; i<d_match.size(); i++ ){\r
+ d_match[i] = TNode::null();\r
+ d_match_term[i] = TNode::null();\r
+ }\r
+ d_curr_var_deq.clear();\r
+ d_tconstraints.clear();\r
+ //add built-in variable constraints\r
+ for( unsigned r=0; r<2; r++ ){\r
+ for( std::map< int, std::vector< Node > >::iterator it = d_var_constraint[r].begin();\r
+ it != d_var_constraint[r].end(); ++it ){\r
+ for( unsigned j=0; j<it->second.size(); j++ ){\r
+ Node rr = it->second[j];\r
+ if( !isVar( rr ) ){\r
+ rr = p->getRepresentative( rr );\r
+ }\r
+ if( addConstraint( p, it->first, rr, r==0 )==-1 ){\r
+ d_var_constraint[0].clear();\r
+ d_var_constraint[1].clear();\r
+ //quantified formula is actually equivalent to true\r
+ Trace("qcf-qregister") << "Quantifier is equivalent to true!!!" << std::endl;\r
+ d_mg->d_children.clear();\r
+ d_mg->d_n = NodeManager::currentNM()->mkConst( true );\r
+ d_mg->d_type = MatchGen::typ_ground;\r
+ return;\r
+ }\r
+ }\r
+ }\r
+ }\r
+ d_mg->reset_round( p );\r
+ for( std::map< int, MatchGen * >::iterator it = d_var_mg.begin(); it != d_var_mg.end(); ++it ){\r
+ it->second->reset_round( p );\r
+ }\r
+ //now, reset for matching\r
+ d_mg->reset( p, false, this );\r
+}\r
+\r
+int QuantInfo::getCurrentRepVar( int v ) {\r
+ if( v!=-1 && !d_match[v].isNull() ){\r
+ int vn = getVarNum( d_match[v] );\r
+ if( vn!=-1 ){\r
+ //int vr = getCurrentRepVar( vn );\r
+ //d_match[v] = d_vars[vr];\r
+ //return vr;\r
+ return getCurrentRepVar( vn );\r
+ }\r
+ }\r
+ return v;\r
+}\r
+\r
+TNode QuantInfo::getCurrentValue( TNode n ) {\r
+ int v = getVarNum( n );\r
+ if( v==-1 ){\r
+ return n;\r
+ }else{\r
+ if( d_match[v].isNull() ){\r
+ return n;\r
+ }else{\r
+ Assert( getVarNum( d_match[v] )!=v );\r
+ return getCurrentValue( d_match[v] );\r
+ }\r
+ }\r
+}\r
+\r
+TNode QuantInfo::getCurrentExpValue( TNode n ) {\r
+ int v = getVarNum( n );\r
+ if( v==-1 ){\r
+ return n;\r
+ }else{\r
+ if( d_match[v].isNull() ){\r
+ return n;\r
+ }else{\r
+ Assert( getVarNum( d_match[v] )!=v );\r
+ if( d_match_term[v].isNull() ){\r
+ return getCurrentValue( d_match[v] );\r
+ }else{\r
+ return d_match_term[v];\r
+ }\r
+ }\r
+ }\r
+}\r
+\r
+bool QuantInfo::getCurrentCanBeEqual( QuantConflictFind * p, int v, TNode n, bool chDiseq ) {\r
+ //check disequalities\r
+ std::map< int, std::map< TNode, int > >::iterator itd = d_curr_var_deq.find( v );\r
+ if( itd!=d_curr_var_deq.end() ){\r
+ for( std::map< TNode, int >::iterator it = itd->second.begin(); it != itd->second.end(); ++it ){\r
+ Node cv = getCurrentValue( it->first );\r
+ Debug("qcf-ccbe") << "compare " << cv << " " << n << std::endl;\r
+ if( cv==n ){\r
+ return false;\r
+ }else if( chDiseq && !isVar( n ) && !isVar( cv ) ){\r
+ //they must actually be disequal if we are looking for conflicts\r
+ if( !p->areDisequal( n, cv ) ){\r
+ //TODO : check for entailed disequal\r
+\r
+ return false;\r
+ }\r
+ }\r
+ }\r
+ }\r
+ return true;\r
+}\r
+\r
+int QuantInfo::addConstraint( QuantConflictFind * p, int v, TNode n, bool polarity ) {\r
+ v = getCurrentRepVar( v );\r
+ int vn = getVarNum( n );\r
+ vn = vn==-1 ? -1 : getCurrentRepVar( vn );\r
+ n = getCurrentValue( n );\r
+ return addConstraint( p, v, n, vn, polarity, false );\r
+}\r
+\r
+int QuantInfo::addConstraint( QuantConflictFind * p, int v, TNode n, int vn, bool polarity, bool doRemove ) {\r
+ //for handling equalities between variables, and disequalities involving variables\r
+ Debug("qcf-match-debug") << "- " << (doRemove ? "un" : "" ) << "constrain : " << v << " -> " << n << " (cv=" << getCurrentValue( n ) << ")";\r
+ Debug("qcf-match-debug") << ", (vn=" << vn << "), polarity = " << polarity << std::endl;\r
+ Assert( doRemove || n==getCurrentValue( n ) );\r
+ Assert( doRemove || v==getCurrentRepVar( v ) );\r
+ Assert( doRemove || vn==getCurrentRepVar( getVarNum( n ) ) );\r
+ if( polarity ){\r
+ if( vn!=v ){\r
+ if( doRemove ){\r
+ if( vn!=-1 ){\r
+ //if set to this in the opposite direction, clean up opposite instead\r
+ // std::map< int, TNode >::iterator itmn = d_match.find( vn );\r
+ if( d_match[vn]==d_vars[v] ){\r
+ return addConstraint( p, vn, d_vars[v], v, true, true );\r
+ }else{\r
+ //unsetting variables equal\r
+ std::map< int, std::map< TNode, int > >::iterator itd = d_curr_var_deq.find( vn );\r
+ if( itd!=d_curr_var_deq.end() ){\r
+ //remove disequalities owned by this\r
+ std::vector< TNode > remDeq;\r
+ for( std::map< TNode, int >::iterator it = itd->second.begin(); it != itd->second.end(); ++it ){\r
+ if( it->second==v ){\r
+ remDeq.push_back( it->first );\r
+ }\r
+ }\r
+ for( unsigned i=0; i<remDeq.size(); i++ ){\r
+ d_curr_var_deq[vn].erase( remDeq[i] );\r
+ }\r
+ }\r
+ }\r
+ }\r
+ d_match[v] = TNode::null();\r
+ return 1;\r
+ }else{\r
+ //std::map< int, TNode >::iterator itm = d_match.find( v );\r
+\r
+ if( vn!=-1 ){\r
+ Debug("qcf-match-debug") << " ...Variable bound to variable" << std::endl;\r
+ //std::map< int, TNode >::iterator itmn = d_match.find( vn );\r
+ if( d_match[v].isNull() ){\r
+ //setting variables equal\r
+ bool alreadySet = false;\r
+ if( !d_match[vn].isNull() ){\r
+ alreadySet = true;\r
+ Assert( !isVar( d_match[vn] ) );\r
+ }\r
+\r
+ //copy or check disequalities\r
+ std::map< int, std::map< TNode, int > >::iterator itd = d_curr_var_deq.find( v );\r
+ if( itd!=d_curr_var_deq.end() ){\r
+ for( std::map< TNode, int >::iterator it = itd->second.begin(); it != itd->second.end(); ++it ){\r
+ Node dv = getCurrentValue( it->first );\r
+ if( !alreadySet ){\r
+ if( d_curr_var_deq[vn].find( dv )==d_curr_var_deq[vn].end() ){\r
+ d_curr_var_deq[vn][dv] = v;\r
+ }\r
+ }else{\r
+ if( !p->areMatchDisequal( d_match[vn], dv ) ){\r
+ Debug("qcf-match-debug") << " -> fail, conflicting disequality" << std::endl;\r
+ return -1;\r
+ }\r
+ }\r
+ }\r
+ }\r
+ if( alreadySet ){\r
+ n = getCurrentValue( n );\r
+ }\r
+ }else{\r
+ if( d_match[vn].isNull() ){\r
+ Debug("qcf-match-debug") << " ...Reverse direction" << std::endl;\r
+ //set the opposite direction\r
+ return addConstraint( p, vn, d_vars[v], v, true, false );\r
+ }else{\r
+ Debug("qcf-match-debug") << " -> Both variables bound, compare" << std::endl;\r
+ //are they currently equal\r
+ return p->areMatchEqual( d_match[v], d_match[vn] ) ? 0 : -1;\r
+ }\r
+ }\r
+ }else{\r
+ Debug("qcf-match-debug") << " ...Variable bound to ground" << std::endl;\r
+ if( d_match[v].isNull() ){\r
+ }else{\r
+ //compare ground values\r
+ Debug("qcf-match-debug") << " -> Ground value, compare " << d_match[v] << " "<< n << std::endl;\r
+ return p->areMatchEqual( d_match[v], n ) ? 0 : -1;\r
+ }\r
+ }\r
+ if( setMatch( p, v, n ) ){\r
+ Debug("qcf-match-debug") << " -> success" << std::endl;\r
+ return 1;\r
+ }else{\r
+ Debug("qcf-match-debug") << " -> fail, conflicting disequality" << std::endl;\r
+ return -1;\r
+ }\r
+ }\r
+ }else{\r
+ Debug("qcf-match-debug") << " -> redundant, variable identity" << std::endl;\r
+ return 0;\r
+ }\r
+ }else{\r
+ if( vn==v ){\r
+ Debug("qcf-match-debug") << " -> fail, variable identity" << std::endl;\r
+ return -1;\r
+ }else{\r
+ if( doRemove ){\r
+ Assert( d_curr_var_deq[v].find( n )!=d_curr_var_deq[v].end() );\r
+ d_curr_var_deq[v].erase( n );\r
+ return 1;\r
+ }else{\r
+ if( d_curr_var_deq[v].find( n )==d_curr_var_deq[v].end() ){\r
+ //check if it respects equality\r
+ //std::map< int, TNode >::iterator itm = d_match.find( v );\r
+ if( !d_match[v].isNull() ){\r
+ TNode nv = getCurrentValue( n );\r
+ if( !p->areMatchDisequal( nv, d_match[v] ) ){\r
+ Debug("qcf-match-debug") << " -> fail, conflicting disequality" << std::endl;\r
+ return -1;\r
+ }\r
+ }\r
+ d_curr_var_deq[v][n] = v;\r
+ Debug("qcf-match-debug") << " -> success" << std::endl;\r
+ return 1;\r
+ }else{\r
+ Debug("qcf-match-debug") << " -> redundant disequality" << std::endl;\r
+ return 0;\r
+ }\r
+ }\r
+ }\r
+ }\r
+}\r
+\r
+bool QuantInfo::isConstrainedVar( int v ) {\r
+ if( d_curr_var_deq.find( v )!=d_curr_var_deq.end() && !d_curr_var_deq[v].empty() ){\r
+ return true;\r
+ }else{\r
+ Node vv = getVar( v );\r
+ //for( std::map< int, TNode >::iterator it = d_match.begin(); it != d_match.end(); ++it ){\r
+ for( unsigned i=0; i<d_match.size(); i++ ){\r
+ if( d_match[i]==vv ){\r
+ return true;\r
+ }\r
+ }\r
+ for( std::map< int, std::map< TNode, int > >::iterator it = d_curr_var_deq.begin(); it != d_curr_var_deq.end(); ++it ){\r
+ for( std::map< TNode, int >::iterator it2 = it->second.begin(); it2 != it->second.end(); ++it2 ){\r
+ if( it2->first==vv ){\r
+ return true;\r
+ }\r
+ }\r
+ }\r
+ return false;\r
+ }\r
+}\r
+\r
+bool QuantInfo::setMatch( QuantConflictFind * p, int v, TNode n ) {\r
+ if( getCurrentCanBeEqual( p, v, n ) ){\r
+ Debug("qcf-match-debug") << "-- bind : " << v << " -> " << n << ", checked " << d_curr_var_deq[v].size() << " disequalities" << std::endl;\r
+ d_match[v] = n;\r
+ return true;\r
+ }else{\r
+ return false;\r
+ }\r
+}\r
+\r
+bool QuantInfo::isMatchSpurious( QuantConflictFind * p ) {\r
+ for( int i=0; i<getNumVars(); i++ ){\r
+ //std::map< int, TNode >::iterator it = d_match.find( i );\r
+ if( !d_match[i].isNull() ){\r
+ if( !getCurrentCanBeEqual( p, i, d_match[i], p->d_effort==QuantConflictFind::effort_conflict ) ){\r
+ return true;\r
+ }\r
+ }\r
+ }\r
+ return false;\r
+}\r
+\r
+bool QuantInfo::isTConstraintSpurious( QuantConflictFind * p, std::vector< Node >& terms ) {\r
+ if( !d_tconstraints.empty() ){\r
+ //check constraints\r
+ for( std::map< Node, bool >::iterator it = d_tconstraints.begin(); it != d_tconstraints.end(); ++it ){\r
+ //apply substitution to the tconstraint\r
+ Node cons = it->first.substitute( p->getQuantifiersEngine()->getTermDatabase()->d_vars[d_q].begin(),\r
+ p->getQuantifiersEngine()->getTermDatabase()->d_vars[d_q].end(),\r
+ terms.begin(), terms.end() );\r
+ cons = it->second ? cons : cons.negate();\r
+ if( !entailmentTest( p, cons, p->d_effort==QuantConflictFind::effort_conflict ) ){\r
+ return true;\r
+ }\r
+ }\r
+ }\r
+ return false;\r
+}\r
+\r
+bool QuantInfo::entailmentTest( QuantConflictFind * p, Node lit, bool chEnt ) {\r
+ Trace("qcf-tconstraint-debug") << "Check : " << lit << std::endl;\r
+ Node rew = Rewriter::rewrite( lit );\r
+ if( rew==p->d_false ){\r
+ Trace("qcf-tconstraint-debug") << "...constraint " << lit << " is disentailed (rewrites to false)." << std::endl;\r
+ return false;\r
+ }else if( rew!=p->d_true ){\r
+ //if checking for conflicts, we must be sure that the constraint is entailed\r
+ if( chEnt ){\r
+ //check if it is entailed\r
+ Trace("qcf-tconstraint-debug") << "Check entailment of " << rew << "..." << std::endl;\r
+ std::pair<bool, Node> et = p->getQuantifiersEngine()->getTheoryEngine()->entailmentCheck(THEORY_OF_TYPE_BASED, rew );\r
+ ++(p->d_statistics.d_entailment_checks);\r
+ Trace("qcf-tconstraint-debug") << "ET result : " << et.first << " " << et.second << std::endl;\r
+ if( !et.first ){\r
+ Trace("qcf-tconstraint-debug") << "...cannot show entailment of " << rew << "." << std::endl;\r
+ return false;\r
+ }else{\r
+ return true;\r
+ }\r
+ }else{\r
+ Trace("qcf-tconstraint-debug") << "...does not need to be entailed." << std::endl;\r
+ return true;\r
+ }\r
+ }else{\r
+ Trace("qcf-tconstraint-debug") << "...rewrites to true." << std::endl;\r
+ return true;\r
+ }\r
+}\r
+\r
+bool QuantInfo::completeMatch( QuantConflictFind * p, std::vector< int >& assigned, bool doContinue ) {\r
+ //assign values for variables that were unassigned (usually not necessary, but handles corner cases)\r
+ bool doFail = false;\r
+ bool success = true;\r
+ if( doContinue ){\r
+ doFail = true;\r
+ success = false;\r
+ }else{\r
+ //solve for interpreted symbol matches\r
+ // this breaks the invariant that all introduced constraints are over existing terms\r
+ for( int i=(int)(d_tsym_vars.size()-1); i>=0; i-- ){\r
+ int index = d_tsym_vars[i];\r
+ TNode v = getCurrentValue( d_vars[index] );\r
+ int slv_v = -1;\r
+ if( v==d_vars[index] ){\r
+ slv_v = index;\r
+ }\r
+ Trace("qcf-tconstraint-debug") << "Solve " << d_vars[index] << " = " << v << " " << d_vars[index].getKind() << std::endl;\r
+ if( d_vars[index].getKind()==PLUS || d_vars[index].getKind()==MULT ){\r
+ Kind k = d_vars[index].getKind();\r
+ std::vector< TNode > children;\r
+ for( unsigned j=0; j<d_vars[index].getNumChildren(); j++ ){\r
+ int vn = getVarNum( d_vars[index][j] );\r
+ if( vn!=-1 ){\r
+ TNode vv = getCurrentValue( d_vars[index][j] );\r
+ if( vv==d_vars[index][j] ){\r
+ //we will assign this\r
+ if( slv_v==-1 ){\r
+ Trace("qcf-tconstraint-debug") << "...will solve for var #" << vn << std::endl;\r
+ slv_v = vn;\r
+ if( p->d_effort!=QuantConflictFind::effort_conflict ){\r
+ break;\r
+ }\r
+ }else{\r
+ Node z = p->getZero( k );\r
+ if( !z.isNull() ){\r
+ Trace("qcf-tconstraint-debug") << "...set " << d_vars[vn] << " = " << z << std::endl;\r
+ assigned.push_back( vn );\r
+ if( !setMatch( p, vn, z ) ){\r
+ success = false;\r
+ break;\r
+ }\r
+ }\r
+ }\r
+ }else{\r
+ Trace("qcf-tconstraint-debug") << "...sum value " << vv << std::endl;\r
+ children.push_back( vv );\r
+ }\r
+ }else{\r
+ Trace("qcf-tconstraint-debug") << "...sum " << d_vars[index][j] << std::endl;\r
+ children.push_back( d_vars[index][j] );\r
+ }\r
+ }\r
+ if( success ){\r
+ if( slv_v!=-1 ){\r
+ Node lhs;\r
+ if( children.empty() ){\r
+ lhs = p->getZero( k );\r
+ }else if( children.size()==1 ){\r
+ lhs = children[0];\r
+ }else{\r
+ lhs = NodeManager::currentNM()->mkNode( k, children );\r
+ }\r
+ Node sum;\r
+ if( v==d_vars[index] ){\r
+ sum = lhs;\r
+ }else{\r
+ if( p->d_effort==QuantConflictFind::effort_conflict ){\r
+ Kind kn = k;\r
+ if( d_vars[index].getKind()==PLUS ){\r
+ kn = MINUS;\r
+ }\r
+ if( kn!=k ){\r
+ sum = NodeManager::currentNM()->mkNode( kn, v, lhs );\r
+ }\r
+ }\r
+ }\r
+ if( !sum.isNull() ){\r
+ assigned.push_back( slv_v );\r
+ Trace("qcf-tconstraint-debug") << "...set " << d_vars[slv_v] << " = " << sum << std::endl;\r
+ if( !setMatch( p, slv_v, sum ) ){\r
+ success = false;\r
+ }\r
+ p->d_tempCache.push_back( sum );\r
+ }\r
+ }else{\r
+ //must show that constraint is met\r
+ Node sum = NodeManager::currentNM()->mkNode( k, children );\r
+ Node eq = sum.eqNode( v );\r
+ if( !entailmentTest( p, eq ) ){\r
+ success = false;\r
+ }\r
+ p->d_tempCache.push_back( sum );\r
+ }\r
+ }\r
+ }\r
+\r
+ if( !success ){\r
+ break;\r
+ }\r
+ }\r
+ if( success ){\r
+ //check what is left to assign\r
+ d_unassigned.clear();\r
+ d_unassigned_tn.clear();\r
+ std::vector< int > unassigned[2];\r
+ std::vector< TypeNode > unassigned_tn[2];\r
+ for( int i=0; i<getNumVars(); i++ ){\r
+ if( d_match[i].isNull() ){\r
+ int rindex = d_var_mg.find( i )==d_var_mg.end() ? 1 : 0;\r
+ unassigned[rindex].push_back( i );\r
+ unassigned_tn[rindex].push_back( getVar( i ).getType() );\r
+ assigned.push_back( i );\r
+ }\r
+ }\r
+ d_unassigned_nvar = unassigned[0].size();\r
+ for( unsigned i=0; i<2; i++ ){\r
+ d_unassigned.insert( d_unassigned.end(), unassigned[i].begin(), unassigned[i].end() );\r
+ d_unassigned_tn.insert( d_unassigned_tn.end(), unassigned_tn[i].begin(), unassigned_tn[i].end() );\r
+ }\r
+ d_una_eqc_count.clear();\r
+ d_una_index = 0;\r
+ }\r
+ }\r
+\r
+ if( !d_unassigned.empty() && ( success || doContinue ) ){\r
+ Trace("qcf-check") << "Assign to unassigned..." << std::endl;\r
+ do {\r
+ if( doFail ){\r
+ Trace("qcf-check-unassign") << "Failure, try again..." << std::endl;\r
+ }\r
+ bool invalidMatch = false;\r
+ while( ( d_una_index>=0 && (int)d_una_index<(int)d_unassigned.size() ) || invalidMatch || doFail ){\r
+ invalidMatch = false;\r
+ if( !doFail && d_una_index==(int)d_una_eqc_count.size() ){\r
+ //check if it has now been assigned\r
+ if( d_una_index<d_unassigned_nvar ){\r
+ if( !isConstrainedVar( d_unassigned[d_una_index] ) ){\r
+ d_una_eqc_count.push_back( -1 );\r
+ }else{\r
+ d_var_mg[ d_unassigned[d_una_index] ]->reset( p, true, this );\r
+ d_una_eqc_count.push_back( 0 );\r
+ }\r
+ }else{\r
+ d_una_eqc_count.push_back( 0 );\r
+ }\r
+ }else{\r
+ bool failed = false;\r
+ if( !doFail ){\r
+ if( d_una_index<d_unassigned_nvar ){\r
+ if( !isConstrainedVar( d_unassigned[d_una_index] ) ){\r
+ Trace("qcf-check-unassign") << "Succeeded, variable unconstrained at " << d_una_index << std::endl;\r
+ d_una_index++;\r
+ }else if( d_var_mg[d_unassigned[d_una_index]]->getNextMatch( p, this ) ){\r
+ Trace("qcf-check-unassign") << "Succeeded match with mg at " << d_una_index << std::endl;\r
+ d_una_index++;\r
+ }else{\r
+ failed = true;\r
+ Trace("qcf-check-unassign") << "Failed match with mg at " << d_una_index << std::endl;\r
+ }\r
+ }else{\r
+ Assert( doFail || d_una_index==(int)d_una_eqc_count.size()-1 );\r
+ if( d_una_eqc_count[d_una_index]<(int)p->d_eqcs[d_unassigned_tn[d_una_index]].size() ){\r
+ int currIndex = d_una_eqc_count[d_una_index];\r
+ d_una_eqc_count[d_una_index]++;\r
+ Trace("qcf-check-unassign") << d_unassigned[d_una_index] << "->" << p->d_eqcs[d_unassigned_tn[d_una_index]][currIndex] << std::endl;\r
+ if( setMatch( p, d_unassigned[d_una_index], p->d_eqcs[d_unassigned_tn[d_una_index]][currIndex] ) ){\r
+ d_match_term[d_unassigned[d_una_index]] = TNode::null();\r
+ Trace("qcf-check-unassign") << "Succeeded match " << d_una_index << std::endl;\r
+ d_una_index++;\r
+ }else{\r
+ Trace("qcf-check-unassign") << "Failed match " << d_una_index << std::endl;\r
+ invalidMatch = true;\r
+ }\r
+ }else{\r
+ failed = true;\r
+ Trace("qcf-check-unassign") << "No more matches " << d_una_index << std::endl;\r
+ }\r
+ }\r
+ }\r
+ if( doFail || failed ){\r
+ do{\r
+ if( !doFail ){\r
+ d_una_eqc_count.pop_back();\r
+ }else{\r
+ doFail = false;\r
+ }\r
+ d_una_index--;\r
+ }while( d_una_index>=0 && d_una_eqc_count[d_una_index]==-1 );\r
+ }\r
+ }\r
+ }\r
+ success = d_una_index>=0;\r
+ if( success ){\r
+ doFail = true;\r
+ Trace("qcf-check-unassign") << " Try: " << std::endl;\r
+ for( unsigned i=0; i<d_unassigned.size(); i++ ){\r
+ int ui = d_unassigned[i];\r
+ if( !d_match[ui].isNull() ){\r
+ Trace("qcf-check-unassign") << " Assigned #" << ui << " : " << d_vars[ui] << " -> " << d_match[ui] << std::endl;\r
+ }\r
+ }\r
+ }\r
+ }while( success && isMatchSpurious( p ) );\r
+ }\r
+ if( success ){\r
+ for( unsigned i=0; i<d_unassigned.size(); i++ ){\r
+ int ui = d_unassigned[i];\r
+ if( !d_match[ui].isNull() ){\r
+ Trace("qcf-check") << " Assigned #" << ui << " : " << d_vars[ui] << " -> " << d_match[ui] << std::endl;\r
+ }\r
+ }\r
+ return true;\r
+ }else{\r
+ for( unsigned i=0; i<assigned.size(); i++ ){\r
+ d_match[ assigned[i] ] = TNode::null();\r
+ }\r
+ assigned.clear();\r
+ return false;\r
+ }\r
+}\r
+\r
+void QuantInfo::getMatch( std::vector< Node >& terms ){\r
+ for( unsigned i=0; i<d_q[0].getNumChildren(); i++ ){\r
+ //Node cv = qi->getCurrentValue( qi->d_match[i] );\r
+ int repVar = getCurrentRepVar( i );\r
+ Node cv;\r
+ //std::map< int, TNode >::iterator itmt = qi->d_match_term.find( repVar );\r
+ if( !d_match_term[repVar].isNull() ){\r
+ cv = d_match_term[repVar];\r
+ }else{\r
+ cv = d_match[repVar];\r
+ }\r
+ Debug("qcf-check-inst") << "INST : " << i << " -> " << cv << ", from " << d_match[i] << std::endl;\r
+ terms.push_back( cv );\r
+ }\r
+}\r
+\r
+void QuantInfo::revertMatch( std::vector< int >& assigned ) {\r
+ for( unsigned i=0; i<assigned.size(); i++ ){\r
+ d_match[ assigned[i] ] = TNode::null();\r
+ }\r
+}\r
+\r
+void QuantInfo::debugPrintMatch( const char * c ) {\r
+ for( int i=0; i<getNumVars(); i++ ){\r
+ Trace(c) << " " << d_vars[i] << " -> ";\r
+ if( !d_match[i].isNull() ){\r
+ Trace(c) << d_match[i];\r
+ }else{\r
+ Trace(c) << "(unassigned) ";\r
+ }\r
+ if( !d_curr_var_deq[i].empty() ){\r
+ Trace(c) << ", DEQ{ ";\r
+ for( std::map< TNode, int >::iterator it = d_curr_var_deq[i].begin(); it != d_curr_var_deq[i].end(); ++it ){\r
+ Trace(c) << it->first << " ";\r
+ }\r
+ Trace(c) << "}";\r
+ }\r
+ if( !d_match_term[i].isNull() && d_match_term[i]!=d_match[i] ){\r
+ Trace(c) << ", EXP : " << d_match_term[i];\r
+ }\r
+ Trace(c) << std::endl;\r
+ }\r
+ if( !d_tconstraints.empty() ){\r
+ Trace(c) << "ADDITIONAL CONSTRAINTS : " << std::endl;\r
+ for( std::map< Node, bool >::iterator it = d_tconstraints.begin(); it != d_tconstraints.end(); ++it ){\r
+ Trace(c) << " " << it->first << " -> " << it->second << std::endl;\r
+ }\r
+ }\r
+}\r
+\r
+MatchGen::MatchGen( QuantInfo * qi, Node n, bool isVar ){\r
+ Trace("qcf-qregister-debug") << "Make match gen for " << n << ", isVar = " << isVar << std::endl;\r
+ std::vector< Node > qni_apps;\r
+ d_qni_size = 0;\r
+ if( isVar ){\r
+ Assert( qi->d_var_num.find( n )!=qi->d_var_num.end() );\r
+ if( n.getKind()==ITE ){\r
+ d_type = typ_ite_var;\r
+ d_type_not = false;\r
+ d_n = n;\r
+ d_children.push_back( MatchGen( qi, d_n[0] ) );\r
+ if( d_children[0].isValid() ){\r
+ d_type = typ_ite_var;\r
+ for( unsigned i=1; i<=2; i++ ){\r
+ Node nn = n.eqNode( n[i] );\r
+ d_children.push_back( MatchGen( qi, nn ) );\r
+ d_children[d_children.size()-1].d_qni_bound_except.push_back( 0 );\r
+ if( !d_children[d_children.size()-1].isValid() ){\r
+ setInvalid();\r
+ break;\r
+ }\r
+ }\r
+ }else{\r
+ d_type = typ_invalid;\r
+ }\r
+ }else{\r
+ d_type = isHandledUfTerm( n ) ? typ_var : typ_tsym;\r
+ d_qni_var_num[0] = qi->getVarNum( n );\r
+ d_qni_size++;\r
+ d_type_not = false;\r
+ d_n = n;\r
+ //Node f = getOperator( n );\r
+ for( unsigned j=0; j<d_n.getNumChildren(); j++ ){\r
+ Node nn = d_n[j];\r
+ Trace("qcf-qregister-debug") << " " << d_qni_size;\r
+ if( qi->isVar( nn ) ){\r
+ int v = qi->d_var_num[nn];\r
+ Trace("qcf-qregister-debug") << " is var #" << v << std::endl;\r
+ d_qni_var_num[d_qni_size] = v;\r
+ //qi->addFuncParent( v, f, j );\r
+ }else{\r
+ Trace("qcf-qregister-debug") << " is gterm " << nn << std::endl;\r
+ d_qni_gterm[d_qni_size] = nn;\r
+ }\r
+ d_qni_size++;\r
+ }\r
+ }\r
+ }else{\r
+ if( n.hasBoundVar() ){\r
+ d_type_not = false;\r
+ d_n = n;\r
+ if( d_n.getKind()==NOT ){\r
+ d_n = d_n[0];\r
+ d_type_not = !d_type_not;\r
+ }\r
+\r
+ if( isHandledBoolConnective( d_n ) ){\r
+ //non-literals\r
+ d_type = typ_formula;\r
+ for( unsigned i=0; i<d_n.getNumChildren(); i++ ){\r
+ if( d_n.getKind()!=FORALL || i==1 ){\r
+ d_children.push_back( MatchGen( qi, d_n[i], false ) );\r
+ if( !d_children[d_children.size()-1].isValid() ){\r
+ setInvalid();\r
+ break;\r
+ }\r
+ }\r
+ /*\r
+ else if( isTop && n.getKind()==OR && d_children[d_children.size()-1].d_type==typ_var_eq ){\r
+ Trace("qcf-qregister-debug") << "Remove child, make built-in constraint" << std::endl;\r
+ //if variable equality/disequality at top level, remove immediately\r
+ bool cIsNot = d_children[d_children.size()-1].d_type_not;\r
+ Node cn = d_children[d_children.size()-1].d_n;\r
+ Assert( cn.getKind()==EQUAL );\r
+ Assert( p->d_qinfo[q].isVar( cn[0] ) || p->d_qinfo[q].isVar( cn[1] ) );\r
+ //make it a built-in constraint instead\r
+ for( unsigned i=0; i<2; i++ ){\r
+ if( p->d_qinfo[q].isVar( cn[i] ) ){\r
+ int v = p->d_qinfo[q].getVarNum( cn[i] );\r
+ Node cno = cn[i==0 ? 1 : 0];\r
+ p->d_qinfo[q].d_var_constraint[ cIsNot ? 0 : 1 ][v].push_back( cno );\r
+ break;\r
+ }\r
+ }\r
+ d_children.pop_back();\r
+ }\r
+ */\r
+ }\r
+ }else{\r
+ d_type = typ_invalid;\r
+ //literals\r
+ if( isHandledUfTerm( d_n ) ){\r
+ Assert( qi->isVar( d_n ) );\r
+ d_type = typ_pred;\r
+ }else if( d_n.getKind()==BOUND_VARIABLE ){\r
+ Assert( d_n.getType().isBoolean() );\r
+ d_type = typ_bool_var;\r
+ }else if( d_n.getKind()==EQUAL || options::qcfTConstraint() ){\r
+ for( unsigned i=0; i<d_n.getNumChildren(); i++ ){\r
+ if( d_n[i].hasBoundVar() ){\r
+ if( !qi->isVar( d_n[i] ) ){\r
+ Trace("qcf-qregister-debug") << "ERROR : not var " << d_n[i] << std::endl;\r
+ }\r
+ Assert( qi->isVar( d_n[i] ) );\r
+ if( d_n.getKind()!=EQUAL && qi->isVar( d_n[i] ) ){\r
+ d_qni_var_num[i+1] = qi->d_var_num[d_n[i]];\r
+ }\r
+ }else{\r
+ d_qni_gterm[i] = d_n[i];\r
+ }\r
+ }\r
+ d_type = d_n.getKind()==EQUAL ? typ_eq : typ_tconstraint;\r
+ Trace("qcf-tconstraint") << "T-Constraint : " << d_n << std::endl;\r
+ }\r
+ }\r
+ }else{\r
+ //we will just evaluate\r
+ d_n = n;\r
+ d_type = typ_ground;\r
+ }\r
+ //if( d_type!=typ_invalid ){\r
+ //determine an efficient children ordering\r
+ //if( !d_children.empty() ){\r
+ //for( unsigned i=0; i<d_children.size(); i++ ){\r
+ // d_children_order.push_back( i );\r
+ //}\r
+ //if( !d_n.isNull() && ( d_n.getKind()==OR || d_n.getKind()==AND || d_n.getKind()==IFF ) ){\r
+ //sort based on the type of the constraint : ground comes first, then literals, then others\r
+ //MatchGenSort mgs;\r
+ //mgs.d_mg = this;\r
+ //std::sort( d_children_order.begin(), d_children_order.end(), mgs );\r
+ //}\r
+ //}\r
+ //}\r
+ }\r
+ Trace("qcf-qregister-debug") << "Done make match gen " << n << ", type = ";\r
+ debugPrintType( "qcf-qregister-debug", d_type, true );\r
+ Trace("qcf-qregister-debug") << std::endl;\r
+ //Assert( d_children.size()==d_children_order.size() );\r
+\r
+}\r
+\r
+void MatchGen::collectBoundVar( QuantInfo * qi, Node n, std::vector< int >& cbvars ) {\r
+ int v = qi->getVarNum( n );\r
+ if( v!=-1 && std::find( cbvars.begin(), cbvars.end(), v )==cbvars.end() ){\r
+ cbvars.push_back( v );\r
+ }\r
+ for( unsigned i=0; i<n.getNumChildren(); i++ ){\r
+ collectBoundVar( qi, n[i], cbvars );\r
+ }\r
+}\r
+\r
+void MatchGen::determineVariableOrder( QuantInfo * qi, std::vector< int >& bvars ) {\r
+ Trace("qcf-qregister-debug") << "Determine variable order " << d_n << std::endl;\r
+ bool isCom = d_type==typ_formula && ( d_n.getKind()==OR || d_n.getKind()==AND || d_n.getKind()==IFF );\r
+ std::map< int, std::vector< int > > c_to_vars;\r
+ std::map< int, std::vector< int > > vars_to_c;\r
+ std::map< int, int > vb_count;\r
+ std::map< int, int > vu_count;\r
+ std::vector< bool > assigned;\r
+ Trace("qcf-qregister-debug") << "Calculate bound variables..." << std::endl;\r
+ for( unsigned i=0; i<d_children.size(); i++ ){\r
+ collectBoundVar( qi, d_children[i].d_n, c_to_vars[i] );\r
+ assigned.push_back( false );\r
+ vb_count[i] = 0;\r
+ vu_count[i] = 0;\r
+ for( unsigned j=0; j<c_to_vars[i].size(); j++ ){\r
+ int v = c_to_vars[i][j];\r
+ vars_to_c[v].push_back( i );\r
+ if( std::find( bvars.begin(), bvars.end(), v )==bvars.end() ){\r
+ vu_count[i]++;\r
+ if( !isCom ){\r
+ bvars.push_back( v );\r
+ }\r
+ }else{\r
+ vb_count[i]++;\r
+ }\r
+ }\r
+ }\r
+ if( isCom ){\r
+ //children that bind the least number of unbound variables go first\r
+ do {\r
+ int min_score = -1;\r
+ int min_score_index = -1;\r
+ for( unsigned i=0; i<d_children.size(); i++ ){\r
+ if( !assigned[i] ){\r
+ int score = vu_count[i];\r
+ if( min_score==-1 || score<min_score ){\r
+ min_score = score;\r
+ min_score_index = i;\r
+ }\r
+ }\r
+ }\r
+ Trace("qcf-qregister-debug") << "...assign child " << min_score_index << "/" << d_children.size() << std::endl;\r
+ Assert( min_score_index!=-1 );\r
+ //add to children order\r
+ d_children_order.push_back( min_score_index );\r
+ assigned[min_score_index] = true;\r
+ //if( vb_count[min_score_index]==0 ){\r
+ // d_independent.push_back( min_score_index );\r
+ //}\r
+ //determine order internal to children\r
+ d_children[min_score_index].determineVariableOrder( qi, bvars );\r
+ Trace("qcf-qregister-debug") << "...bind variables" << std::endl;\r
+ //now, make it a bound variable\r
+ for( unsigned i=0; i<c_to_vars[min_score_index].size(); i++ ){\r
+ int v = c_to_vars[min_score_index][i];\r
+ if( std::find( bvars.begin(), bvars.end(), v )==bvars.end() ){\r
+ for( unsigned j=0; j<vars_to_c[v].size(); j++ ){\r
+ int vc = vars_to_c[v][j];\r
+ vu_count[vc]--;\r
+ vb_count[vc]++;\r
+ }\r
+ bvars.push_back( v );\r
+ }\r
+ }\r
+ Trace("qcf-qregister-debug") << "...done assign child " << min_score_index << std::endl;\r
+ }while( d_children_order.size()!=d_children.size() );\r
+ Trace("qcf-qregister-debug") << "Done assign variable ordering for " << d_n << std::endl;\r
+ }else{\r
+ for( unsigned i=0; i<d_children.size(); i++ ){\r
+ d_children_order.push_back( i );\r
+ d_children[i].determineVariableOrder( qi, bvars );\r
+ }\r
+ }\r
+}\r
+\r
+\r
+void MatchGen::reset_round( QuantConflictFind * p ) {\r
+ d_wasSet = false;\r
+ for( unsigned i=0; i<d_children.size(); i++ ){\r
+ d_children[i].reset_round( p );\r
+ }\r
+ for( std::map< int, TNode >::iterator it = d_qni_gterm.begin(); it != d_qni_gterm.end(); ++it ){\r
+ d_qni_gterm_rep[it->first] = p->getRepresentative( it->second );\r
+ }\r
+ if( d_type==typ_ground ){\r
+ int e = p->evaluate( d_n );\r
+ if( e==1 ){\r
+ d_ground_eval[0] = p->d_true;\r
+ }else if( e==-1 ){\r
+ d_ground_eval[0] = p->d_false;\r
+ }\r
+ }else if( d_type==typ_eq ){\r
+ for( unsigned i=0; i<d_n.getNumChildren(); i++ ){\r
+ if( !d_n[i].hasBoundVar() ){\r
+ d_ground_eval[i] = p->evaluateTerm( d_n[i] );\r
+ }\r
+ }\r
+ }\r
+ d_qni_bound_cons.clear();\r
+ d_qni_bound_cons_var.clear();\r
+ d_qni_bound.clear();\r
+}\r
+\r
+void MatchGen::reset( QuantConflictFind * p, bool tgt, QuantInfo * qi ) {\r
+ d_tgt = d_type_not ? !tgt : tgt;\r
+ Debug("qcf-match") << " Reset for : " << d_n << ", type : ";\r
+ debugPrintType( "qcf-match", d_type );\r
+ Debug("qcf-match") << ", tgt = " << d_tgt << ", children = " << d_children.size() << " " << d_children_order.size() << std::endl;\r
+ d_qn.clear();\r
+ d_qni.clear();\r
+ d_qni_bound.clear();\r
+ d_child_counter = -1;\r
+ d_tgt_orig = d_tgt;\r
+\r
+ //set up processing matches\r
+ if( d_type==typ_invalid ){\r
+ //do nothing\r
+ }else if( d_type==typ_ground ){\r
+ if( d_ground_eval[0]==( d_tgt ? p->d_true : p->d_false ) ){\r
+ d_child_counter = 0;\r
+ }\r
+ }else if( d_type==typ_bool_var ){\r
+ //get current value of the variable\r
+ TNode n = qi->getCurrentValue( d_n );\r
+ int vn = qi->getCurrentRepVar( qi->getVarNum( n ) );\r
+ if( vn==-1 ){\r
+ //evaluate the value, see if it is compatible\r
+ int e = p->evaluate( n );\r
+ if( ( e==1 && d_tgt ) || ( e==0 && !d_tgt ) ){\r
+ d_child_counter = 0;\r
+ }\r
+ }else{\r
+ //unassigned, set match to true/false\r
+ d_qni_bound[0] = vn;\r
+ qi->setMatch( p, vn, d_tgt ? p->d_true : p->d_false );\r
+ d_child_counter = 0;\r
+ }\r
+ if( d_child_counter==0 ){\r
+ d_qn.push_back( NULL );\r
+ }\r
+ }else if( d_type==typ_var ){\r
+ Assert( isHandledUfTerm( d_n ) );\r
+ Node f = getOperator( p, d_n );\r
+ Debug("qcf-match-debug") << " reset: Var will match operators of " << f << std::endl;\r
+ TermArgTrie * qni = p->getTermDatabase()->getTermArgTrie( Node::null(), f );\r
+ if( qni!=NULL ){\r
+ d_qn.push_back( qni );\r
+ }\r
+ d_matched_basis = false;\r
+ }else if( d_type==typ_tsym || d_type==typ_tconstraint ){\r
+ for( std::map< int, int >::iterator it = d_qni_var_num.begin(); it != d_qni_var_num.end(); ++it ){\r
+ int repVar = qi->getCurrentRepVar( it->second );\r
+ if( qi->d_match[repVar].isNull() ){\r
+ Debug("qcf-match-debug") << "Force matching on child #" << it->first << ", which is var #" << repVar << std::endl;\r
+ d_qni_bound[it->first] = repVar;\r
+ }\r
+ }\r
+ d_qn.push_back( NULL );\r
+ }else if( d_type==typ_pred || d_type==typ_eq ){\r
+ //add initial constraint\r
+ Node nn[2];\r
+ int vn[2];\r
+ if( d_type==typ_pred ){\r
+ nn[0] = qi->getCurrentValue( d_n );\r
+ vn[0] = qi->getCurrentRepVar( qi->getVarNum( nn[0] ) );\r
+ nn[1] = p->getRepresentative( d_tgt ? p->d_true : p->d_false );\r
+ vn[1] = -1;\r
+ d_tgt = true;\r
+ }else{\r
+ for( unsigned i=0; i<2; i++ ){\r
+ TNode nc;\r
+ std::map< int, TNode >::iterator it = d_qni_gterm_rep.find( i );\r
+ if( it!=d_qni_gterm_rep.end() ){\r
+ nc = it->second;\r
+ }else{\r
+ nc = d_n[i];\r
+ }\r
+ nn[i] = qi->getCurrentValue( nc );\r
+ vn[i] = qi->getCurrentRepVar( qi->getVarNum( nn[i] ) );\r
+ }\r
+ }\r
+ bool success;\r
+ if( vn[0]==-1 && vn[1]==-1 ){\r
+ //Trace("qcf-explain") << " reset : " << d_n << " check ground values " << nn[0] << " " << nn[1] << " (tgt=" << d_tgt << ")" << std::endl;\r
+ Debug("qcf-match-debug") << " reset: check ground values " << nn[0] << " " << nn[1] << " (" << d_tgt << ")" << std::endl;\r
+ //just compare values\r
+ if( d_tgt ){\r
+ success = p->areMatchEqual( nn[0], nn[1] );\r
+ }else{\r
+ if( p->d_effort==QuantConflictFind::effort_conflict ){\r
+ success = p->areDisequal( nn[0], nn[1] );\r
+ }else{\r
+ success = p->areMatchDisequal( nn[0], nn[1] );\r
+ }\r
+ }\r
+ }else{\r
+ //otherwise, add a constraint to a variable\r
+ if( vn[1]!=-1 && vn[0]==-1 ){\r
+ //swap\r
+ Node t = nn[1];\r
+ nn[1] = nn[0];\r
+ nn[0] = t;\r
+ vn[0] = vn[1];\r
+ vn[1] = -1;\r
+ }\r
+ Debug("qcf-match-debug") << " reset: add constraint " << vn[0] << " -> " << nn[1] << " (vn=" << vn[1] << ")" << std::endl;\r
+ //add some constraint\r
+ int addc = qi->addConstraint( p, vn[0], nn[1], vn[1], d_tgt, false );\r
+ success = addc!=-1;\r
+ //if successful and non-redundant, store that we need to cleanup this\r
+ if( addc==1 ){\r
+ //Trace("qcf-explain") << " reset: " << d_n << " add constraint " << vn[0] << " -> " << nn[1] << " (vn=" << vn[1] << ")" << ", d_tgt = " << d_tgt << std::endl;\r
+ for( unsigned i=0; i<2; i++ ){\r
+ if( vn[i]!=-1 && std::find( d_qni_bound_except.begin(), d_qni_bound_except.end(), i )==d_qni_bound_except.end() ){\r
+ d_qni_bound[vn[i]] = vn[i];\r
+ }\r
+ }\r
+ d_qni_bound_cons[vn[0]] = nn[1];\r
+ d_qni_bound_cons_var[vn[0]] = vn[1];\r
+ }\r
+ }\r
+ //if successful, we will bind values to variables\r
+ if( success ){\r
+ d_qn.push_back( NULL );\r
+ }\r
+ }else{\r
+ if( d_children.empty() ){\r
+ //add dummy\r
+ d_qn.push_back( NULL );\r
+ }else{\r
+ if( d_tgt && d_n.getKind()==FORALL ){\r
+ //do nothing\r
+ }else{\r
+ //reset the first child to d_tgt\r
+ d_child_counter = 0;\r
+ getChild( d_child_counter )->reset( p, d_tgt, qi );\r
+ }\r
+ }\r
+ }\r
+ d_binding = false;\r
+ d_wasSet = true;\r
+ Debug("qcf-match") << " reset: Finished reset for " << d_n << ", success = " << ( !d_qn.empty() || d_child_counter!=-1 ) << std::endl;\r
+}\r
+\r
+bool MatchGen::getNextMatch( QuantConflictFind * p, QuantInfo * qi ) {\r
+ Debug("qcf-match") << " Get next match for : " << d_n << ", type = ";\r
+ debugPrintType( "qcf-match", d_type );\r
+ Debug("qcf-match") << ", children = " << d_children.size() << ", binding = " << d_binding << std::endl;\r
+ if( d_type==typ_invalid || d_type==typ_ground ){\r
+ if( d_child_counter==0 ){\r
+ d_child_counter = -1;\r
+ return true;\r
+ }else{\r
+ d_wasSet = false;\r
+ return false;\r
+ }\r
+ }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 ){\r
+ bool success = false;\r
+ bool terminate = false;\r
+ do {\r
+ bool doReset = false;\r
+ bool doFail = false;\r
+ if( !d_binding ){\r
+ if( doMatching( p, qi ) ){\r
+ Debug("qcf-match-debug") << " - Matching succeeded" << std::endl;\r
+ d_binding = true;\r
+ d_binding_it = d_qni_bound.begin();\r
+ doReset = true;\r
+ //for tconstraint, add constraint\r
+ if( d_type==typ_tconstraint ){\r
+ std::map< Node, bool >::iterator it = qi->d_tconstraints.find( d_n );\r
+ if( it==qi->d_tconstraints.end() ){\r
+ qi->d_tconstraints[d_n] = d_tgt;\r
+ //store that we added this constraint\r
+ d_qni_bound_cons[0] = d_n;\r
+ }else if( d_tgt!=it->second ){\r
+ success = false;\r
+ terminate = true;\r
+ }\r
+ }\r
+ }else{\r
+ Debug("qcf-match-debug") << " - Matching failed" << std::endl;\r
+ success = false;\r
+ terminate = true;\r
+ }\r
+ }else{\r
+ doFail = true;\r
+ }\r
+ if( d_binding ){\r
+ //also need to create match for each variable we bound\r
+ success = true;\r
+ Debug("qcf-match-debug") << " Produce matches for bound variables by " << d_n << ", type = ";\r
+ debugPrintType( "qcf-match-debug", d_type );\r
+ Debug("qcf-match-debug") << "..." << std::endl;\r
+\r
+ while( ( success && d_binding_it!=d_qni_bound.end() ) || doFail ){\r
+ std::map< int, MatchGen * >::iterator itm;\r
+ if( !doFail ){\r
+ Debug("qcf-match-debug") << " check variable " << d_binding_it->second << std::endl;\r
+ itm = qi->d_var_mg.find( d_binding_it->second );\r
+ }\r
+ if( doFail || ( d_binding_it->first!=0 && itm!=qi->d_var_mg.end() ) ){\r
+ Debug("qcf-match-debug") << " we had bound variable " << d_binding_it->second << ", reset = " << doReset << std::endl;\r
+ if( doReset ){\r
+ itm->second->reset( p, true, qi );\r
+ }\r
+ if( doFail || !itm->second->getNextMatch( p, qi ) ){\r
+ do {\r
+ if( d_binding_it==d_qni_bound.begin() ){\r
+ Debug("qcf-match-debug") << " failed." << std::endl;\r
+ success = false;\r
+ }else{\r
+ --d_binding_it;\r
+ Debug("qcf-match-debug") << " decrement..." << std::endl;\r
+ }\r
+ }while( success && ( d_binding_it->first==0 || qi->d_var_mg.find( d_binding_it->second )==qi->d_var_mg.end() ) );\r
+ doReset = false;\r
+ doFail = false;\r
+ }else{\r
+ Debug("qcf-match-debug") << " increment..." << std::endl;\r
+ ++d_binding_it;\r
+ doReset = true;\r
+ }\r
+ }else{\r
+ Debug("qcf-match-debug") << " skip..." << d_binding_it->second << std::endl;\r
+ ++d_binding_it;\r
+ doReset = true;\r
+ }\r
+ }\r
+ if( !success ){\r
+ d_binding = false;\r
+ }else{\r
+ terminate = true;\r
+ if( d_binding_it==d_qni_bound.begin() ){\r
+ d_binding = false;\r
+ }\r
+ }\r
+ }\r
+ }while( !terminate );\r
+ //if not successful, clean up the variables you bound\r
+ if( !success ){\r
+ if( d_type==typ_eq || d_type==typ_pred ){\r
+ //clean up the constraints you added\r
+ for( std::map< int, TNode >::iterator it = d_qni_bound_cons.begin(); it != d_qni_bound_cons.end(); ++it ){\r
+ if( !it->second.isNull() ){\r
+ Debug("qcf-match") << " Clean up bound var " << it->first << (d_tgt ? "!" : "") << " = " << it->second << std::endl;\r
+ std::map< int, int >::iterator itb = d_qni_bound_cons_var.find( it->first );\r
+ int vn = itb!=d_qni_bound_cons_var.end() ? itb->second : -1;\r
+ //Trace("qcf-explain") << " cleanup: " << d_n << " remove constraint " << it->first << " -> " << it->second << " (vn=" << vn << ")" << ", d_tgt = " << d_tgt << std::endl;\r
+ qi->addConstraint( p, it->first, it->second, vn, d_tgt, true );\r
+ }\r
+ }\r
+ d_qni_bound_cons.clear();\r
+ d_qni_bound_cons_var.clear();\r
+ d_qni_bound.clear();\r
+ }else{\r
+ //clean up the matches you set\r
+ for( std::map< int, int >::iterator it = d_qni_bound.begin(); it != d_qni_bound.end(); ++it ){\r
+ Debug("qcf-match") << " Clean up bound var " << it->second << std::endl;\r
+ Assert( it->second<qi->getNumVars() );\r
+ qi->d_match[ it->second ] = TNode::null();\r
+ qi->d_match_term[ it->second ] = TNode::null();\r
+ }\r
+ d_qni_bound.clear();\r
+ }\r
+ if( d_type==typ_tconstraint ){\r
+ //remove constraint if applicable\r
+ if( d_qni_bound_cons.find( 0 )!=d_qni_bound_cons.end() ){\r
+ qi->d_tconstraints.erase( d_n );\r
+ d_qni_bound_cons.clear();\r
+ }\r
+ }\r
+ /*\r
+ if( d_type==typ_var && p->d_effort==QuantConflictFind::effort_mc && !d_matched_basis ){\r
+ d_matched_basis = true;\r
+ Node f = getOperator( d_n );\r
+ TNode mbo = p->getQuantifiersEngine()->getTermDatabase()->getModelBasisOpTerm( f );\r
+ if( qi->setMatch( p, d_qni_var_num[0], mbo ) ){\r
+ success = true;\r
+ d_qni_bound[0] = d_qni_var_num[0];\r
+ }\r
+ }\r
+ */\r
+ }\r
+ Debug("qcf-match") << " ...finished matching for " << d_n << ", success = " << success << std::endl;\r
+ d_wasSet = success;\r
+ return success;\r
+ }else if( d_type==typ_formula || d_type==typ_ite_var ){\r
+ bool success = false;\r
+ if( d_child_counter<0 ){\r
+ if( d_child_counter<-1 ){\r
+ success = true;\r
+ d_child_counter = -1;\r
+ }\r
+ }else{\r
+ while( !success && d_child_counter>=0 ){\r
+ //transition system based on d_child_counter\r
+ if( d_n.getKind()==OR || d_n.getKind()==AND ){\r
+ if( (d_n.getKind()==AND)==d_tgt ){\r
+ //all children must match simultaneously\r
+ if( getChild( d_child_counter )->getNextMatch( p, qi ) ){\r
+ if( d_child_counter<(int)(getNumChildren()-1) ){\r
+ d_child_counter++;\r
+ Debug("qcf-match-debug") << " Reset child " << d_child_counter << " of " << d_n << std::endl;\r
+ getChild( d_child_counter )->reset( p, d_tgt, qi );\r
+ }else{\r
+ success = true;\r
+ }\r
+ }else{\r
+ //if( std::find( d_independent.begin(), d_independent.end(), d_child_counter )!=d_independent.end() ){\r
+ // d_child_counter--;\r
+ //}else{\r
+ d_child_counter--;\r
+ //}\r
+ }\r
+ }else{\r
+ //one child must match\r
+ if( !getChild( d_child_counter )->getNextMatch( p, qi ) ){\r
+ if( d_child_counter<(int)(getNumChildren()-1) ){\r
+ d_child_counter++;\r
+ Debug("qcf-match-debug") << " Reset child " << d_child_counter << " of " << d_n << ", one match" << std::endl;\r
+ getChild( d_child_counter )->reset( p, d_tgt, qi );\r
+ }else{\r
+ d_child_counter = -1;\r
+ }\r
+ }else{\r
+ success = true;\r
+ }\r
+ }\r
+ }else if( d_n.getKind()==IFF ){\r
+ //construct match based on both children\r
+ if( d_child_counter%2==0 ){\r
+ if( getChild( 0 )->getNextMatch( p, qi ) ){\r
+ d_child_counter++;\r
+ getChild( 1 )->reset( p, d_child_counter==1, qi );\r
+ }else{\r
+ if( d_child_counter==0 ){\r
+ d_child_counter = 2;\r
+ getChild( 0 )->reset( p, !d_tgt, qi );\r
+ }else{\r
+ d_child_counter = -1;\r
+ }\r
+ }\r
+ }\r
+ if( d_child_counter>=0 && d_child_counter%2==1 ){\r
+ if( getChild( 1 )->getNextMatch( p, qi ) ){\r
+ success = true;\r
+ }else{\r
+ d_child_counter--;\r
+ }\r
+ }\r
+ }else if( d_n.getKind()==ITE ){\r
+ if( d_child_counter%2==0 ){\r
+ int index1 = d_child_counter==4 ? 1 : 0;\r
+ if( getChild( index1 )->getNextMatch( p, qi ) ){\r
+ d_child_counter++;\r
+ getChild( d_child_counter==5 ? 2 : (d_tgt==(d_child_counter==1) ? 1 : 2) )->reset( p, d_tgt, qi );\r
+ }else{\r
+ if( d_child_counter==4 || ( d_type==typ_ite_var && d_child_counter==2 ) ){\r
+ d_child_counter = -1;\r
+ }else{\r
+ d_child_counter +=2;\r
+ getChild( d_child_counter==2 ? 0 : 1 )->reset( p, d_child_counter==2 ? !d_tgt : d_tgt, qi );\r
+ }\r
+ }\r
+ }\r
+ if( d_child_counter>=0 && d_child_counter%2==1 ){\r
+ int index2 = d_child_counter==5 ? 2 : (d_tgt==(d_child_counter==1) ? 1 : 2);\r
+ if( getChild( index2 )->getNextMatch( p, qi ) ){\r
+ success = true;\r
+ }else{\r
+ d_child_counter--;\r
+ }\r
+ }\r
+ }else if( d_n.getKind()==FORALL ){\r
+ if( getChild( d_child_counter )->getNextMatch( p, qi ) ){\r
+ success = true;\r
+ }else{\r
+ d_child_counter = -1;\r
+ }\r
+ }\r
+ }\r
+ d_wasSet = success;\r
+ Debug("qcf-match") << " ...finished construct match for " << d_n << ", success = " << success << std::endl;\r
+ return success;\r
+ }\r
+ }\r
+ Debug("qcf-match") << " ...already finished for " << d_n << std::endl;\r
+ return false;\r
+}\r
+\r
+bool MatchGen::getExplanation( QuantConflictFind * p, QuantInfo * qi, std::vector< Node >& exp ) {\r
+ if( d_type==typ_eq ){\r
+ Node n[2];\r
+ for( unsigned i=0; i<2; i++ ){\r
+ Trace("qcf-explain") << "Explain term " << d_n[i] << "..." << std::endl;\r
+ n[i] = getExplanationTerm( p, qi, d_n[i], exp );\r
+ }\r
+ Node eq = n[0].eqNode( n[1] );\r
+ if( !d_tgt_orig ){\r
+ eq = eq.negate();\r
+ }\r
+ exp.push_back( eq );\r
+ Trace("qcf-explain") << "Explanation for " << d_n << " (tgt=" << d_tgt_orig << ") is " << eq << ", set = " << d_wasSet << std::endl;\r
+ return true;\r
+ }else if( d_type==typ_pred ){\r
+ Trace("qcf-explain") << "Explain term " << d_n << "..." << std::endl;\r
+ Node n = getExplanationTerm( p, qi, d_n, exp );\r
+ if( !d_tgt_orig ){\r
+ n = n.negate();\r
+ }\r
+ exp.push_back( n );\r
+ Trace("qcf-explain") << "Explanation for " << d_n << " (tgt=" << d_tgt_orig << ") is " << n << ", set = " << d_wasSet << std::endl;\r
+ return true;\r
+ }else if( d_type==typ_formula ){\r
+ Trace("qcf-explain") << "Explanation get for " << d_n << ", counter = " << d_child_counter << ", tgt = " << d_tgt_orig << ", set = " << d_wasSet << std::endl;\r
+ if( d_n.getKind()==OR || d_n.getKind()==AND ){\r
+ if( (d_n.getKind()==AND)==d_tgt ){\r
+ for( unsigned i=0; i<getNumChildren(); i++ ){\r
+ if( !getChild( i )->getExplanation( p, qi, exp ) ){\r
+ return false;\r
+ }\r
+ }\r
+ }else{\r
+ return getChild( d_child_counter )->getExplanation( p, qi, exp );\r
+ }\r
+ }else if( d_n.getKind()==IFF ){\r
+ for( unsigned i=0; i<2; i++ ){\r
+ if( !getChild( i )->getExplanation( p, qi, exp ) ){\r
+ return false;\r
+ }\r
+ }\r
+ }else if( d_n.getKind()==ITE ){\r
+ for( unsigned i=0; i<3; i++ ){\r
+ bool isActive = ( ( i==0 && d_child_counter!=5 ) ||\r
+ ( i==1 && d_child_counter!=( d_tgt ? 3 : 1 ) ) ||\r
+ ( i==2 && d_child_counter!=( d_tgt ? 1 : 3 ) ) );\r
+ if( isActive ){\r
+ if( !getChild( i )->getExplanation( p, qi, exp ) ){\r
+ return false;\r
+ }\r
+ }\r
+ }\r
+ }else{\r
+ return false;\r
+ }\r
+ return true;\r
+ }else{\r
+ return false;\r
+ }\r
+}\r
+\r
+Node MatchGen::getExplanationTerm( QuantConflictFind * p, QuantInfo * qi, Node t, std::vector< Node >& exp ) {\r
+ Node v = qi->getCurrentExpValue( t );\r
+ if( isHandledUfTerm( t ) ){\r
+ for( unsigned i=0; i<t.getNumChildren(); i++ ){\r
+ Node vi = getExplanationTerm( p, qi, t[i], exp );\r
+ if( vi!=v[i] ){\r
+ Node eq = vi.eqNode( v[i] );\r
+ if( std::find( exp.begin(), exp.end(), eq )==exp.end() ){\r
+ Trace("qcf-explain") << " add : " << eq << "." << std::endl;\r
+ exp.push_back( eq );\r
+ }\r
+ }\r
+ }\r
+ }\r
+ return v;\r
+}\r
+\r
+bool MatchGen::doMatching( QuantConflictFind * p, QuantInfo * qi ) {\r
+ if( !d_qn.empty() ){\r
+ if( d_qn[0]==NULL ){\r
+ d_qn.clear();\r
+ return true;\r
+ }else{\r
+ Assert( d_type==typ_var );\r
+ Assert( d_qni_size>0 );\r
+ bool invalidMatch;\r
+ do {\r
+ invalidMatch = false;\r
+ Debug("qcf-match-debug") << " Do matching " << d_n << " " << d_qn.size() << " " << d_qni.size() << std::endl;\r
+ if( d_qn.size()==d_qni.size()+1 ) {\r
+ int index = (int)d_qni.size();\r
+ //initialize\r
+ TNode val;\r
+ std::map< int, int >::iterator itv = d_qni_var_num.find( index );\r
+ if( itv!=d_qni_var_num.end() ){\r
+ //get the representative variable this variable is equal to\r
+ int repVar = qi->getCurrentRepVar( itv->second );\r
+ Debug("qcf-match-debug") << " Match " << index << " is a variable " << itv->second << ", which is repVar " << repVar << std::endl;\r
+ //get the value the rep variable\r
+ //std::map< int, TNode >::iterator itm = qi->d_match.find( repVar );\r
+ if( !qi->d_match[repVar].isNull() ){\r
+ val = qi->d_match[repVar];\r
+ Debug("qcf-match-debug") << " Variable is already bound to " << val << std::endl;\r
+ }else{\r
+ //binding a variable\r
+ d_qni_bound[index] = repVar;\r
+ std::map< TNode, TermArgTrie >::iterator it = d_qn[index]->d_data.begin();\r
+ if( it != d_qn[index]->d_data.end() ) {\r
+ d_qni.push_back( it );\r
+ //set the match\r
+ if( qi->setMatch( p, d_qni_bound[index], it->first ) ){\r
+ Debug("qcf-match-debug") << " Binding variable" << std::endl;\r
+ if( d_qn.size()<d_qni_size ){\r
+ d_qn.push_back( &it->second );\r
+ }\r
+ }else{\r
+ Debug("qcf-match") << " Binding variable, currently fail." << std::endl;\r
+ invalidMatch = true;\r
+ }\r
+ }else{\r
+ Debug("qcf-match-debug") << " Binding variable, fail, no more variables to bind" << std::endl;\r
+ d_qn.pop_back();\r
+ }\r
+ }\r
+ }else{\r
+ Debug("qcf-match-debug") << " Match " << index << " is ground term" << std::endl;\r
+ Assert( d_qni_gterm.find( index )!=d_qni_gterm.end() );\r
+ Assert( d_qni_gterm_rep.find( index )!=d_qni_gterm_rep.end() );\r
+ val = d_qni_gterm_rep[index];\r
+ Assert( !val.isNull() );\r
+ }\r
+ if( !val.isNull() ){\r
+ //constrained by val\r
+ std::map< TNode, TermArgTrie >::iterator it = d_qn[index]->d_data.find( val );\r
+ if( it!=d_qn[index]->d_data.end() ){\r
+ Debug("qcf-match-debug") << " Match" << std::endl;\r
+ d_qni.push_back( it );\r
+ if( d_qn.size()<d_qni_size ){\r
+ d_qn.push_back( &it->second );\r
+ }\r
+ }else{\r
+ Debug("qcf-match-debug") << " Failed to match" << std::endl;\r
+ d_qn.pop_back();\r
+ }\r
+ }\r
+ }else{\r
+ Assert( d_qn.size()==d_qni.size() );\r
+ int index = d_qni.size()-1;\r
+ //increment if binding this variable\r
+ bool success = false;\r
+ std::map< int, int >::iterator itb = d_qni_bound.find( index );\r
+ if( itb!=d_qni_bound.end() ){\r
+ d_qni[index]++;\r
+ if( d_qni[index]!=d_qn[index]->d_data.end() ){\r
+ success = true;\r
+ if( qi->setMatch( p, itb->second, d_qni[index]->first ) ){\r
+ Debug("qcf-match-debug") << " Bind next variable" << std::endl;\r
+ if( d_qn.size()<d_qni_size ){\r
+ d_qn.push_back( &d_qni[index]->second );\r
+ }\r
+ }else{\r
+ Debug("qcf-match-debug") << " Bind next variable, currently fail" << std::endl;\r
+ invalidMatch = true;\r
+ }\r
+ }else{\r
+ qi->d_match[ itb->second ] = TNode::null();\r
+ qi->d_match_term[ itb->second ] = TNode::null();\r
+ Debug("qcf-match-debug") << " Bind next variable, no more variables to bind" << std::endl;\r
+ }\r
+ }else{\r
+ //TODO : if it equal to something else, also try that\r
+ }\r
+ //if not incrementing, move to next\r
+ if( !success ){\r
+ d_qn.pop_back();\r
+ d_qni.pop_back();\r
+ }\r
+ }\r
+ }while( ( !d_qn.empty() && d_qni.size()!=d_qni_size ) || invalidMatch );\r
+ if( d_qni.size()==d_qni_size ){\r
+ //Assert( !d_qni[d_qni.size()-1]->second.d_data.empty() );\r
+ //Debug("qcf-match-debug") << " We matched " << d_qni[d_qni.size()-1]->second.d_children.begin()->first << std::endl;\r
+ Assert( !d_qni[d_qni.size()-1]->second.d_data.empty() );\r
+ TNode t = d_qni[d_qni.size()-1]->second.d_data.begin()->first;\r
+ Debug("qcf-match-debug") << " " << d_n << " matched " << t << std::endl;\r
+ qi->d_match_term[d_qni_var_num[0]] = t;\r
+ //set the match terms\r
+ for( std::map< int, int >::iterator it = d_qni_bound.begin(); it != d_qni_bound.end(); ++it ){\r
+ Debug("qcf-match-debug") << " position " << it->first << " bounded " << it->second << " / " << qi->d_q[0].getNumChildren() << std::endl;\r
+ //if( it->second<(int)qi->d_q[0].getNumChildren() ){ //if it is an actual variable, we are interested in knowing the actual term\r
+ if( it->first>0 ){\r
+ Assert( !qi->d_match[ it->second ].isNull() );\r
+ Assert( p->areEqual( t[it->first-1], qi->d_match[ it->second ] ) );\r
+ qi->d_match_term[it->second] = t[it->first-1];\r
+ }\r
+ //}\r
+ }\r
+ }\r
+ }\r
+ }\r
+ return !d_qn.empty();\r
+}\r
+\r
+void MatchGen::debugPrintType( const char * c, short typ, bool isTrace ) {\r
+ if( isTrace ){\r
+ switch( typ ){\r
+ case typ_invalid: Trace(c) << "invalid";break;\r
+ case typ_ground: Trace(c) << "ground";break;\r
+ case typ_eq: Trace(c) << "eq";break;\r
+ case typ_pred: Trace(c) << "pred";break;\r
+ case typ_formula: Trace(c) << "formula";break;\r
+ case typ_var: Trace(c) << "var";break;\r
+ case typ_ite_var: Trace(c) << "ite_var";break;\r
+ case typ_bool_var: Trace(c) << "bool_var";break;\r
+ }\r
+ }else{\r
+ switch( typ ){\r
+ case typ_invalid: Debug(c) << "invalid";break;\r
+ case typ_ground: Debug(c) << "ground";break;\r
+ case typ_eq: Debug(c) << "eq";break;\r
+ case typ_pred: Debug(c) << "pred";break;\r
+ case typ_formula: Debug(c) << "formula";break;\r
+ case typ_var: Debug(c) << "var";break;\r
+ case typ_ite_var: Debug(c) << "ite_var";break;\r
+ case typ_bool_var: Debug(c) << "bool_var";break;\r
+ }\r
+ }\r
+}\r
+\r
+void MatchGen::setInvalid() {\r
+ d_type = typ_invalid;\r
+ d_children.clear();\r
+}\r
+\r
+bool MatchGen::isHandledBoolConnective( TNode n ) {\r
+ return n.getType().isBoolean() && ( n.getKind()==OR || n.getKind()==AND || n.getKind()==IFF || n.getKind()==ITE || n.getKind()==FORALL || n.getKind()==NOT );\r
+}\r
+\r
+bool MatchGen::isHandledUfTerm( TNode n ) {\r
+ //return n.getKind()==APPLY_UF || n.getKind()==STORE || n.getKind()==SELECT ||\r
+ // n.getKind()==APPLY_CONSTRUCTOR || n.getKind()==APPLY_SELECTOR_TOTAL || n.getKind()==APPLY_TESTER;\r
+ return inst::Trigger::isAtomicTriggerKind( n.getKind() ); \r
+}\r
+\r
+Node MatchGen::getOperator( QuantConflictFind * p, Node n ) {\r
+ if( isHandledUfTerm( n ) ){\r
+ return p->getQuantifiersEngine()->getTermDatabase()->getOperator( n );\r
+ }else{\r
+ return Node::null();\r
+ }\r
+}\r
+\r
+bool MatchGen::isHandled( TNode n ) {\r
+ if( n.getKind()!=BOUND_VARIABLE && n.hasBoundVar() ){\r
+ if( !isHandledBoolConnective( n ) && !isHandledUfTerm( n ) && n.getKind()!=EQUAL && n.getKind()!=ITE ){\r
+ return false;\r
+ }\r
+ for( unsigned i=0; i<n.getNumChildren(); i++ ){\r
+ if( !isHandled( n[i] ) ){\r
+ return false;\r
+ }\r
+ }\r
+ }\r
+ return true;\r
+}\r
+\r
+\r
+QuantConflictFind::QuantConflictFind( QuantifiersEngine * qe, context::Context* c ) :\r
+QuantifiersModule( qe ),\r
+d_c( c ),\r
+d_conflict( c, false ),\r
+d_qassert( c ) {\r
+ d_fid_count = 0;\r
+ d_true = NodeManager::currentNM()->mkConst<bool>(true);\r
+ d_false = NodeManager::currentNM()->mkConst<bool>(false);\r
+}\r
+\r
+Node QuantConflictFind::mkEqNode( Node a, Node b ) {\r
+ if( a.getType().isBoolean() ){\r
+ return a.iffNode( b );\r
+ }else{\r
+ return a.eqNode( b );\r
+ }\r
+}\r
+\r
+//-------------------------------------------------- registration\r
+\r
+void QuantConflictFind::registerQuantifier( Node q ) {\r
+ if( d_quantEngine->hasOwnership( q, this ) ){\r
+ d_quants.push_back( q );\r
+ d_quant_id[q] = d_quants.size();\r
+ Trace("qcf-qregister") << "Register ";\r
+ debugPrintQuant( "qcf-qregister", q );\r
+ Trace("qcf-qregister") << " : " << q << std::endl;\r
+ //make QcfNode structure\r
+ Trace("qcf-qregister") << "- Get relevant equality/disequality pairs, calculate flattening..." << std::endl;\r
+ d_qinfo[q].initialize( q, q[1] );\r
+\r
+ //debug print\r
+ Trace("qcf-qregister") << "- Flattened structure is :" << std::endl;\r
+ Trace("qcf-qregister") << " ";\r
+ debugPrintQuantBody( "qcf-qregister", q, q[1] );\r
+ Trace("qcf-qregister") << std::endl;\r
+ if( d_qinfo[q].d_vars.size()>q[0].getNumChildren() ){\r
+ Trace("qcf-qregister") << " with additional constraints : " << std::endl;\r
+ for( unsigned j=q[0].getNumChildren(); j<d_qinfo[q].d_vars.size(); j++ ){\r
+ Trace("qcf-qregister") << " ?x" << j << " = ";\r
+ debugPrintQuantBody( "qcf-qregister", q, d_qinfo[q].d_vars[j], false );\r
+ Trace("qcf-qregister") << std::endl;\r
+ }\r
+ }\r
+\r
+ Trace("qcf-qregister") << "Done registering quantifier." << std::endl;\r
+ }\r
+}\r
+\r
+int QuantConflictFind::evaluate( Node n, bool pref, bool hasPref ) {\r
+ int ret = 0;\r
+ if( n.getKind()==EQUAL ){\r
+ Node n1 = evaluateTerm( n[0] );\r
+ Node n2 = evaluateTerm( n[1] );\r
+ Debug("qcf-eval") << "Evaluate : Normalize " << n << " to " << n1 << " = " << n2 << std::endl;\r
+ if( areEqual( n1, n2 ) ){\r
+ ret = 1;\r
+ }else if( areDisequal( n1, n2 ) ){\r
+ ret = -1;\r
+ }\r
+ //else if( d_effort>QuantConflictFind::effort_conflict ){\r
+ // ret = -1;\r
+ //}\r
+ }else if( MatchGen::isHandledUfTerm( n ) ){ //predicate\r
+ Node nn = evaluateTerm( n );\r
+ Debug("qcf-eval") << "Evaluate : Normalize " << nn << " to " << n << std::endl;\r
+ if( areEqual( nn, d_true ) ){\r
+ ret = 1;\r
+ }else if( areEqual( nn, d_false ) ){\r
+ ret = -1;\r
+ }\r
+ //else if( d_effort>QuantConflictFind::effort_conflict ){\r
+ // ret = -1;\r
+ //}\r
+ }else if( n.getKind()==NOT ){\r
+ return -evaluate( n[0] );\r
+ }else if( n.getKind()==ITE ){\r
+ int cev1 = evaluate( n[0] );\r
+ int cevc[2] = { 0, 0 };\r
+ for( unsigned i=0; i<2; i++ ){\r
+ if( ( i==0 && cev1!=-1 ) || ( i==1 && cev1!=1 ) ){\r
+ cevc[i] = evaluate( n[i+1] );\r
+ if( cev1!=0 ){\r
+ ret = cevc[i];\r
+ break;\r
+ }else if( cevc[i]==0 ){\r
+ break;\r
+ }\r
+ }\r
+ }\r
+ if( ret==0 && cevc[0]!=0 && cevc[0]==cevc[1] ){\r
+ ret = cevc[0];\r
+ }\r
+ }else if( n.getKind()==IFF ){\r
+ int cev1 = evaluate( n[0] );\r
+ if( cev1!=0 ){\r
+ int cev2 = evaluate( n[1] );\r
+ if( cev2!=0 ){\r
+ ret = cev1==cev2 ? 1 : -1;\r
+ }\r
+ }\r
+\r
+ }else{\r
+ int ssval = 0;\r
+ if( n.getKind()==OR ){\r
+ ssval = 1;\r
+ }else if( n.getKind()==AND ){\r
+ ssval = -1;\r
+ }\r
+ bool isUnk = false;\r
+ for( unsigned i=0; i<n.getNumChildren(); i++ ){\r
+ int cev = evaluate( n[i] );\r
+ if( cev==ssval ){\r
+ ret = ssval;\r
+ break;\r
+ }else if( cev==0 ){\r
+ isUnk = true;\r
+ }\r
+ }\r
+ if( ret==0 && !isUnk ){\r
+ ret = -ssval;\r
+ }\r
+ }\r
+ Debug("qcf-eval") << "Evaluate " << n << " to " << ret << std::endl;\r
+ return ret;\r
+}\r
+\r
+short QuantConflictFind::getMaxQcfEffort() {\r
+ if( options::qcfMode()==QCF_CONFLICT_ONLY ){\r
+ return effort_conflict;\r
+ }else if( options::qcfMode()==QCF_PROP_EQ ){\r
+ return effort_prop_eq;\r
+ }else if( options::qcfMode()==QCF_MC ){\r
+ return effort_mc;\r
+ }else{\r
+ return 0;\r
+ }\r
+}\r
+\r
+bool QuantConflictFind::areMatchEqual( TNode n1, TNode n2 ) {\r
+ //if( d_effort==QuantConflictFind::effort_mc ){\r
+ // return n1==n2 || !areDisequal( n1, n2 );\r
+ //}else{\r
+ return n1==n2;\r
+ //}\r
+}\r
+\r
+bool QuantConflictFind::areMatchDisequal( TNode n1, TNode n2 ) {\r
+ //if( d_effort==QuantConflictFind::effort_conflict ){\r
+ // return areDisequal( n1, n2 );\r
+ //}else{\r
+ return n1!=n2;\r
+ //}\r
+}\r
+\r
+//-------------------------------------------------- handling assertions / eqc\r
+\r
+void QuantConflictFind::assertNode( Node q ) {\r
+ if( d_quantEngine->hasOwnership( q, this ) ){\r
+ Trace("qcf-proc") << "QCF : assertQuantifier : ";\r
+ debugPrintQuant("qcf-proc", q);\r
+ Trace("qcf-proc") << std::endl;\r
+ d_qassert.push_back( q );\r
+ //set the eqRegistries that this depends on to true\r
+ //for( std::map< EqRegistry *, bool >::iterator it = d_qinfo[q].d_rel_eqr.begin(); it != d_qinfo[q].d_rel_eqr.end(); ++it ){\r
+ // it->first->d_active.set( true );\r
+ //}\r
+ }\r
+}\r
+\r
+Node QuantConflictFind::evaluateTerm( Node n ) {\r
+ if( MatchGen::isHandledUfTerm( n ) ){\r
+ Node f = MatchGen::getOperator( this, n );\r
+ Node nn;\r
+ if( getEqualityEngine()->hasTerm( n ) ){\r
+ nn = getTermDatabase()->existsTerm( f, n );\r
+ }else{\r
+ std::vector< TNode > args;\r
+ for( unsigned i=0; i<n.getNumChildren(); i++ ){\r
+ Node c = evaluateTerm( n[i] );\r
+ args.push_back( c );\r
+ }\r
+ nn = getTermDatabase()->d_func_map_trie[f].existsTerm( args );\r
+ }\r
+ if( !nn.isNull() ){\r
+ Debug("qcf-eval") << "GT: Term " << nn << " for " << n << " hasTerm = " << getEqualityEngine()->hasTerm( n ) << std::endl;\r
+ return getRepresentative( nn );\r
+ }else{\r
+ Debug("qcf-eval") << "GT: No term for " << n << " hasTerm = " << getEqualityEngine()->hasTerm( n ) << std::endl;\r
+ return n;\r
+ }\r
+ }else if( n.getKind()==ITE ){\r
+ int v = evaluate( n[0], false, false );\r
+ if( v==1 ){\r
+ return evaluateTerm( n[1] );\r
+ }else if( v==-1 ){\r
+ return evaluateTerm( n[2] );\r
+ }\r
+ }\r
+ return getRepresentative( n );\r
+}\r
+\r
+/** new node */\r
+void QuantConflictFind::newEqClass( Node n ) {\r
+ //Trace("qcf-proc-debug") << "QCF : newEqClass : " << n << std::endl;\r
+ //Trace("qcf-proc2-debug") << "QCF : finished newEqClass : " << n << std::endl;\r
+}\r
+\r
+/** merge */\r
+void QuantConflictFind::merge( Node a, Node b ) {\r
+\r
+}\r
+\r
+/** assert disequal */\r
+void QuantConflictFind::assertDisequal( Node a, Node b ) {\r
+\r
+}\r
+\r
+//-------------------------------------------------- check function\r
+\r
+bool QuantConflictFind::needsCheck( Theory::Effort level ) {\r
+ bool performCheck = false;\r
+ if( options::quantConflictFind() && !d_conflict ){\r
+ if( level==Theory::EFFORT_LAST_CALL ){\r
+ performCheck = options::qcfWhenMode()==QCF_WHEN_MODE_LAST_CALL;\r
+ }else if( level==Theory::EFFORT_FULL ){\r
+ performCheck = options::qcfWhenMode()==QCF_WHEN_MODE_DEFAULT;\r
+ }else if( level==Theory::EFFORT_STANDARD ){\r
+ performCheck = options::qcfWhenMode()==QCF_WHEN_MODE_STD;\r
+ }\r
+ }\r
+ return performCheck;\r
+}\r
+\r
+void QuantConflictFind::reset_round( Theory::Effort level ) {\r
+ d_needs_computeRelEqr = true;\r
+}\r
+\r
+/** check */\r
+void QuantConflictFind::check( Theory::Effort level, unsigned quant_e ) {\r
+ if( quant_e==QuantifiersEngine::QEFFORT_CONFLICT ){\r
+ Trace("qcf-check") << "QCF : check : " << level << std::endl;\r
+ if( d_conflict ){\r
+ Trace("qcf-check2") << "QCF : finished check : already in conflict." << std::endl;\r
+ if( level>=Theory::EFFORT_FULL ){\r
+ Trace("qcf-warn") << "ALREADY IN CONFLICT? " << level << std::endl;\r
+ //Assert( false );\r
+ }\r
+ }else{\r
+ int addedLemmas = 0;\r
+ ++(d_statistics.d_inst_rounds);\r
+ double clSet = 0;\r
+ int prevEt = 0;\r
+ if( Trace.isOn("qcf-engine") ){\r
+ prevEt = d_statistics.d_entailment_checks.getData();\r
+ clSet = double(clock())/double(CLOCKS_PER_SEC);\r
+ Trace("qcf-engine") << "---Conflict Find Engine Round, effort = " << level << "---" << std::endl;\r
+ }\r
+ computeRelevantEqr();\r
+\r
+ //determine order for quantified formulas\r
+ std::vector< Node > qorder;\r
+ std::map< Node, bool > qassert;\r
+ //mark which are asserted\r
+ for( unsigned i=0; i<d_qassert.size(); i++ ){\r
+ qassert[d_qassert[i]] = true;\r
+ }\r
+ //add which ones are specified in the order\r
+ for( unsigned i=0; i<d_quant_order.size(); i++ ){\r
+ Node n = d_quant_order[i];\r
+ if( std::find( qorder.begin(), qorder.end(), n )==qorder.end() && qassert.find( n )!=qassert.end() ){\r
+ qorder.push_back( n );\r
+ }\r
+ }\r
+ d_quant_order.clear();\r
+ d_quant_order.insert( d_quant_order.begin(), qorder.begin(), qorder.end() );\r
+ //add remaining\r
+ for( unsigned i=0; i<d_qassert.size(); i++ ){\r
+ Node n = d_qassert[i];\r
+ if( std::find( qorder.begin(), qorder.end(), n )==qorder.end() ){\r
+ qorder.push_back( n );\r
+ }\r
+ }\r
+\r
+ if( Trace.isOn("qcf-debug") ){\r
+ Trace("qcf-debug") << std::endl;\r
+ debugPrint("qcf-debug");\r
+ Trace("qcf-debug") << std::endl;\r
+ }\r
+ short end_e = getMaxQcfEffort();\r
+ for( short e = effort_conflict; e<=end_e; e++ ){\r
+ d_effort = e;\r
+ Trace("qcf-check") << "Checking quantified formulas at effort " << e << "..." << std::endl;\r
+ for( unsigned j=0; j<qorder.size(); j++ ){\r
+ Node q = qorder[j];\r
+ QuantInfo * qi = &d_qinfo[q];\r
+\r
+ Assert( d_qinfo.find( q )!=d_qinfo.end() );\r
+ if( qi->d_mg->isValid() ){\r
+ Trace("qcf-check") << "Check quantified formula ";\r
+ debugPrintQuant("qcf-check", q);\r
+ Trace("qcf-check") << " : " << q << "..." << std::endl;\r
+\r
+ Trace("qcf-check-debug") << "Reset round..." << std::endl;\r
+ qi->reset_round( this );\r
+ //try to make a matches making the body false\r
+ Trace("qcf-check-debug") << "Get next match..." << std::endl;\r
+ while( qi->d_mg->getNextMatch( this, qi ) ){\r
+ Trace("qcf-inst") << "*** Produced match at effort " << e << " : " << std::endl;\r
+ qi->debugPrintMatch("qcf-inst");\r
+ Trace("qcf-inst") << std::endl;\r
+ std::vector< int > assigned;\r
+ if( !qi->isMatchSpurious( this ) ){\r
+ if( qi->completeMatch( this, assigned ) ){\r
+ std::vector< Node > terms;\r
+ qi->getMatch( terms );\r
+ if( !qi->isTConstraintSpurious( this, terms ) ){\r
+ if( Debug.isOn("qcf-check-inst") ){\r
+ //if( e==effort_conflict ){\r
+ Node inst = d_quantEngine->getInstantiation( q, terms );\r
+ Debug("qcf-check-inst") << "Check instantiation " << inst << "..." << std::endl;\r
+ Assert( evaluate( inst )!=1 );\r
+ Assert( evaluate( inst )==-1 || e>effort_conflict );\r
+ //}\r
+ }\r
+ if( d_quantEngine->addInstantiation( q, terms, false ) ){\r
+ Trace("qcf-check") << " ... Added instantiation" << std::endl;\r
+ Trace("qcf-inst") << "*** Was from effort " << e << " : " << std::endl;\r
+ qi->debugPrintMatch("qcf-inst");\r
+ Trace("qcf-inst") << std::endl;\r
+ ++addedLemmas;\r
+ if( e==effort_conflict ){\r
+ d_quant_order.insert( d_quant_order.begin(), q );\r
+ d_conflict.set( true );\r
+ ++(d_statistics.d_conflict_inst);\r
+ break;\r
+ }else if( e==effort_prop_eq ){\r
+ ++(d_statistics.d_prop_inst);\r
+ }\r
+ }else{\r
+ Trace("qcf-inst") << " ... Failed to add instantiation" << std::endl;\r
+ //Assert( false );\r
+ }\r
+ }\r
+ //clean up assigned\r
+ qi->revertMatch( assigned );\r
+ d_tempCache.clear();\r
+ }else{\r
+ Trace("qcf-inst") << " ... Spurious instantiation (cannot assign unassigned variables)" << std::endl;\r
+ }\r
+ }else{\r
+ Trace("qcf-inst") << " ... Spurious instantiation (match is inconsistent)" << std::endl;\r
+ }\r
+ }\r
+ if( d_conflict ){\r
+ break;\r
+ }\r
+ }\r
+ }\r
+ if( addedLemmas>0 ){\r
+ break;\r
+ }\r
+ }\r
+ if( Trace.isOn("qcf-engine") ){\r
+ double clSet2 = double(clock())/double(CLOCKS_PER_SEC);\r
+ Trace("qcf-engine") << "Finished conflict find engine, time = " << (clSet2-clSet);\r
+ if( addedLemmas>0 ){\r
+ Trace("qcf-engine") << ", effort = " << ( d_effort==effort_conflict ? "conflict" : ( d_effort==effort_prop_eq ? "prop_eq" : "mc" ) );\r
+ Trace("qcf-engine") << ", addedLemmas = " << addedLemmas;\r
+ }\r
+ Trace("qcf-engine") << std::endl;\r
+ int currEt = d_statistics.d_entailment_checks.getData();\r
+ if( currEt!=prevEt ){\r
+ Trace("qcf-engine") << " Entailment checks = " << ( currEt - prevEt ) << std::endl;\r
+ }\r
+ }\r
+ Trace("qcf-check2") << "QCF : finished check : " << level << std::endl;\r
+ }\r
+ }\r
+}\r
+\r
+void QuantConflictFind::computeRelevantEqr() {\r
+ if( d_needs_computeRelEqr ){\r
+ d_needs_computeRelEqr = false;\r
+ Trace("qcf-check") << "Compute relevant equalities..." << std::endl;\r
+ //d_uf_terms.clear();\r
+ //d_eqc_uf_terms.clear();\r
+ d_eqcs.clear();\r
+ d_model_basis.clear();\r
+ //d_arg_reps.clear();\r
+ //double clSet = 0;\r
+ //if( Trace.isOn("qcf-opt") ){\r
+ // clSet = double(clock())/double(CLOCKS_PER_SEC);\r
+ //}\r
+\r
+ //long nTermst = 0;\r
+ //long nTerms = 0;\r
+ //long nEqc = 0;\r
+\r
+ //which nodes are irrelevant for disequality matches\r
+ std::map< TNode, bool > irrelevant_dnode;\r
+ //now, store matches\r
+ eq::EqClassesIterator eqcs_i = eq::EqClassesIterator( getEqualityEngine() );\r
+ while( !eqcs_i.isFinished() ){\r
+ //nEqc++;\r
+ Node r = (*eqcs_i);\r
+ TypeNode rtn = r.getType();\r
+ if( options::qcfMode()==QCF_MC ){\r
+ std::map< TypeNode, std::vector< TNode > >::iterator itt = d_eqcs.find( rtn );\r
+ if( itt==d_eqcs.end() ){\r
+ Node mb = getQuantifiersEngine()->getTermDatabase()->getModelBasisTerm( rtn );\r
+ if( !getEqualityEngine()->hasTerm( mb ) ){\r
+ Trace("qcf-warn") << "WARNING: Model basis term does not exist!" << std::endl;\r
+ Assert( false );\r
+ }\r
+ Node mbr = getRepresentative( mb );\r
+ if( mbr!=r ){\r
+ d_eqcs[rtn].push_back( mbr );\r
+ }\r
+ d_eqcs[rtn].push_back( r );\r
+ d_model_basis[rtn] = mb;\r
+ }else{\r
+ itt->second.push_back( r );\r
+ }\r
+ }else{\r
+ d_eqcs[rtn].push_back( r );\r
+ }\r
+ ++eqcs_i;\r
+ }\r
+ /*\r
+ if( Trace.isOn("qcf-opt") ){\r
+ double clSet2 = double(clock())/double(CLOCKS_PER_SEC);\r
+ Trace("qcf-opt") << "Compute rel eqc : " << std::endl;\r
+ Trace("qcf-opt") << " " << nEqc << " equivalence classes. " << std::endl;\r
+ Trace("qcf-opt") << " " << nTerms << " / " << nTermst << " terms." << std::endl;\r
+ Trace("qcf-opt") << " Time : " << (clSet2-clSet) << std::endl;\r
+ }\r
+ */\r
+ }\r
+}\r
+\r
+\r
+//-------------------------------------------------- debugging\r
+\r
+\r
+void QuantConflictFind::debugPrint( const char * c ) {\r
+ //print the equivalance classes\r
+ Trace(c) << "----------EQ classes" << std::endl;\r
+ eq::EqClassesIterator eqcs_i = eq::EqClassesIterator( getEqualityEngine() );\r
+ while( !eqcs_i.isFinished() ){\r
+ Node n = (*eqcs_i);\r
+ //if( !n.getType().isInteger() ){\r
+ Trace(c) << " - " << n << " : {";\r
+ eq::EqClassIterator eqc_i = eq::EqClassIterator( n, getEqualityEngine() );\r
+ bool pr = false;\r
+ while( !eqc_i.isFinished() ){\r
+ Node nn = (*eqc_i);\r
+ if( nn.getKind()!=EQUAL && nn!=n ){\r
+ Trace(c) << (pr ? "," : "" ) << " " << nn;\r
+ pr = true;\r
+ }\r
+ ++eqc_i;\r
+ }\r
+ Trace(c) << (pr ? " " : "" ) << "}" << std::endl;\r
+ /*\r
+ EqcInfo * eqcn = getEqcInfo( n, false );\r
+ if( eqcn ){\r
+ Trace(c) << " DEQ : {";\r
+ pr = false;\r
+ for( NodeBoolMap::iterator it = eqcn->d_diseq.begin(); it != eqcn->d_diseq.end(); ++it ){\r
+ if( (*it).second ){\r
+ Trace(c) << (pr ? "," : "" ) << " " << (*it).first;\r
+ pr = true;\r
+ }\r
+ }\r
+ Trace(c) << (pr ? " " : "" ) << "}" << std::endl;\r
+ }\r
+ //}\r
+ */\r
+ ++eqcs_i;\r
+ }\r
+}\r
+\r
+void QuantConflictFind::debugPrintQuant( const char * c, Node q ) {\r
+ Trace(c) << "Q" << d_quant_id[q];\r
+}\r
+\r
+void QuantConflictFind::debugPrintQuantBody( const char * c, Node q, Node n, bool doVarNum ) {\r
+ if( n.getNumChildren()==0 ){\r
+ Trace(c) << n;\r
+ }else if( doVarNum && d_qinfo[q].d_var_num.find( n )!=d_qinfo[q].d_var_num.end() ){\r
+ Trace(c) << "?x" << d_qinfo[q].d_var_num[n];\r
+ }else{\r
+ Trace(c) << "(";\r
+ if( n.getKind()==APPLY_UF ){\r
+ Trace(c) << n.getOperator();\r
+ }else{\r
+ Trace(c) << n.getKind();\r
+ }\r
+ for( unsigned i=0; i<n.getNumChildren(); i++ ){\r
+ Trace(c) << " ";\r
+ debugPrintQuantBody( c, q, n[i] );\r
+ }\r
+ Trace(c) << ")";\r
+ }\r
+}\r
+\r
+QuantConflictFind::Statistics::Statistics():\r
+ d_inst_rounds("QuantConflictFind::Inst_Rounds", 0),\r
+ d_conflict_inst("QuantConflictFind::Instantiations_Conflict_Find", 0 ),\r
+ d_prop_inst("QuantConflictFind::Instantiations_Prop", 0 ),\r
+ d_entailment_checks("QuantConflictFind::Entailment_Checks",0)\r
+{\r
+ StatisticsRegistry::registerStat(&d_inst_rounds);\r
+ StatisticsRegistry::registerStat(&d_conflict_inst);\r
+ StatisticsRegistry::registerStat(&d_prop_inst);\r
+ StatisticsRegistry::registerStat(&d_entailment_checks);\r
+}\r
+\r
+QuantConflictFind::Statistics::~Statistics(){\r
+ StatisticsRegistry::unregisterStat(&d_inst_rounds);\r
+ StatisticsRegistry::unregisterStat(&d_conflict_inst);\r
+ StatisticsRegistry::unregisterStat(&d_prop_inst);\r
+ StatisticsRegistry::unregisterStat(&d_entailment_checks);\r
+}\r
+\r
+TNode QuantConflictFind::getZero( Kind k ) {\r
+ std::map< Kind, Node >::iterator it = d_zero.find( k );\r
+ if( it==d_zero.end() ){\r
+ Node nn;\r
+ if( k==PLUS ){\r
+ nn = NodeManager::currentNM()->mkConst( Rational(0) );\r
+ }\r
+ d_zero[k] = nn;\r
+ return nn;\r
+ }else{\r
+ return it->second;\r
+ }\r
+}\r
+\r
+\r
+}\r
-/********************* */
-/*! \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
+/********************* */\r
+/*! \file quant_conflict_find.h\r
+ ** \verbatim\r
+ ** Original author: Andrew Reynolds\r
+ ** Major contributors: none\r
+ ** Minor contributors (to current version): none\r
+ ** This file is part of the CVC4 project.\r
+ ** Copyright (c) 2009-2014 New York University and The University of Iowa\r
+ ** See the file COPYING in the top-level source directory for licensing\r
+ ** information.\endverbatim\r
+ **\r
+ ** \brief quantifiers conflict find class\r
+ **/\r
+\r
+#include "cvc4_private.h"\r
+\r
+#ifndef QUANT_CONFLICT_FIND\r
+#define QUANT_CONFLICT_FIND\r
+\r
+#include "context/cdhashmap.h"\r
+#include "context/cdchunk_list.h"\r
+#include "theory/quantifiers_engine.h"\r
+#include "theory/quantifiers/term_database.h"\r
+\r
+namespace CVC4 {\r
+namespace theory {\r
+namespace quantifiers {\r
+\r
+class QuantConflictFind;\r
+class QuantInfo;\r
+\r
+//match generator\r
+class MatchGen {\r
+ friend class QuantInfo;\r
+private:\r
+ //current children information\r
+ int d_child_counter;\r
+ //children of this object\r
+ std::vector< int > d_children_order;\r
+ unsigned getNumChildren() { return d_children.size(); }\r
+ MatchGen * getChild( int i ) { return &d_children[d_children_order[i]]; }\r
+ //MatchGen * getChild( int i ) { return &d_children[i]; }\r
+ //current matching information\r
+ std::vector< TermArgTrie * > d_qn;\r
+ std::vector< std::map< TNode, TermArgTrie >::iterator > d_qni;\r
+ bool doMatching( QuantConflictFind * p, QuantInfo * qi );\r
+ //for matching : each index is either a variable or a ground term\r
+ unsigned d_qni_size;\r
+ std::map< int, int > d_qni_var_num;\r
+ std::map< int, TNode > d_qni_gterm;\r
+ std::map< int, TNode > d_qni_gterm_rep;\r
+ std::map< int, int > d_qni_bound;\r
+ std::vector< int > d_qni_bound_except;\r
+ std::map< int, TNode > d_qni_bound_cons;\r
+ std::map< int, int > d_qni_bound_cons_var;\r
+ std::map< int, int >::iterator d_binding_it;\r
+ //std::vector< int > d_independent;\r
+ bool d_matched_basis;\r
+ bool d_binding;\r
+ //int getVarBindingVar();\r
+ std::map< int, Node > d_ground_eval;\r
+ //determine variable order\r
+ void determineVariableOrder( QuantInfo * qi, std::vector< int >& bvars );\r
+ void collectBoundVar( QuantInfo * qi, Node n, std::vector< int >& cbvars );\r
+public:\r
+ //type of the match generator\r
+ enum {\r
+ typ_invalid,\r
+ typ_ground,\r
+ typ_pred,\r
+ typ_eq,\r
+ typ_formula,\r
+ typ_var,\r
+ typ_ite_var,\r
+ typ_bool_var,\r
+ typ_tconstraint,\r
+ typ_tsym,\r
+ };\r
+ void debugPrintType( const char * c, short typ, bool isTrace = false );\r
+public:\r
+ MatchGen() : d_type( typ_invalid ){}\r
+ MatchGen( QuantInfo * qi, Node n, bool isVar = false );\r
+ bool d_tgt;\r
+ bool d_tgt_orig;\r
+ bool d_wasSet;\r
+ Node d_n;\r
+ std::vector< MatchGen > d_children;\r
+ short d_type;\r
+ bool d_type_not;\r
+ void reset_round( QuantConflictFind * p );\r
+ void reset( QuantConflictFind * p, bool tgt, QuantInfo * qi );\r
+ bool getNextMatch( QuantConflictFind * p, QuantInfo * qi );\r
+ bool getExplanation( QuantConflictFind * p, QuantInfo * qi, std::vector< Node >& exp );\r
+ Node getExplanationTerm( QuantConflictFind * p, QuantInfo * qi, Node t, std::vector< Node >& exp );\r
+ bool isValid() { return d_type!=typ_invalid; }\r
+ void setInvalid();\r
+\r
+ // is this term treated as UF application?\r
+ static bool isHandledBoolConnective( TNode n );\r
+ static bool isHandledUfTerm( TNode n );\r
+ static Node getOperator( QuantConflictFind * p, Node n );\r
+ //can this node be handled by the algorithm\r
+ static bool isHandled( TNode n );\r
+};\r
+\r
+//info for quantifiers\r
+class QuantInfo {\r
+private:\r
+ void registerNode( Node n, bool hasPol, bool pol, bool beneathQuant = false );\r
+ void flatten( Node n, bool beneathQuant );\r
+private: //for completing match\r
+ std::vector< int > d_unassigned;\r
+ std::vector< TypeNode > d_unassigned_tn;\r
+ int d_unassigned_nvar;\r
+ int d_una_index;\r
+ std::vector< int > d_una_eqc_count;\r
+public:\r
+ QuantInfo() : d_mg( NULL ) {}\r
+ ~QuantInfo() { delete d_mg; }\r
+ std::vector< TNode > d_vars;\r
+ std::map< TNode, int > d_var_num;\r
+ std::vector< int > d_tsym_vars;\r
+ std::map< TNode, bool > d_inMatchConstraint;\r
+ std::map< int, std::vector< Node > > d_var_constraint[2];\r
+ int getVarNum( TNode v ) { return d_var_num.find( v )!=d_var_num.end() ? d_var_num[v] : -1; }\r
+ bool isVar( TNode v ) { return d_var_num.find( v )!=d_var_num.end(); }\r
+ int getNumVars() { return (int)d_vars.size(); }\r
+ TNode getVar( int i ) { return d_vars[i]; }\r
+\r
+ MatchGen * d_mg;\r
+ Node d_q;\r
+ std::map< int, MatchGen * > d_var_mg;\r
+ void reset_round( QuantConflictFind * p );\r
+public:\r
+ //initialize\r
+ void initialize( Node q, Node qn );\r
+ //current constraints\r
+ std::vector< TNode > d_match;\r
+ std::vector< TNode > d_match_term;\r
+ std::map< int, std::map< TNode, int > > d_curr_var_deq;\r
+ std::map< Node, bool > d_tconstraints;\r
+ int getCurrentRepVar( int v );\r
+ TNode getCurrentValue( TNode n );\r
+ TNode getCurrentExpValue( TNode n );\r
+ bool getCurrentCanBeEqual( QuantConflictFind * p, int v, TNode n, bool chDiseq = false );\r
+ int addConstraint( QuantConflictFind * p, int v, TNode n, bool polarity );\r
+ int addConstraint( QuantConflictFind * p, int v, TNode n, int vn, bool polarity, bool doRemove );\r
+ bool setMatch( QuantConflictFind * p, int v, TNode n );\r
+ bool isMatchSpurious( QuantConflictFind * p );\r
+ bool isTConstraintSpurious( QuantConflictFind * p, std::vector< Node >& terms );\r
+ bool entailmentTest( QuantConflictFind * p, Node lit, bool chEnt = true );\r
+ bool completeMatch( QuantConflictFind * p, std::vector< int >& assigned, bool doContinue = false );\r
+ void revertMatch( std::vector< int >& assigned );\r
+ void debugPrintMatch( const char * c );\r
+ bool isConstrainedVar( int v );\r
+public:\r
+ void getMatch( std::vector< Node >& terms );\r
+};\r
+\r
+class QuantConflictFind : public QuantifiersModule\r
+{\r
+ friend class MatchGen;\r
+ friend class QuantInfo;\r
+ typedef context::CDChunkList<Node> NodeList;\r
+ typedef context::CDHashMap<Node, bool, NodeHashFunction> NodeBoolMap;\r
+private:\r
+ context::Context* d_c;\r
+ context::CDO< bool > d_conflict;\r
+ std::vector< Node > d_quant_order;\r
+ std::map< Kind, Node > d_zero;\r
+ //for storing nodes created during t-constraint solving (prevents memory leaks)\r
+ std::vector< Node > d_tempCache;\r
+private:\r
+ std::map< Node, Node > d_op_node;\r
+ int d_fid_count;\r
+ std::map< Node, int > d_fid;\r
+ Node mkEqNode( Node a, Node b );\r
+public: //for ground terms\r
+ Node d_true;\r
+ Node d_false;\r
+ TNode getZero( Kind k );\r
+private:\r
+ Node evaluateTerm( Node n );\r
+ int evaluate( Node n, bool pref = false, bool hasPref = false );\r
+private:\r
+ //currently asserted quantifiers\r
+ NodeList d_qassert;\r
+ std::map< Node, QuantInfo > d_qinfo;\r
+private: //for equivalence classes\r
+ // type -> list(eqc)\r
+ std::map< TypeNode, std::vector< TNode > > d_eqcs;\r
+ std::map< TypeNode, Node > d_model_basis;\r
+public:\r
+ enum {\r
+ effort_conflict,\r
+ effort_prop_eq,\r
+ effort_mc,\r
+ };\r
+ short d_effort;\r
+ void setEffort( int e ) { d_effort = e; }\r
+ static short getMaxQcfEffort();\r
+ bool areMatchEqual( TNode n1, TNode n2 );\r
+ bool areMatchDisequal( TNode n1, TNode n2 );\r
+public:\r
+ QuantConflictFind( QuantifiersEngine * qe, context::Context* c );\r
+ /** register quantifier */\r
+ void registerQuantifier( Node q );\r
+public:\r
+ /** assert quantifier */\r
+ void assertNode( Node q );\r
+ /** new node */\r
+ void newEqClass( Node n );\r
+ /** merge */\r
+ void merge( Node a, Node b );\r
+ /** assert disequal */\r
+ void assertDisequal( Node a, Node b );\r
+ /** needs check */\r
+ bool needsCheck( Theory::Effort level );\r
+ /** reset round */\r
+ void reset_round( Theory::Effort level );\r
+ /** check */\r
+ void check( Theory::Effort level, unsigned quant_e );\r
+private:\r
+ bool d_needs_computeRelEqr;\r
+public:\r
+ void computeRelevantEqr();\r
+private:\r
+ void debugPrint( const char * c );\r
+ //for debugging\r
+ std::vector< Node > d_quants;\r
+ std::map< Node, int > d_quant_id;\r
+ void debugPrintQuant( const char * c, Node q );\r
+ void debugPrintQuantBody( const char * c, Node q, Node n, bool doVarNum = true );\r
+public:\r
+ /** statistics class */\r
+ class Statistics {\r
+ public:\r
+ IntStat d_inst_rounds;\r
+ IntStat d_conflict_inst;\r
+ IntStat d_prop_inst;\r
+ IntStat d_entailment_checks;\r
+ Statistics();\r
+ ~Statistics();\r
+ };\r
+ Statistics d_statistics;\r
+ /** Identify this module */\r
+ std::string identify() const { return "QcfEngine"; }\r
+};\r
+\r
+}\r
+}\r
+}\r
+\r
+#endif\r
#include "theory/quantifiers/quantifiers_attributes.h"
#include "theory/quantifiers/options.h"
+#include "theory/quantifiers/term_database.h"
using namespace std;
using namespace CVC4;
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=="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 );
}
}
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;
* 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 );
};
}
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] );
}
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 ){
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] );
}
}
}
+ 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;
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
}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 ){
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);
//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
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 ) {
//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() ){
}else{
//otherwise, the search will continue
- d_quantEngine->flushLemmas( &d_quantEngine->getOutputChannel() );
}
}
}
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 */
#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;
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 );
}
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 */
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() );
}
}
}
}
}
- 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;
}
}
}
}
}
+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;
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{
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() ){
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;
}
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++ ){
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() ){
}
}
+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();
}
return Node::null();
}
}
+
+
+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(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::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;
+ }
+}
#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 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 */
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;
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 */
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 */
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
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 */
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 */
int isInstanceOf( Node n1, Node n2 );
/** filter all nodes that have instances */
void filterInstances( std::vector< Node >& nodes );
-public:
+
+
+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 );
+
+//attributes
+private:
+ std::map< Node, bool > d_qattr_conjecture;
+ std::map< Node, bool > d_qattr_axiom;
+ 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 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 */
d_baseDecLevel = -1;
out.handleUserAttribute( "axiom", this );
out.handleUserAttribute( "conjecture", this );
+ out.handleUserAttribute( "sygus", this );
+ out.handleUserAttribute( "synthesis", this );
+ out.handleUserAttribute( "quant-inst-max-level", this );
+ out.handleUserAttribute( "rr-priority", this );
}
TheoryQuantifiers::~TheoryQuantifiers() {
}
void TheoryQuantifiers::check(Effort e) {
+ if (done() && !fullEffort(e)) {
+ return;
+ }
+
CodeTimer codeTimer(d_theoryTime);
Trace("quantifiers-check") << "quantifiers::check(" << e << ")" << std::endl;
}
}
-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 );
}
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:
}
};/* 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)
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");
}
}
}
};/* class RewriteRuleTypeRule */
-
class RRRewriteTypeRule {
public:
}
//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 ){
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 ) ){
return true;
}else{
std::map< Node, Node > coeffs;
- if( isArithmeticTrigger( f, n, coeffs ) ){
- return true;
- }else if( isBooleanTermTrigger( n ) ){
+ if( isBooleanTermTrigger( n ) ){
return true;
}
}
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 ) {
}
-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;
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;
}
}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 ){
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;
}
}
}
}
-void Trigger::collectPatTerms( QuantifiersEngine* qe, Node f, Node n, std::vector< Node >& patTerms, int tstrt, bool filterInst ){
+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;
+ }
+}
+
+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 );
}
}
}
- 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 );
}
}
-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 ){
namespace inst {
class IMGenerator;
+class InstMatchGenerator;
//a collect of nodes representing a trigger
class Trigger {
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 );
public:
//different strategies for choosing trigger terms
enum {
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 );
+ /** 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 {
/*
#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"
using namespace CVC4::theory;
using namespace CVC4::theory::inst;
+
+eq::EqualityEngine * QuantifiersModule::getEqualityEngine() {
+ return d_quantEngine->getTheoryEngine()->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){
}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() );
}else{
d_rr_engine = NULL;
}
+ if( options::ceGuidedInst() ){
+ d_ceg_inst = new quantifiers::CegInstantiation( this, c );
+ d_modules.push_back( d_ceg_inst );
+ }else{
+ d_ceg_inst = NULL;
+ }
//options
d_total_inst_count_debug = 0;
}
}
+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 needsBuildModel = 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( 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;
+
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++ ){
+ 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;
+ }
}
- 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;
+ needsBuildModel = 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 ){
}
}
Trace("quant-engine") << "Finished quantifiers engine check." << std::endl;
+ }else{
+ if( e==Theory::EFFORT_LAST_CALL && options::produceModels() ){
+ needsBuildModel = true;
+ }
+ }
+
+ if( needsBuildModel ){
+ 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 );
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 );
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 );
}
}
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++ ){
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;
}
}
}
- 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);
}
}
-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;
}
}
+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++ ){
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;
++(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 ){
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 ){
//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;
}
}
//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;
//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();
}
}
}
}
+//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
}
class QuantifiersEngine;
+namespace quantifiers {
+ class TermDb;
+}
+
class QuantifiersModule {
protected:
QuantifiersEngine* d_quantEngine;
/* 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;
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;
class QuantConflictFind;
class RewriteEngine;
class RelevantDomain;
+ class ConjectureGenerator;
+ class CegInstantiation;
}/* CVC4::theory::quantifiers */
namespace inst {
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;
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;
/** 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 */
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();
/** 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 );
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 */
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(); }
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:
}
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 );
}
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
}
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;
}
void TheorySets::check(Effort e) {
+ if (done() && !fullEffort(e)) {
+ return;
+ }
d_internal->check(e);
}
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);
}
Node explain(TNode);
+ EqualityStatus getEqualityStatus(TNode a, TNode b);
+
+ Node getModelValue(TNode);
+
std::string identify() const { return "THEORY_SETS"; }
void preRegisterTerm(TNode node);
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 ********************/
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)
{
#endif
}
+Node TheorySetsPrivate::getModelValue(TNode n)
+{
+ CodeTimer codeTimer(d_statistics.d_getModelValueTime);
+ return d_termInfoManager->getModelValue(n);
+}
/********************** Helper functions ***************************/
/********************** Helper functions ***************************/
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);
}
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());
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);
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;
}
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) {
return mkAnd(assumptions);
}
+
void TheorySetsPrivate::preRegisterTerm(TNode node)
{
Debug("sets") << "TheorySetsPrivate::preRegisterTerm(" << node << ")"
d_info[S]->addToElementList(x, polarity);
d_info[x]->addToSetList(S, polarity);
+
+ d_theory.d_modelCache.clear();
}
const CDTNodeList* TheorySetsPrivate::TermInfoManager::getParents(TNode x) {
(*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 */
context::UserContext* u);
~TheorySetsPrivate();
-
+
void setMasterEqualityEngine(eq::EqualityEngine* eq);
void addSharedTerm(TNode);
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;
class Statistics {
public:
TimerStat d_checkTime;
+ TimerStat d_getModelValueTime;
+ IntStat d_memberLemmas;
+ IntStat d_disequalityLemmas;
Statistics();
~Statistics();
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;
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);
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 */
}
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();
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
}
}
+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();
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);
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) {
+ 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) {
+ 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();
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 );
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
void TheoryStrings::check(Effort e) {
+ if (done() && !fullEffort(e)) {
+ return;
+ }
+
bool polarity;
TNode atom;
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();
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;
}
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()) {
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);
}
//}
+ 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
}/* CVC4::theory::strings namespace */
}/* CVC4::theory namespace */
-}/* CVC4 namespace */
\ No newline at end of file
+}/* CVC4 namespace */
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) {
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: {
return false;
}
case kind::REGEXP_SIGMA: {
- if(s.size() == 1) {
+ if(s.size() == index_start + 1) {
return true;
} else {
return false;
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] ) );
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) {
}
};
+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 */
/**
* Returns true if the assertFact queue is empty
*/
- bool done() throw() {
+ bool done() const throw() {
return d_factsHead == d_facts.size();
}
* 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());
}
#include "smt/logic_exception.h"
+#include "proof/proof_manager.h"
+
#include "util/node_visitor.h"
#include "util/ite_removal.h"
using namespace CVC4::theory;
void TheoryEngine::finishInit() {
+ PROOF (ProofManager::initTheoryProof(); );
+
// initialize the quantifiers engine
d_quantEngine = new QuantifiersEngine(d_context, d_userContext, this);
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;
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);
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();
void TheoryEngine::combineTheories() {
- Debug("sharing") << "TheoryEngine::combineTheories()" << endl;
+ Trace("combineTheories") << "TheoryEngine::combineTheories()" << endl;
TimerStat::CodeTimer combineTheoriesTimer(d_combineTheoriesTime);
// 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);
+ // }
+ // }
}
}
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 );
}
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) {
}
// 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) {
}
-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?
*/
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.
*/
* 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.
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
/*! \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
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 */
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);
}
}
}/* mkAnd() */
void TheoryUF::check(Effort level) {
+ if (done() && !fullEffort(level)) {
+ return;
+ }
+
while (!done() && !d_conflict)
{
// Get all the assertions
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;
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;
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;
}
//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() );
}
}
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 ){
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,
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 ){
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 ) ){
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:
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 */
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 );
}
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 {
regexp.cpp \
bin_heap.h \
didyoumean.h \
- didyoumean.cpp
+ didyoumean.cpp \
+ unsat_core.h \
+ unsat_core.cpp
libstatistics_la_SOURCES = \
statistics_registry.h \
uninterpreted_constant.i \
chain.i \
regexp.i \
- proof.i
+ proof.i \
+ unsat_core.i
DISTCLEANFILES = \
integer.h.tmp \
}
}
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;
}
#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;
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;
}
}
* 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
--- /dev/null
+/********************* */
+/*! \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 */
--- /dev/null
+/********************* */
+/*! \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 */
--- /dev/null
+%{
+#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"
wiki.19.cvc \
wiki.20.cvc \
wiki.21.cvc \
- simplification_bug3.cvc \
queries0.cvc \
print_lambda.cvc \
trim.cvc
swap_t1_np_nf_ai_00005_007.cvc.smt \
x2.smt \
x3.smt \
- parsing_ringer.cvc
-
-EXTRA_DIST = $(TESTS) \
+ parsing_ringer.cvc \
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
--- /dev/null
+% 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;
--- /dev/null
+(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)
--- /dev/null
+% 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;
--- /dev/null
+(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)
--- /dev/null
+% 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;
--- /dev/null
+; 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)
% EXPECT: sat
% EXPECT: sat
% EXPECT: sat
+% EXPECT: sat
+% EXPECT: sat
+% EXPECT: unsat
+% EXPECT: unsat
+% EXPECT: sat
PUSH;
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;
(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))))
bug286.cvc \
bug438.cvc \
bug438b.cvc \
- wrong-sel-simp.cvc
+ wrong-sel-simp.cvc \
+ tenum-bug.smt2
FAILING_TESTS = \
datatype-dump.cvc
--- /dev/null
+(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
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
--- /dev/null
+; 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
+++ /dev/null
-% COMMAND-LINE: --simplification=incremental
-x, y: BOOLEAN;
-ASSERT x OR y;
-ASSERT NOT x;
-ASSERT NOT y;
-% EXPECT: unsat
-CHECKSAT;
str005.smt2 \
str006.smt2 \
str007.smt2 \
- fmf001.smt2 \
fmf002.smt2 \
type001.smt2 \
type003.smt2 \
FAILING_TESTS =
EXTRA_DIST = $(TESTS) \
+ fmf001.smt2 \
regexp002.smt2 \
type002.smt2
shift
done
+[[ "$VALGRIND" = "1" ]] && {
+ wrapper="libtool --mode=execute valgrind $wrapper"
+}
+
cvc4=$1
benchmark_orig=$2
benchmark="$benchmark_orig"
# 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"
return d_nextVar++;
}
- void addClause(SatClause& c, bool lemma) {
+ void addClause(SatClause& c, bool lemma, uint64_t) {
d_addClauseCalled = true;
}
void renewVar(SatLiteral lit, int level = -1) {
}
+ bool spendResource() {
+ return false;
+ }
+
void interrupt() {
}
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() );
}
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() );
}
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() );
}
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() );
}
// 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() );
}
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() );
}
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() );
}
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() );
}
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() );
}