cvc3-2.4.1/0000775000175400017540000000000011630011320012241 5ustar mdetersmdeterscvc3-2.4.1/Makefile0000664000175400017540000002050111327624065013722 0ustar mdetersmdetersinclude Makefile.local # The list of Makefiles and other important script sources which must # be included in any distribution. DISTFILES = \ Makefile \ Makefile.std \ Makefile.local.in \ configure.ac \ configure \ config.guess \ config.sub \ install-sh \ INSTALL \ LICENSE.in \ PEOPLE \ README \ VERSION \ bin/unpack.in \ bin/run_tests.in \ bin/cvc2smt.in \ doc/Doxyfile.in \ doc/Makefile.in \ doc/devel.dox \ doc/mainpage.dox \ doc/userdoc.dox \ doc/theory_api.dox \ doc/theory_api_flow.fig \ src/Makefile \ src/cvc3.pc.in \ test/Makefile \ test/george.h \ test/george.cpp \ test/main.cpp \ testc/Makefile \ testc/main.c \ emacs/cvc-mode.el all: build .PHONY: build build: cd $(TOP)/src; $(MAKE) $(TARGET) VERSION=$(VERSION) ifeq ($(BUILD_JAVA),1) cd $(TOP)/java; $(MAKE) $(TARGET) VERSION=$(VERSION) endif ifeq ($(CYGWIN),) ifndef TARGET find $(TOP)/src '(' -name "*.h" -o -name "*.cpp" -o \ -name "*.y" ')' \ ! -name "lexPL.cpp" ! -name "parsePL.cpp" \ -print > FILES ifdef ETAGS sed -e s/^/\'/ -e s/$$/\'/ FILES | xargs etags endif ifdef EBROWSE ebrowse --files=FILES endif endif endif #Standard make targets .PHONY: depend spotty install depend: $(MAKE) TARGET=depend spotty: $(MAKE) TARGET=spotty install: $(MAKE) TARGET=install # Special make targets for top Makefile .PHONY: update-web update-web-doc doc dist dist_src dist_bin ld_sh ld_csh update-web: cp $(TOP)/webpage/*.html $(WEBDIR) cp $(TOP)/webpage/*.jpg $(WEBDIR) cp $(TOP)/webpage/*.css $(WEBDIR) update-web-doc: doc cd $(TOP)/doc/html/; tar cvBf - . | (cd $(WEBDIR)/doc/; tar xvpBf -) doc: cd $(TOP)/doc; $(MAKE) dist: dist_src # dist: dist_src dist_bin TMPFILE=$(TOP)/filelist.tmp TARDIR=cvc3-$(VERSION) TARFILE=$(TARDIR).tar.gz DISTTMPDIR=$(TOP)/dist-bak dist_src: @mkdir -p $(DISTTMPDIR) ifndef DPLL_BASIC @mv configure.ac configure $(DISTTMPDIR) @cat $(DISTTMPDIR)/configure.ac | sed '/#BEGIN/,/#END/ d' > $(TOP)/configure.ac @autoconf endif @rm -rf $(TMPFILE); touch $(TMPFILE) echo "Collecting top-level script files" @echo $(DISTFILES) >> $(TMPFILE) cd $(TOP)/src; $(MAKE) print_src FILELIST=$(TMPFILE) cd $(TOP)/java; $(MAKE) print_src FILELIST=$(TMPFILE) echo "Building " $(TARFILE) @mkdir -p $(TARDIR) @tar cf - `cat $(TMPFILE)` | (cd $(TARDIR); tar xf -) @echo "$(VERSION)" > $(TARDIR)/VERSION @tar zcfv $(TARFILE) $(TARDIR) ifndef DPLL_BASIC @rm -f configure.ac configure @mv $(DISTTMPDIR)/configure* $(TOP) endif rm -rf $(TMPFILE) $(TARDIR) $(DISTTMPDIR) dist_bin: echo "Sorry, binary distribution is not implemented yet" exit 1 # Generate LD_LIBRARY_PATH assignments for various shells. # When CVC is compiled with dynamic libraries, run # `make ld_sh` or `make ld_tcsh` # before running cvc executable. ld_sh: @echo "export LD_LIBRARY_PATH=$(TOP)/lib" ld_csh: @echo "setenv LD_LIBRARY_PATH $(TOP)/lib" .PHONY: clean clean_gcov superclean_gcov clean_gprof distclean # Clean up all the files generated by gcov (including *.cpp.gcov) clean_gcov: find src -name "*.da" -exec rm -f {} \; superclean_gcov: clean_gcov find src -name "*.gcov" -exec rm -f {} \; find src -name "*.bb" -exec rm -f {} \; find src -name "*.bbg" -exec rm -f {} \; clean_gprof: rm -f gmon.out clean: superclean_gcov clean_gprof $(MAKE) TARGET=clean @rm -f $(REGRESS_LOG) @rm -f $(TOP)/.test* distclean: cd $(TOP)/src; $(MAKE) distclean cd $(TOP)/doc; $(MAKE) distclean cd $(TOP)/test; $(MAKE) distclean cd $(TOP)/java; $(MAKE) distclean rm -rf $(TOP)/test/bin $(TOP)/test/obj cd $(TOP)/testc; $(MAKE) distclean rm -rf $(TOP)/testc/bin $(TOP)/testc/obj @rm -rf $(DISTTMPDIR) @mkdir -p $(DISTTMPDIR) @mv $(TOP)/bin/*.in $(DISTTMPDIR) @-mv $(TOP)/bin/CVS $(DISTTMPDIR) @-mv $(TOP)/bin/.cvsignore $(DISTTMPDIR) rm -rf $(TOP)/bin @mv $(DISTTMPDIR) $(TOP)/bin @rm -rf $(DISTTMPDIR) rm -f TAGS BROWSE FILES LICENSE Makefile.local rm -rf $(TOP)/autom4te.cache rm -f config.log config.status $(LICENSE_INFO_FILE) rm -f $(REGRESS_LOG) @rm -f $(TOP)/.test* rm -rf $(TOP)/lib $(TOP)/obj # Regression tests: both for internal and presentation languages. .PHONY: regress regress0 regress1 regress2 regress3 regress4 .PHONY: regressonly regressonly0 regressonly1 regressonly2 regressonly3 regressonly4 REGRESS_LOG=regressions.log # The higher the level, the more tests are run (4 = all) REGRESS_TESTS0 = benchmarks REGRESS_TESTS1 = $(REGRESS_TESTS0) REGRESS_TESTS2 = $(REGRESS_TESTS1) REGRESS_TESTS3 = $(REGRESS_TESTS2) REGRESS_TESTS4 = $(REGRESS_TESTS3) REGRESS_TESTS = $(REGRESS_TESTS0) REGRESS_LEVEL=0 # Program name PROGNAME=$(TOP)/bin/cvc3 # Addiional options for run_tests script ifndef RUN_TESTS_OPTIONS ifeq ($(OPTIMIZED),1) RUN_TESTS_OPTIONS=+rt endif endif # Define to max. number of seconds to run each executable. # 0 = no limit TIME_LIMIT=1200 # Additional options CVC_OPTIONS=+stats ALL_OPTIONS= -l $(REGRESS_LEVEL) -vc $(PROGNAME) $(RUN_TESTS_OPTIONS) \ -t $(TIME_LIMIT) $(REGRESS_TESTS) -- $(CVC_OPTIONS) regress: build cd $(TOP)/test; $(MAKE) cd $(TOP)/testc; $(MAKE) @echo "*********************************************************" \ | tee -a $(REGRESS_LOG) @echo "Starting tests at" `date` | tee -a $(REGRESS_LOG) @echo "C++ API test" | tee -a $(REGRESS_LOG) @echo "*********************************************************" \ | tee -a $(REGRESS_LOG) $(TOP)/test/bin/test $(REGRESS_LEVEL) 2>&1 \ | tee -a $(REGRESS_LOG); [ $${PIPESTATUS[0]} -eq 0 ] @echo "*********************************************************" \ | tee -a $(REGRESS_LOG) @echo "C API test" | tee -a $(REGRESS_LOG) @echo "*********************************************************" \ | tee -a $(REGRESS_LOG) $(TOP)/testc/bin/testc $(REGRESS_LEVEL) 2>&1 \ | tee -a $(REGRESS_LOG); [ $${PIPESTATUS[0]} -eq 0 ] @rm -f $(TOP)/.test* ifeq ($(BUILD_JAVA),1) @echo "*********************************************************" \ | tee -a $(REGRESS_LOG) @echo "Java API test" | tee -a $(REGRESS_LOG) @echo "*********************************************************" \ | tee -a $(REGRESS_LOG) $(MAKE) -C java test 2>&1 \ | tee -a $(REGRESS_LOG); [ $${PIPESTATUS[0]} -eq 0 ] endif @echo "*********************************************************" \ | tee -a $(REGRESS_LOG) @echo "Regression tests" | tee -a $(REGRESS_LOG) @echo "*********************************************************" \ | tee -a $(REGRESS_LOG) $(TOP)/bin/run_tests $(ALL_OPTIONS) 2>&1 \ | tee -a $(REGRESS_LOG); [ $${PIPESTATUS[0]} -eq 0 ] @echo "*********************************************************" \ | tee -a $(REGRESS_LOG) @echo "Output is saved in $(REGRESS_LOG)" | tee -a $(REGRESS_LOG) @echo "*********************************************************" \ | tee -a $(REGRESS_LOG) regress0: $(MAKE) regress REGRESS_LEVEL=0 regress1: $(MAKE) regress REGRESS_LEVEL=1 REGRESS_TESTS="$(REGRESS_TESTS1)" regress2: $(MAKE) regress REGRESS_LEVEL=2 REGRESS_TESTS="$(REGRESS_TESTS2)" regress3: $(MAKE) regress REGRESS_LEVEL=3 REGRESS_TESTS="$(REGRESS_TESTS3)" TIME_LIMIT=1500 regress4: $(MAKE) regress REGRESS_LEVEL=4 REGRESS_TESTS="$(REGRESS_TESTS4)" TIME_LIMIT=0 regressonly: build @echo "*********************************************************" \ | tee -a $(REGRESS_LOG) @echo "Starting tests at" `date` | tee -a $(REGRESS_LOG) @echo "*********************************************************" \ | tee -a $(REGRESS_LOG) @echo "Regression tests" | tee -a $(REGRESS_LOG) @echo "*********************************************************" \ | tee -a $(REGRESS_LOG) $(TOP)/bin/run_tests $(ALL_OPTIONS) 2>&1 \ | tee -a $(REGRESS_LOG); [ $${PIPESTATUS[0]} -eq 0 ] @echo "*********************************************************" \ | tee -a $(REGRESS_LOG) @echo "Output is saved in $(REGRESS_LOG)" | tee -a $(REGRESS_LOG) @echo "*********************************************************" \ | tee -a $(REGRESS_LOG) regressonly0: $(MAKE) regressonly REGRESS_LEVEL=0 regressonly1: $(MAKE) regressonly REGRESS_LEVEL=1 REGRESS_TESTS="$(REGRESS_TESTS1)" regressonly2: $(MAKE) regressonly REGRESS_LEVEL=2 REGRESS_TESTS="$(REGRESS_TESTS2)" regressonly3: $(MAKE) regressonly REGRESS_LEVEL=3 REGRESS_TESTS="$(REGRESS_TESTS3)" TIME_LIMIT=1500 regressonly4: $(MAKE) regressonly REGRESS_LEVEL=4 REGRESS_TESTS="$(REGRESS_TESTS4)" TIME_LIMIT=0 cvc3-2.4.1/configure0000775000175400017540000052263511630011277014200 0ustar mdetersmdeters#! /bin/sh # Guess values for system-dependent variables and create Makefiles. # Generated by GNU Autoconf 2.67 for cvc3 2.4.1. # # # Copyright (C) 1992, 1993, 1994, 1995, 1996, 1998, 1999, 2000, 2001, # 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010 Free Software # Foundation, Inc. # # # This configure script is free software; the Free Software Foundation # gives unlimited permission to copy, distribute and modify it. ## -------------------- ## ## M4sh Initialization. ## ## -------------------- ## # Be more Bourne compatible DUALCASE=1; export DUALCASE # for MKS sh if test -n "${ZSH_VERSION+set}" && (emulate sh) >/dev/null 2>&1; then : emulate sh NULLCMD=: # Pre-4.2 versions of Zsh do word splitting on ${1+"$@"}, which # is contrary to our usage. Disable this feature. alias -g '${1+"$@"}'='"$@"' setopt NO_GLOB_SUBST else case `(set -o) 2>/dev/null` in #( *posix*) : set -o posix ;; #( *) : ;; esac fi as_nl=' ' export as_nl # Printing a long string crashes Solaris 7 /usr/bin/printf. as_echo='\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\' as_echo=$as_echo$as_echo$as_echo$as_echo$as_echo as_echo=$as_echo$as_echo$as_echo$as_echo$as_echo$as_echo # Prefer a ksh shell builtin over an external printf program on Solaris, # but without wasting forks for bash or zsh. if test -z "$BASH_VERSION$ZSH_VERSION" \ && (test "X`print -r -- $as_echo`" = "X$as_echo") 2>/dev/null; then as_echo='print -r --' as_echo_n='print -rn --' elif (test "X`printf %s $as_echo`" = "X$as_echo") 2>/dev/null; then as_echo='printf %s\n' as_echo_n='printf %s' else if test "X`(/usr/ucb/echo -n -n $as_echo) 2>/dev/null`" = "X-n $as_echo"; then as_echo_body='eval /usr/ucb/echo -n "$1$as_nl"' as_echo_n='/usr/ucb/echo -n' else as_echo_body='eval expr "X$1" : "X\\(.*\\)"' as_echo_n_body='eval arg=$1; case $arg in #( *"$as_nl"*) expr "X$arg" : "X\\(.*\\)$as_nl"; arg=`expr "X$arg" : ".*$as_nl\\(.*\\)"`;; esac; expr "X$arg" : "X\\(.*\\)" | tr -d "$as_nl" ' export as_echo_n_body as_echo_n='sh -c $as_echo_n_body as_echo' fi export as_echo_body as_echo='sh -c $as_echo_body as_echo' fi # The user is always right. if test "${PATH_SEPARATOR+set}" != set; then PATH_SEPARATOR=: (PATH='/bin;/bin'; FPATH=$PATH; sh -c :) >/dev/null 2>&1 && { (PATH='/bin:/bin'; FPATH=$PATH; sh -c :) >/dev/null 2>&1 || PATH_SEPARATOR=';' } fi # IFS # We need space, tab and new line, in precisely that order. Quoting is # there to prevent editors from complaining about space-tab. # (If _AS_PATH_WALK were called with IFS unset, it would disable word # splitting by setting IFS to empty value.) IFS=" "" $as_nl" # Find who we are. Look in the path if we contain no directory separator. case $0 in #(( *[\\/]* ) as_myself=$0 ;; *) as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. test -r "$as_dir/$0" && as_myself=$as_dir/$0 && break done IFS=$as_save_IFS ;; esac # We did not find ourselves, most probably we were run as `sh COMMAND' # in which case we are not to be found in the path. if test "x$as_myself" = x; then as_myself=$0 fi if test ! -f "$as_myself"; then $as_echo "$as_myself: error: cannot find myself; rerun with an absolute file name" >&2 exit 1 fi # Unset variables that we do not need and which cause bugs (e.g. in # pre-3.0 UWIN ksh). But do not cause bugs in bash 2.01; the "|| exit 1" # suppresses any "Segmentation fault" message there. '((' could # trigger a bug in pdksh 5.2.14. for as_var in BASH_ENV ENV MAIL MAILPATH do eval test x\${$as_var+set} = xset \ && ( (unset $as_var) || exit 1) >/dev/null 2>&1 && unset $as_var || : done PS1='$ ' PS2='> ' PS4='+ ' # NLS nuisances. LC_ALL=C export LC_ALL LANGUAGE=C export LANGUAGE # CDPATH. (unset CDPATH) >/dev/null 2>&1 && unset CDPATH if test "x$CONFIG_SHELL" = x; then as_bourne_compatible="if test -n \"\${ZSH_VERSION+set}\" && (emulate sh) >/dev/null 2>&1; then : emulate sh NULLCMD=: # Pre-4.2 versions of Zsh do word splitting on \${1+\"\$@\"}, which # is contrary to our usage. Disable this feature. alias -g '\${1+\"\$@\"}'='\"\$@\"' setopt NO_GLOB_SUBST else case \`(set -o) 2>/dev/null\` in #( *posix*) : set -o posix ;; #( *) : ;; esac fi " as_required="as_fn_return () { (exit \$1); } as_fn_success () { as_fn_return 0; } as_fn_failure () { as_fn_return 1; } as_fn_ret_success () { return 0; } as_fn_ret_failure () { return 1; } exitcode=0 as_fn_success || { exitcode=1; echo as_fn_success failed.; } as_fn_failure && { exitcode=1; echo as_fn_failure succeeded.; } as_fn_ret_success || { exitcode=1; echo as_fn_ret_success failed.; } as_fn_ret_failure && { exitcode=1; echo as_fn_ret_failure succeeded.; } if ( set x; as_fn_ret_success y && test x = \"\$1\" ); then : else exitcode=1; echo positional parameters were not saved. fi test x\$exitcode = x0 || exit 1" as_suggested=" as_lineno_1=";as_suggested=$as_suggested$LINENO;as_suggested=$as_suggested" as_lineno_1a=\$LINENO as_lineno_2=";as_suggested=$as_suggested$LINENO;as_suggested=$as_suggested" as_lineno_2a=\$LINENO eval 'test \"x\$as_lineno_1'\$as_run'\" != \"x\$as_lineno_2'\$as_run'\" && test \"x\`expr \$as_lineno_1'\$as_run' + 1\`\" = \"x\$as_lineno_2'\$as_run'\"' || exit 1 test \$(( 1 + 1 )) = 2 || exit 1" if (eval "$as_required") 2>/dev/null; then : as_have_required=yes else as_have_required=no fi if test x$as_have_required = xyes && (eval "$as_suggested") 2>/dev/null; then : else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR as_found=false for as_dir in /bin$PATH_SEPARATOR/usr/bin$PATH_SEPARATOR$PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. as_found=: case $as_dir in #( /*) for as_base in sh bash ksh sh5; do # Try only shells that exist, to save several forks. as_shell=$as_dir/$as_base if { test -f "$as_shell" || test -f "$as_shell.exe"; } && { $as_echo "$as_bourne_compatible""$as_required" | as_run=a "$as_shell"; } 2>/dev/null; then : CONFIG_SHELL=$as_shell as_have_required=yes if { $as_echo "$as_bourne_compatible""$as_suggested" | as_run=a "$as_shell"; } 2>/dev/null; then : break 2 fi fi done;; esac as_found=false done $as_found || { if { test -f "$SHELL" || test -f "$SHELL.exe"; } && { $as_echo "$as_bourne_compatible""$as_required" | as_run=a "$SHELL"; } 2>/dev/null; then : CONFIG_SHELL=$SHELL as_have_required=yes fi; } IFS=$as_save_IFS if test "x$CONFIG_SHELL" != x; then : # We cannot yet assume a decent shell, so we have to provide a # neutralization value for shells without unset; and this also # works around shells that cannot unset nonexistent variables. BASH_ENV=/dev/null ENV=/dev/null (unset BASH_ENV) >/dev/null 2>&1 && unset BASH_ENV ENV export CONFIG_SHELL exec "$CONFIG_SHELL" "$as_myself" ${1+"$@"} fi if test x$as_have_required = xno; then : $as_echo "$0: This script requires a shell more modern than all" $as_echo "$0: the shells that I found on your system." if test x${ZSH_VERSION+set} = xset ; then $as_echo "$0: In particular, zsh $ZSH_VERSION has bugs and should" $as_echo "$0: be upgraded to zsh 4.3.4 or later." else $as_echo "$0: Please tell bug-autoconf@gnu.org about your system, $0: including any error possibly output before this $0: message. Then install a modern shell, or manually run $0: the script under such a shell if you do have one." fi exit 1 fi fi fi SHELL=${CONFIG_SHELL-/bin/sh} export SHELL # Unset more variables known to interfere with behavior of common tools. CLICOLOR_FORCE= GREP_OPTIONS= unset CLICOLOR_FORCE GREP_OPTIONS ## --------------------- ## ## M4sh Shell Functions. ## ## --------------------- ## # as_fn_unset VAR # --------------- # Portably unset VAR. as_fn_unset () { { eval $1=; unset $1;} } as_unset=as_fn_unset # as_fn_set_status STATUS # ----------------------- # Set $? to STATUS, without forking. as_fn_set_status () { return $1 } # as_fn_set_status # as_fn_exit STATUS # ----------------- # Exit the shell with STATUS, even in a "trap 0" or "set -e" context. as_fn_exit () { set +e as_fn_set_status $1 exit $1 } # as_fn_exit # as_fn_mkdir_p # ------------- # Create "$as_dir" as a directory, including parents if necessary. as_fn_mkdir_p () { case $as_dir in #( -*) as_dir=./$as_dir;; esac test -d "$as_dir" || eval $as_mkdir_p || { as_dirs= while :; do case $as_dir in #( *\'*) as_qdir=`$as_echo "$as_dir" | sed "s/'/'\\\\\\\\''/g"`;; #'( *) as_qdir=$as_dir;; esac as_dirs="'$as_qdir' $as_dirs" as_dir=`$as_dirname -- "$as_dir" || $as_expr X"$as_dir" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ X"$as_dir" : 'X\(//\)[^/]' \| \ X"$as_dir" : 'X\(//\)$' \| \ X"$as_dir" : 'X\(/\)' \| . 2>/dev/null || $as_echo X"$as_dir" | sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ s//\1/ q } /^X\(\/\/\)[^/].*/{ s//\1/ q } /^X\(\/\/\)$/{ s//\1/ q } /^X\(\/\).*/{ s//\1/ q } s/.*/./; q'` test -d "$as_dir" && break done test -z "$as_dirs" || eval "mkdir $as_dirs" } || test -d "$as_dir" || as_fn_error $? "cannot create directory $as_dir" } # as_fn_mkdir_p # as_fn_append VAR VALUE # ---------------------- # Append the text in VALUE to the end of the definition contained in VAR. Take # advantage of any shell optimizations that allow amortized linear growth over # repeated appends, instead of the typical quadratic growth present in naive # implementations. if (eval "as_var=1; as_var+=2; test x\$as_var = x12") 2>/dev/null; then : eval 'as_fn_append () { eval $1+=\$2 }' else as_fn_append () { eval $1=\$$1\$2 } fi # as_fn_append # as_fn_arith ARG... # ------------------ # Perform arithmetic evaluation on the ARGs, and store the result in the # global $as_val. Take advantage of shells that can avoid forks. The arguments # must be portable across $(()) and expr. if (eval "test \$(( 1 + 1 )) = 2") 2>/dev/null; then : eval 'as_fn_arith () { as_val=$(( $* )) }' else as_fn_arith () { as_val=`expr "$@" || test $? -eq 1` } fi # as_fn_arith # as_fn_error STATUS ERROR [LINENO LOG_FD] # ---------------------------------------- # Output "`basename $0`: error: ERROR" to stderr. If LINENO and LOG_FD are # provided, also output the error to LOG_FD, referencing LINENO. Then exit the # script with STATUS, using 1 if that was 0. as_fn_error () { as_status=$1; test $as_status -eq 0 && as_status=1 if test "$4"; then as_lineno=${as_lineno-"$3"} as_lineno_stack=as_lineno_stack=$as_lineno_stack $as_echo "$as_me:${as_lineno-$LINENO}: error: $2" >&$4 fi $as_echo "$as_me: error: $2" >&2 as_fn_exit $as_status } # as_fn_error if expr a : '\(a\)' >/dev/null 2>&1 && test "X`expr 00001 : '.*\(...\)'`" = X001; then as_expr=expr else as_expr=false fi if (basename -- /) >/dev/null 2>&1 && test "X`basename -- / 2>&1`" = "X/"; then as_basename=basename else as_basename=false fi if (as_dir=`dirname -- /` && test "X$as_dir" = X/) >/dev/null 2>&1; then as_dirname=dirname else as_dirname=false fi as_me=`$as_basename -- "$0" || $as_expr X/"$0" : '.*/\([^/][^/]*\)/*$' \| \ X"$0" : 'X\(//\)$' \| \ X"$0" : 'X\(/\)' \| . 2>/dev/null || $as_echo X/"$0" | sed '/^.*\/\([^/][^/]*\)\/*$/{ s//\1/ q } /^X\/\(\/\/\)$/{ s//\1/ q } /^X\/\(\/\).*/{ s//\1/ q } s/.*/./; q'` # Avoid depending upon Character Ranges. as_cr_letters='abcdefghijklmnopqrstuvwxyz' as_cr_LETTERS='ABCDEFGHIJKLMNOPQRSTUVWXYZ' as_cr_Letters=$as_cr_letters$as_cr_LETTERS as_cr_digits='0123456789' as_cr_alnum=$as_cr_Letters$as_cr_digits as_lineno_1=$LINENO as_lineno_1a=$LINENO as_lineno_2=$LINENO as_lineno_2a=$LINENO eval 'test "x$as_lineno_1'$as_run'" != "x$as_lineno_2'$as_run'" && test "x`expr $as_lineno_1'$as_run' + 1`" = "x$as_lineno_2'$as_run'"' || { # Blame Lee E. McMahon (1931-1989) for sed's syntax. :-) sed -n ' p /[$]LINENO/= ' <$as_myself | sed ' s/[$]LINENO.*/&-/ t lineno b :lineno N :loop s/[$]LINENO\([^'$as_cr_alnum'_].*\n\)\(.*\)/\2\1\2/ t loop s/-\n.*// ' >$as_me.lineno && chmod +x "$as_me.lineno" || { $as_echo "$as_me: error: cannot create $as_me.lineno; rerun with a POSIX shell" >&2; as_fn_exit 1; } # Don't try to exec as it changes $[0], causing all sort of problems # (the dirname of $[0] is not the place where we might find the # original and so on. Autoconf is especially sensitive to this). . "./$as_me.lineno" # Exit status is that of the last command. exit } ECHO_C= ECHO_N= ECHO_T= case `echo -n x` in #((((( -n*) case `echo 'xy\c'` in *c*) ECHO_T=' ';; # ECHO_T is single tab character. xy) ECHO_C='\c';; *) echo `echo ksh88 bug on AIX 6.1` > /dev/null ECHO_T=' ';; esac;; *) ECHO_N='-n';; esac rm -f conf$$ conf$$.exe conf$$.file if test -d conf$$.dir; then rm -f conf$$.dir/conf$$.file else rm -f conf$$.dir mkdir conf$$.dir 2>/dev/null fi if (echo >conf$$.file) 2>/dev/null; then if ln -s conf$$.file conf$$ 2>/dev/null; then as_ln_s='ln -s' # ... but there are two gotchas: # 1) On MSYS, both `ln -s file dir' and `ln file dir' fail. # 2) DJGPP < 2.04 has no symlinks; `ln -s' creates a wrapper executable. # In both cases, we have to default to `cp -p'. ln -s conf$$.file conf$$.dir 2>/dev/null && test ! -f conf$$.exe || as_ln_s='cp -p' elif ln conf$$.file conf$$ 2>/dev/null; then as_ln_s=ln else as_ln_s='cp -p' fi else as_ln_s='cp -p' fi rm -f conf$$ conf$$.exe conf$$.dir/conf$$.file conf$$.file rmdir conf$$.dir 2>/dev/null if mkdir -p . 2>/dev/null; then as_mkdir_p='mkdir -p "$as_dir"' else test -d ./-p && rmdir ./-p as_mkdir_p=false fi if test -x / >/dev/null 2>&1; then as_test_x='test -x' else if ls -dL / >/dev/null 2>&1; then as_ls_L_option=L else as_ls_L_option= fi as_test_x=' eval sh -c '\'' if test -d "$1"; then test -d "$1/."; else case $1 in #( -*)set "./$1";; esac; case `ls -ld'$as_ls_L_option' "$1" 2>/dev/null` in #(( ???[sx]*):;;*)false;;esac;fi '\'' sh ' fi as_executable_p=$as_test_x # Sed expression to map a string onto a valid CPP name. as_tr_cpp="eval sed 'y%*$as_cr_letters%P$as_cr_LETTERS%;s%[^_$as_cr_alnum]%_%g'" # Sed expression to map a string onto a valid variable name. as_tr_sh="eval sed 'y%*+%pp%;s%[^_$as_cr_alnum]%_%g'" test -n "$DJDIR" || exec 7<&0 &1 # Name of the host. # hostname on some systems (SVR3.2, old GNU/Linux) returns a bogus exit status, # so uname gets run too. ac_hostname=`(hostname || uname -n) 2>/dev/null | sed 1q` # # Initializations. # ac_default_prefix=/usr/local ac_clean_files= ac_config_libobj_dir=. LIBOBJS= cross_compiling=no subdirs= MFLAGS= MAKEFLAGS= # Identity of this package. PACKAGE_NAME='cvc3' PACKAGE_TARNAME='cvc3' PACKAGE_VERSION='2.4.1' PACKAGE_STRING='cvc3 2.4.1' PACKAGE_BUGREPORT='' PACKAGE_URL='' # Factoring default headers for most tests. ac_includes_default="\ #include #ifdef HAVE_SYS_TYPES_H # include #endif #ifdef HAVE_SYS_STAT_H # include #endif #ifdef STDC_HEADERS # include # include #else # ifdef HAVE_STDLIB_H # include # endif #endif #ifdef HAVE_STRING_H # if !defined STDC_HEADERS && defined HAVE_MEMORY_H # include # endif # include #endif #ifdef HAVE_STRINGS_H # include #endif #ifdef HAVE_INTTYPES_H # include #endif #ifdef HAVE_STDINT_H # include #endif #ifdef HAVE_UNISTD_H # include #endif" ac_subst_vars='LTLIBOBJS LIBOBJS EBROWSE ETAGS HAVE_DOT FIG2DEV DOXYTAG DOXYGEN TOP JAVA_INCLUDES EGREP GREP JNI_INC PYTHON JREFLAGS JFLAGS JAVAH JAVAC JAVA JAR javadir BUILD_JAVA RATIONAL_IMPL SHARED_LIB_SUFFIX STATIC_LIB_SUFFIX LD_LIB_DIR LD_SWITCHES_POST LD_SWITCHES_PRE SHARED DYNAMIC_FLAG STATIC_FLAG BUILD_SHARED_LIB STATIC LEXLIB LEX_OUTPUT_ROOT LEX YFLAGS YACC PERL TIME LDCONFIG INSTALL_FLAGS INSTALL host_os host_vendor host_cpu host build_os build_vendor build_cpu build LD GPROF GCOV OPTIMIZED VERSION DPLL_BASIC EXTRA_SAT_CPP EXTRA_SAT_HEADERS AR CXXCPP OBJEXT EXEEXT ac_ct_CXX CPPFLAGS LDFLAGS CXXFLAGS CXX LIB_TEENY_VERSION LIB_MINOR_VERSION LIB_MAJOR_VERSION target_alias host_alias build_alias LIBS ECHO_T ECHO_N ECHO_C DEFS mandir localedir libdir psdir pdfdir dvidir htmldir infodir docdir oldincludedir includedir localstatedir sharedstatedir sysconfdir datadir datarootdir libexecdir sbindir bindir program_transform_name prefix exec_prefix PACKAGE_URL PACKAGE_BUGREPORT PACKAGE_STRING PACKAGE_VERSION PACKAGE_TARNAME PACKAGE_NAME PATH_SEPARATOR SHELL' ac_subst_files='LICENSE_INFO' ac_user_opts=' enable_option_checking enable_zchaff with_build enable_debug_yacc with_ld with_extra_libs with_extra_includes with_version enable_broken_cxx enable_static enable_dynamic enable_sharedlibs with_arith enable_java with_java_home with_java_includes ' ac_precious_vars='build_alias host_alias target_alias CXX CXXFLAGS LDFLAGS LIBS CPPFLAGS CCC CXXCPP AR YACC YFLAGS javadir JAR JAVA JAVAC JAVAH JFLAGS JREFLAGS PYTHON' # Initialize some variables set by options. ac_init_help= ac_init_version=false ac_unrecognized_opts= ac_unrecognized_sep= # The variables have the same names as the options, with # dashes changed to underlines. cache_file=/dev/null exec_prefix=NONE no_create= no_recursion= prefix=NONE program_prefix=NONE program_suffix=NONE program_transform_name=s,x,x, silent= site= srcdir= verbose= x_includes=NONE x_libraries=NONE # Installation directory options. # These are left unexpanded so users can "make install exec_prefix=/foo" # and all the variables that are supposed to be based on exec_prefix # by default will actually change. # Use braces instead of parens because sh, perl, etc. also accept them. # (The list follows the same order as the GNU Coding Standards.) bindir='${exec_prefix}/bin' sbindir='${exec_prefix}/sbin' libexecdir='${exec_prefix}/libexec' datarootdir='${prefix}/share' datadir='${datarootdir}' sysconfdir='${prefix}/etc' sharedstatedir='${prefix}/com' localstatedir='${prefix}/var' includedir='${prefix}/include' oldincludedir='/usr/include' docdir='${datarootdir}/doc/${PACKAGE_TARNAME}' infodir='${datarootdir}/info' htmldir='${docdir}' dvidir='${docdir}' pdfdir='${docdir}' psdir='${docdir}' libdir='${exec_prefix}/lib' localedir='${datarootdir}/locale' mandir='${datarootdir}/man' ac_prev= ac_dashdash= for ac_option do # If the previous option needs an argument, assign it. if test -n "$ac_prev"; then eval $ac_prev=\$ac_option ac_prev= continue fi case $ac_option in *=?*) ac_optarg=`expr "X$ac_option" : '[^=]*=\(.*\)'` ;; *=) ac_optarg= ;; *) ac_optarg=yes ;; esac # Accept the important Cygnus configure options, so we can diagnose typos. case $ac_dashdash$ac_option in --) ac_dashdash=yes ;; -bindir | --bindir | --bindi | --bind | --bin | --bi) ac_prev=bindir ;; -bindir=* | --bindir=* | --bindi=* | --bind=* | --bin=* | --bi=*) bindir=$ac_optarg ;; -build | --build | --buil | --bui | --bu) ac_prev=build_alias ;; -build=* | --build=* | --buil=* | --bui=* | --bu=*) build_alias=$ac_optarg ;; -cache-file | --cache-file | --cache-fil | --cache-fi \ | --cache-f | --cache- | --cache | --cach | --cac | --ca | --c) ac_prev=cache_file ;; -cache-file=* | --cache-file=* | --cache-fil=* | --cache-fi=* \ | --cache-f=* | --cache-=* | --cache=* | --cach=* | --cac=* | --ca=* | --c=*) cache_file=$ac_optarg ;; --config-cache | -C) cache_file=config.cache ;; -datadir | --datadir | --datadi | --datad) ac_prev=datadir ;; -datadir=* | --datadir=* | --datadi=* | --datad=*) datadir=$ac_optarg ;; -datarootdir | --datarootdir | --datarootdi | --datarootd | --dataroot \ | --dataroo | --dataro | --datar) ac_prev=datarootdir ;; -datarootdir=* | --datarootdir=* | --datarootdi=* | --datarootd=* \ | --dataroot=* | --dataroo=* | --dataro=* | --datar=*) datarootdir=$ac_optarg ;; -disable-* | --disable-*) ac_useropt=`expr "x$ac_option" : 'x-*disable-\(.*\)'` # Reject names that are not valid shell variable names. expr "x$ac_useropt" : ".*[^-+._$as_cr_alnum]" >/dev/null && as_fn_error $? "invalid feature name: $ac_useropt" ac_useropt_orig=$ac_useropt ac_useropt=`$as_echo "$ac_useropt" | sed 's/[-+.]/_/g'` case $ac_user_opts in *" "enable_$ac_useropt" "*) ;; *) ac_unrecognized_opts="$ac_unrecognized_opts$ac_unrecognized_sep--disable-$ac_useropt_orig" ac_unrecognized_sep=', ';; esac eval enable_$ac_useropt=no ;; -docdir | --docdir | --docdi | --doc | --do) ac_prev=docdir ;; -docdir=* | --docdir=* | --docdi=* | --doc=* | --do=*) docdir=$ac_optarg ;; -dvidir | --dvidir | --dvidi | --dvid | --dvi | --dv) ac_prev=dvidir ;; -dvidir=* | --dvidir=* | --dvidi=* | --dvid=* | --dvi=* | --dv=*) dvidir=$ac_optarg ;; -enable-* | --enable-*) ac_useropt=`expr "x$ac_option" : 'x-*enable-\([^=]*\)'` # Reject names that are not valid shell variable names. expr "x$ac_useropt" : ".*[^-+._$as_cr_alnum]" >/dev/null && as_fn_error $? "invalid feature name: $ac_useropt" ac_useropt_orig=$ac_useropt ac_useropt=`$as_echo "$ac_useropt" | sed 's/[-+.]/_/g'` case $ac_user_opts in *" "enable_$ac_useropt" "*) ;; *) ac_unrecognized_opts="$ac_unrecognized_opts$ac_unrecognized_sep--enable-$ac_useropt_orig" ac_unrecognized_sep=', ';; esac eval enable_$ac_useropt=\$ac_optarg ;; -exec-prefix | --exec_prefix | --exec-prefix | --exec-prefi \ | --exec-pref | --exec-pre | --exec-pr | --exec-p | --exec- \ | --exec | --exe | --ex) ac_prev=exec_prefix ;; -exec-prefix=* | --exec_prefix=* | --exec-prefix=* | --exec-prefi=* \ | --exec-pref=* | --exec-pre=* | --exec-pr=* | --exec-p=* | --exec-=* \ | --exec=* | --exe=* | --ex=*) exec_prefix=$ac_optarg ;; -gas | --gas | --ga | --g) # Obsolete; use --with-gas. with_gas=yes ;; -help | --help | --hel | --he | -h) ac_init_help=long ;; -help=r* | --help=r* | --hel=r* | --he=r* | -hr*) ac_init_help=recursive ;; -help=s* | --help=s* | --hel=s* | --he=s* | -hs*) ac_init_help=short ;; -host | --host | --hos | --ho) ac_prev=host_alias ;; -host=* | --host=* | --hos=* | --ho=*) host_alias=$ac_optarg ;; -htmldir | --htmldir | --htmldi | --htmld | --html | --htm | --ht) ac_prev=htmldir ;; -htmldir=* | --htmldir=* | --htmldi=* | --htmld=* | --html=* | --htm=* \ | --ht=*) htmldir=$ac_optarg ;; -includedir | --includedir | --includedi | --included | --include \ | --includ | --inclu | --incl | --inc) ac_prev=includedir ;; -includedir=* | --includedir=* | --includedi=* | --included=* | --include=* \ | --includ=* | --inclu=* | --incl=* | --inc=*) includedir=$ac_optarg ;; -infodir | --infodir | --infodi | --infod | --info | --inf) ac_prev=infodir ;; -infodir=* | --infodir=* | --infodi=* | --infod=* | --info=* | --inf=*) infodir=$ac_optarg ;; -libdir | --libdir | --libdi | --libd) ac_prev=libdir ;; -libdir=* | --libdir=* | --libdi=* | --libd=*) libdir=$ac_optarg ;; -libexecdir | --libexecdir | --libexecdi | --libexecd | --libexec \ | --libexe | --libex | --libe) ac_prev=libexecdir ;; -libexecdir=* | --libexecdir=* | --libexecdi=* | --libexecd=* | --libexec=* \ | --libexe=* | --libex=* | --libe=*) libexecdir=$ac_optarg ;; -localedir | --localedir | --localedi | --localed | --locale) ac_prev=localedir ;; -localedir=* | --localedir=* | --localedi=* | --localed=* | --locale=*) localedir=$ac_optarg ;; -localstatedir | --localstatedir | --localstatedi | --localstated \ | --localstate | --localstat | --localsta | --localst | --locals) ac_prev=localstatedir ;; -localstatedir=* | --localstatedir=* | --localstatedi=* | --localstated=* \ | --localstate=* | --localstat=* | --localsta=* | --localst=* | --locals=*) localstatedir=$ac_optarg ;; -mandir | --mandir | --mandi | --mand | --man | --ma | --m) ac_prev=mandir ;; -mandir=* | --mandir=* | --mandi=* | --mand=* | --man=* | --ma=* | --m=*) mandir=$ac_optarg ;; -nfp | --nfp | --nf) # Obsolete; use --without-fp. with_fp=no ;; -no-create | --no-create | --no-creat | --no-crea | --no-cre \ | --no-cr | --no-c | -n) no_create=yes ;; -no-recursion | --no-recursion | --no-recursio | --no-recursi \ | --no-recurs | --no-recur | --no-recu | --no-rec | --no-re | --no-r) no_recursion=yes ;; -oldincludedir | --oldincludedir | --oldincludedi | --oldincluded \ | --oldinclude | --oldinclud | --oldinclu | --oldincl | --oldinc \ | --oldin | --oldi | --old | --ol | --o) ac_prev=oldincludedir ;; -oldincludedir=* | --oldincludedir=* | --oldincludedi=* | --oldincluded=* \ | --oldinclude=* | --oldinclud=* | --oldinclu=* | --oldincl=* | --oldinc=* \ | --oldin=* | --oldi=* | --old=* | --ol=* | --o=*) oldincludedir=$ac_optarg ;; -prefix | --prefix | --prefi | --pref | --pre | --pr | --p) ac_prev=prefix ;; -prefix=* | --prefix=* | --prefi=* | --pref=* | --pre=* | --pr=* | --p=*) prefix=$ac_optarg ;; -program-prefix | --program-prefix | --program-prefi | --program-pref \ | --program-pre | --program-pr | --program-p) ac_prev=program_prefix ;; -program-prefix=* | --program-prefix=* | --program-prefi=* \ | --program-pref=* | --program-pre=* | --program-pr=* | --program-p=*) program_prefix=$ac_optarg ;; -program-suffix | --program-suffix | --program-suffi | --program-suff \ | --program-suf | --program-su | --program-s) ac_prev=program_suffix ;; -program-suffix=* | --program-suffix=* | --program-suffi=* \ | --program-suff=* | --program-suf=* | --program-su=* | --program-s=*) program_suffix=$ac_optarg ;; -program-transform-name | --program-transform-name \ | --program-transform-nam | --program-transform-na \ | --program-transform-n | --program-transform- \ | --program-transform | --program-transfor \ | --program-transfo | --program-transf \ | --program-trans | --program-tran \ | --progr-tra | --program-tr | --program-t) ac_prev=program_transform_name ;; -program-transform-name=* | --program-transform-name=* \ | --program-transform-nam=* | --program-transform-na=* \ | --program-transform-n=* | --program-transform-=* \ | --program-transform=* | --program-transfor=* \ | --program-transfo=* | --program-transf=* \ | --program-trans=* | --program-tran=* \ | --progr-tra=* | --program-tr=* | --program-t=*) program_transform_name=$ac_optarg ;; -pdfdir | --pdfdir | --pdfdi | --pdfd | --pdf | --pd) ac_prev=pdfdir ;; -pdfdir=* | --pdfdir=* | --pdfdi=* | --pdfd=* | --pdf=* | --pd=*) pdfdir=$ac_optarg ;; -psdir | --psdir | --psdi | --psd | --ps) ac_prev=psdir ;; -psdir=* | --psdir=* | --psdi=* | --psd=* | --ps=*) psdir=$ac_optarg ;; -q | -quiet | --quiet | --quie | --qui | --qu | --q \ | -silent | --silent | --silen | --sile | --sil) silent=yes ;; -sbindir | --sbindir | --sbindi | --sbind | --sbin | --sbi | --sb) ac_prev=sbindir ;; -sbindir=* | --sbindir=* | --sbindi=* | --sbind=* | --sbin=* \ | --sbi=* | --sb=*) sbindir=$ac_optarg ;; -sharedstatedir | --sharedstatedir | --sharedstatedi \ | --sharedstated | --sharedstate | --sharedstat | --sharedsta \ | --sharedst | --shareds | --shared | --share | --shar \ | --sha | --sh) ac_prev=sharedstatedir ;; -sharedstatedir=* | --sharedstatedir=* | --sharedstatedi=* \ | --sharedstated=* | --sharedstate=* | --sharedstat=* | --sharedsta=* \ | --sharedst=* | --shareds=* | --shared=* | --share=* | --shar=* \ | --sha=* | --sh=*) sharedstatedir=$ac_optarg ;; -site | --site | --sit) ac_prev=site ;; -site=* | --site=* | --sit=*) site=$ac_optarg ;; -srcdir | --srcdir | --srcdi | --srcd | --src | --sr) ac_prev=srcdir ;; -srcdir=* | --srcdir=* | --srcdi=* | --srcd=* | --src=* | --sr=*) srcdir=$ac_optarg ;; -sysconfdir | --sysconfdir | --sysconfdi | --sysconfd | --sysconf \ | --syscon | --sysco | --sysc | --sys | --sy) ac_prev=sysconfdir ;; -sysconfdir=* | --sysconfdir=* | --sysconfdi=* | --sysconfd=* | --sysconf=* \ | --syscon=* | --sysco=* | --sysc=* | --sys=* | --sy=*) sysconfdir=$ac_optarg ;; -target | --target | --targe | --targ | --tar | --ta | --t) ac_prev=target_alias ;; -target=* | --target=* | --targe=* | --targ=* | --tar=* | --ta=* | --t=*) target_alias=$ac_optarg ;; -v | -verbose | --verbose | --verbos | --verbo | --verb) verbose=yes ;; -version | --version | --versio | --versi | --vers | -V) ac_init_version=: ;; -with-* | --with-*) ac_useropt=`expr "x$ac_option" : 'x-*with-\([^=]*\)'` # Reject names that are not valid shell variable names. expr "x$ac_useropt" : ".*[^-+._$as_cr_alnum]" >/dev/null && as_fn_error $? "invalid package name: $ac_useropt" ac_useropt_orig=$ac_useropt ac_useropt=`$as_echo "$ac_useropt" | sed 's/[-+.]/_/g'` case $ac_user_opts in *" "with_$ac_useropt" "*) ;; *) ac_unrecognized_opts="$ac_unrecognized_opts$ac_unrecognized_sep--with-$ac_useropt_orig" ac_unrecognized_sep=', ';; esac eval with_$ac_useropt=\$ac_optarg ;; -without-* | --without-*) ac_useropt=`expr "x$ac_option" : 'x-*without-\(.*\)'` # Reject names that are not valid shell variable names. expr "x$ac_useropt" : ".*[^-+._$as_cr_alnum]" >/dev/null && as_fn_error $? "invalid package name: $ac_useropt" ac_useropt_orig=$ac_useropt ac_useropt=`$as_echo "$ac_useropt" | sed 's/[-+.]/_/g'` case $ac_user_opts in *" "with_$ac_useropt" "*) ;; *) ac_unrecognized_opts="$ac_unrecognized_opts$ac_unrecognized_sep--without-$ac_useropt_orig" ac_unrecognized_sep=', ';; esac eval with_$ac_useropt=no ;; --x) # Obsolete; use --with-x. with_x=yes ;; -x-includes | --x-includes | --x-include | --x-includ | --x-inclu \ | --x-incl | --x-inc | --x-in | --x-i) ac_prev=x_includes ;; -x-includes=* | --x-includes=* | --x-include=* | --x-includ=* | --x-inclu=* \ | --x-incl=* | --x-inc=* | --x-in=* | --x-i=*) x_includes=$ac_optarg ;; -x-libraries | --x-libraries | --x-librarie | --x-librari \ | --x-librar | --x-libra | --x-libr | --x-lib | --x-li | --x-l) ac_prev=x_libraries ;; -x-libraries=* | --x-libraries=* | --x-librarie=* | --x-librari=* \ | --x-librar=* | --x-libra=* | --x-libr=* | --x-lib=* | --x-li=* | --x-l=*) x_libraries=$ac_optarg ;; -*) as_fn_error $? "unrecognized option: \`$ac_option' Try \`$0 --help' for more information" ;; *=*) ac_envvar=`expr "x$ac_option" : 'x\([^=]*\)='` # Reject names that are not valid shell variable names. case $ac_envvar in #( '' | [0-9]* | *[!_$as_cr_alnum]* ) as_fn_error $? "invalid variable name: \`$ac_envvar'" ;; esac eval $ac_envvar=\$ac_optarg export $ac_envvar ;; *) # FIXME: should be removed in autoconf 3.0. $as_echo "$as_me: WARNING: you should use --build, --host, --target" >&2 expr "x$ac_option" : ".*[^-._$as_cr_alnum]" >/dev/null && $as_echo "$as_me: WARNING: invalid host type: $ac_option" >&2 : ${build_alias=$ac_option} ${host_alias=$ac_option} ${target_alias=$ac_option} ;; esac done if test -n "$ac_prev"; then ac_option=--`echo $ac_prev | sed 's/_/-/g'` as_fn_error $? "missing argument to $ac_option" fi if test -n "$ac_unrecognized_opts"; then case $enable_option_checking in no) ;; fatal) as_fn_error $? "unrecognized options: $ac_unrecognized_opts" ;; *) $as_echo "$as_me: WARNING: unrecognized options: $ac_unrecognized_opts" >&2 ;; esac fi # Check all directory arguments for consistency. for ac_var in exec_prefix prefix bindir sbindir libexecdir datarootdir \ datadir sysconfdir sharedstatedir localstatedir includedir \ oldincludedir docdir infodir htmldir dvidir pdfdir psdir \ libdir localedir mandir do eval ac_val=\$$ac_var # Remove trailing slashes. case $ac_val in */ ) ac_val=`expr "X$ac_val" : 'X\(.*[^/]\)' \| "X$ac_val" : 'X\(.*\)'` eval $ac_var=\$ac_val;; esac # Be sure to have absolute directory names. case $ac_val in [\\/$]* | ?:[\\/]* ) continue;; NONE | '' ) case $ac_var in *prefix ) continue;; esac;; esac as_fn_error $? "expected an absolute directory name for --$ac_var: $ac_val" done # There might be people who depend on the old broken behavior: `$host' # used to hold the argument of --host etc. # FIXME: To remove some day. build=$build_alias host=$host_alias target=$target_alias # FIXME: To remove some day. if test "x$host_alias" != x; then if test "x$build_alias" = x; then cross_compiling=maybe $as_echo "$as_me: WARNING: if you wanted to set the --build type, don't use --host. If a cross compiler is detected then cross compile mode will be used" >&2 elif test "x$build_alias" != "x$host_alias"; then cross_compiling=yes fi fi ac_tool_prefix= test -n "$host_alias" && ac_tool_prefix=$host_alias- test "$silent" = yes && exec 6>/dev/null ac_pwd=`pwd` && test -n "$ac_pwd" && ac_ls_di=`ls -di .` && ac_pwd_ls_di=`cd "$ac_pwd" && ls -di .` || as_fn_error $? "working directory cannot be determined" test "X$ac_ls_di" = "X$ac_pwd_ls_di" || as_fn_error $? "pwd does not report name of working directory" # Find the source files, if location was not specified. if test -z "$srcdir"; then ac_srcdir_defaulted=yes # Try the directory containing this script, then the parent directory. ac_confdir=`$as_dirname -- "$as_myself" || $as_expr X"$as_myself" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ X"$as_myself" : 'X\(//\)[^/]' \| \ X"$as_myself" : 'X\(//\)$' \| \ X"$as_myself" : 'X\(/\)' \| . 2>/dev/null || $as_echo X"$as_myself" | sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ s//\1/ q } /^X\(\/\/\)[^/].*/{ s//\1/ q } /^X\(\/\/\)$/{ s//\1/ q } /^X\(\/\).*/{ s//\1/ q } s/.*/./; q'` srcdir=$ac_confdir if test ! -r "$srcdir/$ac_unique_file"; then srcdir=.. fi else ac_srcdir_defaulted=no fi if test ! -r "$srcdir/$ac_unique_file"; then test "$ac_srcdir_defaulted" = yes && srcdir="$ac_confdir or .." as_fn_error $? "cannot find sources ($ac_unique_file) in $srcdir" fi ac_msg="sources are in $srcdir, but \`cd $srcdir' does not work" ac_abs_confdir=`( cd "$srcdir" && test -r "./$ac_unique_file" || as_fn_error $? "$ac_msg" pwd)` # When building in place, set srcdir=. if test "$ac_abs_confdir" = "$ac_pwd"; then srcdir=. fi # Remove unnecessary trailing slashes from srcdir. # Double slashes in file names in object file debugging info # mess up M-x gdb in Emacs. case $srcdir in */) srcdir=`expr "X$srcdir" : 'X\(.*[^/]\)' \| "X$srcdir" : 'X\(.*\)'`;; esac for ac_var in $ac_precious_vars; do eval ac_env_${ac_var}_set=\${${ac_var}+set} eval ac_env_${ac_var}_value=\$${ac_var} eval ac_cv_env_${ac_var}_set=\${${ac_var}+set} eval ac_cv_env_${ac_var}_value=\$${ac_var} done # # Report the --help message. # if test "$ac_init_help" = "long"; then # Omit some internal or obsolete options to make the list less imposing. # This message is too long to be a string in the A/UX 3.1 sh. cat <<_ACEOF \`configure' configures cvc3 2.4.1 to adapt to many kinds of systems. Usage: $0 [OPTION]... [VAR=VALUE]... To assign environment variables (e.g., CC, CFLAGS...), specify them as VAR=VALUE. See below for descriptions of some of the useful variables. Defaults for the options are specified in brackets. Configuration: -h, --help display this help and exit --help=short display options specific to this package --help=recursive display the short help of all the included packages -V, --version display version information and exit -q, --quiet, --silent do not print \`checking ...' messages --cache-file=FILE cache test results in FILE [disabled] -C, --config-cache alias for \`--cache-file=config.cache' -n, --no-create do not create output files --srcdir=DIR find the sources in DIR [configure dir or \`..'] Installation directories: --prefix=PREFIX install architecture-independent files in PREFIX [$ac_default_prefix] --exec-prefix=EPREFIX install architecture-dependent files in EPREFIX [PREFIX] By default, \`make install' will install all the files in \`$ac_default_prefix/bin', \`$ac_default_prefix/lib' etc. You can specify an installation prefix other than \`$ac_default_prefix' using \`--prefix', for instance \`--prefix=\$HOME'. For better control, use the options below. Fine tuning of the installation directories: --bindir=DIR user executables [EPREFIX/bin] --sbindir=DIR system admin executables [EPREFIX/sbin] --libexecdir=DIR program executables [EPREFIX/libexec] --sysconfdir=DIR read-only single-machine data [PREFIX/etc] --sharedstatedir=DIR modifiable architecture-independent data [PREFIX/com] --localstatedir=DIR modifiable single-machine data [PREFIX/var] --libdir=DIR object code libraries [EPREFIX/lib] --includedir=DIR C header files [PREFIX/include] --oldincludedir=DIR C header files for non-gcc [/usr/include] --datarootdir=DIR read-only arch.-independent data root [PREFIX/share] --datadir=DIR read-only architecture-independent data [DATAROOTDIR] --infodir=DIR info documentation [DATAROOTDIR/info] --localedir=DIR locale-dependent data [DATAROOTDIR/locale] --mandir=DIR man documentation [DATAROOTDIR/man] --docdir=DIR documentation root [DATAROOTDIR/doc/cvc3] --htmldir=DIR html documentation [DOCDIR] --dvidir=DIR dvi documentation [DOCDIR] --pdfdir=DIR pdf documentation [DOCDIR] --psdir=DIR ps documentation [DOCDIR] _ACEOF cat <<\_ACEOF System types: --build=BUILD configure for building on BUILD [guessed] --host=HOST cross-compile to build programs to run on HOST [BUILD] _ACEOF fi if test -n "$ac_init_help"; then case $ac_init_help in short | recursive ) echo "Configuration of cvc3 2.4.1:";; esac cat <<\_ACEOF Optional Features: --disable-option-checking ignore unrecognized --enable/--with options --disable-FEATURE do not include FEATURE (same as --enable-FEATURE=no) --enable-FEATURE[=ARG] include FEATURE [ARG=yes] --enable-zchaff Include zchaff code (default = yes) --disable-zchaff Remove zchaff code (default = no) --enable-debug-yacc Enable debugging of yacc (default = no). --enable-broken-cxx=no Force configure to accept the compiler, even if it thinks that it is broken. --enable-static --disable-dynamic Enable static build of cvc3 (default=yes). Disable for faster link times. --enable-dynamic --disable-static Enable shared library build of cvc3 (default = no). --enable-sharedlibs --disable-sharedlibs Enable building of individual shared libraries (default = yes). --enable-java --disable-java Enable building of CVC3 Java interface (default = no). Optional Packages: --with-PACKAGE[=ARG] use PACKAGE [ARG=yes] --without-PACKAGE do not use PACKAGE (same as --with-PACKAGE=no) --with-build=optimized Specify the type of build (default = optimized). Possible values: debug, optimized, gprof, gcov --with-ld Use a specific program for linking. --with-extra-libs List of paths to additional static libraries separated with ":". --with-extra-includes List of paths to additional include files separated with ":". --with-version= The version string to report on cvc3 -version --with-arith=gmp Specify the arithmetic option to use: gmp: C-only GMP package (default) gmpxx: GMP package with C++ extensions (deprecated) native: native computer arithmetic (finite precision) --with-java-home=PATH Java installation path --with-java-includes=PATH Java includes path Some influential environment variables: CXX C++ compiler command CXXFLAGS C++ compiler flags LDFLAGS linker flags, e.g. -L if you have libraries in a nonstandard directory LIBS libraries to pass to the linker, e.g. -l CPPFLAGS (Objective) C/C++ preprocessor flags, e.g. -I if you have headers in a nonstandard directory CXXCPP C++ preprocessor AR C/C++ linker/archiver YACC The `Yet Another C Compiler' implementation to use. Defaults to the first program found out of: `bison -y', `byacc', `yacc'. YFLAGS The list of arguments that will be passed by default to $YACC. This script will default YFLAGS to the empty string to avoid a default value of `-d' given by some make applications. javadir installation directory for Java libraries JAR JAR archive utility command JAVA Java runtime command JAVAC Java compiler command JAVAH JNI utility command JFLAGS Java compiler flags JREFLAGS Java runtime flags PYTHON Python runtime Use these variables to override the choices made by `configure' or to help it to find libraries and programs with nonstandard names/locations. Report bugs to the package provider. _ACEOF ac_status=$? fi if test "$ac_init_help" = "recursive"; then # If there are subdirs, report their specific --help. for ac_dir in : $ac_subdirs_all; do test "x$ac_dir" = x: && continue test -d "$ac_dir" || { cd "$srcdir" && ac_pwd=`pwd` && srcdir=. && test -d "$ac_dir"; } || continue ac_builddir=. case "$ac_dir" in .) ac_dir_suffix= ac_top_builddir_sub=. ac_top_build_prefix= ;; *) ac_dir_suffix=/`$as_echo "$ac_dir" | sed 's|^\.[\\/]||'` # A ".." for each directory in $ac_dir_suffix. ac_top_builddir_sub=`$as_echo "$ac_dir_suffix" | sed 's|/[^\\/]*|/..|g;s|/||'` case $ac_top_builddir_sub in "") ac_top_builddir_sub=. ac_top_build_prefix= ;; *) ac_top_build_prefix=$ac_top_builddir_sub/ ;; esac ;; esac ac_abs_top_builddir=$ac_pwd ac_abs_builddir=$ac_pwd$ac_dir_suffix # for backward compatibility: ac_top_builddir=$ac_top_build_prefix case $srcdir in .) # We are building in place. ac_srcdir=. ac_top_srcdir=$ac_top_builddir_sub ac_abs_top_srcdir=$ac_pwd ;; [\\/]* | ?:[\\/]* ) # Absolute name. ac_srcdir=$srcdir$ac_dir_suffix; ac_top_srcdir=$srcdir ac_abs_top_srcdir=$srcdir ;; *) # Relative name. ac_srcdir=$ac_top_build_prefix$srcdir$ac_dir_suffix ac_top_srcdir=$ac_top_build_prefix$srcdir ac_abs_top_srcdir=$ac_pwd/$srcdir ;; esac ac_abs_srcdir=$ac_abs_top_srcdir$ac_dir_suffix cd "$ac_dir" || { ac_status=$?; continue; } # Check for guested configure. if test -f "$ac_srcdir/configure.gnu"; then echo && $SHELL "$ac_srcdir/configure.gnu" --help=recursive elif test -f "$ac_srcdir/configure"; then echo && $SHELL "$ac_srcdir/configure" --help=recursive else $as_echo "$as_me: WARNING: no configuration information is in $ac_dir" >&2 fi || ac_status=$? cd "$ac_pwd" || { ac_status=$?; break; } done fi test -n "$ac_init_help" && exit $ac_status if $ac_init_version; then cat <<\_ACEOF cvc3 configure 2.4.1 generated by GNU Autoconf 2.67 Copyright (C) 2010 Free Software Foundation, Inc. This configure script is free software; the Free Software Foundation gives unlimited permission to copy, distribute and modify it. _ACEOF exit fi ## ------------------------ ## ## Autoconf initialization. ## ## ------------------------ ## # ac_fn_cxx_try_compile LINENO # ---------------------------- # Try to compile conftest.$ac_ext, and return whether this succeeded. ac_fn_cxx_try_compile () { as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack rm -f conftest.$ac_objext if { { ac_try="$ac_compile" case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" $as_echo "$ac_try_echo"; } >&5 (eval "$ac_compile") 2>conftest.err ac_status=$? if test -s conftest.err; then grep -v '^ *+' conftest.err >conftest.er1 cat conftest.er1 >&5 mv -f conftest.er1 conftest.err fi $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; } && { test -z "$ac_cxx_werror_flag" || test ! -s conftest.err } && test -s conftest.$ac_objext; then : ac_retval=0 else $as_echo "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 ac_retval=1 fi eval $as_lineno_stack; test "x$as_lineno_stack" = x && { as_lineno=; unset as_lineno;} as_fn_set_status $ac_retval } # ac_fn_cxx_try_compile # ac_fn_cxx_try_cpp LINENO # ------------------------ # Try to preprocess conftest.$ac_ext, and return whether this succeeded. ac_fn_cxx_try_cpp () { as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack if { { ac_try="$ac_cpp conftest.$ac_ext" case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" $as_echo "$ac_try_echo"; } >&5 (eval "$ac_cpp conftest.$ac_ext") 2>conftest.err ac_status=$? if test -s conftest.err; then grep -v '^ *+' conftest.err >conftest.er1 cat conftest.er1 >&5 mv -f conftest.er1 conftest.err fi $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; } > conftest.i && { test -z "$ac_cxx_preproc_warn_flag$ac_cxx_werror_flag" || test ! -s conftest.err }; then : ac_retval=0 else $as_echo "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 ac_retval=1 fi eval $as_lineno_stack; test "x$as_lineno_stack" = x && { as_lineno=; unset as_lineno;} as_fn_set_status $ac_retval } # ac_fn_cxx_try_cpp # ac_fn_cxx_try_link LINENO # ------------------------- # Try to link conftest.$ac_ext, and return whether this succeeded. ac_fn_cxx_try_link () { as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack rm -f conftest.$ac_objext conftest$ac_exeext if { { ac_try="$ac_link" case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" $as_echo "$ac_try_echo"; } >&5 (eval "$ac_link") 2>conftest.err ac_status=$? if test -s conftest.err; then grep -v '^ *+' conftest.err >conftest.er1 cat conftest.er1 >&5 mv -f conftest.er1 conftest.err fi $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; } && { test -z "$ac_cxx_werror_flag" || test ! -s conftest.err } && test -s conftest$ac_exeext && { test "$cross_compiling" = yes || $as_test_x conftest$ac_exeext }; then : ac_retval=0 else $as_echo "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 ac_retval=1 fi # Delete the IPA/IPO (Inter Procedural Analysis/Optimization) information # created by the PGI compiler (conftest_ipa8_conftest.oo), as it would # interfere with the next link command; also delete a directory that is # left behind by Apple's compiler. We do this before executing the actions. rm -rf conftest.dSYM conftest_ipa8_conftest.oo eval $as_lineno_stack; test "x$as_lineno_stack" = x && { as_lineno=; unset as_lineno;} as_fn_set_status $ac_retval } # ac_fn_cxx_try_link # ac_fn_cxx_check_header_mongrel LINENO HEADER VAR INCLUDES # --------------------------------------------------------- # Tests whether HEADER exists, giving a warning if it cannot be compiled using # the include files in INCLUDES and setting the cache variable VAR # accordingly. ac_fn_cxx_check_header_mongrel () { as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack if eval "test \"\${$3+set}\"" = set; then : { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $2" >&5 $as_echo_n "checking for $2... " >&6; } if eval "test \"\${$3+set}\"" = set; then : $as_echo_n "(cached) " >&6 fi eval ac_res=\$$3 { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5 $as_echo "$ac_res" >&6; } else # Is the header compilable? { $as_echo "$as_me:${as_lineno-$LINENO}: checking $2 usability" >&5 $as_echo_n "checking $2 usability... " >&6; } cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ $4 #include <$2> _ACEOF if ac_fn_cxx_try_compile "$LINENO"; then : ac_header_compiler=yes else ac_header_compiler=no fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_header_compiler" >&5 $as_echo "$ac_header_compiler" >&6; } # Is the header present? { $as_echo "$as_me:${as_lineno-$LINENO}: checking $2 presence" >&5 $as_echo_n "checking $2 presence... " >&6; } cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include <$2> _ACEOF if ac_fn_cxx_try_cpp "$LINENO"; then : ac_header_preproc=yes else ac_header_preproc=no fi rm -f conftest.err conftest.i conftest.$ac_ext { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_header_preproc" >&5 $as_echo "$ac_header_preproc" >&6; } # So? What about this header? case $ac_header_compiler:$ac_header_preproc:$ac_cxx_preproc_warn_flag in #(( yes:no: ) { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $2: accepted by the compiler, rejected by the preprocessor!" >&5 $as_echo "$as_me: WARNING: $2: accepted by the compiler, rejected by the preprocessor!" >&2;} { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $2: proceeding with the compiler's result" >&5 $as_echo "$as_me: WARNING: $2: proceeding with the compiler's result" >&2;} ;; no:yes:* ) { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $2: present but cannot be compiled" >&5 $as_echo "$as_me: WARNING: $2: present but cannot be compiled" >&2;} { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $2: check for missing prerequisite headers?" >&5 $as_echo "$as_me: WARNING: $2: check for missing prerequisite headers?" >&2;} { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $2: see the Autoconf documentation" >&5 $as_echo "$as_me: WARNING: $2: see the Autoconf documentation" >&2;} { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $2: section \"Present But Cannot Be Compiled\"" >&5 $as_echo "$as_me: WARNING: $2: section \"Present But Cannot Be Compiled\"" >&2;} { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $2: proceeding with the compiler's result" >&5 $as_echo "$as_me: WARNING: $2: proceeding with the compiler's result" >&2;} ;; esac { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $2" >&5 $as_echo_n "checking for $2... " >&6; } if eval "test \"\${$3+set}\"" = set; then : $as_echo_n "(cached) " >&6 else eval "$3=\$ac_header_compiler" fi eval ac_res=\$$3 { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5 $as_echo "$ac_res" >&6; } fi eval $as_lineno_stack; test "x$as_lineno_stack" = x && { as_lineno=; unset as_lineno;} } # ac_fn_cxx_check_header_mongrel # ac_fn_cxx_try_run LINENO # ------------------------ # Try to link conftest.$ac_ext, and return whether this succeeded. Assumes # that executables *can* be run. ac_fn_cxx_try_run () { as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack if { { ac_try="$ac_link" case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" $as_echo "$ac_try_echo"; } >&5 (eval "$ac_link") 2>&5 ac_status=$? $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; } && { ac_try='./conftest$ac_exeext' { { case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" $as_echo "$ac_try_echo"; } >&5 (eval "$ac_try") 2>&5 ac_status=$? $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; }; }; then : ac_retval=0 else $as_echo "$as_me: program exited with status $ac_status" >&5 $as_echo "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 ac_retval=$ac_status fi rm -rf conftest.dSYM conftest_ipa8_conftest.oo eval $as_lineno_stack; test "x$as_lineno_stack" = x && { as_lineno=; unset as_lineno;} as_fn_set_status $ac_retval } # ac_fn_cxx_try_run # ac_fn_cxx_check_header_compile LINENO HEADER VAR INCLUDES # --------------------------------------------------------- # Tests whether HEADER exists and can be compiled using the include files in # INCLUDES, setting the cache variable VAR accordingly. ac_fn_cxx_check_header_compile () { as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $2" >&5 $as_echo_n "checking for $2... " >&6; } if eval "test \"\${$3+set}\"" = set; then : $as_echo_n "(cached) " >&6 else cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ $4 #include <$2> _ACEOF if ac_fn_cxx_try_compile "$LINENO"; then : eval "$3=yes" else eval "$3=no" fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext fi eval ac_res=\$$3 { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5 $as_echo "$ac_res" >&6; } eval $as_lineno_stack; test "x$as_lineno_stack" = x && { as_lineno=; unset as_lineno;} } # ac_fn_cxx_check_header_compile cat >config.log <<_ACEOF This file contains any messages produced by compilers while running configure, to aid debugging if configure makes a mistake. It was created by cvc3 $as_me 2.4.1, which was generated by GNU Autoconf 2.67. Invocation command line was $ $0 $@ _ACEOF exec 5>>config.log { cat <<_ASUNAME ## --------- ## ## Platform. ## ## --------- ## hostname = `(hostname || uname -n) 2>/dev/null | sed 1q` uname -m = `(uname -m) 2>/dev/null || echo unknown` uname -r = `(uname -r) 2>/dev/null || echo unknown` uname -s = `(uname -s) 2>/dev/null || echo unknown` uname -v = `(uname -v) 2>/dev/null || echo unknown` /usr/bin/uname -p = `(/usr/bin/uname -p) 2>/dev/null || echo unknown` /bin/uname -X = `(/bin/uname -X) 2>/dev/null || echo unknown` /bin/arch = `(/bin/arch) 2>/dev/null || echo unknown` /usr/bin/arch -k = `(/usr/bin/arch -k) 2>/dev/null || echo unknown` /usr/convex/getsysinfo = `(/usr/convex/getsysinfo) 2>/dev/null || echo unknown` /usr/bin/hostinfo = `(/usr/bin/hostinfo) 2>/dev/null || echo unknown` /bin/machine = `(/bin/machine) 2>/dev/null || echo unknown` /usr/bin/oslevel = `(/usr/bin/oslevel) 2>/dev/null || echo unknown` /bin/universe = `(/bin/universe) 2>/dev/null || echo unknown` _ASUNAME as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. $as_echo "PATH: $as_dir" done IFS=$as_save_IFS } >&5 cat >&5 <<_ACEOF ## ----------- ## ## Core tests. ## ## ----------- ## _ACEOF # Keep a trace of the command line. # Strip out --no-create and --no-recursion so they do not pile up. # Strip out --silent because we don't want to record it for future runs. # Also quote any args containing shell meta-characters. # Make two passes to allow for proper duplicate-argument suppression. ac_configure_args= ac_configure_args0= ac_configure_args1= ac_must_keep_next=false for ac_pass in 1 2 do for ac_arg do case $ac_arg in -no-create | --no-c* | -n | -no-recursion | --no-r*) continue ;; -q | -quiet | --quiet | --quie | --qui | --qu | --q \ | -silent | --silent | --silen | --sile | --sil) continue ;; *\'*) ac_arg=`$as_echo "$ac_arg" | sed "s/'/'\\\\\\\\''/g"` ;; esac case $ac_pass in 1) as_fn_append ac_configure_args0 " '$ac_arg'" ;; 2) as_fn_append ac_configure_args1 " '$ac_arg'" if test $ac_must_keep_next = true; then ac_must_keep_next=false # Got value, back to normal. else case $ac_arg in *=* | --config-cache | -C | -disable-* | --disable-* \ | -enable-* | --enable-* | -gas | --g* | -nfp | --nf* \ | -q | -quiet | --q* | -silent | --sil* | -v | -verb* \ | -with-* | --with-* | -without-* | --without-* | --x) case "$ac_configure_args0 " in "$ac_configure_args1"*" '$ac_arg' "* ) continue ;; esac ;; -* ) ac_must_keep_next=true ;; esac fi as_fn_append ac_configure_args " '$ac_arg'" ;; esac done done { ac_configure_args0=; unset ac_configure_args0;} { ac_configure_args1=; unset ac_configure_args1;} # When interrupted or exit'd, cleanup temporary files, and complete # config.log. We remove comments because anyway the quotes in there # would cause problems or look ugly. # WARNING: Use '\'' to represent an apostrophe within the trap. # WARNING: Do not start the trap code with a newline, due to a FreeBSD 4.0 bug. trap 'exit_status=$? # Save into config.log some information that might help in debugging. { echo $as_echo "## ---------------- ## ## Cache variables. ## ## ---------------- ##" echo # The following way of writing the cache mishandles newlines in values, ( for ac_var in `(set) 2>&1 | sed -n '\''s/^\([a-zA-Z_][a-zA-Z0-9_]*\)=.*/\1/p'\''`; do eval ac_val=\$$ac_var case $ac_val in #( *${as_nl}*) case $ac_var in #( *_cv_*) { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: cache variable $ac_var contains a newline" >&5 $as_echo "$as_me: WARNING: cache variable $ac_var contains a newline" >&2;} ;; esac case $ac_var in #( _ | IFS | as_nl) ;; #( BASH_ARGV | BASH_SOURCE) eval $ac_var= ;; #( *) { eval $ac_var=; unset $ac_var;} ;; esac ;; esac done (set) 2>&1 | case $as_nl`(ac_space='\'' '\''; set) 2>&1` in #( *${as_nl}ac_space=\ *) sed -n \ "s/'\''/'\''\\\\'\'''\''/g; s/^\\([_$as_cr_alnum]*_cv_[_$as_cr_alnum]*\\)=\\(.*\\)/\\1='\''\\2'\''/p" ;; #( *) sed -n "/^[_$as_cr_alnum]*_cv_[_$as_cr_alnum]*=/p" ;; esac | sort ) echo $as_echo "## ----------------- ## ## Output variables. ## ## ----------------- ##" echo for ac_var in $ac_subst_vars do eval ac_val=\$$ac_var case $ac_val in *\'\''*) ac_val=`$as_echo "$ac_val" | sed "s/'\''/'\''\\\\\\\\'\'''\''/g"`;; esac $as_echo "$ac_var='\''$ac_val'\''" done | sort echo if test -n "$ac_subst_files"; then $as_echo "## ------------------- ## ## File substitutions. ## ## ------------------- ##" echo for ac_var in $ac_subst_files do eval ac_val=\$$ac_var case $ac_val in *\'\''*) ac_val=`$as_echo "$ac_val" | sed "s/'\''/'\''\\\\\\\\'\'''\''/g"`;; esac $as_echo "$ac_var='\''$ac_val'\''" done | sort echo fi if test -s confdefs.h; then $as_echo "## ----------- ## ## confdefs.h. ## ## ----------- ##" echo cat confdefs.h echo fi test "$ac_signal" != 0 && $as_echo "$as_me: caught signal $ac_signal" $as_echo "$as_me: exit $exit_status" } >&5 rm -f core *.core core.conftest.* && rm -f -r conftest* confdefs* conf$$* $ac_clean_files && exit $exit_status ' 0 for ac_signal in 1 2 13 15; do trap 'ac_signal='$ac_signal'; as_fn_exit 1' $ac_signal done ac_signal=0 # confdefs.h avoids OS command line length limits that DEFS can exceed. rm -f -r conftest* confdefs.h $as_echo "/* confdefs.h */" > confdefs.h # Predefined preprocessor variables. cat >>confdefs.h <<_ACEOF #define PACKAGE_NAME "$PACKAGE_NAME" _ACEOF cat >>confdefs.h <<_ACEOF #define PACKAGE_TARNAME "$PACKAGE_TARNAME" _ACEOF cat >>confdefs.h <<_ACEOF #define PACKAGE_VERSION "$PACKAGE_VERSION" _ACEOF cat >>confdefs.h <<_ACEOF #define PACKAGE_STRING "$PACKAGE_STRING" _ACEOF cat >>confdefs.h <<_ACEOF #define PACKAGE_BUGREPORT "$PACKAGE_BUGREPORT" _ACEOF cat >>confdefs.h <<_ACEOF #define PACKAGE_URL "$PACKAGE_URL" _ACEOF # Let the site file select an alternate cache file if it wants to. # Prefer an explicitly selected file to automatically selected ones. ac_site_file1=NONE ac_site_file2=NONE if test -n "$CONFIG_SITE"; then # We do not want a PATH search for config.site. case $CONFIG_SITE in #(( -*) ac_site_file1=./$CONFIG_SITE;; */*) ac_site_file1=$CONFIG_SITE;; *) ac_site_file1=./$CONFIG_SITE;; esac elif test "x$prefix" != xNONE; then ac_site_file1=$prefix/share/config.site ac_site_file2=$prefix/etc/config.site else ac_site_file1=$ac_default_prefix/share/config.site ac_site_file2=$ac_default_prefix/etc/config.site fi for ac_site_file in "$ac_site_file1" "$ac_site_file2" do test "x$ac_site_file" = xNONE && continue if test /dev/null != "$ac_site_file" && test -r "$ac_site_file"; then { $as_echo "$as_me:${as_lineno-$LINENO}: loading site script $ac_site_file" >&5 $as_echo "$as_me: loading site script $ac_site_file" >&6;} sed 's/^/| /' "$ac_site_file" >&5 . "$ac_site_file" \ || { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 $as_echo "$as_me: error: in \`$ac_pwd':" >&2;} as_fn_error $? "failed to load site script $ac_site_file See \`config.log' for more details" "$LINENO" 5 ; } fi done if test -r "$cache_file"; then # Some versions of bash will fail to source /dev/null (special files # actually), so we avoid doing that. DJGPP emulates it as a regular file. if test /dev/null != "$cache_file" && test -f "$cache_file"; then { $as_echo "$as_me:${as_lineno-$LINENO}: loading cache $cache_file" >&5 $as_echo "$as_me: loading cache $cache_file" >&6;} case $cache_file in [\\/]* | ?:[\\/]* ) . "$cache_file";; *) . "./$cache_file";; esac fi else { $as_echo "$as_me:${as_lineno-$LINENO}: creating cache $cache_file" >&5 $as_echo "$as_me: creating cache $cache_file" >&6;} >$cache_file fi # Check that the precious variables saved in the cache have kept the same # value. ac_cache_corrupted=false for ac_var in $ac_precious_vars; do eval ac_old_set=\$ac_cv_env_${ac_var}_set eval ac_new_set=\$ac_env_${ac_var}_set eval ac_old_val=\$ac_cv_env_${ac_var}_value eval ac_new_val=\$ac_env_${ac_var}_value case $ac_old_set,$ac_new_set in set,) { $as_echo "$as_me:${as_lineno-$LINENO}: error: \`$ac_var' was set to \`$ac_old_val' in the previous run" >&5 $as_echo "$as_me: error: \`$ac_var' was set to \`$ac_old_val' in the previous run" >&2;} ac_cache_corrupted=: ;; ,set) { $as_echo "$as_me:${as_lineno-$LINENO}: error: \`$ac_var' was not set in the previous run" >&5 $as_echo "$as_me: error: \`$ac_var' was not set in the previous run" >&2;} ac_cache_corrupted=: ;; ,);; *) if test "x$ac_old_val" != "x$ac_new_val"; then # differences in whitespace do not lead to failure. ac_old_val_w=`echo x $ac_old_val` ac_new_val_w=`echo x $ac_new_val` if test "$ac_old_val_w" != "$ac_new_val_w"; then { $as_echo "$as_me:${as_lineno-$LINENO}: error: \`$ac_var' has changed since the previous run:" >&5 $as_echo "$as_me: error: \`$ac_var' has changed since the previous run:" >&2;} ac_cache_corrupted=: else { $as_echo "$as_me:${as_lineno-$LINENO}: warning: ignoring whitespace changes in \`$ac_var' since the previous run:" >&5 $as_echo "$as_me: warning: ignoring whitespace changes in \`$ac_var' since the previous run:" >&2;} eval $ac_var=\$ac_old_val fi { $as_echo "$as_me:${as_lineno-$LINENO}: former value: \`$ac_old_val'" >&5 $as_echo "$as_me: former value: \`$ac_old_val'" >&2;} { $as_echo "$as_me:${as_lineno-$LINENO}: current value: \`$ac_new_val'" >&5 $as_echo "$as_me: current value: \`$ac_new_val'" >&2;} fi;; esac # Pass precious variables to config.status. if test "$ac_new_set" = set; then case $ac_new_val in *\'*) ac_arg=$ac_var=`$as_echo "$ac_new_val" | sed "s/'/'\\\\\\\\''/g"` ;; *) ac_arg=$ac_var=$ac_new_val ;; esac case " $ac_configure_args " in *" '$ac_arg' "*) ;; # Avoid dups. Use of quotes ensures accuracy. *) as_fn_append ac_configure_args " '$ac_arg'" ;; esac fi done if $ac_cache_corrupted; then { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 $as_echo "$as_me: error: in \`$ac_pwd':" >&2;} { $as_echo "$as_me:${as_lineno-$LINENO}: error: changes in the environment can compromise the build" >&5 $as_echo "$as_me: error: changes in the environment can compromise the build" >&2;} as_fn_error $? "run \`make distclean' and/or \`rm $cache_file' and start over" "$LINENO" 5 fi ## -------------------- ## ## Main body of script. ## ## -------------------- ## ac_ext=c ac_cpp='$CPP $CPPFLAGS' ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' ac_compiler_gnu=$ac_cv_c_compiler_gnu ###################################################################### # Library version information # # IMPORTANT: This version number needs to be bumped if binary # incompatibilities are introduced in the shared library. # # NOTE: This is the *library* version, not the version of the CVC3 # release (which is set by the VERSION variable below). In general, # LIB_MAJOR_VERSION will be greater than VERSION, because we break # compatibility fairly often in point releases. ###################################################################### # Major version: increases for non-backwards-compatible API changes # Minor version: increases for backwards-compatible API changes # Teeny version: increases for library bug fixes (API hasn't changed) LIB_MAJOR_VERSION=5 LIB_MINOR_VERSION=0 LIB_TEENY_VERSION=0 if test "${CXXFLAGS+set}" != set; then CXXFLAGS="" fi ac_ext=cpp ac_cpp='$CXXCPP $CPPFLAGS' ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5' ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' ac_compiler_gnu=$ac_cv_cxx_compiler_gnu ac_ext=cpp ac_cpp='$CXXCPP $CPPFLAGS' ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5' ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' ac_compiler_gnu=$ac_cv_cxx_compiler_gnu if test -z "$CXX"; then if test -n "$CCC"; then CXX=$CCC else if test -n "$ac_tool_prefix"; then for ac_prog in g++ c++ gpp aCC CC cxx cc++ cl.exe FCC KCC RCC xlC_r xlC do # Extract the first word of "$ac_tool_prefix$ac_prog", so it can be a program name with args. set dummy $ac_tool_prefix$ac_prog; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if test "${ac_cv_prog_CXX+set}" = set; then : $as_echo_n "(cached) " >&6 else if test -n "$CXX"; then ac_cv_prog_CXX="$CXX" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then ac_cv_prog_CXX="$ac_tool_prefix$ac_prog" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi CXX=$ac_cv_prog_CXX if test -n "$CXX"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $CXX" >&5 $as_echo "$CXX" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi test -n "$CXX" && break done fi if test -z "$CXX"; then ac_ct_CXX=$CXX for ac_prog in g++ c++ gpp aCC CC cxx cc++ cl.exe FCC KCC RCC xlC_r xlC do # Extract the first word of "$ac_prog", so it can be a program name with args. set dummy $ac_prog; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if test "${ac_cv_prog_ac_ct_CXX+set}" = set; then : $as_echo_n "(cached) " >&6 else if test -n "$ac_ct_CXX"; then ac_cv_prog_ac_ct_CXX="$ac_ct_CXX" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then ac_cv_prog_ac_ct_CXX="$ac_prog" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi ac_ct_CXX=$ac_cv_prog_ac_ct_CXX if test -n "$ac_ct_CXX"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_CXX" >&5 $as_echo "$ac_ct_CXX" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi test -n "$ac_ct_CXX" && break done if test "x$ac_ct_CXX" = x; then CXX="g++" else case $cross_compiling:$ac_tool_warned in yes:) { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 $as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} ac_tool_warned=yes ;; esac CXX=$ac_ct_CXX fi fi fi fi # Provide some information about the compiler. $as_echo "$as_me:${as_lineno-$LINENO}: checking for C++ compiler version" >&5 set X $ac_compile ac_compiler=$2 for ac_option in --version -v -V -qversion; do { { ac_try="$ac_compiler $ac_option >&5" case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" $as_echo "$ac_try_echo"; } >&5 (eval "$ac_compiler $ac_option >&5") 2>conftest.err ac_status=$? if test -s conftest.err; then sed '10a\ ... rest of stderr output deleted ... 10q' conftest.err >conftest.er1 cat conftest.er1 >&5 fi rm -f conftest.er1 conftest.err $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; } done cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int main () { ; return 0; } _ACEOF ac_clean_files_save=$ac_clean_files ac_clean_files="$ac_clean_files a.out a.out.dSYM a.exe b.out" # Try to create an executable without -o first, disregard a.out. # It will help us diagnose broken compilers, and finding out an intuition # of exeext. { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether the C++ compiler works" >&5 $as_echo_n "checking whether the C++ compiler works... " >&6; } ac_link_default=`$as_echo "$ac_link" | sed 's/ -o *conftest[^ ]*//'` # The possible output files: ac_files="a.out conftest.exe conftest a.exe a_out.exe b.out conftest.*" ac_rmfiles= for ac_file in $ac_files do case $ac_file in *.$ac_ext | *.xcoff | *.tds | *.d | *.pdb | *.xSYM | *.bb | *.bbg | *.map | *.inf | *.dSYM | *.o | *.obj ) ;; * ) ac_rmfiles="$ac_rmfiles $ac_file";; esac done rm -f $ac_rmfiles if { { ac_try="$ac_link_default" case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" $as_echo "$ac_try_echo"; } >&5 (eval "$ac_link_default") 2>&5 ac_status=$? $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; }; then : # Autoconf-2.13 could set the ac_cv_exeext variable to `no'. # So ignore a value of `no', otherwise this would lead to `EXEEXT = no' # in a Makefile. We should not override ac_cv_exeext if it was cached, # so that the user can short-circuit this test for compilers unknown to # Autoconf. for ac_file in $ac_files '' do test -f "$ac_file" || continue case $ac_file in *.$ac_ext | *.xcoff | *.tds | *.d | *.pdb | *.xSYM | *.bb | *.bbg | *.map | *.inf | *.dSYM | *.o | *.obj ) ;; [ab].out ) # We found the default executable, but exeext='' is most # certainly right. break;; *.* ) if test "${ac_cv_exeext+set}" = set && test "$ac_cv_exeext" != no; then :; else ac_cv_exeext=`expr "$ac_file" : '[^.]*\(\..*\)'` fi # We set ac_cv_exeext here because the later test for it is not # safe: cross compilers may not add the suffix if given an `-o' # argument, so we may need to know it at that point already. # Even if this section looks crufty: it has the advantage of # actually working. break;; * ) break;; esac done test "$ac_cv_exeext" = no && ac_cv_exeext= else ac_file='' fi if test -z "$ac_file"; then : { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } $as_echo "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 $as_echo "$as_me: error: in \`$ac_pwd':" >&2;} as_fn_error 77 "C++ compiler cannot create executables See \`config.log' for more details" "$LINENO" 5 ; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 $as_echo "yes" >&6; } fi { $as_echo "$as_me:${as_lineno-$LINENO}: checking for C++ compiler default output file name" >&5 $as_echo_n "checking for C++ compiler default output file name... " >&6; } { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_file" >&5 $as_echo "$ac_file" >&6; } ac_exeext=$ac_cv_exeext rm -f -r a.out a.out.dSYM a.exe conftest$ac_cv_exeext b.out ac_clean_files=$ac_clean_files_save { $as_echo "$as_me:${as_lineno-$LINENO}: checking for suffix of executables" >&5 $as_echo_n "checking for suffix of executables... " >&6; } if { { ac_try="$ac_link" case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" $as_echo "$ac_try_echo"; } >&5 (eval "$ac_link") 2>&5 ac_status=$? $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; }; then : # If both `conftest.exe' and `conftest' are `present' (well, observable) # catch `conftest.exe'. For instance with Cygwin, `ls conftest' will # work properly (i.e., refer to `conftest.exe'), while it won't with # `rm'. for ac_file in conftest.exe conftest conftest.*; do test -f "$ac_file" || continue case $ac_file in *.$ac_ext | *.xcoff | *.tds | *.d | *.pdb | *.xSYM | *.bb | *.bbg | *.map | *.inf | *.dSYM | *.o | *.obj ) ;; *.* ) ac_cv_exeext=`expr "$ac_file" : '[^.]*\(\..*\)'` break;; * ) break;; esac done else { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 $as_echo "$as_me: error: in \`$ac_pwd':" >&2;} as_fn_error $? "cannot compute suffix of executables: cannot compile and link See \`config.log' for more details" "$LINENO" 5 ; } fi rm -f conftest conftest$ac_cv_exeext { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_exeext" >&5 $as_echo "$ac_cv_exeext" >&6; } rm -f conftest.$ac_ext EXEEXT=$ac_cv_exeext ac_exeext=$EXEEXT cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include int main () { FILE *f = fopen ("conftest.out", "w"); return ferror (f) || fclose (f) != 0; ; return 0; } _ACEOF ac_clean_files="$ac_clean_files conftest.out" # Check that the compiler produces executables we can run. If not, either # the compiler is broken, or we cross compile. { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether we are cross compiling" >&5 $as_echo_n "checking whether we are cross compiling... " >&6; } if test "$cross_compiling" != yes; then { { ac_try="$ac_link" case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" $as_echo "$ac_try_echo"; } >&5 (eval "$ac_link") 2>&5 ac_status=$? $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; } if { ac_try='./conftest$ac_cv_exeext' { { case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" $as_echo "$ac_try_echo"; } >&5 (eval "$ac_try") 2>&5 ac_status=$? $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; }; }; then cross_compiling=no else if test "$cross_compiling" = maybe; then cross_compiling=yes else { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 $as_echo "$as_me: error: in \`$ac_pwd':" >&2;} as_fn_error $? "cannot run C++ compiled programs. If you meant to cross compile, use \`--host'. See \`config.log' for more details" "$LINENO" 5 ; } fi fi fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $cross_compiling" >&5 $as_echo "$cross_compiling" >&6; } rm -f conftest.$ac_ext conftest$ac_cv_exeext conftest.out ac_clean_files=$ac_clean_files_save { $as_echo "$as_me:${as_lineno-$LINENO}: checking for suffix of object files" >&5 $as_echo_n "checking for suffix of object files... " >&6; } if test "${ac_cv_objext+set}" = set; then : $as_echo_n "(cached) " >&6 else cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int main () { ; return 0; } _ACEOF rm -f conftest.o conftest.obj if { { ac_try="$ac_compile" case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" $as_echo "$ac_try_echo"; } >&5 (eval "$ac_compile") 2>&5 ac_status=$? $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; }; then : for ac_file in conftest.o conftest.obj conftest.*; do test -f "$ac_file" || continue; case $ac_file in *.$ac_ext | *.xcoff | *.tds | *.d | *.pdb | *.xSYM | *.bb | *.bbg | *.map | *.inf | *.dSYM ) ;; *) ac_cv_objext=`expr "$ac_file" : '.*\.\(.*\)'` break;; esac done else $as_echo "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 $as_echo "$as_me: error: in \`$ac_pwd':" >&2;} as_fn_error $? "cannot compute suffix of object files: cannot compile See \`config.log' for more details" "$LINENO" 5 ; } fi rm -f conftest.$ac_cv_objext conftest.$ac_ext fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_objext" >&5 $as_echo "$ac_cv_objext" >&6; } OBJEXT=$ac_cv_objext ac_objext=$OBJEXT { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether we are using the GNU C++ compiler" >&5 $as_echo_n "checking whether we are using the GNU C++ compiler... " >&6; } if test "${ac_cv_cxx_compiler_gnu+set}" = set; then : $as_echo_n "(cached) " >&6 else cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int main () { #ifndef __GNUC__ choke me #endif ; return 0; } _ACEOF if ac_fn_cxx_try_compile "$LINENO"; then : ac_compiler_gnu=yes else ac_compiler_gnu=no fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext ac_cv_cxx_compiler_gnu=$ac_compiler_gnu fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_cxx_compiler_gnu" >&5 $as_echo "$ac_cv_cxx_compiler_gnu" >&6; } if test $ac_compiler_gnu = yes; then GXX=yes else GXX= fi ac_test_CXXFLAGS=${CXXFLAGS+set} ac_save_CXXFLAGS=$CXXFLAGS { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether $CXX accepts -g" >&5 $as_echo_n "checking whether $CXX accepts -g... " >&6; } if test "${ac_cv_prog_cxx_g+set}" = set; then : $as_echo_n "(cached) " >&6 else ac_save_cxx_werror_flag=$ac_cxx_werror_flag ac_cxx_werror_flag=yes ac_cv_prog_cxx_g=no CXXFLAGS="-g" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int main () { ; return 0; } _ACEOF if ac_fn_cxx_try_compile "$LINENO"; then : ac_cv_prog_cxx_g=yes else CXXFLAGS="" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int main () { ; return 0; } _ACEOF if ac_fn_cxx_try_compile "$LINENO"; then : else ac_cxx_werror_flag=$ac_save_cxx_werror_flag CXXFLAGS="-g" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int main () { ; return 0; } _ACEOF if ac_fn_cxx_try_compile "$LINENO"; then : ac_cv_prog_cxx_g=yes fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext ac_cxx_werror_flag=$ac_save_cxx_werror_flag fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_prog_cxx_g" >&5 $as_echo "$ac_cv_prog_cxx_g" >&6; } if test "$ac_test_CXXFLAGS" = set; then CXXFLAGS=$ac_save_CXXFLAGS elif test $ac_cv_prog_cxx_g = yes; then if test "$GXX" = yes; then CXXFLAGS="-g -O2" else CXXFLAGS="-g" fi else if test "$GXX" = yes; then CXXFLAGS="-O2" else CXXFLAGS= fi fi ac_ext=cpp ac_cpp='$CXXCPP $CPPFLAGS' ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5' ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' ac_compiler_gnu=$ac_cv_cxx_compiler_gnu ac_ext=cpp ac_cpp='$CXXCPP $CPPFLAGS' ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5' ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' ac_compiler_gnu=$ac_cv_cxx_compiler_gnu { $as_echo "$as_me:${as_lineno-$LINENO}: checking how to run the C++ preprocessor" >&5 $as_echo_n "checking how to run the C++ preprocessor... " >&6; } if test -z "$CXXCPP"; then if test "${ac_cv_prog_CXXCPP+set}" = set; then : $as_echo_n "(cached) " >&6 else # Double quotes because CXXCPP needs to be expanded for CXXCPP in "$CXX -E" "/lib/cpp" do ac_preproc_ok=false for ac_cxx_preproc_warn_flag in '' yes do # Use a header file that comes with gcc, so configuring glibc # with a fresh cross-compiler works. # Prefer to if __STDC__ is defined, since # exists even on freestanding compilers. # On the NeXT, cc -E runs the code through the compiler's parser, # not just through cpp. "Syntax error" is here to catch this case. cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #ifdef __STDC__ # include #else # include #endif Syntax error _ACEOF if ac_fn_cxx_try_cpp "$LINENO"; then : else # Broken: fails on valid input. continue fi rm -f conftest.err conftest.i conftest.$ac_ext # OK, works on sane cases. Now check whether nonexistent headers # can be detected and how. cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include _ACEOF if ac_fn_cxx_try_cpp "$LINENO"; then : # Broken: success on invalid input. continue else # Passes both tests. ac_preproc_ok=: break fi rm -f conftest.err conftest.i conftest.$ac_ext done # Because of `break', _AC_PREPROC_IFELSE's cleaning code was skipped. rm -f conftest.i conftest.err conftest.$ac_ext if $ac_preproc_ok; then : break fi done ac_cv_prog_CXXCPP=$CXXCPP fi CXXCPP=$ac_cv_prog_CXXCPP else ac_cv_prog_CXXCPP=$CXXCPP fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $CXXCPP" >&5 $as_echo "$CXXCPP" >&6; } ac_preproc_ok=false for ac_cxx_preproc_warn_flag in '' yes do # Use a header file that comes with gcc, so configuring glibc # with a fresh cross-compiler works. # Prefer to if __STDC__ is defined, since # exists even on freestanding compilers. # On the NeXT, cc -E runs the code through the compiler's parser, # not just through cpp. "Syntax error" is here to catch this case. cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #ifdef __STDC__ # include #else # include #endif Syntax error _ACEOF if ac_fn_cxx_try_cpp "$LINENO"; then : else # Broken: fails on valid input. continue fi rm -f conftest.err conftest.i conftest.$ac_ext # OK, works on sane cases. Now check whether nonexistent headers # can be detected and how. cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include _ACEOF if ac_fn_cxx_try_cpp "$LINENO"; then : # Broken: success on invalid input. continue else # Passes both tests. ac_preproc_ok=: break fi rm -f conftest.err conftest.i conftest.$ac_ext done # Because of `break', _AC_PREPROC_IFELSE's cleaning code was skipped. rm -f conftest.i conftest.err conftest.$ac_ext if $ac_preproc_ok; then : else { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 $as_echo "$as_me: error: in \`$ac_pwd':" >&2;} as_fn_error $? "C++ preprocessor \"$CXXCPP\" fails sanity check See \`config.log' for more details" "$LINENO" 5 ; } fi ac_ext=cpp ac_cpp='$CXXCPP $CPPFLAGS' ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5' ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' ac_compiler_gnu=$ac_cv_cxx_compiler_gnu if test -n "$ac_tool_prefix"; then # Extract the first word of "${ac_tool_prefix}ar", so it can be a program name with args. set dummy ${ac_tool_prefix}ar; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if test "${ac_cv_prog_AR+set}" = set; then : $as_echo_n "(cached) " >&6 else if test -n "$AR"; then ac_cv_prog_AR="$AR" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then ac_cv_prog_AR="${ac_tool_prefix}ar" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi AR=$ac_cv_prog_AR if test -n "$AR"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $AR" >&5 $as_echo "$AR" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi fi if test -z "$ac_cv_prog_AR"; then ac_ct_AR=$AR # Extract the first word of "ar", so it can be a program name with args. set dummy ar; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if test "${ac_cv_prog_ac_ct_AR+set}" = set; then : $as_echo_n "(cached) " >&6 else if test -n "$ac_ct_AR"; then ac_cv_prog_ac_ct_AR="$ac_ct_AR" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then ac_cv_prog_ac_ct_AR="ar" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi ac_ct_AR=$ac_cv_prog_ac_ct_AR if test -n "$ac_ct_AR"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_AR" >&5 $as_echo "$ac_ct_AR" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi if test "x$ac_ct_AR" = x; then AR="" else case $cross_compiling:$ac_tool_warned in yes:) { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 $as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} ac_tool_warned=yes ;; esac AR=$ac_ct_AR fi else AR="$ac_cv_prog_AR" fi EXTRA_SAT_HEADERS="" EXTRA_SAT_CPP="" LICENSE_INFO=/dev/null DPLL_BASIC="" #BEGIN zchaff cvc_use_zchaff="yes" # Check whether --enable-zchaff was given. if test "${enable_zchaff+set}" = set; then : enableval=$enable_zchaff; if test "$enableval" = "no"; then cvc_use_zchaff="no" fi fi if test "$cvc_use_zchaff" = "yes"; then /bin/sh >.zchaff <" echo " ./configure --disable-zchaff" echo " make" echo "" echo "" echo "
"
echo "src/sat/xchaff_base.h"
echo "src/sat/xchaff_dbase.h"
echo "src/sat/xchaff_solver.h"
echo "src/sat/xchaff_utils.h"
echo "src/sat/xchaff_dbase.cpp"
echo "src/sat/xchaff_solver.cpp"
echo "src/sat/xchaff_utils.cpp"
echo "
" echo "" EOF EXTRA_SAT_HEADERS="xchaff.h xchaff_base.h xchaff_dbase.h xchaff_solver.h xchaff_utils.h" EXTRA_SAT_CPP="xchaff.cpp xchaff_dbase.cpp xchaff_solver.cpp xchaff_utils.cpp " LICENSE_INFO=.zchaff DPLL_BASIC="-DDPLL_BASIC" fi #END zchaff # Version of CVC OPTIMIZED="0" GCOV="0" GPROF="0" # Check whether --with-build was given. if test "${with_build+set}" = set; then : withval=$with_build; if test "$withval" = "optimized"; then OPTIMIZED="1" elif test "$withval" = "gprof"; then OPTIMIZED="1" GPROF="1" elif test "$withval" = "gcov"; then GCOV="1" else DEBUG_MSG="yes" fi else # --with-build is not given, default is "optimized" build OPTIMIZED="1" fi CXXFLAGS="$CXXFLAGS" # Check whether --enable-debug-yacc was given. if test "${enable_debug_yacc+set}" = set; then : enableval=$enable_debug_yacc; if test "$enableval" = "yes"; then CXXFLAGS="$CXXFLAGS -DYYDEBUG" fi fi LD='$(CXX)' # Check whether --with-ld was given. if test "${with_ld+set}" = set; then : withval=$with_ld; if test ! "x$withval" = "xno" && test ! "x$withval" = "x"; then LD="$withval" fi fi LDFLAGS="$LDFLAGS" # Check whether --with-extra-libs was given. if test "${with_extra_libs+set}" = set; then : withval=$with_extra_libs; if test ! "x$withval" = "xno" && test ! "x$withval" = "x"; then LDFLAGS="$LDFLAGS -L"`echo "$withval" | sed -e 's/:/ -L/g'` fi fi CPPFLAGS="$CPPFLAGS" # Check whether --with-extra-includes was given. if test "${with_extra_includes+set}" = set; then : withval=$with_extra_includes; if test ! "x$withval" = "xno" && test ! "x$withval" = "x"; then CPPFLAGS="$CPPFLAGS -I"`echo "$withval" | sed -e 's/:/ -I/g'` fi fi # Check whether --with-version was given. if test "${with_version+set}" = set; then : withval=$with_version; # If option is given VERSION="$withval" else # If not given VERSION=`cat VERSION` fi # Check whether --enable-broken-cxx was given. if test "${enable_broken_cxx+set}" = set; then : enableval=$enable_broken_cxx; # If option is given if test "x$enableval" = "xyes"; then enable_broken_cxx="yes" else enable_broken_cxx="no" fi else # If option is not given enable_broken_cxx="no" fi ac_aux_dir= for ac_dir in "$srcdir" "$srcdir/.." "$srcdir/../.."; do if test -f "$ac_dir/install-sh"; then ac_aux_dir=$ac_dir ac_install_sh="$ac_aux_dir/install-sh -c" break elif test -f "$ac_dir/install.sh"; then ac_aux_dir=$ac_dir ac_install_sh="$ac_aux_dir/install.sh -c" break elif test -f "$ac_dir/shtool"; then ac_aux_dir=$ac_dir ac_install_sh="$ac_aux_dir/shtool install -c" break fi done if test -z "$ac_aux_dir"; then as_fn_error $? "cannot find install-sh, install.sh, or shtool in \"$srcdir\" \"$srcdir/..\" \"$srcdir/../..\"" "$LINENO" 5 fi # These three variables are undocumented and unsupported, # and are intended to be withdrawn in a future Autoconf release. # They can cause serious problems if a builder's source tree is in a directory # whose full name contains unusual characters. ac_config_guess="$SHELL $ac_aux_dir/config.guess" # Please don't use this var. ac_config_sub="$SHELL $ac_aux_dir/config.sub" # Please don't use this var. ac_configure="$SHELL $ac_aux_dir/configure" # Please don't use this var. # Make sure we can run config.sub. $SHELL "$ac_aux_dir/config.sub" sun4 >/dev/null 2>&1 || as_fn_error $? "cannot run $SHELL $ac_aux_dir/config.sub" "$LINENO" 5 { $as_echo "$as_me:${as_lineno-$LINENO}: checking build system type" >&5 $as_echo_n "checking build system type... " >&6; } if test "${ac_cv_build+set}" = set; then : $as_echo_n "(cached) " >&6 else ac_build_alias=$build_alias test "x$ac_build_alias" = x && ac_build_alias=`$SHELL "$ac_aux_dir/config.guess"` test "x$ac_build_alias" = x && as_fn_error $? "cannot guess build type; you must specify one" "$LINENO" 5 ac_cv_build=`$SHELL "$ac_aux_dir/config.sub" $ac_build_alias` || as_fn_error $? "$SHELL $ac_aux_dir/config.sub $ac_build_alias failed" "$LINENO" 5 fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_build" >&5 $as_echo "$ac_cv_build" >&6; } case $ac_cv_build in *-*-*) ;; *) as_fn_error $? "invalid value of canonical build" "$LINENO" 5 ;; esac build=$ac_cv_build ac_save_IFS=$IFS; IFS='-' set x $ac_cv_build shift build_cpu=$1 build_vendor=$2 shift; shift # Remember, the first character of IFS is used to create $*, # except with old shells: build_os=$* IFS=$ac_save_IFS case $build_os in *\ *) build_os=`echo "$build_os" | sed 's/ /-/g'`;; esac { $as_echo "$as_me:${as_lineno-$LINENO}: checking host system type" >&5 $as_echo_n "checking host system type... " >&6; } if test "${ac_cv_host+set}" = set; then : $as_echo_n "(cached) " >&6 else if test "x$host_alias" = x; then ac_cv_host=$ac_cv_build else ac_cv_host=`$SHELL "$ac_aux_dir/config.sub" $host_alias` || as_fn_error $? "$SHELL $ac_aux_dir/config.sub $host_alias failed" "$LINENO" 5 fi fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_host" >&5 $as_echo "$ac_cv_host" >&6; } case $ac_cv_host in *-*-*) ;; *) as_fn_error $? "invalid value of canonical host" "$LINENO" 5 ;; esac host=$ac_cv_host ac_save_IFS=$IFS; IFS='-' set x $ac_cv_host shift host_cpu=$1 host_vendor=$2 shift; shift # Remember, the first character of IFS is used to create $*, # except with old shells: host_os=$* IFS=$ac_save_IFS case $host_os in *\ *) host_os=`echo "$host_os" | sed 's/ /-/g'`;; esac case "$host_os" in none) host_os="unknown" ;; darwin*) MAC_OSX=1 ;; cygwin) CYGWIN=1 ;; esac case "$host_cpu" in i?86) # punt for Mac OS-- it gives you i386 even on 64-bit # let darwin's gcc build what it wants (or have the user add # -mXX to CXXFLAGS themselves) if test "$MAC_OSX" = 1; then :; else CXXFLAGS="$CXXFLAGS -m32" if test "$CYGWIN" = 1; then :; else # Sun's Java on Windows doesn't have -d* JREFLAGS="$JREFLAGS -d32" fi fi ;; x86_64) CXXFLAGS="$CXXFLAGS -m64" JREFLAGS="$JREFLAGS -d64" ;; esac OSTYPE="$host_cpu-$host_os" # The standard macro does something stupid. Check it explicitly. # AC_PROG_INSTALL # Extract the first word of "install", so it can be a program name with args. set dummy install; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if test "${ac_cv_path_INSTALL+set}" = set; then : $as_echo_n "(cached) " >&6 else case $INSTALL in [\\/]* | ?:[\\/]*) ac_cv_path_INSTALL="$INSTALL" # Let the user override the test with a path. ;; *) as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then ac_cv_path_INSTALL="$as_dir/$ac_word$ac_exec_ext" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS test -z "$ac_cv_path_INSTALL" && ac_cv_path_INSTALL="cp" ;; esac fi INSTALL=$ac_cv_path_INSTALL if test -n "$INSTALL"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $INSTALL" >&5 $as_echo "$INSTALL" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi if test "$INSTALL" = "cp"; then INSTALL_FLAGS="" else # INSTALL_FLAGS="-C --owner=root --group=root" # INSTALL_FLAGS="-C" # Seems like the arguments to 'install' are changing wildly with platform... INSTALL_FLAGS="" fi # Extract the first word of "ldconfig", so it can be a program name with args. set dummy ldconfig; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if test "${ac_cv_path_LDCONFIG+set}" = set; then : $as_echo_n "(cached) " >&6 else case $LDCONFIG in [\\/]* | ?:[\\/]*) ac_cv_path_LDCONFIG="$LDCONFIG" # Let the user override the test with a path. ;; *) as_save_IFS=$IFS; IFS=$PATH_SEPARATOR as_dummy="$PATH:/sbin:/usr/sbin" for as_dir in $as_dummy do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then ac_cv_path_LDCONFIG="$as_dir/$ac_word$ac_exec_ext" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS test -z "$ac_cv_path_LDCONFIG" && ac_cv_path_LDCONFIG="{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: ldconfig not found. Library installation may fail." >&5 $as_echo "$as_me: WARNING: ldconfig not found. Library installation may fail." >&2;}" ;; esac fi LDCONFIG=$ac_cv_path_LDCONFIG if test -n "$LDCONFIG"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $LDCONFIG" >&5 $as_echo "$LDCONFIG" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi if test -n "$MAC_OSX"; then # Extract the first word of "gtime", so it can be a program name with args. set dummy gtime; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if test "${ac_cv_path_TIME+set}" = set; then : $as_echo_n "(cached) " >&6 else case $TIME in [\\/]* | ?:[\\/]*) ac_cv_path_TIME="$TIME" # Let the user override the test with a path. ;; *) as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then ac_cv_path_TIME="$as_dir/$ac_word$ac_exec_ext" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS test -z "$ac_cv_path_TIME" && ac_cv_path_TIME="not found" ;; esac fi TIME=$ac_cv_path_TIME if test -n "$TIME"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $TIME" >&5 $as_echo "$TIME" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi else # Extract the first word of "time", so it can be a program name with args. set dummy time; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if test "${ac_cv_path_TIME+set}" = set; then : $as_echo_n "(cached) " >&6 else case $TIME in [\\/]* | ?:[\\/]*) ac_cv_path_TIME="$TIME" # Let the user override the test with a path. ;; *) as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then ac_cv_path_TIME="$as_dir/$ac_word$ac_exec_ext" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS test -z "$ac_cv_path_TIME" && ac_cv_path_TIME="not found" ;; esac fi TIME=$ac_cv_path_TIME if test -n "$TIME"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $TIME" >&5 $as_echo "$TIME" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi fi if test "$TIME" = "not found"; then { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: Regression tests depend upon GNU time." >&5 $as_echo "$as_me: WARNING: Regression tests depend upon GNU time." >&2;} if test -n "$MAC_OSX"; then { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: Please install GNU time; we suggest using MacPorts" >&5 $as_echo "$as_me: WARNING: Please install GNU time; we suggest using MacPorts" >&2;} fi fi # Extract the first word of "perl", so it can be a program name with args. set dummy perl; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if test "${ac_cv_path_PERL+set}" = set; then : $as_echo_n "(cached) " >&6 else case $PERL in [\\/]* | ?:[\\/]*) ac_cv_path_PERL="$PERL" # Let the user override the test with a path. ;; *) as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then ac_cv_path_PERL="$as_dir/$ac_word$ac_exec_ext" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS test -z "$ac_cv_path_PERL" && ac_cv_path_PERL="not found" ;; esac fi PERL=$ac_cv_path_PERL if test -n "$PERL"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $PERL" >&5 $as_echo "$PERL" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi if test "$PERL" = "not found"; then perl_found=0 { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: Perl not found. Static build will probably fail." >&5 $as_echo "$as_me: WARNING: Perl not found. Static build will probably fail." >&2;} # Set default path for perl, just in case PERL=/usr/bin/perl else perl_found=1 fi for ac_prog in 'bison -y' byacc do # Extract the first word of "$ac_prog", so it can be a program name with args. set dummy $ac_prog; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if test "${ac_cv_prog_YACC+set}" = set; then : $as_echo_n "(cached) " >&6 else if test -n "$YACC"; then ac_cv_prog_YACC="$YACC" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then ac_cv_prog_YACC="$ac_prog" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi YACC=$ac_cv_prog_YACC if test -n "$YACC"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $YACC" >&5 $as_echo "$YACC" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi test -n "$YACC" && break done test -n "$YACC" || YACC="yacc" if test "$YACC" != "bison -y"; then as_fn_error $? "bison not found" "$LINENO" 5 fi for ac_prog in flex lex do # Extract the first word of "$ac_prog", so it can be a program name with args. set dummy $ac_prog; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if test "${ac_cv_prog_LEX+set}" = set; then : $as_echo_n "(cached) " >&6 else if test -n "$LEX"; then ac_cv_prog_LEX="$LEX" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then ac_cv_prog_LEX="$ac_prog" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi LEX=$ac_cv_prog_LEX if test -n "$LEX"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $LEX" >&5 $as_echo "$LEX" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi test -n "$LEX" && break done test -n "$LEX" || LEX=":" if test "x$LEX" != "x:"; then cat >conftest.l <<_ACEOF %% a { ECHO; } b { REJECT; } c { yymore (); } d { yyless (1); } e { yyless (input () != 0); } f { unput (yytext[0]); } . { BEGIN INITIAL; } %% #ifdef YYTEXT_POINTER extern char *yytext; #endif int main (void) { return ! yylex () + ! yywrap (); } _ACEOF { { ac_try="$LEX conftest.l" case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" $as_echo "$ac_try_echo"; } >&5 (eval "$LEX conftest.l") 2>&5 ac_status=$? $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; } { $as_echo "$as_me:${as_lineno-$LINENO}: checking lex output file root" >&5 $as_echo_n "checking lex output file root... " >&6; } if test "${ac_cv_prog_lex_root+set}" = set; then : $as_echo_n "(cached) " >&6 else if test -f lex.yy.c; then ac_cv_prog_lex_root=lex.yy elif test -f lexyy.c; then ac_cv_prog_lex_root=lexyy else as_fn_error $? "cannot find output from $LEX; giving up" "$LINENO" 5 fi fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_prog_lex_root" >&5 $as_echo "$ac_cv_prog_lex_root" >&6; } LEX_OUTPUT_ROOT=$ac_cv_prog_lex_root if test -z "${LEXLIB+set}"; then { $as_echo "$as_me:${as_lineno-$LINENO}: checking lex library" >&5 $as_echo_n "checking lex library... " >&6; } if test "${ac_cv_lib_lex+set}" = set; then : $as_echo_n "(cached) " >&6 else ac_save_LIBS=$LIBS ac_cv_lib_lex='none needed' for ac_lib in '' -lfl -ll; do LIBS="$ac_lib $ac_save_LIBS" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ `cat $LEX_OUTPUT_ROOT.c` _ACEOF if ac_fn_cxx_try_link "$LINENO"; then : ac_cv_lib_lex=$ac_lib fi rm -f core conftest.err conftest.$ac_objext \ conftest$ac_exeext conftest.$ac_ext test "$ac_cv_lib_lex" != 'none needed' && break done LIBS=$ac_save_LIBS fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_lex" >&5 $as_echo "$ac_cv_lib_lex" >&6; } test "$ac_cv_lib_lex" != 'none needed' && LEXLIB=$ac_cv_lib_lex fi { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether yytext is a pointer" >&5 $as_echo_n "checking whether yytext is a pointer... " >&6; } if test "${ac_cv_prog_lex_yytext_pointer+set}" = set; then : $as_echo_n "(cached) " >&6 else # POSIX says lex can declare yytext either as a pointer or an array; the # default is implementation-dependent. Figure out which it is, since # not all implementations provide the %pointer and %array declarations. ac_cv_prog_lex_yytext_pointer=no ac_save_LIBS=$LIBS LIBS="$LEXLIB $ac_save_LIBS" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #define YYTEXT_POINTER 1 `cat $LEX_OUTPUT_ROOT.c` _ACEOF if ac_fn_cxx_try_link "$LINENO"; then : ac_cv_prog_lex_yytext_pointer=yes fi rm -f core conftest.err conftest.$ac_objext \ conftest$ac_exeext conftest.$ac_ext LIBS=$ac_save_LIBS fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_prog_lex_yytext_pointer" >&5 $as_echo "$ac_cv_prog_lex_yytext_pointer" >&6; } if test $ac_cv_prog_lex_yytext_pointer = yes; then $as_echo "#define YYTEXT_POINTER 1" >>confdefs.h fi rm -f conftest.l $LEX_OUTPUT_ROOT.c fi if test "$LEX" != "flex"; then as_fn_error $? "flex not found" "$LINENO" 5 fi { $as_echo "$as_me:${as_lineno-$LINENO}: checking for compiler version ($CXX --version)" >&5 $as_echo_n "checking for compiler version ($CXX --version)... " >&6; } if test "${cvc_cv_cxx_version+set}" = set; then : $as_echo_n "(cached) " >&6 else cvc_cv_cxx_version=`$CXX --version | grep "[0-9][0-9]*[.][0-9]*" | sed -e 's/^[^0-9]*\([0-9.]*\).*$/\1/'` fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $cvc_cv_cxx_version" >&5 $as_echo "$cvc_cv_cxx_version" >&6; } cxx_major_version=`echo $cvc_cv_cxx_version | sed -e 's/^\([0-9]*\).*/\1/'` cxx_minor_version=`echo $cvc_cv_cxx_version | sed -e 's/^[0-9]*[.]\([0-9]*\).*/\1/'` if test "$cxx_major_version.$cxx_minor_version" = "3.0"; then if test "$enable_broken_cxx" = "no"; then as_fn_error $? "Compiler version $cvc_cv_cxx_version is known to generate bad executables. If you still want to compile with it, configure with option --enable-broken-cxx, but then do not ask for help unless you know how to fix it." "$LINENO" 5 else # The user asked for bad compiler. Warn him/her at the end. cxx_bad_version_warning="yes" fi fi STATIC="1" BUILD_SHARED_LIB="0" if test -n "$MAC_OSX"; then DYNAMIC_FLAG="-dynamic" STATIC_FLAG="" SHARED="-dynamiclib -undefined dynamic_lookup" LD_SWITCHES_PRE="" LD_SWITCHES_POST="" elif test -n "$CYGWIN"; then DYNAMIC_FLAG="" STATIC_FLAG="" SHARED="-shared" LD_SWITCHES_PRE="-Wl,-static -Wl,--whole-archive" LD_SWITCHES_POST="-Wl,--no-whole-archive -Wl,-call_shared" else DYNAMIC_FLAG="" STATIC_FLAG="-static" SHARED="-shared" LD_SWITCHES_PRE="-Wl,-static -Wl,--whole-archive" LD_SWITCHES_POST="-Wl,--no-whole-archive -Wl,-call_shared" fi # Check whether --enable-static was given. if test "${enable_static+set}" = set; then : enableval=$enable_static; # If options is given if test "$enableval" = "no"; then STATIC="0" fi fi # Check whether --enable-dynamic was given. if test "${enable_dynamic+set}" = set; then : enableval=$enable_dynamic; # If option is given if test "$enableval" = "yes"; then STATIC="0" fi fi # Check whether --enable-sharedlibs was given. if test "${enable_sharedlibs+set}" = set; then : enableval=$enable_sharedlibs; # If option is given if test "$enableval" = "yes"; then BUILD_SHARED_LIB="1" fi fi STATIC_LIB_SUFFIX="a" if test -n "$MAC_OSX"; then SHARED_LIB_SUFFIX="dylib" elif test -n "$CYGWIN"; then SHARED_LIB_SUFFIX="dll" else SHARED_LIB_SUFFIX="so" fi # Check whether --with-arith was given. if test "${with_arith+set}" = set; then : withval=$with_arith; if test "$withval" = gmpxx; then RATIONAL_IMPL="-DRATIONAL_GMPXX" elif test "$withval" = gmp; then RATIONAL_IMPL="-DRATIONAL_GMP" elif test "$withval" = native; then RATIONAL_IMPL="-DRATIONAL_NATIVE" else RATIONAL_IMPL="" fi else # if option is not given RATIONAL_IMPL="-DRATIONAL_GMP" fi # Make sure we check the appropriate static / shared library if test "$RATIONAL_IMPL" = "-DRATIONAL_GMP"; then { $as_echo "$as_me:${as_lineno-$LINENO}: checking for gmp" >&5 $as_echo_n "checking for gmp... " >&6; } LIBS="-lgmp $LIBS" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include #include int main () { mpq_t x; mpq_init(x); ; return 0; } _ACEOF if ac_fn_cxx_try_link "$LINENO"; then : cvc_gmp_works="yes" else cvc_gmp_works="no" fi rm -f core conftest.err conftest.$ac_objext \ conftest$ac_exeext conftest.$ac_ext if test "$cvc_gmp_works" = "no"; then if test -n "$MAC_OSX"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } { $as_echo "$as_me:${as_lineno-$LINENO}: checking for gmp in /opt/local" >&5 $as_echo_n "checking for gmp in /opt/local... " >&6; } CPPFLAGS="-I/opt/local/include $CPPFLAGS" LDFLAGS="-L/opt/local/lib $LDFLAGS" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include #include int main () { mpq_t x; mpq_init(x); ; return 0; } _ACEOF if ac_fn_cxx_try_link "$LINENO"; then : cvc_gmp_works="yes" else cvc_gmp_works="no" fi rm -f core conftest.err conftest.$ac_objext \ conftest$ac_exeext conftest.$ac_ext fi fi if test "$cvc_gmp_works" = "no"; then as_fn_error $? "libgmp.a is not found. You can still compile CVC3 with native computer arithmetic: ./configure --with-arith=native WARNING: native arithmetic may cause overflows and assertion failures. If CVC3 fails due to an overflow in native arithmetic, do NOT report a bug; it is an intended feature to prevent soundness errors. For these reasons, we STRONGLY recommend installing GMP." "$LINENO" 5 else { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 $as_echo "yes" >&6; } fi elif test "$RATIONAL_IMPL" = "-DRATIONAL_GMPXX"; then { $as_echo "$as_me:${as_lineno-$LINENO}: checking for main in -lgmp" >&5 $as_echo_n "checking for main in -lgmp... " >&6; } if test "${ac_cv_lib_gmp_main+set}" = set; then : $as_echo_n "(cached) " >&6 else ac_check_lib_save_LIBS=$LIBS LIBS="-lgmp $LIBS" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int main () { return main (); ; return 0; } _ACEOF if ac_fn_cxx_try_link "$LINENO"; then : ac_cv_lib_gmp_main=yes else ac_cv_lib_gmp_main=no fi rm -f core conftest.err conftest.$ac_objext \ conftest$ac_exeext conftest.$ac_ext LIBS=$ac_check_lib_save_LIBS fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_gmp_main" >&5 $as_echo "$ac_cv_lib_gmp_main" >&6; } if test "x$ac_cv_lib_gmp_main" = x""yes; then : cat >>confdefs.h <<_ACEOF #define HAVE_LIBGMP 1 _ACEOF LIBS="-lgmp $LIBS" else as_fn_error $? "libgmp.a is not found" "$LINENO" 5 fi { $as_echo "$as_me:${as_lineno-$LINENO}: checking for main in -lgmpxx" >&5 $as_echo_n "checking for main in -lgmpxx... " >&6; } if test "${ac_cv_lib_gmpxx_main+set}" = set; then : $as_echo_n "(cached) " >&6 else ac_check_lib_save_LIBS=$LIBS LIBS="-lgmpxx $LIBS" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int main () { return main (); ; return 0; } _ACEOF if ac_fn_cxx_try_link "$LINENO"; then : ac_cv_lib_gmpxx_main=yes else ac_cv_lib_gmpxx_main=no fi rm -f core conftest.err conftest.$ac_objext \ conftest$ac_exeext conftest.$ac_ext LIBS=$ac_check_lib_save_LIBS fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_gmpxx_main" >&5 $as_echo "$ac_cv_lib_gmpxx_main" >&6; } if test "x$ac_cv_lib_gmpxx_main" = x""yes; then : cat >>confdefs.h <<_ACEOF #define HAVE_LIBGMPXX 1 _ACEOF LIBS="-lgmpxx $LIBS" else as_fn_error $? "libgmpxx.a is not found" "$LINENO" 5 fi elif test -z "$RATIONAL_IMPL"; then as_fn_error $? "\"Unknown argument to with-arith\"" "$LINENO" 5 fi if test "$RATIONAL_IMPL" = "-DRATIONAL_GMPXX"; then # Do some more extensive check of gmpxx, since it may be compiled with # a wrong compiler. { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether gmpxx library works" >&5 $as_echo_n "checking whether gmpxx library works... " >&6; } if test "${cvc_cv_gmpxx_works+set}" = set; then : $as_echo_n "(cached) " >&6 else cvc_cv_gmpxx_works="no" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include #include int main () { mpz_class x; std::cout << x; ; return 0; } _ACEOF if ac_fn_cxx_try_link "$LINENO"; then : cvc_cv_gmpxx_works="yes" fi rm -f core conftest.err conftest.$ac_objext \ conftest$ac_exeext conftest.$ac_ext fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $cvc_cv_gmpxx_works" >&5 $as_echo "$cvc_cv_gmpxx_works" >&6; } if test "$cvc_cv_gmpxx_works" = "no"; then as_fn_error $? "libgmpxx.a did not link. You may have to recompile GMP with the current compiler: $CXX." "$LINENO" 5 fi fi BUILD_JAVA="0" javadir='${exec_prefix}/java' # Check whether --enable-java was given. if test "${enable_java+set}" = set; then : enableval=$enable_java; # If option is given if test "$enableval" = "yes"; then BUILD_JAVA="1" fi fi if test "$BUILD_JAVA" = "1"; then if test "$STATIC" = "1"; then as_fn_error $? "The Java interface requires a dynamic library build. Use --enable-dynamic." "$LINENO" 5 fi # Check whether --with-java-home was given. if test "${with_java_home+set}" = set; then : withval=$with_java_home; JAVA_HOME=${withval} fi # Check whether --with-java-includes was given. if test "${with_java_includes+set}" = set; then : withval=$with_java_includes; JAVA_INCLUDE_PATH="${withval}" fi if test -n "${MAC_OSX}" -a -z "${JAVA_HOME}" ; then JAVA_HOME=/System/Library/Frameworks/JavaVM.framework/Home fi if ! ( test -n "${JAVA_INCLUDE_PATH}" -a -d "${JAVA_INCLUDE_PATH}" ) ; then if test -d ${JAVA_HOME}/include ; then JAVA_INCLUDE_PATH=${JAVA_HOME}/include elif test -d ${JAVA_HOME}/Headers; then JAVA_INCLUDE_PATH=-I${JAVA_HOME}/Headers else as_fn_error $? "Unable to locate Java directories" "$LINENO" 5 fi fi JAVA_INCLUDES=-I${JAVA_INCLUDE_PATH} if test -d ${JAVA_INCLUDE_PATH}/genunix ; then JAVA_INCLUDES="$JAVA_INCLUDES -I${JAVA_INCLUDE_PATH}/genunix" fi if test -d ${JAVA_INCLUDE_PATH}/linux ; then JAVA_INCLUDES="$JAVA_INCLUDES -I${JAVA_INCLUDE_PATH}/linux" fi if test -d ${JAVA_INCLUDE_PATH}/solaris ; then JAVA_INCLUDES="$JAVA_INCLUDES -I${JAVA_INCLUDE_PATH}/solaris" fi if test -d ${JAVA_INCLUDE_PATH}/freebsd ; then JAVA_INCLUDES="$JAVA_INCLUDES -I${JAVA_INCLUDE_PATH}/freebsd" fi if test -d ${JAVA_INCLUDE_PATH}/win32 ; then JAVA_INCLUDES="$JAVA_INCLUDES -I${JAVA_INCLUDE_PATH}/win32" fi if test -d ${JAVA_INCLUDE_PATH}/bsd ; then JAVA_INCLUDES="$JAVA_INCLUDES -I${JAVA_INCLUDE_PATH}/bsd" fi if test -d ${JAVA_HOME}/bin; then PATH=${JAVA_HOME}/bin:$PATH fi # Check for Java tools # Extract the first word of "javac", so it can be a program name with args. set dummy javac; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if test "${ac_cv_path_JAVAC+set}" = set; then : $as_echo_n "(cached) " >&6 else case $JAVAC in [\\/]* | ?:[\\/]*) ac_cv_path_JAVAC="$JAVAC" # Let the user override the test with a path. ;; *) as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then ac_cv_path_JAVAC="$as_dir/$ac_word$ac_exec_ext" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS test -z "$ac_cv_path_JAVAC" && ac_cv_path_JAVAC="as_fn_error $? "javac not found: adjust PATH or set JAVAC" "$LINENO" 5 " ;; esac fi JAVAC=$ac_cv_path_JAVAC if test -n "$JAVAC"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $JAVAC" >&5 $as_echo "$JAVAC" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi # Extract the first word of "javah", so it can be a program name with args. set dummy javah; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if test "${ac_cv_path_JAVAH+set}" = set; then : $as_echo_n "(cached) " >&6 else case $JAVAH in [\\/]* | ?:[\\/]*) ac_cv_path_JAVAH="$JAVAH" # Let the user override the test with a path. ;; *) as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then ac_cv_path_JAVAH="$as_dir/$ac_word$ac_exec_ext" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS test -z "$ac_cv_path_JAVAH" && ac_cv_path_JAVAH="as_fn_error $? "javah not found: adjust PATH or set JAVAH" "$LINENO" 5 " ;; esac fi JAVAH=$ac_cv_path_JAVAH if test -n "$JAVAH"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $JAVAH" >&5 $as_echo "$JAVAH" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi # Extract the first word of "jar", so it can be a program name with args. set dummy jar; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if test "${ac_cv_path_JAR+set}" = set; then : $as_echo_n "(cached) " >&6 else case $JAR in [\\/]* | ?:[\\/]*) ac_cv_path_JAR="$JAR" # Let the user override the test with a path. ;; *) as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then ac_cv_path_JAR="$as_dir/$ac_word$ac_exec_ext" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS test -z "$ac_cv_path_JAR" && ac_cv_path_JAR="as_fn_error $? "jar not found: adjust PATH or set JAR" "$LINENO" 5 " ;; esac fi JAR=$ac_cv_path_JAR if test -n "$JAR"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $JAR" >&5 $as_echo "$JAR" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi # Extract the first word of "java", so it can be a program name with args. set dummy java; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if test "${ac_cv_path_JAVA+set}" = set; then : $as_echo_n "(cached) " >&6 else case $JAVA in [\\/]* | ?:[\\/]*) ac_cv_path_JAVA="$JAVA" # Let the user override the test with a path. ;; *) as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then ac_cv_path_JAVA="$as_dir/$ac_word$ac_exec_ext" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS test -z "$ac_cv_path_JAVA" && ac_cv_path_JAVA="as_fn_error $? "java not found: adjust PATH or set JAVA" "$LINENO" 5 " ;; esac fi JAVA=$ac_cv_path_JAVA if test -n "$JAVA"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $JAVA" >&5 $as_echo "$JAVA" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi OLD_CPPFLAGS="$CPPFLAGS" CPPFLAGS="${JAVA_INCLUDES} $CPPFLAGS" { $as_echo "$as_me:${as_lineno-$LINENO}: checking for grep that handles long lines and -e" >&5 $as_echo_n "checking for grep that handles long lines and -e... " >&6; } if test "${ac_cv_path_GREP+set}" = set; then : $as_echo_n "(cached) " >&6 else if test -z "$GREP"; then ac_path_GREP_found=false # Loop through the user's path and test for each of PROGNAME-LIST as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH$PATH_SEPARATOR/usr/xpg4/bin do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_prog in grep ggrep; do for ac_exec_ext in '' $ac_executable_extensions; do ac_path_GREP="$as_dir/$ac_prog$ac_exec_ext" { test -f "$ac_path_GREP" && $as_test_x "$ac_path_GREP"; } || continue # Check for GNU ac_path_GREP and select it if it is found. # Check for GNU $ac_path_GREP case `"$ac_path_GREP" --version 2>&1` in *GNU*) ac_cv_path_GREP="$ac_path_GREP" ac_path_GREP_found=:;; *) ac_count=0 $as_echo_n 0123456789 >"conftest.in" while : do cat "conftest.in" "conftest.in" >"conftest.tmp" mv "conftest.tmp" "conftest.in" cp "conftest.in" "conftest.nl" $as_echo 'GREP' >> "conftest.nl" "$ac_path_GREP" -e 'GREP$' -e '-(cannot match)-' < "conftest.nl" >"conftest.out" 2>/dev/null || break diff "conftest.out" "conftest.nl" >/dev/null 2>&1 || break as_fn_arith $ac_count + 1 && ac_count=$as_val if test $ac_count -gt ${ac_path_GREP_max-0}; then # Best one so far, save it but keep looking for a better one ac_cv_path_GREP="$ac_path_GREP" ac_path_GREP_max=$ac_count fi # 10*(2^10) chars as input seems more than enough test $ac_count -gt 10 && break done rm -f conftest.in conftest.tmp conftest.nl conftest.out;; esac $ac_path_GREP_found && break 3 done done done IFS=$as_save_IFS if test -z "$ac_cv_path_GREP"; then as_fn_error $? "no acceptable grep could be found in $PATH$PATH_SEPARATOR/usr/xpg4/bin" "$LINENO" 5 fi else ac_cv_path_GREP=$GREP fi fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_path_GREP" >&5 $as_echo "$ac_cv_path_GREP" >&6; } GREP="$ac_cv_path_GREP" { $as_echo "$as_me:${as_lineno-$LINENO}: checking for egrep" >&5 $as_echo_n "checking for egrep... " >&6; } if test "${ac_cv_path_EGREP+set}" = set; then : $as_echo_n "(cached) " >&6 else if echo a | $GREP -E '(a|b)' >/dev/null 2>&1 then ac_cv_path_EGREP="$GREP -E" else if test -z "$EGREP"; then ac_path_EGREP_found=false # Loop through the user's path and test for each of PROGNAME-LIST as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH$PATH_SEPARATOR/usr/xpg4/bin do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_prog in egrep; do for ac_exec_ext in '' $ac_executable_extensions; do ac_path_EGREP="$as_dir/$ac_prog$ac_exec_ext" { test -f "$ac_path_EGREP" && $as_test_x "$ac_path_EGREP"; } || continue # Check for GNU ac_path_EGREP and select it if it is found. # Check for GNU $ac_path_EGREP case `"$ac_path_EGREP" --version 2>&1` in *GNU*) ac_cv_path_EGREP="$ac_path_EGREP" ac_path_EGREP_found=:;; *) ac_count=0 $as_echo_n 0123456789 >"conftest.in" while : do cat "conftest.in" "conftest.in" >"conftest.tmp" mv "conftest.tmp" "conftest.in" cp "conftest.in" "conftest.nl" $as_echo 'EGREP' >> "conftest.nl" "$ac_path_EGREP" 'EGREP$' < "conftest.nl" >"conftest.out" 2>/dev/null || break diff "conftest.out" "conftest.nl" >/dev/null 2>&1 || break as_fn_arith $ac_count + 1 && ac_count=$as_val if test $ac_count -gt ${ac_path_EGREP_max-0}; then # Best one so far, save it but keep looking for a better one ac_cv_path_EGREP="$ac_path_EGREP" ac_path_EGREP_max=$ac_count fi # 10*(2^10) chars as input seems more than enough test $ac_count -gt 10 && break done rm -f conftest.in conftest.tmp conftest.nl conftest.out;; esac $ac_path_EGREP_found && break 3 done done done IFS=$as_save_IFS if test -z "$ac_cv_path_EGREP"; then as_fn_error $? "no acceptable egrep could be found in $PATH$PATH_SEPARATOR/usr/xpg4/bin" "$LINENO" 5 fi else ac_cv_path_EGREP=$EGREP fi fi fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_path_EGREP" >&5 $as_echo "$ac_cv_path_EGREP" >&6; } EGREP="$ac_cv_path_EGREP" { $as_echo "$as_me:${as_lineno-$LINENO}: checking for ANSI C header files" >&5 $as_echo_n "checking for ANSI C header files... " >&6; } if test "${ac_cv_header_stdc+set}" = set; then : $as_echo_n "(cached) " >&6 else cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include #include #include #include int main () { ; return 0; } _ACEOF if ac_fn_cxx_try_compile "$LINENO"; then : ac_cv_header_stdc=yes else ac_cv_header_stdc=no fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext if test $ac_cv_header_stdc = yes; then # SunOS 4.x string.h does not declare mem*, contrary to ANSI. cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include _ACEOF if (eval "$ac_cpp conftest.$ac_ext") 2>&5 | $EGREP "memchr" >/dev/null 2>&1; then : else ac_cv_header_stdc=no fi rm -f conftest* fi if test $ac_cv_header_stdc = yes; then # ISC 2.0.2 stdlib.h does not declare free, contrary to ANSI. cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include _ACEOF if (eval "$ac_cpp conftest.$ac_ext") 2>&5 | $EGREP "free" >/dev/null 2>&1; then : else ac_cv_header_stdc=no fi rm -f conftest* fi if test $ac_cv_header_stdc = yes; then # /bin/cc in Irix-4.0.5 gets non-ANSI ctype macros unless using -ansi. if test "$cross_compiling" = yes; then : : else cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include #include #if ((' ' & 0x0FF) == 0x020) # define ISLOWER(c) ('a' <= (c) && (c) <= 'z') # define TOUPPER(c) (ISLOWER(c) ? 'A' + ((c) - 'a') : (c)) #else # define ISLOWER(c) \ (('a' <= (c) && (c) <= 'i') \ || ('j' <= (c) && (c) <= 'r') \ || ('s' <= (c) && (c) <= 'z')) # define TOUPPER(c) (ISLOWER(c) ? ((c) | 0x40) : (c)) #endif #define XOR(e, f) (((e) && !(f)) || (!(e) && (f))) int main () { int i; for (i = 0; i < 256; i++) if (XOR (islower (i), ISLOWER (i)) || toupper (i) != TOUPPER (i)) return 2; return 0; } _ACEOF if ac_fn_cxx_try_run "$LINENO"; then : else ac_cv_header_stdc=no fi rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext \ conftest.$ac_objext conftest.beam conftest.$ac_ext fi fi fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_header_stdc" >&5 $as_echo "$ac_cv_header_stdc" >&6; } if test $ac_cv_header_stdc = yes; then $as_echo "#define STDC_HEADERS 1" >>confdefs.h fi # On IRIX 5.3, sys/types and inttypes.h are conflicting. for ac_header in sys/types.h sys/stat.h stdlib.h string.h memory.h strings.h \ inttypes.h stdint.h unistd.h do : as_ac_Header=`$as_echo "ac_cv_header_$ac_header" | $as_tr_sh` ac_fn_cxx_check_header_compile "$LINENO" "$ac_header" "$as_ac_Header" "$ac_includes_default " if eval test \"x\$"$as_ac_Header"\" = x"yes"; then : cat >>confdefs.h <<_ACEOF #define `$as_echo "HAVE_$ac_header" | $as_tr_cpp` 1 _ACEOF fi done ac_fn_cxx_check_header_mongrel "$LINENO" "jni.h" "ac_cv_header_jni_h" "$ac_includes_default" if test "x$ac_cv_header_jni_h" = x""yes; then : else as_fn_error $? "jni.h not found: try setting --with-java-home or --with-java-includes" "$LINENO" 5 fi ac_fn_cxx_check_header_mongrel "$LINENO" "jni_md.h" "ac_cv_header_jni_md_h" "$ac_includes_default" if test "x$ac_cv_header_jni_md_h" = x""yes; then : else as_fn_error $? "jni_md.h not found: try setting --with-java-home or --with-java-includes" "$LINENO" 5 fi CPPFLAGS="$OLD_CPPFLAGS" # Extract the first word of "python", so it can be a program name with args. set dummy python; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if test "${ac_cv_path_PYTHON+set}" = set; then : $as_echo_n "(cached) " >&6 else case $PYTHON in [\\/]* | ?:[\\/]*) ac_cv_path_PYTHON="$PYTHON" # Let the user override the test with a path. ;; *) as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then ac_cv_path_PYTHON="$as_dir/$ac_word$ac_exec_ext" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS test -z "$ac_cv_path_PYTHON" && ac_cv_path_PYTHON="as_fn_error $? "python not found: adjust PATH or set PYTHON" "$LINENO" 5 " ;; esac fi PYTHON=$ac_cv_path_PYTHON if test -n "$PYTHON"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $PYTHON" >&5 $as_echo "$PYTHON" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi fi for ac_header in vector list deque set string cstdlib cstdio \ functional algorithm do : as_ac_Header=`$as_echo "ac_cv_header_$ac_header" | $as_tr_sh` ac_fn_cxx_check_header_mongrel "$LINENO" "$ac_header" "$as_ac_Header" "$ac_includes_default" if eval test \"x\$"$as_ac_Header"\" = x"yes"; then : cat >>confdefs.h <<_ACEOF #define `$as_echo "HAVE_$ac_header" | $as_tr_cpp` 1 _ACEOF else as_fn_error $? "header is not found" "$LINENO" 5 fi done TOP=`pwd` # Checking for documentation related programs # Extract the first word of "doxygen", so it can be a program name with args. set dummy doxygen; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if test "${ac_cv_prog_DOXYGEN+set}" = set; then : $as_echo_n "(cached) " >&6 else if test -n "$DOXYGEN"; then ac_cv_prog_DOXYGEN="$DOXYGEN" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then ac_cv_prog_DOXYGEN="doxygen" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi DOXYGEN=$ac_cv_prog_DOXYGEN if test -n "$DOXYGEN"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $DOXYGEN" >&5 $as_echo "$DOXYGEN" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi # Extract the first word of "doxytag", so it can be a program name with args. set dummy doxytag; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if test "${ac_cv_prog_DOXYTAG+set}" = set; then : $as_echo_n "(cached) " >&6 else if test -n "$DOXYTAG"; then ac_cv_prog_DOXYTAG="$DOXYTAG" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then ac_cv_prog_DOXYTAG="doxytag" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi DOXYTAG=$ac_cv_prog_DOXYTAG if test -n "$DOXYTAG"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $DOXYTAG" >&5 $as_echo "$DOXYTAG" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi # Extract the first word of "fig2dev", so it can be a program name with args. set dummy fig2dev; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if test "${ac_cv_prog_FIG2DEV+set}" = set; then : $as_echo_n "(cached) " >&6 else if test -n "$FIG2DEV"; then ac_cv_prog_FIG2DEV="$FIG2DEV" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then ac_cv_prog_FIG2DEV="fig2dev" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi FIG2DEV=$ac_cv_prog_FIG2DEV if test -n "$FIG2DEV"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $FIG2DEV" >&5 $as_echo "$FIG2DEV" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi # Extract the first word of "dot", so it can be a program name with args. set dummy dot; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if test "${ac_cv_prog_HAVE_DOT+set}" = set; then : $as_echo_n "(cached) " >&6 else if test -n "$HAVE_DOT"; then ac_cv_prog_HAVE_DOT="$HAVE_DOT" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then ac_cv_prog_HAVE_DOT=""YES"" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS test -z "$ac_cv_prog_HAVE_DOT" && ac_cv_prog_HAVE_DOT=""NO"" fi fi HAVE_DOT=$ac_cv_prog_HAVE_DOT if test -n "$HAVE_DOT"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $HAVE_DOT" >&5 $as_echo "$HAVE_DOT" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi # Extract the first word of "etags", so it can be a program name with args. set dummy etags; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if test "${ac_cv_prog_ETAGS+set}" = set; then : $as_echo_n "(cached) " >&6 else if test -n "$ETAGS"; then ac_cv_prog_ETAGS="$ETAGS" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then ac_cv_prog_ETAGS=""etags"" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi ETAGS=$ac_cv_prog_ETAGS if test -n "$ETAGS"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ETAGS" >&5 $as_echo "$ETAGS" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi # Extract the first word of "ebrowse", so it can be a program name with args. set dummy ebrowse; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if test "${ac_cv_prog_EBROWSE+set}" = set; then : $as_echo_n "(cached) " >&6 else if test -n "$EBROWSE"; then ac_cv_prog_EBROWSE="$EBROWSE" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then ac_cv_prog_EBROWSE=""ebrowse"" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi EBROWSE=$ac_cv_prog_EBROWSE if test -n "$EBROWSE"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $EBROWSE" >&5 $as_echo "$EBROWSE" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi CVC_OUTPUT_FILES="Makefile.local \ LICENSE \ src/cvc3.pc" OTHER_OUTPUT_FILES="bin/unpack \ bin/run_tests \ bin/cvc2smt \ doc/Doxyfile \ doc/Makefile" ac_config_files="$ac_config_files $CVC_OUTPUT_FILES $OTHER_OUTPUT_FILES" cat >confcache <<\_ACEOF # This file is a shell script that caches the results of configure # tests run on this system so they can be shared between configure # scripts and configure runs, see configure's option --config-cache. # It is not useful on other systems. If it contains results you don't # want to keep, you may remove or edit it. # # config.status only pays attention to the cache file if you give it # the --recheck option to rerun configure. # # `ac_cv_env_foo' variables (set or unset) will be overridden when # loading this file, other *unset* `ac_cv_foo' will be assigned the # following values. _ACEOF # The following way of writing the cache mishandles newlines in values, # but we know of no workaround that is simple, portable, and efficient. # So, we kill variables containing newlines. # Ultrix sh set writes to stderr and can't be redirected directly, # and sets the high bit in the cache file unless we assign to the vars. ( for ac_var in `(set) 2>&1 | sed -n 's/^\([a-zA-Z_][a-zA-Z0-9_]*\)=.*/\1/p'`; do eval ac_val=\$$ac_var case $ac_val in #( *${as_nl}*) case $ac_var in #( *_cv_*) { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: cache variable $ac_var contains a newline" >&5 $as_echo "$as_me: WARNING: cache variable $ac_var contains a newline" >&2;} ;; esac case $ac_var in #( _ | IFS | as_nl) ;; #( BASH_ARGV | BASH_SOURCE) eval $ac_var= ;; #( *) { eval $ac_var=; unset $ac_var;} ;; esac ;; esac done (set) 2>&1 | case $as_nl`(ac_space=' '; set) 2>&1` in #( *${as_nl}ac_space=\ *) # `set' does not quote correctly, so add quotes: double-quote # substitution turns \\\\ into \\, and sed turns \\ into \. sed -n \ "s/'/'\\\\''/g; s/^\\([_$as_cr_alnum]*_cv_[_$as_cr_alnum]*\\)=\\(.*\\)/\\1='\\2'/p" ;; #( *) # `set' quotes correctly as required by POSIX, so do not add quotes. sed -n "/^[_$as_cr_alnum]*_cv_[_$as_cr_alnum]*=/p" ;; esac | sort ) | sed ' /^ac_cv_env_/b end t clear :clear s/^\([^=]*\)=\(.*[{}].*\)$/test "${\1+set}" = set || &/ t end s/^\([^=]*\)=\(.*\)$/\1=${\1=\2}/ :end' >>confcache if diff "$cache_file" confcache >/dev/null 2>&1; then :; else if test -w "$cache_file"; then test "x$cache_file" != "x/dev/null" && { $as_echo "$as_me:${as_lineno-$LINENO}: updating cache $cache_file" >&5 $as_echo "$as_me: updating cache $cache_file" >&6;} cat confcache >$cache_file else { $as_echo "$as_me:${as_lineno-$LINENO}: not updating unwritable cache $cache_file" >&5 $as_echo "$as_me: not updating unwritable cache $cache_file" >&6;} fi fi rm -f confcache test "x$prefix" = xNONE && prefix=$ac_default_prefix # Let make expand exec_prefix. test "x$exec_prefix" = xNONE && exec_prefix='${prefix}' # Transform confdefs.h into DEFS. # Protect against shell expansion while executing Makefile rules. # Protect against Makefile macro expansion. # # If the first sed substitution is executed (which looks for macros that # take arguments), then branch to the quote section. Otherwise, # look for a macro that doesn't take arguments. ac_script=' :mline /\\$/{ N s,\\\n,, b mline } t clear :clear s/^[ ]*#[ ]*define[ ][ ]*\([^ (][^ (]*([^)]*)\)[ ]*\(.*\)/-D\1=\2/g t quote s/^[ ]*#[ ]*define[ ][ ]*\([^ ][^ ]*\)[ ]*\(.*\)/-D\1=\2/g t quote b any :quote s/[ `~#$^&*(){}\\|;'\''"<>?]/\\&/g s/\[/\\&/g s/\]/\\&/g s/\$/$$/g H :any ${ g s/^\n// s/\n/ /g p } ' DEFS=`sed -n "$ac_script" confdefs.h` ac_libobjs= ac_ltlibobjs= U= for ac_i in : $LIBOBJS; do test "x$ac_i" = x: && continue # 1. Remove the extension, and $U if already installed. ac_script='s/\$U\././;s/\.o$//;s/\.obj$//' ac_i=`$as_echo "$ac_i" | sed "$ac_script"` # 2. Prepend LIBOBJDIR. When used with automake>=1.10 LIBOBJDIR # will be set to the directory where LIBOBJS objects are built. as_fn_append ac_libobjs " \${LIBOBJDIR}$ac_i\$U.$ac_objext" as_fn_append ac_ltlibobjs " \${LIBOBJDIR}$ac_i"'$U.lo' done LIBOBJS=$ac_libobjs LTLIBOBJS=$ac_ltlibobjs : ${CONFIG_STATUS=./config.status} ac_write_fail=0 ac_clean_files_save=$ac_clean_files ac_clean_files="$ac_clean_files $CONFIG_STATUS" { $as_echo "$as_me:${as_lineno-$LINENO}: creating $CONFIG_STATUS" >&5 $as_echo "$as_me: creating $CONFIG_STATUS" >&6;} as_write_fail=0 cat >$CONFIG_STATUS <<_ASEOF || as_write_fail=1 #! $SHELL # Generated by $as_me. # Run this file to recreate the current configuration. # Compiler output produced by configure, useful for debugging # configure, is in config.log if it exists. debug=false ac_cs_recheck=false ac_cs_silent=false SHELL=\${CONFIG_SHELL-$SHELL} export SHELL _ASEOF cat >>$CONFIG_STATUS <<\_ASEOF || as_write_fail=1 ## -------------------- ## ## M4sh Initialization. ## ## -------------------- ## # Be more Bourne compatible DUALCASE=1; export DUALCASE # for MKS sh if test -n "${ZSH_VERSION+set}" && (emulate sh) >/dev/null 2>&1; then : emulate sh NULLCMD=: # Pre-4.2 versions of Zsh do word splitting on ${1+"$@"}, which # is contrary to our usage. Disable this feature. alias -g '${1+"$@"}'='"$@"' setopt NO_GLOB_SUBST else case `(set -o) 2>/dev/null` in #( *posix*) : set -o posix ;; #( *) : ;; esac fi as_nl=' ' export as_nl # Printing a long string crashes Solaris 7 /usr/bin/printf. as_echo='\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\' as_echo=$as_echo$as_echo$as_echo$as_echo$as_echo as_echo=$as_echo$as_echo$as_echo$as_echo$as_echo$as_echo # Prefer a ksh shell builtin over an external printf program on Solaris, # but without wasting forks for bash or zsh. if test -z "$BASH_VERSION$ZSH_VERSION" \ && (test "X`print -r -- $as_echo`" = "X$as_echo") 2>/dev/null; then as_echo='print -r --' as_echo_n='print -rn --' elif (test "X`printf %s $as_echo`" = "X$as_echo") 2>/dev/null; then as_echo='printf %s\n' as_echo_n='printf %s' else if test "X`(/usr/ucb/echo -n -n $as_echo) 2>/dev/null`" = "X-n $as_echo"; then as_echo_body='eval /usr/ucb/echo -n "$1$as_nl"' as_echo_n='/usr/ucb/echo -n' else as_echo_body='eval expr "X$1" : "X\\(.*\\)"' as_echo_n_body='eval arg=$1; case $arg in #( *"$as_nl"*) expr "X$arg" : "X\\(.*\\)$as_nl"; arg=`expr "X$arg" : ".*$as_nl\\(.*\\)"`;; esac; expr "X$arg" : "X\\(.*\\)" | tr -d "$as_nl" ' export as_echo_n_body as_echo_n='sh -c $as_echo_n_body as_echo' fi export as_echo_body as_echo='sh -c $as_echo_body as_echo' fi # The user is always right. if test "${PATH_SEPARATOR+set}" != set; then PATH_SEPARATOR=: (PATH='/bin;/bin'; FPATH=$PATH; sh -c :) >/dev/null 2>&1 && { (PATH='/bin:/bin'; FPATH=$PATH; sh -c :) >/dev/null 2>&1 || PATH_SEPARATOR=';' } fi # IFS # We need space, tab and new line, in precisely that order. Quoting is # there to prevent editors from complaining about space-tab. # (If _AS_PATH_WALK were called with IFS unset, it would disable word # splitting by setting IFS to empty value.) IFS=" "" $as_nl" # Find who we are. Look in the path if we contain no directory separator. case $0 in #(( *[\\/]* ) as_myself=$0 ;; *) as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. test -r "$as_dir/$0" && as_myself=$as_dir/$0 && break done IFS=$as_save_IFS ;; esac # We did not find ourselves, most probably we were run as `sh COMMAND' # in which case we are not to be found in the path. if test "x$as_myself" = x; then as_myself=$0 fi if test ! -f "$as_myself"; then $as_echo "$as_myself: error: cannot find myself; rerun with an absolute file name" >&2 exit 1 fi # Unset variables that we do not need and which cause bugs (e.g. in # pre-3.0 UWIN ksh). But do not cause bugs in bash 2.01; the "|| exit 1" # suppresses any "Segmentation fault" message there. '((' could # trigger a bug in pdksh 5.2.14. for as_var in BASH_ENV ENV MAIL MAILPATH do eval test x\${$as_var+set} = xset \ && ( (unset $as_var) || exit 1) >/dev/null 2>&1 && unset $as_var || : done PS1='$ ' PS2='> ' PS4='+ ' # NLS nuisances. LC_ALL=C export LC_ALL LANGUAGE=C export LANGUAGE # CDPATH. (unset CDPATH) >/dev/null 2>&1 && unset CDPATH # as_fn_error STATUS ERROR [LINENO LOG_FD] # ---------------------------------------- # Output "`basename $0`: error: ERROR" to stderr. If LINENO and LOG_FD are # provided, also output the error to LOG_FD, referencing LINENO. Then exit the # script with STATUS, using 1 if that was 0. as_fn_error () { as_status=$1; test $as_status -eq 0 && as_status=1 if test "$4"; then as_lineno=${as_lineno-"$3"} as_lineno_stack=as_lineno_stack=$as_lineno_stack $as_echo "$as_me:${as_lineno-$LINENO}: error: $2" >&$4 fi $as_echo "$as_me: error: $2" >&2 as_fn_exit $as_status } # as_fn_error # as_fn_set_status STATUS # ----------------------- # Set $? to STATUS, without forking. as_fn_set_status () { return $1 } # as_fn_set_status # as_fn_exit STATUS # ----------------- # Exit the shell with STATUS, even in a "trap 0" or "set -e" context. as_fn_exit () { set +e as_fn_set_status $1 exit $1 } # as_fn_exit # as_fn_unset VAR # --------------- # Portably unset VAR. as_fn_unset () { { eval $1=; unset $1;} } as_unset=as_fn_unset # as_fn_append VAR VALUE # ---------------------- # Append the text in VALUE to the end of the definition contained in VAR. Take # advantage of any shell optimizations that allow amortized linear growth over # repeated appends, instead of the typical quadratic growth present in naive # implementations. if (eval "as_var=1; as_var+=2; test x\$as_var = x12") 2>/dev/null; then : eval 'as_fn_append () { eval $1+=\$2 }' else as_fn_append () { eval $1=\$$1\$2 } fi # as_fn_append # as_fn_arith ARG... # ------------------ # Perform arithmetic evaluation on the ARGs, and store the result in the # global $as_val. Take advantage of shells that can avoid forks. The arguments # must be portable across $(()) and expr. if (eval "test \$(( 1 + 1 )) = 2") 2>/dev/null; then : eval 'as_fn_arith () { as_val=$(( $* )) }' else as_fn_arith () { as_val=`expr "$@" || test $? -eq 1` } fi # as_fn_arith if expr a : '\(a\)' >/dev/null 2>&1 && test "X`expr 00001 : '.*\(...\)'`" = X001; then as_expr=expr else as_expr=false fi if (basename -- /) >/dev/null 2>&1 && test "X`basename -- / 2>&1`" = "X/"; then as_basename=basename else as_basename=false fi if (as_dir=`dirname -- /` && test "X$as_dir" = X/) >/dev/null 2>&1; then as_dirname=dirname else as_dirname=false fi as_me=`$as_basename -- "$0" || $as_expr X/"$0" : '.*/\([^/][^/]*\)/*$' \| \ X"$0" : 'X\(//\)$' \| \ X"$0" : 'X\(/\)' \| . 2>/dev/null || $as_echo X/"$0" | sed '/^.*\/\([^/][^/]*\)\/*$/{ s//\1/ q } /^X\/\(\/\/\)$/{ s//\1/ q } /^X\/\(\/\).*/{ s//\1/ q } s/.*/./; q'` # Avoid depending upon Character Ranges. as_cr_letters='abcdefghijklmnopqrstuvwxyz' as_cr_LETTERS='ABCDEFGHIJKLMNOPQRSTUVWXYZ' as_cr_Letters=$as_cr_letters$as_cr_LETTERS as_cr_digits='0123456789' as_cr_alnum=$as_cr_Letters$as_cr_digits ECHO_C= ECHO_N= ECHO_T= case `echo -n x` in #((((( -n*) case `echo 'xy\c'` in *c*) ECHO_T=' ';; # ECHO_T is single tab character. xy) ECHO_C='\c';; *) echo `echo ksh88 bug on AIX 6.1` > /dev/null ECHO_T=' ';; esac;; *) ECHO_N='-n';; esac rm -f conf$$ conf$$.exe conf$$.file if test -d conf$$.dir; then rm -f conf$$.dir/conf$$.file else rm -f conf$$.dir mkdir conf$$.dir 2>/dev/null fi if (echo >conf$$.file) 2>/dev/null; then if ln -s conf$$.file conf$$ 2>/dev/null; then as_ln_s='ln -s' # ... but there are two gotchas: # 1) On MSYS, both `ln -s file dir' and `ln file dir' fail. # 2) DJGPP < 2.04 has no symlinks; `ln -s' creates a wrapper executable. # In both cases, we have to default to `cp -p'. ln -s conf$$.file conf$$.dir 2>/dev/null && test ! -f conf$$.exe || as_ln_s='cp -p' elif ln conf$$.file conf$$ 2>/dev/null; then as_ln_s=ln else as_ln_s='cp -p' fi else as_ln_s='cp -p' fi rm -f conf$$ conf$$.exe conf$$.dir/conf$$.file conf$$.file rmdir conf$$.dir 2>/dev/null # as_fn_mkdir_p # ------------- # Create "$as_dir" as a directory, including parents if necessary. as_fn_mkdir_p () { case $as_dir in #( -*) as_dir=./$as_dir;; esac test -d "$as_dir" || eval $as_mkdir_p || { as_dirs= while :; do case $as_dir in #( *\'*) as_qdir=`$as_echo "$as_dir" | sed "s/'/'\\\\\\\\''/g"`;; #'( *) as_qdir=$as_dir;; esac as_dirs="'$as_qdir' $as_dirs" as_dir=`$as_dirname -- "$as_dir" || $as_expr X"$as_dir" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ X"$as_dir" : 'X\(//\)[^/]' \| \ X"$as_dir" : 'X\(//\)$' \| \ X"$as_dir" : 'X\(/\)' \| . 2>/dev/null || $as_echo X"$as_dir" | sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ s//\1/ q } /^X\(\/\/\)[^/].*/{ s//\1/ q } /^X\(\/\/\)$/{ s//\1/ q } /^X\(\/\).*/{ s//\1/ q } s/.*/./; q'` test -d "$as_dir" && break done test -z "$as_dirs" || eval "mkdir $as_dirs" } || test -d "$as_dir" || as_fn_error $? "cannot create directory $as_dir" } # as_fn_mkdir_p if mkdir -p . 2>/dev/null; then as_mkdir_p='mkdir -p "$as_dir"' else test -d ./-p && rmdir ./-p as_mkdir_p=false fi if test -x / >/dev/null 2>&1; then as_test_x='test -x' else if ls -dL / >/dev/null 2>&1; then as_ls_L_option=L else as_ls_L_option= fi as_test_x=' eval sh -c '\'' if test -d "$1"; then test -d "$1/."; else case $1 in #( -*)set "./$1";; esac; case `ls -ld'$as_ls_L_option' "$1" 2>/dev/null` in #(( ???[sx]*):;;*)false;;esac;fi '\'' sh ' fi as_executable_p=$as_test_x # Sed expression to map a string onto a valid CPP name. as_tr_cpp="eval sed 'y%*$as_cr_letters%P$as_cr_LETTERS%;s%[^_$as_cr_alnum]%_%g'" # Sed expression to map a string onto a valid variable name. as_tr_sh="eval sed 'y%*+%pp%;s%[^_$as_cr_alnum]%_%g'" exec 6>&1 ## ----------------------------------- ## ## Main body of $CONFIG_STATUS script. ## ## ----------------------------------- ## _ASEOF test $as_write_fail = 0 && chmod +x $CONFIG_STATUS || ac_write_fail=1 cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 # Save the log message, to keep $0 and so on meaningful, and to # report actual input values of CONFIG_FILES etc. instead of their # values after options handling. ac_log=" This file was extended by cvc3 $as_me 2.4.1, which was generated by GNU Autoconf 2.67. Invocation command line was CONFIG_FILES = $CONFIG_FILES CONFIG_HEADERS = $CONFIG_HEADERS CONFIG_LINKS = $CONFIG_LINKS CONFIG_COMMANDS = $CONFIG_COMMANDS $ $0 $@ on `(hostname || uname -n) 2>/dev/null | sed 1q` " _ACEOF case $ac_config_files in *" "*) set x $ac_config_files; shift; ac_config_files=$*;; esac cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 # Files that config.status was made for. config_files="$ac_config_files" _ACEOF cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 ac_cs_usage="\ \`$as_me' instantiates files and other configuration actions from templates according to the current configuration. Unless the files and actions are specified as TAGs, all are instantiated by default. Usage: $0 [OPTION]... [TAG]... -h, --help print this help, then exit -V, --version print version number and configuration settings, then exit --config print configuration, then exit -q, --quiet, --silent do not print progress messages -d, --debug don't remove temporary files --recheck update $as_me by reconfiguring in the same conditions --file=FILE[:TEMPLATE] instantiate the configuration file FILE Configuration files: $config_files Report bugs to the package provider." _ACEOF cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 ac_cs_config="`$as_echo "$ac_configure_args" | sed 's/^ //; s/[\\""\`\$]/\\\\&/g'`" ac_cs_version="\\ cvc3 config.status 2.4.1 configured by $0, generated by GNU Autoconf 2.67, with options \\"\$ac_cs_config\\" Copyright (C) 2010 Free Software Foundation, Inc. This config.status script is free software; the Free Software Foundation gives unlimited permission to copy, distribute and modify it." ac_pwd='$ac_pwd' srcdir='$srcdir' test -n "\$AWK" || AWK=awk _ACEOF cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 # The default lists apply if the user does not specify any file. ac_need_defaults=: while test $# != 0 do case $1 in --*=?*) ac_option=`expr "X$1" : 'X\([^=]*\)='` ac_optarg=`expr "X$1" : 'X[^=]*=\(.*\)'` ac_shift=: ;; --*=) ac_option=`expr "X$1" : 'X\([^=]*\)='` ac_optarg= ac_shift=: ;; *) ac_option=$1 ac_optarg=$2 ac_shift=shift ;; esac case $ac_option in # Handling of the options. -recheck | --recheck | --rechec | --reche | --rech | --rec | --re | --r) ac_cs_recheck=: ;; --version | --versio | --versi | --vers | --ver | --ve | --v | -V ) $as_echo "$ac_cs_version"; exit ;; --config | --confi | --conf | --con | --co | --c ) $as_echo "$ac_cs_config"; exit ;; --debug | --debu | --deb | --de | --d | -d ) debug=: ;; --file | --fil | --fi | --f ) $ac_shift case $ac_optarg in *\'*) ac_optarg=`$as_echo "$ac_optarg" | sed "s/'/'\\\\\\\\''/g"` ;; '') as_fn_error $? "missing file argument" ;; esac as_fn_append CONFIG_FILES " '$ac_optarg'" ac_need_defaults=false;; --he | --h | --help | --hel | -h ) $as_echo "$ac_cs_usage"; exit ;; -q | -quiet | --quiet | --quie | --qui | --qu | --q \ | -silent | --silent | --silen | --sile | --sil | --si | --s) ac_cs_silent=: ;; # This is an error. -*) as_fn_error $? "unrecognized option: \`$1' Try \`$0 --help' for more information." ;; *) as_fn_append ac_config_targets " $1" ac_need_defaults=false ;; esac shift done ac_configure_extra_args= if $ac_cs_silent; then exec 6>/dev/null ac_configure_extra_args="$ac_configure_extra_args --silent" fi _ACEOF cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 if \$ac_cs_recheck; then set X '$SHELL' '$0' $ac_configure_args \$ac_configure_extra_args --no-create --no-recursion shift \$as_echo "running CONFIG_SHELL=$SHELL \$*" >&6 CONFIG_SHELL='$SHELL' export CONFIG_SHELL exec "\$@" fi _ACEOF cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 exec 5>>config.log { echo sed 'h;s/./-/g;s/^.../## /;s/...$/ ##/;p;x;p;x' <<_ASBOX ## Running $as_me. ## _ASBOX $as_echo "$ac_log" } >&5 _ACEOF cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 _ACEOF cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 # Handling of arguments. for ac_config_target in $ac_config_targets do case $ac_config_target in "$CVC_OUTPUT_FILES") CONFIG_FILES="$CONFIG_FILES $CVC_OUTPUT_FILES" ;; "$OTHER_OUTPUT_FILES") CONFIG_FILES="$CONFIG_FILES $OTHER_OUTPUT_FILES" ;; *) as_fn_error $? "invalid argument: \`$ac_config_target'" "$LINENO" 5 ;; esac done # If the user did not use the arguments to specify the items to instantiate, # then the envvar interface is used. Set only those that are not. # We use the long form for the default assignment because of an extremely # bizarre bug on SunOS 4.1.3. if $ac_need_defaults; then test "${CONFIG_FILES+set}" = set || CONFIG_FILES=$config_files fi # Have a temporary directory for convenience. Make it in the build tree # simply because there is no reason against having it here, and in addition, # creating and moving files from /tmp can sometimes cause problems. # Hook for its removal unless debugging. # Note that there is a small window in which the directory will not be cleaned: # after its creation but before its name has been assigned to `$tmp'. $debug || { tmp= trap 'exit_status=$? { test -z "$tmp" || test ! -d "$tmp" || rm -fr "$tmp"; } && exit $exit_status ' 0 trap 'as_fn_exit 1' 1 2 13 15 } # Create a (secure) tmp directory for tmp files. { tmp=`(umask 077 && mktemp -d "./confXXXXXX") 2>/dev/null` && test -n "$tmp" && test -d "$tmp" } || { tmp=./conf$$-$RANDOM (umask 077 && mkdir "$tmp") } || as_fn_error $? "cannot create a temporary directory in ." "$LINENO" 5 # Set up the scripts for CONFIG_FILES section. # No need to generate them if there are no CONFIG_FILES. # This happens for instance with `./config.status config.h'. if test -n "$CONFIG_FILES"; then if $AWK 'BEGIN { getline <"/dev/null" }' /dev/null; then ac_cs_awk_getline=: ac_cs_awk_pipe_init= ac_cs_awk_read_file=' while ((getline aline < (F[key])) > 0) print(aline) close(F[key])' ac_cs_awk_pipe_fini= else ac_cs_awk_getline=false ac_cs_awk_pipe_init="print \"cat <<'|#_!!_#|' &&\"" ac_cs_awk_read_file=' print "|#_!!_#|" print "cat " F[key] " &&" '$ac_cs_awk_pipe_init # The final `:' finishes the AND list. ac_cs_awk_pipe_fini='END { print "|#_!!_#|"; print ":" }' fi ac_cr=`echo X | tr X '\015'` # On cygwin, bash can eat \r inside `` if the user requested igncr. # But we know of no other shell where ac_cr would be empty at this # point, so we can use a bashism as a fallback. if test "x$ac_cr" = x; then eval ac_cr=\$\'\\r\' fi ac_cs_awk_cr=`$AWK 'BEGIN { print "a\rb" }' /dev/null` if test "$ac_cs_awk_cr" = "a${ac_cr}b"; then ac_cs_awk_cr='\\r' else ac_cs_awk_cr=$ac_cr fi echo 'BEGIN {' >"$tmp/subs1.awk" && _ACEOF # Create commands to substitute file output variables. { echo "cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1" && echo 'cat >>"\$tmp/subs1.awk" <<\\_ACAWK &&' && echo "$ac_subst_files" | sed 's/.*/F["&"]="$&"/' && echo "_ACAWK" && echo "_ACEOF" } >conf$$files.sh && . ./conf$$files.sh || as_fn_error $? "could not make $CONFIG_STATUS" "$LINENO" 5 rm -f conf$$files.sh { echo "cat >conf$$subs.awk <<_ACEOF" && echo "$ac_subst_vars" | sed 's/.*/&!$&$ac_delim/' && echo "_ACEOF" } >conf$$subs.sh || as_fn_error $? "could not make $CONFIG_STATUS" "$LINENO" 5 ac_delim_num=`echo "$ac_subst_vars" | grep -c '^'` ac_delim='%!_!# ' for ac_last_try in false false false false false :; do . ./conf$$subs.sh || as_fn_error $? "could not make $CONFIG_STATUS" "$LINENO" 5 ac_delim_n=`sed -n "s/.*$ac_delim\$/X/p" conf$$subs.awk | grep -c X` if test $ac_delim_n = $ac_delim_num; then break elif $ac_last_try; then as_fn_error $? "could not make $CONFIG_STATUS" "$LINENO" 5 else ac_delim="$ac_delim!$ac_delim _$ac_delim!! " fi done rm -f conf$$subs.sh cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 cat >>"\$tmp/subs1.awk" <<\\_ACAWK && _ACEOF sed -n ' h s/^/S["/; s/!.*/"]=/ p g s/^[^!]*!// :repl t repl s/'"$ac_delim"'$// t delim :nl h s/\(.\{148\}\)..*/\1/ t more1 s/["\\]/\\&/g; s/^/"/; s/$/\\n"\\/ p n b repl :more1 s/["\\]/\\&/g; s/^/"/; s/$/"\\/ p g s/.\{148\}// t nl :delim h s/\(.\{148\}\)..*/\1/ t more2 s/["\\]/\\&/g; s/^/"/; s/$/"/ p b :more2 s/["\\]/\\&/g; s/^/"/; s/$/"\\/ p g s/.\{148\}// t delim ' >$CONFIG_STATUS || ac_write_fail=1 rm -f conf$$subs.awk cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 _ACAWK cat >>"\$tmp/subs1.awk" <<_ACAWK && for (key in S) S_is_set[key] = 1 FS = "" \$ac_cs_awk_pipe_init } { line = $ 0 nfields = split(line, field, "@") substed = 0 len = length(field[1]) for (i = 2; i < nfields; i++) { key = field[i] keylen = length(key) if (S_is_set[key]) { value = S[key] line = substr(line, 1, len) "" value "" substr(line, len + keylen + 3) len += length(value) + length(field[++i]) substed = 1 } else len += 1 + keylen } if (nfields == 3 && !substed) { key = field[2] if (F[key] != "" && line ~ /^[ ]*@.*@[ ]*$/) { \$ac_cs_awk_read_file next } } print line } \$ac_cs_awk_pipe_fini _ACAWK _ACEOF cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 if sed "s/$ac_cr//" < /dev/null > /dev/null 2>&1; then sed "s/$ac_cr\$//; s/$ac_cr/$ac_cs_awk_cr/g" else cat fi < "$tmp/subs1.awk" > "$tmp/subs.awk" \ || as_fn_error $? "could not setup config files machinery" "$LINENO" 5 _ACEOF # VPATH may cause trouble with some makes, so we remove sole $(srcdir), # ${srcdir} and @srcdir@ entries from VPATH if srcdir is ".", strip leading and # trailing colons and then remove the whole line if VPATH becomes empty # (actually we leave an empty line to preserve line numbers). if test "x$srcdir" = x.; then ac_vpsub='/^[ ]*VPATH[ ]*=[ ]*/{ h s/// s/^/:/ s/[ ]*$/:/ s/:\$(srcdir):/:/g s/:\${srcdir}:/:/g s/:@srcdir@:/:/g s/^:*// s/:*$// x s/\(=[ ]*\).*/\1/ G s/\n// s/^[^=]*=[ ]*$// }' fi cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 fi # test -n "$CONFIG_FILES" eval set X " :F $CONFIG_FILES " shift for ac_tag do case $ac_tag in :[FHLC]) ac_mode=$ac_tag; continue;; esac case $ac_mode$ac_tag in :[FHL]*:*);; :L* | :C*:*) as_fn_error $? "invalid tag \`$ac_tag'" "$LINENO" 5 ;; :[FH]-) ac_tag=-:-;; :[FH]*) ac_tag=$ac_tag:$ac_tag.in;; esac ac_save_IFS=$IFS IFS=: set x $ac_tag IFS=$ac_save_IFS shift ac_file=$1 shift case $ac_mode in :L) ac_source=$1;; :[FH]) ac_file_inputs= for ac_f do case $ac_f in -) ac_f="$tmp/stdin";; *) # Look for the file first in the build tree, then in the source tree # (if the path is not absolute). The absolute path cannot be DOS-style, # because $ac_f cannot contain `:'. test -f "$ac_f" || case $ac_f in [\\/$]*) false;; *) test -f "$srcdir/$ac_f" && ac_f="$srcdir/$ac_f";; esac || as_fn_error 1 "cannot find input file: \`$ac_f'" "$LINENO" 5 ;; esac case $ac_f in *\'*) ac_f=`$as_echo "$ac_f" | sed "s/'/'\\\\\\\\''/g"`;; esac as_fn_append ac_file_inputs " '$ac_f'" done # Let's still pretend it is `configure' which instantiates (i.e., don't # use $as_me), people would be surprised to read: # /* config.h. Generated by config.status. */ configure_input='Generated from '` $as_echo "$*" | sed 's|^[^:]*/||;s|:[^:]*/|, |g' `' by configure.' if test x"$ac_file" != x-; then configure_input="$ac_file. $configure_input" { $as_echo "$as_me:${as_lineno-$LINENO}: creating $ac_file" >&5 $as_echo "$as_me: creating $ac_file" >&6;} fi # Neutralize special characters interpreted by sed in replacement strings. case $configure_input in #( *\&* | *\|* | *\\* ) ac_sed_conf_input=`$as_echo "$configure_input" | sed 's/[\\\\&|]/\\\\&/g'`;; #( *) ac_sed_conf_input=$configure_input;; esac case $ac_tag in *:-:* | *:-) cat >"$tmp/stdin" \ || as_fn_error $? "could not create $ac_file" "$LINENO" 5 ;; esac ;; esac ac_dir=`$as_dirname -- "$ac_file" || $as_expr X"$ac_file" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ X"$ac_file" : 'X\(//\)[^/]' \| \ X"$ac_file" : 'X\(//\)$' \| \ X"$ac_file" : 'X\(/\)' \| . 2>/dev/null || $as_echo X"$ac_file" | sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ s//\1/ q } /^X\(\/\/\)[^/].*/{ s//\1/ q } /^X\(\/\/\)$/{ s//\1/ q } /^X\(\/\).*/{ s//\1/ q } s/.*/./; q'` as_dir="$ac_dir"; as_fn_mkdir_p ac_builddir=. case "$ac_dir" in .) ac_dir_suffix= ac_top_builddir_sub=. ac_top_build_prefix= ;; *) ac_dir_suffix=/`$as_echo "$ac_dir" | sed 's|^\.[\\/]||'` # A ".." for each directory in $ac_dir_suffix. ac_top_builddir_sub=`$as_echo "$ac_dir_suffix" | sed 's|/[^\\/]*|/..|g;s|/||'` case $ac_top_builddir_sub in "") ac_top_builddir_sub=. ac_top_build_prefix= ;; *) ac_top_build_prefix=$ac_top_builddir_sub/ ;; esac ;; esac ac_abs_top_builddir=$ac_pwd ac_abs_builddir=$ac_pwd$ac_dir_suffix # for backward compatibility: ac_top_builddir=$ac_top_build_prefix case $srcdir in .) # We are building in place. ac_srcdir=. ac_top_srcdir=$ac_top_builddir_sub ac_abs_top_srcdir=$ac_pwd ;; [\\/]* | ?:[\\/]* ) # Absolute name. ac_srcdir=$srcdir$ac_dir_suffix; ac_top_srcdir=$srcdir ac_abs_top_srcdir=$srcdir ;; *) # Relative name. ac_srcdir=$ac_top_build_prefix$srcdir$ac_dir_suffix ac_top_srcdir=$ac_top_build_prefix$srcdir ac_abs_top_srcdir=$ac_pwd/$srcdir ;; esac ac_abs_srcdir=$ac_abs_top_srcdir$ac_dir_suffix case $ac_mode in :F) # # CONFIG_FILE # _ACEOF cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 # If the template does not know about datarootdir, expand it. # FIXME: This hack should be removed a few years after 2.60. ac_datarootdir_hack=; ac_datarootdir_seen= ac_sed_dataroot=' /datarootdir/ { p q } /@datadir@/p /@docdir@/p /@infodir@/p /@localedir@/p /@mandir@/p' case `eval "sed -n \"\$ac_sed_dataroot\" $ac_file_inputs"` in *datarootdir*) ac_datarootdir_seen=yes;; *@datadir@*|*@docdir@*|*@infodir@*|*@localedir@*|*@mandir@*) { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $ac_file_inputs seems to ignore the --datarootdir setting" >&5 $as_echo "$as_me: WARNING: $ac_file_inputs seems to ignore the --datarootdir setting" >&2;} _ACEOF cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 ac_datarootdir_hack=' s&@datadir@&$datadir&g s&@docdir@&$docdir&g s&@infodir@&$infodir&g s&@localedir@&$localedir&g s&@mandir@&$mandir&g s&\\\${datarootdir}&$datarootdir&g' ;; esac _ACEOF # Neutralize VPATH when `$srcdir' = `.'. # Shell code in configure.ac might set extrasub. # FIXME: do we really want to maintain this feature? cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 ac_sed_extra="$ac_vpsub $extrasub _ACEOF cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 :t /@[a-zA-Z_][a-zA-Z_0-9]*@/!b s|@configure_input@|$ac_sed_conf_input|;t t s&@top_builddir@&$ac_top_builddir_sub&;t t s&@top_build_prefix@&$ac_top_build_prefix&;t t s&@srcdir@&$ac_srcdir&;t t s&@abs_srcdir@&$ac_abs_srcdir&;t t s&@top_srcdir@&$ac_top_srcdir&;t t s&@abs_top_srcdir@&$ac_abs_top_srcdir&;t t s&@builddir@&$ac_builddir&;t t s&@abs_builddir@&$ac_abs_builddir&;t t s&@abs_top_builddir@&$ac_abs_top_builddir&;t t $ac_datarootdir_hack " eval sed \"\$ac_sed_extra\" "$ac_file_inputs" | if $ac_cs_awk_getline; then $AWK -f "$tmp/subs.awk" else $AWK -f "$tmp/subs.awk" | $SHELL fi >$tmp/out \ || as_fn_error $? "could not create $ac_file" "$LINENO" 5 test -z "$ac_datarootdir_hack$ac_datarootdir_seen" && { ac_out=`sed -n '/\${datarootdir}/p' "$tmp/out"`; test -n "$ac_out"; } && { ac_out=`sed -n '/^[ ]*datarootdir[ ]*:*=/p' "$tmp/out"`; test -z "$ac_out"; } && { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $ac_file contains a reference to the variable \`datarootdir' which seems to be undefined. Please make sure it is defined" >&5 $as_echo "$as_me: WARNING: $ac_file contains a reference to the variable \`datarootdir' which seems to be undefined. Please make sure it is defined" >&2;} rm -f "$tmp/stdin" case $ac_file in -) cat "$tmp/out" && rm -f "$tmp/out";; *) rm -f "$ac_file" && mv "$tmp/out" "$ac_file";; esac \ || as_fn_error $? "could not create $ac_file" "$LINENO" 5 ;; esac done # for ac_tag as_fn_exit 0 _ACEOF ac_clean_files=$ac_clean_files_save test $ac_write_fail = 0 || as_fn_error $? "write failure creating $CONFIG_STATUS" "$LINENO" 5 # configure is writing to config.log, and then calls config.status. # config.status does its own redirection, appending to config.log. # Unfortunately, on DOS this fails, as config.log is still kept open # by configure, so config.status won't be able to write to it; its # output is simply discarded. So we exec the FD to /dev/null, # effectively closing config.log, so it can be properly (re)opened and # appended to by config.status. When coming back to configure, we # need to make the FD available again. if test "$no_create" != yes; then ac_cs_success=: ac_config_status_args= test "$silent" = yes && ac_config_status_args="$ac_config_status_args --quiet" exec 5>/dev/null $SHELL $CONFIG_STATUS $ac_config_status_args || ac_cs_success=false exec 5>>config.log # Use ||, not &&, to avoid exiting from the if with $? = 1, which # would make configure fail if this is the last instruction. $ac_cs_success || as_fn_exit 1 fi if test -n "$ac_unrecognized_opts" && test "$enable_option_checking" != no; then { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: unrecognized options: $ac_unrecognized_opts" >&5 $as_echo "$as_me: WARNING: unrecognized options: $ac_unrecognized_opts" >&2;} fi chmod a+x bin/run_tests chmod a+x bin/cvc2smt chmod a+x bin/unpack opt_arith="$RAITONAL_IMPL" if test "$RATIONAL_IMPL" = "-DRATIONAL_NATIVE"; then opt_arith="native" elif test "$RATIONAL_IMPL" = "-DRATIONAL_GMP"; then opt_arith="GMP" elif test "$RATIONAL_IMPL" = "-DRATIONAL_GMPXX"; then opt_arith="GMP with C++ extensions" fi cat < ;;;; * ;;;; * License to use, copy, modify, sell and/or distribute this software ;;;; * and its documentation for any purpose is hereby granted without ;;;; * royalty, subject to the terms and conditions defined in the \ref ;;;; * LICENSE file provided with this distribution. ;;;; * ;;;; *
;;;; * ;;;; */ ;;;; To use this library, place the following lines into your ~/.emacs file: ;;;; ;;;; ;;; CVC mode ;;;; (autoload 'cvc-mode "cvc-mode" "CVC specifications editing mode." t) ;;;; (setq auto-mode-alist ;;;; (append (list '("\\.cvc$" . cvc-mode)) auto-mode-alist)) ;;;; ;;;; Of course, the file cvc-mode.el must be in one of the directories in your ;;;; `load-path'. C-h v load-path to see the list, or `cons' your own path: ;;;; (setq load-path (cons "/the/full/path/to-your/dir" load-path)) ;;;; ;;;; To turn the font-lock on by default, put in .emacs ;;;; (global-font-lock-mode t) ;; if you use gnu-emacs, or ;;;; (setq-default font-lock-auto-fontify t) ;; if you use xemacs. ;;;; ;;;; In GNU emacs faces `font-lock-preprocessor-face' and ;;;; `font-lock-variable-name-face' may not be predefined. ;;;; In this case they are defined automatically when smv-mode.el ;;;; is loaded the first time. You can also define them yourself in .emacs: ;;;; ;;;; ;;; Make faces that are not in gnu-emacs font-lock by default ;;;; (defvar font-lock-preprocessor-face 'font-lock-preprocessor-face) ;;;; (defvar font-lock-variable-name-face 'font-lock-variable-name-face) ;;;; (make-face 'font-lock-preprocessor-face) ;;;; (make-face 'font-lock-variable-name-face) (require 'font-lock) (require 'compile) (defvar cvc-font-lock-mode-on t "If not nil, turn the fontification on.") (defvar cvc-running-xemacs (string-match "XEmacs\\|Lucid" emacs-version)) ;;;; Syntax definitions (defvar cvc-mode-syntax-table nil "Syntax table used while in CVC mode.") (if cvc-mode-syntax-table () (let ((st (syntax-table))) (unwind-protect (progn (setq cvc-mode-syntax-table (make-syntax-table)) (set-syntax-table cvc-mode-syntax-table) (modify-syntax-entry ?_ "w") (modify-syntax-entry ?- "w") (modify-syntax-entry ?\? "w") (modify-syntax-entry ?: "." ) (modify-syntax-entry ?% "<") (modify-syntax-entry ?\f ">") (modify-syntax-entry ?\n ">")) (set-syntax-table st)))) ;;;; Fontification stuff (defun cvc-keyword-match (keyword) ; "Convert a string into a regexp matching any capitalization of that string." "Convert a string into a regexp matching that string as a separate word." ; (let ((regexp "") ; (index 0) ; (len (length keyword))) ; (while (< index len) ; (let ((c (aref keyword index))) ; (setq regexp ; (concat regexp (format "[%c%c]" (downcase c) (upcase c)))) ; (setq index (+ index 1)))) (format "\\b%s\\b" keyword)) ;) (defvar cvc-font-lock-separator-face 'cvc-font-lock-separator-face) (defvar font-lock-preprocessor-face 'font-lock-preprocessor-face) (defvar font-lock-variable-name-face 'font-lock-variable-name-face) (if (facep 'font-lock-preprocessor-face) () (progn (make-face 'font-lock-preprocessor-face) (set-face-foreground 'font-lock-preprocessor-face "green4"))) (if (facep 'font-lock-variable-name-face) () (progn (make-face 'font-lock-variable-name-face) (set-face-foreground 'font-lock-variable-name-face "deeppink"))) (if (facep 'cvc-font-lock-separator-face) () (progn (make-face 'cvc-font-lock-separator-face) (set-face-foreground 'cvc-font-lock-separator-face "indianred"))) (defvar cvc-mode-hook nil "Functions to run when loading an CVC file.") (defconst cvc-keywords '("ASSERT" "QUERY" "TRACE" "UNTRACE" "OPTION" "HELP" "TRANSFORM" "PRINT" "ECHO" "INCLUDE" "DUMP_ASSUMPTIONS" "DUMP_PROOF" "DUMP_SIG" "WHERE" "COUNTEREXAMPLE" "PUSH" "POP" "POP_SCOPE" "POPTO" "RESET" "CONTEXT" "TYPE" "DATATYPE" "SUBTYPE" "REAL" "INT" "BOOLEAN" "ARRAY" "OF" "TRUE" "FALSE" "FLOOR" "IF" "THEN" "ELSIF" "ELSE" "ENDIF" "LET" "IN" "END" "LAMBDA" "WITH" "FORALL" "EXISTS" "AND" "OR" "XOR" "NOT" ) "The list of CVC keywords.") (defconst cvc-declaration-keywords '("ASSERT" "QUERY" "TRACE" "UNTRACE" "OPTION" "HELP" "TRANSFORM" "PRINT" "ECHO" "INCLUDE" "DUMP_ASSUMPTIONS" "DUMP_PROOF" "DUMP_SIG" "WHERE" "COUNTEREXAMPLE" "PUSH" "POP" "POP_SCOPE" "POPTO" "RESET" "CONTEXT") "The list of keywords that open a declaration. Used for indentation.") (defconst cvc-declaration-regexp (mapconcat 'cvc-keyword-match cvc-declaration-keywords "\\|")) (defconst cvc-opening-keywords '("case" "for" "next" "init" "(") "The list of keywords that open a subexpression. Used for indentation.") (defconst cvc-opening-keywords-regexp (mapconcat 'cvc-keyword-match cvc-opening-keywords "\\|")) (defconst cvc-closing-keywords '("esac" ")") "The list of keywords that close a subexpression. Used for indentation.") (defconst cvc-closing-keywords-regexp (mapconcat 'cvc-keyword-match cvc-closing-keywords "\\|")) (defconst cvc-opening-paren-regexp (concat cvc-opening-keywords-regexp "\\|\\s(")) (defconst cvc-closing-paren-regexp (concat cvc-closing-keywords-regexp "\\|\\s)")) (defconst cvc-infix-operators '("<->" "<-" "->" ":=" "<=w\\>" ">=w\\>" "" ">w\\>" "=w\\>" "+w\\>" "-w\\>" "*w\\>" "<=" ">=" "!=" "=" "\\[" "\\]" "\\b-\\b" "+" "|" "&" "<" ">") "The list of regexps that match CVC infix operators. The distinction is made primarily for indentation purposes.") (defconst cvc-infix-operators-regexp (mapconcat 'identity cvc-infix-operators "\\|")) (defconst cvc-other-operators '("!" "(#" "#)") "Non-infix CVC operators that are not listed in `cvc-infix-operators'.") (defconst cvc-other-operators-regexp (mapconcat 'identity cvc-other-operators "\\|")) (defconst cvc-operators (append cvc-infix-operators cvc-other-operators) "The list of regexps that match CVC operators. It is set to the concatenation of `cvc-infix-operators' and `cvc-other-operators'.") (defconst cvc-separator-regexp "[,.;():]" "A regexp that matches any separator in CVC mode.") (defconst cvc-font-lock-keywords-1 (purecopy (list (list (concat (cvc-keyword-match "MODULE") " *\\([-_?A-Za-z0-9]+\\)") 1 'font-lock-preprocessor-face) (list (concat "\\(" (cvc-keyword-match "init") "\\|" (cvc-keyword-match "next") "\\)(\\s-*\\([][_?.A-Za-z0-9-]+\\)\\s-*)\\s-*:=") 2 'font-lock-variable-name-face) ;;; For DEFINE and invar assignments (list "\\([][_?.A-Za-z0-9-]+\\)\\s-*:=" 1 'font-lock-variable-name-face) (list "\\<\\([Aa]\\|[Ee]\\)\\[" 1 'font-lock-keyword-face) (list (concat "\\(" (mapconcat 'identity cvc-operators "\\|") "\\)") 1 'font-lock-function-name-face 'prepend) (mapconcat 'cvc-keyword-match cvc-keywords "\\|") ;; Fix the `%' comments (list "\\(%.*$\\)" 1 'font-lock-comment-face t) )) "Additional expressions to highlight in CVC mode.") (defconst cvc-font-lock-keywords-2 (purecopy (append cvc-font-lock-keywords-1 (list (list "\\([{}]\\)" 1 'font-lock-type-face) (list (concat "\\(" cvc-separator-regexp "\\)") 1 'cvc-font-lock-separator-face 'prepend)))) "Additional expressions to highlight in CVC mode.") (defconst cvc-font-lock-keywords (if font-lock-maximum-decoration cvc-font-lock-keywords-2 cvc-font-lock-keywords-1)) (defun cvc-minimal-decoration () (interactive) (setq font-lock-keywords cvc-font-lock-keywords-1)) (defun cvc-maximal-decoration () (interactive) (setq font-lock-keywords cvc-font-lock-keywords-2)) ;;;; Running CVC (defvar cvc-command "cvc3" "The command name to run CVC. The default is usually \"cvc3\"") (defvar cvc-sat-option nil "Search Engine choice in CVC. Valid values are nil, \"default\", \"simple\", and \"fast\", or any other values reported by cvc3 -h.") (defvar cvc-trace-flags nil "List of trace flags given on the command line as +trace options") (defvar cvc-verbose-level nil "The verbose mode of CVC. Valid values are nil and \"quiet\". This value is passed to the CVC process as +/-quiet opton.") (defvar cvc-command-line-args nil "Miscellaneous CVC command line args. Must be a single string or nil.") (defvar cvc-compile-buffer nil "The buffer associated with inferior CVC process. This variable is updated automatically each time CVC process takes off.") (defvar cvc-options-changed nil) (defvar cvc-current-buffer nil "The current CVC editing buffer. This variable is buffer-local.") (make-local-variable 'cvc-current-buffer) (defun cvc-args (file &optional args) "Compiles the string of CVC command line args from various variables." (mapconcat 'identity (append (if cvc-sat-option (list "-sat" cvc-sat-option) nil) (if (eq cvc-verbose-level "quiet") (list "+quiet") nil) (mapcar '(lambda (str) (format "+trace \"%s\"" str)) cvc-trace-flags) (if cvc-command-line-args (list cvc-command-line-args)) (if args (list args) nil) (list "<" file)) " ")) (defun cvc-run () "Runs CVC on the current buffer." (interactive) (let ((buffer (current-buffer))) (if (buffer-file-name) (progn (if (buffer-modified-p) (cvc-save-buffer)) (setq cvc-compile-buffer (compile-internal (concat "time " cvc-command " " (cvc-args (buffer-file-name))) "No more errors" "CVC")) (set-buffer cvc-compile-buffer) ;;; Doesn't work??? (end-of-buffer) (set-buffer buffer) ) (error "Buffer does not seem to be associated with any file"))) ) (defun cvc-save-options () "Saves current options in *.opt file." (interactive) (let* ((buffer (current-buffer)) (opt-file-name (let ((match (string-match "\\.cvc$" (buffer-file-name)))) (if match (concat (substring (buffer-file-name) 0 match) ".opt") (concat (buffer-file-name) ".opt")))) (opt-buffer-name (let ((match (string-match "\\.cvc$" (buffer-name)))) (if match (concat (substring (buffer-name) 0 match) ".opt") (concat (buffer-name) ".opt")))) (opt-buffer-exists (get-buffer opt-buffer-name)) (opt-buffer (get-buffer-create opt-buffer-name)) (save-options-from-buffer (and opt-buffer-exists (buffer-modified-p opt-buffer) (y-or-n-p (format "buffer %s is modified. Save options from that buffer?" (buffer-name opt-buffer))))) (options (format ";;;; This file is generated automatically.\n(setq cvc-sat-option %S)\n(setq cvc-verbose-level %S)\n(setq cvc-trace-flags '%S)\n(setq cvc-command-line-args %S)\n" cvc-sat-option cvc-verbose-level cvc-trace-flags cvc-command-line-args))) (set-buffer opt-buffer) (if save-options-from-buffer (cvc-save-and-load-options) (progn (erase-buffer) (insert options) (write-file opt-file-name) (kill-buffer opt-buffer))) (set-buffer buffer) (setq cvc-options-changed nil) (message "Options are saved."))) (defun cvc-save-and-load-options () "Saves the current buffer and updates CVC options in the associated buffer. This buffer is either the value of `cvc-current-buffer', or it tries to make a few reasonable guesses. If no CVC buffer is found, only saves the current buffer. Normally is called from the *.opt file while editing options for CVC specification." (interactive) (let* ((buffer (current-buffer)) (buffer-file (buffer-file-name)) (cvc-buffer-name (let* ((match (string-match "\\.[^.]*$" (buffer-name)))) (if match (concat (substring (buffer-name) 0 match) ".cvc") (concat (buffer-name) ".cvc")))) (cvc-buffer (get-buffer cvc-buffer-name)) (cvc-buffer (cond (cvc-buffer cvc-buffer) ((and (boundp 'cvc-current-buffer) (buffer-live-p cvc-current-buffer)) cvc-current-buffer) (t nil)))) (save-buffer) (if cvc-buffer (let ((cvc-window (get-buffer-window cvc-buffer)) (window (get-buffer-window buffer))) (set-buffer cvc-buffer) (load buffer-file) (setq cvc-current-buffer cvc-buffer) (if cvc-window (select-window cvc-window) (switch-to-buffer cvc-buffer)) (if window (delete-window window)) (setq cvc-options-changed nil)))) ) (defun cvc-save-and-return () "Saves the current buffer and returns back to the associated CVC buffer. The CVC buffer is either the value of `cvc-current-buffer', or it tries to make a few reasonable guesses. If no CVC buffer is found, only saves the current buffer. Normally is called from the *.ord buffer while editing variable ordering for CVC specification. Bound to \\[cvc-save-and-return]" (interactive) (let* ((buffer (current-buffer)) (cvc-buffer-name (let* ((match (string-match "\\.[^.]*$" (buffer-name)))) (if match (concat (substring (buffer-name) 0 match) ".cvc") (concat (buffer-name) ".cvc")))) (cvc-buffer (get-buffer cvc-buffer-name)) (cvc-buffer (cond (cvc-buffer cvc-buffer) ((and (boundp 'cvc-current-buffer) (buffer-live-p cvc-current-buffer)) cvc-current-buffer) (t nil)))) (save-buffer) (if cvc-buffer (let ((cvc-window (get-buffer-window cvc-buffer))) (setq cvc-current-buffer cvc-buffer) (if cvc-window (select-window cvc-window) (switch-to-buffer cvc-buffer)) (if (get-buffer-window buffer) (delete-window (get-buffer-window buffer)))))) ) (defun cvc-edit-options () "Loads current options in a new buffer and lets the user edit it. Run \\[eval-buffer] when done." (interactive) (let* ((buffer (current-buffer)) (opt-buffer-name (let ((match (string-match "\\.cvc$" (buffer-name)))) (if match (concat (substring (buffer-name) 0 match) ".opt") (concat (buffer-name) ".opt")))) (opt-buffer (get-buffer-create opt-buffer-name)) (options (format ";;;; This file is generated automatically.\n(setq cvc-sat-option %S)\n(setq cvc-verbose-level %S)\n(setq cvc-trace-flags '%S)\n(setq cvc-command-line-args %S)\n" cvc-sat-option cvc-verbose-level cvc-trace-flags cvc-command-line-args))) (setq cvc-options-changed t) (switch-to-buffer-other-window opt-buffer) (set-visited-file-name opt-buffer-name) (erase-buffer) (insert options) (make-local-variable 'cvc-currect-buffer) (setq cvc-current-buffer buffer) (cvc-options-edit-mode))) (defun cvc-interrupt () "Kills current CVC process." (interactive) (quit-process (get-buffer-process cvc-compile-buffer) t)) (defun cvc-send-signal (sig) "Sends signal SIG to the CVC process. SIG must be an integer." (if (get-buffer-process cvc-compile-buffer) (if (file-exists-p ".cvc-pid") (save-excursion (let ((buf (get-buffer-create ".cvc-pid"))) (set-buffer buf) (erase-buffer) (insert-file-contents ".cvc-pid") (let ((pid (read buf))) (if (integerp pid) (signal-process pid sig) (error "The file .cvc-pid is screwed up: %s" pid))) (kill-buffer buf))) (error "Your CVC version does not support signal handling")) (error "CVC is not running"))) (defun cvc-send-usr1 () "Sends SIGUSR1 to the current CVC process. I have a version of CVC that uses it to toggle dynamic variable ordering." (interactive) (cvc-send-signal 10)) (defun cvc-send-usr2 () "Sends SIGUSR2 to the current CVC process. I have a version of CVC that uses it to force garbage collection." (interactive) (cvc-send-signal 12)) (defun cvc-set-verbose-level (arg) "Sets CVC verbose level to use in command line option +/-quiet. If empty line is given, use the default." (interactive (list (read-from-minibuffer "Set verbose level to: " cvc-verbose-level))) (if (stringp arg) (progn (if (string= arg "") (setq cvc-verbose-level nil) (setq cvc-verbose-level arg)) (setq cvc-options-changed t)) (error "Not a string. The value is not set."))) (defun cvc-set-command (arg) "Sets the name of the CVC executable to run." (interactive (list (read-file-name "CVC binary: " "" cvc-command nil cvc-command))) (if (stringp arg) (progn (if (string= arg "") nil (setq cvc-command arg)) (setq cvc-options-changed t)) (error "Not a string. The value is not set."))) (defun cvc-trace (arg) "Adds a CVC tracing flag to be given in the +trace command line option." (interactive (list (read-from-minibuffer "Add trace flag: " cvc-verbose-level))) (if (stringp arg) (progn (if (string= arg "") (error "Empty flag is not allowed") (setq cvc-trace-flags (add-to-list 'cvc-trace-flags arg))) (setq cvc-options-changed t) (message "%S" cvc-trace-flags)) (error "Not a string. The value is not set."))) (defun cvc-untrace (arg) "Removes a CVC tracing flag given in the +trace command line option." (interactive (list (completing-read "Remove trace flag: " (mapcar '(lambda (x) (cons x t)) cvc-trace-flags) nil t))) (if (stringp arg) (progn (if (string= arg "") nil ; don't do anything on empty input (setq cvc-trace-flags (delete arg cvc-trace-flags))) (setq cvc-options-changed t) (message "%S" cvc-trace-flags)) (error "Not a string. The value is not set."))) (defun cvc-set-command-line-args (arg) "Sets CVC command line options. Don't set -sat and +quiet options here, use corresponding special variables for that." (interactive (list (read-from-minibuffer "Other arguments: " cvc-command-line-args))) (if (stringp arg) (progn (if (string= arg "") (setq cvc-command-line-args nil) (setq cvc-command-line-args arg)) (setq cvc-options-changed t)) (error "Not a string. The value is not set."))) ;;;; Saving file (defun cvc-save-buffer () "Saves CVC file together with options. Prompts the user whether to override the *.opt file if the options have changed." (interactive) (let ((opt-file-name (let ((match (string-match "\\.cvc$" (buffer-file-name)))) (if match (concat (substring (buffer-file-name) 0 match) ".opt") (concat (buffer-file-name) ".opt"))))) (cond ((and (file-exists-p opt-file-name) cvc-options-changed) (if (y-or-n-p "Options have changed. Save them?") (progn (cvc-save-options) (setq cvc-options-changed nil)))) (cvc-options-changed (cvc-save-options) (setq cvc-options-changed nil)))) (save-buffer)) ;;;; Indentation ;; Definitions ;; - A balanced expression is a matching-paren string or a command ;; (with the semicolon serving as the close-paren) ;; - An enclosing expression for line N is a balanced expression that ;; includes the beginning of line N. ;; Indentation rules: ;; - The indentation of the first line of the buffer or a command is 0. ;; - If the current line has the same innermost enclosing expression as ;; the line before it, it has the same indentation as the line before it. ;; - Otherwise, the indentation of a line is cvc-basic-offset to the right ;; of the first character of its innermost enclosing expression. ;; ;; NOTE: In keeping with Emacs terminology, we consider ;; opening/closing keywords and other paired delimiters as "parens." ;; For simplicity's sake, we treat all such delimiters as parens and ;; make no attempt to enforce true matching (e.g., we will treat "( [ ) ]" ;; as a balanced expression). (defcustom cvc-basic-offset 2 "Amount of basic offset used when indenting CVC code.") (defun cvc-previous-line () "Moves the point to the first non-comment non-blank string before the current one and positions the cursor on the first non-blank character. Returns nil if there is no previous non-comment non-blank line in the buffer." (interactive) (beginning-of-line) (skip-chars-forward " \t") (let ((starting-point (point))) (forward-line -1) (beginning-of-line) (while (and (not (bobp)) (looking-at "\\s-*\\(?:$\\|%\\)")) (forward-line -1) (beginning-of-line)) (cond ((bobp) (goto-char starting-point) nil) (t (skip-chars-forward " \t"))))) (defun cvc-goto-indentation-anchor () "Moves the point to the \"indentation anchor\" of the current line, i.e., the beginning of the innermost enclosing expression or command." (let ((starting-point ;; Find the beginning of the enclosing declaration (save-excursion (while (and (cvc-previous-line) (not (looking-at cvc-declaration-regexp)))) (point))) (depth 1)) (while (and (> depth 0) (search-backward-regexp (concat cvc-opening-paren-regexp "\\|" cvc-closing-paren-regexp) starting-point t)) (if (looking-at cvc-opening-paren-regexp) (setq depth (1- depth)) (setq depth (1+ depth)))) (if (> depth 0) (goto-char starting-point)))) (defun cvc-current-indentation () "Find the current indentation at point. The current indentation is cvc-basic-offset to the right of where the innermost enclosing expression or command starts, unless the previous line has the same indentation anchor and a customized indentation, in which case the customized indentation is used." (let (anchor anchor-column previous-line previous-anchor previous-column) (save-excursion (cvc-goto-indentation-anchor) (setq anchor (point)) (setq anchor-column (current-column))) (save-excursion (cvc-previous-line) (setq previous-line (point)) (setq previous-column (current-column)) (cvc-goto-indentation-anchor) (setq previous-anchor (point))) (if (and (eq anchor previous-anchor) (not (eq anchor previous-line))) previous-column (+ anchor-column cvc-basic-offset)))) (defun cvc-compute-indentation () "Computes the indentation for the current string based on the previous string." (save-excursion (beginning-of-line) (skip-chars-forward " \t") (if (looking-at cvc-declaration-regexp) 0 (let ((indent (cvc-current-indentation))) (if (looking-at cvc-closing-keywords-regexp) (if (< indent cvc-basic-offset) 0 (- indent cvc-basic-offset)) indent))))) ;; ((or (eq type 'opening) (eq type 'declaration)) ;; (+ indent cvc-basic-offset)) ;; (t indent)))))) (defun cvc-indent-line () "Indent the current line relative to the previous meaningful line." (interactive) (let* ((initial (point)) (final (let ((case-fold-search nil)) (cvc-compute-indentation))) (offset0 (save-excursion (beginning-of-line) (skip-chars-forward " \t") (- initial (point)))) (offset (if (< offset0 0) 0 offset0))) (indent-line-to final) (goto-char (+ (point) offset)))) ;; TODO: What's wrong with M-;? ;;;; Now define the keymap (defconst cvc-mode-map nil "CVC keymap") (if cvc-mode-map () (progn (setq cvc-mode-map (make-sparse-keymap)) (define-key cvc-mode-map [delete] 'backward-delete-char-untabify) (define-key cvc-mode-map [backspace] 'backward-delete-char-untabify) (define-key cvc-mode-map "\C-x\C-s" 'cvc-save-buffer) (define-key cvc-mode-map "\C-c\C-e" 'cvc-edit-options) (define-key cvc-mode-map "\C-c\C-f" 'cvc-run) (define-key cvc-mode-map "\C-c\C-t" 'cvc-trace) (define-key cvc-mode-map "\C-c\C-u" 'cvc-untrace) (define-key cvc-mode-map "\C-c\C-r" 'cvc-set-command) (define-key cvc-mode-map "\C-c\C-c" 'cvc-interrupt) ;; (define-key cvc-mode-map "\C-c\C-r" 'cvc-send-usr1) ;; (define-key cvc-mode-map "\C-c\C-s" 'cvc-send-usr2) (define-key cvc-mode-map "\C-c;" 'comment-region) (define-key cvc-mode-map "\t" 'cvc-indent-line))) (defun cvc-make-local-vars () "Create buffer-local variables for CVC modes" (make-local-variable 'cvc-command) (make-local-variable 'cvc-sat-option) (make-local-variable 'cvc-verbose-level) (make-local-variable 'cvc-trace-flags) (make-local-variable 'cvc-command-line-args) (make-local-variable 'cvc-options-changed) (make-local-variable 'cvc-options-changed)) (defun cvc-mode () "Major mode for CVC specification files. \\{cvc-mode-map} \\[cvc-run] runs CVC on buffer, \\[cvc-interrupt] interrupts already running CVC process. \\[cvc-send-usr1] and \\[cvc-send-usr2] are used to send UNIX signals to CVC process to toggle dynamic variable ordering and force garbage collection respectively. Available only for a new (experimental) CVC version. Running CVC (\\[cvc-run]) creates a separate buffer where inferior CVC process will leave its output. Currently, each run of CVC clears the compilation buffer. If you need to save multiple runs, save them one at a time. Please report bugs to barrett@cs.nyu.edu." (interactive) (use-local-map cvc-mode-map) ;;; Disable asking for the compile command (make-local-variable 'compilation-read-command) (setq compilation-read-command nil) ;;; Make all the variables with CVC options local to the current buffer (cvc-make-local-vars) (setq cvc-options-changed nil) ;;; Change the regexp search to be case sensitive ;; (setq case-fold-search nil) ;;; Set syntax table (set-syntax-table cvc-mode-syntax-table) ;; fix up comment handling (set (make-local-variable 'comment-start) "%") (set (make-local-variable 'comment-end) "") (set (make-local-variable 'comment-start-skip) "%+\\s-*") (setq require-final-newline t) (set (make-local-variable 'indent-line-function) 'cvc-indent-line) ;;; Define the major mode (setq major-mode 'cvc-mode) (setq mode-name "CVC") ;;; Load command line options for CVC process (let ((opt-file-name (let ((match (string-match "\\.cvc$" (buffer-file-name)))) (if match (concat (substring (buffer-file-name) 0 match) ".opt") (concat (buffer-file-name) ".opt"))))) (if (file-exists-p opt-file-name) (load opt-file-name))) ;;; Do fontification, if necessary (setq font-lock-keywords (if font-lock-maximum-decoration cvc-font-lock-keywords-2 cvc-font-lock-keywords-1)) (if cvc-running-xemacs (put 'cvc-mode 'font-lock-defaults '(cvc-font-lock-keywords nil nil nil nil)) (setq font-lock-defaults '(cvc-font-lock-keywords nil nil nil nil))) (if (and cvc-font-lock-mode-on (or cvc-running-xemacs font-lock-global-modes) window-system) (font-lock-mode 1)) (setq mode-line-process nil) ; put 'cvc-status when hooked up to inferior CVC (run-hooks 'cvc-mode-hook)) (defun cvc-options-edit-mode () "Major mode for editing CVC options. Actually, this is Emacs Lisp mode with a few changes. In particular, \\[cvc-save-and-load-options] will save the file, find the associated CVC file and updates its options accordingly. See `\\[describe-bindings]' for key bindings. " (interactive) (emacs-lisp-mode) ;;; Make all the variables with CVC options local to the current buffer ;;; to avoid accidental override of the global values (cvc-make-local-vars) (setq major-mode 'cvc-options-edit-mode) (setq mode-name "CVC Options") (if (and cvc-font-lock-mode-on (or cvc-running-xemacs font-lock-global-modes) window-system) (font-lock-mode t)) (use-local-map (copy-keymap (current-local-map))) (local-set-key "\C-c\C-c" 'cvc-save-and-load-options)) (provide 'cvc-mode) cvc3-2.4.1/test/0000775000175400017540000000000011630011320013220 5ustar mdetersmdeterscvc3-2.4.1/test/Makefile0000664000175400017540000000070210560433725014701 0ustar mdetersmdeters################################################## # About this Makefile # # This Makefile depends on srcMakefile.opts ################################################## EXECUTABLE=test SRC = main.cpp george.cpp HEADERS = george.h #On some compilers, george.cpp takes forever with -O2 EXTRAFLAGS = -O0 LD_LIBS = -l$(PROJECTNAME) OTHER_DEPENDENCIES = $(TOP)/lib/lib$(PROJECTNAME).$(LIB_SUFFIX) BASE_DIR = $(TOP)/test include ../Makefile.local cvc3-2.4.1/test/george.cpp0000664000175400017540000114503511033570665015230 0ustar mdetersmdeters#include "vc.h" #include #include "exception.h" #include "command_line_flags.h" using namespace std; using namespace CVC3; extern int exitStatus; void testgeorge1() { CLFlags flags = ValidityChecker::createFlags(); flags.setFlag("arith3", true); ValidityChecker *vc = ValidityChecker::create(flags); try { /*************/ vector inconsistency; /*************/ Type id9 = vc->realType(); Type id7 = vc->intType(); Type id11 = vc->boolType(); vc->push(); Expr id13=vc->trueExpr(); Expr id12=vc->notExpr(vc->trueExpr()); Type id19=vc->arrayType(id7,id7); Type id21=vc->arrayType(id7,id9); Type id23=vc->arrayType(id9,id7); Type id25=vc->arrayType(id9,id9); Type id27=vc->tupleType(id19,id7,id7); Type id29=vc->funType(id27,id19); Op id31=vc->createOp(".Int_Int_store",id29); Type id33=vc->tupleType(id21,id7); Type id35=vc->funType(id33,id9); Op id37=vc->createOp(".Int_Real_select",id35); Type id39=vc->tupleType(id21,id7,id9); Type id41=vc->funType(id39,id21); Op id43=vc->createOp(".Int_Real_store",id41); Type id45=vc->tupleType(id19,id7); Type id47=vc->funType(id45,id7); Op id49=vc->createOp(".Int_Int_select",id47); Type id51=vc->tupleType(id23,id9,id7); Type id53=vc->funType(id51,id23); Op id55=vc->createOp(".Real_Int_store",id53); Type id57=vc->tupleType(id25,id9,id9); Type id59=vc->funType(id57,id25); Op id61=vc->createOp(".Real_Real_store",id59); Type id63=vc->tupleType(id23,id9); Type id65=vc->funType(id63,id7); Op id67=vc->createOp(".Real_Int_select",id65); Type id69=vc->tupleType(id25,id9); Type id71=vc->funType(id69,id9); Op id73=vc->createOp(".Real_Real_select",id71); Type id75=vc->createType("ANY"); Expr id89=vc->varExpr("x_6",id9); Expr id91=vc->varExpr("x_7",id9); Expr id93=vc->varExpr("x_8",id9); Expr id95=vc->varExpr("x_9",id9); Expr id97=vc->varExpr("x_10",id9); Expr id99=vc->varExpr("x_11",id9); Expr id101=vc->varExpr("x_12",id9); Expr id103=vc->varExpr("x_13",id9); Expr id105=vc->varExpr("x_14",id9); Expr id107=vc->varExpr("x_15",id9); Expr id109=vc->varExpr("x_16",id9); Expr id111=vc->varExpr("x_17",id9); Expr id113=vc->varExpr("x_18",id9); Expr id115=vc->varExpr("x_19",id9); Expr id117=vc->varExpr("x_20",id9); Expr id119=vc->varExpr("x_21",id9); Expr id121=vc->varExpr("x_22",id9); Expr id123=vc->varExpr("x_23",id9); Expr id125=vc->varExpr("x_24",id9); Expr id127=vc->varExpr("x_25",id9); Expr id129=vc->varExpr("x_26",id9); Expr id131=vc->varExpr("x_27",id9); Expr id133=vc->varExpr("x_28",id9); Expr id139=vc->varExpr("x_31",id9); Expr id155=vc->varExpr("x_39",id9); Expr id161=vc->varExpr("x_42",id9); Expr id163=vc->varExpr("x_43",id9); Expr id165=vc->varExpr("x_44",id9); Expr id171=vc->varExpr("x_47",id9); Expr id177=vc->varExpr("x_50",id9); Expr id179=vc->varExpr("x_51",id9); Expr id185=vc->varExpr("x_54",id9); Expr id199=vc->varExpr("x_61",id9); Expr id205=vc->varExpr("x_64",id9); Expr id207=vc->varExpr("x_65",id9); Expr id209=vc->varExpr("x_66",id9); Expr id211=vc->varExpr("x_67",id9); Expr id213=vc->varExpr("x_68",id9); Expr id215=vc->varExpr("x_69",id9); Expr id221=vc->varExpr("x_72",id9); Expr id235=vc->varExpr("x_79",id9); Expr id241=vc->varExpr("x_82",id9); Expr id243=vc->varExpr("x_83",id9); Expr id245=vc->varExpr("x_84",id9); Expr id247=vc->varExpr("x_85",id9); Expr id249=vc->varExpr("x_86",id9); Expr id251=vc->varExpr("x_87",id9); Expr id257=vc->varExpr("x_90",id9); Expr id271=vc->varExpr("x_97",id9); Expr id277=vc->varExpr("x_100",id9); Expr id279=vc->varExpr("x_101",id9); Expr id281=vc->varExpr("x_102",id9); Expr id283=vc->varExpr("x_103",id9); Expr id285=vc->varExpr("x_104",id9); Expr id287=vc->varExpr("x_105",id9); Expr id293=vc->varExpr("x_108",id9); Expr id307=vc->varExpr("x_115",id9); Expr id313=vc->varExpr("x_118",id9); Expr id315=vc->varExpr("x_119",id9); Expr id317=vc->varExpr("x_120",id9); Expr id319=vc->varExpr("x_121",id9); Expr id321=vc->varExpr("x_122",id9); Expr id323=vc->varExpr("x_123",id9); Expr id329=vc->varExpr("x_126",id9); Expr id343=vc->varExpr("x_133",id9); Expr id349=vc->varExpr("x_136",id9); Expr id351=vc->varExpr("x_137",id9); Expr id353=vc->varExpr("x_138",id9); Expr id355=vc->varExpr("x_139",id9); Expr id357=vc->varExpr("x_140",id9); Expr id359=vc->varExpr("x_141",id9); Expr id365=vc->varExpr("x_144",id9); Expr id379=vc->varExpr("x_151",id9); Expr id385=vc->varExpr("x_154",id9); Expr id387=vc->varExpr("x_155",id9); Expr id389=vc->varExpr("x_156",id9); Expr id391=vc->varExpr("x_157",id9); Expr id393=vc->varExpr("x_158",id9); Expr id395=vc->varExpr("x_159",id9); Expr id401=vc->varExpr("x_162",id9); Expr id415=vc->varExpr("x_169",id9); Expr id421=vc->varExpr("x_172",id9); Expr id423=vc->varExpr("x_173",id9); Expr id425=vc->varExpr("x_174",id9); Expr id427=vc->varExpr("x_175",id9); Expr id429=vc->varExpr("x_176",id9); Expr id431=vc->varExpr("x_177",id9); Expr id437=vc->varExpr("x_180",id9); Expr id451=vc->varExpr("x_187",id9); Expr id457=vc->varExpr("x_190",id9); Expr id459=vc->varExpr("x_191",id9); Expr id461=vc->varExpr("x_192",id9); Expr id463=vc->varExpr("x_193",id9); Expr id465=vc->varExpr("x_194",id9); Expr id467=vc->varExpr("x_195",id9); Expr id473=vc->varExpr("x_198",id9); Expr id487=vc->varExpr("x_205",id9); Expr id493=vc->varExpr("x_208",id9); Expr id495=vc->varExpr("x_209",id9); Expr id497=vc->varExpr("x_210",id9); Expr id499=vc->varExpr("x_211",id9); Expr id501=vc->varExpr("x_212",id9); Expr id503=vc->varExpr("x_213",id9); Expr id509=vc->varExpr("x_216",id9); Expr id523=vc->varExpr("x_223",id9); Expr id529=vc->varExpr("x_226",id9); Expr id531=vc->varExpr("x_227",id9); Expr id533=vc->varExpr("x_228",id9); Expr id535=vc->varExpr("x_229",id9); Expr id537=vc->varExpr("x_230",id9); Expr id539=vc->varExpr("x_231",id9); Expr id545=vc->varExpr("x_234",id9); Expr id559=vc->varExpr("x_241",id9); Expr id565=vc->varExpr("x_244",id9); Expr id567=vc->varExpr("x_245",id9); Expr id569=vc->varExpr("x_246",id9); Expr id571=vc->varExpr("x_247",id9); Expr id573=vc->varExpr("x_248",id9); Expr id575=vc->varExpr("x_249",id9); Expr id581=vc->varExpr("x_252",id9); Expr id595=vc->varExpr("x_259",id9); Expr id601=vc->varExpr("x_262",id9); Expr id603=vc->varExpr("x_263",id9); Expr id605=vc->varExpr("x_264",id9); Expr id607=vc->varExpr("x_265",id9); Expr id609=vc->varExpr("x_266",id9); Expr id611=vc->varExpr("x_267",id9); Expr id617=vc->varExpr("x_270",id9); Expr id631=vc->varExpr("x_277",id9); Expr id637=vc->varExpr("x_280",id9); Expr id639=vc->varExpr("x_281",id9); Expr id641=vc->varExpr("x_282",id9); Expr id643=vc->varExpr("x_283",id9); Expr id645=vc->varExpr("x_284",id9); Expr id647=vc->varExpr("x_285",id9); Expr id653=vc->varExpr("x_288",id9); Expr id667=vc->varExpr("x_295",id9); Expr id673=vc->varExpr("x_298",id9); Expr id675=vc->varExpr("x_299",id9); Expr id677=vc->varExpr("x_300",id9); Expr id679=vc->varExpr("x_301",id9); Expr id681=vc->varExpr("x_302",id9); Expr id683=vc->varExpr("x_303",id9); Expr id689=vc->varExpr("x_306",id9); Expr id703=vc->varExpr("x_313",id9); Expr id709=vc->varExpr("x_316",id9); Expr id711=vc->varExpr("x_317",id9); Expr id713=vc->varExpr("x_318",id9); Expr id715=vc->varExpr("x_319",id9); Expr id717=vc->varExpr("x_320",id9); Expr id719=vc->varExpr("x_321",id9); Expr id725=vc->varExpr("x_324",id9); Expr id739=vc->varExpr("x_331",id9); Expr id745=vc->varExpr("x_334",id9); Expr id747=vc->varExpr("x_335",id9); Expr id749=vc->varExpr("x_336",id9); Expr id751=vc->varExpr("x_337",id9); Expr id753=vc->varExpr("x_338",id9); Expr id755=vc->varExpr("x_339",id9); Expr id761=vc->varExpr("x_342",id9); Expr id775=vc->varExpr("x_349",id9); Expr id781=vc->varExpr("x_352",id9); Expr id783=vc->varExpr("x_353",id9); Expr id785=vc->varExpr("x_354",id9); Expr id787=vc->varExpr("x_355",id9); Expr id789=vc->varExpr("x_356",id9); Expr id791=vc->varExpr("x_357",id9); Expr id797=vc->varExpr("x_360",id9); Expr id811=vc->varExpr("x_367",id9); Expr id817=vc->varExpr("x_370",id9); Expr id819=vc->varExpr("x_371",id9); Expr id821=vc->varExpr("x_372",id9); Expr id823=vc->varExpr("x_373",id9); Expr id825=vc->varExpr("x_374",id9); Expr id827=vc->varExpr("x_375",id9); Expr id833=vc->varExpr("x_378",id9); Expr id847=vc->varExpr("x_385",id9); Expr id853=vc->varExpr("x_388",id9); Expr id855=vc->varExpr("x_389",id9); Expr id857=vc->varExpr("x_390",id9); Expr id859=vc->varExpr("x_391",id9); Expr id861=vc->varExpr("x_392",id9); Expr id863=vc->eqExpr(id791,id827); Expr id862=vc->notExpr(id863); vc->registerAtom(id863); Expr id867=vc->eqExpr(id797,id833); Expr id866=vc->notExpr(id867); vc->registerAtom(id867); Expr id875=vc->ratExpr(1,1); Expr id877=vc->eqExpr(id875,id819); Expr id876=vc->notExpr(id877); vc->registerAtom(id877); Expr id891=vc->eqExpr(id811,id847); Expr id890=vc->notExpr(id891); vc->registerAtom(id891); Expr id895=vc->ratExpr(0,1); Expr id897=vc->eqExpr(id895,id853); Expr id896=vc->notExpr(id897); vc->registerAtom(id897); Expr id899=vc->eqExpr(id817,id853); Expr id898=vc->notExpr(id899); vc->registerAtom(id899); Expr id901=vc->eqExpr(id895,id819); Expr id900=vc->notExpr(id901); vc->registerAtom(id901); Expr id903=vc->eqExpr(id895,id833); Expr id902=vc->notExpr(id903); vc->registerAtom(id903); Expr id905=vc->eqExpr(id755,id791); Expr id904=vc->notExpr(id905); vc->registerAtom(id905); Expr id909=vc->eqExpr(id761,id797); Expr id908=vc->notExpr(id909); vc->registerAtom(id909); Expr id917=vc->eqExpr(id875,id783); Expr id916=vc->notExpr(id917); vc->registerAtom(id917); Expr id931=vc->eqExpr(id775,id811); Expr id930=vc->notExpr(id931); vc->registerAtom(id931); Expr id935=vc->eqExpr(id895,id817); Expr id934=vc->notExpr(id935); vc->registerAtom(id935); Expr id937=vc->eqExpr(id781,id817); Expr id936=vc->notExpr(id937); vc->registerAtom(id937); Expr id939=vc->eqExpr(id895,id783); Expr id938=vc->notExpr(id939); vc->registerAtom(id939); Expr id941=vc->eqExpr(id895,id797); Expr id940=vc->notExpr(id941); vc->registerAtom(id941); Expr id943=vc->eqExpr(id719,id755); Expr id942=vc->notExpr(id943); vc->registerAtom(id943); Expr id947=vc->eqExpr(id725,id761); Expr id946=vc->notExpr(id947); vc->registerAtom(id947); Expr id955=vc->eqExpr(id875,id747); Expr id954=vc->notExpr(id955); vc->registerAtom(id955); Expr id969=vc->eqExpr(id739,id775); Expr id968=vc->notExpr(id969); vc->registerAtom(id969); Expr id973=vc->eqExpr(id895,id781); Expr id972=vc->notExpr(id973); vc->registerAtom(id973); Expr id975=vc->eqExpr(id745,id781); Expr id974=vc->notExpr(id975); vc->registerAtom(id975); Expr id977=vc->eqExpr(id895,id747); Expr id976=vc->notExpr(id977); vc->registerAtom(id977); Expr id979=vc->eqExpr(id895,id761); Expr id978=vc->notExpr(id979); vc->registerAtom(id979); Expr id981=vc->eqExpr(id683,id719); Expr id980=vc->notExpr(id981); vc->registerAtom(id981); Expr id985=vc->eqExpr(id689,id725); Expr id984=vc->notExpr(id985); vc->registerAtom(id985); Expr id993=vc->eqExpr(id875,id711); Expr id992=vc->notExpr(id993); vc->registerAtom(id993); Expr id1007=vc->eqExpr(id703,id739); Expr id1006=vc->notExpr(id1007); vc->registerAtom(id1007); Expr id1011=vc->eqExpr(id895,id745); Expr id1010=vc->notExpr(id1011); vc->registerAtom(id1011); Expr id1013=vc->eqExpr(id709,id745); Expr id1012=vc->notExpr(id1013); vc->registerAtom(id1013); Expr id1015=vc->eqExpr(id895,id711); Expr id1014=vc->notExpr(id1015); vc->registerAtom(id1015); Expr id1017=vc->eqExpr(id895,id725); Expr id1016=vc->notExpr(id1017); vc->registerAtom(id1017); Expr id1019=vc->eqExpr(id647,id683); Expr id1018=vc->notExpr(id1019); vc->registerAtom(id1019); Expr id1023=vc->eqExpr(id653,id689); Expr id1022=vc->notExpr(id1023); vc->registerAtom(id1023); Expr id1031=vc->eqExpr(id875,id675); Expr id1030=vc->notExpr(id1031); vc->registerAtom(id1031); Expr id1045=vc->eqExpr(id667,id703); Expr id1044=vc->notExpr(id1045); vc->registerAtom(id1045); Expr id1049=vc->eqExpr(id895,id709); Expr id1048=vc->notExpr(id1049); vc->registerAtom(id1049); Expr id1051=vc->eqExpr(id673,id709); Expr id1050=vc->notExpr(id1051); vc->registerAtom(id1051); Expr id1053=vc->eqExpr(id895,id675); Expr id1052=vc->notExpr(id1053); vc->registerAtom(id1053); Expr id1055=vc->eqExpr(id895,id689); Expr id1054=vc->notExpr(id1055); vc->registerAtom(id1055); Expr id1057=vc->eqExpr(id611,id647); Expr id1056=vc->notExpr(id1057); vc->registerAtom(id1057); Expr id1061=vc->eqExpr(id617,id653); Expr id1060=vc->notExpr(id1061); vc->registerAtom(id1061); Expr id1069=vc->eqExpr(id875,id639); Expr id1068=vc->notExpr(id1069); vc->registerAtom(id1069); Expr id1083=vc->eqExpr(id631,id667); Expr id1082=vc->notExpr(id1083); vc->registerAtom(id1083); Expr id1087=vc->eqExpr(id895,id673); Expr id1086=vc->notExpr(id1087); vc->registerAtom(id1087); Expr id1089=vc->eqExpr(id637,id673); Expr id1088=vc->notExpr(id1089); vc->registerAtom(id1089); Expr id1091=vc->eqExpr(id895,id639); Expr id1090=vc->notExpr(id1091); vc->registerAtom(id1091); Expr id1093=vc->eqExpr(id895,id653); Expr id1092=vc->notExpr(id1093); vc->registerAtom(id1093); Expr id1095=vc->eqExpr(id575,id611); Expr id1094=vc->notExpr(id1095); vc->registerAtom(id1095); Expr id1099=vc->eqExpr(id581,id617); Expr id1098=vc->notExpr(id1099); vc->registerAtom(id1099); Expr id1107=vc->eqExpr(id875,id603); Expr id1106=vc->notExpr(id1107); vc->registerAtom(id1107); Expr id1121=vc->eqExpr(id595,id631); Expr id1120=vc->notExpr(id1121); vc->registerAtom(id1121); Expr id1125=vc->eqExpr(id895,id637); Expr id1124=vc->notExpr(id1125); vc->registerAtom(id1125); Expr id1127=vc->eqExpr(id601,id637); Expr id1126=vc->notExpr(id1127); vc->registerAtom(id1127); Expr id1129=vc->eqExpr(id895,id603); Expr id1128=vc->notExpr(id1129); vc->registerAtom(id1129); Expr id1131=vc->eqExpr(id895,id617); Expr id1130=vc->notExpr(id1131); vc->registerAtom(id1131); Expr id1133=vc->eqExpr(id539,id575); Expr id1132=vc->notExpr(id1133); vc->registerAtom(id1133); Expr id1137=vc->eqExpr(id545,id581); Expr id1136=vc->notExpr(id1137); vc->registerAtom(id1137); Expr id1145=vc->eqExpr(id875,id567); Expr id1144=vc->notExpr(id1145); vc->registerAtom(id1145); Expr id1159=vc->eqExpr(id559,id595); Expr id1158=vc->notExpr(id1159); vc->registerAtom(id1159); Expr id1163=vc->eqExpr(id895,id601); Expr id1162=vc->notExpr(id1163); vc->registerAtom(id1163); Expr id1165=vc->eqExpr(id565,id601); Expr id1164=vc->notExpr(id1165); vc->registerAtom(id1165); Expr id1167=vc->eqExpr(id895,id567); Expr id1166=vc->notExpr(id1167); vc->registerAtom(id1167); Expr id1169=vc->eqExpr(id895,id581); Expr id1168=vc->notExpr(id1169); vc->registerAtom(id1169); Expr id1171=vc->eqExpr(id503,id539); Expr id1170=vc->notExpr(id1171); vc->registerAtom(id1171); Expr id1175=vc->eqExpr(id509,id545); Expr id1174=vc->notExpr(id1175); vc->registerAtom(id1175); Expr id1183=vc->eqExpr(id875,id531); Expr id1182=vc->notExpr(id1183); vc->registerAtom(id1183); Expr id1197=vc->eqExpr(id523,id559); Expr id1196=vc->notExpr(id1197); vc->registerAtom(id1197); Expr id1201=vc->eqExpr(id895,id565); Expr id1200=vc->notExpr(id1201); vc->registerAtom(id1201); Expr id1203=vc->eqExpr(id529,id565); Expr id1202=vc->notExpr(id1203); vc->registerAtom(id1203); Expr id1205=vc->eqExpr(id895,id531); Expr id1204=vc->notExpr(id1205); vc->registerAtom(id1205); Expr id1207=vc->eqExpr(id895,id545); Expr id1206=vc->notExpr(id1207); vc->registerAtom(id1207); Expr id1209=vc->eqExpr(id467,id503); Expr id1208=vc->notExpr(id1209); vc->registerAtom(id1209); Expr id1213=vc->eqExpr(id473,id509); Expr id1212=vc->notExpr(id1213); vc->registerAtom(id1213); Expr id1221=vc->eqExpr(id875,id495); Expr id1220=vc->notExpr(id1221); vc->registerAtom(id1221); Expr id1235=vc->eqExpr(id487,id523); Expr id1234=vc->notExpr(id1235); vc->registerAtom(id1235); Expr id1239=vc->eqExpr(id895,id529); Expr id1238=vc->notExpr(id1239); vc->registerAtom(id1239); Expr id1241=vc->eqExpr(id493,id529); Expr id1240=vc->notExpr(id1241); vc->registerAtom(id1241); Expr id1243=vc->eqExpr(id895,id495); Expr id1242=vc->notExpr(id1243); vc->registerAtom(id1243); Expr id1245=vc->eqExpr(id895,id509); Expr id1244=vc->notExpr(id1245); vc->registerAtom(id1245); Expr id1247=vc->eqExpr(id431,id467); Expr id1246=vc->notExpr(id1247); vc->registerAtom(id1247); Expr id1251=vc->eqExpr(id437,id473); Expr id1250=vc->notExpr(id1251); vc->registerAtom(id1251); Expr id1259=vc->eqExpr(id875,id459); Expr id1258=vc->notExpr(id1259); vc->registerAtom(id1259); Expr id1273=vc->eqExpr(id451,id487); Expr id1272=vc->notExpr(id1273); vc->registerAtom(id1273); Expr id1277=vc->eqExpr(id895,id493); Expr id1276=vc->notExpr(id1277); vc->registerAtom(id1277); Expr id1279=vc->eqExpr(id457,id493); Expr id1278=vc->notExpr(id1279); vc->registerAtom(id1279); Expr id1281=vc->eqExpr(id895,id459); Expr id1280=vc->notExpr(id1281); vc->registerAtom(id1281); Expr id1283=vc->eqExpr(id895,id473); Expr id1282=vc->notExpr(id1283); vc->registerAtom(id1283); Expr id1285=vc->eqExpr(id395,id431); Expr id1284=vc->notExpr(id1285); vc->registerAtom(id1285); Expr id1289=vc->eqExpr(id401,id437); Expr id1288=vc->notExpr(id1289); vc->registerAtom(id1289); Expr id1297=vc->eqExpr(id875,id423); Expr id1296=vc->notExpr(id1297); vc->registerAtom(id1297); Expr id1311=vc->eqExpr(id415,id451); Expr id1310=vc->notExpr(id1311); vc->registerAtom(id1311); Expr id1315=vc->eqExpr(id895,id457); Expr id1314=vc->notExpr(id1315); vc->registerAtom(id1315); Expr id1317=vc->eqExpr(id421,id457); Expr id1316=vc->notExpr(id1317); vc->registerAtom(id1317); Expr id1319=vc->eqExpr(id895,id423); Expr id1318=vc->notExpr(id1319); vc->registerAtom(id1319); Expr id1321=vc->eqExpr(id895,id437); Expr id1320=vc->notExpr(id1321); vc->registerAtom(id1321); Expr id1323=vc->eqExpr(id359,id395); Expr id1322=vc->notExpr(id1323); vc->registerAtom(id1323); Expr id1327=vc->eqExpr(id365,id401); Expr id1326=vc->notExpr(id1327); vc->registerAtom(id1327); Expr id1335=vc->eqExpr(id875,id387); Expr id1334=vc->notExpr(id1335); vc->registerAtom(id1335); Expr id1349=vc->eqExpr(id379,id415); Expr id1348=vc->notExpr(id1349); vc->registerAtom(id1349); Expr id1353=vc->eqExpr(id895,id421); Expr id1352=vc->notExpr(id1353); vc->registerAtom(id1353); Expr id1355=vc->eqExpr(id385,id421); Expr id1354=vc->notExpr(id1355); vc->registerAtom(id1355); Expr id1357=vc->eqExpr(id895,id387); Expr id1356=vc->notExpr(id1357); vc->registerAtom(id1357); Expr id1359=vc->eqExpr(id895,id401); Expr id1358=vc->notExpr(id1359); vc->registerAtom(id1359); Expr id1361=vc->eqExpr(id323,id359); Expr id1360=vc->notExpr(id1361); vc->registerAtom(id1361); Expr id1365=vc->eqExpr(id329,id365); Expr id1364=vc->notExpr(id1365); vc->registerAtom(id1365); Expr id1373=vc->eqExpr(id875,id351); Expr id1372=vc->notExpr(id1373); vc->registerAtom(id1373); Expr id1387=vc->eqExpr(id343,id379); Expr id1386=vc->notExpr(id1387); vc->registerAtom(id1387); Expr id1391=vc->eqExpr(id895,id385); Expr id1390=vc->notExpr(id1391); vc->registerAtom(id1391); Expr id1393=vc->eqExpr(id349,id385); Expr id1392=vc->notExpr(id1393); vc->registerAtom(id1393); Expr id1395=vc->eqExpr(id895,id351); Expr id1394=vc->notExpr(id1395); vc->registerAtom(id1395); Expr id1397=vc->eqExpr(id895,id365); Expr id1396=vc->notExpr(id1397); vc->registerAtom(id1397); Expr id1399=vc->eqExpr(id287,id323); Expr id1398=vc->notExpr(id1399); vc->registerAtom(id1399); Expr id1403=vc->eqExpr(id293,id329); Expr id1402=vc->notExpr(id1403); vc->registerAtom(id1403); Expr id1411=vc->eqExpr(id875,id315); Expr id1410=vc->notExpr(id1411); vc->registerAtom(id1411); Expr id1425=vc->eqExpr(id307,id343); Expr id1424=vc->notExpr(id1425); vc->registerAtom(id1425); Expr id1429=vc->eqExpr(id895,id349); Expr id1428=vc->notExpr(id1429); vc->registerAtom(id1429); Expr id1431=vc->eqExpr(id313,id349); Expr id1430=vc->notExpr(id1431); vc->registerAtom(id1431); Expr id1433=vc->eqExpr(id895,id315); Expr id1432=vc->notExpr(id1433); vc->registerAtom(id1433); Expr id1435=vc->eqExpr(id895,id329); Expr id1434=vc->notExpr(id1435); vc->registerAtom(id1435); Expr id1437=vc->eqExpr(id251,id287); Expr id1436=vc->notExpr(id1437); vc->registerAtom(id1437); Expr id1441=vc->eqExpr(id257,id293); Expr id1440=vc->notExpr(id1441); vc->registerAtom(id1441); Expr id1449=vc->eqExpr(id875,id279); Expr id1448=vc->notExpr(id1449); vc->registerAtom(id1449); Expr id1463=vc->eqExpr(id271,id307); Expr id1462=vc->notExpr(id1463); vc->registerAtom(id1463); Expr id1467=vc->eqExpr(id895,id313); Expr id1466=vc->notExpr(id1467); vc->registerAtom(id1467); Expr id1469=vc->eqExpr(id277,id313); Expr id1468=vc->notExpr(id1469); vc->registerAtom(id1469); Expr id1471=vc->eqExpr(id895,id279); Expr id1470=vc->notExpr(id1471); vc->registerAtom(id1471); Expr id1473=vc->eqExpr(id895,id293); Expr id1472=vc->notExpr(id1473); vc->registerAtom(id1473); Expr id1475=vc->eqExpr(id215,id251); Expr id1474=vc->notExpr(id1475); vc->registerAtom(id1475); Expr id1479=vc->eqExpr(id221,id257); Expr id1478=vc->notExpr(id1479); vc->registerAtom(id1479); Expr id1487=vc->eqExpr(id875,id243); Expr id1486=vc->notExpr(id1487); vc->registerAtom(id1487); Expr id1501=vc->eqExpr(id235,id271); Expr id1500=vc->notExpr(id1501); vc->registerAtom(id1501); Expr id1505=vc->eqExpr(id895,id277); Expr id1504=vc->notExpr(id1505); vc->registerAtom(id1505); Expr id1507=vc->eqExpr(id241,id277); Expr id1506=vc->notExpr(id1507); vc->registerAtom(id1507); Expr id1509=vc->eqExpr(id895,id243); Expr id1508=vc->notExpr(id1509); vc->registerAtom(id1509); Expr id1511=vc->eqExpr(id895,id257); Expr id1510=vc->notExpr(id1511); vc->registerAtom(id1511); Expr id1513=vc->eqExpr(id179,id215); Expr id1512=vc->notExpr(id1513); vc->registerAtom(id1513); Expr id1517=vc->eqExpr(id185,id221); Expr id1516=vc->notExpr(id1517); vc->registerAtom(id1517); Expr id1525=vc->eqExpr(id875,id207); Expr id1524=vc->notExpr(id1525); vc->registerAtom(id1525); Expr id1539=vc->eqExpr(id199,id235); Expr id1538=vc->notExpr(id1539); vc->registerAtom(id1539); Expr id1543=vc->eqExpr(id895,id241); Expr id1542=vc->notExpr(id1543); vc->registerAtom(id1543); Expr id1545=vc->eqExpr(id205,id241); Expr id1544=vc->notExpr(id1545); vc->registerAtom(id1545); Expr id1547=vc->eqExpr(id895,id207); Expr id1546=vc->notExpr(id1547); vc->registerAtom(id1547); Expr id1549=vc->eqExpr(id895,id221); Expr id1548=vc->notExpr(id1549); vc->registerAtom(id1549); Expr id1551=vc->eqExpr(id131,id179); Expr id1550=vc->notExpr(id1551); vc->registerAtom(id1551); Expr id1555=vc->eqExpr(id139,id185); Expr id1554=vc->notExpr(id1555); vc->registerAtom(id1555); Expr id1563=vc->eqExpr(id875,id163); Expr id1562=vc->notExpr(id1563); vc->registerAtom(id1563); Expr id1577=vc->eqExpr(id155,id199); Expr id1576=vc->notExpr(id1577); vc->registerAtom(id1577); Expr id1581=vc->eqExpr(id895,id205); Expr id1580=vc->notExpr(id1581); vc->registerAtom(id1581); Expr id1583=vc->eqExpr(id161,id205); Expr id1582=vc->notExpr(id1583); vc->registerAtom(id1583); Expr id1585=vc->eqExpr(id895,id163); Expr id1584=vc->notExpr(id1585); vc->registerAtom(id1585); Expr id1587=vc->eqExpr(id895,id185); Expr id1586=vc->notExpr(id1587); vc->registerAtom(id1587); Expr id1589=vc->eqExpr(id133,id131); Expr id1588=vc->notExpr(id1589); vc->registerAtom(id1589); Expr id1613=vc->eqExpr(id895,id161); Expr id1612=vc->notExpr(id1613); vc->registerAtom(id1613); Expr id1615=vc->eqExpr(id895,id139); Expr id1614=vc->notExpr(id1615); vc->registerAtom(id1615); Expr id1617=vc->eqExpr(id895,id155); Expr id1616=vc->notExpr(id1617); vc->registerAtom(id1617); Expr id1619=vc->plusExpr(id811,id127); Expr id1621=vc->ratExpr(5,1); Expr id1623=vc->leExpr(id1619,id1621); Expr id1622=vc->notExpr(id1623); vc->registerAtom(id1623); Expr id1625=vc->plusExpr(id817,id127); Expr id1627=vc->leExpr(id1625,id875); Expr id1626=vc->notExpr(id1627); vc->registerAtom(id1627); Expr id1629=vc->plusExpr(id775,id125); Expr id1631=vc->leExpr(id1629,id1621); Expr id1630=vc->notExpr(id1631); vc->registerAtom(id1631); Expr id1633=vc->plusExpr(id781,id125); Expr id1635=vc->leExpr(id1633,id875); Expr id1634=vc->notExpr(id1635); vc->registerAtom(id1635); Expr id1637=vc->plusExpr(id739,id123); Expr id1639=vc->leExpr(id1637,id1621); Expr id1638=vc->notExpr(id1639); vc->registerAtom(id1639); Expr id1641=vc->plusExpr(id745,id123); Expr id1643=vc->leExpr(id1641,id875); Expr id1642=vc->notExpr(id1643); vc->registerAtom(id1643); Expr id1645=vc->plusExpr(id703,id121); Expr id1647=vc->leExpr(id1645,id1621); Expr id1646=vc->notExpr(id1647); vc->registerAtom(id1647); Expr id1649=vc->plusExpr(id709,id121); Expr id1651=vc->leExpr(id1649,id875); Expr id1650=vc->notExpr(id1651); vc->registerAtom(id1651); Expr id1653=vc->plusExpr(id667,id119); Expr id1655=vc->leExpr(id1653,id1621); Expr id1654=vc->notExpr(id1655); vc->registerAtom(id1655); Expr id1657=vc->plusExpr(id673,id119); Expr id1659=vc->leExpr(id1657,id875); Expr id1658=vc->notExpr(id1659); vc->registerAtom(id1659); Expr id1661=vc->plusExpr(id631,id117); Expr id1663=vc->leExpr(id1661,id1621); Expr id1662=vc->notExpr(id1663); vc->registerAtom(id1663); Expr id1665=vc->plusExpr(id637,id117); Expr id1667=vc->leExpr(id1665,id875); Expr id1666=vc->notExpr(id1667); vc->registerAtom(id1667); Expr id1669=vc->plusExpr(id595,id115); Expr id1671=vc->leExpr(id1669,id1621); Expr id1670=vc->notExpr(id1671); vc->registerAtom(id1671); Expr id1673=vc->plusExpr(id601,id115); Expr id1675=vc->leExpr(id1673,id875); Expr id1674=vc->notExpr(id1675); vc->registerAtom(id1675); Expr id1677=vc->plusExpr(id559,id113); Expr id1679=vc->leExpr(id1677,id1621); Expr id1678=vc->notExpr(id1679); vc->registerAtom(id1679); Expr id1681=vc->plusExpr(id565,id113); Expr id1683=vc->leExpr(id1681,id875); Expr id1682=vc->notExpr(id1683); vc->registerAtom(id1683); Expr id1685=vc->plusExpr(id523,id111); Expr id1687=vc->leExpr(id1685,id1621); Expr id1686=vc->notExpr(id1687); vc->registerAtom(id1687); Expr id1689=vc->plusExpr(id529,id111); Expr id1691=vc->leExpr(id1689,id875); Expr id1690=vc->notExpr(id1691); vc->registerAtom(id1691); Expr id1693=vc->plusExpr(id487,id109); Expr id1695=vc->leExpr(id1693,id1621); Expr id1694=vc->notExpr(id1695); vc->registerAtom(id1695); Expr id1697=vc->plusExpr(id493,id109); Expr id1699=vc->leExpr(id1697,id875); Expr id1698=vc->notExpr(id1699); vc->registerAtom(id1699); Expr id1701=vc->plusExpr(id451,id107); Expr id1703=vc->leExpr(id1701,id1621); Expr id1702=vc->notExpr(id1703); vc->registerAtom(id1703); Expr id1705=vc->plusExpr(id457,id107); Expr id1707=vc->leExpr(id1705,id875); Expr id1706=vc->notExpr(id1707); vc->registerAtom(id1707); Expr id1709=vc->plusExpr(id415,id105); Expr id1711=vc->leExpr(id1709,id1621); Expr id1710=vc->notExpr(id1711); vc->registerAtom(id1711); Expr id1713=vc->plusExpr(id421,id105); Expr id1715=vc->leExpr(id1713,id875); Expr id1714=vc->notExpr(id1715); vc->registerAtom(id1715); Expr id1717=vc->plusExpr(id379,id103); Expr id1719=vc->leExpr(id1717,id1621); Expr id1718=vc->notExpr(id1719); vc->registerAtom(id1719); Expr id1721=vc->plusExpr(id385,id103); Expr id1723=vc->leExpr(id1721,id875); Expr id1722=vc->notExpr(id1723); vc->registerAtom(id1723); Expr id1725=vc->plusExpr(id343,id101); Expr id1727=vc->leExpr(id1725,id1621); Expr id1726=vc->notExpr(id1727); vc->registerAtom(id1727); Expr id1729=vc->plusExpr(id349,id101); Expr id1731=vc->leExpr(id1729,id875); Expr id1730=vc->notExpr(id1731); vc->registerAtom(id1731); Expr id1733=vc->plusExpr(id307,id99); Expr id1735=vc->leExpr(id1733,id1621); Expr id1734=vc->notExpr(id1735); vc->registerAtom(id1735); Expr id1737=vc->plusExpr(id313,id99); Expr id1739=vc->leExpr(id1737,id875); Expr id1738=vc->notExpr(id1739); vc->registerAtom(id1739); Expr id1741=vc->plusExpr(id271,id97); Expr id1743=vc->leExpr(id1741,id1621); Expr id1742=vc->notExpr(id1743); vc->registerAtom(id1743); Expr id1745=vc->plusExpr(id277,id97); Expr id1747=vc->leExpr(id1745,id875); Expr id1746=vc->notExpr(id1747); vc->registerAtom(id1747); Expr id1749=vc->plusExpr(id235,id95); Expr id1751=vc->leExpr(id1749,id1621); Expr id1750=vc->notExpr(id1751); vc->registerAtom(id1751); Expr id1753=vc->plusExpr(id241,id95); Expr id1755=vc->leExpr(id1753,id875); Expr id1754=vc->notExpr(id1755); vc->registerAtom(id1755); Expr id1757=vc->plusExpr(id199,id93); Expr id1759=vc->leExpr(id1757,id1621); Expr id1758=vc->notExpr(id1759); vc->registerAtom(id1759); Expr id1761=vc->plusExpr(id205,id93); Expr id1763=vc->leExpr(id1761,id875); Expr id1762=vc->notExpr(id1763); vc->registerAtom(id1763); Expr id1765=vc->plusExpr(id155,id91); Expr id1767=vc->leExpr(id1765,id1621); Expr id1766=vc->notExpr(id1767); vc->registerAtom(id1767); Expr id1769=vc->plusExpr(id161,id91); Expr id1771=vc->leExpr(id1769,id875); Expr id1770=vc->notExpr(id1771); vc->registerAtom(id1771); Expr id1773=vc->plusExpr(id895,id89); Expr id1775=vc->leExpr(id1773,id1621); Expr id1774=vc->notExpr(id1775); vc->registerAtom(id1775); Expr id1777=vc->leExpr(id1773,id875); Expr id1776=vc->notExpr(id1777); vc->registerAtom(id1777); Expr id1779=vc->leExpr(id855,id875); Expr id1778=vc->notExpr(id1779); vc->registerAtom(id1779); Expr id1781=vc->geExpr(id855,id895); Expr id1780=vc->notExpr(id1781); vc->registerAtom(id1781); Expr id1785=vc->leExpr(id819,id875); Expr id1784=vc->notExpr(id1785); vc->registerAtom(id1785); Expr id1789=vc->geExpr(id819,id895); Expr id1788=vc->notExpr(id1789); vc->registerAtom(id1789); Expr id1793=vc->leExpr(id783,id875); Expr id1792=vc->notExpr(id1793); vc->registerAtom(id1793); Expr id1797=vc->geExpr(id783,id895); Expr id1796=vc->notExpr(id1797); vc->registerAtom(id1797); Expr id1801=vc->leExpr(id747,id875); Expr id1800=vc->notExpr(id1801); vc->registerAtom(id1801); Expr id1805=vc->geExpr(id747,id895); Expr id1804=vc->notExpr(id1805); vc->registerAtom(id1805); Expr id1809=vc->leExpr(id711,id875); Expr id1808=vc->notExpr(id1809); vc->registerAtom(id1809); Expr id1813=vc->geExpr(id711,id895); Expr id1812=vc->notExpr(id1813); vc->registerAtom(id1813); Expr id1817=vc->leExpr(id675,id875); Expr id1816=vc->notExpr(id1817); vc->registerAtom(id1817); Expr id1821=vc->geExpr(id675,id895); Expr id1820=vc->notExpr(id1821); vc->registerAtom(id1821); Expr id1825=vc->leExpr(id639,id875); Expr id1824=vc->notExpr(id1825); vc->registerAtom(id1825); Expr id1829=vc->geExpr(id639,id895); Expr id1828=vc->notExpr(id1829); vc->registerAtom(id1829); Expr id1833=vc->leExpr(id603,id875); Expr id1832=vc->notExpr(id1833); vc->registerAtom(id1833); Expr id1837=vc->geExpr(id603,id895); Expr id1836=vc->notExpr(id1837); vc->registerAtom(id1837); Expr id1841=vc->leExpr(id567,id875); Expr id1840=vc->notExpr(id1841); vc->registerAtom(id1841); Expr id1845=vc->geExpr(id567,id895); Expr id1844=vc->notExpr(id1845); vc->registerAtom(id1845); Expr id1849=vc->leExpr(id531,id875); Expr id1848=vc->notExpr(id1849); vc->registerAtom(id1849); Expr id1853=vc->geExpr(id531,id895); Expr id1852=vc->notExpr(id1853); vc->registerAtom(id1853); Expr id1857=vc->leExpr(id495,id875); Expr id1856=vc->notExpr(id1857); vc->registerAtom(id1857); Expr id1861=vc->geExpr(id495,id895); Expr id1860=vc->notExpr(id1861); vc->registerAtom(id1861); Expr id1865=vc->leExpr(id459,id875); Expr id1864=vc->notExpr(id1865); vc->registerAtom(id1865); Expr id1869=vc->geExpr(id459,id895); Expr id1868=vc->notExpr(id1869); vc->registerAtom(id1869); Expr id1873=vc->leExpr(id423,id875); Expr id1872=vc->notExpr(id1873); vc->registerAtom(id1873); Expr id1877=vc->geExpr(id423,id895); Expr id1876=vc->notExpr(id1877); vc->registerAtom(id1877); Expr id1881=vc->leExpr(id387,id875); Expr id1880=vc->notExpr(id1881); vc->registerAtom(id1881); Expr id1885=vc->geExpr(id387,id895); Expr id1884=vc->notExpr(id1885); vc->registerAtom(id1885); Expr id1889=vc->leExpr(id351,id875); Expr id1888=vc->notExpr(id1889); vc->registerAtom(id1889); Expr id1893=vc->geExpr(id351,id895); Expr id1892=vc->notExpr(id1893); vc->registerAtom(id1893); Expr id1897=vc->leExpr(id315,id875); Expr id1896=vc->notExpr(id1897); vc->registerAtom(id1897); Expr id1901=vc->geExpr(id315,id895); Expr id1900=vc->notExpr(id1901); vc->registerAtom(id1901); Expr id1905=vc->leExpr(id279,id875); Expr id1904=vc->notExpr(id1905); vc->registerAtom(id1905); Expr id1909=vc->geExpr(id279,id895); Expr id1908=vc->notExpr(id1909); vc->registerAtom(id1909); Expr id1913=vc->leExpr(id243,id875); Expr id1912=vc->notExpr(id1913); vc->registerAtom(id1913); Expr id1917=vc->geExpr(id243,id895); Expr id1916=vc->notExpr(id1917); vc->registerAtom(id1917); Expr id1921=vc->leExpr(id207,id875); Expr id1920=vc->notExpr(id1921); vc->registerAtom(id1921); Expr id1925=vc->geExpr(id207,id895); Expr id1924=vc->notExpr(id1925); vc->registerAtom(id1925); Expr id1929=vc->leExpr(id163,id875); Expr id1928=vc->notExpr(id1929); vc->registerAtom(id1929); Expr id1933=vc->geExpr(id163,id895); Expr id1932=vc->notExpr(id1933); vc->registerAtom(id1933); Expr id1949=vc->ltExpr(id129,id895); Expr id1948=vc->notExpr(id1949); vc->registerAtom(id1949); Expr id1955=vc->ltExpr(id127,id895); Expr id1954=vc->notExpr(id1955); vc->registerAtom(id1955); Expr id1961=vc->ltExpr(id125,id895); Expr id1960=vc->notExpr(id1961); vc->registerAtom(id1961); Expr id1967=vc->ltExpr(id123,id895); Expr id1966=vc->notExpr(id1967); vc->registerAtom(id1967); Expr id1973=vc->ltExpr(id121,id895); Expr id1972=vc->notExpr(id1973); vc->registerAtom(id1973); Expr id1979=vc->ltExpr(id119,id895); Expr id1978=vc->notExpr(id1979); vc->registerAtom(id1979); Expr id1985=vc->ltExpr(id117,id895); Expr id1984=vc->notExpr(id1985); vc->registerAtom(id1985); Expr id1991=vc->ltExpr(id115,id895); Expr id1990=vc->notExpr(id1991); vc->registerAtom(id1991); Expr id1997=vc->ltExpr(id113,id895); Expr id1996=vc->notExpr(id1997); vc->registerAtom(id1997); Expr id2003=vc->ltExpr(id111,id895); Expr id2002=vc->notExpr(id2003); vc->registerAtom(id2003); Expr id2009=vc->ltExpr(id109,id895); Expr id2008=vc->notExpr(id2009); vc->registerAtom(id2009); Expr id2015=vc->ltExpr(id107,id895); Expr id2014=vc->notExpr(id2015); vc->registerAtom(id2015); Expr id2021=vc->ltExpr(id105,id895); Expr id2020=vc->notExpr(id2021); vc->registerAtom(id2021); Expr id2027=vc->ltExpr(id103,id895); Expr id2026=vc->notExpr(id2027); vc->registerAtom(id2027); Expr id2033=vc->ltExpr(id101,id895); Expr id2032=vc->notExpr(id2033); vc->registerAtom(id2033); Expr id2039=vc->ltExpr(id99,id895); Expr id2038=vc->notExpr(id2039); vc->registerAtom(id2039); Expr id2045=vc->ltExpr(id97,id895); Expr id2044=vc->notExpr(id2045); vc->registerAtom(id2045); Expr id2051=vc->ltExpr(id95,id895); Expr id2050=vc->notExpr(id2051); vc->registerAtom(id2051); Expr id2057=vc->ltExpr(id93,id895); Expr id2056=vc->notExpr(id2057); vc->registerAtom(id2057); Expr id2063=vc->ltExpr(id91,id895); Expr id2062=vc->notExpr(id2063); vc->registerAtom(id2063); Expr id2069=vc->ltExpr(id89,id895); Expr id2068=vc->notExpr(id2069); vc->registerAtom(id2069); Expr id2077=vc->varExpr("2075_c",id9); Expr id2079=vc->eqExpr(id2077,id895); Expr id2078=vc->notExpr(id2079); vc->registerAtom(id2079); Expr id2081=vc->eqExpr(id2077,id875); Expr id2080=vc->notExpr(id2081); vc->registerAtom(id2081); Expr id2093=vc->eqExpr(id2077,id855); Expr id2092=vc->notExpr(id2093); vc->registerAtom(id2093); Expr id2099=vc->eqExpr(id895,id857); Expr id2098=vc->notExpr(id2099); vc->registerAtom(id2099); Expr id2115=vc->eqExpr(id895,id847); Expr id2114=vc->notExpr(id2115); vc->registerAtom(id2115); Expr id2119=vc->eqExpr(id875,id857); Expr id2118=vc->notExpr(id2119); vc->registerAtom(id2119); Expr id2127=vc->ratExpr(2,1); Expr id2129=vc->leExpr(id811,id2127); Expr id2128=vc->notExpr(id2129); vc->registerAtom(id2129); Expr id2145=vc->eqExpr(id2127,id857); Expr id2144=vc->notExpr(id2145); vc->registerAtom(id2145); Expr id2163=vc->ratExpr(3,1); Expr id2165=vc->eqExpr(id2163,id857); Expr id2164=vc->notExpr(id2165); vc->registerAtom(id2165); Expr id2185=vc->ratExpr(4,1); Expr id2187=vc->eqExpr(id2185,id857); Expr id2186=vc->notExpr(id2187); vc->registerAtom(id2187); Expr id2209=vc->eqExpr(id1619,id847); Expr id2208=vc->notExpr(id2209); vc->registerAtom(id2209); Expr id2225=vc->eqExpr(id1621,id857); Expr id2224=vc->notExpr(id2225); vc->registerAtom(id2225); Expr id2239=vc->eqExpr(id895,id859); Expr id2238=vc->notExpr(id2239); vc->registerAtom(id2239); Expr id2259=vc->eqExpr(id875,id859); Expr id2258=vc->notExpr(id2259); vc->registerAtom(id2259); Expr id2267=vc->eqExpr(id875,id817); Expr id2266=vc->notExpr(id2267); vc->registerAtom(id2267); Expr id2283=vc->eqExpr(id2127,id859); Expr id2282=vc->notExpr(id2283); vc->registerAtom(id2283); Expr id2305=vc->eqExpr(id2163,id859); Expr id2304=vc->notExpr(id2305); vc->registerAtom(id2305); Expr id2325=vc->eqExpr(id2185,id859); Expr id2324=vc->notExpr(id2325); vc->registerAtom(id2325); Expr id2341=vc->eqExpr(id1625,id853); Expr id2340=vc->notExpr(id2341); vc->registerAtom(id2341); Expr id2357=vc->eqExpr(id1621,id859); Expr id2356=vc->notExpr(id2357); vc->registerAtom(id2357); Expr id2375=vc->eqExpr(id895,id861); Expr id2374=vc->notExpr(id2375); vc->registerAtom(id2375); Expr id2395=vc->eqExpr(id875,id861); Expr id2394=vc->notExpr(id2395); vc->registerAtom(id2395); Expr id2413=vc->eqExpr(id2127,id861); Expr id2412=vc->notExpr(id2413); vc->registerAtom(id2413); Expr id2435=vc->eqExpr(id2163,id861); Expr id2434=vc->notExpr(id2435); vc->registerAtom(id2435); Expr id2443=vc->ltExpr(id797,id875); Expr id2442=vc->notExpr(id2443); vc->registerAtom(id2443); Expr id2459=vc->eqExpr(id2185,id861); Expr id2458=vc->notExpr(id2459); vc->registerAtom(id2459); Expr id2465=vc->plusExpr(id797,id127); Expr id2467=vc->leExpr(id2465,id875); Expr id2466=vc->notExpr(id2467); vc->registerAtom(id2467); Expr id2475=vc->leExpr(id2465,id2127); Expr id2474=vc->notExpr(id2475); vc->registerAtom(id2475); Expr id2481=vc->eqExpr(id2465,id833); Expr id2480=vc->notExpr(id2481); vc->registerAtom(id2481); Expr id2491=vc->eqExpr(id1621,id861); Expr id2490=vc->notExpr(id2491); vc->registerAtom(id2491); Expr id2511=vc->varExpr("2509_c",id9); Expr id2513=vc->eqExpr(id2511,id895); Expr id2512=vc->notExpr(id2513); vc->registerAtom(id2513); Expr id2515=vc->eqExpr(id2511,id875); Expr id2514=vc->notExpr(id2515); vc->registerAtom(id2515); Expr id2527=vc->eqExpr(id2511,id819); Expr id2526=vc->notExpr(id2527); vc->registerAtom(id2527); Expr id2533=vc->eqExpr(id895,id821); Expr id2532=vc->notExpr(id2533); vc->registerAtom(id2533); Expr id2549=vc->eqExpr(id895,id811); Expr id2548=vc->notExpr(id2549); vc->registerAtom(id2549); Expr id2553=vc->eqExpr(id875,id821); Expr id2552=vc->notExpr(id2553); vc->registerAtom(id2553); Expr id2561=vc->leExpr(id775,id2127); Expr id2560=vc->notExpr(id2561); vc->registerAtom(id2561); Expr id2577=vc->eqExpr(id2127,id821); Expr id2576=vc->notExpr(id2577); vc->registerAtom(id2577); Expr id2595=vc->eqExpr(id2163,id821); Expr id2594=vc->notExpr(id2595); vc->registerAtom(id2595); Expr id2615=vc->eqExpr(id2185,id821); Expr id2614=vc->notExpr(id2615); vc->registerAtom(id2615); Expr id2637=vc->eqExpr(id1629,id811); Expr id2636=vc->notExpr(id2637); vc->registerAtom(id2637); Expr id2653=vc->eqExpr(id1621,id821); Expr id2652=vc->notExpr(id2653); vc->registerAtom(id2653); Expr id2667=vc->eqExpr(id895,id823); Expr id2666=vc->notExpr(id2667); vc->registerAtom(id2667); Expr id2687=vc->eqExpr(id875,id823); Expr id2686=vc->notExpr(id2687); vc->registerAtom(id2687); Expr id2695=vc->eqExpr(id875,id781); Expr id2694=vc->notExpr(id2695); vc->registerAtom(id2695); Expr id2711=vc->eqExpr(id2127,id823); Expr id2710=vc->notExpr(id2711); vc->registerAtom(id2711); Expr id2733=vc->eqExpr(id2163,id823); Expr id2732=vc->notExpr(id2733); vc->registerAtom(id2733); Expr id2753=vc->eqExpr(id2185,id823); Expr id2752=vc->notExpr(id2753); vc->registerAtom(id2753); Expr id2769=vc->eqExpr(id1633,id817); Expr id2768=vc->notExpr(id2769); vc->registerAtom(id2769); Expr id2785=vc->eqExpr(id1621,id823); Expr id2784=vc->notExpr(id2785); vc->registerAtom(id2785); Expr id2803=vc->eqExpr(id895,id825); Expr id2802=vc->notExpr(id2803); vc->registerAtom(id2803); Expr id2823=vc->eqExpr(id875,id825); Expr id2822=vc->notExpr(id2823); vc->registerAtom(id2823); Expr id2841=vc->eqExpr(id2127,id825); Expr id2840=vc->notExpr(id2841); vc->registerAtom(id2841); Expr id2863=vc->eqExpr(id2163,id825); Expr id2862=vc->notExpr(id2863); vc->registerAtom(id2863); Expr id2871=vc->ltExpr(id761,id875); Expr id2870=vc->notExpr(id2871); vc->registerAtom(id2871); Expr id2887=vc->eqExpr(id2185,id825); Expr id2886=vc->notExpr(id2887); vc->registerAtom(id2887); Expr id2893=vc->plusExpr(id761,id125); Expr id2895=vc->leExpr(id2893,id875); Expr id2894=vc->notExpr(id2895); vc->registerAtom(id2895); Expr id2903=vc->leExpr(id2893,id2127); Expr id2902=vc->notExpr(id2903); vc->registerAtom(id2903); Expr id2909=vc->eqExpr(id2893,id797); Expr id2908=vc->notExpr(id2909); vc->registerAtom(id2909); Expr id2919=vc->eqExpr(id1621,id825); Expr id2918=vc->notExpr(id2919); vc->registerAtom(id2919); Expr id2939=vc->varExpr("2937_c",id9); Expr id2941=vc->eqExpr(id2939,id895); Expr id2940=vc->notExpr(id2941); vc->registerAtom(id2941); Expr id2943=vc->eqExpr(id2939,id875); Expr id2942=vc->notExpr(id2943); vc->registerAtom(id2943); Expr id2955=vc->eqExpr(id2939,id783); Expr id2954=vc->notExpr(id2955); vc->registerAtom(id2955); Expr id2961=vc->eqExpr(id895,id785); Expr id2960=vc->notExpr(id2961); vc->registerAtom(id2961); Expr id2977=vc->eqExpr(id895,id775); Expr id2976=vc->notExpr(id2977); vc->registerAtom(id2977); Expr id2981=vc->eqExpr(id875,id785); Expr id2980=vc->notExpr(id2981); vc->registerAtom(id2981); Expr id2989=vc->leExpr(id739,id2127); Expr id2988=vc->notExpr(id2989); vc->registerAtom(id2989); Expr id3005=vc->eqExpr(id2127,id785); Expr id3004=vc->notExpr(id3005); vc->registerAtom(id3005); Expr id3023=vc->eqExpr(id2163,id785); Expr id3022=vc->notExpr(id3023); vc->registerAtom(id3023); Expr id3043=vc->eqExpr(id2185,id785); Expr id3042=vc->notExpr(id3043); vc->registerAtom(id3043); Expr id3065=vc->eqExpr(id1637,id775); Expr id3064=vc->notExpr(id3065); vc->registerAtom(id3065); Expr id3081=vc->eqExpr(id1621,id785); Expr id3080=vc->notExpr(id3081); vc->registerAtom(id3081); Expr id3095=vc->eqExpr(id895,id787); Expr id3094=vc->notExpr(id3095); vc->registerAtom(id3095); Expr id3115=vc->eqExpr(id875,id787); Expr id3114=vc->notExpr(id3115); vc->registerAtom(id3115); Expr id3123=vc->eqExpr(id875,id745); Expr id3122=vc->notExpr(id3123); vc->registerAtom(id3123); Expr id3139=vc->eqExpr(id2127,id787); Expr id3138=vc->notExpr(id3139); vc->registerAtom(id3139); Expr id3161=vc->eqExpr(id2163,id787); Expr id3160=vc->notExpr(id3161); vc->registerAtom(id3161); Expr id3181=vc->eqExpr(id2185,id787); Expr id3180=vc->notExpr(id3181); vc->registerAtom(id3181); Expr id3197=vc->eqExpr(id1641,id781); Expr id3196=vc->notExpr(id3197); vc->registerAtom(id3197); Expr id3213=vc->eqExpr(id1621,id787); Expr id3212=vc->notExpr(id3213); vc->registerAtom(id3213); Expr id3231=vc->eqExpr(id895,id789); Expr id3230=vc->notExpr(id3231); vc->registerAtom(id3231); Expr id3251=vc->eqExpr(id875,id789); Expr id3250=vc->notExpr(id3251); vc->registerAtom(id3251); Expr id3269=vc->eqExpr(id2127,id789); Expr id3268=vc->notExpr(id3269); vc->registerAtom(id3269); Expr id3291=vc->eqExpr(id2163,id789); Expr id3290=vc->notExpr(id3291); vc->registerAtom(id3291); Expr id3299=vc->ltExpr(id725,id875); Expr id3298=vc->notExpr(id3299); vc->registerAtom(id3299); Expr id3315=vc->eqExpr(id2185,id789); Expr id3314=vc->notExpr(id3315); vc->registerAtom(id3315); Expr id3321=vc->plusExpr(id725,id123); Expr id3323=vc->leExpr(id3321,id875); Expr id3322=vc->notExpr(id3323); vc->registerAtom(id3323); Expr id3331=vc->leExpr(id3321,id2127); Expr id3330=vc->notExpr(id3331); vc->registerAtom(id3331); Expr id3337=vc->eqExpr(id3321,id761); Expr id3336=vc->notExpr(id3337); vc->registerAtom(id3337); Expr id3347=vc->eqExpr(id1621,id789); Expr id3346=vc->notExpr(id3347); vc->registerAtom(id3347); Expr id3367=vc->varExpr("3365_c",id9); Expr id3369=vc->eqExpr(id3367,id895); Expr id3368=vc->notExpr(id3369); vc->registerAtom(id3369); Expr id3371=vc->eqExpr(id3367,id875); Expr id3370=vc->notExpr(id3371); vc->registerAtom(id3371); Expr id3383=vc->eqExpr(id3367,id747); Expr id3382=vc->notExpr(id3383); vc->registerAtom(id3383); Expr id3389=vc->eqExpr(id895,id749); Expr id3388=vc->notExpr(id3389); vc->registerAtom(id3389); Expr id3405=vc->eqExpr(id895,id739); Expr id3404=vc->notExpr(id3405); vc->registerAtom(id3405); Expr id3409=vc->eqExpr(id875,id749); Expr id3408=vc->notExpr(id3409); vc->registerAtom(id3409); Expr id3417=vc->leExpr(id703,id2127); Expr id3416=vc->notExpr(id3417); vc->registerAtom(id3417); Expr id3433=vc->eqExpr(id2127,id749); Expr id3432=vc->notExpr(id3433); vc->registerAtom(id3433); Expr id3451=vc->eqExpr(id2163,id749); Expr id3450=vc->notExpr(id3451); vc->registerAtom(id3451); Expr id3471=vc->eqExpr(id2185,id749); Expr id3470=vc->notExpr(id3471); vc->registerAtom(id3471); Expr id3493=vc->eqExpr(id1645,id739); Expr id3492=vc->notExpr(id3493); vc->registerAtom(id3493); Expr id3509=vc->eqExpr(id1621,id749); Expr id3508=vc->notExpr(id3509); vc->registerAtom(id3509); Expr id3523=vc->eqExpr(id895,id751); Expr id3522=vc->notExpr(id3523); vc->registerAtom(id3523); Expr id3543=vc->eqExpr(id875,id751); Expr id3542=vc->notExpr(id3543); vc->registerAtom(id3543); Expr id3551=vc->eqExpr(id875,id709); Expr id3550=vc->notExpr(id3551); vc->registerAtom(id3551); Expr id3567=vc->eqExpr(id2127,id751); Expr id3566=vc->notExpr(id3567); vc->registerAtom(id3567); Expr id3589=vc->eqExpr(id2163,id751); Expr id3588=vc->notExpr(id3589); vc->registerAtom(id3589); Expr id3609=vc->eqExpr(id2185,id751); Expr id3608=vc->notExpr(id3609); vc->registerAtom(id3609); Expr id3625=vc->eqExpr(id1649,id745); Expr id3624=vc->notExpr(id3625); vc->registerAtom(id3625); Expr id3641=vc->eqExpr(id1621,id751); Expr id3640=vc->notExpr(id3641); vc->registerAtom(id3641); Expr id3659=vc->eqExpr(id895,id753); Expr id3658=vc->notExpr(id3659); vc->registerAtom(id3659); Expr id3679=vc->eqExpr(id875,id753); Expr id3678=vc->notExpr(id3679); vc->registerAtom(id3679); Expr id3697=vc->eqExpr(id2127,id753); Expr id3696=vc->notExpr(id3697); vc->registerAtom(id3697); Expr id3719=vc->eqExpr(id2163,id753); Expr id3718=vc->notExpr(id3719); vc->registerAtom(id3719); Expr id3727=vc->ltExpr(id689,id875); Expr id3726=vc->notExpr(id3727); vc->registerAtom(id3727); Expr id3743=vc->eqExpr(id2185,id753); Expr id3742=vc->notExpr(id3743); vc->registerAtom(id3743); Expr id3749=vc->plusExpr(id689,id121); Expr id3751=vc->leExpr(id3749,id875); Expr id3750=vc->notExpr(id3751); vc->registerAtom(id3751); Expr id3759=vc->leExpr(id3749,id2127); Expr id3758=vc->notExpr(id3759); vc->registerAtom(id3759); Expr id3765=vc->eqExpr(id3749,id725); Expr id3764=vc->notExpr(id3765); vc->registerAtom(id3765); Expr id3775=vc->eqExpr(id1621,id753); Expr id3774=vc->notExpr(id3775); vc->registerAtom(id3775); Expr id3795=vc->varExpr("3793_c",id9); Expr id3797=vc->eqExpr(id3795,id895); Expr id3796=vc->notExpr(id3797); vc->registerAtom(id3797); Expr id3799=vc->eqExpr(id3795,id875); Expr id3798=vc->notExpr(id3799); vc->registerAtom(id3799); Expr id3811=vc->eqExpr(id3795,id711); Expr id3810=vc->notExpr(id3811); vc->registerAtom(id3811); Expr id3817=vc->eqExpr(id895,id713); Expr id3816=vc->notExpr(id3817); vc->registerAtom(id3817); Expr id3833=vc->eqExpr(id895,id703); Expr id3832=vc->notExpr(id3833); vc->registerAtom(id3833); Expr id3837=vc->eqExpr(id875,id713); Expr id3836=vc->notExpr(id3837); vc->registerAtom(id3837); Expr id3845=vc->leExpr(id667,id2127); Expr id3844=vc->notExpr(id3845); vc->registerAtom(id3845); Expr id3861=vc->eqExpr(id2127,id713); Expr id3860=vc->notExpr(id3861); vc->registerAtom(id3861); Expr id3879=vc->eqExpr(id2163,id713); Expr id3878=vc->notExpr(id3879); vc->registerAtom(id3879); Expr id3899=vc->eqExpr(id2185,id713); Expr id3898=vc->notExpr(id3899); vc->registerAtom(id3899); Expr id3921=vc->eqExpr(id1653,id703); Expr id3920=vc->notExpr(id3921); vc->registerAtom(id3921); Expr id3937=vc->eqExpr(id1621,id713); Expr id3936=vc->notExpr(id3937); vc->registerAtom(id3937); Expr id3951=vc->eqExpr(id895,id715); Expr id3950=vc->notExpr(id3951); vc->registerAtom(id3951); Expr id3971=vc->eqExpr(id875,id715); Expr id3970=vc->notExpr(id3971); vc->registerAtom(id3971); Expr id3979=vc->eqExpr(id875,id673); Expr id3978=vc->notExpr(id3979); vc->registerAtom(id3979); Expr id3995=vc->eqExpr(id2127,id715); Expr id3994=vc->notExpr(id3995); vc->registerAtom(id3995); Expr id4017=vc->eqExpr(id2163,id715); Expr id4016=vc->notExpr(id4017); vc->registerAtom(id4017); Expr id4037=vc->eqExpr(id2185,id715); Expr id4036=vc->notExpr(id4037); vc->registerAtom(id4037); Expr id4053=vc->eqExpr(id1657,id709); Expr id4052=vc->notExpr(id4053); vc->registerAtom(id4053); Expr id4069=vc->eqExpr(id1621,id715); Expr id4068=vc->notExpr(id4069); vc->registerAtom(id4069); Expr id4087=vc->eqExpr(id895,id717); Expr id4086=vc->notExpr(id4087); vc->registerAtom(id4087); Expr id4107=vc->eqExpr(id875,id717); Expr id4106=vc->notExpr(id4107); vc->registerAtom(id4107); Expr id4125=vc->eqExpr(id2127,id717); Expr id4124=vc->notExpr(id4125); vc->registerAtom(id4125); Expr id4147=vc->eqExpr(id2163,id717); Expr id4146=vc->notExpr(id4147); vc->registerAtom(id4147); Expr id4155=vc->ltExpr(id653,id875); Expr id4154=vc->notExpr(id4155); vc->registerAtom(id4155); Expr id4171=vc->eqExpr(id2185,id717); Expr id4170=vc->notExpr(id4171); vc->registerAtom(id4171); Expr id4177=vc->plusExpr(id653,id119); Expr id4179=vc->leExpr(id4177,id875); Expr id4178=vc->notExpr(id4179); vc->registerAtom(id4179); Expr id4187=vc->leExpr(id4177,id2127); Expr id4186=vc->notExpr(id4187); vc->registerAtom(id4187); Expr id4193=vc->eqExpr(id4177,id689); Expr id4192=vc->notExpr(id4193); vc->registerAtom(id4193); Expr id4203=vc->eqExpr(id1621,id717); Expr id4202=vc->notExpr(id4203); vc->registerAtom(id4203); Expr id4223=vc->varExpr("4221_c",id9); Expr id4225=vc->eqExpr(id4223,id895); Expr id4224=vc->notExpr(id4225); vc->registerAtom(id4225); Expr id4227=vc->eqExpr(id4223,id875); Expr id4226=vc->notExpr(id4227); vc->registerAtom(id4227); Expr id4239=vc->eqExpr(id4223,id675); Expr id4238=vc->notExpr(id4239); vc->registerAtom(id4239); Expr id4245=vc->eqExpr(id895,id677); Expr id4244=vc->notExpr(id4245); vc->registerAtom(id4245); Expr id4261=vc->eqExpr(id895,id667); Expr id4260=vc->notExpr(id4261); vc->registerAtom(id4261); Expr id4265=vc->eqExpr(id875,id677); Expr id4264=vc->notExpr(id4265); vc->registerAtom(id4265); Expr id4273=vc->leExpr(id631,id2127); Expr id4272=vc->notExpr(id4273); vc->registerAtom(id4273); Expr id4289=vc->eqExpr(id2127,id677); Expr id4288=vc->notExpr(id4289); vc->registerAtom(id4289); Expr id4307=vc->eqExpr(id2163,id677); Expr id4306=vc->notExpr(id4307); vc->registerAtom(id4307); Expr id4327=vc->eqExpr(id2185,id677); Expr id4326=vc->notExpr(id4327); vc->registerAtom(id4327); Expr id4349=vc->eqExpr(id1661,id667); Expr id4348=vc->notExpr(id4349); vc->registerAtom(id4349); Expr id4365=vc->eqExpr(id1621,id677); Expr id4364=vc->notExpr(id4365); vc->registerAtom(id4365); Expr id4379=vc->eqExpr(id895,id679); Expr id4378=vc->notExpr(id4379); vc->registerAtom(id4379); Expr id4399=vc->eqExpr(id875,id679); Expr id4398=vc->notExpr(id4399); vc->registerAtom(id4399); Expr id4407=vc->eqExpr(id875,id637); Expr id4406=vc->notExpr(id4407); vc->registerAtom(id4407); Expr id4423=vc->eqExpr(id2127,id679); Expr id4422=vc->notExpr(id4423); vc->registerAtom(id4423); Expr id4445=vc->eqExpr(id2163,id679); Expr id4444=vc->notExpr(id4445); vc->registerAtom(id4445); Expr id4465=vc->eqExpr(id2185,id679); Expr id4464=vc->notExpr(id4465); vc->registerAtom(id4465); Expr id4481=vc->eqExpr(id1665,id673); Expr id4480=vc->notExpr(id4481); vc->registerAtom(id4481); Expr id4497=vc->eqExpr(id1621,id679); Expr id4496=vc->notExpr(id4497); vc->registerAtom(id4497); Expr id4515=vc->eqExpr(id895,id681); Expr id4514=vc->notExpr(id4515); vc->registerAtom(id4515); Expr id4535=vc->eqExpr(id875,id681); Expr id4534=vc->notExpr(id4535); vc->registerAtom(id4535); Expr id4553=vc->eqExpr(id2127,id681); Expr id4552=vc->notExpr(id4553); vc->registerAtom(id4553); Expr id4575=vc->eqExpr(id2163,id681); Expr id4574=vc->notExpr(id4575); vc->registerAtom(id4575); Expr id4583=vc->ltExpr(id617,id875); Expr id4582=vc->notExpr(id4583); vc->registerAtom(id4583); Expr id4599=vc->eqExpr(id2185,id681); Expr id4598=vc->notExpr(id4599); vc->registerAtom(id4599); Expr id4605=vc->plusExpr(id617,id117); Expr id4607=vc->leExpr(id4605,id875); Expr id4606=vc->notExpr(id4607); vc->registerAtom(id4607); Expr id4615=vc->leExpr(id4605,id2127); Expr id4614=vc->notExpr(id4615); vc->registerAtom(id4615); Expr id4621=vc->eqExpr(id4605,id653); Expr id4620=vc->notExpr(id4621); vc->registerAtom(id4621); Expr id4631=vc->eqExpr(id1621,id681); Expr id4630=vc->notExpr(id4631); vc->registerAtom(id4631); Expr id4651=vc->varExpr("4649_c",id9); Expr id4653=vc->eqExpr(id4651,id895); Expr id4652=vc->notExpr(id4653); vc->registerAtom(id4653); Expr id4655=vc->eqExpr(id4651,id875); Expr id4654=vc->notExpr(id4655); vc->registerAtom(id4655); Expr id4667=vc->eqExpr(id4651,id639); Expr id4666=vc->notExpr(id4667); vc->registerAtom(id4667); Expr id4673=vc->eqExpr(id895,id641); Expr id4672=vc->notExpr(id4673); vc->registerAtom(id4673); Expr id4689=vc->eqExpr(id895,id631); Expr id4688=vc->notExpr(id4689); vc->registerAtom(id4689); Expr id4693=vc->eqExpr(id875,id641); Expr id4692=vc->notExpr(id4693); vc->registerAtom(id4693); Expr id4701=vc->leExpr(id595,id2127); Expr id4700=vc->notExpr(id4701); vc->registerAtom(id4701); Expr id4717=vc->eqExpr(id2127,id641); Expr id4716=vc->notExpr(id4717); vc->registerAtom(id4717); Expr id4735=vc->eqExpr(id2163,id641); Expr id4734=vc->notExpr(id4735); vc->registerAtom(id4735); Expr id4755=vc->eqExpr(id2185,id641); Expr id4754=vc->notExpr(id4755); vc->registerAtom(id4755); Expr id4777=vc->eqExpr(id1669,id631); Expr id4776=vc->notExpr(id4777); vc->registerAtom(id4777); Expr id4793=vc->eqExpr(id1621,id641); Expr id4792=vc->notExpr(id4793); vc->registerAtom(id4793); Expr id4807=vc->eqExpr(id895,id643); Expr id4806=vc->notExpr(id4807); vc->registerAtom(id4807); Expr id4827=vc->eqExpr(id875,id643); Expr id4826=vc->notExpr(id4827); vc->registerAtom(id4827); Expr id4835=vc->eqExpr(id875,id601); Expr id4834=vc->notExpr(id4835); vc->registerAtom(id4835); Expr id4851=vc->eqExpr(id2127,id643); Expr id4850=vc->notExpr(id4851); vc->registerAtom(id4851); Expr id4873=vc->eqExpr(id2163,id643); Expr id4872=vc->notExpr(id4873); vc->registerAtom(id4873); Expr id4893=vc->eqExpr(id2185,id643); Expr id4892=vc->notExpr(id4893); vc->registerAtom(id4893); Expr id4909=vc->eqExpr(id1673,id637); Expr id4908=vc->notExpr(id4909); vc->registerAtom(id4909); Expr id4925=vc->eqExpr(id1621,id643); Expr id4924=vc->notExpr(id4925); vc->registerAtom(id4925); Expr id4943=vc->eqExpr(id895,id645); Expr id4942=vc->notExpr(id4943); vc->registerAtom(id4943); Expr id4963=vc->eqExpr(id875,id645); Expr id4962=vc->notExpr(id4963); vc->registerAtom(id4963); Expr id4981=vc->eqExpr(id2127,id645); Expr id4980=vc->notExpr(id4981); vc->registerAtom(id4981); Expr id5003=vc->eqExpr(id2163,id645); Expr id5002=vc->notExpr(id5003); vc->registerAtom(id5003); Expr id5011=vc->ltExpr(id581,id875); Expr id5010=vc->notExpr(id5011); vc->registerAtom(id5011); Expr id5027=vc->eqExpr(id2185,id645); Expr id5026=vc->notExpr(id5027); vc->registerAtom(id5027); Expr id5033=vc->plusExpr(id581,id115); Expr id5035=vc->leExpr(id5033,id875); Expr id5034=vc->notExpr(id5035); vc->registerAtom(id5035); Expr id5043=vc->leExpr(id5033,id2127); Expr id5042=vc->notExpr(id5043); vc->registerAtom(id5043); Expr id5049=vc->eqExpr(id5033,id617); Expr id5048=vc->notExpr(id5049); vc->registerAtom(id5049); Expr id5059=vc->eqExpr(id1621,id645); Expr id5058=vc->notExpr(id5059); vc->registerAtom(id5059); Expr id5079=vc->varExpr("5077_c",id9); Expr id5081=vc->eqExpr(id5079,id895); Expr id5080=vc->notExpr(id5081); vc->registerAtom(id5081); Expr id5083=vc->eqExpr(id5079,id875); Expr id5082=vc->notExpr(id5083); vc->registerAtom(id5083); Expr id5095=vc->eqExpr(id5079,id603); Expr id5094=vc->notExpr(id5095); vc->registerAtom(id5095); Expr id5101=vc->eqExpr(id895,id605); Expr id5100=vc->notExpr(id5101); vc->registerAtom(id5101); Expr id5117=vc->eqExpr(id895,id595); Expr id5116=vc->notExpr(id5117); vc->registerAtom(id5117); Expr id5121=vc->eqExpr(id875,id605); Expr id5120=vc->notExpr(id5121); vc->registerAtom(id5121); Expr id5129=vc->leExpr(id559,id2127); Expr id5128=vc->notExpr(id5129); vc->registerAtom(id5129); Expr id5145=vc->eqExpr(id2127,id605); Expr id5144=vc->notExpr(id5145); vc->registerAtom(id5145); Expr id5163=vc->eqExpr(id2163,id605); Expr id5162=vc->notExpr(id5163); vc->registerAtom(id5163); Expr id5183=vc->eqExpr(id2185,id605); Expr id5182=vc->notExpr(id5183); vc->registerAtom(id5183); Expr id5205=vc->eqExpr(id1677,id595); Expr id5204=vc->notExpr(id5205); vc->registerAtom(id5205); Expr id5221=vc->eqExpr(id1621,id605); Expr id5220=vc->notExpr(id5221); vc->registerAtom(id5221); Expr id5235=vc->eqExpr(id895,id607); Expr id5234=vc->notExpr(id5235); vc->registerAtom(id5235); Expr id5255=vc->eqExpr(id875,id607); Expr id5254=vc->notExpr(id5255); vc->registerAtom(id5255); Expr id5263=vc->eqExpr(id875,id565); Expr id5262=vc->notExpr(id5263); vc->registerAtom(id5263); Expr id5279=vc->eqExpr(id2127,id607); Expr id5278=vc->notExpr(id5279); vc->registerAtom(id5279); Expr id5301=vc->eqExpr(id2163,id607); Expr id5300=vc->notExpr(id5301); vc->registerAtom(id5301); Expr id5321=vc->eqExpr(id2185,id607); Expr id5320=vc->notExpr(id5321); vc->registerAtom(id5321); Expr id5337=vc->eqExpr(id1681,id601); Expr id5336=vc->notExpr(id5337); vc->registerAtom(id5337); Expr id5353=vc->eqExpr(id1621,id607); Expr id5352=vc->notExpr(id5353); vc->registerAtom(id5353); Expr id5371=vc->eqExpr(id895,id609); Expr id5370=vc->notExpr(id5371); vc->registerAtom(id5371); Expr id5391=vc->eqExpr(id875,id609); Expr id5390=vc->notExpr(id5391); vc->registerAtom(id5391); Expr id5409=vc->eqExpr(id2127,id609); Expr id5408=vc->notExpr(id5409); vc->registerAtom(id5409); Expr id5431=vc->eqExpr(id2163,id609); Expr id5430=vc->notExpr(id5431); vc->registerAtom(id5431); Expr id5439=vc->ltExpr(id545,id875); Expr id5438=vc->notExpr(id5439); vc->registerAtom(id5439); Expr id5455=vc->eqExpr(id2185,id609); Expr id5454=vc->notExpr(id5455); vc->registerAtom(id5455); Expr id5461=vc->plusExpr(id545,id113); Expr id5463=vc->leExpr(id5461,id875); Expr id5462=vc->notExpr(id5463); vc->registerAtom(id5463); Expr id5471=vc->leExpr(id5461,id2127); Expr id5470=vc->notExpr(id5471); vc->registerAtom(id5471); Expr id5477=vc->eqExpr(id5461,id581); Expr id5476=vc->notExpr(id5477); vc->registerAtom(id5477); Expr id5487=vc->eqExpr(id1621,id609); Expr id5486=vc->notExpr(id5487); vc->registerAtom(id5487); Expr id5507=vc->varExpr("5505_c",id9); Expr id5509=vc->eqExpr(id5507,id895); Expr id5508=vc->notExpr(id5509); vc->registerAtom(id5509); Expr id5511=vc->eqExpr(id5507,id875); Expr id5510=vc->notExpr(id5511); vc->registerAtom(id5511); Expr id5523=vc->eqExpr(id5507,id567); Expr id5522=vc->notExpr(id5523); vc->registerAtom(id5523); Expr id5529=vc->eqExpr(id895,id569); Expr id5528=vc->notExpr(id5529); vc->registerAtom(id5529); Expr id5545=vc->eqExpr(id895,id559); Expr id5544=vc->notExpr(id5545); vc->registerAtom(id5545); Expr id5549=vc->eqExpr(id875,id569); Expr id5548=vc->notExpr(id5549); vc->registerAtom(id5549); Expr id5557=vc->leExpr(id523,id2127); Expr id5556=vc->notExpr(id5557); vc->registerAtom(id5557); Expr id5573=vc->eqExpr(id2127,id569); Expr id5572=vc->notExpr(id5573); vc->registerAtom(id5573); Expr id5591=vc->eqExpr(id2163,id569); Expr id5590=vc->notExpr(id5591); vc->registerAtom(id5591); Expr id5611=vc->eqExpr(id2185,id569); Expr id5610=vc->notExpr(id5611); vc->registerAtom(id5611); Expr id5633=vc->eqExpr(id1685,id559); Expr id5632=vc->notExpr(id5633); vc->registerAtom(id5633); Expr id5649=vc->eqExpr(id1621,id569); Expr id5648=vc->notExpr(id5649); vc->registerAtom(id5649); Expr id5663=vc->eqExpr(id895,id571); Expr id5662=vc->notExpr(id5663); vc->registerAtom(id5663); Expr id5683=vc->eqExpr(id875,id571); Expr id5682=vc->notExpr(id5683); vc->registerAtom(id5683); Expr id5691=vc->eqExpr(id875,id529); Expr id5690=vc->notExpr(id5691); vc->registerAtom(id5691); Expr id5707=vc->eqExpr(id2127,id571); Expr id5706=vc->notExpr(id5707); vc->registerAtom(id5707); Expr id5729=vc->eqExpr(id2163,id571); Expr id5728=vc->notExpr(id5729); vc->registerAtom(id5729); Expr id5749=vc->eqExpr(id2185,id571); Expr id5748=vc->notExpr(id5749); vc->registerAtom(id5749); Expr id5765=vc->eqExpr(id1689,id565); Expr id5764=vc->notExpr(id5765); vc->registerAtom(id5765); Expr id5781=vc->eqExpr(id1621,id571); Expr id5780=vc->notExpr(id5781); vc->registerAtom(id5781); Expr id5799=vc->eqExpr(id895,id573); Expr id5798=vc->notExpr(id5799); vc->registerAtom(id5799); Expr id5819=vc->eqExpr(id875,id573); Expr id5818=vc->notExpr(id5819); vc->registerAtom(id5819); Expr id5837=vc->eqExpr(id2127,id573); Expr id5836=vc->notExpr(id5837); vc->registerAtom(id5837); Expr id5859=vc->eqExpr(id2163,id573); Expr id5858=vc->notExpr(id5859); vc->registerAtom(id5859); Expr id5867=vc->ltExpr(id509,id875); Expr id5866=vc->notExpr(id5867); vc->registerAtom(id5867); Expr id5883=vc->eqExpr(id2185,id573); Expr id5882=vc->notExpr(id5883); vc->registerAtom(id5883); Expr id5889=vc->plusExpr(id509,id111); Expr id5891=vc->leExpr(id5889,id875); Expr id5890=vc->notExpr(id5891); vc->registerAtom(id5891); Expr id5899=vc->leExpr(id5889,id2127); Expr id5898=vc->notExpr(id5899); vc->registerAtom(id5899); Expr id5905=vc->eqExpr(id5889,id545); Expr id5904=vc->notExpr(id5905); vc->registerAtom(id5905); Expr id5915=vc->eqExpr(id1621,id573); Expr id5914=vc->notExpr(id5915); vc->registerAtom(id5915); Expr id5935=vc->varExpr("5933_c",id9); Expr id5937=vc->eqExpr(id5935,id895); Expr id5936=vc->notExpr(id5937); vc->registerAtom(id5937); Expr id5939=vc->eqExpr(id5935,id875); Expr id5938=vc->notExpr(id5939); vc->registerAtom(id5939); Expr id5951=vc->eqExpr(id5935,id531); Expr id5950=vc->notExpr(id5951); vc->registerAtom(id5951); Expr id5957=vc->eqExpr(id895,id533); Expr id5956=vc->notExpr(id5957); vc->registerAtom(id5957); Expr id5973=vc->eqExpr(id895,id523); Expr id5972=vc->notExpr(id5973); vc->registerAtom(id5973); Expr id5977=vc->eqExpr(id875,id533); Expr id5976=vc->notExpr(id5977); vc->registerAtom(id5977); Expr id5985=vc->leExpr(id487,id2127); Expr id5984=vc->notExpr(id5985); vc->registerAtom(id5985); Expr id6001=vc->eqExpr(id2127,id533); Expr id6000=vc->notExpr(id6001); vc->registerAtom(id6001); Expr id6019=vc->eqExpr(id2163,id533); Expr id6018=vc->notExpr(id6019); vc->registerAtom(id6019); Expr id6039=vc->eqExpr(id2185,id533); Expr id6038=vc->notExpr(id6039); vc->registerAtom(id6039); Expr id6061=vc->eqExpr(id1693,id523); Expr id6060=vc->notExpr(id6061); vc->registerAtom(id6061); Expr id6077=vc->eqExpr(id1621,id533); Expr id6076=vc->notExpr(id6077); vc->registerAtom(id6077); Expr id6091=vc->eqExpr(id895,id535); Expr id6090=vc->notExpr(id6091); vc->registerAtom(id6091); Expr id6111=vc->eqExpr(id875,id535); Expr id6110=vc->notExpr(id6111); vc->registerAtom(id6111); Expr id6119=vc->eqExpr(id875,id493); Expr id6118=vc->notExpr(id6119); vc->registerAtom(id6119); Expr id6135=vc->eqExpr(id2127,id535); Expr id6134=vc->notExpr(id6135); vc->registerAtom(id6135); Expr id6157=vc->eqExpr(id2163,id535); Expr id6156=vc->notExpr(id6157); vc->registerAtom(id6157); Expr id6177=vc->eqExpr(id2185,id535); Expr id6176=vc->notExpr(id6177); vc->registerAtom(id6177); Expr id6193=vc->eqExpr(id1697,id529); Expr id6192=vc->notExpr(id6193); vc->registerAtom(id6193); Expr id6209=vc->eqExpr(id1621,id535); Expr id6208=vc->notExpr(id6209); vc->registerAtom(id6209); Expr id6227=vc->eqExpr(id895,id537); Expr id6226=vc->notExpr(id6227); vc->registerAtom(id6227); Expr id6247=vc->eqExpr(id875,id537); Expr id6246=vc->notExpr(id6247); vc->registerAtom(id6247); Expr id6265=vc->eqExpr(id2127,id537); Expr id6264=vc->notExpr(id6265); vc->registerAtom(id6265); Expr id6287=vc->eqExpr(id2163,id537); Expr id6286=vc->notExpr(id6287); vc->registerAtom(id6287); Expr id6295=vc->ltExpr(id473,id875); Expr id6294=vc->notExpr(id6295); vc->registerAtom(id6295); Expr id6311=vc->eqExpr(id2185,id537); Expr id6310=vc->notExpr(id6311); vc->registerAtom(id6311); Expr id6317=vc->plusExpr(id473,id109); Expr id6319=vc->leExpr(id6317,id875); Expr id6318=vc->notExpr(id6319); vc->registerAtom(id6319); Expr id6327=vc->leExpr(id6317,id2127); Expr id6326=vc->notExpr(id6327); vc->registerAtom(id6327); Expr id6333=vc->eqExpr(id6317,id509); Expr id6332=vc->notExpr(id6333); vc->registerAtom(id6333); Expr id6343=vc->eqExpr(id1621,id537); Expr id6342=vc->notExpr(id6343); vc->registerAtom(id6343); Expr id6363=vc->varExpr("6361_c",id9); Expr id6365=vc->eqExpr(id6363,id895); Expr id6364=vc->notExpr(id6365); vc->registerAtom(id6365); Expr id6367=vc->eqExpr(id6363,id875); Expr id6366=vc->notExpr(id6367); vc->registerAtom(id6367); Expr id6379=vc->eqExpr(id6363,id495); Expr id6378=vc->notExpr(id6379); vc->registerAtom(id6379); Expr id6385=vc->eqExpr(id895,id497); Expr id6384=vc->notExpr(id6385); vc->registerAtom(id6385); Expr id6401=vc->eqExpr(id895,id487); Expr id6400=vc->notExpr(id6401); vc->registerAtom(id6401); Expr id6405=vc->eqExpr(id875,id497); Expr id6404=vc->notExpr(id6405); vc->registerAtom(id6405); Expr id6413=vc->leExpr(id451,id2127); Expr id6412=vc->notExpr(id6413); vc->registerAtom(id6413); Expr id6429=vc->eqExpr(id2127,id497); Expr id6428=vc->notExpr(id6429); vc->registerAtom(id6429); Expr id6447=vc->eqExpr(id2163,id497); Expr id6446=vc->notExpr(id6447); vc->registerAtom(id6447); Expr id6467=vc->eqExpr(id2185,id497); Expr id6466=vc->notExpr(id6467); vc->registerAtom(id6467); Expr id6489=vc->eqExpr(id1701,id487); Expr id6488=vc->notExpr(id6489); vc->registerAtom(id6489); Expr id6505=vc->eqExpr(id1621,id497); Expr id6504=vc->notExpr(id6505); vc->registerAtom(id6505); Expr id6519=vc->eqExpr(id895,id499); Expr id6518=vc->notExpr(id6519); vc->registerAtom(id6519); Expr id6539=vc->eqExpr(id875,id499); Expr id6538=vc->notExpr(id6539); vc->registerAtom(id6539); Expr id6547=vc->eqExpr(id875,id457); Expr id6546=vc->notExpr(id6547); vc->registerAtom(id6547); Expr id6563=vc->eqExpr(id2127,id499); Expr id6562=vc->notExpr(id6563); vc->registerAtom(id6563); Expr id6585=vc->eqExpr(id2163,id499); Expr id6584=vc->notExpr(id6585); vc->registerAtom(id6585); Expr id6605=vc->eqExpr(id2185,id499); Expr id6604=vc->notExpr(id6605); vc->registerAtom(id6605); Expr id6621=vc->eqExpr(id1705,id493); Expr id6620=vc->notExpr(id6621); vc->registerAtom(id6621); Expr id6637=vc->eqExpr(id1621,id499); Expr id6636=vc->notExpr(id6637); vc->registerAtom(id6637); Expr id6655=vc->eqExpr(id895,id501); Expr id6654=vc->notExpr(id6655); vc->registerAtom(id6655); Expr id6675=vc->eqExpr(id875,id501); Expr id6674=vc->notExpr(id6675); vc->registerAtom(id6675); Expr id6693=vc->eqExpr(id2127,id501); Expr id6692=vc->notExpr(id6693); vc->registerAtom(id6693); Expr id6715=vc->eqExpr(id2163,id501); Expr id6714=vc->notExpr(id6715); vc->registerAtom(id6715); Expr id6723=vc->ltExpr(id437,id875); Expr id6722=vc->notExpr(id6723); vc->registerAtom(id6723); Expr id6739=vc->eqExpr(id2185,id501); Expr id6738=vc->notExpr(id6739); vc->registerAtom(id6739); Expr id6745=vc->plusExpr(id437,id107); Expr id6747=vc->leExpr(id6745,id875); Expr id6746=vc->notExpr(id6747); vc->registerAtom(id6747); Expr id6755=vc->leExpr(id6745,id2127); Expr id6754=vc->notExpr(id6755); vc->registerAtom(id6755); Expr id6761=vc->eqExpr(id6745,id473); Expr id6760=vc->notExpr(id6761); vc->registerAtom(id6761); Expr id6771=vc->eqExpr(id1621,id501); Expr id6770=vc->notExpr(id6771); vc->registerAtom(id6771); Expr id6791=vc->varExpr("6789_c",id9); Expr id6793=vc->eqExpr(id6791,id895); Expr id6792=vc->notExpr(id6793); vc->registerAtom(id6793); Expr id6795=vc->eqExpr(id6791,id875); Expr id6794=vc->notExpr(id6795); vc->registerAtom(id6795); Expr id6807=vc->eqExpr(id6791,id459); Expr id6806=vc->notExpr(id6807); vc->registerAtom(id6807); Expr id6813=vc->eqExpr(id895,id461); Expr id6812=vc->notExpr(id6813); vc->registerAtom(id6813); Expr id6829=vc->eqExpr(id895,id451); Expr id6828=vc->notExpr(id6829); vc->registerAtom(id6829); Expr id6833=vc->eqExpr(id875,id461); Expr id6832=vc->notExpr(id6833); vc->registerAtom(id6833); Expr id6841=vc->leExpr(id415,id2127); Expr id6840=vc->notExpr(id6841); vc->registerAtom(id6841); Expr id6857=vc->eqExpr(id2127,id461); Expr id6856=vc->notExpr(id6857); vc->registerAtom(id6857); Expr id6875=vc->eqExpr(id2163,id461); Expr id6874=vc->notExpr(id6875); vc->registerAtom(id6875); Expr id6895=vc->eqExpr(id2185,id461); Expr id6894=vc->notExpr(id6895); vc->registerAtom(id6895); Expr id6917=vc->eqExpr(id1709,id451); Expr id6916=vc->notExpr(id6917); vc->registerAtom(id6917); Expr id6933=vc->eqExpr(id1621,id461); Expr id6932=vc->notExpr(id6933); vc->registerAtom(id6933); Expr id6947=vc->eqExpr(id895,id463); Expr id6946=vc->notExpr(id6947); vc->registerAtom(id6947); Expr id6967=vc->eqExpr(id875,id463); Expr id6966=vc->notExpr(id6967); vc->registerAtom(id6967); Expr id6975=vc->eqExpr(id875,id421); Expr id6974=vc->notExpr(id6975); vc->registerAtom(id6975); Expr id6991=vc->eqExpr(id2127,id463); Expr id6990=vc->notExpr(id6991); vc->registerAtom(id6991); Expr id7013=vc->eqExpr(id2163,id463); Expr id7012=vc->notExpr(id7013); vc->registerAtom(id7013); Expr id7033=vc->eqExpr(id2185,id463); Expr id7032=vc->notExpr(id7033); vc->registerAtom(id7033); Expr id7049=vc->eqExpr(id1713,id457); Expr id7048=vc->notExpr(id7049); vc->registerAtom(id7049); Expr id7065=vc->eqExpr(id1621,id463); Expr id7064=vc->notExpr(id7065); vc->registerAtom(id7065); Expr id7083=vc->eqExpr(id895,id465); Expr id7082=vc->notExpr(id7083); vc->registerAtom(id7083); Expr id7103=vc->eqExpr(id875,id465); Expr id7102=vc->notExpr(id7103); vc->registerAtom(id7103); Expr id7121=vc->eqExpr(id2127,id465); Expr id7120=vc->notExpr(id7121); vc->registerAtom(id7121); Expr id7143=vc->eqExpr(id2163,id465); Expr id7142=vc->notExpr(id7143); vc->registerAtom(id7143); Expr id7151=vc->ltExpr(id401,id875); Expr id7150=vc->notExpr(id7151); vc->registerAtom(id7151); Expr id7167=vc->eqExpr(id2185,id465); Expr id7166=vc->notExpr(id7167); vc->registerAtom(id7167); Expr id7173=vc->plusExpr(id401,id105); Expr id7175=vc->leExpr(id7173,id875); Expr id7174=vc->notExpr(id7175); vc->registerAtom(id7175); Expr id7183=vc->leExpr(id7173,id2127); Expr id7182=vc->notExpr(id7183); vc->registerAtom(id7183); Expr id7189=vc->eqExpr(id7173,id437); Expr id7188=vc->notExpr(id7189); vc->registerAtom(id7189); Expr id7199=vc->eqExpr(id1621,id465); Expr id7198=vc->notExpr(id7199); vc->registerAtom(id7199); Expr id7219=vc->varExpr("7217_c",id9); Expr id7221=vc->eqExpr(id7219,id895); Expr id7220=vc->notExpr(id7221); vc->registerAtom(id7221); Expr id7223=vc->eqExpr(id7219,id875); Expr id7222=vc->notExpr(id7223); vc->registerAtom(id7223); Expr id7235=vc->eqExpr(id7219,id423); Expr id7234=vc->notExpr(id7235); vc->registerAtom(id7235); Expr id7241=vc->eqExpr(id895,id425); Expr id7240=vc->notExpr(id7241); vc->registerAtom(id7241); Expr id7257=vc->eqExpr(id895,id415); Expr id7256=vc->notExpr(id7257); vc->registerAtom(id7257); Expr id7261=vc->eqExpr(id875,id425); Expr id7260=vc->notExpr(id7261); vc->registerAtom(id7261); Expr id7269=vc->leExpr(id379,id2127); Expr id7268=vc->notExpr(id7269); vc->registerAtom(id7269); Expr id7285=vc->eqExpr(id2127,id425); Expr id7284=vc->notExpr(id7285); vc->registerAtom(id7285); Expr id7303=vc->eqExpr(id2163,id425); Expr id7302=vc->notExpr(id7303); vc->registerAtom(id7303); Expr id7323=vc->eqExpr(id2185,id425); Expr id7322=vc->notExpr(id7323); vc->registerAtom(id7323); Expr id7345=vc->eqExpr(id1717,id415); Expr id7344=vc->notExpr(id7345); vc->registerAtom(id7345); Expr id7361=vc->eqExpr(id1621,id425); Expr id7360=vc->notExpr(id7361); vc->registerAtom(id7361); Expr id7375=vc->eqExpr(id895,id427); Expr id7374=vc->notExpr(id7375); vc->registerAtom(id7375); Expr id7395=vc->eqExpr(id875,id427); Expr id7394=vc->notExpr(id7395); vc->registerAtom(id7395); Expr id7403=vc->eqExpr(id875,id385); Expr id7402=vc->notExpr(id7403); vc->registerAtom(id7403); Expr id7419=vc->eqExpr(id2127,id427); Expr id7418=vc->notExpr(id7419); vc->registerAtom(id7419); Expr id7441=vc->eqExpr(id2163,id427); Expr id7440=vc->notExpr(id7441); vc->registerAtom(id7441); Expr id7461=vc->eqExpr(id2185,id427); Expr id7460=vc->notExpr(id7461); vc->registerAtom(id7461); Expr id7477=vc->eqExpr(id1721,id421); Expr id7476=vc->notExpr(id7477); vc->registerAtom(id7477); Expr id7493=vc->eqExpr(id1621,id427); Expr id7492=vc->notExpr(id7493); vc->registerAtom(id7493); Expr id7511=vc->eqExpr(id895,id429); Expr id7510=vc->notExpr(id7511); vc->registerAtom(id7511); Expr id7531=vc->eqExpr(id875,id429); Expr id7530=vc->notExpr(id7531); vc->registerAtom(id7531); Expr id7549=vc->eqExpr(id2127,id429); Expr id7548=vc->notExpr(id7549); vc->registerAtom(id7549); Expr id7571=vc->eqExpr(id2163,id429); Expr id7570=vc->notExpr(id7571); vc->registerAtom(id7571); Expr id7579=vc->ltExpr(id365,id875); Expr id7578=vc->notExpr(id7579); vc->registerAtom(id7579); Expr id7595=vc->eqExpr(id2185,id429); Expr id7594=vc->notExpr(id7595); vc->registerAtom(id7595); Expr id7601=vc->plusExpr(id365,id103); Expr id7603=vc->leExpr(id7601,id875); Expr id7602=vc->notExpr(id7603); vc->registerAtom(id7603); Expr id7611=vc->leExpr(id7601,id2127); Expr id7610=vc->notExpr(id7611); vc->registerAtom(id7611); Expr id7617=vc->eqExpr(id7601,id401); Expr id7616=vc->notExpr(id7617); vc->registerAtom(id7617); Expr id7627=vc->eqExpr(id1621,id429); Expr id7626=vc->notExpr(id7627); vc->registerAtom(id7627); Expr id7647=vc->varExpr("7645_c",id9); Expr id7649=vc->eqExpr(id7647,id895); Expr id7648=vc->notExpr(id7649); vc->registerAtom(id7649); Expr id7651=vc->eqExpr(id7647,id875); Expr id7650=vc->notExpr(id7651); vc->registerAtom(id7651); Expr id7663=vc->eqExpr(id7647,id387); Expr id7662=vc->notExpr(id7663); vc->registerAtom(id7663); Expr id7669=vc->eqExpr(id895,id389); Expr id7668=vc->notExpr(id7669); vc->registerAtom(id7669); Expr id7685=vc->eqExpr(id895,id379); Expr id7684=vc->notExpr(id7685); vc->registerAtom(id7685); Expr id7689=vc->eqExpr(id875,id389); Expr id7688=vc->notExpr(id7689); vc->registerAtom(id7689); Expr id7697=vc->leExpr(id343,id2127); Expr id7696=vc->notExpr(id7697); vc->registerAtom(id7697); Expr id7713=vc->eqExpr(id2127,id389); Expr id7712=vc->notExpr(id7713); vc->registerAtom(id7713); Expr id7731=vc->eqExpr(id2163,id389); Expr id7730=vc->notExpr(id7731); vc->registerAtom(id7731); Expr id7751=vc->eqExpr(id2185,id389); Expr id7750=vc->notExpr(id7751); vc->registerAtom(id7751); Expr id7773=vc->eqExpr(id1725,id379); Expr id7772=vc->notExpr(id7773); vc->registerAtom(id7773); Expr id7789=vc->eqExpr(id1621,id389); Expr id7788=vc->notExpr(id7789); vc->registerAtom(id7789); Expr id7803=vc->eqExpr(id895,id391); Expr id7802=vc->notExpr(id7803); vc->registerAtom(id7803); Expr id7823=vc->eqExpr(id875,id391); Expr id7822=vc->notExpr(id7823); vc->registerAtom(id7823); Expr id7831=vc->eqExpr(id875,id349); Expr id7830=vc->notExpr(id7831); vc->registerAtom(id7831); Expr id7847=vc->eqExpr(id2127,id391); Expr id7846=vc->notExpr(id7847); vc->registerAtom(id7847); Expr id7869=vc->eqExpr(id2163,id391); Expr id7868=vc->notExpr(id7869); vc->registerAtom(id7869); Expr id7889=vc->eqExpr(id2185,id391); Expr id7888=vc->notExpr(id7889); vc->registerAtom(id7889); Expr id7905=vc->eqExpr(id1729,id385); Expr id7904=vc->notExpr(id7905); vc->registerAtom(id7905); Expr id7921=vc->eqExpr(id1621,id391); Expr id7920=vc->notExpr(id7921); vc->registerAtom(id7921); Expr id7939=vc->eqExpr(id895,id393); Expr id7938=vc->notExpr(id7939); vc->registerAtom(id7939); Expr id7959=vc->eqExpr(id875,id393); Expr id7958=vc->notExpr(id7959); vc->registerAtom(id7959); Expr id7977=vc->eqExpr(id2127,id393); Expr id7976=vc->notExpr(id7977); vc->registerAtom(id7977); Expr id7999=vc->eqExpr(id2163,id393); Expr id7998=vc->notExpr(id7999); vc->registerAtom(id7999); Expr id8007=vc->ltExpr(id329,id875); Expr id8006=vc->notExpr(id8007); vc->registerAtom(id8007); Expr id8023=vc->eqExpr(id2185,id393); Expr id8022=vc->notExpr(id8023); vc->registerAtom(id8023); Expr id8029=vc->plusExpr(id329,id101); Expr id8031=vc->leExpr(id8029,id875); Expr id8030=vc->notExpr(id8031); vc->registerAtom(id8031); Expr id8039=vc->leExpr(id8029,id2127); Expr id8038=vc->notExpr(id8039); vc->registerAtom(id8039); Expr id8045=vc->eqExpr(id8029,id365); Expr id8044=vc->notExpr(id8045); vc->registerAtom(id8045); Expr id8055=vc->eqExpr(id1621,id393); Expr id8054=vc->notExpr(id8055); vc->registerAtom(id8055); Expr id8075=vc->varExpr("8073_c",id9); Expr id8077=vc->eqExpr(id8075,id895); Expr id8076=vc->notExpr(id8077); vc->registerAtom(id8077); Expr id8079=vc->eqExpr(id8075,id875); Expr id8078=vc->notExpr(id8079); vc->registerAtom(id8079); Expr id8091=vc->eqExpr(id8075,id351); Expr id8090=vc->notExpr(id8091); vc->registerAtom(id8091); Expr id8097=vc->eqExpr(id895,id353); Expr id8096=vc->notExpr(id8097); vc->registerAtom(id8097); Expr id8113=vc->eqExpr(id895,id343); Expr id8112=vc->notExpr(id8113); vc->registerAtom(id8113); Expr id8117=vc->eqExpr(id875,id353); Expr id8116=vc->notExpr(id8117); vc->registerAtom(id8117); Expr id8125=vc->leExpr(id307,id2127); Expr id8124=vc->notExpr(id8125); vc->registerAtom(id8125); Expr id8141=vc->eqExpr(id2127,id353); Expr id8140=vc->notExpr(id8141); vc->registerAtom(id8141); Expr id8159=vc->eqExpr(id2163,id353); Expr id8158=vc->notExpr(id8159); vc->registerAtom(id8159); Expr id8179=vc->eqExpr(id2185,id353); Expr id8178=vc->notExpr(id8179); vc->registerAtom(id8179); Expr id8201=vc->eqExpr(id1733,id343); Expr id8200=vc->notExpr(id8201); vc->registerAtom(id8201); Expr id8217=vc->eqExpr(id1621,id353); Expr id8216=vc->notExpr(id8217); vc->registerAtom(id8217); Expr id8231=vc->eqExpr(id895,id355); Expr id8230=vc->notExpr(id8231); vc->registerAtom(id8231); Expr id8251=vc->eqExpr(id875,id355); Expr id8250=vc->notExpr(id8251); vc->registerAtom(id8251); Expr id8259=vc->eqExpr(id875,id313); Expr id8258=vc->notExpr(id8259); vc->registerAtom(id8259); Expr id8275=vc->eqExpr(id2127,id355); Expr id8274=vc->notExpr(id8275); vc->registerAtom(id8275); Expr id8297=vc->eqExpr(id2163,id355); Expr id8296=vc->notExpr(id8297); vc->registerAtom(id8297); Expr id8317=vc->eqExpr(id2185,id355); Expr id8316=vc->notExpr(id8317); vc->registerAtom(id8317); Expr id8333=vc->eqExpr(id1737,id349); Expr id8332=vc->notExpr(id8333); vc->registerAtom(id8333); Expr id8349=vc->eqExpr(id1621,id355); Expr id8348=vc->notExpr(id8349); vc->registerAtom(id8349); Expr id8367=vc->eqExpr(id895,id357); Expr id8366=vc->notExpr(id8367); vc->registerAtom(id8367); Expr id8387=vc->eqExpr(id875,id357); Expr id8386=vc->notExpr(id8387); vc->registerAtom(id8387); Expr id8405=vc->eqExpr(id2127,id357); Expr id8404=vc->notExpr(id8405); vc->registerAtom(id8405); Expr id8427=vc->eqExpr(id2163,id357); Expr id8426=vc->notExpr(id8427); vc->registerAtom(id8427); Expr id8435=vc->ltExpr(id293,id875); Expr id8434=vc->notExpr(id8435); vc->registerAtom(id8435); Expr id8451=vc->eqExpr(id2185,id357); Expr id8450=vc->notExpr(id8451); vc->registerAtom(id8451); Expr id8457=vc->plusExpr(id293,id99); Expr id8459=vc->leExpr(id8457,id875); Expr id8458=vc->notExpr(id8459); vc->registerAtom(id8459); Expr id8467=vc->leExpr(id8457,id2127); Expr id8466=vc->notExpr(id8467); vc->registerAtom(id8467); Expr id8473=vc->eqExpr(id8457,id329); Expr id8472=vc->notExpr(id8473); vc->registerAtom(id8473); Expr id8483=vc->eqExpr(id1621,id357); Expr id8482=vc->notExpr(id8483); vc->registerAtom(id8483); Expr id8503=vc->varExpr("8501_c",id9); Expr id8505=vc->eqExpr(id8503,id895); Expr id8504=vc->notExpr(id8505); vc->registerAtom(id8505); Expr id8507=vc->eqExpr(id8503,id875); Expr id8506=vc->notExpr(id8507); vc->registerAtom(id8507); Expr id8519=vc->eqExpr(id8503,id315); Expr id8518=vc->notExpr(id8519); vc->registerAtom(id8519); Expr id8525=vc->eqExpr(id895,id317); Expr id8524=vc->notExpr(id8525); vc->registerAtom(id8525); Expr id8541=vc->eqExpr(id895,id307); Expr id8540=vc->notExpr(id8541); vc->registerAtom(id8541); Expr id8545=vc->eqExpr(id875,id317); Expr id8544=vc->notExpr(id8545); vc->registerAtom(id8545); Expr id8553=vc->leExpr(id271,id2127); Expr id8552=vc->notExpr(id8553); vc->registerAtom(id8553); Expr id8569=vc->eqExpr(id2127,id317); Expr id8568=vc->notExpr(id8569); vc->registerAtom(id8569); Expr id8587=vc->eqExpr(id2163,id317); Expr id8586=vc->notExpr(id8587); vc->registerAtom(id8587); Expr id8607=vc->eqExpr(id2185,id317); Expr id8606=vc->notExpr(id8607); vc->registerAtom(id8607); Expr id8629=vc->eqExpr(id1741,id307); Expr id8628=vc->notExpr(id8629); vc->registerAtom(id8629); Expr id8645=vc->eqExpr(id1621,id317); Expr id8644=vc->notExpr(id8645); vc->registerAtom(id8645); Expr id8659=vc->eqExpr(id895,id319); Expr id8658=vc->notExpr(id8659); vc->registerAtom(id8659); Expr id8679=vc->eqExpr(id875,id319); Expr id8678=vc->notExpr(id8679); vc->registerAtom(id8679); Expr id8687=vc->eqExpr(id875,id277); Expr id8686=vc->notExpr(id8687); vc->registerAtom(id8687); Expr id8703=vc->eqExpr(id2127,id319); Expr id8702=vc->notExpr(id8703); vc->registerAtom(id8703); Expr id8725=vc->eqExpr(id2163,id319); Expr id8724=vc->notExpr(id8725); vc->registerAtom(id8725); Expr id8745=vc->eqExpr(id2185,id319); Expr id8744=vc->notExpr(id8745); vc->registerAtom(id8745); Expr id8761=vc->eqExpr(id1745,id313); Expr id8760=vc->notExpr(id8761); vc->registerAtom(id8761); Expr id8777=vc->eqExpr(id1621,id319); Expr id8776=vc->notExpr(id8777); vc->registerAtom(id8777); Expr id8795=vc->eqExpr(id895,id321); Expr id8794=vc->notExpr(id8795); vc->registerAtom(id8795); Expr id8815=vc->eqExpr(id875,id321); Expr id8814=vc->notExpr(id8815); vc->registerAtom(id8815); Expr id8833=vc->eqExpr(id2127,id321); Expr id8832=vc->notExpr(id8833); vc->registerAtom(id8833); Expr id8855=vc->eqExpr(id2163,id321); Expr id8854=vc->notExpr(id8855); vc->registerAtom(id8855); Expr id8863=vc->ltExpr(id257,id875); Expr id8862=vc->notExpr(id8863); vc->registerAtom(id8863); Expr id8879=vc->eqExpr(id2185,id321); Expr id8878=vc->notExpr(id8879); vc->registerAtom(id8879); Expr id8885=vc->plusExpr(id257,id97); Expr id8887=vc->leExpr(id8885,id875); Expr id8886=vc->notExpr(id8887); vc->registerAtom(id8887); Expr id8895=vc->leExpr(id8885,id2127); Expr id8894=vc->notExpr(id8895); vc->registerAtom(id8895); Expr id8901=vc->eqExpr(id8885,id293); Expr id8900=vc->notExpr(id8901); vc->registerAtom(id8901); Expr id8911=vc->eqExpr(id1621,id321); Expr id8910=vc->notExpr(id8911); vc->registerAtom(id8911); Expr id8931=vc->varExpr("8929_c",id9); Expr id8933=vc->eqExpr(id8931,id895); Expr id8932=vc->notExpr(id8933); vc->registerAtom(id8933); Expr id8935=vc->eqExpr(id8931,id875); Expr id8934=vc->notExpr(id8935); vc->registerAtom(id8935); Expr id8947=vc->eqExpr(id8931,id279); Expr id8946=vc->notExpr(id8947); vc->registerAtom(id8947); Expr id8953=vc->eqExpr(id895,id281); Expr id8952=vc->notExpr(id8953); vc->registerAtom(id8953); Expr id8969=vc->eqExpr(id895,id271); Expr id8968=vc->notExpr(id8969); vc->registerAtom(id8969); Expr id8973=vc->eqExpr(id875,id281); Expr id8972=vc->notExpr(id8973); vc->registerAtom(id8973); Expr id8981=vc->leExpr(id235,id2127); Expr id8980=vc->notExpr(id8981); vc->registerAtom(id8981); Expr id8997=vc->eqExpr(id2127,id281); Expr id8996=vc->notExpr(id8997); vc->registerAtom(id8997); Expr id9015=vc->eqExpr(id2163,id281); Expr id9014=vc->notExpr(id9015); vc->registerAtom(id9015); Expr id9035=vc->eqExpr(id2185,id281); Expr id9034=vc->notExpr(id9035); vc->registerAtom(id9035); Expr id9057=vc->eqExpr(id1749,id271); Expr id9056=vc->notExpr(id9057); vc->registerAtom(id9057); Expr id9073=vc->eqExpr(id1621,id281); Expr id9072=vc->notExpr(id9073); vc->registerAtom(id9073); Expr id9087=vc->eqExpr(id895,id283); Expr id9086=vc->notExpr(id9087); vc->registerAtom(id9087); Expr id9107=vc->eqExpr(id875,id283); Expr id9106=vc->notExpr(id9107); vc->registerAtom(id9107); Expr id9115=vc->eqExpr(id875,id241); Expr id9114=vc->notExpr(id9115); vc->registerAtom(id9115); Expr id9131=vc->eqExpr(id2127,id283); Expr id9130=vc->notExpr(id9131); vc->registerAtom(id9131); Expr id9153=vc->eqExpr(id2163,id283); Expr id9152=vc->notExpr(id9153); vc->registerAtom(id9153); Expr id9173=vc->eqExpr(id2185,id283); Expr id9172=vc->notExpr(id9173); vc->registerAtom(id9173); Expr id9189=vc->eqExpr(id1753,id277); Expr id9188=vc->notExpr(id9189); vc->registerAtom(id9189); Expr id9205=vc->eqExpr(id1621,id283); Expr id9204=vc->notExpr(id9205); vc->registerAtom(id9205); Expr id9223=vc->eqExpr(id895,id285); Expr id9222=vc->notExpr(id9223); vc->registerAtom(id9223); Expr id9243=vc->eqExpr(id875,id285); Expr id9242=vc->notExpr(id9243); vc->registerAtom(id9243); Expr id9261=vc->eqExpr(id2127,id285); Expr id9260=vc->notExpr(id9261); vc->registerAtom(id9261); Expr id9283=vc->eqExpr(id2163,id285); Expr id9282=vc->notExpr(id9283); vc->registerAtom(id9283); Expr id9291=vc->ltExpr(id221,id875); Expr id9290=vc->notExpr(id9291); vc->registerAtom(id9291); Expr id9307=vc->eqExpr(id2185,id285); Expr id9306=vc->notExpr(id9307); vc->registerAtom(id9307); Expr id9313=vc->plusExpr(id221,id95); Expr id9315=vc->leExpr(id9313,id875); Expr id9314=vc->notExpr(id9315); vc->registerAtom(id9315); Expr id9323=vc->leExpr(id9313,id2127); Expr id9322=vc->notExpr(id9323); vc->registerAtom(id9323); Expr id9329=vc->eqExpr(id9313,id257); Expr id9328=vc->notExpr(id9329); vc->registerAtom(id9329); Expr id9339=vc->eqExpr(id1621,id285); Expr id9338=vc->notExpr(id9339); vc->registerAtom(id9339); Expr id9359=vc->varExpr("9357_c",id9); Expr id9361=vc->eqExpr(id9359,id895); Expr id9360=vc->notExpr(id9361); vc->registerAtom(id9361); Expr id9363=vc->eqExpr(id9359,id875); Expr id9362=vc->notExpr(id9363); vc->registerAtom(id9363); Expr id9375=vc->eqExpr(id9359,id243); Expr id9374=vc->notExpr(id9375); vc->registerAtom(id9375); Expr id9381=vc->eqExpr(id895,id245); Expr id9380=vc->notExpr(id9381); vc->registerAtom(id9381); Expr id9397=vc->eqExpr(id895,id235); Expr id9396=vc->notExpr(id9397); vc->registerAtom(id9397); Expr id9401=vc->eqExpr(id875,id245); Expr id9400=vc->notExpr(id9401); vc->registerAtom(id9401); Expr id9409=vc->leExpr(id199,id2127); Expr id9408=vc->notExpr(id9409); vc->registerAtom(id9409); Expr id9425=vc->eqExpr(id2127,id245); Expr id9424=vc->notExpr(id9425); vc->registerAtom(id9425); Expr id9443=vc->eqExpr(id2163,id245); Expr id9442=vc->notExpr(id9443); vc->registerAtom(id9443); Expr id9463=vc->eqExpr(id2185,id245); Expr id9462=vc->notExpr(id9463); vc->registerAtom(id9463); Expr id9485=vc->eqExpr(id1757,id235); Expr id9484=vc->notExpr(id9485); vc->registerAtom(id9485); Expr id9501=vc->eqExpr(id1621,id245); Expr id9500=vc->notExpr(id9501); vc->registerAtom(id9501); Expr id9515=vc->eqExpr(id895,id247); Expr id9514=vc->notExpr(id9515); vc->registerAtom(id9515); Expr id9535=vc->eqExpr(id875,id247); Expr id9534=vc->notExpr(id9535); vc->registerAtom(id9535); Expr id9543=vc->eqExpr(id875,id205); Expr id9542=vc->notExpr(id9543); vc->registerAtom(id9543); Expr id9559=vc->eqExpr(id2127,id247); Expr id9558=vc->notExpr(id9559); vc->registerAtom(id9559); Expr id9581=vc->eqExpr(id2163,id247); Expr id9580=vc->notExpr(id9581); vc->registerAtom(id9581); Expr id9601=vc->eqExpr(id2185,id247); Expr id9600=vc->notExpr(id9601); vc->registerAtom(id9601); Expr id9617=vc->eqExpr(id1761,id241); Expr id9616=vc->notExpr(id9617); vc->registerAtom(id9617); Expr id9633=vc->eqExpr(id1621,id247); Expr id9632=vc->notExpr(id9633); vc->registerAtom(id9633); Expr id9651=vc->eqExpr(id895,id249); Expr id9650=vc->notExpr(id9651); vc->registerAtom(id9651); Expr id9671=vc->eqExpr(id875,id249); Expr id9670=vc->notExpr(id9671); vc->registerAtom(id9671); Expr id9689=vc->eqExpr(id2127,id249); Expr id9688=vc->notExpr(id9689); vc->registerAtom(id9689); Expr id9711=vc->eqExpr(id2163,id249); Expr id9710=vc->notExpr(id9711); vc->registerAtom(id9711); Expr id9719=vc->ltExpr(id185,id875); Expr id9718=vc->notExpr(id9719); vc->registerAtom(id9719); Expr id9735=vc->eqExpr(id2185,id249); Expr id9734=vc->notExpr(id9735); vc->registerAtom(id9735); Expr id9741=vc->plusExpr(id185,id93); Expr id9743=vc->leExpr(id9741,id875); Expr id9742=vc->notExpr(id9743); vc->registerAtom(id9743); Expr id9751=vc->leExpr(id9741,id2127); Expr id9750=vc->notExpr(id9751); vc->registerAtom(id9751); Expr id9757=vc->eqExpr(id9741,id221); Expr id9756=vc->notExpr(id9757); vc->registerAtom(id9757); Expr id9767=vc->eqExpr(id1621,id249); Expr id9766=vc->notExpr(id9767); vc->registerAtom(id9767); Expr id9787=vc->varExpr("9785_c",id9); Expr id9789=vc->eqExpr(id9787,id895); Expr id9788=vc->notExpr(id9789); vc->registerAtom(id9789); Expr id9791=vc->eqExpr(id9787,id875); Expr id9790=vc->notExpr(id9791); vc->registerAtom(id9791); Expr id9803=vc->eqExpr(id9787,id207); Expr id9802=vc->notExpr(id9803); vc->registerAtom(id9803); Expr id9809=vc->eqExpr(id895,id209); Expr id9808=vc->notExpr(id9809); vc->registerAtom(id9809); Expr id9825=vc->eqExpr(id895,id199); Expr id9824=vc->notExpr(id9825); vc->registerAtom(id9825); Expr id9829=vc->eqExpr(id875,id209); Expr id9828=vc->notExpr(id9829); vc->registerAtom(id9829); Expr id9837=vc->leExpr(id155,id2127); Expr id9836=vc->notExpr(id9837); vc->registerAtom(id9837); Expr id9853=vc->eqExpr(id2127,id209); Expr id9852=vc->notExpr(id9853); vc->registerAtom(id9853); Expr id9871=vc->eqExpr(id2163,id209); Expr id9870=vc->notExpr(id9871); vc->registerAtom(id9871); Expr id9891=vc->eqExpr(id2185,id209); Expr id9890=vc->notExpr(id9891); vc->registerAtom(id9891); Expr id9913=vc->eqExpr(id1765,id199); Expr id9912=vc->notExpr(id9913); vc->registerAtom(id9913); Expr id9929=vc->eqExpr(id1621,id209); Expr id9928=vc->notExpr(id9929); vc->registerAtom(id9929); Expr id9943=vc->eqExpr(id895,id211); Expr id9942=vc->notExpr(id9943); vc->registerAtom(id9943); Expr id9963=vc->eqExpr(id875,id211); Expr id9962=vc->notExpr(id9963); vc->registerAtom(id9963); Expr id9971=vc->eqExpr(id875,id161); Expr id9970=vc->notExpr(id9971); vc->registerAtom(id9971); Expr id9987=vc->eqExpr(id2127,id211); Expr id9986=vc->notExpr(id9987); vc->registerAtom(id9987); Expr id10009=vc->eqExpr(id2163,id211); Expr id10008=vc->notExpr(id10009); vc->registerAtom(id10009); Expr id10029=vc->eqExpr(id2185,id211); Expr id10028=vc->notExpr(id10029); vc->registerAtom(id10029); Expr id10045=vc->eqExpr(id1769,id205); Expr id10044=vc->notExpr(id10045); vc->registerAtom(id10045); Expr id10061=vc->eqExpr(id1621,id211); Expr id10060=vc->notExpr(id10061); vc->registerAtom(id10061); Expr id10079=vc->eqExpr(id895,id213); Expr id10078=vc->notExpr(id10079); vc->registerAtom(id10079); Expr id10099=vc->eqExpr(id875,id213); Expr id10098=vc->notExpr(id10099); vc->registerAtom(id10099); Expr id10117=vc->eqExpr(id2127,id213); Expr id10116=vc->notExpr(id10117); vc->registerAtom(id10117); Expr id10139=vc->eqExpr(id2163,id213); Expr id10138=vc->notExpr(id10139); vc->registerAtom(id10139); Expr id10147=vc->ltExpr(id139,id875); Expr id10146=vc->notExpr(id10147); vc->registerAtom(id10147); Expr id10163=vc->eqExpr(id2185,id213); Expr id10162=vc->notExpr(id10163); vc->registerAtom(id10163); Expr id10169=vc->plusExpr(id139,id91); Expr id10171=vc->leExpr(id10169,id875); Expr id10170=vc->notExpr(id10171); vc->registerAtom(id10171); Expr id10179=vc->leExpr(id10169,id2127); Expr id10178=vc->notExpr(id10179); vc->registerAtom(id10179); Expr id10185=vc->eqExpr(id10169,id185); Expr id10184=vc->notExpr(id10185); vc->registerAtom(id10185); Expr id10195=vc->eqExpr(id1621,id213); Expr id10194=vc->notExpr(id10195); vc->registerAtom(id10195); Expr id10215=vc->varExpr("10213_c",id9); Expr id10217=vc->eqExpr(id10215,id895); Expr id10216=vc->notExpr(id10217); vc->registerAtom(id10217); Expr id10219=vc->eqExpr(id10215,id875); Expr id10218=vc->notExpr(id10219); vc->registerAtom(id10219); Expr id10225=vc->eqExpr(id10215,id163); Expr id10224=vc->notExpr(id10225); vc->registerAtom(id10225); Expr id10231=vc->eqExpr(id895,id165); Expr id10230=vc->notExpr(id10231); vc->registerAtom(id10231); Expr id10249=vc->eqExpr(id875,id165); Expr id10248=vc->notExpr(id10249); vc->registerAtom(id10249); Expr id10257=vc->geExpr(id2127,id895); Expr id10256=vc->notExpr(id10257); vc->registerAtom(id10257); Expr id10273=vc->eqExpr(id2127,id165); Expr id10272=vc->notExpr(id10273); vc->registerAtom(id10273); Expr id10291=vc->eqExpr(id2163,id165); Expr id10290=vc->notExpr(id10291); vc->registerAtom(id10291); Expr id10311=vc->eqExpr(id2185,id165); Expr id10310=vc->notExpr(id10311); vc->registerAtom(id10311); Expr id10333=vc->eqExpr(id1773,id155); Expr id10332=vc->notExpr(id10333); vc->registerAtom(id10333); Expr id10349=vc->eqExpr(id1621,id165); Expr id10348=vc->notExpr(id10349); vc->registerAtom(id10349); Expr id10363=vc->eqExpr(id895,id171); Expr id10362=vc->notExpr(id10363); vc->registerAtom(id10363); Expr id10383=vc->eqExpr(id875,id171); Expr id10382=vc->notExpr(id10383); vc->registerAtom(id10383); Expr id10391=vc->eqExpr(id875,id895); Expr id10390=vc->notExpr(id10391); vc->registerAtom(id10391); Expr id10407=vc->eqExpr(id2127,id171); Expr id10406=vc->notExpr(id10407); vc->registerAtom(id10407); Expr id10429=vc->eqExpr(id2163,id171); Expr id10428=vc->notExpr(id10429); vc->registerAtom(id10429); Expr id10449=vc->eqExpr(id2185,id171); Expr id10448=vc->notExpr(id10449); vc->registerAtom(id10449); Expr id10465=vc->eqExpr(id1773,id161); Expr id10464=vc->notExpr(id10465); vc->registerAtom(id10465); Expr id10481=vc->eqExpr(id1621,id171); Expr id10480=vc->notExpr(id10481); vc->registerAtom(id10481); Expr id10499=vc->eqExpr(id895,id177); Expr id10498=vc->notExpr(id10499); vc->registerAtom(id10499); Expr id10519=vc->eqExpr(id875,id177); Expr id10518=vc->notExpr(id10519); vc->registerAtom(id10519); Expr id10537=vc->eqExpr(id2127,id177); Expr id10536=vc->notExpr(id10537); vc->registerAtom(id10537); Expr id10559=vc->eqExpr(id2163,id177); Expr id10558=vc->notExpr(id10559); vc->registerAtom(id10559); Expr id10567=vc->gtExpr(id875,id895); Expr id10566=vc->notExpr(id10567); vc->registerAtom(id10567); Expr id10583=vc->eqExpr(id2185,id177); Expr id10582=vc->notExpr(id10583); vc->registerAtom(id10583); Expr id10595=vc->leExpr(id1773,id2127); Expr id10594=vc->notExpr(id10595); vc->registerAtom(id10595); Expr id10601=vc->eqExpr(id1773,id139); Expr id10600=vc->notExpr(id10601); vc->registerAtom(id10601); Expr id10611=vc->eqExpr(id1621,id177); Expr id10610=vc->notExpr(id10611); vc->registerAtom(id10611); vc->push(); vc->query(id12); vc->inconsistent(inconsistency); vc->pop(); vc->push(); vc->query(id10224); vc->popto(1); vc->push(); vc->query(id10225); vc->popto(1); vc->push(); vc->assertFormula(id10225); vc->getImpliedLiteral(); vc->getImpliedLiteral(); vc->getImpliedLiteral(); vc->getImpliedLiteral(); vc->getImpliedLiteral(); vc->push(); vc->query(id9802); vc->popto(2); vc->push(); vc->query(id9803); vc->popto(2); vc->push(); vc->assertFormula(id9803); vc->getImpliedLiteral(); vc->getImpliedLiteral(); vc->push(); vc->query(id9374); vc->popto(3); vc->push(); vc->query(id9375); vc->popto(3); vc->push(); vc->assertFormula(id9375); vc->getImpliedLiteral(); vc->getImpliedLiteral(); vc->push(); vc->query(id8946); vc->popto(4); vc->push(); vc->query(id8947); vc->popto(4); vc->push(); vc->assertFormula(id8947); vc->getImpliedLiteral(); vc->getImpliedLiteral(); vc->push(); vc->query(id8518); vc->popto(5); vc->push(); vc->query(id8519); vc->popto(5); vc->push(); vc->assertFormula(id8519); vc->getImpliedLiteral(); vc->getImpliedLiteral(); vc->push(); vc->query(id8090); vc->popto(6); vc->push(); vc->query(id8091); vc->popto(6); vc->push(); vc->assertFormula(id8091); vc->getImpliedLiteral(); vc->getImpliedLiteral(); vc->push(); vc->query(id7662); vc->popto(7); vc->push(); vc->query(id7663); vc->popto(7); vc->push(); vc->assertFormula(id7663); vc->getImpliedLiteral(); vc->getImpliedLiteral(); vc->push(); vc->query(id7234); vc->popto(8); vc->push(); vc->query(id7235); vc->popto(8); vc->push(); vc->assertFormula(id7235); vc->getImpliedLiteral(); vc->getImpliedLiteral(); vc->push(); vc->query(id6806); vc->popto(9); vc->push(); vc->query(id6807); vc->popto(9); vc->push(); vc->assertFormula(id6807); vc->getImpliedLiteral(); vc->getImpliedLiteral(); vc->push(); vc->query(id6378); vc->popto(10); vc->push(); vc->query(id6379); vc->popto(10); vc->push(); vc->assertFormula(id6379); vc->getImpliedLiteral(); vc->getImpliedLiteral(); vc->push(); vc->query(id5950); vc->popto(11); vc->push(); vc->query(id5951); vc->popto(11); vc->push(); vc->assertFormula(id5951); vc->getImpliedLiteral(); vc->getImpliedLiteral(); vc->push(); vc->query(id5522); vc->popto(12); vc->push(); vc->query(id5523); vc->popto(12); vc->push(); vc->assertFormula(id5523); vc->getImpliedLiteral(); vc->getImpliedLiteral(); vc->push(); vc->query(id5094); vc->popto(13); vc->push(); vc->query(id5095); vc->popto(13); vc->push(); vc->assertFormula(id5095); vc->getImpliedLiteral(); vc->getImpliedLiteral(); vc->push(); vc->query(id4666); vc->popto(14); vc->push(); vc->query(id4667); vc->popto(14); vc->push(); vc->assertFormula(id4667); vc->getImpliedLiteral(); vc->getImpliedLiteral(); vc->push(); vc->query(id4238); vc->popto(15); vc->push(); vc->query(id4239); vc->popto(15); vc->push(); vc->assertFormula(id4239); vc->getImpliedLiteral(); vc->getImpliedLiteral(); vc->push(); vc->query(id3810); vc->popto(16); vc->push(); vc->query(id3811); vc->popto(16); vc->push(); vc->assertFormula(id3811); vc->getImpliedLiteral(); vc->getImpliedLiteral(); vc->push(); vc->query(id3382); vc->popto(17); vc->push(); vc->query(id3383); vc->popto(17); vc->push(); vc->assertFormula(id3383); vc->getImpliedLiteral(); vc->getImpliedLiteral(); vc->push(); vc->query(id2954); vc->popto(18); vc->push(); vc->query(id2955); vc->popto(18); vc->push(); vc->assertFormula(id2955); vc->getImpliedLiteral(); vc->getImpliedLiteral(); vc->push(); vc->query(id2526); vc->popto(19); vc->push(); vc->query(id2527); vc->popto(19); vc->push(); vc->assertFormula(id2527); vc->getImpliedLiteral(); vc->getImpliedLiteral(); vc->push(); vc->query(id2092); vc->popto(20); vc->push(); vc->query(id2093); vc->popto(20); vc->push(); vc->assertFormula(id2093); vc->getImpliedLiteral(); vc->getImpliedLiteral(); vc->push(); vc->query(id2069); vc->popto(21); vc->push(); vc->query(id2068); vc->popto(21); vc->push(); vc->assertFormula(id2068); vc->getImpliedLiteral(); vc->push(); vc->query(id2063); vc->popto(22); vc->push(); vc->query(id2062); vc->popto(22); vc->push(); vc->assertFormula(id2062); vc->getImpliedLiteral(); vc->push(); vc->query(id2057); vc->popto(23); vc->push(); vc->query(id2056); vc->popto(23); vc->push(); vc->assertFormula(id2056); vc->getImpliedLiteral(); vc->push(); vc->query(id2051); vc->popto(24); vc->push(); vc->query(id2050); vc->popto(24); vc->push(); vc->assertFormula(id2050); vc->getImpliedLiteral(); vc->push(); vc->query(id2045); vc->popto(25); vc->push(); vc->query(id2044); vc->popto(25); vc->push(); vc->assertFormula(id2044); vc->getImpliedLiteral(); vc->push(); vc->query(id2039); vc->popto(26); vc->push(); vc->query(id2038); vc->popto(26); vc->push(); vc->assertFormula(id2038); vc->getImpliedLiteral(); vc->push(); vc->query(id2033); vc->popto(27); vc->push(); vc->query(id2032); vc->popto(27); vc->push(); vc->assertFormula(id2032); vc->getImpliedLiteral(); vc->push(); vc->query(id2027); vc->popto(28); vc->push(); vc->query(id2026); vc->popto(28); vc->push(); vc->assertFormula(id2026); vc->getImpliedLiteral(); vc->push(); vc->query(id2021); vc->popto(29); vc->push(); vc->query(id2020); vc->popto(29); vc->push(); vc->assertFormula(id2020); vc->getImpliedLiteral(); vc->push(); vc->query(id2015); vc->popto(30); vc->push(); vc->query(id2014); vc->popto(30); vc->push(); vc->assertFormula(id2014); vc->getImpliedLiteral(); vc->push(); vc->query(id2009); vc->popto(31); vc->push(); vc->query(id2008); vc->popto(31); vc->push(); vc->assertFormula(id2008); vc->getImpliedLiteral(); vc->push(); vc->query(id2003); vc->popto(32); vc->push(); vc->query(id2002); vc->popto(32); vc->push(); vc->assertFormula(id2002); vc->getImpliedLiteral(); vc->push(); vc->query(id1997); vc->popto(33); vc->push(); vc->query(id1996); vc->popto(33); vc->push(); vc->assertFormula(id1996); vc->getImpliedLiteral(); vc->push(); vc->query(id1991); vc->popto(34); vc->push(); vc->query(id1990); vc->popto(34); vc->push(); vc->assertFormula(id1990); vc->getImpliedLiteral(); vc->push(); vc->query(id1985); vc->popto(35); vc->push(); vc->query(id1984); vc->popto(35); vc->push(); vc->assertFormula(id1984); vc->getImpliedLiteral(); vc->push(); vc->query(id1979); vc->popto(36); vc->push(); vc->query(id1978); vc->popto(36); vc->push(); vc->assertFormula(id1978); vc->getImpliedLiteral(); vc->push(); vc->query(id1973); vc->popto(37); vc->push(); vc->query(id1972); vc->popto(37); vc->push(); vc->assertFormula(id1972); vc->getImpliedLiteral(); vc->push(); vc->query(id1967); vc->popto(38); vc->push(); vc->query(id1966); vc->popto(38); vc->push(); vc->assertFormula(id1966); vc->getImpliedLiteral(); vc->push(); vc->query(id1961); vc->popto(39); vc->push(); vc->query(id1960); vc->popto(39); vc->push(); vc->assertFormula(id1960); vc->getImpliedLiteral(); vc->push(); vc->query(id1955); vc->popto(40); vc->push(); vc->query(id1954); vc->popto(40); vc->push(); vc->assertFormula(id1954); vc->getImpliedLiteral(); vc->push(); vc->query(id1949); vc->popto(41); vc->push(); vc->query(id1948); vc->popto(41); vc->push(); vc->assertFormula(id1948); vc->getImpliedLiteral(); vc->push(); vc->query(id1932); vc->popto(42); vc->push(); vc->query(id1933); vc->popto(42); vc->push(); vc->assertFormula(id1933); vc->getImpliedLiteral(); vc->getImpliedLiteral(); vc->push(); vc->query(id1928); vc->popto(43); vc->push(); vc->query(id1929); vc->popto(43); vc->push(); vc->assertFormula(id1929); vc->getImpliedLiteral(); vc->getImpliedLiteral(); vc->push(); vc->query(id1924); vc->popto(44); vc->push(); vc->query(id1925); vc->popto(44); vc->push(); vc->assertFormula(id1925); vc->getImpliedLiteral(); vc->getImpliedLiteral(); vc->push(); vc->query(id1920); vc->popto(45); vc->push(); vc->query(id1921); vc->popto(45); vc->push(); vc->assertFormula(id1921); vc->getImpliedLiteral(); vc->getImpliedLiteral(); vc->push(); vc->query(id1916); vc->popto(46); vc->push(); vc->query(id1917); vc->popto(46); vc->push(); vc->assertFormula(id1917); vc->getImpliedLiteral(); vc->getImpliedLiteral(); vc->push(); vc->query(id1912); vc->popto(47); vc->push(); vc->query(id1913); vc->popto(47); vc->push(); vc->assertFormula(id1913); vc->getImpliedLiteral(); vc->getImpliedLiteral(); vc->push(); vc->query(id1908); vc->popto(48); vc->push(); vc->query(id1909); vc->popto(48); vc->push(); vc->assertFormula(id1909); vc->getImpliedLiteral(); vc->getImpliedLiteral(); vc->push(); vc->query(id1904); vc->popto(49); vc->push(); vc->query(id1905); vc->popto(49); vc->push(); vc->assertFormula(id1905); vc->getImpliedLiteral(); vc->getImpliedLiteral(); vc->push(); vc->query(id1900); vc->popto(50); vc->push(); vc->query(id1901); vc->popto(50); vc->push(); vc->assertFormula(id1901); vc->getImpliedLiteral(); vc->getImpliedLiteral(); vc->push(); vc->query(id1896); vc->popto(51); vc->push(); vc->query(id1897); vc->popto(51); vc->push(); vc->assertFormula(id1897); vc->getImpliedLiteral(); vc->getImpliedLiteral(); vc->push(); vc->query(id1892); vc->popto(52); vc->push(); vc->query(id1893); vc->popto(52); vc->push(); vc->assertFormula(id1893); vc->getImpliedLiteral(); vc->getImpliedLiteral(); vc->push(); vc->query(id1888); vc->popto(53); vc->push(); vc->query(id1889); vc->popto(53); vc->push(); vc->assertFormula(id1889); vc->getImpliedLiteral(); vc->getImpliedLiteral(); vc->push(); vc->query(id1884); vc->popto(54); vc->push(); vc->query(id1885); vc->popto(54); vc->push(); vc->assertFormula(id1885); vc->getImpliedLiteral(); vc->getImpliedLiteral(); vc->push(); vc->query(id1880); vc->popto(55); vc->push(); vc->query(id1881); vc->popto(55); vc->push(); vc->assertFormula(id1881); vc->getImpliedLiteral(); vc->getImpliedLiteral(); vc->push(); vc->query(id1876); vc->popto(56); vc->push(); vc->query(id1877); vc->popto(56); vc->push(); vc->assertFormula(id1877); vc->getImpliedLiteral(); vc->getImpliedLiteral(); vc->push(); vc->query(id1872); vc->popto(57); vc->push(); vc->query(id1873); vc->popto(57); vc->push(); vc->assertFormula(id1873); vc->getImpliedLiteral(); vc->getImpliedLiteral(); vc->push(); vc->query(id1868); vc->popto(58); vc->push(); vc->query(id1869); vc->popto(58); vc->push(); vc->assertFormula(id1869); vc->getImpliedLiteral(); vc->getImpliedLiteral(); vc->push(); vc->query(id1864); vc->popto(59); vc->push(); vc->query(id1865); vc->popto(59); vc->push(); vc->assertFormula(id1865); vc->getImpliedLiteral(); vc->getImpliedLiteral(); vc->push(); vc->query(id1860); vc->popto(60); vc->push(); vc->query(id1861); vc->popto(60); vc->push(); vc->assertFormula(id1861); vc->getImpliedLiteral(); vc->getImpliedLiteral(); vc->push(); vc->query(id1856); vc->popto(61); vc->push(); vc->query(id1857); vc->popto(61); vc->push(); vc->assertFormula(id1857); vc->getImpliedLiteral(); vc->getImpliedLiteral(); vc->push(); vc->query(id1852); vc->popto(62); vc->push(); vc->query(id1853); vc->popto(62); vc->push(); vc->assertFormula(id1853); vc->getImpliedLiteral(); vc->getImpliedLiteral(); vc->push(); vc->query(id1848); vc->popto(63); vc->push(); vc->query(id1849); vc->popto(63); vc->push(); vc->assertFormula(id1849); vc->getImpliedLiteral(); vc->getImpliedLiteral(); vc->push(); vc->query(id1844); vc->popto(64); vc->push(); vc->query(id1845); vc->popto(64); vc->push(); vc->assertFormula(id1845); vc->getImpliedLiteral(); vc->getImpliedLiteral(); vc->push(); vc->query(id1840); vc->popto(65); vc->push(); vc->query(id1841); vc->popto(65); vc->push(); vc->assertFormula(id1841); vc->getImpliedLiteral(); vc->getImpliedLiteral(); vc->push(); vc->query(id1836); vc->popto(66); vc->push(); vc->query(id1837); vc->popto(66); vc->push(); vc->assertFormula(id1837); vc->getImpliedLiteral(); vc->getImpliedLiteral(); vc->push(); vc->query(id1832); vc->popto(67); vc->push(); vc->query(id1833); vc->popto(67); vc->push(); vc->assertFormula(id1833); vc->getImpliedLiteral(); vc->getImpliedLiteral(); vc->push(); vc->query(id1828); vc->popto(68); vc->push(); vc->query(id1829); vc->popto(68); vc->push(); vc->assertFormula(id1829); vc->getImpliedLiteral(); vc->getImpliedLiteral(); vc->push(); vc->query(id1824); vc->popto(69); vc->push(); vc->query(id1825); vc->popto(69); vc->push(); vc->assertFormula(id1825); vc->getImpliedLiteral(); vc->getImpliedLiteral(); vc->push(); vc->query(id1820); vc->popto(70); vc->push(); vc->query(id1821); vc->popto(70); vc->push(); vc->assertFormula(id1821); vc->getImpliedLiteral(); vc->getImpliedLiteral(); vc->push(); vc->query(id1816); vc->popto(71); vc->push(); vc->query(id1817); vc->popto(71); vc->push(); vc->assertFormula(id1817); vc->getImpliedLiteral(); vc->getImpliedLiteral(); vc->push(); vc->query(id1812); vc->popto(72); vc->push(); vc->query(id1813); vc->popto(72); vc->push(); vc->assertFormula(id1813); vc->getImpliedLiteral(); vc->getImpliedLiteral(); vc->push(); vc->query(id1808); vc->popto(73); vc->push(); vc->query(id1809); vc->popto(73); vc->push(); vc->assertFormula(id1809); vc->getImpliedLiteral(); vc->getImpliedLiteral(); vc->push(); vc->query(id1804); vc->popto(74); vc->push(); vc->query(id1805); vc->popto(74); vc->push(); vc->assertFormula(id1805); vc->getImpliedLiteral(); vc->getImpliedLiteral(); vc->push(); vc->query(id1800); vc->popto(75); vc->push(); vc->query(id1801); vc->popto(75); vc->push(); vc->assertFormula(id1801); vc->getImpliedLiteral(); vc->getImpliedLiteral(); vc->push(); vc->query(id1796); vc->popto(76); vc->push(); vc->query(id1797); vc->popto(76); vc->push(); vc->assertFormula(id1797); vc->getImpliedLiteral(); vc->getImpliedLiteral(); vc->push(); vc->query(id1792); vc->popto(77); vc->push(); vc->query(id1793); vc->popto(77); vc->push(); vc->assertFormula(id1793); vc->getImpliedLiteral(); vc->getImpliedLiteral(); vc->push(); vc->query(id1788); vc->popto(78); vc->push(); vc->query(id1789); vc->popto(78); vc->push(); vc->assertFormula(id1789); vc->getImpliedLiteral(); vc->getImpliedLiteral(); vc->push(); vc->query(id1784); vc->popto(79); vc->push(); vc->query(id1785); vc->popto(79); vc->push(); vc->assertFormula(id1785); vc->getImpliedLiteral(); vc->getImpliedLiteral(); vc->push(); vc->query(id1780); vc->popto(80); vc->push(); vc->query(id1781); vc->popto(80); vc->push(); vc->assertFormula(id1781); vc->getImpliedLiteral(); vc->getImpliedLiteral(); vc->push(); vc->query(id1778); vc->popto(81); vc->push(); vc->query(id1779); vc->popto(81); vc->push(); vc->assertFormula(id1779); vc->getImpliedLiteral(); vc->getImpliedLiteral(); vc->push(); vc->query(id10566); vc->popto(82); vc->push(); vc->query(id10567); vc->popto(82); vc->push(); vc->query(id10391); vc->popto(82); vc->push(); vc->query(id10390); vc->popto(82); vc->push(); vc->query(id10256); vc->popto(82); vc->push(); vc->query(id10257); vc->popto(82); vc->push(); vc->query(id10218); vc->popto(82); vc->push(); vc->query(id10219); vc->popto(82); vc->push(); vc->assertFormula(id10219); vc->getImpliedLiteral(); vc->getImpliedLiteral(); vc->getImpliedLiteral(); vc->getImpliedLiteral(); vc->getImpliedLiteral(); vc->push(); vc->query(id1562); vc->popto(83); vc->push(); vc->query(id1563); vc->popto(83); vc->push(); vc->query(id10217); vc->popto(83); vc->push(); vc->query(id10216); vc->popto(83); vc->push(); vc->query(id1585); vc->popto(83); vc->push(); vc->query(id1584); vc->popto(83); vc->push(); vc->query(id9788); vc->popto(83); vc->push(); vc->query(id9789); vc->popto(83); vc->push(); vc->assertFormula(id9789); vc->getImpliedLiteral(); vc->getImpliedLiteral(); vc->getImpliedLiteral(); vc->getImpliedLiteral(); vc->getImpliedLiteral(); vc->push(); vc->query(id1550); vc->popto(84); vc->push(); vc->query(id1551); vc->popto(84); vc->push(); vc->assertFormula(id1551); vc->getImpliedLiteral(); vc->getImpliedLiteral(); vc->push(); vc->query(id9912); vc->popto(85); vc->push(); vc->query(id9913); vc->popto(85); vc->push(); vc->assertFormula(id9913); vc->getImpliedLiteral(); vc->getImpliedLiteral(); vc->push(); vc->query(id10184); vc->popto(86); vc->push(); vc->query(id10185); vc->popto(86); vc->push(); vc->assertFormula(id10185); vc->getImpliedLiteral(); vc->getImpliedLiteral(); vc->push(); vc->query(id10044); } catch(const Exception& e) { exitStatus = 1; cout << "*** Exception caught in testgeorge1(): \n" << e << endl; } delete vc; } void testgeorge2() { CLFlags flags = ValidityChecker::createFlags(); flags.setFlag("arith3", true); ValidityChecker *vc = ValidityChecker::create(flags); try { /*************/ vector inconsistency; /*************/ Type id9 = vc->realType(); Type id7 = vc->intType(); Type id11 = vc->boolType(); vc->push(); Expr id13=vc->trueExpr(); Expr id12=vc->notExpr(vc->trueExpr()); Type id19=vc->arrayType(id7,id7); Type id21=vc->arrayType(id7,id9); Type id23=vc->arrayType(id9,id7); Type id25=vc->arrayType(id9,id9); Type id27=vc->tupleType(id19,id7,id7); Type id29=vc->funType(id27,id19); Op id31=vc->createOp(".Int_Int_store",id29); Type id33=vc->tupleType(id21,id7); Type id35=vc->funType(id33,id9); Op id37=vc->createOp(".Int_Real_select",id35); Type id39=vc->tupleType(id21,id7,id9); Type id41=vc->funType(id39,id21); Op id43=vc->createOp(".Int_Real_store",id41); Type id45=vc->tupleType(id19,id7); Type id47=vc->funType(id45,id7); Op id49=vc->createOp(".Int_Int_select",id47); Type id51=vc->tupleType(id23,id9,id7); Type id53=vc->funType(id51,id23); Op id55=vc->createOp(".Real_Int_store",id53); Type id57=vc->tupleType(id25,id9,id9); Type id59=vc->funType(id57,id25); Op id61=vc->createOp(".Real_Real_store",id59); Type id63=vc->tupleType(id23,id9); Type id65=vc->funType(id63,id7); Op id67=vc->createOp(".Real_Int_select",id65); Type id69=vc->tupleType(id25,id9); Type id71=vc->funType(id69,id9); Op id73=vc->createOp(".Real_Real_select",id71); Expr id75=vc->varExpr("x_0",id7); Expr id77=vc->varExpr("x_1",id7); Expr id79=vc->varExpr("x_2",id7); Expr id81=vc->varExpr("x_3",id7); Expr id83=vc->varExpr("x_4",id19); Expr id85=vc->varExpr("x_5",id7); Expr id87=vc->varExpr("x_6",id7); Expr id89=vc->varExpr("x_7",id7); Expr id91=vc->varExpr("x_8",id7); Expr id93=vc->varExpr("x_9",id7); Expr id95=vc->varExpr("x_10",id19); Expr id97=vc->varExpr("x_11",id19); Expr id99=vc->varExpr("x_12",id7); Expr id101=vc->varExpr("x_13",id7); Expr id103=vc->varExpr("x_14",id7); Expr id105=vc->varExpr("x_15",id7); Expr id107=vc->varExpr("x_16",id19); Expr id109=vc->varExpr("x_17",id7); Expr id111=vc->varExpr("x_18",id7); Expr id113=vc->varExpr("x_19",id7); Expr id115=vc->varExpr("x_20",id7); Expr id117=vc->varExpr("x_21",id7); Expr id119=vc->varExpr("x_22",id7); Expr id121=vc->varExpr("x_23",id7); Expr id123=vc->varExpr("x_24",id19); Expr id125=vc->varExpr("x_25",id7); Expr id127=vc->varExpr("x_26",id7); Expr id129=vc->varExpr("x_27",id7); Expr id131=vc->varExpr("x_28",id19); Expr id133=vc->varExpr("x_29",id7); Expr id135=vc->varExpr("x_30",id7); Expr id137=vc->varExpr("x_31",id7); Expr id139=vc->varExpr("x_32",id7); Expr id141=vc->varExpr("x_33",id7); Expr id143=vc->varExpr("x_34",id7); Expr id145=vc->varExpr("x_35",id19); Expr id147=vc->varExpr("x_36",id7); Expr id149=vc->varExpr("x_37",id7); Expr id151=vc->varExpr("x_38",id7); Expr id153=vc->varExpr("x_39",id19); Expr id155=vc->varExpr("x_40",id7); Expr id157=vc->varExpr("x_41",id7); Expr id159=vc->varExpr("x_42",id7); Expr id161=vc->varExpr("x_43",id7); Expr id163=vc->varExpr("x_44",id7); Expr id165=vc->varExpr("x_45",id7); Expr id167=vc->varExpr("x_46",id19); Expr id169=vc->varExpr("x_47",id7); Expr id171=vc->varExpr("x_48",id7); Expr id173=vc->varExpr("x_49",id7); Expr id175=vc->varExpr("x_50",id19); Expr id177=vc->varExpr("x_51",id7); Expr id179=vc->varExpr("x_52",id7); Expr id181=vc->varExpr("x_53",id7); Expr id183=vc->varExpr("x_54",id7); Expr id185=vc->varExpr("x_55",id7); Expr id187=vc->varExpr("x_56",id7); Expr id189=vc->varExpr("x_57",id19); Expr id191=vc->varExpr("x_58",id7); Expr id193=vc->varExpr("x_59",id7); Expr id195=vc->varExpr("x_60",id7); Expr id197=vc->varExpr("x_61",id19); Expr id199=vc->varExpr("x_62",id7); Expr id201=vc->varExpr("x_63",id7); Expr id203=vc->varExpr("x_64",id7); Expr id205=vc->varExpr("x_65",id7); Expr id207=vc->varExpr("x_66",id7); Expr id209=vc->varExpr("x_67",id7); Expr id211=vc->varExpr("x_68",id19); Expr id213=vc->varExpr("x_69",id7); Expr id215=vc->varExpr("x_70",id7); Expr id217=vc->varExpr("x_71",id7); Expr id219=vc->varExpr("x_72",id19); Expr id221=vc->varExpr("x_73",id7); Expr id223=vc->varExpr("x_74",id7); Expr id225=vc->varExpr("x_75",id7); Expr id227=vc->varExpr("x_76",id7); Expr id229=vc->varExpr("x_77",id7); Expr id231=vc->varExpr("x_78",id7); Expr id233=vc->varExpr("x_79",id19); Expr id235=vc->varExpr("x_80",id7); Expr id237=vc->varExpr("x_81",id7); Expr id239=vc->varExpr("x_82",id7); Expr id241=vc->varExpr("x_83",id19); Expr id243=vc->varExpr("x_84",id7); Expr id245=vc->varExpr("x_85",id7); Expr id247=vc->varExpr("x_86",id7); Expr id249=vc->varExpr("x_87",id7); Expr id251=vc->varExpr("x_88",id7); Expr id253=vc->varExpr("x_89",id7); Expr id255=vc->varExpr("x_90",id19); Expr id257=vc->varExpr("x_91",id7); Expr id259=vc->varExpr("x_92",id7); Expr id261=vc->varExpr("x_93",id7); Expr id263=vc->varExpr("x_94",id19); Expr id265=vc->varExpr("x_95",id7); Expr id267=vc->varExpr("x_96",id7); Expr id269=vc->varExpr("x_97",id7); Expr id271=vc->varExpr("x_98",id7); Expr id273=vc->varExpr("x_99",id7); Expr id275=vc->varExpr("x_100",id7); Expr id277=vc->varExpr("x_101",id19); Expr id279=vc->varExpr("x_102",id7); Expr id281=vc->varExpr("x_103",id7); Expr id283=vc->varExpr("x_104",id7); Expr id285=vc->varExpr("x_105",id19); Expr id287=vc->varExpr("x_106",id7); Expr id289=vc->varExpr("x_107",id7); Expr id291=vc->varExpr("x_108",id7); Expr id293=vc->varExpr("x_109",id7); Expr id295=vc->varExpr("x_110",id7); Expr id297=vc->varExpr("x_111",id7); Expr id299=vc->varExpr("x_112",id19); Expr id301=vc->varExpr("x_113",id7); Expr id303=vc->varExpr("x_114",id7); Expr id305=vc->varExpr("x_115",id7); Expr id307=vc->varExpr("x_116",id19); Expr id309=vc->varExpr("x_117",id7); Expr id311=vc->varExpr("x_118",id7); Expr id313=vc->varExpr("x_119",id7); Expr id315=vc->varExpr("x_120",id7); Expr id317=vc->varExpr("x_121",id7); Expr id319=vc->varExpr("x_122",id7); Expr id321=vc->varExpr("x_123",id7); Expr id323=vc->varExpr("x_124",id7); Expr id325=vc->varExpr("x_125",id7); Expr id327=vc->varExpr("x_126",id7); Expr id329=vc->varExpr("x_127",id7); Expr id331=vc->varExpr("x_128",id7); Expr id333=vc->ratExpr(1,1); Expr id335=vc->plusExpr(id75,id333); Expr id337=vc->eqExpr(id335,id87); Expr id336=vc->notExpr(id337); vc->registerAtom(id337); Expr id339=vc->eqExpr(id79,id93); Expr id338=vc->notExpr(id339); vc->registerAtom(id339); Expr id341=vc->eqExpr(id97,id95); Expr id340=vc->notExpr(id341); vc->registerAtom(id341); Expr id343=vc->eqExpr(id101,id99); Expr id342=vc->notExpr(id343); vc->registerAtom(id343); Expr id345=vc->eqExpr(id77,id103); Expr id344=vc->notExpr(id345); vc->registerAtom(id345); Expr id347=vc->eqExpr(id81,id105); Expr id346=vc->notExpr(id347); vc->registerAtom(id347); Expr id349=vc->eqExpr(id83,id107); Expr id348=vc->notExpr(id349); vc->registerAtom(id349); Expr id351=vc->eqExpr(id111,id109); Expr id350=vc->notExpr(id351); vc->registerAtom(id351); Expr id353=vc->plusExpr(id87,id333); Expr id355=vc->eqExpr(id353,id117); Expr id354=vc->notExpr(id355); vc->registerAtom(id355); Expr id357=vc->eqExpr(id93,id121); Expr id356=vc->notExpr(id357); vc->registerAtom(id357); Expr id359=vc->eqExpr(id95,id123); Expr id358=vc->notExpr(id359); vc->registerAtom(id359); Expr id361=vc->eqExpr(id99,id125); Expr id360=vc->notExpr(id361); vc->registerAtom(id361); Expr id363=vc->eqExpr(id103,id127); Expr id362=vc->notExpr(id363); vc->registerAtom(id363); Expr id365=vc->eqExpr(id105,id129); Expr id364=vc->notExpr(id365); vc->registerAtom(id365); Expr id367=vc->eqExpr(id107,id131); Expr id366=vc->notExpr(id367); vc->registerAtom(id367); Expr id369=vc->eqExpr(id109,id133); Expr id368=vc->notExpr(id369); vc->registerAtom(id369); Expr id371=vc->plusExpr(id117,id333); Expr id373=vc->eqExpr(id371,id139); Expr id372=vc->notExpr(id373); vc->registerAtom(id373); Expr id375=vc->eqExpr(id121,id143); Expr id374=vc->notExpr(id375); vc->registerAtom(id375); Expr id377=vc->eqExpr(id123,id145); Expr id376=vc->notExpr(id377); vc->registerAtom(id377); Expr id379=vc->eqExpr(id125,id147); Expr id378=vc->notExpr(id379); vc->registerAtom(id379); Expr id381=vc->eqExpr(id127,id149); Expr id380=vc->notExpr(id381); vc->registerAtom(id381); Expr id383=vc->eqExpr(id129,id151); Expr id382=vc->notExpr(id383); vc->registerAtom(id383); Expr id385=vc->eqExpr(id131,id153); Expr id384=vc->notExpr(id385); vc->registerAtom(id385); Expr id387=vc->eqExpr(id133,id155); Expr id386=vc->notExpr(id387); vc->registerAtom(id387); Expr id389=vc->plusExpr(id139,id333); Expr id391=vc->eqExpr(id389,id161); Expr id390=vc->notExpr(id391); vc->registerAtom(id391); Expr id393=vc->eqExpr(id143,id165); Expr id392=vc->notExpr(id393); vc->registerAtom(id393); Expr id395=vc->eqExpr(id145,id167); Expr id394=vc->notExpr(id395); vc->registerAtom(id395); Expr id397=vc->eqExpr(id147,id169); Expr id396=vc->notExpr(id397); vc->registerAtom(id397); Expr id399=vc->eqExpr(id149,id171); Expr id398=vc->notExpr(id399); vc->registerAtom(id399); Expr id401=vc->eqExpr(id151,id173); Expr id400=vc->notExpr(id401); vc->registerAtom(id401); Expr id403=vc->eqExpr(id153,id175); Expr id402=vc->notExpr(id403); vc->registerAtom(id403); Expr id405=vc->eqExpr(id155,id177); Expr id404=vc->notExpr(id405); vc->registerAtom(id405); Expr id407=vc->plusExpr(id161,id333); Expr id409=vc->eqExpr(id407,id183); Expr id408=vc->notExpr(id409); vc->registerAtom(id409); Expr id411=vc->eqExpr(id165,id187); Expr id410=vc->notExpr(id411); vc->registerAtom(id411); Expr id413=vc->eqExpr(id167,id189); Expr id412=vc->notExpr(id413); vc->registerAtom(id413); Expr id415=vc->eqExpr(id169,id191); Expr id414=vc->notExpr(id415); vc->registerAtom(id415); Expr id417=vc->eqExpr(id171,id193); Expr id416=vc->notExpr(id417); vc->registerAtom(id417); Expr id419=vc->eqExpr(id173,id195); Expr id418=vc->notExpr(id419); vc->registerAtom(id419); Expr id421=vc->eqExpr(id175,id197); Expr id420=vc->notExpr(id421); vc->registerAtom(id421); Expr id423=vc->eqExpr(id177,id199); Expr id422=vc->notExpr(id423); vc->registerAtom(id423); Expr id425=vc->plusExpr(id183,id333); Expr id427=vc->eqExpr(id425,id205); Expr id426=vc->notExpr(id427); vc->registerAtom(id427); Expr id429=vc->eqExpr(id187,id209); Expr id428=vc->notExpr(id429); vc->registerAtom(id429); Expr id431=vc->eqExpr(id189,id211); Expr id430=vc->notExpr(id431); vc->registerAtom(id431); Expr id433=vc->eqExpr(id191,id213); Expr id432=vc->notExpr(id433); vc->registerAtom(id433); Expr id435=vc->eqExpr(id193,id215); Expr id434=vc->notExpr(id435); vc->registerAtom(id435); Expr id437=vc->eqExpr(id195,id217); Expr id436=vc->notExpr(id437); vc->registerAtom(id437); Expr id439=vc->eqExpr(id197,id219); Expr id438=vc->notExpr(id439); vc->registerAtom(id439); Expr id441=vc->eqExpr(id199,id221); Expr id440=vc->notExpr(id441); vc->registerAtom(id441); Expr id443=vc->plusExpr(id205,id333); Expr id445=vc->eqExpr(id443,id227); Expr id444=vc->notExpr(id445); vc->registerAtom(id445); Expr id447=vc->eqExpr(id209,id231); Expr id446=vc->notExpr(id447); vc->registerAtom(id447); Expr id449=vc->eqExpr(id211,id233); Expr id448=vc->notExpr(id449); vc->registerAtom(id449); Expr id451=vc->eqExpr(id213,id235); Expr id450=vc->notExpr(id451); vc->registerAtom(id451); Expr id453=vc->eqExpr(id215,id237); Expr id452=vc->notExpr(id453); vc->registerAtom(id453); Expr id455=vc->eqExpr(id217,id239); Expr id454=vc->notExpr(id455); vc->registerAtom(id455); Expr id457=vc->eqExpr(id219,id241); Expr id456=vc->notExpr(id457); vc->registerAtom(id457); Expr id459=vc->eqExpr(id221,id243); Expr id458=vc->notExpr(id459); vc->registerAtom(id459); Expr id461=vc->plusExpr(id227,id333); Expr id463=vc->eqExpr(id461,id249); Expr id462=vc->notExpr(id463); vc->registerAtom(id463); Expr id465=vc->eqExpr(id231,id253); Expr id464=vc->notExpr(id465); vc->registerAtom(id465); Expr id467=vc->eqExpr(id233,id255); Expr id466=vc->notExpr(id467); vc->registerAtom(id467); Expr id469=vc->eqExpr(id235,id257); Expr id468=vc->notExpr(id469); vc->registerAtom(id469); Expr id471=vc->eqExpr(id237,id259); Expr id470=vc->notExpr(id471); vc->registerAtom(id471); Expr id473=vc->eqExpr(id239,id261); Expr id472=vc->notExpr(id473); vc->registerAtom(id473); Expr id475=vc->eqExpr(id241,id263); Expr id474=vc->notExpr(id475); vc->registerAtom(id475); Expr id477=vc->eqExpr(id243,id265); Expr id476=vc->notExpr(id477); vc->registerAtom(id477); Expr id479=vc->plusExpr(id249,id333); Expr id481=vc->eqExpr(id479,id271); Expr id480=vc->notExpr(id481); vc->registerAtom(id481); Expr id483=vc->eqExpr(id253,id275); Expr id482=vc->notExpr(id483); vc->registerAtom(id483); Expr id485=vc->eqExpr(id255,id277); Expr id484=vc->notExpr(id485); vc->registerAtom(id485); Expr id487=vc->eqExpr(id257,id279); Expr id486=vc->notExpr(id487); vc->registerAtom(id487); Expr id489=vc->eqExpr(id259,id281); Expr id488=vc->notExpr(id489); vc->registerAtom(id489); Expr id491=vc->eqExpr(id261,id283); Expr id490=vc->notExpr(id491); vc->registerAtom(id491); Expr id493=vc->eqExpr(id263,id285); Expr id492=vc->notExpr(id493); vc->registerAtom(id493); Expr id495=vc->eqExpr(id265,id287); Expr id494=vc->notExpr(id495); vc->registerAtom(id495); Expr id497=vc->plusExpr(id271,id333); Expr id499=vc->eqExpr(id497,id293); Expr id498=vc->notExpr(id499); vc->registerAtom(id499); Expr id501=vc->eqExpr(id275,id297); Expr id500=vc->notExpr(id501); vc->registerAtom(id501); Expr id503=vc->eqExpr(id277,id299); Expr id502=vc->notExpr(id503); vc->registerAtom(id503); Expr id505=vc->eqExpr(id279,id301); Expr id504=vc->notExpr(id505); vc->registerAtom(id505); Expr id507=vc->eqExpr(id281,id303); Expr id506=vc->notExpr(id507); vc->registerAtom(id507); Expr id509=vc->eqExpr(id283,id305); Expr id508=vc->notExpr(id509); vc->registerAtom(id509); Expr id511=vc->eqExpr(id285,id307); Expr id510=vc->notExpr(id511); vc->registerAtom(id511); Expr id513=vc->eqExpr(id287,id309); Expr id512=vc->notExpr(id513); vc->registerAtom(id513); Expr id515=vc->uminusExpr(id333); Expr id517=vc->eqExpr(id515,id79); Expr id516=vc->notExpr(id517); vc->registerAtom(id517); Expr id519=vc->eqExpr(id515,id275); Expr id518=vc->notExpr(id519); vc->registerAtom(id519); Expr id521=vc->eqExpr(id515,id253); Expr id520=vc->notExpr(id521); vc->registerAtom(id521); Expr id523=vc->eqExpr(id515,id231); Expr id522=vc->notExpr(id523); vc->registerAtom(id523); Expr id525=vc->eqExpr(id515,id209); Expr id524=vc->notExpr(id525); vc->registerAtom(id525); Expr id527=vc->eqExpr(id515,id187); Expr id526=vc->notExpr(id527); vc->registerAtom(id527); Expr id529=vc->eqExpr(id515,id165); Expr id528=vc->notExpr(id529); vc->registerAtom(id529); Expr id531=vc->eqExpr(id515,id143); Expr id530=vc->notExpr(id531); vc->registerAtom(id531); Expr id533=vc->eqExpr(id515,id121); Expr id532=vc->notExpr(id533); vc->registerAtom(id533); Expr id535=vc->eqExpr(id515,id93); Expr id534=vc->notExpr(id535); vc->registerAtom(id535); Expr id537=vc->ratExpr(0,1); Expr id539=vc->leExpr(id89,id537); Expr id538=vc->notExpr(id539); vc->registerAtom(id539); Expr id543=vc->eqExpr(id537,id75); Expr id542=vc->notExpr(id543); vc->registerAtom(id543); Expr id547=vc->eqExpr(id537,id77); Expr id546=vc->notExpr(id547); vc->registerAtom(id547); Expr id553=vc->eqExpr(id537,id81); Expr id552=vc->notExpr(id553); vc->registerAtom(id553); Expr id557=vc->readExpr(id83,id79); Expr id559=vc->eqExpr(id557,id313); Expr id558=vc->notExpr(id559); vc->registerAtom(id559); Expr id563=vc->eqExpr(id313,id85); Expr id562=vc->notExpr(id563); vc->registerAtom(id563); Expr id567=vc->ratExpr(2,1); Expr id569=vc->plusExpr(id89,id567); Expr id571=vc->eqExpr(id569,id91); Expr id570=vc->notExpr(id571); vc->registerAtom(id571); Expr id575=vc->readExpr(id107,id93); Expr id577=vc->eqExpr(id575,id315); Expr id576=vc->notExpr(id577); vc->registerAtom(id577); Expr id581=vc->eqExpr(id315,id115); Expr id580=vc->notExpr(id581); vc->registerAtom(id581); Expr id585=vc->eqExpr(id569,id119); Expr id584=vc->notExpr(id585); vc->registerAtom(id585); Expr id589=vc->readExpr(id131,id121); Expr id591=vc->eqExpr(id589,id317); Expr id590=vc->notExpr(id591); vc->registerAtom(id591); Expr id595=vc->eqExpr(id317,id137); Expr id594=vc->notExpr(id595); vc->registerAtom(id595); Expr id599=vc->eqExpr(id569,id141); Expr id598=vc->notExpr(id599); vc->registerAtom(id599); Expr id603=vc->readExpr(id153,id143); Expr id605=vc->eqExpr(id603,id319); Expr id604=vc->notExpr(id605); vc->registerAtom(id605); Expr id609=vc->eqExpr(id319,id159); Expr id608=vc->notExpr(id609); vc->registerAtom(id609); Expr id613=vc->eqExpr(id569,id163); Expr id612=vc->notExpr(id613); vc->registerAtom(id613); Expr id617=vc->readExpr(id175,id165); Expr id619=vc->eqExpr(id617,id321); Expr id618=vc->notExpr(id619); vc->registerAtom(id619); Expr id623=vc->eqExpr(id321,id181); Expr id622=vc->notExpr(id623); vc->registerAtom(id623); Expr id627=vc->eqExpr(id569,id185); Expr id626=vc->notExpr(id627); vc->registerAtom(id627); Expr id631=vc->readExpr(id197,id187); Expr id633=vc->eqExpr(id631,id323); Expr id632=vc->notExpr(id633); vc->registerAtom(id633); Expr id637=vc->eqExpr(id323,id203); Expr id636=vc->notExpr(id637); vc->registerAtom(id637); Expr id641=vc->eqExpr(id569,id207); Expr id640=vc->notExpr(id641); vc->registerAtom(id641); Expr id645=vc->readExpr(id219,id209); Expr id647=vc->eqExpr(id645,id325); Expr id646=vc->notExpr(id647); vc->registerAtom(id647); Expr id651=vc->eqExpr(id325,id225); Expr id650=vc->notExpr(id651); vc->registerAtom(id651); Expr id655=vc->eqExpr(id569,id229); Expr id654=vc->notExpr(id655); vc->registerAtom(id655); Expr id659=vc->readExpr(id241,id231); Expr id661=vc->eqExpr(id659,id327); Expr id660=vc->notExpr(id661); vc->registerAtom(id661); Expr id665=vc->eqExpr(id327,id247); Expr id664=vc->notExpr(id665); vc->registerAtom(id665); Expr id669=vc->eqExpr(id569,id251); Expr id668=vc->notExpr(id669); vc->registerAtom(id669); Expr id673=vc->readExpr(id263,id253); Expr id675=vc->eqExpr(id673,id329); Expr id674=vc->notExpr(id675); vc->registerAtom(id675); Expr id679=vc->eqExpr(id329,id269); Expr id678=vc->notExpr(id679); vc->registerAtom(id679); Expr id683=vc->eqExpr(id569,id273); Expr id682=vc->notExpr(id683); vc->registerAtom(id683); Expr id687=vc->readExpr(id285,id275); Expr id689=vc->eqExpr(id687,id331); Expr id688=vc->notExpr(id689); vc->registerAtom(id689); Expr id693=vc->eqExpr(id331,id291); Expr id692=vc->notExpr(id693); vc->registerAtom(id693); Expr id697=vc->eqExpr(id569,id295); Expr id696=vc->notExpr(id697); vc->registerAtom(id697); Expr id701=vc->eqExpr(id537,id311); Expr id700=vc->notExpr(id701); vc->registerAtom(id701); Expr id703=vc->ltExpr(id271,id89); Expr id702=vc->notExpr(id703); vc->registerAtom(id703); Expr id709=vc->plusExpr(id283,id333); Expr id711=vc->eqExpr(id709,id305); Expr id710=vc->notExpr(id711); vc->registerAtom(id711); Expr id715=vc->eqExpr(id281,id297); Expr id714=vc->notExpr(id715); vc->registerAtom(id715); Expr id719=vc->plusExpr(id281,id333); Expr id721=vc->eqExpr(id719,id303); Expr id720=vc->notExpr(id721); vc->registerAtom(id721); Expr id725=vc->writeExpr(id277,id281,id271); Expr id727=vc->eqExpr(id725,id299); Expr id726=vc->notExpr(id727); vc->registerAtom(id727); Expr id733=vc->writeExpr(id285,id281,id275); Expr id735=vc->eqExpr(id733,id307); Expr id734=vc->notExpr(id735); vc->registerAtom(id735); Expr id741=vc->eqExpr(id333,id311); Expr id740=vc->notExpr(id741); vc->registerAtom(id741); Expr id743=vc->eqExpr(id89,id271); Expr id742=vc->notExpr(id743); vc->registerAtom(id743); Expr id751=vc->eqExpr(id275,id309); Expr id750=vc->notExpr(id751); vc->registerAtom(id751); Expr id755=vc->eqExpr(id291,id297); Expr id754=vc->notExpr(id755); vc->registerAtom(id755); Expr id773=vc->eqExpr(id567,id311); Expr id772=vc->notExpr(id773); vc->registerAtom(id773); Expr id775=vc->plusExpr(id89,id333); Expr id777=vc->eqExpr(id775,id271); Expr id776=vc->notExpr(id777); vc->registerAtom(id777); Expr id793=vc->writeExpr(id285,id287,id291); Expr id795=vc->eqExpr(id793,id307); Expr id794=vc->notExpr(id795); vc->registerAtom(id795); Expr id803=vc->ratExpr(3,1); Expr id805=vc->eqExpr(id803,id311); Expr id804=vc->notExpr(id805); vc->registerAtom(id805); Expr id807=vc->eqExpr(id295,id271); Expr id806=vc->notExpr(id807); vc->registerAtom(id807); Expr id823=vc->writeExpr(id285,id275,id287); Expr id825=vc->eqExpr(id823,id307); Expr id824=vc->notExpr(id825); vc->registerAtom(id825); Expr id833=vc->ratExpr(4,1); Expr id835=vc->eqExpr(id833,id311); Expr id834=vc->notExpr(id835); vc->registerAtom(id835); Expr id837=vc->leExpr(id271,id295); Expr id836=vc->notExpr(id837); vc->registerAtom(id837); Expr id857=vc->eqExpr(id271,id293); Expr id856=vc->notExpr(id857); vc->registerAtom(id857); Expr id865=vc->eqExpr(id537,id289); Expr id864=vc->notExpr(id865); vc->registerAtom(id865); Expr id867=vc->ltExpr(id249,id89); Expr id866=vc->notExpr(id867); vc->registerAtom(id867); Expr id873=vc->plusExpr(id261,id333); Expr id875=vc->eqExpr(id873,id283); Expr id874=vc->notExpr(id875); vc->registerAtom(id875); Expr id879=vc->eqExpr(id259,id275); Expr id878=vc->notExpr(id879); vc->registerAtom(id879); Expr id883=vc->plusExpr(id259,id333); Expr id885=vc->eqExpr(id883,id281); Expr id884=vc->notExpr(id885); vc->registerAtom(id885); Expr id889=vc->writeExpr(id255,id259,id249); Expr id891=vc->eqExpr(id889,id277); Expr id890=vc->notExpr(id891); vc->registerAtom(id891); Expr id897=vc->writeExpr(id263,id259,id253); Expr id899=vc->eqExpr(id897,id285); Expr id898=vc->notExpr(id899); vc->registerAtom(id899); Expr id905=vc->eqExpr(id333,id289); Expr id904=vc->notExpr(id905); vc->registerAtom(id905); Expr id907=vc->eqExpr(id89,id249); Expr id906=vc->notExpr(id907); vc->registerAtom(id907); Expr id915=vc->eqExpr(id253,id287); Expr id914=vc->notExpr(id915); vc->registerAtom(id915); Expr id919=vc->eqExpr(id269,id275); Expr id918=vc->notExpr(id919); vc->registerAtom(id919); Expr id937=vc->eqExpr(id567,id289); Expr id936=vc->notExpr(id937); vc->registerAtom(id937); Expr id939=vc->eqExpr(id775,id249); Expr id938=vc->notExpr(id939); vc->registerAtom(id939); Expr id955=vc->writeExpr(id263,id265,id269); Expr id957=vc->eqExpr(id955,id285); Expr id956=vc->notExpr(id957); vc->registerAtom(id957); Expr id965=vc->eqExpr(id803,id289); Expr id964=vc->notExpr(id965); vc->registerAtom(id965); Expr id967=vc->eqExpr(id273,id249); Expr id966=vc->notExpr(id967); vc->registerAtom(id967); Expr id983=vc->writeExpr(id263,id253,id265); Expr id985=vc->eqExpr(id983,id285); Expr id984=vc->notExpr(id985); vc->registerAtom(id985); Expr id993=vc->eqExpr(id833,id289); Expr id992=vc->notExpr(id993); vc->registerAtom(id993); Expr id995=vc->leExpr(id249,id273); Expr id994=vc->notExpr(id995); vc->registerAtom(id995); Expr id1015=vc->eqExpr(id249,id271); Expr id1014=vc->notExpr(id1015); vc->registerAtom(id1015); Expr id1023=vc->eqExpr(id537,id267); Expr id1022=vc->notExpr(id1023); vc->registerAtom(id1023); Expr id1025=vc->ltExpr(id227,id89); Expr id1024=vc->notExpr(id1025); vc->registerAtom(id1025); Expr id1031=vc->plusExpr(id239,id333); Expr id1033=vc->eqExpr(id1031,id261); Expr id1032=vc->notExpr(id1033); vc->registerAtom(id1033); Expr id1037=vc->eqExpr(id237,id253); Expr id1036=vc->notExpr(id1037); vc->registerAtom(id1037); Expr id1041=vc->plusExpr(id237,id333); Expr id1043=vc->eqExpr(id1041,id259); Expr id1042=vc->notExpr(id1043); vc->registerAtom(id1043); Expr id1047=vc->writeExpr(id233,id237,id227); Expr id1049=vc->eqExpr(id1047,id255); Expr id1048=vc->notExpr(id1049); vc->registerAtom(id1049); Expr id1055=vc->writeExpr(id241,id237,id231); Expr id1057=vc->eqExpr(id1055,id263); Expr id1056=vc->notExpr(id1057); vc->registerAtom(id1057); Expr id1063=vc->eqExpr(id333,id267); Expr id1062=vc->notExpr(id1063); vc->registerAtom(id1063); Expr id1065=vc->eqExpr(id89,id227); Expr id1064=vc->notExpr(id1065); vc->registerAtom(id1065); Expr id1073=vc->eqExpr(id231,id265); Expr id1072=vc->notExpr(id1073); vc->registerAtom(id1073); Expr id1077=vc->eqExpr(id247,id253); Expr id1076=vc->notExpr(id1077); vc->registerAtom(id1077); Expr id1095=vc->eqExpr(id567,id267); Expr id1094=vc->notExpr(id1095); vc->registerAtom(id1095); Expr id1097=vc->eqExpr(id775,id227); Expr id1096=vc->notExpr(id1097); vc->registerAtom(id1097); Expr id1113=vc->writeExpr(id241,id243,id247); Expr id1115=vc->eqExpr(id1113,id263); Expr id1114=vc->notExpr(id1115); vc->registerAtom(id1115); Expr id1123=vc->eqExpr(id803,id267); Expr id1122=vc->notExpr(id1123); vc->registerAtom(id1123); Expr id1125=vc->eqExpr(id251,id227); Expr id1124=vc->notExpr(id1125); vc->registerAtom(id1125); Expr id1141=vc->writeExpr(id241,id231,id243); Expr id1143=vc->eqExpr(id1141,id263); Expr id1142=vc->notExpr(id1143); vc->registerAtom(id1143); Expr id1151=vc->eqExpr(id833,id267); Expr id1150=vc->notExpr(id1151); vc->registerAtom(id1151); Expr id1153=vc->leExpr(id227,id251); Expr id1152=vc->notExpr(id1153); vc->registerAtom(id1153); Expr id1173=vc->eqExpr(id227,id249); Expr id1172=vc->notExpr(id1173); vc->registerAtom(id1173); Expr id1181=vc->eqExpr(id537,id245); Expr id1180=vc->notExpr(id1181); vc->registerAtom(id1181); Expr id1183=vc->ltExpr(id205,id89); Expr id1182=vc->notExpr(id1183); vc->registerAtom(id1183); Expr id1189=vc->plusExpr(id217,id333); Expr id1191=vc->eqExpr(id1189,id239); Expr id1190=vc->notExpr(id1191); vc->registerAtom(id1191); Expr id1195=vc->eqExpr(id215,id231); Expr id1194=vc->notExpr(id1195); vc->registerAtom(id1195); Expr id1199=vc->plusExpr(id215,id333); Expr id1201=vc->eqExpr(id1199,id237); Expr id1200=vc->notExpr(id1201); vc->registerAtom(id1201); Expr id1205=vc->writeExpr(id211,id215,id205); Expr id1207=vc->eqExpr(id1205,id233); Expr id1206=vc->notExpr(id1207); vc->registerAtom(id1207); Expr id1213=vc->writeExpr(id219,id215,id209); Expr id1215=vc->eqExpr(id1213,id241); Expr id1214=vc->notExpr(id1215); vc->registerAtom(id1215); Expr id1221=vc->eqExpr(id333,id245); Expr id1220=vc->notExpr(id1221); vc->registerAtom(id1221); Expr id1223=vc->eqExpr(id89,id205); Expr id1222=vc->notExpr(id1223); vc->registerAtom(id1223); Expr id1231=vc->eqExpr(id209,id243); Expr id1230=vc->notExpr(id1231); vc->registerAtom(id1231); Expr id1235=vc->eqExpr(id225,id231); Expr id1234=vc->notExpr(id1235); vc->registerAtom(id1235); Expr id1253=vc->eqExpr(id567,id245); Expr id1252=vc->notExpr(id1253); vc->registerAtom(id1253); Expr id1255=vc->eqExpr(id775,id205); Expr id1254=vc->notExpr(id1255); vc->registerAtom(id1255); Expr id1271=vc->writeExpr(id219,id221,id225); Expr id1273=vc->eqExpr(id1271,id241); Expr id1272=vc->notExpr(id1273); vc->registerAtom(id1273); Expr id1281=vc->eqExpr(id803,id245); Expr id1280=vc->notExpr(id1281); vc->registerAtom(id1281); Expr id1283=vc->eqExpr(id229,id205); Expr id1282=vc->notExpr(id1283); vc->registerAtom(id1283); Expr id1299=vc->writeExpr(id219,id209,id221); Expr id1301=vc->eqExpr(id1299,id241); Expr id1300=vc->notExpr(id1301); vc->registerAtom(id1301); Expr id1309=vc->eqExpr(id833,id245); Expr id1308=vc->notExpr(id1309); vc->registerAtom(id1309); Expr id1311=vc->leExpr(id205,id229); Expr id1310=vc->notExpr(id1311); vc->registerAtom(id1311); Expr id1331=vc->eqExpr(id205,id227); Expr id1330=vc->notExpr(id1331); vc->registerAtom(id1331); Expr id1339=vc->eqExpr(id537,id223); Expr id1338=vc->notExpr(id1339); vc->registerAtom(id1339); Expr id1341=vc->ltExpr(id183,id89); Expr id1340=vc->notExpr(id1341); vc->registerAtom(id1341); Expr id1347=vc->plusExpr(id195,id333); Expr id1349=vc->eqExpr(id1347,id217); Expr id1348=vc->notExpr(id1349); vc->registerAtom(id1349); Expr id1353=vc->eqExpr(id193,id209); Expr id1352=vc->notExpr(id1353); vc->registerAtom(id1353); Expr id1357=vc->plusExpr(id193,id333); Expr id1359=vc->eqExpr(id1357,id215); Expr id1358=vc->notExpr(id1359); vc->registerAtom(id1359); Expr id1363=vc->writeExpr(id189,id193,id183); Expr id1365=vc->eqExpr(id1363,id211); Expr id1364=vc->notExpr(id1365); vc->registerAtom(id1365); Expr id1371=vc->writeExpr(id197,id193,id187); Expr id1373=vc->eqExpr(id1371,id219); Expr id1372=vc->notExpr(id1373); vc->registerAtom(id1373); Expr id1379=vc->eqExpr(id333,id223); Expr id1378=vc->notExpr(id1379); vc->registerAtom(id1379); Expr id1381=vc->eqExpr(id89,id183); Expr id1380=vc->notExpr(id1381); vc->registerAtom(id1381); Expr id1389=vc->eqExpr(id187,id221); Expr id1388=vc->notExpr(id1389); vc->registerAtom(id1389); Expr id1393=vc->eqExpr(id203,id209); Expr id1392=vc->notExpr(id1393); vc->registerAtom(id1393); Expr id1411=vc->eqExpr(id567,id223); Expr id1410=vc->notExpr(id1411); vc->registerAtom(id1411); Expr id1413=vc->eqExpr(id775,id183); Expr id1412=vc->notExpr(id1413); vc->registerAtom(id1413); Expr id1429=vc->writeExpr(id197,id199,id203); Expr id1431=vc->eqExpr(id1429,id219); Expr id1430=vc->notExpr(id1431); vc->registerAtom(id1431); Expr id1439=vc->eqExpr(id803,id223); Expr id1438=vc->notExpr(id1439); vc->registerAtom(id1439); Expr id1441=vc->eqExpr(id207,id183); Expr id1440=vc->notExpr(id1441); vc->registerAtom(id1441); Expr id1457=vc->writeExpr(id197,id187,id199); Expr id1459=vc->eqExpr(id1457,id219); Expr id1458=vc->notExpr(id1459); vc->registerAtom(id1459); Expr id1467=vc->eqExpr(id833,id223); Expr id1466=vc->notExpr(id1467); vc->registerAtom(id1467); Expr id1469=vc->leExpr(id183,id207); Expr id1468=vc->notExpr(id1469); vc->registerAtom(id1469); Expr id1489=vc->eqExpr(id183,id205); Expr id1488=vc->notExpr(id1489); vc->registerAtom(id1489); Expr id1497=vc->eqExpr(id537,id201); Expr id1496=vc->notExpr(id1497); vc->registerAtom(id1497); Expr id1499=vc->ltExpr(id161,id89); Expr id1498=vc->notExpr(id1499); vc->registerAtom(id1499); Expr id1505=vc->plusExpr(id173,id333); Expr id1507=vc->eqExpr(id1505,id195); Expr id1506=vc->notExpr(id1507); vc->registerAtom(id1507); Expr id1511=vc->eqExpr(id171,id187); Expr id1510=vc->notExpr(id1511); vc->registerAtom(id1511); Expr id1515=vc->plusExpr(id171,id333); Expr id1517=vc->eqExpr(id1515,id193); Expr id1516=vc->notExpr(id1517); vc->registerAtom(id1517); Expr id1521=vc->writeExpr(id167,id171,id161); Expr id1523=vc->eqExpr(id1521,id189); Expr id1522=vc->notExpr(id1523); vc->registerAtom(id1523); Expr id1529=vc->writeExpr(id175,id171,id165); Expr id1531=vc->eqExpr(id1529,id197); Expr id1530=vc->notExpr(id1531); vc->registerAtom(id1531); Expr id1537=vc->eqExpr(id333,id201); Expr id1536=vc->notExpr(id1537); vc->registerAtom(id1537); Expr id1539=vc->eqExpr(id89,id161); Expr id1538=vc->notExpr(id1539); vc->registerAtom(id1539); Expr id1547=vc->eqExpr(id165,id199); Expr id1546=vc->notExpr(id1547); vc->registerAtom(id1547); Expr id1551=vc->eqExpr(id181,id187); Expr id1550=vc->notExpr(id1551); vc->registerAtom(id1551); Expr id1569=vc->eqExpr(id567,id201); Expr id1568=vc->notExpr(id1569); vc->registerAtom(id1569); Expr id1571=vc->eqExpr(id775,id161); Expr id1570=vc->notExpr(id1571); vc->registerAtom(id1571); Expr id1587=vc->writeExpr(id175,id177,id181); Expr id1589=vc->eqExpr(id1587,id197); Expr id1588=vc->notExpr(id1589); vc->registerAtom(id1589); Expr id1597=vc->eqExpr(id803,id201); Expr id1596=vc->notExpr(id1597); vc->registerAtom(id1597); Expr id1599=vc->eqExpr(id185,id161); Expr id1598=vc->notExpr(id1599); vc->registerAtom(id1599); Expr id1615=vc->writeExpr(id175,id165,id177); Expr id1617=vc->eqExpr(id1615,id197); Expr id1616=vc->notExpr(id1617); vc->registerAtom(id1617); Expr id1625=vc->eqExpr(id833,id201); Expr id1624=vc->notExpr(id1625); vc->registerAtom(id1625); Expr id1627=vc->leExpr(id161,id185); Expr id1626=vc->notExpr(id1627); vc->registerAtom(id1627); Expr id1647=vc->eqExpr(id161,id183); Expr id1646=vc->notExpr(id1647); vc->registerAtom(id1647); Expr id1655=vc->eqExpr(id537,id179); Expr id1654=vc->notExpr(id1655); vc->registerAtom(id1655); Expr id1657=vc->ltExpr(id139,id89); Expr id1656=vc->notExpr(id1657); vc->registerAtom(id1657); Expr id1663=vc->plusExpr(id151,id333); Expr id1665=vc->eqExpr(id1663,id173); Expr id1664=vc->notExpr(id1665); vc->registerAtom(id1665); Expr id1669=vc->eqExpr(id149,id165); Expr id1668=vc->notExpr(id1669); vc->registerAtom(id1669); Expr id1673=vc->plusExpr(id149,id333); Expr id1675=vc->eqExpr(id1673,id171); Expr id1674=vc->notExpr(id1675); vc->registerAtom(id1675); Expr id1679=vc->writeExpr(id145,id149,id139); Expr id1681=vc->eqExpr(id1679,id167); Expr id1680=vc->notExpr(id1681); vc->registerAtom(id1681); Expr id1687=vc->writeExpr(id153,id149,id143); Expr id1689=vc->eqExpr(id1687,id175); Expr id1688=vc->notExpr(id1689); vc->registerAtom(id1689); Expr id1695=vc->eqExpr(id333,id179); Expr id1694=vc->notExpr(id1695); vc->registerAtom(id1695); Expr id1697=vc->eqExpr(id89,id139); Expr id1696=vc->notExpr(id1697); vc->registerAtom(id1697); Expr id1705=vc->eqExpr(id143,id177); Expr id1704=vc->notExpr(id1705); vc->registerAtom(id1705); Expr id1709=vc->eqExpr(id159,id165); Expr id1708=vc->notExpr(id1709); vc->registerAtom(id1709); Expr id1727=vc->eqExpr(id567,id179); Expr id1726=vc->notExpr(id1727); vc->registerAtom(id1727); Expr id1729=vc->eqExpr(id775,id139); Expr id1728=vc->notExpr(id1729); vc->registerAtom(id1729); Expr id1745=vc->writeExpr(id153,id155,id159); Expr id1747=vc->eqExpr(id1745,id175); Expr id1746=vc->notExpr(id1747); vc->registerAtom(id1747); Expr id1755=vc->eqExpr(id803,id179); Expr id1754=vc->notExpr(id1755); vc->registerAtom(id1755); Expr id1757=vc->eqExpr(id163,id139); Expr id1756=vc->notExpr(id1757); vc->registerAtom(id1757); Expr id1773=vc->writeExpr(id153,id143,id155); Expr id1775=vc->eqExpr(id1773,id175); Expr id1774=vc->notExpr(id1775); vc->registerAtom(id1775); Expr id1783=vc->eqExpr(id833,id179); Expr id1782=vc->notExpr(id1783); vc->registerAtom(id1783); Expr id1785=vc->leExpr(id139,id163); Expr id1784=vc->notExpr(id1785); vc->registerAtom(id1785); Expr id1805=vc->eqExpr(id139,id161); Expr id1804=vc->notExpr(id1805); vc->registerAtom(id1805); Expr id1813=vc->eqExpr(id537,id157); Expr id1812=vc->notExpr(id1813); vc->registerAtom(id1813); Expr id1815=vc->ltExpr(id117,id89); Expr id1814=vc->notExpr(id1815); vc->registerAtom(id1815); Expr id1821=vc->plusExpr(id129,id333); Expr id1823=vc->eqExpr(id1821,id151); Expr id1822=vc->notExpr(id1823); vc->registerAtom(id1823); Expr id1827=vc->eqExpr(id127,id143); Expr id1826=vc->notExpr(id1827); vc->registerAtom(id1827); Expr id1831=vc->plusExpr(id127,id333); Expr id1833=vc->eqExpr(id1831,id149); Expr id1832=vc->notExpr(id1833); vc->registerAtom(id1833); Expr id1837=vc->writeExpr(id123,id127,id117); Expr id1839=vc->eqExpr(id1837,id145); Expr id1838=vc->notExpr(id1839); vc->registerAtom(id1839); Expr id1845=vc->writeExpr(id131,id127,id121); Expr id1847=vc->eqExpr(id1845,id153); Expr id1846=vc->notExpr(id1847); vc->registerAtom(id1847); Expr id1853=vc->eqExpr(id333,id157); Expr id1852=vc->notExpr(id1853); vc->registerAtom(id1853); Expr id1855=vc->eqExpr(id89,id117); Expr id1854=vc->notExpr(id1855); vc->registerAtom(id1855); Expr id1863=vc->eqExpr(id121,id155); Expr id1862=vc->notExpr(id1863); vc->registerAtom(id1863); Expr id1867=vc->eqExpr(id137,id143); Expr id1866=vc->notExpr(id1867); vc->registerAtom(id1867); Expr id1885=vc->eqExpr(id567,id157); Expr id1884=vc->notExpr(id1885); vc->registerAtom(id1885); Expr id1887=vc->eqExpr(id775,id117); Expr id1886=vc->notExpr(id1887); vc->registerAtom(id1887); Expr id1903=vc->writeExpr(id131,id133,id137); Expr id1905=vc->eqExpr(id1903,id153); Expr id1904=vc->notExpr(id1905); vc->registerAtom(id1905); Expr id1913=vc->eqExpr(id803,id157); Expr id1912=vc->notExpr(id1913); vc->registerAtom(id1913); Expr id1915=vc->eqExpr(id141,id117); Expr id1914=vc->notExpr(id1915); vc->registerAtom(id1915); Expr id1931=vc->writeExpr(id131,id121,id133); Expr id1933=vc->eqExpr(id1931,id153); Expr id1932=vc->notExpr(id1933); vc->registerAtom(id1933); Expr id1941=vc->eqExpr(id833,id157); Expr id1940=vc->notExpr(id1941); vc->registerAtom(id1941); Expr id1943=vc->leExpr(id117,id141); Expr id1942=vc->notExpr(id1943); vc->registerAtom(id1943); Expr id1963=vc->eqExpr(id117,id139); Expr id1962=vc->notExpr(id1963); vc->registerAtom(id1963); Expr id1971=vc->eqExpr(id537,id135); Expr id1970=vc->notExpr(id1971); vc->registerAtom(id1971); Expr id1973=vc->ltExpr(id87,id89); Expr id1972=vc->notExpr(id1973); vc->registerAtom(id1973); Expr id1979=vc->plusExpr(id105,id333); Expr id1981=vc->eqExpr(id1979,id129); Expr id1980=vc->notExpr(id1981); vc->registerAtom(id1981); Expr id1985=vc->eqExpr(id103,id121); Expr id1984=vc->notExpr(id1985); vc->registerAtom(id1985); Expr id1989=vc->plusExpr(id103,id333); Expr id1991=vc->eqExpr(id1989,id127); Expr id1990=vc->notExpr(id1991); vc->registerAtom(id1991); Expr id1995=vc->writeExpr(id95,id103,id87); Expr id1997=vc->eqExpr(id1995,id123); Expr id1996=vc->notExpr(id1997); vc->registerAtom(id1997); Expr id2003=vc->writeExpr(id107,id103,id93); Expr id2005=vc->eqExpr(id2003,id131); Expr id2004=vc->notExpr(id2005); vc->registerAtom(id2005); Expr id2011=vc->eqExpr(id333,id135); Expr id2010=vc->notExpr(id2011); vc->registerAtom(id2011); Expr id2013=vc->eqExpr(id89,id87); Expr id2012=vc->notExpr(id2013); vc->registerAtom(id2013); Expr id2021=vc->eqExpr(id93,id133); Expr id2020=vc->notExpr(id2021); vc->registerAtom(id2021); Expr id2025=vc->eqExpr(id115,id121); Expr id2024=vc->notExpr(id2025); vc->registerAtom(id2025); Expr id2043=vc->eqExpr(id567,id135); Expr id2042=vc->notExpr(id2043); vc->registerAtom(id2043); Expr id2045=vc->eqExpr(id775,id87); Expr id2044=vc->notExpr(id2045); vc->registerAtom(id2045); Expr id2061=vc->writeExpr(id107,id109,id115); Expr id2063=vc->eqExpr(id2061,id131); Expr id2062=vc->notExpr(id2063); vc->registerAtom(id2063); Expr id2071=vc->eqExpr(id803,id135); Expr id2070=vc->notExpr(id2071); vc->registerAtom(id2071); Expr id2073=vc->eqExpr(id119,id87); Expr id2072=vc->notExpr(id2073); vc->registerAtom(id2073); Expr id2089=vc->writeExpr(id107,id93,id109); Expr id2091=vc->eqExpr(id2089,id131); Expr id2090=vc->notExpr(id2091); vc->registerAtom(id2091); Expr id2099=vc->eqExpr(id833,id135); Expr id2098=vc->notExpr(id2099); vc->registerAtom(id2099); Expr id2101=vc->leExpr(id87,id119); Expr id2100=vc->notExpr(id2101); vc->registerAtom(id2101); Expr id2121=vc->eqExpr(id87,id117); Expr id2120=vc->notExpr(id2121); vc->registerAtom(id2121); Expr id2129=vc->eqExpr(id537,id113); Expr id2128=vc->notExpr(id2129); vc->registerAtom(id2129); Expr id2131=vc->ltExpr(id75,id89); Expr id2130=vc->notExpr(id2131); vc->registerAtom(id2131); Expr id2137=vc->plusExpr(id81,id333); Expr id2139=vc->eqExpr(id2137,id105); Expr id2138=vc->notExpr(id2139); vc->registerAtom(id2139); Expr id2143=vc->eqExpr(id77,id93); Expr id2142=vc->notExpr(id2143); vc->registerAtom(id2143); Expr id2147=vc->plusExpr(id77,id333); Expr id2149=vc->eqExpr(id2147,id103); Expr id2148=vc->notExpr(id2149); vc->registerAtom(id2149); Expr id2153=vc->writeExpr(id97,id77,id75); Expr id2155=vc->eqExpr(id2153,id95); Expr id2154=vc->notExpr(id2155); vc->registerAtom(id2155); Expr id2161=vc->writeExpr(id83,id77,id79); Expr id2163=vc->eqExpr(id2161,id107); Expr id2162=vc->notExpr(id2163); vc->registerAtom(id2163); Expr id2169=vc->eqExpr(id333,id113); Expr id2168=vc->notExpr(id2169); vc->registerAtom(id2169); Expr id2171=vc->eqExpr(id89,id75); Expr id2170=vc->notExpr(id2171); vc->registerAtom(id2171); Expr id2179=vc->eqExpr(id79,id109); Expr id2178=vc->notExpr(id2179); vc->registerAtom(id2179); Expr id2183=vc->eqExpr(id85,id93); Expr id2182=vc->notExpr(id2183); vc->registerAtom(id2183); Expr id2201=vc->eqExpr(id567,id113); Expr id2200=vc->notExpr(id2201); vc->registerAtom(id2201); Expr id2203=vc->eqExpr(id775,id75); Expr id2202=vc->notExpr(id2203); vc->registerAtom(id2203); Expr id2219=vc->writeExpr(id83,id111,id85); Expr id2221=vc->eqExpr(id2219,id107); Expr id2220=vc->notExpr(id2221); vc->registerAtom(id2221); Expr id2229=vc->eqExpr(id803,id113); Expr id2228=vc->notExpr(id2229); vc->registerAtom(id2229); Expr id2231=vc->eqExpr(id91,id75); Expr id2230=vc->notExpr(id2231); vc->registerAtom(id2231); Expr id2247=vc->writeExpr(id83,id79,id111); Expr id2249=vc->eqExpr(id2247,id107); Expr id2248=vc->notExpr(id2249); vc->registerAtom(id2249); Expr id2257=vc->eqExpr(id833,id113); Expr id2256=vc->notExpr(id2257); vc->registerAtom(id2257); Expr id2259=vc->leExpr(id75,id91); Expr id2258=vc->notExpr(id2259); vc->registerAtom(id2259); Expr id2279=vc->eqExpr(id75,id87); Expr id2278=vc->notExpr(id2279); vc->registerAtom(id2279); Expr id2287=vc->leExpr(id293,id537); Expr id2286=vc->notExpr(id2287); vc->registerAtom(id2287); Expr id2291=vc->eqExpr(id515,id297); Expr id2290=vc->notExpr(id2291); vc->registerAtom(id2291); Expr id2295=vc->leExpr(id271,id537); Expr id2294=vc->notExpr(id2295); vc->registerAtom(id2295); Expr id2303=vc->leExpr(id249,id537); Expr id2302=vc->notExpr(id2303); vc->registerAtom(id2303); Expr id2311=vc->leExpr(id227,id537); Expr id2310=vc->notExpr(id2311); vc->registerAtom(id2311); Expr id2319=vc->leExpr(id205,id537); Expr id2318=vc->notExpr(id2319); vc->registerAtom(id2319); Expr id2327=vc->leExpr(id183,id537); Expr id2326=vc->notExpr(id2327); vc->registerAtom(id2327); Expr id2335=vc->leExpr(id161,id537); Expr id2334=vc->notExpr(id2335); vc->registerAtom(id2335); Expr id2343=vc->leExpr(id139,id537); Expr id2342=vc->notExpr(id2343); vc->registerAtom(id2343); Expr id2351=vc->leExpr(id117,id537); Expr id2350=vc->notExpr(id2351); vc->registerAtom(id2351); Expr id2359=vc->leExpr(id87,id537); Expr id2358=vc->notExpr(id2359); vc->registerAtom(id2359); Expr id2367=vc->leExpr(id75,id537); Expr id2366=vc->notExpr(id2367); vc->registerAtom(id2367); vc->push(); vc->query(id12); vc->inconsistent(inconsistency); vc->pop(); vc->push(); vc->query(id696); vc->popto(1); vc->push(); vc->query(id697); vc->popto(1); vc->push(); vc->assertFormula(id697); vc->getImpliedLiteral(); vc->getImpliedLiteral(); vc->push(); vc->query(id692); vc->popto(2); vc->push(); vc->query(id693); vc->popto(2); vc->push(); vc->assertFormula(id693); vc->getImpliedLiteral(); vc->getImpliedLiteral(); vc->push(); vc->query(id688); vc->popto(3); vc->push(); vc->query(id689); vc->popto(3); vc->push(); vc->assertFormula(id689); vc->getImpliedLiteral(); vc->getImpliedLiteral(); vc->push(); vc->query(id682); vc->popto(4); vc->push(); vc->query(id683); vc->popto(4); vc->push(); vc->assertFormula(id683); vc->getImpliedLiteral(); vc->getImpliedLiteral(); vc->push(); vc->query(id678); vc->popto(5); vc->push(); vc->query(id679); vc->popto(5); vc->push(); vc->assertFormula(id679); vc->getImpliedLiteral(); vc->getImpliedLiteral(); vc->push(); vc->query(id674); vc->popto(6); vc->push(); vc->query(id675); vc->popto(6); vc->push(); vc->assertFormula(id675); vc->getImpliedLiteral(); vc->getImpliedLiteral(); vc->push(); vc->query(id668); vc->popto(7); vc->push(); vc->query(id669); vc->popto(7); vc->push(); vc->assertFormula(id669); vc->getImpliedLiteral(); vc->getImpliedLiteral(); vc->push(); vc->query(id664); vc->popto(8); vc->push(); vc->query(id665); vc->popto(8); vc->push(); vc->assertFormula(id665); vc->getImpliedLiteral(); vc->getImpliedLiteral(); vc->push(); vc->query(id660); vc->popto(9); vc->push(); vc->query(id661); vc->popto(9); vc->push(); vc->assertFormula(id661); vc->getImpliedLiteral(); vc->getImpliedLiteral(); vc->push(); vc->query(id654); vc->popto(10); vc->push(); vc->query(id655); vc->popto(10); vc->push(); vc->assertFormula(id655); vc->getImpliedLiteral(); vc->getImpliedLiteral(); vc->push(); vc->query(id650); vc->popto(11); vc->push(); vc->query(id651); vc->popto(11); vc->push(); vc->assertFormula(id651); vc->getImpliedLiteral(); vc->getImpliedLiteral(); vc->push(); vc->query(id646); vc->popto(12); vc->push(); vc->query(id647); vc->popto(12); vc->push(); vc->assertFormula(id647); vc->getImpliedLiteral(); vc->getImpliedLiteral(); vc->push(); vc->query(id640); vc->popto(13); vc->push(); vc->query(id641); vc->popto(13); vc->push(); vc->assertFormula(id641); vc->getImpliedLiteral(); vc->getImpliedLiteral(); vc->push(); vc->query(id636); vc->popto(14); vc->push(); vc->query(id637); vc->popto(14); vc->push(); vc->assertFormula(id637); vc->getImpliedLiteral(); vc->getImpliedLiteral(); vc->push(); vc->query(id632); vc->popto(15); vc->push(); vc->query(id633); vc->popto(15); vc->push(); vc->assertFormula(id633); vc->getImpliedLiteral(); vc->getImpliedLiteral(); vc->push(); vc->query(id626); vc->popto(16); vc->push(); vc->query(id627); vc->popto(16); vc->push(); vc->assertFormula(id627); vc->getImpliedLiteral(); vc->getImpliedLiteral(); vc->push(); vc->query(id622); vc->popto(17); vc->push(); vc->query(id623); vc->popto(17); vc->push(); vc->assertFormula(id623); vc->getImpliedLiteral(); vc->getImpliedLiteral(); vc->push(); vc->query(id618); vc->popto(18); vc->push(); vc->query(id619); vc->popto(18); vc->push(); vc->assertFormula(id619); vc->getImpliedLiteral(); vc->getImpliedLiteral(); vc->push(); vc->query(id612); vc->popto(19); vc->push(); vc->query(id613); vc->popto(19); vc->push(); vc->assertFormula(id613); vc->getImpliedLiteral(); vc->getImpliedLiteral(); vc->push(); vc->query(id608); vc->popto(20); vc->push(); vc->query(id609); vc->popto(20); vc->push(); vc->assertFormula(id609); vc->getImpliedLiteral(); vc->getImpliedLiteral(); vc->push(); vc->query(id604); vc->popto(21); vc->push(); vc->query(id605); vc->popto(21); vc->push(); vc->assertFormula(id605); vc->getImpliedLiteral(); vc->getImpliedLiteral(); vc->push(); vc->query(id598); vc->popto(22); vc->push(); vc->query(id599); vc->popto(22); vc->push(); vc->assertFormula(id599); vc->getImpliedLiteral(); vc->getImpliedLiteral(); vc->push(); vc->query(id594); vc->popto(23); vc->push(); vc->query(id595); vc->popto(23); vc->push(); vc->assertFormula(id595); vc->getImpliedLiteral(); vc->getImpliedLiteral(); vc->push(); vc->query(id590); vc->popto(24); vc->push(); vc->query(id591); vc->popto(24); vc->push(); vc->assertFormula(id591); vc->getImpliedLiteral(); vc->getImpliedLiteral(); vc->push(); vc->query(id584); vc->popto(25); vc->push(); vc->query(id585); vc->popto(25); vc->push(); vc->assertFormula(id585); vc->getImpliedLiteral(); vc->getImpliedLiteral(); vc->push(); vc->query(id580); vc->popto(26); vc->push(); vc->query(id581); vc->popto(26); vc->push(); vc->assertFormula(id581); vc->getImpliedLiteral(); vc->getImpliedLiteral(); vc->push(); vc->query(id576); vc->popto(27); vc->push(); vc->query(id577); vc->popto(27); vc->push(); vc->assertFormula(id577); vc->getImpliedLiteral(); vc->getImpliedLiteral(); vc->push(); vc->query(id570); vc->popto(28); vc->push(); vc->query(id571); vc->popto(28); vc->push(); vc->assertFormula(id571); vc->getImpliedLiteral(); vc->getImpliedLiteral(); vc->push(); vc->query(id562); vc->popto(29); vc->push(); vc->query(id563); vc->popto(29); vc->push(); vc->assertFormula(id563); vc->getImpliedLiteral(); vc->getImpliedLiteral(); vc->push(); vc->query(id558); vc->popto(30); vc->push(); vc->query(id559); vc->popto(30); vc->push(); vc->assertFormula(id559); vc->getImpliedLiteral(); vc->getImpliedLiteral(); vc->push(); vc->query(id552); vc->popto(31); vc->push(); vc->query(id553); vc->popto(31); vc->push(); vc->assertFormula(id553); vc->getImpliedLiteral(); vc->getImpliedLiteral(); vc->push(); vc->query(id516); vc->popto(32); vc->push(); vc->query(id517); vc->popto(32); vc->push(); vc->assertFormula(id517); vc->getImpliedLiteral(); vc->getImpliedLiteral(); vc->push(); vc->query(id546); vc->popto(33); vc->push(); vc->query(id547); vc->popto(33); vc->push(); vc->assertFormula(id547); vc->getImpliedLiteral(); vc->getImpliedLiteral(); vc->push(); vc->query(id542); vc->popto(34); vc->push(); vc->query(id543); vc->popto(34); vc->push(); vc->assertFormula(id543); vc->getImpliedLiteral(); vc->getImpliedLiteral(); vc->getImpliedLiteral(); vc->push(); vc->query(id539); vc->popto(35); vc->push(); vc->query(id538); vc->popto(35); vc->push(); vc->assertFormula(id538); vc->getImpliedLiteral(); vc->getImpliedLiteral(); vc->push(); vc->query(id2366); vc->popto(36); vc->push(); vc->query(id2367); vc->popto(36); vc->push(); vc->query(id2130); vc->popto(36); vc->push(); vc->query(id2131); vc->popto(36); vc->push(); vc->query(id343); vc->popto(36); vc->push(); vc->query(id342); vc->popto(36); vc->push(); vc->query(id342); vc->popto(36); vc->push(); vc->query(id343); vc->popto(36); vc->push(); vc->assertFormula(id343); vc->getImpliedLiteral(); vc->getImpliedLiteral(); vc->push(); vc->query(id361); vc->popto(37); vc->push(); vc->query(id360); vc->popto(37); vc->push(); vc->query(id360); vc->popto(37); vc->push(); vc->query(id361); vc->popto(37); vc->push(); vc->assertFormula(id361); vc->getImpliedLiteral(); vc->getImpliedLiteral(); vc->push(); vc->query(id379); vc->popto(38); vc->push(); vc->query(id378); vc->popto(38); vc->push(); vc->query(id378); vc->popto(38); vc->push(); vc->query(id379); vc->popto(38); vc->push(); vc->assertFormula(id379); vc->getImpliedLiteral(); vc->getImpliedLiteral(); vc->push(); vc->query(id397); vc->popto(39); vc->push(); vc->query(id396); vc->popto(39); vc->push(); vc->query(id396); vc->popto(39); vc->push(); vc->query(id397); vc->popto(39); vc->push(); vc->assertFormula(id397); vc->getImpliedLiteral(); vc->getImpliedLiteral(); vc->push(); vc->query(id415); vc->popto(40); vc->push(); vc->query(id414); vc->popto(40); vc->push(); vc->query(id414); vc->popto(40); vc->push(); vc->query(id415); vc->popto(40); vc->push(); vc->assertFormula(id415); vc->getImpliedLiteral(); vc->getImpliedLiteral(); vc->push(); vc->query(id433); vc->popto(41); vc->push(); vc->query(id432); vc->popto(41); vc->push(); vc->query(id432); vc->popto(41); vc->push(); vc->query(id433); vc->popto(41); vc->push(); vc->assertFormula(id433); vc->getImpliedLiteral(); vc->getImpliedLiteral(); vc->push(); vc->query(id451); vc->popto(42); vc->push(); vc->query(id450); vc->popto(42); vc->push(); vc->query(id450); vc->popto(42); vc->push(); vc->query(id451); vc->popto(42); vc->push(); vc->assertFormula(id451); vc->getImpliedLiteral(); vc->getImpliedLiteral(); vc->push(); vc->query(id469); vc->popto(43); vc->push(); vc->query(id468); vc->popto(43); vc->push(); vc->query(id468); vc->popto(43); vc->push(); vc->query(id469); vc->popto(43); vc->push(); vc->assertFormula(id469); vc->getImpliedLiteral(); vc->getImpliedLiteral(); vc->push(); vc->query(id487); vc->popto(44); vc->push(); vc->query(id486); vc->popto(44); vc->push(); vc->query(id486); vc->popto(44); vc->push(); vc->query(id487); vc->popto(44); vc->push(); vc->assertFormula(id487); vc->getImpliedLiteral(); vc->getImpliedLiteral(); vc->push(); vc->query(id505); vc->popto(45); vc->push(); vc->query(id504); vc->popto(45); vc->push(); vc->query(id504); vc->popto(45); vc->push(); vc->query(id505); vc->popto(45); vc->push(); vc->assertFormula(id505); vc->getImpliedLiteral(); vc->getImpliedLiteral(); vc->push(); vc->query(id351); vc->popto(46); vc->push(); vc->query(id350); vc->popto(46); vc->push(); vc->query(id350); vc->popto(46); vc->push(); vc->query(id351); vc->popto(46); vc->push(); vc->assertFormula(id351); vc->getImpliedLiteral(); vc->getImpliedLiteral(); vc->push(); vc->query(id369); vc->popto(47); vc->push(); vc->query(id368); vc->popto(47); vc->push(); vc->query(id368); vc->popto(47); vc->push(); vc->query(id369); vc->popto(47); vc->push(); vc->assertFormula(id369); vc->getImpliedLiteral(); vc->getImpliedLiteral(); vc->push(); vc->query(id347); vc->popto(48); vc->push(); vc->query(id346); vc->popto(48); vc->push(); vc->query(id346); vc->popto(48); vc->push(); vc->query(id347); vc->popto(48); vc->push(); vc->assertFormula(id347); vc->getImpliedLiteral(); vc->getImpliedLiteral(); vc->getImpliedLiteral(); vc->push(); vc->query(id2139); vc->popto(49); vc->push(); vc->query(id2138); vc->popto(49); vc->push(); vc->query(id387); vc->popto(49); vc->push(); vc->query(id386); vc->popto(49); vc->push(); vc->query(id386); vc->popto(49); vc->push(); vc->query(id387); vc->popto(49); vc->push(); vc->assertFormula(id387); vc->getImpliedLiteral(); vc->getImpliedLiteral(); vc->push(); vc->query(id365); vc->popto(50); vc->push(); vc->query(id364); vc->popto(50); vc->push(); vc->query(id364); vc->popto(50); vc->push(); vc->query(id365); vc->popto(50); vc->push(); vc->assertFormula(id365); vc->getImpliedLiteral(); vc->getImpliedLiteral(); vc->getImpliedLiteral(); vc->push(); vc->query(id1981); vc->popto(51); vc->push(); vc->query(id1980); vc->popto(51); vc->push(); vc->query(id345); vc->popto(51); vc->push(); vc->query(id344); vc->popto(51); vc->push(); vc->query(id344); vc->popto(51); vc->push(); vc->query(id345); vc->popto(51); vc->push(); vc->assertFormula(id345); vc->getImpliedLiteral(); vc->getImpliedLiteral(); vc->getImpliedLiteral(); vc->push(); vc->query(id2149); vc->popto(52); vc->push(); vc->query(id2148); vc->popto(52); vc->push(); vc->query(id405); vc->popto(52); vc->push(); vc->query(id404); vc->popto(52); vc->push(); vc->query(id404); vc->popto(52); vc->push(); vc->query(id405); vc->popto(52); vc->push(); vc->assertFormula(id405); vc->getImpliedLiteral(); vc->getImpliedLiteral(); vc->push(); vc->query(id383); vc->popto(53); vc->push(); vc->query(id382); vc->popto(53); vc->push(); vc->query(id382); vc->popto(53); vc->push(); vc->query(id383); vc->popto(53); vc->push(); vc->assertFormula(id383); vc->getImpliedLiteral(); vc->getImpliedLiteral(); vc->getImpliedLiteral(); vc->push(); vc->query(id1823); vc->popto(54); vc->push(); vc->query(id1822); vc->popto(54); vc->push(); vc->query(id363); vc->popto(54); vc->push(); vc->query(id362); vc->popto(54); vc->push(); vc->query(id362); vc->popto(54); vc->push(); vc->query(id363); vc->popto(54); vc->push(); vc->assertFormula(id363); vc->getImpliedLiteral(); vc->getImpliedLiteral(); vc->getImpliedLiteral(); vc->push(); vc->query(id1991); vc->popto(55); vc->push(); vc->query(id1990); vc->popto(55); vc->push(); vc->query(id423); vc->popto(55); vc->push(); vc->query(id422); vc->popto(55); vc->push(); vc->query(id422); vc->popto(55); vc->push(); vc->query(id423); vc->popto(55); vc->push(); vc->assertFormula(id423); vc->getImpliedLiteral(); vc->getImpliedLiteral(); vc->push(); vc->query(id401); vc->popto(56); vc->push(); vc->query(id400); vc->popto(56); vc->push(); vc->query(id400); vc->popto(56); vc->push(); vc->query(id401); vc->popto(56); vc->push(); vc->assertFormula(id401); vc->getImpliedLiteral(); vc->getImpliedLiteral(); vc->getImpliedLiteral(); vc->push(); vc->query(id1665); vc->popto(57); vc->push(); vc->query(id1664); vc->popto(57); vc->push(); vc->query(id381); vc->popto(57); vc->push(); vc->query(id380); vc->popto(57); vc->push(); vc->query(id380); vc->popto(57); vc->push(); vc->query(id381); vc->popto(57); vc->push(); vc->assertFormula(id381); vc->getImpliedLiteral(); vc->getImpliedLiteral(); vc->getImpliedLiteral(); vc->push(); vc->query(id1833); vc->popto(58); vc->push(); vc->query(id1832); vc->popto(58); vc->push(); vc->query(id341); vc->popto(58); vc->push(); vc->query(id340); vc->popto(58); vc->push(); vc->query(id340); vc->popto(58); vc->push(); vc->query(id341); vc->popto(58); vc->push(); vc->assertFormula(id341); vc->getImpliedLiteral(); vc->getImpliedLiteral(); vc->push(); vc->query(id441); vc->popto(59); vc->push(); vc->query(id440); vc->popto(59); vc->push(); vc->query(id440); vc->popto(59); vc->push(); vc->query(id441); vc->popto(59); vc->push(); vc->assertFormula(id441); vc->getImpliedLiteral(); vc->getImpliedLiteral(); vc->push(); vc->query(id419); vc->popto(60); vc->push(); vc->query(id418); vc->popto(60); vc->push(); vc->query(id418); vc->popto(60); vc->push(); vc->query(id419); vc->popto(60); vc->push(); vc->assertFormula(id419); vc->getImpliedLiteral(); vc->getImpliedLiteral(); vc->getImpliedLiteral(); vc->push(); vc->query(id1507); vc->popto(61); vc->push(); vc->query(id1506); vc->popto(61); vc->push(); vc->query(id399); vc->popto(61); vc->push(); vc->query(id398); vc->popto(61); vc->push(); vc->query(id398); vc->popto(61); vc->push(); vc->query(id399); vc->popto(61); vc->push(); vc->assertFormula(id399); vc->getImpliedLiteral(); vc->getImpliedLiteral(); vc->getImpliedLiteral(); vc->push(); vc->query(id1675); vc->popto(62); vc->push(); vc->query(id1674); vc->popto(62); vc->push(); vc->query(id359); vc->popto(62); vc->push(); vc->query(id358); vc->popto(62); vc->push(); vc->query(id358); vc->popto(62); vc->push(); vc->query(id359); vc->popto(62); vc->push(); vc->assertFormula(id359); vc->getImpliedLiteral(); vc->getImpliedLiteral(); vc->push(); vc->query(id459); vc->popto(63); vc->push(); vc->query(id458); vc->popto(63); vc->push(); vc->query(id458); vc->popto(63); vc->push(); vc->query(id459); vc->popto(63); vc->push(); vc->assertFormula(id459); vc->getImpliedLiteral(); vc->getImpliedLiteral(); vc->push(); vc->query(id437); vc->popto(64); vc->push(); vc->query(id436); vc->popto(64); vc->push(); vc->query(id436); vc->popto(64); vc->push(); vc->query(id437); vc->popto(64); vc->push(); vc->assertFormula(id437); vc->getImpliedLiteral(); vc->getImpliedLiteral(); vc->getImpliedLiteral(); vc->push(); vc->query(id1349); vc->popto(65); vc->push(); vc->query(id1348); vc->popto(65); vc->push(); vc->query(id417); vc->popto(65); vc->push(); vc->query(id416); vc->popto(65); vc->push(); vc->query(id416); vc->popto(65); vc->push(); vc->query(id417); vc->popto(65); vc->push(); vc->assertFormula(id417); vc->getImpliedLiteral(); vc->getImpliedLiteral(); vc->getImpliedLiteral(); vc->push(); vc->query(id1517); vc->popto(66); vc->push(); vc->query(id1516); vc->popto(66); vc->push(); vc->query(id377); vc->popto(66); vc->push(); vc->query(id376); vc->popto(66); vc->push(); vc->query(id376); vc->popto(66); vc->push(); vc->query(id377); vc->popto(66); vc->push(); vc->assertFormula(id377); vc->getImpliedLiteral(); vc->getImpliedLiteral(); vc->push(); vc->query(id337); vc->popto(67); vc->push(); vc->query(id336); vc->popto(67); vc->push(); vc->query(id336); vc->popto(67); vc->push(); vc->query(id337); vc->popto(67); vc->push(); vc->assertFormula(id337); vc->getImpliedLiteral(); vc->getImpliedLiteral(); vc->getImpliedLiteral(); vc->getImpliedLiteral(); vc->push(); vc->query(id2359); vc->popto(68); vc->push(); vc->query(id2358); vc->popto(68); vc->push(); vc->query(id2279); vc->popto(68); vc->push(); vc->query(id2278); vc->popto(68); vc->push(); vc->query(id477); vc->popto(68); vc->push(); vc->query(id476); vc->popto(68); vc->push(); vc->query(id476); vc->popto(68); vc->push(); vc->query(id477); vc->popto(68); vc->push(); vc->assertFormula(id477); vc->getImpliedLiteral(); vc->getImpliedLiteral(); vc->push(); vc->query(id455); vc->popto(69); vc->push(); vc->query(id454); vc->popto(69); vc->push(); vc->query(id454); vc->popto(69); vc->push(); vc->query(id455); vc->popto(69); vc->push(); vc->assertFormula(id455); vc->getImpliedLiteral(); vc->getImpliedLiteral(); vc->getImpliedLiteral(); vc->push(); vc->query(id1191); vc->popto(70); vc->push(); vc->query(id1190); vc->popto(70); vc->push(); vc->query(id435); vc->popto(70); vc->push(); vc->query(id434); vc->popto(70); vc->push(); vc->query(id434); vc->popto(70); vc->push(); vc->query(id435); vc->popto(70); vc->push(); vc->assertFormula(id435); vc->getImpliedLiteral(); vc->getImpliedLiteral(); vc->getImpliedLiteral(); vc->push(); vc->query(id1359); vc->popto(71); vc->push(); vc->query(id1358); vc->popto(71); vc->push(); vc->query(id395); vc->popto(71); vc->push(); vc->query(id394); vc->popto(71); vc->push(); vc->query(id394); vc->popto(71); vc->push(); vc->query(id395); vc->popto(71); vc->push(); vc->assertFormula(id395); vc->getImpliedLiteral(); vc->getImpliedLiteral(); vc->push(); vc->query(id495); vc->popto(72); vc->push(); vc->query(id494); vc->popto(72); vc->push(); vc->query(id494); vc->popto(72); vc->push(); vc->query(id495); vc->popto(72); vc->push(); vc->assertFormula(id495); vc->getImpliedLiteral(); vc->getImpliedLiteral(); vc->push(); vc->query(id473); vc->popto(73); vc->push(); vc->query(id472); vc->popto(73); vc->push(); vc->query(id472); vc->popto(73); vc->push(); vc->query(id473); vc->popto(73); vc->push(); vc->assertFormula(id473); vc->getImpliedLiteral(); vc->getImpliedLiteral(); vc->getImpliedLiteral(); vc->push(); vc->query(id1033); vc->popto(74); vc->push(); vc->query(id1032); vc->popto(74); vc->push(); vc->query(id453); vc->popto(74); vc->push(); vc->query(id452); vc->popto(74); vc->push(); vc->query(id452); vc->popto(74); vc->push(); vc->query(id453); vc->popto(74); vc->push(); vc->assertFormula(id453); vc->getImpliedLiteral(); vc->getImpliedLiteral(); vc->getImpliedLiteral(); vc->push(); vc->query(id1201); vc->popto(75); vc->push(); vc->query(id1200); vc->popto(75); vc->push(); vc->query(id413); vc->popto(75); vc->push(); vc->query(id412); vc->popto(75); vc->push(); vc->query(id412); vc->popto(75); vc->push(); vc->query(id413); vc->popto(75); vc->push(); vc->assertFormula(id413); vc->getImpliedLiteral(); vc->getImpliedLiteral(); vc->push(); vc->query(id355); vc->popto(76); vc->push(); vc->query(id354); vc->popto(76); vc->push(); vc->query(id354); vc->popto(76); vc->push(); vc->query(id355); vc->popto(76); vc->push(); vc->assertFormula(id355); vc->getImpliedLiteral(); vc->getImpliedLiteral(); vc->getImpliedLiteral(); vc->getImpliedLiteral(); vc->push(); vc->query(id2351); vc->popto(77); vc->push(); vc->query(id2350); vc->popto(77); vc->push(); vc->query(id2121); vc->popto(77); vc->push(); vc->query(id2120); vc->popto(77); vc->push(); vc->query(id513); vc->popto(77); vc->push(); vc->query(id512); vc->popto(77); vc->push(); vc->query(id512); vc->popto(77); vc->push(); vc->query(id513); vc->popto(77); vc->push(); vc->assertFormula(id513); vc->getImpliedLiteral(); vc->getImpliedLiteral(); vc->push(); vc->query(id491); vc->popto(78); vc->push(); vc->query(id490); vc->popto(78); vc->push(); vc->query(id490); vc->popto(78); vc->push(); vc->query(id491); vc->popto(78); vc->push(); vc->assertFormula(id491); vc->getImpliedLiteral(); vc->getImpliedLiteral(); vc->getImpliedLiteral(); vc->push(); vc->query(id875); vc->popto(79); vc->push(); vc->query(id874); vc->popto(79); vc->push(); vc->query(id471); vc->popto(79); vc->push(); vc->query(id470); vc->popto(79); vc->push(); vc->query(id470); vc->popto(79); vc->push(); vc->query(id471); vc->popto(79); vc->push(); vc->assertFormula(id471); vc->getImpliedLiteral(); vc->getImpliedLiteral(); vc->getImpliedLiteral(); vc->push(); vc->query(id1043); vc->popto(80); vc->push(); vc->query(id1042); vc->popto(80); vc->push(); vc->query(id431); vc->popto(80); vc->push(); vc->query(id430); vc->popto(80); vc->push(); vc->query(id430); vc->popto(80); vc->push(); vc->query(id431); vc->popto(80); vc->push(); vc->assertFormula(id431); vc->getImpliedLiteral(); vc->getImpliedLiteral(); vc->push(); vc->query(id373); vc->popto(81); vc->push(); vc->query(id372); vc->popto(81); vc->push(); vc->query(id372); vc->popto(81); vc->push(); vc->query(id373); vc->popto(81); vc->push(); vc->assertFormula(id373); vc->getImpliedLiteral(); vc->getImpliedLiteral(); vc->getImpliedLiteral(); vc->getImpliedLiteral(); vc->push(); vc->query(id2343); vc->popto(82); vc->push(); vc->query(id2342); vc->popto(82); vc->push(); vc->query(id1963); vc->popto(82); vc->push(); vc->query(id1962); vc->popto(82); vc->push(); vc->query(id509); vc->popto(82); vc->push(); vc->query(id508); vc->popto(82); vc->push(); vc->query(id508); vc->popto(82); vc->push(); vc->query(id509); vc->popto(82); vc->push(); vc->assertFormula(id509); vc->getImpliedLiteral(); vc->getImpliedLiteral(); vc->getImpliedLiteral(); vc->push(); vc->query(id711); vc->popto(83); vc->push(); vc->query(id710); vc->popto(83); vc->push(); vc->query(id489); vc->popto(83); vc->push(); vc->query(id488); vc->popto(83); vc->push(); vc->query(id488); vc->popto(83); vc->push(); vc->query(id489); vc->popto(83); vc->push(); vc->assertFormula(id489); vc->getImpliedLiteral(); vc->getImpliedLiteral(); vc->getImpliedLiteral(); vc->push(); vc->query(id885); vc->popto(84); vc->push(); vc->query(id884); vc->popto(84); vc->push(); vc->query(id449); vc->popto(84); vc->push(); vc->query(id448); vc->popto(84); vc->push(); vc->query(id448); vc->popto(84); vc->push(); vc->query(id449); vc->popto(84); vc->push(); vc->assertFormula(id449); vc->getImpliedLiteral(); vc->getImpliedLiteral(); vc->push(); vc->query(id391); vc->popto(85); vc->push(); vc->query(id390); vc->popto(85); vc->push(); vc->query(id390); vc->popto(85); vc->push(); vc->query(id391); vc->popto(85); vc->push(); vc->assertFormula(id391); vc->getImpliedLiteral(); vc->getImpliedLiteral(); vc->getImpliedLiteral(); vc->getImpliedLiteral(); vc->push(); vc->query(id2335); vc->popto(86); vc->push(); vc->query(id2334); vc->popto(86); vc->push(); vc->query(id1805); vc->popto(86); vc->push(); vc->query(id1804); vc->popto(86); vc->push(); vc->query(id507); vc->popto(86); vc->push(); vc->query(id506); vc->popto(86); vc->push(); vc->query(id506); vc->popto(86); vc->push(); vc->query(id507); vc->popto(86); vc->push(); vc->assertFormula(id507); vc->getImpliedLiteral(); vc->getImpliedLiteral(); vc->getImpliedLiteral(); vc->push(); vc->query(id721); vc->popto(87); vc->push(); vc->query(id720); vc->popto(87); vc->push(); vc->query(id467); vc->popto(87); vc->push(); vc->query(id466); vc->popto(87); vc->push(); vc->query(id466); vc->popto(87); vc->push(); vc->query(id467); vc->popto(87); vc->push(); vc->assertFormula(id467); vc->getImpliedLiteral(); vc->getImpliedLiteral(); vc->push(); vc->query(id409); vc->popto(88); vc->push(); vc->query(id408); vc->popto(88); vc->push(); vc->query(id408); vc->popto(88); vc->push(); vc->query(id409); vc->popto(88); vc->push(); vc->assertFormula(id409); vc->getImpliedLiteral(); vc->getImpliedLiteral(); vc->getImpliedLiteral(); vc->getImpliedLiteral(); vc->push(); vc->query(id2327); vc->popto(89); vc->push(); vc->query(id2326); vc->popto(89); vc->push(); vc->query(id1647); vc->popto(89); vc->push(); vc->query(id1646); vc->popto(89); vc->push(); vc->query(id485); vc->popto(89); vc->push(); vc->query(id484); vc->popto(89); vc->push(); vc->query(id484); vc->popto(89); vc->push(); vc->query(id485); vc->popto(89); vc->push(); vc->assertFormula(id485); vc->getImpliedLiteral(); vc->getImpliedLiteral(); vc->push(); vc->query(id427); vc->popto(90); vc->push(); vc->query(id426); vc->popto(90); vc->push(); vc->query(id426); vc->popto(90); vc->push(); vc->query(id427); vc->popto(90); vc->push(); vc->assertFormula(id427); vc->getImpliedLiteral(); vc->getImpliedLiteral(); vc->getImpliedLiteral(); vc->getImpliedLiteral(); vc->push(); vc->query(id2319); vc->popto(91); vc->push(); vc->query(id2318); vc->popto(91); vc->push(); vc->query(id1489); vc->popto(91); vc->push(); vc->query(id1488); vc->popto(91); vc->push(); vc->query(id503); vc->popto(91); vc->push(); vc->query(id502); vc->popto(91); vc->push(); vc->query(id502); vc->popto(91); vc->push(); vc->query(id503); vc->popto(91); vc->push(); vc->assertFormula(id503); vc->getImpliedLiteral(); vc->getImpliedLiteral(); vc->push(); vc->query(id445); vc->popto(92); vc->push(); vc->query(id444); vc->popto(92); vc->push(); vc->query(id444); vc->popto(92); vc->push(); vc->query(id445); vc->popto(92); vc->push(); vc->assertFormula(id445); vc->getImpliedLiteral(); vc->getImpliedLiteral(); vc->getImpliedLiteral(); vc->getImpliedLiteral(); vc->push(); vc->query(id2311); vc->popto(93); vc->push(); vc->query(id2310); vc->popto(93); vc->push(); vc->query(id1331); vc->popto(93); vc->push(); vc->query(id1330); vc->popto(93); vc->push(); vc->query(id463); vc->popto(93); vc->push(); vc->query(id462); vc->popto(93); vc->push(); vc->query(id462); vc->popto(93); vc->push(); vc->query(id463); vc->popto(93); vc->push(); vc->assertFormula(id463); vc->getImpliedLiteral(); vc->getImpliedLiteral(); vc->getImpliedLiteral(); vc->getImpliedLiteral(); vc->push(); vc->query(id2303); vc->popto(94); vc->push(); vc->query(id2302); vc->popto(94); vc->push(); vc->query(id1173); vc->popto(94); vc->push(); vc->query(id1172); vc->popto(94); vc->push(); vc->query(id481); vc->popto(94); vc->push(); vc->query(id480); vc->popto(94); vc->push(); vc->query(id480); vc->popto(94); vc->push(); vc->query(id481); vc->popto(94); vc->push(); vc->assertFormula(id481); vc->getImpliedLiteral(); vc->getImpliedLiteral(); vc->getImpliedLiteral(); vc->getImpliedLiteral(); vc->push(); vc->query(id2295); vc->popto(95); vc->push(); vc->query(id2294); vc->popto(95); vc->push(); vc->query(id1015); vc->popto(95); vc->push(); vc->query(id1014); vc->popto(95); vc->push(); vc->query(id499); vc->popto(95); vc->push(); vc->query(id498); vc->popto(95); vc->push(); vc->query(id498); vc->popto(95); vc->push(); vc->query(id499); vc->popto(95); vc->push(); vc->assertFormula(id499); vc->getImpliedLiteral(); vc->getImpliedLiteral(); vc->getImpliedLiteral(); vc->getImpliedLiteral(); vc->push(); vc->query(id2287); vc->popto(96); vc->push(); vc->query(id2286); vc->popto(96); vc->push(); vc->query(id857); vc->popto(96); vc->push(); vc->query(id856); vc->popto(96); vc->push(); vc->query(id339); vc->popto(96); vc->push(); vc->query(id338); vc->popto(96); vc->push(); vc->query(id338); vc->popto(96); vc->push(); vc->query(id339); vc->popto(96); vc->push(); vc->assertFormula(id339); vc->getImpliedLiteral(); vc->getImpliedLiteral(); vc->getImpliedLiteral(); vc->getImpliedLiteral(); vc->push(); vc->query(id534); vc->popto(97); vc->push(); vc->query(id535); vc->popto(97); vc->push(); vc->query(id2143); vc->popto(97); vc->push(); vc->query(id2142); vc->popto(97); vc->push(); vc->query(id357); vc->popto(97); vc->push(); vc->query(id356); vc->popto(97); vc->push(); vc->query(id356); vc->popto(97); vc->push(); vc->query(id357); vc->popto(97); vc->push(); vc->assertFormula(id357); vc->getImpliedLiteral(); vc->getImpliedLiteral(); vc->getImpliedLiteral(); vc->getImpliedLiteral(); vc->push(); vc->query(id532); vc->popto(98); vc->push(); vc->query(id533); vc->popto(98); vc->push(); vc->query(id1985); vc->popto(98); vc->push(); vc->query(id1984); vc->popto(98); vc->push(); vc->query(id375); vc->popto(98); vc->push(); vc->query(id374); vc->popto(98); vc->push(); vc->query(id374); vc->popto(98); vc->push(); vc->query(id375); vc->popto(98); vc->push(); vc->assertFormula(id375); vc->getImpliedLiteral(); vc->getImpliedLiteral(); vc->getImpliedLiteral(); vc->getImpliedLiteral(); vc->push(); vc->query(id530); vc->popto(99); vc->push(); vc->query(id531); vc->popto(99); vc->push(); vc->query(id1827); vc->popto(99); vc->push(); vc->query(id1826); vc->popto(99); vc->push(); vc->query(id393); vc->popto(99); vc->push(); vc->query(id392); vc->popto(99); vc->push(); vc->query(id392); vc->popto(99); vc->push(); vc->query(id393); vc->popto(99); vc->push(); vc->assertFormula(id393); vc->getImpliedLiteral(); vc->getImpliedLiteral(); vc->getImpliedLiteral(); vc->getImpliedLiteral(); vc->push(); vc->query(id528); vc->popto(100); vc->push(); vc->query(id529); vc->popto(100); vc->push(); vc->query(id1669); vc->popto(100); vc->push(); vc->query(id1668); vc->popto(100); vc->push(); vc->query(id411); vc->popto(100); vc->push(); vc->query(id410); vc->popto(100); vc->push(); vc->query(id410); vc->popto(100); vc->push(); vc->query(id411); vc->popto(100); vc->push(); vc->assertFormula(id411); vc->getImpliedLiteral(); vc->getImpliedLiteral(); vc->getImpliedLiteral(); vc->getImpliedLiteral(); vc->push(); vc->query(id526); vc->popto(101); vc->push(); vc->query(id527); vc->popto(101); vc->push(); vc->query(id1511); vc->popto(101); vc->push(); vc->query(id1510); vc->popto(101); vc->push(); vc->query(id429); vc->popto(101); vc->push(); vc->query(id428); vc->popto(101); vc->push(); vc->query(id428); vc->popto(101); vc->push(); vc->query(id429); vc->popto(101); vc->push(); vc->assertFormula(id429); vc->getImpliedLiteral(); vc->getImpliedLiteral(); vc->getImpliedLiteral(); vc->getImpliedLiteral(); vc->push(); vc->query(id524); vc->popto(102); vc->push(); vc->query(id525); vc->popto(102); vc->push(); vc->query(id1353); vc->popto(102); vc->push(); vc->query(id1352); vc->popto(102); vc->push(); vc->query(id447); vc->popto(102); vc->push(); vc->query(id446); vc->popto(102); vc->push(); vc->query(id446); vc->popto(102); vc->push(); vc->query(id447); vc->popto(102); vc->push(); vc->assertFormula(id447); vc->getImpliedLiteral(); vc->getImpliedLiteral(); vc->getImpliedLiteral(); vc->getImpliedLiteral(); vc->push(); vc->query(id522); vc->popto(103); vc->push(); vc->query(id523); vc->popto(103); vc->push(); vc->query(id1195); vc->popto(103); vc->push(); vc->query(id1194); vc->popto(103); vc->push(); vc->query(id465); vc->popto(103); vc->push(); vc->query(id464); vc->popto(103); vc->push(); vc->query(id464); vc->popto(103); vc->push(); vc->query(id465); vc->popto(103); vc->push(); vc->assertFormula(id465); vc->getImpliedLiteral(); vc->getImpliedLiteral(); vc->getImpliedLiteral(); vc->getImpliedLiteral(); vc->push(); vc->query(id520); vc->popto(104); vc->push(); vc->query(id521); vc->popto(104); vc->push(); vc->query(id1037); vc->popto(104); vc->push(); vc->query(id1036); vc->popto(104); vc->push(); vc->query(id483); vc->popto(104); vc->push(); vc->query(id482); vc->popto(104); vc->push(); vc->query(id482); vc->popto(104); vc->push(); vc->query(id483); vc->popto(104); vc->push(); vc->assertFormula(id483); vc->getImpliedLiteral(); vc->getImpliedLiteral(); vc->getImpliedLiteral(); vc->getImpliedLiteral(); vc->push(); vc->query(id518); vc->popto(105); vc->push(); vc->query(id519); vc->popto(105); vc->push(); vc->query(id879); vc->popto(105); vc->push(); vc->query(id878); vc->popto(105); vc->push(); vc->query(id501); vc->popto(105); vc->push(); vc->query(id500); vc->popto(105); vc->push(); vc->query(id500); vc->popto(105); vc->push(); vc->query(id501); vc->popto(105); vc->push(); vc->assertFormula(id501); vc->getImpliedLiteral(); vc->getImpliedLiteral(); vc->getImpliedLiteral(); vc->getImpliedLiteral(); vc->push(); vc->query(id2290); vc->popto(106); vc->push(); vc->query(id2291); vc->popto(106); vc->push(); vc->query(id715); vc->popto(106); vc->push(); vc->query(id714); vc->popto(106); vc->push(); vc->query(id2220); vc->popto(106); vc->push(); vc->query(id2221); vc->popto(106); vc->push(); vc->assertFormula(id2221); vc->getImpliedLiteral(); vc->getImpliedLiteral(); vc->push(); vc->query(id2202); vc->popto(107); vc->popto(106); vc->push(); vc->query(id2248); } catch(const Exception& e) { exitStatus = 1; cout << "*** Exception caught in testgeorge2(): \n" << e << endl; } delete vc; } void testgeorge3() { CLFlags flags = ValidityChecker::createFlags(); flags.setFlag("arith3", true); ValidityChecker *vc = ValidityChecker::create(flags); try { /*************/ vector inconsistency; /*************/ Type id9 = vc->realType(); Type id7 = vc->intType(); Type id11 = vc->boolType(); vc->push(); Expr id13=vc->trueExpr(); Expr id12=vc->notExpr(vc->trueExpr()); Type id19=vc->arrayType(id7,id7); Type id21=vc->arrayType(id7,id9); Type id23=vc->arrayType(id9,id7); Type id25=vc->arrayType(id9,id9); Type id27=vc->tupleType(id19,id7,id7); Type id29=vc->funType(id27,id19); Op id31=vc->createOp(".Int_Int_store",id29); Type id33=vc->tupleType(id21,id7); Type id35=vc->funType(id33,id9); Op id37=vc->createOp(".Int_Real_select",id35); Type id39=vc->tupleType(id21,id7,id9); Type id41=vc->funType(id39,id21); Op id43=vc->createOp(".Int_Real_store",id41); Type id45=vc->tupleType(id19,id7); Type id47=vc->funType(id45,id7); Op id49=vc->createOp(".Int_Int_select",id47); Type id51=vc->tupleType(id23,id9,id7); Type id53=vc->funType(id51,id23); Op id55=vc->createOp(".Real_Int_store",id53); Type id57=vc->tupleType(id25,id9,id9); Type id59=vc->funType(id57,id25); Op id61=vc->createOp(".Real_Real_store",id59); Type id63=vc->tupleType(id23,id9); Type id65=vc->funType(id63,id7); Op id67=vc->createOp(".Real_Int_select",id65); Type id69=vc->tupleType(id25,id9); Type id71=vc->funType(id69,id9); Op id73=vc->createOp(".Real_Real_select",id71); Expr id75=vc->varExpr("x_0",id7); Expr id77=vc->varExpr("x_1",id7); Expr id79=vc->varExpr("x_2",id7); Expr id81=vc->varExpr("x_3",id7); Expr id83=vc->varExpr("x_4",id19); Expr id85=vc->varExpr("x_5",id7); Expr id87=vc->varExpr("x_6",id7); Expr id89=vc->varExpr("x_7",id7); Expr id91=vc->varExpr("x_8",id7); Expr id93=vc->varExpr("x_9",id7); Expr id95=vc->varExpr("x_10",id19); Expr id97=vc->varExpr("x_11",id19); Expr id99=vc->varExpr("x_12",id7); Expr id101=vc->varExpr("x_13",id7); Expr id103=vc->varExpr("x_14",id7); Expr id105=vc->varExpr("x_15",id7); Expr id107=vc->varExpr("x_16",id19); Expr id109=vc->varExpr("x_17",id7); Expr id111=vc->varExpr("x_18",id7); Expr id113=vc->varExpr("x_19",id7); Expr id115=vc->varExpr("x_20",id7); Expr id117=vc->varExpr("x_21",id7); Expr id119=vc->varExpr("x_22",id7); Expr id121=vc->varExpr("x_23",id7); Expr id123=vc->varExpr("x_24",id19); Expr id125=vc->varExpr("x_25",id7); Expr id127=vc->varExpr("x_26",id7); Expr id129=vc->varExpr("x_27",id7); Expr id131=vc->varExpr("x_28",id19); Expr id133=vc->varExpr("x_29",id7); Expr id135=vc->varExpr("x_30",id7); Expr id137=vc->varExpr("x_31",id7); Expr id139=vc->varExpr("x_32",id7); Expr id141=vc->varExpr("x_33",id7); Expr id143=vc->varExpr("x_34",id7); Expr id145=vc->varExpr("x_35",id19); Expr id147=vc->varExpr("x_36",id7); Expr id149=vc->varExpr("x_37",id7); Expr id151=vc->varExpr("x_38",id7); Expr id153=vc->varExpr("x_39",id19); Expr id155=vc->varExpr("x_40",id7); Expr id157=vc->varExpr("x_41",id7); Expr id159=vc->varExpr("x_42",id7); Expr id161=vc->varExpr("x_43",id7); Expr id163=vc->varExpr("x_44",id7); Expr id165=vc->varExpr("x_45",id7); Expr id167=vc->varExpr("x_46",id19); Expr id169=vc->varExpr("x_47",id7); Expr id171=vc->varExpr("x_48",id7); Expr id173=vc->varExpr("x_49",id7); Expr id175=vc->varExpr("x_50",id19); Expr id177=vc->varExpr("x_51",id7); Expr id179=vc->varExpr("x_52",id7); Expr id181=vc->varExpr("x_53",id7); Expr id183=vc->varExpr("x_54",id7); Expr id185=vc->varExpr("x_55",id7); Expr id187=vc->varExpr("x_56",id7); Expr id189=vc->varExpr("x_57",id19); Expr id191=vc->varExpr("x_58",id7); Expr id193=vc->varExpr("x_59",id7); Expr id195=vc->varExpr("x_60",id7); Expr id197=vc->varExpr("x_61",id19); Expr id199=vc->varExpr("x_62",id7); Expr id201=vc->varExpr("x_63",id7); Expr id203=vc->varExpr("x_64",id7); Expr id205=vc->varExpr("x_65",id7); Expr id207=vc->varExpr("x_66",id7); Expr id209=vc->varExpr("x_67",id7); Expr id211=vc->varExpr("x_68",id19); Expr id213=vc->varExpr("x_69",id7); Expr id215=vc->varExpr("x_70",id7); Expr id217=vc->varExpr("x_71",id7); Expr id219=vc->varExpr("x_72",id19); Expr id221=vc->varExpr("x_73",id7); Expr id223=vc->varExpr("x_74",id7); Expr id225=vc->varExpr("x_75",id7); Expr id227=vc->varExpr("x_76",id7); Expr id229=vc->varExpr("x_77",id7); Expr id231=vc->varExpr("x_78",id7); Expr id233=vc->varExpr("x_79",id19); Expr id235=vc->varExpr("x_80",id7); Expr id237=vc->varExpr("x_81",id7); Expr id239=vc->varExpr("x_82",id7); Expr id241=vc->varExpr("x_83",id19); Expr id243=vc->varExpr("x_84",id7); Expr id245=vc->varExpr("x_85",id7); Expr id247=vc->varExpr("x_86",id7); Expr id249=vc->varExpr("x_87",id7); Expr id251=vc->varExpr("x_88",id7); Expr id253=vc->varExpr("x_89",id7); Expr id255=vc->varExpr("x_90",id19); Expr id257=vc->varExpr("x_91",id7); Expr id259=vc->varExpr("x_92",id7); Expr id261=vc->varExpr("x_93",id7); Expr id263=vc->varExpr("x_94",id19); Expr id265=vc->varExpr("x_95",id7); Expr id267=vc->varExpr("x_96",id7); Expr id269=vc->varExpr("x_97",id7); Expr id271=vc->varExpr("x_98",id7); Expr id273=vc->varExpr("x_99",id7); Expr id275=vc->varExpr("x_100",id7); Expr id277=vc->varExpr("x_101",id19); Expr id279=vc->varExpr("x_102",id7); Expr id281=vc->varExpr("x_103",id7); Expr id283=vc->varExpr("x_104",id7); Expr id285=vc->varExpr("x_105",id19); Expr id287=vc->varExpr("x_106",id7); Expr id289=vc->varExpr("x_107",id7); Expr id291=vc->varExpr("x_108",id7); Expr id293=vc->varExpr("x_109",id7); Expr id295=vc->varExpr("x_110",id7); Expr id297=vc->varExpr("x_111",id7); Expr id299=vc->varExpr("x_112",id19); Expr id301=vc->varExpr("x_113",id7); Expr id303=vc->varExpr("x_114",id7); Expr id305=vc->varExpr("x_115",id7); Expr id307=vc->varExpr("x_116",id19); Expr id309=vc->varExpr("x_117",id7); Expr id311=vc->varExpr("x_118",id7); Expr id313=vc->varExpr("x_119",id7); Expr id315=vc->varExpr("x_120",id7); Expr id317=vc->varExpr("x_121",id7); Expr id319=vc->varExpr("x_122",id7); Expr id321=vc->varExpr("x_123",id19); Expr id323=vc->varExpr("x_124",id7); Expr id325=vc->varExpr("x_125",id7); Expr id327=vc->varExpr("x_126",id7); Expr id329=vc->varExpr("x_127",id19); Expr id331=vc->varExpr("x_128",id7); Expr id333=vc->varExpr("x_129",id7); Expr id335=vc->varExpr("x_130",id7); Expr id337=vc->varExpr("x_131",id7); Expr id339=vc->varExpr("x_132",id7); Expr id341=vc->varExpr("x_133",id7); Expr id343=vc->varExpr("x_134",id19); Expr id345=vc->varExpr("x_135",id7); Expr id347=vc->varExpr("x_136",id7); Expr id349=vc->varExpr("x_137",id7); Expr id351=vc->varExpr("x_138",id19); Expr id353=vc->varExpr("x_139",id7); Expr id355=vc->varExpr("x_140",id7); Expr id357=vc->varExpr("x_141",id7); Expr id359=vc->varExpr("x_142",id7); Expr id361=vc->varExpr("x_143",id7); Expr id363=vc->varExpr("x_144",id7); Expr id365=vc->varExpr("x_145",id19); Expr id367=vc->varExpr("x_146",id7); Expr id369=vc->varExpr("x_147",id7); Expr id371=vc->varExpr("x_148",id7); Expr id373=vc->varExpr("x_149",id19); Expr id375=vc->varExpr("x_150",id7); Expr id377=vc->varExpr("x_151",id7); Expr id379=vc->varExpr("x_152",id7); Expr id381=vc->varExpr("x_153",id7); Expr id383=vc->varExpr("x_154",id7); Expr id385=vc->varExpr("x_155",id7); Expr id387=vc->varExpr("x_156",id19); Expr id389=vc->varExpr("x_157",id7); Expr id391=vc->varExpr("x_158",id7); Expr id393=vc->varExpr("x_159",id7); Expr id395=vc->varExpr("x_160",id19); Expr id397=vc->varExpr("x_161",id7); Expr id399=vc->varExpr("x_162",id7); Expr id401=vc->varExpr("x_163",id7); Expr id403=vc->varExpr("x_164",id7); Expr id405=vc->varExpr("x_165",id7); Expr id407=vc->varExpr("x_166",id7); Expr id409=vc->varExpr("x_167",id19); Expr id411=vc->varExpr("x_168",id7); Expr id413=vc->varExpr("x_169",id7); Expr id415=vc->varExpr("x_170",id7); Expr id417=vc->varExpr("x_171",id19); Expr id419=vc->varExpr("x_172",id7); Expr id421=vc->varExpr("x_173",id7); Expr id423=vc->varExpr("x_174",id7); Expr id425=vc->varExpr("x_175",id7); Expr id427=vc->varExpr("x_176",id7); Expr id429=vc->varExpr("x_177",id7); Expr id431=vc->varExpr("x_178",id7); Expr id433=vc->varExpr("x_179",id7); Expr id435=vc->varExpr("x_180",id7); Expr id437=vc->varExpr("x_181",id7); Expr id439=vc->varExpr("x_182",id7); Expr id441=vc->varExpr("x_183",id7); Expr id443=vc->varExpr("x_184",id7); Expr id445=vc->varExpr("x_185",id7); Expr id447=vc->varExpr("x_186",id7); Expr id449=vc->varExpr("x_187",id7); Expr id451=vc->varExpr("x_188",id7); Expr id453=vc->ratExpr(1,1); Expr id455=vc->plusExpr(id75,id453); Expr id457=vc->eqExpr(id455,id87); Expr id456=vc->notExpr(id457); vc->registerAtom(id457); Expr id459=vc->eqExpr(id79,id93); Expr id458=vc->notExpr(id459); vc->registerAtom(id459); Expr id461=vc->eqExpr(id97,id95); Expr id460=vc->notExpr(id461); vc->registerAtom(id461); Expr id463=vc->eqExpr(id101,id99); Expr id462=vc->notExpr(id463); vc->registerAtom(id463); Expr id465=vc->eqExpr(id77,id103); Expr id464=vc->notExpr(id465); vc->registerAtom(id465); Expr id467=vc->eqExpr(id81,id105); Expr id466=vc->notExpr(id467); vc->registerAtom(id467); Expr id469=vc->eqExpr(id83,id107); Expr id468=vc->notExpr(id469); vc->registerAtom(id469); Expr id471=vc->eqExpr(id111,id109); Expr id470=vc->notExpr(id471); vc->registerAtom(id471); Expr id473=vc->plusExpr(id87,id453); Expr id475=vc->eqExpr(id473,id117); Expr id474=vc->notExpr(id475); vc->registerAtom(id475); Expr id477=vc->eqExpr(id93,id121); Expr id476=vc->notExpr(id477); vc->registerAtom(id477); Expr id479=vc->eqExpr(id95,id123); Expr id478=vc->notExpr(id479); vc->registerAtom(id479); Expr id481=vc->eqExpr(id99,id125); Expr id480=vc->notExpr(id481); vc->registerAtom(id481); Expr id483=vc->eqExpr(id103,id127); Expr id482=vc->notExpr(id483); vc->registerAtom(id483); Expr id485=vc->eqExpr(id105,id129); Expr id484=vc->notExpr(id485); vc->registerAtom(id485); Expr id487=vc->eqExpr(id107,id131); Expr id486=vc->notExpr(id487); vc->registerAtom(id487); Expr id489=vc->eqExpr(id109,id133); Expr id488=vc->notExpr(id489); vc->registerAtom(id489); Expr id491=vc->plusExpr(id117,id453); Expr id493=vc->eqExpr(id491,id139); Expr id492=vc->notExpr(id493); vc->registerAtom(id493); Expr id495=vc->eqExpr(id121,id143); Expr id494=vc->notExpr(id495); vc->registerAtom(id495); Expr id497=vc->eqExpr(id123,id145); Expr id496=vc->notExpr(id497); vc->registerAtom(id497); Expr id499=vc->eqExpr(id125,id147); Expr id498=vc->notExpr(id499); vc->registerAtom(id499); Expr id501=vc->eqExpr(id127,id149); Expr id500=vc->notExpr(id501); vc->registerAtom(id501); Expr id503=vc->eqExpr(id129,id151); Expr id502=vc->notExpr(id503); vc->registerAtom(id503); Expr id505=vc->eqExpr(id131,id153); Expr id504=vc->notExpr(id505); vc->registerAtom(id505); Expr id507=vc->eqExpr(id133,id155); Expr id506=vc->notExpr(id507); vc->registerAtom(id507); Expr id509=vc->plusExpr(id139,id453); Expr id511=vc->eqExpr(id509,id161); Expr id510=vc->notExpr(id511); vc->registerAtom(id511); Expr id513=vc->eqExpr(id143,id165); Expr id512=vc->notExpr(id513); vc->registerAtom(id513); Expr id515=vc->eqExpr(id145,id167); Expr id514=vc->notExpr(id515); vc->registerAtom(id515); Expr id517=vc->eqExpr(id147,id169); Expr id516=vc->notExpr(id517); vc->registerAtom(id517); Expr id519=vc->eqExpr(id149,id171); Expr id518=vc->notExpr(id519); vc->registerAtom(id519); Expr id521=vc->eqExpr(id151,id173); Expr id520=vc->notExpr(id521); vc->registerAtom(id521); Expr id523=vc->eqExpr(id153,id175); Expr id522=vc->notExpr(id523); vc->registerAtom(id523); Expr id525=vc->eqExpr(id155,id177); Expr id524=vc->notExpr(id525); vc->registerAtom(id525); Expr id527=vc->plusExpr(id161,id453); Expr id529=vc->eqExpr(id527,id183); Expr id528=vc->notExpr(id529); vc->registerAtom(id529); Expr id531=vc->eqExpr(id165,id187); Expr id530=vc->notExpr(id531); vc->registerAtom(id531); Expr id533=vc->eqExpr(id167,id189); Expr id532=vc->notExpr(id533); vc->registerAtom(id533); Expr id535=vc->eqExpr(id169,id191); Expr id534=vc->notExpr(id535); vc->registerAtom(id535); Expr id537=vc->eqExpr(id171,id193); Expr id536=vc->notExpr(id537); vc->registerAtom(id537); Expr id539=vc->eqExpr(id173,id195); Expr id538=vc->notExpr(id539); vc->registerAtom(id539); Expr id541=vc->eqExpr(id175,id197); Expr id540=vc->notExpr(id541); vc->registerAtom(id541); Expr id543=vc->eqExpr(id177,id199); Expr id542=vc->notExpr(id543); vc->registerAtom(id543); Expr id545=vc->plusExpr(id183,id453); Expr id547=vc->eqExpr(id545,id205); Expr id546=vc->notExpr(id547); vc->registerAtom(id547); Expr id549=vc->eqExpr(id187,id209); Expr id548=vc->notExpr(id549); vc->registerAtom(id549); Expr id551=vc->eqExpr(id189,id211); Expr id550=vc->notExpr(id551); vc->registerAtom(id551); Expr id553=vc->eqExpr(id191,id213); Expr id552=vc->notExpr(id553); vc->registerAtom(id553); Expr id555=vc->eqExpr(id193,id215); Expr id554=vc->notExpr(id555); vc->registerAtom(id555); Expr id557=vc->eqExpr(id195,id217); Expr id556=vc->notExpr(id557); vc->registerAtom(id557); Expr id559=vc->eqExpr(id197,id219); Expr id558=vc->notExpr(id559); vc->registerAtom(id559); Expr id561=vc->eqExpr(id199,id221); Expr id560=vc->notExpr(id561); vc->registerAtom(id561); Expr id563=vc->plusExpr(id205,id453); Expr id565=vc->eqExpr(id563,id227); Expr id564=vc->notExpr(id565); vc->registerAtom(id565); Expr id567=vc->eqExpr(id209,id231); Expr id566=vc->notExpr(id567); vc->registerAtom(id567); Expr id569=vc->eqExpr(id211,id233); Expr id568=vc->notExpr(id569); vc->registerAtom(id569); Expr id571=vc->eqExpr(id213,id235); Expr id570=vc->notExpr(id571); vc->registerAtom(id571); Expr id573=vc->eqExpr(id215,id237); Expr id572=vc->notExpr(id573); vc->registerAtom(id573); Expr id575=vc->eqExpr(id217,id239); Expr id574=vc->notExpr(id575); vc->registerAtom(id575); Expr id577=vc->eqExpr(id219,id241); Expr id576=vc->notExpr(id577); vc->registerAtom(id577); Expr id579=vc->eqExpr(id221,id243); Expr id578=vc->notExpr(id579); vc->registerAtom(id579); Expr id581=vc->plusExpr(id227,id453); Expr id583=vc->eqExpr(id581,id249); Expr id582=vc->notExpr(id583); vc->registerAtom(id583); Expr id585=vc->eqExpr(id231,id253); Expr id584=vc->notExpr(id585); vc->registerAtom(id585); Expr id587=vc->eqExpr(id233,id255); Expr id586=vc->notExpr(id587); vc->registerAtom(id587); Expr id589=vc->eqExpr(id235,id257); Expr id588=vc->notExpr(id589); vc->registerAtom(id589); Expr id591=vc->eqExpr(id237,id259); Expr id590=vc->notExpr(id591); vc->registerAtom(id591); Expr id593=vc->eqExpr(id239,id261); Expr id592=vc->notExpr(id593); vc->registerAtom(id593); Expr id595=vc->eqExpr(id241,id263); Expr id594=vc->notExpr(id595); vc->registerAtom(id595); Expr id597=vc->eqExpr(id243,id265); Expr id596=vc->notExpr(id597); vc->registerAtom(id597); Expr id599=vc->plusExpr(id249,id453); Expr id601=vc->eqExpr(id599,id271); Expr id600=vc->notExpr(id601); vc->registerAtom(id601); Expr id603=vc->eqExpr(id253,id275); Expr id602=vc->notExpr(id603); vc->registerAtom(id603); Expr id605=vc->eqExpr(id255,id277); Expr id604=vc->notExpr(id605); vc->registerAtom(id605); Expr id607=vc->eqExpr(id257,id279); Expr id606=vc->notExpr(id607); vc->registerAtom(id607); Expr id609=vc->eqExpr(id259,id281); Expr id608=vc->notExpr(id609); vc->registerAtom(id609); Expr id611=vc->eqExpr(id261,id283); Expr id610=vc->notExpr(id611); vc->registerAtom(id611); Expr id613=vc->eqExpr(id263,id285); Expr id612=vc->notExpr(id613); vc->registerAtom(id613); Expr id615=vc->eqExpr(id265,id287); Expr id614=vc->notExpr(id615); vc->registerAtom(id615); Expr id617=vc->plusExpr(id271,id453); Expr id619=vc->eqExpr(id617,id293); Expr id618=vc->notExpr(id619); vc->registerAtom(id619); Expr id621=vc->eqExpr(id275,id297); Expr id620=vc->notExpr(id621); vc->registerAtom(id621); Expr id623=vc->eqExpr(id277,id299); Expr id622=vc->notExpr(id623); vc->registerAtom(id623); Expr id625=vc->eqExpr(id279,id301); Expr id624=vc->notExpr(id625); vc->registerAtom(id625); Expr id627=vc->eqExpr(id281,id303); Expr id626=vc->notExpr(id627); vc->registerAtom(id627); Expr id629=vc->eqExpr(id283,id305); Expr id628=vc->notExpr(id629); vc->registerAtom(id629); Expr id631=vc->eqExpr(id285,id307); Expr id630=vc->notExpr(id631); vc->registerAtom(id631); Expr id633=vc->eqExpr(id287,id309); Expr id632=vc->notExpr(id633); vc->registerAtom(id633); Expr id635=vc->plusExpr(id293,id453); Expr id637=vc->eqExpr(id635,id315); Expr id636=vc->notExpr(id637); vc->registerAtom(id637); Expr id639=vc->eqExpr(id297,id319); Expr id638=vc->notExpr(id639); vc->registerAtom(id639); Expr id641=vc->eqExpr(id299,id321); Expr id640=vc->notExpr(id641); vc->registerAtom(id641); Expr id643=vc->eqExpr(id301,id323); Expr id642=vc->notExpr(id643); vc->registerAtom(id643); Expr id645=vc->eqExpr(id303,id325); Expr id644=vc->notExpr(id645); vc->registerAtom(id645); Expr id647=vc->eqExpr(id305,id327); Expr id646=vc->notExpr(id647); vc->registerAtom(id647); Expr id649=vc->eqExpr(id307,id329); Expr id648=vc->notExpr(id649); vc->registerAtom(id649); Expr id651=vc->eqExpr(id309,id331); Expr id650=vc->notExpr(id651); vc->registerAtom(id651); Expr id653=vc->plusExpr(id315,id453); Expr id655=vc->eqExpr(id653,id337); Expr id654=vc->notExpr(id655); vc->registerAtom(id655); Expr id657=vc->eqExpr(id319,id341); Expr id656=vc->notExpr(id657); vc->registerAtom(id657); Expr id659=vc->eqExpr(id321,id343); Expr id658=vc->notExpr(id659); vc->registerAtom(id659); Expr id661=vc->eqExpr(id323,id345); Expr id660=vc->notExpr(id661); vc->registerAtom(id661); Expr id663=vc->eqExpr(id325,id347); Expr id662=vc->notExpr(id663); vc->registerAtom(id663); Expr id665=vc->eqExpr(id327,id349); Expr id664=vc->notExpr(id665); vc->registerAtom(id665); Expr id667=vc->eqExpr(id329,id351); Expr id666=vc->notExpr(id667); vc->registerAtom(id667); Expr id669=vc->eqExpr(id331,id353); Expr id668=vc->notExpr(id669); vc->registerAtom(id669); Expr id671=vc->plusExpr(id337,id453); Expr id673=vc->eqExpr(id671,id359); Expr id672=vc->notExpr(id673); vc->registerAtom(id673); Expr id675=vc->eqExpr(id341,id363); Expr id674=vc->notExpr(id675); vc->registerAtom(id675); Expr id677=vc->eqExpr(id343,id365); Expr id676=vc->notExpr(id677); vc->registerAtom(id677); Expr id679=vc->eqExpr(id345,id367); Expr id678=vc->notExpr(id679); vc->registerAtom(id679); Expr id681=vc->eqExpr(id347,id369); Expr id680=vc->notExpr(id681); vc->registerAtom(id681); Expr id683=vc->eqExpr(id349,id371); Expr id682=vc->notExpr(id683); vc->registerAtom(id683); Expr id685=vc->eqExpr(id351,id373); Expr id684=vc->notExpr(id685); vc->registerAtom(id685); Expr id687=vc->eqExpr(id353,id375); Expr id686=vc->notExpr(id687); vc->registerAtom(id687); Expr id689=vc->plusExpr(id359,id453); Expr id691=vc->eqExpr(id689,id381); Expr id690=vc->notExpr(id691); vc->registerAtom(id691); Expr id693=vc->eqExpr(id363,id385); Expr id692=vc->notExpr(id693); vc->registerAtom(id693); Expr id695=vc->eqExpr(id365,id387); Expr id694=vc->notExpr(id695); vc->registerAtom(id695); Expr id697=vc->eqExpr(id367,id389); Expr id696=vc->notExpr(id697); vc->registerAtom(id697); Expr id699=vc->eqExpr(id369,id391); Expr id698=vc->notExpr(id699); vc->registerAtom(id699); Expr id701=vc->eqExpr(id371,id393); Expr id700=vc->notExpr(id701); vc->registerAtom(id701); Expr id703=vc->eqExpr(id373,id395); Expr id702=vc->notExpr(id703); vc->registerAtom(id703); Expr id705=vc->eqExpr(id375,id397); Expr id704=vc->notExpr(id705); vc->registerAtom(id705); Expr id707=vc->plusExpr(id381,id453); Expr id709=vc->eqExpr(id707,id403); Expr id708=vc->notExpr(id709); vc->registerAtom(id709); Expr id711=vc->eqExpr(id385,id407); Expr id710=vc->notExpr(id711); vc->registerAtom(id711); Expr id713=vc->eqExpr(id387,id409); Expr id712=vc->notExpr(id713); vc->registerAtom(id713); Expr id715=vc->eqExpr(id389,id411); Expr id714=vc->notExpr(id715); vc->registerAtom(id715); Expr id717=vc->eqExpr(id391,id413); Expr id716=vc->notExpr(id717); vc->registerAtom(id717); Expr id719=vc->eqExpr(id393,id415); Expr id718=vc->notExpr(id719); vc->registerAtom(id719); Expr id721=vc->eqExpr(id395,id417); Expr id720=vc->notExpr(id721); vc->registerAtom(id721); Expr id723=vc->eqExpr(id397,id419); Expr id722=vc->notExpr(id723); vc->registerAtom(id723); Expr id725=vc->uminusExpr(id453); Expr id727=vc->eqExpr(id725,id79); Expr id726=vc->notExpr(id727); vc->registerAtom(id727); Expr id729=vc->eqExpr(id725,id385); Expr id728=vc->notExpr(id729); vc->registerAtom(id729); Expr id731=vc->eqExpr(id725,id363); Expr id730=vc->notExpr(id731); vc->registerAtom(id731); Expr id733=vc->eqExpr(id725,id341); Expr id732=vc->notExpr(id733); vc->registerAtom(id733); Expr id735=vc->eqExpr(id725,id319); Expr id734=vc->notExpr(id735); vc->registerAtom(id735); Expr id737=vc->eqExpr(id725,id297); Expr id736=vc->notExpr(id737); vc->registerAtom(id737); Expr id739=vc->eqExpr(id725,id275); Expr id738=vc->notExpr(id739); vc->registerAtom(id739); Expr id741=vc->eqExpr(id725,id253); Expr id740=vc->notExpr(id741); vc->registerAtom(id741); Expr id743=vc->eqExpr(id725,id231); Expr id742=vc->notExpr(id743); vc->registerAtom(id743); Expr id745=vc->eqExpr(id725,id209); Expr id744=vc->notExpr(id745); vc->registerAtom(id745); Expr id747=vc->eqExpr(id725,id187); Expr id746=vc->notExpr(id747); vc->registerAtom(id747); Expr id749=vc->eqExpr(id725,id165); Expr id748=vc->notExpr(id749); vc->registerAtom(id749); Expr id751=vc->eqExpr(id725,id143); Expr id750=vc->notExpr(id751); vc->registerAtom(id751); Expr id753=vc->eqExpr(id725,id121); Expr id752=vc->notExpr(id753); vc->registerAtom(id753); Expr id755=vc->eqExpr(id725,id93); Expr id754=vc->notExpr(id755); vc->registerAtom(id755); Expr id757=vc->ratExpr(0,1); Expr id759=vc->leExpr(id89,id757); Expr id758=vc->notExpr(id759); vc->registerAtom(id759); Expr id763=vc->eqExpr(id757,id75); Expr id762=vc->notExpr(id763); vc->registerAtom(id763); Expr id767=vc->eqExpr(id757,id77); Expr id766=vc->notExpr(id767); vc->registerAtom(id767); Expr id773=vc->eqExpr(id757,id81); Expr id772=vc->notExpr(id773); vc->registerAtom(id773); Expr id777=vc->readExpr(id83,id79); Expr id779=vc->eqExpr(id777,id423); Expr id778=vc->notExpr(id779); vc->registerAtom(id779); Expr id783=vc->eqExpr(id423,id85); Expr id782=vc->notExpr(id783); vc->registerAtom(id783); Expr id787=vc->ratExpr(2,1); Expr id789=vc->plusExpr(id89,id787); Expr id791=vc->eqExpr(id789,id91); Expr id790=vc->notExpr(id791); vc->registerAtom(id791); Expr id795=vc->readExpr(id107,id93); Expr id797=vc->eqExpr(id795,id425); Expr id796=vc->notExpr(id797); vc->registerAtom(id797); Expr id801=vc->eqExpr(id425,id115); Expr id800=vc->notExpr(id801); vc->registerAtom(id801); Expr id805=vc->eqExpr(id789,id119); Expr id804=vc->notExpr(id805); vc->registerAtom(id805); Expr id809=vc->readExpr(id131,id121); Expr id811=vc->eqExpr(id809,id427); Expr id810=vc->notExpr(id811); vc->registerAtom(id811); Expr id815=vc->eqExpr(id427,id137); Expr id814=vc->notExpr(id815); vc->registerAtom(id815); Expr id819=vc->eqExpr(id789,id141); Expr id818=vc->notExpr(id819); vc->registerAtom(id819); Expr id823=vc->readExpr(id153,id143); Expr id825=vc->eqExpr(id823,id429); Expr id824=vc->notExpr(id825); vc->registerAtom(id825); Expr id829=vc->eqExpr(id429,id159); Expr id828=vc->notExpr(id829); vc->registerAtom(id829); Expr id833=vc->eqExpr(id789,id163); Expr id832=vc->notExpr(id833); vc->registerAtom(id833); Expr id837=vc->readExpr(id175,id165); Expr id839=vc->eqExpr(id837,id431); Expr id838=vc->notExpr(id839); vc->registerAtom(id839); Expr id843=vc->eqExpr(id431,id181); Expr id842=vc->notExpr(id843); vc->registerAtom(id843); Expr id847=vc->eqExpr(id789,id185); Expr id846=vc->notExpr(id847); vc->registerAtom(id847); Expr id851=vc->readExpr(id197,id187); Expr id853=vc->eqExpr(id851,id433); Expr id852=vc->notExpr(id853); vc->registerAtom(id853); Expr id857=vc->eqExpr(id433,id203); Expr id856=vc->notExpr(id857); vc->registerAtom(id857); Expr id861=vc->eqExpr(id789,id207); Expr id860=vc->notExpr(id861); vc->registerAtom(id861); Expr id865=vc->readExpr(id219,id209); Expr id867=vc->eqExpr(id865,id435); Expr id866=vc->notExpr(id867); vc->registerAtom(id867); Expr id871=vc->eqExpr(id435,id225); Expr id870=vc->notExpr(id871); vc->registerAtom(id871); Expr id875=vc->eqExpr(id789,id229); Expr id874=vc->notExpr(id875); vc->registerAtom(id875); Expr id879=vc->readExpr(id241,id231); Expr id881=vc->eqExpr(id879,id437); Expr id880=vc->notExpr(id881); vc->registerAtom(id881); Expr id885=vc->eqExpr(id437,id247); Expr id884=vc->notExpr(id885); vc->registerAtom(id885); Expr id889=vc->eqExpr(id789,id251); Expr id888=vc->notExpr(id889); vc->registerAtom(id889); Expr id893=vc->readExpr(id263,id253); Expr id895=vc->eqExpr(id893,id439); Expr id894=vc->notExpr(id895); vc->registerAtom(id895); Expr id899=vc->eqExpr(id439,id269); Expr id898=vc->notExpr(id899); vc->registerAtom(id899); Expr id903=vc->eqExpr(id789,id273); Expr id902=vc->notExpr(id903); vc->registerAtom(id903); Expr id907=vc->readExpr(id285,id275); Expr id909=vc->eqExpr(id907,id441); Expr id908=vc->notExpr(id909); vc->registerAtom(id909); Expr id913=vc->eqExpr(id441,id291); Expr id912=vc->notExpr(id913); vc->registerAtom(id913); Expr id917=vc->eqExpr(id789,id295); Expr id916=vc->notExpr(id917); vc->registerAtom(id917); Expr id921=vc->readExpr(id307,id297); Expr id923=vc->eqExpr(id921,id443); Expr id922=vc->notExpr(id923); vc->registerAtom(id923); Expr id927=vc->eqExpr(id443,id313); Expr id926=vc->notExpr(id927); vc->registerAtom(id927); Expr id931=vc->eqExpr(id789,id317); Expr id930=vc->notExpr(id931); vc->registerAtom(id931); Expr id935=vc->readExpr(id329,id319); Expr id937=vc->eqExpr(id935,id445); Expr id936=vc->notExpr(id937); vc->registerAtom(id937); Expr id941=vc->eqExpr(id445,id335); Expr id940=vc->notExpr(id941); vc->registerAtom(id941); Expr id945=vc->eqExpr(id789,id339); Expr id944=vc->notExpr(id945); vc->registerAtom(id945); Expr id949=vc->readExpr(id351,id341); Expr id951=vc->eqExpr(id949,id447); Expr id950=vc->notExpr(id951); vc->registerAtom(id951); Expr id955=vc->eqExpr(id447,id357); Expr id954=vc->notExpr(id955); vc->registerAtom(id955); Expr id959=vc->eqExpr(id789,id361); Expr id958=vc->notExpr(id959); vc->registerAtom(id959); Expr id963=vc->readExpr(id373,id363); Expr id965=vc->eqExpr(id963,id449); Expr id964=vc->notExpr(id965); vc->registerAtom(id965); Expr id969=vc->eqExpr(id449,id379); Expr id968=vc->notExpr(id969); vc->registerAtom(id969); Expr id973=vc->eqExpr(id789,id383); Expr id972=vc->notExpr(id973); vc->registerAtom(id973); Expr id977=vc->readExpr(id395,id385); Expr id979=vc->eqExpr(id977,id451); Expr id978=vc->notExpr(id979); vc->registerAtom(id979); Expr id983=vc->eqExpr(id451,id401); Expr id982=vc->notExpr(id983); vc->registerAtom(id983); Expr id987=vc->eqExpr(id789,id405); Expr id986=vc->notExpr(id987); vc->registerAtom(id987); Expr id991=vc->eqExpr(id757,id421); Expr id990=vc->notExpr(id991); vc->registerAtom(id991); Expr id993=vc->ltExpr(id381,id89); Expr id992=vc->notExpr(id993); vc->registerAtom(id993); Expr id999=vc->plusExpr(id393,id453); Expr id1001=vc->eqExpr(id999,id415); Expr id1000=vc->notExpr(id1001); vc->registerAtom(id1001); Expr id1005=vc->eqExpr(id391,id407); Expr id1004=vc->notExpr(id1005); vc->registerAtom(id1005); Expr id1009=vc->plusExpr(id391,id453); Expr id1011=vc->eqExpr(id1009,id413); Expr id1010=vc->notExpr(id1011); vc->registerAtom(id1011); Expr id1015=vc->writeExpr(id387,id391,id381); Expr id1017=vc->eqExpr(id1015,id409); Expr id1016=vc->notExpr(id1017); vc->registerAtom(id1017); Expr id1023=vc->writeExpr(id395,id391,id385); Expr id1025=vc->eqExpr(id1023,id417); Expr id1024=vc->notExpr(id1025); vc->registerAtom(id1025); Expr id1031=vc->eqExpr(id453,id421); Expr id1030=vc->notExpr(id1031); vc->registerAtom(id1031); Expr id1033=vc->eqExpr(id89,id381); Expr id1032=vc->notExpr(id1033); vc->registerAtom(id1033); Expr id1041=vc->eqExpr(id385,id419); Expr id1040=vc->notExpr(id1041); vc->registerAtom(id1041); Expr id1045=vc->eqExpr(id401,id407); Expr id1044=vc->notExpr(id1045); vc->registerAtom(id1045); Expr id1063=vc->eqExpr(id787,id421); Expr id1062=vc->notExpr(id1063); vc->registerAtom(id1063); Expr id1065=vc->plusExpr(id89,id453); Expr id1067=vc->eqExpr(id1065,id381); Expr id1066=vc->notExpr(id1067); vc->registerAtom(id1067); Expr id1083=vc->writeExpr(id395,id397,id401); Expr id1085=vc->eqExpr(id1083,id417); Expr id1084=vc->notExpr(id1085); vc->registerAtom(id1085); Expr id1093=vc->ratExpr(3,1); Expr id1095=vc->eqExpr(id1093,id421); Expr id1094=vc->notExpr(id1095); vc->registerAtom(id1095); Expr id1097=vc->eqExpr(id405,id381); Expr id1096=vc->notExpr(id1097); vc->registerAtom(id1097); Expr id1113=vc->writeExpr(id395,id385,id397); Expr id1115=vc->eqExpr(id1113,id417); Expr id1114=vc->notExpr(id1115); vc->registerAtom(id1115); Expr id1123=vc->ratExpr(4,1); Expr id1125=vc->eqExpr(id1123,id421); Expr id1124=vc->notExpr(id1125); vc->registerAtom(id1125); Expr id1127=vc->leExpr(id381,id405); Expr id1126=vc->notExpr(id1127); vc->registerAtom(id1127); Expr id1147=vc->eqExpr(id381,id403); Expr id1146=vc->notExpr(id1147); vc->registerAtom(id1147); Expr id1155=vc->eqExpr(id757,id399); Expr id1154=vc->notExpr(id1155); vc->registerAtom(id1155); Expr id1157=vc->ltExpr(id359,id89); Expr id1156=vc->notExpr(id1157); vc->registerAtom(id1157); Expr id1163=vc->plusExpr(id371,id453); Expr id1165=vc->eqExpr(id1163,id393); Expr id1164=vc->notExpr(id1165); vc->registerAtom(id1165); Expr id1169=vc->eqExpr(id369,id385); Expr id1168=vc->notExpr(id1169); vc->registerAtom(id1169); Expr id1173=vc->plusExpr(id369,id453); Expr id1175=vc->eqExpr(id1173,id391); Expr id1174=vc->notExpr(id1175); vc->registerAtom(id1175); Expr id1179=vc->writeExpr(id365,id369,id359); Expr id1181=vc->eqExpr(id1179,id387); Expr id1180=vc->notExpr(id1181); vc->registerAtom(id1181); Expr id1187=vc->writeExpr(id373,id369,id363); Expr id1189=vc->eqExpr(id1187,id395); Expr id1188=vc->notExpr(id1189); vc->registerAtom(id1189); Expr id1195=vc->eqExpr(id453,id399); Expr id1194=vc->notExpr(id1195); vc->registerAtom(id1195); Expr id1197=vc->eqExpr(id89,id359); Expr id1196=vc->notExpr(id1197); vc->registerAtom(id1197); Expr id1205=vc->eqExpr(id363,id397); Expr id1204=vc->notExpr(id1205); vc->registerAtom(id1205); Expr id1209=vc->eqExpr(id379,id385); Expr id1208=vc->notExpr(id1209); vc->registerAtom(id1209); Expr id1227=vc->eqExpr(id787,id399); Expr id1226=vc->notExpr(id1227); vc->registerAtom(id1227); Expr id1229=vc->eqExpr(id1065,id359); Expr id1228=vc->notExpr(id1229); vc->registerAtom(id1229); Expr id1245=vc->writeExpr(id373,id375,id379); Expr id1247=vc->eqExpr(id1245,id395); Expr id1246=vc->notExpr(id1247); vc->registerAtom(id1247); Expr id1255=vc->eqExpr(id1093,id399); Expr id1254=vc->notExpr(id1255); vc->registerAtom(id1255); Expr id1257=vc->eqExpr(id383,id359); Expr id1256=vc->notExpr(id1257); vc->registerAtom(id1257); Expr id1273=vc->writeExpr(id373,id363,id375); Expr id1275=vc->eqExpr(id1273,id395); Expr id1274=vc->notExpr(id1275); vc->registerAtom(id1275); Expr id1283=vc->eqExpr(id1123,id399); Expr id1282=vc->notExpr(id1283); vc->registerAtom(id1283); Expr id1285=vc->leExpr(id359,id383); Expr id1284=vc->notExpr(id1285); vc->registerAtom(id1285); Expr id1305=vc->eqExpr(id359,id381); Expr id1304=vc->notExpr(id1305); vc->registerAtom(id1305); Expr id1313=vc->eqExpr(id757,id377); Expr id1312=vc->notExpr(id1313); vc->registerAtom(id1313); Expr id1315=vc->ltExpr(id337,id89); Expr id1314=vc->notExpr(id1315); vc->registerAtom(id1315); Expr id1321=vc->plusExpr(id349,id453); Expr id1323=vc->eqExpr(id1321,id371); Expr id1322=vc->notExpr(id1323); vc->registerAtom(id1323); Expr id1327=vc->eqExpr(id347,id363); Expr id1326=vc->notExpr(id1327); vc->registerAtom(id1327); Expr id1331=vc->plusExpr(id347,id453); Expr id1333=vc->eqExpr(id1331,id369); Expr id1332=vc->notExpr(id1333); vc->registerAtom(id1333); Expr id1337=vc->writeExpr(id343,id347,id337); Expr id1339=vc->eqExpr(id1337,id365); Expr id1338=vc->notExpr(id1339); vc->registerAtom(id1339); Expr id1345=vc->writeExpr(id351,id347,id341); Expr id1347=vc->eqExpr(id1345,id373); Expr id1346=vc->notExpr(id1347); vc->registerAtom(id1347); Expr id1353=vc->eqExpr(id453,id377); Expr id1352=vc->notExpr(id1353); vc->registerAtom(id1353); Expr id1355=vc->eqExpr(id89,id337); Expr id1354=vc->notExpr(id1355); vc->registerAtom(id1355); Expr id1363=vc->eqExpr(id341,id375); Expr id1362=vc->notExpr(id1363); vc->registerAtom(id1363); Expr id1367=vc->eqExpr(id357,id363); Expr id1366=vc->notExpr(id1367); vc->registerAtom(id1367); Expr id1385=vc->eqExpr(id787,id377); Expr id1384=vc->notExpr(id1385); vc->registerAtom(id1385); Expr id1387=vc->eqExpr(id1065,id337); Expr id1386=vc->notExpr(id1387); vc->registerAtom(id1387); Expr id1403=vc->writeExpr(id351,id353,id357); Expr id1405=vc->eqExpr(id1403,id373); Expr id1404=vc->notExpr(id1405); vc->registerAtom(id1405); Expr id1413=vc->eqExpr(id1093,id377); Expr id1412=vc->notExpr(id1413); vc->registerAtom(id1413); Expr id1415=vc->eqExpr(id361,id337); Expr id1414=vc->notExpr(id1415); vc->registerAtom(id1415); Expr id1431=vc->writeExpr(id351,id341,id353); Expr id1433=vc->eqExpr(id1431,id373); Expr id1432=vc->notExpr(id1433); vc->registerAtom(id1433); Expr id1441=vc->eqExpr(id1123,id377); Expr id1440=vc->notExpr(id1441); vc->registerAtom(id1441); Expr id1443=vc->leExpr(id337,id361); Expr id1442=vc->notExpr(id1443); vc->registerAtom(id1443); Expr id1463=vc->eqExpr(id337,id359); Expr id1462=vc->notExpr(id1463); vc->registerAtom(id1463); Expr id1471=vc->eqExpr(id757,id355); Expr id1470=vc->notExpr(id1471); vc->registerAtom(id1471); Expr id1473=vc->ltExpr(id315,id89); Expr id1472=vc->notExpr(id1473); vc->registerAtom(id1473); Expr id1479=vc->plusExpr(id327,id453); Expr id1481=vc->eqExpr(id1479,id349); Expr id1480=vc->notExpr(id1481); vc->registerAtom(id1481); Expr id1485=vc->eqExpr(id325,id341); Expr id1484=vc->notExpr(id1485); vc->registerAtom(id1485); Expr id1489=vc->plusExpr(id325,id453); Expr id1491=vc->eqExpr(id1489,id347); Expr id1490=vc->notExpr(id1491); vc->registerAtom(id1491); Expr id1495=vc->writeExpr(id321,id325,id315); Expr id1497=vc->eqExpr(id1495,id343); Expr id1496=vc->notExpr(id1497); vc->registerAtom(id1497); Expr id1503=vc->writeExpr(id329,id325,id319); Expr id1505=vc->eqExpr(id1503,id351); Expr id1504=vc->notExpr(id1505); vc->registerAtom(id1505); Expr id1511=vc->eqExpr(id453,id355); Expr id1510=vc->notExpr(id1511); vc->registerAtom(id1511); Expr id1513=vc->eqExpr(id89,id315); Expr id1512=vc->notExpr(id1513); vc->registerAtom(id1513); Expr id1521=vc->eqExpr(id319,id353); Expr id1520=vc->notExpr(id1521); vc->registerAtom(id1521); Expr id1525=vc->eqExpr(id335,id341); Expr id1524=vc->notExpr(id1525); vc->registerAtom(id1525); Expr id1543=vc->eqExpr(id787,id355); Expr id1542=vc->notExpr(id1543); vc->registerAtom(id1543); Expr id1545=vc->eqExpr(id1065,id315); Expr id1544=vc->notExpr(id1545); vc->registerAtom(id1545); Expr id1561=vc->writeExpr(id329,id331,id335); Expr id1563=vc->eqExpr(id1561,id351); Expr id1562=vc->notExpr(id1563); vc->registerAtom(id1563); Expr id1571=vc->eqExpr(id1093,id355); Expr id1570=vc->notExpr(id1571); vc->registerAtom(id1571); Expr id1573=vc->eqExpr(id339,id315); Expr id1572=vc->notExpr(id1573); vc->registerAtom(id1573); Expr id1589=vc->writeExpr(id329,id319,id331); Expr id1591=vc->eqExpr(id1589,id351); Expr id1590=vc->notExpr(id1591); vc->registerAtom(id1591); Expr id1599=vc->eqExpr(id1123,id355); Expr id1598=vc->notExpr(id1599); vc->registerAtom(id1599); Expr id1601=vc->leExpr(id315,id339); Expr id1600=vc->notExpr(id1601); vc->registerAtom(id1601); Expr id1621=vc->eqExpr(id315,id337); Expr id1620=vc->notExpr(id1621); vc->registerAtom(id1621); Expr id1629=vc->eqExpr(id757,id333); Expr id1628=vc->notExpr(id1629); vc->registerAtom(id1629); Expr id1631=vc->ltExpr(id293,id89); Expr id1630=vc->notExpr(id1631); vc->registerAtom(id1631); Expr id1637=vc->plusExpr(id305,id453); Expr id1639=vc->eqExpr(id1637,id327); Expr id1638=vc->notExpr(id1639); vc->registerAtom(id1639); Expr id1643=vc->eqExpr(id303,id319); Expr id1642=vc->notExpr(id1643); vc->registerAtom(id1643); Expr id1647=vc->plusExpr(id303,id453); Expr id1649=vc->eqExpr(id1647,id325); Expr id1648=vc->notExpr(id1649); vc->registerAtom(id1649); Expr id1653=vc->writeExpr(id299,id303,id293); Expr id1655=vc->eqExpr(id1653,id321); Expr id1654=vc->notExpr(id1655); vc->registerAtom(id1655); Expr id1661=vc->writeExpr(id307,id303,id297); Expr id1663=vc->eqExpr(id1661,id329); Expr id1662=vc->notExpr(id1663); vc->registerAtom(id1663); Expr id1669=vc->eqExpr(id453,id333); Expr id1668=vc->notExpr(id1669); vc->registerAtom(id1669); Expr id1671=vc->eqExpr(id89,id293); Expr id1670=vc->notExpr(id1671); vc->registerAtom(id1671); Expr id1679=vc->eqExpr(id297,id331); Expr id1678=vc->notExpr(id1679); vc->registerAtom(id1679); Expr id1683=vc->eqExpr(id313,id319); Expr id1682=vc->notExpr(id1683); vc->registerAtom(id1683); Expr id1701=vc->eqExpr(id787,id333); Expr id1700=vc->notExpr(id1701); vc->registerAtom(id1701); Expr id1703=vc->eqExpr(id1065,id293); Expr id1702=vc->notExpr(id1703); vc->registerAtom(id1703); Expr id1719=vc->writeExpr(id307,id309,id313); Expr id1721=vc->eqExpr(id1719,id329); Expr id1720=vc->notExpr(id1721); vc->registerAtom(id1721); Expr id1729=vc->eqExpr(id1093,id333); Expr id1728=vc->notExpr(id1729); vc->registerAtom(id1729); Expr id1731=vc->eqExpr(id317,id293); Expr id1730=vc->notExpr(id1731); vc->registerAtom(id1731); Expr id1747=vc->writeExpr(id307,id297,id309); Expr id1749=vc->eqExpr(id1747,id329); Expr id1748=vc->notExpr(id1749); vc->registerAtom(id1749); Expr id1757=vc->eqExpr(id1123,id333); Expr id1756=vc->notExpr(id1757); vc->registerAtom(id1757); Expr id1759=vc->leExpr(id293,id317); Expr id1758=vc->notExpr(id1759); vc->registerAtom(id1759); Expr id1779=vc->eqExpr(id293,id315); Expr id1778=vc->notExpr(id1779); vc->registerAtom(id1779); Expr id1787=vc->eqExpr(id757,id311); Expr id1786=vc->notExpr(id1787); vc->registerAtom(id1787); Expr id1789=vc->ltExpr(id271,id89); Expr id1788=vc->notExpr(id1789); vc->registerAtom(id1789); Expr id1795=vc->plusExpr(id283,id453); Expr id1797=vc->eqExpr(id1795,id305); Expr id1796=vc->notExpr(id1797); vc->registerAtom(id1797); Expr id1801=vc->eqExpr(id281,id297); Expr id1800=vc->notExpr(id1801); vc->registerAtom(id1801); Expr id1805=vc->plusExpr(id281,id453); Expr id1807=vc->eqExpr(id1805,id303); Expr id1806=vc->notExpr(id1807); vc->registerAtom(id1807); Expr id1811=vc->writeExpr(id277,id281,id271); Expr id1813=vc->eqExpr(id1811,id299); Expr id1812=vc->notExpr(id1813); vc->registerAtom(id1813); Expr id1819=vc->writeExpr(id285,id281,id275); Expr id1821=vc->eqExpr(id1819,id307); Expr id1820=vc->notExpr(id1821); vc->registerAtom(id1821); Expr id1827=vc->eqExpr(id453,id311); Expr id1826=vc->notExpr(id1827); vc->registerAtom(id1827); Expr id1829=vc->eqExpr(id89,id271); Expr id1828=vc->notExpr(id1829); vc->registerAtom(id1829); Expr id1837=vc->eqExpr(id275,id309); Expr id1836=vc->notExpr(id1837); vc->registerAtom(id1837); Expr id1841=vc->eqExpr(id291,id297); Expr id1840=vc->notExpr(id1841); vc->registerAtom(id1841); Expr id1859=vc->eqExpr(id787,id311); Expr id1858=vc->notExpr(id1859); vc->registerAtom(id1859); Expr id1861=vc->eqExpr(id1065,id271); Expr id1860=vc->notExpr(id1861); vc->registerAtom(id1861); Expr id1877=vc->writeExpr(id285,id287,id291); Expr id1879=vc->eqExpr(id1877,id307); Expr id1878=vc->notExpr(id1879); vc->registerAtom(id1879); Expr id1887=vc->eqExpr(id1093,id311); Expr id1886=vc->notExpr(id1887); vc->registerAtom(id1887); Expr id1889=vc->eqExpr(id295,id271); Expr id1888=vc->notExpr(id1889); vc->registerAtom(id1889); Expr id1905=vc->writeExpr(id285,id275,id287); Expr id1907=vc->eqExpr(id1905,id307); Expr id1906=vc->notExpr(id1907); vc->registerAtom(id1907); Expr id1915=vc->eqExpr(id1123,id311); Expr id1914=vc->notExpr(id1915); vc->registerAtom(id1915); Expr id1917=vc->leExpr(id271,id295); Expr id1916=vc->notExpr(id1917); vc->registerAtom(id1917); Expr id1937=vc->eqExpr(id271,id293); Expr id1936=vc->notExpr(id1937); vc->registerAtom(id1937); Expr id1945=vc->eqExpr(id757,id289); Expr id1944=vc->notExpr(id1945); vc->registerAtom(id1945); Expr id1947=vc->ltExpr(id249,id89); Expr id1946=vc->notExpr(id1947); vc->registerAtom(id1947); Expr id1953=vc->plusExpr(id261,id453); Expr id1955=vc->eqExpr(id1953,id283); Expr id1954=vc->notExpr(id1955); vc->registerAtom(id1955); Expr id1959=vc->eqExpr(id259,id275); Expr id1958=vc->notExpr(id1959); vc->registerAtom(id1959); Expr id1963=vc->plusExpr(id259,id453); Expr id1965=vc->eqExpr(id1963,id281); Expr id1964=vc->notExpr(id1965); vc->registerAtom(id1965); Expr id1969=vc->writeExpr(id255,id259,id249); Expr id1971=vc->eqExpr(id1969,id277); Expr id1970=vc->notExpr(id1971); vc->registerAtom(id1971); Expr id1977=vc->writeExpr(id263,id259,id253); Expr id1979=vc->eqExpr(id1977,id285); Expr id1978=vc->notExpr(id1979); vc->registerAtom(id1979); Expr id1985=vc->eqExpr(id453,id289); Expr id1984=vc->notExpr(id1985); vc->registerAtom(id1985); Expr id1987=vc->eqExpr(id89,id249); Expr id1986=vc->notExpr(id1987); vc->registerAtom(id1987); Expr id1995=vc->eqExpr(id253,id287); Expr id1994=vc->notExpr(id1995); vc->registerAtom(id1995); Expr id1999=vc->eqExpr(id269,id275); Expr id1998=vc->notExpr(id1999); vc->registerAtom(id1999); Expr id2017=vc->eqExpr(id787,id289); Expr id2016=vc->notExpr(id2017); vc->registerAtom(id2017); Expr id2019=vc->eqExpr(id1065,id249); Expr id2018=vc->notExpr(id2019); vc->registerAtom(id2019); Expr id2035=vc->writeExpr(id263,id265,id269); Expr id2037=vc->eqExpr(id2035,id285); Expr id2036=vc->notExpr(id2037); vc->registerAtom(id2037); Expr id2045=vc->eqExpr(id1093,id289); Expr id2044=vc->notExpr(id2045); vc->registerAtom(id2045); Expr id2047=vc->eqExpr(id273,id249); Expr id2046=vc->notExpr(id2047); vc->registerAtom(id2047); Expr id2063=vc->writeExpr(id263,id253,id265); Expr id2065=vc->eqExpr(id2063,id285); Expr id2064=vc->notExpr(id2065); vc->registerAtom(id2065); Expr id2073=vc->eqExpr(id1123,id289); Expr id2072=vc->notExpr(id2073); vc->registerAtom(id2073); Expr id2075=vc->leExpr(id249,id273); Expr id2074=vc->notExpr(id2075); vc->registerAtom(id2075); Expr id2095=vc->eqExpr(id249,id271); Expr id2094=vc->notExpr(id2095); vc->registerAtom(id2095); Expr id2103=vc->eqExpr(id757,id267); Expr id2102=vc->notExpr(id2103); vc->registerAtom(id2103); Expr id2105=vc->ltExpr(id227,id89); Expr id2104=vc->notExpr(id2105); vc->registerAtom(id2105); Expr id2111=vc->plusExpr(id239,id453); Expr id2113=vc->eqExpr(id2111,id261); Expr id2112=vc->notExpr(id2113); vc->registerAtom(id2113); Expr id2117=vc->eqExpr(id237,id253); Expr id2116=vc->notExpr(id2117); vc->registerAtom(id2117); Expr id2121=vc->plusExpr(id237,id453); Expr id2123=vc->eqExpr(id2121,id259); Expr id2122=vc->notExpr(id2123); vc->registerAtom(id2123); Expr id2127=vc->writeExpr(id233,id237,id227); Expr id2129=vc->eqExpr(id2127,id255); Expr id2128=vc->notExpr(id2129); vc->registerAtom(id2129); Expr id2135=vc->writeExpr(id241,id237,id231); Expr id2137=vc->eqExpr(id2135,id263); Expr id2136=vc->notExpr(id2137); vc->registerAtom(id2137); Expr id2143=vc->eqExpr(id453,id267); Expr id2142=vc->notExpr(id2143); vc->registerAtom(id2143); Expr id2145=vc->eqExpr(id89,id227); Expr id2144=vc->notExpr(id2145); vc->registerAtom(id2145); Expr id2153=vc->eqExpr(id231,id265); Expr id2152=vc->notExpr(id2153); vc->registerAtom(id2153); Expr id2157=vc->eqExpr(id247,id253); Expr id2156=vc->notExpr(id2157); vc->registerAtom(id2157); Expr id2175=vc->eqExpr(id787,id267); Expr id2174=vc->notExpr(id2175); vc->registerAtom(id2175); Expr id2177=vc->eqExpr(id1065,id227); Expr id2176=vc->notExpr(id2177); vc->registerAtom(id2177); Expr id2193=vc->writeExpr(id241,id243,id247); Expr id2195=vc->eqExpr(id2193,id263); Expr id2194=vc->notExpr(id2195); vc->registerAtom(id2195); Expr id2203=vc->eqExpr(id1093,id267); Expr id2202=vc->notExpr(id2203); vc->registerAtom(id2203); Expr id2205=vc->eqExpr(id251,id227); Expr id2204=vc->notExpr(id2205); vc->registerAtom(id2205); Expr id2221=vc->writeExpr(id241,id231,id243); Expr id2223=vc->eqExpr(id2221,id263); Expr id2222=vc->notExpr(id2223); vc->registerAtom(id2223); Expr id2231=vc->eqExpr(id1123,id267); Expr id2230=vc->notExpr(id2231); vc->registerAtom(id2231); Expr id2233=vc->leExpr(id227,id251); Expr id2232=vc->notExpr(id2233); vc->registerAtom(id2233); Expr id2253=vc->eqExpr(id227,id249); Expr id2252=vc->notExpr(id2253); vc->registerAtom(id2253); Expr id2261=vc->eqExpr(id757,id245); Expr id2260=vc->notExpr(id2261); vc->registerAtom(id2261); Expr id2263=vc->ltExpr(id205,id89); Expr id2262=vc->notExpr(id2263); vc->registerAtom(id2263); Expr id2269=vc->plusExpr(id217,id453); Expr id2271=vc->eqExpr(id2269,id239); Expr id2270=vc->notExpr(id2271); vc->registerAtom(id2271); Expr id2275=vc->eqExpr(id215,id231); Expr id2274=vc->notExpr(id2275); vc->registerAtom(id2275); Expr id2279=vc->plusExpr(id215,id453); Expr id2281=vc->eqExpr(id2279,id237); Expr id2280=vc->notExpr(id2281); vc->registerAtom(id2281); Expr id2285=vc->writeExpr(id211,id215,id205); Expr id2287=vc->eqExpr(id2285,id233); Expr id2286=vc->notExpr(id2287); vc->registerAtom(id2287); Expr id2293=vc->writeExpr(id219,id215,id209); Expr id2295=vc->eqExpr(id2293,id241); Expr id2294=vc->notExpr(id2295); vc->registerAtom(id2295); Expr id2301=vc->eqExpr(id453,id245); Expr id2300=vc->notExpr(id2301); vc->registerAtom(id2301); Expr id2303=vc->eqExpr(id89,id205); Expr id2302=vc->notExpr(id2303); vc->registerAtom(id2303); Expr id2311=vc->eqExpr(id209,id243); Expr id2310=vc->notExpr(id2311); vc->registerAtom(id2311); Expr id2315=vc->eqExpr(id225,id231); Expr id2314=vc->notExpr(id2315); vc->registerAtom(id2315); Expr id2333=vc->eqExpr(id787,id245); Expr id2332=vc->notExpr(id2333); vc->registerAtom(id2333); Expr id2335=vc->eqExpr(id1065,id205); Expr id2334=vc->notExpr(id2335); vc->registerAtom(id2335); Expr id2351=vc->writeExpr(id219,id221,id225); Expr id2353=vc->eqExpr(id2351,id241); Expr id2352=vc->notExpr(id2353); vc->registerAtom(id2353); Expr id2361=vc->eqExpr(id1093,id245); Expr id2360=vc->notExpr(id2361); vc->registerAtom(id2361); Expr id2363=vc->eqExpr(id229,id205); Expr id2362=vc->notExpr(id2363); vc->registerAtom(id2363); Expr id2379=vc->writeExpr(id219,id209,id221); Expr id2381=vc->eqExpr(id2379,id241); Expr id2380=vc->notExpr(id2381); vc->registerAtom(id2381); Expr id2389=vc->eqExpr(id1123,id245); Expr id2388=vc->notExpr(id2389); vc->registerAtom(id2389); Expr id2391=vc->leExpr(id205,id229); Expr id2390=vc->notExpr(id2391); vc->registerAtom(id2391); Expr id2411=vc->eqExpr(id205,id227); Expr id2410=vc->notExpr(id2411); vc->registerAtom(id2411); Expr id2419=vc->eqExpr(id757,id223); Expr id2418=vc->notExpr(id2419); vc->registerAtom(id2419); Expr id2421=vc->ltExpr(id183,id89); Expr id2420=vc->notExpr(id2421); vc->registerAtom(id2421); Expr id2427=vc->plusExpr(id195,id453); Expr id2429=vc->eqExpr(id2427,id217); Expr id2428=vc->notExpr(id2429); vc->registerAtom(id2429); Expr id2433=vc->eqExpr(id193,id209); Expr id2432=vc->notExpr(id2433); vc->registerAtom(id2433); Expr id2437=vc->plusExpr(id193,id453); Expr id2439=vc->eqExpr(id2437,id215); Expr id2438=vc->notExpr(id2439); vc->registerAtom(id2439); Expr id2443=vc->writeExpr(id189,id193,id183); Expr id2445=vc->eqExpr(id2443,id211); Expr id2444=vc->notExpr(id2445); vc->registerAtom(id2445); Expr id2451=vc->writeExpr(id197,id193,id187); Expr id2453=vc->eqExpr(id2451,id219); Expr id2452=vc->notExpr(id2453); vc->registerAtom(id2453); Expr id2459=vc->eqExpr(id453,id223); Expr id2458=vc->notExpr(id2459); vc->registerAtom(id2459); Expr id2461=vc->eqExpr(id89,id183); Expr id2460=vc->notExpr(id2461); vc->registerAtom(id2461); Expr id2469=vc->eqExpr(id187,id221); Expr id2468=vc->notExpr(id2469); vc->registerAtom(id2469); Expr id2473=vc->eqExpr(id203,id209); Expr id2472=vc->notExpr(id2473); vc->registerAtom(id2473); Expr id2491=vc->eqExpr(id787,id223); Expr id2490=vc->notExpr(id2491); vc->registerAtom(id2491); Expr id2493=vc->eqExpr(id1065,id183); Expr id2492=vc->notExpr(id2493); vc->registerAtom(id2493); Expr id2509=vc->writeExpr(id197,id199,id203); Expr id2511=vc->eqExpr(id2509,id219); Expr id2510=vc->notExpr(id2511); vc->registerAtom(id2511); Expr id2519=vc->eqExpr(id1093,id223); Expr id2518=vc->notExpr(id2519); vc->registerAtom(id2519); Expr id2521=vc->eqExpr(id207,id183); Expr id2520=vc->notExpr(id2521); vc->registerAtom(id2521); Expr id2537=vc->writeExpr(id197,id187,id199); Expr id2539=vc->eqExpr(id2537,id219); Expr id2538=vc->notExpr(id2539); vc->registerAtom(id2539); Expr id2547=vc->eqExpr(id1123,id223); Expr id2546=vc->notExpr(id2547); vc->registerAtom(id2547); Expr id2549=vc->leExpr(id183,id207); Expr id2548=vc->notExpr(id2549); vc->registerAtom(id2549); Expr id2569=vc->eqExpr(id183,id205); Expr id2568=vc->notExpr(id2569); vc->registerAtom(id2569); Expr id2577=vc->eqExpr(id757,id201); Expr id2576=vc->notExpr(id2577); vc->registerAtom(id2577); Expr id2579=vc->ltExpr(id161,id89); Expr id2578=vc->notExpr(id2579); vc->registerAtom(id2579); Expr id2585=vc->plusExpr(id173,id453); Expr id2587=vc->eqExpr(id2585,id195); Expr id2586=vc->notExpr(id2587); vc->registerAtom(id2587); Expr id2591=vc->eqExpr(id171,id187); Expr id2590=vc->notExpr(id2591); vc->registerAtom(id2591); Expr id2595=vc->plusExpr(id171,id453); Expr id2597=vc->eqExpr(id2595,id193); Expr id2596=vc->notExpr(id2597); vc->registerAtom(id2597); Expr id2601=vc->writeExpr(id167,id171,id161); Expr id2603=vc->eqExpr(id2601,id189); Expr id2602=vc->notExpr(id2603); vc->registerAtom(id2603); Expr id2609=vc->writeExpr(id175,id171,id165); Expr id2611=vc->eqExpr(id2609,id197); Expr id2610=vc->notExpr(id2611); vc->registerAtom(id2611); Expr id2617=vc->eqExpr(id453,id201); Expr id2616=vc->notExpr(id2617); vc->registerAtom(id2617); Expr id2619=vc->eqExpr(id89,id161); Expr id2618=vc->notExpr(id2619); vc->registerAtom(id2619); Expr id2627=vc->eqExpr(id165,id199); Expr id2626=vc->notExpr(id2627); vc->registerAtom(id2627); Expr id2631=vc->eqExpr(id181,id187); Expr id2630=vc->notExpr(id2631); vc->registerAtom(id2631); Expr id2649=vc->eqExpr(id787,id201); Expr id2648=vc->notExpr(id2649); vc->registerAtom(id2649); Expr id2651=vc->eqExpr(id1065,id161); Expr id2650=vc->notExpr(id2651); vc->registerAtom(id2651); Expr id2667=vc->writeExpr(id175,id177,id181); Expr id2669=vc->eqExpr(id2667,id197); Expr id2668=vc->notExpr(id2669); vc->registerAtom(id2669); Expr id2677=vc->eqExpr(id1093,id201); Expr id2676=vc->notExpr(id2677); vc->registerAtom(id2677); Expr id2679=vc->eqExpr(id185,id161); Expr id2678=vc->notExpr(id2679); vc->registerAtom(id2679); Expr id2695=vc->writeExpr(id175,id165,id177); Expr id2697=vc->eqExpr(id2695,id197); Expr id2696=vc->notExpr(id2697); vc->registerAtom(id2697); Expr id2705=vc->eqExpr(id1123,id201); Expr id2704=vc->notExpr(id2705); vc->registerAtom(id2705); Expr id2707=vc->leExpr(id161,id185); Expr id2706=vc->notExpr(id2707); vc->registerAtom(id2707); Expr id2727=vc->eqExpr(id161,id183); Expr id2726=vc->notExpr(id2727); vc->registerAtom(id2727); Expr id2735=vc->eqExpr(id757,id179); Expr id2734=vc->notExpr(id2735); vc->registerAtom(id2735); Expr id2737=vc->ltExpr(id139,id89); Expr id2736=vc->notExpr(id2737); vc->registerAtom(id2737); Expr id2743=vc->plusExpr(id151,id453); Expr id2745=vc->eqExpr(id2743,id173); Expr id2744=vc->notExpr(id2745); vc->registerAtom(id2745); Expr id2749=vc->eqExpr(id149,id165); Expr id2748=vc->notExpr(id2749); vc->registerAtom(id2749); Expr id2753=vc->plusExpr(id149,id453); Expr id2755=vc->eqExpr(id2753,id171); Expr id2754=vc->notExpr(id2755); vc->registerAtom(id2755); Expr id2759=vc->writeExpr(id145,id149,id139); Expr id2761=vc->eqExpr(id2759,id167); Expr id2760=vc->notExpr(id2761); vc->registerAtom(id2761); Expr id2767=vc->writeExpr(id153,id149,id143); Expr id2769=vc->eqExpr(id2767,id175); Expr id2768=vc->notExpr(id2769); vc->registerAtom(id2769); Expr id2775=vc->eqExpr(id453,id179); Expr id2774=vc->notExpr(id2775); vc->registerAtom(id2775); Expr id2777=vc->eqExpr(id89,id139); Expr id2776=vc->notExpr(id2777); vc->registerAtom(id2777); Expr id2785=vc->eqExpr(id143,id177); Expr id2784=vc->notExpr(id2785); vc->registerAtom(id2785); Expr id2789=vc->eqExpr(id159,id165); Expr id2788=vc->notExpr(id2789); vc->registerAtom(id2789); Expr id2807=vc->eqExpr(id787,id179); Expr id2806=vc->notExpr(id2807); vc->registerAtom(id2807); Expr id2809=vc->eqExpr(id1065,id139); Expr id2808=vc->notExpr(id2809); vc->registerAtom(id2809); Expr id2825=vc->writeExpr(id153,id155,id159); Expr id2827=vc->eqExpr(id2825,id175); Expr id2826=vc->notExpr(id2827); vc->registerAtom(id2827); Expr id2835=vc->eqExpr(id1093,id179); Expr id2834=vc->notExpr(id2835); vc->registerAtom(id2835); Expr id2837=vc->eqExpr(id163,id139); Expr id2836=vc->notExpr(id2837); vc->registerAtom(id2837); Expr id2853=vc->writeExpr(id153,id143,id155); Expr id2855=vc->eqExpr(id2853,id175); Expr id2854=vc->notExpr(id2855); vc->registerAtom(id2855); Expr id2863=vc->eqExpr(id1123,id179); Expr id2862=vc->notExpr(id2863); vc->registerAtom(id2863); Expr id2865=vc->leExpr(id139,id163); Expr id2864=vc->notExpr(id2865); vc->registerAtom(id2865); Expr id2885=vc->eqExpr(id139,id161); Expr id2884=vc->notExpr(id2885); vc->registerAtom(id2885); Expr id2893=vc->eqExpr(id757,id157); Expr id2892=vc->notExpr(id2893); vc->registerAtom(id2893); Expr id2895=vc->ltExpr(id117,id89); Expr id2894=vc->notExpr(id2895); vc->registerAtom(id2895); Expr id2901=vc->plusExpr(id129,id453); Expr id2903=vc->eqExpr(id2901,id151); Expr id2902=vc->notExpr(id2903); vc->registerAtom(id2903); Expr id2907=vc->eqExpr(id127,id143); Expr id2906=vc->notExpr(id2907); vc->registerAtom(id2907); Expr id2911=vc->plusExpr(id127,id453); Expr id2913=vc->eqExpr(id2911,id149); Expr id2912=vc->notExpr(id2913); vc->registerAtom(id2913); Expr id2917=vc->writeExpr(id123,id127,id117); Expr id2919=vc->eqExpr(id2917,id145); Expr id2918=vc->notExpr(id2919); vc->registerAtom(id2919); Expr id2925=vc->writeExpr(id131,id127,id121); Expr id2927=vc->eqExpr(id2925,id153); Expr id2926=vc->notExpr(id2927); vc->registerAtom(id2927); Expr id2933=vc->eqExpr(id453,id157); Expr id2932=vc->notExpr(id2933); vc->registerAtom(id2933); Expr id2935=vc->eqExpr(id89,id117); Expr id2934=vc->notExpr(id2935); vc->registerAtom(id2935); Expr id2943=vc->eqExpr(id121,id155); Expr id2942=vc->notExpr(id2943); vc->registerAtom(id2943); Expr id2947=vc->eqExpr(id137,id143); Expr id2946=vc->notExpr(id2947); vc->registerAtom(id2947); Expr id2965=vc->eqExpr(id787,id157); Expr id2964=vc->notExpr(id2965); vc->registerAtom(id2965); Expr id2967=vc->eqExpr(id1065,id117); Expr id2966=vc->notExpr(id2967); vc->registerAtom(id2967); Expr id2983=vc->writeExpr(id131,id133,id137); Expr id2985=vc->eqExpr(id2983,id153); Expr id2984=vc->notExpr(id2985); vc->registerAtom(id2985); Expr id2993=vc->eqExpr(id1093,id157); Expr id2992=vc->notExpr(id2993); vc->registerAtom(id2993); Expr id2995=vc->eqExpr(id141,id117); Expr id2994=vc->notExpr(id2995); vc->registerAtom(id2995); Expr id3011=vc->writeExpr(id131,id121,id133); Expr id3013=vc->eqExpr(id3011,id153); Expr id3012=vc->notExpr(id3013); vc->registerAtom(id3013); Expr id3021=vc->eqExpr(id1123,id157); Expr id3020=vc->notExpr(id3021); vc->registerAtom(id3021); Expr id3023=vc->leExpr(id117,id141); Expr id3022=vc->notExpr(id3023); vc->registerAtom(id3023); Expr id3043=vc->eqExpr(id117,id139); Expr id3042=vc->notExpr(id3043); vc->registerAtom(id3043); Expr id3051=vc->eqExpr(id757,id135); Expr id3050=vc->notExpr(id3051); vc->registerAtom(id3051); Expr id3053=vc->ltExpr(id87,id89); Expr id3052=vc->notExpr(id3053); vc->registerAtom(id3053); Expr id3059=vc->plusExpr(id105,id453); Expr id3061=vc->eqExpr(id3059,id129); Expr id3060=vc->notExpr(id3061); vc->registerAtom(id3061); Expr id3065=vc->eqExpr(id103,id121); Expr id3064=vc->notExpr(id3065); vc->registerAtom(id3065); Expr id3069=vc->plusExpr(id103,id453); Expr id3071=vc->eqExpr(id3069,id127); Expr id3070=vc->notExpr(id3071); vc->registerAtom(id3071); Expr id3075=vc->writeExpr(id95,id103,id87); Expr id3077=vc->eqExpr(id3075,id123); Expr id3076=vc->notExpr(id3077); vc->registerAtom(id3077); Expr id3083=vc->writeExpr(id107,id103,id93); Expr id3085=vc->eqExpr(id3083,id131); Expr id3084=vc->notExpr(id3085); vc->registerAtom(id3085); Expr id3091=vc->eqExpr(id453,id135); Expr id3090=vc->notExpr(id3091); vc->registerAtom(id3091); Expr id3093=vc->eqExpr(id89,id87); Expr id3092=vc->notExpr(id3093); vc->registerAtom(id3093); Expr id3101=vc->eqExpr(id93,id133); Expr id3100=vc->notExpr(id3101); vc->registerAtom(id3101); Expr id3105=vc->eqExpr(id115,id121); Expr id3104=vc->notExpr(id3105); vc->registerAtom(id3105); Expr id3123=vc->eqExpr(id787,id135); Expr id3122=vc->notExpr(id3123); vc->registerAtom(id3123); Expr id3125=vc->eqExpr(id1065,id87); Expr id3124=vc->notExpr(id3125); vc->registerAtom(id3125); Expr id3141=vc->writeExpr(id107,id109,id115); Expr id3143=vc->eqExpr(id3141,id131); Expr id3142=vc->notExpr(id3143); vc->registerAtom(id3143); Expr id3151=vc->eqExpr(id1093,id135); Expr id3150=vc->notExpr(id3151); vc->registerAtom(id3151); Expr id3153=vc->eqExpr(id119,id87); Expr id3152=vc->notExpr(id3153); vc->registerAtom(id3153); Expr id3169=vc->writeExpr(id107,id93,id109); Expr id3171=vc->eqExpr(id3169,id131); Expr id3170=vc->notExpr(id3171); vc->registerAtom(id3171); Expr id3179=vc->eqExpr(id1123,id135); Expr id3178=vc->notExpr(id3179); vc->registerAtom(id3179); Expr id3181=vc->leExpr(id87,id119); Expr id3180=vc->notExpr(id3181); vc->registerAtom(id3181); Expr id3201=vc->eqExpr(id87,id117); Expr id3200=vc->notExpr(id3201); vc->registerAtom(id3201); Expr id3209=vc->eqExpr(id757,id113); Expr id3208=vc->notExpr(id3209); vc->registerAtom(id3209); Expr id3211=vc->ltExpr(id75,id89); Expr id3210=vc->notExpr(id3211); vc->registerAtom(id3211); Expr id3217=vc->plusExpr(id81,id453); Expr id3219=vc->eqExpr(id3217,id105); Expr id3218=vc->notExpr(id3219); vc->registerAtom(id3219); Expr id3223=vc->eqExpr(id77,id93); Expr id3222=vc->notExpr(id3223); vc->registerAtom(id3223); Expr id3227=vc->plusExpr(id77,id453); Expr id3229=vc->eqExpr(id3227,id103); Expr id3228=vc->notExpr(id3229); vc->registerAtom(id3229); Expr id3233=vc->writeExpr(id97,id77,id75); Expr id3235=vc->eqExpr(id3233,id95); Expr id3234=vc->notExpr(id3235); vc->registerAtom(id3235); Expr id3241=vc->writeExpr(id83,id77,id79); Expr id3243=vc->eqExpr(id3241,id107); Expr id3242=vc->notExpr(id3243); vc->registerAtom(id3243); Expr id3249=vc->eqExpr(id453,id113); Expr id3248=vc->notExpr(id3249); vc->registerAtom(id3249); Expr id3251=vc->eqExpr(id89,id75); Expr id3250=vc->notExpr(id3251); vc->registerAtom(id3251); Expr id3259=vc->eqExpr(id79,id109); Expr id3258=vc->notExpr(id3259); vc->registerAtom(id3259); Expr id3263=vc->eqExpr(id85,id93); Expr id3262=vc->notExpr(id3263); vc->registerAtom(id3263); Expr id3281=vc->eqExpr(id787,id113); Expr id3280=vc->notExpr(id3281); vc->registerAtom(id3281); Expr id3283=vc->eqExpr(id1065,id75); Expr id3282=vc->notExpr(id3283); vc->registerAtom(id3283); Expr id3299=vc->writeExpr(id83,id111,id85); Expr id3301=vc->eqExpr(id3299,id107); Expr id3300=vc->notExpr(id3301); vc->registerAtom(id3301); Expr id3309=vc->eqExpr(id1093,id113); Expr id3308=vc->notExpr(id3309); vc->registerAtom(id3309); Expr id3311=vc->eqExpr(id91,id75); Expr id3310=vc->notExpr(id3311); vc->registerAtom(id3311); Expr id3327=vc->writeExpr(id83,id79,id111); Expr id3329=vc->eqExpr(id3327,id107); Expr id3328=vc->notExpr(id3329); vc->registerAtom(id3329); Expr id3337=vc->eqExpr(id1123,id113); Expr id3336=vc->notExpr(id3337); vc->registerAtom(id3337); Expr id3339=vc->leExpr(id75,id91); Expr id3338=vc->notExpr(id3339); vc->registerAtom(id3339); Expr id3359=vc->eqExpr(id75,id87); Expr id3358=vc->notExpr(id3359); vc->registerAtom(id3359); Expr id3367=vc->leExpr(id403,id757); Expr id3366=vc->notExpr(id3367); vc->registerAtom(id3367); Expr id3371=vc->eqExpr(id725,id407); Expr id3370=vc->notExpr(id3371); vc->registerAtom(id3371); Expr id3375=vc->leExpr(id381,id757); Expr id3374=vc->notExpr(id3375); vc->registerAtom(id3375); Expr id3383=vc->leExpr(id359,id757); Expr id3382=vc->notExpr(id3383); vc->registerAtom(id3383); Expr id3391=vc->leExpr(id337,id757); Expr id3390=vc->notExpr(id3391); vc->registerAtom(id3391); Expr id3399=vc->leExpr(id315,id757); Expr id3398=vc->notExpr(id3399); vc->registerAtom(id3399); Expr id3407=vc->leExpr(id293,id757); Expr id3406=vc->notExpr(id3407); vc->registerAtom(id3407); Expr id3415=vc->leExpr(id271,id757); Expr id3414=vc->notExpr(id3415); vc->registerAtom(id3415); Expr id3423=vc->leExpr(id249,id757); Expr id3422=vc->notExpr(id3423); vc->registerAtom(id3423); Expr id3431=vc->leExpr(id227,id757); Expr id3430=vc->notExpr(id3431); vc->registerAtom(id3431); Expr id3439=vc->leExpr(id205,id757); Expr id3438=vc->notExpr(id3439); vc->registerAtom(id3439); Expr id3447=vc->leExpr(id183,id757); Expr id3446=vc->notExpr(id3447); vc->registerAtom(id3447); Expr id3455=vc->leExpr(id161,id757); Expr id3454=vc->notExpr(id3455); vc->registerAtom(id3455); Expr id3463=vc->leExpr(id139,id757); Expr id3462=vc->notExpr(id3463); vc->registerAtom(id3463); Expr id3471=vc->leExpr(id117,id757); Expr id3470=vc->notExpr(id3471); vc->registerAtom(id3471); Expr id3479=vc->leExpr(id87,id757); Expr id3478=vc->notExpr(id3479); vc->registerAtom(id3479); Expr id3487=vc->leExpr(id75,id757); Expr id3486=vc->notExpr(id3487); vc->registerAtom(id3487); vc->push(); vc->query(id12); vc->inconsistent(inconsistency); vc->pop(); vc->push(); vc->query(id986); vc->popto(1); vc->push(); vc->query(id987); vc->popto(1); vc->push(); vc->assertFormula(id987); vc->getImpliedLiteral(); vc->getImpliedLiteral(); vc->push(); vc->query(id982); vc->popto(2); vc->push(); vc->query(id983); vc->popto(2); vc->push(); vc->assertFormula(id983); vc->getImpliedLiteral(); vc->getImpliedLiteral(); vc->push(); vc->query(id978); vc->popto(3); vc->push(); vc->query(id979); vc->popto(3); vc->push(); vc->assertFormula(id979); vc->getImpliedLiteral(); vc->getImpliedLiteral(); vc->push(); vc->query(id972); vc->popto(4); vc->push(); vc->query(id973); vc->popto(4); vc->push(); vc->assertFormula(id973); vc->getImpliedLiteral(); vc->getImpliedLiteral(); vc->push(); vc->query(id968); vc->popto(5); vc->push(); vc->query(id969); vc->popto(5); vc->push(); vc->assertFormula(id969); vc->getImpliedLiteral(); vc->getImpliedLiteral(); vc->push(); vc->query(id964); vc->popto(6); vc->push(); vc->query(id965); vc->popto(6); vc->push(); vc->assertFormula(id965); vc->getImpliedLiteral(); vc->getImpliedLiteral(); vc->push(); vc->query(id958); vc->popto(7); vc->push(); vc->query(id959); vc->popto(7); vc->push(); vc->assertFormula(id959); vc->getImpliedLiteral(); vc->getImpliedLiteral(); vc->push(); vc->query(id954); vc->popto(8); vc->push(); vc->query(id955); vc->popto(8); vc->push(); vc->assertFormula(id955); vc->getImpliedLiteral(); vc->getImpliedLiteral(); vc->push(); vc->query(id950); vc->popto(9); vc->push(); vc->query(id951); vc->popto(9); vc->push(); vc->assertFormula(id951); vc->getImpliedLiteral(); vc->getImpliedLiteral(); vc->push(); vc->query(id944); vc->popto(10); vc->push(); vc->query(id945); vc->popto(10); vc->push(); vc->assertFormula(id945); vc->getImpliedLiteral(); vc->getImpliedLiteral(); vc->push(); vc->query(id940); vc->popto(11); vc->push(); vc->query(id941); vc->popto(11); vc->push(); vc->assertFormula(id941); vc->getImpliedLiteral(); vc->getImpliedLiteral(); vc->push(); vc->query(id936); vc->popto(12); vc->push(); vc->query(id937); vc->popto(12); vc->push(); vc->assertFormula(id937); vc->getImpliedLiteral(); vc->getImpliedLiteral(); vc->push(); vc->query(id930); vc->popto(13); vc->push(); vc->query(id931); vc->popto(13); vc->push(); vc->assertFormula(id931); vc->getImpliedLiteral(); vc->getImpliedLiteral(); vc->push(); vc->query(id926); vc->popto(14); vc->push(); vc->query(id927); vc->popto(14); vc->push(); vc->assertFormula(id927); vc->getImpliedLiteral(); vc->getImpliedLiteral(); vc->push(); vc->query(id922); vc->popto(15); vc->push(); vc->query(id923); vc->popto(15); vc->push(); vc->assertFormula(id923); vc->getImpliedLiteral(); vc->getImpliedLiteral(); vc->push(); vc->query(id916); vc->popto(16); vc->push(); vc->query(id917); vc->popto(16); vc->push(); vc->assertFormula(id917); vc->getImpliedLiteral(); vc->getImpliedLiteral(); vc->push(); vc->query(id912); vc->popto(17); vc->push(); vc->query(id913); vc->popto(17); vc->push(); vc->assertFormula(id913); vc->getImpliedLiteral(); vc->getImpliedLiteral(); vc->push(); vc->query(id908); vc->popto(18); vc->push(); vc->query(id909); vc->popto(18); vc->push(); vc->assertFormula(id909); vc->getImpliedLiteral(); vc->getImpliedLiteral(); vc->push(); vc->query(id902); vc->popto(19); vc->push(); vc->query(id903); vc->popto(19); vc->push(); vc->assertFormula(id903); vc->getImpliedLiteral(); vc->getImpliedLiteral(); vc->push(); vc->query(id898); vc->popto(20); vc->push(); vc->query(id899); vc->popto(20); vc->push(); vc->assertFormula(id899); vc->getImpliedLiteral(); vc->getImpliedLiteral(); vc->push(); vc->query(id894); vc->popto(21); vc->push(); vc->query(id895); vc->popto(21); vc->push(); vc->assertFormula(id895); vc->getImpliedLiteral(); vc->getImpliedLiteral(); vc->push(); vc->query(id888); vc->popto(22); vc->push(); vc->query(id889); vc->popto(22); vc->push(); vc->assertFormula(id889); vc->getImpliedLiteral(); vc->getImpliedLiteral(); vc->push(); vc->query(id884); vc->popto(23); vc->push(); vc->query(id885); vc->popto(23); vc->push(); vc->assertFormula(id885); vc->getImpliedLiteral(); vc->getImpliedLiteral(); vc->push(); vc->query(id880); vc->popto(24); vc->push(); vc->query(id881); vc->popto(24); vc->push(); vc->assertFormula(id881); vc->getImpliedLiteral(); vc->getImpliedLiteral(); vc->push(); vc->query(id874); vc->popto(25); vc->push(); vc->query(id875); vc->popto(25); vc->push(); vc->assertFormula(id875); vc->getImpliedLiteral(); vc->getImpliedLiteral(); vc->push(); vc->query(id870); vc->popto(26); vc->push(); vc->query(id871); vc->popto(26); vc->push(); vc->assertFormula(id871); vc->getImpliedLiteral(); vc->getImpliedLiteral(); vc->push(); vc->query(id866); vc->popto(27); vc->push(); vc->query(id867); vc->popto(27); vc->push(); vc->assertFormula(id867); vc->getImpliedLiteral(); vc->getImpliedLiteral(); vc->push(); vc->query(id860); vc->popto(28); vc->push(); vc->query(id861); vc->popto(28); vc->push(); vc->assertFormula(id861); vc->getImpliedLiteral(); vc->getImpliedLiteral(); vc->push(); vc->query(id856); vc->popto(29); vc->push(); vc->query(id857); vc->popto(29); vc->push(); vc->assertFormula(id857); vc->getImpliedLiteral(); vc->getImpliedLiteral(); vc->push(); vc->query(id852); vc->popto(30); vc->push(); vc->query(id853); vc->popto(30); vc->push(); vc->assertFormula(id853); vc->getImpliedLiteral(); vc->getImpliedLiteral(); vc->push(); vc->query(id846); vc->popto(31); vc->push(); vc->query(id847); vc->popto(31); vc->push(); vc->assertFormula(id847); vc->getImpliedLiteral(); vc->getImpliedLiteral(); vc->push(); vc->query(id842); vc->popto(32); vc->push(); vc->query(id843); vc->popto(32); vc->push(); vc->assertFormula(id843); vc->getImpliedLiteral(); vc->getImpliedLiteral(); vc->push(); vc->query(id838); vc->popto(33); vc->push(); vc->query(id839); vc->popto(33); vc->push(); vc->assertFormula(id839); vc->getImpliedLiteral(); vc->getImpliedLiteral(); vc->push(); vc->query(id832); vc->popto(34); vc->push(); vc->query(id833); vc->popto(34); vc->push(); vc->assertFormula(id833); vc->getImpliedLiteral(); vc->getImpliedLiteral(); vc->push(); vc->query(id828); vc->popto(35); vc->push(); vc->query(id829); vc->popto(35); vc->push(); vc->assertFormula(id829); vc->getImpliedLiteral(); vc->getImpliedLiteral(); vc->push(); vc->query(id824); vc->popto(36); vc->push(); vc->query(id825); vc->popto(36); vc->push(); vc->assertFormula(id825); vc->getImpliedLiteral(); vc->getImpliedLiteral(); vc->push(); vc->query(id818); vc->popto(37); vc->push(); vc->query(id819); vc->popto(37); vc->push(); vc->assertFormula(id819); vc->getImpliedLiteral(); vc->getImpliedLiteral(); vc->push(); vc->query(id814); vc->popto(38); vc->push(); vc->query(id815); vc->popto(38); vc->push(); vc->assertFormula(id815); vc->getImpliedLiteral(); vc->getImpliedLiteral(); vc->push(); vc->query(id810); vc->popto(39); vc->push(); vc->query(id811); vc->popto(39); vc->push(); vc->assertFormula(id811); vc->getImpliedLiteral(); vc->getImpliedLiteral(); vc->push(); vc->query(id804); vc->popto(40); vc->push(); vc->query(id805); vc->popto(40); vc->push(); vc->assertFormula(id805); vc->getImpliedLiteral(); vc->getImpliedLiteral(); vc->push(); vc->query(id800); vc->popto(41); vc->push(); vc->query(id801); vc->popto(41); vc->push(); vc->assertFormula(id801); vc->getImpliedLiteral(); vc->getImpliedLiteral(); vc->push(); vc->query(id796); vc->popto(42); vc->push(); vc->query(id797); vc->popto(42); vc->push(); vc->assertFormula(id797); vc->getImpliedLiteral(); vc->getImpliedLiteral(); vc->push(); vc->query(id790); vc->popto(43); vc->push(); vc->query(id791); vc->popto(43); vc->push(); vc->assertFormula(id791); vc->getImpliedLiteral(); vc->getImpliedLiteral(); vc->push(); vc->query(id782); vc->popto(44); vc->push(); vc->query(id783); vc->popto(44); vc->push(); vc->assertFormula(id783); vc->getImpliedLiteral(); vc->getImpliedLiteral(); vc->push(); vc->query(id778); vc->popto(45); vc->push(); vc->query(id779); vc->popto(45); vc->push(); vc->assertFormula(id779); vc->getImpliedLiteral(); vc->getImpliedLiteral(); vc->push(); vc->query(id772); vc->popto(46); vc->push(); vc->query(id773); vc->popto(46); vc->push(); vc->assertFormula(id773); vc->getImpliedLiteral(); vc->getImpliedLiteral(); vc->push(); vc->query(id726); vc->popto(47); vc->push(); vc->query(id727); vc->popto(47); vc->push(); vc->assertFormula(id727); vc->getImpliedLiteral(); vc->getImpliedLiteral(); vc->push(); vc->query(id766); vc->popto(48); vc->push(); vc->query(id767); vc->popto(48); vc->push(); vc->assertFormula(id767); vc->getImpliedLiteral(); vc->getImpliedLiteral(); vc->push(); vc->query(id762); vc->popto(49); vc->push(); vc->query(id763); vc->popto(49); vc->push(); vc->assertFormula(id763); vc->getImpliedLiteral(); vc->getImpliedLiteral(); vc->getImpliedLiteral(); vc->push(); vc->query(id759); vc->popto(50); vc->push(); vc->query(id758); vc->popto(50); vc->push(); vc->assertFormula(id758); vc->getImpliedLiteral(); vc->getImpliedLiteral(); vc->push(); vc->query(id3486); vc->popto(51); vc->push(); vc->query(id3487); vc->popto(51); vc->push(); vc->query(id3210); vc->popto(51); vc->push(); vc->query(id3211); vc->popto(51); vc->push(); vc->query(id463); vc->popto(51); vc->push(); vc->query(id462); vc->popto(51); vc->push(); vc->query(id462); vc->popto(51); vc->push(); vc->query(id463); vc->popto(51); vc->push(); vc->assertFormula(id463); vc->getImpliedLiteral(); vc->getImpliedLiteral(); vc->push(); vc->query(id481); vc->popto(52); vc->push(); vc->query(id480); vc->popto(52); vc->push(); vc->query(id480); vc->popto(52); vc->push(); vc->query(id481); vc->popto(52); vc->push(); vc->assertFormula(id481); vc->getImpliedLiteral(); vc->getImpliedLiteral(); vc->push(); vc->query(id499); vc->popto(53); vc->push(); vc->query(id498); vc->popto(53); vc->push(); vc->query(id498); vc->popto(53); vc->push(); vc->query(id499); vc->popto(53); vc->push(); vc->assertFormula(id499); vc->getImpliedLiteral(); vc->getImpliedLiteral(); vc->push(); vc->query(id517); vc->popto(54); vc->push(); vc->query(id516); vc->popto(54); vc->push(); vc->query(id516); vc->popto(54); vc->push(); vc->query(id517); vc->popto(54); vc->push(); vc->assertFormula(id517); vc->getImpliedLiteral(); vc->getImpliedLiteral(); vc->push(); vc->query(id535); vc->popto(55); vc->push(); vc->query(id534); vc->popto(55); vc->push(); vc->query(id534); vc->popto(55); vc->push(); vc->query(id535); vc->popto(55); vc->push(); vc->assertFormula(id535); vc->getImpliedLiteral(); vc->getImpliedLiteral(); vc->push(); vc->query(id553); vc->popto(56); vc->push(); vc->query(id552); vc->popto(56); vc->push(); vc->query(id552); vc->popto(56); vc->push(); vc->query(id553); vc->popto(56); vc->push(); vc->assertFormula(id553); vc->getImpliedLiteral(); vc->getImpliedLiteral(); vc->push(); vc->query(id571); vc->popto(57); vc->push(); vc->query(id570); vc->popto(57); vc->push(); vc->query(id570); vc->popto(57); vc->push(); vc->query(id571); vc->popto(57); vc->push(); vc->assertFormula(id571); vc->getImpliedLiteral(); vc->getImpliedLiteral(); vc->push(); vc->query(id589); vc->popto(58); vc->push(); vc->query(id588); vc->popto(58); vc->push(); vc->query(id588); vc->popto(58); vc->push(); vc->query(id589); vc->popto(58); vc->push(); vc->assertFormula(id589); vc->getImpliedLiteral(); vc->getImpliedLiteral(); vc->push(); vc->query(id607); vc->popto(59); vc->push(); vc->query(id606); vc->popto(59); vc->push(); vc->query(id606); vc->popto(59); vc->push(); vc->query(id607); vc->popto(59); vc->push(); vc->assertFormula(id607); vc->getImpliedLiteral(); vc->getImpliedLiteral(); vc->push(); vc->query(id625); vc->popto(60); vc->push(); vc->query(id624); vc->popto(60); vc->push(); vc->query(id624); vc->popto(60); vc->push(); vc->query(id625); vc->popto(60); vc->push(); vc->assertFormula(id625); vc->getImpliedLiteral(); vc->getImpliedLiteral(); vc->push(); vc->query(id643); vc->popto(61); vc->push(); vc->query(id642); vc->popto(61); vc->push(); vc->query(id642); vc->popto(61); vc->push(); vc->query(id643); vc->popto(61); vc->push(); vc->assertFormula(id643); vc->getImpliedLiteral(); vc->getImpliedLiteral(); vc->push(); vc->query(id661); vc->popto(62); vc->push(); vc->query(id660); vc->popto(62); vc->push(); vc->query(id660); vc->popto(62); vc->push(); vc->query(id661); vc->popto(62); vc->push(); vc->assertFormula(id661); vc->getImpliedLiteral(); vc->getImpliedLiteral(); vc->push(); vc->query(id679); vc->popto(63); vc->push(); vc->query(id678); vc->popto(63); vc->push(); vc->query(id678); vc->popto(63); vc->push(); vc->query(id679); vc->popto(63); vc->push(); vc->assertFormula(id679); vc->getImpliedLiteral(); vc->getImpliedLiteral(); vc->push(); vc->query(id697); vc->popto(64); vc->push(); vc->query(id696); vc->popto(64); vc->push(); vc->query(id696); vc->popto(64); vc->push(); vc->query(id697); vc->popto(64); vc->push(); vc->assertFormula(id697); vc->getImpliedLiteral(); vc->getImpliedLiteral(); vc->push(); vc->query(id715); vc->popto(65); vc->push(); vc->query(id714); vc->popto(65); vc->push(); vc->query(id714); vc->popto(65); vc->push(); vc->query(id715); vc->popto(65); vc->push(); vc->assertFormula(id715); vc->getImpliedLiteral(); vc->getImpliedLiteral(); vc->push(); vc->query(id471); vc->popto(66); vc->push(); vc->query(id470); vc->popto(66); vc->push(); vc->query(id470); vc->popto(66); vc->push(); vc->query(id471); vc->popto(66); vc->push(); vc->assertFormula(id471); vc->getImpliedLiteral(); vc->getImpliedLiteral(); vc->push(); vc->query(id489); vc->popto(67); vc->push(); vc->query(id488); vc->popto(67); vc->push(); vc->query(id488); vc->popto(67); vc->push(); vc->query(id489); vc->popto(67); vc->push(); vc->assertFormula(id489); vc->getImpliedLiteral(); vc->getImpliedLiteral(); vc->push(); vc->query(id467); vc->popto(68); vc->push(); vc->query(id466); vc->popto(68); vc->push(); vc->query(id466); vc->popto(68); vc->push(); vc->query(id467); vc->popto(68); vc->push(); vc->assertFormula(id467); vc->getImpliedLiteral(); vc->getImpliedLiteral(); vc->getImpliedLiteral(); vc->push(); vc->query(id3219); vc->popto(69); vc->push(); vc->query(id3218); vc->popto(69); vc->push(); vc->query(id507); vc->popto(69); vc->push(); vc->query(id506); vc->popto(69); vc->push(); vc->query(id506); vc->popto(69); vc->push(); vc->query(id507); vc->popto(69); vc->push(); vc->assertFormula(id507); vc->getImpliedLiteral(); vc->getImpliedLiteral(); vc->push(); vc->query(id485); vc->popto(70); vc->push(); vc->query(id484); vc->popto(70); vc->push(); vc->query(id484); vc->popto(70); vc->push(); vc->query(id485); vc->popto(70); vc->push(); vc->assertFormula(id485); vc->getImpliedLiteral(); vc->getImpliedLiteral(); vc->getImpliedLiteral(); vc->push(); vc->query(id3061); vc->popto(71); vc->push(); vc->query(id3060); vc->popto(71); vc->push(); vc->query(id465); vc->popto(71); vc->push(); vc->query(id464); vc->popto(71); vc->push(); vc->query(id464); vc->popto(71); vc->push(); vc->query(id465); vc->popto(71); vc->push(); vc->assertFormula(id465); vc->getImpliedLiteral(); vc->getImpliedLiteral(); vc->getImpliedLiteral(); vc->push(); vc->query(id3229); vc->popto(72); vc->push(); vc->query(id3228); vc->popto(72); vc->push(); vc->query(id525); vc->popto(72); vc->push(); vc->query(id524); vc->popto(72); vc->push(); vc->query(id524); vc->popto(72); vc->push(); vc->query(id525); vc->popto(72); vc->push(); vc->assertFormula(id525); vc->getImpliedLiteral(); vc->getImpliedLiteral(); vc->push(); vc->query(id503); vc->popto(73); vc->push(); vc->query(id502); vc->popto(73); vc->push(); vc->query(id502); vc->popto(73); vc->push(); vc->query(id503); vc->popto(73); vc->push(); vc->assertFormula(id503); vc->getImpliedLiteral(); vc->getImpliedLiteral(); vc->getImpliedLiteral(); vc->push(); vc->query(id2903); vc->popto(74); vc->push(); vc->query(id2902); vc->popto(74); vc->push(); vc->query(id483); vc->popto(74); vc->push(); vc->query(id482); vc->popto(74); vc->push(); vc->query(id482); vc->popto(74); vc->push(); vc->query(id483); vc->popto(74); vc->push(); vc->assertFormula(id483); vc->getImpliedLiteral(); vc->getImpliedLiteral(); vc->getImpliedLiteral(); vc->push(); vc->query(id3071); vc->popto(75); vc->push(); vc->query(id3070); vc->popto(75); vc->push(); vc->query(id543); vc->popto(75); vc->push(); vc->query(id542); vc->popto(75); vc->push(); vc->query(id542); vc->popto(75); vc->push(); vc->query(id543); vc->popto(75); vc->push(); vc->assertFormula(id543); vc->getImpliedLiteral(); vc->getImpliedLiteral(); vc->push(); vc->query(id521); vc->popto(76); vc->push(); vc->query(id520); vc->popto(76); vc->push(); vc->query(id520); vc->popto(76); vc->push(); vc->query(id521); vc->popto(76); vc->push(); vc->assertFormula(id521); vc->getImpliedLiteral(); vc->getImpliedLiteral(); vc->getImpliedLiteral(); vc->push(); vc->query(id2745); vc->popto(77); vc->push(); vc->query(id2744); vc->popto(77); vc->push(); vc->query(id501); vc->popto(77); vc->push(); vc->query(id500); vc->popto(77); vc->push(); vc->query(id500); vc->popto(77); vc->push(); vc->query(id501); vc->popto(77); vc->push(); vc->assertFormula(id501); vc->getImpliedLiteral(); vc->getImpliedLiteral(); vc->getImpliedLiteral(); vc->push(); vc->query(id2913); vc->popto(78); vc->push(); vc->query(id2912); vc->popto(78); vc->push(); vc->query(id461); vc->popto(78); vc->push(); vc->query(id460); vc->popto(78); vc->push(); vc->query(id460); vc->popto(78); vc->push(); vc->query(id461); vc->popto(78); vc->push(); vc->assertFormula(id461); vc->getImpliedLiteral(); vc->getImpliedLiteral(); vc->push(); vc->query(id561); vc->popto(79); vc->push(); vc->query(id560); vc->popto(79); vc->push(); vc->query(id560); vc->popto(79); vc->push(); vc->query(id561); vc->popto(79); vc->push(); vc->assertFormula(id561); vc->getImpliedLiteral(); vc->getImpliedLiteral(); vc->push(); vc->query(id539); vc->popto(80); vc->push(); vc->query(id538); vc->popto(80); vc->push(); vc->query(id538); vc->popto(80); vc->push(); vc->query(id539); vc->popto(80); vc->push(); vc->assertFormula(id539); vc->getImpliedLiteral(); vc->getImpliedLiteral(); vc->getImpliedLiteral(); vc->push(); vc->query(id2587); vc->popto(81); vc->push(); vc->query(id2586); vc->popto(81); vc->push(); vc->query(id519); vc->popto(81); vc->push(); vc->query(id518); vc->popto(81); vc->push(); vc->query(id518); vc->popto(81); vc->push(); vc->query(id519); vc->popto(81); vc->push(); vc->assertFormula(id519); vc->getImpliedLiteral(); vc->getImpliedLiteral(); vc->getImpliedLiteral(); vc->push(); vc->query(id2755); vc->popto(82); vc->push(); vc->query(id2754); vc->popto(82); vc->push(); vc->query(id479); vc->popto(82); vc->push(); vc->query(id478); vc->popto(82); vc->push(); vc->query(id478); vc->popto(82); vc->push(); vc->query(id479); vc->popto(82); vc->push(); vc->assertFormula(id479); vc->getImpliedLiteral(); vc->getImpliedLiteral(); vc->push(); vc->query(id579); vc->popto(83); vc->push(); vc->query(id578); vc->popto(83); vc->push(); vc->query(id578); vc->popto(83); vc->push(); vc->query(id579); vc->popto(83); vc->push(); vc->assertFormula(id579); vc->getImpliedLiteral(); vc->getImpliedLiteral(); vc->push(); vc->query(id557); vc->popto(84); vc->push(); vc->query(id556); vc->popto(84); vc->push(); vc->query(id556); vc->popto(84); vc->push(); vc->query(id557); vc->popto(84); vc->push(); vc->assertFormula(id557); vc->getImpliedLiteral(); vc->getImpliedLiteral(); vc->getImpliedLiteral(); vc->push(); vc->query(id2429); vc->popto(85); vc->push(); vc->query(id2428); vc->popto(85); vc->push(); vc->query(id537); vc->popto(85); vc->push(); vc->query(id536); vc->popto(85); vc->push(); vc->query(id536); vc->popto(85); vc->push(); vc->query(id537); vc->popto(85); vc->push(); vc->assertFormula(id537); vc->getImpliedLiteral(); vc->getImpliedLiteral(); vc->getImpliedLiteral(); vc->push(); vc->query(id2597); vc->popto(86); vc->push(); vc->query(id2596); vc->popto(86); vc->push(); vc->query(id497); vc->popto(86); vc->push(); vc->query(id496); vc->popto(86); vc->push(); vc->query(id496); vc->popto(86); vc->push(); vc->query(id497); vc->popto(86); vc->push(); vc->assertFormula(id497); vc->getImpliedLiteral(); vc->getImpliedLiteral(); vc->push(); vc->query(id597); vc->popto(87); vc->push(); vc->query(id596); vc->popto(87); vc->push(); vc->query(id596); vc->popto(87); vc->push(); vc->query(id597); vc->popto(87); vc->push(); vc->assertFormula(id597); vc->getImpliedLiteral(); vc->getImpliedLiteral(); vc->push(); vc->query(id575); vc->popto(88); vc->push(); vc->query(id574); vc->popto(88); vc->push(); vc->query(id574); vc->popto(88); vc->push(); vc->query(id575); vc->popto(88); vc->push(); vc->assertFormula(id575); vc->getImpliedLiteral(); vc->getImpliedLiteral(); vc->getImpliedLiteral(); vc->push(); vc->query(id2271); vc->popto(89); vc->push(); vc->query(id2270); vc->popto(89); vc->push(); vc->query(id555); vc->popto(89); vc->push(); vc->query(id554); vc->popto(89); vc->push(); vc->query(id554); vc->popto(89); vc->push(); vc->query(id555); vc->popto(89); vc->push(); vc->assertFormula(id555); vc->getImpliedLiteral(); vc->getImpliedLiteral(); vc->getImpliedLiteral(); vc->push(); vc->query(id2439); vc->popto(90); vc->push(); vc->query(id2438); vc->popto(90); vc->push(); vc->query(id515); vc->popto(90); vc->push(); vc->query(id514); vc->popto(90); vc->push(); vc->query(id514); vc->popto(90); vc->push(); vc->query(id515); vc->popto(90); vc->push(); vc->assertFormula(id515); vc->getImpliedLiteral(); vc->getImpliedLiteral(); vc->push(); vc->query(id457); vc->popto(91); vc->push(); vc->query(id456); vc->popto(91); vc->push(); vc->query(id456); vc->popto(91); vc->push(); vc->query(id457); vc->popto(91); vc->push(); vc->assertFormula(id457); vc->getImpliedLiteral(); vc->getImpliedLiteral(); vc->getImpliedLiteral(); vc->getImpliedLiteral(); vc->push(); vc->query(id3479); vc->popto(92); vc->push(); vc->query(id3478); vc->popto(92); vc->push(); vc->query(id3359); vc->popto(92); vc->push(); vc->query(id3358); vc->popto(92); vc->push(); vc->query(id615); vc->popto(92); vc->push(); vc->query(id614); vc->popto(92); vc->push(); vc->query(id614); vc->popto(92); vc->push(); vc->query(id615); vc->popto(92); vc->push(); vc->assertFormula(id615); vc->getImpliedLiteral(); vc->getImpliedLiteral(); vc->push(); vc->query(id593); vc->popto(93); vc->push(); vc->query(id592); vc->popto(93); vc->push(); vc->query(id592); vc->popto(93); vc->push(); vc->query(id593); vc->popto(93); vc->push(); vc->assertFormula(id593); vc->getImpliedLiteral(); vc->getImpliedLiteral(); vc->getImpliedLiteral(); vc->push(); vc->query(id2113); vc->popto(94); vc->push(); vc->query(id2112); vc->popto(94); vc->push(); vc->query(id573); vc->popto(94); vc->push(); vc->query(id572); vc->popto(94); vc->push(); vc->query(id572); vc->popto(94); vc->push(); vc->query(id573); vc->popto(94); vc->push(); vc->assertFormula(id573); vc->getImpliedLiteral(); vc->getImpliedLiteral(); vc->getImpliedLiteral(); vc->push(); vc->query(id2281); vc->popto(95); vc->push(); vc->query(id2280); vc->popto(95); vc->push(); vc->query(id533); vc->popto(95); vc->push(); vc->query(id532); vc->popto(95); vc->push(); vc->query(id532); vc->popto(95); vc->push(); vc->query(id533); vc->popto(95); vc->push(); vc->assertFormula(id533); vc->getImpliedLiteral(); vc->getImpliedLiteral(); vc->push(); vc->query(id475); vc->popto(96); vc->push(); vc->query(id474); vc->popto(96); vc->push(); vc->query(id474); vc->popto(96); vc->push(); vc->query(id475); vc->popto(96); vc->push(); vc->assertFormula(id475); vc->getImpliedLiteral(); vc->getImpliedLiteral(); vc->getImpliedLiteral(); vc->getImpliedLiteral(); vc->push(); vc->query(id3471); vc->popto(97); vc->push(); vc->query(id3470); vc->popto(97); vc->push(); vc->query(id3201); vc->popto(97); vc->push(); vc->query(id3200); vc->popto(97); vc->push(); vc->query(id633); vc->popto(97); vc->push(); vc->query(id632); vc->popto(97); vc->push(); vc->query(id632); vc->popto(97); vc->push(); vc->query(id633); vc->popto(97); vc->push(); vc->assertFormula(id633); vc->getImpliedLiteral(); vc->getImpliedLiteral(); vc->push(); vc->query(id611); vc->popto(98); vc->push(); vc->query(id610); vc->popto(98); vc->push(); vc->query(id610); vc->popto(98); vc->push(); vc->query(id611); vc->popto(98); vc->push(); vc->assertFormula(id611); vc->getImpliedLiteral(); vc->getImpliedLiteral(); vc->getImpliedLiteral(); vc->push(); vc->query(id1955); vc->popto(99); vc->push(); vc->query(id1954); vc->popto(99); vc->push(); vc->query(id591); vc->popto(99); vc->push(); vc->query(id590); vc->popto(99); vc->push(); vc->query(id590); vc->popto(99); vc->push(); vc->query(id591); vc->popto(99); vc->push(); vc->assertFormula(id591); vc->getImpliedLiteral(); vc->getImpliedLiteral(); vc->getImpliedLiteral(); vc->push(); vc->query(id2123); vc->popto(100); vc->push(); vc->query(id2122); vc->popto(100); vc->push(); vc->query(id551); vc->popto(100); vc->push(); vc->query(id550); vc->popto(100); vc->push(); vc->query(id550); vc->popto(100); vc->push(); vc->query(id551); vc->popto(100); vc->push(); vc->assertFormula(id551); vc->getImpliedLiteral(); vc->getImpliedLiteral(); vc->push(); vc->query(id493); vc->popto(101); vc->push(); vc->query(id492); vc->popto(101); vc->push(); vc->query(id492); vc->popto(101); vc->push(); vc->query(id493); vc->popto(101); vc->push(); vc->assertFormula(id493); vc->getImpliedLiteral(); vc->getImpliedLiteral(); vc->getImpliedLiteral(); vc->getImpliedLiteral(); vc->push(); vc->query(id3463); vc->popto(102); vc->push(); vc->query(id3462); vc->popto(102); vc->push(); vc->query(id3043); vc->popto(102); vc->push(); vc->query(id3042); vc->popto(102); vc->push(); vc->query(id651); vc->popto(102); vc->push(); vc->query(id650); vc->popto(102); vc->push(); vc->query(id650); vc->popto(102); vc->push(); vc->query(id651); vc->popto(102); vc->push(); vc->assertFormula(id651); vc->getImpliedLiteral(); vc->getImpliedLiteral(); vc->push(); vc->query(id629); vc->popto(103); vc->push(); vc->query(id628); vc->popto(103); vc->push(); vc->query(id628); vc->popto(103); vc->push(); vc->query(id629); vc->popto(103); vc->push(); vc->assertFormula(id629); vc->getImpliedLiteral(); vc->getImpliedLiteral(); vc->getImpliedLiteral(); vc->push(); vc->query(id1797); vc->popto(104); vc->push(); vc->query(id1796); vc->popto(104); vc->push(); vc->query(id609); vc->popto(104); vc->push(); vc->query(id608); vc->popto(104); vc->push(); vc->query(id608); vc->popto(104); vc->push(); vc->query(id609); vc->popto(104); vc->push(); vc->assertFormula(id609); vc->getImpliedLiteral(); vc->getImpliedLiteral(); vc->getImpliedLiteral(); vc->push(); vc->query(id1965); vc->popto(105); vc->push(); vc->query(id1964); vc->popto(105); vc->push(); vc->query(id569); vc->popto(105); vc->push(); vc->query(id568); vc->popto(105); vc->push(); vc->query(id568); vc->popto(105); vc->push(); vc->query(id569); vc->popto(105); vc->push(); vc->assertFormula(id569); vc->getImpliedLiteral(); vc->getImpliedLiteral(); vc->push(); vc->query(id511); vc->popto(106); vc->push(); vc->query(id510); vc->popto(106); vc->push(); vc->query(id510); vc->popto(106); vc->push(); vc->query(id511); vc->popto(106); vc->push(); vc->assertFormula(id511); vc->getImpliedLiteral(); vc->getImpliedLiteral(); vc->getImpliedLiteral(); vc->getImpliedLiteral(); vc->push(); vc->query(id3455); vc->popto(107); vc->push(); vc->query(id3454); vc->popto(107); vc->push(); vc->query(id2885); vc->popto(107); vc->push(); vc->query(id2884); vc->popto(107); vc->push(); vc->query(id669); vc->popto(107); vc->push(); vc->query(id668); vc->popto(107); vc->push(); vc->query(id668); vc->popto(107); vc->push(); vc->query(id669); vc->popto(107); vc->push(); vc->assertFormula(id669); vc->getImpliedLiteral(); vc->getImpliedLiteral(); vc->push(); vc->query(id647); vc->popto(108); vc->push(); vc->query(id646); vc->popto(108); vc->push(); vc->query(id646); vc->popto(108); vc->push(); vc->query(id647); vc->popto(108); vc->push(); vc->assertFormula(id647); vc->getImpliedLiteral(); vc->getImpliedLiteral(); vc->getImpliedLiteral(); vc->push(); vc->query(id1639); vc->popto(109); vc->push(); vc->query(id1638); vc->popto(109); vc->push(); vc->query(id627); vc->popto(109); vc->push(); vc->query(id626); vc->popto(109); vc->push(); vc->query(id626); vc->popto(109); vc->push(); vc->query(id627); vc->popto(109); vc->push(); vc->assertFormula(id627); vc->getImpliedLiteral(); vc->getImpliedLiteral(); vc->getImpliedLiteral(); vc->push(); vc->query(id1807); vc->popto(110); vc->push(); vc->query(id1806); vc->popto(110); vc->push(); vc->query(id587); vc->popto(110); vc->push(); vc->query(id586); vc->popto(110); vc->push(); vc->query(id586); vc->popto(110); vc->push(); vc->query(id587); vc->popto(110); vc->push(); vc->assertFormula(id587); vc->getImpliedLiteral(); vc->getImpliedLiteral(); vc->push(); vc->query(id529); vc->popto(111); vc->push(); vc->query(id528); vc->popto(111); vc->push(); vc->query(id528); vc->popto(111); vc->push(); vc->query(id529); vc->popto(111); vc->push(); vc->assertFormula(id529); vc->getImpliedLiteral(); vc->getImpliedLiteral(); vc->getImpliedLiteral(); vc->getImpliedLiteral(); vc->push(); vc->query(id3447); vc->popto(112); vc->push(); vc->query(id3446); vc->popto(112); vc->push(); vc->query(id2727); vc->popto(112); vc->push(); vc->query(id2726); vc->popto(112); vc->push(); vc->query(id687); vc->popto(112); vc->push(); vc->query(id686); vc->popto(112); vc->push(); vc->query(id686); vc->popto(112); vc->push(); vc->query(id687); vc->popto(112); vc->push(); vc->assertFormula(id687); vc->getImpliedLiteral(); vc->getImpliedLiteral(); vc->push(); vc->query(id665); vc->popto(113); vc->push(); vc->query(id664); vc->popto(113); vc->push(); vc->query(id664); vc->popto(113); vc->push(); vc->query(id665); vc->popto(113); vc->push(); vc->assertFormula(id665); vc->getImpliedLiteral(); vc->getImpliedLiteral(); vc->getImpliedLiteral(); vc->push(); vc->query(id1481); vc->popto(114); vc->push(); vc->query(id1480); vc->popto(114); vc->push(); vc->query(id645); vc->popto(114); vc->push(); vc->query(id644); vc->popto(114); vc->push(); vc->query(id644); vc->popto(114); vc->push(); vc->query(id645); vc->popto(114); vc->push(); vc->assertFormula(id645); vc->getImpliedLiteral(); vc->getImpliedLiteral(); vc->getImpliedLiteral(); vc->push(); vc->query(id1649); vc->popto(115); vc->push(); vc->query(id1648); vc->popto(115); vc->push(); vc->query(id605); vc->popto(115); vc->push(); vc->query(id604); vc->popto(115); vc->push(); vc->query(id604); vc->popto(115); vc->push(); vc->query(id605); vc->popto(115); vc->push(); vc->assertFormula(id605); vc->getImpliedLiteral(); vc->getImpliedLiteral(); vc->push(); vc->query(id547); vc->popto(116); vc->push(); vc->query(id546); vc->popto(116); vc->push(); vc->query(id546); vc->popto(116); vc->push(); vc->query(id547); vc->popto(116); vc->push(); vc->assertFormula(id547); vc->getImpliedLiteral(); vc->getImpliedLiteral(); vc->getImpliedLiteral(); vc->getImpliedLiteral(); vc->push(); vc->query(id3439); vc->popto(117); vc->push(); vc->query(id3438); vc->popto(117); vc->push(); vc->query(id2569); vc->popto(117); vc->push(); vc->query(id2568); vc->popto(117); vc->push(); vc->query(id705); vc->popto(117); vc->push(); vc->query(id704); vc->popto(117); vc->push(); vc->query(id704); vc->popto(117); vc->push(); vc->query(id705); vc->popto(117); vc->push(); vc->assertFormula(id705); vc->getImpliedLiteral(); vc->getImpliedLiteral(); vc->push(); vc->query(id683); vc->popto(118); vc->push(); vc->query(id682); vc->popto(118); vc->push(); vc->query(id682); vc->popto(118); vc->push(); vc->query(id683); vc->popto(118); vc->push(); vc->assertFormula(id683); vc->getImpliedLiteral(); vc->getImpliedLiteral(); vc->getImpliedLiteral(); vc->push(); vc->query(id1323); vc->popto(119); vc->push(); vc->query(id1322); vc->popto(119); vc->push(); vc->query(id663); vc->popto(119); vc->push(); vc->query(id662); vc->popto(119); vc->push(); vc->query(id662); vc->popto(119); vc->push(); vc->query(id663); vc->popto(119); vc->push(); vc->assertFormula(id663); vc->getImpliedLiteral(); vc->getImpliedLiteral(); vc->getImpliedLiteral(); vc->push(); vc->query(id1491); vc->popto(120); vc->push(); vc->query(id1490); vc->popto(120); vc->push(); vc->query(id623); vc->popto(120); vc->push(); vc->query(id622); vc->popto(120); vc->push(); vc->query(id622); vc->popto(120); vc->push(); vc->query(id623); vc->popto(120); vc->push(); vc->assertFormula(id623); vc->getImpliedLiteral(); vc->getImpliedLiteral(); vc->push(); vc->query(id565); vc->popto(121); vc->push(); vc->query(id564); vc->popto(121); vc->push(); vc->query(id564); vc->popto(121); vc->push(); vc->query(id565); vc->popto(121); vc->push(); vc->assertFormula(id565); vc->getImpliedLiteral(); vc->getImpliedLiteral(); vc->getImpliedLiteral(); vc->getImpliedLiteral(); vc->push(); vc->query(id3431); vc->popto(122); vc->push(); vc->query(id3430); vc->popto(122); vc->push(); vc->query(id2411); vc->popto(122); vc->push(); vc->query(id2410); vc->popto(122); vc->push(); vc->query(id723); vc->popto(122); vc->push(); vc->query(id722); vc->popto(122); vc->push(); vc->query(id722); vc->popto(122); vc->push(); vc->query(id723); vc->popto(122); vc->push(); vc->assertFormula(id723); vc->getImpliedLiteral(); vc->getImpliedLiteral(); vc->push(); vc->query(id701); vc->popto(123); vc->push(); vc->query(id700); vc->popto(123); vc->push(); vc->query(id700); vc->popto(123); vc->push(); vc->query(id701); vc->popto(123); vc->push(); vc->assertFormula(id701); vc->getImpliedLiteral(); vc->getImpliedLiteral(); vc->getImpliedLiteral(); vc->push(); vc->query(id1165); vc->popto(124); vc->push(); vc->query(id1164); vc->popto(124); vc->push(); vc->query(id681); vc->popto(124); vc->push(); vc->query(id680); vc->popto(124); vc->push(); vc->query(id680); vc->popto(124); vc->push(); vc->query(id681); vc->popto(124); vc->push(); vc->assertFormula(id681); vc->getImpliedLiteral(); vc->getImpliedLiteral(); vc->getImpliedLiteral(); vc->push(); vc->query(id1333); vc->popto(125); vc->push(); vc->query(id1332); vc->popto(125); vc->push(); vc->query(id641); vc->popto(125); vc->push(); vc->query(id640); vc->popto(125); vc->push(); vc->query(id640); vc->popto(125); vc->push(); vc->query(id641); vc->popto(125); vc->push(); vc->assertFormula(id641); vc->getImpliedLiteral(); vc->getImpliedLiteral(); vc->push(); vc->query(id583); vc->popto(126); vc->push(); vc->query(id582); vc->popto(126); vc->push(); vc->query(id582); vc->popto(126); vc->push(); vc->query(id583); vc->popto(126); vc->push(); vc->assertFormula(id583); vc->getImpliedLiteral(); vc->getImpliedLiteral(); vc->getImpliedLiteral(); vc->getImpliedLiteral(); vc->push(); vc->query(id3423); vc->popto(127); vc->push(); vc->query(id3422); vc->popto(127); vc->push(); vc->query(id2253); vc->popto(127); vc->push(); vc->query(id2252); vc->popto(127); vc->push(); vc->query(id719); vc->popto(127); vc->push(); vc->query(id718); vc->popto(127); vc->push(); vc->query(id718); vc->popto(127); vc->push(); vc->query(id719); vc->popto(127); vc->push(); vc->assertFormula(id719); vc->getImpliedLiteral(); vc->getImpliedLiteral(); vc->getImpliedLiteral(); vc->push(); vc->query(id1001); vc->popto(128); vc->push(); vc->query(id1000); vc->popto(128); vc->push(); vc->query(id699); vc->popto(128); vc->push(); vc->query(id698); vc->popto(128); vc->push(); vc->query(id698); vc->popto(128); vc->push(); vc->query(id699); vc->popto(128); vc->push(); vc->assertFormula(id699); vc->getImpliedLiteral(); vc->getImpliedLiteral(); vc->getImpliedLiteral(); vc->push(); vc->query(id1175); vc->popto(129); vc->push(); vc->query(id1174); vc->popto(129); vc->push(); vc->query(id659); vc->popto(129); vc->push(); vc->query(id658); vc->popto(129); vc->push(); vc->query(id658); vc->popto(129); vc->push(); vc->query(id659); vc->popto(129); vc->push(); vc->assertFormula(id659); vc->getImpliedLiteral(); vc->getImpliedLiteral(); vc->push(); vc->query(id601); vc->popto(130); vc->push(); vc->query(id600); vc->popto(130); vc->push(); vc->query(id600); vc->popto(130); vc->push(); vc->query(id601); vc->popto(130); vc->push(); vc->assertFormula(id601); vc->getImpliedLiteral(); vc->getImpliedLiteral(); vc->getImpliedLiteral(); vc->getImpliedLiteral(); vc->push(); vc->query(id3415); vc->popto(131); vc->push(); vc->query(id3414); vc->popto(131); vc->push(); vc->query(id2095); vc->popto(131); vc->push(); vc->query(id2094); vc->popto(131); vc->push(); vc->query(id717); vc->popto(131); vc->push(); vc->query(id716); vc->popto(131); vc->push(); vc->query(id716); vc->popto(131); vc->push(); vc->query(id717); vc->popto(131); vc->push(); vc->assertFormula(id717); vc->getImpliedLiteral(); vc->getImpliedLiteral(); vc->getImpliedLiteral(); vc->push(); vc->query(id1011); vc->popto(132); vc->push(); vc->query(id1010); vc->popto(132); vc->push(); vc->query(id677); vc->popto(132); vc->push(); vc->query(id676); vc->popto(132); vc->push(); vc->query(id676); vc->popto(132); vc->push(); vc->query(id677); vc->popto(132); vc->push(); vc->assertFormula(id677); vc->getImpliedLiteral(); vc->getImpliedLiteral(); vc->push(); vc->query(id619); vc->popto(133); vc->push(); vc->query(id618); vc->popto(133); vc->push(); vc->query(id618); vc->popto(133); vc->push(); vc->query(id619); vc->popto(133); vc->push(); vc->assertFormula(id619); vc->getImpliedLiteral(); vc->getImpliedLiteral(); vc->getImpliedLiteral(); vc->getImpliedLiteral(); vc->push(); vc->query(id3407); vc->popto(134); vc->push(); vc->query(id3406); vc->popto(134); vc->push(); vc->query(id1937); vc->popto(134); vc->push(); vc->query(id1936); vc->popto(134); vc->push(); vc->query(id695); vc->popto(134); vc->push(); vc->query(id694); vc->popto(134); vc->push(); vc->query(id694); vc->popto(134); vc->push(); vc->query(id695); vc->popto(134); vc->push(); vc->assertFormula(id695); vc->getImpliedLiteral(); vc->getImpliedLiteral(); vc->push(); vc->query(id637); vc->popto(135); vc->push(); vc->query(id636); vc->popto(135); vc->push(); vc->query(id636); vc->popto(135); vc->push(); vc->query(id637); vc->popto(135); vc->push(); vc->assertFormula(id637); vc->getImpliedLiteral(); vc->getImpliedLiteral(); vc->getImpliedLiteral(); vc->getImpliedLiteral(); vc->push(); vc->query(id3399); vc->popto(136); vc->push(); vc->query(id3398); vc->popto(136); vc->push(); vc->query(id1779); vc->popto(136); vc->push(); vc->query(id1778); vc->popto(136); vc->push(); vc->query(id713); vc->popto(136); vc->push(); vc->query(id712); vc->popto(136); vc->push(); vc->query(id712); vc->popto(136); vc->push(); vc->query(id713); vc->popto(136); vc->push(); vc->assertFormula(id713); vc->getImpliedLiteral(); vc->getImpliedLiteral(); vc->push(); vc->query(id655); vc->popto(137); vc->push(); vc->query(id654); vc->popto(137); vc->push(); vc->query(id654); vc->popto(137); vc->push(); vc->query(id655); vc->popto(137); vc->push(); vc->assertFormula(id655); vc->getImpliedLiteral(); vc->getImpliedLiteral(); vc->getImpliedLiteral(); vc->getImpliedLiteral(); vc->push(); vc->query(id3391); vc->popto(138); vc->push(); vc->query(id3390); vc->popto(138); vc->push(); vc->query(id1621); vc->popto(138); vc->push(); vc->query(id1620); vc->popto(138); vc->push(); vc->query(id673); vc->popto(138); vc->push(); vc->query(id672); vc->popto(138); vc->push(); vc->query(id672); vc->popto(138); vc->push(); vc->query(id673); vc->popto(138); vc->push(); vc->assertFormula(id673); vc->getImpliedLiteral(); vc->getImpliedLiteral(); vc->getImpliedLiteral(); vc->getImpliedLiteral(); vc->push(); vc->query(id3383); vc->popto(139); vc->push(); vc->query(id3382); vc->popto(139); vc->push(); vc->query(id1463); vc->popto(139); vc->push(); vc->query(id1462); vc->popto(139); vc->push(); vc->query(id691); vc->popto(139); vc->push(); vc->query(id690); vc->popto(139); vc->push(); vc->query(id690); vc->popto(139); vc->push(); vc->query(id691); vc->popto(139); vc->push(); vc->assertFormula(id691); vc->getImpliedLiteral(); vc->getImpliedLiteral(); vc->getImpliedLiteral(); vc->getImpliedLiteral(); vc->push(); vc->query(id3375); vc->popto(140); vc->push(); vc->query(id3374); vc->popto(140); vc->push(); vc->query(id1305); vc->popto(140); vc->push(); vc->query(id1304); vc->popto(140); vc->push(); vc->query(id709); vc->popto(140); vc->push(); vc->query(id708); vc->popto(140); vc->push(); vc->query(id708); vc->popto(140); vc->push(); vc->query(id709); vc->popto(140); vc->push(); vc->assertFormula(id709); vc->getImpliedLiteral(); vc->getImpliedLiteral(); vc->getImpliedLiteral(); vc->getImpliedLiteral(); vc->push(); vc->query(id3367); vc->popto(141); vc->push(); vc->query(id3366); vc->popto(141); vc->push(); vc->query(id1147); vc->popto(141); vc->push(); vc->query(id1146); vc->popto(141); vc->push(); vc->query(id459); vc->popto(141); vc->push(); vc->query(id458); vc->popto(141); vc->push(); vc->query(id458); vc->popto(141); vc->push(); vc->query(id459); vc->popto(141); vc->push(); vc->assertFormula(id459); vc->getImpliedLiteral(); vc->getImpliedLiteral(); vc->getImpliedLiteral(); vc->getImpliedLiteral(); vc->push(); vc->query(id754); vc->popto(142); vc->push(); vc->query(id755); vc->popto(142); vc->push(); vc->query(id3223); vc->popto(142); vc->push(); vc->query(id3222); vc->popto(142); vc->push(); vc->query(id477); vc->popto(142); vc->push(); vc->query(id476); vc->popto(142); vc->push(); vc->query(id476); vc->popto(142); vc->push(); vc->query(id477); vc->popto(142); vc->push(); vc->assertFormula(id477); vc->getImpliedLiteral(); vc->getImpliedLiteral(); vc->getImpliedLiteral(); vc->getImpliedLiteral(); vc->push(); vc->query(id752); vc->popto(143); vc->push(); vc->query(id753); vc->popto(143); vc->push(); vc->query(id3065); vc->popto(143); vc->push(); vc->query(id3064); vc->popto(143); vc->push(); vc->query(id495); vc->popto(143); vc->push(); vc->query(id494); vc->popto(143); vc->push(); vc->query(id494); vc->popto(143); vc->push(); vc->query(id495); vc->popto(143); vc->push(); vc->assertFormula(id495); vc->getImpliedLiteral(); vc->getImpliedLiteral(); vc->getImpliedLiteral(); vc->getImpliedLiteral(); vc->push(); vc->query(id750); vc->popto(144); vc->push(); vc->query(id751); vc->popto(144); vc->push(); vc->query(id2907); vc->popto(144); vc->push(); vc->query(id2906); vc->popto(144); vc->push(); vc->query(id513); vc->popto(144); vc->push(); vc->query(id512); vc->popto(144); vc->push(); vc->query(id512); vc->popto(144); vc->push(); vc->query(id513); vc->popto(144); vc->push(); vc->assertFormula(id513); vc->getImpliedLiteral(); vc->getImpliedLiteral(); vc->getImpliedLiteral(); vc->getImpliedLiteral(); vc->push(); vc->query(id748); vc->popto(145); vc->push(); vc->query(id749); vc->popto(145); vc->push(); vc->query(id2749); vc->popto(145); vc->push(); vc->query(id2748); vc->popto(145); vc->push(); vc->query(id531); vc->popto(145); vc->push(); vc->query(id530); vc->popto(145); vc->push(); vc->query(id530); vc->popto(145); vc->push(); vc->query(id531); vc->popto(145); vc->push(); vc->assertFormula(id531); vc->getImpliedLiteral(); vc->getImpliedLiteral(); vc->getImpliedLiteral(); vc->getImpliedLiteral(); vc->push(); vc->query(id746); vc->popto(146); vc->push(); vc->query(id747); vc->popto(146); vc->push(); vc->query(id2591); vc->popto(146); vc->push(); vc->query(id2590); vc->popto(146); vc->push(); vc->query(id549); vc->popto(146); vc->push(); vc->query(id548); vc->popto(146); vc->push(); vc->query(id548); vc->popto(146); vc->push(); vc->query(id549); vc->popto(146); vc->push(); vc->assertFormula(id549); vc->getImpliedLiteral(); vc->getImpliedLiteral(); vc->getImpliedLiteral(); vc->getImpliedLiteral(); vc->push(); vc->query(id744); vc->popto(147); vc->push(); vc->query(id745); vc->popto(147); vc->push(); vc->query(id2433); vc->popto(147); vc->push(); vc->query(id2432); vc->popto(147); vc->push(); vc->query(id567); vc->popto(147); vc->push(); vc->query(id566); vc->popto(147); vc->push(); vc->query(id566); vc->popto(147); vc->push(); vc->query(id567); vc->popto(147); vc->push(); vc->assertFormula(id567); vc->getImpliedLiteral(); vc->getImpliedLiteral(); vc->getImpliedLiteral(); vc->getImpliedLiteral(); vc->push(); vc->query(id742); vc->popto(148); vc->push(); vc->query(id743); vc->popto(148); vc->push(); vc->query(id2275); vc->popto(148); vc->push(); vc->query(id2274); vc->popto(148); vc->push(); vc->query(id585); vc->popto(148); vc->push(); vc->query(id584); vc->popto(148); vc->push(); vc->query(id584); vc->popto(148); vc->push(); vc->query(id585); vc->popto(148); vc->push(); vc->assertFormula(id585); vc->getImpliedLiteral(); vc->getImpliedLiteral(); vc->getImpliedLiteral(); vc->getImpliedLiteral(); vc->push(); vc->query(id740); vc->popto(149); vc->push(); vc->query(id741); vc->popto(149); vc->push(); vc->query(id2117); vc->popto(149); vc->push(); vc->query(id2116); vc->popto(149); vc->push(); vc->query(id603); vc->popto(149); vc->push(); vc->query(id602); vc->popto(149); vc->push(); vc->query(id602); vc->popto(149); vc->push(); vc->query(id603); vc->popto(149); vc->push(); vc->assertFormula(id603); vc->getImpliedLiteral(); vc->getImpliedLiteral(); vc->getImpliedLiteral(); vc->getImpliedLiteral(); vc->push(); vc->query(id738); vc->popto(150); vc->push(); vc->query(id739); vc->popto(150); vc->push(); vc->query(id1959); vc->popto(150); vc->push(); vc->query(id1958); vc->popto(150); vc->push(); vc->query(id621); vc->popto(150); vc->push(); vc->query(id620); vc->popto(150); vc->push(); vc->query(id620); vc->popto(150); vc->push(); vc->query(id621); vc->popto(150); vc->push(); vc->assertFormula(id621); vc->getImpliedLiteral(); vc->getImpliedLiteral(); vc->getImpliedLiteral(); vc->getImpliedLiteral(); vc->push(); vc->query(id736); vc->popto(151); vc->push(); vc->query(id737); vc->popto(151); vc->push(); vc->query(id1801); vc->popto(151); vc->push(); vc->query(id1800); vc->popto(151); vc->push(); vc->query(id639); vc->popto(151); vc->push(); vc->query(id638); vc->popto(151); vc->push(); vc->query(id638); vc->popto(151); vc->push(); vc->query(id639); vc->popto(151); vc->push(); vc->assertFormula(id639); vc->getImpliedLiteral(); vc->getImpliedLiteral(); vc->getImpliedLiteral(); vc->getImpliedLiteral(); vc->push(); vc->query(id734); vc->popto(152); vc->push(); vc->query(id735); vc->popto(152); vc->push(); vc->query(id1643); vc->popto(152); vc->push(); vc->query(id1642); vc->popto(152); vc->push(); vc->query(id657); vc->popto(152); vc->push(); vc->query(id656); vc->popto(152); vc->push(); vc->query(id656); vc->popto(152); vc->push(); vc->query(id657); vc->popto(152); vc->push(); vc->assertFormula(id657); vc->getImpliedLiteral(); vc->getImpliedLiteral(); vc->getImpliedLiteral(); vc->getImpliedLiteral(); vc->push(); vc->query(id732); vc->popto(153); vc->push(); vc->query(id733); vc->popto(153); vc->push(); vc->query(id1485); vc->popto(153); vc->push(); vc->query(id1484); vc->popto(153); vc->push(); vc->query(id675); vc->popto(153); vc->push(); vc->query(id674); vc->popto(153); vc->push(); vc->query(id674); vc->popto(153); vc->push(); vc->query(id675); vc->popto(153); vc->push(); vc->assertFormula(id675); vc->getImpliedLiteral(); vc->getImpliedLiteral(); vc->getImpliedLiteral(); vc->getImpliedLiteral(); vc->push(); vc->query(id730); vc->popto(154); vc->push(); vc->query(id731); vc->popto(154); vc->push(); vc->query(id1327); vc->popto(154); vc->push(); vc->query(id1326); vc->popto(154); vc->push(); vc->query(id693); vc->popto(154); vc->push(); vc->query(id692); vc->popto(154); vc->push(); vc->query(id692); vc->popto(154); vc->push(); vc->query(id693); vc->popto(154); vc->push(); vc->assertFormula(id693); vc->getImpliedLiteral(); vc->getImpliedLiteral(); vc->getImpliedLiteral(); vc->getImpliedLiteral(); vc->push(); vc->query(id728); vc->popto(155); vc->push(); vc->query(id729); vc->popto(155); vc->push(); vc->query(id1169); vc->popto(155); vc->push(); vc->query(id1168); vc->popto(155); vc->push(); vc->query(id711); vc->popto(155); vc->push(); vc->query(id710); vc->popto(155); vc->push(); vc->query(id710); vc->popto(155); vc->push(); vc->query(id711); vc->popto(155); vc->push(); vc->assertFormula(id711); vc->getImpliedLiteral(); vc->getImpliedLiteral(); vc->getImpliedLiteral(); vc->getImpliedLiteral(); vc->push(); vc->query(id3370); vc->popto(156); vc->push(); vc->query(id3371); vc->popto(156); vc->push(); vc->query(id1005); vc->popto(156); vc->push(); vc->query(id1004); vc->popto(156); vc->push(); vc->query(id3300); vc->popto(156); vc->push(); vc->query(id3301); vc->popto(156); vc->push(); vc->assertFormula(id3301); vc->getImpliedLiteral(); vc->getImpliedLiteral(); vc->push(); vc->query(id3282); vc->popto(157); vc->popto(156); vc->push(); vc->query(id3328); } catch(const Exception& e) { exitStatus = 1; cout << "*** Exception caught in testgeorge3(): \n" << e << endl; } delete vc; } void testgeorge4() { CLFlags flags = ValidityChecker::createFlags(); flags.setFlag("arith3", true); ValidityChecker *vc = ValidityChecker::create(flags); try { /*************/ vector inconsistency; /*************/ Type id9 = vc->realType(); Type id7 = vc->intType(); Type id11 = vc->boolType(); vc->push(); vc->stackLevel(); Expr id13=vc->trueExpr(); Expr id12=vc->notExpr(vc->trueExpr()); Type id19=vc->arrayType(id7,id7); Type id21=vc->arrayType(id7,id9); Type id23=vc->arrayType(id9,id7); Type id25=vc->arrayType(id9,id9); Type id27=vc->tupleType(id19,id7,id7); Type id29=vc->funType(id27,id19); Op id31=vc->createOp(".Int_Int_store",id29); Type id33=vc->tupleType(id21,id7); Type id35=vc->funType(id33,id9); Op id37=vc->createOp(".Int_Real_select",id35); Type id39=vc->tupleType(id21,id7,id9); Type id41=vc->funType(id39,id21); Op id43=vc->createOp(".Int_Real_store",id41); Type id45=vc->tupleType(id19,id7); Type id47=vc->funType(id45,id7); Op id49=vc->createOp(".Int_Int_select",id47); Type id51=vc->tupleType(id23,id9,id7); Type id53=vc->funType(id51,id23); Op id55=vc->createOp(".Real_Int_store",id53); Type id57=vc->tupleType(id25,id9,id9); Type id59=vc->funType(id57,id25); Op id61=vc->createOp(".Real_Real_store",id59); Type id63=vc->tupleType(id23,id9); Type id65=vc->funType(id63,id7); Op id67=vc->createOp(".Real_Int_select",id65); Type id69=vc->tupleType(id25,id9); Type id71=vc->funType(id69,id9); Op id73=vc->createOp(".Real_Real_select",id71); Expr id79=vc->varExpr("AT2_PROC1_X",id7); Expr id81=vc->varExpr("AT0_PROC1_X",id7); Expr id105=vc->varExpr("AT2_Z",id7); Expr id133=vc->varExpr("AT2_PROC2_X",id7); Expr id135=vc->varExpr("AT0_PROC2_X",id7); Expr id137=vc->varExpr("AT1_PROC1_X",id7); Expr id141=vc->varExpr("AT1_Z",id7); Expr id205=vc->varExpr("AT1_PROC2_X",id7); Expr id209=vc->varExpr("AT0_Z",id7); Expr id219=vc->eqExpr(id209,id81); Expr id218=vc->notExpr(id219); vc->registerAtom(id219); Expr id221=vc->gtExpr(id81,id209); Expr id220=vc->notExpr(id221); vc->registerAtom(id221); Expr id225=vc->eqExpr(id141,id137); Expr id224=vc->notExpr(id225); vc->registerAtom(id225); Expr id227=vc->gtExpr(id137,id141); Expr id226=vc->notExpr(id227); vc->registerAtom(id227); Expr id231=vc->eqExpr(id105,id79); Expr id230=vc->notExpr(id231); vc->registerAtom(id231); Expr id233=vc->gtExpr(id79,id105); Expr id232=vc->notExpr(id233); vc->registerAtom(id233); Expr id237=vc->eqExpr(id209,id135); Expr id236=vc->notExpr(id237); vc->registerAtom(id237); Expr id239=vc->gtExpr(id135,id209); Expr id238=vc->notExpr(id239); vc->registerAtom(id239); Expr id243=vc->eqExpr(id141,id205); Expr id242=vc->notExpr(id243); vc->registerAtom(id243); Expr id245=vc->gtExpr(id205,id141); Expr id244=vc->notExpr(id245); vc->registerAtom(id245); Expr id249=vc->eqExpr(id105,id133); Expr id248=vc->notExpr(id249); vc->registerAtom(id249); Expr id251=vc->gtExpr(id133,id105); Expr id250=vc->notExpr(id251); vc->registerAtom(id251); Expr id255=vc->minusExpr(id81,id209); Expr id257=vc->ratExpr(10,1); Expr id259=vc->leExpr(id255,id257); Expr id258=vc->notExpr(id259); vc->registerAtom(id259); Expr id261=vc->minusExpr(id137,id141); Expr id263=vc->leExpr(id261,id257); Expr id262=vc->notExpr(id263); vc->registerAtom(id263); Expr id265=vc->minusExpr(id135,id209); Expr id267=vc->leExpr(id265,id257); Expr id266=vc->notExpr(id267); vc->registerAtom(id267); Expr id269=vc->minusExpr(id205,id141); Expr id271=vc->leExpr(id269,id257); Expr id270=vc->notExpr(id271); vc->registerAtom(id271); Expr id273=vc->eqExpr(id81,id137); Expr id272=vc->notExpr(id273); vc->registerAtom(id273); Expr id275=vc->eqExpr(id137,id79); Expr id274=vc->notExpr(id275); vc->registerAtom(id275); Expr id277=vc->eqExpr(id209,id141); Expr id276=vc->notExpr(id277); vc->registerAtom(id277); Expr id279=vc->eqExpr(id141,id105); Expr id278=vc->notExpr(id279); vc->registerAtom(id279); Expr id281=vc->eqExpr(id135,id205); Expr id280=vc->notExpr(id281); vc->registerAtom(id281); Expr id283=vc->eqExpr(id205,id133); Expr id282=vc->notExpr(id283); vc->registerAtom(id283); Expr id285=vc->ltExpr(id141,id209); Expr id284=vc->notExpr(id285); vc->registerAtom(id285); Expr id289=vc->ltExpr(id105,id141); Expr id288=vc->notExpr(id289); vc->registerAtom(id289); Expr id293=vc->ltExpr(id137,id81); Expr id292=vc->notExpr(id293); vc->registerAtom(id293); Expr id297=vc->ltExpr(id79,id137); Expr id296=vc->notExpr(id297); vc->registerAtom(id297); Expr id301=vc->ltExpr(id205,id135); Expr id300=vc->notExpr(id301); vc->registerAtom(id301); Expr id305=vc->ltExpr(id133,id205); Expr id304=vc->notExpr(id305); vc->registerAtom(id305); Expr id319=vc->ltExpr(id141,id137); Expr id318=vc->notExpr(id319); vc->registerAtom(id319); Expr id325=vc->ltExpr(id141,id205); Expr id324=vc->notExpr(id325); vc->registerAtom(id325); Expr id539=vc->minusExpr(id79,id105); Expr id541=vc->leExpr(id539,id257); Expr id540=vc->notExpr(id541); vc->registerAtom(id541); Expr id555=vc->minusExpr(id133,id105); Expr id557=vc->leExpr(id555,id257); Expr id556=vc->notExpr(id557); vc->registerAtom(id557); Expr id683=vc->gtExpr(id255,id257); Expr id682=vc->notExpr(id683); vc->registerAtom(id683); Expr id773=vc->gtExpr(id261,id257); Expr id772=vc->notExpr(id773); vc->registerAtom(id773); Expr id903=vc->gtExpr(id265,id257); Expr id902=vc->notExpr(id903); vc->registerAtom(id903); Expr id993=vc->gtExpr(id269,id257); Expr id992=vc->notExpr(id993); vc->registerAtom(id993); Expr id1619=vc->ltExpr(id209,id81); Expr id1618=vc->notExpr(id1619); vc->registerAtom(id1619); Expr id1665=vc->ltExpr(id105,id79); Expr id1664=vc->notExpr(id1665); vc->registerAtom(id1665); Expr id1699=vc->ltExpr(id209,id135); Expr id1698=vc->notExpr(id1699); vc->registerAtom(id1699); Expr id1745=vc->ltExpr(id105,id133); Expr id1744=vc->notExpr(id1745); vc->registerAtom(id1745); Expr id2009=vc->eqExpr(id539,id261); Expr id2008=vc->notExpr(id2009); vc->registerAtom(id2009); Expr id2053=vc->eqExpr(id555,id269); Expr id2052=vc->notExpr(id2053); vc->registerAtom(id2053); vc->push(); vc->query(id12); vc->inconsistent(inconsistency); vc->pop(); vc->push(); vc->query(id2052); vc->stackLevel(); vc->popto(1); vc->push(); vc->query(id2053); vc->stackLevel(); vc->popto(1); vc->push(); vc->assertFormula(id2053); vc->getImpliedLiteral(); vc->getImpliedLiteral(); vc->push(); vc->query(id2008); } catch(const Exception& e) { exitStatus = 1; cout << "*** Exception caught in testgeorge4(): \n" << e << endl; } delete vc; } void testgeorge5() { CLFlags flags = ValidityChecker::createFlags(); flags.setFlag("arith3", true); ValidityChecker *vc = ValidityChecker::create(flags); try { /*************/ vector inconsistency; /*************/ Type id2 = vc->realType(); Type id1 = vc->intType(); Type id3 = vc->boolType(); vc->push(); vc->stackLevel(); Expr id4=vc->trueExpr(); Expr idn4=vc->notExpr(vc->trueExpr()); Type id7=vc->arrayType(id1,id1); Type id8=vc->arrayType(id1,id2); Type id9=vc->arrayType(id2,id1); Type id10=vc->arrayType(id2,id2); Type id11=vc->tupleType(id7,id1,id1); Type id12=vc->funType(id11,id7); Op id13=vc->createOp(".Int_Int_store",id12); Type id14=vc->tupleType(id8,id1); Type id15=vc->funType(id14,id2); Op id16=vc->createOp(".Int_Real_select",id15); Type id17=vc->tupleType(id8,id1,id2); Type id18=vc->funType(id17,id8); Op id19=vc->createOp(".Int_Real_store",id18); Type id20=vc->tupleType(id7,id1); Type id21=vc->funType(id20,id1); Op id22=vc->createOp(".Int_Int_select",id21); Type id23=vc->tupleType(id9,id2,id1); Type id24=vc->funType(id23,id9); Op id25=vc->createOp(".Real_Int_store",id24); Type id26=vc->tupleType(id10,id2,id2); Type id27=vc->funType(id26,id10); Op id28=vc->createOp(".Real_Real_store",id27); Type id29=vc->tupleType(id9,id2); Type id30=vc->funType(id29,id1); Op id31=vc->createOp(".Real_Int_select",id30); Type id32=vc->tupleType(id10,id2); Type id33=vc->funType(id32,id2); Op id34=vc->createOp(".Real_Real_select",id33); Type id36=vc->funType(id1,id3); Op id37=vc->createOp("trainhere",id36); Op id40=vc->createOp("trains_i",id36); Op id41=vc->createOp("trains_p",id36); Op id42=vc->createOp("trains_nothere",id36); Expr id45=vc->varExpr("i",id1); Expr id46=vc->varExpr("j",id1); Expr id47=vc->varExpr("t",id2); Expr id48=vc->varExpr("gammaup",id2); Expr id49=vc->varExpr("lastup",id2); Expr id50=vc->varExpr("beta",id2); Type id51=vc->tupleType(id2,id2); Type id52=vc->funType(id51,id2); Op id53=vc->createOp("-",id52); Expr id54=vc->varExpr("conmini",id2); Expr id55=vc->varExpr("carpassingtime",id2); Expr id56=vc->varExpr("gaterisetime",id2); Expr id57=vc->varExpr("gammadown",id2); Type id58=vc->funType(id1,id2); Op id59=vc->createOp("lastenter",id58); Expr id60=vc->varExpr("gatedowntime",id2); Expr id61=vc->varExpr("mintimetoi",id2); Op id62=vc->createOp("schedtime",id58); Expr id63=vc->varExpr("lastdown",id2); Op id64=vc->createOp("firstenter",id58); Expr id65=vc->varExpr("maxtimetoi",id2); Expr id75 = vc->funExpr(id41,id45); Expr idn75=vc->notExpr(id75); Expr id76 = vc->funExpr(id64,id45); Expr id77=vc->geExpr(id47,id76); Expr idn77=vc->notExpr(id77); vc->push(); vc->query(id77); vc->stackLevel(); vc->popto(1); vc->push(); vc->query(idn77); vc->stackLevel(); vc->popto(1); vc->push(); vc->query(id75); vc->stackLevel(); vc->popto(1); vc->push(); vc->query(idn75); vc->stackLevel(); vc->popto(1); Expr id83=vc->varExpr("1?82",id1); Expr id84 = vc->funExpr(id64,id83); Expr id85=vc->ltExpr(id47,id84); Expr idn85=vc->notExpr(id85); Expr id87 = vc->funExpr(id40,id83); Expr idn87=vc->notExpr(id87); Expr id91=vc->varExpr("2?90",id1); Expr id92 = vc->funExpr(id40,id91); Expr idn92=vc->notExpr(id92); Expr id93 = vc->funExpr(id41,id91); Expr idn93=vc->notExpr(id93); Expr id94 = vc->funExpr(id42,id91); Expr idn94=vc->notExpr(id94); Expr id97=vc->varExpr("3?96",id1); Expr id98 = vc->funExpr(id40,id97); Expr idn98=vc->notExpr(id98); Expr id100 = vc->funExpr(id41,id97); Expr idn100=vc->notExpr(id100); Expr id101 = vc->funExpr(id42,id97); Expr idn101=vc->notExpr(id101); Expr id106=vc->varExpr("4?105",id1); Expr id107 = vc->funExpr(id41,id106); Expr idn107=vc->notExpr(id107); Expr id109 = vc->funExpr(id40,id106); Expr idn109=vc->notExpr(id109); Expr id110 = vc->funExpr(id42,id106); Expr idn110=vc->notExpr(id110); Expr id115=vc->varExpr("5?114",id1); Expr id116 = vc->funExpr(id42,id115); Expr idn116=vc->notExpr(id116); Expr id118 = vc->funExpr(id41,id115); Expr idn118=vc->notExpr(id118); Expr id119 = vc->funExpr(id40,id115); Expr idn119=vc->notExpr(id119); Expr id124=vc->varExpr("6?123",id1); Expr id125=vc->eqExpr(id45,id124); Expr idn125=vc->notExpr(id125); Expr id128 = vc->funExpr(id40,id124); Expr idn128=vc->notExpr(id128); Expr id133 = vc->funExpr(id41,id124); Expr idn133=vc->notExpr(id133); Expr id136 = vc->funExpr(id42,id124); Expr idn136=vc->notExpr(id136); Expr id139=vc->varExpr("7?138",id1); Expr id140=vc->eqExpr(id45,id139); Expr idn140=vc->notExpr(id140); Expr id143 = vc->funExpr(id40,id139); Expr idn143=vc->notExpr(id143); Expr id149 = vc->funExpr(id41,id139); Expr idn149=vc->notExpr(id149); Expr id152 = vc->funExpr(id42,id139); Expr idn152=vc->notExpr(id152); Expr id157=vc->varExpr("8?156",id1); Expr id158=vc->eqExpr(id45,id157); Expr idn158=vc->notExpr(id158); Expr id162 = vc->funExpr(id41,id157); Expr idn162=vc->notExpr(id162); Expr id168 = vc->funExpr(id40,id157); Expr idn168=vc->notExpr(id168); Expr id170 = vc->funExpr(id42,id157); Expr idn170=vc->notExpr(id170); Expr id175=vc->varExpr("9?174",id1); Expr id176 = vc->funExpr(id42,id175); Expr idn176=vc->notExpr(id176); Expr id178=vc->eqExpr(id45,id175); Expr idn178=vc->notExpr(id178); Expr id182 = vc->funExpr(id41,id175); Expr idn182=vc->notExpr(id182); Expr id187 = vc->funExpr(id40,id175); Expr idn187=vc->notExpr(id187); Expr id195=vc->varExpr("10?194",id1); Expr id196=vc->eqExpr(id45,id195); Expr idn196=vc->notExpr(id196); Expr id199 = vc->funExpr(id40,id195); Expr idn199=vc->notExpr(id199); Expr id202 = vc->funExpr(id64,id195); Expr id203=vc->ltExpr(id47,id202); Expr idn203=vc->notExpr(id203); inconsistency.clear( ); vc->push(); vc->query(idn4); vc->inconsistent(inconsistency); vc->pop(); Expr id206 = vc->funExpr(id64,id115); Expr id207 = vc->funExpr(id64,id97); Expr id208 = vc->funExpr(id64,id157); Expr id209 = vc->funExpr(id64,id139); Expr id210 = vc->funExpr(id64,id124); Expr id211 = vc->funExpr(id64,id175); Expr id212 = vc->funExpr(id64,id106); vc->push(); vc->query(id203); vc->stackLevel(); vc->popto(1); vc->push(); vc->query(idn203); vc->stackLevel(); vc->popto(1); vc->push(); vc->assertFormula(id203); vc->push(); vc->query(id178); vc->stackLevel(); vc->popto(2); vc->push(); vc->query(idn178); vc->stackLevel(); vc->popto(2); vc->push(); vc->assertFormula(id178); vc->push(); vc->query(id158); vc->stackLevel(); vc->popto(3); vc->push(); vc->query(idn158); vc->stackLevel(); vc->popto(3); vc->push(); vc->assertFormula(id158); vc->push(); vc->query(id152); vc->stackLevel(); vc->popto(4); vc->push(); vc->query(idn152); vc->stackLevel(); vc->popto(4); vc->push(); vc->assertFormula(id152); vc->push(); vc->query(id125); vc->stackLevel(); vc->popto(5); vc->push(); vc->query(idn125); vc->stackLevel(); vc->popto(5); vc->push(); vc->assertFormula(idn125); vc->push(); vc->query(id140); vc->stackLevel(); vc->popto(6); vc->push(); vc->query(idn140); vc->stackLevel(); vc->popto(6); vc->push(); vc->assertFormula(id140); vc->push(); vc->query(id182); vc->stackLevel(); vc->popto(7); vc->push(); vc->query(idn182); vc->stackLevel(); vc->popto(7); vc->push(); vc->assertFormula(id182); vc->push(); vc->query(id162); vc->stackLevel(); vc->popto(8); vc->push(); vc->query(idn162); vc->stackLevel(); vc->popto(8); vc->push(); vc->query(id162); inconsistency.clear( ); vc->getAssumptions(inconsistency); vc->stackLevel(); vc->popto(8); vc->push(); vc->query(id85); vc->stackLevel(); vc->popto(8); vc->push(); vc->query(idn85); vc->stackLevel(); vc->popto(8); vc->push(); vc->assertFormula(id85); vc->push(); vc->query(id187); vc->stackLevel(); vc->popto(9); vc->push(); vc->query(idn187); vc->stackLevel(); vc->popto(9); vc->push(); vc->assertFormula(id187); vc->push(); vc->query(id87); vc->stackLevel(); vc->popto(10); vc->push(); vc->query(idn87); vc->stackLevel(); vc->popto(10); vc->push(); vc->assertFormula(id87); vc->push(); vc->query(id119); vc->stackLevel(); vc->popto(11); vc->push(); vc->query(idn119); vc->stackLevel(); vc->popto(11); vc->push(); vc->assertFormula(id119); vc->push(); vc->query(id170); vc->stackLevel(); vc->popto(12); vc->push(); vc->query(idn170); vc->stackLevel(); vc->popto(12); vc->push(); vc->query(id170); inconsistency.clear( ); vc->getAssumptions(inconsistency); vc->stackLevel(); vc->popto(12); vc->push(); vc->query(id110); vc->stackLevel(); vc->popto(12); vc->push(); vc->query(idn110); vc->stackLevel(); vc->popto(12); vc->push(); vc->assertFormula(id110); vc->push(); vc->query(id118); vc->stackLevel(); vc->popto(13); vc->push(); vc->query(idn118); vc->stackLevel(); vc->popto(13); vc->push(); vc->assertFormula(id118); vc->push(); vc->query(id196); vc->stackLevel(); vc->popto(14); vc->push(); vc->query(idn196); vc->stackLevel(); vc->popto(14); vc->push(); vc->assertFormula(id196); vc->push(); vc->query(id199); vc->stackLevel(); vc->popto(15); vc->push(); vc->query(idn199); vc->stackLevel(); vc->popto(15); vc->push(); vc->query(id199); inconsistency.clear( ); vc->getAssumptions(inconsistency); vc->stackLevel(); vc->popto(15); vc->push(); vc->query(id100); vc->stackLevel(); vc->popto(15); vc->push(); vc->query(idn100); vc->stackLevel(); vc->popto(15); vc->push(); vc->assertFormula(id100); vc->push(); vc->query(id107); vc->stackLevel(); vc->popto(16); vc->push(); vc->query(idn107); vc->stackLevel(); vc->popto(16); vc->push(); vc->assertFormula(id107); vc->push(); vc->query(id98); vc->stackLevel(); vc->popto(17); vc->push(); vc->query(idn98); vc->stackLevel(); vc->popto(17); vc->push(); vc->assertFormula(id98); vc->push(); vc->query(id101); vc->stackLevel(); vc->popto(18); vc->push(); vc->query(idn101); vc->stackLevel(); vc->popto(18); vc->push(); vc->assertFormula(id101); vc->push(); vc->query(id75); vc->stackLevel(); vc->popto(19); vc->push(); vc->query(idn75); vc->stackLevel(); vc->popto(19); vc->push(); vc->query(id75); inconsistency.clear( ); vc->getAssumptions(inconsistency); vc->stackLevel(); vc->popto(19); vc->push(); vc->query(id77); vc->stackLevel(); vc->popto(19); vc->push(); vc->query(idn77); vc->stackLevel(); vc->popto(19); vc->push(); vc->query(idn77); inconsistency.clear( ); vc->getAssumptions(inconsistency); vc->stackLevel(); vc->popto(19); vc->push(); vc->query(id143); vc->stackLevel(); vc->popto(19); vc->push(); vc->query(idn143); vc->stackLevel(); vc->popto(19); vc->push(); vc->query(id143); inconsistency.clear( ); vc->getAssumptions(inconsistency); vc->stackLevel(); vc->popto(19); vc->push(); vc->query(id149); vc->stackLevel(); vc->popto(19); vc->push(); vc->query(idn149); vc->stackLevel(); vc->popto(19); vc->push(); vc->query(id149); inconsistency.clear( ); vc->getAssumptions(inconsistency); vc->stackLevel(); vc->popto(19); vc->push(); vc->query(id109); vc->stackLevel(); vc->popto(19); vc->push(); vc->query(idn109); vc->stackLevel(); vc->popto(19); vc->push(); vc->assertFormula(id109); vc->push(); vc->query(id94); vc->stackLevel(); vc->popto(20); vc->push(); vc->query(idn94); vc->stackLevel(); vc->popto(20); vc->push(); vc->assertFormula(idn94); vc->push(); vc->query(id128); vc->stackLevel(); vc->popto(21); vc->push(); vc->query(idn128); vc->stackLevel(); vc->popto(21); vc->push(); vc->assertFormula(idn128); vc->push(); vc->query(id92); vc->stackLevel(); vc->popto(22); vc->push(); vc->query(idn92); vc->stackLevel(); vc->popto(22); vc->push(); vc->assertFormula(idn92); vc->push(); vc->query(id133); vc->stackLevel(); vc->popto(23); vc->push(); vc->query(idn133); vc->stackLevel(); vc->popto(23); vc->push(); vc->assertFormula(idn133); vc->push(); vc->query(id116); vc->stackLevel(); vc->popto(24); vc->push(); vc->query(idn116); vc->stackLevel(); vc->popto(24); vc->push(); vc->assertFormula(id116); vc->push(); vc->query(id93); vc->stackLevel(); vc->popto(25); vc->push(); vc->query(idn93); vc->stackLevel(); vc->popto(25); vc->push(); vc->assertFormula(idn93); vc->push(); vc->query(id176); vc->stackLevel(); vc->popto(26); vc->push(); vc->query(idn176); vc->stackLevel(); vc->popto(26); vc->push(); vc->query(id176); inconsistency.clear( ); vc->getAssumptions(inconsistency); vc->stackLevel(); vc->popto(26); vc->push(); vc->query(id136); vc->stackLevel(); vc->popto(26); vc->push(); vc->query(idn136); vc->stackLevel(); vc->popto(26); vc->push(); vc->assertFormula(idn136); vc->push(); vc->query(id168); vc->stackLevel(); vc->popto(27); vc->push(); vc->query(idn168); vc->stackLevel(); vc->popto(27); vc->push(); vc->query(id168); inconsistency.clear( ); vc->getAssumptions(inconsistency); vc->stackLevel(); vc->popto(27); inconsistency.clear( ); vc->push(); vc->query(idn4); vc->inconsistent(inconsistency); vc->pop(); vc->stackLevel(); vc->popto(26); vc->stackLevel(); vc->popto(25); vc->stackLevel(); vc->popto(24); vc->stackLevel(); vc->popto(23); vc->stackLevel(); vc->popto(22); vc->stackLevel(); vc->popto(21); vc->stackLevel(); vc->popto(20); vc->stackLevel(); vc->popto(19); vc->stackLevel(); vc->popto(18); vc->stackLevel(); vc->popto(17); vc->stackLevel(); vc->popto(16); vc->stackLevel(); vc->popto(15); vc->stackLevel(); vc->popto(14); vc->stackLevel(); vc->popto(13); vc->stackLevel(); vc->popto(12); vc->stackLevel(); vc->popto(11); vc->stackLevel(); vc->popto(10); vc->stackLevel(); vc->popto(9); vc->stackLevel(); vc->popto(8); vc->stackLevel(); vc->popto(7); vc->stackLevel(); vc->popto(6); vc->stackLevel(); vc->popto(5); vc->stackLevel(); vc->popto(4); vc->stackLevel(); vc->popto(3); vc->stackLevel(); vc->popto(2); vc->stackLevel(); vc->popto(1); } catch(const Exception& e) { exitStatus = 1; cout << "*** Exception caught in testgeorge5(): \n" << e << endl; } delete vc; } cvc3-2.4.1/test/george.h0000664000175400017540000000014410466450544014665 0ustar mdetersmdetersvoid testgeorge1(); void testgeorge2(); void testgeorge3(); void testgeorge4(); void testgeorge5(); cvc3-2.4.1/test/main.cpp0000664000175400017540000016670011406431275014702 0ustar mdetersmdeters/////////////////////////////////////////////////////////////////////////////// // // // File: main.cpp // // Author: Clark Barrett // // Created: Sat Apr 19 01:47:47 2003 // // // /////////////////////////////////////////////////////////////////////////////// #include "vc.h" #include "theory_arith.h" // for arith kinds and expressions #include "theory_array.h" #include #include #include #include #include "exception.h" #include "typecheck_exception.h" #include "command_line_flags.h" #include "debug.h" #include "george.h" using namespace std; using namespace CVC3; int exitStatus; // Check whether e is valid bool check(ValidityChecker* vc, Expr e, bool verbose=true) { if(verbose) { cout << "Query: "; vc->printExpr(e); } bool res = vc->query(e); switch (res) { case false: if(verbose) cout << "Invalid" << endl << endl; break; case true: if(verbose) cout << "Valid" << endl << endl; break; } return res; } // Make a new assertion void newAssertion(ValidityChecker* vc, Expr e) { cout << "Assert: "; vc->printExpr(e); vc->assertFormula(e); } int eqExprVecs(const vector& v1, const vector& v2) { if( v1.size() != v2.size() ) { return 0; } for( unsigned int i=0; i < v1.size(); ++i ) { if( v1[i] != v2[i] ) { return 0; } } return 1; } int eqExprVecVecs(const vector > vv1, const vector > vv2) { if( vv1.size() != vv2.size() ) { return 0; } for( unsigned int i=0; i < vv1.size(); ++i ) { if( !eqExprVecs(vv1[i],vv2[i]) ) { return 0; } } return 1; } void test () { CLFlags flags = ValidityChecker::createFlags(); ValidityChecker* vc = ValidityChecker::create(flags); try { Type it (vc->intType ()); //int Op f = vc->createOp("f",vc->funType(it,it)); Expr z = vc->varExpr("z",it); Expr e = vc->funExpr(f, vc->funExpr(f, z)); e = e[0]; Expr f2 = vc->funExpr(f, e); Expr f3 = vc->funExpr(f, f2); DebugAssert(e != f2 && e != f3, "Refcount problems"); Expr x (vc->boundVarExpr ("x", "0", it));//x0:int vector xs; xs.push_back (x); // Op lxsx (vc->lambdaExpr (xs,x)); //\. x0:int Expr y (vc->ratExpr (1,1)); //1 vector ys; ys.push_back (y); //<1> Expr lxsxy = vc->funExpr (lxsx, y); //(\. x0:int)1 Expr lxsxys = vc->funExpr (lxsx, ys); //(\. x0:int)<1> cout << "Lambda application: " << lxsxy << endl; cout << "Simplified: " << vc->simplify(lxsxy) << endl; } catch(const Exception& e) { exitStatus = 1; cout << "*** Exception caught in test (): \n" << e << endl; } delete vc; } void test1() { CLFlags flags = ValidityChecker::createFlags(); flags.setFlag("dagify-exprs",false); flags.setFlag("dump-log", ".test1.cvc"); ValidityChecker* vc = ValidityChecker::create(flags); // It is important that all Expr objects are deleted before vc is // deleted. Therefore, we enclose them in a scope of try{ }catch // block. // // Also, vc methods may throw an Exception, and we want to delete vc // even in those exceptional cases. try { IF_DEBUG(bool b =) check(vc, vc->trueExpr()); DebugAssert(b, "Should be valid"); vc->push(); IF_DEBUG(b =) check(vc, vc->falseExpr()); DebugAssert(!b, "Should be invalid"); vc->pop(); // Check p OR ~p Expr p = vc->varExpr("p", vc->boolType()); Expr e = vc->orExpr(p, vc->notExpr(p)); IF_DEBUG(b =) check(vc, e); DebugAssert(b, "Should be valid"); // Check x = y -> f(x) = f(y) Expr x = vc->varExpr("x", vc->realType()); Expr y = vc->varExpr("y", vc->realType()); Type real2real = vc->funType(vc->realType(), vc->realType()); Op f = vc->createOp("f", real2real); Expr fx = vc->funExpr(f, x); Expr fy = vc->funExpr(f, y); e = vc->impliesExpr(vc->eqExpr(x,y),vc->eqExpr(fx, fy)); IF_DEBUG(b =) check(vc, e); DebugAssert(b, "Should be valid"); // Check f(x) = f(y) -> x = y e = vc->impliesExpr(vc->eqExpr(fx,fy),vc->eqExpr(x, y)); IF_DEBUG(int scopeLevel = vc->scopeLevel();) vc->push(); IF_DEBUG(b =) check(vc, e); DebugAssert(!b, "Should be invalid"); // Get counter-example vector assertions; cout << "Scope level: " << vc->scopeLevel() << endl; cout << "Counter-example:" << endl; vc->getCounterExample(assertions); for (unsigned i = 0; i < assertions.size(); ++i) { vc->printExpr(assertions[i]); } cout << "End of counter-example" << endl << endl; // Reset to initial scope cout << "Resetting" << endl; vc->pop(); DebugAssert(scopeLevel == vc->scopeLevel(), "scope error"); cout << "Scope level: " << vc->scopeLevel() << endl << endl; // Check w = x & x = y & y = z & f(x) = f(y) & x = 1 & z = 2 Expr w = vc->varExpr("w", vc->realType()); Expr z = vc->varExpr("z", vc->realType()); cout << "Push Scope" << endl << endl; vc->push(); newAssertion(vc, vc->eqExpr(w, x)); newAssertion(vc, vc->eqExpr(x, y)); newAssertion(vc, vc->eqExpr(y, z)); newAssertion(vc, vc->eqExpr(fx, fy)); newAssertion(vc, vc->eqExpr(x, vc->ratExpr(1))); cout << endl << "simplify(w) = "; vc->printExpr(vc->simplify(w)); cout << endl; DebugAssert(vc->simplify(w)==vc->ratExpr(1), "Expected simplify(w) = 1"); newAssertion(vc, vc->eqExpr(z, vc->ratExpr(2))); assertions.clear(); cout << "Inconsistent?: " << vc->inconsistent(assertions) << endl; cout << "Assumptions Used:" << endl; for (unsigned i = 0; i < assertions.size(); ++i) { vc->printExpr(assertions[i]); } cout << endl << "Pop Scope" << endl << endl; vc->pop(); cout << "simplify(w) = "; vc->printExpr(vc->simplify(w)); DebugAssert(vc->simplify(w)==w, "Expected simplify(w) = w"); cout << endl; assertions.clear(); cout << "Inconsistent?: " << vc->inconsistent(assertions) << endl; } catch(const Exception& e) { exitStatus = 1; cout << "*** Exception caught in test1(): \n" << e << endl; } delete vc; } void test2() { CLFlags flags = ValidityChecker::createFlags(); flags.setFlag("dagify-exprs",false); ValidityChecker* vc = ValidityChecker::create(flags); try { Expr bexpr = vc->varExpr("b", vc->intType()); vc->assertFormula(vc->ltExpr(bexpr, vc->ratExpr(10))); Expr c = vc->varExpr("c", vc->intType()); vc->assertFormula(c.eqExpr(vc->ratExpr(0)) || c.eqExpr(vc->ratExpr(1))); IF_DEBUG(bool b =) check(vc, vc->leExpr(bexpr, vc->ratExpr(10))); DebugAssert(b, "Should be valid"); IF_DEBUG(b =) check(vc, vc->falseExpr()); DebugAssert(!b, "Should be invalid"); vc->returnFromCheck(); // Check x = y -> g(x,y) = g(y,x) Expr x = vc->varExpr("x", vc->realType()); Expr y = vc->varExpr("y", vc->realType()); Type real = vc->realType(); vector RxR; RxR.push_back(real); RxR.push_back(real); Type realxreal2real = vc->funType(RxR, real); Op g = vc->createOp("g", realxreal2real); Expr gxy = vc->funExpr(g, x, y); Expr gyx = vc->funExpr(g, y, x); Expr e = vc->impliesExpr(vc->eqExpr(x,y),vc->eqExpr(gxy, gyx)); IF_DEBUG(b =) check(vc, e); DebugAssert(b, "Should be valid"); Op h = vc->createOp("h", realxreal2real); Expr hxy = vc->funExpr(h, x, y); Expr hyx = vc->funExpr(h, y, x); e = vc->impliesExpr(vc->eqExpr(x,y),vc->eqExpr(hxy, hyx)); IF_DEBUG(b =) check(vc, e); DebugAssert(b, "Should be valid"); } catch(const Exception& e) { exitStatus = 1; cout << "*** Exception caught in test2(): \n" << e << endl; } delete vc; } Expr ltLex(ValidityChecker* vc, Expr i1, Expr i2, Expr j1, Expr j2) { Expr res = vc->ltExpr(i1, j1); return vc->orExpr(res, vc->andExpr(vc->eqExpr(i1, j1), vc->ltExpr(i2, j2))); } Expr createTestFormula(ValidityChecker* vc, Expr i1, Expr i2, Expr r1, Expr r2) { Expr lt1 = ltLex(vc, r1, r2, i1, i2); Expr lt2 = ltLex(vc, i2, i1, r2, r1); return vc->andExpr(lt1, lt2); } void test3() { CLFlags flags = ValidityChecker::createFlags(); flags.setFlag("dagify-exprs",false); ValidityChecker* vc = ValidityChecker::create(flags); try { Expr i = vc->varExpr("i", vc->realType()); Expr j = vc->varExpr("j", vc->realType()); Expr k = vc->varExpr("k", vc->realType()); Expr one = vc->ratExpr(1); cout << "i: " << i.getIndex() << endl; Expr test = createTestFormula(vc, i, j, vc->minusExpr(i, one), vc->minusExpr(j, k)); cout << "Trying test: "; vc->printExpr(test); cout << endl; vc->push(); bool result = vc->query(test); if (result) { cout << "Test Valid" << endl; vc->pop(); } else { Expr condition; vector assertions; unsigned index; vc->getCounterExample(assertions); cout << "Test Invalid Under Conditions:" << endl; for (index = 0; index < assertions.size(); ++index) { vc->printExpr(assertions[index]); } // Try assertions one by one for (index = 0; index < assertions.size(); ++index) { condition = vc->notExpr(assertions[index]); cout << "Trying test under condition: "; vc->printExpr(condition); cout << endl; vc->pop(); vc->push(); result = vc->query(vc->impliesExpr(condition, test)); if (result) { cout << "Result Valid" << endl; break; } else { cout << "Result Invalid" << endl; } } } } catch(const Exception& e) { exitStatus = 1; cout << "*** Exception caught in test3(): \n" << e << endl; } delete vc; } void test4() { CLFlags flags = ValidityChecker::createFlags(); flags.setFlag("dagify-exprs",false); ValidityChecker* vc = ValidityChecker::create(flags); try { Expr i = vc->varExpr("i", vc->realType()); Expr j = vc->varExpr("j", vc->realType()); Expr k = vc->varExpr("k", vc->realType()); Expr one = vc->ratExpr(1); cout << "i: " << i.getIndex() << endl; Expr test = createTestFormula(vc, i, j, vc->minusExpr(i, one), vc->minusExpr(j, k)); cout << "Trying test: "; vc->printExpr(test); cout << endl; vc->push(); bool result = vc->query(test); if (result) { cout << "Test Valid" << endl; } else { Expr condition; vector assertions; unsigned index; vc->getCounterExample(assertions); cout << "Test Invalid Under Conditions:" << endl; for (index = 0; index < assertions.size(); ++index) { vc->printExpr(assertions[index]); } // Try assertions one by one for (index = 0; index < assertions.size(); ++index) { condition = vc->notExpr(assertions[index]); cout << "Trying test under condition: "; vc->printExpr(condition); cout << endl; vc->pop(); vc->push(); result = vc->query(vc->impliesExpr(condition, test)); if (result) { cout << "Result Valid" << endl; break; } else { cout << "Result Invalid" << endl; } } } } catch(const Exception& e) { exitStatus = 1; cout << "*** Exception caught in test4(): \n" << e << endl; } delete vc; } void findLeaves(Expr e, vector& l) { int ar = e.arity(); if (ar > 0) { for (int i = 0; i < ar; ++i) findLeaves(e[i], l); return; } l.push_back(e); } bool hasij(Expr e, Expr i, Expr j) { int ar = e.arity(); if (ar > 0) { for (int k = 0; k < ar; ++k) if (hasij(e[k], i, j)) return true; return false; } if (e == i || e == j) return true; return false; } Expr plusExpr(ValidityChecker* vc, vector& kids) { if (kids.size() == 0) return vc->ratExpr(0); else if (kids.size() == 1) return kids[0]; else if (kids.size() == 2) return vc->plusExpr(kids[0], kids[1]); else { Expr r = kids.back(); kids.pop_back(); return vc->plusExpr(plusExpr(vc, kids), r); } } void test5() { CLFlags flags = ValidityChecker::createFlags(); flags.setFlag("dagify-exprs",false); flags.setFlag("dump-log", ".test5.cvc"); ValidityChecker* vc = ValidityChecker::create(flags); try { Expr i = vc->varExpr("i1", vc->realType()); Expr j = vc->varExpr("i2", vc->realType()); Expr p = vc->varExpr("p", vc->realType()); Expr q = vc->varExpr("q", vc->realType()); Expr r = vc->varExpr("r", vc->realType()); Expr a = vc->varExpr("arb_addr", vc->realType()); Expr N = vc->varExpr("N", vc->realType()); Expr M = vc->varExpr("M", vc->arrayType(vc->realType(), vc->realType())); Expr M2 = vc->writeExpr(M, vc->plusExpr(q, i), vc->readExpr(M, vc->plusExpr(r, i))); Expr M1 = vc->writeExpr(M, vc->plusExpr(p, j), vc->readExpr(M, vc->plusExpr(r, j))); Expr e = vc->eqExpr(vc->readExpr(vc->writeExpr(M2, vc->plusExpr(p, j), vc->readExpr(M2, vc->plusExpr(r, j))), a), vc->readExpr(vc->writeExpr(M1, vc->plusExpr(q, i), vc->readExpr(M1, vc->plusExpr(r, i))), a)); Expr one = vc->ratExpr(1); Expr zero = vc->ratExpr(0); Expr qmp = vc->minusExpr(q, p); Expr qmr = vc->minusExpr(q, r); vector hyp; hyp.push_back(vc->ltExpr(i, j)); // hyp.push_back(vc->orExpr(vc->geExpr(qmp, N), vc->leExpr(qmp, zero))); // hyp.push_back(vc->orExpr(vc->geExpr(qmr, N), vc->leExpr(qmr, zero))); Expr test = vc->impliesExpr(vc->andExpr(hyp), e); Expr query; cout << "Checking verification condition:" << endl; vc->printExpr(test); cout << endl; vc->push(); bool result = vc->query(test); if (result) { cout << "Valid" << endl; } else { vector conditions; vector assertions; unsigned index, index2; int req; vector leaves; vc->getCounterExample(assertions); cout << "Invalid Under Conditions:" << endl; for (index = 0; index < assertions.size(); ++index) { if (assertions[index] == (!test)) { for (; index < assertions.size()-1; ++index) { assertions[index] = assertions[index+1]; } assertions.pop_back(); break; } } for (index = 0; index < assertions.size(); ++index) { vc->printExpr(assertions[index]); } cout << endl; // Try assertions one by one for (index = 0; index < assertions.size(); ++index) { e = assertions[index]; // Check condition for eligibility if (e.isNot()) { cout << "Condition ineligible: negation" << endl; vc->printExpr(e); cout << endl; continue; } if (e.isEq()) { req = 2; } else req = 1; leaves.clear(); findLeaves(e, leaves); for (index2 = 0; index2 < leaves.size(); ++index2) { if (!leaves[index2].isVar() || leaves[index2] == i || leaves[index2] == j || leaves[index2] == a) continue; req--; } if (req > 0) { cout << "Condition ineligible: not enough non-loop variables" << endl; vc->printExpr(e); cout << endl; continue; } cout << "Condition selected:" << endl; vc->printExpr(e); cout << endl << endl; conditions.push_back(vc->notExpr(e)); cout << "Trying verification condition with hypothesis:" << endl; vc->printExpr(vc->andExpr(conditions)); cout << endl; vc->pop(); vc->push(); query = vc->impliesExpr(vc->andExpr(conditions), test); result = vc->query(query); if (result) { cout << "Result Valid" << endl; break; } else { assertions.clear(); vc->getCounterExample(assertions); cout << "Invalid Under Conditions:" << endl; for (index2 = 0; index2 < assertions.size(); ++index2) { if (assertions[index2] == (!query)) { for (; index2 < assertions.size()-1; ++index2) { assertions[index2] = assertions[index2+1]; } assertions.pop_back(); break; } } for (index2 = 0; index2 < assertions.size(); ++index2) { vc->printExpr(assertions[index2]); } cout << endl; index = (unsigned)-1; } } cout << endl << "Attempting to remove loop variables" << endl; // replace loop variables in conditions vector newConditions; vector newPlus; bool foundi, foundj, negi, negj; Expr minusone = vc->ratExpr(-1); for (index = 0; index < conditions.size(); ++index) { if (conditions[index][0].isEq()) { e = vc->simplify(vc->minusExpr(conditions[index][0][0], conditions[index][0][1])); if (hasij(e, i, j)) { if (e.getKind() == CVC3::PLUS) { newPlus.clear(); newPlus.push_back(e[0]); foundi = foundj = negi = negj = false; for (index2 = 1; index2 < (unsigned)e.arity(); index2++) { Expr term = e[index2]; if (term == i && !foundi) foundi = true; else if (term == j && !foundj) { foundj = true; negj = true; } else if (term.getKind() == CVC3::MULT && term[0] == minusone && term[1] == i && !foundi) { foundi = true; negi = true; } else if (term.getKind() == CVC3::MULT && term[0] == minusone && term[1] == j && !foundj) foundj = true; else newPlus.push_back(term); } if (foundi && foundj && ((negi && negj) || (!negi && !negj))) { e = plusExpr(vc, newPlus); if (negi && negj) e = vc->uminusExpr(e); e = vc->simplify(e); if (!hasij(e, i, j)) { newConditions.push_back(vc->orExpr(vc->geExpr(e, N), vc->leExpr(e, zero))); continue; } } } cout << "Unable to remove loop variables:" << endl; vc->printExpr(e); break; } } newConditions.push_back(conditions[index]); } if (index == conditions.size()) { cout << "Loop variables successfully removed:" << endl; Expr cond = (newConditions.size()>0)? vc->andExpr(newConditions) : vc->trueExpr(); vc->printExpr(cond); cout << endl; vector loopConditions; loopConditions.push_back(cond); loopConditions.push_back(vc->geExpr(i, one)); loopConditions.push_back(vc->geExpr(j, one)); loopConditions.push_back(vc->leExpr(i, N)); loopConditions.push_back(vc->leExpr(j, N)); vc->pop(); vc->push(); cout << "Final query" << endl; result = vc->query(vc->impliesExpr(vc->andExpr(loopConditions), test)); if (result) { cout << "Result Valid" << endl; } else { cout << "Result Invalid" << endl; } } } } catch(const Exception& e) { exitStatus = 1; cout << "*** Exception caught in test5(): \n" << e << endl; } delete vc; } #include "debug.h" // Test importing of Exprs from a different validity checker void test6() { ValidityChecker* vc1 = ValidityChecker::create(); ValidityChecker* vc2 = ValidityChecker::create(); try { Type real1 = vc1->realType(); Expr x1 = vc1->varExpr("x", real1); Expr y1 = vc1->boundVarExpr("y", "0", real1); cout << "vc1 variables: " << x1 << ", " << y1 << endl; Expr x2 = vc2->varExpr("x", vc2->importType(real1)); Expr y2 = vc2->boundVarExpr("y", "0", vc2->realType()); cout << "vc2 variables: " << x2 << ", " << y2 << endl; cout << "vars imported to vc2 from vc1: " << vc2->importExpr(x1) << ", " << vc2->importExpr(y1) << endl; Expr t1 = vc1->trueExpr(); Expr and1 = vc1->andExpr(t1, vc1->falseExpr()); Op f1 = vc1->createOp("f", vc1->funType(real1, real1)); Expr fx1 = vc1->funExpr(f1, x1); Expr f5_1 = vc1->funExpr(f1, vc1->ratExpr(5,1)); Type rt1 = vc1->recordType("foo", real1, "bar", real1); Expr r1 = vc1->recordExpr("foo", fx1, "bar", f5_1); Expr r1_eq = vc1->eqExpr(r1, vc1->recUpdateExpr(r1, "foo", f5_1)); Type art1 = vc1->arrayType(real1, rt1); Expr ar1 = vc1->varExpr("ar", art1); Expr ar_eq1 = vc1->eqExpr(vc1->writeExpr(ar1, x1, r1), ar1); Expr query1 = vc1->eqExpr(vc1->recSelectExpr(vc1->readExpr(ar1, x1), "foo"), vc1->recSelectExpr(r1, "bar")); cout << "*** VC #1:" << endl; newAssertion(vc1, r1_eq); newAssertion(vc1, ar_eq1); check(vc1, query1); cout << "*** VC #2:" << endl; newAssertion(vc2, vc2->importExpr(r1_eq)); newAssertion(vc2, vc2->importExpr(ar_eq1)); check(vc2, vc2->importExpr(query1)); } catch(const Exception& e) { exitStatus = 1; cout << "*** Exception caught in test6(): \n" << e << endl; } delete vc1; delete vc2; } void test7() { ValidityChecker* vc1 = ValidityChecker::create(); ValidityChecker* vc2 = ValidityChecker::create(); try { Expr e1 = vc1->varExpr("e1", vc1->realType()); Expr e2 = vc2->varExpr("e2", vc2->realType()); newAssertion(vc2, vc2->eqExpr(vc2->importExpr(e1), e2)); } catch(const Exception& e) { exitStatus = 1; cout << "*** Exception caught in test7(): \n" << e << endl; } delete vc1; delete vc2; } void test8() { ValidityChecker* vc = ValidityChecker::create(); try { vector vec; vec.push_back(vc->boundVarExpr("x", "x", vc->realType())); Expr lambda = vc->lambdaExpr(vec, vc->falseExpr()).getExpr(); Expr witness; try { Type t = vc->subtypeType(lambda, witness); DebugAssert(false, "Typechecking exception expected"); } catch(const TypecheckException&) { // fall through } } catch(const Exception& e) { exitStatus = 1; cout << "*** Exception caught in test8(): \n" << e << endl; } delete vc; } Expr adder(ValidityChecker* vc, const Expr& a, const Expr& b, const Expr& c) { return vc->notExpr(vc->iffExpr(vc->notExpr(vc->iffExpr(a,b)),c)); } Expr carry(ValidityChecker* vc, const Expr& a, const Expr& b, const Expr& c) { return vc->orExpr(vc->andExpr(a,b), vc->orExpr(vc->andExpr(b,c),vc->andExpr(a,c))); } void add(ValidityChecker* vc, vector a, vector b, vector& sum) { int i,N=a.size(); Expr c = vc->falseExpr(); for (i=0; i < N; i++) { sum.push_back(adder(vc,a[i],b[i],c)); c = carry(vc,a[i],b[i],c); } } Expr vectorEq(ValidityChecker* vc, vector a, vector b) { int i, N=a.size(); Expr result = vc->trueExpr(); for (i=0; i < N; i++) { result = result && a[i].iffExpr(b[i]); } return result; } void test9(int N) { CLFlags flags = ValidityChecker::createFlags(); // flags.setFlag("proofs",true); ValidityChecker* vc = ValidityChecker::create(flags); try { int i; vector a,b,sum1,sum2; for (i=0; i < N; i++) { a.push_back(vc->varExpr("a" + int2string(i), vc->boolType())); b.push_back(vc->varExpr("b" + int2string(i), vc->boolType())); } add(vc,a,b,sum1); add(vc,b,a,sum2); Expr q = vectorEq(vc,sum1,sum2); check(vc, q); // Proof p = vc->getProof(); } catch(const Exception& e) { exitStatus = 1; cout << "*** Exception caught in test9(): \n" << e << endl; } delete vc; } Expr bvadder(ValidityChecker* vc, const Expr& a, const Expr& b, const Expr& c) { return vc->newBVXorExpr(a, vc->newBVXorExpr(b, c)); } Expr bvcarry(ValidityChecker* vc, const Expr& a, const Expr& b, const Expr& c) { return vc->newBVOrExpr(vc->newBVAndExpr(a,b), vc->newBVOrExpr(vc->newBVAndExpr(b,c),vc->newBVAndExpr(a,c))); } void bvadd(ValidityChecker* vc, vector a, vector b, vector& sum) { int i,N=a.size(); Expr c = vc->newBVConstExpr(Rational(0), 1); for (i=0; i < N; i++) { sum.push_back(bvadder(vc,a[i],b[i],c)); c = bvcarry(vc,a[i],b[i],c); } } Expr bvvectorEq(ValidityChecker* vc, vector a, vector b) { int i, N=a.size(); Expr result = vc->newBVConstExpr(string("1")); for (i=0; i < N; i++) { result = vc->newBVAndExpr(result, vc->newBVXnorExpr(a[i], b[i])); } return result; } void bvtest9(int N) { CLFlags flags = ValidityChecker::createFlags(); ValidityChecker* vc = ValidityChecker::create(flags); try { int i; vector avec,bvec,sum1vec,sum2; Expr a, b, sum1; a = vc->varExpr("a", vc->bitvecType(N)); b = vc->varExpr("b", vc->bitvecType(N)); vector kids; kids.push_back(a); kids.push_back(b); sum1 = vc->newBVPlusExpr(N, kids); for (i=0; i < N; i++) { avec.push_back(vc->newBVExtractExpr(a, i, i)); bvec.push_back(vc->newBVExtractExpr(b, i, i)); sum1vec.push_back(vc->newBVExtractExpr(sum1, i, i)); } bvadd(vc,avec,bvec,sum2); Expr q = bvvectorEq(vc,sum1vec,sum2); check(vc, vc->eqExpr(q,vc->newBVConstExpr(string("1")))); } catch(const Exception& e) { exitStatus = 1; cout << "*** Exception caught in bvtest9(): \n" << e << endl; } delete vc; } // Test for memory leaks (run silently) void test10() { CLFlags flags = ValidityChecker::createFlags(); ValidityChecker* vc = ValidityChecker::create(flags); // Create all expressions in a separate scope, so that they are // destroyed before vc is deleted. try { // Check x = y -> g(x,y) = g(y,x) Expr x = vc->varExpr("x", vc->realType()); Expr y = vc->varExpr("y", vc->realType()); Type real = vc->realType(); vector RxR; RxR.push_back(real); RxR.push_back(real); Type realxreal2real = vc->funType(RxR, real); Op g = vc->createOp("g", realxreal2real); Expr gxy = vc->funExpr(g, x, y); Expr gyx = vc->funExpr(g, y, x); Expr e = vc->impliesExpr(vc->eqExpr(x,y),vc->eqExpr(gxy, gyx)); check(vc, e, false); Op h = vc->createOp("h", realxreal2real); Expr hxy = vc->funExpr(h, x, y); Expr hyx = vc->funExpr(h, y, x); e = vc->impliesExpr(vc->eqExpr(x,y),vc->eqExpr(hxy, hyx)); check(vc, e, false); } catch(const Exception& e) { exitStatus = 1; cout << "*** Exception caught in test10(): \n" << e << endl; } // Make sure all Expr's are deleted first delete vc; } unsigned int printImpliedLiterals(ValidityChecker* vc) { unsigned int count = 0; cout << "Implied Literals:" << endl; Expr impLit = vc->getImpliedLiteral(); while (!impLit.isNull()) { ++count; vc->printExpr(impLit); impLit = vc->getImpliedLiteral(); } return count; } void test11() { CLFlags flags = ValidityChecker::createFlags(); ValidityChecker* vc = ValidityChecker::create(flags); try { Expr x = vc->varExpr("x", vc->realType()); Expr y = vc->varExpr("y", vc->realType()); Expr z = vc->varExpr("z", vc->realType()); Type real = vc->realType(); Type real2real = vc->funType(real, real); Type real2bool = vc->funType(real, vc->boolType()); Op f = vc->createOp("f", real2real); Op p = vc->createOp("p", real2bool); Expr fx = vc->funExpr(f, x); Expr fy = vc->funExpr(f, y); Expr px = vc->funExpr(p, x); Expr py = vc->funExpr(p, y); Expr xeqy = vc->eqExpr(x, y); Expr yeqx = vc->eqExpr(y, x); Expr xeqz = vc->eqExpr(x, z); Expr zeqx = vc->eqExpr(z, x); Expr yeqz = vc->eqExpr(y, z); Expr zeqy = vc->eqExpr(z, y); unsigned int c; vc->registerAtom(vc->eqExpr(x,vc->ratExpr(0,1))); vc->registerAtom(xeqy); vc->registerAtom(yeqx); vc->registerAtom(xeqz); vc->registerAtom(zeqx); vc->registerAtom(yeqz); vc->registerAtom(zeqy); vc->registerAtom(px); vc->registerAtom(py); vc->registerAtom(vc->eqExpr(fx, fy)); cout << "Push" << endl; vc->push(); cout << "Assert x = y" << endl; vc->assertFormula(xeqy); c = printImpliedLiterals(vc); DebugAssert(c==3,"Implied literal error 0"); cout << "Push" << endl; vc->push(); cout << "Assert x /= z" << endl; vc->assertFormula(!xeqz); c = printImpliedLiterals(vc); DebugAssert(c==4,"Implied literal error 1"); cout << "Pop" << endl; vc->pop(); cout << "Push" << endl; vc->push(); cout << "Assert y /= z" << endl; vc->assertFormula(!yeqz); c = printImpliedLiterals(vc); DebugAssert(c==4,"Implied literal error 2"); cout << "Pop" << endl; vc->pop(); cout << "Push" << endl; vc->push(); cout << "Assert p(x)" << endl; vc->assertFormula(px); c = printImpliedLiterals(vc); DebugAssert(c==2,"Implied literal error 3"); cout << "Pop" << endl; vc->pop(); cout << "Push" << endl; vc->push(); cout << "Assert p(y)" << endl; vc->assertFormula(py); c = printImpliedLiterals(vc); DebugAssert(c==2,"Implied literal error 4"); cout << "Pop" << endl; vc->pop(); cout << "Pop" << endl; vc->pop(); cout << "Push" << endl; vc->push(); cout << "Assert y = x" << endl; vc->assertFormula(yeqx); c = printImpliedLiterals(vc); DebugAssert(c==3,"Implied literal error 5"); cout << "Pop" << endl; vc->pop(); cout << "Push" << endl; vc->push(); cout << "Assert p(x)" << endl; vc->assertFormula(px); c = printImpliedLiterals(vc); DebugAssert(c==1,"Implied literal error 6"); cout << "Assert x = y" << endl; vc->assertFormula(xeqy); c = printImpliedLiterals(vc); DebugAssert(c==4,"Implied literal error 7"); cout << "Pop" << endl; vc->pop(); cout << "Push" << endl; vc->push(); cout << "Assert NOT p(x)" << endl; vc->assertFormula(!px); c = printImpliedLiterals(vc); DebugAssert(c==1,"Implied literal error 8"); cout << "Assert x = y" << endl; vc->assertFormula(xeqy); c = printImpliedLiterals(vc); DebugAssert(c==4,"Implied literal error 9"); cout << "Pop" << endl; vc->pop(); } catch(const Exception& e) { exitStatus = 1; cout << "*** Exception caught in test11(): \n" << e << endl; } delete vc; } void test12() { ValidityChecker * vc = ValidityChecker::create( ); try { Type realType = vc->realType(); Type intType = vc->intType(); Type boolType = vc->boolType(); vc -> push(); int initial_layer = vc->stackLevel(); IF_DEBUG(int initial_scope =) vc->scopeLevel(); Expr exprObj_trueID = vc->trueExpr(); Expr exprObj_falseID = vc->notExpr(vc->trueExpr()); vc->popto(initial_layer); DebugAssert(vc->scopeLevel() == initial_scope, "Expected no change"); DebugAssert(vc->stackLevel() == initial_layer, "Expected no change"); // TODO: what happens if we push and then popscope? } catch(const Exception& e) { exitStatus = 1; cout << "*** Exception caught in test12(): \n" << e << endl; } delete vc; } void test13() { CLFlags flags = ValidityChecker::createFlags(); flags.setFlag("dagify-exprs", false); flags.setFlag("dump-log", ".test13.cvc"); ValidityChecker* vc = ValidityChecker::create(flags); try { Expr rat_one = vc->ratExpr(1); Expr rat_two = vc->ratExpr(2); Expr rat_minus_one = vc->ratExpr(-1); bool query_result; query_result = vc->query(vc->eqExpr(rat_two,rat_one)); cout << "2=1 " << query_result << endl; query_result = vc->query(vc->eqExpr(rat_two,rat_minus_one)); cout << "2=-1 " << query_result << endl; } catch(const Exception& e) { exitStatus = 1; cout << "*** Exception caught in test13(): \n" << e << endl; } delete vc; } Expr func1(ValidityChecker *vc) { // local Expr 'tmp' Expr tmp = vc->varExpr("tmp", vc->boolType()); return vc->trueExpr(); } void test14() { ValidityChecker *vc = ValidityChecker::create(); try { // func call: ok Expr test1 = func1(vc); // func call: fail Expr test2 = func1(vc); } catch(const Exception& e) { exitStatus = 1; cout << "*** Exception caught in test14(): \n" << e << endl; } delete vc; } void test15() { CLFlags flags = ValidityChecker::createFlags(); flags.setFlag("dagify-exprs", false); ValidityChecker *vc = ValidityChecker::create(flags); try { /***************************************************** * array declaration * *****************************************************/ // array: index type Type index_type = vc->subrangeType(vc->ratExpr(0), vc->ratExpr(3)); // array: data type Type data_type = vc->subrangeType(vc->ratExpr(0), vc->ratExpr(3)); // array type: [0 .. 3] of 0 .. 3 Type array_type = vc->arrayType(index_type, data_type); Expr arr = vc->varExpr("array", array_type); // array: [1,1,0,0] arr = vc->writeExpr(arr, vc->ratExpr(0), vc->ratExpr(1)); arr = vc->writeExpr(arr, vc->ratExpr(1), vc->ratExpr(1)); arr = vc->writeExpr(arr, vc->ratExpr(2), vc->ratExpr(0)); arr = vc->writeExpr(arr, vc->ratExpr(3), vc->ratExpr(0)); /***************************************************** * forall Expr * *****************************************************/ // for loop: index Expr id = vc->boundVarExpr("id", "0", vc->subrangeType(vc->ratExpr(0), vc->ratExpr(2))); vector vars; vars.push_back(id); // for loop: body Expr for_body = vc->leExpr(vc->readExpr(arr, id), vc->readExpr(arr, vc->plusExpr(id, vc->ratExpr(1)))); // forall expr Expr forall_expr = vc->forallExpr(vars, for_body); vc->push(); check(vc, forall_expr); vector assertions; cout << "Scope level: " << vc->scopeLevel() << endl; cout << "Counter-example:" << endl; vc->getCounterExample(assertions); for (unsigned i = 0; i < assertions.size(); ++i) { vc->printExpr(assertions[i]); } cout << "End of counter-example" << endl << endl; vc->pop(); /***************************************************** * manual expansion * *****************************************************/ Expr e1 = vc->leExpr(vc->readExpr(arr, vc->ratExpr(0)), vc->readExpr(arr, vc->ratExpr(1))); Expr e2 = vc->leExpr(vc->readExpr(arr, vc->ratExpr(1)), vc->readExpr(arr, vc->ratExpr(2))); Expr e3 = vc->leExpr(vc->readExpr(arr, vc->ratExpr(2)), vc->readExpr(arr, vc->ratExpr(3))); Expr manual_expr = vc->andExpr(e1, vc->andExpr(e2, e3)); /***************************************************** * exists Expr * *****************************************************/ // exists: index Expr id_ex = vc->varExpr("id_ex", vc->subrangeType(vc->ratExpr(0), vc->ratExpr(2))); vector vars_ex; vars_ex.push_back(id_ex); // exists: body Expr ex_body = vc->gtExpr(vc->readExpr(arr, id_ex), vc->readExpr(arr, vc->plusExpr(id_ex, vc->ratExpr(1)))); // exists expr Expr ex_expr = vc->existsExpr(vars_ex, ex_body); /***************************************************** * ??? forall <==> manual expansion * *****************************************************/ cout << endl << "Checking forallExpr <==> manual expansion ..." << endl; if (vc->query(vc->iffExpr(forall_expr, manual_expr))) cout << " -- yes." << endl; else { cout << " -- no, with counter examples as " << endl; vector assert1; vc->getCounterExample(assert1); for (unsigned int i = 0; i < assert1.size(); i ++) vc->printExpr(assert1[i]); } cout << endl; /***************************************************** * ??? !forall <==> existsExpr * *****************************************************/ cout << endl << "Checking !forallExpr <==> existsExpr ..." << endl; if (vc->query(vc->iffExpr(vc->notExpr(forall_expr), ex_expr))) cout << " -- yes." << endl; else if (vc->incomplete()) { cout << " -- incomplete:" << endl; vector reasons; vc->incomplete(reasons); for (unsigned int i = 0; i < reasons.size(); ++i) cout << reasons[i] << endl; } else { cout << " -- no, with counter examples as " << endl; vector assert2; vc->getCounterExample(assert2); for (unsigned int i = 0; i < assert2.size(); i ++) vc->printExpr(assert2[i]); } cout << endl << "End of testcases." << endl << endl; } catch(const Exception& e) { exitStatus = 1; cout << "*** Exception caught in test15(): \n" << e << endl; } delete vc; } void test16() { ValidityChecker *vc = ValidityChecker::create(); try { Type zto100 = vc->subrangeType(vc->ratExpr(0), vc->ratExpr(100)); Expr mem = vc->varExpr("mem", vc->arrayType(zto100, vc->intType())); Expr a = vc->varExpr("a", zto100); Expr b = vc->varExpr("b", zto100); Expr lhs = vc->readExpr(vc->writeExpr(mem, a, vc->ratExpr(30)), b); Expr rhs = vc->readExpr(vc->writeExpr(mem, b, vc->ratExpr(40)), a); Expr q = vc->impliesExpr(vc->notExpr(vc->eqExpr(a, b)), vc->eqExpr(lhs, rhs)); check(vc, q); vector assertions; cout << "Scope level: " << vc->scopeLevel() << endl; cout << "Counter-example:" << endl; vc->getCounterExample(assertions); DebugAssert(assertions.size() > 0, "Expected non-empty counter-example"); for (unsigned i = 0; i < assertions.size(); ++i) { vc->printExpr(assertions[i]); } cout << "End of counter-example" << endl << endl; ExprMap m; vc->getConcreteModel(m); ExprMap::iterator it = m.begin(), end = m.end(); if(it == end) cout << " Did not find concrete model for any vars" << endl; else { cout << "%Satisfiable Variable Assignment: % \n"; for(; it!= end; it++) { Expr eq; if(it->first.getType().isBool()) { DebugAssert((it->second).isBoolConst(), "Bad variable assignement: e = "+(it->first).toString() +"\n\n val = "+(it->second).toString()); if((it->second).isTrue()) eq = it->first; else eq = !(it->first); } else eq = (it->first).eqExpr(it->second); cout << Expr(ASSERT, eq) << "\n"; } } } catch(const Exception& e) { exitStatus = 1; cout << "*** Exception caught in test16(): \n" << e << endl; } delete vc; } void test17() { ValidityChecker *vc = ValidityChecker::create(); try { try { vector selectors; vector types; selectors.push_back("car"); types.push_back(vc->intType().getExpr()); selectors.push_back("cdr"); types.push_back(vc->stringExpr("list")); Type badList = vc->dataType("list", "cons", selectors, types); DebugAssert(false, "Typechecking exception expected"); } catch(const TypecheckException&) { // fall through } delete vc; vc = ValidityChecker::create(); { vector constructors; vector > selectors(2); vector > types(2); constructors.push_back("cons"); selectors[0].push_back("car"); types[0].push_back(vc->intType().getExpr()); selectors[0].push_back("cdr"); types[0].push_back(vc->stringExpr("list")); constructors.push_back("null"); Type list = vc->dataType("list", constructors, selectors, types); Expr x = vc->varExpr("x", vc->intType()); Expr y = vc->varExpr("y", list); vector args; args.push_back(x); args.push_back(y); Expr cons = vc->datatypeConsExpr("cons", args); Expr sel = vc->datatypeSelExpr("car", cons); IF_DEBUG(bool b =) check(vc, vc->eqExpr(sel, x)); DebugAssert(b, "Should be valid"); } delete vc; vc = ValidityChecker::create(); try { vector names; vector > constructors(2); vector > > selectors(2); vector > > types(2); vector returnTypes; names.push_back("list1"); selectors[0].resize(1); types[0].resize(1); constructors[0].push_back("cons1"); selectors[0][0].push_back("car1"); types[0][0].push_back(vc->intType().getExpr()); selectors[0][0].push_back("cdr1"); types[0][0].push_back(vc->stringExpr("list2")); names.push_back("list2"); selectors[1].resize(1); types[1].resize(1); constructors[1].push_back("cons2"); selectors[0][0].push_back("car2"); types[0][0].push_back(vc->intType().getExpr()); selectors[0][0].push_back("cdr2"); types[0][0].push_back(vc->stringExpr("list1")); vc->dataType(names, constructors, selectors, types, returnTypes); DebugAssert(false, "Typechecking exception expected"); } catch(const TypecheckException&) { // fall through } delete vc; vc = ValidityChecker::create(); { vector names; vector > constructors(2); vector > > selectors(2); vector > > types(2); vector returnTypes; names.push_back("list1"); selectors[0].resize(1); types[0].resize(1); constructors[0].push_back("cons1"); selectors[0][0].push_back("car1"); types[0][0].push_back(vc->intType().getExpr()); selectors[0][0].push_back("cdr1"); types[0][0].push_back(vc->stringExpr("list2")); names.push_back("list2"); selectors[1].resize(2); types[1].resize(2); constructors[1].push_back("cons2"); selectors[1][0].push_back("car2"); types[1][0].push_back(vc->intType().getExpr()); selectors[1][0].push_back("cdr2"); types[1][0].push_back(vc->stringExpr("list1")); constructors[1].push_back("null"); vc->dataType(names, constructors, selectors, types, returnTypes); Type list1 = returnTypes[0]; Type list2 = returnTypes[1]; Expr x = vc->varExpr("x", vc->intType()); Expr y = vc->varExpr("y", list2); Expr z = vc->varExpr("z", list1); vector args; args.push_back(x); args.push_back(y); Expr cons1 = vc->datatypeConsExpr("cons1", args); Expr isnull = vc->datatypeTestExpr("null", y); Expr hyp = vc->andExpr(vc->eqExpr(z, cons1), isnull); args.clear(); Expr null = vc->datatypeConsExpr("null", args); args.push_back(x); args.push_back(null); Expr cons1_2 = vc->datatypeConsExpr("cons1", args); IF_DEBUG(bool b =) check(vc, vc->impliesExpr(hyp, vc->eqExpr(z, cons1_2))); DebugAssert(b, "Should be valid"); } delete vc; vc = ValidityChecker::create(); { vector constructors; vector > selectors(2); vector > types(2); constructors.push_back("A"); constructors.push_back("B"); Type two = vc->dataType("two", constructors, selectors, types); Expr x = vc->varExpr("x", two); Expr y = vc->varExpr("y", two); Expr z = vc->varExpr("z", two); vector args; args.push_back(!vc->eqExpr(x,y)); args.push_back(!vc->eqExpr(y,z)); args.push_back(!vc->eqExpr(x,z)); IF_DEBUG(bool b =) check(vc, !vc->andExpr(args)); DebugAssert(b, "Should be valid"); } } catch(const Exception& e) { exitStatus = 1; cout << "*** Exception caught in test17(): \n" << e << endl; } delete vc; } void test18() { CLFlags flags = ValidityChecker::createFlags(); flags.setFlag("tcc", true); ValidityChecker *vc = ValidityChecker::create(flags); try { vector names; vector > constructors(3); vector > > selectors(3); vector > > types(3); vector returnTypes; names.push_back("nat"); selectors[0].resize(2); types[0].resize(2); constructors[0].push_back("zero"); constructors[0].push_back("succ"); selectors[0][1].push_back("pred"); types[0][1].push_back(vc->stringExpr("nat")); names.push_back("list"); selectors[1].resize(2); types[1].resize(2); constructors[1].push_back("cons"); selectors[1][0].push_back("car"); types[1][0].push_back(vc->stringExpr("tree")); selectors[1][0].push_back("cdr"); types[1][0].push_back(vc->stringExpr("list")); constructors[1].push_back("null"); names.push_back("tree"); selectors[2].resize(2); types[2].resize(2); constructors[2].push_back("leaf"); constructors[2].push_back("node"); selectors[2][1].push_back("data"); types[2][1].push_back(vc->stringExpr("nat")); selectors[2][1].push_back("children"); types[2][1].push_back(vc->stringExpr("list")); vc->dataType(names, constructors, selectors, types, returnTypes); Type nat = returnTypes[0]; Type listType = returnTypes[1]; Type tree = returnTypes[2]; Expr x = vc->varExpr("x", nat); vector args; Expr zero = vc->datatypeConsExpr("zero", args); Expr null = vc->datatypeConsExpr("null", args); Expr leaf = vc->datatypeConsExpr("leaf", args); vc->push(); try { check(vc, vc->notExpr(vc->eqExpr(zero, null))); DebugAssert(false, "Should have caught tcc exception"); } catch(const TypecheckException&) { } vc->pop(); args.push_back(vc->datatypeSelExpr("pred",x)); Expr spx = vc->datatypeConsExpr("succ", args); Expr spxeqx = vc->eqExpr(spx, x); vc->push(); try { check(vc, spxeqx); DebugAssert(false, "Should have caught tcc exception"); } catch(const TypecheckException&) { } vc->pop(); bool b = check(vc, vc->impliesExpr(vc->datatypeTestExpr("succ", x), spxeqx)); DebugAssert(b, "Should be valid"); b = check(vc, vc->orExpr(vc->datatypeTestExpr("zero", x), vc->datatypeTestExpr("succ", x))); DebugAssert(b, "Should be valid"); Expr y = vc->varExpr("y", nat); Expr xeqy = vc->eqExpr(x, y); args.clear(); args.push_back(x); Expr sx = vc->datatypeConsExpr("succ", args); args.clear(); args.push_back(y); Expr sy = vc->datatypeConsExpr("succ", args); Expr sxeqsy = vc->eqExpr(sx,sy); b = check(vc, vc->impliesExpr(xeqy, sxeqsy)); DebugAssert(b, "Should be valid"); b = check(vc, vc->notExpr(vc->eqExpr(sx, zero))); DebugAssert(b, "Should be valid"); b = check(vc, vc->impliesExpr(sxeqsy, xeqy)); DebugAssert(b, "Should be valid"); b = check(vc, vc->notExpr(vc->eqExpr(sx, x))); DebugAssert(b, "Should be valid"); } catch(const Exception& e) { exitStatus = 1; cout << "*** Exception caught in test18(): \n" << e << endl; } delete vc; } void test19() { CVC3::CLFlags flags = CVC3::ValidityChecker::createFlags(); flags.setFlag("dagify-exprs", false); CVC3::ValidityChecker* vc = CVC3::ValidityChecker::create(flags); try { CVC3::Type RealType=(vc->realType()); CVC3::Type IntType=(vc->intType()); CVC3::Type BoolType=(vc->boolType()); CVC3::Type PtrType=(RealType); CVC3::Type HeapType=(vc->arrayType(PtrType, RealType)); // ----------------- //ASSERT(FORALL (CVCi: REAL): (Hs[CVCi] = Ht[CVCi])); //QUERY(Hs[(t6 + (3 * 1))] = Ht[(t6 + (3 * 1))]); CVC3::Expr Ad = vc->boundVarExpr("CVCi", "CVCi", RealType); CVC3::Expr Hs = vc->varExpr("Hs", HeapType); CVC3::Expr Ht = vc->varExpr("Ht", HeapType); CVC3::Expr t6 = vc->varExpr("t6", RealType); vector Vars; Vars.push_back(Ad); // Body= (Hs[Ad] = Ht[Ad]) CVC3::Expr Body = vc->eqExpr(vc->readExpr(Hs, Ad), vc->readExpr(Ht, Ad)); //A = forall (~i:REAL): Body CVC3::Expr A = vc->forallExpr(Vars, Body); // Q = (Hs[t6] = Ht[t6]) CVC3::Expr Q = vc->eqExpr(vc->readExpr(Hs, t6), vc->readExpr(Ht, t6)); // ----------- CHECK A -> Q vc->push(); vc->assertFormula(A); cout<<"Checking formula "<query(Q); DebugAssert(Succ, "Expected valid formula"); } catch(const Exception& e) { exitStatus = 1; cout << "*** Exception caught in test19(): \n" << e << endl; } delete vc; } void test20() { ValidityChecker *vc = ValidityChecker::create(); try { vector names; vector > constructors(3); vector > > selectors(3); vector > > types(3); vector returnTypes; names.push_back("pair"); selectors[0].resize(1); types[0].resize(1); constructors[0].push_back("p"); selectors[0][0].push_back("p1"); types[0][0].push_back(vc->stringExpr("t1")); selectors[0][0].push_back("p2"); types[0][0].push_back(vc->stringExpr("t2")); names.push_back("t1"); selectors[1].resize(5); types[1].resize(5); constructors[1].push_back("a"); constructors[1].push_back("b"); constructors[1].push_back("c"); constructors[1].push_back("d"); constructors[1].push_back("e"); names.push_back("t2"); selectors[2].resize(1); types[2].resize(1); constructors[2].push_back("cons"); selectors[2][0].push_back("s0"); types[2][0].push_back(vc->bitvecType(2).getExpr()); selectors[2][0].push_back("s1"); types[2][0].push_back(vc->arrayType(vc->intType(), vc->subrangeType(vc->ratExpr(0), vc->ratExpr(0))).getExpr()); vc->dataType(names, constructors, selectors, types, returnTypes); DebugAssert(returnTypes[0].card() == CARD_FINITE, "Expected finite"); Unsigned size = returnTypes[0].sizeFinite(); Unsigned i = 0; for (; i < size; ++i) { cout << i << ": "; vc->printExpr(returnTypes[0].enumerateFinite(i)); } } catch(const Exception& e) { exitStatus = 1; cout << "*** Exception caught in test20(): \n" << e << endl; } delete vc; } void test21() { ValidityChecker *vc = ValidityChecker::create(); try { Type t = vc->realType(); Expr x1 = vc->varExpr("x",t); Expr x2 = vc->exprFromString("x"); cout << "x1: " << x1; cout << "\nx2: " << x2; DebugAssert(x1 == x2, "Expected x1 == x2"); Expr y1 = vc->varExpr("y",t); Expr y2 = vc->exprFromString("y"); cout << "\ny1: " << y1; cout << "\ny2: " << y2; DebugAssert(y1 == y2, "Expected y1 == y2"); Expr a1 = vc->gtExpr(x1,vc->ratExpr(0,1)); Expr a2 = vc->exprFromString("x > 0"); cout << "\na1: " << a1; cout << "\na2: " << a2; DebugAssert(a1 == a2, "Expected a1 == a2"); Expr b1 = vc->ltExpr(x1,y1); Expr b2 = vc->exprFromString ("x < y"); cout << "\nb1: " << b1; cout << "\nb2: " << b2; DebugAssert(b1 == b2, "Expected b1 == b2"); Expr e1 = a1 && b1; Expr e2 = vc->exprFromString("x > 0 AND x < y"); cout << "\ne1: " << e1; cout << "\ne2: " << e2; DebugAssert(e1 == e2, "Expected e1 == e2"); } catch(const Exception& e) { exitStatus = 1; cout << "*** Exception caught in test21(): \n" << e << endl; } delete vc; } void test22() { CLFlags flags = ValidityChecker::createFlags(); ValidityChecker* vc = ValidityChecker::create(flags); try { Type intType(vc->intType()); Type fType(vc->funType(intType,intType)); Op f(vc->createOp("f",fType)); Expr x(vc->varExpr("x",intType)); Expr fx(vc->exprFromString("f(x)")); Expr p(vc->exprFromString("FORALL (x:INT) : x < f(x)")); vector > patternvv; vector patternv; patternv.push_back(fx); patternvv.push_back(patternv); vc->setTriggers(p,patternv); DebugAssert( eqExprVecVecs(p.getTriggers(), patternvv), "Expected p.getTriggers() == patternvv: " + p.toString() ); vc->setTriggers(p,patternvv); DebugAssert( eqExprVecVecs(p.getTriggers(), patternvv), "Expected p.getTriggers() == patternvv: " + p.toString() ); // [chris 10/4/2009] Not sure why, but this fails // Expr q(vc->exprFromString("FORALL (x:INT) : PATTERN (f(x)) : x < f(x)")); // DebugAssert( eqExprVecVecs(q.getTriggers(), patternvv), // "Expected q.getTriggers() == patternvv" + q.toString()); vector vars; vars.push_back(x); Expr r(vc->forallExpr( vars, vc->ltExpr(x,fx), patternvv )); DebugAssert( eqExprVecVecs(r.getTriggers(), patternvv), "Expected r.getTriggers() == patternvv: " + r.toString() ); Expr s(vc->exprFromString("FORALL (x:INT) : x > f(x)")); vc->setTrigger(s,fx); std::vector > trigsvv = s.getTriggers(); DebugAssert( trigsvv.size() == 1, "Expected s.getTriggers().size() == 1: " + trigsvv.size() ); std::vector trigsv = trigsvv[0]; DebugAssert( trigsv.size() == 1, "Expected s.getTriggers()[0].size() == 1: " + trigsv.size() ); DebugAssert( trigsv[0] == fx, "Expected s.getTriggers()[0][0] == fx: " + (trigsv[0].toString()) ); Expr t(vc->exprFromString("FORALL (x:INT) : x > f(x)")); vc->setMultiTrigger(t,patternv); trigsvv = t.getTriggers(); DebugAssert( trigsvv.size() == 1, "Expected t.getTriggers().size() == 1: " + trigsvv.size() ); trigsv = trigsvv[0]; DebugAssert( trigsv.size() == 1, "Expected t.getTriggers()[0].size() == 1: " + trigsv.size() ); DebugAssert( trigsv[0] == fx, "Expected t.getTriggers()[0][0] == fx: " + (trigsv[0].toString()) ); } catch(const Exception& e) { exitStatus = 1; cout << "*** Exception caught in test22(): \n" << e << endl; } delete vc; } void test23() { CLFlags flags = ValidityChecker::createFlags(); ValidityChecker* vc = ValidityChecker::create(flags); try { Type intType(vc->intType()); Type fType(vc->funType(intType,intType)); Expr x(vc->varExpr("x",intType)); Expr y(vc->varExpr("y",intType)); Expr a(vc->varExpr("a",intType)); Expr b(vc->varExpr("b",intType)); Expr s(vc->exprFromString("x < y")); Expr t(vc->exprFromString("a < b")); cout << "s=" << s << "\nt=" << t << "\n"; std::vector oldExprs, newExprs; oldExprs.push_back(x); oldExprs.push_back(y); newExprs.push_back(a); newExprs.push_back(b); Expr u(s.substExpr(oldExprs,newExprs)); cout << "u=" << u << "\n"; DebugAssert( t == u, "Expected t==u" ); } catch(const Exception& e) { exitStatus = 1; cout << "*** Exception caught in test23(): \n" << e << endl; } delete vc; } void test24() { CLFlags flags = ValidityChecker::createFlags(); ValidityChecker* vc = ValidityChecker::create(flags); try { Type intType(vc->intType()); Type aType(vc->arrayType(intType,intType)); Expr a(vc->varExpr("a",aType)); Expr x(vc->varExpr("x",intType)); Expr ax(vc->exprFromString("a[x]")); Expr p(vc->exprFromString("FORALL (x:INT) : PATTERN (a[x]) : x < a[x]")); cout << p << "\n"; vector > pTriggers(p.getTriggers()); DebugAssert( pTriggers.size() == 1, "Expected one trigger set. Found: " + int2string(pTriggers.size())); DebugAssert( pTriggers[0].size() == 1, "Expected one trigger. Found: " + int2string( pTriggers[0].size())); /* We can't check that the trigger == ax, because x will have * been replaced with a bvar */ DebugAssert( pTriggers[0][0].getKind() == READ, "Expected READ expression. Found: " + pTriggers[0][0].getKind()); DebugAssert( pTriggers[0][0][0] == a, "Expected read on array: " + a.toString() + "\nFound: " + pTriggers[0][0][0].toString() ); Expr aPrime(vc->varExpr("a'",aType)); Expr axPrime(vc->exprFromString("a'[x]")); ExprHashMap substMap; substMap.insert(a,aPrime); Expr q(p.substExpr(substMap)); cout << q << "\n"; vector > qTriggers(q.getTriggers()); DebugAssert( qTriggers.size() == 1, "Expected one trigger set. Found: " + int2string(qTriggers.size())); DebugAssert( qTriggers[0].size() == 1, "Expected one trigger. Found: " + int2string( qTriggers[0].size())); DebugAssert( qTriggers[0][0].getKind() == READ, "Expected READ expression. Found: " + qTriggers[0][0].getKind()); DebugAssert( qTriggers[0][0][0] == aPrime, "Expected read on array: " + aPrime.toString() + "\nFound: " + qTriggers[0][0][0].toString() ); } catch(const Exception& e) { exitStatus = 1; cout << "*** Exception caught in test24(): \n" << e << endl; } delete vc; } void test25() { CLFlags flags = ValidityChecker::createFlags(); ValidityChecker* vc = ValidityChecker::create(flags); try { Type realType(vc->realType()); Expr x = vc->ratExpr("-0.1"); cout << "-0.1: " << x << endl; Expr y = vc->ratExpr("-1/10"); cout << "-1/10: " << y << endl; Expr z = vc->ratExpr("-1","10",10); cout << "-1 over 10: " << z << endl; Expr w = vc->ratExpr(-1,10); cout << "-1 over 10 (ints): " << w << endl; DebugAssert(x == y && y == z && z == w, "Error in rational constants"); } catch(const Exception& e) { exitStatus = 1; cout << "*** Exception caught in test25(): \n" << e << endl; } delete vc; } void test26() { CLFlags flags = ValidityChecker::createFlags(); ValidityChecker* vc = ValidityChecker::create(flags); try { Type bvType(vc->bitvecType(32)); Expr x = vc->varExpr("x", bvType); Expr e1 = vc->newFixedConstWidthLeftShiftExpr(x, 16); Expr e2 = vc->newBVSHL(x, vc->newBVConstExpr(16, 32)); bool b = check(vc, vc->eqExpr(e1, e2)); DebugAssert(b, "Should be valid"); e1 = vc->newFixedRightShiftExpr(x, 16); e2 = vc->newBVLSHR(x, vc->newBVConstExpr(16, 32)); b = check(vc, vc->eqExpr(e1, e2)); DebugAssert(b, "Should be valid"); e2 = vc->newBVASHR(x, vc->newBVConstExpr(16, 32)); b = check(vc, vc->eqExpr(e1, e2)); DebugAssert(!b, "Should be invalid"); } catch(const Exception& e) { exitStatus = 1; cout << "*** Exception caught in test26(): \n" << e << endl; } delete vc; } int main(int argc, char** argv) { int regressLevel = 3; if (argc > 1) regressLevel = atoi(argv[1]); cout << "Running API test, regress level = " << regressLevel << endl; exitStatus = 0; try { cout << "\n}\ntest26(): {" << endl; test26(); cout << "\ntest(): {" << endl; test(); cout << "\n}\ntest1(): {" << endl; test1(); cout << "\n}\n\ntest2(): {" << endl; test2(); cout << "\n}\n\ntest3(): {" << endl; test3(); cout << "\n}\n\ntest4(): {" << endl; test4(); if (regressLevel > 0) { cout << "\n}\n\ntest5(): {" << endl; test5(); } cout << "\n}\n\ntest6(): {" << endl; test6(); cout << "\n}\n\ntest7(): {" << endl; test7(); cout << "\n}\n\ntest8(): {" << endl; test8(); cout << "\n}\n\ntest9(" << 10*regressLevel+10 << "): {" << endl; test9(10*regressLevel+10); cout << "\nbvtest9(): {" << endl; bvtest9(regressLevel*3+2); cout << "\n}" << endl; // Test for obvious memory leaks int limit = 100 * regressLevel+10; for(int i=0; i 1) { cout << "\n}\ntestgeorge1(): {" << endl; testgeorge1(); cout << "\n}\ntestgeorge2(): {" << endl; testgeorge2(); cout << "\n}\ntestgeorge3(): {" << endl; testgeorge3(); cout << "\n}\ntestgeorge4(): {" << endl; testgeorge4(); cout << "\n}\ntestgeorge5(): {" << endl; testgeorge5(); } cout << "\n}" << endl; } catch(const Exception& e) { cout << "*** Exception caught: \n" << e << endl; exitStatus = 1; } if(exitStatus == 0) cout << "Program exits successfully." << endl; else cout << "Program exits with error status = " << exitStatus << "." << endl; return exitStatus; } cvc3-2.4.1/LICENSE.in0000664000175400017540000000431511166777254013713 0ustar mdetersmdeters/*!\page LICENSE LICENSE Copyright (C) 2003-2009 by the Board of Trustees of Leland Stanford Junior University, New York University, and the University of Iowa, hereafter designated as the Copyright Owners. All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: * Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. * Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. * Neither the names of the Copyright Owners nor the names of any contributors may be used to endorse or promote products derived from this software without specific prior written permission. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT OWNERS AND CONTRIBUTORS ''AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. Note: The following files contain code whose copyright does not belong to the Copyright Owners. However, separate copyright notices in these files give express permission to copy, use, modify, sell, or distribute the code. Please see the copyright notices in the individual files for details.
src/include/fdstream.h
src/include/hash_map.h
src/include/hash_fun.h
src/include/hash_set.h
src/include/hash_table.h
src/sat/minisat_varorder.h
src/sat/minisat_solver.cpp
src/sat/minisat_heap.h
src/sat/minisat_types.h
src/sat/minisat_solver.h
src/sat/minisat_global.h
@LICENSE_INFO@ */ cvc3-2.4.1/testc/0000775000175400017540000000000011630011320013363 5ustar mdetersmdeterscvc3-2.4.1/testc/main.c0000664000175400017540000004442311520105445014474 0ustar mdetersmdeters/////////////////////////////////////////////////////////////////////////////// // // // File: main.cpp // // Author: Clark Barrett // // Created: Sat Apr 19 01:47:47 2003 // // // /////////////////////////////////////////////////////////////////////////////// #include "c_interface.h" #include #include #define TRUE 1 #define FALSE 0 #define FatalAssert(b,msg) \ if (!(b)) { \ fprintf(stderr, "Assertion Failure: %s\n", msg); \ exit(1); } // Check whether e is valid void check_error(char* msg) { if(vc_get_error_status() < 0) { fprintf(stderr, "%s\n", msg); fprintf(stderr, "%s\n", vc_get_error_string()); exit(1); } } int check(VC vc, Expr e) { int res; printf("Query: "); vc_printExpr(vc, e); check_error("Error occured during query"); res = vc_query(vc, e); switch (res) { case 0: printf("Invalid\n\n"); break; case 1: printf("Valid\n\n"); break; } return res; } // Make a new assertion void newAssertion(VC vc, Expr e) { // Testing printing to file descriptor. Turns out, we need to flush // the file in C before printing through C++ (they apparently use // different buffers, and text may come out of order). printf("Assert: "); fflush(stdout); vc_printExprFile(vc, e, 1); vc_assertFormula(vc, e); check_error("Error occured during assertion"); } void test1() { Flags flags = vc_createFlags(); VC vc; Type b; Expr p, np, e; Type r, real2real; Expr x, y, fx, fy, xeqy, fxeqfy, w, z, weqx, yeqz, one, two, xeqone, xeqtwo, simp, simp2; Op f; Expr* assertions; int i, size, res; Kind k; vc_setStringFlag(flags, "dump-log", ".testc1.cvc"); vc_setStrSeqFlag(flags, "trace", "pushpop", 1); vc = vc_createValidityChecker(flags); // Check p OR ~p b = vc_boolType(vc); p = vc_varExpr(vc, "p", vc_boolType(vc)); np = vc_notExpr(vc, p); e = vc_orExpr(vc, p, np); res = check(vc, e); FatalAssert(res == 1, "Expected Valid"); FatalAssert(vc_getKind(e) == OR, "Expected TRUE for kind check"); FatalAssert(vc_getKind(vc_getType(vc, e)) == BOOLEAN, "Expected TRUE for type kind check"); vc_deleteType(b); vc_deleteExpr(p); vc_deleteExpr(np); vc_deleteExpr(e); /* Check x = y -> f(x) = f(y) */ r = vc_realType(vc); x = vc_varExpr(vc, "x", r); y = vc_varExpr(vc, "y", r); real2real = vc_funType1(vc, r, r); f = vc_createOp(vc, "f", real2real); fx = vc_funExpr1(vc, f, x); fy = vc_funExpr1(vc, f, y); xeqy = vc_eqExpr(vc, x, y); fxeqfy = vc_eqExpr(vc, fx, fy); e = vc_impliesExpr(vc, xeqy, fxeqfy); res = check(vc, e); FatalAssert(res == 1, "Expected Valid"); vc_deleteType(real2real); vc_deleteExpr(e); // Check f(x) = f(y) -> x = y e = vc_impliesExpr(vc, fxeqfy, xeqy); vc_push(vc); res = check(vc, e); FatalAssert(res == 0, "Expected Invalid"); vc_deleteExpr(e); // Get counter-example printf("Stack level: %d\n", vc_stackLevel(vc)); printf("Counter-example:\n"); assertions = vc_getCounterExample(vc, &size); for (i = 0; i < size; ++i) { vc_printExpr(vc, assertions[i]); } vc_deleteVector(assertions); printf("End of counter-example\n\n"); printf("Concrete model:\n"); assertions = vc_getConcreteModel(vc, &size); for (i = 0; i < size; ++i) { vc_printExpr(vc, assertions[i]); } vc_deleteVector(assertions); printf("End of concrete model\n\n"); // Reset to initial scope printf("Resetting\n"); vc_pop(vc); printf("Stack level: %d\n\n", vc_stackLevel(vc)); // Check w = x & x = y & y = z & f(x) = f(y) & x = 1 & z = 2 w = vc_varExpr(vc, "w", r); z = vc_varExpr(vc, "z", r); printf("Push Scope\n\n"); vc_push(vc); weqx = vc_eqExpr(vc, w, x); yeqz = vc_eqExpr(vc, y, z); one = vc_ratExpr(vc, 1, 1); two = vc_ratExpr(vc, 2, 1); xeqone = vc_eqExpr(vc, x, one); xeqtwo = vc_eqExpr(vc, x, two); newAssertion(vc, weqx); newAssertion(vc, xeqy); newAssertion(vc, yeqz); newAssertion(vc, fxeqfy); newAssertion(vc, xeqone); newAssertion(vc, xeqtwo); printf("\nsimplify(w) = "); simp = vc_simplify(vc, w); char* str = vc_printExprString(vc, simp); printf("%s\n", str); vc_deleteString(str); printf("Inconsistent?: %d\n", vc_inconsistent(vc, &assertions, &size)); check_error("Error occured during inconsistency check"); printf("Assumptions Used:\n"); for (i = 0; i < size; ++i) { vc_printExpr(vc, assertions[i]); } vc_deleteVector(assertions); printf("\nPop Scope\n\n"); vc_pop(vc); printf("simplify(w) = "); simp2 = vc_simplify(vc, w); vc_printExpr(vc, simp2); printf("\n"); printf("Inconsistent?: %d\n", vc_inconsistent(vc, &assertions, &size)); vc_deleteVector(assertions); vc_deleteType(r); vc_deleteExpr(x); vc_deleteExpr(y); vc_deleteOp(f); vc_deleteExpr(fx); vc_deleteExpr(fy); vc_deleteExpr(xeqy); vc_deleteExpr(fxeqfy); vc_deleteExpr(w); vc_deleteExpr(z); vc_deleteExpr(weqx); vc_deleteExpr(yeqz); vc_deleteExpr(one); vc_deleteExpr(two); vc_deleteExpr(xeqone); vc_deleteExpr(xeqtwo); vc_deleteExpr(simp); vc_deleteExpr(simp2); vc_destroyValidityChecker(vc); vc_deleteFlags(flags); } void test2() { VC vc = vc_createValidityChecker(NULL); // Check x = y -> g(x,y) = g(y,x) Type r = vc_realType(vc); Expr x = vc_varExpr(vc, "x", r); Expr y = vc_varExpr(vc, "y", r); Type realxreal2real = vc_funType2(vc, r, r, r); Op g = vc_createOp(vc, "g", realxreal2real); Expr gxy = vc_funExpr2(vc, g, x, y); Expr gyx = vc_funExpr2(vc, g, y, x); Expr xeqy = vc_eqExpr(vc, x, y); Expr gxyeqgyx = vc_eqExpr(vc, gxy, gyx); Expr e = vc_impliesExpr(vc, xeqy, gxyeqgyx); Type v[2]; Op h; Expr hxy, hyx, hxyeqhyx; int res; res = check(vc, e); FatalAssert(res == 1, "Expected Valid"); vc_deleteType(realxreal2real); vc_deleteOp(g); vc_deleteExpr(gxy); vc_deleteExpr(gyx); vc_deleteExpr(gxyeqgyx); vc_deleteExpr(e); v[0] = r; v[1] = r; realxreal2real = vc_funTypeN(vc, v, r, 2); h = vc_createOp(vc, "h", realxreal2real); hxy = vc_funExpr2(vc, h, x, y); hyx = vc_funExpr2(vc, h, y, x); hxyeqhyx = vc_eqExpr(vc, hxy, hyx); e = vc_impliesExpr(vc, xeqy, hxyeqhyx); res = check(vc, e); FatalAssert(res == 1, "Expected Valid"); vc_deleteType(r); vc_deleteExpr(x); vc_deleteExpr(y); vc_deleteType(realxreal2real); vc_deleteExpr(hxy); vc_deleteExpr(hxyeqhyx); vc_deleteExpr(e); vc_destroyValidityChecker(vc); } /* void test3() */ /* { */ /* VC vc = vc_createValidityChecker(NULL); */ /* // Check x = y -> g(x,y) = g(y,x) */ /* Type r = vc_realType(vc); */ /* Expr x = vc_varExpr(vc, "x", r); */ /* Expr y = vc_varExpr(vc, "y", r); */ /* Type realxreal2real = vc_funType2(vc, r, r, r); */ /* Op g = vc_createOp(vc, "g", realxreal2real); */ /* Expr gxy = vc_parseExpr(vc, "g(x,y)"); */ /* Expr gxy2; */ /* vc_printExpr(vc, gxy); */ /* gxy2 = vc_funExpr2(vc, g, x, y); */ /* vc_printExpr(vc, gxy2); */ /* FatalAssert((gxy == gxy2), "Should be equal"); */ /* vc_deleteType(r); */ /* vc_deleteExpr(x); */ /* vc_deleteExpr(y); */ /* vc_deleteType(realxreal2real); */ /* vc_deleteOp(g); */ /* vc_deleteExpr(gxy); */ /* vc_deleteExpr(gxy2); */ /* vc_destroyValidityChecker(vc); */ /* } */ void test4(int regressLevel) { VC vc = vc_createValidityChecker(NULL); // Check x >= 10 /\ x >= 40 /\ y <= 0 --> // x >= 1 /\ y < 10 Type r = vc_realType(vc); Expr x = vc_varExpr(vc, "x", r); Expr y = vc_varExpr(vc, "y", r); Expr ten = vc_ratExpr(vc, 10, 1); Expr ge = vc_geExpr(vc, x, ten); Expr forty = vc_ratExpr(vc, 40, 1); Expr ge2 = vc_geExpr(vc, x, forty); Expr zero = vc_ratExpr(vc, 0, 1); Expr ge3 = vc_leExpr(vc, y, zero); Expr children[3]; Expr hyp, one, conc, query; int i; children[0] = ge; children[1] = ge2; children[2] = ge3; hyp = vc_andExprN(vc, children, 3); vc_deleteType(r); vc_deleteExpr(ge); vc_deleteExpr(forty); vc_deleteExpr(ge2); vc_deleteExpr(zero); vc_deleteExpr(ge3); one = vc_ratExpr(vc, 1, 1); ge = vc_geExpr(vc, x, one); ge2 = vc_ltExpr(vc, y, ten); conc = vc_andExpr(vc, ge, ge2); query = vc_impliesExpr(vc, hyp, conc); vc_deleteExpr(x); vc_deleteExpr(y); vc_deleteExpr(ten); vc_deleteExpr(hyp); vc_deleteExpr(one); vc_deleteExpr(ge); vc_deleteExpr(ge2); vc_deleteExpr(conc); for (i = 0; i < 100*regressLevel; i++) vc_query(vc, query); vc_deleteExpr(query); vc_destroyValidityChecker(vc); } void test5() { Flags flags = vc_createFlags(); VC vc; Type r; Expr x, xEQx, p; // vc_setBoolFlag(flags, "proofs", TRUE); vc = vc_createValidityChecker(flags); r = vc_realType(vc); x = vc_varExpr(vc, "x", r); xEQx = vc_eqExpr(vc, x, x); vc_query(vc, xEQx); // p = vc_getProof(vc); // vc_printExpr(vc, p); vc_deleteType(r); vc_deleteExpr(x); vc_deleteExpr(xEQx); // vc_deleteExpr(p); vc_destroyValidityChecker(vc); vc_deleteFlags(flags); } void test6() { Flags flags = vc_createFlags(); VC vc; Expr p, p3, p32; char *x; // vc_setBoolFlag(flags, "proofs", 1); vc_setBoolFlag(flags, "dagify-exprs", 0); vc = vc_createValidityChecker(flags); // p = vc_getProofOfFile(vc,"benchmarks/add1.cvc"); check_error("Failed to check file"); // vc_deleteExpr(p); vc_destroyValidityChecker(vc); vc_deleteFlags(flags); /* p3 = getChild(p,3); */ /* p32 = getChild(p3,2); */ /* if (isLambda(p32)) */ /* printf("The expression is Lambda\n"); */ /* else */ /* printf("The expression is not Lambda\n"); */ /* x = exprString(p32); */ /* printf("Test expr,%s",x);*/ } int printImpliedLiterals(VC vc) { int count = 0; Expr impLit = vc_getImpliedLiteral(vc); printf("Implied Literals:\n"); while (impLit) { ++count; vc_printExpr(vc, impLit); vc_deleteExpr(impLit); impLit = vc_getImpliedLiteral(vc); } return count; } void test7() { VC vc = vc_createValidityChecker(NULL); Type r = vc_realType(vc); Type b = vc_boolType(vc); Expr x = vc_varExpr(vc, "x", r); Expr y = vc_varExpr(vc, "y", r); Expr z = vc_varExpr(vc, "z", r); Type real2real = vc_funType1(vc, r, r); Type real2bool = vc_funType1(vc, r, b); Op f = vc_createOp(vc, "f", real2real); Op p = vc_createOp(vc, "p", real2bool); Expr fx = vc_funExpr1(vc, f, x); Expr fy = vc_funExpr1(vc, f, y); Expr fxeqfy = vc_eqExpr(vc, fx, fy); Expr px = vc_funExpr1(vc, p, x); Expr py = vc_funExpr1(vc, p, y); Expr xeqy = vc_eqExpr(vc, x, y); Expr yeqx = vc_eqExpr(vc, y, x); Expr xeqz = vc_eqExpr(vc, x, z); Expr zeqx = vc_eqExpr(vc, z, x); Expr yeqz = vc_eqExpr(vc, y, z); Expr zeqy = vc_eqExpr(vc, z, y); Expr notxeqz = vc_notExpr(vc, xeqz); int c; vc_registerAtom(vc, xeqy); vc_registerAtom(vc, yeqx); vc_registerAtom(vc, xeqz); vc_registerAtom(vc, zeqx); vc_registerAtom(vc, yeqz); vc_registerAtom(vc, zeqy); vc_registerAtom(vc, px); vc_registerAtom(vc, py); vc_registerAtom(vc, fxeqfy); printf("Push\n"); vc_push(vc); printf("Assert x = y\n"); vc_assertFormula(vc, xeqy); c = printImpliedLiterals(vc); FatalAssert(c==3,"Implied literal error 0"); printf("Push\n"); vc_push(vc); printf("Assert x /= z\n"); vc_assertFormula(vc, notxeqz); c = printImpliedLiterals(vc); FatalAssert(c==4,"Implied literal error 1"); printf("Pop\n"); vc_pop(vc); printf("Pop\n"); vc_pop(vc); vc_deleteExpr(notxeqz); vc_deleteExpr(zeqy); vc_deleteExpr(yeqz); vc_deleteExpr(zeqx); vc_deleteExpr(xeqz); vc_deleteExpr(yeqx); vc_deleteExpr(xeqy); vc_deleteExpr(py); vc_deleteExpr(px); vc_deleteExpr(fxeqfy); vc_deleteExpr(fy); vc_deleteExpr(fx); vc_deleteOp(p); vc_deleteOp(f); vc_deleteType(real2bool); vc_deleteType(real2real); vc_deleteExpr(z); vc_deleteExpr(y); vc_deleteExpr(x); vc_deleteType(b); vc_deleteType(r); vc_destroyValidityChecker(vc); } void test8 (void) { Flags flags = vc_createFlags(); /* vc_setStrSeqFlag(flags, "trace", "pushpop", 1); */ /* vc_setStrSeqFlag(flags, "trace", "assertLit", 1); */ /* vc_setStrSeqFlag(flags, "trace", "assertFactCore", 1); */ /* vc_setStrSeqFlag(flags, "trace", "assertFormula", 1); */ VC vc = vc_createValidityChecker (flags); Type bv32 = vc_bvType (vc, 32); Expr zero = vc_bvConstExprFromInt (vc, 32, 0); Expr one = vc_bvConstExprFromInt (vc, 32, 1); Expr a = vc_varExpr (vc, "a", bv32); Expr three = vc_bvConstExprFromInt (vc, 32, 3); Expr prod = vc_bvMultExpr (vc, 32, a, three); { Expr a64 = vc_bvSignExtend (vc, a, 64); Expr three64 = vc_bvSignExtend (vc, three, 64); Expr prod64 = vc_bvMultExpr (vc, 64, a64, three64); Expr max = vc_bvConstExprFromInt (vc, 32, 2147483647); Expr min = vc_bvConstExprFromInt (vc, 32, (-2147483647 - 1)); Expr prod64_sge_min = vc_bvSGeExpr (vc, prod64, min); Expr prod64_sle_max = vc_bvSLeExpr (vc, prod64, max); Expr prod64_sge_min_and_sle_max = vc_andExpr (vc, prod64_sge_min, prod64_sle_max); vc_assertFormula (vc, prod64_sge_min_and_sle_max); } Expr D4 = vc_varExpr (vc, "D4", bv32); { Expr cond = vc_bvSLtExpr (vc, a, prod); Expr test = vc_iteExpr (vc, cond, one, zero); Expr D4_eq_test = vc_eqExpr (vc, D4, test); vc_assertFormula (vc, D4_eq_test); } Expr D6 = vc_varExpr (vc, "D6", bv32); { Expr cond = vc_bvSLeExpr (vc, a, prod); Expr test = vc_iteExpr (vc, cond, one, zero); Expr D6_eq_test = vc_eqExpr (vc, D6, test); vc_assertFormula (vc, D6_eq_test); } vc_push (vc); vc_pop (vc); vc_push (vc); { Expr cond = vc_bvSLtExpr (vc, a, zero); Expr test = vc_iteExpr (vc, cond, one, zero); Expr test_eq_one = vc_eqExpr (vc, test, one); vc_assertFormula (vc, test_eq_one); vc_push (vc); { Expr D4_eq_one = vc_eqExpr (vc, D4, one); vc_query (vc, D4_eq_one); } vc_pop (vc); vc_push (vc); vc_pop (vc); vc_push (vc); vc_pop (vc); } vc_pop (vc); { Expr cond = vc_eqExpr (vc, a, zero); Expr test = vc_iteExpr (vc, cond, one, zero); Expr test_eq_one = vc_eqExpr (vc, test, one); vc_assertFormula (vc, test_eq_one); vc_push (vc); vc_pop (vc); { Expr zero_eq_one = vc_eqExpr (vc, zero, one); vc_query (vc, zero_eq_one); } } vc_destroyValidityChecker(vc); } void test9 (void) { VC vc = vc_createValidityChecker (((void *) 0)); Type bv32 = vc_bvType (vc, 32); Expr zero = vc_bvConstExprFromInt (vc, 32, 0); Expr one = vc_bvConstExprFromInt (vc, 32, 1); Expr a = vc_varExpr (vc, "a", bv32); Expr three = vc_bvConstExprFromInt (vc, 32, 3); Expr three64 = vc_bvSignExtend (vc, three, 64); Expr a64 = vc_bvSignExtend (vc, a, 64); Expr prod64 = vc_bvMultExpr (vc, 64, a64, three64); Expr min = vc_bvConstExprFromInt (vc, 32, (-2147483647 - 1)); Expr max = vc_bvConstExprFromInt (vc, 32, 2147483647); Expr prod64_sge_min = vc_bvSGeExpr (vc, prod64, min); Expr prod64_sle_max = vc_bvSLeExpr (vc, prod64, max); Expr prod64_sge_min_and_sle_max = vc_andExpr (vc, prod64_sge_min, prod64_sle_max); vc_assertFormula (vc, prod64_sge_min_and_sle_max); Expr D3 = vc_varExpr (vc, "D3", bv32); Expr prod = vc_bvMultExpr (vc, 32, a, three); Expr D3_eq_prod = vc_eqExpr (vc, D3, prod); vc_assertFormula (vc, D3_eq_prod); Expr D4 = vc_varExpr (vc, "D4", bv32); Expr D3_sle_a_cond = vc_bvSLeExpr (vc, D3, a); Expr D3_sle_a_expr = vc_iteExpr (vc, D3_sle_a_cond, one, zero); Expr D4_eq_D3_sle_a_expr = vc_eqExpr (vc, D4, D3_sle_a_expr); vc_assertFormula (vc, D4_eq_D3_sle_a_expr); Expr D6 = vc_varExpr (vc, "D6", bv32); Expr D3_slt_a_cond = vc_bvSLtExpr (vc, D3, a); Expr D3_slt_a_expr = vc_iteExpr (vc, D3_slt_a_cond, one, zero); Expr D6_eq_D3_slt_a_expr = vc_eqExpr (vc, D6, D3_slt_a_expr); vc_assertFormula (vc, D6_eq_D3_slt_a_expr); Expr zero_lt_a = vc_bvSLtExpr (vc, zero, a); vc_assertFormula (vc, zero_lt_a); Expr D4_eq_one = vc_eqExpr (vc, D4, one); Expr not_D4_eq_one = vc_notExpr (vc, D4_eq_one); vc_query (vc, not_D4_eq_one); Expr D6_eq_one = vc_eqExpr (vc, D6, one); Expr not_D6_eq_one = vc_notExpr (vc, D6_eq_one); vc_query (vc, not_D6_eq_one); vc_destroyValidityChecker(vc); } void test10() { Flags flags = vc_createFlags(); VC vc = vc_createValidityChecker(flags); Type a = vc_createType(vc, "a"); Type aa = vc_funType1(vc, a, a); Op f1 = vc_createOp(vc, "f", aa); Type aa2; Op f2 = vc_lookupOp(vc, "f", &aa2); FatalAssert(f2 != NULL, "Expected f2 not NULL"); FatalAssert(f1 == f2, "Expected equal"); Expr x = vc_varExpr(vc, "x", a); Expr f1x = vc_funExpr1(vc, f1, x); Expr f2x = vc_funExpr1(vc, f2, x); Expr eq = vc_eqExpr(vc, f1x, f2x); int res = vc_query(vc, eq); printf("eq: %d\n", res); vc_destroyValidityChecker(vc); } void test11() { Flags flags = vc_createFlags(); VC vc = vc_createValidityChecker(flags); Type a = vc_createType(vc, "a"); Type aa = vc_funType1(vc, a, a); Op f = vc_createOp(vc, "f", aa); Expr x = vc_varExpr(vc, "x", a); Expr fx = vc_funExpr1(vc, f, x); Expr ffx = vc_funExpr1(vc, f, fx); Expr e = vc_eqExpr(vc, x, fx); Expr expectE = vc_eqExpr(vc, fx, ffx); Expr newE = vc_substExpr(vc, e, &x, 1, &fx, 1); FatalAssert(expectE == newE, "Expected equal"); vc_destroyValidityChecker(vc); } int main(int argc, char** argv) { int regressLevel = 2; if (argc > 1) regressLevel = atoi(argv[1]); printf("Running C API test, regress level = %d\n", regressLevel); printf("\ntest1() {\n"); test1(); check_error("test1"); printf("\n}\ntest2() {\n"); test2(); check_error("test2"); /* TODO: implement parseExpr */ /* test3(); */ /* check_error("test3"); */ printf("\n}\ntest4() {\n"); test4(regressLevel); check_error("test4"); printf("\n}\ntest5() {\n"); test5(); check_error("test5"); if (regressLevel > 0) { printf("\n}\ntest6() {\n"); test6(); check_error("test6"); } printf("\n}\ntest7() {\n"); test7(); check_error("test7"); if (regressLevel > 0) { printf("\n}\ntest8() {\n"); test8(); check_error("test8"); printf("\n}\ntest9() {\n"); test9(); check_error("test9"); } printf("\n}"); printf("\ntest10() {\n"); test10(); printf("\n}"); printf("\ntest11() {\n"); test11(); printf("\n}\n"); return 0; } cvc3-2.4.1/testc/Makefile0000664000175400017540000000201411273617151015041 0ustar mdetersmdeters################################################## # About this Makefile # # This Makefile depends on srcMakefile.opts ################################################## EXECUTABLE = testc LD_LIBS = -l$(PROJECTNAME) BASE_DIR = $(TOP)/testc OTHER_OBJ = $(OBJ_DIR)/main.o OTHER_DEPENDENCIES = $(TOP)/lib/lib$(PROJECTNAME).$(LIB_SUFFIX) MY_DEPEND = 1 TRANSIENT = $(OBJ_DIR)/main.o include ../Makefile.local $(OBJ_DIR)/main.o : main.c @mkdir -p $(OBJ_DIR) gcc $(CXXFLAGS) -g -I../src/include -o $(OBJ_DIR)/main.o -c main.c depend: main.c @mkdir -p $(OBJ_DIR) @-rm -f $(MAKEFILE_DEPS) $(MAKEFILE_DEPS_TMP) $(MAKEFILE_DEPS_TMP2) @echo '# Dependencies for C files' >> $(MAKEFILE_DEPS_TMP) @echo >> $(MAKEFILE_DEPS_TMP) @echo "Making dependencies for $(SRC)" gcc -M -g -I../src/include main.c >> $(MAKEFILE_DEPS_TMP) @echo >> $(MAKEFILE_DEPS_TMP) @sed -e '/^.*:/ s#^#$(OBJ_DIR)/#' < $(MAKEFILE_DEPS_TMP) > $(MAKEFILE_DEPS_TMP2) @cat $(MAKEFILE_DEPS_TMP2) > $(MAKEFILE_DEPS) @rm -f $(MAKEFILE_DEPS_TMP) $(MAKEFILE_DEPS_TMP2) cvc3-2.4.1/config.sub0000775000175400017540000010115311154061001014227 0ustar mdetersmdeters#! /bin/sh # Configuration validation subroutine script. # Copyright (C) 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999, # 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008 # Free Software Foundation, Inc. timestamp='2008-01-16' # This file is (in principle) common to ALL GNU software. # The presence of a machine in this file suggests that SOME GNU software # can handle that machine. It does not imply ALL GNU software can. # # This file is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program; if not, write to the Free Software # Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, MA # 02110-1301, USA. # # As a special exception to the GNU General Public License, if you # distribute this file as part of a program that contains a # configuration script generated by Autoconf, you may include it under # the same distribution terms that you use for the rest of that program. # Please send patches to . Submit a context # diff and a properly formatted ChangeLog entry. # # Configuration subroutine to validate and canonicalize a configuration type. # Supply the specified configuration type as an argument. # If it is invalid, we print an error message on stderr and exit with code 1. # Otherwise, we print the canonical config type on stdout and succeed. # This file is supposed to be the same for all GNU packages # and recognize all the CPU types, system types and aliases # that are meaningful with *any* GNU software. # Each package is responsible for reporting which valid configurations # it does not support. The user should be able to distinguish # a failure to support a valid configuration from a meaningless # configuration. # The goal of this file is to map all the various variations of a given # machine specification into a single specification in the form: # CPU_TYPE-MANUFACTURER-OPERATING_SYSTEM # or in some cases, the newer four-part form: # CPU_TYPE-MANUFACTURER-KERNEL-OPERATING_SYSTEM # It is wrong to echo any other type of specification. me=`echo "$0" | sed -e 's,.*/,,'` usage="\ Usage: $0 [OPTION] CPU-MFR-OPSYS $0 [OPTION] ALIAS Canonicalize a configuration name. Operation modes: -h, --help print this help, then exit -t, --time-stamp print date of last modification, then exit -v, --version print version number, then exit Report bugs and patches to ." version="\ GNU config.sub ($timestamp) Copyright (C) 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008 Free Software Foundation, Inc. This is free software; see the source for copying conditions. There is NO warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE." help=" Try \`$me --help' for more information." # Parse command line while test $# -gt 0 ; do case $1 in --time-stamp | --time* | -t ) echo "$timestamp" ; exit ;; --version | -v ) echo "$version" ; exit ;; --help | --h* | -h ) echo "$usage"; exit ;; -- ) # Stop option processing shift; break ;; - ) # Use stdin as input. break ;; -* ) echo "$me: invalid option $1$help" exit 1 ;; *local*) # First pass through any local machine types. echo $1 exit ;; * ) break ;; esac done case $# in 0) echo "$me: missing argument$help" >&2 exit 1;; 1) ;; *) echo "$me: too many arguments$help" >&2 exit 1;; esac # Separate what the user gave into CPU-COMPANY and OS or KERNEL-OS (if any). # Here we must recognize all the valid KERNEL-OS combinations. maybe_os=`echo $1 | sed 's/^\(.*\)-\([^-]*-[^-]*\)$/\2/'` case $maybe_os in nto-qnx* | linux-gnu* | linux-dietlibc | linux-newlib* | linux-uclibc* | \ uclinux-uclibc* | uclinux-gnu* | kfreebsd*-gnu* | knetbsd*-gnu* | netbsd*-gnu* | \ storm-chaos* | os2-emx* | rtmk-nova*) os=-$maybe_os basic_machine=`echo $1 | sed 's/^\(.*\)-\([^-]*-[^-]*\)$/\1/'` ;; *) basic_machine=`echo $1 | sed 's/-[^-]*$//'` if [ $basic_machine != $1 ] then os=`echo $1 | sed 's/.*-/-/'` else os=; fi ;; esac ### Let's recognize common machines as not being operating systems so ### that things like config.sub decstation-3100 work. We also ### recognize some manufacturers as not being operating systems, so we ### can provide default operating systems below. case $os in -sun*os*) # Prevent following clause from handling this invalid input. ;; -dec* | -mips* | -sequent* | -encore* | -pc532* | -sgi* | -sony* | \ -att* | -7300* | -3300* | -delta* | -motorola* | -sun[234]* | \ -unicom* | -ibm* | -next | -hp | -isi* | -apollo | -altos* | \ -convergent* | -ncr* | -news | -32* | -3600* | -3100* | -hitachi* |\ -c[123]* | -convex* | -sun | -crds | -omron* | -dg | -ultra | -tti* | \ -harris | -dolphin | -highlevel | -gould | -cbm | -ns | -masscomp | \ -apple | -axis | -knuth | -cray) os= basic_machine=$1 ;; -sim | -cisco | -oki | -wec | -winbond) os= basic_machine=$1 ;; -scout) ;; -wrs) os=-vxworks basic_machine=$1 ;; -chorusos*) os=-chorusos basic_machine=$1 ;; -chorusrdb) os=-chorusrdb basic_machine=$1 ;; -hiux*) os=-hiuxwe2 ;; -sco6) os=-sco5v6 basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` ;; -sco5) os=-sco3.2v5 basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` ;; -sco4) os=-sco3.2v4 basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` ;; -sco3.2.[4-9]*) os=`echo $os | sed -e 's/sco3.2./sco3.2v/'` basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` ;; -sco3.2v[4-9]*) # Don't forget version if it is 3.2v4 or newer. basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` ;; -sco5v6*) # Don't forget version if it is 3.2v4 or newer. basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` ;; -sco*) os=-sco3.2v2 basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` ;; -udk*) basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` ;; -isc) os=-isc2.2 basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` ;; -clix*) basic_machine=clipper-intergraph ;; -isc*) basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` ;; -lynx*) os=-lynxos ;; -ptx*) basic_machine=`echo $1 | sed -e 's/86-.*/86-sequent/'` ;; -windowsnt*) os=`echo $os | sed -e 's/windowsnt/winnt/'` ;; -psos*) os=-psos ;; -mint | -mint[0-9]*) basic_machine=m68k-atari os=-mint ;; esac # Decode aliases for certain CPU-COMPANY combinations. case $basic_machine in # Recognize the basic CPU types without company name. # Some are omitted here because they have special meanings below. 1750a | 580 \ | a29k \ | alpha | alphaev[4-8] | alphaev56 | alphaev6[78] | alphapca5[67] \ | alpha64 | alpha64ev[4-8] | alpha64ev56 | alpha64ev6[78] | alpha64pca5[67] \ | am33_2.0 \ | arc | arm | arm[bl]e | arme[lb] | armv[2345] | armv[345][lb] | avr | avr32 \ | bfin \ | c4x | clipper \ | d10v | d30v | dlx | dsp16xx \ | fido | fr30 | frv \ | h8300 | h8500 | hppa | hppa1.[01] | hppa2.0 | hppa2.0[nw] | hppa64 \ | i370 | i860 | i960 | ia64 \ | ip2k | iq2000 \ | m32c | m32r | m32rle | m68000 | m68k | m88k \ | maxq | mb | microblaze | mcore | mep \ | mips | mipsbe | mipseb | mipsel | mipsle \ | mips16 \ | mips64 | mips64el \ | mips64vr | mips64vrel \ | mips64orion | mips64orionel \ | mips64vr4100 | mips64vr4100el \ | mips64vr4300 | mips64vr4300el \ | mips64vr5000 | mips64vr5000el \ | mips64vr5900 | mips64vr5900el \ | mipsisa32 | mipsisa32el \ | mipsisa32r2 | mipsisa32r2el \ | mipsisa64 | mipsisa64el \ | mipsisa64r2 | mipsisa64r2el \ | mipsisa64sb1 | mipsisa64sb1el \ | mipsisa64sr71k | mipsisa64sr71kel \ | mipstx39 | mipstx39el \ | mn10200 | mn10300 \ | mt \ | msp430 \ | nios | nios2 \ | ns16k | ns32k \ | or32 \ | pdp10 | pdp11 | pj | pjl \ | powerpc | powerpc64 | powerpc64le | powerpcle | ppcbe \ | pyramid \ | score \ | sh | sh[1234] | sh[24]a | sh[23]e | sh[34]eb | sheb | shbe | shle | sh[1234]le | sh3ele \ | sh64 | sh64le \ | sparc | sparc64 | sparc64b | sparc64v | sparc86x | sparclet | sparclite \ | sparcv8 | sparcv9 | sparcv9b | sparcv9v \ | spu | strongarm \ | tahoe | thumb | tic4x | tic80 | tron \ | v850 | v850e \ | we32k \ | x86 | xc16x | xscale | xscalee[bl] | xstormy16 | xtensa \ | z8k) basic_machine=$basic_machine-unknown ;; m6811 | m68hc11 | m6812 | m68hc12) # Motorola 68HC11/12. basic_machine=$basic_machine-unknown os=-none ;; m88110 | m680[12346]0 | m683?2 | m68360 | m5200 | v70 | w65 | z8k) ;; ms1) basic_machine=mt-unknown ;; # We use `pc' rather than `unknown' # because (1) that's what they normally are, and # (2) the word "unknown" tends to confuse beginning users. i*86 | x86_64) basic_machine=$basic_machine-pc ;; # Object if more than one company name word. *-*-*) echo Invalid configuration \`$1\': machine \`$basic_machine\' not recognized 1>&2 exit 1 ;; # Recognize the basic CPU types with company name. 580-* \ | a29k-* \ | alpha-* | alphaev[4-8]-* | alphaev56-* | alphaev6[78]-* \ | alpha64-* | alpha64ev[4-8]-* | alpha64ev56-* | alpha64ev6[78]-* \ | alphapca5[67]-* | alpha64pca5[67]-* | arc-* \ | arm-* | armbe-* | armle-* | armeb-* | armv*-* \ | avr-* | avr32-* \ | bfin-* | bs2000-* \ | c[123]* | c30-* | [cjt]90-* | c4x-* | c54x-* | c55x-* | c6x-* \ | clipper-* | craynv-* | cydra-* \ | d10v-* | d30v-* | dlx-* \ | elxsi-* \ | f30[01]-* | f700-* | fido-* | fr30-* | frv-* | fx80-* \ | h8300-* | h8500-* \ | hppa-* | hppa1.[01]-* | hppa2.0-* | hppa2.0[nw]-* | hppa64-* \ | i*86-* | i860-* | i960-* | ia64-* \ | ip2k-* | iq2000-* \ | m32c-* | m32r-* | m32rle-* \ | m68000-* | m680[012346]0-* | m68360-* | m683?2-* | m68k-* \ | m88110-* | m88k-* | maxq-* | mcore-* \ | mips-* | mipsbe-* | mipseb-* | mipsel-* | mipsle-* \ | mips16-* \ | mips64-* | mips64el-* \ | mips64vr-* | mips64vrel-* \ | mips64orion-* | mips64orionel-* \ | mips64vr4100-* | mips64vr4100el-* \ | mips64vr4300-* | mips64vr4300el-* \ | mips64vr5000-* | mips64vr5000el-* \ | mips64vr5900-* | mips64vr5900el-* \ | mipsisa32-* | mipsisa32el-* \ | mipsisa32r2-* | mipsisa32r2el-* \ | mipsisa64-* | mipsisa64el-* \ | mipsisa64r2-* | mipsisa64r2el-* \ | mipsisa64sb1-* | mipsisa64sb1el-* \ | mipsisa64sr71k-* | mipsisa64sr71kel-* \ | mipstx39-* | mipstx39el-* \ | mmix-* \ | mt-* \ | msp430-* \ | nios-* | nios2-* \ | none-* | np1-* | ns16k-* | ns32k-* \ | orion-* \ | pdp10-* | pdp11-* | pj-* | pjl-* | pn-* | power-* \ | powerpc-* | powerpc64-* | powerpc64le-* | powerpcle-* | ppcbe-* \ | pyramid-* \ | romp-* | rs6000-* \ | sh-* | sh[1234]-* | sh[24]a-* | sh[23]e-* | sh[34]eb-* | sheb-* | shbe-* \ | shle-* | sh[1234]le-* | sh3ele-* | sh64-* | sh64le-* \ | sparc-* | sparc64-* | sparc64b-* | sparc64v-* | sparc86x-* | sparclet-* \ | sparclite-* \ | sparcv8-* | sparcv9-* | sparcv9b-* | sparcv9v-* | strongarm-* | sv1-* | sx?-* \ | tahoe-* | thumb-* \ | tic30-* | tic4x-* | tic54x-* | tic55x-* | tic6x-* | tic80-* \ | tron-* \ | v850-* | v850e-* | vax-* \ | we32k-* \ | x86-* | x86_64-* | xc16x-* | xps100-* | xscale-* | xscalee[bl]-* \ | xstormy16-* | xtensa*-* \ | ymp-* \ | z8k-*) ;; # Recognize the basic CPU types without company name, with glob match. xtensa*) basic_machine=$basic_machine-unknown ;; # Recognize the various machine names and aliases which stand # for a CPU type and a company and sometimes even an OS. 386bsd) basic_machine=i386-unknown os=-bsd ;; 3b1 | 7300 | 7300-att | att-7300 | pc7300 | safari | unixpc) basic_machine=m68000-att ;; 3b*) basic_machine=we32k-att ;; a29khif) basic_machine=a29k-amd os=-udi ;; abacus) basic_machine=abacus-unknown ;; adobe68k) basic_machine=m68010-adobe os=-scout ;; alliant | fx80) basic_machine=fx80-alliant ;; altos | altos3068) basic_machine=m68k-altos ;; am29k) basic_machine=a29k-none os=-bsd ;; amd64) basic_machine=x86_64-pc ;; amd64-*) basic_machine=x86_64-`echo $basic_machine | sed 's/^[^-]*-//'` ;; amdahl) basic_machine=580-amdahl os=-sysv ;; amiga | amiga-*) basic_machine=m68k-unknown ;; amigaos | amigados) basic_machine=m68k-unknown os=-amigaos ;; amigaunix | amix) basic_machine=m68k-unknown os=-sysv4 ;; apollo68) basic_machine=m68k-apollo os=-sysv ;; apollo68bsd) basic_machine=m68k-apollo os=-bsd ;; aux) basic_machine=m68k-apple os=-aux ;; balance) basic_machine=ns32k-sequent os=-dynix ;; blackfin) basic_machine=bfin-unknown os=-linux ;; blackfin-*) basic_machine=bfin-`echo $basic_machine | sed 's/^[^-]*-//'` os=-linux ;; c90) basic_machine=c90-cray os=-unicos ;; convex-c1) basic_machine=c1-convex os=-bsd ;; convex-c2) basic_machine=c2-convex os=-bsd ;; convex-c32) basic_machine=c32-convex os=-bsd ;; convex-c34) basic_machine=c34-convex os=-bsd ;; convex-c38) basic_machine=c38-convex os=-bsd ;; cray | j90) basic_machine=j90-cray os=-unicos ;; craynv) basic_machine=craynv-cray os=-unicosmp ;; cr16) basic_machine=cr16-unknown os=-elf ;; crds | unos) basic_machine=m68k-crds ;; crisv32 | crisv32-* | etraxfs*) basic_machine=crisv32-axis ;; cris | cris-* | etrax*) basic_machine=cris-axis ;; crx) basic_machine=crx-unknown os=-elf ;; da30 | da30-*) basic_machine=m68k-da30 ;; decstation | decstation-3100 | pmax | pmax-* | pmin | dec3100 | decstatn) basic_machine=mips-dec ;; decsystem10* | dec10*) basic_machine=pdp10-dec os=-tops10 ;; decsystem20* | dec20*) basic_machine=pdp10-dec os=-tops20 ;; delta | 3300 | motorola-3300 | motorola-delta \ | 3300-motorola | delta-motorola) basic_machine=m68k-motorola ;; delta88) basic_machine=m88k-motorola os=-sysv3 ;; djgpp) basic_machine=i586-pc os=-msdosdjgpp ;; dpx20 | dpx20-*) basic_machine=rs6000-bull os=-bosx ;; dpx2* | dpx2*-bull) basic_machine=m68k-bull os=-sysv3 ;; ebmon29k) basic_machine=a29k-amd os=-ebmon ;; elxsi) basic_machine=elxsi-elxsi os=-bsd ;; encore | umax | mmax) basic_machine=ns32k-encore ;; es1800 | OSE68k | ose68k | ose | OSE) basic_machine=m68k-ericsson os=-ose ;; fx2800) basic_machine=i860-alliant ;; genix) basic_machine=ns32k-ns ;; gmicro) basic_machine=tron-gmicro os=-sysv ;; go32) basic_machine=i386-pc os=-go32 ;; h3050r* | hiux*) basic_machine=hppa1.1-hitachi os=-hiuxwe2 ;; h8300hms) basic_machine=h8300-hitachi os=-hms ;; h8300xray) basic_machine=h8300-hitachi os=-xray ;; h8500hms) basic_machine=h8500-hitachi os=-hms ;; harris) basic_machine=m88k-harris os=-sysv3 ;; hp300-*) basic_machine=m68k-hp ;; hp300bsd) basic_machine=m68k-hp os=-bsd ;; hp300hpux) basic_machine=m68k-hp os=-hpux ;; hp3k9[0-9][0-9] | hp9[0-9][0-9]) basic_machine=hppa1.0-hp ;; hp9k2[0-9][0-9] | hp9k31[0-9]) basic_machine=m68000-hp ;; hp9k3[2-9][0-9]) basic_machine=m68k-hp ;; hp9k6[0-9][0-9] | hp6[0-9][0-9]) basic_machine=hppa1.0-hp ;; hp9k7[0-79][0-9] | hp7[0-79][0-9]) basic_machine=hppa1.1-hp ;; hp9k78[0-9] | hp78[0-9]) # FIXME: really hppa2.0-hp basic_machine=hppa1.1-hp ;; hp9k8[67]1 | hp8[67]1 | hp9k80[24] | hp80[24] | hp9k8[78]9 | hp8[78]9 | hp9k893 | hp893) # FIXME: really hppa2.0-hp basic_machine=hppa1.1-hp ;; hp9k8[0-9][13679] | hp8[0-9][13679]) basic_machine=hppa1.1-hp ;; hp9k8[0-9][0-9] | hp8[0-9][0-9]) basic_machine=hppa1.0-hp ;; hppa-next) os=-nextstep3 ;; hppaosf) basic_machine=hppa1.1-hp os=-osf ;; hppro) basic_machine=hppa1.1-hp os=-proelf ;; i370-ibm* | ibm*) basic_machine=i370-ibm ;; # I'm not sure what "Sysv32" means. Should this be sysv3.2? i*86v32) basic_machine=`echo $1 | sed -e 's/86.*/86-pc/'` os=-sysv32 ;; i*86v4*) basic_machine=`echo $1 | sed -e 's/86.*/86-pc/'` os=-sysv4 ;; i*86v) basic_machine=`echo $1 | sed -e 's/86.*/86-pc/'` os=-sysv ;; i*86sol2) basic_machine=`echo $1 | sed -e 's/86.*/86-pc/'` os=-solaris2 ;; i386mach) basic_machine=i386-mach os=-mach ;; i386-vsta | vsta) basic_machine=i386-unknown os=-vsta ;; iris | iris4d) basic_machine=mips-sgi case $os in -irix*) ;; *) os=-irix4 ;; esac ;; isi68 | isi) basic_machine=m68k-isi os=-sysv ;; m68knommu) basic_machine=m68k-unknown os=-linux ;; m68knommu-*) basic_machine=m68k-`echo $basic_machine | sed 's/^[^-]*-//'` os=-linux ;; m88k-omron*) basic_machine=m88k-omron ;; magnum | m3230) basic_machine=mips-mips os=-sysv ;; merlin) basic_machine=ns32k-utek os=-sysv ;; mingw32) basic_machine=i386-pc os=-mingw32 ;; mingw32ce) basic_machine=arm-unknown os=-mingw32ce ;; miniframe) basic_machine=m68000-convergent ;; *mint | -mint[0-9]* | *MiNT | *MiNT[0-9]*) basic_machine=m68k-atari os=-mint ;; mips3*-*) basic_machine=`echo $basic_machine | sed -e 's/mips3/mips64/'` ;; mips3*) basic_machine=`echo $basic_machine | sed -e 's/mips3/mips64/'`-unknown ;; monitor) basic_machine=m68k-rom68k os=-coff ;; morphos) basic_machine=powerpc-unknown os=-morphos ;; msdos) basic_machine=i386-pc os=-msdos ;; ms1-*) basic_machine=`echo $basic_machine | sed -e 's/ms1-/mt-/'` ;; mvs) basic_machine=i370-ibm os=-mvs ;; ncr3000) basic_machine=i486-ncr os=-sysv4 ;; netbsd386) basic_machine=i386-unknown os=-netbsd ;; netwinder) basic_machine=armv4l-rebel os=-linux ;; news | news700 | news800 | news900) basic_machine=m68k-sony os=-newsos ;; news1000) basic_machine=m68030-sony os=-newsos ;; news-3600 | risc-news) basic_machine=mips-sony os=-newsos ;; necv70) basic_machine=v70-nec os=-sysv ;; next | m*-next ) basic_machine=m68k-next case $os in -nextstep* ) ;; -ns2*) os=-nextstep2 ;; *) os=-nextstep3 ;; esac ;; nh3000) basic_machine=m68k-harris os=-cxux ;; nh[45]000) basic_machine=m88k-harris os=-cxux ;; nindy960) basic_machine=i960-intel os=-nindy ;; mon960) basic_machine=i960-intel os=-mon960 ;; nonstopux) basic_machine=mips-compaq os=-nonstopux ;; np1) basic_machine=np1-gould ;; nsr-tandem) basic_machine=nsr-tandem ;; op50n-* | op60c-*) basic_machine=hppa1.1-oki os=-proelf ;; openrisc | openrisc-*) basic_machine=or32-unknown ;; os400) basic_machine=powerpc-ibm os=-os400 ;; OSE68000 | ose68000) basic_machine=m68000-ericsson os=-ose ;; os68k) basic_machine=m68k-none os=-os68k ;; pa-hitachi) basic_machine=hppa1.1-hitachi os=-hiuxwe2 ;; paragon) basic_machine=i860-intel os=-osf ;; parisc) basic_machine=hppa-unknown os=-linux ;; parisc-*) basic_machine=hppa-`echo $basic_machine | sed 's/^[^-]*-//'` os=-linux ;; pbd) basic_machine=sparc-tti ;; pbb) basic_machine=m68k-tti ;; pc532 | pc532-*) basic_machine=ns32k-pc532 ;; pc98) basic_machine=i386-pc ;; pc98-*) basic_machine=i386-`echo $basic_machine | sed 's/^[^-]*-//'` ;; pentium | p5 | k5 | k6 | nexgen | viac3) basic_machine=i586-pc ;; pentiumpro | p6 | 6x86 | athlon | athlon_*) basic_machine=i686-pc ;; pentiumii | pentium2 | pentiumiii | pentium3) basic_machine=i686-pc ;; pentium4) basic_machine=i786-pc ;; pentium-* | p5-* | k5-* | k6-* | nexgen-* | viac3-*) basic_machine=i586-`echo $basic_machine | sed 's/^[^-]*-//'` ;; pentiumpro-* | p6-* | 6x86-* | athlon-*) basic_machine=i686-`echo $basic_machine | sed 's/^[^-]*-//'` ;; pentiumii-* | pentium2-* | pentiumiii-* | pentium3-*) basic_machine=i686-`echo $basic_machine | sed 's/^[^-]*-//'` ;; pentium4-*) basic_machine=i786-`echo $basic_machine | sed 's/^[^-]*-//'` ;; pn) basic_machine=pn-gould ;; power) basic_machine=power-ibm ;; ppc) basic_machine=powerpc-unknown ;; ppc-*) basic_machine=powerpc-`echo $basic_machine | sed 's/^[^-]*-//'` ;; ppcle | powerpclittle | ppc-le | powerpc-little) basic_machine=powerpcle-unknown ;; ppcle-* | powerpclittle-*) basic_machine=powerpcle-`echo $basic_machine | sed 's/^[^-]*-//'` ;; ppc64) basic_machine=powerpc64-unknown ;; ppc64-*) basic_machine=powerpc64-`echo $basic_machine | sed 's/^[^-]*-//'` ;; ppc64le | powerpc64little | ppc64-le | powerpc64-little) basic_machine=powerpc64le-unknown ;; ppc64le-* | powerpc64little-*) basic_machine=powerpc64le-`echo $basic_machine | sed 's/^[^-]*-//'` ;; ps2) basic_machine=i386-ibm ;; pw32) basic_machine=i586-unknown os=-pw32 ;; rdos) basic_machine=i386-pc os=-rdos ;; rom68k) basic_machine=m68k-rom68k os=-coff ;; rm[46]00) basic_machine=mips-siemens ;; rtpc | rtpc-*) basic_machine=romp-ibm ;; s390 | s390-*) basic_machine=s390-ibm ;; s390x | s390x-*) basic_machine=s390x-ibm ;; sa29200) basic_machine=a29k-amd os=-udi ;; sb1) basic_machine=mipsisa64sb1-unknown ;; sb1el) basic_machine=mipsisa64sb1el-unknown ;; sde) basic_machine=mipsisa32-sde os=-elf ;; sei) basic_machine=mips-sei os=-seiux ;; sequent) basic_machine=i386-sequent ;; sh) basic_machine=sh-hitachi os=-hms ;; sh5el) basic_machine=sh5le-unknown ;; sh64) basic_machine=sh64-unknown ;; sparclite-wrs | simso-wrs) basic_machine=sparclite-wrs os=-vxworks ;; sps7) basic_machine=m68k-bull os=-sysv2 ;; spur) basic_machine=spur-unknown ;; st2000) basic_machine=m68k-tandem ;; stratus) basic_machine=i860-stratus os=-sysv4 ;; sun2) basic_machine=m68000-sun ;; sun2os3) basic_machine=m68000-sun os=-sunos3 ;; sun2os4) basic_machine=m68000-sun os=-sunos4 ;; sun3os3) basic_machine=m68k-sun os=-sunos3 ;; sun3os4) basic_machine=m68k-sun os=-sunos4 ;; sun4os3) basic_machine=sparc-sun os=-sunos3 ;; sun4os4) basic_machine=sparc-sun os=-sunos4 ;; sun4sol2) basic_machine=sparc-sun os=-solaris2 ;; sun3 | sun3-*) basic_machine=m68k-sun ;; sun4) basic_machine=sparc-sun ;; sun386 | sun386i | roadrunner) basic_machine=i386-sun ;; sv1) basic_machine=sv1-cray os=-unicos ;; symmetry) basic_machine=i386-sequent os=-dynix ;; t3e) basic_machine=alphaev5-cray os=-unicos ;; t90) basic_machine=t90-cray os=-unicos ;; tic54x | c54x*) basic_machine=tic54x-unknown os=-coff ;; tic55x | c55x*) basic_machine=tic55x-unknown os=-coff ;; tic6x | c6x*) basic_machine=tic6x-unknown os=-coff ;; tile*) basic_machine=tile-unknown os=-linux-gnu ;; tx39) basic_machine=mipstx39-unknown ;; tx39el) basic_machine=mipstx39el-unknown ;; toad1) basic_machine=pdp10-xkl os=-tops20 ;; tower | tower-32) basic_machine=m68k-ncr ;; tpf) basic_machine=s390x-ibm os=-tpf ;; udi29k) basic_machine=a29k-amd os=-udi ;; ultra3) basic_machine=a29k-nyu os=-sym1 ;; v810 | necv810) basic_machine=v810-nec os=-none ;; vaxv) basic_machine=vax-dec os=-sysv ;; vms) basic_machine=vax-dec os=-vms ;; vpp*|vx|vx-*) basic_machine=f301-fujitsu ;; vxworks960) basic_machine=i960-wrs os=-vxworks ;; vxworks68) basic_machine=m68k-wrs os=-vxworks ;; vxworks29k) basic_machine=a29k-wrs os=-vxworks ;; w65*) basic_machine=w65-wdc os=-none ;; w89k-*) basic_machine=hppa1.1-winbond os=-proelf ;; xbox) basic_machine=i686-pc os=-mingw32 ;; xps | xps100) basic_machine=xps100-honeywell ;; ymp) basic_machine=ymp-cray os=-unicos ;; z8k-*-coff) basic_machine=z8k-unknown os=-sim ;; none) basic_machine=none-none os=-none ;; # Here we handle the default manufacturer of certain CPU types. It is in # some cases the only manufacturer, in others, it is the most popular. w89k) basic_machine=hppa1.1-winbond ;; op50n) basic_machine=hppa1.1-oki ;; op60c) basic_machine=hppa1.1-oki ;; romp) basic_machine=romp-ibm ;; mmix) basic_machine=mmix-knuth ;; rs6000) basic_machine=rs6000-ibm ;; vax) basic_machine=vax-dec ;; pdp10) # there are many clones, so DEC is not a safe bet basic_machine=pdp10-unknown ;; pdp11) basic_machine=pdp11-dec ;; we32k) basic_machine=we32k-att ;; sh[1234] | sh[24]a | sh[34]eb | sh[1234]le | sh[23]ele) basic_machine=sh-unknown ;; sparc | sparcv8 | sparcv9 | sparcv9b | sparcv9v) basic_machine=sparc-sun ;; cydra) basic_machine=cydra-cydrome ;; orion) basic_machine=orion-highlevel ;; orion105) basic_machine=clipper-highlevel ;; mac | mpw | mac-mpw) basic_machine=m68k-apple ;; pmac | pmac-mpw) basic_machine=powerpc-apple ;; *-unknown) # Make sure to match an already-canonicalized machine name. ;; *) echo Invalid configuration \`$1\': machine \`$basic_machine\' not recognized 1>&2 exit 1 ;; esac # Here we canonicalize certain aliases for manufacturers. case $basic_machine in *-digital*) basic_machine=`echo $basic_machine | sed 's/digital.*/dec/'` ;; *-commodore*) basic_machine=`echo $basic_machine | sed 's/commodore.*/cbm/'` ;; *) ;; esac # Decode manufacturer-specific aliases for certain operating systems. if [ x"$os" != x"" ] then case $os in # First match some system type aliases # that might get confused with valid system types. # -solaris* is a basic system type, with this one exception. -solaris1 | -solaris1.*) os=`echo $os | sed -e 's|solaris1|sunos4|'` ;; -solaris) os=-solaris2 ;; -svr4*) os=-sysv4 ;; -unixware*) os=-sysv4.2uw ;; -gnu/linux*) os=`echo $os | sed -e 's|gnu/linux|linux-gnu|'` ;; # First accept the basic system types. # The portable systems comes first. # Each alternative MUST END IN A *, to match a version number. # -sysv* is not here because it comes later, after sysvr4. -gnu* | -bsd* | -mach* | -minix* | -genix* | -ultrix* | -irix* \ | -*vms* | -sco* | -esix* | -isc* | -aix* | -sunos | -sunos[34]*\ | -hpux* | -unos* | -osf* | -luna* | -dgux* | -solaris* | -sym* \ | -amigaos* | -amigados* | -msdos* | -newsos* | -unicos* | -aof* \ | -aos* \ | -nindy* | -vxsim* | -vxworks* | -ebmon* | -hms* | -mvs* \ | -clix* | -riscos* | -uniplus* | -iris* | -rtu* | -xenix* \ | -hiux* | -386bsd* | -knetbsd* | -mirbsd* | -netbsd* \ | -openbsd* | -solidbsd* \ | -ekkobsd* | -kfreebsd* | -freebsd* | -riscix* | -lynxos* \ | -bosx* | -nextstep* | -cxux* | -aout* | -elf* | -oabi* \ | -ptx* | -coff* | -ecoff* | -winnt* | -domain* | -vsta* \ | -udi* | -eabi* | -lites* | -ieee* | -go32* | -aux* \ | -chorusos* | -chorusrdb* \ | -cygwin* | -pe* | -psos* | -moss* | -proelf* | -rtems* \ | -mingw32* | -linux-gnu* | -linux-newlib* | -linux-uclibc* \ | -uxpv* | -beos* | -mpeix* | -udk* \ | -interix* | -uwin* | -mks* | -rhapsody* | -darwin* | -opened* \ | -openstep* | -oskit* | -conix* | -pw32* | -nonstopux* \ | -storm-chaos* | -tops10* | -tenex* | -tops20* | -its* \ | -os2* | -vos* | -palmos* | -uclinux* | -nucleus* \ | -morphos* | -superux* | -rtmk* | -rtmk-nova* | -windiss* \ | -powermax* | -dnix* | -nx6 | -nx7 | -sei* | -dragonfly* \ | -skyos* | -haiku* | -rdos* | -toppers* | -drops*) # Remember, each alternative MUST END IN *, to match a version number. ;; -qnx*) case $basic_machine in x86-* | i*86-*) ;; *) os=-nto$os ;; esac ;; -nto-qnx*) ;; -nto*) os=`echo $os | sed -e 's|nto|nto-qnx|'` ;; -sim | -es1800* | -hms* | -xray | -os68k* | -none* | -v88r* \ | -windows* | -osx | -abug | -netware* | -os9* | -beos* | -haiku* \ | -macos* | -mpw* | -magic* | -mmixware* | -mon960* | -lnews*) ;; -mac*) os=`echo $os | sed -e 's|mac|macos|'` ;; -linux-dietlibc) os=-linux-dietlibc ;; -linux*) os=`echo $os | sed -e 's|linux|linux-gnu|'` ;; -sunos5*) os=`echo $os | sed -e 's|sunos5|solaris2|'` ;; -sunos6*) os=`echo $os | sed -e 's|sunos6|solaris3|'` ;; -opened*) os=-openedition ;; -os400*) os=-os400 ;; -wince*) os=-wince ;; -osfrose*) os=-osfrose ;; -osf*) os=-osf ;; -utek*) os=-bsd ;; -dynix*) os=-bsd ;; -acis*) os=-aos ;; -atheos*) os=-atheos ;; -syllable*) os=-syllable ;; -386bsd) os=-bsd ;; -ctix* | -uts*) os=-sysv ;; -nova*) os=-rtmk-nova ;; -ns2 ) os=-nextstep2 ;; -nsk*) os=-nsk ;; # Preserve the version number of sinix5. -sinix5.*) os=`echo $os | sed -e 's|sinix|sysv|'` ;; -sinix*) os=-sysv4 ;; -tpf*) os=-tpf ;; -triton*) os=-sysv3 ;; -oss*) os=-sysv3 ;; -svr4) os=-sysv4 ;; -svr3) os=-sysv3 ;; -sysvr4) os=-sysv4 ;; # This must come after -sysvr4. -sysv*) ;; -ose*) os=-ose ;; -es1800*) os=-ose ;; -xenix) os=-xenix ;; -*mint | -mint[0-9]* | -*MiNT | -MiNT[0-9]*) os=-mint ;; -aros*) os=-aros ;; -kaos*) os=-kaos ;; -zvmoe) os=-zvmoe ;; -none) ;; *) # Get rid of the `-' at the beginning of $os. os=`echo $os | sed 's/[^-]*-//'` echo Invalid configuration \`$1\': system \`$os\' not recognized 1>&2 exit 1 ;; esac else # Here we handle the default operating systems that come with various machines. # The value should be what the vendor currently ships out the door with their # machine or put another way, the most popular os provided with the machine. # Note that if you're going to try to match "-MANUFACTURER" here (say, # "-sun"), then you have to tell the case statement up towards the top # that MANUFACTURER isn't an operating system. Otherwise, code above # will signal an error saying that MANUFACTURER isn't an operating # system, and we'll never get to this point. case $basic_machine in score-*) os=-elf ;; spu-*) os=-elf ;; *-acorn) os=-riscix1.2 ;; arm*-rebel) os=-linux ;; arm*-semi) os=-aout ;; c4x-* | tic4x-*) os=-coff ;; # This must come before the *-dec entry. pdp10-*) os=-tops20 ;; pdp11-*) os=-none ;; *-dec | vax-*) os=-ultrix4.2 ;; m68*-apollo) os=-domain ;; i386-sun) os=-sunos4.0.2 ;; m68000-sun) os=-sunos3 # This also exists in the configure program, but was not the # default. # os=-sunos4 ;; m68*-cisco) os=-aout ;; mep-*) os=-elf ;; mips*-cisco) os=-elf ;; mips*-*) os=-elf ;; or32-*) os=-coff ;; *-tti) # must be before sparc entry or we get the wrong os. os=-sysv3 ;; sparc-* | *-sun) os=-sunos4.1.1 ;; *-be) os=-beos ;; *-haiku) os=-haiku ;; *-ibm) os=-aix ;; *-knuth) os=-mmixware ;; *-wec) os=-proelf ;; *-winbond) os=-proelf ;; *-oki) os=-proelf ;; *-hp) os=-hpux ;; *-hitachi) os=-hiux ;; i860-* | *-att | *-ncr | *-altos | *-motorola | *-convergent) os=-sysv ;; *-cbm) os=-amigaos ;; *-dg) os=-dgux ;; *-dolphin) os=-sysv3 ;; m68k-ccur) os=-rtu ;; m88k-omron*) os=-luna ;; *-next ) os=-nextstep ;; *-sequent) os=-ptx ;; *-crds) os=-unos ;; *-ns) os=-genix ;; i370-*) os=-mvs ;; *-next) os=-nextstep3 ;; *-gould) os=-sysv ;; *-highlevel) os=-bsd ;; *-encore) os=-bsd ;; *-sgi) os=-irix ;; *-siemens) os=-sysv4 ;; *-masscomp) os=-rtu ;; f30[01]-fujitsu | f700-fujitsu) os=-uxpv ;; *-rom68k) os=-coff ;; *-*bug) os=-coff ;; *-apple) os=-macos ;; *-atari*) os=-mint ;; *) os=-none ;; esac fi # Here we handle the case where we know the os, and the CPU type, but not the # manufacturer. We pick the logical manufacturer. vendor=unknown case $basic_machine in *-unknown) case $os in -riscix*) vendor=acorn ;; -sunos*) vendor=sun ;; -aix*) vendor=ibm ;; -beos*) vendor=be ;; -hpux*) vendor=hp ;; -mpeix*) vendor=hp ;; -hiux*) vendor=hitachi ;; -unos*) vendor=crds ;; -dgux*) vendor=dg ;; -luna*) vendor=omron ;; -genix*) vendor=ns ;; -mvs* | -opened*) vendor=ibm ;; -os400*) vendor=ibm ;; -ptx*) vendor=sequent ;; -tpf*) vendor=ibm ;; -vxsim* | -vxworks* | -windiss*) vendor=wrs ;; -aux*) vendor=apple ;; -hms*) vendor=hitachi ;; -mpw* | -macos*) vendor=apple ;; -*mint | -mint[0-9]* | -*MiNT | -MiNT[0-9]*) vendor=atari ;; -vos*) vendor=stratus ;; esac basic_machine=`echo $basic_machine | sed "s/unknown/$vendor/"` ;; esac echo $basic_machine$os exit # Local variables: # eval: (add-hook 'write-file-hooks 'time-stamp) # time-stamp-start: "timestamp='" # time-stamp-format: "%:y-%02m-%02d" # time-stamp-end: "'" # End: cvc3-2.4.1/configure.ac0000664000175400017540000004637611630011263014555 0ustar mdetersmdetersdnl Process with autoconf to generate configure script -*- sh -*- dnl Init with sanity check for source directory AC_INIT(cvc3,2.4.1) ###################################################################### # Library version information # # IMPORTANT: This version number needs to be bumped if binary # incompatibilities are introduced in the shared library. # # NOTE: This is the *library* version, not the version of the CVC3 # release (which is set by the VERSION variable below). In general, # LIB_MAJOR_VERSION will be greater than VERSION, because we break # compatibility fairly often in point releases. ###################################################################### # Major version: increases for non-backwards-compatible API changes AC_SUBST(LIB_MAJOR_VERSION) # Minor version: increases for backwards-compatible API changes AC_SUBST(LIB_MINOR_VERSION) # Teeny version: increases for library bug fixes (API hasn't changed) AC_SUBST(LIB_TEENY_VERSION) LIB_MAJOR_VERSION=5 LIB_MINOR_VERSION=0 LIB_TEENY_VERSION=0 dnl We don't want the default autoconf CXXFLAGS=-g -O2 if test "${CXXFLAGS+set}" != set; then CXXFLAGS="" fi dnl Set C++ as the default language for all tests AC_LANG([C++]) AC_REQUIRE_CPP AC_ARG_VAR([AR],[C/C++ linker/archiver]) AC_CHECK_TOOL([AR],ar) AC_SUBST(EXTRA_SAT_HEADERS) AC_SUBST(EXTRA_SAT_CPP) AC_SUBST_FILE([LICENSE_INFO]) AC_SUBST(DPLL_BASIC) EXTRA_SAT_HEADERS="" EXTRA_SAT_CPP="" LICENSE_INFO=/dev/null DPLL_BASIC="" #BEGIN zchaff cvc_use_zchaff="yes" AC_ARG_ENABLE(zchaff, [ --enable-zchaff Include zchaff code (default = yes) --disable-zchaff Remove zchaff code (default = no)], if test "$enableval" = "no"; then cvc_use_zchaff="no" fi) if test "$cvc_use_zchaff" = "yes"; then /bin/sh >.zchaff <" echo " ./configure --disable-zchaff" echo " make" echo "" echo "" echo "
"
echo "src/sat/xchaff_base.h"
echo "src/sat/xchaff_dbase.h"
echo "src/sat/xchaff_solver.h"
echo "src/sat/xchaff_utils.h"
echo "src/sat/xchaff_dbase.cpp"
echo "src/sat/xchaff_solver.cpp"
echo "src/sat/xchaff_utils.cpp"
echo "
" echo "" EOF EXTRA_SAT_HEADERS="xchaff.h xchaff_base.h xchaff_dbase.h xchaff_solver.h xchaff_utils.h" EXTRA_SAT_CPP="xchaff.cpp xchaff_dbase.cpp xchaff_solver.cpp xchaff_utils.cpp " LICENSE_INFO=.zchaff DPLL_BASIC="-DDPLL_BASIC" fi #END zchaff dnl # Name of the OS dnl AC_SUBST(OSTYPE) # Version of CVC AC_SUBST(VERSION) AC_SUBST(OPTIMIZED) OPTIMIZED="0" AC_SUBST(GCOV) GCOV="0" AC_SUBST(GPROF) GPROF="0" AC_ARG_WITH([build], [ --with-build=optimized Specify the type of build (default = optimized). Possible values: debug, optimized, gprof, gcov], [if test "$withval" = "optimized"; then OPTIMIZED="1" elif test "$withval" = "gprof"; then OPTIMIZED="1" GPROF="1" elif test "$withval" = "gcov"; then GCOV="1" else DEBUG_MSG="yes" fi], # --with-build is not given, default is "optimized" build [OPTIMIZED="1"] ) AC_SUBST(CXXFLAGS) CXXFLAGS="$CXXFLAGS" AC_ARG_ENABLE(debug-yacc, [ --enable-debug-yacc Enable debugging of yacc (default = no).], if test "$enableval" = "yes"; then CXXFLAGS="$CXXFLAGS -DYYDEBUG" fi) dnl Some extra features AC_SUBST(LD) LD='$(CXX)' AC_ARG_WITH(ld, [ --with-ld Use a specific program for linking.], if test ! "x$withval" = "xno" && test ! "x$withval" = "x"; then LD="$withval" fi) AC_SUBST(LDFLAGS) LDFLAGS="$LDFLAGS" AC_ARG_WITH(extra-libs, [ --with-extra-libs List of paths to additional static libraries separated with ":".], if test ! "x$withval" = "xno" && test ! "x$withval" = "x"; then LDFLAGS="$LDFLAGS -L"`echo "$withval" | sed -e 's/:/ -L/g'` fi) AC_SUBST(CPPFLAGS) CPPFLAGS="$CPPFLAGS" AC_ARG_WITH(extra-includes, [ --with-extra-includes List of paths to additional include files separated with ":".], if test ! "x$withval" = "xno" && test ! "x$withval" = "x"; then CPPFLAGS="$CPPFLAGS -I"`echo "$withval" | sed -e 's/:/ -I/g'` fi) AC_ARG_WITH(version, [ --with-version= The version string to report on cvc3 -version], # If option is given VERSION="$withval", # If not given VERSION=`cat VERSION`) dnl Override check for "broken" compilers AC_ARG_ENABLE(broken-cxx, [ --enable-broken-cxx[=no] Force configure to accept the compiler, even if it thinks that it is broken.], # If option is given if test "x$enableval" = "xyes"; then enable_broken_cxx="yes" else enable_broken_cxx="no" fi, # If option is not given enable_broken_cxx="no") dnl Find out what OS-specific subdirectory name to use AC_CANONICAL_HOST AC_EXEEXT case "$host_os" in none) host_os="unknown" ;; darwin*) MAC_OSX=1 ;; cygwin) CYGWIN=1 ;; esac case "$host_cpu" in i?86) # punt for Mac OS-- it gives you i386 even on 64-bit # let darwin's gcc build what it wants (or have the user add # -mXX to CXXFLAGS themselves) if test "$MAC_OSX" = 1; then :; else CXXFLAGS="$CXXFLAGS -m32" if test "$CYGWIN" = 1; then :; else # Sun's Java on Windows doesn't have -d* JREFLAGS="$JREFLAGS -d32" fi fi ;; x86_64) CXXFLAGS="$CXXFLAGS -m64" JREFLAGS="$JREFLAGS -d64" ;; esac OSTYPE="$host_cpu-$host_os" dnl OSTYPE=`echo "$OSTYPE" | sed 'y%ABCDEFGHIJKLMNOPQRSTUVWXYZ %abcdefghijklmnopqrstuvwxyz_%'` # The standard macro does something stupid. Check it explicitly. # AC_PROG_INSTALL AC_SUBST(INSTALL) AC_SUBST(INSTALL_FLAGS) AC_PATH_PROG(INSTALL, install, cp) if test "$INSTALL" = "cp"; then INSTALL_FLAGS="" else # INSTALL_FLAGS="-C --owner=root --group=root" # INSTALL_FLAGS="-C" # Seems like the arguments to 'install' are changing wildly with platform... INSTALL_FLAGS="" fi AC_SUBST(LDCONFIG) AC_PATH_PROG(LDCONFIG, ldconfig, AC_MSG_WARN([ldconfig not found. Library installation may fail.]), [$PATH:/sbin:/usr/sbin]) AC_SUBST(TIME) if test -n "$MAC_OSX"; then AC_PATH_PROG(TIME, gtime, [not found]) else AC_PATH_PROG(TIME, time, [not found]) fi if test "$TIME" = "not found"; then AC_MSG_WARN(Regression tests depend upon GNU time.) if test -n "$MAC_OSX"; then AC_MSG_WARN(Please install GNU time; we suggest using MacPorts, see INSTALL.) fi fi AC_SUBST(PERL) AC_PATH_PROG(PERL, perl, [not found]) if test "$PERL" = "not found"; then perl_found=0 AC_MSG_WARN(Perl not found. Static build will probably fail.) # Set default path for perl, just in case PERL=/usr/bin/perl else perl_found=1 fi dnl These checks rely on the behavior of autoconf and *require* bison and flex, rather than yacc or lex. AC_PROG_YACC if test "$YACC" != "bison -y"; then AC_MSG_ERROR([bison not found]) fi AC_PROG_LEX if test "$LEX" != "flex"; then AC_MSG_ERROR([flex not found]) fi dnl Check compiler version (we know that 3.0 does not compile) AC_CACHE_CHECK(for compiler version ($CXX --version), cvc_cv_cxx_version, cvc_cv_cxx_version=`$CXX --version | grep "[[[0-9]]][[[0-9]]]*[[[.]]][[[0-9]]]*" | sed -e 's/^[[[^0-9]]]*\([[[0-9.]]]*\).*$/\1/'`) cxx_major_version=`echo $cvc_cv_cxx_version | sed -e 's/^\([[0-9]]*\).*/\1/'` cxx_minor_version=`echo $cvc_cv_cxx_version | sed -e 's/^[[0-9]]*[[.]]\([[0-9]]*\).*/\1/'` if test "$cxx_major_version.$cxx_minor_version" = "3.0"; then if test "$enable_broken_cxx" = "no"; then AC_MSG_ERROR( [Compiler version $cvc_cv_cxx_version is known to generate bad executables. If you still want to compile with it, configure with option --enable-broken-cxx, but then do not ask for help unless you know how to fix it.]) else # The user asked for bad compiler. Warn him/her at the end. cxx_bad_version_warning="yes" fi fi AC_SUBST(STATIC) STATIC="1" AC_SUBST(BUILD_SHARED_LIB) BUILD_SHARED_LIB="0" AC_SUBST(STATIC_FLAG) AC_SUBST(DYNAMIC_FLAG) AC_SUBST(SHARED) AC_SUBST(LD_SWITCHES_PRE) AC_SUBST(LD_SWITCHES_POST) AC_SUBST(LD_LIB_DIR) if test -n "$MAC_OSX"; then DYNAMIC_FLAG="-dynamic" STATIC_FLAG="" SHARED="-dynamiclib -undefined dynamic_lookup" LD_SWITCHES_PRE="" LD_SWITCHES_POST="" elif test -n "$CYGWIN"; then DYNAMIC_FLAG="" STATIC_FLAG="" SHARED="-shared" LD_SWITCHES_PRE="-Wl,-static -Wl,--whole-archive" LD_SWITCHES_POST="-Wl,--no-whole-archive -Wl,-call_shared" else DYNAMIC_FLAG="" STATIC_FLAG="-static" SHARED="-shared" LD_SWITCHES_PRE="-Wl,-static -Wl,--whole-archive" LD_SWITCHES_POST="-Wl,--no-whole-archive -Wl,-call_shared" fi AC_ARG_ENABLE(static, [ --enable-static --disable-dynamic Enable static build of cvc3 (default=yes). Disable for faster link times.], # If options is given if test "$enableval" = "no"; then STATIC="0" fi) AC_ARG_ENABLE(dynamic, [ --enable-dynamic --disable-static Enable shared library build of cvc3 (default = no).], # If option is given if test "$enableval" = "yes"; then STATIC="0" fi) AC_ARG_ENABLE(sharedlibs, [ --enable-sharedlibs --disable-sharedlibs Enable building of individual shared libraries (default = yes).], # If option is given if test "$enableval" = "yes"; then BUILD_SHARED_LIB="1" fi) AC_SUBST(STATIC_LIB_SUFFIX) STATIC_LIB_SUFFIX="a" AC_SUBST(SHARED_LIB_SUFFIX) if test -n "$MAC_OSX"; then SHARED_LIB_SUFFIX="dylib" elif test -n "$CYGWIN"; then SHARED_LIB_SUFFIX="dll" else SHARED_LIB_SUFFIX="so" fi AC_SUBST(RATIONAL_IMPL) AC_ARG_WITH(arith, [ --with-arith=gmp Specify the arithmetic option to use: gmp: C-only GMP package (default) gmpxx: GMP package with C++ extensions (deprecated) native: native computer arithmetic (finite precision)], if test "$withval" = gmpxx; then RATIONAL_IMPL="-DRATIONAL_GMPXX" elif test "$withval" = gmp; then RATIONAL_IMPL="-DRATIONAL_GMP" elif test "$withval" = native; then RATIONAL_IMPL="-DRATIONAL_NATIVE" else RATIONAL_IMPL="" fi, # if option is not given RATIONAL_IMPL="-DRATIONAL_GMP" ) dnl Checks for libraries. Adds -lfoo to LIBS for each found library 'foo' dnl and defines HAVE_LIBfoo, unless 3rd and 4th args are specified. # Make sure we check the appropriate static / shared library if test "$RATIONAL_IMPL" = "-DRATIONAL_GMP"; then AC_MSG_CHECKING(for gmp) LIBS="-lgmp $LIBS" AC_LINK_IFELSE([AC_LANG_PROGRAM([[ #include #include ]], [[ mpq_t x; mpq_init(x); ]])],[cvc_gmp_works="yes"],[cvc_gmp_works="no"]) if test "$cvc_gmp_works" = "no"; then if test -n "$MAC_OSX"; then AC_MSG_RESULT(no) AC_MSG_CHECKING(for gmp in /opt/local) CPPFLAGS="-I/opt/local/include $CPPFLAGS" LDFLAGS="-L/opt/local/lib $LDFLAGS" AC_LINK_IFELSE([AC_LANG_PROGRAM([[ #include #include ]], [[ mpq_t x; mpq_init(x); ]])],[cvc_gmp_works="yes"],[cvc_gmp_works="no"]) fi fi if test "$cvc_gmp_works" = "no"; then AC_MSG_ERROR([[libgmp.a is not found. You can still compile CVC3 with native computer arithmetic: ./configure --with-arith=native WARNING: native arithmetic may cause overflows and assertion failures. If CVC3 fails due to an overflow in native arithmetic, do NOT report a bug; it is an intended feature to prevent soundness errors. For these reasons, we STRONGLY recommend installing GMP.]]) else AC_MSG_RESULT(yes) fi elif test "$RATIONAL_IMPL" = "-DRATIONAL_GMPXX"; then AC_CHECK_LIB(gmp, main, , AC_MSG_ERROR(libgmp.a is not found)) AC_CHECK_LIB(gmpxx, main, , AC_MSG_ERROR(libgmpxx.a is not found)) elif test -z "$RATIONAL_IMPL"; then AC_MSG_ERROR("Unknown argument to with-arith") fi if test "$RATIONAL_IMPL" = "-DRATIONAL_GMPXX"; then # Do some more extensive check of gmpxx, since it may be compiled with # a wrong compiler. AC_CACHE_CHECK(whether gmpxx library works, cvc_cv_gmpxx_works, cvc_cv_gmpxx_works="no" AC_LINK_IFELSE([AC_LANG_PROGRAM([[ #include #include ]], [[ mpz_class x; std::cout << x; ]])],[cvc_cv_gmpxx_works="yes"],[])) if test "$cvc_cv_gmpxx_works" = "no"; then AC_MSG_ERROR([libgmpxx.a did not link. You may have to recompile GMP with the current compiler: $CXX.]) fi fi dnl Java interface options AC_SUBST(BUILD_JAVA) BUILD_JAVA="0" AC_ARG_VAR([javadir],[installation directory for Java libraries]) AC_ARG_VAR([JAR],[JAR archive utility command]) AC_ARG_VAR([JAVA],[Java runtime command]) AC_ARG_VAR([JAVAC],[Java compiler command]) AC_ARG_VAR([JAVAH],[JNI utility command]) AC_ARG_VAR([JFLAGS],[Java compiler flags]) AC_ARG_VAR([JREFLAGS],[Java runtime flags]) AC_ARG_VAR([PYTHON],[Python runtime]) javadir='${exec_prefix}/java' dnl Take JNI_INC as a configuration option. By default, assume it's in dnl the standard Sun JDK 6 location. AC_SUBST([JNI_INC]) AC_ARG_ENABLE([java], [ --enable-java --disable-java Enable building of CVC3 Java interface (default = no).], # If option is given if test "$enableval" = "yes"; then BUILD_JAVA="1" fi) dnl AC_ARG_WITH([jni-include], dnl [AS_HELP_STRING([--with-jni-include=PATH], dnl [specify PATH of the JNI include directory])], dnl [JNI_INC=$withval], dnl [JNI_INC=/usr/lib/jvm/java-6-sun/include]) if test "$BUILD_JAVA" = "1"; then if test "$STATIC" = "1"; then AC_MSG_ERROR([The Java interface requires a dynamic library build. Use --enable-dynamic.]) fi dnl [chris] BEGIN: crib from libjmagick6-jni (significantly altered) dnl Determine if we have a decent Java distribution AC_ARG_WITH([java-home], [AS_HELP_STRING([--with-java-home=PATH], [Java installation path])], [JAVA_HOME=${withval}]) AC_ARG_WITH([java-includes], [AS_HELP_STRING([--with-java-includes=PATH],[Java includes path])], [JAVA_INCLUDE_PATH="${withval}"]) dnl [chris] Use a sensible default for JAVA_HOME on Mac if test -n "${MAC_OSX}" -a -z "${JAVA_HOME}" ; then JAVA_HOME=/System/Library/Frameworks/JavaVM.framework/Home fi dnl If we don't have a Java include path, try to derive one from JAVA_HOME if ! ( test -n "${JAVA_INCLUDE_PATH}" -a -d "${JAVA_INCLUDE_PATH}" ) ; then if test -d ${JAVA_HOME}/include ; then JAVA_INCLUDE_PATH=${JAVA_HOME}/include dnl check for Mac OS X series of systems elif test -d ${JAVA_HOME}/Headers; then JAVA_INCLUDE_PATH=-I${JAVA_HOME}/Headers else AC_MSG_ERROR([Unable to locate Java directories]) fi fi JAVA_INCLUDES=-I${JAVA_INCLUDE_PATH} dnl The Blackdown JDK seems to have genunix. if test -d ${JAVA_INCLUDE_PATH}/genunix ; then JAVA_INCLUDES="$JAVA_INCLUDES -I${JAVA_INCLUDE_PATH}/genunix" fi dnl The Sun Linux JDK seems to use linux if test -d ${JAVA_INCLUDE_PATH}/linux ; then JAVA_INCLUDES="$JAVA_INCLUDES -I${JAVA_INCLUDE_PATH}/linux" fi dnl The Sun Solaris JDK seems to use solaris if test -d ${JAVA_INCLUDE_PATH}/solaris ; then JAVA_INCLUDES="$JAVA_INCLUDES -I${JAVA_INCLUDE_PATH}/solaris" fi dnl The Sun FreeBSD JDK seems to use freebsd if test -d ${JAVA_INCLUDE_PATH}/freebsd ; then JAVA_INCLUDES="$JAVA_INCLUDES -I${JAVA_INCLUDE_PATH}/freebsd" fi dnl The Sun Windows JDK seems to use win32 if test -d ${JAVA_INCLUDE_PATH}/win32 ; then JAVA_INCLUDES="$JAVA_INCLUDES -I${JAVA_INCLUDE_PATH}/win32" fi if test -d ${JAVA_INCLUDE_PATH}/bsd ; then JAVA_INCLUDES="$JAVA_INCLUDES -I${JAVA_INCLUDE_PATH}/bsd" fi dnl [chris] END: crib from libjmagick6-jni if test -d ${JAVA_HOME}/bin; then PATH=${JAVA_HOME}/bin:$PATH fi # Check for Java tools AC_PATH_PROG([JAVAC],[javac], [AC_MSG_ERROR([javac not found: adjust PATH or set JAVAC])]) AC_PATH_PROG([JAVAH],[javah], [AC_MSG_ERROR([javah not found: adjust PATH or set JAVAH])] ) AC_PATH_PROG([JAR],[jar], [AC_MSG_ERROR([jar not found: adjust PATH or set JAR])] ) AC_PATH_PROG([JAVA],[java], [AC_MSG_ERROR([java not found: adjust PATH or set JAVA])] ) dnl Save and restore CPPFLAGS while checking for JNI headers OLD_CPPFLAGS="$CPPFLAGS" CPPFLAGS="${JAVA_INCLUDES} $CPPFLAGS" AC_CHECK_HEADER([jni.h],, [AC_MSG_ERROR(jni.h not found: try setting --with-java-home or --with-java-includes)]) AC_CHECK_HEADER([jni_md.h],, [AC_MSG_ERROR(jni_md.h not found: try setting --with-java-home or --with-java-includes)]) dnl Restore original CPPFLAGS CPPFLAGS="$OLD_CPPFLAGS" AC_PATH_PROG([PYTHON],[python], [AC_MSG_ERROR([python not found: adjust PATH or set PYTHON])]) fi dnl end of Java tests AC_SUBST(JAVA_INCLUDES) dnl Checks for header files. dnl Defines HAVE_headerFile for each headerFile found AC_CHECK_HEADERS([vector list deque set string cstdlib cstdio \ functional algorithm], , AC_MSG_ERROR(header is not found)) dnl Checks for typedefs, structures, and compiler characteristics. dnl Checks for library functions. dnl Other tests dnl Define the build and source directories for all sub-projects and dnl flags for optional packages if we want them to be built dnl CVC dnl Top-level directory for CVC AC_SUBST(TOP) TOP=`pwd` # Checking for documentation related programs AC_SUBST(DOXYGEN) AC_CHECK_PROG(DOXYGEN, doxygen, doxygen) AC_SUBST(DOXYTAG) AC_CHECK_PROG(DOXYTAG, doxytag, doxytag) AC_SUBST(FIG2DEV) AC_CHECK_PROG(FIG2DEV, fig2dev, fig2dev) AC_SUBST(HAVE_DOT) AC_CHECK_PROG(HAVE_DOT, dot, "YES", "NO") AC_SUBST(ETAGS) AC_CHECK_PROG(ETAGS, etags, "etags") AC_SUBST(EBROWSE) AC_CHECK_PROG(EBROWSE, ebrowse, "ebrowse") CVC_OUTPUT_FILES="Makefile.local \ LICENSE \ src/cvc3.pc" OTHER_OUTPUT_FILES="bin/unpack \ bin/run_tests \ bin/cvc2smt \ doc/Doxyfile \ doc/Makefile" AC_CONFIG_FILES([$CVC_OUTPUT_FILES \ $OTHER_OUTPUT_FILES ]) AC_OUTPUT chmod a+x bin/run_tests chmod a+x bin/cvc2smt chmod a+x bin/unpack opt_arith="$RAITONAL_IMPL" if test "$RATIONAL_IMPL" = "-DRATIONAL_NATIVE"; then opt_arith="native" elif test "$RATIONAL_IMPL" = "-DRATIONAL_GMP"; then opt_arith="GMP" elif test "$RATIONAL_IMPL" = "-DRATIONAL_GMPXX"; then opt_arith="GMP with C++ extensions" fi cat < UNPACKED cat UNPACKED | xargs $(AR) ruvs '$@.$(LIB_VERSION)' rm -rf $(UNPACKTMPDIR) UNPACKED @echo Linking $(LIB_STATIC_NAME) to $@ ln -sf $(LIB_STATIC_NAME).$(LIB_VERSION) '$@' $(LIB_SHARED): $(LIBS) @echo Building shared library $(LIB_SHARED) -rm -rf $(UNPACKTMPDIR) $(TOP)/bin/unpack $(UNPACKTMPDIR) $(LIBS) > UNPACKED ifneq ($(MAC_OSX),) cat UNPACKED | xargs $(CXX) $(SHARED) $(CXXFLAGS) $(LDFLAGS) \ -install_name $(libdir)/$(LIB_SHARED_MAJOR) \ -compatibility_version $(LIB_COMPAT_VERSION) \ -current_version $(LIB_VERSION) \ -o '$(LIB_SHARED)' `` $(LD_LIBS) else ifneq ($(CYGWIN),) eval $(CXX) $(SHARED) $(CXXFLAGS) $(LDFLAGS) \ -Wl,-soname,$(LIB_SHARED_MAJOR) -o \''$(LIB_SHARED)'\' `cat UNPACKED` $(LD_LIBS) else cat UNPACKED | xargs $(CXX) $(SHARED) $(CXXFLAGS) $(LDFLAGS) \ -Wl,-soname,$(LIB_SHARED_MAJOR) -o '$(LIB_SHARED)' `` $(LD_LIBS) $(LDCONFIG) -nv $(LIB_DIR) endif endif ln -sf $(LIB_SHARED_FULL) $(LIB_DIR)/$(LIB_SHARED_COMPAT) ln -sf $(LIB_SHARED_FULL) $(LIB_DIR)/$(LIB_SHARED_MAJOR) ln -sf $(LIB_SHARED_FULL) $(LIB_DIR)/$(LIB_SHARED_BASE) @rm -rf $(UNPACKTMPDIR) UNPACKED ifeq ($(STATIC),1) $(CVC_LIB): $(LIB_STATIC) ln -sf $(LIB_STATIC).$(LIB_VERSION) '$(call dirx,$@)/$(LIB_STATIC_NAME).$(LIB_VERSION)' ln -sf $(LIB_STATIC_NAME).$(LIB_VERSION) '$@' else $(CVC_LIB): $(LIB_SHARED) ln -sf $(LIB_SHARED) '$(call dirx,$@)/$(LIB_SHARED_FULL)' ifeq ($(MAC_OSX),) ifeq ($(CYGWIN),) $(LDCONFIG) -nv '$(call dirx,$@)' endif endif ln -sf $(LIB_SHARED_FULL) '$(call dirx,$@)/$(LIB_SHARED_COMPAT)' ln -sf $(LIB_SHARED_FULL) '$(call dirx,$@)/$(LIB_SHARED_MAJOR)' ln -sf $(LIB_SHARED_FULL) '$(call dirx,$@)/$(LIB_SHARED_BASE)' endif # Standard make targets depend: $(MAKE) build TARGET=depend clean: $(MAKE) build TARGET=clean rm -f $(LIB_STATIC)* $(LIB_SHARED)* $(CVC_LIB) distclean: $(MAKE) build TARGET=distclean rm -rf cvc3.pc spotty: $(MAKE) build TARGET=spotty rm -f $(LIB_STATIC) $(LIB_SHARED) $(CVC_LIB) HEADERS = $(patsubst %, $(TOP)/src/include/%, $(HEADER_NAMES)) install: $(HEADERS) $(MAKE) build TARGET= mkdir -p $(incdir) $(INSTALL) $(INSTALL_FLAGS) -m 644 $(HEADERS) $(incdir) mkdir -p $(libdir) ifeq ($(STATIC),1) $(INSTALL) $(INSTALL_FLAGS) -m 644 $(CVC_LIB_DIR)/$(CVC_LIB_NAME).$(LIB_VERSION) $(libdir) ln -sf $(CVC_LIB_NAME).$(LIB_VERSION) $(libdir)/$(call notdirx,$(CVC_LIB)) else $(INSTALL) $(INSTALL_FLAGS) -m 644 $(CVC_LIB) $(libdir) ifeq ($(MAC_OSX),) ifeq ($(CYGWIN),) $(LDCONFIG) -nv $(libdir) endif endif ln -sf $(CVC_LIB_NAME) $(libdir)/$(LIB_SHARED_COMPAT) ln -sf $(CVC_LIB_NAME) $(libdir)/$(LIB_SHARED_MAJOR) ln -sf $(CVC_LIB_NAME) $(libdir)/$(LIB_SHARED_BASE) endif mkdir -p $(bindir) $(INSTALL) $(INSTALL_FLAGS) -m 755 $(CVC_EXE) $(bindir) mkdir -p $(libdir)/pkgconfig $(INSTALL) $(INSTALL_FLAGS) -m 644 cvc3.pc $(libdir)/pkgconfig ifndef FILELIST FILELIST = /dev/null endif print_src: $(MAKE) build TARGET=print_src echo $(patsubst %, src/include/%, $(HEADER_NAMES)) >> $(FILELIST) cvc3-2.4.1/src/theory_simulate/0000775000175400017540000000000011630011320016245 5ustar mdetersmdeterscvc3-2.4.1/src/theory_simulate/Makefile0000664000175400017540000000056410533133655017733 0ustar mdetersmdeters################################################## # About this Makefile # # This Makefile depends on Makefile.opts ################################################## MODULE = theory_simulate SRC = theory_simulate.cpp simulate_theorem_producer.cpp HEADERS = simulate_proof_rules.h simulate_theorem_producer.h LIBRARY=libtheory_simulate.a include ../../Makefile.local cvc3-2.4.1/src/theory_simulate/simulate_theorem_producer.cpp0000664000175400017540000000502410466450541024245 0ustar mdetersmdeters/*****************************************************************************/ /*! *\file simulate_theorem_producer.cpp *\brief Trusted implementation of the proof rules for symbolic simulator * * Author: Sergey Berezin * * Created: Tue Oct 7 10:55:24 2003 * *
* * License to use, copy, modify, sell and/or distribute this software * and its documentation for any purpose is hereby granted without * royalty, subject to the terms and conditions defined in the \ref * LICENSE file provided with this distribution. * *
* */ /*****************************************************************************/ // This code is trusted #define _CVC3_TRUSTED_ #include #include "simulate_theorem_producer.h" #include "theory_simulate.h" #include "theory_core.h" using namespace std; using namespace CVC3; //////////////////////////////////////////////////////////////////// // TheoryArith: trusted method for creating ArithTheoremProducer //////////////////////////////////////////////////////////////////// SimulateProofRules* TheorySimulate::createProofRules() { return new SimulateTheoremProducer(theoryCore()->getTM()); } //////////////////////////////////////////////////////////////////// // Proof rules //////////////////////////////////////////////////////////////////// Theorem SimulateTheoremProducer::expandSimulate(const Expr& e) { const int arity = e.arity(); if (CHECK_PROOFS) { CHECK_SOUND(e.getKind() == SIMULATE, "SimulateTheoremProducer::expandSimulate: " "expected SIMULATE expression: " +e.toString()); CHECK_SOUND(arity >= 3 && e[arity - 1].isRational() && e[arity - 1].getRational().isInteger(), "SimulateTheoremProducer::expandSimulate: " "incorrect children in SIMULATE: " + e.toString()); } int n = e[arity - 1].getRational().getInt(); if(CHECK_PROOFS) { CHECK_SOUND(n >= 0, "SimulateTheoremProducer::expandSimulate: " "Requested negative number of iterations: "+int2string(n)); } // Compute f(f(...f(f(s0, I1(0), I2(0), ...), I1(1), ...), ... ), // I1(n-1), ...) // // We do this by accumulating the expression in 'res': // res_{i+1} = func(res_i, I1(i), ..., Ik(i)) Expr res(e[1]); for(int i=0; i args; args.push_back(res); Expr ri(d_em->newRatExpr(i)); for(int j=2; j * * License to use, copy, modify, sell and/or distribute this software * and its documentation for any purpose is hereby granted without * royalty, subject to the terms and conditions defined in the \ref * LICENSE file provided with this distribution. * *
* */ /*****************************************************************************/ #ifndef _cvc3__theory_simulate__simulate_proof_rules_h_ #define _cvc3__theory_simulate__simulate_proof_rules_h_ namespace CVC3 { class Expr; class Theorem; class SimulateProofRules { public: //! Destructor virtual ~SimulateProofRules() { } //! SIMULATE(f, s_0, i_1, ..., i_k, N) <=> f(...f(f(s_0, i_1), i_2), ... i_k) virtual Theorem expandSimulate(const Expr& e) = 0; }; // end of class SimulateProofRules } // end of namespace CVC3 #endif cvc3-2.4.1/src/theory_simulate/theory_simulate.cpp0000664000175400017540000002013111352466706022212 0ustar mdetersmdeters/*****************************************************************************/ /*! *\file theory_simulate.cpp *\brief Implementation of class TheorySimulate. * * Author: Sergey Berezin * * Created: Tue Oct 7 10:28:14 2003 * *
* * License to use, copy, modify, sell and/or distribute this software * and its documentation for any purpose is hereby granted without * royalty, subject to the terms and conditions defined in the \ref * LICENSE file provided with this distribution. * *
* */ /*****************************************************************************/ #include "theory_simulate.h" #include "simulate_proof_rules.h" #include "typecheck_exception.h" #include "parser_exception.h" #include "smtlib_exception.h" // For the type REAL #include "theory_arith.h" using namespace std; using namespace CVC3; TheorySimulate::TheorySimulate(TheoryCore* core) : Theory(core, "Simulate") { // Initialize the proof rules d_rules = createProofRules(); // Register the kinds vector kinds; kinds.push_back(SIMULATE); // Register the theory with the core registerTheory(this, kinds, false /* no solver */); } TheorySimulate::~TheorySimulate() { delete d_rules; } Theorem TheorySimulate::rewrite(const Expr& e) { switch (e.getKind()) { case SIMULATE: return d_rules->expandSimulate(e); break; default: return reflexivityRule(e); } } void TheorySimulate::computeType(const Expr& e) { switch (e.getKind()) { case SIMULATE: { // SIMULATE(f, s0, i_1, ..., i_k, N) const int arity = e.arity(); if (!e[arity - 1].isRational() || !e[arity - 1].getRational().isInteger()) { throw TypecheckException ("Number of cycles in SIMULATE (last arg) " "must be an integer constant:\n\n " + e[arity -1].toString() +"\n\nIn the following expression:\n\n " +e.toString()); } const Expr& fn(e[0]); Type fnType(getBaseType(fn)); // The arity of function is k+1, which is e.arity()-2. // The arity of the type also includes the result type. if(fnType.arity() != e.arity()-1) throw TypecheckException ("Wrong number of arguments in SIMULATE:\n\n" +e.toString() +"\n\nExpected "+int2string(fnType.arity()+1) +" arguments, but received "+int2string(e.arity())+"."); // Build the function type that SIMULATE expects vector argTp; // The (initial) state type Type resType(getBaseType(e[1])); argTp.push_back(resType); for(int i=2, iend=e.arity()-1; i " "\n\nBut the actual type is:\n\n " +iTp.toString()); argTp.push_back(iTpBase[1]); } Type expectedFnType(Type::funType(argTp, resType)); if(fnType != expectedFnType) throw TypecheckException ("Type mismatch in SIMULATE:\n\n " +e.toString() +"\n\nThe transition function is expected to be of type:\n\n " +expectedFnType.toString() +"\n\nBut the actual type is:\n\n " +fnType.toString()); e.setType(resType); break; } default: DebugAssert(false,"TheorySimulate::computeType: Unexpected expression: " +e.toString()); } } /////////////////////////////////////////////////////////////////////////////// //parseExprOp: //Recursive call of parseExpr defined in theory_ libaries based on kind of expr //being built /////////////////////////////////////////////////////////////////////////////// Expr TheorySimulate::parseExprOp(const Expr& e) { TRACE("parser", "TheorySimulate::parseExprOp(", e, ")"); // If the expression is not a list, it must have been already // parsed, so just return it as is. if(RAW_LIST != e.getKind()) return e; DebugAssert(e.arity() > 0, "TheorySimulate::parseExprOp:\n e = "+e.toString()); /* The first element of the list (e[0] is an ID of the operator. ID string values are the dirst element of the expression */ const Expr& c1 = e[0][0]; int kind = getEM()->getKind(c1.getString()); switch(kind) { case SIMULATE: { // Application of SIMULATE to args vector k; Expr::iterator i = e.begin(), iend=e.end(); // Skip first element of the vector of kids in 'e'. // The first element is the operator. ++i; // Parse the kids of e and push them into the vector 'k' for(; i!=iend; ++i) k.push_back(parseExpr(*i)); return Expr(SIMULATE, k, e.getEM()); break; } default: DebugAssert(false, "TheorySimulate::parseExprOp: Unexpected operator: " +e.toString()); } return e; } Expr TheorySimulate::computeTCC(const Expr& e) { switch (e.getKind()) { case SIMULATE: { // TCC(SIMULATE(f, s, i1, ..., ik, N)): // First, we require that the type of the first argument of f is // exactly the same as the type of f's result (otherwise we need // to check subtyping relation, which might be undecidable), and // whether f is defined on s. // // Then, we check that the result type of i_j exactly matches the // type of the j+1-th argument of f (again, for efficiency and // decidability reasons), and that each i_j is defined on every // integer from 0..N-1. vector tccs; Type fnType(e[0].getType()); DebugAssert(fnType.arity() == e.arity()-1, "TheorySimulate::computeTCC: SIMULATE() doesn't typecheck: " +e.toString()); Type resType(fnType[fnType.arity()-1]); // Check that the state type matches the 1st arg and the result type in f if(fnType[0] != resType) return getEM()->falseExpr(); // Compute TCC for f on the initial state tccs.push_back(getTypePred(fnType[0], e[1])); const Rational& N = e[e.arity()-1].getRational(); // Now, iterate through the inputs for(int i=2, iend=e.arity()-1; ifalseExpr(); // Compute the TCC for i(0) ... i(N-1) for(Rational j=0; jnewRatExpr(j))); } return rewriteAnd(andExpr(tccs)).getRHS(); } default: DebugAssert(false, "TheorySimulate::computeTCC("+e.toString() +")\n\nUnknown expression."); return getEM()->trueExpr(); } } ExprStream& TheorySimulate::print(ExprStream& os, const Expr& e) { switch(os.lang()) { case PRESENTATION_LANG: switch(e.getKind()) { case SIMULATE:{ os << "SIMULATE" << "(" << push; bool first(true); for (int i = 0; i < e.arity(); i++) { if (first) first = false; else os << push << "," << pop << space; os << e[i]; } os << push << ")"; break; } default: // Print the top node in the default LISP format, continue with // pretty-printing for children. e.printAST(os); break; } break; case SMTLIB_LANG: case SMTLIB_V2_LANG: d_theoryUsed = true; throw SmtlibException("TheorySimulate::print: SMTLIB not supported"); switch(e.getKind()) { case SIMULATE:{ os << "(" << push << "SIMULATE" << space; for (int i = 0; i < e.arity(); i++) { os << space << e[i]; } os << push << ")"; break; } default: // Print the top node in the default LISP format, continue with // pretty-printing for children. e.printAST(os); break; } break; case LISP_LANG: switch(e.getKind()) { case SIMULATE:{ os << "(" << push << "SIMULATE" << space; for (int i = 0; i < e.arity(); i++) { os << space << e[i]; } os << push << ")"; break; } default: // Print the top node in the default LISP format, continue with // pretty-printing for children. e.printAST(os); break; } break; default: // Not a known language e.printAST(os); break; } return os; } cvc3-2.4.1/src/theory_simulate/simulate_theorem_producer.h0000664000175400017540000000254510466450541023717 0ustar mdetersmdeters/*****************************************************************************/ /*! *\file simulate_theorem_producer.h *\brief Implementation of the symbolic simulator proof rules * * Author: Sergey Berezin * * Created: Tue Oct 7 10:49:14 2003 * *
* * License to use, copy, modify, sell and/or distribute this software * and its documentation for any purpose is hereby granted without * royalty, subject to the terms and conditions defined in the \ref * LICENSE file provided with this distribution. * *
* */ /*****************************************************************************/ #ifndef _cvc3__theory_simulate__simulate_theorem_producer_h_ #define _cvc3__theory_simulate__simulate_theorem_producer_h_ #include "theorem_producer.h" #include "simulate_proof_rules.h" namespace CVC3 { class SimulateTheoremProducer: public SimulateProofRules, public TheoremProducer { public: //! Constructor SimulateTheoremProducer(TheoremManager* tm): TheoremProducer(tm) { } virtual ~SimulateTheoremProducer() { } virtual Theorem expandSimulate(const Expr& e); /* private: Expr substFreeTerm(const Expr& e, const Expr& oldE, const Expr& newE); Expr recursiveSubst(const Expr& e, const Expr& oldE, const Expr& newE, ExprMap& visited); */ }; // end of class SimulateTheoremProducer } // end of namespace CVC3 #endif cvc3-2.4.1/src/expr/0000775000175400017540000000000011630011320014006 5ustar mdetersmdeterscvc3-2.4.1/src/expr/Makefile0000664000175400017540000000050510533133650015462 0ustar mdetersmdeters################################################## # About this Makefile # # This Makefile depends on Makefile.opts ################################################## MODULE = expr SRC = expr.cpp \ expr_manager.cpp \ expr_stream.cpp \ expr_value.cpp \ expr_op.cpp LIBRARY=libexpr.a include ../../Makefile.local cvc3-2.4.1/src/expr/expr_manager.cpp0000644000175400017540000004762611624746721017226 0ustar mdetersmdeters/*****************************************************************************/ /*! * \file expr_manager.cpp * * Author: Sergey Berezin * * Created: Wed Dec 4 14:20:56 2002 * *
* * License to use, copy, modify, sell and/or distribute this software * and its documentation for any purpose is hereby granted without * royalty, subject to the terms and conditions defined in the \ref * LICENSE file provided with this distribution. * *
* */ /*****************************************************************************/ #include "expr_manager.h" #include "command_line_flags.h" #include "expr_stream.h" #include "pretty_printer.h" #include "memory_manager_malloc.h" #include "memory_manager_chunks.h" using namespace CVC3; using namespace std; // File-local function which registers all the commonly declared // kinds (defined below) static void registerKinds(ExprManager& em); void ExprManager::installExprValue(ExprValue* p_ev) { DebugAssert(isActive(), "ExprManager::installExprValue(ExprValue*)"); // int maxHeight = 0; // p_ev->d_highestKid = 0; // for (unsigned i = 0; i < p_ev->arity(); i++) // { // int height = p_ev->getKids()[i].getHeight(); // if (height > maxHeight) // { // maxHeight = height; // p_ev->d_highestKid = i; // } // } // if (p_ev->d_kind == ITE && p_ev->arity() == 3) // { // if (p_ev->getKids()[1].getHeight() > p_ev->getKids()[2].getHeight()) // p_ev->d_highestKid = 1; // else // p_ev->d_highestKid = 2; // } // switch (p_ev->d_kind) { // case NOT: case AND: case OR: case ITE: case IFF: case IMPLIES: // maxHeight++; // } // p_ev->d_height = maxHeight; d_exprSet.insert(p_ev); } // Constructor ExprManager::ExprManager(ContextManager* cm, const CLFlags& flags) // Initial number of buckets is 1024 (it's kinda arbitrary) : d_cm(cm), d_index(0), d_flagCounter(1), d_prettyPrinter(NULL), d_printDepth(&(flags["print-depth"].getInt())), d_withIndentation(&(flags["indent"].getBool())), d_indent(0), d_indentTransient(0), d_lineWidth(&(flags["width"].getInt())), d_inputLang(&(flags["lang"].getString())), d_outputLang(&(flags["output-lang"].getString())), d_dagPrinting(&(flags["dagify-exprs"].getBool())), d_mmFlag(flags["mm"].getString()), d_exprSet(1024, HashEV(this), EqEV()), d_mm(EXPR_VALUE_TYPE_LAST), d_simpCacheTagCurrent(1), d_disableGC(false), d_postponeGC(false), d_inGC(false), d_typeComputer(NULL) { // Initialize the notifier d_notifyObj = new ExprManagerNotifyObj(this, d_cm->getCurrentContext()); // Initialize core memory managers if(d_mmFlag == "chunks") { d_mm[EXPR_VALUE] = new MemoryManagerChunks(sizeof(ExprValue)); d_mm[EXPR_NODE] = new MemoryManagerChunks(sizeof(ExprNode)); d_mm[EXPR_APPLY] = new MemoryManagerChunks(sizeof(ExprApply)); d_mm[EXPR_STRING] = new MemoryManagerChunks(sizeof(ExprString)); d_mm[EXPR_RATIONAL] = new MemoryManagerChunks(sizeof(ExprRational)); d_mm[EXPR_UCONST] = new MemoryManagerChunks(sizeof(ExprVar)); d_mm[EXPR_SYMBOL] = new MemoryManagerChunks(sizeof(ExprSymbol)); d_mm[EXPR_BOUND_VAR] = new MemoryManagerChunks(sizeof(ExprBoundVar)); d_mm[EXPR_CLOSURE] = new MemoryManagerChunks(sizeof(ExprClosure)); d_mm[EXPR_SKOLEM] = new MemoryManagerChunks(sizeof(ExprSkolem)); } else { d_mm[EXPR_VALUE] = new MemoryManagerMalloc(); d_mm[EXPR_NODE] = new MemoryManagerMalloc(); d_mm[EXPR_APPLY] = new MemoryManagerMalloc(); d_mm[EXPR_STRING] = new MemoryManagerMalloc(); d_mm[EXPR_RATIONAL] = new MemoryManagerMalloc(); d_mm[EXPR_UCONST] = new MemoryManagerMalloc(); d_mm[EXPR_SYMBOL] = new MemoryManagerMalloc(); d_mm[EXPR_BOUND_VAR] = new MemoryManagerMalloc(); d_mm[EXPR_CLOSURE] = new MemoryManagerMalloc(); d_mm[EXPR_SKOLEM] = new MemoryManagerMalloc(); } registerKinds(*this); d_bool = newLeafExpr(BOOLEAN); d_false = newLeafExpr(FALSE_EXPR); d_false.setType(Type::typeBool(this)); d_true = newLeafExpr(TRUE_EXPR); d_true.setType(Type::typeBool(this)); IF_DEBUG(d_inRebuild = false;) } // Destructor ExprManager::~ExprManager() { FatalAssert(d_emptyVec.size()==0, "~ExprManager()"); delete d_notifyObj; // Make sure garbage collector doesn't get in the way d_disableGC = false; // clear() will assert this. clear(); d_disableGC = true; // Destroy memory managers TRACE_MSG("delete", "~ExprManager: deleting d_mm's {"); for(size_t i=0; i exprs; exprs.reserve(d_exprSet.size()); TRACE_MSG("delete", "clear:() collecting exprs { "); IF_DEBUG(int n(0);) for(ExprValueSet::iterator i=d_exprSet.begin(), iend=d_exprSet.end(); i!=iend; ++i) { TRACE("delete", "expr[", n++, "]"); exprs.push_back(*i); } TRACE_MSG("delete", "clear(): finished collecting exprs }"); d_exprSet.clear(); TRACE_MSG("delete", "clear(): deleting exprs { "); for(vector::iterator i=exprs.begin(), iend=exprs.end(); i!=iend; ++i) { ExprValue *pExpr= *i; size_t tp(pExpr->getMMIndex()); // which memory manager to use delete (pExpr); d_mm[tp]->deleteData(pExpr); } TRACE_MSG("delete", "clear(): finished deleting exprs }"); } bool ExprManager::isActive() { return !d_disableGC; } // Garbage collect the ExprValue pointer void ExprManager::gc(ExprValue* ev) { if(!d_disableGC) { d_exprSet.erase(ev); if (d_inGC) d_pending.push_back(ev); else if (d_postponeGC) d_postponed.push_back(ev); else { IF_DEBUG(FatalAssert(d_pending.size() == 0, "Expected size 1");) d_inGC = true; size_t tp = ev->getMMIndex(); delete ev; d_mm[tp]->deleteData(ev); while (d_pending.size() > 0) { ev = d_pending.front(); d_pending.pop_front(); tp = ev->getMMIndex(); delete ev; d_mm[tp]->deleteData(ev); } d_inGC = false; } } } void ExprManager::resumeGC() { d_postponeGC = false; while(d_postponed.size()>0) { ExprValue* ev = d_postponed.back(); size_t tp(ev->getMMIndex()); d_postponed.pop_back(); delete ev; d_mm[tp]->deleteData(ev); } } // Rebuild the Expr with this ExprManager if it belongs to another // ExprManager Expr ExprManager::rebuild(const Expr& e) { // TRACE("expr", "rebuild(", e, ") {"); // Shouldn't rebuild a Null Expr (it's a bug) DebugAssert(!e.isNull(), "ExprManager::rebuild called on Null Expr"); // Both ExprManagers must be active DebugAssert(isActive() && e.getEM()->isActive(), "ExprManager::rebuild is called on inactive ExprManager"); // If e has the same ExprManager, no rebuilding is necessary if(e.isNull() || (e.getEM() == this)) { // TRACE_MSG("expr", "rebuild (same EM) => }"); return e; } // Gotta rebuild DebugAssert(!d_inRebuild, "ExprManager::rebuild()"); IF_DEBUG(ScopeWatcher sw(&d_inRebuild);) // First, clear the cache if(d_rebuildCache.size() > 0) d_rebuildCache.clear(); Expr res = rebuildRec(e); // Leave no trail behind (free up Exprs) if(d_rebuildCache.size() > 0) d_rebuildCache.clear(); // TRACE("expr", "rebuild => ", e, " }"); return res; } Expr ExprManager::rebuildRec(const Expr& e) { DebugAssert(d_inRebuild, "ExprManager::rebuildRec("+e.toString()+")"); // Check cache ExprHashMap::iterator j=d_rebuildCache.find(e), jend=d_rebuildCache.end(); if(j!=jend) return (*j).second; ExprValue* ev = e.d_expr->rebuild(this); // Uniquify the pointer ExprValueSet::iterator i(d_exprSet.find(ev)), iend(d_exprSet.end()); if(i != iend) { MemoryManager* mm = getMM(ev->getMMIndex()); delete ev; mm->deleteData(ev); ev = *i; } else { ev->setIndex(nextIndex()); d_exprSet.insert(ev); } // Use non-uniquifying Expr() constructor Expr res(ev); // Cache the result d_rebuildCache[e] = res; // Rebuild the type too Type t; if (!e.d_expr->d_type.isNull()) { t = Type(rebuildRec(e.d_expr->d_type.getExpr())); if (ev->d_type.isNull()) ev->d_type = t; if (ev->d_type != t) { throw Exception("Types don't match in rebuildRec"); } } return res; } ExprValue* ExprManager::newExprValue(ExprValue* ev) { DebugAssert(isActive(), "ExprManager::newExprValue(ExprValue*)"); ExprValueSet::iterator i(d_exprSet.find(ev)), iend(d_exprSet.end()); if(i != iend) return (*i); // No such ExprValue. Create a clean copy, insert it into the set // and return the new pointer. ExprValue* p_ev = ev->copy(this, nextIndex()); d_exprSet.insert(p_ev); return p_ev; } // ExprValue* ExprManager::newExprValue(const Expr& op, // const vector& kids) { // // Check if op and kids have the same ExprManager // DebugAssert(isActive(), "ExprManager::newExprValue(op, kids)"); // DebugAssert(this == op.getEM(), // "ExprManager::newExprValue(op, kids): op is from a wrong " // "ExprManager/ValidityChecker, call importExpr() first:\n" // +op.toString()); // IF_DEBUG( // for(vector::const_iterator i=kids.begin(), iend=kids.end(); // i!=iend; ++i) // DebugAssert(!i->isNull() && (i->getEM() == this), // "ExprManager::newExprValue(op, kids): the child is" // " from a wrong instance of ExprManager/ValidityChecker," // "call importExpr() first:\n" // +i->toString()); // ) // ExprValue* res = op.d_expr->copy(this, kids); // ExprValueSet::iterator i(d_exprSet.find(res)), iend(d_exprSet.end()); // if(i != iend) { // MemoryManager* mm = getMM(res->getMMIndex()); // delete res; // mm->deleteData(res); // return (*i); // } else { // res->setIndex(nextIndex()); // installExprValue(res); // return res; // } // } //! Set initial indentation. Returns the previous permanent value. int ExprManager::indent(int n, bool permanent) { int ret(d_indent); d_indentTransient = n; if(permanent) d_indent = n; return ret; } //! Increment the current transient indentation by n /*! If the second argument is true, sets the result as permanent. \return previous permanent value. */ int ExprManager::incIndent(int n, bool permanent) { int ret(d_indent); d_indentTransient += n; if(permanent) d_indent = d_indentTransient; return ret; } // Various options InputLanguage ExprManager::getInputLang() const { return getLanguage(*d_inputLang); } InputLanguage ExprManager::getOutputLang() const { const std::string* langPtr = (*d_outputLang == "")? d_inputLang : d_outputLang; return getLanguage(*langPtr); } void ExprManager::newKind(int kind, const string &name, bool isType) { if(d_kindMap.count(kind) == 0) { d_kindMap[kind] = name; if(isType) d_typeKinds.insert(kind); } else if(d_kindMap[kind] != name) { DebugAssert(false, "CVC3::ExprManager::newKind(kind = " + int2string(kind) + ", name = " + name + "): \n" + "this kind is already registered with a different name: " + d_kindMap[kind]); } if(d_kindMapByName.count(name) == 0) d_kindMapByName[name] = kind; else if(d_kindMapByName[name] != kind) { DebugAssert(false, "CVC3::ExprManager::newKind(kind = " + int2string(kind) + ", name = " + name + "): \n" + "this kind name is already registered with a different index: " + int2string(d_kindMapByName[name])); } } // Register a printer void ExprManager::registerPrettyPrinter(PrettyPrinter& printer) { DebugAssert(d_prettyPrinter==NULL, "ExprManager:registerPrettyPrinter():" " printer is already registered"); d_prettyPrinter = &printer; } // Unregister a printer void ExprManager::unregisterPrettyPrinter() { FatalAssert(d_prettyPrinter!=NULL, "ExprManager:unregisterPrettyPrinter():" " printer is not registered"); d_prettyPrinter = NULL; } const string& ExprManager::getKindName(int kind) { DebugAssert(d_kindMap.count(kind) > 0, ("CVC3::ExprManager::getKindName(kind = " + int2string(kind) + "): kind is not registered.").c_str()); return d_kindMap[kind]; } int ExprManager::getKind(const string& name) { std::hash_map::iterator i=d_kindMapByName.find(name), iend=d_kindMapByName.end(); if(i==iend) return NULL_KIND; else return (*i).second; } size_t ExprManager::registerSubclass(size_t sizeOfSubclass) { size_t idx(d_mm.size()); if(d_mmFlag == "chunks") d_mm.push_back(new MemoryManagerChunks(sizeOfSubclass)); else d_mm.push_back(new MemoryManagerMalloc()); FatalAssert(d_mm.back() != NULL, "Out of memory"); return idx; } unsigned long ExprManager::getMemory(int verbosity) { unsigned long memSelf = sizeof(ExprManager); unsigned long mem = 0; // mem += MemoryTracker::getHashMap(verbosity - 1, d_kindMap); // mem += d_typeKinds.getMemory(verbosity - 1); // mem += d_kindMapByName.getMemory(verbosity - 1); // mem += d_prettyPrinter->getMemory(verbosity - 1); mem += MemoryTracker::getString(verbosity - 1, d_mmFlag); // mem += d_exprSet.getMemory(verbosity - 1); // mem += getMemoryVec(d_mm); // for (i = 0; i < d_mm.size(); ++i) { // mem += d_mm->getMemory(verbosity - 1); // } // mem += d_pointerHash.getMemory(verbosity - 1) - sizeof(hash); // mem += getMemoryVec(d_emptyVec); // mem += getMemoryVec(d_postponed); // mem += d_rebuildCache.getMemory(verbosity - 1) - sizeof(ExprHashMap); // mem += d_typecomputer->getMemory(verbosity - 1); MemoryTracker::print("ExprManager", verbosity, memSelf, mem); return mem + memSelf; } void ExprManager::computeType(const Expr& e) { DebugAssert(d_typeComputer, "No type computer installed"); d_typeComputer->computeType(e); DebugAssert(!e.getType().getExpr().isNull(), "Type not set by computeType"); } void ExprManager::checkType(const Expr& e) { DebugAssert(d_typeComputer, "No type computer installed"); if (!e.isValidType()) d_typeComputer->checkType(e); DebugAssert(e.isValidType(), "Type not checked by checkType"); } Cardinality ExprManager::finiteTypeInfo(Expr& e, Unsigned& n, bool enumerate, bool computeSize) { DebugAssert(d_typeComputer, "No type computer installed"); return d_typeComputer->finiteTypeInfo(e, n, enumerate, computeSize); } // Kind registration macro #define REG(k) em.newKind(k, #k) #define REG_TYPE(k) em.newKind(k, #k, true) static void registerKinds(ExprManager& em) { // Register type kinds em.newKind(BOOLEAN, "_BOOLEAN", true); // REG(TUPLE_TYPE); em.newKind(ANY_TYPE, "_ANY_TYPE", true); em.newKind(ARROW, "_ARROW", true); em.newKind(TYPE, "_TYPE", true); em.newKind(TYPEDECL, "_TYPEDECL", true); em.newKind(TYPEDEF, "_TYPEDEF", true); em.newKind(SUBTYPE, "_SUBTYPE", true); // Register expression (non-type) kinds em.newKind(NULL_KIND, "_NULL_KIND"); em.newKind(RAW_LIST, "_RAW_LIST"); em.newKind(STRING_EXPR, "_STRING_EXPR"); em.newKind(RATIONAL_EXPR, "_RATIONAL_EXPR"); em.newKind(TRUE_EXPR, "_TRUE_EXPR"); em.newKind(FALSE_EXPR, "_FALSE_EXPR"); em.newKind(EQ, "_EQ"); em.newKind(NEQ, "_NEQ"); em.newKind(DISTINCT, "_DISTINCT"); em.newKind(NOT, "_NOT"); em.newKind(AND, "_AND"); em.newKind(OR, "_OR"); em.newKind(XOR, "_XOR"); em.newKind(IFF, "_IFF"); em.newKind(IMPLIES, "_IMPLIES"); em.newKind(AND_R, "_AND_R"); em.newKind(IFF_R, "_IFF_R"); em.newKind(ITE_R, "_ITE_R"); em.newKind(ITE, "_ITE"); em.newKind(FORALL, "_FORALL"); em.newKind(EXISTS, "_EXISTS"); em.newKind(UFUNC, "_UFUNC"); em.newKind(APPLY, "_APPLY"); em.newKind(ASSERT, "_ASSERT"); em.newKind(QUERY, "_QUERY"); em.newKind(CHECKSAT, "_CHECKSAT"); em.newKind(CONTINUE, "_CONTINUE"); em.newKind(RESTART, "_RESTART"); em.newKind(DBG, "_DBG"); em.newKind(TRACE, "_TRACE"); em.newKind(UNTRACE, "_UNTRACE"); em.newKind(OPTION, "_OPTION"); em.newKind(HELP, "_HELP"); em.newKind(TRANSFORM, "_TRANSFORM"); em.newKind(PRINT, "_PRINT"); em.newKind(CALL, "_CALL"); em.newKind(ECHO, "_ECHO"); em.newKind(INCLUDE, "_INCLUDE"); em.newKind(GET_VALUE, "_GET_VALUE"); em.newKind(GET_ASSIGNMENT, "_GET_ASSIGNMENT"); em.newKind(DUMP_PROOF, "_DUMP_PROOF"); em.newKind(DUMP_ASSUMPTIONS, "_DUMP_ASSUMPTIONS"); em.newKind(DUMP_SIG, "_DUMP_SIG"); em.newKind(DUMP_TCC, "_DUMP_TCC"); em.newKind(DUMP_TCC_ASSUMPTIONS, "_DUMP_TCC_ASSUMPTIONS"); em.newKind(DUMP_TCC_PROOF, "_DUMP_TCC_PROOF"); em.newKind(DUMP_CLOSURE, "_DUMP_CLOSURE"); em.newKind(DUMP_CLOSURE_PROOF, "_DUMP_CLOSURE_PROOF"); em.newKind(WHERE, "_WHERE"); em.newKind(ASSERTIONS, "_ASSERTIONS"); em.newKind(ASSUMPTIONS, "_ASSUMPTIONS"); em.newKind(COUNTEREXAMPLE, "_COUNTEREXAMPLE"); em.newKind(COUNTERMODEL, "_COUNTERMODEL"); em.newKind(PUSH, "_PUSH"); em.newKind(POP, "_POP"); em.newKind(POPTO, "_POPTO"); em.newKind(PUSH_SCOPE, "_PUSH_SCOPE"); em.newKind(POP_SCOPE, "_POP_SCOPE"); em.newKind(POPTO_SCOPE, "_POPTO_SCOPE"); em.newKind(RESET, "_RESET"); em.newKind(CONTEXT, "_CONTEXT"); em.newKind(FORGET, "_FORGET"); em.newKind(GET_TYPE, "_GET_TYPE"); em.newKind(CHECK_TYPE, "_CHECK_TYPE"); em.newKind(GET_CHILD, "_GET_CHILD"); em.newKind(SUBSTITUTE, "_SUBSTITUTE"); em.newKind(SEQ, "_SEQ"); em.newKind(ARITH_VAR_ORDER, "_ARITH_VAR_ORDER"); em.newKind(ANNOTATION, "_ANNOTATION"); // Kinds used mostly in the parser em.newKind(TCC, "_TCC"); em.newKind(ID, "_ID"); em.newKind(VARDECL, "_VARDECL"); em.newKind(VARDECLS, "_VARDECLS"); em.newKind(BOUND_VAR, "_BOUND_VAR"); em.newKind(BOUND_ID, "_BOUND_ID"); em.newKind(SKOLEM_VAR, "_SKOLEM_VAR"); em.newKind(THEOREM_KIND, "_THEOREM_KIND"); // em.newKind(UPDATE, "_UPDATE"); // em.newKind(UPDATE_SELECT, "_UPDATE_SELECT"); // em.newKind(RECORD_TYPE, "_RECORD_TYPE"); // em.newKind(RECORD, "_RECORD"); // em.newKind(RECORD_SELECT, "_RECORD_SELECT"); // em.newKind(RECORD_UPDATE, "_RECORD_UPDATE"); // em.newKind(TUPLE, "_TUPLE"); // em.newKind(TUPLE_SELECT, "_TUPLE_SELECT"); // em.newKind(TUPLE_UPDATE, "_TUPLE_UPDATE"); // em.newKind(SUBRANGE, "_SUBRANGE"); // em.newKind(SCALARTYPE, "_SCALARTYPE"); // em.newKind(DATATYPE, "_DATATYPE"); // em.newKind(THISTYPE, "_THISTYPE"); // em.newKind(CONSTRUCTOR, "_CONSTRUCTOR"); // em.newKind(SELECTOR, "_SELECTOR"); // em.newKind(TESTER, "_TESTER"); // em.newKind(DATATYPE_UPDATE, "_DATATYPE_UPDATE"); em.newKind(IF, "_IF"); em.newKind(IFTHEN, "_IFTHEN"); em.newKind(ELSE, "_ELSE"); em.newKind(COND, "_COND"); em.newKind(LET, "_LET"); em.newKind(LETDECLS, "_LETDECLS"); em.newKind(LETDECL, "_LETDECL"); em.newKind(LAMBDA, "_LAMBDA"); em.newKind(SIMULATE, "_SIMULATE"); em.newKind(CONST, "_CONST"); em.newKind(VARLIST, "_VARLIST"); em.newKind(UCONST, "_UCONST"); em.newKind(DEFUN, "_DEFUN"); // Arithmetic types and operators // em.newKind(REAL, "_REAL"); // em.newKind(INT, "_INT"); // em.newKind(UMINUS, "_UMINUS"); // em.newKind(PLUS, "_PLUS"); // em.newKind(MINUS, "_MINUS"); // em.newKind(MULT, "_MULT"); // em.newKind(DIVIDE, "_DIVIDE"); // em.newKind(POW, "_POW"); // em.newKind(INTDIV, "_INTDIV"); // em.newKind(MOD, "_MOD"); // em.newKind(LT, "_LT"); // em.newKind(LE, "_LE"); // em.newKind(GT, "_GT"); // em.newKind(GE, "_GE"); // em.newKind(IS_INTEGER, "_IS_INTEGER"); // em.newKind(NEGINF, "_NEGINF"); // em.newKind(POSINF, "_POSINF"); // em.newKind(FLOOR, "_FLOOR"); } void ExprManagerNotifyObj::notifyPre() { d_em->postponeGC(); } void ExprManagerNotifyObj::notify() { d_em->resumeGC(); } cvc3-2.4.1/src/expr/expr_value.cpp0000664000175400017540000002226111262166130016702 0ustar mdetersmdeters/*****************************************************************************/ /*! * \file expr_value.cpp * * Author: Sergey Berezin * * Created: Fri Feb 7 22:29:04 2003 * *
* * License to use, copy, modify, sell and/or distribute this software * and its documentation for any purpose is hereby granted without * royalty, subject to the terms and conditions defined in the \ref * LICENSE file provided with this distribution. * *
* */ /*****************************************************************************/ #include "expr_value.h" #include "notifylist.h" using namespace std; namespace CVC3 { //////////////////////////////////////////////////////////////////////// // Class ExprValue static members //////////////////////////////////////////////////////////////////////// std::hash ExprValue::s_charHash; std::hash ExprValue::s_intHash; //////////////////////////////////////////////////////////////////////// // Class ExprValue methods //////////////////////////////////////////////////////////////////////// // Destructor ExprValue::~ExprValue() { // Be careful deleting the attributes: first set them to NULL, then // delete, to avoid circular destructor calls if (d_find) { CDO* find = d_find; d_find = NULL; delete find; free(find); } if (d_eqNext) { CDO* eqNext = d_eqNext; d_eqNext = NULL; delete eqNext; free(eqNext); } if(d_notifyList != NULL) { NotifyList* nl = d_notifyList; d_notifyList = NULL; delete nl; } // Set all smart pointers to Null d_type = Type(); d_simpCache=Theorem(); // d_simpFrom=Expr(); } // Equality between any two ExprValue objects (including subclasses) bool ExprValue::operator==(const ExprValue& ev2) const { DebugAssert(getMMIndex() == EXPR_VALUE, "ExprValue::operator==() called from a subclass"); if(getMMIndex() != ev2.getMMIndex()) return false; return (d_kind == ev2.d_kind); } ExprValue* ExprValue::copy(ExprManager* em, ExprIndex idx) const { DebugAssert(getMMIndex() == EXPR_VALUE, "ExprValue::copy() called from a subclass"); return new(em->getMM(EXPR_VALUE)) ExprValue(em, d_kind, idx); } bool ExprNodeTmp::operator==(const ExprValue& ev2) const { return getMMIndex() == ev2.getMMIndex() && d_kind == ev2.getKind() && getKids() == ev2.getKids(); } ExprValue* ExprNodeTmp::copy(ExprManager* em, ExprIndex idx) const { if (d_em != em) { vector children; vector::const_iterator i = d_children.begin(), iend = d_children.end(); for (; i != iend; ++i) children.push_back(rebuild(*i, em)); return new(em->getMM(getMMIndex())) ExprNode(em, d_kind, children, idx); } return new(em->getMM(getMMIndex())) ExprNode(em, d_kind, d_children, idx); } ExprNode::~ExprNode() { // Be careful deleting the attributes: first set them to NULL, then // delete, to avoid circular destructor calls if (d_sig) { CDO* sig = d_sig; d_sig = NULL; delete sig; free(sig); } if (d_rep) { CDO* rep = d_rep; d_rep = NULL; delete rep; free(rep); } } bool ExprNode::operator==(const ExprValue& ev2) const { if(getMMIndex() != ev2.getMMIndex()) return false; return (d_kind == ev2.getKind()) && (getKids() == ev2.getKids()); } ExprValue* ExprNode::copy(ExprManager* em, ExprIndex idx) const { if (d_em != em) { vector children; vector::const_iterator i = d_children.begin(), iend = d_children.end(); for (; i != iend; ++i) children.push_back(rebuild(*i, em)); return new(em->getMM(getMMIndex())) ExprNode(em, d_kind, children, idx); } return new(em->getMM(getMMIndex())) ExprNode(em, d_kind, d_children, idx); } bool ExprString::operator==(const ExprValue& ev2) const { if(getMMIndex() != ev2.getMMIndex()) return false; return (getString() == ev2.getString()); } ExprValue* ExprString::copy(ExprManager* em, ExprIndex idx) const { return new(em->getMM(getMMIndex())) ExprString(em, d_str, idx); } bool ExprSkolem::operator==(const ExprValue& ev2) const { if(getMMIndex() != ev2.getMMIndex()) return false; return (getBoundIndex() == ev2.getBoundIndex() && getExistential() == ev2.getExistential()); } ExprValue* ExprSkolem::copy(ExprManager* em, ExprIndex idx) const { if (d_em != em) { return new(em->getMM(getMMIndex())) ExprSkolem(em, getBoundIndex(), rebuild(getExistential(), em), idx); } return new(em->getMM(getMMIndex())) ExprSkolem(em, getBoundIndex(), getExistential(), idx); } bool ExprRational::operator==(const ExprValue& ev2) const { if(getMMIndex() != ev2.getMMIndex()) return false; return (getRational() == ev2.getRational()); } ExprValue* ExprRational::copy(ExprManager* em, ExprIndex idx) const { return new(em->getMM(getMMIndex())) ExprRational(em, d_r, idx); } bool ExprVar::operator==(const ExprValue& ev2) const { if(getMMIndex() != ev2.getMMIndex()) return false; return (getKind() == ev2.getKind() && getName() == ev2.getName()); } ExprValue* ExprVar::copy(ExprManager* em, ExprIndex idx) const { return new(em->getMM(getMMIndex())) ExprVar(em, d_name, idx); } bool ExprSymbol::operator==(const ExprValue& ev2) const { if(getMMIndex() != ev2.getMMIndex()) return false; return (getKind() == ev2.getKind() && getName() == ev2.getName()); } ExprValue* ExprSymbol::copy(ExprManager* em, ExprIndex idx) const { return new(em->getMM(getMMIndex())) ExprSymbol(em, d_kind, d_name, idx); } bool ExprBoundVar::operator==(const ExprValue& ev2) const { if(getMMIndex() != ev2.getMMIndex()) return false; return (getKind() == ev2.getKind() && getName() == ev2.getName() && getUid() == ev2.getUid()); } ExprValue* ExprBoundVar::copy(ExprManager* em, ExprIndex idx) const { return new(em->getMM(getMMIndex())) ExprBoundVar(em, d_name, d_uid, idx); } bool ExprApply::operator==(const ExprValue& ev2) const { if(getMMIndex() != ev2.getMMIndex()) return false; return (getOp() == ev2.getOp()) && (getKids() == ev2.getKids()); } ExprValue* ExprApply::copy(ExprManager* em, ExprIndex idx) const { if (d_em != em) { vector children; vector::const_iterator i = d_children.begin(), iend = d_children.end(); for (; i != iend; ++i) children.push_back(rebuild(*i, em)); return new(em->getMM(getMMIndex())) ExprApply(em, Op(rebuild(d_opExpr, em)), children, idx); } return new(em->getMM(getMMIndex())) ExprApply(em, Op(d_opExpr), d_children, idx); } bool ExprApplyTmp::operator==(const ExprValue& ev2) const { if(getMMIndex() != ev2.getMMIndex()) return false; return (getOp() == ev2.getOp()) && (getKids() == ev2.getKids()); } ExprValue* ExprApplyTmp::copy(ExprManager* em, ExprIndex idx) const { if (d_em != em) { vector children; vector::const_iterator i = d_children.begin(), iend = d_children.end(); for (; i != iend; ++i) children.push_back(rebuild(*i, em)); return new(em->getMM(getMMIndex())) ExprApply(em, Op(rebuild(d_opExpr, em)), children, idx); } return new(em->getMM(getMMIndex())) ExprApply(em, Op(d_opExpr), d_children, idx); } bool ExprClosure::operator==(const ExprValue& ev2) const { if(getMMIndex() != ev2.getMMIndex()) return false; return (getKind() == ev2.getKind()) && (getBody() == ev2.getBody()) && (getVars() == ev2.getVars()); } ExprValue* ExprClosure::copy(ExprManager* em, ExprIndex idx) const { if (d_em != em) { vector vars; vector::const_iterator i = d_vars.begin(), iend = d_vars.end(); for (; i != iend; ++i) vars.push_back(rebuild(*i, em)); vector > manual_trigs; vector >::const_iterator j = d_manual_triggers.begin(), jend = d_manual_triggers.end(); for (; j != jend; ++j) { vector::const_iterator k = j->begin(), kend = j->end(); vector cur_trig; for (; k != kend; ++k){ cur_trig.push_back(rebuild(*k,em)); } // manual_trigs.push_back(rebuild(*j, em)); manual_trigs.push_back(cur_trig); } return new(em->getMM(getMMIndex())) ExprClosure(em, d_kind, vars, rebuild(d_body, em), manual_trigs, idx); } return new(em->getMM(getMMIndex())) ExprClosure(em, d_kind, d_vars, d_body, d_manual_triggers, idx); } //////////////////////////////////////////////////////////////////////// // Methods of subclasses of ExprValue //////////////////////////////////////////////////////////////////////// // Hash function for subclasses with kids. size_t ExprValue::hash(const int kind, const std::vector& kids) { size_t res(s_intHash((long int)kind)); for(std::vector::const_iterator i=kids.begin(), iend=kids.end(); i!=iend; ++i) { void* ptr = i->d_expr; res = res*PRIME + pointerHash(ptr); } return res; } // Size function for subclasses with kids. Unsigned ExprValue::sizeWithChildren(const std::vector& kids) { Unsigned res = 1; for(vector::const_iterator i=kids.begin(), iend=kids.end(); i!=iend; ++i) { res += (*i).d_expr->getSize(); } return res; } size_t ExprClosure::computeHash() const { return d_body.hash()*PRIME + ExprValue::hash(d_kind, d_vars); } } // end of namespace CVC3 cvc3-2.4.1/src/expr/expr_op.cpp0000664000175400017540000000175210466450541016215 0ustar mdetersmdeters/*****************************************************************************/ /*! * \file expr_op.cpp * * Author: Sergey Berezin * * Created: Fri Feb 7 15:29:42 2003 * *
* * License to use, copy, modify, sell and/or distribute this software * and its documentation for any purpose is hereby granted without * royalty, subject to the terms and conditions defined in the \ref * LICENSE file provided with this distribution. * *
* */ /*****************************************************************************/ #include "expr_op.h" using namespace std; namespace CVC3 { Op::Op(ExprManager* em, const Op& op) : d_kind(op.d_kind), d_expr() { if (!op.d_expr.isNull()) d_expr = em->rebuild(op.d_expr); } Op& Op::operator=(const Op& op) { if(&op == this) return *this; // Self-assignment d_kind = op.d_kind; d_expr = op.d_expr; return *this; } string Op::toString() const { ostringstream ss; ss << *this; return ss.str(); } } // end of namespace CVC3 cvc3-2.4.1/src/expr/expr.cpp0000664000175400017540000004274411306035506015517 0ustar mdetersmdeters/*****************************************************************************/ /*! * \file expr.cpp * * Author: Sergey Berezin * * Created: Thu Dec 5 11:35:55 2002 * *
* * License to use, copy, modify, sell and/or distribute this software * and its documentation for any purpose is hereby granted without * royalty, subject to the terms and conditions defined in the \ref * LICENSE file provided with this distribution. * *
* */ /*****************************************************************************/ #include #include "expr.h" #include "pretty_printer.h" #include "expr_stream.h" #include "notifylist.h" #include "exception.h" using namespace std; namespace CVC3 { Expr Expr::s_null; /////////////////////////////////////////////////////////////////////// // Class Expr methods // /////////////////////////////////////////////////////////////////////// vector > Expr::substTriggers(const ExprHashMap & subst, ExprHashMap & visited) const { /* Do the substitution in triggers */ vector > vvOldTriggers(getTriggers()); vector > vvNewTriggers; vector >::const_iterator i, iEnd; for( i = vvOldTriggers.begin(), iEnd = vvOldTriggers.end(); i != iEnd; ++i ) { vector vOldTriggers(*i); vector vNewTriggers; vector::const_iterator j, jEnd; for( j = vOldTriggers.begin(), jEnd = vOldTriggers.end(); j != jEnd; ++j ) { vNewTriggers.push_back((*j).recursiveSubst(subst, visited)); } vvNewTriggers.push_back(vNewTriggers); } return vvNewTriggers; } Expr Expr::recursiveSubst(const ExprHashMap& subst, ExprHashMap& visited) const { // Check the cache. // INVARIANT: visited contains all the flagged expressions, and only those if(getFlag()) return visited[*this]; ExprIndex minIndex = 0; for(ExprHashMap::const_iterator i = subst.begin(),iend=subst.end();i!=iend;++i) { if(minIndex > (i->first).getIndex()) minIndex = (i->first).getIndex(); } Expr replaced; if(isClosure()) { const vector & vars = getVars(); vector common; // Bound vars which occur in subst for(vector::const_iterator i = vars.begin(), iend=vars.end(); i!=iend; ++i) { if(subst.count(*i) > 0) common.push_back(*i); } if(common.size() > 0) { IF_DEBUG(debugger.counter("substExpr: bound var clashes")++;) // Reduced substitution (without the common vars) ExprHashMap newSubst(subst); // Remove variables in "common" from the substitution for(vector::iterator i=common.begin(), iend=common.end(); i!=iend; ++i) newSubst.erase(*i); // Clear all the caches (important!) visited.clear(); clearFlags(); visited = newSubst; ExprHashMap::iterator j = newSubst.begin(); for (; j != newSubst.end(); ++j) { // old vars bound in e j->first.setFlag(); } vector > vvNewTriggers = substTriggers(newSubst,visited); replaced = getEM()->newClosureExpr(getKind(), vars, getBody().recursiveSubst(newSubst, visited), vvNewTriggers); // Clear the flags again, as we restore the substitution visited.clear(); clearFlags(); visited = subst; // Restore the flags on the original substitutions for (ExprHashMap::const_iterator i = subst.begin(), iend=subst.end(); i != iend; ++i) i->first.setFlag(); } else { vector > vvNewTriggers = substTriggers(subst,visited); replaced = getEM()->newClosureExpr(getKind(), vars, getBody().recursiveSubst(subst, visited), vvNewTriggers); } } else { // Not a Closure int changed=0; vector children; for(Expr::iterator i=begin(), iend=end(); i!=iend; ++i){ Expr repChild = *i; if(repChild.getIndex() >= minIndex) repChild = (*i).recursiveSubst(subst, visited); if(repChild != *i) changed++; children.push_back(repChild); } Expr opExpr; if (isApply()) { opExpr = getOpExpr().recursiveSubst(subst, visited); if (opExpr != getOpExpr()) ++changed; } if(changed > 0) { Op op = opExpr.isNull() ? getOp() : opExpr.mkOp(); replaced = Expr(op, children); } else replaced = *this; } visited.insert(*this, replaced); setFlag(); return replaced; } static bool subExprRec(const Expr& e1, const Expr& e2) { if(e1 == e2) return true; if(e2.getFlag()) return false; // e1 is created after e2, so e1 cannot be a subexpr of e2 if(e1 > e2) return false; e2.setFlag(); bool res(false); for(Expr::iterator i=e2.begin(), iend=e2.end(); !res && i!=iend; ++i) res = subExprRec(e1, *i); return res; } bool Expr::subExprOf(const Expr& e) const { if(*this == e) return true; // "this" is created after e, so it cannot be e's subexpression if(*this > e) return false; clearFlags(); return subExprRec(*this, e); } Expr Expr::substExpr(const vector& oldTerms, const vector& newTerms) const { DebugAssert(oldTerms.size() == newTerms.size(), "substExpr: vectors" "don't match in size"); // Catch the vacuous case if(oldTerms.size() == 0) return *this; ExprHashMap oldToNew(10); clearFlags(); for(unsigned int i=0; i visited(oldToNew); return recursiveSubst(oldToNew, visited); } Expr Expr::substExpr(const ExprHashMap& oldToNew) const { // Catch the vacuous case if(oldToNew.size() == 0) return *this; // Rebuild the map: we'll be using it as a cache ExprHashMap visited(oldToNew); clearFlags(); // Flag all the LHS expressions in oldToNew map. We'll be checking // all flagged expressions (and only those) for substitution. for(ExprHashMap::const_iterator i=oldToNew.begin(), iend=oldToNew.end(); i!=iend; ++i) { (*i).first.setFlag(); } return recursiveSubst(oldToNew, visited); } Expr Expr::substExprQuant(const vector& oldTerms, const vector& newTerms) const { //let us disable this first yeting // static ExprHashMap substCache; // Expr cacheIndex = Expr(RAW_LIST, *this, Expr(RAW_LIST, newTerms)); // ExprHashMap::iterator i = substCache.find(cacheIndex); // if (i != substCache.end()){ // return i->second; // } DebugAssert(oldTerms.size() == newTerms.size(), "substExpr: vectors" "don't match in size"); // Catch the vacuous case if(oldTerms.size() == 0) return *this; ExprHashMap oldToNew(oldTerms.size()); // clearFlags(); for(unsigned int i=0; i visited(oldToNew); Expr returnExpr = recursiveQuantSubst(oldToNew, visited);; // substCache[cacheIndex] = returnExpr; // cout<<"pushed " << cacheIndex << endl << "RET " << returnExpr << endl; return returnExpr; } Expr Expr::substExprQuant(const ExprHashMap& oldToNew) const { ExprHashMap visited(oldToNew); return recursiveQuantSubst(oldToNew,visited); } Expr Expr::recursiveQuantSubst(const ExprHashMap& substMap, ExprHashMap& visited) const { /* [chris 12/3/2009] It appears that visited is never used. */ if (!containsBoundVar()){ // std::cout <<"no bound var " << *this << std::endl; return *this; } // Check the cache. // INVARIANT: visited contains all the flagged expressions, and only those // the above invariant is no longer true. yeting if(getKind() == BOUND_VAR ) { ExprHashMap::const_iterator find = substMap.find(*this); if (find != substMap.end()) { return find->second; } /* // Expr ret = visited[*this]; const Expr ret = substMap[*this]; if (!ret.isNull()){ return ret; } */ } // if(getFlag()) return visited[*this]; // why we need this. // ExprIndex minIndex = 0; // for(ExprHashMap::iterator i = substMap.begin(),iend=substMap.end();i!=iend;++i) { // if(minIndex > (i->first).getIndex()) // minIndex = (i->first).getIndex(); // } Expr replaced; if(isClosure()) { // for safety, we can wrap the following lines by if debug const vector & vars = getVars(); // vector common; // Bound vars which occur in subst // for(vector::const_iterator i = vars.begin(), iend=vars.end(); // i!=iend; ++i) { // if(substMap.count(*i) > 0) common.push_back(*i); // } // if(common.size() > 0) { // cout<<"error in quant subst" << endl; // } else { /* Perform substition on the triggers */ vector > vvNewTriggers = substTriggers(substMap,visited); replaced = getEM()->newClosureExpr(getKind(), vars, getBody().recursiveQuantSubst(substMap, visited), vvNewTriggers ); // } } else { // Not a Closure int changed=0; vector children; for(Expr::iterator i=begin(), iend=end(); i!=iend; ++i){ Expr repChild ; repChild = (*i).recursiveQuantSubst(substMap, visited); if(repChild != *i) changed++; children.push_back(repChild); } if(changed > 0) replaced = Expr(getOp(), children); else replaced = *this; } // visited.insert(*this, replaced); // setFlag(); return replaced; } string Expr::toString() const { return toString(PRESENTATION_LANG); // if(isNull()) return "Null"; // ostringstream ss; // ss << (*this); // return ss.str(); } string Expr::toString(InputLanguage lang) const { if(isNull()) return "Null"; ostringstream ss; ExprStream os(getEM()); os.lang(lang); os.os(ss); os << (*this); return ss.str(); } void Expr::print(InputLanguage lang, bool dagify) const { if(isNull()) { cout << "Null" << endl; return; } ExprStream os(getEM()); os.lang(lang); os.dagFlag(dagify); os << *this << endl; } void Expr::pprint() const { if(isNull()) { cout << "Null" << endl; return; } ExprStream os(getEM()); os << *this << endl; } void Expr::pprintnodag() const { if(isNull()) { cout << "Null" << endl; return; } ExprStream os(getEM()); os.dagFlag(false); os << *this << endl; } void Expr::printnodag() const { print(AST_LANG, false); } ExprStream& Expr::printAST(ExprStream& os) const { if(isNull()) return os << "Null" << endl; bool isLetDecl(getKind() == LETDECL); os << "(" << push; os << getEM()->getKindName(getKind()); if (isApply()) { os << space << "{" << getOp().getExpr() << push << "}"; } else if (isSymbol()) { os << space << "{Symbol: " << getName() << "}"; } else if (isClosure()) { os << space << "{" << space << "(" << push; const vector& vars = getVars(); vector::const_iterator i=vars.begin(), iend=vars.end(); if(i!=iend) { os << *i; ++i; } for(; i!=iend; ++i) os << space << *i; os << push << ") " << pop << pop; os << getBody() << push << "}"; } else { switch(getKind()) { case STRING_EXPR: DebugAssert(isString(), "Expected String"); os << space << "{" << '"'+ getString() + '"' << "}"; break; case SKOLEM_VAR: getExistential(); os << space << "{SKOLEM_" << (int)getIndex() << "}"; break; case RATIONAL_EXPR: os << space << "{" << getRational() << "}"; break; case UCONST: DebugAssert(isVar(), "Expected Var"); os << space << "{" << getName() << "}"; break; case BOUND_VAR: DebugAssert(isVar(), "Expected Var"); os << space << "{"+getName()+"_"+getUid()+"}"; break; case THEOREM_KIND: DebugAssert(isTheorem(), "Expected Theorem"); os << space << "{Theorem: " << getTheorem().toString() << "}"; default: ; // Don't do anything } } for(Expr::iterator i=begin(), iend=end(); i!=iend; ++i) { if(isLetDecl) os << nodag; os << space << *i; } os << push << ")"; os.resetIndent(); return os; } ExprStream& Expr::print(ExprStream& os) const { if(isNull()) return os << "Null" << endl; if (isSymbol()) return os << getName(); switch(getKind()) { case TRUE_EXPR: return os << "TRUE"; case FALSE_EXPR: return os << "FALSE"; case NULL_KIND: return os << "Null"; case STRING_EXPR: return os << '"'+ getString() + '"'; case RATIONAL_EXPR: return os << getRational(); case SKOLEM_VAR: return os << "SKOLEM_" << hash(); case UCONST: return os << getName(); case BOUND_VAR: return os << "(BOUND_VAR "+getName()+"_"+getUid()+")"; case RAW_LIST: { os << "(" << push; bool firstTime(true); for(Expr::iterator i=begin(), iend=end(); i!=iend; ++i) { if(firstTime) firstTime = false; else os << space; os << *i; } return os << push << ")"; } case FORALL: case EXISTS: if(isQuantifier()) { os << "(" << push << getEM()->getKindName(getKind()) << space << "(" << push; const vector& vars = getVars(); vector::const_iterator i=vars.begin(), iend=vars.end(); if(i!=iend) { os << *i; ++i; } for(; i!=iend; ++i) os << space << *i; os << push << ") " << pop << pop; return os << getBody() << push << ")"; } // If not an internal representation of quantifiers, it'll be // printed as "normal" Expr with a kind and children case RESTART: return os << "RESTART " << (*this)[0] << ";"; default: // os << "(" << push; os << getEM()->getKindName(getKind()); // os << push << ")"; } os.resetIndent(); return os; } //! Set initial indentation to n. /*! The indentation will be reset to default unless the second argument is true. This setting only takes effect when printing to std::ostream. When printing to ExprStream, the indentation can be set directly in the ExprStream. */ Expr& Expr::indent(int n, bool permanent) { DebugAssert(!isNull(), "Expr::indent called on Null Expr"); getEM()->indent(n, permanent); return *this; } void Expr::addToNotify(Theory* i, const Expr& e) const { DebugAssert(!isNull(), "Expr::addToNotify() on Null expr"); if(getNotify() == NULL) d_expr->d_notifyList = new NotifyList(getEM()->getCurrentContext()); getNotify()->add(i, e); } bool Expr::containsTermITE() const { if (getType().isBool()) { // We overload the isAtomicFlag to mean !containsTermITE for exprs // of Boolean type if (validIsAtomicFlag()) { return !getIsAtomicFlag(); } for (int k = 0; k < arity(); ++k) { if ((*this)[k].containsTermITE()) { setIsAtomicFlag(false); return true; } } setIsAtomicFlag(true); return false; } else return !isAtomic(); } bool Expr::isAtomic() const { if (getType().isBool()) { return isBoolConst(); } if (validIsAtomicFlag()) { return getIsAtomicFlag(); } for (int k = 0; k < arity(); ++k) { if (!(*this)[k].isAtomic()) { setIsAtomicFlag(false); return false; } } setIsAtomicFlag(true); return true; } bool Expr::isAtomicFormula() const { // TRACE("isAtomic", "isAtomicFormula(", *this, ") {"); if (!getType().isBool()) { // TRACE_MSG("isAtomic", "isAtomicFormula[kid] => false }"); return false; } switch(getKind()) { case FORALL: case EXISTS: case XOR: case NOT: case AND: case OR: case ITE: case IFF: case IMPLIES: // TRACE_MSG("isAtomic", "isAtomicFormula[connective] => false }"); return false; } for (Expr::iterator k = begin(), kend=end(); k != kend; ++k) { if (!(*k).isAtomic()) { // TRACE_MSG("isAtomic", "isAtomicFormula[kid] => false }"); return false; } } // TRACE_MSG("isAtomic", "isAtomicFormula => true }"); return true; } // This is one of the most friequently called routines. Make it as // efficient as possible. int compare(const Expr& e1, const Expr& e2) { // Quick equality check (operator== is implemented independently // and more efficiently) if(e1 == e2) return 0; if(e1.d_expr == NULL) return -1; if(e2.d_expr == NULL) return 1; // Both are non-Null. Check for constant bool e1c = e1.isConstant(); if (e1c != e2.isConstant()) { return e1c ? -1 : 1; } // Compare the indices return (e1.getIndex() < e2.getIndex())? -1 : 1; } /////////////////////////////////////////////////////////////////////// // Class Expr::iterator methods // /////////////////////////////////////////////////////////////////////// ostream& operator<<(ostream& os, const Expr& e) { if(e.isNull()) return os << "Null"; ExprStream es(e.getEM()); es.os(os); es << e; e.getEM()->restoreIndent(); return os; } // Functions from class Type Type::Type(Expr expr) : d_expr(expr) { if (expr.isNull()) return; expr.getEM()->checkType(expr); } Type Type::funType(const std::vector& typeDom, const Type& typeRan) { vector tmp; for(vector::const_iterator i=typeDom.begin(), iend=typeDom.end(); i!=iend; ++i) tmp.push_back(i->getExpr()); tmp.push_back(typeRan.getExpr()); return Type(Expr(ARROW, tmp)); } } // end of namespace CVC3 cvc3-2.4.1/src/expr/expr_stream.cpp0000664000175400017540000002520111437276450017071 0ustar mdetersmdeters/*****************************************************************************/ /*! * \file expr_stream.cpp * * Author: Sergey Berezin * * Created: Mon Jun 16 13:57:29 2003 * *
* * License to use, copy, modify, sell and/or distribute this software * and its documentation for any purpose is hereby granted without * royalty, subject to the terms and conditions defined in the \ref * LICENSE file provided with this distribution. * *
* */ /*****************************************************************************/ #include "pretty_printer.h" #include "expr_stream.h" #include "theory_core.h" using namespace std; namespace CVC3 { ExprStream::ExprStream(ExprManager *em) : d_em(em), d_os(&cout), d_depth(em->printDepth()), d_currDepth(0), d_lang(em->getOutputLang()), d_indent(em->withIndentation()), d_col(em->indent()), d_lineWidth(em->lineWidth()), d_indentReg(0), d_beginningOfLine(false), d_dag(em->dagPrinting()), d_dagBuilt(false), d_idCounter(0), d_nodag(false) { d_indentStack.push_back(d_em->indent()); d_indentLast = d_indentStack.size(); d_dagPtr.push_back(0); d_lastDagSize=d_dagPtr.size(); } //! Generating unique names in DAG expr string ExprStream::newName() { ostringstream name; name << "v_" << d_idCounter++; return name.str(); } static bool isTrivialExpr(const Expr& e) { return (e.arity()==0 && !e.isClosure()); } //! Traverse the Expr, collect shared subexpressions in d_dagMap void ExprStream::collectShared(const Expr& e, ExprMap& cache) { // If seen before, and it's not something trivial, add to d_dagMap if(!isTrivialExpr(e) && cache.count(e) > 0) { if(d_dagMap.count(e) == 0) { string s(newName()); if (d_lang == SMTLIB_LANG) { Type type(e.getType()); if (type.isBool()) { s = "$" + s; } else { s = "?" + s; } } else if (d_lang == SMTLIB_V2_LANG) { s = "?" + s; } if (d_lang == TPTP_LANG) { s = to_upper( s); } d_dagMap[e] = s; d_newDagMap[e] = s; d_dagStack.push_back(e); } return; } cache[e] = true; for(Expr::iterator i=e.begin(), iend=e.end(); i!=iend; ++i) collectShared(*i, cache); d_dagBuilt = true; } //! Wrap e into the top-level LET ... IN header from the dagMap /*! * We rely on the fact that d_dagMap is ordered by the Expr creation * order, so earlier expressions cannot depend on later ones. */ Expr ExprStream::addLetHeader(const Expr& e) { ExprManager* em = e.getEM(); if(d_newDagMap.size() == 0) return e; vector decls; for(ExprMap::iterator i=d_newDagMap.begin(), iend=d_newDagMap.end(); i!=iend; ++i) { Expr var(em->newVarExpr((*i).second)); if(((*i).first).isType()) decls.push_back(Expr(LETDECL, var, em->newLeafExpr(TYPE), (*i).first)); else decls.push_back(Expr(LETDECL, var, (*i).first)); } d_newDagMap.clear(); return Expr(LET, Expr(LETDECLS, decls), e); } void ExprStream::popIndent() { DebugAssert(d_indentStack.size() > 0 && d_indentStack.size() > d_indentLast, "ExprStream::popIndent(): popped too much: " "stack size = "+int2string(d_indentStack.size()) +", indentLast = "+int2string(d_indentLast)); if(d_indentStack.size() > 0 && d_indentStack.size() > d_indentLast) d_indentStack.pop_back(); } //! Reset indentation to what it was at this level void ExprStream::resetIndent() { while(d_indentStack.size() > d_indentLast) d_indentStack.pop_back(); } void ExprStream::pushDag() { d_dagBuilt = false; d_dagPtr.push_back(d_dagStack.size()); } void ExprStream::popDag() { DebugAssert(d_dagPtr.size() > d_lastDagSize, "ExprStream::popDag: popping more than pushed"); DebugAssert(d_lastDagSize > 0, "ExprStream::popDag: this cannot happen!"); if(d_dagPtr.size() > d_lastDagSize) { size_t size(d_dagPtr.back()); d_dagPtr.pop_back(); while(d_dagStack.size() > size) { d_dagMap.erase(d_dagStack.back()); d_dagStack.pop_back(); } d_newDagMap.clear(); } } void ExprStream::resetDag() { while(d_dagPtr.size() > d_lastDagSize) popDag(); } /*! \defgroup ExprStream_Op Overloaded operator<< * \ingroup PrettyPrinting * @{ */ //! Use manipulators which are functions over ExprStream& ExprStream& operator<<(ExprStream& os, ExprStream& (*manip)(ExprStream&)) { return (*manip)(os); } //! Print Expr ExprStream& operator<<(ExprStream& os, const Expr& e) { //os << "Printing in expr_stream"; // If the max print depth is reached, print "..." if(os.d_depth >= 0 && os.d_currDepth > os.d_depth) return os << "..."; Expr e2(e); // Don't LET-ify commands like ASSERT, QUERY, TRANSFORM switch(e.getKind()) { case QUERY: case ASSERT: case RESTART: case TRANSFORM: case TYPE: case CONST: os.d_nodag = true; break; default: break; } // Check cache for DAG printing if(os.d_dag && !os.d_nodag && os.d_lang != SPASS_LANG) { // SPASS doesn't support LET if(os.d_dagBuilt) { ExprMap::iterator i(os.d_dagMap.find(e)); if(i != os.d_dagMap.end()) { ostringstream ss; ss << (*i).second; return os << ss.str(); } } else { // We are at the top level; build dagMap and print LET header ExprMap cache; os.collectShared(e, cache); e2 = os.addLetHeader(e); } } os.d_nodag=false; // Increase the depth before the (possibly) recursive call os.d_currDepth++; // Save the indentation stack position and register int indentLast = os.d_indentLast; int reg = os.d_indentReg; size_t lastDagSize = os.d_lastDagSize; os.d_indentLast = os.d_indentStack.size(); os.d_lastDagSize = os.d_dagPtr.size(); PrettyPrinter* pp = os.d_em->getPrinter(); // If no pretty-printer, or the language is AST, print the AST if(pp == NULL || os.d_lang == AST_LANG) e2.printAST(os); // Otherwise simply call the pretty-printer else pp->print(os, e2); // Restore the depth after the (possibly) recursive call os.d_currDepth--; // Restore the indentation stack and register os.resetIndent(); os.resetDag(); os.d_indentLast = indentLast; os.d_indentReg = reg; os.d_lastDagSize = lastDagSize; return os; } //! Print Type ExprStream& operator<<(ExprStream& os, const Type& t) { return os << t.getExpr(); } //! Print string /*! This is where all the indentation is happening. The algorithm for determining whether to go to the next line is the following: - If the new d_col does not exceed d_lineWidth/2 or current indentation, don't bother. - If the difference between the new d_col and the current indentation is less than d_lineWidth/4, don't bother either, so that we don't get lots of very short lines clumped to the right side. - Similarly, if the difference between the old d_col and the current indentation is less than d_lineWidth/6, keep the same line. Otherwise, for long atomic strings, we may get useless line breaks. - Otherwise, go to the next line. */ ExprStream& operator<<(ExprStream& os, const string& s) { // Save the old position int oldCol(os.d_col); // The new position after printing s os.d_col += s.size(); if(os.d_indent) { // Current indentation position int n(os.d_indentStack.size()? os.d_indentStack.back() : 0); // See if we need to go to the next line before printing. if(2*os.d_col > os.d_lineWidth && 4*(os.d_col - n) > os.d_lineWidth && 6*(oldCol - n) > os.d_lineWidth) { os << endl; // Recompute the new column os.d_col += s.size(); } } *os.d_os << s; os.d_beginningOfLine = false; return os; } //! Print char* string ExprStream& operator<<(ExprStream& os, const char* s) { return os << string(s); } //! Print Rational ExprStream& operator<<(ExprStream& os, const Rational& r) { ostringstream ss; ss << r; return os << ss.str(); } //! Print int ExprStream& operator<<(ExprStream& os, int i) { ostringstream ss; ss << i; return os << ss.str(); } /*! @} */ // End of group ExprStream_Op /*! \defgroup ExprStream_Manip Manipulators * \ingroup PrettyPrinting * @{ */ //! Set the indentation to the current position ExprStream& push(ExprStream& os) { os.pushIndent(); return os; } //! Restore the indentation ExprStream& pop(ExprStream& os) { os.popIndent(); return os; } //! Remember the current indentation and pop to the previous position /*! There is only one register to save the previous position. If you use popSave() more than once, only the latest position can be restored with pushRestore(). */ ExprStream& popSave(ExprStream& os) { os.d_indentReg = os.d_indentStack.size() ? os.d_indentStack.back() : 0; os.popIndent(); return os; } //! Set the indentation to the position saved by popSave() /*! There is only one register to save the previous position. Using pushRestore() several times will set intendation to the same position. */ ExprStream& pushRestore(ExprStream& os) { os.pushIndent(os.d_indentReg); return os; } //! Reset the indentation to the default at this level ExprStream& reset(ExprStream& os) { os.resetIndent(); return os; } //! Insert a single white space separator /*! It is preferred to use 'space' rather than a string of spaces (" ") because ExprStream needs to delete extra white space if it decides to end the line. If you use strings for spaces, you'll mess up the indentation. */ ExprStream& space(ExprStream& os) { // Prevent " " to carry to the next line if(!os.d_beginningOfLine) os << push << " " << pop; return os; } ExprStream& nodag(ExprStream& os) { os.d_nodag = true; return os; } ExprStream& pushdag(ExprStream& os) { os.pushDag(); return os; } ExprStream& popdag(ExprStream& os) { os.popDag(); return os; } /*! @} */ // End of group ExprStream_Manip } // End of namespace CVC3 namespace std { //! Print the end-of-line /*! * The new line will not necessarily start at column 0 because of * indentation. * \ingroup ExprStream_Manip */ CVC3::ExprStream& endl(CVC3::ExprStream& os) { if(os.d_indent) { // Current indentation int n(os.d_indentStack.size()? os.d_indentStack.back() : 0); // Create a string of n white spaces string spaces(n, ' '); (*os.d_os) << endl << spaces; os.d_col = n; } else { (*os.d_os) << endl; os.d_col = 0; } os.d_beginningOfLine = true; return os; } } cvc3-2.4.1/src/theory_uf/0000775000175400017540000000000011630011320015034 5ustar mdetersmdeterscvc3-2.4.1/src/theory_uf/Makefile0000664000175400017540000000052610533133655016520 0ustar mdetersmdeters################################################## # About this Makefile # # This Makefile depends on Makefile.opts ################################################## MODULE = theory_uf SRC = uf_theorem_producer.cpp theory_uf.cpp HEADERS = \ uf_proof_rules.h \ uf_theorem_producer.h LIBRARY=libtheory_uf.a include ../../Makefile.local cvc3-2.4.1/src/theory_uf/uf_proof_rules.h0000664000175400017540000000267010466450544020270 0ustar mdetersmdeters/*****************************************************************************/ /*! *\file uf_proof_rules.h *\brief Abstract interface for uninterpreted function/predicate proof rules * * Author: Clark Barrett * * Created: Tue Aug 31 23:12:01 2004 * *
* * License to use, copy, modify, sell and/or distribute this software * and its documentation for any purpose is hereby granted without * royalty, subject to the terms and conditions defined in the \ref * LICENSE file provided with this distribution. * *
* * CLASS: UFProofRules * */ /*****************************************************************************/ #ifndef _cvc3__theory_uf__uf_proof_rules_h_ #define _cvc3__theory_uf__uf_proof_rules_h_ namespace CVC3 { class Expr; class Theorem; class UFProofRules { public: // Destructor virtual ~UFProofRules() { } //////////////////////////////////////////////////////////////////// // Proof rules //////////////////////////////////////////////////////////////////// virtual Theorem relToClosure(const Theorem& rel) = 0; virtual Theorem relTrans(const Theorem& t1, const Theorem& t2) = 0; //! Beta reduction: |- (lambda x. f(x))(arg) = f(arg) virtual Theorem applyLambda(const Expr& e) = 0; //! Replace LETDECL in the operator with the definition virtual Theorem rewriteOpDef(const Expr& e) = 0; }; // end of class UFProofRules } // end of namespace CVC3 #endif cvc3-2.4.1/src/theory_uf/uf_theorem_producer.h0000664000175400017540000000254310466450544021276 0ustar mdetersmdeters/*****************************************************************************/ /*! *\file uf_theorem_producer.h *\brief TRUSTED implementation of uninterpreted function/predicate proof rules * * Author: Clark Barrett * * Created: Tue Aug 31 23:14:54 2004 * *
* * License to use, copy, modify, sell and/or distribute this software * and its documentation for any purpose is hereby granted without * royalty, subject to the terms and conditions defined in the \ref * LICENSE file provided with this distribution. * *
* * CLASS: UFTheoremProducer * */ /*****************************************************************************/ #ifndef _cvc3__theory_uf__uf_theorem_producer_h_ #define _cvc3__theory_uf__uf_theorem_producer_h_ #include "uf_proof_rules.h" #include "theorem_producer.h" namespace CVC3 { class TheoryUF; class UFTheoremProducer: public UFProofRules, public TheoremProducer { TheoryUF* d_theoryUF; private: public: //! Constructor UFTheoremProducer(TheoremManager* tm, TheoryUF* theoryUF) : TheoremProducer(tm), d_theoryUF(theoryUF) { } Theorem relToClosure(const Theorem& rel); Theorem relTrans(const Theorem& t1, const Theorem& t2); Theorem applyLambda(const Expr& e); Theorem rewriteOpDef(const Expr& e); }; // end of class UFTheoremProducer } // end of namespace CVC3 #endif cvc3-2.4.1/src/theory_uf/uf_theorem_producer.cpp0000664000175400017540000001103210466450544021622 0ustar mdetersmdeters/*****************************************************************************/ /*! *\file uf_theorem_producer.cpp *\brief TRUSTED implementation of uninterpreted function/predicate rules * * Author: Clark Barrett * * Created: Tue Aug 31 23:20:27 2004 * *
* * License to use, copy, modify, sell and/or distribute this software * and its documentation for any purpose is hereby granted without * royalty, subject to the terms and conditions defined in the \ref * LICENSE file provided with this distribution. * *
* */ /*****************************************************************************/ // This code is trusted #define _CVC3_TRUSTED_ #include "uf_theorem_producer.h" #include "theory_uf.h" #include "theory_core.h" using namespace std; using namespace CVC3; //////////////////////////////////////////////////////////////////// // TheoryUF: trusted method for creating UFTheoremProducer //////////////////////////////////////////////////////////////////// UFProofRules* TheoryUF::createProofRules() { return new UFTheoremProducer(theoryCore()->getTM(), this); } //////////////////////////////////////////////////////////////////// // Proof rules //////////////////////////////////////////////////////////////////// #define CLASS_NAME "CVC3::UFTheoremProducer" Theorem UFTheoremProducer::relToClosure(const Theorem& rel) { const Expr& relExpr = rel.getExpr(); if(CHECK_PROOFS) CHECK_SOUND(relExpr.isApply() && relExpr.arity() == 2, CLASS_NAME "theorem is not a relation or has wrong arity:\n" + rel.getExpr().toString()); Proof pf; if(withProof()) { pf = newPf("rel_closure", rel.getProof()); } const string& name = relExpr.getOp().getExpr().getName(); Expr tc = d_theoryUF->transClosureExpr(name, relExpr[0], relExpr[1]); return newTheorem(tc, rel.getAssumptionsRef(), pf); } Theorem UFTheoremProducer::relTrans(const Theorem& t1, const Theorem& t2) { const Expr& e1 = t1.getExpr(); const Expr& e2 = t2.getExpr(); if (CHECK_PROOFS) { CHECK_SOUND(e1.getOpKind() == TRANS_CLOSURE && e1.arity() == 2, (CLASS_NAME "theorem is not a proper trans_closure expr:\n" + e1.toString()).c_str()); CHECK_SOUND(e2.getOpKind() == TRANS_CLOSURE && e2.arity() == 2, (CLASS_NAME "theorem is not a proper trans_closure expr:\n" + e2.toString()).c_str()); } if (CHECK_PROOFS) { CHECK_SOUND(e1.getOpExpr().getName() == e2.getOpExpr().getName() && e1[1] == e2[0], (CLASS_NAME "Expr's don't match:\n" + e1.toString() + " and " + e2.toString()).c_str()); } Assumptions a(t1, t2); Proof pf; if(withProof()) { vector pfs; pfs.push_back(t1.getProof()); pfs.push_back(t2.getProof()); pf = newPf("rel_trans", pfs); } return newTheorem(Expr(e1.getOp(), e1[0], e2[1]), a, pf); } Theorem UFTheoremProducer::applyLambda(const Expr& e) { if(CHECK_PROOFS) { CHECK_SOUND(e.isApply() && e.getOpKind() == LAMBDA, "applyLambda("+e.toString() +"):\n\n expression is not an APPLY"); } Expr lambda(e.getOpExpr()); if (CHECK_PROOFS) { CHECK_SOUND(lambda.isLambda(), "applyLambda:\n" "Operator is not LAMBDA: " + lambda.toString()); } Expr body(lambda.getBody()); const vector& vars = lambda.getVars(); if(CHECK_PROOFS) { CHECK_SOUND(vars.size() == (size_t)e.arity(), "wrong number of arguments applied to lambda\n"); } // Use the Expr's efficient substitution body = body.substExpr(vars, e.getKids()); // for (unsigned i = 0; i < vars.size(); i++) { // body = substFreeTerm(body, vars[i], e[i]); // } Proof pf; if(withProof()) pf = newPf("apply_lambda", e); return newRWTheorem(e, body, Assumptions::emptyAssump(), pf); } Theorem UFTheoremProducer::rewriteOpDef(const Expr& e) { if(CHECK_PROOFS) { CHECK_SOUND(e.isApply(), "UFTheoremProducer::rewriteOpDef: 'e' is not a " "function application:\n\n "+e.toString()); } Expr op = e.getOpExpr(); int opKind = op.getKind(); if(CHECK_PROOFS) { CHECK_SOUND(opKind==LETDECL, "UFTheoremProducer::rewriteOpDef: operator is not a " "named function in:\n\n "+e.toString()); } // Now actually replace the name with the definition while(opKind==LETDECL) { if(CHECK_PROOFS) { CHECK_SOUND(op.arity()==2, "UFTheoremProducer::rewriteOpDef: bad named " "operator in:\n\n "+e.toString()); } op = op[1]; opKind = op.getKind(); } // ...and construct a Theorem Proof pf; if(withProof()) pf = newPf("rewrite_op_def", e); return newRWTheorem(e, Expr(op.mkOp(), e.getKids()), Assumptions::emptyAssump(), pf); } cvc3-2.4.1/src/theory_uf/theory_uf.cpp0000664000175400017540000010454211437276452017602 0ustar mdetersmdeters/*****************************************************************************/ /*! * \file theory_uf.cpp * * Author: Clark Barrett * * Created: Fri Jan 24 02:07:59 2003 * *
* * License to use, copy, modify, sell and/or distribute this software * and its documentation for any purpose is hereby granted without * royalty, subject to the terms and conditions defined in the \ref * LICENSE file provided with this distribution. * *
* */ /*****************************************************************************/ #include "theory_uf.h" #include "uf_proof_rules.h" #include "typecheck_exception.h" #include "parser_exception.h" #include "smtlib_exception.h" #include "command_line_flags.h" #include "theory_core.h" #include "translator.h" // HACK: include theory_records.h to access the TUPLE_TYPE kind #include "theory_records.h" using namespace std; using namespace CVC3; /////////////////////////////////////////////////////////////////////////////// // TheoryUF Public Methods // /////////////////////////////////////////////////////////////////////////////// TheoryUF::TheoryUF(TheoryCore* core)//, bool useAckermann) : Theory(core, "Uninterpreted Functions"), d_applicationsInModel(core->getFlags()["applications"].getBool()), d_funApplications(core->getCM()->getCurrentContext()), d_funApplicationsIdx(core->getCM()->getCurrentContext(), 0), d_sharedIdx1(core->getCM()->getCurrentContext(), 0), d_sharedIdx2(core->getCM()->getCurrentContext(), 0), d_sharedTermsMap(core->getCM()->getCurrentContext()) // d_useAckermann(useAckermann) { d_rules = createProofRules(); // Register new local kinds with ExprManager getEM()->newKind(TRANS_CLOSURE, "_TRANS_CLOSURE"); getEM()->newKind(OLD_ARROW, "_OLD_ARROW", true); vector kinds; //TODO: should this stuff really be in theory_uf? kinds.push_back(TYPEDECL); kinds.push_back(LAMBDA); kinds.push_back(ARROW); kinds.push_back(OLD_ARROW); kinds.push_back(UFUNC); kinds.push_back(TRANS_CLOSURE); registerTheory(this, kinds); } TheoryUF::~TheoryUF() { delete d_rules; } //TODO: clean up transitive closure tables // be sure to free CD objects void TheoryUF::assertFact(const Theorem& e) { const Expr& expr = e.getExpr(); switch (expr.getKind()) { case NOT: break; case APPLY: if (expr.getOpExpr().computeTransClosure()) { enqueueFact(d_rules->relToClosure(e)); } else if (expr.getOpKind() == TRANS_CLOSURE) { // const Expr& rel = expr.getFun(); DebugAssert(expr.isApply(), "Should be apply"); Expr rel = resolveID(expr.getOpExpr().getName()); DebugAssert(!rel.isNull(), "Expected known identifier"); DebugAssert(rel.isSymbol() && rel.getKind()==UFUNC && expr.arity()==2, "Unexpected use of transitive closure: "+expr.toString()); // Insert into transitive closure table ExprMap::iterator i = d_transClosureMap.find(rel); TCMapPair* pTable; if (i == d_transClosureMap.end()) { pTable = new TCMapPair(); d_transClosureMap[rel] = pTable; } else { pTable = (*i).second; } ExprMap*>::iterator i2 = pTable->appearsFirstMap.find(expr[0]); CDList* pList; if (i2 == pTable->appearsFirstMap.end()) { pList = new(true) CDList(theoryCore()->getCM()->getCurrentContext()); pTable->appearsFirstMap[expr[0]] = pList; } else { pList = (*i2).second; } pList->push_back(e); i2 = pTable->appearsSecondMap.find(expr[1]); if (i2 == pTable->appearsSecondMap.end()) { pList = new(true) CDList(theoryCore()->getCM()->getCurrentContext()); pTable->appearsSecondMap[expr[1]] = pList; } else { pList = (*i2).second; } pList->push_back(e); // Compute transitive closure with existing relations size_t s,l; i2 = pTable->appearsFirstMap.find(expr[1]); if (i2 != pTable->appearsFirstMap.end()) { pList = (*i2).second; s = pList->size(); for (l = 0; l < s; ++l) { enqueueFact(d_rules->relTrans(e,(*pList)[l])); } } i2 = pTable->appearsSecondMap.find(expr[0]); if (i2 != pTable->appearsSecondMap.end()) { pList = (*i2).second; s = pList->size(); for (l = 0; l < s; ++l) { enqueueFact(d_rules->relTrans((*pList)[l],e)); } } } break; default: break; } } void TheoryUF::checkSat(bool fullEffort) { // Check for any unexpanded lambdas bool enqueued = false; for(; d_funApplicationsIdx < d_funApplications.size(); d_funApplicationsIdx = d_funApplicationsIdx + 1) { const Expr& e = d_funApplications[d_funApplicationsIdx]; if(e.getOp().getExpr().isLambda()) { IF_DEBUG(debugger.counter("Expanded lambdas (checkSat)")++;) enqueueFact(d_rules->applyLambda(e)); enqueued = true; } } // If something has been returned, we are done if (!fullEffort || enqueued) return; // Expand on the shared terms for( ; d_sharedIdx1 < d_funApplications.size(); d_sharedIdx1 = d_sharedIdx1 + 1, d_sharedIdx2 = 0 ) { Expr f1 = d_funApplications[d_sharedIdx1]; if( f1.getOpKind() == UFUNC && !f1.getSig().isNull() ) { f1 = f1.getSig().getRHS(); Expr f1_fun = f1.getOp().getExpr(); for( ; d_sharedIdx2 < d_sharedIdx1; d_sharedIdx2 = d_sharedIdx2 + 1 ) { Expr f2 = d_funApplications[d_sharedIdx2]; if (f2.getOpKind() == UFUNC && !f2.getSig().isNull() ) { f2 = f2.getSig().getRHS(); Expr f2_fun = f2.getOp().getExpr(); if( f1 != f2 && find(f1).getRHS() != find(f2).getRHS() && f1_fun == f2_fun ) { for( int k = 0; k < f1.arity(); ++k ) { Expr x_k = f1[k]; Expr y_k = f2[k]; if( d_sharedTermsMap.find(x_k) == d_sharedTermsMap.end() ) continue; if( d_sharedTermsMap.find(y_k) == d_sharedTermsMap.end() ) continue; Expr eq = x_k.eqExpr(y_k); if( !simplify(eq).getRHS().isBoolConst() ) { TRACE("sharing", "splitting " + y_k.toString(), " and ", x_k.toString()); TRACE("sharing", "from " + f2.toString(), " and ", f1.toString()); addSplitter(eq); enqueued = true; } } if( enqueued ) return; } } } } } } Theorem TheoryUF::rewrite(const Expr& e) { if (e.isApply()) { const Expr& op = e.getOpExpr(); int opKind = op.getKind(); switch(opKind) { case LAMBDA: { Theorem res = d_rules->applyLambda(e); // Simplify recursively res = transitivityRule(res, simplify(res.getRHS())); IF_DEBUG(debugger.counter("Expanded lambdas")++;) return res; } default: // A truly uninterpreted function if (e.getType().isBool()) return reflexivityRule(e); else return rewriteCC(e); } } else { e.setRewriteNormal(); return reflexivityRule(e); } } void TheoryUF::setup(const Expr& e) { if (e.isTerm() && e.getType().card() != CARD_INFINITE) { addSharedTerm(e); theoryOf(e.getType())->addSharedTerm(e); } if (e.getKind() != APPLY) return; // if (d_useAckermann) { // Theorem thm = getCommonRules()->varIntroSkolem(e); // theoryCore()->addToVarDB(thm.getRHS()); // enqueueFact(thm); // } // else { setupCC(e); // } // Add this function application for concrete model generation TRACE("model", "TheoryUF: add function application ", e, ""); d_funApplications.push_back(e); } void TheoryUF::update(const Theorem& e, const Expr& d) { /* int k, ar(d.arity()); const Theorem& dEQdsig = d.getSig(); if (!dEQdsig.isNull()) { Expr dsig = dEQdsig.getRHS(); Theorem thm = updateHelper(d); const Expr& sigNew = thm.getRHS(); if (sigNew == dsig) return; dsig.setRep(Theorem()); const Theorem& repEQsigNew = sigNew.getRep(); if (!repEQsigNew.isNull()) { d.setSig(Theorem()); enqueueFact(transitivityRule(repEQsigNew, symmetryRule(thm))); } else { for (k = 0; k < ar; ++k) { if (sigNew[k] != dsig[k]) { sigNew[k].addToNotify(this, d); } } d.setSig(thm); sigNew.setRep(thm); if (d_compute_trans_closure && d.getKind() == APPLY && d.arity() == 2 && findExpr(d).isTrue()) { thm = iffTrueElim(transitivityRule(symmetryRule(thm),find(d))); enqueueFact(d_rules->relToClosure(thm)); } } } */ // Record the original signature const Theorem& dEQdsig = d.getSig(); if (!dEQdsig.isNull()) { const Expr& dsig = dEQdsig.getRHS(); Theorem thm = updateHelper(d); const Expr& sigNew = thm.getRHS(); if (sigNew == dsig) { // TRACE_MSG("facts update", "updateCC["+getName()+"]() [no change] => }"); return; } dsig.setRep(Theorem()); const Theorem& repEQsigNew = sigNew.getRep(); if (!repEQsigNew.isNull()) { d.setSig(Theorem()); enqueueFact(transitivityRule(repEQsigNew, symmetryRule(thm))); } else if (d.getType().isBool()) { d.setSig(Theorem()); enqueueFact(thm); } else { int k, ar(d.arity()); for (k = 0; k < ar; ++k) { if (sigNew[k] != dsig[k]) { sigNew[k].addToNotify(this, d); } } d.setSig(thm); sigNew.setRep(thm); if (dsig != sigNew && d.isApply() && findExpr(d).isTrue()) { if (d.getOpExpr().computeTransClosure()) { thm = getCommonRules()->iffTrueElim(transitivityRule(symmetryRule(thm), find(d))); enqueueFact(d_rules->relToClosure(thm)); } else if (d.getOpKind() == TRANS_CLOSURE) { thm = getCommonRules()->iffTrueElim(transitivityRule(symmetryRule(thm), find(d))); enqueueFact(thm); } } } } } void TheoryUF::checkType(const Expr& e) { switch (e.getKind()) { case ARROW: { if (e.arity() < 2) throw Exception ("Function type needs at least two arguments" +e.toString()); Expr::iterator i = e.begin(), iend = e.end(); for (; i != iend; ) { Type t(*i); ++i; if (i == iend && t.isBool()) break; if (t.isBool()) throw Exception ("Function argument types must be non-Boolean: " +e.toString()); if (t.isFunction()) throw Exception ("Function domain or range types cannot be functions: " +e.toString()); } break; } case TYPEDECL: { break; } default: DebugAssert(false, "Unexpected kind in TheoryUF::checkType" +getEM()->getKindName(e.getKind())); } } Cardinality TheoryUF::finiteTypeInfo(Expr& e, Unsigned& n, bool enumerate, bool computeSize) { if (e.getKind() != ARROW) { // uninterpreted type return CARD_UNKNOWN; } Expr::iterator i = e.begin(), iend = e.end(); Cardinality card = CARD_FINITE, cardTmp; Unsigned thisSize = 1, size; bool getSize = enumerate || computeSize; for (; i != iend; ) { Expr e2 = (*i); cardTmp = theoryOf(e2)->finiteTypeInfo(e2, size, getSize, false); if (cardTmp == CARD_INFINITE) { return CARD_INFINITE; } else if (cardTmp == CARD_UNKNOWN) { card = CARD_UNKNOWN; getSize = false; // Keep looking to see if we can determine it is infinite } else if (getSize) { thisSize = thisSize * size; // Give up if it gets too big if (thisSize > 1000000) thisSize = 0; if (thisSize == 0) { getSize = false; } } } if (card == CARD_FINITE) { if (enumerate) { // TODO: enumerate functions? maybe at least n == 0 e = Expr(); } if (computeSize) { n = thisSize; } } return card; } void TheoryUF::computeType(const Expr& e) { switch (e.getKind()) { case LAMBDA: { vector args; const vector& vars = e.getVars(); DebugAssert(vars.size() > 0, "TheorySimulate::computeType("+e.toString()+")"); for(vector::const_iterator i=vars.begin(), iend=vars.end(); i!=iend; ++i) args.push_back((*i).getType()); e.setType(Type::funType(args, e.getBody().getType())); break; } case APPLY: { theoryOf(APPLY)->computeType(e); break; } case TRANS_CLOSURE: { DebugAssert(e.isSymbol(), "Expected symbol"); Expr funExpr = resolveID(e.getName()); if (funExpr.isNull()) { throw TypecheckException ("Attempt to take transitive closure of unknown id: " +e.getName()); } Type funType = funExpr.getType(); if(!funType.isFunction()) { throw TypecheckException ("Attempt to take transitive closure of non-function:\n\n" +funExpr.toString() + "\n\n which has type: " +funType.toString()); } if(funType.arity()!=3) { throw TypecheckException ("Attempt to take transitive closure of non-binary function:\n\n" +funExpr.toString() + "\n\n which has type: " +funType.toString()); } if (!funType[2].isBool()) { throw TypecheckException ("Attempt to take transitive closure of function:\n\n" +funExpr.toString() + "\n\n which does not return BOOLEAN"); } e.setType(funType); break; } default: DebugAssert(false,"Unexpected type: "+e.toString()); break; } } Type TheoryUF::computeBaseType(const Type& t) { const Expr& e = t.getExpr(); switch(e.getKind()) { case ARROW: { DebugAssert(e.arity() > 0, "Expected non-empty ARROW"); vector kids; for(Expr::iterator i=e.begin(), iend=e.end(); i!=iend; ++i) { kids.push_back(getBaseType(Type(*i)).getExpr()); } return Type(Expr(e.getOp(), kids)); } case TYPEDECL: return t; default: DebugAssert(false, "TheoryUF::computeBaseType("+t.toString()+")"); return t; } } void TheoryUF::computeModelTerm(const Expr& e, std::vector& v) { for(CDList::const_iterator i=d_funApplications.begin(), iend=d_funApplications.end(); i!=iend; ++i) { if((*i).isApply() && (*i).getOp().getExpr() == e) { // Add both the function application // getModelTerm(*i, v); v.push_back(*i); // and the arguments to the model terms. Reason: the argument // to the function better be a concrete value, and it might not // necessarily be in the current list of model terms. for(Expr::iterator j=(*i).begin(), jend=(*i).end(); j!=jend; ++j) // getModelTerm(*j, v); v.push_back(*j); } } } void TheoryUF::computeModel(const Expr& e, std::vector& vars) { // Repeat the same search for applications of e as in // computeModelTerm(), but this time get the concrete values of the // arguments, and return the applications of e to concrete values in // vars. // We'll assign 'e' a value later. vars.push_back(e); // Map of f(c) to val for concrete values of c and val ExprHashMap appls; for(CDList::const_iterator i=d_funApplications.begin(), iend=d_funApplications.end(); i!=iend; ++i) { if((*i).isApply() && (*i).getOp().getExpr() == e) { // Update all arguments with concrete values vector thms; vector changed; for(int j=0; j<(*i).arity(); ++j) { Theorem asst(getModelValue((*i)[j])); if(asst.getLHS()!=asst.getRHS()) { thms.push_back(asst); changed.push_back(j); } } Expr var; if(changed.size()>0) { // Arguments changed. Compute the new application, and assign // it a concrete value Theorem subst = substitutivityRule(*i, changed, thms); assignValue(transitivityRule(symmetryRule(subst), getModelValue(*i))); var = subst.getRHS(); } else var = *i; if(d_applicationsInModel) vars.push_back(var); // Record it in the map appls[var] = getModelValue(var).getRHS(); } } // Create a LAMBDA expression for e if(appls.size()==0) { // Leave it fully uninterpreted assignValue(reflexivityRule(e)); } else { // Bound vars vector args; Type tp(e.getType()); static unsigned count(0); DebugAssert(tp.isFunction(), "TheoryUF::computeModel("+e.toString() +" : "+tp.toString()+")"); for(int i=0, iend=tp.arity()-1; inewBoundVarExpr(str, int2string(count++)); v.setType(tp[i]); args.push_back(v); } DebugAssert(args.size()>0, "TheoryUF::computeModel()"); ExprHashMap::iterator i=appls.begin(), iend=appls.end(); DebugAssert(i!=iend, "TheoryUF::computeModel(): empty appls hash"); // Use one of the concrete values as a default Expr res((*i).second); ++i; for(; i!=iend; ++i) { // Optimization: if the current value is the same as that of the // next application, skip this case; i.e. keep 'res' instead of // building ite(cond, res, res). if((*i).second == res) continue; // Create an ITE condition Expr cond; vector eqs; for(int j=0, jend=args.size(); jT, // and e = f(e0,...,en), then the TCC is // // pred_T0(e0) & ... & pred_Tn(en) & TCC(e), // // where the last TCC(e) is the conjunction of TCCs for the // arguments, which ensures that all arguments are defined. // // If the operator is a lambda-expression, compute the TCC for // the beta-reduced expression. We do this in a somewhat sneaky // but an efficient way: first, compute TCC of the op.body // (which depends on the bound vars), then wrap that into // lambda, and apply it to the arguments: // // (LAMBDA(x0...xn): TCC(op.body)) (e0 ... en) // // The reason it is more efficient is that TCC(op.body) is cached, // and doesn't change with the arguments. vector preds; preds.push_back(Theory::computeTCC(e)); DebugAssert(e.isApply(), "Should be application"); Expr op(e.getOp().getExpr()); Type funType(op.getType()); DebugAssert(funType.isFunction() || funType.isBool(), "TheoryUF::computeTCC(): funType = " +funType.toString()); if(funType.isFunction()) { DebugAssert(funType.arity() == e.arity()+1, "TheoryUF::computeTCC(): funType = " +funType.toString()+"\n e = "+e.toString()); for(int i=0, iend=e.arity(); igetTranslator()->fixConstName(e.getName()); break; default: { DebugAssert(false, "TheoryUF::print: SMTLIB_LANG: Unexpected expression: " +getEM()->getKindName(e.getKind())); } } } ExprStream& TheoryUF::print(ExprStream& os, const Expr& e) { switch(os.lang()) { case SIMPLIFY_LANG: switch(e.getKind()) { case OLD_ARROW: case ARROW: os<<"ERROR:ARROW:unsupported in Simplify\n"; break; case LAMBDA: { os<<"ERROR:LAMBDA:unsupported in Simplify\n"; break; } case TRANS_CLOSURE: os<<"ERROR:TRANS_CLOSURE:unsupported in Simplify\n"; break; case TYPEDECL: os<<"ERROR:TYPEDECL:unsupported in Simplify\n"; break; case UFUNC: case APPLY: if(e.isApply()) os << "(" << e.getOp().getExpr()<<" "; if(e.arity() > 0) { bool first(true); for (Expr::iterator i=e.begin(), iend=e.end(); i!=iend; ++i) { if(first) first = false; else os << " " ; os << *i; } os << ")"; } break; default: { DebugAssert(false, "TheoryUF::print: Unexpected expression: " +getEM()->getKindName(e.getKind())); } } break; // end of case SIMPLIFY_LANGUAGE case TPTP_LANG: switch(e.getKind()) { case OLD_ARROW: case ARROW: if(e.arity() < 2) e.printAST(os); else { os << "(" << push; bool first(true); for(int i=0, iend=e.arity()-1; i " << e[e.arity()-1]; } break; case LAMBDA: { os<<"ERROR:LAMBDA:unsupported in TPTP\n"; break; } case TRANS_CLOSURE: os<<"ERROR:TRANS_CLOSURE:unsupported in TPTP\n"; break; case TYPEDECL: if(e.arity() != 1) e.printAST(os); else os << e[0].getString(); break; case UFUNC: DebugAssert(e.isSymbol(), "Expected symbol"); os << to_lower(e.getName()); break; case APPLY: if(e.isApply()) os < 0) { bool first(true); for (Expr::iterator i=e.begin(), iend=e.end(); i!=iend; ++i) { if(first) first = false; else os << "," ; os << *i; } os << ")"; } break; default: { DebugAssert(false, "TheoryUF::print: Unexpected expression: " +getEM()->getKindName(e.getKind())); } } break; // end of case TPTP_LANGUAGE case PRESENTATION_LANG: switch(e.getKind()) { case OLD_ARROW: case ARROW: if(e.arity() < 2) e.printAST(os); else { if(e.arity() == 2) os << e[0]; else { os << "(" << push; bool first(true); for(int i=0, iend=e.arity()-1; i" << space << e[e.arity()-1]; } break; case TYPEDECL: // If it's straight from the parser, we may have several type // names in one declaration. Print these in LISP format. // Otherwise, print the name of the type. if(e.arity() != 1) e.printAST(os); else os << e[0].getString(); break; case LAMBDA: { DebugAssert(e.isLambda(), "Expected Lambda"); os << "(" << push << "LAMBDA" << space << push; const vector& vars = e.getVars(); bool first(true); os << "(" << push; for(vector::const_iterator i=vars.begin(), iend=vars.end(); i!=iend; ++i) { if(first) first = false; else os << push << "," << pop << space; os << *i; // The lambda Expr may be in a raw parsed form, in which case // the type is not assigned yet if(i->isVar()) os << ":" << space << pushdag << (*i).getType() << popdag; } os << push << "): " << pushdag << push << e.getBody() << push << ")"; break; } case APPLY: os << e.getOpExpr(); if(e.arity() > 0) { os << "(" << push; bool first(true); for (Expr::iterator i=e.begin(), iend=e.end(); i!=iend; ++i) { if(first) first = false; else os << "," << space; os << *i; } os << push << ")"; } break; case TRANS_CLOSURE: DebugAssert(e.isSymbol(), "Expected symbol"); os << e.getName() << "*"; break; case UFUNC: DebugAssert(e.isSymbol(), "Expected symbol"); os << e.getName(); break; default: { DebugAssert(false, "TheoryUF::print: Unexpected expression: " +getEM()->getKindName(e.getKind())); } } break; // end of case PRESENTATION_LANGUAGE case SMTLIB_LANG: switch(e.getKind()) { case OLD_ARROW: case ARROW: { if(e.arity() < 2) { throw SmtlibException("TheoryUF::print: Expected 2 or more arguments to ARROW"); // e.print(os); } d_theoryUsed = true; os << push; bool oldDagFlag = os.dagFlag(false); int iend = e.arity(); if (e[iend-1].getKind() == BOOLEAN) --iend; for(int i=0; i D as "(A B C) D" */ if(e.arity() < 2) { throw SmtlibException("TheoryUF::print: Expected 2 or more arguments to ARROW"); // e.print(os); } d_theoryUsed = true; bool oldDagFlag = os.dagFlag(false); os << push << "("; for( int i = 0; i < e.arity() - 1; ++i ) { if( i != 0 ) { os << space; } os << e[i]; } os << ")" << space << e[e.arity() - 1] << pop ; os.dagFlag(oldDagFlag); break; } default: printSmtLibShared(os,e); } break; // End of SMT-LIB v2 case LISP_LANG: switch(e.getKind()) { case OLD_ARROW: case ARROW: if(e.arity() < 2) e.printAST(os); os << "(" << push << "ARROW"; for(int i=0, iend=e.arity(); i& vars = e.getVars(); bool first(true); os << "(" << push; for(vector::const_iterator i=vars.begin(), iend=vars.end(); i!=iend; ++i) { if(first) first = false; else os << space; os << "(" << push << *i; // The expression may be in a raw parsed form, in which case // the type is not assigned yet if(i->isVar()) os << space << pushdag << (*i).getType() << popdag; os << push << ")" << pop << pop; } os << push << ")" << pop << pop << pushdag << e.getBody() << push << ")"; break; } case APPLY: DebugAssert(e.isApply(), "Expected Apply"); if (e.arity() == 0) os << e.getOp().getExpr(); else { os << "(" << push << e.getOp().getExpr(); for (int i=0, iend=e.arity(); igetKindName(e.getKind())); } } break; // End of LISP_LANG case SPASS_LANG: switch(e.getKind()) { case UFUNC: os << e.getName(); break; case APPLY: os << push << e.getOp().getExpr(); if(e.arity() > 0) { os << "(" << e[0]; for (int i=1, iend=e.arity(); igetKindName(e.getKind())); } break; default: // Print the top node in the default format, continue with // pretty-printing for children. e.printAST(os); break; } return os; } ////////////////////////////////////////////////////////////////////////////// //parseExprOp: //translating special Exprs to regular EXPR?? /////////////////////////////////////////////////////////////////////////////// Expr TheoryUF::parseExprOp(const Expr& e) { // If the expression is not a list, it must have been already // parsed, so just return it as is. if(RAW_LIST != e.getKind()) return e; DebugAssert(e.arity() > 0, "TheoryUF::parseExprOp:\n e = "+e.toString()); if (e[0].getKind() == RAW_LIST) { if(e.arity() < 2) throw ParserException("Bad function application: "+e.toString()); Expr::iterator i=e.begin(), iend=e.end(); Expr op(parseExpr(*i)); ++i; vector args; for(; i!=iend; ++i) args.push_back(parseExpr(*i)); return Expr(op.mkOp(), args); } DebugAssert(e[0].getKind() == ID || e[0][0].getKind() == ID, "Expected identifier"); int kind = e[0].getKind(); if (kind == ID) kind = getEM()->getKind(e[0][0].getString()); switch(kind) { case OLD_ARROW: { if (!theoryCore()->getFlags()["old-func-syntax"].getBool()) { throw ParserException("You seem to be using the old syntax for function types.\n" "Please convert to the new syntax or run with +old-func-syntax"); } DebugAssert(e.arity()==3,"Expected arity 3 in OLD_ARROW"); Expr arg = parseExpr(e[1]); vector k; if (arg.getOpKind() == TUPLE_TYPE) { Expr::iterator i = arg.begin(), iend=arg.end(); for (; i != iend; ++i) { k.push_back(*i); } } else k.push_back(arg); k.push_back(parseExpr(e[2])); return Expr(ARROW, k); } case ARROW: case TYPEDECL: { vector k; Expr::iterator i = e.begin(), iend=e.end(); // Skip first element of the vector of kids in 'e'. // The first element is the operator. ++i; // Parse the kids of e and push them into the vector 'k' for(; i!=iend; ++i) k.push_back(parseExpr(*i)); return Expr(kind, k, e.getEM()); break; } case TRANS_CLOSURE: { if(e.arity() != 4) throw ParserException("Wrong number of arguments to " "TRANS_CLOSURE expression\n" " (expected 3 arguments): "+e.toString()); const string& name = e[1][0].getString(); Expr funExpr = resolveID(name); if (funExpr.isNull()) throw ParserException("Attempt to take transitive closure of unknown " "predicate"+name); return transClosureExpr(name, parseExpr(e[2]), parseExpr(e[3])); } case LAMBDA: { // (LAMBDA ((v1 ... vn tp1) ...) body) if(!(e.arity() == 3 && e[1].getKind() == RAW_LIST && e[1].arity() > 0)) throw ParserException("Bad LAMBDA expression: "+e.toString()); // Iterate through the groups of bound variables vector > vars; // temporary stack of bound variables for(Expr::iterator i=e[1].begin(), iend=e[1].end(); i!=iend; ++i) { if(i->getKind() != RAW_LIST || i->arity() < 2) throw ParserException("Bad variable declaration block in LAMBDA " "expression: "+i->toString()+ "\n e = "+e.toString()); // Iterate through individual bound vars in the group. The // last element is the type, which we have to rebuild and // parse, since it is used in the creation of bound variables. Type tp(parseExpr((*i)[i->arity()-1])); for(int j=0, jend=i->arity()-1; j args; for(; i!=iend; ++i) args.push_back(parseExpr(*i)); return Expr(op.mkOp(), args); } } return e; } Expr TheoryUF::lambdaExpr(const vector& vars, const Expr& body) { return getEM()->newClosureExpr(LAMBDA, vars, body); } Expr TheoryUF::transClosureExpr(const std::string& name, const Expr& e1, const Expr& e2) { return Expr(getEM()->newSymbolExpr(name, TRANS_CLOSURE).mkOp(), e1, e2); } void TheoryUF::addSharedTerm(const CVC3::Expr& e) { d_sharedTermsMap[e] = true; } cvc3-2.4.1/src/theory_array/0000775000175400017540000000000011630011320015540 5ustar mdetersmdeterscvc3-2.4.1/src/theory_array/Makefile0000664000175400017540000000054210533133653017220 0ustar mdetersmdeters################################################## # About this Makefile # # This Makefile depends on Makefile.opts ################################################## MODULE = theory_array SRC = array_theorem_producer.cpp theory_array.cpp HEADERS = array_proof_rules.h array_theorem_producer.h LIBRARY=libtheory_array.a include ../../Makefile.local cvc3-2.4.1/src/theory_array/array_theorem_producer.cpp0000664000175400017540000002713011415512204023023 0ustar mdetersmdeters/*****************************************************************************/ /*! * \file array_theorem_producer.cpp * \brief Description: TRUSTED implementation of array proof rules. * * Author: Clark Barrett * * Created: Thu May 29 14:02:16 2003 * *
* * License to use, copy, modify, sell and/or distribute this software * and its documentation for any purpose is hereby granted without * royalty, subject to the terms and conditions defined in the \ref * LICENSE file provided with this distribution. * *
* */ /*****************************************************************************/ // This code is trusted #define _CVC3_TRUSTED_ #include "array_theorem_producer.h" #include "theory_array.h" #include "theory_core.h" using namespace std; using namespace CVC3; //////////////////////////////////////////////////////////////////// // TheoryArray: trusted method for creating ArrayTheoremProducer //////////////////////////////////////////////////////////////////// ArrayProofRules* TheoryArray::createProofRules() { return new ArrayTheoremProducer(this); } ArrayTheoremProducer::ArrayTheoremProducer(TheoryArray* theoryArray) : TheoremProducer(theoryArray->theoryCore()->getTM()), d_theoryArray(theoryArray) {} //////////////////////////////////////////////////////////////////// // Proof rules //////////////////////////////////////////////////////////////////// #define CLASS_NAME "CVC3::ArrayTheoremProducer" // ==> // write(store, index_0, v_0, index_1, v_1, ..., index_n, v_n) = store IFF // // read(store, index_n) = v_n & // index_{n-1} != index_n -> read(store, index_{n-1}) = v_{n-1} & // (index_{n-2} != index_{n-1} & index_{n-2} != index_n) -> read(store, index_{n-2}) = v_{n-2} & // ... // (index_1 != index_2 & ... & index_1 != index_n) -> read(store, index_1) = v_1 // (index_0 != index_1 & index_0 != index_2 & ... & index_0 != index_n) -> read(store, index_0) = v_0 Theorem ArrayTheoremProducer::rewriteSameStore(const Expr& e, int n) { IF_DEBUG( DebugAssert(e.isEq(), "EQ expected"); Expr e1 = e[0]; int N = 0; while (isWrite(e1)) { N++; e1 = e1[0]; } DebugAssert(N == n && n > 0, "Counting error"); DebugAssert(e1 == e[1], "Stores do not match"); ) Proof pf; Expr write_i, write_j, index_i, index_j, hyp, conc, result; int i, j; write_i = e[0]; for (i = n-1; i >= 0; --i) { index_i = write_i[1]; // build: [index_i /= index_n && index_i /= index_(n-1) && // ... && index_i /= index_(i+1)] -> read(store, index_i) = v_i write_j = e[0]; for (j = n - 1; j > i; --j) { index_j = write_j[1]; Expr hyp2(!((index_i.getType().isBool())? index_i.iffExpr(index_j) : index_i.eqExpr(index_j))); if (hyp.isNull()) hyp = hyp2; else hyp = hyp && hyp2; write_j = write_j[0]; } Expr r1(Expr(READ, e[1], index_i)); conc = (r1.getType().isBool())? r1.iffExpr(write_i[2]) : r1.eqExpr(write_i[2]); if (!hyp.isNull()) conc = hyp.impExpr(conc); // And into result if (result.isNull()) result = conc; else result = result && conc; // Prepare for next iteration write_i = write_i[0]; hyp = Expr(); } if (withProof()) pf = newPf("rewriteSameStore", e); return newRWTheorem(e, result, Assumptions::emptyAssump(), pf); } // ==> write(store, index, value) = write(...) IFF // store = write(write(...), index, read(store, index)) & // value = read(write(...), index) Theorem ArrayTheoremProducer::rewriteWriteWrite(const Expr& e) { IF_DEBUG( DebugAssert(e.isEq(), "EQ expected"); DebugAssert(isWrite(e[0]) && isWrite(e[1]), "Expected WRITE = WRITE"); ) Proof pf; const Expr& left = e[0]; const Expr& right = e[1]; const Expr& store = left[0]; const Expr& index = left[1]; const Expr& value = left[2]; Expr e1 = (store.getType().isBool())? store.iffExpr(Expr(WRITE, right, index, Expr(READ, store, index))) : store.eqExpr(Expr(WRITE, right, index, Expr(READ, store, index))); Expr e2 = (value.getType().isBool()) ? value.iffExpr(Expr(READ, right, index)) : value.eqExpr(Expr(READ, right, index)); if (withProof()) pf = newPf("rewriteWriteWrite", e); return newRWTheorem(e, e1.andExpr(e2), Assumptions::emptyAssump(), pf); } // ==> read(write(store, index1, value), index2) = // ite(index1 = index2, value, read(store, index2)) Theorem ArrayTheoremProducer::rewriteReadWrite(const Expr& e) { IF_DEBUG( DebugAssert(isRead(e), "Read expected"); DebugAssert(isWrite(e[0]), "Expected Read(Write)"); ) Proof pf; const Expr& store = e[0][0]; const Expr& index1 = e[0][1]; const Expr& value = e[0][2]; const Expr& index2 = e[1]; Expr indexCond = (index1.getType().isBool())? index1.iffExpr(index2) : index1.eqExpr(index2); if (withProof()) pf = newPf("rewriteReadWrite", e); return newRWTheorem(e, indexCond.iteExpr(value, Expr(READ, store, index2)), Assumptions::emptyAssump(), pf); } // e = read(write(store, index1, value), index2): // ==> ite(index1 = index2, // read(write(store, index1, value), index2) = value, // read(write(store, index1, value), index2) = read(store, index2)) Theorem ArrayTheoremProducer::rewriteReadWrite2(const Expr& e) { IF_DEBUG( DebugAssert(isRead(e), "Read expected"); DebugAssert(isWrite(e[0]), "Expected Read(Write)"); ) Proof pf; const Expr& store = e[0][0]; const Expr& index1 = e[0][1]; const Expr& value = e[0][2]; const Expr& index2 = e[1]; Expr indexCond = (index1.getType().isBool())? index1.iffExpr(index2) : index1.eqExpr(index2); if (withProof()) pf = newPf("rewriteReadWrite2", e); return newTheorem(indexCond.iteExpr(e.eqExpr(value), e.eqExpr(Expr(READ, store, index2))), Assumptions::emptyAssump(), pf); } // read(store, index) = value ==> // write(store, index, value) = store // // More general case: // // read(store, index_n) = value_n ==> // write(store, index_0, v_0, index_1, v_1, ..., index_n, value_n) = // write(store, index_0, ite(index_n = index_0, value_n, v_0), // index_1, ite(index_n = index_1, value_n, v_1), // ... // index_{n-1}, ite(index_n = index_{n-1}, value_n, value_{n-1})) Theorem ArrayTheoremProducer::rewriteRedundantWrite1(const Theorem& r_eq_v, const Expr& write) { DebugAssert(r_eq_v.isRewrite(), "Expected equation"); DebugAssert(isRead(r_eq_v.getLHS()), "Expected Read"); const Expr& index = r_eq_v.getLHS()[1]; const Expr& value = r_eq_v.getRHS(); DebugAssert(isWrite(write) && index == write[1] && value == write[2], "Error in parameters to rewriteRedundantWrite1"); vector indices; vector values; Expr store = write[0]; while (isWrite(store)) { indices.push_back(store[1]); values.push_back(store[2]); store = store[0]; } DebugAssert(store == r_eq_v.getLHS()[0], "Store does not match in rewriteRedundantWrite"); while (!indices.empty()) { store = Expr(WRITE, store, indices.back(), index.eqExpr(indices.back()).iteExpr(value, values.back())); indices.pop_back(); values.pop_back(); } Proof pf; if(withProof()) { pf = newPf("rewriteRedundantWrite1", write, r_eq_v.getProof()); } return newRWTheorem(write, store, r_eq_v.getAssumptionsRef(), pf); } // ==> // write(write(store, index, v1), index, v2) = write(store, index, v2) Theorem ArrayTheoremProducer::rewriteRedundantWrite2(const Expr& e) { DebugAssert(isWrite(e) && isWrite(e[0]) && e[0][1] == e[1], "Error in parameters to rewriteRedundantWrite2"); Proof pf; if(withProof()) { pf = newPf("rewriteRedundantWrite2", e); } return newRWTheorem(e, Expr(WRITE, e[0][0], e[1], e[2]), Assumptions::emptyAssump(), pf); } // ==> // write(write(store, index1, v1), index2, v2) = // write(write(store, index2, v2), index1, ite(index1 = index2, v2, v1)) Theorem ArrayTheoremProducer::interchangeIndices(const Expr& e) { DebugAssert(isWrite(e) && isWrite(e[0]), "Error in parameters to interchangeIndices"); Proof pf; if(withProof()) { pf = newPf("interchangeIndices", e); } Expr w0 = Expr(WRITE, e[0][0], e[1], e[2]); Expr indexCond = (e[0][1].getType().isBool())? e[0][1].iffExpr(e[1]) : e[0][1].eqExpr(e[1]); Expr w2 = Expr(WRITE, w0, e[0][1], indexCond.iteExpr(e[2], e[0][2])); return newRWTheorem(e, w2, Assumptions::emptyAssump(), pf); } Theorem ArrayTheoremProducer::readArrayLiteral(const Expr& e) { if(CHECK_PROOFS) { CHECK_SOUND(e.getKind() == READ, "ArrayTheoremProducer::readArrayLiteral("+e.toString() +"):\n\n expression is not a READ"); } Expr arrayLit(e[0]); if (CHECK_PROOFS) { CHECK_SOUND(arrayLit.isClosure() && arrayLit.getKind()==ARRAY_LITERAL, "ArrayTheoremProducer::readArrayLiteral("+e.toString()+")"); } Expr body(arrayLit.getBody()); const vector& vars = arrayLit.getVars(); if(CHECK_PROOFS) { CHECK_SOUND(vars.size() == 1, "ArrayTheoremProducer::readArrayLiteral("+e.toString()+"):\n" +"wrong number of bound variables"); } // Use the Expr's efficient substitution vector ind; ind.push_back(e[1]); body = body.substExpr(vars, ind); Proof pf; if(withProof()) pf = newPf("read_array_literal", e); return newRWTheorem(e, body, Assumptions::emptyAssump(), pf); } Theorem ArrayTheoremProducer::liftReadIte(const Expr& e) { if(CHECK_PROOFS) { CHECK_SOUND(e.getKind() == READ && e[0].getKind() == ITE, "ArrayTheoremProducer::liftReadIte("+e.toString() +"):\n\n expression is not READ(ITE..."); } const Expr& ite = e[0]; Proof pf; if (withProof()) pf = newPf("lift_read_ite",e); return newRWTheorem(e, Expr(ITE, ite[0], Expr(READ, ite[1], e[1]), Expr(READ, ite[2], e[1])), Assumptions::emptyAssump(), pf); } Theorem ArrayTheoremProducer::arrayNotEq(const Theorem& e) { if(CHECK_PROOFS) { CHECK_SOUND(e.getExpr().getKind() == NOT && e.getExpr()[0].getKind() == EQ && isArray(d_theoryArray->getBaseType(e.getExpr()[0][0])), "ArrayTheoremProducer::arrayNotEq("+e.toString() +"):\n\n expression is ill-formed"); } Expr eq = e.getExpr()[0]; Proof pf; if (withProof()) pf = newPf("array_not_eq", e.getProof()); Type arrType = d_theoryArray->getBaseType(eq[0]); Type indType = Type(arrType.getExpr()[0]); Expr var = d_theoryArray->getEM()->newBoundVarExpr(indType); eq = Expr(READ, eq[0], var).eqExpr(Expr(READ, eq[1], var)); return newTheorem(d_theoryArray->getEM()->newClosureExpr(EXISTS, var, !eq), Assumptions(e), pf); } Theorem ArrayTheoremProducer::splitOnConstants(const Expr& a, const std::vector& consts) { Theorem res; Expr result; vector eq; vector diseq; for (unsigned i = 0; i < consts.size(); ++ i) { eq.push_back(a.eqExpr(consts[i])); diseq.push_back(a.eqExpr(consts[i]).notExpr()); } if (eq.size() == 1) { result = eq[0].orExpr(diseq[0]); } else { eq.push_back(andExpr(diseq)); result = orExpr(eq); } Proof pf; if (withProof()) pf = newPf("splitOnConstants"); return newTheorem(result, Assumptions::emptyAssump(), pf); } Theorem ArrayTheoremProducer::propagateIndexDiseq(const Theorem& read1eqread2isFalse) { Expr read1eqread2 = read1eqread2isFalse.getLHS(); Expr read1 = read1eqread2[0]; Expr read2 = read1eqread2[1]; Expr i1 = read1[1]; Expr i2 = read2[1]; Proof pf; if (withProof()) pf = newPf("propagateIndexDiseq", read1eqread2isFalse.getProof()); return newTheorem(i1.eqExpr(i2).notExpr(), Assumptions(read1eqread2isFalse), pf); } cvc3-2.4.1/src/theory_array/array_proof_rules.h0000664000175400017540000000652211415512204021463 0ustar mdetersmdeters/*****************************************************************************/ /*! * \file array_proof_rules.h * * Author: Clark Barrett 5/29/2003 * * Created: May 29 19:16:33 GMT 2003 * *
* * License to use, copy, modify, sell and/or distribute this software * and its documentation for any purpose is hereby granted without * royalty, subject to the terms and conditions defined in the \ref * LICENSE file provided with this distribution. * *
* * CLASS: ArrayProofRules * * * Description: Array proof rules. */ /*****************************************************************************/ #ifndef _cvc3__theory_array__array_proof_rules_h_ #define _cvc3__theory_array__array_proof_rules_h_ #include namespace CVC3 { class Theorem; class Expr; class ArrayProofRules { public: // Destructor virtual ~ArrayProofRules() { } //////////////////////////////////////////////////////////////////// // Proof rules //////////////////////////////////////////////////////////////////// // ==> // write(store, index_0, v_0, index_1, v_1, ..., index_n, v_n) = store IFF // // read(store, index_n) = v_n & // index_{n-1} != index_n -> read(store, index_{n-1}) = v_{n-1} & // (index_{n-2} != index_{n-1} & index_{n-2} != index_n) -> read(store, index_{n-2}) = v_{n-2} & // ... // (index_1 != index_2 & ... & index_1 != index_n) -> read(store, index_1) = v_1 // (index_0 != index_1 & index_0 != index_2 & ... & index_0 != index_n) -> read(store, index_0) = v_0 virtual Theorem rewriteSameStore(const Expr& e, int n) = 0; // ==> write(store, index, value) = write(...) IFF // store = write(write(...), index, read(store, index)) & // value = read(write(...), index) virtual Theorem rewriteWriteWrite(const Expr& e) = 0; // ==> read(write(store, index1, value), index2) = // ite(index1 = index2, value, read(store, index2)) virtual Theorem rewriteReadWrite(const Expr& e) = 0; // e = read(write(store, index1, value), index2): // ==> ite(index1 = index2, // read(write(store, index1, value), index2) = value, // read(write(store, index1, value), index2) = read(store, index2)) virtual Theorem rewriteReadWrite2(const Expr& e) = 0; // value = read(store, index) ==> // write(store, index, value) = store virtual Theorem rewriteRedundantWrite1(const Theorem& v_eq_r, const Expr& write) = 0; // ==> // write(write(store, index, v1), index, v2) = write(store, index, v2) virtual Theorem rewriteRedundantWrite2(const Expr& e) = 0; // ==> // write(write(store, index1, v1), index2, v2) = // write(write(store, index2, v2), index1, ite(index1 = index2, v2, v1)) virtual Theorem interchangeIndices(const Expr& e) = 0; //! Beta reduction of array literal: |- (array x. f(x))[arg] = f(arg) virtual Theorem readArrayLiteral(const Expr& e) = 0; //! Lift ite over read virtual Theorem liftReadIte(const Expr& e) = 0; //! a /= b |- exists i. a[i] /= b[i] virtual Theorem arrayNotEq(const Theorem& e) = 0; virtual Theorem splitOnConstants(const Expr& a, const std::vector& consts) = 0; virtual Theorem propagateIndexDiseq(const Theorem& read1eqread2isFalse) = 0; }; // end of class ArrayProofRules } // end of namespace CVC3 #endif cvc3-2.4.1/src/theory_array/array_theorem_producer.h0000664000175400017540000000671311415512204022474 0ustar mdetersmdeters/*****************************************************************************/ /*! * \file array_theorem_producer.h * * Author: Clark Barrett, 5/29/2003 * * Created: May 29 19:16:33 GMT 2003 * *
* * License to use, copy, modify, sell and/or distribute this software * and its documentation for any purpose is hereby granted without * royalty, subject to the terms and conditions defined in the \ref * LICENSE file provided with this distribution. * *
* * CLASS: ArrayProofRules * * * Description: TRUSTED implementation of array proof rules. DO * NOT use this file in any DP code, use the exported API in * array_proof_rules.h instead. * */ /*****************************************************************************/ #ifndef _cvc3__theory_array__array_theorem_producer_h_ #define _cvc3__theory_array__array_theorem_producer_h_ #include "array_proof_rules.h" #include "theorem_producer.h" namespace CVC3 { class TheoryArray; class ArrayTheoremProducer: public ArrayProofRules, public TheoremProducer { private: TheoryArray* d_theoryArray; public: // Constructor ArrayTheoremProducer(TheoryArray* theoryArray); //////////////////////////////////////////////////////////////////// // Proof rules //////////////////////////////////////////////////////////////////// // ==> // write(store, index_0, v_0, index_1, v_1, ..., index_n, v_n) = store IFF // // read(store, index_n) = v_n & // index_{n-1} != index_n -> read(store, index_{n-1}) = v_{n-1} & // (index_{n-2} != index_{n-1} & index_{n-2} != index_n) -> read(store, index_{n-2}) = v_{n-2} & // ... // (index_1 != index_2 & ... & index_1 != index_n) -> read(store, index_1) = v_1 // (index_0 != index_1 & index_0 != index_2 & ... & index_0 != index_n) -> read(store, index_0) = v_0 Theorem rewriteSameStore(const Expr& e, int n); // ==> write(store, index, value) = write(...) IFF // store = write(write(...), index, read(store, index)) & // value = read(write(...), index) Theorem rewriteWriteWrite(const Expr& e); // ==> read(write(store, index1, value), index2) = // ite(index1 = index2, value, read(store, index2)) Theorem rewriteReadWrite(const Expr& e); // e = read(write(store, index1, value), index2): // ==> ite(index1 = index2, // read(write(store, index1, value), index2) = value, // read(write(store, index1, value), index2) = read(store, index2)) Theorem rewriteReadWrite2(const Expr& e); // value = read(store, index) ==> // write(store, index, value) = store Theorem rewriteRedundantWrite1(const Theorem& v_eq_r, const Expr& write); // ==> // write(write(store, index, v1), index, v2) = write(store, index, v2) Theorem rewriteRedundantWrite2(const Expr& e); // ==> // write(write(store, index1, v1), index2, v2) = // write(write(store, index2, v2), index1, ite(index1 = index2, v2, v1)) Theorem interchangeIndices(const Expr& e); // Beta reduction of array literal: |- (array x. f(x))[arg] = f(arg) Theorem readArrayLiteral(const Expr& e); Theorem liftReadIte(const Expr& e); // a /= b |- exists i. a[i] /= b[i] Theorem arrayNotEq(const Theorem& e); Theorem splitOnConstants(const Expr& a, const std::vector& consts); Theorem propagateIndexDiseq(const Theorem& read1eqread2isFalse); }; // end of class ArrayTheoremProducer } // end of namespace CVC3 #endif cvc3-2.4.1/src/theory_array/theory_array.cpp0000664000175400017540000011707211415512204020774 0ustar mdetersmdeters/*****************************************************************************/ /*! * \file theory_array.cpp * * Author: Clark Barrett * * Created: Thu Feb 27 00:38:55 2003 * *
* * License to use, copy, modify, sell and/or distribute this software * and its documentation for any purpose is hereby granted without * royalty, subject to the terms and conditions defined in the \ref * LICENSE file provided with this distribution. * *
* */ /*****************************************************************************/ #include "theory_array.h" #include "theory_bitvector.h" #include "array_proof_rules.h" #include "typecheck_exception.h" #include "parser_exception.h" #include "smtlib_exception.h" #include "theory_core.h" #include "command_line_flags.h" #include "translator.h" using namespace std; using namespace CVC3; /////////////////////////////////////////////////////////////////////////////// // TheoryArray Public Methods // /////////////////////////////////////////////////////////////////////////////// TheoryArray::TheoryArray(TheoryCore* core) : Theory(core, "Arrays"), d_reads(core->getCM()->getCurrentContext()), d_applicationsInModel(core->getFlags()["applications"].getBool()), d_liftReadIte(core->getFlags()["liftReadIte"].getBool()), d_sharedSubterms(core->getCM()->getCurrentContext()), d_sharedSubtermsList(core->getCM()->getCurrentContext()), d_index(core->getCM()->getCurrentContext(), 0, 0), d_sharedIdx1(core->getCM()->getCurrentContext(), 0, 0), d_sharedIdx2(core->getCM()->getCurrentContext(), 0, 0), d_inCheckSat(0) { d_rules = createProofRules(); // Register new local kinds with ExprManager getEM()->newKind(ARRAY, "_ARRAY", true); getEM()->newKind(READ, "_READ"); getEM()->newKind(WRITE, "_WRITE"); getEM()->newKind(ARRAY_LITERAL, "_ARRAY_LITERAL"); vector kinds; kinds.push_back(ARRAY); kinds.push_back(READ); kinds.push_back(WRITE); kinds.push_back(ARRAY_LITERAL); registerTheory(this, kinds); } // Destructor: delete the proof rules class if it's present TheoryArray::~TheoryArray() { if(d_rules != NULL) delete d_rules; } void TheoryArray::addSharedTerm(const Expr& e) { if (d_sharedSubterms.count(e) > 0) return; TRACE("arrAddSharedTerm", "TheoryArray::addSharedTerm(", e.toString(), ")"); // Cache all shared terms d_sharedSubterms[e]=e; // Make sure we get notified if shared term is assigned to something else // We need this because we only check non-array-normalized (nan) shared terms, // so if a variable gets set to a nan term, we will need to know about it. e.addToNotify(this, Expr()); if (isWrite(e) || (isRead(e) && isWrite(e[0]))) { // Children of shared terms better be shared so we can detect any failure of normalization for (int i = 0; i < e.arity(); ++i) addSharedTerm(e[i]); // Only check writes that are not normalized if (!isWrite(e) || e.notArrayNormalized()) { // Put in list to check during checkSat d_sharedSubtermsList.push_back(e); } } } void TheoryArray::assertFact(const Theorem& e) { const Expr& expr = e.getExpr(); TRACE("arrAssertFact", "TheoryArray::assertFact(", e.getExpr().toString(), ")"); switch (expr.getOpKind()) { case NOT: DebugAssert(expr[0].isEq(), "Unexpected negation"); if (isArray(getBaseType(expr[0][0]))) { // For disequalities between arrays, do the polite thing, and introduce witnesses enqueueFact(d_rules->arrayNotEq(e)); break; } // We can use the shared term mechanism here: // In checksat we will ensure that all shared terms are in a normal form // so if two are known to be equal, we will discover it addSharedTerm(expr[0][0]); addSharedTerm(expr[0][1]); break; case EQ: DebugAssert(theoryCore()->inUpdate() || (d_inCheckSat > 0) || !isWrite(expr[0]), "Invariant violated"); break; default: FatalAssert(false, "Unexpected case"); break; } } Expr findAtom(Expr e) { DebugAssert(e.arity() != 0, "Invariant Violated"); int i; for (i = 0; i < e.arity(); ++i) { if (!e[i].isAtomic()) break; } if (e[i].isAbsAtomicFormula()) return e[i]; return findAtom(e[i]); } void TheoryArray::checkSat(bool fullEffort) { if (fullEffort == true) { // Check that all non-array-normalized shared terms are normalized Theorem thm; for (; d_index < d_sharedSubtermsList.size(); d_index = d_index + 1) { Expr e = d_sharedSubtermsList[d_index]; if (isRead(e)) { DebugAssert(isWrite(e[0]), "Expected read(write)"); // This should be a signature without a find DebugAssert(!e.hasFind(), "Expected no find"); // If this is no longer a valid signature, we can skip it if (!e.hasRep()) continue; // Check to see if we know whether indices are equal Expr ieq = e[0][1].eqExpr(e[1]); Theorem ieqSimp = simplify(ieq); if (!ieqSimp.getRHS().isBoolConst()) { // if not, split on equality of indices // TODO: really tricky optimization: maybe we can avoid this split // if both then and else are unknown terms? addSplitter(ieq); return; } // Get the representative for the signature Theorem repEqSig = e.getRep(); DebugAssert(!repEqSig.isRefl(), "Expected non-self rep"); // Apply the read over write rule thm = d_rules->rewriteReadWrite(e); // Carefully simplify thm = transitivityRule(thm, substitutivityRule(thm.getRHS(), 0, ieqSimp)); thm = transitivityRule(thm, rewriteIte(thm.getRHS())); // Derive the new equality and simplify thm = transitivityRule(repEqSig, thm); thm = iffMP(thm, simplify(thm.getExpr())); Expr newExpr = thm.getExpr(); if (newExpr.isTrue()) { // Fact is already known, continue continue; } else if (newExpr.isAbsAtomicFormula()) { enqueueFact(thm); } else { // expr is not atomic formula, so pick a splitter that will help make it atomic addSplitter(findAtom(newExpr)); } return; } // OK, everything else should be a write DebugAssert(isWrite(e), "Expected Write"); DebugAssert(e.notArrayNormalized(), "Only non-normalized writes expected"); // If write is not its own find, this means that the write // was normalized to something else already, so it's not relevant // any more if (find(e).getRHS() != e) continue; // First check for violation of redundantWrite1 Expr store = e[0]; while (isWrite(store)) store = store[0]; DebugAssert(findExpr(e[2]) == e[2], "Expected own find"); thm = simplify(Expr(READ, store, e[1])); if (thm.getRHS() == e[2]) { thm = d_rules->rewriteRedundantWrite1(thm, e); } // Then check for violation of redundantWrite2 else if (isWrite(e[0]) && e[0][1] > e[1]) { thm = d_rules->interchangeIndices(e); } else { FatalAssert(false, "Unexpected expr"); continue; } // Write needs to be normalized, see what its new normal form is: thm = transitivityRule(thm, simplify(thm.getRHS())); Expr newExpr = thm.getRHS(); if (newExpr.isAtomic()) { // If the new normal form is atomic, go ahead and update the normal form directly ++d_inCheckSat; assertEqualities(thm); // To ensure updates are processed and checkSat gets called again enqueueFact(thm); --d_inCheckSat; } else { // normal form is not atomic, so pick a splitter that will help make it atomic addSplitter(findAtom(newExpr)); } return; } // All the terms should be normalized now... Ok, lets split on the read // indices. TRACE("sharing", "checking shared terms, size = ", int2string(d_reads.size()), ""); // Collect all the arrays and indices of interest ExprMap< hash_set > reads_by_array; ExprMap< hash_set > const_reads_by_array; for (unsigned i = 0; i < d_reads.size(); ++i) { Expr read = d_reads[i]; if (read.getSig().isNull()) continue; if( d_sharedSubterms.find(read[1]) == d_sharedSubterms.end() ) continue; Expr read_array = getBaseArray(read[0]); if (read[1].getKind() != BVCONST) { hash_set& reads = reads_by_array[read_array]; reads.insert(read); } else { hash_set& reads = const_reads_by_array[read_array]; reads.insert(read); } } ExprMap< hash_set >::iterator it = reads_by_array.begin(); ExprMap< hash_set >::iterator it_end = reads_by_array.end(); for(; it != it_end; ++ it) { Expr array = it->first; hash_set& reads_single_array = it->second; hash_set::iterator read1_it = reads_single_array.begin(); hash_set::iterator read1_end = reads_single_array.end(); for (; read1_it != read1_end; ++ read1_it) { Expr read1 = (*read1_it); Expr x_k = read1[1]; Expr read1_find = find(read1).getRHS(); // The non-const reads arrays hash_set::iterator read2_it = reads_single_array.begin(); for (; read2_it != read1_it; ++ read2_it) { Expr read2 = (*read2_it); Expr read2_find = find(read2).getRHS(); if (read1_find != read2_find) { Theorem simpl = simplify(read1.eqExpr(read2)); Expr y_k = read2[1]; Expr eq = x_k.eqExpr(y_k); if( !simplify(eq).getRHS().isBoolConst() ) { if (simpl.getRHS().isFalse()) { enqueueFact(d_rules->propagateIndexDiseq(simpl)); } else { TRACE("sharing", "from " + read2.toString(), "with find = ", find(read2).getRHS()); TRACE("sharing", "from " + read1.toString(), "with find = ", find(read1).getRHS()); TRACE("sharing", "splitting " + y_k.toString(), " and ", x_k.toString()); addSplitter(eq); } } } } // The const reads arrays hash_set& const_reads_single_array = const_reads_by_array[array]; read2_it = const_reads_single_array.begin(); hash_set::iterator read2_it_end = const_reads_single_array.end(); for (; read2_it != read2_it_end; ++ read2_it) { Expr read2 = (*read2_it); Expr read2_find = find(read2).getRHS(); if (read1_find != read2_find) { Theorem simpl = simplify(read1.eqExpr(read2)); Expr y_k = read2[1]; Expr eq = x_k.eqExpr(y_k); if( !simplify(eq).getRHS().isBoolConst() ) { if (simpl.getRHS().isFalse()) { enqueueFact(d_rules->propagateIndexDiseq(simpl)); } else { TRACE("sharing", "from " + read2.toString(), "with find = ", find(read2).getRHS()); TRACE("sharing", "from " + read1.toString(), "with find = ", find(read1).getRHS()); TRACE("sharing", "splitting " + y_k.toString(), " and ", x_k.toString()); addSplitter(eq); } } } } } } TRACE("sharing", "checking shared terms, done", int2string(d_reads.size()), ""); } } // w(...,i,v1,...,) => w(......,i,v1') // Returns Null Theorem if index does not appear Theorem TheoryArray::pullIndex(const Expr& e, const Expr& index) { DebugAssert(isWrite(e), "Expected write"); if (e[1] == index) return reflexivityRule(e); // Index does not appear if (!isWrite(e[0])) return Theorem(); // Index is at next nesting level if (e[0][1] == index) { return d_rules->interchangeIndices(e); } // Index is (possibly) at deeper nesting level Theorem thm = pullIndex(e[0], index); if (thm.isNull()) return thm; thm = substitutivityRule(e, 0, thm); thm = transitivityRule(thm, d_rules->interchangeIndices(thm.getRHS())); return thm; } Theorem TheoryArray::rewrite(const Expr& e) { Theorem thm; switch (e.getKind()) { case READ: { switch(e[0].getKind()) { case WRITE: thm = d_rules->rewriteReadWrite(e); return transitivityRule(thm, simplify(thm.getRHS())); case ARRAY_LITERAL: { IF_DEBUG(debugger.counter("Read array literals")++;) thm = d_rules->readArrayLiteral(e); return transitivityRule(thm, simplify(thm.getRHS())); } case ITE: { if (d_liftReadIte) { thm = d_rules->liftReadIte(e); return transitivityRule(thm, simplify(thm.getRHS())); } e.setRewriteNormal(); return reflexivityRule(e); } default: { break; } } const Theorem& rep = e.getRep(); if (rep.isNull()) return reflexivityRule(e); else return symmetryRule(rep); } case EQ: // if (e[0].isAtomic() && e[1].isAtomic() && isWrite(e[0])) { if (isWrite(e[0])) { Expr left = e[0], right = e[1]; int leftWrites = 1, rightWrites = 0; // Count nested writes Expr e1 = left[0]; while (isWrite(e1)) { leftWrites++; e1 = e1[0]; } Expr e2 = right; while (isWrite(e2)) { rightWrites++; e2 = e2[0]; } if (rightWrites == 0) { if (e1 == e2) { thm = d_rules->rewriteSameStore(e, leftWrites); return transitivityRule(thm, simplify(thm.getRHS())); } else { e.setRewriteNormal(); return reflexivityRule(e); } } if (leftWrites > rightWrites) { thm = getCommonRules()->rewriteUsingSymmetry(e); thm = transitivityRule(thm, d_rules->rewriteWriteWrite(thm.getRHS())); } else thm = d_rules->rewriteWriteWrite(e); return transitivityRule(thm, simplify(thm.getRHS())); } e.setRewriteNormal(); return reflexivityRule(e); case NOT: e.setRewriteNormal(); return reflexivityRule(e); case WRITE: { // if (!e.isAtomic()) { // e.setRewriteNormal(); // return reflexivityRule(e); // } const Expr& store = e[0]; // Enabling this slows stuff down a lot if (!isWrite(store)) { DebugAssert(findExpr(e[2]) == e[2], "Expected own find"); if (isRead(e[2]) && e[2][0] == store && e[2][1] == e[1]) { thm = d_rules->rewriteRedundantWrite1(reflexivityRule(e[2]), e); return transitivityRule(thm, simplify(thm.getRHS())); } e.setRewriteNormal(); return reflexivityRule(e); } else { // if (isWrite(store)) { thm = pullIndex(store,e[1]); if (!thm.isNull()) { if (thm.isRefl()) { return d_rules->rewriteRedundantWrite2(e); } thm = substitutivityRule(e,0,thm); thm = transitivityRule(thm, d_rules->rewriteRedundantWrite2(thm.getRHS())); return transitivityRule(thm, simplify(thm.getRHS())); } if (store[1] > e[1]) { // Only do this rewrite if the result is atomic // (avoid too many ITEs) thm = d_rules->interchangeIndices(e); thm = transitivityRule(thm, simplify(thm.getRHS())); if (thm.getRHS().isAtomic()) { return thm; } // not normal because might be possible to interchange later return reflexivityRule(e); } } e.setRewriteNormal(); return reflexivityRule(e); } case ARRAY_LITERAL: e.setRewriteNormal(); return reflexivityRule(e); default: DebugAssert(e.isVar() && isArray(getBaseType(e)), "Unexpected default case"); e.setRewriteNormal(); return reflexivityRule(e); } FatalAssert(false, "should be unreachable"); return reflexivityRule(e); } void TheoryArray::setup(const Expr& e) { if (e.isNot() || e.isEq()) return; DebugAssert(e.isAtomic(), "e should be atomic"); for (int k = 0; k < e.arity(); ++k) { e[k].addToNotify(this, e); } if (isRead(e)) { if (e.getType().card() != CARD_INFINITE) { addSharedTerm(e); theoryOf(e.getType())->addSharedTerm(e); } Theorem thm = reflexivityRule(e); e.setSig(thm); e.setRep(thm); e.setUsesCC(); DebugAssert(!isWrite(e[0]), "expected no read of writes"); // Record the read operator for concrete models TRACE("model", "TheoryArray: add array read ", e, ""); d_reads.push_back(e); } else if (isWrite(e)) { Expr store = e[0]; if (isWrite(store)) { // check interchangeIndices invariant if (store[1] > e[1]) { e.setNotArrayNormalized(); if (d_sharedSubterms.count(e) > 0) { // write was identified as a shared term before it was setup: add it to list to check d_sharedSubtermsList.push_back(e); } } // redundantWrite2 invariant should hold DebugAssert(pullIndex(store, e[1]).isNull(), "Unexpected non-array-normalized term in setup"); } // check redundantWrite1 invariant // there is a hidden dependency of write(a,i,v) on read(a,i) while (isWrite(store)) store = store[0]; // Need to simplify, not just take find: read could be a signature Expr r = simplifyExpr(Expr(READ, store, e[1])); theoryCore()->setupTerm(r, this, theoryCore()->getTheoremForTerm(e)); DebugAssert(r.isAtomic(), "Should be atomic"); DebugAssert(findExpr(e[2]) == e[2], "Expected own find"); if (r == e[2] && !e.notArrayNormalized()) { e.setNotArrayNormalized(); if (d_sharedSubterms.count(e) > 0) { // write was identified as a shared term before it was setup: add it to list to check d_sharedSubtermsList.push_back(e); } } else { r.addToNotify(this, e); } } } void TheoryArray::update(const Theorem& e, const Expr& d) { if (inconsistent()) return; if (d.isNull()) { // d is a shared term // we want to mark the new find representative as a shared term too Expr lhs = e.getLHS(); Expr rhs = e.getRHS(); DebugAssert(d_sharedSubterms.find(lhs) != d_sharedSubterms.end(), "Expected lhs to be shared"); CDMap::iterator it = d_sharedSubterms.find(rhs); if (it == d_sharedSubterms.end()) { addSharedTerm(rhs); } return; } int k, ar(d.arity()); if (isRead(d)) { const Theorem& dEQdsig = d.getSig(); if (!dEQdsig.isNull()) { Expr dsig = dEQdsig.getRHS(); Theorem thm = updateHelper(d); Expr sigNew = thm.getRHS(); if (sigNew == dsig) return; dsig.setRep(Theorem()); if (isWrite(sigNew[0])) { // This is the tricky case. // Theorem thm2 = d_rules->rewriteReadWrite(sigNew); thm2 = transitivityRule(thm2, simplify(thm2.getRHS())); if (thm2.getRHS().isAtomic()) { // If read over write simplifies, go ahead and assert the equality enqueueFact(transitivityRule(thm, thm2)); } else { // Otherwise, delay processing until checkSat addSharedTerm(sigNew); } // thm = d_rules->rewriteReadWrite2(sigNew); // Theorem renameTheorem = renameExpr(d); // enqueueFact(transitivityRule(symmetryRule(renameTheorem), thm)); // d.setSig(Theorem()); // enqueueFact(thm); // enqueueFact(renameTheorem); } // else { // Update the signature in all cases Theorem repEQsigNew = sigNew.getRep(); if (!repEQsigNew.isNull()) { d.setSig(Theorem()); enqueueFact(transitivityRule(repEQsigNew, symmetryRule(thm))); } else { for (k = 0; k < ar; ++k) { if (sigNew[k] != dsig[k]) { sigNew[k].addToNotify(this, d); } } d.setSig(thm); sigNew.setRep(thm); getEM()->invalidateSimpCache(); } // } } return; } DebugAssert(isWrite(d), "Expected write: d = "+d.toString()); if (find(d).getRHS() != d) return; Theorem thm = updateHelper(d); Expr sigNew = thm.getRHS(); // TODO: better normalization in some cases Expr store = sigNew[0]; if (!isWrite(store)) { Theorem thm2 = find(Expr(READ, store, sigNew[1])); if (thm2.getRHS() == sigNew[2]) { thm = transitivityRule(thm, d_rules->rewriteRedundantWrite1(thm2, sigNew)); sigNew = thm.getRHS(); } } else { // TODO: this check is expensive, it seems Theorem thm2 = pullIndex(store,sigNew[1]); if (!thm2.isNull()) { if (thm2.isRefl()) { thm = transitivityRule(thm, d_rules->rewriteRedundantWrite2(sigNew)); } else { thm2 = substitutivityRule(sigNew,0,thm2); thm2 = transitivityRule(thm2, d_rules->rewriteRedundantWrite2(thm2.getRHS())); thm = transitivityRule(thm, thm2); } sigNew = thm.getRHS(); store = sigNew[0]; } if (isWrite(store) && (store[1] > sigNew[1])) { thm2 = d_rules->interchangeIndices(sigNew); thm2 = transitivityRule(thm2, simplify(thm2.getRHS())); // Only update if result is atomic if (thm2.getRHS().isAtomic()) { thm = transitivityRule(thm, thm2); sigNew = thm.getRHS(); // no need to update store because d == sigNew // case only happens if sigNew hasn't changed } } } if (d == sigNew) { // Hidden dependency must have changed while (isWrite(store)) store = store[0]; Expr r = e.getRHS(); if (r == d[2]) { // no need to update notify list as we are already on list of d[2] if (!d.notArrayNormalized()) { d.setNotArrayNormalized(); if (d_sharedSubterms.count(d) > 0) { // write has become non-normalized: add it to list to check d_sharedSubtermsList.push_back(d); } } } else { // update the notify list r.addToNotify(this, d); } return; } DebugAssert(sigNew.isAtomic(), "Expected atomic formula"); // Since we aren't doing a full normalization here, it's possible that sigNew is not normal // and so it might have a different find. In that case, the find should be the new rhs. if (sigNew.hasFind()) { Theorem findThm = findRef(sigNew); if (!findThm.isRefl()) { thm = transitivityRule(thm, findThm); } assertEqualities(thm); return; } // If it doesn't have a find at all, it needs to be simplified Theorem simpThm = simplify(sigNew); thm = transitivityRule(thm, simpThm); sigNew = thm.getRHS(); if (sigNew.isAtomic()) { assertEqualities(thm); } else { // Simplify could maybe? introduce case splits in the expression. Handle this by renaminig Theorem renameTheorem = renameExpr(d); enqueueFact(transitivityRule(symmetryRule(renameTheorem), thm)); assertEqualities(renameTheorem); } } Theorem TheoryArray::solve(const Theorem& eThm) { const Expr& e = eThm.getExpr(); DebugAssert(e.isEq(), "TheoryArray::solve("+e.toString()+")"); if (isWrite(e[0])) { DebugAssert(!isWrite(e[1]), "Should have been rewritten: e = " +e.toString()); return symmetryRule(eThm); } return eThm; } void TheoryArray::checkType(const Expr& e) { switch (e.getKind()) { case ARRAY: { if (e.arity() != 2) throw Exception ("ARRAY type should have two arguments"); Type t1(e[0]); if (t1.isBool()) throw Exception ("Array index types must be non-Boolean"); if (t1.isFunction()) throw Exception ("Array index types cannot be functions"); Type t2(e[1]); if (t2.isBool()) throw Exception ("Array value types must be non-Boolean"); if (t2.isFunction()) throw Exception ("Array value types cannot be functions"); break; } default: DebugAssert(false, "Unexpected kind in TheoryArray::checkType" +getEM()->getKindName(e.getKind())); } } Cardinality TheoryArray::finiteTypeInfo(Expr& e, Unsigned& n, bool enumerate, bool computeSize) { Cardinality card = CARD_INFINITE; switch (e.getKind()) { case ARRAY: { Type typeIndex = Type(e[0]); Type typeElem = Type(e[1]); if (typeElem.card() == CARD_FINITE && (typeIndex.card() == CARD_FINITE || typeElem.sizeFinite() == 1)) { card = CARD_FINITE; if (enumerate) { // Right now, we only enumerate the first element for finite arrays if (n == 0) { Expr ind(getEM()->newBoundVarExpr(Type(e[0]))); e = arrayLiteral(ind, typeElem.enumerateFinite(0)); } else e = Expr(); } if (computeSize) { n = 0; Unsigned sizeElem = typeElem.sizeFinite(); if (sizeElem == 1) { n = 1; } else if (sizeElem > 1) { Unsigned sizeIndex = typeIndex.sizeFinite(); if (sizeIndex > 0) { n = sizeElem; while (--sizeIndex > 0) { n = n * sizeElem; if (n > 1000000) { // if it starts getting too big, just return 0 n = 0; break; } } } } } } break; } default: break; } return card; } void TheoryArray::computeType(const Expr& e) { switch (e.getKind()) { case READ: { DebugAssert(e.arity() == 2,""); Type arrType = e[0].getType(); if (!isArray(arrType)) { arrType = getBaseType(arrType); } if (!isArray(arrType)) throw TypecheckException ("Expected an ARRAY type in\n\n " +e[0].toString()+"\n\nBut received this:\n\n " +arrType.toString()+"\n\nIn the expression:\n\n " +e.toString()); Type idxType = getBaseType(e[1]); if(getBaseType(arrType[0]) != idxType && idxType != Type::anyType(getEM())) { throw TypecheckException ("The type of index expression:\n\n " +idxType.toString() +"\n\nDoes not match the ARRAY index type:\n\n " +arrType[0].toString() +"\n\nIn the expression: "+e.toString()); } e.setType(arrType[1]); break; } case WRITE: { DebugAssert(e.arity() == 3,""); Type arrType = e[0].getType(); if (!isArray(arrType)) { arrType = getBaseType(arrType); } Type idxType = getBaseType(e[1]); Type valType = getBaseType(e[2]); if (!isArray(arrType)) throw TypecheckException ("Expected an ARRAY type in\n\n " +e[0].toString()+"\n\nBut received this:\n\n " +arrType.toString()+"\n\nIn the expression:\n\n " +e.toString()); bool idxCorrect = getBaseType(arrType[0]) == idxType || idxType == Type::anyType(getEM()); bool valCorrect = getBaseType(arrType[1]) == valType || valType == Type::anyType(getEM());; if(!idxCorrect) { throw TypecheckException ("The type of index expression:\n\n " +idxType.toString() +"\n\nDoes not match the ARRAY's type index:\n\n " +arrType[0].toString() +"\n\nIn the expression: "+e.toString()); } if(!valCorrect) { throw TypecheckException ("The type of value expression:\n\n " +valType.toString() +"\n\nDoes not match the ARRAY's value type:\n\n " +arrType[1].toString() +"\n\nIn the expression: "+e.toString()); } e.setType(arrType); break; } case ARRAY_LITERAL: { DebugAssert(e.isClosure(), "TheoryArray::computeType("+e.toString()+")"); DebugAssert(e.getVars().size()==1, "TheoryArray::computeType("+e.toString()+")"); Type ind(e.getVars()[0].getType()); e.setType(arrayType(ind, e.getBody().getType())); break; } default: DebugAssert(false,"Unexpected type"); break; } } Type TheoryArray::computeBaseType(const Type& t) { const Expr& e = t.getExpr(); DebugAssert(e.getKind()==ARRAY && e.arity() == 2, "TheoryArray::computeBaseType("+t.toString()+")"); vector kids; for(Expr::iterator i=e.begin(), iend=e.end(); i!=iend; ++i) { kids.push_back(getBaseType(Type(*i)).getExpr()); } return Type(Expr(e.getOp(), kids)); } void TheoryArray::computeModelTerm(const Expr& e, std::vector& v) { switch(e.getKind()) { case WRITE: // a WITH [i] := v -- report a, i and v as the model terms. // getModelTerm(e[1], v); // getModelTerm(e[2], v); v.push_back(e[0]); v.push_back(e[1]); v.push_back(e[2]); break; case READ: // For a[i], add the index i // getModelTerm(e[1], v); v.push_back(e[1]); // And continue to collect the reads a[i][j] (remember, e is of // ARRAY type) default: // For array terms, find all their reads if(e.getType().getExpr().getKind() == ARRAY) { for(CDList::const_iterator i=d_reads.begin(), iend=d_reads.end(); i!=iend; ++i) { DebugAssert(isRead(*i) && (*i).arity()==2, "Bad array read: " +(*i).toString()); if((*i)[0] == e) { // Add both the read operator a[i] // getModelTerm(*i, v); v.push_back(*i); // and the index 'i' to the model terms. Reason: the index to // the array should better be a concrete value, and it might not // necessarily be in the current list of model terms. // getModelTerm((*i)[1], v); v.push_back((*i)[1]); } } } break; } } void TheoryArray::computeModel(const Expr& e, std::vector& v) { static unsigned count(0); // For bound vars switch(e.getKind()) { case WRITE: { // We should already have a value for the original array Expr res(getModelValue(e[0]).getRHS()); Expr ind(getEM()->newBoundVarExpr("arr_var", int2string(count++))); Type tp(e.getType()); DebugAssert(isArray(tp) && tp.arity()==2, "TheoryArray::computeModel(WRITE)"); ind.setType(tp[0]); res = rewrite(Expr(READ, res, ind)).getRHS(); Expr indVal(getModelValue(e[1]).getRHS()); Expr updVal(getModelValue(e[2]).getRHS()); res = (ind.eqExpr(indVal)).iteExpr(updVal, res); res = arrayLiteral(ind, res); assignValue(e, res); v.push_back(e); break; } // case READ: { // // Get the assignment for the index // Expr idx(getModelValue(e[1]).getRHS()); // // And the assignment for the // var = read(idxThm.getRHS(), e[0]); // } // And continue to collect the reads a[i][j] (remember, e is of // ARRAY type) default: { // Assign 'e' a value later. v.push_back(e); // Map of e[i] to val for concrete values of i and val ExprHashMap reads; // For array terms, find all their reads DebugAssert(getBaseType(e).getExpr().getKind() == ARRAY, ""); for(CDList::const_iterator i=d_reads.begin(), iend=d_reads.end(); i!=iend; ++i) { TRACE("model", "TheoryArray::computeModel: read = ", *i, ""); DebugAssert(isRead(*i) && (*i).arity()==2, "Bad array read: " +(*i).toString()); if((*i)[0] == e) { // Get the value of the index Theorem asst(getModelValue((*i)[1])); Expr var; if(asst.getLHS()!=asst.getRHS()) { vector thms; vector changed; thms.push_back(asst); changed.push_back(1); Theorem subst(substitutivityRule(*i, changed, thms)); assignValue(transitivityRule(symmetryRule(subst), getModelValue(*i))); var = subst.getRHS(); } else var = *i; if(d_applicationsInModel) v.push_back(var); // Record it in the map Expr val(getModelValue(var).getRHS()); DebugAssert(!val.isNull(), "TheoryArray::computeModel(): Variable " +var.toString()+" has a Null value"); reads[var] = val; } } // Create an array literal if(reads.size()==0) { // Leave the array uninterpreted assignValue(reflexivityRule(e)); } else { // Bound var for the index Expr ind(getEM()->newBoundVarExpr("arr_var", int2string(count++))); Type tp(e.getType()); DebugAssert(isArray(tp) && tp.arity()==2, "TheoryArray::computeModel(WRITE)"); ind.setType(tp[0]); ExprHashMap::iterator i=reads.begin(), iend=reads.end(); DebugAssert(i!=iend, "TheoryArray::computeModel(): expected the reads " "table be non-empty"); // Use one of the concrete values as a default Expr res((*i).second); ++i; DebugAssert(!res.isNull(), "TheoryArray::computeModel()"); for(; i!=iend; ++i) { // Optimization: if the current value is the same as that of the // next application, skip this case; i.e. keep 'res' instead of // building ite(cond, res, res). if((*i).second == res) continue; // ITE condition Expr cond = ind.eqExpr((*i).first[1]); res = cond.iteExpr((*i).second, res); } // Construct the array literal res = arrayLiteral(ind, res); assignValue(e, res); } break; } } } Expr TheoryArray::computeTCC(const Expr& e) { Expr tcc(Theory::computeTCC(e)); switch (e.getKind()) { case READ: DebugAssert(e.arity() == 2,""); return tcc.andExpr(getTypePred(e[0].getType()[0], e[1])); case WRITE: { DebugAssert(e.arity() == 3,""); Type arrType = e[0].getType(); return rewriteAnd(getTypePred(arrType[0], e[1]).andExpr (getTypePred(arrType[1], e[2])).andExpr(tcc)).getRHS(); } case ARRAY_LITERAL: { return tcc; } default: DebugAssert(false,"TheoryArray::computeTCC: Unexpected expression: " +e.toString()); return tcc; } } /////////////////////////////////////////////////////////////////////////////// // Pretty-printing // /////////////////////////////////////////////////////////////////////////////// bool debug_write = false; ExprStream& TheoryArray::print(ExprStream& os, const Expr& e) { d_theoryUsed = true; if (theoryCore()->getTranslator()->printArrayExpr(os, e)) return os; switch(os.lang()) { case PRESENTATION_LANG: switch(e.getKind()) { case READ: if(e.arity() == 1) os << "[" << push << e[0] << push << "]"; else os << e[0] << "[" << push << e[1] << push << "]"; break; case WRITE: IF_DEBUG( if (debug_write) { os << "w(" << push << e[0] << space << ", " << push << e[1] << ", " << push << e[2] << push << ")"; break; } ) os << "(" << push << e[0] << space << "WITH [" << push << e[1] << "] := " << push << e[2] << push << ")"; break; case ARRAY: os << "(ARRAY" << space << e[0] << space << "OF" << space << e[1] << ")"; break; case ARRAY_LITERAL: if(e.isClosure()) { const vector& vars = e.getVars(); const Expr& body = e.getBody(); os << "(" << push << "ARRAY" << space << "(" << push; bool first(true); for(size_t i=0; i 0, "TheoryArray::parseExprOp:\n e = "+e.toString()); const Expr& c1 = e[0][0]; int kind = getEM()->getKind(c1.getString()); switch(kind) { case READ: if(!(e.arity() == 3)) throw ParserException("Bad array access expression: "+e.toString()); return Expr(READ, parseExpr(e[1]), parseExpr(e[2])); case WRITE: if(!(e.arity() == 4)) throw ParserException("Bad array update expression: "+e.toString()); return Expr(WRITE, parseExpr(e[1]), parseExpr(e[2]), parseExpr(e[3])); case ARRAY: { vector k; Expr::iterator i = e.begin(), iend=e.end(); // Skip first element of the vector of kids in 'e'. // The first element is the operator. ++i; // Parse the kids of e and push them into the vector 'k' for(; i!=iend; ++i) k.push_back(parseExpr(*i)); return Expr(kind, k, e.getEM()); break; } case ARRAY_LITERAL: { // (ARRAY (v tp1) body) if(!(e.arity() == 3 && e[1].getKind() == RAW_LIST && e[1].arity() == 2)) throw ParserException("Bad ARRAY literal expression: "+e.toString()); const Expr& varPair = e[1]; if(varPair.getKind() != RAW_LIST) throw ParserException("Bad variable declaration block in ARRAY " "literal expression: "+varPair.toString()+ "\n e = "+e.toString()); if(varPair[0].getKind() != ID) throw ParserException("Bad variable declaration in ARRAY" "literal expression: "+varPair.toString()+ "\n e = "+e.toString()); Type varTp(parseExpr(varPair[1])); vector var; var.push_back(addBoundVar(varPair[0][0].getString(), varTp)); Expr body(parseExpr(e[2])); // Build the resulting Expr as (LAMBDA (vars) body) return getEM()->newClosureExpr(ARRAY_LITERAL, var, body); break; } default: DebugAssert(false, "TheoryArray::parseExprOp: wrong type: " + e.toString()); break; } return e; } Expr TheoryArray::getBaseArray(const Expr& e) const { if (e.getKind() == WRITE) return getBaseArray(e[0]); return e; } namespace CVC3 { Expr arrayLiteral(const Expr& ind, const Expr& body) { vector vars; vars.push_back(ind); return body.getEM()->newClosureExpr(ARRAY_LITERAL, vars, body); } } // end of namespace CVC3 cvc3-2.4.1/src/theory_records/0000775000175400017540000000000011630011320016063 5ustar mdetersmdeterscvc3-2.4.1/src/theory_records/records_theorem_producer.h0000664000175400017540000001122710466450541023350 0ustar mdetersmdeters/*****************************************************************************/ /*! * \file records_theorem_producer.h * * Author: Daniel Wichs * * Created: Jul 22 22:59:07 GMT 2003 * *
* * License to use, copy, modify, sell and/or distribute this software * and its documentation for any purpose is hereby granted without * royalty, subject to the terms and conditions defined in the \ref * LICENSE file provided with this distribution. * *
* */ /*****************************************************************************/ #ifndef _cvc3__records_theorem_producer_h_ #define _cvc3__records_theorem_producer_h_ #include "records_proof_rules.h" #include "theorem_producer.h" #include "theory_records.h" namespace CVC3 { class RecordsTheoremProducer: public RecordsProofRules, public TheoremProducer { TheoryRecords* d_theoryRecords; public: // Constructor RecordsTheoremProducer(TheoremManager* tm, TheoryRecords* t): TheoremProducer(tm), d_theoryRecords(t) { } Theorem rewriteLitSelect(const Expr &e); Theorem rewriteUpdateSelect(const Expr& e); Theorem rewriteLitUpdate(const Expr& e); Theorem expandEq(const Theorem& eqThrm); Theorem expandNeq(const Theorem& neqThrm); Theorem expandRecord(const Expr& e); Theorem expandTuple(const Expr& e); // Expr creation functions //! Test whether expr is a record type bool isRecordType(const Expr& e) { return d_theoryRecords->isRecordType(e); } //! Test whether Type is a record type bool isRecordType(const Type& t) { return d_theoryRecords->isRecordType(t); } //! Test whether expr is a record select/update subclass bool isRecordAccess(const Expr& e) { return d_theoryRecords->isRecordAccess(e); } //! Create a record literal Expr recordExpr(const std::vector& fields, const std::vector& kids) { return d_theoryRecords->recordExpr(fields, kids); } //! Create a record literal Expr recordExpr(const std::vector& fields, const std::vector& kids) { return d_theoryRecords->recordExpr(fields, kids); } //! Create a record type Type recordType(const std::vector& fields, const std::vector& types) { return d_theoryRecords->recordType(fields, types); } //! Create a record type (field types are given as a vector of Expr) Type recordType(const std::vector& fields, const std::vector& types) { return d_theoryRecords->recordType(fields, types); } //! Create a record field select expression Expr recordSelect(const Expr& r, const std::string& field) { return d_theoryRecords->recordSelect(r, field); } //! Create a record field update expression Expr recordUpdate(const Expr& r, const std::string& field, const Expr& val) { return d_theoryRecords->recordUpdate(r, field, val); } //! Get the list of fields from a record literal const std::vector& getFields(const Expr& r) { return d_theoryRecords->getFields(r); } //! Get the i-th field name from the record literal or type const std::string& getField(const Expr& e, int i) { return d_theoryRecords->getField(e, i); } //! Get the field index in the record literal or type /*! The field must be present in the record; otherwise it's an error. */ int getFieldIndex(const Expr& e, const std::string& field) { return d_theoryRecords->getFieldIndex(e, field); } //! Get the field name from the record select and update expressions const std::string& getField(const Expr& e) { return d_theoryRecords->getField(e); } //! Create a tuple literal Expr tupleExpr(const std::vector& kids) { return d_theoryRecords->tupleExpr(kids); } //! Create a tuple type Type tupleType(const std::vector& types) { return d_theoryRecords->tupleType(types); } //! Create a tuple type (types of components are given as Exprs) Type tupleType(const std::vector& types) { return d_theoryRecords->tupleType(types); } //! Create a tuple index selector expression Expr tupleSelect(const Expr& tup, int i) { return d_theoryRecords->tupleSelect(tup, i); } //! Create a tuple index update expression Expr tupleUpdate(const Expr& tup, int i, const Expr& val) { return d_theoryRecords->tupleUpdate(tup, i, val); } //! Get the index from the tuple select and update expressions int getIndex(const Expr& e) { return d_theoryRecords->getIndex(e); } //! Test whether expr is a tuple select/update subclass bool isTupleAccess(const Expr& e) { return d_theoryRecords->isTupleAccess(e); } }; } #endif cvc3-2.4.1/src/theory_records/Makefile0000664000175400017540000000055610533133654017551 0ustar mdetersmdeters################################################## # About this Makefile # # This Makefile depends on Makefile.opts ################################################## MODULE = theory_records SRC = theory_records.cpp records_theorem_producer.cpp HEADERS = records_proof_rules.h records_theorem_producer.h LIBRARY=libtheory_records.a include ../../Makefile.local cvc3-2.4.1/src/theory_records/records_proof_rules.h0000664000175400017540000000323710466450541022343 0ustar mdetersmdeters/*****************************************************************************/ /*! * \file records_proof_rules.h * * Author: Daniel Wichs * * Created: Jul 22 22:59:07 GMT 2003 * *
* * License to use, copy, modify, sell and/or distribute this software * and its documentation for any purpose is hereby granted without * royalty, subject to the terms and conditions defined in the \ref * LICENSE file provided with this distribution. * *
* */ /*****************************************************************************/ #ifndef _cvc3__records_proof_rules_h_ #define _cvc3__records_proof_rules_h_ namespace CVC3 { class Expr; class Theorem; class RecordsProofRules { public: //!< Destructor virtual ~RecordsProofRules() { } //! ==> (REC_LITERAL (f1 v1) ... (fi vi) ...).fi = vi virtual Theorem rewriteLitSelect(const Expr &e) = 0; //! ==> (REC_SELECT (REC_UPDATE e fi vi) fi) = vi virtual Theorem rewriteUpdateSelect(const Expr& e) = 0; //! ==> (REC_UPDATE (REC_LITERAL (f1 v1) ... (fi vi) ...) fi v') =(REC_LITERAL (f1 v1) ... (fi v') ...) virtual Theorem rewriteLitUpdate(const Expr& e) = 0; //! From T|- e = e' return T|- AND (e.i = e'.i) for all i virtual Theorem expandEq(const Theorem& eqThrm) = 0; //! From T|- NOT e=e' return T|- NOT AND (e.i = e'.i) for all i virtual Theorem expandNeq(const Theorem& neqThrm) = 0; //! Expand a record into a literal: |- e = (# f1:=e.f1, ..., fn:=e.fn #) virtual Theorem expandRecord(const Expr& e) = 0; //! Expand a tuple into a literal: |- e = (e.0, ..., e.n-1) virtual Theorem expandTuple(const Expr& e) = 0; }; } #endif cvc3-2.4.1/src/theory_records/records_theorem_producer.cpp0000664000175400017540000002112111327625723023700 0ustar mdetersmdeters /*****************************************************************************/ /*! * \file records_theorem_producer.cpp * * Author: Daniel Wichs * * Created: Jul 22 22:59:07 GMT 2003 * *
* * License to use, copy, modify, sell and/or distribute this software * and its documentation for any purpose is hereby granted without * royalty, subject to the terms and conditions defined in the \ref * LICENSE file provided with this distribution. * *
* */ /*****************************************************************************/ #define _CVC3_TRUSTED_ #include "records_theorem_producer.h" #include "theory_records.h" #include "theory_core.h" using namespace std; using namespace CVC3; RecordsProofRules* TheoryRecords::createProofRules() { return new RecordsTheoremProducer(theoryCore()->getTM(), this); } #define CLASS_NAME "CVC3::RecordsTheoremProducer" //! ==> (SELECT (LITERAL v1 ... vi ...) fi) = vi Theorem RecordsTheoremProducer::rewriteLitSelect(const Expr &e){ Proof pf; if(withProof()) pf = newPf("rewrite_record_literal_select", e); int index=0; switch(e.getOpKind()) { case RECORD_SELECT: { if(CHECK_PROOFS) { CHECK_SOUND(e[0].getOpKind()==RECORD, "expected RECORD child:\n" +e.toString()); } index = getFieldIndex(e[0], getField(e)); break; } case TUPLE_SELECT: { if(CHECK_PROOFS) { CHECK_SOUND(e[0].getOpKind()==TUPLE, "expected TUPLE child:\n" +e.toString()); } index = getIndex(e); break; } default: { if(CHECK_PROOFS) CHECK_SOUND(false, "expected TUPLE_SELECT or RECORD_SELECT kind" + e.toString()); } } if(CHECK_PROOFS) { CHECK_SOUND(index!=-1 && index (RECORD_SELECT (RECORD_UPDATE r fi vi) fj) = vi //iff j=i, r.fj otherwise (and same for tuples) Theorem RecordsTheoremProducer::rewriteUpdateSelect(const Expr& e) { Proof pf; switch(e.getOpKind()) { case RECORD_SELECT: { if(CHECK_PROOFS) CHECK_SOUND(e[0].getOpKind() == RECORD_UPDATE, "expected RECORD_UPDATE child" + e.toString()); if(withProof()) pf = newPf("rewrite_record_update_and_select", e); if(getField(e) == getField(e[0])) return newRWTheorem(e, e[0][1], Assumptions::emptyAssump(), pf); else return newRWTheorem(e, recordSelect(e[0][0], getField(e)), Assumptions::emptyAssump(), pf); break; } case TUPLE_SELECT: { if(CHECK_PROOFS) CHECK_SOUND(e[0].getOpKind() == TUPLE_UPDATE, "expected TUPLE_UPDATE child" + e.toString()); if(withProof()) pf = newPf("rewrite_record_update_and_select", e); if(getIndex(e) == getIndex(e[0])) return newRWTheorem(e, e[0][1], Assumptions::emptyAssump(), pf); else return newRWTheorem(e, tupleSelect(e[0][0], getIndex(e)), Assumptions::emptyAssump(), pf); break; } default: if(CHECK_PROOFS) CHECK_SOUND(false, "expected RECORD_SELECT or TUPLE_SELECT kind" + e.toString()); break; } //to avoid warnings return newRWTheorem(e, e, Assumptions::emptyAssump(), pf); } //! ==> (RECORD_UPDATE (RECORD (f1 v1) ... (fi vi) ...) fi v') =(RECORD (f1 v1) ... (fi v') ...) and same for tuples. Theorem RecordsTheoremProducer::rewriteLitUpdate(const Expr& e) { int index =0; switch(e.getOpKind()) { case RECORD_UPDATE: { if(CHECK_PROOFS) CHECK_SOUND(e[0].getOpKind() == RECORD, "expected a RECORD: e = "+e.toString()); index = getFieldIndex(e[0], getField(e)); break; } case TUPLE_UPDATE: { if(CHECK_PROOFS) CHECK_SOUND(e[0].getOpKind() == TUPLE, "expected a TUPLE: e = "+ e.toString()); index = getIndex(e); break; } default: if(CHECK_PROOFS) CHECK_SOUND(false, "expected RECORD_UPDATE or TUPLE_UPDATE kind" + e.toString()); } vector fieldVals= e[0].getKids(); if(CHECK_PROOFS) CHECK_SOUND(index!=-1 && index orChildren; for(int i=0; i andChildren; for(int i=0; i& fields(getFields(e0)); DebugAssert(fields[i].getString() == getField(e1, i), "equation types mismatch \n" + eqThrm.getExpr().toString()); lhs1 = recordSelect(lhs, fields[i].getString()); rhs1 = recordSelect(rhs, fields[i].getString()); break; } case TUPLE_TYPE: { lhs1 = tupleSelect(lhs, i); rhs1 = tupleSelect(rhs, i); break; } default: DebugAssert(false, "RecordsTheoremProducer::expandEq(): " "Type must be TUPLE or RECORD: "+e0.toString()); } Expr eq = lhs1.getType().isBool()? lhs1.iffExpr(rhs1) : lhs1.eqExpr(rhs1); andChildren.push_back(eq); } Proof pf; if(withProof()) pf= newPf("rewrite record_literal_update", eqThrm.getExpr(), eqThrm.getProof()); return newTheorem(andExpr(andChildren), eqThrm.getAssumptionsRef() , pf); } Theorem RecordsTheoremProducer::expandRecord(const Expr& e) { Type tp(d_theoryRecords->getBaseType(e)); if(CHECK_PROOFS) { CHECK_SOUND(isRecordType(tp), "expandRecord("+e.toString()+"): not a record type"); } const vector& fields = getFields(tp.getExpr()); vector kids; for(vector::const_iterator i=fields.begin(), iend=fields.end(); i!=iend; ++i) kids.push_back(recordSelect(e, (*i).getString())); Proof pf; if(withProof()) pf = newPf("expand_record", e); return newRWTheorem(e, recordExpr(fields, kids), Assumptions::emptyAssump(), pf); } Theorem RecordsTheoremProducer::expandTuple(const Expr& e) { Type tp(d_theoryRecords->getBaseType(e)); if(CHECK_PROOFS) { CHECK_SOUND(tp.getExpr().getOpKind() == TUPLE_TYPE, "expandTuple("+e.toString()+"): not a tuple type"); } int size(tp.arity()); vector kids; for(int i=0; i * * License to use, copy, modify, sell and/or distribute this software * and its documentation for any purpose is hereby granted without * royalty, subject to the terms and conditions defined in the \ref * LICENSE file provided with this distribution. * *
* */ /*****************************************************************************/ #include "theory_records.h" #include "typecheck_exception.h" #include "parser_exception.h" #include "smtlib_exception.h" #include "records_proof_rules.h" #include "theory_core.h" using namespace std; using namespace CVC3; /*! * When a record/tuple (dis)equality is expanded into the * (dis)equalities of fields, we have to perform rewrites on the * resulting record terms before the simplifier kicks in. * * Otherwise, if we have r1.f = r2.f, but r1=r2 was asserted before, * for some complex record expressions r1 and r2, then the simplifier * will substitute r2 for r1, and we get r2.f=r2.f at the end, which * is not a useful fact to have. * * However, r1.f and/or r2.f may rewrite to something interesting, and * the equality may yield new important facts. */ Theorem TheoryRecords::rewriteAux(const Expr& e) { Theorem res; switch(e.getKind()) { case EQ: case IFF: case AND: case OR: { vector changed; vector thms; for(int i=0, iend=e.arity(); i 0) { res = substitutivityRule(e, changed, thms); // Need to guarantee that new expressions are fully simplified if(res.getRHS().hasFind()) res = transitivityRule(res, res.getRHS().getFind()); } else res = reflexivityRule(e); break; } case NOT: { vector thms; thms.push_back(rewriteAux(e[0])); if(thms[0].getLHS() != thms[0].getRHS()) { res = substitutivityRule(NOT, thms); // Need to guarantee that new expressions are fully simplified if(res.getRHS().hasFind()) res = transitivityRule(res, res.getRHS().getFind()); } else res = reflexivityRule(e); break; } default: res = rewrite(e); break; } return res; } Theorem TheoryRecords::rewriteAux(const Theorem& thm) { return iffMP(thm, rewriteAux(thm.getExpr())); } TheoryRecords::TheoryRecords(TheoryCore* core) : Theory(core, "Records") { getEM()->newKind(RECORD_TYPE, "_RECORD_TYPE", true); getEM()->newKind(TUPLE_TYPE, "_TUPLE_TYPE", true); getEM()->newKind(RECORD, "_RECORD"); getEM()->newKind(RECORD_SELECT, "_RECORD_SELECT"); getEM()->newKind(RECORD_UPDATE, "_RECORD_UPDATE"); getEM()->newKind(TUPLE, "_TUPLE"); getEM()->newKind(TUPLE_SELECT, "_TUPLE_SELECT"); getEM()->newKind(TUPLE_UPDATE, "_TUPLE_UPDATE"); d_rules = createProofRules(); vector kinds; kinds.push_back(RECORD); kinds.push_back(RECORD_SELECT); kinds.push_back(RECORD_UPDATE); kinds.push_back(RECORD_TYPE); kinds.push_back(TUPLE_TYPE); kinds.push_back(TUPLE); kinds.push_back(TUPLE_SELECT); kinds.push_back(TUPLE_UPDATE); registerTheory(this, kinds); } TheoryRecords::~TheoryRecords() { delete d_rules; } void TheoryRecords::assertFact(const Theorem& e) { // TRACE("records", "assertFact => ", e.toString(), ""); const Expr& expr = e.getExpr(); Theorem expanded; switch(expr.getKind()) { case IFF: case EQ: { int lhsKind = getBaseType(expr[0]).getExpr().getOpKind(); if(lhsKind == RECORD_TYPE || lhsKind== TUPLE_TYPE) { expanded = rewriteAux(d_rules->expandEq(e)); TRACE("records", "assertFact: enqueuing: ", expanded.toString(), ""); enqueueFact(expanded); } return; } case NOT: DebugAssert(expr[0].getKind() == EQ || expr[0].getKind() == IFF, "expecting a disequality or boolean field extraction: " +expr.toString()); break; default: DebugAssert(false, "TheoryRecords::assertFact expected an equation" " or negation of equation expression. Instead it got" + e.toString()); } } Theorem TheoryRecords::rewrite(const Expr& e) { Theorem rw; TRACE("records", "rewrite(", e, ") {"); bool needRecursion=false; switch(e.getOpKind()) { case TUPLE_SELECT: case RECORD_SELECT: { switch(e[0].getOpKind()){ case RECORD:{ rw = d_rules->rewriteLitSelect(e); break; } case TUPLE: { rw = d_rules->rewriteLitSelect(e); break; } case RECORD_UPDATE: { rw = d_rules->rewriteUpdateSelect(e); needRecursion=true; break; } case TUPLE_UPDATE: { rw = d_rules->rewriteUpdateSelect(e); needRecursion=true; break; } default:{ rw = reflexivityRule(e); break; } } break; } case RECORD_UPDATE: { DebugAssert(e.arity() == 2, "TheoryRecords::rewrite(RECORD_UPDATE): e="+e.toString()); if(e[0].getOpKind() == RECORD) rw= d_rules->rewriteLitUpdate(e); else rw = reflexivityRule(e); break; } case TUPLE_UPDATE: { if(e[0].getOpKind() == TUPLE) rw = d_rules->rewriteLitUpdate(e); else rw = reflexivityRule(e); break; } case RECORD: case TUPLE: rw = rewriteCC(e); // Congruence closure rewrites break; default: { rw = reflexivityRule(e); break; } } Theorem res; if(needRecursion==true) res = transitivityRule(rw, rewrite(rw.getRHS())); else res = rw; TRACE("records", "rewrite => ", res.getRHS(), " }"); return res; } Expr TheoryRecords::computeTCC(const Expr& e) { TRACE("records", "computeTCC( ", e, ") {"); Expr tcc(Theory::computeTCC(e)); switch (e.getOpKind()) { case RECORD: case RECORD_SELECT: case TUPLE: case TUPLE_SELECT: break; case RECORD_UPDATE: { Expr tExpr = e.getType().getExpr(); const std::string field(getField(e)); int index = getFieldIndex(tExpr, field); Expr pred = getTypePred(e.getType()[index], e[1]); tcc = rewriteAnd(tcc.andExpr(pred)).getRHS(); break; } case TUPLE_UPDATE: { Expr tExpr = e.getType().getExpr(); int index = getIndex(e); Expr pred = getTypePred(e.getType()[index], e[1]); tcc = rewriteAnd(tcc.andExpr(pred)).getRHS(); break; } default: { DebugAssert (false, "Theory records cannot calculate this tcc"); } } TRACE("records", "computeTCC => ", tcc, "}"); return tcc; } void TheoryRecords::computeModelTerm(const Expr& e, std::vector& v) { Type t = e.getType(); Expr tExpr = t.getExpr(); if(tExpr.getOpKind() == RECORD_TYPE) { const vector& fields = getFields(tExpr); for(unsigned int i = 0; i < fields.size() ; i++) { Expr term(recordSelect(e, fields[i].getString())); term = rewrite(term).getRHS(); v.push_back(term); } } else if(tExpr.getOpKind() == TUPLE_TYPE) { for(int i=0; i& v) { Type t = getBaseType(e); Expr tExpr = t.getExpr(); vector thms; vector changed; Theorem asst; if(tExpr.getOpKind() == RECORD_TYPE) asst = d_rules->expandRecord(e); else if(tExpr.getOpKind() == TUPLE_TYPE) asst = d_rules->expandTuple(e); else { DebugAssert(false, "TheoryRecords::computeModel("+e.toString()+")"); return; } const Expr& lit = asst.getRHS(); int size(lit.arity()); for(int i = 0; i < size ; i++) { Theorem thm(getModelValue(lit[i])); if(thm.getLHS() != thm.getRHS()) { thms.push_back(thm); changed.push_back(i); } } if(changed.size()>0) asst = transitivityRule(asst, substitutivityRule(lit, changed, thms)); assignValue(asst); v.push_back(e); } Expr TheoryRecords::computeTypePred(const Type& t, const Expr& e) { TRACE("typePred", "ComputeTypePred[Records]", e, ""); Expr tExpr = t.getExpr(); switch(tExpr.getOpKind()) { case RECORD_TYPE: { const vector& fields = getFields(tExpr); vector fieldPreds; for(unsigned int i = 0; i fieldPreds; for(int i = 0; igetKindName(e.getOpKind())); } } //TODO: implement finiteTypeInfo Cardinality TheoryRecords::finiteTypeInfo(Expr& e, Unsigned& n, bool enumerate, bool computeSize) { return CARD_UNKNOWN; } void TheoryRecords::computeType(const Expr& e) { switch (e.getOpKind()) { case RECORD:{ DebugAssert(e.arity() > 0, "wrong arity of RECORD" + e.toString()); vector fieldTypes; const vector& fields = getFields(e); string previous; DebugAssert((unsigned int)e.arity() == fields.size(), "size of fields does not match size of values"); for(int i = 0; i 0, "wrong arity of TUPLE"+ e.toString()); std::vector types; for(Expr::iterator it = e.begin(), end=e.end(); it!=end; ++it) { types.push_back((*it).getType().getExpr()); } e.setType(Type(Expr(TUPLE_TYPE, types, getEM()))); return; } case TUPLE_SELECT: { DebugAssert(e.arity() == 1, "wrong arity of TUPLE_SELECT" + e.toString()); Expr t = e[0].getType().getExpr(); int index = getIndex(e); DebugAssert(t.getOpKind() == TUPLE_TYPE, "incorrect TUPLE_SELECT expression: " "first child is not a TUPLE_TYPE:\n\n" + e.toString()); if(index >= t.arity()) throw TypecheckException("tuple index exceeds number of fields: \n" + e.toString()); e.setType(Type(t[index])); return; } case TUPLE_UPDATE: { DebugAssert(e.arity() == 2, "wrong arity of TUPLE_UPDATE" + e.toString()); Expr t = e[0].getType().getExpr(); int index = getIndex(e); DebugAssert(t.getOpKind() == TUPLE_TYPE, "incorrect TUPLE_SELECT expression: " "first child not a TUPLE_TYPE:\n\n" + e.toString()); if(index >= t.arity()) throw TypecheckException("tuple index exceeds number of fields: \n" + e.toString()); if(getBaseType(Type(t[index])) != getBaseType(e[1])) throw TypecheckException("tuple update type mismatch: \n"+ e.toString()); e.setType(e[0].getType()); return; } default: DebugAssert(false,"Unexpected type: "+e.toString()); break; } } Type TheoryRecords::computeBaseType(const Type& t) { const Expr& e = t.getExpr(); Type res; switch(e.getOpKind()) { case TUPLE_TYPE: case RECORD_TYPE: { DebugAssert(e.arity() > 0, "Expected non-empty type"); vector kids; for(Expr::iterator i=e.begin(), iend=e.end(); i!=iend; ++i) { kids.push_back(getBaseType(Type(*i)).getExpr()); } res = Type(Expr(e.getOp(), kids)); break; } default: DebugAssert(false, "TheoryRecords::computeBaseType("+t.toString()+")"); res = t; } return res; } void TheoryRecords::setup(const Expr& e) { // Only set up terms if (e.isTerm()) { switch(e.getOpKind()) { case RECORD: case TUPLE: // Setup for congruence closure setupCC(e); break; default: { // Everything else for(Expr::iterator i=e.begin(), iend=e.end(); i!=iend; ++i) i->addToNotify(this, e); // Check if we have a tuple of record type, and set up those for CC Type tp(getBaseType(e)); Theorem thm; if(isRecordType(tp)) // Expand e into its literal, and it setup for CC thm = d_rules->expandRecord(e); else if(isTupleType(tp)) thm = d_rules->expandTuple(e); if(!thm.isNull()) { Expr lit(thm.getRHS()); TRACE("records", "setup: lit = ", lit, ""); // Simplify the kids vector thms; vector changed; for(int i=0,iend=lit.arity(); i0) { thm = transitivityRule(thm, substitutivityRule(lit, changed, thms)); lit = thm.getRHS(); } // Check if lit has already been setup if(lit.hasFind()) { enqueueFact(transitivityRule(thm, find(lit))); } else { theoryCore()->setupTerm(lit, this, thm); assertEqualities(symmetryRule(thm)); } } } } } } void TheoryRecords::update(const Theorem& e, const Expr& d) { if (inconsistent()) return; DebugAssert(d.hasFind(), "Expected d to have find"); switch(d.getOpKind()) { case RECORD: case TUPLE: // Record and tuple literals are handled by congruence closure updates updateCC(e, d); break; default: // Everything else // If d is not its own representative, don't do anything; the // representative will be sent to us eventually. if (find(d).getRHS() == d) { // Substitute e[1] for e[0] in d and assert the result equal to d Theorem thm = updateHelper(d); thm = transitivityRule(thm, rewrite(thm.getRHS())); assertEqualities(transitivityRule(thm, find(thm.getRHS()))); } } } ExprStream& TheoryRecords::print(ExprStream& os, const Expr& e) { switch(os.lang()) { case PRESENTATION_LANG: { switch(e.getOpKind()){ case TUPLE:{ int i=0, iend=e.arity(); os << "(" << push; if(i!=iend) os << e[i]; ++i; for(; i!=iend; ++i) os << push << "," << pop << space << e[i]; os << push << ")"; break; } case TUPLE_TYPE: { int i=0, iend=e.arity(); os << "[" << push; if(i!=iend) os << e[i]; ++i; for(; i!=iend; ++i) os << push << "," << pop << space << e[i]; os << push << "]"; break; } case RECORD: { size_t i=0, iend=e.arity(); if(!isRecord(e)) { e.printAST(os); break; } const vector& fields = getFields(e); if(iend != fields.size()) { e.printAST(os); break; } os << "(# " << push; if(i!=iend) { os << fields[i].getString() << space << ":="<< space << push << e[i] << pop; ++i; } for(; i!=iend; ++i) os << push << "," << pop << space << fields[i].getString() << space << ":="<< space << push << e[i] << pop; os << push << space << "#)"; break; } case RECORD_TYPE: { size_t i=0, iend=e.arity(); if(!isRecordType(e)) { e.printAST(os); break; } const vector& fields = getFields(e); if(iend != fields.size()) { e.printAST(os); break; } os << "[# " << push; if(i!=iend) { os << fields[i].getString() << ":"<< space << push << e[i] << pop; ++i; } for(; i!=iend; ++i) os << push << "," << pop << space << fields[i].getString() << ":"<< space << push << e[i] << pop; os << push << space << "#]"; break; } case RECORD_SELECT: if(isRecordAccess(e) && e.arity() == 1) os << "(" << push << e[0] << push << ")" << "." << push << getField(e); else e.printAST(os); break; case TUPLE_SELECT: if(isTupleAccess(e) && e.arity() == 1) os << "(" << push << e[0] << push << ")" << "." << push << getIndex(e); else e.printAST(os); break; case RECORD_UPDATE: if(isRecordAccess(e) && e.arity() == 2) os << "(" << push << e[0] << space << "WITH ." << push << getField(e) << space << ":=" << space << push << e[1] << push << ")"; else e.printAST(os); break; case TUPLE_UPDATE: if(isTupleAccess(e) && e.arity() == 2) os << "(" << push << e[0] << space << "WITH ." << push << getIndex(e) << space << ":=" << space << push << e[1] << push << ")"; else e.printAST(os); break; default: e.printAST(os); break; } break; } case SMTLIB_LANG: case SMTLIB_V2_LANG: { d_theoryUsed = true; throw SmtlibException("TheoryRecords::print: SMTLIB not supported"); switch(e.getOpKind()){ case TUPLE:{ int i=0, iend=e.arity(); os << "(" << push << "TUPLE"; for(; i& fields = getFields(e); if(iend != fields.size()) { e.printAST(os); break; } os << "(" << push << "RECORD"; for(; i!=iend; ++i) os << space << "(" << push << fields[i].getString() << space << e[i] << push << ")" << pop << pop; os << push << ")"; break; } case RECORD_TYPE: { size_t i=0, iend=e.arity(); if(!isRecord(e)) { e.printAST(os); break; } const vector& fields = getFields(e); if(iend != fields.size()) { e.printAST(os); break; } os << "(" << push << "RECORD_TYPE"; for(; i!=iend; ++i) os << space << "(" << push << fields[i].getString() << space << e[i] << push << ")" << pop << pop; os << push << space << ")"; break; } case RECORD_SELECT: if(isRecordAccess(e)) os << "(" << push << "RECORD_SELECT" << space << e[0] << space << getField(e) << push << ")"; else e.printAST(os); break; case TUPLE_SELECT: if(isTupleAccess(e)) os << "(" << push << "TUPLE_SELECT" << space << e[0] << space << getIndex(e) << push << ")"; else e.printAST(os); break; case RECORD_UPDATE: if(isRecordAccess(e) && e.arity() == 2) os << "(" << push << "RECORD_UPDATE" << space << e[0] << space << getField(e) << space << e[1] << push << ")"; else e.printAST(os); break; case TUPLE_UPDATE: if(isTupleAccess(e)) os << "(" << push << "TUPLE_UPDATE" << space << e[0] << space << getIndex(e) << space << e[1] << push << ")"; else e.printAST(os); break; default: e.printAST(os); break; } break; } case LISP_LANG: { switch(e.getOpKind()){ case TUPLE:{ int i=0, iend=e.arity(); os << "(" << push << "TUPLE"; for(; i& fields = getFields(e); if(iend != fields.size()) { e.printAST(os); break; } os << "(" << push << "RECORD"; for(; i!=iend; ++i) os << space << "(" << push << fields[i].getString() << space << e[i] << push << ")" << pop << pop; os << push << ")"; break; } case RECORD_TYPE: { size_t i=0, iend=e.arity(); if(!isRecord(e)) { e.printAST(os); break; } const vector& fields = getFields(e); if(iend != fields.size()) { e.printAST(os); break; } os << "(" << push << "RECORD_TYPE"; for(; i!=iend; ++i) os << space << "(" << push << fields[i].getString() << space << e[i] << push << ")" << pop << pop; os << push << space << ")"; break; } case RECORD_SELECT: if(isRecordAccess(e)) os << "(" << push << "RECORD_SELECT" << space << e[0] << space << getField(e) << push << ")"; else e.printAST(os); break; case TUPLE_SELECT: if(isTupleAccess(e)) os << "(" << push << "TUPLE_SELECT" << space << e[0] << space << getIndex(e) << push << ")"; else e.printAST(os); break; case RECORD_UPDATE: if(isRecordAccess(e) && e.arity() == 2) os << "(" << push << "RECORD_UPDATE" << space << e[0] << space << getField(e) << space << e[1] << push << ")"; else e.printAST(os); break; case TUPLE_UPDATE: if(isTupleAccess(e)) os << "(" << push << "TUPLE_UPDATE" << space << e[0] << space << getIndex(e) << space << e[1] << push << ")"; else e.printAST(os); break; default: e.printAST(os); break; } break; } default: e.printAST(os); break; } return os; } /////////////////////////////////////////////////////////////////////////////// //parseExprOp: //translating special Exprs to regular EXPR?? /////////////////////////////////////////////////////////////////////////////// Expr TheoryRecords::parseExprOp(const Expr& e) { TRACE("parser", "TheoryRecords::parseExprOp(", e, ")"); // If the expression is not a list, it must have been already // parsed, so just return it as is. if(RAW_LIST != e.getKind()) return e; DebugAssert(e.arity() > 0, "TheoryRecords::parseExprOp:\n e = "+e.toString()); const Expr& c1 = e[0][0]; const string& kindStr = c1.getString(); int kind = e.getEM()->getKind(kindStr); switch(kind) { case RECORD_TYPE: // (RECORD_TYPE (f1 e1) (f2 e2) ...) case RECORD: { // (RECORD (f1 e1) (f2 e2) ...) if(e.arity() < 2) throw ParserException("Empty "+kindStr+": "+e.toString()); vector fields; vector kids; Expr::iterator i = e.begin(), iend=e.end(); ++i; for(; i!=iend; ++i) { if(i->arity() != 2 || (*i)[0].getKind() != ID) throw ParserException("Bad field declaration in "+kindStr+": " +i->toString()+"\n in "+e.toString()); fields.push_back((*i)[0][0]); kids.push_back(parseExpr((*i)[1])); } return (kind==RECORD)? recordExpr(fields, kids) : recordType(fields, kids).getExpr(); } case RECORD_SELECT: { // (RECORD_SELECT e field) if(e.arity() != 3 || e[2].getKind() != ID) throw ParserException("Field must be an ID in RECORD_SELECT: " +e.toString()); return recordSelect(parseExpr(e[1]), e[2][0].getString()); } case RECORD_UPDATE: { // (RECORD_UPDATE e1 field e2) if(e.arity() != 4 || e[2].getKind() != ID) throw ParserException("Field must be an ID in RECORD_UPDATE: " +e.toString()); return recordUpdate(parseExpr(e[1]), e[2][0].getString(), parseExpr(e[3])); } case TUPLE_SELECT: { // (TUPLE_SELECT e index) if(e.arity() != 3 || !e[2].isRational() || !e[2].getRational().isInteger()) throw ParserException("Index must be an integer in TUPLE_SELECT: " +e.toString()); return tupleSelect(parseExpr(e[1]), e[2].getRational().getInt()); } case TUPLE_UPDATE: { // (TUPLE_UPDATE e1 index e2) if(e.arity() != 4 || !e[2].isRational() || !e[2].getRational().isInteger()) throw ParserException("Index must be an integer in TUPLE_UPDATE: " +e.toString()); return tupleUpdate(parseExpr(e[1]), e[2].getRational().getInt(), parseExpr(e[3])); } case TUPLE_TYPE: case TUPLE: { if(e.arity() < 2) throw ParserException("Empty "+kindStr+": "+e.toString()); vector k; Expr::iterator i = e.begin(), iend=e.end(); // Skip first element of the vector of kids in 'e'. // The first element is the operator. ++i; // Parse the kids of e and push them into the vector 'k' for(; i!=iend; ++i) k.push_back(parseExpr(*i)); return (kind==TUPLE)? tupleExpr(k) : tupleType(k).getExpr(); } default: DebugAssert(false, "TheoryRecords::parseExprOp: invalid command or expression: " + e.toString()); break; } return e; } //! Create a record literal Expr TheoryRecords::recordExpr(const std::vector& fields, const std::vector& kids) { vector fieldExprs; vector::const_iterator i = fields.begin(), iend = fields.end(); for (; i != iend; ++i) fieldExprs.push_back(getEM()->newStringExpr(*i)); return recordExpr(fieldExprs, kids); } Expr TheoryRecords::recordExpr(const std::vector& fields, const std::vector& kids) { return Expr(Expr(RECORD, fields).mkOp(), kids); } //! Create a record type Type TheoryRecords::recordType(const std::vector& fields, const std::vector& types) { vector kids; for(vector::const_iterator i=types.begin(), iend=types.end(); i!=iend; ++i) kids.push_back(i->getExpr()); return recordType(fields, kids); } //! Create a record type Type TheoryRecords::recordType(const std::vector& fields, const std::vector& types) { vector fieldExprs; vector::const_iterator i = fields.begin(), iend = fields.end(); for (; i != iend; ++i) fieldExprs.push_back(getEM()->newStringExpr(*i)); return recordType(fieldExprs, types); } Type TheoryRecords::recordType(const std::vector& fields, const std::vector& types) { return Type(Expr(Expr(RECORD_TYPE, fields).mkOp(), types)); } //! Create a record field selector expression Expr TheoryRecords::recordSelect(const Expr& r, const std::string& field) { return Expr(getEM()->newSymbolExpr(field, RECORD_SELECT).mkOp(), r); } //! Create a record field update expression Expr TheoryRecords::recordUpdate(const Expr& r, const std::string& field, const Expr& val) { return Expr(getEM()->newSymbolExpr(field, RECORD_UPDATE).mkOp(), r, val); } //! Get the list of fields from a record literal const vector& TheoryRecords::getFields(const Expr& r) { DebugAssert(r.isApply() && (r.getOpKind() == RECORD || r.getOpKind() == RECORD_TYPE), "TheoryRecords::getFields: Not a record literal: " +r.toString(AST_LANG)); return r.getOpExpr().getKids(); } // Get the i-th field name from the record literal const string& TheoryRecords::getField(const Expr& r, int i) { DebugAssert(r.isApply() && (r.getOpKind() == RECORD || r.getOpKind() == RECORD_TYPE), "TheoryRecords::getField: Not a record literal: " +r.toString()); return r.getOpExpr()[i].getString(); } // Get field index from the record literal int TheoryRecords::getFieldIndex(const Expr& e, const string& field) { const vector& fields = getFields(e); for(size_t i=0, iend=fields.size(); i& kids) { return Expr(TUPLE, kids, getEM()); } //! Create a tuple type Type TheoryRecords::tupleType(const std::vector& types) { vector kids; for(vector::const_iterator i=types.begin(), iend=types.end(); i!=iend; ++i) kids.push_back(i->getExpr()); return Type(Expr(TUPLE_TYPE, kids, getEM())); } //! Create a tuple type Type TheoryRecords::tupleType(const std::vector& types) { return Expr(TUPLE_TYPE, types, getEM()); } //! Create a tuple index selector expression Expr TheoryRecords::tupleSelect(const Expr& tup, int i) { return Expr(Expr(TUPLE_SELECT, getEM()->newRatExpr(i)).mkOp(), tup); } //! Create a tuple index update expression Expr TheoryRecords::tupleUpdate(const Expr& tup, int i, const Expr& val) { return Expr(Expr(TUPLE_UPDATE, getEM()->newRatExpr(i)).mkOp(), tup, val); } //! Get the index from the tuple select and update expressions int TheoryRecords::getIndex(const Expr& r) { DebugAssert(r.isApply() && (r.getOpKind() == TUPLE_SELECT || r.getOpKind() == TUPLE_UPDATE), "TheoryRecords::getField: Not a record literal: "); return r.getOpExpr()[0].getRational().getInt(); } cvc3-2.4.1/src/include/0000775000175400017540000000000011630011320014453 5ustar mdetersmdeterscvc3-2.4.1/src/include/expr_value.h0000664000175400017540000007147711267471567017053 0ustar mdetersmdeters/*****************************************************************************/ /*! * \file expr_value.h * * Author: Sergey Berezin * * Created: Fri Feb 7 15:07:18 2003 * *
* * License to use, copy, modify, sell and/or distribute this software * and its documentation for any purpose is hereby granted without * royalty, subject to the terms and conditions defined in the \ref * LICENSE file provided with this distribution. * *
* * Class ExprValue: the value holding class of Expr. No one should * use it directly; use Expr API instead. To enforce that, the * constructors are made protected, and only Expr, ExprManager, and * subclasses can use them. */ /*****************************************************************************/ // *** HACK ATTACK *** (trick from Aaron Stump's code) // In order to inline the Expr constructors (for efficiency), this // file (expr_value.h) must be included in expr.h. However, we also // need to include expr.h here, hence, circular dependency. A way to // break it is to include expr_value.h in the middle of expr.h after // the definition of class Expr, but before the definition of its // inlined methods. So, expr.h included below will also suck in // expr_value.h recursively, meaning that we then should skip the rest // of the file (since it's already been included). // That's why expr.h is outside of #ifndef. The same is true for // type.h and theorem.h. #ifndef _cvc3__expr_h_ #include "expr.h" #endif #ifndef _cvc3__expr_value_h_ #define _cvc3__expr_value_h_ #include "theorem.h" #include "type.h" // The prime number used in the hash function for a vector of elements #define PRIME 131 namespace CVC3 { /*****************************************************************************/ /*! *\class ExprValue *\brief The base class for holding the actual data in expressions * * * Author: Sergey Berezin * * Created: long time ago * * \anchor ExprValue The base class just holds the operator. * All the additional data resides in subclasses. * */ /*****************************************************************************/ class CVC_DLL ExprValue { friend class Expr; friend class Expr::iterator; friend class ExprManager; friend class ::CInterface; friend class ExprApply; friend class Theorem; friend class ExprClosure; //! Unique expression id ExprIndex d_index; //! Reference counter for garbage collection unsigned d_refcount; //! Cached hash value (initially 0) size_t d_hash; //! The find attribute (may be NULL) CDO* d_find; //! Equality between this term and next term in ring of all terms in the equivalence class CDO* d_eqNext; //! The cached type of the expression (may be Null) Type d_type; //! The cached TCC of the expression (may be Null) // Expr d_tcc; //! Subtyping predicate for the expression and all subexpressions // Theorem d_subtypePred; //! Notify list may be NULL (== no such attribute) NotifyList* d_notifyList; //! For caching calls to Simplify Theorem d_simpCache; //! For checking whether simplify cache is valid unsigned d_simpCacheTag; //! context-dependent bit-vector for flags that are context-dependent CDFlags d_dynamicFlags; //! Size of dag rooted at this expression Unsigned d_size; //! Which child has the largest height // int d_highestKid; //! Most distant expression we were simplified *from* // Expr d_simpFrom; //! Generic flag for marking expressions (e.g. in DAG traversal) unsigned d_flag; protected: /*! @brief The kind of the expression. In particular, it determines which * subclass of ExprValue is used to store the expression. */ int d_kind; //! Our expr. manager ExprManager* d_em; // End of data members private: //! Set the ExprIndex void setIndex(ExprIndex idx) { d_index = idx; } //! Increment reference counter void incRefcount() { ++d_refcount; } //! Decrement reference counter void decRefcount() { // Cannot be DebugAssert, since we are called in a destructor // and should not throw an exception IF_DEBUG(FatalAssert(d_refcount > 0, "Mis-handled the ref. counting");) if((--d_refcount) == 0) d_em->gc(this); } //! Caching hash function /*! Do NOT implement it in subclasses! Implement computeHash() instead. */ size_t hash() const { if (d_hash == 0) const_cast(this)->d_hash = computeHash(); return d_hash; } //! Return DAG-size of Expr Unsigned getSize() const { if (d_flag == d_em->getFlag()) return 0; const_cast(this)->d_flag = d_em->getFlag(); return computeSize(); } //! Return child with greatest height // int getHighestKid() const { return d_highestKid; } //! Get Expr simplified to obtain this expr // const Expr& getSimpFrom() const { return d_simpFrom; } //! Set Expr simplified to obtain this expr // void setSimpFrom(const Expr& simpFrom) { d_simpFrom = simpFrom; } protected: // Static hash functions. They don't depend on the context // (ExprManager and such), so it is still thread-safe to have them // static. static std::hash s_charHash; static std::hash s_intHash; static size_t pointerHash(void* p) { return s_intHash((long int)p); } // Hash function for subclasses with children static size_t hash(const int kind, const std::vector& kids); // Hash function for kinds static size_t hash(const int n) { return s_intHash((long int)n); } // Size function for subclasses with children static Unsigned sizeWithChildren(const std::vector& kids); //! Return the memory manager (for the benefit of subclasses) MemoryManager* getMM(size_t MMIndex) { DebugAssert(d_em!=NULL, "ExprValue::getMM()"); return d_em->getMM(MMIndex); } //! Make a clean copy of itself using the given ExprManager ExprValue* rebuild(ExprManager* em) const { return copy(em, 0); } //! Make a clean copy of the expr using the given ExprManager Expr rebuild(Expr e, ExprManager* em) const { return em->rebuildRec(e); } // Protected API //! Non-caching hash function which actually computes the hash. /*! This is the method that all subclasses should implement */ virtual size_t computeHash() const { return hash(d_kind); } //! Non-caching size function which actually computes the size. /*! This is the method that all subclasses should implement */ virtual Unsigned computeSize() const { return 1; } //! Make a clean copy of itself using the given ExprManager virtual ExprValue* copy(ExprManager* em, ExprIndex idx) const; public: //! Constructor ExprValue(ExprManager* em, int kind, ExprIndex idx = 0) : d_index(idx), d_refcount(0), d_hash(0), d_find(NULL), d_eqNext(NULL), d_notifyList(NULL), d_simpCacheTag(0), d_dynamicFlags(em->getCurrentContext()), d_size(0), // d_height(0), d_highestKid(-1), d_flag(0), d_kind(kind), d_em(em) { DebugAssert(em != NULL, "NULL ExprManager is given to ExprValue()"); DebugAssert(em->isKindRegistered(kind), ("ExprValue(kind = " + int2string(kind) + ")): kind is not registered").c_str()); DebugAssert(kind != APPLY, "Only ExprApply should have APPLY kind"); // #ifdef _CVC3_DEBUG_MODE //added by yeting, just hold a place to put my breakpoints in gdb // if(idx != 0){ // TRACE("expr", "expr created ", idx, "");//the line added by yeting // // char * a; // // a="a"; // // a[999999]=255; // } // #endif } //! Destructor virtual ~ExprValue(); //! Get the kind of the expression int getKind() const { return d_kind; } //! Overload operator new void* operator new(size_t size, MemoryManager* mm) { return mm->newData(size); } void operator delete(void* pMem, MemoryManager* mm) { mm->deleteData(pMem); } //! Overload operator delete void operator delete(void*) { } //! Get unique memory manager ID virtual size_t getMMIndex() const { return EXPR_VALUE; } //! Equality between any two ExprValue objects (including subclasses) virtual bool operator==(const ExprValue& ev2) const; // Testers //! Test whether the expression is a generic subclass /*! * \return 0 for the core classes, and getMMIndex() value for * generic subclasses (those defined in DPs) */ virtual const ExprValue* getExprValue() const { throw Exception("Illegal call to getExprValue()"); } //! String expression tester virtual bool isString() const { return false; } //! Rational number expression tester virtual bool isRational() const { return false; } //! Uninterpreted constants virtual bool isVar() const { return false; } //! Application of another expression virtual bool isApply() const { return false; } //! Special named symbol virtual bool isSymbol() const { return false; } //! A LAMBDA-expression or a quantifier virtual bool isClosure() const { return false; } //! Special Expr holding a theorem virtual bool isTheorem() const { return false; } //! Get kids: by default, returns a ref to an empty vector virtual const std::vector& getKids() const { return d_em->getEmptyVector(); } // Methods to access leaf data in subclasses //! Default arity = 0 virtual unsigned arity() const { return 0; } //! Special attributes for uninterpreted functions virtual CDO* getSig() const { DebugAssert(false, "getSig() is called on ExprValue"); return NULL; } virtual CDO* getRep() const { DebugAssert(false, "getRep() is called on ExprValue"); return NULL; } virtual void setSig(CDO* sig) { DebugAssert(false, "setSig() is called on ExprValue"); } virtual void setRep(CDO* rep) { DebugAssert(false, "setRep() is called on ExprValue"); } virtual const std::string& getUid() const { static std::string null; DebugAssert(false, "ExprValue::getUid() called in base class"); return null; } virtual const std::string& getString() const { DebugAssert(false, "getString() is called on ExprValue"); static std::string s(""); return s; } virtual const Rational& getRational() const { DebugAssert(false, "getRational() is called on ExprValue"); static Rational r(0); return r; } //! Returns the string name of UCONST and BOUND_VAR expr's. virtual const std::string& getName() const { static std::string ret = ""; DebugAssert(false, "getName() is called on ExprValue"); return ret; } //! Returns the original Boolean variable (for BoolVarExprValue) virtual const Expr& getVar() const { DebugAssert(false, "getVar() is called on ExprValue"); static Expr null; return null; } //! Get the Op from an Apply Expr virtual Op getOp() const { DebugAssert(false, "getOp() is called on ExprValue"); return Op(NULL_KIND); } virtual const std::vector& getVars() const { DebugAssert(false, "getVars() is called on ExprValue"); static std::vector null; return null; } virtual const Expr& getBody() const { DebugAssert(false, "getBody() is called on ExprValue"); static Expr null; return null; } virtual void setTriggers(const std::vector >& triggers) { DebugAssert(false, "setTriggers() is called on ExprValue"); } virtual const std::vector >& getTriggers() const { //by yeting DebugAssert(false, "getTrigs() is called on ExprValue"); static std::vector > null; return null; } virtual const Expr& getExistential() const { DebugAssert(false, "getExistential() is called on ExprValue"); static Expr null; return null; } virtual int getBoundIndex() const { DebugAssert(false, "getIndex() is called on ExprValue"); return 0; } virtual const std::vector& getFields() const { DebugAssert(false, "getFields() is called on ExprValue"); static std::vector null; return null; } virtual const std::string& getField() const { DebugAssert(false, "getField() is called on ExprValue"); static std::string null; return null; } virtual int getTupleIndex() const { DebugAssert(false, "getTupleIndex() is called on ExprValue"); return 0; } virtual const Theorem& getTheorem() const { static Theorem null; DebugAssert(false, "getTheorem() is called on ExprValue"); return null; } }; // end of class ExprValue // Class ExprNode; it's an expression with children class CVC_DLL ExprNode: public ExprValue { friend class Expr; friend class ExprManager; protected: //! Vector of children std::vector d_children; // Special attributes for helping with congruence closure CDO* d_sig; CDO* d_rep; private: //! Tell ExprManager who we are size_t getMMIndex() const { return EXPR_NODE; } protected: //! Return number of children unsigned arity() const { return d_children.size(); } //! Return reference to children std::vector& getKids1() { return d_children; } //! Return reference to children const std::vector& getKids() const { return d_children; } //! Use our static hash() for the member method size_t computeHash() const { return ExprValue::hash(d_kind, d_children); } //! Use our static sizeWithChildren() for the member method Unsigned computeSize() const { return ExprValue::sizeWithChildren(d_children); } //! Make a clean copy of itself using the given memory manager virtual ExprValue* copy(ExprManager* em, ExprIndex idx = 0) const; public: //! Constructor ExprNode(ExprManager* em, int kind, ExprIndex idx = 0) : ExprValue(em, kind, idx), d_sig(NULL), d_rep(NULL) { } //! Constructor ExprNode(ExprManager* em, int kind, const std::vector& kids, ExprIndex idx = 0) : ExprValue(em, kind, idx), d_children(kids), d_sig(NULL), d_rep(NULL) { } //! Destructor virtual ~ExprNode(); //! Overload operator new void* operator new(size_t size, MemoryManager* mm) { return mm->newData(size); } void operator delete(void* pMem, MemoryManager* mm) { mm->deleteData(pMem); } //! Overload operator delete void operator delete(void*) { } //! Compare with another ExprValue virtual bool operator==(const ExprValue& ev2) const; virtual CDO* getSig() const { return d_sig; } virtual CDO* getRep() const { return d_rep; } virtual void setRep(CDO* rep) { d_rep = rep; } virtual void setSig(CDO* sig) { d_sig = sig; } }; // end of class ExprNode // Class ExprNodeTmp; special version of ExprNode for Expr constructor class ExprNodeTmp: public ExprValue { friend class Expr; friend class ExprManager; protected: //! Vector of children const std::vector& d_children; private: //! Tell ExprManager who we are size_t getMMIndex() const { return EXPR_NODE; } protected: //! Return number of children unsigned arity() const { return d_children.size(); } //! Return reference to children const std::vector& getKids() const { return d_children; } //! Use our static hash() for the member method size_t computeHash() const { return ExprValue::hash(d_kind, d_children); } //! Use our static sizeWithChildren() for the member method Unsigned computeSize() const { return ExprValue::sizeWithChildren(d_children); } //! Make a clean copy of itself using the given memory manager virtual ExprValue* copy(ExprManager* em, ExprIndex idx = 0) const; public: //! Constructor ExprNodeTmp(ExprManager* em, int kind, const std::vector& kids) : ExprValue(em, kind, 0), d_children(kids) { } //! Destructor virtual ~ExprNodeTmp() {} //! Compare with another ExprValue virtual bool operator==(const ExprValue& ev2) const; }; // end of class ExprNodeTmp // Special version for Expr Constructor class ExprApplyTmp: public ExprNodeTmp { friend class Expr; friend class ExprManager; private: Expr d_opExpr; protected: size_t getMMIndex() const { return EXPR_APPLY; } size_t computeHash() const { return PRIME*ExprNodeTmp::computeHash() + d_opExpr.hash(); } Op getOp() const { return Op(d_opExpr); } bool isApply() const { return true; } // Make a clean copy of itself using the given memory manager ExprValue* copy(ExprManager* em, ExprIndex idx = 0) const; public: // Constructor ExprApplyTmp(ExprManager* em, const Op& op, const std::vector& kids) : ExprNodeTmp(em, NULL_KIND, kids), d_opExpr(op.getExpr()) { DebugAssert(!op.getExpr().isNull(), "Expected non-null Op"); d_kind = APPLY; } virtual ~ExprApplyTmp() { } bool operator==(const ExprValue& ev2) const; }; // end of class ExprApply class CVC_DLL ExprApply: public ExprNode { friend class Expr; friend class ExprManager; private: Expr d_opExpr; protected: size_t getMMIndex() const { return EXPR_APPLY; } size_t computeHash() const { return PRIME*ExprNode::computeHash() + d_opExpr.hash(); } Op getOp() const { return Op(d_opExpr); } bool isApply() const { return true; } // Make a clean copy of itself using the given memory manager ExprValue* copy(ExprManager* em, ExprIndex idx = 0) const; public: // Constructor ExprApply(ExprManager* em, const Op& op, ExprIndex idx = 0) : ExprNode(em, NULL_KIND, idx), d_opExpr(op.getExpr()) { DebugAssert(!op.getExpr().isNull(), "Expected non-null Op"); d_kind = APPLY; } ExprApply(ExprManager* em, const Op& op, const std::vector& kids, ExprIndex idx = 0) : ExprNode(em, NULL_KIND, kids, idx), d_opExpr(op.getExpr()) { DebugAssert(!op.getExpr().isNull(), "Expected non-null Op"); d_kind = APPLY; } virtual ~ExprApply() { } bool operator==(const ExprValue& ev2) const; // Memory management void* operator new(size_t size, MemoryManager* mm) { return mm->newData(size); } void operator delete(void* pMem, MemoryManager* mm) { mm->deleteData(pMem); } void operator delete(void*) { } }; // end of class ExprApply /*****************************************************************************/ /*! *\class NamedExprValue *\brief NamedExprValue * * Author: Clark Barrett * * Created: Thu Dec 2 23:18:17 2004 * * Subclass of ExprValue for kinds that have a name associated with them. */ /*****************************************************************************/ // class NamedExprValue : public ExprNode { // friend class Expr; // friend class ExprManager; // private: // std::string d_name; // protected: // ExprValue* copy(ExprManager* em, ExprIndex idx = 0) const { // return new(em->getMM(getMMIndex())) // NamedExprValue(d_em, d_kind, d_name, d_children, idx); // } // ExprValue* copy(ExprManager* em, const std::vector& kids, // ExprIndex idx = 0) const { // return new(em->getMM(getMMIndex())) // NamedExprValue(d_em, d_kind, d_name, kids, idx); // } // size_t computeHash() const { // return s_charHash(d_name.c_str())*PRIME + ExprNode::computeHash(); // } // size_t getMMIndex() const { return EXPR_NAMED; } // public: // // Constructor // NamedExprValue(ExprManager *em, int kind, const std::string& name, // const std::vector& kids, ExprIndex idx = 0) // : ExprNode(em, kind, kids, idx), d_name(name) { } // // virtual ~NamedExprValue(); // bool operator==(const ExprValue& ev2) const { // if(getMMIndex() != ev2.getMMIndex()) return false; // return (getName() == ev2.getName()) // && ExprNode::operator==(ev2); // } // const std::string& getName() const { return d_name; } // // Memory management // void* operator new(size_t size, MemoryManager* mm) { // return mm->newData(size); // } // void operator delete(void*) { } // }; // end of class NamedExprValue // Leaf expressions class ExprString: public ExprValue { friend class Expr; friend class ExprManager; private: std::string d_str; // Hash function for this subclass static size_t hash(const std::string& str) { return s_charHash(str.c_str()); } // Tell ExprManager who we are virtual size_t getMMIndex() const { return EXPR_STRING; } protected: // Use our static hash() for the member method virtual size_t computeHash() const { return hash(d_str); } virtual bool isString() const { return true; } virtual const std::string& getString() const { return d_str; } //! Make a clean copy of itself using the given memory manager virtual ExprValue* copy(ExprManager* em, ExprIndex idx = 0) const; public: // Constructor ExprString(ExprManager* em, const std::string& s, ExprIndex idx = 0) : ExprValue(em, STRING_EXPR, idx), d_str(s) { } // Destructor virtual ~ExprString() { } virtual bool operator==(const ExprValue& ev2) const; // Memory management void* operator new(size_t size, MemoryManager* mm) { return mm->newData(size); } void operator delete(void* pMem, MemoryManager* mm) { mm->deleteData(pMem); } void operator delete(void*) { } }; // end of class ExprString class ExprSkolem: public ExprValue { friend class Expr; friend class ExprManager; private: Expr d_quant; //!< The quantified expression to skolemize int d_idx; //!< Variable index in the quantified expression const Expr& getExistential() const {return d_quant;} int getBoundIndex() const {return d_idx;} // Tell ExprManager who we are size_t getMMIndex() const { return EXPR_SKOLEM;} protected: size_t computeHash() const { size_t res = getExistential().getBody().hash(); res = PRIME*res + getBoundIndex(); return res; } bool operator==(const ExprValue& ev2) const; //! Make a clean copy of itself using the given memory manager ExprValue* copy(ExprManager* em, ExprIndex idx = 0) const; bool isVar() const { return true; } public: // Constructor ExprSkolem(ExprManager* em, int index, const Expr& exist, ExprIndex idx = 0) : ExprValue(em, SKOLEM_VAR, idx), d_quant(exist), d_idx(index) { } // Destructor virtual ~ExprSkolem() { } // Memory management void* operator new(size_t size, MemoryManager* mm) { return mm->newData(size); } void operator delete(void* pMem, MemoryManager* mm) { mm->deleteData(pMem); } void operator delete(void*) { } }; // end of class ExprSkolem class ExprRational: public ExprValue { friend class Expr; friend class ExprManager; private: Rational d_r; virtual const Rational& getRational() const { return d_r; } // Hash function for this subclass static size_t hash(const Rational& r) { return s_charHash(r.toString().c_str()); } // Tell ExprManager who we are virtual size_t getMMIndex() const { return EXPR_RATIONAL; } protected: virtual size_t computeHash() const { return hash(d_r); } virtual bool operator==(const ExprValue& ev2) const; //! Make a clean copy of itself using the given memory manager virtual ExprValue* copy(ExprManager* em, ExprIndex idx = 0) const; virtual bool isRational() const { return true; } public: // Constructor ExprRational(ExprManager* em, const Rational& r, ExprIndex idx = 0) : ExprValue(em, RATIONAL_EXPR, idx), d_r(r) { } // Destructor virtual ~ExprRational() { } // Memory management void* operator new(size_t size, MemoryManager* mm) { return mm->newData(size); } void operator delete(void* pMem, MemoryManager* mm) { mm->deleteData(pMem); } void operator delete(void*) { } }; // end of class ExprRational // Uninterpreted constants (variables) class ExprVar: public ExprValue { friend class Expr; friend class ExprManager; private: std::string d_name; virtual const std::string& getName() const { return d_name; } // Tell ExprManager who we are virtual size_t getMMIndex() const { return EXPR_UCONST; } protected: virtual size_t computeHash() const { return s_charHash(d_name.c_str()); } virtual bool isVar() const { return true; } //! Make a clean copy of itself using the given memory manager virtual ExprValue* copy(ExprManager* em, ExprIndex idx = 0) const; public: // Constructor ExprVar(ExprManager *em, const std::string& name, ExprIndex idx = 0) : ExprValue(em, UCONST, idx), d_name(name) { } // Destructor virtual ~ExprVar() { } virtual bool operator==(const ExprValue& ev2) const; // Memory management void* operator new(size_t size, MemoryManager* mm) { return mm->newData(size); } void operator delete(void* pMem, MemoryManager* mm) { mm->deleteData(pMem); } void operator delete(void*) { } }; // end of class ExprVar // Interpreted symbols: similar to UCONST, but returns false for isVar(). class ExprSymbol: public ExprValue { friend class Expr; friend class ExprManager; private: std::string d_name; virtual const std::string& getName() const { return d_name; } // Tell ExprManager who we are virtual size_t getMMIndex() const { return EXPR_SYMBOL; } protected: virtual size_t computeHash() const { return s_charHash(d_name.c_str())*PRIME + s_intHash(d_kind); } //! Make a clean copy of itself using the given memory manager virtual ExprValue* copy(ExprManager* em, ExprIndex idx = 0) const; bool isSymbol() const { return true; } public: // Constructor ExprSymbol(ExprManager *em, int kind, const std::string& name, ExprIndex idx = 0) : ExprValue(em, kind, idx), d_name(name) { } // Destructor virtual ~ExprSymbol() { } virtual bool operator==(const ExprValue& ev2) const; // Memory management void* operator new(size_t size, MemoryManager* mm) { return mm->newData(size); } void operator delete(void* pMem, MemoryManager* mm) { mm->deleteData(pMem); } void operator delete(void*) { } }; // end of class ExprSymbol class ExprBoundVar: public ExprValue { friend class Expr; friend class ExprManager; private: std::string d_name; std::string d_uid; virtual const std::string& getName() const { return d_name; } virtual const std::string& getUid() const { return d_uid; } // Tell ExprManager who we are virtual size_t getMMIndex() const { return EXPR_BOUND_VAR; } protected: virtual size_t computeHash() const { return s_charHash(d_name.c_str())*PRIME + s_charHash(d_uid.c_str()); } virtual bool isVar() const { return true; } //! Make a clean copy of itself using the given memory manager virtual ExprValue* copy(ExprManager* em, ExprIndex idx = 0) const; public: // Constructor ExprBoundVar(ExprManager *em, const std::string& name, const std::string& uid, ExprIndex idx = 0) : ExprValue(em, BOUND_VAR, idx), d_name(name), d_uid(uid) { } // Destructor virtual ~ExprBoundVar() { } virtual bool operator==(const ExprValue& ev2) const; // Memory management void* operator new(size_t size, MemoryManager* mm) { return mm->newData(size); } void operator delete(void* pMem, MemoryManager* mm) { mm->deleteData(pMem); } void operator delete(void*) { } }; // end of class ExprBoundVar /*! @brief A "closure" expression which binds variables used in the "body". Used by LAMBDA and quantifiers. */ class ExprClosure: public ExprValue { friend class Expr; friend class ExprManager; private: //! Bound variables std::vector d_vars; //! The body of the quantifier/lambda Expr d_body; //! Manual triggers. // added by yeting // Note that due to expr caching, only the most recent triggers specified for a given formula will be used. std::vector > d_manual_triggers; //! Tell ExprManager who we are virtual size_t getMMIndex() const { return EXPR_CLOSURE; } virtual const std::vector& getVars() const { return d_vars; } virtual const Expr& getBody() const { return d_body; } virtual void setTriggers(const std::vector >& triggers) { d_manual_triggers = triggers; } virtual const std::vector >& getTriggers() const { return d_manual_triggers; } protected: size_t computeHash() const; Unsigned computeSize() const { return d_body.d_expr->getSize() + 1; } //! Make a clean copy of itself using the given memory manager ExprValue* copy(ExprManager* em, ExprIndex idx = 0) const; public: // Constructor ExprClosure(ExprManager *em, int kind, const Expr& var, const Expr& body, ExprIndex idx = 0) : ExprValue(em, kind, idx), d_body(body) { d_vars.push_back(var); } ExprClosure(ExprManager *em, int kind, const std::vector& vars, const Expr& body, ExprIndex idx = 0) : ExprValue(em, kind, idx), d_vars(vars), d_body(body) { } ExprClosure(ExprManager *em, int kind, const std::vector& vars, const Expr& body, const std::vector >& trigs, ExprIndex idx = 0) : ExprValue(em, kind, idx), d_vars(vars), d_body(body), d_manual_triggers(trigs) { } // Destructor virtual ~ExprClosure() { } bool operator==(const ExprValue& ev2) const; // Memory management void* operator new(size_t size, MemoryManager* mm) { return mm->newData(size); } void operator delete(void* pMem, MemoryManager* mm) { mm->deleteData(pMem); } void operator delete(void*) { } virtual bool isClosure() const { return true; } }; // end of class ExprClosure } // end of namespace CVC3 #endif cvc3-2.4.1/src/include/search_sat.h0000664000175400017540000002537411224465537017001 0ustar mdetersmdeters/*****************************************************************************/ /*! *\file search_sat.h *\brief Search engine that uses an external SAT engine * * Author: Clark Barrett * * Created: Mon Dec 5 17:52:05 2005 * *
* * License to use, copy, modify, sell and/or distribute this software * and its documentation for any purpose is hereby granted without * royalty, subject to the terms and conditions defined in the \ref * LICENSE file provided with this distribution. * *
* */ /*****************************************************************************/ #ifndef _cvc3__include__search_sat_h_ #define _cvc3__include__search_sat_h_ #include #include #include "search.h" #include "smartcdo.h" #include "cdlist.h" #include "cnf_manager.h" #include "expr.h" #include "dpllt.h" #include "theory_core.h" #include "formula_value.h" namespace CVC3 { //! Search engine that connects to a generic SAT reasoning module /*! \ingroup SE */ class SearchSat :public SearchEngine { //! Name of search engine std::string d_name; //! Bottom scope for current query CDO d_bottomScope; //! Last expr checked for validity CDO d_lastCheck; /*! @brief Theorem from the last successful checkValid call. It is used by getProof and getAssumptions. */ CDO d_lastValid; //! List of all user assumptions CDList d_userAssumptions; //! List of all internal assumptions CDList d_intAssumptions; //! Index to where unprocessed assumptions start CDO d_idxUserAssump; TheoryCore::CoreSatAPI* d_coreSatAPI; //! Pointer to DPLLT implementation SAT::DPLLT* d_dpllt; //! Implementation of TheoryAPI for DPLLT SAT::DPLLT::TheoryAPI* d_theoryAPI; //! Implementation of Decider for DPLLT SAT::DPLLT::Decider* d_decider; //! Store of theorems for expressions sent to DPLLT CDMap d_theorems; //! Manages CNF formula and its relationship to original Exprs and Theorems SAT::CNF_Manager *d_cnfManager; //! Callback for CNF_Manager SAT::CNF_Manager::CNFCallback *d_cnfCallback; //! Cached values of variables std::vector d_vars; //! Whether we are currently in a call to dpllt->checkSat bool d_inCheckSat; //! CNF Formula used for theory lemmas SAT::CD_CNF_Formula d_lemmas; //! Lemmas waiting to be translated since last call to getNewClauses() std::vector > d_pendingLemmas; //! Scope parameter for lemmas waiting to be translated since last call to getNewClauses() std::vector d_pendingScopes; //! Backtracking size of d_pendingLemmas CDO d_pendingLemmasSize; //! Backtracking next item in d_pendingLemmas CDO d_pendingLemmasNext; //! Current position in d_lemmas CDO d_lemmasNext; //! List for backtracking var values std::vector d_varsUndoList; //! Backtracking size of d_varsUndoList CDO d_varsUndoListSize; public: //! Pair of Lit and priority of this Lit class LitPriorityPair { SAT::Lit d_lit; int d_priority; LitPriorityPair() {} public: LitPriorityPair(SAT::Lit lit, int priority) : d_lit(lit), d_priority(priority) {} SAT::Lit getLit() const { return d_lit; } int getPriority() const { return d_priority; } friend bool operator<(const LitPriorityPair& p1, const LitPriorityPair& p2); }; private: //! Used to determine order to find splitters std::set d_prioritySet; //! Current position in prioritySet CDO::const_iterator> d_prioritySetStart; //! Backtracking size of priority set entries CDO d_prioritySetEntriesSize; //! Entries in priority set in insertion order (so set can be backtracked) std::vector::iterator> d_prioritySetEntries; //! Backtracking size of priority set entries at bottom scope std::vector d_prioritySetBottomEntriesSizeStack; //! Current size of bottom entries unsigned d_prioritySetBottomEntriesSize; //! Entries in priority set in insertion order (so set can be backtracked) std::vector::iterator> d_prioritySetBottomEntries; //! Last Var registered with core theory CDO d_lastRegisteredVar; //! Whether it's OK to call DPLLT solver from the current scope CDO d_dplltReady; CDO d_nextImpliedLiteral; //! Helper class for resetting DPLLT engine /*! We need to be notified when the scope goes below the scope from * which the last invalid call to checkValid originated. This helper class * ensures that this happens. */ friend class Restorer; class Restorer :public ContextNotifyObj { SearchSat* d_ss; public: Restorer(Context* context, SearchSat* ss) : ContextNotifyObj(context), d_ss(ss) {} void notifyPre() { d_ss->restorePre(); } void notify() { d_ss->restore(); } }; //! Instance of Restorer class Restorer d_restorer; private: //! Get rid of bottom scope entries in prioritySet void restorePre(); //! Get rid of entries in prioritySet and pendingLemmas added since last push void restore(); //! Helper for addLemma and check bool recordNewRootLit(SAT::Lit lit, int priority = 0, bool atBottomScope = false); friend class SearchSatCoreSatAPI; friend class SearchSatCNFCallback; //! Core theory callback which adds a new lemma from the core theory void addLemma(const Theorem& thm, int priority = 0, bool atBotomScope = false); //! Core theory callback which asks for the bottom scope for current query int getBottomScope() { return d_bottomScope; } //! Core theory callback which suggests a splitter void addSplitter(const Expr& e, int priority); friend class SearchSatTheoryAPI; //! DPLLT callback to inform theory that a literal has been assigned void assertLit(SAT::Lit l); //! DPLLT callback to ask if theory has detected inconsistency. SAT::DPLLT::ConsistentResult checkConsistent(SAT::CNF_Formula& cnf, bool fullEffort); //! DPLLT callback to get theory propagations. SAT::Lit getImplication(); //! DPLLT callback to explain a theory propagation. void getExplanation(SAT::Lit l, SAT::CNF_Formula& cnf); //! DPLLT callback to get more general theory clauses. bool getNewClauses(SAT::CNF_Formula& cnf); friend class SearchSatDecider; //! DPLLT callback to decide which literal to split on next SAT::Lit makeDecision(); //! Recursively traverse DAG looking for a splitter /*! Returns true if a splitter is found, false otherwise. The splitter is * returned in lit (lit should be set to true). Nodes whose current value is * fully justified are marked by calling setFlag to avoid searching them in * the future. */ bool findSplitterRec(SAT::Lit lit, SAT::Var::Val value, SAT::Lit* litDecision); //! Get the value of a CNF Literal SAT::Var::Val getValue(SAT::Lit c) { DebugAssert(!c.isNull() && (!c.isVar() || unsigned(c.getVar()) < d_vars.size()), "Lit out of bounds in getValue"); return c.isPositive() ? d_vars[c.getVar()] : c.isInverted() ? SAT::Var::invertValue(d_vars[c.getVar()]) : c.isTrue() ? SAT::Var::TRUE_VAL : SAT::Var::FALSE_VAL; } SAT::Var::Val getValue(SAT::Var v) { DebugAssert(v.isVar() && unsigned(v) < d_vars.size(), "Var out of bounds in getValue"); return d_vars[v]; } //! Set the value of a variable void setValue(SAT::Var v, SAT::Var::Val val) { DebugAssert(!v.isNull(), "expected non-null Var"); DebugAssert(unsigned(v) < d_vars.size(), "Var out of bounds in getValue"); DebugAssert(d_vars[v] == SAT::Var::UNKNOWN, "Expected unknown"); DebugAssert(val != SAT::Var::UNKNOWN, "Expected set to non-unknown"); d_vars[v] = val; DebugAssert(d_varsUndoListSize == d_varsUndoList.size(), "Size mismatch"); d_varsUndoList.push_back(unsigned(v)); d_varsUndoListSize = d_varsUndoListSize + 1; } //! Check whether this variable's value is justified bool checkJustified(SAT::Var v) { return d_cnfManager->concreteLit(SAT::Lit(v)).isJustified(); } //! Mark this variable as justified void setJustified(SAT::Var v) { d_cnfManager->concreteLit(SAT::Lit(v)).setJustified(); } //! Main checking procedure shared by checkValid and restart QueryResult check(const Expr& e, Theorem& result, bool isRestart = false); //! Helper for newUserAssumptionInt void newUserAssumptionIntHelper(const Theorem& thm, SAT::CNF_Formula_Impl& cnf, bool atBottomScope); //! Helper for newUserAssumption Theorem newUserAssumptionInt(const Expr& e, SAT::CNF_Formula_Impl& cnf, bool atBottomScope); public: //! Constructor //! name is the name of the dpllt engine to use, as returned by getName() SearchSat(TheoryCore* core, const std::string& name); //! Destructor virtual ~SearchSat(); // Implementation of virtual SearchEngine methods virtual const std::string& getName() { return d_name; } virtual void registerAtom(const Expr& e); virtual Theorem getImpliedLiteral(); virtual void push() { d_dpllt->push(); } virtual void pop() { d_dpllt->pop(); } virtual QueryResult checkValid(const Expr& e, Theorem& result) { return check(e, result); } virtual QueryResult restart(const Expr& e, Theorem& result) { return check(e, result, true); } virtual void returnFromCheck(); virtual Theorem lastThm() { return d_lastValid; } virtual Theorem newUserAssumption(const Expr& e); virtual void getUserAssumptions(std::vector& assumptions); virtual void getInternalAssumptions(std::vector& assumptions); virtual void getAssumptions(std::vector& assumptions); virtual bool isAssumption(const Expr& e); virtual void getCounterExample(std::vector& assertions, bool inOrder = true); virtual Proof getProof(); //:ALEX: virtual FormulaValue getValue(const CVC3::Expr& e) { SAT::Lit l = d_cnfManager->getCNFLit(e); if (l.isNull()) { //:DEBUG: std::cout << "No lit for expr: " << e.toString() << std::endl; FatalAssert(false, "getValue"); return UNKNOWN_VAL; } else { switch (getValue(l)) { case SAT::Var::TRUE_VAL: return TRUE_VAL; case SAT::Var::FALSE_VAL: return FALSE_VAL; case SAT::Var::UNKNOWN: return UNKNOWN_VAL; default: DebugAssert(false, "unreachable"); return UNKNOWN_VAL; } } } }; inline bool operator<(const SearchSat::LitPriorityPair& p1, const SearchSat::LitPriorityPair& p2) { if (p1.d_priority > p2.d_priority) return true; if (p1.d_priority < p2.d_priority) return false; return abs(p1.d_lit.getID()) < abs(p2.d_lit.getID()) || (abs(p1.d_lit.getID()) == abs(p2.d_lit.getID()) && p1.d_lit.getID() > 0 && (!(p2.d_lit.getID() > 0))); } } #endif cvc3-2.4.1/src/include/search_impl_base.h0000664000175400017540000002547211070741375020140 0ustar mdetersmdeters/*****************************************************************************/ /*! * \file search_impl_base.h * \brief Abstract API to the proof search engine * * Author: Clark Barrett, Vijay Ganesh (Clausal Normal Form Converter) * * Created: Fri Jan 17 13:35:03 2003 * *
* * License to use, copy, modify, sell and/or distribute this software * and its documentation for any purpose is hereby granted without * royalty, subject to the terms and conditions defined in the \ref * LICENSE file provided with this distribution. * *
* */ /*****************************************************************************/ #ifndef _cvc3__include__search_impl_base_h_ #define _cvc3__include__search_impl_base_h_ #include "search.h" #include "theory_core.h" #include "variable.h" #include "formula_value.h" namespace CVC3 { class SearchEngineRules; class VariableManager; //! API to to a generic proof search engine (a.k.a. SAT solver) /*! \ingroup SE */ class SearchImplBase :public SearchEngine { friend class DecisionEngine; protected: /*! \addtogroup SE * @{ */ //! Variable manager for classes Variable and Literal VariableManager* d_vm; /*! @brief The bottom-most scope for the current call to checkSAT (where conflict clauses are still valid). */ CDO d_bottomScope; TheoryCore::CoreSatAPI* d_coreSatAPI_implBase; //! Representation of a DP-suggested splitter class Splitter { Literal d_lit; public: // int priority; //! Constructor Splitter(const Literal& lit); //! Copy constructor Splitter(const Splitter& s); //! Assignment Splitter& operator=(const Splitter& s); //! Descructor ~Splitter(); operator Literal() { return d_lit; } //! The order is descending by priority ("reversed", highest first) // friend bool operator<(const Splitter& s1, const Splitter& s2) { // return (s1.priority > s2.priority // || (s1.priority == s2.priority && s1.expr > s2.expr)); // } }; //! Backtracking ordered set of DP-suggested splitters CDList d_dpSplitters; /*! @brief Theorem from the last successful checkValid call. It is used by getProof and getAssumptions. */ Theorem d_lastValid; /*! @brief Assumptions from the last unsuccessful checkValid call. These are used by getCounterExample. */ ExprHashMap d_lastCounterExample; /*! @brief Maintain the list of current assumptions (user asserts and splitters) for getAssumptions(). */ CDMap d_assumptions; //! Backtracking cache for the CNF generator CDMap d_cnfCache; //! Backtracking set of new variables generated by CNF translator /*! Specific search engines do not have to split on these variables */ CDMap d_cnfVars; //! Command line flag whether to convert to CNF const bool* d_cnfOption; //! Flag: whether to convert term ITEs into CNF const bool* d_ifLiftOption; //! Flag: ignore auxiliary CNF variables when searching for a splitter const bool* d_ignoreCnfVarsOption; //! Flag: Preserve the original formula with +cnf (for splitter heuristics) const bool* d_origFormulaOption; /*! * \name CNF Caches * * These caches are for subexpressions of the translated formula * phi, to avoid expanding phi into a tree. We cannot use * d_cnfCache for that, since it is effectively non-backtracking, * and we do not know if a subexpression of phi was translated at * the current level, or at some other (inactive) branch of the * decision tree. * @{ */ //! Cache for enqueueCNF() CDMap d_enqueueCNFCache; //! Cache for applyCNFRules() CDMap d_applyCNFRulesCache; //! Cache for replaceITE() CDMap d_replaceITECache; /*@}*/ // End of CNF Caches //! Construct a Literal out of an Expr or return an existing one Literal newLiteral(const Expr& e) { return Literal(d_vm, e); } /*! @brief Our version of simplifier: take Theorem(e), apply simplifier to get Theorem(e==e'), return Theorem(e') */ Theorem simplify(const Theorem& e) { return d_core->iffMP(e, d_core->simplify(e.getExpr())); } //! Notify the search engine about a new literal fact. /*! It should be called by SearchEngine::addFact() only. * Must be implemented by the subclasses of SearchEngine. * * IMPORTANT: do not call addFact() from this function; use * enqueueFact() or setInconsistent() instead. */ virtual void addLiteralFact(const Theorem& thm) = 0; //! Notify the search engine about a new non-literal fact. /*! It should be called by SearchEngine::addFact() only. * Must be implemented by the subclasses of SearchEngine. * * IMPORTANT: do not call addFact() from this function; use * enqueueFact() or setInconsistent() instead. */ virtual void addNonLiteralFact(const Theorem& thm) = 0; //! Add a new fact to the search engine bypassing CNF converter /*! Calls either addLiteralFact() or addNonLiteralFact() * appropriately, and converts to CNF when d_cnfOption is set. If * fromCore==true, this fact already comes from the core, and * doesn't need to be reported back to the core. */ void addCNFFact(const Theorem& thm, bool fromCore=false); public: int getBottomScope() { return d_bottomScope; } //! Check if e is a clause (a literal, or a disjunction of literals) bool isClause(const Expr& e); //! Check if e is a propositional clause /*! \sa isPropAtom() */ bool isPropClause(const Expr& e); //! Check whether e is a fresh variable introduced by the CNF converter /*! Search engines do not need to split on those variables in order * to be complete */ bool isCNFVar(const Expr& e) { return (d_cnfVars.count(e) > 0); } //! Check if a splitter is required for completeness /*! Currently, it checks that 'e' is not an auxiliary CNF variable */ bool isGoodSplitter(const Expr& e); private: //! Translate theta to CNF and enqueue the new clauses void enqueueCNF(const Theorem& theta); //! Recursive version of enqueueCNF() void enqueueCNFrec(const Theorem& theta); //! FIXME: write a comment void applyCNFRules(const Theorem& e); //! Cache a theorem phi <=> v by phi, where v is a literal. void addToCNFCache(const Theorem& thm); //! Find a theorem phi <=> v by phi, where v is a literal. /*! \return Null Theorem if not found. */ Theorem findInCNFCache(const Expr& e); //! Replaces ITE subexpressions in e with variables Theorem replaceITE(const Expr& e); protected: //! Return the current scope level (for convenience) int scopeLevel() { return d_core->getCM()->scopeLevel(); } public: //! Constructor SearchImplBase(TheoryCore* core); //! Destructor virtual ~SearchImplBase(); virtual void registerAtom(const Expr& e) { d_core->theoryOf(e)->registerAtom(e, Theorem()); } virtual Theorem getImpliedLiteral() { return d_core->getImpliedLiteral(); } virtual void push() { d_core->getCM()->push(); } virtual void pop() { d_core->getCM()->pop(); } /////////////////////////////////////////////////////////////////////////// // checkValid() is the method that subclasses must implement. /////////////////////////////////////////////////////////////////////////// //! Checks the validity of a formula in the current context /*! The method that actually calls the SAT solver (implemented in a subclass). It should maintain d_assumptions (add all asserted splitters to it), and set d_lastValid and d_lastCounterExample appropriately before exiting. */ virtual QueryResult checkValidInternal(const Expr& e) = 0; //! Similar to checkValidInternal(), only returns Theorem(e) or Null virtual QueryResult checkValid(const Expr& e, Theorem& result); //! Reruns last check with e as an additional assumption virtual QueryResult restartInternal(const Expr& e) = 0; //! Reruns last check with e as an additional assumption virtual QueryResult restart(const Expr& e, Theorem& result); void returnFromCheck() { Theorem thm; restart(d_core->falseExpr(), thm); } virtual Theorem lastThm() { return d_lastValid; } /////////////////////////////////////////////////////////////////////////// // The following methods are provided by the base class, and in most // cases should be sufficient. However, they are virtual so that // subclasses can add functionality to them if needed. /////////////////////////////////////////////////////////////////////////// /*! @brief Generate and add a new assertion to the set of assertions in the current context. This should only be used by class VCL in assertFormula(). */ Theorem newUserAssumption(const Expr& e); //! Add a new internal asserion virtual Theorem newIntAssumption(const Expr& e); //! Helper for above function void newIntAssumption(const Theorem& thm); //! Get all assumptions made in this and all previous contexts. /*! \param assumptions should be an empty vector which will be filled \ with the assumptions */ void getUserAssumptions(std::vector& assumptions); void getInternalAssumptions(std::vector& assumptions); virtual void getAssumptions(std::vector& assumptions); //! Check if the formula has been assumed virtual bool isAssumption(const Expr& e); //! Add a new fact to the search engine from the core /*! It should be called by TheoryCore::assertFactCore(). */ void addFact(const Theorem& thm); //! Suggest a splitter to the SearchEngine /*! The higher is the priority, the sooner the SAT solver will split * on it. It can be positive or negative (default is 0). * * The set of suggested splitters is backtracking; that is, a * splitter is "forgotten" once the scope is backtracked. * * This method can be used either to change the priority * of existing splitters, or to introduce new splitters that DPs * consider relevant, even though they do not appear in existing * formulas. */ virtual void addSplitter(const Expr& e, int priority); virtual void getCounterExample(std::vector& assertions, bool inOrder = true); // The following two methods should be called only after a checkValid // which returns true. In any other case, they return Null values. //! Returns the proof term for the last proven query /*! It should be called only after a checkValid which returns true. In any other case, it returns Null. */ virtual Proof getProof(); /*! @brief Returns the set of assumptions used in the proof. It should be a subset of getAssumptions(). */ /*! It should be called only after a checkValid which returns true. In any other case, it returns Null. */ virtual const Assumptions& getAssumptionsUsed(); //! Process result of checkValid void processResult(const Theorem& res, const Expr& e); //:ALEX: inline virtual FormulaValue getValue(const CVC3::Expr& e) { FatalAssert(false, "not implemented"); return UNKNOWN_VAL; } /* @} */ // end of group SE }; } #endif cvc3-2.4.1/src/include/vc_cmd.h0000664000175400017540000000350411154015777016106 0ustar mdetersmdeters/*****************************************************************************/ /*! * \file vc_cmd.h * * Author: Clark Barrett * * Created: Fri Dec 13 22:35:15 2002 * *
* * License to use, copy, modify, sell and/or distribute this software * and its documentation for any purpose is hereby granted without * royalty, subject to the terms and conditions defined in the \ref * LICENSE file provided with this distribution. * *
* */ /*****************************************************************************/ #ifndef _cvc3__vc_cvc__vc_cmd_h_ #define _cvc3__vc_cvc__vc_cmd_h_ #include #include "compat_hash_map.h" #include "exception.h" #include "queryresult.h" namespace CVC3 { class ValidityChecker; class Parser; class Context; class Expr; template class ExprMap; class VCCmd { ValidityChecker* d_vc; Parser* d_parser; // TODO: move state variables into validity checker. typedef std::hash_map CtxtMap; std::string d_name_of_cur_ctxt; CtxtMap d_map; bool d_calledFromParser; //! Print the symbols in e, cache results void printSymbols(Expr e, ExprMap& cache); //! Take a parsed Expr and evaluate it bool evaluateCommand(const Expr& e); // Fetch the next command and evaluate it. Return true if // evaluation was successful, false otherwise. In especially bad // cases an exception may be thrown. bool evaluateNext(); void findAxioms(const Expr& e, ExprMap& skolemAxioms, ExprMap& visited); Expr skolemizeAx(const Expr& e); void reportResult(QueryResult qres, bool checkingValidity = true); void printModel(); void printCounterExample(); public: VCCmd(ValidityChecker* vc, Parser* parser, bool calledFromParser=false); ~VCCmd(); // Main loop function void processCommands(); }; } #endif cvc3-2.4.1/src/include/theorem_producer.h0000664000175400017540000002025211103725115020204 0ustar mdetersmdeters/*****************************************************************************/ /*! * \file theorem_producer.h * * Author: Sergey Berezin * * Created: Dec 10 00:37:49 GMT 2002 * *
* * License to use, copy, modify, sell and/or distribute this software * and its documentation for any purpose is hereby granted without * royalty, subject to the terms and conditions defined in the \ref * LICENSE file provided with this distribution. * *
* */ /*****************************************************************************/ // CLASS: Theorem_Producer // // AUTHOR: Sergey Berezin, 07/05/02 // // Abstract: // // This class is the only one that can create new Theorem classes. // // Only TRUSTED code can use it; a symbol _CVC3_TRUSTED_ must be // defined in *.cpp file before including this one; otherwise you'll // get a compiler warning. Custom header files (*.h) which include // this file should NOT define _CVC3_TRUSTED_. This practice enforces // the programmer to be aware of which part of his/her code is // trusted. // // It defines a protected NON-virtual method newTheorem() so that any // subclass can create a new Theorem. This means that no untrusted // decision procedure's code should see this interface. // Unfortunately, this has to be a coding policy rather than something // we can enforce by C++ class structure. // // The intended use of this class is to make a subclass and define new // methods corresponding to proof rules (they take theorems and // generate new theorems). Each decision procedure should have such a // subclass for its trusted core. Each new proof rule must be sound; // that is, each new theorem that it generates must logically follow // from the theorems in the arguments, or the new theorem must be a // tautology. // // Each such subclass must also inherit from a decision // procedure-specific abstract interface which declares the new // methods (other than newTheorem). The decision procedure should only // use the new abstract interface. Thus, the DP will not even see // newTheorem() method. // // This way the untrusted part of the code will not be able to create // an unsound theorem. // // Proof rules may expect theorems in the arguments be of a certain // form; if the expectations are not met, the right thing to do is to // fail in DebugAssert with the appropriate message. In other words, // it is a coding bug to pass wrong theorems to the wrong rules. // // It is also a bug if a wrong theorem is passed but not detected by // the proof rule, unless such checks are explicitly turned off // globally for efficiency. //////////////////////////////////////////////////////////////////////// #ifndef _CVC3_TRUSTED_ #warning "This file should be included only by TRUSTED code. Define _CVC3_TRUSTED_ before including this file." #endif #ifndef _cvc3__theorem_producer_h_ #define _cvc3__theorem_producer_h_ #include "assumptions.h" #include "theorem_manager.h" #include "exception.h" // Macro to check for soundness. It should only be executed within a // TheoremProducer class, and only if the -check-proofs option is set. // When its 'cond' is violated, it will call a function which will // eventually throw a soundness exception. #define CHECK_SOUND(cond, msg) { if(!(cond)) \ soundError(__FILE__, __LINE__, #cond, msg); } // Flag whether to check soundness or not #define CHECK_PROOFS *d_checkProofs namespace CVC3 { class TheoremProducer { protected: TheoremManager* d_tm; ExprManager* d_em; // Command-line option whether to check for soundness const bool* d_checkProofs; // Operator for creating proof terms Op d_pfOp; // Expr for filling in "condition" arguments in flea proofs Expr d_hole; // Make it possible for the subclasses to create theorems directly. //! Create a new theorem. See also newRWTheorem() and newReflTheorem() Theorem newTheorem(const Expr& thm, const Assumptions& assump, const Proof& pf) { IF_DEBUG(if(!thm.isEq() && !thm.isIff()) { TRACE("newTheorem", "newTheorem(", thm, ")"); debugger.counter("newTheorem() called on equality")++; }) return Theorem(d_tm, thm, assump, pf); } //! Create a rewrite theorem: lhs = rhs Theorem newRWTheorem(const Expr& lhs, const Expr& rhs, const Assumptions& assump, const Proof& pf) { return Theorem(d_tm, lhs, rhs, assump, pf); } //! Create a reflexivity theorem Theorem newReflTheorem(const Expr& e) { return Theorem(e); } Theorem newAssumption(const Expr& thm, const Proof& pf, int scope = -1) { return Theorem(d_tm, thm, Assumptions::emptyAssump(), pf, true, scope); } Theorem3 newTheorem3(const Expr& thm, const Assumptions& assump, const Proof& pf) { IF_DEBUG(if(!thm.isEq() && !thm.isIff()) { TRACE("newTheorem", "newTheorem3(", thm, ")"); debugger.counter("newTheorem3() called on equality")++; }) return Theorem3(d_tm, thm, assump, pf); } Theorem3 newRWTheorem3(const Expr& lhs, const Expr& rhs, const Assumptions& assump, const Proof& pf) { return Theorem3(d_tm, lhs, rhs, assump, pf); } void soundError(const std::string& file, int line, const std::string& cond, const std::string& msg); public: // Constructor TheoremProducer(TheoremManager *tm); // Destructor virtual ~TheoremProducer() { } //! Testing whether to generate proofs bool withProof() { return d_tm->withProof(); } //! Testing whether to generate assumptions bool withAssumptions() { return d_tm->withAssumptions(); } //! Create a new proof label (bound variable) for an assumption (formula) Proof newLabel(const Expr& e); ////////////////////////////////////////////////////////////////// // Functions to create proof terms ////////////////////////////////////////////////////////////////// // Apply a rule named 'name' to its arguments, Proofs or Exprs Proof newPf(const std::string& name); Proof newPf(const std::string& name, const Expr& e); Proof newPf(const std::string& name, const Proof& pf); Proof newPf(const std::string& name, const Expr& e1, const Expr& e2); Proof newPf(const std::string& name, const Expr& e, const Proof& pf); Proof newPf(const std::string& name, const Expr& e1, const Expr& e2, const Expr& e3); Proof newPf(const std::string& name, const Expr& e1, const Expr& e2, const Proof& pf); // Methods with iterators. // Iterators are preferred to vectors, since they are often // efficient Proof newPf(const std::string& name, Expr::iterator begin, const Expr::iterator &end); Proof newPf(const std::string& name, const Expr& e, Expr::iterator begin, const Expr::iterator &end); Proof newPf(const std::string& name, Expr::iterator begin, const Expr::iterator &end, const std::vector& pfs); // Methods with vectors. Proof newPf(const std::string& name, const std::vector& args); Proof newPf(const std::string& name, const Expr& e, const std::vector& args); Proof newPf(const std::string& name, const Expr& e, const std::vector& pfs); Proof newPf(const std::string& name, const Expr& e1, const Expr& e2, const std::vector& pfs); Proof newPf(const std::string& name, const std::vector& pfs); Proof newPf(const std::string& name, const std::vector& args, const Proof& pf); Proof newPf(const std::string& name, const std::vector& args, const std::vector& pfs); //! Creating LAMBDA-abstraction (LAMBDA label formula proof) /*! The label must be a variable with a formula as a type, and * matching the given "frm". */ Proof newPf(const Proof& label, const Expr& frm, const Proof& pf); //! Creating LAMBDA-abstraction (LAMBDA label proof). /*! The label must be a variable with a formula as a type. */ Proof newPf(const Proof& label, const Proof& pf); /*! @brief Similarly, multi-argument lambda-abstractions: * (LAMBDA (u1,...,un): (f1,...,fn). pf) */ Proof newPf(const std::vector& labels, const std::vector& frms, const Proof& pf); Proof newPf(const std::vector& labels, const Proof& pf); }; // end of Theorem_Producer class } // end of namespace CVC3 #endif cvc3-2.4.1/src/include/dpllt_basic.h0000664000175400017540000000474611174103202017123 0ustar mdetersmdeters/*****************************************************************************/ /*! *\file dpllt_basic.h *\brief Basic implementation of dpllt module * * Author: Clark Barrett * * Created: Mon Dec 12 19:06:58 2005 * *
* * License to use, copy, modify, sell and/or distribute this software * and its documentation for any purpose is hereby granted without * royalty, subject to the terms and conditions defined in the \ref * LICENSE file provided with this distribution. * *
*/ /*****************************************************************************/ #ifndef _cvc3__sat__dpllt_basic_h_ #define _cvc3__sat__dpllt_basic_h_ #include "dpllt.h" #include "sat_api.h" #include "cdo.h" #include "proof.h" #include "cnf_manager.h" namespace SAT { class DPLLTBasic :public DPLLT { CVC3::ContextManager* d_cm; bool d_ready; SatSolver* d_mng; CNF_Formula_Impl* d_cnf; CD_CNF_Formula* d_assertions; std::vector d_mngStack; std::vector d_cnfStack; std::vector d_assertionsStack; bool d_printStats; CVC3::CDO d_pushLevel; CVC3::CDO d_readyPrev; CVC3::CDO d_prevStackSize; CVC3::CDO d_prevAStackSize; void createManager(); void generate_CDB (CNF_Formula_Impl& cnf); void handle_result(SatSolver::SATStatus outcome); void verify_solution(); public: DPLLTBasic(TheoryAPI* theoryAPI, Decider* decider, CVC3::ContextManager* cm, bool printStats = false); virtual ~DPLLTBasic(); void addNewClause(const Clause& c); void addNewClauses(CNF_Formula_Impl& cnf); SatSolver::Lit cvc2SAT(Lit l) { return l.isNull() ? SatSolver::Lit() : d_mng->MakeLit(d_mng->GetVar(l.getVar()), l.isPositive() ? 0 : 1); } Lit SAT2cvc(SatSolver::Lit l) { return l.IsNull() ? Lit() : Lit(d_mng->GetVarIndex(d_mng->GetVarFromLit(l)), d_mng->GetPhaseFromLit(l) == 0); } SatSolver* satSolver() { return d_mng; } // Implementation of virtual DPLLT methods void push(); void pop(); void addAssertion(const CNF_Formula& cnf); virtual std::vector getCurAssignments() ; virtual std::vector > getCurClauses(); CVC3::QueryResult checkSat(const CNF_Formula& cnf); CVC3::QueryResult continueCheck(const CNF_Formula& cnf); Var::Val getValue(Var v) { return Var::Val(d_mng->GetVarAssignment(d_mng->GetVar(v))); } CVC3::Proof getSatProof(CNF_Manager*, CVC3::TheoryCore*); }; } #endif cvc3-2.4.1/src/include/memory_manager_context.h0000664000175400017540000001146211267754362021430 0ustar mdetersmdeters/*****************************************************************************/ /*! *\file memory_manager_context.h *\brief Stack-based memory manager * * Author: Clark Barrett * * Created: Thu Aug 3 21:39:07 2006 * *
* * License to use, copy, modify, sell and/or distribute this software * and its documentation for any purpose is hereby granted without * royalty, subject to the terms and conditions defined in the \ref * LICENSE file provided with this distribution. * *
*/ /*****************************************************************************/ #ifndef _cvc3__include__memory_manager_context_h #define _cvc3__include__memory_manager_context_h #include #include #include "memory_manager.h" namespace CVC3 { const unsigned chunkSizeBytes = 16384; // #bytes in each chunk /*****************************************************************************/ /*! *\class ContextMemoryManager *\brief ContextMemoryManager * * Author: Clark Barrett * * Created: Thu Aug 3 16:41:35 2006 * * Stack-based memory manager */ /*****************************************************************************/ class ContextMemoryManager :public MemoryManager { static std::vector s_freePages; std::vector d_chunkList; // Pointers to the beginning of each chunk // Pointers to the next free block of memory in the current chunk char* d_nextFree; // Pointer to end of current chunk (1 byte off the end) char* d_endChunk; // Index into chunk vector unsigned d_indexChunkList; // Stack of pointers to the next free block of memory in the current chunk std::vector d_nextFreeStack; // Stack of pointers to end of current chunk (1 byte off the end) std::vector d_endChunkStack; // Stack of indices into chunk vector std::vector d_indexChunkListStack; // Private methods void newChunk() { // Allocate new chunk DebugAssert(d_chunkList.size() > 0, "expected unempty list"); ++d_indexChunkList; DebugAssert(d_chunkList.size() == d_indexChunkList, "invariant violated"); if (s_freePages.empty()) { d_chunkList.push_back((char*)malloc(chunkSizeBytes)); } else { d_chunkList.push_back(s_freePages.back()); s_freePages.pop_back(); } d_nextFree = d_chunkList.back(); FatalAssert(d_nextFree != NULL, "Out of memory"); d_endChunk = d_nextFree + chunkSizeBytes; } public: // Constructor ContextMemoryManager() : d_indexChunkList(0) { if (s_freePages.empty()) { d_chunkList.push_back((char*)malloc(chunkSizeBytes)); } else { d_chunkList.push_back(s_freePages.back()); s_freePages.pop_back(); } d_nextFree = d_chunkList.back(); FatalAssert(d_nextFree != NULL, "Out of memory"); d_endChunk = d_nextFree + chunkSizeBytes; } // Destructor ~ContextMemoryManager() { while(!d_chunkList.empty()) { s_freePages.push_back(d_chunkList.back()); d_chunkList.pop_back(); } } void* newData(size_t size) { void* res = (void*)d_nextFree; d_nextFree += size; if (d_nextFree > d_endChunk) { newChunk(); res = (void*)d_nextFree; d_nextFree += size; DebugAssert(d_nextFree <= d_endChunk, "chunk not big enough"); } return res; } void deleteData(void* d) { } void push() { d_nextFreeStack.push_back(d_nextFree); d_endChunkStack.push_back(d_endChunk); d_indexChunkListStack.push_back(d_indexChunkList); } void pop() { d_nextFree = d_nextFreeStack.back(); d_nextFreeStack.pop_back(); d_endChunk = d_endChunkStack.back(); d_endChunkStack.pop_back(); while (d_indexChunkList > d_indexChunkListStack.back()) { s_freePages.push_back(d_chunkList.back()); d_chunkList.pop_back(); --d_indexChunkList; } d_indexChunkListStack.pop_back(); } static void garbageCollect(void) { while (!s_freePages.empty()) { free(s_freePages.back()); s_freePages.pop_back(); } } unsigned getMemory(int verbosity) { unsigned long memSelf = sizeof(ContextMemoryManager); unsigned long mem = 0; mem += MemoryTracker::getVec(verbosity - 1, d_chunkList); mem += MemoryTracker::getVec(verbosity - 1, d_nextFreeStack); mem += MemoryTracker::getVec(verbosity - 1, d_endChunkStack); mem += MemoryTracker::getVec(verbosity - 1, d_indexChunkListStack); mem += d_chunkList.size() * chunkSizeBytes; MemoryTracker::print("ContextMemoryManager", verbosity, memSelf, mem); return mem + memSelf; } static unsigned getStaticMemory(int verbosity) { unsigned mem = 0; mem += MemoryTracker::getVec(verbosity - 1, s_freePages); mem += s_freePages.size() * chunkSizeBytes; MemoryTracker::print("ContextMemoryManager Static", verbosity, 0, mem); return mem; } }; // end of class ContextMemoryManager } #endif cvc3-2.4.1/src/include/proof.h0000664000175400017540000000356711027560537016007 0ustar mdetersmdeters/*****************************************************************************/ /*! * \file proof.h * * Author: Sergey Berezin * * Created: Dec 10 00:37:49 GMT 2002 * *
* * License to use, copy, modify, sell and/or distribute this software * and its documentation for any purpose is hereby granted without * royalty, subject to the terms and conditions defined in the \ref * LICENSE file provided with this distribution. * *
* */ /*****************************************************************************/ // CLASS: Proof // // AUTHOR: Sergey Berezin, 12/03/2002 // // Abstract: // // Proof is a wrapper around Expr, to prevent accidental mix-up. Only // proof rules and adaptors are supposed to use any of its methods. /////////////////////////////////////////////////////////////////////////////// #ifndef _cvc3__expr_h_ #include "expr.h" #endif #ifndef _cvc3__proof_h_ #define _cvc3__proof_h_ namespace CVC3 { class Proof { private: Expr d_proof; // unsigned d_insts; //by yeting, this is to store the number of instantiations. debug only public: Proof(const Expr &e) : d_proof(e) { } // Constructor Proof(const Proof& p) : d_proof(p.d_proof) { } // Copy constructor Proof() : d_proof() { } // Null proof constructor Expr getExpr() const { return d_proof; } // Extract the expr handle bool isNull() const { return d_proof.isNull(); } // Printing friend std::ostream& operator<<(std::ostream& os, const Proof& pf); std::string toString() const { std::ostringstream ss; ss<<(*this); return ss.str(); } }; // End of class Proof inline std::ostream& operator<<(std::ostream& os, const Proof& pf) { return os << "Proof(" << pf.getExpr() << ")"; } inline bool operator==(const Proof& pf1, const Proof& pf2) { return pf1.getExpr() == pf2.getExpr(); } } // end of namespace CVC3 #endif cvc3-2.4.1/src/include/expr_hash.h0000664000175400017540000000222610557763737016650 0ustar mdetersmdeters/*****************************************************************************/ /*! * \file expr_hash.h * \brief Definition of the API to expression package. See class Expr for details. * * Author: Clark Barrett * * Created: Tue Nov 26 00:27:40 2002 * *
* * License to use, copy, modify, sell and/or distribute this software * and its documentation for any purpose is hereby granted without * royalty, subject to the terms and conditions defined in the \ref * LICENSE file provided with this distribution. * *
* * Define std::hash and std::hash for hash_map and * hash_set over Expr class. */ /*****************************************************************************/ #ifndef _cvc3__expr_h_ #include "expr.h" #endif #ifndef _cvc3__include__expr_hash_h_ #define _cvc3__include__expr_hash_h_ #include "hash_fun.h" namespace Hash { template<> struct hash { size_t operator()(const CVC3::Expr& e) const { return e.hash(); } }; template<> class hash { private: hash h; public: size_t operator()(const std::string& s) const { return h(s.c_str()); } }; } #endif cvc3-2.4.1/src/include/dpllt.h0000664000175400017540000001517510716213261015770 0ustar mdetersmdeters/*****************************************************************************/ /*! *\file dpllt.h *\brief Generic DPLL(T) module * * Author: Clark Barrett * * Created: Mon Dec 12 16:28:08 2005 */ /*****************************************************************************/ #ifndef _cvc3__include__dpllt_h_ #define _cvc3__include__dpllt_h_ #include "queryresult.h" #include "cnf.h" #include "cnf_manager.h" #include "proof.h" #include "theory_core.h" namespace SAT { class DPLLT { public: enum ConsistentResult {INCONSISTENT, MAYBE_CONSISTENT, CONSISTENT }; class TheoryAPI { public: TheoryAPI() {} virtual ~TheoryAPI() {} //! Set a checkpoint for backtracking virtual void push() = 0; //! Restore most recent checkpoint virtual void pop() = 0; //! Notify theory when a literal is set to true virtual void assertLit(Lit l) = 0; //! Check consistency of the current assignment. /*! The result is either INCONSISTENT, MAYBE_CONSISTENT, or CONSISTENT * Most of the time, fullEffort should be false, and the result will most * likely be either INCONSISTENT or MAYBE_CONSISTENT. To force a full * check, set fullEffort to true. When fullEffort is set to true, the * only way the result can be MAYBE_CONSISTENT is if there are new clauses * to get (via getNewClauses). * \param cnf should be empty initially. If INCONSISTENT is returned, * then cnf will contain one or more clauses ruling out the current * assignment when it returns. Otherwise, cnf is unchanged. * \param fullEffort true for a full check, false for a fast check */ virtual ConsistentResult checkConsistent(CNF_Formula& cnf, bool fullEffort) = 0; //! Check if the work budget has been exceeded /*! If true, it means that the engine should quit and return ABORT. * Otherwise, it should proceed normally. This should be checked regularly. */ virtual bool outOfResources() = 0; //! Get a literal that is implied by the current assignment. /*! This is theory propagation. It can be called repeatedly and returns a * Null literal when there are no more literals to propagate. It should * only be called when the assignment is not known to be inconsistent. */ virtual Lit getImplication() = 0; //! Get an explanation for a literal that was implied /*! Given a literal l that is true in the current assignment as a result of * an earlier call to getImplication(), this method returns a set of clauses which * justifies the propagation of that literal. The clauses will contain the * literal l as well as other literals that are in the current assignment. * The clauses are such that they would have propagated l via unit * propagation at the time getImplication() was called. * \param l the literal * \param c should be empty initially. */ virtual void getExplanation(Lit l, CNF_Formula& c) = 0; //! Get new clauses from the theory. /*! This is extended theory learning. Returns false if there are no new * clauses to get. Otherwise, returns true and new clauses are added to * cnf. Note that the new clauses (if any) are theory lemmas, i.e. clauses * that are valid in the theory and not dependent on the current * assignment. The clauses may contain new literals as well as literals * that are true in the current assignment. * \param cnf should be empty initially. */ virtual bool getNewClauses(CNF_Formula& cnf) = 0; }; class Decider { public: Decider() {} virtual ~Decider() {} //! Make a decision. /* Returns a NULL Lit if there are no more decisions to make */ virtual Lit makeDecision() = 0; }; protected: TheoryAPI* d_theoryAPI; Decider* d_decider; public: //! Constructor /*! The client constructing DPLLT must provide an implementation of * TheoryAPI. It may also optionally provide an implementation of Decider. * If decider is NULL, then the DPLLT class must make its own decisions. */ DPLLT(TheoryAPI* theoryAPI, Decider* decider) : d_theoryAPI(theoryAPI), d_decider(decider) {} virtual ~DPLLT() {} TheoryAPI* theoryAPI() { return d_theoryAPI; } Decider* decider() { return d_decider; } void setDecider(Decider* decider) { d_decider = decider; } //! Set a checkpoint for backtracking /*! This should effectively save the current state of the solver. Note that * it should also result in a call to TheoryAPI::push. */ virtual void push() = 0; //! Restore checkpoint /*! This should return the state to what it was immediately before the last * call to push. In particular, if one or more calls to checkSat, * continueCheck, or addAssertion have been made since the last push, these * should be undone. Note also that in this case, a single call to * DPLLT::pop may result in multiple calls to TheoryAPI::pop. */ virtual void pop() = 0; //! Add new clauses to the SAT solver /*! This is used to add clauses that form a "context" for the next call to * checkSat */ virtual void addAssertion(const CNF_Formula& cnf) = 0; virtual std::vector getCurAssignments() =0 ; virtual std::vector > getCurClauses() =0 ; //! Check the satisfiability of a set of clauses in the current context /*! If the result is SATISFIABLE, UNKNOWN, or ABORT, the DPLLT engine should * remain in the state it is in until pop() is called. If the result is * UNSATISFIABLE, the DPLLT engine should return to the state it was in when * called. Note that it should be possible to call checkSat multiple times, * even if the result is true (each additional call should use the context * left by the previous call). */ virtual CVC3::QueryResult checkSat(const CNF_Formula& cnf) = 0; //! Continue checking the last check with additional constraints /*! Should only be called after a previous call to checkSat (or * continueCheck) that returned SATISFIABLE. It should add the clauses in * cnf to the existing clause database and search for a satisfying * assignment. As with checkSat, if the result is not UNSATISFIABLE, the * DPLLT engine should remain in the state containing the satisfiable * assignment until pop() is called. Similarly, if the result is * UNSATISFIABLE, the DPLLT engine should return to the state it was in when * checkSat was last called. */ virtual CVC3::QueryResult continueCheck(const CNF_Formula& cnf) = 0; //! Get value of variable: unassigned, false, or true virtual Var::Val getValue(Var v) = 0; //! Get the proof from SAT engine. virtual CVC3::Proof getSatProof(CNF_Manager*, CVC3::TheoryCore*) = 0 ; }; } #endif cvc3-2.4.1/src/include/theory_datatype_lazy.h0000664000175400017540000000352411210144237021104 0ustar mdetersmdeters/*****************************************************************************/ /*! *\file theory_datatype_lazy.h * * Author: Clark Barrett * * Created: Wed Dec 1 22:24:32 2004 * *
* * License to use, copy, modify, sell and/or distribute this software * and its documentation for any purpose is hereby granted without * royalty, subject to the terms and conditions defined in the \ref * LICENSE file provided with this distribution. * *
* */ /*****************************************************************************/ #ifndef _cvc3__include__theory_datatype_lazy_h_ #define _cvc3__include__theory_datatype_lazy_h_ #include "theory.h" #include "smartcdo.h" #include "cdmap.h" #include "theory_datatype.h" namespace CVC3 { /*****************************************************************************/ /*! *\class TheoryDatatypeLazy *\ingroup Theories *\brief This theory handles datatypes. * * Author: Clark Barrett * * Created: Wed Dec 1 22:27:12 2004 */ /*****************************************************************************/ class TheoryDatatypeLazy :public TheoryDatatype { typedef enum { MERGE1 = 0, MERGE2, ENQUEUE } ProcessKinds; CDList d_processQueue; CDList d_processQueueKind; CDO d_processIndex; CDO d_typeComplete; private: void instantiate(const Expr& e, const Unsigned& u); void initializeLabels(const Expr& e, const Type& t); void mergeLabels(const Theorem& thm, const Expr& e1, const Expr& e2); void mergeLabels(const Theorem& thm, const Expr& e, unsigned position, bool positive); public: TheoryDatatypeLazy(TheoryCore* theoryCore); ~TheoryDatatypeLazy() {} // Theory interface void checkSat(bool fullEffort); void setup(const Expr& e); void update(const Theorem& e, const Expr& d); }; } #endif cvc3-2.4.1/src/include/circuit.h0000664000175400017540000000155410466450542016316 0ustar mdetersmdeters/*****************************************************************************/ /*! * \file circuit.h * \brief Circuit class * *
* * License to use, copy, modify, sell and/or distribute this software * and its documentation for any purpose is hereby granted without * royalty, subject to the terms and conditions defined in the \ref * LICENSE file provided with this distribution. * *
* */ /*****************************************************************************/ #ifndef _cvc3__include__circuit_h_ #define _cvc3__include__circuit_h_ #include "variable.h" #include "theorem.h" using namespace std; namespace CVC3 { class SearchEngineFast; class Circuit { private: Theorem d_thm; Literal d_lits[4]; public: Circuit(SearchEngineFast* se, const Theorem& thm); bool propagate(SearchEngineFast* se); }; } // namespace CVC3 #endif cvc3-2.4.1/src/include/parser_exception.h0000664000175400017540000000223211103725115020206 0ustar mdetersmdeters/*****************************************************************************/ /*! * \file parser_exception.h * \brief An exception thrown by the parser. * * Author: Sergey Berezin * * Created: Thu Feb 6 13:23:39 2003 * *
* * License to use, copy, modify, sell and/or distribute this software * and its documentation for any purpose is hereby granted without * royalty, subject to the terms and conditions defined in the \ref * LICENSE file provided with this distribution. * *
* */ /*****************************************************************************/ #ifndef _cvc3__parser_exception_h_ #define _cvc3__parser_exception_h_ #include "exception.h" #include #include namespace CVC3 { class ParserException: public Exception { public: // Constructors ParserException() { } ParserException(const std::string& msg): Exception(msg) { } ParserException(const char* msg): Exception(msg) { } // Destructor virtual ~ParserException() { } virtual std::string toString() const { return "Parse Error: " + d_msg; } }; // end of class ParserException } // end of namespace CVC3 #endif cvc3-2.4.1/src/include/expr_transform.h0000664000175400017540000001714511234135020017711 0ustar mdetersmdeters/*****************************************************************************/ /*! *\file expr_transform.h *\brief Generally Useful Expression Transformations * * Author: Clark Barrett * * Created: Fri Aug 5 16:11:51 2005 * *
* * License to use, copy, modify, sell and/or distribute this software * and its documentation for any purpose is hereby granted without * royalty, subject to the terms and conditions defined in the \ref * LICENSE file provided with this distribution. * *
* */ /*****************************************************************************/ #ifndef _cvc3__include__expr_transform_h_ #define _cvc3__include__expr_transform_h_ #include "expr.h" namespace CVC3 { class VCL; class TheoryCore; class CommonProofRules; class CoreProofRules; class TheoryArith; class ExprTransform { TheoryCore* d_core; TheoryArith* d_theoryArith; CommonProofRules* d_commonRules; CoreProofRules* d_rules; //! Cache for pushNegation() ExprMap d_pushNegCache; //! Cache for newPP ExprMap d_newPPCache; //! Budget limit for newPP int d_budgetLimit; public: ExprTransform(TheoryCore* core); ~ExprTransform() {} void setTheoryArith(TheoryArith* arith) { d_theoryArith = arith; } // class CParameter; //void get_atoms(std::set< Expr >& atoms, const Expr& e); //Theorem do_static_learn(const Expr& e); typedef std::map< std::pair< Expr, ExprTransform::CParameter >, Expr > T_name_map; typedef std::map< Expr, std::set< ExprTransform::CParameter >* > T_ack_map; typedef std::map< Expr, Type> T_type_map; typedef std::map< std::pair< Expr, Expr>, Expr > B_name_map; typedef std::map B_type_map; typedef std::map< Expr, std::set*> T_generator_map; typedef std::map*> B_Term_map; typedef std::map< Expr, Expr> T_ITE_map; typedef std::map< Expr, int> B_formula_map; typedef std::map*> NEW_formula_map; typedef std::vector T_ITE_vec; std::string NewBryantVar(const int a, const int b); std::string NewVar(const int a, const int b); B_name_map BryantNames(T_generator_map& generator_map, B_type_map& type_map); Expr ITE_generator(Expr& Orig, Expr& Value, B_Term_map& Creation_map, B_name_map& name_map, T_ITE_map& ITE_map); void Get_ITEs(B_formula_map& instance_map, std::set& Not_replaced_set, B_Term_map& P_term_map, T_ITE_vec& ITE_vec, B_Term_map& Creation_map, B_name_map& name_map, T_ITE_map& ITE_map); void PredConstrainTester(std::set& Not_replaced_set, const Expr& e, B_name_map& name_map, std::vector& Pred_vec, std::set& Constrained_set, std::set& P_constrained_set, T_generator_map& Constrained_map); void PredConstrainer(std::set& Not_replaced_set, const Expr& e, const Expr& Pred, int location, B_name_map& name_map, std::set& SeenBefore, std::set& Constrained_set, T_generator_map& Constrained_map, std::set& P_constrained_set); Expr ConstrainedConstraints(std::set& Not_replaced_set, T_generator_map& Constrained_map, B_name_map& name_map, B_Term_map& Creation_map, std::set& Constrained_set, std::set& UnConstrained_set, std::set& P_constrained_set); void RemoveFunctionApps(const Expr& orig, std::set& Not_replaced_set, std::vector& Old, std::vector& New, T_ITE_map& ITE_map, std::set& SeenBefore); void GetSortedOpVec(B_Term_map& X_generator_map, B_Term_map& X_term_map, B_Term_map& P_term_map, std::set& P_terms, std::set& G_terms, std::set& X_terms, std::vector& sortedOps, std::set& SeenBefore); void GetFormulaMap(const Expr& e, std::set& formula_map, std::set& G_terms, int& size, int negations); void GetGTerms2(std::set& formula_map, std::set& G_terms); void GetSub_vec(T_ITE_vec& ITE_vec, const Expr& e, std::set& ITE_Added); //void GetOrderedTerms(B_Term_map& X_term_map, T_ITE_vec& ITE_vec, std::set& G_terms, std::set& X_terms, std::vector& Pred_vec, std::vector& sortedOps, std::vector& Constrained_vec, std::vector& UnConstrained_vec, B_Term_map& G_term_map, B_Term_map& P_term_map, std::set& SeenBefore, std::set& ITE_Added); void GetOrderedTerms(B_formula_map& instance_map, B_name_map& name_map, B_Term_map& X_term_map, T_ITE_vec& ITE_vec, std::set& G_terms, std::set& X_terms, std::vector& Pred_vec, std::vector& sortedOps, std::vector& Constrained_vec, std::vector& UnConstrained_vec, std::set& Constrained_set, std::set& UnConstrained_set, B_Term_map& G_term_map, B_Term_map& P_term_map, std::set& SeenBefore, std::set& ITE_Added); void GetPEqs(const Expr& e, B_name_map& name_map, std::set& P_constrained_set, std::set& Constrained_set, T_generator_map& Constrained_map, std::set& SeenBefore); Expr ConstrainedConstraints(T_generator_map& Constrained_map, B_name_map& name_map, B_Term_map& Creation_map, std::set& Constrained_set, std::set& UnConstrained_set, std::set& P_constrained_set); void BuildBryantMaps(const Expr& e, T_generator_map& generator_map, B_Term_map& X_generator_map, B_type_map& type_map, std::vector& Pred_vec, std::set& P_terms, std::set& G_terms, B_Term_map& P_term_map, B_Term_map& G_term_map, std::set< Expr >& SeenBefore, std::set& ITE_Added); int CountSubTerms(const Expr& e, int& counter); void GetOrdering(B_Term_map& X_generator_map, B_Term_map& G_term_map, B_Term_map& P_Term_map); void B_Term_Map_Deleter(B_Term_map& Map); void T_generator_Map_Deleter(T_generator_map& Map); Theorem dobryant(const Expr& T); T_name_map ANNames(T_ack_map& ack_map, T_type_map& type_map); Expr AckConstraints(T_ack_map& ack_map, T_name_map& name_map); void GetAckSwap(const Expr& orig, std::vector& OldAck, std::vector& NewAck, T_name_map& name_map, T_ack_map& ack_map, std::set& SeenBefore); void BuildMap(const Expr& e, T_ack_map& ack_map, T_type_map& type_map, std::set< Expr >& SeenBefore); Theorem doackermann(const Expr& T); // //! Simplification that avoids stack overflow /*! Stack overflow is avoided by traversing the expression to depths that are multiples of 5000 until the bottom is reached. Then, simplification is done bottom-up. */ Theorem smartSimplify(const Expr& e, ExprMap& cache); Theorem preprocess(const Expr& e); Theorem preprocess(const Theorem& thm); //! Push all negations down to the leaves Theorem pushNegation(const Expr& e); //! Auxiliary recursive function for pushNegation(). Theorem pushNegationRec(const Expr& e, bool neg); //! Its version for transitivity Theorem pushNegationRec(const Theorem& e, bool neg); //! Push negation one level down. Takes 'e' which is 'NOT e[0]' Theorem pushNegation1(const Expr& e); //! Helper for newPP Theorem specialSimplify(const Expr& e, ExprHashMap& cache); //! new preprocessing code Theorem newPP(const Expr& e, int& budget); //! main new preprocessing code Theorem newPPrec(const Expr& e, int& budget); private: //! Helper for simplifyWithCare void updateQueue(ExprMap* >& queue, const Expr& e, const std::set& careSet); //! Helper for simplifyWithCare Theorem substitute(const Expr& e, ExprHashMap& substTable, ExprHashMap& cache); public: //! ITE simplification from Burch paper Theorem simplifyWithCare(const Expr& e); /*@}*/ // end of preprocessor stuff }; } #endif cvc3-2.4.1/src/include/memory_manager.h0000664000175400017540000000277710466450542017666 0ustar mdetersmdeters/*****************************************************************************/ /*! * \file memory_manager.h * * Author: Sergey Berezin * * Created: Thu Apr 3 16:47:14 2003 * *
* * License to use, copy, modify, sell and/or distribute this software * and its documentation for any purpose is hereby granted without * royalty, subject to the terms and conditions defined in the \ref * LICENSE file provided with this distribution. * *
* * Class MemoryManager: allocates/deallocates memory for objects of a * requested size. Some instanced of this class may be specialized to * a specific object size, and the actual memory may be allocated in * big chunks, for efficiency. * * Typical use of this class is to create * MemoryManager* mm = new MemoryManagerChunks(sizeof(YourClass)); * where YourClass has operators new and delete redefined: * void* YourClass::operator new(size_t size, MemoryManager* mm) * { return mm->newData(size); } * void YourClass::delete(void*) { } // do not deallocate memory here * Then, create objects with obj = new(mm) YourClass(), and destroy them with * delete obj; mm->deleteData(obj); */ /*****************************************************************************/ #ifndef _cvc3__memory_manager_h #define _cvc3__memory_manager_h namespace CVC3 { class MemoryManager { public: // Destructor virtual ~MemoryManager() { } virtual void* newData(size_t size) = 0; virtual void deleteData(void* d) = 0; }; // end of class MemoryManager } #endif cvc3-2.4.1/src/include/statistics.h0000664000175400017540000001420010466450542017036 0ustar mdetersmdeters/*****************************************************************************/ /*! * \file statistics.h * \brief Description: Counters and flags for collecting run-time statistics. * * Author: Sergey Berezin * * Created: Thu Jun 5 17:38:13 2003 * *
* * License to use, copy, modify, sell and/or distribute this software * and its documentation for any purpose is hereby granted without * royalty, subject to the terms and conditions defined in the \ref * LICENSE file provided with this distribution. * *
* */ /*****************************************************************************/ #ifndef _cvc3__statistics_h #define _cvc3__statistics_h #include #include #include #include namespace CVC3 { class Statistics; // The main class, defined below // First, wrapper classes for flags and counters. Later, we // overload some operators like '=', '++', etc. for those classes. // Boolean flag (can only be true or false) class StatFlag { private: bool* d_flag; // We don't own the pointer public: // Constructor: takes the pointer to the actual flag, normally // stored in class Statistics below. StatFlag(bool& flag) : d_flag(&flag) { } // Destructor ~StatFlag() { } // Auto-cast to boolean operator bool() { return *d_flag; } // Setting and resetting by ++ and -- // Prefix versions: bool operator--() { *d_flag = false; return false; } bool operator++() { *d_flag = true; return true; } // Postfix versions: bool operator--(int) { bool x=*d_flag; *d_flag=false; return x; } bool operator++(int) { bool x=*d_flag; *d_flag=true; return x; } // Can be assigned only a boolean value StatFlag& operator=(bool x) { *d_flag=(x!=false); return *this; } // Comparisons friend bool operator==(const StatFlag& f1, const StatFlag& f2); friend bool operator!=(const StatFlag& f1, const StatFlag& f2); // Printing friend std::ostream& operator<<(std::ostream& os, const StatFlag& f); }; // end of class StatFlag inline bool operator==(const StatFlag& f1, const StatFlag& f2) { return (*f1.d_flag) == (*f2.d_flag); } inline bool operator!=(const StatFlag& f1, const StatFlag& f2) { return (*f1.d_flag) != (*f2.d_flag); } inline std::ostream& operator<<(std::ostream& os, const StatFlag& f) { if(*f.d_flag) return(os << "true"); else return(os << "false"); } // Integer counter. Intended use is to count events (e.g. number of // function calls), but can be used to store any integer value // (e.g. size of some data structure) class StatCounter { private: int* d_counter; // We don't own the pointer public: // Constructor: takes the pointer to the actual counter, normally // stored in class Statistics below. StatCounter(int& c) : d_counter(&c) { } // Destructor ~StatCounter() { } // Auto-cast to int. In particular, arithmetic comparisons like // <, >, <=, >= will work because of this. operator int() { return *d_counter; } // Auto-increment operators // Prefix versions: int operator--() { return --(*d_counter); } int operator++() { return ++(*d_counter); } // Postfix versions: int operator--(int) { return (*d_counter)--; } int operator++(int) { return (*d_counter)++; } // Can be assigned an integer or the value of another StatCounter StatCounter& operator=(int x) { *d_counter=x; return *this; } StatCounter& operator+=(int x) { *d_counter+=x; return *this; } StatCounter& operator-=(int x) { *d_counter-=x; return *this; } StatCounter& operator=(const StatCounter& x) { *d_counter=*x.d_counter; return *this; } StatCounter& operator-=(const StatCounter& x) { *d_counter-=*x.d_counter; return *this; } StatCounter& operator+=(const StatCounter& x) { *d_counter+=*x.d_counter; return *this; } // Comparisons to integers and other StatCounters friend bool operator==(const StatCounter& c1, const StatCounter& c2); friend bool operator!=(const StatCounter& c1, const StatCounter& c2); friend bool operator==(int c1, const StatCounter& c2); friend bool operator!=(int c1, const StatCounter& c2); friend bool operator==(const StatCounter& c1, int c2); friend bool operator!=(const StatCounter& c1, int c2); // Printing friend std::ostream& operator<<(std::ostream& os, const StatCounter& f); }; // end of class StatCounter inline bool operator==(const StatCounter& c1, const StatCounter& c2) { return (*c1.d_counter) == (*c2.d_counter); } inline bool operator!=(const StatCounter& c1, const StatCounter& c2) { return (*c1.d_counter) != (*c2.d_counter); } inline bool operator==(int c1, const StatCounter& c2) { return c1 == (*c2.d_counter); } inline bool operator!=(int c1, const StatCounter& c2) { return c1 != (*c2.d_counter); } inline bool operator==(const StatCounter& c1, int c2) { return (*c1.d_counter) == c2; } inline bool operator!=(const StatCounter& c1, int c2) { return (*c1.d_counter) != c2; } inline std::ostream& operator<<(std::ostream& os, const StatCounter& c) { return (os << *c.d_counter); } // class Statistics: the storage for all flags and counters class Statistics { private: // Output control std::ostream* d_os; typedef std::map StatFlagMap; typedef std::map StatCounterMap; StatFlagMap d_flags; StatCounterMap d_counters; public: // Constructor Statistics() { } // Destructor (must destroy objects it d_timers) ~Statistics() { } // Accessing flags, counters, and timers by name. If an object // doesn't exist, it is created and initialized to false or 0. StatFlag flag(const std::string& name) { return StatFlag(d_flags[name]); } StatCounter counter(const std::string& name) { return StatCounter(d_counters[name]); } // Print all the collected data std::ostream& printAll(std::ostream& os) const; friend std::ostream& operator<<(std::ostream& os, const Statistics& stats) { return stats.printAll(os); } }; // end of class Statistics } // end of namespace CVC3 #endif cvc3-2.4.1/src/include/formula_value.h0000664000175400017540000000173611070741375017516 0ustar mdetersmdeters/*****************************************************************************/ /*! *\file formula_value.h *\brief enumerated type for value of formulas * * Author: Alexander Fuchs * * Created: Fri Dec 07 08:00:00 2007 * *
* * License to use, copy, modify, sell and/or distribute this software * and its documentation for any purpose is hereby granted without * royalty, subject to the terms and conditions defined in the \ref * LICENSE file provided with this distribution. * *
*/ /*****************************************************************************/ #ifndef _cvc3__include__formula_value_h_ #define _cvc3__include__formula_value_h_ namespace CVC3 { /*****************************************************************************/ /* * Type for truth value of formulas. */ /*****************************************************************************/ typedef enum FormulaValue { TRUE_VAL, FALSE_VAL, UNKNOWN_VAL } FormulaValue; } #endif cvc3-2.4.1/src/include/cvc_util.h0000664000175400017540000001457411167727101016467 0ustar mdetersmdeters/*****************************************************************************/ /*! *\file cvc_util.h *\brief basic helper utilities * * Author: Clark Barrett * * Created: Thu Dec 1 16:35:52 2005 * *
* * License to use, copy, modify, sell and/or distribute this software * and its documentation for any purpose is hereby granted without * royalty, subject to the terms and conditions defined in the \ref * LICENSE file provided with this distribution. * *
*/ /*****************************************************************************/ #ifndef _cvc3__debug_h #include "debug.h" #endif #ifndef _cvc3__cvc_util_h #define _cvc3__cvc_util_h namespace CVC3 { inline std::string to_upper(const std::string & src){ std::string nameup; for(std::string::const_iterator i=src.begin(), iend = src.end(); i!=iend ; i++){ nameup.push_back(toupper(*i)); } return nameup; } inline std::string to_lower(const std::string & src){ std::string nameup; for(std::string::const_iterator i=src.begin(), iend = src.end(); i!=iend ; i++){ nameup.push_back(tolower(*i)); } return nameup; } inline std::string int2string(int n) { std::ostringstream ss; ss << n; return ss.str(); } template T abs(T t) { return t < 0 ? -t : t; } template T max(T a, T b) { return a > b ? a : b; } struct ltstr{ bool operator()(const std::string& s1, const std::string& s2) const{ return s1.compare(s2) < 0; } }; template class StrPairLess { public: bool operator()(const std::pair& p1, const std::pair& p2) const { return p1.first < p2.first; } }; template std::pair strPair(const std::string& f, const T& t) { return std::pair(f, t); } typedef std::pair StrPair; //! Sort two vectors based on the first vector template void sort2(std::vector& keys, std::vector& vals) { DebugAssert(keys.size()==vals.size(), "sort2()"); // Create std::vector of pairs std::vector > pairs; for(size_t i=0, iend=keys.size(); i comp; sort(pairs.begin(), pairs.end(), comp); DebugAssert(pairs.size() == keys.size(), "sort2()"); // Split the pairs back into the original vectors for(size_t i=0, iend=pairs.size(); i 0) { std::cout << name << ": " << memSelf << std::endl; std::cout << " Children: " << mem << std::endl; std::cout << " Total: " << mem+memSelf << std::endl; } } template static unsigned long getVec(int verbosity, const std::vector& v) { unsigned long memSelf = sizeof(std::vector); unsigned long mem = 0; print("vector", verbosity, memSelf, mem); return memSelf + mem; } template static unsigned long getVecAndData(int verbosity, const std::vector& v) { unsigned long memSelf = sizeof(std::vector); unsigned long mem = 0; for (unsigned i = 0; i < v.size(); ++i) { mem += v[i].getMemory(verbosity - 1); } print("vector+data", verbosity, memSelf, mem); return memSelf + mem; } template static unsigned long getVecAndDataP(int verbosity, const std::vector& v) { unsigned long memSelf = sizeof(std::vector); unsigned long mem = 0; for (unsigned i = 0; i < v.size(); ++i) { mem += v[i]->getMemory(verbosity - 1); } print("vector+data(p)", verbosity, memSelf, mem); return memSelf + mem; } static unsigned long getString(int verbosity, const std::string& s) { unsigned long memSelf = sizeof(std::string); unsigned long mem = s.capacity() * sizeof(char); print("string", verbosity, memSelf, mem); return memSelf + mem; } // template // unsigned long get(int verbosity, const hash_table<_Key, _Value, _HashFcn, // unsigned long memSelf = sizeof(BucketNode); // unsigned long mem = 0; // BucketNode* node = this; // do { // if (getMemoryData) { // mem += d_value.getMemory(verbosity // node = node->d_next; // } while (node != NULL) // unsigned long mem = 0; // mem += getMemoryVec(verbosity - 1, d_data, false, true); // printMemory("hash_table", verbosity, memSelf, mem); // return mem+memSelf; // } // unsigned long getMemory(int verbosity, hash_table) { // unsigned long memSelf = sizeof(hash_table); // unsigned long mem = 0; // mem += d_hash.getmemory(verbosity - 1) - sizeof(hasher); // mem += d_equal.getmemory(verbosity - 1) - sizeof(key_equal); // mem += d_extractKey.getmemory(verbosity - 1) - sizeof(_ExtractKey); // // handle data // mem += sizeof(Data); // mem += sizeof(Bucket*)*d_data.capacity(); // for (unsigned i = 0; i < d_data.size(); ++i) { // mem += d_data[i]->getMemory(verbosity - 1, getMemoryData, getMemoryDataP); // } // printMemory("hash_table", verbosity, memSelf, mem); // return mem+memSelf; // } // unsigned long getMemory(int verbosity, hash_map) const { // unsigned long memSelf = sizeof(hash_map); // unsigned long mem = 0; // mem += d_table.getMemory(verbosity - 1) - sizeof(_hash_table); // MemoryTracker::print("hash_map", verbosity, memSelf, mem); // return mem+memSelf; // } }; // End of MemoryTracker } #endif cvc3-2.4.1/src/include/vc.h0000644000175400017540000012214111624746722015263 0ustar mdetersmdeters/*****************************************************************************/ /*! * \file vc.h * \brief Generic API for a validity checker * * Author: Clark Barrett * * Created: Tue Nov 26 17:45:10 2002 * *
* * License to use, copy, modify, sell and/or distribute this software * and its documentation for any purpose is hereby granted without * royalty, subject to the terms and conditions defined in the \ref * LICENSE file provided with this distribution. * *
* */ /*****************************************************************************/ #ifndef _cvc3__include__vc_h_ #define _cvc3__include__vc_h_ #include "os.h" #include "queryresult.h" #include "expr.h" #include "formula_value.h" /*****************************************************************************/ /*! Note that this list of modules is very incomplete */ /*****************************************************************************/ /*****************************************************************************/ /*! *\defgroup CVC3 CVC3 *\brief The top level group which includes all of CVC3 documentation. *@{ */ /*****************************************************************************/ /*****************************************************************************/ /*! *\defgroup BuildingBlocks Building Blocks *\brief Code providing basic infrastructure */ /*****************************************************************************/ /*****************************************************************************/ /*! *\defgroup VC Validity Checker *\brief The modules that make up the validity checker */ /*****************************************************************************/ /*@}*/ // end of group CVC3 /*****************************************************************************/ /*! *\defgroup VC_API Validity Checker API * \ingroup VC *\brief The library interface of the validity checker (class ValidityChecker) */ /*****************************************************************************/ namespace CVC3 { class Context; class CLFlags; class Statistics; /*****************************************************************************/ /*! *\class ValidityChecker *\brief Generic API for a validity checker *\ingroup VC_API *\anchor vc * * Author: Clark Barrett * * Created: Tue Nov 26 18:24:25 2002 * * All terms and formulas are represented as expressions using the Expr class. * The notion of a context is also important. A context is a "background" set * of formulas which are assumed to be true or false. Formulas can be added to * the context explicitly, using assertFormula, or they may be added as part of * processing a query command. At any time, the current set of formulas making * up the context can be retrieved using getAssumptions. */ /*****************************************************************************/ class CVC_DLL ValidityChecker { public: //! Constructor ValidityChecker() {} //! Destructor virtual ~ValidityChecker() {} //! Return the set of command-line flags /*! The flags are returned by reference, and if modified, will have an immediate effect on the subsequent commands. Note that not all flags will have such an effect; some flags are used only at initialization time (like "sat"), and therefore, will not take effect if modified after ValidityChecker is created. */ virtual CLFlags& getFlags() const = 0; //! Force reprocessing of all flags virtual void reprocessFlags() = 0; /***************************************************************************/ /* * Static methods */ /***************************************************************************/ //! Create the set of command line flags with default values; /*! \return the set of flags by value */ static CLFlags createFlags(); //! Create an instance of ValidityChecker /*! \param flags is the set of command line flags. */ static ValidityChecker* create(const CLFlags& flags); //! Create an instance of ValidityChecker using default flag values. static ValidityChecker* create(); /***************************************************************************/ /*! *\name Type-related methods * Methods for creating and looking up types *\sa class Type *@{ */ /***************************************************************************/ // Basic types virtual Type boolType() = 0; //!< Create type BOOLEAN virtual Type realType() = 0; //!< Create type REAL virtual Type intType() = 0; //!< Create type INT //! Create a subrange type [l..r] /*! l and r can be Null; l=Null represents minus infinity, r=Null is * plus infinity. */ virtual Type subrangeType(const Expr& l, const Expr& r) = 0; //! Creates a subtype defined by the given predicate /*! * \param pred is a predicate taking one argument of type T and returning * Boolean. The resulting type is a subtype of T whose elements x are those * satisfying the predicate pred(x). * * \param witness is an expression of type T for which pred holds (if a Null * expression is passed as a witness, cvc will try to prove \f$\exists x. pred(x))\f$. * if the witness check fails, a TypecheckException is thrown. */ virtual Type subtypeType(const Expr& pred, const Expr& witness) = 0; // Tuple types //! 2-element tuple virtual Type tupleType(const Type& type0, const Type& type1) = 0; //! 3-element tuple virtual Type tupleType(const Type& type0, const Type& type1, const Type& type2) = 0; //! n-element tuple (from a vector of types) virtual Type tupleType(const std::vector& types) = 0; // Record types //! 1-element record virtual Type recordType(const std::string& field, const Type& type) = 0; //! 2-element record /*! Fields will be sorted automatically */ virtual Type recordType(const std::string& field0, const Type& type0, const std::string& field1, const Type& type1) = 0; //! 3-element record /*! Fields will be sorted automatically */ virtual Type recordType(const std::string& field0, const Type& type0, const std::string& field1, const Type& type1, const std::string& field2, const Type& type2) = 0; //! n-element record (fields and types must be of the same length) /*! Fields will be sorted automatically */ virtual Type recordType(const std::vector& fields, const std::vector& types) = 0; // Datatypes //! Single datatype, single constructor /*! The types are either type exressions (obtained from a type with * getExpr()) or string expressions containing the name of (one of) the * dataType(s) being defined. */ virtual Type dataType(const std::string& name, const std::string& constructor, const std::vector& selectors, const std::vector& types) = 0; //! Single datatype, multiple constructors /*! The types are either type exressions (obtained from a type with * getExpr()) or string expressions containing the name of (one of) the * dataType(s) being defined. */ virtual Type dataType(const std::string& name, const std::vector& constructors, const std::vector >& selectors, const std::vector >& types) = 0; //! Multiple datatypes /*! The types are either type exressions (obtained from a type with * getExpr()) or string expressions containing the name of (one of) the * dataType(s) being defined. */ virtual void dataType(const std::vector& names, const std::vector >& constructors, const std::vector > >& selectors, const std::vector > >& types, std::vector& returnTypes) = 0; //! Create an array type (ARRAY typeIndex OF typeData) virtual Type arrayType(const Type& typeIndex, const Type& typeData) = 0; //! Create a bitvector type of length n virtual Type bitvecType(int n) = 0; //! Create a function type typeDom -> typeRan virtual Type funType(const Type& typeDom, const Type& typeRan) = 0; //! Create a function type (t1,t2,...,tn) -> typeRan virtual Type funType(const std::vector& typeDom, const Type& typeRan) = 0; //! Create named user-defined uninterpreted type virtual Type createType(const std::string& typeName) = 0; //! Create named user-defined interpreted type (type abbreviation) virtual Type createType(const std::string& typeName, const Type& def) = 0; //! Lookup a user-defined (uninterpreted) type by name. Returns Null if none. virtual Type lookupType(const std::string& typeName) = 0; /*@}*/ // End of Type-related methods /***************************************************************************/ /*! *\name General Expr methods *\sa class Expr *\sa class ExprManager *@{ */ /***************************************************************************/ //! Return the ExprManager virtual ExprManager* getEM() = 0; //! Create a variable with a given name and type /*! \param name is the name of the variable \param type is its type. The type cannot be a function type. \return an Expr representation of a new variable */ virtual Expr varExpr(const std::string& name, const Type& type) = 0; //! Create a variable with a given name, type, and value virtual Expr varExpr(const std::string& name, const Type& type, const Expr& def) = 0; //! Get the variable associated with a name, and its type /*! \param name is the variable name \param type is where the type value is returned \return a variable by the name. If there is no such Expr, a NULL \ Expr is returned. */ virtual Expr lookupVar(const std::string& name, Type* type) = 0; //! Get the type of the Expr. virtual Type getType(const Expr& e) = 0; //! Get the largest supertype of the Expr. virtual Type getBaseType(const Expr& e) = 0; //! Get the largest supertype of the Type. virtual Type getBaseType(const Type& t) = 0; //! Get the subtype predicate virtual Expr getTypePred(const Type&t, const Expr& e) = 0; //! Create a string Expr virtual Expr stringExpr(const std::string& str) = 0; //! Create an ID Expr virtual Expr idExpr(const std::string& name) = 0; //! Create a list Expr /*! Intermediate representation for DP-specific expressions. * Normally, the first element of the list is a string Expr * representing an operator, and the rest of the list are the * arguments. For example, * * kids.push_back(vc->stringExpr("PLUS")); * kids.push_back(x); // x and y are previously created Exprs * kids.push_back(y); * Expr lst = vc->listExpr(kids); * * Or, alternatively (using its overloaded version): * * Expr lst = vc->listExpr("PLUS", x, y); * * or * * vector summands; * summands.push_back(x); summands.push_back(y); ... * Expr lst = vc->listExpr("PLUS", summands); */ virtual Expr listExpr(const std::vector& kids) = 0; //! Overloaded version of listExpr with one argument virtual Expr listExpr(const Expr& e1) = 0; //! Overloaded version of listExpr with two arguments virtual Expr listExpr(const Expr& e1, const Expr& e2) = 0; //! Overloaded version of listExpr with three arguments virtual Expr listExpr(const Expr& e1, const Expr& e2, const Expr& e3) = 0; //! Overloaded version of listExpr with string operator and many arguments virtual Expr listExpr(const std::string& op, const std::vector& kids) = 0; //! Overloaded version of listExpr with string operator and one argument virtual Expr listExpr(const std::string& op, const Expr& e1) = 0; //! Overloaded version of listExpr with string operator and two arguments virtual Expr listExpr(const std::string& op, const Expr& e1, const Expr& e2) = 0; //! Overloaded version of listExpr with string operator and three arguments virtual Expr listExpr(const std::string& op, const Expr& e1, const Expr& e2, const Expr& e3) = 0; //! Prints e to the standard output virtual void printExpr(const Expr& e) = 0; //! Prints e to the given ostream virtual void printExpr(const Expr& e, std::ostream& os) = 0; //! Parse an expression using a Theory-specific parser virtual Expr parseExpr(const Expr& e) = 0; //! Parse a type expression using a Theory-specific parser virtual Type parseType(const Expr& e) = 0; //! Import the Expr from another instance of ValidityChecker /*! When expressions need to be passed among several instances of * ValidityChecker, they need to be explicitly imported into the * corresponding instance using this method. The return result is * an identical expression that belongs to the current instance of * ValidityChecker, and can be safely used as part of more complex * expressions from the same instance. */ virtual Expr importExpr(const Expr& e) = 0; //! Import the Type from another instance of ValidityChecker /*! \sa getType() */ virtual Type importType(const Type& t) = 0; //! Parse a sequence of commands from a presentation language string virtual void cmdsFromString(const std::string& s, InputLanguage lang=PRESENTATION_LANG) = 0; //! Parse an expression from a presentation language string virtual Expr exprFromString(const std::string& e) = 0; /*@}*/ // End of General Expr Methods /***************************************************************************/ /*! *\name Core expression methods * Methods for manipulating core expressions * * Except for equality and ite, the children provided as arguments must be of * type Boolean. *@{ */ /***************************************************************************/ //! Return TRUE Expr virtual Expr trueExpr() = 0; //! Return FALSE Expr virtual Expr falseExpr() = 0; //! Create negation virtual Expr notExpr(const Expr& child) = 0; //! Create 2-element conjunction virtual Expr andExpr(const Expr& left, const Expr& right) = 0; //! Create n-element conjunction virtual Expr andExpr(const std::vector& children) = 0; //! Create 2-element disjunction virtual Expr orExpr(const Expr& left, const Expr& right) = 0; //! Create n-element disjunction virtual Expr orExpr(const std::vector& children) = 0; //! Create Boolean implication virtual Expr impliesExpr(const Expr& hyp, const Expr& conc) = 0; //! Create left IFF right (boolean equivalence) virtual Expr iffExpr(const Expr& left, const Expr& right) = 0; //! Create an equality expression. /*! The two children must have the same type, and cannot be of type Boolean. */ virtual Expr eqExpr(const Expr& child0, const Expr& child1) = 0; //! Create IF ifpart THEN thenpart ELSE elsepart ENDIF /*! \param ifpart must be of type Boolean. \param thenpart and \param elsepart must have the same type, which will also be the type of the ite expression. */ virtual Expr iteExpr(const Expr& ifpart, const Expr& thenpart, const Expr& elsepart) = 0; /** * Create an expression asserting that all the children are different. * @param children the children to be asserted different */ virtual Expr distinctExpr(const std::vector& children) = 0; /*@}*/ // End of Core expression methods /***************************************************************************/ /*! *\name User-defined (uninterpreted) function methods * Methods for manipulating uninterpreted function expressions *@{ */ /***************************************************************************/ //! Create a named uninterpreted function with a given type /*! \param name is the new function's name (as ID Expr) \param type is a function type ( [range -> domain] ) */ virtual Op createOp(const std::string& name, const Type& type) = 0; //! Create a named user-defined function with a given type virtual Op createOp(const std::string& name, const Type& type, const Expr& def) = 0; //! Get the Op associated with a name, and its type /*! \param name is the operator name \param type is where the type value is returned \return an Op by the name. If there is no such Op, a NULL \ Op is returned. */ virtual Op lookupOp(const std::string& name, Type* type) = 0; //! Unary function application (op must be of function type) virtual Expr funExpr(const Op& op, const Expr& child) = 0; //! Binary function application (op must be of function type) virtual Expr funExpr(const Op& op, const Expr& left, const Expr& right) = 0; //! Ternary function application (op must be of function type) virtual Expr funExpr(const Op& op, const Expr& child0, const Expr& child1, const Expr& child2) = 0; //! n-ary function application (op must be of function type) virtual Expr funExpr(const Op& op, const std::vector& children) = 0; /*@}*/ // End of User-defined (uninterpreted) function methods /***************************************************************************/ /*! *\name Arithmetic expression methods * Methods for manipulating arithmetic expressions * * These functions create arithmetic expressions. The children provided * as arguments must be of type Real. *@{ */ /***************************************************************************/ /*! * Add the pair of variables to the variable ordering for aritmetic solving. * Terms that are not arithmetic will be ignored. * \param smaller the smaller variable * \param bigger the bigger variable */ virtual bool addPairToArithOrder(const Expr& smaller, const Expr& bigger) = 0; //! Create a rational number with numerator n and denominator d. /*! \param n the numerator \param d the denominator, cannot be 0. */ virtual Expr ratExpr(int n, int d = 1) = 0; //! Create a rational number with numerator n and denominator d. /*! Here n and d are given as strings. They are converted to arbitrary-precision integers according to the given base. */ virtual Expr ratExpr(const std::string& n, const std::string& d, int base) = 0; //! Create a rational from a single string. /*! \param n can be a string containing an integer, a pair of integers "nnn/ddd", or a number in the fixed or floating point format. \param base is the base in which to interpret the string. */ virtual Expr ratExpr(const std::string& n, int base = 10) = 0; //! Unary minus. virtual Expr uminusExpr(const Expr& child) = 0; //! Create 2-element sum (left + right) virtual Expr plusExpr(const Expr& left, const Expr& right) = 0; //! Create n-element sum virtual Expr plusExpr(const std::vector& children) = 0; //! Make a difference (left - right) virtual Expr minusExpr(const Expr& left, const Expr& right) = 0; //! Create a product (left * right) virtual Expr multExpr(const Expr& left, const Expr& right) = 0; //! Create a power expression (x ^ n); n must be integer virtual Expr powExpr(const Expr& x, const Expr& n) = 0; //! Create expression x / y virtual Expr divideExpr(const Expr& numerator, const Expr& denominator) = 0; //! Create (left < right) virtual Expr ltExpr(const Expr& left, const Expr& right) = 0; //! Create (left <= right) virtual Expr leExpr(const Expr& left, const Expr& right) = 0; //! Create (left > right) virtual Expr gtExpr(const Expr& left, const Expr& right) = 0; //! Create (left >= right) virtual Expr geExpr(const Expr& left, const Expr& right) = 0; /*@}*/ // End of Arithmetic expression methods /***************************************************************************/ /*! *\name Record expression methods * Methods for manipulating record expressions *@{ */ /***************************************************************************/ //! Create a 1-element record value (# field := expr #) /*! Fields will be sorted automatically */ virtual Expr recordExpr(const std::string& field, const Expr& expr) = 0; //! Create a 2-element record value (# field0 := expr0, field1 := expr1 #) /*! Fields will be sorted automatically */ virtual Expr recordExpr(const std::string& field0, const Expr& expr0, const std::string& field1, const Expr& expr1) = 0; //! Create a 3-element record value (# field_i := expr_i #) /*! Fields will be sorted automatically */ virtual Expr recordExpr(const std::string& field0, const Expr& expr0, const std::string& field1, const Expr& expr1, const std::string& field2, const Expr& expr2) = 0; //! Create an n-element record value (# field_i := expr_i #) /*! * \param fields * \param exprs must be the same length as fields * * Fields will be sorted automatically */ virtual Expr recordExpr(const std::vector& fields, const std::vector& exprs) = 0; //! Create record.field (field selection) /*! Create an expression representing the selection of a field from a record. */ virtual Expr recSelectExpr(const Expr& record, const std::string& field) = 0; //! Record update; equivalent to "record WITH .field := newValue" /*! Notice the `.' before field in the presentation language (and the comment above); this is to distinguish it from datatype update. */ virtual Expr recUpdateExpr(const Expr& record, const std::string& field, const Expr& newValue) = 0; /*@}*/ // End of Record expression methods /***************************************************************************/ /*! *\name Array expression methods * Methods for manipulating array expressions *@{ */ /***************************************************************************/ //! Create an expression array[index] (array access) /*! Create an expression for the value of array at the given index */ virtual Expr readExpr(const Expr& array, const Expr& index) = 0; //! Array update; equivalent to "array WITH index := newValue" virtual Expr writeExpr(const Expr& array, const Expr& index, const Expr& newValue) = 0; /*@}*/ // End of Array expression methods /***************************************************************************/ /*! *\name Bitvector expression methods * Methods for manipulating bitvector expressions *@{ */ /***************************************************************************/ // Bitvector constants // From a string of digits in a given base virtual Expr newBVConstExpr(const std::string& s, int base = 2) = 0; // From a vector of bools virtual Expr newBVConstExpr(const std::vector& bits) = 0; // From a rational: bitvector is of length 'len', or the min. needed length when len=0. virtual Expr newBVConstExpr(const Rational& r, int len = 0) = 0; // Concat and extract virtual Expr newConcatExpr(const Expr& t1, const Expr& t2) = 0; virtual Expr newConcatExpr(const std::vector& kids) = 0; virtual Expr newBVExtractExpr(const Expr& e, int hi, int low) = 0; // Bitwise Boolean operators: Negation, And, Nand, Or, Nor, Xor, Xnor virtual Expr newBVNegExpr(const Expr& t1) = 0; virtual Expr newBVAndExpr(const Expr& t1, const Expr& t2) = 0; virtual Expr newBVAndExpr(const std::vector& kids) = 0; virtual Expr newBVOrExpr(const Expr& t1, const Expr& t2) = 0; virtual Expr newBVOrExpr(const std::vector& kids) = 0; virtual Expr newBVXorExpr(const Expr& t1, const Expr& t2) = 0; virtual Expr newBVXorExpr(const std::vector& kids) = 0; virtual Expr newBVXnorExpr(const Expr& t1, const Expr& t2) = 0; virtual Expr newBVXnorExpr(const std::vector& kids) = 0; virtual Expr newBVNandExpr(const Expr& t1, const Expr& t2) = 0; virtual Expr newBVNorExpr(const Expr& t1, const Expr& t2) = 0; virtual Expr newBVCompExpr(const Expr& t1, const Expr& t2) = 0; // Unsigned bitvector inequalities virtual Expr newBVLTExpr(const Expr& t1, const Expr& t2) = 0; virtual Expr newBVLEExpr(const Expr& t1, const Expr& t2) = 0; // Signed bitvector inequalities virtual Expr newBVSLTExpr(const Expr& t1, const Expr& t2) = 0; virtual Expr newBVSLEExpr(const Expr& t1, const Expr& t2) = 0; // Sign-extend t1 to a total of len bits virtual Expr newSXExpr(const Expr& t1, int len) = 0; // Bitvector arithmetic: unary minus, plus, subtract, multiply virtual Expr newBVUminusExpr(const Expr& t1) = 0; virtual Expr newBVSubExpr(const Expr& t1, const Expr& t2) = 0; //! 'numbits' is the number of bits in the result virtual Expr newBVPlusExpr(int numbits, const std::vector& k) = 0; virtual Expr newBVPlusExpr(int numbits, const Expr& t1, const Expr& t2) = 0; virtual Expr newBVMultExpr(int numbits, const Expr& t1, const Expr& t2) = 0; virtual Expr newBVUDivExpr(const Expr& t1, const Expr& t2) = 0; virtual Expr newBVURemExpr(const Expr& t1, const Expr& t2) = 0; virtual Expr newBVSDivExpr(const Expr& t1, const Expr& t2) = 0; virtual Expr newBVSRemExpr(const Expr& t1, const Expr& t2) = 0; virtual Expr newBVSModExpr(const Expr& t1, const Expr& t2) = 0; // Left shift by r bits: result is old size + r bits virtual Expr newFixedLeftShiftExpr(const Expr& t1, int r) = 0; // Left shift by r bits: result is same size as t1 virtual Expr newFixedConstWidthLeftShiftExpr(const Expr& t1, int r) = 0; // Logical right shift by r bits: result is same size as t1 virtual Expr newFixedRightShiftExpr(const Expr& t1, int r) = 0; // Left shift with shift parameter an arbitrary bit-vector expr virtual Expr newBVSHL(const Expr& t1, const Expr& t2) = 0; // Logical right shift with shift parameter an arbitrary bit-vector expr virtual Expr newBVLSHR(const Expr& t1, const Expr& t2) = 0; // Arithmetic right shift with shift parameter an arbitrary bit-vector expr virtual Expr newBVASHR(const Expr& t1, const Expr& t2) = 0; // Get value of BV Constant virtual Rational computeBVConst(const Expr& e) = 0; /*@}*/ // End of Bitvector expression methods /***************************************************************************/ /*! *\name Other expression methods * Methods for manipulating other kinds of expressions *@{ */ /***************************************************************************/ //! Tuple expression virtual Expr tupleExpr(const std::vector& exprs) = 0; //! Tuple select; equivalent to "tuple.n", where n is an numeral (e.g. tup.5) virtual Expr tupleSelectExpr(const Expr& tuple, int index) = 0; //! Tuple update; equivalent to "tuple WITH index := newValue" virtual Expr tupleUpdateExpr(const Expr& tuple, int index, const Expr& newValue) = 0; //! Datatype constructor expression virtual Expr datatypeConsExpr(const std::string& constructor, const std::vector& args) = 0; //! Datatype selector expression virtual Expr datatypeSelExpr(const std::string& selector, const Expr& arg) = 0; //! Datatype tester expression virtual Expr datatypeTestExpr(const std::string& constructor, const Expr& arg) = 0; //! Create a bound variable with a given name, unique ID (uid) and type /*! \param name is the name of the variable \param uid is the unique ID (a string), which must be unique for each variable \param type is its type. The type cannot be a function type. \return an Expr representation of a new variable */ virtual Expr boundVarExpr(const std::string& name, const std::string& uid, const Type& type) = 0; //! Universal quantifier virtual Expr forallExpr(const std::vector& vars, const Expr& body) = 0; //! Universal quantifier with a trigger virtual Expr forallExpr(const std::vector& vars, const Expr& body, const Expr& trigger) = 0; //! Universal quantifier with a set of triggers. virtual Expr forallExpr(const std::vector& vars, const Expr& body, const std::vector& triggers) = 0; //! Universal quantifier with a set of multi-triggers. virtual Expr forallExpr(const std::vector& vars, const Expr& body, const std::vector >& triggers) = 0; //! Set triggers for quantifier instantiation /*! * \param e the expression for which triggers are being set. * \param triggers Each item in triggers is a vector of Expr containing one * or more patterns. A pattern is a term or Atomic predicate sub-expression * of e. A vector containing more than one pattern is treated as a * multi-trigger. Patterns will be matched in the order they occur in * the vector. */ virtual void setTriggers(const Expr& e, const std::vector > & triggers) = 0; //! Set triggers for quantifier instantiation (no multi-triggers) virtual void setTriggers(const Expr& e, const std::vector& triggers) = 0; //! Set a single trigger for quantifier instantiation virtual void setTrigger(const Expr& e, const Expr& trigger) = 0; //! Set a single multi-trigger for quantifier instantiation virtual void setMultiTrigger(const Expr& e, const std::vector& multiTrigger) = 0; //! Existential quantifier virtual Expr existsExpr(const std::vector& vars, const Expr& body) = 0; //! Lambda-expression virtual Op lambdaExpr(const std::vector& vars, const Expr& body) = 0; //! Transitive closure of a binary predicate virtual Op transClosure(const Op& op) = 0; //! Symbolic simulation expression /*! * \param f is the next state function (LAMBDA-expression) * \param s0 is the initial state * \param inputs is the vector of LAMBDA-expressions representing * the sequences of inputs to f * \param n is a constant, the number of cycles to run the simulation. */ virtual Expr simulateExpr(const Expr& f, const Expr& s0, const std::vector& inputs, const Expr& n) = 0; /*@}*/ // End of Other expression methods /***************************************************************************/ /*! *\name Validity checking methods * Methods related to validity checking * * This group includes methods for asserting formulas, checking * validity in the given logical context, manipulating the scope * level of the context, etc. *@{ */ /***************************************************************************/ //! Set the resource limit (0==unlimited, 1==exhausted). /*! Currently, the limit is the total number of processed facts. */ virtual void setResourceLimit(unsigned limit) = 0; //! Set a time limit in tenth of a second, /*! counting the cpu time used by the current process from now on. * Currently, when the limit is reached, cvc3 tries to quickly * terminate, probably with the status unknown. */ virtual void setTimeLimit(unsigned limit) = 0; //! Assert a new formula in the current context. /*! This creates the assumption e |- e. The formula must have Boolean type. */ virtual void assertFormula(const Expr& e) = 0; //! Register an atomic formula of interest. /*! Registered atoms are tracked by the decision procedures. If one of them is deduced to be true or false, it is added to a list of implied literals. Implied literals can be retrieved with the getImpliedLiteral function */ virtual void registerAtom(const Expr& e) = 0; //! Return next literal implied by last assertion. Null Expr if none. /*! Returned literals are either registered atomic formulas or their negation */ virtual Expr getImpliedLiteral() = 0; //! Simplify e with respect to the current context virtual Expr simplify(const Expr& e) = 0; //! Check validity of e in the current context. /*! If it returns VALID, the scope and context are the same * as when called. If it returns INVALID, the context will be one which * falsifies the query. If it returns UNKNOWN, the context will falsify the * query, but the context may be inconsistent. Finally, if it returns * ABORT, the context will be one which satisfies as much as possible. * * \param e is the queried formula */ virtual QueryResult query(const Expr& e) = 0; //! Check satisfiability of the expr in the current context. /*! Equivalent to query(!e) */ virtual QueryResult checkUnsat(const Expr& e) = 0; //! Get the next model /*! This method should only be called after a query which returns INVALID. Its return values are as for query(). */ virtual QueryResult checkContinue() = 0; //! Restart the most recent query with e as an additional assertion. /*! This method should only be called after a query which returns INVALID. Its return values are as for query(). */ virtual QueryResult restart(const Expr& e) = 0; //! Returns to context immediately before last invalid query. /*! This method should only be called after a query which returns false. */ virtual void returnFromCheck() = 0; //! Get assumptions made by the user in this and all previous contexts. /*! User assumptions are created either by calls to assertFormula or by a * call to query. In the latter case, the negated query is added as an * assumption. * \param assumptions should be empty on entry. */ virtual void getUserAssumptions(std::vector& assumptions) = 0; //! Get assumptions made internally in this and all previous contexts. /*! Internal assumptions are literals assumed by the sat solver. * \param assumptions should be empty on entry. */ virtual void getInternalAssumptions(std::vector& assumptions) = 0; //! Get all assumptions made in this and all previous contexts. /*! \param assumptions should be empty on entry. */ virtual void getAssumptions(std::vector& assumptions) = 0; //! Returns the set of assumptions used in the proof of queried formula. /*! It returns a subset of getAssumptions(). If the last query was false * or there has not yet been a query, it does nothing. * NOTE: this functionality is not supported yet * \param assumptions should be empty on entry. */ virtual void getAssumptionsUsed(std::vector& assumptions) = 0; virtual Expr getProofQuery() = 0; //! Return the internal assumptions that make the queried formula false. /*! This method should only be called after a query which returns false. It will try to return the simplest possible subset of the internal assumptions sufficient to make the queried expression false. \param assumptions should be empty on entry. \param inOrder if true, returns the assumptions in the order they were made. This is slightly more expensive than inOrder = false. */ virtual void getCounterExample(std::vector& assumptions, bool inOrder=true) = 0; //! Will assign concrete values to all user created variables /*! This function should only be called after a query which return false. */ virtual void getConcreteModel(ExprMap & m) = 0; //! If the result of the last query was UNKNOWN try to actually build the model //! to verify the result. /*! This function should only be called after a query which return unknown. */ virtual QueryResult tryModelGeneration() = 0; //:ALEX: returns the current truth value of a formula // returns UNKNOWN_VAL if e is not associated // with a boolean variable in the SAT module, // i.e. if its value can not determined without search. virtual FormulaValue value(const Expr& e) = 0; //! Returns true if the current context is inconsistent. /*! Also returns a minimal set of assertions used to determine the inconsistency. \param assumptions should be empty on entry. */ virtual bool inconsistent(std::vector& assumptions) = 0; //! Returns true if the current context is inconsistent. virtual bool inconsistent() = 0; //! Returns true if the invalid result from last query() is imprecise /*! * Some decision procedures in CVC are incomplete (quantifier * elimination, non-linear arithmetic, etc.). If any incomplete * features were used during the last query(), and the result is * "invalid" (query() returns false), then this result is * inconclusive. It means that the system gave up the search for * contradiction at some point. */ virtual bool incomplete() = 0; //! Returns true if the invalid result from last query() is imprecise /*! * \sa incomplete() * * The argument is filled with the reasons for incompleteness (they * are intended to be shown to the end user). */ virtual bool incomplete(std::vector& reasons) = 0; //! Returns the proof term for the last proven query /*! If there has not been a successful query, it should return a NULL proof */ virtual Proof getProof() = 0; //! Evaluate an expression and return a concrete value in the model /*! If the last query was not invalid, should return NULL expr */ virtual Expr getValue(Expr e) = 0; //! Returns the list of pairs (name value) for each :named attribute. /*! If the last query was not invalid, should return NULL expr */ virtual Expr getAssignment() = 0; //! Returns the TCC of the last assumption or query /*! Returns Null if no assumptions or queries were performed. */ virtual Expr getTCC() = 0; //! Return the set of assumptions used in the proof of the last TCC virtual void getAssumptionsTCC(std::vector& assumptions) = 0; //! Returns the proof of TCC of the last assumption or query /*! Returns Null if no assumptions or queries were performed. */ virtual Proof getProofTCC() = 0; //! After successful query, return its closure |- Gamma => phi /*! Turn a valid query Gamma |- phi into an implication * |- Gamma => phi. * * Returns Null if last query was invalid. */ virtual Expr getClosure() = 0; //! Construct a proof of the query closure |- Gamma => phi /*! Returns Null if last query was Invalid. */ virtual Proof getProofClosure() = 0; /*@}*/ // End of Validity checking methods /***************************************************************************/ /*! *\name Context methods * Methods for manipulating contexts * * Contexts support stack-based push and pop. There are two * separate notions of the current context stack. stackLevel(), push(), * pop(), and popto() work with the user-level notion of the stack. * * scopeLevel(), pushScope(), popScope(), and poptoScope() work with * the internal stack which is more fine-grained than the user * stack. * * Do not use the scope methods unless you know what you are doing. * *@{ */ /***************************************************************************/ //! Returns the current stack level. Initial level is 0. virtual int stackLevel() = 0; //! Checkpoint the current context and increase the scope level virtual void push() = 0; //! Restore the current context to its state at the last checkpoint virtual void pop() = 0; //! Restore the current context to the given stackLevel. /*! \param stackLevel should be greater than or equal to 0 and less than or equal to the current scope level. */ virtual void popto(int stackLevel) = 0; //! Returns the current scope level. Initially, the scope level is 1. virtual int scopeLevel() = 0; /*! @brief Checkpoint the current context and increase the * internal scope level. Do not use unless you * know what you're doing! */ virtual void pushScope() = 0; /*! @brief Restore the current context to its state at the last * internal checkpoint. Do not use unless you know * what you're doing! */ virtual void popScope() = 0; //! Restore the current context to the given scopeLevel. /*! \param scopeLevel should be less than or equal to the current scope level. If scopeLevel is less than 1, then the current context is reset and the scope level is set to 1. */ virtual void poptoScope(int scopeLevel) = 0; //! Get the current context virtual Context* getCurrentContext() = 0; //! Destroy and recreate validity checker: resets everything except for flags virtual void reset() = 0; //! Add an annotation to the current script - prints annot when translating virtual void logAnnotation(const Expr& annot) = 0; /*@}*/ // End of Context methods /***************************************************************************/ /*! *\name Reading files * Methods for reading external files *@{ */ /***************************************************************************/ //! Read and execute the commands from a file given by name ("" means stdin) virtual void loadFile(const std::string& fileName, InputLanguage lang = PRESENTATION_LANG, bool interactive = false, bool calledFromParser = false) = 0; //! Read and execute the commands from a stream virtual void loadFile(std::istream& is, InputLanguage lang = PRESENTATION_LANG, bool interactive = false) = 0; /*@}*/ // End of methods for reading files /***************************************************************************/ /*! *\name Reporting Statistics * Methods for collecting and reporting run-time statistics *@{ */ /***************************************************************************/ //! Get statistics object virtual Statistics& getStatistics() = 0; //! Print collected statistics to stdout virtual void printStatistics() = 0; /*@}*/ // End of Statistics Methods }; // End of class ValidityChecker } // End of namespace CVC3 #endif cvc3-2.4.1/src/include/debug.h0000664000175400017540000003662011153264564015745 0ustar mdetersmdeters/*****************************************************************************/ /*! * \file debug.h * \brief Description: Collection of debugging macros and functions. * * Author: Sergey Berezin * * Created: Thu Dec 5 13:12:59 2002 * *
* * License to use, copy, modify, sell and/or distribute this software * and its documentation for any purpose is hereby granted without * royalty, subject to the terms and conditions defined in the \ref * LICENSE file provided with this distribution. * *
* */ /*****************************************************************************/ #ifndef _cvc3__debug_h #define _cvc3__debug_h #include #include #include #include #include "os.h" #include "exception.h" /*! @brief If something goes horribly wrong, print a message and abort immediately with exit(1). */ /*! This macro stays even in the non-debug build, so the end users can send us meaningful bug reports. */ #define FatalAssert(cond, msg) if(!(cond)) \ CVC3::fatalError(__FILE__, __LINE__, #cond, msg) namespace CVC3 { //! Function for fatal exit. /*! It just exits with code 1, but is provided here for the debugger to set a breakpoint to. For this reason, it is not inlined. */ extern CVC_DLL void fatalError(const std::string& file, int line, const std::string& cond, const std::string& msg); } #ifdef _CVC3_DEBUG_MODE #include "compat_hash_map.h" #include "compat_hash_set.h" //! Any debugging code must be within IF_DEBUG(...) #define IF_DEBUG(code) code //! Print a value conditionally. /*! If 'cond' is true, print 'pre', then 'v', then 'post'. The type of v must have overloaded operator<<. It expects a ';' after it. */ #define DBG_PRINT(cond, pre, v, post) if(cond) CVC3::debugger.getOS() \ << (pre) << (v) << (post) << std::endl //! Print a message conditionally #define DBG_PRINT_MSG(cond, msg) \ if(cond) CVC3::debugger.getOS() << (msg) << std::endl /*! @brief Same as DBG_PRINT, only takes a flag name instead of a general condition */ #define TRACE(flag, pre, v, post) \ DBG_PRINT(CVC3::debugger.trace(flag), pre, v, post) //! Same as TRACE, but for a simple message #define TRACE_MSG(flag, msg) \ DBG_PRINT_MSG(CVC3::debugger.trace(flag), msg) //! Sanity check for debug build. It disappears in the production code. #define DebugAssert(cond, str) if(!(cond)) \ CVC3::debugError(__FILE__, __LINE__, #cond, str) namespace CVC3 { class Expr; //! Our exception to throw class DebugException: public Exception { public: // Constructor DebugException(const std::string& msg): Exception(msg) { } // Printing virtual std::string toString() const { return "Assertion violation " + d_msg; } }; // end of class DebugException //! Similar to fatalError to raise an exception when DebugAssert fires. /*! This does not necessarily cause the program to quit. */ extern CVC_DLL void debugError(const std::string& file, int line, const std::string& cond, const std::string& msg); // First, wrapper classes for flags, counters, and timers. Later, // we overload some operators like '=', '++', etc. for those // classes. //! Boolean flag (can only be true or false) class DebugFlag { private: bool* d_flag; // We don't own the pointer public: // Constructor: takes the pointer to the actual flag, normally // stored in class Debug below. DebugFlag(bool& flag) : d_flag(&flag) { } // Destructor ~DebugFlag() { } // Auto-cast to boolean operator bool() { return *d_flag; } // Setting and resetting by ++ and -- // Prefix versions: bool operator--() { *d_flag = false; return false; } bool operator++() { *d_flag = true; return true; } // Postfix versions: bool operator--(int) { bool x=*d_flag; *d_flag=false; return x; } bool operator++(int) { bool x=*d_flag; *d_flag=true; return x; } // Can be assigned only a boolean value DebugFlag& operator=(bool x) { *d_flag=(x!=false); return *this; } // Comparisons friend bool operator==(const DebugFlag& f1, const DebugFlag& f2); friend bool operator!=(const DebugFlag& f1, const DebugFlag& f2); // Printing friend std::ostream& operator<<(std::ostream& os, const DebugFlag& f); }; // end of class DebugFlag //! Checks if the *values* of the flags are equal inline bool operator==(const DebugFlag& f1, const DebugFlag& f2) { return (*f1.d_flag) == (*f2.d_flag); } //! Checks if the *values* of the flags are disequal inline bool operator!=(const DebugFlag& f1, const DebugFlag& f2) { return (*f1.d_flag) != (*f2.d_flag); } //! Printing flags inline std::ostream& operator<<(std::ostream& os, const DebugFlag& f) { if(*f.d_flag) return(os << "true"); else return(os << "false"); } //! Integer counter for debugging purposes. /*! Intended use is to count events (e.g. number of function calls), but can be used to store any integer value (e.g. size of some data structure) */ class DebugCounter { private: int* d_counter; //!< We don't own the pointer public: //! Constructor /*! Takes the pointer to the actual counter, normally stored in class Debug below. */ DebugCounter(int& c) : d_counter(&c) { } //! Destructor ~DebugCounter() { } //! Auto-cast to int. /*! In particular, arithmetic comparisons like <, >, <=, >= will work because of this. */ operator int() { return *d_counter; } // Auto-increment operators //! Prefix auto-decrement int operator--() { return --(*d_counter); } //! Prefix auto-increment int operator++() { return ++(*d_counter); } //! Postfix auto-decrement int operator--(int) { return (*d_counter)--; } //! Postfix auto-increment int operator++(int) { return (*d_counter)++; } //! Value assignment. DebugCounter& operator=(int x) { *d_counter=x; return *this; } DebugCounter& operator+=(int x) { *d_counter+=x; return *this; } DebugCounter& operator-=(int x) { *d_counter-=x; return *this; } //! Assignment from another counter. /*! It copies the value, not the pointer */ DebugCounter& operator=(const DebugCounter& x) { *d_counter=*x.d_counter; return *this; } /*! It copies the value, not the pointer */ DebugCounter& operator-=(const DebugCounter& x) { *d_counter-=*x.d_counter; return *this; } /*! It copies the value, not the pointer */ DebugCounter& operator+=(const DebugCounter& x) { *d_counter+=*x.d_counter; return *this; } // Comparisons to integers and other DebugCounters friend bool operator==(const DebugCounter& c1, const DebugCounter& c2); friend bool operator!=(const DebugCounter& c1, const DebugCounter& c2); friend bool operator==(int c1, const DebugCounter& c2); friend bool operator!=(int c1, const DebugCounter& c2); friend bool operator==(const DebugCounter& c1, int c2); friend bool operator!=(const DebugCounter& c1, int c2); //! Printing counters friend std::ostream& operator<<(std::ostream& os, const DebugCounter& f); }; // end of class DebugCounter inline bool operator==(const DebugCounter& c1, const DebugCounter& c2) { return (*c1.d_counter) == (*c2.d_counter); } inline bool operator!=(const DebugCounter& c1, const DebugCounter& c2) { return (*c1.d_counter) != (*c2.d_counter); } inline bool operator==(int c1, const DebugCounter& c2) { return c1 == (*c2.d_counter); } inline bool operator!=(int c1, const DebugCounter& c2) { return c1 != (*c2.d_counter); } inline bool operator==(const DebugCounter& c1, int c2) { return (*c1.d_counter) == c2; } inline bool operator!=(const DebugCounter& c1, int c2) { return (*c1.d_counter) != c2; } inline std::ostream& operator<<(std::ostream& os, const DebugCounter& c) { return (os << *c.d_counter); } //! A class holding the time value. /*! What exactly is time is not exposed. It can be the system's struct timeval, or it can be the (subset of the) user/system/real time tuple. */ class DebugTime; //! Time counter. /*! Intended use is to store time intervals or accumulated time for multiple events (e.g. time spent to execute certain lines of code, or accumulated time spent in a particular function). */ class CVC_DLL DebugTimer { private: DebugTime* d_time; //!< The time value bool d_clean_time; //!< Set if we own *d_time public: //! Constructor: takes the pointer to the actual time value. /*! It is either stored in class Debug below (then the timer is "public"), or we own it, making the timer "private". */ DebugTimer(DebugTime* time, bool take_time = false) : d_time(time), d_clean_time(take_time) { } /*! @brief Copy constructor: copy the *pointer* from public timers, and *value* from private. */ /*! The reason for different behavior for public and private time is the following. When you modify a public timer, you want the changes to show in the central database and everywhere else, whereas private timers are used as independent temporary variables holding intermediate time values. */ DebugTimer(const DebugTimer& timer); //! Assignment: same logistics as for the copy constructor DebugTimer& operator=(const DebugTimer& timer); //! Destructor ~DebugTimer(); // Operators //! Set time to zero void reset(); DebugTimer& operator+=(const DebugTimer& timer); DebugTimer& operator-=(const DebugTimer& timer); //! Produces new "private" timer DebugTimer operator+(const DebugTimer& timer); //! Produces new "private" timer DebugTimer operator-(const DebugTimer& timer); // Our friends friend class Debug; // Comparisons friend bool operator==(const DebugTimer& t1, const DebugTimer& t2); friend bool operator!=(const DebugTimer& t1, const DebugTimer& t2); friend bool operator<(const DebugTimer& t1, const DebugTimer& t2); friend bool operator>(const DebugTimer& t1, const DebugTimer& t2); friend bool operator<=(const DebugTimer& t1, const DebugTimer& t2); friend bool operator>=(const DebugTimer& t1, const DebugTimer& t2); //! Print the timer's value friend std::ostream& operator<<(std::ostream& os, const DebugTimer& timer); }; // end of class DebugTimer //! The heart of the Bug Extermination Kingdom. /*! This class exposes many important components of the entire CVC-lite system for use in debugging, keeps all the flags, counters, and timers in the central database, and provides timing and printing functions. */ class CVC_DLL Debug { private: //! Command line options for tracing; these override the TRACE command const std::vector >* d_traceOptions; //! name of dump file const std::string* d_dumpName; // Output control std::ostream* d_os; // Stream for dumping trace to file ("dump-trace" option) std::ostream* d_osDumpTrace; //! Private hasher class for strings class stringHash { public: size_t operator()(const std::string& s) const { std::hash h; return h(s.c_str()); } }; // end of stringHash // Hash tables for storing flags, counters, and timers typedef std::hash_map FlagMap; typedef std::hash_map CounterMap; typedef std::hash_map TimerMap; FlagMap d_flags; //!< Set of flags FlagMap d_traceFlags; //!< Set of trace flags CounterMap d_counters; //!< Set of counters /*! Note, that the d_timers map does *not* own the pointers; so the objects in d_timers must be destroyed explicitly in our destructor. */ TimerMap d_timers; //!< Set of timers public: //! Constructor Debug(): d_traceOptions(NULL), d_os(&std::cerr), d_osDumpTrace(NULL) { } //! Destructor (must destroy objects it d_timers) ~Debug(); //! Must be called before Debug class can be safely used void init(const std::vector >* traceOptions, const std::string* dumpName); //! Must be called before arguments supplied to init are deallocated void finalize(); //! Accessing flags by name. /*! If a flag doesn't exist, it is created and initialized to false. */ DebugFlag flag(const std::string& name) { return DebugFlag(d_flags[name]); } //! Accessing tracing flags by name. /*! If a flag doesn't exist, it is created and initialized to false. */ DebugFlag traceFlag(const std::string& name) { return DebugFlag(d_traceFlags[name]); } //! Accessing tracing flag by char* name (mostly for GDB) DebugFlag traceFlag(const char* name); //! Set tracing of everything on (1) and off (0) [for use in GDB] void traceAll(bool enable = true); //! Accessing counters by name. /*! If a counter doesn't exist, it is created and initialized to 0. */ DebugCounter counter(const std::string& name) { return DebugCounter(d_counters[name]); } //! Accessing timers by name. /*! If a timer doesn't exist, it is created and initialized to 0. */ DebugTimer timer(const std::string& name); //! Check whether to print trace info for a particular flag. /*! Trace flags are the same DebugFlag objects, but live in a different namespace from the normal debug flags */ bool trace(const std::string& name); // Timer functions //! Create a new "private" timer, initially set to 0. /*! The new timer will not be added to the set of timers, will not have a name, and will not be printed by 'printAll()'. It is intended to be used to measure time intervals which are later added or assigned to the named timers. */ static DebugTimer newTimer(); //! Set the timer to the current time (whatever that means) void setCurrentTime(DebugTimer& timer); void setCurrentTime(const std::string& name) { DebugTimer t(timer(name)); setCurrentTime(t); } /*! @brief Set the timer to the difference between current time and the time stored in the timer: timer = currentTime - timer. */ /*! Intended to obtain the time interval since the last call to setCurrentTime() with that timer. */ void setElapsed(DebugTimer& timer); //! Return the ostream used for debugging output std::ostream& getOS() { return *d_os; } //! Return the ostream for dumping trace std::ostream& getOSDumpTrace(); //! Print an entry to the dump file void dumpTrace(const std::string& title, const std::vector >& fields); //! Set the debugging ostream void setOS(std::ostream& os) { d_os = &os; } //! Print all the collected data if "DEBUG" flag is set to 'os' void printAll(std::ostream& os); /*! @brief Print all the collected data if "DEBUG" flag is set to the default debug stream */ void printAll() { printAll(*d_os); } // Generally useful functions //! Get the current scope level int scopeLevel(); }; // end of class Debug extern CVC_DLL Debug debugger; } // end of namespace CVC3 #else // if _CVC3_DEBUG_MODE is not defined // All debugging macros are empty here #define IF_DEBUG(code) #define DebugAssert(cond, str) #define DBG_PRINT(cond, pre, v, post) #define TRACE(cond, pre, v, post) #define DBG_PRINT_MSG(cond, msg) #define TRACE_MSG(flag, msg) // to make the CLI wrapper happy namespace CVC3 { class DebugException: public Exception { }; } #endif // _CVC3_DEBUG_MODE #include "cvc_util.h" #endif // _cvc3__debug_h cvc3-2.4.1/src/include/theory_bitvector.h0000664000175400017540000003233511352466704020252 0ustar mdetersmdeters/*****************************************************************************/ /*! * \file theory_bitvector.h * * Author: Vijay Ganesh * * Created: Wed May 05 18:34:55 PDT 2004 * *
* * License to use, copy, modify, sell and/or distribute this software * and its documentation for any purpose is hereby granted without * royalty, subject to the terms and conditions defined in the \ref * LICENSE file provided with this distribution. * *
* */ /*****************************************************************************/ #ifndef _cvc3__include__theory_bitvector_h_ #define _cvc3__include__theory_bitvector_h_ #include "theory_core.h" #include "statistics.h" namespace CVC3 { class VCL; class BitvectorProofRules; typedef enum { //some new BV kinds // New constants BVCONST = 80, BITVECTOR = 8000, CONCAT, EXTRACT, BOOLEXTRACT, LEFTSHIFT, CONST_WIDTH_LEFTSHIFT, RIGHTSHIFT, BVSHL, BVLSHR, BVASHR, SX, BVREPEAT, BVZEROEXTEND, BVROTL, BVROTR, BVAND, BVOR, BVXOR, BVXNOR, BVNEG, BVNAND, BVNOR, BVCOMP, BVUMINUS, BVPLUS, BVSUB, BVMULT, BVUDIV, BVSDIV, BVUREM, BVSREM, BVSMOD, BVLT, BVLE, BVGT, BVGE, BVSLT, BVSLE, BVSGT, BVSGE, INTTOBV, // Not implemented yet BVTOINT, // Not implemented yet // A wrapper for delaying the construction of type predicates BVTYPEPRED } BVKinds; /*****************************************************************************/ /*! *\class TheoryBitvector *\ingroup Theories *\brief Theory of bitvectors of known length \ * (operations include: @,[i:j],[i],+,.,BVAND,BVNEG) * * Author: Vijay Ganesh * * Created:Wed May 5 15:35:07 PDT 2004 */ /*****************************************************************************/ class TheoryBitvector :public Theory { BitvectorProofRules* d_rules; //! MemoryManager index for BVConstExpr subclass size_t d_bvConstExprIndex; size_t d_bvPlusExprIndex; size_t d_bvParameterExprIndex; size_t d_bvTypePredExprIndex; //! counts delayed asserted equalities StatCounter d_bvDelayEq; //! counts asserted equalities StatCounter d_bvAssertEq; //! counts delayed asserted disequalities StatCounter d_bvDelayDiseq; //! counts asserted disequalities StatCounter d_bvAssertDiseq; //! counts type predicates StatCounter d_bvTypePreds; //! counts delayed type predicates StatCounter d_bvDelayTypePreds; //! counts bitblasted equalities StatCounter d_bvBitBlastEq; //! counts bitblasted disequalities StatCounter d_bvBitBlastDiseq; //! boolean on the fly rewrite flag const bool* d_booleanRWFlag; //! bool extract cache flag const bool* d_boolExtractCacheFlag; //! flag which indicates that all arithmetic is 32 bit with no overflow const bool* d_bv32Flag; //! Cache for storing the results of the bitBlastTerm function CDMap d_bitvecCache; //! Cache for pushNegation(). it is ok that this is cache is //ExprMap. it is cleared for each call of pushNegation. Does not add //value across calls of pushNegation ExprMap d_pushNegCache; //! Backtracking queue for equalities CDList d_eq; //! Backtracking queue for unsolved equalities CDList d_eqPending; //! Index to current position in d_eqPending CDO d_eq_index; //! Backtracking queue for all other assertions CDList d_bitblast; //! Index to current position in d_bitblast CDO d_bb_index; //! Backtracking database of subterms of shared terms CDMap d_sharedSubterms; //! Backtracking database of subterms of shared terms CDList d_sharedSubtermsList; //! Constant 1-bit bit-vector 0bin0 Expr d_bvZero; //! Constant 1-bit bit-vector 0bin0 Expr d_bvOne; //! Return cached constant 0bin0 const Expr& bvZero() const { return d_bvZero; } //! Return cached constant 0bin1 const Expr& bvOne() const { return d_bvOne; } //! Max size of any bitvector we've seen int d_maxLength; //! Used in checkSat CDO d_index1; CDO d_index2; //! functions which implement the DP strategy for bitblasting Theorem bitBlastEqn(const Expr& e); //! bitblast disequation Theorem bitBlastDisEqn(const Theorem& notE); //! function which implements the DP strtagey to bitblast Inequations Theorem bitBlastIneqn(const Expr& e); //! functions which implement the DP strategy for bitblasting Theorem bitBlastTerm(const Expr& t, int bitPosition); // //! strategy fucntions for BVPLUS NORMAL FORM // Theorem padBVPlus(const Expr& e); // //! strategy fucntions for BVPLUS NORMAL FORM // Theorem flattenBVPlus(const Expr& e); // //! Implementation of the concatenation normal form // Theorem normalizeConcat(const Expr& e, bool useFind); // //! Implementation of the n-bit arithmetic normal form // Theorem normalizeBVArith(const Expr& e, bool useFind); // //! Helper method for composing normalizations // Theorem normalizeConcat(const Theorem& t, bool useFind) { // return transitivityRule(t, normalizeConcat(t.getRHS(), useFind)); // } // //! Helper method for composing normalizations // Theorem normalizeBVArith(const Theorem& t, bool useFind) { // return transitivityRule(t, normalizeBVArith(t.getRHS(), useFind)); // } // Theorem signExtendBVLT(const Expr& e, int len, bool useFind); public: Theorem pushNegationRec(const Expr& e); private: Theorem pushNegation(const Expr& e); //! Top down simplifier virtual Theorem simplifyOp(const Expr& e); //! Internal rewrite method for constants // Theorem rewriteConst(const Expr& e); //! Main rewrite method (implements the actual rewrites) Theorem rewriteBV(const Expr& e, ExprMap& cache, int n = 1); //! Rewrite children 'n' levels down (n==1 means "only the top level") Theorem rewriteBV(const Expr& e, int n = 1); // Shortcuts for theorems Theorem rewriteBV(const Theorem& t, ExprMap& cache, int n = 1) { return transitivityRule(t, rewriteBV(t.getRHS(), cache, n)); } Theorem rewriteBV(const Theorem& t, int n = 1) { return transitivityRule(t, rewriteBV(t.getRHS(), n)); } //! rewrite input boolean expression e to a simpler form Theorem rewriteBoolean(const Expr& e); /*Beginning of Lorenzo PLatania's methods*/ Expr multiply_coeff( Rational mult_inv, const Expr& e); // extract the min value from a Rational list int min(std::vector list); // evaluates the gcd of two integer coefficients // int gcd(int c1, int c2); // converts a bv constant to an integer // int bv2int(const Expr& e); // return the odd coefficient of a leaf for which we can solve the // equation, or zero if no one has been found Rational Odd_coeff( const Expr& e ); // returns 1 if e is a linear term int check_linear( const Expr &e ); bool isTermIn(const Expr& e1, const Expr& e2); Theorem updateSubterms( const Expr& d ); // returns how many times "term" appears in "e" int countTermIn( const Expr& term, const Expr& e); Theorem simplifyPendingEq(const Theorem& thm, int maxEffort); Theorem generalBitBlast( const Theorem& thm ); /*End of Lorenzo PLatania's methods*/ ExprStream& printSmtLibShared(ExprStream& os, const Expr& e); public: TheoryBitvector(TheoryCore* core); ~TheoryBitvector(); ExprMap d_bvPlusCarryCacheLeftBV; ExprMap d_bvPlusCarryCacheRightBV; // Trusted method that creates the proof rules class (used in constructor). // Implemented in bitvector_theorem_producer.cpp BitvectorProofRules* createProofRules(); // Theory interface void addSharedTerm(const Expr& e); void assertFact(const Theorem& e); void assertTypePred(const Expr& e, const Theorem& pred); void checkSat(bool fullEffort); Theorem rewrite(const Expr& e); Theorem rewriteAtomic(const Expr& e); void setup(const Expr& e); void update(const Theorem& e, const Expr& d); Theorem solve(const Theorem& e); void checkType(const Expr& e); Cardinality finiteTypeInfo(Expr& e, Unsigned& n, bool enumerate, bool computeSize); void computeType(const Expr& e); void computeModelTerm(const Expr& e, std::vector& v); void computeModel(const Expr& e, std::vector& vars); Expr computeTypePred(const Type& t, const Expr& e); Expr computeTCC(const Expr& e); ExprStream& print(ExprStream& os, const Expr& e); Expr parseExprOp(const Expr& e); //helper functions //! Return the number of bits in the bitvector expression int BVSize(const Expr& e); Expr rat(const Rational& r) { return getEM()->newRatExpr(r); } //!pads e to be of length len Expr pad(int len, const Expr& e); bool comparebv(const Expr& e1, const Expr& e2); //helper functions: functions to construct exprs Type newBitvectorType(int i) { return newBitvectorTypeExpr(i); } Expr newBitvectorTypePred(const Type& t, const Expr& e); Expr newBitvectorTypeExpr(int i); Expr newBVAndExpr(const Expr& t1, const Expr& t2); Expr newBVAndExpr(const std::vector& kids); Expr newBVOrExpr(const Expr& t1, const Expr& t2); Expr newBVOrExpr(const std::vector& kids); Expr newBVXorExpr(const Expr& t1, const Expr& t2); Expr newBVXorExpr(const std::vector& kids); Expr newBVXnorExpr(const Expr& t1, const Expr& t2); Expr newBVXnorExpr(const std::vector& kids); Expr newBVNandExpr(const Expr& t1, const Expr& t2); Expr newBVNorExpr(const Expr& t1, const Expr& t2); Expr newBVCompExpr(const Expr& t1, const Expr& t2); Expr newBVLTExpr(const Expr& t1, const Expr& t2); Expr newBVLEExpr(const Expr& t1, const Expr& t2); Expr newSXExpr(const Expr& t1, int len); Expr newBVIndexExpr(int kind, const Expr& t1, int len); Expr newBVSLTExpr(const Expr& t1, const Expr& t2); Expr newBVSLEExpr(const Expr& t1, const Expr& t2); Expr newBVNegExpr(const Expr& t1); Expr newBVUminusExpr(const Expr& t1); Expr newBoolExtractExpr(const Expr& t1, int r); Expr newFixedLeftShiftExpr(const Expr& t1, int r); Expr newFixedConstWidthLeftShiftExpr(const Expr& t1, int r); Expr newFixedRightShiftExpr(const Expr& t1, int r); Expr newConcatExpr(const Expr& t1, const Expr& t2); Expr newConcatExpr(const Expr& t1, const Expr& t2, const Expr& t3); Expr newConcatExpr(const std::vector& kids); Expr newBVConstExpr(const std::string& s, int base = 2); Expr newBVConstExpr(const std::vector& bits); // Lorenzo's wrapper // as computeBVConst can not give the BV expr of a negative rational, // I use this wrapper to do that Expr signed_newBVConstExpr( Rational c, int bv_size); // end of Lorenzo's wrapper // Construct BVCONST of length 'len', or the min. needed length when len=0. Expr newBVConstExpr(const Rational& r, int len = 0); Expr newBVZeroString(int r); Expr newBVOneString(int r); //! hi and low are bit indices Expr newBVExtractExpr(const Expr& e, int hi, int low); Expr newBVSubExpr(const Expr& t1, const Expr& t2); //! 'numbits' is the number of bits in the result Expr newBVPlusExpr(int numbits, const Expr& k1, const Expr& k2); //! 'numbits' is the number of bits in the result Expr newBVPlusExpr(int numbits, const std::vector& k); //! pads children and then builds plus expr Expr newBVPlusPadExpr(int bvLength, const std::vector& k); Expr newBVMultExpr(int bvLength, const Expr& t1, const Expr& t2); Expr newBVMultExpr(int bvLength, const std::vector& kids); Expr newBVMultPadExpr(int bvLength, const Expr& t1, const Expr& t2); Expr newBVMultPadExpr(int bvLength, const std::vector& kids); Expr newBVUDivExpr(const Expr& t1, const Expr& t2); Expr newBVURemExpr(const Expr& t1, const Expr& t2); Expr newBVSDivExpr(const Expr& t1, const Expr& t2); Expr newBVSRemExpr(const Expr& t1, const Expr& t2); Expr newBVSModExpr(const Expr& t1, const Expr& t2); // Accessors for expression parameters int getBitvectorTypeParam(const Expr& e); int getBitvectorTypeParam(const Type& t) { return getBitvectorTypeParam(t.getExpr()); } Type getTypePredType(const Expr& tp); const Expr& getTypePredExpr(const Expr& tp); int getSXIndex(const Expr& e); int getBVIndex(const Expr& e); int getBoolExtractIndex(const Expr& e); int getFixedLeftShiftParam(const Expr& e); int getFixedRightShiftParam(const Expr& e); int getExtractHi(const Expr& e); int getExtractLow(const Expr& e); int getBVPlusParam(const Expr& e); int getBVMultParam(const Expr& e); unsigned getBVConstSize(const Expr& e); bool getBVConstValue(const Expr& e, int i); //!computes the integer value of a bitvector constant Rational computeBVConst(const Expr& e); //!computes the integer value of ~c+1 or BVUMINUS(c) Rational computeNegBVConst(const Expr& e); int getMaxSize() { return d_maxLength; } /*Beginning of Lorenzo PLatania's public methods*/ bool isLinearTerm( const Expr& e ); void extract_vars( const Expr& e, std::vector& vars ); // checks whether e can be solved in term bool canSolveFor( const Expr& term, const Expr& e ); // evaluates the multipicative inverse Rational multiplicative_inverse(Rational r, int n_bits); /*End of Lorenzo PLatania's public methods*/ std::vector additionalRewriteConstraints; }; //end of class TheoryBitvector }//end of namespace CVC3 #endif cvc3-2.4.1/src/include/theory_records.h0000664000175400017540000001336511210144237017677 0ustar mdetersmdeters/*****************************************************************************/ /*! * \file theory_records.h * * Author: Daniel Wichs * * Created: 7/22/03 * *
* * License to use, copy, modify, sell and/or distribute this software * and its documentation for any purpose is hereby granted without * royalty, subject to the terms and conditions defined in the \ref * LICENSE file provided with this distribution. * *
* */ /*****************************************************************************/ #ifndef _cvc3__include__theory_records_h_ #define _cvc3__include__theory_records_h_ #include "theory.h" namespace CVC3 { class RecordsProofRules; typedef enum { RECORD = 2500, RECORD_SELECT, RECORD_UPDATE, RECORD_TYPE, TUPLE, TUPLE_SELECT, TUPLE_UPDATE, TUPLE_TYPE } RecordKinds; /*****************************************************************************/ /*! *\class TheoryRecords *\ingroup Theories *\brief This theory handles records. * * Author: Daniel Wichs * * Created: 7/22/03 */ /*****************************************************************************/ class TheoryRecords :public Theory { RecordsProofRules* d_rules; //! Auxiliary rewrites: Processing of AND and OR of equations. Returns e=e'. Theorem rewriteAux(const Expr& e); //! Takes Thm(e), returns Thm(e'), where e rewrites to e' by rewriteAux. Theorem rewriteAux(const Theorem& thm); public: TheoryRecords(TheoryCore* core); //!< Constructor ~TheoryRecords(); //!< Destructor //! creates a reference to the proof rules RecordsProofRules* createProofRules(); // Theory interface //! assert a fact to the theory of records void assertFact(const Theorem& e); //! empty implementation to fit theory interface void checkSat(bool fullEffort) {} //! rewrites an expression e to one of several allowed forms Theorem rewrite(const Expr& e); //! check record or tuple type void checkType(const Expr& e); Cardinality finiteTypeInfo(Expr& e, Unsigned& n, bool enumerate, bool computeSize); //! computes the type of a record or a tuple void computeType(const Expr& e); Type computeBaseType(const Type& t); Expr computeTypePred(const Type& t, const Expr& e); void computeModelTerm(const Expr& e, std::vector& v); void computeModel(const Expr& e, std::vector& vars); Expr computeTCC(const Expr& e); virtual Expr parseExprOp(const Expr& e); void setup(const Expr& e); void update(const Theorem& e, const Expr& d); //! pretty printing ExprStream& print(ExprStream& os, const Expr& e); //! Test whether expr is a record literal bool isRecord(const Expr& e) { return e.isApply() && e.getOpKind() == RECORD; } //! Test whether expr is a record type bool isRecordType(const Expr& e) { return e.isApply() && e.getOpKind() == RECORD_TYPE; } //! Test whether expr is a record type bool isRecordType(const Type& t) { return isRecordType(t.getExpr()); } //! Test whether expr is a record select/update subclass bool isRecordAccess(const Expr& e) { return e.isApply() && (e.getOpKind() == RECORD_SELECT || e.getOpKind() == RECORD_UPDATE); } //! Create a record literal Expr recordExpr(const std::vector& fields, const std::vector& kids); //! Create a record literal Expr recordExpr(const std::vector& fields, const std::vector& kids); //! Create a record type Type recordType(const std::vector& fields, const std::vector& types); //! Create a record type (field types are given as a vector of Expr) Type recordType(const std::vector& fields, const std::vector& types); //! Create a record type (fields and types are given as a vector of Expr) Type recordType(const std::vector& fields, const std::vector& types); //! Create a record field select expression Expr recordSelect(const Expr& r, const std::string& field); //! Create a record field update expression Expr recordUpdate(const Expr& r, const std::string& field, const Expr& val); //! Get the list of fields from a record literal const std::vector& getFields(const Expr& r); //! Get the i-th field name from the record literal or type const std::string& getField(const Expr& e, int i); //! Get the field index in the record literal or type /*! The field must be present in the record; otherwise it's an error. */ int getFieldIndex(const Expr& e, const std::string& field); //! Get the field name from the record select and update expressions const std::string& getField(const Expr& e); //! Create a tuple literal Expr tupleExpr(const std::vector& kids); //! Create a tuple type Type tupleType(const std::vector& types); //! Create a tuple type (types of components are given as Exprs) Type tupleType(const std::vector& types); //! Create a tuple index selector expression Expr tupleSelect(const Expr& tup, int i); //! Create a tuple index update expression Expr tupleUpdate(const Expr& tup, int i, const Expr& val); //! Get the index from the tuple select and update expressions int getIndex(const Expr& e); //! Test whether expr is a tuple select/update subclass bool isTupleAccess(const Expr& e) { return e.isApply() && (e.getOpKind() == TUPLE_SELECT || e.getOpKind() == TUPLE_UPDATE); } //! Test if expr is a tuple literal bool isTuple(const Expr& e) { return e.isApply() && e.getOpKind() == TUPLE; } //! Test if expr represents a tuple type bool isTupleType(const Expr& e) { return e.isApply() && e.getOpKind() == TUPLE_TYPE; } //! Test if 'tp' is a tuple type bool isTupleType(const Type& tp) { return isTupleType(tp.getExpr()); } }; // end of class TheoryRecords } #endif cvc3-2.4.1/src/include/command_line_flags.h0000664000175400017540000002407611222666423020457 0ustar mdetersmdeters/*****************************************************************************/ /*! * \file command_line_flags.h * * Author: Sergey Berezin * * Created: Mon Feb 10 16:22:00 2003 * *
* * License to use, copy, modify, sell and/or distribute this software * and its documentation for any purpose is hereby granted without * royalty, subject to the terms and conditions defined in the \ref * LICENSE file provided with this distribution. * *
* */ /*****************************************************************************/ #ifndef _cvc3__command_line_flags_h_ #define _cvc3__command_line_flags_h_ #include #include #include #include #include "command_line_exception.h" #include "debug.h" namespace CVC3 { //! Different types of command line flags typedef enum { CLFLAG_NULL, CLFLAG_BOOL, CLFLAG_INT, CLFLAG_STRING, CLFLAG_STRVEC //!< Vector of pair } CLFlagType; /*! Class CLFlag (for Command Line Flag) Author: Sergey Berezin Date: Fri May 30 14:10:48 2003 This class implements a data structure to hold a value of a single command line flag. */ class CLFlag { private: //! Type of the argument CLFlagType d_tp; //! The argument union { bool b; int i; std::string* s; std::vector >* sv; } d_data; //! This tag is set to true when the flag is assigned a new value bool d_modified; //! Help string std::string d_help; //! Whether to display this flag when user invokes cvc3 -h bool d_display; public: //! Constructor for a boolean flag CLFlag(bool b, const std::string& help, bool display = true) : d_tp(CLFLAG_BOOL), d_modified(0), d_help(help), d_display(display) { d_data.b = b; } //! Constructor for an integer flag CLFlag(int i, const std::string& help, bool display = true) : d_tp(CLFLAG_INT), d_modified(0), d_help(help), d_display(display) { d_data.i = i; } //! Constructor for a string flag CLFlag(const std::string& s, const std::string& help, bool display = true) : d_tp(CLFLAG_STRING), d_modified(0), d_help(help), d_display(display) { d_data.s = new std::string(s); } //! Constructor for a string flag from char* CLFlag(const char* s, const std::string& help, bool display = true) : d_tp(CLFLAG_STRING), d_modified(0), d_help(help), d_display(display) { d_data.s = new std::string((char*)s); } //! Constructor for a vector flag CLFlag(const std::vector >& sv, const std::string& help, bool display = true) : d_tp(CLFLAG_STRVEC), d_modified(0), d_help(help), d_display(display) { d_data.sv = new std::vector >(sv); } //! Default constructor CLFlag(): d_tp(CLFLAG_NULL), d_modified(0), d_help("Undefined flag"), d_display(false) { } //! Copy constructor CLFlag(const CLFlag& f) : d_tp(f.d_tp), d_modified(f.d_modified), d_help(f.d_help), d_display(f.d_display) { switch(d_tp) { case CLFLAG_STRING: d_data.s = new std::string(*f.d_data.s); break; case CLFLAG_STRVEC: d_data.sv = new std::vector >(*f.d_data.sv); break; default: d_data = f.d_data; } } //! Destructor ~CLFlag() { switch(d_tp) { case CLFLAG_STRING: delete d_data.s; break; case CLFLAG_STRVEC: delete d_data.sv; break; default: break;// Nothing to do } } //! Assignment from another flag CLFlag& operator=(const CLFlag& f) { if(this == &f) return *this; // Self-assignment // Try to preserve the existing heap objects if possible if(d_tp == f.d_tp) { switch(d_tp) { case CLFLAG_STRING: *d_data.s = *f.d_data.s; break; case CLFLAG_STRVEC: *d_data.sv = *f.d_data.sv; break; default: d_data = f.d_data; } } else { switch(d_tp) { case CLFLAG_STRING: delete d_data.s; break; case CLFLAG_STRVEC: delete d_data.sv; break; default: break; } switch(f.d_tp) { case CLFLAG_STRING: d_data.s = new std::string(*f.d_data.s); break; case CLFLAG_STRVEC: d_data.sv=new std::vector >(*f.d_data.sv); break; default: d_data = f.d_data; } } d_tp = f.d_tp; d_modified = f.d_modified; d_help = f.d_help; d_display = f.d_display; return *this; } //! Assignment of a boolean value /*! The flag must already have the right type */ CLFlag& operator=(bool b) { DebugAssert(d_tp == CLFLAG_BOOL, ""); d_data.b = b; d_modified = true; return *this; } //! Assignment of an integer value /*! The flag must already have the right type */ CLFlag& operator=(int i) { DebugAssert(d_tp == CLFLAG_INT, ""); d_data.i = i; d_modified = true; return *this; } //! Assignment of a string value /*! The flag must already have a string type. */ CLFlag& operator=(const std::string& s) { DebugAssert(d_tp == CLFLAG_STRING, ""); *d_data.s = s; d_modified = true; return *this; } //! Assignment of an string value from char* /*! The flag must already have a string type. */ CLFlag& operator=(const char* s) { DebugAssert(d_tp == CLFLAG_STRING, ""); *d_data.s = s; d_modified = true; return *this; } //! Assignment of a string value with a boolean tag to a vector flag /*! The flag must already have a vector type. The pair of will be appended to the vector. */ CLFlag& operator=(const std::pair& p) { DebugAssert(d_tp == CLFLAG_STRVEC, ""); d_data.sv->push_back(p); d_modified = true; return *this; } //! Assignment of a vector value /*! The flag must already have a vector type. */ CLFlag& operator=(const std::vector >& sv) { DebugAssert(d_tp == CLFLAG_STRVEC, ""); *d_data.sv = sv; d_modified = true; return *this; } // Accessor methods //! Return the type of the flag CLFlagType getType() const { return d_tp; } /*! @brief Return true if the flag was modified from the default value (e.g. set on the command line) */ bool modified() const { return d_modified; } //! Return true if flag should be displayed in regular help bool display() const { return d_display; } // The value accessors return a reference. For the system-wide // flags, this reference will remain valid throughout the run of the // program, even if the flag's value changes. So, the reference can // be cached, and the value can be checked directly (which is more // efficient). const bool& getBool() const { DebugAssert(d_tp == CLFLAG_BOOL, "CLFlag::getBool: not a boolean flag"); return d_data.b; } const int& getInt() const { DebugAssert(d_tp == CLFLAG_INT, "CLFlag::getInt: not an integer flag"); return d_data.i; } const std::string& getString() const { DebugAssert(d_tp == CLFLAG_STRING, "CLFlag::getString: not a string flag"); return *d_data.s; } const std::vector >& getStrVec() const { DebugAssert(d_tp == CLFLAG_STRVEC, "CLFlag::getStrVec: not a string vector flag"); return *d_data.sv; } const std::string& getHelp() const { return d_help; } }; // end of class CLFlag /////////////////////////////////////////////////////////////////////// // Class CLFlag (for Command Line Flag) // // Author: Sergey Berezin // Date: Fri May 30 14:10:48 2003 // // Database of command line flags. /////////////////////////////////////////////////////////////////////// class CLFlags { private: typedef std::map CharMap; CharMap d_map; // Private methods // Retrieve an existing flag for modification. The 'name' must be a // full name of an existing flag. CLFlag& getFlag0(const std::string& name) { DebugAssert(d_map.count(name) > 0, "getFlag0("+name+"): there are no flags with this name"); return (*d_map.find(name)).second; } public: // Public methods // Add a new flag. The name must be a complete flag name. void addFlag(const std::string& name, const CLFlag& f) { d_map[name] = f; } // Count how many flags match the name prefix size_t countFlags(const std::string& name) const { size_t res(0), len(name.size()); for(CharMap::const_iterator i=d_map.begin(), iend=d_map.end(); i!=iend; ++i) { if(std::strncmp(name.c_str(), (*i).first.c_str(), len) == 0) res++; } return res; } // Match the name prefix and add all the matching names to the vector size_t countFlags(const std::string& name, std::vector& names) const { size_t res(0), len(name.size()); for(CharMap::const_iterator i=d_map.begin(), iend=d_map.end(); i!=iend; ++i) { if(std::strncmp(name.c_str(), (*i).first.c_str(), len) == 0) { names.push_back((*i).first); res++; } } return res; } // Retrieve an existing flag. The 'name' must be a full name of an // existing flag. const CLFlag& getFlag(const std::string& name) const { DebugAssert(d_map.count(name) > 0, "getFlag("+name+"): there are no flags with this name"); return (*d_map.find(name)).second; } const CLFlag& operator[](const std::string& name) const { return getFlag(name); } // Setting the flag to a new value, but preserving the help string. // The 'name' prefix must uniquely resolve to an existing flag. void setFlag(const std::string& name, const CLFlag& f) { CLFlag& oldF(getFlag0(name)); DebugAssert(oldF.getType() == f.getType(), "setFlag("+name+"): flag type doesn't match"); oldF = f; } // Variants of setFlag for all the types void setFlag(const std::string& name, bool b) { getFlag0(name) = b; } void setFlag(const std::string& name, int i) { getFlag0(name) = i; } void setFlag(const std::string& name, const std::string& s) { getFlag0(name) = s; } void setFlag(const std::string& name, const char* s) { getFlag0(name) = s; } void setFlag(const std::string& name, const std::pair& p) { getFlag0(name) = p; } void setFlag(const std::string& name, const std::vector >& sv) { getFlag0(name) = sv; } }; // end of class CLFlags } // end of namespace CVC3 #endif cvc3-2.4.1/src/include/expr_op.h0000664000175400017540000000640111254727702016325 0ustar mdetersmdeters/*****************************************************************************/ /*! * \file expr_op.h * \brief Class Op representing the Expr's operator. * * Author: Sergey Berezin * * Created: Fri Feb 7 15:14:42 2003 * *
* * License to use, copy, modify, sell and/or distribute this software * and its documentation for any purpose is hereby granted without * royalty, subject to the terms and conditions defined in the \ref * LICENSE file provided with this distribution. * *
* */ /*****************************************************************************/ // expr.h Has to be included outside of #ifndef, since it sources us // recursively (read comments in expr_value.h). #ifndef _cvc3__expr_h_ #include "expr.h" #endif #ifndef _cvc3__expr_op_h_ #define _cvc3__expr_op_h_ namespace CVC3 { class ExprManager; /////////////////////////////////////////////////////////////////////////////// // // // Class: Op // // Author: Clark Barrett // // Created: Wed Nov 27 15:50:38 2002 // // Description: Encapsulates all possible Expr operators (including UFUNC) // // and allows switching on the kind. // // Kinds should be registered with ExprManager. // // // Technically, class Op is not part of Expr; it is provided as an // abstraction for the user. So, building an Expr from an Op is less // efficient than building the same Expr directly from the kind. /////////////////////////////////////////////////////////////////////////////// class Op { friend class Expr; friend class ExprApply; friend class ExprApplyTmp; friend class ::CInterface; int d_kind; Expr d_expr; // Disallow silent conversion of expr to op //! Constructor for operators Op(const Expr& e): d_kind(APPLY), d_expr(e) { } public: ///////////////////////////////////////////////////////////////////////// // Public methods ///////////////////////////////////////////////////////////////////////// Op() : d_kind(NULL_KIND) { } // Construct an operator from a kind. Op(int kind) : d_kind(kind), d_expr() { DebugAssert(kind != APPLY, "APPLY cannot be an operator on its own"); } // Copy constructor Op(const Op& op): d_kind(op.d_kind), d_expr(op.d_expr) { } // A constructor that rebuilds the Op for the given ExprManager Op(ExprManager* em, const Op& op); // Destructor (does nothing) ~Op() { } // Assignment operator Op& operator=(const Op& op); // Check if Op is NULL bool isNull() const { return d_kind == NULL_KIND; } // Return the kind of the operator int getKind() const { return d_kind; } // Return the expr associated with this operator if applicable. const Expr& getExpr() const { DebugAssert(d_kind == APPLY, "Expected APPLY"); return d_expr; } // Printing functions. std::string toString() const; friend std::ostream& operator<<(std::ostream& os, const Op& op) { return os << "Op(" << op.d_kind << " " << op.d_expr << ")"; } friend bool operator==(const Op& op1, const Op& op2) { return op1.d_kind == op2.d_kind && op1.d_expr == op2.d_expr; } }; // end of class Op } // end of namespace CVC3 #endif cvc3-2.4.1/src/include/dpllt_minisat.h0000664000175400017540000000613610716213261017511 0ustar mdetersmdeters/*****************************************************************************/ /*! *\file dpllt_minisat.h *\brief Implementation of dpllt module based on minisat * * Author: Alexander Fuchs * * Created: Fri Sep 08 11:04:00 2006 * *
* * License to use, copy, modify, sell and/or distribute this software * and its documentation for any purpose is hereby granted without * royalty, subject to the terms and conditions defined in the \ref * LICENSE file provided with this distribution. * *
*/ /*****************************************************************************/ #ifndef _cvc3__sat__dpllt_minisat_h_ #define _cvc3__sat__dpllt_minisat_h_ #include "dpllt.h" #include "proof.h" #include "cnf_manager.h" #include // forward declaration of the minisat solver namespace MiniSat { class Solver; } namespace SAT { class SatProof; // an implementation of the DPLLT interface using an adapted MiniSat SAT solver class DPLLTMiniSat : public DPLLT { public: protected: // determines if the derivation statistic of the solver // is printed after the derivation terminates. // can only be set with the constructor bool d_printStats; // if true then minisat will create a derivation // of the empty clause for an unsatisfiable problem. // see getProof(). bool d_createProof; // if d_createProof, then the proof of the last unsatisfiable search SatProof* d_proof; // the dpllt interface operates in a stack fashion via checkSat and push. // each stack's data is stored in a level, which is just an instance of MiniSat. // whenever a checkSat or push is done on a solver that is already in a search, // a new solver is created and pushed. std::stack d_solvers; // returnes the currently active MiniSat instance // // must not be called when there is no active MiniSat instance, // i.e. d_solvers is empty. MiniSat::Solver* getActiveSolver(); // creates a solver as an extension of the previous solver // (i.e. takes clauses/assignments/lemmas) // and pushes it on d_solvers void pushSolver(); // called by checkSat and continueCheck to initiate a search // with a SAT solver CVC3::QueryResult search(); public: DPLLTMiniSat(TheoryAPI* theoryAPI, Decider* decider, bool printStats = false, bool createProof = false); virtual ~DPLLTMiniSat(); // Implementation of the DPLLT interface virtual CVC3::QueryResult checkSat(const CNF_Formula& cnf); virtual CVC3::QueryResult continueCheck(const CNF_Formula& cnf); virtual void push(); virtual void pop(); virtual void addAssertion(const CNF_Formula& cnf); virtual std::vector getCurAssignments() ; virtual std::vector > getCurClauses(); virtual Var::Val getValue(Var v); // if createProof was given returns a proof of the last unsatisfiable search, // otherwise (or if there was no unsatisfiable search) NULL // ownership remains with DPLLTMiniSat SatProof* getProof() { DebugAssert((d_proof != NULL), "null proof foound") ; return d_proof; }; CVC3::Proof getSatProof(CNF_Manager*, CVC3::TheoryCore*) ; }; } #endif cvc3-2.4.1/src/include/fdstream.h0000664000175400017540000001126610607034534016456 0ustar mdetersmdeters/*! \file fdstream.h * @brief The following code declares classes to read from and write to * file descriptore or file handles. * * See * http://www.josuttis.com/cppcode * for details and the latest version. * * - open: * - integrating BUFSIZ on some systems? * - optimized reading of multiple characters * - stream for reading AND writing * - i18n * * (C) Copyright Nicolai M. Josuttis 2001. * Permission to copy, use, modify, sell and distribute this software * is granted provided this copyright notice appears in all copies. * This software is provided "as is" without express or implied * warranty, and with no claim as to its suitability for any purpose. * * Version: Jul 28, 2002 * History: * Jul 28, 2002: bugfix memcpy() => memmove() * fdinbuf::underflow(): cast for return statements * Aug 05, 2001: first public version */ #ifndef BOOST_FDSTREAM_HPP #define BOOST_FDSTREAM_HPP #include #include #include // for EOF: #include // for memmove(): #include // low-level read and write functions #ifdef _MSC_VER # include #else # include //extern "C" { // int write (int fd, const char* buf, int num); // int read (int fd, char* buf, int num); //} #endif // BEGIN namespace BOOST namespace std { /************************************************************ * fdostream * - a stream that writes on a file descriptor ************************************************************/ class fdoutbuf : public std::streambuf { protected: int fd; // file descriptor public: // constructor fdoutbuf (int _fd) : fd(_fd) { } protected: // write one character virtual int_type overflow (int_type c) { if (c != EOF) { char z = c; if (write (fd, &z, 1) != 1) { return EOF; } } return c; } // write multiple characters virtual std::streamsize xsputn (const char* s, std::streamsize num) { return write(fd,s,num); } }; class fdostream : public std::ostream { protected: fdoutbuf buf; public: fdostream (int fd) : std::ostream(0), buf(fd) { rdbuf(&buf); } }; /************************************************************ * fdistream * - a stream that reads on a file descriptor ************************************************************/ class fdinbuf : public std::streambuf { protected: int fd; // file descriptor protected: /* data buffer: * - at most, pbSize characters in putback area plus * - at most, bufSize characters in ordinary read buffer */ static const int pbSize = 4; // size of putback area static const int bufSize = 1024; // size of the data buffer char buffer[bufSize+pbSize]; // data buffer public: /* constructor * - initialize file descriptor * - initialize empty data buffer * - no putback area * => force underflow() */ fdinbuf (int _fd) : fd(_fd) { setg (buffer+pbSize, // beginning of putback area buffer+pbSize, // read position buffer+pbSize); // end position } protected: // insert new characters into the buffer virtual int_type underflow () { #ifndef _MSC_VER using std::memmove; #endif // is read position before end of buffer? if (gptr() < egptr()) { return traits_type::to_int_type(*gptr()); } /* process size of putback area * - use number of characters read * - but at most size of putback area */ int numPutback; numPutback = gptr() - eback(); if (numPutback > pbSize) { numPutback = pbSize; } /* copy up to pbSize characters previously read into * the putback area */ memmove (buffer+(pbSize-numPutback), gptr()-numPutback, numPutback); // read at most bufSize new characters int num; num = read (fd, buffer+pbSize, bufSize); if (num <= 0) { // ERROR or EOF return EOF; } // reset buffer pointers setg (buffer+(pbSize-numPutback), // beginning of putback area buffer+pbSize, // read position buffer+pbSize+num); // end of buffer // return next character return traits_type::to_int_type(*gptr()); } }; class fdistream : public std::istream { protected: fdinbuf buf; public: fdistream (int fd) : std::istream(0), buf(fd) { rdbuf(&buf); } }; } // END namespace boost #endif /*BOOST_FDSTREAM_HPP*/ cvc3-2.4.1/src/include/theory_arith.h0000664000175400017540000002054011366166030017345 0ustar mdetersmdeters/*****************************************************************************/ /*! * \file theory_arith.h * * Author: Clark Barrett * * Created: Fri Jan 17 18:34:55 2003 * *
* * License to use, copy, modify, sell and/or distribute this software * and its documentation for any purpose is hereby granted without * royalty, subject to the terms and conditions defined in the \ref * LICENSE file provided with this distribution. * *
* */ /*****************************************************************************/ #ifndef _cvc3__include__theory_arith_h_ #define _cvc3__include__theory_arith_h_ #include "theory.h" #include "cdmap.h" namespace CVC3 { class ArithProofRules; typedef enum { // New constants REAL_CONST = 30, // wrapper around constants to indicate that they should be real NEGINF = 31, POSINF = 32, REAL = 3000, INT, SUBRANGE, UMINUS, PLUS, MINUS, MULT, DIVIDE, POW, INTDIV, MOD, LT, LE, GT, GE, IS_INTEGER, DARK_SHADOW, GRAY_SHADOW } ArithKinds; /*****************************************************************************/ /*! *\class TheoryArith *\ingroup Theories *\brief This theory handles basic linear arithmetic. * * Author: Clark Barrett * * Created: Sat Feb 8 14:44:32 2003 */ /*****************************************************************************/ class TheoryArith :public Theory { protected: Type d_realType; Type d_intType; std::vector d_kinds; protected: //! Canonize the expression e, assuming all children are canonical virtual Theorem canon(const Expr& e) = 0; //! Canonize the expression e recursively Theorem canonRec(const Expr& e); //! Print a rational in SMT-LIB format void printRational(ExprStream& os, const Rational& r, bool printAsReal = false); //! Whether any ite's appear in the arithmetic part of the term e bool isAtomicArithTerm(const Expr& e); //! simplify leaves and then canonize Theorem canonSimp(const Expr& e); //! helper for checkAssertEqInvariant bool recursiveCanonSimpCheck(const Expr& e); public: TheoryArith(TheoryCore* core, const std::string& name) : Theory(core, name) {} ~TheoryArith() {} virtual void addMultiplicativeSignSplit(const Theorem& case_split_thm) {}; /** * Record that smaller should be smaller than bigger in the variable order. * Should be implemented in decision procedures that support it. */ virtual bool addPairToArithOrder(const Expr& smaller, const Expr& bigger) { return true; }; // Used by translator //! Return whether e is syntactically identical to a rational constant bool isSyntacticRational(const Expr& e, Rational& r); //! Whether any ite's appear in the arithmetic part of the formula e bool isAtomicArithFormula(const Expr& e); //! Rewrite an atom to look like x - y op c if possible--for smtlib translation Expr rewriteToDiff(const Expr& e); /*! @brief Composition of canon(const Expr&) by transitivity: take e0 = e1, * canonize e1 to e2, return e0 = e2. */ Theorem canonThm(const Theorem& thm) { return transitivityRule(thm, canon(thm.getRHS())); } // ArithTheoremProducer needs this function, so make it public //! Separate monomial e = c*p1*...*pn into c and 1*p1*...*pn virtual void separateMonomial(const Expr& e, Expr& c, Expr& var) = 0; // Theory interface virtual void addSharedTerm(const Expr& e) = 0; virtual void assertFact(const Theorem& e) = 0; virtual void refineCounterExample() = 0; virtual void computeModelBasic(const std::vector& v) = 0; virtual void computeModel(const Expr& e, std::vector& vars) = 0; virtual void checkSat(bool fullEffort) = 0; virtual Theorem rewrite(const Expr& e) = 0; virtual void setup(const Expr& e) = 0; virtual void update(const Theorem& e, const Expr& d) = 0; virtual Theorem solve(const Theorem& e) = 0; virtual void checkAssertEqInvariant(const Theorem& e) = 0; virtual void checkType(const Expr& e) = 0; virtual Cardinality finiteTypeInfo(Expr& e, Unsigned& n, bool enumerate, bool computeSize) = 0; virtual void computeType(const Expr& e) = 0; virtual Type computeBaseType(const Type& t) = 0; virtual void computeModelTerm(const Expr& e, std::vector& v) = 0; virtual Expr computeTypePred(const Type& t, const Expr& e) = 0; virtual Expr computeTCC(const Expr& e) = 0; virtual ExprStream& print(ExprStream& os, const Expr& e) = 0; virtual Expr parseExprOp(const Expr& e) = 0; // Arith constructors Type realType() { return d_realType; } Type intType() { return d_intType;} Type subrangeType(const Expr& l, const Expr& r) { return Type(Expr(SUBRANGE, l, r)); } Expr rat(Rational r) { return getEM()->newRatExpr(r); } // Dark and Gray shadows (for internal use only) //! Construct the dark shadow expression representing lhs <= rhs Expr darkShadow(const Expr& lhs, const Expr& rhs) { return Expr(DARK_SHADOW, lhs, rhs); } //! Construct the gray shadow expression representing c1 <= v - e <= c2 /*! Alternatively, v = e + i for some i s.t. c1 <= i <= c2 */ Expr grayShadow(const Expr& v, const Expr& e, const Rational& c1, const Rational& c2) { return Expr(GRAY_SHADOW, v, e, rat(c1), rat(c2)); } bool leavesAreNumConst(const Expr& e); }; // Arith testers inline bool isReal(Type t) { return t.getExpr().getKind() == REAL; } inline bool isInt(Type t) { return t.getExpr().getKind() == INT; } // Static arith testers inline bool isRational(const Expr& e) { return e.isRational(); } inline bool isIntegerConst(const Expr& e) { return e.isRational() && e.getRational().isInteger(); } inline bool isUMinus(const Expr& e) { return e.getKind() == UMINUS; } inline bool isPlus(const Expr& e) { return e.getKind() == PLUS; } inline bool isMinus(const Expr& e) { return e.getKind() == MINUS; } inline bool isMult(const Expr& e) { return e.getKind() == MULT; } inline bool isDivide(const Expr& e) { return e.getKind() == DIVIDE; } inline bool isPow(const Expr& e) { return e.getKind() == POW; } inline bool isLT(const Expr& e) { return e.getKind() == LT; } inline bool isLE(const Expr& e) { return e.getKind() == LE; } inline bool isGT(const Expr& e) { return e.getKind() == GT; } inline bool isGE(const Expr& e) { return e.getKind() == GE; } inline bool isDarkShadow(const Expr& e) { return e.getKind() == DARK_SHADOW;} inline bool isGrayShadow(const Expr& e) { return e.getKind() == GRAY_SHADOW;} inline bool isIneq(const Expr& e) { return isLT(e) || isLE(e) || isGT(e) || isGE(e); } inline bool isIntPred(const Expr& e) { return e.getKind() == IS_INTEGER; } // Static arith constructors inline Expr uminusExpr(const Expr& child) { return Expr(UMINUS, child); } inline Expr plusExpr(const Expr& left, const Expr& right) { return Expr(PLUS, left, right); } inline Expr plusExpr(const std::vector& children) { DebugAssert(children.size() > 0, "plusExpr()"); return Expr(PLUS, children); } inline Expr minusExpr(const Expr& left, const Expr& right) { return Expr(MINUS, left, right); } inline Expr multExpr(const Expr& left, const Expr& right) { return Expr(MULT, left, right); } // Begin Deepak: //! a Mult expr with two or more children inline Expr multExpr(const std::vector& children) { DebugAssert(children.size() > 0, "multExpr()"); return Expr(MULT, children); } //! Power (x^n, or base^{pow}) expressions inline Expr powExpr(const Expr& pow, const Expr & base) { return Expr(POW, pow, base);} // End Deepak inline Expr divideExpr(const Expr& left, const Expr& right) { return Expr(DIVIDE, left, right); } inline Expr ltExpr(const Expr& left, const Expr& right) { return Expr(LT, left, right); } inline Expr leExpr(const Expr& left, const Expr& right) { return Expr(LE, left, right); } inline Expr gtExpr(const Expr& left, const Expr& right) { return Expr(GT, left, right); } inline Expr geExpr(const Expr& left, const Expr& right) { return Expr(GE, left, right); } inline Expr operator-(const Expr& child) { return uminusExpr(child); } inline Expr operator+(const Expr& left, const Expr& right) { return plusExpr(left, right); } inline Expr operator-(const Expr& left, const Expr& right) { return minusExpr(left, right); } inline Expr operator*(const Expr& left, const Expr& right) { return multExpr(left, right); } inline Expr operator/(const Expr& left, const Expr& right) { return divideExpr(left, right); } } #endif cvc3-2.4.1/src/include/cdmap_ordered.h0000664000175400017540000002434710656155007017450 0ustar mdetersmdeters/*****************************************************************************/ /*! * \file cdmap_ordered.h * * Author: Sergey Berezin * * Created: Thu May 15 15:55:09 2003 * *
* * License to use, copy, modify, sell and/or distribute this software * and its documentation for any purpose is hereby granted without * royalty, subject to the terms and conditions defined in the \ref * LICENSE file provided with this distribution. * *
* */ /*****************************************************************************/ #ifndef _cvc3__include__cdmap_ordered_h_ #define _cvc3__include__cdmap_ordered_h_ #include #include #include "context.h" namespace CVC3 { /////////////////////////////////////////////////////////////////////////////// // // // Class: CDMapOrdered (Context Dependent Map) // // Author: Sergey Berezin // // Created: Thu May 15 15:55:09 2003 // // Description: Generic templated class for a map which must be saved // // and restored as contexts are pushed and popped. Requires // // that operator= be defined for the data class, and // // operator< for the key class. // // // /////////////////////////////////////////////////////////////////////////////// // Auxiliary class: almost the same as CDO (see cdo.h), but on // setNull() call it erases itself from the map. template class CDMapOrdered; template class CDOmapOrdered :public ContextObj { Key d_key; Data d_data; bool d_inMap; // whether the data must be in the map CDMapOrdered* d_cdmap; // Doubly-linked list for keeping track of elements in order of insertion CDOmapOrdered* d_prev; CDOmapOrdered* d_next; virtual ContextObj* makeCopy(ContextMemoryManager* cmm) { return new(cmm) CDOmapOrdered(*this); } virtual void restoreData(ContextObj* data) { CDOmapOrdered* p((CDOmapOrdered*)data); if(p->d_inMap) { d_data = p->d_data; d_inMap = true; } else setNull(); } virtual void setNull(void) { // Erase itself from the map and put itself into trash. We cannot // "delete this" here, because it will break context operations in // a non-trivial way. if(d_cdmap->d_map.count(d_key) > 0) { d_cdmap->d_map.erase(d_key); d_cdmap->d_trash.push_back(this); } d_prev->d_next = d_next; d_next->d_prev = d_prev; if (d_cdmap->d_first == this) { d_cdmap->d_first = d_next; if (d_next == this) { d_cdmap->d_first = NULL; } } } public: CDOmapOrdered(Context* context, CDMapOrdered* cdmap, const Key& key, const Data& data, int scope = -1) : ContextObj(context, true /* use bottom scope */), d_key(key), d_inMap(false), d_cdmap(cdmap) { set(data, scope); IF_DEBUG(setName("CDOmapOrdered");) CDOmapOrdered*& first = d_cdmap->d_first; if (first == NULL) { first = d_next = d_prev = this; } else { d_prev = first->d_prev; d_next = first; d_prev->d_next = first->d_prev = this; } } ~CDOmapOrdered() {} void set(const Data& data, int scope=-1) { makeCurrent(scope); d_data = data; d_inMap = true; } const Key& getKey() const { return d_key; } const Data& get() const { return d_data; } operator Data() { return get(); } CDOmapOrdered& operator=(const Data& data) { set(data); return *this; } CDOmapOrdered* next() const { if (d_next == d_cdmap->d_first) return NULL; else return d_next; } }; // end of class CDOmapOrdered // Dummy subclass of ContextObj to serve as our data class class CDMapOrderedData : public ContextObj { ContextObj* makeCopy(ContextMemoryManager* cmm) { return new(cmm) CDMapOrderedData(*this); } void restoreData(ContextObj* data) { } void setNull(void) { } public: CDMapOrderedData(Context* context): ContextObj(context) { } CDMapOrderedData(const ContextObj& co): ContextObj(co) { } }; // The actual class CDMapOrdered template class CDMapOrdered: public ContextObj { friend class CDOmapOrdered; private: std::map*> d_map; // The vector of CDOmapOrdered objects to be destroyed std::vector*> d_trash; CDOmapOrdered* d_first; Context* d_context; // Nothing to save; the elements take care of themselves virtual ContextObj* makeCopy(ContextMemoryManager* cmm) { return new(cmm) CDMapOrderedData(*this); } // Similarly, nothing to restore virtual void restoreData(ContextObj* data) { } // Destroy stale CDOmapOrdered objects from trash void emptyTrash() { for(typename std::vector*>::iterator i=d_trash.begin(), iend=d_trash.end(); i!=iend; ++i) delete *i; d_trash.clear(); } virtual void setNull(void) { // Delete all the elements and clear the map for(typename std::map*>::iterator i=d_map.begin(), iend=d_map.end(); i!=iend; ++i) delete (*i).second; d_map.clear(); emptyTrash(); } public: CDMapOrdered(Context* context, int scope = -1) : ContextObj(context), d_first(NULL), d_context(context) { IF_DEBUG(setName("CDMapOrdered")); ; } ~CDMapOrdered() { setNull(); } // The usual operators of map size_t size() const { return d_map.size(); } size_t count(const Key& k) const { return d_map.count(k); } // If a key is not present, a new object is created and inserted CDOmapOrdered& operator[](const Key& k) { emptyTrash(); typename std::map*>::iterator i(d_map.find(k)); CDOmapOrdered* obj; if(i == d_map.end()) { // Create new object obj = new CDOmapOrdered(d_context, this, k, Data()); d_map[k] = obj; } else { obj = (*i).second; } return *obj; } void insert(const Key& k, const Data& d, int scope = -1) { emptyTrash(); typename std::map*>::iterator i(d_map.find(k)); if(i == d_map.end()) { // Create new object CDOmapOrdered* obj(new CDOmapOrdered(d_context, this, k, d, scope)); d_map[k] = obj; } else { (*i).second->set(d, scope); } } // FIXME: no erase(), too much hassle to implement efficiently... // Iterator for CDMapOrdered: points to pair&>; // in most cases, this will be functionally similar to pair. class iterator : public std::iterator,std::ptrdiff_t> { private: // Private members typename std::map*>::const_iterator d_it; public: // Constructor from std::map iterator(const typename std::map*>::const_iterator& i) : d_it(i) { } // Copy constructor iterator(const iterator& i): d_it(i.d_it) { } // Default constructor iterator() { } // (Dis)equality bool operator==(const iterator& i) const { return d_it == i.d_it; } bool operator!=(const iterator& i) const { return d_it != i.d_it; } // Dereference operators. std::pair operator*() const { const std::pair*>& p(*d_it); return std::pair(p.first, *p.second); } // Who needs an operator->() for maps anyway?... // It'd be nice, but not possible by design. //std::pair* operator->() const { // return &(operator*()); //} // Prefix and postfix increment iterator& operator++() { ++d_it; return *this; } // Postfix increment: requires a Proxy object to hold the // intermediate value for dereferencing class Proxy { const std::pair* d_pair; public: Proxy(const std::pair& p): d_pair(&p) { } std::pair& operator*() { return *d_pair; } }; // Actual postfix increment: returns Proxy with the old value. // Now, an expression like *i++ will return the current *i, and // then advance the iterator. However, don't try to use Proxy for // anything else. Proxy operator++(int) { Proxy e(*(*this)); ++(*this); return e; } }; iterator begin() const { return iterator(d_map.begin()); } iterator end() const { return iterator(d_map.end()); } class orderedIterator { const CDOmapOrdered* d_it; public: orderedIterator(const CDOmapOrdered* p): d_it(p) {} orderedIterator(const orderedIterator& i): d_it(i.d_it) { } // Default constructor orderedIterator() { } // (Dis)equality bool operator==(const orderedIterator& i) const { return d_it == i.d_it; } bool operator!=(const orderedIterator& i) const { return d_it != i.d_it; } // Dereference operators. std::pair operator*() const { return std::pair(d_it->getKey(), d_it->get()); } // Prefix and postfix increment orderedIterator& operator++() { d_it = d_it->next(); return *this; } // Postfix increment: requires a Proxy object to hold the // intermediate value for dereferencing class Proxy { const std::pair* d_pair; public: Proxy(const std::pair& p): d_pair(&p) { } std::pair& operator*() { return *d_pair; } }; // Actual postfix increment: returns Proxy with the old value. // Now, an expression like *i++ will return the current *i, and // then advance the orderedIterator. However, don't try to use Proxy for // anything else. Proxy operator++(int) { Proxy e(*(*this)); ++(*this); return e; } }; orderedIterator orderedBegin() const { return orderedIterator(d_first); } orderedIterator orderedEnd() const { return orderedIterator(NULL); } iterator find(const Key& k) const { return iterator(d_map.find(k)); } }; // end of class CDMapOrdered } #endif cvc3-2.4.1/src/include/theory_uf.h0000664000175400017540000000635411437276451016667 0ustar mdetersmdeters/*****************************************************************************/ /*! * \file theory_uf.h * * Author: Clark Barrett * * Created: Fri Jan 17 18:25:40 2003 * *
* * License to use, copy, modify, sell and/or distribute this software * and its documentation for any purpose is hereby granted without * royalty, subject to the terms and conditions defined in the \ref * LICENSE file provided with this distribution. * *
* */ /*****************************************************************************/ #ifndef _cvc3__include__theory_uf_h_ #define _cvc3__include__theory_uf_h_ #include "theory.h" #include "cdmap.h" namespace CVC3 { class UFProofRules; //! Local kinds for transitive closure of binary relations typedef enum { TRANS_CLOSURE = 500, OLD_ARROW // for backward compatibility with old function declarations } UFKinds; /*****************************************************************************/ /*! *\class TheoryUF *\ingroup Theories *\brief This theory handles uninterpreted functions. * * Author: Clark Barrett * * Created: Sat Feb 8 14:51:19 2003 */ /*****************************************************************************/ class TheoryUF :public Theory { UFProofRules* d_rules; //! Flag to include function applications to the concrete model const bool& d_applicationsInModel; // For computing transitive closure of binary relations typedef struct TCMapPair { ExprMap*> appearsFirstMap; ExprMap*> appearsSecondMap; } TCMapPair; ExprMap d_transClosureMap; //! Backtracking list of function applications /*! Used for building concrete models and beta-reducing * lambda-expressions. */ CDList d_funApplications; //! Pointer to the last unprocessed element (for lambda expansions) CDO d_funApplicationsIdx; //! The pointers to the last unprocessed shared pair CDO d_sharedIdx1, d_sharedIdx2; //! The set of all shared terms CDMap d_sharedTermsMap; public: TheoryUF(TheoryCore* core); ~TheoryUF(); // Trusted method that creates the proof rules class (used in constructor). // Implemented in uf_theorem_producer.cpp UFProofRules* createProofRules(); // Theory interface void addSharedTerm(const Expr& e); void assertFact(const Theorem& e); void checkSat(bool fullEffort); Theorem rewrite(const Expr& e); void setup(const Expr& e); void update(const Theorem& e, const Expr& d); void checkType(const Expr& e); Cardinality finiteTypeInfo(Expr& e, Unsigned& n, bool enumerate, bool computeSize); void computeType(const Expr& e); Type computeBaseType(const Type& t); void computeModelTerm(const Expr& e, std::vector& v); void computeModel(const Expr& e, std::vector& vars); Expr computeTCC(const Expr& e); virtual Expr parseExprOp(const Expr& e); ExprStream& print(ExprStream& os, const Expr& e); //! Create a new LAMBDA-abstraction Expr lambdaExpr(const std::vector& vars, const Expr& body); //! Create a transitive closure expression Expr transClosureExpr(const std::string& name, const Expr& e1, const Expr& e2); private: void printSmtLibShared(ExprStream& os, const Expr& e); }; } #endif cvc3-2.4.1/src/include/cnf_manager.h0000664000175400017540000002063611352431444017111 0ustar mdetersmdeters/*****************************************************************************/ /*! *\file cnf_manager.h *\brief Manager for conversion to and traversal of CNF formulas * * Author: Clark Barrett * * Created: Thu Dec 15 13:53:16 2005 * *
* * License to use, copy, modify, sell and/or distribute this software * and its documentation for any purpose is hereby granted without * royalty, subject to the terms and conditions defined in the \ref * LICENSE file provided with this distribution. * *
*/ /*****************************************************************************/ #ifndef _cvc3__include__cnf_manager_h_ #define _cvc3__include__cnf_manager_h_ #include "cnf.h" #include "expr.h" #include "expr_map.h" #include "cdmap.h" #include "statistics.h" namespace CVC3 { class CommonProofRules; class CNF_Rules; class ValidityChecker; class Statistics; } namespace SAT { class CNF_Manager { //! For clause minimization CVC3::ValidityChecker* d_vc; //! Whether to use brute-force clause minimization bool d_minimizeClauses; //! Common proof rules CVC3::CommonProofRules* d_commonRules; //! Rules for manipulating CNF CVC3::CNF_Rules* d_rules; //! Information kept for each CNF variable struct Varinfo { CVC3::Expr expr; std::vector fanins; std::vector fanouts; }; //! vector that maps a variable index to information for that variable std::vector d_varInfo; //! Map from Exprs to Vars representing those Exprs CVC3::ExprHashMap d_cnfVars; //! Cached translation of term-ite-containing expressions CVC3::ExprHashMap d_iteMap; //! Map of possibly useful lemmas // CVC3::ExprMap d_usefulLemmas; //! Maps a clause id to the theorem justifying that clause /*! Note that clauses created by simple CNF translation are not given id's. * This is because theorems for these clauses can be created lazily later. */ // CVC3::CDMap d_theorems; // CVC3::CDMap d_theorems; //! Next clause id int d_clauseIdNext; //! Whether expr has already been translated // CVC3::CDMap d_translated; //! Bottom scope in which translation is valid int d_bottomScope; //! Queue of theorems to translate std::deque d_translateQueueThms; //! Queue of fanouts corresponding to thms to translate std::deque d_translateQueueVars; //! Whether thm to translate is "translate only" std::deque d_translateQueueFlags; //! Reference to statistics object CVC3::Statistics& d_statistics; //! Reference to command-line flags const CVC3::CLFlags& d_flags; //! Reference to null Expr const CVC3::Expr& d_nullExpr; public: //! Abstract class for callbacks class CNFCallback { public: CNFCallback() {} virtual ~CNFCallback() {} //! Register an atom virtual void registerAtom(const CVC3::Expr& e, const CVC3::Theorem& thm) = 0; }; private: //! Instance of CNF_CallBack: must be registered CNFCallback* d_cnfCallback; CVC3::CNF_Rules* createProofRules(CVC3::TheoremManager* tm, const CVC3::CLFlags&); //! Register a new atomic formula void registerAtom(const CVC3::Expr& e, const CVC3::Theorem& thm); //! Return the expr corresponding to the literal unless the expr is TRUE of FALSE CVC3::Expr concreteExpr(const CVC3::Expr& e, const Lit& literal); //! Return the theorem if e is not as concreteExpr(e). CVC3::Theorem concreteThm(const CVC3::Expr& e); //! Recursively translate e into cnf /*! A non-context dependent cache, d_cnfVars is used to remember translations * of expressions. A context-dependent attribute, isTranslated, is used to * remember whether an expression has been translated in the current context */ Lit translateExprRec(const CVC3::Expr& e, CNF_Formula& cnf, const CVC3::Theorem& thmIn); //! Recursively traverse an expression with an embedded term ITE /*! Term ITE's are handled by introducing a skolem variable for the ITE term * and then adding new constraints describing the ITE in terms of the new variable. */ CVC3::Theorem replaceITErec(const CVC3::Expr& e, Var v, bool translateOnly); //! Recursively translate e into cnf /*! Call translateExprRec. If additional expressions are queued up, * translate them too, until none are left. */ Lit translateExpr(const CVC3::Theorem& thmIn, CNF_Formula& cnf); // bool isTranslated(const CVC3::Expr& e) // { CVC3::CDMap::iterator i = d_translated.find(e); // return i != d_translated.end() && (*i).second; } // void setTranslated(const CVC3::Expr& e) // { DebugAssert(!isTranslated(e),"already set"); // d_translated.insert(e, true, d_bottomScope); } // void clearTranslated(const CVC3::Expr& e) // { d_translated.insert(e, false, d_bottomScope); } public: CNF_Manager(CVC3::TheoremManager* tm, CVC3::Statistics& statistics, const CVC3::CLFlags& flags); ~CNF_Manager(); //! Register CNF callback void registerCNFCallback(CNFCallback* cnfCallback) { d_cnfCallback = cnfCallback; } //! Set scope for translation void setBottomScope(int scope) { d_bottomScope = scope; } //! Return the number of variables being managed unsigned numVars() { return d_varInfo.size(); } //! Return number of fanins for CNF node c /*! A CNF node x is a fanin of CNF node y if the expr for x is a child of the * expr for y or if y is an ITE leaf and x is a new CNF node obtained by * translating the ITE leaf y. * \sa isITELeaf() */ unsigned numFanins(Var c) { if (!c.isVar()) return 0; if (unsigned(c) >= d_varInfo.size()) return 0; return d_varInfo[c].fanins.size(); } //! Returns the ith fanin of c. Lit getFanin(Var c, unsigned i) { DebugAssert(i < numFanins(c), "attempt to access unknown fanin"); return d_varInfo[c].fanins[i]; } //! Return number of fanins for c /*! x is a fanout of y if y is a fanin of x * \sa numFanins */ unsigned numFanouts(Var c) { if (!c.isVar()) return 0; if (unsigned(c) >= d_varInfo.size()) return 0; return d_varInfo[c].fanouts.size(); } //! Returns the ith fanout of c. Lit getFanout(Var c, unsigned i) { DebugAssert(i < numFanouts(c), "attempt to access unknown fanin"); return Lit(d_varInfo[c].fanouts[i]); } //! Convert a CNF literal to an Expr literal /*! Returns a NULL Expr if there is no corresponding Expr for l */ const CVC3::Expr& concreteVar(Var v) { if (v.isNull()) return d_nullExpr; if (unsigned(v) >= d_varInfo.size() || (!d_varInfo[v].expr.isTranslated())) return d_nullExpr; return d_varInfo[v].expr; } //! Convert a CNF literal to an Expr literal /*! Returns a NULL Expr if there is no corresponding Expr for l */ CVC3::Expr concreteLit(Lit l, bool checkTranslated = true) { if (l.isNull()) return d_nullExpr; bool inverted = !l.isPositive(); int index = l.getVar(); if ((unsigned)index >= d_varInfo.size() || (checkTranslated && !d_varInfo[index].expr.isTranslated())) return d_nullExpr; return inverted ? !d_varInfo[index].expr : d_varInfo[index].expr; } //! Look up the CNF literal for an Expr /*! Returns a NULL Lit if there is no corresponding CNF literal for e */ Lit getCNFLit(const CVC3::Expr& e) { if (e.isFalse()) return Lit::getFalse(); if (e.isTrue()) return Lit::getTrue(); if (e.isNot()) return !getCNFLit(e[0]); CVC3::ExprHashMap::iterator i = d_cnfVars.find(e); if (!e.isTranslated() || i == d_cnfVars.end()) return Lit(); return Lit((*i).second); } void cons(unsigned lb, unsigned ub, const CVC3::Expr& e2, std::vector& newLits); //! Convert thm A |- B (A is a set of literals) into one or more clauses /*! cnf should be empty -- it will be filled with the result */ void convertLemma(const CVC3::Theorem& thm, CNF_Formula& cnf); //! Given thm of form A |- B, convert B to CNF and add it to cnf /*! Returns Lit corresponding to the root of the expression that was * translated. */ Lit addAssumption(const CVC3::Theorem& thm, CNF_Formula& cnf); //! Convert thm to CNF and add it to the current formula /*! \param thm should be of form A |- B where A is a set of literals. * \param cnf the new clauses are added to cnf. * Returns Lit corresponding to the root of the expression that was * translated. */ Lit addLemma(CVC3::Theorem thm, CNF_Formula& cnf); }; } #endif cvc3-2.4.1/src/include/c_interface.h0000664000175400017540000006155711516323041017115 0ustar mdetersmdeters/*****************************************************************************/ /*! * \file c_interface.h * * Authors: Clark Barrett * Cristian Cadar * * Created: Thu Jun 5 10:34:02 2003 * *
* * License to use, copy, modify, sell and/or distribute this software * and its documentation for any purpose is hereby granted without * royalty, subject to the terms and conditions defined in the \ref * LICENSE file provided with this distribution. * *
* */ /*****************************************************************************/ #ifndef _cvc3__include__c_interface_h_ #define _cvc3__include__c_interface_h_ #include "c_interface_defs.h" //! Flags can be NULL VC vc_createValidityChecker(Flags flags); //! Create validity checker's flags Flags vc_createFlags(); //! Destroy the validity checker. /*! Must be called after all other objects are deleted, except the flags */ void vc_destroyValidityChecker(VC vc); //! Delete the flags void vc_deleteFlags(Flags flags); //! Delete type void vc_deleteType(Type t); //! Delete expression void vc_deleteExpr(Expr e); //! Delete operator void vc_deleteOp(Op op); //! Delete vector of expressions void vc_deleteVector(Expr* e); //! Delete vector of types void vc_deleteTypeVector(Type* e); // Setting the flags //! Set a boolean flag to true or false void vc_setBoolFlag(Flags flags, char* name, int val); //! Set an integer flag to the given value void vc_setIntFlag(Flags flags, char* name, int val); //! Set a string flag to the given value void vc_setStringFlag(Flags flags, char* name, char* val); //! Add a (string, bool) pair to the multy-string flag void vc_setStrSeqFlag(Flags flags, char* name, char* str, int val); // Basic types Type vc_boolType(VC vc); Type vc_realType(VC vc); Type vc_intType(VC vc); //! Create a subrange type Type vc_subRangeType(VC vc, int lowerEnd, int upperEnd); //! Creates a subtype defined by the given predicate /*! * \param pred is a predicate taking one argument of type T and returning * Boolean. The resulting type is a subtype of T whose elements x are those * satisfying the predicate pred(x). * * \param witness is an expression of type T for which pred holds (if a Null * expression is passed as a witness, cvc will try to prove \f$\exists x. pred(x))\f$. * if the witness check fails, a TypecheckException is thrown. */ Type vc_subtypeType(VC vc, Expr pred, Expr witness); // Tuple types Type vc_tupleType2(VC vc, Type type0, Type type1); Type vc_tupleType3(VC vc, Type type0, Type type1, Type type2); //! Create a tuple type. 'types' is an array of types of length numTypes. Type vc_tupleTypeN(VC vc, Type* types, int numTypes); // Record types Type vc_recordType1(VC vc, char* field, Type type); Type vc_recordType2(VC vc, char* field0, Type type0, char* field1, Type type1); Type vc_recordType3(VC vc, char* field0, Type type0, char* field1, Type type1, char* field2, Type type2); //! Create a record type. /*! 'fields' and 'types' are arrays of length numFields. */ Type vc_recordTypeN(VC vc, char** fields, Type* types, int numFields); // Datatypes //! Single datatype, single constructor /*! The types are either type exressions (obtained from a type with * getExpr()) or string expressions containing the name of (one of) the * dataType(s) being defined. */ Type vc_dataType1(VC vc, char* name, char* constructor, int arity, char** selectors, Expr* types); //! Single datatype, multiple constructors /*! The types are either type exressions (obtained from a type with * getExpr()) or string expressions containing the name of (one of) the * dataType(s) being defined. */ Type vc_dataTypeN(VC vc, char* name, int numCons, char** constructors, int* arities, char*** selectors, Expr** types); //! Multiple datatypes /*! The types are either type exressions (obtained from a type with * getExpr()) or string expressions containing the name of (one of) the * dataType(s) being defined. * Returns an array of size numTypes which must be freed by calling * vc_deleteTypeVector. */ Type* vc_dataTypeMN(VC vc, int numTypes, char** names, int* numCons, char*** constructors, int** arities, char**** selectors, Expr*** types); //! Create an array type Type vc_arrayType(VC vc, Type typeIndex, Type typeData); //! Create a bitvector type of length n Type vc_bvType(VC vc, int n); //! Create a function type with 1 argument Type vc_funType1(VC vc, Type a1, Type typeRan); //! Create a function type with 2 arguments Type vc_funType2(VC vc, Type a1, Type a2, Type typeRan); //! Create a function type with 3 arguments Type vc_funType3(VC vc, Type a1, Type a2, Type a3, Type typeRan); //! Create a function type with N arguments Type vc_funTypeN(VC vc, Type* args, Type typeRan, int numArgs); // User-defined types //! Create an uninterpreted named type Type vc_createType(VC vc, char* typeName); //! Lookup a user-defined (uninterpreted) type by name Type vc_lookupType(VC vc, char* typeName); ///////////////////////////////////////////////////////////////////////////// // Expr manipulation methods // ///////////////////////////////////////////////////////////////////////////// //! Return the ExprManager ExprManager* vc_getEM(VC vc); //! Create a variable with a given name and type /*! The type cannot be a function type. */ Expr vc_varExpr(VC vc, char* name, Type type); //! Create a variable with a given name, type, and value Expr vc_varExprDef(VC vc, char* name, Type type, Expr def); //! Get the expression and type associated with a name. /*! If there is no such Expr, a NULL Expr is returned. */ Expr vc_lookupVar(VC vc, char* name, Type* type); //! Get the type of the Expr. Type vc_getType(VC vc, Expr e); //! Get the largest supertype of the Expr. Type vc_getBaseType(VC vc, Expr e); //! Get the largest supertype of the Type. Type vc_getBaseTypeOfType(VC vc, Type t); //! Get the subtype predicate Expr vc_getTypePred(VC vc, Type t, Expr e); //! Create a string Expr Expr vc_stringExpr(VC vc, char* str); //! Create an ID Expr Expr vc_idExpr(VC vc, char* name); //! Create a list Expr /*! Intermediate representation for DP-specific expressions. * Normally, the first element of the list is a string Expr * representing an operator, and the rest of the list are the * arguments. For example, * * kids.push_back(vc->stringExpr("PLUS")); * kids.push_back(x); // x and y are previously created Exprs * kids.push_back(y); * Expr lst = vc->listExpr(kids); * * Or, alternatively (using its overloaded version): * * Expr lst = vc->listExpr("PLUS", x, y); * * or * * vector summands; * summands.push_back(x); summands.push_back(y); ... * Expr lst = vc->listExpr("PLUS", summands); */ Expr vc_listExpr(VC vc, int numKids, Expr* kids); // Expr I/O //! Expr vc_parseExpr(VC vc, char* s); void vc_printExpr(VC vc, Expr e); //! Print e into a char* /*! Note that the ownership of the char* is given to the caller which should free the memory when it is done with it. This can be done by calling vc_deleteString. */ char* vc_printExprString(VC vc, Expr e); //! Delete char* returned by previous function void vc_deleteString(char* str); //! Print 'e' into an open file descriptor void vc_printExprFile(VC vc, Expr e, int fd); //! Import the Expr from another instance of VC /*! When expressions need to be passed among several instances of * VC, they need to be explicitly imported into the * corresponding instance using this method. The return result is * an identical expression that belongs to the current instance of * VC, and can be safely used as part of more complex * expressions from the same instance. \param vc is the instance to be imported into \param e is the expression created using a different (not vc) instance */ Expr vc_importExpr(VC vc, Expr e); //! Import the Type from another instance of VC /*! \sa vc_importExpr() */ Type vc_importType(Type t); //! Create an equality expression. The two children must have the same type. Expr vc_eqExpr(VC vc, Expr child0, Expr child1); //! Create an all distinct expression. All children must ahve the same type. Expr vc_distinctExpr(VC vc, Expr* children, int numChildren); // Boolean expressions // The following functions create Boolean expressions. The children provided // as arguments must be of type Boolean. Expr vc_trueExpr(VC vc); Expr vc_falseExpr(VC vc); Expr vc_notExpr(VC vc, Expr child); Expr vc_andExpr(VC vc, Expr left, Expr right); Expr vc_andExprN(VC vc, Expr* children, int numChildren); Expr vc_orExpr(VC vc, Expr left, Expr right); Expr vc_orExprN(VC vc, Expr* children, int numChildren); Expr vc_impliesExpr(VC vc, Expr hyp, Expr conc); Expr vc_iffExpr(VC vc, Expr left, Expr right); Expr vc_iteExpr(VC vc, Expr ifpart, Expr thenpart, Expr elsepart); // Substitution // Substitutes oldTerms for newTerms in e. // This function doesn't actually exist in ValidityChecker interface, // but it does in Expr, and its functionality is needed in the C interface. // For consistency, it is represented here as if it were in ValidityChecker. Expr vc_substExpr(VC vc, Expr e, Expr* oldTerms, int numOldTerms, Expr* newTerms, int numNewTerms); // User-defined (uninterpreted) functions. //! Create an operator from a function with a given name and type. /*! Name is given as an ID Expr, and the type must be a function type. */ Op vc_createOp(VC vc, char* name, Type type); //! Create a named user-defined function with a given type Op vc_createOpDef(VC vc, char* name, Type type, Expr def); //! Lookup an operator by name. /*! Returns the operator and the type if the operator exists. * Returns NULL otherwise */ Op vc_lookupOp(VC vc, char* name, Type* type); //! Create expressions with a user-defined operator. /*! op must have a function type. */ Expr vc_funExpr1(VC vc, Op op, Expr child); Expr vc_funExpr2(VC vc, Op op, Expr left, Expr right); Expr vc_funExpr3(VC vc, Op op, Expr child0, Expr child1, Expr child2); Expr vc_funExprN(VC vc, Op op, Expr* children, int numChildren); // Arithmetic //! Create a rational number with numerator n and denominator d. /*! d cannot be 0. */ Expr vc_ratExpr(VC vc, int n, int d); //! Create a rational number n/d; n and d are given as strings /*! n and d are converted to arbitrary-precision integers according to * the given base. d cannot be 0. */ Expr vc_ratExprFromStr(VC vc, char* n, char* d, int base); //! Create a rational from a single string. /*! \param n can be a string containing an integer, a pair of integers "nnn/ddd", or a number in the fixed or floating point format. \param base is the base in which to interpret the string. */ Expr vc_ratExprFromStr1(VC vc, char* n, int base); //! Unary minus. Child must have a numeric type. Expr vc_uminusExpr(VC vc, Expr child); // plus, minus, mult. Children must have numeric types. Expr vc_plusExpr(VC vc, Expr left, Expr right); Expr vc_plusExprN(VC vc, Expr* children, int numChildren); Expr vc_minusExpr(VC vc, Expr left, Expr right); Expr vc_multExpr(VC vc, Expr left, Expr right); Expr vc_powExpr(VC vc, Expr pow, Expr base); Expr vc_divideExpr(VC vc, Expr numerator, Expr denominator); // The following functions create less-than, less-than or equal, // greater-than, and greater-than or equal expressions of type Boolean. // Their arguments must be of numeric types. Expr vc_ltExpr(VC vc, Expr left, Expr right); Expr vc_leExpr(VC vc, Expr left, Expr right); Expr vc_gtExpr(VC vc, Expr left, Expr right); Expr vc_geExpr(VC vc, Expr left, Expr right); // Records // Create record literals; Expr vc_recordExpr1(VC vc, char* field, Expr expr); Expr vc_recordExpr2(VC vc, char* field0, Expr expr0, char* field1, Expr expr1); Expr vc_recordExpr3(VC vc, char* field0, Expr expr0, char* field1, Expr expr1, char* field2, Expr expr2); Expr vc_recordExprN(VC vc, char** fields, Expr* exprs, int numFields); //! Create an expression representing the selection of a field from a record. Expr vc_recSelectExpr(VC vc, Expr record, char* field); //! Record update; equivalent to "record WITH .field := newValue" Expr vc_recUpdateExpr(VC vc, Expr record, char* field, Expr newValue); // Arrays //! Create an expression for the value of array at the given index Expr vc_readExpr(VC vc, Expr array, Expr index); //! Array update; equivalent to "array WITH [index] := newValue" Expr vc_writeExpr(VC vc, Expr array, Expr index, Expr newValue); // Bitvectors // Additional type constructor Type vc_bv32Type(VC vc); // Bitvector constants Expr vc_bvConstExprFromStr(VC vc, char* binary_repr); Expr vc_bvConstExprFromInt(VC vc, int n_bits, unsigned int value); Expr vc_bv32ConstExprFromInt(VC vc, unsigned int value); Expr vc_bvConstExprFromLL(VC vc, int n_bits, unsigned long value); // Concat and extract Expr vc_bvConcatExpr(VC vc, Expr left, Expr right); Expr vc_bvConcatExprN(VC vc, Expr* children, int numChildren); Expr vc_bvExtract(VC vc, Expr child, int high_bit_no, int low_bit_no); Expr vc_bvBoolExtract(VC vc, Expr child, int bit_no); // Bitwise Boolean operators: Negation, And, Or, Xor Expr vc_bvNotExpr(VC vc, Expr child); Expr vc_bvAndExpr(VC vc, Expr left, Expr right); Expr vc_bvOrExpr(VC vc, Expr left, Expr right); Expr vc_bvXorExpr(VC vc, Expr left, Expr right); // Unsigned bitvector inequalities Expr vc_bvLtExpr(VC vc, Expr left, Expr right); Expr vc_bvLeExpr(VC vc, Expr left, Expr right); Expr vc_bvGtExpr(VC vc, Expr left, Expr right); Expr vc_bvGeExpr(VC vc, Expr left, Expr right); // Signed bitvector inequalities Expr vc_bvSLtExpr(VC vc, Expr left, Expr right); Expr vc_bvSLeExpr(VC vc, Expr left, Expr right); Expr vc_bvSGtExpr(VC vc, Expr left, Expr right); Expr vc_bvSGeExpr(VC vc, Expr left, Expr right); // Sign-extend child to a total of nbits bits Expr vc_bvSignExtend(VC vc, Expr child, int nbits); // Bitvector arithmetic: unary minus, plus, subtract, multiply Expr vc_bvUMinusExpr(VC vc, Expr child); Expr vc_bvPlusExpr(VC vc, int n_bits, Expr left, Expr right); Expr vc_bv32PlusExpr(VC vc, Expr left, Expr right); Expr vc_bvMinusExpr(VC vc, int n_bits, Expr left, Expr right); Expr vc_bv32MinusExpr(VC vc, Expr left, Expr right); Expr vc_bvMultExpr(VC vc, int n_bits, Expr left, Expr right); Expr vc_bv32MultExpr(VC vc, Expr left, Expr right); Expr vc_bvUDivExpr(VC vc, Expr left, Expr right); Expr vc_bvURemExpr(VC vc, Expr left, Expr right); Expr vc_bvSDivExpr(VC vc, Expr left, Expr right); Expr vc_bvSRemExpr(VC vc, Expr left, Expr right); Expr vc_bvSModExpr(VC vc, Expr left, Expr right); // Shift operators Expr vc_bvLeftShiftExpr(VC vc, int sh_amt, Expr child); Expr vc_bvRightShiftExpr(VC vc, int sh_amt, Expr child); Expr vc_bv32LeftShiftExpr(VC vc, int sh_amt, Expr child); Expr vc_bv32RightShiftExpr(VC vc, int sh_amt, Expr child); Expr vc_bvVar32LeftShiftExpr(VC vc, Expr sh_amt, Expr child); Expr vc_bvVar32RightShiftExpr(VC vc, Expr sh_amt, Expr child); Expr vc_bvVar32DivByPowOfTwoExpr(VC vc, Expr child, Expr rhs); /*C pointer support: C interface to support C memory arrays in CVC3 */ Expr vc_bvCreateMemoryArray(VC vc, char * arrayName); Expr vc_bvReadMemoryArray(VC vc, Expr array, Expr byteIndex, int numOfBytes); Expr vc_bvWriteToMemoryArray(VC vc, Expr array, Expr byteIndex, Expr element, int numOfBytes); // Tuples //! Create a tuple expression /*! 'children' is an array of elements of length numChildren */ Expr vc_tupleExprN(VC vc, Expr* children, int numChildren); //! Tuple select; equivalent to "tuple.n", where n is an numeral (e.g. tup.5) Expr vc_tupleSelectExpr(VC vc, Expr tuple, int index); //! Tuple update; equivalent to "tuple WITH index := newValue" Expr vc_tupleUpdateExpr(VC vc, Expr tuple, int index, Expr newValue); // Datatypes //! Datatype constructor expression Expr vc_datatypeConsExpr(VC vc, char* constructor, int numArgs, Expr* args); //! Datatype selector expression Expr vc_datatypeSelExpr(VC vc, char* selector, Expr arg); //! Datatype tester expression Expr vc_datatypeTestExpr(VC vc, char* constructor, Expr arg); // Quantifiers //! Create a bound variable. /*! \param name * \param uid is a fresh unique string to distinguish this variable * from other bound variables with the same name * \param type */ Expr vc_boundVarExpr(VC vc, char* name, char *uid, Type type); //! Create a FORALL quantifier. /*! Bvars is an array of bound variables of length numBvars. */ Type vc_forallExpr(VC vc, Expr* Bvars, int numBvars, Expr f); //! Set triggers for a forallExpr void vc_setTriggers(VC vc, Expr e, int numTrigs, Expr* triggers); //! Create an EXISTS quantifier. /*! Bvars is an array of bound variables of length numBvars. */ Expr vc_existsExpr(VC vc, Expr* Bvars, int numBvars, Expr f); //! Lambda-expression Op vc_lambdaExpr(VC vc, int numVars, Expr* vars, Expr body); ///////////////////////////////////////////////////////////////////////////// // Context-related methods // ///////////////////////////////////////////////////////////////////////////// //! Set the resource limit (0==unlimited, 1==exhausted). /*! Currently, the limit is the total number of processed facts. */ void vc_setResourceLimit(VC vc, unsigned limit); //! Assert a new formula in the current context. /*! The formula must have Boolean type. */ void vc_assertFormula(VC vc, Expr e); //! Register an atomic formula of interest. /*! Registered atoms are tracked by the decision procedures. If one of them is deduced to be true or false, it is added to a list of implied literals. Implied literals can be retrieved with the getImpliedLiteral function */ void vc_registerAtom(VC vc, Expr e); //! Return next literal implied by last assertion. Null if none. /*! Returned literals are either registered atomic formulas or their negation */ Expr vc_getImpliedLiteral(VC vc); //! Simplify e with respect to the current context Expr vc_simplify(VC vc, Expr e); //! Check validity of e in the current context. /*! Possible results are: 0 = invalid, 1 = valid, 2 = abort, 3 = unknown, * -100 = exception (type error, internal error, etc). * If the result is 1, then the resulting context is the same as * the starting context. If the result is 0 or 3, then the resulting * context is a context in which e is false (though the context may be * inconsistent in the case of an unknown result). e must have Boolean * type. In the case of a result of -100, refer to vc_get_error_string() * to see what went wrong. */ int vc_query(VC vc, Expr e); //! Get the next model /*! This method should only be called after a query which returns 0. Its return values are as for vc_query(). */ int vc_checkContinue(VC vc); //! Restart the most recent query with e as an additional assertion. /*! This method should only be called after a query which returns 0. Its return values are as for vc_query(). */ int vc_restart(VC vc, Expr e); //! Returns to context immediately before last invalid query. /*! This method should only be called after a query which returns 0. */ void vc_returnFromCheck(VC vc); //! Get assumptions made by the user in this and all previous contexts. /*! User assumptions are created either by calls to assertFormula or by a * call to query. In the latter case, the negated query is added as an * assumption. The caller is responsible for freeing the array when * finished with it. */ Expr* vc_getUserAssumptions(VC vc, int* size); //! Get assumptions made internally in this and all previous contexts. /*! Internal assumptions are literals assumed by the sat solver. * The caller is responsible for freeing the array when finished with it by * calling vc_deleteVector. */ Expr* vc_getInternalAssumptions(VC vc, int* size); //! Get all assumptions made in this and all previous contexts. /*! * The caller is responsible for freeing the array when finished with it by * calling vc_deleteVector. */ Expr* vc_getAssumptions(VC vc, int* size); //yeting, for proof translation, get the assumptions used. //the assumptions used are different from the user assumptions. //the assumptions used are preprocessed if 'preprocess' is ena Expr vc_getProofAssumptions(VC vc); //yeting, for proof translation, Expr vc_getProofQuery(VC vc); //! Returns the set of assumptions used in the proof of queried formula. /*! It returns a subset of getAssumptions(). If the last query was false * or there has not yet been a query, it does nothing. * The caller is responsible for freeing the array when finished with it by * calling vc_deleteVector. */ Expr* vc_getAssumptionsUsed(VC vc, int* size); //! Return the counterexample after a failed query. /*! This method should only be called after a query which returns * false. It will try to return the simplest possible set of * assertions which are sufficient to make the queried expression * false. The caller is responsible for freeing the array when finished with * it by calling vc_deleteVector. */ Expr* vc_getCounterExample(VC vc, int* size); //! Will assign concrete values to all user created variables /*! This function should only be called after a query which return false. * Returns an array of Exprs with size *size. * The caller is responsible for freeing the array when finished with it by * calling vc_deleteVector. */ Expr* vc_getConcreteModel(VC vc, int* size); // Returns true if the current context is inconsistent. /*! Also returns a minimal set of assertions used to determine the * inconsistency. The caller is responsible for freeing the array when finished * with it by calling vc_deleteVector. */ int vc_inconsistent(VC vc, Expr** assumptions, int* size); //! Returns non-NULL if the invalid result from last query() is imprecise /*! * The return value is filled with the reasons for incompleteness (it * is intended to be shown to the end user). The caller is responsible for * freeing the string returned by calling vc_deleteString. */ char* vc_incomplete(VC vc); //! Returns the proof for the last proven query Expr vc_getProof(VC vc); //! Returns the proof of a .cvc file, if it is valid. Expr vc_getProofOfFile(VC vc, char * filename); //! Returns the TCC of the last assumption or query /*! Returns Null Expr if no assumptions or queries were performed. */ Expr vc_getTCC(VC vc); //! Return the set of assumptions used in the proof of the last TCC /*! The caller is responsible for freeing the array when finished with it by * calling vc_deleteVector. */ Expr* vc_getAssumptionsTCC(VC vc, int* size); //! Returns the proof of TCC of the last assumption or query /*! Returns Null Expr if no assumptions or queries were performed. */ Expr vc_getProofTCC(VC vc); //! After successful query, return its closure |- Gamma => phi /*! Turn a valid query Gamma |- phi into an implication * |- Gamma => phi. * * Returns Null Expr if last query was invalid. */ Expr vc_getClosure(VC vc); //! Construct a proof of the query closure |- Gamma => phi /*! Returns Null if last query was Invalid. */ Expr vc_getProofClosure(VC vc); //! Returns the current stack level. Initial level is 0. int vc_stackLevel(VC vc); //! Checkpoint the current context and increase the scope level void vc_push(VC vc); //! Restore the current context to its state at the last checkpoint void vc_pop(VC vc); //! Restore the current context to the given stackLevel. /*! stackLevel must be less than or equal to the current stack level. */ void vc_popto(VC vc, int stackLevel); //! Get the current context Context* vc_getCurrentContext(VC vc); /* ---------------------------------------------------------------------- */ /* Util */ /* ---------------------------------------------------------------------- */ // Order //! Compares two expressions /*! If e1 < e2, e1==e2, and e1 > e2, it returns -1, 0, 1 * respectively. A return value of -100 signals an error (refer to * vc_get_error_string() for details). * * Can't be 'compare' because already defined in ocaml */ int vc_compare_exprs(Expr e1,Expr e2); // Printing //! Convert Expr to string char* vc_exprString(Expr e); //! Convert Type to string char* vc_typeString(Type t); // What kind of Expr? int vc_isClosure(Expr e); int vc_isQuantifier(Expr e); int vc_isLambda(Expr e); Expr vc_isVar(Expr e); int vc_arity(Expr e); int vc_getKind(Expr e); Expr vc_getChild(Expr e, int i); int vc_getNumVars(Expr e); Expr vc_getVar(Expr e, int i); Expr vc_getBody(Expr e); Expr vc_getExistential(Expr e); Expr vc_getFun(VC vc, Expr e); Expr vc_toExpr(Type t); //! Translate a kind int to a string const char* vc_getKindString(VC vc,int kind); //! Translate a kind string to an int int vc_getKindInt(VC vc,char* kind_name); //! Return an int from a rational expression int vc_getInt(Expr e); //! Return an int from a constant bitvector expression int vc_getBVInt(VC vc, Expr e); //! Return an unsigned int from a constant bitvector expression unsigned int vc_getBVUnsigned(VC vc, Expr e); // Debug int vc_get_error_status(); void vc_reset_error_status(); char* vc_get_error_string(); //! Print statistics void vc_print_statistics(VC vc); #endif cvc3-2.4.1/src/include/smartcdo.h0000664000175400017540000000774511172145605016474 0ustar mdetersmdeters/*****************************************************************************/ /*! *\file smartcdo.h *\brief Smart context-dependent object wrapper * * Author: Clark Barrett * * Created: Fri Nov 12 17:28:58 2004 * *
* * License to use, copy, modify, sell and/or distribute this software * and its documentation for any purpose is hereby granted without * royalty, subject to the terms and conditions defined in the \ref * LICENSE file provided with this distribution. * *
* */ /*****************************************************************************/ #ifndef _cvc3__include__smartcdo_h_ #define _cvc3__include__smartcdo_h_ #include "cdo.h" namespace CVC3 { /*****************************************************************************/ /*! *\class SmartCDO *\brief SmartCDO * * Author: Clark Barrett * * Created: Fri Nov 12 17:33:31 2004 * * Wrapper for CDO which automatically allocates and deletes a pointer to a * CDO. This allows the copy constructor and operator= to be defined which are * especially useful for storing CDO's in vectors. All operations are const to * enable use as a member of CDLists. * * Be careful not to delete RefCDO during pop(), since this messes up * the backtracking data structures. We delay the deletion by * registering each RefCDO to be notified before and after each pop(). * This makes the use of SmartCDO somewhat more expensive, so use it * with care. * */ /*****************************************************************************/ template class SmartCDO { template class RefCDO { friend class SmartCDO; unsigned d_refCount; CDO d_cdo; bool d_delay; //!< Whether to delay our own deletion class RefNotifyObj : public ContextNotifyObj { friend class RefCDO; RefCDO* d_ref; //! Constructor RefNotifyObj(RefCDO* ref, Context* context) : ContextNotifyObj(context), d_ref(ref) { } void notifyPre() { d_ref->d_delay = true; } void notify() { d_ref->d_delay = false; d_ref->kill(); } }; RefNotifyObj* d_notifyObj; friend class RefNotifyObj; RefCDO(Context* context): d_refCount(0), d_cdo(context), d_delay(false), d_notifyObj(new RefNotifyObj(this, context)) {} RefCDO(Context* context, const U& cdo, int scope = -1) : d_refCount(0), d_cdo(context, cdo, scope), d_delay(false), d_notifyObj(new RefNotifyObj(this, context)) {} ~RefCDO() { delete d_notifyObj; } //! Delete itself, unless delayed (then we'll be called again later) void kill() { if(d_refCount==0 && !d_delay) delete this; } }; RefCDO* d_data; public: //! Check if the SmartCDO object is Null bool isNull() const { return (d_data==NULL); } //! Default constructor: create a Null SmartCDO object SmartCDO(): d_data(NULL) { } //! Create and initialize SmartCDO object at the current scope SmartCDO(Context* context) { d_data = new RefCDO(context); d_data->d_refCount++; } //! Create and initialize SmartCDO object at the given scope SmartCDO(Context* context, const T& data, int scope = -1) { d_data = new RefCDO(context, data, scope); d_data->d_refCount++; } //! Delete ~SmartCDO() { if (isNull()) return; if (--d_data->d_refCount == 0) d_data->kill(); } SmartCDO(const SmartCDO& cdo) : d_data(cdo.d_data) { if (!isNull()) d_data->d_refCount++; } SmartCDO& operator=(const SmartCDO& cdo) { if (this == &cdo) return *this; if (!isNull() && --(d_data->d_refCount)) d_data->kill(); d_data = cdo.d_data; if (!isNull()) ++(d_data->d_refCount); return *this; } void set(const T& data, int scope=-1) const { DebugAssert(!isNull(), "SmartCDO::set: we are Null"); d_data->d_cdo.set(data, scope); } const T& get() const { DebugAssert(!isNull(), "SmartCDO::get: we are Null"); return d_data->d_cdo.get(); } operator T() const { return get(); } const SmartCDO& operator=(const T& data) const {set(data); return *this;} }; } #endif cvc3-2.4.1/src/include/smtlib_exception.h0000664000175400017540000000227311026606025020213 0ustar mdetersmdeters/*****************************************************************************/ /*! * \file smtlib_exception.h * \brief An exception to be thrown by the smtlib translator. * * Author: Clark Barrett * * Created: Thu Feb 24 18:22:18 2005 * *
* * License to use, copy, modify, sell and/or distribute this software * and its documentation for any purpose is hereby granted without * royalty, subject to the terms and conditions defined in the \ref * LICENSE file provided with this distribution. * *
* */ /*****************************************************************************/ #ifndef _cvc3__smtlib_exception_h_ #define _cvc3__smtlib_exception_h_ #include #include #include "exception.h" namespace CVC3 { class SmtlibException: public Exception { public: // Constructors SmtlibException() { } SmtlibException(const std::string& msg): Exception(msg) { } SmtlibException(const char* msg): Exception(msg) { } // Destructor virtual ~SmtlibException() { } virtual std::string toString() const { return "SMTLIB translation error: " + d_msg; } }; // end of class SmtlibException } // end of namespace CVC3 #endif cvc3-2.4.1/src/include/theory_datatype.h0000664000175400017540000001162111221406446020047 0ustar mdetersmdeters/*****************************************************************************/ /*! *\file theory_datatype.h * * Author: Clark Barrett * * Created: Wed Dec 1 22:24:32 2004 * *
* * License to use, copy, modify, sell and/or distribute this software * and its documentation for any purpose is hereby granted without * royalty, subject to the terms and conditions defined in the \ref * LICENSE file provided with this distribution. * *
* */ /*****************************************************************************/ #ifndef _cvc3__include__theory_datatype_h_ #define _cvc3__include__theory_datatype_h_ #include "theory.h" #include "smartcdo.h" #include "cdmap.h" namespace CVC3 { class DatatypeProofRules; //! Local kinds for datatypes typedef enum { DATATYPE_DECL = 600, DATATYPE, CONSTRUCTOR, SELECTOR, TESTER } DatatypeKinds; /*****************************************************************************/ /*! *\class TheoryDatatype *\ingroup Theories *\brief This theory handles datatypes. * * Author: Clark Barrett * * Created: Wed Dec 1 22:27:12 2004 */ /*****************************************************************************/ class TheoryDatatype :public Theory { protected: DatatypeProofRules* d_rules; // maps DATATYPE expressions to map containing constructors for that datatype ExprMap > d_datatypes; // maps constructor to its selectors ExprMap > d_constructorMap; // maps selector to a pair containing the constructor and the position of the selctor for that constructor ExprMap > d_selectorMap; // maps tester to constructor that it matches ExprMap d_testerMap; ExprMap d_reach; CDMap > d_labels; CDList d_facts; CDList d_splitters; CDO d_splittersIndex; CDO d_splitterAsserted; const bool& d_smartSplits; ExprMap d_getConstantStack; protected: virtual void instantiate(const Expr& e, const Unsigned& u); virtual void initializeLabels(const Expr& e, const Type& t); virtual void mergeLabels(const Theorem& thm, const Expr& e1, const Expr& e2); virtual void mergeLabels(const Theorem& thm, const Expr& e, unsigned position, bool positive); public: TheoryDatatype(TheoryCore* theoryCore); virtual ~TheoryDatatype(); // Trusted method that creates the proof rules class (used in constructor). // Implemented in datatype_theorem_producer.cpp DatatypeProofRules* createProofRules(); // Theory interface void addSharedTerm(const Expr& e); void assertFact(const Theorem& e); virtual void checkSat(bool fullEffort); Theorem rewrite(const Expr& e); virtual void setup(const Expr& e); virtual void update(const Theorem& e, const Expr& d); Theorem solve(const Theorem& e); void checkType(const Expr& e); Cardinality finiteTypeInfo(Expr& e, Unsigned& n, bool enumerate, bool computeSize); void computeType(const Expr& e); void computeModelTerm(const Expr& e, std::vector& v); Expr computeTCC(const Expr& e); Expr parseExprOp(const Expr& e); ExprStream& print(ExprStream& os, const Expr& e); // Returns Expr(DATATYPE_DECL datatype) Expr dataType(const std::string& name, const std::vector& constructors, const std::vector >& selectors, const std::vector >& types); // Returns Expr(DATATYPE_DECL type_1, type_2, ...) Expr dataType(const std::vector& names, const std::vector >& constructors, const std::vector > >& selectors, const std::vector > >& types); Expr datatypeConsExpr(const std::string& constructor, const std::vector& args); Expr datatypeSelExpr(const std::string& selector, const Expr& arg); Expr datatypeTestExpr(const std::string& constructor, const Expr& arg); const std::pair& getSelectorInfo(const Expr& e); Expr getConsForTester(const Expr& e); unsigned getConsPos(const Expr& e); Expr getConstant(const Type& t); const Op& getReachablePredicate(const Type& t); bool canCollapse(const Expr& e); }; inline bool isDatatype(const Type& t) { return t.getExpr().getKind() == DATATYPE; } inline bool isConstructor(const Expr& e) { return (e.getKind() == CONSTRUCTOR && e.getType().arity()==1) || (e.isApply() && e.getOpKind() == CONSTRUCTOR); } inline bool isSelector(const Expr& e) { return e.isApply() && e.getOpKind() == SELECTOR; } inline bool isTester(const Expr& e) { return e.isApply() && e.getOpKind() == TESTER; } inline Expr getConstructor(const Expr& e) { DebugAssert(isConstructor(e), "Constructor expected"); return e.isApply() ? e.getOpExpr() : e; } } #endif cvc3-2.4.1/src/include/cdlist.h0000664000175400017540000000665710656155007016146 0ustar mdetersmdeters/*****************************************************************************/ /*! * \file cdlist.h * * Author: Clark Barrett * * Created: Wed Feb 12 18:45:26 2003 * *
* * License to use, copy, modify, sell and/or distribute this software * and its documentation for any purpose is hereby granted without * royalty, subject to the terms and conditions defined in the \ref * LICENSE file provided with this distribution. * *
* */ /*****************************************************************************/ #ifndef _cvc3__include__cdlist_h_ #define _cvc3__include__cdlist_h_ #include "context.h" #include namespace CVC3 { /////////////////////////////////////////////////////////////////////////////// // // // Class: CDList (Context Dependent List) // // Author: Clark Barrett // // Created: Wed Feb 12 17:28:25 2003 // // Description: Generic templated class for list which grows monotonically // // over time (if the context is not popped) but must also be // // saved and restored as contexts are pushed and popped. // // // /////////////////////////////////////////////////////////////////////////////// // TODO: more efficient implementation template class CDList :public ContextObj { //! The actual data. /*! Use deque because it doesn't create/destroy data on resize. This pointer is only non-NULL in the master copy. */ std::deque* d_list; // unsigned d_size; virtual ContextObj* makeCopy(ContextMemoryManager* cmm) { return new(cmm) CDList(*this); } virtual void restoreData(ContextObj* data) { d_size = ((CDList*)data)->d_size; while (d_list->size() > d_size) d_list->pop_back(); } virtual void setNull(void) { while (d_list->size()) d_list->pop_back(); d_size = 0; } // Copy constructor (private). Do NOT copy d_list. It's not used // in restore, and it will be deleted in destructor. CDList(const CDList& l): ContextObj(l), d_list(NULL), d_size(l.d_size) { } public: CDList(Context* context) : ContextObj(context), d_size(0) { d_list = new std::deque(); IF_DEBUG(setName("CDList");) } virtual ~CDList() { if(d_list != NULL) delete d_list; } unsigned size() const { return d_size; } bool empty() const { return d_size == 0; } T& push_back(const T& data, int scope = -1) { makeCurrent(scope); d_list->push_back(data); ++d_size; return d_list->back(); } void pop_back() { DebugAssert(isCurrent() && getRestore() && d_size > ((CDList*)getRestore())->d_size, "pop_back precond violated"); d_list->pop_back(); --d_size; } const T& operator[](unsigned i) const { DebugAssert(i < size(), "CDList["+int2string(i)+"]: i < size="+int2string(size())); return (*d_list)[i]; } const T& at(unsigned i) const { DebugAssert(i < size(), "CDList["+int2string(i)+"]: i < size="+int2string(size())); return (*d_list)[i]; } const T& back() const { DebugAssert(size() > 0, "CDList::back(): size="+int2string(size())); return d_list->back(); } typedef typename std::deque::const_iterator const_iterator; const_iterator begin() const { return d_list->begin(); } const_iterator end() const { return begin() + d_size; } }; } #endif cvc3-2.4.1/src/include/context.h0000664000175400017540000003310511152032743016325 0ustar mdetersmdeters/*****************************************************************************/ /*! * \file context.h * * Author: Clark Barrett * * Created: Tue Dec 31 19:07:38 2002 * *
* * License to use, copy, modify, sell and/or distribute this software * and its documentation for any purpose is hereby granted without * royalty, subject to the terms and conditions defined in the \ref * LICENSE file provided with this distribution. * *
* */ /*****************************************************************************/ #ifndef _cvc3__include__context_h_ #define _cvc3__include__context_h_ #include #include #include #include "debug.h" #include "memory_manager_context.h" #include "os.h" namespace CVC3 { /****************************************************************************/ /*! \defgroup Context Context Management * \ingroup BuildingBlocks * Infrastructure for backtrackable data structures. * @{ */ /****************************************************************************/ class Context; class ContextManager; class ContextNotifyObj; class ContextObj; class ContextObjChain; /****************************************************************************/ /*! * Author: Clark Barrett * * Created: Thu Feb 13 00:19:15 2003 * * A scope encapsulates the portion of a context which has changed * since the last call to push(). Thus, when pop() is called, * everything in this scope is restored to its previous state. */ /****************************************************************************/ class Scope { friend class ContextObj; friend class ContextObjChain; friend class CDFlags; //! Context that created this scope Context* d_context; //! Memory manager for this scope ContextMemoryManager* d_cmm; //! Previous scope in this context Scope* d_prevScope; //! Scope level int d_level; /*! @brief Linked list of objects which are "current" in this scope, and thus need to be restored when the scope is deleted */ ContextObjChain* d_restoreChain; //! Called by ContextObj when created void addToChain(ContextObjChain* obj); public: //! Constructor Scope(Context* context, ContextMemoryManager* cmm, Scope* prevScope = NULL) : d_context(context), d_cmm(cmm), d_prevScope(prevScope), d_restoreChain(NULL) { if (prevScope) d_level = prevScope->level() + 1; else d_level = 0; } //! Destructor ~Scope() {} //! Access functions Scope* prevScope() const { return d_prevScope; } int level(void) const { return d_level; } bool isCurrent(void) const; Scope* topScope() const; Context* getContext() const { return d_context; } ContextMemoryManager* getCMM() const { return d_cmm; } void* operator new(size_t size, MemoryManager* mm) { return mm->newData(size); } void operator delete(void* pMem, MemoryManager* mm) { mm->deleteData(pMem); } void operator delete(void*) { } //! Restore all the values void restore(void); //! Called by ~ContextManager void finalize(void); //! Check for memory leaks void check(void); //! Compute memory used unsigned long getMemory(int verbosity); }; /////////////////////////////////////////////////////////////////////////////// // // // Class: ContextObjChain // // Author: Sergey Berezin // // Created: Wed Mar 12 11:25:22 2003 // /*! Description: An element of a doubly linked list holding a copy of * ContextObj in a scope. It is made separate from ContextObj to keep * the list pointers valid in all scopes at all times, so that the * object can be easily removed from the list when the master * ContextObj is destroyed. */ /////////////////////////////////////////////////////////////////////////////// class ContextObjChain { friend class Scope; friend class ContextObj; friend class CDFlags; private: //! Next link in chain ContextObjChain* d_restoreChainNext; /*! @brief Pointer to the pointer of the previous object which points to us. This makes a doubly-linked list for easy element deletion */ ContextObjChain** d_restoreChainPrev; //! Pointer to the previous copy which belongs to the same master ContextObjChain* d_restore; //! Pointer to copy of master to be restored when restore() is called ContextObj* d_data; //! Pointer to the master object ContextObj* d_master; //! Private constructor (only friends can use it) ContextObjChain(ContextObj* data, ContextObj* master, ContextObjChain* restore) : d_restoreChainNext(NULL), d_restoreChainPrev(NULL), d_restore(restore), d_data(data), d_master(master) { } //! Restore from d_data to d_master ContextObjChain* restore(void); public: //! Destructor ~ContextObjChain() {} void* operator new(size_t size, MemoryManager* mm) { return mm->newData(size); } void operator delete(void* pMem, MemoryManager* mm) { mm->deleteData(pMem); } void operator delete(void*) { } // If you use this operator, you have to call free yourself when the memory // is freed. void* operator new(size_t size, bool b) { return malloc(size); } void operator delete(void* pMem, bool b) { free(pMem); } IF_DEBUG(std::string name() const;) }; /////////////////////////////////////////////////////////////////////////////// // // // Class: ContextObj // // Author: Clark Barrett // // Created: Thu Feb 13 00:21:13 2003 // /*! Description: This is a generic class from which all objects that * are context-dependent should inherit. Subclasses need to implement * makeCopy, restoreData, and setNull. */ /////////////////////////////////////////////////////////////////////////////// class CVC_DLL ContextObj { friend class Scope; friend class ContextObjChain; friend class CDFlags; private: //! Last scope in which this object was modified. Scope* d_scope; /*! @brief The list of values on previous scopes; our destructor * should clean up those. */ ContextObjChain* d_restore; IF_DEBUG(std::string d_name;) IF_DEBUG(bool d_active;) //! Update on the given scope, on the current scope if 'scope' == -1 void update(int scope = -1); protected: //! Copy constructor (defined mainly for debugging purposes) ContextObj(const ContextObj& co) : d_scope(co.d_scope), d_restore(co.d_restore) { IF_DEBUG(d_name=co.d_name;) DebugAssert(co.d_active, "ContextObj["+co.name()+"] copy constructor"); IF_DEBUG(d_active = co.d_active;) // TRACE("context verbose", "ContextObj()[", this, "]: copy constructor"); } //! Assignment operator (defined mainly for debugging purposes) ContextObj& operator=(const ContextObj& co) { DebugAssert(false, "ContextObj::operator=(): shouldn't be called"); return *this; } /*! @brief Make a copy of the current object so it can be restored * to its current state */ virtual ContextObj* makeCopy(ContextMemoryManager* cmm) = 0; //! Restore the current object from the given data virtual void restoreData(ContextObj* data) { FatalAssert(false, "ContextObj::restoreData(): call in the base abstract class"); } const ContextObj* getRestore() { return d_restore ? d_restore->d_data : NULL; } //! Set the current object to be invalid virtual void setNull(void) = 0; //! Return our name (for debugging) IF_DEBUG(virtual std::string name() const { return d_name; }) //! Get context memory manager ContextMemoryManager* getCMM() { return d_scope->getCMM(); } public: //! Create a new ContextObj. /*! * The initial scope is set to the bottom scope by default, to * reduce the work of pop() (otherwise, if the object is defined * only on a very high scope, its scope will be moved down with each * pop). If 'atBottomScope' == false, the scope is set to the * current scope. */ ContextObj(Context* context); virtual ~ContextObj(); int level() const { return (d_scope==NULL)? 0 : d_scope->level(); } bool isCurrent(int scope = -1) const { if(scope >= 0) return d_scope->level() == scope; else return d_scope->isCurrent(); } void makeCurrent(int scope = -1) { if (!isCurrent(scope)) update(scope); } IF_DEBUG(void setName(const std::string& name) { d_name=name; }) void* operator new(size_t size, MemoryManager* mm) { return mm->newData(size); } void operator delete(void* pMem, MemoryManager* mm) { mm->deleteData(pMem); } // If you use this operator, you have to call free yourself when the memory // is freed. void* operator new(size_t size, bool b) { return malloc(size); } void operator delete(void* pMem, bool b) { free(pMem); } void operator delete(void*) { } }; /////////////////////////////////////////////////////////////////////////////// // // // Class: Context // // Author: Clark Barrett // // Created: Thu Feb 13 00:24:59 2003 // /*! * Encapsulates the general notion of stack-based saving and restoring * of a database. */ /////////////////////////////////////////////////////////////////////////////// class CVC_DLL Context { //! Context Manager ContextManager* d_cm; //! Name of context std::string d_name; //! Context ID int d_id; //! Pointer to top and bottom scopes of context Scope* d_topScope; Scope* d_bottomScope; //! List of objects to notify with every pop std::vector d_notifyObjList; //! Stack of free ContextMemoryManager's std::vector d_cmmStack; public: Context(ContextManager* cm, const std::string& name, int id); ~Context(); //! Access methods ContextManager* getCM() const { return d_cm; } const std::string& name() const { return d_name; } int id() const { return d_id; } Scope* topScope() const { return d_topScope; } Scope* bottomScope() const { return d_bottomScope; } int level() const { return d_topScope->level(); } void push(); void pop(); void popto(int toLevel); void addNotifyObj(ContextNotifyObj* obj) { d_notifyObjList.push_back(obj); } void deleteNotifyObj(ContextNotifyObj* obj); unsigned long getMemory(int verbosity); }; // Have to define after Context class inline bool Scope::isCurrent(void) const { return this == d_context->topScope(); } inline void Scope::addToChain(ContextObjChain* obj) { if(d_restoreChain != NULL) d_restoreChain->d_restoreChainPrev = &(obj->d_restoreChainNext); obj->d_restoreChainNext = d_restoreChain; obj->d_restoreChainPrev = &d_restoreChain; d_restoreChain = obj; } inline Scope* Scope::topScope() const { return d_context->topScope(); } inline void Scope::restore(void) { // TRACE_MSG("context verbose", "Scope::restore() {"); while (d_restoreChain != NULL) d_restoreChain = d_restoreChain->restore(); // TRACE_MSG("context verbose", "Scope::restore() }"); } // Create a new ContextObj. The initial scope is set to the bottom // scope by default, to reduce the work of pop() (otherwise, if the // object is defined only on a very high scope, its scope will be // moved down with each pop). If 'atBottomScope' == false, the // scope is set to the current scope. inline ContextObj::ContextObj(Context* context) IF_DEBUG(: d_name("ContextObj")) { IF_DEBUG(d_active=true;) DebugAssert(context != NULL, "NULL context pointer"); d_scope = context->bottomScope(); d_restore = new(true) ContextObjChain(NULL, this, NULL); d_scope->addToChain(d_restore); // if (atBottomScope) d_scope->addSpecialObject(d_restore); // TRACE("context verbose", "ContextObj()[", this, "]"); } /****************************************************************************/ //! Manager for multiple contexts. Also holds current context. /*! * Author: Clark Barrett * * Created: Thu Feb 13 00:26:29 2003 */ /****************************************************************************/ class ContextManager { Context* d_curContext; std::vector d_contexts; public: ContextManager(); ~ContextManager(); void push() { d_curContext->push(); } void pop() { d_curContext->pop(); } void popto(int toLevel) { d_curContext->popto(toLevel); } int scopeLevel() { return d_curContext->level(); } Context* createContext(const std::string& name=""); Context* getCurrentContext() { return d_curContext; } Context* switchContext(Context* context); unsigned long getMemory(int verbosity); }; /****************************************************************************/ /*! Author: Clark Barrett * * Created: Sat Feb 22 16:21:47 2003 * * Lightweight version of ContextObj: objects are simply notified * every time there's a pop. notifyPre() is called right before the * context is restored, and notify() is called after the context is * restored. */ /****************************************************************************/ class ContextNotifyObj { friend class Context; protected: Context* d_context; public: ContextNotifyObj(Context* context): d_context(context) { context->addNotifyObj(this); } virtual ~ContextNotifyObj() { // If we are being deleted before the context, remove ourselves // from the notify list. However, if the context is deleted // before we are, then our d_context will be cleared from ~Context() if(d_context!=NULL) d_context->deleteNotifyObj(this); } virtual void notifyPre(void) {} virtual void notify(void) {} virtual unsigned long getMemory(int verbosity) { return sizeof(ContextNotifyObj); } }; /*@}*/ // end of group Context } #endif cvc3-2.4.1/src/include/sat_api.h0000664000175400017540000002620410500320634016256 0ustar mdetersmdeters/////////////////////////////////////////////////////////////////////////////// // // // File: sat_api.h // // Author: Clark Barrett // // Created: Tue Oct 22 11:30:54 2002 // // Description: Generic enhanced SAT API // // // /////////////////////////////////////////////////////////////////////////////// #ifndef _SAT_API_H_ #define _SAT_API_H_ #include #include /////////////////////////////////////////////////////////////////////////////// // // // Class: SAT // // Author: Clark Barrett // // Created: Tue Oct 22 12:02:53 2002 // // Description: API for generic SAT solver with enhanced interface features. // // // /////////////////////////////////////////////////////////////////////////////// class SatSolver { public: typedef enum SATStatus { UNKNOWN, UNSATISFIABLE, SATISFIABLE, BUDGET_EXCEEDED, OUT_OF_MEMORY } SATStatus; // Constructor and Destructor SatSolver() {} virtual ~SatSolver() {} // Implementation must provide this function static SatSolver *Create(); ///////////////////////////////////////////////////////////////////////////// // Variables, Literals, and Clauses // ///////////////////////////////////////////////////////////////////////////// // Variables, literals and clauses are all simple union classes. This makes // it easy to use integers or pointers to some more complex data structure // for the implementation while at the same time increasing safety by // imposing strict type requirements on users of the API. // The value -1 is reserved to represent an empty or NULL value union Var { long id; void *vptr; Var() : id(-1) {} bool IsNull() { return id == -1; } void Reset() { id = -1; } }; union Lit { long id; void *vptr; Lit() : id(-1) {} bool IsNull() { return id == -1; } void Reset() { id = -1; } }; union Clause { long id; void *vptr; Clause() : id(-1) {} bool IsNull() { return id == -1; } void Reset() { id = -1; } }; // Return total number of variables virtual int NumVariables()=0; // Returns the first of nvar new variables. virtual Var AddVariables(int nvars)=0; // Return a new variable Var AddVariable() { return AddVariables(1); } // Get the varIndexth variable. varIndex must be between 1 and // NumVariables() inclusive. virtual Var GetVar(int varIndex)=0; // Return the index (between 1 and NumVariables()) of v. virtual int GetVarIndex(Var v)=0; // Get the first variable. Returns a NULL Var if there are no variables. virtual Var GetFirstVar()=0; // Get the next variable after var. Returns a NULL Var if var is the last // variable. virtual Var GetNextVar(Var var)=0; // Return a literal made from the given var and phase (0 is positive phase, 1 // is negative phase). virtual Lit MakeLit(Var var, int phase)=0; // Get var from literal. virtual Var GetVarFromLit(Lit lit)=0; // Get phase from literal ID. virtual int GetPhaseFromLit(Lit lit)=0; // Return total number of clauses virtual int NumClauses()=0; // Add a new clause. Lits is a vector of literal ID's. Note that this // function can be called at any time, even after the search for solution has // started. A clause ID is returned which can be used to refer to this // clause in the future. virtual Clause AddClause(std::vector& lits)=0; // Delete a clause. This can only be done if the clause has unassigned // literals and it must delete not only the clause in question, but // any learned clauses which depend on it. Since this may be difficult to // implement, implementing this function is not currently required. // DeleteClause returns true if the clause was successfully deleted, and // false otherwise. virtual bool DeleteClause(Clause clause) { return false; } // Get the clauseIndexth clause. clauseIndex must be between 0 and // NumClauses()-1 inclusive. virtual Clause GetClause(int clauseIndex)=0; // Get the first clause. Returns a NULL Clause if there are no clauses. virtual Clause GetFirstClause()=0; // Get the next clause after clause. Returns a NULL Clause if clause is // the last clause. virtual Clause GetNextClause(Clause clause)=0; // Returns in lits the literals that make up clause. lits is assumed to be // empty when the function is called. virtual void GetClauseLits(Clause clause, std::vector* lits)=0; ///////////////////////////////////////////////////////////////////////////// // Checking Satisfiability and Retrieving Solutions // ///////////////////////////////////////////////////////////////////////////// // Main check for satisfiability. The parameter allowNewClauses tells the // solver whether to expect additional clauses to be added by the API during // the search for a solution. The default is that no new clauses will be // added. If new clauses can be added, then certain optimizations such as // the pure literal rule must be disabled. virtual SATStatus Satisfiable(bool allowNewClauses=false)=0; // Get current value of variable. -1=unassigned, 0=false, 1=true virtual int GetVarAssignment(Var var)=0; // After Satisfiable has returned with a SATISFIABLE result, this function // may be called to search for the next satisfying assignment. If one is // found then SATISFIABLE is returned. If there are no more satisfying // assignments then UNSATISFIABLE is returned. virtual SATStatus Continue()=0; // Pop all decision levels and remove all assignments, but do not delete any // clauses virtual void Restart()=0; // Pop all decision levels, remove all assignments, and delete all clauses. virtual void Reset()=0; ///////////////////////////////////////////////////////////////////////////// // Advanced Features // ///////////////////////////////////////////////////////////////////////////// // The following four methods allow callback functions to be registered. // Each function that is registered may optionally provide a cookie (void *) // which will be passed back to that function whenever it is called. // Register a function f which is called every time the decision level // increases or decreases (i.e. every time the stack is pushed or popped). // The argument to f is the change in decision level. For example, +1 is a // Push, -1 is a Pop. virtual void RegisterDLevelHook(void (*f)(void *, int), void *cookie)=0; // Register a function to replace the built-in decision heuristics. Every // time a new decision needs to be made, the solver will call this function. // The function should return a literal which should be set to true. If the // bool pointer is returned with the value false, then a literal was // successfully chosen. If the value is true, this signals the solver to // exit with a satisfiable result. If the bool value is false and the // literal is NULL, then this signals the solver to use its own internal // method for making the next decision. virtual void RegisterDecisionHook(Lit (*f)(void *, bool *), void *cookie)=0; // Register a function which is called every time the value of a variable is // changed (i.e. assigned or unassigned). The first parameter is the // variable ID which has changed. The second is the new value: -1=unassigned, // 0=false, 1=true virtual void RegisterAssignmentHook(void (*f)(void *, Var, int), void *cookie)=0; // Register a function which will be called after Boolean propagation and // before making a new decision. Note that the hook function may add new // clauses and this should be handled correctly. virtual void RegisterDeductionHook(void (*f)(void *), void *cookie)=0; ///////////////////////////////////////////////////////////////////////////// // Setting Parameters // ///////////////////////////////////////////////////////////////////////////// // Implementations are not required to implement any of these // parameter-adjusting routines. Each function will return true if the request // is successful and false otherwise. // Implementation will define budget. An example budget would be time. virtual bool SetBudget(int budget) { return false; } // Set memory limit in bytes. virtual bool SetMemLimit(int mem_limit) { return false; } // Set parameters controlling randomness. Implementation defines what this // means. virtual bool SetRandomness(int n) { return false; } virtual bool SetRandSeed(int seed) { return false; } // Enable or disable deletion of conflict clauses to help control memory. virtual bool EnableClauseDeletion() { return false; } virtual bool DisableClauseDeletion() { return false; } /////////////////////////////////////////////////////////////////////////////// // Statistics // /////////////////////////////////////////////////////////////////////////////// // As with the parameter functions, the statistics-gathering functions may or // may not be implemented. They return -1 if not implemented, and the // correct value otherwise. // Return the amount of the budget (set by SetBudget) which has been used virtual int GetBudgetUsed() { return -1; } // Return the amount of memory in use virtual int GetMemUsed() { return -1; } // Return the number of decisions made so far virtual int GetNumDecisions() { return -1; } // Return the number of conflicts (equal to the number of backtracks) virtual int GetNumConflicts() { return -1; } // Return the number of conflicts generated by the registered external // conflict generator virtual int GetNumExtConflicts() { return -1; } // Return the elapsed CPU time (in seconds) since the call to Satisfiable() virtual float GetTotalTime() { return -1; } // Return the CPU time spent (in seconds) inside the SAT solver // (as opposed to in the registered hook functions) virtual float GetSATTime() { return -1; } // Return the total number of literals in all clauses virtual int GetNumLiterals() { return -1; } // Return the number of clauses that were deleted virtual int GetNumDeletedClauses() { return -1; } // Return the total number of literals in all deleted clauses virtual int GetNumDeletedLiterals() { return -1; } // Return the number of unit propagations virtual int GetNumImplications() { return -1; } // Return the maximum decision level reached virtual int GetMaxDLevel() { return -1; } // Print all implemented statistics void PrintStatistics(std::ostream & os = std::cout); }; #endif cvc3-2.4.1/src/include/exception.h0000664000175400017540000000332010755667434016656 0ustar mdetersmdeters/*****************************************************************************/ /*! * \file exception.h * * Author: Sergey Berezin * * Created: Thu Feb 6 13:09:44 2003 * *
* * License to use, copy, modify, sell and/or distribute this software * and its documentation for any purpose is hereby granted without * royalty, subject to the terms and conditions defined in the \ref * LICENSE file provided with this distribution. * *
* * A generic exception. Any thrown exception must inherit from this * class and whenever possible, set the error message. */ /*****************************************************************************/ #ifndef _cvc3__exception_h_ #define _cvc3__exception_h_ #include #include namespace CVC3 { class Exception { protected: std::string d_msg; public: // Constructors Exception(): d_msg("Unknown exception") { } Exception(const std::string& msg): d_msg(msg) { } Exception(const char* msg): d_msg(msg) { } // Destructor virtual ~Exception() { } // NON-VIRTUAL METHODs for setting and printing the error message void setMessage(const std::string& msg) { d_msg = msg; } // Printing: feel free to redefine toString(). When inherited, // it's recommended that this method print the type of exception // before the actual message. virtual std::string toString() const { return d_msg; } // No need to overload operator<< for the inherited classes friend std::ostream& operator<<(std::ostream& os, const Exception& e); }; // end of class Exception inline std::ostream& operator<<(std::ostream& os, const Exception& e) { return os << e.toString(); } } // end of namespace CVC3 #endif cvc3-2.4.1/src/include/typecheck_exception.h0000664000175400017540000000230711103725115020674 0ustar mdetersmdeters/*****************************************************************************/ /*! * \file typecheck_exception.h * \brief An exception to be thrown at typecheck error. * * Author: Sergey Berezin * * Created: Fri Feb 14 18:44:15 2003 * *
* * License to use, copy, modify, sell and/or distribute this software * and its documentation for any purpose is hereby granted without * royalty, subject to the terms and conditions defined in the \ref * LICENSE file provided with this distribution. * *
* */ /*****************************************************************************/ #ifndef _cvc3__typecheck_exception_h_ #define _cvc3__typecheck_exception_h_ #include #include #include "exception.h" namespace CVC3 { class TypecheckException: public Exception { public: // Constructors TypecheckException() { } TypecheckException(const std::string& msg): Exception(msg) { } TypecheckException(const char* msg): Exception(msg) { } // Destructor virtual ~TypecheckException() { } virtual std::string toString() const { return "Type Checking error: " + d_msg; } }; // end of class TypecheckException } // end of namespace CVC3 #endif cvc3-2.4.1/src/include/kinds.h0000644000175400017540000001572311624746721015771 0ustar mdetersmdeters/*****************************************************************************/ /*! * \file kinds.h * * Author: Clark Barrett * * Created: Mon Jan 20 13:38:52 2003 * *
* * License to use, copy, modify, sell and/or distribute this software * and its documentation for any purpose is hereby granted without * royalty, subject to the terms and conditions defined in the \ref * LICENSE file provided with this distribution. * *
* */ /*****************************************************************************/ #ifndef _cvc3__include__kinds_h_ #define _cvc3__include__kinds_h_ #ifdef __cplusplus namespace CVC3 { #endif /* __cplusplus */ // The commonly used kinds and the kinds needed by the parser. All // these kinds are registered by the ExprManager and are readily // available for everyone else. typedef enum { NULL_KIND = 0, // Constant (Leaf) Exprs TRUE_EXPR = 1, FALSE_EXPR = 2, RATIONAL_EXPR = 3, STRING_EXPR = 4, // All constants should have kinds less than MAX_CONST MAX_CONST = 100, // Generic LISP kinds for representing raw parsed expressions RAW_LIST, //!< May have any number of children >= 0 //! Identifier is (ID (STRING_EXPR "name")) ID, // Types BOOLEAN, // TUPLE_TYPE, ANY_TYPE, ARROW, // The "type" of any expression type (as in BOOLEAN : TYPE). TYPE, // Declaration of new (uninterpreted) types: T1, T2, ... : TYPE // (TYPEDECL T1 T2 ...) TYPEDECL, // Declaration of a defined type T : TYPE = type === (TYPEDEF T type) TYPEDEF, // Equality EQ, NEQ, DISTINCT, // Propositional connectives NOT, AND, OR, XOR, IFF, IMPLIES, // BOOL_VAR, //!< Boolean variables are treated as 0-ary predicates // Propositional relations (for circuit propagation) AND_R, IFF_R, ITE_R, // (ITE c e1 e2) == IF c THEN e1 ELSE e2 ENDIF, the internal // representation of the conditional. Parser produces (IF ...). ITE, // Quantifiers FORALL, EXISTS, // Uninterpreted function UFUNC, // Application of a function APPLY, // Top-level Commands ASSERT, QUERY, CHECKSAT, CONTINUE, RESTART, DBG, TRACE, UNTRACE, OPTION, HELP, TRANSFORM, PRINT, CALL, ECHO, INCLUDE, GET_VALUE, GET_ASSIGNMENT, DUMP_PROOF, DUMP_ASSUMPTIONS, DUMP_SIG, DUMP_TCC, DUMP_TCC_ASSUMPTIONS, DUMP_TCC_PROOF, DUMP_CLOSURE, DUMP_CLOSURE_PROOF, WHERE, ASSERTIONS, ASSUMPTIONS, COUNTEREXAMPLE, COUNTERMODEL, PUSH, POP, POPTO, PUSH_SCOPE, POP_SCOPE, POPTO_SCOPE, RESET, CONTEXT, FORGET, GET_TYPE, CHECK_TYPE, GET_CHILD, SUBSTITUTE, SEQ, ARITH_VAR_ORDER, ANNOTATION, // Kinds used mostly in the parser TCC, // Variable declaration (VARDECL v1 v2 ... v_n type). A variable // can be an ID or a BOUNDVAR. VARDECL, // A list of variable declarations (VARDECLS (VARDECL ...) (VARDECL ...) ...) VARDECLS, // Bound variables have a "printable name", the one the user typed // in, and a uniqueID used to distinguish it from other bound // variables, which is effectively the alpha-renaming: // Op(BOUND_VAR (BOUND_ID "user_name" "uniqueID")). Note that // BOUND_VAR is an operator (Expr without children), just as UFUNC // and UCONST. // The uniqueID normally is just a number, so one can print a bound // variable X as X_17. // NOTE that in the parsed expressions like LET x: T = e IN foo(x), // the second instance of 'x' will be an ID, and *not* a BOUNDVAR. // The parser does not know how to resolve bound variables, and it // has to be resolved later. BOUND_VAR, BOUND_ID, // Updator "e1 WITH := e2" is represented as // (UPDATE e1 (UPDATE_SELECT ) e2), where is the list of accessors: // (READ idx) // ID (what's that for?) // (REC_SELECT ID) // and (TUPLE_SELECT num). // UPDATE, // UPDATE_SELECT, // Record type [# f1 : t1, f2 : t2 ... #] is represented as // (RECORD_TYPE (f1 t1) (f2 t2) ... ) // RECORD_TYPE, // // (# f1=e1, f2=e2, ...#) == (RECORD (f1 e1) ...) // RECORD, // RECORD_SELECT, // RECORD_UPDATE, // // (e1, e2, ...) == (TUPLE e1 e2 ...) // TUPLE, // TUPLE_SELECT, // TUPLE_UPDATE, // SUBRANGE, // Enumerated type (SCALARTYPE v1 v2 ...) // SCALARTYPE, // Predicate subtype: the argument is the predicate (lambda-expression) SUBTYPE, // Datatype is Expr(DATATYPE, Constructors), where Constructors is a // vector of Expr(CONSTRUCTOR, id [ , arg ]), where 'id' is an ID, // and 'arg' a VARDECL node (list of variable declarations with // types). If 'arg' is present, the constructor has arguments // corresponding to the declared variables. // DATATYPE, // THISTYPE, // Used to indicate recursion in recursive datatypes // CONSTRUCTOR, // SELECTOR, // TESTER, // Expression e WITH accessor := e2 is transformed by the command // processor into (DATATYPE_UPDATE e accessor e2), where e is the // original datatype value C(a1, ..., an) (here C is the // constructor), and "accessor" is the name of one of the arguments // a_i of C. // DATATYPE_UPDATE, // Statement IF c1 THEN e1 ELSIF c2 THEN e2 ... ELSE e_n ENDIF is // represented as (IF (IFTHEN c1 e1) (IFTHEN c2 e2) ... (ELSE e_n)) IF, IFTHEN, ELSE, // Lisp version of multi-branch IF: // (COND (c1 e1) (c2 e2) ... (ELSE en)) COND, // LET x1: t1 = e1, x2: t2 = e2, ... IN e // Parser builds: // (LET (LETDECLS (LETDECL x1 t1 e1) (LETDECL x2 t2 e2) ... ) e) // where each x_i is a BOUNDVAR. // After processing, it is rebuilt to have (LETDECL var def); the // type is set as the attribute to var. LET, LETDECLS, LETDECL, // Lambda-abstraction LAMBDA () : e === (LAMBDA e) LAMBDA, // Symbolic simulation operator SIMULATE, // Uninterpreted constants (variables) x1, x2, ... , x_n : type // (CONST (VARLIST x1 x2 ... x_n) type) // Uninterpreted functions are declared as constants of functional type. // After processing, uninterpreted functions and constants // (a.k.a. variables) are represented as Op(UFUNC, (ID "name")) and // Op(UCONST, (ID "name")) with the appropriate type attribute. CONST, VARLIST, UCONST, // User function definition f(args) : type = e === (DEFUN args type e) // Here 'args' are bound var declarations DEFUN, // Arithmetic types and operators // REAL, // INT, // UMINUS, // PLUS, // MINUS, // MULT, // DIVIDE, // INTDIV, // MOD, // LT, // LE, // GT, // GE, // IS_INTEGER, // NEGINF, // POSINF, // DARK_SHADOW, // GRAY_SHADOW, // //Floor theory operators // FLOOR, // Kind for Extension to Non-linear Arithmetic // POW, // Kinds for proof terms PF_APPLY, PF_HOLE, // // Mlss // EMPTY, // {} // UNION, // + // INTER, // * // DIFF, // SINGLETON, // IN, // INCS, // INCIN, //Skolem variable SKOLEM_VAR, // Expr that holds a theorem THEOREM_KIND, //! Must always be the last kind LAST_KIND } Kind; #ifdef __cplusplus } // end of namespace CVC3 #endif /* __cplusplus */ #endif cvc3-2.4.1/src/include/expr.h0000664000175400017540000014414411306035505015625 0ustar mdetersmdeters/*****************************************************************************/ /*! * \file expr.h * \brief Definition of the API to expression package. See class Expr for details. * * Author: Clark Barrett * * Created: Tue Nov 26 00:27:40 2002 * *
* * License to use, copy, modify, sell and/or distribute this software * and its documentation for any purpose is hereby granted without * royalty, subject to the terms and conditions defined in the \ref * LICENSE file provided with this distribution. * *
* */ /*****************************************************************************/ #ifndef _cvc3__expr_h_ #define _cvc3__expr_h_ #include #include #include #include #include #include #include "os.h" #include "compat_hash_map.h" #include "compat_hash_set.h" #include "rational.h" #include "kinds.h" #include "cdo.h" #include "cdflags.h" #include "lang.h" #include "memory_manager.h" class CInterface; namespace CVC3 { class NotifyList; class Theory; class Op; class Type; class Theorem; template class ExprHashMap; class ExprManager; // Internal data-holding classes class ExprValue; class ExprNode; // Printing class ExprStream; //! Type ID of each ExprValue subclass. /*! It is defined in expr.h, so that ExprManager can use it before loading expr_value.h */ typedef enum { EXPR_VALUE, EXPR_NODE, EXPR_APPLY, //!< Application of functions and predicates EXPR_STRING, EXPR_RATIONAL, EXPR_SKOLEM, EXPR_UCONST, EXPR_SYMBOL, EXPR_BOUND_VAR, EXPR_CLOSURE, EXPR_VALUE_TYPE_LAST // The end of list; don't assign it to any subclass } ExprValueType; //! Enum for cardinality of types typedef enum { CARD_FINITE, CARD_INFINITE, CARD_UNKNOWN } Cardinality; //! Expression index type typedef long unsigned ExprIndex; /**************************************************************************/ /*! \defgroup ExprPkg Expression Package * \ingroup BuildingBlocks */ /**************************************************************************/ /*! \defgroup Expr_SmartPointer Smart Pointer Functionality in Expr * \ingroup ExprPkg */ /**************************************************************************/ /**************************************************************************/ //! Data structure of expressions in CVC3 /*! \ingroup ExprPkg * Class: Expr
* Author: Clark Barrett
* Created: Mon Nov 25 15:29:37 2002 * * This class is the main data structure for expressions that all * other components should use. It is actually a smart * pointer to the actual data holding class ExprValue and its * subclasses. * * Expressions are represented as DAGs with maximal sharing of * subexpressions. Therefore, testing for equality is a constant time * operation (simply compare the pointers). * * Unused expressions are automatically garbage-collected. The use is * determined by a reference counting mechanism. In particular, this * means that if there is a circular dependency among expressions * (e.g. an attribute points back to the expression itself), these * expressions will not be garbage-collected, even if no one else is * using them. * * The most frequently used operations are getKind() (determining the * kind of the top level node of the expression), arity() (how many * children an Expr has), operator[]() for accessing a child, and * various testers and methods for constructing new expressions. * * In addition, a total ordering operator<() is provided. It is * guaranteed to remain the same for the lifetime of the expressions * (it may change, however, if the expression is garbage-collected and * reborn). */ /**************************************************************************/ class CVC_DLL Expr { friend class ExprHasher; friend class ExprManager; friend class Op; friend class ExprValue; friend class ExprNode; friend class ExprClosure; friend class ::CInterface; friend class Theorem; /*! \addtogroup ExprPkg * @{ */ //! bit-masks for static flags typedef enum { //! Whether is valid TYPE expr VALID_TYPE = 0x1, //! Whether IS_ATOMIC flag is valid (initialized) VALID_IS_ATOMIC = 0x2, //! Whether the expression is an atomic term or formula IS_ATOMIC = 0x4, //! Expression is the result of a "normal" (idempotent) rewrite REWRITE_NORMAL = 0x8, //! Finite type IS_FINITE = 0x400, //! Well-founded (used in datatypes) WELL_FOUNDED = 0x800, //! Compute transitive closure (for binary uninterpreted predicates) COMPUTE_TRANS_CLOSURE = 0x1000, //! Whether expr contains a bounded variable (for quantifier instantiation) CONTAINS_BOUND_VAR = 0x00020000, //! Whether expr uses CC algorithm that relies on not simplifying an expr that has a find USES_CC = 0x00080000, //! Whether TERMINALS_CONST flag is valid (initialized) VALID_TERMINALS_CONST = 0x00100000, //! Whether expr contains only numerical constants at all possible ite terminals TERMINALS_CONST = 0x00200000 } StaticFlagsEnum; //! bit-masks for dynamic flags // TODO: Registered flags instead of hard-wired typedef enum { //! Whether expr has been added as an implied literal IMPLIED_LITERAL = 0x10, IS_USER_ASSUMPTION = 0x20, IS_INT_ASSUMPTION = 0x40, IS_JUSTIFIED = 0x80, IS_TRANSLATED = 0x100, IS_USER_REGISTERED_ATOM = 0x200, IS_SELECTED = 0x2000, IS_STORED_PREDICATE = 0x4000, IS_REGISTERED_ATOM = 0x8000, IN_USER_ASSUMPTION = 0x00010000, //! Whether expr is normalized (in array theory) NOT_ARRAY_NORMALIZED = 0x00040000 } DynamicFlagsEnum; //! Convenient null expr static Expr s_null; ///////////////////////////////////////////////////////////////////////////// // Private Dynamic Data // ///////////////////////////////////////////////////////////////////////////// //! The value. This is the only data member in this class. ExprValue* d_expr; ///////////////////////////////////////////////////////////////////////////// // Private methods // ///////////////////////////////////////////////////////////////////////////// //! Private constructor, simply wraps around the pointer Expr(ExprValue* expr); Expr recursiveSubst(const ExprHashMap& subst, ExprHashMap& visited) const; Expr recursiveQuantSubst(const ExprHashMap& subst, ExprHashMap& visited) const; std::vector > substTriggers(const ExprHashMap & subst, ExprHashMap & visited) const; public: ///////////////////////////////////////////////////////////////////////////// // Public Classes and Types // ///////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////// /*! * Class: Expr::iterator * Author: Sergey Berezin * Created: Fri Dec 6 15:38:51 2002 * Description: STL-like iterator API to the Expr's children. * IMPORTANT: the iterator will not be valid after the originating * expression is destroyed. */ ///////////////////////////////////////////////////////////////////////////// class CVC_DLL iterator : public std::iterator { friend class Expr; private: std::vector::const_iterator d_it; // Private constructors (used by Expr only) // //! Construct an iterator out of the vector's iterator iterator(std::vector::const_iterator it): d_it(it) { } // Public methods public: //! Default constructor iterator() { } // Copy constructor and operator= are defined by C++, that's good enough //! Equality bool operator==(const iterator& i) const { return d_it == i.d_it; } //! Disequality bool operator!=(const iterator& i) const { return !(*this == i); } //! Dereference operator const Expr& operator*() const { return *d_it; } //! Dereference and member access const Expr* operator->() const { return &(operator*()); } //! Prefix increment iterator& operator++() { ++d_it; return *this; } /*! @brief Postfix increment requires a Proxy object to hold the * intermediate value for dereferencing */ class Proxy { const Expr* d_e; public: Proxy(const Expr& e) : d_e(&e) { } Expr operator*() { return *d_e; } }; //! Postfix increment /*! \return Proxy with the old Expr. * * Now, an expression like *i++ will return the current *i, and * then advance the iterator. However, don't try to use Proxy for * anything else. */ Proxy operator++(int) { Proxy e(*(*this)); ++(*this); return e; } }; // end of class Expr::iterator ///////////////////////////////////////////////////////////////////////////// // Constructors // ///////////////////////////////////////////////////////////////////////////// //! Default constructor creates the Null Expr Expr(): d_expr(NULL) {} /*! @brief Copy constructor and assignment (copy the pointer and take care of the refcount) */ Expr(const Expr& e); //! Assignment operator: take care of the refcounting and GC Expr& operator=(const Expr& e); // These constructors grab the ExprManager from the Op or the first // child. The operator and all children must belong to the same // ExprManager. Expr(const Op& op, const Expr& child); Expr(const Op& op, const Expr& child0, const Expr& child1); Expr(const Op& op, const Expr& child0, const Expr& child1, const Expr& child2); Expr(const Op& op, const Expr& child0, const Expr& child1, const Expr& child2, const Expr& child3); Expr(const Op& op, const std::vector& children, ExprManager* em = NULL); //! Destructor ~Expr(); // Compound expression constructors Expr eqExpr(const Expr& right) const; Expr notExpr() const; Expr negate() const; // avoid double-negatives Expr andExpr(const Expr& right) const; Expr orExpr(const Expr& right) const; Expr iteExpr(const Expr& thenpart, const Expr& elsepart) const; Expr iffExpr(const Expr& right) const; Expr impExpr(const Expr& right) const; Expr xorExpr(const Expr& right) const; //! Create a Skolem constant for the i'th variable of an existential (*this) Expr skolemExpr(int i) const; //! Create a Boolean variable out of the expression // Expr boolVarExpr() const; //! Rebuild Expr with a new ExprManager Expr rebuild(ExprManager* em) const; // Expr newForall(const Expr& e); // Expr newExists(const Expr& e); Expr substExpr(const std::vector& oldTerms, const std::vector& newTerms) const; Expr substExpr(const ExprHashMap& oldToNew) const; // by yeting, a special subst function for TheoryQuant Expr substExprQuant(const std::vector& oldTerms, const std::vector& newTerms) const; Expr substExprQuant(const ExprHashMap& oldToNew) const; Expr operator!() const { return notExpr(); } Expr operator&&(const Expr& right) const { return andExpr(right); } Expr operator||(const Expr& right) const { return orExpr(right); } ///////////////////////////////////////////////////////////////////////////// // Public Static Methods // ///////////////////////////////////////////////////////////////////////////// static size_t hash(const Expr& e); ///////////////////////////////////////////////////////////////////////////// // Read-only (const) methods // ///////////////////////////////////////////////////////////////////////////// size_t hash() const; // Core expression testers bool isFalse() const { return getKind() == FALSE_EXPR; } bool isTrue() const { return getKind() == TRUE_EXPR; } bool isBoolConst() const { return isFalse() || isTrue(); } bool isVar() const; bool isBoundVar() const { return getKind() == BOUND_VAR; } bool isString() const; bool isClosure() const; bool isQuantifier() const; bool isLambda() const; bool isApply() const; bool isSymbol() const; bool isTheorem() const; bool isConstant() const { return getOpKind() <= MAX_CONST; } bool isRawList() const {return getKind() == RAW_LIST;} //! Expr represents a type bool isType() const; /* bool isRecord() const; bool isRecordAccess() const; bool isTupleAccess() const; */ //! Provide access to ExprValue for client subclasses of ExprValue *only* /*@ Calling getExprValue on an Expr with a built-in ExprValue class will * cause an error */ const ExprValue* getExprValue() const; //! Test if e is a term (as opposed to a predicate/formula) bool isTerm() const; //! Test if e is atomic /*! An atomic expression is TRUE or FALSE or one that does not * contain a formula (including not being a formula itself). * \sa isAtomicFormula */ bool isAtomic() const; //! Test if e is an atomic formula /*! An atomic formula is TRUE or FALSE or an application of a predicate (possibly 0-ary) which does not properly contain any formula. For instance, the formula "x = IF f THEN y ELSE z ENDIF" is not an atomic formula, since it contains the condition "f", which is a formula. */ bool isAtomicFormula() const; //! An abstract atomic formua is an atomic formula or a quantified formula bool isAbsAtomicFormula() const { return isQuantifier() || isAtomicFormula(); } //! Test if e is a literal /*! A literal is an atomic formula, or its negation. \sa isAtomicFormula */ bool isLiteral() const { return (isAtomicFormula() || (isNot() && (*this)[0].isAtomicFormula())); } //! Test if e is an abstract literal bool isAbsLiteral() const { return (isAbsAtomicFormula() || (isNot() && (*this)[0].isAbsAtomicFormula())); } //! A Bool connective is one of NOT,AND,OR,IMPLIES,IFF,XOR,ITE (with type Bool) bool isBoolConnective() const; //! True iff expr is not a Bool connective bool isPropAtom() const { return !isTerm() && !isBoolConnective(); } //! PropAtom or negation of PropAtom bool isPropLiteral() const { return (isNot() && (*this)[0].isPropAtom()) || isPropAtom(); } //! Return whether Expr contains a non-bool type ITE as a sub-term bool containsTermITE() const; bool isEq() const { return getKind() == EQ; } bool isNot() const { return getKind() == NOT; } bool isAnd() const { return getKind() == AND; } bool isOr() const { return getKind() == OR; } bool isITE() const { return getKind() == ITE; } bool isIff() const { return getKind() == IFF; } bool isImpl() const { return getKind() == IMPLIES; } bool isXor() const { return getKind() == XOR;} bool isForall() const { return getKind() == FORALL; } bool isExists() const { return getKind() == EXISTS; } bool isRational() const { return getKind() == RATIONAL_EXPR; } bool isSkolem() const { return getKind() == SKOLEM_VAR;} // Leaf accessors - these functions must only be called one expressions of // the appropriate kind. // For UCONST and BOUND_VAR Expr's const std::string& getName() const; //! For BOUND_VAR, get the UID const std::string& getUid() const; // For STRING_EXPR's const std::string& getString() const; //! Get bound variables from a closure Expr const std::vector& getVars() const; //! Get the existential axiom expression for skolem constant const Expr& getExistential() const; //! Get the index of the bound var that skolem constant comes from int getBoundIndex() const; //! Get the body of the closure Expr const Expr& getBody() const; //! Set the triggers for a closure Expr void setTriggers(const std::vector >& triggers) const; void setTriggers(const std::vector& triggers) const; void setTrigger(const Expr& trigger) const; void setMultiTrigger(const std::vector& multiTrigger) const; //! Get the manual triggers of the closure Expr const std::vector >& getTriggers() const; //by yeting //! Get the Rational value out of RATIONAL_EXPR const Rational& getRational() const; //! Get theorem from THEOREM_EXPR const Theorem& getTheorem() const; // Get the expression manager. The expression must be non-null. ExprManager *getEM() const; // Return a ref to the vector of children. const std::vector& getKids() const; // Get the kind of this expr. int getKind() const; // Get the index field ExprIndex getIndex() const; // True if this is the most recently created expression bool hasLastIndex() const; //! Make the expr into an operator Op mkOp() const; //! Get operator from expression Op getOp() const; //! Get expression of operator (for APPLY Exprs only) Expr getOpExpr() const; //! Get kind of operator (for APPLY Exprs only) int getOpKind() const; // Return the number of children. Note, that an application of a // user-defined function has the arity of that function (the number // of arguments), and the function name itself is part of the // operator. int arity() const; // Return the ith child. As with arity, it's also the ith argument // in function application. const Expr& operator[](int i) const; //! Remove leading NOT if any const Expr& unnegate() const { return isNot() ? (*this)[0] : *this; } //! Begin iterator iterator begin() const; //! End iterator iterator end() const; // Check if Expr is Null bool isNull() const; // Check if Expr is not Null bool isInitialized() const { return d_expr != NULL; } //! Get the memory manager index (it uniquely identifies the subclass) size_t getMMIndex() const; // Attributes // True if the find attribute has been set to something other than NULL. bool hasFind() const; // Return the attached find attribute for the expr. Note that this // must be called repeatedly to get the root of the union-find tree. // Should only be called if hasFind is true. const Theorem& getFind() const; int getFindLevel() const; const Theorem& getEqNext() const; // Return the notify list NotifyList* getNotify() const; //! Get the type. Recursively compute if necessary Type getType() const; //! Look up the current type. Do not recursively compute (i.e. may be NULL) Type lookupType() const; //! Return cardinality of type Cardinality typeCard() const; //! Return nth (starting with 0) element in a finite type /*! Returns NULL Expr if unable to compute nth element */ Expr typeEnumerateFinite(Unsigned n) const; //! Return size of a finite type; returns 0 if size cannot be determined Unsigned typeSizeFinite() const; /*! @brief Return true if there is a valid cached value for calling simplify on this Expr. */ bool validSimpCache() const; // Get the cached Simplify of this Expr. const Theorem& getSimpCache() const; // Return true if valid type flag is set for Expr bool isValidType() const; // Return true if there is a valid flag for whether Expr is atomic bool validIsAtomicFlag() const; // Return true if there is a valid flag for whether terminals are const bool validTerminalsConstFlag() const; // Get the isAtomic flag bool getIsAtomicFlag() const; // Get the TerminalsConst flag bool getTerminalsConstFlag() const; // Get the RewriteNormal flag bool isRewriteNormal() const; // Get the isFinite flag bool isFinite() const; // Get the WellFounded flag bool isWellFounded() const; // Get the ComputeTransClosure flag bool computeTransClosure() const; // Get the ContainsBoundVar flag bool containsBoundVar() const; // Get the usesCC flag bool usesCC() const; // Get the notArrayNormalized flag bool notArrayNormalized() const; // Get the ImpliedLiteral flag bool isImpliedLiteral() const; // Get the UserAssumption flag bool isUserAssumption() const; // Get the inUserAssumption flag bool inUserAssumption() const; // Get the IntAssumption flag bool isIntAssumption() const; // Get the Justified flag bool isJustified() const; // Get the Translated flag bool isTranslated() const; // Get the UserRegisteredAtom flag bool isUserRegisteredAtom() const; // Get the RegisteredAtom flag bool isRegisteredAtom() const; // Get the Selected flag bool isSelected() const; // Get the Stored Predicate flag bool isStoredPredicate() const; //! Check if the generic flag is set bool getFlag() const; //! Set the generic flag void setFlag() const; //! Clear the generic flag in all Exprs void clearFlags() const; // Printing functions //! Print the expression to a string std::string toString() const; //! Print the expression to a string using the given output language std::string toString(InputLanguage lang) const; //! Print the expression in the specified format void print(InputLanguage lang, bool dagify = true) const; //! Print the expression as AST (lisp-like format) void print() const { print(AST_LANG); } //! Print the expression as AST without dagifying void printnodag() const; //! Pretty-print the expression void pprint() const; //! Pretty-print without dagifying void pprintnodag() const; //! Print a leaf node /*@ The top node is pretty-printed if it is a basic leaf type; * otherwise, just the kind is printed. Should only be called on expressions * with no children. */ ExprStream& print(ExprStream& os) const; //! Print the top node and then recurse through the children */ /*@ The top node is printed as an AST with all the information, including * "hidden" Exprs that are part of the ExprValue */ ExprStream& printAST(ExprStream& os) const; //! Set initial indentation to n. /*! The indentation will be reset to default unless the second argument is true. \return reference to itself, so one can write `os << e.indent(5)' */ Expr& indent(int n, bool permanent = false); ///////////////////////////////////////////////////////////////////////////// // Other Public methods // ///////////////////////////////////////////////////////////////////////////// // Attributes //! Set the find attribute to e void setFind(const Theorem& e) const; //! Set the eqNext attribute to e void setEqNext(const Theorem& e) const; //! Add (e,i) to the notify list of this expression void addToNotify(Theory* i, const Expr& e) const; //! Set the cached type void setType(const Type& t) const; // Cache the result of a call to Simplify on this Expr void setSimpCache(const Theorem& e) const; // Set the valid type flag for this Expr void setValidType() const; // Set the isAtomicFlag for this Expr void setIsAtomicFlag(bool value) const; // Set the TerminalsConst flag for this Expr void setTerminalsConstFlag(bool value) const; // Set or clear the RewriteNormal flag void setRewriteNormal() const; void clearRewriteNormal() const; // Set the isFinite flag void setFinite() const; // Set the WellFounded flag void setWellFounded() const; // Set the ComputeTransClosure flag void setComputeTransClosure() const; // Set the ContainsBoundVar flag void setContainsBoundVar() const; // Set the UsesCC flag void setUsesCC() const; // Set the notArrayNormalized flag void setNotArrayNormalized() const; // Set the impliedLiteral flag for this Expr void setImpliedLiteral() const; // Set the user assumption flag for this Expr void setUserAssumption(int scope = -1) const; // Set the in user assumption flag for this Expr void setInUserAssumption(int scope = -1) const; // Set the internal assumption flag for this Expr void setIntAssumption() const; // Set the justified flag for this Expr void setJustified() const; //! Set the translated flag for this Expr void setTranslated(int scope = -1) const; //! Set the UserRegisteredAtom flag for this Expr void setUserRegisteredAtom() const; //! Set the RegisteredAtom flag for this Expr void setRegisteredAtom() const; //! Set the Selected flag for this Expr void setSelected() const; //! Set the Stored Predicate flag for this Expr void setStoredPredicate() const; //! Check if the current Expr (*this) is a subexpression of e bool subExprOf(const Expr& e) const; // Returns the maximum number of Boolean expressions on a path from // this to a leaf, including this. inline Unsigned getSize() const; // inline int getHeight() const; // // Returns the index of the highest kid. // inline int getHighestKid() const; // // Gets/sets an expression that this expression was simplified from // // (see newRWTheorem). This is the equivalent of SVC's Sigx. // inline bool hasSimpFrom() const; // inline const Expr& getSimpFrom() const; // inline void setSimpFrom(const Expr& simpFrom); // Attributes for uninterpreted function symbols. bool hasSig() const; bool hasRep() const; const Theorem& getSig() const; const Theorem& getRep() const; void setSig(const Theorem& e) const; void setRep(const Theorem& e) const; ///////////////////////////////////////////////////////////////////////////// // Friend methods // ///////////////////////////////////////////////////////////////////////////// friend CVC_DLL std::ostream& operator<<(std::ostream& os, const Expr& e); // The master method which defines some fixed total ordering on all // Exprs. If e1 < e2, e1==e2, and e1 > e2, it returns -1, 0, 1 // respectively. A Null expr is always "smaller" than any other // expr, but is equal to itself. friend int compare(const Expr& e1, const Expr& e2); friend bool operator==(const Expr& e1, const Expr& e2); friend bool operator!=(const Expr& e1, const Expr& e2); friend bool operator<(const Expr& e1, const Expr& e2); friend bool operator<=(const Expr& e1, const Expr& e2); friend bool operator>(const Expr& e1, const Expr& e2); friend bool operator>=(const Expr& e1, const Expr& e2); /*!@}*/ // end of group Expr }; // end of class Expr } // end of namespace CVC3 // Include expr_value.h here. We cannot include it earlier, since it // needs the definition of class Expr. See comments in expr_value.h. #ifndef DOXYGEN #include "expr_op.h" #include "expr_manager.h" #endif namespace CVC3 { inline Expr::Expr(ExprValue* expr) : d_expr(expr) { d_expr->incRefcount(); } inline Expr::Expr(const Expr& e) : d_expr(e.d_expr) { if (d_expr != NULL) d_expr->incRefcount(); } inline Expr& Expr::operator=(const Expr& e) { if(&e == this) return *this; // Self-assignment ExprValue* tmp = e.d_expr; if(tmp == d_expr) return *this; if (tmp == NULL) { d_expr->decRefcount(); } else { tmp->incRefcount(); if(d_expr != NULL) { d_expr->decRefcount(); } } d_expr = tmp; return *this; } inline Expr::Expr(const Op& op, const Expr& child) { ExprManager* em = child.getEM(); if (op.getKind() != APPLY) { ExprNode ev(em, op.getKind()); std::vector& kids = ev.getKids1(); kids.push_back(child); d_expr = em->newExprValue(&ev); } else { ExprApply ev(em, op); std::vector& kids = ev.getKids1(); kids.push_back(child); d_expr = em->newExprValue(&ev); } d_expr->incRefcount(); } inline Expr::Expr(const Op& op, const Expr& child0, const Expr& child1) { ExprManager* em = child0.getEM(); if (op.getKind() != APPLY) { ExprNode ev(em, op.getKind()); std::vector& kids = ev.getKids1(); kids.push_back(child0); kids.push_back(child1); d_expr = em->newExprValue(&ev); } else { ExprApply ev(em, op); std::vector& kids = ev.getKids1(); kids.push_back(child0); kids.push_back(child1); d_expr = em->newExprValue(&ev); } d_expr->incRefcount(); } inline Expr::Expr(const Op& op, const Expr& child0, const Expr& child1, const Expr& child2) { ExprManager* em = child0.getEM(); if (op.getKind() != APPLY) { ExprNode ev(em, op.getKind()); std::vector& kids = ev.getKids1(); kids.push_back(child0); kids.push_back(child1); kids.push_back(child2); d_expr = em->newExprValue(&ev); } else { ExprApply ev(em, op); std::vector& kids = ev.getKids1(); kids.push_back(child0); kids.push_back(child1); kids.push_back(child2); d_expr = em->newExprValue(&ev); } d_expr->incRefcount(); } inline Expr::Expr(const Op& op, const Expr& child0, const Expr& child1, const Expr& child2, const Expr& child3) { ExprManager* em = child0.getEM(); if (op.getKind() != APPLY) { ExprNode ev(em, op.getKind()); std::vector& kids = ev.getKids1(); kids.push_back(child0); kids.push_back(child1); kids.push_back(child2); kids.push_back(child3); d_expr = em->newExprValue(&ev); } else { ExprApply ev(em, op); std::vector& kids = ev.getKids1(); kids.push_back(child0); kids.push_back(child1); kids.push_back(child2); kids.push_back(child3); d_expr = em->newExprValue(&ev); } d_expr->incRefcount(); } inline Expr::Expr(const Op& op, const std::vector& children, ExprManager* em) { if (em == NULL) { if (op.getKind() == APPLY) em = op.getExpr().getEM(); else { DebugAssert(children.size() > 0, "Expr::Expr(Op, children): op's EM is NULL and " "no children given"); em = children[0].getEM(); } } if (op.getKind() != APPLY) { ExprNodeTmp ev(em, op.getKind(), children); d_expr = em->newExprValue(&ev); } else { ExprApplyTmp ev(em, op, children); d_expr = em->newExprValue(&ev); } d_expr->incRefcount(); } inline Expr Expr::eqExpr(const Expr& right) const { return Expr(EQ, *this, right); } inline Expr Expr::notExpr() const { return Expr(NOT, *this); } inline Expr Expr::negate() const { return isNot() ? (*this)[0] : this->notExpr(); } inline Expr Expr::andExpr(const Expr& right) const { return Expr(AND, *this, right); } inline Expr andExpr(const std::vector & children) { DebugAssert(children.size()>0 && !children[0].isNull(), "Expr::andExpr(kids)"); return Expr(AND, children); } inline Expr Expr::orExpr(const Expr& right) const { return Expr(OR, *this, right); } inline Expr orExpr(const std::vector & children) { DebugAssert(children.size()>0 && !children[0].isNull(), "Expr::andExpr(kids)"); return Expr(OR, children); } inline Expr Expr::iteExpr(const Expr& thenpart, const Expr& elsepart) const { return Expr(ITE, *this, thenpart, elsepart); } inline Expr Expr::iffExpr(const Expr& right) const { return Expr(IFF, *this, right); } inline Expr Expr::impExpr(const Expr& right) const { return Expr(IMPLIES, *this, right); } inline Expr Expr::xorExpr(const Expr& right) const { return Expr(XOR, *this, right); } inline Expr Expr::skolemExpr(int i) const { return getEM()->newSkolemExpr(*this, i); } inline Expr Expr::rebuild(ExprManager* em) const { return em->rebuild(*this); } inline Expr::~Expr() { if(d_expr != NULL) { IF_DEBUG(FatalAssert(d_expr->d_refcount > 0, "Mis-handled the ref. counting");) if (--(d_expr->d_refcount) == 0) d_expr->d_em->gc(d_expr); } } inline size_t Expr::hash(const Expr& e) { return e.getEM()->hash(e); } ///////////////////////////////////////////////////////////////////////////// // Read-only (const) methods // ///////////////////////////////////////////////////////////////////////////// inline size_t Expr::hash() const { return getEM()->hash(*this); } inline const ExprValue* Expr::getExprValue() const { return d_expr->getExprValue(); } // Core Expression Testers inline bool Expr::isVar() const { return d_expr->isVar(); } inline bool Expr::isString() const { return d_expr->isString(); } inline bool Expr::isClosure() const { return d_expr->isClosure(); } inline bool Expr::isQuantifier() const { return (isClosure() && (getKind() == FORALL || getKind() == EXISTS)); } inline bool Expr::isLambda() const { return (isClosure() && getKind() == LAMBDA); } inline bool Expr::isApply() const { DebugAssert((getKind() != APPLY || d_expr->isApply()) && (!d_expr->isApply() || getKind() == APPLY), "APPLY mismatch"); return getKind() == APPLY; } inline bool Expr::isSymbol() const { return d_expr->isSymbol(); } inline bool Expr::isTheorem() const { return d_expr->isTheorem(); } inline bool Expr::isType() const { return getEM()->isTypeKind(getOpKind()); } inline bool Expr::isTerm() const { return !getType().isBool(); } inline bool Expr::isBoolConnective() const { if (!getType().isBool()) return false; switch (getKind()) { case NOT: case AND: case OR: case IMPLIES: case IFF: case XOR: case ITE: return true; } return false; } inline Unsigned Expr::getSize() const { if (d_expr->d_size == 0) { clearFlags(); const_cast(d_expr)->d_size = d_expr->getSize(); } return d_expr->d_size; } //inline int Expr::getHeight() const { return d_expr->getHeight(); } //inline int Expr::getHighestKid() const { return d_expr->getHighestKid(); } //inline bool Expr::hasSimpFrom() const // { return !d_expr->getSimpFrom().isNull(); } // inline const Expr& Expr::getSimpFrom() const // { return hasSimpFrom() ? d_expr->getSimpFrom() : *this; } // inline void Expr::setSimpFrom(const Expr& simpFrom) // { d_expr->setSimpFrom(simpFrom); } // Leaf accessors inline const std::string& Expr::getName() const { DebugAssert(!isNull(), "Expr::getName() on Null expr"); return d_expr->getName(); } inline const std::string& Expr::getString() const { DebugAssert(isString(), "CVC3::Expr::getString(): not a string Expr:\n " + toString(AST_LANG)); return d_expr->getString(); } inline const std::vector& Expr::getVars() const { DebugAssert(isClosure(), "CVC3::Expr::getVars(): not a closure Expr:\n " + toString(AST_LANG)); return d_expr->getVars(); } inline const Expr& Expr::getBody() const { DebugAssert(isClosure(), "CVC3::Expr::getBody(): not a closure Expr:\n " + toString(AST_LANG)); return d_expr->getBody(); } inline void Expr::setTriggers(const std::vector< std::vector >& triggers) const { DebugAssert(isClosure(), "CVC3::Expr::setTriggers(): not a closure Expr:\n " + toString(AST_LANG)); d_expr->setTriggers(triggers); } inline void Expr::setTriggers(const std::vector& triggers) const { DebugAssert(isClosure(), "CVC3::Expr::setTriggers(): not a closure Expr:\n " + toString(AST_LANG)); std::vector > patternvv; for(std::vector::const_iterator i = triggers.begin(); i != triggers.end(); ++i ) { std::vector patternv; patternv.push_back(*i); patternvv.push_back(patternv); } d_expr->setTriggers(patternvv); } inline void Expr::setTrigger(const Expr& trigger) const { DebugAssert(isClosure(), "CVC3::Expr::setTrigger(): not a closure Expr:\n " + toString(AST_LANG)); std::vector > patternvv; std::vector patternv; patternv.push_back(trigger); patternvv.push_back(patternv); setTriggers(patternvv); } inline void Expr::setMultiTrigger(const std::vector& multiTrigger) const { DebugAssert(isClosure(), "CVC3::Expr::setTrigger(): not a closure Expr:\n " + toString(AST_LANG)); std::vector > patternvv; patternvv.push_back(multiTrigger); setTriggers(patternvv); } inline const std::vector >& Expr::getTriggers() const { //by yeting DebugAssert(isClosure(), "CVC3::Expr::getTrigs(): not a closure Expr:\n " + toString(AST_LANG)); return d_expr->getTriggers(); } inline const Expr& Expr::getExistential() const { DebugAssert(isSkolem(), "CVC3::Expr::getExistential() not a skolem variable"); return d_expr->getExistential(); } inline int Expr::getBoundIndex() const { DebugAssert(isSkolem(), "CVC3::Expr::getBoundIndex() not a skolem variable"); return d_expr->getBoundIndex(); } inline const Rational& Expr::getRational() const { DebugAssert(isRational(), "CVC3::Expr::getRational(): not a rational Expr:\n " + toString(AST_LANG)); return d_expr->getRational(); } inline const Theorem& Expr::getTheorem() const { DebugAssert(isTheorem(), "CVC3::Expr::getTheorem(): not a Theorem Expr:\n " + toString(AST_LANG)); return d_expr->getTheorem(); } inline const std::string& Expr::getUid() const { DebugAssert(getKind() == BOUND_VAR, "CVC3::Expr::getUid(): not a BOUND_VAR Expr:\n " + toString(AST_LANG)); return d_expr->getUid(); } inline ExprManager* Expr::getEM() const { DebugAssert(d_expr != NULL, "CVC3::Expr:getEM: on Null Expr (not initialized)"); return d_expr->d_em; } inline const std::vector& Expr::getKids() const { DebugAssert(d_expr != NULL, "Expr::getKids on Null Expr"); if(isNull()) return getEM()->getEmptyVector(); else return d_expr->getKids(); } inline int Expr::getKind() const { if(d_expr == NULL) return NULL_KIND; // FIXME: invent a better Null kind return d_expr->d_kind; } inline ExprIndex Expr::getIndex() const { return d_expr->d_index; } inline bool Expr::hasLastIndex() const { return d_expr->d_em->lastIndex() == getIndex(); } inline Op Expr::mkOp() const { DebugAssert(!isNull(), "Expr::mkOp() on Null expr"); return Op(*this); } inline Op Expr::getOp() const { DebugAssert(!isNull(), "Expr::getOp() on Null expr"); if (isApply()) return d_expr->getOp(); DebugAssert(arity() > 0, "Expr::getOp() called on non-apply expr with no children"); return Op(getKind()); } inline Expr Expr::getOpExpr() const { DebugAssert(isApply(), "getOpExpr() called on non-apply"); return getOp().getExpr(); } inline int Expr::getOpKind() const { if (!isApply()) return getKind(); return getOp().getExpr().getKind(); } inline int Expr::arity() const { if(isNull()) return 0; else return d_expr->arity(); } inline const Expr& Expr::operator[](int i) const { DebugAssert(i < arity(), "out of bounds access"); return (d_expr->getKids())[i]; } inline Expr::iterator Expr::begin() const { if (isNull() || d_expr->arity() == 0) return Expr::iterator(getEM()->getEmptyVector().begin()); else return Expr::iterator(d_expr->getKids().begin()); } inline Expr::iterator Expr::end() const { if (isNull() || d_expr->arity() == 0) return Expr::iterator(getEM()->getEmptyVector().end()); else return Expr::iterator(d_expr->getKids().end()); } inline bool Expr::isNull() const { return (d_expr == NULL) || (d_expr->d_kind == NULL_KIND); } inline size_t Expr::getMMIndex() const { DebugAssert(!isNull(), "Expr::getMMIndex()"); return d_expr->getMMIndex(); } inline bool Expr::hasFind() const { DebugAssert(!isNull(), "hasFind called on NULL Expr"); return (d_expr->d_find && !(d_expr->d_find->get().isNull())); } inline const Theorem& Expr::getFind() const { DebugAssert(hasFind(), "Should only be called if find is valid"); return d_expr->d_find->get(); } inline int Expr::getFindLevel() const { DebugAssert(hasFind(), "Should only be called if find is valid"); return d_expr->d_find->level(); } inline const Theorem& Expr::getEqNext() const { DebugAssert(!isNull(), "getEqNext called on NULL Expr"); DebugAssert(hasFind(), "Should only be called if find is valid"); DebugAssert(d_expr->d_eqNext, "getEqNext: d_eqNext is NULL"); return d_expr->d_eqNext->get(); } inline NotifyList* Expr::getNotify() const { if(isNull()) return NULL; else return d_expr->d_notifyList; } inline Type Expr::getType() const { if (isNull()) return s_null; if (d_expr->d_type.isNull()) getEM()->computeType(*this); return d_expr->d_type; } inline Type Expr::lookupType() const { if (isNull()) return s_null; return d_expr->d_type; } inline Cardinality Expr::typeCard() const { DebugAssert(!isNull(), "typeCard called on NULL Expr"); Expr e(*this); Unsigned n; return getEM()->finiteTypeInfo(e, n, false, false); } inline Expr Expr::typeEnumerateFinite(Unsigned n) const { DebugAssert(!isNull(), "typeEnumerateFinite called on NULL Expr"); Expr e(*this); Cardinality card = getEM()->finiteTypeInfo(e, n, true, false); if (card != CARD_FINITE) e = Expr(); return e; } inline Unsigned Expr::typeSizeFinite() const { DebugAssert(!isNull(), "typeCard called on NULL Expr"); Expr e(*this); Unsigned n; Cardinality card = getEM()->finiteTypeInfo(e, n, false, true); if (card != CARD_FINITE) n = 0; return n; } inline bool Expr::validSimpCache() const { return d_expr->d_simpCacheTag == getEM()->getSimpCacheTag(); } inline const Theorem& Expr::getSimpCache() const { return d_expr->d_simpCache; } inline bool Expr::isValidType() const { return d_expr->d_dynamicFlags.get(VALID_TYPE); } inline bool Expr::validIsAtomicFlag() const { return d_expr->d_dynamicFlags.get(VALID_IS_ATOMIC); } inline bool Expr::validTerminalsConstFlag() const { return d_expr->d_dynamicFlags.get(VALID_TERMINALS_CONST); } inline bool Expr::getIsAtomicFlag() const { return d_expr->d_dynamicFlags.get(IS_ATOMIC); } inline bool Expr::getTerminalsConstFlag() const { return d_expr->d_dynamicFlags.get(TERMINALS_CONST); } inline bool Expr::isRewriteNormal() const { return d_expr->d_dynamicFlags.get(REWRITE_NORMAL); } inline bool Expr::isFinite() const { return d_expr->d_dynamicFlags.get(IS_FINITE); } inline bool Expr::isWellFounded() const { return d_expr->d_dynamicFlags.get(WELL_FOUNDED); } inline bool Expr::computeTransClosure() const { return d_expr->d_dynamicFlags.get(COMPUTE_TRANS_CLOSURE); } inline bool Expr::containsBoundVar() const { return d_expr->d_dynamicFlags.get(CONTAINS_BOUND_VAR); } inline bool Expr::usesCC() const { return d_expr->d_dynamicFlags.get(USES_CC); } inline bool Expr::notArrayNormalized() const { return d_expr->d_dynamicFlags.get(NOT_ARRAY_NORMALIZED); } inline bool Expr::isImpliedLiteral() const { return d_expr->d_dynamicFlags.get(IMPLIED_LITERAL); } inline bool Expr::isUserAssumption() const { return d_expr->d_dynamicFlags.get(IS_USER_ASSUMPTION); } inline bool Expr::inUserAssumption() const { return d_expr->d_dynamicFlags.get(IN_USER_ASSUMPTION); } inline bool Expr::isIntAssumption() const { return d_expr->d_dynamicFlags.get(IS_INT_ASSUMPTION); } inline bool Expr::isJustified() const { return d_expr->d_dynamicFlags.get(IS_JUSTIFIED); } inline bool Expr::isTranslated() const { return d_expr->d_dynamicFlags.get(IS_TRANSLATED); } inline bool Expr::isUserRegisteredAtom() const { return d_expr->d_dynamicFlags.get(IS_USER_REGISTERED_ATOM); } inline bool Expr::isRegisteredAtom() const { return d_expr->d_dynamicFlags.get(IS_REGISTERED_ATOM); } inline bool Expr::isSelected() const { return d_expr->d_dynamicFlags.get(IS_SELECTED); } inline bool Expr::isStoredPredicate() const { return d_expr->d_dynamicFlags.get(IS_STORED_PREDICATE); } inline bool Expr::getFlag() const { DebugAssert(!isNull(), "Expr::getFlag() on Null Expr"); return (d_expr->d_flag == getEM()->getFlag()); } inline void Expr::setFlag() const { DebugAssert(!isNull(), "Expr::setFlag() on Null Expr"); d_expr->d_flag = getEM()->getFlag(); } inline void Expr::clearFlags() const { DebugAssert(!isNull(), "Expr::clearFlags() on Null Expr"); getEM()->clearFlags(); } inline void Expr::setFind(const Theorem& e) const { DebugAssert(!isNull(), "Expr::setFind() on Null expr"); DebugAssert(e.getLHS() == *this, "bad call to setFind"); if (d_expr->d_find) d_expr->d_find->set(e); else { CDO* tmp = new(true) CDO(getEM()->getCurrentContext(), e); d_expr->d_find = tmp; IF_DEBUG(tmp->setName("CDO[Expr.find]");) } } inline void Expr::setEqNext(const Theorem& e) const { DebugAssert(!isNull(), "Expr::setEqNext() on Null expr"); DebugAssert(e.getLHS() == *this, "bad call to setEqNext"); if (d_expr->d_eqNext) d_expr->d_eqNext->set(e); else { CDO* tmp = new(true) CDO(getEM()->getCurrentContext(), e); d_expr->d_eqNext = tmp; IF_DEBUG(tmp->setName("CDO[Expr.eqNext]");) } } inline void Expr::setType(const Type& t) const { DebugAssert(!isNull(), "Expr::setType() on Null expr"); d_expr->d_type = t; } inline void Expr::setSimpCache(const Theorem& e) const { DebugAssert(!isNull(), "Expr::setSimpCache() on Null expr"); d_expr->d_simpCache = e; d_expr->d_simpCacheTag = getEM()->getSimpCacheTag(); } inline void Expr::setValidType() const { DebugAssert(!isNull(), "Expr::setValidType() on Null expr"); d_expr->d_dynamicFlags.set(VALID_TYPE, 0); } inline void Expr::setIsAtomicFlag(bool value) const { DebugAssert(!isNull(), "Expr::setIsAtomicFlag() on Null expr"); d_expr->d_dynamicFlags.set(VALID_IS_ATOMIC, 0); if (value) d_expr->d_dynamicFlags.set(IS_ATOMIC, 0); else d_expr->d_dynamicFlags.clear(IS_ATOMIC, 0); } inline void Expr::setTerminalsConstFlag(bool value) const { DebugAssert(!isNull(), "Expr::setTerminalsConstFlag() on Null expr"); d_expr->d_dynamicFlags.set(VALID_TERMINALS_CONST, 0); if (value) d_expr->d_dynamicFlags.set(TERMINALS_CONST, 0); else d_expr->d_dynamicFlags.clear(TERMINALS_CONST, 0); } inline void Expr::setRewriteNormal() const { DebugAssert(!isNull(), "Expr::setRewriteNormal() on Null expr"); TRACE("setRewriteNormal", "setRewriteNormal(", *this, ")"); d_expr->d_dynamicFlags.set(REWRITE_NORMAL, 0); } inline void Expr::setFinite() const { DebugAssert(!isNull(), "Expr::setFinite() on Null expr"); d_expr->d_dynamicFlags.set(IS_FINITE, 0); } inline void Expr::setWellFounded() const { DebugAssert(!isNull(), "Expr::setWellFounded() on Null expr"); d_expr->d_dynamicFlags.set(WELL_FOUNDED, 0); } inline void Expr::setComputeTransClosure() const { DebugAssert(!isNull(), "Expr::setComputeTransClosure() on Null expr"); d_expr->d_dynamicFlags.set(COMPUTE_TRANS_CLOSURE, 0); } inline void Expr::setContainsBoundVar() const { DebugAssert(!isNull(), "Expr::setContainsBoundVar() on Null expr"); d_expr->d_dynamicFlags.set(CONTAINS_BOUND_VAR, 0); } inline void Expr::setUsesCC() const { DebugAssert(!isNull(), "Expr::setUsesCC() on Null expr"); d_expr->d_dynamicFlags.set(USES_CC, 0); } inline void Expr::setNotArrayNormalized() const { DebugAssert(!isNull(), "Expr::setContainsBoundVar() on Null expr"); d_expr->d_dynamicFlags.set(NOT_ARRAY_NORMALIZED); } inline void Expr::setImpliedLiteral() const { DebugAssert(!isNull(), "Expr::setImpliedLiteral() on Null expr"); d_expr->d_dynamicFlags.set(IMPLIED_LITERAL); } inline void Expr::setUserAssumption(int scope) const { DebugAssert(!isNull(), "Expr::setUserAssumption() on Null expr"); d_expr->d_dynamicFlags.set(IS_USER_ASSUMPTION, scope); } inline void Expr::setInUserAssumption(int scope) const { DebugAssert(!isNull(), "Expr::setInUserAssumption() on Null expr"); d_expr->d_dynamicFlags.set(IN_USER_ASSUMPTION, scope); } inline void Expr::setIntAssumption() const { DebugAssert(!isNull(), "Expr::setIntAssumption() on Null expr"); d_expr->d_dynamicFlags.set(IS_INT_ASSUMPTION); } inline void Expr::setJustified() const { DebugAssert(!isNull(), "Expr::setJustified() on Null expr"); d_expr->d_dynamicFlags.set(IS_JUSTIFIED); } inline void Expr::setTranslated(int scope) const { DebugAssert(!isNull(), "Expr::setTranslated() on Null expr"); d_expr->d_dynamicFlags.set(IS_TRANSLATED, scope); } inline void Expr::setUserRegisteredAtom() const { DebugAssert(!isNull(), "Expr::setUserRegisteredAtom() on Null expr"); d_expr->d_dynamicFlags.set(IS_USER_REGISTERED_ATOM); } inline void Expr::setRegisteredAtom() const { DebugAssert(!isNull(), "Expr::setUserRegisteredAtom() on Null expr"); d_expr->d_dynamicFlags.set(IS_REGISTERED_ATOM); } inline void Expr::setSelected() const { DebugAssert(!isNull(), "Expr::setSelected() on Null expr"); d_expr->d_dynamicFlags.set(IS_SELECTED); } inline void Expr::setStoredPredicate() const { DebugAssert(!isNull(), "Expr::setStoredPredicate() on Null expr"); d_expr->d_dynamicFlags.set(IS_STORED_PREDICATE); } inline void Expr::clearRewriteNormal() const { DebugAssert(!isNull(), "Expr::clearRewriteNormal() on Null expr"); d_expr->d_dynamicFlags.clear(REWRITE_NORMAL, 0); } inline bool Expr::hasSig() const { return (!isNull() && d_expr->getSig() != NULL && !(d_expr->getSig()->get().isNull())); } inline bool Expr::hasRep() const { return (!isNull() && d_expr->getRep() != NULL && !(d_expr->getRep()->get().isNull())); } inline const Theorem& Expr::getSig() const { static Theorem nullThm; DebugAssert(!isNull(), "Expr::getSig() on Null expr"); if(d_expr->getSig() != NULL) return d_expr->getSig()->get(); else return nullThm; } inline const Theorem& Expr::getRep() const { static Theorem nullThm; DebugAssert(!isNull(), "Expr::getRep() on Null expr"); if(d_expr->getRep() != NULL) return d_expr->getRep()->get(); else return nullThm; } inline void Expr::setSig(const Theorem& e) const { DebugAssert(!isNull(), "Expr::setSig() on Null expr"); CDO* sig = d_expr->getSig(); if(sig != NULL) sig->set(e); else { CDO* tmp = new(true) CDO(getEM()->getCurrentContext(), e); d_expr->setSig(tmp); IF_DEBUG(tmp->setName("CDO[Expr.sig] in "+toString());) } } inline void Expr::setRep(const Theorem& e) const { DebugAssert(!isNull(), "Expr::setRep() on Null expr"); CDO* rep = d_expr->getRep(); if(rep != NULL) rep->set(e); else { CDO* tmp = new(true) CDO(getEM()->getCurrentContext(), e); d_expr->setRep(tmp); IF_DEBUG(tmp->setName("CDO[Expr.rep] in "+toString());) } } inline bool operator==(const Expr& e1, const Expr& e2) { // Comparing pointers (equal expressions are always shared) return e1.d_expr == e2.d_expr; } inline bool operator!=(const Expr& e1, const Expr& e2) { return !(e1 == e2); } // compare() is defined in expr.cpp inline bool operator<(const Expr& e1, const Expr& e2) { return compare(e1,e2) < 0; } inline bool operator<=(const Expr& e1, const Expr& e2) { return compare(e1,e2) <= 0; } inline bool operator>(const Expr& e1, const Expr& e2) { return compare(e1,e2) > 0; } inline bool operator>=(const Expr& e1, const Expr& e2) { return compare(e1,e2) >= 0; } } // end of namespace CVC3 #endif cvc3-2.4.1/src/include/cdo.h0000664000175400017540000000446410656155007015423 0ustar mdetersmdeters/*****************************************************************************/ /*! * \file cdo.h * * Author: Clark Barrett * * Created: Wed Feb 12 17:27:43 2003 * *
* * License to use, copy, modify, sell and/or distribute this software * and its documentation for any purpose is hereby granted without * royalty, subject to the terms and conditions defined in the \ref * LICENSE file provided with this distribution. * *
* */ /*****************************************************************************/ #ifndef _cvc3__include__cdo_h_ #define _cvc3__include__cdo_h_ #include "context.h" namespace CVC3 { /////////////////////////////////////////////////////////////////////////////// // // // Class: CDO (Context Dependent Object) // // Author: Clark Barrett // // Created: Wed Feb 12 17:28:25 2003 // // Description: Generic templated class for an object which must be saved // // and restored as contexts are pushed and popped. Requires // // that operator= be defined for the data class. // // // /////////////////////////////////////////////////////////////////////////////// template class CDO :public ContextObj { T d_data; virtual ContextObj* makeCopy(ContextMemoryManager* cmm) { return new(cmm) CDO(*this); } virtual void restoreData(ContextObj* data) { d_data = ((CDO*)data)->d_data; } virtual void setNull(void) { d_data = T(); } // Disable copy constructor and operator= // If you need these, use smartcdo instead CDO(const CDO& cdo): ContextObj(cdo), d_data(cdo.d_data) { } CDO& operator=(const CDO& cdo) {} public: CDO(Context* context) : ContextObj(context) { IF_DEBUG(setName("CDO");) } CDO(Context* context, const T& data, int scope = -1) : ContextObj(context) { IF_DEBUG(setName("CDO")); ; set(data, scope); } ~CDO() {} void set(const T& data, int scope=-1) { makeCurrent(scope); d_data = data; } const T& get() const { return d_data; } operator T() { return get(); } CDO& operator=(const T& data) { set(data); return *this; } }; } #endif cvc3-2.4.1/src/include/translator.h0000664000175400017540000001406311547365570017053 0ustar mdetersmdeters/*****************************************************************************/ /*! * \file translator.h * \brief An exception to be thrown by the smtlib translator. * * Author: Clark Barrett * * Created: Sat Jun 25 18:03:09 2005 * *
* * License to use, copy, modify, sell and/or distribute this software * and its documentation for any purpose is hereby granted without * royalty, subject to the terms and conditions defined in the \ref * LICENSE file provided with this distribution. * *
* */ /*****************************************************************************/ #ifndef _cvc3__translator_h_ #define _cvc3__translator_h_ #include #include #include #include #include "queryresult.h" #include "compat_hash_map.h" namespace CVC3 { class Expr; template class ExprMap; class Type; class ExprManager; class ExprStream; class TheoryCore; class TheoryUF; class TheoryArith; class TheoryArray; class TheoryQuant; class TheoryRecords; class TheorySimulate; class TheoryBitvector; class TheoryDatatype; template class ExprMap; //! Used to keep track of which subset of arith is being used typedef enum { NOT_USED = 0, TERMS_ONLY, DIFF_ONLY, LINEAR, NONLINEAR } ArithLang; //All the translation code should go here class Translator { ExprManager* d_em; const bool& d_translate; const bool& d_real2int; const bool& d_convertArith; const std::string& d_convertToDiff; bool d_iteLiftArith; const std::string& d_expResult; std::string d_category; bool d_convertArray; bool d_combineAssump; /** Private class for hashing strings; copied from ExprManager */ class HashString { std::hash h; public: size_t operator()(const std::string& s) const { return h(const_cast(s.c_str())); } }; std::hash_map d_replaceSymbols; //! The log file for top-level API calls in the CVC3 input language std::ostream* d_osdump; std::ofstream d_osdumpFile; std::ifstream d_tmpFile; bool d_dump, d_dumpFileOpen; bool d_intIntArray, d_intRealArray, d_intIntRealArray, d_ax, d_unknown; bool d_realUsed; bool d_intUsed; bool d_intConstUsed; ArithLang d_langUsed; bool d_UFIDL_ok; bool d_arithUsed; Expr* d_zeroVar; int d_convertToBV; TheoryCore* d_theoryCore; TheoryUF* d_theoryUF; TheoryArith* d_theoryArith; TheoryArray* d_theoryArray; TheoryQuant* d_theoryQuant; TheoryRecords* d_theoryRecords; TheorySimulate* d_theorySimulate; TheoryBitvector* d_theoryBitvector; TheoryDatatype* d_theoryDatatype; std::vector d_dumpExprs; std::map* d_arrayConvertMap; Type* d_indexType; Type* d_elementType; Type* d_arrayType; std::vector d_equalities; // Name of benchmark in SMT-LIB std::string d_benchName; // Status of benchmark in SMT-LIB std::string d_status; // Source of benchmark in SMT-LIB std::string d_source; std::string fileToSMTLIBIdentifier(const std::string& filename); Expr preprocessRec(const Expr& e, ExprMap& cache); Expr preprocess(const Expr& e, ExprMap& cache); Expr preprocess2Rec(const Expr& e, ExprMap& cache, Type desiredType); Expr preprocess2(const Expr& e, ExprMap& cache); bool containsArray(const Expr& e); Expr processType(const Expr& e); /* Expr spassPreprocess(const Expr& e, ExprMap& mapping, std::vector& functions, std::vector& predicates); */ public: // Constructors Translator(ExprManager* em, const bool& translate, const bool& real2int, const bool& convertArith, const std::string& convertToDiff, bool iteLiftArith, const std::string& expResult, const std::string& category, bool convertArray, bool combineAssump, int convertToBV); ~Translator(); bool start(const std::string& dumpFile); /*! Dump the expression in the current output language \param dumpOnly When false, the expression is output both when translating and when producing a trace of commands. When true, the expression is only output when producing a trace of commands (i.e. ignored during translation). */ void dump(const Expr& e, bool dumpOnly = false); bool dumpAssertion(const Expr& e); bool dumpQuery(const Expr& e); void dumpQueryResult(QueryResult qres); void finish(); void setTheoryCore(TheoryCore* theoryCore) { d_theoryCore = theoryCore; } void setTheoryUF(TheoryUF* theoryUF) { d_theoryUF = theoryUF; } void setTheoryArith(TheoryArith* theoryArith) { d_theoryArith = theoryArith; } void setTheoryArray(TheoryArray* theoryArray) { d_theoryArray = theoryArray; } void setTheoryQuant(TheoryQuant* theoryQuant) { d_theoryQuant = theoryQuant; } void setTheoryRecords(TheoryRecords* theoryRecords) { d_theoryRecords = theoryRecords; } void setTheorySimulate(TheorySimulate* theorySimulate) { d_theorySimulate = theorySimulate; } void setTheoryBitvector(TheoryBitvector* theoryBitvector) { d_theoryBitvector = theoryBitvector; } void setTheoryDatatype(TheoryDatatype* theoryDatatype) { d_theoryDatatype = theoryDatatype; } void setBenchName(std::string name) { d_benchName = name; } std::string benchName() { return d_benchName; } void setStatus(std::string status) { d_status = status; } std::string status() { return d_status; } void setSource(std::string source) { d_source = source; } std::string source() { return d_source; } void setCategory(std::string category) { d_category = category; } std::string category() { return d_category; } const std::string fixConstName(const std::string& s); const std::string escapeSymbol(const std::string& s); const std::string quoteAnnotation(const std::string& s); //! Returns true if expression has been printed /*! If false is returned, array theory should print expression as usual */ bool printArrayExpr(ExprStream& os, const Expr& e); Expr zeroVar(); }; // end of class Translator } // end of namespace CVC3 #endif cvc3-2.4.1/src/include/search_simple.h0000664000175400017540000000376010540310276017463 0ustar mdetersmdeters/*****************************************************************************/ /*! * \file search_simple.h * * Author: Clark Barrett * * Created: Sat Mar 29 21:53:46 2003 * *
* * License to use, copy, modify, sell and/or distribute this software * and its documentation for any purpose is hereby granted without * royalty, subject to the terms and conditions defined in the \ref * LICENSE file provided with this distribution. * *
* */ /*****************************************************************************/ #ifndef _cvc3__include__search_simple_h_ #define _cvc3__include__search_simple_h_ #include "search_impl_base.h" #include "statistics.h" namespace CVC3 { class DecisionEngine; /*! * \defgroup SE_Simple Simple Search Engine * \ingroup SE * * This module includes all the components of a very simplistic search * engine. It is used mainly for debugging purposes. */ //! Implementation of the simple search engine /*! \ingroup SE_Simple */ class SearchSimple: public SearchImplBase { /*! \addtogroup SE_Simple * @{ */ //! Name std::string d_name; //! Decision Engine DecisionEngine* d_decisionEngine; //! Formula being checked CDO d_goal; //! Non-literals generated by DP's CDO d_nonLiterals; //! Theorem which records simplification of the last query CDO d_simplifiedThm; //! Recursive DPLL algorithm used by checkValid QueryResult checkValidRec(Theorem& thm); //! Private helper function for checkValid and restart QueryResult checkValidMain(const Expr& e2); public: //! Constructor SearchSimple(TheoryCore* core); //! Destructor ~SearchSimple(); // Implementation of virtual SearchEngine methods const std::string& getName() { return d_name; } QueryResult checkValidInternal(const Expr& e); QueryResult restartInternal(const Expr& e); void addLiteralFact(const Theorem& thm) {} void addNonLiteralFact(const Theorem& thm); /*! @} */ // end addtogroup SE_Simple }; } #endif cvc3-2.4.1/src/include/theorem.h0000664000175400017540000003567411027560537016331 0ustar mdetersmdeters/*****************************************************************************/ /*! * \file theorem.h * * Author: Sergey Berezin * * Created: Dec 10 00:37:49 GMT 2002 * *
* * License to use, copy, modify, sell and/or distribute this software * and its documentation for any purpose is hereby granted without * royalty, subject to the terms and conditions defined in the \ref * LICENSE file provided with this distribution. * *
* */ /*****************************************************************************/ // CLASS: Theorem // // AUTHOR: Sergey Berezin, 07/05/02 // // Abstract: // // A class representing a proven fact in CVC. It stores the theorem // as a CVC expression, and in the proof prodicing mode also its // proof. // // The idea is to allow only a few trusted classes to create values of // this class. If all the critical computations in the decision // procedures are done through the use of Theorems, then soundness of // these decision procedures will rely only on the soundness of the // methods in the trusted classes (the inference rules). // // Thus, proof checking can effectively be done at run-time on the // fly. Or the soundness may be potentially proven by static analysis // and many run-time checks can then be optimized away. // // This theorem.h file should be used by the decision procedures that // use Theorem. // //////////////////////////////////////////////////////////////////////// // expr.h Has to be included outside of #ifndef, since it sources us // recursively (read comments in expr_value.h). #ifndef _cvc3__expr_h_ #include "expr.h" #endif #ifndef _cvc3__theorem_h_ #define _cvc3__theorem_h_ #include "os.h" #include "proof.h" namespace CVC3 { // Declare the data holding classes but hide the definitions class TheoremManager; class TheoremValue; class Assumptions; // Theorem is basically a wrapper around a pointer to a // TheoremValue, so that we can pass this class around by value. // All the constructors of this class are private, so do not inherit // from it and do not try to create a value directly. Only // TheoremProducer can create new Theorem instances. // // Theorems, unlike expressions, are NOT made unique, and it is // possible to have the same theorem in different scopes with // different assumptions and proofs. It is a deliberate feature, // since natural deduction sometimes requires proving the same // conclusion from different assumptions independently, e.g. in // disjunction elimination rule. class CVC_DLL Theorem { private: // Make a theorem producing class our friend. No definition is // exposed here. friend class TheoremProducer; // Also allow our 3-valued cousin to create us friend class Theorem3; // Also TheoremValue classes for assumptions friend class RegTheoremValue; friend class RWTheoremValue; // Optimization: reflexivity theorems just store the exprValue pointer // directly. Also, the lowest bit is set to 1 to indicate that its // a reflexivity theorem. This really helps performance! union { intptr_t d_thm; ExprValue* d_expr; }; //! Compare Theorems by their expressions. Return -1, 0, or 1. friend int compare(const Theorem& t1, const Theorem& t2); //! Compare a Theorem with an Expr (as if Expr is a Theorem) friend int compare(const Theorem& t1, const Expr& e2); //! Compare Theorems by TheoremValue pointers. Return -1, 0, or 1. friend int compareByPtr(const Theorem& t1, const Theorem& t2); //! Equality is w.r.t. compare() friend bool operator==(const Theorem& t1, const Theorem& t2) { return (compare(t1, t2)==0); } //! Disequality is w.r.t. compare() friend bool operator!=(const Theorem& t1, const Theorem& t2) { return (compare(t1, t2) != 0); } //! Constructor only used by TheoremValue for assumptions Theorem(TheoremValue* thm) :d_thm(((intptr_t)thm) | 0x1) {} //! Constructor for a new theorem Theorem(TheoremManager* tm, const Expr &thm, const Assumptions& assump, const Proof& pf, bool isAssump = false, int scope = -1); //! Constructor for rewrite theorems. /*! These use a special efficient subclass of TheoremValue for * theorems which represent rewrites: A |- t = t' or A |- phi<=>phi' */ Theorem(TheoremManager* tm, const Expr& lhs, const Expr& rhs, const Assumptions& assump, const Proof& pf, bool isAssump = false, int scope = -1); //! Constructor for a reflexivity theorem: |-t=t or |-phi<=>phi Theorem(const Expr& e); void recursivePrint(int& i) const; void getAssumptionsRec(std::set& assumptions) const; void getAssumptionsAndCongRec(std::set& assumptions, std::vector& congruences) const; void GetSatAssumptionsRec(std::vector& assumptions) const; ExprValue* exprValue() const { return d_expr; } TheoremValue* thm() const { return (TheoremValue*)(d_thm & (~(0x1))); } public: // recusive function to print theorems and all assumptions recursively // important: this function will corrupt all flags!! so exercise // caution when using in any graph traversals // (probably more useful to call it only before a crash) void printDebug() const { clearAllFlags(); setCachedValue(0); setFlag(); int i = 1; recursivePrint(i); } // Default constructor creates Null theorem to allow untrusted // code declare local vars without initialization (vector // may need that, for instance). Theorem(): d_thm(0) { } // Copy constructor Theorem(const Theorem &th); // Assignment operator Theorem& operator=(const Theorem &th); // Destructor ~Theorem(); // Test if we are running in a proof production mode and with assumptions bool withProof() const; bool withAssumptions() const; bool isNull() const { return d_thm == 0; } // True if theorem is of the form t=t' or phi iff phi' bool isRewrite() const; // True if theorem was created using assumpRule bool isAssump() const; // True if reflexivity theorem bool isRefl() const { return d_thm && !(d_thm & 0x1); } // Return the theorem value as an Expr Expr getExpr() const; const Expr& getLHS() const; const Expr& getRHS() const; void GetSatAssumptions(std::vector& assumptions) const; // Return the assumptions. a should be empty and uninitialized // void getAssumptions(Assumptions& a) const; // Recurse to get actual assumptions void getLeafAssumptions(std::vector& assumptions, bool negate = false) const; // Same as above but also collects congruences in the proof tree void getAssumptionsAndCong(std::vector& assumptions, std::vector& congruences, bool negate = false) const; const Assumptions& getAssumptionsRef() const; // Return the proof of the theorem. If running without proofs, // return the Null proof. Proof getProof() const; // Return the lowest scope level at which this theorem is valid. // Value -1 means no information is available. int getScope() const; //! Return quantification level for this theorem unsigned getQuantLevel() const; unsigned getQuantLevelDebug() const; //! Set the quantification level for this theorem void setQuantLevel(unsigned level); // hash size_t hash() const; // Printing std::string toString() const; // For debugging void printx() const; void printxnodag() const; void pprintx() const; void pprintxnodag() const; void print() const; /*! \name Methods for Theorem Attributes * * Several attributes used in conflict analysis and assumptions * graph traversals. * @{ */ //! Check if the flag attribute is set bool isFlagged() const; //! Clear the flag attribute in all the theorems void clearAllFlags() const; //! Set the flag attribute void setFlag() const; //! Set flag stating that theorem is an instance of substitution void setSubst() const; //! Is theorem an instance of substitution bool isSubst() const; //! Set the "expand" attribute void setExpandFlag(bool val) const; //! Check the "expand" attribute bool getExpandFlag() const; //! Set the "literal" attribute /*! The expression of this theorem will be added as a conflict * clause literal */ void setLitFlag(bool val) const; //! Check the "literal" attribute /*! The expression of this theorem will be added as a conflict * clause literal */ bool getLitFlag() const; //! Check if the theorem is a literal bool isAbsLiteral() const; bool refutes(const Expr& e) const { return (e.isNot() && e[0] == getExpr()) || (getExpr().isNot() && getExpr()[0] == e); } bool proves(const Expr& e) const { return getExpr() == e; } bool matches(const Expr& e) const { return proves(e) || refutes(e); } void setCachedValue(int value) const; int getCachedValue() const; /*!@}*/ // End of Attribute methods //! Printing a theorem to a stream, calling it "name". std::ostream& print(std::ostream& os, const std::string& name) const; friend std::ostream& operator<<(std::ostream& os, const Theorem& t) { return t.print(os, "Theorem"); } static bool TheoremEq(const Theorem& t1, const Theorem& t2) { DebugAssert(!t1.isNull() && !t2.isNull(), "AssumptionsValue() Null Theorem passed to constructor"); return t1 == t2; } }; // End of Theorem /*****************************************************************************/ /*! *\class Theorem3 *\brief Theorem3 * * Author: Sergey Berezin * * Created: Tue Nov 4 17:57:07 2003 * * Implements the 3-valued theorem used for the user assertions and * the result of query. It is simply a wrapper around class Theorem, * but has a different semantic meaning: the formula may have partial * functions and has the Kleene's 3-valued interpretation. The fact * that a Theorem3 value is derived means that the TCCs for the * formula and all of its assumptions are valid in the current * context, and the proofs of TCCs contribute to the set of * assumptions. */ /*****************************************************************************/ class Theorem3 { private: // Make a theorem producing class our friend. No definition is // exposed here. friend class TheoremProducer; Theorem d_thm; friend bool operator==(const Theorem3& t1, const Theorem3& t2) { return t1.d_thm == t2.d_thm; } friend bool operator!=(const Theorem3& t1, const Theorem3& t2) { return t1.d_thm != t2.d_thm; } // Private constructors for a new theorem Theorem3(TheoremManager* tm, const Expr &thm, const Assumptions& assump, const Proof& pf, bool isAssump = false, int scope = -1) : d_thm(tm, thm, assump, pf, isAssump, scope) { } // Constructors for rewrite theorems. These use a special efficient // subclass of TheoremValue for theorems which represent rewrites: // A |- t = t' or A |- phi iff phi' Theorem3(TheoremManager* tm, const Expr& lhs, const Expr& rhs, const Assumptions& assump, const Proof& pf) : d_thm(tm, lhs, rhs, assump, pf) { } public: // recusive function to print theorems and all assumptions recursively // important: this function will corrupt all flags!! so exercise // caution when using in any graph traversals // (probably more useful to call it only before a crash) void printDebug() const { d_thm.printDebug(); } // Default constructor creates Null theorem to allow untrusted // code declare local vars without initialization (vector // may need that, for instance). Theorem3() { } // Destructor virtual ~Theorem3() { } bool isNull() const { return d_thm.isNull(); } // True if theorem is of the form t=t' or phi iff phi' bool isRewrite() const { return d_thm.isRewrite(); } bool isAssump() const { return d_thm.isAssump(); } // Return the theorem value as an Expr Expr getExpr() const { return d_thm.getExpr(); } const Expr& getLHS() const { return d_thm.getLHS(); } const Expr& getRHS() const { return d_thm.getRHS(); } // Return the assumptions. // It's an error if called while running without assumptions. // void getAssumptions(Assumptions& a) const { d_thm.getAssumptions(a); } const Assumptions& getAssumptionsRef() const { return d_thm.getAssumptionsRef(); } // Return the proof of the theorem. If running without proofs, // return the Null proof. Proof getProof() const { return d_thm.getProof(); } // Return the lowest scope level at which this theorem is valid. // Value -1 means no information is available. int getScope() const { return d_thm.getScope(); } // Test if we are running in a proof production mode and with assumptions bool withProof() const { return d_thm.withProof(); } bool withAssumptions() const { return d_thm.withAssumptions(); } // Printing std::string toString() const; // For debugging void printx() const { d_thm.printx(); } void print() const { d_thm.print(); } //! Check if the theorem is a literal bool isAbsLiteral() const { return d_thm.isAbsLiteral(); } friend std::ostream& operator<<(std::ostream& os, const Theorem3& t) { return t.d_thm.print(os, "Theorem3"); } }; // End of Theorem3 //! "Less" comparator for theorems by TheoremValue pointers class TheoremLess { public: bool operator()(const Theorem& t1, const Theorem& t2) const { return (compareByPtr(t1, t2) < 0); } }; typedef std::map TheoremMap; inline std::string Theorem::toString() const { std::ostringstream ss; ss << (*this); return ss.str(); } inline std::string Theorem3::toString() const { std::ostringstream ss; ss << (*this); return ss.str(); } // Merge assumptions from different theorems // inline Assumptions merge(const Theorem& t1, const Theorem& t2) { // return Assumptions(t1, t2); // } // inline void merge(Assumptions& a, const Theorem& t) { // a.add(t); // } // inline Assumptions merge(const std::vector& t) { // return Assumptions(t); // } inline bool operator<(const Theorem& t1, const Theorem& t2) { return compare(t1, t2) < 0; } inline bool operator<=(const Theorem& t1, const Theorem& t2) { return compare(t1, t2) <= 0; } inline bool operator>(const Theorem& t1, const Theorem& t2) { return compare(t1, t2) > 0; } inline bool operator>=(const Theorem& t1, const Theorem& t2) { return compare(t1, t2) >= 0; } } // end of namespace CVC3 #include "hash_fun.h" namespace Hash { template<> struct hash { size_t operator()(const CVC3::Theorem& e) const { return e.hash(); } }; } #endif cvc3-2.4.1/src/include/eval_exception.h0000664000175400017540000000256211103725115017647 0ustar mdetersmdeters/*****************************************************************************/ /*! * \file eval_exception.h * * Author: Sergey Berezin * * Created: Tue Feb 25 14:58:57 2003 * *
* * License to use, copy, modify, sell and/or distribute this software * and its documentation for any purpose is hereby granted without * royalty, subject to the terms and conditions defined in the \ref * LICENSE file provided with this distribution. * *
* * An exception thrown on an error while evaluating a command. Use it * only when the error does not fall under any of the standard cases * like typecheck or parse errors. */ /*****************************************************************************/ #ifndef _cvc3__eval_exception_h_ #define _cvc3__eval_exception_h_ #include "exception.h" namespace CVC3 { class EvalException: public Exception { public: // Constructors EvalException() { } EvalException(const std::string& msg): Exception(msg) { } EvalException(const char* msg): Exception(msg) { } // Destructor virtual ~EvalException() { } // Printing the message virtual std::string toString() const { return "Error while evaluating a command:\n " + d_msg; } }; class ResetException: public Exception { public: // Constructors ResetException(): Exception("Reset Exception") { } // Destructor virtual ~ResetException() { } }; } #endif cvc3-2.4.1/src/include/lang.h0000664000175400017540000000471211437303444015571 0ustar mdetersmdeters/*****************************************************************************/ /*! * \file lang.h * \brief Definition of input and output languages to CVC3 * * Author: Mehul Trivedi * * Created: Thu Jul 29 11:56:34 2004 * *
* * License to use, copy, modify, sell and/or distribute this software * and its documentation for any purpose is hereby granted without * royalty, subject to the terms and conditions defined in the \ref * LICENSE file provided with this distribution. * *
* */ /*****************************************************************************/ #ifndef _cvc3__lang_h_ #define _cvc3__lang_h_ #include "debug.h" namespace CVC3 { //! Different input languages typedef enum { //! Nice SAL-like language for manually written specs PRESENTATION_LANG, //! SMT-LIB format SMTLIB_LANG, //! Lisp-like format for automatically generated specs LISP_LANG, AST_LANG, /* @brief AST is only for printing the Expr abstract syntax tree in lisp format; there is no such input language per se */ //! for output into Simplify format SIMPLIFY_LANG, //! for output in TPTP format TPTP_LANG, //! for output in SPASS format SPASS_LANG, //! SMT-LIB v2 format SMTLIB_V2_LANG } InputLanguage; inline bool isPrefix(const std::string& prefix, const std::string& str) { return str.rfind( prefix, 0 ) == 0; } inline InputLanguage getLanguage(const std::string& lang) { if (lang.size() > 0) { if(isPrefix(lang,"presentation")) { return PRESENTATION_LANG; } if(isPrefix(lang, "lisp")) { return LISP_LANG; } if(isPrefix(lang,"ast")) { return AST_LANG; } if(isPrefix(lang,"tptp")) { return TPTP_LANG; } /* Languages starting with 's' must have at least 2 letters, since there's more than one of them. */ if(lang.size() > 1) { if(isPrefix(lang,"simplify")) { return SIMPLIFY_LANG; } if(isPrefix(lang,"spass")) { return SPASS_LANG; } if (lang[ lang.length() - 1 ] == '2' && isPrefix(lang.substr(0,lang.length()-1),"smtlib")) { return SMTLIB_V2_LANG; } if(isPrefix(lang,"smtlib")) { return SMTLIB_LANG; } } } throw Exception("Bad input language specified"); return AST_LANG; } } // end of namespace CVC3 #endif cvc3-2.4.1/src/include/theory_array.h0000664000175400017540000000737511415512203017357 0ustar mdetersmdeters/*****************************************************************************/ /*! * \file theory_array.h * * Author: Clark Barrett * * Created: Wed Feb 26 18:32:06 2003 * *
* * License to use, copy, modify, sell and/or distribute this software * and its documentation for any purpose is hereby granted without * royalty, subject to the terms and conditions defined in the \ref * LICENSE file provided with this distribution. * *
* */ /*****************************************************************************/ #ifndef _cvc3__include__theory_array_h_ #define _cvc3__include__theory_array_h_ #include "theory_core.h" namespace CVC3 { class ArrayProofRules; typedef enum { ARRAY = 2000, READ, WRITE, // Array literal [ [type] e ]; creates a constant array holding 'e' // in all elements: (CONST_ARRAY type e) ARRAY_LITERAL } ArrayKinds; /*****************************************************************************/ /*! *\class TheoryArray *\ingroup Theories *\brief This theory handles arrays. * * Author: Clark Barrett * * Created: Thu Feb 27 00:38:20 2003 */ /*****************************************************************************/ class TheoryArray :public Theory { ArrayProofRules* d_rules; //! Backtracking list of array reads, for building concrete models. CDList d_reads; //! Set of renaming theorems \f$\exists x. t = x\f$ indexed by t ExprMap d_renameThms; //! Flag to include array reads to the concrete model const bool& d_applicationsInModel; //! Flag to lift ite's over reads const bool& d_liftReadIte; //! Backtracking database of subterms of shared terms CDMap d_sharedSubterms; //! Backtracking database of subterms of shared terms CDList d_sharedSubtermsList; //! Used in checkSat CDO d_index; CDO d_sharedIdx1, d_sharedIdx2; //! Flag for use in checkSat int d_inCheckSat; //! Derived rule // w(...,i,v1,...,) => w(......,i,v1') // Returns Null Theorem if index does not appear Theorem pullIndex(const Expr& e, const Expr& index); public: TheoryArray(TheoryCore* core); ~TheoryArray(); // Trusted method that creates the proof rules class (used in constructor). // Implemented in array_theorem_producer.cpp ArrayProofRules* createProofRules(); // Theory interface void addSharedTerm(const Expr& e); void assertFact(const Theorem& e); void checkSat(bool fullEffort); Theorem rewrite(const Expr& e); void setup(const Expr& e); void update(const Theorem& e, const Expr& d); Theorem solve(const Theorem& e); void checkType(const Expr& e); Cardinality finiteTypeInfo(Expr& e, Unsigned& n, bool enumerate, bool computeSize); void computeType(const Expr& e); Type computeBaseType(const Type& t); void computeModelTerm(const Expr& e, std::vector& v); void computeModel(const Expr& e, std::vector& vars); Expr computeTCC(const Expr& e); virtual Expr parseExprOp(const Expr& e); ExprStream& print(ExprStream& os, const Expr& e); Expr getBaseArray(const Expr& e) const; }; // Array testers inline bool isArray(const Type& t) { return t.getExpr().getKind() == ARRAY; } inline bool isRead(const Expr& e) { return e.getKind() == READ; } inline bool isWrite(const Expr& e) { return e.getKind() == WRITE; } inline bool isArrayLiteral(const Expr& e) { return (e.isClosure() && e.getKind() == ARRAY_LITERAL); } // Array constructors inline Type arrayType(const Type& type1, const Type& type2) { return Type(Expr(ARRAY, type1.getExpr(), type2.getExpr())); } // Expr read(const Expr& arr, const Expr& index); // Expr write(const Expr& arr, const Expr& index, const Expr& value); Expr arrayLiteral(const Expr& ind, const Expr& body); } // end of namespace CVC3 #endif cvc3-2.4.1/src/include/c_interface_defs.h0000664000175400017540000000242311520105445020102 0ustar mdetersmdeters/*****************************************************************************/ /*! * \file c_interface_defs.h * * Author: Clark Barrett * * Created: Thu Jun 5 13:16:26 2003 * *
* * License to use, copy, modify, sell and/or distribute this software * and its documentation for any purpose is hereby granted without * royalty, subject to the terms and conditions defined in the \ref * LICENSE file provided with this distribution. * *
* */ /*****************************************************************************/ #ifndef _cvc3__include__c_interface_defs_h_ #define _cvc3__include__c_interface__defs_h_ #include "kinds.h" #ifdef CVC3_STRONG_TYPING typedef struct _cvc_VC *VC; typedef struct _cvc_Context *Context; typedef struct _cvc_ExprManager *ExprManager; typedef struct _cvc_Flags *Flags; typedef struct _cvc_Expr * Expr; typedef struct _cvc_Op * Op; typedef struct _cvc_Type* Type; #else //This gives absolutely no static pointer typing. typedef void* VC; typedef void* Context; typedef void* ExprManager; typedef void* Flags; typedef void* Expr; typedef void* Op; typedef void* Type; typedef void* Proof; #endif #endif cvc3-2.4.1/src/include/memory_manager_malloc.h0000664000175400017540000000275210557763737021224 0ustar mdetersmdeters/*****************************************************************************/ /*! * \file memory_manager_malloc.h * * Author: Sergey Berezin * * Created: Tue Apr 19 14:30:36 2005 * *
* * License to use, copy, modify, sell and/or distribute this software * and its documentation for any purpose is hereby granted without * royalty, subject to the terms and conditions defined in the \ref * LICENSE file provided with this distribution. * *
* * Class MemoryManagerMalloc: default implementation of MemoryManager * using malloc(). * * Typical use of this class is to create * MemoryManager* mm = new MemoryManager(sizeof(YourClass)); * where YourClass has operators new and delete redefined: * void* YourClass::operator new(size_t, MemoryManager* mm) * { return mm->newData(); } * void YourClass::delete(void*) { } // do not deallocate memory here * Then, create objects with obj = new(mm) YourClass(), and destroy them with * delete obj; mm->deleteData(obj); */ /*****************************************************************************/ #ifndef _cvc3__memory_manager_malloc_h #define _cvc3__memory_manager_malloc_h #include "memory_manager.h" namespace CVC3 { class MemoryManagerMalloc: public MemoryManager { public: // Constructor MemoryManagerMalloc() { } // Destructor ~MemoryManagerMalloc() { } void* newData(size_t size) { return malloc(size); } void deleteData(void* d) { free(d); } }; // end of class MemoryManager } #endif cvc3-2.4.1/src/include/hash_fun.h0000664000175400017540000000641210516512376016445 0ustar mdetersmdeters/*****************************************************************************/ /*! *\file hash_fun.h *\brief hash functions * * Author: Alexander Fuchs * * Created: Fri Oct 20 11:04:00 2006 * *
* * License to use, copy, modify, sell and/or distribute this software * and its documentation for any purpose is hereby granted without * royalty, subject to the terms and conditions defined in the \ref * LICENSE file provided with this distribution. * *
*/ /*****************************************************************************/ /* * Copyright (c) 1996-1998 * Silicon Graphics Computer Systems, Inc. * * Permission to use, copy, modify, distribute and sell this software * and its documentation for any purpose is hereby granted without fee, * provided that the above copyright notice appear in all copies and * that both that copyright notice and this permission notice appear * in supporting documentation. Silicon Graphics makes no * representations about the suitability of this software for any * purpose. It is provided "as is" without express or implied warranty. * * * Copyright (c) 1994 * Hewlett-Packard Company * * Permission to use, copy, modify, distribute and sell this software * and its documentation for any purpose is hereby granted without fee, * provided that the above copyright notice appear in all copies and * that both that copyright notice and this permission notice appear * in supporting documentation. Hewlett-Packard Company makes no * representations about the suitability of this software for any * purpose. It is provided "as is" without express or implied warranty. * */ // this is basically (modulo renaming and namespace) the SGI implementation: // http://www.sgi.com/tech/stl/stl_hash_fun.h #ifndef _cvc3__hash__hash_fun_h_ #define _cvc3__hash__hash_fun_h_ // to get size_t #include namespace Hash { using std::size_t; template struct hash { }; inline size_t __stl_hash_string(const char* __s) { unsigned long __h = 0; for ( ; *__s; ++__s) __h = 5*__h + *__s; return size_t(__h); } template<> struct hash { size_t operator()(const char* __s) const { return __stl_hash_string(__s); } }; template<> struct hash { size_t operator()(const char* __s) const { return __stl_hash_string(__s); } }; template<> struct hash { size_t operator()(char __x) const { return __x; } }; template<> struct hash { size_t operator()(unsigned char __x) const { return __x; } }; template<> struct hash { size_t operator()(unsigned char __x) const { return __x; } }; template<> struct hash { size_t operator()(short __x) const { return __x; } }; template<> struct hash { size_t operator()(unsigned short __x) const { return __x; } }; template<> struct hash { size_t operator()(int __x) const { return __x; } }; template<> struct hash { size_t operator()(unsigned int __x) const { return __x; } }; template<> struct hash { size_t operator()(long __x) const { return __x; } }; template<> struct hash { size_t operator()(unsigned long __x) const { return __x; } }; } #endif cvc3-2.4.1/src/include/expr_manager.h0000664000175400017540000004775411310064375017332 0ustar mdetersmdeters/*****************************************************************************/ /*! * \file expr_manager.h * \brief Expression manager API * * Author: Sergey Berezin * * Created: Wed Dec 4 14:20:56 2002 * *
* * License to use, copy, modify, sell and/or distribute this software * and its documentation for any purpose is hereby granted without * royalty, subject to the terms and conditions defined in the \ref * LICENSE file provided with this distribution. * *
* */ /*****************************************************************************/ // Must be before #ifndef, since expr.h also includes this file (see // comments in expr_value.h) #ifndef _cvc3__expr_h_ #include "expr.h" #endif #ifndef _cvc3__include__expr_manager_h_ #define _cvc3__include__expr_manager_h_ #include "os.h" #include "expr_map.h" #include namespace CVC3 { // Command line flags class CLFlags; class PrettyPrinter; class MemoryManager; class ExprManagerNotifyObj; class TheoremManager; /////////////////////////////////////////////////////////////////////////////// //! Expression Manager /*! Class: ExprManager Author: Sergey Berezin Created: Wed Dec 4 14:26:35 2002 Description: Global state of the Expr package for a particular instance of CVC3. Each instance of the CVC3 library has its own expression manager, for thread-safety. */ /////////////////////////////////////////////////////////////////////////////// class CVC_DLL ExprManager { friend class Expr; friend class ExprValue; friend class Op; // It wants to call rebuildExpr friend class HashEV; // Our own private class friend class Type; ContextManager* d_cm; //!< For backtracking attributes TheoremManager* d_tm; //!< Needed for Refl Theorems ExprManagerNotifyObj* d_notifyObj; //!< Notification on pop() ExprIndex d_index; //!< Index counter for Expr compare() unsigned d_flagCounter; //!< Counter for a generic Expr flag //! The database of registered kinds std::hash_map d_kindMap; //! The set of kinds representing a type std::hash_set d_typeKinds; //! Private class for hashing strings class HashString { std::hash h; public: size_t operator()(const std::string& s) const { return h(const_cast(s.c_str())); } }; //! The reverse map of names to kinds std::hash_map d_kindMapByName; /*! @brief The registered pretty-printer, a connector to theory-specific pretty-printers */ PrettyPrinter *d_prettyPrinter; size_t hash(const ExprValue* ev) const; // Printing and other options /*! @brief Print upto the given depth, replace the rest with "...". -1==unlimited depth. */ const int* d_printDepth; //! Whether to print with indentation const bool* d_withIndentation; //! Permanent indentation int d_indent; //! Transient indentation /*! Normally is the same as d_indent, but may temporarily be different for printing one single Expr */ int d_indentTransient; //! Suggested line width for printing with indentation const int* d_lineWidth; //! Input language (printing) const std::string* d_inputLang; //! Output language (printing) const std::string* d_outputLang; //! Whether to print Expr's as DAGs const bool* d_dagPrinting; //! Which memory manager to use (copy the flag value and keep it the same) const std::string d_mmFlag; //! Private class for d_exprSet class HashEV { ExprManager* d_em; public: HashEV(ExprManager* em): d_em(em) { } size_t operator()(ExprValue* ev) const { return d_em->hash(ev); } }; //! Private class for d_exprSet class EqEV { public: bool operator()(const ExprValue* ev1, const ExprValue* ev2) const; }; //! Hash set type for uniquifying expressions typedef std::hash_set ExprValueSet; //! Hash set for uniquifying expressions ExprValueSet d_exprSet; //! Array of memory managers for subclasses of ExprValue std::vector d_mm; //! A hash function for hashing pointers std::hash d_pointerHash; //! Expr constants cached for fast access Expr d_bool; Expr d_false; Expr d_true; //! Empty vector of Expr to return by reference as empty vector of children std::vector d_emptyVec; //! Null Expr to return by reference, for efficiency Expr d_nullExpr; void installExprValue(ExprValue* ev); //! Current value of the simplifier cache tag /*! The cached values of calls to Simplify are valid as long as their cache tag matches this tag. Caches can then be invalidated by incrementing this tag. */ unsigned d_simpCacheTagCurrent; //! Disable garbage collection /*! This flag disables the garbage collection. Normally, it's set in the destructor, so that we can delete all remaining expressions without GC getting in the way. */ bool d_disableGC; //! Postpone deleting garbage-collected expressions. /*! Useful during manipulation of context, especially at the time * of backtracking, since we may have objects with circular * dependencies (like find pointers). * * The postponed expressions will be deleted the next time the * garbage collector is called after this flag is cleared. */ bool d_postponeGC; //! Vector of postponed garbage-collected expressions std::vector d_postponed; //! Flag for whether GC is already running bool d_inGC; //! Queue of pending exprs to GC std::deque d_pending; //! Rebuild cache ExprHashMap d_rebuildCache; IF_DEBUG(bool d_inRebuild;) public: //! Abstract class for computing expr type class TypeComputer { public: TypeComputer() {} virtual ~TypeComputer() {} //! Compute the type of e virtual void computeType(const Expr& e) = 0; //! Check that e is a valid Type expr virtual void checkType(const Expr& e) = 0; //! Get information related to finiteness of a type virtual Cardinality finiteTypeInfo(Expr& e, Unsigned& n, bool enumerate, bool computeSize) = 0; }; private: //! Instance of TypeComputer: must be registered TypeComputer* d_typeComputer; ///////////////////////////////////////////////////////////////////////// /*! \defgroup EM_Priv Private methods * \ingroup ExprPkg * @{ */ ///////////////////////////////////////////////////////////////////////// //! Cached recursive descent. Must be called only during rebuild() Expr rebuildRec(const Expr& e); //! Return either an existing or a new ExprValue matching ev ExprValue* newExprValue(ExprValue* ev); //! Return the current Expr flag counter unsigned getFlag() { return d_flagCounter; } //! Increment and return the Expr flag counter (this clears all the flags) unsigned nextFlag() { FatalAssert(++d_flagCounter, "flag overflow"); return d_flagCounter; } //! Compute the type of the Expr void computeType(const Expr& e); //! Check well-formedness of a type Expr void checkType(const Expr& e); //! Get information related to finiteness of a type // 1. Returns Cardinality of the type (finite, infinite, or unknown) // 2. If cardinality = finite and enumerate is true, // sets e to the nth element of the type if it can // sets e to NULL if n is out of bounds or if unable to compute nth element // 3. If cardinality = finite and computeSize is true, // sets n to the size of the type if it can // sets n to 0 otherwise Cardinality finiteTypeInfo(Expr& e, Unsigned& n, bool enumerate, bool computeSize); public: //! Constructor ExprManager(ContextManager* cm, const CLFlags& flags); //! Destructor ~ExprManager(); //! Free up all memory and delete all the expressions. /*! * No more expressions can be created after this point, only * destructors ~Expr() can be called. * * This method is needed to dis-entangle the mutual dependency of * ExprManager and ContextManager, when destructors of ExprValue * (sub)classes need to delete backtracking objects, and deleting * the ContextManager requires destruction of some remaining Exprs. */ void clear(); //! Check if the ExprManager is still active (clear() was not called) bool isActive(); //! Garbage collect the ExprValue pointer /*! \ingroup EM_Priv */ void gc(ExprValue* ev); //! Postpone deletion of garbage-collected expressions. /*! \sa resumeGC() */ void postponeGC() { d_postponeGC = true; } //! Resume deletion of garbage-collected expressions. /*! \sa postponeGC() */ void resumeGC(); /*! @brief Rebuild the Expr with this ExprManager if it belongs to another ExprManager */ Expr rebuild(const Expr& e); //! Return the next Expr index /*! It should be used only by ExprValue() constructor */ ExprIndex nextIndex() { return d_index++; } ExprIndex lastIndex() { return d_index - 1; } //! Clears the generic Expr flag in all Exprs void clearFlags() { nextFlag(); } // Core leaf exprs //! BOOLEAN Expr const Expr& boolExpr() { return d_bool; } //! FALSE Expr const Expr& falseExpr() { return d_false; } //! TRUE Expr const Expr& trueExpr() { return d_true; } //! References to empty objects (used in ExprValue) const std::vector& getEmptyVector() { return d_emptyVec; } //! References to empty objects (used in ExprValue) const Expr& getNullExpr() { return d_nullExpr; } // Expr constructors //! Return either an existing or a new Expr matching ev Expr newExpr(ExprValue* ev) { return Expr(newExprValue(ev)); } Expr newLeafExpr(const Op& op); Expr newStringExpr(const std::string &s); Expr newRatExpr(const Rational& r); Expr newSkolemExpr(const Expr& e, int i); Expr newVarExpr(const std::string &s); Expr newSymbolExpr(const std::string &s, int kind); Expr newBoundVarExpr(const std::string &name, const std::string& uid); Expr newBoundVarExpr(const std::string &name, const std::string& uid, const Type& type); Expr newBoundVarExpr(const Type& type); Expr newClosureExpr(int kind, const Expr& var, const Expr& body); Expr newClosureExpr(int kind, const std::vector& vars, const Expr& body); Expr newClosureExpr(int kind, const std::vector& vars, const Expr& body, const Expr& trigger); Expr newClosureExpr(int kind, const std::vector& vars, const Expr& body, const std::vector& triggers); Expr newClosureExpr(int kind, const std::vector& vars, const Expr& body, const std::vector >& triggers); // Vector of children constructors (vector may be empty) Expr andExpr(const std::vector & children) { return Expr(AND, children, this); } Expr orExpr(const std::vector & children) { return Expr(OR, children, this); } // Public methods //! Hash function for a single Expr size_t hash(const Expr& e) const; //! Fetch our ContextManager ContextManager* getCM() const { return d_cm; } //! Get the current context from our ContextManager Context* getCurrentContext() const { return d_cm->getCurrentContext(); } //! Get current scope level int scopelevel() { return d_cm->scopeLevel(); } //! Set the TheoremManager void setTM(TheoremManager* tm) { d_tm = tm; } //! Fetch the TheoremManager TheoremManager* getTM() const { return d_tm; } //! Return a MemoryManager for the given ExprValue type MemoryManager* getMM(size_t MMIndex) { DebugAssert(MMIndex < d_mm.size(), "ExprManager::getMM()"); return d_mm[MMIndex]; } //! Get the simplifier's cache tag unsigned getSimpCacheTag() const { return d_simpCacheTagCurrent; } //! Invalidate the simplifier's cache tag void invalidateSimpCache() { d_simpCacheTagCurrent++; } //! Register type computer void registerTypeComputer(TypeComputer* typeComputer) { d_typeComputer = typeComputer; } //! Get printing depth int printDepth() const { return *d_printDepth; } //! Whether to print with indentation bool withIndentation() const { return *d_withIndentation; } //! Suggested line width for printing with indentation int lineWidth() const { return *d_lineWidth; } //! Get initial indentation int indent() const { return d_indentTransient; } //! Set initial indentation. Returns the previous permanent value. int indent(int n, bool permanent = false); //! Increment the current transient indentation by n /*! If the second argument is true, sets the result as permanent. \return previous permanent value. */ int incIndent(int n, bool permanent = false); //! Set transient indentation to permanent void restoreIndent() { d_indentTransient = d_indent; } //! Get the input language for printing InputLanguage getInputLang() const; //! Get the output language for printing InputLanguage getOutputLang() const; //! Whether to print Expr's as DAGs bool dagPrinting() const { return *d_dagPrinting; } /*! @brief Return the pretty-printer if there is one; otherwise return NULL. */ PrettyPrinter* getPrinter() const { return d_prettyPrinter; } ///////////////////////////////////////////////////////////////////////////// // Kind registration // ///////////////////////////////////////////////////////////////////////////// //! Register a new kind. /*! The kind may already be registered under the same name, but if * the name is different, it's an error. * * If the new kind is supposed to represent a type, set isType to true. */ void newKind(int kind, const std::string &name, bool isType = false); //! Register the pretty-printer (can only do it if none registered) /*! The pointer is NOT owned by ExprManager. Delete it yourself. */ void registerPrettyPrinter(PrettyPrinter& printer); //! Tell ExprManager that the printer is no longer valid void unregisterPrettyPrinter(); /*! @brief Returns true if kind is built into CVC or has been registered via newKind. */ bool isKindRegistered(int kind) { return d_kindMap.count(kind) > 0; } //! Check if a kind represents a type bool isTypeKind(int kind) { return d_typeKinds.count(kind) > 0; } /*! @brief Return the name associated with a kind. The kind must already be registered. */ const std::string& getKindName(int kind); //! Return a kind associated with a name. Returns NULL_KIND if not found. int getKind(const std::string& name); //! Register a new subclass of ExprValue /*! * Takes the size (in bytes) of the new subclass and returns the * unique index of that subclass. Subsequent calls to the * subclass's getMMIndex() must return that index. */ size_t registerSubclass(size_t sizeOfSubclass); //! Calculate memory usage unsigned long getMemory(int verbosity); }; // end of class ExprManager /*****************************************************************************/ /*! *\class ExprManagerNotifyObj *\brief Notifies ExprManager before and after each pop() * * Author: Sergey Berezin * * Created: Tue Mar 1 12:29:14 2005 * * Disables the deletion of Exprs during context restoration * (backtracking). This solves the problem of circular dependencies, * e.g. in find pointers. */ /*****************************************************************************/ class ExprManagerNotifyObj: public ContextNotifyObj { ExprManager* d_em; public: //! Constructor ExprManagerNotifyObj(ExprManager* em, Context* cxt) : ContextNotifyObj(cxt), d_em(em) { } void notifyPre(void); void notify(void); unsigned long getMemory(int verbosity) { return sizeof(ExprManagerNotifyObj); } }; } // end of namespace CVC3 // Include expr_value here for inline definitions #include "expr_value.h" namespace CVC3 { inline size_t ExprManager::hash(const ExprValue* ev) const { DebugAssert(ev!=NULL, "ExprManager::hash() called on a NULL ExprValue"); return ev->hash(); } inline Expr ExprManager::newLeafExpr(const Op& op) { if (op.getKind() != APPLY) { ExprValue ev(this, op.getKind()); return newExpr(&ev); } else { DebugAssert(op.getExpr().getEM() == this, "ExprManager mismatch"); std::vector kids; ExprApply ev(this, op, kids); return newExpr(&ev); } } inline Expr ExprManager::newStringExpr(const std::string &s) { ExprString ev(this, s); return newExpr(&ev); } inline Expr ExprManager::newRatExpr(const Rational& r) { ExprRational ev(this, r); return newExpr(&ev); } inline Expr ExprManager::newSkolemExpr(const Expr& e, int i) { DebugAssert(e.getEM() == this, "ExprManager mismatch"); ExprSkolem ev(this, i, e); return newExpr(&ev); } inline Expr ExprManager::newVarExpr(const std::string &s) { ExprVar ev(this, s); return newExpr(&ev); } inline Expr ExprManager::newSymbolExpr(const std::string &s, int kind) { ExprSymbol ev(this, kind, s); return newExpr(&ev); } inline Expr ExprManager::newBoundVarExpr(const std::string &name, const std::string& uid) { ExprBoundVar ev(this, name, uid); return newExpr(&ev); } inline Expr ExprManager::newBoundVarExpr(const std::string& name, const std::string& uid, const Type& type) { Expr res = newBoundVarExpr(name, uid); DebugAssert(type.getExpr().getKind() != ARROW,""); DebugAssert(res.lookupType().isNull(), "newBoundVarExpr: redefining a variable " + name); res.setType(type); return res; } inline Expr ExprManager::newBoundVarExpr(const Type& type) { static int nextNum = 0; std::string name("_cvc3_"); std::string uid = int2string(nextNum++); return newBoundVarExpr(name, uid, type); } inline Expr ExprManager::newClosureExpr(int kind, const Expr& var, const Expr& body) { ExprClosure ev(this, kind, var, body); return newExpr(&ev); } inline Expr ExprManager::newClosureExpr(int kind, const std::vector& vars, const Expr& body) { ExprClosure ev(this, kind, vars, body); return newExpr(&ev); } inline Expr ExprManager::newClosureExpr(int kind, const std::vector& vars, const Expr& body, const std::vector& triggers) { ExprClosure ev(this, kind, vars, body); Expr ret = newExpr(&ev); ret.setTriggers(triggers); return ret; } inline Expr ExprManager::newClosureExpr(int kind, const std::vector& vars, const Expr& body, const std::vector >& triggers) { ExprClosure ev(this, kind, vars, body); Expr ret = newExpr(&ev); ret.setTriggers(triggers); return ret; } inline Expr ExprManager::newClosureExpr(int kind, const std::vector& vars, const Expr& body, const Expr& trigger) { ExprClosure ev(this, kind, vars, body); Expr ret = newExpr(&ev); ret.setTrigger(trigger); return ret; } inline bool ExprManager::EqEV::operator()(const ExprValue* ev1, const ExprValue* ev2) const { return (*ev1) == (*ev2); } inline size_t ExprManager::hash(const Expr& e) const { DebugAssert(!e.isNull(), "ExprManager::hash() called on a Null Expr"); return e.d_expr->hash(); } } // end of namespace CVC3 #endif cvc3-2.4.1/src/include/variable.h0000664000175400017540000003505010562776537016453 0ustar mdetersmdeters/*****************************************************************************/ /*! * \file variable.h * * Author: Sergey Berezin * * Created: Fri Apr 25 11:52:17 2003 * *
* * License to use, copy, modify, sell and/or distribute this software * and its documentation for any purpose is hereby granted without * royalty, subject to the terms and conditions defined in the \ref * LICENSE file provided with this distribution. * *
* * A data structure representing a variable in the search engine. It * is a smart pointer with a uniquifying mechanism similar to Expr, * and a variable is uniquely determined by its expression. It can be * thought of as an Expr with additional attributes, but the type is * different, so it will not be confused with other Exprs. */ /*****************************************************************************/ #ifndef _cvc3__variable_h_ #define _cvc3__variable_h_ #include "expr.h" namespace CVC3 { class VariableManager; class VariableValue; class Clause; class SearchEngineRules; // The main "smart pointer" class class Variable { private: VariableValue* d_val; // Private methods Theorem deriveThmRec(bool checkAssump) const; public: // Default constructor Variable(): d_val(NULL) { } // Constructor from an Expr; if such variable already exists, it // will be found and used. Variable(VariableManager* vm, const Expr& e); // Copy constructor Variable(const Variable& l); // Destructor ~Variable(); // Assignment Variable& operator=(const Variable& l); bool isNull() const { return d_val == NULL; } // Accessors // Expr is the only constant attribute of a variable; other // attributes can be changed. const Expr& getExpr() const; // The Expr of the inverse of the variable. This function is // caching, so !e is only constructed once. const Expr& getNegExpr() const; // IMPORTANT: Value can be -1 (false), 1 (true), or 0 (unresolved) int getValue() const; // If the value is set, scope level and either a theorem or // an antecedent clause must be defined int getScope() const; const Theorem& getTheorem() const; const Clause& getAntecedent() const; // Index of this variable in the antecedent clause; if it is -1, // the variable is FALSE, and that clause caused the contradiction int getAntecedentIdx() const; // Theorem of the form l |- l produced by the 'assump' rule, if // this variable is a splitter, or a new intermediate assumption // is generated for it. const Theorem& getAssumpThm() const; // Setting the attributes: it can be either derived from the // antecedent clause, or by a theorem. The scope level is set to // the current scope. void setValue(int val, const Clause& c, int idx); // The theorem's expr must be the same as the variable's expr or // its negation, and the scope is the lowest scope where all // assumptions of the theorem are true void setValue(const Theorem& thm); void setValue(const Theorem& thm, int scope); void setAssumpThm(const Theorem& a, int scope); // Derive the theorem for either the variable or its negation. If // the value is set by a theorem, that theorem is returned; // otherwise a unit propagation rule is applied to the antecedent // clause. Theorem deriveTheorem() const; // Accessing Chaff counters (read and modified by reference) unsigned& count(bool neg); unsigned& countPrev(bool neg); int& score(bool neg); bool& added(bool neg); // Read-only versions unsigned count(bool neg) const; unsigned countPrev(bool neg) const; int score(bool neg) const; bool added(bool neg) const; // Watch pointer access std::vector >& wp(bool neg) const; // Friend methods friend bool operator==(const Variable& l1, const Variable& l2) { return l1.d_val == l2.d_val; } // Printing friend std::ostream& operator<<(std::ostream& os, const Variable& l); std::string toString() const; }; // end of class Variable class Literal { private: Variable d_var; bool d_negative; public: // Constructors: from a variable Literal(const Variable& v, bool positive = true) : d_var(v), d_negative(!positive) { } // Default constructor Literal(): d_negative(false) { } // from Expr: if e == !e', construct negative literal of e', // otherwise positive of e Literal(VariableManager* vm, const Expr& e) : d_var(vm, (e.isNot())? e[0] : e), d_negative(e.isNot()) { } Variable& getVar() { return d_var; } const Variable& getVar() const { return d_var; } bool isPositive() const { return !d_negative; } bool isNegative() const { return d_negative; } bool isNull() const { return d_var.isNull(); } // Return var or !var const Expr& getExpr() const { if(d_negative) return d_var.getNegExpr(); else return d_var.getExpr(); } int getValue() const { if(d_negative) return -(d_var.getValue()); else return d_var.getValue(); } int getScope() const { return getVar().getScope(); } // Set the value of the literal // void setValue(int val, const Clause& c, int idx) { // d_var.setValue(d_negative? -val : val, c, idx); // } void setValue(const Theorem& thm) { d_var.setValue(thm, thm.getScope()); } void setValue(const Theorem& thm, int scope) { d_var.setValue(thm, scope); } const Theorem& getTheorem() const { return d_var.getTheorem(); } // const Clause& getAntecedent() const { return d_var.getAntecedent(); } // int getAntecedentIdx() const { return d_var.getAntecedentIdx(); } // Defined when the literal has a value. Derives a theorem // proving either this literal or its inverse. Theorem deriveTheorem() const { return d_var.deriveTheorem(); } // Accessing Chaff counters (read and modified by reference) unsigned& count() { return d_var.count(d_negative); } unsigned& countPrev() { return d_var.countPrev(d_negative); } int& score() { return d_var.score(d_negative); } bool& added() { return d_var.added(d_negative); } // Read-only versions unsigned count() const { return d_var.count(d_negative); } unsigned countPrev() const { return d_var.countPrev(d_negative); } int score() const { return d_var.score(d_negative); } bool added() const { return d_var.added(d_negative); } // Watch pointer access std::vector >& wp() const { return d_var.wp(d_negative); } // Printing friend std::ostream& operator<<(std::ostream& os, const Literal& l); std::string toString() const; // Equality friend bool operator==(const Literal& l1, const Literal& l2) { return (l1.d_negative == l2.d_negative && l1.d_var==l1.d_var); } }; // end of class Literal // Non-member methods: negation of Variable and Literal inline Literal operator!(const Variable& v) { return Literal(v, false); } inline Literal operator!(const Literal& l) { return Literal(l.getVar(), l.isNegative()); } std::ostream& operator<<(std::ostream& os, const Literal& l); } // end of namespace CVC3 // Clause uses class Variable, have to include it here #include "clause.h" namespace CVC3 { // The value holding class class VariableValue { friend class Variable; friend class VariableManager; private: VariableManager* d_vm; int d_refcount; Expr d_expr; // The inverse expression (initally Null) Expr d_neg; // Non-backtracking attributes (Chaff counters) // For positive instances unsigned d_count; unsigned d_countPrev; int d_score; // For negative instances unsigned d_negCount; unsigned d_negCountPrev; int d_negScore; // Whether the corresponding literal is in the list of active literals bool d_added; bool d_negAdded; // Watch pointer lists std::vector > d_wp; std::vector > d_negwp; // Backtracking attributes // Value of the variable: -1 (false), 1 (true), 0 (unresolved) CDO* d_val; CDO* d_scope; // Scope level where the variable is assigned // Theorem of the form (d_expr) or (!d_expr), reflecting d_val CDO* d_thm; CDO* d_ante; // Antecedent clause and index of the variable CDO* d_anteIdx; CDO* d_assump; // Theorem generated by assump rule, if any // Constructor is private; only class Variable can create it VariableValue(VariableManager* vm, const Expr& e) : d_vm(vm), d_refcount(0), d_expr(e), d_count(0), d_countPrev(0), d_score(0), d_negCount(0), d_negCountPrev(0), d_negScore(0), d_added(false), d_negAdded(false), d_val(NULL), d_scope(NULL), d_thm(NULL), d_ante(NULL), d_anteIdx(NULL), d_assump(NULL) { } public: ~VariableValue(); // Accessor methods const Expr& getExpr() const { return d_expr; } const Expr& getNegExpr() const { if(d_neg.isNull()) { const_cast(this)->d_neg = d_expr.negate(); } return d_neg; } int getValue() const { if(d_val==NULL) return 0; else return d_val->get(); } int getScope() const { if(d_scope==NULL) return 0; else return d_scope->get(); } const Theorem& getTheorem() const { static Theorem null; if(d_thm==NULL) return null; else return d_thm->get(); } const Clause& getAntecedent() const { static Clause null; if(d_ante==NULL) return null; else return d_ante->get(); } int getAntecedentIdx() const { if(d_anteIdx==NULL) return 0; else return d_anteIdx->get(); } const Theorem& getAssumpThm() const { static Theorem null; if(d_assump==NULL) return null; else return d_assump->get(); } // Setting the attributes: it can be either derived from the // antecedent clause, or by a theorem void setValue(int val, const Clause& c, int idx); // The theorem's expr must be the same as the variable's expr or // its negation void setValue(const Theorem& thm, int scope); void setAssumpThm(const Theorem& a, int scope); // Chaff counters: read and modified by reference unsigned& count(bool neg) { if(neg) return d_negCount; else return d_count; } unsigned& countPrev(bool neg) { if(neg) return d_negCountPrev; else return d_countPrev; } int& score(bool neg) { if(neg) return d_negScore; else return d_score; } bool& added(bool neg) { if(neg) return d_negAdded; else return d_added; } // Memory management void* operator new(size_t size, MemoryManager* mm) { return mm->newData(size); } void operator delete(void* pMem, MemoryManager* mm) { mm->deleteData(pMem); } void operator delete(void*) { } // friend methods friend std::ostream& operator<<(std::ostream& os, const VariableValue& v); friend bool operator==(const VariableValue& v1, const VariableValue& v2) { return v1.d_expr == v2.d_expr; } }; // end of class VariableValue // Accessing Chaff counters (read and modified by reference) inline unsigned& Variable::count(bool neg) { return d_val->count(neg); } inline unsigned& Variable::countPrev(bool neg) { return d_val->countPrev(neg); } inline int& Variable::score(bool neg) { return d_val->score(neg); } inline bool& Variable::added(bool neg) { return d_val->added(neg); } inline unsigned Variable::count(bool neg) const { return d_val->count(neg); } inline unsigned Variable::countPrev(bool neg) const { return d_val->countPrev(neg); } inline int Variable::score(bool neg) const { return d_val->score(neg); } inline bool Variable::added(bool neg) const { return d_val->added(neg); } inline std::vector >& Variable::wp(bool neg) const { if(neg) return d_val->d_negwp; else return d_val->d_wp; } class VariableManagerNotifyObj; // The manager class class VariableManager { friend class Variable; friend class VariableValue; private: ContextManager* d_cm; MemoryManager* d_mm; SearchEngineRules* d_rules; VariableManagerNotifyObj* d_notifyObj; //! Disable the garbage collection /*! Normally, it's set in the destructor, so that we can delete * all remaining variables without GC getting in the way */ bool d_disableGC; //! Postpone garbage collection bool d_postponeGC; //! Vector of variables to be deleted (postponed during pop()) std::vector d_deleted; // Hash only by the Expr class HashLV { public: size_t operator()(VariableValue* v) const { return v->getExpr().hash(); } }; class EqLV { public: bool operator()(const VariableValue* lv1, const VariableValue* lv2) const { return lv1->getExpr() == lv2->getExpr(); } }; // Hash set for existing variables typedef std::hash_set VariableValueSet; VariableValueSet d_varSet; // Creating unique VariableValue VariableValue* newVariableValue(const Expr& e); public: // Constructor. mmFlag indicates which memory manager to use. VariableManager(ContextManager* cm, SearchEngineRules* rules, const std::string& mmFlag); // Destructor ~VariableManager(); //! Garbage collect VariableValue pointer void gc(VariableValue* v); //! Postpone garbage collection void postponeGC() { d_postponeGC = true; } //! Resume garbage collection void resumeGC(); // Accessors ContextManager* getCM() const { return d_cm; } SearchEngineRules* getRules() const { return d_rules; } }; // end of class VariableManager /*****************************************************************************/ /*! *\class VariableManagerNotifyObj *\brief Notifies VariableManager before and after each pop() * * Author: Sergey Berezin * * Created: Tue Mar 1 13:52:28 2005 * * Disables the deletion of VariableValue objects during context * restoration (backtracking). This solves the problem of circular * dependencies (e.g. a Variable pointing to its antecedent Clause). */ /*****************************************************************************/ class VariableManagerNotifyObj: public ContextNotifyObj { VariableManager* d_vm; public: //! Constructor VariableManagerNotifyObj(VariableManager* vm, Context* cxt) : ContextNotifyObj(cxt), d_vm(vm) { } void notifyPre(void) { d_vm->postponeGC(); } void notify(void) { d_vm->resumeGC(); } }; } // end of namespace CVC3 #endif cvc3-2.4.1/src/include/rational.h0000644000175400017540000002561511547077344016475 0ustar mdetersmdeters/*****************************************************************************/ /*! * \file rational.h * * Author: Sergey Berezin * * Created: Dec 12 22:00:18 GMT 2002 * *
* * License to use, copy, modify, sell and/or distribute this software * and its documentation for any purpose is hereby granted without * royalty, subject to the terms and conditions defined in the \ref * LICENSE file provided with this distribution. * *
* */ /*****************************************************************************/ // Class: Rational // Author: Sergey Berezin, 12/12/2002 (adapted from Bignum) // // Description: This is an abstration of a rational with arbitrary // precision. It provides a constructor from a pair of ints and // strings, overloaded operator{+,-,*,/}, assignment, etc. The // current implementation uses GMP mpq_class. /////////////////////////////////////////////////////////////////////////////// #ifndef _cvc3__rational_h_ #define _cvc3__rational_h_ // Do not include here; it contains some depricated C++ // headers. We only include it in the .cpp file. #include #include "debug.h" // To be defined only in bignum.cpp namespace CVC3 { class Unsigned; class CVC_DLL Rational { friend class Unsigned; private: class Impl; Impl *d_n; // Debugging #ifdef _DEBUG_RATIONAL_ // Encapsulate static values in a function to guarantee // initialization when we need it int& getCreated() { static int num_created = 0; return(num_created); } int& getDeleted() { static int num_deleted = 0; return(num_deleted); } void printStats(); #endif // Private constructor (for internal consumption only) Rational(const Impl& t); public: // Constructors Rational(); // Copy constructor Rational(const Rational &n); Rational(const Unsigned& n); Rational(int n, int d = 1); Rational(const char* n, int base = 10); Rational(const std::string& n, int base = 10); Rational(const char* n, const char* d, int base = 10); Rational(const std::string& n, const std::string& d, int base = 10); // Destructor ~Rational(); // Assignment Rational& operator=(const Rational& n); std::string toString(int base = 10) const; // Compute hash value (for DAG expression representation) size_t hash() const; friend CVC_DLL bool operator==(const Rational &n1, const Rational &n2); friend CVC_DLL bool operator<(const Rational &n1, const Rational &n2); friend CVC_DLL bool operator<=(const Rational &n1, const Rational &n2); friend CVC_DLL bool operator>(const Rational &n1, const Rational &n2); friend CVC_DLL bool operator>=(const Rational &n1, const Rational &n2); friend CVC_DLL bool operator!=(const Rational &n1, const Rational &n2); friend CVC_DLL Rational operator+(const Rational &n1, const Rational &n2); friend CVC_DLL Rational operator-(const Rational &n1, const Rational &n2); friend CVC_DLL Rational operator*(const Rational &n1, const Rational &n2); friend CVC_DLL Rational operator/(const Rational &n1, const Rational &n2); // 'mod' operator, defined only for integer values of n1 and n2 friend CVC_DLL Rational operator%(const Rational &n1, const Rational &n2); // Unary minus Rational operator-() const; Rational &operator+=(const Rational &n2); Rational &operator-=(const Rational &n2); Rational &operator*=(const Rational &n2); Rational &operator/=(const Rational &n2); //! Prefix increment const Rational& operator++() { *this = (*this)+1; return *this; } //! Postfix increment Rational operator++(int) { Rational x(*this); *this = x+1; return x; } //! Prefix decrement const Rational& operator--() { *this = (*this)-1; return *this; } //! Postfix decrement Rational operator--(int) { Rational x(*this); *this = x-1; return x; } // Result is integer Rational getNumerator() const; Rational getDenominator() const; // Equivalent to (getDenominator() == 1), but possibly more efficient bool isInteger() const; // Convert to int; defined only on integer values int getInt() const; // Equivalent to (*this >= 0 && isInteger()) bool isUnsigned() const { return (isInteger() && (*this) >= 0); } // Convert to unsigned int; defined only on non-negative integer values unsigned int getUnsigned() const; Unsigned getUnsignedMP() const; friend std::ostream &operator<<(std::ostream &os, const Rational &n); friend std::ostream &operator<<(std::ostream &os, const Impl &n); /* Computes gcd and lcm on *integer* values. Result is always a positive integer. */ friend CVC_DLL Rational gcd(const Rational &x, const Rational &y); friend CVC_DLL Rational gcd(const std::vector &v); friend CVC_DLL Rational lcm(const Rational &x, const Rational &y); friend CVC_DLL Rational lcm(const std::vector &v); friend CVC_DLL Rational abs(const Rational &x); //! Compute the floor of x (result is an integer) friend CVC_DLL Rational floor(const Rational &x); //! Compute the ceiling of x (result is an integer) friend CVC_DLL Rational ceil(const Rational &x); //! Compute non-negative remainder for *integer* x,y. friend CVC_DLL Rational mod(const Rational &x, const Rational &y); //! nth root: return 0 if no exact answer (base should be nonzero) friend CVC_DLL Rational intRoot(const Rational& base, unsigned long int n); // For debugging, to be able to print in gdb void print() const; }; // Rational class //! Raise 'base' into the power of 'pow' (pow must be an integer) inline Rational pow(Rational pow, const Rational& base) { DebugAssert(pow.isInteger(), "pow("+pow.toString() +", "+base.toString()+")"); FatalAssert(base != 0 || pow >= 0, "Attempt to divide by zero"); bool neg(pow < 0); if(neg) pow = -pow; Rational res(1); for(; pow > 0; --pow) res *= base; if(neg) res = 1/res; return res; } //! take nth root of base, return result if it is exact, 0 otherwise // base should not be 0 inline Rational ratRoot(const Rational& base, unsigned long int n) { DebugAssert(base != 0, "Expected nonzero base"); Rational num = base.getNumerator(); num = intRoot(num, n); if (num != 0) { Rational den = base.getDenominator(); den = intRoot(den, n); if (den != 0) { return num / den; } } return 0; } // Methods creating new Rational values, similar to the // constructors, but can be nested inline Rational newRational(int n, int d = 1) { return Rational(n, d); } inline Rational newRational(const char* n, int base = 10) { return Rational(n, base); } inline Rational newRational(const std::string& n, int base = 10) { return Rational(n, base); } inline Rational newRational(const char* n, const char* d, int base = 10) { return Rational(n, d, base); } inline Rational newRational(const std::string& n, const std::string& d, int base = 10) { return Rational(n, d, base); } // Debugging print void printRational(const Rational &x); class CVC_DLL Unsigned { private: friend class Rational::Impl; class Impl; Impl *d_n; // Private constructor (for internal consumption only) Unsigned(const Impl& t); public: // Constructors Unsigned(); // Copy constructor Unsigned(const Unsigned &n); Unsigned(int n); Unsigned(unsigned n); Unsigned(const char* n, int base = 10); Unsigned(const std::string& n, int base = 10); // Destructor ~Unsigned(); // Assignment Unsigned& operator=(const Unsigned& n); std::string toString(int base = 10) const; // Compute hash value (for DAG expression representation) size_t hash() const; friend CVC_DLL bool operator==(const Unsigned &n1, const Unsigned &n2); friend CVC_DLL bool operator<(const Unsigned &n1, const Unsigned &n2); friend CVC_DLL bool operator<=(const Unsigned &n1, const Unsigned &n2); friend CVC_DLL bool operator>(const Unsigned &n1, const Unsigned &n2); friend CVC_DLL bool operator>=(const Unsigned &n1, const Unsigned &n2); friend CVC_DLL bool operator!=(const Unsigned &n1, const Unsigned &n2); friend CVC_DLL Unsigned operator+(const Unsigned &n1, const Unsigned &n2); friend CVC_DLL Unsigned operator-(const Unsigned &n1, const Unsigned &n2); friend CVC_DLL Unsigned operator*(const Unsigned &n1, const Unsigned &n2); friend CVC_DLL Unsigned operator/(const Unsigned &n1, const Unsigned &n2); // 'mod' operator, defined only for integer values of n1 and n2 friend CVC_DLL Unsigned operator%(const Unsigned &n1, const Unsigned &n2); friend CVC_DLL Unsigned operator<<(const Unsigned& n1, unsigned n2); friend CVC_DLL Unsigned operator&(const Unsigned& n1, const Unsigned& n2); Unsigned &operator+=(const Unsigned &n2); Unsigned &operator-=(const Unsigned &n2); Unsigned &operator*=(const Unsigned &n2); Unsigned &operator/=(const Unsigned &n2); //! Prefix increment const Unsigned& operator++() { *this = (*this)+1; return *this; } //! Postfix increment Unsigned operator++(int) { Unsigned x(*this); *this = x+1; return x; } //! Prefix decrement const Unsigned& operator--() { *this = (*this)-1; return *this; } //! Postfix decrement Unsigned operator--(int) { Unsigned x(*this); *this = x-1; return x; } // Convert to unsigned int if possible unsigned long getUnsigned() const; friend std::ostream &operator<<(std::ostream &os, const Unsigned &n); /* Computes gcd and lcm on *integer* values. Result is always a positive integer. */ friend CVC_DLL Unsigned gcd(const Unsigned &x, const Unsigned &y); friend CVC_DLL Unsigned gcd(const std::vector &v); friend CVC_DLL Unsigned lcm(const Unsigned &x, const Unsigned &y); friend CVC_DLL Unsigned lcm(const std::vector &v); //! Compute non-negative remainder for *integer* x,y. friend CVC_DLL Unsigned mod(const Unsigned &x, const Unsigned &y); //! nth root: return 0 if no exact answer (base should be nonzero) friend CVC_DLL Unsigned intRoot(const Unsigned& base, unsigned long int n); // For debugging, to be able to print in gdb void print() const; }; // Unsigned class //! Raise 'base' into the power of 'pow' (pow must be an integer) inline Unsigned pow(Unsigned pow, const Unsigned& base) { Unsigned res(1); for(; pow > (unsigned)0; --pow) res *= base; return res; } // Methods creating new Unsigned values, similar to the // constructors, but can be nested inline Unsigned newUnsigned(int n) { return Unsigned(n); } inline Unsigned newUnsigned(const char* n, int base = 10) { return Unsigned(n, base); } inline Unsigned newUnsigned(const std::string& n, int base = 10) { return Unsigned(n, base); } // Debugging print void printUnsigned(const Unsigned &x); } // end of namespace CVC3 #endif cvc3-2.4.1/src/include/sound_exception.h0000664000175400017540000000227511267754362020072 0ustar mdetersmdeters/*****************************************************************************/ /*! * \file sound_exception.h * \brief An exception to be thrown when unsoundness is detected in a proof rule * * Author: Sergey Berezin * * Created: Fri Jun 6 10:48:38 2003 * *
* * License to use, copy, modify, sell and/or distribute this software * and its documentation for any purpose is hereby granted without * royalty, subject to the terms and conditions defined in the \ref * LICENSE file provided with this distribution. * *
* */ /*****************************************************************************/ #ifndef _cvc3__sound_exception_h_ #define _cvc3__sound_exception_h_ #include #include #include "exception.h" namespace CVC3 { class SoundException: public Exception { public: // Constructors SoundException() { } SoundException(const std::string& msg): Exception(msg) { } SoundException(const char* msg): Exception(msg) { } // Destructor virtual ~SoundException() { } virtual std::string toString() const { return "Soundness error: " + d_msg; } }; // end of class SoundException } // end of namespace CVC3 #endif cvc3-2.4.1/src/include/compat_hash_map.h0000664000175400017540000000220510634045774017775 0ustar mdetersmdeters/*****************************************************************************/ /*! * \file compat_hash_map.h * * Author: Sergey Berezin * * Created: Jan 31 02:23:26 GMT 2003 * *
* * License to use, copy, modify, sell and/or distribute this software * and its documentation for any purpose is hereby granted without * royalty, subject to the terms and conditions defined in the \ref * LICENSE file provided with this distribution. * *
* * Compatibility header file for STL extension "hash_map". Any other * source file that needs to use hash_map should include this instead. * * If hash_map is not defined in namespace std, we bring it in there. * It turns out that different versions of gcc use different * namespaces for STL extensions (std, __gnu_cxx, and God knows * what'll be next). * * This header assumes that only one of HAVE_*_HASH_MAP symbols is * defined. * */ /*****************************************************************************/ #ifndef _cvc3__include__compat_hash_map_h_ #define _cvc3__include__compat_hash_map_h_ #include "hash_map.h" namespace std { using namespace Hash; } #endif cvc3-2.4.1/src/include/type.h0000664000175400017540000000630511210144240015613 0ustar mdetersmdeters/*****************************************************************************/ /*! * \file type.h * * Author: Clark Barrett * * Created: Thu Dec 12 12:53:28 2002 * *
* * License to use, copy, modify, sell and/or distribute this software * and its documentation for any purpose is hereby granted without * royalty, subject to the terms and conditions defined in the \ref * LICENSE file provided with this distribution. * *
* */ /*****************************************************************************/ // expr.h Has to be included outside of #ifndef, since it sources us // recursively (read comments in expr_value.h). #ifndef _cvc3__expr_h_ #include "expr.h" #endif #ifndef _cvc3__include__type_h_ #define _cvc3__include__type_h_ namespace CVC3 { #include "os.h" /////////////////////////////////////////////////////////////////////////////// // // // Class: Type // // Author: Clark Barrett // // Created: Thu Dec 12 12:53:34 2002 // // Description: Wrapper around expr for api // // // /////////////////////////////////////////////////////////////////////////////// class CVC_DLL Type { Expr d_expr; public: Type() {} Type(Expr expr); //! Special constructor that doesn't check if expr is a type //TODO: make this private Type(const Type& type) :d_expr(type.d_expr) {} Type(Expr expr, bool dummy) :d_expr(expr) {} const Expr& getExpr() const { return d_expr; } // Reasoning about children int arity() const { return d_expr.arity(); } Type operator[](int i) const { return Type(d_expr[i]); } // Core testers bool isNull() const { return d_expr.isNull(); } bool isBool() const { return d_expr.getKind() == BOOLEAN; } bool isSubtype() const { return d_expr.getKind() == SUBTYPE; } bool isFunction() const { return d_expr.getKind() == ARROW; } //! Return cardinality of type Cardinality card() const { return d_expr.typeCard(); } //! Return nth (starting with 0) element in a finite type /*! Returns NULL Expr if unable to compute nth element */ Expr enumerateFinite(Unsigned n) const { return d_expr.typeEnumerateFinite(n); } //! Return size of a finite type; returns 0 if size cannot be determined Unsigned sizeFinite() const { return d_expr.typeSizeFinite(); } // Core constructors static Type typeBool(ExprManager* em) { return Type(em->boolExpr(), true); } static Type anyType(ExprManager* em) { return Type(em->newLeafExpr(ANY_TYPE)); } static Type funType(const std::vector& typeDom, const Type& typeRan); Type funType(const Type& typeRan) const { return Type(Expr(ARROW, d_expr, typeRan.d_expr)); } // Printing std::string toString() const { return getExpr().toString(); } }; inline bool operator==(const Type& t1, const Type& t2) { return t1.getExpr() == t2.getExpr(); } inline bool operator!=(const Type& t1, const Type& t2) { return t1.getExpr() != t2.getExpr(); } // Printing inline std::ostream& operator<<(std::ostream& os, const Type& t) { return os << t.getExpr(); } } #endif cvc3-2.4.1/src/include/parser.h0000664000175400017540000000473011366166030016143 0ustar mdetersmdeters/*****************************************************************************/ /*! * \file parser.h * * Author: Sergey Berezin * * Created: Wed Feb 5 11:46:57 2003 * *
* * License to use, copy, modify, sell and/or distribute this software * and its documentation for any purpose is hereby granted without * royalty, subject to the terms and conditions defined in the \ref * LICENSE file provided with this distribution. * *
* * The top-level API to the parser. At this level, it is simply a * stream of commands (Expr's) terminated by an infinite sequence of * Null Expr. It has a support to parse several different input * languages (as many as we care to implement), and may take a file * name, or an istream to read from (default: std::cin, or stdin). * Using iostream means no more worries about whether to close files * or not. */ /*****************************************************************************/ #ifndef _cvc3__parser_h_ #define _cvc3__parser_h_ #include "exception.h" #include "lang.h" namespace CVC3 { class ValidityChecker; class Translator; class Expr; // Internal parser state and other data class ParserData; class Parser { private: ParserData* d_data; // Internal methods for constructing and destroying the actual parser void initParser(); void deleteParser(); public: // Constructors Parser(ValidityChecker* vc, Translator* translator, InputLanguage lang, // The 'interactive' flag is ignored when fileName != "" bool interactive = true, const std::string& fileName = ""); Parser(ValidityChecker* vc, Translator* translator, InputLanguage lang, std::istream& is, bool interactive = false); // Destructor ~Parser(); // Read the next command. Expr next(); // Check if we are done (end of input has been reached) bool done() const; // The same check can be done by using the class Parser's value as // a Boolean operator bool() const { return done(); } void printLocation(std::ostream & out) const; // Reset any local data that depends on validity checker void reset(); }; // end of class Parser // The global pointer to ParserTemp. Each instance of class Parser // sets this pointer before any calls to the lexer. We do it this // way because flex and bison use global vars, and we want each // Parser object to appear independent. class ParserTemp; extern ParserTemp* parserTemp; } // end of namespace CVC3 #endif cvc3-2.4.1/src/include/memory_manager_chunks.h0000664000175400017540000000605210557763737021245 0ustar mdetersmdeters/*****************************************************************************/ /*! * \file memory_manager_chunks.h * * Author: Sergey Berezin * * Created: Tue Apr 19 14:30:36 2005 * *
* * License to use, copy, modify, sell and/or distribute this software * and its documentation for any purpose is hereby granted without * royalty, subject to the terms and conditions defined in the \ref * LICENSE file provided with this distribution. * *
* * Class MemoryManager: allocates/deallocates memory for objects of a * fixed size (the size is a parameter to the constructor). The * actual memory is allocated in big chunks, which (at the moment) are * never released back. However, the deallocated blocks are later reused. * * Typical use of this class is to create * MemoryManager* mm = new MemoryManager(sizeof(YourClass)); * where YourClass has operators new and delete redefined: * void* YourClass::operator new(size_t, MemoryManager* mm) * { return mm->newData(); } * void YourClass::delete(void*) { } // do not deallocate memory here * Then, create objects with obj = new(mm) YourClass(), and destroy them with * delete obj; mm->deleteData(obj); */ /*****************************************************************************/ #ifndef _cvc3__memory_manager_chunks_h #define _cvc3__memory_manager_chunks_h #include #include "memory_manager.h" namespace CVC3 { class MemoryManagerChunks: public MemoryManager { private: unsigned d_dataSize; // #bytes in each data element unsigned d_chunkSize; // number of data elements unsigned d_chunkSizeBytes; // #bytes in each chunk std::vector d_freeList; std::vector d_chunkList; // Pointers to the beginning of each chunk // Pointer to the next free block of memory in the current chunk char* d_nextFree; // End of current chunk (1 byte off the end) char* d_endChunk; // Private methods void newChunk() { // Allocate new chunk d_nextFree = (char*)malloc(d_chunkSizeBytes); FatalAssert(d_nextFree != NULL, "Out of memory"); d_endChunk = d_nextFree + d_chunkSizeBytes; d_chunkList.push_back(d_nextFree); } public: // Constructor MemoryManagerChunks(unsigned dataSize, unsigned chunkSize = 1024) : d_dataSize(dataSize), d_chunkSize(chunkSize), d_chunkSizeBytes(dataSize*chunkSize), d_nextFree(NULL), d_endChunk(NULL) { } // Destructor ~MemoryManagerChunks() { while(d_chunkList.size() > 0) { free(d_chunkList.back()); d_chunkList.pop_back(); } } void* newData(size_t size) { DebugAssert(size == d_dataSize, "MemoryManager::newData: the data size doesn't match"); void* res; // Check the free list first if(d_freeList.size() > 0) { res = (void*)d_freeList.back(); d_freeList.pop_back(); return res; } if(d_nextFree == NULL || d_nextFree == d_endChunk) newChunk(); res = (void*)d_nextFree; d_nextFree += d_dataSize; return res; } void deleteData(void* d) { d_freeList.push_back((char*)d); } }; // end of class MemoryManager } #endif cvc3-2.4.1/src/include/assumptions.h0000664000175400017540000001323511004130320017212 0ustar mdetersmdeters/*****************************************************************************/ /*! * \file assumptions.h * * Author: Sergey Berezin * * Created: Dec 10 00:37:49 GMT 2002 * *
* * License to use, copy, modify, sell and/or distribute this software * and its documentation for any purpose is hereby granted without * royalty, subject to the terms and conditions defined in the \ref * LICENSE file provided with this distribution. * *
* */ /*****************************************************************************/ // CLASS: Assumptions // // AUTHOR: Sergey Berezin, 12/03/2002 // // Abstract: // // Mathematically, the value of class Assumptions is a set of pairs // 'u:A' on the LHS of the Theorem's sequent. Both u and A are Expr. // // Null assumptions is almost always treated as the empty set. The // only exception: iterators cannot be constructed for Null. // // This interface should be used as little as possible by the users of // Theorem class. /////////////////////////////////////////////////////////////////////////////// #ifndef _cvc3__expr_h_ #include "expr.h" #endif #ifndef _cvc3__assumptions_h_ #define _cvc3__assumptions_h_ #include "theorem.h" namespace CVC3 { class Assumptions { private: std::vector d_vector; static Assumptions s_empty; private: // Private constructor for internal use. Assumes v != NULL. // Assumptions(AssumptionsValue *v); // helper function for [] const Theorem& findTheorem(const Expr& e) const; static bool findExpr(const Assumptions& a, const Expr& e, std::vector& gamma); static bool findExprs(const Assumptions& a, const std::vector& es, std::vector& gamma); void add(const std::vector& thms); public: //! Default constructor: no value is created Assumptions() { } //! Constructor from a vector of theorems Assumptions(const std::vector& v); //! Constructor for one theorem (common case) Assumptions(const Theorem& t) { d_vector.push_back(t); } //! Constructor for two theorems (common case) Assumptions(const Theorem& t1, const Theorem& t2); // Destructor ~Assumptions() {} // Copy constructor. Assumptions(const Assumptions &assump) : d_vector(assump.d_vector) {} // Assignment. Assumptions &operator=(const Assumptions &assump) { d_vector = assump.d_vector; return *this; } static const Assumptions& emptyAssump() { return s_empty; } void add1(const Theorem& t) { DebugAssert(d_vector.empty(), "expected empty vector"); d_vector.push_back(t); } void add(const Theorem& t); void add(const Assumptions& a) { add(a.d_vector); } // clear the set of assumptions void clear() { d_vector.clear(); } // get the size unsigned size() const { return d_vector.size(); } bool empty() const { return d_vector.empty(); } // needed by TheoremValue Theorem& getFirst() { DebugAssert(size() > 0, "Expected size > 0"); return d_vector[0]; } // Print functions std::string toString() const; void print() const; // Return Assumption associated with the expression. The // value will be Null if the assumption is not in the set. // // NOTE: do not try to assign anything to the result, it won't work. const Theorem& operator[](const Expr& e) const; // find only searches through current set of assumptions, will not recurse const Theorem& find(const Expr& e) const; //! Iterator for the Assumptions: points to class Theorem. /*! Cannot inherit from vector::const_iterator in gcc 2.96 */ class iterator : public std::iterator { // Let's be friends friend class Assumptions; private: std::vector::const_iterator d_it; iterator(const std::vector::const_iterator& i): d_it(i) { } public: //! Default constructor iterator() { } //! Destructor ~iterator() { } //! Equality bool operator==(const iterator& i) const { return (d_it == i.d_it); } //! Disequality bool operator!=(const iterator& i) const { return (d_it != i.d_it); } //! Dereference operator const Theorem& operator*() const { return *d_it; } //! Member dereference operator const Theorem* operator->() const { return &(operator*()); } //! Prefix increment iterator& operator++() { ++d_it; return *this; } //! Proxy class for postfix increment class Proxy { const Theorem* d_t; public: Proxy(const Theorem& t) : d_t(&t) { } const Theorem& operator*() { return *d_t; } }; //! Postfix increment Proxy operator++(int) { return Proxy(*(d_it++)); } }; iterator begin() const { return iterator(d_vector.begin()); } iterator end() const { return iterator(d_vector.end()); } // Merging assumptions // friend Assumptions operator+(const Assumptions& a1, const Assumptions& a2); //! Returns all (recursive) assumptions except e friend Assumptions operator-(const Assumptions& a, const Expr& e); //! Returns all (recursive) assumptions except those in es friend Assumptions operator-(const Assumptions& a, const std::vector& es); friend std::ostream& operator<<(std::ostream& os, const Assumptions &assump); friend bool operator==(const Assumptions& a1, const Assumptions& a2) { return a1.d_vector == a2.d_vector; } friend bool operator!=(const Assumptions& a1, const Assumptions& a2) { return a1.d_vector != a2.d_vector; } }; // end of class Assumptions } // end of namespace CVC3 #endif cvc3-2.4.1/src/include/vcl.h0000644000175400017540000003727011624746722015447 0ustar mdetersmdeters/*****************************************************************************/ /*! * \file vcl.h * \brief Main implementation of ValidityChecker for CVC3. * * Author: Clark Barrett * * Created: Wed Dec 11 14:40:39 2002 * *
* * License to use, copy, modify, sell and/or distribute this software * and its documentation for any purpose is hereby granted without * royalty, subject to the terms and conditions defined in the \ref * LICENSE file provided with this distribution. * *
* */ /*****************************************************************************/ #ifndef _cvc3__include__vcl_h_ #define _cvc3__include__vcl_h_ #include #include "vc.h" #include "command_line_flags.h" #include "statistics.h" #include "cdmap.h" #include "cdlist.h" namespace CVC3 { class SearchEngine; class Theory; class TheoryCore; class TheoryUF; class TheoryArith; class TheoryArray; class TheoryQuant; class TheoryRecords; class TheorySimulate; class TheoryBitvector; class TheoryDatatype; class Translator; class CVC_DLL VCL : public ValidityChecker { //! Pointers to main system components ExprManager* d_em; ContextManager* d_cm; TheoremManager* d_tm; SearchEngine* d_se; //! Pointers to theories TheoryCore* d_theoryCore; TheoryUF* d_theoryUF; TheoryArith* d_theoryArith; TheoryArray* d_theoryArray; TheoryQuant* d_theoryQuant; TheoryRecords* d_theoryRecords; TheorySimulate* d_theorySimulate; TheoryBitvector* d_theoryBitvector; TheoryDatatype* d_theoryDatatype; Translator* d_translator; //! All theories are stored in this common vector /*! This includes TheoryCore and TheoryArith. */ std::vector d_theories; //! Command line flags CLFlags *d_flags; //! User-level view of the scope stack CDO *d_stackLevel; //! True iff we've pushed the stack artificially to avoid polluting context bool d_modelStackPushed; //! Run-time statistics Statistics* d_statistics; //! Next index for user assertion size_t d_nextIdx; //! Structure to hold user assertions indexed by declaration order class UserAssertion { size_t d_idx; Theorem d_thm; //! The theorem of the assertion (a |- a) Theorem d_tcc; //! The proof of its TCC public: //! Default constructor UserAssertion() { } //! Constructor UserAssertion(const Theorem& thm, const Theorem& tcc, size_t idx) : d_idx(idx), d_thm(thm), d_tcc(tcc) { } //! Fetching a Theorem const Theorem& thm() const { return d_thm; } //! Fetching a TCC const Theorem& tcc() const { return d_tcc; } //! Auto-conversion to Theorem operator Theorem() { return d_thm; } //! Comparison for use in std::map, to sort in declaration order friend bool operator<(const UserAssertion& a1, const UserAssertion& a2) { return (a1.d_idx < a2.d_idx); } }; //! Backtracking map of user assertions CDMap* d_userAssertions; //! Backtracking map of assertions when assertion batching is on CDList* d_batchedAssertions; //! Index into batched Assertions CDO* d_batchedAssertionsIdx; //! Result of the last query() /*! Saved for printing assumptions and proofs. Normally it is * Theorem3, but query() on a TCC returns a 2-valued Theorem. */ Theorem3 d_lastQuery; //! Result of the last query(e, true) (for a TCC). Theorem d_lastQueryTCC; //! Closure of the last query(e): |- Gamma => e Theorem3 d_lastClosure; //! Whether to dump a trace (or a translated version) bool d_dump; // Private methods //! Construct the closure "|-_3 Gamma => phi" of thm = "Gamma |-_3 phi" Theorem3 deriveClosure(const Theorem3& thm); //! Recursive assumption graph traversal to find user assumptions /*! * If an assumption has a TCC, traverse the proof of TCC and add its * assumptions to the set recursively. */ void getAssumptionsRec(const Theorem& thm, std::set& assumptions, bool addTCCs); //! Get set of user assertions from the set of assumptions void getAssumptions(const Assumptions& a, std::vector& assumptions); //! Check the tcc Theorem checkTCC(const Expr& tcc); #ifdef _CVC3_DEBUG_MODE //! Print an entry to the dump file: change of scope void dumpTrace(int scope); #endif //! Initialize everything except flags void init(void); //! Destroy everything except flags void destroy(void); public: // Takes the vector of command line flags. VCL(const CLFlags& flags); ~VCL(); // Implementation of vc.h virtual functions CLFlags& getFlags() const { return *d_flags; } void reprocessFlags(); TheoryCore* core(); Type boolType(); Type realType(); Type intType(); Type subrangeType(const Expr& l, const Expr& r); Type subtypeType(const Expr& pred, const Expr& witness); Type tupleType(const Type& type0, const Type& type1); Type tupleType(const Type& type0, const Type& type1, const Type& type2); Type tupleType(const std::vector& types); Type recordType(const std::string& field, const Type& type); Type recordType(const std::string& field0, const Type& type0, const std::string& field1, const Type& type1); Type recordType(const std::string& field0, const Type& type0, const std::string& field1, const Type& type1, const std::string& field2, const Type& type2); Type recordType(const std::vector& fields, const std::vector& types); Type dataType(const std::string& name, const std::string& constructor, const std::vector& selectors, const std::vector& types); Type dataType(const std::string& name, const std::vector& constructors, const std::vector >& selectors, const std::vector >& types); void dataType(const std::vector& names, const std::vector >& constructors, const std::vector > >& selectors, const std::vector > >& types, std::vector& returnTypes); Type arrayType(const Type& typeIndex, const Type& typeData); Type bitvecType(int n); Type funType(const Type& typeDom, const Type& typeRan); Type funType(const std::vector& typeDom, const Type& typeRan); Type createType(const std::string& typeName); Type createType(const std::string& typeName, const Type& def); Type lookupType(const std::string& typeName); ExprManager* getEM() { return d_em; } Expr varExpr(const std::string& name, const Type& type); Expr varExpr(const std::string& name, const Type& type, const Expr& def); Expr lookupVar(const std::string& name, Type* type); Type getType(const Expr& e); Type getBaseType(const Expr& e); Type getBaseType(const Type& e); Expr getTypePred(const Type&t, const Expr& e); Expr stringExpr(const std::string& str); Expr idExpr(const std::string& name); Expr listExpr(const std::vector& kids); Expr listExpr(const Expr& e1); Expr listExpr(const Expr& e1, const Expr& e2); Expr listExpr(const Expr& e1, const Expr& e2, const Expr& e3); Expr listExpr(const std::string& op, const std::vector& kids); Expr listExpr(const std::string& op, const Expr& e1); Expr listExpr(const std::string& op, const Expr& e1, const Expr& e2); Expr listExpr(const std::string& op, const Expr& e1, const Expr& e2, const Expr& e3); void printExpr(const Expr& e); void printExpr(const Expr& e, std::ostream& os); Expr parseExpr(const Expr& e); Type parseType(const Expr& e); Expr importExpr(const Expr& e); Type importType(const Type& t); void cmdsFromString(const std::string& s, InputLanguage lang); Expr exprFromString(const std::string& s); Expr trueExpr(); Expr falseExpr(); Expr notExpr(const Expr& child); Expr andExpr(const Expr& left, const Expr& right); Expr andExpr(const std::vector& children); Expr orExpr(const Expr& left, const Expr& right); Expr orExpr(const std::vector& children); Expr impliesExpr(const Expr& hyp, const Expr& conc); Expr iffExpr(const Expr& left, const Expr& right); Expr eqExpr(const Expr& child0, const Expr& child1); Expr distinctExpr(const std::vector& children); Expr iteExpr(const Expr& ifpart, const Expr& thenpart, const Expr& elsepart); Op createOp(const std::string& name, const Type& type); Op createOp(const std::string& name, const Type& type, const Expr& def); Op lookupOp(const std::string& name, Type* type); Expr funExpr(const Op& op, const Expr& child); Expr funExpr(const Op& op, const Expr& left, const Expr& right); Expr funExpr(const Op& op, const Expr& child0, const Expr& child1, const Expr& child2); Expr funExpr(const Op& op, const std::vector& children); bool addPairToArithOrder(const Expr& smaller, const Expr& bigger); Expr ratExpr(int n, int d); Expr ratExpr(const std::string& n, const std::string& d, int base); Expr ratExpr(const std::string& n, int base); Expr uminusExpr(const Expr& child); Expr plusExpr(const Expr& left, const Expr& right); Expr plusExpr(const std::vector& children); Expr minusExpr(const Expr& left, const Expr& right); Expr multExpr(const Expr& left, const Expr& right); Expr powExpr(const Expr& x, const Expr& n); Expr divideExpr(const Expr& left, const Expr& right); Expr ltExpr(const Expr& left, const Expr& right); Expr leExpr(const Expr& left, const Expr& right); Expr gtExpr(const Expr& left, const Expr& right); Expr geExpr(const Expr& left, const Expr& right); Expr recordExpr(const std::string& field, const Expr& expr); Expr recordExpr(const std::string& field0, const Expr& expr0, const std::string& field1, const Expr& expr1); Expr recordExpr(const std::string& field0, const Expr& expr0, const std::string& field1, const Expr& expr1, const std::string& field2, const Expr& expr2); Expr recordExpr(const std::vector& fields, const std::vector& exprs); Expr recSelectExpr(const Expr& record, const std::string& field); Expr recUpdateExpr(const Expr& record, const std::string& field, const Expr& newValue); Expr readExpr(const Expr& array, const Expr& index); Expr writeExpr(const Expr& array, const Expr& index, const Expr& newValue); Expr newBVConstExpr(const std::string& s, int base); Expr newBVConstExpr(const std::vector& bits); Expr newBVConstExpr(const Rational& r, int len); Expr newConcatExpr(const Expr& t1, const Expr& t2); Expr newConcatExpr(const std::vector& kids); Expr newBVExtractExpr(const Expr& e, int hi, int low); Expr newBVNegExpr(const Expr& t1); Expr newBVAndExpr(const Expr& t1, const Expr& t2); Expr newBVAndExpr(const std::vector& kids); Expr newBVOrExpr(const Expr& t1, const Expr& t2); Expr newBVOrExpr(const std::vector& kids); Expr newBVXorExpr(const Expr& t1, const Expr& t2); Expr newBVXorExpr(const std::vector& kids); Expr newBVXnorExpr(const Expr& t1, const Expr& t2); Expr newBVXnorExpr(const std::vector& kids); Expr newBVNandExpr(const Expr& t1, const Expr& t2); Expr newBVNorExpr(const Expr& t1, const Expr& t2); Expr newBVCompExpr(const Expr& t1, const Expr& t2); Expr newBVLTExpr(const Expr& t1, const Expr& t2); Expr newBVLEExpr(const Expr& t1, const Expr& t2); Expr newBVSLTExpr(const Expr& t1, const Expr& t2); Expr newBVSLEExpr(const Expr& t1, const Expr& t2); Expr newSXExpr(const Expr& t1, int len); Expr newBVUminusExpr(const Expr& t1); Expr newBVSubExpr(const Expr& t1, const Expr& t2); Expr newBVPlusExpr(int numbits, const std::vector& k); Expr newBVPlusExpr(int numbits, const Expr& t1, const Expr& t2); Expr newBVMultExpr(int numbits, const Expr& t1, const Expr& t2); Expr newBVUDivExpr(const Expr& t1, const Expr& t2); Expr newBVURemExpr(const Expr& t1, const Expr& t2); Expr newBVSDivExpr(const Expr& t1, const Expr& t2); Expr newBVSRemExpr(const Expr& t1, const Expr& t2); Expr newBVSModExpr(const Expr& t1, const Expr& t2); Expr newFixedLeftShiftExpr(const Expr& t1, int r); Expr newFixedConstWidthLeftShiftExpr(const Expr& t1, int r); Expr newFixedRightShiftExpr(const Expr& t1, int r); Expr newBVSHL(const Expr& t1, const Expr& t2); Expr newBVLSHR(const Expr& t1, const Expr& t2); Expr newBVASHR(const Expr& t1, const Expr& t2); Rational computeBVConst(const Expr& e); Expr tupleExpr(const std::vector& exprs); Expr tupleSelectExpr(const Expr& tuple, int index); Expr tupleUpdateExpr(const Expr& tuple, int index, const Expr& newValue); Expr datatypeConsExpr(const std::string& constructor, const std::vector& args); Expr datatypeSelExpr(const std::string& selector, const Expr& arg); Expr datatypeTestExpr(const std::string& constructor, const Expr& arg); Expr boundVarExpr(const std::string& name, const std::string& uid, const Type& type); Expr forallExpr(const std::vector& vars, const Expr& body); Expr forallExpr(const std::vector& vars, const Expr& body, const Expr& trigger); Expr forallExpr(const std::vector& vars, const Expr& body, const std::vector& triggers); Expr forallExpr(const std::vector& vars, const Expr& body, const std::vector >& triggers); void setTriggers(const Expr& e, const std::vector >& triggers); void setTriggers(const Expr& e, const std::vector& triggers); void setTrigger(const Expr& e, const Expr& trigger); void setMultiTrigger(const Expr& e, const std::vector& multiTrigger); Expr existsExpr(const std::vector& vars, const Expr& body); Op lambdaExpr(const std::vector& vars, const Expr& body); Op transClosure(const Op& op); Expr simulateExpr(const Expr& f, const Expr& s0, const std::vector& inputs, const Expr& n); void setResourceLimit(unsigned limit); void setTimeLimit(unsigned limit); void assertFormula(const Expr& e); void registerAtom(const Expr& e); Expr getImpliedLiteral(); Expr simplify(const Expr& e); Theorem simplifyThm(const Expr& e); QueryResult query(const Expr& e); QueryResult checkUnsat(const Expr& e); QueryResult checkContinue(); QueryResult restart(const Expr& e); void returnFromCheck(); void getUserAssumptions(std::vector& assumptions); void getInternalAssumptions(std::vector& assumptions); void getAssumptions(std::vector& assumptions); void getAssumptionsUsed(std::vector& assumptions); Expr getProofQuery(); void getCounterExample(std::vector& assumptions, bool inOrder); void getConcreteModel(ExprMap & m); QueryResult tryModelGeneration(); FormulaValue value(const Expr& e); bool inconsistent(std::vector& assumptions); bool inconsistent(); bool incomplete(); bool incomplete(std::vector& reasons); Proof getProof(); Expr getAssignment(); Expr getValue(Expr e); Expr getTCC(); void getAssumptionsTCC(std::vector& assumptions); Proof getProofTCC(); Expr getClosure(); Proof getProofClosure(); int stackLevel(); void push(); void pop(); void popto(int stackLevel); int scopeLevel(); void pushScope(); void popScope(); void poptoScope(int scopeLevel); Context* getCurrentContext(); void reset(); void logAnnotation(const Expr& annot); void loadFile(const std::string& fileName, InputLanguage lang = PRESENTATION_LANG, bool interactive = false, bool calledFromParser = false); void loadFile(std::istream& is, InputLanguage lang = PRESENTATION_LANG, bool interactive = false); Statistics& getStatistics() { return *d_statistics; } void printStatistics() { std::cout << *d_statistics << std::endl; } unsigned long getMemory(int verbosity = 0); }; } #endif cvc3-2.4.1/src/include/notifylist.h0000664000175400017540000000217010656155010017044 0ustar mdetersmdeters/*****************************************************************************/ /*! * \file notifylist.h * * Author: Clark Barrett * * Created: Mon Jan 20 13:52:19 2003 * *
* * License to use, copy, modify, sell and/or distribute this software * and its documentation for any purpose is hereby granted without * royalty, subject to the terms and conditions defined in the \ref * LICENSE file provided with this distribution. * *
* */ /*****************************************************************************/ #ifndef _cvc3__include__notifylist_h_ #define _cvc3__include__notifylist_h_ #include "expr.h" #include "cdlist.h" namespace CVC3 { class Theory; class NotifyList { CDList d_tlist; CDList d_elist; public: NotifyList(Context* c) : d_tlist(c), d_elist(c) { IF_DEBUG(d_elist.setName("CDList[NotifyList]");) } unsigned size() const { return d_tlist.size(); } void add(Theory* t, const Expr& e) { d_tlist.push_back(t); d_elist.push_back(e); } Theory* getTheory(int i) const { return d_tlist[i]; } Expr getExpr(int i) const { return d_elist[i]; } }; } #endif cvc3-2.4.1/src/include/theory_arith3.h0000664000175400017540000003036211277111607017434 0ustar mdetersmdeters/*****************************************************************************/ /*! * \file theory_arith3.h * * Author: Clark Barrett * * Created: Thu Jun 14 13:22:11 2007 * *
* * License to use, copy, modify, sell and/or distribute this software * and its documentation for any purpose is hereby granted without * royalty, subject to the terms and conditions defined in the \ref * LICENSE file provided with this distribution. * *
* */ /*****************************************************************************/ #ifndef _cvc3__include__theory_arith3_h_ #define _cvc3__include__theory_arith3_h_ #include "theory_arith.h" namespace CVC3 { class TheoryArith3 :public TheoryArith { CDList d_diseq; // For concrete model generation CDO d_diseqIdx; // Index to the next unprocessed disequality ArithProofRules* d_rules; CDO d_inModelCreation; //! Data class for the strongest free constant in separation inqualities class FreeConst { private: Rational d_r; bool d_strict; public: FreeConst() { } FreeConst(const Rational& r, bool strict): d_r(r), d_strict(strict) { } const Rational& getConst() const { return d_r; } bool strict() const { return d_strict; } }; //! Printing friend std::ostream& operator<<(std::ostream& os, const FreeConst& fc); //! Private class for an inequality in the Fourier-Motzkin database class Ineq { private: Theorem d_ineq; //!< The inequality bool d_rhs; //!< Var is isolated on the RHS const FreeConst* d_const; //!< The max/min const for subsumption check //! Default constructor is disabled Ineq() { } public: //! Initial constructor. 'r' is taken from the subsumption database. Ineq(const Theorem& ineq, bool varOnRHS, const FreeConst& c): d_ineq(ineq), d_rhs(varOnRHS), d_const(&c) { } //! Get the inequality const Theorem& ineq() const { return d_ineq; } //! Get the max/min constant const FreeConst& getConst() const { return *d_const; } //! Flag whether var is isolated on the RHS bool varOnRHS() const { return d_rhs; } //! Flag whether var is isolated on the LHS bool varOnLHS() const { return !d_rhs; } //! Auto-cast to Theorem operator Theorem() const { return d_ineq; } }; //! Printing friend std::ostream& operator<<(std::ostream& os, const Ineq& ineq); //! Database of inequalities with a variable isolated on the right ExprMap *> d_inequalitiesRightDB; //! Database of inequalities with a variable isolated on the left ExprMap *> d_inequalitiesLeftDB; //! Mapping of inequalities to the largest/smallest free constant /*! The Expr is the original inequality with the free constant * removed and inequality converted to non-strict (for indexing * purposes). I.e. ax, the smallest (largest for c+t d_freeConstDB; // Input buffer to store the incoming inequalities CDList d_buffer; //!< Buffer of input inequalities CDO d_bufferIdx; //!< Buffer index of the next unprocessed inequality const int* d_bufferThres; //!< Threshold when the buffer must be processed // Statistics for the variables /*! @brief Mapping of a variable to the number of inequalities where the variable would be isolated on the right */ CDMap d_countRight; /*! @brief Mapping of a variable to the number of inequalities where the variable would be isolated on the left */ CDMap d_countLeft; //! Set of shared terms (for counterexample generation) CDMap d_sharedTerms; //! Set of shared integer variables (i-leaves) CDMap d_sharedVars; //Directed Acyclic Graph representing partial variable ordering for //variable projection over inequalities. class VarOrderGraph { ExprMap > d_edges; ExprMap d_cache; bool dfs(const Expr& e1, const Expr& e2); public: void addEdge(const Expr& e1, const Expr& e2); //returns true if e1 < e2, false otherwise. bool lessThan(const Expr& e1, const Expr& e2); //selects those variables which are largest and incomparable among //v1 and puts it into v2 void selectLargest(const std::vector& v1, std::vector& v2); //selects those variables which are smallest and incomparable among //v1, removes them from v1 and puts them into v2. void selectSmallest( std::vector& v1, std::vector& v2); }; VarOrderGraph d_graph; // Private methods //! Check the term t for integrality. /*! \return a theorem of IS_INTEGER(t) or Null. */ Theorem isIntegerThm(const Expr& e); //! A helper method for isIntegerThm() /*! Check if IS_INTEGER(e) is easily derivable from the given 'thm' */ Theorem isIntegerDerive(const Expr& isIntE, const Theorem& thm); //! Extract the free constant from an inequality const Rational& freeConstIneq(const Expr& ineq, bool varOnRHS); //! Update the free constant subsumption database with new inequality /*! \return a reference to the max/min constant. * * Also, sets 'subsumed' argument to true if the inequality is * subsumed by an existing inequality. */ const FreeConst& updateSubsumptionDB(const Expr& ineq, bool varOnRHS, bool& subsumed); //! Check if the kids of e are fully simplified and canonized (for debugging) bool kidsCanonical(const Expr& e); //! Canonize the expression e, assuming all children are canonical Theorem canon(const Expr& e); /*! @brief Canonize and reduce e w.r.t. union-find database; assume * all children are canonical */ Theorem canonSimplify(const Expr& e); /*! @brief Composition of canonSimplify(const Expr&) by * transitivity: take e0 = e1, canonize and simplify e1 to e2, * return e0 = e2. */ Theorem canonSimplify(const Theorem& thm) { return transitivityRule(thm, canonSimplify(thm.getRHS())); } //! Canonize predicate (x = y, x < y, etc.) Theorem canonPred(const Theorem& thm); //! Canonize predicate like canonPred except that the input theorem //! is an equivalent transformation. Theorem canonPredEquiv(const Theorem& thm); //! Solve an equation and return an equivalent Theorem in the solved form Theorem doSolve(const Theorem& e); //! takes in a conjunction equivalence Thm and canonizes it. Theorem canonConjunctionEquiv(const Theorem& thm); //! picks the monomial with the smallest abs(coeff) from the input //integer equation. bool pickIntEqMonomial(const Expr& right, Expr& isolated, bool& nonlin); //! processes equalities with 1 or more vars of type REAL Theorem processRealEq(const Theorem& eqn); //! processes equalities whose vars are all of type INT Theorem processIntEq(const Theorem& eqn); //! One step of INT equality processing (aux. method for processIntEq()) Theorem processSimpleIntEq(const Theorem& eqn); //! Process inequalities in the buffer void processBuffer(); //! Take an inequality and isolate a variable Theorem isolateVariable(const Theorem& inputThm, bool& e1); //! Update the statistics counters for the variable with a coeff. c void updateStats(const Rational& c, const Expr& var); //! Update the statistics counters for the monomial void updateStats(const Expr& monomial); //! Add an inequality to the input buffer. See also d_buffer void addToBuffer(const Theorem& thm); /*! @brief Given a canonized term, compute a factor to make all coefficients integer and relatively prime */ Expr computeNormalFactor(const Expr& rhs); //! Normalize an equation (make all coefficients rel. prime integers) Theorem normalize(const Expr& e); //! Normalize an equation (make all coefficients rel. prime integers) /*! accepts a rewrite theorem over eqn|ineqn and normalizes it * and returns a theorem to that effect. */ Theorem normalize(const Theorem& thm); Expr pickMonomial(const Expr& right); void getFactors(const Expr& e, std::set& factors); public: // ArithTheoremProducer needs this function, so make it public //! Separate monomial e = c*p1*...*pn into c and 1*p1*...*pn void separateMonomial(const Expr& e, Expr& c, Expr& var); //! Check the term t for integrality (return bool) bool isInteger(const Expr& e) { return !(isIntegerThm(e).isNull()); } private: bool lessThanVar(const Expr& isolatedVar, const Expr& var2); //! Check if the term expression is "stale" bool isStale(const Expr& e); //! Check if the inequality is "stale" or subsumed bool isStale(const Ineq& ineq); void projectInequalities(const Theorem& theInequality,bool isolatedVarOnRHS); void assignVariables(std::vector&v); void findRationalBound(const Expr& varSide, const Expr& ratSide, const Expr& var, Rational &r); bool findBounds(const Expr& e, Rational& lub, Rational& glb); Theorem normalizeProjectIneqs(const Theorem& ineqThm1, const Theorem& ineqThm2); //! Take a system of equations and turn it into a solved form Theorem solvedForm(const std::vector& solvedEqs); /*! @brief Substitute all vars in term 't' according to the * substitution 'subst' and canonize the result. */ Theorem substAndCanonize(const Expr& t, ExprMap& subst); /*! @brief Substitute all vars in the RHS of the equation 'eq' of * the form (x = t) according to the substitution 'subst', and * canonize the result. */ Theorem substAndCanonize(const Theorem& eq, ExprMap& subst); //! Traverse 'e' and push all the i-leaves into 'vars' vector void collectVars(const Expr& e, std::vector& vars, std::set& cache); /*! @brief Check if alpha <= ax & bx <= beta is a finite interval * for integer var 'x', and assert the corresponding constraint */ void processFiniteInterval(const Theorem& alphaLEax, const Theorem& bxLEbeta); //! For an integer var 'x', find and process all constraints A <= ax <= A+c void processFiniteIntervals(const Expr& x); //! Recursive setup for isolated inequalities (and other new expressions) void setupRec(const Expr& e); public: TheoryArith3(TheoryCore* core); ~TheoryArith3(); // Trusted method that creates the proof rules class (used in constructor). // Implemented in arith_theorem_producer.cpp ArithProofRules* createProofRules3(); // Theory interface void addSharedTerm(const Expr& e); void assertFact(const Theorem& e); void refineCounterExample(); void computeModelBasic(const std::vector& v); void computeModel(const Expr& e, std::vector& vars); void checkSat(bool fullEffort); Theorem rewrite(const Expr& e); void setup(const Expr& e); void update(const Theorem& e, const Expr& d); Theorem solve(const Theorem& e); void checkAssertEqInvariant(const Theorem& e); void checkType(const Expr& e); Cardinality finiteTypeInfo(Expr& e, Unsigned& n, bool enumerate, bool computeSize); void computeType(const Expr& e); Type computeBaseType(const Type& t); void computeModelTerm(const Expr& e, std::vector& v); Expr computeTypePred(const Type& t, const Expr& e); Expr computeTCC(const Expr& e); ExprStream& print(ExprStream& os, const Expr& e); Expr parseExprOp(const Expr& e); private: /** Map from variables to the maximal (by absolute value) of one of it's coefficients */ CDMap maxCoefficientLeft; CDMap maxCoefficientRight; /** Map from variables to the fixed value of one of it's coefficients */ CDMap fixedMaxCoefficient; /** * Returns the current maximal coefficient of the variable. * * @param var the variable. */ Rational currentMaxCoefficient(Expr var); /** * Fixes the current max coefficient to be used in the ordering. If the maximal coefficient * changes in the future, it will not be used in the ordering. * * @param variable the variable * @param max the value to set it to */ void fixCurrentMaxCoefficient(Expr variable, Rational max); /** * Among given input variables, select the smallest ones with respect to the coefficients. */ void selectSmallestByCoefficient(std::vector input, std::vector& output); }; } #endif cvc3-2.4.1/src/include/pretty_printer.h0000664000175400017540000000220410466450542017737 0ustar mdetersmdeters/*****************************************************************************/ /*! * \file pretty_printer.h * * Author: Sergey Berezin * * Created: Mon Jun 16 12:31:08 2003 * *
* * License to use, copy, modify, sell and/or distribute this software * and its documentation for any purpose is hereby granted without * royalty, subject to the terms and conditions defined in the \ref * LICENSE file provided with this distribution. * *
* * Defines an abstract class PrettyPrinter which connects the * theory-specific pretty-printers with ExprManager. * */ /*****************************************************************************/ #ifndef _cvc3__pretty_printer_h_ #define _cvc3__pretty_printer_h_ namespace CVC3 { class Expr; class ExprStream; //! Abstract API to a pretty-printer for Expr /*! \ingroup PrettyPrinting */ class PrettyPrinter { public: //! Default constructor PrettyPrinter() { } //! Virtual destructor virtual ~PrettyPrinter() { } //! The pretty-printer which subclasses must implement virtual ExprStream& print(ExprStream& os, const Expr& e) = 0; }; } #endif cvc3-2.4.1/src/include/cdflags.h0000664000175400017540000000422511131357435016252 0ustar mdetersmdeters/*****************************************************************************/ /*! *\file cdflags.h *\brief Context Dependent Vector of Flags * * Author: Clark Barrett * * Created: Thu Jan 26 16:37:46 2006 * *
* * License to use, copy, modify, sell and/or distribute this software * and its documentation for any purpose is hereby granted without * royalty, subject to the terms and conditions defined in the \ref * LICENSE file provided with this distribution. * *
* */ /*****************************************************************************/ #ifndef _cvc3__include__cdflags_h_ #define _cvc3__include__cdflags_h_ #include "context.h" #include "os.h" namespace CVC3 { /////////////////////////////////////////////////////////////////////////////// // // // Class: CDFlags (Context Dependent Vector of Flags) // // Author: Clark Barrett // // Created: Thu Jan 26 16:37:46 2006 // // // /////////////////////////////////////////////////////////////////////////////// class CVC_DLL CDFlags :public ContextObj { unsigned d_flags; virtual ContextObj* makeCopy(ContextMemoryManager* cmm) { return new(cmm) CDFlags(*this); } virtual void restoreData(ContextObj* data) { d_flags = ((CDFlags*)data)->d_flags; } virtual void setNull(void) { FatalAssert(false, "Should never be called"); } void update(unsigned mask, int scope, bool setMask); // Disable copy constructor and operator= // If you need these, use smartcdo instead CDFlags(const CDFlags& cdflags): ContextObj(cdflags), d_flags(cdflags.d_flags) { } CDFlags& operator=(const CDFlags& cdflags) { return *this; } public: CDFlags(Context* context) : ContextObj(context), d_flags(0) { IF_DEBUG(setName("CDFlags");) } ~CDFlags() {} void set(unsigned mask, int scope=-1) { update(mask, scope, true); } void clear(unsigned mask, int scope=-1) { update(mask, scope, false); } bool get(unsigned mask) const { return (d_flags & mask) != 0; } }; } #endif cvc3-2.4.1/src/include/expr_stream.h0000664000175400017540000002700011155273722017176 0ustar mdetersmdeters/*****************************************************************************/ /*! * \file expr_stream.h * * Author: Sergey Berezin * * Created: Mon Jun 16 10:59:18 2003 * *
* * License to use, copy, modify, sell and/or distribute this software * and its documentation for any purpose is hereby granted without * royalty, subject to the terms and conditions defined in the \ref * LICENSE file provided with this distribution. * *
* * Declaration of class ExprStream, an output stream to pretty-print * Expr in various nice output formats (presentation/internal/other * languages, outo-indentation, bounded depth printing, DAG-ified * printing, etc, etc...). * * This stream is most useful for the decision procedure designer when * writing a pretty-printer (Theory::print() method). ExprStream * carries information about the current output language, and all the * indentation and depth pretty-printing is done automagically by the * operator<<(). * */ /*****************************************************************************/ #ifndef _cvc3__expr_stream_h_ #define _cvc3__expr_stream_h_ #include "os.h" #include "expr.h" namespace CVC3 { class ExprStream; } namespace std { CVC3::ExprStream& endl(CVC3::ExprStream& os); } namespace CVC3 { /*! \defgroup PrettyPrinting Pretty-printing related classes and methods * \ingroup BuildingBlocks * If you are writing a theory-specific pretty-printer, please read * carefully all the documentation about class ExprStream and its * manipulators. * * @{ */ //! Pretty-printing output stream for Expr. READ THE DOCS BEFORE USING! /*! Use this class as a standard ostream for Expr, string, int, Rational, manipulators like endl, and it will do the expected thing. Additionally, it has methods to access the current printing flags. In order for the indentation engine to work correctly, you must use the manipulators properly. Never use "\\n" in a string; always use endl manipulator, which knows about indentation and will do the right thing. Always assume that the object you are printing may start printing on a new line from the current indentation position. Therefore, no string should start with an empty space (otherwise parts of your expression will be mis-indented). If you need a white space separator, or an operator surrounded by spaces, like os << " = ", use os << space << "= " instead. The 'space' manipulator adds one white space only if it's not at the beginning of a newly indented line. Think of it as a logical white-space separator with intelligent behavior, rather than a stupid hard space like " ". Indentation can be set to the current position with os << push, and restored to the previous with os << pop. You do not need to restore it before exiting your print function, ExprStream knows how to restore it automatically. For example, you can write: os << "(" << push << e[0] << space << "+ " << e[1] << push << ")"; to print (PLUS a b) as "(a + b)". Notice the second 'push' before the closing paren. This is intentional (not a typo), and prevents the paren ")" from jumping to the next line by itself. ExprStream will not go to the next line if the current position is too close to the indentation, since this will not give the expression a better look. The indentation level is not restored in this example, and that is fine, ExprStream will take care of that. For complex expressions like IF-THEN-ELSE, you may want to remember the indentation to which you want to return later. You can save the current indentation position with os << popSave, and restore it later with os << pushRestore. These manipulators are similar to pop and push, but 'pushRestore' will set the new indentation level to the one popped by the last popSave instead of the current one. At the moment, there is only one register for saving an indentation position, so multiple pushRestore will not work as you would expect (maybe this should be fixed?..). For concrete examples, see TheoryCore::print() and TheoryArith::print(). */ class CVC_DLL ExprStream { private: ExprManager* d_em; //!< The ExprManager to use std::ostream* d_os; //!< The ostream to print into int d_depth; //!< Printing only upto this depth; -1 == unlimited int d_currDepth; //!< Current depth of Expr InputLanguage d_lang; //!< Output language bool d_indent; //!< Whether to print with indentations int d_col; //!< Current column in a line int d_lineWidth; //!< Try to format/indent for this line width //! Indentation stack /*! The user code can set the indentation to the current d_col by pushing the new value on the stack. This value is popped automatically when returning from the recursive call. */ std::vector d_indentStack; //! The lowest position of the indent stack the user can pop size_t d_indentLast; //! Indentation register for popSave() and pushRestore() int d_indentReg; //! Whether it is a beginning of line (for eating up extra spaces) bool d_beginningOfLine; bool d_dag; //!< Print Expr as a DAG //! Mapping subexpressions to names for DAG printing ExprMap d_dagMap; //! New subexpressions not yet printed in a LET header ExprMap d_newDagMap; //! Stack of shared subexpressions (same as in d_dagMap) std::vector d_dagStack; //! Stack of pointers to d_dagStack for pushing/popping shared subexprs std::vector d_dagPtr; //! The smallest size of d_dagPtr the user can `popDag' size_t d_lastDagSize; //! Flag whether the dagMap is already built bool d_dagBuilt; //! Counter for generating unique LET var names int d_idCounter; //! nodag() manipulator has been applied bool d_nodag; //! Generating unique names in DAG expr std::string newName(); //! Traverse the Expr, collect shared subexpressions in d_dagMap void collectShared(const Expr& e, ExprMap& cache); //! Wrap e into the top-level LET ... IN header from the dagMap Expr addLetHeader(const Expr& e); public: //! Default constructor ExprStream(ExprManager *em); //! Destructor ~ExprStream() { } //! Set a new output stream /*! Note, that there is no method to access the ostream. This is done on purpose, so that DP designers had to use only ExprStream to print everything in their versions of Theory::print(). */ void os(std::ostream& os) { d_os = &os; } //! Get the current output language InputLanguage lang() const { return d_lang; } //! Set the output language void lang(InputLanguage l) { d_lang = l; } //! Get the printing depth int depth() const { return d_depth; } //! Set the printing depth void depth(int d) { d_depth = d; } //! Set the line width void lineWidth(int w) { d_lineWidth = w; } //! Set the DAG flag (return previous value) bool dagFlag(bool flag = true) { bool old = d_dag; d_dag = flag; return old; } //! Set the indentation to the current column /*! The value will be restorted automatically after the DP print() function returns */ void pushIndent() { d_indentStack.push_back(d_col); } //! Set the indentation to the given absolute position /*! The value will be restorted automatically after the DP print() function returns */ void pushIndent(int pos) { d_indentStack.push_back(pos); } //! Restore the indentation (user cannot pop more than pushed) void popIndent(); //! Reset indentation to what it was at this level void resetIndent(); //! Return the current column position int column() const { return d_col; } //! Recompute shared subexpression for the next Expr void pushDag(); //! Delete shared subexpressions previously added with pushdag void popDag(); //! Reset the DAG to what it was at this level void resetDag(); // The printing action //! Use manipulators which are functions over ExprStream& friend ExprStream& operator<<(ExprStream& os, ExprStream& (*manip)(ExprStream&)); //! Print Expr friend ExprStream& operator<<(ExprStream& os, const Expr& e); //! Print Type friend ExprStream& operator<<(ExprStream& os, const Type& t); //! Print string friend ExprStream& operator<<(ExprStream& os, const std::string& s); //! Print char* string friend ExprStream& operator<<(ExprStream& os, const char* s); //! Print Rational friend ExprStream& operator<<(ExprStream& os, const Rational& r); //! Print int friend ExprStream& operator<<(ExprStream& os, int i); //! Set the indentation to the current position friend ExprStream& push(ExprStream& os); //! Restore the indentation to the previous position friend ExprStream& pop(ExprStream& os); //! Remember the current indentation and pop to the previous position friend ExprStream& popSave(ExprStream& os); //! Set the indentation to the position saved by popSave() friend ExprStream& pushRestore(ExprStream& os); //! Reset the indentation to the default at this level friend ExprStream& reset(ExprStream& os); //! Insert a single white space separator /*! It is preferred to use 'space' rather than a string of spaces (" ") because ExprStream needs to delete extra white space if it decides to end the line. If you use strings for spaces, you'll mess up the indentation. */ friend ExprStream& space(ExprStream& os); //! Print the next top-level expression node without DAG-ifying /*! * DAG-printing will resume for the children of the node. This is * useful when printing definitions in the header of a DAGified * LET expressions: defs have names, but must be printed expanded. */ friend ExprStream& nodag(ExprStream& os); //! Recompute shared subexpression for the next Expr /*! * For some constructs with bound variables (notably, * quantifiers), shared subexpressions are not computed, because * they cannot be defined outside the scope of bound variables. * If this manipulator is applied before an expression within the * scope of bound vars, these internal subexpressions will then be * computed. */ friend ExprStream& pushdag(ExprStream& os); //! Delete shared subexpressions previously added with pushdag /*! * Similar to push/pop, shared subexpressions are automatically * deleted upon a return from a recursive call, so popdag is not * necessary after a pushdag in theory-specific print() functions. * Also, you cannot pop more than you pushed an the current * recursion level. */ friend ExprStream& popdag(ExprStream& os); //! Print the end-of-line /*! The new line will not necessarily start at column 0 because of indentation. The name endl will be introduced in namespace std, otherwise CVC3::endl would overshadow std::endl, wreaking havoc... */ friend ExprStream& std::endl(ExprStream& os); }; // end of class ExprStream /*! @} */ // End of group PrettyPrinting ExprStream& push(ExprStream& os); ExprStream& pop(ExprStream& os); ExprStream& popSave(ExprStream& os); ExprStream& pushRestore(ExprStream& os); ExprStream& reset(ExprStream& os); ExprStream& space(ExprStream& os); ExprStream& nodag(ExprStream& os); ExprStream& pushdag(ExprStream& os); ExprStream& popdag(ExprStream& os); } // End of namespace CVC3 /* namespace std { CVC3::ExprStream& endl(CVC3::ExprStream& os); } */ #endif cvc3-2.4.1/src/include/search.h0000664000175400017540000001554211345602014016111 0ustar mdetersmdeters/*****************************************************************************/ /*! * \file search.h * \brief Abstract API to the proof search engine * * Author: Clark Barrett, Vijay Ganesh (Clausal Normal Form Converter) * * Created: Fri Jan 17 13:35:03 2003 * *
* * License to use, copy, modify, sell and/or distribute this software * and its documentation for any purpose is hereby granted without * royalty, subject to the terms and conditions defined in the \ref * LICENSE file provided with this distribution. * *
* */ /*****************************************************************************/ #ifndef _cvc3__include__search_h_ #define _cvc3__include__search_h_ #include #include "queryresult.h" #include "cdo.h" #include "formula_value.h" namespace CVC3 { class SearchEngineRules; class Theorem; class Expr; class Proof; class TheoryCore; class CommonProofRules; template class ExprMap; /*! \defgroup SE Search Engine * \ingroup VC * The search engine includes Boolean reasoning and coordinates with theory * reasoning. It consists of a generic abstract API (class SearchEngine) and * subclasses implementing concrete instances of search engines. */ //! API to to a generic proof search engine /*! \ingroup SE */ class SearchEngine { protected: /*! \addtogroup SE * @{ */ //! Access to theory reasoning TheoryCore* d_core; //! Common proof rules CommonProofRules* d_commonRules; //! Proof rules for the search engine SearchEngineRules* d_rules; //! Create the trusted component /*! This function is defined in search_theorem_producer.cpp */ SearchEngineRules* createRules(); // hack for printing original assumptions in LFSC proofs by liana SearchEngineRules* createRules(SearchEngine* s_eng); public: //! Constructor SearchEngine(TheoryCore* core); //! Destructor virtual ~SearchEngine(); //! Name of this search engine virtual const std::string& getName() = 0; //! Accessor for common rules CommonProofRules* getCommonRules() { return d_commonRules; } //! Accessor for TheoryCore TheoryCore* theoryCore() { return d_core; } //! Register an atomic formula of interest. /*! Registered atoms are tracked by the decision procedures. If one of them is deduced to be true or false, it is added to a list of implied literals. Implied literals can be retrieved with the getImpliedLiteral function */ virtual void registerAtom(const Expr& e) = 0; //! Return next literal implied by last assertion. Null Expr if none. /*! Returned literals are either registered atomic formulas or their negation */ virtual Theorem getImpliedLiteral() = 0; //! Push a checkpoint virtual void push() = 0; //! Restore last checkpoint virtual void pop() = 0; //! Checks the validity of a formula in the current context /*! If the query is valid, it returns VALID, the result parameter contains * the corresponding theorem, and the scope and context are the same * as when called. If it returns INVALID, the context will be one which * falsifies the query. If it returns UNKNOWN, the context will falsify the * query, but the context may be inconsistent. Finally, if it returns * ABORT, the context will be one which satisfies as much as * possible. * \param e the formula to check. * \param result the resulting theorem, if the formula is valid. */ virtual QueryResult checkValid(const Expr& e, Theorem& result) = 0; //! Reruns last check with e as an additional assumption /*! This method should only be called after a query which is invalid. * \param e the additional assumption * \param result the resulting theorem, if the query is valid. */ virtual QueryResult restart(const Expr& e, Theorem& result) = 0; //! Returns to context immediately before last call to checkValid /*! This method should only be called after a query which returns something * other than VALID. */ virtual void returnFromCheck() = 0; //! Returns the result of the most recent valid theorem /*! Returns Null Theorem if last call was not valid */ virtual Theorem lastThm() = 0; /*! @brief Generate and add an assumption to the set of * assumptions in the current context. */ /*! By default, the assumption is added at the current scope. The default * can be overridden by specifying the scope parameter. */ virtual Theorem newUserAssumption(const Expr& e) = 0; //! Get all user assumptions made in this and all previous contexts. /*! User assumptions are created either by calls to newUserAssumption or * a call to checkValid. In the latter case, the negated query is added * as an assumption. * \param assumptions should be empty on entry. */ virtual void getUserAssumptions(std::vector& assumptions) = 0; //! Get assumptions made internally in this and all previous contexts. /*! Internal assumptions are literals assumed by the sat solver. * \param assumptions should be empty on entry. */ virtual void getInternalAssumptions(std::vector& assumptions) = 0; //! Get all assumptions made in this and all previous contexts. /*! \param assumptions should be an empty vector which will be filled \ with the assumptions */ virtual void getAssumptions(std::vector& assumptions) = 0; //! Check if the formula has already been assumed previously virtual bool isAssumption(const Expr& e) = 0; //! Will return the set of assertions which make the queried formula false. /*! This method should only be called after an query which returns INVALID. * It will try to return the simplest possible set of assertions which are * sufficient to make the queried expression false. * \param assertions should be empty on entry. * \param inOrder if true, returns the assertions in the order they were * asserted. This is slightly more expensive than inOrder = false. */ virtual void getCounterExample(std::vector& assertions, bool inOrder = true) = 0; //! Returns the proof term for the last proven query /*! It should be called only after a query which returns VALID. * In any other case, it returns Null. */ virtual Proof getProof() = 0; /*! @brief Build a concrete Model (assign values to variables), * should only be called after a query which returns INVALID. */ void getConcreteModel(ExprMap& m); /*! @brief Try to build a concrete Model (assign values to variables), * should only be called after a query which returns UNKNOWN. * Returns a theorem if inconsistent */ bool tryModelGeneration(Theorem& thm); //:ALEX: returns the current truth value of a formula // returns CVC3::UNKNOWN_VAL if e is not associated // with a boolean variable in the SAT module, // i.e. if its value can not determined without search. virtual FormulaValue getValue(const CVC3::Expr& e) = 0; /* @} */ // end of group SE }; } #endif cvc3-2.4.1/src/include/clause.h0000664000175400017540000002374110656155007016131 0ustar mdetersmdeters/*****************************************************************************/ /*! * \file clause.h * * Author: Sergey Berezin * * Created: Fri Mar 7 16:03:38 2003 * *
* * License to use, copy, modify, sell and/or distribute this software * and its documentation for any purpose is hereby granted without * royalty, subject to the terms and conditions defined in the \ref * LICENSE file provided with this distribution. * *
* * Class to represent a clause, which is a disjunction of formulas * which are literals for conflict clauses, and possibly more complex * formulas for the clauses derived from the user-asserted formulas. * * class Clause is implemented as a smart pointer to ClauseValue, so * it can be freely copied and assigned with low overhead (like * Theorem or Expr). */ /*****************************************************************************/ // Include it before ifndef, since it includes this file recursively #ifndef DOXYGEN #include "variable.h" #endif #ifndef _cvc3__include__clause_h_ #define _cvc3__include__clause_h_ namespace CVC3 { class Clause; class ClauseOwner; class TheoryCore; class ClauseValue { friend class Clause; private: //! Ref. counter int d_refcount; //! Ref. counter of ClauseOwner classes holding it int d_refcountOwner; // The original clause (disjunction of literals) Theorem d_thm; // Scope where the clause is valid int d_scope; // Theorems l_i <=> l'_i for each literal l_i // FIXME: more efficient implementation for fixed arrays of CDOs std::vector d_literals; // Disallow copy constructor and assignment (make private) ClauseValue(const ClauseValue& c); // Undefined (since it cannot be used) ClauseValue& operator=(const ClauseValue& c) { return *this; } // Pointers to watched literals (Watch Pointers). They are not // backtrackable. size_t d_wp[2]; // Direction flags for the watch pointers (1 or -1) // FIXME: should we use one bit of d_wp{1,2} instead? (efficiency // vs. space) int d_dir[2]; // A flag indicating that the clause is shown satisfiable CDO d_sat; // Marks the clause as deleted bool d_deleted; // Creation file and line number (for debugging) IF_DEBUG(std::string d_file; int d_line;) // Constructor: takes the main clause theorem which must be a // disjunction of literals and have no assumptions. ClauseValue(TheoryCore* core, VariableManager* vm, const Theorem& clause, int scope); public: // Destructor ~ClauseValue(); }; // end of class ClauseValue //! A class representing a CNF clause (a smart pointer) class Clause { private: friend class ClauseOwner; //! The only value member ClauseValue* d_clause; //! Export owner refcounting to ClauseOwner int& countOwner() { DebugAssert(d_clause != NULL, ""); return d_clause->d_refcountOwner; } public: Clause(): d_clause(NULL) { } // Constructors Clause(TheoryCore* core, VariableManager* vm, const Theorem& clause, int scope, const std::string& file = "", int line = 0) : d_clause(new ClauseValue(core, vm, clause, scope)) { d_clause->d_refcount++; IF_DEBUG(d_clause->d_file = file; d_clause->d_line=line;) } // Copy constructor Clause(const Clause& c): d_clause(c.d_clause) { if(d_clause != NULL) d_clause->d_refcount++; } // Destructor ~Clause(); // Assignment operator Clause& operator=(const Clause& c); bool isNull() const { return d_clause == NULL; } // Other public methods size_t size() const { return (d_clause == NULL)? 0 : d_clause->d_literals.size(); } // Get the theorem representing the entire clause const Theorem& getTheorem() const { DebugAssert(!isNull(), "Clause::getTheorem(): Null Clause"); return d_clause->d_thm; } // Get the scope where the clause is valid int getScope() const { if(isNull()) return 0; else return d_clause->d_scope; } // Get the current value of the i-th literal const Literal& getLiteral(size_t i) const { DebugAssert(!isNull(), "Clause::getLiteral(): Null Clause"); DebugAssert(i < size(), "Clause::getLiteral(" + int2string(i) + "): i >= size = " + int2string(size())); return d_clause->d_literals[i]; } // Get the current value of the i-th literal const Literal& operator[](size_t i) const { return getLiteral(i); } // Get the reference to the vector of literals, for fast access const std::vector& getLiterals() const { DebugAssert(!isNull(), "Clause::getLiterals(): Null Clause"); return d_clause->d_literals; } // Get the values of watch pointers size_t wp(int i) const { DebugAssert(!isNull(), "Clause::wp(i): Null Clause"); DebugAssert(i==0 || i==1, "wp(i): Watch pointer index is out of bounds: i = " + int2string(i)); return d_clause->d_wp[i]; } // Get the watched literals const Literal& watched(int i) const { return getLiteral(wp(i)); } // Set the watch pointers and return the new value size_t wp(int i, size_t l) const { DebugAssert(!isNull(), "Clause::wp(i,l): Null Clause"); DebugAssert(i==0 || i==1, "wp(i,l): Watch pointer index is out of bounds: i = " + int2string(i)); DebugAssert(l < size(), "Clause::wp(i = " + int2string(i) + ", l = " + int2string(l) + "): l >= size() = " + int2string(size())); TRACE("clauses", " **clauses** UPDATE wp(idx=" +int2string(i)+", l="+int2string(l), ")\n clause #: ", id()); d_clause->d_wp[i] = l; return l; } // Get the direction of the i-th watch pointer int dir(int i) const { DebugAssert(!isNull(), "Clause::dir(i): Null Clause"); DebugAssert(i==0 || i==1, "dir(i): Watch pointer index is out of bounds: i = " + int2string(i)); return d_clause->d_dir[i]; } // Set the direction of the i-th watch pointer int dir(int i, int d) const { DebugAssert(!isNull(), "Clause::dir(i,d): Null Clause"); DebugAssert(i==0 || i==1, "dir(i="+int2string(i)+",d="+int2string(d) +"): Watch pointer index is out of bounds"); DebugAssert(d==1 || d==-1, "dir(i="+int2string(i)+",d="+int2string(d) +"): Direction is out of bounds"); d_clause->d_dir[i] = d; return d; } //! Check if the clause marked as SAT bool sat() const { DebugAssert(!isNull(), "Clause::sat()"); return d_clause->d_sat; } //! Precise version of sat(): check all the literals and cache the result bool sat(bool ignored) const { DebugAssert(!isNull(), "Clause::sat()"); bool flag = false; if (!d_clause->d_sat) { for (size_t i = 0; !flag && i < d_clause->d_literals.size(); ++i) if (d_clause->d_literals[i].getValue() == 1) flag = true; } if (flag) { //std::cout << "*** Manually marking SAT" << std::endl; markSat(); } return d_clause->d_sat; } // Mark the clause as SAT void markSat() const { DebugAssert(!isNull(), "Clause::markSat()"); d_clause->d_sat = true; } // Check / mark the clause as deleted bool deleted() const { DebugAssert(!isNull(), "Clause::deleted()"); return d_clause->d_deleted; } void markDeleted() const; // For debugging: return some kind of unique ID size_t id() const { return (size_t) d_clause; } // Equality: compare the pointers bool operator==(const Clause& c) const { return d_clause == c.d_clause; } //! Tell how many owners this clause has (for debugging) int owners() const { return d_clause->d_refcountOwner; } // Printing std::string toString() const; friend std::ostream& operator<<(std::ostream& os, const Clause& c); IF_DEBUG(bool wpCheck() const;) IF_DEBUG(const std::string& getFile() const { return d_clause->d_file; }) IF_DEBUG(int getLine() const { return d_clause->d_line; }) }; // end of class Clause //! Same as class Clause, but when destroyed, marks the clause as deleted /*! Needed for backtraking data structures. When the SAT solver backtracks, some clauses will be thrown away automatically, and we need to mark those as deleted. */ class ClauseOwner { Clause d_clause; //! Disable default constructor ClauseOwner() { } public: //! Constructor from class Clause ClauseOwner(const Clause& c): d_clause(c) { d_clause.countOwner()++; } //! Construct a new Clause ClauseOwner(TheoryCore* core, VariableManager* vm, const Theorem& clause, int scope): d_clause(core, vm, clause, scope) { d_clause.countOwner()++; } //! Copy constructor (keep track of refcounts) ClauseOwner(const ClauseOwner& c): d_clause(c.d_clause) { d_clause.countOwner()++; } //! Assignment (keep track of refcounts) ClauseOwner& operator=(const ClauseOwner& c) { if(&c == this) return *this; // Seft-assignment DebugAssert(d_clause.countOwner() > 0, "in operator="); if(--(d_clause.countOwner()) == 0) d_clause.markDeleted(); d_clause = c.d_clause; d_clause.countOwner()++; return *this; } //! Destructor: mark the clause as deleted ~ClauseOwner() { FatalAssert(d_clause.countOwner() > 0, "in ~ClauseOwner"); if(--(d_clause.countOwner()) == 0) { d_clause.markDeleted(); } } //! Automatic type conversion to Clause ref operator Clause& () { return d_clause; } //! Automatic type conversion to Clause const ref operator const Clause& () const { return d_clause; } }; // end of class ClauseOwner // I/O Manipulators // Print clause in a compact form: Clause[x=-1@scope, ...], mark // watched literals by '*' class CompactClause { private: Clause d_clause; public: CompactClause(const Clause& c): d_clause(c) { } friend std::ostream& operator<<(std::ostream& os, const CompactClause& c); std::string toString() const; }; } // end of namespace CVC3 #endif cvc3-2.4.1/src/include/theorem_manager.h0000664000175400017540000000720210500320635017771 0ustar mdetersmdeters/*****************************************************************************/ /*! * \file theorem_manager.h * * Author: Sergey Berezin, Tue Feb 4 14:29:25 2003 * * Created: Feb 05 18:29:37 GMT 2003 * *
* * License to use, copy, modify, sell and/or distribute this software * and its documentation for any purpose is hereby granted without * royalty, subject to the terms and conditions defined in the \ref * LICENSE file provided with this distribution. * *
* * CLASS: TheoremManager * * * Holds the shared data for the class Theorem */ /*****************************************************************************/ #ifndef _cvc3__theorem_manager_h_ #define _cvc3__theorem_manager_h_ #include "debug.h" #include "compat_hash_map.h" namespace CVC3 { class ContextManager; class ExprManager; class CLFlags; class MemoryManager; class CommonProofRules; class TheoremManager { private: ContextManager* d_cm; ExprManager* d_em; const CLFlags& d_flags; MemoryManager* d_mm; MemoryManager* d_rwmm; bool d_withProof; bool d_withAssump; unsigned d_flag; // used for setting flags in Theorems bool d_active; //!< Whether TheoremManager is active. See also clear() CommonProofRules* d_rules; std::hash_map d_reflFlags; std::hash_map d_cachedValues; std::hash_map d_expandFlags; std::hash_map d_litFlags; CommonProofRules* createProofRules(); public: //! Constructor TheoremManager(ContextManager* cm, ExprManager* em, const CLFlags& flags); //! Destructor ~TheoremManager(); //! Deactivate TheoremManager /*! No more Theorems can be created after this call, only deleted. * The purpose of this call is to dis-entangle the mutual * dependency of ExprManager and TheoremManager during destruction time. */ void clear(); //! Test whether the TheoremManager is still active bool isActive() { return d_active; } ContextManager* getCM() const { return d_cm; } ExprManager* getEM() const { return d_em; } const CLFlags& getFlags() const { return d_flags; } MemoryManager* getMM() const { return d_mm; } MemoryManager* getRWMM() const { return d_rwmm; } CommonProofRules* getRules() const { return d_rules; } unsigned getFlag() const { return d_flag; } void clearAllFlags() { d_reflFlags.clear(); FatalAssert(++d_flag, "Theorem flag overflow."); } bool withProof() { return d_withProof; } bool withAssumptions() { return d_withAssump; } // For Refl theorems void setFlag(long ptr) { d_reflFlags[ptr] = true; } bool isFlagged(long ptr) { return d_reflFlags.count(ptr) > 0; } void setCachedValue(long ptr, int value) { d_cachedValues[ptr] = value; } int getCachedValue(long ptr) { std::hash_map::const_iterator i = d_cachedValues.find(ptr); if (i != d_cachedValues.end()) return (*i).second; else return 0; } void setExpandFlag(long ptr, bool value) { d_expandFlags[ptr] = value; } bool getExpandFlag(long ptr) { std::hash_map::const_iterator i = d_expandFlags.find(ptr); if (i != d_expandFlags.end()) return (*i).second; else return false; } void setLitFlag(long ptr, bool value) { d_litFlags[ptr] = value; } bool getLitFlag(long ptr) { std::hash_map::const_iterator i = d_litFlags.find(ptr); if (i != d_litFlags.end()) return (*i).second; else return false; } }; // end of class TheoremManager } // end of namespace CVC3 #endif cvc3-2.4.1/src/include/search_fast.h0000664000175400017540000004002611122576130017123 0ustar mdetersmdeters/////////////////////////////////////////////////////////////////////////////// /*! * \file search_fast.h * * Author: Mark Zavislak * * Created: Mon Jul 21 17:33:18 UTC 2003 * *
* * License to use, copy, modify, sell and/or distribute this software * and its documentation for any purpose is hereby granted without * royalty, subject to the terms and conditions defined in the \ref * LICENSE file provided with this distribution. * *
* * A faster implementation of the proof search engine */ /////////////////////////////////////////////////////////////////////////////// #ifndef _cvc3__include__search_fast_h_ #define _cvc3__include__search_fast_h_ #include #include #include "search_impl_base.h" #include "variable.h" #include "circuit.h" #include "statistics.h" #include #include "smartcdo.h" namespace CVC3 { class VariableManager; class DecisionEngine; //////////////////////////////////////////////////////////////////////////// //////////// Definition of modules (groups) for doxygen //////////////////// //////////////////////////////////////////////////////////////////////////// /*! * \defgroup SE_Fast Fast Search Engine * \ingroup SE * * This module includes all the components of the fast search * engine. * @{ */ //! Implementation of a faster search engine, using newer techniques. /*! This search engine is engineered for greater speed. It seeks to eliminate the use of recursion, and instead replace it with iterative procedures that have cleanly defined invariants. This will hopefully not only eliminate bugs or inefficiencies that have been difficult to track down in the default version, but it should also make it easier to trace, read, and understand. It strives to be in line with the most modern SAT techniques. There are three other significant changes. One, we want to improve the performance on heavily non-CNF problems. Unlike the older CVC, CVC3 does not expand problems into CNF and solve, but rather uses decision procedures to effect the same thing, but often much more slowly. This search engine will leverage off knowledge gained from the DPs in the form of conflict clauses as much as possible. Two, the solver has traditionally had a difficult time getting started on non-CNF problems. Modern satsolvers also have this problem, and so they employ "restarts" to try solving the problem again after gaining more knowledge about the problem at hand. This allows a more accurate choice of splitters, and in the case of non-CNF problems, the solver can immediately leverage off CNF conflict clauses that were not initially available. Third, this code is specifically designed to deal with the new dependency tracking. Lazy maps will be eliminated in favor implicit conflict graphs, reducing computation time in two different ways. */ class SearchEngineFast : public SearchImplBase { friend class Circuit; /*! \addtogroup SE_Fast * @{ */ //! Name std::string d_name; //! Decision Engine DecisionEngine *d_decisionEngine; //! Total number of unit propagations StatCounter d_unitPropCount; //! Total number of circuit propagations StatCounter d_circuitPropCount; //! Total number of conflicts StatCounter d_conflictCount; //! Total number of conflict clauses generated (not all may be active) StatCounter d_conflictClauseCount; //! Backtrackable list of clauses. /*! New clauses may come into play from the decision procedures that are context dependent. */ CDList d_clauses; //! Backtrackable set of pending unprocessed literals. /*! These can be discovered at any scope level during conflict analysis. */ CDMap d_unreportedLits; CDMap d_unreportedLitsHandled; //! Backtrackable list of non-literals (non-CNF formulas). /*! We treat nonliterals like clauses, because they are a superset of clauses. We stick the real clauses into d_clauses, but all the rest have to be stored elsewhere. */ CDList > d_nonLiterals; CDMap d_nonLiteralsSaved; //!< prevent reprocessing // CDMap d_nonLiteralSimplified; //!< Simplified non-literals //! Theorem which records simplification of the last query CDO d_simplifiedThm; //! Size of d_nonLiterals before most recent query CDO d_nonlitQueryStart; //! Size of d_nonLiterals after query (not including DP-generated non-literals) CDO d_nonlitQueryEnd; //! Size of d_clauses before most recent query CDO d_clausesQueryStart; //! Size of d_clauses after query CDO d_clausesQueryEnd; //! Array of conflict clauses: one deque for each outstanding query std::vector* > d_conflictClauseStack; //! Reference to top deque of conflict clauses std::deque* d_conflictClauses; //! Helper class for managing conflict clauses /*! Conflict clauses should only get popped when the context in which a * call to checkValid originates is popped. This helper class checks * every time there's a pop to see if the conflict clauses need to be * restored. */ friend class ConflictClauseManager; class ConflictClauseManager :public ContextNotifyObj { SearchEngineFast* d_se; std::vector d_restorePoints; public: ConflictClauseManager(Context* context, SearchEngineFast* se) : ContextNotifyObj(context), d_se(se) {} void setRestorePoint(); void notify(); }; ConflictClauseManager d_conflictClauseManager; //! Unprocessed unit conflict clauses /*! When we find unit conflict clauses, we are automatically going to jump back to the original scope. Hopefully we won't find multiple ones, but you never know with those wacky decision procedures just spitting new information out. These are then directly asserted then promptly forgotten about. Chaff keeps them around (for correctness maybe), but we already have the proofs stored in the literals themselves. */ std::vector d_unitConflictClauses; //! Set of literals to be processed by bcp. /*! These are emptied out upon backtracking, because they can only be valid if they were already all processed without conflicts. Therefore, they don't need to be context dependent. */ std::vector d_literals; //! Set of asserted literals which may survive accross checkValid() calls /*! * When a literal is asserted outside of checkValid() call, its * value is remembered in a Literal database, but the literal * queue for BCP is cleared. We add literals to this set at the * proper scope levels, and propagate them at the beginning of a * checkValid() call. */ CDMap d_literalSet; //! Queue of derived facts to be sent to DPs /*! \sa addFact() and commitFacts() */ std::vector d_factQueue; /*! @brief When true, use TheoryCore::enqueueFact() instead of * addFact() in commitFacts() */ bool d_useEnqueueFact; //! True when checkSAT() is running /*! Used by addLiteralFact() to determine whether to BCP the * literals immediately (outside of checkSAT()) or not. */ bool d_inCheckSAT; //! Set of alive literals that shouldn't be garbage-collected /*! Unfortunately, I have a keep-alive issue. I think literals actually have to hang around, so I assert them to a separate d_litsAlive CDList. */ CDList d_litsAlive; /*! @brief Mappings of literals to vectors of pointers to the corresponding watched literals. */ /*! A pointer is a pair (clause,i), where 'i' in {0,1} is the index of the watch pointer in the clause. */ // ExprHashMap > > d_wp; std::vector d_circuits; ExprHashMap > d_circuitsByExpr; //! The scope of the last conflict /*! This is the true scope of the conflict, not necessarily the scope where the conflict was detected. */ int d_lastConflictScope; //! The last conflict clause (for checkSAT()). May be Null. /*! It records which conflict clause must be processed by BCP after backtracking from a conflict. A conflict may generate several conflict clauses, but only one of them will cause a unit propagation. */ Clause d_lastConflictClause; //! Theorem(FALSE) which generated a conflict Theorem d_conflictTheorem; /*! @brief Return a ref to the vector of watched literals. If no such vector exists, create it. */ std::vector >& wp(const Literal& literal); /*! @brief \return true if SAT, false otherwise. * * When false is returned, proof is saved in d_lastConflictTheorem */ QueryResult checkSAT(); //! Choose a splitter. /*! Preconditions: The current context is consistent. * * \return true if splitter available, and it asserts it through * newIntAssumption() after first pushing a new context. * * \return false if no splitters are available, which means the * context is SAT. * * Postconditions: A literal has been asserted through * newIntAssumption(). */ bool split(); // Moved from the decision engine: //! Returns a splitter Expr findSplitter(); //! Position of a literal with max score in d_litsByScores unsigned d_litsMaxScorePos; //! Vector of literals sorted by score std::vector d_litsByScores; /* //! Mapping of literals to scores ExprHashMap d_litScores; //! Mapping of literals to their counters ExprHashMap d_litCounts; //! Mapping of literals to previous counters (what's that, anyway?) ExprHashMap d_litCountPrev; */ //! Internal splitter counter for delaying updateLitScores() int d_splitterCount; //! Internal (decrementing) count of added splitters, to sort d_litByScores int d_litSortCount; //! Flag to switch on/off the berkmin heuristic const bool d_berkminFlag; //! Clear the list of asserted literals (d_literals) void clearLiterals(); void updateLitScores(bool firstTime); //! Add the literals of a new clause to d_litsByScores void updateLitCounts(const Clause& c); //! Boolean constraint propagation. /*! Preconditions: On every run besides the first, the CNF clause * database must not have any unit or unsat clauses, and there * must be a literal queued up for processing. The current * context must be consistent. Any and all assertions and * assignments must actually be made within the bcp loop. Other * parts of the solver may queue new facts with addLiteralFact() * and addNonLiteralFact(). bcp() will either process them, or * it will find a conflict, in which case they will no longer be * valid and will be dumped. Any nonLiterals must already be * simplified. * * Description: BCP will systematically work through all the * literals and nonliterals, using boolean constraint propagation * by detecting unit clauses and using addLiteralFact() on the * unit literal while also marking the clause as SAT. Any * clauses marked SAT are guaranteed to be SAT, but clauses not * marked SAT are not guaranteed to be unsat. * * \return false if a conflict is found, true otherwise. * * Postconditions: False indicates conflict. If the conflict was * discovered in CNF, we call the proof rule, then store that * clause pointer so fixConflict() can skip over it during the * search (when we finally change dependency tracking). * * True indicates success. All literals and nonLiterals have * been processed without causing a conflict. Processing * nonliterals implies running simplify on them, immediately * asserting any simplifications back to the core, and marking * the original nonLiteral as simplified, to be ignored by all * future (this context or deeper) splitters and bcp runs. * Therefore, there will be no unsimplified nonliterals * remaining. */ bool bcp(); //! Determines backtracking level and adds conflict clauses. /*! Preconditions: The current context is inconsistent. If it * resulted from a conflictRule() application, then the theorem * is stored inside d_lastConflictTheorem. * * If this was caused from bcp, we obtain the conflictRule() * theorem from the d_lastConflictTheorem instance variable. * From here we build conflict clauses and determine the correct * backtracking level, at which point we actually backtrack * there. Finally, we also call addLiteralFact() on the "failure * driven assertion" literal so that bcp has some place to begin * (and it satisfies the bcp preconditions) * * Postconditions: If True is returned: The current context is * consistent, and a literal is queued up for bcp to process. If * False is returned: The context cannot be made consistent * without backtracking past the original one, so the formula is * unsat. */ bool fixConflict(); //! FIXME: document this void assertAssumptions(); //! Queue up a fact to assert to the DPs later void enqueueFact(const Theorem& thm); //! Set the context inconsistent. Takes Theorem(FALSE). void setInconsistent(const Theorem& thm); //! Commit all the enqueued facts to the DPs void commitFacts(); //! Clear the local fact queue void clearFacts(); /*! @name Processing a Conflict */ //@{ /*! @brief Take a conflict in the form of Literal, or Theorem, and generate all the necessary conflict clauses. */ Theorem processConflict(const Literal& l); Theorem processConflict(const Theorem& thm); //@} //! Auxiliary function for unit propagation bool propagate(const Clause &c, int idx, bool& wpUpdated); //! Do the unit propagation for the clause void unitPropagation(const Clause &c, unsigned idx); //! Analyse the conflict, find the UIPs, etc. void analyzeUIPs(const Theorem &falseThm, int conflictScope); ///////////////////////////// // New convenience methods // ///////////////////////////// //! Go through all the clauses and check the watch pointers (for debugging) IF_DEBUG(void fullCheck();) //! Set up the watch pointers for the new clause void addNewClause(Clause &c); //! Process a new derived fact (auxiliary function) void recordFact(const Theorem& thm); //! First pass in conflict analysis; takes a theorem of FALSE void traceConflict(const Theorem& conflictThm); //! Private helper function for checkValid and restart QueryResult checkValidMain(const Expr& e2); public: //! The main Constructor SearchEngineFast(TheoryCore* core); //! Destructor virtual ~SearchEngineFast(); const std::string& getName() { return d_name; } //! Implementation of the API call virtual QueryResult checkValidInternal(const Expr& e); virtual QueryResult restartInternal(const Expr& e); //! Redefine the counterexample generation. virtual void getCounterExample(std::vector& assertions); //! Notify the search engine about a new literal fact. void addLiteralFact(const Theorem& thm); //! Notify the search engine about a new non-literal fact. void addNonLiteralFact(const Theorem& thm); /*! @brief Redefine newIntAssumption(): we need to add the new theorem to the appropriate Literal */ virtual Theorem newIntAssumption(const Expr& e); virtual bool isAssumption(const Expr& e); void addSplitter(const Expr& e, int priority); /*! @} */ // end of addtogroup SE_Fast //! Return next clause whose satisfiability is unknown //virtual Clause nextClause(); //! Return next non-clause which does not reduce to false //virtual Expr nextNonClause(); }; /*! @} */ // end of SE_Fast } #endif cvc3-2.4.1/src/include/theory_arith_old.h0000644000175400017540000007707711630011150020204 0ustar mdetersmdeters/*****************************************************************************/ /*! * \file theory_arith_old.h * * Author: Clark Barrett * * Created: Thu Jun 14 13:22:11 2007 * *
* * License to use, copy, modify, sell and/or distribute this software * and its documentation for any purpose is hereby granted without * royalty, subject to the terms and conditions defined in the \ref * LICENSE file provided with this distribution. * *
* */ /*****************************************************************************/ #ifndef _cvc3__include__theory_arith_old_h_ #define _cvc3__include__theory_arith_old_h_ #include "theory_arith.h" #include #include namespace CVC3 { class TheoryArithOld :public TheoryArith { CDList d_diseq; // For concrete model generation CDO d_diseqIdx; // Index to the next unprocessed disequality CDMap diseqSplitAlready; // Have we eplit on this disequality already ArithProofRules* d_rules; CDO d_inModelCreation; //! Data class for the strongest free constant in separation inqualities class FreeConst { private: Rational d_r; bool d_strict; public: FreeConst() { } FreeConst(const Rational& r, bool strict): d_r(r), d_strict(strict) { } const Rational& getConst() const { return d_r; } bool strict() const { return d_strict; } }; //! Printing friend std::ostream& operator<<(std::ostream& os, const FreeConst& fc); //! Private class for an inequality in the Fourier-Motzkin database class Ineq { private: Theorem d_ineq; //!< The inequality bool d_rhs; //!< Var is isolated on the RHS const FreeConst* d_const; //!< The max/min const for subsumption check //! Default constructor is disabled Ineq() { } public: //! Initial constructor. 'r' is taken from the subsumption database. Ineq(const Theorem& ineq, bool varOnRHS, const FreeConst& c): d_ineq(ineq), d_rhs(varOnRHS), d_const(&c) { } //! Get the inequality const Theorem ineq() const { return d_ineq; } //! Get the max/min constant const FreeConst& getConst() const { return *d_const; } //! Flag whether var is isolated on the RHS bool varOnRHS() const { return d_rhs; } //! Flag whether var is isolated on the LHS bool varOnLHS() const { return !d_rhs; } //! Auto-cast to Theorem operator Theorem() const { return d_ineq; } }; //! Printing friend std::ostream& operator<<(std::ostream& os, const Ineq& ineq); //! Database of inequalities with a variable isolated on the right ExprMap *> d_inequalitiesRightDB; //! Database of inequalities with a variable isolated on the left ExprMap *> d_inequalitiesLeftDB; //! Mapping of inequalities to the largest/smallest free constant /*! The Expr is the original inequality with the free constant * removed and inequality converted to non-strict (for indexing * purposes). I.e. ax, the smallest (largest for c+t d_freeConstDB; // /** Is the problem only difference logic */ // CDO isDL; // CDO total_buf_size; // CDO processed; // // Input buffer to store the incoming inequalities CDList d_buffer_0; //!< Buffer of input inequalities (high priority) CDList d_buffer_1; //!< Buffer of input inequalities (one variable) CDList d_buffer_2; //!< Buffer of input inequalities (small constraints) CDList d_buffer_3; //!< Buffer of input inequalities (big constraint) CDO d_bufferIdx_0; //!< Buffer index of the next unprocessed inequality CDO d_bufferIdx_1; //!< Buffer index of the next unprocessed inequality CDO d_bufferIdx_2; //!< Buffer index of the next unprocessed inequality CDO d_bufferIdx_3; //!< Buffer index of the next unprocessed inequality CDO diff_logic_size; //!< Number of queries that are just difference logic const int* d_bufferThres; //!< Threshold when the buffer must be processed const bool* d_splitSign; // Whether to split on the signs of non-trivial nonlinear products const int* d_grayShadowThres; //!< Threshold on gray shadow size (ignore it and set incomplete) // Statistics for the variables /*! @brief Mapping of a variable to the number of inequalities where the variable would be isolated on the right */ CDMap d_countRight; /*! @brief Mapping of a variable to the number of inequalities where the variable would be isolated on the left */ CDMap d_countLeft; //! Set of shared terms (for counterexample generation) CDMap d_sharedTerms; CDList d_sharedTermsList; //! Set of shared integer variables (i-leaves) CDMap d_sharedVars; //Directed Acyclic Graph representing partial variable ordering for //variable projection over inequalities. class VarOrderGraph { ExprMap > d_edges; ExprMap d_cache; bool dfs(const Expr& e1, const Expr& e2); void dfs(const Expr& e1, std::vector& output_list); public: void addEdge(const Expr& e1, const Expr& e2); //returns true if e1 < e2, false otherwise. bool lessThan(const Expr& e1, const Expr& e2); //selects those variables which are largest and incomparable among //v1 and puts it into v2 void selectLargest(const std::vector& v1, std::vector& v2); //selects those variables which are smallest and incomparable among //v1, removes them from v1 and puts them into v2. void selectSmallest( std::vector& v1, std::vector& v2); //returns the list of vertices in the topological order void getVerticesTopological(std::vector& output_list); }; VarOrderGraph d_graph; // Private methods //! Check the term t for integrality. /*! \return a theorem of IS_INTEGER(t) or Null. */ Theorem isIntegerThm(const Expr& e); //! A helper method for isIntegerThm() /*! Check if IS_INTEGER(e) is easily derivable from the given 'thm' */ Theorem isIntegerDerive(const Expr& isIntE, const Theorem& thm); //! Extract the free constant from an inequality const Rational& freeConstIneq(const Expr& ineq, bool varOnRHS); //! Update the free constant subsumption database with new inequality /*! \return a reference to the max/min constant. * * Also, sets 'subsumed' argument to true if the inequality is * subsumed by an existing inequality. */ const FreeConst& updateSubsumptionDB(const Expr& ineq, bool varOnRHS, bool& subsumed); //! Check if the kids of e are fully simplified and canonized (for debugging) bool kidsCanonical(const Expr& e); //! Canonize the expression e, assuming, all children are canonical Theorem canon(const Expr& e); /*! @brief Canonize and reduce e w.r.t. union-find database; assume * all children are canonical */ Theorem canonSimplify(const Expr& e); /*! @brief Composition of canonSimplify(const Expr&) by * transitivity: take e0 = e1, canonize and simplify e1 to e2, * return e0 = e2. */ Theorem canonSimplify(const Theorem& thm) { return transitivityRule(thm, canonSimplify(thm.getRHS())); } //! Canonize predicate (x = y, x < y, etc.) Theorem canonPred(const Theorem& thm); //! Canonize predicate like canonPred except that the input theorem //! is an equivalent transformation. Theorem canonPredEquiv(const Theorem& thm); //! Solve an equation and return an equivalent Theorem in the solved form Theorem doSolve(const Theorem& e); //! takes in a conjunction equivalence Thm and canonizes it. Theorem canonConjunctionEquiv(const Theorem& thm); //! picks the monomial with the smallest abs(coeff) from the input //integer equation. bool pickIntEqMonomial(const Expr& right, Expr& isolated, bool& nonlin); //! processes equalities with 1 or more vars of type REAL Theorem processRealEq(const Theorem& eqn); //! processes equalities whose vars are all of type INT Theorem processIntEq(const Theorem& eqn); //! One step of INT equality processing (aux. method for processIntEq()) Theorem processSimpleIntEq(const Theorem& eqn); //! Process inequalities in the buffer void processBuffer(); //! Take an inequality and isolate a variable Theorem isolateVariable(const Theorem& inputThm, bool& e1); //! Update the statistics counters for the variable with a coeff. c void updateStats(const Rational& c, const Expr& var); //! Update the statistics counters for the monomial void updateStats(const Expr& monomial); //! Add an inequality to the input buffer. See also d_buffer bool addToBuffer(const Theorem& thm, bool priority = false); /*! @brief Given a canonized term, compute a factor to make all coefficients integer and relatively prime */ Expr computeNormalFactor(const Expr& rhs, bool normalizeConstants); //! Normalize an equation (make all coefficients rel. prime integers) Theorem normalize(const Expr& e); //! Normalize an equation (make all coefficients rel. prime integers) /*! accepts a rewrite theorem over eqn|ineqn and normalizes it * and returns a theorem to that effect. */ Theorem normalize(const Theorem& thm); Expr pickMonomial(const Expr& right); void getFactors(const Expr& e, std::set& factors); public: // ArithTheoremProducer needs these functions, so make them public //! Separate monomial e = c*p1*...*pn into c and 1*p1*...*pn void separateMonomial(const Expr& e, Expr& c, Expr& var); //! Check the term t for integrality (return bool) bool isInteger(const Expr& e) { return isInt(e.getType()) ? true : (isReal(e.getType()) ? false : !(isIntegerThm(e).isNull())); } private: bool lessThanVar(const Expr& isolatedVar, const Expr& var2); //! Check if the term expression is "stale" bool isStale(const Expr& e); //! Check if the inequality is "stale" or subsumed bool isStale(const Ineq& ineq); void projectInequalities(const Theorem& theInequality,bool isolatedVarOnRHS); void assignVariables(std::vector&v); void findRationalBound(const Expr& varSide, const Expr& ratSide, const Expr& var, Rational &r); bool findBounds(const Expr& e, Rational& lub, Rational& glb); Theorem normalizeProjectIneqs(const Theorem& ineqThm1, const Theorem& ineqThm2); //! Take a system of equations and turn it into a solved form Theorem solvedForm(const std::vector& solvedEqs); /*! @brief Substitute all vars in term 't' according to the * substitution 'subst' and canonize the result. */ Theorem substAndCanonize(const Expr& t, ExprMap& subst); /*! @brief Substitute all vars in the RHS of the equation 'eq' of * the form (x = t) according to the substitution 'subst', and * canonize the result. */ Theorem substAndCanonize(const Theorem& eq, ExprMap& subst); //! Traverse 'e' and push all the i-leaves into 'vars' vector void collectVars(const Expr& e, std::vector& vars, std::set& cache); /*! @brief Check if alpha <= ax & bx <= beta is a finite interval * for integer var 'x', and assert the corresponding constraint */ void processFiniteInterval(const Theorem& alphaLEax, const Theorem& bxLEbeta); //! For an integer var 'x', find and process all constraints A <= ax <= A+c void processFiniteIntervals(const Expr& x); //! Recursive setup for isolated inequalities (and other new expressions) void setupRec(const Expr& e); public: TheoryArithOld(TheoryCore* core); ~TheoryArithOld(); // Trusted method that creates the proof rules class (used in constructor). // Implemented in arith_theorem_producer.cpp ArithProofRules* createProofRulesOld(); // Theory interface void addSharedTerm(const Expr& e); void assertFact(const Theorem& e); void refineCounterExample(); void computeModelBasic(const std::vector& v); void computeModel(const Expr& e, std::vector& vars); void checkSat(bool fullEffort); Theorem rewrite(const Expr& e); void setup(const Expr& e); void update(const Theorem& e, const Expr& d); Theorem solve(const Theorem& e); void checkAssertEqInvariant(const Theorem& e); void checkType(const Expr& e); Cardinality finiteTypeInfo(Expr& e, Unsigned& n, bool enumerate, bool computeSize); void computeType(const Expr& e); Type computeBaseType(const Type& t); void computeModelTerm(const Expr& e, std::vector& v); Expr computeTypePred(const Type& t, const Expr& e); Expr computeTCC(const Expr& e); ExprStream& print(ExprStream& os, const Expr& e); Expr parseExprOp(const Expr& e); private: /** Map from variables to the maximal (by absolute value) of one of it's coefficients */ ExprMap maxCoefficientLeft; ExprMap maxCoefficientRight; /** Map from variables to the fixed value of one of it's coefficients */ ExprMap fixedMaxCoefficient; /** * Returns the current maximal coefficient of the variable. * * @param var the variable. */ Rational currentMaxCoefficient(Expr var); /** * Fixes the current max coefficient to be used in the ordering. If the maximal coefficient * changes in the future, it will not be used in the ordering. * * @param variable the variable * @param max the value to set it to */ void fixCurrentMaxCoefficient(Expr variable, Rational max); /** * Among given input variables, select the smallest ones with respect to the coefficients. */ void selectSmallestByCoefficient(const std::vector& input, std::vector& output); /** * Given an inequality theorem check if it is on integers and get rid of the non-integer * constants. */ Theorem rafineInequalityToInteger(const Theorem& thm); /** * Given an equality theorem check if it is on integers with a non-integer constant. If * yes, return a theorem 0 = 1 */ Theorem checkIntegerEquality(const Theorem& thm); /** Keep the expressions that are already in the buffer */ CDMap bufferedInequalities; /** Strict lower bounds on terms, so that we don't add inequalities to the buffer */ CDMap termLowerBound; CDMap termLowerBoundThm; /** Strict upper bounds on terms, so that we don't add inequalities to the buffer */ CDMap termUpperBound; CDMap termUpperBoundThm; /** * Which inequalities have already been projected (on which monomial). * - if we get an update of an inequality that's not been projected, we don't care * it will get projected (it's find) * - when projecting, project the finds, not the originals * - when done projecting add here, both original and the find */ CDMap alreadyProjected; /** * Sometimes we know an inequality is in the buffer (as a find of something) and * we don't want it in the buffer, but we do want to pre-process it, so we put it * here. */ CDMap dontBuffer; /** * Are we doing only difference logic? */ CDO diffLogicOnly; /** * Takes an inequality theorem and substitutes the rhs for it's find. It also get's normalized. */ Theorem inequalityToFind(const Theorem& inequalityThm, bool normalizeRHS); // x -y <= c struct GraphEdge { Expr x; Expr y; Rational c; }; /** * Take inequality of the form 0 op t and extract the c1, t1, c2 and t2, such that * c1 <= t1 and t2 <= c2, where c1 and c2 are constants, and t1 and t2 are either * sums of monomials or a monomial. * * @return the number of variables in terms t1 and t2 */ int extractTermsFromInequality(const Expr& inequality, Rational& c1, Expr& t1, Rational& c2, Expr& t2); void registerAtom(const Expr& e); typedef ExprMap< std::set< std::pair > > AtomsMap; /** Map from terms to their lower bound (and the original formula expression) */ AtomsMap formulaAtomLowerBound; /** Map from terms to their upper bound (and the original formula expression) */ AtomsMap formulaAtomUpperBound; /** Map of all the atoms in the formula */ ExprMap formulaAtoms; class DifferenceLogicGraph { public: /** * EpsRational class ecapsulates the rationals with a symbolic small \f$\epsilon\f$ added. Each rational * number is presented as a pair \f$(q, k) = q + k\epsilon\f$, where \f$\epsilon\f$ is treated symbolically. * The operations on the new rationals are defined as *
    *
  • \f$(q_1, k_1) + (q_2, k_2) \equiv (q_1 + q_2, k_1 + k_2)\f$ *
  • \f$a \times (q, k) \equiv (a \times q, a \times k)\f$ *
  • \f$(q_1, k_1) \leq (q_2, k_2) \equiv (q_1 < q_2) \vee (q_1 = q_2 \wedge k_1 \leq k_2)\f$ *
* * Note that the operations on the infinite values are not defined, as they are never used currently. Infinities can * only be asigned or compared. */ class EpsRational { protected: /** Type of rationals, normal and the two infinities */ typedef enum { FINITE, PLUS_INFINITY, MINUS_INFINITY } RationalType; /** The type of this rational */ RationalType type; /** The rational part */ Rational q; /** The epsilon multiplier */ Rational k; /** * Private constructor to construt infinities. */ EpsRational(RationalType type) : type(type) {} public: /** * Returns if the numbe is finite. */ inline bool isFinite() const { return type == FINITE; } /** * Returns if the number is a plain rational. * * @return true if rational, false otherwise */ inline bool isRational() const { return k == 0; } /** * Returns if the number is a plain integer. * * @return true if rational, false otherwise */ inline bool isInteger() const { return k == 0 && q.isInteger(); } /** * Returns the floor of the number \f$x = q + k \epsilon\f$ using the following fomula * \f[ * \lfloor \beta(x) \rfloor = * \begin{cases} * \lfloor q \rfloor & \text{ if } q \notin Z\\ * q & \text{ if } q \in Z \text{ and } k \geq 0\\ * q - 1 & \text{ if } q \in Z \text{ and } k < 0 * \end{cases} * \f] */ inline Rational getFloor() const { if (q.isInteger()) { if (k >= 0) return q; else return q - 1; } else // If not an integer, just floor it return floor(q); } /** * Returns the rational part of the number * * @return the rational */ inline Rational getRational() const { return q; } /** * Returns the epsilon part of the number * * @return the epsilon */ inline Rational getEpsilon() const { return k; } /** The infinity constant */ static const EpsRational PlusInfinity; /** The negative infinity constant */ static const EpsRational MinusInfinity; /** The zero constant */ static const EpsRational Zero; /** The blank constructor */ EpsRational() : type(FINITE), q(0), k(0) {} /** Copy constructor */ EpsRational(const EpsRational& r) : type(r.type), q(r.q), k(r.k) {} /** * Constructor from a rational, constructs a new pair (q, 0). * * @param q the rational */ EpsRational(const Rational& q) : type(FINITE), q(q), k(0) {} /** * Constructor from a rational and a given epsilon multiplier, constructs a * new pair (q, k). * * @param q the rational * @param k the epsilon multiplier */ EpsRational(const Rational& q, const Rational& k) : type(FINITE), q(q), k(k) {} /** * Addition operator for two EpsRational numbers. * * @param r the number to be added * @return the sum as defined in the class */ inline EpsRational operator + (const EpsRational& r) const { DebugAssert(type == FINITE, "EpsRational::operator +, adding to infinite number"); DebugAssert(r.type == FINITE, "EpsRational::operator +, adding an infinite number"); return EpsRational(q + r.q, k + r.k); } /** * Addition operator for two EpsRational numbers. * * @param r the number to be added * @return the sum as defined in the class */ inline EpsRational& operator += (const EpsRational& r) { DebugAssert(type == FINITE, "EpsRational::operator +, adding to infinite number"); q = q + r.q; k = k + r.k; return *this; } /** * Subtraction operator for two EpsRational numbers. * * @param r the number to be added * @return the sum as defined in the class */ inline EpsRational operator - (const EpsRational& r) const { DebugAssert(type == FINITE, "EpsRational::operator -, subtracting from infinite number"); DebugAssert(r.type == FINITE, "EpsRational::operator -, subtracting an infinite number"); return EpsRational(q - r.q, k - r.k); } /** * Unary minus operator */ inline EpsRational operator - () { DebugAssert(type == FINITE, "EpsRational::operator -, subtracting from infinite number"); q = -q; k = -k; return *this; } /** * Multiplication operator EpsRational number and a rational number. * * @param a the number to be multiplied * @return the product as defined in the class */ inline EpsRational operator * (const Rational& a) const { DebugAssert(type == FINITE, "EpsRational::operator *, multiplying an infinite number"); return EpsRational(a * q, a * k); } /** * Division operator EpsRational number and a rational number. * * @param a the number to be multiplied * @return the product as defined in the class */ inline EpsRational operator / (const Rational& a) const { DebugAssert(type == FINITE, "EpsRational::operator *, dividing an infinite number"); return EpsRational(q / a, k / a); } /** * Equality comparison operator. */ inline bool operator == (const EpsRational& r) const { return (q == r.q && k == r.k); } /** * Less than or equal comparison operator. */ inline bool operator <= (const EpsRational& r) const { switch (r.type) { case FINITE: if (type == FINITE) // Normal comparison return (q < r.q || (q == r.q && k <= r.k)); else // Finite number is bigger only of the negative infinity return type == MINUS_INFINITY; case PLUS_INFINITY: // Everything is less then or equal than +inf return true; case MINUS_INFINITY: // Only -inf is less then or equal than -inf return (type == MINUS_INFINITY); default: // Ohohohohohoooooo, whats up FatalAssert(false, "EpsRational::operator <=, what kind of number is this????"); } return false; } /** * Less than comparison operator. */ inline bool operator < (const EpsRational& r) const { return !(r <= *this); } /** * Greater than comparison operator. */ inline bool operator > (const EpsRational& r) const { return !(*this <= r); } /** * Returns the string representation of the number. * * @return the string representation of the number */ std::string toString() const { switch (type) { case FINITE: return "(" + q.toString() + ", " + k.toString() + ")"; case PLUS_INFINITY: return "+inf"; case MINUS_INFINITY: return "-inf"; default: FatalAssert(false, "EpsRational::toString, what kind of number is this????"); } return "hm, what am I?"; } }; struct EdgeInfo { /** The length of this edge */ EpsRational length; /** The number of edges in this path */ int path_length_in_edges; /** If this is a summary edge, a vertex in the path */ Expr in_path_vertex; /** If this is an original edge, the theorem that explains it */ Theorem explanation; /** Returnes if the edge is well define (i.e. not +infinity) */ bool isDefined() const { return path_length_in_edges != 0; } EdgeInfo(): path_length_in_edges(0) {} }; /** * Given two vertices in the graph and an path edge, reconstruct all the theorems and put them * in the output vector */ void getEdgeTheorems(const Expr& x, const Expr& y, const EdgeInfo& edgeInfo, std::vector& outputTheorems); /** * Returns the current weight of the edge. */ EpsRational getEdgeWeight(const Expr& x, const Expr& y); /** * Returns whether a vertex has incoming edges. */ bool hasIncoming(const Expr& x); /** * Returns whether a vertex has outgoing edges. */ bool hasOutgoing(const Expr& x); protected: /** Threshold on path length to process (ignore bigger than and set incomplete) */ const int* d_pathLenghtThres; /** The arithmetic that's using this graph */ TheoryArithOld* arith; /** The core theory */ TheoryCore* core; /** The arithmetic that is using u us */ ArithProofRules* rules; /** The unsat theorem if available */ CDO unsat_theorem; /** The biggest epsilon from EpsRational we used in paths */ CDO biggestEpsilon; /** The smallest rational difference we used in path relaxation */ CDO smallestPathDifference; /** The graph itself, maps expressions (x-y) to the edge information */ typedef CDMap Graph; /** Graph of <= paths */ Graph leGraph; typedef ExprMap*> EdgesList; /** List of vertices adjacent backwards to a vertex */ EdgesList incomingEdges; /** List of vertices adjacent forward to a vertex */ EdgesList outgoingEdges; /** * Returns the edge (path) info for the given kind * * @param x the starting vertex * @param y the ending vertex * @return the edge information */ Graph::ElementReference getEdge(const Expr& x, const Expr& y); /** * Try to update the shortest path from x to z using y. */ bool tryUpdate(const Expr& x, const Expr& y, const Expr& z); public: void writeGraph(std::ostream& out); /** * Fills the vector with all the variables (vertices) in the graph */ void getVariables(std::vector& variables); void setRules(ArithProofRules* rules) { this->rules = rules; } void setArith(TheoryArithOld* arith) { this->arith = arith; } /** * Class constructor. */ DifferenceLogicGraph(TheoryArithOld* arith, TheoryCore* core, ArithProofRules* rules, Context* context); /** * Destructor */ ~DifferenceLogicGraph(); /** * Returns the reference to the unsat theorem if there is a negative * cycle in the graph. * * @return the unsat theorem */ Theorem getUnsatTheorem(); /** * Returns true if there is a negative cycle in the graph. */ bool isUnsat(); void computeModel(); Rational getValuation(const Expr& x); /** * Adds an edge corresponding to the constraint x - y <= c. * * @param x variable x::Difference * @param y variable y * @param c rational c * @param edge_thm the theorem for this edge */ void addEdge(const Expr& x, const Expr& y, const Rational& c, const Theorem& edge_thm); /** * Check if there is an edge from x to y */ bool existsEdge(const Expr& x, const Expr& y); /** * Check if x is in a cycle */ bool inCycle(const Expr& x); /** * Given a shared integer term expand it into the gray shadow on the bounds (if bounded from both sides). */ void expandSharedTerm(const Expr& x); protected: /** Whether the variable is in a cycle */ CDMap varInCycle; Expr sourceVertex; /** * Produced the unsat theorem from a cycle x --> x of negative length * * @param x the variable to use for the conflict * @param kind the kind of edges to consider */ void analyseConflict(const Expr& x, int kind); }; /** The graph for difference logic */ DifferenceLogicGraph diffLogicGraph; Expr zero; /** Index for expanding on shared term equalities */ CDO shared_index_1; /** Index for expanding on shared term equalities */ CDO shared_index_2; std::vector multiplicativeSignSplits; int termDegree(const Expr& e); bool canPickEqMonomial(const Expr& right); private: // Keeps all expressions that are bounded for disequality splitting and shared term comparisons CDMap termUpperBounded; CDMap termLowerBounded; CDMap d_varConstrainedPlus; CDMap d_varConstrainedMinus; // Keeps all expressions that are constrained CDMap termConstrainedBelow; CDMap termConstrainedAbove; enum BoundsQueryType { /** Query the bounds/constrained using cache for leaves */ QueryWithCacheLeaves, /** Query the bounds/constrained using cashe for leaves, but also see if the value is constrained */ QueryWithCacheLeavesAndConstrainedComputation, /** Query the bounds/constrained by only querying the cache, don't try to figure it out */ QueryWithCacheAll }; /** * Check if the term is bounded. If the term is non-linear, just returns false. */ bool isBounded(const Expr& t, BoundsQueryType queryType = QueryWithCacheLeaves); bool hasLowerBound(const Expr& t, BoundsQueryType queryType = QueryWithCacheLeaves) { return getLowerBound(t, queryType).isFinite(); } bool hasUpperBound(const Expr& t, BoundsQueryType queryType = QueryWithCacheLeaves) { return getUpperBound(t, queryType).isFinite(); } bool isConstrained(const Expr& t, bool intOnly = true, BoundsQueryType queryType = QueryWithCacheLeaves); bool isConstrainedAbove(const Expr& t, BoundsQueryType queryType = QueryWithCacheLeaves); bool isConstrainedBelow(const Expr& t, BoundsQueryType queryType = QueryWithCacheLeaves); /** * Check if the term is bounded from above. If the term is non-linear, just returns false. */ DifferenceLogicGraph::EpsRational getUpperBound(const Expr& t, BoundsQueryType queryType = QueryWithCacheLeaves); /** * Check if the term is bouned from below. If the term is non-linear, just return false. */ DifferenceLogicGraph::EpsRational getLowerBound(const Expr& t, BoundsQueryType queryType = QueryWithCacheLeaves); /** * See whether and which terms are bounded. */ int computeTermBounds(); public: void updateConstrained(const Expr& t); bool isUnconstrained(const Expr& t); void tryPropagate(const Expr& x, const Expr& y, const DifferenceLogicGraph::EdgeInfo& x_y_edge, int kind); void addMultiplicativeSignSplit(const Theorem& case_split_thm); bool addPairToArithOrder(const Expr& smaller, const Expr& bigger); bool nonlinearSignSplit() const { return *d_splitSign; } /** * Check if equation is nonlinear. An equation is nonlinear if there is at least one nonlinear term in the sum * on either side of the equation. */ bool isNonlinearEq(const Expr& e); /** * Check if a sum term is nonlinear */ bool isNonlinearSumTerm(const Expr& term); /** * Check if the equality is of the form c + power1^n - power2^n = 0; */ bool isPowersEquality(const Expr& nonlinearEq, Expr& power1, Expr& power2); /** * Check if the equality is of the form c - x^n = 0 */ bool isPowerEquality(const Expr& nonlinearEq, Rational& constant, Expr& power1); }; } #endif cvc3-2.4.1/src/include/cnf.h0000664000175400017540000001360611165227612015420 0ustar mdetersmdeters/*****************************************************************************/ /*! *\file cnf.h *\brief Basic classes for reasoning about formulas in CNF * * Author: Clark Barrett * * Created: Mon Dec 12 20:32:33 2005 * *
* * License to use, copy, modify, sell and/or distribute this software * and its documentation for any purpose is hereby granted without * royalty, subject to the terms and conditions defined in the \ref * LICENSE file provided with this distribution. * *
*/ /*****************************************************************************/ #ifndef _cvc3__include__cnf_h_ #define _cvc3__include__cnf_h_ #include #include "compat_hash_map.h" #include "cvc_util.h" #include "cdo.h" #include "cdlist.h" #include "theorem.h" namespace SAT { class Var { int d_index; public: enum Val { UNKNOWN = -1, FALSE_VAL, TRUE_VAL}; static Val invertValue(Val); Var() : d_index(-1) {} Var(int index) :d_index(index) {} operator int() { return d_index; } bool isNull() const { return d_index == -1; } void reset() { d_index = -1; } int getIndex() const { return d_index; } bool isVar() const { return d_index > 0; } bool operator==(const Var& var) const { return (d_index == var.d_index); } }; inline Var::Val Var::invertValue(Var::Val v) { return v == Var::UNKNOWN ? Var::UNKNOWN : Var::Val(1-v); } class Lit { int d_index; static Lit mkLit(int index) { Lit l; l.d_index = index; return l; } public: Lit() : d_index(0) {} explicit Lit(Var v, bool positive=true) { if (v.isNull()) d_index = 0; else d_index = positive ? v+1 : -v-1; } static Lit getTrue() { return mkLit(1); } static Lit getFalse() { return mkLit(-1); } bool isNull() const { return d_index == 0; } bool isPositive() const { return d_index > 1; } bool isInverted() const { return d_index < -1; } bool isFalse() const { return d_index == -1; } bool isTrue() const { return d_index == 1; } bool isVar() const { return abs(d_index) > 1; } int getID() const { return d_index; } Var getVar() const { DebugAssert(isVar(),"Bad call to Lit::getVar"); return abs(d_index)-1; } void reset() { d_index = 0; } friend Lit operator!(const Lit& lit) { return mkLit(-lit.d_index); } }; class Clause { int d_satisfied:1; int d_unit:1; std::vector d_lits; CVC3::Theorem d_reason; //the theorem for the clause, used in proofs. by yeting public: Clause(): d_satisfied(0), d_unit(0) { }; Clause(const Clause& clause) : d_satisfied(clause.d_satisfied), d_unit(clause.d_unit), d_lits(clause.d_lits), d_reason(clause.d_reason) { }; typedef std::vector::const_iterator const_iterator; const_iterator begin() const { return d_lits.begin(); } const_iterator end() const { return d_lits.end(); } void clear() { d_satisfied = d_unit = 0; d_lits.clear(); } unsigned size() const { return d_lits.size(); } void addLiteral(Lit l) { if (!d_satisfied) d_lits.push_back(l); } unsigned getMaxVar() const; bool isSatisfied() const { return d_satisfied != 0; } bool isUnit() const { return d_unit != 0; } bool isNull() const { return d_lits.size() == 0; } void setSatisfied() { d_satisfied = 1; } void setUnit() { d_unit = 1; } void print() const; void setClauseTheorem(CVC3::Theorem thm){ d_reason = thm;} CVC3::Theorem getClauseTheorem() const { return d_reason;} }; class CNF_Formula { protected: Clause* d_current; virtual void setNumVars(unsigned numVars) = 0; void copy(const CNF_Formula& cnf); public: CNF_Formula() : d_current(NULL) {} virtual ~CNF_Formula() {} typedef std::deque::const_iterator const_iterator; virtual bool empty() const = 0; virtual const Clause& operator[](int i) const = 0; virtual const_iterator begin() const = 0; virtual const_iterator end() const = 0; virtual unsigned numVars() const = 0; virtual unsigned numClauses() const = 0; virtual void newClause() = 0; virtual void registerUnit() = 0; void addLiteral(Lit l, bool invert=false) { if (l.isVar() && unsigned(l.getVar()) > numVars()) setNumVars(l.getVar()); d_current->addLiteral(invert ? !l : l); } Clause& getCurrentClause() { return *d_current; } void print() const; const CNF_Formula& operator+=(const CNF_Formula& cnf); const CNF_Formula& operator+=(const Clause& c); }; class CNF_Formula_Impl :public CNF_Formula { std::hash_map d_lits; std::deque d_formula; unsigned d_numVars; private: void setNumVars(unsigned numVars) { d_numVars = numVars; } public: CNF_Formula_Impl() : CNF_Formula(), d_numVars(0) {} CNF_Formula_Impl(const CNF_Formula& cnf) : CNF_Formula() { copy(cnf); } ~CNF_Formula_Impl() {}; bool empty() const { return d_formula.empty(); } const Clause& operator[](int i) const { return d_formula[i]; } const_iterator begin() const { return d_formula.begin(); } const_iterator end() const { return d_formula.end(); } unsigned numVars() const { return d_numVars; } unsigned numClauses() const { return d_formula.size(); } void deleteLast() { DebugAssert(d_formula.size() > 0, "size == 0"); d_formula.pop_back(); } void newClause(); void registerUnit(); void simplify(); void reset(); }; class CD_CNF_Formula :public CNF_Formula { CVC3::CDList d_formula; CVC3::CDO d_numVars; private: void setNumVars(unsigned numVars) { d_numVars = numVars; } public: CD_CNF_Formula(CVC3::Context* context) : CNF_Formula(), d_formula(context), d_numVars(context, 0, 0) {} ~CD_CNF_Formula() {} bool empty() const { return d_formula.empty(); } const Clause& operator[](int i) const { return d_formula[i]; } const_iterator begin() const { return d_formula.begin(); } const_iterator end() const { return d_formula.end(); } unsigned numVars() const { return d_numVars.get(); } unsigned numClauses() const { return d_formula.size(); } void deleteLast() { d_formula.pop_back(); } void newClause(); void registerUnit(); }; } #endif cvc3-2.4.1/src/include/theory.h0000664000175400017540000007001011323220245016143 0ustar mdetersmdeters/*****************************************************************************/ /*! * \file theory.h * \brief Generic API for Theories plus methods commonly used by theories * * Author: Clark Barrett * * Created: Sat Nov 30 23:30:15 2002 * *
* * License to use, copy, modify, sell and/or distribute this software * and its documentation for any purpose is hereby granted without * royalty, subject to the terms and conditions defined in the \ref * LICENSE file provided with this distribution. * *
* */ /*****************************************************************************/ #ifndef _cvc3__include__theory_h_ #define _cvc3__include__theory_h_ #include "expr_stream.h" #include "common_proof_rules.h" #include "cdlist.h" namespace CVC3 { class TheoryCore; class Theorem; class Type; /************************************************************************/ /*! *\defgroup Theories Theories *\ingroup VC *\brief Theories *@{ */ /***********************************************************************/ /*****************************************************************************/ /*! *\anchor Theory *\class Theory *\brief Base class for theories * * Author: Clark Barrett * * Created: Thu Jan 30 16:37:56 2003 * * This is an abstract class which all theories should inherit from. In * addition to providing an abstract theory interface, it provides access * functions to core functionality. However, in order to avoid duplicating the * data structures which implement this functionality, all the functionality is * stored in a separate class (which actually derives from this one) called * TheoryCore. These two classes work closely together to provide the core * functionality. */ /*****************************************************************************/ class Theory { friend class TheoryCore; private: ExprManager* d_em; TheoryCore* d_theoryCore; //!< Provides the core functionality CommonProofRules* d_commonRules; //!< Commonly used proof rules std::string d_name; //!< Name of the theory (for debugging) //! Private default constructor. /*! Everyone besides TheoryCore has to use the public constructor which sets up all the provided functionality automatically. */ Theory(void); protected: bool d_theoryUsed; //! Whether theory has been used (for smtlib translator) public: //! Exposed constructor. /*! Note that each instance of Theory must have a name (mostly for debugging purposes). */ Theory(TheoryCore* theoryCore, const std::string& name); //! Destructor virtual ~Theory(void); //! Access to ExprManager ExprManager* getEM() { return d_em; } //! Get a pointer to theoryCore TheoryCore* theoryCore() { return d_theoryCore; } //! Get a pointer to common proof rules CommonProofRules* getCommonRules() { return d_commonRules; } //! Get the name of the theory (for debugging purposes) const std::string& getName() const { return d_name; } //! Set the "used" flag on this theory (for smtlib translator) virtual void setUsed() { d_theoryUsed = true; } //! Get whether theory has been used (for smtlib translator) virtual bool theoryUsed() { return d_theoryUsed; } /***************************************************************************/ /*! *\defgroup Theory_API Abstract Theory Interface *\anchor theory_api *\ingroup Theories *\brief Abstract Theory Interface * * These are the theory-specific methods which provide the decision procedure * functionality for a new theory. At the very least, a theory must * implement the checkSat method. The other methods can be used to make the * implementation more convenient. For more information on this API, see * Clark Barrett's PhD dissertation and \ref theory_api_howto. *@{ */ /***************************************************************************/ //! Notify theory of a new shared term /*! When a term e associated with theory i occurs as a child of an expression associated with theory j, the framework calls i->addSharedTerm(e) and j->addSharedTerm(e) */ virtual void addSharedTerm(const Expr& e) {} //! Assert a new fact to the decision procedure /*! Each fact that makes it into the core framework is assigned to exactly one theory: the theory associated with that fact. assertFact is called to inform the theory that a new fact has been assigned to the theory. */ virtual void assertFact(const Theorem& e) = 0; //! Check for satisfiability in the theory /*! \param fullEffort when it is false, checkSat can do as much or as little work as it likes, though simple inferences and checks for consistency should be done to increase efficiency. If fullEffort is true, checkSat must check whether the set of facts given by assertFact together with the arrangement of shared terms (provided by addSharedTerm) induced by the global find database equivalence relation are satisfiable. If satisfiable, checkSat does nothing. If satisfiability can be acheived by merging some of the shared terms, a new fact must be enqueued using enqueueFact (this fact need not be a literal). If there is no way to make things satisfiable, setInconsistent must be called. */ virtual void checkSat(bool fullEffort) = 0; //! Theory-specific rewrite rules. /*! By default, rewrite just returns a reflexive theorem stating that the input expression is equivalent to itself. However, rewrite is allowed to return any theorem which describes how the input expression is equivalent to some new expression. rewrite should be used to perform simplifications, normalization, and any other preprocessing on theory-specific expressions that needs to be done. */ virtual Theorem rewrite(const Expr& e) { return reflexivityRule(e); } //! Theory-specific preprocessing /*! This gets called each time a new assumption or query is preprocessed. By default it does nothing. */ virtual Theorem theoryPreprocess(const Expr& e) { return reflexivityRule(e); } //! Set up the term e for call-backs when e or its children change. /*! setup is called once for each expression associated with the theory. It is typically used to setup theory-specific data for an expression and to add call-back information for use with update. \sa update */ virtual void setup(const Expr& e) {} //! Notify a theory of a new equality /*! update is a call-back used by the notify mechanism of the core theory. It works as follows. When an equation t1 = t2 makes it into the core framework, the two find equivalence classes for t1 and t2 are merged. The result is that t2 is the new equivalence class representative and t1 is no longer an equivalence class representative. When this happens, the notify list of t1 is traversed. Notify list entries consist of a theory and an expression d. For each entry (i,d), i->update(e, d) is called, where e is the theorem corresponding to the equality t1=t2. To add the entry (i,d) to a term t1's notify list, a call must be made to t1.addNotify(i,d). This is typically done in setup. \sa setup */ virtual void update(const Theorem& e, const Expr& d) {} //! An optional solver. /*! The solve method can be used to implement a Shostak-style solver. Since solvers do not in general combine, the following technique is used. One theory is designated as the primary solver (in our case, it is the theory of arithmetic). For each equation that enters the core framework, the primary solver is called to ensure that the equation is in solved form with respect to the primary theory. After the primary solver, the solver for the theory associated with the equation is called. This solver can do whatever it likes, as long as the result is still in solved form with respect to the primary solver. This is a slight generalization of what is described in my (Clark)'s PhD thesis. */ virtual Theorem solve(const Theorem& e) { return e; } //! A debug check used by the primary solver virtual void checkAssertEqInvariant(const Theorem& e) { } ///////////////////////////////// // Extensions to original API: // ///////////////////////////////// //! Recursive simplification step /*! * INVARIANT: the result is a Theorem(e=e'), where e' is a fully * simplified version of e. To simplify subexpressions recursively, * call simplify() function. * * This theory-specific method is called when the simplifier * descends top-down into the expression. Normally, every kid is * simplified recursively, and the results are combined into the new * parent with the same operator (Op). This functionality is * provided with the default implementation. * * However, in some expressions some kids may not matter in the * result, and can be skipped. For instance, if the first kid in a * long AND simplifies to FALSE, then the entire expression * simplifies to FALSE, and the remaining kids do not need to be * simplified. * * This call is a chance for a DP to provide these types of * optimizations during the top-down phase of simplification. */ virtual Theorem simplifyOp(const Expr& e); //! Check that e is a valid Type expr virtual void checkType(const Expr& e) { throw Exception("Cannot construct type from expr: "+e.toString()); } //! Compute information related to finiteness of types /*! Used by the TypeComputer defined in TheoryCore (theories should not call this * funtion directly -- they should use the methods in Type instead). Each theory * should implement this if it contains any types that could be non-infinite. * * 1. Returns Cardinality of the type (finite, infinite, or unknown) * 2. If cardinality = finite and enumerate is true, * sets e to the nth element of the type if it can * sets e to NULL if n is out of bounds or if unable to compute nth element * 3. If cardinality = finite and computeSize is true, * sets n to the size of the type if it can * sets n to 0 otherwise */ virtual Cardinality finiteTypeInfo(Expr& e, Unsigned& n, bool enumerate, bool computeSize) { return CARD_INFINITE; } //! Compute and store the type of e /*! * \param e is the expression whose type is computed. * * This function computes the type of the top-level operator of e, * and recurses into children using getType(), if necessary. */ virtual void computeType(const Expr& e) {} //! Compute the base type of the top-level operator of an arbitrary type virtual Type computeBaseType(const Type& tp) { return tp; } /*! @brief Theory specific computation of the subtyping predicate for * type t applied to the expression e. */ /*! By default returns true. Each theory needs to compute subtype predicates * for the types associated with it. So, for example, the theory of records * will take a record type [# f1: T1, f2: T2 #] and an expression e * and will return the subtyping predicate for e, namely: * computeTypePred(T1, e.f1) AND computeTypePred(T2, e.f2) */ virtual Expr computeTypePred(const Type& t, const Expr& e) { return e.getEM()->trueExpr(); } //! Compute and cache the TCC of e. /*! * \param e is an expression (term or formula). This function * computes the TCC of e which is true iff the expression is defined. * * This function computes the TCC or predicate of the top-level * operator of e, and recurses into children using getTCC(), if * necessary. * * The default implementation is to compute TCCs recursively for all * children, and return their conjunction. */ virtual Expr computeTCC(const Expr& e); //! Theory-specific parsing implemented by the DP virtual Expr parseExprOp(const Expr& e) { return e; } //! Theory-specific pretty-printing. /*! By default, print the top node in AST, and resume pretty-printing the children. The same call e.print(os) can be used in DP-specific printers to use AST printing for the given node. In fact, it is strongly recommended to add e.print(os) as the default for all the cases/kinds that are not handled by the particular pretty-printer. */ virtual ExprStream& print(ExprStream& os, const Expr& e) { return e.printAST(os); } //! Add variables from 'e' to 'v' for constructing a concrete model /*! If e is already of primitive type, do NOT add it to v. */ virtual void computeModelTerm(const Expr& e, std::vector& v); //! Process disequalities from the arrangement for model generation virtual void refineCounterExample() {} //! Assign concrete values to basic-type variables in v virtual void computeModelBasic(const std::vector& v) {} //! Compute the value of a compound variable from the more primitive ones /*! The more primitive variables for e are already assigned concrete * values, and are available through getModelValue(). * * The new value for e must be assigned using assignValue() method. * * \param e is the compound type expression to assign a value; * * \param vars are the variables actually assigned. Normally, 'e' * is the only element of vars. However, e.g. in the case of * uninterpreted functions, assigning 'f' means assigning all * relevant applications of 'f' to constant values (f(0), f(5), * etc.). Such applications might not be known before the model is * constructed (they may be of the form f(x), f(y+z), etc., where * x,y,z are still unassigned). * * Populating 'vars' is an opportunity for a DP to change the set of * top-level "variables" to assign, if needed. In particular, it * may drop 'e' from the model entirely, if it is already a concrete * value by itself. */ virtual void computeModel(const Expr& e, std::vector& vars) { assignValue(find(e)); vars.push_back(e); } //! Receives all the type predicates for the types of the given theory /*! Type predicates may be expensive to enqueue eagerly, and DPs may choose to postpone them, or transform them to something more efficient. By default, the asserted type predicate is immediately enqueued as a new fact. Note: Used only by bitvector theory. \param e is the expression for which the type predicate is computed \param pred is the predicate theorem P(e) */ virtual void assertTypePred(const Expr& e, const Theorem& pred) { enqueueFact(pred); } //! Theory-specific rewrites for atomic formulas /*! The intended use is to convert complex atomic formulas into an * equivalent Boolean combination of simpler formulas. Such * conversion may be harmful for algebraic rewrites, and is not * always desirable to have in rewrite() method. * * Note: Used only by bitvector theory and rewriteLiteral in core. * * However, if rewrite() alone cannot solve the problem, and the SAT * solver needs to be envoked, these additional rewrites may ease * the job for the SAT solver. */ virtual Theorem rewriteAtomic(const Expr& e) { return reflexivityRule(e); } //! Notification of conflict /*! * Decision procedures implement this method when they want to be * notified about a conflict. * * Note: Used only by quantifier theory * * \param thm is the theorem of FALSE given to setInconsistent() */ virtual void notifyInconsistent(const Theorem& thm) { } virtual void registerAtom(const Expr& e, const Theorem& thm); //! Theory-specific registration of atoms /*! * If a theory wants to implement its own theory propagation, it * should implement this method and use it to collect all atoms * that the core is interested in. If the theory can deduce the atom * or its negation, it should do so (using enqueueFact). */ virtual void registerAtom(const Expr& e) { } #ifdef _CVC3_DEBUG_MODE //! Theory-specific debug function virtual void debug(int i) { } //! help function, as debug(int i). yeting virtual int help(int i) { return 9999 ;} ; #endif /*@}*/ // End of Theory_API group /***************************************************************************/ /*! *\name Core Framework Functionality * These methods provide convenient access to core functionality for the * benefit of decision procedures. *@{ */ /***************************************************************************/ //! Check if the current context is inconsistent virtual bool inconsistent(); //! Make the context inconsistent; The formula proved by e must FALSE. virtual void setInconsistent(const Theorem& e); //! Mark the current decision branch as possibly incomplete /*! * This should be set when a decision procedure uses an incomplete * algorithm, and cannot guarantee satisfiability after the final * checkSat() call with full effort. An example would be * instantiation of universal quantifiers. * * A decision procedure can provide a reason for incompleteness, * which will be reported back to the user. */ virtual void setIncomplete(const std::string& reason); //! Simplify a term e and return a Theorem(e==e') /*! \sa simplifyExpr() */ virtual Theorem simplify(const Expr& e); //! Simplify a term e w.r.t. the current context /*! \sa simplify */ Expr simplifyExpr(const Expr& e) { return simplify(e).getRHS(); } //! Submit a derived fact to the core from a decision procedure /*! \param e is the Theorem for the new fact */ virtual void enqueueFact(const Theorem& e); virtual void enqueueSE(const Theorem& e); //! Handle new equalities (usually asserted through addFact) /*! * INVARIANT: the Theorem 'e' is an equality e1==e2, where e2 is * i-leaf simplified in the current context, or a conjunction of * such equalities. * */ virtual void assertEqualities(const Theorem& e); //! Parse the generic expression. /*! This method should be used in parseExprOp() for recursive calls * to subexpressions, and is the method called by the command * processor. */ virtual Expr parseExpr(const Expr& e); //! Assigns t a concrete value val. Used in model generation. virtual void assignValue(const Expr& t, const Expr& val); //! Record a derived assignment to a variable (LHS). virtual void assignValue(const Theorem& thm); /*@}*/ // End of Core Framework Functionality /***************************************************************************/ /*! *\name Theory Helper Methods * These methods provide basic functionality needed by all theories. *@{ */ /***************************************************************************/ //! Register new kinds with the given theory void registerKinds(Theory* theory, std::vector& kinds); //! Unregister kinds for a theory void unregisterKinds(Theory* theory, std::vector& kinds); //! Register a new theory void registerTheory(Theory* theory, std::vector& kinds, bool hasSolver=false); //! Unregister a theory void unregisterTheory(Theory* theory, std::vector& kinds, bool hasSolver); //! Return the number of registered theories int getNumTheories(); //! Test whether a kind maps to any theory bool hasTheory(int kind); //! Return the theory associated with a kind Theory* theoryOf(int kind); //! Return the theory associated with a type Theory* theoryOf(const Type& e); //! Return the theory associated with an Expr Theory* theoryOf(const Expr& e); //! Return the theorem that e is equal to its find Theorem find(const Expr& e); //! Return the find as a reference: expr must have a find const Theorem& findRef(const Expr& e); //! Return find-reduced version of e Theorem findReduce(const Expr& e); //! Return true iff e is find-reduced bool findReduced(const Expr& e); //! Return the find of e, or e if it has no find inline Expr findExpr(const Expr& e) { return e.hasFind() ? find(e).getRHS() : e; } //! Compute the TCC of e, or the subtyping predicate, if e is a type Expr getTCC(const Expr& e); //! Compute (or look up in cache) the base type of e and return the result Type getBaseType(const Expr& e); //! Compute the base type from an arbitrary type Type getBaseType(const Type& tp); //! Calls the correct theory to compute a type predicate Expr getTypePred(const Type& t, const Expr& e); //! Update the children of the term e /*! When a decision procedure receives a call to update() because a child of a term 'e' has changed, this method can be called to compute the new value of 'e'. \sa update */ Theorem updateHelper(const Expr& e); //! Setup a term for congruence closure (must have sig and rep attributes) void setupCC(const Expr& e); //! Update a term w.r.t. congruence closure (must be setup with setupCC()) void updateCC(const Theorem& e, const Expr& d); //! Rewrite a term w.r.t. congruence closure (must be setup with setupCC()) Theorem rewriteCC(const Expr& e); /*! @brief Calls the correct theory to get all of the terms that need to be assigned values in the concrete model */ void getModelTerm(const Expr& e, std::vector& v); //! Fetch the concrete assignment to the variable during model generation Theorem getModelValue(const Expr& e); //! Suggest a splitter to the SearchEngine void addSplitter(const Expr& e, int priority = 0); //! Add a global lemma void addGlobalLemma(const Theorem& thm, int priority = 0); /*@}*/ // End of Theory Helper Methods /***************************************************************************/ /*! *\name Core Testers *@{ */ /***************************************************************************/ //! Test if e is an i-leaf term for the current theory /*! A term 'e' is an i-leaf for a theory 'i', if it is a variable, or 'e' belongs to a different theory. This definition makes sense for a larger term which by itself belongs to the current theory 'i', but (some of) its children are variables or belong to different theories. */ bool isLeaf(const Expr& e) { return e.isVar() || theoryOf(e) != this; } //! Test if e1 is an i-leaf in e2 /*! \sa isLeaf */ bool isLeafIn(const Expr& e1, const Expr& e2); //! Test if all i-leaves of e are simplified /*! \sa isLeaf */ bool leavesAreSimp(const Expr& e); /*@}*/ // End of Core Testers /***************************************************************************/ /*! *\name Common Type and Expr Methods *@{ */ /***************************************************************************/ //! Return BOOLEAN type Type boolType() { return Type::typeBool(d_em); } //! Return FALSE Expr const Expr& falseExpr() { return d_em->falseExpr(); } //! Return TRUE Expr const Expr& trueExpr() { return d_em->trueExpr(); } //! Create a new variable given its name and type /*! Add the variable to the database for resolving IDs in parseExpr */ Expr newVar(const std::string& name, const Type& type); //! Create a new named expression given its name, type, and definition /*! Add the definition to the database for resolving IDs in parseExpr */ Expr newVar(const std::string& name, const Type& type, const Expr& def); //! Create a new uninterpreted function /*! Add the definition to the database for resolving IDs in parseExpr */ Op newFunction(const std::string& name, const Type& type, bool computeTransClosure); //! Look up a function by name. /*! Returns the function and sets type to the type of the function if it * exists. If not, returns a NULL Op object. */ Op lookupFunction(const std::string& name, Type* type); //! Create a new defined function /*! Add the definition to the database for resolving IDs in parseExpr */ Op newFunction(const std::string& name, const Type& type, const Expr& def); //! Create and add a new bound variable to the stack, for parseExprOp(). /*! * The stack is popped automatically upon return from the * parseExprOp() which used this method. * * Bound variable names may repeat, in which case the latest * declaration takes precedence. */ Expr addBoundVar(const std::string& name, const Type& type); //! Create and add a new bound named def to the stack, for parseExprOp(). /*! * The stack is popped automatically upon return from the * parseExprOp() which used this method. * * Bound variable names may repeat, in which case the latest * declaration takes precedence. * * The type may be Null, but 'def' must always be a valid Expr */ Expr addBoundVar(const std::string& name, const Type& type, const Expr& def); /*! @brief Lookup variable and return it and its type. Return NULL Expr if it doesn't exist yet. */ Expr lookupVar(const std::string& name, Type* type); //! Create a new uninterpreted type with the given name /*! Add the name to the global variable database d_globals */ Type newTypeExpr(const std::string& name); //! Lookup type by name. Return Null if no such type exists. Type lookupTypeExpr(const std::string& name); //! Create a new type abbreviation with the given name Type newTypeExpr(const std::string& name, const Type& def); //! Create a new subtype expression Type newSubtypeExpr(const Expr& pred, const Expr& witness); //! Resolve an identifier, for use in parseExprOp() /*! * First, search the bound variable stack, and if the name is not * found, search the global constant and type declarations. * * \return an expression to use in place of the identifier, or Null * if cannot resolve the name. */ Expr resolveID(const std::string& name); //! Install name as a new identifier associated with Expr e void installID(const std::string& name, const Expr& e); Theorem typePred(const Expr& e); /*@}*/ // End of Common Type and Expr Methods /***************************************************************************/ /*! *\name Commonly Used Proof Rules *\anchor theory_api_core_proof_rules *@{ */ /***************************************************************************/ //! ==> a == a Theorem reflexivityRule(const Expr& a) { return d_commonRules->reflexivityRule(a); } //! a1 == a2 ==> a2 == a1 Theorem symmetryRule(const Theorem& a1_eq_a2) { return d_commonRules->symmetryRule(a1_eq_a2); } //! (a1 == a2) & (a2 == a3) ==> (a1 == a3) Theorem transitivityRule(const Theorem& a1_eq_a2, const Theorem& a2_eq_a3) { return d_commonRules->transitivityRule(a1_eq_a2, a2_eq_a3); } //! (c_1 == d_1) & ... & (c_n == d_n) ==> op(c_1,...,c_n) == op(d_1,...,d_n) Theorem substitutivityRule(const Op& op, const std::vector& thms) { return d_commonRules->substitutivityRule(op, thms); } //! Special case for unary operators Theorem substitutivityRule(const Expr& e, const Theorem& t) { return d_commonRules->substitutivityRule(e, t); } //! Special case for binary operators Theorem substitutivityRule(const Expr& e, const Theorem& t1, const Theorem& t2) { return d_commonRules->substitutivityRule(e, t1, t2); } //! Optimized: only positions which changed are included Theorem substitutivityRule(const Expr& e, const std::vector& changed, const std::vector& thms) { return d_commonRules->substitutivityRule(e, changed, thms); } //! Optimized: only a single position changed Theorem substitutivityRule(const Expr& e, int changed, const Theorem& thm) { return d_commonRules->substitutivityRule(e, changed, thm); } //! e1 AND (e1 IFF e2) ==> e2 Theorem iffMP(const Theorem& e1, const Theorem& e1_iff_e2) { return d_commonRules->iffMP(e1, e1_iff_e2); } //! ==> AND(e1,e2) IFF [simplified expr] Theorem rewriteAnd(const Expr& e) { return d_commonRules->rewriteAnd(e); } //! ==> OR(e1,...,en) IFF [simplified expr] Theorem rewriteOr(const Expr& e) { return d_commonRules->rewriteOr(e); } //! Derived rule for rewriting ITE Theorem rewriteIte(const Expr& e); //! Derived rule to create a new name for an expression Theorem renameExpr(const Expr& e); /*@}*/ // End of Commonly Used Proof Rules }; /*@}*/ // End of group Theories } #endif cvc3-2.4.1/src/include/os.h0000664000175400017540000000372111224473075015272 0ustar mdetersmdeters/*****************************************************************************/ /*! * \file os.h * \brief Abstraction over different operating systems. * * Author: Alexander Fuchs * * Created: Fri Feb 16 12:00:00 2007 * *
* * License to use, copy, modify, sell and/or distribute this software * and its documentation for any purpose is hereby granted without * royalty, subject to the terms and conditions defined in the \ref * LICENSE file provided with this distribution. * *
* */ /*****************************************************************************/ #ifndef _cvc3__windows_h_ #define _cvc3__windows_h_ // define if cvc3lib built as a dll, comment if cvc3lib is linked statically // #define CVC_DLL_LINKAGE // library export of C++ symbols for C++ windows interface // for dynamic binding dll export needed #ifdef CVC_DLL_LINKAGE #ifdef CVC_DLL_EXPORT #define CVC_DLL __declspec(dllexport) #elif CVC_DLL_IMPORT #define CVC_DLL __declspec(dllimport) #else #define CVC_DLL #endif // for static binding dll export not needed #else #define CVC_DLL #endif #ifndef _LINUX_WINDOWS_CROSS_COMPILE /// MS C++ specific settings #ifdef _MSC_VER // CLR specific settings // #ifdef _MANAGED // if lex files are created with cygwin they require isatty, // which in MS VS C++ requires using _isatty #include #define isatty _isatty // C99 stdint data types typedef signed __int8 int8_t; typedef signed __int16 int16_t; typedef signed __int32 int32_t; typedef signed __int64 int64_t; typedef unsigned __int8 uint8_t; typedef unsigned __int16 uint16_t; typedef unsigned __int32 uint32_t; typedef unsigned __int64 uint64_t; // unix specific settings #else // C99 data types // (should) provide: // int8_t, int16_t, int32_t, int64_t, uint8_t, uint16_t, uint32_t, uint64_tm // intptr_t, uintptr_t #include #endif #else // Cross-compile include the same as for unix #include #endif #endif cvc3-2.4.1/src/include/theory_quant.h0000644000175400017540000005623011604636626017401 0ustar mdetersmdeters/*****************************************************************************/ /*! * \file theory_quant.h * * Author: Sergey Berezin, Yeting Ge * * Created: Jun 24 21:13:59 GMT 2003 * *
* * License to use, copy, modify, sell and/or distribute this software * and its documentation for any purpose is hereby granted without * royalty, subject to the terms and conditions defined in the \ref * LICENSE file provided with this distribution. * *
* * ! Author: Daniel Wichs * ! Created: Wednesday July 2, 2003 * * */ /*****************************************************************************/ #ifndef _cvc3__include__theory_quant_h_ #define _cvc3__include__theory_quant_h_ #include "theory.h" #include "cdmap.h" #include "statistics.h" #include namespace CVC3 { class QuantProofRules; /*****************************************************************************/ /*! *\class TheoryQuant *\ingroup Theories *\brief This theory handles quantifiers. * * Author: Daniel Wichs * * Created: Wednesday July 2, 2003 */ /*****************************************************************************/ typedef enum{ Ukn, Pos, Neg, PosNeg} Polarity; class Trigger { public: Expr trig; Polarity polarity; std::vector bvs; Expr head; bool hasRWOp; bool hasTrans; bool hasT2; //if has trans of 2, bool isSimple; //if of the form g(x,a); bool isSuperSimple; //if of the form g(x,y); bool isMulti; size_t multiIndex; size_t multiId; Trigger(TheoryCore* core, Expr e, Polarity pol, std::set); bool isPos(); bool isNeg(); Expr getEx(); std::vector getBVs(); void setHead(Expr h); Expr getHead(); void setRWOp(bool b); bool hasRW(); void setTrans(bool b); bool hasTr(); void setTrans2(bool b); bool hasTr2(); void setSimp(); bool isSimp(); void setSuperSimp(); bool isSuperSimp(); void setMultiTrig(); bool isMultiTrig(); }; typedef struct dynTrig{ Trigger trig; size_t univ_id; ExprMap binds; dynTrig(Trigger t, ExprMap b, size_t id); } dynTrig; class CompleteInstPreProcessor { TheoryCore* d_theoryCore; //needed by plusOne and minusOne; QuantProofRules* d_quant_rules; std::set d_allIndex; //a set contains all index ExprMap d_expr_pol ;//map a expr to its polarity ExprMap d_quant_equiv_map ; //map a quant to its equivalent form std::vector d_gnd_cache; //cache of all ground formulas, before index can be collected, all such ground terms must be put into d_expr_pol. ExprMap d_is_macro_def;//if a quant is a macro quant ExprMap d_macro_quant;//map a macro to its macro quant. ExprMap d_macro_def;//map a macro head to its def. ExprMap d_macro_lhs;//map a macro to its lhs. //! if all formulas checked so far are good bool d_all_good ; //! if e satisfies the shiled property, that is all bound vars are parameters of uninterpreted functions/predicates and array reads/writes bool isShield(const Expr& e); bool hasShieldVar(const Expr& e); //! insert an index void addIndex(const Expr& e); void collect_shield_index(const Expr& e); void collect_forall_index(const Expr& forall_quant); //! if e is a quant in the array property fragmenet bool isGoodQuant(const Expr& e); //! return e+1 Expr plusOne(const Expr& e); //! return e-1 Expr minusOne(const Expr& e); void collectHeads(const Expr& assert, std::set& heads); //! if assert is a macro definition bool isMacro(const Expr& assert); Expr recInstMacros(const Expr& assert); Expr substMacro(const Expr&); Expr recRewriteNot(const Expr&, ExprMap&); //! rewrite neg polarity forall / exists to pos polarity Expr rewriteNot(const Expr &); Expr recSkolemize(const Expr &, ExprMap&); Expr pullVarOut(const Expr&); public : CompleteInstPreProcessor(TheoryCore * , QuantProofRules*); //! if e is a formula in the array property fragment bool isGood(const Expr& e); //! collect index for instantiation void collectIndex(const Expr & e); //! inst forall quant using index from collectIndex Expr inst(const Expr & e); //! if there are macros bool hasMacros(const std::vector& asserts); //! substitute a macro in assert Expr instMacros(const Expr& , const Expr ); //! simplify a=a to True Expr simplifyEq(const Expr &); //! put all quants in postive form and then skolemize all exists Expr simplifyQuant(const Expr &); }; class TheoryQuant :public Theory { Theorem rewrite(const Expr& e); Theorem theoryPreprocess(const Expr& e); class TypeComp { //!< needed for typeMap public: bool operator() (const Type t1, const Type t2) const {return (t1.getExpr() < t2.getExpr()); } }; //! used to facilitate instantiation of universal quantifiers typedef std::map, TypeComp > typeMap; //! database of universally quantified theorems CDList d_univs; CDList d_rawUnivs; CDList d_arrayTrigs; CDO d_lastArrayPos; //! universally quantified formulas to be instantiated, the var bindings is in d_bingQueue and the ground term matched with the trigger is in d_gtermQueue std::queue d_univsQueue; std::queue d_simplifiedThmQueue; std::queue d_gUnivQueue; std::queue d_gBindQueue; ExprMap > > d_tempBinds; //!tracks the possition of preds CDO d_lastPredsPos; //!tracks the possition of terms CDO d_lastTermsPos; //!tracks the positions of preds for partial instantiation CDO d_lastPartPredsPos; //!tracks the possition of terms for partial instantiation CDO d_lastPartTermsPos; //!tracks a possition in the database of universals for partial instantiation CDO d_univsPartSavedPos; //! the last decision level on which partial instantion is called CDO d_lastPartLevel; CDO d_partCalled; //! the max instantiation level reached CDO d_maxILReached; //!useful gterms for matching CDList d_usefulGterms; //!tracks the position in d_usefulGterms CDO d_lastUsefulGtermsPos; //!tracks a possition in the savedTerms map CDO d_savedTermsPos; //!tracks a possition in the database of universals CDO d_univsSavedPos; CDO d_rawUnivsSavedPos; //!tracks a possition in the database of universals CDO d_univsPosFull; //!tracks a possition in the database of universals if fulleffort mode, the d_univsSavedPos now uesed when fulleffort=0 only. CDO d_univsContextPos; CDO d_instCount; //!< number of instantiations made in given context //! set if the fullEffort = 1 int d_inEnd; int d_allout; //! a map of types to posisitions in the d_contextTerms list std::map* ,TypeComp> d_contextMap; //! a list of all the terms appearing in the current context CDList d_contextTerms; //!< chache of expressions CDMap d_contextCache; //! a map of types to positions in the d_savedTerms vector typeMap d_savedMap; ExprMap d_savedCache; //!< cache of expressions //! a vector of all of the terms that have produced conflicts. std::vector d_savedTerms; //! a map of instantiated universals to a vector of their instantiations ExprMap > d_insts; //! quantifier theorem production rules QuantProofRules* d_rules; const int* d_maxQuantInst; //!< Command line option /*! \brief categorizes all the terms contained in an expressions by *type. * * Updates d_contextTerms, d_contextMap, d_contextCache accordingly. * returns true if the expression does not contain bound variables, false * otherwise. */ bool recursiveMap(const Expr& term); /*! \brief categorizes all the terms contained in a vector of expressions by * type. * * Updates d_contextTerms, d_contextMap, d_contextCache accordingly. */ void mapTermsByType(const CDList& terms); /*! \brief Queues up all possible instantiations of bound * variables. * * The savedMap boolean indicates whether to use savedMap or * d_contextMap the all boolean indicates weather to use all * instantiation or only new ones and newIndex is the index where * new instantiations begin. */ void instantiate(Theorem univ, bool all, bool savedMap, size_t newIndex); //! does most of the work of the instantiate function. void recInstantiate(Theorem& univ , bool all, bool savedMap,size_t newIndex, std::vector& varReplacements); /*! \brief A recursive function used to find instantiated universals * in the hierarchy of assumptions. */ void findInstAssumptions(const Theorem& thm); // CDO usedup; const bool* d_useNew;//!use new way of instantiation const bool* d_useLazyInst;//!use lazy instantiation const bool* d_useSemMatch;//!use semantic matching const bool* d_useCompleteInst; //! Try complete instantiation const bool* d_translate;//!translate only const bool* d_usePart;//!use partial instantiaion const bool* d_useMult;//use // const bool* d_useInstEnd; const bool* d_useInstLCache; const bool* d_useInstGCache; const bool* d_useInstThmCache; const bool* d_useInstTrue; const bool* d_usePullVar; const bool* d_useExprScore; const int* d_useTrigLoop; const int* d_maxInst; // const int* d_maxUserScore; const int* d_maxIL; const bool* d_useTrans; const bool* d_useTrans2; const bool* d_useManTrig; const bool* d_useGFact; const int* d_gfactLimit; const bool* d_useInstAll; const bool* d_usePolarity; const bool* d_useEqu; const bool* d_useNewEqu; const int* d_maxNaiveCall; const bool* d_useNaiveInst; CDO d_curMaxExprScore; bool d_useFullTrig; bool d_usePartTrig; bool d_useMultTrig; //ExprMap > d_arrayIndic; //map array name to a list of indics CDMap > d_arrayIndic; //map array name to a list of indics void arrayIndexName(const Expr& e); std::vector d_allInsts; //! all instantiations int d_initMaxScore; int d_offset_multi_trig ; int d_instThisRound; int d_callThisRound; int partial_called; // ExprMap > d_fullTriggers; //for multi-triggers, now we only have one set of multi-triggers. ExprMap > d_multTriggers; ExprMap > d_partTriggers; ExprMap > d_fullTrigs; //for multi-triggers, now we only have one set of multi-triggers. ExprMap > d_multTrigs; ExprMap > d_partTrigs; CDO d_exprLastUpdatedPos ;//the position of the last expr updated in d_exprUpdate std::map d_indexScore; std::map d_indexExpr; int getExprScore(const Expr& e); //!the score for a full trigger ExprMap d_hasTriggers; ExprMap d_hasMoreBVs; int d_trans_num; int d_trans2_num; typedef struct{ std::vector > common_pos; std::vector > var_pos; std::vector* > var_binds_found; std::vector* >* > uncomm_list; // Theorem univThm; // for test only size_t univ_id; // for test only } multTrigsInfo ; ExprMap d_multitrigs_maps; std::vector d_all_multTrigsInfo; ExprMap* > d_trans_back; ExprMap* > d_trans_forw; CDMap d_trans_found; CDMap d_trans2_found; inline bool transFound(const Expr& comb); inline void setTransFound(const Expr& comb); inline bool trans2Found(const Expr& comb); inline void setTrans2Found(const Expr& comb); inline CDList & backList(const Expr& ex); inline CDList & forwList(const Expr& ex); void inline iterFWList(const Expr& sr, const Expr& dt, size_t univ_id, const Expr& gterm); void inline iterBKList(const Expr& sr, const Expr& dt, size_t univ_id, const Expr& gterm); Expr defaultWriteExpr; Expr defaultReadExpr; Expr defaultPlusExpr; Expr defaultMinusExpr ; Expr defaultMultExpr ; Expr defaultDivideExpr; Expr defaultPowExpr ; Expr getHead(const Expr& e) ; Expr getHeadExpr(const Expr& e) ; CDList null_cdlist; Theorem d_transThm; inline void pushBackList(const Expr& node, Expr ex); inline void pushForwList(const Expr& node, Expr ex); ExprMap >* > d_mtrigs_inst; //map expr to bindings ExprMap* > d_same_head_expr; //map an expr to a list of expres shard the same head ExprMap* > d_eq_list; //the equalities list CDList d_eqsUpdate; //the equalities list collected from update() CDO d_lastEqsUpdatePos; CDList d_eqs; //the equalities list CDO d_eqs_pos; //the equalities list ExprMap* > d_eq_pos; ExprMap* > d_parent_list; void collectChangedTerms(CDList& changed_terms); ExprMap > d_mtrigs_bvorder; int loc_gterm(const std::vector& border, const Expr& gterm, int pos); void recSearchCover(const std::vector& border, const std::vector& mtrigs, int cur_depth, std::vector >& instSet, std::vector& cur_inst ); void searchCover(const Expr& thm, const std::vector& border, std::vector >& instSet ); std::map,TypeComp > d_typeExprMap; std::set cacheHead; StatCounter d_allInstCount ; //the number instantiations asserted in SAT StatCounter d_allInstCount2 ; StatCounter d_totalInstCount ;// the total number of instantiations. StatCounter d_trueInstCount;//the number of instantiation simplified to be true. StatCounter d_abInstCount; // size_t d_totalInstCount; // size_t d_trueInstCount; // size_t d_abInstCount; std::vector d_cacheTheorem; size_t d_cacheThmPos; void addNotify(const Expr& e); int sendInstNew(); CDMap > > d_instHistory;//the history of instantiations //map univ to the trig, gterm and result ExprMap d_thmCount; ExprMap d_totalThmCount; ExprMap* > d_bindHistory; //the history of instantiations ExprMap* > d_bindGlobalHistory; //the history of instantiations ExprMap* > d_bindGlobalThmHistory; //the history of instantiations ExprMap > > d_instHistoryGlobal;//the history of instantiations ExprMap > d_subTermsMap; //std::map > d_subTermsMap; const std::vector& getSubTerms(const Expr& e); void simplifyExprMap(ExprMap& orgExprMap); void simplifyVectorExprMap(std::vector >& orgVectorExprMap); std::string exprMap2string(const ExprMap& vec); std::string exprMap2stringSimplify(const ExprMap& vec); std::string exprMap2stringSig(const ExprMap& vec); //ExprMap d_thmTimes; void enqueueInst(const Theorem, const Theorem); void enqueueInst(const Theorem& univ, const std::vector& bind, const Expr& gterm); void enqueueInst(size_t univ_id , const std::vector& bind, const Expr& gterm); void enqueueInst(const Theorem& univ, Trigger& trig, const std::vector& binds, const Expr& gterm ); void synCheckSat(ExprMap* >* >& , bool); void synCheckSat(bool); void semCheckSat(bool); void naiveCheckSat(bool); bool insted(const Theorem & univ, const std::vector& binds); void synInst(const Theorem & univ, const CDList& allterms, size_t tBegin); void synFullInst(const Theorem & univ, const CDList& allterms, size_t tBegin); void arrayHeuristic(const Trigger& trig, size_t univid); Expr simpRAWList(const Expr& org); void synNewInst(size_t univ_id, const std::vector& binds, const Expr& gterm, const Trigger& trig ); void synMultInst(const Theorem & univ, const CDList& allterms, size_t tBegin); void synPartInst(const Theorem & univ, const CDList& allterms, size_t tBegin); void semInst(const Theorem & univ, size_t tBegin); void goodSynMatch(const Expr& e, const std::vector & boundVars, std::vector >& instBindsTerm, std::vector& instGterm, const CDList& allterms, size_t tBegin); void goodSynMatchNewTrig(const Trigger& trig, const std::vector & boundVars, std::vector >& instBinds, std::vector& instGterms, const CDList& allterms, size_t tBegin); bool goodSynMatchNewTrig(const Trigger& trig, const std::vector & boundVars, std::vector >& instBinds, std::vector& instGterms, const Expr& gterm); void matchListOld(const CDList& list, size_t gbegin, size_t gend); // void matchListOld(const Expr& gterm); void matchListNew(ExprMap*>*>& new_trigs, const CDList& list, size_t gbegin, size_t gend); void delNewTrigs(ExprMap*>*>& new_trigs); void combineOldNewTrigs(ExprMap*>*>& new_trigs); inline void add_parent(const Expr& parent); void newTopMatch(const Expr& gterm, const Expr& vterm, std::vector >& binds, const Trigger& trig); void newTopMatchSig(const Expr& gterm, const Expr& vterm, std::vector >& binds, const Trigger& trig); void newTopMatchNoSig(const Expr& gterm, const Expr& vterm, std::vector >& binds, const Trigger& trig); void newTopMatchBackupOnly(const Expr& gterm, const Expr& vterm, std::vector >& binds, const Trigger& trig); bool synMatchTopPred(const Expr& gterm, const Trigger trig, ExprMap& env); // inline bool matchChild(const Expr& gterm, const Expr& vterm, ExprMap& env); // inline void matchChild(const Expr& gterm, const Expr& vterm, std::vector >& env); bool recSynMatch(const Expr& gterm, const Expr& vterm, ExprMap& env); bool recMultMatch(const Expr& gterm,const Expr& vterm, std::vector >& binds); bool recMultMatchDebug(const Expr& gterm,const Expr& vterm, std::vector >& binds); bool recMultMatchNewWay(const Expr& gterm,const Expr& vterm, std::vector >& binds); bool recMultMatchOldWay(const Expr& gterm,const Expr& vterm, std::vector >& binds); inline bool multMatchChild(const Expr& gterm, const Expr& vterm, std::vector >& binds, bool top=false); inline bool multMatchTop(const Expr& gterm, const Expr& vterm, std::vector >& binds); bool recSynMatchBackupOnly(const Expr& gterm, const Expr& vterm, ExprMap& env); bool hasGoodSynInstNewTrigOld(Trigger& trig, std::vector & boundVars, std::vector >& instBinds, std::vector& instGterms, const CDList& allterms, size_t tBegin); bool hasGoodSynInstNewTrig(Trigger& trig, const std::vector & boundVars, std::vector >& instBinds, std::vector& instGterms, const CDList& allterms, size_t tBegin); bool hasGoodSynMultiInst(const Expr& e, std::vector& bVars, std::vector >& instSet, const CDList& allterms, size_t tBegin); void recGoodSemMatch(const Expr& e, const std::vector& bVars, std::vector& newInst, std::set >& instSet); bool hasGoodSemInst(const Expr& e, std::vector& bVars, std::set >& instSet, size_t tBegin); bool isTransLike (const std::vector& cur_trig); bool isTrans2Like (const std::vector& all_terms, const Expr& tr2); static const size_t MAX_TRIG_BVS=15; Expr d_mybvs[MAX_TRIG_BVS]; Expr recGeneralTrig(const Expr& trig, ExprMap& bvs, size_t& mybvs_count); Expr generalTrig(const Expr& trig, ExprMap& bvs); ExprMap* >* > d_allmap_trigs; CDList d_alltrig_list; void registerTrig(ExprMap* >* >& cur_trig_map, Trigger trig, const std::vector thmBVs, size_t univ_id); void registerTrigReal(Trigger trig, const std::vector, size_t univ_id); bool canMatch(const Expr& t1, const Expr& t2, ExprMap& env); void setGround(const Expr& gterm, const Expr& trig, const Theorem& univ, const std::vector& subTerms) ; // std::string getHead(const Expr& e) ; void setupTriggers(ExprMap* >*>& trig_maps, const Theorem& thm, size_t univs_id); void saveContext(); /*! \brief categorizes all the terms contained in an expressions by *type. * * Updates d_contextTerms, d_contextMap, d_contextCache accordingly. * returns true if the expression does not contain bound variables, false * otherwise. */ public: TheoryQuant(TheoryCore* core); //!< Constructor ~TheoryQuant(); //! Destructor QuantProofRules* createProofRules(); void addSharedTerm(const Expr& e) {} //!< Theory interface /*! \brief Theory interface function to assert quantified formulas * * pushes in negations and converts to either universally or existentially * quantified theorems. Universals are stored in a database while * existentials are enqueued to be handled by the search engine. */ void assertFact(const Theorem& e); /* \brief Checks the satisfiability of the universal theorems stored in a * databse by instantiating them. * * There are two algorithms that the checkSat function uses to find * instnatiations. The first algortihm looks for instanitations in a saved * database of previous instantiations that worked in proving an earlier * theorem unsatifiable. All of the class variables with the word saved in * them are for the use of this algorithm. The other algorithm uses terms * found in the assertions that exist in the particular context when * checkSat is called. All of the class variables with the word context in * them are used for the second algorithm. */ void checkSat(bool fullEffort); void setup(const Expr& e); int help(int i); void update(const Theorem& e, const Expr& d); /*!\brief Used to notify the quantifier algorithm of possible * instantiations that were used in proving a context inconsistent. */ void debug(int i); void notifyInconsistent(const Theorem& thm); //! computes the type of a quantified term. Always a boolean. void computeType(const Expr& e); Expr computeTCC(const Expr& e); virtual Expr parseExprOp(const Expr& e); ExprStream& print(ExprStream& os, const Expr& e); }; } #endif cvc3-2.4.1/src/include/queryresult.h0000664000175400017540000000212410512365615017250 0ustar mdetersmdeters/*****************************************************************************/ /*! *\file queryresult.h *\brief enumerated type for result of queries * * Author: Clark Barrett * * Created: Thu May 18 12:36:25 2006 * *
* * License to use, copy, modify, sell and/or distribute this software * and its documentation for any purpose is hereby granted without * royalty, subject to the terms and conditions defined in the \ref * LICENSE file provided with this distribution. * *
*/ /*****************************************************************************/ #ifndef _cvc3__include__queryresult_h_ #define _cvc3__include__queryresult_h_ namespace CVC3 { /*****************************************************************************/ /* * Type for result of queries. VALID and UNSATISFIABLE are treated as * equivalent, as are SATISFIABLE and INVALID. */ /*****************************************************************************/ typedef enum QueryResult { SATISFIABLE = 0, INVALID = 0, VALID = 1, UNSATISFIABLE = 1, ABORT, UNKNOWN } QueryResult; } #endif cvc3-2.4.1/src/include/hash_set.h0000664000175400017540000001435310565700147016452 0ustar mdetersmdeters/*****************************************************************************/ /*! *\file hash_set.h *\brief hash map implementation * * Author: Alexander Fuchs * * Created: Thu Oct 19 11:04:00 2006 * *
* * License to use, copy, modify, sell and/or distribute this software * and its documentation for any purpose is hereby granted without * royalty, subject to the terms and conditions defined in the \ref * LICENSE file provided with this distribution. * *
*/ /*****************************************************************************/ /* * Copyright (c) 1996,1997 * Silicon Graphics Computer Systems, Inc. * * Permission to use, copy, modify, distribute and sell this software * and its documentation for any purpose is hereby granted without fee, * provided that the above copyright notice appear in all copies and * that both that copyright notice and this permission notice appear * in supporting documentation. Silicon Graphics makes no * representations about the suitability of this software for any * purpose. It is provided "as is" without express or implied warranty. * * * Copyright (c) 1994 * Hewlett-Packard Company * * Permission to use, copy, modify, distribute and sell this software * and its documentation for any purpose is hereby granted without fee, * provided that the above copyright notice appear in all copies and * that both that copyright notice and this permission notice appear * in supporting documentation. Hewlett-Packard Company makes no * representations about the suitability of this software for any * purpose. It is provided "as is" without express or implied warranty. * */ // this implementation is in essence a subset of the SGI implementation: // http://www.sgi.com/tech/stl/stl_hash_set.h #ifndef _cvc3__hash__hash_set_h_ #define _cvc3__hash__hash_set_h_ #include "hash_fun.h" #include "hash_table.h" namespace Hash { // identity is an extension taken from the SGI // implementation of the STL file functional: // http://www.sgi.com/tech/stl/stl_function.h template struct _Identity : public std::unary_function<_Tp,_Tp> { const _Tp& operator()(const _Tp& __x) const { return __x; } }; /*! hash set implementation based on the sgi interface: http://www.sgi.com/tech/stl/hash_set.html _Key: hash key type _HashFcn: functional class providing a hash function: size_type (_Key) _EqualKey: functional class providing a comparison function: bool(_Key, _Key) returns true iff two keys are considered to be equal */ template , class _EqualKey = std::equal_to<_Key> > class hash_set { /// types protected: typedef hash_table<_Key, _Key, _HashFcn, _EqualKey, _Identity<_Key> > _hash_table; public: // typedefs as custom for other implementations typedef typename _hash_table::size_type size_type; typedef typename _hash_table::key_type key_type; typedef typename _hash_table::value_type value_type; typedef typename _hash_table::hasher hasher; typedef typename _hash_table::key_equal key_equal; public: // iterators typedef typename _hash_table::iterator iterator; typedef typename _hash_table::const_iterator const_iterator; /// variables protected: // the hash table _hash_table d_table; /// methods public: /// constructors // default size is 16 buckets hash_set() : d_table() { }; // specifiy initial number of buckets - must be positive hash_set(size_type initial_capacity) : d_table(initial_capacity) { }; // specifiy initial number of buckets and hash function hash_set(size_type initial_capacity, const _HashFcn& hash) : d_table(initial_capacity, hash) { }; // specifiy initial number of buckets, hash and equal function hash_set(size_type initial_capacity, const _HashFcn& hash, const _EqualKey& equal) : d_table(initial_capacity, hash, equal) { }; // copy hash map. hash_set(const hash_set& other) : d_table(other.d_table) { }; // assign hash map hash_set& operator=(const hash_set& other) { if (this != &other) { d_table = other.d_table; } return *this; } void swap(hash_set& other) { d_table.swap(other.d_table); } // removes all entries, number of buckets is not reduced. void clear() { d_table.clear(); }; /// operations // returns end iterator if key was not bound iterator find(const key_type& key) { return d_table.find(key); } // const version of find const_iterator find(const key_type& key) const { return d_table.find(key); } // adds the mapping from key to data, if key is still unbound // otherwise returns false std::pair insert(const value_type& entry) { return d_table.insert(entry); } // removes binding of key // returns number of keys removed, // i.e. 1 if key was bound, 0 if key was not bound. size_type erase(const key_type& key) { return d_table.erase(key); } /// status // is the key bound? bool contains(const key_type& key) const { return d_table.contains(key); } // returns the number of times a key is bound, // i.e. 0 or 1 size_type count(const _Key& key) const { return d_table.count(key); } // is the hash map empty? bool empty() const { return d_table.empty(); } // the number of elements in the hash map size_type size() const { return d_table.size(); } // the number of buckets in the hash map size_type bucket_count() const { return d_table.bucket_count(); } // returns the average number of elements per bucket float load_factor() const { return d_table.load_factor(); } /// iterators // returns forward iterator to iterate over all key/data pairs iterator begin() { return d_table.begin(); } // const version of begin const_iterator begin() const { return d_table.begin(); } // returns end iterator iterator end() { return d_table.end(); } // const version of end const_iterator end() const { return d_table.end(); } }; } #endif cvc3-2.4.1/src/include/expr_map.h0000664000175400017540000002777311233414122016465 0ustar mdetersmdeters/*****************************************************************************/ /*! * \file expr_map.h * * Author: Sergey Berezin * * Created: Dec 11 01:22:49 GMT 2002 * *
* * License to use, copy, modify, sell and/or distribute this software * and its documentation for any purpose is hereby granted without * royalty, subject to the terms and conditions defined in the \ref * LICENSE file provided with this distribution. * *
* */ /*****************************************************************************/ // CLASS: ExprMap // // AUTHOR: Sergey Berezin, 12/10/2002 // // Abstract: // // An abstract interface mapping Expr values to Data. The // implementation is a hash table. // // Subclassing is NOT allowed; this would lose the iterators (can we // fix it? Maybe not worth the trouble.) // // Functions follow the style of STL 'map' container. // // ExprMap() [Default constructor] Creates an empty map // int count(Expr e) Counts the number of elements mapped from e. // Normally, returns 0 or 1. // Data& operator[](e) Returns Data associated with e. If e is not mapped, // insert new Data() into ExprMap. // Can be used to populate ExprMap as follows: // ExprMap map; // map[e1] = data1; map[e2] = data2; ... // Caveat: Data must have a default constructor and be assignable. // void erase(Expr e) Erase e->data mapping from ExprMap. // void insert(Expr e, Data d) Insert e->d mapping. // iterator begin() Return simple "input" iterators for ExprMap // iterator end() (as defined in STL) // size_t size() Return size of the map // bool empty() Check for emptiness /////////////////////////////////////////////////////////////////////////////// #ifndef _cvc3__expr_h_ #include "expr.h" #endif #ifndef _cvc3__expr_map_h_ #define _cvc3__expr_map_h_ #include "expr_hash.h" namespace CVC3 { template class ExprMap { private: typedef std::map ExprMapType; // Private members ExprMapType d_map; public: ////////////////////////////////////////////////////////////////////////// // Class: ExprMap::iterator // Author: Sergey Berezin // Created: Tue Dec 10 16:25:19 2002 // Description: ////////////////////////////////////////////////////////////////////////// class const_iterator: public std::iterator,std::ptrdiff_t> { friend class ExprMap; private: typename ExprMapType::const_iterator d_it; // Private constructor const_iterator(const typename ExprMapType::const_iterator& it) : d_it(it) { } public: // Default constructor const_iterator() { } // (Dis)equality bool operator==(const const_iterator& i) const { return d_it == i.d_it; } bool operator!=(const const_iterator& i) const { return d_it != i.d_it; } // Dereference operators. const std::pair& operator*() const { return *d_it; } const std::pair* operator->() const { return d_it.operator->(); } // Prefix increment const_iterator& operator++() { ++d_it; return *this; } // Postfix increment: requires a Proxy object to hold the // intermediate value for dereferencing class Proxy { const std::pair& d_pair; public: Proxy(const std::pair& pair) : d_pair(pair) { } std::pair operator*() { return d_pair; } }; // end of class Proxy // Actual postfix increment: returns Proxy with the old value. // Now, an expression like *i++ will return the current *i, and // then advance the iterator. However, don't try to use Proxy for // anything else. Proxy operator++(int) { Proxy tmp(*(*this)); ++(*this); return tmp; } // Prefix decrement const_iterator& operator--() { --d_it; return *this; } }; // end of class const_iterator class iterator: public std::iterator,std::ptrdiff_t> { friend class ExprMap; private: typename ExprMapType::iterator d_it; // Private constructor iterator(const typename ExprMapType::iterator& it) : d_it(it) { } public: // Default constructor iterator() { } // (Dis)equality bool operator==(const iterator& i) const { return d_it == i.d_it; } bool operator!=(const iterator& i) const { return d_it != i.d_it; } // Dereference operators. std::pair& operator*() const { return *d_it; } std::pair* operator->() const { return d_it.operator->(); } // Prefix increment iterator& operator++() { ++d_it; return *this; } // Postfix increment: requires a Proxy object to hold the // intermediate value for dereferencing class Proxy { std::pair& d_pair; public: Proxy(std::pair& pair) : d_pair(pair) { } std::pair operator*() { return d_pair; } }; // end of class Proxy // Actual postfix increment: returns Proxy with the old value. // Now, an expression like *i++ will return the current *i, and // then advance the iterator. However, don't try to use Proxy for // anything else. Proxy operator++(int) { Proxy tmp(*(*this)); ++(*this); return tmp; } // Prefix decrement iterator& operator--() { --d_it; return *this; } }; // end of class iterator ////////////////////////////////////////////////////////////////////////// // Public methods ////////////////////////////////////////////////////////////////////////// // Default constructor ExprMap() { } // Copy constructor ExprMap(const ExprMap& map): d_map(map.d_map) { } // Other methods bool empty() const { return d_map.empty(); } size_t size() const { return d_map.size(); } size_t count(const Expr& e) const { return d_map.count(e); } Data& operator[](const Expr& e) { return d_map[e]; } void clear() { d_map.clear(); } void insert(const Expr& e, const Data& d) { d_map[e] = d; } void erase(const Expr& e) { d_map.erase(e); } template void insert(InputIterator l, InputIterator r) { d_map.insert(l,r); } template void erase(InputIterator l, InputIterator r) { for(; l!=r; ++l) { d_map.erase((*l).first); } } iterator begin() { return iterator(d_map.begin()); } iterator end() { return iterator(d_map.end()); } const_iterator begin() const { return const_iterator(d_map.begin()); } const_iterator end() const { return const_iterator(d_map.end()); } iterator find(const Expr& e) { return iterator(d_map.find(e)); } const_iterator find(const Expr& e) const { return const_iterator(d_map.find(e)); } friend bool operator==(const ExprMap& m1, const ExprMap& m2) { return m1.d_map == m2.d_map; } friend bool operator!=(const ExprMap& m1, const ExprMap& m2) { return !(m1 == m2); } }; // end of class ExprMap template class ExprHashMap { private: typedef std::hash_map ExprHashMapType; // Private members ExprHashMapType d_map; public: class const_iterator: public std::iterator,std::ptrdiff_t> { friend class ExprHashMap; private: typename ExprHashMapType::const_iterator d_it; // Private constructor const_iterator(const typename ExprHashMapType::const_iterator& it) : d_it(it) { } public: // Default constructor const_iterator() { } // (Dis)equality bool operator==(const const_iterator& i) const { return d_it == i.d_it; } bool operator!=(const const_iterator& i) const { return d_it != i.d_it; } // Dereference operators. const std::pair& operator*() const { return *d_it; } const std::pair* operator->() const { return d_it.operator->(); } // Prefix increment const_iterator& operator++() { ++d_it; return *this; } // Postfix increment: requires a Proxy object to hold the // intermediate value for dereferencing class Proxy { const std::pair& d_pair; public: Proxy(const std::pair& pair) : d_pair(pair) { } std::pair operator*() { return d_pair; } }; // end of class Proxy // Actual postfix increment: returns Proxy with the old value. // Now, an expression like *i++ will return the current *i, and // then advance the iterator. However, don't try to use Proxy for // anything else. Proxy operator++(int) { Proxy tmp(*(*this)); ++(*this); return tmp; } }; // end of class const_iterator class iterator: public std::iterator,std::ptrdiff_t> { friend class ExprHashMap; private: typename ExprHashMapType::iterator d_it; // Private constructor iterator(const typename ExprHashMapType::iterator& it) : d_it(it) { } public: // Default constructor iterator() { } // (Dis)equality bool operator==(const iterator& i) const { return d_it == i.d_it; } bool operator!=(const iterator& i) const { return d_it != i.d_it; } // Dereference operators. std::pair& operator*() const { return *d_it; } std::pair* operator->() const { return d_it.operator->(); } // Prefix increment iterator& operator++() { ++d_it; return *this; } // Postfix increment: requires a Proxy object to hold the // intermediate value for dereferencing class Proxy { std::pair& d_pair; public: Proxy(std::pair& pair) : d_pair(pair) { } std::pair operator*() { return d_pair; } }; // end of class Proxy // Actual postfix increment: returns Proxy with the old value. // Now, an expression like *i++ will return the current *i, and // then advance the iterator. However, don't try to use Proxy for // anything else. Proxy operator++(int) { Proxy tmp(*(*this)); ++(*this); return tmp; } }; // end of class iterator ////////////////////////////////////////////////////////////////////////// // Public methods ////////////////////////////////////////////////////////////////////////// //! Default constructor ExprHashMap() { } //! Constructor specifying the initial number of buckets ExprHashMap(size_t n): d_map(n) { } // Copy constructor ExprHashMap(const ExprHashMap& map): d_map(map.d_map) { } // Other methods bool empty() const { return d_map.empty(); } size_t size() const { return d_map.size(); } size_t count(const Expr& e) const { return d_map.count(e); } Data& operator[](const Expr& e) { return d_map[e]; } void clear() { d_map.clear(); } void insert(const Expr& e, const Data& d) { d_map[e] = d; } void erase(const Expr& e) { d_map.erase(e); } template void insert(InputIterator l, InputIterator r) { d_map.insert(l,r); } template void erase(InputIterator l, InputIterator r) { for(; l!=r; ++l) { d_map.erase((*l).first); } } iterator begin() { return iterator(d_map.begin()); } iterator end() { return iterator(d_map.end()); } const_iterator begin() const { return const_iterator(d_map.begin()); } const_iterator end() const { return const_iterator(d_map.end()); } iterator find(const Expr& e) { return iterator(d_map.find(e)); } const_iterator find(const Expr& e) const { return const_iterator(d_map.find(e)); } // These aren't implemented // friend bool operator==(const ExprHashMap& m1, const ExprHashMap& m2) { // return m1.d_map == m2.d_map; // } // friend bool operator!=(const ExprHashMap& m1, const ExprHashMap& m2) { // return !(m1 == m2); // } }; // end of class ExprHashMap } // end of namespace CVC3 #endif cvc3-2.4.1/src/include/compat_hash_set.h0000664000175400017540000000222610634045774020016 0ustar mdetersmdeters/*****************************************************************************/ /*! * \file compat_hash_set.h * * Author: Sergey Berezin * * Created: Jan 31 02:23:26 GMT 2003 * *
* * License to use, copy, modify, sell and/or distribute this software * and its documentation for any purpose is hereby granted without * royalty, subject to the terms and conditions defined in the \ref * LICENSE file provided with this distribution. * *
* * Compatibility header file for STL extension "hash_set". Any other * source file that needs to use hash_set should include this instead. * * If hash_set and hash are not defined in namespace std, we bring * them in there. It turns out that different versions of gcc use * different namespaces for STL extensions (std, __gnu_cxx, and God * knows what'll be next). * * This header assumes that only one of HAVE_*_HASH_SET symbols is * defined. * * */ /*****************************************************************************/ #ifndef _core_utilities_compat_hash_set_h_ #define _core_utilities_compat_hash_set_h_ #include "hash_set.h" namespace std { using namespace Hash; } #endif cvc3-2.4.1/src/include/hash_map.h0000664000175400017540000001626010673337470016440 0ustar mdetersmdeters/*****************************************************************************/ /*! *\file hash_map.h *\brief hash map implementation * * Author: Alexander Fuchs * * Created: Fri Oct 13 11:04:00 2006 * *
* * License to use, copy, modify, sell and/or distribute this software * and its documentation for any purpose is hereby granted without * royalty, subject to the terms and conditions defined in the \ref * LICENSE file provided with this distribution. * *
*/ /*****************************************************************************/ /* * Copyright (c) 1996,1997 * Silicon Graphics Computer Systems, Inc. * * Permission to use, copy, modify, distribute and sell this software * and its documentation for any purpose is hereby granted without fee, * provided that the above copyright notice appear in all copies and * that both that copyright notice and this permission notice appear * in supporting documentation. Silicon Graphics makes no * representations about the suitability of this software for any * purpose. It is provided "as is" without express or implied warranty. * * * Copyright (c) 1994 * Hewlett-Packard Company * * Permission to use, copy, modify, distribute and sell this software * and its documentation for any purpose is hereby granted without fee, * provided that the above copyright notice appear in all copies and * that both that copyright notice and this permission notice appear * in supporting documentation. Hewlett-Packard Company makes no * representations about the suitability of this software for any * purpose. It is provided "as is" without express or implied warranty. * */ // this implementation is in essence a subset of the SGI implementation: // http://www.sgi.com/tech/stl/stl_hash_map.h #ifndef _cvc3__hash__hash_map_h_ #define _cvc3__hash__hash_map_h_ #include "hash_fun.h" #include "hash_table.h" #include #include namespace Hash { // select1st is an extension taken from the SGI // implementation of the STL file functional: // http://www.sgi.com/tech/stl/stl_function.h template struct _Select1st : public std::unary_function<_Pair, typename _Pair::first_type> { const typename _Pair::first_type& operator()(const _Pair& __x) const { return __x.first; } }; /*! hash map implementation based on the sgi interface: http://www.sgi.com/tech/stl/hash_map.html _Key: hash key type _Data: data to store _HashFcn: functional class providing a hash function: size_type (_Key) _EqualKey: functional class providing a comparison function: bool(_Key, _Key) returns true iff two keys are considered to be equal */ template , class _EqualKey = std::equal_to<_Key> > class hash_map { /// types protected: // note: const _Key must be used for _Value and _ExtractKey. // if one is const and the other is not, // then extracting a key will require a conversion and a temporary // (at least in debug mode), // so that the reference returned by _ExtractKey point to a temporary. typedef hash_table<_Key, std::pair, _HashFcn, _EqualKey, _Select1st > > _hash_table; public: // typedefs as custom for other implementations typedef typename _hash_table::size_type size_type; typedef typename _hash_table::key_type key_type; typedef _Data data_type; typedef typename _hash_table::value_type value_type; typedef typename _hash_table::hasher hasher; typedef typename _hash_table::key_equal key_equal; public: // iterators typedef typename _hash_table::iterator iterator; typedef typename _hash_table::const_iterator const_iterator; /// variables protected: // the hash table _hash_table d_table; /// methods public: /// constructors // default size is 16 buckets hash_map() : d_table() { }; // specifiy initial number of buckets - must be positive hash_map(size_type initial_capacity) : d_table(initial_capacity) { }; // specifiy initial number of buckets and hash function hash_map(size_type initial_capacity, const _HashFcn& hash) : d_table(initial_capacity, hash) { }; // specifiy initial number of buckets, hash and equal function hash_map(size_type initial_capacity, const _HashFcn& hash, const _EqualKey& equal) : d_table(initial_capacity, hash, equal) { }; // copy hash map. hash_map(const hash_map& other) : d_table(other.d_table) { }; // assign hash map hash_map& operator=(const hash_map& other) { if (this != &other) { d_table = other.d_table; } return *this; } void swap(hash_map& other) { d_table.swap(other.d_table); } // removes all entries, number of buckets is not reduced. void clear() { d_table.clear(); }; /// operations // returns end iterator if key was not bound iterator find(const key_type& key) { return d_table.find(key); } // const version of find const_iterator find(const key_type& key) const { return d_table.find(key); } // if key in value is already bound, // returns that binding, // otherwise inserts a default value and returns a reference to it. data_type& operator[](const key_type& key) { return d_table.find_or_insert(std::make_pair(key, data_type())).second; } // adds the mapping from key to data, if key is still unbound // otherwise returns false std::pair insert(const value_type& entry) { return d_table.insert(entry); } // removes binding of key // returns number of keys removed, // i.e. 1 if key was bound, 0 if key was not bound. size_type erase(const key_type& key) { return d_table.erase(key); } // removes element pointed to by iter, // returns element after iter. const_iterator erase(const const_iterator& i) { return d_table.erase(i); } /// status // is the key bound? bool contains(const key_type& key) const { return d_table.contains(key); } // returns the number of times a key is bound, // i.e. 0 or 1 size_type count(const _Key& key) const { return d_table.count(key); } // is the hash map empty? bool empty() const { return d_table.empty(); } // the number of elements in the hash map size_type size() const { return d_table.size(); } // the number of buckets in the hash map size_type bucket_count() const { return d_table.bucket_count(); } // returns the average number of elements per bucket float load_factor() const { return d_table.load_factor(); } /// iterators // returns forward iterator to iterate over all key/data pairs iterator begin() { return d_table.begin(); } // const version of begin const_iterator begin() const { return d_table.begin(); } // returns end iterator iterator end() { return d_table.end(); } // const version of end const_iterator end() const { return d_table.end(); } }; } #endif cvc3-2.4.1/src/include/theory_arith_new.h0000664000175400017540000010664211277111607020227 0ustar mdetersmdeters/*****************************************************************************/ /*! * \file theory_arith_new.h * * Author: Dejan Jovanovic * * Created: Thu Jun 14 13:38:16 2007 * *
* * License to use, copy, modify, sell and/or distribute this software * and its documentation for any purpose is hereby granted without * royalty, subject to the terms and conditions defined in the \ref * LICENSE file provided with this distribution. * *
* */ /*****************************************************************************/ #ifndef _cvc3__include__theory_arith_new_h_ #define _cvc3__include__theory_arith_new_h_ #include "theory_arith.h" #include #include #include #include namespace CVC3 { /** * This theory handles basic linear arithmetic. * * @author Clark Barrett * * @since Sat Feb 8 14:44:32 2003 */ class TheoryArithNew :public TheoryArith { /** For concrete model generation */ CDList d_diseq; /** Index to the next unprocessed disequality */ CDO d_diseqIdx; ArithProofRules* d_rules; CDO d_inModelCreation; /** Data class for the strongest free constant in separation inqualities **/ class FreeConst { private: Rational d_r; bool d_strict; public: FreeConst() { } FreeConst(const Rational& r, bool strict): d_r(r), d_strict(strict) { } const Rational& getConst() const { return d_r; } bool strict() const { return d_strict; } }; //! Printing friend std::ostream& operator<<(std::ostream& os, const FreeConst& fc); //! Private class for an inequality in the Fourier-Motzkin database class Ineq { private: Theorem d_ineq; //!< The inequality bool d_rhs; //!< Var is isolated on the RHS const FreeConst* d_const; //!< The max/min const for subsumption check //! Default constructor is disabled Ineq() { } public: //! Initial constructor. 'r' is taken from the subsumption database. Ineq(const Theorem& ineq, bool varOnRHS, const FreeConst& c): d_ineq(ineq), d_rhs(varOnRHS), d_const(&c) { } //! Get the inequality const Theorem& ineq() const { return d_ineq; } //! Get the max/min constant const FreeConst& getConst() const { return *d_const; } //! Flag whether var is isolated on the RHS bool varOnRHS() const { return d_rhs; } //! Flag whether var is isolated on the LHS bool varOnLHS() const { return !d_rhs; } //! Auto-cast to Theorem operator Theorem() const { return d_ineq; } }; //! Printing friend std::ostream& operator<<(std::ostream& os, const Ineq& ineq); //! Database of inequalities with a variable isolated on the right ExprMap *> d_inequalitiesRightDB; //! Database of inequalities with a variable isolated on the left ExprMap *> d_inequalitiesLeftDB; //! Mapping of inequalities to the largest/smallest free constant /*! The Expr is the original inequality with the free constant * removed and inequality converted to non-strict (for indexing * purposes). I.e. ax, the smallest (largest for c+t d_freeConstDB; // Input buffer to store the incoming inequalities CDList d_buffer; //!< Buffer of input inequalities CDO d_bufferIdx; //!< Buffer index of the next unprocessed inequality const int* d_bufferThres; //!< Threshold when the buffer must be processed // Statistics for the variables /*! @brief Mapping of a variable to the number of inequalities where the variable would be isolated on the right */ CDMap d_countRight; /*! @brief Mapping of a variable to the number of inequalities where the variable would be isolated on the left */ CDMap d_countLeft; //! Set of shared terms (for counterexample generation) CDMap d_sharedTerms; //! Set of shared integer variables (i-leaves) CDMap d_sharedVars; //Directed Acyclic Graph representing partial variable ordering for //variable projection over inequalities. class VarOrderGraph { ExprMap > d_edges; ExprMap d_cache; bool dfs(const Expr& e1, const Expr& e2); public: void addEdge(const Expr& e1, const Expr& e2); //returns true if e1 < e2, false otherwise. bool lessThan(const Expr& e1, const Expr& e2); //selects those variables which are largest and incomparable among //v1 and puts it into v2 void selectLargest(const std::vector& v1, std::vector& v2); //selects those variables which are smallest and incomparable among //v1, removes them from v1 and puts them into v2. void selectSmallest( std::vector& v1, std::vector& v2); }; VarOrderGraph d_graph; // Private methods //! Check the term t for integrality. /*! \return a theorem of IS_INTEGER(t) or Null. */ Theorem isIntegerThm(const Expr& e); //! A helper method for isIntegerThm() /*! Check if IS_INTEGER(e) is easily derivable from the given 'thm' */ Theorem isIntegerDerive(const Expr& isIntE, const Theorem& thm); //! Check if the kids of e are fully simplified and canonized (for debugging) bool kidsCanonical(const Expr& e); //! Canonize the expression e, assuming all children are canonical Theorem canon(const Expr& e); /*! @brief Canonize and reduce e w.r.t. union-find database; assume * all children are canonical */ Theorem canonSimplify(const Expr& e); /*! @brief Composition of canonSimplify(const Expr&) by * transitivity: take e0 = e1, canonize and simplify e1 to e2, * return e0 = e2. */ Theorem canonSimplify(const Theorem& thm) { return transitivityRule(thm, canonSimplify(thm.getRHS())); } //! Canonize predicate (x = y, x < y, etc.) Theorem canonPred(const Theorem& thm); //! Canonize predicate like canonPred except that the input theorem //! is an equivalent transformation. Theorem canonPredEquiv(const Theorem& thm); //! Solve an equation and return an equivalent Theorem in the solved form Theorem doSolve(const Theorem& e); //! takes in a conjunction equivalence Thm and canonizes it. Theorem canonConjunctionEquiv(const Theorem& thm); //! picks the monomial with the smallest abs(coeff) from the input //integer equation. Expr pickIntEqMonomial(const Expr& right); //! processes equalities with 1 or more vars of type REAL Theorem processRealEq(const Theorem& eqn); //! processes equalities whose vars are all of type INT Theorem processIntEq(const Theorem& eqn); //! One step of INT equality processing (aux. method for processIntEq()) Theorem processSimpleIntEq(const Theorem& eqn); //! Take an inequality and isolate a variable Theorem isolateVariable(const Theorem& inputThm, bool& e1); //! Update the statistics counters for the variable with a coeff. c void updateStats(const Rational& c, const Expr& var); //! Update the statistics counters for the monomial void updateStats(const Expr& monomial); //! Add an inequality to the input buffer. See also d_buffer void addToBuffer(const Theorem& thm); Expr pickMonomial(const Expr& right); public: // ArithTheoremProducer needs this function, so make it public //! Separate monomial e = c*p1*...*pn into c and 1*p1*...*pn void separateMonomial(const Expr& e, Expr& c, Expr& var); //! Check the term t for integrality (return bool) bool isInteger(const Expr& e) { return !(isIntegerThm(e).isNull()); } private: bool lessThanVar(const Expr& isolatedVar, const Expr& var2); //! Check if the term expression is "stale" bool isStale(const Expr& e); //! Check if the inequality is "stale" or subsumed bool isStale(const Ineq& ineq); void projectInequalities(const Theorem& theInequality,bool isolatedVarOnRHS); void assignVariables(std::vector&v); void findRationalBound(const Expr& varSide, const Expr& ratSide, const Expr& var, Rational &r); bool findBounds(const Expr& e, Rational& lub, Rational& glb); Theorem normalizeProjectIneqs(const Theorem& ineqThm1, const Theorem& ineqThm2); //! Take a system of equations and turn it into a solved form Theorem solvedForm(const std::vector& solvedEqs); /*! @brief Substitute all vars in term 't' according to the * substitution 'subst' and canonize the result. */ Theorem substAndCanonize(const Expr& t, ExprMap& subst); /*! @brief Substitute all vars in the RHS of the equation 'eq' of * the form (x = t) according to the substitution 'subst', and * canonize the result. */ Theorem substAndCanonize(const Theorem& eq, ExprMap& subst); //! Traverse 'e' and push all the i-leaves into 'vars' vector void collectVars(const Expr& e, std::vector& vars, std::set& cache); /*! @brief Check if alpha <= ax & bx <= beta is a finite interval * for integer var 'x', and assert the corresponding constraint */ void processFiniteInterval(const Theorem& alphaLEax, const Theorem& bxLEbeta); //! For an integer var 'x', find and process all constraints A <= ax <= A+c void processFiniteIntervals(const Expr& x); //! Recursive setup for isolated inequalities (and other new expressions) void setupRec(const Expr& e); public: TheoryArithNew(TheoryCore* core); ~TheoryArithNew(); // Trusted method that creates the proof rules class (used in constructor). // Implemented in arith_theorem_producer.cpp ArithProofRules* createProofRules(); // Theory interface void addSharedTerm(const Expr& e); void assertFact(const Theorem& e); void refineCounterExample(); void computeModelBasic(const std::vector& v); void computeModel(const Expr& e, std::vector& vars); void checkSat(bool fullEffort); Theorem rewrite(const Expr& e); void setup(const Expr& e); void update(const Theorem& e, const Expr& d); Theorem solve(const Theorem& e); void checkAssertEqInvariant(const Theorem& e); void checkType(const Expr& e); Cardinality finiteTypeInfo(Expr& e, Unsigned& n, bool enumerate, bool computeSize); void computeType(const Expr& e); Type computeBaseType(const Type& t); void computeModelTerm(const Expr& e, std::vector& v); Expr computeTypePred(const Type& t, const Expr& e); Expr computeTCC(const Expr& e); ExprStream& print(ExprStream& os, const Expr& e); virtual Expr parseExprOp(const Expr& e); // DDDDDDDDDDDDDDDDDDDDDDDDEEEEEEEEEEEEEEEEEEEEEEEJJJJJJJJJJJJJJJJJJJJJAAAAAAAAAAAAAAAAAAAAAAANNNNNNNNNNNNNNNNNNNNNNN public: /** * EpsRational class ecapsulates the rationals with a symbolic small \f$\epsilon\f$ added. Each rational * number is presented as a pair \f$(q, k) = q + k\epsilon\f$, where \f$\epsilon\f$ is treated symbolically. * The operations on the new rationals are defined as *
    *
  • \f$(q_1, k_1) + (q_2, k_2) \equiv (q_1 + q_2, k_1 + k_2)\f$ *
  • \f$a \times (q, k) \equiv (a \times q, a \times k)\f$ *
  • \f$(q_1, k_1) \leq (q_2, k_2) \equiv (q_1 < q_2) \vee (q_1 = q_2 \wedge k_1 \leq k_2)\f$ *
* * Note that the operations on the infinite values are not defined, as they are never used currently. Infinities can * only be asigned or compared. */ class EpsRational { protected: /** Type of rationals, normal and the two infinities */ typedef enum { FINITE, PLUS_INFINITY, MINUS_INFINITY } RationalType; /** The type of this rational */ RationalType type; /** The rational part */ Rational q; /** The epsilon multiplier */ Rational k; /** * Private constructor to construt infinities. */ EpsRational(RationalType type) : type(type) {} public: /** * Returns if the number is a plain rational. * * @return true if rational, false otherwise */ inline bool isRational() const { return k == 0; } /** * Returns if the number is a plain integer. * * @return true if rational, false otherwise */ inline bool isInteger() const { return k == 0 && q.isInteger(); } /** * Returns the floor of the number \f$x = q + k \epsilon\f$ using the following formula * \f[ * \lfloor \beta(x) \rfloor = \left\{ * \begin{tabular}{ll} * $\lfloor q \rfloor$ & $\mathrm{if\ } q \notin Z$\\ * $q$ & $\mathrm{if\ } q \in Z \mathrm{\ and\ } k \geq 0$\\ * $q - 1$ & $\mathrm{if\ } q \in Z \mathrm{\ and\ } k < 0$ * \end{tabular}\right. * \f] */ inline Rational getFloor() const { if (q.isInteger()) { if (k >= 0) return q; else return q - 1; } else // If not an integer, just floor it return floor(q); } /** * Returns the rational part of the number * * @return the rational */ inline Rational getRational() const { return q; } /** The infinity constant */ static const EpsRational PlusInfinity; /** The negative infinity constant */ static const EpsRational MinusInfinity; /** The zero constant */ static const EpsRational Zero; /** The blank constructor */ EpsRational() : type(FINITE), q(0), k(0) {} /** Copy constructor */ EpsRational(const EpsRational& r) : type(r.type), q(r.q), k(r.k) {} /** * Constructor from a rational, constructs a new pair (q, 0). * * @param q the rational */ EpsRational(const Rational q) : type(FINITE), q(q), k(0) {} /** * Constructor from a rational and a given epsilon multiplier, constructs a * new pair (q, k). * * @param q the rational * @param k the epsilon multiplier */ EpsRational(const Rational q, const Rational k) : type(FINITE), q(q), k(k) {} /** * Addition operator for two EpsRational numbers. * * @param r the number to be added * @return the sum as defined in the class */ inline EpsRational operator + (const EpsRational& r) const { DebugAssert(type == FINITE, "EpsRational::operator +, adding to infinite number"); DebugAssert(r.type == FINITE, "EpsRational::operator +, adding an infinite number"); return EpsRational(q + r.q, k + r.k); } /** * Addition operator for two EpsRational numbers. * * @param r the number to be added * @return the sum as defined in the class */ inline EpsRational& operator += (const EpsRational& r) { DebugAssert(type == FINITE, "EpsRational::operator +, adding to infinite number"); q = q + r.q; k = k + r.k; return *this; } /** * Subtraction operator for two EpsRational numbers. * * @param r the number to be added * @return the sum as defined in the class */ inline EpsRational operator - (const EpsRational& r) const { DebugAssert(type == FINITE, "EpsRational::operator -, subtracting from infinite number"); DebugAssert(r.type == FINITE, "EpsRational::operator -, subtracting an infinite number"); return EpsRational(q - r.q, k - r.k); } /** * Multiplication operator EpsRational number and a rational number. * * @param a the number to be multiplied * @return the product as defined in the class */ inline EpsRational operator * (const Rational& a) const { DebugAssert(type == FINITE, "EpsRational::operator *, multiplying an infinite number"); return EpsRational(a * q, a * k); } /** * Division operator EpsRational number and a rational number. * * @param a the number to be multiplied * @return the product as defined in the class */ inline EpsRational operator / (const Rational& a) const { DebugAssert(type == FINITE, "EpsRational::operator *, dividing an infinite number"); return EpsRational(q / a, k / a); } /** * Equality comparison operator. */ inline bool operator == (const EpsRational& r) const { return (q == r.q && k == r.k); } /** * Less than or equal comparison operator. */ inline bool operator <= (const EpsRational& r) const { switch (r.type) { case FINITE: if (type == FINITE) // Normal comparison return (q < r.q || (q == r.q && k <= r.k)); else // Finite number is bigger only of the negative infinity return type == MINUS_INFINITY; case PLUS_INFINITY: // Everything is less then or equal than +inf return true; case MINUS_INFINITY: // Only -inf is less then or equal than -inf return (type == MINUS_INFINITY); default: // Ohohohohohoooooo, whats up FatalAssert(false, "EpsRational::operator <=, what kind of number is this????"); } return false; } /** * Less than comparison operator. */ inline bool operator < (const EpsRational& r) const { return !(r <= *this); } /** * Greater than comparison operator. */ inline bool operator > (const EpsRational& r) const { return !(*this <= r); } /** * Returns the string representation of the number. * * @return the string representation of the number */ std::string toString() const { switch (type) { case FINITE: return "(" + q.toString() + ", " + k.toString() + ")"; case PLUS_INFINITY: return "+inf"; case MINUS_INFINITY: return "-inf"; default: FatalAssert(false, "EpsRational::toString, what kind of number is this????"); } return "hm, what am I?"; } }; /** * Registers the atom given from the core. This atoms are stored so that they can be used * for theory propagation. * * @param e the expression (atom) that is part of the input formula */ void registerAtom(const Expr& e); private: /** A set of all integer variables */ std::set intVariables; /** * Return a Gomory cut plane derivation of the variable $x_i$. Mixed integer * Gomory cut can be constructed if *
    *
  • \f$x_i\f$ is a integer basic variable with a non-integer value *
  • all non-basic variables in the row of \f$x_i\f$ are assigned to their * upper or lower bounds *
  • all the values on the right side of the row have rational values (non * eps-rational values) *
*/ Theorem deriveGomoryCut(const Expr& x_i); /** * Tries to rafine the integer constraint of the theorem. For example, * x < 1 is rewritten as x <= 0, and x <(=) 1.5 is rewritten as x <= 1. * The constraint should be in the normal form. * * @param thm the derivation of the constraint */ Theorem rafineIntegerConstraints(const Theorem& thm); /** Are we consistent or not */ CDO consistent; /** The theorem explaining the inconsistency */ Theorem explanation; /** * The structure necessaty to hold the bounds. */ struct BoundInfo { /** The bound itself */ EpsRational bound; /** The assertion theoreem of the bound */ Theorem theorem; /** Constructor */ BoundInfo(const EpsRational& bound, const Theorem& thm): bound(bound), theorem(thm) {} /** The empty constructor for the map */ BoundInfo(): bound(0), theorem() {} /** * The comparator, just if we need it. Compares first by expressions then by bounds */ bool operator < (const BoundInfo& bI) const { // Get tje expressoins const Expr& expr1 = (theorem.isRewrite() ? theorem.getRHS() : theorem.getExpr()); const Expr& expr2 = (bI.theorem.isRewrite() ? bI.theorem.getRHS() : bI.theorem.getExpr()); std::cout << expr1 << " @ " << expr2 << std::endl; // Compare first by the expressions (right sides of expressions) if (expr1[1] == expr2[1]) // If the same, just return the bound comparison (plus a trick to order equal bounds, different relations) if (bound == bI.bound && expr1.getKind() != expr2.getKind()) return expr1.getKind() == LE; // LE before GE -- only case that can happen else return bound < bI.bound; else // Return the expression comparison return expr1[1] < expr2[1]; } }; /** * The structure necessaty to hold the bounds on expressions (for theory propagation). */ struct ExprBoundInfo { /** The bound itself */ EpsRational bound; /** The assertion theoreem of the bound */ Expr e; /** Constructor */ ExprBoundInfo(const EpsRational& bound, const Expr& e): bound(bound), e(e) {} /** The empty constructor for the map */ ExprBoundInfo(): bound(0) {} /** * The comparator, just if we need it. Compares first by expressions then by bounds */ bool operator < (const ExprBoundInfo& bI) const { // Compare first by the expressions (right sides of expressions) if (e[1] == bI.e[1]) // If the same, just return the bound comparison (plus a trick to order equal bounds, different relations) if (bound == bI.bound && e.getKind() != bI.e.getKind()) return e.getKind() == LE; // LE before GE -- only case that can happen else return bound < bI.bound; else // Return the expression comparison return e[1] < bI.e[1]; } }; /** The map from variables to lower bounds (these must be backtrackable) */ CDMap lowerBound; /** The map from variables to upper bounds (these must be backtrackable) */ CDMap upperBound; /** The current real valuation of the variables (these must be backtrackable for the last succesefull checkSAT!!!) */ CDMap beta; typedef Hash::hash_map TebleauxMap; //typedef google::sparse_hash_map > TebleauxMap; //typedef std::map TebleauxMap; typedef std::set SetOfVariables; typedef Hash::hash_map DependenciesMap; /** Maps variables to sets of variables that depend on it in the tableaux */ DependenciesMap dependenciesMap; /** The tableaux, a map from basic variables to the expressions over the non-basic ones (theorems that explain them how we got there) */ TebleauxMap tableaux; /** Additional tableaux map from expressions asserted to the corresponding theorems explaining the introduction of the new variables */ TebleauxMap freshVariables; /** A set containing all the unsatisfied basic variables */ std::set unsatBasicVariables; /** The vector to keep the assignments from fresh variables to expressions they represent */ std::vector assertedExpr; /** The backtrackable number of fresh variables asserted so far */ CDO assertedExprCount; /** A set of BoundInfo objects */ typedef std::set BoundInfoSet; /** Internal variable to see wheather to propagate or not */ bool propagate; /** * Propagate all that is possible from given assertion and its bound */ void propagateTheory(const Expr& assertExpr, const EpsRational& bound, const EpsRational& oldBound); /** * Store all the atoms from the formula in this set. It is searchable by an expression * and the bound. To get all the implied atoms, one just has to go up (down) and check if the * atom or it's negation are implied. */ BoundInfoSet allBounds; /** * Adds var to the dependencies sets of all the variables in the sum. * * @param var the variable on the left side * @param sum the sum that defines the variable */ void updateDependenciesAdd(const Expr& var, const Expr& sum); /** * Remove var from the dependencies sets of all the variables in the sum. * * @param var the variable on the left side * @param sum the sum that defines the variable */ void updateDependenciesRemove(const Expr& var, const Expr& sum); /** * Updates the dependencies if a right side of an expression in the tableaux is changed. For example, * if oldExpr is x + y and newExpr is y + z, var will be added to the dependency list of z, and removed * from the dependency list of x. * * @param oldExpr the old right side of the tableaux * @param newExpr the new right side of the tableaux * @param var the variable that is defined by these two expressions * @param skipVar a variable to skip when going through the expressions */ void updateDependencies(const Expr& oldExpr, const Expr& newExpr, const Expr& var, const Expr& skipVar); /** * Update the values of variables that have appeared in the tableaux due to backtracking. */ void updateFreshVariables(); /** * Updates the value of variable var by computing the value of expression e. * * @param var the variable to update * @param e the expression to compute */ void updateValue(const Expr& var, const Expr& e); /** * Returns a string representation of the tableaux. * * @return tableaux as string */ std::string tableauxAsString() const; /** * Returns a string representation of the unsat variables. * * @return unsat as string */ std::string unsatAsString() const; /** * Returns a string representation of the current bounds. * * @return tableaux as string */ std::string boundsAsString(); /** * Gets the equality of the fresh variable tableaux variable corresponding to this expression. If the expression has already been * asserted, the coresponding variable is returned, othervise a fresh variable is created and the theorem is returned. * * @param leftSide the left side of the asserted constraint * @return the equality theorem s = leftSide */ Theorem getVariableIntroThm(const Expr& leftSide); /** * Find the coefficient standing by the variable var in the expression expr. Expresion is expected to be * in canonical form, i.e either a rational constant, an arithmetic leaf (i.e. variable or term from some * other theory), (MULT rat leaf) where rat is a non-zero rational constant, leaf is an arithmetic leaf or * (PLUS \f$const term_0 term_1 ... term_n\f$) where each \f$term_i\f$ is either a leaf or (MULT \f$rat leaf\f$) * and each leaf in \f$term_i\f$ must be strictly greater than the leaf in \f$term_{i+1}\f$. * * @param var the variable * @param expr the expression to search in */ const Rational& findCoefficient(const Expr& var, const Expr& expr); /** * Return true iof the given variable is basic in the tableaux, i.e. it is on the left side, expressed * in terms of the non-basic variables. * * @param x the variable to be checked * @return true if the variable is basic, false if the variable is non-basic */ bool isBasic(const Expr& x) const; /** * Returns the coefficient at a_ij in the current tableaux, i.e. the coefficient * at x_j in the row of x_i. * * @param x_i a basic variable * @param x_j a non-basic variable * @return the reational coefficient */ Rational getTableauxEntry(const Expr& x_i, const Expr& x_j); /** * Swaps a basic variable \f$x_r\f$ and a non-basic variable \f$x_s\f$ such * that ars \f$a_{rs} \neq 0\f$. After pivoting, \f$x_s\f$ becomes basic and \f$x_r\f$ becomes non-basic. * The tableau is updated by replacing equation \f[x_r = \sum_{x_j \in N}{a_{rj}xj}\f] with * \f[x_s = \frac{x_r}{a_{rs}} - \sum_{x_j \in N }{\frac{a_{rj}}{a_rs}x_j}\f] and this equation * is used to eliminate \f$x_s\f$ from the rest of the tableau by substitution. * * @param x_r a basic variable * @param x_s a non-basic variable */ void pivot(const Expr& x_r, const Expr& x_s); /** * Sets the value of a non-basic variable \f$x_i\f$ to \f$v\f$ and adjusts the value of all * the basic variables so that all equations remain satisfied. * * @param x_i a non-basic variable * @param v the value to set the variable \f$x_i\f$ to */ void update(const Expr& x_i, const EpsRational& v); /** * Pivots the basic variable \f$x_i\f$ and the non-basic variable \f$x_j\f$. It also sets \f$x_i\f$ to \f$v\f$ and adjusts all basic * variables to keep the equations satisfied. * * @param x_i a basic variable * @param x_j a non-basic variable * @param v the valie to assign to x_i */ void pivotAndUpdate(const Expr& x_i, const Expr& x_j, const EpsRational& v); /** * Asserts a new upper bound constraint on a variable and performs a simple check for consistency (not complete). * * @param x_i the variable to assert the bound on * @param c the bound to assert */ QueryResult assertUpper(const Expr& x_i, const EpsRational& c, const Theorem& thm); /** * Asserts a new lower bound constraint on a variable and performs a simple check for consistency (not complete). * * @param x_i the variable to assert the bound on * @param c the bound to assert */ QueryResult assertLower(const Expr& x_i, const EpsRational& c, const Theorem& thm); /** * Asserts a new equality constraint on a variable by asserting both upper and lower bounds. * * @param x_i the variable to assert the bound on * @param c the bound to assert */ QueryResult assertEqual(const Expr& x_i, const EpsRational& c, const Theorem& thm); /** * Type of noramlization GCD = 1 or just first coefficient 1 */ typedef enum { NORMALIZE_GCD, NORMALIZE_UNIT } NormalizationType; /** * Given a canonized term, compute a factor to make all coefficients integer and relatively prime */ Expr computeNormalFactor(const Expr& rhs, NormalizationType type = NORMALIZE_GCD); /** * Normalize an equation (make all coefficients rel. prime integers) */ Theorem normalize(const Expr& e, NormalizationType type = NORMALIZE_GCD); /** * Normalize an equation (make all coefficients rel. prime integers) accepts a rewrite theorem over * eqn|ineqn and normalizes it and returns a theorem to that effect. */ Theorem normalize(const Theorem& thm, NormalizationType type = NORMALIZE_GCD); /** * Canonise the equation using the tebleaux equations, i.e. replace all the tableaux right sides * with the corresponding left sides and canonise the result. * * @param eq the equation to canonise * @return the explaining theorem */ Theorem substAndCanonizeModTableaux(const Theorem& eq); /** * Canonise the sum using the tebleaux equations, i.e. replace all the tableaux right sides * with the corresponding left sides and canonise the result. * * @param sum the canonised sum to canonise * @return the explaining theorem */ Theorem substAndCanonizeModTableaux(const Expr& sum); /** * Sustitute the given equation everywhere in the tableaux. * * @param eq the equation to use for substitution */ void substAndCanonizeTableaux(const Theorem& eq); /** * Given an equality eq: \f$\sum a_i x_i = y\f$ and a variable $var$ that appears in * on the left hand side, pivots $y$ and $var$ so that $y$ comes to the right-hand * side. * * @param eq the proof of the equality * @param var the variable to move to the right-hand side */ Theorem pivotRule(const Theorem& eq, const Expr& var); /** * Knowing that the tableaux row for \f$x_i\f$ is the problematic one, generate the * explanation clause. The variables in the row of \f$x_i = \sum_{x_j \in \mathcal{N}}{a_ij x_j}\f$ are separated to *
    *
  • \f$\mathcal{N}^+ = \left\lbrace x_j \in \mathcal{N} \; | \; a_{ij} > 0 \right\rbrace\f$ *
  • \f$\mathcal{N}^- = \left\lbrace x_j \in \mathcal{N} \; | \; a_{ij} < 0\right\rbrace\f$ *
* Then, the explanation clause to be returned is * \f[\Gamma = \left\lbrace x_j \leq u_j \; | \; x_j \in \mathcal{N}^+\right\rbrace \cup \left\lbrace l_j \leq x_j \; | \; * x_j \in \mathcal{N}^-\right\rbrace \cup \left\lbrace l_i \leq x_i \right\rbrace\f] * * @param var_it the variable that caused the clash * @return the theorem explainang the clash */ Theorem getLowerBoundExplanation(const TebleauxMap::iterator& var_it); /** * Knowing that the tableaux row for \f$x_i\f$ is the problematic one, generate the * explanation clause. The variables in the row of \f$x_i = \sum_{x_j \in \mathcal{N}}{a_ij x_j}\f$ are separated to *
    *
  • \f$\mathcal{N}^+ = \left\lbrace x_j \in \mathcal{N} \; | \; a_{ij} > 0 \right\rbrace\f$ *
  • \f$\mathcal{N}^- = \left\lbrace x_j \in \mathcal{N} \; | \; a_{ij} < 0\right\rbrace\f$ *
* Then, the explanation clause to be returned is * \f[\Gamma = \left\lbrace x_j \leq u_j \; | \; x_j \in \mathcal{N}^-\right\rbrace \cup \left\lbrace l_j \leq x_j \; | \; * x_j \in \mathcal{N}^+\right\rbrace \cup \left\lbrace x_i \leq u_i \right\rbrace\f] * * @param var_it the variable that caused the clash * @return the theorem explainang the clash */ Theorem getUpperBoundExplanation(const TebleauxMap::iterator& var_it); Theorem addInequalities(const Theorem& le_1, const Theorem& le_2); /** * Check the satisfiability */ QueryResult checkSatSimplex(); /** * Check the satisfiability of integer constraints */ QueryResult checkSatInteger(); /** * The last lemma that we asserted to check the integer satisfiability. We don't do checksat until * the lemma split has been asserted. */ CDO integer_lemma; public: /** * Gets the current lower bound on variable x. * * @param x the variable * @return the current lower bound on x */ EpsRational getLowerBound(const Expr& x) const; /** * Get the current upper bound on variable x. * * @param x the variable * @return the current upper bound on x */ EpsRational getUpperBound(const Expr& x) const; /** * Gets the theorem of the current lower bound on variable x. * * @param x the variable * @return the current lower bound on x */ Theorem getLowerBoundThm(const Expr& x) const; /** * Get the theorem of the current upper bound on variable x. * * @param x the variable * @return the current upper bound on x */ Theorem getUpperBoundThm(const Expr& x) const; /** * Gets the current valuation of variable x (beta). * * @param x the variable * @return the current value of variable x */ EpsRational getBeta(const Expr& x); // DDDDDDDDDDDDDDDDDDDDDDDDEEEEEEEEEEEEEEEEEEEEEEEJJJJJJJJJJJJJJJJJJJJJAAAAAAAAAAAAAAAAAAAAAAANNNNNNNNNNNNNNNNNNNNNNN }; } #endif cvc3-2.4.1/src/include/theory_simulate.h0000664000175400017540000000352610466450542020072 0ustar mdetersmdeters/*****************************************************************************/ /*! *\file theory_simulate.h *\brief Implementation of a symbolic simulator * * Author: Sergey Berezin * * Created: Tue Oct 7 10:13:15 2003 * *
* * License to use, copy, modify, sell and/or distribute this software * and its documentation for any purpose is hereby granted without * royalty, subject to the terms and conditions defined in the \ref * LICENSE file provided with this distribution. * *
* */ /*****************************************************************************/ #ifndef _cvc3__include__theory_simulate_h_ #define _cvc3__include__theory_simulate_h_ #include "theory.h" namespace CVC3 { class SimulateProofRules; /*****************************************************************************/ /*! * \class TheorySimulate * \ingroup Theories * \brief "Theory" of symbolic simulation. * * Author: Sergey Berezin * * Created: Tue Oct 7 10:13:15 2003 * * This theory owns the SIMULATE operator. It's job is to replace the above * expressions by their definitions using rewrite rules. */ /*****************************************************************************/ class TheorySimulate: public Theory { private: //! Our local proof rules SimulateProofRules* d_rules; //! Create proof rules for this theory SimulateProofRules* createProofRules(); public: //! Constructor TheorySimulate(TheoryCore* core); //! Destructor ~TheorySimulate(); // The required Theory API functions void assertFact(const Theorem& e) { } void checkSat(bool fullEffort) { } Theorem rewrite(const Expr& e); void computeType(const Expr& e); Expr computeTCC(const Expr& e); Expr parseExprOp(const Expr& e); ExprStream& print(ExprStream& os, const Expr& e); }; // end of class TheorySimulate } // end of namespace CVC3 #endif cvc3-2.4.1/src/include/command_line_exception.h0000664000175400017540000000220511267754362021360 0ustar mdetersmdeters/*****************************************************************************/ /*! * \file command_line_exception.h * * Author: Sergey Berezin * * Created: Fri May 30 14:59:51 2003 * *
* * License to use, copy, modify, sell and/or distribute this software * and its documentation for any purpose is hereby granted without * royalty, subject to the terms and conditions defined in the \ref * LICENSE file provided with this distribution. * *
* * An exception thrown on an error while processing a command line * argument. */ /*****************************************************************************/ #ifndef _cvc3__command_line_exception_h_ #define _cvc3__command_line_exception_h_ #include "exception.h" namespace CVC3 { class CLException: public Exception { public: // Constructors CLException() { } CLException(const std::string& msg): Exception(msg) { } CLException(const char* msg): Exception(msg) { } // Destructor virtual ~CLException() { } // Printing the message virtual std::string toString() const { return "Error while processing a command line option:\n " + d_msg; } }; } #endif cvc3-2.4.1/src/include/common_proof_rules.h0000664000175400017540000003041411231577260020556 0ustar mdetersmdeters/*****************************************************************************/ /*! * \file common_proof_rules.h * * Author: Sergey Berezin * * Created: Dec 11 18:15:37 GMT 2002 * *
* * License to use, copy, modify, sell and/or distribute this software * and its documentation for any purpose is hereby granted without * royalty, subject to the terms and conditions defined in the \ref * LICENSE file provided with this distribution. * *
* */ /*****************************************************************************/ // CLASS: CommonProofRules // // AUTHOR: Sergey Berezin, 12/09/2002 // // Description: Commonly used proof rules (reflexivity, symmetry, // transitivity, substitutivity, etc.). // // Normally, proof rule interfaces belong to their decision // procedures. However, in the case of equational logic, the rules // are so useful, that even some basic classes like Transformer use // these rules under the hood. Therefore, it is made public, and its // implementation is provided by the 'theorem' module. /////////////////////////////////////////////////////////////////////////////// #ifndef _cvc3__common_proof_rules_h_ #define _cvc3__common_proof_rules_h_ #include namespace CVC3 { class Theorem; class Theorem3; class Expr; class Op; class CommonProofRules { public: //! Destructor virtual ~CommonProofRules() { } //////////////////////////////////////////////////////////////////////// // TCC rules (3-valued logic) //////////////////////////////////////////////////////////////////////// // G1 |- phi G2 |- D_phi // ------------------------- // G1,G2 |-_3 phi /*! * @brief Convert 2-valued formula to 3-valued by discharging its * TCC (\f$D_\phi\f$): * \f[\frac{\Gamma_1\vdash_2 \phi\quad \Gamma_2\vdash_2 D_{\phi}} * {\Gamma_1,\,\Gamma_2\vdash_3\phi}\f] */ virtual Theorem3 queryTCC(const Theorem& phi, const Theorem& D_phi) = 0; // G0,a1,...,an |-_3 phi G1 |- D_a1 ... Gn |- D_an // ------------------------------------------------- // G0,G1,...,Gn |-_3 (a1 & ... & an) -> phi /*! * @brief 3-valued implication introduction rule: * \f[\frac{\Gamma_0,\,\alpha_1\,\ldots,\,\alpha_n\vdash_3\phi\quad * (\Gamma_i\vdash D_{\alpha_i})_{i\in[1..n]}} * {\Gamma_0,\,\Gamma_1, \ldots, \Gamma_n\vdash_3 * (\bigwedge_{i=1}^n\alpha_i)\to\phi}\f] * * \param phi is the formula \f$\phi\f$ * \param assump is the vector of assumptions \f$\alpha_1\ldots\alpha_n\f$ * \param tccs is the vector of TCCs for assumptions * \f$D_{\alpha_1}\ldots D_{\alpha_n}\f$ */ virtual Theorem3 implIntro3(const Theorem3& phi, const std::vector& assump, const std::vector& tccs) = 0; //////////////////////////////////////////////////////////////////////// // Common rules //////////////////////////////////////////////////////////////////////// // ==> u:a |- a //! \f[\frac{}{a\vdash a}\f] virtual Theorem assumpRule(const Expr& a, int scope = -1) = 0; // ==> a == a or ==> a IFF a //! \f[\frac{}{a = a}\quad or \quad\frac{}{a \Leftrightarrow a}\f] virtual Theorem reflexivityRule(const Expr& a) = 0; //! ==> (a == a) IFF TRUE virtual Theorem rewriteReflexivity(const Expr& a_eq_a) = 0; // a1 == a2 ==> a2 == a1 (same for IFF) //! \f[\frac{a_1=a_2}{a_2=a_1}\f] (same for IFF) virtual Theorem symmetryRule(const Theorem& a1_eq_a2) = 0; // ==> (a1 == a2) IFF (a2 == a1) //! \f[\frac{}{(a_1=a_2)\Leftrightarrow (a_2=a_1)}\f] virtual Theorem rewriteUsingSymmetry(const Expr& a1_eq_a2) = 0; // (a1 == a2) & (a2 == a3) ==> (a1 == a3) [same for IFF] //! \f[\frac{a_1=a_2\quad a_2=a_3}{a_1=a_3}\f] (same for IFF) virtual Theorem transitivityRule(const Theorem& a1_eq_a2, const Theorem& a2_eq_a3) = 0; //! Optimized case for expr with one child virtual Theorem substitutivityRule(const Expr& e, const Theorem& thm) = 0; //! Optimized case for expr with two children virtual Theorem substitutivityRule(const Expr& e, const Theorem& thm1, const Theorem& thm2) = 0; // (c_1 == d_1) & ... & (c_n == d_n) // ==> op(c_1,...,c_n) == op(d_1,...,d_n) /*! @brief \f[\frac{(c_1=d_1)\wedge\ldots\wedge(c_n=d_n)} {op(c_1,\ldots,c_n)=op(d_1,\ldots,d_n)}\f] */ virtual Theorem substitutivityRule(const Op& op, const std::vector& thms) = 0; // (c_1 == d_1) & ... & (c_n == d_n) // ==> op(c_1,...,c_n) == op(d_1,...,d_n) /*! @brief \f[\frac{(c_1=d_1)\wedge\ldots\wedge(c_n=d_n)} {op(c_1,\ldots,c_n)=op(d_1,\ldots,d_n)}\f] except that only those arguments are given that \f$c_i\not=d_i\f$. \param e is the original expression \f$op(c_1,\ldots,c_n)\f$. \param changed is the vector of indices of changed kids \param thms are the theorems \f$c_i=d_i\f$ for the changed kids. */ virtual Theorem substitutivityRule(const Expr& e, const std::vector& changed, const std::vector& thms) = 0; virtual Theorem substitutivityRule(const Expr& e, const int changed, const Theorem& thm) = 0; // |- e, |- !e ==> |- FALSE /*! @brief \f[\frac{\Gamma_1\vdash e\quad\Gamma_2\vdash \neg e} {\Gamma_1\cup\Gamma_2\vdash \mathrm{FALSE}} \f] */ virtual Theorem contradictionRule(const Theorem& e, const Theorem& not_e) = 0; // |- e OR !e virtual Theorem excludedMiddle(const Expr& e) = 0; // e ==> e IFF TRUE //! \f[\frac{\Gamma\vdash e}{\Gamma\vdash e\Leftrightarrow\mathrm{TRUE}}\f] virtual Theorem iffTrue(const Theorem& e) = 0; // e ==> !e IFF FALSE //! \f[\frac{\Gamma\vdash e}{\Gamma\vdash\neg e\Leftrightarrow\mathrm{FALSE}}\f] virtual Theorem iffNotFalse(const Theorem& e) = 0; // e IFF TRUE ==> e //! \f[\frac{\Gamma\vdash e\Leftrightarrow\mathrm{TRUE}}{\Gamma\vdash e}\f] virtual Theorem iffTrueElim(const Theorem& e) = 0; // e IFF FALSE ==> !e //! \f[\frac{\Gamma\vdash e\Leftrightarrow\mathrm{FALSE}}{\Gamma\vdash\neg e}\f] virtual Theorem iffFalseElim(const Theorem& e) = 0; //! e1 <=> e2 ==> ~e1 <=> ~e2 /*! \f[\frac{\Gamma\vdash e_1\Leftrightarrow e_2} * {\Gamma\vdash\sim e_1\Leftrightarrow\sim e_2}\f] * Where ~e is the inverse of e (that is, ~(!e') = e'). */ virtual Theorem iffContrapositive(const Theorem& thm) = 0; // !!e ==> e //! \f[\frac{\Gamma\vdash\neg\neg e}{\Gamma\vdash e}\f] virtual Theorem notNotElim(const Theorem& not_not_e) = 0; // e1 AND (e1 IFF e2) ==> e2 /*! @brief \f[\frac{\Gamma_1\vdash e_1\quad \Gamma_2\vdash(e_1\Leftrightarrow e_2)} {\Gamma_1\cup\Gamma_2\vdash e_2} \f] */ virtual Theorem iffMP(const Theorem& e1, const Theorem& e1_iff_e2) = 0; // e1 AND (e1 IMPLIES e2) ==> e2 /*! @brief \f[\frac{\Gamma_1\vdash e_1\quad \Gamma_2\vdash(e_1\Rightarrow e_2)} {\Gamma_1\cup\Gamma_2\vdash e_2} \f] */ virtual Theorem implMP(const Theorem& e1, const Theorem& e1_impl_e2) = 0; // AND(e_1,...e_n) ==> e_i //! \f[\frac{\vdash e_1\wedge\cdots\wedge e_n}{\vdash e_i}\f] virtual Theorem andElim(const Theorem& e, int i) = 0; // e1, e2 ==> AND(e1, e2) /*! @brief \f[\frac{\Gamma_1\vdash e_1\quad \Gamma_2\vdash e_2} {\Gamma_1\cup\Gamma_2\vdash e_1\wedge e_2} \f] */ virtual Theorem andIntro(const Theorem& e1, const Theorem& e2) = 0; // e1, ..., en ==> AND(e1, ..., en) /*! @brief \f[\frac{\Gamma_1\vdash e_1\quad \cdots \quad\Gamma_n\vdash e_n} {\bigcup_{i=1}^n\Gamma_i\vdash \bigwedge_{i=1}^n e_i} \f] */ virtual Theorem andIntro(const std::vector& es) = 0; // G,a1,...,an |- phi // ------------------------------------------------- // G |- (a1 & ... & an) -> phi /*! * @brief Implication introduction rule: * \f[\frac{\Gamma,\,\alpha_1\,\ldots,\,\alpha_n\vdash\phi} * {\Gamma\vdash(\bigwedge_{i=1}^n\alpha_i)\to\phi}\f] * * \param phi is the formula \f$\phi\f$ * \param assump is the vector of assumptions \f$\alpha_1\ldots\alpha_n\f$ */ virtual Theorem implIntro(const Theorem& phi, const std::vector& assump) = 0; //! e1 => e2 ==> ~e2 => ~e1 /*! \f[\frac{\Gamma\vdash e_1\Rightarrow e_2} * {\Gamma\vdash\sim e_2\Rightarrow\sim e_1}\f] * Where ~e is the inverse of e (that is, ~(!e') = e'). */ virtual Theorem implContrapositive(const Theorem& thm) = 0; //! ==> ITE(TRUE, e1, e2) == e1 virtual Theorem rewriteIteTrue(const Expr& e) = 0; //! ==> ITE(FALSE, e1, e2) == e2 virtual Theorem rewriteIteFalse(const Expr& e) = 0; //! ==> ITE(c, e, e) == e virtual Theorem rewriteIteSame(const Expr& e) = 0; // NOT e ==> e IFF FALSE //! \f[\frac{\vdash\neg e}{\vdash e\Leftrightarrow\mathrm{FALSE}}\f] virtual Theorem notToIff(const Theorem& not_e) = 0; // e1 XOR e2 ==> e1 IFF (NOT e2) //! \f[\frac{\vdash e_1 XOR e_2}{\vdash e_1\Leftrightarrow(\neg e_2)}\f] virtual Theorem xorToIff(const Expr& e) = 0; //! ==> (e1 <=> e2) <=> [simplified expr] /*! Rewrite formulas like FALSE/TRUE <=> e, e <=> NOT e, etc. */ virtual Theorem rewriteIff(const Expr& e) = 0; // AND and OR rewrites check for TRUE and FALSE arguments and // remove them or collapse the entire expression to TRUE and FALSE // appropriately //! ==> AND(e1,e2) IFF [simplified expr] virtual Theorem rewriteAnd(const Expr& e) = 0; //! ==> OR(e1,...,en) IFF [simplified expr] virtual Theorem rewriteOr(const Expr& e) = 0; //! ==> NOT TRUE IFF FALSE virtual Theorem rewriteNotTrue(const Expr& e) = 0; //! ==> NOT FALSE IFF TRUE virtual Theorem rewriteNotFalse(const Expr& e) = 0; //! ==> NOT NOT e IFF e, takes !!e virtual Theorem rewriteNotNot(const Expr& e) = 0; //! ==> NOT FORALL (vars): e IFF EXISTS (vars) NOT e virtual Theorem rewriteNotForall(const Expr& forallExpr) = 0; //! ==> NOT EXISTS (vars): e IFF FORALL (vars) NOT e virtual Theorem rewriteNotExists(const Expr& existsExpr) = 0; //From expr EXISTS(x1: t1, ..., xn: tn) phi(x1,...,cn) //we create phi(c1,...,cn) where ci is a skolem constant //defined by the original expression and the index i. virtual Expr skolemize(const Expr& e) = 0; /*! skolem rewrite rule: Introduces axiom |- Exists(x) phi(x) <=> phi(c) * where c is a constant defined by the expression Exists(x) phi(x) */ virtual Theorem skolemizeRewrite(const Expr& e) = 0; //! Special version of skolemizeRewrite for "EXISTS x. t = x" virtual Theorem skolemizeRewriteVar(const Expr& e) = 0; //! |- EXISTS x. e = x virtual Theorem varIntroRule(const Expr& e) = 0; /*! @brief If thm is (EXISTS x: phi(x)), create the Skolemized version and add it to the database. Otherwise returns just thm. */ /*! * \param thm is the Theorem(EXISTS x: phi(x)) */ virtual Theorem skolemize(const Theorem& thm) = 0; //! Retrun a theorem "|- e = v" for a new Skolem constant v /*! * This is equivalent to skolemize(d_core->varIntroRule(e)), only more * efficient. */ virtual Theorem varIntroSkolem(const Expr& e) = 0; // Derived rules //! ==> TRUE virtual Theorem trueTheorem() = 0; //! AND(e1,e2) ==> [simplified expr] virtual Theorem rewriteAnd(const Theorem& e) = 0; //! OR(e1,...,en) ==> [simplified expr] virtual Theorem rewriteOr(const Theorem& e) = 0; // TODO: do we really need this? virtual std::vector& getSkolemAxioms() = 0; //TODO: do we need this? virtual void clearSkolemAxioms() = 0; virtual Theorem ackermann(const Expr& e1, const Expr& e2) = 0; // Given a propositional atom containing embedded ite's, lifts first ite condition // to form a Boolean ITE // |- P(...ite(a,b,c)...) <=> ite(a,P(...b...),P(...c...)) virtual Theorem liftOneITE(const Expr& e) = 0; }; // end of class CommonProofRules } // end of namespace CVC3 #endif cvc3-2.4.1/src/include/hash_table.h0000664000175400017540000005321611153264564016751 0ustar mdetersmdeters/*****************************************************************************/ /*! *\file hash_table.h *\brief hash table implementation * * Author: Alexander Fuchs * * Created: Thu Oct 19 11:04:00 2006 * *
* * License to use, copy, modify, sell and/or distribute this software * and its documentation for any purpose is hereby granted without * royalty, subject to the terms and conditions defined in the \ref * LICENSE file provided with this distribution. * *
*/ /*****************************************************************************/ /* * Copyright (c) 1996,1997 * Silicon Graphics Computer Systems, Inc. * * Permission to use, copy, modify, distribute and sell this software * and its documentation for any purpose is hereby granted without fee, * provided that the above copyright notice appear in all copies and * that both that copyright notice and this permission notice appear * in supporting documentation. Silicon Graphics makes no * representations about the suitability of this software for any * purpose. It is provided "as is" without express or implied warranty. * * * Copyright (c) 1994 * Hewlett-Packard Company * * Permission to use, copy, modify, distribute and sell this software * and its documentation for any purpose is hereby granted without fee, * provided that the above copyright notice appear in all copies and * that both that copyright notice and this permission notice appear * in supporting documentation. Hewlett-Packard Company makes no * representations about the suitability of this software for any * purpose. It is provided "as is" without express or implied warranty. * */ // this implementation is in essence a subset of the SGI implementation: // http://www.sgi.com/tech/stl/stl_hashtable.h #ifndef _cvc3__hash__hash_table_h_ #define _cvc3__hash__hash_table_h_ #include #include #include #include #include "hash_fun.h" #include "os.h" // For some reason, including debug.h doesn't work--so redeclare macros here #ifdef _CVC3_DEBUG_MODE #define DebugAssert(cond, str) if(!(cond)) \ CVC3::debugError(__FILE__, __LINE__, #cond, str) namespace CVC3 { extern CVC_DLL void debugError(const std::string& file, int line, const std::string& cond, const std::string& msg); } #else #define DebugAssert(cond, str) #endif namespace Hash { // get size_t from hash_fun, which gets it from cstddef typedef size_t size_type; /// primes for increasing the hash table size // Note: assumes size_type is unsigned and at least 32 bits. const size_type num_primes = 28; static const size_type prime_list[num_primes] = { 53ul, 97ul, 193ul, 389ul, 769ul, 1543ul, 3079ul, 6151ul, 12289ul, 24593ul, 49157ul, 98317ul, 196613ul, 393241ul, 786433ul, 1572869ul, 3145739ul, 6291469ul, 12582917ul, 25165843ul, 50331653ul, 100663319ul, 201326611ul, 402653189ul, 805306457ul, 1610612741ul, 3221225473ul, 4294967291ul }; inline size_type next_prime(size_type n) { const size_type* first = prime_list; const size_type* last = prime_list + (size_type)num_primes; const size_type* pos = std::lower_bound(first, last, n); return pos == last ? *(last - 1) : *pos; } /*! template to instante to hash map and hash set based on the sgi implementation: http://www.sgi.com/tech/stl/HashedAssociativeContainer.html _Key: hash key type _Data: key + value data to store _HashFcn: functional class providing a hash function: int(_Key) Note: in some STL implementations hash is already part of some extension an in namespace std or stdext, in some it is not. So we assume that it is not available. :TODO: _EqualKey: functional class providing a comparison function: bool(_Key, _Key) returns true iff two keys are considered to be equal _ExtractKey: extracts key from _Data: _Key(_Data) */ // // can't use debug.h as debug.h uses hash maps... // // implemented as an array of lists (buckets) template class hash_table { /// types public: // interface typedefs typedef Hash::size_type size_type; typedef _Key key_type; typedef _Value value_type; typedef _HashFcn hasher; typedef _EqualKey key_equal; protected: // a bucket is a list of values // using an STL list makes it more complicated to have a nice end iterator, // as iterators of different lists can not be compared // (at least in the MS STL). // so instead we implement our own single-linked list here, // where NULL is the end iterator for all lists. struct BucketNode { BucketNode(BucketNode* next, const value_type& value) : d_next(next), d_value(value) { }; BucketNode* d_next; value_type d_value; }; typedef BucketNode Bucket; // the buckets are kept in an array typedef std::vector Data; typedef typename Data::iterator data_iter; typedef typename Data::const_iterator data_const_iter; public: // iterators class iterator; friend class iterator; class const_iterator; friend class const_iterator; /// variables protected: /// template parameters // the hash function for a key hasher d_hash; // the equality function between keys key_equal d_equal; // extraction of key from data _ExtractKey d_extractKey; // the current number of elements - stored for efficiency size_type d_size; // the hash table - an array of buckets Data d_data; /// methods protected: /// template parameters // the hash function for a key size_type hash(const key_type& key) const { return d_hash(key); } // equality between keys bool equal(const key_type& key1, const key_type& key2) const { return d_equal(key1, key2); } // extraction of a key const key_type& extractKey(const value_type& value) const { return d_extractKey(value); } /// bucket retrieval // returns the index in the array which contains the bucket // with the keys mapping to the same hash value as key size_type getBucketIndex(const key_type& key) const { return (hash(key) % d_data.size()); } Bucket* getBucketByKey(const key_type& key) { return getBucketByIndex(getBucketIndex(key)); } const Bucket* getBucketByKey(const key_type& key) const { return getBucketByIndex(getBucketIndex(key)); } Bucket* getBucketByIndex(const size_type index) { DebugAssert(index < d_data.size(),"hash_table::getBucketByIndex"); return d_data.at(index); } const Bucket* getBucketByIndex(const size_type index) const { DebugAssert(index < d_data.size(),"hash_table::getBucketByIndex (const)"); return d_data.at(index); } /// resize // increase the size of the table, typically if the load factor is too high void resize() { if (load_factor() > 1) { // create new table with doubled size size //size_type size = 2 * d_data.size(); // this is simple, but might not be efficient for bad hash functions, // which for example mainly hash to values which contain 2 as a factor. // thus, instead we go from a prime to a prime of more or less double size. size_type size = next_prime(d_data.size() + 1); Data copy(size, NULL); // move entries to new table for (size_type i = 0; i < d_data.size(); ++i) { // head of current bucket to move BucketNode* bucket = d_data[i]; while (bucket != NULL) { // move head of old bucket BucketNode* current = bucket; bucket = bucket->d_next; // move old head to new bucket size_type new_index = hash(extractKey(current->d_value)) % size; BucketNode* new_bucket = copy[new_index]; current->d_next = new_bucket; copy[new_index] = current; } d_data[i] = NULL; } d_data.swap(copy); } } public: /// constructors // default size is 16 buckets hash_table() : d_hash(_HashFcn()), d_equal(_EqualKey()), d_extractKey(_ExtractKey()), d_size(0), d_data(16) { init(); }; // specifiy initial number of buckets - must be positive hash_table(size_type initial_capacity) : d_hash(_HashFcn()), d_equal(_EqualKey()), d_extractKey(_ExtractKey()), d_size(0), d_data(initial_capacity) { init(); }; // specifiy initial number of buckets and hash function hash_table(size_type initial_capacity, const _HashFcn& hash) : d_hash(hash), d_equal(_EqualKey()), d_extractKey(_ExtractKey()), d_size(0), d_data(initial_capacity) { init(); }; // specifiy initial number of buckets, hash and equal function hash_table(size_type initial_capacity, const _HashFcn& hash, const _EqualKey& equal) : d_hash(hash), d_equal(equal), d_extractKey(_ExtractKey()), d_size(0), d_data(initial_capacity) { init(); }; // copy hash table hash_table(const hash_table& other) : d_hash(other.d_hash), d_equal(other.d_equal), d_extractKey(other.d_extractKey), d_size(other.d_size), d_data(0) { assignTable(other.d_data); }; ~hash_table() { clear(); } // assign hash table hash_table& operator=(const hash_table& other) { if (this != &other) { clear(); d_hash = other.d_hash; d_equal = other.d_equal; d_extractKey = other.d_extractKey; d_size = other.d_size; assignTable(other.d_data); } return *this; } // replaces the current hash table with the given one void assignTable(const Data& data) { // copy elements: // default assignment operator does not work if value_type contains // constants, which should be the case as the key should be constant. // so not even shrinking a vector is possible, // so create a new table instead and swap with the current one. Data tmp(data.size()); d_data.swap(tmp); // for each bucket ... for (size_type i = 0; i < data.size(); ++i) { // .. copy each element DebugAssert(i < d_data.size(),"hash_table::operator="); // copy bucket if not empty Bucket* source = data[i]; if (source != NULL) { // set first element Bucket* target = new BucketNode(NULL, source->d_value); d_data[i] = target; source = source->d_next; // copy remaining nodes while (source != NULL) { target->d_next = new BucketNode(NULL, source->d_value); target = target->d_next; source = source->d_next; } } } } void swap(hash_table& other) { std::swap(d_hash, other.d_hash); std::swap(d_equal, other.d_equal); std::swap(d_extractKey, other.d_extractKey); std::swap(d_size, other.d_size); d_data.swap(other.d_data); } // sets all buckets to NULL void init() { for (size_type i = 0; i < d_data.size(); ++i) { d_data[i] = NULL; } } // empty all buckets void clear() { d_size = 0; for (size_type i = 0; i < d_data.size(); ++i) { BucketNode* head = d_data[i]; while (head != NULL) { BucketNode* next = head->d_next; delete head; head = next; } d_data[i] = NULL; } } /// operations // returns end iterator if key was not bound iterator find(const key_type& key) { for (BucketNode* node = getBucketByKey(key); node != NULL; node = node->d_next) { if (equal(extractKey(node->d_value), key)) { return iterator(this, node); } } return end(); } // const version of find const_iterator find(const key_type& key) const { for (const BucketNode* node = getBucketByKey(key); node != NULL; node = node->d_next) { if (equal(extractKey(node->d_value), key)) { return const_iterator(this, node); } } return end(); } // adds the mapping from key to data, if key is still unbound // otherwise returns false std::pair insert(const value_type& value) { // resize in case we insert resize(); const key_type& key = extractKey(value); size_type index = getBucketIndex(key); // check if key is already bound for (BucketNode* node = d_data[index]; node != NULL; node = node->d_next) { if (equal(extractKey(node->d_value), key)) { return std::make_pair(end(), false); } } // insert new value ++d_size; d_data[index] = new BucketNode(d_data[index], value); return std::make_pair(iterator(this, d_data[index]), true); } // if key in value is already bound, // returns that bindings, // otherwise inserts value and returns it. value_type& find_or_insert(const value_type& value) { // resize in case we insert resize(); const key_type& key = extractKey(value); size_type index = getBucketIndex(key); // check if key is already bound for (BucketNode* node = d_data[index]; node != NULL; node = node->d_next) { if (equal(extractKey(node->d_value), key)) { return node->d_value; } } // insert new value ++d_size; d_data[index] = new BucketNode(d_data[index], value); return d_data[index]->d_value; } // removes binding of key // returns number of keys removed, // i.e. 1 if key was bound, 0 if key was not bound. size_type erase(const key_type& key) { size_type index = getBucketIndex(key); // keep track of the node previous to the current one BucketNode* prev = NULL; for (BucketNode* node = d_data[index]; node != NULL; node = node->d_next) { if (equal(extractKey(node->d_value), key)) { --d_size; // remove the bucket's head if (prev == NULL) { d_data[index] = node->d_next; } // remove within the list; else { prev->d_next = node->d_next; } delete node; return 1; } prev = node; } return 0; } // removes element pointed to by iter, // returns element after iter. const_iterator erase(const const_iterator& iter) { const_iterator next(iter); ++next; const key_type& key = extractKey(*iter); size_type index = getBucketIndex(key); // keep track of the node previous to the current one BucketNode* prev = NULL; for (BucketNode* node = d_data[index]; node != NULL; node = node->d_next) { if (equal(extractKey(node->d_value), key)) { --d_size; // remove the bucket's head if (prev == NULL) { d_data[index] = node->d_next; } // remove within the list; else { prev->d_next = node->d_next; } delete node; return next; } prev = node; } return next; } /// status // is the key bound? bool contains(const key_type& key) const { return (find(key) != end()); } // returns the number of times a key is bound, // i.e. 0 or 1 size_type count(const _Key& key) const { if (contains(key)) { return 1; } else { return 0; } } // is the hash table empty? bool empty() const { return (d_size == 0); } // the number of elements in the hash table size_type size() const { return d_size; } // the number of buckets in the hash table size_type bucket_count() const { return d_data.size(); } // returns the average number of elements per bucket float load_factor() const { return (float(d_size) / float(d_data.size())); } /// iterators // returns forward iterator to iterate over all key/data pairs iterator begin() { if (d_size > 0) { // find first non-empty bucket size_type index = 0; while (d_data[index] == NULL) { ++index; } return iterator(this, d_data[index]); } else { return end(); } } // const version of begin const_iterator begin() const { if (d_size > 0) { // find first non-empty bucket size_type index = 0; while (d_data[index] == NULL) { ++index; } return const_iterator(this, d_data[index]); } else { return end(); } } // returns end iterator iterator end() { return iterator(this, NULL); } // const version of end const_iterator end() const { return const_iterator(this, NULL); } /// inner classes // iterator over hashtable elements // modifying the hash table leaves iterator intact, // unless the key in the value it points to is modified/deleted class iterator { friend class hash_table; friend class const_iterator; /// variables protected: // the hash table of this iterator hash_table* d_hash_table; // iterator points to current element in some bucket BucketNode* d_node; /// methods protected: // used by hash_table to create an iterator iterator(hash_table* hash_table, BucketNode* node) : d_hash_table(hash_table), d_node(node) { } public: // public default constructor, // leaves the iterator in undefined state. iterator() : d_hash_table(NULL), d_node(NULL) { } // copy constructor iterator(const iterator& other) : d_hash_table(other.d_hash_table), d_node(other.d_node) { } // assignment iterator& operator=(const iterator& other) { if (this != &other) { d_hash_table = other.d_hash_table; d_node = other.d_node; } return *this; } // go to next data - pre-increment iterator& operator++() { // must not be the end iterator DebugAssert(d_node != NULL, "hash operator++"); // get current bucket index size_type index = d_hash_table->getBucketIndex(d_hash_table->extractKey(d_node->d_value)); // go to next entry in bucket d_node = d_node->d_next; // while current bucket empty while (d_node == NULL) { // go to next bucket ++index; // all buckets exhausted if (index == d_hash_table->d_data.size()) { // unfortunately this does not work, as end() returns a tmp value // return d_hash_table->end(); *this = d_hash_table->end(); return *this; } DebugAssert(index < d_hash_table->d_data.size(), "hash operator++ 2"); d_node = d_hash_table->getBucketByIndex(index); } return *this; }; // go to next data - post-increment iterator operator++(int) { iterator tmp = *this; ++(*this); return tmp; } value_type& operator*() const { return d_node->d_value; } value_type* operator->() const { return &(operator*()); } // are two iterator identical? bool operator==(const iterator& other) const { // if the same bucket iterator, then it must be the same hash table DebugAssert(d_node == NULL || d_node != other.d_node || d_hash_table == other.d_hash_table, "hash operator=="); return (d_node == other.d_node); } // negation of == bool operator!=(const iterator& other) const { return !(*this == other); } }; // const iterator over hashtable elements // modifying the hash table leaves iterator intact, // unless the key in the value it points to is modified/deleted class const_iterator { friend class hash_table; /// variables protected: // the hash table of this iterator const hash_table* d_hash_table; // iterator points to current element in some bucket const BucketNode* d_node; /// methods protected: // used by hash_table to create an iterator const_iterator(hash_table const* hash_table, const BucketNode* node) : d_hash_table(hash_table), d_node(node) { } public: // public default constructor, // leaves the iterator in undefined state. const_iterator() : d_hash_table(NULL), d_node(NULL) { } // copy constructor const_iterator(const const_iterator& other) : d_hash_table(other.d_hash_table), d_node(other.d_node) { } // conversion constructor from non-const iterator const_iterator(const iterator& other) : d_hash_table(other.d_hash_table), d_node(other.d_node) { } // assignment const_iterator& operator=(const const_iterator& other) { if (this != &other) { d_hash_table = other.d_hash_table; d_node = other.d_node; } return *this; } // go to next data - pre-increment const_iterator& operator++() { // must not be the end iterator DebugAssert(d_node != NULL, ""); // get current bucket index size_type index = d_hash_table->getBucketIndex(d_hash_table->extractKey(d_node->d_value)); // go to next entry in bucket d_node = d_node->d_next; // while current bucket empty while (d_node == NULL) { // go to next bucket ++index; // all buckets exhausted if (index == d_hash_table->d_data.size()) { // unfortunately this does not work, as end() returns a tmp value // return d_hash_table->end(); *this = d_hash_table->end(); return *this; } DebugAssert(index < d_hash_table->d_data.size(),""); d_node = d_hash_table->getBucketByIndex(index); } return *this; }; // go to next data - post-increment const_iterator operator++(int) { const_iterator tmp = *this; ++(*this); return tmp; } const value_type& operator*() const { return d_node->d_value; } const value_type* operator->() const { return &(operator*()); } // are two iterator identical? bool operator==(const const_iterator& other) const { // if the same bucket iterator, then it must be the same hash table DebugAssert(d_node == NULL || d_node != other.d_node || d_hash_table == other.d_hash_table,""); return (d_node == other.d_node); } // negation of == bool operator!=(const const_iterator& other) const { return !(*this == other); } }; }; } #endif cvc3-2.4.1/src/include/theory_core.h0000644000175400017540000004461511624746722017206 0ustar mdetersmdeters/*****************************************************************************/ /*! * \file theory_core.h * * Author: Clark Barrett * * Created: Thu Jan 30 16:58:05 2003 * *
* * License to use, copy, modify, sell and/or distribute this software * and its documentation for any purpose is hereby granted without * royalty, subject to the terms and conditions defined in the \ref * LICENSE file provided with this distribution. * *
* */ /*****************************************************************************/ #ifndef _cvc3__include__theory_core_h_ #define _cvc3__include__theory_core_h_ #include #include "theory.h" #include "cdmap.h" #include "statistics.h" #include #include "notifylist.h" #include #include //#include "expr_transform.h" namespace CVC3 { class ExprTransform; // class Statistics; class CoreProofRules; class Translator; /*****************************************************************************/ /*! *\class TheoryCore *\ingroup Theories *\brief This theory handles the built-in logical connectives plus equality. * It also handles the registration and cooperation among all other theories. * * Author: Clark Barrett * * Created: Sat Feb 8 14:54:05 2003 */ /*****************************************************************************/ class TheoryCore :public Theory { friend class Theory; //! Context manager ContextManager* d_cm; //! Theorem manager TheoremManager* d_tm; //! Core proof rules CoreProofRules* d_rules; //! Reference to command line flags const CLFlags& d_flags; //! Reference to statistics Statistics& d_statistics; //! PrettyPrinter (we own it) PrettyPrinter* d_printer; //! Type Computer ExprManager::TypeComputer* d_typeComputer; //! Expr Transformer ExprTransform* d_exprTrans; //! Translator Translator* d_translator; //! Assertion queue std::queue d_queue; //! Queue of facts to be sent to the SearchEngine std::vector d_queueSE; //! Inconsistent flag CDO d_inconsistent; //! The set of reasons for incompleteness (empty when we are complete) CDMap d_incomplete; //! Proof of inconsistent CDO d_incThm; //! List of all active terms in the system (for quantifier instantiation) CDList d_terms; //! Map from active terms to theorems that introduced those terms std::hash_map d_termTheorems; // CDMap d_termTheorems; //! List of all active non-equality atomic formulas in the system (for quantifier instantiation) CDList d_predicates; //! List of variables that were created up to this point std::vector d_vars; //! Database of declared identifiers std::map d_globals; //! Bound variable stack: a vector of pairs std::vector > d_boundVarStack; //! Map for bound vars std::hash_map d_boundVarMap; //! Top-level cache for parser // This cache is only used when there are no bound variables ExprMap d_parseCacheTop; //! Alternative cache for parser when not at top-level // This cache used when there are bound variables - and it is cleared // every time the bound variable stack changes ExprMap d_parseCacheOther; //! Current cache being used for parser ExprMap* d_parseCache; //! Cache for tcc's ExprMap d_tccCache; //! Array of registered theories std::vector d_theories; //! Array mapping kinds to theories std::hash_map d_theoryMap; //! The theory which has the solver (if any) Theory* d_solver; //! Mapping of compound type variables to simpler types (model generation) ExprHashMap > d_varModelMap; //! Mapping of intermediate variables to their values ExprHashMap d_varAssignments; //! List of basic variables (temporary storage for model generation) std::vector d_basicModelVars; //! Mapping of basic variables to simplified expressions (temp. storage) /*! There may be some vars which simplify to something else; we save * those separately, and keep only those which simplify to * themselves. Once the latter vars are assigned, we'll re-simplify * the former variables and use the results as concrete values. */ ExprHashMap d_simplifiedModelVars; //! Command line flag whether to simplify in place const bool* d_simplifyInPlace; //! Which recursive simplifier to use Theorem (TheoryCore::*d_currentRecursiveSimplifier)(const Expr&); //! Resource limit (0==unlimited, 1==no more resources, >=2 - available). /*! Currently, it is the number of enqueued facts. Once the * resource is exhausted, the remaining facts will be dropped, and * an incomplete flag is set. */ unsigned d_resourceLimit; //! Time limit (0==unlimited, >0==total available cpu time in seconds). /*! Currently, if exhausted processFactQueue will not perform any more * reasoning with FULL effor and an incomplete flag is set. */ unsigned d_timeBase; unsigned d_timeLimit; bool d_inCheckSATCore; bool d_inAddFact; bool d_inRegisterAtom; bool d_inPP; IF_DEBUG(ExprMap d_simpStack;) //! So we get notified every time there's a pop friend class CoreNotifyObj; class CoreNotifyObj :public ContextNotifyObj { TheoryCore* d_theoryCore; public: CoreNotifyObj(TheoryCore* tc, Context* context) : ContextNotifyObj(context), d_theoryCore(tc) {} void notify() { d_theoryCore->getEM()->invalidateSimpCache(); } }; CoreNotifyObj d_notifyObj; //! List of implied literals, based on registered atomic formulas of interest CDList d_impliedLiterals; //! Next index in d_impliedLiterals that has not yet been fetched CDO d_impliedLiteralsIdx; //! List of theorems from calls to update() // These are stored here until the equality lists are finished and then // processed by processUpdates() std::vector d_update_thms; //! List of data accompanying above theorems from calls to update() std::vector d_update_data; //! Notify list that gets processed on every equality NotifyList d_notifyEq; //! Whether we are in the middle of doing updates unsigned d_inUpdate; //! The set of named expressions to evaluate on a GET_ASSIGNMENT request std::vector< std::pair > d_assignment; public: /***************************************************************************/ /*! *\class CoreSatAPI *\brief Interface class for callbacks to SAT from Core * * Author: Clark Barrett * * Created: Mon Dec 5 18:42:15 2005 */ /***************************************************************************/ class CoreSatAPI { public: CoreSatAPI() {} virtual ~CoreSatAPI() {} //! Add a new lemma derived by theory core virtual void addLemma(const Theorem& thm, int priority = 0, bool atBottomScope = false) = 0; //! Add an assumption to the set of assumptions in the current context /*! Assumptions have the form e |- e */ virtual Theorem addAssumption(const Expr& assump) = 0; //! Suggest a splitter to the Sat engine /*! \param e is a literal. * \param priority is between -10 and 10. A priority above 0 indicates * that the splitter should be favored. A priority below 0 indicates that * the splitter should be delayed. */ virtual void addSplitter(const Expr& e, int priority) = 0; //! Check the validity of e in the current context virtual bool check(const Expr& e) = 0; }; private: CoreSatAPI* d_coreSatAPI; private: //! Private method to get a new theorem producer. /*! This method is used ONLY by the TheoryCore constructor. The only reason to have this method is to separate the trusted part of the constructor into a separate .cpp file (Alternative is to make the entire constructer trusted, which is not very safe). Method is implemented in core_theorem_producer.cpp */ CoreProofRules* createProofRules(TheoremManager* tm); // Helper functions //! Effort level for processFactQueue /*! LOW means just process facts, don't call theory checkSat methods NORMAL means call theory checkSat methods without full effort FULL means call theory checkSat methods with full effort */ typedef enum { LOW, NORMAL, FULL } EffortLevel; //! A helper function for addFact() /*! Returns true if lemmas were added to search engine, false otherwise */ bool processFactQueue(EffortLevel effort = NORMAL); //! Process a notify list triggered as a result of new theorem e void processNotify(const Theorem& e, NotifyList* L); //! Transitive composition of other rewrites with the above Theorem rewriteCore(const Theorem& e); //! Helper for registerAtom void setupSubFormulas(const Expr& s, const Expr& e, const Theorem& thm); //! Process updates recorded by calls to update() void processUpdates(); /*! @brief The assumptions for e must be in H or phi. "Core" added * to avoid conflict with theory interface function name */ void assertFactCore(const Theorem& e); //! Process a newly derived formula void assertFormula(const Theorem& e); //! Check that lhs and rhs of thm have same base type IF_DEBUG(void checkRewriteType(const Theorem& thm);) /*! @brief Returns phi |= e = rewriteCore(e). "Core" added to avoid conflict with theory interface function name */ Theorem rewriteCore(const Expr& e); //! Set the find pointer of an atomic formula and notify SearchEngine /*! \param thm is a Theorem(phi) or Theorem(NOT phi), where phi is * an atomic formula to get a find pointer to TRUE or FALSE, * respectively. */ void setFindLiteral(const Theorem& thm); //! Core rewrites for literals (NOT and EQ) Theorem rewriteLitCore(const Expr& e); //! Enqueue a fact to be sent to the SearchEngine // void enqueueSE(const Theorem& thm);//yeting //! Fetch the concrete assignment to the variable during model generation Theorem getModelValue(const Expr& e); //! An auxiliary recursive function to process COND expressions into ITE Expr processCond(const Expr& e, int i); //! Return true if no special parsing is required for this kind bool isBasicKind(int kind); //! Helper check functions for solve void checkEquation(const Theorem& thm); //! Helper check functions for solve void checkSolved(const Theorem& thm); // Time limit exhausted bool timeLimitReached(); //! Print an expression in the shared subset of SMT-LIB v1/v2 //! Should only be called if os.lang() is SMTLIB_LANG or SMTLIB_V2_LANG. ExprStream& printSmtLibShared(ExprStream& os, const Expr& e); public: //! Constructor TheoryCore(ContextManager* cm, ExprManager* em, TheoremManager* tm, Translator* tr, const CLFlags& flags, Statistics& statistics); //! Destructor ~TheoryCore(); //! Request a unit of resource /*! It will be subtracted from the resource limit. * * \return true if resource unit is granted, false if no more * resources available. */ void getResource() { getStatistics().counter("resource")++; if (d_resourceLimit > 1) d_resourceLimit--; } //! Register a SatAPI for TheoryCore void registerCoreSatAPI(CoreSatAPI* coreSatAPI) { d_coreSatAPI = coreSatAPI; } //! Register a callback for every equality void addNotifyEq(Theory* t, const Expr& e) { d_notifyEq.add(t, e); } //! Call theory-specific preprocess routines Theorem callTheoryPreprocess(const Expr& e); ContextManager* getCM() const { return d_cm; } TheoremManager* getTM() const { return d_tm; } const CLFlags& getFlags() const { return d_flags; } Statistics& getStatistics() const { return d_statistics; } ExprTransform* getExprTrans() const { return d_exprTrans; } CoreProofRules* getCoreRules() const { return d_rules; } Translator* getTranslator() const { return d_translator; } //! Access to tcc cache (needed by theory_bitvector) ExprMap& tccCache() { return d_tccCache; } //! Get list of terms const CDList& getTerms() { return d_terms; } int getCurQuantLevel(); //! Set the flag for the preprocessor void setInPP() { d_inPP = true; } void clearInPP() { d_inPP = false; } //! Get theorem which was responsible for introducing this term Theorem getTheoremForTerm(const Expr& e); //! Get quantification level at which this term was introduced unsigned getQuantLevelForTerm(const Expr& e); //! Get list of predicates const CDList& getPredicates() { return d_predicates; } //! Whether updates are being processed bool inUpdate() { return d_inUpdate > 0; } //! Whether its OK to add new facts (for use in rewrites) bool okToEnqueue() { return d_inAddFact || d_inCheckSATCore || d_inRegisterAtom || d_inPP; } // Implementation of Theory API /*! Variables of uninterpreted types may be sent here, and they should be ignored. */ void addSharedTerm(const Expr& e) { } void assertFact(const Theorem& e); void checkSat(bool fullEffort) { } Theorem rewrite(const Expr& e); /*! Only Boolean constants (TRUE and FALSE) and variables of uninterpreted types should appear here (they come from records and tuples). Just ignore them. */ void setup(const Expr& e) { } void update(const Theorem& e, const Expr& d); Theorem solve(const Theorem& e); Theorem simplifyOp(const Expr& e); void checkType(const Expr& e); Cardinality finiteTypeInfo(Expr& e, Unsigned& n, bool enumerate, bool computeSize); void computeType(const Expr& e); Type computeBaseType(const Type& t); Expr computeTCC(const Expr& e); Expr computeTypePred(const Type& t,const Expr& e); Expr parseExprOp(const Expr& e); ExprStream& print(ExprStream& os, const Expr& e); //! Calls for other theories to add facts to refine a coutnerexample. void refineCounterExample(); bool refineCounterExample(Theorem& thm); void computeModelBasic(const std::vector& v); // User-level API methods /*! @brief Add a new assertion to the core from the user or a SAT solver. Do NOT use it in a decision procedure; use enqueueFact(). */ /*! \sa enqueueFact */ void addFact(const Theorem& e); //! Top-level simplifier Theorem simplify(const Expr& e); //! Check if the current context is inconsistent bool inconsistent() { return d_inconsistent ; } //! Get the proof of inconsistency for the current context /*! \return Theorem(FALSE) */ Theorem inconsistentThm() { return d_incThm; } /*! @brief To be called by SearchEngine when it believes the context * is satisfiable. * * \return true if definitely consistent or inconsistent and false if * consistency is unknown. */ bool checkSATCore(); //! Check if the current decision branch is marked as incomplete bool incomplete() { return d_incomplete.size() > 0 ; } //! Check if the branch is incomplete, and return the reasons (strings) bool incomplete(std::vector& reasons); //! Register an atomic formula of interest. /*! If e or its negation is later deduced, we will add the implied literal to d_impliedLiterals */ void registerAtom(const Expr& e, const Theorem& thm); //! Return the next implied literal (NULL Theorem if none) Theorem getImpliedLiteral(void); //! Return total number of implied literals unsigned numImpliedLiterals() { return d_impliedLiterals.size(); } //! Return an implied literal by index Theorem getImpliedLiteralByIndex(unsigned index); //! Parse the generic expression. /*! This method should be used in parseExprOp() for recursive calls * to subexpressions, and is the method called by the command * processor. */ Expr parseExpr(const Expr& e); //! Top-level call to parseExpr, clears the bound variable stack. /*! Use it in VCL instead of parseExpr(). */ Expr parseExprTop(const Expr& e) { d_boundVarStack.clear(); d_parseCache = &d_parseCacheTop; return parseExpr(e); } //! Assign t a concrete value val. Used in model generation. void assignValue(const Expr& t, const Expr& val); //! Record a derived assignment to a variable (LHS). void assignValue(const Theorem& thm); //! Adds expression to var database void addToVarDB(const Expr & e); //! Split compound vars into basic type variables /*! The results are saved in d_basicModelVars and * d_simplifiedModelVars. Also, add new basic vars as shared terms * whenever their type belongs to a different theory than the term * itself. */ void collectBasicVars(); //! Calls theory specific computeModel, results are placed in map void buildModel(ExprMap& m); bool buildModel(Theorem& thm); //! Recursively build a compound-type variable assignment for e void collectModelValues(const Expr& e, ExprMap& m); //! Set the resource limit (0==unlimited). void setResourceLimit(unsigned limit) { d_resourceLimit = limit; } //! Get the resource limit unsigned getResourceLimit() { return d_resourceLimit; } //! Return true if resources are exhausted bool outOfResources() { return d_resourceLimit == 1; } //! Initialize base time used for !setTimeLimit void initTimeLimit(); //! Set the time limit in seconds (0==unlimited). void setTimeLimit(unsigned limit); //! Called by search engine Theorem rewriteLiteral(const Expr& e); //! Get the value of all :named terms Expr getAssignment(); //! Get the value of an arbitrary formula or term Expr getValue(Expr e); private: // Methods provided for benefit of theories. Access is made available through theory.h //! Assert a system of equations (1 or more). /*! e is either a single equation, or a conjunction of equations */ void assertEqualities(const Theorem& e); //! Mark the branch as incomplete void setIncomplete(const std::string& reason); //! Return a theorem for the type predicate of e /*! Note: used only by theory_arith */ Theorem typePred(const Expr& e); public: // TODO: These should be private //! Enqueue a new fact /*! not private because used in search_fast.cpp */ void enqueueFact(const Theorem& e); void enqueueSE(const Theorem& thm);//yeting // Must provide proof of inconsistency /*! not private because used in search_fast.cpp */ void setInconsistent(const Theorem& e); //! Setup additional terms within a theory-specific setup(). /*! not private because used in theory_bitvector.cpp */ void setupTerm(const Expr& e, Theory* i, const Theorem& thm); }; //! Printing NotifyList class std::ostream& operator<<(std::ostream& os, const NotifyList& l); } #endif cvc3-2.4.1/src/include/cdmap.h0000664000175400017540000002504011152032743015724 0ustar mdetersmdeters/*****************************************************************************/ /*! * \file cdmap.h * * Author: Sergey Berezin * * Created: Thu May 15 15:55:09 2003 * *
* * License to use, copy, modify, sell and/or distribute this software * and its documentation for any purpose is hereby granted without * royalty, subject to the terms and conditions defined in the \ref * LICENSE file provided with this distribution. * *
* */ /*****************************************************************************/ #ifndef _cvc3__include__cdmap_h_ #define _cvc3__include__cdmap_h_ #include #include "context.h" namespace CVC3 { /////////////////////////////////////////////////////////////////////////////// // // // Class: CDMap (Context Dependent Map) // // Author: Sergey Berezin // // Created: Thu May 15 15:55:09 2003 // // Description: Generic templated class for a map which must be saved // // and restored as contexts are pushed and popped. Requires // // that operator= be defined for the data class, and // // operator== for the key class. In addition, a hash // // template specialization must be defined, or a hash class // // explicitly provided in the template. // // // /////////////////////////////////////////////////////////////////////////////// // Auxiliary class: almost the same as CDO (see cdo.h), but on // setNull() call it erases itself from the map. template > class CDMap; template > class CDOmap :public ContextObj { Key d_key; Data d_data; bool d_inMap; // whether the data must be in the map CDMap* d_cdmap; // Doubly-linked list for keeping track of elements in order of insertion CDOmap* d_prev; CDOmap* d_next; virtual ContextObj* makeCopy(ContextMemoryManager* cmm) { return new(cmm) CDOmap(*this); } virtual void restoreData(ContextObj* data) { CDOmap* p((CDOmap*)data); if(p->d_inMap) { d_data = p->d_data; d_inMap = true; } else setNull(); } virtual void setNull(void) { // Erase itself from the map and put itself into trash. We cannot // "delete this" here, because it will break context operations in // a non-trivial way. if(d_cdmap->d_map.count(d_key) > 0) { d_cdmap->d_map.erase(d_key); d_cdmap->d_trash.push_back(this); } d_prev->d_next = d_next; d_next->d_prev = d_prev; if (d_cdmap->d_first == this) { d_cdmap->d_first = d_next; if (d_next == this) { d_cdmap->d_first = NULL; } } } public: CDOmap(Context* context, CDMap* cdmap, const Key& key, const Data& data, int scope = -1) : ContextObj(context), d_key(key), d_inMap(false), d_cdmap(cdmap) { set(data, scope); IF_DEBUG(setName("CDOmap");) CDOmap*& first = d_cdmap->d_first; if (first == NULL) { first = d_next = d_prev = this; } else { d_prev = first->d_prev; d_next = first; d_prev->d_next = first->d_prev = this; } } ~CDOmap() {} void set(const Data& data, int scope=-1) { makeCurrent(scope); d_data = data; d_inMap = true; } const Key& getKey() const { return d_key; } const Data& get() const { return d_data; } operator Data() { return get(); } CDOmap& operator=(const Data& data) { set(data); return *this; } CDOmap* next() const { if (d_next == d_cdmap->d_first) return NULL; else return d_next; } }; // end of class CDOmap // Dummy subclass of ContextObj to serve as our data class class CDMapData : public ContextObj { ContextObj* makeCopy(ContextMemoryManager* cmm) { return new(cmm) CDMapData(*this); } void restoreData(ContextObj* data) { } void setNull(void) { } public: CDMapData(Context* context): ContextObj(context) { } CDMapData(const ContextObj& co): ContextObj(co) { } }; // The actual class CDMap template class CDMap: public ContextObj { friend class CDOmap; private: std::hash_map*,HashFcn> d_map; // The vector of CDOmap objects to be destroyed std::vector*> d_trash; CDOmap* d_first; Context* d_context; // Nothing to save; the elements take care of themselves virtual ContextObj* makeCopy(ContextMemoryManager* cmm) { return new(cmm) CDMapData(*this); } // Similarly, nothing to restore virtual void restoreData(ContextObj* data) { } // Destroy stale CDOmap objects from trash void emptyTrash() { for(typename std::vector*>::iterator i=d_trash.begin(), iend=d_trash.end(); i!=iend; ++i) { delete *i; free(*i); } d_trash.clear(); } virtual void setNull(void) { // Delete all the elements and clear the map for(typename std::hash_map*,HashFcn>::iterator i=d_map.begin(), iend=d_map.end(); i!=iend; ++i) { delete (*i).second; free((*i).second); } d_map.clear(); emptyTrash(); } public: CDMap(Context* context, int scope = -1) : ContextObj(context), d_first(NULL), d_context(context) { IF_DEBUG(setName("CDMap")); ; } ~CDMap() { setNull(); } // The usual operators of map size_t size() const { return d_map.size(); } size_t count(const Key& k) const { return d_map.count(k); } typedef CDOmap& ElementReference; // If a key is not present, a new object is created and inserted CDOmap& operator[](const Key& k) { emptyTrash(); typename std::hash_map*,HashFcn>::iterator i(d_map.find(k)); CDOmap* obj; if(i == d_map.end()) { // Create new object obj = new(true) CDOmap(d_context, this, k, Data()); d_map[k] = obj; } else { obj = (*i).second; } return *obj; } void insert(const Key& k, const Data& d, int scope = -1) { emptyTrash(); typename std::hash_map*,HashFcn>::iterator i(d_map.find(k)); if(i == d_map.end()) { // Create new object CDOmap* obj(new(true) CDOmap(d_context, this, k, d, scope)); d_map[k] = obj; } else { (*i).second->set(d, scope); } } // FIXME: no erase(), too much hassle to implement efficiently... // Iterator for CDMap: points to pair&>; // in most cases, this will be functionally similar to pair. class iterator : public std::iterator,std::ptrdiff_t> { private: // Private members typename std::hash_map*,HashFcn>::const_iterator d_it; public: // Constructor from std::hash_map iterator(const typename std::hash_map*,HashFcn>::const_iterator& i) : d_it(i) { } // Copy constructor iterator(const iterator& i): d_it(i.d_it) { } // Default constructor iterator() { } // (Dis)equality bool operator==(const iterator& i) const { return d_it == i.d_it; } bool operator!=(const iterator& i) const { return d_it != i.d_it; } // Dereference operators. std::pair operator*() const { const std::pair*>& p(*d_it); return std::pair(p.first, *p.second); } // Who needs an operator->() for maps anyway?... // It'd be nice, but not possible by design. //std::pair* operator->() const { // return &(operator*()); //} // Prefix and postfix increment iterator& operator++() { ++d_it; return *this; } // Postfix increment: requires a Proxy object to hold the // intermediate value for dereferencing class Proxy { const std::pair* d_pair; public: Proxy(const std::pair& p): d_pair(&p) { } std::pair& operator*() { return *d_pair; } }; // Actual postfix increment: returns Proxy with the old value. // Now, an expression like *i++ will return the current *i, and // then advance the iterator. However, don't try to use Proxy for // anything else. Proxy operator++(int) { Proxy e(*(*this)); ++(*this); return e; } }; iterator begin() const { return iterator(d_map.begin()); } iterator end() const { return iterator(d_map.end()); } class orderedIterator { const CDOmap* d_it; public: orderedIterator(const CDOmap* p): d_it(p) {} orderedIterator(const orderedIterator& i): d_it(i.d_it) { } // Default constructor orderedIterator() { } // (Dis)equality bool operator==(const orderedIterator& i) const { return d_it == i.d_it; } bool operator!=(const orderedIterator& i) const { return d_it != i.d_it; } // Dereference operators. std::pair operator*() const { return std::pair(d_it->getKey(), d_it->get()); } // Prefix and postfix increment orderedIterator& operator++() { d_it = d_it->next(); return *this; } // Postfix increment: requires a Proxy object to hold the // intermediate value for dereferencing class Proxy { const std::pair* d_pair; public: Proxy(const std::pair& p): d_pair(&p) { } std::pair& operator*() { return *d_pair; } }; // Actual postfix increment: returns Proxy with the old value. // Now, an expression like *i++ will return the current *i, and // then advance the orderedIterator. However, don't try to use Proxy for // anything else. Proxy operator++(int) { Proxy e(*(*this)); ++(*this); return e; } }; orderedIterator orderedBegin() const { return orderedIterator(d_first); } orderedIterator orderedEnd() const { return orderedIterator(NULL); } iterator find(const Key& k) const { return iterator(d_map.find(k)); } }; // end of class CDMap } #endif cvc3-2.4.1/src/theorem/0000775000175400017540000000000011630011320014473 5ustar mdetersmdeterscvc3-2.4.1/src/theorem/Makefile0000664000175400017540000000061610533133652016154 0ustar mdetersmdeters################################################## # About this Makefile # # This Makefile depends on Makefile.opts ################################################## MODULE = theorem SRC = assumptions.cpp \ theorem.cpp theorem_manager.cpp theorem_producer.cpp common_theorem_producer.cpp HEADERS = theorem_value.h common_theorem_producer.h LIBRARY=libtheorem.a include ../../Makefile.local cvc3-2.4.1/src/theorem/common_theorem_producer.cpp0000664000175400017540000012254511263451005022140 0ustar mdetersmdeters/*****************************************************************************/ /*! *\file common_theorem_producer.cpp *\brief Implementation of common proof rules * * Author: Clark Barrett * * Created: Wed Jan 11 16:10:15 2006 * *
* * License to use, copy, modify, sell and/or distribute this software * and its documentation for any purpose is hereby granted without * royalty, subject to the terms and conditions defined in the \ref * LICENSE file provided with this distribution. * *
* */ /*****************************************************************************/ // This code is trusted #define _CVC3_TRUSTED_ #include "common_theorem_producer.h" using namespace CVC3; using namespace std; // The trusted method of TheoremManager which creates this theorem producer CommonProofRules* TheoremManager::createProofRules() { return new CommonTheoremProducer(this); } CommonTheoremProducer::CommonTheoremProducer(TheoremManager* tm) : TheoremProducer(tm), d_skolemized_thms(tm->getCM()->getCurrentContext()), d_skolemVars(tm->getCM()->getCurrentContext()) {} //////////////////////////////////////////////////////////////////////// // TCC rules (3-valued logic) //////////////////////////////////////////////////////////////////////// // G1 |- phi G2 |- D_phi // ------------------------- // G1,G2 |-_3 phi Theorem3 CommonTheoremProducer::queryTCC(const Theorem& phi, const Theorem& D_phi) { Proof pf; // if(CHECK_PROOFS) // CHECK_SOUND(D_phi.getExpr() == d_core->getTCC(phi.getExpr()), // "CoreTheoremProducer::queryTCC: " // "bad TCC for a formula:\n\n " // +phi.getExpr().toString() // +"\n\n TCC must be the following:\n\n " // +d_core->getTCC(phi.getExpr()).toString() // +"\n\nBut given this as a TCC:\n\n " // +D_phi.getExpr().toString()); Assumptions a = phi.getAssumptionsRef(); a.add(D_phi); if(withProof()) { vector args; vector pfs; args.push_back(phi.getExpr()); args.push_back(D_phi.getExpr()); pfs.push_back(phi.getProof()); pfs.push_back(D_phi.getProof()); pf = newPf("queryTCC", args, pfs); } return newTheorem3(phi.getExpr(), a, pf); } // G0,a1,...,an |-_3 phi G1 |- D_a1 ... Gn |- D_an // ------------------------------------------------- // G0,G1,...,Gn |-_3 (a1 & ... & an) -> phi Theorem3 CommonTheoremProducer::implIntro3(const Theorem3& phi, const std::vector& assump, const vector& tccs) { bool checkProofs(CHECK_PROOFS); // This rule only makes sense when runnnig with assumptions if(checkProofs) { CHECK_SOUND(withAssumptions(), "implIntro3: called while running without assumptions"); } const Assumptions& phiAssump = phi.getAssumptionsRef(); if(checkProofs) { CHECK_SOUND(assump.size() == tccs.size(), "implIntro3: number of assumptions (" +int2string(assump.size())+") and number of TCCs (" +int2string(tccs.size()) +") does not match"); for(size_t i=0; i (a == a) IFF TRUE Theorem CommonTheoremProducer::rewriteReflexivity(const Expr& t) { if(CHECK_PROOFS) CHECK_SOUND((t.isEq() || t.isIff()) && t[0] == t[1], "rewriteReflexivity: wrong expression: " + t.toString()); Proof pf; if(withProof()) { if(t.isEq()) { DebugAssert(!t[0].getType().isNull(), "rewriteReflexivity: t[0] has no type: " + t[0].toString()); pf = newPf("rewrite_eq_refl", t[0].getType().getExpr(), t[0]); } else pf = newPf("rewrite_iff_refl", t[0]); } return newRWTheorem(t, d_em->trueExpr(), Assumptions::emptyAssump(), pf); } Theorem CommonTheoremProducer::symmetryRule(const Theorem& a1_eq_a2) { if(CHECK_PROOFS) CHECK_SOUND(a1_eq_a2.isRewrite(), ("CVC3::CommonTheoremProducer: " "theorem is not an equality or iff:\n " + a1_eq_a2.getExpr().toString()).c_str()); const Expr& a1 = a1_eq_a2.getLHS(); const Expr& a2 = a1_eq_a2.getRHS(); Proof pf; ///////////////////////////////////////////////////////////////////////// //// Proof compaction ///////////////////////////////////////////////////////////////////////// // If a1 == a2, use reflexivity if(a1 == a2) return reflexivityRule(a1); // Otherwise, do the work if(withProof()) { Type t = a1.getType(); // Check the types IF_DEBUG(a1_eq_a2.getExpr().getType();) bool isEquality = !t.isBool(); if(isEquality) { vector args; args.push_back(t.getExpr()); args.push_back(a1); args.push_back(a2); pf = newPf("eq_symm", args, a1_eq_a2.getProof()); } else pf = newPf("iff_symm", a1, a2, a1_eq_a2.getProof()); } return newRWTheorem(a2, a1, Assumptions(a1_eq_a2), pf); } Theorem CommonTheoremProducer::rewriteUsingSymmetry(const Expr& a1_eq_a2) { bool isIff = a1_eq_a2.isIff(); if(CHECK_PROOFS) CHECK_SOUND(a1_eq_a2.isEq() || isIff, "rewriteUsingSymmetry precondition violated"); const Expr& a1 = a1_eq_a2[0]; const Expr& a2 = a1_eq_a2[1]; // Proof compaction: if a1 == a2, use reflexivity if(a1 == a2) return reflexivityRule(a1_eq_a2); // Otherwise, do the work Proof pf; if(withProof()) { Type t = a1.getType(); DebugAssert(!t.isNull(), "rewriteUsingSymmetry: a1 has no type: " + a1.toString()); if(isIff) pf = newPf("rewrite_iff_symm", a1, a2); else { pf = newPf("rewrite_eq_symm", t.getExpr(), a1, a2); } } return newRWTheorem(a1_eq_a2, isIff ? a2.iffExpr(a1) : a2.eqExpr(a1), Assumptions::emptyAssump(), pf); } Theorem CommonTheoremProducer::transitivityRule(const Theorem& a1_eq_a2, const Theorem& a2_eq_a3) { DebugAssert(!a1_eq_a2.isNull(), "transitivityRule()"); DebugAssert(!a2_eq_a3.isNull(), "transitivityRule()"); if(CHECK_PROOFS) { CHECK_SOUND(a1_eq_a2.isRewrite() && a2_eq_a3.isRewrite(), "CVC3::CommonTheoremProducer::transitivityRule:\n " "Wrong premises: first = " + a1_eq_a2.getExpr().toString() + ", second = " + a2_eq_a3.getExpr().toString()); CHECK_SOUND(a1_eq_a2.getRHS() == a2_eq_a3.getLHS(), "CVC3::CommonTheoremProducer::transitivityRule:\n " "Wrong premises: first = " + a1_eq_a2.getExpr().toString() + ", second = " + a2_eq_a3.getExpr().toString()); } const Expr& a1 = a1_eq_a2.getLHS(); const Expr& a2 = a1_eq_a2.getRHS(); const Expr& a3 = a2_eq_a3.getRHS(); ///////////////////////////////////////////////////////////////////////// //// Proof compaction ///////////////////////////////////////////////////////////////////////// // if a1 == a3, use reflexivity (and lose all assumptions) if(a1 == a3) return reflexivityRule(a1); // if a1 == a2, or if a2 == a3, use only the non-trivial part if(a1 == a2) return a2_eq_a3; if(a2 == a3) return a1_eq_a2; //////////////////////////////////////////////////////////////////////// //// No shortcuts. Do the work. //////////////////////////////////////////////////////////////////////// Proof pf; Assumptions a(a1_eq_a2, a2_eq_a3); // Build the proof if(withProof()) { Type t = a1.getType(); bool isEquality = (!t.isBool()); string name((isEquality)? "eq_trans" : "iff_trans"); vector args; vector pfs; DebugAssert(!t.isNull(), "transitivityRule: " "Type is not computed for a1: " + a1.toString()); // Type argument is needed only for equality if(isEquality) args.push_back(t.getExpr()); args.push_back(a1); args.push_back(a2); args.push_back(a3); pfs.push_back(a1_eq_a2.getProof()); pfs.push_back(a2_eq_a3.getProof()); pf = newPf(name, args, pfs); } return newRWTheorem(a1, a3, a, pf); } Theorem CommonTheoremProducer::substitutivityRule(const Expr& e, const Theorem& thm) { IF_DEBUG (static DebugTimer accum0(debugger.timer("substitutivityRule0 time")); static DebugTimer tmpTimer(debugger.newTimer()); static DebugCounter count(debugger.counter("substitutivityRule0 calls")); debugger.setCurrentTime(tmpTimer); count++;) // Check that t is c == d or c IFF d if(CHECK_PROOFS) { CHECK_SOUND(e.arity() == 1 && e[0] == thm.getLHS(), "Unexpected use of substitutivityRule0"); CHECK_SOUND(thm.isRewrite(), "CVC3::CommonTheoremProducer::substitutivityRule0:\n " "premis is not an equality or IFF: " + thm.getExpr().toString() + "\n expr = " + e.toString()); } Expr e2(e.getOp(), thm.getRHS()); Proof pf; if(withProof()) pf = newPf("basic_subst_op0",e, e2,thm.getProof()); Theorem res = newRWTheorem(e, e2, Assumptions(thm), pf); if (!res.isRefl()) res.setSubst(); return res; } Theorem CommonTheoremProducer::substitutivityRule(const Expr& e, const Theorem& thm1, const Theorem& thm2) { IF_DEBUG (static DebugTimer accum0(debugger.timer("substitutivityRule1 time")); static DebugTimer tmpTimer(debugger.newTimer()); static DebugCounter count(debugger.counter("substitutivityRule1 calls")); debugger.setCurrentTime(tmpTimer); count++;) // Check that t is c == d or c IFF d if(CHECK_PROOFS) { CHECK_SOUND(e.arity() == 2 && e[0] == thm1.getLHS() && e[1] == thm2.getLHS(), "Unexpected use of substitutivityRule1"); CHECK_SOUND(thm1.isRewrite(), "CVC3::CommonTheoremProducer::substitutivityRule1:\n " "premis is not an equality or IFF: " + thm1.getExpr().toString() + "\n expr = " + e.toString()); CHECK_SOUND(thm2.isRewrite(), "CVC3::CommonTheoremProducer::substitutivityRule1:\n " "premis is not an equality or IFF: " + thm2.getExpr().toString() + "\n expr = " + e.toString()); } Expr e2(e.getOp(), thm1.getRHS(), thm2.getRHS()); Proof pf; if(withProof()) { vector pfs; pfs.push_back(thm1.getProof()); pfs.push_back(thm2.getProof()); pf = newPf("basic_subst_op1", e, e2, pfs); } Theorem res = newRWTheorem(e, e2, Assumptions(thm1, thm2), pf); if (!res.isRefl()) res.setSubst(); return res; } Theorem CommonTheoremProducer::substitutivityRule(const Op& op, const vector& thms) { IF_DEBUG (static DebugTimer accum0(debugger.timer("substitutivityRule time")); static DebugTimer tmpTimer(debugger.newTimer()); static DebugCounter count(debugger.counter("substitutivityRule calls")); debugger.setCurrentTime(tmpTimer); count++;) // Check for trivial case: no theorems, return (op == op) unsigned size(thms.size()); if(size == 0) return reflexivityRule(d_tm->getEM()->newLeafExpr(op)); // Check that theorems are of the form c_i == d_i and collect // vectors of c_i's and d_i's and the vector of proofs vector c, d; vector pfs; // Reserve memory for argument vectors. Do not reserve memory for // pfs, they are rarely used and slow anyway. c.reserve(size); d.reserve(size); for(vector::const_iterator i = thms.begin(), iend = thms.end(); i != iend; ++i) { // Check that t is c == d or c IFF d if(CHECK_PROOFS) CHECK_SOUND(i->isRewrite(), "CVC3::CommonTheoremProducer::substitutivityRule:\n " "premis is not an equality or IFF: " + i->getExpr().toString() + "\n op = " + op.toString()); // Collect the pieces c.push_back(i->getLHS()); d.push_back(i->getRHS()); if(withProof()) pfs.push_back(i->getProof()); } Expr e1(op, c), e2(op, d); // Proof compaction: if e1 == e2, use reflexivity if(e1 == e2) return reflexivityRule(e1); // Otherwise, do the work Assumptions a(thms); Proof pf; if(withProof()) // FIXME: this rule is not directly expressible in flea pf = newPf("basic_subst_op",e1,e2,pfs); Theorem res = newRWTheorem(e1, e2, a, pf); IF_DEBUG(debugger.setElapsed(tmpTimer); accum0 += tmpTimer;) res.setSubst(); return res; } Theorem CommonTheoremProducer::substitutivityRule(const Expr& e, const vector& changed, const vector& thms) { IF_DEBUG (static DebugTimer accum0(debugger.timer("substitutivityRule2 time")); static DebugTimer tmpTimer(debugger.newTimer()); static DebugCounter count(debugger.counter("substitutivityRule2 calls")); debugger.setCurrentTime(tmpTimer); count++;) DebugAssert(changed.size() > 0, "substitutivityRule2 should not be called"); DebugAssert(changed.size() == thms.size(), "substitutivityRule2: wrong args"); // Check that theorems are of the form c_i == d_i and collect // vectors of c_i's and d_i's and the vector of proofs unsigned size = e.arity(); if (size == 1) return substitutivityRule(e, thms.back()); unsigned csize = changed.size(); if (size == 2) { if (csize == 2) return substitutivityRule(e, thms[0], thms[1]); if (changed[0] == 0) { return substitutivityRule(e, thms[0], reflexivityRule(e[1])); } else { return substitutivityRule(e, reflexivityRule(e[0]), thms[0]); } } DebugAssert(size >= csize, "Bad call to substitutivityRule2"); vector c; bool checkProofs(CHECK_PROOFS); for(unsigned j = 0, k = 0; k < size; ++k) { if (j == csize || changed[j] != k) { c.push_back(e[k]); continue; } // Check that t is c == d or c IFF d if(checkProofs) CHECK_SOUND(thms[j].isRewrite() && thms[j].getLHS() == e[k], "CVC3::CommonTheoremProducer::substitutivityRule:\n " "premis is not an equality or IFF: " + thms[j].getExpr().toString() + "\n e = " + e.toString()); // Collect the pieces c.push_back(thms[j].getRHS()); ++j; } Expr e2(e.getOp(), c); IF_DEBUG(if(e == e2) { ostream& os = debugger.getOS(); os << "substitutivityRule2: e = " << e << "\n e2 = " << e2 << "\n changed kids: [\n"; for(unsigned j=0; jgetExpr().toString()); // + "\n op = " + ((Op) e.getOp).toString()); pfs.push_back(i->getProof()); } pf = newPf("optimized_subst_op",e,e2,pfs); } Theorem res = newRWTheorem(e, e2, a, pf); IF_DEBUG(debugger.setElapsed(tmpTimer); accum0 += tmpTimer;) if (!res.isRefl()) res.setSubst(); return res; } Theorem CommonTheoremProducer::substitutivityRule(const Expr& e, const int changed, const Theorem& thm) { // Get the arity of the expression int size = e.arity(); // The changed must be within the arity DebugAssert(size >= changed, "Bad call to substitutivityRule"); // Check that t is c == d or c IFF d if(CHECK_PROOFS) CHECK_SOUND(thm.isRewrite() && thm.getLHS() == e[changed], "CVC3::CommonTheoremProducer::substitutivityRule:\n " "premise is not an equality or IFF: " + thm.getExpr().toString() + "\n" + "e = " + e.toString()); // Collect the new sub-expressions vector c; for(int k = 0; k < size; ++ k) if (k != changed) c.push_back(e[k]); else c.push_back(thm.getRHS()); // Construct the new expression Expr e2(e.getOp(), c); // Check if they are the same IF_DEBUG(if(e == e2) { ostream& os = debugger.getOS(); os << "substitutivityRule: e = " << e << "\n e2 = " << e2 << endl; }) // The new expressions must not be equal DebugAssert(e != e2, "substitutivityRule should not be called in this case:\ne = "+e.toString()); // Construct the proof object Proof pf; Assumptions a(thm); if(withProof()) { // Check that t is c == d or c IFF d if(CHECK_PROOFS) CHECK_SOUND(thm.isRewrite(), "CVC3::CommonTheoremProducer::substitutivityRule:\npremise is not an equality or IFF: " + thm.getExpr().toString()); pf = newPf("optimized_subst_op2",e,e2,thm.getProof()); } // Return the resulting theorem Theorem res = newRWTheorem(e, e2, a, pf);; res.setSubst(); return res; } // |- e, |- !e ==> |- FALSE Theorem CommonTheoremProducer::contradictionRule(const Theorem& e, const Theorem& not_e) { Proof pf; if(CHECK_PROOFS) CHECK_SOUND(!e.getExpr() == not_e.getExpr(), "CommonTheoremProducer::contraditionRule: " "theorems don't match:\n e = "+e.toString() +"\n not_e = "+not_e.toString()); Assumptions a(e, not_e); if(withProof()) { vector pfs; pfs.push_back(e.getProof()); pfs.push_back(not_e.getProof()); pf = newPf("contradition", e.getExpr(), pfs); } return newTheorem(d_em->falseExpr(), a, pf); } Theorem CommonTheoremProducer::excludedMiddle(const Expr& e) { Proof pf; if (withProof()) { pf = newPf("excludedMiddle", e); } return newTheorem(e.orExpr(!e), Assumptions::emptyAssump(), pf); } // e ==> e IFF TRUE Theorem CommonTheoremProducer::iffTrue(const Theorem& e) { Proof pf; if(withProof()) { pf = newPf("iff_true", e.getExpr(), e.getProof()); } return newRWTheorem(e.getExpr(), d_em->trueExpr(), Assumptions(e), pf); } // e ==> !e IFF FALSE Theorem CommonTheoremProducer::iffNotFalse(const Theorem& e) { Proof pf; if(withProof()) { pf = newPf("iff_not_false", e.getExpr(), e.getProof()); } return newRWTheorem(!e.getExpr(), d_em->falseExpr(), Assumptions(e), pf); } // e IFF TRUE ==> e Theorem CommonTheoremProducer::iffTrueElim(const Theorem& e) { if(CHECK_PROOFS) CHECK_SOUND(e.isRewrite() && e.getRHS().isTrue(), "CommonTheoremProducer::iffTrueElim: " "theorem is not e<=>TRUE: "+ e.toString()); Proof pf; if(withProof()) { pf = newPf("iff_true_elim", e.getLHS(), e.getProof()); } return newTheorem(e.getLHS(), Assumptions(e), pf); } // e IFF FALSE ==> !e Theorem CommonTheoremProducer::iffFalseElim(const Theorem& e) { if(CHECK_PROOFS) CHECK_SOUND(e.isRewrite() && e.getRHS().isFalse(), "CommonTheoremProducer::iffFalseElim: " "theorem is not e<=>FALSE: "+ e.toString()); const Expr& lhs = e.getLHS(); Proof pf; if(withProof()) { pf = newPf("iff_false_elim", lhs, e.getProof()); } return newTheorem(!lhs, Assumptions(e), pf); } // e1 <=> e2 ==> ~e1 <=> ~e2 Theorem CommonTheoremProducer::iffContrapositive(const Theorem& e) { if(CHECK_PROOFS) CHECK_SOUND(e.isRewrite() && e.getRHS().getType().isBool(), "CommonTheoremProducer::iffContrapositive: " "theorem is not e1<=>e2: "+ e.toString()); Proof pf; if(withProof()) { pf = newPf("iff_contrapositive", e.getExpr(), e.getProof()); } return newRWTheorem(e.getLHS().negate(),e.getRHS().negate(), Assumptions(e), pf); } // !!e ==> e Theorem CommonTheoremProducer::notNotElim(const Theorem& not_not_e) { if(CHECK_PROOFS) CHECK_SOUND(not_not_e.getExpr().isNot() && not_not_e.getExpr()[0].isNot(), "CommonTheoremProducer::notNotElim: bad theorem: !!e = " + not_not_e.toString()); Proof pf; if(withProof()) pf = newPf("not_not_elim", not_not_e.getExpr(), not_not_e.getProof()); return newTheorem(not_not_e.getExpr()[0][0], Assumptions(not_not_e), pf); } Theorem CommonTheoremProducer::iffMP(const Theorem& e1, const Theorem& e1_iff_e2) { if(CHECK_PROOFS) { CHECK_SOUND(e1_iff_e2.isRewrite(), "iffMP: not IFF: "+e1_iff_e2.toString()); CHECK_SOUND(e1.getExpr() == (e1_iff_e2.getLHS()), "iffMP: theorems don't match:\n e1 = " + e1.toString() + ", e1_iff_e2 = " + e1_iff_e2.toString()); } const Expr& e2(e1_iff_e2.getRHS()); // Avoid e1.getExpr(), it may cause unneeded Expr creation if (e1_iff_e2.getLHS() == e2) return e1; Proof pf; Assumptions a(e1, e1_iff_e2); if(withProof()) { vector pfs; pfs.push_back(e1.getProof()); pfs.push_back(e1_iff_e2.getProof()); pf = newPf("iff_mp", e1.getExpr(), e2, pfs); } return newTheorem(e2, a, pf); } // e1 AND (e1 IMPLIES e2) ==> e2 Theorem CommonTheoremProducer::implMP(const Theorem& e1, const Theorem& e1_impl_e2) { const Expr& impl = e1_impl_e2.getExpr(); if(CHECK_PROOFS) { CHECK_SOUND(impl.isImpl() && impl.arity()==2, "implMP: not IMPLIES: "+impl.toString()); CHECK_SOUND(e1.getExpr() == impl[0], "implMP: theorems don't match:\n e1 = " + e1.toString() + ", e1_impl_e2 = " + impl.toString()); } const Expr& e2 = impl[1]; // Avoid e1.getExpr(), it may cause unneeded Expr creation // if (impl[0] == e2) return e1; // this line commented by yeting because of proof translation Proof pf; Assumptions a(e1, e1_impl_e2); if(withProof()) { vector pfs; pfs.push_back(e1.getProof()); pfs.push_back(e1_impl_e2.getProof()); pf = newPf("impl_mp", e1.getExpr(), e2, pfs); } return newTheorem(e2, a, pf); } // AND(e_0,...e_{n-1}) ==> e_i Theorem CommonTheoremProducer::andElim(const Theorem& e, int i) { if(CHECK_PROOFS) { CHECK_SOUND(e.getExpr().isAnd(), "andElim: not an AND: " + e.toString()); CHECK_SOUND(i < e.getExpr().arity(), "andElim: i = " + int2string(i) + " >= arity = " + int2string(e.getExpr().arity()) + " in " + e.toString()); } Proof pf; if(withProof()) pf = newPf("andE", d_em->newRatExpr(i), e.getExpr(), e.getProof()); return newTheorem(e.getExpr()[i], Assumptions(e), pf); } //! e1, e2 ==> AND(e1, e2) Theorem CommonTheoremProducer::andIntro(const Theorem& e1, const Theorem& e2) { vector thms; thms.push_back(e1); thms.push_back(e2); return andIntro(thms); } Theorem CommonTheoremProducer::andIntro(const vector& es) { Proof pf; if(CHECK_PROOFS) CHECK_SOUND(es.size() > 1, "andIntro(vector): vector must have more than 1 element"); Assumptions a(es); /* if(withProof()) { vector pfs; for(vector::const_iterator i=es.begin(), iend=es.end(); i!=iend; ++i) pfs.push_back(i->getProof()); // pf = newPf("andI", andExpr(kids), pfs); } */ vector kids; for(vector::const_iterator i=es.begin(), iend=es.end(); i!=iend; ++i) kids.push_back(i->getExpr()); if(withProof()) { vector pfs; for(vector::const_iterator i=es.begin(), iend=es.end(); i!=iend; ++i) pfs.push_back(i->getProof()); pf = newPf("andI", andExpr(kids), pfs); } return newTheorem(andExpr(kids), a, pf); } // G,a1,...,an |- phi // ------------------------------------------------- // G |- (a1 & ... & an) -> phi Theorem CommonTheoremProducer::implIntro(const Theorem& phi, const std::vector& assump) { bool checkProofs(CHECK_PROOFS); // This rule only makes sense when runnnig with assumptions if(checkProofs) { CHECK_SOUND(withAssumptions(), "implIntro: called while running without assumptions"); } const Assumptions& phiAssump = phi.getAssumptionsRef(); if(checkProofs) { for(size_t i=0; i e2 ==> ~e2 => ~e1 Theorem CommonTheoremProducer::implContrapositive(const Theorem& thm) { const Expr& impl = thm.getExpr(); if(CHECK_PROOFS) { CHECK_SOUND(impl.isImpl() && impl.arity()==2, "CommonTheoremProducer::implContrapositive: thm=" +impl.toString()); } Proof pf; if(withProof()) pf = newPf("impl_contrapositive", impl, thm.getProof()); return newTheorem(impl[1].negate().impExpr(impl[0].negate()), Assumptions(thm), pf); } // ==> ITE(TRUE, e1, e2) == e1 Theorem CommonTheoremProducer::rewriteIteTrue(const Expr& e) { Proof pf; if(CHECK_PROOFS) CHECK_SOUND(e.isITE() && e[0].isTrue(), "rewriteIteTrue precondition violated"); if(withProof()) { Type t = e[1].getType(); DebugAssert(!t.isNull(), "rewriteIteTrue: e1 has no type: " + e[1].toString()); bool useIff = t.isBool(); if(useIff) pf = newPf("rewrite_ite_true_iff", e[1], e[2]); else { pf = newPf("rewrite_ite_true", t.getExpr(), e[1], e[2]); } } return newRWTheorem(e, e[1], Assumptions::emptyAssump(), pf); } // ==> ITE(FALSE, e1, e2) == e2 Theorem CommonTheoremProducer::rewriteIteFalse(const Expr& e) { Proof pf; if(CHECK_PROOFS) CHECK_SOUND(e.isITE() && e[0].isFalse(), "rewriteIteFalse precondition violated"); if(withProof()) { Type t = e[1].getType(); DebugAssert(!t.isNull(), "rewriteIteFalse: e1 has no type: " + e[1].toString()); bool useIff = t.isBool(); if(useIff) pf = newPf("rewrite_ite_false_iff", e[1], e[2]); else { pf = newPf("rewrite_ite_false", t.getExpr(), e[1], e[2]); } } return newRWTheorem(e, e[2], Assumptions::emptyAssump(), pf); } // ==> ITE(c, e, e) == e Theorem CommonTheoremProducer::rewriteIteSame(const Expr& e) { Proof pf; if(CHECK_PROOFS) CHECK_SOUND(e.isITE() && e[1] == e[2], "rewriteIteSame precondition violated"); if(withProof()) { Type t = e[1].getType(); DebugAssert(!t.isNull(), "rewriteIteSame: e[1] has no type: " + e[1].toString()); bool useIff = t.isBool(); if(useIff) pf = newPf("rewrite_ite_same_iff", e[0], e[1]); else { pf = newPf("rewrite_ite_same", t.getExpr(), e[0], e[1]); } } return newRWTheorem(e, e[1], Assumptions::emptyAssump(), pf); } // NOT e ==> e IFF FALSE Theorem CommonTheoremProducer::notToIff(const Theorem& not_e) { if(CHECK_PROOFS) CHECK_SOUND(not_e.getExpr().isNot(), "notToIff: not NOT: "+not_e.toString()); // Make it an atomic rule (more efficient) Expr e(not_e.getExpr()[0]); Proof pf; if(withProof()) pf=newPf("not_to_iff", e, not_e.getProof()); return newRWTheorem(e, d_em->falseExpr(), Assumptions(not_e), pf); } // e1 XOR e2 ==> e1 IFF (NOT e2) Theorem CommonTheoremProducer::xorToIff(const Expr& e) { if(CHECK_PROOFS) { CHECK_SOUND(e.isXor(), "xorToIff precondition violated"); CHECK_SOUND(e.arity() >= 2, "Expected XOR of arity >= 2"); } Expr res = e[e.arity()-1]; for (int i = e.arity()-2; i >=0; --i) { res = (!e[i]).iffExpr(res); } Proof pf; if(withProof()) { pf = newPf("xorToIff"); } return newRWTheorem(e, res, Assumptions::emptyAssump(), pf); } // ==> IFF(e1,e2) IFF Theorem CommonTheoremProducer::rewriteIff(const Expr& e) { Proof pf; if(CHECK_PROOFS) CHECK_SOUND(e.isIff(), "rewriteIff precondition violated"); if(withProof()) { pf = newPf("rewrite_iff", e[0], e[1]); } if(e[0] == e[1]) return rewriteReflexivity(e); switch(e[0].getKind()) { case TRUE_EXPR: return newRWTheorem(e, e[1], Assumptions::emptyAssump(), pf); case FALSE_EXPR: return newRWTheorem(e, !e[1], Assumptions::emptyAssump() ,pf); case NOT: if(e[0][0]==e[1]) return newRWTheorem(e, d_em->falseExpr(), Assumptions::emptyAssump(), pf); break; default: break; } switch(e[1].getKind()) { case TRUE_EXPR: return newRWTheorem(e, e[0], Assumptions::emptyAssump(), pf); case FALSE_EXPR: return newRWTheorem(e, !e[0], Assumptions::emptyAssump(), pf); case NOT: if(e[0]==e[1][0]) return newRWTheorem(e, d_em->falseExpr(), Assumptions::emptyAssump(), pf); break; default: break; } if(e[0] < e[1]) return rewriteUsingSymmetry(e); else return reflexivityRule(e); } // ==> AND(e_1,...,e_n) IFF // 1) if e_i = FALSE then return FALSE // 2) if e_i = TRUE, remove it from children // 3) if e_i = AND(f_1,...,f_m) then AND(e_1,...,e_{i-1},f_1,...,f_m,e_{i+1},...,e_n) // 4) if n=0 return TRUE // 5) if n=1 return e_1 Theorem CommonTheoremProducer::rewriteAnd(const Expr& e) { if(CHECK_PROOFS) CHECK_SOUND(e.isAnd(), "rewriteAnd: bad Expr: " + e.toString()); Proof pf; ExprMap newKids; bool isFalse (false); for (Expr::iterator k=e.begin(), kend=e.end(); !isFalse && k != kend; ++k) { const Expr& ek = *k; if (ek.isFalse()) { isFalse=true; break; } if (ek.isAnd() && ek.arity() < 10) { for(Expr::iterator j=ek.begin(), jend=ek.end(); j!=jend; ++j) { if(newKids.count(j->negate()) > 0) { isFalse=true; break; } newKids[*j]=true; } } else if(!ek.isTrue()) { if(newKids.count(ek.negate()) > 0) { isFalse=true; break; } newKids[ek]=true; } } Expr res; if (isFalse) res = d_em->falseExpr(); else if (newKids.size() == 0) res = d_em->trueExpr(); // All newKids were TRUE else if (newKids.size() == 1) res = newKids.begin()->first; // The only child else { vector v; for(ExprMap::iterator i=newKids.begin(), iend=newKids.end(); i!=iend; ++i) v.push_back(i->first); res = andExpr(v); } if(withProof()) { pf = newPf("rewrite_and", e,res); } return newRWTheorem(e, res, Assumptions::emptyAssump(), pf); } // ==> OR(e1,e2) IFF Theorem CommonTheoremProducer::rewriteOr(const Expr& e) { if(CHECK_PROOFS) CHECK_SOUND(e.isOr(), "rewriteOr: bad Expr: " + e.toString()); Proof pf; ExprMap newKids; bool isTrue (false); for (Expr::iterator k=e.begin(), kend=e.end(); !isTrue && k != kend; ++k) { const Expr& ek = *k; if (ek.isTrue()) { isTrue=true; break; } else if (ek.isOr() && ek.arity() < 10) { for(Expr::iterator j=ek.begin(), jend=ek.end(); j!=jend; ++j) { if(newKids.count(j->negate()) > 0) { isTrue=true; break; } newKids[*j]=true; } } else if(!ek.isFalse()) { if(newKids.count(ek.negate()) > 0) { isTrue=true; break; } newKids[ek]=true; } } Expr res; if (isTrue) res = d_em->trueExpr(); else if (newKids.size() == 0) res = d_em->falseExpr(); // All kids were FALSE else if (newKids.size() == 1) res = newKids.begin()->first; // The only child else { vector v; for(ExprMap::iterator i=newKids.begin(), iend=newKids.end(); i!=iend; ++i) v.push_back(i->first); res = orExpr(v); } if(withProof()) { pf = newPf("rewrite_or", e, res); } return newRWTheorem(e, res, Assumptions::emptyAssump(), pf); } // ==> NOT TRUE IFF FALSE Theorem CommonTheoremProducer::rewriteNotTrue(const Expr& e) { Proof pf; if(CHECK_PROOFS) CHECK_SOUND(e.isNot() && e[0].isTrue(), "rewriteNotTrue precondition violated"); if(withProof()) pf = newPf("rewrite_not_true"); return newRWTheorem(e, d_em->falseExpr(), Assumptions::emptyAssump(), pf); } // ==> NOT FALSE IFF TRUE Theorem CommonTheoremProducer::rewriteNotFalse(const Expr& e) { Proof pf; if(CHECK_PROOFS) CHECK_SOUND(e.isNot() && e[0].isFalse(), "rewriteNotFalse precondition violated"); if(withProof()) pf = newPf("rewrite_not_false"); return newRWTheorem(e, d_em->trueExpr(), Assumptions::emptyAssump(), pf); } // ==> (NOT NOT e) IFF e, takes !!e Theorem CommonTheoremProducer::rewriteNotNot(const Expr& e) { Proof pf; if(CHECK_PROOFS) CHECK_SOUND(e.isNot() && e[0].isNot(), "rewriteNotNot precondition violated"); if(withProof()) pf = newPf("rewrite_not_not", e[0][0]); return newRWTheorem(e, e[0][0], Assumptions::emptyAssump(), pf); } //! ==> NOT FORALL (vars): e IFF EXISTS (vars) NOT e Theorem CommonTheoremProducer::rewriteNotForall(const Expr& e) { if(CHECK_PROOFS) { CHECK_SOUND(e.isNot() && e[0].isForall(), "rewriteNotForall: expr must be NOT FORALL:\n" +e.toString()); } Proof pf; if(withProof()) pf = newPf("rewrite_not_forall", e); return newRWTheorem(e, d_em->newClosureExpr(EXISTS, e[0].getVars(), !e[0].getBody()), Assumptions::emptyAssump(), pf); } //! ==> NOT EXISTS (vars): e IFF FORALL (vars) NOT e Theorem CommonTheoremProducer::rewriteNotExists(const Expr& e) { if(CHECK_PROOFS) { CHECK_SOUND(e.isNot() && e[0].isExists(), "rewriteNotExists: expr must be NOT FORALL:\n" +e.toString()); } Proof pf; if(withProof()) pf = newPf("rewrite_not_exists", e); return newRWTheorem(e, d_em->newClosureExpr(FORALL, e[0].getVars(), !e[0].getBody()), Assumptions::emptyAssump(), pf); } Expr CommonTheoremProducer::skolemize(const Expr& e) { vector vars; const vector& boundVars = e.getVars(); for(unsigned int i=0; i& boundVars = e.getVars(); const Expr& body = e.getBody(); if(CHECK_PROOFS) { CHECK_SOUND(boundVars.size()==1, "skolemizeRewriteVar(" +e.toString()+")"); CHECK_SOUND(body.isEq() || body.isIff(), "skolemizeRewriteVar(" +e.toString()+")"); const Expr& v = boundVars[0]; CHECK_SOUND(body[1] == v, "skolemizeRewriteVar(" +e.toString()+")"); CHECK_SOUND(!(v.subExprOf(body[0])), "skolemizeRewriteVar(" +e.toString()+")"); } // Create the Skolem constant appropriately Expr skolV(e.skolemExpr(0)); Type tp(e.getVars()[0].getType()); skolV.setType(tp); // Skolemized expression Expr skol = Expr(body.getOp(), body[0], skolV); if(withProof()) { Expr rw(e.iffExpr(skol)); pf = newLabel(rw); } return newRWTheorem(e, skol, Assumptions::emptyAssump(), pf); } Theorem CommonTheoremProducer::varIntroRule(const Expr& phi) { // This rule is sound for all expressions phi Proof pf; const Expr boundVar = d_em->newBoundVarExpr(phi.getType()); Expr body; if(phi.getType().isBool()) body = phi.iffExpr(boundVar); else body = phi.eqExpr(boundVar); std::vector v; v.push_back(boundVar); const Expr result = d_em->newClosureExpr(EXISTS, v, body); if(withProof()) pf = newPf("var_intro", phi, boundVar); return newTheorem(result, Assumptions::emptyAssump(), pf); } Theorem CommonTheoremProducer::skolemize(const Theorem& thm) { const Expr& e = thm.getExpr(); if(e.isExists()) { TRACE("skolem", "Skolemizing existential:", "", "{"); CDMap::iterator i=d_skolemized_thms.find(e), iend=d_skolemized_thms.end(); if(i!=iend) { TRACE("skolem", "Skolemized theorem found in map: ", (*i).second, "}"); return iffMP(thm, (*i).second); } Theorem skol = skolemizeRewrite(e); for(unsigned int i=0; igetBottomScope()); skol = iffMP(thm, skol); TRACE("skolem", "skolemized new theorem: ", skol, "}"); return skol; } return thm; } Theorem CommonTheoremProducer::varIntroSkolem(const Expr& e) { // First, look up the cache CDMap::iterator i=d_skolemVars.find(e), iend=d_skolemVars.end(); if(i!=iend) return (*i).second; // Not in cache; create a new one Theorem thm = varIntroRule(e); const Expr& e2 = thm.getExpr(); DebugAssert(e2.isExists() && e2.getVars().size()==1, "varIntroSkolem: e2 = " +e2.toString()); Theorem skolThm; // Check if we have a corresponding skolemized version already CDMap::iterator j=d_skolemized_thms.find(e2), jend=d_skolemized_thms.end(); if(j!=jend) { skolThm = (*i).second; } else { skolThm = skolemizeRewriteVar(e2); d_skolem_axioms.push_back(skolThm); d_skolemized_thms.insert(e2, skolThm, 0); //d_coreSatAPI->getBottomScope()); } thm = iffMP(thm, skolThm); d_skolemVars.insert(e, thm, 0); //d_coreSatAPI->getBottomScope()); return thm; } // Derived Rules Theorem CommonTheoremProducer::trueTheorem() { return iffTrueElim(reflexivityRule(d_em->trueExpr())); } Theorem CommonTheoremProducer::rewriteAnd(const Theorem& e) { return iffMP(e, rewriteAnd(e.getExpr())); } Theorem CommonTheoremProducer::rewriteOr(const Theorem& e) { return iffMP(e, rewriteOr(e.getExpr())); } Theorem CommonTheoremProducer::ackermann(const Expr& e1, const Expr& e2) { Proof pf; if(CHECK_PROOFS) CHECK_SOUND(e1.isApply() && e2.isApply() && e1.getOp() == e2.getOp(), "ackermann precondition violated"); Expr hyp; int ar = e1.arity(); if (ar == 1) { hyp = Expr(e1[0].eqExpr(e2[0])); } else { vector vec; for (int i = 0; i != ar; ++i) { vec.push_back(e1[i].eqExpr(e2[i])); } hyp = Expr(AND, vec); } if(withProof()) pf = newPf("ackermann", e1, e2); return newTheorem(hyp.impExpr(e1.eqExpr(e2)), Assumptions::emptyAssump(), pf); } void CommonTheoremProducer::findITE(const Expr& e, Expr& condition, Expr& thenpart, Expr& elsepart) { if (!e.getType().isBool() && e.isITE()) { condition = e[0]; if (!condition.containsTermITE()) { thenpart = e[1]; elsepart = e[2]; return; } } vector kids; int i = 0; for (; i < e.arity(); ++i) { if (e[i].containsTermITE()) break; kids.push_back(e[i]); } if(CHECK_PROOFS) { CHECK_SOUND(i < e.arity(), "could not find ITE"); } Expr t2, e2; findITE(e[i], condition, t2, e2); kids.push_back(t2); for(int k = i+1; k < e.arity(); ++k) { kids.push_back(e[k]); } thenpart = Expr(e.getOp(), kids); kids[i] = e2; elsepart = Expr(e.getOp(), kids); } Theorem CommonTheoremProducer::liftOneITE(const Expr& e) { if(CHECK_PROOFS) { CHECK_SOUND(e.containsTermITE(), "CommonTheoremProducer::liftOneITE: bad input" + e.toString()); } Expr cond, thenpart, elsepart; findITE(e, cond, thenpart, elsepart); Proof pf; if(withProof()) pf = newPf("lift_one_ite", e); return newRWTheorem(e, cond.iteExpr(thenpart, elsepart), Assumptions::emptyAssump(), pf); } cvc3-2.4.1/src/theorem/theorem_producer.cpp0000664000175400017540000002016411351741373020572 0ustar mdetersmdeters/*****************************************************************************/ /*! * \file theorem_producer.cpp * \brief See theorem_producer.h file for more information. * * Author: Sergey Berezin * * Created: Thu Feb 20 16:22:31 2003 * *
* * License to use, copy, modify, sell and/or distribute this software * and its documentation for any purpose is hereby granted without * royalty, subject to the terms and conditions defined in the \ref * LICENSE file provided with this distribution. * *
* */ /*****************************************************************************/ #define _CVC3_TRUSTED_ #include "theorem_producer.h" #include "sound_exception.h" #include "command_line_flags.h" using namespace std; using namespace CVC3; void TheoremProducer::soundError(const std::string& file, int line, const std::string& cond, const std::string& msg) { ostringstream ss; ss << "in " << file << ":" << line << " (" << cond << ")\n" << msg; throw SoundException(ss.str()); } // Constructor TheoremProducer::TheoremProducer(TheoremManager *tm) : d_tm(tm), d_em(tm->getEM()), d_checkProofs(&(tm->getFlags()["check-proofs"].getBool())), // Proof rule application: will have kids d_pfOp(PF_APPLY) { d_hole = d_em->newLeafExpr(PF_HOLE); } Proof TheoremProducer::newLabel(const Expr& e) { // Counter to generate unique proof labels ('u') static int s_counter = 0; static string s_prefix = "assump"; ostringstream ss; ss << s_counter++; if ((d_tm->getFlags()["lfsc-mode"]).getInt()!= 0 ) { return newPf("assumptions", e); } else { //TODO: Get rid of hack storing expr in Type field // the following lines are commented by Yeting, for neat proofs Expr var = d_tm->getEM()->newBoundVarExpr(s_prefix, ss.str(), Type(e, true)); return Proof(var); //by Yeting. } return newPf("assumptions", e); //return newPf("assumptions", var , e); } Proof TheoremProducer::newPf(const string& name) { return Proof(Expr(d_pfOp, d_em->newVarExpr(name))); } Proof TheoremProducer::newPf(const string& name, const Expr& e) { return Proof(Expr(d_pfOp, d_em->newVarExpr(name), e)); } Proof TheoremProducer::newPf(const string& name, const Proof& pf) { return Proof(Expr(d_pfOp, d_em->newVarExpr(name), pf.getExpr())); } Proof TheoremProducer::newPf(const string& name, const Expr& e1, const Expr& e2) { return Proof(Expr(d_pfOp, d_em->newVarExpr(name), e1, e2)); } Proof TheoremProducer::newPf(const string& name, const Expr& e, const Proof& pf) { return Proof(Expr(d_pfOp, d_em->newVarExpr(name), e, pf.getExpr())); } Proof TheoremProducer::newPf(const string& name, const Expr& e1, const Expr& e2, const Expr& e3) { vector kids; kids.push_back(d_em->newVarExpr(name)); kids.push_back(e1); kids.push_back(e2); kids.push_back(e3); return Proof(Expr(d_pfOp, kids)); } Proof TheoremProducer::newPf(const string& name, const Expr& e1, const Expr& e2, const Proof& pf) { vector kids; kids.push_back(d_em->newVarExpr(name)); kids.push_back(e1); kids.push_back(e2); kids.push_back(pf.getExpr()); return Proof(Expr(d_pfOp, kids)); } Proof TheoremProducer::newPf(const string& name, Expr::iterator begin, const Expr::iterator &end) { vector kids; kids.push_back(d_em->newVarExpr(name)); kids.insert(kids.end(), begin, end); return Proof(Expr(d_pfOp, kids)); } Proof TheoremProducer::newPf(const string& name, const Expr& e, Expr::iterator begin, const Expr::iterator &end) { vector kids; kids.push_back(d_em->newVarExpr(name)); kids.push_back(e); kids.insert(kids.end(), begin, end); return Proof(Expr(d_pfOp, kids)); } Proof TheoremProducer::newPf(const string& name, Expr::iterator begin, const Expr::iterator &end, const vector& pfs) { vector kids; kids.push_back(d_em->newVarExpr(name)); kids.insert(kids.end(), begin, end); for(vector::const_iterator i=pfs.begin(), iend=pfs.end(); i != iend; ++i) kids.push_back(i->getExpr()); return Proof(Expr(d_pfOp, kids)); } Proof TheoremProducer::newPf(const string& name, const vector& args) { vector kids; kids.push_back(d_em->newVarExpr(name)); kids.insert(kids.end(), args.begin(), args.end()); return Proof(Expr(d_pfOp, kids)); } Proof TheoremProducer::newPf(const string& name, const Expr& e, const vector& args) { vector kids; kids.push_back(d_em->newVarExpr(name)); kids.push_back(e); kids.insert(kids.end(), args.begin(), args.end()); return Proof(Expr(d_pfOp, kids)); } Proof TheoremProducer::newPf(const string& name, const Expr& e, const vector& pfs) { vector kids; kids.push_back(d_em->newVarExpr(name)); kids.push_back(e); for(vector::const_iterator i=pfs.begin(), iend=pfs.end(); i != iend; ++i) kids.push_back(i->getExpr()); return Proof(Expr(d_pfOp, kids)); } Proof TheoremProducer::newPf(const string& name, const Expr& e1, const Expr& e2, const vector& pfs) { vector kids; kids.push_back(d_em->newVarExpr(name)); kids.push_back(e1); kids.push_back(e2); for(vector::const_iterator i=pfs.begin(), iend=pfs.end(); i != iend; ++i) kids.push_back(i->getExpr()); return Proof(Expr(d_pfOp, kids)); } Proof TheoremProducer::newPf(const string& name, const vector& pfs) { vector kids; kids.push_back(d_em->newVarExpr(name)); for(vector::const_iterator i=pfs.begin(), iend=pfs.end(); i != iend; ++i) kids.push_back(i->getExpr()); return Proof(Expr(d_pfOp, kids)); } Proof TheoremProducer::newPf(const string& name, const vector& args, const Proof& pf) { vector kids; kids.push_back(d_em->newVarExpr(name)); kids.insert(kids.end(), args.begin(), args.end()); kids.push_back(pf.getExpr()); return Proof(Expr(d_pfOp, kids)); } Proof TheoremProducer::newPf(const string& name, const vector& args, const vector& pfs) { vector kids; kids.push_back(d_em->newVarExpr(name)); kids.insert(kids.end(), args.begin(), args.end()); for(vector::const_iterator i=pfs.begin(), iend=pfs.end(); i != iend; ++i) kids.push_back(i->getExpr()); return Proof(Expr(d_pfOp, kids)); } Proof TheoremProducer::newPf(const Proof& label, const Expr& frm, const Proof& pf) { Expr v(label.getExpr()); IF_DEBUG(Type tp(frm, true);) DebugAssert(v.isVar() && v.getType() == tp, "TheoremProducer::newPf: bad variable in LAMBDA expression: " +v.toString()); vector u; u.push_back(v); return Proof(d_tm->getEM()->newClosureExpr(LAMBDA, u, pf.getExpr())); } Proof TheoremProducer::newPf(const Proof& label, const Proof& pf) { Expr v(label.getExpr()); DebugAssert(v.isVar(), "TheoremProducer::newPf: bad variable in LAMBDA expression: " +v.toString()); vector u; u.push_back(v); return Proof(d_tm->getEM()->newClosureExpr(LAMBDA, u, pf.getExpr())); } Proof TheoremProducer::newPf(const std::vector& labels, const std::vector& frms, const Proof& pf) { std::vector u; for(unsigned i=0; igetEM()->newClosureExpr(LAMBDA, u, pf.getExpr())); } Proof TheoremProducer::newPf(const std::vector& labels, const Proof& pf) { std::vector u; for(unsigned i=0; igetEM()->newClosureExpr(LAMBDA, u, pf.getExpr())); } cvc3-2.4.1/src/theorem/theorem.cpp0000664000175400017540000004305611275717242016677 0ustar mdetersmdeters/*****************************************************************************/ /*! * \file theorem.cpp * * Author: Sergey Berezin * * Created: Dec 10 00:37:49 GMT 2002 * *
* * License to use, copy, modify, sell and/or distribute this software * and its documentation for any purpose is hereby granted without * royalty, subject to the terms and conditions defined in the \ref * LICENSE file provided with this distribution. * *
* */ /*****************************************************************************/ // CLASS: Theorem // // AUTHOR: Sergey Berezin, 07/05/02 // // See theorem.h file for more information. /////////////////////////////////////////////////////////////////////////////// #include "theorem.h" #include "theorem_value.h" #include "command_line_flags.h" namespace CVC3 { using namespace std; //! Compare Theorems by their expressions. Return -1, 0, or 1. /*! * This is an arbitrary total ordering on Theorems. For * simplicity, we define rewrite theorems (e1 = e2 or e1 <=> e2) to * be smaller than other theorems. */ /* int compare(const Theorem& t1, const Theorem& t2) { return compare(t1.getExpr(), t2.getExpr()); } */ int compare(const Theorem& t1, const Theorem& t2) { if(t1.d_thm == t2.d_thm) return 0; if(t1.isNull()) return -1; // Null Theorem is less than other theorems if(t2.isNull()) return 1; bool rw1(t1.isRewrite()), rw2(t2.isRewrite()); if(!rw2) return compare(t1, t2.getExpr()); else if(!rw1) return -compare(t2, t1.getExpr()); else { int res(compare(t1.getLHS(), t2.getLHS())); if(res==0) res = compare(t1.getRHS(), t2.getRHS()); return res; } } /* int compare(const Theorem& t1, const Expr& e2) { return compare(t1.getExpr(), e2); } */ int compare(const Theorem& t1, const Expr& e2) { bool rw1(t1.isRewrite()), rw2(e2.isEq() || e2.isIff()); if(!rw1) { const Expr& e1 = t1.getExpr(); rw1 = (e1.isEq() || e1.isIff()); } if(rw1) { if(rw2) { int res(compare(t1.getLHS(), e2[0])); if(res==0) res = compare(t1.getRHS(), e2[1]); return res; } else return -1; } else { if(rw2) return 1; else return compare(t1.getExpr(), e2); } } int compareByPtr(const Theorem& t1, const Theorem& t2) { if(t1.d_thm == t2.d_thm) return 0; else if(t1.d_thm < t2.d_thm) return -1; else return 1; } // Assignment operator Theorem& Theorem::operator=(const Theorem& th) { // Handle self-assignment if(this == &th) return *this; if(d_thm == th.d_thm) return *this; long tmp = th.d_thm; // Increase the refcount on th if (tmp & 0x1) { TheoremValue* tv = (TheoremValue*) (tmp & (~(0x1))); DebugAssert(tv->d_refcount > 0, "Theorem::operator=: invariant violated"); ++(tv->d_refcount); } else if (tmp != 0) { th.exprValue()->incRefcount(); } // Decrease the refcount on this if (d_thm & 0x1) { TheoremValue* tv = thm(); DebugAssert(tv->d_refcount > 0, "Theorem::operator=: invariant violated"); if(--(tv->d_refcount) == 0) { MemoryManager* mm = tv->getMM(); delete tv; mm->deleteData(tv); } } else if (d_thm != 0) { exprValue()->decRefcount(); } d_thm = tmp; return *this; } // Constructors Theorem::Theorem(TheoremManager* tm, const Expr &thm, const Assumptions& assump, const Proof& pf, bool isAssump, int scope) { TheoremValue* tv; if (thm.isEq() || thm.isIff()) { if (thm[0] == thm[1]) { d_expr = thm[0].d_expr; d_expr->incRefcount(); return; } tv = new(tm->getRWMM()) RWTheoremValue(tm, thm, assump, pf, isAssump, scope); } else tv = new(tm->getMM()) RegTheoremValue(tm, thm, assump, pf, isAssump, scope); tv->d_refcount++; d_thm = ((intptr_t)tv)|0x1; // TRACE("theorem", "Theorem(e) => ", *this, ""); DebugAssert(!withProof() || !pf.isNull(), "Null proof in theorem:\n"+toString()); } Theorem::Theorem(TheoremManager* tm, const Expr& lhs, const Expr& rhs, const Assumptions& assump, const Proof& pf, bool isAssump, int scope) { if (lhs == rhs) { d_expr = lhs.d_expr; d_expr->incRefcount(); return; } TheoremValue* tv = new(tm->getRWMM()) RWTheoremValue(tm, lhs, rhs, assump, pf, isAssump, scope); tv->d_refcount++; d_thm = ((long)tv)|0x1; DebugAssert(!withProof() || !pf.isNull(), "Null proof in theorem:\n"+toString()); } // Copy constructor Theorem::Theorem(const Theorem &th) : d_thm(th.d_thm) { if (d_thm & 0x1) { DebugAssert(thm()->d_refcount > 0, "Theorem(const Theorem&): refcount = " + int2string(thm()->d_refcount)); thm()->d_refcount++; // TRACE("theorem", "Theorem(Theorem&) => ", *this, ""); } else if (d_thm != 0) { exprValue()->incRefcount(); } } Theorem::Theorem(const Expr& e) : d_expr(e.d_expr) { d_expr->incRefcount(); } // Destructor Theorem::~Theorem() { if (d_thm & 0x1) { TheoremValue* tv = thm(); // TRACE("theorem", "~Theorem(", *this, ") {"); IF_DEBUG(FatalAssert(tv->d_refcount > 0, "~Theorem(): refcount = " + int2string(tv->d_refcount));) if((--tv->d_refcount) == 0) { // TRACE_MSG("theorem", "~Theorem(): deleting"); MemoryManager* mm = tv->getMM(); delete tv; mm->deleteData(tv); } } else if (d_thm != 0) { exprValue()->decRefcount(); } } void Theorem::printx() const { getExpr().print(); } void Theorem::printxnodag() const { getExpr().printnodag(); } void Theorem::pprintx() const { getExpr().pprint(); } void Theorem::pprintxnodag() const { getExpr().pprintnodag(); } void Theorem::print() const { cout << toString() << endl; } // Test if we are running in a proof production mode and with assumptions bool Theorem::withProof() const { if (isRefl()) return exprValue()->d_em->getTM()->withProof(); return thm()->d_tm->withProof(); } bool Theorem::withAssumptions() const { if (isRefl()) return exprValue()->d_em->getTM()->withAssumptions(); return thm()->d_tm->withAssumptions(); } bool Theorem::isRewrite() const { DebugAssert(!isNull(), "CVC3::Theorem::isRewrite(): we are Null"); return isRefl() || thm()->isRewrite(); } // Return the theorem value as an Expr Expr Theorem::getExpr() const { DebugAssert(!isNull(), "CVC3::Theorem::getExpr(): we are Null"); if (isRefl()) { Expr e(exprValue()); if (e.isTerm()) return e.eqExpr(e); else return e.iffExpr(e); } else return thm()->getExpr(); } const Expr& Theorem::getLHS() const { DebugAssert(!isNull(), "CVC3::Theorem::getLHS: we are Null"); if (isRefl()) return *((Expr*)(&d_expr)); else return thm()->getLHS(); } const Expr& Theorem::getRHS() const { DebugAssert(!isNull(), "CVC3::Theorem::getRHS: we are Null"); if (isRefl()) return *((Expr*)(&d_expr)); else return thm()->getRHS(); } // Return the assumptions. // void Theorem::getAssumptions(Assumptions& a) const // { // a = getAssumptionsRef(); // } void Theorem::getAssumptionsRec(set& assumptions) const { if (isRefl() || isFlagged()) return; setFlag(); if(isAssump()) { assumptions.insert(getExpr()); } else { const Assumptions& a = getAssumptionsRef(); for(Assumptions::iterator i=a.begin(), iend=a.end(); i!=iend; ++i) (*i).getAssumptionsRec(assumptions); } } void Theorem::getLeafAssumptions(vector& assumptions, bool negate) const { if (isNull() || isRefl()) return; set assumpSet; clearAllFlags(); getAssumptionsRec(assumpSet); // Order assumptions by their creation time for(set::iterator i=assumpSet.begin(), iend=assumpSet.end(); i!=iend; ++i) assumptions.push_back(negate ? (*i).negate() : *i); } void Theorem::GetSatAssumptionsRec(vector& assumptions) const { DebugAssert(!isRefl() && !isFlagged(), "Invariant violated"); setFlag(); Expr e = getExpr(); if (e.isAbsLiteral()) { if (isAssump() || e.isRegisteredAtom() || (e.isNot() && e[0].isRegisteredAtom())) { assumptions.push_back(*this); return; } } const Assumptions& a = getAssumptionsRef(); for (Assumptions::iterator i = a.begin(); i != a.end(); i++) { if ((*i).isRefl() || (*i).isFlagged()) continue; (*i).GetSatAssumptionsRec(assumptions); } } void Theorem::GetSatAssumptions(vector& assumptions) const { DebugAssert(!isRefl() && !isFlagged(), "Invariant violated"); setFlag(); const Assumptions& a = getAssumptionsRef(); for (Assumptions::iterator i = a.begin(); i != a.end(); i++) { if ((*i).isRefl() || (*i).isFlagged()) continue; (*i).GetSatAssumptionsRec(assumptions); } } void Theorem::getAssumptionsAndCongRec(set& assumptions, vector& congruences) const { if (isRefl() || isFlagged()) return; setFlag(); if(isAssump()) { assumptions.insert(getExpr()); } else { const Assumptions& a = getAssumptionsRef(); if (isSubst() && a.size() == 1) { vector hyp; const Theorem& thm = *(a.begin()); thm.getAssumptionsAndCongRec(assumptions, congruences); if (thm.isRewrite() && thm.getLHS().isTerm() && thm.getLHS().isAtomic() && thm.getRHS().isAtomic() && !thm.isRefl()) { hyp.push_back(!thm.getExpr()); } else return; const Expr& e = getExpr(); if (e.isAtomicFormula()) { if (e[0] < e[1]) { hyp.push_back(e[1].eqExpr(e[0])); } else { hyp.push_back(e); } congruences.push_back(Expr(OR, hyp)); } else if (e[0].isAtomicFormula() && !e[0].isEq()) { hyp.push_back(!e[0]); hyp.push_back(e[1]); congruences.push_back(Expr(OR, hyp)); hyp.pop_back(); hyp.pop_back(); hyp.push_back(e[0]); hyp.push_back(!e[1]); congruences.push_back(Expr(OR, hyp)); } } else { Assumptions::iterator i=a.begin(), iend=a.end(); for(; i!=iend; ++i) (*i).getAssumptionsAndCongRec(assumptions, congruences); } } } void Theorem::getAssumptionsAndCong(vector& assumptions, vector& congruences, bool negate) const { if (isNull() || isRefl()) return; set assumpSet; clearAllFlags(); getAssumptionsAndCongRec(assumpSet, congruences); // Order assumptions by their creation time for(set::iterator i=assumpSet.begin(), iend=assumpSet.end(); i!=iend; ++i) assumptions.push_back(negate ? (*i).negate() : *i); } const Assumptions& Theorem::getAssumptionsRef() const { DebugAssert(!isNull(), "CVC3::Theorem::getAssumptionsRef: we are Null"); if (!isRefl()) { return thm()->getAssumptionsRef(); } else return Assumptions::emptyAssump(); } bool Theorem::isAssump() const { DebugAssert(!isNull(), "CVC3::Theorem::isAssump: we are Null"); return isRefl() ? false : thm()->isAssump(); } // Return the proof of the theorem. If running without proofs, // return the Null proof. Proof Theorem::getProof() const { static Proof null; DebugAssert(!isNull(), "CVC3::Theorem::getProof: we are Null"); if (isRefl()) { return Proof(Expr(PF_APPLY, exprValue()->d_em->newVarExpr("refl"), Expr(exprValue()))); } else if (withProof() == true) return thm()->getProof(); else return null; } bool Theorem::isFlagged() const { DebugAssert(!isNull(), "CVC3::Theorem::isFlagged: we are Null"); if (isRefl()) return exprValue()->d_em->getTM()->isFlagged((long)d_expr); else return thm()->isFlagged(); } void Theorem::clearAllFlags() const { DebugAssert(!isNull(), "CVC3::Theorem::clearAllFlags: we are Null"); if (isRefl()) { exprValue()->d_em->getTM()->clearAllFlags(); } else thm()->clearAllFlags(); } void Theorem::setFlag() const { DebugAssert(!isNull(), "CVC3::Theorem::setFlag: we are Null"); if (isRefl()) exprValue()->d_em->getTM()->setFlag((long)d_expr); else thm()->setFlag(); } void Theorem::setCachedValue(int value) const { DebugAssert(!isNull(), "CVC3::Theorem::setCachedValue: we are Null"); if (isRefl()) exprValue()->d_em->getTM()->setCachedValue((long)d_expr, value); else thm()->setCachedValue(value); } int Theorem::getCachedValue() const { DebugAssert(!isNull(), "CVC3::Theorem::getCachedValue: we are Null"); if (isRefl()) return exprValue()->d_em->getTM()->getCachedValue((long)d_expr); return thm()->getCachedValue(); } void Theorem::setSubst() const { DebugAssert(!isNull() && !isRefl(), "CVC3::Theorem::setSubst: invalid thm"); thm()->setSubst(); } bool Theorem::isSubst() const { DebugAssert(!isNull(), "CVC3::Theorem::isSubst: we are Null"); if (isRefl()) return false; return thm()->isSubst(); } void Theorem::setExpandFlag(bool val) const { DebugAssert(!isNull(), "CVC3::Theorem::setExpandFlag: we are Null"); if (isRefl()) exprValue()->d_em->getTM()->setExpandFlag((long)d_expr, val); thm()->setExpandFlag(val); } bool Theorem::getExpandFlag() const { DebugAssert(!isNull(), "CVC3::Theorem::getExpandFlag: we are Null"); if (isRefl()) return exprValue()->d_em->getTM()->getExpandFlag((long)d_expr); return thm()->getExpandFlag(); } void Theorem::setLitFlag(bool val) const { DebugAssert(!isNull(), "CVC3::Theorem::setLitFlag: we are Null"); if (isRefl()) exprValue()->d_em->getTM()->setLitFlag((long)d_expr, val); thm()->setLitFlag(val); } bool Theorem::getLitFlag() const { DebugAssert(!isNull(), "CVC3::Theorem::getLitFlag: we are Null"); if (isRefl()) return exprValue()->d_em->getTM()->getLitFlag((long)d_expr); return thm()->getLitFlag(); } bool Theorem::isAbsLiteral() const { return getExpr().isAbsLiteral(); } int Theorem::getScope() const { DebugAssert(!isNull(), "CVC3::Theorem::getScope: we are Null"); return isRefl() ? 0 : thm()->getScope(); } unsigned Theorem::getQuantLevel() const { DebugAssert(!isNull(), "CVC3::Theorem::getQuantLevel: we are Null"); TRACE("quant-level", "isRefl? ", isRefl(), ""); return isRefl() ? 0 : thm()->getQuantLevel(); } unsigned Theorem::getQuantLevelDebug() const { DebugAssert(!isNull(), "CVC3::Theorem::getQuantLevel: we are Null"); TRACE("quant-level", "isRefl? ", isRefl(), ""); return isRefl() ? 0 : thm()->getQuantLevelDebug(); } void Theorem::setQuantLevel(unsigned level) { DebugAssert(!isNull(), "CVC3::Theorem::setQuantLevel: we are Null"); // DebugAssert(!isRefl(), "CVC3::Theorem::setQuantLevel: we are Refl"); if (isRefl()) return; thm()->setQuantLevel(level); } size_t Theorem::hash() const { static std::hash h; return h(d_thm); } void Theorem::recursivePrint(int& i) const { const Assumptions::iterator iend = getAssumptionsRef().end(); Assumptions::iterator it = getAssumptionsRef().begin(); if (!isAssump()) { for (; it != iend; ++it) { if (it->isFlagged()) continue; it->recursivePrint(i); it->setFlag(); } } setCachedValue(i++); cout << "[" << getCachedValue() << "]@" << getScope() << "\tTheorem: {"; if (isAssump()) { cout << "assump"; } else if (getAssumptionsRef().empty()) { cout << "empty"; } else { for (it = getAssumptionsRef().begin(); it != iend; ++it) { if (it != getAssumptionsRef().begin()) cout << ", "; cout << "[" << it->getCachedValue() << "]" ; } } cout << "}" << endl << "\t\t|- " << getExpr(); if (isSubst()) cout << " [[Subst]]"; cout << endl; } // Return the scope level at which this theorem was created // int Theorem::getScope() const { // DebugAssert(!isNull(), "CVC3::Theorem::getScope: we are Null"); // return thm()->getScope(); // } // Assumptions Theorem::getUserAssumptions() const { // ExprMap em; // Assumptions a = getAssumptionsCopy(); // collectAssumptions(a, em); // return a; // } // void collectAssumptions(Assumptions &a, ExprMap em ) const { // if (isAssump()) { // // cache? // return; // } // const Assumptions a2 = thm()->getAssumptions(); // a.add(a2); // Assumptions::iterator a2begin = a2.begin(); // const Assumptions::iterator a2end = a2.end(); // } // Printing Theorem ostream& Theorem::print(ostream& os, const string& name) const { if(isNull()) return os << name << "(Null)"; ExprManager *em = getExpr().getEM(); if (isRefl()) os << getExpr(); else if (withAssumptions()) { em->incIndent(name.size()+2); os << name << "([" << thm() << "#" << thm()->d_refcount << "]@" << getScope() << "\n["; if(isAssump()) os << "Assump"; else { if(thm()->d_tm->getFlags()["print-assump"].getBool() && em->isActive()) os << getAssumptionsRef(); else os << ""; } os << "]\n |--- "; em->indent(7); if(em->isActive()) os << getExpr(); else os << "(being destructed)"; if(withProof()) os << "\n Proof = " << getProof(); return os << ")"; } else { em->incIndent(name.size()+1); os << name << "("; if(em->isActive()) os << getExpr(); else os << "being destructed"; return os << ")"; } return os; } } // end of namespace CVC3 cvc3-2.4.1/src/theorem/assumptions.cpp0000664000175400017540000001752710672077433017626 0ustar mdetersmdeters/*****************************************************************************/ /*! *\file assumptions.cpp *\brief Implementation of class Assumptions * * Author: Clark Barrett * * Created: Thu Jan 5 06:25:52 2006 * *
* * License to use, copy, modify, sell and/or distribute this software * and its documentation for any purpose is hereby granted without * royalty, subject to the terms and conditions defined in the \ref * LICENSE file provided with this distribution. * *
* */ /*****************************************************************************/ #include #include "assumptions.h" using namespace std; using namespace CVC3; Assumptions Assumptions::s_empty; const Theorem& Assumptions::findTheorem(const Expr& e) const { static Theorem null; // TRACE_MSG("assumptions", "findTheorem"); const Theorem& t = find(e); if (!t.isNull()) return t; // recurse const vector::const_iterator aend = d_vector.end(); for (vector::const_iterator iter2 = d_vector.begin(); iter2 != aend; ++iter2) { if (iter2->isRefl() || !iter2->isFlagged()) { if (compare(*iter2, e) == 0) return *iter2; if (!iter2->isAssump()) { const Theorem& t = iter2->getAssumptionsRef().findTheorem(e); if (!t.isNull()) return t; } if (!iter2->isRefl()) iter2->setFlag(); } } return null; // not found } bool Assumptions::findExpr(const Assumptions& a, const Expr& e, vector& gamma) { bool found = false; const Assumptions::iterator aend = a.end(); Assumptions::iterator iter = a.begin(); for (; iter != aend; ++iter) { if (iter->isRefl()) continue; if (iter->isFlagged()) { if (iter->getCachedValue()) found = true; } else { if ((iter->getExpr() == e) || (!iter->isAssump() && findExpr(iter->getAssumptionsRef(), e, gamma))) { found = true; iter->setCachedValue(true); } else iter->setCachedValue(false); iter->setFlag(); } } if (found) { for (iter = a.begin(); iter != aend; ++iter) { if (iter->isRefl()) continue; if (!iter->getCachedValue()) gamma.push_back(*iter); } } return found; } bool Assumptions::findExprs(const Assumptions& a, const vector& es, vector& gamma) { bool found = false; const vector::const_iterator esbegin = es.begin(); const vector::const_iterator esend = es.end(); const Assumptions::iterator aend = a.end(); Assumptions::iterator iter = a.begin(); for (; iter != aend; ++iter) { if (iter->isRefl()) continue; else if (iter->isFlagged()) { if (iter->getCachedValue()) found = true; } else { // switch to binary search below? (sort es first) if ((::find(esbegin, esend, iter->getExpr()) != esend) || (!iter->isAssump() && findExprs(iter->getAssumptionsRef(), es, gamma))) { found = true; iter->setCachedValue(true); } else iter->setCachedValue(false); iter->setFlag(); } } if (found) { for (iter = a.begin(); iter != aend; ++iter) { if (iter->isRefl()) continue; if (!iter->getCachedValue()) gamma.push_back(*iter); } } return found; } Assumptions::Assumptions(const vector& v) { if (v.empty()) return; d_vector.reserve(v.size()); const vector::const_iterator iend = v.end(); vector::const_iterator i = v.begin(); for (;i != iend; ++i) { if ((!i->getAssumptionsRef().empty())) { d_vector.push_back(*i); } } if (d_vector.size() <= 1) return; sort(d_vector.begin(), d_vector.end()); vector::iterator newend = unique(d_vector.begin(), d_vector.end(), Theorem::TheoremEq); d_vector.resize(newend - d_vector.begin()); } Assumptions::Assumptions(const Theorem& t1, const Theorem& t2) { if (!t1.getAssumptionsRef().empty()) { if (!t2.getAssumptionsRef().empty()) { switch(compare(t1, t2)) { case -1: // t1 < t2: d_vector.push_back(t1); d_vector.push_back(t2); break; case 0: // t1 == t2: d_vector.push_back(t1); break; case 1: // t1 > t2: d_vector.push_back(t2); d_vector.push_back(t1); break; } } else d_vector.push_back(t1); } else if (!t2.getAssumptionsRef().empty()) { d_vector.push_back(t2); } /* switch(compare(t1, t2)) { case -1: // t1 < t2: d_vector.push_back(t1); d_vector.push_back(t2); break; case 0: // t1 == t2: d_vector.push_back(t1); break; case 1: // t1 > t2: d_vector.push_back(t2); d_vector.push_back(t1); break; } */ } void Assumptions::add(const Theorem& t) { if (t.getAssumptionsRef().empty()) return; vector::iterator iter, iend = d_vector.end(); iter = lower_bound(d_vector.begin(), iend, t); if (iter != iend && compare(t, *iter) == 0) return; d_vector.insert(iter, t); } void Assumptions::add(const std::vector& thms) { if (thms.size() == 0) return; IF_DEBUG( vector::const_iterator iend = thms.end(); for (vector::const_iterator i = thms.begin(); i != iend; ++i) { if (i+1 == iend) break; DebugAssert(compare(*i, *(i+1)) == -1, "Expected sorted"); } ) vector v; v.reserve(d_vector.size()+thms.size()); vector::const_iterator i = d_vector.begin(); vector::const_iterator j = thms.begin(); const vector::const_iterator v1end = d_vector.end(); const vector::const_iterator v2end = thms.end(); // merge while (i != v1end && j != v2end) { if (j->getAssumptionsRef().empty()) { ++j; continue; } switch(compare(*i, *j)) { case 0: // copy only 1, drop down to next case ++j; case -1: // < v.push_back(*i); ++i; break; default: // > v.push_back(*j); ++j; }; } // Push in the remaining elements for(; i != v1end; ++i) v.push_back(*i); for(; j != v2end; ++j) { if (!j->getAssumptionsRef().empty()) v.push_back(*j); } d_vector.swap(v); } string Assumptions::toString() const { ostringstream ss; ss << (*this); return ss.str(); } void Assumptions::print() const { cout << toString() << endl; } const Theorem& Assumptions::operator[](const Expr& e) const { if (!d_vector.empty()) { d_vector.front().clearAllFlags(); } return findTheorem(e); } const Theorem& Assumptions::find(const Expr& e) const { static Theorem null; // binary search int lo = 0; int hi = d_vector.size() - 1; int loc; while (lo <= hi) { loc = (lo + hi) / 2; switch (compare(d_vector[loc], e)) { case 0: return d_vector[loc]; case -1: // t < e lo = loc + 1; break; default: // t > e hi = loc - 1; }; } return null; } //////////////////////////////////////////////////////////////////// // Assumptions friend methods //////////////////////////////////////////////////////////////////// namespace CVC3 { Assumptions operator-(const Assumptions& a, const Expr& e) { if (a.begin() != a.end()) { a.begin()->clearAllFlags(); vector gamma; if (Assumptions::findExpr(a, e, gamma)) return Assumptions(gamma); } return a; } Assumptions operator-(const Assumptions& a, const vector& es) { if (!es.empty() && a.begin() != a.end()) { a.begin()->clearAllFlags(); vector gamma; if (Assumptions::findExprs(a, es, gamma)) return Assumptions(gamma); } return a; } ostream& operator<<(ostream& os, const Assumptions &assump) { vector::const_iterator i = assump.d_vector.begin(); const vector::const_iterator iend = assump.d_vector.end(); if(i != iend) { os << i->getExpr(); i++; } for(; i != iend; i++) os << ",\n " << i->getExpr(); return os; } } // end of namespace CVC3 cvc3-2.4.1/src/theorem/common_theorem_producer.h0000664000175400017540000001166611225731020021602 0ustar mdetersmdeters/*****************************************************************************/ /*! * \file common_theorem_producer.h * * Author: Sergey Berezin * * Created: Feb 05 03:40:36 GMT 2003 * *
* * License to use, copy, modify, sell and/or distribute this software * and its documentation for any purpose is hereby granted without * royalty, subject to the terms and conditions defined in the \ref * LICENSE file provided with this distribution. * *
* */ /*****************************************************************************/ // CLASS: CommonTheoremProducer // // AUTHOR: Sergey Berezin, 12/09/2002 // // Description: Implementation of the proof rules for ground // equational logic (reflexivity, symmetry, transitivity, and // substitutivity). // /////////////////////////////////////////////////////////////////////////////// #ifndef _cvc3__common_theorem_producer_h_ #define _cvc3__common_theorem_producer_h_ #include "common_proof_rules.h" #include "theorem_producer.h" #include "theorem.h" #include "cdmap.h" namespace CVC3 { class CommonTheoremProducer: public CommonProofRules, public TheoremProducer { private: // TODO: do we need to record skolem axioms? do we need context-dependence? // skolem axioms std::vector d_skolem_axioms; /* @brief Keep skolemization axioms so that they can be reused without being recreated each time */ CDMap d_skolemized_thms; //! Mapping of e to "|- e = v" for fresh Skolem vars v CDMap d_skolemVars; //! Helper function for liftOneITE void findITE(const Expr& e, Expr& condition, Expr& thenpart, Expr& elsepart); public: CommonTheoremProducer(TheoremManager* tm); virtual ~CommonTheoremProducer() { } Theorem3 queryTCC(const Theorem& phi, const Theorem& D_phi); Theorem3 implIntro3(const Theorem3& phi, const std::vector& assump, const std::vector& tccs); Theorem assumpRule(const Expr& a, int scope = -1); Theorem reflexivityRule(const Expr& a); Theorem rewriteReflexivity(const Expr& t); Theorem symmetryRule(const Theorem& a1_eq_a2); Theorem rewriteUsingSymmetry(const Expr& a1_eq_a2); Theorem transitivityRule(const Theorem& a1_eq_a2, const Theorem& a2_eq_a3); Theorem substitutivityRule(const Expr& e, const Theorem& thm); Theorem substitutivityRule(const Expr& e, const Theorem& thm1, const Theorem& thm2); Theorem substitutivityRule(const Op& op, const std::vector& thms); Theorem substitutivityRule(const Expr& e, const std::vector& changed, const std::vector& thms); Theorem substitutivityRule(const Expr& e, const int changed, const Theorem& thm); Theorem contradictionRule(const Theorem& e, const Theorem& not_e); Theorem excludedMiddle(const Expr& e); Theorem iffTrue(const Theorem& e); Theorem iffNotFalse(const Theorem& e); Theorem iffTrueElim(const Theorem& e); Theorem iffFalseElim(const Theorem& e); Theorem iffContrapositive(const Theorem& thm); Theorem notNotElim(const Theorem& e); Theorem iffMP(const Theorem& e1, const Theorem& e1_iff_e2); Theorem implMP(const Theorem& e1, const Theorem& e1_impl_e2); Theorem andElim(const Theorem& e, int i); Theorem andIntro(const Theorem& e1, const Theorem& e2); Theorem andIntro(const std::vector& es); Theorem implIntro(const Theorem& phi, const std::vector& assump); Theorem implContrapositive(const Theorem& thm); Theorem rewriteIteTrue(const Expr& e); Theorem rewriteIteFalse(const Expr& e); Theorem rewriteIteSame(const Expr& e); Theorem notToIff(const Theorem& not_e); Theorem xorToIff(const Expr& e); Theorem rewriteIff(const Expr& e); Theorem rewriteAnd(const Expr& e); Theorem rewriteOr(const Expr& e); Theorem rewriteNotTrue(const Expr& e); Theorem rewriteNotFalse(const Expr& e); Theorem rewriteNotNot(const Expr& e); Theorem rewriteNotForall(const Expr& forallExpr); Theorem rewriteNotExists(const Expr& existsExpr); Expr skolemize(const Expr& e); Theorem skolemizeRewrite(const Expr& e); Theorem skolemizeRewriteVar(const Expr& e); Theorem varIntroRule(const Expr& e); Theorem skolemize(const Theorem& thm); Theorem varIntroSkolem(const Expr& e); Theorem trueTheorem(); Theorem rewriteAnd(const Theorem& e); Theorem rewriteOr(const Theorem& e); Theorem ackermann(const Expr& e1, const Expr& e2); Theorem liftOneITE(const Expr& e); std::vector& getSkolemAxioms() { return d_skolem_axioms; } void clearSkolemAxioms() { d_skolem_axioms.clear(); } }; // end of class CommonTheoremProducer } // end of namespace CVC3 #endif cvc3-2.4.1/src/theorem/theorem_manager.cpp0000664000175400017540000000414010473665424020363 0ustar mdetersmdeters/*****************************************************************************/ /*! * \file theorem_manager.cpp * * Author: Sergey Berezin * * Created: Feb 11 02:39:35 GMT 2003 * *
* * License to use, copy, modify, sell and/or distribute this software * and its documentation for any purpose is hereby granted without * royalty, subject to the terms and conditions defined in the \ref * LICENSE file provided with this distribution. * *
* */ /*****************************************************************************/ // File: theorem_manager.cpp // // AUTHOR: Sergey Berezin, 07/05/02 // // Defines some functions for class TheoremManager. They are not // inlined becaule they use ExprManager (expr_manager.h), which // includes theorem_manager.h. // /////////////////////////////////////////////////////////////////////////////// #include "theorem_value.h" #include "memory_manager_chunks.h" #include "memory_manager_malloc.h" #include "command_line_flags.h" #include "common_proof_rules.h" using namespace std; using namespace CVC3; // ExprManager is not initialized in vcl yet when we are created; we // use d_em as our local cache to fetch the EM when our getEM() is // first called. TheoremManager::TheoremManager(ContextManager* cm, ExprManager* em, const CLFlags& flags) : d_cm(cm), d_em(em), d_flags(flags), d_withProof(flags["proofs"].getBool()), d_withAssump(true), d_flag(1), d_active(true) { d_em->newKind(PF_APPLY, "|-"); d_em->newKind(PF_HOLE, "**"); DebugAssert(!d_withProof || d_withAssump, "TheoremManager(): proofs without assumptions are not allowed"); if (flags["mm"].getString() == "chunks") { d_mm = new MemoryManagerChunks(sizeof(RegTheoremValue)); d_rwmm = new MemoryManagerChunks(sizeof(RWTheoremValue)); } else { d_mm = new MemoryManagerMalloc(); d_rwmm = new MemoryManagerMalloc(); } d_rules = createProofRules(); } TheoremManager::~TheoremManager() { delete d_mm; delete d_rwmm; } void TheoremManager::clear() { delete d_rules; d_active=false; } cvc3-2.4.1/src/theorem/theorem_value.h0000664000175400017540000004245311027560537017536 0ustar mdetersmdeters/*****************************************************************************/ /*! * \file theorem_value.h * * Author: Sergey Berezin * * Created: Dec 10 01:03:34 GMT 2002 * *
* * License to use, copy, modify, sell and/or distribute this software * and its documentation for any purpose is hereby granted without * royalty, subject to the terms and conditions defined in the \ref * LICENSE file provided with this distribution. * *
* */ /*****************************************************************************/ // CLASS: TheoremValue // // AUTHOR: Sergey Berezin, 07/05/02 // // Abstract: // // A class representing a proven fact in CVC. It stores the theorem // as a CVC expression, and in the appropriate modes also the set of // assumptions and the proof. // // The idea is to allow only a few trusted classes to create values of // this class. If all the critical computations in the decision // procedures are done through the use of Theorems, then soundness of // these decision procedures will rely only on the soundness of the // methods in the trusted classes (the inference rules). // // Thus, proof checking can effectively be done at run-time on the // fly. Or the soundness may be potentially proven by static analysis // and many run-time checks can then be optimized away. // // This theorem_value.h file should NOT be used by the decision // procedures. Use theorem.h instead. // //////////////////////////////////////////////////////////////////////// #ifndef _cvc3__theorem_value_h_ #define _cvc3__theorem_value_h_ #include "assumptions.h" #include "theorem_manager.h" //#include "theory_core.h" //#include "vcl.h" namespace CVC3 { //extern VCL* myvcl; class TheoremValue { // These are the only classes that can create new TheoremValue classes friend class Theorem; friend class RegTheoremValue; friend class RWTheoremValue; protected: //! Theorem Manager TheoremManager* d_tm; //! The expression representing a theorem Expr d_thm; //! Proof of the theorem Proof d_proof; //! How many pointers to this theorem value unsigned d_refcount; //! Largest scope level of the assumptions int d_scopeLevel; //! Quantification level of this theorem unsigned d_quantLevel; //! debug quantlevel, this one is from proof, not from assumption list // unsigned d_quantLevelDebug; //! Temporary flag used during traversals unsigned d_flag; //! Temporary cache used during traversals int d_cachedValue : 28; bool d_isSubst : 1; //!< whether this theorem was generated by substitution bool d_isAssump : 1; bool d_expand : 1; //!< whether it should this be expanded in graph traversal bool d_clauselit : 1; //!< whether it belongs to the conflict clause private: // Constructor. /*! * NOTE: it is private; only friend classes can call it. * * If the assumptions refer to only one theorem, grab the * assumptions of that theorem instead. */ //by yeting, we should do something to catch theorems created with empty assumptions. //one way is to set the d_quantLevel 999 here. TheoremValue(TheoremManager* tm, const Expr &thm, const Proof& pf, bool isAssump) : d_tm(tm), d_thm(thm), d_proof(pf), d_refcount(0), d_scopeLevel(0), d_quantLevel(0), d_flag(0), d_cachedValue(0), d_isSubst(0), d_isAssump(isAssump), d_expand(0), d_clauselit(0) {} // Disable copy constructor and assignment TheoremValue(const TheoremValue& t) { FatalAssert(false, "TheoremValue() copy constructor called"); } TheoremValue& operator=(const TheoremValue& t) { FatalAssert(false, "TheoremValue assignment operator called"); return *this; } bool isFlagged() const { return d_flag == d_tm->getFlag(); } void clearAllFlags() { d_tm->clearAllFlags(); } void setFlag() { d_flag = d_tm->getFlag(); } void setCachedValue(int value) { d_cachedValue = value; } int getCachedValue() const { return d_cachedValue; } void setSubst() { d_isSubst = true; } bool isSubst() { return d_isSubst; } void setExpandFlag(bool val) { d_expand = val; } bool getExpandFlag() { return d_expand; } void setLitFlag(bool val) { d_clauselit = val; } bool getLitFlag() { return d_clauselit; } int getScope() { return d_scopeLevel; } unsigned getQuantLevel() { return d_quantLevel; } unsigned getQuantLevelDebug() { return 0; // return d_quantLevelDebug; } void setQuantLevel(unsigned level) { d_quantLevel = level; } unsigned recQuantLevel(Expr proof){ return d_quantLevel; /* if( ! proof.isNull()){ // std::cout << "debug level " << proof << std::endl;; } else { // std::cout << "proof null" << proof << std::endl;; } unsigned nch = proof.arity(); unsigned level(0); if (proof.getKind() == PF_APPLY){ for (unsigned i = 1 ; i < nch ; i++){ if ((proof[i]).getKind() == PF_APPLY || proof[i].getKind() == LAMBDA || proof[i].isVar()) { if(proof[i].isVar()){ // std::cout << "found var in pf # " << proof << std::endl; } unsigned chLevel = recQuantLevel(proof[i]); level = chLevel > level ? chLevel : level ; } } if(proof[0].getName() == "universal_elimination"){ level++; unsigned gtermLevel = myvcl->core()->getQuantLevelForTerm(proof[4]); if((gtermLevel + 1) > level ){ level = gtermLevel+1; } // std::cout << "level " << level << std::endl; } else { // std::cout << "proof name non-inst" << proof[0].getName() << std::endl; } // std::cout << "get level " << d_thm << std::endl; // std::cout << "get level " << level << std::endl; // std::cout << "get level " << proof << std::endl; return level; } else if (proof.getKind() == LAMBDA){ std::cout << "lambda " << proof << std::endl; std::cout << "lambda body " << proof << std::endl; return recQuantLevel(proof.getBody()); } else if (proof.isNull() ){ // std::cout <<" error in get quantleveldebug " << std::endl; // std::cout << proof << std::endl; return 100000; } else if (proof.isVar()){ if(proof.getType().getExpr().getType().isBool()){ //std::cout << "var proof " << proof.getType().getExpr() << std::endl; // std::cout << "found proof var # " << proof << std::endl; // std::cout << proof.getType() << std::endl; // std::cout << "the quant level is " << myvcl->core()->getQuantLevelForTerm(proof.getType().getExpr()) << std::endl; return myvcl->core()->getQuantLevelForTerm(proof.getType().getExpr()); } else{ return 0; } } else{ std::cout <<" error in get quantleveldebug " << std::endl; std::cout << proof << std::endl; std::cout << proof.isVar() << std::endl; return 200000; } return 0; */ } unsigned findQuantLevelDebug(){ return d_quantLevel; /* Expr p (d_proof.getExpr()); unsigned ret ; if (isAssump()){ if(d_thm.inUserAssumption()){ ret = 0 ; // return 0; } else { // std::cout <<" why here " << std::endl; // std::cout << "the quant level is " << myvcl->core()->getQuantLevelForTerm(d_thm) << std::endl; // std::cout << d_thm << std::endl; // std::cout <<" == end of why here " << std::endl; ret = myvcl->core()->getQuantLevelForTerm(d_thm); // // return myvcl->core()->getQuantLevelForTerm(d_thm); } } else if (p.isVar()){ unsigned level1 = myvcl->core()->getQuantLevelForTerm(p.getType().getExpr()); unsigned level2 = d_quantLevel; if(level1 != level2){ std::cout <<"not rq" << std::endl; } else{ ret = level1; // return level1; } } else { ret = recQuantLevel(p); // return recQuantLevel(p); } // std::cout << " get -- begin with debug level " << ret << std::endl; // std::cout << " quant level " << d_quantLevel << std::endl; // std::cout << " get level thm " << d_thm << std::endl; // std::cout << " get level is var " << p.isVar() << std::endl; if(p.isVar()){ // std::cout << "var proof " << p.getType().getExpr()<< std::endl; } return ret; */ } // virtual bool isRewrite() const { return d_thm.isEq() || d_thm.isIff(); } virtual bool isRewrite() const { return false; } virtual const Expr& getExpr() const { return d_thm; } virtual const Expr& getLHS() const { // TRACE("getExpr","TheoremValue::getLHS called (",d_thm,")"); DebugAssert(isRewrite(), "TheoremValue::getLHS() called on non-rewrite theorem:\n" +toString()); return d_thm[0]; } virtual const Expr& getRHS() const { // TRACE("getExpr","TheoremValue::getRHS called (",d_thm,")"); DebugAssert(isRewrite(), "TheoremValue::getRHS() called on non-rewrite theorem:\n" +toString()); return d_thm[1]; } virtual const Assumptions& getAssumptionsRef() const = 0; bool isAssump() const { return d_isAssump; } const Proof& getProof() { return d_proof; } public: // Destructor virtual ~TheoremValue() { IF_DEBUG(FatalAssert(d_refcount == 0, "Thm::TheoremValue::~TheoremValue(): refcount != 0.");) } std::string toString() const { return getAssumptionsRef().toString() + " |- " + getExpr().toString(); } // Memory management virtual MemoryManager* getMM() = 0; }; // end of class TheoremValue /////////////////////////////////////////////////////////////////////////////// // // // Class: RegTheoremValue // // Author: Clark Barrett // // Created: Fri May 2 12:51:55 2003 // // Description: A special subclass for non-rewrite theorems. Assumptions are// // embedded in the object for easy reference. // // // /////////////////////////////////////////////////////////////////////////////// class RegTheoremValue :public TheoremValue { friend class Theorem; protected: //! The assumptions for the theorem Assumptions d_assump; private: // Constructor. NOTE: it is private; only friend classes can call it. RegTheoremValue(TheoremManager* tm, const Expr& thm, const Assumptions& assump, const Proof& pf, bool isAssump, int scope = -1) : TheoremValue(tm, thm, pf, isAssump), d_assump(assump) { DebugAssert(d_tm->isActive(), "TheoremValue()"); if (isAssump) { DebugAssert(assump.empty(), "Expected empty assumptions"); // refcount tricks are because a loop is created with Assumptions d_refcount = 1; { Theorem t(this); d_assump.add1(t); } d_refcount = 0; if (scope == -1) d_scopeLevel = tm->getCM()->scopeLevel(); else d_scopeLevel = scope; // TRACE("quantlevel", d_quantLevel, " theorem init assump", thm.toString()); } else { if (!d_assump.empty()) { const Assumptions::iterator iend = d_assump.end(); for (Assumptions::iterator i = d_assump.begin(); i != iend; ++i) { if (i->getScope() > d_scopeLevel) d_scopeLevel = i->getScope(); if (i->getQuantLevel() > d_quantLevel){ d_quantLevel = i->getQuantLevel(); } } // TRACE("quantlevel", d_quantLevel, " theorem non-null assump", thm.toString()); } else{ TRACE("quantlevel","empty assumptions found ", thm , ""); } } //yeting, let me check d_quantleveldebug here // d_quantLevelDebug = findQuantLevelDebug(); } public: // Destructor ~RegTheoremValue() { if (d_isAssump) { IF_DEBUG(FatalAssert(d_assump.size() == 1, "Expected size 1");) IF_DEBUG(FatalAssert(d_assump.getFirst().thm() == this, "Expected loop");) d_assump.getFirst().d_thm = 0; } } const Assumptions& getAssumptionsRef() const { return d_assump; } // Memory management MemoryManager* getMM() { return d_tm->getMM(); } void* operator new(size_t size, MemoryManager* mm) { return mm->newData(size); } void operator delete(void* pMem, MemoryManager* mm) { mm->deleteData(pMem); } void operator delete(void* d) { } }; // end of class RegTheoremValue /////////////////////////////////////////////////////////////////////////////// // // // Class: RWTheoremValue // // Author: Clark Barrett // // Created: Fri May 2 12:51:55 2003 // // Description: A special subclass for theorems of the form A |- t=t' or // // A |- phi iff phi'. The actual Expr is only created on // // demand. The idea is that getLHS and getRHS should be used // // whenever possible, avoiding creating unnecessary Expr's. // // // /////////////////////////////////////////////////////////////////////////////// class RWTheoremValue :public TheoremValue { friend class Theorem; protected: // d_thm in the base class contains the full expression, which is // only constructed on demand. Expr d_lhs; Expr d_rhs; Assumptions* d_assump; private: void init(const Assumptions& assump, int scope) { DebugAssert(d_tm->isActive(), "TheoremValue()"); if (d_isAssump) { DebugAssert(assump.empty(), "Expected empty assumptions"); // refcount tricks are because a loop is created with Assumptions d_refcount = 1; { Theorem t(this); d_assump = new Assumptions(t); } d_refcount = 0; if (scope == -1) d_scopeLevel = d_tm->getCM()->scopeLevel(); else d_scopeLevel = scope; // TRACE("quantlevel", d_quantLevel, " RW theorem init is assump ", d_thm.toString()); } else { if (!assump.empty()) { d_assump = new Assumptions(assump); const Assumptions::iterator iend = assump.end(); for (Assumptions::iterator i = assump.begin(); i != iend; ++i) { if (i->getScope() > d_scopeLevel) d_scopeLevel = i->getScope(); if (i->getQuantLevel() > d_quantLevel){ d_quantLevel = i->getQuantLevel(); // TRACE("quantlevel", d_quantLevel, "=========\n RW theorem init has non-null assump ", this->toString()); } } // TRACE("quantlevel", d_quantLevel, " RW theorem init has non-null assump ", d_thm.toString()); } else{ TRACE("quantlevel", "RW empty assup found lhs << " , d_lhs, "" ); TRACE("quantlevel", "RW empty assup found rhs >> " , d_rhs, "" ); } // TRACE("quantlevel", d_quantLevel, " RW theorem init has null assump ", d_thm.toString()); } // d_quantLevelDebug = findQuantLevelDebug(); } // Constructor. NOTE: it is private; only friend classes can call it. RWTheoremValue(TheoremManager* tm, const Expr& lhs, const Expr& rhs, const Assumptions& assump, const Proof& pf, bool isAssump, int scope = -1) : TheoremValue(tm, Expr(), pf, isAssump), d_lhs(lhs), d_rhs(rhs), d_assump(NULL) { init(assump, scope); } // Sometimes we have the full expression already created RWTheoremValue(TheoremManager* tm, const Expr& thm, const Assumptions& assump, const Proof& pf, bool isAssump, int scope = -1) : TheoremValue(tm, thm, pf, isAssump), d_lhs(thm[0]), d_rhs(thm[1]), d_assump(NULL) { init(assump, scope); } const Expr& getExpr() const { if (d_thm.isNull()) { bool isBool = d_lhs.getType().isBool(); // have to fake out the const qualifier Expr* pexpr = const_cast(&d_thm); *pexpr = isBool ? d_lhs.iffExpr(d_rhs) : d_lhs.eqExpr(d_rhs); // TRACE("getExpr", "getExpr called on RWTheorem (", d_thm, ")"); } return d_thm; } const Expr& getLHS() const { return d_lhs; } const Expr& getRHS() const { return d_rhs; } public: // Destructor ~RWTheoremValue() { if (d_isAssump) { IF_DEBUG(FatalAssert(d_assump && d_assump->size() == 1, "Expected size 1");) IF_DEBUG(FatalAssert(d_assump->getFirst().thm() == this, "Expected loop");) d_assump->getFirst().d_thm = 0; } if (d_assump) delete d_assump; } bool isRewrite() const { return true; } const Assumptions& getAssumptionsRef() const { if (d_assump) return *d_assump; else return Assumptions::emptyAssump(); } // Memory management MemoryManager* getMM() { return d_tm->getRWMM(); } void* operator new(size_t size, MemoryManager* mm) { return mm->newData(size); } void operator delete(void* pMem, MemoryManager* mm) { mm->deleteData(pMem); } void operator delete(void* d) { } }; // end of class RWTheoremValue } // end of namespace CVC3 #endif cvc3-2.4.1/src/c_interface/0000775000175400017540000000000011630011320015272 5ustar mdetersmdeterscvc3-2.4.1/src/c_interface/Makefile0000664000175400017540000000041410533133647016753 0ustar mdetersmdeters################################################## # About this Makefile # # This Makefile depends on Makefile.opts ################################################## MODULE = c_interface SRC = c_interface.cpp LIBRARY=libc_interface.a include ../../Makefile.local cvc3-2.4.1/src/c_interface/c_interface.cpp0000664000175400017540000021561211517365165020276 0ustar mdetersmdeters/*****************************************************************************/ /*! * \file c_interface.cpp * * Authors: Clark Barrett * Cristian Cadar * * Created: Thu Jun 5 10:34:02 2003 * *
* * License to use, copy, modify, sell and/or distribute this software * and its documentation for any purpose is hereby granted without * royalty, subject to the terms and conditions defined in the \ref * LICENSE file provided with this distribution. * *
* */ /*****************************************************************************/ #include #include "c_interface_defs.h" #include "vc.h" #include "command_line_flags.h" #include "parser.h" #include "vc_cmd.h" #include "theory_bitvector.h" #include "fdstream.h" #include using namespace std; // ------------------------------------------------------------------------- // Debugging // ------------------------------------------------------------------------- // + will mean OK // - will mean error int c_interface_error_flag = 1; const int error_int = -100; const char* c_interface_error_message = "An Exception Occured: System in a compromised state."; string c_interface_error_string; // Used to return char* values. Note that the value is only good until // the next call to a function returning char* static string tmpString; void signal_error(const char* message,int flag_val,CVC3::Exception ex){ ostringstream ss; ss << c_interface_error_message << endl; ss << "Message: " << message << endl; ss << "Exception: " << ex << endl; IF_DEBUG(cerr << ss.str();) c_interface_error_string = ss.str(); c_interface_error_flag = flag_val; } extern "C" int vc_get_error_status(){ return c_interface_error_flag; } extern "C" void vc_reset_error_status(){ c_interface_error_flag = 1; c_interface_error_string = ""; } extern "C" char* vc_get_error_string() { return (char*) (c_interface_error_string.c_str()); } // Private to implementation class CInterface { public: static CVC3::Type fromType(Type t); static Type toType(const CVC3::Type& t); static CVC3::Expr fromExpr(Expr e); static Expr toExpr(const CVC3::Expr& e); static CVC3::Op fromOp(Op op); static Op toOp(VC vc, const CVC3::Op& op); // static CVC3::Proof fromProof(Proof proof); // static Proof toProof(const CVC3::Proof& proof); static void deleteExpr(Expr e); static void deleteVector(Expr* vec); }; CVC3::Type CInterface::fromType(Type t) { return CVC3::Type(fromExpr(t)); } Type CInterface::toType(const CVC3::Type& t) { return toExpr(t.getExpr()); } CVC3::Expr CInterface::fromExpr(Expr e) { return CVC3::Expr((CVC3::ExprValue*)e); } Expr CInterface::toExpr(const CVC3::Expr& e) { if (!e.d_expr) return NULL; e.d_expr->incRefcount(); return (Expr)e.d_expr; } CVC3::Op CInterface::fromOp(Op op) { CVC3::Expr e = fromExpr(op); if (e.isApply()) return e.getOp(); return CVC3::Op(e.getKind()); } Op CInterface::toOp(VC vc, const CVC3::Op& op) { if (op.isNull()) return NULL; CVC3::ValidityChecker* cvc = (CVC3::ValidityChecker*) vc; return (Op)(toExpr(cvc->getEM()->newLeafExpr(op))); } // CVC3::Proof CInterface::fromProof(Proof proof) // { // return CVC3::Proof(fromExpr(proof)); // } // Proof CInterface::toProof(const CVC3::Proof& proof) // { // return toExpr(proof.getExpr()); // } void CInterface::deleteExpr(Expr e) { if (e) ((CVC3::ExprValue*)e)->decRefcount(); } void CInterface::deleteVector(Expr* e) { if (e) delete [] e; } static CVC3::Type fromType(Type t) { return CInterface::fromType(t); } static Type toType(const CVC3::Type& t) { return CInterface::toType(t); } static CVC3::Expr fromExpr(Expr e) { return CInterface::fromExpr(e); } static Expr toExpr(const CVC3::Expr& e) { return CInterface::toExpr(e); } static CVC3::Op fromOp(Op op) { return CInterface::fromOp(op); } static Op toOp(VC vc, const CVC3::Op& op) { return CInterface::toOp(vc, op); } // static CVC3::Proof fromProof(Proof proof) { return CInterface::fromProof(proof); } // static Proof toProof(const CVC3::Proof& proof) { return CInterface::toProof(proof); } static char *val_to_binary_str(unsigned nbits, unsigned long val) { char s[65]; assert(nbits < sizeof s); strcpy(s, ""); while(nbits-- > 0) { if((val >> nbits) & 1) strcat(s, "1"); else strcat(s, "0"); } return strdup(s); } /////////////////////////////////////////////////////////////////////////// // Begin implementation of C interface // /////////////////////////////////////////////////////////////////////////// extern "C" VC vc_createValidityChecker(Flags flags) { try{ CVC3::CLFlags f = (flags==NULL)? CVC3::ValidityChecker::createFlags() : *((CVC3::CLFlags*)flags); return (VC)CVC3::ValidityChecker::create(f); } catch (CVC3::Exception ex){ signal_error("vc_createValidityChecker",error_int,ex); return NULL; } } extern "C" Flags vc_createFlags() { try{ return new CVC3::CLFlags(CVC3::ValidityChecker::createFlags()); } catch (CVC3::Exception ex){ signal_error("vc_createFlags",error_int,ex); return NULL; } } extern "C" void vc_destroyValidityChecker(VC vc) { try{ CVC3::ValidityChecker* cvc = (CVC3::ValidityChecker*) vc; delete cvc; } catch (CVC3::Exception ex){ signal_error("vc_destroyVelidityChecker",error_int,ex); } } extern "C" void vc_deleteFlags(Flags flags) { try{ delete ((CVC3::CLFlags*)flags); } catch (CVC3::Exception ex){ signal_error("vc_deleteFlags",error_int,ex); } } extern "C" void vc_deleteExpr(Expr e) { try{ CInterface::deleteExpr(e); } catch (CVC3::Exception ex){ signal_error("vc_deleteExpr",error_int,ex); } } extern "C" void vc_deleteType(Type t) { vc_deleteExpr(t); } extern "C" void vc_deleteOp(Op op) { vc_deleteExpr(op); } extern "C" void vc_deleteVector(Expr* e) { try{ CInterface::deleteVector(e); } catch (CVC3::Exception ex){ signal_error("vc_deleteVector",error_int,ex); } } extern "C" void vc_deleteTypeVector(Type* e) { vc_deleteVector(e); } extern "C" void vc_setBoolFlag(Flags flags, char* name, int val) { try{ CVC3::CLFlags& f = *((CVC3::CLFlags*)flags); f.setFlag(name, (val!=0)); } catch (CVC3::Exception ex){ signal_error("vc_setBoolFlag",error_int,ex); } } extern "C" void vc_setIntFlag(Flags flags, char* name, int val) { try{ CVC3::CLFlags& f = *((CVC3::CLFlags*)flags); f.setFlag(name, val); } catch (CVC3::Exception ex){ signal_error("vc_setIntFlag",error_int,ex); } } extern "C" void vc_setStringFlag(Flags flags, char* name, char* val) { try{ CVC3::CLFlags& f = *((CVC3::CLFlags*)flags); f.setFlag(name, string(val)); } catch (CVC3::Exception ex){ signal_error("vc_setStringFlag",error_int,ex); } } extern "C" void vc_setStrSeqFlag(Flags flags, char* name, char* str, int val) { try{ CVC3::CLFlags& f = *((CVC3::CLFlags*)flags); f.setFlag(name, pair(string(str), val!=0)); } catch (CVC3::Exception ex){ signal_error("vc_setStrSeqFlag",error_int,ex); } } extern "C" Type vc_boolType(VC vc) { try{ CVC3::ValidityChecker* cvc = (CVC3::ValidityChecker*) vc; return toType(cvc->boolType()); } catch (CVC3::Exception ex){ signal_error("vc_boolType",error_int,ex); return NULL; } } extern "C" Type vc_realType(VC vc) { try{ CVC3::ValidityChecker* cvc = (CVC3::ValidityChecker*) vc; return toType(cvc->realType()); }catch (CVC3::Exception ex){ signal_error("vc_realType",error_int,ex); return NULL; } } extern "C" Type vc_intType(VC vc) { try{ CVC3::ValidityChecker* cvc = (CVC3::ValidityChecker*) vc; return toType(cvc->intType()); }catch (CVC3::Exception ex){ signal_error("vc_intType",error_int,ex); return NULL; } } extern "C" Type vc_subRangeType(VC vc, int lowerEnd, int upperEnd) { try{ CVC3::ValidityChecker* cvc = (CVC3::ValidityChecker*) vc; return toType(cvc->subrangeType(cvc->ratExpr(lowerEnd), cvc->ratExpr(upperEnd))); }catch (CVC3::Exception &ex){ signal_error("vc_subRangeType",error_int,ex); return NULL; } } extern "C" Type vc_subtypeType(VC vc, Expr pred, Expr witness) { try{ CVC3::ValidityChecker* cvc = (CVC3::ValidityChecker*) vc; return toType(cvc->subtypeType(fromExpr(pred), fromExpr(witness))); }catch (CVC3::Exception &ex){ signal_error("vc_subtypeType",error_int,ex); return NULL; } } extern "C" Type vc_tupleType2(VC vc, Type type0, Type type1) { try{ CVC3::ValidityChecker* cvc = (CVC3::ValidityChecker*) vc; return toType(cvc->tupleType(fromType(type0), fromType(type1))); }catch (CVC3::Exception ex){ signal_error("vc_tupleType2",error_int,ex); return NULL; } } extern "C" Type vc_tupleType3(VC vc, Type type0, Type type1, Type type2) { try{ CVC3::ValidityChecker* cvc = (CVC3::ValidityChecker*) vc; return toType(cvc->tupleType(fromType(type0), fromType(type1), fromType(type2))); }catch (CVC3::Exception ex){ signal_error("vc_tupleType3",error_int,ex); return NULL; } } extern "C" Type vc_tupleTypeN(VC vc, Type* types, int numTypes) { try{ CVC3::ValidityChecker* cvc = (CVC3::ValidityChecker*) vc; vector cvcTypes; for (int i = 0; i < numTypes; ++i) { cvcTypes.push_back(fromType(types[i])); } return toType(cvc->tupleType(cvcTypes)); }catch(CVC3::Exception ex){ signal_error("vc_tupleTypeN",error_int,ex); return NULL; } } extern "C" Type vc_recordType1(VC vc, char* field, Type type) { try{ CVC3::ValidityChecker* cvc = (CVC3::ValidityChecker*) vc; return toType(cvc->recordType(field, fromType(type))); }catch(CVC3::Exception ex){ signal_error("vc_recordType1",error_int,ex); return NULL; } } extern "C" Type vc_recordType2(VC vc, char* field0, Type type0, char* field1, Type type1) { try{ CVC3::ValidityChecker* cvc = (CVC3::ValidityChecker*) vc; return toType(cvc->recordType(field0, fromType(type0), field1, fromType(type1))); }catch(CVC3::Exception ex){ signal_error("vc_recordType2",error_int,ex); return NULL; } } extern "C" Type vc_recordType3(VC vc, char* field0, Type type0, char* field1, Type type1, char* field2, Type type2) { try{ CVC3::ValidityChecker* cvc = (CVC3::ValidityChecker*) vc; return toType(cvc->recordType(field0, fromType(type0), field1, fromType(type1), field2, fromType(type2))); }catch(CVC3::Exception ex){ signal_error("vc_recordType3",error_int,ex); return NULL; } } extern "C" Type vc_recordTypeN(VC vc, char** fields, Type* types, int numFields) { try{ CVC3::ValidityChecker* cvc = (CVC3::ValidityChecker*) vc; vector cvcFields; vector cvcTypes; for (int i = 0; i < numFields; ++i) { cvcFields.push_back(fields[i]); cvcTypes.push_back(fromType(types[i])); } return toType(cvc->recordType(cvcFields, cvcTypes)); }catch(CVC3::Exception ex){ signal_error("vc_recordTypeN",error_int,ex); return NULL; } } extern "C" Type vc_dataType1(VC vc, char* name, char* constructor, int arity, char** selectors, Expr* types) { try{ CVC3::ValidityChecker* cvc = (CVC3::ValidityChecker*) vc; string cvcName(name); string cvcConstructor(constructor); vector cvcSelectors; vector cvcTypes; for (int i = 0; i < arity; ++i) { cvcSelectors.push_back(selectors[i]); cvcTypes.push_back(fromExpr(types[i])); } return toType(cvc->dataType(cvcName, cvcConstructor, cvcSelectors, cvcTypes)); }catch(CVC3::Exception ex){ signal_error("vc_dataType1",error_int,ex); return NULL; } } extern "C" Type vc_dataTypeN(VC vc, char* name, int numCons, char** constructors, int* arities, char*** selectors, Expr** types) { try{ CVC3::ValidityChecker* cvc = (CVC3::ValidityChecker*) vc; string cvcName(name); vector cvcConstructors; vector > cvcSelectors(numCons); vector > cvcTypes(numCons); for (int i = 0; i < numCons; ++i) { cvcConstructors.push_back(constructors[i]); for (int j = 0; j < arities[i]; ++j) { cvcSelectors[i].push_back(selectors[i][j]); cvcTypes[i].push_back(fromExpr(types[i][j])); } } return toType(cvc->dataType(cvcName, cvcConstructors, cvcSelectors, cvcTypes)); }catch(CVC3::Exception ex){ signal_error("vc_dataTypeN",error_int,ex); return NULL; } } extern "C" Type* vc_dataTypeMN(VC vc, int numTypes, char** names, int* numCons, char*** constructors, int** arities, char**** selectors, Expr*** types) { try{ CVC3::ValidityChecker* cvc = (CVC3::ValidityChecker*) vc; vector cvcNames; vector > cvcConstructors(numTypes); vector > > cvcSelectors(numTypes); vector > > cvcTypes(numTypes); int i; for (i = 0; i < numTypes; ++i) { cvcNames.push_back(names[i]); cvcSelectors[i].resize(numCons[i]); cvcTypes[i].resize(numCons[i]); for (int j = 0; i < numCons[i]; ++j) { cvcConstructors[i].push_back(constructors[i][j]); for (int k = 0; k < arities[i][j]; ++k) { cvcSelectors[i][j].push_back(selectors[i][j][k]); cvcTypes[i][j].push_back(fromExpr(types[i][j][k])); } } } vector cvcReturnTypes; cvc->dataType(cvcNames, cvcConstructors, cvcSelectors, cvcTypes, cvcReturnTypes); Type* returnTypes = new Type[numTypes]; for (i = 0; i < numTypes; ++i) { returnTypes[i] = toType(cvcReturnTypes[i]); } return returnTypes; }catch(CVC3::Exception ex){ signal_error("vc_dataTypeN",error_int,ex); return NULL; } } extern "C" Type vc_arrayType(VC vc, Type typeIndex, Type typeData) { try{ CVC3::ValidityChecker* cvc = (CVC3::ValidityChecker*) vc; return toType(cvc->arrayType(fromType(typeIndex), fromType(typeData))); }catch(CVC3::Exception ex){ signal_error("vc_arrayType",error_int,ex); return NULL; } } extern "C" Type vc_bvType(VC vc, int n) { try{ CVC3::ValidityChecker* cvc = (CVC3::ValidityChecker*) vc; return toType(cvc->bitvecType(n)); }catch (CVC3::Exception ex){ signal_error("vc_bvType",error_int,ex); return NULL; } } extern "C" Type vc_funType1(VC vc, Type typeDom, Type typeRan) { try{ CVC3::ValidityChecker* cvc = (CVC3::ValidityChecker*) vc; return toType(cvc->funType(fromType(typeDom), fromType(typeRan))); }catch(CVC3::Exception ex){ signal_error("vc_funType1",error_int,ex); return NULL; } } extern "C" Type vc_funType2(VC vc, Type a1, Type a2, Type typeRan) { try{ CVC3::ValidityChecker* cvc = (CVC3::ValidityChecker*) vc; vector args; args.push_back(fromType(a1)); args.push_back(fromType(a2)); return toType(cvc->funType(args, fromType(typeRan))); }catch(CVC3::Exception ex){ signal_error("vc_funType2",error_int,ex); return NULL; } } extern "C" Type vc_funType3(VC vc, Type a1, Type a2, Type a3, Type typeRan) { try { CVC3::ValidityChecker* cvc = (CVC3::ValidityChecker*) vc; vector args; args.push_back(fromType(a1)); args.push_back(fromType(a2)); args.push_back(fromType(a3)); return toType(cvc->funType(args, fromType(typeRan))); } catch(CVC3::Exception ex){ signal_error("vc_funType3",error_int,ex); return NULL; } } extern "C" Type vc_funTypeN(VC vc, Type* a, Type typeRan, int numArgs) { try{ CVC3::ValidityChecker* cvc = (CVC3::ValidityChecker*) vc; vector args; for(int i=0; ifunType(args, fromType(typeRan))); }catch(CVC3::Exception ex){ signal_error("vc_funTypeN",error_int,ex); return NULL; } } extern "C" Type vc_createType(VC vc, char* typeName) { try{ CVC3::ValidityChecker* cvc = (CVC3::ValidityChecker*) vc; return toType(cvc->createType(typeName)); }catch(CVC3::Exception ex){ signal_error("vc_createType",error_int,ex); return NULL; } } extern "C" Type vc_lookupType(VC vc, char* typeName) { try{ CVC3::ValidityChecker* cvc = (CVC3::ValidityChecker*) vc; return toType(cvc->lookupType(typeName)); }catch(CVC3::Exception ex){ signal_error("vc_lookupType",error_int,ex); return NULL; } } ///////////////////////////////////////////////////////////////////////////// // Expr manipulation methods // ///////////////////////////////////////////////////////////////////////////// extern "C" ExprManager vc_getEM(VC vc) { try{ CVC3::ValidityChecker* cvc = (CVC3::ValidityChecker*) vc; return (ExprManager)cvc->getEM(); }catch(CVC3::Exception ex){ signal_error("vc_getEM",error_int,ex); return NULL; } } extern "C" Expr vc_varExpr(VC vc, char* name, Type type) { try{ CVC3::ValidityChecker* cvc = (CVC3::ValidityChecker*) vc; return toExpr(cvc->varExpr(name, fromType(type))); }catch(CVC3::Exception ex){ signal_error("vc_varExpr",error_int,ex); return NULL; } } extern "C" Expr vc_varExprDef(VC vc, char* name, Type type, Expr def) { try{ CVC3::ValidityChecker* cvc = (CVC3::ValidityChecker*) vc; return toExpr(cvc->varExpr(name, fromType(type), fromExpr(def))); }catch(CVC3::Exception ex){ signal_error("vc_varExprDef",error_int,ex); return NULL; } } extern "C" Expr vc_lookupVar(VC vc, char* name, Type* type) { try{ CVC3::ValidityChecker* cvc = (CVC3::ValidityChecker*) vc; CVC3::Type t; Expr e = toExpr(cvc->lookupVar(name, &t)); *type = toType(t); return e; }catch(CVC3::Exception ex){ signal_error("vc_lookupVar",error_int,ex); return NULL; } } extern "C" Type vc_getType(VC vc, Expr e) { try{ CVC3::ValidityChecker* cvc = (CVC3::ValidityChecker*) vc; return toType(cvc->getType(fromExpr(e))); }catch(CVC3::Exception ex){ signal_error("vc_getType",error_int,ex); return NULL; } } extern "C" Type vc_getBaseType(VC vc, Expr e) { try{ CVC3::ValidityChecker* cvc = (CVC3::ValidityChecker*) vc; return toType(cvc->getBaseType(fromExpr(e))); }catch(CVC3::Exception ex){ signal_error("vc_getBaseType",error_int,ex); return NULL; } } extern "C" Type vc_getBaseTypeOfType(VC vc, Type t) { try{ CVC3::ValidityChecker* cvc = (CVC3::ValidityChecker*) vc; return toType(cvc->getBaseType(fromType(t))); }catch(CVC3::Exception ex){ signal_error("vc_getBaseTypeOfType",error_int,ex); return NULL; } } extern "C" Expr vc_getTypePred(VC vc, Type t, Expr e) { try{ CVC3::ValidityChecker* cvc = (CVC3::ValidityChecker*) vc; return toExpr(cvc->getTypePred(fromType(t), fromExpr(e))); }catch(CVC3::Exception ex){ signal_error("vc_getTypePred",error_int,ex); return NULL; } } extern "C" Expr vc_stringExpr(VC vc, char* str) { try{ CVC3::ValidityChecker* cvc = (CVC3::ValidityChecker*) vc; return toExpr(cvc->stringExpr(str)); }catch(CVC3::Exception ex){ signal_error("vc_stringExpr",error_int,ex); return NULL; } } extern "C" Expr vc_idExpr(VC vc, char* str) { try{ CVC3::ValidityChecker* cvc = (CVC3::ValidityChecker*) vc; return toExpr(cvc->idExpr(str)); }catch(CVC3::Exception ex){ signal_error("vc_idExpr",error_int,ex); return NULL; } } extern "C" Expr vc_listExpr(VC vc, int numKids, Expr* kids) { try{ CVC3::ValidityChecker* cvc = (CVC3::ValidityChecker*) vc; vector args; for(int i=0; ilistExpr(args)); }catch(CVC3::Exception ex){ signal_error("vc_listExpr",error_int,ex); return NULL; } } extern "C" void vc_printExpr(VC vc, Expr e) { try{ CVC3::ValidityChecker* cvc = (CVC3::ValidityChecker*) vc; cvc->printExpr(fromExpr(e)); }catch(CVC3::Exception ex){ signal_error("vc_printExpr",error_int,ex); } } extern "C" char* vc_printExprString(VC vc, Expr e) { try{ ostringstream os; string aa; char* result; CVC3::ValidityChecker* cvc = (CVC3::ValidityChecker*) vc; cvc->printExpr(fromExpr(e), os); os.flush(); aa=os.str(); result=new char[aa.length()+1]; strcpy(result,aa.c_str()); return result; } catch(CVC3::Exception ex) { signal_error("vc_printExprString",error_int,ex); return NULL; } } extern "C" void vc_deleteString(char* str) { if (str) delete [] str; } extern "C" void vc_printExprFile(VC vc, Expr e, int fd) { try { fdostream os(fd); if(!os) throw CVC3::Exception("vc_printExprFile: Bad file descriptor: " +CVC3::int2string(fd)); CVC3::ValidityChecker* cvc = (CVC3::ValidityChecker*) vc; cvc->printExpr(fromExpr(e), os); os.flush(); } catch(CVC3::Exception ex) { signal_error("vc_printExpr",error_int,ex); } } extern "C" Expr vc_importExpr(VC vc, Expr e) { try{ CVC3::ValidityChecker* cvc = (CVC3::ValidityChecker*) vc; return toExpr(cvc->importExpr(fromExpr(e))); }catch(CVC3::Exception ex){ signal_error("vc_importExpr",error_int,ex); return NULL; } } extern "C" Type vc_importType(VC vc, Type e) { try{ CVC3::ValidityChecker* cvc = (CVC3::ValidityChecker*) vc; return toType(cvc->importType(fromType(e))); }catch(CVC3::Exception ex){ signal_error("vc_importType",error_int,ex); return NULL; } } extern "C" Expr vc_eqExpr(VC vc, Expr child0, Expr child1) { try{ CVC3::ValidityChecker* cvc = (CVC3::ValidityChecker*) vc; return toExpr(cvc->eqExpr(fromExpr(child0), fromExpr(child1))); }catch(CVC3::Exception ex){ signal_error("vc_eqExpr",error_int,ex); return NULL; } } extern "C" Expr vc_distinctExpr(VC vc, Expr* children, int numChildren) { try{ CVC3::ValidityChecker* cvc = (CVC3::ValidityChecker*) vc; vector cvcExprs; for (int i = 0; i < numChildren; ++i) { cvcExprs.push_back(fromExpr(children[i])); } return toExpr(cvc->distinctExpr(cvcExprs)); }catch(CVC3::Exception ex){ signal_error("vc_distinctExpr",error_int,ex); return NULL; } } extern "C" Expr vc_trueExpr(VC vc) { try{ CVC3::ValidityChecker* cvc = (CVC3::ValidityChecker*) vc; return toExpr(cvc->trueExpr()); }catch(CVC3::Exception ex){ signal_error("vc_trueExpr",error_int,ex); return NULL; } } extern "C" Expr vc_falseExpr(VC vc) { try{ CVC3::ValidityChecker* cvc = (CVC3::ValidityChecker*) vc; return toExpr(cvc->falseExpr()); }catch(CVC3::Exception ex){ signal_error("vc_falseExpr",error_int,ex); return NULL; } } extern "C" Expr vc_notExpr(VC vc, Expr child) { try{ CVC3::ValidityChecker* cvc = (CVC3::ValidityChecker*) vc; return toExpr(cvc->notExpr(fromExpr(child))); }catch(CVC3::Exception ex){ signal_error("vc_notExpr",error_int,ex); return NULL; } } extern "C" Expr vc_andExpr(VC vc, Expr left, Expr right) { try{ CVC3::ValidityChecker* cvc = (CVC3::ValidityChecker*) vc; return toExpr(cvc->andExpr(fromExpr(left), fromExpr(right))); }catch(CVC3::Exception ex){ signal_error("vc_andExpr",error_int,ex); return NULL; } } extern "C" Expr vc_andExprN(VC vc, Expr* children, int numChildren) { try{ CVC3::ValidityChecker* cvc = (CVC3::ValidityChecker*) vc; vector cvcExprs; for (int i = 0; i < numChildren; ++i) { cvcExprs.push_back(fromExpr(children[i])); } return toExpr(cvc->andExpr(cvcExprs)); }catch(CVC3::Exception ex){ signal_error("vc_andExprN",error_int,ex); return NULL; } } extern "C" Expr vc_orExpr(VC vc, Expr left, Expr right) { try{ CVC3::ValidityChecker* cvc = (CVC3::ValidityChecker*) vc; return toExpr(cvc->orExpr(fromExpr(left), fromExpr(right))); }catch(CVC3::Exception ex){ signal_error("vc_orExpr",error_int,ex); return NULL; } } extern "C" Expr vc_orExprN(VC vc, Expr* children, int numChildren) { try{ CVC3::ValidityChecker* cvc = (CVC3::ValidityChecker*) vc; vector cvcExprs; for (int i = 0; i < numChildren; ++i) { cvcExprs.push_back(fromExpr(children[i])); } return toExpr(cvc->orExpr(cvcExprs)); }catch(CVC3::Exception ex){ signal_error("vc_orExprN",error_int,ex); return NULL; } } extern "C" Expr vc_impliesExpr(VC vc, Expr hyp, Expr conc) { try{ CVC3::ValidityChecker* cvc = (CVC3::ValidityChecker*) vc; return toExpr(cvc->impliesExpr(fromExpr(hyp), fromExpr(conc))); }catch(CVC3::Exception ex){ signal_error("vc_impliesExpr",error_int,ex); return NULL; } } extern "C" Expr vc_iffExpr(VC vc, Expr left, Expr right) { try{ CVC3::ValidityChecker* cvc = (CVC3::ValidityChecker*) vc; return toExpr(cvc->iffExpr(fromExpr(left), fromExpr(right))); }catch(CVC3::Exception ex){ signal_error("vc_iffExpr",error_int,ex); return NULL; } } extern "C" Expr vc_iteExpr(VC vc, Expr ifpart, Expr thenpart, Expr elsepart) { try{ CVC3::ValidityChecker* cvc = (CVC3::ValidityChecker*) vc; return toExpr(cvc->iteExpr(fromExpr(ifpart), fromExpr(thenpart), fromExpr(elsepart))); }catch(CVC3::Exception ex){ signal_error("vc_iteExpr",error_int,ex); return NULL; } } extern "C" Expr vc_substExpr(VC vc, Expr e, Expr* oldTerms, int numOldTerms, Expr* newTerms, int numNewTerms) { try{ vector oldExprs, newExprs; CVC3::Expr ex = fromExpr(e); //CVC3::ValidityChecker* cvc = (CVC3::ValidityChecker*) vc; for (int i = 0; i < numOldTerms; ++i) { oldExprs.push_back(fromExpr(oldTerms[i])); } for (int i = 0; i < numNewTerms; ++i) { newExprs.push_back(fromExpr(newTerms[i])); } return toExpr(ex.substExpr(oldExprs, newExprs)); }catch(CVC3::Exception ex){ signal_error("vc_substExpr",error_int,ex); return NULL; } } extern "C" Op vc_createOp(VC vc, char* name, Type type) { try{ CVC3::ValidityChecker* cvc = (CVC3::ValidityChecker*) vc; return toOp(vc, cvc->createOp(name, fromType(type))); }catch(CVC3::Exception ex){ signal_error("vc_createOp",error_int,ex); return NULL; } } extern "C" Op vc_createOpDef(VC vc, char* name, Type type, Expr def) { try{ CVC3::ValidityChecker* cvc = (CVC3::ValidityChecker*) vc; return toOp(vc, cvc->createOp(name, fromType(type), fromExpr(def))); }catch(CVC3::Exception ex){ signal_error("vc_createOpDef",error_int,ex); return NULL; } } extern "C" Op vc_lookupOp(VC vc, char* name, Type* type) { try{ CVC3::ValidityChecker* cvc = (CVC3::ValidityChecker*) vc; CVC3::Type t; Op op = toOp(vc, cvc->lookupOp(name, &t)); *type = toType(t); return op; } catch(CVC3::Exception ex){ signal_error("vc_lookupOp",error_int,ex); return NULL; } } extern "C" Expr vc_funExpr1(VC vc, Op op, Expr child) { try{ CVC3::ValidityChecker* cvc = (CVC3::ValidityChecker*) vc; return toExpr(cvc->funExpr(fromOp(op), fromExpr(child))); }catch(CVC3::Exception ex){ signal_error("vc_funExpr1",error_int,ex); return NULL; } } extern "C" Expr vc_funExpr2(VC vc, Op op, Expr left, Expr right) { try{ CVC3::ValidityChecker* cvc = (CVC3::ValidityChecker*) vc; return toExpr(cvc->funExpr(fromOp(op), fromExpr(left), fromExpr(right))); }catch(CVC3::Exception ex){ signal_error("vc_funExpr2",error_int,ex); return NULL; } } extern "C" Expr vc_funExpr3(VC vc, Op op, Expr child0, Expr child1, Expr child2) { try{ CVC3::ValidityChecker* cvc = (CVC3::ValidityChecker*) vc; return toExpr(cvc->funExpr(fromOp(op), fromExpr(child0), fromExpr(child1), fromExpr(child2))); }catch(CVC3::Exception ex){ signal_error("vc_funExpr3",error_int,ex); return NULL; } } extern "C" Expr vc_funExprN(VC vc, Op op, Expr* children, int numChildren) { try{ CVC3::ValidityChecker* cvc = (CVC3::ValidityChecker*) vc; vector cvcExprs; for (int i = 0; i < numChildren; ++i) { cvcExprs.push_back(fromExpr(children[i])); } return toExpr(cvc->funExpr(fromOp(op), cvcExprs)); }catch(CVC3::Exception ex){ signal_error("vc_funExprN",error_int,ex); return NULL; } } extern "C" Expr vc_ratExpr(VC vc, int n, int d) { try{ CVC3::ValidityChecker* cvc = (CVC3::ValidityChecker*) vc; return toExpr(cvc->ratExpr(n, d)); }catch(CVC3::Exception ex){ signal_error("vc_ratExpr",error_int,ex); return NULL; } } extern "C" Expr vc_ratExprFromStr(VC vc, char* n, char* d, int base) { try{ CVC3::ValidityChecker* cvc = (CVC3::ValidityChecker*) vc; return toExpr(cvc->ratExpr(n, d, base)); }catch(CVC3::Exception ex){ signal_error("vc_ratExprFromStr",error_int,ex); return NULL; } } extern "C" Expr vc_ratExprFromStr1(VC vc, char* n, int base) { try{ CVC3::ValidityChecker* cvc = (CVC3::ValidityChecker*) vc; return toExpr(cvc->ratExpr(n, base)); }catch(CVC3::Exception ex){ signal_error("vc_ratExprFromStr1",error_int,ex); return NULL; } } extern "C" Expr vc_uminusExpr(VC vc, Expr child) { try{ CVC3::ValidityChecker* cvc = (CVC3::ValidityChecker*) vc; return toExpr(cvc->uminusExpr(fromExpr(child))); }catch(CVC3::Exception ex){ signal_error("vc_uminusExpr",error_int,ex); return NULL; } } extern "C" Expr vc_plusExpr(VC vc, Expr left, Expr right) { try{ CVC3::ValidityChecker* cvc = (CVC3::ValidityChecker*) vc; return toExpr(cvc->plusExpr(fromExpr(left), fromExpr(right))); }catch(CVC3::Exception ex){ signal_error("vc_plusExpr",error_int,ex); return NULL; } } extern "C" Expr vc_plusExprN(VC vc, Expr* children, int numChildren) { try{ CVC3::ValidityChecker* cvc = (CVC3::ValidityChecker*) vc; vector cvcExprs; for (int i = 0; i < numChildren; ++i) { cvcExprs.push_back(fromExpr(children[i])); } return toExpr(cvc->plusExpr(cvcExprs)); }catch(CVC3::Exception ex){ signal_error("vc_plusExprN",error_int,ex); return NULL; } } extern "C" Expr vc_minusExpr(VC vc, Expr left, Expr right) { try{ CVC3::ValidityChecker* cvc = (CVC3::ValidityChecker*) vc; return toExpr(cvc->minusExpr(fromExpr(left), fromExpr(right))); }catch(CVC3::Exception ex){ signal_error("vc_minusExpr",error_int,ex); return NULL; } } extern "C" Expr vc_multExpr(VC vc, Expr left, Expr right) { try{ CVC3::ValidityChecker* cvc = (CVC3::ValidityChecker*) vc; return toExpr(cvc->multExpr(fromExpr(left), fromExpr(right))); }catch(CVC3::Exception ex){ signal_error("vc_multExpr",error_int,ex); return NULL; } } extern "C" Expr vc_powExpr(VC vc, Expr pow, Expr base) { try{ CVC3::ValidityChecker* cvc = (CVC3::ValidityChecker*) vc; return toExpr(cvc->powExpr(fromExpr(pow), fromExpr(base))); }catch(CVC3::Exception ex){ signal_error("vc_powExpr",error_int,ex); return NULL; } } extern "C" Expr vc_divideExpr(VC vc, Expr numerator, Expr denominator) { try{ CVC3::ValidityChecker* cvc = (CVC3::ValidityChecker*) vc; return toExpr(cvc->divideExpr(fromExpr(numerator), fromExpr(denominator))); }catch(CVC3::Exception ex){ signal_error("vc_divideExpr",error_int,ex); return NULL; } } extern "C" Expr vc_ltExpr(VC vc, Expr left, Expr right) { try{ CVC3::ValidityChecker* cvc = (CVC3::ValidityChecker*) vc; return toExpr(cvc->ltExpr(fromExpr(left), fromExpr(right))); }catch(CVC3::Exception ex){ signal_error("vc_ltExpr",error_int,ex); return NULL; } } extern "C" Expr vc_leExpr(VC vc, Expr left, Expr right) { try{ CVC3::ValidityChecker* cvc = (CVC3::ValidityChecker*) vc; return toExpr(cvc->leExpr(fromExpr(left), fromExpr(right))); }catch(CVC3::Exception ex){ signal_error("vc_leExpr",error_int,ex); return NULL; } } extern "C" Expr vc_gtExpr(VC vc, Expr left, Expr right) { try{ CVC3::ValidityChecker* cvc = (CVC3::ValidityChecker*) vc; return toExpr(cvc->gtExpr(fromExpr(left), fromExpr(right))); }catch(CVC3::Exception ex){ signal_error("vc_gtExpr",error_int,ex); return NULL; } } extern "C" Expr vc_geExpr(VC vc, Expr left, Expr right) { try{ CVC3::ValidityChecker* cvc = (CVC3::ValidityChecker*) vc; return toExpr(cvc->geExpr(fromExpr(left), fromExpr(right))); }catch(CVC3::Exception ex){ signal_error("vc_geExpr",error_int,ex); return NULL; } } extern "C" Expr vc_recordExpr1(VC vc, char* field, Expr expr) { try{ CVC3::ValidityChecker* cvc = (CVC3::ValidityChecker*) vc; return toExpr(cvc->recordExpr(field, fromExpr(expr))); }catch(CVC3::Exception ex){ signal_error("vc_recordExpr1",error_int,ex); return NULL; } } extern "C" Expr vc_recordExpr2(VC vc, char* field0, Expr expr0, char* field1, Expr expr1) { try{ CVC3::ValidityChecker* cvc = (CVC3::ValidityChecker*) vc; return toExpr(cvc->recordExpr(field0, fromExpr(expr0), field1, fromExpr(expr1))); }catch(CVC3::Exception ex){ signal_error("vc_recordExpr2",error_int,ex); return NULL; } } extern "C" Expr vc_recordExpr3(VC vc, char* field0, Expr expr0, char* field1, Expr expr1, char* field2, Expr expr2) { try{ CVC3::ValidityChecker* cvc = (CVC3::ValidityChecker*) vc; return toExpr(cvc->recordExpr(field0, fromExpr(expr0), field1, fromExpr(expr1), field2, fromExpr(expr2))); }catch(CVC3::Exception ex){ signal_error("vc_recordExpr3",error_int,ex); return NULL; } } extern "C" Expr vc_recordExprN(VC vc, char** fields, Expr* exprs, int numFields) { try{ CVC3::ValidityChecker* cvc = (CVC3::ValidityChecker*) vc; vector cvcFields; vector cvcExprs; for (int i = 0; i < numFields; ++i) { cvcFields.push_back(fields[i]); cvcExprs.push_back(fromExpr(exprs[i])); } return toExpr(cvc->recordExpr(cvcFields, cvcExprs)); }catch(CVC3::Exception ex){ signal_error("vc_recordExprN",error_int,ex); return NULL; } } extern "C" Expr vc_recSelectExpr(VC vc, Expr record, char* field) { try{ CVC3::ValidityChecker* cvc = (CVC3::ValidityChecker*) vc; return toExpr(cvc->recSelectExpr(fromExpr(record), field)); }catch(CVC3::Exception ex){ signal_error("vc_recSelectExpr",error_int,ex); return NULL; } } extern "C" Expr vc_recUpdateExpr(VC vc, Expr record, char* field, Expr newValue) { try{ CVC3::ValidityChecker* cvc = (CVC3::ValidityChecker*) vc; return toExpr(cvc->recUpdateExpr(fromExpr(record), field, fromExpr(newValue))); }catch(CVC3::Exception ex){ signal_error("vc_recUpdateExpr",error_int,ex); return NULL; } } extern "C" Expr vc_readExpr(VC vc, Expr array, Expr index) { try{ CVC3::ValidityChecker* cvc = (CVC3::ValidityChecker*) vc; return toExpr(cvc->readExpr(fromExpr(array), fromExpr(index))); }catch(CVC3::Exception ex){ signal_error("vc_readExpr",error_int,ex); return NULL; } } extern "C" Expr vc_writeExpr(VC vc, Expr array, Expr index, Expr newValue) { try{ CVC3::ValidityChecker* cvc = (CVC3::ValidityChecker*) vc; return toExpr(cvc->writeExpr(fromExpr(array), fromExpr(index), fromExpr(newValue))); }catch(CVC3::Exception ex){ signal_error("vc_writeExpr",error_int,ex); return NULL; } } extern "C" Type vc_bv32Type(VC vc) { return vc_bvType(vc, 32); } extern "C" Expr vc_bvConstExprFromStr(VC vc, char* binary_repr) { try{ CVC3::ValidityChecker* cvc = (CVC3::ValidityChecker*) vc; return toExpr(cvc->parseExpr(cvc->listExpr("_BVCONST", cvc->stringExpr(binary_repr)))); }catch(CVC3::Exception ex){ signal_error("vc_bvConstExpr",error_int, ex); return NULL; } } extern "C" Expr vc_bvConstExprFromInt(VC vc, int n_bits, unsigned int value) { char* s = val_to_binary_str(n_bits, value); return vc_bvConstExprFromStr(vc, s); } extern "C" Expr vc_bv32ConstExprFromInt(VC vc, unsigned int value) { return vc_bvConstExprFromInt(vc, 32, value); } extern "C" Expr vc_bvConstExprFromLL(VC vc, int n_bits, unsigned long value) { char* s = val_to_binary_str(n_bits, value); return vc_bvConstExprFromStr(vc, s); } extern "C" Expr vc_bvConcatExpr(VC vc, Expr left, Expr right) { try{ CVC3::ValidityChecker* cvc = (CVC3::ValidityChecker*) vc; return toExpr(cvc->newConcatExpr(fromExpr(left), fromExpr(right))); }catch(CVC3::Exception &ex){ signal_error("vc_bvConcatExpr",error_int,ex); return NULL; } } extern "C" Expr vc_bvConcatExprN(VC vc, Expr* children, int numChildren) { try{ CVC3::ValidityChecker* cvc = (CVC3::ValidityChecker*) vc; vector cvcExprs; for (int i = 0; i < numChildren; ++i) { cvcExprs.push_back(fromExpr(children[i])); } return toExpr(cvc->newConcatExpr(cvcExprs)); }catch(CVC3::Exception &ex){ signal_error("vc_concatExprN",error_int,ex); return NULL; } } extern "C" Expr vc_bvExtract(VC vc, Expr child, int high_bit_no, int low_bit_no) { try{ CVC3::ValidityChecker* cvc = (CVC3::ValidityChecker*) vc; return toExpr(cvc->newBVExtractExpr(fromExpr(child), high_bit_no, low_bit_no)); }catch(CVC3::Exception ex){ signal_error("vc_bvExtract",error_int,ex); return NULL; } } extern "C" Expr vc_bvBoolExtract(VC vc, Expr child, int bit_no) { try{ CVC3::ValidityChecker* cvc = (CVC3::ValidityChecker*) vc; CVC3::Expr lExpr = cvc->listExpr("_BOOLEXTRACT", fromExpr(child), cvc->ratExpr(bit_no)); return toExpr(cvc->parseExpr(lExpr)); }catch(CVC3::Exception ex){ signal_error("vc_bvBoolExtract",error_int,ex); return NULL; } } extern "C" Expr vc_bvNotExpr(VC vc, Expr child) { try{ CVC3::ValidityChecker* cvc = (CVC3::ValidityChecker*) vc; return toExpr(cvc->newBVNegExpr(fromExpr(child))); }catch(CVC3::Exception ex){ signal_error("vc_bvNotExpr",error_int,ex); return NULL; } } extern "C" Expr vc_bvAndExpr(VC vc, Expr left, Expr right) { try{ CVC3::ValidityChecker* cvc = (CVC3::ValidityChecker*) vc; return toExpr(cvc->newBVAndExpr(fromExpr(left), fromExpr(right))); }catch(CVC3::Exception ex){ signal_error("vc_bvAndExpr",error_int,ex); return NULL; } } extern "C" Expr vc_bvOrExpr(VC vc, Expr left, Expr right) { try{ CVC3::ValidityChecker* cvc = (CVC3::ValidityChecker*) vc; return toExpr(cvc->newBVOrExpr(fromExpr(left), fromExpr(right))); }catch(CVC3::Exception ex){ signal_error("vc_bvOrExpr",error_int,ex); return NULL; } } extern "C" Expr vc_bvXorExpr(VC vc, Expr left, Expr right) { try{ CVC3::ValidityChecker* cvc = (CVC3::ValidityChecker*) vc; return toExpr(cvc->newBVXorExpr(fromExpr(left), fromExpr(right))); }catch(CVC3::Exception ex){ signal_error("vc_bvXorExpr",error_int,ex); return NULL; } } extern "C" Expr vc_bvLtExpr(VC vc, Expr left, Expr right) { try{ CVC3::ValidityChecker* cvc = (CVC3::ValidityChecker*) vc; return toExpr(cvc->newBVLTExpr(fromExpr(left), fromExpr(right))); }catch(CVC3::Exception ex){ signal_error("vc_bvLtExpr",error_int,ex); return NULL; } } extern "C" Expr vc_bvLeExpr(VC vc, Expr left, Expr right) { try{ CVC3::ValidityChecker* cvc = (CVC3::ValidityChecker*) vc; return toExpr(cvc->newBVLEExpr(fromExpr(left), fromExpr(right))); }catch(CVC3::Exception ex){ signal_error("vc_bvLeExpr",error_int,ex); return NULL; } } extern "C" Expr vc_bvGtExpr(VC vc, Expr left, Expr right) { try{ CVC3::ValidityChecker* cvc = (CVC3::ValidityChecker*) vc; CVC3::Expr lExpr = cvc->listExpr("_BVGT", fromExpr(left), fromExpr(right)); return toExpr(cvc->parseExpr(lExpr)); }catch(CVC3::Exception ex){ signal_error("vc_bvGtExpr",error_int,ex); return NULL; } } extern "C" Expr vc_bvGeExpr(VC vc, Expr left, Expr right) { try{ CVC3::ValidityChecker* cvc = (CVC3::ValidityChecker*) vc; CVC3::Expr lExpr = cvc->listExpr("_BVGE", fromExpr(left), fromExpr(right)); return toExpr(cvc->parseExpr(lExpr)); }catch(CVC3::Exception ex){ signal_error("vc_bvGeExpr",error_int,ex); return NULL; } } extern "C" Expr vc_bvSLtExpr(VC vc, Expr left, Expr right) { try{ CVC3::ValidityChecker* cvc = (CVC3::ValidityChecker*) vc; return toExpr(cvc->newBVSLTExpr(fromExpr(left), fromExpr(right))); }catch(CVC3::Exception ex){ signal_error("vc_bvSLtExpr",error_int,ex); return NULL; } } extern "C" Expr vc_bvSLeExpr(VC vc, Expr left, Expr right) { try{ CVC3::ValidityChecker* cvc = (CVC3::ValidityChecker*) vc; return toExpr(cvc->newBVSLEExpr(fromExpr(left), fromExpr(right))); }catch(CVC3::Exception ex){ signal_error("vc_bvSLeExpr",error_int,ex); return NULL; } } extern "C" Expr vc_bvSGtExpr(VC vc, Expr left, Expr right) { try{ CVC3::ValidityChecker* cvc = (CVC3::ValidityChecker*) vc; CVC3::Expr lExpr = cvc->listExpr("_BVSGT", fromExpr(left), fromExpr(right)); return toExpr(cvc->parseExpr(lExpr)); }catch(CVC3::Exception ex){ signal_error("vc_bvSGtExpr",error_int,ex); return NULL; } } extern "C" Expr vc_bvSGeExpr(VC vc, Expr left, Expr right) { try{ CVC3::ValidityChecker* cvc = (CVC3::ValidityChecker*) vc; CVC3::Expr lExpr = cvc->listExpr("_BVSGE", fromExpr(left), fromExpr(right)); return toExpr(cvc->parseExpr(lExpr)); }catch(CVC3::Exception ex){ signal_error("vc_bvSGeExpr",error_int,ex); return NULL; } } extern "C" Expr vc_bvSignExtend(VC vc, Expr child, int nbits) { try{ CVC3::ValidityChecker* cvc = (CVC3::ValidityChecker*) vc; return toExpr(cvc->newSXExpr(fromExpr(child), nbits)); }catch(CVC3::Exception ex){ signal_error("vc_bvSignExtend",error_int,ex); return NULL; } } extern "C" Expr vc_bvUMinusExpr(VC vc, Expr child) { try{ CVC3::ValidityChecker* cvc = (CVC3::ValidityChecker*) vc; return toExpr(cvc->newBVUminusExpr(fromExpr(child))); }catch(CVC3::Exception ex){ signal_error("vc_bvUMinusExpr",error_int,ex); return NULL; } } extern "C" Expr vc_bvPlusExpr(VC vc, int n_bits, Expr left, Expr right) { try{ CVC3::ValidityChecker* cvc = (CVC3::ValidityChecker*) vc; vector args; args.push_back(fromExpr(left)); args.push_back(fromExpr(right)); return toExpr(cvc->newBVPlusExpr(n_bits, args)); }catch(CVC3::Exception ex){ signal_error("vc_bvPlusExpr",error_int,ex); return NULL; } } extern "C" Expr vc_bv32PlusExpr(VC vc, Expr left, Expr right) { return vc_bvPlusExpr(vc, 32, left, right); } extern "C" Expr vc_bvMinusExpr(VC vc, int n_bits, Expr left, Expr right) { try{ CVC3::ValidityChecker* cvc = (CVC3::ValidityChecker*) vc; CVC3::Expr lExpr = cvc->listExpr("_BVSUB", cvc->ratExpr(n_bits), fromExpr(left), fromExpr(right)); return toExpr(cvc->parseExpr(lExpr)); }catch(CVC3::Exception ex){ signal_error("vc_bvMinusExpr",error_int,ex); return NULL; } } extern "C" Expr vc_bv32MinusExpr(VC vc, Expr left, Expr right) { return vc_bvMinusExpr(vc, 32, left, right); } extern "C" Expr vc_bvMultExpr(VC vc, int n_bits, Expr left, Expr right) { try{ CVC3::ValidityChecker* cvc = (CVC3::ValidityChecker*) vc; return toExpr(cvc->newBVMultExpr(n_bits, fromExpr(left), fromExpr(right))); }catch(CVC3::Exception ex){ signal_error("vc_bvMultExpr",error_int,ex); return NULL; } } extern "C" Expr vc_bv32MultExpr(VC vc, Expr left, Expr right) { return vc_bvMultExpr(vc, 32, left, right); } extern "C" Expr vc_bvLeftShiftExpr(VC vc, int sh_amt, Expr child) { try{ CVC3::ValidityChecker* cvc = (CVC3::ValidityChecker*) vc; return toExpr(cvc->newFixedLeftShiftExpr(fromExpr(child), sh_amt)); }catch(CVC3::Exception ex){ signal_error("vc_bvLeftShiftExpr",error_int,ex); return NULL; } } extern "C" Expr vc_bvRightShiftExpr(VC vc, int sh_amt, Expr child) { try{ CVC3::ValidityChecker* cvc = (CVC3::ValidityChecker*) vc; return toExpr(cvc->newFixedRightShiftExpr(fromExpr(child), sh_amt)); }catch(CVC3::Exception ex){ signal_error("vc_bvRightShiftExpr",error_int,ex); return NULL; } } extern "C" Expr vc_bvUDivExpr(VC vc, Expr left, Expr right) { try{ CVC3::ValidityChecker* cvc = (CVC3::ValidityChecker*) vc; return toExpr(cvc->newBVUDivExpr(fromExpr(left), fromExpr(right))); }catch(CVC3::Exception ex){ signal_error("vc_bvUDivExpr",error_int,ex); return NULL; } } extern "C" Expr vc_bvURemExpr(VC vc, Expr left, Expr right) { try{ CVC3::ValidityChecker* cvc = (CVC3::ValidityChecker*) vc; return toExpr(cvc->newBVURemExpr(fromExpr(left), fromExpr(right))); }catch(CVC3::Exception ex){ signal_error("vc_bvURemExpr",error_int,ex); return NULL; } } extern "C" Expr vc_bvSDivExpr(VC vc, Expr left, Expr right) { try{ CVC3::ValidityChecker* cvc = (CVC3::ValidityChecker*) vc; return toExpr(cvc->newBVSDivExpr(fromExpr(left), fromExpr(right))); }catch(CVC3::Exception ex){ signal_error("vc_bvSDivExpr",error_int,ex); return NULL; } } extern "C" Expr vc_bvSRemExpr(VC vc, Expr left, Expr right) { try{ CVC3::ValidityChecker* cvc = (CVC3::ValidityChecker*) vc; return toExpr(cvc->newBVSRemExpr(fromExpr(left), fromExpr(right))); }catch(CVC3::Exception ex){ signal_error("vc_bvSRemExpr",error_int,ex); return NULL; } } extern "C" Expr vc_bvSModExpr(VC vc, Expr left, Expr right) { try{ CVC3::ValidityChecker* cvc = (CVC3::ValidityChecker*) vc; return toExpr(cvc->newBVSModExpr(fromExpr(left), fromExpr(right))); }catch(CVC3::Exception ex){ signal_error("vc_bvSModExpr",error_int,ex); return NULL; } } /* Same as vc_bvLeftShift only that the answer in 32 bits long */ extern "C" Expr vc_bv32LeftShiftExpr(VC vc, int sh_amt, Expr child) { return vc_bvExtract(vc, vc_bvLeftShiftExpr(vc, sh_amt, child), 31, 0); } /* Same as vc_bvRightShift only that the answer in 32 bits long */ extern "C" Expr vc_bv32RightShiftExpr(VC vc, int sh_amt, Expr child) { return vc_bvExtract(vc, vc_bvRightShiftExpr(vc, sh_amt, child), 31, 0); } extern "C" Expr vc_bvVar32LeftShiftExpr(VC vc, Expr sh_amt, Expr child) { try{ Expr ifpart; Expr thenpart; Expr elsepart = vc_trueExpr(vc); Expr ite = vc_trueExpr(vc); for(int count=32; count >= 0; count--){ if(count != 32) { ifpart = vc_eqExpr(vc, sh_amt, vc_bvConstExprFromInt(vc, 32, count)); thenpart = vc_bvExtract(vc, vc_bvLeftShiftExpr(vc, count, child), 31, 0); ite = vc_iteExpr(vc,ifpart,thenpart,elsepart); elsepart = ite; } else { elsepart = vc_bvConstExprFromInt(vc,32, 0); } } return ite; }catch(CVC3::Exception ex){ signal_error("vc_bvVar32LeftShiftExpr",error_int,ex); return NULL; } } extern "C" Expr vc_bvVar32DivByPowOfTwoExpr(VC vc, Expr child, Expr rhs) { try{ Expr ifpart; Expr thenpart; Expr elsepart = vc_trueExpr(vc); Expr ite = vc_trueExpr(vc); for(int count=32; count >= 0; count--){ if(count != 32) { ifpart = vc_eqExpr(vc, rhs, vc_bvConstExprFromInt(vc, 32, 1 << count)); thenpart = vc_bvRightShiftExpr(vc, count, child); ite = vc_iteExpr(vc,ifpart,thenpart,elsepart); elsepart = ite; } else { elsepart = vc_bvConstExprFromInt(vc,32, 0); } } return ite; }catch(CVC3::Exception ex){ signal_error("vc_bvVar32DivByPowOfTwoExpr",error_int,ex); return NULL; } } extern "C" Expr vc_bvVar32RightShiftExpr(VC vc, Expr sh_amt, Expr child) { try{ Expr ifpart; Expr thenpart; Expr elsepart = vc_trueExpr(vc); Expr ite = vc_trueExpr(vc); for(int count=32; count >= 0; count--){ if(count != 32) { ifpart = vc_eqExpr(vc, sh_amt, vc_bvConstExprFromInt(vc, 32, count)); thenpart = vc_bvRightShiftExpr(vc, count, child); ite = vc_iteExpr(vc,ifpart,thenpart,elsepart); elsepart = ite; } else { elsepart = vc_bvConstExprFromInt(vc,32, 0); } } return ite; }catch(CVC3::Exception ex){ signal_error("vc_bvVar32LeftShiftExpr",error_int,ex); return NULL; } } /* C pointer support: C interface to support C memory arrays in CVC3 */ extern "C" Expr vc_bvCreateMemoryArray(VC vc, char * arrayName) { Type bv8 = vc_bvType(vc,8); Type bv32 = vc_bvType(vc,32); Type malloced_mem0 = vc_arrayType(vc,bv32,bv8); return vc_varExpr(vc, arrayName, malloced_mem0); } /*OLD VERSIONS C pointer theory functions. DO NOT DELETE */ // //Warning: Type checking needed to ensure that the function is run // //correctly is not being done. it is assumed that the function // //recieves inputs of the correct types // extern "C" Expr vc_bvReadMemoryArray(VC vc, // Expr array, // Expr byteIndex, int newBitsPerElem) { // DebugAssert(newBitsPerElem%8 == 0, // "new bits per element must be a multiple of 8\n"); // Expr numerator = vc_bvMultExpr(vc,32, // vc_bvConstExprFromInt(vc,32,newBitsPerElem), // byteIndex); // int numOfBytes = newBitsPerElem/8; // DebugAssert(numOfBytes > 0, // "numOfBytes must be greater than 0"); // if(numOfBytes == 1) // return vc_readExpr(vc,array,numerator); // else { // int count = 1; // Expr a = vc_readExpr(vc,array,numerator); // while(--numOfBytes > 0) { // Expr b = vc_readExpr(vc,array, // vc_bvPlusExpr(vc,32,numerator,vc_bvConstExprFromInt(vc,32,count))); // a = vc_bvConcatExpr(vc,a,b); // count++; // } // return a; // } // } // extern "C" Expr vc_bvWriteToMemoryArray(VC vc, // Expr array, Expr byteIndex, // Expr element, int newBitsPerElem) { // DebugAssert(newBitsPerElem%8 == 0, // "new bits per element must be a multiple of 8\n"); // Expr numerator = vc_bvMultExpr(vc,32, // vc_bvConstExprFromInt(vc,32,newBitsPerElem), // byteIndex); // int numOfBytes = newBitsPerElem/8; // DebugAssert(numOfBytes > 0, // "numOfBytes must be greater than 0"); // if(numOfBytes == 1) // return vc_writeExpr(vc,array,numerator, element); // else { // int count = 1; // int hi = newBitsPerElem - 1; // int low = newBitsPerElem - 8; // Expr c = vc_bvExtract(vc,element,hi,low); // Expr newarray = vc_writeExpr(vc,array,numerator,c); // while(--numOfBytes > 0) { // hi = low-1; // low = low-8; // c = vc_bvExtract(vc,element,hi,low); // newarray = vc_writeExpr(vc,newarray,numerator,c); // count++; // } // return newarray; // } // } extern "C" Expr vc_bvReadMemoryArray(VC vc, Expr array, Expr byteIndex, int numOfBytes) { DebugAssert(0 < numOfBytes, "number of Bytes must be greater than 0\n"); if(numOfBytes == 1) return vc_readExpr(vc,array,byteIndex); else { int count = 1; Expr a = vc_readExpr(vc,array,byteIndex); while(--numOfBytes > 0) { Expr b = vc_readExpr(vc,array, /*vc_simplify(vc, */ vc_bvPlusExpr(vc, 32, byteIndex, vc_bvConstExprFromInt(vc,32,count)))/*)*/; a = vc_bvConcatExpr(vc,b,a); count++; } return a; } } extern "C" Expr vc_bvWriteToMemoryArray(VC vc, Expr array, Expr byteIndex, Expr element, int numOfBytes) { DebugAssert(numOfBytes > 0, "numOfBytes must be greater than 0"); int newBitsPerElem = numOfBytes*8; if(numOfBytes == 1) return vc_writeExpr(vc, array, byteIndex, element); else { int count = 1; int hi = newBitsPerElem - 1; int low = newBitsPerElem - 8; int low_elem = 0; int hi_elem = low_elem + 7; Expr c = vc_bvExtract(vc, element, hi_elem, low_elem); Expr newarray = vc_writeExpr(vc, array, byteIndex, c); while(--numOfBytes > 0) { hi = low-1; low = low-8; low_elem = low_elem + 8; hi_elem = low_elem + 7; c = vc_bvExtract(vc, element, hi_elem, low_elem); newarray = vc_writeExpr(vc, newarray, vc_bvPlusExpr(vc, 32, byteIndex, vc_bvConstExprFromInt(vc,32,count)), c); count++; } return newarray; } } extern "C" Expr vc_tupleExprN(VC vc, Expr* children, int numChildren) { try{ CVC3::ValidityChecker* cvc = (CVC3::ValidityChecker*) vc; vector cvcExprs; for (int i = 0; i < numChildren; ++i) { cvcExprs.push_back(fromExpr(children[i])); } return toExpr(cvc->tupleExpr(cvcExprs)); }catch(CVC3::Exception ex){ signal_error("vc_tupleExprN",error_int,ex); return NULL; } } extern "C" Expr vc_tupleSelectExpr(VC vc, Expr tuple, int index) { try{ CVC3::ValidityChecker* cvc = (CVC3::ValidityChecker*) vc; return toExpr(cvc->tupleSelectExpr(fromExpr(tuple), index)); }catch(CVC3::Exception ex){ signal_error("vc_tupleSelectExpr",error_int,ex); return NULL; } } extern "C" Expr vc_tupleUpdateExpr(VC vc, Expr tuple, int index, Expr newValue) { try{ CVC3::ValidityChecker* cvc = (CVC3::ValidityChecker*) vc; return toExpr(cvc->tupleUpdateExpr(fromExpr(tuple), index, fromExpr(newValue))); }catch(CVC3::Exception ex){ signal_error("vc_tupleUpdateExpr",error_int,ex); return NULL; } } extern "C" Expr vc_datatypeConsExpr(VC vc, char* constructor, int numArgs, Expr* args) { try{ CVC3::ValidityChecker* cvc = (CVC3::ValidityChecker*) vc; vector cvcArgs; for (int i = 0; i < numArgs; ++i) { cvcArgs.push_back(fromExpr(args[i])); } return toExpr(cvc->datatypeConsExpr(constructor, cvcArgs)); }catch(CVC3::Exception ex){ signal_error("vc_datatypeConsExpr",error_int,ex); return NULL; } } extern "C" Expr vc_datatypeSelExpr(VC vc, char* selector, Expr arg) { try{ CVC3::ValidityChecker* cvc = (CVC3::ValidityChecker*) vc; return toExpr(cvc->datatypeSelExpr(selector, fromExpr(arg))); }catch(CVC3::Exception ex){ signal_error("vc_datatypeSelExpr",error_int,ex); return NULL; } } extern "C" Expr vc_datatypeTestExpr(VC vc, char* constructor, Expr arg) { try{ CVC3::ValidityChecker* cvc = (CVC3::ValidityChecker*) vc; return toExpr(cvc->datatypeTestExpr(constructor, fromExpr(arg))); }catch(CVC3::Exception ex){ signal_error("vc_datatypeTestExpr",error_int,ex); return NULL; } } extern "C" Expr vc_boundVarExpr(VC vc, char* name, char *uid, Type type) { try{ CVC3::ValidityChecker* cvc = (CVC3::ValidityChecker*) vc; return toExpr(cvc->boundVarExpr(name, uid, fromType(type))); }catch(CVC3::Exception ex){ signal_error("vc_getEM",error_int,ex); return NULL; } } extern "C" Type vc_forallExpr(VC vc, Expr* Bvars, int numBvars, Expr f) { try{ CVC3::ValidityChecker* cvc = (CVC3::ValidityChecker*) vc; vector cvcBvars; for (int i = 0; i < numBvars; ++i) { cvcBvars.push_back(fromExpr(Bvars[i])); } return toExpr(cvc->forallExpr(cvcBvars,fromExpr(f))); }catch(CVC3::Exception ex){ signal_error("vc_forallExpr",error_int,ex); return NULL; } } // triggers must be an array of listExpr // each listExpr represent a trigger // if a listExpr contains more than one Expr, then it is a multi-trigger extern "C" void vc_setTriggers(VC vc, Expr e, int numTrigs, Expr* triggers) { try{ CVC3::ValidityChecker* cvc = (CVC3::ValidityChecker*) vc; vector >cvcTriggers; for (int i = 0; i < numTrigs; ++i) { vector curTrig; CVC3::Expr trigExpr = fromExpr(triggers[i]); if(trigExpr.isRawList()){ for(int j = 0 ; j < trigExpr.arity(); j++){ curTrig.push_back(trigExpr[j]); } } else{ curTrig.push_back(trigExpr); } cvcTriggers.push_back(curTrig); } cvc->setTriggers(fromExpr(e), cvcTriggers); }catch(CVC3::Exception ex){ signal_error("vc_setTriggers",error_int,ex); } } extern "C" Expr vc_existsExpr(VC vc, Expr* Bvars, int numBvars, Expr f) { try{ CVC3::ValidityChecker* cvc = (CVC3::ValidityChecker*) vc; vector cvcBvars; for (int i = 0; i < numBvars; ++i) { cvcBvars.push_back(fromExpr(Bvars[i])); } return toExpr(cvc->existsExpr(cvcBvars,fromExpr(f))); }catch(CVC3::Exception ex){ signal_error("vc_existsExpr",error_int,ex); return NULL; } } extern "C" Op vc_lambdaExpr(VC vc, int numVars, Expr* vars, Expr body) { try{ CVC3::ValidityChecker* cvc = (CVC3::ValidityChecker*) vc; vector cvcVars; for (int i = 0; i < numVars; ++i) { cvcVars.push_back(fromExpr(vars[i])); } return toOp(vc, cvc->lambdaExpr(cvcVars, fromExpr(body))); }catch(CVC3::Exception ex){ signal_error("vc_lambdaExpr",error_int,ex); return NULL; } } ///////////////////////////////////////////////////////////////////////////// // Context-related methods // ///////////////////////////////////////////////////////////////////////////// extern "C" void vc_setResourceLimit(VC vc, unsigned limit) { try{ CVC3::ValidityChecker* cvc = (CVC3::ValidityChecker*) vc; cvc->setResourceLimit(limit); }catch(CVC3::Exception ex){ signal_error("vc_setResourceLimit",error_int,ex); } } extern "C" void vc_assertFormula(VC vc, Expr e) { try{ CVC3::ValidityChecker* cvc = (CVC3::ValidityChecker*) vc; cvc->assertFormula(fromExpr(e)); }catch(CVC3::Exception ex){ signal_error("vc_assertFormula",error_int,ex); } } extern "C" void vc_registerAtom(VC vc, Expr e) { try{ CVC3::ValidityChecker* cvc = (CVC3::ValidityChecker*) vc; cvc->registerAtom(fromExpr(e)); }catch(CVC3::Exception ex){ signal_error("vc_registerAtom",error_int,ex); } } extern "C" Expr vc_getImpliedLiteral(VC vc) { try { CVC3::ValidityChecker* cvc = (CVC3::ValidityChecker*) vc; return toExpr(cvc->getImpliedLiteral()); } catch(CVC3::Exception ex){ signal_error("vc_getImpliedLiteral",error_int,ex); return NULL; } } extern "C" Expr vc_simplify(VC vc, Expr e) { try{ CVC3::ValidityChecker* cvc = (CVC3::ValidityChecker*) vc; return toExpr(cvc->simplify(fromExpr(e))); }catch(CVC3::Exception ex){ signal_error("vc_simplify",error_int,ex); return NULL; } } extern "C" int vc_query(VC vc, Expr e) { try{ CVC3::ValidityChecker* cvc = (CVC3::ValidityChecker*) vc; return (int)cvc->query(fromExpr(e)); }catch(CVC3::Exception ex){ signal_error("vc_query",error_int,ex); return error_int; } } extern "C" int vc_checkContinue(VC vc) { try{ CVC3::ValidityChecker* cvc = (CVC3::ValidityChecker*) vc; return (int)cvc->checkContinue(); }catch(CVC3::Exception ex){ signal_error("vc_checkContinue",error_int,ex); return error_int; } } extern "C" int vc_restart(VC vc, Expr e) { try{ CVC3::ValidityChecker* cvc = (CVC3::ValidityChecker*) vc; return (int)cvc->restart(fromExpr(e)); }catch(CVC3::Exception ex){ signal_error("vc_restart",error_int,ex); return error_int; } } extern "C" void vc_returnFromCheck(VC vc) { try{ CVC3::ValidityChecker* cvc = (CVC3::ValidityChecker*) vc; cvc->returnFromCheck(); }catch(CVC3::Exception ex){ signal_error("vc_returnFromCheck",error_int,ex); } } extern "C" Expr* vc_getUserAssumptions(VC vc, int* size) { try{ CVC3::ValidityChecker* cvc = (CVC3::ValidityChecker*) vc; vector cvcAssumptions; cvc->getUserAssumptions(cvcAssumptions); Expr* assumptions = new Expr[cvcAssumptions.size()]; unsigned n = 0; for (; n < cvcAssumptions.size(); ++n) { assumptions[n] = toExpr(cvcAssumptions[n]); } *size = int(n); return assumptions; }catch(CVC3::Exception ex){ signal_error("vc_getUserAssumptions",error_int,ex); return NULL; } } extern "C" Expr* vc_getInternalAssumptions(VC vc, int* size) { try{ CVC3::ValidityChecker* cvc = (CVC3::ValidityChecker*) vc; vector cvcAssumptions; cvc->getInternalAssumptions(cvcAssumptions); Expr* assumptions = new Expr[cvcAssumptions.size()]; unsigned n = 0; for (; n < cvcAssumptions.size(); ++n) { assumptions[n] = toExpr(cvcAssumptions[n]); } *size = int(n); return assumptions; }catch(CVC3::Exception ex){ signal_error("vc_getInternalAssumptions",error_int,ex); return NULL; } } extern "C" Expr* vc_getAssumptions(VC vc, int* size) { try{ CVC3::ValidityChecker* cvc = (CVC3::ValidityChecker*) vc; vector cvcAssumptions; cvc->getAssumptions(cvcAssumptions); Expr* assumptions = new Expr[cvcAssumptions.size()]; unsigned n = 0; for (; n < cvcAssumptions.size(); ++n) { assumptions[n] = toExpr(cvcAssumptions[n]); } *size = int(n); return assumptions; }catch(CVC3::Exception ex){ signal_error("vc_getAssumptions",error_int,ex); return NULL; } } //yeting, this is for proof translation, extern "C" Expr vc_getProofAssumptions(VC vc) { try{ CVC3::ValidityChecker* cvc = (CVC3::ValidityChecker*) vc; vector cvcAssumptions; cvc->getUserAssumptions(cvcAssumptions); return toExpr(cvc->listExpr(cvcAssumptions)); }catch(CVC3::Exception ex){ signal_error("vc_getProofAssumptions",error_int,ex); return NULL; } } //yeting, this is for proof translation extern "C" Expr vc_getProofQuery(VC vc) { try{ CVC3::ValidityChecker* cvc = (CVC3::ValidityChecker*) vc; return toExpr(cvc->getProofQuery()); }catch(CVC3::Exception ex){ signal_error("vc_getProofQuery",error_int,ex); return NULL; } } extern "C" Expr* vc_getAssumptionsUsed(VC vc, int* size) { try{ CVC3::ValidityChecker* cvc = (CVC3::ValidityChecker*) vc; vector cvcAssumptions; cvc->getAssumptionsUsed(cvcAssumptions); Expr* assumptions = new Expr[cvcAssumptions.size()]; unsigned n = 0; for (; n < cvcAssumptions.size(); ++n) { assumptions[n] = toExpr(cvcAssumptions[n]); } *size = int(n); return assumptions; }catch(CVC3::Exception ex){ signal_error("vc_getAssumptionsUsed",error_int,ex); return NULL; } } extern "C" Expr* vc_getCounterExample(VC vc, int* size) { try{ CVC3::ValidityChecker* cvc = (CVC3::ValidityChecker*) vc; vector cvcAssumptions; cvc->getCounterExample(cvcAssumptions); Expr* assumptions = new Expr[cvcAssumptions.size()]; unsigned n = 0; for (; n < cvcAssumptions.size(); ++n) { assumptions[n] = toExpr(cvcAssumptions[n]); } *size = int(n); return assumptions; }catch(CVC3::Exception ex){ signal_error("vc_getCounterExample",error_int,ex); return NULL; } } extern "C" Expr* vc_getConcreteModel(VC vc, int* size) { try{ CVC3::ValidityChecker* cvc = (CVC3::ValidityChecker*) vc; CVC3::ExprMap assertions; cvc->getConcreteModel(assertions); Expr* locAssumptions = new Expr[assertions.size()]; int n = 0; CVC3::ExprMap::iterator it = assertions.begin(), end = assertions.end(); for (; it != end; it++) { locAssumptions[n] = toExpr(cvc->eqExpr(it->first, it->second)); n++; } *size = n; return locAssumptions; }catch(CVC3::Exception ex){ signal_error("vc_getConcreteModel",error_int,ex); return NULL; } } extern "C" int vc_inconsistent(VC vc, Expr** assumptions, int* size) { try{ CVC3::ValidityChecker* cvc = (CVC3::ValidityChecker*) vc; vector assertions; bool ret = cvc->inconsistent(assertions); Expr* locAssumptions = new Expr[assertions.size()]; for (unsigned i = 0; i < assertions.size(); ++i) { locAssumptions[i] = toExpr(assertions[i]); } *assumptions = locAssumptions; *size = assertions.size(); return (int)ret; }catch(CVC3::Exception ex){ signal_error("vc_inconsistent",error_int,ex); return 0; } } extern "C" char* vc_incomplete(VC vc) { try{ CVC3::ValidityChecker* cvc = (CVC3::ValidityChecker*) vc; vector reasons; bool ret = cvc->incomplete(reasons); if (!ret) return NULL; string allReasons = ""; for (unsigned i = 0; i < reasons.size(); ++i) { allReasons += '\n'; allReasons += reasons[i]; } char* retStr = new char[allReasons.length()+1]; allReasons.copy(retStr, allReasons.length()); retStr[allReasons.length()] = '\0'; return retStr; }catch(CVC3::Exception ex){ signal_error("vc_incomplete",error_int,ex); return NULL; } } extern "C" Expr vc_getProof(VC vc) { try{ CVC3::ValidityChecker* cvc = (CVC3::ValidityChecker*) vc; return toExpr(cvc->getProof().getExpr()); }catch(CVC3::Exception ex){ signal_error("vc_getProof",error_int,ex); return NULL; } } extern "C" Expr vc_getProofOfFile(VC vc, char* fileName){ try{ CVC3::ValidityChecker* cvc = (CVC3::ValidityChecker*) vc; CVC3::Parser* parser; parser = new CVC3::Parser(cvc, NULL, cvc->getEM()->getInputLang(), 0, string(fileName)); CVC3::VCCmd* cmd = new CVC3::VCCmd(cvc, parser); cmd->processCommands(); delete cmd; delete parser; return toExpr(cvc->getProof().getExpr()); } catch (CVC3::Exception ex){ signal_error("vc_getProofsOfFile",error_int,ex); return NULL; } } extern "C" Expr vc_getTCC(VC vc) { try{ CVC3::ValidityChecker* cvc = (CVC3::ValidityChecker*) vc; return toExpr(cvc->getTCC()); }catch(CVC3::Exception ex){ signal_error("vc_getTCC",error_int,ex); return NULL; } } extern "C" Expr* vc_getAssumptionsTCC(VC vc, int* size) { try{ CVC3::ValidityChecker* cvc = (CVC3::ValidityChecker*) vc; vector cvcAssumptions; cvc->getAssumptionsTCC(cvcAssumptions); Expr* assumptions = new Expr[cvcAssumptions.size()]; unsigned n = 0; for (; n < cvcAssumptions.size(); ++n) { assumptions[n] = toExpr(cvcAssumptions[n]); } *size = int(n); return assumptions; }catch(CVC3::Exception ex){ signal_error("vc_getAssumptionsTCC",error_int,ex); return NULL; } } extern "C" Expr vc_getProofTCC(VC vc) { try{ CVC3::ValidityChecker* cvc = (CVC3::ValidityChecker*) vc; return toExpr(cvc->getProofTCC().getExpr()); }catch(CVC3::Exception ex){ signal_error("vc_getProofTCC",error_int,ex); return NULL; } } extern "C" Expr vc_getClosure(VC vc) { try{ CVC3::ValidityChecker* cvc = (CVC3::ValidityChecker*) vc; return toExpr(cvc->getClosure()); }catch(CVC3::Exception ex){ signal_error("vc_getClosure",error_int,ex); return NULL; } } extern "C" Expr vc_getProofClosure(VC vc) { try{ CVC3::ValidityChecker* cvc = (CVC3::ValidityChecker*) vc; return toExpr(cvc->getProofClosure().getExpr()); }catch(CVC3::Exception ex){ signal_error("vc_getProofClosure",error_int,ex); return NULL; } } extern "C" int vc_stackLevel(VC vc) { try{ CVC3::ValidityChecker* cvc = (CVC3::ValidityChecker*) vc; return cvc->stackLevel(); }catch(CVC3::Exception ex){ signal_error("vc_stackLevel",error_int,ex); return 0; } } extern "C" void vc_push(VC vc) { try{ CVC3::ValidityChecker* cvc = (CVC3::ValidityChecker*) vc; cvc->push(); }catch(CVC3::Exception ex){ signal_error("vc_push",error_int,ex); } } extern "C" void vc_pop(VC vc) { try{ CVC3::ValidityChecker* cvc = (CVC3::ValidityChecker*) vc; cvc->pop(); }catch(CVC3::Exception ex){ signal_error("vc_pop",error_int,ex); } } extern "C" void vc_popto(VC vc, int stackLevel) { try{ CVC3::ValidityChecker* cvc = (CVC3::ValidityChecker*) vc; cvc->popto(stackLevel); }catch(CVC3::Exception ex){ signal_error("vc_popto",error_int,ex); } } extern "C" Context vc_getCurrentContext(VC vc) { CVC3::ValidityChecker* cvc = (CVC3::ValidityChecker*) vc; return (Context)cvc->getCurrentContext(); } // ------------------------------------------------------------------------- // Util // ------------------------------------------------------------------------- extern "C" int vc_compare_exprs(Expr e1,Expr e2){ try{ return (compare(fromExpr(e1),fromExpr(e2))); } catch (CVC3::Exception ex){ signal_error("vc_compare_exprs",error_int,ex); return error_int; } } extern "C" const char* vc_exprString(Expr e){ try{ tmpString =(fromExpr(e)).toString(); return tmpString.c_str(); } catch (CVC3::Exception ex){ signal_error("vc_exprString",error_int,ex); return "ERROR"; } } extern "C" const char* vc_typeString(Type t){ try{ tmpString = (fromExpr(t)).toString(); return tmpString.c_str(); } catch (CVC3::Exception ex){ signal_error("vc_typeString",error_int,ex); return "ERROR"; } } extern "C" bool vc_isClosure(Expr e){ try{ return (fromExpr(e)).isClosure(); } catch (CVC3::Exception ex){ signal_error("vc_isClosure",error_int,ex); return false; } } extern "C" bool vc_isQuantifier(Expr e){ try{ return (fromExpr(e)).isQuantifier(); } catch (CVC3::Exception ex){ signal_error("vc_isQuantifier",error_int,ex); return false; } } extern "C" bool vc_isLambda(Expr e){ try{ return (fromExpr(e)).isLambda(); } catch (CVC3::Exception ex){ signal_error("vc_isLambda",error_int,ex); return false; } } extern "C" bool vc_isVar(Expr e){ try{ return (fromExpr(e)).isVar(); } catch (CVC3::Exception ex){ signal_error("vc_isVar",error_int,ex); return false; } } extern "C" int vc_arity(Expr e){ try{ return (fromExpr(e)).arity(); } catch (CVC3::Exception ex){ signal_error("vc_arity",error_int,ex); return error_int; } } extern "C" int vc_getKind(Expr e){ try{ return (fromExpr(e)).getKind(); } catch (CVC3::Exception ex){ signal_error("vc_getKind",error_int,ex); return error_int; } } extern "C" Expr vc_getChild(Expr e, int i){ try{ return toExpr(((fromExpr(e))[i])); } catch (CVC3::Exception ex){ signal_error("vc_getChild",error_int,ex); return NULL; } } extern "C" int vc_getNumVars(Expr e){ try{ return (fromExpr(e)).getVars().size(); } catch (CVC3::Exception ex){ signal_error("vc_getNumVars",error_int,ex); return error_int; } } extern "C" Expr vc_getVar(Expr e, int i){ try{ int size = ((fromExpr(e)).getVars()).size(); if(i < size){ Expr expr = toExpr(((fromExpr(e)).getVars())[i]); return expr; } else { throw CVC3::Exception(); } } catch (CVC3::Exception ex){ signal_error("vc_getVar",error_int,ex); return NULL; } } extern "C" Expr vc_getBody(Expr e){ try{ return toExpr((fromExpr(e)).getBody()); } catch (CVC3::Exception ex){ signal_error("vc_getBody",error_int,ex); return NULL; } } extern "C" Expr vc_getExistential(Expr e){ try{ return toExpr((fromExpr(e)).getExistential()); } catch (CVC3::Exception ex){ signal_error("vc_getExistential",error_int,ex); return NULL; } } extern "C" Expr vc_getFun(VC vc, Expr e) { try{ return toExpr((fromExpr(e)).getOp().getExpr()); }catch(CVC3::Exception ex){ signal_error("vc_getFun",error_int,ex); return NULL; } } extern "C" Expr vc_toExpr(Type t){ try{ return toExpr(fromExpr(t)); } catch (CVC3::Exception ex){ signal_error("vc_toExpr",error_int,ex); return NULL; } } extern "C" const char* vc_getKindString(VC vc,int kind) { try{ CVC3::ValidityChecker* cvc = (CVC3::ValidityChecker*) vc; tmpString = (cvc->getEM())->getKindName(kind); return tmpString.c_str(); } catch (CVC3::Exception ex){ signal_error("vc_getKindString",error_int,ex); return NULL; } } extern "C" int vc_getKindInt(VC vc,char* kind_name) { try{ CVC3::ValidityChecker* cvc = (CVC3::ValidityChecker*) vc; return (cvc->getEM())->getKind(kind_name); } catch (CVC3::Exception ex){ signal_error("vc_getKindInt",error_int,ex); return error_int; } } extern "C" int vc_getInt(Expr e){ try{ return (fromExpr(e)).getRational().getInt(); } catch (CVC3::Exception ex){ signal_error("vc_getInt",error_int,ex); return error_int; } } extern "C" int vc_getBVInt(VC vc, Expr e){ try{ CVC3::ValidityChecker* cvc = (CVC3::ValidityChecker*) vc; return cvc->computeBVConst(fromExpr(e)).getInt(); } catch (CVC3::Exception ex){ signal_error("vc_getBVInt",error_int,ex); return 0; } } extern "C" unsigned int vc_getBVUnsigned(VC vc, Expr e){ try{ CVC3::ValidityChecker* cvc = (CVC3::ValidityChecker*) vc; return cvc->computeBVConst(fromExpr(e)).getUnsigned(); } catch (CVC3::Exception ex){ signal_error("vc_getBVUnsigned",error_int,ex); return 0; } } extern "C" void vc_print_statistics(VC vc) { try{ CVC3::ValidityChecker* cvc = (CVC3::ValidityChecker*) vc; cvc->printStatistics(); } catch (CVC3::Exception ex){ signal_error("vc_print_statistics",error_int,ex); } } cvc3-2.4.1/src/translator/0000775000175400017540000000000011630011320015221 5ustar mdetersmdeterscvc3-2.4.1/src/translator/Makefile0000664000175400017540000000041110533133655016676 0ustar mdetersmdeters################################################## # About this Makefile # # This Makefile depends on Makefile.opts ################################################## MODULE = translator SRC = translator.cpp LIBRARY=libtranslator.a include ../../Makefile.local cvc3-2.4.1/src/translator/translator.cpp0000644000175400017540000016363311624746724020162 0ustar mdetersmdeters/*****************************************************************************/ /*! * \file translator.cpp * \brief Description: Code for translation between languages * * Author: Clark Barrett * * Created: Sat Jun 25 18:06:52 2005 * *
* * License to use, copy, modify, sell and/or distribute this software * and its documentation for any purpose is hereby granted without * royalty, subject to the terms and conditions defined in the \ref * LICENSE file provided with this distribution. * *
* */ /*****************************************************************************/ #include #include "translator.h" #include "expr.h" #include "theory_core.h" #include "theory_uf.h" #include "theory_arith.h" #include "theory_bitvector.h" #include "theory_array.h" #include "theory_quant.h" #include "theory_records.h" #include "theory_simulate.h" #include "theory_datatype.h" #include "theory_datatype_lazy.h" #include "smtlib_exception.h" #include "command_line_flags.h" using namespace std; using namespace CVC3; string Translator::fileToSMTLIBIdentifier(const string& filename) { string tmpName; string::size_type pos = filename.rfind("/"); if (pos == string::npos) { tmpName = filename; } else { tmpName = filename.substr(pos+1); } char c = tmpName[0]; string res; if ((c < 'A' || c > 'Z') && (c < 'a' || c > 'z')) { res = "B_"; } for (unsigned i = 0; i < tmpName.length(); ++i) { c = tmpName[i]; if ((c < 'A' || c > 'Z') && (c < 'a' || c > 'z') && (c < '0' || c > '9') && (c != '.' && c != '_')) { c = '_'; } res += c; } return res; } Expr Translator::preprocessRec(const Expr& e, ExprMap& cache) { ExprMap::iterator i(cache.find(e)); if(i != cache.end()) { return (*i).second; } if (d_theoryCore->getFlags()["liftITE"].getBool() && e.isPropAtom() && e.containsTermITE()) { Theorem thm = d_theoryCore->getCommonRules()->liftOneITE(e); return preprocessRec(thm.getRHS(), cache); } if (e.isClosure()) { Expr newBody = preprocessRec(e.getBody(), cache); Expr e2(e); if (newBody != e.getBody()) { e2 = d_em->newClosureExpr(e.getKind(), e.getVars(), newBody); } d_theoryCore->theoryOf(e2)->setUsed(); cache[e] = e2; return e2; } Expr e2(e); vector children; bool diff = false; for(int k = 0; k < e.arity(); ++k) { // Recursively preprocess the kids Expr child = preprocessRec(e[k], cache); if (child != e[k]) diff = true; children.push_back(child); } if (diff) { e2 = Expr(e.getOp(), children); } Rational r; switch (e2.getKind()) { case RATIONAL_EXPR: if (d_convertToBV) { Rational r = e2.getRational(); if (!r.isInteger()) { FatalAssert(false, "Cannot convert non-integer constant to BV"); } Rational limit = pow(d_convertToBV-1, (Rational)2); if (r >= limit) { FatalAssert(false, "Cannot convert to BV: integer too big"); } else if (r < -limit) { FatalAssert(false, "Cannot convert to BV: integer too small"); } e2 = d_theoryBitvector->signed_newBVConstExpr(r, d_convertToBV); break; } case READ: if (!d_unknown && d_theoryCore->getFlags()["convert2array"].getBool()) { if (e2[1].getKind() != UCONST) break; map::iterator i = d_arrayConvertMap->find(e2[1].getName()); if (i == d_arrayConvertMap->end()) { (*d_arrayConvertMap)[e2[1].getName()] = *d_indexType; } else { if ((*i).second != (*d_indexType)) { d_unknown = true; } } } break; case WRITE: if (!d_unknown && d_theoryCore->getFlags()["convert2array"].getBool()) { map::iterator i; if (e2[1].getKind() == UCONST) { i = d_arrayConvertMap->find(e2[1].getName()); if (i == d_arrayConvertMap->end()) { (*d_arrayConvertMap)[e2[1].getName()] = *d_indexType; } else { if ((*i).second != (*d_indexType)) { d_unknown = true; break; } } } if (e2[2].getKind() != UCONST) break; i = d_arrayConvertMap->find(e2[2].getName()); if (i == d_arrayConvertMap->end()) { (*d_arrayConvertMap)[e2[2].getName()] = *d_elementType; } else { if ((*i).second != (*d_elementType)) { d_unknown = true; } } } break; case APPLY: // Expand lambda applications if (e2.getOpKind() == LAMBDA) { Expr lambda(e2.getOpExpr()); Expr body(lambda.getBody()); const vector& vars = lambda.getVars(); FatalAssert(vars.size() == (size_t)e2.arity(), "wrong number of arguments applied to lambda\n"); body = body.substExpr(vars, e2.getKids()); e2 = preprocessRec(body, cache); } break; case EQ: if (d_theoryArith->getBaseType(e2[0]) != d_theoryArith->realType()) break; if (d_theoryCore->getFlags()["convert2array"].getBool() && ((e2[0].getKind() == UCONST && d_arrayConvertMap->find(e2[0].getName()) == d_arrayConvertMap->end()) || (e2[1].getKind() == UCONST && d_arrayConvertMap->find(e2[1].getName()) == d_arrayConvertMap->end()))) { d_equalities.push_back(e2); } goto arith_rewrites; case UMINUS: if (d_convertToBV) { e2 = Expr(BVUMINUS, e2[0]); break; } if (d_theoryArith->isSyntacticRational(e2, r)) { e2 = preprocessRec(d_em->newRatExpr(r), cache); break; } goto arith_rewrites; case DIVIDE: if (d_convertToBV) { FatalAssert(false, "Conversion of DIVIDE to BV not implemented yet"); break; } if (d_theoryArith->isSyntacticRational(e2, r)) { e2 = preprocessRec(d_em->newRatExpr(r), cache); break; } else if (d_convertArith && e2[1].isRational()) { r = e2[1].getRational(); if (r != 0) { e2 = d_em->newRatExpr(1/r) * e2[0]; e2 = preprocessRec(e2, cache); break; } } goto arith_rewrites; case MINUS: if (d_convertToBV) { e2 = Expr(BVSUB, e2[0], e2[1]); break; } if (d_convertArith) { if (e2[0].isRational() && e2[1].isRational()) { e2 = d_em->newRatExpr(e2[0].getRational() - e2[1].getRational()); break; } } goto arith_rewrites; case PLUS: if (d_convertToBV) { e2 = Expr(Expr(BVPLUS, d_em->newRatExpr(d_convertToBV)).mkOp(), e2.getKids()); break; } if (d_convertArith) { // Flatten and combine constants vector terms; bool changed = false; int numConst = 0; r = 0; Expr::iterator i = e2.begin(), iend = e2.end(); for(; i!=iend; ++i) { if ((*i).getKind() == PLUS) { changed = true; Expr::iterator i2 = (*i).begin(), i2end = (*i).end(); for (; i2 != i2end; ++i2) { if ((*i2).isRational()) { r += (*i2).getRational(); numConst++; } else terms.push_back(*i2); } } else { if ((*i).isRational()) { r += (*i).getRational(); numConst++; if (numConst > 1) changed = true; } else terms.push_back(*i); } } if (terms.size() == 0) { e2 = preprocessRec(d_em->newRatExpr(r), cache); break; } else if (terms.size() == 1) { if (r == 0) { e2 = terms[0]; break; } else if (r < 0) { e2 = preprocessRec(Expr(MINUS, terms[0], d_em->newRatExpr(-r)), cache); break; } } if (changed) { if (r != 0) terms.push_back(d_em->newRatExpr(r)); e2 = preprocessRec(Expr(PLUS, terms), cache); break; } } goto arith_rewrites; case MULT: if (d_convertToBV) { e2 = Expr(Expr(BVMULT, d_em->newRatExpr(d_convertToBV)).mkOp(), e2.getKids()); break; } if (d_convertArith) { // Flatten and combine constants vector terms; bool changed = false; int numConst = 0; r = 1; Expr::iterator i = e2.begin(), iend = e2.end(); for(; i!=iend; ++i) { if ((*i).getKind() == MULT) { changed = true; Expr::iterator i2 = (*i).begin(), i2end = (*i).end(); for (; i2 != i2end; ++i2) { if ((*i2).isRational()) { r *= (*i2).getRational(); numConst++; } else terms.push_back(*i2); } } else { if ((*i).isRational()) { r *= (*i).getRational(); numConst++; if (numConst > 1) changed = true; } else terms.push_back(*i); } } if (r == 0) { e2 = preprocessRec(d_em->newRatExpr(0), cache); break; } else if (terms.size() == 0) { e2 = preprocessRec(d_em->newRatExpr(r), cache); break; } else if (terms.size() == 1) { if (r == 1) { e2 = terms[0]; break; } } if (changed) { if (r != 1) terms.push_back(d_em->newRatExpr(r)); e2 = preprocessRec(Expr(MULT, terms), cache); break; } } goto arith_rewrites; case POW: if (d_convertToBV) { FatalAssert(false, "Conversion of POW to BV not implemented"); break; } if (d_convertArith && e2[0].isRational()) { r = e2[0].getRational(); if (r.isInteger() && r.getNumerator() == 2) { e2 = preprocessRec(e2[1] * e2[1], cache); break; } } // fall through case LT: if (d_convertToBV) { e2 = Expr(BVSLT, e2[0], e2[1]); break; } case GT: if (d_convertToBV) { e2 = Expr(BVSLT, e2[1], e2[0]); break; } case LE: if (d_convertToBV) { e2 = Expr(BVSLE, e2[0], e2[1]); break; } case GE: if (d_convertToBV) { e2 = Expr(BVSLE, e2[1], e2[0]); break; } case INTDIV: case MOD: arith_rewrites: if (d_iteLiftArith) { diff = false; children.clear(); vector children2; Expr cond; for (int k = 0; k < e2.arity(); ++k) { if (e2[k].getKind() == ITE && !diff) { diff = true; cond = e2[k][0]; children.push_back(e2[k][1]); children2.push_back(e2[k][2]); } else { children.push_back(e2[k]); children2.push_back(e2[k]); } } if (diff) { Expr thenpart = Expr(e2.getOp(), children); Expr elsepart = Expr(e2.getOp(), children2); e2 = cond.iteExpr(thenpart, elsepart); e2 = preprocessRec(e2, cache); break; } } if (d_convertToDiff != "" && d_theoryArith->isAtomicArithFormula(e2)) { Expr e3 = d_theoryArith->rewriteToDiff(e2); if (e2 != e3) { DebugAssert(e3 == d_theoryArith->rewriteToDiff(e3), "Expected idempotent rewrite"); e2 = preprocessRec(e3, cache); } break; } break; default: if (d_convertToBV && isInt(e2.getType())) { FatalAssert(e2.isVar(), "Cannot convert non-variables yet"); e2 = d_theoryCore->newVar(e2.getName()+"_bv", d_theoryBitvector->newBitvectorType(d_convertToBV)); } break; } // Figure out language switch (e2.getKind()) { case RATIONAL_EXPR: r = e2.getRational(); if (r.isInteger()) { d_intConstUsed = true; } else { d_realUsed = true; } if (d_langUsed == NOT_USED) d_langUsed = TERMS_ONLY; break; case IS_INTEGER: d_realUsed = true; d_intUsed = true; break; case PLUS: { if (e2.arity() == 2) { int nonconst = 0, isconst = 0; Expr::iterator i = e2.begin(), iend = e2.end(); for(; i!=iend; ++i) { if ((*i).isRational()) { if ((*i).getRational() <= 0) { d_UFIDL_ok = false; break; } else ++isconst; } else ++nonconst; } if (nonconst > 1 || isconst > 1) d_UFIDL_ok = false; } else d_UFIDL_ok = false; if (d_langUsed == NOT_USED) d_langUsed = TERMS_ONLY; break; } case MINUS: if (!e2[1].isRational() || e2[1].getRational() <= 0) { d_UFIDL_ok = false; } if (d_langUsed == NOT_USED) d_langUsed = TERMS_ONLY; break; case UMINUS: d_UFIDL_ok = false; if (d_langUsed == NOT_USED) d_langUsed = TERMS_ONLY; break; case MULT: { d_UFIDL_ok = false; if (d_langUsed == NONLINEAR) break; d_langUsed = LINEAR; bool nonconst = false; for (int i=0; i!=e2.arity(); ++i) { if (e2[i].isRational()) continue; if (nonconst) { d_langUsed = NONLINEAR; break; } nonconst = true; } break; } case POW: case DIVIDE: d_unknown = true; break; case EQ: if (d_theoryArith->getBaseType(e2[0]) != d_theoryArith->realType() || (e2[0].getType() == d_theoryArith->intType() && d_theoryCore->getFlags()["convert2array"].getBool())) break; case LT: case GT: case LE: case GE: if (d_langUsed >= LINEAR) break; if (!d_theoryArith->isAtomicArithFormula(e2)) { d_langUsed = LINEAR; break; } if (e2[0].getKind() == MINUS && d_theoryArith->isLeaf(e2[0][0]) && d_theoryArith->isLeaf(e2[0][1]) && e2[1].isRational()) { d_langUsed = DIFF_ONLY; break; } if (d_theoryArith->isLeaf(e2[0]) && d_theoryArith->isLeaf(e2[1])) { d_langUsed = DIFF_ONLY; break; } d_langUsed = LINEAR; break; default: break; } switch (e2.getKind()) { case EQ: case NOT: break; case UCONST: if (e2.arity() == 0) break; default: d_theoryCore->theoryOf(e2)->setUsed(); } cache[e] = e2; return e2; } Expr Translator::preprocess(const Expr& e, ExprMap& cache) { Expr result; try { result = preprocessRec(e, cache); } catch (SmtlibException& ex) { cerr << "Error while processing the formula:\n" << e.toString() << endl; throw ex; } return result; } Expr Translator::preprocess2Rec(const Expr& e, ExprMap& cache, Type desiredType) { TRACE("smtlib2-linear", "preprocess2Rec: ", e, ""); ExprMap::iterator i(cache.find(e)); if(i != cache.end()) { if ((desiredType.isNull() && (*i).second.getType() != d_theoryArith->realType()) || (*i).second.getType() == desiredType) { return (*i).second; } } if (e.isClosure()) { Expr newBody = preprocess2Rec(e.getBody(), cache, Type()); Expr e2(e); if (newBody != e.getBody()) { e2 = d_em->newClosureExpr(e.getKind(), e.getVars(), newBody); } cache[e] = e2; return e2; } bool forceReal = false; if (desiredType == d_theoryArith->intType() && e.getType() != d_theoryArith->intType()) { d_unknown = true; // throw SmtlibException("Unable to separate int and real "+ // e.getType().getExpr().toString()+ // "\n\nwhile processing the term:\n"+ // e.toString(PRESENTATION_LANG)); } // Try to force type-compliance switch (e.getKind()) { case EQ: case LT: case GT: case LE: case GE: if (e[0].getType() != e[1].getType()) { if (e[0].getType() != d_theoryArith->intType() && e[1].getType() != d_theoryArith->intType()) { d_unknown = true; throw SmtlibException("Expected each side to be REAL or INT, but we got lhs: "+ e[0].getType().getExpr().toString()+" and rhs: "+ e[1].getType().getExpr().toString()+ "\n\nwhile processing the term:\n"+ e.toString()); } forceReal = true; break; case ITE: case UMINUS: case PLUS: case MINUS: case MULT: if (desiredType == d_theoryArith->realType()) forceReal = true; break; case DIVIDE: forceReal = true; break; default: break; } } Expr e2(e); vector children; bool diff = false; Type funType; if (e.isApply()) { funType = e.getOpExpr().getType(); if (funType.getExpr().getKind() == ANY_TYPE) funType = Type(); } else if (e.getKind() == WRITE) { // an array store is like a function ARRAY -> INDEX -> ELEMENT -> ARRAY vector kids; kids.push_back(e.getType()); kids.push_back(e.getType()[0]); kids.push_back(e.getType()[1]); funType = Type::funType(kids, e.getType()); } for(int k = 0; k < e.arity(); ++k) { Type t; if (forceReal && e[k].getType() == d_theoryArith->intType()) t = d_theoryArith->realType(); else if (!funType.isNull()) t = funType[k]; // Recursively preprocess the kids Expr child = preprocess2Rec(e[k], cache, t); if (child != e[k]) diff = true; children.push_back(child); } if (diff) { e2 = Expr(e.getOp(), children); } else if (e2.getKind() == RATIONAL_EXPR && d_realUsed && d_intUsed) { if (e2.getType() == d_theoryArith->realType() || (e2.getType() == d_theoryArith->intType() && desiredType == d_theoryArith->realType())) e2 = Expr(REAL_CONST, e2); } if (e2.getKind() == MULT) { // SMT-LIBv2 is strict about where * is permitted in linear logics if (d_langUsed > NOT_USED && d_langUsed <= LINEAR && d_em->getOutputLang() == SMTLIB_V2_LANG) { Expr e2save = e2; TRACE("smtlib2-linear", "SMT-LIBv2 linearizing: ", e2save, ""); FatalAssert(e2.arity() > 1, "Unary MULT not permitted here"); // combine constants to form a linear term Expr trm;// the singular, non-constant term in the MULT Rational constCoef = 1;// constant coefficient bool realConst = false; bool trmFirst = false; for(int i = 0; i < e2.arity(); ++i) { Expr x = e2[i]; if(x.getKind() == REAL_CONST) { x = x[0]; realConst = true; DebugAssert(x.isRational(), "unexpected REAL_CONST-wrapped kind"); } if(x.isRational()) { constCoef *= x.getRational(); } else { FatalAssert(trm.isNull(), "translating with LINEAR restriction, but found > 1 non-constant under MULT"); trm = x; trmFirst = (i == 0); } } // First, do no harm: if it was a binary MULT already in correct shape // for SMT-LIBv2 linear logics, use it. if( !( e2.arity() == 2 && !trm.isNull() && (trm.isApply() || trm.getKind() == READ || trm.isVar()) ) ) { // Otherwise, there are several cases, enumerated below. Expr coef = d_em->newRatExpr(constCoef); if(realConst) { // if any part of the coefficient was wrapped with REAL_CONST to // force printing as a real (e.g. "1.0"), then wrap the combined // coefficient coef = Expr(REAL_CONST, coef); } if(trm.isNull()) { // Case 1: entirely constant; the mult goes away TRACE("smtlib2-linear", "(1) constant", "", ""); e2 = coef; } else if(constCoef == 1) { // Case 2: unit coefficient; the mult goes away TRACE("smtlib2-linear", "(2) unit coefficient: ", trm, ""); e2 = trm; } else if(trm.getKind() == PLUS || trm.getKind() == MINUS) { // Case 3: have to distribute the MULT over PLUS/MINUS TRACE("smtlib2-linear", "(3) mult over plus/minus: ", trm, ""); vector kids; for(int i = 0; i < trm.arity(); ++i) { Expr trmi(MULT, coef, trm[i]); trmi = preprocess2Rec(trmi, cache, desiredType); kids.push_back(trmi); } e2 = Expr(trm.getKind(), kids); } else if(trm.getKind() == MULT) { // Case 4: have to distribute MULT over MULT TRACE("smtlib2-linear", "(4) mult over mult: ", trm, ""); vector kids; kids.push_back(coef); for(int i = 0; i < trm.arity(); ++i) { kids.push_back(trm[i]); } e2 = Expr(MULT, kids); e2 = preprocess2Rec(e2, cache, desiredType); } else if(trm.getKind() == ITE) { // Case 5: have to distribute MULT over ITE TRACE("smtlib2-linear", "(5) mult over ite: ", trm, ""); Expr thn = Expr(MULT, coef, trm[1]); Expr els = Expr(MULT, coef, trm[2]); thn = preprocess2Rec(thn, cache, desiredType); els = preprocess2Rec(els, cache, desiredType); e2 = Expr(ITE, trm[0], thn, els); } else { // Default case: TRACE("smtlib2-linear", "(*) coef, trm: ", coef, trm); // don't change order if not necessary (makes it easier to inspect the translation) if(trmFirst) { e2 = Expr(MULT, trm, coef); } else { e2 = Expr(MULT, coef, trm); } FatalAssert(trm.isVar(), string("translating with LINEAR restriction, but found malformed MULT over term that's not a free constant: ") + e2.toString()); } } else { TRACE("smtlib2-linear", "(x) no handling necessary: ", trm, ""); } TRACE("smtlib2-linear", "SMT-LIBv2 linearized: ", e2save, ""); TRACE("smtlib2-linear", " into: ", e2, ""); } } if (!desiredType.isNull() && e2.getType() != desiredType) { if(isInt(e2.getType()) && isReal(desiredType) && !d_intUsed) { // the implicit cast is ok here } else { d_unknown = true; throw SmtlibException("Type error: expected "+ desiredType.getExpr().toString()+ " but instead got "+ e2.getType().getExpr().toString()+ "\n\nwhile processing term:\n"+ e.toString()); } } cache[e] = e2; return e2; } Expr Translator::preprocess2(const Expr& e, ExprMap& cache) { Expr result; try { result = preprocess2Rec(e, cache, Type()); } catch (SmtlibException& ex) { cerr << "Error while processing the formula:\n" << e.toString() << endl; throw ex; } return result; } bool Translator::containsArray(const Expr& e) { if (e.getKind() == ARRAY) return true; Expr::iterator i = e.begin(), iend=e.end(); for(; i!=iend; ++i) if (containsArray(*i)) return true; return false; } Translator::Translator(ExprManager* em, const bool& translate, const bool& real2int, const bool& convertArith, const string& convertToDiff, bool iteLiftArith, const string& expResult, const string& category, bool convertArray, bool combineAssump, int convertToBV) : d_em(em), d_translate(translate), d_real2int(real2int), d_convertArith(convertArith), d_convertToDiff(convertToDiff), d_iteLiftArith(iteLiftArith), d_expResult(expResult), d_category(category), d_convertArray(convertArray), d_combineAssump(combineAssump), d_dump(false), d_dumpFileOpen(false), d_intIntArray(false), d_intRealArray(false), d_intIntRealArray(false), d_ax(false), d_unknown(false), d_realUsed(false), d_intUsed(false), d_intConstUsed(false), d_langUsed(NOT_USED), d_UFIDL_ok(true), d_arithUsed(false), d_zeroVar(NULL), d_convertToBV(convertToBV) { d_arrayConvertMap = new map; } Translator::~Translator() { delete d_arrayConvertMap; } bool Translator::start(const string& dumpFile) { if (d_translate && (d_em->getOutputLang() == SMTLIB_LANG)) { d_dump = true; if (dumpFile == "") { d_osdump = &cout; } else { d_osdumpFile.open(dumpFile.c_str()); if(!d_osdumpFile) throw Exception("cannot open a log file: "+dumpFile); else { d_dumpFileOpen = true; d_osdump = &d_osdumpFile; } } string tmpName; string::size_type pos = dumpFile.rfind("/"); if (pos == string::npos) { tmpName = "README"; } else { tmpName = dumpFile.substr(0,pos+1) + "README"; } d_tmpFile.open(tmpName.c_str()); *d_osdump << "(benchmark " << fileToSMTLIBIdentifier(dumpFile) << endl << " :source {" << endl; char c; if (d_tmpFile.is_open()) { d_tmpFile.get(c); while (!d_tmpFile.eof()) { if ( c == '{' || c == '}' ) { *d_osdump << '\\'; } *d_osdump << c; d_tmpFile.get(c); } } else { *d_osdump << "Source unknown"; } *d_osdump << endl; *d_osdump << "}" << endl; d_tmpFile.close(); } else if (d_translate && d_em->getOutputLang() == SPASS_LANG) { d_dump = true; if (dumpFile == "") { d_osdump = &cout; } else { d_osdumpFile.open(dumpFile.c_str()); if(!d_osdumpFile) throw Exception("cannot open a log file: "+dumpFile); else { d_dumpFileOpen = true; d_osdump = &d_osdumpFile; } } *d_osdump << "begin_problem(Unknown). " << endl; *d_osdump << endl; *d_osdump << "list_of_descriptions. " << endl; *d_osdump << "name({* " << fileToSMTLIBIdentifier(dumpFile) << " *}). " << endl; *d_osdump << "author({* CVC2SPASS translator *})." << endl; //end of SPASS } else { if (dumpFile == "") { if (d_translate) { d_osdump = &cout; d_dump = true; } } else { d_osdumpFile.open(dumpFile.c_str()); if(!d_osdumpFile) throw Exception("cannot open a log file: "+dumpFile); else { d_dump = true; d_dumpFileOpen = true; d_osdump = &d_osdumpFile; } } } return d_dump; } void Translator::dump(const Expr& e, bool dumpOnly) { DebugAssert(d_dump, "dump called unexpectedly"); if (!dumpOnly || !d_translate) { if (d_convertArray && e.getKind() == CONST && e.arity() == 2) { if (e[1].getKind() == ARRAY) { if (containsArray(e[1][0]) || containsArray(e[1][1])) { throw Exception("convertArray failed because of nested arrays in"+ e[1].toString()); } Expr funType = Expr(ARROW, e[1][0], e[1][1]); Expr outExpr = Expr(CONST, e[0], funType); d_dumpExprs.push_back(outExpr); } else if (containsArray(e[1])) { throw Exception("convertArray failed becauase of use of arrays in"+ e[1].toString()); } else { d_dumpExprs.push_back(e); } } else { d_dumpExprs.push_back(e); } } } bool Translator::dumpAssertion(const Expr& e) { Expr outExpr = Expr(ASSERT, e); d_dumpExprs.push_back(outExpr); return d_translate; } bool Translator::dumpQuery(const Expr& e) { Expr outExpr = Expr(QUERY, e); d_dumpExprs.push_back(outExpr); return d_translate; } void Translator::dumpQueryResult(QueryResult qres) { if( d_translate && d_em->getOutputLang() == SMTLIB_LANG ) { *d_osdump << " :status "; switch( qres ) { case UNSATISFIABLE: *d_osdump << "unsat" << endl; break; case SATISFIABLE: *d_osdump << "sat" << endl; break; default: *d_osdump << "unknown" << endl; break; } } else if( d_translate && d_em->getOutputLang() == SMTLIB_V2_LANG ) { *d_osdump << "(set-info :status "; switch( qres ) { case UNSATISFIABLE: *d_osdump << "unsat"; break; case SATISFIABLE: *d_osdump << "sat"; break; default: *d_osdump << "unknown"; break; } *d_osdump << ")" << endl; } else if( d_translate && d_em->getOutputLang() == SPASS_LANG ) { *d_osdump << "status("; switch( qres ) { case UNSATISFIABLE: *d_osdump << "unsatisfiable"; break; case SATISFIABLE: *d_osdump << "satisfiable"; break; default: *d_osdump << "unknown"; break; } *d_osdump << ")." << endl; } } /* Expr Translator::spassPreprocess(const Expr& e, ExprMap& mapping, vector& functions, vector& predicates) { if(e.getKind() == LET) { if(e.arity() != 2) { throw SmtlibException("Translator::spassPreprocess(): LET with arity != 2 not supported"); } char name[80]; snprintf(name, sizeof(name), "_cvc3_let%u", mapping.size()); Expr id(ID, d_em->newStringExpr(name)); cout << "ENCOUNTERED A LET:" << endl << id << endl; mapping.insert(e[0][0], e[0][1]); functions.push_back(Expr(CONST, id, e[1].getType().getExpr())); return spassPreprocess(e[1], mapping, functions, predicates); //} else if(e.getKind() == x) { } else if(e.arity() > 0) { vector args; for(int i = 0, iend = e.arity(); i < iend; ++i) { args.push_back(spassPreprocess(e[i], mapping, functions, predicates)); } Expr out(e.getOp(), args); return out; } return e; } */ Expr Translator::processType(const Expr& e) { switch (e.getKind()) { case TYPEDECL: return e; case INT: if (d_convertToBV) { return d_theoryBitvector->newBitvectorType(d_convertToBV).getExpr(); } if (d_theoryCore->getFlags()["convert2array"].getBool()) { return d_elementType->getExpr(); } d_intUsed = true; break; case REAL: if (d_real2int) { d_intUsed = true; return d_theoryArith->intType().getExpr(); } else { d_realUsed = true; } break; case SUBRANGE: d_unknown = true; break; case ARRAY: if (d_theoryCore->getFlags()["convert2array"].getBool()) { d_ax = true; return d_arrayType->getExpr(); } if (e[0].getKind() == TYPEDECL) { DebugAssert(e[0].arity() == 1, "expected arity 1"); if (e[0][0].getString() == "Index") { if (e[1].getKind() == TYPEDECL) { DebugAssert(e[1].arity() == 1, "expected arity 1"); if (e[1][0].getString() == "Element") { d_ax = true; break; } } } } else if (isInt(Type(e[0]))) { if (isInt(Type(e[1]))) { d_intIntArray = true; break; } else if (isReal(Type(e[1]))) { d_intRealArray = true; break; } else if (isArray(Type(e[1])) && isInt(Type(e[1][0])) && isReal(Type(e[1][1]))) { d_intIntRealArray = true; break; } } else if (e[0].getKind() == BITVECTOR && e[1].getKind() == BITVECTOR) { break; } d_unknown = true; break; default: break; } d_theoryCore->theoryOf(e)->setUsed(); if (e.arity() == 0) return e; bool changed = false; vector vec; for (int i = 0; i < e.arity(); ++i) { vec.push_back(processType(e[i])); if (vec.back() != e[i]) changed = true; } if (changed) return Expr(e.getOp(), vec); return e; } void Translator::finish() { bool qf_uf = false; if (d_translate) { if (d_em->getOutputLang() == SPASS_LANG) { *d_osdump << "status("; if (d_expResult == "invalid" || d_expResult == "satisfiable" || d_expResult == "sat") *d_osdump << "satisfiable"; else if (d_expResult == "valid" || d_expResult == "unsatisfiable" || d_expResult == "unsat") *d_osdump << "unsatisfiable"; else if (d_expResult != "") *d_osdump << "unknown"; else if (status() == "invalid" || status() == "satisfiable" || status() == "sat") *d_osdump << "satisfiable"; else if (status() == "valid" || status() == "unsatisfiable" || status() == "unsat") *d_osdump << "unsatisfiable"; else *d_osdump << "unknown"; *d_osdump << ")." << endl; *d_osdump << "description({* Unknown *})." << endl; *d_osdump << "end_of_list." << endl; vector functions, predicates, sorts; for(vector::reverse_iterator i = d_dumpExprs.rbegin(), iend = d_dumpExprs.rend(); i != iend; ++i) { Expr e = *i; switch(e.getKind()) { case TYPE: sorts.push_back(e); d_dumpExprs.erase(i.base() - 1); break; case CONST: if(e.arity() == 2) { if (e[1].getKind() == BOOLEAN || (e[1].getKind() == ARROW && e[1][e[1].arity()-1].getKind() == BOOLEAN)) { predicates.push_back(e); } else { functions.push_back(e); } d_dumpExprs.erase(i.base() - 1); } else { throw SmtlibException("Translator::finish: SPASS_LANG: CONST not implemented for arity != 2"); } break; case ANNOTATION: if (d_theoryCore->getFlags()["trans-skip-difficulty"].getBool() && e[0].getKind() == STRING_EXPR && e[0].getString() == "difficulty") { // do nothing; skip the difficulty annotation } else { *d_osdump << "%% "; *d_osdump << e[0]; if (e.arity() > 1) { *d_osdump << ": " << e[1]; } } d_dumpExprs.erase(i.base() - 1); break; /* case ASSERT: case QUERY: { ExprMap m; *i = Expr(e.getKind(), spassPreprocess(e[0], m, functions, predicates)); break; } */ default: //*d_osdump << "DOING NOTHING FOR: " << e << endl; break; } } // add some built-ins for the translation // only arity matters for SPASS; the real type of _cvc3_ite is Bool -> 'a -> 'a -> 'a //Expr cvc3ite(CONST, Expr(ID, d_em->newStringExpr("_cvc3_ite")), //Expr(ARROW, vector(4, d_theoryArith->intType().getExpr()))); // only arity matters for SPASS; the real type of _cvc3_xor is // Bool -> Bool -> Bool, but we can't represent Bool-arg'ed // functions /* Expr cvc3xor(CONST, Expr(ID, d_em->newStringExpr("_cvc3_xor")), Expr(ARROW, vector(2, d_theoryArith->intType().getExpr()))); //functions.push_back(cvc3ite); predicates.push_back(cvc3xor); */ *d_osdump << endl; *d_osdump << "list_of_symbols." << endl; if(!functions.empty()) { *d_osdump << "functions["; vector::reverse_iterator i = functions.rbegin(), iend = functions.rend(); while(i != iend) { Expr e = *i; string name = e[0][0].getString(); if(isReal(d_theoryCore->getBaseType(Type(e[1])))) { // SPASS guys want "np" prefix on arith vars name = "np" + name; } *d_osdump << "(" << name << "," << ( e[1].getKind() == ARROW ? e[1].arity()-1 : e[1].arity() ) << ")"; if(++i != iend) { *d_osdump << ","; } } *d_osdump << "]." << endl; } if(!predicates.empty()) { *d_osdump << "predicates["; vector::reverse_iterator i = predicates.rbegin(), iend = predicates.rend(); while(i != iend) { Expr e = *i; *d_osdump << "(" << e[0][0].getString() << "," << e[1].arity() << ")"; if(++i != iend) { *d_osdump << ","; } } *d_osdump << "]." << endl; } if(!sorts.empty()) { *d_osdump << "sorts["; vector::reverse_iterator i = sorts.rbegin(), iend = sorts.rend(); while(i != iend) { Expr e = *i; *d_osdump << e[0][0].getString(); if(++i != iend) { *d_osdump << ","; } } *d_osdump << "]." << endl; } *d_osdump << "end_of_list." << endl; /* *d_osdump << endl; *d_osdump << "list_of_declarations." << endl; *d_osdump << "end_of_list." << endl; */ // define an ITE operator for the translation /* *d_osdump << endl; *d_osdump << "list_of_formulae(axioms)." << endl; *d_osdump << "formula( forall([A,B],equiv(_cvc3_xor(A,B),not(equal(A,B)))) )." << endl; // *d_osdump << "formula(forall([A,B],equal(_cvc3_ite(\ntrue\n,A,B),A)))." << endl; // *d_osdump << "formula(forall([A,B],equal(_cvc3_ite(\nfalse\n,A,B),B)))." << endl; *d_osdump << "end_of_list." << endl; */ *d_osdump << endl; *d_osdump << "list_of_formulae(conjectures)." << endl; } if (d_em->getOutputLang() == SMTLIB_LANG) { // Print the rest of the preamble for smt-lib benchmarks // Get status from expResult flag *d_osdump << " :status "; if (d_expResult == "invalid" || d_expResult == "satisfiable") *d_osdump << "sat"; else if (d_expResult == "valid" || d_expResult == "unsatisfiable") *d_osdump << "unsat"; else if (status() != "") { *d_osdump << status(); } else *d_osdump << "unknown"; *d_osdump << endl; // difficulty // *d_osdump << " :difficulty { unknown }" << endl; // category if (category() != "") { *d_osdump << " :category { "; *d_osdump << category() << " }" << endl; } // Create types for theory QF_AX if needed if (d_theoryCore->getFlags()["convert2array"].getBool()) { d_indexType = new Type(d_theoryCore->newTypeExpr("Index")); d_elementType = new Type(d_theoryCore->newTypeExpr("Element")); d_arrayType = new Type(arrayType(*d_indexType, *d_elementType)); } } // Preprocess and compute logic for smt-lib if (!d_theoryCore->getFlags()["trans-skip-pp"].getBool()) { ExprMap cache; // Step 1: preprocess asserts, queries, and types vector::iterator i = d_dumpExprs.begin(), iend = d_dumpExprs.end(); for (; i != iend; ++i) { Expr e = *i; switch (e.getKind()) { case ASSERT: { Expr e2 = preprocess(e[0], cache); if (e[0] == e2) break; e2.getType(); *i = Expr(ASSERT, e2); break; } case QUERY: { Expr e2 = preprocess(e[0].negate(), cache); if (e[0].negate() == e2) break; e2.getType(); *i = Expr(QUERY, e2.negate()); break; } case CONST: { DebugAssert(e.arity() == 2, "Expected CONST with arity 2"); if (d_theoryCore->getFlags()["convert2array"].getBool()) break; Expr e2 = processType(e[1]); if (e[1] == e2) break; if (d_convertToBV) { Expr newName = Expr(ID, d_em->newStringExpr(e[0][0].getString()+"_bv")); *i = Expr(CONST, newName, e2); } else { *i = Expr(CONST, e[0], e2); } break; } default: break; } } } if (d_zeroVar) { d_dumpExprs.insert(d_dumpExprs.begin(), Expr(CONST, Expr(ID, d_em->newStringExpr("cvc3Zero")), processType(d_zeroVar->getType().getExpr()))); } // Type inference over equality if (!d_unknown && d_theoryCore->getFlags()["convert2array"].getBool()) { bool changed; do { changed = false; unsigned i; for (i = 0; i < d_equalities.size(); ++i) { if (d_equalities[i][0].getKind() == UCONST && d_arrayConvertMap->find(d_equalities[i][0].getName()) == d_arrayConvertMap->end()) { if (d_equalities[i][1].getKind() == READ) { changed = true; (*d_arrayConvertMap)[d_equalities[i][0].getName()] = *d_elementType; } else if (d_equalities[i][1].getKind() == UCONST) { map::iterator it = d_arrayConvertMap->find(d_equalities[i][1].getName()); if (it != d_arrayConvertMap->end()) { changed = true; (*d_arrayConvertMap)[d_equalities[i][0].getName()] = (*it).second; } } } else if (d_equalities[i][1].getKind() == UCONST && d_arrayConvertMap->find(d_equalities[i][1].getName()) == d_arrayConvertMap->end()) { if (d_equalities[i][0].getKind() == READ) { changed = true; (*d_arrayConvertMap)[d_equalities[i][1].getName()] = *d_elementType; } else if (d_equalities[i][0].getKind() == UCONST) { map::iterator it = d_arrayConvertMap->find(d_equalities[i][0].getName()); if (it != d_arrayConvertMap->end()) { changed = true; (*d_arrayConvertMap)[d_equalities[i][1].getName()] = (*it).second; } } } } } while (changed); } if (d_em->getOutputLang() == SMTLIB_LANG || d_em->getOutputLang() == SMTLIB_V2_LANG) { // Step 2: If both int and real are used, try to separate them if ((!d_unknown && (d_intUsed && d_realUsed)) || d_theoryCore->getFlags()["convert2array"].getBool() || ( d_em->getOutputLang() == SMTLIB_V2_LANG && d_langUsed > NOT_USED && d_langUsed <= LINEAR )) { ExprMap cache; vector::iterator i = d_dumpExprs.begin(), iend = d_dumpExprs.end(); for (; i != iend; ++i) { Expr e = *i; switch (e.getKind()) { case ASSERT: { if (d_theoryCore->getFlags()["convert2array"].getBool()) break; Expr e2 = preprocess2(e[0], cache); e2.getType(); *i = Expr(ASSERT, e2); break; } case QUERY: { if (d_theoryCore->getFlags()["convert2array"].getBool()) break; Expr e2 = preprocess2(e[0].negate(), cache); e2.getType(); *i = Expr(QUERY, e2.negate()); break; } case CONST: { if (!d_theoryCore->getFlags()["convert2array"].getBool()) break; map::iterator it = d_arrayConvertMap->find(e[0][0].getString()); if (it != d_arrayConvertMap->end()) { *i = Expr(CONST, e[0], (*it).second.getExpr()); } else { Expr e2 = processType(e[1]); if (e[1] == e2) break; *i = Expr(CONST, e[0], e2); } break; } default: break; } } } d_arithUsed = d_realUsed || d_intUsed || d_intConstUsed || (d_langUsed != NOT_USED); // Step 3: Go through the cases and figure out the right logic if (d_em->getOutputLang() == SMTLIB_LANG) { *d_osdump << " :logic "; } else {// d_em->getOutputLang() == SMTLIB_V2_LANG *d_osdump << "(set-logic "; } if (d_unknown || d_theoryRecords->theoryUsed() || d_theorySimulate->theoryUsed() || d_theoryDatatype->theoryUsed()) { *d_osdump << "unknown"; } else { if ((d_ax && (d_arithUsed || d_theoryBitvector->theoryUsed() || d_theoryUF->theoryUsed())) || (d_intIntArray && d_realUsed) || (d_arithUsed && d_theoryBitvector->theoryUsed())) { *d_osdump << "unknown"; } else { bool QF = false; bool A = false; bool UF = false; bool promote = d_theoryCore->getFlags()["promote"].getBool(); if (!d_theoryQuant->theoryUsed()) { QF = true; *d_osdump << "QF_"; } if (d_theoryArray->theoryUsed() && !d_convertArray) { A = true; *d_osdump << "A"; } // Promote undefined subset logics else if (promote && !QF && !(d_arithUsed && d_realUsed && !d_intUsed && d_langUsed <= LINEAR) && !(d_arithUsed && !d_realUsed && d_intUsed && d_langUsed == NONLINEAR)) { A = true; *d_osdump << "A"; } if (d_theoryUF->theoryUsed() || (d_theoryArray->theoryUsed() && d_convertArray)) { UF = true; *d_osdump << "UF"; } // Promote undefined subset logics else if (promote && !QF && !(d_arithUsed && d_realUsed && !d_intUsed && d_langUsed <= LINEAR)) { UF = true; *d_osdump << "UF"; } if (d_arithUsed) { if (d_intUsed && d_realUsed) { if (d_langUsed < NONLINEAR) { *d_osdump << "LIRA"; } else *d_osdump << "NIRA"; } else if (d_realUsed) { if (d_langUsed <= DIFF_ONLY) { // Promote undefined subset logics if (promote && !QF) { *d_osdump << "LRA"; } else *d_osdump << "RDL"; } else if (d_langUsed <= LINEAR) { *d_osdump << "LRA"; } else { // Promote undefined subset logics if (promote && !QF) { *d_osdump << "NIRA"; } else *d_osdump << "NRA"; } } else { if (QF && !A && UF && d_langUsed <= LINEAR) { if (!d_realUsed && d_langUsed <= LINEAR && d_UFIDL_ok) { *d_osdump << "IDL"; } else { *d_osdump << "LIA"; } } else if (d_langUsed <= DIFF_ONLY) { // Promote undefined subset logics if (promote && !QF) { *d_osdump << "LIA"; } else if (A) { if (!UF) { UF = true; *d_osdump << "UF"; } *d_osdump << "LIA"; } else *d_osdump << "IDL"; } else if (d_langUsed <= LINEAR) { // Promote undefined subset logics if (promote && QF && A && !UF) { UF = true; *d_osdump << "UF"; } if (QF && !A && (!d_realUsed && d_langUsed <= LINEAR && d_UFIDL_ok)) { *d_osdump << "UFIDL"; } else { *d_osdump << "LIA"; } } else { *d_osdump << "NIA"; } } } else if (d_theoryBitvector->theoryUsed()) { // Promote undefined subset logics if (promote && A && QF && !UF) { UF = true; *d_osdump << "UF"; } *d_osdump << "BV"; } else { if (d_ax) { *d_osdump << "X"; } // Promote undefined subset logics else if (promote && (!QF || (A && UF))) { *d_osdump << "LIA"; } else { // Default logic if (!A && !UF) { UF = true; *d_osdump << "UF"; } qf_uf = QF && UF && (!A); } } } } if (d_em->getOutputLang() == SMTLIB_V2_LANG) { *d_osdump << ")"; } *d_osdump << endl; } if (d_em->getOutputLang() == SMTLIB_V2_LANG) { // Print the rest of the set-info commands if (source() != "") { *d_osdump << "(set-info :source " << quoteAnnotation(source()) << ')' << endl; } *d_osdump << "(set-info :smt-lib-version 2.0)" << endl; // Remove leading and trailing spaces from category string c = category(); size_t i = 0, j = c.size(); while (c[i] == ' ') { ++i; --j; } while (j > 0 && c[i+j-1] == ' ') --j; if (j > 0) { c = c.substr(i,j); *d_osdump << "(set-info :category \"" << c << "\")" << endl; } // if (benchName() != "") { // *d_osdump << "(set-info :name \"" << benchName() << "\")" << endl; // } // Get status from expResult flag *d_osdump << "(set-info :status "; if (d_expResult == "invalid" || d_expResult == "satisfiable") *d_osdump << "sat"; else if (d_expResult == "valid" || d_expResult == "unsatisfiable") *d_osdump << "unsat"; else if (status() != "") { *d_osdump << status(); } else *d_osdump << "unknown"; *d_osdump << ")" << endl; // Create types for theory QF_AX if needed if (d_theoryCore->getFlags()["convert2array"].getBool()) { d_indexType = new Type(d_theoryCore->newTypeExpr("Index")); d_elementType = new Type(d_theoryCore->newTypeExpr("Element")); d_arrayType = new Type(arrayType(*d_indexType, *d_elementType)); } } if (d_em->getOutputLang() == PRESENTATION_LANG) { // If we translate SMT-LIBv2 to PRESENTATION, we should set // "no-save-model" so that multiple-query benchmarks give // the same results in both languages. // // Translation the other way doesn't work, since SMT-LIBv2 // doesn't support CVC3 presentation language semantics. if(d_theoryCore->getFlags()["no-save-model"].getBool()) { *d_osdump << "OPTION \"no-save-model\" 1;" << endl; } } } if (d_dump) { // Dump the actual expressions vector::const_iterator i = d_dumpExprs.begin(), iend = d_dumpExprs.end(); vector assumps; bool skip_diff = d_theoryCore->getFlags()["trans-skip-difficulty"].getBool(); for (; i != iend; ++i) { Expr e = *i; switch (e.getKind()) { case ASSERT: { if (d_combineAssump) { assumps.push_back(e[0]); } else { *d_osdump << e << endl; } break; } case QUERY: { if (!assumps.empty()) { assumps.push_back(e[0].negate()); e = Expr(QUERY, Expr(NOT, Expr(AND, assumps))); } *d_osdump << e << endl; break; } default: if (d_em->getOutputLang() == SMTLIB_LANG && qf_uf && e.getKind() == TYPE && e[0].getKind() == RAW_LIST && e[0][0].getKind() == ID && e[0][0][0].getKind() == STRING_EXPR && e[0][0][0].getString() == "U") break; if (d_em->getOutputLang() == SMTLIB_LANG && d_ax && e.getKind() == TYPE && e[0].getKind() == RAW_LIST && e[0][0].getKind() == ID && e[0][0][0].getKind() == STRING_EXPR && ( e[0][0][0].getString() == "Index" || e[0][0][0].getString() == "Element" )) break; if (skip_diff && e.getKind() == ANNOTATION && e[0].getKind() == STRING_EXPR && e[0].getString() == "difficulty") break; if (d_em->getOutputLang() == SMTLIB_V2_LANG && (e.getKind() == CONST && e[0].getKind() == ID) && (d_realUsed || d_intUsed)) { if (e[0][0].getString() == "abs") { // [MGD] Some benchmarks define their own abs, but we have to // rename it in the benchmark becuase in SMTLIBv2 the Reals and // Ints and Reals_Ints theories define abs. d_replaceSymbols["abs"] = "abs_"; } else if (e[0][0].getString() == "mod") { // ditto for mod d_replaceSymbols["mod"] = "mod_"; } } *d_osdump << e << endl; break; } } } if (d_translate) { if (d_em->getOutputLang() == SMTLIB_LANG) { *d_osdump << ")" << endl; } else if (d_em->getOutputLang() == SMTLIB_V2_LANG) { *d_osdump << "(exit)" << endl; } if (d_em->getOutputLang() == SPASS_LANG) { *d_osdump << "end_of_list." << endl; *d_osdump << endl; *d_osdump << "list_of_settings(SPASS)." << endl << "{*" << endl << "set_flag(Auto,1). % auto configuration" << endl << "set_flag(Splits,-1). % enable Splitting" << endl << "set_flag(RVAA,1). % enable variable assignment abstraction for LA" << endl << "set_flag(RInput,0). % no input reduction" << endl << "set_flag(Sorts,0). % no Sorts" << endl << "set_flag(ISHy,0). % no Hyper Resolution" << endl << "set_flag(IOHy,0). % no Hyper Resolution" << endl << "set_flag(RTer,0). % no Terminator" << endl << "set_flag(RCon,0). % no Condensation" << endl << "set_flag(RFRew,1). % no Contextual Rewriting" << endl << "set_flag(RBRew,1). % no Contextual Rewriting" << endl << "*}" << endl << "end_of_list." << endl; *d_osdump << endl; *d_osdump << "end_problem." << endl; } } if (d_dumpFileOpen) d_osdumpFile.close(); if (d_zeroVar) delete d_zeroVar; } const string Translator::fixConstName(const string& s) { if (d_em->getOutputLang() == SMTLIB_LANG) { if (s[0] == '_') { return "smt"+s; } } std::hash_map::iterator i = d_replaceSymbols.find(s); return (i == d_replaceSymbols.end()) ? s : (*i).second; } const string Translator::escapeSymbol(const string& s) { if (d_em->getOutputLang() == SMTLIB_V2_LANG) { if (s.length() == 0 || isdigit(s[0])) return "|" + s + "|"; // This is the legal set of SMTLIB v2 symbol characters from page // 20 of the SMT-LIB v2.0 spec. If any character in the symbol // string falls outside this set, the symbol must be |-delimited. if(s.find_first_not_of("abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789~!@$%^&*_-+=<>.?/") != string::npos) return "|" + s + "|"; } return s; } const string Translator::quoteAnnotation(const string& s) { if(s.find('|') == string::npos) { return "|" + s + "|"; } else { stringstream sb; sb << '"'; for(string::const_iterator i = s.begin(); i != s.end(); ++i) { char c = *i; if(c == '"') sb << "\\\""; else sb << *i; } sb << '"'; return sb.str(); } } bool Translator::printArrayExpr(ExprStream& os, const Expr& e) { if (e.getKind() == ARRAY) { if (d_convertArray) { os << Expr(ARROW, e[0], e[1]); return true; } if (d_em->getOutputLang() == SMTLIB_V2_LANG) { DebugAssert( e.arity() == 2, "expected arity 2"); os << push << "(Array" << space << nodag << e[0] << space << nodag << e[1] << ")" << pop; return true; } if (d_em->getOutputLang() != SMTLIB_LANG) return false; if (e[0].getKind() == TYPEDECL) { DebugAssert(e[0].arity() == 1, "expected arity 1"); if (e[0][0].getString() == "Index") { if (e[1].getKind() == TYPEDECL) { DebugAssert(e[1].arity() == 1, "expected arity 1"); if (e[1][0].getString() == "Element") { os << "Array"; return true; } } } } else if (isInt(Type(e[0]))) { if (isInt(Type(e[1]))) { d_intIntArray = true; os << "Array"; return true; } else if (isReal(Type(e[1]))) { d_intRealArray = true; os << "Array1"; return true; } else if (isArray(Type(e[1])) && isInt(Type(e[1][0])) && isReal(Type(e[1][1]))) { d_intIntRealArray = true; os << "Array2"; return true; } } else if (e[0].getKind() == BITVECTOR && e[1].getKind() == BITVECTOR) { os << "Array["; os << d_theoryBitvector->getBitvectorTypeParam(Type(e[0])); os << ":"; os << d_theoryBitvector->getBitvectorTypeParam(Type(e[1])); os << "]"; return true; } os << "UnknownArray"; d_unknown = true; return true; } switch (e.getKind()) { case READ: if (d_convertArray) { if (e[0].getKind() == UCONST) { os << Expr(d_em->newSymbolExpr(e[0].getName(), UFUNC).mkOp(), e[1]); return true; } else if (e[0].getKind() == WRITE) { throw Exception("READ of WRITE not implemented yet for convertArray"); } else { throw Exception("Unexpected case for convertArray"); } } break; case WRITE: if (d_convertArray) { throw Exception("WRITE expression encountered while attempting " "to convert arrays to uninterpreted functions"); } break; case ARRAY_LITERAL: if (d_convertArray) { throw Exception("ARRAY_LITERAL expression encountered while attempting" " to convert arrays to uninterpreted functions"); } break; default: throw Exception("Unexpected case in printArrayExpr"); break; } return false; } Expr Translator::zeroVar() { if (!d_zeroVar) { d_zeroVar = new Expr(); if (d_convertToDiff == "int") { *d_zeroVar = d_theoryCore->newVar("cvc3Zero", d_theoryArith->intType().getExpr()); } else if (d_convertToDiff == "real") { *d_zeroVar = d_theoryCore->newVar("cvc3Zero", d_theoryArith->realType().getExpr()); } } return *d_zeroVar; } cvc3-2.4.1/src/theory_bitvector/0000775000175400017540000000000011630011320016423 5ustar mdetersmdeterscvc3-2.4.1/src/theory_bitvector/bitvector_theorem_producer.h0000664000175400017540000006246511265744143024264 0ustar mdetersmdeters/*****************************************************************************/ /*! * \file bitvector_theorem_producer.h * \brief TRUSTED implementation of bitvector proof rules * * Author: Vijay Ganesh * * Created: Wed May 5 16:10:28 PST 2004 * *
* * License to use, copy, modify, sell and/or distribute this software * and its documentation for any purpose is hereby granted without * royalty, subject to the terms and conditions defined in the \ref * LICENSE file provided with this distribution. * *
* */ /*****************************************************************************/ #ifndef _cvc3__bitvector_theorem_producer_h_ #define _cvc3__bitvector_theorem_producer_h_ #include "bitvector_proof_rules.h" #include "theorem_producer.h" namespace CVC3 { class TheoryBitvector; /*! @brief This class implements proof rules for bitvector * normalizers (concatenation normal form, bvplus normal form), * bitblaster rules, other relevant rewrite rules for bv arithmetic * and word-level operators */ /*! Author: Vijay Ganesh, May-August, 2004 */ class BitvectorTheoremProducer: public BitvectorProofRules, public TheoremProducer { private: TheoryBitvector* d_theoryBitvector; //! instance of bitvector DP //! Constant 1-bit bit-vector 0bin0 Expr d_bvZero; //! Constant 1-bit bit-vector 0bin1 Expr d_bvOne; //! Return cached constant 0bin0 const Expr& bvZero() const { return d_bvZero; } //! Return cached constant 0bin1 const Expr& bvOne() const { return d_bvOne; } //! Collect all of: a*x1+b*x1 + c*x2-x2 + d*x3 + ~x3 + ~x4 +e into //! (a+b, x1) , (c-1 , x2), (d-1, x3), (-1, x4) and the constant e-2. //! The constant is calculated from the formula -x = ~x+1 (or -x-1=~x). void collectLikeTermsOfPlus(const Expr& e, ExprMap & likeTerms, Rational & plusConstant); //! Collect a single coefficient*var pair into likeTerms. //! Update the counter of likeTerms[var] += coefficient. //! Potentially update the constant additive plusConstant. void collectOneTermOfPlus(const Rational & coefficient, const Expr& var, ExprMap & likeTerms, Rational & plusConstant); //! Create a vector which will form the next PVPLUS. //! Use the colleciton of likeTerms, and the constant additive plusConstant void createNewPlusCollection(const Expr & e, const ExprMap & likeTerms, Rational & plusConstant, std::vector & result); //! Create expression by applying plus to all elements. //! All elements should be normalized and ready. //! If there are too few elements, a non BVPLUS expression will be created. Expr sumNormalizedElements(int bvplusLength, const std::vector& elements); void getPlusTerms(const Expr& e, Rational& known_term, ExprMap& sumHashMap); Expr buildPlusTerm(int bv_size, Rational& known_term, ExprMap& sumHashMap); Expr chopConcat(int bv_size, Rational c, std::vector& concatKids); bool okToSplit(const Expr& e); public: //! Constructor: constructs an instance of bitvector DP BitvectorTheoremProducer(TheoryBitvector* theoryBitvector); ~BitvectorTheoremProducer() {} //ExprMap d_bvPlusCarryCacheLeftBV; //ExprMap d_bvPlusCarryCacheRightBV; //////////////////////////////////////////////////////////////////// // Partial Canonization rules //////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////// // Bitblasting rules for equations //////////////////////////////////////////////////////////////////// /*! \param thm input theorem: (e1[i]<=>e2[i])<=>false * * \result (e1=e2)<=>false */ Theorem bitvectorFalseRule(const Theorem& thm); /*! \param thm input theorem: (~e1[i]<=>e2[i])<=>true * * \result (e1!=e2)<=>true */ Theorem bitvectorTrueRule(const Theorem& thm); /*! \param e input equation: e1=e2 over bitvector terms * \param f formula over the bits of bitvector variables in e: * * \result \f[\frac{e_1 = e_2}{\bigwedge_{i=1}^n (e_{1}[i] * \iff e_{2}[i]) } \f] where each of \f[ e_{1}[i], e{2}[i] \f] denotes a * formula over variables in \f[ e_{1}, e_{2} \f] respectively */ Theorem bitBlastEqnRule(const Expr& e, const Expr& f); /*! \param e : input disequality: e1 != e2 over bitvector terms * \param f : formula over the bits of bitvector variables in e: * * \result \f[\frac{e_1 \not = e_2}{\bigwedge_{i=1}^n ((\neg e_{1}[i]) * \iff e_{2}[i]) } \f] where each of \f[ e_{1}[i], e{2}[i] \f] denotes a * formula over variables in \f[ e_{1}, e_{2} \f] respectively */ Theorem bitBlastDisEqnRule(const Theorem& e, const Expr& f); //////////////////////////////////////////////////////////////////// // Bitblasting and rewrite rules for Inequations //////////////////////////////////////////////////////////////////// //! sign extend the input SX(e) appropriately Theorem signExtendRule(const Expr& e); //! Pad the kids of BVLT/BVLE to make their length equal Theorem padBVLTRule(const Expr& e, int len); //! Sign Extend the kids of BVSLT/BVSLE to make their length equal Theorem padBVSLTRule(const Expr& e, int len); /*! input: e0 <=(s) e1. output depends on whether the topbits(MSB) of * e0 and e1 are constants. If they are constants then optimizations * are done, otherwise the following rule is implemented. * * e0 <=(s) e1 <==> (e0[n-1] AND NOT e1[n-1]) OR * (e0[n-1] AND e1[n-1] AND e1[n-2:0] <= e0[n-2:0]) OR * (NOT e0[n-1] AND NOT e1[n-1] AND e0[n-2:0] <= e1[n-2:0]) */ Theorem signBVLTRule(const Expr& e, const Theorem& topBit0, const Theorem& topBit1); /*! NOT(e[0][0] = e[0][1]) <==> e[0][0] = ~e[0][1] */ Theorem notBVEQ1Rule(const Expr& e); /*! NOT(e[0][0] < e[0][1]) <==> (e[0][1] <= e[0][0]), * NOT(e[0][0] <= e[0][1]) <==> (e[0][1] < e[0][0]) */ Theorem notBVLTRule(const Expr& e); //! if(lhs==rhs) then we have (lhs < rhs <==> false),(lhs <= rhs <==> true) Theorem lhsEqRhsIneqn(const Expr& e, int kind); Theorem zeroLeq(const Expr& e); Theorem bvConstIneqn(const Expr& e, int kind); Theorem generalIneqn(const Expr& e, const Theorem& lhs_i, const Theorem& rhs_i, int kind); //////////////////////////////////////////////////////////////////// // Bitblasting rules for terms //////////////////////////////////////////////////////////////////// // Input: |- BOOLEXTRACT(a,0) <=> bc_0, ... BOOLEXTRACT(a,n-1) <=> bc_(n-1) // where each bc_0 is TRUE or FALSE // Output: |- a = c // where c is an n-bit constant made from the values bc_0..bc_(n-1) Theorem bitExtractAllToConstEq(std::vector& thms); //! t[i] ==> t[i:i] = 0bin1 or NOT t[i] ==> t[i:i] = 0bin0 Theorem bitExtractToExtract(const Theorem& thm); //! t[i] <=> t[i:i][0] (to use rewriter for simplifying t[i:i]) Theorem bitExtractRewrite(const Expr& x); /*! \param x : input1 is bitvector constant * \param i : input2 is extracted bitposition * * \result \f[ \frac{}{\mathrm{BOOLEXTRACT(x,i)} \iff * \mathrm{TRUE}} \f], if bitposition has a 1; \f[ * \frac{}{\mathrm{BOOLEXTRACT(x,i)} \iff \mathrm{FALSE}} \f], if * the bitposition has a 0 */ Theorem bitExtractConstant(const Expr & x, int i); /*! \param x : input1 is bitvector binary concatenation * \param i : input2 is extracted bitposition * * \result \f[ \frac{}{(t_{[m]}@q_{[n]})[i] \iff (q_{[n]})[i]} * \f], where \f[ 0 \geq i \geq n-1 \f], another case of * boolextract over concatenation is: * \f[\frac{}{(t_{[m]}@q_{[n]})[i] \iff (t_{[m]})[i-n]} \f], * where \f[ n \geq i \geq m+n-1 \f] */ Theorem bitExtractConcatenation(const Expr & x, int i); /*! \param t : input1 is bitvector binary BVMULT. x[0] must be BVCONST * \param i : input2 is extracted bitposition * * \result bitblast of BVMULT */ Theorem bitExtractConstBVMult(const Expr& t, int i); /*! \param t : input1 is bitvector binary BVMULT. t[0] must not be BVCONST * \param i : input2 is extracted bitposition * * \result bitblast of BVMULT */ Theorem bitExtractBVMult(const Expr& t, int i); /*! \param x : input1 is bitvector extraction [k:j] * \param i : input2 is extracted bitposition * * \result \f[ \frac{}{(t_{[n]}[k:j])[i] \iff (t_{[n]})[i+j]} * \f], where \f[ 0 \geq j \geq k < n, 0 \geq i < k-j \f] */ Theorem bitExtractExtraction(const Expr & x, int i); /*! \param t1 : input1 is vector of bitblasts of t, from bit i-1 to 0 * \param t2 : input2 is vector of bitblasts of q, from bit i-1 to 0 * \param bvPlusTerm : input3 is BVPLUS term: BVPLUS(n,t,q) * \param i : input4 is extracted bitposition * * \result The base case is: \f[ * \frac{}{(\mathrm{BVPLUS}(n,t,q))[0] \iff t[0] \oplus q[0]} * \f], when \f[ 0 < i \leq n-1 \f], we have \f[ * \frac{}{(\mathrm{BVPLUS}(n,t,q))[i] \iff t[i] \oplus q[i] * \oplus c(t,q,i)} \f], where c(t,q,i) is the carry generated * by the addition of bits from 0 to i-1 */ Theorem bitExtractBVPlus(const std::vector& t1, const std::vector& t2, const Expr& bvPlusTerm, int i); Theorem bitExtractBVPlusPreComputed(const Theorem& t1_i, const Theorem& t2_i, const Expr& bvPlusTerm, int bitPos, int precomputed); /*! \param bvPlusTerm : input1 is bvPlusTerm, a BVPLUS term with * arity > 2 * * \result : output is iff-Theorem: bvPlusTerm <==> outputTerm, * where outputTerm is an equivalent BINARY bvplus. */ Theorem bvPlusAssociativityRule(const Expr& bvPlusTerm); /*! \param x : input1 is bitwise NEGATION * \param i : input2 is extracted bitposition * * \result \f[ \frac{}{(\sim t_{[n]})[i] \iff \neg (t_{[n]}[i])} * \f] */ Theorem bitExtractNot(const Expr & x, int i); //! Extract from bitwise AND, OR, or XOR Theorem bitExtractBitwise(const Expr& x, int i, int kind); /*! \param x : input1 is bitvector FIXED SHIFT \f[ e_{[n]} \ll k \f] * \param i : input2 is extracted bitposition * * \result \f[\frac{}{(e_{[n]} \ll k)[i] \iff \mathrm{FALSE}} * \f], if 0 <= i < k. however, if k <= i < n then, result is * \f[\frac{}{(e_{[n]} \ll k)[i] \iff e_{[n]}[i]} \f] */ Theorem bitExtractFixedLeftShift(const Expr & x, int i); Theorem bitExtractFixedRightShift(const Expr & x, int i); // BOOLEXTRACT(bvshl(t,s),i) <=> ((s = 0) AND BOOLEXTRACT(t,i)) OR // ((s = 1) AND BOOLEXTRACT(t,i-1)) OR ... // ((s = i) AND BOOLEXTRACT(t,0)) Theorem bitExtractBVSHL(const Expr & x, int i); // BOOLEXTRACT(bvlshr(t,s),i) <=> ((s = 0) AND BOOLEXTRACT(t,i)) OR // ((s = 1) AND BOOLEXTRACT(t,i+1)) OR ... // ((s = n-1-i) AND BOOLEXTRACT(t,n-1)) Theorem bitExtractBVLSHR(const Expr & x, int i); // BOOLEXTRACT(bvashr(t,s),i) <=> ((s = 0) AND BOOLEXTRACT(t,i)) OR // ((s = 1) AND BOOLEXTRACT(t,i+1)) OR ... // ((s >= n-1-i) AND BOOLEXTRACT(t,n-1)) Theorem bitExtractBVASHR(const Expr & x, int i); /*! \param e : input1 is bitvector term * \param r : input2 is extracted bitposition * * \result we check if r > bvlength(e). if yes, then return * BOOLEXTRACT(e,r) <==> FALSE; else raise soundness * exception. (Note: this rule is used in BVPLUS bitblast * function) */ Theorem zeroPaddingRule(const Expr& e, int r); Theorem bitExtractSXRule(const Expr& e, int i); //! c1=c2 <=> TRUE/FALSE (equality of constant bitvectors) Theorem eqConst(const Expr& e); //! |- c1=c2 ==> |- AND(c1[i:i] = c2[i:i]) - expanding equalities into bits Theorem eqToBits(const Theorem& eq); //! t<>m = 0bin00...00 @ t[bvlength-1:m], takes e == (t>>n) Theorem rightShiftToConcat(const Expr& e); //! BVSHL(t,c) = t[n-c,0] @ 0bin00...00 Theorem bvshlToConcat(const Expr& e); //! BVSHL(t,c) = IF (c = 0) THEN t ELSE IF (c = 1) ... Theorem bvshlSplit(const Expr& e); //! BVLSHR(t,c) = 0bin00...00 @ t[n-1,c] Theorem bvlshrToConcat(const Expr& e); //! All shifts over a 0 constant = 0 Theorem bvShiftZero(const Expr& e); //! BVASHR(t,c) = SX(t[n-1,c], n-1) Theorem bvashrToConcat(const Expr& e); //! a XNOR b <=> (~a & ~b) | (a & b) Theorem rewriteXNOR(const Expr& e); //! a NAND b <=> ~(a & b) Theorem rewriteNAND(const Expr& e); //! a NOR b <=> ~(a | b) Theorem rewriteNOR(const Expr& e); //! BVCOMP(a,b) <=> ITE(a=b,0bin1,0bin0) Theorem rewriteBVCOMP(const Expr& e); //! a - b <=> a + (-b) Theorem rewriteBVSub(const Expr& e); //! k*t = BVPLUS(n, ) -- translation of k*t to BVPLUS /*! If k = 2^m, return k*t = t\@0...0 */ Theorem constMultToPlus(const Expr& e); //! 0bin0...0 @ BVPLUS(n, args) = BVPLUS(n+k, args) /*! where k is the size of the 0bin0...0 */ Theorem bvplusZeroConcatRule(const Expr& e); /////////////////////////////////////////////////////////////////// ///// Bvplus Normal Form rules /////////////////////////////////////////////////////////////////// Theorem zeroCoeffBVMult(const Expr& e); Theorem oneCoeffBVMult(const Expr& e); Theorem flipBVMult(const Expr& e); //! converts e to a bitvector of length rat Expr pad(int rat, const Expr& e); Theorem padBVPlus(const Expr& e); Theorem padBVMult(const Expr& e); Theorem bvConstMultAssocRule(const Expr& e); Theorem bvMultAssocRule(const Expr& e); Theorem bvMultDistRule(const Expr& e); Theorem flattenBVPlus(const Expr& e); Theorem combineLikeTermsRule(const Expr& e); Theorem lhsMinusRhsRule(const Expr& e); Theorem extractBVMult(const Expr& e); Theorem extractBVPlus(const Expr& e); //! ite(c,t1,t2)[i:j] <=> ite(c,t1[i:j],t2[i:j]) Theorem iteExtractRule(const Expr& e); //! ~ite(c,t1,t2) <=> ite(c,~t1,~t2) Theorem iteBVnegRule(const Expr& e); Theorem bvuminusBVConst(const Expr& e); Theorem bvuminusBVMult(const Expr& e); Theorem bvuminusBVUminus(const Expr& e); Theorem bvuminusVar(const Expr& e); Theorem bvmultBVUminus(const Expr& e); //! -t <==> ~t+1 Theorem bvuminusToBVPlus(const Expr& e); //! -(c1*t1+...+cn*tn) <==> (-(c1*t1)+...+-(cn*tn)) Theorem bvuminusBVPlus(const Expr& e); /////////////////////////////////////////////////////////////////// ///// Concatenation Normal Form rules /////////////////////////////////////////////////////////////////// // Extraction rules //! c1[i:j] = c (extraction from a constant bitvector) Theorem extractConst(const Expr& e); //! t[n-1:0] = t for n-bit t Theorem extractWhole(const Expr& e); //! t[i:j][k:l] = t[k+j:l+j] (eliminate double extraction) Theorem extractExtract(const Expr& e); //! (t1 @ t2)[i:j] = t1[...] @ t2[...] (push extraction through concat) Theorem extractConcat(const Expr& e); //! Auxiliary function: (t1 op t2)[i:j] = t1[i:j] op t2[i:j] Theorem extractBitwise(const Expr& e, int kind, const std::string& name); //! (t1 & t2)[i:j] = t1[i:j] & t2[i:j] (push extraction through OR) Theorem extractAnd(const Expr& e); //! (t1 | t2)[i:j] = t1[i:j] | t2[i:j] (push extraction through AND) Theorem extractOr(const Expr& e); //! (~t)[i:j] = ~(t[i:j]) (push extraction through NEG) Theorem extractNeg(const Expr& e); // Negation rules //! ~c1 = c (bit-wise negation of a constant bitvector) Theorem negConst(const Expr& e); //! ~(t1\@...\@tn) = (~t1)\@...\@(~tn) -- push negation through concat Theorem negConcat(const Expr& e); //! ~(~t) = t -- eliminate double negation Theorem negNeg(const Expr& e); //! ~t = -1*t + 1 -- eliminate negation Theorem negElim(const Expr& e); //! ~(t1 & t2) <=> ~t1 | ~t2 -- DeMorgan's Laws Theorem negBVand(const Expr& e); //! ~(t1 | t2) <=> ~t1 & ~t2 -- DeMorgan's Laws Theorem negBVor(const Expr& e); //! ~(t1 xor t2) = ~t1 xor t2 Theorem negBVxor(const Expr& e); //! ~(t1 xnor t2) = t1 xor t2 Theorem negBVxnor(const Expr& e); // Bit-wise rules //! Combine constants in bitwise AND, OR, XOR Theorem bitwiseConst(const Expr& e, const std::vector& idxs, int kind); //! Lifts concatenation above bitwise operators. Theorem bitwiseConcat(const Expr& e, int kind); //! Flatten bitwise operation Theorem bitwiseFlatten(const Expr& e, int kind); //! Simplify bitwise operator containing a constant child /*! \param e is the bit-wise expr * \param idx is the index of the constant bitvector * \param kind is the kind of e */ Theorem bitwiseConstElim(const Expr& e, int idx, int kind); /*! checks if e is already present in likeTerms without conflicts. * if yes return 1, else{ if conflict return -1 else return 0 } * we have conflict if * 1. the kind of e is BVNEG, * and e[0] is already present in likeTerms * 2. ~e is present in likeTerms already */ int sameKidCheck(const Expr& e, ExprMap& likeTerms); // Concatenation rules //! c1\@c2\@...\@cn = c (concatenation of constant bitvectors) Theorem concatConst(const Expr& e); //! Flatten one level of nested concatenation, e.g.: x\@(y\@z)\@w = x\@y\@z\@w Theorem concatFlatten(const Expr& e); //! Merge n-ary concat. of adjacent extractions: x[15:8]\@x[7:0] = x[15:0] Theorem concatMergeExtract(const Expr& e); /////////////////////////////////////////////////////////////////// ///// Modulo arithmetic rules /////////////////////////////////////////////////////////////////// //! BVPLUS(n, c1,c2,...,cn) = c (bit-vector plus of constant bitvectors) Theorem bvplusConst(const Expr& e); /*! @brief n*c1 = c, where n >= 0 (multiplication of a constant * bitvector by a non-negative constant) */ Theorem bvmultConst(const Expr& e); /////////////////////////////////////////////////////////////////// ///// Type predicate rules /////////////////////////////////////////////////////////////////// //! |- t=0 OR t=1 for any 1-bit bitvector t Theorem typePredBit(const Expr& e); //! Expand the type predicate wrapper (compute the actual type predicate) Theorem expandTypePred(const Theorem& tp); //////////////////////////////////////////////////////////////////// // Helper functions //////////////////////////////////////////////////////////////////// //! Create Expr from Rational (for convenience) Expr rat(const Rational& r) { return d_em->newRatExpr(r); } /*! \param t1BitExtractThms : input1 is vector of bitblasts of t1, * from bit i-1 to 0 * * \param t2BitExtractThms : input2 is vector of bitblasts of t2, * from bit i-1 to 0 * * \param bitPos : input3 is extracted * bitposition * * \result is the expression \f$t1[0] \wedge t2[0]\f$ if * bitPos=0. this function is recursive; if bitPos > 0 then the * output expression is * \f[ (t1[i-1] \wedge t2[i-1]) * \vee (t1[i-1] \wedge computeCarry(t1,t2,i-1)) * \vee (t2[i-1] \wedge computeCarry(t1,t2,i-1)) * \f] */ Expr computeCarry(const std::vector& t1BitExtractThms, const std::vector& t2BitExtractThms, int bitPos); Expr computeCarryPreComputed(const Theorem& t1_i, const Theorem& t2_i, int bitPos, int precomputedFlag); /*Beginning of Lorenzo PLatania's methods*/ // virtual Theorem multiply_coeff( Rational mult_inv, const Expr& e); //! isolate a variable with coefficient = 1 on the Lhs of an //equality expression virtual Theorem isolate_var(const Expr& e); // BVPLUS(N, a@b, y) = BVPLUS(N-n,a,BVPLUS(N,b,y)[N-1:n])@BVPLUS(n,b,y) // where n = BVSize(b), a != 0 virtual Theorem liftConcatBVMult(const Expr& e); //! canonize BVMult expressions in order to get one coefficient //multiplying the variable(s) in the expression virtual Theorem canonBVMult( const Expr& e ); // BVPLUS(N, a@b, y) = BVPLUS(N-n,a,BVPLUS(N,b,y)[N-1:n])@BVPLUS(n,b,y) // where n = BVSize(b) virtual Theorem liftConcatBVPlus(const Expr& e); //! canonize BVPlus expressions in order to get just one //coefficient multiplying each variable in the expression virtual Theorem canonBVPlus( const Expr& e ); //! canonize BVMinus expressions: push the minus to the leafs in //BVPLUS expr; simplify minus in BVMULT and BVMINUS expr virtual Theorem canonBVUMinus( const Expr& e ); // Input: t[hi:lo] = rhs // if t appears as leaf in rhs, then: // t[hi:lo] = rhs |- Exists x,y,z. (t = x @ y @ z AND y = rhs), solvedForm = false // else // t[hi:lo] = rhs |- Exists x,y,z. (t = x @ rhs @ z AND y = rhs), solvedForm = true virtual Theorem processExtract(const Theorem& e, bool& solvedForm); // normalizes equation virtual Theorem canonBVEQ( const Expr& e, int maxEffort = 3 ); //! apply the distributive rule on the BVMULT expression e virtual Theorem distributive_rule( const Expr& e ); // virtual Theorem BVMultConstTerm( const Expr& e1, const Expr& e2); // recursively reorder subterms in a BVMULT term virtual Theorem BVMult_order_subterms( const Expr& e); // rewrites the equation in the form 0 = Expr // this is needed for TheoryBitvector::solve virtual Theorem MarkNonSolvableEq( const Expr& e); /*End of Lorenzo PLatania's methods*/ // rewrite BVZEROEXTEND into CONCAT virtual Theorem zeroExtendRule(const Expr& e); // rewrite BVREPEAT into CONCAT virtual Theorem repeatRule(const Expr& e); // rewrite BVROTL into CONCAT virtual Theorem rotlRule(const Expr& e); // rewrite BVROTR into CONCAT virtual Theorem rotrRule(const Expr& e); // Dejan: Division rewrites /** * Divide a with b unsigned and return the bit-vector constant result */ virtual Theorem bvUDivConst(const Expr& divExpr); /** * Rewrite x/y to * \exists s: s = x/y \wedge (y \neq 0 \implies x = y * s + m & 0 <= m < y) */ virtual Theorem bvUDivTheorem(const Expr& divExpr); /** * Compute the remainder */ virtual Theorem bvURemConst(const Expr& remExpr); /** * Rewrite a%b in terms of a/b, i.e. a - a/b */ virtual Theorem bvURemRewrite(const Expr& remExpr); /** * Bit-blast the multiplication a_times_b given the bits in a_bits and b_bits. * The resulting output bits will be in the vector output_bits. The return value * is a theorem saying there is no overflow for this multiplication. (TODO, it's * just an empty theorem for now). */ virtual Theorem bitblastBVMult(const std::vector& a_bits, const std::vector& b_bits, const Expr& a_times_b, std::vector& output_bits); /** * Bit-blast the sum a_plus_b given the bits in a_bits and b_bits. * The resulting output bits will be in the vector output_bits. The return value * is a theorem saying there is no overflow for this sum. (TODO, it's * just an empty theorem for now). */ virtual Theorem bitblastBVPlus(const std::vector& a_bits, const std::vector& b_bits, const Expr& a_plus_b, std::vector& output_bits); /** * Rewrite the signed divide in terms of the unsigned one. */ virtual Theorem bvSDivRewrite(const Expr& sDivExpr); /** * Rewrite the signed remainder in terms of the unsigned one. */ virtual Theorem bvSRemRewrite(const Expr& sRemExpr); /** * Rewrite the signed mod in terms of the unsigned one. */ virtual Theorem bvSModRewrite(const Expr& sModExpr); /** * Rewrite x_1 \vee x_2 \vee \ldots \vee x_n = 0 into * x_1 = 0 \wedge x_2 = 0 \wedge \ldots \wedge x_n = 0. */ virtual Theorem zeroBVOR(const Expr& orEqZero); /** * Rewrite x_1 \wedge x_2 \wedge \ldots \wedge x_n = 1^n into * x_1 = 1^n \wedge x_2 = 1^n \wedge \ldots \wedge x_n = 1^n. */ virtual Theorem oneBVAND(const Expr& andEqOne); /** * Equalities over constants go to true/false. */ virtual Theorem constEq(const Expr& eq); /** * Returns true if equation is of the form x[i:j] = x[k:l], where the * extracted segments overlap, i.e. i > j >= k > l or k > i >= l > j. */ bool solveExtractOverlapApplies(const Expr& eq); /** * Returns the theorem that simplifies the equality of two overlapping * extracts over the same term. */ Theorem solveExtractOverlap(const Expr& eq); }; // end of class BitvectorTheoremProducer } // end of name-space CVC3 #endif cvc3-2.4.1/src/theory_bitvector/Makefile0000664000175400017540000000066310533133653020107 0ustar mdetersmdeters################################################## # About this Makefile # # This Makefile depends on Makefile.opts ################################################## MODULE = theory_bitvector SRC = bitvector_theorem_producer.cpp theory_bitvector.cpp HEADERS = \ bitvector_proof_rules.h \ bitvector_theorem_producer.h \ bitvector_expr_value.h \ bitvector_exception.h LIBRARY=libtheory_bitvector.a include ../../Makefile.local cvc3-2.4.1/src/theory_bitvector/bitvector_expr_value.h0000664000175400017540000000460110562777003023054 0ustar mdetersmdeters/*****************************************************************************/ /*! *\file bitvector_expr_value.h *\brief Subclasses of ExprValue for bit-vector expressions * * Author: Sergey Berezin, Vijay Ganesh * * Created: Wed Jun 23 14:36:59 2004 * *
* * License to use, copy, modify, sell and/or distribute this software * and its documentation for any purpose is hereby granted without * royalty, subject to the terms and conditions defined in the \ref * LICENSE file provided with this distribution. * *
* */ /*****************************************************************************/ #ifndef _cvc3__theory_bitvector__bitvector_expr_value_h_ #define _cvc3__theory_bitvector__bitvector_expr_value_h_ #include "theory_bitvector.h" namespace CVC3 { /////////////////////////////////////////////////////////////////////////////// //class BVConstExpr /////////////////////////////////////////////////////////////////////////////// //! An expression subclass for bitvector constants. class BVConstExpr : public ExprValue { private: std::vector d_bvconst; //!< value of bitvector constant size_t d_MMIndex; //!< The registration index for ExprManager public: //! Constructor BVConstExpr(ExprManager* em, std::string bvconst, size_t mmIndex, ExprIndex idx = 0); //! Constructor BVConstExpr(ExprManager* em, std::vector bvconst, size_t mmIndex, ExprIndex idx = 0); ExprValue* copy(ExprManager* em, ExprIndex idx = 0) const { return new(em->getMM(getMMIndex())) BVConstExpr(em, d_bvconst, d_MMIndex, idx); } size_t computeHash() const; size_t getMMIndex() const { return d_MMIndex; } const ExprValue* getExprValue() const { return this; } //! Only compare the bitvector constant, not the integer attribute bool operator==(const ExprValue& ev2) const { if(ev2.getMMIndex() != d_MMIndex) return false; return (d_bvconst == ((const BVConstExpr&)ev2).d_bvconst); } void* operator new(size_t size, MemoryManager* mm) { return mm->newData(size); } void operator delete(void* pMem, MemoryManager* mm) { mm->deleteData(pMem); } void operator delete(void*) { } unsigned size() const { return d_bvconst.size(); } bool getValue(int i) const { DebugAssert(0 <= i && (unsigned)i < size(), "out of bounds"); return d_bvconst[i]; } }; //end of BVConstExpr } // end of namespace CVC3 #endif cvc3-2.4.1/src/theory_bitvector/bitvector_theorem_producer.cpp0000644000175400017540000070662711624746723024627 0ustar mdetersmdeters/*****************************************************************************/ /*! * \file bitvector_theorem_producer.cpp * * Author: Vijay Ganesh * * Created: Wed May 5 16:19:49 PST 2004 * *
* * License to use, copy, modify, sell and/or distribute this software * and its documentation for any purpose is hereby granted without * royalty, subject to the terms and conditions defined in the \ref * LICENSE file provided with this distribution. * *
* */ /*****************************************************************************/ // CLASS: BitvectorProofRules // // AUTHOR: Vijay Ganesh, 05/30/2003 // // Description: TRUSTED implementation of bitvector proof rules. // /////////////////////////////////////////////////////////////////////////////// // This code is trusted #define _CVC3_TRUSTED_ #include #include "bitvector_theorem_producer.h" #include "common_proof_rules.h" #include "theory_core.h" #include "theory_bitvector.h" using namespace std; using namespace CVC3; /////////////////////////////////////////////////////////////////////// // TheoryBitvector:trusted method for creating BitvectorTheoremProducer /////////////////////////////////////////////////////////////////////// BitvectorProofRules* TheoryBitvector::createProofRules() { return new BitvectorTheoremProducer(this); } BitvectorTheoremProducer::BitvectorTheoremProducer(TheoryBitvector* theoryBV) : TheoremProducer(theoryBV->theoryCore()->getTM()), d_theoryBitvector(theoryBV) { // Cache constants 0bin0 and 0bin1 vector bits(1); bits[0]=false; d_bvZero = d_theoryBitvector->newBVConstExpr(bits); bits[0]=true; d_bvOne = d_theoryBitvector->newBVConstExpr(bits); } /////////////////////////////////////////////////////////////////////// // BitBlasting rules for equations /////////////////////////////////////////////////////////////////////// // |- (BOOLEXTRACT(a,i) <=> BOOLEXTRACT(b,i)) <=> False ==> |- a = b <=> False Theorem BitvectorTheoremProducer::bitvectorFalseRule(const Theorem& thm) { if(CHECK_PROOFS) { const Expr e = thm.getExpr(); CHECK_SOUND(e.isIff() && e[0].isIff(), "TheoryBitvector::bitvectorFalseRule: " "premise must be a iff theorem:\n e = " +e.toString()); CHECK_SOUND(e[1].isFalse(), "TheoryBitvector::bitvectorFalseRule: " "premise must be iff Theorem, with False as the RHS:\n e = " +e.toString()); CHECK_SOUND(e[0][0].getOpKind() == BOOLEXTRACT && e[0][1].getOpKind() == BOOLEXTRACT, "TheoryBitvector::bitvectorFalseRule: " "premise must be iff Theorem, with False as the RHS:\n e = " +e.toString()); CHECK_SOUND(d_theoryBitvector->getBoolExtractIndex(e[0][0]) == d_theoryBitvector->getBoolExtractIndex(e[0][1]), "TheoryBitvector::bitvectorFalseRule: " "premise must be iff Theorem, with False as the RHS:\n e = " +e.toString()); } const Expr& e = thm.getExpr(); const Expr& t1 = e[0][0][0]; const Expr& t2 = e[0][1][0]; Proof pf; if(withProof()) pf = newPf("bitvector_false_rule", e, thm.getProof()); return newRWTheorem(t1.eqExpr(t2), e[1], thm.getAssumptionsRef(), pf); } /*! \param thm input theorem: (~e1[i]<=>e2[i])<=>true * * \result (e1!=e2)<=>true */ // |- (NOT (BOOLEXTRACT(a,i)) <=> BOOLEXTRACT(b,i)) <=> TRUE ==> // |- NOT (a = b) <=> TRUE Theorem BitvectorTheoremProducer::bitvectorTrueRule(const Theorem& thm) { if(CHECK_PROOFS) { const Expr e = thm.getExpr(); CHECK_SOUND(e.isIff() && e[0].isIff(), "TheoryBitvector::bitvectorFalseRule: " "premise must be a iff theorem:\n e = " +e.toString()); CHECK_SOUND(e[1].isTrue(), "TheoryBitvector::bitvectorFalseRule: " "premise must be iff Theorem, with False as the RHS:\n e = " +e.toString()); CHECK_SOUND(e[0][0].getKind() == NOT && e[0][0][0].getOpKind() == BOOLEXTRACT && e[0][1].getOpKind() == BOOLEXTRACT, "TheoryBitvector::bitvectorFalseRule: " "premise must be iff Theorem, with False as the RHS:\n e = " +e.toString()); CHECK_SOUND(d_theoryBitvector->getBoolExtractIndex(e[0][0][0]) == d_theoryBitvector->getBoolExtractIndex(e[0][1]), "TheoryBitvector::bitvectorFalseRule: " "premise must be iff Theorem, with False as the RHS:\n e = " +e.toString()); } const Expr& e = thm.getExpr(); //e is (~BE(t1,i)<=>BE(t2,i))<=>true. to extract t1 we have to go 4 level deep //FIXME: later const Expr& t1 = e[0][0][0][0]; const Expr& t2 = e[0][1][0]; Proof pf; if(withProof()) pf = newPf("bitvector_true_rule", e, thm.getProof()); return newRWTheorem(t1.eqExpr(t2).negate(), e[1], thm.getAssumptionsRef(), pf); } // Input: e: a = b // f :AND_0^(bvLength-1)(a[bitPosition] <=> b[bitPosition]) // Output: |- e <=> f Theorem BitvectorTheoremProducer::bitBlastEqnRule(const Expr& e, const Expr& f) { if(CHECK_PROOFS) { CHECK_SOUND(e.isEq(), "TheoryBitvector::bitBlastEqnRule: " "premise must be a rewrite theorem:\n e = " +e.toString()); const Expr& lhs = e[0]; const Expr& rhs = e[1]; const Type& leftType = lhs.getType(); const Type& rightType = rhs.getType(); CHECK_SOUND(BITVECTOR == leftType.getExpr().getOpKind() && BITVECTOR == rightType.getExpr().getOpKind(), "TheoryBitvector::bitBlastEqnRule: " "lhs & rhs must be bitvectors:\n e =" +e.toString()); int lhsLength = d_theoryBitvector->BVSize(lhs); int rhsLength = d_theoryBitvector->BVSize(rhs); CHECK_SOUND(lhsLength == rhsLength, "TheoryBitvector::bitBlastEqnRule: " "lhs & rhs must be bitvectors of same bvLength.\n size(lhs) = " + int2string(lhsLength) +"\n size(rhs) = " + int2string(rhsLength) +"\n e = "+e.toString()); int bvLength = d_theoryBitvector->BVSize(leftType.getExpr()); CHECK_SOUND(f.isAnd(), "TheoryBitvector::bitBlastEqnRule: " "consequence of the rule must be an AND.\n f = " +f.toString()); CHECK_SOUND(bvLength == f.arity(), "TheoryBitvector::bitBlastEqnRule: " "the arity of the consequence AND must " "equal the bvLength of the bitvector:\n f = " +f.toString()+"\n bvLength = "+ int2string(bvLength)); for (int i=0; i < bvLength; ++i) { const Expr& conjunct = f[i]; CHECK_SOUND(conjunct.isIff() && 2 == conjunct.arity(), "TheoryBitvector::bitBlastEqnRule: " "each conjunct in consequent must be an IFF.\n f = " +f.toString()); const Expr& leftExtract = conjunct[0]; const Expr& rightExtract = conjunct[1]; CHECK_SOUND(BOOLEXTRACT == leftExtract.getOpKind(), "TheoryBitvector::bitBlastEqnRule: " "each conjunct in consequent must be boolextract.\n" " f["+int2string(i)+"] = "+conjunct.toString()); CHECK_SOUND(BOOLEXTRACT == rightExtract.getOpKind(), "TheoryBitvector::bitBlastEqnRule: " "each conjunct in consequent must be boolextract.\n" " f["+int2string(i)+"] = "+conjunct.toString()); const Expr& leftBV = leftExtract[0]; const Expr& rightBV = rightExtract[0]; CHECK_SOUND(leftBV == lhs && rightBV == rhs, "TheoryBitvector::bitBlastEqnRule: each boolextract" " must be applied to the correct bitvector.\n conjunct = " +conjunct.toString() +"\n leftBV = "+ leftBV.toString() +"\n lhs = "+ lhs.toString() +"\n rightBV = "+rightBV.toString() +"\n rhs = "+rhs.toString()); int leftBitPosition = d_theoryBitvector->getBoolExtractIndex(leftExtract); int rightBitPosition = d_theoryBitvector->getBoolExtractIndex(rightExtract); CHECK_SOUND(leftBitPosition == i && rightBitPosition == i, "TheoryBitvector::bitBlastEqnRule: " "boolextract positions must match i= "+int2string(i) +"\n conjunct = "+conjunct.toString()); } } Proof pf; if(withProof()) pf = newPf("bit_blast_equations", e, f); return newRWTheorem(e, f, Assumptions::emptyAssump(), pf); } /////////////////////////////////////////////////////////////////////// // BitBlasting rules for dis-equations: separate rule for disequations // for efficiency sake /////////////////////////////////////////////////////////////////////// Theorem BitvectorTheoremProducer::bitBlastDisEqnRule(const Theorem& notE, const Expr& f){ TRACE("bitvector", "input to bitBlastDisEqnRule(", notE.toString(), ")"); DebugAssert(notE.getExpr().isNot() && (notE.getExpr())[0].isEq(), "TheoryBitvector::bitBlastDisEqnRule:" "expecting an equation" + notE.getExpr().toString()); //e is the equation const Expr& e = (notE.getExpr())[0]; if(CHECK_PROOFS) { CHECK_SOUND(e.isEq(), "TheoryBitvector::bitBlastDisEqnRule:" "premise must be a rewrite theorem" + e.toString()); const Expr& lhs = e[0]; const Expr& rhs = e[1]; const Type& leftType = lhs.getType(); const Type& rightType = rhs.getType(); CHECK_SOUND(BITVECTOR == leftType.getExpr().getOpKind() && BITVECTOR == rightType.getExpr().getOpKind(), "TheoryBitvector::bitBlastDisEqnRule:" "lhs & rhs must be bitvectors" + e.toString()); CHECK_SOUND(d_theoryBitvector->BVSize(leftType.getExpr()) == d_theoryBitvector->BVSize(rightType.getExpr()), "TheoryBitvector::bitBlastDisEqnRule:" "lhs & rhs must be bitvectors of same bvLength"); int bvLength = d_theoryBitvector->BVSize(leftType.getExpr()); CHECK_SOUND(f.isOr(), "TheoryBitvector::bitBlastDisEqnRule:" "consequence of the rule must be an OR" + f.toString()); CHECK_SOUND(bvLength == f.arity(), "TheoryBitvector::bitBlastDisEqnRule:" "the arity of the consequence OR must be" "equal to the bvLength of the bitvector" + f.toString() + int2string(bvLength)); for(int i=0; i getBoolExtractIndex(leftExtract); int rightBitPosition = d_theoryBitvector->getBoolExtractIndex(rightExtract); CHECK_SOUND(leftBitPosition == i && rightBitPosition == i, "TheoryBitvector::bitBlastDisEqnRule:" "boolextract positions must match" + disjunct.toString()); } } Proof pf; if(withProof()) pf = newPf("bit_blast_disequations", notE.getExpr(), f, notE.getProof()); return newTheorem(f, notE.getAssumptionsRef(), pf); } /////////////////////////////////////////////////////////////////////// // Rules for Inequations /////////////////////////////////////////////////////////////////////// //! Pad the kids of BVLT/BVLE to make their bvLength equal Theorem BitvectorTheoremProducer::padBVLTRule(const Expr& e, int len) { if(CHECK_PROOFS) { CHECK_SOUND((BVLT == e.getOpKind() || BVLE == e.getOpKind()) && e.arity()==2, "BitvectorTheoremProducer::padBVLTRule: " "input must e be a BVLT/BVLE: e = " + e.toString()); CHECK_SOUND(BITVECTOR==e[0].getType().getExpr().getOpKind() && BITVECTOR==e[1].getType().getExpr().getOpKind(), "BitvectorTheoremProducer::padBVLTRule: " "for BVMULT terms e[0],e[1] must be a BV: " + e.toString()); CHECK_SOUND(0=0 and an integer: len = " + int2string(len)); } Expr e0 = pad(len, e[0]); Expr e1 = pad(len, e[1]); int kind = e.getOpKind(); Expr output; if(kind == BVLT) output = d_theoryBitvector->newBVLTExpr(e0,e1); else output = d_theoryBitvector->newBVLEExpr(e0,e1); Proof pf; if(withProof()) pf = newPf("pad_bvlt_rule", e); Theorem result(newRWTheorem(e,output,Assumptions::emptyAssump(),pf)); return result; } //! signExtendRule: pads the input e with topBit to length len Theorem BitvectorTheoremProducer::signExtendRule(const Expr& e) { if(CHECK_PROOFS) { CHECK_SOUND(BITVECTOR==e.getType().getExpr().getOpKind(), "input must be a bitvector. \n e = " + e.toString()); CHECK_SOUND(SX == e.getOpKind(), "input must be SX(e).\n e = " + e.toString()); CHECK_SOUND(SX != e[0].getOpKind(), "input cannot have nested SX.\n e = " + e.toString()); } Expr input0 = e[0]; //strip the top level SX applications while(SX == input0.getOpKind()) input0 = input0[0]; int bvLength = d_theoryBitvector->BVSize(e); int bvLength0 = d_theoryBitvector->BVSize(input0); Expr output; if(bvLength0 == bvLength) { output = input0; } else if(bvLength0 < bvLength) { std::vector k; int c = bvLength - bvLength0; Expr topBit = d_theoryBitvector->newBVExtractExpr(input0,bvLength0-1,bvLength0-1); while(c--) k.push_back(topBit); k.push_back(input0); output = d_theoryBitvector->newConcatExpr(k); } else output = d_theoryBitvector->newBVExtractExpr(input0, bvLength-1, 0); Proof pf; if(withProof()) pf = newPf("sign_extend_rule", e); Theorem result(newRWTheorem(e,output,Assumptions::emptyAssump(),pf)); return result; } //! bitExtractSXRule Theorem BitvectorTheoremProducer::bitExtractSXRule(const Expr& e, int i) { //little bit of cheating here. calling a rule from inside a rule. //just a shorthand Theorem thm = signExtendRule(e); Expr e_i = d_theoryBitvector->newBoolExtractExpr(e,i); Expr newE_i = d_theoryBitvector->newBoolExtractExpr(thm.getRHS(),i); Proof pf; if(withProof()) pf = newPf("bitExtract_SX_rule",e,rat(i)); Theorem result(newRWTheorem(e_i,newE_i,Assumptions::emptyAssump(),pf)); return result; } //! Pad the kids of SIGN BVLT/SIGN BVLE to make their bvLength equal Theorem BitvectorTheoremProducer::padBVSLTRule(const Expr& e, int len) { if(CHECK_PROOFS) { CHECK_SOUND((BVSLT == e.getOpKind() || BVSLE == e.getOpKind()) && e.arity()==2, "BitvectorTheoremProducer::padBVSLTRule: " "input must e be a BVSLT/BVSLE: e = " + e.toString()); CHECK_SOUND(BITVECTOR==e[0].getType().getExpr().getOpKind() && BITVECTOR==e[1].getType().getExpr().getOpKind(), "BitvectorTheoremProducer::padBVSLTRule: " "for BVMULT terms e[0],e[1] must be a BV: " + e.toString()); CHECK_SOUND(0<=len, "BitvectorTheoremProducer::padBVSLTRule: " "input len must be >=0 and an integer: len = " + int2string(len)); } Expr e0 = d_theoryBitvector->newSXExpr(e[0], len); Expr e1 = d_theoryBitvector->newSXExpr(e[1], len); int kind = e.getOpKind(); Expr output; if(kind == BVSLT) output = d_theoryBitvector->newBVSLTExpr(e0,e1); else output = d_theoryBitvector->newBVSLEExpr(e0,e1); Proof pf; if(withProof()) pf = newPf("pad_bvslt_rule", e); Theorem result(newRWTheorem(e,output,Assumptions::emptyAssump(),pf)); return result; } /*! input: e0 <=(s) e1. output depends on whether the topbits(MSB) of * e0 and e1 are constants. If they are constants then optimizations * are done, otherwise the following rule is implemented. * * e0 <=(s) e1 <==> (e0[n-1] AND NOT e1[n-1]) OR * (e0[n-1] = e1[n-1] AND e0[n-2:0] <= e1[n-2:0]) */ Theorem BitvectorTheoremProducer::signBVLTRule(const Expr& e, const Theorem& topBit0, const Theorem& topBit1){ if(CHECK_PROOFS) { CHECK_SOUND((BVSLT == e.getOpKind() || BVSLE == e.getOpKind()) && e.arity()==2, "BitvectorTheoremProducer::signedBVLTRule: " "input must e be a BVSLT/BVSLE: e = " + e.toString()); CHECK_SOUND(BITVECTOR==e[0].getType().getExpr().getOpKind() && BITVECTOR==e[1].getType().getExpr().getOpKind(), "BitvectorTheoremProducer::signedBVLTRule: " "for BVMULT terms e[0],e[1] must be a BV: " + e.toString()); } const Expr e0 = e[0]; const Expr e1 = e[1]; int e0len = d_theoryBitvector->BVSize(e0); int e1len = d_theoryBitvector->BVSize(e1); if(CHECK_PROOFS) { const Expr e0ext = d_theoryBitvector->newBVExtractExpr(e0,e0len-1,e0len-1); const Expr e1ext = d_theoryBitvector->newBVExtractExpr(e1,e1len-1,e1len-1); CHECK_SOUND(e0ext == topBit0.getLHS(), "BitvectorTheoremProducer::signedBVLTRule: " "topBit0.getLHS() is the un-rewritten form of MSB of e0\n" "topBit0 is screwed up: topBit0 = " + topBit0.getExpr().toString()); CHECK_SOUND(e1ext == topBit1.getLHS(), "BitvectorTheoremProducer::signedBVLTRule: " "topBit1.getLHS() is the un-rewritten form of MSB of e1\n" "topBit1 is screwed up: topBit1 = " + topBit1.getExpr().toString()); CHECK_SOUND(e0len == e1len, "BitvectorTheoremProducer::signedBVLTRule: " "both e[0] and e[1] must have the same length\n. e =" + e.toString()); } const Expr MSB0 = topBit0.getRHS(); const Expr MSB1 = topBit1.getRHS(); int eKind = e.getOpKind(); Expr output; //if both MSBs are constants, then we can optimize the output. we //know precisely the value of the signed comparison in cases where //topbit of e0 and e1 are constants. e.g. |-1\@t0 < 0\@t1 is clearly //|-TRUE. //-1 indicates that both topBits are not known to be BVCONSTS Rational b0 = -1; Rational b1 = -1; if(MSB0.getKind() == BVCONST) b0 = d_theoryBitvector->computeBVConst(MSB0); if(MSB1.getKind() == BVCONST) b1 = d_theoryBitvector->computeBVConst(MSB1); //useful expressions to be used below const Expr tExpr = d_theoryBitvector->trueExpr(); const Expr fExpr = d_theoryBitvector->falseExpr(); const Expr MSB0isZero = MSB0.eqExpr(bvZero()); const Expr MSB0isOne = MSB0.eqExpr(bvOne()); const Expr MSB1isZero = MSB1.eqExpr(bvZero()); const Expr MSB1isOne = MSB1.eqExpr(bvOne()); //handle single bit e0 <=(s) e1 in a special way. this is clumsy //(i.e. extra and redundant code) but much more efficient and easy //to read if(e0len == 1) { if(b0==0 && b1==0) output = eKind==BVSLT ? fExpr : tExpr; else if(b0==0 && b1==1) output = fExpr; else if(b0==1 && b1==0) output = tExpr; else if(b0==1 && b1==1) output = eKind==BVSLT ? fExpr : tExpr; else if(b0==0 && b1==-1) output = eKind==BVSLT ? fExpr : MSB1isZero; else if(b0==1 && b1==-1) output = eKind==BVSLT ? MSB1isZero : tExpr; else if(b0==-1 && b1==0) output = eKind==BVSLT ? MSB0isOne : tExpr; else if(b0==-1 && b1==1) output = eKind==BVSLT ? fExpr : MSB0isOne; else //both b0 and b1 are -1 output = eKind==BVSLT ? MSB0isOne.andExpr(MSB1isZero) : MSB0isOne.orExpr(MSB1isZero); } else { //useful expressions to be used below Expr newE0 = d_theoryBitvector->newBVExtractExpr(e0,e0len-2,0); Expr newE1 = d_theoryBitvector->newBVExtractExpr(e1,e1len-2,0); Expr newBVLT = eKind==BVSLT ? d_theoryBitvector->newBVLTExpr(newE0,newE1): d_theoryBitvector->newBVLEExpr(newE0,newE1); // Expr newBVLTreverse = // eKind==BVSLT ? // d_theoryBitvector->newBVLTExpr(newE1,newE0): // d_theoryBitvector->newBVLEExpr(newE1,newE0); //both MSBs are simultaneously constants if(-1 != b0 && -1 !=b1) { //e0 is negative and e1 is positive if(b0 == 1 && b1 == 0) output = tExpr; //e0 is positive and e1 is negative else if(b0 == 0 && b1 == 1) output = fExpr; //e0 = e1, so result is determined by the rest of the bits else { output = newBVLT; } } else if(-1 != b0 && -1 == b1) { //only b0 is a constant. Both topBits are not simultaneously constants. //if (b0==0) // e0 <=(s) e1 <==> NOT e1[n-1] AND e0[n-2:0] <= e1[n-2:0]) //else // e0 <=(s) e1 <==> NOT e1[n-1] OR (e1[n-1] AND e0[n-2:0] <= e1[n-2:0])) output = (b0==0) ? //means that b1 has to be 0 and e0[n-2:0] <= e1[n-2:0] MSB1isZero.andExpr(newBVLT) : //means that either b1 is 0 or (b1 is 1 and e0[n-2:0] <= e1[n-2:0]) MSB1isZero.orExpr(MSB1isOne.andExpr(newBVLT)); } else if(-1 == b0 && -1 != b1) { //only b1 is a constant. Both topBits are not simultaneously constants. //if (b1==0) // e0 <=(s) e1 <==> e0[n-1] OR (NOT e0[n-1] AND e0[n-2:0] <= e1[n-2:0])) //else // e0 <=(s) e1 <==> e0[n-1] AND e0[n-2:0] <= e1[n-2:0])) output = (b1==0) ? //means that either b0 must be 1 or (b0 = 0 and e0[n-2:0] <= e1[n-2:0]) MSB0isOne.orExpr(MSB0isZero.andExpr(newBVLT)) : //means that b0 must be 1 and e0[n-2:0] <= e1[n-2:0] MSB0isOne.andExpr(newBVLT); } else { //both top bits are not constants. //(e0[n-1] AND NOT e1[n-1]) Expr k0 = MSB0isOne.andExpr(MSB1isZero); //(e0[n-1] = e1[n-1]) Expr k1 = MSB0.eqExpr(MSB1); //e0 <=(s) e1 <==> (e0[n-1] AND NOT e1[n-1]) OR // (e0[n-1] = e1[n-1] AND e0[n-2:0] <= e1[n-2:0]) output = k0.orExpr(k1.andExpr(newBVLT)); } } Proof pf; if(withProof()) pf = newPf("sign_bvlt_rule", e); return newRWTheorem(e, output, Assumptions::emptyAssump(), pf); } /*! NOT(e[0][0] = e[0][1]) <==> e[0][0] = ~e[0][1] */ Theorem BitvectorTheoremProducer::notBVEQ1Rule(const Expr& e) { if(CHECK_PROOFS) { CHECK_SOUND(e.getKind() == NOT, "BitvectorTheoremProducer::notBVEQ1Rule: " "input kind must be a NOT:\n e = " + e.toString()); CHECK_SOUND(e[0].getOpKind() == EQ, "BitvectorTheoremProducer::notBVEQ1Rule: " "e[0] must be EQ: \n e = " + e.toString()); CHECK_SOUND(d_theoryBitvector->BVSize(e[0][0]) == 1, "BitvectorTheoremProducer::notBVEQ1Rule: " "BVSize(e[0][0]) must be 1: \n e = " + e.toString()); } Expr output = e[0][0].eqExpr(d_theoryBitvector->newBVNegExpr(e[0][1])); Proof pf; if(withProof()) pf = newPf("not_eq1_rule", e); return newRWTheorem(e, output, Assumptions::emptyAssump(), pf); } /*! NOT(e[0][0] < e[0][1]) <==> (e[0][1] <= e[0][0]), * NOT(e[0][0] <= e[0][1]) <==> (e[0][1] < e[0][0]) */ Theorem BitvectorTheoremProducer::notBVLTRule(const Expr& e) { if(CHECK_PROOFS) { CHECK_SOUND(e.getKind() == NOT, "BitvectorTheoremProducer::notBVLTRule: " "input kind must be a NOT:\n e = " + e.toString()); CHECK_SOUND(e[0].getOpKind() == BVLT || e[0].getOpKind() == BVLE, "BitvectorTheoremProducer::notBVLTRule: " "e[0] must be BVLT or BVLE: \n e = " + e.toString()); } Expr output; const Expr& e00 = e[0][0]; const Expr& e01 = e[0][1]; if(BVLT == e[0].getOpKind()) output = d_theoryBitvector->newBVLEExpr(e01,e00); else output = d_theoryBitvector->newBVLTExpr(e01,e00); Proof pf; if(withProof()) pf = newPf("not_bvlt_rule", e); return newRWTheorem(e, output, Assumptions::emptyAssump(), pf); } //! if(lhs==rhs) then we have (lhs < rhs <==> false),(lhs <= rhs <==> true) Theorem BitvectorTheoremProducer::lhsEqRhsIneqn(const Expr& e, int kind) { if(CHECK_PROOFS) { CHECK_SOUND(BVLT == e.getOpKind() || BVLE == e.getOpKind(), "BitvectorTheoremProducer::lhsEqRhsIneqn: " "input kind must be BVLT or BVLE: e = " + e.toString()); CHECK_SOUND(kind == e.getOpKind(), "BitvectorTheoremProducer::lhsEqRhsIneqn: " "input kind must match e.getOpKind(): " "\n e = " + e.toString()); CHECK_SOUND((e.arity()==2) && (e[0]==e[1]), "BitvectorTheoremProducer::lhsEqRhsIneqn: " "input arity must be 2, and e[0] must be equal to e[1]: " "\ne = " + e.toString()); } Expr output; if(kind == BVLT) output = d_theoryBitvector->falseExpr(); else output = d_theoryBitvector->trueExpr(); Proof pf; if(withProof()) pf = newPf("lhs_eq_rhs_ineqn", e); return newRWTheorem(e, output, Assumptions::emptyAssump(), pf); } //! |= 0 <= foo <-> TRUE Theorem BitvectorTheoremProducer::zeroLeq(const Expr& e) { if(CHECK_PROOFS) { CHECK_SOUND(BVLE == e.getOpKind(), "BitvectorTheoremProducer::zeroLeq: " "input kind must be BVLE: e = " + e.toString()); CHECK_SOUND(e.arity()==2 && e[0].getOpKind() == BVCONST && d_theoryBitvector->computeBVConst(e[0]) == 0, "BitvectorTheoremProducer::zeroLeq: " "unexpected input: e = " + e.toString()); } Proof pf; if(withProof()) pf = newPf("zeroLeq", e); return newRWTheorem(e, d_theoryBitvector->trueExpr(), Assumptions::emptyAssump(), pf); } //! if indeed e[0] < e[1] then (e<==>true) else (e<==>false) Theorem BitvectorTheoremProducer::bvConstIneqn(const Expr& e, int kind) { if(CHECK_PROOFS) { CHECK_SOUND(BVLT == e.getOpKind() || BVLE == e.getOpKind(), "BitvectorTheoremProducer::bvConstIneqn: " "input kind must be BVLT or BVLE: e = " + e.toString()); CHECK_SOUND(kind == e.getOpKind(), "BitvectorTheoremProducer::bvConstIneqn: " "input kind must match e.getOpKind(): " "\n e = " + e.toString()); CHECK_SOUND((e.arity()==2), "BitvectorTheoremProducer::bvConstIneqn: " "input arity must be 2: \ne = " + e.toString()); CHECK_SOUND(BVCONST == e[0].getKind() && BVCONST == e[1].getKind(), "BitvectorTheoremProducer::bvConstIneqn: " "e[0] and e[1] must both be constants:\n e = " + e.toString()); } int e0len = d_theoryBitvector->BVSize(e[0]); int e1len = d_theoryBitvector->BVSize(e[1]); if(CHECK_PROOFS) CHECK_SOUND(e0len == e1len, "BitvectorTheoremProducer::bvConstIneqn: " "e[0] and e[1] must have the same bvLength:\ne = " + e.toString()); Rational lhsVal = d_theoryBitvector->computeBVConst(e[0]); Rational rhsVal = d_theoryBitvector->computeBVConst(e[1]); Expr output; if(BVLT == kind) { if(lhsVal < rhsVal) output = d_theoryBitvector->trueExpr(); else output = d_theoryBitvector->falseExpr(); } else { if(lhsVal <= rhsVal) output = d_theoryBitvector->trueExpr(); else output = d_theoryBitvector->falseExpr(); } Proof pf; if(withProof()) pf = newPf("bv_const_ineqn", e); return newRWTheorem(e, output, Assumptions::emptyAssump(), pf); } // Input: e: a op b, where op is < or <= // lhs_i: BOOLEXTRACT(a,i) <=> b1 // rhs_i: BOOLEXTRACT(b,i) <=> b2 // kind: op // i = BVSize(a)-1 = BVSize(b)-1 // Output: for i > 0: // (lhs_i < rhs_i) OR (lhs_i = rhs_i AND a[i-1:0] op b[i-1:0]) // for i = 0: // (lhs_i op rhs_i) Theorem BitvectorTheoremProducer::generalIneqn(const Expr& e, const Theorem& lhs_i, const Theorem& rhs_i, int kind) { if(CHECK_PROOFS) { CHECK_SOUND(BVLT == e.getOpKind() || BVLE == e.getOpKind(), "BitvectorTheoremProducer::generalIneqn: " "input kind must be BVLT or BVLE: e = " + e.toString()); CHECK_SOUND(kind == e.getOpKind(), "BitvectorTheoremProducer::generalIneqn: " "input kind must match e.getOpKind(): " "\n e = " + e.toString()); CHECK_SOUND((e.arity()==2), "BitvectorTheoremProducer::generalIneqn: " "input arity must be 2: \ne = " + e.toString()); CHECK_SOUND(lhs_i.isRewrite() && rhs_i.isRewrite(), "BitvectorTheoremProducer::generalIneqn: " "lhs_i and rhs_i must be rewrite theorems: " "\nlhs_i = " + lhs_i.toString() + "\nrhs_i = " + rhs_i.toString()); } int e0len = d_theoryBitvector->BVSize(e[0]); int e1len = d_theoryBitvector->BVSize(e[1]); const Expr& e0_iBit = lhs_i.getLHS(); const Expr& e1_iBit = rhs_i.getLHS(); if(CHECK_PROOFS) { CHECK_SOUND(BOOLEXTRACT == e0_iBit.getOpKind() && BOOLEXTRACT == e1_iBit.getOpKind(), "BitvectorTheoremProducer::generalIneqn: " "lhs_i.getRHS() and rhs_i.getRHS() must be BOOLEXTRACTs:" "\nlhs_i = " + lhs_i.toString() + "\nrhs_i = " + rhs_i.toString()); CHECK_SOUND(e[0] == e0_iBit[0], "BitvectorTheoremProducer::generalIneqn: " "e[0] must be equal to LHS of lhs_i: \nlhs_i = " + lhs_i.toString() + "\n e[0] = " + e[0].toString()); CHECK_SOUND(e[1] == e1_iBit[0], "BitvectorTheoremProducer::generalIneqn: " "e[1] must be equal to LHS of rhs_i: \nrhs_i = " + rhs_i.toString() + "\n e[1] = " + e[1].toString()); CHECK_SOUND(e0len == e1len, "BitvectorTheoremProducer::generalIneqn: " "e[0] and e[1] must have the same bvLength:\ne = " + e.toString()); int e0_iBitIndex = d_theoryBitvector->getBoolExtractIndex(e0_iBit); int e1_iBitIndex = d_theoryBitvector->getBoolExtractIndex(e1_iBit); CHECK_SOUND(e0_iBitIndex == e1_iBitIndex && e0_iBitIndex == e0len-1, "BitvectorTheoremProducer::generalIneqn: " "e0_iBit & e1_iBit must have same extract index: " "\ne0_iBit = " + e0_iBit.toString() + "\ne1_iBit = " + e1_iBit.toString()); } const Expr& b1 = lhs_i.getRHS(); const Expr& b2 = rhs_i.getRHS(); const Expr& trueExpression = d_theoryBitvector->trueExpr(); const Expr& falseExpression = d_theoryBitvector->falseExpr(); if(CHECK_PROOFS) { CHECK_SOUND(b1.getType().isBool(), "BitvectorTheoremProducer::generalIneqn: " "b1 must be a boolean type: " "\n b1 = " + b1.toString()); CHECK_SOUND(b2.getType().isBool(), "BitvectorTheoremProducer::generalIneqn: " "b2 must be boolean type: " "\n b2 = " + b2.toString()); } Expr output; // Check for the shortcuts if (b1.isFalse() && b2.isTrue()) // b1 < b2 output = trueExpression; else if (b1.isTrue() && b2.isFalse()) // b1 > b2 output = falseExpression; else if (e0len==1) { // If this is the last bit, and one of them is a constant if (kind==BVLE && (b1.isFalse() || b2.isTrue())) // F <= x or x <= T output = trueExpression; else if (kind==BVLT && (b2.isFalse() || b1.isTrue())) // x < F or T < x output = falseExpression; } // No shortcuts found if (output.isNull()) { // Process the top bits if (kind == BVLT || e0len > 1) { output = (!b1) && b2; } else { output = (!b1) || b2; } if(e0len > 1) { //construct e0[n-2:0] Expr e0_extract = d_theoryBitvector->newBVExtractExpr(e[0],e0len-2,0); //construct e1[n-2:0] Expr e1_extract = d_theoryBitvector->newBVExtractExpr(e[1],e1len-2,0); Expr a; if(kind==BVLT) //construct e0[n-2:0] < e1[n-2:0] a = d_theoryBitvector->newBVLTExpr(e0_extract,e1_extract); else //construct e0[n-2:0] <= e1[n-2:0] a = d_theoryBitvector->newBVLEExpr(e0_extract,e1_extract); //construct (b1=0 and/or b2=1) or (b1=b2 and a) output = output || (b1.iffExpr(b2) && a); } } Proof pf; if(withProof()) pf = newPf("general_ineqn", e); return newRWTheorem(e, output, Assumptions::emptyAssump(), pf); } /////////////////////////////////////////////////////////////////////// // BitExtracting rules for terms /////////////////////////////////////////////////////////////////////// // Input: |- BOOLEXTRACT(a,0) <=> bc_0, ... BOOLEXTRACT(a,n-1) <=> bc_(n-1) // where each bc_0 is TRUE or FALSE // Output: |- a = c // where c is an n-bit constant made from the values bc_0..bc_(n-1) Theorem BitvectorTheoremProducer::bitExtractAllToConstEq(vector& thms) { if (CHECK_PROOFS) { CHECK_SOUND(thms.size() > 0, "Expected size > 0"); unsigned i; for(i = 0; i < thms.size(); ++i) { Expr e = thms[i].getExpr(); CHECK_SOUND(e.getKind() == IFF && e.arity() == 2 && e[1].isBoolConst(), "Unexpected structure"); CHECK_SOUND(e[0].getOpKind() == BOOLEXTRACT && e[0].arity() == 1 && e[0][0] == thms[0].getExpr()[0][0] && unsigned(d_theoryBitvector->getBoolExtractIndex(e[0])) == i, "Unexpected structure"); } } Expr lhs = thms[0].getExpr()[0][0]; vector bits; for (unsigned i = 0; i < thms.size(); ++i) { bits.push_back(thms[i].getExpr()[1].isTrue() ? true : false); } Expr rhs = d_theoryBitvector->newBVConstExpr(bits); Assumptions a(thms); Proof pf; if (withProof()) pf = newPf("bit_extract_all_to_const_eq"); return newRWTheorem(lhs, rhs, a, pf); } //! t[i] ==> t[i:i] = 0bin1 or NOT t[i] ==> t[i:i] = 0bin0 Theorem BitvectorTheoremProducer::bitExtractToExtract(const Theorem& thm) { const Expr& e = thm.getExpr(); if(CHECK_PROOFS) { CHECK_SOUND((e.isNot() && e[0].getOpKind() == BOOLEXTRACT) || (e.getOpKind() == BOOLEXTRACT), "BitvectorTheoremProducer::bitExtractToExtract:\n e = " +e.toString()); } bool negative = e.isNot(); const Expr& boolExtract = negative? e[0] : e; int i = d_theoryBitvector->getBoolExtractIndex(boolExtract); Expr lhs = d_theoryBitvector->newBVExtractExpr(boolExtract[0], i, i); Proof pf; if(withProof()) pf = newPf("bit_extract_to_extract", e, thm.getProof()); return newRWTheorem(lhs, negative? bvZero() : bvOne(), thm.getAssumptionsRef(), pf); } //! t[i] <=> t[i:i][0] (to use rewriter for simplifying t[i:i]) Theorem BitvectorTheoremProducer::bitExtractRewrite(const Expr& x) { if(CHECK_PROOFS) { CHECK_SOUND(x.getOpKind() == BOOLEXTRACT, "BitvectorTheoremProducer::bitExtractRewrite: x = " +x.toString()); } int i = d_theoryBitvector->getBoolExtractIndex(x); const Expr& t = x[0]; int bvLength = d_theoryBitvector->BVSize(t); if(CHECK_PROOFS) { CHECK_SOUND(0<=i && inewBVExtractExpr(t, i, i); res = d_theoryBitvector->newBoolExtractExpr(res, 0); return newRWTheorem(x, res, Assumptions::emptyAssump(), pf); } // |- BOOLEXTRACT(x,i) <=> *Boolean value of x[i]* Theorem BitvectorTheoremProducer::bitExtractConstant(const Expr & x, int i) { TRACE("bitvector", "bitExtractConstant(", x, ", "+ int2string(i) +" ) {"); if(CHECK_PROOFS) { //check if the expr is indeed a bitvector constant. CHECK_SOUND(BVCONST == x.getKind(), "BitvectorTheoremProducer::bitExtractConstant:" "the bitvector must be a constant."); //check if 0<= i < bvLength of bitvector constant CHECK_SOUND(0 <= i && (unsigned)i < d_theoryBitvector->getBVConstSize(x), "BitvectorTheoremProducer::bitExtractConstant:" "illegal extraction attempted on the bitvector x = " + x.toString() + "\nat the position i = " + int2string(i)); } // bool-extract of the bitvector constant const Expr bitExtract = d_theoryBitvector->newBoolExtractExpr(x, i); //extract the actual expr_value string, bitextract it at i and check //if the value is 'false'. if so then return c[i] <==> false else //return c[i] <==> true. Expr output; if(!d_theoryBitvector->getBVConstValue(x, i)) output = d_theoryBitvector->falseExpr(); else output = d_theoryBitvector->trueExpr(); Proof pf; if(withProof()) pf = newPf("bit_extract_constant", x, rat(i)); Theorem result(newRWTheorem(bitExtract,output,Assumptions::emptyAssump(),pf)); TRACE("bitvector", "bitExtractConstant => ", result, " }"); return result; } // Input: x: a_0 \@ ... \@ a_n, // i: bitposition // Output |- BOOLEXTRACT(a_0 \@ ... \@ a_n, i) <=> BOOLEXTRACT(a_j, k) // where j and k are determined by structure of CONCAT Theorem BitvectorTheoremProducer::bitExtractConcatenation(const Expr & x, int i) { TRACE("bitvector", "bitExtractConcatenation(", x.toString(), ", "+ int2string(i) + " ) {"); Type type = d_theoryBitvector->getBaseType(x); if(CHECK_PROOFS) { //check if the expr is indeed a bitvector term and a concat. CHECK_SOUND(BITVECTOR == type.getExpr().getOpKind(), "BitvectorTheoremProducer::bitExtractConcatenation: " "term must be bitvector:\n x = "+x.toString()); CHECK_SOUND(CONCAT == x.getOpKind() && x.arity() >= 2, "BitvectorTheoremProducer::bitExtractConcatenation: " "the bitvector must be a concat:\n x = " + x.toString()); } //check if 0<= i < bvLength of bitvector constant int bvLength = d_theoryBitvector->BVSize(x); if(CHECK_PROOFS) { CHECK_SOUND(0 <= i && i < bvLength, "BitvectorTheoremProducer::bitExtractNot:" "illegal boolean extraction was attempted at position i = " + int2string(i) + "\non bitvector x = " + x.toString() + "\nwhose bvLength is = " + int2string(bvLength)); } // bool-extract of the bitvector constant const Expr bitExtract = d_theoryBitvector->newBoolExtractExpr(x, i); int numOfKids = x.arity(); int lenOfKidsSeen = 0; Expr bitExtractKid; for(int count = numOfKids-1; count >= 0; --count) { int bvLengthOfKid = d_theoryBitvector->BVSize(x[count]); if(lenOfKidsSeen <= i && i < bvLengthOfKid + lenOfKidsSeen) { bitExtractKid = d_theoryBitvector->newBoolExtractExpr(x[count], i - lenOfKidsSeen); break; } lenOfKidsSeen += bvLengthOfKid; } DebugAssert(!bitExtractKid.isNull(), "BitvectorTheoremProducer::bitExtractConcatenation: " "something's broken..."); Proof pf; if(withProof()) pf = newPf("bit_extract_concatenation", x, rat(i)); Theorem result(newRWTheorem(bitExtract, bitExtractKid, Assumptions::emptyAssump(), pf)); TRACE("bitvector", "bitExtractConcatenation => ", result, " }"); return result; } // |- BOOLEXTRACT(BVMULT(c,t),i) <=> BOOLEXTRACT(t',i) where t' is not a BVMULT Theorem BitvectorTheoremProducer::bitExtractConstBVMult(const Expr& t, int i) { TRACE("bitvector", "input to bitExtractConstBVMult(", t.toString(), ")"); TRACE("bitvector", "input to bitExtractConstBVMult(", int2string(i), ")"); Type type = t.getType(); int bvLength = d_theoryBitvector->BVSize(t); if(CHECK_PROOFS) { CHECK_SOUND(BITVECTOR == type.getExpr().getOpKind(), "BitvectorTheoremProducer::bitExtractConstBVMult:" "the term must be a bitvector: " + t.toString()); CHECK_SOUND(BVMULT == t.getOpKind() && 2 == t.arity(), "BitvectorTheoremProducer::bitExtractConstBVMult:" "the term must be a MULT of arity 2: " + t.toString()); CHECK_SOUND(d_theoryBitvector->BVSize(t[0]) == bvLength && d_theoryBitvector->BVSize(t[1]) == bvLength, "BitvectorTheoremProducer::bitExtractConstBVMult:" "Expected inputs of same length"); CHECK_SOUND(0 <= i && i < bvLength, "BitvectorTheoremProducer::bitExtractNot:" "illegal boolean extraction was attempted at position i = " + int2string(i) + "\non bitvector x = " + t.toString() + "\nwhose bvLength is = " + int2string(bvLength)); CHECK_SOUND(BVCONST == t[0].getKind(), "BitvectorTheoremProducer::bitExtractConstBVMult:" "illegal BVMULT expression" + t.toString()); } std::vector k; for(int j=0; j < bvLength; ++j) if (d_theoryBitvector->getBVConstValue(t[0], j)) { Expr leftshiftTerm = d_theoryBitvector->newFixedConstWidthLeftShiftExpr(t[1], j); k.push_back(leftshiftTerm); } Expr mult; //size of k will always be >= 0 switch(k.size()) { case 0: //the vector k will remain empty if all bits in coeff are 0's mult = d_theoryBitvector->newBVZeroString(bvLength); break; case 1: mult = k[0]; break; default: mult = d_theoryBitvector->newBVPlusExpr(bvLength, k); break; } Expr output = d_theoryBitvector->newBoolExtractExpr(mult, i); // bool-extract of the bitvector term const Expr bitExtract = d_theoryBitvector->newBoolExtractExpr(t, i); Proof pf; if(withProof()) pf = newPf("bit_extract_const_bvmult", t, rat(i)); const Theorem result = newRWTheorem(bitExtract,output,Assumptions::emptyAssump(),pf); TRACE("bitvector", "output of bitExtract_const_bvmult(", result, ")"); return result; } // |- BOOLEXTRACT(t,i) <=> BOOLEXTRACT(t',i) where t' is not BVMULT Theorem BitvectorTheoremProducer::bitExtractBVMult(const Expr& t, int i) { TRACE("bitvector", "input to bitExtractBVMult(", t.toString(), ")"); TRACE("bitvector", "input to bitExtractBVMult(", int2string(i), ")"); Type type = t.getType(); int bvLength= d_theoryBitvector->BVSize(t); if(CHECK_PROOFS) { CHECK_SOUND(BITVECTOR == type.getExpr().getOpKind(), "BitvectorTheoremProducer::bitExtractBVMult:" "the term must be a bitvector" + t.toString()); CHECK_SOUND(BVMULT == t.getOpKind() && 2 == t.arity(), "BitvectorTheoremProducer::bitExtractBVMult:" "the term must be a bitvector" + t.toString()); CHECK_SOUND(d_theoryBitvector->BVSize(t[0]) == bvLength && d_theoryBitvector->BVSize(t[1]) == bvLength, "BitvectorTheoremProducer::bitExtractConstBVMult:" "Expected inputs of same length"); CHECK_SOUND(0 <= i && i < bvLength, "BitvectorTheoremProducer::bitExtractNot:" "illegal boolean extraction was attempted at position i = " + int2string(i) + "\non bitvector t = " + t.toString() + "\nwhose Length is = " + int2string(bvLength)); CHECK_SOUND(BVCONST != t[0].getOpKind(), "BitvectorTheoremProducer::bitExtractBVMult:" "illegal BVMULT expression" + t.toString()); } Expr trueExpression = d_theoryBitvector->trueExpr(); std::vector k; for(int j=bvLength-1; j >= 0; j--) { Expr ext = d_theoryBitvector->newBVExtractExpr(t[0],j,j); Expr cond = ext.eqExpr(d_theoryBitvector->newBVOneString(1)); Expr leftshiftTerm = d_theoryBitvector->newFixedConstWidthLeftShiftExpr(t[1], j); Expr zeroString = d_theoryBitvector->newBVZeroString(bvLength); Expr iteTerm = cond.iteExpr(leftshiftTerm, zeroString); k.push_back(iteTerm); } if(CHECK_PROOFS) CHECK_SOUND(k.size() > 0, "BitvectorTheoremProducer::bitExtractBVMult:" "size of output vector must be > 0"); Expr mult; if (k.size() > 1) mult = d_theoryBitvector->newBVPlusExpr(bvLength, k); else mult = k[0]; Expr output = d_theoryBitvector->newBoolExtractExpr(mult, i); // bool-extract of the bitvector term const Expr bitExtract = d_theoryBitvector->newBoolExtractExpr(t, i); Proof pf; if(withProof()) pf = newPf("bit_extract_bvmult", t, rat(i)); const Theorem result = newRWTheorem(bitExtract,output,Assumptions::emptyAssump(),pf); TRACE("bitvector","output of bitExtract_bvmult(", result, ")"); return result; } // Input x: a[hi:low] // i: bitposition // Output: |- BOOLEXTRACT(a[hi:low], i) <=> BOOLEXTRACT(a, i+low) Theorem BitvectorTheoremProducer::bitExtractExtraction(const Expr & x, int i) { TRACE("bitvector", "input to bitExtractExtraction(", x.toString(), ")"); TRACE("bitvector", "input to bitExtractExtraction(", int2string(i), ")"); Type type = x.getType(); if(CHECK_PROOFS) { //check if the expr is indeed a bitvector term and a concat. CHECK_SOUND(BITVECTOR == type.getExpr().getOpKind(), "BitvectorTheoremProducer::bitExtract-Extraction:" "term must be bitvector."); CHECK_SOUND(EXTRACT == x.getOpKind() && 1 == x.arity(), "BitvectorTheoremProducer::bitExtract-Extraction:" "the bitvector must be an extract." + x.toString()); //check if 0<= i < bvLength of bitvector constant int bvLength= d_theoryBitvector->BVSize(type.getExpr()); CHECK_SOUND(0 <= i && i < bvLength, "BitvectorTheoremProducer::bitExtractNot:" "illegal boolean extraction was attempted at position i = " + int2string(i) + "\non bitvector t = " + x.toString() + "\nwhose Length is = " + int2string(bvLength)); int extractLeft = d_theoryBitvector->getExtractHi(x); int extractRight = d_theoryBitvector->getExtractLow(x); CHECK_SOUND(extractLeft >= extractRight && extractLeft >= 0, "BitvectorTheoremProducer::bitExtract-Extraction:" "illegal boolean extraction was attempted." + int2string(i) + int2string(extractLeft) + int2string(extractRight)); CHECK_SOUND(0 <= i && i < extractLeft-extractRight+1, "BitvectorTheoremProducer::bitExtract-Extraction:" "illegal boolean extraction was attempted." + int2string(i) + int2string(extractLeft) + int2string(extractRight)); } // bool-extract of the bitvector constant const Expr bitExtract = d_theoryBitvector->newBoolExtractExpr(x, i); const Expr bitExtractExtraction = d_theoryBitvector->newBoolExtractExpr(x[0], i + d_theoryBitvector->getExtractLow(x)); Proof pf; if(withProof()) pf = newPf("bit_extract_extraction", x, rat(i)); Theorem result(newRWTheorem(bitExtract, bitExtractExtraction, Assumptions::emptyAssump(), pf)); TRACE("bitvector", "output of bitExtractExtraction(", result, ")"); return result; } Theorem BitvectorTheoremProducer:: bitExtractBVPlus(const std::vector& t1BitExtractThms, const std::vector& t2BitExtractThms, const Expr& bvPlusTerm, int bitPos) { TRACE("bitvector","input to bitExtractBVPlus(", bvPlusTerm.toString(), ")"); TRACE("bitvector","input to bitExtractBVPlus(", int2string(bitPos), ")"); if(CHECK_PROOFS) { CHECK_SOUND(BVPLUS == bvPlusTerm.getOpKind() && 2 == bvPlusTerm.arity(), "BitvectorTheoremProducer::bitExtractBVPlus: illegal bitvector fed to the function." + bvPlusTerm.toString()); CHECK_SOUND(d_theoryBitvector->getBVPlusParam(bvPlusTerm) >= 0, "BitvectorTheoremProducer::bitExtractBVPlus: illegal bitvector fed to the function." + bvPlusTerm.toString()); CHECK_SOUND(bitPos+1 == (int)t1BitExtractThms.size() && bitPos+1 == (int)t2BitExtractThms.size(), "BitvectorTheoremProducer::bitExtractBVPlus: illegal bitvector fed to the function." + int2string(bitPos)); const Expr& t1 = bvPlusTerm[0]; const Expr& t2 = bvPlusTerm[1]; std::vector::const_iterator i = t1BitExtractThms.begin(); std::vector::const_iterator iend = t1BitExtractThms.end(); std::vector::const_iterator j = t2BitExtractThms.begin(); for(; i !=iend; ++i, ++j) { const Expr& t1Expr = i->getLHS(); const Expr& t2Expr = j->getLHS(); CHECK_SOUND(t1Expr[0] == t1 && t2Expr[0] == t2, "BitvectorTheoremProducer::bitExtractBVPlus: illegal bitvector fed to the function." + t1Expr.toString() + " ==\n" + t1.toString() + "\n" + t2.toString() + " == \n" + t2Expr.toString()); } } const Expr lhs = d_theoryBitvector->newBoolExtractExpr(bvPlusTerm, bitPos); Expr rhs; const Expr& t1_iBit = (t1BitExtractThms[bitPos]).getRHS(); const Expr& t2_iBit = (t2BitExtractThms[bitPos]).getRHS(); if(0 != bitPos) { const Expr carry_iBit = computeCarry(t1BitExtractThms, t2BitExtractThms, bitPos); //constructing an XOR of 3 exprs using equivalences. Note that (x //\xor y \xor z) is the same as (x \iff y \iff z). but remember, x //\xor y is not the same as x \iff y, but is equal instead to x //\neg\iff y rhs = t1_iBit.iffExpr(t2_iBit).iffExpr(carry_iBit); //cout << "the addition output is : " << rhs.toString() << "\n"; //TRACE("bitvector", // "output of bitExtractBVPlus(", carry_iBit.toString(), ")"); } else //bitblasting the 0th bit. construct NOT(t1_iBit <=> t2_iBit) rhs = !(t1_iBit.iffExpr(t2_iBit)); Proof pf; if(withProof()) pf = newPf("bit_extract_BVPlus_rule",bvPlusTerm,rat(bitPos)); Theorem result = newRWTheorem(lhs, rhs, Assumptions::emptyAssump(), pf); TRACE("bitvector","output of bitExtractBVPlus(", result, ")"); return result; } Expr BitvectorTheoremProducer::computeCarry(const std::vector& t1BitExtractThms, const std::vector& t2BitExtractThms, int i){ vector carry; int bitPos = i; DebugAssert(bitPos >= 0, "computeCarry: negative bitExtract_Pos is illegal"); if(0 == bitPos) { const Expr& t1Thm = t1BitExtractThms[bitPos].getRHS(); const Expr& t2Thm = t2BitExtractThms[bitPos].getRHS(); carry.push_back(t1Thm.andExpr(t2Thm)); } else { const Expr& t1Thm = t1BitExtractThms[bitPos-1].getRHS(); const Expr& t2Thm = t2BitExtractThms[bitPos-1].getRHS(); const Expr iMinusOneTerm = t1Thm.andExpr(t2Thm); carry.push_back(iMinusOneTerm); const Expr iMinusOneCarry = computeCarry(t1BitExtractThms,t2BitExtractThms,bitPos-1); const Expr secondTerm = t1Thm.andExpr(iMinusOneCarry); carry.push_back(secondTerm); const Expr thirdTerm = t2Thm.andExpr(iMinusOneCarry); carry.push_back(thirdTerm); } return orExpr(carry); } Theorem BitvectorTheoremProducer:: bitExtractBVPlusPreComputed(const Theorem& t1_i, const Theorem& t2_i, const Expr& bvPlusTerm, int bitPos, int precomputedFlag) { DebugAssert(0 != precomputedFlag, "precomputedFlag cannot be 0"); TRACE("bitvector","input to bitExtractBVPlus(", bvPlusTerm.toString(), ")"); TRACE("bitvector","input to bitExtractBVPlus(", int2string(bitPos), ")"); if(CHECK_PROOFS) { CHECK_SOUND(BVPLUS == bvPlusTerm.getOpKind() && 2 == bvPlusTerm.arity(), "BitvectorTheoremProducer::bitExtractBVPlus:" "illegal bitvector fed to the function." + bvPlusTerm.toString()); CHECK_SOUND(d_theoryBitvector->getBVPlusParam(bvPlusTerm) >= 0, "BitvectorTheoremProducer::bitExtractBVPlus:" "illegal bitvector fed to the function." + bvPlusTerm.toString()); const Expr& t1 = bvPlusTerm[0]; const Expr& t2 = bvPlusTerm[1]; CHECK_SOUND(t1_i.getLHS()[0] == t1 && t2_i.getLHS()[0] == t2, "BitvectorTheoremProducer::bitExtractBVPlus:" "illegal theorems fed to the function. Theorem1 = " + t1_i.toString() + "\nTheorem2 = " + t2_i.toString()); CHECK_SOUND(t1_i.getLHS().getOpKind() == BOOLEXTRACT && t2_i.getLHS().getOpKind() == BOOLEXTRACT, "BitvectorTheoremProducer::bitExtractBVPlus:" "illegal theorems fed to the function. Theorem1 = " + t1_i.toString() + "\nTheorem2 = " + t2_i.toString()); CHECK_SOUND(d_theoryBitvector->getBoolExtractIndex(t1_i.getLHS()) == bitPos && d_theoryBitvector->getBoolExtractIndex(t2_i.getLHS()) == bitPos, "BitvectorTheoremProducer::bitExtractBVPlus:" "illegal theorems fed to the function. Theorem1 = " + t1_i.toString() + "\nTheorem2 = " + t2_i.toString()); } const Expr lhs = d_theoryBitvector->newBoolExtractExpr(bvPlusTerm, bitPos); Expr rhs; const Expr& t1_iBit = t1_i.getRHS(); const Expr& t2_iBit = t2_i.getRHS(); const Expr carry_iBit = computeCarryPreComputed(t1_i, t2_i, bitPos, precomputedFlag); if(0 != bitPos) { //constructing an XOR of 3 exprs using equivalences. Note that (x //\xor y \xor z) is the same as (x \iff y \iff z). but remember, x //\xor y is not the same as x \iff y, but is equal instead to x //\neg\iff y rhs = t1_iBit.iffExpr(t2_iBit).iffExpr(carry_iBit); //cout << "the addition output is : " << rhs.toString() << "\n"; } else //bitblasting the 0th bit. construct NOT(t1_iBit <=> t2_iBit) rhs = !(t1_iBit.iffExpr(t2_iBit)); Proof pf; if(withProof()) pf = newPf("bit_extract_BVPlus_precomputed_rule",bvPlusTerm,rat(bitPos)); Theorem result = newRWTheorem(lhs, rhs, Assumptions::emptyAssump(), pf); TRACE("bitvector","output of bitExtractBVPlus(", result, ")"); return result; } //! compute carryout of the current bits and cache them, and return //carryin of the current bits Expr BitvectorTheoremProducer:: computeCarryPreComputed(const Theorem& t1_i, const Theorem& t2_i, int bitPos, int preComputed){ DebugAssert(1 == preComputed || 2 == preComputed, "cannot happen"); Expr carryout; Expr carryin; DebugAssert(bitPos >= 0, "computeCarry: negative bitExtract_Pos is illegal"); const Expr& t1Thm = t1_i.getRHS(); const Expr& t2Thm = t2_i.getRHS(); Expr x = t1Thm.andExpr(t2Thm); const Expr& t1 = t1_i.getLHS()[0]; const Expr& t2 = t2_i.getLHS()[0]; Expr t1Andt2 = t1.andExpr(t2); Expr index = t1Andt2.andExpr(rat(bitPos)); if(0 == bitPos) { if(1 == preComputed) d_theoryBitvector->d_bvPlusCarryCacheLeftBV.insert(index,x); else d_theoryBitvector->d_bvPlusCarryCacheRightBV.insert(index,x); carryout = x; //carry.push_back(x); } else { if(1 == preComputed) { Expr indexMinusOne = t1Andt2.andExpr(rat(bitPos-1)); if(d_theoryBitvector->d_bvPlusCarryCacheLeftBV.find(indexMinusOne) == d_theoryBitvector->d_bvPlusCarryCacheLeftBV.end()) DebugAssert(false, "this should not happen"); carryin = (d_theoryBitvector->d_bvPlusCarryCacheLeftBV).find(indexMinusOne)->second; Expr secondTerm = t1Thm.andExpr(carryin); Expr thirdTerm = t2Thm.andExpr(carryin); carryout = (x.orExpr(secondTerm)).orExpr(thirdTerm); d_theoryBitvector->d_bvPlusCarryCacheLeftBV.insert(index,carryout); } else { Expr indexMinusOne = t1Andt2.andExpr(rat(bitPos-1)); if(d_theoryBitvector->d_bvPlusCarryCacheRightBV.find(indexMinusOne) == d_theoryBitvector->d_bvPlusCarryCacheRightBV.end()) DebugAssert(false, "this should not happen"); carryin = (d_theoryBitvector->d_bvPlusCarryCacheRightBV).find(indexMinusOne)->second; //(*d_bvPlusCarryCacheRightBV.find(indexMinusOne)).second; Expr secondTerm = t1Thm.andExpr(carryin); Expr thirdTerm = t2Thm.andExpr(carryin); carryout = (x.orExpr(secondTerm)).orExpr(thirdTerm); d_theoryBitvector->d_bvPlusCarryCacheRightBV.insert(index,carryout); } } //cout << "the carry for" << index << " is : " << carryout << "\n"; return carryin; } Theorem BitvectorTheoremProducer:: zeroPaddingRule(const Expr& e, int i) { if(CHECK_PROOFS) { CHECK_SOUND(BITVECTOR == e.getType().getExpr().getOpKind(), "BitvectorTheoremProducer::zeroPaddingRule:" "Wrong Input: Input must be a bitvector. But the input is: " + e.toString()); } int bvLength = d_theoryBitvector->BVSize(d_theoryBitvector->getBaseType(e).getExpr()); if(CHECK_PROOFS) { CHECK_SOUND(0 <= i && i >= bvLength, "BitvectorTheoremProducer::zeroPaddingRule:" "bitPosition of extraction must be greater than bvLength" + int2string(i) + "bvLength:" + int2string(bvLength)); } const Expr boolExtractExpr = d_theoryBitvector->newBoolExtractExpr(e, i); Proof pf; if(withProof()) pf = newPf("zeropadding_rule", e, rat(i)); return newRWTheorem(boolExtractExpr, d_theoryBitvector->falseExpr(), Assumptions::emptyAssump(), pf); } Theorem BitvectorTheoremProducer:: bvPlusAssociativityRule(const Expr& bvPlusTerm) { TRACE("bitvector", "input to bvPlusAssociativityRule(", bvPlusTerm.toString(), ")"); Type type = bvPlusTerm.getType(); if(CHECK_PROOFS) { CHECK_SOUND(BITVECTOR == type.getExpr().getOpKind(), "BitvectorTheoremProducer::bvPlusAssociativityRule:" "term must be BITVECTOR type."); CHECK_SOUND(BVPLUS == bvPlusTerm.getOpKind(), "BitvectorTheoremProducer::bvPlusAssociativityRule:" "term must have the kind BVPLUS."); CHECK_SOUND(2 < bvPlusTerm.arity(), "BitvectorTheoremProducer::bvPlusAssociativityRule:" "term must have arity() greater than 2 for associativity."); } std::vector BVPlusTerms0; std::vector::const_iterator j = (bvPlusTerm.getKids()).begin(); std::vector::const_iterator jend = (bvPlusTerm.getKids()).end(); //skip the first kid j++; BVPlusTerms0.insert(BVPlusTerms0.end(), j, jend); int bvLength = d_theoryBitvector->BVSize(bvPlusTerm); const Expr bvplus0 = d_theoryBitvector->newBVPlusExpr(bvLength, BVPlusTerms0); std::vector BVPlusTerms1; BVPlusTerms1.push_back(*((bvPlusTerm.getKids()).begin())); BVPlusTerms1.push_back(bvplus0); const Expr bvplusOutput = d_theoryBitvector->newBVPlusExpr(bvLength, BVPlusTerms1); Proof pf; if(withProof()) pf = newPf("bv_plus_associativityrule", bvPlusTerm); const Theorem result(newRWTheorem(bvPlusTerm, bvplusOutput, Assumptions::emptyAssump(), pf)); TRACE("bitvector", "output of bvPlusAssociativityRule(", result, ")"); return result; } Theorem BitvectorTheoremProducer::bitExtractNot(const Expr & x, int i) { TRACE("bitvector", "input to bitExtractNot(", x.toString(), ")"); TRACE("bitvector", "input to bitExtractNot(", int2string(i), ")"); Type type = x.getType(); if(CHECK_PROOFS) { //check if the expr is indeed a bitvector term and a concat. CHECK_SOUND(BITVECTOR == type.getExpr().getOpKind(), "BitvectorTheoremProducer::bitExtractNot:" "term must be bitvector."); CHECK_SOUND(BVNEG == x.getOpKind() && 1 == x.arity(), "BitvectorTheoremProducer::bitExtractNot:" "the bitvector must be an bitwise negation." + x.toString()); //check if 0<= i < Length of bitvector constant int bvLength= d_theoryBitvector->BVSize(type.getExpr()); CHECK_SOUND(0 <= i && i < bvLength, "BitvectorTheoremProducer::bitExtractNot:" "illegal boolean extraction was attempted at position i = " + int2string(i) + "\non bitvector x = " + x.toString() + "\nwhose Length is = " + int2string(bvLength)); } // bool-extract of the bitvector constant const Expr bitExtract = d_theoryBitvector->newBoolExtractExpr(x, i); const Expr bitNegTerm = d_theoryBitvector->newBoolExtractExpr(x[0], i); Proof pf; if(withProof()) pf = newPf("bit_extract_bitwiseneg", x, rat(i)); const Theorem result(newRWTheorem(bitExtract,!bitNegTerm,Assumptions::emptyAssump(),pf)); TRACE("bitvector","output of bitExtractNot(", result, ")"); return result; } Theorem BitvectorTheoremProducer::bitExtractBitwise(const Expr & x, int i, int kind) { TRACE("bitvector", "bitExtractBitwise(", x, ", "+ int2string(i)+") {"); Type type = x.getType(); if(CHECK_PROOFS) { CHECK_SOUND(kind == BVAND || kind == BVOR || kind == BVXOR, "BitvectorTheoremProducer::bitExtractBitwise: kind = " +d_theoryBitvector->getEM()->getKindName(kind)); //check if the expr is indeed a bitvector term and a concat. CHECK_SOUND(BITVECTOR == type.getExpr().getOpKind(), "BitvectorTheoremProducer::bitExtractBitwise: " "term must be bitvector.\n x = "+x.toString() +" : "+type.toString()); CHECK_SOUND(x.getOpKind() == kind && 2 <= x.arity(), "BitvectorTheoremProducer::bitExtractBitwise: " "kind does not match.\n x = " + x.toString()); //check if 0<= i < Length of bitvector constant int size = d_theoryBitvector->BVSize(x); CHECK_SOUND(0 <= i && i < size, "BitvectorTheoremProducer::bitExtractBitwise: " "illegal boolean extraction was attempted.\n i = " + int2string(i) + "\n size = "+ int2string(size)); } // bool-extract of the bitvector constant const Expr bitExtract = d_theoryBitvector->newBoolExtractExpr(x, i); vector kids; for(Expr::iterator j=x.begin(), jend=x.end(); j!=jend; ++j) { kids.push_back(d_theoryBitvector->newBoolExtractExpr(*j, i)); } int resKind = kind == BVAND ? AND : kind == BVOR ? OR : XOR; Expr rhs = Expr(resKind, kids); Proof pf; if(withProof()) pf = newPf("bit_extract_bitwise", x, rat(i)); const Theorem result(newRWTheorem(bitExtract, rhs, Assumptions::emptyAssump(), pf)); TRACE("bitvector", "bitExtractBitwise => ", result.toString(), " }"); return result; } Theorem BitvectorTheoremProducer::bitExtractFixedLeftShift(const Expr & x, int i) { TRACE("bitvector", "input to bitExtractFixedleftshift(", x.toString(), ")"); TRACE("bitvector", "input to bitExtractFixedleftshift(", int2string(i), ")"); Type type = x.getType(); if(CHECK_PROOFS) { //check if the expr is indeed a bitvector term and a left shift. CHECK_SOUND(BITVECTOR == type.getExpr().getOpKind(), "BitvectorTheoremProducer::bitExtractFixedleftshift:" "term must be bitvector."); CHECK_SOUND((x.getOpKind() == LEFTSHIFT || x.getOpKind() == CONST_WIDTH_LEFTSHIFT) && 1 == x.arity(), "BitvectorTheoremProducer::bitExtractFixedleftshift:" "the bitvector must be a bitwise LEFTSHIFT." + x.toString()); CHECK_SOUND(d_theoryBitvector->getFixedLeftShiftParam(x) >= 0, "BitvectorTheoremProducer::bitExtractFixedleftshift:" "the bitvector must be a bitwise LEFTSHIFT." + x.toString()); //check if 0<= i < bvLength of bitvector constant int bvLength= d_theoryBitvector->BVSize(type.getExpr()); CHECK_SOUND(0 <= i && i < bvLength, "BitvectorTheoremProducer::bitExtractNot:" "illegal boolean extraction was attempted at position i = " + int2string(i) + "\non bitvector x = " + x.toString() + "\nwhose bvLength is = " + int2string(bvLength)); } // bool-extract of the bitvector constant const Expr bitExtract = d_theoryBitvector->newBoolExtractExpr(x, i); int shiftLength = d_theoryBitvector->getFixedLeftShiftParam(x); Expr output; if(0 <= i && i < shiftLength) output = d_theoryBitvector->falseExpr(); else output = d_theoryBitvector->newBoolExtractExpr(x[0], i-shiftLength); Proof pf; if(withProof()) pf = newPf("bit_extract_bitwisefixedleftshift", x,rat(i)); const Theorem result = newRWTheorem(bitExtract, output, Assumptions::emptyAssump(), pf); TRACE("bitvector", "output of bitExtractFixedleftshift(", result, ")"); return result; } Theorem BitvectorTheoremProducer::bitExtractFixedRightShift(const Expr & x, int i) { TRACE("bitvector", "input to bitExtractFixedRightShift(", x.toString(), ")"); TRACE("bitvector", "input to bitExtractFixedRightShift(", int2string(i), ")"); Type type = x.getType(); if(CHECK_PROOFS) { //check if the expr is indeed a bitvector term and a concat. CHECK_SOUND(BITVECTOR == type.getExpr().getOpKind(), "BitvectorTheoremProducer::bitExtractFixedRightShift:" "term must be bitvector."); CHECK_SOUND(RIGHTSHIFT == x.getOpKind() && 1 == x.arity(), "BitvectorTheoremProducer::bitExtractFixedRightShift:" "the bitvector must be an bitwise RIGHTSHIFT." + x.toString()); CHECK_SOUND(d_theoryBitvector->getFixedRightShiftParam(x) >= 0, "BitvectorTheoremProducer::bitExtractFixedRightShift:" "the bitvector must be an bitwise RIGHTSHIFT." + x.toString()); } //check if 0<= i < bvLength of bitvector constant int bvLength = d_theoryBitvector->BVSize(x); if(CHECK_PROOFS) CHECK_SOUND(0 <= i && i < bvLength, "BitvectorTheoremProducer::bitExtractNot:" "illegal boolean extraction was attempted at position i = " + int2string(i) + "\non bitvector t = " + x.toString() + "\nwhose Length is = " + int2string(bvLength)); // bool-extract of the bitvector constant const Expr bitExtract = d_theoryBitvector->newBoolExtractExpr(x, i); int shiftLength = d_theoryBitvector->getFixedRightShiftParam(x); Expr output; if(bvLength > i && i > bvLength-shiftLength-1) output = d_theoryBitvector->falseExpr(); else output = d_theoryBitvector->newBoolExtractExpr(x[0], i); Proof pf; if(withProof()) pf = newPf("bit_extract_bitwiseFixedRightShift", x,rat(i)); const Theorem result = newRWTheorem(bitExtract, output, Assumptions::emptyAssump(), pf); TRACE("bitvector", "output of bitExtractFixedRightShift(", result, ")"); return result; } // BOOLEXTRACT(bvshl(t,s),i) <=> ((s = 0) AND BOOLEXTRACT(t,i)) OR // ((s = 1) AND BOOLEXTRACT(t,i-1)) OR ... // ((s = i) AND BOOLEXTRACT(t,0)) Theorem BitvectorTheoremProducer::bitExtractBVSHL(const Expr & x, int i) { Type type = x.getType(); int bvLength= d_theoryBitvector->BVSize(x); if(CHECK_PROOFS) { //check if the expr is indeed a bitvector term and a left shift. CHECK_SOUND(BITVECTOR == type.getExpr().getOpKind(), "BitvectorTheoremProducer::bitExtractBVSHL:" "term must be bitvector."); CHECK_SOUND(x.getOpKind() == BVSHL && 2 == x.arity(), "BitvectorTheoremProducer::bitExtractBVSHL:" "the bitvector must be a BVSHL." + x.toString()); //check if 0<= i < bvLength of bitvector constant CHECK_SOUND(0 <= i && i < bvLength, "BitvectorTheoremProducer::bitExtractBVSHL:" "illegal boolean extraction was attempted at position i = " + int2string(i) + "\non bitvector x = " + x.toString() + "\nwhose bvLength is = " + int2string(bvLength)); } // bool-extract of the bitvector constant const Expr bitExtract = d_theoryBitvector->newBoolExtractExpr(x, i); const Expr& term = x[0]; const Expr& shift = x[1]; vector kids; for (int j = 0; j <= i; ++j) { Expr eq = shift.eqExpr(d_theoryBitvector->newBVConstExpr(j, bvLength)); Expr ext = d_theoryBitvector->newBoolExtractExpr(term, i-j); kids.push_back(eq && ext); } Expr output; if (kids.size() == 1) { output = kids[0]; } else { output = Expr(OR, kids); } Proof pf; if(withProof()) pf = newPf("bit_extract_bvshl", x, rat(i)); return newRWTheorem(bitExtract, output, Assumptions::emptyAssump(), pf); } // BOOLEXTRACT(bvlshr(t,s),i) <=> ((s = 0) AND BOOLEXTRACT(t,i)) OR // ((s = 1) AND BOOLEXTRACT(t,i+1)) OR ... // ((s = n-1-i) AND BOOLEXTRACT(t,n-1)) Theorem BitvectorTheoremProducer::bitExtractBVLSHR(const Expr & x, int i) { Type type = x.getType(); int bvLength= d_theoryBitvector->BVSize(x); if(CHECK_PROOFS) { //check if the expr is indeed a bitvector term and a left shift. CHECK_SOUND(BITVECTOR == type.getExpr().getOpKind(), "BitvectorTheoremProducer::bitExtractBVSHL:" "term must be bitvector."); CHECK_SOUND(x.getOpKind() == BVLSHR && 2 == x.arity(), "BitvectorTheoremProducer::bitExtractBVSHL:" "the bitvector must be a BVSHL." + x.toString()); //check if 0<= i < bvLength of bitvector constant CHECK_SOUND(0 <= i && i < bvLength, "BitvectorTheoremProducer::bitExtractBVSHL:" "illegal boolean extraction was attempted at position i = " + int2string(i) + "\non bitvector x = " + x.toString() + "\nwhose bvLength is = " + int2string(bvLength)); } // bool-extract of the bitvector constant const Expr bitExtract = d_theoryBitvector->newBoolExtractExpr(x, i); const Expr& term = x[0]; const Expr& shift = x[1]; vector kids; for (int j = 0; j <= bvLength-1-i; ++j) { Expr eq = shift.eqExpr(d_theoryBitvector->newBVConstExpr(j, bvLength)); Expr ext = d_theoryBitvector->newBoolExtractExpr(term, i+j); kids.push_back(eq && ext); } Expr output; if (kids.size() == 1) { output = kids[0]; } else { output = Expr(OR, kids); } Proof pf; if(withProof()) pf = newPf("bit_extract_bvlshr", x, rat(i)); return newRWTheorem(bitExtract, output, Assumptions::emptyAssump(), pf); } // BOOLEXTRACT(bvashr(t,s),i) <=> ((s = 0) AND BOOLEXTRACT(t,i)) OR // ((s = 1) AND BOOLEXTRACT(t,i+1)) OR ... // ((s >= n-1-i) AND BOOLEXTRACT(t,n-1)) Theorem BitvectorTheoremProducer::bitExtractBVASHR(const Expr & x, int i) { Type type = x.getType(); int bvLength= d_theoryBitvector->BVSize(x); if(CHECK_PROOFS) { //check if the expr is indeed a bitvector term and a left shift. CHECK_SOUND(BITVECTOR == type.getExpr().getOpKind(), "BitvectorTheoremProducer::bitExtractBVSHL:" "term must be bitvector."); CHECK_SOUND(x.getOpKind() == BVASHR && 2 == x.arity(), "BitvectorTheoremProducer::bitExtractBVSHL:" "the bitvector must be a BVSHL." + x.toString()); //check if 0<= i < bvLength of bitvector constant CHECK_SOUND(0 <= i && i < bvLength, "BitvectorTheoremProducer::bitExtractBVSHL:" "illegal boolean extraction was attempted at position i = " + int2string(i) + "\non bitvector x = " + x.toString() + "\nwhose bvLength is = " + int2string(bvLength)); } // bool-extract of the bitvector constant const Expr bitExtract = d_theoryBitvector->newBoolExtractExpr(x, i); const Expr& term = x[0]; const Expr& shift = x[1]; vector kids; int j = 0; for (; j < bvLength-1-i; ++j) { Expr eq = shift.eqExpr(d_theoryBitvector->newBVConstExpr(j, bvLength)); Expr ext = d_theoryBitvector->newBoolExtractExpr(term, i+j); kids.push_back(eq && ext); } Expr tmp = d_theoryBitvector->newBVConstExpr(j, bvLength); tmp = d_theoryBitvector->newBVLEExpr(tmp, shift); Expr ext = d_theoryBitvector->newBoolExtractExpr(term, bvLength-1); kids.push_back(tmp && ext); Expr output; if (kids.size() == 1) { output = kids[0]; } else { output = Expr(OR, kids); } Proof pf; if(withProof()) pf = newPf("bit_extract_bvashr", x, rat(i)); return newRWTheorem(bitExtract, output, Assumptions::emptyAssump(), pf); } //! Check that all the kids of e are BVCONST static bool constantKids(const Expr& e) { for(Expr::iterator i=e.begin(), iend=e.end(); i!=iend; ++i) if(i->getOpKind() != BVCONST) return false; return true; } //! c1=c2 <=> TRUE/FALSE (equality of constant bitvectors) Theorem BitvectorTheoremProducer::eqConst(const Expr& e) { if(CHECK_PROOFS) { // The kids must be constant expressions CHECK_SOUND(e.isEq(), "BitvectorTheoremProducer::eqConst: e = "+e.toString()); CHECK_SOUND(constantKids(e), "BitvectorTheoremProducer::eqConst: e = "+e.toString()); } Proof pf; if(withProof()) pf = newPf("bitvector_eq_const", e); Expr res((e[0]==e[1])? d_theoryBitvector->trueExpr() : d_theoryBitvector->falseExpr()); return newRWTheorem(e, res, Assumptions::emptyAssump(), pf); } //! |- c1=c2 ==> |- AND(c1[i:i] = c2[i:i]) - expanding equalities into bits Theorem BitvectorTheoremProducer::eqToBits(const Theorem& eq) { if(CHECK_PROOFS) { CHECK_SOUND(eq.isRewrite(), "BitvectorTheoremProducer::eqToBits: eq = "+eq.toString()); } const Expr& lhs = eq.getLHS(); const Expr& rhs = eq.getRHS(); if(CHECK_PROOFS) { CHECK_SOUND(d_theoryBitvector->getBaseType(lhs).getExpr().getOpKind() == BITVECTOR, "BitvectorTheoremProducer::eqToBits: eq = "+eq.toString()); CHECK_SOUND(d_theoryBitvector->BVSize(lhs) == d_theoryBitvector->BVSize(rhs), "BitvectorTheoremProducer::eqToBits: eq = "+eq.toString()); } int i=0, size=d_theoryBitvector->BVSize(lhs); vector bitEqs; for(; inewBVExtractExpr(lhs, i, i); Expr r = d_theoryBitvector->newBVExtractExpr(rhs, i, i); bitEqs.push_back(l.eqExpr(r)); } Expr res = andExpr(bitEqs); Proof pf; if(withProof()) pf = newPf("eq_to_bits", eq.getExpr(), eq.getProof()); return newTheorem(res, eq.getAssumptionsRef(), pf); } //! t<>m = 0bin00...00 \@ t[bvLength-1:m], takes e == (t>>n) Theorem BitvectorTheoremProducer::rightShiftToConcat(const Expr& e) { if(CHECK_PROOFS) { CHECK_SOUND(e.getOpKind() == RIGHTSHIFT && e.arity() == 1, "BitvectorTheoremProducer::rightShiftConst: e = "+e.toString()); CHECK_SOUND(d_theoryBitvector->getFixedRightShiftParam(e) >= 0, "BitvectorTheoremProducer::rightShiftConst: e = "+e.toString()); } int bvLength = d_theoryBitvector->BVSize(e[0]); int shiftSize=d_theoryBitvector->getFixedRightShiftParam(e); Expr output; if (shiftSize == 0) output = e[0]; if (shiftSize >= bvLength) output = d_theoryBitvector->newBVZeroString(bvLength); else { Expr padding = d_theoryBitvector->newBVZeroString(shiftSize); Expr out0 = d_theoryBitvector->newBVExtractExpr(e[0],bvLength-1,shiftSize); output = d_theoryBitvector->newConcatExpr(padding,out0); } DebugAssert(bvLength == d_theoryBitvector->BVSize(output), "BitvectorTheoremProducer::rightShiftConst: e = "+e.toString()); Proof pf; if(withProof()) pf = newPf("rightshift_to_concat", e); return newRWTheorem(e, output, Assumptions::emptyAssump(), pf); } //! BVSHL(t,c) = t[n-c,0] \@ 0bin00...00 Theorem BitvectorTheoremProducer::bvshlToConcat(const Expr& e) { if(CHECK_PROOFS) { // The second kid must be a constant expression CHECK_SOUND(e.getOpKind() == BVSHL && e.arity() == 2, "BitvectorTheoremProducer::bvshlToConcat: e = "+e.toString()); CHECK_SOUND(e[1].getOpKind() == BVCONST, "BitvectorTheoremProducer::bvshlToConcat: e = "+e.toString()); } const Expr& e0 = e[0]; Expr res; Rational shiftSize=d_theoryBitvector->computeBVConst(e[1]); if (shiftSize == 0) res = e0; else { int bvLength = d_theoryBitvector->BVSize(e); if (shiftSize >= bvLength) res = d_theoryBitvector->newBVConstExpr(Rational(0), bvLength); else { Expr padding = d_theoryBitvector->newBVConstExpr(Rational(0), shiftSize.getInt()); res = d_theoryBitvector->newBVExtractExpr(e0, bvLength-shiftSize.getInt()-1, 0); res = d_theoryBitvector->newConcatExpr(res, padding); } } Proof pf; if(withProof()) pf = newPf("bvshl_to_concat"); return newRWTheorem(e, res, Assumptions::emptyAssump(), pf); } // bvshl(t,s) = IF (s = 0) THEN t ELSE // IF (s = 1) then t[n-2:0] @ 0 Else // ... // ELSE 0 Theorem BitvectorTheoremProducer::bvshlSplit(const Expr &e) { Type type = e.getType(); int bvLength= d_theoryBitvector->BVSize(e); if(CHECK_PROOFS) { //check if the expr is indeed a bitvector term and a left shift. CHECK_SOUND(BITVECTOR == type.getExpr().getOpKind(), "BitvectorTheoremProducer::bitExtractBVSHL:" "term must be bitvector."); CHECK_SOUND(e.getOpKind() == BVSHL && 2 == e.arity(), "BitvectorTheoremProducer::bitExtractBVSHL:" "the bitvector must be a BVSHL." + e.toString()); } const Expr& term = e[0]; const Expr& shift = e[1]; Expr newExpr = d_theoryBitvector->newBVZeroString(bvLength); Expr eq, tmp; for (int i = bvLength-1; i > 0; --i) { eq = shift.eqExpr(d_theoryBitvector->newBVConstExpr(i, bvLength)); tmp = d_theoryBitvector->newBVExtractExpr(term, bvLength-i-1, 0); tmp = d_theoryBitvector->newConcatExpr(tmp, d_theoryBitvector->newBVZeroString(i)); newExpr = eq.iteExpr(tmp, newExpr); } eq = shift.eqExpr(d_theoryBitvector->newBVZeroString(bvLength)); newExpr = eq.iteExpr(term, newExpr); Proof pf; if(withProof()) pf = newPf("bvshl_split", e); return newRWTheorem(e, newExpr, Assumptions::emptyAssump(), pf); } //! BVLSHR(t,c) = 0bin00...00 \@ t[n-1,c] Theorem BitvectorTheoremProducer::bvlshrToConcat(const Expr& e) { if(CHECK_PROOFS) { CHECK_SOUND(e.getOpKind() == BVLSHR && e.arity() == 2, "BitvectorTheoremProducer::bvlshrToConcat: e = "+e.toString()); CHECK_SOUND(e[1].getOpKind() == BVCONST, "BitvectorTheoremProducer::bvlshrToConcat: e = "+e.toString()); } int bvLength = d_theoryBitvector->BVSize(e); Rational shiftSize=d_theoryBitvector->computeBVConst(e[1]); Expr output; if (shiftSize == 0) output = e[0]; else if(shiftSize >= bvLength) output = d_theoryBitvector->newBVZeroString(bvLength); else { Expr padding = d_theoryBitvector->newBVZeroString(shiftSize.getInt()); Expr out0 = d_theoryBitvector->newBVExtractExpr(e[0],bvLength-1,shiftSize.getInt()); output = d_theoryBitvector->newConcatExpr(padding,out0); } Proof pf; if(withProof()) pf = newPf("bvlshr_to_concat", e); return newRWTheorem(e, output, Assumptions::emptyAssump(), pf); } Theorem BitvectorTheoremProducer::bvShiftZero(const Expr& e) { if(CHECK_PROOFS) { int kind = e.getOpKind(); CHECK_SOUND((kind == BVLSHR || kind == BVSHL || kind == BVASHR || kind == LEFTSHIFT || kind == CONST_WIDTH_LEFTSHIFT || kind == RIGHTSHIFT) && e.arity() == 2, "BitvectorTheoremProducer::bvShiftZero: e = "+e.toString()); CHECK_SOUND(e[0].getOpKind() == BVCONST && d_theoryBitvector->computeBVConst(e[0]) == 0, "BitvectorTheoremProducer::bvShiftZero: e = "+e.toString()); } int bvLength = d_theoryBitvector->BVSize(e); Expr output = d_theoryBitvector->newBVZeroString(bvLength); Proof pf; if(withProof()) pf = newPf("shift_zero", e); return newRWTheorem(e, output, Assumptions::emptyAssump(), pf); } //! BVASHR(t,c) = SX(t[n-1,c], n-1) Theorem BitvectorTheoremProducer::bvashrToConcat(const Expr& e) { if(CHECK_PROOFS) { CHECK_SOUND(e.getOpKind() == BVASHR && e.arity() == 2, "BitvectorTheoremProducer::bvlshrToConcat: e = "+e.toString()); CHECK_SOUND(e[1].getOpKind() == BVCONST, "BitvectorTheoremProducer::bvlshrToConcat: e = "+e.toString()); } int bvLength = d_theoryBitvector->BVSize(e); Rational shiftSize=d_theoryBitvector->computeBVConst(e[1]); Expr output; if (shiftSize > 0) { if (shiftSize >= bvLength) shiftSize = bvLength - 1; Expr out0 = d_theoryBitvector->newBVExtractExpr(e[0],bvLength-1,shiftSize.getInt()); output = d_theoryBitvector->newSXExpr(out0, bvLength); } else output = e[0]; Proof pf; if(withProof()) pf = newPf("bvashr_to_concat", e); return newRWTheorem(e, output, Assumptions::emptyAssump(), pf); } Theorem BitvectorTheoremProducer::rewriteXNOR(const Expr& e) { if (CHECK_PROOFS) { CHECK_SOUND(e.getKind() == BVXNOR && e.arity() == 2, "Bad call to rewriteXNOR"); } Expr res = d_theoryBitvector->newBVNegExpr(e[0]); res = d_theoryBitvector->newBVXorExpr(res, e[1]); Proof pf; if (withProof()) pf = newPf("rewriteXNOR", e); return newRWTheorem(e, res, Assumptions::emptyAssump(), pf); } Theorem BitvectorTheoremProducer::rewriteNAND(const Expr& e) { if (CHECK_PROOFS) { CHECK_SOUND(e.getKind() == BVNAND && e.arity() == 2, "Bad call to rewriteNAND"); } Expr andExpr = d_theoryBitvector->newBVAndExpr(e[0], e[1]); Proof pf; if (withProof()) pf = newPf("rewriteNAND", e); return newRWTheorem(e, d_theoryBitvector->newBVNegExpr(andExpr), Assumptions::emptyAssump(), pf); } Theorem BitvectorTheoremProducer::rewriteNOR(const Expr& e) { if (CHECK_PROOFS) { CHECK_SOUND(e.getKind() == BVNOR && e.arity() == 2, "Bad call to rewriteNOR"); } Expr orExpr = d_theoryBitvector->newBVOrExpr(e[0], e[1]); Proof pf; if (withProof()) pf = newPf("rewriteNOR", e); return newRWTheorem(e, d_theoryBitvector->newBVNegExpr(orExpr), Assumptions::emptyAssump(), pf); } Theorem BitvectorTheoremProducer::rewriteBVCOMP(const Expr& e) { if (CHECK_PROOFS) { CHECK_SOUND(e.getKind() == BVCOMP && e.arity() == 2, "Bad call to rewriteBVCOMP"); } Expr res = e[0].eqExpr(e[1]).iteExpr(d_theoryBitvector->newBVOneString(1), d_theoryBitvector->newBVZeroString(1)); Proof pf; if (withProof()) pf = newPf("rewriteBVCOMP"); return newRWTheorem(e, res, Assumptions::emptyAssump(), pf); } Theorem BitvectorTheoremProducer::rewriteBVSub(const Expr& e) { if (CHECK_PROOFS) { CHECK_SOUND(e.getKind() == BVSUB && e.arity() == 2 && d_theoryBitvector->BVSize(e[0]) == d_theoryBitvector->BVSize(e[1]), "Bad call to rewriteBVSub"); } int bvsize = d_theoryBitvector->BVSize(e[0]); vector k; k.push_back(e[0]); k.push_back(d_theoryBitvector->newBVUminusExpr(e[1])); Expr new_expr = d_theoryBitvector->newBVPlusExpr(bvsize, k); ExprMap sumHashMap; Rational known_term; getPlusTerms(new_expr, known_term, sumHashMap); new_expr = buildPlusTerm(bvsize, known_term, sumHashMap); Proof pf; if (withProof()) pf = newPf("rewriteBVSub", e); return newRWTheorem(e, new_expr, Assumptions::emptyAssump(), pf); } //! k*t = BVPLUS(n, ) -- translation of k*t to BVPLUS /*! If k = 2^m, return k*t = t\@0...0 */ Theorem BitvectorTheoremProducer::constMultToPlus(const Expr& e) { DebugAssert(false, "BitvectorTheoremProducer::constMultToPlus: this rule does not work\n"); if(CHECK_PROOFS) { CHECK_SOUND(e.getOpKind() == BVMULT && e.arity() == 2 && e[0].isRational() && e[0].getRational().isInteger(), "BitvectorTheoremProducer::constMultToPlus:\n e = " +e.toString()); } Rational k = e[0].getRational(); const Expr& t = e[1]; int resLength = d_theoryBitvector->BVSize(e); string coeffBinary = abs(k).toString(2); int len = coeffBinary.length(); Expr res; // The resulting expression if(k == 0) { // Construct n-bit vector of 0's vector bits; int len = resLength; for(int i=0; inewBVConstExpr(bits); } else { // Construct the vector of shifts, the kids of the resulting BVPLUS vector kids; for(int i=0; inewFixedLeftShiftExpr(t, (len-1)-i)); } res = (kids.size() == 1)? kids[0] : d_theoryBitvector->newBVPlusExpr(resLength, kids); // For negative k, compute (~res+1), the 2's complement if(k < 0) { vector kk; kk.push_back(d_theoryBitvector->newBVNegExpr(res)); kk.push_back(rat(1)); res = d_theoryBitvector->newBVPlusExpr(resLength, kk); } } Proof pf; if(withProof()) pf = newPf("const_mult_to_plus", e); return newRWTheorem(e, res, Assumptions::emptyAssump(), pf); } Theorem BitvectorTheoremProducer::bvplusZeroConcatRule(const Expr& e) { if(CHECK_PROOFS) { CHECK_SOUND(e.getOpKind()==CONCAT && e.arity()==2, "BitvectorTheoremProducer::bvplusZeroConcatRule: e = " +e.toString()); CHECK_SOUND(e[0].getKind()==BVCONST && e[1].getOpKind()==BVPLUS && d_theoryBitvector->computeBVConst(e[0])==0, "BitvectorTheoremProducer::bvplusZeroConcatRule: e = " +e.toString()); } int constSize = d_theoryBitvector->BVSize(e[0]); const Expr& bvplus = e[1]; int bvplusSize = d_theoryBitvector->getBVPlusParam(bvplus); // Check if we can apply the rewrite rule int maxKidSize(0); for(Expr::iterator i=bvplus.begin(), iend=bvplus.end(); i!=iend; ++i) { int size(d_theoryBitvector->BVSize(*i)); // if kid is 0bin0 @ ..., then we can shorten its effective size if(i->getOpKind()==CONCAT && i->arity()>=2 && (*i)[0].getKind()==BVCONST && d_theoryBitvector->computeBVConst((*i)[0])==0) size -= d_theoryBitvector->BVSize((*i)[0]); if(size > maxKidSize) maxKidSize = size; } int numKids = bvplus.arity(); // Compute ceiling of log2(numKids) int log2 = 0; for(int i=1; i < numKids; i *=2, log2++); if(log2+maxKidSize > bvplusSize) { // Skip the rewrite, it's potentially unsound TRACE("bv 0@+", "bvplusZeroConcatRule(", e, "): skipped"); return d_theoryBitvector->reflexivityRule(e); } Expr res(d_theoryBitvector->newBVPlusExpr(bvplusSize+constSize, bvplus.getKids())); Proof pf; if(withProof()) pf = newPf("bvplus_zero_concat", e); return newRWTheorem(e, res, Assumptions::emptyAssump(), pf); } //! c1[i:j] = c (extraction from a constant bitvector) Theorem BitvectorTheoremProducer::extractConst(const Expr& e) { if(CHECK_PROOFS) { // The kids must be constant expressions CHECK_SOUND(e.getOpKind() == EXTRACT && e.arity() == 1, "BitvectorTheoremProducer::extractConst: e = "+e.toString()); CHECK_SOUND(constantKids(e), "BitvectorTheoremProducer::extractConst: e = "+e.toString()); } int hi = d_theoryBitvector->getExtractHi(e); int low = d_theoryBitvector->getExtractLow(e); const Expr& e0 = e[0]; if(CHECK_PROOFS) { CHECK_SOUND(0 <= low && low <= hi, "BitvectorTheoremProducer::extractConst: e = "+e.toString()); CHECK_SOUND((unsigned)hi < d_theoryBitvector->getBVConstSize(e0), "BitvectorTheoremProducer::extractConst: e = "+e.toString()); } vector res; for(int bit=low; bit <= hi; bit++) res.push_back(d_theoryBitvector->getBVConstValue(e0, bit)); Proof pf; if(withProof()) pf = newPf("extract_const", e); return newRWTheorem(e, d_theoryBitvector->newBVConstExpr(res), Assumptions::emptyAssump(), pf); } // t[n-1:0] = t for n-bit t Theorem BitvectorTheoremProducer::extractWhole(const Expr& e) { if(CHECK_PROOFS) { CHECK_SOUND(e.getOpKind() == EXTRACT && e.arity() == 1, "BitvectorTheoremProducer::extractWhole: e = "+e.toString()); } int hi = d_theoryBitvector->getExtractHi(e); int low = d_theoryBitvector->getExtractLow(e); const Expr& e0 = e[0]; if(CHECK_PROOFS) { CHECK_SOUND(low ==0 && hi == d_theoryBitvector->BVSize(e0) - 1, "BitvectorTheoremProducer::extractWhole: e = "+e.toString() +"\n BVSize(e) = "+ int2string(d_theoryBitvector->BVSize(e0))); } Proof pf; if(withProof()) pf = newPf("extract_whole", e); return newRWTheorem(e, e0, Assumptions::emptyAssump(), pf); } //! t[i:j][k:l] = t[k+j:l+j] (eliminate double extraction) Theorem BitvectorTheoremProducer::extractExtract(const Expr& e) { if(CHECK_PROOFS) { CHECK_SOUND(e.getOpKind() == EXTRACT && e.arity() == 1, "BitvectorTheoremProducer::extractExtract: e = "+e.toString()); } int hi = d_theoryBitvector->getExtractHi(e); int low = d_theoryBitvector->getExtractLow(e); const Expr& e0 = e[0]; if(CHECK_PROOFS) { // Check the bounds CHECK_SOUND(0 <= low && low <= hi, "BitvectorTheoremProducer::extractExtract: e = "+e.toString()); // The base expression must also be EXTRACT CHECK_SOUND(e0.getOpKind() == EXTRACT && e0.arity() == 1, "BitvectorTheoremProducer::extractExtract: e0 = " +e0.toString()); } int hi0 = d_theoryBitvector->getExtractHi(e0); int low0 = d_theoryBitvector->getExtractLow(e0); const Expr& e00 = e0[0]; if(CHECK_PROOFS) { // The extractions must be within the correct bounds CHECK_SOUND((0 <= low) && (low <= hi) && (hi <= hi0-low0), "BitvectorTheoremProducer::extractExtract:\n" " [hi:low][hi0:low0] = ["+ int2string(hi0)+":"+ int2string(low0) +"]["+ int2string(hi) + ":" + int2string(low) +"]\n e = "+e.toString()); } Expr res = d_theoryBitvector->newBVExtractExpr(e00, hi+low0, low+low0); Proof pf; if(withProof()) pf = newPf("extract_extract", e); return newRWTheorem(e, res, Assumptions::emptyAssump(), pf); } //! (t1 \@ t2)[i:j] = t1[...] \@ t2[...] (push extraction through concat) Theorem BitvectorTheoremProducer::extractConcat(const Expr& e) { TRACE("bitvector rules", "extractConcat(", e, ") {"); if(CHECK_PROOFS) { CHECK_SOUND(e.getOpKind() == EXTRACT && e.arity() == 1, "BitvectorTheoremProducer::extractConcat: e = "+e.toString()); } int hi = d_theoryBitvector->getExtractHi(e); int low = d_theoryBitvector->getExtractLow(e); const Expr& e0 = e[0]; if(CHECK_PROOFS) { // Check the bounds CHECK_SOUND(0 <= low && low <= hi, "BitvectorTheoremProducer::extractConcat: e = "+e.toString()); CHECK_SOUND(hi < d_theoryBitvector->BVSize(e0), "BitvectorTheoremProducer::extractConcat: e = "+e.toString() +"\n BVSize(e0) = "+ int2string(d_theoryBitvector->BVSize(e0))); // The base expression must be CONCAT CHECK_SOUND(e0.getOpKind() == CONCAT, "BitvectorTheoremProducer::extractConcat: e0 = " +e0.toString()); } // Collect the relevant kids from concatenation vector kids; int width(d_theoryBitvector->BVSize(e0)); TRACE("bitvector rules", "extractConcat: width=", width, ""); for(Expr::iterator i=e0.begin(), iend=e0.end(); i!=iend && width>low; ++i) { TRACE("bitvector rules", "extractConcat: *i=", *i, ""); int w(d_theoryBitvector->BVSize(*i)); int newWidth = width-w; int l(0), h(0); TRACE("bitvector rules", "extractConcat: w=", w, ""); TRACE("bitvector rules", "extractConcat: newWidth=", newWidth, ""); if(width > hi) { // Previous kids were outside of extract window if(hi >= newWidth) { // The first relevant kid h = hi-newWidth; l = (newWidth <= low)? low-newWidth : 0; TRACE("bitvector rules", "extractConcat[newWidth<=hinewConcatExpr(kids); Proof pf; if(withProof()) pf = newPf("extract_concat", e); Theorem thm(newRWTheorem(e, res, Assumptions::emptyAssump(), pf)); TRACE("bitvector rules", "extractConcat => ", thm.getExpr(), " }"); return thm; } // (t1 op t2)[i:j] = t1[i:j] op t2[i:j] -- push extraction through // bit-wise operator Theorem BitvectorTheoremProducer::extractBitwise(const Expr& e, int kind, const string& pfName) { if(CHECK_PROOFS) { CHECK_SOUND(e.getOpKind() == EXTRACT && e.arity() == 1, "BitvectorTheoremProducer::"+pfName+": e = "+e.toString()); CHECK_SOUND(kind == BVAND || kind == BVOR || kind == BVNEG || kind == BVXOR || kind == BVXNOR, "BitvectorTheoremProducer::"+pfName+": kind = " +d_theoryBitvector->getEM()->getKindName(kind)); } int hi = d_theoryBitvector->getExtractHi(e); int low = d_theoryBitvector->getExtractLow(e); const Expr& e0 = e[0]; if(CHECK_PROOFS) { // Check the bounds CHECK_SOUND(0 <= low && low <= hi, "BitvectorTheoremProducer::"+pfName+": e = "+e.toString()); // The base expression must also be EXTRACT CHECK_SOUND(e0.getOpKind() == kind, "BitvectorTheoremProducer::"+pfName+": e0 = " +e0.toString()); } vector kids; for(Expr::iterator i=e0.begin(), iend=e0.end(); i!=iend; ++i) { kids.push_back(d_theoryBitvector->newBVExtractExpr(*i, hi, low)); } Expr res = Expr(e0.getOp(), kids); Proof pf; if(withProof()) pf = newPf(pfName, e); return newRWTheorem(e, res, Assumptions::emptyAssump(), pf); } //! (t1 & t2)[i:j] = t1[i:j] & t2[i:j] (push extraction through OR) Theorem BitvectorTheoremProducer::extractAnd(const Expr& e) { return extractBitwise(e, BVAND, "extract_and"); } //! (t1 | t2)[i:j] = t1[i:j] | t2[i:j] (push extraction through AND) Theorem BitvectorTheoremProducer::extractOr(const Expr& e) { return extractBitwise(e, BVOR, "extract_or"); } //! (~t)[i:j] = ~(t[i:j]) (push extraction through NEG) Theorem BitvectorTheoremProducer::extractNeg(const Expr& e) { return extractBitwise(e, BVNEG, "extract_neg"); } //! ite(c,t1,t2)[i:j] <=> ite(c,t1[i:j],t2[i:j]) Theorem BitvectorTheoremProducer::iteExtractRule(const Expr& e) { if(CHECK_PROOFS) { CHECK_SOUND(e.getOpKind() == EXTRACT && e.arity()==1, "BitvectorTheoremProducer::iteExtractRule: " "input must be an bitvector EXTRACT expr:\n"+ e.toString()); } int hi = d_theoryBitvector->getExtractHi(e); int low = d_theoryBitvector->getExtractLow(e); if(CHECK_PROOFS) { CHECK_SOUND(e[0].getKind() == ITE && e[0].arity()==3 && BITVECTOR == e[0].getType().getExpr().getOpKind(), "BitvectorTheoremProducer::iteExtractRule: " "input must be an bitvector EXTRACT expr over an ITE:\n" + e.toString()); CHECK_SOUND(hi >= low && d_theoryBitvector->BVSize(e[0]) >= hi-low, "BitvectorTheoremProducer::iteExtractRule: " "i should be greater than j in e[i:j] = " +e.toString()); } const Expr ite = e[0]; Expr cond = ite[0]; Expr e1 = d_theoryBitvector->newBVExtractExpr(ite[1],hi,low); Expr e2 = d_theoryBitvector->newBVExtractExpr(ite[2],hi,low); Expr output = Expr(CVC3::ITE,cond,e1,e2); Proof pf; if(withProof()) pf = newPf("ite_extract_rule", e); return newRWTheorem(e, output, Assumptions::emptyAssump(), pf); } //! ~ite(c,t1,t2) <=> ite(c,~t1,~t2) Theorem BitvectorTheoremProducer::iteBVnegRule(const Expr& e) { if(CHECK_PROOFS) { CHECK_SOUND(e.getOpKind() == BVNEG && e.arity()==1, "BitvectorTheoremProducer::itebvnegrule: " "input must be an bitvector EXTRACT expr:\n"+ e.toString()); } if(CHECK_PROOFS) { CHECK_SOUND(e[0].getKind() == ITE && e[0].arity()==3 && BITVECTOR == e[0].getType().getExpr().getOpKind(), "BitvectorTheoremProducer::itebvnegrule: " "input must be an bitvector EXTRACT expr over an ITE:\n" + e.toString()); } const Expr ite = e[0]; Expr cond = ite[0]; Expr e1 = d_theoryBitvector->newBVNegExpr(ite[1]); Expr e2 = d_theoryBitvector->newBVNegExpr(ite[2]); Expr output = Expr(CVC3::ITE,cond,e1,e2); Proof pf; if(withProof()) pf = newPf("ite_bvneg_rule", e); return newRWTheorem(e, output, Assumptions::emptyAssump(), pf); } //! ~c1 = c (bit-wise negation of a constant bitvector) Theorem BitvectorTheoremProducer::negConst(const Expr& e) { if(CHECK_PROOFS) { // The kids must be constant expressions CHECK_SOUND(e.getOpKind() == BVNEG && e.arity() == 1, "BitvectorTheoremProducer::negConst: e = "+e.toString()); CHECK_SOUND(constantKids(e), "BitvectorTheoremProducer::negConst: e = "+e.toString()); } const Expr& e0 = e[0]; vector res; for(int bit=0, size=d_theoryBitvector->getBVConstSize(e0); bitgetBVConstValue(e0, bit)); Proof pf; if(withProof()) pf = newPf("bitneg_const", e); return newRWTheorem(e, d_theoryBitvector->newBVConstExpr(res), Assumptions::emptyAssump(), pf); } //! ~(t1\@...\@tn) = (~t1)\@...\@(~tn) -- push negation through concat Theorem BitvectorTheoremProducer::negConcat(const Expr& e) { if(CHECK_PROOFS) { // The kids must be constant expressions CHECK_SOUND(e.getOpKind() == BVNEG && e.arity() == 1, "BitvectorTheoremProducer::negConcat: e = "+e.toString()); CHECK_SOUND(e[0].getOpKind() == CONCAT, "BitvectorTheoremProducer::negConcat: e = "+e.toString()); } const Expr& e0 = e[0]; vector kids; for(Expr::iterator i=e0.begin(), iend=e0.end(); i!=iend; ++i) kids.push_back(d_theoryBitvector->newBVNegExpr(*i)); Expr res = d_theoryBitvector->newConcatExpr(kids); Proof pf; if(withProof()) pf = newPf("bitneg_concat", e); return newRWTheorem(e, res, Assumptions::emptyAssump(), pf); } //! ~(~t) = t -- eliminate double negation Theorem BitvectorTheoremProducer::negNeg(const Expr& e) { if(CHECK_PROOFS) { CHECK_SOUND(e.getOpKind() == BVNEG && e.arity() == 1, "BitvectorTheoremProducer::negNeg: e = "+e.toString()); CHECK_SOUND(e[0].getOpKind() == BVNEG && e[0].arity() == 1, "BitvectorTheoremProducer::negNeg: e = "+e.toString()); } Proof pf; if(withProof()) pf = newPf("bitneg_neg", e); return newRWTheorem(e, e[0][0], Assumptions::emptyAssump(), pf); } //! ~t = -1*t + 1 -- eliminate negation Theorem BitvectorTheoremProducer::negElim(const Expr& e) { if(CHECK_PROOFS) { CHECK_SOUND(e.getOpKind() == BVNEG && e.arity() == 1, "BitvectorTheoremProducer::negNeg: e = "+e.toString()); } int bv_size = d_theoryBitvector->BVSize(e[0]); Rational modulus = pow(Rational(bv_size), Rational(2)); Expr minus_one = d_theoryBitvector->newBVConstExpr(modulus-1, bv_size); vector bvplusTerms; bvplusTerms.push_back(minus_one); bvplusTerms.push_back(d_theoryBitvector->newBVMultExpr(bv_size, minus_one, e[0])); Expr res = d_theoryBitvector->newBVPlusExpr(bv_size, bvplusTerms); Proof pf; if(withProof()) pf = newPf("bitneg_elim", e); return newRWTheorem(e, res, Assumptions::emptyAssump(), pf); } //! ~(t1 & t2) = ~t1 | ~t2 -- DeMorgan's Laws Theorem BitvectorTheoremProducer::negBVand(const Expr& e) { if(CHECK_PROOFS) { CHECK_SOUND(e.getOpKind() == BVNEG && e.arity() == 1, "BitvectorTheoremProducer::negBVand: e = "+e.toString()); CHECK_SOUND(e[0].getOpKind() == BVAND, "BitvectorTheoremProducer::negBVand: e = "+e.toString()); } Expr output; std::vector negated; for(Expr::iterator i = e[0].begin(),iend=e[0].end();i!=iend;++i) negated.push_back(d_theoryBitvector->newBVNegExpr(*i)); output = d_theoryBitvector->newBVOrExpr(negated); Proof pf; if(withProof()) pf = newPf("bitneg_and", e); return newRWTheorem(e, output, Assumptions::emptyAssump(), pf); } //! ~(t1 | t2) = ~t1 & ~t2 -- DeMorgan's Laws Theorem BitvectorTheoremProducer::negBVor(const Expr& e) { if(CHECK_PROOFS) { CHECK_SOUND(e.getOpKind() == BVNEG && e.arity() == 1, "BitvectorTheoremProducer::negBVor: e = "+e.toString()); CHECK_SOUND(e[0].getOpKind() == BVOR, "BitvectorTheoremProducer::negBVor: e = "+e.toString()); } Expr output; std::vector negated; for(Expr::iterator i = e[0].begin(),iend=e[0].end();i!=iend;++i) negated.push_back(d_theoryBitvector->newBVNegExpr(*i)); output = d_theoryBitvector->newBVAndExpr(negated); Proof pf; if(withProof()) pf = newPf("bitneg_or", e); return newRWTheorem(e, output, Assumptions::emptyAssump(), pf); } //! ~(t1 xor t2) = ~t1 xor t2 Theorem BitvectorTheoremProducer::negBVxor(const Expr& e) { if(CHECK_PROOFS) { CHECK_SOUND(e.getOpKind() == BVNEG && e.arity() == 1 && e[0].arity() > 0, "BitvectorTheoremProducer::negBVxor: e = "+e.toString()); CHECK_SOUND(e[0].getOpKind() == BVXOR, "BitvectorTheoremProducer::negBVxor: e = "+e.toString()); } Expr output; std::vector children; Expr::iterator i = e[0].begin(), iend = e[0].end(); children.push_back(d_theoryBitvector->newBVNegExpr(*i)); ++i; for(; i!=iend; ++i) children.push_back(*i); output = d_theoryBitvector->newBVXorExpr(children); Proof pf; if(withProof()) pf = newPf("bitneg_xor", e); return newRWTheorem(e, output, Assumptions::emptyAssump(), pf); } //! ~(t1 xnor t2) = t1 xor t2 Theorem BitvectorTheoremProducer::negBVxnor(const Expr& e) { if(CHECK_PROOFS) { CHECK_SOUND(e.getOpKind() == BVNEG && e.arity() == 1 && e[0].arity() > 0, "BitvectorTheoremProducer::negBVxor: e = "+e.toString()); CHECK_SOUND(e[0].getOpKind() == BVXNOR, "BitvectorTheoremProducer::negBVxor: e = "+e.toString()); } Expr t2 = e[0][1]; if (e[0].arity() > 2) { std::vector children; Expr::iterator i = e[0].begin(), iend = e[0].end(); ++i; for(; i!=iend; ++i) children.push_back(*i); t2 = d_theoryBitvector->newBVXnorExpr(children); } Expr output = d_theoryBitvector->newBVXorExpr(e[0][0], t2); Proof pf; if(withProof()) pf = newPf("bitneg_xnor", e); return newRWTheorem(e, output, Assumptions::emptyAssump(), pf); } //! c1 op c2 = c -- bit-wise AND, OR, XOR of constant bitvectors Theorem BitvectorTheoremProducer::bitwiseConst(const Expr& e, const vector& idxs, int kind) { if(CHECK_PROOFS) { // The kids must be constant expressions CHECK_SOUND(e.getOpKind() == kind, "BitvectorTheoremProducer::bitwiseConst: e = "+e.toString()); CHECK_SOUND(e.getOpKind() == BVAND || e.getOpKind() == BVOR || e.getOpKind() == BVXOR, "Expected AND, OR, or XOR"); CHECK_SOUND(idxs.size() >= 2, "BitvectorTheoremProducer::bitwiseConst():\n e = " +e.toString()); for(size_t i=0; i=2, "BitvectorTheoremProducer::bitwiseFlatten: e = "+e.toString()); CHECK_SOUND(e.getOpKind() == BVAND || e.getOpKind() == BVOR || e.getOpKind() == BVXOR, "Expected AND, OR, or XOR"); } int bvLength = d_theoryBitvector->BVSize(e); // flatten the nested ops vector flattenkids; for(Expr::iterator i = e.begin(),iend=e.end();i!=iend; ++i) { if(i->getOpKind() == kind) flattenkids.insert(flattenkids.end(), i->getKids().begin(),i->getKids().end()); else flattenkids.push_back(*i); } // drop duplicate subterms and detect conflicts like t, ~t Expr output; int flag; ExprMap likeTerms; vector::iterator j = flattenkids.begin(); vector::iterator jend = flattenkids.end(); bool negate = false; for(; output.isNull() && j != flattenkids.end(); ++j) { Expr t = *j; if (kind == BVXOR && t.getOpKind() == BVNEG) { negate = !negate; t = t[0]; } //check if *j is duplicated or its negation already occured flag = sameKidCheck(t, likeTerms); switch(flag) { case 0: //no duplicates break; case 1: //duplicate detected. ignore the duplicate for BVAND, BVOR if (kind == BVXOR) { // remove both for BVXOR likeTerms.erase(t); } break; case -1: //conflict detected if (kind == BVAND) output = d_theoryBitvector->newBVZeroString(bvLength); else if (kind == BVOR) output = d_theoryBitvector->newBVOneString(bvLength); else { DebugAssert(false, "Shouldn't be possible"); } break; default: DebugAssert(false, "control should not reach here"); break; } } if (output.isNull()) { vector outputkids; ExprMap::iterator it = likeTerms.begin(); for(; it != likeTerms.end(); ++it) { outputkids.push_back((*it).first); } if(CHECK_PROOFS) { CHECK_SOUND(kind == BVXOR || outputkids.size() > 0, "TheoryBitvector:bitwiseFlatten: fatal error"); } if (outputkids.size() == 0) { outputkids.push_back(d_theoryBitvector->newBVZeroString(bvLength)); } if (negate) { outputkids[0] = d_theoryBitvector->newBVNegExpr(outputkids[0]); } if (outputkids.size() == 1) { output = outputkids[0]; } else { output = Expr(kind, outputkids); } } Proof pf; if(withProof()) pf = newPf("bitwise_flatten", e); return newRWTheorem(e, output, Assumptions::emptyAssump(), pf); } // Rewrite bitwise operation with constant using concatenation, // negation, and extraction Theorem BitvectorTheoremProducer::bitwiseConstElim(const Expr& e, int idx, int kind) { if(CHECK_PROOFS) { CHECK_SOUND(e.getOpKind() == kind, "BitvectorTheoremProducer::bitwiseConstElim: e = "+e.toString()); CHECK_SOUND(e.getOpKind() == BVAND || e.getOpKind() == BVOR || e.getOpKind() == BVXOR, "Expected AND, OR, or XOR"); CHECK_SOUND(idx < e.arity() && e.arity() > 1, "BitvectorTheoremProducer::bitwiseConstElim: e = "+e.toString() +"\n idx = "+int2string(idx) +"\n e.arity() = "+int2string(e.arity())); CHECK_SOUND(e[idx].getOpKind() == BVCONST, "BitvectorTheoremProducer::bitwiseConstElim: e["+int2string(idx) +"] = "+e[idx].toString()); } int bvLength = d_theoryBitvector->BVSize(e); Expr output; vector kids; for (int i = 0; i < e.arity(); ++i) { if (i == idx) continue; kids.push_back(e[i]); } if (kids.size() == 1) output = kids[0]; else output = Expr(kind, kids); const Expr& c = e[idx]; int i=d_theoryBitvector->getBVConstSize(c)-1; bool curVal = d_theoryBitvector->getBVConstValue(c, i); int hi = bvLength-1; Expr term; vector concatTerms; for(--i; i >= 0; --i) { if (d_theoryBitvector->getBVConstValue(c,i) != curVal) { if (kind == BVAND && curVal == false) { term = d_theoryBitvector->newBVZeroString(hi-i); } else if (kind == BVOR && curVal == true) { term = d_theoryBitvector->newBVOneString(hi-i); } else { term = d_theoryBitvector->newBVExtractExpr(output, hi, i+1); if (kind == BVXOR && curVal == true) { term = d_theoryBitvector->newBVNegExpr(term); } } concatTerms.push_back(term); curVal = !curVal; hi = i; } } if (kind == BVAND && curVal == false) { term = d_theoryBitvector->newBVZeroString(hi+1); } else if (kind == BVOR && curVal == true) { term = d_theoryBitvector->newBVOneString(hi+1); } else { if (hi < bvLength-1) { term = d_theoryBitvector->newBVExtractExpr(output, hi, 0); } else term = output; if (kind == BVXOR && curVal == true) { term = d_theoryBitvector->newBVNegExpr(term); } } concatTerms.push_back(term); if (concatTerms.size() == 1) { output = concatTerms[0]; } else { output = d_theoryBitvector->newConcatExpr(concatTerms); } Proof pf; if(withProof()) pf = newPf("bitwise_zero", e, rat(idx)); return newRWTheorem(e, output, Assumptions::emptyAssump(), pf); } /*! checks if e is already present in likeTerms without conflicts. * if yes return 1, else{ if conflict return -1 else return 0 } * we have conflict if * 1. the kind of e is BVNEG, * and e[0] is already present in likeTerms * 2. ~e is present in likeTerms already */ int BitvectorTheoremProducer::sameKidCheck(const Expr& e, ExprMap& likeTerms) { //initially flag = 0, i.e. we assume e is not in likeTerms int flag = 0; //look for e ExprMap::iterator it = likeTerms.find(e); //no entry found for e if(it==likeTerms.end()) { switch(e.getOpKind()) { case BVNEG: { ExprMap::iterator it0 = likeTerms.find(e[0]); if(it0!=likeTerms.end()) flag = -1; break; } default: { Expr bvNeg = d_theoryBitvector->newBVNegExpr(e); ExprMap::iterator negIt = likeTerms.find(bvNeg); if(negIt!=likeTerms.end()) flag=-1; break; } } if (flag == 0) likeTerms[e] = 1; return flag; } //found an entry for e return 1; } //! c1\@c2\@...\@cn = c (concatenation of constant bitvectors) Theorem BitvectorTheoremProducer::concatConst(const Expr& e) { if(CHECK_PROOFS) { // The kids must be constant expressions CHECK_SOUND(e.getOpKind() == CONCAT, "BitvectorTheoremProducer::concatConst: e = "+e.toString()); CHECK_SOUND(constantKids(e), "BitvectorTheoremProducer::concatConst: e = "+e.toString()); } vector res; for(int i=e.arity()-1; i >= 0; --i) { for(int bit=0, size=d_theoryBitvector->getBVConstSize(e[i]); bit < size; bit++) res.push_back(d_theoryBitvector->getBVConstValue(e[i], bit)); } Proof pf; if(withProof()) pf = newPf("concat_const", e); return newRWTheorem(e, d_theoryBitvector->newBVConstExpr(res), Assumptions::emptyAssump(), pf); } //! Flatten one level of nested concatenation, e.g.: x\@(y\@z)\@w = x\@y\@z\@w Theorem BitvectorTheoremProducer::concatFlatten(const Expr& e) { if(CHECK_PROOFS) { CHECK_SOUND(e.getOpKind() == CONCAT && e.arity() >= 2, "BitvectorTheoremProducer::concatFlatten: e = "+e.toString()); } // Rebuild the expression: copy the kids and flatten the nested CONCATs vector kids; for(Expr::iterator i=e.begin(), iend=e.end(); i!=iend; ++i) { if(i->getOpKind() == CONCAT) kids.insert(kids.end(), i->getKids().begin(), i->getKids().end()); else kids.push_back(*i); } Proof pf; if(withProof()) pf = newPf("concat_flatten", e); return newRWTheorem(e, Expr(e.getOp(), kids), Assumptions::emptyAssump(), pf); } //! Merge n-ary concat. of adjacent extractions: x[15:8]\@x[7:0] = x[15:0] Theorem BitvectorTheoremProducer::concatMergeExtract(const Expr& e) { if(CHECK_PROOFS) { CHECK_SOUND(e.getOpKind() == CONCAT && e.arity() >= 2, "BitvectorTheoremProducer::concatMergeExtract: e = " +e.toString()); CHECK_SOUND(e[0].getOpKind() == EXTRACT, "BitvectorTheoremProducer::concatMergeExtract: e = " +e.toString()); CHECK_SOUND(d_theoryBitvector->getExtractHi(e[0]) >= d_theoryBitvector->getExtractLow(e[0]), "BitvectorTheoremProducer::concatMergeExtract: e = " +e.toString()); } const Expr& base = e[0][0]; // The common base of all extractions if(CHECK_PROOFS) { // Check that all extractions have the same base and are contiguous int low = d_theoryBitvector->getExtractLow(e[0]); for(int i=1, iend=e.arity(); igetBVPlusParam(e); vector res(resSize); for(int i=0; inewBVConstExpr(res), Assumptions::emptyAssump(), pf); } /*! @brief c0*c1 = c, multiplication of two BVCONST */ Theorem BitvectorTheoremProducer::bvmultConst(const Expr& e) { if(CHECK_PROOFS) { // The kids must be constant expressions CHECK_SOUND(e.getOpKind() == BVMULT, "BitvectorTheoremProducer::extractConst: e = "+e.toString()); CHECK_SOUND(constantKids(e), "BitvectorTheoremProducer::extractConst: e = "+e.toString()); } Rational c = d_theoryBitvector->computeBVConst(e[0]); // Do the multiplication Rational x = d_theoryBitvector->computeBVConst(e[1]) * c; // Extract the bits of 'x' into the vector int resSize = d_theoryBitvector->BVSize(e.getType().getExpr()); vector res(resSize); for(int i=0; inewBVConstExpr(res), Assumptions::emptyAssump(), pf); } Theorem BitvectorTheoremProducer::zeroCoeffBVMult(const Expr& e) { if(CHECK_PROOFS) { CHECK_SOUND(e.getOpKind() == BVMULT && e.arity() == 2, "BitvectorTheoremProducer::zeroCoeffBVMult: e = "+e.toString()); CHECK_SOUND(BVCONST == e[0].getKind(), "BitvectorTheoremProducer::zeroCoeffBVMult: e = "+e.toString()); Rational c = d_theoryBitvector->computeBVConst(e[0]); CHECK_SOUND(0 == c, "BitvectorTheoremProducer::zeroCoeffBVMult:" "coeff must be zero:\n e = " +e.toString()); } int size = d_theoryBitvector->BVSize(e); Expr output = d_theoryBitvector->newBVZeroString(size); Proof pf; if(withProof()) pf = newPf("zerocoeff_bvmult", e); Theorem result(newRWTheorem(e,output,Assumptions::emptyAssump(),pf)); return result; } Theorem BitvectorTheoremProducer::oneCoeffBVMult(const Expr& e) { if(CHECK_PROOFS) { CHECK_SOUND(e.getOpKind() == BVMULT && e.arity() == 2, "BitvectorTheoremProducer::oneCoeffBVMult: e = " +e.toString()); CHECK_SOUND(BVCONST == e[0].getKind(), "BitvectorTheoremProducer::oneCoeffBVMult: e = " +e.toString()); Rational c = d_theoryBitvector->computeBVConst(e[0]); CHECK_SOUND(1 == c, "BitvectorTheoremProducer::oneCoeffBVMult:" "coeff must be one:\n e = " +e.toString()); } int size = d_theoryBitvector->BVSize(e); Expr output = pad(size,e); Proof pf; if(withProof()) pf = newPf("onecoeff_bvmult", e); Theorem result(newRWTheorem(e,output,Assumptions::emptyAssump(),pf)); return result; } //! t1*a <==> a*t1 Theorem BitvectorTheoremProducer::flipBVMult(const Expr& e) { if(CHECK_PROOFS) { CHECK_SOUND(e.arity()==2 && BVMULT == e.getOpKind(), "BVMULT must have exactly 2 kids: " + e.toString()); } int len = d_theoryBitvector->BVSize(e); Expr output = d_theoryBitvector->newBVMultExpr(len,e[1],e[0]); Proof pf; if(withProof()) pf = newPf("flip_bvmult", e); Theorem result(newRWTheorem(e,output,Assumptions::emptyAssump(),pf)); return result; } //! Converts e into a BVVECTOR of bvLength 'len' /*! * \param len is the desired bvLength of the resulting bitvector * \param e is the original bitvector of arbitrary bvLength */ Expr BitvectorTheoremProducer::pad(int len, const Expr& e) { DebugAssert(len > 0, "TheoryBitvector::pad:" "padding bvLength must be a non-negative integer: "+ int2string(len)); DebugAssert(BITVECTOR == e.getType().getExpr().getOpKind(), "TheoryBitvector::newBVPlusExpr:" "input must be a BITVECTOR: " + e.toString()); int size = d_theoryBitvector->BVSize(e); Expr res; if(size == len) res = e; else if (len < size) res = d_theoryBitvector->newBVExtractExpr(e,len-1,0); else { // size < len Expr zero = d_theoryBitvector->newBVZeroString(len-size); res = d_theoryBitvector->newConcatExpr(zero,e); } return res; } //! Pad the kids of BVMULT to make their bvLength = # of output-bits Theorem BitvectorTheoremProducer::padBVPlus(const Expr& e) { if(CHECK_PROOFS) { CHECK_SOUND(BVPLUS == e.getOpKind() && e.arity()>1, "BitvectorTheoremProducer::padBVPlus: " "input must be a BVPLUS: " + e.toString()); } int len = d_theoryBitvector->BVSize(e); vector kids; for(Expr::iterator i=e.begin(), iend=e.end(); i!=iend; ++i) { if(i->getOpKind() == BVMULT) { Expr e0 = pad(len, (*i)[0]); Expr e1 = pad(len, (*i)[1]); Expr out = d_theoryBitvector->newBVMultExpr(len,e0,e1); kids.push_back(out); } else kids.push_back(pad(len, *i)); } Expr output = d_theoryBitvector->newBVPlusExpr(len, kids); Proof pf; if(withProof()) pf = newPf("pad_bvplus", e); Theorem result(newRWTheorem(e,output,Assumptions::emptyAssump(),pf)); return result; } //! Pad the kids of BVMULT to make their bvLength = # of output-bits Theorem BitvectorTheoremProducer::padBVMult(const Expr& e) { if(CHECK_PROOFS) { CHECK_SOUND(BVMULT == e.getOpKind() && e.arity()==2, "BitvectorTheoremProducer::padBVMult: " "input must be a BVMULT: " + e.toString()); CHECK_SOUND(BITVECTOR==e[0].getType().getExpr().getOpKind() && BITVECTOR==e[1].getType().getExpr().getOpKind(), "for BVMULT terms e[0],e[1] must be a BV: " + e.toString()); } int len = d_theoryBitvector->BVSize(e); Expr e0 = pad(len, e[0]); Expr e1 = pad(len, e[1]); Expr output = d_theoryBitvector->newBVMultExpr(len,e0,e1); Proof pf; if(withProof()) pf = newPf("pad_bvmult", e); Theorem result(newRWTheorem(e,output,Assumptions::emptyAssump(),pf)); return result; } //! a*(b*t) <==> (a*b)*t, where a,b,t have same bvLength Theorem BitvectorTheoremProducer::bvConstMultAssocRule(const Expr& e) { if(CHECK_PROOFS) { CHECK_SOUND(BVMULT == e.getOpKind() && e.arity() == 2, "BitvectorTheoremProducer::bvConstMultAssocRule: " "input must be a BVMULT: " + e.toString()); CHECK_SOUND(BVMULT == e[1].getOpKind(), "BitvectorTheoremProducer::bvConstMultAssocRule: " "e[1] must be a BVMULT:\n e= " + e.toString()); CHECK_SOUND(BVCONST == e[0].getKind() && BVCONST == e[1][0].getKind(), "BitvectorTheoremProducer::bvConstMultAssocRule: " "e[0] & e[1][0] must be a BVCONST:\n e = " + e.toString()); } int len = d_theoryBitvector->BVSize(e); int len0 = d_theoryBitvector->BVSize(e[0]); int len10 = d_theoryBitvector->BVSize(e[1][0]); int len11 = d_theoryBitvector->BVSize(e[1][1]); if(CHECK_PROOFS) { CHECK_SOUND(len == len0 && len0 == len10 && len0 == len11, "BitvectorTheoremProducer::bvConstMultAssocRule: " "kids of BVMULT must be equibvLength: "); } Rational e0 = d_theoryBitvector->computeBVConst(e[0]); Rational e10 = d_theoryBitvector->computeBVConst(e[1][0]); Expr c = d_theoryBitvector->newBVConstExpr(e0*e10, len); Expr output = d_theoryBitvector->newBVMultExpr(len, c, e[1][1]); Proof pf; if(withProof()) pf = newPf("bvconstmult_assoc_rule", e); Theorem result(newRWTheorem(e,output,Assumptions::emptyAssump(),pf)); return result; } //FIXME: make BVMULT n-ary //! (t1*t2)*t3 <==> t1*(t2*t3), where t1 outputkids; if(BVMULT == e[0].getOpKind() && BVMULT != e[1].getOpKind()) { outputkids.push_back(e0[0]); outputkids.push_back(e0[1]); outputkids.push_back(e1); } else if(BVMULT != e[0].getOpKind() && BVMULT == e[1].getOpKind()) { outputkids.push_back(e1[0]); outputkids.push_back(e1[1]); outputkids.push_back(e0); } else { //both must be BVMULTs outputkids.push_back(e0[0]); outputkids.push_back(e0[1]); outputkids.push_back(e1[0]); outputkids.push_back(e1[1]); } sort(outputkids.begin(),outputkids.end()); Expr output; switch(outputkids.size()) { case 3: { Expr out1 = d_theoryBitvector->newBVMultExpr(len, outputkids[1],outputkids[2]); output = d_theoryBitvector->newBVMultExpr(len, outputkids[0], out1); break; } case 4: { Expr out0 = d_theoryBitvector->newBVMultExpr(len, outputkids[0], outputkids[1]); Expr out1 = d_theoryBitvector->newBVMultExpr(len, outputkids[2], outputkids[3]); output = d_theoryBitvector->newBVMultExpr(len, out0, out1); break; } } Proof pf; if(withProof()) pf = newPf("bvmult_assoc_rule", e); Theorem result(newRWTheorem(e,output,Assumptions::emptyAssump(),pf)); return result; } //! a*(t1+...+tn) <==> (a*t1+...+a*tn), where all kids are equibvLength Theorem BitvectorTheoremProducer::bvMultDistRule(const Expr& e) { if(CHECK_PROOFS) { CHECK_SOUND(BVMULT == e.getOpKind() && e.arity() == 2, "BitvectorTheoremProducer::bvMultDistRule: " "input must be a BVMULT: " + e.toString()); CHECK_SOUND(BVPLUS == e[1].getOpKind(), "BitvectorTheoremProducer::bvMultDistRule: " "input must be of the form a*(t1+...+tn): " + e.toString()); } int bvLength= d_theoryBitvector->BVSize(e); int e0len = d_theoryBitvector->BVSize(e[0]); int e1len = d_theoryBitvector->BVSize(e[1]); if(CHECK_PROOFS) { CHECK_SOUND(bvLength== e0len && e0len == e1len, "BitvectorTheoremProducer::bvMultDistRule: " "all subterms must of equal bvLength: " + e.toString()); } const Expr& e0 = e[0]; const Expr& e1 = e[1]; std::vector v; Expr::iterator i = e1.begin(); Expr::iterator iend = e1.end(); for(;i != iend; ++i) { Expr s = d_theoryBitvector->newBVMultExpr(bvLength, e0, *i); v.push_back(s); } Expr output = d_theoryBitvector->newBVPlusExpr(bvLength,v); Proof pf; if(withProof()) pf = newPf("bvmult_distributivity_rule", e); Theorem result(newRWTheorem(e,output,Assumptions::emptyAssump(),pf)); return result; } //! input BVPLUS expression e.output e <==> e', where e' has no BVPLUS // kids. remember, the invariant is that kids are already in // bvplus normal-form Theorem BitvectorTheoremProducer::flattenBVPlus(const Expr& e) { if(CHECK_PROOFS) { CHECK_SOUND(e.getOpKind() == BVPLUS && e.arity() >= 2, "BitvectorTheoremProducer::flattenBVPlus: e = "+e.toString()); } int bvLength= d_theoryBitvector->BVSize(e); const int numOfKids = e.arity(); if(CHECK_PROOFS) { for(int i=0; iBVSize(e[i]) == bvLength, "BitvectorTheoremProducer::flattenBVPlus: " "summands must be of the same bvLength as BVPLUS:\n e = " +e.toString()); } //collect the kids of e in the vector v. if any kid is a BVPLUS, //then collect its kids into v. then construct a BVPLUS expr std::vector v; for(int i = 0; i < numOfKids; ++i) { if(e[i].getOpKind() == BVPLUS) { const Expr& bvplusKid = e[i]; const int bvplusArity = bvplusKid.arity(); for(int j=0; j < bvplusArity; ++j) v.push_back(bvplusKid[j]); } else v.push_back(e[i]); } Expr eprime = d_theoryBitvector->newBVPlusExpr(bvLength, v); Proof pf; if(withProof()) pf = newPf("flatten_bvplus", e); return newRWTheorem(e, eprime, Assumptions::emptyAssump(), pf); } void BitvectorTheoremProducer::collectOneTermOfPlus(const Rational & coefficient, const Expr& term, ExprMap & likeTerms, Rational & plusConstant) { ExprMap::iterator it = likeTerms.find(term); if(it!=likeTerms.end()) likeTerms[term] += coefficient; else { // Check if there is a negated form of this term already in likeTerms map. bool foundNegated= false; if (!likeTerms.empty()) { Expr negTerm = d_theoryBitvector->newBVNegExpr(term); negTerm = d_theoryBitvector->pushNegationRec(term).getRHS(); it = likeTerms.find(negTerm); if (it!= likeTerms.end()) { foundNegated = true; // Use the rule that ~(c*x) = -c*x-1 (based on the fact: -x= ~x+1). likeTerms[negTerm] += -coefficient; plusConstant+= -1; } } if (!foundNegated) // Negated form was not found, need to register the new positive form. likeTerms[term] = coefficient; } } void BitvectorTheoremProducer::collectLikeTermsOfPlus(const Expr& e, ExprMap & likeTerms, Rational & plusConstant) { likeTerms.clear(); Expr::iterator i = e.begin(); Expr::iterator iend = e.end(); plusConstant= 0; //go thru' bvplus term, one monom at a time for(; i!=iend; ++i) { const Expr s = *i; switch(s.getOpKind()) { case BVMULT: { //if monom is BVMULT, collect like terms using ExprMap if (s[0].getKind() == BVCONST) { Rational coefficient= d_theoryBitvector->computeBVConst(s[0]); const Expr& var = s[1]; collectOneTermOfPlus(coefficient, var, likeTerms, plusConstant); } else { // non-linear mult if(CHECK_PROOFS) { CHECK_SOUND(BVCONST != s[1].getKind(), "TheoryBitvector::combineLikeTerms: " "Unexpected MULT syntax:\n\n s = " + s.toString() +"\n\n in e = "+e.toString()); } collectOneTermOfPlus(1, s, likeTerms, plusConstant); } break; } case BVUMINUS: collectOneTermOfPlus(-1, s[0], likeTerms, plusConstant); break; case BVCONST: plusConstant += d_theoryBitvector->computeBVConst(s); break; default: //we have just a variable; check if variable in ExprMap collectOneTermOfPlus(1, s, likeTerms, plusConstant); break; } } } static Rational boundedModulo(const Rational & value, const Rational & modulo, const Rational & lowerBound) { Rational ret = mod(value, modulo); if(ret == 0) return ret; if (ret< lowerBound) ret+= modulo; else { // end is one position beyond upper limit. Rational end= modulo+lowerBound; if (ret >= end) ret-= modulo; } return ret; } void BitvectorTheoremProducer:: createNewPlusCollection(const Expr & e, const ExprMap & likeTerms, Rational & plusConstant, std::vector & result) { int bvplusLength= d_theoryBitvector->BVSize(e); // Compute 2^n, to use as a modulus base Rational power2(1); for(int i=0; i::const_iterator j = likeTerms.begin(); ExprMap::const_iterator jend = likeTerms.end(); for(; j!=jend; ++j) { // The coefficient will be equivalent to j->second modulus of power2 // and in the range [-power2/2+1, power2/2] // FIXME: Need to reconsider the "best" coefficient normalization scheme. Rational coefficient = boundedModulo(j->second, power2, -power2/2+1); if(coefficient == 0) continue; Expr multiplicand = j->first; Expr monomial; if (coefficient<0) { // Make the coefficient positive: c<0 ; // (c*x)= (-c)*(-x)= (-c)*(~x+1)=(-c)*(~x) -c multiplicand = d_theoryBitvector->newBVNegExpr(multiplicand); multiplicand = d_theoryBitvector->pushNegationRec(multiplicand).getRHS(); coefficient= coefficient*-1; plusConstant +=coefficient; } if(coefficient == 1) monomial = multiplicand; else { Expr coeffExpr = d_theoryBitvector->newBVConstExpr(coefficient, bvplusLength); monomial = d_theoryBitvector->newBVMultExpr(bvplusLength, coeffExpr,multiplicand); } if(CHECK_PROOFS) { CHECK_SOUND(BITVECTOR==monomial.getType().getExpr().getOpKind(), "TheoryBitvector::combineLikeTerms:" "each monomial must be a bitvector:\n" "monomial = " + monomial.toString()); CHECK_SOUND(bvplusLength == d_theoryBitvector->BVSize(monomial), "TheoryBitvector::combineLikeTerms:" "bvLength of each monomial must be the same as e:\n" "monomial = " + monomial.toString() + "\n e = " + e.toString()); } result.push_back(monomial); } // Positive modulo of the constant plusConstant = boundedModulo(plusConstant, power2, 0); //make the constant a subterm of the BVPLUS expression if(plusConstant != 0) { const Expr c = d_theoryBitvector->newBVConstExpr(plusConstant, bvplusLength); result.push_back(c); } } Expr BitvectorTheoremProducer::sumNormalizedElements(int bvplusLength, const std::vector&items){ //construct a new BVPLUS term using the ExprMap. if size of //likeTerms is less than 2, then do NOT construct BVPLUS switch(items.size()) { case 0: //items are empty. only constant 0 remains return d_theoryBitvector->newBVZeroString(bvplusLength); case 1: //items may contain a Expr of the form a*x or x or a return items[0]; default: //items have 2 or more kids return d_theoryBitvector->newBVPlusExpr(bvplusLength, items); } } Theorem BitvectorTheoremProducer::combineLikeTermsRule(const Expr& e) { TRACE("bitvector rewrite", "combineLikeTermsRule(",e.toString(), ") {"); if(CHECK_PROOFS) { CHECK_SOUND(BVPLUS == e.getOpKind() && e.arity()>=2, "TheoryBitvector::combineLikeTerms: " "input must be a BVPLUS term:\n e = " + e.toString()); int bvplusLength = d_theoryBitvector->BVSize(e); Expr::iterator i = e.begin(); Expr::iterator iend = e.end(); for(;i!=iend;++i) { const Expr& s = *i; if(s.getOpKind() == BVPLUS) { CHECK_SOUND(s.getOpKind() != BVPLUS, "TheoryBitvector::combineLikeTerms: " "BVPLUS must be flattened:\n e = " + e.toString()); } int bvLength= d_theoryBitvector->BVSize(s); //bvLength checks for BVCONST and variables CHECK_SOUND(bvLength==bvplusLength, "TheoryBitvector::combineLikeTerms: " "BVPLUS must be padded:\n e = " + e.toString()); //Length checks for BVMULTs if(s.getOpKind()==BVMULT) { int s0len = d_theoryBitvector->BVSize(s[0]); int s1len = d_theoryBitvector->BVSize(s[1]); CHECK_SOUND(bvplusLength == s0len && s0len== s1len, "all monoms must have the samebvLength " "as the bvplus term: " + e.toString()); } } } int bvplusLength = d_theoryBitvector->BVSize(e); ExprMap likeTerms; Rational theConstant(0); collectLikeTermsOfPlus(e, likeTerms, theConstant); std::vector collection; createNewPlusCollection(e, likeTerms, theConstant, collection); Expr output= sumNormalizedElements(bvplusLength, collection); TRACE("bitvector rewrite", "combineLikeTermsRule =>",output.toString(), "}"); Proof pf; if(withProof()) pf=newPf("bvplus_combine_like_terms", e); return newRWTheorem(e, output, Assumptions::emptyAssump(), pf); } Theorem BitvectorTheoremProducer::lhsMinusRhsRule(const Expr& e) { if(CHECK_PROOFS) { CHECK_SOUND(EQ == e.getKind() && e.arity() == 2, "BitvectorTheoremProducer::lhsMinusRhsRule: " "input must be an EQ: e = " +e.toString()); CHECK_SOUND(BVPLUS == e[0].getOpKind() || BVPLUS == e[1].getOpKind(), "BitvectorTheoremProducer::lhsMinusRhsRule: " "atleast one of the input subterms must be BVPLUS:" "e = " +e.toString()); int bvLength0 = d_theoryBitvector->BVSize(e[0]); int bvLength1 = d_theoryBitvector->BVSize(e[1]); CHECK_SOUND(bvLength0 == bvLength1, "BitvectorTheoremProducer::lhsMinusRhsRule: " "both sides of EQ must be same Length. e = " +e.toString()); for(Expr::iterator i=e[0].begin(),iend=e[0].end();i!=iend;++i) { int bvLength= d_theoryBitvector->BVSize(*i); CHECK_SOUND(bvLength0 == bvLength, "BitvectorTheoremProducer::lhsMinusRhsRule: " "all subterms of e[0] must be of same Length." "e = " +e.toString()); } for(Expr::iterator i=e[1].begin(),iend=e[1].end();i!=iend;++i) { int bvLength= d_theoryBitvector->BVSize(*i); CHECK_SOUND(bvLength1 == bvLength, "BitvectorTheoremProducer::lhsMinusRhsRule: " "all subterms of e[1] must be of same Length." "e = " +e.toString()); } } Expr output; int bvLength = d_theoryBitvector->BVSize(e[0]); std::vector k; //construct 0 of bvLength Expr zeroStr = d_theoryBitvector->newBVZeroString(bvLength); if(e[0] == e[1]) output = Expr(EQ, zeroStr, zeroStr); else { //drop common subterms std::vector e0K = e[0].getKids(); std::vector e1K = e[1].getKids(); for(vector::iterator i=e0K.begin(),iend=e0K.end();i!=iend;++i){ for(vector::iterator j=e1K.begin(),jend=e1K.end();j!=jend;++j){ if(*i == *j) { e0K.erase(i); e1K.erase(j); break; } } } Expr newLhs = d_theoryBitvector->newBVPlusExpr(bvLength, e0K); k.push_back(newLhs); Expr newRhs = d_theoryBitvector->newBVPlusExpr(bvLength, e1K); //construct -rhs Expr uminus = d_theoryBitvector->newBVUminusExpr(newRhs); //push back -rhs k.push_back(uminus); //construct lhs-rhs Expr lhsMinusRhs = d_theoryBitvector->newBVPlusExpr(bvLength,k); //construct lhs-rhs=0 output = Expr(EQ, lhsMinusRhs, zeroStr); } Proof pf; if(withProof()) pf = newPf("lhs_minus_rhs_rule", e); return newRWTheorem(e, output, Assumptions::emptyAssump(), pf); } //! generic rule used for bitblasting step. -e <==> ~e+1 Theorem BitvectorTheoremProducer::bvuminusToBVPlus(const Expr& e) { if(CHECK_PROOFS) { CHECK_SOUND(BVUMINUS == e.getOpKind(), "BitvectorTheoremProducer::bvuminusBitBlastRule: " "input must be bvuminus: e = " + e.toString()); } int bvLength = d_theoryBitvector->BVSize(e); std::vector k; Expr negE0 = d_theoryBitvector->newBVNegExpr(e[0]); k.push_back(negE0); Expr plusOne = d_theoryBitvector->newBVConstExpr(1, bvLength); k.push_back(plusOne); Expr output = d_theoryBitvector->newBVPlusExpr(bvLength, k); Proof pf; if(withProof()) pf = newPf("bvuminus_bitblast_rule", e); return newRWTheorem(e, output, Assumptions::emptyAssump(), pf); } //! -0 <==> 0, -c <==> ~c+1 Theorem BitvectorTheoremProducer::bvuminusBVConst(const Expr& e) { if(CHECK_PROOFS) { CHECK_SOUND(BVUMINUS == e.getOpKind() && BVCONST == e[0].getKind(), "BitvectorTheoremProducer::bvuminusBVConst: " "e should be bvuminus, e[0] should be bvconst: e = " + e.toString()); } Expr output; int e0Length = d_theoryBitvector->BVSize(e[0]); // output == 0 if(d_theoryBitvector->computeBVConst(e[0]) == 0) output = e[0]; else { // Compute -c, which is ~c+1 Rational x = d_theoryBitvector->computeNegBVConst(e[0]); output = d_theoryBitvector->newBVConstExpr(x, e0Length); } Proof pf; if(withProof()) pf = newPf("bvuminus_bvconst_rule", e); return newRWTheorem(e, output, Assumptions::emptyAssump(), pf); } //! -(c*t)<=>(-c)*t; if -c==0 return e<=>0. if(-c==1) return e<=>t Theorem BitvectorTheoremProducer::bvuminusBVMult(const Expr& e) { if(CHECK_PROOFS) { CHECK_SOUND(BVUMINUS == e.getOpKind(), "BitvectorTheoremProducer::bvuminusBVMult: " "e should be bvuminus: e =" + e.toString()); CHECK_SOUND(BVMULT == e[0].getOpKind(), "Bitvectortheoremproducer::bvuminusBVMult: " "in input expression e = " + e.toString() + "\ne[0] should be bvmult: e[0] = " + e[0].toString()); CHECK_SOUND(BVCONST == e[0][0].getKind(), "Bitvectortheoremproducer::bvuminusBVMult: " "in input expression e = " + e.toString() + "\ne[0][0] should be bvconst: e[0][0] = " + e[0][0].toString()); int bvLength = d_theoryBitvector->BVSize(e); int e0Length = d_theoryBitvector->BVSize(e[0]); int e00Length = d_theoryBitvector->BVSize(e[0][0]); CHECK_SOUND(bvLength == e0Length && e0Length == e00Length, "Bitvectortheoremproducer::bvuminusBVMult: " "in input expression e = " + e.toString() + "\nLengths of all subexprs must be equal: e = " + e.toString()); } //e is of the form -(c*t) Expr output; int e0Length = d_theoryBitvector->BVSize(e[0]); //compute ~c+1 Rational coeff = d_theoryBitvector->computeNegBVConst(e[0][0]); if(0 == coeff) //if ~c+1 == 0 output = d_theoryBitvector->newBVZeroString(e0Length); else if (1 == coeff) //if ~c+1 == 1 output = e[0][1]; else { //construct (~c+1)*t Expr newcoeff = d_theoryBitvector->newBVConstExpr(coeff, e0Length); output = d_theoryBitvector->newBVMultExpr(e0Length, newcoeff, e[0][1]); } Proof pf; if(withProof()) pf = newPf("bvuminus_bvmult_rule", e); return newRWTheorem(e, output, Assumptions::emptyAssump(), pf); } //! -(-e) <==> e Theorem BitvectorTheoremProducer::bvuminusBVUminus(const Expr& e) { if(CHECK_PROOFS) { CHECK_SOUND(BVUMINUS == e.getOpKind(), "BitvectorTheoremProducer::bvuminusBVUminus: " "e should be bvuminus: e =" + e.toString()); CHECK_SOUND(BVUMINUS == e[0].getOpKind(), "Bitvectortheoremproducer::bvuminusBVUminus: " "in input expression e = " + e.toString() + "\ne[0] should be bvmult: e[0] = " + e[0].toString()); } Expr output; // -(-e) <==> e output = e[0][0]; Proof pf; if(withProof()) pf = newPf("bvuminus_bvuminus_rule", e); return newRWTheorem(e, output, Assumptions::emptyAssump(), pf); } //! -v <==> -1*v Theorem BitvectorTheoremProducer::bvuminusVar(const Expr& e) { if(CHECK_PROOFS) { CHECK_SOUND(BVUMINUS == e.getOpKind(), "BitvectorTheoremProducer::bvuminusVar: " "e should be bvuminus: e =" + e.toString()); } Expr output; std::vector res; int e0Length = d_theoryBitvector->BVSize(e[0]); for(int i=0; inewBVConstExpr(res); output = d_theoryBitvector->newBVMultExpr(e0Length, coeff, e[0]); Proof pf; if(withProof()) pf = newPf("bvuminus_var_rule", e); return newRWTheorem(e, output, Assumptions::emptyAssump(), pf); } //! c*(-t) <==> (-c)*t Theorem BitvectorTheoremProducer::bvmultBVUminus(const Expr& e) { if(CHECK_PROOFS) { CHECK_SOUND(BVUMINUS == e.getOpKind(), "BitvectorTheoremProducer::bvmultBVUminus: " "e should be bvuminus: e =" + e.toString()); CHECK_SOUND(BVMULT == e[0].getOpKind() && BVCONST == e[0][0].getKind() && BVUMINUS == e[0][1].getOpKind(), "Bitvectortheoremproducer::bvmultBVUminus: " "in input expression e = " + e.toString() + "\ne[0] has to be bvmult" "e[0][1] must be bvuminus: e[0] = " + e[0].toString()); int bvLength = d_theoryBitvector->BVSize(e); int e00Length = d_theoryBitvector->BVSize(e[0][0]); int e01Length = d_theoryBitvector->BVSize(e[0][1]); CHECK_SOUND(bvLength == e00Length && e00Length == e01Length, "Bitvectortheoremproducer::bvmultBVUminus: " "in input expression e = " + e.toString() + "\nLengths of all subexprs must be equal."); } Expr output; int bvLength = d_theoryBitvector->BVSize(e); const Expr& coeff = e[0][0]; Rational negatedcoeff = d_theoryBitvector->computeNegBVConst(coeff); const Expr& e010 = e[0][1][0]; if(0 == negatedcoeff) //if ~c+1 == 0 output = d_theoryBitvector->newBVZeroString(bvLength); else if (1 == negatedcoeff) //if ~c+1 == 1 output = e010; else { //construct (~c+1)*t Expr newcoeff = d_theoryBitvector->newBVConstExpr(negatedcoeff, bvLength); output = d_theoryBitvector->newBVMultExpr(bvLength, newcoeff, e010); } Proof pf; if(withProof()) pf = newPf("bvmult_bvuminus_rule", e); return newRWTheorem(e, output, Assumptions::emptyAssump(), pf); } //! -(c1*t1+...+cn*tn) <==> (-(c1*t1)+...+-(cn*tn)) Theorem BitvectorTheoremProducer::bvuminusBVPlus(const Expr& e) { // if(CHECK_PROOFS) { // CHECK_SOUND(BVUMINUS == e.getOpKind(), // "BitvectorTheoremProducer::bvuminusBVPlus: " // "e should be bvuminus: e =" + e.toString()); // CHECK_SOUND(BVPLUS == e[0].getOpKind(), // "BitvectorTheoremProducer::bvuminusBVPlus: " // "e[0] should be bvplus: e[0] =" + e[0].toString()); // } // int bvLength = d_theoryBitvector->BVSize(e); // const Expr& e0 = e[0]; // Expr::iterator i = e0.begin(); // Expr::iterator iend = e0.end(); // std::vector output; // for(; i!=iend; ++i) { // const Expr& s = *i; // Expr t = d_theoryBitvector->newBVUminusExpr(s); // output.push_back(t); // } // Expr outputPlus = // d_theoryBitvector->newBVPlusExpr(bvLength, output); // Assumptions a; // Proof pf; // if(withProof()) // pf = newPf("bvminus_bvplus_rule", e); // return newRWTheorem(e, outputPlus, a, pf); Proof pf; if(withProof()) pf = newPf("bvminus_bvplus_rule", e); return newRWTheorem(e, e, Assumptions::emptyAssump(), pf); } Theorem BitvectorTheoremProducer::extractBVMult(const Expr& e) { if(CHECK_PROOFS) { CHECK_SOUND(e.getOpKind() == EXTRACT && e[0].getOpKind() == BVMULT && e[0].arity() == 2, "BitvectorTheoremProducer::extractBVMult: " "input must be an EXTRACT over BVMULT:\n e = "+e.toString()); } const Expr& bvmult = e[0]; int bvmultLen = d_theoryBitvector->BVSize(bvmult); int extractHi = d_theoryBitvector->getExtractHi(e); int extractLow = d_theoryBitvector->getExtractLow(e); if(CHECK_PROOFS) { CHECK_SOUND(bvmultLen > extractHi, "BitvectorTheoremProducer::extractBVMult: " "bvmult Length must be greater than extract Length:\n e = " +e.toString()); } Expr output = d_theoryBitvector->newBVMultPadExpr(extractHi+1, bvmult[0], bvmult[1]); if(extractLow > 0) output=d_theoryBitvector->newBVExtractExpr(output, extractHi, extractLow); Proof pf; if(withProof()) pf = newPf("extract_bvmult_rule", e); return newRWTheorem(e, output, Assumptions::emptyAssump(), pf); } Theorem BitvectorTheoremProducer::extractBVPlus(const Expr& e) { if(CHECK_PROOFS) { CHECK_SOUND(e.getOpKind() == EXTRACT && e[0].getOpKind() == BVPLUS, "BitvectorTheoremProducer::extractBVPlus: " "input must be an EXTRACT over BVPLUS:\n e = "+e.toString()); } const Expr& bvplus = e[0]; int bvplusLen = d_theoryBitvector->BVSize(bvplus); int extractHi = d_theoryBitvector->getExtractHi(e); int extractLow = d_theoryBitvector->getExtractLow(e); if(CHECK_PROOFS) { CHECK_SOUND(bvplusLen > extractHi, "BitvectorTheoremProducer::extractBVPlus: " "bvplus Length must be greater than extract bvLength:\n e = " +e.toString()); } // Shortcut if(bvplusLen == extractHi+1) return d_theoryBitvector->reflexivityRule(e); // Shorten the result width of the bvplus term Expr output(d_theoryBitvector->newBVPlusPadExpr(extractHi+1, bvplus.getKids())); if(extractLow > 0) output=d_theoryBitvector->newBVExtractExpr(output, extractHi, extractLow); Proof pf; if(withProof()) pf = newPf("extract_bvplus_rule", e); return newRWTheorem(e, output, Assumptions::emptyAssump(), pf); } // |- t=0 OR t=1 for any 1-bit bitvector t Theorem BitvectorTheoremProducer::typePredBit(const Expr& e) { if(CHECK_PROOFS) { CHECK_SOUND(d_theoryBitvector->getBaseType(e).getExpr().getOpKind() == BITVECTOR, "BitvectorTheoremProducer::typePredBit: e = "+e.toString()); CHECK_SOUND(d_theoryBitvector->BVSize(e) == 1, "BitvectorTheoremProducer::typePredBit: e = "+e.toString()); } Proof pf; if(withProof()) pf=newPf("type_pred_bit", e); return newTheorem(e.eqExpr(bvZero()) || e.eqExpr(bvOne()), Assumptions::emptyAssump(), pf); } //! Expand the type predicate wrapper (compute the actual type predicate) Theorem BitvectorTheoremProducer::expandTypePred(const Theorem& tp) { Expr tpExpr = tp.getExpr(); if(CHECK_PROOFS) { CHECK_SOUND(tpExpr.getOpKind() == BVTYPEPRED || (tpExpr.getKind() == NOT && tpExpr[0].getOpKind() == BVTYPEPRED), "BitvectorTheoremProducer::expandTypePred: " "Expected BV_TYPE_PRED wrapper:\n tp = " +tpExpr.toString()); } Expr res; if(tpExpr.getKind() == NOT) res = d_theoryBitvector->falseExpr(); else { Type t(d_theoryBitvector->getTypePredType(tpExpr)); const Expr& e(d_theoryBitvector->getTypePredExpr(tpExpr)); int size(d_theoryBitvector->getBitvectorTypeParam(t)); // DebugAssert(BVSize(e)==size, "TheoryBitvector::computeTypePred: e=" // +e.toString()+", t="+t.toString()); if(size >= 2) { vector kids; for(int i=0; inewBVExtractExpr(e, i, i)); kids.push_back(bit.eqExpr(bvZero()) || bit.eqExpr(bvOne())); } res = andExpr(kids); } else { res = (e.eqExpr(bvZero()) || e.eqExpr(bvOne())); } } Proof pf; if(withProof()) pf = newPf("expand_type_pred", tp.getExpr(), tp.getProof()); return newTheorem(res, tp.getAssumptionsRef(), pf); } /*Beginning of Lorenzo PLatania's methods*/ // Theorem BitvectorTheoremProducer::multiply_coeff( Rational mult_inv, const Expr& e) // { // Expr rhs= d_theoryBitvector->multiply_coeff( mult_inv, e); // Proof pf= newPf("multiply both sides for a constant"); // return newRWTheorem( e, rhs, Assumptions::emptyAssump(), pf); // } // rewrites the equation in the form 0 = Expr // this is needed for TheoryBitvector::solve Theorem BitvectorTheoremProducer::MarkNonSolvableEq( const Expr& e) { int bv_size = d_theoryBitvector->BVSize(e[0]); Expr bv_zero( d_theoryBitvector->newBVZeroString(bv_size)); if (CHECK_PROOFS) CHECK_SOUND( e.isEq() && ( e[0] == bv_zero || e[1] == bv_zero ), "MarkNonSolvableEq: input must be a canonized equation" + e.toString()); if( e[1] == bv_zero ) { Expr expr_res= Expr(EQ, e[1], e[0]); Proof pf= newPf("mark non solvable eq"); Theorem th_res= newRWTheorem( e, expr_res, Assumptions::emptyAssump(), pf); return th_res; } else { return d_theoryBitvector->reflexivityRule(e); } } // Given an expression t = 0, isolate a single leaf on the lhs if possible, // returning t = 0 <=> leaf = rest. // Otherwise, return e <=> e Theorem BitvectorTheoremProducer::isolate_var(const Expr& e) { int bv_size = d_theoryBitvector->BVSize(e[0]); Expr bv_zero(d_theoryBitvector->newBVZeroString(bv_size)); if (CHECK_PROOFS) { CHECK_SOUND(e.isEq() && e[1] == bv_zero && e[0].getOpKind() != BVCONST, "isolate_var: input must be an equation with lhs non-cosnt and rhs must be zero" + e.toString()); } // cout<<"BitvectorTheoremProducer::isolate_var: "<computeBVConst(lhs[0]) % 2 == 0, "Expected even coeff"); } res_expr = e; break; case BVPLUS: { int e_kid_arity = lhs.arity(); bool foundUnitCoeff = false; Expr new_lhs, new_rhs, new_coeff; vector newKids; Rational tmp, const_term = 0; for( int i = 0; i < e_kid_arity; ++i) { // it can be a BVMULT, a var, or a const Expr e_sub_kid = lhs[i]; switch (e_sub_kid.getOpKind()) { case BVCONST: DebugAssert(const_term == 0, "Expected only one constant"); const_term = ((modulus-1) * d_theoryBitvector->computeBVConst(e_sub_kid)) % modulus; newKids.push_back(d_theoryBitvector->newBVConstExpr(const_term, bv_size)); break; case BVMULT: if( e_sub_kid[0].getOpKind() == BVCONST ) { DebugAssert(e_sub_kid.arity() == 2, "Expected arity 2 BVMULT"); tmp = d_theoryBitvector->computeBVConst(e_sub_kid[0]); DebugAssert(tmp != 1, "Expected coeff other than 1"); tmp = (tmp * (modulus-1)) % modulus; new_coeff = d_theoryBitvector->newBVConstExpr(tmp, bv_size); newKids.push_back(d_theoryBitvector->newBVMultExpr(bv_size, new_coeff, e_sub_kid[1])); } else { new_coeff = d_theoryBitvector->newBVConstExpr(modulus-1, bv_size); newKids.push_back(d_theoryBitvector->newBVMultExpr(bv_size, new_coeff, e_sub_kid)); } break; default: if (!foundUnitCoeff) { foundUnitCoeff = true; new_lhs = e_sub_kid; } else { new_coeff = d_theoryBitvector->newBVConstExpr(modulus-1, bv_size); newKids.push_back(d_theoryBitvector->newBVMultExpr(bv_size, new_coeff, e_sub_kid)); } break; } } if (foundUnitCoeff) { DebugAssert(newKids.size() > 0, "Expected non-empty kids"); Expr new_rhs; if (newKids.size() == 1) { new_rhs = newKids[0]; } else { new_rhs = d_theoryBitvector->newBVPlusExpr(bv_size, newKids); } res_expr = Expr(EQ, new_lhs, new_rhs); } else { res_expr = e; } break; } default: res_expr = e; break; } Proof pf= newPf("isolate var"); // cout<<"TheoryBitvector::isolate_var: result is: " <isLeaf(res_expr[0]) && !d_theoryBitvector->isLeafIn(res_expr[0], res_expr[1])), "Expected no change or solved form"); return newRWTheorem(e, res_expr, Assumptions::emptyAssump(), pf); } // Theorem BitvectorTheoremProducer::isolate_var( const Theorem& t, const Expr& e) // { // int bv_size = d_theoryBitvector->BVSize(e[0]); // Expr bv_zero( d_theoryBitvector->newBVZeroString(bv_size)); // Expr BV_one = d_theoryBitvector->newBVConstExpr(1,bv_size); // if (CHECK_PROOFS) // // the RHS assumptio has to be removed // CHECK_SOUND( e.isEq() && // ( e[0] == bv_zero || e[1] == bv_zero ), // "isolate_var: input must be an equation and one of the kids must be a zero" + e.toString()); // cout<<"BitvectorTheoremProducer::isolate_var: "<canSolveFor( lhs[index], e)) // // if( d_theoryBitvector->isLeaf( lhs[index]) || (lhs[index].getOpKind() == BVMULT && lhs[index][0].isVar() && lhs[index][0].isVar()) ) // { // found = 1; // solve_pos = index; // break; // } // } // // else // // if( lhs[index].getOpKind() == BVCONST ) // // rhs = lhs[index]; // } // DebugAssert(found, // "BitvectorTheoremProducer::isolate_var: No variable with unary coefficient found"); // // L:: Index says which variable we are solving the equation for. // // for all other variables we have to invert the sign of the // // coefficient and put them in the rhs with the known term // cout<<"we solve for the var in position "< new_rhs_list; // Rational known_term = 0; // int scan; // for( scan = 0; scan < lhs_arity; ++scan) // { // if( scan != solve_pos ) // { // // I think the first case is useless // // the operand of the sum is just a var, but different from // // the one we choose to solve the equation // // if( lhs[scan].isVar()) // // { // // new_rhs_list.push_back( d_theoryBitvector->newBVUminusExpr( lhs[scan]) ); // // } // // else // // we add the constant to the known term // if( lhs[scan].getOpKind() == BVCONST ) // { // Rational tmp = d_theoryBitvector->computeNegBVConst( lhs[scan]); // Expr bv_tmp = d_theoryBitvector->signed_newBVConstExpr( tmp, bv_size ); // new_rhs_list.push_back ( bv_tmp); // cout<<"input constant: "<computeNegBVConst( lhs[scan][0] ); // Expr bv_new_coeff = d_theoryBitvector->signed_newBVConstExpr( new_coeff, bv_size ); // if( bv_new_coeff == BV_one) // new_rhs_list.push_back( lhs[scan][1]); // else // { // Expr bv_new_expr = d_theoryBitvector->newBVMultExpr( bv_size, bv_new_coeff, lhs[scan][1]); // new_rhs_list.push_back( bv_new_expr ); // } // } // else // { // new_rhs_list.push_back( d_theoryBitvector->newBVUminusExpr( lhs[scan] ) ); // } // } // else // if( d_theoryBitvector->isLeaf( lhs[scan] ) ) // new_rhs_list.push_back( lhs[scan] ); // else // DebugAssert(0, // "BitvectorTheoremProducer::isolate_var: subterm of non implemented kind"); // } // } // for(unsigned int i=0; i < new_rhs_list.size(); i++) // cout<<"new_rhs_list["< 1) // new_rhs = d_theoryBitvector->newBVPlusExpr( bv_size, new_rhs_list); // else // new_rhs = new_rhs_list[0]; // Expr expr_res; // // if( lhs[index] >= new_rhs) // // expr_res= Expr(EQ, lhs[index], new_rhs); // // else // // expr_res= Expr(EQ, new_rhs, lhs[index]); // // L:: fix according to the new form for variables // new_lhs = lhs[solve_pos]; // expr_res= Expr(EQ, new_lhs, new_rhs); // Proof pf= newPf("isolate var"); // Theorem th_res= newRWTheorem( e, expr_res, Assumptions::emptyAssump(), pf); // cout<<"TheoryBitvector::isolate_var: result is: "<iffMP( e, expr_res); // } Theorem BitvectorTheoremProducer::BVMult_order_subterms( const Expr& e ) { if (CHECK_PROOFS) CHECK_SOUND(e.getOpKind() == BVMULT, "BitvectorTheoremProducer::BVMult_order_vars: input must be a BVMULT expression" + e.toString()); // cout<<"BitvectorTheoremProducer::BVMult_order_subterms, e: "<BVSize(e); Expr new_expr; vector vars; // as the term has already been processed by BVcanon, a constant can // be just at the beginning of the term bool hasConst = false; if (e[0].getOpKind() == BVCONST) { d_theoryBitvector->extract_vars(e[1], vars); hasConst = true; } else { d_theoryBitvector->extract_vars(e, vars); } int vars_size = vars.size(); ExprMap vars_map; for( int i=0; i < vars_size; ++i) { // cout<<"vars["<::iterator j = vars_map.begin(); new_expr = (*j).first; if ((*j).second != 1) { for(int k=1; k < (*j).second; ++k) { new_expr = d_theoryBitvector->newBVMultExpr( bv_size, (*j).first, new_expr); } } for( ++j; j != vars_map.end(); ++j) { new_expr = d_theoryBitvector->newBVMultExpr( bv_size, (*j).first, new_expr); if ((*j).second != 1) { for(int k=1; k < (*j).second; ++k) { new_expr = d_theoryBitvector->newBVMultExpr( bv_size, (*j).first, new_expr); } } } Proof pf; if (withProof()) pf = newPf("BVMult_order_subterms"); if (hasConst) { new_expr = d_theoryBitvector->newBVMultExpr( bv_size, e[0], new_expr); } Theorem result = newRWTheorem( e, new_expr, Assumptions::emptyAssump(), pf); return result; } // BVMULT(N, a\@b, y) = BVPLUS(N, BVMULT(N,b,y), BVMULT(N-n,a,y) \@ n-bit-0-string) // where n = BVSize(b), a != 0, one of a or b is a constant Theorem BitvectorTheoremProducer::liftConcatBVMult(const Expr& e) { if (CHECK_PROOFS) { CHECK_SOUND(e.getOpKind() == BVMULT, "BitvectorTheoremProducer::liftConcatBVMult: input must be a BVMULT expression" + e.toString()); } int bv_size = d_theoryBitvector->BVSize( e ); vector kids; int idx = -1; bool first = false; int i = 0; for (; i< e.arity(); ++i) { const Expr& kid = e[i]; if (idx == -1 && kid.getOpKind() == CONCAT) { if (kid[kid.arity()-1].getKind() == BVCONST) { idx = i; } else if (kid[0].getKind() == BVCONST && d_theoryBitvector->computeBVConst(kid[0]) != 0) { idx = i; first = true; } else kids.push_back(kid); } else kids.push_back(kid); } if (idx == -1) return d_theoryBitvector->reflexivityRule(e); Expr concatHi, concatLo; if (first) { // Split concat at the first kid if (e[idx].arity() == 2) { concatLo = e[idx][1]; } else { vector concatKids; for (i = 1; i < e[idx].arity(); ++i) { concatKids.push_back(e[idx][i]); } concatLo = d_theoryBitvector->newConcatExpr(concatKids); } concatHi = e[idx][0]; } else { // Split concat at the last kid vector concatKids = e[idx].getKids(); concatLo = concatKids.back(); concatKids.pop_back(); if (concatKids.size() == 1) { concatHi = concatKids[0]; } else { concatHi = d_theoryBitvector->newConcatExpr(concatKids); } } int n = d_theoryBitvector->BVSize(concatLo); kids.push_back(concatLo); Expr bvMult1 = d_theoryBitvector->newBVMultPadExpr(bv_size, kids); kids.pop_back(); kids.push_back(concatHi); Expr bvMult2 = d_theoryBitvector->newBVMultPadExpr(bv_size-n,kids); Expr newLowConcat = d_theoryBitvector->newBVZeroString(n); Expr newConcat = d_theoryBitvector->newConcatExpr(bvMult2, newLowConcat); Expr res_expr = d_theoryBitvector->newBVPlusExpr(bv_size, bvMult1, newConcat); Proof pf; if (withProof()) pf = newPf("liftConcatBVMult"); return newRWTheorem(e, res_expr, Assumptions::emptyAssump(), pf); } // Let c * \prod_1^n a_i be the flattened BVMult term where c is a constant and each a_i cannot be: // a) const, b) bvuminus, c) bvplus, d) bvmult // The canonical form is: // 1. if c = 0, then 0 // 2. if c = 1 and n = 1 then a_1 // 3. else if c = 1 then \prod_1^n a_i // 4. else c * \prod_1^n a_i // Note that \prod should be ordered and made up of binary mult's Theorem BitvectorTheoremProducer::canonBVMult( const Expr& e ) { TRACE("canonBVMult", "canonBVMult: {\n ", e.toString(), " --"); if (CHECK_PROOFS) CHECK_SOUND(e.getOpKind() == BVMULT, "BitvectorTheoremProducer::canonBVMult: input must be a BVMULT expression" + e.toString()); // cout<<"BitvectorTheoremProducer::canonBVMult, e:"<BVSize(e); Theorem result; std::vector mult_vars; Rational temp_coeff = 1; Expr new_expr; Expr no_minus_kid; Expr new_prod; Rational modulus = pow(Rational(bv_size), Rational(2)); // separating all the constants and variables in the // multiplications for( int i = 0; i < expr_arity; ++i) { if (e[i].getOpKind() == BVUMINUS) { temp_coeff = (temp_coeff * (modulus-1)) % modulus; no_minus_kid = e[i][0]; } else no_minus_kid = e[i]; switch (no_minus_kid.getOpKind()) { case BVCONST: { // Collect constants temp_coeff *= d_theoryBitvector->computeBVConst( no_minus_kid ); temp_coeff = temp_coeff % modulus; break; } case BVMULT: { if (no_minus_kid[0].getOpKind() == BVCONST) { // collect coefficient and the variable temp_coeff *= d_theoryBitvector->computeBVConst(no_minus_kid[0]); temp_coeff = temp_coeff % modulus; DebugAssert(no_minus_kid[1].getOpKind() != BVCONST && no_minus_kid[1].getOpKind() != BVPLUS && no_minus_kid[1].getOpKind() != BVUMINUS, "Expected canonized subterm"); if (!new_prod.isNull()) { // multiply the kid by the product so far new_prod = d_theoryBitvector->newBVMultExpr( bv_size, new_prod, no_minus_kid[1]); } else { new_prod = no_minus_kid[1]; } } else { if (!new_prod.isNull()) { // multiply the kid by the product so far new_prod = d_theoryBitvector->newBVMultExpr( bv_size, new_prod, no_minus_kid); } else { new_prod = no_minus_kid; } } break; } case BVPLUS: { result = distributive_rule( e ); TRACE("canonBVMult", "--> ", result.getRHS().toString(), "\n}"); return result; } default: if (!new_prod.isNull()) { // multiply the kid by the product so far new_prod = d_theoryBitvector->newBVMultExpr( bv_size, new_prod, no_minus_kid); } else { new_prod = no_minus_kid; } } } // producing the result if (temp_coeff == 0 || new_prod.isNull()) { // the variables found don't matter new_expr = d_theoryBitvector->newBVConstExpr(temp_coeff, bv_size); } else { if (new_prod.getOpKind() == BVMULT) { new_prod = BVMult_order_subterms(new_prod).getRHS(); } ExprMap sumHashMap; Rational known_term; Expr coeff_expr = d_theoryBitvector->newBVConstExpr(temp_coeff, bv_size); new_expr = d_theoryBitvector->newBVMultExpr(bv_size, coeff_expr, new_prod); getPlusTerms(new_expr, known_term, sumHashMap); new_expr = buildPlusTerm(bv_size, known_term, sumHashMap); } Proof pf; if (withProof()) pf = newPf("canonBVMult"); result = newRWTheorem(e, new_expr, Assumptions::emptyAssump(), pf); TRACE("canonBVMult", "--> ", new_expr.toString(), "\n}"); // cout<<"BitvectorTheoremProducer::canonBVMult, e: "<BVSize(e); // BVMULT terms have just two kids; at least one of the two must be // a BVPLUS vector e0_kids, e1_kids, result_kids; if (e[0].getOpKind() == BVPLUS) { e0_kids = e[0].getKids(); } else e0_kids.push_back(e[0]); if (e[1].getOpKind() == BVPLUS) { e1_kids = e[1].getKids(); } else e1_kids.push_back(e[1]); unsigned e0_kids_size = e0_kids.size(); unsigned e1_kids_size = e1_kids.size(); for( unsigned i = 0; i < e0_kids_size; ++i) { for( unsigned j = 0; j < e1_kids_size; ++j) { Expr sum_term = d_theoryBitvector->newBVMultExpr ( bv_size, e0_kids[i], e1_kids[j] ); result_kids.push_back( sum_term ); } } Expr result_sum = d_theoryBitvector->newBVPlusExpr ( bv_size, result_kids); Proof pf; if (withProof()) pf = newPf("distributive rule"); Theorem result = newRWTheorem( e, result_sum, Assumptions::emptyAssump(), pf); return result; } // BVPLUS(N, a0, ..., an) = BVPLUS(N-n,a0[N-1:n],...an[N-1:n])\@t // where n = BVSize(t), and the sum of the lowest n bits of a0..an is exactly // equal to t (i.e. no carry) Theorem BitvectorTheoremProducer::liftConcatBVPlus(const Expr& e) { if (CHECK_PROOFS) { CHECK_SOUND(e.getOpKind() == BVPLUS, "BitvectorTheoremProducer::liftConcatBVPlus: input must be a BVPLUS expression" + e.toString()); } int bv_size = d_theoryBitvector->BVSize( e ); vector kids; int i = 0; Rational c = 0; if (e[0].getOpKind() == BVCONST) { ++i; c = d_theoryBitvector->computeBVConst(e[0]); } int chopSize = bv_size; bool nonzero = false; bool nonconst = false; Expr term; for (; i< e.arity(); ++i) { const Expr& kid = e[i]; if (kid.getOpKind() != CONCAT) { return d_theoryBitvector->reflexivityRule(e); } Expr last = kid[kid.arity()-1]; int size = d_theoryBitvector->BVSize(last); // If the last concat kid is not a constant, then our only hope is to chop // it off exactly and hope that all other last concat kids are equal to // 0 and wider (in bits) than last if (last.getOpKind() != BVCONST) { if (nonzero || size > chopSize) { return d_theoryBitvector->reflexivityRule(e); } nonzero = true; nonconst = true; chopSize = size; term = last; continue; } // If last is a zero-string, then we are OK, as long as it's at least as // wide as any nonconst we have encountered. If it's less wide than the // constants we have encountered so far, reduce chopSize accordingly if (d_theoryBitvector->computeBVConst(last) == 0) { if (size >= chopSize) continue; if (nonconst) return d_theoryBitvector->reflexivityRule(e); chopSize = size; continue; } // If last is a nonzero const, it's OK as long as it is the only nonzero // thing we encounter if (nonzero) return d_theoryBitvector->reflexivityRule(e); nonzero = true; if (size < chopSize) chopSize = size; term = last; } // if nonzero exists, check the constant if (nonzero) { if (c != 0) { Rational modulus = pow(Rational(chopSize), Rational(2)); if ((c % modulus) != 0) { return d_theoryBitvector->reflexivityRule(e); } } } else if (c == 0) { term = d_theoryBitvector->newBVZeroString(chopSize); } else { term = d_theoryBitvector->newBVExtractExpr(e[0], chopSize-1, 0); } vector newKids; for (i = 0; i < e.arity(); ++i) { newKids.push_back(d_theoryBitvector->newBVExtractExpr(e[i], bv_size-1, chopSize)); } Expr bvPlus = d_theoryBitvector->newBVPlusExpr(bv_size-chopSize, newKids); if (d_theoryBitvector->BVSize(term) > chopSize) { term = d_theoryBitvector->newBVExtractExpr(term, chopSize-1, 0); } Expr res_expr = d_theoryBitvector->newConcatExpr(bvPlus, term); Proof pf; if (withProof()) pf = newPf("liftConcatBVPlus"); return newRWTheorem(e, res_expr, Assumptions::emptyAssump(), pf); } void BitvectorTheoremProducer::getPlusTerms(const Expr& e, Rational& known_term, ExprMap& sumHashMap) { int bv_size = d_theoryBitvector->BVSize( e ); Rational modulus = pow(Rational(bv_size), Rational(2)); unsigned i; vector plusTerms; vector coeffs; plusTerms.push_back(e); coeffs.push_back(1); known_term = 0; for(i = 0; i < plusTerms.size(); ++i) { Expr kid = plusTerms[i]; int kidSize = d_theoryBitvector->BVSize(kid); DebugAssert(kidSize <= bv_size, "Expected kid no wider than bv_size"); Rational coeff = coeffs[i]; if (coeff == 0) continue; switch (kid.getOpKind()) { case BVCONST: known_term += coeff * d_theoryBitvector->computeBVConst( kid ); known_term = known_term % modulus; break; case BVUMINUS: DebugAssert(kidSize == bv_size, "Unexpected size for uminus"); plusTerms.push_back(plusTerms[i][0]); coeffs.push_back((coeff * (modulus - 1)) % modulus); break; case BVNEG: if (kidSize < bv_size) { Rational m2 = pow(Rational(kidSize), Rational(2)); known_term += coeff * (m2-1); } else { known_term += coeff * (modulus-1); } known_term = known_term % modulus; plusTerms.push_back(plusTerms[i][0]); coeffs.push_back((coeff * (modulus-1)) % modulus); break; case BVMULT: if (kidSize < bv_size) { int shift = 0; Rational tcoeff = coeff; for (; tcoeff % 2 == 0; ++shift, tcoeff = tcoeff / 2); if (shift + kidSize < bv_size) { // can't combine different sizes-- // just insert it as is sumHashMap[ kid ] = sumHashMap[ kid ] + coeff; break; } } // OK to combine sizes if( kid[0].getOpKind() == BVCONST ) { DebugAssert(kid.arity() == 2, "Expected arity 2 BVMULT"); plusTerms.push_back(kid[1]); coeffs.push_back((coeff * d_theoryBitvector->computeBVConst(kid[0])) % modulus); } else { sumHashMap[ kid ] = sumHashMap[ kid ] + coeff; } break; case BVPLUS: { if (kidSize < bv_size) { int shift = 0; Rational tcoeff = coeff; for (; tcoeff % 2 == 0; ++shift, tcoeff = tcoeff / 2); if (shift + kidSize < bv_size) { // can't combine BVPLUSes of different size-- // just insert it as is sumHashMap[ kid ] = sumHashMap[ kid ] + coeff; break; } } // OK to combine BVPLUS terms int kid_arity = kid.arity(); for(int j = 0; j < kid_arity; ++j) { plusTerms.push_back(kid[j]); coeffs.push_back(coeff); } break; } case CONCAT: { // Convert CONCAT to BVPLUS int n = d_theoryBitvector->BVSize(kid); Rational concatConst; for (int j = 0; j < kid.arity(); ++j) { const Expr& concatKid = kid[j]; n -= d_theoryBitvector->BVSize(concatKid); concatConst = pow(Rational(n), Rational(2)) * coeff; plusTerms.push_back(concatKid); coeffs.push_back(concatConst % modulus); } break; } case EXTRACT: { // TODO: maybe re-enable this in some cases, but it leads to simplification loops if (false && kidSize < bv_size) { // If the top part of a term is cut off with an extract, try to put it back const Expr& ext_kid = kid[0]; int size = d_theoryBitvector->BVSize(ext_kid); int extractLeft = d_theoryBitvector->getExtractHi(kid); if (extractLeft < size-1) { int shift = 0; Rational tcoeff = coeff; for (; tcoeff % 2 == 0; ++shift, tcoeff = tcoeff / 2); if (shift + kidSize >= bv_size) { int bitsToAdd = bv_size - kidSize; extractLeft += bitsToAdd; if (extractLeft > size - 1) extractLeft = size - 1; int extractRight = d_theoryBitvector->getExtractLow(kid); if (extractLeft == size-1 && extractRight == 0) { plusTerms.push_back(ext_kid); coeffs.push_back(coeff); } else { plusTerms.push_back(d_theoryBitvector->newBVExtractExpr(ext_kid, extractLeft, extractRight)); coeffs.push_back(coeff); } break; } } else { DebugAssert(d_theoryBitvector->getExtractLow(kid) != 0, "Unexpected extract bounds"); } } // fall through } default: sumHashMap[ kid] = sumHashMap[ kid] + coeff; break; } } } Expr BitvectorTheoremProducer::chopConcat(int bv_size, Rational c, vector& concatKids) { int chopSize = bv_size; bool nonzero = false; bool nonconst = false; Expr term, kid, last; int size; unsigned i; for (i = 0; i< concatKids.size(); ++i) { kid = concatKids[i]; if (kid.getOpKind() != CONCAT) return Expr(); last = kid[kid.arity()-1]; size = d_theoryBitvector->BVSize(last); // If the last concat kid is not a constant, then our only hope is to chop // it off exactly and hope that all other last concat kids are equal to // 0 and wider (in bits) than last if (last.getOpKind() != BVCONST) { if (nonzero || size > chopSize) return Expr(); nonzero = true; nonconst = true; chopSize = size; term = last; continue; } // If last is a zero-string, then we are OK, as long as it's at least as // wide as any nonconst we have encountered. If it's less wide than the // constants we have encountered so far, reduce chopSize accordingly if (d_theoryBitvector->computeBVConst(last) == 0) { if (size >= chopSize) continue; if (nonconst) return Expr(); chopSize = size; continue; } // If last is a nonzero const, it's OK as long as it is the only nonzero // thing we encounter if (nonzero) return Expr(); nonzero = true; if (size < chopSize) chopSize = size; term = last; } Rational modulus = pow(Rational(chopSize), Rational(2)); // if nonzero exists, check the constant if (nonzero) { if (c != 0) { if ((c % modulus) != 0) return Expr(); c = c / modulus; } } else if (c == 0) { term = d_theoryBitvector->newBVZeroString(chopSize); } else { Rational value = c % modulus; term = d_theoryBitvector->newBVConstExpr(value, chopSize); c = c - value; c = c / modulus; } // Now chop them for (i = 0; i < concatKids.size(); ++i) { kid = concatKids[i]; vector kids = kid.getKids(); last = kids.back(); kids.pop_back(); size = d_theoryBitvector->BVSize(last); if (size != chopSize) { DebugAssert(size > chopSize, "Expected last to be wider than chopSize"); DebugAssert(last.getOpKind() == BVCONST, "Expected last kind = BVCONST"); Rational value = d_theoryBitvector->computeBVConst(last); if (value != 0) { value = value - (value % modulus); value = value / modulus; } kids.push_back(d_theoryBitvector->newBVConstExpr(value, size - chopSize)); } DebugAssert(kids.size() > 0, "Expected size > 0"); if (kids.size() == 1) { concatKids[i] = kids[0]; } else { concatKids[i] = d_theoryBitvector->newConcatExpr(kids); } } if (d_theoryBitvector->BVSize(term) > chopSize) { DebugAssert(term.getOpKind() == BVCONST, "Expected BVCONST"); Rational value = d_theoryBitvector->computeBVConst(term); DebugAssert(value != 0, "Expected 0"); value = value % modulus; term = d_theoryBitvector->newBVConstExpr(value, chopSize); } Expr bvPlus = chopConcat(bv_size-chopSize, c, concatKids); if (!bvPlus.isNull()) { DebugAssert(bvPlus.getOpKind() == CONCAT, "Expected CONCAT"); vector kids = bvPlus.getKids(); kids.push_back(term); return d_theoryBitvector->newConcatExpr(kids); } vector newKids; if (c != 0) { newKids.push_back(d_theoryBitvector->newBVConstExpr(c, bv_size - chopSize)); } for (i = 0; i < concatKids.size(); ++i) { newKids.push_back(concatKids[i]); } DebugAssert(newKids.size() > 1, "Expected more than one kid"); bvPlus = d_theoryBitvector->newBVPlusExpr(bv_size-chopSize, newKids); // Make sure bvPlus is canonized ExprMap sumHashMap; Rational known_term; getPlusTerms(bvPlus, known_term, sumHashMap); bvPlus = buildPlusTerm(bv_size-chopSize, known_term, sumHashMap); return d_theoryBitvector->newConcatExpr(bvPlus, term); } Expr BitvectorTheoremProducer::buildPlusTerm(int bv_size, Rational& known_term, ExprMap& sumHashMap) { // Try to convert into CONCATs Rational modulus = pow(Rational(bv_size), Rational(2)); Rational coeff, pos; Rational tmask, tcoeff, marked = 0; int nbits, lg; ExprMap::iterator j = sumHashMap.begin(); vector multKids, concatKids; unsigned i; for(; j != sumHashMap.end(); ++j) { coeff = mod((*j).second, modulus); Expr term = (*j).first; nbits = d_theoryBitvector->BVSize(term); // Fast case: coeff is 1 and term takes up all the bits if (coeff == 1 && nbits == bv_size) { if (nbits == 1 && known_term == 1) { // rewrite 1-bit x + 1 as ~x multKids.push_back(d_theoryBitvector->newBVNegExpr(term)); known_term = 0; } else { multKids.push_back(term); } continue; } while (coeff != 0) { for (pos = coeff, lg = 0; pos % 2 == 0; pos = pos / 2, ++lg); pos = pow(Rational(lg), Rational(2)); // Position of lsb containing a 1 Expr concatTerm; // pos of first bit beyond term Rational tmodulus = modulus; if (nbits+lg < bv_size) tmodulus = pow(Rational(nbits+lg), Rational(2)); Rational tcoeff = coeff % tmodulus; if (tcoeff == pos) { coeff -= tcoeff; concatTerm = term; } else if (((tcoeff + pos) % tmodulus) == 0) { coeff = (coeff + pos) % modulus; // rewrite as bvneg concatTerm = d_theoryBitvector->newBVNegExpr(term); known_term += pos; if (nbits + lg < bv_size) { known_term += (modulus - tmodulus); } if (pos == 1 && nbits == bv_size) { multKids.push_back(concatTerm); continue; } } else { // create a BVMULT if (nbits + lg > bv_size) { // term is too big: chop it off int diff = nbits + lg - bv_size; int high, low; if (term.getOpKind() == EXTRACT) { // Collapse extract of extract high = d_theoryBitvector->getExtractHi(term) - diff; low = d_theoryBitvector->getExtractLow(term); term = term[0]; } else { high = nbits - 1 - diff; low = 0; } term = d_theoryBitvector->newBVExtractExpr(term, high, low); } nbits = bv_size - lg; coeff = coeff / pos; Expr new_coeff = d_theoryBitvector->newBVConstExpr(coeff, nbits); term = d_theoryBitvector->newBVMultPadExpr(nbits, new_coeff, term); coeff = 0; if (lg == 0) { multKids.push_back(term); continue; } concatTerm = term; } // Insert concatTerm at position lg into a CONCAT bool found = false; Expr t; vector tmp; int bits, size, k, t_arity; for (i = 0; i < concatKids.size(); ++i) { t = concatKids[i]; DebugAssert(t.getOpKind() == CONCAT, "Expected CONCAT"); bits = bv_size; t_arity = t.arity(); for (k = 0; k < t_arity; ++k) { if (k > 0 && bits < lg + nbits) break; size = d_theoryBitvector->BVSize(t[k]); if (bits - size <= lg) { if (t[k].getOpKind() == BVCONST) { found = true; } break; } else { tmp.push_back(t[k]); bits -= size; } } if (found) break; tmp.clear(); } if (!found) { bits = bv_size; size = bv_size; k = t_arity = 0; } if (lg + nbits < bits) { tmp.push_back(d_theoryBitvector->newBVZeroString(bits-(lg+nbits))); } if (lg + nbits > bits) { bool negate = false; if (concatTerm.getOpKind() == BVNEG) { // Push extract inside negation negate = true; concatTerm = concatTerm[0]; } DebugAssert(!found || k == 0, "Too big only OK for first child"); // If term is too big, chop it off int diff = lg + nbits - bits; int high, low; if (concatTerm.getOpKind() == EXTRACT) { // Collapse extract of extract high = d_theoryBitvector->getExtractHi(concatTerm) - diff; low = d_theoryBitvector->getExtractLow(concatTerm); concatTerm = concatTerm[0]; } else { high = nbits - 1 - diff; low = 0; } concatTerm = d_theoryBitvector->newBVExtractExpr(concatTerm, high, low); if (negate) { concatTerm = d_theoryBitvector->newBVNegExpr(concatTerm); } } tmp.push_back(concatTerm); bits -= size; if (lg > bits) { tmp.push_back(d_theoryBitvector->newBVZeroString(lg-bits)); } for (++k; k < t_arity; ++k) { tmp.push_back(t[k]); } if (tmp.size() == 1) { DebugAssert(!found, "Invariant violated"); multKids.push_back(tmp[0]); } else if (found) { // replace existing concat term concatKids[i] = d_theoryBitvector->newConcatExpr(tmp); } else { // push back new concat term concatKids.push_back(d_theoryBitvector->newConcatExpr(tmp)); } } } known_term = known_term % modulus; // See if we can merge constant in with CONCATs if (known_term != 0 && !concatKids.empty()) { vector tmp; for (i = 0; i < concatKids.size(); ++i) { Expr t = concatKids[i]; DebugAssert(t.getOpKind() == CONCAT, "Expected CONCAT"); int bits = bv_size; int size; bool anyChanged = false; for (int k = 0; k < t.arity(); ++k) { size = d_theoryBitvector->BVSize(t[k]); bool changed = false; if (known_term != 0 && t[k].getOpKind() == BVCONST) { Rational high = pow(Rational(bits), Rational(2)); Rational partConst = known_term % high; if (partConst != 0) { Rational low = pow(Rational(bits - size), Rational(2)); partConst = partConst - (partConst % low); if (partConst != 0) { anyChanged = changed = true; tmp.push_back(d_theoryBitvector->newBVConstExpr(partConst / low, size)); known_term -= partConst; } } } if (!changed) { tmp.push_back(t[k]); } bits -= size; } if (anyChanged) { concatKids[i] = d_theoryBitvector->newConcatExpr(tmp); if (known_term == 0) break; } tmp.clear(); } } // reassembling terms into a unique BVPLUS expression Expr expr_result; // Check to see if we can chop off the bottom of the BVPLUS if (multKids.size() == 0 && (concatKids.size() > 1 || (concatKids.size() == 1 && known_term != 0))) { expr_result = chopConcat(bv_size, known_term, concatKids); if (!expr_result.isNull()) return expr_result; } if (known_term == 0) { for (i = 0; i < concatKids.size(); ++i) { multKids.push_back(concatKids[i]); } if (multKids.size() == 0) { expr_result = d_theoryBitvector->newBVConstExpr( Rational(0), bv_size); } else if (multKids.size() == 1) { expr_result = multKids[0]; } else { expr_result = d_theoryBitvector->newBVPlusExpr( bv_size, multKids); } } else { vector sumKids; sumKids.push_back( d_theoryBitvector->newBVConstExpr( known_term, bv_size)); for (i = 0; i < multKids.size(); ++i) { sumKids.push_back(multKids[i]); } for (i = 0; i < concatKids.size(); ++i) { sumKids.push_back(concatKids[i]); } if (sumKids.size() == 1) { expr_result = sumKids[0]; } else { expr_result = d_theoryBitvector->newBVPlusExpr( bv_size, sumKids); } } return expr_result; } // It assumes that all the kids have already been canonized Theorem BitvectorTheoremProducer::canonBVPlus( const Expr& e ) { TRACE("canonBVPlus", "canonBVPlus: {\n ", e.toString(), " --"); if (CHECK_PROOFS) CHECK_SOUND(e.getOpKind() == BVPLUS, "BitvectorTheoremProducer::canonBVPlus: input must be a BVPLUS expression" + e.toString()); // cout<<"BitvectorTheoremProducer::canonBVPlus, e is: "< sumHashMap; int bv_size = d_theoryBitvector->BVSize( e ); Rational known_term; // Get plus terms in a hash map getPlusTerms(e, known_term, sumHashMap); // Build the plus term from known_term, sumHashMap Expr expr_result = buildPlusTerm(bv_size, known_term, sumHashMap); Proof pf; if (withProof()) pf = newPf("canonBVPlus"); Theorem result = newRWTheorem( e, expr_result, Assumptions::emptyAssump(), pf); TRACE("canonBVPlus", "--> ", expr_result.toString(), "\n}"); return result; } Theorem BitvectorTheoremProducer::canonBVUMinus( const Expr& e ) { if (CHECK_PROOFS) CHECK_SOUND(e.getOpKind() == BVUMINUS, "BitvectorTheoremProducer::canonBVUMinus: input must be a BVUMINUS expression" + e.toString()); int bv_size = d_theoryBitvector->BVSize(e); Rational modulus = pow(Rational(bv_size), Rational(2)); Expr coeff = d_theoryBitvector->newBVConstExpr(modulus-1, bv_size); Expr res_expr = d_theoryBitvector->newBVMultExpr(bv_size, coeff, e[0]); Proof pf; if (withProof()) pf = newPf("canonBVUMinus"); return newRWTheorem(e, res_expr, Assumptions::emptyAssump(), pf); } /*End of Lorenzo PLatania's methods*/ // Input: t[hi:lo] = rhs // if t appears as leaf in rhs, then: // t[hi:lo] = rhs |- Exists x,y,z. (t = x \@ y \@ z AND y = rhs), solvedForm = false // else // t[hi:lo] = rhs |- Exists x,z. (t = x \@ rhs \@ z), solvedForm = true Theorem BitvectorTheoremProducer::processExtract(const Theorem& e, bool& solvedForm) { Expr expr = e.getExpr(); if (CHECK_PROOFS) { CHECK_SOUND(expr.getOpKind() == EQ && expr[0].getOpKind() == EXTRACT, "BitvectorTheoremProducer::processExtract: invalid input"); CHECK_SOUND(d_theoryBitvector->BVSize(expr[0]) == d_theoryBitvector->BVSize(expr[1]), "Expected same size"); } Expr ext = expr[0]; Expr lhs; Expr rhs = expr[1]; Expr child = ext[0]; int size = d_theoryBitvector->BVSize(child); int high = d_theoryBitvector->getExtractHi(ext); int low = d_theoryBitvector->getExtractLow(ext); DebugAssert(d_theoryBitvector->isLeaf(child), "Expected leaf"); solvedForm = !d_theoryBitvector->isLeafIn(child, rhs); vector terms; vector boundVars; if (high < size-1) { terms.push_back(d_theoryBitvector->getEM()->newBoundVarExpr(d_theoryBitvector->newBitvectorType(size-1-high))); boundVars.push_back(terms.back()); } if (solvedForm) terms.push_back(rhs); else { lhs = d_theoryBitvector->getEM()->newBoundVarExpr(d_theoryBitvector->newBitvectorType(high-low+1)); terms.push_back(lhs); boundVars.push_back(lhs); } if (low > 0) { terms.push_back(d_theoryBitvector->getEM()->newBoundVarExpr(d_theoryBitvector->newBitvectorType(low))); boundVars.push_back(terms.back()); } DebugAssert(terms.size() > 1, "Expected at least two terms"); Expr result = child.eqExpr(d_theoryBitvector->newConcatExpr(terms)); if (!solvedForm) result = result && lhs.eqExpr(rhs); result = d_theoryBitvector->getEM()->newClosureExpr(EXISTS, boundVars, result); Assumptions a(e); Proof pf; if (withProof()) pf = newPf("processExtract"); return newTheorem(result, a, pf); } bool BitvectorTheoremProducer::okToSplit(const Expr& e) { if (d_theoryBitvector->isLeaf(e)) return true; switch (e.getOpKind()) { case BVCONST: case EXTRACT: case BVAND: case BVOR: case BVXOR: case BVNEG: return true; case BVSHL: case BVLSHR: case BVASHR: case BVPLUS: case BVMULT: case BVUDIV: case BVSDIV: case BVUREM: case BVSREM: case BVSMOD: return false; default: FatalAssert(false, "unexpected kind in okToSplit"); break; } return false; } // puts the equation in solved form if possible, otherwise in the form // \sum a_i*x_i +c = 0. // default maxEffort is 3: solves only when lhs can be isolated without splitting // maxEffort 5: solves when lhs can be isolated with splitting // maxEffort 6: solves even when result is not in solved form (good for bitblasting) Theorem BitvectorTheoremProducer::canonBVEQ( const Expr& e, int maxEffort ) { TRACE("canonBVEQ", "canonBVEQ: {\n ", e.toString(), " --"); DebugAssert(maxEffort == 3 || maxEffort == 5 || maxEffort == 6, "Unexpected value for maxEffort"); if(CHECK_PROOFS) { CHECK_SOUND( e.getOpKind() == EQ, "BitvectorTheoremProducer::canonBVEQ: expression must be an equation"); CHECK_SOUND(BITVECTOR==e[0].getType().getExpr().getOpKind(), "input must be a bitvector eqn. \n e = " + e.toString()); } Expr lhs = e[0]; Expr rhs = e[1]; int bv_size = d_theoryBitvector->BVSize( lhs ); // Look for easy split of concats if (lhs.getOpKind() == CONCAT || rhs.getOpKind() == CONCAT) { Expr::iterator lit, rit; int lsize, rsize; if (lhs.getOpKind() == CONCAT) { lit = e[0].begin(); } else { lit = e.begin(); } if (rhs.getOpKind() == CONCAT) { rit = e[1].begin(); } else { rit = e.begin(); ++rit; } int splitSize; lsize = d_theoryBitvector->BVSize(*lit); rsize = d_theoryBitvector->BVSize(*rit); while (true) { DebugAssert(lsize <= bv_size && rsize <= bv_size, "invariant violated"); if (lsize < rsize) { if (okToSplit(*rit)) { splitSize = lsize; break; } else { ++lit; lsize += d_theoryBitvector->BVSize(*lit); } } else if (lsize > rsize) { if (okToSplit(*lit)) { splitSize = rsize; break; } else { ++rit; rsize += d_theoryBitvector->BVSize(*rit); } } else { splitSize = lsize; break; } } if (splitSize != bv_size) { Proof pf; if (withProof()) pf = newPf("canonBVEQ"); Expr tmp = d_theoryBitvector->newBVExtractExpr(lhs, bv_size-1, bv_size-splitSize); tmp = tmp.eqExpr(d_theoryBitvector->newBVExtractExpr(rhs, bv_size-1, bv_size-splitSize)); Expr expr_result = d_theoryBitvector->newBVExtractExpr(lhs, bv_size-splitSize-1, 0); expr_result = expr_result.eqExpr(d_theoryBitvector->newBVExtractExpr(rhs, bv_size-splitSize-1, 0)); expr_result = tmp && expr_result; TRACE("canonBVEQ", "--> ", expr_result.toString(), "\n}"); return newRWTheorem( e, expr_result, Assumptions::emptyAssump(), pf); } } rhs = d_theoryBitvector->newBVUminusExpr(rhs); ExprMap sumHashMap; Rational modulus = pow(Rational(bv_size), Rational(2)); Rational known_term; getPlusTerms(d_theoryBitvector->newBVPlusExpr(bv_size, lhs, rhs), known_term, sumHashMap); // Loop through all terms and perform two tasks: // A. Truncate coefficients // B. Look for a something to solve for: // 1. first choice: full-sized leaf not occurring elsewhere // 2. second choice: full-sized leaf inside BVXOR not occurring elsewhere // 3. third choice: full-sized extract of a leaf or over-sized leaf or extract of leaf // 4. fourth choice: under-sized leaf not occurring elsewhere or extract of leaf // 5. fifth choice: even-coeff leaf not occurring elsewhere or extract of leaf // 6. sixth choice: first term with an odd coeff (even if not a leaf or occurring elsewhere) // 7. seventh choice: nothing to solve for and all coeffs are even // If choice > maxEffort (and not 7), put in form sum = 0 instead. Rational coeff, foundCoeff = 1; ExprMap::iterator j = sumHashMap.begin(); ExprMap::iterator fixCoeff = j; Expr xor_leaf, leaf, foundterm; unsigned xor_idx=0, xor_size=0; int priority, size, foundpriority = 7; bool isExtract; for(; j != sumHashMap.end(); ++j) { Expr t = (*j).first; coeff = (*j).second; size = d_theoryBitvector->BVSize(t); if (j == fixCoeff) { coeff = (*j).second = mod(coeff, modulus); ++fixCoeff; } if (coeff == 0) continue; priority = 7; isExtract = false; if (coeff % 2 == 1) { if (d_theoryBitvector->isLeaf(t)) { if (size == bv_size) { leaf = t; priority = 1; } else if (size > bv_size) { isExtract = true; leaf = t; priority = 3; } else { leaf = t; priority = 4; } } else if (t.getOpKind() == EXTRACT && d_theoryBitvector->isLeaf(t[0])) { isExtract = true; if (size >= bv_size) { leaf = t[0]; priority = 3; } else { leaf = t[0]; priority = 4; } } else if (t.getOpKind() == BVXOR && size == bv_size) { if (foundpriority == 2) continue; xor_idx = 0; xor_size = t.arity(); for (xor_idx = 0; xor_idx < xor_size; ++xor_idx) { if (!d_theoryBitvector->isLeaf(t[xor_idx])) { continue; } unsigned l = 0; for (; l < xor_size; ++l) { if (l == xor_idx) continue; if (d_theoryBitvector->isLeafIn(t[xor_idx], t[l])) break; } if (l < xor_size) continue; break; } if (xor_idx < xor_size) { leaf = t[xor_idx]; xor_leaf = leaf; priority = 2; } else { leaf = t; priority = 6; } } else { leaf = t; priority = 6; } } else if (maxEffort >= 5) { if (d_theoryBitvector->isLeaf(t)) { leaf = t; priority = 5; } else if (t.getOpKind() == EXTRACT && d_theoryBitvector->isLeaf(t[0])) { isExtract = true; leaf = t[0]; priority = 5; } } if (priority < foundpriority) { if (priority < 6) { ExprMap::iterator k = sumHashMap.begin(); while (k != sumHashMap.end()) { if (j == k) { ++k; continue; } if (k == fixCoeff) { (*k).second = mod((*k).second, modulus); ++fixCoeff; } if ((*k).second == 0) { ++k; continue; } if (!isExtract && d_theoryBitvector->isLeafIn(leaf, (*k).first)) { if (priority == 2) { // Try to find another leaf in the BVXOR for (++xor_idx; xor_idx < xor_size; ++xor_idx) { if (!d_theoryBitvector->isLeaf(t[xor_idx])) { continue; } unsigned l = 0; for (; l < xor_size; ++l) { if (l == xor_idx) continue; if (d_theoryBitvector->isLeafIn(t[xor_idx], t[l])) break; } if (l < xor_size) continue; break; } if (xor_idx < xor_size) { // found a leaf, continue checking it leaf = t[xor_idx]; xor_leaf = leaf; k = sumHashMap.begin(); continue; } } // this leaf cannot be solved for break; } ++k; } if (k == sumHashMap.end()) { foundpriority = priority; foundterm = t; if (coeff == 1 || priority == 5) foundCoeff = 1; else foundCoeff = d_theoryBitvector->multiplicative_inverse(coeff, bv_size); if (priority == 1) break; } } if (foundpriority > 6 && priority != 5) { foundpriority = 6; foundterm = t; if (coeff == 1) foundCoeff = 1; else foundCoeff = d_theoryBitvector->multiplicative_inverse(coeff, bv_size); } } } bool solving = (foundpriority <= maxEffort); if (foundpriority == 7) { // All coeffs are even if (known_term % 2 == 1) { Proof pf; if (withProof()) pf = newPf("canonBVEQ"); TRACE("canonBVEQ", "--> ", d_theoryBitvector->falseExpr().toString(), "\n}"); return newRWTheorem(e, d_theoryBitvector->falseExpr(), Assumptions::emptyAssump(), pf); } else foundCoeff = foundCoeff / Rational(2); if (bv_size > 1) { bv_size = bv_size - 1; modulus = pow(Rational(bv_size), Rational(2)); } } else if (!solving && (e[1] == d_theoryBitvector->newBVZeroString(bv_size))) { // if we aren't solving, and rhs was already 0, then stop here: lhs already normalized by plus canonizer // further rewriting risks a simplification loop TRACE("canonBVEQ", "--> ", e, "\n}"); return newReflTheorem(e); } Rational solveCoeff = 0; // Multiply through by foundCoeff if it is not 1 // Also, multiply by -1 (i.e. subtract from modulus) if solving if (solving || foundCoeff != 1) { known_term = (known_term * foundCoeff) % modulus; if (solving && known_term != 0) known_term = modulus - known_term; for(j = sumHashMap.begin(); j != sumHashMap.end(); ++j) { coeff = (*j).second; if (coeff == 0) continue; (*j).second = (coeff * foundCoeff) % modulus; if (solving) { if ((*j).first == foundterm) { // remove the leaf being solved for solveCoeff = (*j).second; (*j).second = 0; } else { (*j).second = modulus - (*j).second; } } } } // Collect the terms for the new bitplus term Expr plusTerm = buildPlusTerm(bv_size, known_term, sumHashMap); Expr new_lhs, new_rhs, expr_result; // Solve the equation if (solving) { DebugAssert(solveCoeff != 0, "Expected solveCoeff != 0"); if (foundpriority == 6 && d_theoryBitvector->BVSize(foundterm) < bv_size) { // zero-extend to get the right size foundterm = d_theoryBitvector->pad(bv_size, foundterm); } switch (foundpriority) { case 1: // 1. first choice: full-sized leaf // foundterm is full-sized leaf case 6: // 6. sixth choice: Not in solved form, but isolate first term // with odd coeff on lhs anyway. DebugAssert(solveCoeff == 1, "Expected coeff = 1"); new_lhs = foundterm; new_rhs = plusTerm; break; case 2: { // 2. second choice: leaf inside BVXOR DebugAssert(solveCoeff == 1, "Expected coeff = 1"); vector rhsTerms; rhsTerms.push_back(plusTerm); for (unsigned l = 0; l < xor_size; ++l) { if (l == xor_idx) continue; rhsTerms.push_back(foundterm[l]); } new_lhs = xor_leaf; new_rhs = d_theoryBitvector->newBVXorExpr(rhsTerms); break; } case 3: // 3. third choice: full-sized extract of a leaf or over-sized leaf or extract of leaf // foundterm is full-sized extract of leaf DebugAssert(solveCoeff == 1, "Expected coeff = 1"); if (d_theoryBitvector->BVSize(foundterm) > bv_size) { if (foundterm.getOpKind() == EXTRACT) { int diff = d_theoryBitvector->BVSize(foundterm) - bv_size; int high = d_theoryBitvector->getExtractHi(foundterm); int low = d_theoryBitvector->getExtractLow(foundterm); foundterm = d_theoryBitvector->newBVExtractExpr(foundterm[0], high - diff, low); } else { foundterm = d_theoryBitvector->newBVExtractExpr(foundterm, bv_size-1, 0); } } new_lhs = foundterm; new_rhs = plusTerm; break; case 4: { // 4. fourth choice: under-sized leaf or extract of leaf // foundterm is less than full-sized extract or leaf DebugAssert(solveCoeff == 1, "Expected coeff = 1"); int foundtermsize = d_theoryBitvector->BVSize(foundterm); DebugAssert(foundtermsize < bv_size, "Expected undersized term"); new_rhs = d_theoryBitvector->newBVExtractExpr(plusTerm, foundtermsize-1, 0); expr_result = foundterm.eqExpr(new_rhs); new_rhs = d_theoryBitvector->newBVExtractExpr(plusTerm, bv_size-1, foundtermsize); new_lhs = d_theoryBitvector->newBVZeroString(bv_size - foundtermsize); expr_result = expr_result && new_lhs.eqExpr(new_rhs); break; } case 5: { // 5. fifth choice: even-coeff leaf or extract of leaf // foundterm has even coeff int lg = 0; for (; solveCoeff % 2 == 0; solveCoeff = solveCoeff / 2, ++lg); new_lhs = d_theoryBitvector->newBVConstExpr(solveCoeff, bv_size-lg); new_lhs = d_theoryBitvector->newBVMultPadExpr(bv_size-lg, new_lhs, foundterm); new_rhs = d_theoryBitvector->newBVExtractExpr(plusTerm, bv_size-1, lg); expr_result = new_lhs.eqExpr(new_rhs); new_lhs = d_theoryBitvector->newBVZeroString(lg); new_rhs = d_theoryBitvector->newBVExtractExpr(plusTerm, lg - 1, 0); expr_result = expr_result && new_lhs.eqExpr(new_rhs); break; } default: FatalAssert(false, "Expected priority < 7"); break; } } else { new_lhs = plusTerm; new_rhs = d_theoryBitvector->newBVZeroString(bv_size); } if (expr_result.isNull()) { if ( new_lhs == new_rhs) { expr_result = d_theoryBitvector->trueExpr(); } else if ( new_lhs >= new_rhs) { expr_result = Expr(EQ, new_lhs, new_rhs); } else { expr_result = Expr(EQ, new_rhs, new_lhs); } } Proof pf; if (withProof()) pf = newPf("canonBVEQ"); TRACE("canonBVEQ", "--> ", expr_result.toString(), "\n}"); Theorem result = newRWTheorem( e, expr_result, Assumptions::emptyAssump(), pf); return result; } //! BVZEROEXTEND(e, i) = zeroString \@ e // where zeroString is a string of i zeroes Theorem BitvectorTheoremProducer::zeroExtendRule(const Expr& e) { if(CHECK_PROOFS) { CHECK_SOUND(BITVECTOR==e.getType().getExpr().getOpKind(), "input must be a bitvector. \n e = " + e.toString()); CHECK_SOUND(BVZEROEXTEND == e.getOpKind(), "input must be BVZEROEXTEND(e).\n e = " + e.toString()); } int extendLen = d_theoryBitvector->getBVIndex(e); Expr res; if (extendLen == 0) { res = e[0]; } else { Expr extend = d_theoryBitvector->newBVZeroString(extendLen); res = d_theoryBitvector->newConcatExpr(extend, e[0]); } Proof pf; if(withProof()) pf = newPf("zero_extend_rule"); Theorem result(newRWTheorem(e, res, Assumptions::emptyAssump(), pf)); return result; } //! BVREPEAT(e, i) = e \@ e \@ ... \@ e // where e appears i times on the right Theorem BitvectorTheoremProducer::repeatRule(const Expr& e) { if(CHECK_PROOFS) { CHECK_SOUND(BITVECTOR==e.getType().getExpr().getOpKind(), "input must be a bitvector. \n e = " + e.toString()); CHECK_SOUND(BVREPEAT == e.getOpKind(), "input must be BVREPEAT(e).\n e = " + e.toString()); CHECK_SOUND(d_theoryBitvector->getBVIndex(e) > 0, "Expected positive repeat value"); } int repeatVal = d_theoryBitvector->getBVIndex(e); Expr res; if (repeatVal == 1) { res = e[0]; } else { vector kids; for (int i = 0; i < repeatVal; ++i) { kids.push_back(e[0]); } res = d_theoryBitvector->newConcatExpr(kids); } Proof pf; if(withProof()) pf = newPf("repeat_rule"); Theorem result(newRWTheorem(e, res, Assumptions::emptyAssump(), pf)); return result; } //! BVROTL(e, i) = a[n-i-1:0] \@ a[n-1:n-i] // where n is the size of e and i is less than n (otherwise i mod n is used) Theorem BitvectorTheoremProducer::rotlRule(const Expr& e) { if(CHECK_PROOFS) { CHECK_SOUND(BITVECTOR==e.getType().getExpr().getOpKind(), "input must be a bitvector. \n e = " + e.toString()); CHECK_SOUND(BVROTL == e.getOpKind(), "input must be BVROTL(e).\n e = " + e.toString()); } int bvsize = d_theoryBitvector->BVSize(e); int rotation = d_theoryBitvector->getBVIndex(e); rotation = rotation % bvsize; Expr res; if (rotation == 0) { res = e[0]; } else { Expr hi = d_theoryBitvector->newBVExtractExpr(e[0],bvsize-1-rotation,0); Expr low = d_theoryBitvector->newBVExtractExpr(e[0],bvsize-1, bvsize-rotation); res = d_theoryBitvector->newConcatExpr(hi, low); } Proof pf; if(withProof()) pf = newPf("rotl_rule"); Theorem result(newRWTheorem(e, res, Assumptions::emptyAssump(), pf)); return result; } //! BVROTR(e, i) = a[i-1:0] \@ a[n-1:i] // where n is the size of e and i is less than n (otherwise i mod n is used) Theorem BitvectorTheoremProducer::rotrRule(const Expr& e) { if(CHECK_PROOFS) { CHECK_SOUND(BITVECTOR==e.getType().getExpr().getOpKind(), "input must be a bitvector. \n e = " + e.toString()); CHECK_SOUND(BVROTR == e.getOpKind(), "input must be BVROTR(e).\n e = " + e.toString()); } int bvsize = d_theoryBitvector->BVSize(e); int rotation = d_theoryBitvector->getBVIndex(e); rotation = rotation % bvsize; Expr res; if (rotation == 0) { res = e[0]; } else { Expr hi = d_theoryBitvector->newBVExtractExpr(e[0],rotation-1,0); Expr low = d_theoryBitvector->newBVExtractExpr(e[0],bvsize-1, rotation); res = d_theoryBitvector->newConcatExpr(hi, low); } Proof pf; if(withProof()) pf = newPf("rotr_rule"); Theorem result(newRWTheorem(e, res, Assumptions::emptyAssump(), pf)); return result; } Theorem BitvectorTheoremProducer::bvURemConst(const Expr& remExpr) { const Expr& a = remExpr[0]; const Expr& b = remExpr[1]; int size = d_theoryBitvector->BVSize(remExpr); Rational a_value = d_theoryBitvector->computeBVConst(a); Rational b_value = d_theoryBitvector->computeBVConst(b); Expr rem; if (b_value != 0) { Rational rem_value = a_value - floor(a_value / b_value)*b_value; rem = d_theoryBitvector->newBVConstExpr(rem_value, size); } else { static int div_by_zero_count = 0; div_by_zero_count ++; char var_name[10000]; sprintf(var_name, "mod_by_zero_const_%d", div_by_zero_count); rem = d_theoryBitvector->newVar(var_name, remExpr.getType()); } Proof pf; if (withProof()) pf = newPf("bvUDivConst"); return newRWTheorem(remExpr, rem, Assumptions::emptyAssump(), pf); } Theorem BitvectorTheoremProducer::bvURemRewrite(const Expr& remExpr) { Expr a = remExpr[0]; Expr b = remExpr[1]; int size = d_theoryBitvector->BVSize(remExpr); Expr div = d_theoryBitvector->newBVUDivExpr(a, b); Expr rem = d_theoryBitvector->newBVSubExpr(a, d_theoryBitvector->newBVMultExpr(size, div, b)); Proof pf; if (withProof()) pf = newPf("bvURemRewrite", remExpr); return newRWTheorem(remExpr, rem, Assumptions::emptyAssump(), pf); } Theorem BitvectorTheoremProducer::bvUDivConst(const Expr& divExpr) { const Expr& a = divExpr[0]; const Expr& b = divExpr[1]; int size = d_theoryBitvector->BVSize(divExpr); Rational a_value = d_theoryBitvector->computeBVConst(a); Rational b_value = d_theoryBitvector->computeBVConst(b); Expr div; if (b_value != 0) { Rational div_value = floor(a_value / b_value); div = d_theoryBitvector->newBVConstExpr(div_value, size); } else { static int div_by_zero_count = 0; div_by_zero_count ++; char var_name[10000]; sprintf(var_name, "div_by_zero_const_%d", div_by_zero_count); div = d_theoryBitvector->newVar(var_name, divExpr.getType()); } Proof pf; if (withProof()) pf = newPf("bvUDivConst"); return newRWTheorem(divExpr, div, Assumptions::emptyAssump(), pf); } Theorem BitvectorTheoremProducer::bvUDivTheorem(const Expr& divExpr) { int size = d_theoryBitvector->BVSize(divExpr); if(CHECK_PROOFS) { CHECK_SOUND(BITVECTOR == divExpr.getType().getExpr().getOpKind(), "input must be a bitvector. \n e = " + divExpr.toString()); CHECK_SOUND(BVUDIV == divExpr.getOpKind(),"input must be BVUDIV(e).\n e = " + divExpr.toString()); } const Expr a = divExpr[0]; const Expr b = divExpr[1]; Type type = divExpr.getType(); Expr div = d_theoryBitvector->getEM()->newBoundVarExpr(type); Expr mod = d_theoryBitvector->getEM()->newBoundVarExpr(type); vector boundVars; boundVars.push_back(div); boundVars.push_back(mod); vector assertions; Expr pad = d_theoryBitvector->newBVConstExpr(Rational(0), size); Expr a_expanded = d_theoryBitvector->newConcatExpr(pad, a); Expr b_expanded = d_theoryBitvector->newConcatExpr(pad, b); Expr div_expanded = d_theoryBitvector->newConcatExpr(pad, div); Expr mod_expanded = d_theoryBitvector->newConcatExpr(pad, mod); assertions.push_back(a_expanded.eqExpr( d_theoryBitvector->newBVPlusExpr(2*size, d_theoryBitvector->newBVMultExpr(2*size, b_expanded, div_expanded), mod_expanded ) ) ); assertions.push_back(d_theoryBitvector->newBVLTExpr(mod, b)); Expr non_zero_div = andExpr(assertions); // b != 0 -> a = b*div + mod ... Expr complete_div = (b.eqExpr(d_theoryBitvector->newBVConstExpr(Rational(0), size))).negate().impExpr(non_zero_div); // x/y = div \wedge complete_div complete_div = divExpr.eqExpr(div).andExpr(complete_div); // Close the result Expr result = d_theoryBitvector->getEM()->newClosureExpr(EXISTS, boundVars, complete_div); // Make the proof Proof pf; if (withProof()) pf = newPf("bvUDiv"); // Return the theorem return newTheorem(result, Assumptions::emptyAssump(), pf); } Theorem BitvectorTheoremProducer::bitblastBVMult(const std::vector& a_bits, const std::vector& b_bits, const Expr& a_times_b, std::vector& output_bits) { if(CHECK_PROOFS) { CHECK_SOUND(a_times_b.arity() == 2, "must be a binary multiplication"); CHECK_SOUND(BITVECTOR == a_times_b.getType().getExpr().getOpKind(), "input must be a bitvector. \n e = " + a_times_b.toString()); CHECK_SOUND(BVMULT == a_times_b.getOpKind(),"input must be BVMULT(e).\n e = " + a_times_b.toString()); CHECK_SOUND(a_bits.size() == b_bits.size(), "given bit expansions of different size"); CHECK_SOUND((int) a_bits.size() <= d_theoryBitvector->BVSize(a_times_b), "the expansion is bigger than the multiplier"); } int size = a_bits.size(); Expr falseExpr = d_theoryBitvector->falseExpr(); // DISABLED FOR NOW, WE ARENT ENSURING THAT ALL TERMS THAT ENTER BITBLASTING // ARE NON-ZERO // if (CHECK_PROOFS) { // bool all_zero = true; // Expr a = a_times_b[0]; // for (int bit = 0; bit < size; bit++) { // Theorem bit_i = a_bits[bit]; // Expr bit_extract = d_theoryBitvector->newBoolExtractExpr(a, bit); // CHECK_SOUND(bit_extract == bit_i.getLHS(), "not the right bit theorems"); // if (bit_i.getRHS() != falseExpr) all_zero = false; // } // CHECK_SOUND(!all_zero, "expected non-zero inputs"); // all_zero = true; // Expr b = a_times_b[1]; // for (int bit = 0; bit < size; bit++) { // Theorem bit_i = b_bits[bit]; // Expr bit_extract = d_theoryBitvector->newBoolExtractExpr(b, bit); // CHECK_SOUND(bit_extract == bit_i.getLHS(), "not the right bit theorems"); // if (bit_i.getRHS() != falseExpr) all_zero = false; // } // CHECK_SOUND(!all_zero, "expected non-zero inputs"); // } vector sum_bits; vector carry_bits; // Find the first non-zero bits in a and b int a_bit, b_bit; for (a_bit = size - 1; a_bit >= 0 && a_bits[a_bit].getRHS() == falseExpr; a_bit --); for (b_bit = size - 1; b_bit >= 0 && b_bits[b_bit].getRHS() == falseExpr; b_bit --); // DISABLED, SAME AS ABOVE // DebugAssert(a_bit >= 0 && b_bit >= 0, "Expected non-zero inputs"); int new_size = size; if (a_bit + b_bit + 2 < new_size) new_size = a_bit + b_bit + 2; // Build the first row of the multiplier for (int i = 0; i < new_size; i ++) { sum_bits.push_back(a_bits[i].getRHS().andExpr(b_bits[0].getRHS())); carry_bits.push_back(d_theoryBitvector->falseExpr()); } // Now go down the rows Expr carry = d_theoryBitvector->falseExpr(); for (int row = 1; row < new_size; row ++) { for (int bit = new_size-1; bit >= row; bit --) { Expr m = a_bits[bit-row].getRHS().andExpr(b_bits[row].getRHS()); Expr sum = sum_bits[bit].iffExpr(m).iffExpr(carry_bits[bit - 1]); Expr carry = sum_bits[bit].andExpr(m).orExpr(carry_bits[bit - 1].andExpr(sum_bits[bit].orExpr(m))); sum_bits[bit] = sum; carry_bits[bit] = carry; } // The carry on the side of the multiplier carry = carry.orExpr(carry_bits[new_size - 1]); } // Create all the theorems now for (int bit = 0; bit < size; bit ++) { Proof pf; if (withProof()) { pf = newPf("bitblastBVMult", a_times_b, rat(bit)); } output_bits.push_back(newRWTheorem(d_theoryBitvector->newBoolExtractExpr(a_times_b, bit), bit < new_size ? sum_bits[bit] : falseExpr, Assumptions::emptyAssump(), pf)); } Theorem carry_thm; return carry_thm; } Theorem BitvectorTheoremProducer::bitblastBVPlus(const std::vector& a_bits, const std::vector& b_bits, const Expr& a_plus_b, std::vector& output_bits) { if(CHECK_PROOFS) { CHECK_SOUND(a_plus_b.arity() == 2, "must be a binary addition"); CHECK_SOUND(BITVECTOR == a_plus_b.getType().getExpr().getOpKind(), "input must be a bitvector. \n e = " + a_plus_b.toString()); CHECK_SOUND(BVPLUS == a_plus_b.getOpKind(),"input must be BVPLUS(e).\n e = " + a_plus_b.toString()); CHECK_SOUND(a_bits.size() == b_bits.size(), "given bit expansions of different size"); CHECK_SOUND((int) a_bits.size() <= d_theoryBitvector->BVSize(a_plus_b), "the expansion is bigger than the multiplier"); } int size = a_bits.size(); if (CHECK_PROOFS) { Expr a = a_plus_b[0]; for (int bit = 0; bit < size; bit++) { Theorem bit_i = a_bits[bit]; Expr bit_extract = d_theoryBitvector->newBoolExtractExpr(a, bit); CHECK_SOUND(bit_extract == bit_i.getLHS(), "not the right bit theorems"); } Expr b = a_plus_b[1]; for (int bit = 0; bit < size; bit++) { Theorem bit_i = b_bits[bit]; Expr bit_extract = d_theoryBitvector->newBoolExtractExpr(b, bit); CHECK_SOUND(bit_extract == bit_i.getLHS(), "not the right bit theorems"); } } vector sum_bits; Expr carry = d_theoryBitvector->falseExpr(); for (int i = 0; i < size; i ++) { Expr a_i = a_bits[i].getRHS(); Expr b_i = b_bits[i].getRHS(); sum_bits.push_back(a_i.iffExpr(b_i).iffExpr(carry)); carry = a_i.andExpr(b_i).orExpr(carry.andExpr(a_i.orExpr(b_i))); } // Create all the theorems now for (int bit = 0; bit < size; bit ++) { Proof pf; if (withProof()) { pf = newPf("bitblastBVPlus", a_plus_b, rat(bit)); } output_bits.push_back(newRWTheorem(d_theoryBitvector->newBoolExtractExpr(a_plus_b, bit), sum_bits[bit], Assumptions::emptyAssump(), pf)); } Theorem carry_thm; return carry_thm; } /** * Rewrite the signed divide in terms of the unsigned one. */ Theorem BitvectorTheoremProducer::bvSDivRewrite(const Expr& sDivExpr) { if(CHECK_PROOFS) { CHECK_SOUND(BITVECTOR == sDivExpr.getType().getExpr().getOpKind(), "input must be a bitvector. \n e = " + sDivExpr.toString()); CHECK_SOUND(BVSDIV == sDivExpr.getOpKind(),"input must be BVSDIV(e).\n e = " + sDivExpr.toString()); } int m = d_theoryBitvector->BVSize(sDivExpr); Proof pf; if (withProof()) pf = newPf("bvSDivRewrite", sDivExpr); // (bvsdiv s t) abbreviates // (let (?msb_s (extract[|m-1|:|m-1|] s)) // (let (?msb_t (extract[|m-1|:|m-1|] t)) // (ite (and (= ?msb_s bit0) (= ?msb_t bit0)) ---------> cond1 // (bvudiv s t) // (ite (and (= ?msb_s bit1) (= ?msb_t bit0)) ---------> cond2 // (bvneg (bvudiv (bvneg s) t)) // (ite (and (= ?msb_s bit0) (= ?msb_t bit1)) ---------> cond3 // (bvneg (bvudiv s (bvneg t))) // (bvudiv (bvneg s) (bvneg t))))))) Expr s = sDivExpr[0]; Expr t = sDivExpr[1]; Expr s_neg = d_theoryBitvector->newBVUminusExpr(s); Expr t_neg = d_theoryBitvector->newBVUminusExpr(t); Expr msb_s = d_theoryBitvector->newBVExtractExpr(s, m-1, m-1); Expr msb_t = d_theoryBitvector->newBVExtractExpr(t, m-1, m-1); Expr bit0 = d_theoryBitvector->newBVConstExpr(Rational(0), 1); Expr bit1 = d_theoryBitvector->newBVConstExpr(Rational(1), 1); Expr cond1 = msb_s.eqExpr(bit0).andExpr(msb_t.eqExpr(bit0)); Expr cond2 = msb_s.eqExpr(bit1).andExpr(msb_t.eqExpr(bit0)); Expr cond3 = msb_s.eqExpr(bit0).andExpr(msb_t.eqExpr(bit1)); Expr result = cond1.iteExpr( d_theoryBitvector->newBVUDivExpr(s, t), cond2.iteExpr( d_theoryBitvector->newBVUminusExpr(d_theoryBitvector->newBVUDivExpr(s_neg, t)), cond3.iteExpr( d_theoryBitvector->newBVUminusExpr(d_theoryBitvector->newBVUDivExpr(s, t_neg)), d_theoryBitvector->newBVUDivExpr(s_neg, t_neg) ) ) ); return newRWTheorem(sDivExpr, result, Assumptions::emptyAssump(), pf); } /** * Rewrite the signed remainder in terms of the unsigned one. */ Theorem BitvectorTheoremProducer::bvSRemRewrite(const Expr& sRemExpr) { if(CHECK_PROOFS) { CHECK_SOUND(BITVECTOR == sRemExpr.getType().getExpr().getOpKind(), "input must be a bitvector. \n e = " + sRemExpr.toString()); CHECK_SOUND(BVSREM == sRemExpr.getOpKind(),"input must be BVSDIV(e).\n e = " + sRemExpr.toString()); } int m = d_theoryBitvector->BVSize(sRemExpr); Proof pf; if (withProof()) pf = newPf("bvSRemRewrite", sRemExpr); // (bvsrem s t) abbreviates // (let (?msb_s (extract[|m-1|:|m-1|] s)) // (let (?msb_t (extract[|m-1|:|m-1|] t)) // (ite (and (= ?msb_s bit0) (= ?msb_t bit0)) // (bvurem s t) // (ite (and (= ?msb_s bit1) (= ?msb_t bit0)) // (bvneg (bvurem (bvneg s) t)) // (ite (and (= ?msb_s bit0) (= ?msb_t bit1)) // (bvurem s (bvneg t)) // (bvneg (bvurem (bvneg s) (bvneg t)))))))) Expr s = sRemExpr[0]; Expr t = sRemExpr[1]; Expr s_neg = d_theoryBitvector->newBVUminusExpr(s); Expr t_neg = d_theoryBitvector->newBVUminusExpr(t); Expr msb_s = d_theoryBitvector->newBVExtractExpr(s, m-1, m-1); Expr msb_t = d_theoryBitvector->newBVExtractExpr(t, m-1, m-1); Expr bit0 = d_theoryBitvector->newBVConstExpr(Rational(0), 1); Expr bit1 = d_theoryBitvector->newBVConstExpr(Rational(1), 1); Expr cond1 = msb_s.eqExpr(bit0).andExpr(msb_t.eqExpr(bit0)); Expr cond2 = msb_s.eqExpr(bit1).andExpr(msb_t.eqExpr(bit0)); Expr cond3 = msb_s.eqExpr(bit0).andExpr(msb_t.eqExpr(bit1)); Expr result = cond1.iteExpr( d_theoryBitvector->newBVURemExpr(s, t), cond2.iteExpr( d_theoryBitvector->newBVUminusExpr(d_theoryBitvector->newBVURemExpr(s_neg, t)), cond3.iteExpr( d_theoryBitvector->newBVURemExpr(s, t_neg), d_theoryBitvector->newBVUminusExpr(d_theoryBitvector->newBVURemExpr(s_neg, t_neg)) ) ) ); return newRWTheorem(sRemExpr, result, Assumptions::emptyAssump(), pf); } /** * Rewrite the signed mod in terms of the unsigned one. */ Theorem BitvectorTheoremProducer::bvSModRewrite(const Expr& sModExpr) { if(CHECK_PROOFS) { CHECK_SOUND(BITVECTOR == sModExpr.getType().getExpr().getOpKind(), "input must be a bitvector. \n e = " + sModExpr.toString()); CHECK_SOUND(BVSMOD == sModExpr.getOpKind(),"input must be BVSDIV(e).\n e = " + sModExpr.toString()); } int m = d_theoryBitvector->BVSize(sModExpr); Proof pf; if (withProof()) pf = newPf("bvSModRewrite", sModExpr); // (bvsmod s t) abbreviates // (let ((?msb_s ((_ extract |m-1| |m-1|) s)) // (?msb_t ((_ extract |m-1| |m-1|) t))) // (let ((abs_s (ite (= ?msb_s #b0) s (bvneg s))) // (abs_t (ite (= ?msb_t #b0) t (bvneg t)))) // (let ((u (bvurem abs_s abs_t))) // (ite (= u (_ bv0 m)) // u // (ite (and (= ?msb_s #b0) (= ?msb_t #b0)) // u // (ite (and (= ?msb_s #b1) (= ?msb_t #b0)) // (bvadd (bvneg u) t) // (ite (and (= ?msb_s #b0) (= ?msb_t #b1)) // (bvadd u t) // (bvneg u)))))))) Expr s = sModExpr[0]; Expr t = sModExpr[1]; Expr msb_s = d_theoryBitvector->newBVExtractExpr(s, m-1, m-1); Expr msb_t = d_theoryBitvector->newBVExtractExpr(t, m-1, m-1); Expr bit0 = d_theoryBitvector->newBVConstExpr(Rational(0), 1); Expr bit1 = d_theoryBitvector->newBVConstExpr(Rational(1), 1); Expr abs_s = msb_s.eqExpr(bit0).iteExpr(s, d_theoryBitvector->newBVUminusExpr(s)); Expr abs_t = msb_t.eqExpr(bit0).iteExpr(t, d_theoryBitvector->newBVUminusExpr(t)); Expr u = d_theoryBitvector->newBVURemExpr(abs_s, abs_t); Expr cond0 = u.eqExpr(d_theoryBitvector->newBVConstExpr(Rational(0), m)); Expr cond1 = msb_s.eqExpr(bit0).andExpr(msb_t.eqExpr(bit0)); Expr cond2 = msb_s.eqExpr(bit1).andExpr(msb_t.eqExpr(bit0)); Expr cond3 = msb_s.eqExpr(bit0).andExpr(msb_t.eqExpr(bit1)); Expr result = cond0.iteExpr(u, cond1.iteExpr(u, cond2.iteExpr( d_theoryBitvector->newBVPlusExpr(m, d_theoryBitvector->newBVUminusExpr(u), t), cond3.iteExpr(d_theoryBitvector->newBVPlusExpr(m, u, t), d_theoryBitvector->newBVUminusExpr(u))))); return newRWTheorem(sModExpr, result, Assumptions::emptyAssump(), pf); } Theorem BitvectorTheoremProducer::zeroBVOR(const Expr& orEqZero) { if(CHECK_PROOFS) { CHECK_SOUND(orEqZero.isEq(), "input must be an equality. \n e = " + orEqZero.toString()); CHECK_SOUND(orEqZero[0].getKind() == BVOR, "left-hand side must be a bitwise or. \n e = " + orEqZero.toString()); CHECK_SOUND(orEqZero[1].getKind() == BVCONST, "right-hand side must be a constant or. \n e = " + orEqZero.toString()); CHECK_SOUND(d_theoryBitvector->computeBVConst(orEqZero[1]) == 0, "right-hand side must be 0. \n e = " + orEqZero.toString()); } vector conjuncts; for (int disjunct = 0; disjunct < orEqZero[0].arity(); disjunct ++) conjuncts.push_back(orEqZero[0][disjunct].eqExpr(orEqZero[1])); Expr result = andExpr(conjuncts); Proof pf; if (withProof()) pf = newPf("zeroBVOR", orEqZero); return newRWTheorem(orEqZero, result, Assumptions::emptyAssump(), pf); } Theorem BitvectorTheoremProducer::oneBVAND(const Expr& andEqOne) { if(CHECK_PROOFS) { CHECK_SOUND(andEqOne.isEq(), "input must be an equality. \n e = " + andEqOne.toString()); CHECK_SOUND(andEqOne[0].getKind() == BVAND, "left-hand side must be a bitwise and. \n e = " + andEqOne.toString()); CHECK_SOUND(andEqOne[1].getKind() == BVCONST, "right-hand side must be a constant or. \n e = " + andEqOne.toString()); CHECK_SOUND(d_theoryBitvector->computeBVConst(andEqOne[1]) == pow(d_theoryBitvector->BVSize(andEqOne[1]), (Unsigned)2) - 1, "right-hand side must be 1^n. \n e = " + andEqOne.toString()); } vector conjuncts; for (int conjunct = 0; conjunct < andEqOne[0].arity(); conjunct ++) conjuncts.push_back(andEqOne[0][conjunct].eqExpr(andEqOne[1])); Expr result = andExpr(conjuncts); Proof pf; if (withProof()) pf = newPf("oneBVAND", andEqOne); return newRWTheorem(andEqOne, result, Assumptions::emptyAssump(), pf); } Theorem BitvectorTheoremProducer::constEq(const Expr& eq) { if(CHECK_PROOFS) { CHECK_SOUND(eq.isEq(), "input must be an equality. \n e = " + eq.toString()); CHECK_SOUND(eq[0].getKind() == BVCONST, "left-hand side must be a constant. \n e = " + eq.toString()); CHECK_SOUND(eq[1].getKind() == BVCONST, "right-hand side must be a constant. \n e = " + eq.toString()); } Expr result = eq[0] == eq[1] ? d_theoryBitvector->trueExpr() : d_theoryBitvector->falseExpr(); Proof pf; if (withProof()) pf = newPf("constEq", eq); return newRWTheorem(eq, result, Assumptions::emptyAssump(), pf); } bool BitvectorTheoremProducer::solveExtractOverlapApplies(const Expr& eq) { // Both sides should be an extract if (eq[0].getOpKind() != EXTRACT) return false; if (eq[1].getOpKind() != EXTRACT) return false; // Terms under extract should be identical if (eq[0][0] != eq[1][0]) return false; // We have x[i:j] == x[k:l] int i = d_theoryBitvector->getExtractHi(eq[0]); int j = d_theoryBitvector->getExtractLow(eq[0]); int k = d_theoryBitvector->getExtractHi(eq[1]); int l = d_theoryBitvector->getExtractLow(eq[1]); // They can't be equal, so we either have // i > k >= j > l or // k > i >= l > j if (i == k) return false; else if (i > k) return (k >= j && j > l); else return (i >= l && l > j); } Theorem BitvectorTheoremProducer::solveExtractOverlap(const Expr& eq) { Expr res; if (CHECK_PROOFS) CHECK_SOUND(solveExtractOverlapApplies(eq), "solveExtractOvelap does not apply to " + eq.toString()); // Left and right side of the equation Expr lhs = eq[0]; Expr rhs = eq[1]; // We have x[i:j] == x[k:l] int i = d_theoryBitvector->getExtractHi(lhs); int j = d_theoryBitvector->getExtractLow(lhs); int k = d_theoryBitvector->getExtractHi(rhs); int l = d_theoryBitvector->getExtractLow(rhs); // We only do case where i > k if (i > k) { vector terms; vector boundVars; // Get the term Expr x = lhs[0]; int x_size = d_theoryBitvector->BVSize(x); // If there is a initial part of x, put it in if (i < x_size - 1) { Expr x_begin = d_theoryBitvector->getEM()->newBoundVarExpr(d_theoryBitvector->newBitvectorType(x_size - i - 1)); terms.push_back(x_begin); boundVars.push_back(x_begin); } if (2*k + 1 <= i + j) { // Case when the overlap is smaller then the rest // i k j l // xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx // xxxxAAAAABBBBBBBBBBBBAAAAABBBBBBBBBBBBAAAAAxxxxx // a b c d e int o_size = k - j + 1; // Overlap size bool no_rest = (2*k + 1 == i + j); // Make The a = c = e expression Expr a = d_theoryBitvector->getEM()->newBoundVarExpr(d_theoryBitvector->newBitvectorType(o_size)); boundVars.push_back(a); terms.push_back(a); if (no_rest) { // c and e terms.push_back(a); terms.push_back(a); } else { // Make the b = d expression Expr b = d_theoryBitvector->getEM()->newBoundVarExpr(d_theoryBitvector->newBitvectorType(i - k - o_size)); boundVars.push_back(b); terms.push_back(b); terms.push_back(a); terms.push_back(b); terms.push_back(a); } } else { // Case when the overlap is bigger then the rest // i k j l // xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx // xxxxABCABCABCABCABCABCABCABCABCABCABCABCABCxxxxx int o_size = k - j + 1; // Overlap size int r_size = i - k; // Rest szie // Smallest slice int d = gcd(Rational(o_size), Rational(r_size)).getInt(); // Number of different pieces int different_pieces = r_size / d; // How many different slices will we get // Add all the initial different pieces for (int p = 0; p < different_pieces; p ++) { Expr piece = d_theoryBitvector->getEM()->newBoundVarExpr(d_theoryBitvector->newBitvectorType(d)); boundVars.push_back(piece); terms.push_back(piece); } // Add the rest of them cyclicly int other_pieces = (o_size + r_size) / d; for (int p = 0; p < other_pieces; p ++) terms.push_back(terms[terms.size() - different_pieces]); } // If there is a ending part of x, put it in if (l > 0) { Expr x_end = d_theoryBitvector->getEM()->newBoundVarExpr(d_theoryBitvector->newBitvectorType(l)); terms.push_back(x_end); boundVars.push_back(x_end); } res = x.eqExpr(d_theoryBitvector->newConcatExpr(terms)); res = d_theoryBitvector->getEM()->newClosureExpr(EXISTS, boundVars, res); } else // Other case by symmetry res = solveExtractOverlap(rhs.eqExpr(lhs)).getRHS(); Proof pf; if (withProof()) pf = newPf("solveExtractOverlap", eq); return newTheorem(eq.iffExpr(res), Assumptions::emptyAssump(), pf); } cvc3-2.4.1/src/theory_bitvector/bitvector_proof_rules.h0000664000175400017540000005476611265744142023261 0ustar mdetersmdeters/*****************************************************************************/ /*! * \file bitvector_proof_rules.h * \brief Arithmetic proof rules * * Author: Vijay Ganesh. * * Created:Wed May 5 15:47:28 PST 2004 * *
* * License to use, copy, modify, sell and/or distribute this software * and its documentation for any purpose is hereby granted without * royalty, subject to the terms and conditions defined in the \ref * LICENSE file provided with this distribution. * *
* */ /*****************************************************************************/ #ifndef _cvc3__bitvector_proof_rules_h_ #define _cvc3__bitvector_proof_rules_h_ #include #include namespace CVC3 { class Expr; class Theorem; class BitvectorProofRules { public: // Destructor virtual ~BitvectorProofRules() { } //////////////////////////////////////////////////////////////////// // Bitblasting rules for equations //////////////////////////////////////////////////////////////////// /*! \param thm input theorem: (e1[i]<=>e2[i])<=>false * * \result (e1=e2)<=>false */ virtual Theorem bitvectorFalseRule(const Theorem& thm) = 0; /*! \param thm input theorem: (~e1[i]<=>e2[i])<=>true * * \result (e1!=e2)<=>true */ virtual Theorem bitvectorTrueRule(const Theorem& thm) = 0; //! t1=t2 ==> AND_i(t1[i:i] = t2[i:i]) /*! * \param e is a Expr(t1=t2) * * \param f is the resulting expression AND_i(t1[i:i] = t2[i:i]) * is passed to the rule for efficiency. */ virtual Theorem bitBlastEqnRule(const Expr& e, const Expr& f) = 0; //! t1/=t2 ==> OR_i(NOT t1[i]<=>t2[i]) /*! * \param e is a Theorem(t1/=t2) * * \param f is the resulting expression OR_i(NOT t1[i]<=>t2[i]), * passed to the rule for efficiency. */ virtual Theorem bitBlastDisEqnRule(const Theorem& e, const Expr& f) = 0; //////////////////////////////////////////////////////////////////// // Bitblasting and rewrite rules for Inequations //////////////////////////////////////////////////////////////////// //! sign extend the input SX(e) appropriately virtual Theorem signExtendRule(const Expr& e) = 0; //! Pad the kids of BVLT/BVLE to make their length equal virtual Theorem padBVLTRule(const Expr& e, int len) = 0; //! Sign Extend the kids of BVSLT/BVSLE to make their length equal virtual Theorem padBVSLTRule(const Expr& e, int len) = 0; /*! input: e0 <=(s) e1. output depends on whether the topbits(MSB) of * e0 and e1 are constants. If they are constants then optimizations * are done, otherwise the following rule is implemented. * * e0 <=(s) e1 <==> (e0[n-1] AND NOT e1[n-1]) OR * (e0[n-1] AND e1[n-1] AND e1[n-2:0] <= e0[n-2:0]) OR * (NOT e0[n-1] AND NOT e1[n-1] AND e0[n-2:0] <= e1[n-2:0]) */ virtual Theorem signBVLTRule(const Expr& e, const Theorem& topBit0, const Theorem& topBit1) = 0; /*! NOT(e[0][0] = e[0][1]) <==> e[0][0] = ~e[0][1] */ virtual Theorem notBVEQ1Rule(const Expr& e) = 0; /*! NOT(e[0][0] < e[0][1]) <==> (e[0][1] <= e[0][0]), * NOT(e[0][0] <= e[0][1]) <==> (e[0][1] < e[0][0]) */ virtual Theorem notBVLTRule(const Expr& e) = 0; //! if(lhs==rhs) then we have (lhs < rhs <==> false),(lhs <= rhs <==> true) virtual Theorem lhsEqRhsIneqn(const Expr& e, int kind) = 0; virtual Theorem zeroLeq(const Expr& e) = 0; virtual Theorem bvConstIneqn(const Expr& e, int kind) = 0; virtual Theorem generalIneqn(const Expr& e, const Theorem& e0, const Theorem& e1, int kind) = 0; //////////////////////////////////////////////////////////////////// // Bitblast rules for terms //////////////////////////////////////////////////////////////////// // Input: |- BOOLEXTRACT(a,0) <=> bc_0, ... BOOLEXTRACT(a,n-1) <=> bc_(n-1) // where each bc_0 is TRUE or FALSE // Output: |- a = c // where c is an n-bit constant made from the values bc_0..bc_(n-1) virtual Theorem bitExtractAllToConstEq(std::vector& thms) = 0; //! t[i] ==> t[i:i] = 0bin1 or NOT t[i] ==> t[i:i] = 0bin0 /*! \param thm is a Theorem(t[i]) or Theorem(NOT t[i]), where t[i] * is BOOLEXTRACT(t, i). */ virtual Theorem bitExtractToExtract(const Theorem& thm) = 0; //! t[i] <=> t[i:i][0] (to use rewriter for simplifying t[i:i]) virtual Theorem bitExtractRewrite(const Expr& x) = 0; /*! \param x is bitvector constant * \param i is extracted bitposition * * \result \f[ \frac{}{\mathrm{BOOLEXTRACT(x,i)} \iff * \mathrm{TRUE}} \f], if bitposition has a 1; \f[ * \frac{}{\mathrm{BOOLEXTRACT(x,i)} \iff \mathrm{FALSE}} \f], if * the bitposition has a 0 */ virtual Theorem bitExtractConstant(const Expr & x, int i)= 0; /*! \param x is bitvector binary concatenation * \param i is extracted bitposition * * \result \f[ \frac{}{(t_{[m]}@q_{[n]})[i] \iff (q_{[n]})[i]} * \f], where \f[ 0 \geq i \geq n-1 \f], another case of * boolextract over concatenation is: * \f[\frac{}{(t_{[m]}@q_{[n]})[i] \iff (t_{[m]})[i-n]} \f], * where \f[ n \geq i \geq m+n-1 \f] */ virtual Theorem bitExtractConcatenation(const Expr & x, int i)= 0; /*! \param t is bitvector binary BVMULT. x[0] must be BVCONST * \param i is extracted bitposition * * \result bitblast of BVMULT */ virtual Theorem bitExtractConstBVMult(const Expr& t, int i)= 0; /*! \param t : input1 is bitvector binary BVMULT. t[0] must not be BVCONST * \param i : input2 is extracted bitposition * * \result bitblast of BVMULT */ virtual Theorem bitExtractBVMult(const Expr& t, int i) = 0; /*! \param x is bitvector extraction e[k:j] * \param i is extracted bitposition * * \result \f[ \frac{}{(t_{[n]}[k:j])[i] \iff (t_{[n]})[i+j]} * \f], where \f[ 0 \geq j \geq k < n, 0 \geq i < k-j \f] */ virtual Theorem bitExtractExtraction(const Expr & x, int i)= 0; /*! \param t1 is vector of bitblasts of t, from bit i-1 to 0 * \param t2 is vector of bitblasts of q, from bit i-1 to 0 * \param bvPlusTerm is BVPLUS term: BVPLUS(n,t,q) * \param i is extracted bitposition * * \result The base case is: \f[ * \frac{}{(\mathrm{BVPLUS}(n,t,q))[0] \iff t[0] \oplus q[0]} * \f], when \f[ 0 < i \leq n-1 \f], we have \f[ * \frac{}{(\mathrm{BVPLUS}(n,t,q))[i] \iff t[i] \oplus q[i] * \oplus c(t,q,i)} \f], where c(t,q,i) is the carry generated * by the addition of bits from 0 to i-1 */ virtual Theorem bitExtractBVPlus(const std::vector& t1, const std::vector& t2, const Expr& bvPlusTerm, int i) = 0; virtual Theorem bitExtractBVPlusPreComputed(const Theorem& t1_i, const Theorem& t2_i, const Expr& bvPlusTerm, int bitPos, int precomputed) = 0; /*! \param bvPlusTerm : input1 is bvPlusTerm, a BVPLUS term with * arity > 2 * * \result : output is iff-Theorem: bvPlusTerm <==> outputTerm, * where outputTerm is an equivalent BINARY bvplus. */ virtual Theorem bvPlusAssociativityRule(const Expr& bvPlusTerm)= 0; /*! \param x : input1 is bitwise NEGATION * \param i : input2 is extracted bitposition * * \result \f[ \frac{}{(\sim t_{[n]})[i] \iff \neg (t_{[n]}[i])} * \f] */ virtual Theorem bitExtractNot(const Expr & x, int i)= 0; //! Extract from bitwise AND, OR, or XOR virtual Theorem bitExtractBitwise(const Expr & x, int i, int kind)= 0; /*! \param x : input1 is bitvector FIXED SHIFT \f[ e_{[n]} \ll k \f] * \param i : input2 is extracted bitposition * * \result \f[\frac{}{(e_{[n]} \ll k)[i] \iff \mathrm{FALSE}} * \f], if 0 <= i < k. however, if k <= i < n then, result is * \f[\frac{}{(e_{[n]} \ll k)[i] \iff e_{[n]}[i]} \f] */ virtual Theorem bitExtractFixedLeftShift(const Expr & x, int i)= 0; virtual Theorem bitExtractFixedRightShift(const Expr & x, int i)= 0; // BOOLEXTRACT(bvshl(t,s),i) <=> ((s = 0) AND BOOLEXTRACT(t,i)) OR // ((s = 1) AND BOOLEXTRACT(t,i-1)) OR ... // ((s = i) AND BOOLEXTRACT(t,0)) virtual Theorem bitExtractBVSHL(const Expr & x, int i) = 0; // BOOLEXTRACT(bvlshr(t,s),i) <=> ((s = 0) AND BOOLEXTRACT(t,i)) OR // ((s = 1) AND BOOLEXTRACT(t,i+1)) OR ... // ((s = n-1-i) AND BOOLEXTRACT(t,n-1)) virtual Theorem bitExtractBVLSHR(const Expr & x, int i) = 0; // BOOLEXTRACT(bvashr(t,s),i) <=> ((s = 0) AND BOOLEXTRACT(t,i)) OR // ((s = 1) AND BOOLEXTRACT(t,i+1)) OR ... // ((s >= n-1-i) AND BOOLEXTRACT(t,n-1)) virtual Theorem bitExtractBVASHR(const Expr & x, int i) = 0; /*! \param e : input1 is bitvector term * \param r : input2 is extracted bitposition * * \result we check if r > bvlength(e). if yes, then return * BOOLEXTRACT(e,r) <==> FALSE; else raise soundness * exception. (Note: this rule is used in BVPLUS bitblast * function) */ virtual Theorem zeroPaddingRule(const Expr& e, int r)= 0; virtual Theorem bitExtractSXRule(const Expr& e, int i) = 0; /////////////////////////////////////////////////////////////////// ///// Special case rewrite rules /////////////////////////////////////////////////////////////////// //! c1=c2 <=> TRUE/FALSE (equality of constant bitvectors) virtual Theorem eqConst(const Expr& e) = 0; //! |- c1=c2 ==> |- AND(c1[i:i] = c2[i:i]) - expanding equalities into bits virtual Theorem eqToBits(const Theorem& eq) = 0; //! t<>m = 0bin00...00 @ t[bvlength-1:m], takes e == (t>>n) virtual Theorem rightShiftToConcat(const Expr& e) = 0; //! BVSHL(t,c) = t[n-c,0] @ 0bin00...00 virtual Theorem bvshlToConcat(const Expr& e) = 0; //! BVSHL(t,c) = IF (c = 0) THEN t ELSE IF (c = 1) ... virtual Theorem bvshlSplit(const Expr& e) = 0; //! BVLSHR(t,c) = 0bin00...00 @ t[n-1,c] virtual Theorem bvlshrToConcat(const Expr& e) = 0; //! Any shift over a zero = 0 virtual Theorem bvShiftZero(const Expr& e) = 0; //! BVASHR(t,c) = SX(t[n-1,c], n-1) virtual Theorem bvashrToConcat(const Expr& e) = 0; //! a XNOR b <=> (~a & ~b) | (a & b) virtual Theorem rewriteXNOR(const Expr& e) = 0; //! a NAND b <=> ~(a & b) virtual Theorem rewriteNAND(const Expr& e) = 0; //! a NOR b <=> ~(a | b) virtual Theorem rewriteNOR(const Expr& e) = 0; //! BVCOMP(a,b) <=> ITE(a=b,0bin1,0bin0) virtual Theorem rewriteBVCOMP(const Expr& e) = 0; //! a - b <=> a + (-b) virtual Theorem rewriteBVSub(const Expr& e) = 0; //! k*t = BVPLUS(n, ) -- translation of k*t to BVPLUS /*! If k = 2^m, return k*t = t\@0...0 */ virtual Theorem constMultToPlus(const Expr& e) = 0; //! 0bin0...0 @ BVPLUS(n, args) = BVPLUS(n+k, args) /*! provided that m+ceil(log2(l)) <= n, where k is the size of the * 0bin0...0, m is the max. length of each argument, and l is the * number of arguments. */ virtual Theorem bvplusZeroConcatRule(const Expr& e) = 0; /////////////////////////////////////////////////////////////////// ///// Bvplus Normal Form rules /////////////////////////////////////////////////////////////////// virtual Theorem zeroCoeffBVMult(const Expr& e)=0; virtual Theorem oneCoeffBVMult(const Expr& e)=0; virtual Theorem flipBVMult(const Expr& e) = 0; //! Make args the same length as the result (zero-extend) virtual Theorem padBVPlus(const Expr& e) = 0; //! Make args the same length as the result (zero-extend) virtual Theorem padBVMult(const Expr& e) = 0; virtual Theorem bvConstMultAssocRule(const Expr& e) = 0; virtual Theorem bvMultAssocRule(const Expr& e) = 0; virtual Theorem bvMultDistRule(const Expr& e) = 0; virtual Theorem flattenBVPlus(const Expr& e) = 0; virtual Theorem combineLikeTermsRule(const Expr& e) = 0; virtual Theorem lhsMinusRhsRule(const Expr& e) = 0; //! (x *[n] y)[m:k] = (x *[m+1] y)[m:k], where m < n virtual Theorem extractBVMult(const Expr& e) = 0; //! (x +[n] y)[m:k] = (x +[m+1] y)[m:k], where m < n virtual Theorem extractBVPlus(const Expr& e) = 0; //! ite(c,t1,t2)[i:j] <=> ite(c,t1[i:j],t2[i:j]) virtual Theorem iteExtractRule(const Expr& e) = 0; //! ~ite(c,t1,t2) <=> ite(c,~t1,~t2) virtual Theorem iteBVnegRule(const Expr& e) = 0; virtual Theorem bvuminusBVConst(const Expr& e) = 0; virtual Theorem bvuminusBVMult(const Expr& e) = 0; virtual Theorem bvuminusBVUminus(const Expr& e) = 0; virtual Theorem bvuminusVar(const Expr& e) = 0; virtual Theorem bvmultBVUminus(const Expr& e) = 0; //! -t <==> ~t+1 virtual Theorem bvuminusToBVPlus(const Expr& e) = 0; //! -(c1*t1+...+cn*tn) <==> (-(c1*t1)+...+-(cn*tn)) virtual Theorem bvuminusBVPlus(const Expr& e) = 0; /////////////////////////////////////////////////////////////////// ///// Concatenation Normal Form rules /////////////////////////////////////////////////////////////////// // Extraction rules //! c1[i:j] = c (extraction from a constant bitvector) virtual Theorem extractConst(const Expr& e) = 0; //! t[n-1:0] = t for n-bit t virtual Theorem extractWhole(const Expr& e) = 0; //! t[i:j][k:l] = t[k+j:l+j] (eliminate double extraction) virtual Theorem extractExtract(const Expr& e) = 0; //! (t1 @ t2)[i:j] = t1[...] @ t2[...] (push extraction through concat) virtual Theorem extractConcat(const Expr& e) = 0; //! (t1 & t2)[i:j] = t1[i:j] & t2[i:j] (push extraction through OR) virtual Theorem extractAnd(const Expr& e) = 0; //! (t1 | t2)[i:j] = t1[i:j] | t2[i:j] (push extraction through AND) virtual Theorem extractOr(const Expr& e) = 0; //! (~t)[i:j] = ~(t[i:j]) (push extraction through NEG) virtual Theorem extractNeg(const Expr& e) = 0; //! Auxiliary function: (t1 op t2)[i:j] = t1[i:j] op t2[i:j] virtual Theorem extractBitwise(const Expr& e, int kind, const std::string& name) = 0; // Negation rules //! ~c1 = c (bit-wise negation of a constant bitvector) virtual Theorem negConst(const Expr& e) = 0; //! ~(t1\@...\@tn) = (~t1)\@...\@(~tn) -- push negation through concat virtual Theorem negConcat(const Expr& e) = 0; //! ~(~t) = t -- eliminate double negation virtual Theorem negNeg(const Expr& e) = 0; //! ~t = -1*t + 1 -- eliminate negation virtual Theorem negElim(const Expr& e) = 0; //! ~(t1 & t2) <=> ~t1 | ~t2 -- DeMorgan's Laws virtual Theorem negBVand(const Expr& e) = 0; //! ~(t1 | t2) <=> ~t1 & ~t2 -- DeMorgan's Laws virtual Theorem negBVor(const Expr& e) = 0; //! ~(t1 xor t2) = ~t1 xor t2 virtual Theorem negBVxor(const Expr& e) = 0; //! ~(t1 xnor t2) = t1 xor t2 virtual Theorem negBVxnor(const Expr& e) = 0; //! Combine constants in bitwise AND, OR, XOR virtual Theorem bitwiseConst(const Expr& e, const std::vector& idxs, int kind) = 0; //! Lifts concatenation above bitwise operators. virtual Theorem bitwiseConcat(const Expr& e, int kind) = 0; //! Flatten bitwise operation virtual Theorem bitwiseFlatten(const Expr& e, int kind) = 0; //! Simplify bitwise operator containing a constant child /*! \param e is the bit-wise expr * \param idx is the index of the constant bitvector * \param kind is the kind of e */ virtual Theorem bitwiseConstElim(const Expr& e, int idx, int kind) = 0; // Concatenation rules //! c1\@c2\@...\@cn = c (concatenation of constant bitvectors) virtual Theorem concatConst(const Expr& e) = 0; //! Flatten one level of nested concatenation, e.g.: x\@(y\@z)\@w = x\@y\@z\@w virtual Theorem concatFlatten(const Expr& e) = 0; //! Merge n-ary concat. of adjacent extractions: x[15:8]\@x[7:0] = x[15:0] virtual Theorem concatMergeExtract(const Expr& e) = 0; /////////////////////////////////////////////////////////////////// ///// Modulo arithmetic rules /////////////////////////////////////////////////////////////////// //! BVPLUS(n, c1,c2,...,cn) = c (bit-vector plus of constant bitvectors) virtual Theorem bvplusConst(const Expr& e) = 0; /*! @brief n*c1 = c, where n >= 0 (multiplication of a constant * bitvector by a non-negative constant) */ virtual Theorem bvmultConst(const Expr& e) = 0; /////////////////////////////////////////////////////////////////// ///// Type predicate rules /////////////////////////////////////////////////////////////////// //! |- t=0 OR t=1 for any 1-bit bitvector t virtual Theorem typePredBit(const Expr& e) = 0; //! Expand the type predicate wrapper (compute the actual type predicate) virtual Theorem expandTypePred(const Theorem& tp) = 0; /*Beginning of Lorenzo PLatania's methods*/ // virtual Theorem multiply_coeff( Rational mult_inv, const Expr& e)=0; //! isolate a variable with coefficient = 1 on the Lhs of an //equality expression virtual Theorem isolate_var(const Expr& e)=0; // BVPLUS(N, a@b, y) = BVPLUS(N-n,a,BVPLUS(N,b,y)[N-1:n])@BVPLUS(n,b,y) // where n = BVSize(b), a != 0 virtual Theorem liftConcatBVMult(const Expr& e)=0; //! canonize BVMult expressions in order to get one coefficient //multiplying the variable(s) in the expression virtual Theorem canonBVMult( const Expr& e )=0; // BVPLUS(N, a@b, y) = BVPLUS(N-n,a,BVPLUS(N,b,y)[N-1:n])@BVPLUS(n,b,y) // where n = BVSize(b) virtual Theorem liftConcatBVPlus(const Expr& e)=0; //! canonize BVPlus expressions in order to get just one //coefficient multiplying each variable in the expression virtual Theorem canonBVPlus( const Expr& e )=0; virtual Theorem canonBVUMinus( const Expr& e )=0; // Input: t[hi:lo] = rhs // if t appears as leaf in rhs, then: // t[hi:lo] = rhs |- Exists x,y,z. (t = x @ y @ z AND y = rhs), solvedForm = false // else // t[hi:lo] = rhs |- Exists x,y,z. (t = x @ rhs @ z AND y = rhs), solvedForm = true virtual Theorem processExtract(const Theorem& e, bool& solvedForm)=0; // normalizes equation virtual Theorem canonBVEQ( const Expr& e, int maxEffort = 3 )=0; //! apply the distributive rule on the BVMULT expression e virtual Theorem distributive_rule( const Expr& e )=0; // virtual Theorem BVMultConstTerm( const Expr& e1, const Expr& e2)=0; // recursively reorder subterms in a BVMULT term virtual Theorem BVMult_order_subterms( const Expr& e ) = 0; // rewrites the equation in the form 0 = Expr // this is needed for TheoryBitvector::solve virtual Theorem MarkNonSolvableEq( const Expr& e) = 0; /*End of Lorenzo PLatania's methods*/ // rewrite BVZEROEXTEND into CONCAT virtual Theorem zeroExtendRule(const Expr& e) = 0; // rewrite BVREPEAT into CONCAT virtual Theorem repeatRule(const Expr& e) = 0; // rewrite BVROTL into CONCAT virtual Theorem rotlRule(const Expr& e) = 0; // rewrite BVROTR into CONCAT virtual Theorem rotrRule(const Expr& e) = 0; /** * Divide a with b unsigned and return the bit-vector constant result */ virtual Theorem bvUDivConst(const Expr& divExpr) = 0; /** * Rewrite a/b with a fresh variable d and add the constraints to make it be a divider. */ virtual Theorem bvUDivTheorem(const Expr& divExpr) = 0; /** * Divide a with b unsigned and return the bit-vector constant result */ virtual Theorem bvURemConst(const Expr& remExpr) = 0; /** * Rewrite a%b in terms of a/b, i.e. a - a/b */ virtual Theorem bvURemRewrite(const Expr& divExpr) = 0; /** * Rewrite the signed divide in terms of the unsigned one. */ virtual Theorem bvSDivRewrite(const Expr& sDivExpr) = 0; /** * Rewrite the signed remainder in terms of the unsigned one. */ virtual Theorem bvSRemRewrite(const Expr& sRemExpr) = 0; /** * Rewrite the signed mod in terms of the unsigned one. */ virtual Theorem bvSModRewrite(const Expr& sModExpr) = 0; /** * Bit-blast the multiplication a_times_b given the bits in a_bits and b_bits. * The resulting output bits will be in the vector output_bits. The return value * is a theorem saying there is no overflow for this multiplication. (TODO, it's * just an empty theorem for now). */ virtual Theorem bitblastBVMult(const std::vector& a_bits, const std::vector& b_bits, const Expr& a_times_b, std::vector& output_bits) = 0; /** * Bit-blast the sum a_times_b given the bits in a_bits and b_bits. * The resulting output bits will be in the vector output_bits. The return value * is a theorem saying there is no overflow for this sum. (TODO, it's * just an empty theorem for now). */ virtual Theorem bitblastBVPlus(const std::vector& a_bits, const std::vector& b_bits, const Expr& a_plus_b, std::vector& output_bits) = 0; /** * Rewrite x_1 \vee x_2 \vee \ldots \vee x_n = 0 into * x_1 = 0 \wedge x_2 = 0 \wedge \ldots \wedge x_n = 0. */ virtual Theorem zeroBVOR(const Expr& orEqZero) = 0; /** * Rewrite x_1 \wedge x_2 \wedge \ldots \wedge x_n = 1^n into * x_1 = 1^n \wedge x_2 = 1^n \wedge \ldots \wedge x_n = 1^n. */ virtual Theorem oneBVAND(const Expr& andEqOne) = 0; /** * Equalities over constants go to true/false. */ virtual Theorem constEq(const Expr& eq) = 0; /** * Returns true if equation is of the form x[i:j] = x[k:l], where the * extracted segments overlap, i.e. i > j >= k > l or k > i >= l > j. */ virtual bool solveExtractOverlapApplies(const Expr& eq) = 0; /** * Returns the theorem that simplifies the equality of two overlapping * extracts over the same term. */ virtual Theorem solveExtractOverlap(const Expr& eq) = 0; }; // end of class BitvectorProofRules } // end of name-space CVC3 #endif cvc3-2.4.1/src/theory_bitvector/bitvector_exception.h0000664000175400017540000000243310466450544022702 0ustar mdetersmdeters/*****************************************************************************/ /*! * \file bitvector_exception.h * \brief An exception thrown by the bitvector decision procedure. * * Author: Vijay Ganesh * * Created: Wed May 5 16:23:45 PST 2004 * *
* * License to use, copy, modify, sell and/or distribute this software * and its documentation for any purpose is hereby granted without * royalty, subject to the terms and conditions defined in the \ref * LICENSE file provided with this distribution. * *
* */ /*****************************************************************************/ #ifndef _cvc3__theory_bitvector__bitvector_exception_h_ #define _cvc3__theory_bitvector__bitvector_exception_h_ #include #include #include "exception.h" namespace CVC3 { class BitvectorException: public Exception { // protected: // std::string d_msg; public: // Constructors BitvectorException() { } BitvectorException(const std::string& msg): Exception(msg) { } BitvectorException(char* msg): Exception(msg) { } // Destructor virtual ~BitvectorException() { } virtual std::string toString() const { return "Bitvector error: " + d_msg; } }; // end of class BitvectorException } // end of namespace CVC3 #endif cvc3-2.4.1/src/theory_bitvector/theory_bitvector.cpp0000664000175400017540000054314611450462172022556 0ustar mdetersmdeters/*****************************************************************************/ /*! * \file theory_bitvector.cpp * * Author: Vijay Ganesh. * * Created: Wed May 5 16:16:59 PST 2004 * *
* * License to use, copy, modify, sell and/or distribute this software * and its documentation for any purpose is hereby granted without * royalty, subject to the terms and conditions defined in the \ref * LICENSE file provided with this distribution. * *
* */ /*****************************************************************************/ #include "theory_bitvector.h" #include "bitvector_proof_rules.h" #include "bitvector_exception.h" #include "typecheck_exception.h" #include "parser_exception.h" #include "smtlib_exception.h" #include "bitvector_expr_value.h" #include "command_line_flags.h" #define HASH_VALUE_ZERO 380 #define HASH_VALUE_ONE 450 using namespace std; using namespace CVC3; /////////////////////////////////////////////////////////////////////////////// // TheoryBitvector Private Methods // /////////////////////////////////////////////////////////////////////////////// int TheoryBitvector::BVSize(const Expr& e) { Type tp(getBaseType(e)); DebugAssert(tp.getExpr().getOpKind() == BITVECTOR, "BVSize: e = "+e.toString()); return getBitvectorTypeParam(tp); } //! Converts e into a BITVECTOR of length 'len' /*! * \param len is the desired length of the resulting bitvector * \param e is the original bitvector of arbitrary length */ Expr TheoryBitvector::pad(int len, const Expr& e) { DebugAssert(len >=0, "TheoryBitvector::newBVPlusExpr:" "padding length must be a non-negative integer: "+ int2string(len)); DebugAssert(BITVECTOR == e.getType().getExpr().getOpKind(), "TheoryBitvector::newBVPlusExpr:" "input must be a BITVECTOR: " + e.toString()); int size = BVSize(e); Expr res; if(size == len) res = e; else if (len < size) res = newBVExtractExpr(e,len-1,0); else { // size < len Expr zero = newBVZeroString(len-size); res = newConcatExpr(zero,e); } return res; } // Bit-blasting methods //! accepts a bitvector equation t1 = t2. /*! \return a rewrite theorem which is a conjunction of equivalences * over the bits of t1,t2 respectively. */ Theorem TheoryBitvector::bitBlastEqn(const Expr& e) { TRACE("bitvector", "bitBlastEqn(", e.toString(), ") {"); d_bvBitBlastEq++; DebugAssert(e.isEq(), "TheoryBitvector::bitBlastEqn:" "expecting an equation" + e.toString()); const Expr& leftBV = e[0]; const Expr& rightBV = e[1]; IF_DEBUG(const Type& leftType = getBaseType(leftBV);) IF_DEBUG(const Type& rightType = getBaseType(rightBV);) DebugAssert(BITVECTOR == leftType.getExpr().getOpKind() && BITVECTOR == rightType.getExpr().getOpKind(), "TheoryBitvector::bitBlastEqn:" "lhs & rhs must be bitvectors"); DebugAssert(BVSize(leftBV) == BVSize(rightBV), "TheoryBitvector::bitBlastEqn:\n e = " +e.toString()); Theorem result = reflexivityRule(e); Theorem bitBlastLeftThm; Theorem bitBlastRightThm; std::vector substThms; std::vector leftBVrightBVThms; int bvLength = BVSize(leftBV); int bitPosition = 0; Theorem thm0; for(; bitPosition < bvLength; ++bitPosition) { //bitBlastLeftThm is the theorem 'leftBV[bitPosition] <==> phi' bitBlastLeftThm = bitBlastTerm(leftBV, bitPosition); //bitBlastRightThm is the theorem 'rightBV[bitPosition] <==> theta' bitBlastRightThm = bitBlastTerm(rightBV, bitPosition); //collect the two theorems created above in the vector //leftBVrightBVthms. leftBVrightBVThms.push_back(bitBlastLeftThm); leftBVrightBVThms.push_back(bitBlastRightThm); //construct (leftBV[bitPosition] <==> rightBV[bitPosition]) //<====> phi <==> theta //and store in the vector substThms. Theorem thm = substitutivityRule(IFF, leftBVrightBVThms); thm = transitivityRule(thm, rewriteBoolean(thm.getRHS())); leftBVrightBVThms.clear(); substThms.push_back(thm); //if phi <==> theta is false, then stop bitblasting. immediately //exit and return false. if(thm.getRHS().isFalse()) return transitivityRule(result, d_rules->bitvectorFalseRule(thm)); } // AND_0^bvLength(leftBV[bitPosition] <==> rightBV[bitPosition]) <====> // AND_0^bvLength(phi <==> theta) Theorem thm = substitutivityRule(AND, substThms); // AND_0^bvLength(leftBV[bitPosition] <==> rightBV[bitPosition]) <====> // rewriteBoolean(AND_0^bvLength(phi <==> theta)) thm = transitivityRule(thm, rewriteBoolean(thm.getRHS())); //call trusted rule for bitblasting equations. result = d_rules->bitBlastEqnRule(e, thm.getLHS()); result = transitivityRule(result, thm); TRACE("bitvector", "bitBlastEqn => ", result.toString(), " }"); return result; } //! accepts a bitvector equation t1 != t2. /*! \return a rewrite theorem which is a conjunction of * (dis)-equivalences over the bits of t1,t2 respectively. * * A separate rule for disequations for efficiency sake. Obvious * implementation using rule for equations and rule for NOT, is not * efficient. */ Theorem TheoryBitvector::bitBlastDisEqn(const Theorem& notE) { TRACE("bitvector", "bitBlastDisEqn(", notE, ") {"); IF_DEBUG(debugger.counter("bit-blasted diseq")++); //stat counter d_bvBitBlastDiseq++; DebugAssert(notE.getExpr().isNot() && (notE.getExpr())[0].isEq(), "TheoryBitvector::bitBlastDisEqn:" "expecting an equation" + notE.getExpr().toString()); //e is the equation const Expr& e = (notE.getExpr())[0]; const Expr& leftBV = e[0]; const Expr& rightBV = e[1]; IF_DEBUG(Type leftType = leftBV.getType()); IF_DEBUG(debugger.counter("bit-blasted diseq bits")+= BVSize(leftBV)); IF_DEBUG(Type rightType = rightBV.getType()); DebugAssert(BITVECTOR == leftType.getExpr().getOpKind() && BITVECTOR == rightType.getExpr().getOpKind(), "TheoryBitvector::bitBlastDisEqn:" "lhs & rhs must be bitvectors"); DebugAssert(BVSize(leftBV) == BVSize(rightBV), "TheoryBitvector::bitBlastDisEqn: e = " +e.toString()); Theorem bitBlastLeftThm; Theorem bitBlastRightThm; std::vector substThms; std::vector leftBVrightBVThms; int bvLength = BVSize(leftBV); int bitPosition = 0; for(; bitPosition < bvLength; bitPosition = bitPosition+1) { //bitBlastLeftThm is the theorem '~leftBV[bitPosition] <==> ~phi' bitBlastLeftThm = getCommonRules()->iffContrapositive(bitBlastTerm(leftBV, bitPosition)); //bitBlastRightThm is the theorem 'rightBV[bitPosition] <==> theta' bitBlastRightThm = bitBlastTerm(rightBV, bitPosition); //collect the two theorems created above in the vector leftBVrightBVthms. leftBVrightBVThms.push_back(bitBlastLeftThm); leftBVrightBVThms.push_back(bitBlastRightThm); //construct (~leftBV[bitPosition] <==> rightBV[bitPosition]) //<====> ~phi <==> theta //and store in the vector substThms. //recall that (p <=/=> q) is same as (~p <==> q) Theorem thm = substitutivityRule(IFF, leftBVrightBVThms); thm = transitivityRule(thm, rewriteBoolean(thm.getRHS())); leftBVrightBVThms.clear(); substThms.push_back(thm); //if phi <==> theta is the True theorem, then stop bitblasting. immediately //exit and return t1!=t2 <=> true. if(thm.getRHS().isTrue()) return d_rules->bitvectorTrueRule(thm); } // OR_0^bvLength(~leftBV[bitPosition] <==> rightBV[bitPosition]) <====> // OR_0^bvLength(~phi <==> theta) Theorem thm1 = substitutivityRule(OR, substThms); // Call trusted rule for bitblasting disequations. Theorem result = d_rules->bitBlastDisEqnRule(notE, thm1.getLHS()); Theorem thm2 = transitivityRule(thm1, rewriteBoolean(thm1.getRHS())); result = iffMP(result, thm2); TRACE("bitvector", "bitBlastDisEqn => ", result.toString(), " }"); return result; } /*! \param e has the form e1 pred e2, where pred is < or <=. * * if e1,e2 are constants, determine bv2int(e1) pred bv2int(e2). * * most significant bit of ei is denoted by msb(ei) * * \return \f$(msb(e1)\ pred\ msb(e2)) \vee * (msb(e1)=msb(e2) \wedge e1[n-2:0]\ pred\ e2[n-2:0])\f$ */ Theorem TheoryBitvector::bitBlastIneqn(const Expr& e) { TRACE("bitvector", "bitBlastIneqn(", e.toString(), ") {"); DebugAssert(BVLT == e.getOpKind() || BVLE == e.getOpKind(), "TheoryBitvector::bitBlastIneqn: " "input e must be BVLT/BVLE: e = " + e.toString()); DebugAssert(e.arity() == 2, "TheoryBitvector::bitBlastIneqn: " "arity of e must be 2: e = " + e.toString()); Expr lhs = e[0]; Expr rhs = e[1]; int e0len = BVSize(lhs); DebugAssert(e0len == BVSize(rhs), "Expected sizes to match"); int kind = e.getOpKind(); Theorem res; if(lhs == rhs) { res = d_rules->lhsEqRhsIneqn(e, kind); } else if (lhs.getKind() == BVCONST && rhs.getKind() == BVCONST) { res = d_rules->bvConstIneqn(e, kind); } else { Theorem lhs_i = bitBlastTerm(lhs, e0len-1); Theorem rhs_i = bitBlastTerm(rhs, e0len-1); res = d_rules->generalIneqn(e, lhs_i, rhs_i, kind); //check if output is TRUE or FALSE theorem, and then simply return Theorem output = rewriteBoolean(res.getRHS()); if (output.getRHS().isBoolConst()) { res = transitivityRule(res, output); } else if (e0len > 1) { // Copy by value, since 'res' will be changing Expr resRHS = res.getRHS(); // resRHS is of the form (\alpha or (\beta and \gamma)) // where \gamma is an inequality DebugAssert(resRHS.getKind() == OR && resRHS.arity() == 2 && resRHS[1].getKind() == AND && resRHS[1].arity() == 2, "Unexpected structure"); vector changed; vector thms; // \gamma <=> \gamma' Theorem thm = bitBlastIneqn(resRHS[1][1]); // (\beta and \gamma) <=> (\beta and \gamma') changed.push_back(1); thms.push_back(thm); thm = substitutivityRule(resRHS[1], changed, thms); // (\alpha or (\beta and \gamma)) <=> (\alpha or (\beta and \gamma')) // 'changed' is the same, only update thms[0] thms[0] = thm; thm = substitutivityRule(resRHS, changed, thms); res = transitivityRule(res, thm); /* //resRHS can be of the form (\beta and \gamma) or //resRHS can be of the form (\alpha or \gamma) or //resRHS can be of the form (\gamma) // Our mission is to bitblast \gamma and insert it back to the formula switch(resRHS.getOpKind()) { case OR: if(resRHS[1].isAnd()) { // (\alpha or (\beta and \gamma)) break; } // (\alpha or \gamma) - fall through (same as the AND case) case AND: { // (\beta and \gamma) changed.push_back(1); gamma = resRHS[1]; // \gamma <=> \gamma' gammaThm = rewriteBV(gamma,2); //\gamma' <=> \gamma" Theorem thm3 = bitBlastIneqn(gammaThm.getRHS()); //Theorem thm3 = bitBlastIneqn(gamma); //\gamma <=> \gamma' <=> \gamma" thm3 = transitivityRule(gammaThm, thm3); thms.push_back(thm3); // (\beta and \gamma) <=> (\beta and \gamma") thm3 = substitutivityRule(resRHS,changed,thms); res = transitivityRule(res, thm3); break; } default: // (\gamma) IF_DEBUG(gamma = resRHS;) // \gamma <=> \gamma' gammaThm = rewriteBV(resRHS,2); //\gamma' <=> \gamma" Theorem thm3 = bitBlastIneqn(gammaThm.getRHS()); //Theorem thm3 = bitBlastIneqn(gamma); //\gamma <=> \gamma' <=> \gamma" thm3 = transitivityRule(gammaThm, thm3); res = transitivityRule(res, thm3); break; } DebugAssert(kind == gamma.getOpKind(), "TheoryBitvector::bitBlastIneqn: " "gamma must be a BVLT/BVLE. gamma = " + gamma.toString()); */ } } TRACE("bitvector", "bitBlastIneqn => ", res.toString(), " }"); return res; } /*! The invariant maintained by this function is: accepts a bitvector * term, t,and a bitPosition, i. returns a formula over the set of * propositional variables defined using BOOLEXTRACT of bitvector * variables in t at the position i. * * \return Theorem(BOOLEXTRACT(t, bitPosition) <=> phi), where phi is * a Boolean formula over the individual bits of bit-vector variables. */ Theorem TheoryBitvector::bitBlastTerm(const Expr& t, int bitPosition) { TRACE("bitvector", "bitBlastTerm(", t, ", " + int2string(bitPosition) + ") {"); IF_DEBUG(Type type = t.getType();) DebugAssert(BITVECTOR == type.getExpr().getOpKind(), "TheoryBitvector::bitBlastTerm: The type of input to bitBlastTerm must be BITVECTOR.\n t = " +t.toString()); DebugAssert(bitPosition >= 0, "TheoryBitvector::bitBlastTerm: illegal bitExtraction attempted.\n bitPosition = " + int2string(bitPosition)); Theorem result; // Check the cache Expr t_i = newBoolExtractExpr(t, bitPosition); CDMap::iterator it = d_bitvecCache.find(t_i); if (it != d_bitvecCache.end()) { result = (*it).second; TRACE("bitvector", "bitBlastTerm[cached] => ", result, " }"); DebugAssert(t_i == result.getLHS(), "TheoryBitvector::bitBlastTerm: created wrong theorem" + result.toString() + t_i.toString()); return result; } // Construct the theorem t[bitPosition] <=> \theta_i and put it into // d_bitvecCache switch(t.getOpKind()) { case BVCONST: result = d_rules->bitExtractConstant(t, bitPosition); break; case CONCAT: { Theorem thm = d_rules->bitExtractConcatenation(t, bitPosition); const Expr& boolExtractTerm = thm.getRHS(); DebugAssert(BOOLEXTRACT == boolExtractTerm.getOpKind(), "TheoryBitvector::bitBlastTerm: recursion: term must be bool_extract"); const Expr& term = boolExtractTerm[0]; int bitPos = getBoolExtractIndex(boolExtractTerm); TRACE("bitvector", "term for bitblastTerm recursion:(", term.toString(), ")"); result = transitivityRule(thm, bitBlastTerm(term, bitPos)); break; } case EXTRACT: { Theorem thm = d_rules->bitExtractExtraction(t, bitPosition); const Expr& boolExtractTerm = thm.getRHS(); DebugAssert(BOOLEXTRACT == boolExtractTerm.getOpKind(), "TheoryBitvector::bitBlastTerm: recursion: term must be bool_extract"); const Expr& term = boolExtractTerm[0]; int bitPos = getBoolExtractIndex(boolExtractTerm); TRACE("bitvector", "term for bitblastTerm recursion:(", term, ")"); result = transitivityRule(thm, bitBlastTerm(term, bitPos)); break; } case CONST_WIDTH_LEFTSHIFT: { result = d_rules->bitExtractFixedLeftShift(t, bitPosition); const Expr& extractTerm = result.getRHS(); if(BOOLEXTRACT == extractTerm.getOpKind()) result = transitivityRule(result, bitBlastTerm(extractTerm[0], getBoolExtractIndex(extractTerm))); break; } case BVSHL: { // BOOLEXTRACT(bvshl(t,x),i) <=> ((x = 0) AND BOOLEXTRACT(t,i)) OR // ((x = 1) AND BOOLEXTRACT(t,i-1)) OR ... // ((x = i) AND BOOLEXTRACT(t,0)) Theorem thm = d_rules->bitExtractBVSHL(t, bitPosition); // bitblast the equations and extractions vector thms, thms0; int bvsize = BVSize(t); for (int i = 0; i <= bitPosition; ++i) { thms0.push_back(bitBlastEqn(t[1].eqExpr(newBVConstExpr(i, bvsize)))); thms0.push_back(bitBlastTerm(t[0], bitPosition-i)); thms.push_back(substitutivityRule(AND, thms0)); thms0.clear(); } // Put it all together if (thms.size() == 1) { result = transitivityRule(thm, thms[0]); } else { Theorem thm2 = substitutivityRule(OR, thms); result = transitivityRule(thm, thm2); } break; } case BVLSHR: { // BOOLEXTRACT(bvlshr(t,x),i) <=> ((x = 0) AND BOOLEXTRACT(t,i)) OR // ((x = 1) AND BOOLEXTRACT(t,i+1)) OR ... // ((x = n-1-i) AND BOOLEXTRACT(t,n-1)) Theorem thm = d_rules->bitExtractBVLSHR(t, bitPosition); // bitblast the equations and extractions vector thms, thms0; int bvsize = BVSize(t); for (int i = 0; i <= bvsize-1-bitPosition; ++i) { thms0.push_back(bitBlastEqn(t[1].eqExpr(newBVConstExpr(i, bvsize)))); thms0.push_back(bitBlastTerm(t[0], bitPosition+i)); thms.push_back(substitutivityRule(AND, thms0)); thms0.clear(); } // Put it all together if (thms.size() == 1) { result = transitivityRule(thm, thms[0]); } else { Theorem thm2 = substitutivityRule(OR, thms); result = transitivityRule(thm, thm2); } break; } case BVASHR: { // BOOLEXTRACT(bvlshr(t,x),i) <=> ((x = 0) AND BOOLEXTRACT(t,i)) OR // ((x = 1) AND BOOLEXTRACT(t,i+1)) OR ... // ((x >= n-1-i) AND BOOLEXTRACT(t,n-1)) Theorem thm = d_rules->bitExtractBVASHR(t, bitPosition); // bitblast the equations and extractions vector thms, thms0; int bvsize = BVSize(t); int i = 0; for (; i < bvsize-1-bitPosition; ++i) { thms0.push_back(bitBlastEqn(t[1].eqExpr(newBVConstExpr(i, bvsize)))); thms0.push_back(bitBlastTerm(t[0], bitPosition+i)); thms.push_back(substitutivityRule(AND, thms0)); thms0.clear(); } Expr leExpr = newBVLEExpr(newBVConstExpr(i, bvsize), t[1]); thms0.push_back(bitBlastIneqn(leExpr)); thms0.push_back(bitBlastTerm(t[0], bvsize-1)); thms.push_back(substitutivityRule(AND, thms0)); // Put it all together if (thms.size() == 1) { result = transitivityRule(thm, thms[0]); } else { Theorem thm2 = substitutivityRule(OR, thms); result = transitivityRule(thm, thm2); } break; } case BVOR: case BVAND: case BVXOR: { int kind = t.getOpKind(); int resKind = (kind == BVOR) ? OR : kind == BVAND ? AND : XOR; Theorem thm = d_rules->bitExtractBitwise(t, bitPosition, kind); const Expr& phi = thm.getRHS(); DebugAssert(phi.getOpKind() == resKind && phi.arity() == t.arity(), "TheoryBitvector::bitBlastTerm: recursion:\n phi = " + phi.toString() + "\n t = " + t.toString()); vector substThms; for(Expr::iterator i=phi.begin(), iend=phi.end(); i!=iend; ++i) { DebugAssert(i->getOpKind() == BOOLEXTRACT, "Expected BOOLEXTRACT"); substThms.push_back(bitBlastTerm((*i)[0], getBoolExtractIndex(*i))); } result = transitivityRule(thm, substitutivityRule(resKind, substThms)); break; } case BVNEG: { Theorem thm = d_rules->bitExtractNot(t, bitPosition); const Expr& extractTerm = thm.getRHS(); DebugAssert(NOT == extractTerm.getKind(), "TheoryBitvector::bitBlastTerm: recursion: term must be NOT"); const Expr& term0 = extractTerm[0]; DebugAssert(BOOLEXTRACT == term0.getOpKind(), "TheoryBitvector::bitBlastTerm: recursion:(terms must be BOOL-EXTRACT"); int bitPos0 = getBoolExtractIndex(term0); std::vector res; res.push_back(bitBlastTerm(term0[0], bitPos0)); result = transitivityRule(thm, substitutivityRule(NOT, res)); break; } case BVPLUS: { Theorem thm_binary; if(t.arity() > 2) thm_binary = d_rules->bvPlusAssociativityRule(t); else thm_binary = reflexivityRule(t); Expr bvPlusTerm = thm_binary.getRHS(); // Get the bits of the right multiplicand Expr b = bvPlusTerm[1]; vector b_bits(bitPosition + 1); for (int bit = bitPosition; bit >= 0; -- bit) b_bits[bit] = bitBlastTerm(b, bit); // The output of the bit-blasting vector output_bits; // Get the bits of the left multiplicand Expr a = bvPlusTerm[0]; vector a_bits(bitPosition + 1); for (int bit = bitPosition; bit >= 0; -- bit) a_bits[bit] = bitBlastTerm(a, bit); // Bit-blast them and get all the output bits (of this size) d_rules->bitblastBVPlus(a_bits, b_bits, bvPlusTerm, output_bits); // Simplify all the resulting bit expressions and add them to the bit-blasting cache Theorem thm; for (int bit = 0; bit <= bitPosition; bit ++) { thm = output_bits[bit]; Expr original_boolextract = newBoolExtractExpr(t, bit); Expr boolextract = thm.getLHS(); Expr bitblasted = thm.getRHS(); CDMap::iterator it = d_bitvecCache.find(boolextract); if (it != d_bitvecCache.end()) continue; thm = d_bitvecCache[boolextract] = transitivityRule(thm, rewriteBoolean(thm.getRHS())); if (boolextract != original_boolextract) thm = d_bitvecCache[original_boolextract] = transitivityRule(substitutivityRule(original_boolextract, thm_binary), thm); } // We are returning the last theorem return thm; break; } case BVMULT: { Theorem thm; bool a_is_const = (BVCONST == t[0].getKind()); // If a constant, rewrite using addition if (a_is_const) { thm = d_rules->bitExtractConstBVMult(t, bitPosition); const Expr& boolExtractTerm = thm.getRHS(); const Expr& term = boolExtractTerm[0]; result = transitivityRule(thm, bitBlastTerm(term, bitPosition)); break; } // Get the bits ot the right multiplicant Expr b = t[1]; vector b_bits(bitPosition + 1); for (int bit = bitPosition; bit >= 0; -- bit) b_bits[bit] = bitBlastTerm(b, bit); // The output of the bitblasting vector output_bits; // Get the bits of the left multiplicant Expr a = t[0]; vector a_bits(bitPosition + 1); for (int bit = bitPosition; bit >= 0; -- bit) a_bits[bit] = bitBlastTerm(a, bit); // Bitblast them and get all the output bits (of this size) d_rules->bitblastBVMult(a_bits, b_bits, t, output_bits); // Simplify all the resulting bit expressions and add them to the bitblasting cache for (int bit = 0; bit <= bitPosition; bit ++) { thm = output_bits[bit]; Expr boolextract = thm.getLHS(); Expr bitblasted = thm.getRHS(); CDMap::iterator it = d_bitvecCache.find(boolextract); if (it != d_bitvecCache.end()) continue; thm = d_bitvecCache[boolextract] = transitivityRule(thm, rewriteBoolean(thm.getRHS())); // not allowed to use simplify in bitblasting //theoryCore()->simplify(thm.getRHS())); } // We are returning the last theorem return thm; break; } // case BVMULT: { // // Theorem thm; // if(BVCONST == t[0].getKind()) // thm = d_rules->bitExtractConstBVMult(t, bitPosition); // else // thm = d_rules->bitExtractBVMult(t, bitPosition); // const Expr& boolExtractTerm = thm.getRHS(); // const Expr& term = boolExtractTerm[0]; // result = transitivityRule(thm, bitBlastTerm(term, bitPosition)); // break; // } default: { FatalAssert(theoryOf(t.getOpKind()) != this, "Unexpected operator in bitBlastTerm:" + t.toString()); //we have bitvector variable. check if the expr is indeed a BITVECTOR. IF_DEBUG(Type type = t.getType();) DebugAssert(BITVECTOR == (type.getExpr()).getOpKind(), "BitvectorTheoremProducer::bitBlastTerm: the type must be BITVECTOR"); //check if 0<= i < length of BITVECTOR IF_DEBUG(int bvLength=BVSize(t);) DebugAssert(0 <= bitPosition && bitPosition < bvLength, "BitvectorTheoremProducer::bitBlastTerm: the bitextract position must be legal"); TRACE("bitvector", "bitBlastTerm: blasting variables(", t, ")"); const Expr bitExtract = newBoolExtractExpr(t, bitPosition); result = reflexivityRule(bitExtract); TRACE("bitvector", "bitBlastTerm: blasting variables(", t, ")"); break; } } DebugAssert(!result.isNull(), "TheoryBitvector::bitBlastTerm()"); Theorem simpThm = rewriteBoolean(result.getRHS()); // not allowed to use simplify in bitblasting // theoryCore()->simplify(result.getRHS()); result = transitivityRule(result, simpThm); d_bitvecCache[t_i] = result; DebugAssert(t_i == result.getLHS(), "TheoryBitvector::bitBlastTerm: " "created wrong theorem.\n result = " +result.toString() +"\n t_i = "+t_i.toString()); TRACE("bitvector", "bitBlastTerm => ", result, " }"); return result; } // Rewriting methods //! Check that all the kids of e are BVCONST static bool constantKids(const Expr& e) { for(Expr::iterator i=e.begin(), iend=e.end(); i!=iend; ++i) if(!i->isRational() && i->getKind() != BVCONST) return false; return true; } //! Search for all the BVCONST kids of e, and return their indices in idxs static void constantKids(const Expr& e, vector& idxs) { for(int i=0, iend=e.arity(); i e' or !e <==> e', depending on whether // neg is false or true, respectively. // This function must be called only from the pushNegation function Theorem TheoryBitvector::pushNegationRec(const Expr& e) { TRACE("pushNegation", "pushNegationRec(", e,") {"); DebugAssert(e.getKind() == BVNEG, "Expected BVNEG in pushNegationRec"); ExprMap::iterator i = d_pushNegCache.find(e); if(i != d_pushNegCache.end()) { // Found cached result TRACE("TheoryBitvector::pushNegation", "pushNegationRec [cached] => ", (*i).second, "}"); return (*i).second; } Theorem res(reflexivityRule(e)); switch(e[0].getOpKind()) { case BVCONST: res = d_rules->negConst(e); break; case BVNEG:{ res = d_rules->negNeg(e); break; } case BVAND: { //demorgan's laws. Theorem thm0 = d_rules->negBVand(e); Expr ee = thm0.getRHS(); if (ee.arity() == 0) res = thm0; else { //process each negated kid Op op = ee.getOp(); vector thms; for(Expr::iterator i=ee.begin(), iend=ee.end(); i!=iend; ++i) thms.push_back(pushNegationRec(*i)); res = substitutivityRule(op, thms); res = transitivityRule(thm0, res); } break; } case BVOR: { //demorgan's laws. Theorem thm0 = d_rules->negBVor(e); Expr ee = thm0.getRHS(); if (ee.arity() == 0) res = thm0; else { //process each negated kid Op op = ee.getOp(); vector thms; for(Expr::iterator i=ee.begin(), iend=ee.end(); i!=iend; ++i) thms.push_back(pushNegationRec(*i)); res = substitutivityRule(op, thms); res = transitivityRule(thm0, res); } break; } case BVXOR: { res = d_rules->negBVxor(e); Expr ee = res.getRHS(); // only the first child is negated Theorem thm0 = pushNegationRec(ee[0]); if (!thm0.isRefl()) { thm0 = substitutivityRule(ee, 0, thm0); res = transitivityRule(res, thm0); } break; } case BVXNOR: { res = d_rules->negBVxnor(e); break; } case CONCAT: { //demorgan's laws. Theorem thm0 = d_rules->negConcat(e); Expr ee = thm0.getRHS(); if (ee.arity() == 0) res = thm0; else { //process each negated kid Op op = ee.getOp(); vector thms; for(Expr::iterator i=ee.begin(), iend=ee.end(); i!=iend; ++i) thms.push_back(pushNegationRec(*i)); res = substitutivityRule(op, thms); res = transitivityRule(thm0, res); } break; } case BVPLUS: // FIXME: Need to implement the following transformation: // ~(x+y) <=> ~x+~y+1 // (because ~(x+y)+1= -(x+y) = -x-y = ~x+1+~y+1) case BVMULT: // FIXME: Need to implement the following transformation: // ~(x*y) <=> (~x+1)*y-1 // [ where we prefer x to be constant/AND/OR/NEG and then // BVPLUS, and only then everything else]. // (because ~(x*y)+1= -(x+y) = (-x)*y = (~x+1)*y) default: res = reflexivityRule(e); break; } TRACE("TheoryBitvector::pushNegation", "pushNegationRec => ", res, "}"); d_pushNegCache[e] = res; return res; } // We assume that the cache is initially empty Theorem TheoryBitvector::pushNegation(const Expr& e) { d_pushNegCache.clear(); DebugAssert(BVNEG == e.getOpKind(), "Expected BVNEG"); return pushNegationRec(e); } //! Top down simplifier Theorem TheoryBitvector::simplifyOp(const Expr& e) { if (e.arity() > 0) { Expr ee(e); Theorem thm0; switch(e.getOpKind()) { case BVNEG: thm0 = pushNegation(e); break; case EXTRACT: switch(e[0].getOpKind()) { case BVPLUS: thm0 = d_rules->extractBVPlus(e); break; case BVMULT: thm0 = d_rules->extractBVMult(e); break; default: thm0 = reflexivityRule(e); break; } break; case BVPLUS: break; case BVMULT: // thm0 = d_rules->padBVMult(e); break; case CONCAT: // 0bin0_[k] @ BVPLUS(n, args) => BVPLUS(n+k, args) // if(e.arity()==2 && e[0].getKind()==BVCONST && e[1].getOpKind()==BVPLUS // && computeBVConst(e[0]) == 0) { // thm0 = d_rules->bvplusZeroConcatRule(e); // } break; case RIGHTSHIFT: thm0 = d_rules->rightShiftToConcat(e); break; case LEFTSHIFT: thm0 = d_rules->leftShiftToConcat(e); break; case CONST_WIDTH_LEFTSHIFT: thm0 = d_rules->constWidthLeftShiftToConcat(e); break; default: thm0 = reflexivityRule(e); break; } vector newChildrenThm; vector changed; if(thm0.isNull()) thm0 = reflexivityRule(e); ee = thm0.getRHS(); int ar = ee.arity(); for(int k = 0; k < ar; ++k) { // Recursively simplify the kids Theorem thm = simplify(ee[k]); if (thm.getLHS() != thm.getRHS()) { newChildrenThm.push_back(thm); changed.push_back(k); } } if(changed.size() > 0) { Theorem thm1 = substitutivityRule(ee, changed, newChildrenThm); return transitivityRule(thm0,thm1); } else return thm0; } return reflexivityRule(e); } // Theorem TheoryBitvector::rewriteConst(const Expr& e) // { // Theorem result = reflexivityRule(e); // return result; // } Theorem TheoryBitvector::rewriteBV(const Expr& e, ExprMap& cache, int n) { TRACE("bitvector rewrite", "TheoryBitvector::rewriteBV(", e, ") {"); if (n <= 0) return reflexivityRule(e); Theorem res; if(n >= 2) { // rewrite children recursively Theorem thm; vector thms; vector changed; for(int i=0, iend=e.arity(); i 0) { thm = substitutivityRule(e, changed, thms); return transitivityRule(thm, rewriteBV(thm.getRHS(), cache)); } // else fall through } // Check the cache ExprMap::iterator it = cache.find(e); if (it != cache.end()) { res = (*it).second; TRACE("bitvector rewrite", "TheoryBitvector::rewrite["+int2string(n) +"][cached] => ", res.getExpr(), " }"); IF_DEBUG(debugger.counter("bv rewriteBV[n] cache hits")++;) return res; } // Main rewrites switch(e.getOpKind()) { case NOT: switch (e[0].getKind()) { case BVLT: case BVLE: res = d_rules->notBVLTRule(e); if (!res.isRefl()) { res = transitivityRule(res, simplify(res.getRHS())); } break; case EQ: if (BVSize(e[0][0]) == 1) { res = d_rules->notBVEQ1Rule(e); res = transitivityRule(res, simplify(res.getRHS())); break; } break; } break; case EQ: { // Canonise constant equations to true or false if (e[0].getKind() == BVCONST && e[1].getKind() == BVCONST) { res = d_rules->constEq(e); } else // If x_1 or x_2 = 0 then both have to be 0 if (e[0].getKind() == BVOR && e[1].getKind() == BVCONST && computeBVConst(e[1]) == 0) { res = d_rules->zeroBVOR(e); res = transitivityRule(res, simplify(res.getRHS())); } // if x_1 and x_2 = 1 then both have to be 1 else if (e[0].getKind() == BVAND && e[1].getKind() == BVCONST && computeBVConst(e[1]) == pow(BVSize(e[1]), (Unsigned)2) - 1) { res = d_rules->oneBVAND(e); res = transitivityRule(res, simplify(res.getRHS())); } // Solve else { res = d_rules->canonBVEQ(e); if (!res.isRefl()) { res = transitivityRule(res, simplify(res.getRHS())); } else e.setRewriteNormal(); } break; } case BVCONST: { res = reflexivityRule(e); break; } case CONCAT: { // First, flatten concatenation res = d_rules->concatFlatten(e); TRACE("bitvector rewrite", "rewriteBV (CONCAT): flattened = ", res.getRHS(), ""); // Search for adjacent constants and accumulate the vector of // nested concatenations (@ t1 ... (@ c1 ... ck) ... tn), and the // indices of constant concatenations in this new expression. // We'll connect this term to 'e' by inverse of flattenning, and // rewrite concatenations of constants into bitvector constants. vector idxs; vector kids; // Kids of the new concatenation vector thms; // Rewrites of constant concatenations vector nestedKids; // Kids of the current concatenation of constants // res will be overwritten, using const Expr& may be dangerous Expr e1 = res.getRHS(); for(int i=0, iend=e1.arity(); i 0) { // This is the end of a batch if(nestedKids.size() >= 2) { // Create a nested const concat Expr cc = newConcatExpr(nestedKids); idxs.push_back(kids.size()); kids.push_back(cc); thms.push_back(d_rules->concatConst(cc)); TRACE("bitvector rewrite", "rewriteBV: wrapping ", cc, ""); } else { // A single constant, add it as it is TRACE("bitvector rewrite", "rewriteBV: single const ", nestedKids[0], ""); kids.push_back(nestedKids[0]); } nestedKids.clear(); } // Add the current non-constant BV kids.push_back(e1[i]); } } // Handle the last BVCONST if(nestedKids.size() > 0) { if(nestedKids.size() >= 2) { // Create a nested const concat Expr cc = newConcatExpr(nestedKids); idxs.push_back(kids.size()); kids.push_back(cc); thms.push_back(d_rules->concatConst(cc)); TRACE("bitvector rewrite", "rewriteBV: wrapping ", cc, ""); } else { // A single constant, add it as it is kids.push_back(nestedKids[0]); TRACE("bitvector rewrite", "rewriteBV: single const ", nestedKids[0], ""); } nestedKids.clear(); } // If there are any constants to merge, do the merging if(idxs.size() > 0) { // CONCAT with constants groupped if(kids.size() == 1) { // Special case: all elements are constants DebugAssert(thms.size() == 1, "TheoryBitvector::rewriteBV:\n" "case CONCAT: all constants. thms.size() == " +int2string(thms.size())); res = transitivityRule(res, thms[0]); } else { Expr ee = newConcatExpr(kids); Theorem constMerge = substitutivityRule(ee, idxs, thms); // The inverse flattening of ee Theorem unFlatten = symmetryRule(d_rules->concatFlatten(ee)); // Putting it together: Theorem(e==e'), where e' has constants merged res = transitivityRule(res, unFlatten); res = transitivityRule(res, constMerge); } } // Now do a similar search for mergeable extractions idxs.clear(); thms.clear(); kids.clear(); // nestedKids must already be empty DebugAssert(nestedKids.size() == 0, "rewriteBV() case CONCAT, end of const merge"); Expr prevExpr; // Previous base of extraction (initially Null) // The first and the last bit in the batch of mergeable extractions int hi(-1), low(-1); // Refresh e1 e1 = res.getRHS(); for(int i=0, iend=e1.arity(); i 0 && ei[0] == prevExpr && (low-1) == getExtractHi(ei)) { // Continue to accumulate the current batch nestedKids.push_back(ei); low = getExtractLow(ei); } else { // Start a new batch // First, check if there was a batch before that if(nestedKids.size() >= 2) { // Create a nested const concat Expr cc = newConcatExpr(nestedKids); idxs.push_back(kids.size()); kids.push_back(cc); thms.push_back(d_rules->concatMergeExtract(cc)); nestedKids.clear(); } else if(nestedKids.size() == 1) { // A single extraction, add it as it is kids.push_back(nestedKids[0]); nestedKids.clear(); } // Now, actually start a new batch nestedKids.push_back(ei); hi = getExtractHi(ei); low = getExtractLow(ei); prevExpr = ei[0]; } } else { // e1[i] is not an EXTRACT if(nestedKids.size() >= 2) { // Create a nested const concat Expr cc = newConcatExpr(nestedKids); idxs.push_back(kids.size()); kids.push_back(cc); thms.push_back(d_rules->concatMergeExtract(cc)); } else if(nestedKids.size() == 1) { // A single extraction, add it as it is kids.push_back(nestedKids[0]); } nestedKids.clear(); // Add the current non-EXTRACT BV kids.push_back(ei); } } // Handle the last batch of extractions if(nestedKids.size() >= 2) { // Create a nested const concat Expr cc = newConcatExpr(nestedKids); idxs.push_back(kids.size()); kids.push_back(cc); // The extraction may include all the bits, we need to rewrite again thms.push_back(rewriteBV(d_rules->concatMergeExtract(cc), cache, 1)); } else if(nestedKids.size() == 1) { // A single extraction, add it as it is kids.push_back(nestedKids[0]); } // If there are any extractions to merge, do the merging if(idxs.size() > 0) { // CONCAT with extractions groupped if(kids.size() == 1) { // Special case: all elements merge together DebugAssert(thms.size() == 1, "TheoryBitvector::rewriteBV:\n" "case CONCAT: all extracts merge. thms.size() == " +int2string(thms.size())); res = thms[0]; } else { Expr ee = newConcatExpr(kids); Theorem extractMerge = substitutivityRule(ee, idxs, thms); // The inverse flattening of ee Theorem unFlatten = symmetryRule(d_rules->concatFlatten(ee)); // Putting it together: Theorem(e==e'), where e' has extractions merged res = transitivityRule(res, unFlatten); res = transitivityRule(res, extractMerge); } } // Check for 0bin00 @ BVPLUS(n, ...). Most of the time, this // case will be handled during the top-down phase // (simplifyOp()), but not always. // Expr ee = res.getRHS(); // if(ee.getOpKind()==CONCAT && ee.arity() == 2 && ee[0].getKind()==BVCONST // && ee[1].getOpKind()==BVPLUS && computeBVConst(ee[0]) == 0) { // // Push the concat down through BVPLUS // Theorem thm = d_rules->bvplusZeroConcatRule(ee); // if(thm.getLHS()!=thm.getRHS()) { // thm = transitivityRule(thm, d_rules->padBVPlus(thm.getRHS())); // // Kids may need to be rewritten again // res = rewriteBV(transitivityRule(res, thm), cache, 2); // } // } // Since we may have pulled subexpressions from more than one // level deep, we cannot guarantee that all the new kids are // fully simplified, and have to call simplify explicitly again. // Since this is potentially an expensive operation, we try to // minimize the need for it: // * check if the result has a find pointer (then kids don't // need to be simplified), // * check if any of the kids simplify (if not, don't bother). // If kids are already simplified, we'll hit the simplifier // cache. It's only expensive when kids do indeed simplify. if(!res.isRefl() && (theoryCore()->inUpdate() || !res.getRHS().hasFind())) { res = transitivityRule(res, simplify(res.getRHS())); } break; } case EXTRACT: { DebugAssert(e.arity() == 1, "TheoryBitvector::rewriteBV: e = " +e.toString()); if(getExtractLow(e) == 0 && getExtractHi(e) == BVSize(e[0])-1) res = d_rules->extractWhole(e); else { switch(e[0].getOpKind()) { case BVCONST: res = d_rules->extractConst(e); break; case EXTRACT: res = d_rules->extractExtract(e); break; case CONCAT: // Push extraction through concat, and rewrite the kids res = rewriteBV(d_rules->extractConcat(e), cache, 2); break; case BVNEG: res = rewriteBV(d_rules->extractNeg(e), cache, 2); break; case BVAND: res = rewriteBV(d_rules->extractAnd(e), cache, 2); break; case BVOR: res = rewriteBV(d_rules->extractOr(e), cache, 2); break; case BVXOR: res = rewriteBV(d_rules->extractBitwise(e, BVXOR, "extract_bvxor"), cache, 2); break; case BVMULT: { const Expr& bvmult = e[0]; int hiBit = getExtractHi(e); int bvmultLen = BVSize(bvmult); // Applicable if it changes anything if(hiBit+1 < bvmultLen) { res = d_rules->extractBVMult(e); res = rewriteBV(res, cache, 3); } else res = reflexivityRule(e); break; } case BVPLUS: { const Expr& bvplus = e[0]; int hiBit = getExtractHi(e); int bvplusLen = BVSize(bvplus); if(hiBit+1 < bvplusLen) { res = d_rules->extractBVPlus(e); } else res = reflexivityRule(e); break; } default: res = reflexivityRule(e); break; } } if (!res.isRefl()) { res = transitivityRule(res, simplify(res.getRHS())); } break; } case BOOLEXTRACT: { Expr t(e); // Normal form: t[0] for 1-bit t, collapse t[i:i][0] into t[i] if(BVSize(e[0]) > 1) { // transform t[i] to t[i:i][0] and rewrite res = rewriteBV(d_rules->bitExtractRewrite(e), cache, 2); t = res.getRHS(); } if(t.getOpKind() == BOOLEXTRACT && t[0].getOpKind() == EXTRACT) { // Collapse t[i:i][0] to t[i] int low = getExtractLow(t[0]); if(getExtractHi(t[0]) == low) { Theorem thm(d_rules->bitExtractRewrite (newBoolExtractExpr(t[0][0], low))); thm = symmetryRule(thm); res = (res.isNull())? thm : transitivityRule(res, thm); t = res.getRHS()[0]; // Make sure t in the resulting t[i] is its own find pointer // (global invariant) if(t.hasFind()) { Theorem findThm = find(t); if(t != findThm.getRHS()) { vector thms; thms.push_back(findThm); thm = substitutivityRule(res.getRHS().getOp(), thms); res = transitivityRule(res, thm); } } } } if(!res.isNull()) t = res.getRHS(); // Rewrite a constant extraction to TRUE or FALSE if(t.getOpKind() == BOOLEXTRACT && constantKids(t)) { Theorem thm = d_rules->bitExtractConstant(t[0], getBoolExtractIndex(t)); res = (res.isNull())? thm : transitivityRule(res, thm); } break; } case LEFTSHIFT: if (e[0].getKind() == BVCONST && computeBVConst(e[0]) == 0) { res = d_rules->bvShiftZero(e); } else { res = d_rules->leftShiftToConcat(e); if (!res.isRefl()) { res = transitivityRule(res, simplify(res.getRHS())); } } break; case CONST_WIDTH_LEFTSHIFT: if (e[0].getKind() == BVCONST && computeBVConst(e[0]) == 0) { res = d_rules->bvShiftZero(e); } else { res = d_rules->constWidthLeftShiftToConcat(e); if (!res.isRefl()) { res = transitivityRule(res, simplify(res.getRHS())); } } break; case RIGHTSHIFT: if (e[0].getKind() == BVCONST && computeBVConst(e[0]) == 0) { res = d_rules->bvShiftZero(e); } else { res = d_rules->rightShiftToConcat(e); if (!res.isRefl()) { res = transitivityRule(res, simplify(res.getRHS())); } } break; case BVSHL: if (e[0].getKind() == BVCONST && computeBVConst(e[0]) == 0) { res = d_rules->bvShiftZero(e); } else if (e[1].getKind() == BVCONST) { res = d_rules->bvshlToConcat(e); res = transitivityRule(res, simplify(res.getRHS())); } // else { // res = d_rules->bvshlSplit(e); // res = transitivityRule(res, simplify(res.getRHS())); // } break; case BVLSHR: if (e[0].getKind() == BVCONST && computeBVConst(e[0]) == 0) { res = d_rules->bvShiftZero(e); } else if (e[1].getKind() == BVCONST) { res = d_rules->bvlshrToConcat(e); res = transitivityRule(res, simplify(res.getRHS())); } break; case BVASHR: if (e[0].getKind() == BVCONST && computeBVConst(e[0]) == 0) { res = d_rules->bvShiftZero(e); } else if (e[1].getKind() == BVCONST) { res = d_rules->bvashrToConcat(e); res = transitivityRule(res, simplify(res.getRHS())); } break; case SX: { res = d_rules->signExtendRule(e); res = transitivityRule(res, simplify(res.getRHS())); break; } case BVZEROEXTEND: res = d_rules->zeroExtendRule(e); res = transitivityRule(res, simplify(res.getRHS())); break; case BVREPEAT: res = d_rules->repeatRule(e); res = transitivityRule(res, simplify(res.getRHS())); break; case BVROTL: res = d_rules->rotlRule(e); res = transitivityRule(res, simplify(res.getRHS())); break; case BVROTR: res = d_rules->rotrRule(e); res = transitivityRule(res, simplify(res.getRHS())); break; case BVAND: case BVOR: case BVXOR: { int kind = e.getOpKind(); // Flatten the bit-wise AND, eliminate duplicates, reorder terms res = d_rules->bitwiseFlatten(e, kind); Expr ee = res.getRHS(); if (ee.getOpKind() != kind) break; // Search for constant bitvectors vector idxs; constantKids(ee, idxs); int idx = -1; if(idxs.size() >= 2) { res = transitivityRule(res, d_rules->bitwiseConst(ee, idxs, kind)); ee = res.getRHS(); if (ee.getOpKind() != kind) break; idx = 0; } else if (idxs.size() == 1) { idx = idxs[0]; } if (idx >= 0) { res = transitivityRule(res, d_rules->bitwiseConstElim(ee, idx, kind)); ee = res.getRHS(); } if (ee.getOpKind() == kind) { res = transitivityRule(res, d_rules->bitwiseConcat(ee, kind)); } if (!res.isRefl()) { res = transitivityRule(res, simplify(res.getRHS())); } else { e.setRewriteNormal(); } break; } case BVXNOR: { res = d_rules->rewriteXNOR(e); res = transitivityRule(res, simplify(res.getRHS())); break; } case BVNEG: { res = pushNegation(e); if (!res.isRefl()) { res = transitivityRule(res, simplify(res.getRHS())); } break; } case BVNAND: { res = d_rules->rewriteNAND(e); res = transitivityRule(res, simplify(res.getRHS())); break; } case BVNOR: { res = d_rules->rewriteNOR(e); res = transitivityRule(res, simplify(res.getRHS())); break; } case BVCOMP: { res = d_rules->rewriteBVCOMP(e); res = transitivityRule(res, simplify(res.getRHS())); break; } case BVUMINUS: { res = d_rules->canonBVUMinus( e ); res = transitivityRule(res, simplify(res.getRHS())); break; } case BVPLUS: { res = d_rules->canonBVPlus(e ); if (!res.isRefl()) { res = transitivityRule(res, simplify(res.getRHS())); } else e.setRewriteNormal(); break; } case BVSUB: { res = d_rules->rewriteBVSub(e); res = transitivityRule(res, simplify(res.getRHS())); break; } case BVMULT: { res = d_rules->liftConcatBVMult(e); if (!res.isRefl()) { res = transitivityRule(res, simplify(res.getRHS())); } else { res = d_rules->canonBVMult( e ); if (!res.isRefl()) res = transitivityRule(res, simplify(res.getRHS())); else e.setRewriteNormal(); } break; } case BVUDIV: { Expr a = e[0]; Expr b = e[1]; // Constant division if (a.getOpKind() == BVCONST && b.getOpKind() == BVCONST) { res = d_rules->bvUDivConst(e); break; } if (theoryCore()->okToEnqueue()) { // get the full theorem // e = x/y // \exists div, mod: e = div & (y != 0 -> ...) // result is the equality // assert the additional conjunct Theorem fullTheorem = d_rules->bvUDivTheorem(e); // Skolemise the variables Theorem skolem_div = getCommonRules()->skolemize(fullTheorem); // Get the rewrite part res = getCommonRules()->andElim(skolem_div, 0); // Get the division part Theorem additionalConstraint = getCommonRules()->andElim(skolem_div, 1); // Enqueue the division part enqueueFact(additionalConstraint); res = transitivityRule(res, simplify(res.getRHS())); } else { res = reflexivityRule(e); } break; } case BVSDIV: res = d_rules->bvSDivRewrite(e); res = transitivityRule(res, simplify(res.getRHS())); break; case BVUREM: { Expr a = e[0]; Expr b = e[1]; // Constant division if (a.getOpKind() == BVCONST && b.getOpKind() == BVCONST) { res = d_rules->bvURemConst(e); break; } res = d_rules->bvURemRewrite(e); res = transitivityRule(res, theoryCore()->simplify(res.getRHS())); break; } case BVSREM: res = d_rules->bvSRemRewrite(e); res = transitivityRule(res, simplify(res.getRHS())); break; case BVSMOD: res = d_rules->bvSModRewrite(e); res = transitivityRule(res, simplify(res.getRHS())); break; case BVLT: case BVLE: { Expr lhs = e[0]; Expr rhs = e[1]; if (BVSize(lhs) != BVSize(rhs)) { res = d_rules->padBVLTRule(e, BVSize(lhs) > BVSize(rhs) ? BVSize(lhs) : BVSize(rhs)); res = transitivityRule(res, simplify(res.getRHS())); } else { if(lhs == rhs) res = d_rules->lhsEqRhsIneqn(e, e.getOpKind()); else if (BVCONST == lhs.getKind() && BVCONST == rhs.getKind()) res = d_rules->bvConstIneqn(e, e.getOpKind()); else if (e.getOpKind() == BVLE && BVCONST == lhs.getKind() && computeBVConst(lhs) == 0) res = d_rules->zeroLeq(e); } break; } case BVGT: case BVGE: FatalAssert(false, "Should be eliminated at parse-time"); break; case BVSLT: case BVSLE:{ /*! input: e0 <=(s) e1. output depends on whether the topbits(MSB) of * e0 and e1 are constants. If they are constants then optimizations * are done. In general, the following rule is implemented. * Step1: * e0 <=(s) e1 * <==> * pad(e0) <=(s) pad(e1) * Step2: * pad(e0) <=(s) pad(e1) * <==> * (e0[n-1] AND NOT e1[n-1]) OR * (e0[n-1] = e1[n-1] AND e0[n-2:0] <= e1[n-2:0]) */ int e0len = BVSize(e[0]); int e1len = BVSize(e[1]); int bvlength = e0len>=e1len ? e0len : e1len; //e0 <=(s) e1 <=> signpad(e0) <=(s) signpad(e1) std::vector thms; std::vector changed; //e0 <= e1 <==> pad(e0) <= pad(e1) Theorem thm = d_rules->padBVSLTRule(e, bvlength); Expr paddedE = thm.getRHS(); //the rest of the code simply normalizes pad(e0) and pad(e1) Theorem thm0 = d_rules->signExtendRule(paddedE[0]); Expr rhs0 = thm0.getRHS(); thm0 = transitivityRule(thm0, rewriteBV(rhs0, cache)); if(thm0.getLHS() != thm0.getRHS()) { thms.push_back(thm0); changed.push_back(0); } Theorem thm1 = d_rules->signExtendRule(paddedE[1]); Expr rhs1 = thm1.getRHS(); thm1 = transitivityRule(thm1, rewriteBV(rhs1, cache)); if(thm1.getLHS() != thm1.getRHS()) { thms.push_back(thm1); changed.push_back(1); } if(changed.size() > 0) { thm0 = substitutivityRule(paddedE,changed,thms); thm0 = transitivityRule(thm, thm0); } else thm0 = reflexivityRule(e); //signpad(e0) <= signpad(e1) Expr thm0RHS = thm0.getRHS(); DebugAssert(thm0RHS.getOpKind() == BVSLT || thm0RHS.getOpKind() == BVSLE, "TheoryBitvector::RewriteBV"); //signpad(e0)[bvlength-1:bvlength-1] const Expr MSB0 = newBVExtractExpr(thm0RHS[0],bvlength-1,bvlength-1); //signpad(e1)[bvlength-1:bvlength-1] const Expr MSB1 = newBVExtractExpr(thm0RHS[1],bvlength-1,bvlength-1); //rewritten MSB0 const Theorem topBit0 = rewriteBV(MSB0, cache, 2); //rewritten MSB1 const Theorem topBit1 = rewriteBV(MSB1, cache, 2); //compute e0 <=(s) e1 <==> signpad(e0) <=(s) signpad(e1) <==> //output as given above thm1 = d_rules->signBVLTRule(thm0RHS, topBit0, topBit1); thm1 = transitivityRule(thm1,simplify(thm1.getRHS())); res = transitivityRule(thm0,thm1); break; } case BVSGT: case BVSGE: FatalAssert(false, "Should be eliminated at parse-time"); break; default: res = reflexivityRule(e); break; } if (res.isNull()) res = reflexivityRule(e); // Update cache cache[e] = res; TRACE("bitvector rewrite", "TheoryBitvector::rewriteBV => ", res.getExpr(), " }"); return res; } Theorem TheoryBitvector::rewriteBV(const Expr& e, int n) { ExprMap cache; return rewriteBV(e, cache, n); } Theorem TheoryBitvector::rewriteBoolean(const Expr& e) { Theorem thm; switch (e.getKind()) { case NOT: if (e[0].isTrue()) thm = getCommonRules()->rewriteNotTrue(e); else if (e[0].isFalse()) thm = getCommonRules()->rewriteNotFalse(e); else if (e[0].isNot()) thm = getCommonRules()->rewriteNotNot(e); break; case IFF: { thm = getCommonRules()->rewriteIff(e); const Expr& rhs = thm.getRHS(); // The only time we need to rewrite the result (rhs) is when // e==(FALSE<=>e1) or (e1<=>FALSE), so rhs==!e1. if (e != rhs && rhs.isNot()) thm = transitivityRule(thm, rewriteBoolean(rhs)); break; } case AND:{ std::vector newK; std::vector changed; unsigned count(0); for(Expr::iterator ii=e.begin(),iiend=e.end();ii!=iiend;ii++,count++) { Theorem temp = rewriteBoolean(*ii); if(temp.getLHS() != temp.getRHS()) { newK.push_back(temp); changed.push_back(count); } } if(changed.size() > 0) { Theorem res = substitutivityRule(e,changed,newK); thm = transitivityRule(res, rewriteAnd(res.getRHS())); } else thm = rewriteAnd(e); } break; case OR:{ std::vector newK; std::vector changed; unsigned count(0); for(Expr::iterator ii=e.begin(),iiend=e.end();ii!=iiend;ii++,count++) { Theorem temp = rewriteBoolean(*ii); if(temp.getLHS() != temp.getRHS()) { newK.push_back(temp); changed.push_back(count); } } if(changed.size() > 0) { Theorem res = substitutivityRule(e,changed,newK); thm = transitivityRule(res, rewriteOr(res.getRHS())); } else thm = rewriteOr(e); } break; default: break; } if(thm.isNull()) thm = reflexivityRule(e); return thm; } /////////////////////////////////////////////////////////////////////////////// // TheoryBitvector Public Methods // /////////////////////////////////////////////////////////////////////////////// TheoryBitvector::TheoryBitvector(TheoryCore* core) : Theory(core, "Bitvector"), d_bvDelayEq(core->getStatistics().counter("bv delayed assert eqs")), d_bvAssertEq(core->getStatistics().counter("bv eager assert eqs")), d_bvDelayDiseq(core->getStatistics().counter("bv delayed assert diseqs")), d_bvAssertDiseq(core->getStatistics().counter("bv eager assert diseqs")), d_bvTypePreds(core->getStatistics().counter("bv type preds enqueued")), d_bvDelayTypePreds(core->getStatistics().counter("bv type preds delayed")), d_bvBitBlastEq(core->getStatistics().counter("bv bitblast eqs")), d_bvBitBlastDiseq(core->getStatistics().counter("bv bitblast diseqs")), d_bv32Flag(&(core->getFlags()["bv32-flag"].getBool())), d_bitvecCache(core->getCM()->getCurrentContext()), d_eq(core->getCM()->getCurrentContext()), d_eqPending(core->getCM()->getCurrentContext()), d_eq_index(core->getCM()->getCurrentContext(), 0, 0), d_bitblast(core->getCM()->getCurrentContext()), d_bb_index(core->getCM()->getCurrentContext(), 0, 0), d_sharedSubterms(core->getCM()->getCurrentContext()), d_sharedSubtermsList(core->getCM()->getCurrentContext()), d_maxLength(0), d_index1(core->getCM()->getCurrentContext(), 0, 0), d_index2(core->getCM()->getCurrentContext(), 0, 0) // d_solvedEqSet(core->getCM()->getCurrentContext(), 0, 0) { getEM()->newKind(BITVECTOR, "_BITVECTOR", true); getEM()->newKind(BVCONST, "_BVCONST"); getEM()->newKind(CONCAT, "_CONCAT"); getEM()->newKind(EXTRACT, "_EXTRACT"); getEM()->newKind(BOOLEXTRACT, "_BOOLEXTRACT"); getEM()->newKind(LEFTSHIFT, "_LEFTSHIFT"); getEM()->newKind(CONST_WIDTH_LEFTSHIFT, "_CONST_WIDTH_LEFTSHIFT"); getEM()->newKind(RIGHTSHIFT, "_RIGHTSHIFT"); getEM()->newKind(BVSHL, "_BVSHL"); getEM()->newKind(BVLSHR, "_BVLSHR"); getEM()->newKind(BVASHR, "_BVASHR"); getEM()->newKind(SX,"_SX"); getEM()->newKind(BVREPEAT,"_BVREPEAT"); getEM()->newKind(BVZEROEXTEND,"_BVZEROEXTEND"); getEM()->newKind(BVROTL,"_BVROTL"); getEM()->newKind(BVROTR,"_BVROTR"); getEM()->newKind(BVAND, "_BVAND"); getEM()->newKind(BVOR, "_BVOR"); getEM()->newKind(BVXOR, "_BVXOR"); getEM()->newKind(BVXNOR, "_BVXNOR"); getEM()->newKind(BVNEG, "_BVNEG"); getEM()->newKind(BVNAND, "_BVNAND"); getEM()->newKind(BVNOR, "_BVNOR"); getEM()->newKind(BVCOMP, "_BVCOMP"); getEM()->newKind(BVUMINUS, "_BVUMINUS"); getEM()->newKind(BVPLUS, "_BVPLUS"); getEM()->newKind(BVSUB, "_BVSUB"); getEM()->newKind(BVMULT, "_BVMULT"); getEM()->newKind(BVUDIV, "_BVUDIV"); getEM()->newKind(BVSDIV, "_BVSDIV"); getEM()->newKind(BVUREM, "_BVUREM"); getEM()->newKind(BVSREM, "_BVSREM"); getEM()->newKind(BVSMOD, "_BVSMOD"); getEM()->newKind(BVLT, "_BVLT"); getEM()->newKind(BVLE, "_BVLE"); getEM()->newKind(BVGT, "_BVGT"); getEM()->newKind(BVGE, "_BVGE"); getEM()->newKind(BVSLT, "_BVSLT"); getEM()->newKind(BVSLE, "_BVSLE"); getEM()->newKind(BVSGT, "_BVSGT"); getEM()->newKind(BVSGE, "_BVSGE"); getEM()->newKind(INTTOBV, "_INTTOBV"); getEM()->newKind(BVTOINT, "_BVTOINT"); getEM()->newKind(BVTYPEPRED, "_BVTYPEPRED"); std::vector kinds; kinds.push_back(BITVECTOR); kinds.push_back(BVCONST); kinds.push_back(CONCAT); kinds.push_back(EXTRACT); kinds.push_back(BOOLEXTRACT); kinds.push_back(LEFTSHIFT); kinds.push_back(CONST_WIDTH_LEFTSHIFT); kinds.push_back(RIGHTSHIFT); kinds.push_back(BVSHL); kinds.push_back(BVLSHR); kinds.push_back(BVASHR); kinds.push_back(SX); kinds.push_back(BVREPEAT); kinds.push_back(BVZEROEXTEND); kinds.push_back(BVROTL); kinds.push_back(BVROTR); kinds.push_back(BVAND); kinds.push_back(BVOR); kinds.push_back(BVXOR); kinds.push_back(BVXNOR); kinds.push_back(BVNEG); kinds.push_back(BVNAND); kinds.push_back(BVNOR); kinds.push_back(BVCOMP); kinds.push_back(BVUMINUS); kinds.push_back(BVPLUS); kinds.push_back(BVSUB); kinds.push_back(BVMULT); kinds.push_back(BVUDIV); kinds.push_back(BVSDIV); kinds.push_back(BVUREM); kinds.push_back(BVSREM); kinds.push_back(BVSMOD); kinds.push_back(BVLT); kinds.push_back(BVLE); kinds.push_back(BVGT); kinds.push_back(BVGE); kinds.push_back(BVSLT); kinds.push_back(BVSLE); kinds.push_back(BVSGT); kinds.push_back(BVSGE); kinds.push_back(INTTOBV); kinds.push_back(BVTOINT); kinds.push_back(BVTYPEPRED); registerTheory(this, kinds); d_bvConstExprIndex = getEM()->registerSubclass(sizeof(BVConstExpr)); // Cache constants 0bin0 and 0bin1 vector bits(1); bits[0]=false; d_bvZero = newBVConstExpr(bits); bits[0]=true; d_bvOne = newBVConstExpr(bits); // Instantiate the rules after all expression creation is // registered, since the constructor creates some bit-vector // expressions. d_rules = createProofRules(); } // Destructor: delete the proof rules class if it's present TheoryBitvector::~TheoryBitvector() { if(d_rules != NULL) delete d_rules; } // Main theory API void TheoryBitvector::addSharedTerm(const Expr& e) { } /*Modified by Lorenzo PLatania*/ // solvable fact (e.g. solvable equations) are added to d_eq CDList, // all the others have to be in a different CDList. If the equation is // solvable it comes here already solved. Should distinguish between // solved and not solved eqs void TheoryBitvector::assertFact(const Theorem& e) { const Expr& expr = e.getExpr(); TRACE("bvAssertFact", "TheoryBitvector::assertFact(", e.getExpr().toString(), ")"); // cout<<"TheoryBitvector::assertFact, expr: "<contradictionRule(tpThm, e)); return; } DebugAssert(expr[0].isEq(), "Unexpected negation"); d_bitblast.push_back(e); break; case EQ: // Updates are also ignored: // Note: this can only be true if this fact was asserted as a result of // assertEqualities. For BV theory, this should only be possible if // the update was made from our own theory, so we can ignore it. if (theoryCore()->inUpdate()) return; // If we have already started bitblasting, just store the eq in d_bitblast; // if we haven't yet bitblasted and expr is a solved linear equation then // we store it in d_eq CDList, otherwise we store it in d_eqPending if (d_bb_index != 0) { d_bitblast.push_back(e); } else if (isLeaf(expr[0]) && !isLeafIn(expr[0], expr[1])) { d_eq.push_back( e ); } else { d_eqPending.push_back( e ); } break; default: // if the fact is not an equation it will be bit-blasted d_bitblast.push_back( e ); break; } } //TODO: can we get rid of this in exchange for a more general politeness-based sharing mechanism? void TheoryBitvector::assertTypePred(const Expr& e, const Theorem& pred) { // Ignore bitvector constants (they always satisfy type predicates) // and bitvector operators. When rewrites and updates are enabled. // their type predicates will be implicitly derived from the type // predicates of the arguments. if (theoryOf(e) == this) return; TRACE("bvAssertTypePred", "TheoryBitvector::assertTypePred(", e.toString(PRESENTATION_LANG), ")"); addSharedTerm(e); } /*Beginning of Lorenzo PLatania's methods*/ // evaluates the gcd of two integers using // Euclid algorithm // int TheoryBitvector::gcd(int c1, int c2) // { // if(c2==0) // return c1; // else // return gcd( c2, c1%c2); // } void TheoryBitvector::extract_vars(const Expr& e, vector& result) { if (e.getOpKind() == BVMULT ) { extract_vars(e[0], result); extract_vars(e[1], result); } else { DebugAssert(e.getOpKind() != BVCONST && e.getOpKind() != BVUMINUS && e.getOpKind() != BVPLUS, "Unexpected structure"); result.push_back(e); } } Expr TheoryBitvector::multiply_coeff( Rational mult_inv, const Expr& e) { // nothing to be done if( mult_inv == 1) return e; if(e.isEq()) { Expr lhs = e[0]; Expr rhs = e[1]; Expr new_lhs = multiply_coeff( mult_inv, lhs); Expr new_rhs = multiply_coeff( mult_inv, rhs); Expr res(EQ, new_lhs, new_rhs); return res; } else { int kind = e.getOpKind(); int size = BVSize(e); if( kind == BVMULT ) { //lhs is like 'a_0*x_0' Rational new_coeff = mult_inv * computeBVConst( e[0] ); Expr new_expr_coeff = newBVConstExpr( new_coeff, size); Expr BV_one = newBVConstExpr(1,size); if( new_expr_coeff == BV_one ) { return e[1]; } else { return newBVMultExpr( size, new_expr_coeff, e[1]); } } else if( kind == BVPLUS) { int expr_arity= e.arity(); std::vector tmp_list; for( int i = 0; i < expr_arity; ++i) { tmp_list.push_back(multiply_coeff( mult_inv, e[i])); } // Expr::iterator i = e.begin(); // int index; // Expr::iterator end = e.end(); // std::vector tmp_list; // for( i = e.begin(), index=0; i!=end; ++i, ++index) // { // tmp_list.push_back(multiply_coeff( mult_inv, *i)); // } return newBVPlusExpr(size, tmp_list); } else if( kind == BVCONST ) { Rational new_const = mult_inv * computeBVConst(e); Expr res = newBVConstExpr( new_const, size); // cout< list) // { // int res = 0; // int i; // int size = list.size(); // for(i = 0; i < size; ++i) // { // cout<<"list["<list[i]) // res=i; // cout<<"res: "< mydeque; // // set some values (from 1 to 10) // for (i=1; i<=10; i++) mydeque.push_back(i); // // erase the 6th element // mydeque.erase (mydeque.begin()+5); // // erase the first 3 elements: // mydeque.erase (mydeque.begin(),mydeque.begin()+3); // cout << "mydeque contains:"; // for (i=0; i instead of std::deque // int TheoryBitvector::gcd(std::deque coeff_list) // { // cout<<"TheoryBitvector::gcd: begin\n"; // for(unsigned int i=0; i0) // { // min_index = min(coeff_list); // int min_coeff_2 = coeff_list[min_index]; // cout<<"erasing element: "< newChildrenThm; vector changed; Theorem thm0; for (int k = 0; k < ar; ++k) { thm0 = find(lhs[k]); if (thm0.getLHS() != thm0.getRHS()) { newChildrenThm.push_back(thm0); changed.push_back(k); } } if(changed.size() > 0) { // lhs = updated_lhs thm0 = substitutivityRule(lhs, changed, newChildrenThm); // lhs = updated_and_rewritten_lhs thm0 = transitivityRule(thm0, rewrite(thm0.getRHS())); // updated_and_rewritten_lhs = rhs thm2 = transitivityRule(symmetryRule(thm0), thm); } } // updated_and_rewritten_lhs = find(rhs) thm2 = transitivityRule(thm2, find(rhs)); // canonized EQ thm2 = iffMP(thm2, d_rules->canonBVEQ(thm2.getExpr(), maxEffort)); if (thm2.isRewrite() && thm2.getRHS() == lhs && thm2.getLHS() == rhs) { thm2 = thm; } return thm2; } Theorem TheoryBitvector::generalBitBlast( const Theorem& thm ) { // cout<<"TheoryBitvector::generalBitBlast, thm: "< newChildrenThm; vector changed; Theorem thm0; for (int k = 0; k < ar; ++k) { thm0 = find(e[k]); if (thm0.getLHS() != thm0.getRHS()) { newChildrenThm.push_back(thm0); changed.push_back(k); } } if(changed.size() > 0) { // updated_e thm0 = iffMP(thm, substitutivityRule(e, changed, newChildrenThm)); // updated_and_rewritten_e thm0 = iffMP(thm0, rewrite(thm0.getExpr())); if (thm0.getExpr().getOpKind() != e.getOpKind()) return thm0; return iffMP(thm0, bitBlastIneqn(thm0.getExpr())); } return iffMP(thm, bitBlastIneqn(e)); } // a NOT should mean a disequality, as negation of inequalities // can be expressed as other inequalities. case NOT: { // Carefully simplify DebugAssert(e.arity() == 1, "Expected arity 1"); DebugAssert(e[0].isEq(), "Expected disequality"); DebugAssert(e[0].arity() == 2, "Expected arity 2"); vector newChildrenThm; vector changed; Theorem thm0; for (int k = 0; k < 2; ++k) { thm0 = find(e[0][k]); if (thm0.getLHS() != thm0.getRHS()) { newChildrenThm.push_back(thm0); changed.push_back(k); } } if(changed.size() > 0) { // a = b <=> a' = b' thm0 = substitutivityRule(e[0], changed, newChildrenThm); } else thm0 = reflexivityRule(e[0]); // a = b <=> canonized EQ thm0 = transitivityRule(thm0, d_rules->canonBVEQ(thm0.getRHS(), 6)); // NOT(canonized EQ) thm0 = iffMP(thm, substitutivityRule(e, thm0)); if (thm0.getExpr()[0].isEq()) { return bitBlastDisEqn(thm0); } else return thm0; } default: FatalAssert(false, "TheoryBitvector::generalBitBlast: unknown expression kind"); break; } return reflexivityRule( e ); } /*End of Lorenzo PLatania's methods*/ static Expr findAtom(const Expr& e) { if (e.isAbsAtomicFormula()) return e; for (int i = 0; i < e.arity(); ++i) { Expr e_i = findAtom(e[i]); if (!e_i.isNull()) return e_i; } return Expr(); } bool TheoryBitvector::comparebv(const Expr& e1, const Expr& e2) { int size = BVSize(e1); FatalAssert(size == BVSize(e2), "expected same size"); Theorem c1, c2; int idx1 = -1; vector thms1; if (d_bb_index == 0) { Expr splitter = e1.eqExpr(e2); Theorem thm = simplify(splitter); if (!thm.getRHS().isBoolConst()) { addSplitter(e1.eqExpr(e2)); return true; } // Store a dummy theorem to indicate bitblasting has begun d_bb_index = 1; d_bitblast.push_back(getCommonRules()->trueTheorem()); } for (int i = 0; i < size; ++i) { c1 = bitBlastTerm(e1, i); c1 = transitivityRule(c1, simplify(c1.getRHS())); c2 = bitBlastTerm(e2, i); c2 = transitivityRule(c2, simplify(c2.getRHS())); thms1.push_back(c1); if (!c1.getRHS().isBoolConst()) { if (idx1 == -1) idx1 = i; continue; } if (!c2.getRHS().isBoolConst()) { continue; } if (c1.getRHS() != c2.getRHS()) return false; } if (idx1 == -1) { // If e1 is known to be a constant, assert that DebugAssert(e1.getKind() != BVCONST, "Expected non-const"); assertEqualities(d_rules->bitExtractAllToConstEq(thms1)); addSplitter(e1.eqExpr(e2)); // enqueueFact(getCommonRules()->trueTheorem()); return true; } Theorem thm = bitBlastEqn(e1.eqExpr(e2)); thm = iffMP(thm, simplify(thm.getExpr())); if (!thm.getExpr().isTrue()) { enqueueFact(thm); return true; } // Nothing to assert from bitblasted equation. Best way to resolve this // problem is to split until the term can be equated with a bitvector // constant. Expr e = findAtom(thms1[idx1].getRHS()); DebugAssert(!e.isNull(), "Expected atom"); addSplitter(e); return true; } static bool bvdump = false; void TheoryBitvector::checkSat(bool fullEffort) { if(fullEffort) { for (unsigned i = 0; i < additionalRewriteConstraints.size(); i ++) enqueueFact(additionalRewriteConstraints[i]); additionalRewriteConstraints.clear(); if (bvdump) { CDList::const_iterator it_list=d_eq.begin(); unsigned int i; for(i=0; itrueTheorem()); } for( ; d_eq_index < eq_list_size; d_eq_index = d_eq_index + 1) { Theorem bb_result = generalBitBlast( d_eqPending[ d_eq_index ]); enqueueFact( bb_result); } // If newly bitblasted formulas, skip the shared term check return; } } } Theorem TheoryBitvector::rewrite(const Expr& e) { ExprMap cache; return rewriteBV(e, cache); } Theorem TheoryBitvector::rewriteAtomic(const Expr& e) { return reflexivityRule(e); } void TheoryBitvector::setup(const Expr& e) { int k(0), ar(e.arity()); if( e.isTerm() ) { for ( ; k < ar; ++k) { e[k].addToNotify(this, e); } } } // Lorenzo's version void TheoryBitvector::update(const Theorem& e, const Expr& d) { if (inconsistent()) return; // cout<<"TheoryBitvector::update, theorem e:"<::iterator it = d_sharedSubterms.find(rhs); if (it == d_sharedSubterms.end()) { addSharedTerm(rhs); } return; } // { // // found an equality between shared subterms! // bool changed = false; // if ((*it).second != lhs) { // lhs = (*it).second; // it = d_sharedSubterms.find(lhs); // DebugAssert(it != d_sharedSubterms.end() && (*it).second == lhs, // "Invariant violated in TheoryBitvector::update"); // changed = true; // } // if ((*it2).second != rhs) { // rhs = (*it2).second; // it2 = d_sharedSubterms.find(rhs); // DebugAssert(it2 != d_sharedSubterms.end() && (*it2).second == rhs, // "Invariant violated in TheoryBitvector::update"); // changed = true; // } // DebugAssert(findExpr(lhs) == e.getRHS() && // findExpr(rhs) == e.getRHS(), "Unexpected value for finds"); // // It may be needed to check whether the two terms are the // // same, in that case don't do anything // if (changed) { // Theorem thm = transitivityRule(find(lhs),symmetryRule(find(rhs))); // const Expr& expr = thm.getExpr(); // if (d_bb_index == 0 && // isLeaf(expr[0]) && !isLeafIn(expr[0], expr[1])) { // d_eq.push_back( thm ); // } // else { // d_bitblast.push_back( thm ); // } // } // // canonize and solve befor asserting it // // cout<<"TheoryBitvector::update, thm.getRHS(): "< 0) { vector newChildrenThm; vector changed; Theorem thm; for (int k = 0; k < ar; ++k) { thm = updateSubterms(e[k]); if (thm.getLHS() != thm.getRHS()) { newChildrenThm.push_back(thm); changed.push_back(k); } } if(changed.size() > 0) { thm = substitutivityRule(e, changed, newChildrenThm); thm = transitivityRule(thm, rewrite(thm.getRHS())); return transitivityRule(thm, find(thm.getRHS())); } else return find(e); } return find(e); } Theorem TheoryBitvector::solve(const Theorem& t) { DebugAssert(t.isRewrite() && t.getLHS().isTerm(), ""); Expr e = t.getExpr(); if (isLeaf(e[0]) && !isLeafIn(e[0], e[1])) { // already solved return t; } else if (isLeaf(e[1]) && !isLeafIn(e[1], e[0])) { return symmetryRule(t); } else if (e[0].getOpKind() == EXTRACT && isLeaf(e[0][0])) { bool solvedForm; Theorem thm; if (d_rules->solveExtractOverlapApplies(e)) { thm = iffMP(t, d_rules->solveExtractOverlap(e)); solvedForm = true; } else thm = d_rules->processExtract(t, solvedForm); thm = getCommonRules()->skolemize(thm); if (solvedForm) return thm; else { enqueueFact(getCommonRules()->andElim(thm, 1)); return getCommonRules()->andElim(thm, 0); } } else if (e[1].getOpKind() == EXTRACT && isLeaf(e[1][0])) { bool solvedForm; Theorem thm = getCommonRules()->skolemize(d_rules->processExtract(symmetryRule(t), solvedForm)); if (solvedForm) return thm; else { enqueueFact(getCommonRules()->andElim(thm, 1)); return getCommonRules()->andElim(thm, 0); } } IF_DEBUG( Theorem t2 = iffMP(t, d_rules->canonBVEQ(e)); if (e[0] < e[1]) { DebugAssert(e[1].getOpKind() == BVCONST, "Should be only case when lhs < rhs"); t2 = symmetryRule(t2); } DebugAssert(t2.getExpr() == e, "Expected no change"); ) if (e[0].getOpKind() == BVCONST) { DebugAssert(e[1].getOpKind() != BVCONST, "should not have const = const"); return symmetryRule(t); } return t; } // // solving just linear equations; for everything else I just return // // the same expression // if( ! e.isEq()) // { // return reflexivityRule( e ); // } // //the search for the odd coefficient should also check that the // //multiplied term does not appear in other terms. The coefficient can // //also multiply a non-linear term // // L:: look for a odd coefficient, if one, then the eq is solvable // // and we can find the mult-inverse using Barrett-Dill-Levitt // Expr lhs = e[0]; // Expr::iterator it = lhs.begin(), iend = lhs.end(); // for (; it != iend; ++it) { // switch ((*it).getOpKind()) { // case BVCONST: continue; // case BVMULT: { // DebugAssert((*it).arity() == 2 && // (*it)[0].getOpKind() == BVCONST && // computeBVConst((*it)[0]) != 1, "Unexpected format"); // continue // } // coefficient = Odd_coeff( e ); // // Rational odd_coeff = anyOdd( coeff ); // if( coefficient != 0) // { // // the equation is solvable // cout<<"Odd coefficient found => the equation is solvable\n"; // if (coefficient != 1) { // Rational mult_inv = multiplicative_inverse( coefficient, BVSize(e[0])); // // multiply all the coefficients in the expression by the inverse // // Expr tmp_expr = e; // e = multiply_coeff( mult_inv, e); // // Expr isolated_expr = isolate_var( new_expr); // } // Theorem solved_th = d_rules->isolate_var( t, e); // cout<<"solved theorem: "< the equation is not solvable\n"; // Theorem thm = d_rules->MarkNonSolvableEq( e ); // cout<<"TheoryBitvector::solve, input e: "<getKindName(e.getOpKind())); } } Cardinality TheoryBitvector::finiteTypeInfo(Expr& e, Unsigned& n, bool enumerate, bool computeSize) { FatalAssert(e.getKind() == BITVECTOR, "Unexpected kind in TheoryBitvector::finiteTypeInfo"); if (enumerate || computeSize) { int bitwidth = getBitvectorTypeParam(e); Rational max_val = pow( bitwidth, (Rational) 2); if (enumerate) { if (n < max_val.getUnsigned()) { e = newBVConstExpr(n, bitwidth); } else e = Expr(); } if (computeSize) { n = max_val.getUnsignedMP(); } } return CARD_FINITE; } void TheoryBitvector::computeType(const Expr& e) { if (e.isApply()) { switch(e.getOpKind()) { case BOOLEXTRACT: { if(!(1 == e.arity() && BITVECTOR == getBaseType(e[0]).getExpr().getOpKind())) throw TypecheckException("Type Checking error:"\ "attempted extraction from non-bitvector \n"+ e.toString()); int extractLength = getBoolExtractIndex(e); if(!(0 <= extractLength)) throw TypecheckException("Type Checking error: \n" "attempted out of range extraction \n"+ e.toString()); e.setType(boolType()); break; } case BVMULT:{ if(!(2 == e.arity() && BITVECTOR == getBaseType(e[0]).getExpr().getOpKind() && BITVECTOR == getBaseType(e[1]).getExpr().getOpKind())) throw TypecheckException ("Not a bit-vector expression in BVMULT:\n\n " +e.toString()); int bvLen = getBVMultParam(e); Type bvType = newBitvectorType(bvLen); e.setType(bvType); break; } case EXTRACT:{ if(!(1 == e.arity() && BITVECTOR == getBaseType(e[0]).getExpr().getOpKind())) throw TypecheckException ("Not a bit-vector expression in bit-vector extraction:\n\n " + e.toString()); int bvLength = BVSize(e[0]); int leftExtract = getExtractHi(e); int rightExtract = getExtractLow(e); if(!(0 <= rightExtract && rightExtract <= leftExtract && leftExtract < bvLength)) throw TypecheckException ("Wrong bounds in bit-vector extract:\n\n "+e.toString()); int extractLength = leftExtract - rightExtract + 1; Type bvType = newBitvectorType(extractLength); e.setType(bvType); break; } case BVPLUS: { int bvPlusLength = getBVPlusParam(e); if(!(0 <= bvPlusLength)) throw TypecheckException ("Bad bit-vector length specified in BVPLUS expression:\n\n " + e.toString()); for(Expr::iterator i=e.begin(), iend=e.end(); i != iend; ++i) { if(BITVECTOR != getBaseType(*i).getExpr().getOpKind()) throw TypecheckException ("Not a bit-vector expression in BVPLUS:\n\n "+e.toString()); } Type bvType = newBitvectorType(bvPlusLength); e.setType(bvType); break; } case LEFTSHIFT: { if(!(1 == e.arity() && BITVECTOR == getBaseType(e[0]).getExpr().getOpKind())) throw TypecheckException ("Not a bit-vector expression in bit-vector shift:\n\n " +e.toString()); int bvLength = BVSize(e[0]); int shiftLength = getFixedLeftShiftParam(e); if(!(shiftLength >= 0)) throw TypecheckException("Bad shift value in bit-vector shift:\n\n " +e.toString()); int newLength = bvLength + shiftLength; Type bvType = newBitvectorType(newLength); e.setType(bvType); break; } case CONST_WIDTH_LEFTSHIFT: { if(!(1 == e.arity() && BITVECTOR == getBaseType(e[0]).getExpr().getOpKind())) throw TypecheckException ("Not a bit-vector expression in bit-vector shift:\n\n " +e.toString()); int bvLength = BVSize(e[0]); int shiftLength = getFixedLeftShiftParam(e); if(!(shiftLength >= 0)) throw TypecheckException("Bad shift value in bit-vector shift:\n\n " +e.toString()); Type bvType = newBitvectorType(bvLength); e.setType(bvType); break; } case RIGHTSHIFT: { if(!(1 == e.arity() && BITVECTOR == getBaseType(e[0]).getExpr().getOpKind())) throw TypecheckException ("Not a bit-vector expression in bit-vector shift:\n\n " +e.toString()); int bvLength = BVSize(e[0]); int shiftLength = getFixedRightShiftParam(e); if(!(shiftLength >= 0)) throw TypecheckException("Bad shift value in bit-vector shift:\n\n " +e.toString()); //int newLength = bvLength + shiftLength; Type bvType = newBitvectorType(bvLength); e.setType(bvType); break; } case BVTYPEPRED: e.setType(boolType()); break; case SX: { if(!(1 == e.arity() && BITVECTOR == getBaseType(e[0]).getExpr().getOpKind())) throw TypecheckException("Type Checking error:"\ "non-bitvector \n"+ e.toString()); int bvLength = getSXIndex(e); if(!(1 <= bvLength)) throw TypecheckException("Type Checking error: \n" "out of range\n"+ e.toString()); Type bvType = newBitvectorType(bvLength); e.setType(bvType); break; } case BVREPEAT: { if(!(1 == e.arity() && BITVECTOR == getBaseType(e[0]).getExpr().getOpKind())) throw TypecheckException("Type Checking error:"\ "non-bitvector \n"+ e.toString()); int bvLength = getBVIndex(e) * BVSize(e[0]); if(!(1 <= bvLength)) throw TypecheckException("Type Checking error: \n" "out of range\n"+ e.toString()); Type bvType = newBitvectorType(bvLength); e.setType(bvType); break; } case BVZEROEXTEND: { if(!(1 == e.arity() && BITVECTOR == getBaseType(e[0]).getExpr().getOpKind())) throw TypecheckException("Type Checking error:"\ "non-bitvector \n"+ e.toString()); int bvLength = getBVIndex(e) + BVSize(e[0]); if(!(1 <= bvLength)) throw TypecheckException("Type Checking error: \n" "out of range\n"+ e.toString()); Type bvType = newBitvectorType(bvLength); e.setType(bvType); break; } case BVROTL: case BVROTR: { if(!(1 == e.arity() && BITVECTOR == getBaseType(e[0]).getExpr().getOpKind())) throw TypecheckException("Type Checking error:"\ "non-bitvector \n"+ e.toString()); e.setType(getBaseType(e[0])); break; } default: FatalAssert(false, "TheoryBitvector::computeType: unexpected kind in application" + int2string(e.getOpKind())); break; } } else { switch(e.getKind()) { case BOOLEXTRACT: case BVMULT: case EXTRACT: case BVPLUS: case LEFTSHIFT: case CONST_WIDTH_LEFTSHIFT: case RIGHTSHIFT: case BVTYPEPRED: case SX: case BVREPEAT: case BVZEROEXTEND: case BVROTL: case BVROTR: // These operators are handled above when applied to arguments, here we // are dealing with the operators themselves which are polymorphic, so // don't assign them a specific type. e.setType(Type::anyType(getEM())); break; case BVCONST: { Type bvType = newBitvectorType(getBVConstSize(e)); e.setType(bvType); break; } case CONCAT: { if(e.arity() < 2) throw TypecheckException ("Concatenation must have at least 2 bit-vectors:\n\n "+e.toString()); // Compute the total length of concatenation int bvLength(0); for(int i=0, iend=e.arity(); i ", e.getType(), " }"); } void TheoryBitvector::computeModelTerm(const Expr& e, std::vector& v) { switch(e.getOpKind()) { case BVPLUS: case BVSUB: case BVUMINUS: case BVMULT: case LEFTSHIFT: case CONST_WIDTH_LEFTSHIFT: case RIGHTSHIFT: case BVOR: case BVAND: case BVXOR: case BVXNOR: case BVNAND: case BVNOR: case BVNEG: case CONCAT: case EXTRACT: case BVSLT: case BVSLE: case BVSGT: case BVSGE: case BVLT: case BVLE: case BVGT: case BVGE: for(Expr::iterator i=e.begin(), iend=e.end(); i!=iend; ++i) // getModelTerm(*i, v); v.push_back(*i); return; case BVCONST: // No model variables here return; default: break; // It's a variable; continue processing } Type tp(e.getType()); switch(tp.getExpr().getOpKind()) { case BITVECTOR: { int n = getBitvectorTypeParam(tp); for(int i=0; i& v) { switch(e.getOpKind()) { case BVPLUS: case BVSUB: case BVUMINUS: case BVMULT: case LEFTSHIFT: case CONST_WIDTH_LEFTSHIFT: case RIGHTSHIFT: case BVOR: case BVAND: case BVXOR: case BVXNOR: case BVNAND: case BVNOR: case BVNEG: case CONCAT: case EXTRACT: case SX: case BVSLT: case BVSLE: case BVSGT: case BVSGE: case BVLT: case BVLE: case BVGT: case BVGE: { // More primitive vars are kids, and they should have been // assigned concrete values assignValue(simplify(e)); v.push_back(e); return; } case BVCONST: // No model variables here return; default: break; // It's a variable; continue processing } Type tp(e.getType()); switch(tp.getExpr().getOpKind()) { case BITVECTOR: { const Rational& n = getBitvectorTypeParam(tp); vector bits; // FIXME: generate concrete assignment from bits using proof // rules. For now, just create a new assignment. for(int i=0; i 0, "expected arity > 0 in BVPLUS"); int length = getBVPlusParam(e); int i; for( i = 0; i < e.arity(); ++i ) { if( (i + 1) == e.arity() ) { os << pad(length, e[i]); } else { os << "(bvadd" << space << push << pad(length, e[i]) << space << push; } } for( --i; i != 0; --i ) os << push << ")"; } break; case BVSUB: os << "(bvsub" << space << push << e[0] << space << push << e[1] << push << ")"; break; case BVMULT: { int length = getBVMultParam(e); os << "(bvmul" << space << push << pad(length, e[0]) << space << push << pad(length, e[1]) << push << ")"; break; } case BVUDIV: os << "(bvudiv" << space << push << e[0] << space << push << e[1] << push << ")"; break; case BVSDIV: os << "(bvsdiv" << space << push << e[0] << space << push << e[1] << push << ")"; break; case BVUREM: os << "(bvurem" << space << push << e[0] << space << push << e[1] << push << ")"; break; case BVSREM: os << "(bvsrem" << space << push << e[0] << space << push << e[1] << push << ")"; break; case BVSMOD: os << "(bvsmod" << space << push << e[0] << space << push << e[1] << push << ")"; break; case BVLT: os << "(bvult" << space << push << e[0] << space << push << e[1] << push << ")"; break; case BVLE: os << "(bvule" << space << push << e[0] << space << push << e[1] << push << ")"; break; case BVGT: os << "(bvugt" << space << push << e[0] << space << push << e[1] << push << ")"; break; case BVGE: os << "(bvuge" << space << push << e[0] << space << push << e[1] << push << ")"; break; case BVSLT: os << "(bvslt" << space << push << e[0] << space << push << e[1] << push << ")"; break; case BVSLE: os << "(bvsle" << space << push << e[0] << space << push << e[1] << push << ")"; break; case BVSGT: os << "(bvsgt" << space << push << e[0] << space << push << e[1] << push << ")"; break; case BVSGE: os << "(bvsge" << space << push << e[0] << space << push << e[1] << push << ")"; break; case INTTOBV: throw SmtlibException( "TheoryBitvector::print: INTTOBV, SMTLIB not supported"); break; case BVTOINT: throw SmtlibException( "TheoryBitvector::print: BVTOINT, SMTLIB not supported"); break; case BVTYPEPRED: throw SmtlibException( "TheoryBitvector::print: BVTYPEPRED, SMTLIB not supported"); if( e.isApply() ) { os << "BVTYPEPRED[" << push << e.getOp().getExpr() << push << "," << pop << space << e[0] << push << "]"; } else e.printAST(os); break; default: FatalAssert(false, "Unknown BV kind"); e.printAST(os); break; } return os; } ExprStream& TheoryBitvector::print(ExprStream& os, const Expr& e) { switch(os.lang()) { case PRESENTATION_LANG: switch(e.getOpKind()) { case BITVECTOR: //printing type expression os << "BITVECTOR(" << push << getBitvectorTypeParam(e) << push << ")"; break; case BVCONST: { std::ostringstream ss; ss << "0bin"; for(int i=(int)getBVConstSize(e)-1; i>=0; --i) ss << (getBVConstValue(e, i) ? "1" : "0"); os << ss.str(); break; } case CONCAT: if(e.arity() <= 1) e.printAST(os); else { os << "(" << push; bool first(true); for(Expr::iterator i=e.begin(), iend=e.end(); i!=iend; ++i) { if(first) first=false; else os << space << "@" << space; os << (*i); } os << push << ")"; } break; case EXTRACT: os << "(" << push << e[0] << push << ")" << pop << pop << "[" << push << getExtractHi(e) << ":"; os << getExtractLow(e) << push << "]"; break; case BOOLEXTRACT: os << "BOOLEXTRACT(" << push << e[0] << "," << getBoolExtractIndex(e) << push << ")"; break; case LEFTSHIFT: os << "(" << push << e[0] << space << "<<" << space << getFixedLeftShiftParam(e) << push << ")"; break; case CONST_WIDTH_LEFTSHIFT: os << "(" << push << e[0] << space << "<<" << space << getFixedLeftShiftParam(e) << push << ")"; os << "[" << push << BVSize(e)-1 << ":0]"; break; case RIGHTSHIFT: os << "(" << push << e[0] << space << ">>" << space << getFixedRightShiftParam(e) << push << ")"; break; case BVSHL: os << "BVSHL(" << push << e[0] << "," << e[1] << push << ")"; break; case BVLSHR: os << "BVLSHR(" << push << e[0] << "," << e[1] << push << ")"; break; case BVASHR: os << "BVASHR(" << push << e[0] << "," << e[1] << push << ")"; break; case BVZEROEXTEND: os << "BVZEROEXTEND(" << push << e[0] << "," << getBVIndex(e) << push << ")"; break; case BVREPEAT: os << "BVREPEAT(" << push << e[0] << "," << getBVIndex(e) << push << ")"; break; case BVROTL: os << "BVROTL(" << push << e[0] << "," << getBVIndex(e) << push << ")"; break; case BVROTR: os << "BVROTR(" << push << e[0] << "," << getBVIndex(e) << push << ")"; break; case SX: os << "SX(" << push << e[0] << "," << push << getSXIndex(e) << ")"; break; case BVAND: if(e.arity() <= 1) e.printAST(os); else { os << "(" << push; bool first(true); for(Expr::iterator i=e.begin(), iend=e.end(); i!=iend; ++i) { if(first) first=false; else os << space << "&" << space; os << (*i); } os << push << ")"; } break; case BVOR: if(e.arity() <= 1) e.printAST(os); else { os << "(" << push; bool first(true); for(Expr::iterator i=e.begin(), iend=e.end(); i!=iend; ++i) { if(first) first=false; else os << space << "|" << space; os << (*i); } os << push << ")"; } break; case BVXOR: DebugAssert(e.arity() > 0, "TheoryBitvector::print: BVXOR arity <= 0"); if (e.arity() == 1) os << e[0]; else { int i; for(i = 0; i < e.arity(); ++i) { if ((i+1) == e.arity()) { os << e[i]; } else { os << "BVXOR(" << push << e[i] << "," << push; } } for (--i; i != 0; --i) os << push << ")"; } break; case BVXNOR: DebugAssert(e.arity() > 0, "TheoryBitvector::print: BVXNOR arity <= 0"); if (e.arity() == 1) os << e[0]; else { int i; for(i = 0; i < e.arity(); ++i) { if ((i+1) == e.arity()) { os << e[i]; } else { os << "BVXNOR(" << push << e[i] << "," << push; } } for (--i; i != 0; --i) os << push << ")"; } break; case BVNEG: os << "(~(" << push << e[0] << push << "))"; break; case BVNAND: os << "BVNAND(" << push << e[0] << "," << e[1] << push << ")"; break; case BVNOR: os << "BVNAND(" << push << e[0] << "," << e[1] << push << ")"; break; case BVCOMP: os << "BVCOMP(" << push << e[0] << "," << e[1] << push << ")"; break; case BVUMINUS: os << "BVUMINUS(" << push << e[0] << push << ")"; break; case BVPLUS: os << "BVPLUS(" << push << getBVPlusParam(e); for(Expr::iterator i=e.begin(), iend=e.end(); i!=iend; ++i) { os << push << "," << pop << space << (*i); } os << push << ")"; break; case BVSUB: os << "BVSUB(" << push << BVSize(e) << "," << e[0] << "," << e[1] << push << ")"; break; case BVMULT: os << "BVMULT(" << push << getBVMultParam(e) << "," << e[0] << "," << e[1]<= 0, "Expected non-negative integer"); os << push << "bv" << r << "[" << BVSize(e) << "]"; break; } case EXTRACT: os << push << "(extract[" << getExtractHi(e) << ":" << getExtractLow(e) << "]"; os << space << push << e[0] << push << ")"; break; case BOOLEXTRACT: os << "(=" << space << push << "(extract[" << getBoolExtractIndex(e) << ":" << getBoolExtractIndex(e) << "]"; os << space << push << e[0] << push << ")" << space << "bit1" << push << ")"; break; case LEFTSHIFT: { int bvLength = getFixedLeftShiftParam(e); if( bvLength != 0 ) { os << "(concat" << space << push << e[0] << space; os << push << "bv0[" << bvLength << "]" << push << ")"; break; } // else fall-through } case CONST_WIDTH_LEFTSHIFT: os << "(bvshl" << space << push << e[0] << space << push << "bv" << getFixedLeftShiftParam(e) << "[" << BVSize(e[0]) << "]" << push << ")"; break; case RIGHTSHIFT: os << "(bvlshr" << space << push << e[0] << space << push << "bv" << getFixedRightShiftParam(e) << "[" << BVSize(e[0]) << "]" << push << ")"; break; case SX: { int extend = getSXIndex(e) - BVSize(e[0]); if( extend == 0 ) os << e[0]; else if( extend < 0 ) throw SmtlibException( "TheoryBitvector::print: SX: extension is shorter than argument"); else os << "(sign_extend[" << extend << "]" << space << push << e[0] << push << ")"; break; } case BVREPEAT: os << "(repeat[" << getBVIndex(e) << "]" << space << push << e[0] << push << ")"; break; case BVZEROEXTEND: { int extend = getBVIndex(e); if( extend == 0 ) os << e[0]; else if( extend < 0 ) throw SmtlibException( "TheoryBitvector::print: ZEROEXTEND: extension is less than zero"); else os << "(zero_extend[" << extend << "]" << space << push << e[0] << push << ")"; break; } case BVROTL: os << "(rotate_left[" << getBVIndex(e) << "]" << space << push << e[0] << push << ")"; break; case BVROTR: os << "(rotate_right[" << getBVIndex(e) << "]" << space << push << e[0] << push << ")"; break; default: printSmtLibShared(os,e); } break; case SMTLIB_V2_LANG: switch(e.getOpKind()) { case BITVECTOR: //printing type expression os << push << "(_" << space << "BitVec" << space << getBitvectorTypeParam(e) << ")" << pop; break; case BVCONST: { Rational r = computeBVConst(e); DebugAssert(r.isInteger() && r >= 0, "Expected non-negative integer"); os << push << "(_ bv" << r << space << BVSize(e) << ")"; break; } case EXTRACT: os << push << "((_ extract" << space << getExtractHi(e) << space << getExtractLow(e) << ")"; os << space << push << e[0] << push << ")"; break; case BOOLEXTRACT: os << "(=" << space << push << "((_ extract" << getBoolExtractIndex(e) << space << getBoolExtractIndex(e) << ")"; os << space << push << e[0] << push << ")" << space << "#b1" << push << ")"; break; case LEFTSHIFT: { int bvLength = getFixedLeftShiftParam(e); if( bvLength != 0 ) { os << "(concat" << space << push << e[0] << space; os << push << "#b"; for (int i = 0; i < bvLength; ++i) os << "0"; os << push << ")"; break; } // else fall-through } case CONST_WIDTH_LEFTSHIFT: os << "(bvshl" << space << push << e[0] << space << push; os << newBVConstExpr(getFixedLeftShiftParam(e), BVSize(e[0])) << push << ")"; break; case RIGHTSHIFT: os << "(bvlshr" << space << push << e[0] << space << push; os << newBVConstExpr(getFixedRightShiftParam(e), BVSize(e[0])) << push << ")"; break; case SX: { int extend = getSXIndex(e) - BVSize(e[0]); if( extend == 0 ) os << e[0]; else if( extend < 0 ) throw SmtlibException( "TheoryBitvector::print: SX: extension is shorter than argument"); else os << "((_ sign_extend" << space << extend << ")" << space << push << e[0] << push << ")"; break; } case BVREPEAT: os << "((_ repeat" << space << getBVIndex(e) << ")" << space << push << e[0] << push << ")"; break; case BVZEROEXTEND: { int extend = getBVIndex(e); if( extend == 0 ) os << e[0]; else if( extend < 0 ) throw SmtlibException( "TheoryBitvector::print: ZEROEXTEND: extension is less than zero"); else os << "((_ zero_extend" << space << extend << ")" << space << push << e[0] << push << ")"; break; } case BVROTL: os << "((_ rotate_left" << space << getBVIndex(e) << ")" << space << push << e[0] << push << ")"; break; case BVROTR: os << "((_ rotate_right" << space << getBVIndex(e) << ")" << space << push << e[0] << push << ")"; break; default: printSmtLibShared(os,e); } break; default: switch(e.getOpKind()) { case BVCONST: { os << "0bin"; for(int i=(int)getBVConstSize(e)-1; i>=0; --i) os << (getBVConstValue(e, i) ? "1" : "0"); break; } default: e.printAST(os); break; } } return os; } /////////////////////////////////////////////////////////////////////////////// //parseExprOp: //translating special Exprs to regular EXPR?? /////////////////////////////////////////////////////////////////////////////// Expr TheoryBitvector::parseExprOp(const Expr& e) { d_theoryUsed = true; TRACE("parser", "TheoryBitvector::parseExprOp(", e, ")"); // If the expression is not a list, it must have been already // parsed, so just return it as is. if(RAW_LIST != e.getKind()) return e; if(!(e.arity() > 0)) throw ParserException("TheoryBitvector::parseExprOp: wrong input:\n\n" +e.toString()); const Expr& c1 = e[0][0]; int kind = getEM()->getKind(c1.getString()); switch(kind) { case BITVECTOR: if(!(e.arity() == 2)) throw ParserException("TheoryBitvector::parseExprOp: BITVECTOR" "kind should have exactly 1 arg:\n\n" + e.toString()); if(!(e[1].isRational() && e[1].getRational().isInteger())) throw ParserException("BITVECTOR TYPE must have an integer constant" "as its first argument:\n\n" +e.toString()); if(!(e[1].getRational().getInt() >=0 )) throw ParserException("parameter must be an integer constant >= 0.\n" +e.toString()); return newBitvectorTypeExpr(e[1].getRational().getInt()); break; case BVCONST: if(!(e.arity() == 2 || e.arity() == 3)) throw ParserException("TheoryBitvector::parseExprOp: BVCONST " "kind should have 1 or 2 args:\n\n" + e.toString()); if(!(e[1].isRational() || e[1].isString())) throw ParserException("TheoryBitvector::parseExprOp: BVCONST " "kind should have arg of type Rational " "or String:\n\n" + e.toString()); if(e[1].isRational()) { // ("BVCONST" value [bitwidth]) if(e.arity()==3) { if(!e[2].isRational() || !e[2].getRational().isInteger()) throw ParserException("TheoryBitvector::parseExprOp: BVCONST " "2nd argument must be an integer:\n\n" +e.toString()); return newBVConstExpr(e[1].getRational(), e[2].getRational().getInt()); } else return newBVConstExpr(e[1].getRational()); } else if(e[1].isString()) { // ("BVCONST" string [base]) if(e.arity() == 3) { if(!e[2].isRational() || !e[2].getRational().isInteger()) throw ParserException("TheoryBitvector::parseExprOp: BVCONST " "2nd argument must be an integer:\n\n" +e.toString()); return newBVConstExpr(e[1].getString(), e[2].getRational().getInt()); } else return newBVConstExpr(e[1].getString()); } break; case CONCAT: { if(!(e.arity() >= 3)) throw ParserException("TheoryBitvector::parseExprOp: CONCAT" "kind should have at least 2 args:\n\n" + e.toString()); vector kids; Expr::iterator i=e.begin(), iend=e.end(); DebugAssert(i!=iend, "TheoryBitvector::parseExprOp("+e.toString()+")"); ++i; // Skip the first element - the operator name for(; i!=iend; ++i) kids.push_back(parseExpr(*i)); return newConcatExpr(kids); break; } case EXTRACT: { if(!(e.arity() == 4)) throw ParserException("TheoryBitvector::parseExprOp: EXTRACT" "kind should have exactly 3 arg:\n\n" + e.toString()); if(!e[1].isRational() || !e[1].getRational().isInteger()) throw ParserException("EXTRACT must have an integer constant as its " "1st argument:\n\n" +e.toString()); if(!e[2].isRational() || !e[2].getRational().isInteger()) throw ParserException("EXTRACT must have an integer constant as its " "2nd argument:\n\n" +e.toString()); int hi = e[1].getRational().getInt(); int lo = e[2].getRational().getInt(); if(!(hi >= lo && lo >=0)) throw ParserException("parameter must be an integer constant >= 0.\n" +e.toString()); // Check for extract of left shift Expr arg = e[3]; if (lo == 0 && arg.getKind() == RAW_LIST && arg[0].getKind() == ID && getEM()->getKind(arg[0][0].getString()) == LEFTSHIFT) { if(!(arg.arity() == 3)) throw ParserException("TheoryBitvector::parseExprOp: LEFTSHIFT" "kind should have exactly 2 arg:\n\n" + arg.toString()); if(!arg[2].isRational() || !arg[2].getRational().isInteger()) throw ParserException("LEFTSHIFT must have an integer constant as its " "2nd argument:\n\n" +arg.toString()); if(!(arg[2].getRational().getInt() >=0 )) throw ParserException("parameter must be an integer constant >= 0.\n" +arg.toString()); Expr ls_arg = parseExpr(arg[1]); if (BVSize(ls_arg) == hi + 1) { return newFixedConstWidthLeftShiftExpr(ls_arg, arg[2].getRational().getInt()); } } return newBVExtractExpr(parseExpr(arg), hi, lo); break; } case BOOLEXTRACT: if(!(e.arity() == 3)) throw ParserException("TheoryBitvector::parseExprOp: BOOLEXTRACT" "kind should have exactly 2 arg:\n\n" + e.toString()); if(!e[2].isRational() || !e[2].getRational().isInteger()) throw ParserException("BOOLEXTRACT must have an integer constant as its" " 2nd argument:\n\n" +e.toString()); if(!(e[2].getRational().getInt() >=0 )) throw ParserException("parameter must be an integer constant >= 0.\n" +e.toString()); return newBoolExtractExpr(parseExpr(e[1]), e[2].getRational().getInt()); break; case LEFTSHIFT: if(!(e.arity() == 3)) throw ParserException("TheoryBitvector::parseExprOp: LEFTSHIFT" "kind should have exactly 2 arg:\n\n" + e.toString()); if(!e[2].isRational() || !e[2].getRational().isInteger()) throw ParserException("LEFTSHIFT must have an integer constant as its " "2nd argument:\n\n" +e.toString()); if(!(e[2].getRational().getInt() >=0 )) throw ParserException("parameter must be an integer constant >= 0.\n" +e.toString()); return newFixedLeftShiftExpr(parseExpr(e[1]), e[2].getRational().getInt()); break; case CONST_WIDTH_LEFTSHIFT: if(!(e.arity() == 3)) throw ParserException("TheoryBitvector::parseExprOp: CONST_WIDTH_LEFTSHIFT" "kind should have exactly 2 arg:\n\n" + e.toString()); if(!e[2].isRational() || !e[2].getRational().isInteger()) throw ParserException("CONST_WIDTH_LEFTSHIFT must have an integer constant as its " "2nd argument:\n\n" +e.toString()); if(!(e[2].getRational().getInt() >=0 )) throw ParserException("parameter must be an integer constant >= 0.\n" +e.toString()); return newFixedConstWidthLeftShiftExpr(parseExpr(e[1]), e[2].getRational().getInt()); break; case RIGHTSHIFT: if(!(e.arity() == 3)) throw ParserException("TheoryBitvector::parseExprOp: RIGHTSHIFT" "kind should have exactly 2 arg:\n\n" + e.toString()); if(!e[2].isRational() || !e[2].getRational().isInteger()) throw ParserException("RIGHTSHIFT must have an integer constant as its " "2nd argument:\n\n" +e.toString()); if(!(e[2].getRational().getInt() >=0 )) throw ParserException("parameter must be an integer constant >= 0.\n" +e.toString()); return newFixedRightShiftExpr(parseExpr(e[1]), e[2].getRational().getInt()); break; // BVSHL, BVLSHR, BVASHR handled with arith operators below case SX: // smtlib format interprets the integer argument as the number of bits to // extend, while CVC format interprets it as the new total size. // The smtlib parser inserts an extra argument "_smtlib" for this operator // so that we can distinguish the two cases here. if (e.arity() == 4 && e[1].getKind() == ID && e[1][0].getString() == "_smtlib") { if(!e[2].isRational() || !e[2].getRational().isInteger()) throw ParserException("sign_extend must have an integer constant as its" " 1st argument:\n\n" +e.toString()); if(!(e[2].getRational().getInt() >=0 )) throw ParserException("sign_extend must have an integer constant as its" " 1st argument >= 0:\n\n" +e.toString()); Expr e3 = parseExpr(e[3]); return newSXExpr(e3, BVSize(e3) + e[2].getRational().getInt()); } if(!(e.arity() == 3)) throw ParserException("TheoryBitvector::parseExprOp: SX" "kind should have exactly 2 arg:\n\n" + e.toString()); if(!e[2].isRational() || !e[2].getRational().isInteger()) throw ParserException("SX must have an integer constant as its" " 2nd argument:\n\n" +e.toString()); if(!(e[2].getRational().getInt() >=0 )) throw ParserException("SX must have an integer constant as its" " 2nd argument >= 0:\n\n" +e.toString()); return newSXExpr(parseExpr(e[1]), e[2].getRational().getInt()); break; case BVROTL: case BVROTR: case BVREPEAT: case BVZEROEXTEND: if(!(e.arity() == 3)) throw ParserException("TheoryBitvector::parseExprOp:" "kind should have exactly 2 arg:\n\n" + e.toString()); if(!e[1].isRational() || !e[1].getRational().isInteger()) throw ParserException("BVIndexExpr must have an integer constant as its" " 1st argument:\n\n" +e.toString()); if (kind == BVREPEAT && !(e[1].getRational().getInt() >0 )) throw ParserException("BVREPEAT must have an integer constant as its" " 1st argument > 0:\n\n" +e.toString()); if(!(e[1].getRational().getInt() >=0 )) throw ParserException("BVIndexExpr must have an integer constant as its" " 1st argument >= 0:\n\n" +e.toString()); return newBVIndexExpr(kind, parseExpr(e[2]), e[1].getRational().getInt()); break; case BVAND: { if(!(e.arity() >= 3)) throw ParserException("TheoryBitvector::parseExprOp: BVAND " "kind should have at least 2 arg:\n\n" + e.toString()); vector kids; for(int i=1, iend=e.arity(); i= 3)) throw ParserException("TheoryBitvector::parseExprOp: BVOR " "kind should have at least 2 arg:\n\n" + e.toString()); vector kids; for(int i=1, iend=e.arity(); i k; Expr::iterator i = e.begin(), iend=e.end(); if (!e[1].isRational()) { int maxsize = 0; Expr child; // Parse the kids of e and push them into the vector 'k' for(++i; i!=iend; ++i) { child = parseExpr(*i); if (getBaseType(child).getExpr().getOpKind() != BITVECTOR) { throw ParserException("BVPLUS argument is not bitvector"); } if (BVSize(child) > maxsize) maxsize = BVSize(child); k.push_back(child); } if (e.arity() == 1) return k[0]; return newBVPlusPadExpr(maxsize, k); } else { if(!(e.arity() >= 4)) throw ParserException("Expected at least 3 args in BVPLUS:\n\n" +e.toString()); if(!e[1].isRational() || !e[1].getRational().isInteger()) throw ParserException ("Expected integer constant in BVPLUS:\n\n" +e.toString()); if(!(e[1].getRational().getInt() > 0)) throw ParserException("parameter must be an integer constant > 0.\n" +e.toString()); // Skip first two elements of the vector of kids in 'e'. // The first element is the kind, and the second is the // numOfBits of the bvplus operator. ++i;++i; Expr child; // Parse the kids of e and push them into the vector 'k' for(; i!=iend; ++i) { child = parseExpr(*i); if (getBaseType(child).getExpr().getOpKind() != BITVECTOR) { throw ParserException("BVPLUS argument is not bitvector"); } k.push_back(child); } return newBVPlusPadExpr(e[1].getRational().getInt(), k); } break; } case BVSUB: { if (e.arity() == 3) { Expr summand1 = parseExpr(e[1]); Expr summand2 = parseExpr(e[2]); if (getBaseType(summand1).getExpr().getOpKind() != BITVECTOR || getBaseType(summand2).getExpr().getOpKind() != BITVECTOR) { throw ParserException("BVSUB argument is not bitvector"); } if (BVSize(summand1) != BVSize(summand2)) { throw ParserException("BVSUB: expected same sized arguments" +e.toString()); } return newBVSubExpr(summand1, summand2); } else if (e.arity() != 4) throw ParserException("BVSUB: wrong number of arguments:\n\n" +e.toString()); if (!e[1].isRational() || !e[1].getRational().isInteger()) throw ParserException("BVSUB: expected an integer constant as " "first argument:\n\n" +e.toString()); if (!(e[1].getRational().getInt() > 0)) throw ParserException("parameter must be an integer constant > 0.\n" +e.toString()); int bvsublength = e[1].getRational().getInt(); Expr summand1 = parseExpr(e[2]); Expr summand2 = parseExpr(e[3]); if (getBaseType(summand1).getExpr().getOpKind() != BITVECTOR || getBaseType(summand2).getExpr().getOpKind() != BITVECTOR) { throw ParserException("BVSUB argument is not bitvector"); } summand1 = pad(bvsublength, summand1); summand2 = pad(bvsublength, summand2); return newBVSubExpr(summand1, summand2); break; } case BVMULT: { vector k; Expr::iterator i = e.begin(), iend=e.end(); if (!e[1].isRational()) { if (e.arity() != 3) { throw ParserException("TheoryBitvector::parseExprOp: BVMULT: " "expected exactly 2 args:\n\n" + e.toString()); } int maxsize = 0; Expr child; // Parse the kids of e and push them into the vector 'k' for(++i; i!=iend; ++i) { child = parseExpr(*i); if (getBaseType(child).getExpr().getOpKind() != BITVECTOR) { throw ParserException("BVMULT argument is not bitvector"); } if (BVSize(child) > maxsize) maxsize = BVSize(child); k.push_back(child); } if (e.arity() == 1) return k[0]; return newBVMultPadExpr(maxsize, k[0], k[1]); } if(!(e.arity() == 4)) throw ParserException("TheoryBitvector::parseExprOp: BVMULT: " "expected exactly 3 args:\n\n" + e.toString()); if(!e[1].isRational() || !e[1].getRational().isInteger()) throw ParserException("BVMULT: expected integer constant" "as first argument:\n\n" +e.toString()); if(!(e[1].getRational().getInt() > 0)) throw ParserException("parameter must be an integer constant > 0.\n" +e.toString()); Expr a = parseExpr(e[2]); Expr b = parseExpr(e[3]); if (getBaseType(a).getExpr().getOpKind() != BITVECTOR || getBaseType(b).getExpr().getOpKind() != BITVECTOR) { throw ParserException("BVMULT argument is not bitvector"); } return newBVMultPadExpr(e[1].getRational().getInt(),a,b); break; } case BVUDIV: case BVSDIV: case BVUREM: case BVSREM: case BVSMOD: case BVSHL: case BVASHR: case BVLSHR: { if(!(e.arity() == 3)) throw ParserException("TheoryBitvector::parseExprOp:" "kind should have exactly 2 args:\n\n" + e.toString()); Expr e1 = parseExpr(e[1]); Expr e2 = parseExpr(e[2]); if (e1.getType().getExpr().getOpKind() != BITVECTOR || e2.getType().getExpr().getOpKind() != BITVECTOR) throw ParserException("TheoryBitvector::parseExprOp:" "Expected bitvector arguments:\n\n" + e.toString()); if (BVSize(e1) != BVSize(e2)) throw ParserException("TheoryBitvector::parseExprOp:" "Expected bitvectors of same size:\n\n" + e.toString()); if (kind == BVSHL) { if (e2.getKind() == BVCONST) return newFixedConstWidthLeftShiftExpr(e1, computeBVConst(e2).getInt()); } else if (kind == BVLSHR) { if (e2.getKind() == BVCONST) return newFixedRightShiftExpr(e1, computeBVConst(e2).getInt()); } return Expr(kind, e1, e2); break; } case BVLT: if(!(e.arity() == 3)) throw ParserException("TheoryBitvector::parseExprOp: BVLT" "kind should have exactly 2 arg:\n\n" + e.toString()); return newBVLTExpr(parseExpr(e[1]),parseExpr(e[2])); break; case BVLE: if(!(e.arity() == 3)) throw ParserException("TheoryBitvector::parseExprOp: BVLE" "kind should have exactly 2 arg:\n\n" + e.toString()); return newBVLEExpr(parseExpr(e[1]),parseExpr(e[2])); break; case BVGT: if(!(e.arity() == 3)) throw ParserException("TheoryBitvector::parseExprOp: BVGT" "kind should have exactly 2 arg:\n\n" + e.toString()); return newBVLTExpr(parseExpr(e[2]),parseExpr(e[1])); break; case BVGE: if(!(e.arity() == 3)) throw ParserException("TheoryBitvector::parseExprOp: BVGE" "kind should have exactly 2 arg:\n\n" + e.toString()); return newBVLEExpr(parseExpr(e[2]),parseExpr(e[1])); break; case BVSLT: if(!(e.arity() == 3)) throw ParserException("TheoryBitvector::parseExprOp: BVLT" "kind should have exactly 2 arg:\n\n" + e.toString()); return newBVSLTExpr(parseExpr(e[1]),parseExpr(e[2])); break; case BVSLE: if(!(e.arity() == 3)) throw ParserException("TheoryBitvector::parseExprOp: BVLE" "kind should have exactly 2 arg:\n\n" + e.toString()); return newBVSLEExpr(parseExpr(e[1]),parseExpr(e[2])); break; case BVSGT: if(!(e.arity() == 3)) throw ParserException("TheoryBitvector::parseExprOp: BVGT" "kind should have exactly 2 arg:\n\n" + e.toString()); return newBVSLTExpr(parseExpr(e[2]),parseExpr(e[1])); break; case BVSGE: if(!(e.arity() == 3)) throw ParserException("TheoryBitvector::parseExprOp: BVGE" "kind should have exactly 2 arg:\n\n" + e.toString()); return newBVSLEExpr(parseExpr(e[2]),parseExpr(e[1])); break; case INTTOBV: throw ParserException("INTTOBV not implemented"); break; case BVTOINT: throw ParserException("BVTOINT not implemented"); break; case BVTYPEPRED: throw ParserException("BVTYPEPRED is used internally"); break; default: FatalAssert(false, "TheoryBitvector::parseExprOp: unrecognized input operator" +e.toString()); break; } return e; } /////////////////////////////////////////////////////////////////////////////// //helper functions /////////////////////////////////////////////////////////////////////////////// Expr TheoryBitvector::newBitvectorTypeExpr(int bvLength) { DebugAssert(bvLength > 0, "TheoryBitvector::newBitvectorTypeExpr:\n" "len of a BV must be a positive integer:\n bvlength = "+ int2string(bvLength)); if (bvLength > d_maxLength) d_maxLength = bvLength; return Expr(BITVECTOR, getEM()->newRatExpr(bvLength)); } Expr TheoryBitvector::newBitvectorTypePred(const Type& t, const Expr& e) { return Expr(Expr(BVTYPEPRED, t.getExpr()).mkOp(), e); } Expr TheoryBitvector::newBVAndExpr(const Expr& t1, const Expr& t2) { DebugAssert(BITVECTOR == t1.getType().getExpr().getOpKind() && BITVECTOR == t2.getType().getExpr().getOpKind(), "TheoryBitvector::newBVAndExpr:" "inputs must have type BITVECTOR:\n t1 = " + t1.toString() + "\n t2 = " +t2.toString()); DebugAssert(BVSize(t1) == BVSize(t2), "TheoryBitvector::bitwise operator" "inputs must have same length:\n t1 = " + t1.toString() + "\n t2 = " + t2.toString()); return Expr(CVC3::BVAND, t1, t2); } Expr TheoryBitvector::newBVAndExpr(const vector& kids) { DebugAssert(kids.size() >= 2, "TheoryBitvector::newBVAndExpr:" "# of subterms must be at least 2"); for(unsigned int i=0; i 0"); DebugAssert(len >=0, "TheoryBitvector::newBVIndexExpr:" "index must be a non-negative integer"+ int2string(len)); DebugAssert(BITVECTOR == t1.getType().getExpr().getOpKind(), "TheoryBitvector::newBVIndexExpr:" "inputs must have type BITVECTOR:\n t1 = " + t1.toString()); return Expr(Expr(kind, getEM()->newRatExpr(len)).mkOp(), t1); } Expr TheoryBitvector::newBVSLTExpr(const Expr& t1, const Expr& t2) { DebugAssert(BITVECTOR == t1.getType().getExpr().getOpKind() && BITVECTOR == t2.getType().getExpr().getOpKind(), "TheoryBitvector::newBVSLTExpr:" "inputs must have type BITVECTOR:\n t1 = " + t1.toString() + "\n t2 = " +t2.toString()); return Expr(CVC3::BVSLT, t1, t2); } Expr TheoryBitvector::newBVSLEExpr(const Expr& t1, const Expr& t2) { DebugAssert(BITVECTOR == t1.getType().getExpr().getOpKind() && BITVECTOR == t2.getType().getExpr().getOpKind(), "TheoryBitvector::newBVSLEExpr:" "inputs must have type BITVECTOR:\n t1 = " + t1.toString() + "\n t2 = " +t2.toString()); return Expr(CVC3::BVSLE, t1, t2); } Expr TheoryBitvector::newBVNegExpr(const Expr& t1) { DebugAssert(BITVECTOR == t1.getType().getExpr().getOpKind(), "TheoryBitvector::newBVNegExpr:" "inputs must have type BITVECTOR:\n t1 = " + t1.toString()); return Expr(CVC3::BVNEG, t1); } Expr TheoryBitvector::newBVUminusExpr(const Expr& t1) { DebugAssert(BITVECTOR == t1.getType().getExpr().getOpKind(), "TheoryBitvector::newBVNegExpr:" "inputs must have type BITVECTOR:\n t1 = " + t1.toString()); return Expr(CVC3::BVUMINUS, t1); } Expr TheoryBitvector::newBoolExtractExpr(const Expr& t1, int index) { DebugAssert(index >=0, " TheoryBitvector::newBoolExtractExpr:" "bool_extract index must be a non-negative integer"+ int2string(index)); DebugAssert(BITVECTOR == t1.getType().getExpr().getOpKind(), "TheoryBitvector::newBVBoolExtractExpr:" "inputs must have type BITVECTOR:\n t1 = " + t1.toString()); return Expr(Expr(BOOLEXTRACT, getEM()->newRatExpr(index)).mkOp(), t1); } Expr TheoryBitvector::newFixedLeftShiftExpr(const Expr& t1, int shiftLength) { DebugAssert(shiftLength >=0, " TheoryBitvector::newFixedleftshift:" "fixed_shift index must be a non-negative integer"+ int2string(shiftLength)); DebugAssert(BITVECTOR == t1.getType().getExpr().getOpKind(), "TheoryBitvector::newBVFixedleftshiftExpr:" "inputs must have type BITVECTOR:\n t1 = " + t1.toString()); return Expr(Expr(LEFTSHIFT, getEM()->newRatExpr(shiftLength)).mkOp(), t1); } Expr TheoryBitvector::newFixedConstWidthLeftShiftExpr(const Expr& t1, int shiftLength) { DebugAssert(shiftLength >=0, " TheoryBitvector::newFixedConstWidthLeftShift:" "fixed_shift index must be a non-negative integer"+ int2string(shiftLength)); DebugAssert(BITVECTOR == t1.getType().getExpr().getOpKind(), "TheoryBitvector::newBVFixedleftshiftExpr:" "inputs must have type BITVECTOR:\n t1 = " + t1.toString()); return Expr(Expr(CONST_WIDTH_LEFTSHIFT, getEM()->newRatExpr(shiftLength)).mkOp(), t1); } Expr TheoryBitvector::newFixedRightShiftExpr(const Expr& t1, int shiftLength) { DebugAssert(shiftLength >=0, " TheoryBitvector::newFixedRightShift:" "fixed_shift index must be a non-negative integer"+ int2string(shiftLength)); DebugAssert(BITVECTOR == t1.getType().getExpr().getOpKind(), "TheoryBitvector::newBVFixedRightShiftExpr:" "inputs must have type BITVECTOR:\n t1 = " + t1.toString()); if(shiftLength==0) return t1; return Expr(Expr(RIGHTSHIFT, getEM()->newRatExpr(shiftLength)).mkOp(), t1); } Expr TheoryBitvector::newConcatExpr(const Expr& t1, const Expr& t2) { DebugAssert(BITVECTOR == t1.getType().getExpr().getOpKind() && BITVECTOR == t2.getType().getExpr().getOpKind(), "TheoryBitvector::newBVConcatExpr:" "inputs must have type BITVECTOR:\n t1 = " + t1.toString() + "\n t2 = " +t2.toString()); return Expr(CONCAT, t1, t2); } Expr TheoryBitvector::newConcatExpr(const Expr& t1, const Expr& t2, const Expr& t3) { DebugAssert(BITVECTOR == t1.getType().getExpr().getOpKind() && BITVECTOR == t2.getType().getExpr().getOpKind() && BITVECTOR == t3.getType().getExpr().getOpKind(), "TheoryBitvector::newBVConcatExpr:" "inputs must have type BITVECTOR:\n t1 = " + t1.toString() + "\n t2 = " +t2.toString() + "\n t3 =" + t3.toString()); return Expr(CONCAT, t1, t2, t3); } Expr TheoryBitvector::newConcatExpr(const vector& kids) { DebugAssert(kids.size() >= 2, "TheoryBitvector::newBVConcatExpr:" "# of subterms must be at least 2"); for(unsigned int i=0; i 0: bvLength = " + int2string(bvLength)); DebugAssert(BITVECTOR == t1.getType().getExpr().getOpKind() && BITVECTOR == t2.getType().getExpr().getOpKind(), "TheoryBitvector::newBVmultExpr:" "inputs must have type BITVECTOR:\n t1 = " + t1.toString() + "\n t2 = " +t2.toString()); DebugAssert(bvLength == BVSize(t1) && bvLength == BVSize(t2), "Expected same length"); return Expr(Expr(BVMULT, getEM()->newRatExpr(bvLength)).mkOp(), t1, t2); } Expr TheoryBitvector::newBVMultExpr(int bvLength, const vector& kids) { DebugAssert(bvLength > 0, "TheoryBitvector::newBVmultExpr:" "bvLength must be an integer > 0: bvLength = " + int2string(bvLength)); for(unsigned int i=0; inewRatExpr(bvLength)).mkOp(), kids); } Expr TheoryBitvector::newBVMultPadExpr(int bvLength, const vector& kids) { vector newKids; for (unsigned i = 0; i < kids.size(); ++i) { newKids.push_back(pad(bvLength, kids[i])); } return newBVMultExpr(bvLength, newKids); } Expr TheoryBitvector::newBVMultPadExpr(int bvLength, const Expr& t1, const Expr& t2) { return newBVMultExpr(bvLength, pad(bvLength, t1), pad(bvLength, t2)); } Expr TheoryBitvector::newBVUDivExpr(const Expr& t1, const Expr& t2) { DebugAssert(BITVECTOR == t1.getType().getExpr().getOpKind() && BITVECTOR == t2.getType().getExpr().getOpKind(), "TheoryBitvector::newBVUDivExpr:" "inputs must have type BITVECTOR:\n t1 = " + t1.toString() + "\n t2 = " +t2.toString()); DebugAssert(BVSize(t2) == BVSize(t1), "Expected same length"); return Expr(BVUDIV, t1, t2); } Expr TheoryBitvector::newBVURemExpr(const Expr& t1, const Expr& t2) { DebugAssert(BITVECTOR == t1.getType().getExpr().getOpKind() && BITVECTOR == t2.getType().getExpr().getOpKind(), "TheoryBitvector::newBVURemExpr:" "inputs must have type BITVECTOR:\n t1 = " + t1.toString() + "\n t2 = " +t2.toString()); DebugAssert(BVSize(t2) == BVSize(t1), "Expected same length"); return Expr(BVUREM, t1, t2); } Expr TheoryBitvector::newBVSDivExpr(const Expr& t1, const Expr& t2) { DebugAssert(BITVECTOR == t1.getType().getExpr().getOpKind() && BITVECTOR == t2.getType().getExpr().getOpKind(), "TheoryBitvector::newBVSDivExpr:" "inputs must have type BITVECTOR:\n t1 = " + t1.toString() + "\n t2 = " +t2.toString()); DebugAssert(BVSize(t1) == BVSize(t2), "Expected same length"); return Expr(BVSDIV, t1, t2); } Expr TheoryBitvector::newBVSRemExpr(const Expr& t1, const Expr& t2) { DebugAssert(BITVECTOR == t1.getType().getExpr().getOpKind() && BITVECTOR == t2.getType().getExpr().getOpKind(), "TheoryBitvector::newBVSRemExpr:" "inputs must have type BITVECTOR:\n t1 = " + t1.toString() + "\n t2 = " +t2.toString()); DebugAssert(BVSize(t1) == BVSize(t2), "Expected same length"); return Expr(BVSREM, t1, t2); } Expr TheoryBitvector::newBVSModExpr(const Expr& t1, const Expr& t2) { DebugAssert(BITVECTOR == t1.getType().getExpr().getOpKind() && BITVECTOR == t2.getType().getExpr().getOpKind(), "TheoryBitvector::newBVSModExpr:" "inputs must have type BITVECTOR:\n t1 = " + t1.toString() + "\n t2 = " +t2.toString()); DebugAssert(BVSize(t1) == BVSize(t2), "Expected same length"); return Expr(BVSMOD, t1, t2); } //! produces a string of 0's of length bvLength Expr TheoryBitvector::newBVZeroString(int bvLength) { DebugAssert(bvLength > 0, "TheoryBitvector::newBVZeroString:must be >= 0: " + int2string(bvLength)); std::vector bits; for(int count=0; count < bvLength; count++) { bits.push_back(false); } return newBVConstExpr(bits); } //! produces a string of 1's of length bvLength Expr TheoryBitvector::newBVOneString(int bvLength) { DebugAssert(bvLength > 0, "TheoryBitvector::newBVOneString:must be >= 0: " + int2string(bvLength)); std::vector bits; for(int count=0; count < bvLength; count++) { bits.push_back(true); } return newBVConstExpr(bits); } Expr TheoryBitvector::newBVConstExpr(const vector& bits) { DebugAssert(bits.size() > 0, "TheoryBitvector::newBVConstExpr:" "size of bits should be > 0"); BVConstExpr bv(getEM(), bits, d_bvConstExprIndex); return getEM()->newExpr(&bv); } Expr TheoryBitvector::newBVConstExpr(const Rational& r, int bvLength) { DebugAssert(r.isInteger(), "TheoryBitvector::newBVConstExpr: not an integer: " + r.toString()); DebugAssert(bvLength > 0, "TheoryBitvector::newBVConstExpr: bvLength = " + int2string(bvLength)); string s(r.toString(2)); size_t strsize = s.size(); size_t length = bvLength; Expr res; if(length > 0 && length != strsize) { //either (length > strsize) or (length < strsize) if(length < strsize) { s = s.substr((strsize-length), length); } else { string zeros(""); for(size_t i=0, pad=length-strsize; i < pad; ++i) zeros += "0"; s = zeros+s; } res = newBVConstExpr(s, 2); } else res = newBVConstExpr(s, 2); return res; } Expr TheoryBitvector::newBVConstExpr(const std::string& s, int base) { DebugAssert(s.size() > 0, "TheoryBitvector::newBVConstExpr:" "# of subterms must be at least 2"); DebugAssert(base == 2 || base == 16, "TheoryBitvector::newBVConstExpr: base = " +int2string(base)); //hexadecimal std::string str = s; if(16 == base) { Rational r(str, 16); return newBVConstExpr(r, str.size()*4); } else { BVConstExpr bv(getEM(), str, d_bvConstExprIndex); return getEM()->newExpr(&bv); } } Expr TheoryBitvector:: newBVExtractExpr(const Expr& e, int hi, int low) { DebugAssert(low>=0 && hi>=low, " TheoryBitvector::newBVExtractExpr: " "bad bv_extract indices: hi = " + int2string(hi) + ", low = " + int2string(low)); if (e.getOpKind() == LEFTSHIFT && hi == BVSize(e[0])-1 && low == 0) { return newFixedConstWidthLeftShiftExpr(e[0], getFixedLeftShiftParam(e)); } DebugAssert(BITVECTOR == e.getType().getExpr().getOpKind(), "TheoryBitvector::newBVExtractExpr:" "inputs must have type BITVECTOR:\n e = " + e.toString()); return Expr(Expr(EXTRACT, getEM()->newRatExpr(hi), getEM()->newRatExpr(low)).mkOp(), e); } Expr TheoryBitvector::newBVSubExpr(const Expr& t1, const Expr& t2) { DebugAssert(BITVECTOR == t1.getType().getExpr().getOpKind() && BITVECTOR == t2.getType().getExpr().getOpKind(), "TheoryBitvector::newBVSubExpr:" "inputs must have type BITVECTOR:\n t1 = " + t1.toString() + "\n t2 = " +t2.toString()); DebugAssert(BVSize(t1) == BVSize(t2), "TheoryBitvector::newBVSubExpr" "inputs must have same length:\n t1 = " + t1.toString() + "\n t2 = " + t2.toString()); return Expr(BVSUB, t1, t2); } Expr TheoryBitvector::newBVPlusExpr(int bvLength, const Expr& k1, const Expr& k2) { DebugAssert(bvLength > 0, " TheoryBitvector::newBVPlusExpr:" "bvplus length must be a positive integer: "+ int2string(bvLength)); DebugAssert(BITVECTOR == k1.getType().getExpr().getOpKind(), "TheoryBitvector::newBVPlusExpr:" "inputs must have type BITVECTOR:\n t1 = " + k1.toString()); DebugAssert(BVSize(k1) == bvLength, "Expected matching sizes"); DebugAssert(BITVECTOR == k2.getType().getExpr().getOpKind(), "TheoryBitvector::newBVPlusExpr:" "inputs must have type BITVECTOR:\n t1 = " + k2.toString()); DebugAssert(BVSize(k2) == bvLength, "Expected matching sizes"); return Expr(Expr(BVPLUS, getEM()->newRatExpr(bvLength)).mkOp(), k1, k2); } Expr TheoryBitvector::newBVPlusExpr(int bvLength, const vector& k) { DebugAssert(bvLength > 0, " TheoryBitvector::newBVPlusExpr:" "bvplus length must be a positive integer: "+ int2string(bvLength)); DebugAssert(k.size() > 1, " TheoryBitvector::newBVPlusExpr:" " size of input vector must be greater than 0: "); for(unsigned int i=0; inewRatExpr(bvLength)).mkOp(), k); } Expr TheoryBitvector::newBVPlusPadExpr(int bvLength, const vector& k) { vector newKids; for (unsigned i = 0; i < k.size(); ++i) { newKids.push_back(pad(bvLength, k[i])); } return newBVPlusExpr(bvLength, newKids); } // Accessors for expression parameters int TheoryBitvector::getBitvectorTypeParam(const Expr& e) { DebugAssert(BITVECTOR == e.getKind(), "TheoryBitvector::getBitvectorTypeParam: wrong kind: " + e.toString()); return e[0].getRational().getInt(); } Type TheoryBitvector::getTypePredType(const Expr& tp) { DebugAssert(tp.getOpKind()==BVTYPEPRED && tp.isApply(), "TheoryBitvector::getTypePredType:\n tp = "+tp.toString()); return Type(tp.getOpExpr()[0]); } const Expr& TheoryBitvector::getTypePredExpr(const Expr& tp) { DebugAssert(tp.getOpKind()==BVTYPEPRED, "TheoryBitvector::getTypePredType:\n tp = "+tp.toString()); return tp[0]; } int TheoryBitvector::getBoolExtractIndex(const Expr& e) { DebugAssert(BOOLEXTRACT == e.getOpKind() && e.isApply(), "TheoryBitvector::getBoolExtractIndex: wrong kind" + e.toString()); return e.getOpExpr()[0].getRational().getInt(); } int TheoryBitvector::getSXIndex(const Expr& e) { DebugAssert(SX == e.getOpKind() && e.isApply(), "TheoryBitvector::getSXIndex: wrong kind\n"+e.toString()); return e.getOpExpr()[0].getRational().getInt(); } int TheoryBitvector::getBVIndex(const Expr& e) { DebugAssert(e.isApply() && (e.getOpKind() == BVREPEAT || e.getOpKind() == BVROTL || e.getOpKind() == BVROTR || e.getOpKind() == BVZEROEXTEND), "TheoryBitvector::getBVIndex: wrong kind\n"+e.toString()); return e.getOpExpr()[0].getRational().getInt(); } int TheoryBitvector::getFixedLeftShiftParam(const Expr& e) { DebugAssert(e.isApply() && (LEFTSHIFT == e.getOpKind() || CONST_WIDTH_LEFTSHIFT == e.getOpKind()), "TheoryBitvector::getFixedLeftShiftParam: wrong kind" + e.toString()); return e.getOpExpr()[0].getRational().getInt(); } int TheoryBitvector::getFixedRightShiftParam(const Expr& e) { DebugAssert(RIGHTSHIFT == e.getOpKind() && e.isApply(), "TheoryBitvector::getFixedRightShiftParam: wrong kind" + e.toString()); return e.getOpExpr()[0].getRational().getInt(); } int TheoryBitvector::getExtractLow(const Expr& e) { DebugAssert(EXTRACT == e.getOpKind() && e.isApply(), "TheoryBitvector::getExtractLow: wrong kind" + e.toString()); return e.getOpExpr()[1].getRational().getInt(); } int TheoryBitvector::getExtractHi(const Expr& e) { DebugAssert(EXTRACT == e.getOpKind() && e.isApply(), "TheoryBitvector::getExtractHi: wrong kind" + e.toString()); return e.getOpExpr()[0].getRational().getInt(); } int TheoryBitvector::getBVPlusParam(const Expr& e) { DebugAssert(BVPLUS == e.getOpKind() && e.isApply(), "TheoryBitvector::getBVPlusParam: wrong kind" + e.toString(AST_LANG)); return e.getOpExpr()[0].getRational().getInt(); } int TheoryBitvector::getBVMultParam(const Expr& e) { DebugAssert(BVMULT == e.getOpKind() && e.isApply(), "TheoryBitvector::getBVMultParam: wrong kind " + e.toString(AST_LANG)); return e.getOpExpr()[0].getRational().getInt(); } unsigned TheoryBitvector::getBVConstSize(const Expr& e) { DebugAssert(BVCONST == e.getKind(), "getBVConstSize called on non-bvconst"); const BVConstExpr* bvc = dynamic_cast(e.getExprValue()); DebugAssert(bvc, "getBVConstSize: cast failed"); return bvc->size(); } bool TheoryBitvector::getBVConstValue(const Expr& e, int i) { DebugAssert(BVCONST == e.getKind(), "getBVConstSize called on non-bvconst"); const BVConstExpr* bvc = dynamic_cast(e.getExprValue()); DebugAssert(bvc, "getBVConstSize: cast failed"); return bvc->getValue(i); } // as newBVConstExpr can not give the BV expr of a negative rational, // I use this wrapper to do that Expr TheoryBitvector::signed_newBVConstExpr( Rational c, int bv_size) { if( c > 0) return newBVConstExpr( c, bv_size); else { c = -c; Expr tmp = newBVConstExpr( c, bv_size); Rational neg_tmp = computeNegBVConst( tmp ); return newBVConstExpr( neg_tmp, bv_size ); } } // Computes the integer value of a bitvector constant Rational TheoryBitvector::computeBVConst(const Expr& e) { DebugAssert(BVCONST == e.getKind(), "TheoryBitvector::computeBVConst:" "input must be a BITVECTOR CONST: " + e.toString()); if(*d_bv32Flag) { int c(0); for(int j=(int)getBVConstSize(e)-1; j>=0; j--) c = 2*c + getBVConstValue(e, j) ? 1 : 0; Rational d(c); return d; } else { Rational c(0); for(int j=(int)getBVConstSize(e)-1; j>=0; j--) c = 2*c + (getBVConstValue(e, j) ? Rational(1) : Rational(0)); return c; } } // Computes the integer value of ~c+1 Rational TheoryBitvector::computeNegBVConst(const Expr& e) { DebugAssert(BVCONST == e.getKind(), "TheoryBitvector::computeBVConst:" "input must be a BITVECTOR CONST: " + e.toString()); if(*d_bv32Flag) { int c(0); for(int j=(int)getBVConstSize(e)-1; j>=0; j--) c = 2*c + getBVConstValue(e, j) ? 0 : 1; Rational d(c+1); return d; } else { Rational c(0); for(int j=(int)getBVConstSize(e)-1; j>=0; j--) c = 2*c + (getBVConstValue(e, j) ? Rational(0) : Rational(1)); return c+1; } } ////////////////////////////////////////////////////////////////////// // class BVConstExpr methods ///////////////////////////////////////////////////////////////////// //! Constructor BVConstExpr::BVConstExpr(ExprManager* em, std::string bvconst, size_t mmIndex, ExprIndex idx) : ExprValue(em, BVCONST, idx), d_MMIndex(mmIndex) { std::string::reverse_iterator i = bvconst.rbegin(); std::string::reverse_iterator iend = bvconst.rend(); DebugAssert(bvconst.size() > 0, "TheoryBitvector::newBVConstExpr:" "# of subterms must be at least 2"); for(;i != iend; ++i) { TRACE("bitvector", "BVConstExpr: bit ", *i, ""); if('0' == *i) d_bvconst.push_back(false); else { if('1' == *i) d_bvconst.push_back(true); else DebugAssert(false, "BVConstExpr: bad binary bit-vector: " + bvconst); } } TRACE("bitvector", "BVConstExpr: #bits ", d_bvconst.size(), ""); } BVConstExpr::BVConstExpr(ExprManager* em, std::vector bvconst, size_t mmIndex, ExprIndex idx) : ExprValue(em, BVCONST, idx), d_bvconst(bvconst), d_MMIndex(mmIndex) { TRACE("bitvector", "BVConstExpr(vector): arg. size = ", bvconst.size(), ", d_bvconst.size = "+int2string(d_bvconst.size())); } size_t BVConstExpr::computeHash() const { std::vector::const_iterator i = d_bvconst.begin(); std::vector::const_iterator iend = d_bvconst.end(); size_t hash_value = 0; hash_value = ExprValue::hash(BVCONST); for (;i != iend; i++) if(*i) hash_value = PRIME*hash_value + HASH_VALUE_ONE; else hash_value = PRIME*hash_value + HASH_VALUE_ZERO; return hash_value; } Expr TheoryBitvector::computeTCC(const Expr& e) { // inline recursive computation for deeply nested bitvector Exprs vector operatorStack; vector operandStack; vector childStack; Expr e2, tcc; operatorStack.push_back(e); childStack.push_back(0); while (!operatorStack.empty()) { DebugAssert(operatorStack.size() == childStack.size(), "Invariant violated"); if (childStack.back() < operatorStack.back().arity()) { e2 = operatorStack.back()[childStack.back()++]; if (e2.isVar()) { operandStack.push_back(trueExpr()); } else { ExprMap::iterator itccCache = theoryCore()->tccCache().find(e2); if (itccCache != theoryCore()->tccCache().end()) { operandStack.push_back((*itccCache).second); } else if (theoryOf(e2) == this) { if (e2.arity() == 0) { operandStack.push_back(trueExpr()); } else { operatorStack.push_back(e2); childStack.push_back(0); } } else { operandStack.push_back(getTCC(e2)); } } } else { e2 = operatorStack.back(); operatorStack.pop_back(); childStack.pop_back(); vector children; vector::iterator childStart = operandStack.end() - (e2.arity()); children.insert(children.begin(), childStart, operandStack.end()); operandStack.erase(childStart, operandStack.end()); tcc = (children.size() == 0) ? trueExpr() : (children.size() == 1) ? children[0] : getCommonRules()->rewriteAnd(andExpr(children)).getRHS(); switch(e2.getKind()) { case BVUDIV: case BVSDIV: case BVUREM: case BVSREM: case BVSMOD: { DebugAssert(e2.arity() == 2, ""); int size = BVSize(e2); tcc = getCommonRules()->rewriteAnd(tcc.andExpr(!(e2[1].eqExpr(newBVZeroString(size))))).getRHS(); break; } default: break; } operandStack.push_back(tcc); theoryCore()->tccCache()[e2] = tcc; } } DebugAssert(childStack.empty(), "Invariant violated"); DebugAssert(operandStack.size() == 1, "Expected single operand left"); return operandStack.back(); } cvc3-2.4.1/src/context/0000775000175400017540000000000011630011320014514 5ustar mdetersmdeterscvc3-2.4.1/src/context/Makefile0000664000175400017540000000041410533133647016175 0ustar mdetersmdeters################################################## # About this Makefile # # This Makefile depends on Makefile.opts ################################################## MODULE = context SRC = context.cpp cdflags.cpp LIBRARY=libcontext.a include ../../Makefile.local cvc3-2.4.1/src/context/context.cpp0000664000175400017540000002467011167727100016734 0ustar mdetersmdeters/*****************************************************************************/ /*! * \file context.cpp * * Author: Clark Barrett * * Created: Fri Jan 17 14:30:37 2003 * *
* * License to use, copy, modify, sell and/or distribute this software * and its documentation for any purpose is hereby granted without * royalty, subject to the terms and conditions defined in the \ref * LICENSE file provided with this distribution. * *
* */ /*****************************************************************************/ #include "context.h" using namespace CVC3; using namespace std; vector ContextMemoryManager::s_freePages; /////////////////////////////////////////////////////////////////////////////// // Scope methods // /////////////////////////////////////////////////////////////////////////////// void Scope::finalize(void) { ContextObjChain* obj = d_restoreChain; while (obj != NULL) { ContextObjChain* tmp = obj->d_restoreChainNext; // When called from ~ContextManager(), the master objects may // still point to this scope. Disconnect them here. if (obj->d_master != NULL) { if (obj->d_master->d_scope == this) obj->d_master->d_scope = NULL; if (obj->d_master->d_restore == obj) obj->d_master->d_restore = NULL; } obj = tmp; } } void Scope::check(void) { IF_DEBUG( ContextObjChain* obj = d_restoreChain; if (debugger.trace("memory") && obj != NULL) { ostream& os = debugger.getOS(); int n(0); ContextObjChain* tmp = obj; while(tmp != NULL) { tmp = tmp->d_restoreChainNext; n++; } os << "*** Warning: ~Scope(): found "<< n << " leaked objects " << "in scope " << d_level << ":" << endl; if (debugger.flag("memory leaks")) { tmp = obj; while(tmp != NULL) { os << tmp->name() << "\n"; tmp = tmp->d_restoreChainNext; } } os << flush; } ) } unsigned long Scope::getMemory(int verbosity) { unsigned long memSelf = 0; // scope is allocated in cmm unsigned long mem = 0; mem += getCMM()->getMemory(verbosity - 1); if (d_prevScope != NULL) { mem += d_prevScope->getMemory(verbosity - 1); } // TODO: d_restoreChain? if (verbosity > 0) { cout << "Scope " << d_level << ": " << memSelf << endl; cout << " Children: " << mem << endl; cout << " Total: " << mem+memSelf << endl; } return mem + memSelf; } /////////////////////////////////////////////////////////////////////////////// // ContextObjChain methods // /////////////////////////////////////////////////////////////////////////////// ContextObjChain* ContextObjChain::restore(void) { // Assign 'next' pointer only when the master object is restored, // since this may change our next pointer (master may have other // context objects removed). DebugAssert(d_master != NULL, "How did this happen"); // if (d_master == NULL) return d_restoreChainNext; ContextObjChain* next; DebugAssert(d_data != NULL, "Shouldn't happen"); // if (d_data == NULL) { // d_master->setNull(); // d_master->d_scope = d_master->d_scope->prevScope(); // DebugAssert(d_restore==NULL,"Expected NULL"); // next = d_restoreChainNext; // d_master->d_scope->addToChain(this); // } // else { d_master->restoreData(d_data); d_master->d_scope = d_data->d_scope; d_master->d_restore = d_restore; next = d_restoreChainNext; if (d_data != NULL) delete d_data; DebugAssert(d_master->d_restore != this, "points to self"); // } return next; } #ifdef _CVC3_DEBUG_MODE std::string ContextObjChain::name() const { DebugAssert(d_master != NULL, "NULL master"); return d_master->name(); } #endif /////////////////////////////////////////////////////////////////////////////// // ContextObj methods // /////////////////////////////////////////////////////////////////////////////// void ContextObj::update(int scope) { Scope* tmpScope = d_scope; DebugAssert(scope < 0 || d_scope->level() <= scope, "ContextObj::update(scope="+int2string(scope) +"): scope < d_scope->level() = " +int2string(d_scope->level())); d_scope = d_scope->topScope(); if (scope >= 0) { // Fetch the specified scope for(int i=level(); i>scope; --i) { d_scope = d_scope->prevScope(); DebugAssert(d_scope != NULL, "ContextObj::update[" +name()+"]: d_scope == NULL"); } } ContextObj* data = makeCopy(getCMM()); data->d_scope = tmpScope; // The destructor of the copy should not destroy our older copies data->d_restore=NULL; IF_DEBUG(data->setName(name()+" [copy]");) d_restore = new(getCMM()) ContextObjChain(data, this, d_restore); d_scope->addToChain(d_restore); } ContextObj::~ContextObj() { // Delete our restore copies IF_DEBUG(FatalAssert(d_active, "~ContextObj["+name()+"]");) IF_DEBUG(d_active=false);; for(ContextObjChain* obj = d_restore; obj != NULL; ) { ContextObjChain* tmp = obj->d_restore; // Remove the object from the restore chain if(obj->d_restoreChainNext != NULL) obj->d_restoreChainNext->d_restoreChainPrev = obj->d_restoreChainPrev; *(obj->d_restoreChainPrev) = obj->d_restoreChainNext; // if (obj->d_data != NULL) delete obj->d_data; obj->d_master = NULL; if (tmp == NULL) { delete obj; free(obj); break; } obj = tmp; } // TRACE("context verbose", "~ContextObj()[", this, "] }"); } /////////////////////////////////////////////////////////////////////////////// // Context methods // /////////////////////////////////////////////////////////////////////////////// Context::Context(ContextManager* cm, const string& name, int id) : d_cm(cm), d_name(name), d_id(id) { ContextMemoryManager* cmm = new ContextMemoryManager(); d_topScope = new(cmm) Scope(this, cmm); d_bottomScope = d_topScope; TRACE("context", "*** [context] Creating new context: name = " + name + "id = ", id, ""); } // Don't pop, just delete everything. At this point, most of the // system is already destroyed, popping may be dangerous. Context::~Context() { // popto(0); Scope* top = d_topScope; while(top != NULL) { top = d_topScope->prevScope(); d_topScope->finalize(); delete d_topScope->getCMM(); d_topScope = top; } while (!d_cmmStack.empty()) { delete d_cmmStack.back(); d_cmmStack.pop_back(); } ContextMemoryManager::garbageCollect(); // Erase ourselves from the notify objects, so they don't call us for(vector::iterator i=d_notifyObjList.begin(), iend=d_notifyObjList.end(); i!=iend; ++i) { (*i)->d_context = NULL; } } void Context::push() { IF_DEBUG( string indentStr(level(), ' '); TRACE("pushpop", indentStr, "Push", " {"); ) ContextMemoryManager* cmm; if (!d_cmmStack.empty()) { cmm = d_cmmStack.back(); d_cmmStack.pop_back(); } else { cmm = new ContextMemoryManager(); } cmm->push(); d_topScope = new(cmm) Scope(this, cmm, d_topScope); // TRACE("context", "*** [context] Pushing scope to level ", level(), " {"); IF_DEBUG(DebugCounter maxLevel(debugger.counter("max scope level"));) IF_DEBUG(if(maxLevelprevScope() != NULL, "Illegal to pop last scope off of stack."); // Notify before popping the scope for(vector::iterator i=d_notifyObjList.begin(), iend=d_notifyObjList.end(); i != iend; ++i) (*i)->notifyPre(); // Pop the scope d_topScope = top->prevScope(); top->restore(); IF_DEBUG(top->check();) ContextMemoryManager* cmm = top->getCMM(); cmm->pop(); d_cmmStack.push_back(cmm); // Notify after the pop is done for(vector::iterator i=d_notifyObjList.begin(), iend=d_notifyObjList.end(); i != iend; ++i) (*i)->notify(); // TRACE("context", "*** [context] Popped scope to level ", level(), "}"); IF_DEBUG( string indentStr(level(), ' '); TRACE("pushpop", indentStr, "}", " Pop"); ) } void Context::popto(int toLevel) { while (toLevel < topScope()->level()) pop(); } void Context::deleteNotifyObj(ContextNotifyObj* obj) { size_t i(0), iend(d_notifyObjList.size()); for(; igetMemory(verbosity - 1); mem += MemoryTracker::getVecAndDataP(verbosity - 1, d_notifyObjList); mem += MemoryTracker::getVecAndDataP(verbosity - 1, d_cmmStack); MemoryTracker::print("Context "+d_name, verbosity, memSelf, mem); return mem + memSelf; } /////////////////////////////////////////////////////////////////////////////// // ContextManager methods // /////////////////////////////////////////////////////////////////////////////// ContextManager::ContextManager() { d_curContext = createContext("default"); } ContextManager::~ContextManager() { while (d_contexts.size()) { delete d_contexts.back(); d_contexts.pop_back(); } } Context* ContextManager::createContext(const string& name) { d_contexts.push_back(new Context(this, name, d_contexts.size())); return d_contexts.back(); } Context* ContextManager::switchContext(Context* context) { FatalAssert(false, "Multiple contexts not yet implemented"); Context* old = d_curContext; DebugAssert(context && context == d_contexts[context->id()], "Unknown context"); d_curContext = context; // TODO: Fix up all Context Objects return old; } unsigned long ContextManager::getMemory(int verbosity) { unsigned long memSelf = sizeof(ContextManager); unsigned long mem = 0; // free pages in the context memory manager need to be counted somewhere // this seems as good a place as any mem += ContextMemoryManager::getStaticMemory(verbosity - 1); for (unsigned i = 0; i < d_contexts.size(); ++i) { mem += d_contexts[i]->getMemory(verbosity - 1); } MemoryTracker::print("ContextManager", verbosity, memSelf, mem); return mem + memSelf; } cvc3-2.4.1/src/context/cdflags.cpp0000664000175400017540000000571311103725113016640 0ustar mdetersmdeters/*****************************************************************************/ /*! *\file cdflags.cpp *\brief Implementation for CDFlags class * * Author: Clark Barrett * * Created: Thu Jan 26 16:53:28 2006 * *
* * License to use, copy, modify, sell and/or distribute this software * and its documentation for any purpose is hereby granted without * royalty, subject to the terms and conditions defined in the \ref * LICENSE file provided with this distribution. * *
* */ /*****************************************************************************/ #include "cdflags.h" #include "memory_manager_context.h" using namespace CVC3; using namespace std; void CDFlags::update(unsigned mask, int scope, bool setMask) { DebugAssert(mask && (mask & (mask-1)) == 0, "Expected single bit mask"); if (scope < 0 || d_scope->level() <= scope) { makeCurrent(scope); if (setMask) d_flags = d_flags | mask; else d_flags = d_flags & ~mask; } else { // Kind of ugly: have to "change the past", but that's the price we pay for // keeping all the flags in one word for efficiency. IF_DEBUG(bool on = (d_flags & mask) != 0;) // Update current object if (setMask) d_flags = d_flags | mask; else d_flags = d_flags & ~mask; ContextObjChain** lastPtr = &d_restore; CDFlags* pastFlags; Scope* lastScope = d_scope; bool done = false; // Update past objects while (true) { pastFlags = (CDFlags*)((*lastPtr)->d_data); DebugAssert(pastFlags != NULL, "expected non-NULL data"); if (pastFlags->d_scope->level() >= scope) { DebugAssert((on && (pastFlags->d_flags & mask)) || (!on && !(pastFlags->d_flags & mask)), "Expected no change in flag since scope"); if (setMask) { pastFlags->d_flags = pastFlags->d_flags | mask; } else { pastFlags->d_flags = pastFlags->d_flags & ~mask; } if (pastFlags->d_scope->level() == scope) { done = true; break; } lastScope = pastFlags->d_scope; } else break; lastPtr = &((*lastPtr)->d_restore); DebugAssert(*lastPtr != NULL, "Should always be object at scope 0"); } if (done) return; // No past object exists at the target scope: create one DebugAssert(lastScope != NULL && lastScope->level() > scope, "Expected lastScope to be above target scope"); while (lastScope->level() > scope) lastScope = lastScope->prevScope(); ContextObj* data = pastFlags->makeCopy(lastScope->getCMM()); pastFlags->d_scope = lastScope; ContextObjChain* obj = new(lastScope->getCMM()) ContextObjChain(data, this, (*lastPtr)->d_restore); (*lastPtr)->d_restore = obj; lastScope->addToChain(obj); // Update newly created past object if (setMask) { pastFlags->d_flags = pastFlags->d_flags | mask; } else { pastFlags->d_flags = pastFlags->d_flags & ~mask; } } } cvc3-2.4.1/src/theory_quant/0000775000175400017540000000000011630011320015552 5ustar mdetersmdeterscvc3-2.4.1/src/theory_quant/Makefile0000664000175400017540000000054210533133654017233 0ustar mdetersmdeters################################################## # About this Makefile # # This Makefile depends on Makefile.opts ################################################## MODULE = theory_quant SRC = theory_quant.cpp quant_theorem_producer.cpp HEADERS = quant_proof_rules.h quant_theorem_producer.h LIBRARY=libtheory_quant.a include ../../Makefile.local cvc3-2.4.1/src/theory_quant/quant_proof_rules.h0000664000175400017540000000524011027560540021510 0ustar mdetersmdeters/*****************************************************************************/ /*! * \file quant_proof_rules.h * * Author: Daniel Wichs * * Created: Jul 07 22:22:38 GMT 2003 * *
* * License to use, copy, modify, sell and/or distribute this software * and its documentation for any purpose is hereby granted without * royalty, subject to the terms and conditions defined in the \ref * LICENSE file provided with this distribution. * *
* */ /*****************************************************************************/ #ifndef _cvc3__quant_proof_rules_h_ #define _cvc3__quant_proof_rules_h_ #include namespace CVC3 { class Expr; class Theorem; class QuantProofRules { public: //! Destructor virtual ~QuantProofRules() { } virtual Theorem addNewConst(const Expr& e) =0; virtual Theorem newRWThm(const Expr& e, const Expr& newE) = 0 ; virtual Theorem normalizeQuant(const Expr& e) =0; //! ==> NOT EXISTS (vars): e IFF FORALL (vars) NOT e virtual Theorem rewriteNotExists(const Expr& e) = 0; //! ==> NOT FORALL (vars): e IFF EXISTS (vars) NOT e virtual Theorem rewriteNotForall(const Expr& e) = 0; //! Instantiate a universally quantified formula /*! From T|-FORALL(var): e generate T|-e' where e' is obtained * from e by instantiating bound variables with terms in * vector& terms. The vector of terms should be the same * size as the vector of bound variables in e. Also elements in * each position i need to have matching types. * \param t1 is the quantifier (a Theorem) * \param terms are the terms to instantiate. * \param quantLevel is the quantification level for the theorem. */ virtual Theorem universalInst(const Theorem& t1, const std::vector& terms, int quantLevel, Expr gterm ) = 0 ; virtual Theorem universalInst(const Theorem& t1, const std::vector& terms, int quantLevel) = 0; virtual Theorem universalInst(const Theorem& t1, const std::vector& terms) = 0; virtual Theorem partialUniversalInst(const Theorem& t1, const std::vector& terms, int quantLevel) = 0; /*! @brief From T|- QUANTIFIER (vars): e we get T|-QUANTIFIER(vars') e * where vars' is obtained from vars by removing all bound variables * not used in e. If vars' is empty the produced theorem is just T|-e */ virtual Theorem boundVarElim(const Theorem& t1) = 0; virtual Theorem packVar(const Theorem& t1) = 0; virtual Theorem pullVarOut(const Theorem& t1) = 0; virtual Theorem adjustVarUniv(const Theorem& t1, const std::vector& newBvs) = 0; }; } #endif cvc3-2.4.1/src/theory_quant/quant_theorem_producer.h0000664000175400017540000000612011027560540022515 0ustar mdetersmdeters/*****************************************************************************/ /*! * \file quant_theorem_producer.h * * Author: Daniel Wichs * * Created: Jul 07 22:22:38 GMT 2003 * *
* * License to use, copy, modify, sell and/or distribute this software * and its documentation for any purpose is hereby granted without * royalty, subject to the terms and conditions defined in the \ref * LICENSE file provided with this distribution. * *
* */ /*****************************************************************************/ #ifndef _cvc3__quant_theorem_producer_h_ #define _cvc3__quant_theorem_producer_h_ #include "quant_proof_rules.h" #include "theorem_producer.h" #include "theory_quant.h" namespace CVC3 { class QuantTheoremProducer: public QuantProofRules, public TheoremProducer { TheoryQuant* d_theoryQuant; std::map d_typeFound; private: //! find all bound variables in e and maps them to true in boundVars void recFindBoundVars(const Expr& e, ExprMap & boundVars, ExprMap &visited); public: //! Constructor QuantTheoremProducer(TheoremManager* tm, TheoryQuant* theoryQuant): TheoremProducer(tm), d_theoryQuant(theoryQuant) { d_typeFound.clear(); } virtual Theorem addNewConst(const Expr& e) ; virtual Theorem newRWThm(const Expr& e, const Expr& newE) ; virtual Theorem normalizeQuant(const Expr& e) ; //! ==> NOT EXISTS (vars): e IFF FORALL (vars) NOT e virtual Theorem rewriteNotExists(const Expr& e); //! ==> NOT FORALL (vars): e IFF EXISTS (vars) NOT e virtual Theorem rewriteNotForall(const Expr& e); //! Instantiate a universally quantified formula /*! From T|-FORALL(var): e generate T|-e' where e' is obtained * from e by instantiating bound variables with terms in * vector& terms. The vector of terms should be the same * size as the vector of bound variables in e. Also elements in * each position i need to have matching types. * \param t1 is the quantifier (a Theorem) * \param terms are the terms to instantiate. * \param quantLevel the quantification level for the theorem. */ virtual Theorem universalInst(const Theorem& t1, const std::vector& terms, int quantLevel , Expr gterm); virtual Theorem universalInst(const Theorem& t1, const std::vector& terms, int quantLevel); virtual Theorem universalInst(const Theorem& t1, const std::vector& terms); virtual Theorem partialUniversalInst(const Theorem& t1, const std::vector& terms, int quantLevel) ; /*! @brief From T|- QUANTIFIER (vars): e we get T|-QUANTIFIER(vars') e * where vars' is obtained from vars by removing all bound variables * not used in e. If vars' is empty the produced theorem is just T|-e */ virtual Theorem boundVarElim(const Theorem& t1); virtual Theorem adjustVarUniv(const Theorem& t1, const std::vector& newBvs); virtual Theorem packVar(const Theorem& t1); virtual Theorem pullVarOut(const Theorem& t1); }; } #endif cvc3-2.4.1/src/theory_quant/theory_quant.cpp0000644000175400017540000077556411604636630021050 0ustar mdetersmdeters/*****************************************************************************/ /*! * \File theory_quant.cpp * * Author: Daniel Wichs, Yeting Ge * * Created: Wednesday July 2, 2003 * *
* * License to use, copy, modify, sell and/or distribute this software * and its documentation for any purpose is hereby granted without * royalty, subject to the terms and conditions defined in the \ref * LICENSE file provided with this distribution. * *
* */ /*****************************************************************************/ #include "theory_quant.h" #include "theory_arith.h" #include "theory_array.h" #include "typecheck_exception.h" #include "parser_exception.h" #include "smtlib_exception.h" #include "quant_proof_rules.h" #include "theory_core.h" #include "command_line_flags.h" #include "vcl.h" #include #include #include #include "assumptions.h" using namespace std; using namespace CVC3; /////////////////////////////////////////////////////////////////////////////// // TheoryQuant Public Methods // /////////////////////////////////////////////////////////////////////////////// static const Expr null_expr; const int FOUND_FALSE = 1; Trigger::Trigger(TheoryCore* core, Expr e, Polarity pol, std::set boundVars){ trig=e ; polarity=pol; head=null_expr; hasRWOp=false; hasTrans=false; hasT2=false; isSimple=false; isSuperSimple=false; isMulti=false; multiIndex = 99999; multiId = 99999; for(std::set::const_iterator i=boundVars.begin(),iend=boundVars.end(); i!=iend; ++i) bvs.push_back(*i); } bool Trigger::isPos(){ return (Pos==polarity||PosNeg==polarity); } bool Trigger::isNeg(){ return (Neg==polarity || PosNeg==polarity); } std::vector Trigger::getBVs(){ return bvs; } Expr Trigger::getEx(){ return trig; } void Trigger::setHead(Expr h){ head=h; } Expr Trigger::getHead(){ return head; } void Trigger::setRWOp(bool b){ hasRWOp =b ; } bool Trigger::hasRW(){ return hasRWOp; } void Trigger::setTrans(bool b){ hasTrans =b ; } bool Trigger::hasTr(){ return hasTrans; } void Trigger::setTrans2(bool b){ hasT2 =b ; } bool Trigger::hasTr2(){ return hasT2; } void Trigger::setSimp(){ isSimple =true ; } bool Trigger::isSimp(){ return isSimple; } void Trigger::setSuperSimp(){ isSuperSimple =true ; } bool Trigger::isSuperSimp(){ return isSuperSimple; } void Trigger::setMultiTrig(){ isMulti = true ; } bool Trigger::isMultiTrig(){ return isMulti; } dynTrig::dynTrig(Trigger t, ExprMap b, size_t id) :trig(t), univ_id(id), binds(b) {} TheoryQuant::TheoryQuant(TheoryCore* core) //!< Constructor : Theory(core, "Quantified Expressions"), d_univs(core->getCM()->getCurrentContext()), d_rawUnivs(core->getCM()->getCurrentContext()), d_arrayTrigs(core->getCM()->getCurrentContext()), d_lastArrayPos(core->getCM()->getCurrentContext(), 0 , 0), d_lastPredsPos(core->getCM()->getCurrentContext(), 0, 0), d_lastTermsPos(core->getCM()->getCurrentContext(), 0, 0), d_lastPartPredsPos(core->getCM()->getCurrentContext(), 0, 0), d_lastPartTermsPos(core->getCM()->getCurrentContext(), 0, 0), d_univsPartSavedPos(core->getCM()->getCurrentContext(), 0, 0), d_lastPartLevel(core->getCM()->getCurrentContext(), 0, 0), d_partCalled(core->getCM()->getCurrentContext(),false,0), d_maxILReached(core->getCM()->getCurrentContext(),false,0), d_usefulGterms(core->getCM()->getCurrentContext()), d_lastUsefulGtermsPos(core->getCM()->getCurrentContext(), 0, 0), d_savedTermsPos(core->getCM()->getCurrentContext(), 0, 0), d_univsSavedPos(core->getCM()->getCurrentContext(), 0, 0), d_rawUnivsSavedPos(core->getCM()->getCurrentContext(), 0, 0), d_univsPosFull(core->getCM()->getCurrentContext(), 0, 0), d_univsContextPos(core->getCM()->getCurrentContext(), 0, 0), d_instCount(core->getCM()->getCurrentContext(), 0,0), d_contextTerms(core->getCM()->getCurrentContext()), d_contextCache(core->getCM()->getCurrentContext()), d_maxQuantInst(&(core->getFlags()["max-quant-inst"].getInt())), d_useNew(&(core->getFlags()["quant-new"].getBool())), d_useLazyInst(&(core->getFlags()["quant-lazy"].getBool())), d_useSemMatch(&(core->getFlags()["quant-sem-match"].getBool())), d_useCompleteInst(&(core->getFlags()["quant-complete-inst"].getBool())), d_translate(&(core->getFlags()["translate"].getBool())), // d_usePart(&(core->getFlags()["quant-inst-part"].getBool())), // d_useMult(&(core->getFlags()["quant-inst-mult"].getBool())), d_useInstLCache(&(core->getFlags()["quant-inst-lcache"].getBool())), d_useInstGCache(&(core->getFlags()["quant-inst-gcache"].getBool())), d_useInstThmCache(&(core->getFlags()["quant-inst-tcache"].getBool())), d_useInstTrue(&(core->getFlags()["quant-inst-true"].getBool())), d_usePullVar(&(core->getFlags()["quant-pullvar"].getBool())), d_useExprScore(&(core->getFlags()["quant-score"].getBool())), d_maxIL(&(core->getFlags()["quant-max-IL"].getInt())), d_useTrans(&(core->getFlags()["quant-trans3"].getBool())), d_useTrans2(&(core->getFlags()["quant-trans2"].getBool())), d_useManTrig(&(core->getFlags()["quant-man-trig"].getBool())), d_useGFact(&(core->getFlags()["quant-gfact"].getBool())), d_gfactLimit(&(core->getFlags()["quant-glimit"].getInt())), d_usePolarity(&(core->getFlags()["quant-polarity"].getBool())), d_useNewEqu(&(core->getFlags()["quant-eqnew"].getBool())), d_maxNaiveCall(&(core->getFlags()["quant-naive-num"].getInt())), d_useNaiveInst(&(core->getFlags()["quant-naive-inst"].getBool())), d_curMaxExprScore(core->getCM()->getCurrentContext(), (core->getFlags()["quant-max-score"].getInt()),0), d_arrayIndic(core->getCM()->getCurrentContext()), d_exprLastUpdatedPos(core->getCM()->getCurrentContext(),0 ,0), d_trans_found(core->getCM()->getCurrentContext()), d_trans2_found(core->getCM()->getCurrentContext()), null_cdlist(core->getCM()->getCurrentContext()), d_eqsUpdate(core->getCM()->getCurrentContext()), d_lastEqsUpdatePos(core->getCM()->getCurrentContext(), 0, 0), d_eqs(core->getCM()->getCurrentContext()), d_eqs_pos(core->getCM()->getCurrentContext(), 0, 0), d_allInstCount(core->getStatistics().counter("quantifier instantiations")), d_allInstCount2(core->getStatistics().counter("quantifier instantiations2")), d_totalInstCount(core->getStatistics().counter("quant total instantiations")), d_trueInstCount(core->getStatistics().counter("quant true instantiations")), d_abInstCount(core->getStatistics().counter("quant abandoned instantiations")), d_instHistory(core->getCM()->getCurrentContext()), d_alltrig_list(core->getCM()->getCurrentContext()) { IF_DEBUG(d_univs.setName("CDList[TheoryQuant::d_univs]");) vector kinds; d_instCount = 0; d_cacheThmPos=0; d_trans_num=0; d_trans2_num=0; d_rules=createProofRules(); kinds.push_back(EXISTS); kinds.push_back(FORALL); registerTheory(this, kinds); d_partCalled=false; d_offset_multi_trig=2; d_initMaxScore=(theoryCore()->getFlags()["quant-max-score"].getInt()); for(size_t i=0; inewBoundVarExpr("_genbv", int2string(i), Type::anyType(getEM())); } core->addNotifyEq(this, null_expr); defaultReadExpr = theoryCore()->getEM()->newStringExpr("read"); defaultWriteExpr = theoryCore()->getEM()->newStringExpr("write"); defaultPlusExpr= theoryCore()->getEM()->newStringExpr("+"); defaultMinusExpr= theoryCore()->getEM()->newStringExpr("-"); defaultMultExpr= theoryCore()->getEM()->newStringExpr("*"); defaultDivideExpr= theoryCore()->getEM()->newStringExpr("/"); defaultPowExpr= theoryCore()->getEM()->newStringExpr("pow"); } //! Destructor TheoryQuant::~TheoryQuant() { if(d_rules != NULL) delete d_rules; for(std::map* ,TypeComp>::iterator it = d_contextMap.begin(), iend = d_contextMap.end(); it!= iend; ++it) { delete it->second; free(it->second); } } std::string vectorExpr2string(const std::vector & vec){ std::string buf; for(size_t i=0; inormalizeQuant(e); // Expr newE = resThm.getRHS(); return resThm; } else{ if (e.isNot() && e[0].isForall()){ // cout<getQuantLevelForTerm(e); } bool isSysPred(const Expr& e){ return ( isLE(e) || isLT(e) || isGE(e) || isGT(e) || e.isEq()); } bool canGetHead(const Expr& e){ // return (e.getKind() == APPLY || e.getKind() == READ || e.getKind() == WRITE); return (e.getKind() == APPLY || e.getKind() == READ || e.getKind() == WRITE || isPlus(e) || isMinus(e) || isMult(e) || isDivide(e) || isPow(e) ); } bool isSimpleTrig(const Expr& t){ if(!canGetHead(t)) return false; for(int i = 0; i < t.arity(); i++){ if (t[i].arity()>0 && t[i].containsBoundVar()) return false; if (BOUND_VAR == t[i].getKind()){ for(int j = 0; j < i; j++){ if(t[i] == t[j]) return false; } } } return true; } bool isSuperSimpleTrig(const Expr& t){ if(!isSimpleTrig(t)) return false; if(t.getKind() == READ || t.getKind() == WRITE){ return false; //in case var1[var2] } for(int i = 0; i < t.arity(); i++){ if (t[i].arity()>0 ) return false; if (BOUND_VAR != t[i].getKind()){ return false; } } return true; } bool usefulInMatch(const Expr& e){ if(e.arity() == 0){ TRACE("usefulInMatch", e.toString()+": ",e.arity(), ""); TRACE("usefulInMatch", e.isRational(), "", ""); } // cout << "is useful in match" << (canGetHead(e) || (isSysPred(e) && (!e.isEq()) )) << "#" << e<< endl; // if (e.getKind() == APPLY){ // cout << (e.getKind() == APPLY) << endl; // cout << e.getOp().getExpr() << endl; // cout << e.getOp() << endl; // } return ( canGetHead(e) || (isSysPred(e) && (!e.isEq()) ) ); } void TheoryQuant::setup(const Expr& e) {} int TheoryQuant::help(int i) { return d_curMaxExprScore; } void TheoryQuant::debug(int i){ cout<<"in debug " << endl; cout << "max expr score " << d_curMaxExprScore << endl; cout << "all gterms " << endl; for(size_t gtermIndex =0; gtermIndex < d_usefulGterms.size() ; gtermIndex++){ cout << gtermIndex << " :: " << getExprScore(d_usefulGterms[gtermIndex]) << " | " << d_usefulGterms[gtermIndex] << endl; } cout << " ============= all terms ========================== " << endl; const CDList& allterms = theoryCore()->getTerms(); for(size_t gtermIndex =0; gtermIndex < allterms.size() ; gtermIndex++){ const Expr& curGterm = allterms[gtermIndex]; cout << gtermIndex << " :: " << getExprScore(curGterm) << " | " << curGterm << endl; cout << "--- "; if (curGterm.isApply() && curGterm.hasRep()){ Expr curRep = curGterm.getRep().getRHS() ; if(curRep != curGterm){ cout<<"DIFF " <& allpreds = theoryCore()->getPredicates(); for(size_t gtermIndex =0; gtermIndex < allpreds.size() ; gtermIndex++){ const Expr& curGterm = allpreds[gtermIndex]; cout << gtermIndex << " :: " << getExprScore(curGterm) << " | " << curGterm << endl; cout << "--- "; if (curGterm.isApply() && curGterm.hasRep()){ Expr curRep = curGterm.getRep().getRHS() ; if(curRep != curGterm){ cout<<"DIFF " <getName() == "Uninterpreted Functions"){ cout << "[" << l.getTheory(i)->getName() << ", " << l.getExpr(i) << "] " << l.getExpr(i).getSig().isNull() << endl; } } const Expr& rightTerm = t.getRHS(); cout<<"right term is " << rightTerm << endl; NotifyList* rightUpList = rightTerm.getNotify(); if(NULL == rightUpList) return; cout<<"the right notify list" << endl; NotifyList& ll = *rightUpList; for(size_t i=0,iend=ll.size(); igetName() == "Uninterpreted Functions"){ cout << "[" << ll.getTheory(i)->getName() << ", " << ll.getExpr(i) << "] " << ll.getExpr(i).getSig().isNull() << endl; } } // cout<<"------------" << leftTerm << " # " << rightTerm <getName() == "Uninterpreted Functions"){ // cout<<"%%%%%%%%%%%%" << (leftTerm.getSig()).isNull() << " # " << (rightTerm.getSig()).isNull() <getName()<& backL = backList(leftTerm); CDList& forwL = forwList(rightTerm); size_t backLen = backL.size(); size_t forwLen = forwL.size(); for(size_t i =0; i < backLen; i++){ for(size_t j =0; j < forwLen; j++){ // cout<& backL = backList(rightTerm); CDList& forwL = forwList(leftTerm); size_t backLen = backL.size(); size_t forwLen = forwL.size(); for(size_t i = 0; i < backLen; i++){ for(size_t j = 0; j < forwLen; j++){ // cout<& vec){ string result; // for( ExprMap::iterator i = vec.begin(), iend = vec.end(); i != iend; i++){ // result.append((i->first).toString()); // result.append(" # "); // result.append((i->second).toString()); // result.append("\n"); // } // result.append("------ end map ------\n"); return result; } std::string TheoryQuant::exprMap2stringSimplify(const ExprMap& vec){ string result; // for( ExprMap::iterator i = vec.begin(), iend = vec.end(); i != iend; i++){ // result.append((i->first).toString()); // result.append(" # "); // result.append((simplifyExpr(i->second)).toString()); // result.append("\n"); // } result.append("------ end map ------\n"); return result; } std::string TheoryQuant::exprMap2stringSig(const ExprMap& vec){ string result; // for( ExprMap::iterator i = vec.begin(), iend = vec.end(); i != iend; i++){ // result.append((i->first).toString()); // result.append(" # "); // Expr isecond = i->second; // if(simplifyExpr(isecond) == isecond && isecond.isApply() && isecond.hasSig()){ // result.append((isecond.getSig().getRHS()).toString()); // } // else{ // // result.append(isecond.toString()); // } // result.append("\n"); // } result.append("------ end map ------\n"); return result; } void TheoryQuant::simplifyExprMap(ExprMap& orgExprMap){ ExprMap newExprMap; for( ExprMap::iterator i = orgExprMap.begin(), iend = orgExprMap.end(); i != iend; i++){ newExprMap[(*i).first] = simplifyExpr((*i).second); } orgExprMap = newExprMap; } void TheoryQuant::simplifyVectorExprMap(vector >& orgVectorExprMap){ std::vector > newVectorExprMap; for( size_t orgVectorIndex = 0; orgVectorIndex < orgVectorExprMap.size(); orgVectorIndex++){ ExprMap curExprMap = orgVectorExprMap[orgVectorIndex]; simplifyExprMap(curExprMap); newVectorExprMap.push_back(curExprMap); } orgVectorExprMap = newVectorExprMap; } static void recursiveGetSubTrig(const Expr& e, std::vector & res) { if(e.getFlag()) return; if(e.isClosure()) return recursiveGetSubTrig(e.getBody(),res); if (e.isApply()|| isSysPred(e)){ res.push_back(e); } else if ( e.isTerm() && (!e.isVar()) && (e.getKind()!=RATIONAL_EXPR) ) { res.push_back(e); } for(Expr::iterator i=e.begin(), iend=e.end(); i!=iend; ++i) { recursiveGetSubTrig(*i,res); } e.setFlag(); return ; } std::vector getSubTrig(const Expr& e){ e.clearFlags(); std::vector res; recursiveGetSubTrig(e,res); e.clearFlags(); TRACE("getsub","e is ", e.toString(),""); TRACE("getsub","have ", res.size()," subterms"); return res; } static void recGetSubTerms(const Expr& e, std::vector & res) { if(e.getFlag()) return; if(e.isClosure()) return recGetSubTerms(e.getBody(),res); for(Expr::iterator i=e.begin(), iend=e.end(); i!=iend; ++i) { recGetSubTerms(*i,res); } res.push_back(e); e.setFlag(); return ; } const std::vector& TheoryQuant::getSubTerms(const Expr& e){ //the last item in res is e itself ExprMap >::iterator iter= d_subTermsMap.find(e); if( d_subTermsMap.end() == iter){ e.clearFlags(); std::vector res; recGetSubTerms(e,res); e.clearFlags(); TRACE("getsubs", "getsubs, e is: ", e, ""); TRACE("getsubs", "e has ", res.size(), " subterms"); d_subTermsMap[e] = res; return d_subTermsMap[e]; } else{ return (*iter).second; } } void TheoryQuant::enqueueInst(const Theorem& univ, const vector& bind, const Expr& gterm){ static int max_score =-1; bool partInst=false; if(bind.size() < univ.getExpr().getVars().size()){ partInst=false; TRACE("sendinst","partinst",partInst,""); } Expr bind_expr(RAW_LIST, bind, getEM()); if (*d_useInstLCache){ const Expr& e = univ.getExpr(); ExprMap*>::iterator iterCache = d_bindHistory.find(e); if (iterCache != d_bindHistory.end()){ CDMap* cache = (*iterCache).second; if(cache->find(bind_expr) !=cache->end()){ return ; } else{ (*cache)[bind_expr] = true; } } else{ CDMap* new_cache = new(true) CDMap (theoryCore()->getCM()->getCurrentContext()); (*new_cache)[bind_expr] = true; d_bindHistory[e] = new_cache; } } Theorem thm ; if(null_expr == gterm ){//it is from naive instantiation or multi-inst TRACE("sendinst","gterm",gterm,""); if(partInst) { thm = d_rules->partialUniversalInst(univ, bind, 0); } else{ // thm = d_rules->universalInst(univ, bind, 0); thm = d_rules->universalInst(univ, bind, 0, gterm); } } else{ int gscore = theoryCore()->getQuantLevelForTerm(gterm); if(gscore > max_score){ max_score = gscore; // cout<<"max score "<partialUniversalInst(univ, bind, gscore); } else{ // thm = d_rules->universalInst(univ, bind, gscore); thm = d_rules->universalInst(univ, bind, gscore, gterm); } } d_totalInstCount++; d_totalThmCount[thm.getExpr()]++; Theorem simpThm = simplify(thm.getExpr()); if(*d_useInstTrue){ Expr res = simpThm.getRHS(); if(res.isTrue()){ d_trueInstCount++; return; } if(res.isFalse() ){ d_thmCount[thm.getExpr()]++; // enqueueSE(thm); // if(*d_useGFact || d_totalThmCount[thm.getExpr()] > *d_gfactLimit){ if(*d_useGFact || d_thmCount[thm.getExpr()] > *d_gfactLimit){ // if(*d_useGFact || ){ // addGlobalLemma(thm, -1); enqueueFact(thm); } else{ enqueueFact(thm); } // // cout<<"false found "<getQuantLevelForTerm(gterm), ""); TRACE("quant sendinst", "= add fact simp: ", simplifyExpr(thm.getExpr()), ""); TRACE("quant sendinst", "= add fact org: ", thm.getExpr(), ""); TRACE("quant sendinst", "= add fact from: ", univ.getExpr(), "\n===: "+vectorExpr2string(bind)); } //void TheoryQuant::enqueueInst(size_t univ_id , const std::vector& bind, const Expr& gterm){ void TheoryQuant::enqueueInst(size_t univ_id , const std::vector& orgBind, const Expr& gterm){ // static int max_score =-1; TRACE("quant sendinst", "= begin univ id: ", univ_id, ""); TRACE("quant sendinst", "= begin bind: ", vectorExpr2string(orgBind), ""); TRACE("quant sendinst", "= begin gterm: ", gterm, ""); const Theorem& univ = d_univs[univ_id]; // static vector storage ; // storage.push_back(univ); bool partInst=false; if(orgBind.size() < univ.getExpr().getVars().size()){ partInst=false; TRACE("sendinst","partinst",partInst,""); } vector simpBind(orgBind); for(size_t orgBindIndex = 0; orgBindIndex < orgBind.size(); orgBindIndex++){ simpBind [orgBindIndex] = simplifyExpr(orgBind[orgBindIndex]); } Expr orgBindList(RAW_LIST, orgBind, getEM()); Expr simpBindList(RAW_LIST, simpBind, getEM()); // if(orgBindList != simpBindList){ // cout<<"debugerror" << endl; // cout<< "-orgBind " << vectorExpr2string(orgBind) << endl; // cout<< "-simpBind " << vectorExpr2string(simpBind) << endl; // } vector bind(simpBind); Expr bind_expr(simpBindList); // vector bind(orgBind); // Expr bind_expr(orgBindList); TRACE("quant sendinst", "==add fact from= ", univ.getExpr(), "\n===: "+vectorExpr2string(bind)); if (*d_useInstLCache){ const Expr& e = univ.getExpr(); ExprMap*>::iterator iterCache = d_bindHistory.find(e); if (iterCache != d_bindHistory.end()){ CDMap* cache = (*iterCache).second; if(cache->find(bind_expr) != cache->end()){ // cout<<"return inst 1"<* new_cache = new(true) CDMap (theoryCore()->getCM()->getCurrentContext()); (*new_cache)[bind_expr] = true; d_bindHistory[e] = new_cache; } } if (*d_useInstGCache){ const Expr& e = univ.getExpr(); ExprMap*>::iterator iterCache = d_bindGlobalHistory.find(e); if (iterCache != d_bindGlobalHistory.end()){ std::hash_map* cache = (*iterCache).second; if(cache->find(bind_expr) != cache->end()){ // cout<<"return inst 1"<getQuantLevelForTerm(gterm); // Theorem local_thm = d_rules->universalInst(univ, bind, gscore); /* if(!(simplifyExpr(local_thm.getExpr())).isTrue()){ cout<<"en?" <* new_cache = new std::hash_map ; (*new_cache)[bind_expr] = true; d_bindGlobalHistory[e] = new_cache; d_allInstCount2++; */ } } Theorem thm ; if (*d_useInstThmCache){ const Expr& e = univ.getExpr(); ExprMap* >::iterator iterCache = d_bindGlobalThmHistory.find(e); if (iterCache != d_bindGlobalThmHistory.end()){ std::hash_map* cache = (*iterCache).second; std::hash_map::iterator thm_iter = cache->find(bind_expr); if(thm_iter != cache->end()){ thm = thm_iter->second; } else{ { if(null_expr == gterm ){//it is from naive instantiation or multi-inst TRACE("sendinst","gterm",gterm,""); if(partInst) { thm = d_rules->partialUniversalInst(univ, bind, 0); } else{ // thm = d_rules->universalInst(univ, bind, 0); thm = d_rules->universalInst(univ, bind, 0, gterm); } } else{ int gscore = theoryCore()->getQuantLevelForTerm(gterm); if(partInst) { thm = d_rules->partialUniversalInst(univ, bind, gscore); } else{ // thm = d_rules->universalInst(univ, bind, gscore); thm = d_rules->universalInst(univ, bind, gscore, gterm); } } } (*cache)[bind_expr] = thm; d_allInstCount2++; } } else{ { if(null_expr == gterm ){//it is from naive instantiation or multi-inst TRACE("sendinst","gterm",gterm,""); if(partInst) { thm = d_rules->partialUniversalInst(univ, bind, 0); } else{ // thm = d_rules->universalInst(univ, bind, 0); thm = d_rules->universalInst(univ, bind, 0, gterm); } } else{ int gscore = theoryCore()->getQuantLevelForTerm(gterm); if(partInst) { thm = d_rules->partialUniversalInst(univ, bind, gscore); } else{ // thm = d_rules->universalInst(univ, bind, gscore); thm = d_rules->universalInst(univ, bind, gscore, gterm); } } } std::hash_map* new_cache = new std::hash_map ; (*new_cache)[bind_expr] = thm; d_bindGlobalThmHistory[e] = new_cache; d_allInstCount2++; } } else{ if(null_expr == gterm ){//it is from naive instantiation or multi-inst TRACE("sendinst","gterm",gterm,""); if(partInst) { thm = d_rules->partialUniversalInst(univ, bind, 0); } else{ //thm = d_rules->universalInst(univ, bind, 0); thm = d_rules->universalInst(univ, bind, 0, gterm); } } else{ int gscore = theoryCore()->getQuantLevelForTerm(gterm); /* if(gscore > max_score){ max_score = gscore; cout<<"max score "<partialUniversalInst(univ, bind, gscore); } else{ // thm = d_rules->universalInst(univ, bind, gscore); thm = d_rules->universalInst(univ, bind, gscore, gterm); } } } d_totalInstCount++; d_totalThmCount[thm.getExpr()]++; Theorem simpThm = simplify(thm.getExpr()); if(*d_useInstTrue){ Expr res = simpThm.getRHS(); if(res.isTrue()){ d_trueInstCount++; // cout<<"return because true"< *d_gfactLimit ){ if(*d_useGFact || d_thmCount[thm.getExpr()] > *d_gfactLimit ){ // if(*d_useGFact){ // addGlobalLemma(thm, -1); enqueueFact(thm); } else{ enqueueFact(thm); } // enqueueSE(thm); // // setInconsistent(simpThm); d_allInstCount++; d_instThisRound++; // cout<<"false found 2"<getQuantLevelForTerm(gterm)){ cout<<"gterm" << gterm <getQuantLevelForTerm(gterm)<& binds, const Expr& gterm) { return enqueueInst(univ,binds,gterm); } int TheoryQuant::sendInstNew(){ int resNum = 0 ; while(!d_simplifiedThmQueue.empty()){ const Theorem thm = d_simplifiedThmQueue.front(); d_simplifiedThmQueue.pop(); d_allInstCount++; d_instThisRound++; resNum++; if (*d_useInstGCache){ const Theorem & univ = d_gUnivQueue.front(); const Expr & bind = d_gBindQueue.front(); const Expr& e = univ.getExpr(); ExprMap*>::iterator iterCache = d_bindGlobalHistory.find(e); if (iterCache != d_bindGlobalHistory.end()){ std::hash_map* cache = (*iterCache).second; (*cache)[bind] = true; } else{ std::hash_map* new_cache = new std::hash_map ; (*new_cache)[bind] = true; d_bindGlobalHistory[e] = new_cache; } } d_thmCount[thm.getExpr()]++; // if(*d_useGFact || d_totalThmCount[thm.getExpr()] > *d_gfactLimit ){ if(*d_useGFact || d_thmCount[thm.getExpr()] > *d_gfactLimit ){ // addGlobalLemma(thm, -1); enqueueFact(thm); } else{ enqueueFact(thm); } // enqueueSE(thm); // } return resNum; } void TheoryQuant::addNotify(const Expr& e){} int recursiveExprScore(const Expr& e) { int res=0; DebugAssert(!(e.isClosure()), "exprScore called on closure"); if(e.arity()== 0){ res = 0; } else{ for(Expr::iterator i=e.begin(), iend=e.end(); i!=iend; ++i) { res += recursiveExprScore(*i); } } res++; return res; } int exprScore(const Expr& e){ return recursiveExprScore(e); } Expr TheoryQuant::getHeadExpr(const Expr& e){ if (e.getKind() == APPLY){ return e.getOp().getExpr(); } if ( READ == e.getKind() ){ return defaultReadExpr; } if ( WRITE == e.getKind() ){ return defaultWriteExpr; } if (isPlus(e)){ return defaultPlusExpr; } if (isMinus(e)){ return defaultMinusExpr; } if (isMult(e)){ return defaultMultExpr; } if (isDivide(e)){ return defaultDivideExpr; } if (isPow(e)){ return defaultPowExpr; } // if ( READ == e.getKind() || WRITE == e.getKind() ) { // int kind = e[0].getKind(); // if (UCONST==kind) { // return e[0]; // } // else if (APPLY==kind || UFUNC == kind || READ == kind || WRITE == kind){ // return getHeadExpr(e[0]); // } // else if(e[0].isSkolem()){ // return e[0]; // } // } return null_expr; } Expr TheoryQuant::getHead(const Expr& e) { return getHeadExpr(e); } //! get the bound vars in term e, static bool recursiveGetBoundVars(const Expr& e, std::set& result) { bool res(false); if(e.getFlag()){ return e.containsBoundVar(); } else if(e.isClosure()){ res = recursiveGetBoundVars(e.getBody(),result); } else if (BOUND_VAR == e.getKind() ){ result.insert(e); e.setContainsBoundVar(); res = true; } else { res = false; for(Expr::iterator i=e.begin(), iend=e.end(); i!=iend; ++i){ if(recursiveGetBoundVars(*i,result)){ res = true; } } } e.setFlag(); if(res) { e.setContainsBoundVar(); } return res; } //! get bound vars in term e, std::set getBoundVars(const Expr& e){ // static ExprMap > bvsCache; // static std::map > bvsCache; // std::map >::iterator iterCache = bvsCache.find(e); //ExprMap >::iterator iterCache = bvsCache.find(e); // if (iterCache != bvsCache.end()){ // // return iterCache->second; // return (*iterCache).second; // } e.clearFlags(); std::set result ; recursiveGetBoundVars(e,result); e.clearFlags(); // bvsCache[e]=result; return result; } void findPolarity(const Expr& e, ExprMap& res, Polarity pol){ if(!e.getType().isBool()) return; //now a AND b will be given a polarity too, this is not necessary. if(res.count(e)>0){ if ((Neg == res[e] && Pos == pol) || (Neg == res[e] && Pos == pol) ){ res[e]=PosNeg; } } else{ res[e]=pol; } TRACE("find-polarity", e, "has ", (int)pol); if(PosNeg==pol){ for(int i=0; i bVarsOut = thm_expr.getVars(); const Expr innerExists =outBody[0][1]; const Expr innerBody = innerExists.getBody(); vector bVarsIn = innerExists.getVars(); for(vector::iterator i=bVarsIn.begin(), iend=bVarsIn.end(); i!=iend; i++){ bVarsOut.push_back(*i); } Expr newbody; newbody=(outBody[0][0].notExpr()).orExpr(innerBody.notExpr()); Expr newQuantExpr; newQuantExpr = d_theoryCore->getEM()->newClosureExpr(FORALL, bVarsOut, newbody); return newQuantExpr ; } else if ((outBody.isAnd() && outBody[1].isForall()) || (outBody.isImpl() && outBody[1].isForall())){ vector bVarsOut = thm_expr.getVars(); const Expr innerForall=outBody[1]; const Expr innerBody = innerForall.getBody(); vector bVarsIn = innerForall.getVars(); for(vector::iterator i=bVarsIn.begin(), iend=bVarsIn.end(); i!=iend; i++){ bVarsOut.push_back(*i); } Expr newbody; if(outBody.isAnd()){ newbody=outBody[0].andExpr(innerBody); } else if(outBody.isImpl()){ newbody=outBody[0].impExpr(innerBody); } Expr newQuantExpr; newQuantExpr = d_theoryCore->getEM()->newClosureExpr(FORALL, bVarsOut, newbody); return(newQuantExpr); } return thm_expr; // case cannot be handled now. } else if (thm_expr.isExists()){ if ((outBody.isAnd() && outBody[1].isExists()) || (outBody.isImpl() && outBody[1].isExists())){ vector bVarsOut = thm_expr.getVars(); const Expr innerExists = outBody[1]; const Expr innerBody = innerExists.getBody(); vector bVarsIn = innerExists.getVars(); for(vector::iterator i=bVarsIn.begin(), iend=bVarsIn.end(); i!=iend; i++){ bVarsOut.push_back(*i); } Expr newbody; if(outBody.isAnd()){ newbody=outBody[0].andExpr(innerBody); } else if(outBody.isImpl()){ newbody=outBody[0].impExpr(innerBody); } Expr newQuantExpr; newQuantExpr = d_theoryCore->getEM()->newClosureExpr(EXISTS, bVarsOut, newbody); return newQuantExpr; } } return thm_expr; } CompleteInstPreProcessor::CompleteInstPreProcessor(TheoryCore * core, QuantProofRules* quant_rule): d_theoryCore(core), d_quant_rules(quant_rule) {} // collect all uninterpreted pedidates in assert void CompleteInstPreProcessor::collectHeads(const Expr& assert, set& heads){ if ( ! assert.getType().isBool()){ return; } else if ( ! assert.isAbsAtomicFormula()){ for (int i = 0 ; i < assert.arity(); i++){ collectHeads(assert[i], heads); } return; } else if (assert.isClosure()){ collectHeads(assert.getBody(), heads); } else if (assert.isAtomicFormula()){ if (isUniterpFunc(assert)){ heads.insert(assert.getOp().getExpr()); } } else{ // cout << " error in collect heads" << endl; } } bool CompleteInstPreProcessor::isMacro(const Expr& assert){ if (d_is_macro_def.count(assert) > 0 ) { return true; } if (assert.isForall()){ Expr body = assert.getBody(); if (body.isIff()){ Expr right = body[0]; Expr left = body[1]; if ((isUniterpFunc(right) && left.isForall()) || (right.isForall() && isUniterpFunc(left) )){ Expr macro_lhs ; Expr macro_def; if (isUniterpFunc(right)){ macro_lhs = right; macro_def = left; } else{ macro_lhs = left; macro_def = right; } Expr test_def_exists = d_theoryCore->getEM()->newClosureExpr(EXISTS, assert.getVars(), macro_def); Expr test_def_sko = d_theoryCore->getCommonRules()->skolemize(test_def_exists); if (isGoodQuant(test_def_sko)){ Expr macro_head = macro_lhs.getOp().getExpr(); set heads_set; collectHeads(macro_def, heads_set); if (heads_set.count(macro_head) <= 0 ){ d_is_macro_def[assert] = true; d_macro_quant[macro_head] = assert; d_macro_def[macro_head] = macro_def; d_macro_lhs[macro_head] = macro_lhs; return true; } } else { // cout << "NOT good DEF" << def<< endl; } } } } return false; } bool CompleteInstPreProcessor::hasMacros(const vector& asserts){ bool has_macros = false; for (size_t i = 0 ; i < asserts.size(); i++){ if (isMacro(asserts[i])){ has_macros = true; } } return has_macros; } Expr CompleteInstPreProcessor::substMacro(const Expr& old){ Expr head = old.getOp().getExpr(); DebugAssert(d_macro_lhs.count(head)>0, "macro lhs not found"); DebugAssert(d_macro_def.count(head)>0, "macro def not found"); DebugAssert(d_macro_quant.count(head)>0, "macro quant not found"); Expr macro_lhs = d_macro_lhs[head]; Expr macro_def = d_macro_def[head]; Expr macro_quant = d_macro_quant[head]; DebugAssert(head == macro_lhs.getOp().getExpr(), "impossible in substMacro"); ExprMap binding; for (int i = 0; i < macro_lhs.arity(); i++){ if (macro_lhs[i].isBoundVar()){ binding[macro_lhs[i]] = old[i]; } } vector quant_vars = macro_quant.getVars(); vector gterms; for (size_t i = 0 ; i < binding.size(); i++){ gterms.push_back(binding[quant_vars[i]]); } return macro_def.substExpr(quant_vars,gterms); } Expr CompleteInstPreProcessor::simplifyEq(const Expr& assert){ if ( ! assert.getType().isBool()){ return assert; } else if ( ! assert.isAbsAtomicFormula()){ vector children ; for (int i = 0 ; i < assert.arity(); i++){ children.push_back(simplifyEq(assert[i])); } return Expr(assert.getOp(),children); } else if (assert.isClosure()){ Expr new_body = simplifyEq(assert.getBody()); if (assert.isForall()){ d_theoryCore->getEM()->newClosureExpr(FORALL, assert.getVars(), new_body); } else if (assert.isExists()){ d_theoryCore->getEM()->newClosureExpr(EXISTS, assert.getVars(), new_body); } else{ DebugAssert(false, "impossible case in recInstMacros"); } } else if (assert.isAtomicFormula()){ if (assert.isEq() && assert[0] == assert[1]){ return d_theoryCore->trueExpr(); } else { return assert; } } cout < children ; for (int i = 0 ; i < assert.arity(); i++){ children.push_back(recInstMacros(assert[i])); } return Expr(assert.getOp(),children); } else if (assert.isClosure()){ Expr new_body = recInstMacros(assert.getBody()); if (assert.isForall()){ d_theoryCore->getEM()->newClosureExpr(FORALL, assert.getVars(), new_body); } else if (assert.isExists()){ d_theoryCore->getEM()->newClosureExpr(EXISTS, assert.getVars(), new_body); } else{ DebugAssert(false, "impossible case in recInstMacros"); } } else if (assert.isAtomicFormula()){ if (isUniterpFunc(assert)){ Expr assert_op = assert.getOp().getExpr(); if ( d_macro_def.count(assert_op) > 0 ){ return substMacro(assert); } else{ return assert; } } else { return assert; } } DebugAssert(false, "impossible case in recInstMacors"); return assert; } // if assert is a macro quant, then replace it with macro_quant_sub Expr CompleteInstPreProcessor::instMacros(const Expr& assert, const Expr macro_quant_sub ){ if (isMacro(assert)){ return macro_quant_sub; } return recInstMacros(assert); } bool CompleteInstPreProcessor::hasShieldVar(const Expr& e){ if (isUniterpFunc(e) && e.arity() > 0 ){ for (int i = 0; i 0 ){ for (int i = 0; i 0 ){ for (int i = 0; i 0 ){ for (int i = 0; i& res, Polarity pol){ if(!e.getType().isBool()) return; //now a AND b will be given a polarity too, this is not necessary. if(res.count(e)>0){ if ((Neg == res[e] && Pos == pol) || (Neg == res[e] && Pos == pol) ){ res[e]=PosNeg; } } else{ res[e]=pol; } // cout <<"finding " << e << endl; if(PosNeg == pol){ for(int i=0; i& pol_map){ if ( ! e.getType().isBool()){ return e; } else if (e.isClosure()){ if (e.isForall()) { return e; } else if (e.isExists() && Pos == pol_map[e]){ Expr new_body = recSkolemize(e.getBody(), pol_map); Expr new_quant = d_theoryCore->getEM()->newClosureExpr(EXISTS, e.getVars(), new_body); return d_theoryCore->getCommonRules()->skolemize(new_quant); } } else if (e.arity() > 0 ) { vector children; for (int i = 0 ; i < e.arity(); i++){ Expr new_child = recSkolemize(e[i], pol_map); if (new_child.isNot() && new_child[0].isNot()){ children.push_back(new_child[0][0]); //(not not expr) --> expr } else{ children.push_back(new_child); } } Expr new_expr = Expr(e.getOp(), children); if (new_expr.isNot() && new_expr[0].isNot()){ return new_expr[0][0]; } else { return new_expr; } } return e; } Expr CompleteInstPreProcessor::simplifyQuant(const Expr& e){ //put all quant into postive form Expr pos_expr = rewriteNot(e); TRACE("simp-quant", e , "\n ---rewriteNot---> \n", pos_expr); Expr next_expr; if(e.isForall()){ Theorem atoa = d_theoryCore->getCommonRules()->assumpRule(pos_expr); Theorem packVarThm = d_quant_rules->packVar(atoa); next_expr = packVarThm.getExpr(); } else{ next_expr = pos_expr; } //skolemize all postive exists, because we only care for satisfiablility now. ExprMap pol_map; // findPolarity(pos_expr, pol_map, Pos); findPolarity(next_expr, pol_map, Pos); // Expr ret = recSkolemize(pos_expr, pol_map); Expr ret = recSkolemize(next_expr, pol_map); TRACE("simp-quant", e , "\n ---skolemize---> \n", ret); return ret; } Expr CompleteInstPreProcessor::rewriteNot(const Expr& e){ ExprMap pol_map; findPolarity(e, pol_map, Pos); set t = getBoundVars(e); //set containsBoundVar flag return recRewriteNot(e, pol_map); } Expr CompleteInstPreProcessor::recRewriteNot(const Expr & e, ExprMap& pol_map){ if ( ! e.getType().isBool()){ return e; } if (isGround(e)){ return e; } if (e.isClosure()){ DebugAssert(pol_map.find(e) != pol_map.end(), "cannot find polarity" ); if ( Neg == pol_map[e]){ Expr body = recRewriteNot(e.getBody(), pol_map); Expr new_body = body.notExpr(); Kind new_kind = e.isForall() ? EXISTS : FORALL; Expr new_quant = d_theoryCore->getEM()->newClosureExpr(new_kind,e.getVars(),new_body); Expr new_expr = new_quant.notExpr(); return new_expr; } else { //it is too much to deal with the case PosNeg == pol_map[e] //becasue PosNeg will be introduced for IFF and IF, return e; } } else if (e.arity() > 0 ) { vector children; for (int i = 0 ; i < e.arity(); i++){ Expr new_child = recRewriteNot(e[i], pol_map); if (new_child.isNot() && new_child[0].isNot()){ children.push_back(new_child[0][0]); //(not not expr) --> expr } else{ children.push_back(new_child); } } Expr new_expr = Expr(e.getOp(), children); if (new_expr.isNot() && new_expr[0].isNot()){ return new_expr[0][0]; } else { return new_expr; } } else if (0 == e.arity() ){ return e; } DebugAssert(false, "impossible in rewriteNot"); return e; } void CompleteInstPreProcessor::addIndex(const Expr& e){ if ( ! isInt(e.getType())) return; d_allIndex.insert(d_theoryCore->simplifyExpr(e)); } Expr CompleteInstPreProcessor::plusOne(const Expr& e){ Expr one = d_theoryCore->getEM()->newRatExpr(1); return Expr(PLUS, e, one); } Expr CompleteInstPreProcessor::minusOne(const Expr& e){ Expr one = d_theoryCore->getEM()->newRatExpr(1); return Expr(MINUS, e, one); } void CompleteInstPreProcessor::collect_shield_index(const Expr& e){ if (isUniterpFunc(e) && e.arity() > 0 ){ for (int i = 0; i 0 ){ for (int i = 0; i cur_expr_pol; findPolarity(forall_quant, cur_expr_pol, Pos); for (ExprMap::iterator i = cur_expr_pol.begin(), iend = cur_expr_pol.end(); i != iend ; i++){ Expr cur_expr = i->first; Polarity pol = i->second; if (isLE(cur_expr)){ const Expr& left = cur_expr[0]; const Expr& right = cur_expr[1]; if (left.isBoundVar() && isGround(right)){ if (Pos == pol || PosNeg == pol){ addIndex(plusOne(right)); } if (Neg == pol || PosNeg == pol){ addIndex(right); } } else if (right.isBoundVar() && isGround(left)){ if (Pos == pol || PosNeg == pol){ addIndex(plusOne(left)); } if (Neg == pol || PosNeg == pol){ addIndex(left); } } else if (left.isBoundVar() && right.isBoundVar()){ //do nothing } //well, neither left nor right is a bound var. else if (isShield(left) && isShield(right)){ collect_shield_index(left); collect_shield_index(right); } else{ cout << " foall is " << forall_quant << endl; DebugAssert(false, "impossible case in collect index "); } } else if (cur_expr.isEq()){ const Expr& left = cur_expr[0]; const Expr& right = cur_expr[1]; if (left.isBoundVar() && isGround(right)){ if (Pos == pol || PosNeg == pol){ addIndex(minusOne(right)); addIndex(plusOne(right)); } if (Neg == pol || PosNeg == pol){ addIndex(minusOne(right)); } } else if (right.isBoundVar() && isGround(left)){ if (Pos == pol || PosNeg == pol){ addIndex(minusOne(left)); addIndex(plusOne(left)); } if (Neg == pol || PosNeg == pol){ addIndex(left); } } else if (left.isBoundVar() && right.isBoundVar()){ DebugAssert(false, "impossible case collect index"); } //well, neither left nor right is a bound var. else if (isShield(left) && isShield(right)){ collect_shield_index(left); collect_shield_index(right); } else{ DebugAssert(false, "impossible case in collect index"); } } else if (isLT(cur_expr)){ const Expr& left = cur_expr[0]; const Expr& right = cur_expr[1]; if (left.isBoundVar() && isGround(right)){ if (Pos == pol || PosNeg == pol){ addIndex(plusOne(right)); } if (Neg == pol || PosNeg == pol){ addIndex(right); } } else if (right.isBoundVar() && isGround(left)){ if (Pos == pol || PosNeg == pol){ addIndex(plusOne(left)); } if (Neg == pol || PosNeg == pol){ addIndex(left); } } else if (left.isBoundVar() && right.isBoundVar()){ //do nothing } //well, neither left nor right is a bound var. else if (isShield(left) && isShield(right)){ collect_shield_index(left); collect_shield_index(right); } else{ DebugAssert(false, "impossible case in collect index"); } } else{ collect_shield_index(cur_expr); } } } void CompleteInstPreProcessor::collectIndex(const Expr& assert){ // cout <<"BEGIN COLLECTING " << assert << endl; //must be called after isGoodForCompleteInst; if(isGround(assert)){ collect_shield_index(assert); return; } ExprMap cur_expr_pol; findPolarityAtomic(assert, cur_expr_pol, Pos); for(ExprMap::iterator i = cur_expr_pol.begin(), iend = cur_expr_pol.end(); i != iend; i++) { const Expr& cur_expr = i->first; Polarity pol = i->second; // cout <<"NOW COLLECTING " << cur_expr << endl; if (cur_expr.isAtomicFormula()){ if (cur_expr.containsBoundVar()){ DebugAssert(false, "error in collecting "); return; } collect_shield_index(cur_expr); } else if (cur_expr.isForall()){ if (Pos != pol){ DebugAssert(false, "error in polarity "); return; } Expr newQuant = pullVarOut(cur_expr); collect_forall_index(newQuant); // cout <<"PUSH FORALL" << cur_expr << endl; d_quant_equiv_map[cur_expr] = newQuant; } else if (cur_expr.isExists()){ if (Pos != pol){ DebugAssert(false, "error in polarity " ); return; } Expr newQuant = pullVarOut(cur_expr); Expr sko_expr = d_theoryCore->getCommonRules()->skolemize(newQuant); collect_forall_index(sko_expr); // cout <<"PUSH EXISTS" << cur_expr << endl; d_quant_equiv_map[cur_expr] = sko_expr; } } return; } bool CompleteInstPreProcessor::isGood(const Expr& assert){ // cout << " in isgood " << assert << endl; const std::set& bvs = getBoundVars(assert); if (bvs.size() <= 0 ) { // d_gnd_cache.push_back(e); // cout << " return in isgood because no bound vars" << assert << endl; return true; //this is a ground formula, } ExprMap cur_expr_pol; findPolarityAtomic(assert, cur_expr_pol, Pos); for(ExprMap::iterator i = cur_expr_pol.begin(), iend = cur_expr_pol.end(); i != iend; i++) { const Expr& cur_expr = i->first; Polarity pol = i->second; // cout <<"isgood cur expr " << cur_expr << endl; if(cur_expr.isForall()) { if (Pos == pol){ if( isGoodQuant(cur_expr)){ if ( ! hasShieldVar(cur_expr)) { return false; } } else{ d_all_good = false; return false; } } else { DebugAssert(false, "error, Neg polarity in isGood "); return false; } } else if (cur_expr.isExists()){ DebugAssert(false, "error, found exists in is good"); if (Neg == pol || PosNeg == pol){ DebugAssert(false, "error, neg polarity in isGood "); return false; } } } return true; } // if (cur_expr.isClosure()){ // if( Pos == pol){ // Theorem newQuant; // newQuant = (d_rules->pullVarOut(d_rules->addNewConst(cur_expr))).getExpr(); // if (cur_expr.isExists()){ // Expr t = getCommonRules()->skolemize(newQuant); // d_quant_equiv_map[cur_expr] = t; // d_gnd_cache.push_Back(t); //used later by isGoodQuant and collectIndex // } // else if (cur_expr.isForall()){ // if( isGoodQuantCompleteInst()){ // d_quant_equiv_map[cur_expr] = newQuant; // } // else{ // d_all_good = false; // return false; // } // } // } // else{ // cout << "cannot deal with neg polarity now " << endl; // } // } // else if (cur_expr.isAtomicFormula()){ // findPolarity(cur_expr, d_expr_pol, Pos); //used later by isGoodQuant and collectIndex // } // } // return true; //} bool CompleteInstPreProcessor::isGoodQuant(const Expr& e){ // cout << " test is good quant" << endl; // const std::set& bvs = getBoundVars(e); // if (bvs.size() <= 0 ) { // return true; //this is a ground formula, // } // if (e.getVars().size() != bvs.size()){ // return false; // we can do more on this case later. // } vector bvs = e.getVars(); for (vector::iterator i = bvs.begin(), iend = bvs.end(); i != iend; i++){ if ( ! isInt(i->getType() ) ){ return false; //now only inteter can be handled } } // if (e.isExists()){ // return true; // } // findPolarity(newQuant, d_expr_pol, Pos); //used later by isGoodQuant and collectIndex ExprMap body_pol ; findPolarity(e, body_pol, Pos); for(ExprMap::iterator i = body_pol.begin(), iend = body_pol.end(); i != iend; i++) { if ((i->first).isAtomicFormula()){ const Expr& cur_expr = i->first; Polarity pol = i->second; // cout <<" good " << cur_expr << endl; if (!cur_expr.containsBoundVar()){ continue; // this is a ground term, no need to do anything } else if (isShield(cur_expr)){ continue; // this is good } else if (isLE(cur_expr) || isLT(cur_expr) || cur_expr.isEq()){ const Expr& left = cur_expr[0]; const Expr& right = cur_expr[1]; if (left.isBoundVar() && !right.containsBoundVar()){ continue; //good case } else if (right.isBoundVar() && !left.containsBoundVar()){ continue; } else if (left.isBoundVar() && right.isBoundVar()){ if (Neg == pol && isLE(cur_expr)){ continue; } } //well, neither left nor right is a bound var. else if (isShield(left) && isShield(right)){ continue; } // cout << "RETURN 1 " << cur_expr << endl; return false; } else{ // cout << "RETURN 2 " << cur_expr << endl; return false; } } } return true; } class recCompleteInster{ const Expr& d_body; const std::vector& d_bvs; std::vector d_buff; const std::set& d_all_index; std::vector d_exprs; Expr d_result; void inst_helper(int num_vars); Expr& build_tree(); public: recCompleteInster(const Expr&, const std::vector&, std::set& , Expr); Expr inst(); }; recCompleteInster::recCompleteInster(const Expr& body, const std::vector& bvs, std::set& all_index, Expr res): d_body(body),d_bvs(bvs), d_all_index(all_index),d_result(res){} Expr recCompleteInster::inst(){ d_buff.resize(d_bvs.size()); // cout << "there are " << d_all_index.size() << " gterms" << endl; inst_helper(d_bvs.size()); return build_tree(); } void recCompleteInster::inst_helper(int num_vars){ if (1 == num_vars){ for (set::const_iterator i = d_all_index.begin(), iend = d_all_index.end(); i != iend; i++ ){ d_buff[num_vars-1] = *i; d_exprs.push_back(d_body.substExpr(d_bvs,d_buff)); } } else{ for (set::const_iterator i = d_all_index.begin(), iend = d_all_index.end(); i != iend; i++ ){ d_buff[num_vars-1] = *i; inst_helper(num_vars-1); } } } Expr& recCompleteInster::build_tree() { std::vector& d_old = d_exprs, d_new; while (d_old.size() > 1) { int old_size = d_old.size(); for (int i = 0; i < old_size - 1; i += 2) { d_new.push_back(d_old[i].andExpr(d_old[i + 1])); } if (old_size % 2 == 1) { d_new.push_back(d_old[old_size - 1]); } d_old.clear(); d_old.swap(d_new); } if (d_old.size() > 0) d_result = d_result.andExpr(d_old[0]); d_old.clear(); return d_result; } Expr CompleteInstPreProcessor::inst(const Expr& assert){ if(isGround(assert)){ return assert; } else if (assert.isExists()){ DebugAssert(d_quant_equiv_map.count(assert) > 0,"assert not found" ) ; return d_quant_equiv_map[assert]; } else if( ! assert.isForall()){ if (assert.arity() > 0){ vector children; for (int i = 0 ; i < assert.arity(); i++){ Expr rep_child; rep_child = inst(assert[i]); children.push_back(rep_child); } return Expr(assert.getOp(), children); } else{ DebugAssert(false, "error in inst"); return assert; } } DebugAssert(assert.isForall(), "not a forall"); DebugAssert(d_quant_equiv_map.count(assert) > 0, "assert not found" ) ; Expr forall = d_quant_equiv_map[assert]; const vector& bvs = forall.getVars(); const Expr body = forall.getBody(); vector and_list; if(d_allIndex.size() == 0){ addIndex(d_theoryCore->getEM()->newRatExpr(0)); } if(bvs.size() == 1 ) { // getBoundVars(body); for (set::const_iterator i = d_allIndex.begin(), iend = d_allIndex.end(); i != iend; i++ ){ vector inst_st; inst_st.push_back(*i); // if(body.substExprQuant(bvs,inst_st) != body.substExpr(bvs,inst_st)){ // cout << "old " << body.substExpr(bvs,inst_st) << endl ; // cout << "new " << body.substExprQuant(bvs,inst_st) << endl; // } //and_list.push_back(body.substExprQuant(bvs,inst_st)); and_list.push_back(body.substExpr(bvs,inst_st)); } return Expr(AND,and_list); } else if (bvs.size() == 2 ){ // getBoundVars(body); for (set::const_iterator i = d_allIndex.begin(), iend = d_allIndex.end(); i != iend; i++ ){ for (set::const_iterator j = d_allIndex.begin(), jend = d_allIndex.end(); j != jend; j++ ){ vector inst_st; inst_st.push_back(*i); inst_st.push_back(*j); // cout << "== " << inst_st[0] << " " << inst_st[1] << endl; // if(body.substExprQuant(bvs,inst_st) != body.substExpr(bvs,inst_st)){ // cout << "old " << body.substExpr(bvs,inst_st) << endl ; // cout << "new " << body.substExprQuant(bvs,inst_st) << endl; // } //and_list.push_back(body.substExprQuant(bvs,inst_st)); and_list.push_back(body.substExpr(bvs,inst_st)); // cout << "INST: " << body.substExpr(bvs,inst_st) << endl; } } // cout << "we have " << and_list.size() << " ands " << endl; return Expr(AND,and_list); } // else if ( 0 < bvs.size() && bvs.size() <= 5 ){ else{ Expr init_expr = d_theoryCore->trueExpr(); // cout <<"we have " << bvs.size() << endl; recCompleteInster inster(body, bvs, d_allIndex, init_expr); // cout<& results){ if (ands.isAnd()){ for(Expr::iterator i=ands.begin(), iend=ands.end(); i!=iend; ++i) { flatAnds(*i,results); } } else if (ands.isNot() && ands[0].isOr()){ for(Expr::iterator i=ands[0].begin(), iend=ands[0].end(); i!=iend; ++i) { if(i->isNot()){ flatAnds((*i)[0], results); } else{ flatAnds(i->notExpr(), results); } } } else{ results.push_back(ands); } } Theorem TheoryQuant::theoryPreprocess(const Expr& e){ // cout<<"theory process " << e << endl; // COMMENT for LFSC on 4-2-2010, Yeting // return reflexivityRule(e); if ( ! theoryCore()->getFlags()["quant-complete-inst"].getBool()){ return reflexivityRule(e); } const std::set& bvs = getBoundVars(e); if (bvs.size() <= 0){ return reflexivityRule(e); } std::vector assertList; flatAnds(e, assertList); CompleteInstPreProcessor comp_inst_proc(theoryCore(), d_rules); if (comp_inst_proc.hasMacros(assertList)){ for(size_t i = 0; i < assertList.size();i++){ // cout << "== assert: " << i << " : " << assertList[i] << endl; assertList[i] = comp_inst_proc.instMacros(assertList[i], trueExpr().notExpr().notExpr()); } } for(size_t i = 0; i < assertList.size() ; i++){ // cout << "BEFORE: " << assertList[i] << endl; assertList[i] = comp_inst_proc.simplifyQuant(assertList[i]); // cout << "AFTER: " << assertList[i] << endl; } for(size_t i = 0; i < assertList.size() ; i++){ if ( ! comp_inst_proc.isGood(assertList[i])){ // cout << " no good " << endl; // cout << " because of " << assertList[i] << endl; return reflexivityRule(e); } } for(size_t i = 0; i < assertList.size() ; i++){ // cout << "collecting " << assertList[i] << endl; comp_inst_proc.collectIndex(assertList[i]); } vector new_asserts; for(size_t i = 0; i < assertList.size() ; i++){ Expr new_asser = comp_inst_proc.inst(assertList[i]); getBoundVars(new_asser); if (new_asser.containsBoundVar()){ return reflexivityRule(e); } else{ new_asserts.push_back(new_asser); } } // vector all_index; // for(size_t i = 0; i < assertList.size() ; i++){ // collectIndex(assertList[i], all_index); // } // set inst_index; // for(size_t i = 0; i < all_index.size() ; i++){ // if (isInt(all_index[i].getType())){ // inst_index.insert(all_index[i]); // } // else{ // cout <<"strange" << all_index[i] << endl; // } // } // int j(0); // for(set::iterator i = inst_index.begin(), iend = inst_index.end(); // i != iend; i++){ // cout << "i=" << j++ << " " << *i << endl; // } // for(size_t i = 0; i < assertList.size() ; i++){ // Expr& cur_expr = assertList[i]; // if(cur_expr.isForall()){ // Expr new_inst = instIndex(cur_expr, inst_index); // assertList[i] = new_inst; // // cout << "new inst " << new_inst << endl; // } // } // for(size_t i = 0; i < assertList.size() ; i++){ // // cout << "AFTER i=" << i << " " << assertList[i] << endl; // } for(size_t i = 0; i < new_asserts.size() ; i++){ new_asserts[i] = comp_inst_proc.simplifyEq(new_asserts[i]); } for(size_t i = 0; i < new_asserts.size() ; i++){ //cout << ":assumption " << new_asserts[i] << endl; // cout << "NEW" << comp_inst_proc.inst(assertList[i]) << endl; } //this is really a bad way, add a new proof rule here Expr res = Expr(AND, new_asserts); Theorem ret_thm = d_rules->addNewConst(e.iffExpr(res)); // cout << "NEW THM " << ret_thm << endl; return ret_thm; } bool isGoodSysPredTrigger(const Expr& e){ if(!isSysPred(e)) return false; if(usefulInMatch(e[0]) || usefulInMatch(e[1])) return true; return false; } bool isGoodFullTrigger(const Expr& e, const std::vector& bVarsThm){ if( !usefulInMatch(e)) return false; const std::set& bvs = getBoundVars(e); if (bvs.size() >= bVarsThm.size()){ for(size_t i=0; i& bVarsThm, int offset){ if( !usefulInMatch(e) ) return false; int bvar_missing = 0; const std::set& bvs = getBoundVars(e); if(bvs.size() <= 0) return false; for(size_t i=0; i& bVarsThm){ if( !usefulInMatch(e) ) return false; size_t bvar_missing = 0; const std::set& bvs = getBoundVars(e); for(size_t i=0; i& res) { if(e.getFlag()) return false; if(e.isClosure()) return recursiveGetPartTriggers(e.getBody(), res); if(0 == e.arity()){ if(BOUND_VAR == e.getKind()){ return false; } else{ return true; } } bool good=true; bool no_bound =true; for(Expr::iterator i=e.begin(), iend=e.end(); i!=iend; ++i) { if(BOUND_VAR == i->getKind()){ no_bound=false; continue; } bool temp = recursiveGetPartTriggers(*i,res); if(false == temp) { good=false; } } e.setFlag(); if(good && no_bound) { return true; } else if(good && !no_bound){ res.push_back(e); return false; } else{ return false; } } std::vector getPartTriggers(const Expr& e){ e.clearFlags(); std::vector res; recursiveGetPartTriggers(e,res); e.clearFlags(); return res; } int trigInitScore(const Expr& e){ if( isSysPred(e) && !isGoodSysPredTrigger(e)){ return 1; } else { return 0; } } void TheoryQuant::arrayIndexName(const Expr& e){ std::vector res; const std::vector& subs=getSubTerms(e); for(size_t i=0; i tp = d_arrayIndic[name]; tp.push_back(index); d_arrayIndic[name]=tp; } else { } } } } void TheoryQuant::registerTrig(ExprMap* >* >& cur_trig_map, Trigger trig, const std::vector thmBVs, size_t univ_id){ { if(trig.hasRWOp){ ExprMap bv_map; dynTrig newDynTrig(trig, bv_map,univ_id); d_arrayTrigs.push_back(newDynTrig); } } ExprMap bv_map; /* for(size_t i = 0; i* >* >::iterator iter = cur_trig_map.find(head); if(cur_trig_map.end() == iter){ ExprMap* >* new_cd_map= new ExprMap* > ; cur_trig_map[head] = new_cd_map; vector* new_dyntrig_list = new vector; (*new_cd_map)[genTrig] = new_dyntrig_list; (*new_dyntrig_list).push_back(newDynTrig); } else{ ExprMap* >* cd_map = iter->second; ExprMap* >::iterator iter_map = cd_map->find(genTrig); if(cd_map->end() == iter_map){ vector* new_dyntrig_list = new vector; (*cd_map)[genTrig] = new_dyntrig_list; (*new_dyntrig_list).push_back(newDynTrig); } else{ // cout<<"never happen here" << endl; // (*((*cd_map)[generalTrig])).push_back(newDynTrig); (*(iter_map->second)).push_back(newDynTrig); } } } /* void TheoryQuant::registerTrigReal(Trigger trig, const std::vector thmBVs, size_t univ_id){ cout<<"register: "< bv_map; for(size_t i = 0; i* >* >::iterator iter = d_allmap_trigs.find(head); if(d_allmap_trigs.end() == iter){ CDMap* >* new_cd_map= new(true) CDMap* > (theoryCore()->getCM()->getCurrentContext()); d_allmap_trigs[head] = new_cd_map; CDList* new_dyntrig_list = new(true) CDList (theoryCore()->getCM()->getCurrentContext()); (*new_cd_map)[genTrig] = new_dyntrig_list; (*new_dyntrig_list).push_back(newDynTrig); } else{ CDMap* >* cd_map = iter->second; CDMap* >::iterator iter_map = cd_map->find(genTrig); if(cd_map->end() == iter_map){ CDList* new_dyntrig_list = new(true) CDList (theoryCore()->getCM()->getCurrentContext()); (*cd_map)[genTrig] = new_dyntrig_list; (*new_dyntrig_list).push_back(newDynTrig); } else{ // (*((*cd_map)[generalTrig])).push_back(newDynTrig); (*((*iter_map).second)).push_back(newDynTrig); cout<<"once more"<& bvs){ //temp fix return trig; Expr newtrig = trig; getBoundVars(newtrig); size_t count =0 ; Expr res = recGeneralTrig(trig, bvs, count); getBoundVars(res); return res; } Expr TheoryQuant::recGeneralTrig(const Expr& trig, ExprMap& bvs, size_t& mybvs_count){ if (!trig.containsBoundVar()) return trig; if (BOUND_VAR == trig.getKind()){ if (bvs.find(trig) != bvs.end()){ const Expr& ubv = bvs[trig]; if(null_expr ==ubv){ Expr new_bv = d_mybvs[mybvs_count++]; bvs[trig] = new_bv ; if((mybvs_count) >= MAX_TRIG_BVS ){ // cout<< "general trig error" < children; for(Expr::iterator i=trig.begin(), iend=trig.end(); i!=iend; ++i){ Expr repChild; if(i->containsBoundVar()){ repChild = recGeneralTrig(*i, bvs, mybvs_count); } else{ repChild = *i; } children.push_back(repChild); } return Expr(trig.getOp(), children); } } */ //this function is used to check if two triggers can match with eath other bool TheoryQuant::canMatch(const Expr& t1, const Expr& t2, ExprMap& env){ if(getBaseType(t1) != getBaseType(t2)) return false; if (BOUND_VAR == t1.getKind() || BOUND_VAR == t2.getKind()) { return true; } if ( (t1.arity() != t2.arity()) || (t1.getKind() != t2.getKind() )) { return false; } if (canGetHead(t1) && canGetHead(t2)) { if ( getHead(t1) != getHead(t2) ){ return false; } for(int i=0; i& cur_trig){ if(!(*d_useTrans)){ return false; } if(3==cur_trig.size()){ const Expr& t1=cur_trig[0]; const Expr& t2=cur_trig[1]; const Expr& t3=cur_trig[2]; if ( canGetHead(t1) && canGetHead(t2) && canGetHead(t3) && (getHead(t1) == getHead(t2)) && (getHead(t2) == getHead(t3))){ const std::set& ts1 = getBoundVars(t1); const std::set& ts2 = getBoundVars(t2); const std::set& ts3 = getBoundVars(t3); if ( 2==ts1.size() && 2==ts2.size() && 2==ts2.size() && (ts1 != ts2) && (ts2 != ts3) && (ts3 != ts1)){ std::set all; for(set::const_iterator i=ts1.begin(), iend = ts1.end(); i != iend; i++){ all.insert(*i); } for(set::const_iterator i=ts2.begin(), iend = ts2.end(); i != iend; i++){ all.insert(*i); } for(set::const_iterator i=ts3.begin(), iend = ts3.end(); i != iend; i++){ all.insert(*i); } bool res = true; if(3==all.size()){ for(set::const_iterator i=all.begin(), iend = all.end(); i != iend; i++){ if(!i->isVar()) { res = false; break; } } if(res) { } return res; } } } } return false; } bool TheoryQuant::isTrans2Like (const std::vector& all_terms, const Expr& tr2){ if(!(*d_useTrans2)){ return false; } for(size_t i = 0; i < all_terms.size(); i++){ if(all_terms[i].isEq()){ const Expr& cur = all_terms[i]; if(cur[0] != cur[1] && ( (cur[0]==tr2[0] && cur[1]==tr2[1]) || (cur[0]==tr2[1] && cur[1]==tr2[0]))){ return true; } } } return false; } bool goodMultiTriggers(const std::vector& exprs, const std::vector bVars){ ExprMap bvar_found; for( std::vector::const_iterator i = bVars.begin(), iend= bVars.end(); i!=iend; i++) { bvar_found[*i]=false; } for (size_t i=0; i< exprs.size();i++){ const std::set & bv_in_trig = getBoundVars(exprs[i]); for(std::set::const_iterator j=bv_in_trig.begin(), jend = bv_in_trig.end(); j != jend; j++){ if(bvar_found.find(*j) != bvar_found.end()){ bvar_found[*j]=true; } } } for( std::vector::const_iterator i = bVars.begin(), iend= bVars.end(); i!=iend; i++) { if(false == bvar_found[*i]){ return false ; } } return true; } inline size_t locVar(const vector& bvsThm, const Expr& bv){ for(size_t i=0, iend = bvsThm.size(); i < iend; i++){ if (bvsThm[i] == bv){ return i; } } return 999; //this number should be big enough } void TheoryQuant::setupTriggers(ExprMap* >*>& trig_maps, const Theorem& thm, size_t univs_id){ // static std::vector libQuant; const Expr& e = thm.getExpr(); TRACE("triggers", "setup : "+int2string(e.getIndex()), " | " , e.toString()); d_univs.push_back(thm); const std::vector& bVarsThm = e.getVars(); if (d_hasTriggers.count(e) > 0 ) { if(d_fullTrigs.count(e)>0){ std::vector& new_trigs = d_fullTrigs[e]; for(size_t i=0; i 0){ if( d_multTrigs.count(e) > 0){ std::vector& new_mult_trigs = d_multTrigs[e]; for(size_t j=0; j 0) { // cout<<"manual trig found"<& subterms = getSubTrig(e); const std::vector subterms = getSubTrig(e); // #ifdef _CVC3_DEBUG_MODE // if( CVC3::debugger.trace("triggers") ){ // cout<<"===========all sub terms =========="<getKindName(sub.getKind()) << endl; // } // } // #endif ExprMap exprPol; findPolarity(e, exprPol, Pos); {// for full triggers std::vector trig_list; std::vector trig_cadt; for(std::vector::const_iterator i = subterms.begin(),iend=subterms.end(); i!=iend; i++){ if(isGoodFullTrigger(*i, bVarsThm)) { trig_cadt.push_back(*i); } } if(*d_useManTrig && e.getTriggers().size() > 0 ){ std::vector > man_trigs = e.getTriggers(); for(std::vector >::const_iterator i=man_trigs.begin(), iend=man_trigs.end(); i != iend; i++){ if(1 == i->size()){ if (isGoodFullTrigger((*i)[0],bVarsThm)){ trig_list.push_back((*i)[0]); // cout<<"full manual pushed "<<(*i)[0] << endl; } else{ // cout<<"full manual discarded "<<(*i)[0] << endl; } } // else if(2 == i->arity()){ else if(2 == i->size()){ if (isGoodFullTrigger((*i)[0], bVarsThm) && isGoodFullTrigger((*i)[1], bVarsThm)){ trig_list.push_back((*i)[0]); trig_list.push_back((*i)[1]); break; // it must be trans2like } } } } else{ for(size_t iter =0; iter < trig_cadt.size(); iter++) { Expr* i = &(trig_cadt[iter]); bool notfound = true; for(size_t index=0; index< trig_list.size(); index++){ if (i->subExprOf(trig_list[index])) { trig_list[index]=*i; notfound=false; break; } if (trig_list[index].subExprOf(*i)) { notfound=false; break; } } if (notfound) { trig_list.push_back(*i); } } } std::vector trig_ex; for (size_t i=0; i< trig_list.size();i++){ const Expr& cur = trig_list[i]; const std::set cur_bvs = getBoundVars(cur); int score = trigInitScore(cur); if(score > 0) continue; //1. test trans2 //2. test whether a trigger can trig a bigger instance of itself, now we have no actions for such case because we use expr score and dynamic loop prevention. for(size_t j=0; j< trig_cadt.size(); j++){ if (trig_list[i] == trig_cadt[j]) continue; ExprMap null; if (canMatch(trig_list[i], trig_cadt[j], null)){ if(exprScore(trig_list[i]) < exprScore(trig_cadt[j])){ } else if(*d_useTrans2 && trig_list.size() == 2 && trig_list[i].arity() == 2 && BOUND_VAR == trig_list[i][0].getKind() && BOUND_VAR == trig_list[i][1].getKind() && BOUND_VAR == trig_cadt[j][0].getKind() && BOUND_VAR == trig_cadt[j][1].getKind() && isTrans2Like(subterms, trig_list[i]) ){ score =0; //useless, to delete; d_trans2_num++; DebugAssert(d_trans2_num<=1, "more than 2 trans2 found"); TRACE("triggers", "trans2 found ", trig_list[i], ""); Trigger t(theoryCore(), cur, Neg, cur_bvs); t.setTrans2(true); t.setHead(getHeadExpr(cur)); if(isSimpleTrig(cur)){ t.setSimp(); } if(isSuperSimpleTrig(cur)){ t.setSuperSimp(); } d_fullTrigs[e].push_back(t); registerTrig(trig_maps,t, bVarsThm, univs_id); return; } else{ score =0; } } } Polarity pol= Ukn; if(cur.getType().isBool()){ DebugAssert(exprPol.count(e)>0,"unknown polarity:"+cur.toString()); pol = exprPol[cur]; } Trigger* t; Trigger* t_ex; //so, if a pred is PosNeg, we actually put two triggers into the list, one pos and the other neg if(PosNeg == pol && *d_usePolarity){ t = new Trigger(theoryCore(), cur, Pos, cur_bvs); t_ex = new Trigger(theoryCore(), cur, Neg, cur_bvs); if(isSimpleTrig(cur)){ t->setSimp(); t_ex->setSimp(); } if(isSuperSimpleTrig(cur)){ t->setSuperSimp(); t_ex->setSuperSimp(); } } else{ t = new Trigger(theoryCore(), cur, pol, cur_bvs); if(isSimpleTrig(cur)){ t->setSimp(); } if(isSuperSimpleTrig(cur)){ t->setSuperSimp(); } t_ex = NULL; } if(canGetHead(cur)) { t->setHead(getHeadExpr(cur)); if(NULL != t_ex){ t_ex->setHead(getHeadExpr(cur)); } } else{ if(!isSysPred(cur)){ // cout<<"cur " << cur <setRWOp(false); if(READ == cur.getKind() || WRITE == cur.getKind()){ arrayIndexName(cur); } if(READ == cur.getKind() && WRITE== cur[0].getKind() && 1 == bVarsThm.size() ){ // cout<trig<setRWOp(true); if(t_ex != NULL) t_ex->setRWOp(true); } if(t_ex != NULL) { trig_ex.push_back(*t_ex); } d_fullTrigs[e].push_back(*t); registerTrig(trig_maps,*t, bVarsThm, univs_id); TRACE("triggers", "new:full triggers:", cur.toString(),""); TRACE("triggers", "new:full trigger score:", score,""); TRACE("triggers", "new:full trigger pol:", pol,""); } if(e.getTriggers().size() > 0) { // cout<<"#### manual_trig: "; // cout<& cur_trig = d_multTriggers[e]; if(*d_useManTrig && e.getTriggers().size() > 0 ){ std::vector > man_trig = e.getTriggers(); int count(0); for(std::vector >::const_iterator i = man_trig.begin(), iend = man_trig.end(); i != iend; i++){ // if (i->arity() > 1) count++; if (i->size() > 1) count++; // cout << "count" << count << " " << *i << endl; } /* if(count > 1){ //cout<<"en, cannot handle this now"<::const_iterator j = man_trig[count-1].begin(), jend = man_trig[count-1].end(); j != jend; ++j){ cur_trig.push_back(*j); } if (! goodMultiTriggers(cur_trig, bVarsThm)){ cur_trig.clear(); return; } } } else{ for( std::vector::const_iterator i = subterms.begin(), iend=subterms.end(); i!=iend; i++) { if(isGoodMultiTrigger(*i, bVarsThm, d_offset_multi_trig)) { bool notfound = true; for(size_t index=0; indexsubExprOf(d_multTriggers[e][index])) { (d_multTriggers[e][index])=*i; notfound=false; } } if (notfound){ d_multTriggers[e].push_back(*i); } } } if (goodMultiTriggers(cur_trig, bVarsThm)){ // cout<<"good multi triggers"<setHead(getHeadExpr(ex)); if(isSimpleTrig(ex)){ trans_trig->setSimp(); } if(isSuperSimpleTrig(ex)){ trans_trig->setSuperSimp(); } trans_trig->setTrans(true); d_fullTrigs[e].push_back(*trans_trig); registerTrig(trig_maps,*trans_trig, bVarsThm, univs_id); cur_trig.clear(); TRACE("triggers", " trans like found ", ex, ""); d_transThm = thm; } } //enhanced multi-triggers // if(cur_trig.size() >0 && !(*d_useManTrig)){ if(cur_trig.size() >0 ){ // if(cur_trig.size() >0 ){ std::vector posList, negList; for(size_t k=0; k tempList; tempList.clear(); tempList.push_back(cur_trig[i]); tempList.push_back(cur_trig[j]); // cout< bvs = getBoundVars(cur_trig[i]); Trigger trig(theoryCore(), cur_trig[i], Ukn, bvs); // // cout<<"new way of multi-trig"<& one_set_bvs = d_multTrigs[e][i].bvs; std::vector one_set_pos; for(size_t v = 0, vend = one_set_bvs.size(); v common; std::vector& tar1 = multTrigs.var_pos[0]; std::vector& tar2 = multTrigs.var_pos[1]; vector::iterator t1(tar1.begin()), t2(tar2.begin()); while(t1 != tar1.end() && t2!= tar2.end()){ size_t pos1 = *t1; size_t pos2 = *t2; if( pos1 == pos2 ) { common.push_back(pos1); t1=tar1.erase(t1); t2=tar2.erase(t2); } else if( pos1 > pos2 ){ t2++; } else { t1++; } } multTrigs.common_pos.push_back(common); size_t multi_size = d_multTrigs[e].size(); //should be 2 for(size_t i =0; i< multi_size; i++){ multTrigs.var_binds_found.push_back(new (true) CDMap (theoryCore()->getCM()->getCurrentContext())); } multTrigs.uncomm_list.push_back(new ExprMap* >); multTrigs.uncomm_list.push_back(new ExprMap* >); multTrigs.univThm = thm; multTrigs.univ_id = univs_id; d_multitrigs_maps[e] = multTrigs; d_all_multTrigsInfo.push_back(multTrigs); } } } /* //setup partial triggers if(*d_usePart) { std::vector trig_ex; trig_ex.clear(); for( std::vector::const_iterator i = subterms.begin(), iend=subterms.end(); i!=iend; i++) { if(isGoodPartTrigger(*i, bVarsThm)) { bool notfound = true; for(size_t index=0; indexsubExprOf(d_partTriggers[e][index])) { (d_partTriggers[e][index])=*i; notfound=false; } } if (notfound) d_partTriggers[e].push_back(*i); } } for (size_t i=0; i< d_partTriggers[e].size();i++){ TRACE("triggers", "partial triggers:", d_partTriggers[e][i].toString(),""); } for (size_t i=0; i< d_partTriggers[e].size();i++){ Polarity pol= Ukn; const Expr& cur = d_partTriggers[e][i]; const std::set cur_bvs = getBoundVars(cur); if(cur.getType().isBool()){ DebugAssert(exprPol.count(e)>0,"unknown polarity:"+cur.toString()); pol = exprPol[cur]; } Trigger* t; Trigger* t_ex; //so, if a pred is PosNeg, we actually put two triggers into the list, one pos and the other neg if(PosNeg == pol && *d_usePolarity){ t = new Trigger(theoryCore(), cur, Pos, cur_bvs); t_ex = new Trigger(theoryCore(), cur, Neg, cur_bvs); } else{ t = new Trigger(theoryCore(), cur, pol, cur_bvs); t_ex = NULL; } if(canGetHead(cur)) { t->setHead(getHeadExpr(cur)); } if(t_ex != NULL) trig_ex.push_back(*t_ex); d_partTrigs[e].push_back(*t); TRACE("triggers", "new:part trigger pol:", pol,cur.toString()); } for(size_t i=0; i& bvsOutmost = thm.getVars(); const std::set& bvs = getBoundVars(thm); return int(bvs.size()-bvsOutmost.size()); } /*! \brief Theory interface function to assert quantified formulas * * pushes in negations and converts to either universally or existentially * quantified theorems. Universals are stored in a database while * existentials are enqueued to be handled by the search engine. */ //static ExprMap found_exist; void TheoryQuant::assertFact(const Theorem& thm){ if(d_maxILReached){ return; } if(*d_translate) return; TRACE("quant assertfact", "assertFact => ", thm.toString(), "{"); Theorem rule, result; const Expr& expr = thm.getExpr(); // Ignore existentials if(expr.isExists()) { TRACE("quant assertfact", "assertFact => (ignoring existential) }", expr.toString(), ""); return; } DebugAssert(expr.isForall() || (expr.isNot() && (expr[0].isExists() || expr[0].isForall())), "Theory of quantifiers cannot handle expression " + expr.toString()); if(expr.isNot()) {//find the right rule to eliminate negation if(expr[0].isForall()) { rule = d_rules->rewriteNotForall(expr); } else if(expr[0].isExists()) { rule = d_rules->rewriteNotExists(expr); } result = iffMP(thm, rule); } else{ result = thm; } result = d_rules->boundVarElim(result); //eliminate useless bound variables if(result.getExpr().isForall()){ // Added by Clark: // If domain of quantified variable is finite and not too big, just do complete instantiation const vector& vars = result.getExpr().getVars(); Unsigned u, count = 1; Cardinality card; vector::const_iterator it = vars.begin(), iend = vars.end(); for (; it != iend; ++it) { card = (*it).getType().card(); if (card != CARD_FINITE) { count = 0; break; } u = (*it).getType().sizeFinite(); if (u > 100) u = 0; count = count * u; if (count == 0 || count > 100) { count = 0; break; } } bool incomplete = false; if (count > 0 && count <= 100) { vector terms(vars.size()); vector indices(vars.size()); for (unsigned i = 0; i < vars.size(); ++i) { indices[i] = 0; terms[i] = vars[i].getType().enumerateFinite(0); if (terms[i].isNull()) { incomplete = true; break; } } Theorem thm; unsigned i = 0; for (;;) { thm = d_rules->universalInst(result, terms, 0); enqueueFact(thm); while (i < indices.size()) { indices[i] = indices[i] + 1; if (indices[i] < vars[i].getType().sizeFinite()) { terms[i] = vars[i].getType().enumerateFinite(indices[i]); if (terms[i].isNull()) { incomplete = true; i = indices.size(); } break; } ++i; } if (i > 0) { if (i == indices.size()) break; for (unsigned j = 0; j < i; ++j) { indices[j] = 0; terms[j] = vars[j].getType().enumerateFinite(0); } i = 0; } } if (!incomplete) return; } if(*d_useNew){ if(result.getExpr().getBody().isForall()){ // if it is of the form forall x. forall. y // COMMENT for LFSC on 4-3-2010, Yeting result=d_rules->packVar(result); } result = d_rules->boundVarElim(result); //eliminate useless bound variables // int nBVs = hasMoreBVs(result.getExpr()); // if( nBVs >= 1){ // d_hasMoreBVs[result.getExpr()]=true; // } if(result.getExpr().isForall()){ d_rawUnivs.push_back(result); } else{ enqueueFact(result); } return; /* -------------------------------------- */ // int nBVs = hasMoreBVs(result.getExpr()); /* if(0 == nBVs){//good TRACE("quant assertfact", "assertFact => forall enqueueing: ", result.toString(), "}"); d_univs.push_back(result); setupTriggers(result, d_univs.size()-1); } else if(1== nBVs){ d_hasMoreBVs[result.getExpr()]=true; const Expr& body = result.getExpr().getBody(); if(*d_usePullVar){ if((body.isAnd() && body[1].isForall()) || (body.isImpl() && body[1].isForall()) ){ result=d_rules->pullVarOut(result); TRACE("quant assertfact", "assertFact => pull-var enqueueing: ", result.toString(), "}"); d_univs.push_back(result); setupTriggers(result, d_univs.size()-1); } } else{ TRACE("quant assertfact", "debug:not recognized case", result.toString(), thm.toString()); d_univs.push_back(result); setupTriggers(result, d_univs.size()-1); return; } } else{ d_hasMoreBVs[result.getExpr()]=true; d_univs.push_back(result); setupTriggers(result, d_univs.size()-1); return; } */ } else{ TRACE("quant assertfact", "assertFact => old-fashoin enqueueing: ", result.toString(), "}"); // cout<<"error"< non-forall enqueueing: ", result.toString(), "}"); if(*d_useGFact || true ){ // addGlobalLemma(result, -1); enqueueFact(result); } else{ enqueueFact(result); // enqueueSE(result); } /* { Expr expr = result.getExpr(); if(expr.isNot()) { expr = expr[0]; } ; if (expr.isExists()){ if(found_exist.find(expr) != found_exist.end()) { // cout<<"again " << expr<& bVars, std::vector& newInst, std::set >& instSet) { size_t curPos = newInst.size(); if (bVars.size() == curPos) { Expr simpleExpr = simplifyExpr(e.substExpr(bVars,newInst)); if (simpleExpr.hasFind()){ std::vector temp = newInst; instSet.insert(temp); TRACE("quant yeting", "new inst found for ", e.toString()+" ==> ", simpleExpr.toString()); }; } else { Type t = getBaseType(bVars[curPos]); std::vector tyExprs= d_typeExprMap[t]; if (0 == tyExprs.size()) { return;//has some problem } else{ for (size_t i=0;i* >::iterator iter; for(int i=0; i< parent.arity(); i++){ const Expr& child = parent[i]; iter = d_parent_list.find(child); if(d_parent_list.end() == iter){ d_parent_list[child] = new(true) CDList (theoryCore()->getCM()->getCurrentContext()) ; d_parent_list[child]->push_back(parent); } else{ iter->second->push_back(parent); } } } void TheoryQuant::collectChangedTerms(CDList& changed){ ExprMap eqs_hash; ExprMap changed_hash; /* { for(ExprMap* >::iterator iter = d_eq_list.begin(), iter_end=d_eq_list.end(); iter != iter_end; iter++){ CDList* cur_eqs = iter->second; int begin_pos; Expr head = iter->first; if(d_eq_pos.find(head) == d_eq_pos.end()){ begin_pos=0; d_eq_pos[head]= new(true) CDO(theoryCore()->getCM()->getCurrentContext(), 0, 0); } else{ begin_pos = *(d_eq_pos[head]); } for(size_t i=begin_pos; isize(); i++){ eqs_hash[(*cur_eqs)[i]]=true; } (d_eq_pos[head])->set(cur_eqs->size()); } }*/ for(size_t i=d_eqs_pos; i::iterator iter = eqs_hash.begin(), iter_end = eqs_hash.end(); iter != iter_end; iter++){ const Expr& cur_ex = iter->first; ExprMap* >::iterator iter_parent = d_parent_list.find(cur_ex); if(d_parent_list.end() != iter_parent){ CDList* cur_parents = iter_parent->second; for(size_t i=0; isize(); i++){ changed_hash[(*cur_parents)[i]]=true; } } } } { for(ExprMap::iterator iter = changed_hash.begin(), iter_end = changed_hash.end(); iter != iter_end; iter++){ changed.push_back(iter->first); } } } /* inline bool TheoryQuant::matchChild(const Expr& gterm, const Expr& vterm, ExprMap& env){ cout<<"error, should not be called, matchChild" << endl; if(gterm.arity() != vterm.arity()) { return false; } for(int i = 0 ; i< gterm.arity(); i++){ //we should make the matching "flat" const Expr& cur_v = vterm[i]; const Expr& cur_g = gterm[i]; if(BOUND_VAR == cur_v.getKind()){ ExprMap::iterator p = env.find(cur_v); if ( p != env.end()){ if (simplifyExpr(cur_g) != simplifyExpr(p->second)){ return false; } } else { env[cur_v] = simplifyExpr(cur_g); } } else if (!cur_v.containsBoundVar()){ if(simplifyExpr(cur_v) != simplifyExpr(cur_g)){ return false; } } else{ if (false == recSynMatch(cur_g, cur_v, env)){ return false; } } } return true; } inline void TheoryQuant::matchChild(const Expr& gterm, const Expr& vterm, vector >& binds){ cout<<"-error, should not be called more, matchChild" << endl; ExprMap env; if(gterm.arity() != vterm.arity()) { return; } for(int i = 0 ; i< gterm.arity(); i++){ const Expr& cur_v = vterm[i]; const Expr& cur_g = gterm[i]; if(BOUND_VAR == cur_v.getKind()){ ExprMap::iterator p = env.find(cur_v); if ( p != env.end()){ if (simplifyExpr(cur_g) != simplifyExpr(p->second)){ return; } } else { env[cur_v] = simplifyExpr(cur_g); } } else if (!cur_v.containsBoundVar()){ if(simplifyExpr(cur_v) != simplifyExpr(cur_g)){ return ; } } else{ if (false == recSynMatch(cur_g, cur_v, env)){ return; } } } binds.push_back(env); return; } */ /* multMatchChild input : partial bindings in binds output: successful bindings in binds */ inline bool TheoryQuant::multMatchChild(const Expr& gterm, const Expr& vterm, vector >& binds, bool top){ if(gterm.arity() != vterm.arity()) { TRACE("multmatch", "not same kind", gterm , vterm); return false; } // if (binds.size()>1) {cout<<"match child >1 " < allGterms; allGterms.push_back(gterm); if(!gterm.getSig().isNull() ){ Expr gtermSig = gterm.getSig().getRHS(); if(!top && gterm.hasFind() && !gterm.isAtomicFormula() ) { Expr curCandidateGterm = gterm.getEqNext().getRHS(); while (curCandidateGterm != gterm){ if(getHead(curCandidateGterm) == getHead(gterm) && !curCandidateGterm.getSig().isNull() && curCandidateGterm.getSig().getRHS() != gtermSig && getExprScore(curCandidateGterm) <= d_curMaxExprScore ){ allGterms.push_back(curCandidateGterm); } curCandidateGterm = curCandidateGterm.getEqNext().getRHS(); } } } vector > returnBinds; for(size_t curGtermIndex =0; curGtermIndex < allGterms.size(); curGtermIndex++) { vector > currentBinds(binds); if(0 == currentBinds.size()){//we need something to work on, even it is empty ExprMap emptyEnv; currentBinds.push_back(emptyEnv); } Expr gterm = allGterms[curGtermIndex]; //be careful, this gterm hides the gterm in the beginning. fix this soon vector > nextBinds; for(int i = 0 ; i< gterm.arity(); i++){ const Expr& curVterm = vterm[i]; const Expr& curGterm = gterm[i]; for(size_t curEnvIndex =0; curEnvIndex < currentBinds.size(); curEnvIndex++){ //maybe we should exchange the iteration of ith child and curentBinds. ExprMap& curEnv(currentBinds[curEnvIndex]); if(BOUND_VAR == curVterm.getKind()){ ExprMap::iterator iterVterm = curEnv.find(curVterm); if ( iterVterm != curEnv.end()){ if (simplifyExpr(curGterm) == simplifyExpr(iterVterm->second)){ nextBinds.push_back(curEnv); //success, record the good binding } //else do nothing } else { curEnv[curVterm] = simplifyExpr(curGterm); nextBinds.push_back(curEnv); // success, record the good binding } } else if (!curVterm.containsBoundVar()){ if(simplifyExpr(curVterm) == simplifyExpr(curGterm)){ nextBinds.push_back(curEnv); // sueecess, record the good } //else do nothing } else{ vector > newBinds; newBinds.push_back(curEnv); bool goodChild = recMultMatch(curGterm, curVterm, newBinds); if(goodChild){ for(vector >::iterator i = newBinds.begin(), iend = newBinds.end(); i != iend; i++){ nextBinds.push_back(*i); } } } } currentBinds = nextBinds; //nextBinds are good bindings nextBinds.clear(); } for(size_t curBindsIndex=0; curBindsIndex < currentBinds.size(); curBindsIndex++){ returnBinds.push_back(currentBinds[curBindsIndex]); } } // binds = currentBinds; binds = returnBinds; return (binds.size() > 0) ? true : false; } //multMatchTop can be called anywhere inline bool TheoryQuant::multMatchTop(const Expr& gterm, const Expr& vterm, vector >& binds){ vector > currentBinds(binds); if(0 == currentBinds.size()){//we need something to work on, even it is empty ExprMap emptyEnv; currentBinds.push_back(emptyEnv); } vector > nextBinds; const Expr& curVterm = vterm; const Expr& curGterm = gterm; for(size_t curEnvIndex =0; curEnvIndex < currentBinds.size(); curEnvIndex++){ ExprMap& curEnv(currentBinds[curEnvIndex]); vector > newBinds; newBinds.push_back(curEnv); bool goodChild = recMultMatch(curGterm, curVterm, newBinds); if(goodChild){ for(vector >::iterator i = newBinds.begin(), iend = newBinds.end(); i != iend; i++){ nextBinds.push_back(*i); } } } binds = nextBinds; //nextBinds stores the good bindings return (binds.size() > 0) ? true : false; } //match a gterm against all the trigs in d_allmap_trigs void TheoryQuant::matchListOld(const CDList& glist, size_t gbegin, size_t gend){ for(size_t g_index = gbegin; g_index < gend; g_index++){ const Expr& gterm = glist[g_index]; // cout<<"matching old "<* > *>::iterator iter = d_allmap_trigs.find(head); if(d_allmap_trigs.end() == iter) continue; CDMap*>* cd_map = iter->second; // if(cd_map->size()>10){ // cout<<"map size1:"<size()<*>::iterator iter_trig = (*cd_map).begin(); CDMap*>::iterator iter_trig_end = (*cd_map).end(); for(;iter_trig != iter_trig_end; iter_trig++){ CDList* cur_list = (*iter_trig).second; if(1 == cur_list->size() || null_expr == head || gterm.getType().isBool() ){ for(size_t cur_index =0; cur_index < cur_list->size(); cur_index++){ const Trigger& cur_trig = (*cur_list)[cur_index].trig; size_t univ_id = (*cur_list)[cur_index].univ_id; vector > binds; const Expr& vterm = cur_trig.trig; if(vterm.getKind() != gterm.getKind()) continue; // if(*d_useNewEqu){ // if ( d_allout && cur_trig.isSuperSimple ) continue; //delete this after test yeting // } if ( d_allout && cur_trig.isSuperSimple && !cur_trig.hasTrans && !cur_trig.isMulti) continue; // if ( d_allout && cur_trig.isSimple ) continue; newTopMatch(gterm, vterm, binds, cur_trig); for(size_t i=0; i& cur_map = binds[i]; vector bind_vec; const vector& bVarsThm = d_univs[univ_id].getExpr().getVars(); for(size_t j=0; j< bVarsThm.size(); j++){ bind_vec.push_back(cur_map[bVarsThm[j]]); } synNewInst(univ_id, bind_vec, gterm, cur_trig); } } } else if ( cur_list->size() > 1){ const Trigger& cur_trig = (*cur_list)[0].trig;//here we have a polarity problem const Expr& general_vterm = (*iter_trig).first; // cout<<"matching new trig case 2:"< > binds; // if(*d_useNewEqu){ // if ( d_allout && cur_trig.isSuperSimple ) continue; //delete this after test yeting // } if ( d_allout && cur_trig.isSuperSimple && !cur_trig.hasTrans && !cur_trig.isMulti) continue; //if ( d_allout && cur_trig.isSimple ) continue; newTopMatch(gterm, general_vterm, binds, cur_trig); for(size_t bindsIndex = 0 ; bindsIndex < binds.size() ; bindsIndex++){ // cout<<"i = " << bindsIndex << " : " << exprMap2string(binds[bindsIndex]) << endl ; } if(binds.size() <= 0) continue; for(size_t trig_index = 0; trig_index< cur_list->size(); trig_index++){ size_t univ_id = (*cur_list)[trig_index].univ_id; const ExprMap& trig_map = (*cur_list)[trig_index].binds; const Trigger& ind_cur_trig = (*cur_list)[trig_index].trig; for(size_t i=0; i& cur_map = binds[i]; vector bind_vec; const vector& bVarsThm = d_univs[univ_id].getExpr().getVars(); for(size_t j=0; j< bVarsThm.size(); j++){ const Expr& inter=(*(trig_map.find(bVarsThm[j]))).second; const Expr& inter2 = cur_map[inter]; bind_vec.push_back(inter2); } // cout<<"==++ for instantiation " << d_univs[univ_id] <*>*>& new_trigs){ //return; ExprMap*>*>::iterator i = new_trigs.begin(); ExprMap*>*>::iterator iend = new_trigs.end(); for(; i!=iend; i++){ ExprMap*>* cur_new_cd_map = i->second; ExprMap* >::iterator j = cur_new_cd_map->begin(); ExprMap* >::iterator jend = cur_new_cd_map->end(); for(; j!=jend; j++){ Expr general_trig = j->first; vector* trigs = j->second; delete trigs; } delete cur_new_cd_map; } new_trigs.clear(); } void TheoryQuant::combineOldNewTrigs(ExprMap*>*>& new_trigs){ ExprMap*>*>::iterator i = new_trigs.begin(); ExprMap*>*>::iterator iend = new_trigs.end(); for(; i!=iend; i++){ ExprMap*>* cur_new_cd_map = i->second; Expr head = i->first; ExprMap* >* >::iterator old_iter = d_allmap_trigs.find(head); if(d_allmap_trigs.end() == old_iter){ CDMap* >* old_cd_map = // new(true) CDMap* > (theoryCore()->getCM()->getCurrentContext()); new(false) CDMap* > (theoryCore()->getCM()->getCurrentContext()); d_allmap_trigs[head] = old_cd_map; ExprMap* >::iterator j = cur_new_cd_map->begin(); ExprMap* >::iterator jend = cur_new_cd_map->end(); for(; j!=jend; j++){ Expr general_trig = j->first; vector* trigs = j->second; CDList* old_cd_list = //new(true) CDList (theoryCore()->getCM()->getCurrentContext()); new(false) CDList (theoryCore()->getCM()->getCurrentContext()); (*old_cd_map)[general_trig] = old_cd_list; for(size_t k=0; ksize(); k++){ (*old_cd_list).push_back((*trigs)[k]); // cout<<"combined 1 "<<(*trigs)[k].trig.getEx()<* >* old_cd_map = old_iter->second; ExprMap*>::iterator j = cur_new_cd_map->begin(); ExprMap*>::iterator jend = cur_new_cd_map->end(); for(; j!=jend; j++){ Expr general_trig = j->first; vector* trigs = j->second; CDMap* >::iterator old_trigs_iter = old_cd_map->find(general_trig); CDList* old_cd_list; if(old_cd_map->end() == old_trigs_iter){ old_cd_list = //new(true) CDList (theoryCore()->getCM()->getCurrentContext()); new(false) CDList (theoryCore()->getCM()->getCurrentContext()); (*old_cd_map)[general_trig] = old_cd_list; } else{ old_cd_list = (*old_trigs_iter).second; } for(size_t k=0; ksize(); k++){ (*old_cd_list).push_back((*trigs)[k]); // cout<<"combined 2 "<<(*trigs)[k].trig.getEx()<*>*>& new_trigs, const CDList& glist, size_t gbegin, size_t gend){ //return; // if(!d_allout) return; for(size_t g_index = gbegin; g_index* > *>::iterator iter = new_trigs.find(head); if(new_trigs.end() == iter) continue; ExprMap*>* cd_map = iter->second; // if(cd_map->size()>10){ // cout<<"map size2:"<size()<*>::iterator iter_trig = (*cd_map).begin(); ExprMap*>::iterator iter_trig_end = (*cd_map).end(); for(;iter_trig != iter_trig_end; iter_trig++){ vector* cur_list = (*iter_trig).second; if(1 == cur_list->size() || null_expr == head || gterm.getType().isBool() ){ for(size_t cur_index =0; cur_index < cur_list->size(); cur_index++){ const Trigger& cur_trig = (*cur_list)[cur_index].trig; // if(*d_useNewEqu){ // if ( d_allout && cur_trig.isSuperSimple ) continue; //delete this after test yeting // } if ( d_allout && cur_trig.isSuperSimple && !cur_trig.hasTrans) continue; size_t univ_id = (*cur_list)[cur_index].univ_id; vector > binds; const Expr& vterm = cur_trig.trig; if(vterm.getKind() != gterm.getKind()) continue; newTopMatch(gterm, vterm, binds, cur_trig); for(size_t i=0; i& cur_map = binds[i]; vector bind_vec; const vector& bVarsThm = d_univs[univ_id].getExpr().getVars(); for(size_t j=0; j< bVarsThm.size(); j++){ bind_vec.push_back(cur_map[bVarsThm[j]]); } synNewInst(univ_id, bind_vec, gterm, cur_trig); } } } else if ( cur_list->size() > 1){ const Trigger& cur_trig = (*cur_list)[0].trig;//here we have a polarity problem // if(*d_useNewEqu){ // if ( d_allout && cur_trig.isSuperSimple ) continue; //delete this after test yeting // } // if ( d_allout && cur_trig.isSuperSimple && !cur_trig.hasTrans) continue; const Expr& general_vterm = (*iter_trig).first; if(general_vterm.getKind() != gterm.getKind()) continue; vector > binds; newTopMatch(gterm, general_vterm, binds, cur_trig); if(binds.size() <= 0) continue; for(size_t trig_index = 0; trig_index< cur_list->size(); trig_index++){ size_t univ_id = (*cur_list)[trig_index].univ_id; const Trigger& ind_cur_trig = (*cur_list)[trig_index].trig; const ExprMap& trig_map = (*cur_list)[trig_index].binds; for(size_t i=0; i& cur_map = binds[i]; vector bind_vec; const vector& bVarsThm = d_univs[univ_id].getExpr().getVars(); for(size_t j=0; j< bVarsThm.size(); j++){ const Expr& inter=(*(trig_map.find(bVarsThm[j]))).second; const Expr& inter2 = cur_map[inter]; bind_vec.push_back(inter2); } synNewInst(univ_id, bind_vec, gterm, ind_cur_trig); } } } else{ FatalAssert(false, "error in matchlistnew"); } }//end of for each trig begins with head }// end of each gterm } //void TheoryQuant::newTopMatchNoSig(const Expr& gtermOrg, void TheoryQuant::newTopMatchNoSig(const Expr& gterm, const Expr& vterm, vector >& binds, const Trigger& trig){ // cout<<"matching " << gterm << endl << "----" << endl << vterm << endl; if(trig.isSuperSimple){ ExprMap cur_bind; for(int i = vterm.arity()-1; i>=0 ; i--){ cur_bind[vterm[i]] = simplifyExpr(gterm[i]); } binds.push_back(cur_bind); return; } if(trig.isSimple){ ExprMap cur_bind; for(int i = vterm.arity()-1; i>=0 ; i--){ if(BOUND_VAR != vterm[i].getKind()){ if(simplifyExpr(gterm[i]) != simplifyExpr(vterm[i])) { return ; } } else{ if(getBaseType(vterm[i]) == (getBaseType(gterm[i]))){ cur_bind[vterm[i]] = simplifyExpr(gterm[i]); } else return; } } binds.push_back(cur_bind); return; } if(!isSysPred(vterm)){ //then gterm cannot be a syspred if(!gterm.getType().isBool()){ // res2= recSynMatch(gterm, vterm, env); multMatchChild(gterm, vterm, binds, true); return; } // DebugAssert(falseExpr()==findExpr(gterm) || trueExpr()==findExpr(gterm), " why "); multMatchChild(gterm, vterm, binds, true); return; if(!*d_usePolarity){ // return recSynMatch(gterm, vterm, env); multMatchChild(gterm, vterm, binds); return; } const bool gtrue = (trueExpr()==findExpr(gterm)); // const bool gtrue = (trueExpr()==simplifyExpr(gterm)); if(gtrue ){ if((Neg==trig.polarity || PosNeg==trig.polarity)) { // return recSynMatch(gterm, vterm, env); multMatchChild(gterm, vterm, binds); return; } else{ // cout<<"returned 1"< >& binds, const Trigger& trig){ //return newTopMatchSig(gtermOrg,vterm, binds, trig); return newTopMatchNoSig(gtermOrg,vterm, binds, trig); // cout<<"gterm org: " << gtermOrg << endl; // cout<<"vterm org: " << vterm << endl; // if(isPow(gtermOrg)){ // if(isIntx(gtermOrg[0],2)){ // vector mults; // mults.push_back(gtermOrg[1]); // mults.push_back(gtermOrg[1]); // cout<<"new expr" << multExpr(mults) << endl;; // } // else{ // cout <<"cannot do this"< > oldBinds; newTopMatchNoSig(gtermOrg,vterm, oldBinds, trig); vector > newBinds; newTopMatchSig(gtermOrg,vterm, newBinds, trig); vector > oldBindsBack(oldBinds); vector > newBindsBack(newBinds); simplifyVectorExprMap(oldBinds); simplifyVectorExprMap(newBinds); if (false && oldBinds != newBinds){ cout<<"let us see" << endl; cout<< "===gterm is : " << gtermOrg << endl ;; // cout<< exprChild2string(gtermOrg) << endl; // cout<< exprChild2string(gtermOrg[0]) << endl; // cout<< exprChild2string(gtermOrg[1]) << endl; if(gtermOrg.isApply() && gtermOrg.hasSig()){ Expr sig = gtermOrg.getSig().getRHS(); cout << "\n---gterm sig is: " << sig << endl; // cout << exprChild2string(sig) << endl; // cout << exprChild2string(sig[0]) << endl; // cout << exprChild2string(sig[1]) << endl; } // cout << "vterm is " << vterm << endl << exprChild2string(vterm) << endl; // cout << exprChild2string(vterm[0]) << endl; // cout << exprChild2string(vterm[1]) << endl; for(size_t oldBindsIndex = 0; oldBindsIndex < oldBinds.size(); oldBindsIndex++){ cout << "--O- " << oldBindsIndex << endl; cout << exprMap2string(oldBindsBack[oldBindsIndex]) << endl; cout << exprMap2string(oldBinds[oldBindsIndex]) << endl; cout << exprMap2stringSimplify(oldBinds[oldBindsIndex]) << endl; cout << exprMap2stringSig(oldBinds[oldBindsIndex]) << endl; } for(size_t newBindsIndex = 0; newBindsIndex < newBinds.size(); newBindsIndex++){ cout << "--N- " << newBindsIndex << endl; cout << exprMap2string(newBindsBack[newBindsIndex]) << endl; cout << exprMap2string(newBinds[newBindsIndex]) << endl; cout << exprMap2stringSimplify(newBinds[newBindsIndex]) << endl; cout << exprMap2stringSig(newBinds[newBindsIndex]) << endl; } } //binds = newBinds; // cout<<"newbinds size" << newBinds.size() << endl; binds = oldBinds; return; } void TheoryQuant::newTopMatchSig(const Expr& gtermOrg, const Expr& vterm, vector >& binds, const Trigger& trig){ // cout<<"matching " << gterm << endl << "----" << endl << vterm << endl; Expr gterm; if(gtermOrg.isApply() && gtermOrg.hasSig()){ gterm = gtermOrg.getSig().getRHS(); } else{ gterm = gtermOrg; } if(trig.isSuperSimple){ ExprMap cur_bind; for(int i = vterm.arity()-1; i>=0 ; i--){ cur_bind[vterm[i]] = simplifyExpr(gterm[i]); } binds.push_back(cur_bind); return; } if(trig.isSimple){ ExprMap cur_bind; for(int i = vterm.arity()-1; i>=0 ; i--){ if(BOUND_VAR != vterm[i].getKind()){ if(simplifyExpr(gterm[i]) != simplifyExpr(vterm[i])) { return ; } } else{ if (getBaseType(vterm[i])==getBaseType(gterm[i])){ cur_bind[vterm[i]] = simplifyExpr(gterm[i]); } else return; } } binds.push_back(cur_bind); return; } if(!isSysPred(vterm)){ //then gterm cannot be a syspred if(!gterm.getType().isBool()){ // res2= recSynMatch(gterm, vterm, env); multMatchChild(gterm, vterm, binds); return; } // DebugAssert(falseExpr()==findExpr(gterm) || trueExpr()==findExpr(gterm), " why "); // multMatchChild(gterm, vterm, binds); // return; // when man trig is enabled, we should not use polarity because the manual triggers do not have polairities. // should I fix this? if(!*d_usePolarity || d_useManTrig){ // return recSynMatch(gterm, vterm, env); multMatchChild(gterm, vterm, binds); return; } const bool gtrue = (trueExpr()==findExpr(gterm)); // const bool gtrue = (trueExpr()==simplifyExpr(gterm)); if(gtrue ){ if((Neg==trig.polarity || PosNeg==trig.polarity)) { // return recSynMatch(gterm, vterm, env); multMatchChild(gterm, vterm, binds); return; } else{ // cout<<"returned 1"< >& binds, const Trigger& trig){ cout<<"-error should not be called more, newTopMatchBackupOnly" << endl; ExprMap cur_bind; // cout<<"matching " << gterm << " +++ " <=0 ; i--){ cur_bind[vterm[i]] = simplifyExpr(gterm[i]); } binds.push_back(cur_bind); return; } if(trig.isSimple){ for(int i = vterm.arity()-1; i>=0 ; i--){ if(BOUND_VAR != vterm[i].getKind()){ if(simplifyExpr(gterm[i]) != simplifyExpr(vterm[i])) { return ; } } else{ cur_bind[vterm[i]] = simplifyExpr(gterm[i]); } } binds.push_back(cur_bind); return; } if(!isSysPred(vterm)){ //then gterm cannot be a syspred if(!gterm.getType().isBool()){ // res2= recSynMatch(gterm, vterm, env); matchChild(gterm, vterm, binds); return; } matchChild(gterm, vterm, binds); return; if(!*d_usePolarity){ // return recSynMatch(gterm, vterm, env); matchChild(gterm, vterm, binds); return; } const bool gtrue = (trueExpr()==findExpr(gterm)); // const bool gtrue = (trueExpr()==simplifyExpr(gterm)); if(gtrue ){ if((Neg==trig.polarity || PosNeg==trig.polarity)) { // return recSynMatch(gterm, vterm, env); matchChild(gterm, vterm, binds); return; } else{ // cout<<"returned 1"<& env){ Expr vterm = trig.getEx(); TRACE("quant toppred", "top pred: gterm:| "+gterm.toString()," vterm:| "+vterm.toString(),""); DebugAssert ((BOUND_VAR != gterm.getKind()),"gound term "+gterm.toString()+" has bound var"); DebugAssert ((BOUND_VAR != vterm.getKind()),"top pred match "+gterm.toString()+" has bound var"); if(gterm.isEq() || vterm.isEq()){ return false; // we do not match with equality } bool res2=false; if(vterm.arity() != gterm.arity()) return false; if(trig.isSuperSimp()){ if(trig.getHead() == getHead(gterm) ){ for(int i = vterm.arity()-1; i>=0 ; i--){ env[vterm[i]] = simplifyExpr(gterm[i]); } return true; } return false; } if(trig.isSimp()){ if(trig.getHead() == getHead(gterm) ){ for(int i = vterm.arity()-1; i>=0 ; i--){ if(BOUND_VAR != vterm[i].getKind()){ if(simplifyExpr(gterm[i]) != simplifyExpr(vterm[i])) { return false; } } } for(int i = vterm.arity()-1; i>=0 ; i--){ if(BOUND_VAR == vterm[i].getKind()){ if(d_allout){ env[vterm[i]] = simplifyExpr(gterm[i]); } else { env[vterm[i]] = simplifyExpr(gterm[i]); } } } return true; } else{ return false; } } if(!(isSysPred(vterm) && isSysPred(gterm))){ if(isSysPred(vterm) || isSysPred(gterm)) { return false; } if(!usefulInMatch(gterm)){ return false; } if(trig.getHead() != getHead(gterm)){ return false; } if(!gterm.getType().isBool()){ // res2= recSynMatch(gterm, vterm, env); res2= matchChild(gterm, vterm, env); return res2; } if(!*d_usePolarity){ // return recSynMatch(gterm, vterm, env); return matchChild(gterm, vterm, env); } const bool gtrue = (trueExpr()==findExpr(gterm)); if(gtrue ){ if(trig.isNeg()) { // return recSynMatch(gterm, vterm, env); return matchChild(gterm, vterm, env); } else{ return false; } } const bool gfalse = (falseExpr()==findExpr(gterm)); if(gfalse){ if (trig.isPos()){ // return recSynMatch(gterm, vterm, env); return matchChild(gterm, vterm, env); } else{ return false; } } else { return false; } } else{ DebugAssert((2==gterm.arity() && 2==vterm.arity()), "impossible situation in top pred"); DebugAssert(!((isLE(gterm) || isLT(gterm)) && !isIntx(gterm[0],0)), "canonical form changed"); #ifdef _CVC3_DEBUG_MODE if( CVC3::debugger.trace("quant toppred") ){ cout << "toppred gterm, vterm" << gterm << "::" << vterm << endl; cout << findExpr(gterm) << "::" << trig.isPos() << "|" << trig.isNeg() << endl; } #endif Expr gl = getLeft(gterm[1]); Expr gr = getRight(gterm[1]); if(null_expr == gr || null_expr == gl){ gl = gterm[0]; gr = gterm[1]; } Expr vr, vl; Expr tvr, tvl; tvr=null_expr; tvl=null_expr; if(isGE(vterm) || isGT(vterm)){ vr = vterm[0]; vl = vterm[1]; } else if(isLE(vterm) || isLT(vterm)){ vr = vterm[1]; vl = vterm[0]; } else{ DebugAssert(false, "impossilbe in toppred"); } if(isIntx(vl,0)){ tvl = getLeft(vr); tvr = getRight(vr); } else if(isIntx(vr,0)) { tvl = getLeft(vl); tvr = getRight(vl); } if( (null_expr != tvl) && (null_expr != tvr)){ vl = tvl; vr = tvr; } const bool gtrue = (trueExpr()==findExpr(gterm)); const bool gfalse = (falseExpr()==findExpr(gterm)); TRACE("quant toppred"," vl, gl, vr, gr:", vl.toString()+"::"+gl.toString()+"||", vr.toString()+"::"+gr.toString()); bool res; DebugAssert(!(trig.isNeg() && trig.isPos()), "expr in both pos and neg"); if(!*d_usePolarity){ return (recSynMatch(gl, vl, env) && recSynMatch(gr, vr, env)); } if(trig.isNeg()){ if (( gtrue ) ) { res=(recSynMatch(gl, vl, env) && recSynMatch(gr, vr, env)); } else { res=(recSynMatch(gl, vr, env) && recSynMatch(gr, vl, env)); } } else if(trig.isPos()){ if (( gfalse )) { res=(recSynMatch(gl, vl, env) && recSynMatch(gr, vr, env)); } else { res=(recSynMatch(gl, vr, env) && recSynMatch(gr, vl, env)); } } else { DebugAssert(false, "impossible polarity for trig"); res = false; } #ifdef _CVC3_DEBUG_MODE if( CVC3::debugger.trace("quant toppred") ){ cout<<"res| "<< res << " | " << gtrue << " | " << gfalse << endl; } #endif return res; } } */ /* Idealy, once a successful mathing is found here, the search should continue to check if there are more matchings. For example, suppose vterm is f(g(x)) and gterm is f(a), and a=g(c)=g(d), c!=d. The algorithm used now will only return the matching x=c. There is no reason to leave x=d out. However, testing of all quantified cases in SMT LIB, as of 11/28/2007, shows that the above senario never happens. So, the search algorithm here returns once a successful matching is found This is not true for set1.smt */ bool cmpExpr( Expr e1, Expr e2){ if(e1.isNull()) return true; if(e2.isNull()) return false; return (e1.getIndex() < e2.getIndex()); } /* recMultMatch: syntax match, will return multiple bindings if possible must be called by multMatchChild or multMatchTop requires binds.size() == 1; input: one partial (empty) bindings in binds. output: successful bindings in binds */ bool TheoryQuant::recMultMatchDebug(const Expr& gterm,const Expr& vterm, vector >& binds){ //bool TheoryQuant::recMultMatch(const Expr& gterm,const Expr& vterm, vector >& binds){ TRACE("quant match", gterm , " VS ", vterm); DebugAssert ((BOUND_VAR != gterm.getKind()),"gound term "+gterm.toString()+" has bound var"); DebugAssert (!isSysPred(vterm) && !isSysPred(gterm), "pred found in recMultMatch"); DebugAssert (binds.size() == 1, "binds.size() > 1"); if (BOUND_VAR == vterm.getKind() ) { ExprMap& curEnv = binds[0]; //curEnv is both input and output ExprMap::iterator iterVterm = curEnv.find(vterm); if ( iterVterm != curEnv.end()){ return (simplifyExpr(gterm) == simplifyExpr(iterVterm->second)) ? true : false ; } else { curEnv[vterm] = simplifyExpr(gterm); return true; } } else if (!vterm.containsBoundVar()){ return (simplifyExpr(vterm) == simplifyExpr(gterm)) ? true : false ; } else{ //let's do matching if(canGetHead(vterm)){ Expr vhead = getHead(vterm); if(vterm.isAtomicFormula()){ //we do not want to match predicate up to equality here. why? //more, if all pridicate is equilvent to true or false, we can just match the vterm with true or flase, we do not need a special case in theory, but the way here is more efficient for the current impelemention. // anoher problem is the interaction between matching and term's signature, I need to figure this out. if (canGetHead(gterm)) { if ( vhead != getHead(gterm) ){ return false; } return multMatchChild(gterm, vterm, binds); } else{ return false; } } if ( (canGetHead(gterm)) && vhead == getHead(gterm)){ return multMatchChild(gterm, vterm, binds); } // cout<<"-- begin multi equality matching -- " << endl; // cout<<"vterm: " << vterm << endl; // cout<<"gterm: " << gterm << endl; ExprMap orginalEnv = binds[0]; vector > candidateNewEnvs; bool newwayResult(false); if(*d_useNewEqu){ vector candidateGterms; { Expr curCandidateGterm = gterm.getEqNext().getRHS(); while (curCandidateGterm != gterm){ DebugAssert(simplifyExpr(curCandidateGterm) == simplifyExpr(gterm), "curCandidateGterm != gterm"); // cout<<"pushed candidate gterm " << getExprScore(curCandidateGterm) << " # " << curCandidateGterm << endl; if(getExprScore(curCandidateGterm) <= d_curMaxExprScore || true){ candidateGterms.push_back(curCandidateGterm); } curCandidateGterm = curCandidateGterm.getEqNext().getRHS(); } } // std::sort(candidateGterms.begin(), candidateGterms.end()); // for(int curGtermIndex = candidateGterms.size()-1; curGtermIndex >=0 ; curGtermIndex--){ for(size_t curGtermIndex = 0 ; curGtermIndex < candidateGterms.size(); curGtermIndex++){ const Expr& curGterm = candidateGterms[curGtermIndex]; if(getHead(curGterm) == vhead){ vector > newBinds; newBinds.push_back(orginalEnv); bool res = multMatchChild(curGterm, vterm, newBinds); if (res) { // cout << "found new match: " << endl; // cout << "curGterm: " << curGterm << endl; // cout << "simplified Gterm: " << simplifyExpr(gterm) << endl; // cout << "simplified curGterm: " << simplifyExpr(curGterm) << endl; for(size_t newBindsIndex = 0; newBindsIndex < newBinds.size(); newBindsIndex++){ candidateNewEnvs.push_back(newBinds[newBindsIndex]); } // cout << "pushed newEnvs " << newBinds.size() << endl; } } } if (candidateNewEnvs.size() >= 1){ // cout<<"found more matcings: " << candidateNewEnvs.size() << endl; newwayResult = true; } else{ newwayResult = false; } } //end of new way of matching // let's do matching in the old way vector > candidateOldEnvs; if( d_same_head_expr.count(vhead) > 0 ) { const Expr& findGterm = simplifyExpr(gterm); //if(isIntx(findGterm,0) || isIntx(findGterm,1)) return false;//special for simplify benchmark CDList* gls = d_same_head_expr[vhead]; for(size_t i = 0; i < gls->size(); i++){ const Expr& curGterm = (*gls)[i]; if(getExprScore(curGterm)> d_curMaxExprScore){ continue; } // cout<<"same head term " << curGterm << endl; if (simplifyExpr(curGterm) == findGterm){ DebugAssert((*gls)[i].arity() == vterm.arity(), "gls has different arity"); vector > newBinds ; newBinds.push_back(orginalEnv); bool goodMatching(false); goodMatching = multMatchChild(curGterm, vterm, newBinds); if(goodMatching){ // cout << "old curGterm: " << curGterm << endl; // cout << "old simplifed curGterm: " << simplifyExpr(curGterm) << endl; for(size_t newBindsIndex = 0; newBindsIndex < newBinds.size(); newBindsIndex++){ candidateOldEnvs.push_back(newBinds[newBindsIndex]); } // cout << "pushed oldEnvs " << newBinds.size() << endl; } } }//end of same head list } bool oldwayResult(false); if(candidateOldEnvs.size() >= 1){ oldwayResult = true; } else{ oldwayResult = false; } // cout<<"new env size" << candidateNewEnvs.size() << endl; // cout<<"old env size" << candidateOldEnvs.size() << endl; if( candidateNewEnvs.size() != candidateOldEnvs.size()){ ; // cout<<"found error?" << endl; } if(oldwayResult != newwayResult){ ; // cout << "-found bug in multMatch " << endl; } // binds = candidateNewEnvs; binds = candidateOldEnvs; return oldwayResult; } else{ if( (gterm.getKind() == vterm.getKind()) && (gterm.arity() == vterm.arity()) && gterm.arity()>0 ){ // cout<<"why"< >& binds){ //bool TheoryQuant::recMultMatch(const Expr& gterm,const Expr& vterm, vector >& binds){ TRACE("quant match", "==recMultMatch\n", "---"+gterm.toString(), "\n+++"+vterm.toString()); DebugAssert ((BOUND_VAR != gterm.getKind()),"gound term "+gterm.toString()+" has bound var"); DebugAssert (!isSysPred(vterm) && !isSysPred(gterm), "pred found in recMultMatch"); DebugAssert (binds.size() == 1, "binds.size() > 1"); if (BOUND_VAR == vterm.getKind() ) { ExprMap& curEnv = binds[0]; //curEnv is both input and output ExprMap::iterator iterVterm = curEnv.find(vterm); if ( iterVterm != curEnv.end()){ return (simplifyExpr(gterm) == simplifyExpr(iterVterm->second)) ? true : false ; } else { curEnv[vterm] = simplifyExpr(gterm); return true; } } else if (!vterm.containsBoundVar()){ return (simplifyExpr(vterm) == simplifyExpr(gterm)) ? true : false ; } else{ //let's do matching if(canGetHead(vterm)){ Expr vhead = getHead(vterm); if(vterm.isAtomicFormula()){ //we do not want to match predicate up to equality here. why? if (canGetHead(gterm)) { if ( vhead != getHead(gterm) ){ return false; } return multMatchChild(gterm, vterm, binds); } else{ return false; } } if ( (canGetHead(gterm)) && vhead == getHead(gterm)){ return multMatchChild(gterm, vterm, binds); } TRACE("quant multmatch", "-- begin multi equality matching -- ", "" ,""); TRACE("quant multmatch", "vterm: " , vterm, ""); TRACE("quant multmatch", "gterm: " , gterm, ""); ExprMap orginalEnv = binds[0]; vector > candidateOldEnvs; if( d_same_head_expr.count(vhead) > 0 ) { const Expr& findGterm = simplifyExpr(gterm); TRACE("quant multmatch", "simp gterm: " , simplifyExpr(gterm), ""); //if(isIntx(findGterm,0) || isIntx(findGterm,1)) return false;//special for simplify benchmark CDList* gls = d_same_head_expr[vhead]; for(size_t i = 0; i < gls->size(); i++){ const Expr& curGterm = (*gls)[i]; if(getExprScore(curGterm)> d_curMaxExprScore){ continue; } TRACE("quant multmatch", "same head term ", curGterm, ""); TRACE("quant multmatch", "simp same head term ", simplifyExpr(curGterm), ""); if (simplifyExpr(curGterm) == findGterm){ DebugAssert((*gls)[i].arity() == vterm.arity(), "gls has different arity"); vector > newBinds ; newBinds.push_back(orginalEnv); bool goodMatching(false); goodMatching = multMatchChild(curGterm, vterm, newBinds); if(goodMatching){ TRACE("quant multmatch", "old curGterm: ", curGterm, ""); TRACE("quant multmatch", "old simplifed curGterm: ", simplifyExpr(curGterm), ""); for(size_t newBindsIndex = 0; newBindsIndex < newBinds.size(); newBindsIndex++){ candidateOldEnvs.push_back(newBinds[newBindsIndex]); } TRACE("quant multmatch", "pushed oldEnvs " , newBinds.size(), ""); } } }//end of same head list } bool oldwayResult(false); if(candidateOldEnvs.size() >= 1){ oldwayResult = true; } else{ oldwayResult = false; } TRACE("quant multmatch", "old env size" ,candidateOldEnvs.size(), ""); binds = candidateOldEnvs; return oldwayResult; } else{ if( (gterm.getKind() == vterm.getKind()) && (gterm.arity() == vterm.arity()) && gterm.arity()>0 ){ return multMatchChild(gterm, vterm, binds); } else { return false; } } } return false; } //bool TheoryQuant::recMultMatchNewWay(const Expr& gterm,const Expr& vterm, vector >& binds){ bool TheoryQuant::recMultMatch(const Expr& gterm,const Expr& vterm, vector >& binds){ TRACE("quant match", gterm , " VS ", vterm); DebugAssert ((BOUND_VAR != gterm.getKind()),"gound term "+gterm.toString()+" has bound var"); DebugAssert (!isSysPred(vterm) && !isSysPred(gterm), "pred found in recMultMatch"); DebugAssert (binds.size() == 1, "binds.size() > 1"); if (BOUND_VAR == vterm.getKind() ) { ExprMap& curEnv = binds[0]; //curEnv is both input and output ExprMap::iterator iterVterm = curEnv.find(vterm); if ( iterVterm != curEnv.end()){ return (simplifyExpr(gterm) == simplifyExpr(iterVterm->second)) ? true : false ; } else { curEnv[vterm] = simplifyExpr(gterm); return true; } } else if (!vterm.containsBoundVar()){ return (simplifyExpr(vterm) == simplifyExpr(gterm)) ? true : false ; } else{ //let's do matching if(canGetHead(vterm)){ Expr vhead = getHead(vterm); if(vterm.isAtomicFormula()){ //we do not want to match predicate up to equality here. why? if (canGetHead(gterm)) { if ( vhead != getHead(gterm) ){ return false; } return multMatchChild(gterm, vterm, binds); } else{ return false; } } if ( (canGetHead(gterm)) && vhead == getHead(gterm)){ //well, what if gterm and vterm cannot match later, but vterm can match some guys in the equivalent class of gterm? return multMatchChild(gterm, vterm, binds); } TRACE("quant multmatch", "-- begin multi equality matching -- ", "" ,""); TRACE("qunat multmatch", "vterm: " , vterm, ""); TRACE("qunat multmatch", "gterm: " , gterm, ""); ExprMap orginalEnv = binds[0]; vector > candidateNewEnvs; bool newwayResult(false); if(*d_useNewEqu){ vector candidateGterms; { if(!gterm.hasFind()) { return false; } Expr curCandidateGterm = gterm.getEqNext().getRHS(); while (curCandidateGterm != gterm){ DebugAssert(simplifyExpr(curCandidateGterm) == simplifyExpr(gterm), "curCandidateGterm != gterm"); TRACE("quant multmatch", "pushed candidate gterm ", getExprScore(curCandidateGterm), " # " + curCandidateGterm.toString()); //maybe we should not check the score here, but we need check sig . if(getExprScore(curCandidateGterm) <= d_curMaxExprScore || true ){ candidateGterms.push_back(curCandidateGterm); } curCandidateGterm = curCandidateGterm.getEqNext().getRHS(); } } for(size_t curGtermIndex = 0 ; curGtermIndex < candidateGterms.size(); curGtermIndex++){ const Expr& curGterm = candidateGterms[curGtermIndex]; if(getHead(curGterm) == vhead){ vector > newBinds; newBinds.push_back(orginalEnv); bool res = multMatchChild(curGterm, vterm, newBinds, true); if (res) { TRACE("quant multmatch", "found new match: ", "" ,""); TRACE("quant multmatch", "curGterm: ", curGterm , ""); TRACE("quant multmatch", "simplified Gterm: ", simplifyExpr(gterm), "" ); TRACE("quant multmatch", "simplified curGterm: ", simplifyExpr(curGterm), ""); for(size_t newBindsIndex = 0; newBindsIndex < newBinds.size(); newBindsIndex++){ candidateNewEnvs.push_back(newBinds[newBindsIndex]); } TRACE("quant multmathc", "pushed newEnvs ", newBinds.size(), ""); } } } if (candidateNewEnvs.size() >= 1){ TRACE("quant multmacht", "found more matcings: " , candidateNewEnvs.size(), ""); newwayResult = true; } else{ newwayResult = false; } } //end of new way of matching TRACE("quant multmatch", "new env size " , candidateNewEnvs.size(), ""); binds = candidateNewEnvs; return newwayResult; } else{ if ( (gterm.getKind() == vterm.getKind()) && (gterm.arity() == vterm.arity()) && gterm.arity()>0 ) { return multMatchChild(gterm, vterm, binds); } else { return false; } } } return false; } /* bool TheoryQuant::recSynMatch(const Expr& gterm, const Expr& vterm, ExprMap& env){ cout << "-error: should not be called, recSynMatch" << endl; TRACE("quant match", gterm , " VS ", vterm); DebugAssert ((BOUND_VAR != gterm.getKind()),"gound term "+gterm.toString()+" has bound var"); DebugAssert (!isSysPred(vterm) && !isSysPred(gterm), "pred found"); if (BOUND_VAR == vterm.getKind() ) { ExprMap::iterator p = env.find(vterm); if ( p != env.end()){ return (simplifyExpr(gterm) == simplifyExpr(p->second)) ? true : false ; } else { env[vterm] = simplifyExpr(gterm); return true; } } else if (!vterm.containsBoundVar()){ return (simplifyExpr(vterm) == simplifyExpr(gterm)) ? true : false ; } else{ //let's do matching if(canGetHead(vterm)){ Expr vhead = getHead(vterm); if(vterm.isAtomicFormula()){ //we do not want to match predicate up to equality here. why? if (canGetHead(gterm)) { if ( vhead != getHead(gterm) ){ return false; } return matchChild(gterm, vterm, env); } else{ return false; } } if ( (canGetHead(gterm)) && vhead == getHead(gterm)){ return matchChild(gterm, vterm, env); } if(!*d_useEqu){ return false; } cout<<"-- begin equality matching -- " << endl; cout<<"vterm: " << vterm << endl; cout<<"gterm: " << gterm << endl; ExprMap orginalEnv = env; vector > candidateNewEnvs; // if(*d_useNewEqu){ vector candidateGterms; { Expr curCandidateGterm = gterm.getEqNext().getRHS(); while (curCandidateGterm != gterm){ DebugAssert(simplifyExpr(curCandidateGterm) == simplifyExpr(gterm), "curCandidateGterm != gterm"); cout<<"pushed candidate gterm " << curCandidateGterm << endl; candidateGterms.push_back(curCandidateGterm); curCandidateGterm = curCandidateGterm.getEqNext().getRHS(); } } std::sort(candidateGterms.begin(), candidateGterms.end()); // for(int curGtermIndex = candidateGterms.size()-1; curGtermIndex >=0 ; curGtermIndex--){ for(size_t curGtermIndex = 0 ; curGtermIndex < candidateGterms.size(); curGtermIndex++){ const Expr& curGterm = candidateGterms[curGtermIndex]; if(getHead(curGterm) == vhead){ ExprMap newEnv = orginalEnv; bool res = matchChild(curGterm, vterm, newEnv); if (res) { cout << "found new match: " << endl; cout << "curGterm: " << curGterm << endl; cout << "simplified Gterm: " << simplifyExpr(gterm) << endl; cout << "simplified curGterm: " << simplifyExpr(curGterm) << endl; candidateNewEnvs.push_back(newEnv); } } } ExprMap newwayEnv; bool newwayResult(false); if (candidateNewEnvs.size() >= 1){ cout<<"found more matcings: " << candidateNewEnvs.size() << endl; newwayEnv = candidateNewEnvs[0]; // we have a choice here // newwayEnv = candidateNewEnvs.back(); // we have a choice here newwayResult = true; } else{ newwayResult = false; } // } //end of new way of matching // let's do matching in the old way vector > candidateOldEnvs; if( d_same_head_expr.count(vhead) > 0 ) { const Expr& findGterm = simplifyExpr(gterm); //if(isIntx(findGterm,0) || isIntx(findGterm,1)) return false;//special for simplify benchmark CDList* gls = d_same_head_expr[vhead]; for(size_t i = 0; i < gls->size(); i++){ cout<<"same head term " << (*gls)[i] << endl; if (simplifyExpr((*gls)[i]) == findGterm){ DebugAssert((*gls)[i].arity() == vterm.arity(), "gls has different arity"); ExprMap curEnv = orginalEnv; const Expr& curGterm = (*gls)[i]; bool goodMatching(false); goodMatching = matchChild(curGterm, vterm, curEnv); if(goodMatching){ cout << "old curGterm: " << curGterm << endl; cout << "old simplifed curGterm: " << simplifyExpr(curGterm) << endl; candidateOldEnvs.push_back(curEnv); ; } } }//end of same head list } ExprMap oldwayEnv; bool oldwayResult(false); if(candidateOldEnvs.size() >= 1){ oldwayResult = true; oldwayEnv = candidateOldEnvs[0]; } else{ oldwayResult = false; } cout<<"new env size" << candidateNewEnvs.size() << endl; cout<<"old env size" << candidateOldEnvs.size() << endl; if( candidateNewEnvs.size() != candidateOldEnvs.size()){ cout<<"found error?" << endl; } if(oldwayResult != newwayResult){ cout<<"found bug" << endl; cout<<"oldway result: " << oldwayResult << endl; cout<<"newway result: " << newwayResult << endl; } if(false == oldwayResult ) return false; if(newwayEnv != oldwayEnv){ bool notFound(true); int foundIndex(-1); for(size_t i = 0; i 0 ){ return matchChild(gterm, vterm, env); } else { return false; } } } return false; } */ /* //the following is not used anymore, the code is here for refreence. bool TheoryQuant::recSynMatchBackupOnly(const Expr& gterm, const Expr& vterm, ExprMap& env){ cout<<"-error: should not be called: recSynMatchBackupOnly " << endl; TRACE("quant match", "gterm:| "+gterm.toString()," vterm:| "+vterm.toString(),""); DebugAssert ((BOUND_VAR != gterm.getKind()),"gound term "+gterm.toString()+" has bound var"); if (BOUND_VAR == vterm.getKind() ) { TRACE("quant match", "bound var found;", vterm.toString(),""); ExprMap::iterator p = env.find(vterm); if ( p != env.end()){ if (simplifyExpr(gterm) != simplifyExpr(p->second)){ return false; } else return true; } else { env[vterm] = simplifyExpr(gterm); return true; } } else if (!vterm.containsBoundVar()){ // return true; // cout<<"vterm and gterm"<= 0; i--){ // if (false == recSynMatch(gterm[i], vterm[i] , env)) // return false; // } // return true; } else{ return false; } } if ( (canGetHead(gterm)) && vhead == getHead(gterm)){ // if(gterm.arity() != vterm.arity()){ // return false; // } // for(int i=vterm.arity()-1; i >= 0; i--){ // if (false == recSynMatch(gterm[i], vterm[i] , env)) { // return false; // } // } // return true; return matchChild(gterm, vterm, env); } if(!*d_useEqu){ return false; } cout<<"-- begin equality matching -- " << endl; cout<<"vterm: " << vterm << endl; cout<<"gterm: " << gterm << endl; bool newwayResult(false); bool oldwayResult(false); ExprMap orgEnv = env; ExprMap newwayEnv; ExprMap oldwayEnv; vector > candidateEnv; // here just for test if(*d_useNewEqu){ // int debug1= vterm.getIndex(); // int debug2= gterm.getIndex(); // if(debug1 == 311 && debug2 == 361){ // cout<<"begin here" << endl; // } Expr cur_next = gterm.getEqNext().getRHS(); Expr vhead = getHead(vterm); TRACE("quant newequ", "gterm: " ,gterm, ""); TRACE("quant newequ", "v: " , vterm, "" ); // Idealy, once a successful mathing is found here, the search should continue to checkif there are more matchings. For example, suppose vterm is f(g(x)) and gterm is f(a), and a=g(c)=g(d), c!=d. The algorithm used now will only return the matching x=c. There is no reason to leave x=d out. However, testing of all quantified cases in SMT LIB, as of 11/28/2007, shows that the above senario never happens. So, the search algorithm here returns once a successful matching is found // This is not true for set1.smt // vector > candidateEnv; vector candidateGterms; while (cur_next != gterm){ if(simplifyExpr(cur_next) != simplifyExpr(gterm)){ cout<<" impossible"<=0 ; curGtermIndex--){ for(size_t curGtermIndex = 0 ; curGtermIndex < candidateGterms.size(); curGtermIndex++){ Expr curGterm = candidateGterms[curGtermIndex]; if(getHead(curGterm) == vhead){ TRACE("quant newequ", " matched good", "", ""); ExprMap newEnv = orgEnv; bool res = matchChild(curGterm, vterm, newEnv); TRACE("quant newequ", "final result: ",res ,""); if (res) { env=newEnv; // return res; cout << "found new match: " << endl; cout << "curGterm: " << curGterm << endl; cout << "simplified Gterm: " << simplifyExpr(gterm) << endl; cout << "simplified curGterm: " << simplifyExpr(curGterm) << endl; newwayEnv = newEnv; newwayResult = res; //break;; candidateEnv.push_back(newEnv); } } } while (cur_next != gterm) { TRACE("quant newequ", "g: " ,cur_next, ""); TRACE("quant newequ", "vhead: ", vhead, ""); TRACE("quant newequ", "g head: ", getHead(cur_next), ""); TRACE("quant newequ", "g score: ", getExprScore(cur_next), ""); // if(getExprScore(cur_next)>15) continue; if(getHead(cur_next) == vhead){ TRACE("quant newequ", " matched good", "", ""); ExprMap newEnv = env; bool res = matchChild(cur_next, vterm, newEnv); TRACE("quant newequ", "final result: ",res ,""); if (res) { env=newEnv; // return res; newwayEnv = newEnv; newwayResult = res; //break;; candidateEnv.push_back(newEnv); } } cur_next = cur_next.getEqNext().getRHS(); } // if(candidateEnv.size() == 1){ // env = candidateEnv[0]; // return true; // } // else if (candidateEnv.size() > 1){ // env = candidateEnv[0]; // return true; // cout<<"found more matcings" << endl; // } if (candidateEnv.size() > 1){ cout<<"found more matcings" << endl; // newwayEnv = candidateEnv[0]; } TRACE("quant newequ", " not matched ", vterm, gterm); // return false; if(newwayResult) { } else{ newwayResult = false ; } } vector > candidateOldEnv; //for test only // else { //else we use old equ algorithm env = orgEnv; // cout<<"==============================="< eq_set; std::map eq_set; eq_set.clear(); eq_set[gterm]=true; std::queue eq_queue; ExprMap* >::iterator iter = d_eq_list.find(gterm); if(iter != d_eq_list.end()){ for(size_t len =0; len< iter->second->size(); len++){ eq_queue.push((*(iter->second))[len]); } int count =0; while(eq_queue.size()>0){ count++; const Expr& cur = eq_queue.front(); eq_queue.pop(); if(eq_set.find(cur) == eq_set.end()){ if(canGetHead(cur) && getHead(cur) == vhead){ // cout<<"VTERM: "<* >::iterator iter = d_eq_list.find(cur); if(iter != d_eq_list.end()){ for(size_t len =0; len< iter->second->size(); len++){ eq_queue.push((*(iter->second))[len]); } } } } } // return false; } if( d_same_head_expr.count(vhead) > 0 ) { const Expr& findGterm = simplifyExpr(gterm); //if(isIntx(findGterm,0) || isIntx(findGterm,1)) return false;//special for simplify benchmark TRACE("quant match", "find gterm:", findGterm.toString(),""); CDList* gls = d_same_head_expr[vhead]; if (false) { int count =0; for(size_t i = 0; isize(); i++){ if (simplifyExpr((*gls)[i]) == findGterm){ count++; } } if(count>1){ cout<<"count " << count << " # " << gls->size() << " | "<size(); i++){ if (simplifyExpr((*gls)[i]) == findGterm){ cout<<"eq "<<(*gls)[i]<size(); i++){ cout<<"same head term " << (*gls)[i] << endl; if (simplifyExpr((*gls)[i]) == findGterm){ env = orgEnv; oldwayResult = true; TRACE("quant match", "find matched gterm:", (*gls)[i].toString(),""); DebugAssert((*gls)[i].arity() == vterm.arity(), "gls has different arity"); const Expr& newgterm = (*gls)[i]; for(int child=vterm.arity()-1; child >= 0 ; child--){ if (false == recSynMatch(newgterm[child], vterm[child] , env)){ TRACE("quant match", "match false", (*gls)[i][child].toString(), vterm[child].toString()); // return false; oldwayEnv = env; oldwayResult = false; break; } } TRACE("quant match", "good match, return true:", gterm, vterm.toString()); // cout<<"quant good match: " <0 ){ // for(int child=0; child < vterm.arity() ; child++){ // if (false == recSynMatch(gterm[child], vterm[child] , env)){ // TRACE("quant match", "match false", gterm[child].toString(), vterm[child].toString()); // return false; // } // } // return true; // if( gterm.getKind() == PLUS || gterm.getKind() == MINUS){ // cout<<"g v"<& env){ const Expr vterm = trig.getEx(); TRACE("quant toppred", "top pred: gterm:| "+gterm.toString()," vterm:| "+vterm.toString(),""); DebugAssert ((BOUND_VAR != gterm.getKind()),"gound term "+gterm.toString()+" has bound var"); DebugAssert ((BOUND_VAR != vterm.getKind()),"top pred match "+gterm.toString()+" has bound var"); if(gterm.isEq() || vterm.isEq()){ return false; // we do not match with equality } bool res2=false; // if(vterm.arity() != gterm.arity()) return false; if(trig.isSimp()){ if(trig.getHead() == getHead(gterm) ){ for(int i = vterm.arity()-1; i>=0 ; i--){ if(BOUND_VAR != vterm[i].getKind()){ if(simplifyExpr(gterm[i]) != simplifyExpr(vterm[i])) { return false; } } } for(int i = vterm.arity()-1; i>=0 ; i--){ if(BOUND_VAR == vterm[i].getKind()){ if(d_allout){ env[vterm[i]] = simplifyExpr(gterm[i]); } else { env[vterm[i]] = simplifyExpr(gterm[i]); } } } return true; } else{ return false; } } if(!(isSysPred(vterm) && isSysPred(gterm))){ if(isSysPred(vterm) || isSysPred(gterm)) { return false; } if(!usefulInMatch(gterm)){ return false; } if(trig.getHead() != getHead(gterm)){ return false; } if(!gterm.getType().isBool()){ res2= recSynMatch(gterm, vterm, env); return res2; } if(!*d_usePolarity){ return recSynMatch(gterm, vterm, env); } const bool gtrue = (trueExpr()==findExpr(gterm)); if(gtrue ){ if(trig.isNeg()) { return recSynMatch(gterm, vterm, env); } else{ return false; } } const bool gfalse = (falseExpr()==findExpr(gterm)); if(gfalse){ if (trig.isPos()){ return recSynMatch(gterm, vterm, env); } else{ return false; } } else { return false; } } else{ DebugAssert((2==gterm.arity() && 2==vterm.arity()), "impossible situation in top pred"); DebugAssert(!((isLE(gterm) || isLT(gterm)) && !isIntx(gterm[0],0)), "canonical form changed"); #ifdef _CVC3_DEBUG_MODE if( CVC3::debugger.trace("quant toppred") ){ cout << "toppred gterm, vterm" << gterm << "::" << vterm << endl; cout << findExpr(gterm) << "::" << trig.isPos() << "|" << trig.isNeg() << endl; } #endif Expr gl = getLeft(gterm[1]); Expr gr = getRight(gterm[1]); if(null_expr == gr || null_expr == gl){ gl = gterm[0]; gr = gterm[1]; } Expr vr, vl; Expr tvr, tvl; tvr=null_expr; tvl=null_expr; if(isGE(vterm) || isGT(vterm)){ vr = vterm[0]; vl = vterm[1]; } else if(isLE(vterm) || isLT(vterm)){ vr = vterm[1]; vl = vterm[0]; } else{ DebugAssert(false, "impossilbe in toppred"); } if(isIntx(vl,0)){ tvl = getLeft(vr); tvr = getRight(vr); } else if(isIntx(vr,0)) { tvl = getLeft(vl); tvr = getRight(vl); } if( (null_expr != tvl) && (null_expr != tvr)){ vl = tvl; vr = tvr; } const bool gtrue = (trueExpr()==findExpr(gterm)); const bool gfalse = (falseExpr()==findExpr(gterm)); TRACE("quant toppred"," vl, gl, vr, gr:", vl.toString()+"::"+gl.toString()+"||", vr.toString()+"::"+gr.toString()); bool res; DebugAssert(!(trig.isNeg() && trig.isPos()), "expr in both pos and neg"); if(!*d_usePolarity){ return (recSynMatch(gl, vl, env) && recSynMatch(gr, vr, env)); } if(trig.isNeg()){ if (( gtrue ) ) { res=(recSynMatch(gl, vl, env) && recSynMatch(gr, vr, env)); } else { res=(recSynMatch(gl, vr, env) && recSynMatch(gr, vl, env)); } } else if(trig.isPos()){ if (( gfalse )) { res=(recSynMatch(gl, vl, env) && recSynMatch(gr, vr, env)); } else { res=(recSynMatch(gl, vr, env) && recSynMatch(gr, vl, env)); } } else { DebugAssert(false, "impossible polarity for trig"); res = false; } #ifdef _CVC3_DEBUG_MODE if( CVC3::debugger.trace("quant toppred") ){ cout<<"res| "<< res << " | " << gtrue << " | " << gfalse << endl; } #endif return res; } } bool TheoryQuant::recSynMatch(const Expr& gterm, const Expr& vterm, ExprMap& env){ TRACE("quant match", "gterm:| "+gterm.toString()," vterm:| "+vterm.toString(),""); DebugAssert ((BOUND_VAR != gterm.getKind()),"gound term "+gterm.toString()+" has bound var"); if (BOUND_VAR == vterm.getKind()) { TRACE("quant match", "bound var found;", vterm.toString(),""); ExprMap::iterator p = env.find(vterm); if ( p != env.end()){ if (simplifyExpr(gterm) != simplifyExpr(p->second)){ return false; } else return true; } else { env[vterm] = simplifyExpr(gterm); return true; } } else if (!vterm.containsBoundVar()){ if(simplifyExpr(vterm) == simplifyExpr(gterm)) { return true; } else{ return false; } } else if(false && isSysPred(vterm) && isSysPred(gterm)){ TRACE("quant syspred"," vterm, gterm ", vterm.toString()+" :|: ", gterm.toString()); TRACE("quant syspred"," simplified vterm, gterm ", simplifyExpr(vterm).toString()+" :|: ", simplifyExpr(gterm).toString()); FatalAssert(false, "should not be here in synmatch"); exit(3); } else{ if(canGetHead(vterm)){ Expr vhead = getHead(vterm); TRACE("quant match", "head vterm:", getHead(vterm), ""); if(vterm.isAtomicFormula()){ if (canGetHead(gterm)) { if ( vhead != getHead(gterm) ){ return false; } for(int i=vterm.arity()-1; i >= 0; i--){ if (false == recSynMatch(gterm[i], vterm[i] , env)) return false; } return true; } else{ return false; } } if ( (canGetHead(gterm)) && vhead == getHead(gterm)){ if(gterm.arity() != vterm.arity()){ return false; } for(int i=vterm.arity()-1; i >= 0; i--){ if (false == recSynMatch(gterm[i], vterm[i] , env)) { return false; } } return true; } if(false && !*d_useEqu){ return false; } if( d_same_head_expr.count(vhead) > 0 ) { const Expr& findGterm = simplifyExpr(gterm); //if(isIntx(findGterm,0) || isIntx(findGterm,1)) return false;//special for simplify benchmark TRACE("quant match", "find gterm:", findGterm.toString(),""); CDList* gls = d_same_head_expr[vhead]; for(size_t i = 0; isize(); i++){ if (simplifyExpr((*gls)[i]) == findGterm){ TRACE("quant match", "find matched gterm:", (*gls)[i].toString(),""); DebugAssert((*gls)[i].arity() == vterm.arity(), "gls has different arity"); for(int child=vterm.arity()-1; child >= 0 ; child--){ const Expr& newgterm = (*gls)[i]; if (false == recSynMatch(newgterm[child], vterm[child] , env)){ TRACE("quant match", "match false", (*gls)[i][child].toString(), vterm[child].toString()); return false; } } TRACE("quant match", "good match, return true:", gterm, vterm.toString()); return true; } }//end of for return false; } else { return false;//end of if } } else{ TRACE("quant match more", "match more", gterm.toString()+" # ", vterm.toString()); if( (gterm.getKind() == vterm.getKind()) && (gterm.arity() == vterm.arity()) && gterm.arity()>0 ){ for(int child=0; child < vterm.arity() ; child++){ if (false == recSynMatch(gterm[child], vterm[child] , env)){ TRACE("quant match", "match false", gterm[child].toString(), vterm[child].toString()); return false; } } return true; } else return false; } } } */ /* void TheoryQuant::goodSynMatch(const Expr& e, const std::vector & boundVars, std::vector >& instBinds, std::vector& instGterms, const CDList& allterms, size_t tBegin){ for (size_t i=tBegin; i env; env.clear(); bool found = recSynMatch(gterm,e,env); if(found){ TRACE("quant matching found", " good:",gterm.toString()+" to " , e.toString()); TRACE("quant matching found", " simplified good:",simplifyExpr(gterm).toString()+" to " , simplifyExpr(e).toString()); std::vector inst; DebugAssert((boundVars.size() == env.size()),"bound var size != env.size()"); for(size_t i=0; i::iterator p = env.find(boundVars[i]); DebugAssert((p!=env.end()),"bound var cannot be found"); inst.push_back(p->second); } instBinds.push_back(inst); instGterms.push_back(gterm); } else{ TRACE("quant matching", "bad one",gterm.toString()+" to " , e.toString()); } } } } */ /* void TheoryQuant::goodSynMatchNewTrig(const Trigger& trig, const std::vector & boundVars, std::vector >& instBinds, std::vector& instGterms, const CDList& allterms, size_t tBegin){ for (size_t i=tBegin; i env; env.clear(); bool found = synMatchTopPred(gterm,trig,env); if(found){ //TRACE("quant matching found", " top good:",gterm.toString()+" to " , trig.getEx().toString()); std::vector inst; inst.clear(); DebugAssert((boundVars.size() <= env.size()),"bound var size != env.size()"); for(size_t i=0; i::iterator p = env.find(boundVars[i]); DebugAssert((p!=env.end()),"bound var cannot be found"); inst.push_back(p->second); } instBinds.push_back(inst); instGterms.push_back(gterm); } else{ // TRACE("quant matching", "bad one",gterm.toString()+" to ", trig.getEx().toString()); } } } } */ /* bool TheoryQuant::hasGoodSynInstNewTrigOld(Trigger& trig, std::vector & boundVars, std::vector >& instBinds, std::vector& instGterms, const CDList& allterms, size_t tBegin){ const std::set& bvs = getBoundVars(trig.getEx()); boundVars.clear(); for(std::set::const_iterator i=bvs.begin(),iend=bvs.end(); i!=iend; ++i) boundVars.push_back(*i); instBinds.clear(); goodSynMatchNewTrig(trig, boundVars, instBinds, instGterms, allterms, tBegin); if (instBinds.size() > 0) return true; else return false; } bool TheoryQuant::hasGoodSynInstNewTrig(Trigger& trig, const std::vector& boundVars, std::vector >& instBinds, std::vector& instGterms, const CDList& allterms, size_t tBegin){ // boundVars=trig.getBVs(); // const std::set& bvs = getBoundVars(trig.getEx()); // boundVars.clear(); // for(std::set::const_iterator i=bvs.begin(),iend=bvs.end(); i!=iend; ++i) // boundVars.push_back(*i); instBinds.clear(); goodSynMatchNewTrig(trig, boundVars, instBinds, instGterms, allterms, tBegin); if (instBinds.size() > 0) return true; else return false; } */ int TheoryQuant::loc_gterm(const std::vector& border, const Expr& vterm, int pos){ const std::vector& order = d_mtrigs_bvorder[vterm]; const Expr& var = order[pos]; for(size_t i=0; i& border, const std::vector& mtrigs, int cur_depth, std::vector >& instSet, std::vector& cur_inst ){ int max_dep = mtrigs.size(); if(cur_depth >= max_dep) return; Expr cur_vterm = mtrigs[cur_depth]; //get the current vterm if(d_mtrigs_inst.count(cur_vterm) <=0) return; CDList >* gterm_list = d_mtrigs_inst[cur_vterm]; // get the list of ground term found for cur_vterm for(size_t i=0; i< gterm_list->size(); i++){ const std::vector& cur_gterm = (*gterm_list)[i]; std::vector new_inst(border.size()); //get a new inst array for(size_t j=0; j< border.size(); j++){ new_inst[j]=cur_inst[j]; //copy to cur_int to new_inst } bool has_problem = false;//next, try to put the cur gterm into new_inst for(size_t j=0; j< cur_gterm.size(); j++){ int cur_loc_gterm = loc_gterm(border, cur_vterm, j); if( null_expr == new_inst[cur_loc_gterm]){ new_inst[cur_loc_gterm] = cur_gterm[j]; } else if (new_inst[cur_loc_gterm] != cur_gterm[j]){ has_problem = true; break; } } if (has_problem){ continue; } bool finished = true; for(size_t j=0; j< border.size() ;j++){ if(null_expr == new_inst[j]){ finished = false; break; } } if(finished){ std::vector good_inst; for(size_t j=0; j& border, std::vector >& instSet ){ std::vector dumy(border.size()) ; //use dynamic array here for(size_t j=0; j< border.size() ;j++){ dumy[j]=null_expr; } const std::vector& mtrigs = d_multTriggers[thm]; recSearchCover(border, mtrigs, 0, instSet, dumy); } */ /* bool TheoryQuant::hasGoodSynMultiInst(const Expr& thm, std::vector & boundVars, std::vector >& instSet, const CDList& allterms, size_t tBegin){ const std::set& bvs = getBoundVars(thm); boundVars.clear(); for(std::set::const_iterator i=bvs.begin(),iend=bvs.end(); i!=iend; ++i) boundVars.push_back(*i); instSet.clear(); bool new_match = false; //assumption: every trig is different //this is not true later, fix this asap const std::vector& mtrigs = d_multTriggers[thm]; for(std::vector::const_iterator i= mtrigs.begin(), iend = mtrigs.end(); i != iend; i++){ if(d_mtrigs_bvorder[*i].empty()){ //setup an order const std::set& trig_bvs = getBoundVars(*i); for(std::set::const_iterator j= trig_bvs.begin(), jend = trig_bvs.end(); j != jend; j++){ d_mtrigs_bvorder[*i].push_back(*j); } } const std::vector& trig_bvorder = d_mtrigs_bvorder[*i]; // std::set > trig_insts; std::vector > trig_insts; trig_insts.clear(); std::vector gtms; goodSynMatch(*i, trig_bvorder, trig_insts, gtms, allterms, tBegin); if (trig_insts.size() > 0){ new_match=true; if(d_mtrigs_inst.count(*i) <= 0){ d_mtrigs_inst[*i] = new(true) CDList > (theoryCore()->getCM()->getCurrentContext()); } for(std::vector >::const_iterator j = trig_insts.begin(), jend = trig_insts.end(); j != jend; j++){ d_mtrigs_inst[*i]->push_back(*j); for(std::vector::const_iterator k = j->begin(), kend = j->end(); k != kend; k++){ } } } } // end of for for(std::vector::const_iterator i= mtrigs.begin(), iend = mtrigs.end(); i != iend; i++){ if (d_mtrigs_inst.count(*i) <=0 ) continue; for(CDList >::const_iterator j = d_mtrigs_inst[*i]->begin(), jend = d_mtrigs_inst[*i]->end(); j != jend; j++){ for(std::vector::const_iterator k = j->begin(), kend = j->end(); k != kend; k++){ } } } {//code for search a cover if(new_match){ searchCover(thm, boundVars, instSet); } } if(instSet.size() > 0 ) { return true; } else { return false; } } */ /* bool inStrCache(std::set cache, std::string str){ return (cache.find(str) != cache.end()); } */ /* bool TheoryQuant::hasGoodSemInst(const Expr& e, std::vector & boundVars, std::set >& instSet, size_t tBegin){ return false; } */ /* void genPartInstSetThm(const std::vector& bVarsThm, std::vector& bVarsTerm, const std::vector >& termInst, std::vector >& instSetThm){ ExprMap bVmap; for(size_t i=0; i< bVarsThm.size(); ++i) { bVmap[bVarsThm[i]]=true; } std::vector tempBVterm; std::vector locTerm; for (size_t j=0; j 0){ locTerm.push_back(1); tempBVterm.push_back(bVarsTerm[j]); } else{ locTerm.push_back(0); } } DebugAssert(locTerm.size() == bVarsTerm.size(), "locTerm.size !- bVarsTerm.size()"); for(std::vector >::const_iterator i=termInst.begin(), iend=termInst.end();i!=iend; i++) { std::vector buf; buf.clear(); for(size_t j=0; j< bVarsTerm.size(); ++j){ if(locTerm[j]) buf.push_back((*i)[j]); } instSetThm.push_back(buf); } bVarsTerm=tempBVterm; } */ /* void genInstSetThm(const std::vector& bVarsThm, const std::vector& bVarsTerm, const std::vector >& termInst, std::vector >& instSetThm){ std::vector bVmap; for(size_t i=0; i< bVarsThm.size(); ++i) { bVmap.push_back(-1); for (size_t j=0; j >::const_iterator i=termInst.begin(), iend=termInst.end();i!=iend; i++) { std::vector buf; buf.clear(); for(size_t j=0; j< bVarsThm.size(); ++j){ buf.push_back((*i)[bVmap[j]]); } instSetThm.push_back(buf); } } */ /* void TheoryQuant::synInst(const Theorem & univ, const CDList& allterms, size_t tBegin ){ if(d_useFullTrig){ synFullInst(univ, allterms, tBegin); } if(d_useMultTrig){ synMultInst(univ, allterms, tBegin); } if(d_usePartTrig){ synPartInst(univ, allterms, tBegin); } } */ inline bool TheoryQuant::transFound(const Expr& comb){ return (d_trans_found.count(comb) > 0); } inline void TheoryQuant::setTransFound(const Expr& comb){ d_trans_found[comb] = true; } inline bool TheoryQuant::trans2Found(const Expr& comb){ return (d_trans2_found.count(comb) > 0); } inline void TheoryQuant::setTrans2Found(const Expr& comb){ d_trans2_found[comb] = true; } inline CDList & TheoryQuant::backList(const Expr& ex){ if(d_trans_back.count(ex)>0){ return *d_trans_back[ex]; } else{ return null_cdlist; } } inline CDList & TheoryQuant::forwList(const Expr& ex){ if(d_trans_forw.count(ex)>0){ return *d_trans_forw[ex]; } else{ return null_cdlist; } } inline void TheoryQuant::pushBackList(const Expr& node, Expr ex){ if(d_trans_back.count(node)>0){ d_trans_back[node]->push_back(ex); } else{ d_trans_back[node] = new(true) CDList (theoryCore()->getCM()->getCurrentContext()); d_trans_back[node]->push_back(ex); } } inline void TheoryQuant::pushForwList(const Expr& node, Expr ex){ if(d_trans_forw.count(node)>0){ d_trans_forw[node]->push_back(ex); } else{ d_trans_forw[node] = new(true) CDList (theoryCore()->getCM()->getCurrentContext()); d_trans_forw[node]->push_back(ex); } } /* void TheoryQuant::synFullInst(const Theorem & univ, const CDList& allterms, size_t tBegin ){ const Expr& quantExpr = univ.getExpr(); // const std::vector& bVarsThm = quantExpr.getVars(); std::vector bVarsThm = quantExpr.getVars(); TRACE("quant inst", "try full inst with:|", quantExpr.toString() , " "); std::vector > instBindsThm; //set of instantiations for the thm, std::vector > instBindsTerm; //bindings, in the order of bVarsTrig std::vector instGterms; //instGterms are gterms matched, instBindsTerm and instGterms must have the same length std::vector bVarsTrig; if(*d_useTrigNew){ std::vector& new_trigs=d_fullTrigs[quantExpr]; for( size_t i= 0; i bind; bind.clear(); bind.push_back(sr); bind.push_back(dt); enqueueInst(univ, bind, gterm); TRACE("quant inst", "trans pred rule2 ", univ.toString(), " | with bind: "+vectorExpr2string(bind)); TRACE("quant trans", "trans2 ", vectorExpr2string(bind), ""); } } } } } return; } } {//code for trans pred if(trig.hasTr()){ // if(hasGoodSynInstNewTrig(trig, bVarsTrig, instBindsTerm, instGterms, allterms, tBegin)) { if(hasGoodSynInstNewTrig(trig, trig.getBVs(), instBindsTerm, instGterms, allterms, tBegin)) { for(size_t j=0; j& dtForw = forwList(dt); const CDList& srBack = backList(sr); for(size_t k=0; k bind; bind.clear(); bind.push_back(sr); bind.push_back(dt); bind.push_back(dtForw[k]); enqueueInst(univ, bind, gterm); TRACE("quant inst", "trans pred rule", univ.toString(), " | with bind: "+vectorExpr2string(bind)); TRACE("quant trans", "trans res forw: ", vectorExpr2string(bind), ""); } for(size_t k=0; k bind; bind.clear(); bind.push_back(srBack[k]); bind.push_back(sr); bind.push_back(dt); enqueueInst(univ, bind, gterm); TRACE("quant inst", "trans pred rule ", univ.toString(), " | with bind: "+vectorExpr2string(bind)); TRACE("quant trans", "trans res back: ", vectorExpr2string(bind), ""); } pushForwList(sr,dt); pushBackList(dt,sr); } } } } return; } } bool univsHasMoreBVs ; univsHasMoreBVs = (d_hasMoreBVs.count(quantExpr) > 0); // if ( !d_allout || !trig.isSimp() || univsHasMoreBVs || *d_useLazyInst){ // if ( !d_allout || !trig.isSimp() || univsHasMoreBVs || true){ if ( !d_allout || !trig.isSuperSimp() || univsHasMoreBVs ){ // if ( !d_allout || !trig.isSimp() || univsHasMoreBVs ){ */ /* if(hasGoodSynInstNewTrigOld(trig, bVarsTrig, instBindsTerm, instGterms, allterms, tBegin)) { genInstSetThm(bVarsThm, bVarsTrig, instBindsTerm, instBindsThm); for (size_t j = 0; j& binds = instBindsThm[j]; enqueueInst(univ, trig, binds, gterm); TRACE("quant inst", "insert full inst", univ.toString(), " | with bind: "+vectorExpr2string(binds)); } } */ /* bVarsTrig=trig.getBVs();//vVarsTrig is used later, do not forget this. if(hasGoodSynInstNewTrig(trig, bVarsThm, instBindsTerm, instGterms, allterms, tBegin)) { for (size_t j = 0; j& binds = instBindsTerm[j]; enqueueInst(univ, trig, binds, gterm); TRACE("quant inst", "insert full inst", univ.toString(), " | with bind: "+vectorExpr2string(binds)); } } } // if(!d_allout || *d_useLazyInst){ if(!d_allout){ if(trig.hasRW() ){ if(1 == bVarsTrig.size()){ std::vector tp = d_arrayIndic[trig.getHead()]; for(size_t i=0; i tp = d_arrayIndic[trig.getHead()]; Expr index = tp[i]; std::vector temp; temp.clear(); temp.push_back(index); enqueueInst(univ, temp, index); TRACE("quant inst", "read write rule", univ.toString(), " | with bind: "+vectorExpr2string(temp)); } } else{ } } } }//end for each trigger } } */ void TheoryQuant::arrayHeuristic(const Trigger& trig, size_t univ_id){ return; std::vector tp = d_arrayIndic[trig.head]; for(size_t i=0; i temp; temp.push_back(index); enqueueInst(univ_id, temp, index); // TRACE("quant inst", "read write rule", univ.toString(), " | with bind: "+vectorExpr2string(temp)); } } void inline TheoryQuant::iterFWList(const Expr& sr, const Expr& dt, size_t univ_id, const Expr& gterm){ const CDList& dtForw = forwList(dt); for(size_t k=0; k tri_bind; tri_bind.push_back(sr); tri_bind.push_back(dt); tri_bind.push_back(dtForw[k]); enqueueInst(univ_id, tri_bind, gterm); } } void inline TheoryQuant::iterBKList(const Expr& sr, const Expr& dt, size_t univ_id, const Expr& gterm){ const CDList& srBack = backList(sr); for(size_t k=0; k tri_bind; tri_bind.push_back(srBack[k]); tri_bind.push_back(sr); tri_bind.push_back(dt); enqueueInst(univ_id, tri_bind, gterm); } } Expr TheoryQuant::simpRAWList(const Expr& org){ vector result; if(null_expr == org) return null_expr; for(int i =0 ; i < org.arity(); i++){ result.push_back(simplifyExpr(org[i])); } return Expr(RAW_LIST,result); } void TheoryQuant::synNewInst(size_t univ_id, const vector& bind, const Expr& gterm, const Trigger& trig ){ if(trig.isMulti){ const multTrigsInfo& mtriginfo = d_all_multTrigsInfo[trig.multiId]; vector actual_bind; for(size_t i=0, iend=bind.size(); i * oldBindMap = mtriginfo.var_binds_found[index]; CDMap::iterator cur_iter = oldBindMap->find(actual_bind_expr); if (oldBindMap->end() != cur_iter){ return; } else{ (*oldBindMap)[actual_bind_expr] = true; } //for now, we only have one set of commom positions, so it must be 0 //this is not true later. const vector& comm_pos = mtriginfo.common_pos[0]; size_t comm_pos_size = comm_pos.size(); Expr comm_expr; vector comm_expr_vec; for(size_t i = 0; i < comm_pos_size; i++){ comm_expr_vec.push_back(bind[comm_pos[i]]); } if(0 == comm_pos_size){ comm_expr = null_expr; } else{ comm_expr = Expr(RAW_LIST, comm_expr_vec); } Expr uncomm_expr; vector uncomm_expr_vec; const vector& uncomm_pos = mtriginfo.var_pos[index]; size_t uncomm_pos_size = uncomm_pos.size(); for(size_t i = 0; i< uncomm_pos_size; i++){ uncomm_expr_vec.push_back(bind[uncomm_pos[i]]); } if(0 == uncomm_pos_size){ uncomm_expr = null_expr; } else{ uncomm_expr = Expr(RAW_LIST, uncomm_expr_vec); } CDList* add_into_list ; CDList* iter_list; ExprMap* >::iterator add_into_iter; ExprMap* >::iterator iter_iter; size_t other_index = 0; if(0 == index){ other_index =1; } else if (1 == index){ other_index = 0; } else{ FatalAssert(false, "Sorry, only two vterms in a multi-trigger."); } add_into_iter = mtriginfo.uncomm_list[index]->find(comm_expr); if(mtriginfo.uncomm_list[index]->end() == add_into_iter){ add_into_list = new (true) CDList (theoryCore()->getCM()->getCurrentContext()); (*mtriginfo.uncomm_list[index])[comm_expr] = add_into_list; } else{ add_into_list = add_into_iter->second; } add_into_list->push_back(uncomm_expr); Expr simpCommExpr = simpRAWList(comm_expr); // if(simpCommExpr != comm_expr) { // cout<<"common and simplified comm expr" << comm_expr << " I " << simpCommExpr << endl; // } { // ExprMap* >* otherMap = mtriginfo.uncomm_list[other_index]; // iter_iter = mtriginfo.uncomm_list[other_index]->find(comm_expr); ExprMap* >::iterator otherMapBegin = otherMap->begin(), otherMapEnd = otherMap->end(); for(ExprMap* >::iterator otherMapIter = otherMapBegin; otherMapIter != otherMapEnd; otherMapIter++){ Expr otherCommonExpr = simpRAWList(otherMapIter->first); if(simpCommExpr != otherCommonExpr) continue; // iter_iter = otherMap->find(comm_expr); // if(mtriginfo.uncomm_list[other_index]->end() == iter_iter){ // return; // } // else{ // iter_list = iter_iter->second; // } if(comm_expr != otherMapIter->first) { } iter_list = otherMapIter->second; const vector& uncomm_iter_pos = mtriginfo.var_pos[other_index]; size_t uncomm_iter_pos_size = uncomm_iter_pos.size(); for(size_t i =0, iend = iter_list->size(); i new_bind(bind); for(size_t j=0; j actual_bind; for(size_t i=0; i actual_bind; for(size_t i=0; i& bind, const Expr& gterm, const Trigger& trig ){ // cout<<"synnewinst "< actual_bind; for(size_t i=0; i actual_bind; for(size_t i=0; i& dtForw = forwList(dt); const CDList& srBack = backList(sr); for(size_t k=0; k tri_bind; tri_bind.push_back(sr); tri_bind.push_back(dt); tri_bind.push_back(dtForw[k]); enqueueInst(univ_id, tri_bind, gterm); } for(size_t k=0; k tri_bind; tri_bind.push_back(srBack[k]); tri_bind.push_back(sr); tri_bind.push_back(dt); enqueueInst(univ_id, tri_bind, gterm); // TRACE("quant inst", "trans pred rule ", univ.toString(), " | with bind: "+vectorExpr2string(bind)); // TRACE("quant trans", "trans res back: ", vectorExpr2string(bind), ""); } pushForwList(sr,dt); pushBackList(dt,sr); } } return; } } // cout<<"before enqueueisnt"< tp = d_arrayIndic[trig.head]; for(size_t i=0; i tp = d_arrayIndic[trig.head]; Expr index = tp[i]; std::vector temp; temp.clear(); temp.push_back(index); enqueueInst(univ_id, temp, index); // TRACE("quant inst", "read write rule", univ.toString(), " | with bind: "+vectorExpr2string(temp)); } } else{ } } } } */ /* void TheoryQuant::synMultInst(const Theorem & univ, const CDList& allterms, size_t tBegin ){ const Expr& quantExpr = univ.getExpr(); if(d_multTriggers[quantExpr].size() <= 0) return ; TRACE("quant inst", "try muli with:|", quantExpr.toString() , " "); const std::vector& bVarsThm = quantExpr.getVars(); std::vector > instSetThm; //set of instantiations for the thm std::vector > termInst; //terminst are bindings, in the order of bVarsTrig std::vector bVarsTrig; if(hasGoodSynMultiInst(quantExpr, bVarsTrig, termInst, allterms, tBegin)) { genInstSetThm(bVarsThm, bVarsTrig, termInst, instSetThm); } { for(std::vector >::iterator i=instSetThm.begin(), iend=instSetThm.end(); i!=iend; ++i) { enqueueInst(univ, *i, null_expr);//fix the null_expr here asap TRACE("quant inst", "insert mult inst", univ.toString(), " | with bind: "+vectorExpr2string(*i)); } } } */ /* void TheoryQuant::synPartInst(const Theorem & univ, const CDList& allterms, size_t tBegin ){ const Expr& quantExpr = univ.getExpr(); TRACE("quant inst", "try part with ", quantExpr.toString() , " "); const std::vector& triggers = d_partTrigs[quantExpr]; std::vector > instSetThm; //set of instantiations for the thm std::vector > termInst; //terminst are bindings, in the order of bVarsTrig std::vector bVarsTrig; std::vector instGterms; for( std::vector::const_iterator i= triggers.begin(), iend=triggers.end();i!=iend;++i) { Trigger trig = *i; TRACE("quant inst","handle part trigger", trig.getEx().toString(),""); termInst.clear(); bVarsTrig.clear(); instSetThm.clear(); // if(hasGoodSynInstNewTrig(trig, bVarsTrig, termInst, instGterms,allterms, tBegin)) { if(hasGoodSynInstNewTrig(trig, trig.getBVs(), termInst, instGterms,allterms, tBegin)) { TRACE("quant syninst", "has good ", termInst.size(),""); TRACE("quant syninst", "after good ",instSetThm.size(), ""); Theorem newUniv = d_rules->adjustVarUniv(univ, trig.getBVs()); TRACE("quant syninst", " new univ:" ,newUniv.toString(),""); { for(size_t i = 0; i< termInst.size(); i++){ const std::vector& binds = termInst[i]; const Expr& gterm = instGterms[i]; enqueueInst(newUniv, binds, gterm); TRACE("quant yeting inst", "instantiating =========", "" , ""); TRACE("quant yeting inst", "instantiating", newUniv.getExpr().toString(), " | with bind: "+vectorExpr2string(binds)); TRACE("quant yeting inst", "instantiating org ", univ.getExpr().toString(), " | with gterm "+gterm.toString()); } } } } } */ /* void TheoryQuant::semInst(const Theorem & univ, size_t tBegin){ } */ void TheoryQuant::checkSat(bool fullEffort){ if(*d_translate) return; if(d_rawUnivs.size() <=0 ) return; if (d_maxILReached) { // cout<<"return bc max il "< d_all_multTrigsInfo; // cout<< " size " << d_all_multTrigsInfo.size() << endl; int numUsefulMultTriger = 0; for(size_t i = 0; i < d_all_multTrigsInfo.size(); i++){ multTrigsInfo& curMultiTrigger = d_all_multTrigsInfo[i]; if(curMultiTrigger.uncomm_list.size() != 2 ){ FatalAssert(false, "error in "); } ExprMap* >* uncommonMapOne = curMultiTrigger.uncomm_list[0]; ExprMap* >* uncommonMapTwo = curMultiTrigger.uncomm_list[1]; if(uncommonMapOne->size() != 0 || uncommonMapTwo->size() != 0 ){ numUsefulMultTriger++; } // continue; if(uncommonMapOne->size() == 0 ) { continue; } //why uncommonMapOne is empty but uncommonMapTwo is not?, let me figure this out. ExprMap* >::iterator iterOneBegin(uncommonMapOne->begin()), iterOneEnd(uncommonMapOne->end()); //cout<<"left and right " << leftTerm << " $ " << rightTerm <* > > oneFoundTerms; for(ExprMap* >::iterator iterOne=iterOneBegin; iterOne != iterOneEnd; iterOne++){ if(simplifyExpr((iterOne->first)[0]) == simplifyExpr(rightTerm)){ //for test only for trans // cout<<"found one " << iterOne->first << endl; // oneFoundTerms.push_back(iterOne->second); oneFoundTerms.push_back(*iterOne); } } ExprMap* >::iterator iterTwoBegin(uncommonMapTwo->begin()), iterTwoEnd(uncommonMapTwo->end()); // vector* > twoFoundTerms; vector* > >twoFoundTerms; for(ExprMap* >::iterator iterTwo = iterTwoBegin; iterTwo != iterTwoEnd; iterTwo++){ if(simplifyExpr((iterTwo->first)[0]) == simplifyExpr(rightTerm)){ // cout<<"found two " << iterTwo->first << endl; // twoFoundTerms.push_back(iterTwo->second); twoFoundTerms.push_back(*iterTwo); } } { for(size_t i= 0 ; i< oneFoundTerms.size(); i++){ for(size_t j= 0 ; j< twoFoundTerms.size(); j++){ pair* > pairOne = oneFoundTerms[i]; pair* > pairTwo = twoFoundTerms[j]; if(pairOne.first == pairTwo.first) continue; // cout<<"pairone.first " << pairOne.first << endl; // cout<<"pairTwo.first " << pairTwo.first << endl; CDList* oneExprList = pairOne.second; CDList* twoExprList = pairTwo.second; // cout<<"one size" << oneExprList->size() << endl; for(size_t oneIter = 0; oneIter < oneExprList->size(); oneIter++){ // cout<<"two size" << twoExprList->size() << endl; for(size_t twoIter = 0; twoIter < twoExprList->size(); twoIter++){ Expr gterm1 = (*oneExprList)[oneIter][0]; Expr gterm2 = (*twoExprList)[twoIter][0]; // cout<<"one and two " << oneIter << " # " << twoIter << endl; // cout<<"one and two " << gterm1 << " # " << gterm2 << endl; vector bind ; bind.push_back(gterm1); bind.push_back(rightTerm); bind.push_back(gterm2); size_t univID = curMultiTrigger.univ_id; if(d_univs[univID] != curMultiTrigger.univThm) { // cout << "errror in debuging:" << endl; // cout << d_univs[univID] << endl; // cout << curMultiTrigger.univThm << endl; exit(3); } enqueueInst(curMultiTrigger.univ_id, bind, rightTerm); // cout << "enqueued 1" << vectorExpr2string(bind) <getName() << ", " << l.getExpr(i) << "] " << l.getExpr(i).getSig().isNull() << endl; } const Expr& rightTerm = t.getRHS(); cout<<"right term is " << rightTerm << endl; NotifyList* rightUpList = rightTerm.getNotify(); if(NULL == rightUpList) continue; cout<<"the right notify list" << endl; NotifyList& ll = *rightUpList; for(size_t i=0,iend=ll.size(); igetName() << ", " << ll.getExpr(i) << "] " << ll.getExpr(i).getSig().isNull() << endl; } cout<<"------------" << leftTerm << " # " << rightTerm <::iterator i=d_simpUnivs.begin(), iend=d_simpUnivs.end(); i!=iend; i++){ // cout<<"------------------------------------"<first).toString()<second).getExpr().toString()<*>::iterator i=d_same_head_expr.begin(), iend=d_same_head_expr.end(); i!=iend; i++){ cout<<"------------------------------------"<first)< * terms= i->second; for(size_t i =0; isize(); i++){ cout<<(*terms)[i]<& allpreds = theoryCore()->getPredicates(); cout<<"=========== cur pred & terms =========="<& allterms = theoryCore()->getTerms(); for (size_t i=d_lastTermsPos; i& allpreds = theoryCore()->getPredicates(); cout<<"=========== cur pred equ =========="<& allterms = theoryCore()->getTerms(); for(size_t i=d_lastTermsPos; i0){ d_same_head_expr[getHead(t)]->push_back(t); } else{ d_same_head_expr[getHead(t)]= new(true) CDList (theoryCore()->getCM()->getCurrentContext()) ; d_same_head_expr[getHead(t)]->push_back(t); } } } const CDList& allpreds = theoryCore()->getPredicates(); for(size_t i=d_lastPredsPos; i0){ d_same_head_expr[getHead(t)]->push_back(t); } else{ d_same_head_expr[getHead(t)]= new(true) CDList (theoryCore()->getCM()->getCurrentContext()) ; d_same_head_expr[getHead(t)]->push_back(t); } } } } if(false){ for(size_t eqs_index = d_lastEqsUpdatePos; eqs_index < d_eqsUpdate.size(); eqs_index++){ const Expr lTerm = d_eqsUpdate[eqs_index].getLHS(); const Expr rTerm = d_eqsUpdate[eqs_index].getRHS(); d_eqs.push_back(lTerm); d_eqs.push_back(rTerm); } } if(false) {//for the equalities list const CDList& allpreds = theoryCore()->getPredicates(); for(size_t i=d_lastPredsPos; i* >::iterator iter = d_eq_list.find(lterm); if(d_eq_list.end() == iter){ d_eq_list[lterm] = new(true) CDList (theoryCore()->getCM()->getCurrentContext()) ; d_eq_list[lterm]->push_back(rterm); } else{ iter->second->push_back(rterm); } // cout<<"LTERM: " < (theoryCore()->getCM()->getCurrentContext()) ; d_eq_list[rterm]->push_back(lterm); } else{ iter->second->push_back(lterm); } // cout<<"RTERM: " <& allterms = theoryCore()->getTerms(); for(size_t i=d_lastTermsPos; i* >* > new_trigs; if(fullEffort || theoryCore()->getCM()->scopeLevel() <= 5 || true){ for(size_t i=d_univs.size(); igetTerms().size() < (size_t)(*d_maxNaiveCall )) { // cout<<"naive called"<getTerms().size()){ static int counter =0; std::set types; for(size_t i = 0; i cur_vars = cur_quant.getVars(); for(size_t j =0; j::iterator i=types.begin(), iend = types.end(); i != iend; i++){ counter++; std::stringstream tempout; tempout << counter; std::string out_str = base + tempout.str(); Expr newExpr = theoryCore()->getEM()->newVarExpr(out_str); newExpr.setType(Type(*i)); Proof pf; Expr newExpr2 = theoryCore()->getEM()->newVarExpr(out_str+"extra"); newExpr2.setType(Type(*i)); Expr newConstThm; if(Type(*i) == theoryCore()->getEM()->newRatExpr(0).getType()){ //somehow theory_arith will complain if we use expr2 to form the eq here newConstThm = newExpr.eqExpr(theoryCore()->getEM()->newRatExpr(0)); } else{ newConstThm = newExpr.eqExpr(newExpr2); } Theorem newThm = d_rules->addNewConst(newConstThm); if(*d_useGFact){ // addGlobalLemma(newThm, -1); enqueueFact(newThm); } else{ enqueueFact(newThm); } // enqueueSE(newThm); // d_tempBinds.clear(); return; } } naiveCheckSat(fullEffort); } }//end of try catch (int x){ while(!d_simplifiedThmQueue.empty()){ d_simplifiedThmQueue.pop(); d_abInstCount++; } while(!d_gUnivQueue.empty()){ d_gUnivQueue.pop(); } while(!d_gBindQueue.empty()){ d_gBindQueue.pop(); } d_tempBinds.clear(); saveContext(); delNewTrigs(new_trigs); return; } if(fullEffort) { sendInstNew(); } combineOldNewTrigs(new_trigs); delNewTrigs(new_trigs); } void TheoryQuant::saveContext(){ d_lastArrayPos.set(d_arrayTrigs.size()); d_univsSavedPos.set(d_univs.size()); d_rawUnivsSavedPos.set(d_rawUnivs.size()); d_lastTermsPos.set(theoryCore()->getTerms().size()); d_lastPredsPos.set(theoryCore()->getPredicates().size()); d_lastUsefulGtermsPos.set(d_usefulGterms.size()); d_lastEqsUpdatePos.set(d_eqsUpdate.size()); } void TheoryQuant::synCheckSat(ExprMap* >* >& new_trigs, bool fullEffort){ d_allout=false; if(fullEffort) { setIncomplete("Quantifier instantiation"); } size_t uSize = d_univs.size() ; const CDList& allterms = theoryCore()->getTerms(); const CDList& allpreds = theoryCore()->getPredicates(); size_t tSize = allterms.size(); size_t pSize = allpreds.size(); TRACE("quant",uSize, " uSize and univsSavedPOS ", d_univsSavedPos); TRACE("quant",tSize, " tSize and termsLastPos ", d_lastTermsPos); TRACE("quant",pSize, " pSize and predsLastPos ", d_lastPredsPos); TRACE("quant", fullEffort, " fulleffort:scope ",theoryCore()->getCM()->scopeLevel() ); for(size_t i=d_lastTermsPos; i 0){ TRACE("inend", "debug 1", "" ,"" ); return; } d_allout = true; //let me look at these d_allout later yeting { CDList* changed_terms = new (false) CDList (theoryCore()->getCM()->getCurrentContext()) ; collectChangedTerms(*changed_terms); matchListOld(*changed_terms, 0, changed_terms->size()); matchListNew(new_trigs, *changed_terms, 0 , changed_terms->size()); delete changed_terms; } d_allout = false; int n; if( ( n = sendInstNew()) > 0){ TRACE("inend", "debug 2", " # ",n ); return; } bool hasMoreGterms(false); do { hasMoreGterms=false; int numNewTerm=0; int oldNum=d_usefulGterms.size(); for(size_t i=0; i d_curMaxExprScore){ if((d_curMaxExprScore + 1) == score){ // if((d_curMaxExprScore + 1) <= score){ d_usefulGterms.push_back(cur); add_parent(cur); numNewTerm++; } else{ hasMoreGterms = true; TRACE("inend", "is this good? ", cur.toString()+" #-# " , score); // cout<<"should not be here"< d_curMaxExprScore){ if((d_curMaxExprScore + 1) == score){ // if((d_curMaxExprScore + 1) <= score){ d_usefulGterms.push_back(cur); add_parent(cur); numNewTerm++; } else{ hasMoreGterms = true; TRACE("inend", "is this good? ", cur.toString()+" #-# " , score); // cout<<"should not be here"< getExprScore(allpreds[i+1]) ){ cout<<"strange pred"< getExprScore(allterms[i+1])){ cout<<"strange term"<= 0 && d_curMaxExprScore <= *d_maxIL ){ d_curMaxExprScore = d_curMaxExprScore+1;; } else { d_curMaxExprScore = d_curMaxExprScore+1; // d_curMaxExprScore = d_curMaxExprScore+0; //this is for debugging Yeting d_maxILReached = true; //cout<<"il reached: " << endl; } // cout << " max il " << *d_maxIL << endl; // cout <0 ){ matchListOld(d_usefulGterms, oldNum, d_usefulGterms.size() ); matchListNew(new_trigs, d_usefulGterms, oldNum, d_usefulGterms.size()); if(sendInstNew() > 0){ TRACE("inend", "debug 3 1", "" , "" ); return; } } if(hasMoreGterms){ ; // cout<<"has more " << endl; // cout< 0){ TRACE("inend", "debug 3 2", "" , "" ); return; } d_allout = false; // for(size_t array_index = 0; array_index < d_arrayTrigs.size(); array_index++){ // arrayHeuristic(d_arrayTrigs[array_index].trig, d_arrayTrigs[array_index].univ_id); // } return ; } TRACE("inend", "debug 3 0", "", ""); TRACE("quant","this round; ",d_callThisRound,""); return; } if ((uSize == d_univsSavedPos) && (tSize == d_lastTermsPos) && (pSize == d_lastPredsPos) ) return; // cout<<"match old"< 0)) { // First of all, this algorithm is incomplete setIncomplete("Quantifier instantiation"); if(d_instCount>=*d_maxQuantInst) return; //first attempt to instantiate with the saved terms //only do this if there are new saved terms or new theroems and // at least some saved terms bool savedOnly = ((uSize > d_univsSavedPos.get() && stSize > 0) || (stSize > d_savedTermsPos.get())); int origCount = d_instCount; if(savedOnly) { TRACE("quant", "checkSat [saved insts]: univs size = ", uSize , " "); for(size_t i=0, pos = d_univsSavedPos.get(); i= *d_maxQuantInst) break; else instantiate(d_univs[i], i>=pos, true, d_savedTermsPos.get()); } d_univsSavedPos.set(d_univs.size()); d_savedTermsPos.set(stSize); } if(!savedOnly || d_instCount == origCount) { //instantiate with context dependent assertions terms TRACE("quant", "checkSat [context insts]: univs size = ", uSize , " "); const CDList& assertions = theoryCore()->getTerms(); int origSize = d_contextTerms.size(); // for(size_t i=0; i= *d_maxQuantInst) break; else instantiate(d_univs[i], i>=pos, false, origSize); } d_univsContextPos.set(d_univs.size()); } TRACE("quant terse", "checkSat total insts: ", d_instCount, ", new "+int2string(d_instCount - instCount)); } TRACE("quant", "checkSat total insts: ", d_instCount, " "); TRACE("quant", "checkSat new insts: ", d_instCount - instCount, " "); TRACE("quant", "checkSat effort:", fullEffort, " }"); } /*! \brief Queues up all possible instantiations of bound * variables. * * The savedMap boolean indicates whether to use savedMap or * d_contextMap the all boolean indicates weather to use all * instantiation or only new ones and newIndex is the index where * new instantiations begin. */ void TheoryQuant::instantiate(Theorem univ, bool all, bool savedMap, size_t newIndex) { if(!all && ((savedMap && newIndex == d_savedTerms.size()) ||(!savedMap && newIndex == d_contextTerms.size()))) return; TRACE("quant", "instanitate", all , "{"); std::vector varReplacements; recInstantiate(univ, all, savedMap, newIndex, varReplacements); TRACE("quant", "instanitate", "", "}"); } //! does most of the work of the instantiate function. void TheoryQuant::recInstantiate(Theorem& univ, bool all, bool savedMap, size_t newIndex, std::vector& varReplacements) { Expr quantExpr = univ.getExpr(); const vector& boundVars = quantExpr.getVars(); size_t curPos = varReplacements.size(); TRACE("quant", "recInstantiate: ", boundVars.size() - curPos, ""); //base case: a full vector of instantiations exists if(curPos == boundVars.size()) { if(!all) return; Theorem t = d_rules->universalInst(univ, varReplacements); d_insts[t.getExpr()] = varReplacements; TRACE("quant", "recInstantiate => " , t.toString(), ""); if(d_instCount< *d_maxQuantInst) { d_instCount=d_instCount+1; enqueueInst(univ, varReplacements, null_expr); // enqueueInst(univ, t); // enqueueFact(t); } return; } //recursively add all possible instantiations in the next //available space of the vector else { Type t = getBaseType(boundVars[curPos]); int iendC=0, iendS=0, iend; std::vector* typeVec = NULL; // = d_savedMap[t]; CDList* typeList = NULL; // = *d_contextMap[t]; if(d_savedMap.count(t) > 0) { typeVec = &(d_savedMap[t]); iendS = typeVec->size(); TRACE("quant", "adding from savedMap: ", iendS, ""); } if(!savedMap) { if(d_contextMap.count(t) > 0) { typeList = d_contextMap[t]; iendC = typeList->size(); TRACE("quant", "adding from contextMap:", iendC , ""); } } iend = iendC + iendS; for(int i =0; i& terms) { Expr trExpr=trueExpr(), flsExpr = falseExpr(); Type boolT = boolType(); if(d_contextMap.count(boolT) == 0) { d_contextMap[boolT] = new(true) CDList(theoryCore()->getCM()->getCurrentContext()); size_t pos = d_contextTerms.size(); d_contextTerms.push_back(trExpr); d_contextTerms.push_back(flsExpr); (*d_contextMap[boolT]).push_back(pos); (*d_contextMap[boolT]).push_back(pos+1); } for(size_t i=0; i0) { return(d_contextCache[e]); } if(e.arity()>0) { for(Expr::iterator it = e.begin(), iend = e.end(); it!=iend; ++it) //maps the children and returns a bool if(recursiveMap(*it) == false) { d_contextCache[e] = false; } } else if(e.getKind() == EXISTS || e.getKind() == FORALL){ //maps the body if(recursiveMap(e.getBody())==false) { d_contextCache[e]=false; } } //found a bound variable in the children if(d_contextCache.count(e)>0) { return false; } if(d_savedCache.count(e) > 0) { return true; } Type type = getBaseType(e); if(!type.isBool() && !(e.getKind()==BOUND_VAR)){ TRACE("quant", "recursiveMap: found ", e.toString() + " of type " + type.toString(), ""); int pos = d_contextTerms.size(); d_contextTerms.push_back(e); if(d_contextMap.count(type)==0) d_contextMap[type] = new(true) CDList(theoryCore()->getCM()->getCurrentContext()); (*d_contextMap[type]).push_back(pos); } if(e.getKind() == BOUND_VAR) { d_contextCache[e] = false; return false; } else { d_contextCache[e] = true; return true; } //need to implement: //insert all instantiations if type is finite and reasonable //also need to implement instantiations of subtypes } /*!\brief Used to notify the quantifier algorithm of possible * instantiations that were used in proving a context inconsistent. */ void TheoryQuant::notifyInconsistent(const Theorem& thm){ #ifdef _CVC3_DEBUG_MODE if( CVC3::debugger.trace("quant inscon") ){ cout<<"the one caused incsonsistency"< assump; thm.getLeafAssumptions(assump); cout<<"===========leaf assumptions; =========="<::iterator i=assump.begin(), iend=assump.end(); i!=iend; i++){ cout<<">>"<toString()< 0) { vector& insts = d_insts[e]; int pos; for(vector::iterator it = insts.begin(), iend = insts.end(); it!=iend ; ++it) { if(d_savedCache.count(*it) == 0) { TRACE("quant", "notifyInconsistent: found:", (*it).toString(), ""); d_savedCache[*it] = true; pos = d_savedTerms.size(); d_savedTerms.push_back(*it); d_savedMap[getBaseType(*it)].push_back(pos); } } } if(thm.isAssump()) return; const Assumptions& a = thm.getAssumptionsRef(); for(Assumptions::iterator it =a.begin(), iend = a.end(); it!=iend; ++it){ findInstAssumptions(*it); } } //! computes the type of a quantified term. Always a boolean. void TheoryQuant::computeType(const Expr& e) { switch (e.getKind()) { case FORALL: case EXISTS: { if(!e.getBody().getType().isBool()) throw TypecheckException("Type mismatch for expression:\n\n " + e.getBody().toString() + "\n\nhas the following type:\n\n " + e.getBody().getType().toString() + "\n\nbut the expected type is Boolean:\n\n "); else e.setType(e.getBody().getType()); break; } default: DebugAssert(false,"Unexpected kind in Quantifier Theory: " + e.toString()); break; } } /*! * TCC(forall x.phi(x)) = (forall x. TCC(phi(x))) * OR (exists x. TCC(phi(x)) & !phi(x)) * TCC(exists x.phi(x)) = (forall x. TCC(phi(x))) * OR (exists x. TCC(phi(x)) & phi(x)) */ Expr TheoryQuant::computeTCC(const Expr& e) { DebugAssert(e.isQuantifier(), "Unexpected expression in Quantifier Theory: " + e.toString()); bool forall(e.getKind() == FORALL); const Expr& phi = e.getBody(); Expr tcc_phi = getTCC(phi); Expr forall_tcc = getEM()->newClosureExpr(FORALL, e.getVars(), tcc_phi); Expr exists_tcc = getEM()->newClosureExpr(EXISTS, e.getVars(), tcc_phi && (forall? !phi : phi)); return (forall_tcc || exists_tcc); } ExprStream& TheoryQuant::print(ExprStream& os, const Expr& e) { switch(os.lang()) { case SIMPLIFY_LANG: { switch(e.getKind()){ case FORALL: case EXISTS: { if(!e.isQuantifier()) { e.print(os); break; } os << "(" << ((e.getKind() == FORALL)? "FORALL" : "EXISTS"); const vector& vars = e.getVars(); bool first(true); os << "(" ; for(vector::const_iterator i=vars.begin(), iend=vars.end(); i!=iend; ++i) { if(first) first = false; else os << " " ; os << *i; // The quantifier may be in a raw parsed form, in which case // the type is not assigned yet //if(i->isVar()) // simplify do not need type // os << ":" << space << pushdag << (*i).getType() << popdag; } os << ") " << e.getBody() << ")"; } break; default: e.print(os); break; } break; } case TPTP_LANG: { switch(e.getKind()){ case FORALL: case EXISTS: { if(!e.isQuantifier()) { e.print(os); break; } os << ((e.getKind() == FORALL)? " ! " : " ? "); const vector& vars = e.getVars(); bool first(true); os << "[" ; for(vector::const_iterator i=vars.begin(), iend=vars.end(); i!=iend; ++i) { if(first) first = false; else os << "," ; os << *i ; if(i->isVar()) os << ": "<< (*i).getType() ; } os << "] : (" << e.getBody() <<")"; } break; default: e.print(os); break; } break; } case PRESENTATION_LANG: { switch(e.getKind()){ case FORALL: case EXISTS: { if(!e.isQuantifier()) { e.print(os); break; } os << "(" << push << ((e.getKind() == FORALL)? "FORALL" : "EXISTS") << space << push; const vector& vars = e.getVars(); bool first(true); os << "(" << push; for(vector::const_iterator i=vars.begin(), iend=vars.end(); i!=iend; ++i) { if(first) first = false; else os << push << "," << pop << space; os << *i; // The quantifier may be in a raw parsed form, in which case // the type is not assigned yet // the following lines are changed for a neat output / by yeting if(*d_translate || true){ if(i->isVar()) os << ":" << space << pushdag << (*i).getType() << popdag; } } os << push << ") " << pushdag << push; // print manual triggers const vector >& triggers = e.getTriggers(); for (vector >::const_iterator i=triggers.begin(), iend=triggers.end(); i != iend; ++i) { // const vector& terms = (*i).getKids(); const vector& terms = (*i); if (terms.size() > 0) { os << push << ": PATTERN (" << pushdag << push; vector::const_iterator j=terms.begin(), jend=terms.end(); os << nodag << pushdag << *j << popdag; ++j; for(;j!=jend; ++j) { os << push << ", " << pop << space << pushdag << *j << popdag; } os << ") " << push; } } os << ": " << pushdag << e.getBody() << push << ")"; } break; default: e.print(os); break; } break; } case SMTLIB_LANG: { d_theoryUsed = true; switch(e.getKind()){ case FORALL: case EXISTS: { if(!e.isQuantifier()) { e.print(os); break; } os << "(" << push << ((e.getKind() == FORALL)? "forall" : "exists") << space; const vector& vars = e.getVars(); bool first(true); // os << "(" << push; for(vector::const_iterator i=vars.begin(), iend=vars.end(); i!=iend; ++i) { if(first) first = false; else os << space; os << "(" << push << *i; // The quantifier may be in a raw parsed form, in which case // the type is not assigned yet if(i->isVar()) os << space << pushdag << (*i).getType() << popdag; os << push << ")" << pop << pop; } os << space << pushdag << e.getBody() << push; // print manual triggers const vector >& triggers = e.getTriggers(); for (vector >::const_iterator i=triggers.begin(), iend=triggers.end(); i != iend; ++i) { // const vector& terms = (*i).getKids(); const vector& terms = (*i); /* TODO: How does SMT-LIB v2 handle patterns? */ if (terms.size() > 0) { os << push << space << ":pat {" << space << pushdag << push; vector::const_iterator j=terms.begin(), jend=terms.end(); os << nodag << pushdag << *j << popdag; ++j; for(;j!=jend; ++j) { os << space << pushdag << *j << popdag; } os << space << "}" << space << push; } } os << push << ")"; break; } default: throw SmtlibException("TheoryQuant::print: SMTLIB_LANG: Unexpected expression: " +getEM()->getKindName(e.getKind())); break; } break; } // End of SMTLIB_LANG case SMTLIB_V2_LANG: { d_theoryUsed = true; switch(e.getKind()){ case FORALL: case EXISTS: { if(!e.isQuantifier()) { e.print(os); break; } os << "(" << push << ((e.getKind() == FORALL)? "forall" : "exists") << space; const vector& vars = e.getVars(); bool first(true); os << "(" << push; for(vector::const_iterator i=vars.begin(), iend=vars.end(); i!=iend; ++i) { if(first) first = false; else os << space; os << "(" << push << *i; // The quantifier may be in a raw parsed form, in which case // the type is not assigned yet if(i->isVar()) os << space << pushdag << (*i).getType() << popdag; os << push << ")" << pop << pop; } os << ")" << pop; const vector >& triggers = e.getTriggers(); if( !triggers.empty() ) { os << space << push << "(!"; } os << space << pushdag << e.getBody() << popdag; // print manual triggers for (vector >::const_iterator i=triggers.begin(), iend=triggers.end(); i != iend; ++i) { // const vector& terms = (*i).getKids(); const vector& terms = (*i); if (terms.size() > 0) { os << push << space << ":pattern" << space << push << "(" ; vector::const_iterator j=terms.begin(), jend=terms.end(); os << nodag << pushdag << *j << popdag; ++j; for(;j!=jend; ++j) { os << space << pushdag << *j << popdag; } os << ")" << pop << space ; } } if( !triggers.empty() ) { os << ")" << pop; } os << ")" << pop; break; } default: throw SmtlibException("TheoryQuant::print: SMTLIB_LANG: Unexpected expression: " +getEM()->getKindName(e.getKind())); break; } break; } // End of SMTLIB_LANG case LISP_LANG: { switch(e.getKind()){ case FORALL: case EXISTS: { if(!e.isQuantifier()) { e.print(os); break; } os << "(" << push << ((e.getKind() == FORALL)? "FORALL" : "EXISTS") << space; const vector& vars = e.getVars(); bool first(true); os << "(" << push; for(vector::const_iterator i=vars.begin(), iend=vars.end(); i!=iend; ++i) { if(first) first = false; else os << space; os << "(" << push << *i; // The quantifier may be in a raw parsed form, in which case // the type is not assigned yet if(i->isVar()) os << space << pushdag << (*i).getType() << popdag; os << push << ")" << pop << pop; } os << push << ")" << pop << pop << pushdag << e.getBody() << push << ")"; } break; default: e.print(os); break; } break; } default: e.print(os); break; } return os; } /////////////////////////////////////////////////////////////////////////////// //parseExprOp: //translating special Exprs to regular EXPR?? /////////////////////////////////////////////////////////////////////////////// Expr TheoryQuant::parseExprOp(const Expr& e) { if(theoryCore()->getFlags()["unknown-check-model"].getBool()) { throw ParserException("ERROR: +unknown-check-model unsafe with quantifiers"); } TRACE("parser", "TheoryQuant::parseExprOp(", e, ")"); // If the expression is not a list, it must have been already // parsed, so just return it as is. if(RAW_LIST != e.getKind()) return e; DebugAssert(e.arity() > 0, "TheoryQuant::parseExprOp:\n e = "+e.toString()); const Expr& c1 = e[0][0]; const string& opName(c1.getString()); int kind = getEM()->getKind(opName); switch(kind) { case FORALL: case EXISTS: { // (OP ((v1 ... vn tp1) ...) body) if(!( (e.arity() == 3 || 4 == e.arity()) && e[1].getKind() == RAW_LIST && e[1].arity() > 0)) throw ParserException("Bad "+opName+" expression: "+e.toString()); // Iterate through the groups of bound variables vector > vars; // temporary stack of bound variables for(Expr::iterator i=e[1].begin(), iend=e[1].end(); i!=iend; ++i) { if(i->getKind() != RAW_LIST || i->arity() < 2) throw ParserException("Bad variable declaration block in "+opName +" expression: "+i->toString() +"\n e = "+e.toString()); // Iterate through individual bound vars in the group. The // last element is the type, which we have to rebuild and // parse, since it is used in the creation of bound variables. Type tp(parseExpr((*i)[i->arity()-1])); if (tp == boolType()) { throw ParserException("A quantified variable may not be of type BOOLEAN"); } for(int j=0, jend=i->arity()-1; j cur_pattern; for(int j =0; j < cur_trig.arity(); j++){ try { cur_pattern.push_back(parseExpr(cur_trig[j])); } catch (Exception e){ // cout <getFlags()["translate"].getBool()) { // don't tolerate bad patterns when translating throw; } cur_pattern.clear(); } } if (cur_pattern.size() > 0 ){ // Expr cur_parsed_trig(RAW_LIST, cur_pattern, getEM()); patterns.push_back(cur_pattern); } } } Expr res; if(3 == e.arity()) { res = getEM()->newClosureExpr((kind == FORALL) ? FORALL : EXISTS,boundVars, body); } else{// 4 == e.arity() res = getEM()->newClosureExpr((kind == FORALL) ? FORALL : EXISTS,boundVars, body, patterns ); // cout<<"patterns vector"< * * License to use, copy, modify, sell and/or distribute this software * and its documentation for any purpose is hereby granted without * royalty, subject to the terms and conditions defined in the \ref * LICENSE file provided with this distribution. * *
* * CLASS: QuantProofRules * * * Description: TRUSTED implementation of arithmetic proof rules. * */ /*****************************************************************************/ // This code is trusted #define _CVC3_TRUSTED_ #include "quant_theorem_producer.h" #include "theory_quant.h" #include "theory_core.h" using namespace std; using namespace CVC3; QuantProofRules* TheoryQuant::createProofRules() { return new QuantTheoremProducer(theoryCore()->getTM(), this); } #define CLASS_NAME "CVC3::QuantTheoremProducer" //! ==> NOT FORALL (vars): e IFF EXISTS (vars) NOT e Theorem QuantTheoremProducer::rewriteNotForall(const Expr& e) { if(CHECK_PROOFS) { CHECK_SOUND(e.isNot() && e[0].isForall(), "rewriteNotForall: expr must be NOT FORALL:\n" +e.toString()); } Proof pf; if(withProof()) pf = newPf("rewrite_not_forall", e); return newRWTheorem(e, e.getEM()->newClosureExpr(EXISTS, e[0].getVars(), !e[0].getBody()), Assumptions::emptyAssump(), pf); } Theorem QuantTheoremProducer::addNewConst(const Expr& e) { Proof pf; if(withProof()) pf = newPf("add_new_const", e); return newTheorem(e, Assumptions::emptyAssump(), pf); } ///do not use this rule, this is for debug only Theorem QuantTheoremProducer::newRWThm(const Expr& e, const Expr& newE) { Proof pf; if(withProof()) pf = newPf("from cache", e); return newRWTheorem(e, newE,Assumptions::emptyAssump(), pf); } Theorem QuantTheoremProducer::normalizeQuant(const Expr& quant) { if(CHECK_PROOFS) { CHECK_SOUND(quant.isForall()||quant.isExists(), "normalizeQuant: expr must be FORALL or EXISTS\n" +quant.toString()); } std::map::iterator typeIter; std::string base("_BD"); int counter(0); vector newVars; const std::vector& cur_vars = quant.getVars(); for(size_t j =0; jsecond; } counter++; std::stringstream stringType; stringType << counter << "TY" << typeIndex ; std::string out_str = base + stringType.str(); Expr newExpr = d_theoryQuant->getEM()->newBoundVarExpr(out_str, int2string(counter)); newExpr.setType(t); newVars.push_back(newExpr); } vector > trigs = quant.getTriggers(); for(size_t i = 0 ; i < trigs.size(); i++){ for(size_t j = 0 ; j < trigs[i].size(); j++){ trigs[i][j] = trigs[i][j].substExpr(cur_vars,newVars); } } Expr normBody = quant.getBody().substExpr(cur_vars,newVars); Expr normQuant = d_theoryQuant->getEM()->newClosureExpr(quant.isForall()?FORALL:EXISTS, newVars, normBody, trigs); Proof pf; if(withProof()) pf = newPf("normalizeQuant", quant, normQuant); return newRWTheorem(quant, normQuant, Assumptions::emptyAssump(), pf); } //! ==> NOT EXISTS (vars): e IFF FORALL (vars) NOT e Theorem QuantTheoremProducer::rewriteNotExists(const Expr& e) { if(CHECK_PROOFS) { CHECK_SOUND(e.isNot() && e[0].isExists(), "rewriteNotExists: expr must be NOT FORALL:\n" +e.toString()); } Proof pf; if(withProof()) pf = newPf("rewrite_not_exists", e); return newRWTheorem(e, e.getEM()->newClosureExpr(FORALL, e[0].getVars(), !e[0].getBody()), Assumptions::emptyAssump(), pf); } Theorem QuantTheoremProducer::universalInst(const Theorem& t1, const vector& terms, int quantLevel, Expr gterm){ Expr e = t1.getExpr(); const vector& boundVars = e.getVars(); for(unsigned int i=0; igetBaseType(boundVars[i]) != d_theoryQuant->getBaseType(terms[i])){ Proof pf; return newRWTheorem(terms[i],terms[i], Assumptions::emptyAssump(), pf); } //this is the same as return a TRUE theorem, which will be ignored immeridatele. So, this is just return doing nothing. } if(CHECK_PROOFS) { CHECK_SOUND(boundVars.size() == terms.size(), "Universal instantiation: size of terms array does " "not match quanitfied variables array size"); CHECK_SOUND(e.isForall(), "universal instantiation: expr must be FORALL:\n" +e.toString()); for(unsigned int i=0; igetBaseType(boundVars[i]) == d_theoryQuant->getBaseType(terms[i]), "Universal instantiation: type mismatch"); } //build up a conjunction of type predicates for expression Expr tr = e.getEM()->trueExpr(); Expr typePred = tr; // unsigned qlevel, qlevelMax = 0; for(unsigned int i=0; igetTypePred(boundVars[i].getType(),terms[i]); if(p!=tr) { if(typePred==tr) typePred = p; else typePred = typePred.andExpr(p); } // qlevel = d_theoryQuant->theoryCore()->getQuantLevelForTerm(terms[i]); // if (qlevel > qlevelMax) qlevel = qlevelMax; } // Expr inst = e.getBody().substExprQuant(e.getVars(), terms); Expr inst = e.getBody().substExpr(e.getVars(), terms); // Expr inst = e.getBody().substExpr(e.getVars(), terms); Proof pf; if(withProof()) { vector pfs; vector es; pfs.push_back(t1.getProof()); es.push_back(e); es.push_back(Expr(RAW_LIST,terms)); // es.insert(es.end(), terms.begin(), terms.end()); es.push_back(inst); if (gterm.isNull()) { es.push_back( d_theoryQuant->getEM()->newRatExpr(0)); } else {es.push_back(gterm); } pf= newPf("universal_elimination1", es, pfs); } // Expr inst = e.getBody().substExpr(e.getVars(), terms); Expr imp; if(typePred == tr ) //just for a easy life, yeting, change this assp imp = inst; else imp = typePred.impExpr(inst); Theorem ret = newTheorem(imp, t1.getAssumptionsRef(), pf); int thmLevel = t1.getQuantLevel(); if(quantLevel >= thmLevel) { ret.setQuantLevel(quantLevel+1); } else{ ret.setQuantLevel(thmLevel+1); } // ret.setQuantLevel(quantLevel+1); return ret; } //! Instantiate a universally quantified formula /*! From T|-FORALL(var): e generate T|-psi => e' where e' is obtained * from e by instantiating bound variables with terms in * vector& terms. The vector of terms should be the same * size as the vector of bound variables in e. Also elements in * each position i need to have matching base types. psi is the conjunction of * subtype predicates for the bound variables of the quanitfied expression. * \param t1 the quantifier (a Theorem) * \param terms the terms to instantiate. * \param quantLevel the quantification level for the formula */ Theorem QuantTheoremProducer::universalInst(const Theorem& t1, const vector& terms, int quantLevel){ Expr e = t1.getExpr(); const vector& boundVars = e.getVars(); if(CHECK_PROOFS) { CHECK_SOUND(boundVars.size() == terms.size(), "Universal instantiation: size of terms array does " "not match quanitfied variables array size"); CHECK_SOUND(e.isForall(), "universal instantiation: expr must be FORALL:\n" +e.toString()); for(unsigned int i=0; igetBaseType(boundVars[i]) == d_theoryQuant->getBaseType(terms[i]), "Universal instantiation: type mismatch"); } //build up a conjunction of type predicates for expression Expr tr = e.getEM()->trueExpr(); Expr typePred = tr; // unsigned qlevel, qlevelMax = 0; for(unsigned int i=0; igetTypePred(boundVars[i].getType(),terms[i]); if(p!=tr) { if(typePred==tr) typePred = p; else typePred = typePred.andExpr(p); } // qlevel = d_theoryQuant->theoryCore()->getQuantLevelForTerm(terms[i]); // if (qlevel > qlevelMax) qlevel = qlevelMax; } //Expr inst = e.getBody().substExprQuant(e.getVars(), terms); Expr inst = e.getBody().substExpr(e.getVars(), terms); // Expr inst = e.getBody().substExpr(e.getVars(), terms); Proof pf; if(withProof()) { vector pfs; vector es; pfs.push_back(t1.getProof()); es.push_back(e); es.push_back(Expr(RAW_LIST,terms)); // es.insert(es.end(), terms.begin(), terms.end()); es.push_back(inst); pf= newPf("universal_elimination2", es, pfs); } // Expr inst = e.getBody().substExpr(e.getVars(), terms); Expr imp; if(typePred == tr) //just for a easy life, yeting, change this assp imp = inst; else imp = typePred.impExpr(inst); Theorem ret = newTheorem(imp, t1.getAssumptionsRef(), pf); int thmLevel = t1.getQuantLevel(); if(quantLevel >= thmLevel) { ret.setQuantLevel(quantLevel+1); } else{ ret.setQuantLevel(thmLevel+1); } // ret.setQuantLevel(quantLevel+1); return ret; } Theorem QuantTheoremProducer::universalInst(const Theorem& t1, const vector& terms){ Expr e = t1.getExpr(); const vector& boundVars = e.getVars(); if(CHECK_PROOFS) { CHECK_SOUND(boundVars.size() == terms.size(), "Universal instantiation: size of terms array does " "not match quanitfied variables array size"); CHECK_SOUND(e.isForall(), "universal instantiation: expr must be FORALL:\n" +e.toString()); for(unsigned int i=0; igetBaseType(boundVars[i]) == d_theoryQuant->getBaseType(terms[i]), "Universal instantiation: type mismatch"); } //build up a conjunction of type predicates for expression Expr tr = e.getEM()->trueExpr(); Expr typePred = tr; unsigned qlevel=0, qlevelMax = 0; for(unsigned int i=0; igetTypePred(boundVars[i].getType(),terms[i]); if(p!=tr) { if(typePred==tr) typePred = p; else typePred = typePred.andExpr(p); } qlevel = d_theoryQuant->theoryCore()->getQuantLevelForTerm(terms[i]); if (qlevel > qlevelMax) qlevel = qlevelMax; } Expr inst = e.getBody().substExpr(e.getVars(), terms); // Expr inst = e.getBody().substExprQuant(e.getVars(), terms); // Expr inst = e.getBody().substExpr(e.getVars(), terms); Proof pf; if(withProof()) { vector pfs; vector es; pfs.push_back(t1.getProof()); es.push_back(e); es.push_back(Expr(RAW_LIST,terms)); // es.insert(es.end(), terms.begin(), terms.end()); es.push_back(inst); pf= newPf("universal_elimination3", es, pfs); } // Expr inst = e.getBody().substExpr(e.getVars(), terms); Expr imp; if( typePred == tr ) //just for easy life, yeting, change this asap imp = inst; else imp = typePred.impExpr(inst); Theorem ret = newTheorem(imp, t1.getAssumptionsRef(), pf); unsigned thmLevel = t1.getQuantLevel(); if(qlevel >= thmLevel) { ret.setQuantLevel(qlevel+1); } else{ // ret.setQuantLevel(thmLevel+1); ret.setQuantLevel(thmLevel+1); } // ret.setQuantLevel(qlevel+1); return ret; } Theorem QuantTheoremProducer::partialUniversalInst(const Theorem& t1, const vector& terms, int quantLevel){ cout<<"error in partial inst" << endl; Expr e = t1.getExpr(); const vector& boundVars = e.getVars(); if(CHECK_PROOFS) { CHECK_SOUND(boundVars.size() >= terms.size(), "Universal instantiation: size of terms array does " "not match quanitfied variables array size"); CHECK_SOUND(e.isForall(), "universal instantiation: expr must be FORALL:\n" +e.toString()); for(unsigned int i=0; igetBaseType(boundVars[i]) == d_theoryQuant->getBaseType(terms[i]), "partial Universal instantiation: type mismatch"); } } //build up a conjunction of type predicates for expression Expr tr = e.getEM()->trueExpr(); Expr typePred = tr; for(unsigned int i=0; igetTypePred(boundVars[i].getType(),terms[i]); if(p!=tr) { if(typePred==tr) typePred = p; else typePred = typePred.andExpr(p); } } Proof pf; if(withProof()) { vector pfs; vector es; pfs.push_back(t1.getProof()); es.push_back(e); es.insert(es.end(), terms.begin(), terms.end()); pf= newPf("partial_universal_instantiation", es, pfs); } if(terms.size() == boundVars.size()){ Expr inst = e.getBody().substExpr(e.getVars(), terms); Expr imp; if(typePred == tr) imp = inst; else imp = typePred.impExpr(inst); return(newTheorem(imp, t1.getAssumptionsRef(), pf)); } else{ vector newBoundVars; for(size_t i=0; ileftBoundVars; for(size_t i=terms.size(); igetEM()->newClosureExpr(FORALL, leftBoundVars, tempinst); Expr imp; if(typePred == tr) imp = inst; else imp = typePred.impExpr(inst); Theorem res = (newTheorem(imp, t1.getAssumptionsRef(), pf)); int thmLevel = t1.getQuantLevel(); if(quantLevel >= thmLevel) { res.setQuantLevel(quantLevel+1); } else{ //k ret.setQuantLevel(thmLevel+1); res.setQuantLevel(thmLevel); } return res; } } //! find all bound variables in e and maps them to true in boundVars void QuantTheoremProducer::recFindBoundVars(const Expr& e, ExprMap & boundVars, ExprMap &visited) { if(visited.count(e)>0) return; else visited[e] = true; if(e.getKind() == BOUND_VAR) boundVars[e] = true; if(e.getKind() == EXISTS || e.getKind() == FORALL) recFindBoundVars(e.getBody(), boundVars, visited); for(Expr::iterator it = e.begin(); it!=e.end(); ++it) recFindBoundVars(*it, boundVars, visited); } //!adjust the order of bound vars, newBvs begin first Theorem QuantTheoremProducer::adjustVarUniv(const Theorem& t1, const std::vector& newBvs){ const Expr e=t1.getExpr(); const Expr body = e.getBody(); if(CHECK_PROOFS) { CHECK_SOUND(e.isForall(), "adjustVarUniv: " +e.toString()); } const vector& origVars = e.getVars(); ExprMap oldmap; for(vector::const_iterator it = origVars.begin(), iend=origVars.end(); it!=iend; ++it) { oldmap[*it]=true; } vector quantVars; for(vector::const_iterator it = newBvs.begin(), iend=newBvs.end(); it!=iend; ++it) { if(oldmap.count(*it) > 0) quantVars.push_back(*it); } if(quantVars.size() == origVars.size()) return t1; ExprMap newmap; for(vector::const_iterator it = newBvs.begin(), iend=newBvs.end(); it!=iend; ++it) { newmap[*it]=true; } for(vector::const_iterator it = origVars.begin(), iend=origVars.end(); it!=iend; ++it) { if(newmap.count(*it)<=0){ quantVars.push_back(*it); }; } Proof pf; if(withProof()) { vector es; vector pfs; es.push_back(e); es.insert(es.end(), quantVars.begin(), quantVars.end()); pfs.push_back(t1.getProof()); pf= newPf("adjustVarUniv", es, pfs); } Expr newQuantExpr; newQuantExpr = d_theoryQuant->getEM()->newClosureExpr(FORALL, quantVars, body); return(newTheorem(newQuantExpr, t1.getAssumptionsRef(), pf)); } //!pack (forall (x) forall (y)) into (forall (x y)) Theorem QuantTheoremProducer::packVar(const Theorem& t1){ Expr out_forall =t1.getExpr(); if(CHECK_PROOFS) { CHECK_SOUND(out_forall.isForall(), "packVar: " +out_forall.toString()); } vector bVars = out_forall.getVars(); if(!out_forall.getBody().isForall()){ return t1; } Expr cur_body = out_forall.getBody(); while(cur_body.isForall()){ vector bVarsLeft = cur_body.getVars(); for(vector::iterator i=bVarsLeft.begin(), iend=bVarsLeft.end(); i!=iend; i++){ bVars.push_back(*i); } cur_body=cur_body.getBody(); } Proof pf; if(withProof()) { vector es; vector pfs; es.push_back(out_forall); es.insert(es.end(), bVars.begin(), bVars.end()); pfs.push_back(t1.getProof()); pf= newPf("packVar", es, pfs); } Expr newQuantExpr; newQuantExpr = d_theoryQuant->getEM()->newClosureExpr(FORALL, bVars, cur_body); return (newTheorem(newQuantExpr, t1.getAssumptionsRef(), pf)); // return (newRWTheorem(t1,newQuantExpr, t1.getAssumptionsRef(), pf)); } //! convert (forall (x) ... forall (y)) into (forall (x y)...) //! convert (exists (x) ... exists (y)) into (exists (x y)...) Theorem QuantTheoremProducer::pullVarOut(const Theorem& t1){ const Expr thm_expr=t1.getExpr(); if(CHECK_PROOFS) { CHECK_SOUND(thm_expr.isForall() || thm_expr.isExists(), "pullVarOut: " +thm_expr.toString()); } const Expr outBody = thm_expr.getBody(); // if(((outBody.isAnd() && outBody[1].isForall()) || // (outBody.isImpl() && outBody[1].isForall()) || // (outBody.isNot() && outBody[0].isAnd() && outBody[0][1].isExists()) )){ // return t1; // } if (thm_expr.isForall()){ if((outBody.isNot() && outBody[0].isAnd() && outBody[0][1].isExists())){ vector bVarsOut = thm_expr.getVars(); const Expr innerExists =outBody[0][1]; const Expr innerBody = innerExists.getBody(); vector bVarsIn = innerExists.getVars(); for(vector::iterator i=bVarsIn.begin(), iend=bVarsIn.end(); i!=iend; i++){ bVarsOut.push_back(*i); } Proof pf; if(withProof()) { vector es; vector pfs; es.push_back(thm_expr); es.insert(es.end(), bVarsIn.begin(), bVarsIn.end()); pfs.push_back(t1.getProof()); pf= newPf("pullVarOut", es, pfs); } Expr newbody; newbody=(outBody[0][0].notExpr()).orExpr(innerBody.notExpr()); Expr newQuantExpr; newQuantExpr = d_theoryQuant->getEM()->newClosureExpr(FORALL, bVarsOut, newbody); return(newTheorem(newQuantExpr, t1.getAssumptionsRef(), pf)); } else if ((outBody.isAnd() && outBody[1].isForall()) || (outBody.isImpl() && outBody[1].isForall())){ vector bVarsOut = thm_expr.getVars(); const Expr innerForall=outBody[1]; const Expr innerBody = innerForall.getBody(); vector bVarsIn = innerForall.getVars(); for(vector::iterator i=bVarsIn.begin(), iend=bVarsIn.end(); i!=iend; i++){ bVarsOut.push_back(*i); } Proof pf; if(withProof()) { vector es; vector pfs; es.push_back(thm_expr); es.insert(es.end(), bVarsIn.begin(), bVarsIn.end()); pfs.push_back(t1.getProof()); pf= newPf("pullVarOut", es, pfs); } Expr newbody; if(outBody.isAnd()){ newbody=outBody[0].andExpr(innerBody); } else if(outBody.isImpl()){ newbody=outBody[0].impExpr(innerBody); } Expr newQuantExpr; newQuantExpr = d_theoryQuant->getEM()->newClosureExpr(FORALL, bVarsOut, newbody); return(newTheorem(newQuantExpr, t1.getAssumptionsRef(), pf)); } return t1; // case cannot be handled now. } else if (thm_expr.isExists()){ if ((outBody.isAnd() && outBody[1].isExists()) || (outBody.isImpl() && outBody[1].isExists())){ vector bVarsOut = thm_expr.getVars(); const Expr innerExists = outBody[1]; const Expr innerBody = innerExists.getBody(); vector bVarsIn = innerExists.getVars(); for(vector::iterator i=bVarsIn.begin(), iend=bVarsIn.end(); i!=iend; i++){ bVarsOut.push_back(*i); } Proof pf; if(withProof()) { vector es; vector pfs; es.push_back(thm_expr); es.insert(es.end(), bVarsIn.begin(), bVarsIn.end()); pfs.push_back(t1.getProof()); pf= newPf("pullVarOut", es, pfs); } Expr newbody; if(outBody.isAnd()){ newbody=outBody[0].andExpr(innerBody); } else if(outBody.isImpl()){ newbody=outBody[0].impExpr(innerBody); } Expr newQuantExpr; newQuantExpr = d_theoryQuant->getEM()->newClosureExpr(EXISTS, bVarsOut, newbody); return(newTheorem(newQuantExpr, t1.getAssumptionsRef(), pf)); } } return t1; } /*! @brief From T|- QUANTIFIER (vars): e we get T|-QUANTIFIER(vars') e * where vars' is obtained from vars by removing all bound variables * not used in e. If vars' is empty the produced theorem is just T|-e */ Theorem QuantTheoremProducer::boundVarElim(const Theorem& t1) { const Expr e=t1.getExpr(); const Expr body = e.getBody(); if(CHECK_PROOFS) { CHECK_SOUND(e.isForall() || e.isExists(), "bound var elimination: " +e.toString()); } ExprMap boundVars; //a mapping of bound variables in the body to true ExprMap visited; //to make sure expressions aren't traversed //multiple times recFindBoundVars(body, boundVars, visited); vector quantVars; const vector& origVars = e.getVars(); for(vector::const_iterator it = origVars.begin(), iend=origVars.end(); it!=iend; ++it) { if(boundVars.count(*it) > 0) quantVars.push_back(*it); } // If all variables are used, just return the original theorem if(quantVars.size() == origVars.size()) return t1; Proof pf; if(withProof()) { vector es; vector pfs; es.push_back(e); es.insert(es.end(), quantVars.begin(), quantVars.end()); pfs.push_back(t1.getProof()); pf= newPf("bound_variable_elimination", es, pfs); } if(quantVars.size() == 0) return(newTheorem(e.getBody(), t1.getAssumptionsRef(), pf)); Expr newQuantExpr; if(e.isForall()) newQuantExpr = d_theoryQuant->getEM()->newClosureExpr(FORALL, quantVars, body); else newQuantExpr = d_theoryQuant->getEM()->newClosureExpr(EXISTS, quantVars, body); return(newTheorem(newQuantExpr, t1.getAssumptionsRef(), pf)); } cvc3-2.4.1/src/theory_core/0000775000175400017540000000000011630011320015352 5ustar mdetersmdeterscvc3-2.4.1/src/theory_core/Makefile0000664000175400017540000000063511033512415017026 0ustar mdetersmdeters################################################## # About this Makefile # # This Makefile depends on Makefile.opts ################################################## MODULE = theory_core SRC = theory.cpp \ theory_core.cpp \ core_theorem_producer.cpp \ expr_transform.cpp \ bryant.cpp HEADERS = core_proof_rules.h \ core_theorem_producer.h LIBRARY=libtheory_core.a include ../../Makefile.local cvc3-2.4.1/src/theory_core/core_theorem_producer.h0000664000175400017540000000535711146605674022142 0ustar mdetersmdeters/*****************************************************************************/ /*! * \file core_theorem_producer.h * * Author: Sergey Berezin * * Created: Feb 05 03:40:36 GMT 2003 * *
* * License to use, copy, modify, sell and/or distribute this software * and its documentation for any purpose is hereby granted without * royalty, subject to the terms and conditions defined in the \ref * LICENSE file provided with this distribution. * *
* */ /*****************************************************************************/ // CLASS: CoreTheoremProducer // // AUTHOR: Sergey Berezin, 12/09/2002 // // Description: Implementation of the proof rules for ground // equational logic (reflexivity, symmetry, transitivity, and // substitutivity). // /////////////////////////////////////////////////////////////////////////////// #ifndef _cvc3__core_theorem_producer_h_ #define _cvc3__core_theorem_producer_h_ #include "core_proof_rules.h" #include "theorem_producer.h" namespace CVC3 { class TheoryCore; class CoreTheoremProducer: public CoreProofRules, public TheoremProducer { private: //! pointer to theory core TheoryCore* d_core; public: CoreTheoremProducer(TheoremManager* tm, TheoryCore* core) : TheoremProducer(tm), d_core(core) { } virtual ~CoreTheoremProducer() { } Theorem typePred(const Expr& e); Theorem rewriteLetDecl(const Expr& e); Theorem rewriteNotAnd(const Expr& e); Theorem rewriteNotOr(const Expr& e); Theorem rewriteNotIff(const Expr& e); Theorem rewriteNotIte(const Expr& e); Theorem rewriteIteThen(const Expr& e, const Theorem& thenThm); Theorem rewriteIteElse(const Expr& e, const Theorem& elseThm); Theorem rewriteIteBool(const Expr& c, const Expr& e1, const Expr& e2); Theorem orDistributivityRule(const Expr& e); Theorem andDistributivityRule(const Expr& e); Theorem rewriteImplies(const Expr& e); Theorem rewriteDistinct(const Expr& e); Theorem NotToIte(const Expr& not_e); Theorem OrToIte(const Expr& e); Theorem AndToIte(const Expr& e); Theorem IffToIte(const Expr& e); Theorem ImpToIte(const Expr& e); Theorem rewriteIteToNot(const Expr& e); Theorem rewriteIteToOr(const Expr& e); Theorem rewriteIteToAnd(const Expr& e); Theorem rewriteIteToIff(const Expr& e); Theorem rewriteIteToImp(const Expr& e); Theorem rewriteIteCond(const Expr& e); Theorem ifLiftUnaryRule(const Expr& e); Theorem iffOrDistrib(const Expr& iff); Theorem iffAndDistrib(const Expr& iff); Theorem rewriteAndSubterms(const Expr& e, int idx); Theorem rewriteOrSubterms(const Expr& e, int idx); Theorem dummyTheorem(const Expr& e); }; // end of class CoreTheoremProducer } // end of namespace CVC3 #endif cvc3-2.4.1/src/theory_core/theory_core.cpp0000644000175400017540000037376311624746724020453 0ustar mdetersmdeters/*****************************************************************************/ /*! * \file theory_core.cpp * * Author: Clark Barrett, Vijay Ganesh (CNF converter) * * Created: Thu Jan 30 16:57:52 2003 * *
* * License to use, copy, modify, sell and/or distribute this software * and its documentation for any purpose is hereby granted without * royalty, subject to the terms and conditions defined in the \ref * LICENSE file provided with this distribution. * *
* */ /*****************************************************************************/ #include #include #include #include "command_line_flags.h" #include "expr.h" #include "notifylist.h" #include "pretty_printer.h" #include "common_proof_rules.h" #include "parser_exception.h" #include "typecheck_exception.h" #include "smtlib_exception.h" #include "eval_exception.h" #include "theory_core.h" #include "expr_transform.h" #include "core_proof_rules.h" #include "theorem_manager.h" #include "translator.h" #include "theory_arith.h" // for isReal() tester using namespace std; namespace CVC3 { //! Implementation of PrettyPrinter class /*! \ingroup PrettyPrinting */ class PrettyPrinterCore: public PrettyPrinter { private: TheoryCore *d_core; //! Disable the default constructor PrettyPrinterCore() { } public: //! Constructor PrettyPrinterCore(TheoryCore* core): d_core(core) { } ExprStream& print(ExprStream& os, const Expr& e) { if(e.isString()) return e.print(os); else if (e.isApply()) return d_core->theoryOf(e)->print(os, e); else if(d_core->hasTheory(e.getKind())) return d_core->theoryOf(e.getKind())->print(os, e); else return e.print(os); } }; class TypeComputerCore: public ExprManager::TypeComputer { TheoryCore *d_core; public: TypeComputerCore(TheoryCore* core): d_core(core) { } void computeType(const Expr& e) { DebugAssert(!e.isVar(), "Variables should have a type: "+e.toString()); Theory* i = d_core->theoryOf(e.getKind()); if (e.isApply()) i = d_core->theoryOf(e); i->computeType(e); DebugAssert(!e.lookupType().getExpr().isNull(), "Type not set by computeType"); } void checkType(const Expr& e) { if (!e.isType()) throw Exception ("Tried to use non-type as a type: "+e.toString()); d_core->theoryOf(e)->checkType(e); e.setValidType(); } Cardinality finiteTypeInfo(Expr& e, Unsigned& n, bool enumerate, bool computeSize) { DebugAssert(e.isType(), "finiteTypeInfo called on non-type"); return d_core->theoryOf(e)->finiteTypeInfo(e, n, enumerate, computeSize); } }; ostream& operator<<(ostream& os, const NotifyList& l) { os << "NotifyList(\n"; for(size_t i=0,iend=l.size(); igetName() << ", " << l.getExpr(i) << "]\n"; } return os << ")"; } } using namespace CVC3; /*****************************************************************************/ /* * Private helper functions */ /*****************************************************************************/ bool TheoryCore::processFactQueue(EffortLevel effort) { Theorem thm; vector::iterator i, iend = d_theories.end(); bool lemmasAdded = false; do { processUpdates(); while (!d_queue.empty() && !d_inconsistent && !timeLimitReached()) { thm = d_queue.front(); d_queue.pop(); assertFactCore(thm); processUpdates(); }; if (d_inconsistent) break; while (!d_queueSE.empty() && !timeLimitReached()) { // Copy a Theorem by value, to guarantee valid reference down // the call chain lemmasAdded = true; Theorem thm(d_queueSE.back()); d_queueSE.pop_back(); d_coreSatAPI->addLemma(thm); } if (effort > LOW) { for(i = d_theories.begin(); d_update_thms.empty() && d_queue.empty() && i != iend && !d_inconsistent && !timeLimitReached(); ++i) { (*i)->checkSat(effort == FULL && !lemmasAdded); } } } while ((!d_queue.empty() || !d_update_thms.empty()) && !d_inconsistent && !timeLimitReached()); if (d_inconsistent) { d_update_thms.clear(); d_update_data.clear(); while(d_queue.size()) d_queue.pop(); d_queueSE.clear(); return false; } if (timeLimitReached()) { // clear all work queues to satisfy invariants d_update_thms.clear(); d_update_data.clear(); while (!d_queue.empty()) d_queue.pop(); d_queueSE.clear(); } return lemmasAdded; } void TheoryCore::processNotify(const Theorem& e, NotifyList *L) { ++d_inUpdate; DebugAssert(L, "Expected non-NULL notify list"); for(unsigned k = 0; k < L->size() && !d_inconsistent; ++k) { L->getTheory(k)->update(e, L->getExpr(k)); } --d_inUpdate; } Theorem TheoryCore::simplify(const Expr& e) { DebugAssert(d_simpStack.count(e) == 0, "TheoryCore::simplify: loop detected over e =\n" +e.toString()); DebugAssert(d_simpStack.size() < 10000, "TheoryCore::simplify: too deep recursion depth"); IF_DEBUG(d_simpStack[e] = true;) // Normally, if an expr has a find, we don't need to simplify, just return the find. // However, if we are in the middle of an update, the find may not yet be updated, so // we should do a full simplify. The exception is expressions like // uninterp. functions or reads that use a congruence closure algorithm that // relies on not simplifying inside of expressions that have finds. if (e.hasFind()) { DebugAssert((find(e).getRHS().hasFind() && find(e).getRHS().isTerm()) || find(e).getRHS().isTrue() || find(e).getRHS().isFalse(), "Unexpected find pointer"); if (d_inUpdate) { if (e.usesCC()) { Theorem thm = find(e); if (!thm.isRefl()) { thm = transitivityRule(thm, simplify(thm.getRHS())); } IF_DEBUG(d_simpStack.erase(e);) return thm; } } else { IF_DEBUG(d_simpStack.erase(e);) return find(e); } } if(e.validSimpCache()) { IF_DEBUG(d_simpStack.erase(e);) return e.getSimpCache(); } Theorem thm; if (e.isVar()) { thm = rewriteCore(e); } else { thm = rewriteCore(theoryOf(e.getOpKind())->simplifyOp(e)); } const Expr& e2 = thm.getRHS(); #ifdef _CVC3_DEBUG_MODE if (!e2.usesCC()) { //2.isTerm() || !e2.hasFind()) { // The rewriter should guarantee that all of its children are simplified. for (int k=0; kiffTrueElim(thm)); } else if (thm.getRHS().isFalse()) { setFindLiteral(d_commonRules->iffFalseElim(thm)); } else { DebugAssert(e.isRewrite(), "Unexpected theorem in TheoryCore::update"); if (e.getRHS().getType().isBool()) continue; find(e.getRHS()).getRHS().addToNotify(this, d); if (thm.getRHS().isAbsAtomicFormula()) thm.getRHS().addToNotify(this, d); } } } void TheoryCore::assertFactCore(const Theorem& e) { IF_DEBUG(string indentStr(getCM()->scopeLevel(), ' ');) TRACE("assertFactCore", indentStr, "AssertFactCore: ", e.getExpr().toString(PRESENTATION_LANG)); Theorem estarThm(e); Expr estar = e.getExpr(); IF_DEBUG(Expr e2 = estar;) Theorem equiv = simplify(estar); if (!equiv.isRefl()) { estarThm = iffMP(e, equiv); // Make sure originally asserted atomic formulas have a find pointer if (!estar.isTrue() && estar.isAbsLiteral()) { setFindLiteral(e); } estar = estarThm.getExpr(); } if (estar.isAbsLiteral()) { if (estar.isEq()) { Theorem solvedThm(solve(estarThm)); if(estar != solvedThm.getExpr()) setFindLiteral(estarThm); if (!solvedThm.getExpr().isTrue()) assertEqualities(solvedThm); } else if (estar.isFalse()) { IF_DEBUG(debugger.counter("conflicts from simplifier")++;) setInconsistent(estarThm); } else if (!estar.isTrue()) { assertFormula(estarThm); } else { // estar is true, nothing will be done // Make sure equivalence classes of equations between two terms with finds get merged // We skip this check for now because unsolvable nonlinear equations bring up this kind of // problems, i.e. x^2 + y^2 = z^2 is not solved, it is true, but the find of LHS and RHS are // different if (!incomplete() && e.isRewrite() && e.getLHS().hasFind() && e.getRHS().hasFind() && find(e.getLHS()).getRHS() != find(e.getRHS()).getRHS()) { TRACE("assertFactCore", "Problem (LHS of): ", e.getExpr(), ""); TRACE("assertFactCore", find(e.getLHS()).getRHS(), " vs ", find(e.getRHS()).getRHS()); IF_DEBUG(cerr << "Warning: Equivalence classes didn't get merged" << endl;) } } } else if (estar.isAnd()) { for(int i=0,iend=estar.arity(); iandElim(estarThm, i)); return; } else { // Notify the search engine enqueueSE(estarThm); } DebugAssert(!e2.isAbsLiteral() || e2.hasFind() || (e2.isNot() && e2[0].hasFind()), "assertFactCore: e2 = "+e2.toString()); DebugAssert(!estar.isAbsLiteral() || estar.hasFind() || (estar.isNot() && estar[0].hasFind()), "assertFactCore: estar = "+estar.toString()); } void TheoryCore::assertFormula(const Theorem& thm) { const Expr& e = thm.getExpr(); DebugAssert(e.isAbsLiteral(),"assertFormula: nonliteral asserted:\n " +thm.toString()); IF_DEBUG(string indentStr(getCM()->scopeLevel(), ' ');) TRACE("assertFormula",indentStr,"AssertFormula: ", e.toString(PRESENTATION_LANG)); Theory* i = theoryOf(e); Theory* i2 = i; // Recursively set up terms in this formula setupTerm(e,i,thm); // Use find to force af to rewrite to TRUE and NOT af to rewrite to FALSE, // where af is an atomic formula. If af is an equality, make sure its lhs // is greater than its rhs so the simplifier will be able to use the find. DebugAssert(!e.isNot() || (!e.hasFind() && !e[0].hasFind()), "Expected negated argument to assertFormula to not have find"); setFindLiteral(thm); // Special processing for existentials, equalities, disequalities switch (e.getKind()) { case EXISTS: // Do not send existential quantifiers to DPs; instead, skolemize them enqueueFact(d_commonRules->skolemize(thm)); return; case NOT: if (e[0].isEq()) { // Save the disequality for later processing e[0][0].addToNotify(this, e); e[0][1].addToNotify(this, e); i2 = theoryOf(getBaseType(e[0][0])); DebugAssert(e[0][0] > e[0][1], "Expected lhs of diseq to be greater"); // if(e[0][0] < e[0][1]) { // Expr e2 = e[0][1].eqExpr(e[0][0]); // DebugAssert(!e2.hasFind(), "already has find"); // thm2 = transitivityRule(d_commonRules->rewriteUsingSymmetry(e2), // d_commonRules->notToIff(thm)); // setFindLiteral(d_commonRules->iffFalseElim(thm2)); // } } break; case EQ: i2 = theoryOf(getBaseType(e[0])); if (e[0] < e[1]) { // this can happen because of the solver Expr e2 = e[1].eqExpr(e[0]); if (!e2.hasFind()) { Theorem thm2 = transitivityRule(d_commonRules->rewriteUsingSymmetry(e2), d_commonRules->iffTrue(thm)); setFindLiteral(d_commonRules->iffTrueElim(thm2)); } } break; default: break; } // Send formula to the appropriate DP i->assertFact(thm); // Equalities and disequalities are also asserted to the theories of // their types if (i != i2) i2->assertFact(thm); } Theorem CVC3::TheoryCore::rewriteCore(const Expr& e) { // Normally, if an expr has a find, we don't need to rewrite, just return the find. // However, if we are in the middle of an update, the find may not yet be updated, so // we should simplify the result. if (e.hasFind()) { Theorem thm = find(e); if (d_inUpdate && !thm.isRefl()) { thm = transitivityRule(thm, simplify(thm.getRHS())); } return thm; } if (e.isRewriteNormal()) { IF_DEBUG( // Check that the RewriteNormal flag is set properly. Note that we // assume theory-specific rewrites are idempotent e.clearRewriteNormal(); Expr rewritten(rewriteCore(e).getRHS()); e.setRewriteNormal(); // Restore the flag DebugAssert(rewritten == e, "Expected no change: e = " + e.toString() +"\n rewriteCore(e) = "+rewritten.toString()); ) return reflexivityRule(e); } switch (e.getKind()) { case EQ: if (e[0] < e[1]) return rewriteCore(d_commonRules->rewriteUsingSymmetry(e)); else if (e[0] == e[1]) return d_commonRules->rewriteReflexivity(e); break; case NOT: if (e[0].isNot()) return rewriteCore(d_commonRules->rewriteNotNot(e)); break; default: break; } Theorem thm = theoryOf(e)->rewrite(e); const Expr& e2 = thm.getRHS(); // Theory-specific rewrites for equality should ensure that lhs >= rhs, or // there is danger of an infinite loop. DebugAssert(!e2.isEq() || e2[0] >= e2[1], "theory-specific rewrites for equality should ensure lhs >= rhs"); if (e != e2) { thm = rewriteCore(thm); } return thm; } void TheoryCore::setFindLiteral(const Theorem& thm) { const Expr& e = thm.getExpr(); NotifyList* L; if (e.isNot()) { const Expr& e0 = e[0]; if (!e0.hasFind()) { IF_DEBUG(string indentStr(getCM()->scopeLevel(), ' ');) TRACE("setFindLiteral", indentStr, "SFL: ", e.toString(PRESENTATION_LANG)); Theorem findThm = d_commonRules->notToIff(thm); e0.setFind(findThm); if (e0.isRegisteredAtom()) { DebugAssert(!e.isImpliedLiteral(), "Should be new implied lit"); e.setImpliedLiteral(); d_impliedLiterals.push_back(thm); } d_em->invalidateSimpCache(); L = e0.getNotify(); if (L) processNotify(findThm, L); } else { Theorem findThm = find(e0); if (findThm.getRHS().isTrue()) { setInconsistent(iffMP(d_commonRules->iffTrueElim(findThm), d_commonRules->notToIff(thm))); } } } else if (!e.hasFind()) { IF_DEBUG(string indentStr(getCM()->scopeLevel(), ' ');) TRACE("setFindLiteral", indentStr, "SFL: ", e.toString(PRESENTATION_LANG)); Theorem findThm = d_commonRules->iffTrue(thm); e.setFind(findThm); if (e.isRegisteredAtom()) { DebugAssert(!e.isImpliedLiteral(), "Should be new implied lit"); e.setImpliedLiteral(); d_impliedLiterals.push_back(thm); } d_em->invalidateSimpCache(); L = e.getNotify(); if (L) processNotify(findThm, L); } else { Theorem findThm = find(e); if (findThm.getRHS().isFalse()) { setInconsistent(iffMP(thm, findThm)); } } } Theorem TheoryCore::rewriteLitCore(const Expr& e) { switch (e.getKind()) { case EQ: if (e[0] == e[1]) return d_commonRules->rewriteReflexivity(e); else if (e[0] < e[1]) return d_commonRules->rewriteUsingSymmetry(e); break; case NOT: if (e[0].isTrue()) return d_commonRules->rewriteNotTrue(e); else if (e[0].isFalse()) return d_commonRules->rewriteNotFalse(e); else if (e[0].isNot()) return d_commonRules->rewriteNotNot(e); break; default: DebugAssert(false, "TheoryCore::rewriteLitCore(" + e.toString() + "): Not implemented"); break; } return reflexivityRule(e); } void TheoryCore::enqueueSE(const Theorem& thm) { DebugAssert(okToEnqueue(), "enqueueSE()"); d_queueSE.push_back(thm); } Theorem TheoryCore::getModelValue(const Expr& e) { ExprHashMap::iterator i=d_varAssignments.find(e), iend=d_varAssignments.end(); if(i!=iend) return (*i).second; else return find(e); } //! An auxiliary recursive function to process COND expressions into ITE Expr TheoryCore::processCond(const Expr& e, int i) { DebugAssert(i < e.arity()-1, "e = "+e.toString()+", i = "+int2string(i)); if(i == e.arity()-2) { if(e[i].getKind() == RAW_LIST && e[i].arity() == 2 && e[i+1].getKind() == RAW_LIST && e[i+1].arity() == 2 && e[i+1][0].getKind() == ID && e[i+1][0][0].getString() == "_ELSE") { Expr c(parseExpr(e[i][0])); Expr e1(parseExpr(e[i][1])); Expr e2(parseExpr(e[i+1][1])); return c.iteExpr(e1,e2); } } else { if(e[i].getKind() == RAW_LIST && e[i].arity() == 2 && e[i+1].getKind() == RAW_LIST && e[i+1].arity() == 2) { Expr c(parseExpr(e[i][0])); Expr e1(parseExpr(e[i][1])); Expr e2(processCond(e, i+1)); return c.iteExpr(e1,e2); } } throw ParserException("Parse Error: bad COND expression: "+e.toString()); } bool TheoryCore::isBasicKind(int kind) { switch (kind) { case VARDECLS: case LETDECLS: case HELP: case GET_VALUE: case GET_ASSIGNMENT: case DUMP_PROOF: case DUMP_ASSUMPTIONS: case DUMP_SIG: case DUMP_TCC: case DUMP_TCC_ASSUMPTIONS: case DUMP_TCC_PROOF: case DUMP_CLOSURE: case DUMP_CLOSURE_PROOF: case WHERE: case ASSERTIONS: case ASSUMPTIONS: case COUNTEREXAMPLE: case COUNTERMODEL: case ASSERT: case PRINT: case QUERY: case CHECKSAT: case CONTINUE: case RESTART: case TRACE: case ECHO: case UNTRACE: case VARLIST: case FORGET: case GET_TYPE: case IFF: case IMPLIES: case TYPEDEF: case OPTION: case AND: case OR: case XOR: case NOT: case DISTINCT: case CALL: case TRANSFORM: case CHECK_TYPE: case VARDECL: case GET_CHILD: case SUBSTITUTE: case SEQ: case DBG: case PUSH: case POP: case POPTO: case PUSH_SCOPE: case POP_SCOPE: case POPTO_SCOPE: case RESET: case LETDECL: case ELSE: case CONTEXT: return true; default: break; } return false; } TheoryCore::TheoryCore(ContextManager* cm, ExprManager* em, TheoremManager* tm, Translator* translator, const CLFlags& flags, Statistics& statistics) : Theory(), d_cm(cm), d_tm(tm), d_flags(flags), d_statistics(statistics), d_translator(translator), d_inconsistent(cm->getCurrentContext(), false, 0), d_incomplete(cm->getCurrentContext()), d_incThm(cm->getCurrentContext()), d_terms(cm->getCurrentContext()), // d_termTheorems(cm->getCurrentContext()), d_predicates(cm->getCurrentContext()), d_solver(NULL), d_simplifyInPlace(false), d_currentRecursiveSimplifier(NULL), d_resourceLimit(0), d_timeBase(0), d_timeLimit(0), d_inCheckSATCore(false), d_inAddFact(false), d_inRegisterAtom(false), d_inPP(false), d_notifyObj(this, cm->getCurrentContext()), d_impliedLiterals(cm->getCurrentContext()), d_impliedLiteralsIdx(cm->getCurrentContext(), 0, 0), d_notifyEq(cm->getCurrentContext()), d_inUpdate(0), d_coreSatAPI(NULL) { d_em = em; // Since we are in the middle of creating TheoryCore, we set the pointer to // TheoryCore in the Theory base class ourselves. d_theoryCore = this; d_commonRules = tm->getRules(); d_name = "Core"; d_theoryUsed = false; d_rules = createProofRules(tm); d_printer = new PrettyPrinterCore(this); d_typeComputer = new TypeComputerCore(this); d_em->registerTypeComputer(d_typeComputer); d_exprTrans = new ExprTransform(this); // Register the pretty-printer d_em->registerPrettyPrinter(*d_printer); // for (int i = 0; i < LAST_KIND; ++i) d_theoryMap[i] = NULL; vector kinds; kinds.push_back(RAW_LIST); kinds.push_back(BOOLEAN); kinds.push_back(ANY_TYPE); kinds.push_back(SUBTYPE); kinds.push_back(STRING_EXPR); kinds.push_back(ID); kinds.push_back(TRUE_EXPR); kinds.push_back(FALSE_EXPR); kinds.push_back(UCONST); kinds.push_back(BOUND_VAR); kinds.push_back(SKOLEM_VAR); kinds.push_back(EQ); kinds.push_back(NEQ); kinds.push_back(DISTINCT); kinds.push_back(ECHO); kinds.push_back(DBG); kinds.push_back(TRACE); kinds.push_back(UNTRACE); kinds.push_back(OPTION); kinds.push_back(HELP); kinds.push_back(AND); kinds.push_back(OR); kinds.push_back(IFTHEN); kinds.push_back(IF); kinds.push_back(ELSE); kinds.push_back(COND); kinds.push_back(XOR); kinds.push_back(NOT); kinds.push_back(ITE); kinds.push_back(IFF); kinds.push_back(IMPLIES); kinds.push_back(APPLY); // For printing LET expressions (in DAG printing mode) kinds.push_back(LET); kinds.push_back(LETDECLS); kinds.push_back(LETDECL); // For printing raw parsed quantifier expressions kinds.push_back(VARLIST); kinds.push_back(VARDECLS); kinds.push_back(VARDECL); // Type declarations and definitions kinds.push_back(TYPE); // For printing type declarations (or definitions) kinds.push_back(CONST); kinds.push_back(TYPEDEF); kinds.push_back(DEFUN); // Printing proofs kinds.push_back(PF_APPLY); kinds.push_back(PF_HOLE); // Register commands for pretty-printing. Currently, only ASSERT // needs to be printed. kinds.push_back(ASSERT); kinds.push_back(QUERY); kinds.push_back(PRINT); kinds.push_back(GET_VALUE); kinds.push_back(GET_ASSIGNMENT); kinds.push_back(DUMP_PROOF); kinds.push_back(DUMP_ASSUMPTIONS); kinds.push_back(DUMP_SIG); kinds.push_back(DUMP_TCC); kinds.push_back(DUMP_TCC_ASSUMPTIONS); kinds.push_back(DUMP_TCC_PROOF); kinds.push_back(DUMP_CLOSURE); kinds.push_back(DUMP_CLOSURE_PROOF); kinds.push_back(TRANSFORM); kinds.push_back(CALL); kinds.push_back(WHERE); kinds.push_back(ASSERTIONS); kinds.push_back(ASSUMPTIONS); kinds.push_back(COUNTEREXAMPLE); kinds.push_back(COUNTERMODEL); kinds.push_back(PUSH); kinds.push_back(POP); kinds.push_back(POPTO); kinds.push_back(PUSH_SCOPE); kinds.push_back(POP_SCOPE); kinds.push_back(POPTO_SCOPE); kinds.push_back(RESET); kinds.push_back(CONTEXT); kinds.push_back(FORGET); kinds.push_back(GET_TYPE); kinds.push_back(CHECK_TYPE); kinds.push_back(GET_CHILD); kinds.push_back(SUBSTITUTE); kinds.push_back(SEQ); kinds.push_back(ARITH_VAR_ORDER); kinds.push_back(ANNOTATION); kinds.push_back(THEOREM_KIND); kinds.push_back(AND_R); kinds.push_back(IFF_R); kinds.push_back(ITE_R); registerTheory(this, kinds); } TheoryCore::~TheoryCore() { delete d_exprTrans; delete d_rules; delete d_typeComputer; d_em->unregisterPrettyPrinter(); delete d_printer; } Theorem TheoryCore::callTheoryPreprocess(const Expr& e) { Theorem thm = reflexivityRule(e); for(unsigned i=1; itheoryPreprocess(thm.getRHS())); } processFactQueue(LOW); return thm; } Theorem TheoryCore::getTheoremForTerm(const Expr& e){ // <<<<<<< theory_core_sat.cpp // // DebugAssert(e.hasFind(), "getTheoremForTerm called on term without find"); // CDMap::iterator i = d_termTheorems.find(e); // if( i == d_termTheorems.end()){ // TRACE("quantlevel", "getTheoremForTerm: no theorem found: ", e , ""); // Theorem nul; // return nul; // } // // DebugAssert(i != d_termTheorems.end(), "getTheoremForTerm: no theorem found"); // ======= // DebugAssert(e.hasFind() || e.isStoredPredicate(), "getTheoremForTerm called on invalid term"); hash_map::iterator i = d_termTheorems.find(e); // yeting, I think we should use CDMap here, but a static map works better. // CDMap::iterator i = d_termTheorems.find(e); // DebugAssert(i != d_termTheorems.end(), "getTheoremForTerm: no theorem found"); if(i != d_termTheorems.end()){ return (*i).second; } else{ TRACE("quantlevel", "getTheoremForTerm: no theorem found: ", e , ""); Theorem x; return x; } } #ifdef _CVC3_DEBUG_MODE int TheoryCore::getCurQuantLevel(){ return theoryOf(FORALL)->help(1); } #endif unsigned TheoryCore::getQuantLevelForTerm(const Expr& e) { /* if (!e.hasFind() && !e.isStoredPredicate()) { TRACE("quantlevel", "get 0 ", e , ""); return 0; } */ TRACE("quantlevel", "trying get level for (" + e.toString() + ") with index ", "", e.getIndex()); Theorem thm = getTheoremForTerm(e); if (thm.isNull()) { if(e.isNot()){ thm = getTheoremForTerm(e[0]); } } if(thm.isNull()){ if (e.inUserAssumption()) { return 0 ; } else{ TRACE("quantlevel", "expr get null :", e.getIndex(), "" ); if( ! (e.isNot() || e.isIff())){ TRACE("quantlevel", "cannot find expr: " , e, ""); } return 0; } } TRACE("quantlevel", "expr get level:", thm.getQuantLevel(), ""); /* if(thm.getQuantLevel() != thm.getQuantLevelDebug()){ cout << "theorem: " << thm.getExpr().toString() < qld ? ql : qld); */ } /////////////////////////////////////////////////////////////////////////////// // Theory interface implementaion // /////////////////////////////////////////////////////////////////////////////// void TheoryCore::assertFact(const Theorem& e) { DebugAssert(e.getExpr().unnegate().getKind() == SKOLEM_VAR || e.getExpr().unnegate().getKind() == UCONST, "TheoryCore::assertFact("+e.toString()+")"); } Theorem TheoryCore::rewrite(const Expr& e) { Theorem thm; switch (e.getKind()) { case TRUE_EXPR: case FALSE_EXPR: case UCONST: case BOUND_VAR: case SKOLEM_VAR: thm = reflexivityRule(e); break; // do not rewrite case LETDECL: // Replace LETDECL with its definition. The // typechecker makes sure it's type-safe to do so. thm = d_rules->rewriteLetDecl(e); break; case APPLY: //TODO: this is a bit of a hack if (e.getOpKind() == LAMBDA) thm = theoryOf(LAMBDA)->rewrite(e); else thm = reflexivityRule(e); break; case EQ: case NOT: thm = rewriteLitCore(e); break; case DISTINCT: { Theorem thm1 = d_rules->rewriteDistinct(e); thm = transitivityRule(thm1, simplify(thm1.getRHS())); break; } case IMPLIES: { thm = d_rules->rewriteImplies(e); const Expr& rhs = thm.getRHS(); // rhs = OR(!e1, e2). Rewrite !e1, then top-level OR(). DebugAssert(rhs.isOr() && rhs.arity() == 2, "TheoryCore::rewrite[IMPLIES]: rhs = "+rhs.toString()); Theorem rw = rewriteCore(rhs[0]); if (!rw.isRefl()) { vector changed; vector thms; changed.push_back(0); thms.push_back(rw); rw = substitutivityRule(rhs, changed, thms); // Simplify to the find pointer of the result rw = transitivityRule(rw, find(rw.getRHS())); // Now rw = Theorem(rhs = rhs') rw = transitivityRule(rw, rewrite(rw.getRHS())); } else rw = rewrite(rhs); thm = transitivityRule(thm, rw); // thm = transitivityRule(thm, simplify(thm.getRHS())); break; } case XOR: { thm = d_commonRules->xorToIff(e); thm = transitivityRule(thm, simplify(thm.getRHS())); break; } case IFF: { thm = d_commonRules->rewriteIff(e); Expr e1 = thm.getRHS(); // The only time we need to rewrite the result (e1) is when // e==(FALSE<=>e[1]) or (e[1]<=>FALSE), so e1==!e[1]. if (e != e1 && e1.isNot()) thm = transitivityRule(thm, rewriteCore(e1)); break; } case ITE: thm = rewriteIte(e); if (!thm.isRefl()) break; else if (getFlags()["un-ite-ify"].getBool()) { // undo the rewriting of Boolean connectives to ITEs. // helpful for examples converted from SVC. // must rewrite again because we might create expressions // that can be further rewritten, and we must normalize. if (e[1].isFalse() && e[2].isTrue()) thm = rewriteCore(d_rules->rewriteIteToNot(e)); else if (e[1].isTrue()) thm = rewriteCore(d_rules->rewriteIteToOr(e)); else if (e[2].isFalse()) thm = rewriteCore(d_rules->rewriteIteToAnd(e)); else if (e[2].isTrue()) thm = rewriteCore(d_rules->rewriteIteToImp(e)); else if (e[1] == e[2].negate()) thm = rewriteCore(d_rules->rewriteIteToIff(e)); else thm = reflexivityRule(e); } else if(getFlags()["ite-cond-simp"].getBool()) { thm = d_rules->rewriteIteCond(e); if (!thm.isRefl()) { thm = transitivityRule(thm, simplify(thm.getRHS())); } } else thm = reflexivityRule(e); break; case AND: { thm = rewriteAnd(e); Expr ee = thm.getRHS(); break; } case OR: { thm = rewriteOr(e); Expr ee = thm.getRHS(); break; } // Quantifiers case FORALL: case EXISTS: thm = d_commonRules->reflexivityRule(e); break; // don't need to rewrite these case AND_R: case IFF_R: case ITE_R: thm = reflexivityRule(e); break; default: DebugAssert(false, "TheoryCore::rewrite(" + e.toString() + " : " + e.getType().toString() + "): Not implemented"); break; } DebugAssert(thm.getLHS() == e, "TheoryCore::rewrite("+e.toString() +") = "+thm.getExpr().toString()); Expr rhs = thm.getRHS(); // Advanced Boolean rewrites switch(rhs.getKind()) { case AND: if(getFlags()["simp-and"].getBool()) { Theorem tmp(reflexivityRule(rhs)); for(int i=0, iend=rhs.arity(); irewriteAndSubterms(tmp.getRHS(), i)); } if(tmp.getRHS() != rhs) { // Something changed: simplify recursively thm = transitivityRule(thm, tmp); thm = transitivityRule(thm, simplify(thm.getRHS())); rhs = thm.getRHS(); } } break; case OR: if(getFlags()["simp-or"].getBool()) { Theorem tmp(reflexivityRule(rhs)); for(int i=0, iend=rhs.arity(); irewriteOrSubterms(tmp.getRHS(), i)); } if(tmp.getRHS() != rhs) { // Something changed: simplify recursively thm = transitivityRule(thm, tmp); thm = transitivityRule(thm, simplify(thm.getRHS())); rhs = thm.getRHS(); } } break; default: break; } if (theoryOf(rhs) == this) { // Core rewrites are idempotent (FIXME: are they, still?) rhs.setRewriteNormal(); } return thm; } /*! We use the update method of theory core to track registered atomic * formulas. Updates are recorded and then processed by calling processUpdates * once all equalities have been processed. */ void TheoryCore::update(const Theorem& e, const Expr& d) { // Disequalities if (d.isNot()) { const Expr& eq = d[0]; DebugAssert(eq.isEq(), "Expected equality"); Theorem thm1(find(eq[0])); Theorem thm2(find(eq[1])); const Expr& newlhs = thm1.getRHS(); const Expr& newrhs = thm2.getRHS(); if (newlhs == newrhs) { Theorem thm = find(eq); DebugAssert(thm.getRHS().isFalse(), "Expected disequality"); Theorem leftEqRight = transitivityRule(thm1, symmetryRule(thm2)); setInconsistent(iffMP(leftEqRight, thm)); } else { e.getRHS().addToNotify(this, d); // propagate new disequality Theorem thm = d_commonRules->substitutivityRule(eq, thm1, thm2); if (newlhs < newrhs) { thm = transitivityRule(thm, d_commonRules->rewriteUsingSymmetry(thm.getRHS())); } const Expr& newEq = thm.getRHS(); if (newEq.hasFind()) { Theorem thm2 = find(newEq); if (thm2.getRHS().isTrue()) { thm2 = transitivityRule(thm, thm2); thm = find(eq); DebugAssert(thm.getRHS().isFalse(), "Expected disequality"); thm = transitivityRule(symmetryRule(thm), thm2); setInconsistent(d_commonRules->iffTrueElim(thm)); } // else if thm2.getRHS().isFalse(), nothing to do } else { Theorem thm2 = find(eq); DebugAssert(thm2.getRHS().isFalse(), "Expected disequality"); thm2 = transitivityRule(symmetryRule(thm),thm2); setFindLiteral(d_commonRules->iffFalseElim(thm2)); } } } // Registered atoms else { DebugAssert(d.isRegisteredAtom(), "Expected registered atom"); if (!d.isImpliedLiteral()) { d_update_thms.push_back(e); d_update_data.push_back(d); } } } void TheoryCore::checkEquation(const Theorem& thm) { Expr e2 = thm.getExpr(); DebugAssert(e2.isEq(), "Expected equation"); Expr solved; if (d_solver) { solved = d_solver->solve(thm).getExpr(); DebugAssert(solved == e2, "e2 = "+e2.toString() +"\nsolved = "+solved.toString()); } Theory* i = theoryOf(e2); if (d_solver != i) { solved = i->solve(thm).getExpr(); DebugAssert(solved == e2, "e2 = "+e2.toString() +"\nsolved = "+solved.toString()); } Theory* j = theoryOf(e2[0].getType()); if (d_solver != j && i != j) { solved = j->solve(thm).getExpr(); DebugAssert(solved == e2, "e2 = "+e2.toString() +"\nsolved = "+solved.toString()); } } void TheoryCore::checkSolved(const Theorem& thm) { Expr e2 = thm.getExpr(); if (e2.isAnd()) { for (int index = 0; index < e2.arity(); ++index) { checkEquation(d_commonRules->andElim(thm, index)); } } else if (!e2.isBoolConst()) checkEquation(thm); } /*****************************************************************************/ /*! * Function: TheoryCore::solve * * Author: Clark Barrett * * Created: Wed Feb 26 16:17:54 2003 * * This is a generalization of what's in my thesis. The goal is to rewrite e * into an equisatisfiable conjunction of equations such that the left-hand * side of each equation is a variable which does not appear as an i-leaf of * the rhs, where i is the theory of the primary solver. Any solution which * satisfies this is fine. "Solvers" from other theories can do whatever they * want as long as we eventually reach this form. */ /*****************************************************************************/ Theorem TheoryCore::solve(const Theorem& eThm) { const Expr& e = eThm.getExpr(); Theorem thm; Expr e2; DebugAssert(eThm.isRewrite() && eThm.getLHS().isTerm(), "Expected equation"); // Invoke the primary solver if (d_solver) { thm = d_solver->solve(eThm); e2 = thm.getExpr(); if (e2.isBoolConst() || e2.isAnd()) { // We expect a conjunction of equations, each of which is terminally solved IF_DEBUG(checkSolved(thm)); return thm; } } else { thm = eThm; e2 = e; } // Invoke solver based on owner of equation DebugAssert(e2.isEq(), "Expected equation"); Theory* i = theoryOf(e2); if (d_solver != i) thm = i->solve(thm); e2 = thm.getExpr(); if (e2.isBoolConst() || e2.isAnd()) { // We expect a conjunction of equations, each of which is solved IF_DEBUG(checkSolved(thm)); return thm; } // Invoke solver based on type of terms in equation DebugAssert(e2.isEq(), "Expected equation"); Theory* j = theoryOf(getBaseType(e2[0])); if (d_solver != j && i != j) thm = j->solve(thm); IF_DEBUG(checkSolved(thm)); return thm; } Theorem TheoryCore::simplifyOp(const Expr& e) { int kind(e.getKind()); switch(kind) { case EQ: case IFF: if(e[0]==e[1]) { IF_DEBUG(debugger.counter("simplified x=x")++;) return d_commonRules->iffTrue(reflexivityRule(e[0])); } return Theory::simplifyOp(e); case AND: case OR: { // Stop when a child has this kind int endKind = (kind==AND)? FALSE_EXPR : TRUE_EXPR; int ar = e.arity(); // Optimization: before simplifying anything recursively, check if // any kid is already TRUE or FALSE, and just return at that point int l(0); for(; l newChildrenThm; vector changed; for(int k = 0; k < ar; ++k) { // Recursively simplify the kids Theorem thm = simplify(e[k]); if (!thm.isRefl()) { if (thm.getRHS().getKind() == endKind) { newChildrenThm.clear(); changed.clear(); newChildrenThm.push_back(thm); changed.push_back(k); thm = substitutivityRule(e, changed, newChildrenThm); // Simplify to TRUE or FALSE if(kind==AND) thm = transitivityRule(thm, rewriteAnd(thm.getRHS())); else thm = transitivityRule(thm, rewriteOr(thm.getRHS())); IF_DEBUG(debugger.counter("simplified AND/OR: skipped kids") += ar-k-1;) return thm; } else { // Child simplified to something else newChildrenThm.push_back(thm); changed.push_back(k); } } } if(changed.size() > 0) return substitutivityRule(e, changed, newChildrenThm); break; } case ITE: { DebugAssert(e.arity()==3, "Bad ITE in TheoryCore::simplify(e=" +e.toString()+")"); // Optimization: check if the two branches are the same, so we // don't have to simplify the condition if(e[1]==e[2]) { IF_DEBUG(debugger.counter("simplified ITE(c,e,e)")++;) Theorem res = d_commonRules->rewriteIteSame(e); return transitivityRule(res, simplify(res.getRHS())); } // First, simplify the conditional vector newChildrenThm; vector changed; Theorem thm = simplify(e[0]); if (!thm.isRefl()) { newChildrenThm.push_back(thm); changed.push_back(0); } Expr cond = thm.getRHS(); for(int k=1; k<=2; ++k) { // If condition value is known, only the appropriate branch // needs to be simplified if (cond.isBoolConst()) { if((k==1 && cond.isFalse()) || (k==2 && cond.isTrue())) { IF_DEBUG(debugger.counter("simplified ITE: skiped one branch")++;) continue; } } thm = simplify(e[k]); if (!thm.isRefl()) { newChildrenThm.push_back(thm); changed.push_back(k); } } if(changed.size() > 0) return substitutivityRule(e, changed, newChildrenThm); break; } case NOT: { Theorem res = simplify(e[0]); if (!res.isRefl()) { return d_commonRules->substitutivityRule(e, res); } break; } case IMPLIES: { Theorem res = d_rules->rewriteImplies(e); return transitivityRule(res, simplifyOp(res.getRHS())); } default: return Theory::simplifyOp(e); } return reflexivityRule(e); } void TheoryCore::checkType(const Expr& e) { switch (e.getKind()) { case BOOLEAN: if (e.arity() > 0) { throw Exception("Ill-formed Boolean type:\n\n"+e.toString()); } break; case SUBTYPE: { if (e.arity() != 1) throw Exception("Ill-formed SUBTYPE expression:\n\n"+e.toString()); Type t = e[0].getType(); if (!t.isFunction()) throw Exception ("Non-function argument to SUBTYPE:\n\n" +e.toString()); if (!t[1].isBool()) throw Exception ("Non-predicate argument to SUBTYPE:\n\n" +e.toString()); } break; case ANY_TYPE: { if (e.arity() != 0) { throw Exception("Expected no children: "+e.toString()); } break; } default: FatalAssert(false, "Unexpected kind in TheoryCore::checkType" +getEM()->getKindName(e.getKind())); } } Cardinality TheoryCore::finiteTypeInfo(Expr& e, Unsigned& n, bool enumerate, bool computeSize) { Cardinality card = CARD_INFINITE; switch (e.getKind()) { case BOOLEAN: card = CARD_FINITE; if (enumerate) { e = (n == 0) ? falseExpr() : (n == 1) ? trueExpr() : Expr(); } if (computeSize) { n = 2; } break; case SUBTYPE: card = CARD_UNKNOWN; break; case ANY_TYPE: card = CARD_UNKNOWN; break; default: FatalAssert(false, "Unexpected kind in TheoryCore::finiteTypeInfo" +getEM()->getKindName(e.getKind())); } return card; } void TheoryCore::computeType(const Expr& e) { switch (e.getKind()) { case ITE: { Type t1(getBaseType(e[1])), t2(getBaseType(e[2])); if (e[0].getType() != boolType()) throw TypecheckException ("The conditional in IF-THEN-ELSE must be BOOLEAN, but is:\n\n" +e[0].getType().toString() +"\n\nIn the expression:\n\n " +e.toString()); if(t1 != t2) { throw TypecheckException ("The types of the IF-THEN-ELSE branches do not match.\n" "THEN branch has the type:\n\n " +e[1].getType().toString() +"\n\nELSE branch has the type:\n\n " +e[2].getType().toString() +"\n\nIn expression:\n\n "+e.toString()); } Type res(e[1].getType()); // If the precise types match in both branches, use it as the // result type. if(res == e[2].getType()) { e.setType(res); } else // Note: setting the base type, since e[1] and e[2] have // different exact types, and the base type is a conservative // approximation we can easily compute. e.setType(t1); } break; case EQ: { Type t0(getBaseType(e[0])), t1(getBaseType(e[1])); if (t0.isBool() || t1.isBool()) { throw TypecheckException ("Cannot use EQ ('=') for BOOLEAN type; use IFF ('<=>') instead.\n" "Error in the following expression:\n"+e.toString()); } if (t0 != t1) { throw TypecheckException ("Type mismatch in equality:\n\n LHS type:\n"+t0.toString() +"\n\n RHS type: \n"+t1.toString() +"\n\n in expression: \n"+e.toString()); } e.setType(boolType()); break; } case DISTINCT: { Type t0(getBaseType(e[0])); for (int i = 1; i < e.arity(); ++i) { if (t0 != getBaseType(e[i])) { throw TypecheckException ("Type mismatch in distinct:\n\n types:\n"+t0.toString() +"\n\n and type: \n"+getBaseType(e[i]).toString() +"\n\n in expression: \n"+e.toString()); } } e.setType(boolType()); break; } case NOT: case AND: case OR: case XOR: case IFF: case IMPLIES: case AND_R: case IFF_R: case ITE_R: for (int k = 0; k < e.arity(); ++k) { if (e[k].getType() != boolType()) { throw TypecheckException(e.toString()); } } if((e.getKind() == NOT && e.arity() != 1) || (e.getKind() == IFF && e.arity() != 2) || (e.getKind() == IMPLIES && e.arity() != 2)) { throw TypecheckException("Wrong arity ("+int2string(e.arity())+") for operator: "+e.toString()); } e.setType(boolType()); break; case LETDECL: { Type varTp(getBaseType(e[0])); Type valTp(getBaseType(e[1])); if(valTp != varTp) { throw TypecheckException("Type mismatch for "+e[0].toString()+":" +"\n declared: " + varTp.toString() +"\n derived: "+ valTp.toString()); } e.setType(e[0].getType()); } break; case APPLY: { DebugAssert(e.isApply(), "Should be application"); DebugAssert(e.arity() > 0, "Expected non-zero arity in APPLY"); Expr funExpr = e.getOpExpr(); Type funType = funExpr.getType(); if(!funType.isFunction()) { throw TypecheckException ("Expected function type for:\n\n" + funExpr.toString() + "\n\n but got this: " +funType.getExpr().toString() +"\n\n in function application:\n\n"+e.toString()); } if(funType.arity() != e.arity()+1) throw TypecheckException("Type mismatch for expression:\n\n " + e.toString() + "\n\nFunction \""+funExpr.toString() +"\" expects "+int2string(funType.arity()-1) +" argument" +string((funType.arity()==2)? "" : "s") +", but received " +int2string(e.arity())+"."); for (int k = 0; k < e.arity(); ++k) { Type valType(getBaseType(e[k])); if (funType[k] != Type::anyType(d_em) && !(valType == getBaseType(funType[k]) || valType == Type::anyType(d_em)) ) { throw TypecheckException("Type mismatch for expression:\n\n " + e[k].toString() + "\n\nhas the following type:\n\n " + e[k].getType().toString() + "\n\nbut the expected type is:\n\n " + funType[k].getExpr().toString() + "\n\nin function application:\n\n " + e.toString()); } } e.setType(funType[funType.arity()-1]); break; } case RAW_LIST: throw TypecheckException("computeType called on RAW_LIST"); break; default: DebugAssert(false,"TheoryCore::computeType(" + e.toString() + "):\nNot implemented"); break; } } Type TheoryCore::computeBaseType(const Type& tp) { const Expr& e = tp.getExpr(); Type res; switch(e.getKind()) { case SUBTYPE: { DebugAssert(e.arity() == 1, "Expr::computeBaseType(): "+e.toString()); Type lambdaTp = e[0].getType(); Type lambdaBaseTp = getBaseType(lambdaTp); DebugAssert(lambdaBaseTp.isFunction(), "Expr::computeBaseType(): lambdaBaseTp = " +lambdaBaseTp.toString()+" in e = "+e.toString()); res = lambdaBaseTp[0]; break; } case BOOLEAN: case ANY_TYPE: res = tp; break; case TYPEDEF: // Compute the base type of the definition res = getBaseType(Type(e[1])); break; default: DebugAssert(false, "TheoryCore::computeBaseType("+tp.toString()+")"); res = tp; } return res; } Expr TheoryCore::computeTCC(const Expr& e) { Expr res; switch (e.getKind()) { case NOT: res = getTCC(e[0]); break; case AND: { // ( (tcc(e1) & !e1) \/ ... \/ (tcc(en) & !en) \/ (tcc(e1)&...&tcc(en)) vector tccs; for(Expr::iterator i=e.begin(), iend=e.end(); i!=iend; ++i) tccs.push_back(getTCC(*i)); vector pairs; pairs.push_back(rewriteAnd(andExpr(tccs)).getRHS()); for(size_t i=0, iend=tccs.size(); i tccs; for(Expr::iterator i=e.begin(), iend=e.end(); i!=iend; ++i) tccs.push_back(getTCC(*i)); vector pairs; pairs.push_back(rewriteAnd(andExpr(tccs)).getRHS()); for(size_t i=0, iend=tccs.size(); icomputeTCC(e); // fall through } default: // All the other operators are strict res = Theory::computeTCC(e); break; } return res; } Expr TheoryCore::computeTypePred(const Type& t, const Expr& e) { Expr tExpr = t.getExpr(); switch(tExpr.getKind()) { case SUBTYPE: { Expr pred = tExpr[0]; const Type& argTp = pred.lookupType()[0]; return Expr(pred.mkOp(), e).andExpr(getTypePred(argTp, e)); } case APPLY: { Theory* i = theoryOf(e); if (i != this) return i->computeTypePred(t, e); // fall through } default: return e.getEM()->trueExpr(); } } Expr TheoryCore::parseExprOp(const Expr& e) { // If the expression is not a list, it must have been already // parsed, so just return it as is. switch(e.getKind()) { case ID: { int kind = getEM()->getKind(e[0].getString()); switch(kind) { case NULL_KIND: return e; // nothing to do case TRUE_EXPR: case FALSE_EXPR: case TYPE: case BOOLEAN: return getEM()->newLeafExpr(kind); default: DebugAssert(false, "Bad use of bare keyword: "+e.toString()); return e; } } case RAW_LIST: break; // break out of switch, do the work default: return e; } DebugAssert(e.getKind()==RAW_LIST && e.arity() > 0 && e[0].getKind()==ID, "TheoryCore::parseExprOp:\n e = "+e.toString()); TRACE("parse", "TheoryCore::parseExprOp:\n e = ", e.toString(), ""); /* The first element of the list (e[0] is an ID of the operator. ID string values are the dirst element of the expression */ const Expr& c1 = e[0][0]; int kind = getEM()->getKind(c1.getString()); if (isBasicKind(kind)) { vector operatorStack; vector operandStack; vector childStack; Expr e2; operatorStack.push_back(e); childStack.push_back(1); while (!operatorStack.empty()) { DebugAssert(operatorStack.size() == childStack.size(), "Invariant violated"); if (childStack.back() < operatorStack.back().arity()) { e2 = operatorStack.back()[childStack.back()++]; ExprMap::iterator iParseCache = d_parseCache->find(e2); if (iParseCache != d_parseCache->end()) { operandStack.push_back((*iParseCache).second); } else if (e2.getKind() == RAW_LIST && e2.arity() > 0 && e2[0].getKind() == ID && isBasicKind(getEM()->getKind(e2[0][0].getString()))) { operatorStack.push_back(e2); childStack.push_back(1); } else { operandStack.push_back(parseExpr(e2)); } } else { e2 = operatorStack.back(); operatorStack.pop_back(); childStack.pop_back(); vector children; vector::iterator childStart = operandStack.end() - (e2.arity() - 1); children.insert(children.begin(), childStart, operandStack.end()); operandStack.erase(childStart, operandStack.end()); kind = getEM()->getKind(e2[0][0].getString()); operandStack.push_back(Expr(kind, children, e2.getEM())); (*d_parseCache)[e2] = operandStack.back(); if (!getEM()->isTypeKind(operandStack.back().getKind())) { operandStack.back().getType(); } } } DebugAssert(childStack.empty(), "Invariant violated"); DebugAssert(operandStack.size() == 1, "Expected single operand left"); return operandStack.back(); } switch(kind) { case SUBTYPE: if (e.arity() <= 3) { Expr witness; if (e.arity() == 3) { witness = parseExpr(e[2]); } return newSubtypeExpr(parseExpr(e[1]), witness).getExpr(); } else { throw ParserException("Expected one or two arguments to SUBTYPE"); } case EQ: if(e.arity()==3) { Expr e1 = parseExpr(e[1]); Expr e2 = parseExpr(e[2]); if (e1.getType() == boolType() && getFlags()["convert-eq-iff"].getBool()) { return e1.iffExpr(e2); } else { return e1.eqExpr(e2); } } else throw ParserException("Equality requires exactly two arguments: " +e.toString()); break; case NEQ: if(e.arity()==3) return !(parseExpr(e[1]).eqExpr(parseExpr(e[2]))); else throw ParserException("Disequality requires exactly two arguments: " +e.toString()); break; case TYPE: { if(e.arity()==2) { const Expr& types = e[1]; if(types.getKind() == RAW_LIST) { vector names; for(Expr::iterator i=types.begin(), iend=types.end(); i!=iend; ++i) names.push_back(*i); return Expr(TYPEDECL, names, getEM()); } } else if(e.arity() == 3 && e[1].getKind() == ID) return Expr(TYPEDEF, e[1], parseExpr(e[2])); throw ParserException("Bad TYPE declaration: "+e.toString()); break; } //TODO: Is IF still used? case IF: if(e.arity() == 4) { Expr c(parseExpr(e[1])); Expr e1(parseExpr(e[2])); Expr e2(parseExpr(e[3])); return c.iteExpr(e1, e2); } else throw ParserException("Bad IF-THEN-ELSE expression: " +e.toString()); case COND: { if(e.arity() >= 3) return processCond(e, 1); else throw ParserException("Bad COND expression: "+e.toString()); break; } case LET: { // (LET ((v1 e1) (v2 e2) ... ) body) Expr e2(e); while (true) { if(!(e2.arity() == 3 && e2[1].getKind() == RAW_LIST && e2[1].arity() > 0)) throw ParserException("Bad LET expression: "+e2.toString()); // Iterate through the bound variables for(Expr::iterator i=e2[1].begin(), iend=e2[1].end(); i!=iend; ++i) { const Expr& decl = *i; if (decl.getKind() != RAW_LIST || decl.arity() != 2) throw ParserException("Bad variable declaration block in LET " "expression: "+decl.toString()+ "\n e2 = "+e2.toString()); if (decl[0].getKind() != ID) throw ParserException("Variable must be an identifier in LET " "expression: "+decl[0].toString()+ "\n e2 = "+e2.toString()); addBoundVar(decl[0][0].getString(), Type(), parseExpr(decl[1])); } // Optimization for nested LETs: if (e2[2].getKind()==RAW_LIST && e2[2].arity() > 0 && e2[2][0].getKind()==ID && getEM()->getKind(e2[2][0][0].getString()) == LET) { e2 = e2[2]; } else break; } // Parse the body recursively and return it (nuke the LET) return parseExpr(e2[2]); } case TRUE_EXPR: { return e.getEM()->trueExpr(); } case FALSE_EXPR: { return e.getEM()->falseExpr();} case BOOLEAN: { return e.getEM()->boolExpr(); } break; default: DebugAssert(false, "TheoryCore::parseExprOp: invalid command or expression: " + e.toString()); break; } return e; } ExprStream& TheoryCore::printSmtLibShared(ExprStream& os, const Expr& e) { DebugAssert(os.lang() == SMTLIB_LANG || os.lang() == SMTLIB_V2_LANG, "Invalid state in printSmtLibShared" ); switch(e.getKind()) { case TRUE_EXPR: os << "true"; break; case FALSE_EXPR: os << "false"; break; case UCONST: os << d_translator->escapeSymbol(d_translator->fixConstName(e.getName())); break; case BOOLEAN: e.printAST(os); break; case STRING_EXPR: e.print(os); break; case SUBTYPE: throw SmtlibException("TheoryCore::print: SMTLIB: SUBTYPE not implemented"); break; case TYPEDEF: { throw SmtlibException("TheoryCore::print: SMTLIB: TYPEDEF not implemented"); break; } case EQ: os << "(" << push << "=" << space << e[0] << space << e[1] << push << ")"; break; case DISTINCT: { int i=0, iend=e.arity(); os << "(" << push << "distinct"; for(; i!=iend; ++i) os << space << e[i]; os << push << ")"; break; } case NOT: os << "(" << push << "not" << space << e[0] << push << ")"; break; case AND: { int i=0, iend=e.arity(); if(iend == 1 && os.lang() == SMTLIB_V2_LANG) { os << e[0]; } else { os << "(" << push << "and"; for(; i!=iend; ++i) os << space << e[i]; os << push << ")"; } break; } case OR: { int i=0, iend=e.arity(); if(iend == 1 && os.lang() == SMTLIB_V2_LANG) { os << e[0]; } else { os << "(" << push << "or"; for(; i!=iend; ++i) os << space << e[i]; os << push << ")"; } break; } case XOR: { int i=0, iend=e.arity(); if(iend == 1 && os.lang() == SMTLIB_V2_LANG) { os << e[0]; } else { os << "(" << push << "xor"; for(; i!=iend; ++i) os << space << e[i]; os << push << ")"; } break; } case TRANSFORM: throw SmtlibException("TheoryCore::print: SMTLIB: TRANSFORM not implemented"); os << "(" << push << "TRANSFORM" << space << e[0] << push << ")"; break; case LETDECL: // throw SmtlibException("TheoryCore::print: SMTLIB: LETDECL not implemented"); if(e.arity() == 2) os << e[1]; else e.printAST(os); break; case PF_APPLY: { DebugAssert(e.arity() > 0, "TheoryCore::print(): " "Proof rule application must have at " "least one argument (rule name):\n "+e.toString()); // os << e[0]; by yeting os << e[0] << "\n" ; if(e.arity() > 1) { // Print the arguments os << push << "(" << push; bool first(true); for(int i=1; igetKindName(e.getKind())); } return os; } static bool containsRec(const Expr& def, ExprHashMap& defs, ExprHashMap& visited) { ExprHashMap::iterator it = visited.find(def); if (it != visited.end()) return false; it = defs.find(def); if (it != defs.end()) return true; for(Expr::iterator i = def.begin(), iend=def.end(); i != iend; ++i) { if (containsRec(*i,defs,visited)) return true; } // [MGD] Closure exprs (LAMBDAs and quantifiers) don't have children, // they have bodies. if(def.isClosure()) { if (containsRec(def.getBody(),defs,visited)) return true; } visited[def] = true; return false; } static bool contains(const Expr& def, ExprHashMap& defs) { ExprHashMap visited; return containsRec(def, defs, visited); } ExprStream& TheoryCore::print(ExprStream& os, const Expr& e) { switch(os.lang()) { case SPASS_LANG: switch(e.getKind()) { case TRUE_EXPR: os << "true"; break; case FALSE_EXPR: os << "false"; break; case UCONST: if(isReal(getBaseType(e.getType()))) { // SPASS guys want "np" prefix on arith vars os << "np"; } os << e.getName(); break; case BOOLEAN: e.printAST(os); break; case STRING_EXPR: e.print(os); break; case TYPE: throw SmtlibException("TheoryCore::print: SPASS_LANG: TYPE should have been handled by Translator::finish()"); case ID: if(e.arity() == 1 && e[0].isString()) os << e[0].getString(); else e.printAST(os); break; case CONST: throw SmtlibException("TheoryCore::print: SPASS_LANG: CONST should have been handled by Translator::finish()"); case SUBTYPE: throw SmtlibException("TheoryCore::print: SPASS_LANG: SUBTYPE not implemented"); break; case TYPEDEF: { throw SmtlibException("TheoryCore::print: SPASS_LANG: TYPEDEF not implemented"); break; } case EQ: os << push << "equal(" << e[0] << "," << space << e[1] << push << ")"; break; case DISTINCT: { throw SmtlibException("TheoryCore::print: SPASS_LANG: SUBTYPE not implemented"); break; } case NOT: os << push << "not(" << e[0] << push << ")"; break; case AND: { int i=0, iend=e.arity(); os << push << "and(" << e[i]; while(++i != iend) os << "," << space << e[i]; os << push << ")"; break; } case OR: { int i=0, iend=e.arity(); os << push << "or(" << e[i]; while(++i != iend) os << "," << space << e[i]; os << push << ")"; break; } case XOR: { if(e.arity() != 2) { throw SmtlibException("TheoryCore::print: SPASS_LANG: XOR not supported when arity != 2 !"); } os << push << "or(and(" << e[0] << "," << space << "not(" << e[1] << "))," << space << "and(not(" << e[0] << ")," << space << e[1] << ")" << push << ")"; break; } case ITE: if (e.getType().isBool()) { os << push << "and(" << space << push << "implies(" << space << e[0] << "," << space << e[1] << push << ")" << "," << space << push << "implies(" << space << e[0].negate() << "," << space << e[2] << push << ")" << push << ")"; } else { os << push << "if_then_else(" << e[0] << "," << space << e[1] << "," << space << e[2] << push << ")"; } break; case IFF: os << push << "equiv(" << space << e[0] << space << "," << space << e[1] << push << ")"; break; case IMPLIES: os << push << "implies(" << space << e[0] << space << "," << space << e[1] << push << ")"; break; case ASSERT: // SPASS guys don't want formula(false) etc: comment them out if(e[0] == d_em->trueExpr() || e[0] == d_em->falseExpr().notExpr()) { os << "% "; } os << "formula(" << space << push << e[0].negate() << space << ")."; break; case TRANSFORM: throw SmtlibException("TheoryCore::print: SPASS: TRANSFORM not implemented"); break; case QUERY: // SPASS guys don't want formula(false) etc: comment them out if(e[0].negate() == d_em->trueExpr() || e[0].negate() == d_em->falseExpr().notExpr()) { os << "% "; } os << "formula(" << space << push << e[0] << space << ")."; break; case LETDECL: throw SmtlibException("TheoryCore::print: SPASS_LANG: LETDECL not implemented"); case LET: throw SmtlibException("TheoryCore::print: SPASS_LANG: LET should have been handled in Translator::finish()"); case BOUND_VAR: if(isReal(getBaseType(e.getType()))) { // SPASS guys want "np" prefix on arith vars os << "np"; } os << e.getName(); break; case SKOLEM_VAR: os << push << "SKOLEM_" + int2string((int)e.getIndex()); break; case PF_APPLY: throw SmtlibException("TheoryCore::print: SPASS_LANG: PF_APPLY not implemented"); case ANNOTATION: throw SmtlibException("TheoryCore::print: SPASS_LANG: ANNOTATION should have been handled by Translator::finish()"); case RAW_LIST: case ANY_TYPE: case WHERE: case ASSERTIONS: case ASSUMPTIONS: case COUNTEREXAMPLE: case COUNTERMODEL: case PUSH: case POP: case POPTO: case PUSH_SCOPE: case POP_SCOPE: case POPTO_SCOPE: case RESET: case PF_HOLE: default: throw SmtlibException("TheoryCore::print: SPASS_LANG: Unexpected expression: " +getEM()->getKindName(e.getKind())); } break; // end of case SPASS_LANG case SIMPLIFY_LANG: switch(e.getKind()) { case TRUE_EXPR: os << "TRUE"; break; case FALSE_EXPR: os << "FALSE"; break; case TYPE: break; // no type for Simplify case ID: if(e.arity() == 1 && e[0].isString()) os << e[0].getString(); else e.print(os); break; case CONST: // os << "ERROR:const to be supported\n"; simplify do not need this break; case SUBTYPE: break; case TYPEDEF: { break; } case EQ: os << "(EQ " << e[0] << " " << e[1] << ")"; break; case NOT: os << "(NOT " << e[0] << ")"; break; case AND: { int i=0, iend=e.arity(); os << "(AND "; if(i!=iend) { os << e[i]; ++i; } for(; i!=iend; ++i) os << " " << e[i]; os << ")"; } break; case OR: { int i=0, iend=e.arity(); os << "(OR "; if(i!=iend) { os << e[i]; ++i; } for(; i!=iend; ++i) os << " " << e[i]; os << ")"; } break; case ITE: os<<"ERROR:ITE:not supported yet\n"; break; case IFF: if(e.arity() == 2) os << "(IFF " << e[0] << " " << e[1] << ")"; else e.print(os); break; case IMPLIES: os << "(IMPLIES " <arity() == 3) { os << (*i)[0] << ":" << space << push << (*i)[1] << space << "= " << push << nodag << (*i)[2] << pop << pop; } else { os << (*i)[0]; Type tp((*i)[0].lookupType()); if(!tp.isNull()) os << ":" << space << push << tp.getExpr(); else os << push; os << space << "= " << push << nodag << (*i)[1] << pop << pop; } } os << pop << endl << "IN" << space << push << e[1] << push << ")"; */ os << "LET not supported in Simplify\n"; break; } case BOUND_VAR: // os << e.getName()+"_"+e.getUid(); // by yeting for a neat output os << e.getName(); break; case SKOLEM_VAR: os << "SKOLEM_" + int2string((int)e.getIndex()); break; case PF_APPLY: // FIXME: this will eventually go to the "symsim" theory /* DebugAssert(e.arity() > 0, "TheoryCore::print(): " "Proof rule application must have at " "least one argument (rule name):\n "+e.toString()); os << e[0]; if(e.arity() > 1) { // Print the arguments os << push << "(" << push; bool first(true); for(int i=1; i 2"; } break; case SUBTYPE: break; case TYPEDEF: { break; } case EQ: os << e[0] << " = " << e[1]; break; case DISTINCT: { int i=0, iend=e.arity(); os << "$distinct(" ; os << e[i] ; i++; for(; i!=iend; ++i) os << ", " << e[i] ; os << ")"; break; } case NOT: os << "~(" << e[0]<<")" ; break; case AND: { int i=0, iend=e.arity(); if(iend == 1) { os << e[i]; } else if(iend > 1) { for(i=0 ; i < iend-1; i++) { os << "(" << e[i] << " \n& " ; } os << e[iend-1]; for(i=0 ; i < iend-1; i++) { os << ")"; } } else{ os <<"ERROR:AND has less than 1 parameter\n"; } break; } case OR: { int i=0, iend=e.arity(); if(iend == 1) { os << e[i]; } else if(iend > 1) { for(i=0 ; i < iend-1; i++) { os << "(" << e[i] << " \n| " ; } os << e[iend-1]; for(i=0 ; i < iend-1; i++) { os << ")"; } } else{ os <<"ERROR:OR has less than 1 parameter\n"; } break; } case ITE: os<<"ERROR:ITE:not supported in TPTP yet\n"; /* os << "(AND (IMPLIES "<< e[0] << " " << e[1]<<")" << "(IMPLIES (NOT " < " << e[1] << ")" ; else e.print(os); break; case IMPLIES: os << "(" << e[0] << " \n=> " << e[1] << ")" ; break; // Commands case ASSERT: os << "tff(" << axiom_counter++ << ", axiom, \n " <arity() == 3) { os << (*i)[0] << ":" << (*i)[1] << " ERROR= " << nodag << (*i)[2] ; } else { os << (*i)[0]; os << " := " << nodag << (*i)[1] ; } os < 0, "TheoryCore::print(): " "Proof rule application must have at " "least one argument (rule name):\n "+e.toString()); os << e[0]; if(e.arity() > 1) { // Print the arguments os << push << "(" << push; bool first(true); for(int i=1; i= 5){ if ('C' == name[0] && 'V' == name[1] && 'C' == name[2] && '_' == name[3] && isdigit(name[4])){ os << to_upper(name); } else { os << to_lower(name); } } else { os<getKindName(e.getKind())< " << e[1] << push << ")"; else e.printAST(os); break; case IMPLIES: os << "(" << push << e[0] << space << "=> " << e[1] << push << ")"; break; // Commands case ASSERT: os << "ASSERT " << push << e[0] << push << ";"; break; case TRANSFORM: os << "TRANSFORM " << push << e[0] << push << ";"; break; case QUERY: os << "QUERY " << push << e[0] << push << ";"; break; case WHERE: os << "WHERE;"; break; case ASSERTIONS: os << "ASSERTIONS;"; break; case ASSUMPTIONS: os << "ASSUMPTIONS;"; break; case COUNTEREXAMPLE: os << "COUNTEREXAMPLE;"; break; case COUNTERMODEL: os << "COUNTERMODEL;"; break; case PUSH: if(e.arity()==0) os << "PUSH;"; else os << "PUSH" << space << e[0] << push << ";"; break; case POP: if(e.arity()==0) os << "POP;"; else os << "POP" << space << e[0] << push << ";"; break; case POPTO: os << "POPTO" << space << e[0] << push << ";"; break; case PUSH_SCOPE: if(e.arity()==0) os << "PUSH_SCOPE;"; else os << "PUSH_SCOPE" << space << e[0] << push << ";"; break; case POP_SCOPE: if(e.arity()==0) os << "POP_SCOPE;"; else os << "POP_SCOPE" << space << e[0] << push << ";"; break; case POPTO_SCOPE: os << "POPTO_SCOPE" << space << e[0] << push << ";"; break; case RESET: os << "RESET;"; break; case LETDECL: if(e.arity() == 2) os << e[1]; else e.printAST(os); break; case LET: { // (LET (LETDECLS (LETDECL var [ type ] val) .... ) body) bool first(true); os << "(" << push << "LET" << space << push; for(Expr::iterator i=e[0].begin(), iend=e[0].end(); i!=iend; ++i) { if(!first) os << push << "," << pop << endl; else first = false; if(i->arity() == 3) { os << (*i)[0] << ":" << space << push << (*i)[1] << space << "= " << push << nodag << (*i)[2] << pop << pop; } else { os << (*i)[0]; Type tp((*i)[0].lookupType()); if(!tp.isNull()) os << ":" << space << push << tp.getExpr(); else os << push; os << space << "= " << push << nodag << (*i)[1] << pop << pop; } } os << pop << endl << "IN" << space << push << e[1] << push << ")"; break; } case BOUND_VAR: // os << e.getName()+"_"+e.getUid(); //by yeting, as requested by Sascha Boehme for proofs if(getFlags()["print-var-type"].getBool()) { os << e.getName() << "(" << e.getType() << ")"; } else { os << e.getName(); //for better support of proof translation yeting } break; case SKOLEM_VAR: os << "SKOLEM_" + int2string((int)e.getIndex()); break; case PF_APPLY: // FIXME: this will eventually go to the "symsim" theory DebugAssert(e.arity() > 0, "TheoryCore::print(): " "Proof rule application must have at " "least one argument (rule name):\n "+e.toString()); // os << e[0]; by yeting os << e[0] << "\n" ; if(e.arity() > 1) { // Print the arguments os << push << "(" << push; bool first(true); for(int i=1; i 1) { os << ": " << e[1]; } } case PF_HOLE: // FIXME: implement this (now fall through to default) default: // Print the top node in the default LISP format, continue with // pretty-printing for children. e.printAST(os); } break; // end of case PRESENTATION_LANG /* There's a lot of overlap between SMT-LIB v1 and v2, so we'll only handle * v1-specific stuff here, then goto (!) then end of the v2 block below. */ case SMTLIB_LANG: switch(e.getKind()) { case TYPE: if (e.arity() == 1) { os << " :extrasorts ("; for (int i=0; i < e[0].arity(); ++i) { if (i != 0) os << push << space; os << push << e[0][i]; } os << push << ")"; } else if (e.arity() == 2) { break; } else { throw SmtlibException("TheoryCore::print: SMTLIB: Unexpected TYPE expression"); } break; case CONST: if(e.arity() == 2) { if (e[1].getKind() == BOOLEAN) { os << " :extrapreds ((" << push << d_translator->fixConstName(e[0][0].getString()) << push << "))"; } else if (e[1].getKind() == ARROW && e[1][e[1].arity()-1].getKind() == BOOLEAN) { os << " :extrapreds ((" << push << d_translator->fixConstName(e[0][0].getString()) << space << nodag << e[1] << push << "))"; } else { os << " :extrafuns ((" << push << d_translator->fixConstName(e[0][0].getString()) << space << nodag << e[1] << push << "))"; } } else if (e.arity() == 0) e.printAST(os); else { throw SmtlibException("TheoryCore::print: SMTLIB: CONST not implemented"); } break; case ID: // FIXME: when lisp becomes case-insensitive, fix printing of IDs if(e.arity() == 1 && e[0].isString()) os << e[0].getString(); else e.printAST(os); break; case IMPLIES: os << "(" << push << "implies" << space << e[0] << space << e[1] << push << ")"; break; case IFF: os << "(" << push << "iff" << space << e[0] << space << e[1] << push << ")"; break; case ITE: os << "(" << push; if (e.getType().isBool()) os << "if_then_else"; else os << "ite"; os << space << e[0] << space << e[1] << space << e[2] << push << ")"; break; // Commands case ASSERT: os << " :assumption" << space << push << e[0]; break; case QUERY: os << " :formula" << space << push << e[0].negate(); break; case LET: { // (LET ((var [ type ] val) .... ) body) for(Expr::iterator i=e[0].begin(), iend=e[0].end(); i!=iend; ++i) { os << "(" << push; Type tp(i->arity() == 3 ? (*i)[2].getType() : (*i)[1].getType()); DebugAssert(!tp.isNull(), "Unexpected Null type"); if (tp.getExpr().getKind() == BOOLEAN) { os << "flet" << space << "(" << push; } else { os << "let" << space << "(" << push; } if(i->arity() == 3) { os << (*i)[0] << space << nodag << (*i)[2]; } else { os << (*i)[0] << space << nodag << (*i)[1]; } os << push << ")" << pop << pop << space; } os << e[1] << push; for (int j = 0; j < e[0].arity(); ++j) os << ")"; break; } case BOUND_VAR: { // os << push << "?" << e.getName()+"_"+e.getUid(); string str = e.getName(); if (str[0] == '_') str[0] = '?'; os << push << str; break; } case SKOLEM_VAR: os << push << "SKOLEM_" + int2string((int)e.getIndex()); break; case WHERE: os << " :cvc_command \"WHERE\""; break; case ASSERTIONS: os << " :cvc_command \"ASSERTIONS\""; break; case ASSUMPTIONS: os << " :cvc_command \"ASSUMPTIONS\""; break; case COUNTEREXAMPLE: os << " :cvc_command \"COUNTEREXAMPLE\""; break; case COUNTERMODEL: os << " :cvc_command \"COUNTERMODEL\""; break; case PUSH: os << " :cvc_command" << space; if(e.arity()==0) os << "\"PUSH\""; else os << "\"PUSH" << space << e[0] << push << "\""; break; case POP: os << " :cvc_command" << space; if(e.arity()==0) os << "\"POP\""; else os << "\"POP" << space << e[0] << push << "\""; break; case POPTO: os << " :cvc_command" << space; os << "\"POPTO" << space << e[0] << push << "\""; break; case PUSH_SCOPE: os << " :cvc_command" << space; if(e.arity()==0) os << "\"PUSH_SCOPE\""; else os << "\"PUSH_SCOPE" << space << e[0] << push << "\""; break; case POP_SCOPE: os << " :cvc_command" << space; if(e.arity()==0) os << "\"POP_SCOPE\""; else os << "\"POP_SCOPE" << space << e[0] << push << "\""; break; case POPTO_SCOPE: os << " :cvc_command" << space; os << "\"POPTO_SCOPE" << space << e[0] << push << "\""; break; break; case RESET: os << " :cvc_command" << space; os << "\"RESET\""; break; break; case ANNOTATION: { os << " :" << e[0].getString(); if (e[0].getString() == "notes") { os << space << e[1]; } else if (e.arity() > 1) { os << space << "{" << e[1].getString() << "}"; } break; } default: /* Must be shared, jump to the end of SMT-LIB v2 symbols */ printSmtLibShared(os,e); } break; case SMTLIB_V2_LANG: switch(e.getKind()) { case TYPE: if (e.arity() == 1) { for (int i=0; i < e[0].arity(); ++i) { if( i!=0 ) { os << endl; } os << "(declare-sort" << space << push << nodag << e[0][i] << " 0)" << pop; } } else if (e.arity() == 2) { break; } else { throw SmtlibException("TheoryCore::print: SMTLIB: Unexpected TYPE expression"); } break; case BOOLEAN: os << "Bool"; break; case CONST: if(e.arity() == 2) { os << "(declare-fun" << space << push << d_translator->escapeSymbol(d_translator->fixConstName(e[0][0].getString())) << space; if( e[1].getKind() == ARROW ) { os << nodag << e[1]; } else { os << "()" << space << nodag << e[1]; } os << ")" << pop; } else if (e.arity() == 0) e.printAST(os); else { throw SmtlibException("TheoryCore::print: SMTLIB: CONST not implemented"); } break; case ID: // FIXME: when lisp becomes case-insensitive, fix printing of IDs if(e.arity() == 1 && e[0].isString()) os << d_translator->escapeSymbol(e[0].getString()); else e.printAST(os); break; case IMPLIES: os << "(" << push << "=>" << space << e[0] << space << e[1] << push << ")"; break; case IFF: os << "(" << push << "=" << space << e[0] << space << e[1] << push << ")"; break; case ITE: os << "(" << push << "ite"; os << space << e[0] << space << e[1] << space << e[2] << push << ")"; break; // Commands case ASSERT: os << "(assert" << space << push << e[0] << ")" << pop; break; case QUERY: if (e[0] != falseExpr() && e[0].negate() != trueExpr()) { os << push << "(assert" << space << push << e[0].negate() << pop << ")" << pop << endl; } os << "(check-sat)"; break; case LET: { // (LET ((var [ type ] val) .... ) body) Expr var, def; bool first = true; int letCount = 0; ExprHashMap defs; for(Expr::iterator i=e[0].begin(), iend=e[0].end(); i!=iend; ++i) { Type tp(i->arity() == 3 ? (*i)[2].getType() : (*i)[1].getType()); DebugAssert(!tp.isNull(), "Unexpected Null type"); var = (*i)[0]; if(i->arity() == 3) { def = (*i)[2]; } else { def = (*i)[1]; } if (first || contains(def, defs)) { if (!first) { os << push << ")" << pop << pop << space; defs.clear(); } os << "(" << push << "let" << space << "(" << push; ++letCount; first = false; } else { os << space; } defs[def] = true; os << "(" << push << var << space << nodag << def << ")" << pop; } DebugAssert(!first, "Expected at least one child"); os << push << ")" << pop << pop << space << e[1]; for (int j = 0; j < letCount; ++j) os << ")" << pop; break; } case BOUND_VAR: { string str = e.getName(); if (str[0] == '_') str[0] = '?'; os << push << d_translator->escapeSymbol(str); break; } case SKOLEM_VAR: os << "SKOLEM_" + int2string((int)e.getIndex()); break; case WHERE: case ASSERTIONS: case ASSUMPTIONS: os << "(get-assertions)"; break; case COUNTEREXAMPLE: os << "(get-unsat-core)"; break; case COUNTERMODEL: os << "(get-model)"; break; case PUSH: case PUSH_SCOPE: if(e.arity()==0) os << "(push 1)"; else os << "(push" << space << push << e[0] << ")" << pop; break; case POP: case POP_SCOPE: if(e.arity()==0) os << "(pop 1)"; else os << "(pop" << space << push << e[0] << ")" << pop; break; case POPTO: os << " :cvc_command" << space << "\"POPTO" << space << e[0] << push << "\""; break; case POPTO_SCOPE: os << " :cvc_command" << space << "\"POPTO_SCOPE" << space << push << e[0] << "\"" << pop; break; case RESET: os << " :cvc_command" << space; os << "\"RESET\""; break; break; case ANNOTATION: { os << "(set-info :" << e[0].getString(); if (e.arity() > 1) os << space << d_translator->quoteAnnotation(e[1].getString()); os << ")"; break; } default: // fall-through to shared symbols printSmtLibShared(os,e); } break; case LISP_LANG: switch(e.getKind()) { case TRUE_EXPR: case FALSE_EXPR: case UCONST: e.print(os); break; case TYPE: if(e.arity() == 0) os << "TYPE"; else if(e.arity() == 1) os << "(" << push << "TYPE" << space << e[0] << push << ")"; else if(e.arity() == 2) os << "(" << push << "TYPE" << space << e[0] << space << e[1] << push << ")"; else e.printAST(os); break; case ID: // FIXME: when lisp becomes case-insensitive, fix printing of IDs if(e.arity() == 1 && e[0].isString()) os << e[0].getString(); else e.printAST(os); break; case CONST: if(e.arity() == 2) os << "(" << push << "CONST" << space << e[0] << space << e[1] << push << ")"; else e.printAST(os); break; case SUBTYPE: os << "SUBTYPE(" << push << e[0] << push << ")"; break; case TYPEDEF: { // This is used when dumping declarations to file. Print just // the name of the type, unless it's a messed-up expression. if(e.arity() != 2) e.printAST(os); else if(e[0].isString()) os << e[0].getString(); else e[0].print(os); break; } case EQ: // When a separator starts with a space (like " = "), add the // leading space with 'space' modifier. If this separator goes // to the next line, the leading spaces must be eaten up to get // the indentation right; 'space' will tell the indentation // engine that it is a space that can be eaten. A space in a // string (like " ") will never be eaten. os << "(" << push << "=" << space << e[0] << space << e[1] << push << ")"; break; case NOT: os << "(" << push << "NOT" << space << e[0] << push << ")"; break; case AND: { int i=0, iend=e.arity(); os << "(" << push << "AND"; for(; i!=iend; ++i) os << space << e[i]; os << push << ")"; } break; case OR: { int i=0, iend=e.arity(); os << "(" << push << "OR"; for(; i!=iend; ++i) os << space << e[i] << space; os << push << ")"; } break; case ITE: os << "(" << push << "IF" << space << e[0] << space << e[1] << space << e[2] << push << ")"; break; case IFF: os << "(" << push << "<=>" << space << e[0] << space << e[1] << push << ")"; break; case IMPLIES: os << "(" << push << "=>" << space << e[0] << space << e[1] << push << ")"; break; // Commands case ASSERT: os << "(" << push << "ASSERT" << space << e[0] << push << ")"; break; case TRANSFORM: os << "(" << push << "TRANSFORM" << space << e[0] << push << ")"; break; case QUERY: os << "(" << push << "QUERY" << space << e[0] << push << ")"; break; case PUSH: os << "(PUSH)"; break; case POP: os << "(POP)"; break; case POPTO: os << "(" << push << "POPTO" << space << e[0] << push << ")"; break; case RESET: os << "(" << push << "RESET" << push << ")"; break; case LETDECL: if(e.arity() == 2) os << e[1]; else if(e.arity()==3) // It's a declaration of a named Expr os << e[0] << push << ":" << space << push << e[1] << push << " =" << pop << pop << space << e[2]; else e.printAST(os); break; case LET: { // (LET ((var [ type ] val) .... ) body) bool first(true); os << "(" << push << "LET" << space << "(" << push; for(Expr::iterator i=e[0].begin(), iend=e[0].end(); i!=iend; ++i) { if(!first) os << space; else first = false; os << "(" << push; if(i->arity() == 3) { os << (*i)[0] << space << (*i)[1] << space << nodag << (*i)[2]; } else { os << (*i)[0]; Type tp((*i)[0].lookupType()); if(!tp.isNull()) os << space << tp.getExpr(); os << space << nodag << (*i)[1]; } os << push << ")" << pop << pop; } os << push << ")" << pop << pop << space << e[1] << push << ")"; break; } case BOUND_VAR: // os << e.getName()+"_"+e.getUid(); by yeting os << e.getName(); break; case SKOLEM_VAR: os << "SKOLEM_" + int2string((int)e.getIndex()); break; case PF_APPLY: {// FIXME: this will eventually go to the "symsim" theory DebugAssert(e.arity() > 0, "TheoryCore::print(): " "Proof rule application must have at " "least one argument (rule name):\n "+e.toString()); os << push << "(" << push; bool first(true); for(int i=0; irefineCounterExample(); if(inconsistent()) { thm = inconsistentThm(); return false; } } return true; } void TheoryCore::refineCounterExample() { // Theory 0 is TheoryCore, skip it for(int i = 1; irefineCounterExample(); if(inconsistent()) { vector assump; inconsistentThm().getLeafAssumptions(assump); Expr a = Expr(RAW_LIST, assump, d_em); throw EvalException("Theory["+d_theories[i]->getName() +"]: Model Creation failed due " "to the following assumptions:\n\n" +a.toString() +"\n\nYou might be using an incomplete logical fragment."); } } } void TheoryCore::computeModelBasic(const vector& v) { for(vector::const_iterator i=v.begin(), iend=v.end(); i!=iend; ++i) { TRACE("model", "Model var "+i->toString()+" = ", find(*i).getRHS(), ""); DebugAssert((*i).getType().isBool(), "TheoryCore::computeModel: *i = " +(*i).toString()); Expr val = find(*i).getRHS(); if(!val.isBoolConst()) val = d_em->trueExpr(); assignValue(*i, val); } } /*****************************************************************************/ /* * User-level API methods */ /*****************************************************************************/ void TheoryCore::addFact(const Theorem& e) { //<<<<<<< theory_core_sat.cpp // cout<<"theory_core_sat.cpp asserted fact:"<scopeLevel(), ' ');) // TRACE("addFact", indentStr, "Assert: ", e.getExpr().toString(PRESENTATION_LANG)); //======= IF_DEBUG(string indentStr(getCM()->scopeLevel(), ' ');) TRACE("addFact", indentStr, "Assert: ", e.getExpr().toString(PRESENTATION_LANG)); //>>>>>>> 1.7 DebugAssert(!d_inAddFact, "Recursive call to addFact() is not allowed"); DebugAssert(d_queue.empty(), "addFact[start]: Expected empty queue"); // DebugAssert(d_queueSE.empty(), "addFact[start]: Expected empty queue"); DebugAssert(d_update_thms.empty() && d_update_data.empty(), "addFact[start]: Expected empty update list"); ScopeWatcher sw(&d_inAddFact); if(!d_inconsistent && !outOfResources()) { getResource(); d_queue.push(e); // cout<<"queue pushed" <& reasons) { if(d_incomplete.size() > 0) { for(CDMap::iterator i=d_incomplete.begin(), iend=d_incomplete.end(); i!=iend; ++i) reasons.push_back((*i).first); return true; } else return false; } void TheoryCore::registerAtom(const Expr& e, const Theorem& thm) { DebugAssert(!e.isEq() || e[0] != e[1], "expected non-reflexive"); DebugAssert(!e.isRegisteredAtom(), "atom registered more than once"); // if (e.isQuantifier()) return; e.setRegisteredAtom(); if(d_termTheorems.find(e) != d_termTheorems.end()){ // cout<<"found this before 1 : "<iffTrueElim(thm2)); } else if (thm2.getRHS().isFalse()) { setFindLiteral(d_commonRules->iffFalseElim(thm2)); } else { //TODO: why does arith need thm2.getRHS() instead of e? // theoryOf(e)->registerAtom(e); theoryOf(thm2.getRHS())->registerAtom(thm2.getRHS()); setupSubFormulas(thm2.getRHS(), e, thm); } processFactQueue(LOW); } Theorem TheoryCore::getImpliedLiteral(void) { Theorem res; if (d_impliedLiteralsIdx < d_impliedLiterals.size()) { res = d_impliedLiterals[d_impliedLiteralsIdx]; d_impliedLiteralsIdx = d_impliedLiteralsIdx + 1; } return res; } Theorem TheoryCore::getImpliedLiteralByIndex(unsigned index) { DebugAssert(index < d_impliedLiterals.size(), "index out of bounds"); return d_impliedLiterals[index]; } Expr TheoryCore::parseExpr(const Expr& e) { // check cache ExprMap::iterator iParseCache = d_parseCache->find(e); if (iParseCache != d_parseCache->end()) { return (*iParseCache).second; } // Remember the current size of the bound variable stack size_t boundVarSize = d_boundVarStack.size(); // Compute the kind to determine what to do with the expression int kind = NULL_KIND; Expr res; switch(e.getKind()) { case ID: { const Expr c1 = e[0]; kind = getEM()->getKind(c1.getString()); if(kind == NULL_KIND) { // It's an identifier; try to resolve it res = resolveID(e[0].getString()); if(res.isNull()) throw ParserException("cannot resolve an identifier: " +e[0].toString()); else { DebugAssert(!e.isApply(), "Unexpected apply function"); } } // Otherwise exit the switch and use DP-specific parsing break; } case RAW_LIST: { if(e.arity() == 0) throw ParserException("Empty list is not an expression!"); const Expr& op = e[0]; // First, resolve the operator switch(op.getKind()) { case ID: { // The operator in the list is ID: is it keyword or variable? kind = getEM()->getKind(op[0].getString()); if(kind == NULL_KIND) { // It's a named function application. Resolve the ID. res = resolveID(op[0].getString()); if(res.isNull()){ // cout<<"stop here: " << e << endl; // cout<<"stop here op: " << op << endl; // cout<<"stop here op[0]: " << op[0] << endl; throw ParserException("cannot resolve an identifier: " +op[0].toString()); } if(e.arity() < 2) throw ParserException("Bad function application: "+e.toString()); Expr::iterator i=e.begin(), iend=e.end(); ++i; vector args; for(; i!=iend; ++i) args.push_back(parseExpr(*i)); res = Expr(res.mkOp(), args); } // Proceed to DP-specific parsing break; } case RAW_LIST: // This can only be a lambda expression application. kind = LAMBDA; break; case STRING_EXPR: { vector assignmentVars; if(op.getString() == "_ANNOTATION") { for(int i = 0; i < e[2].arity(); ++i) { if(e[2][i][0][0].getString() == ":named") { FatalAssert(e[2][i].arity() == 2 && e[2][i][1].getKind() == ID, ":named annotation must take a name"); assignmentVars.push_back(e[2][i][1]); } } Expr parsed = parseExpr(e[1]); for(unsigned i = 0; i < assignmentVars.size(); ++i) { d_assignment.push_back(make_pair(assignmentVars[i], parsed)); } // Return rather than break; nothing more to do with the // annotation expr itself; it is stripped away. return parsed; } /* else fall through... */ } default: throw ParserException("Bad operator in "+e.toString()); } break; // Exit the top-level switch, proceed to DP-specific parsing } default: // Can only be a string or a number. res = e; } // DP-specific parsing if(res.isNull()) { if (hasTheory(kind)) { res = theoryOf(kind)->parseExprOp(e); // Restore the bound variable stack if (d_boundVarStack.size() > boundVarSize) { d_parseCache->clear(); if (boundVarSize == 0) { d_parseCache = &d_parseCacheTop; } while(d_boundVarStack.size() > boundVarSize) { pair& bv = d_boundVarStack.back(); hash_map::iterator iBoundVarMap = d_boundVarMap.find(bv.first); DebugAssert(iBoundVarMap != d_boundVarMap.end(), "Expected bv in map"); if ((*iBoundVarMap).second.getKind() == RAW_LIST) { (*iBoundVarMap).second = (*iBoundVarMap).second[1]; } else d_boundVarMap.erase(bv.first); d_boundVarStack.pop_back(); } } } else { res = e; } } (*d_parseCache)[e] = res; if (!getEM()->isTypeKind(res.getOpKind())) res.getType(); return res; } void TheoryCore::assignValue(const Expr& t, const Expr& val) { DebugAssert(d_varAssignments.count(t) == 0 || d_varAssignments[t].getRHS() == val, "TheoryCore::assignValue("+t.toString()+" := "+val.toString() +")\n variable already has a different value"); // Check if the assignment theorem can be derived from the find of t Theorem thm(find(t)); Expr t2 = thm.getRHS(); if(t2!=val) { bool isBool(t2.getType().isBool()); Expr assump = (isBool)? t2.iffExpr(val) : t2.eqExpr(val); Theorem assertThm = d_coreSatAPI->addAssumption(assump); addFact(assertThm); thm = transitivityRule(thm, assertThm); } d_varAssignments[t] = thm; } void TheoryCore::assignValue(const Theorem& thm) { DebugAssert(thm.isRewrite(), "TheoryCore::assignValue("+thm.toString()+")"); const Expr& t = thm.getLHS(); const Expr& val = thm.getRHS(); DebugAssert(d_varAssignments.count(t) == 0 || d_varAssignments[t].getRHS() == val, "TheoryCore::assignValue("+thm.getExpr().toString() +")\n variable already has a different value:\n " +d_varAssignments[t].getExpr().toString()); d_varAssignments[t] = thm; // Check if the assignment theorem can be derived from the find of t Theorem findThm(find(t)); const Expr& t2 = findThm.getRHS(); if(t2!=val) { Theorem thm2 = transitivityRule(symmetryRule(findThm), thm); addFact(thm2); } } void TheoryCore::addToVarDB(const Expr& e) { TRACE("model", "TheoryCore::addToVarDB(", e, ")"); d_vars.push_back(e); } void TheoryCore::collectBasicVars() { TRACE_MSG("model", "collectBasicVars() {"); // Clear caches d_varModelMap.clear(); d_varAssignments.clear(); d_basicModelVars.clear(); d_simplifiedModelVars.clear(); // Current stack of variables to process vector stack(d_vars.begin(), d_vars.end()); size_t lastSize(0); while(stack.size() > 0) { Expr var(stack.back()); stack.pop_back(); if(d_varModelMap.count(var) > 0) continue; // Already processed Theorem findThm(find(var)); if(findThm.getRHS()!=var) { // Replace var with its find d_simplifiedModelVars[var] = findThm; stack.push_back(findThm.getRHS()); TRACE("model", "collectBasicVars: simplified var: ", findThm.getExpr(), ""); continue; // Recycle to the beginning of the loop } lastSize = stack.size(); TRACE("model", "getModelTerm(", var, ") {"); getModelTerm(var, stack); TRACE("model", "getModelTerm => ", Expr(RAW_LIST, stack, getEM()), " }"); if(stack.size() == lastSize) { // Add a primitive variable TRACE("model", "collectBasicVars: adding primitive var: ", var, ""); d_basicModelVars.push_back(var); if(var.isTerm()) { Theory* t1 = theoryOf(var); Theory* t2 = theoryOf(getBaseType(var).getExpr().getKind()); if(t1 != t2) { TRACE("model", "collectBasicVars: adding shared var: ", var, ""); t1->addSharedTerm(var); t2->addSharedTerm(var); } } } else { // Record the descendants of var vector& kids = d_varModelMap[var]; for(size_t i=lastSize; i }"); } bool TheoryCore::buildModel(Theorem& thm) { size_t numTheories = getNumTheories(); // Use STL set to prune duplicate variables in theories vector > theoryExprs(numTheories+1); // Sort out model vars by theories for(size_t j = 0 ; jgetName()+"] for the variable: " +var.toString()); theoryExprs[i].insert(var); TRACE("model", "buildModel: adding ", var, " to theory "+d_theories[i]->getName()); } // Build a model for the basic-type variables for(int i=0; i 0) { TRACE("model", "computeModelBasic[", d_theories[i]->getName(), "] {"); // Copy the corresponding variables into a vector vector vars; vars.insert(vars.end(), theoryExprs[i].begin(), theoryExprs[i].end()); d_theories[i]->computeModelBasic(vars); TRACE("model", "computeModelBasic[", d_theories[i]->getName(), "] => }"); if(inconsistent()) { vector assump; thm = inconsistentThm(); return false; } } } return true; } void TheoryCore::buildModel(ExprMap& m) { TRACE_MSG("model", "buildModel() {"); size_t numTheories = getNumTheories(); // Use STL set to prune duplicate variables in theories vector > theoryExprs(numTheories+1); // Sort out model vars by theories for(size_t j = 0 ; jgetName()+"] for the variable: " +var.toString()); theoryExprs[i].insert(var); TRACE("model", "buildModel: adding ", var, " to theory "+d_theories[i]->getName()); } // Build a model for the basic-type variables for(int i=0; i 0) { TRACE("model", "computeModelBasic[", d_theories[i]->getName(), "] {"); // Copy the corresponding variables into a vector vector vars; vars.insert(vars.end(), theoryExprs[i].begin(), theoryExprs[i].end()); d_theories[i]->computeModelBasic(vars); TRACE("model", "computeModelBasic[", d_theories[i]->getName(), "] => }"); if(inconsistent()) { vector assump; inconsistentThm().getLeafAssumptions(assump); Expr a = Expr(RAW_LIST, assump, d_em); throw EvalException ("Model Creation failed in Theory[" +d_theories[i]->getName() +"] due to the following assumptions:\n\n" +a.toString() +"\n\nYou might be using an incomplete logical fragment."); } } } // Recombine the values for the compound-type variables ExprHashMap::iterator k, kend=d_simplifiedModelVars.end(); for(vector::const_iterator i=d_vars.begin(), iend=d_vars.end(); i!=iend; ++i) { Expr var(*i); TRACE("model", "buildModel: recombining var=", var, ""); k=d_simplifiedModelVars.find(var); Theorem simp; // Null by default if(k!=kend) { // This var is simplified simp = k->second; TRACE("model", "buildModel: simplified var="+var.toString()+" to ", simp.getRHS(), ""); var = simp.getRHS(); } collectModelValues(var, m); if(d_varAssignments.count(var) > 0) { if(!simp.isNull()) { Theorem thm(transitivityRule(simp, d_varAssignments[var])); assignValue(thm); DebugAssert(thm.getLHS() == *i, ""); m[*i] = thm.getRHS(); } else m[*i] = d_varAssignments[var].getRHS(); } // else if(simp.isNull()) // m[*i] = *i; // else // m[*i] = simp.getRHS(); } TRACE_MSG("model", "buildModel => }"); } // Recursively build a compound-type variable assignment for e /*! Not all theories may implement aggregation of compound values. If * a compound variable is not assigned by a theory, add the more * primitive variable assignments to 'm'. * * Some variables may simplify to something else (simplifiedVars map). * INVARIANT: e is always simplified (it's not in simplifiedVars map). * Also, if v simplifies to e, and e is assigned, then v must be assigned. */ void TheoryCore::collectModelValues(const Expr& e, ExprMap& m) { TRACE("model", "collectModelValues(", e, ") {"); if(d_varAssignments.count(e) > 0) { TRACE("model", "collectModelValues[cached] => ", d_varAssignments[e].getRHS(), " }"); return; // Got it already } ExprHashMap::iterator k, kend=d_simplifiedModelVars.end(); k=d_simplifiedModelVars.find(e); if(k!=kend) { const Theorem& findThm = k->second; const Expr& ee = findThm.getRHS(); collectModelValues(ee, m); if(d_varAssignments.count(ee) > 0) { Theorem thm = transitivityRule(findThm, d_varAssignments[ee]); assignValue(thm); } TRACE("model", "collectModelValues[simplified] => ", d_varAssignments[e].getRHS(), " }"); return; } if(d_varModelMap.count(e) == 0) { // Consider it a value of itself assignValue(reflexivityRule(e)); TRACE("model", "collectModelValues[e=e] => ", e, " }"); return; // Got it already } // Get the vector of more primitive vars const vector& vars = d_varModelMap[e]; // Recurse bool gotAll(true); // Whether we got all the values for(vector::const_iterator i=vars.begin(), iend=vars.end(); i!=iend; ++i) { Expr var(*i); // k=d_simplifiedModelVars.find(var); // Theorem simp; // Null by default // if(k!=kend) { // This var is simplified // simp = k->second; // var = simp.getRHS(); // } collectModelValues(var, m); if(d_varAssignments.count(var) == 0) { gotAll = false; } // else if(!simp.isNull()) { // Theorem thm(transitivityRule(simp, d_varAssignments[var])); // DebugAssert(thm.getLHS() == *i, ""); // assignValue(thm); // } } IF_DEBUG(vector res;) if(gotAll) { vector assigned; // What DP actually assigns Theory* th = theoryOf(getBaseType(e).getExpr()); TRACE("model", "computeModel["+th->getName()+"](", e, ") {"); th->computeModel(e, assigned); TRACE("model", "computeModel["+th->getName()+"] => ", Expr(RAW_LIST, assigned, getEM()), " }"); // Check if the assigned vars are different from e if(!(assigned.size()==1 && assigned[0]==e)) { // if(d_varAssignments.count(e) == 0) { for(vector::iterator i=assigned.begin(), iend=assigned.end(); i!=iend; ++i) { if(*i == e) continue; // Skip the original var m[*i] = getModelValue(*i).getRHS(); IF_DEBUG(res.push_back(getModelValue(*i).getExpr());) } } else { IF_DEBUG(res.push_back(getModelValue(e).getExpr());) } } TRACE("model", "collectModelValues => ", Expr(RAW_LIST, res, getEM()), " }"); } Theorem TheoryCore::rewriteLiteral(const Expr& e) { DebugAssert(e.isAbsLiteral(), "rewriteLiteral("+e.toString() +")\nExpected a literal."); Theorem res; //Theory* i = theoryOf(getBaseType(e).getExpr()); bool neg(e.isNot()); const Expr a = neg? e[0] : e; Theory * i; if(a.isEq()) i = theoryOf(getBaseType(a[0]).getExpr()); else if (a.arity() > 1) i = theoryOf(getBaseType(a[0]).getExpr()); else i = theoryOf(a); res = i->rewriteAtomic(a); if(neg) res = d_commonRules->iffContrapositive(res); return res; } void TheoryCore::setTimeLimit(unsigned limit) { initTimeLimit(); d_timeLimit = limit; } void TheoryCore::initTimeLimit() { d_timeBase = clock() / (CLOCKS_PER_SEC / 10); } bool TheoryCore::timeLimitReached() { if (d_timeLimit > 0 && d_timeLimit < (unsigned)(clock() / (CLOCKS_PER_SEC / 10)) - d_timeBase) { setIncomplete("Exhausted user-specified time limit"); return true; } else { return false; } } /*****************************************************************************/ /* * Methods provided for benefit of theories */ /*****************************************************************************/ /*! * Invariants: * - The input theorem e is either an equality or a conjunction of * equalities; * - In each equality e1=e2, the RHS e2 i-leaf-simplified; * - At the time of calling update(), all equalities in the queue are * processed by assertFormula() and the equivalence classes are merged * in the union-find database. * * In other words, the entire equality queue is processed "in parallel". */ void TheoryCore::assertEqualities(const Theorem& e) { IF_DEBUG( string indentStr(getCM()->scopeLevel(), ' '); TRACE("facts", indentStr, "assertEqualities: ", e); if (!incomplete()) d_solver->checkAssertEqInvariant(e); ) TRACE("quant update", "equs in core ", e.getExpr(), ""); // fast case if (e.isRewrite()) { const Expr& lhs = e.getLHS(); const Expr& rhs = e.getRHS(); DebugAssert(lhs.isTerm(), "term expected"); DebugAssert(findReduced(lhs) && findReduced(rhs), "should be find-reduced"); DebugAssert(lhs != rhs, "expected different lhs and rhs"); assertFormula(e); lhs.setFind(e); Theorem tmp = lhs.getEqNext(); lhs.setEqNext(transitivityRule(e, rhs.getEqNext())); rhs.setEqNext(transitivityRule(symmetryRule(e), tmp)); d_em->invalidateSimpCache(); NotifyList *L; L = lhs.getNotify(); if (L) processNotify(e, L); processNotify(e, &d_notifyEq); } else if (e.getExpr().isFalse()) { setInconsistent(e); } else { Expr conj = e.getExpr(); DebugAssert(conj.isAnd(), "Expected conjunction"); vector eqs; Theorem t; int index; for (index = 0; index < conj.arity(); ++index) { t = d_commonRules->andElim(e, index); eqs.push_back(t); if (t.getExpr().isFalse()) { setInconsistent(t); return; } DebugAssert(t.isRewrite(), "Expected rewrite"); DebugAssert(t.getLHS().isTerm(), "term expected"); DebugAssert(findReduced(t.getLHS()) && findReduced(t.getRHS()), "should be find-reduced"); assertFormula(t); if (d_inconsistent) return; } // Merge the equivalence classes vector::iterator i = eqs.begin(), iend = eqs.end(); for(; i!=iend; ++i) { const Theorem& thm = *i; const Expr& lhs = thm.getLHS(); const Expr& rhs = thm.getRHS(); DebugAssert(find(lhs).getRHS() == lhs, "find error: thm = "+thm.getExpr().toString() +"\n\n find(lhs) = " +find(lhs).getRHS().toString()); DebugAssert(find(rhs).getRHS() == rhs, "find error: thm = "+thm.getExpr().toString() +"\n\n find(rhs) = " +find(rhs).getRHS().toString()); lhs.setFind(thm); Theorem tmp = lhs.getEqNext(); lhs.setEqNext(transitivityRule(thm, rhs.getEqNext())); rhs.setEqNext(transitivityRule(symmetryRule(thm), tmp)); } d_em->invalidateSimpCache(); // Call the update() functions (process NotifyLists). for(i=eqs.begin(); i!=iend && !d_inconsistent; ++i) { const Theorem& thm = *i; NotifyList *L = thm.getLHS().getNotify(); if (L) processNotify(thm, L); processNotify(thm, &d_notifyEq); } } } void TheoryCore::setIncomplete(const string& reason) { d_incomplete.insert(reason, true); } Theorem TheoryCore::typePred(const Expr& e) { return d_rules->typePred(e); } static bool hasBoundVarRec(const Expr& e) { if (e.getFlag()) return false; if (e.isQuantifier()) return false; if (e.getKind() == BOUND_VAR) return true; for (int i = 0, ar = e.arity(); i < ar; ++i) { if (hasBoundVarRec(e[i])) return true; } e.setFlag(); return false; } IF_DEBUG( static bool hasBoundVar(const Expr& e) { e.getEM()->clearFlags(); return hasBoundVarRec(e); } ) void TheoryCore::enqueueFact(const Theorem& e) { // The theorem scope shouldn't be higher than current DebugAssert(e.getScope() <= d_cm->scopeLevel(), "\n e.getScope()="+int2string(e.getScope()) +"\n scopeLevel="+int2string(d_cm->scopeLevel()) +"\n e = "+e.getExpr().toString()); DebugAssert(okToEnqueue(), "enqueueFact() is called outside of addFact()" " or checkSATCore() or registerAtom() or preprocess"); DebugAssert((e.isRewrite() && !hasBoundVar(e.getLHS()) && !hasBoundVar(e.getRHS())) || (!e.isRewrite() && !hasBoundVar(e.getExpr())), "Bound vars shouldn't be free: " + e.toString()); // No need to enqueue when already inconsistent or out of resources if (d_inconsistent || outOfResources()) return; if (!e.isRewrite() && e.getExpr().isFalse()) { setInconsistent(e); } else { getResource(); d_queue.push(e); if (outOfResources()) { // No more resources: ignore all the remaining facts and fail // gracefully setIncomplete("Exhausted user-specified resource"); } } } void TheoryCore::setInconsistent(const Theorem& e) { DebugAssert(e.getExpr() == falseExpr(), "Expected proof of false"); d_inconsistent = true; d_incThm = e; // if(!d_queueSE.empty()){ // cout<<"before SAT 1"<notifyInconsistent(e); } } void TheoryCore::setupTerm(const Expr& t, Theory* i, const Theorem& thm) { int k; // Atomic formulas (non-terms) may have find pointers without the // subterms being setup. Recurse down to the terms before checking // for find pointers. if (!t.isTerm()) { if (!t.isStoredPredicate()) { DebugAssert(t.isAbsLiteral(), "Expected absliteral"); for (k = 0; k < t.arity(); ++k) { setupTerm(t[k], i, thm); } t.setStoredPredicate(); d_predicates.push_back(t); d_termTheorems[t] = thm; theoryOf(t)->setup(t); TRACE("quantlevel", "==========\npushed pred | ", t.getIndex(), "|" + t.toString()+"because : "+thm.toString() ); TRACE("quant","pushed pred ",t,thm); } return; } // Even if t is already setup, it may become shared with another theory Theory* j = theoryOf(t); if(i != j) { j->addSharedTerm(t); i->addSharedTerm(t); } // If already setup, nothing else to do if (t.hasFind()) return; // Proceed with the setup // Add the term into the set of all terms d_terms.push_back(t); d_termTheorems[t] = thm; TRACE("quantlevel","=========\npushed term ("+t.toString(), ") with quantlevel: ", thm.getQuantLevel()); for (k = 0; k < t.arity(); ++k) { setupTerm(t[k], j, thm); } t.setFind(reflexivityRule(t)); t.setEqNext(reflexivityRule(t)); j->setup(t); // Assert the subtyping predicate AFTER the setup is complete Theorem pred = d_rules->typePred(t); pred = iffMP(pred, simplify(pred.getExpr())); const Expr& predExpr = pred.getExpr(); if(predExpr.isFalse()) { IF_DEBUG(debugger.counter("conflicts from type predicate")++;) setInconsistent(pred); } else if(!predExpr.isTrue()) { Theory* k = theoryOf(t.getType().getExpr()); k->assertTypePred(t, pred); } } Expr TheoryCore::getAssignment() { vector v; for(unsigned i = 0; i < d_assignment.size(); ++i) { Theorem res = d_exprTrans->preprocess(d_assignment[i].second); Theorem simpThm = d_theoryCore->simplify(res.getRHS()); vector pr; pr.push_back(d_assignment[i].first); pr.push_back(simpThm.getRHS()); v.push_back(Expr(RAW_LIST, pr, getEM())); } return Expr(RAW_LIST, v, getEM()); } Expr TheoryCore::getValue(Expr e) { Theorem res = d_exprTrans->preprocess(e); Theorem simpThm = d_theoryCore->simplify(res.getRHS()); return simpThm.getRHS(); } cvc3-2.4.1/src/theory_core/core_theorem_producer.cpp0000664000175400017540000004723511234135021022454 0ustar mdetersmdeters/*****************************************************************************/ /*! * \file core_theorem_producer.cpp * * Author: Sergey Berezin * * Created: Feb 05 03:40:36 GMT 2003 * *
* * License to use, copy, modify, sell and/or distribute this software * and its documentation for any purpose is hereby granted without * royalty, subject to the terms and conditions defined in the \ref * LICENSE file provided with this distribution. * *
* */ /*****************************************************************************/ // CLASS: CoreTheoremProducer // // AUTHOR: Sergey Berezin, 12/09/2002 // Vijay Ganesh, september 15th, 2004 (CNF Converter rules) // // Description: Implementation of the proof rules for ground // equational logic (reflexivity, symmetry, transitivity, and // substitutivity). // /////////////////////////////////////////////////////////////////////////////// // This code is trusted #define _CVC3_TRUSTED_ #include "core_theorem_producer.h" #include "theory_core.h" using namespace CVC3; using namespace std; // The trusted method of TheoryCore which creates this theorem producer CoreProofRules* TheoryCore::createProofRules(TheoremManager* tm) { return new CoreTheoremProducer(tm, this); } // e: T ==> |- typePred_T(e) [asserting the type predicate of e] Theorem CoreTheoremProducer::typePred(const Expr& e) { Type tp(e.getType()); Expr pred(d_core->getTypePred(tp, e)); Proof pf; if(withProof()) { pf = newPf("type_pred", e, tp.getExpr()); } return newTheorem(pred, Assumptions::emptyAssump(), pf); } Theorem CoreTheoremProducer::rewriteLetDecl(const Expr& e) { if(CHECK_PROOFS) CHECK_SOUND(e.getKind() == LETDECL, "rewriteLetDecl: wrong expression: " + e.toString()); Proof pf; if(withProof()) // FIXME: implement this in flea pf = newPf("rewrite_letdecl", e[1]); return newRWTheorem(e, e[1], Assumptions::emptyAssump(), pf); } // ==> NOT (AND e1 ... en) IFF (OR !e1 ... !en), takes (AND ...) Theorem CoreTheoremProducer::rewriteNotAnd(const Expr& e) { if(CHECK_PROOFS) CHECK_SOUND(e.isNot() && e[0].isAnd(), "rewriteNotAnd: precondition violated: " + e.toString()); vector kids; // vector of for(Expr::iterator i=e[0].begin(), iend=e[0].end(); i!=iend; ++i) // Collapse double negations kids.push_back(i->negate()); Proof pf; if(withProof()) pf = newPf("rewrite_not_and", e); return newRWTheorem(e, orExpr(kids), Assumptions::emptyAssump(), pf); } // ==> NOT (OR e1 ... en) IFF (AND !e1 ... !en), takes (OR ...) Theorem CoreTheoremProducer::rewriteNotOr(const Expr& e) { if(CHECK_PROOFS) CHECK_SOUND(e.isNot() && e[0].isOr(), "rewriteNotOr: precondition violated: " + e.toString()); vector kids; // vector of for(Expr::iterator i=e[0].begin(), iend=e[0].end(); i!=iend; ++i) // Collapse double negations kids.push_back(i->negate()); Proof pf; if(withProof()) pf = newPf("rewrite_not_or", e); return newRWTheorem(e, andExpr(kids), Assumptions::emptyAssump(), pf); } // ==> NOT IFF(e1,e2) IFF IFF(e1,NOT e2) Theorem CoreTheoremProducer::rewriteNotIff(const Expr& e) { Proof pf; if(CHECK_PROOFS) CHECK_SOUND(e.isNot() && e[0].isIff(), "rewriteNotIff precondition violated"); if(withProof()) { pf = newPf("rewrite_not_iff", e); } return newRWTheorem(e, e[0][0].iffExpr(!e[0][1]), Assumptions::emptyAssump(), pf); } // ==> NOT ITE(a,b,c) IFF ITE(a,NOT b,NOT c) Theorem CoreTheoremProducer::rewriteNotIte(const Expr& e) { Proof pf; if(CHECK_PROOFS) CHECK_SOUND(e.isNot() && e[0].isITE(), "rewriteNotIte precondition violated"); if(withProof()) { pf = newPf("rewrite_not_ite", e); } return newRWTheorem(e, e[0][0].iteExpr(!e[0][1], !e[0][2]), Assumptions::emptyAssump(), pf); } // a |- b == d ==> ITE(a, b, c) == ITE(a, d, c) Theorem CoreTheoremProducer::rewriteIteThen(const Expr& e, const Theorem& thenThm) { Proof pf; if(CHECK_PROOFS) { CHECK_SOUND(withAssumptions(), "Cannot check proof without assumptions"); CHECK_SOUND(e.isITE() && thenThm.isRewrite() && e[1] == thenThm.getLHS(), "rewriteIteThen precondition violated \n then expression: " + thenThm.getExpr().toString() + "\n e = " + e.toString()); } Assumptions a = thenThm.getAssumptionsRef() - e[0]; if(withProof()) { Type t = e.getType(); DebugAssert(!t.isNull(), "rewriteIteThen: e has no type: " + e.toString()); bool useIff = t.isBool(); if(useIff) pf = newPf("rewrite_ite_then_iff", e, thenThm.getProof()); else { pf = newPf("rewrite_ite_then", e, thenThm.getProof()); } } return newRWTheorem(e, e[0].iteExpr(thenThm.getRHS(), e[2]), a, pf); } // !a |- c == d ==> ITE(a, b, c) == ITE(a, b, d) Theorem CoreTheoremProducer::rewriteIteElse(const Expr& e, const Theorem& elseThm) { Proof pf; if(CHECK_PROOFS) { CHECK_SOUND(withAssumptions(), "Cannot check proof without assumptions"); CHECK_SOUND(e.isITE() && elseThm.isRewrite() && e[2] == elseThm.getLHS(), "rewriteIteElse precondition violated \n else expression: " + elseThm.getExpr().toString() + "\n e = " + e.toString()); } Assumptions a = elseThm.getAssumptionsRef() - !e[0]; if(withProof()) { Type t = e.getType(); DebugAssert(!t.isNull(), "rewriteIteElse: e has no type: " + e.toString()); bool useIff = t.isBool(); if(useIff) pf = newPf("rewrite_ite_else_iff", e, elseThm.getProof()); else { pf = newPf("rewrite_ite_else", e, elseThm.getProof()); } } return newRWTheorem(e, e[0].iteExpr(e[1], elseThm.getRHS()), a, pf); } // ==> ITE(c, e1, e2) <=> (!c OR e1) AND (c OR e2) Theorem CoreTheoremProducer::rewriteIteBool(const Expr& c, const Expr& e1, const Expr& e2) { if(CHECK_PROOFS) CHECK_SOUND(e1.getType().isBool() && e2.getType().isBool(), "rewriteIteBool: Not a boolean ITE: " + c.iteExpr(e1, e2).toString()); Proof pf; if(withProof()) pf = newPf("rewrite_ite_bool", c, e1, e2); return newRWTheorem(c.iteExpr(e1,e2), (e1.orExpr(!c).andExpr(c.orExpr(e2))), Assumptions::emptyAssump(), pf); } //! |= (A & B1) | (A & B2) | ... | (A & bn) <=> A & (B1 | B2 | ...| Bn) Theorem CoreTheoremProducer::orDistributivityRule(const Expr& e) { if(CHECK_PROOFS) { CHECK_SOUND(e.isOr() && e.arity() >= 2, "CoreTheoremProducer::orDistributivityRule: " "input must be an OR expr: \n" + e.toString()); const Expr& e0 = e[0]; CHECK_SOUND(e0.isAnd() && e0.arity() == 2, "CoreTheoremProducer::orDistributivityRule: " "input must be an OR of binary ANDs: \n" + e.toString()); } const Expr& A = e[0][0]; if(CHECK_PROOFS) { for(Expr::iterator i=e.begin(),iend=e.end();i!=iend;++i) { const Expr& ei = *i; CHECK_SOUND(ei.isAnd() && ei.arity() == 2, "CoreTheoremProducer::orDistributivityRule: " "input must be an OR of binary ANDs: \n" + e.toString()); CHECK_SOUND(A == ei[0], "CoreTheoremProducer::orDistributivityRule: " "input must have a common factor: \n" + e.toString()); } } vector output; for(Expr::iterator i=e.begin(),iend=e.end();i!=iend;++i) { Expr ei = *i; output.push_back(ei[1]); } Expr out = A.andExpr(orExpr(output)); Proof pf; if(withProof()) pf = newPf("or_distribuitivity_rule", e); return newRWTheorem(e, out, Assumptions::emptyAssump(), pf); } //! |= (A | B1) & (A | B2) & ... & (A | bn) <=> A | (B1 & B2 & ...& Bn) Theorem CoreTheoremProducer::andDistributivityRule(const Expr& e) { if(CHECK_PROOFS) { CHECK_SOUND(e.isAnd() && e.arity() >= 2, "CoreTheoremProducer::andDistributivityRule: " "input must be an AND expr: \n" + e.toString()); const Expr& e0 = e[0]; CHECK_SOUND(e0.isOr() && e0.arity() == 2, "CoreTheoremProducer::orDistributivityRule: " "input must be an AND of binary ORs: \n" + e.toString()); } const Expr& A = e[0][0]; if(CHECK_PROOFS) { for(Expr::iterator i=e.begin(),iend=e.end();i!=iend;++i) { const Expr& ei = *i; CHECK_SOUND(ei.isOr() && ei.arity() == 2, "CoreTheoremProducer::andDistributivityRule: " "input must be an AND of binary ORs: \n" + e.toString()); CHECK_SOUND(A == ei[0], "CoreTheoremProducer::andDistributivityRule: " "input must have a common factor: \n" + e.toString()); } } vector output; for(Expr::iterator i=e.begin(),iend=e.end();i!=iend;++i) { output.push_back((*i)[1]); } Expr out = A.orExpr(andExpr(output)); Proof pf; if(withProof()) pf = newPf("and_distribuitivity_rule", e); return newRWTheorem(e, out, Assumptions::emptyAssump(), pf); } // ==> IMPLIES(e1,e2) IFF OR(!e1, e2) Theorem CoreTheoremProducer::rewriteImplies(const Expr& e) { Proof pf; if(CHECK_PROOFS) CHECK_SOUND(e.isImpl(), "rewriteImplies precondition violated"); if(withProof()) { pf = newPf("rewrite_implies", e[0], e[1]); } return newRWTheorem(e, !e[0] || e[1], Assumptions::emptyAssump(), pf); } // ==> DISTINCT(e1,...,en) IFF AND 1 <= i < j <= n (e[i] /= e[j]) Theorem CoreTheoremProducer::rewriteDistinct(const Expr& e) { Proof pf; if(CHECK_PROOFS) { CHECK_SOUND(e.getKind() == DISTINCT, "rewriteDistinct precondition violated"); CHECK_SOUND(e.arity() > 0, "rewriteDistinct precondition violated"); } Expr res; if (e.arity() == 1) { res = e.getEM()->trueExpr(); } else if (e.arity() == 2) { res = !(e[0].eqExpr(e[1])); } else { vector tmp; for (int i = 0; i < e.arity(); ++i) { for (int j = i+1; j < e.arity(); ++j) { tmp.push_back(!(e[i].eqExpr(e[j]))); } } res = Expr(AND, tmp); } if(withProof()) { pf = newPf("rewrite_distinct", e , res); } return newRWTheorem(e, res, Assumptions::emptyAssump(), pf); } // ==> NOT(e) == ITE(e, FALSE, TRUE) Theorem CoreTheoremProducer::NotToIte(const Expr& not_e){ Proof pf; if(CHECK_PROOFS) CHECK_SOUND(not_e.isNot() && not_e[0].getType().isBool(), "NotToIte precondition violated"); if(withProof()) pf = newPf("NotToIte", not_e[0]); if(not_e[0].isTrue()) return d_core->getCommonRules()->rewriteNotTrue(not_e); else if(not_e[0].isFalse()) return d_core->getCommonRules()->rewriteNotFalse(not_e); Expr ite(not_e[0].iteExpr(d_em->falseExpr(), d_em->trueExpr())); return newRWTheorem(not_e, ite, Assumptions::emptyAssump(), pf); } // ==> Or(e) == ITE(e[1], TRUE, e[0]) Theorem CoreTheoremProducer::OrToIte(const Expr& e){ if(CHECK_PROOFS) CHECK_SOUND(e.isOr(), "OrToIte: precondition violated: " + e.toString()); Proof pf; if(withProof()) { pf = newPf("OrToIte", e); } const vector& kids = e.getKids(); unsigned k(kids.size()); if(k==0) return newRWTheorem(e, d_em->falseExpr(), Assumptions::emptyAssump(), pf); if(k==1) return newRWTheorem(e, e[0], Assumptions::emptyAssump(), pf); Expr ite(kids[k-1]); if(CHECK_PROOFS) CHECK_SOUND(!ite.getType().isNull(), "OrToIte: kid " + int2string(k-1) + " has no type: " + (ite).toString()); for (; k > 1; k--) { if (kids[k-2].isTrue()) { ite = d_em->trueExpr(); break; } else if(kids[k-2].isFalse()) continue; else{ if(CHECK_PROOFS) CHECK_SOUND(!kids[k-2].getType().isNull(), "OrToIte: kid " + int2string(k-2) + " has no type: " + (kids[k-2]).toString()); ite = ite.iteExpr(d_em->trueExpr(), kids[k-2]); } } return newRWTheorem(e, ite, Assumptions::emptyAssump(), pf); } // ==> And(e) == ITE(e[1], e[0], FALSE) Theorem CoreTheoremProducer::AndToIte(const Expr& e){ if(CHECK_PROOFS) CHECK_SOUND(e.isAnd(), "AndToIte: precondition violated: " + e.toString()); Proof pf; if(withProof()) { pf = newPf("AndToIte", e); } const vector& kids = e.getKids(); unsigned k(kids.size()); if(k==0) return newRWTheorem(e, d_em->trueExpr(), Assumptions::emptyAssump(), pf); if(k==1) return newRWTheorem(e, e[0], Assumptions::emptyAssump(), pf); Expr ite(kids[k-1]); if(CHECK_PROOFS) CHECK_SOUND(!ite.getType().isNull(), "AndToIte: kid " + int2string(k-1) + " has no type: " + (ite).toString()); for (; k > 1; k--) { if (kids[k-2].isFalse()) { ite = d_em->falseExpr(); break; } else if(kids[k-2].isTrue()) { continue; } else{ if(CHECK_PROOFS) CHECK_SOUND(!kids[k-2].getType().isNull(), "AndToIte: kid " + int2string(k-2) + " has no type: " + (kids[k-2]).toString()); ite = ite.iteExpr(kids[k-2], d_em->falseExpr()); } } return newRWTheorem(e, ite, Assumptions::emptyAssump(), pf); } // ==> IFF(a,b) == ITE(a, b, !b) Theorem CoreTheoremProducer::IffToIte(const Expr& e){ if(CHECK_PROOFS) CHECK_SOUND(e.isIff() && e[0].getType().isBool() && e[1].getType().isBool(), "IffToIte: precondition violated: " + e.toString()); Proof pf; if(e[0] == e[1]) return d_core->getCommonRules()->reflexivityRule(e); Expr ite(e[0].iteExpr(e[1], e[1].iteExpr(d_em->falseExpr(), d_em->trueExpr()))); if(withProof()) { pf = newPf("iff_to_ite", e); } return newRWTheorem(e, ite, Assumptions::emptyAssump(), pf); } // ==> IMPLIES(a,b) == ITE(a, b, TRUE) Theorem CoreTheoremProducer::ImpToIte(const Expr& e){ if(CHECK_PROOFS) CHECK_SOUND(e.isImpl() && e[0].getType().isBool() && e[1].getType().isBool(), "ImpToIte: precondition violated: " + e.toString()); Proof pf; if(e[0] == e[1]) return d_core->getCommonRules()->reflexivityRule(e); Expr ite(e[0].iteExpr(e[1], d_em->trueExpr())); if(withProof()) { pf = newPf("imp_to_ite", e); } return newRWTheorem(e, ite, Assumptions::emptyAssump(), pf); } // ==> ITE(e, FALSE, TRUE) IFF NOT(e) Theorem CoreTheoremProducer::rewriteIteToNot(const Expr& e) { if (CHECK_PROOFS) CHECK_SOUND(e.isITE() && e[1].isFalse() && e[2].isTrue(), "rewriteIteToNot: " + e.toString()); Proof pf; if (withProof()) pf = newPf("rewrite_ite_to_not", e); return newRWTheorem(e, e[0].negate(), Assumptions::emptyAssump(), pf); } // ==> ITE(a, TRUE, b) IFF OR(a, b) Theorem CoreTheoremProducer::rewriteIteToOr(const Expr& e) { if (CHECK_PROOFS) CHECK_SOUND(e.isITE() && e[1].isTrue(), "rewriteIteToOr: " + e.toString()); Proof pf; if (withProof()) pf = newPf("rewrite_ite_to_or", e); return newRWTheorem(e, e[0] || e[2], Assumptions::emptyAssump(), pf); } // ==> ITE(a, b, FALSE) IFF AND(a, b) Theorem CoreTheoremProducer::rewriteIteToAnd(const Expr& e) { if (CHECK_PROOFS) CHECK_SOUND(e.isITE() && e[2].isFalse(), "rewriteIteToAnd: " + e.toString()); Proof pf; if (withProof()) pf = newPf("rewrite_ite_to_and", e); return newRWTheorem(e, e[0] && e[1], Assumptions::emptyAssump(), pf); } // ==> ITE(a, b, !b) IFF IFF(a, b) Theorem CoreTheoremProducer::rewriteIteToIff(const Expr& e) { if (CHECK_PROOFS) CHECK_SOUND(e.isITE() && e[1] == e[2].negate(), "rewriteIteToIff: " + e.toString()); Proof pf; if (withProof()) pf = newPf("rewrite_ite_to_iff", e); return newRWTheorem(e, e[0].iffExpr(e[1]), Assumptions::emptyAssump(), pf); } // ==> ITE(a, b, TRUE) IFF IMPLIES(a, b) Theorem CoreTheoremProducer::rewriteIteToImp(const Expr& e) { if (CHECK_PROOFS) CHECK_SOUND(e.isITE() && e[2].isTrue(), "rewriteIteToImp: " + e.toString()); Proof pf; if (withProof()) pf = newPf("rewrite_ite_to_imp", e); return newRWTheorem(e, e[0].impExpr(e[1]), Assumptions::emptyAssump(), pf); } // ==> ITE(a, b(a), c(a)) IFF ITE(a, b(TRUE), c(FALSE)) // ==> ITE(x = y, b, c) IFF ITE(x = y b[x/y], c[x = y/FALSE]) Theorem CoreTheoremProducer::rewriteIteCond(const Expr& e) { if (CHECK_PROOFS) CHECK_SOUND(e.isITE() && e.arity()==3, "rewriteIteCond: " + e.toString()); vector oldTerms, newTerms; // // if (e[0].isEq()) { // // oldTerms.push_back(e[0][0]); // // newTerms.push_back(e[0][1]); // // } // // else { oldTerms.push_back(e[0]); newTerms.push_back(d_em->trueExpr()); // } Expr e1(e[1].substExpr(oldTerms, newTerms)); oldTerms[0] = e[0]; newTerms[0] = d_em->falseExpr(); Expr e2(e[2].substExpr(oldTerms, newTerms)); Proof pf; if (withProof()) pf = newPf("rewrite_ite_cond", e); return newRWTheorem(e, e[0].iteExpr(e1, e2), Assumptions::emptyAssump(), pf); } Theorem CoreTheoremProducer::iffOrDistrib(const Expr& iff) { if(CHECK_PROOFS) { CHECK_SOUND(iff.isIff() && iff.arity()==2, "iffOrDistrib(" +iff.toString()+")"); CHECK_SOUND(iff[0].isOr() && iff[0].arity()==2, "iffOrDistrib(" +iff.toString()+")"); CHECK_SOUND(iff[1].isOr() && iff[1].arity()==2, "iffOrDistrib(" +iff.toString()+")"); CHECK_SOUND(iff[0][0]==iff[1][0], "iffOrDistrib(" +iff.toString()+")"); } const Expr& a = iff[0][0]; const Expr& b = iff[0][1]; const Expr& c = iff[1][1]; Proof pf; if(withProof()) pf = newPf("iff_or_distrib", iff); return newRWTheorem(iff, (a || (b.iffExpr(c))), Assumptions::emptyAssump(), pf); } Theorem CoreTheoremProducer::iffAndDistrib(const Expr& iff) { if(CHECK_PROOFS) { CHECK_SOUND(iff.isIff() && iff.arity()==2, "iffAndDistrib(" +iff.toString()+")"); CHECK_SOUND(iff[0].isAnd() && iff[0].arity()==2, "iffAndDistrib(" +iff.toString()+")"); CHECK_SOUND(iff[1].isAnd() && iff[1].arity()==2, "iffAndDistrib(" +iff.toString()+")"); CHECK_SOUND(iff[0][0]==iff[1][0], "iffOrDistrib(" +iff.toString()+")"); } const Expr& a = iff[0][0]; const Expr& b = iff[0][1]; const Expr& c = iff[1][1]; Proof pf; if(withProof()) pf = newPf("iff_and_distrib", iff); return newRWTheorem(iff, (!a || (b.iffExpr(c))), Assumptions::emptyAssump(), pf); } // |- op(ITE(cond,a,b)) =/<=> ITE(cond,op(a),op(b)) Theorem CoreTheoremProducer::ifLiftUnaryRule(const Expr& e) { if(CHECK_PROOFS) { CHECK_SOUND(e.arity()==1 && e[0].isITE(), "CoreTheoremProducer::ifLiftUnaryRule(" "e = " + e.toString() + ")"); } Op op(e.getOp()); const Expr& ite = e[0]; const Expr& cond = ite[0]; const Expr& t1 = ite[1]; const Expr& t2 = ite[2]; if(CHECK_PROOFS) { CHECK_SOUND(cond.getType().isBool(), "CoreTheoremProducer::ifLiftUnaryRule(" "e = " + e.toString()+")"); } Expr e1 = Expr(op, t1); Expr e2 = Expr(op, t2); Expr resultITE = cond.iteExpr(e1, e2); Proof pf; if (withProof()) pf = newPf("if_lift_unary_rule", e); return newRWTheorem(e, resultITE, Assumptions::emptyAssump(), pf); } // (a & b) <=> a & b[a/true]; takes the index of a and rewrites all // the other conjuncts. Theorem CoreTheoremProducer::rewriteAndSubterms(const Expr& e, int idx) { if(CHECK_PROOFS) { CHECK_SOUND(e.isAnd() && 0 <= idx && idx < e.arity(), "rewriteAndSubterms("+e.toString() +", idx="+int2string(idx) +"):\n Expected an AND and a valid index of a child"); } vector kids; ExprHashMap subst; subst.insert(e[idx], d_em->trueExpr()); for(int i=0, iend=e.arity(); inewRatExpr(idx)); return newRWTheorem(e, Expr(e.getOp(), kids), Assumptions::emptyAssump(), pf); } // (a | b) <=> a | b[a/false]; takes the index of a and rewrites all // the other disjuncts. Theorem CoreTheoremProducer::rewriteOrSubterms(const Expr& e, int idx) { if(CHECK_PROOFS) { CHECK_SOUND(e.isOr() && 0 <= idx && idx < e.arity(), "rewriteOrSubterms("+e.toString() +", idx="+int2string(idx) +"):\n Expected an OR and a valid index of a child"); } vector kids; ExprHashMap subst; subst.insert(e[idx], d_em->falseExpr()); for(int i=0, iend=e.arity(); inewRatExpr(idx)); return newRWTheorem(e, Expr(e.getOp(), kids), Assumptions::emptyAssump(), pf); } Theorem CoreTheoremProducer::dummyTheorem(const Expr& e) { Proof pf; return newTheorem(e, Assumptions::emptyAssump(), pf); } cvc3-2.4.1/src/theory_core/expr_transform.cpp0000664000175400017540000004335711256001241021150 0ustar mdetersmdeters/*****************************************************************************/ /*! * \file expr_transform.cpp * * Author: Ying Hu, Clark Barrett * * Created: Jun 05 2003 * *
* * License to use, copy, modify, sell and/or distribute this software * and its documentation for any purpose is hereby granted without * royalty, subject to the terms and conditions defined in the \ref * LICENSE file provided with this distribution. * *
* */ /*****************************************************************************/ #include "expr_transform.h" #include "theory_core.h" #include "theory_arith.h" #include "command_line_flags.h" #include "core_proof_rules.h" #include using namespace std; using namespace CVC3; ExprTransform::ExprTransform(TheoryCore* core) : d_core(core) { d_commonRules = d_core->getCommonRules(); d_rules = d_core->getCoreRules(); } Theorem ExprTransform::smartSimplify(const Expr& e, ExprMap& cache) { ExprMap::iterator it; vector operatorStack; vector childStack; Expr e2; operatorStack.push_back(e); childStack.push_back(0); while (!operatorStack.empty()) { DebugAssert(operatorStack.size() == childStack.size(), "Invariant violated"); if (childStack.back() < operatorStack.back().arity()) { e2 = operatorStack.back()[childStack.back()++]; it = cache.find(e2); if (it != cache.end() || e2.hasFind() || e2.validSimpCache() || e2.arity() == 0) continue; if (operatorStack.size() >= 5000) { smartSimplify(e2, cache); cache[e2] = true; } else { operatorStack.push_back(e2); childStack.push_back(0); } } else { cache[operatorStack.back()] = true; operatorStack.pop_back(); childStack.pop_back(); } } DebugAssert(childStack.empty(), "Invariant violated"); return d_core->simplify(e); } Theorem ExprTransform::preprocess(const Expr& e) { // Force simplifier to run d_core->getEM()->invalidateSimpCache(); d_core->setInPP(); Theorem res = d_commonRules->reflexivityRule(e); if (d_core->getFlags()["preprocess"].getBool()) { if (d_core->getFlags()["pp-pushneg"].getBool()) { res = pushNegation(e); } ExprMap cache; if (d_core->getFlags()["pp-bryant"].getBool()) { res = d_commonRules->transitivityRule(res, smartSimplify(res.getRHS(), cache)); res = d_commonRules->transitivityRule(res, dobryant(res.getRHS())); } if (d_core->getFlags()["pp-care"].getBool()) { res = d_commonRules->transitivityRule(res, smartSimplify(res.getRHS(), cache)); res = d_commonRules->transitivityRule(res, simplifyWithCare(res.getRHS())); } int budget = 0; d_budgetLimit = d_core->getFlags()["pp-budget"].getInt(); while (budget < d_budgetLimit) { res = d_commonRules->transitivityRule(res, smartSimplify(res.getRHS(), cache)); Theorem ppRes = newPP(res.getRHS(), budget); if (ppRes.isRefl()) break; res = d_commonRules->transitivityRule(res, ppRes); if (d_core->getFlags()["pp-care"].getBool()) { res = d_commonRules->transitivityRule(res, smartSimplify(res.getRHS(), cache)); res = d_commonRules->transitivityRule(res, simplifyWithCare(res.getRHS())); } } res = d_commonRules->transitivityRule(res, smartSimplify(res.getRHS(), cache)); // Make sure this call is last as it cleans up theory core res = d_commonRules->transitivityRule(res, d_core->callTheoryPreprocess(res.getRHS())); } d_core->clearInPP(); return res; } Theorem ExprTransform::preprocess(const Theorem& thm) { return d_commonRules->iffMP(thm, preprocess(thm.getExpr())); } // We assume that the cache is initially empty Theorem ExprTransform::pushNegation(const Expr& e) { if(e.isTerm()) return d_commonRules->reflexivityRule(e); Theorem res(pushNegationRec(e, false)); d_pushNegCache.clear(); return res; } // Recursively descend into the expression e, keeping track of whether // we are under even or odd number of negations ('neg' == true means // odd, the context is "negative"). // Produce a proof of e <==> e' or !e <==> e', depending on whether // neg is false or true, respectively. Theorem ExprTransform::pushNegationRec(const Expr& e, bool neg) { TRACE("pushNegation", "pushNegationRec(", e, ", neg=" + string(neg? "true":"false") + ") {"); DebugAssert(!e.isTerm(), "pushNegationRec: not boolean e = "+e.toString()); ExprMap::iterator i = d_pushNegCache.find(neg? !e : e); if(i != d_pushNegCache.end()) { // Found cached result TRACE("pushNegation", "pushNegationRec [cached] => ", (*i).second, "}"); return (*i).second; } // By default, do not rewrite Theorem res(d_core->reflexivityRule((neg)? !e : e)); if(neg) { switch(e.getKind()) { case TRUE_EXPR: res = d_commonRules->rewriteNotTrue(!e); break; case FALSE_EXPR: res = d_commonRules->rewriteNotFalse(!e); break; case NOT: res = pushNegationRec(d_commonRules->rewriteNotNot(!e), false); break; case AND: res = pushNegationRec(d_rules->rewriteNotAnd(!e), false); break; case OR: res = pushNegationRec(d_rules->rewriteNotOr(!e), false); break; case IMPLIES: { vector thms; thms.push_back(d_rules->rewriteImplies(e)); res = pushNegationRec (d_commonRules->substitutivityRule(NOT, thms), true); break; } // case IFF: // // Preserve equivalences to explore structural similarities // if(e[0].getKind() == e[1].getKind()) // res = d_commonRules->reflexivityRule(!e); // else // res = pushNegationRec(d_commonRules->rewriteNotIff(!e), false); // break; case ITE: res = pushNegationRec(d_rules->rewriteNotIte(!e), false); break; // Replace LETDECL with its definition. The // typechecker makes sure it's type-safe to do so. case LETDECL: { vector thms; thms.push_back(d_rules->rewriteLetDecl(e)); res = pushNegationRec (d_commonRules->substitutivityRule(NOT, thms), true); break; } default: res = d_commonRules->reflexivityRule(!e); } // end of switch(e.getKind()) } else { // if(!neg) switch(e.getKind()) { case NOT: res = pushNegationRec(e[0], true); break; case AND: case OR: case IFF: case ITE: { Op op = e.getOp(); vector thms; for(Expr::iterator i=e.begin(), iend=e.end(); i!=iend; ++i) thms.push_back(pushNegationRec(*i, false)); res = d_commonRules->substitutivityRule(op, thms); break; } case IMPLIES: res = pushNegationRec(d_rules->rewriteImplies(e), false); break; case LETDECL: res = pushNegationRec(d_rules->rewriteLetDecl(e), false); break; default: res = d_commonRules->reflexivityRule(e); } // end of switch(e.getKind()) } TRACE("pushNegation", "pushNegationRec => ", res, "}"); d_pushNegCache[neg? !e : e] = res; return res; } Theorem ExprTransform::pushNegationRec(const Theorem& thm, bool neg) { DebugAssert(thm.isRewrite(), "pushNegationRec(Theorem): bad theorem: " + thm.toString()); Expr e(thm.getRHS()); if(neg) { DebugAssert(e.isNot(), "pushNegationRec(Theorem, neg = true): bad Theorem: " + thm.toString()); e = e[0]; } return d_commonRules->transitivityRule(thm, pushNegationRec(e, neg)); } Theorem ExprTransform::pushNegation1(const Expr& e) { TRACE("pushNegation1", "pushNegation1(", e, ") {"); DebugAssert(e.isNot(), "pushNegation1("+e.toString()+")"); Theorem res; switch(e[0].getKind()) { case TRUE_EXPR: res = d_commonRules->rewriteNotTrue(e); break; case FALSE_EXPR: res = d_commonRules->rewriteNotFalse(e); break; case NOT: res = d_commonRules->rewriteNotNot(e); break; case AND: res = d_rules->rewriteNotAnd(e); break; case OR: res = d_rules->rewriteNotOr(e); break; case IMPLIES: { vector thms; thms.push_back(d_rules->rewriteImplies(e[0])); res = d_commonRules->substitutivityRule(e.getOp(), thms); res = d_commonRules->transitivityRule(res, d_rules->rewriteNotOr(res.getRHS())); break; } case ITE: res = d_rules->rewriteNotIte(e); break; // Replace LETDECL with its definition. The // typechecker makes sure it's type-safe to do so. case LETDECL: { vector thms; thms.push_back(d_rules->rewriteLetDecl(e[0])); res = d_commonRules->substitutivityRule(e.getOp(), thms); res = d_commonRules->transitivityRule(res, pushNegation1(res.getRHS())); break; } default: res = d_commonRules->reflexivityRule(e); } TRACE("pushNegation1", "pushNegation1 => ", res.getExpr(), " }"); return res; } Theorem ExprTransform::newPP(const Expr& e, int& budget) { if (!e.getType().isBool()) return d_commonRules->reflexivityRule(e); d_newPPCache.clear(); Theorem thm = newPPrec(e, budget); // cout << "budget = " << budget << endl; if (budget > d_budgetLimit || thm.getRHS().getSize() > 2 * e.getSize()) { return d_commonRules->reflexivityRule(e); } return thm; } Theorem ExprTransform::specialSimplify(const Expr& e, ExprHashMap& cache) { if (e.isAtomic()) return d_commonRules->reflexivityRule(e); ExprHashMap::iterator it = cache.find(e); if (it != cache.end()) return (*it).second; Theorem thm; if (e.getType().isBool()) { thm = d_core->simplify(e); if (thm.getRHS().isBoolConst()) { cache[e] = thm; return thm; } } thm = d_commonRules->reflexivityRule(e); vector newChildrenThm; vector changed; int ar = e.arity(); for(int k = 0; k < ar; ++k) { // Recursively process the kids Theorem thm2 = specialSimplify(e[k], cache); if (!thm2.isRefl()) { newChildrenThm.push_back(thm2); changed.push_back(k); } } if(changed.size() > 0) { thm = d_commonRules->substitutivityRule(e, changed, newChildrenThm); } cache[e] = thm; return thm; } Theorem ExprTransform::newPPrec(const Expr& e, int& budget) { DebugAssert(e.getType().isBool(), "Expected Boolean expression"); Theorem res = d_commonRules->reflexivityRule(e); if (!e.containsTermITE()) return res; ExprMap::iterator i = d_newPPCache.find(e); if (i != d_newPPCache.end()) { // Found cached result res = (*i).second; return res; } Expr current = e; Expr newExpr; Theorem thm, thm2; do { if (budget > d_budgetLimit) break; ++budget; // Recursive case if (!current.isPropAtom()) { vector newChildrenThm; vector changed; int ar = current.arity(); for(int k = 0; k < ar; ++k) { // Recursively process the kids thm = newPPrec(current[k], budget); if (!thm.isRefl()) { newChildrenThm.push_back(thm); changed.push_back(k); } } if(changed.size() > 0) { thm = d_commonRules->transitivityRule(res, d_commonRules->substitutivityRule(current, changed, newChildrenThm)); newExpr = thm.getRHS(); res = thm; } break; } // if (current.getSize() > 1000) { // break; // } // Contains Term ITEs thm = d_commonRules->transitivityRule(res, d_commonRules->liftOneITE(current)); newExpr = thm.getRHS(); if ((newExpr[0].isLiteral() || newExpr[0].isAnd())) { d_core->getCM()->push(); d_core->addFact(d_commonRules->assumpRule(newExpr[0])); thm2 = d_core->simplify(newExpr[1]); thm = d_commonRules->transitivityRule(thm, d_rules->rewriteIteThen(newExpr, thm2)); d_core->getCM()->pop(); d_core->getCM()->push(); d_core->addFact(d_commonRules->assumpRule(newExpr[0].negate())); thm2 = d_core->simplify(newExpr[2]); newExpr = thm.getRHS(); thm = d_commonRules->transitivityRule(thm, d_rules->rewriteIteElse(newExpr, thm2)); d_core->getCM()->pop(); newExpr = thm.getRHS(); } res = thm; current = newExpr; } while (current.containsTermITE()); d_newPPCache[e] = res; return res; } void ExprTransform::updateQueue(ExprMap* >& queue, const Expr& e, const set& careSet) { ExprMap* >::iterator it = queue.find(e), iend = queue.end(); if (it != iend) { set* cs2 = (*it).second; set* csNew = new set; set_intersection(careSet.begin(), careSet.end(), cs2->begin(), cs2->end(), inserter(*csNew, csNew->begin())); (*it).second = csNew; delete cs2; } else { queue[e] = new set(careSet); } } Theorem ExprTransform::substitute(const Expr& e, ExprHashMap& substTable, ExprHashMap& cache) { if (e.isAtomic()) return d_commonRules->reflexivityRule(e); // check cache ExprHashMap::iterator it = cache.find(e), iend = cache.end(); if (it != iend) { return it->second; } // do substitution? it = substTable.find(e); iend = substTable.end(); if (it != iend) { return d_commonRules->transitivityRule(it->second, substitute(it->second.getRHS(), substTable, cache)); } Theorem res = d_commonRules->reflexivityRule(e); int ar = e.arity(); if (ar > 0) { vector newChildrenThm; vector changed; for(int k = 0; k < ar; ++k) { Theorem thm = substitute(e[k], substTable, cache); if (!thm.isRefl()) { newChildrenThm.push_back(thm); changed.push_back(k); } } if(changed.size() > 0) { res = d_commonRules->substitutivityRule(e, changed, newChildrenThm); } } cache[e] = res; return res; } Theorem ExprTransform::simplifyWithCare(const Expr& e) { ExprHashMap substTable; ExprMap* > queue; ExprMap* >::iterator it; set cs; updateQueue(queue, e, cs); Expr v; bool done; Theorem thm; int i; while (!queue.empty()) { it = queue.end(); --it; v = it->first; cs = *(it->second); delete it->second; queue.erase(v); if (v.isAtomic() || v.isAtomicFormula()) { // Unfortunately, this can lead to incompleteness bugs // d_core->getCM()->push(); // set::iterator iCare = cs.begin(), iCareEnd = cs.end(); // for (; iCare != iCareEnd; ++iCare) { // d_core->addFact(d_commonRules->assumpRule((*iCare))); // } // thm = d_core->simplify(v); // if (!thm.isRefl()) { // substTable[v] = d_rules->dummyTheorem(thm.getExpr()); // } // d_core->getCM()->pop(); continue; } if (false && v.isPropAtom() && d_core->theoryOf(v) == d_theoryArith && d_theoryArith->leavesAreNumConst(v)) { Expr vNew = v; thm = d_commonRules->reflexivityRule(vNew); while (vNew.containsTermITE()) { thm = d_commonRules->transitivityRule(thm, d_commonRules->liftOneITE(vNew)); DebugAssert(!thm.isRefl(), "Expected non-reflexive"); thm = d_commonRules->transitivityRule(thm, d_rules->rewriteIteCond(thm.getRHS())); thm = d_commonRules->transitivityRule(thm, d_core->simplify(thm.getRHS())); vNew = thm.getRHS(); } substTable[v] = thm; continue; } done = false; set::iterator iCare, iCareEnd = cs.end(); switch (v.getKind()) { case ITE: { iCare = cs.find(v[0]); if (iCare != iCareEnd) { Expr rewrite = v.getType().isBool() ? v.iffExpr(v[1]) : v.eqExpr(v[1]); substTable[v] = d_rules->dummyTheorem(rewrite); updateQueue(queue, v[1], cs); done = true; break; } else { iCare = cs.find(v[0].negate()); if (iCare != iCareEnd) { Expr rewrite = v.getType().isBool() ? v.iffExpr(v[2]) : v.eqExpr(v[2]); substTable[v] = d_rules->dummyTheorem(rewrite); updateQueue(queue, v[2], cs); done = true; break; } } updateQueue(queue, v[0], cs); cs.insert(v[0]); updateQueue(queue, v[1], cs); cs.erase(v[0]); cs.insert(v[0].negate()); updateQueue(queue, v[2], cs); done = true; break; } case AND: { for (i = 0; i < v.arity(); ++i) { iCare = cs.find(v[i].negate()); if (iCare != iCareEnd) { Expr rewrite = v.iffExpr(d_core->getEM()->falseExpr()); substTable[v] = d_rules->dummyTheorem(rewrite); done = true; break; } } if (done) break; DebugAssert(v.arity() > 1, "Expected arity > 1"); cs.insert(v[1]); updateQueue(queue, v[0], cs); cs.erase(v[1]); cs.insert(v[0]); for (i = 1; i < v.arity(); ++i) { updateQueue(queue, v[i], cs); } done = true; break; } case OR: { for (i = 0; i < v.arity(); ++i) { iCare = cs.find(v[i]); if (iCare != iCareEnd) { Expr rewrite = v.iffExpr(d_core->getEM()->trueExpr()); substTable[v] = d_rules->dummyTheorem(rewrite); done = true; break; } } if (done) break; DebugAssert(v.arity() > 1, "Expected arity > 1"); cs.insert(v[1].negate()); updateQueue(queue, v[0], cs); cs.erase(v[1].negate()); cs.insert(v[0].negate()); for (i = 1; i < v.arity(); ++i) { updateQueue(queue, v[i], cs); } done = true; break; } default: break; } if (done) continue; for (int i = 0; i < v.arity(); ++i) { updateQueue(queue, v[i], cs); } } ExprHashMap cache; return substitute(e, substTable, cache); } cvc3-2.4.1/src/theory_core/bryant.cpp0000664000175400017540000005550411103725116017400 0ustar mdetersmdeters#include "vc.h" #include "expr_transform.h" #include "theory_core.h" #include "command_line_flags.h" #include "core_proof_rules.h" using namespace std; using namespace CVC3; const int LIMIT = 55; int ExprTransform::CountSubTerms(const Expr& e, int& counter) { if (e.arity() == 0) return 0; for (int i = 0; i < e.arity(); i++) { int count = CountSubTerms(e[i], counter) + 1; if (count > counter) counter = count; } return counter; } std::string ExprTransform::NewBryantVar(const int a, const int b){ std::string S; std::stringstream out1, out2; out1 << a; out2 << b; std::string Tempvar = "A"; S = Tempvar + out1.str() + "B" + out2.str(); return S; } ExprTransform::B_name_map ExprTransform::BryantNames(T_generator_map& generator_map, B_type_map& type_map) { B_name_map name_map; int VarTotal = 0; for (T_generator_map::iterator f = generator_map.begin(); f != generator_map.end(); f++){ VarTotal++; Type TempType = type_map.find((*f).first)->second; int ArgVar = 0; for (set< Expr >::iterator p = (*f).second->begin(); p != (*f).second->end(); p++){ ArgVar++; pair< Expr, Expr > key = pair< Expr, Expr >((*f).first, (*p)); std::string NewName = NewBryantVar(VarTotal, ArgVar); Expr value = d_core->newVar(NewName, TempType); name_map.insert( *new pair< pair< Expr, Expr>, Expr >(key, value)); } } return name_map; } void ExprTransform::PredConstrainer(set& Not_replaced_set, const Expr& e, const Expr& Pred, int location, B_name_map& name_map, set& SeenBefore, set& Constrained_set, T_generator_map& Constrained_map, set& P_constrained_set) { if (!SeenBefore.insert(e).second) return; if (e.isApply() && e.getOpKind() == UFUNC && !e.isTerm()) if (e.getOpExpr() == Pred.getOpExpr() && Pred[location] != e[location]) { Expr Temp0, Temp1; if (e[location].isVar() || Not_replaced_set.find(e[location]) != Not_replaced_set.end()) Temp0 = e[location]; else Temp0 = name_map.find(pair((e[location]).getOpExpr(),(e[location])))->second; if (Pred[location].isVar()) Temp1 = Pred[location]; else Temp1 = name_map.find(pair((Pred[location]).getOpExpr(),(Pred[location])))->second; if (Constrained_set.find(e[location]) != Constrained_set.end()) { Expr Eq = Temp0.eqExpr(Temp1); Expr Reflexor = Temp1.eqExpr(Temp0); Eq = Eq.notExpr(); Reflexor = Reflexor.notExpr(); if (P_constrained_set.find(Reflexor) == P_constrained_set.end()) P_constrained_set.insert(Eq); } else { if (Constrained_map.find(Pred[location]) == Constrained_map.end()) Constrained_map.insert(pair*>(Pred[location], new set)); Constrained_map[Pred[location]]->insert(Temp0); } } for (int l = 0; l < e.arity(); l++) PredConstrainer(Not_replaced_set, e[l], Pred, location, name_map, SeenBefore, Constrained_set, Constrained_map, P_constrained_set); } void ExprTransform::PredConstrainTester(set& Not_replaced_set, const Expr& e, B_name_map& name_map, vector& Pred_vec, set& Constrained_set, set& P_constrained_set, T_generator_map& Constrained_map) { for (vector::iterator i = Pred_vec.begin(); i != Pred_vec.end(); i++) { for (int k = 0; k < (*i).arity(); k++) if (Constrained_set.find((*i)[k]) != Constrained_set.end()){ set SeenBefore; PredConstrainer(Not_replaced_set, e, (*i), k, name_map, SeenBefore, Constrained_set, Constrained_map, P_constrained_set); } } } Expr ExprTransform::ITE_generator(Expr& Orig, Expr& Value, B_Term_map& Creation_map, B_name_map& name_map, T_ITE_map& ITE_map) { Expr NewITE; for (vector::reverse_iterator f = (Creation_map.find(Orig.getOpExpr())->second->rbegin()); f != (Creation_map.find(Orig.getOpExpr())->second->rend()); f++) { if ((*f).getOpExpr() == Orig.getOpExpr()) { Expr TempExpr; for (int i = 0; i < Orig.arity(); i++) { Expr TempEqExpr; if ((*f)[i].isApply()) //(Orig[i].isApply()) TempEqExpr = ITE_map.find((*f)[i])->second; else TempEqExpr = (*f)[i]; // TempEqExpr = Orig[i]; if (Orig[i].isApply()) // ((*f)[i].isApply()) TempEqExpr = TempEqExpr.eqExpr(ITE_map.find(Orig[i])->second); else TempEqExpr = TempEqExpr.eqExpr(Orig[i]); if (TempExpr.isNull() == true) TempExpr = TempEqExpr; else TempExpr = TempExpr.andExpr(TempEqExpr); } if (NewITE.isNull() == true) NewITE = TempExpr.iteExpr(name_map.find(pair((*f).getOpExpr(),(*f)))->second, Value); else { Expr Temp = NewITE; NewITE = TempExpr.iteExpr(name_map.find(pair((*f).getOpExpr(),(*f)))->second, Temp); } } } return NewITE; } void ExprTransform::Get_ITEs(B_formula_map& instance_map, set& Not_replaced_set, B_Term_map& P_term_map, T_ITE_vec& ITE_vec, B_Term_map& Creation_map, B_name_map& name_map, T_ITE_map& ITE_map) { for (T_ITE_vec::iterator f = ITE_vec.begin(); f != ITE_vec.end(); f++) { if (!(*f).isVar()) { if (Creation_map.find((*f).getOpExpr()) == Creation_map.end()) { Creation_map.insert(pair*> ( (*f).getOpExpr(), new vector ())); Creation_map[(*f).getOpExpr()]->push_back((*f)); if (instance_map[(*f).getOpExpr()] < LIMIT || !(*f).isTerm()) ITE_map.insert(pair ((*f), name_map.find(pair< Expr, Expr> ((*f).getOpExpr(), (*f)))->second)); else { ITE_map.insert(pair ((*f), (*f))); Not_replaced_set.insert(*f); } } else { if (instance_map[(*f).getOpExpr()] > LIMIT && (*f).isTerm()) { ITE_map.insert(pair ((*f), (*f))); Creation_map[(*f).getOpExpr()]->push_back((*f)); Not_replaced_set.insert(*f); } else { Expr NewValue = name_map.find(pair ( (*f).getOpExpr(), (*f)))->second; Expr Add = ITE_generator((*f), NewValue, Creation_map, name_map, ITE_map); ITE_map.insert(pair ((*f), Add)); Creation_map[(*f).getOpExpr()]->push_back((*f)); } } } } } void ExprTransform::RemoveFunctionApps(const Expr& orig, set& Not_replaced_set, vector& Old, vector& New, T_ITE_map& ITE_map, set& SeenBefore) { if (!SeenBefore.insert( orig ).second) return; for (int i = 0; i < orig.arity() ; i++) RemoveFunctionApps(orig[i], Not_replaced_set, Old, New, ITE_map, SeenBefore); if (orig.isApply() && orig.getOpKind() == UFUNC && Not_replaced_set.find(orig) != Not_replaced_set.end()) { Old.push_back(orig); New.push_back(ITE_map.find(orig)->second); } } void ExprTransform::GetSortedOpVec(B_Term_map& X_generator_map, B_Term_map& X_term_map, B_Term_map& P_term_map, set& P_terms, set& G_terms, set& X_terms, vector& sortedOps, set& SeenBefore) { for (B_Term_map::iterator i = X_generator_map.begin(); i != X_generator_map.end(); i++) { for (vector::iterator j = (*i).second->begin(); j != (*i).second->end(); j++) { if (P_terms.find(*j) != P_terms.end()) { vector::iterator k = j; k++; bool added = false; for (; k != (*i).second->end(); k++) { if (G_terms.find(*k) != G_terms.end() && !added) { if (X_term_map.find((*j).getOpExpr()) == X_term_map.end()) X_term_map.insert(pair*>((*j).getOpExpr(), new vector)); X_term_map[(*j).getOpExpr()]->push_back(*j); X_terms.insert(*j); added = true; } } } } } set sorted; map*> Opmap; for (B_Term_map::iterator i = P_term_map.begin(); i != P_term_map.end(); i++) { int count = 0; for (vector::iterator j = (*i).second->begin(); j != (*i).second->end(); j++) count++; if (X_term_map.find((*i).first) != X_term_map.end()) { for (vector::iterator j = X_term_map[(*i).first]->begin(); j != X_term_map[(*i).first]->end(); j++) count--; } if (Opmap.find(count) == Opmap.end()) Opmap.insert(pair*>(count, new set)); Opmap[count]->insert((*i).first); sorted.insert(count); } vector sortedvec; for (set::iterator i = sorted.begin(); i != sorted.end(); i++) sortedvec.push_back(*i); sort(sortedvec.begin(), sortedvec.end()); for (vector::iterator i = sortedvec.begin(); i != sortedvec.end(); i++) { for (set::iterator j = Opmap[*i]->begin(); j != Opmap[*i]->end(); j++) sortedOps.push_back(*j); } } void ExprTransform::GetFormulaMap(const Expr& e, set& formula_map, set& G_terms, int& size, int negations) { if (e.isEq() && negations % 2 == 1) formula_map.insert(e); if (e.isNot()) negations++; size++; for (int i = 0; i < e.arity(); i++) GetFormulaMap(e[i], formula_map, G_terms, size, negations); } void ExprTransform::GetGTerms2(set& formula_map, set& G_terms) { for (set::iterator i = formula_map.begin(); i != formula_map.end(); i++) if ((*i)[0].isTerm()) for (int j = 0; j < 2; j++) { G_terms.insert((*i)[j]); } } void ExprTransform::GetSub_vec(T_ITE_vec& ITE_vec, const Expr& e, set& ITE_Added) { for (int i = 0; i < e.arity(); i++ ) GetSub_vec(ITE_vec, e[i], ITE_Added); if (e.isTerm() && ITE_Added.insert(e).second) ITE_vec.push_back(e); } void ExprTransform::GetOrderedTerms(B_formula_map& instance_map, B_name_map& name_map, B_Term_map& X_term_map, T_ITE_vec& ITE_vec, set& G_terms, set& X_terms, vector& Pred_vec, vector& sortedOps, vector& Constrained_vec, vector& UnConstrained_vec, set& Constrained_set, set& UnConstrained_set, B_Term_map& G_term_map, B_Term_map& P_term_map, set& SeenBefore, set& ITE_Added) { for (vector::iterator i = sortedOps.begin(); i != sortedOps.end(); i++){ if (G_term_map.find(*i) != G_term_map.end()) { for (vector::iterator j = G_term_map[*i]->begin(); j != G_term_map[*i]->end(); j++) GetSub_vec(ITE_vec,(*j), ITE_Added); } } for (vector::iterator i = sortedOps.begin(); i != sortedOps.end(); i++){ if (!P_term_map[*i]->empty()) { for (vector::iterator j = P_term_map[*i]->begin(); j != P_term_map[*i]->end(); j++) GetSub_vec(ITE_vec, (*j), ITE_Added); } } for (vector::iterator i = ITE_vec.begin(); i != ITE_vec.end(); i++) { if (G_terms.find(*i) != G_terms.end()) { UnConstrained_set.insert(*i); UnConstrained_vec.push_back(*i); } else if ((*i).isApply()) { if (instance_map[(*i).getOpExpr()] > 40){ UnConstrained_set.insert(*i); UnConstrained_vec.push_back(*i); } } else if (X_terms.find(*i) == X_terms.end()) { Constrained_set.insert(*i); Constrained_vec.push_back(*i); } else { vector::iterator j = i; j = j + 1; bool found = false; for (; j != ITE_vec.end(); j++) { if (!(*j).isVar()) if (G_terms.find(*j) != G_terms.end() && (*j).getOpExpr() == (*i).getOpExpr() && !found) { UnConstrained_vec.push_back(*i); UnConstrained_set.insert(*i); j = ITE_vec.end(); j--; found = true; } } if (!found) { Constrained_vec.push_back(*i); Constrained_set.insert(*i); } } } for (vector::iterator l = Pred_vec.begin(); l != Pred_vec.end(); l++) ITE_vec.push_back(*l); } void ExprTransform::BuildBryantMaps(const Expr& e, T_generator_map& generator_map, B_Term_map& X_generator_map, B_type_map& type_map, vector& Pred_vec, set& P_terms, set& G_terms, B_Term_map& P_term_map, B_Term_map& G_term_map, set< Expr >& SeenBefore, set& ITE_Added){ if ( !SeenBefore.insert( e ).second ) return; if ( e.isApply() && e.getOpKind() == UFUNC){ type_map.insert(pair(e.getOpExpr(), e.getType())); if ( generator_map.find( e.getOpExpr() ) == generator_map.end() ) generator_map.insert(pair< Expr, set* >( e.getOpExpr(), new set())); generator_map[e.getOpExpr()]->insert(e); } if (e.isApply() && e.getOpKind() == UFUNC && !e.isTerm()) Pred_vec.push_back(e); for ( int i = 0; i < e.arity(); i++ ) BuildBryantMaps(e[i], generator_map, X_generator_map, type_map, Pred_vec, P_terms, G_terms, P_term_map, G_term_map, SeenBefore, ITE_Added); if (e.isTerm() && G_terms.find(e) == G_terms.end()) P_terms.insert(e); if (e.isTerm()) { if (!e.isVar()) { if (X_generator_map.find(e.getOpExpr()) == X_generator_map.end()) X_generator_map.insert(pair< Expr, vector* >( e.getOpExpr(), new vector())); X_generator_map[e.getOpExpr()]->push_back(e); } if (ITE_Added.insert(e).second) { if (G_terms.find(e) != G_terms.end()) { if (e.isVar()) { G_term_map.insert(pair*>(e, new vector())); P_term_map.insert(pair*>(e, new vector())); G_term_map[e]->push_back(e); } else { if (G_term_map.find(e.getOpExpr()) == G_term_map.end()) { G_term_map.insert(pair*>(e.getOpExpr(), new vector())); P_term_map.insert(pair*>(e.getOpExpr(), new vector())); } G_term_map[e.getOpExpr()]->push_back(e); } } else { if (e.isVar()) { if (P_term_map.find(e) == P_term_map.end()) P_term_map.insert(pair*>(e, new vector())); P_term_map[e]->push_back(e); } else { if (P_term_map.find(e.getOpExpr()) == P_term_map.end()) P_term_map.insert(pair*>(e.getOpExpr(), new vector())); P_term_map[e.getOpExpr()]->push_back(e); } } } } return; } void ExprTransform::GetPEqs(const Expr& e, B_name_map& name_map, set& P_constrained_set, set& Constrained_set, T_generator_map& Constrained_map, set& SeenBefore) { if (!SeenBefore.insert(e).second) return; if (e.isEq()) { if (Constrained_set.find(e[1]) != Constrained_set.end() && Constrained_set.find(e[0]) != Constrained_set.end()) { Expr Temp0, Temp1; if (e[0] != e[1]) { if (e[0].isVar()) Temp0 = e[0]; else Temp0 = name_map.find(pair ((e[0]).getOpExpr(), (e[0])))->second; if (e[1].isVar()) Temp1 = e[1]; else Temp1 = name_map.find(pair ((e[1]).getOpExpr(), (e[1])))->second; Expr Eq = Temp0.eqExpr(Temp1); Expr Reflexor = Temp1.eqExpr(Temp0); Eq = Eq.notExpr(); Reflexor = Reflexor.notExpr(); if (P_constrained_set.find(Reflexor) == P_constrained_set.end()) P_constrained_set.insert(Eq); } } else if (Constrained_set.find(e[0]) != Constrained_set.end()) { if (Constrained_map.find(e[0]) == Constrained_map.end()) Constrained_map.insert(pair*> (e[0], new set< Expr> )); Constrained_map[e[0]]->insert(e[1]); } else if (Constrained_set.find(e[1]) != Constrained_set.end()) { if (Constrained_map.find(e[1]) == Constrained_map.end()) Constrained_map.insert(pair*> (e[1], new set< Expr> )); Constrained_map[e[1]]->insert(e[0]); } } for (int i = 0; i < e.arity(); i++) GetPEqs(e[i], name_map, P_constrained_set, Constrained_set, Constrained_map, SeenBefore); } Expr ExprTransform::ConstrainedConstraints(set& Not_replaced_set, T_generator_map& Constrained_map, B_name_map& name_map, B_Term_map& Creation_map, set& Constrained_set, set& UnConstrained_set, set& P_constrained_set) { if (Constrained_set.empty()) return d_core->trueExpr(); for (T_generator_map::iterator f = Constrained_map.begin(); f != Constrained_map.end(); f++) { Expr Value; if ((*f).first.isVar()) Value = (*f).first; else Value = name_map.find(pair((*f).first.getOpExpr(),(*f).first))->second; for (set::iterator j = (*f).second->begin(); j != (*f).second->end(); j++) { if (Value != (*j)) { if ((*j).isVar() || Not_replaced_set.find(*j) != Not_replaced_set.end()){ Expr Temp = Value.eqExpr(*j); Temp = Temp.notExpr(); P_constrained_set.insert(Temp); } else { vector::iterator c = Creation_map[(*j).getOpExpr()]->begin(); bool done = false; while ( !done && c != Creation_map[(*j).getOpExpr()]->end() ) { if ((*c) == (*j)) done = true; Expr Temp = name_map.find(pair((*c).getOpExpr(),(*c)))->second; Expr TempEqExpr = Value.eqExpr(Temp); TempEqExpr = TempEqExpr.notExpr(); if (!Value == Temp) P_constrained_set.insert(TempEqExpr); c++; } } } } } if (P_constrained_set.empty()) return d_core->trueExpr(); else { Expr Constraints = *(P_constrained_set.begin()); set::iterator i = P_constrained_set.begin(); i++; for (; i != P_constrained_set.end(); i++) Constraints = Constraints.andExpr(*i); return Constraints; } } void ExprTransform::GetOrdering(B_Term_map& X_generator_map, B_Term_map& G_term_map, B_Term_map& P_term_map) { for (B_Term_map::iterator i = X_generator_map.begin(); i != X_generator_map.end(); i++) { map*> Order_map; set Order_set; for (vector::iterator j = (*i).second->begin(); j != (*i).second->end(); j++) { int temp = 0; int Counter = CountSubTerms(*j, temp); if (Order_map.find(Counter) == Order_map.end()) Order_map.insert(pair*>(Counter, new vector)); Order_map[Counter]->push_back(*j); Order_set.insert(Counter); } vector Order_vec; for (set::iterator m = Order_set.begin(); m != Order_set.end(); m++) Order_vec.push_back(*m); (*i).second->clear(); sort(Order_vec.begin(), Order_vec.end()); for (vector::iterator k = Order_vec.begin(); k != Order_vec.end(); k++) for (vector::iterator l = Order_map[*k]->begin(); l != Order_map[*k]->end(); l++){ (*i).second->push_back(*l); } } for (B_Term_map::iterator i = G_term_map.begin(); i != G_term_map.end(); i++) { map*> Order_map; set Order_set; for (vector::iterator j = (*i).second->begin(); j != (*i).second->end(); j++) { int temp = 0; int Counter = CountSubTerms(*j, temp); if (Order_map.find(Counter) == Order_map.end()) Order_map.insert(pair*>(Counter, new vector)); Order_map[Counter]->push_back(*j); Order_set.insert(Counter); } vector Order_vec; for (set::iterator m = Order_set.begin(); m != Order_set.end(); m++) Order_vec.push_back(*m); (*i).second->clear(); sort(Order_vec.begin(), Order_vec.end()); for (vector::iterator k = Order_vec.begin(); k != Order_vec.end(); k++) for (vector::iterator l = Order_map[*k]->begin(); l != Order_map[*k]->end(); l++){ (*i).second->push_back(*l); } } for (B_Term_map::iterator i = P_term_map.begin(); i != P_term_map.end(); i++) { map*> Order_map; set Order_set; for (vector::iterator j = (*i).second->begin(); j != (*i).second->end(); j++) { int temp = 0; int Counter = CountSubTerms(*j, temp); if (Order_map.find(Counter) == Order_map.end()) Order_map.insert(pair*>(Counter, new vector)); Order_map[Counter]->push_back(*j); Order_set.insert(Counter); } vector Order_vec; for (set::iterator m = Order_set.begin(); m != Order_set.end(); m++) Order_vec.push_back(*m); (*i).second->clear(); sort(Order_vec.begin(), Order_vec.end()); for (vector::iterator k = Order_vec.begin(); k != Order_vec.end(); k++) for (vector::iterator l = Order_map[*k]->begin(); l != Order_map[*k]->end(); l++){ (*i).second->push_back(*l); } } } void ExprTransform::B_Term_Map_Deleter(B_Term_map& Map) { for (B_Term_map::iterator j = Map.begin(); j != Map.end(); j++) delete (*j).second; } void ExprTransform::T_generator_Map_Deleter(T_generator_map& Map) { for (T_generator_map::iterator j = Map.begin(); j != Map.end(); j++) delete (*j).second; } Theorem ExprTransform::dobryant(const Expr& T){ Expr U = T.notExpr(); set P_terms, G_terms, X_terms, formula_1_map, Constrained_set, UnConstrained_set, P_constrained_set, UnConstrained_Pred_set, Not_replaced_set; B_name_map name_map; B_type_map type_map; B_Term_map P_term_map, G_term_map, X_term_map, X_generator_map, Creation_map; B_formula_map instance_map; T_generator_map generator_map, Constrained_map; T_ITE_vec ITE_vec; T_ITE_map ITE_map; int size = 0; GetFormulaMap(U, formula_1_map, G_terms, size, 0); GetGTerms2(formula_1_map, G_terms); vector sortedOps, Constrained_vec, UnConstrained_vec, Pred_vec; set SeenBefore1, ITE_Added1; BuildBryantMaps(U, generator_map, X_generator_map, type_map, Pred_vec, P_terms, G_terms, P_term_map, G_term_map, SeenBefore1, ITE_Added1); bool proceed = false; for (T_generator_map::iterator i = generator_map.begin(); i != generator_map.end(); i++) if ((*i).second->begin()->isTerm()) { int count = 0; for (set::iterator j = (*i).second->begin(); j != (*i).second->end(); j++) count++; if (count <= LIMIT) proceed = true; instance_map.insert(pair((*i).first, count)); } if (!proceed) return d_core->reflexivityRule(T); GetOrdering(X_generator_map, G_term_map, P_term_map); name_map = BryantNames(generator_map, type_map); set SeenBefore2; GetSortedOpVec(X_generator_map, X_term_map, P_term_map, P_terms, G_terms, X_terms, sortedOps, SeenBefore2); set SeenBefore3, ITE_added3; GetOrderedTerms(instance_map, name_map, X_term_map, ITE_vec, G_terms, X_terms, Pred_vec, sortedOps, Constrained_vec, UnConstrained_vec, Constrained_set, UnConstrained_set, G_term_map, P_term_map, SeenBefore3, ITE_added3); //PredicateEliminator(U, Pred_vec, UnConstrained_Pred_set, name_map, ITE_map, Constrained_set); Get_ITEs(instance_map, Not_replaced_set, P_term_map, ITE_vec, Creation_map, name_map, ITE_map); set SeenBefore4; GetPEqs(U, name_map, P_constrained_set, Constrained_set, Constrained_map, SeenBefore4); PredConstrainTester(Not_replaced_set, U, name_map, Pred_vec, Constrained_set, P_constrained_set, Constrained_map); Expr Constraints = ConstrainedConstraints(Not_replaced_set, Constrained_map, name_map, Creation_map, Constrained_set, UnConstrained_set, P_constrained_set); // Constraints.pprintnodag(); vector< Expr > Old; vector< Expr > New; set SeenBefore6; RemoveFunctionApps(U, Not_replaced_set, Old, New, ITE_map, SeenBefore6); Expr Result = U.substExpr(Old, New); Expr Final = Constraints.impExpr(Result); Final = Final.notExpr(); B_Term_Map_Deleter(Creation_map); B_Term_Map_Deleter(X_generator_map); B_Term_Map_Deleter(X_term_map); B_Term_Map_Deleter(G_term_map); T_generator_Map_Deleter(Constrained_map); T_generator_Map_Deleter(generator_map); return d_rules->dummyTheorem(T.iffExpr(Final)); } cvc3-2.4.1/src/theory_core/theory.cpp0000664000175400017540000006352711424613255017425 0ustar mdetersmdeters/*****************************************************************************/ /*! * \file theory.cpp * * Author: Clark Barrett * * Created: Thu Jan 30 15:11:55 2003 * *
* * License to use, copy, modify, sell and/or distribute this software * and its documentation for any purpose is hereby granted without * royalty, subject to the terms and conditions defined in the \ref * LICENSE file provided with this distribution. * *
* */ /*****************************************************************************/ #include "theory_core.h" #include "common_proof_rules.h" #include "typecheck_exception.h" #include "theorem_manager.h" #include "command_line_flags.h" using namespace CVC3; using namespace std; Theory::Theory(void) : d_theoryCore(NULL) { } Theory::Theory(TheoryCore* theoryCore, const string& name) : d_em(theoryCore->getEM()), d_theoryCore(theoryCore), d_commonRules(theoryCore->getTM()->getRules()), d_name(name), d_theoryUsed(false) { } Theory::~Theory(void) { } void Theory::computeModelTerm(const Expr& e, vector& v) { TRACE("model", "Theory::computeModelTerm(", e, "): is a variable"); // v.push_back(e); } Theorem Theory::simplifyOp(const Expr& e) { int ar = e.arity(); if (ar > 0) { if (ar == 1) { Theorem res = d_theoryCore->simplify(e[0]); if (!res.isRefl()) { return d_commonRules->substitutivityRule(e, res); } } else { vector newChildrenThm; vector changed; for(int k = 0; k < ar; ++k) { // Recursively simplify the kids Theorem thm = d_theoryCore->simplify(e[k]); if (!thm.isRefl()) { newChildrenThm.push_back(thm); changed.push_back(k); } } if(changed.size() > 0) return d_commonRules->substitutivityRule(e, changed, newChildrenThm); } } return reflexivityRule(e); } Expr Theory::computeTCC(const Expr& e) { vector kids; for(Expr::iterator i=e.begin(), iend=e.end(); i!=iend; ++i) kids.push_back(getTCC(*i)); return (kids.size() == 0) ? trueExpr() : (kids.size() == 1) ? kids[0] : d_commonRules->rewriteAnd(andExpr(kids)).getRHS(); } void Theory::registerAtom(const Expr& e, const Theorem& thm) { d_theoryCore->registerAtom(e, thm); } bool Theory::inconsistent() { return d_theoryCore->inconsistent(); } void Theory::setInconsistent(const Theorem& e) { // TRACE("facts assertFact", ("setInconsistent[" + getName() + "->]("), e, ")"); // TRACE("conflict", ("setInconsistent[" + getName() + "->]("), e, ")"); IF_DEBUG(debugger.counter("conflicts from DPs")++;) d_theoryCore->setInconsistent(e); } void Theory::setIncomplete(const string& reason) { // TRACE("facts assertFact", "setIncomplete["+getName()+"](", reason, ")"); d_theoryCore->setIncomplete(reason); } Theorem Theory::simplify(const Expr& e) { // TRACE("simplify", ("simplify[" + getName() + "->]("), e, ") {"); Theorem res(d_theoryCore->simplify(e)); // TRACE("simplify", "simplify[" + getName() + "] => ", res, "}"); return res; } void Theory::enqueueFact(const Theorem& e) { // TRACE("facts assertFact", ("enqueueFact[" + getName() + "->]("), e, ")"); d_theoryCore->enqueueFact(e); } void Theory::enqueueSE(const Theorem& e) { // TRACE("facts assertFact", ("enqueueFact[" + getName() + "->]("), e, ")"); d_theoryCore->enqueueSE(e); } void Theory::assertEqualities(const Theorem& e) { d_theoryCore->assertEqualities(e); } void Theory::addSplitter(const Expr& e, int priority) { TRACE("facts assertFact", "addSplitter[" + getName() + "->](", e, ", pri="+int2string(priority)+")"); // DebugAssert(simplifyExpr(e) == e, "Expected splitter to be simplified"); DebugAssert(e.isAbsLiteral() && !e.isBoolConst(), "Expected literal"); d_theoryCore->d_coreSatAPI->addSplitter(e, priority); } void Theory::addGlobalLemma(const Theorem& thm, int priority) { d_theoryCore->d_coreSatAPI->addLemma(thm, priority, true); } void Theory::assignValue(const Expr& t, const Expr& val) { TRACE("facts assertFact", "assignValue["+getName()+"](", t, ", "+ val.toString()+") {"); d_theoryCore->assignValue(t, val); TRACE("facts assertFact", "assignValue[", getName(), "] => }"); } void Theory::assignValue(const Theorem& thm) { TRACE("facts assertFact", "assignValue["+getName()+"](", thm, ") {"); d_theoryCore->assignValue(thm); TRACE("facts assertFact", "assignValue[", getName(), "] => }"); } void Theory::registerKinds(Theory* theory, vector& kinds) { vector::const_iterator k; vector::const_iterator kEnd; for (k = kinds.begin(), kEnd = kinds.end(); k != kEnd; ++k) { DebugAssert(d_theoryCore->d_theoryMap.count(*k) == 0, "kind already registered: "+getEM()->getKindName(*k) +" = "+int2string(*k)); d_theoryCore->d_theoryMap[*k] = theory; } } void Theory::unregisterKinds(Theory* theory, vector& kinds) { vector::const_iterator k; vector::const_iterator kEnd; for (k = kinds.begin(), kEnd = kinds.end(); k != kEnd; ++k) { DebugAssert(d_theoryCore->d_theoryMap[*k] == theory, "kind not registered: "+getEM()->getKindName(*k) +" = "+int2string(*k)); d_theoryCore->d_theoryMap.erase(*k); } } void Theory::registerTheory(Theory* theory, vector& kinds, bool hasSolver) { registerKinds(theory, kinds); unsigned i = 0; for (; i < d_theoryCore->d_theories.size(); ++i) { if (d_theoryCore->d_theories[i] == NULL) { d_theoryCore->d_theories[i] = theory; break; } } if (i == d_theoryCore->d_theories.size()) { d_theoryCore->d_theories.push_back(theory); } if (hasSolver) { DebugAssert(!d_theoryCore->d_solver,"Solver already registered"); d_theoryCore->d_solver = theory; } } void Theory::unregisterTheory(Theory* theory, vector& kinds, bool hasSolver) { unregisterKinds(theory, kinds); unsigned i = 0; for (; i < d_theoryCore->d_theories.size(); ++i) { if (d_theoryCore->d_theories[i] == theory) { d_theoryCore->d_theories[i] = NULL; } } if (hasSolver) { DebugAssert(d_theoryCore->d_solver == theory, "Solver not registered"); d_theoryCore->d_solver = NULL; } } int Theory::getNumTheories() { return d_theoryCore->d_theories.size(); } bool Theory::hasTheory(int kind) { return (d_theoryCore->d_theoryMap.count(kind) > 0); } Theory* Theory::theoryOf(int kind) { DebugAssert(d_theoryCore->d_theoryMap.count(kind) > 0, "Unknown operator: " + getEM()->getKindName(kind)); return d_theoryCore->d_theoryMap[kind]; } Theory* Theory::theoryOf(const Type& e) { const Expr& typeExpr = getBaseType(e).getExpr(); DebugAssert(!typeExpr.isNull(),"Null type"); int kind = typeExpr.getOpKind(); DebugAssert(d_theoryCore->d_theoryMap.count(kind) > 0, "Unknown operator: " + getEM()->getKindName(kind)); return d_theoryCore->d_theoryMap[kind]; } Theory* Theory::theoryOf(const Expr& e) { Expr e2(e); while (e2.isNot() || e2.isEq()) { e2 = e2[0]; } if (e2.isApply()) { return d_theoryCore->d_theoryMap[e2.getOpKind()]; } if (!e2.isVar()) { return d_theoryCore->d_theoryMap[e2.getKind()]; } // Theory of a var is determined by its *base* type, since SUBTYPE // may have different base types, but SUBTYPE itself belongs to // TheoryCore. const Expr& typeExpr = getBaseType(e2).getExpr(); DebugAssert(!typeExpr.isNull(),"Null type"); int kind = typeExpr.getOpKind(); DebugAssert(d_theoryCore->d_theoryMap.count(kind) > 0, "Unknown operator: " + getEM()->getKindName(kind)); return d_theoryCore->d_theoryMap[kind]; } const Theorem& Theory::findRef(const Expr& e) { DebugAssert(e.hasFind(), "expected find"); const Theorem& thm1 = e.getFind(); if (thm1.isRefl()) return thm1; const Expr& e1 = thm1.getRHS(); if (!e1.hasFind() || e1.getFind().getRHS() == e1) return thm1; const Theorem& thm2 = findRef(e1); DebugAssert(thm2.getLHS()==e1,""); DebugAssert(thm2.getLHS() != thm2.getRHS(),""); e.setFind(transitivityRule(thm1,thm2)); return e.getFind(); } Theorem Theory::find(const Expr& e) { if (!e.hasFind()) return reflexivityRule(e); const Theorem& thm1 = e.getFind(); if (thm1.isRefl()) return thm1; const Expr& e1 = thm1.getRHS(); if (e1 == e || !e1.hasFind() || e1.getFind().getRHS() == e1) return thm1; Theorem thm2 = find(e1); DebugAssert(thm2.getLHS()==e1,""); DebugAssert(thm2.getLHS() != thm2.getRHS(),""); thm2 = transitivityRule(thm1,thm2); e.setFind(thm2); return thm2; } Theorem Theory::findReduce(const Expr& e) { if (e.hasFind()) return find(e); int ar = e.arity(); if (ar > 0) { if (ar == 1) { Theorem res = findReduce(e[0]); if (!res.isRefl()) { return d_commonRules->substitutivityRule(e, res); } } else { vector newChildrenThm; vector changed; for(int k = 0; k < ar; ++k) { // Recursively reduce the kids Theorem thm = findReduce(e[k]); if (!thm.isRefl()) { newChildrenThm.push_back(thm); changed.push_back(k); } } if(changed.size() > 0) return d_commonRules->substitutivityRule(e, changed, newChildrenThm); } } return reflexivityRule(e); } bool Theory::findReduced(const Expr& e) { if (e.hasFind()) return e.getFind().getRHS() == e; for (Expr::iterator i = e.begin(), iend = e.end(); i != iend; ++i) if (!findReduced(*i)) return false; return true; } Expr Theory::getTCC(const Expr& e) { if(e.isVar()) return trueExpr(); ExprMap::iterator itccCache = d_theoryCore->d_tccCache.find(e); if (itccCache != d_theoryCore->d_tccCache.end()) { return (*itccCache).second; } Theory* i = theoryOf(e.getKind()); TRACE("tccs", "computeTCC["+i->getName()+"](", e, ") {"); Expr tcc = i->computeTCC(e); d_theoryCore->d_tccCache[e] = tcc; TRACE("tccs", "computeTCC["+i->getName()+"] => ", tcc, " }"); return tcc; } Type Theory::getBaseType(const Expr& e) { return getBaseType(e.getType()); } Type Theory::getBaseType(const Type& tp) { const Expr& e = tp.getExpr(); DebugAssert(!e.isNull(), "Theory::getBaseType(Type(Null))"); // See if we have it cached Type res(e.lookupType()); if(!res.isNull()) return res; DebugAssert(theoryOf(e) != NULL, "Theory::getBaseType(): No theory for the type: " +tp.toString()); res= theoryOf(e)->computeBaseType(tp); e.setType(res); return res; } Expr Theory::getTypePred(const Type& t, const Expr& e) { Expr pred; Theory *i = theoryOf(t.getExpr().getKind()); // TRACE("typePred", "computeTypePred["+i->getName()+"]("+t.toString()+", ", e, ") {"); pred = i->computeTypePred(t, e); // TRACE("typePred", "computeTypePred["+i->getName()+"] => ", pred, " }"); return pred; } Theorem Theory::updateHelper(const Expr& e) { int ar = e.arity(); switch (ar) { case 0: break; case 1: { const Theorem& res = findRef(e[0]); if (res.getLHS() != res.getRHS()) { return d_commonRules->substitutivityRule(e, res); } break; } case 2: { const Theorem thm0 = findRef(e[0]); const Theorem thm1 = findRef(e[1]); if (thm0.getLHS() != thm0.getRHS() || thm1.getLHS() != thm1.getRHS()) { return d_commonRules->substitutivityRule(e, thm0, thm1); } break; } default: { vector newChildrenThm; vector changed; for (int k = 0; k < ar; ++k) { const Theorem& thm = findRef(e[k]); if (thm.getLHS() != thm.getRHS()) { newChildrenThm.push_back(thm); changed.push_back(k); } } if (changed.size() > 0) return d_commonRules->substitutivityRule(e, changed, newChildrenThm); break; } } return reflexivityRule(e); } //! Setup a term for congruence closure (must have sig and rep attributes) void Theory::setupCC(const Expr& e) { // TRACE("facts setup", "setupCC["+getName()+"](", e, ") {"); for (int k = 0; k < e.arity(); ++k) { e[k].addToNotify(this, e); } Theorem thm = reflexivityRule(e); e.setSig(thm); e.setRep(thm); e.setUsesCC(); // TRACE_MSG("facts setup", "setupCC["+getName()+"]() => }"); } //! Update a term w.r.t. congruence closure (must be setup with setupCC()) void Theory::updateCC(const Theorem& e, const Expr& d) { // TRACE("facts update", "updateCC["+getName()+"]("+e.getExpr().toString()+", ", // d, ") {"); int k, ar(d.arity()); const Theorem& dEQdsig = d.getSig(); if (!dEQdsig.isNull()) { const Expr& dsig = dEQdsig.getRHS(); Theorem thm = updateHelper(d); const Expr& sigNew = thm.getRHS(); if (sigNew == dsig) { // TRACE_MSG("facts update", "updateCC["+getName()+"]() [no change] => }"); return; } dsig.setRep(Theorem()); const Theorem& repEQsigNew = sigNew.getRep(); if (!repEQsigNew.isNull()) { d.setSig(Theorem()); enqueueFact(transitivityRule(repEQsigNew, symmetryRule(thm))); } else if (d.getType().isBool()) { d.setSig(Theorem()); enqueueFact(thm); } else { for (k = 0; k < ar; ++k) { if (sigNew[k] != dsig[k]) { sigNew[k].addToNotify(this, d); } } d.setSig(thm); sigNew.setRep(thm); getEM()->invalidateSimpCache(); } } // TRACE_MSG("facts update", "updateCC["+getName()+"]() => }"); } //! Rewrite a term w.r.t. congruence closure (must be setup with setupCC()) Theorem Theory::rewriteCC(const Expr& e) { const Theorem& rep = e.getRep(); if (rep.isNull()) return reflexivityRule(e); else return symmetryRule(rep); } Expr Theory::parseExpr(const Expr& e) { // TRACE("facts parseExpr", "parseExpr(", e, ") {"); Expr res(d_theoryCore->parseExpr(e)); // TRACE("facts parseExpr", "parseExpr => ", res, " }"); return res; } void Theory::getModelTerm(const Expr& e, vector& v) { Theory *i = theoryOf(getBaseType(e).getExpr()); TRACE("model", "computeModelTerm["+i->getName()+"](", e, ") {"); IF_DEBUG(unsigned size = v.size();) i->computeModelTerm(e, v); TRACE("model", "computeModelTerm[", i->getName(), "] => }"); DebugAssert(v.size() <= size || v.back() != e, "Primitive var was pushed on " "the stack in computeModelTerm["+i->getName() +"]: "+e.toString()); } Theorem Theory::getModelValue(const Expr& e) { return d_theoryCore->getModelValue(e); } bool Theory::isLeafIn(const Expr& e1, const Expr& e2) { DebugAssert(isLeaf(e1),"Expected leaf"); if (e1 == e2) return true; if (theoryOf(e2) != this) return false; for(Expr::iterator i=e2.begin(), iend=e2.end(); i != iend; ++i) if (isLeafIn(e1, *i)) return true; return false; } bool Theory::leavesAreSimp(const Expr& e) { if (isLeaf(e)) { return !e.hasFind() || e.getFind().getRHS() == e; } for (int k = 0; k < e.arity(); ++k) { if (!leavesAreSimp(e[k])) return false; } return true; } Expr Theory::newVar(const string& name, const Type& type) { DebugAssert(!type.isNull(), "Error: defining a variable of NULL type"); Expr res = resolveID(name); Type t; // Expr res = lookupVar(name, &t); if (!res.isNull()) { t = res.getType(); if (t != type) { throw TypecheckException ("incompatible redefinition of variable "+name+":\n " "already defined with type: "+t.toString() +"\n the new type is: "+type.toString()); } return res; } // Replace TYPEDEF with its definition t = type; while(t.getExpr().getKind() == TYPEDEF) { DebugAssert(t.arity() == 2, "Bad TYPEDEF: "+t.toString()); t = t[1]; } if (type.isBool()) res = d_em->newSymbolExpr(name, UCONST); else res = getEM()->newVarExpr(name); // Add the variable for constructing a concrete model d_theoryCore->addToVarDB(res); // Add the new global declaration installID(name, res); if( type.isFunction() ) { throw Exception("newVar: expected non-function type"); } if( !res.lookupType().isNull() ) { throw Exception("newVarExpr: redefining a variable " + name); } res.setType(type); return res; } Expr Theory::newVar(const string& name, const Type& type, const Expr& def) { DebugAssert(!type.isNull(), "Error: defining a variable of NULL type"); Type t; Expr res = resolveID(name); if (!res.isNull()) { throw TypecheckException ("Redefinition of variable "+name+":\n " "This variable is already defined."); } Expr v; // Replace TYPEDEF with its definition t = type; while(t.getExpr().getKind() == TYPEDEF) { DebugAssert(t.arity() == 2, "Bad TYPEDEF: "+t.toString()); t = t[1]; } // Typecheck if(getBaseType(def) != getBaseType(t)) { throw TypecheckException("Type mismatch in constant definition:\n" "Constant "+name+ " is declared with type:\n " +t.toString() +"\nBut the type of definition is\n " +def.getType().toString()); } DebugAssert(t.getExpr().getKind() != ARROW,""); // Add the new global declaration installID(name, def); return def; } Op Theory::newFunction(const string& name, const Type& type, bool computeTransClosure) { DebugAssert(!type.isNull(), "Error: defining a variable of NULL type"); Expr res = resolveID(name); Type t; if (!res.isNull()) { t = res.getType(); throw TypecheckException ("Redefinition of variable "+name+":\n " "already defined with type: "+t.toString() +"\n the new type is: "+type.toString()); } res = getEM()->newSymbolExpr(name, UFUNC); // Replace TYPEDEF with its definition t = type; while(t.getExpr().getKind() == TYPEDEF) { DebugAssert(t.arity() == 2, "Bad TYPEDEF: "+t.toString()); t = t[1]; } res.setType(t); // Add it to the database of variables for concrete model generation d_theoryCore->addToVarDB(res); // Add the new global declaration installID(name, res); if (computeTransClosure && t.isFunction() && t.arity() == 3 && t[2].isBool()) res.setComputeTransClosure(); return res.mkOp(); } Op Theory::newFunction(const string& name, const Type& type, const Expr& def) { DebugAssert(!type.isNull(), "Error: defining a variable of NULL type"); Expr res = resolveID(name); Type t; if (!res.isNull()) { t = res.getType(); throw TypecheckException ("Redefinition of name "+name+":\n " "already defined with type: "+t.toString() +"\n the new type is: "+type.toString()); } // Add the new global declaration installID(name, def); return def.mkOp(); } Op Theory::lookupFunction(const string& name, Type* type) { Expr e = getEM()->newSymbolExpr(name, UFUNC); *type = e.lookupType(); if ((*type).isNull()) return Op(); return e.mkOp(); } static int boundVarCount = 0; Expr Theory::addBoundVar(const string& name, const Type& type) { ostringstream ss; ss << boundVarCount++; Expr v(getEM()->newBoundVarExpr(name, ss.str(), type)); if (d_theoryCore->d_boundVarStack.size() == 0) { DebugAssert(d_theoryCore->d_parseCache == &d_theoryCore->d_parseCacheTop, "Parse cache invariant violated"); d_theoryCore->d_parseCache = &d_theoryCore->d_parseCacheOther; DebugAssert(d_theoryCore->d_parseCache->empty(), "Expected empty cache"); } else { DebugAssert(d_theoryCore->d_parseCache == &d_theoryCore->d_parseCacheOther, "Parse cache invariant violated 2"); d_theoryCore->d_parseCache->clear(); } d_theoryCore->d_boundVarStack.push_back(pair(name,v)); DebugAssert(v.getKind() != RAW_LIST, "Bound vars cannot be bound to RAW_LIST"); hash_map::iterator iBoundVarMap = d_theoryCore->d_boundVarMap.find(name); if (iBoundVarMap != d_theoryCore->d_boundVarMap.end()) { (*iBoundVarMap).second = Expr(RAW_LIST, v, (*iBoundVarMap).second); } else d_theoryCore->d_boundVarMap[name] = v; TRACE("vars", "addBoundVar("+name+", ", type, ") => "+v.toString()); return v; } Expr Theory::addBoundVar(const string& name, const Type& type, const Expr& def) { Expr res; // Without the type, just replace the bound variable with the definition if(type.isNull()) res = def; else { // When type is given, construct (LETDECL var, def) for the typechecker ostringstream ss; ss << boundVarCount++; res = Expr(LETDECL, getEM()->newBoundVarExpr(name, ss.str(), type), def); } if (d_theoryCore->d_boundVarStack.size() == 0) { DebugAssert(d_theoryCore->d_parseCache == &d_theoryCore->d_parseCacheTop, "Parse cache invariant violated"); d_theoryCore->d_parseCache = &d_theoryCore->d_parseCacheOther; DebugAssert(d_theoryCore->d_parseCache->empty(), "Expected empty cache"); } else { DebugAssert(d_theoryCore->d_parseCache == &d_theoryCore->d_parseCacheOther, "Parse cache invariant violated 2"); d_theoryCore->d_parseCache->clear(); } d_theoryCore->d_boundVarStack.push_back(pair(name,res)); DebugAssert(res.getKind() != RAW_LIST, "Bound vars cannot be bound to RAW_LIST"); hash_map::iterator iBoundVarMap = d_theoryCore->d_boundVarMap.find(name); if (iBoundVarMap != d_theoryCore->d_boundVarMap.end()) { (*iBoundVarMap).second = Expr(RAW_LIST, res, (*iBoundVarMap).second); } else d_theoryCore->d_boundVarMap[name] = res; TRACE("vars", "addBoundVar("+name+", "+type.toString()+", ", def, ") => "+res.toString()); return res; } Expr Theory::lookupVar(const string& name, Type* type) { Expr e = getEM()->newVarExpr(name); *type = e.lookupType(); // if ((*type).isNull()) { // e = newApplyExpr(Op(UFUNC, e)); // *type = e.lookupType(); if ((*type).isNull()) return Expr(); // } return e; } // TODO: reconcile this with parser-driven new type expressions Type Theory::newTypeExpr(const string& name) { Expr res = resolveID(name); if (!res.isNull()) { throw TypecheckException ("Redefinition of type variable "+name+":\n " "This variable is already defined."); } res = Expr(TYPEDECL, getEM()->newStringExpr(name)); // Add the new global declaration installID(name, res); return Type(res); } Type Theory::lookupTypeExpr(const string& name) { Expr res = resolveID(name); if (res.isNull() || (res.getKind() != TYPEDECL && !res.isType())) { return Type(); } return Type(res); } Type Theory::newSubtypeExpr(const Expr& pred, const Expr& witness) { Type predTp(pred.getType()); if(!predTp.isFunction() || predTp.arity() != 2) throw TypecheckException ("Expected unary predicate in the predicate subtype:\n\n " +predTp.toString() +"\n\nThe predicate is:\n\n " +pred.toString()); if(!predTp[1].isBool()) throw TypecheckException ("Range is not BOOLEAN in the predicate subtype:\n\n " +predTp.toString() +"\n\nThe predicate is:\n\n " +pred.toString()); Expr p(simplifyExpr(pred)); // Make sure that the supplied predicate is total: construct // // FORALL (x: domType): getTCC(pred(x)) // // This only needs to be done for LAMBDA-expressions, since // uninterpreted predicates are defined for all the arguments // of correct (exact) types. if (pred.isLambda() && d_theoryCore->getFlags()["tcc"].getBool()) { Expr quant = d_em->newClosureExpr(FORALL, p.getVars(), d_theoryCore->getTCC(p.getBody())); if (!d_theoryCore->d_coreSatAPI->check(quant)) { throw TypecheckException ("Subtype predicate could not be proved total in the following type:\n\n " +Expr(SUBTYPE, p).toString() +"\n\nThe failed TCC is:\n\n " +quant.toString()); } } // We require that there exists an object of this type (otherwise there is an inherent inconsistency) Expr q; if (witness.isNull()) { vector vec; vec.push_back(d_em->newBoundVarExpr(predTp[0])); q = d_em->newClosureExpr(EXISTS, vec, simplifyExpr(Expr(pred.mkOp(), vec.back()))); } else { q = Expr(pred.mkOp(), witness); } if (!d_theoryCore->d_coreSatAPI->check(q)) { throw TypecheckException ("Unable to prove witness for subtype:\n\n " +Expr(SUBTYPE, p).toString() +"\n\nThe failed condition is:\n\n " +q.toString()); } return Type(Expr(SUBTYPE, p)); } //! Create a new type abbreviation with the given name Type Theory::newTypeExpr(const string& name, const Type& def) { Expr res = resolveID(name); if (!res.isNull()) { throw TypecheckException ("Redefinition of type variable "+name+":\n " "This variable is already defined."); } res = def.getExpr(); // Add the new global declaration installID(name, res); return Type(res); } Expr Theory::resolveID(const string& name) { // TRACE("vars", "resolveID(", name, ") {"); Expr res; // Result is Null by default // First, look up the bound variable stack hash_map::iterator iBoundVarMap = d_theoryCore->d_boundVarMap.find(name); if (iBoundVarMap != d_theoryCore->d_boundVarMap.end()) { res = (*iBoundVarMap).second; if (res.getKind() == RAW_LIST) { res = res[0]; } } else { // Next, check in the globals map::iterator i=d_theoryCore->d_globals.find(name), iend=d_theoryCore->d_globals.end(); if(i!=iend) res = i->second; } // TRACE("vars", "resolveID => ", res, " }"); return res; } void Theory::installID(const string& name, const Expr& e) { DebugAssert(resolveID(name).isNull(), "installID called on existing identifier"); d_theoryCore->d_globals[name] = e; } Theorem Theory::typePred(const Expr& e) { return d_theoryCore->typePred(e); } Theorem Theory::rewriteIte(const Expr& e) { if (e[0].isTrue()) return d_commonRules->rewriteIteTrue(e); if (e[0].isFalse()) return d_commonRules->rewriteIteFalse(e); if (e[1] == e[2]) return d_commonRules->rewriteIteSame(e); return reflexivityRule(e); } Theorem Theory::renameExpr(const Expr& e) { Theorem thm = d_commonRules->varIntroSkolem(e); DebugAssert(thm.isRewrite() && thm.getRHS().isSkolem(), "thm = "+thm.toString()); d_theoryCore->addToVarDB(thm.getRHS()); return thm; } cvc3-2.4.1/src/theory_core/core_proof_rules.h0000664000175400017540000001105211146605674021120 0ustar mdetersmdeters/*****************************************************************************/ /*! *\file core_proof_rules.h *\brief Proof rules used by theory_core * * Author: Clark Barrett * * Created: Wed Jan 11 15:48:35 2006 * *
* * License to use, copy, modify, sell and/or distribute this software * and its documentation for any purpose is hereby granted without * royalty, subject to the terms and conditions defined in the \ref * LICENSE file provided with this distribution. * *
* */ /*****************************************************************************/ #ifndef _cvc3__core_proof_rules_h_ #define _cvc3__core_proof_rules_h_ #include namespace CVC3 { class Theorem; class Theorem3; class Expr; class Op; class CoreProofRules { public: //! Destructor virtual ~CoreProofRules() { } //! e: T ==> |- typePred_T(e) [deriving the type predicate of e] virtual Theorem typePred(const Expr& e) = 0; //////////////////////////////////////////////////////////////////////// // Core rewrite rules //////////////////////////////////////////////////////////////////////// //! Replace LETDECL with its definition /*! Used only in TheoryCore */ virtual Theorem rewriteLetDecl(const Expr& e) = 0; //! ==> NOT (AND e1 ... en) IFF (OR !e1 ... !en), takes (AND ...) virtual Theorem rewriteNotAnd(const Expr& e) = 0; //! ==> NOT (OR e1 ... en) IFF (AND !e1 ... !en), takes (OR ...) virtual Theorem rewriteNotOr(const Expr& e) = 0; //! ==> NOT IFF(e1,e2) IFF IFF(e1,NOT e2) virtual Theorem rewriteNotIff(const Expr& e) = 0; //! ==> NOT ITE(a,b,c) IFF ITE(a,NOT b,NOT c) virtual Theorem rewriteNotIte(const Expr& e) = 0; //! a |- b == d ==> ITE(a, b, c) == ITE(a, d, c) virtual Theorem rewriteIteThen(const Expr& e, const Theorem& thenThm) = 0; //! !a |- c == d ==> ITE(a, b, c) == ITE(a, b, d) virtual Theorem rewriteIteElse(const Expr& e, const Theorem& elseThm) = 0; //! ==> ITE(c, e1, e2) <=> (c => e1) AND (!c => e2) virtual Theorem rewriteIteBool(const Expr& c, const Expr& e1, const Expr& e2) = 0; //! |= (A & B1) | (A & B2) | ... | (A & bn) <=> A & (B1 | B2 | ...| Bn) virtual Theorem orDistributivityRule(const Expr& e) = 0; //! |= (A | B1) & (A | B2) & ... & (A | bn) <=> A | (B1 & B2 & ...& Bn) virtual Theorem andDistributivityRule(const Expr& e) = 0; //! ==> IMPLIES(e1,e2) IFF OR(!e1, e2) virtual Theorem rewriteImplies(const Expr& e) = 0; //! ==> DISTINCT(e1,...,en) IFF AND 1 <= i < j <= n (e[i] /= e[j]) virtual Theorem rewriteDistinct(const Expr& e) = 0; //! ==> NOT(e) == ITE(e, FALSE, TRUE) virtual Theorem NotToIte(const Expr& not_e) = 0; //! ==> Or(e) == ITE(e[1], TRUE, e[0]) virtual Theorem OrToIte(const Expr& e) = 0; //! ==> And(e) == ITE(e[1], e[0], FALSE) virtual Theorem AndToIte(const Expr& e) = 0; //! ==> IFF(a,b) == ITE(a, b, !b) virtual Theorem IffToIte(const Expr& e) = 0; //! ==> IMPLIES(a,b) == ITE(a, b, TRUE) virtual Theorem ImpToIte(const Expr& e) = 0; //! ==> ITE(e, FALSE, TRUE) IFF NOT(e) virtual Theorem rewriteIteToNot(const Expr& e) = 0; //! ==> ITE(a, TRUE, b) IFF OR(a, b) virtual Theorem rewriteIteToOr(const Expr& e) = 0; //! ==> ITE(a, b, FALSE) IFF AND(a, b) virtual Theorem rewriteIteToAnd(const Expr& e) = 0; //! ==> ITE(a, b, !b) IFF IFF(a, b) virtual Theorem rewriteIteToIff(const Expr& e) = 0; //! ==> ITE(a, b, TRUE) IFF IMPLIES(a, b) virtual Theorem rewriteIteToImp(const Expr& e) = 0; //! ==> ITE(a, b(a), c(a)) IFF ITE(a, b(TRUE), c(FALSE)) virtual Theorem rewriteIteCond(const Expr& e) = 0; //! |- op(ITE(cond,a,b)) =/<=> ITE(cond,op(a),op(b)) virtual Theorem ifLiftUnaryRule(const Expr& e) = 0; //! ((a|b)<=>(a|c))<=>(a|(b<=>c)); takes ((a|b)<=>(a|c)) as 'iff' virtual Theorem iffOrDistrib(const Expr& iff) = 0; //! ((a&b)<=>(a&c))<=>(!a|(b<=>c)); takes ((a&b)<=>(a&c)) as 'iff' virtual Theorem iffAndDistrib(const Expr& iff) = 0; // Advanced Boolean transformations //! (a & b) <=> a & b[a/true]; takes the index of a /*! and rewrites all the other conjuncts. */ virtual Theorem rewriteAndSubterms(const Expr& e, int idx) = 0; //! (a | b) <=> a | b[a/false]; takes the index of a /*! and rewrites all the other disjuncts. */ virtual Theorem rewriteOrSubterms(const Expr& e, int idx) = 0; //! Temporary cheat for building theorems virtual Theorem dummyTheorem(const Expr& e) = 0; }; // end of class CoreProofRules } // end of namespace CVC3 #endif cvc3-2.4.1/src/vcl/0000775000175400017540000000000011630011320013614 5ustar mdetersmdeterscvc3-2.4.1/src/vcl/Makefile0000664000175400017540000000037710533133656015305 0ustar mdetersmdeters################################################## # About this Makefile # # This Makefile depends on Makefile.opts ################################################## MODULE = vcl SRC = vcl.cpp vc_cmd.cpp LIBRARY=libvcl.a include ../../Makefile.local cvc3-2.4.1/src/vcl/vc_cmd.cpp0000644000175400017540000007071111624746725015612 0ustar mdetersmdeters/*****************************************************************************/ /*! * \file vc_cmd.cpp * * Author: Clark Barrett * * Created: Fri Dec 13 22:39:02 2002 * *
* License to use, copy, modify, sell and/or distribute this software * and its documentation for any purpose is hereby granted without * royalty, subject to the terms and conditions defined in the \ref * LICENSE file provided with this distribution. * *
* */ /*****************************************************************************/ #include #include "vc_cmd.h" #include "vc.h" #include "parser.h" #include "eval_exception.h" #include "typecheck_exception.h" #include "command_line_flags.h" #include "expr_stream.h" using namespace std; using namespace CVC3; VCCmd::VCCmd(ValidityChecker* vc, Parser* parser, bool calledFromParser) : d_vc(vc), d_parser(parser), d_name_of_cur_ctxt("DEFAULT"), d_calledFromParser(calledFromParser) { d_map[d_name_of_cur_ctxt.c_str()] = d_vc->getCurrentContext(); } VCCmd::~VCCmd() { } void VCCmd::findAxioms(const Expr& e, ExprMap& skolemAxioms, ExprMap& visited) { if(visited.count(e)>0) return; else visited[e] = true; if(e.isSkolem()) { skolemAxioms.insert(e.getExistential(), true); return; } if(e.isClosure()) { findAxioms(e.getBody(), skolemAxioms, visited); } if(e.arity()>0) { Expr::iterator end = e.end(); for(Expr::iterator i = e.begin(); i!=end; ++i) findAxioms(*i, skolemAxioms, visited); } } Expr VCCmd::skolemizeAx(const Expr& e) { vectorvars; const vectorboundVars = e.getVars(); for(unsigned int i=0; idone()) return false; // No more commands Expr e; try { TRACE_MSG("commands", "** [commands] Parsing command..."); e = d_parser->next(); TRACE("commands verbose", "evaluateNext(", e, ")"); } catch(Exception& e) { cerr << "*** " << e << endl; IF_DEBUG(++(debugger.counter("parse errors"));) } // The parser may return a Null Expr in case of parse errors or end // of file. The right thing to do is to ignore it and repeat // reading. if(e.isNull()) { TRACE_MSG("commands", "** [commands] Null command; read again"); goto readAgain; } if( d_vc->getFlags()["parse-only"].getBool() ) { TRACE_MSG("commands", "** [commands] parse-only; skipping evaluateCommand"); goto readAgain; } return evaluateCommand(e); } void VCCmd::reportResult(QueryResult qres, bool checkingValidity) { if (d_vc->getFlags()["printResults"].getBool()) { if (d_vc->getEM()->getOutputLang() == SMTLIB_LANG || d_vc->getEM()->getOutputLang() == SMTLIB_V2_LANG) { switch (qres) { case VALID: cout << "unsat" << endl; break; case INVALID: cout << "sat" << endl; break; case ABORT: case UNKNOWN: cout << "unknown" << endl; break; default: FatalAssert(false, "Unexpected case"); } } else { switch (qres) { case VALID: cout << (checkingValidity ? "Valid." : "Unsatisfiable.") << endl; break; case INVALID: cout << (checkingValidity ? "Invalid." : "Satisfiable.") << endl; break; case ABORT: cout << "Unknown: resource limit exhausted." << endl; break; case UNKNOWN: { // Vector of reasons in case of incomplete result vector reasons; IF_DEBUG(bool b =) d_vc->incomplete(reasons); DebugAssert(b, "Expected incompleteness"); cout << "Unknown.\n\n"; cout << "CVC3 was incomplete in this example due to:"; for(vector::iterator i=reasons.begin(), iend=reasons.end(); i!=iend; ++i) cout << "\n * " << (*i); cout << endl << endl; break; } default: FatalAssert(false, "Unexpected case"); } } cout << flush; } //d_vc->printStatistics(); // exit(0); } void VCCmd::printModel() { ExprMap m; d_vc->getConcreteModel(m); cout << "Current scope level is " << d_vc->scopeLevel() << "." << endl; ExprMap::iterator it = m.begin(), end = m.end(); if(it == end) cout << " Did not find concrete model for any vars" << endl; else { cout << "%Satisfiable Variable Assignment: % \n"; for(; it!= end; it++) { Expr eq; if(it->first.getType().isBool()) { DebugAssert((it->second).isBoolConst(), "Bad variable assignement: e = "+(it->first).toString() +"\n\n val = "+(it->second).toString()); if((it->second).isTrue()) eq = it->first; else eq = !(it->first); } else eq = (it->first).eqExpr(it->second); cout << Expr(ASSERT, eq) << "\n"; } } } // For debugging: there are missing cases: user-defined types, symbols inside of quantifiers, etc. void VCCmd::printSymbols(Expr e, ExprMap& cache) { if (cache.find(e) != cache.end()) return; switch (e.getKind()) { case SKOLEM_VAR: case UCONST: { cout << e << " : "; ExprStream os(d_vc->getEM()); os.dagFlag(false); os << e.getType().getExpr(); cout << ";" << endl; break; } case APPLY: { Expr op = e.getOpExpr(); if ((op.getKind() == UFUNC) && (cache.find(op) == cache.end())) { cout << op << " : "; ExprStream os(d_vc->getEM()); os.dagFlag(false); os << op.getType().getExpr(); cout << ";" << endl; cache[op] = true; } // fall through } default: { Expr::iterator i = e.begin(), iend = e.end(); for (; i != iend; ++i) { printSymbols(*i, cache); } break; } } cache[e] = true; } bool debug_skolem = false; void VCCmd::printCounterExample() { vector assertions; ExprMap skolemAxioms; ExprMap visited; d_vc->getCounterExample(assertions); // get variable information ExprMap cache; unsigned i; for (i = 0; i < assertions.size(); i++) { printSymbols(assertions[i], cache); } cout << "% Current scope level is " << d_vc->scopeLevel() << "." << endl; if (assertions.size() == 0) { cout << "% There are no assertions\n"; } else { cout << "% Assertions which make the QUERY invalid:\n"; for (i = 0; i < assertions.size(); i++) { cout << Expr(ASSERT, assertions[i]) << "\n"; findAxioms(assertions[i], skolemAxioms, visited); } if (debug_skolem) { cout << "% Including skolemization axioms:\n"; ExprMap::iterator end = skolemAxioms.end(); for(ExprMap::iterator it = skolemAxioms.begin(); it!=end; it++) cout << "ASSERT " << skolemizeAx((*it).first) << ";" << endl; } } cout << endl; } bool VCCmd::evaluateCommand(const Expr& e0) { TRACE("commands", "evaluateCommand(", e0.toString(PRESENTATION_LANG), ") {"); Expr e(e0); if(e.getKind() != RAW_LIST || e.arity() == 0 || e[0].getKind() != ID) throw EvalException("Invalid command: "+e.toString()); const string& kindName = e[0][0].getString(); int kind = d_vc->getEM()->getKind(kindName); if(kind == NULL_KIND) throw EvalException("Unknown command: "+e.toString()); switch(kind) { case CONST: { // (CONST (id_1 ... id_n) type) or (CONST id type) if(e.arity() == 3) { Type t(d_vc->parseExpr(e[2])); vector vars; if(e[1].getKind() == RAW_LIST) vars = e[1].getKids(); else vars.push_back(e[1]); for(vector::iterator i=vars.begin(), iend=vars.end(); i!=iend; ++i) { if((*i).getKind() != ID) throw EvalException("Constant name must be an identifier: " +i->toString()); } if (t.isFunction()) { for(vector::iterator i=vars.begin(), iend=vars.end(); i!=iend; ++i) { Op op = d_vc->createOp((*i)[0].getString(), t); TRACE("commands", "evaluateNext: declare new uninterpreted function: ", op, ""); } } else { for(vector::iterator i=vars.begin(), iend=vars.end(); i!=iend; ++i) { // Add to variable list Expr v = d_vc->varExpr((*i)[0].getString(), t); TRACE_MSG("commands", "** [commands] Declare new variable"); TRACE("commands verbose", "evaluateNext: declare new UCONST: ", v, ""); } } } else if(e.arity() == 4) { // Constant definition (CONST id type def) TRACE_MSG("commands", "** [commands] Define new constant"); // Set the type for later typechecking DebugAssert(e[1].getKind() == ID, "Expected ID kind"); Type t(d_vc->parseExpr(e[2])); Expr def(d_vc->parseExpr(e[3])); if(t.isFunction()) { d_vc->createOp(e[1][0].getString(), t, def); TRACE("commands verbose", "evaluateNext: define new function: ", e[1][0].getString(), ""); } else { d_vc->varExpr(e[1][0].getString(), t, def); TRACE("commands verbose", "evaluateNext: define new variable: ", e[1][0].getString(), ""); } } else throw EvalException("Wrong number of arguments in CONST: "+e.toString()); break; } case DEFUN: { // (DEFUN name ((x y z type1) ... ) resType [ body ]) if(e.arity() != 5 && e.arity() != 4) throw EvalException ("DEFUN requires 3 or 4 arguments:" " (DEFUN f (args) type [ body ]):\n\n " +e.toString()); if(e[2].getKind() != RAW_LIST) throw EvalException ("2nd argument of DEFUN must be a list of arguments:\n\n " +e.toString()); // Build a CONST declaration and parse it recursively // Build the function type vector argTps; for(Expr::iterator i=e[2].begin(), iend=e[2].end(); i!=iend; ++i) { if(i->getKind() != RAW_LIST || i->arity() < 2) throw EvalException ("DEFUN: bad argument declaration:\n\n "+i->toString() +"\n\nIn the following statement:\n\n " +e.toString()); Expr tp((*i)[i->arity()-1]); for(int j=0, jend=i->arity()-1; jlistExpr("ARROW", argTps); Expr newDecl; // The resulting transformed declaration if(e.arity() == 5) { // Build the LAMBDA expression Expr lambda(d_vc->listExpr("LAMBDA", e[2], e[4])); // Construct the (CONST name fnType lambda) declaration newDecl = d_vc->listExpr("CONST", e[1], fnType, lambda); } else { newDecl = d_vc->listExpr("CONST", e[1], fnType); } // Parse the new declaration return evaluateCommand(newDecl); break; } case TYPEDEF: { if (e.arity() == 2) { // Datatype command DebugAssert(e.arity() == 2, "Bad TYPEDEF"); Expr res = d_vc->parseExpr(e[1]); // convert res to vectors Expr eNames = res[0]; Expr eCons = res[1]; Expr eSel = res[2]; Expr eTypes = res[3]; vector names; vector > constructors(eNames.arity()); vector > > selectors(eNames.arity()); vector > > types(eNames.arity()); int i, j, k; for (i = 0; i < eNames.arity(); ++i) { names.push_back(eNames[i].getString()); selectors[i].resize(eSel[i].arity()); types[i].resize(eTypes[i].arity()); for (j = 0; j < eCons[i].arity(); ++j) { constructors[i].push_back(eCons[i][j].getString()); for (k = 0; k < eSel[i][j].arity(); ++k) { selectors[i][j].push_back(eSel[i][j][k].getString()); types[i][j].push_back(eTypes[i][j][k]); } } } vector returnTypes; d_vc->dataType(names, constructors, selectors, types, returnTypes); break; } DebugAssert(e.arity() == 3, "Bad TYPEDEF"); Expr def(d_vc->parseExpr(e[2])); Type t = d_vc->createType(e[1][0].getString(), def); TRACE("commands", "evaluateNext: declare new TYPEDEF: ", t, ""); } break; case TYPE: { if(e.arity() < 2) throw EvalException("Bad TYPE declaration: "+e.toString()); Expr::iterator i=e.begin(), iend=e.end(); ++i; // Skip "TYPE" symbol for(; i!=iend; ++i) { if(i->getKind() != ID) throw EvalException("Type name must be an identifier: "+i->toString()); Type t = d_vc->createType((*i)[0].getString()); TRACE("commands", "evaluateNext: declare new TYPEDECL: ", t, ""); } } break; case ASSERT: { if(e.arity() != 2) throw EvalException("ASSERT requires exactly one argument, but is given " +int2string(e.arity()-1)+":\n "+e.toString()); TRACE_MSG("commands", "** [commands] Asserting formula"); d_vc->assertFormula(d_vc->parseExpr(e[1])); break; } case QUERY: { if(e.arity() != 2) throw EvalException("QUERY requires exactly one argument, but is given " +int2string(e.arity()-1)+":\n "+e.toString()); TRACE_MSG("commands", "** [commands] Query formula"); QueryResult qres = d_vc->query(d_vc->parseExpr(e[1])); if (qres == UNKNOWN && d_vc->getFlags()["unknown-check-model"].getBool()) qres = d_vc->tryModelGeneration(); reportResult(qres); if (qres == INVALID) { if (d_vc->getFlags()["counterexample"].getBool()) { printCounterExample(); } if (d_vc->getFlags()["model"].getBool()) { printModel(); } } break; } case CHECKSAT: { QueryResult qres; TRACE_MSG("commands", "** [commands] CheckSat"); if (e.arity() == 1) { qres = d_vc->checkUnsat(d_vc->trueExpr()); } else if (e.arity() == 2) { qres = d_vc->checkUnsat(d_vc->parseExpr(e[1])); } else { throw EvalException("CHECKSAT requires no more than one argument, but is given " +int2string(e.arity()-1)+":\n "+e.toString()); } if (qres == UNKNOWN && !d_vc->getFlags()["translate"].getBool() && d_vc->getFlags()["unknown-check-model"].getBool()) qres = d_vc->tryModelGeneration(); reportResult(qres, false); if (qres == SATISFIABLE) { if (d_vc->getFlags()["counterexample"].getBool()) { printCounterExample(); } if (d_vc->getFlags()["model"].getBool()) { printModel(); } } // {//for debug only by yeting // Proof p = d_vc->getProof(); // if (d_vc->getFlags()["printResults"].getBool()) { // cout << p << endl; // cout << flush; // } // } break; } case CONTINUE: { if (e.arity() != 1) { throw EvalException("CONTINUE takes no arguments"); } TRACE_MSG("commands", "** [commands] Continue"); QueryResult qres = d_vc->checkContinue(); if (d_vc->getFlags()["printResults"].getBool()) { switch (qres) { case VALID: cout << "No more models found." << endl; break; case INVALID: cout << "Model found" << endl; break; case ABORT: cout << "Unknown: resource limit exhausted." << endl; break; case UNKNOWN: { // Vector of reasons in case of incomplete result vector reasons; IF_DEBUG(bool b =) d_vc->incomplete(reasons); DebugAssert(b, "Expected incompleteness"); cout << "Unknown.\n\n"; cout << "CVC3 was incomplete in this example due to:"; for(vector::iterator i=reasons.begin(), iend=reasons.end(); i!=iend; ++i) cout << "\n * " << (*i); cout << endl << endl; break; } default: FatalAssert(false, "Unexpected case"); } cout << flush; } break; } case RESTART: { if(e.arity() != 2) throw EvalException("RESTART requires exactly one argument, but is given " +int2string(e.arity()-1)+":\n "+e.toString()); TRACE_MSG("commands", "** [commands] Restart formula"); QueryResult qres = d_vc->restart(d_vc->parseExpr(e[1])); reportResult(qres); if (qres == INVALID) { if (d_vc->getFlags()["counterexample"].getBool()) { printCounterExample(); } if (d_vc->getFlags()["model"].getBool()) { printModel(); } } break; } case TRANSFORM: { if(e.arity() != 2) throw EvalException ("TRANSFORM requires exactly one argument, but is given " +int2string(e.arity()-1)+":\n "+e.toString()); TRACE_MSG("commands", "** [commands] Transforming expression"); Expr ee = d_vc->parseExpr(e[1]); e = d_vc->simplify(ee); if (d_vc->getFlags()["printResults"].getBool()) d_vc->printExpr(e); break; } case PRINT: if(e.arity() != 2) throw EvalException ("PRINT requires exactly one argument, but is given " +int2string(e.arity()-1)+":\n "+e.toString()); d_vc->printExpr(d_vc->parseExpr(e[1])); break; case PUSH: case POP: case PUSH_SCOPE: case POP_SCOPE: { int arg; if (e.arity() == 1) arg = 1; else { DebugAssert(e.arity() == 2 && e[1].getKind() == RATIONAL_EXPR, "Bad argument to "+kindName); arg = e[1].getRational().getInt(); if(arg <= 0) throw EvalException("Argument to PUSH or POP is <= 0"); } if (kind == PUSH) { for (int i = 0; i < arg; i++) { d_vc->push(); } } else if (kind == POP) { if(arg > d_vc->stackLevel()) throw EvalException("Argument to POP is out of range:\n" " current stack level = " +int2string(d_vc->stackLevel()) +"\n argument = " +int2string(arg)); for (int i = 0; i < arg; i++) { d_vc->pop(); } } else if (kind == PUSH_SCOPE) { for (int i = 0; i < arg; i++) { d_vc->pushScope(); } } else if (kind == POP_SCOPE) { if(arg >= d_vc->scopeLevel()) throw EvalException("Argument to POP_SCOPE is out of range:\n" " current scope = " +int2string(d_vc->scopeLevel()) +"\n argument = " +int2string(arg)); for (int i = 0; i < arg; i++) { d_vc->popScope(); } } break; } case POPTO: case POPTO_SCOPE: { int arg; if (e.arity() == 1) arg = 0; else { DebugAssert(e.arity() == 2 && e[1].getKind() == RATIONAL_EXPR, "Bad argument to "+kindName); arg = e[1].getRational().getInt(); } if (kind == POPTO) { d_vc->popto(arg); } else { d_vc->poptoScope(arg); } break; } case RESET: { throw ResetException(); break; } case WHERE: case ASSERTIONS: case ASSUMPTIONS: { vector assertions; ExprMap skolemAxioms; ExprMap visited; d_vc->getAssumptions(assertions); if (d_vc->getFlags()["printResults"].getBool()) { cout << "Current stack level is " << d_vc->stackLevel() << " (scope " << d_vc->scopeLevel() << ")." << endl; if (assertions.size() == 0) { cout << "% No active assumptions\n"; } else { cout << "% Active assumptions:\n"; for (unsigned i = 0; i < assertions.size(); i++) { cout << "ASSERT " << assertions[i] << ";" << endl; findAxioms(assertions[i], skolemAxioms, visited); } ExprMap::iterator it = skolemAxioms.begin(); ExprMap::iterator end = skolemAxioms.end(); if (it != end) { cout << "% Skolemization axioms" << endl; for(; it!=end; ++it) cout << "ASSERT " << skolemizeAx((*it).first) << ";" << endl; } } cout << endl; } break; } case COUNTEREXAMPLE: { if (d_vc->getFlags()["printResults"].getBool()) { printCounterExample(); } break; } case COUNTERMODEL: { if (d_vc->getFlags()["printResults"].getBool()) { try { printModel(); } catch (Exception& e) { throw EvalException(e.toString()); } } break; } case TRACE: { // Set a trace flag #ifdef _CVC3_DEBUG_MODE if(e.arity() != 2) throw EvalException("TRACE takes exactly one string argument"); if(!e[1].isString()) throw EvalException("TRACE requires a string argument"); debugger.traceFlag(e[1].getString()) = true; #endif } break; case UNTRACE: { // Unset a trace flag #ifdef _CVC3_DEBUG_MODE if(e.arity() != 2) throw EvalException("UNTRACE takes exactly one string argument"); if(!e[1].isString()) throw EvalException("UNTRACE requires a string argument"); debugger.traceFlag(e[1].getString()) = false; #endif } break; case OPTION: { if(e.arity() != 3) throw EvalException("OPTION takes exactly two arguments " "(name and value of a flag)"); if(!e[1].isString()) throw EvalException("OPTION: flag name must be a string"); CLFlags& flags = d_vc->getFlags(); string name(e[1].getString()); vector names; size_t n = flags.countFlags(name, names); if(n != 1) throw EvalException("OPTION: found "+int2string(n) +" flags matching "+name +".\nThe flag name must uniquely resolve."); name = names[0]; const CLFlag& flag(flags[name]); // If the flag is set on the command line, ignore it if(flag.modified()) break; switch(flag.getType()) { case CLFLAG_BOOL: if(!(e[2].isRational() && e[2].getRational().isInteger())) throw EvalException("OPTION: flag "+name +" expects a boolean value (0 or 1"); flags.setFlag(name, e[2].getRational().getInt() != 0); break; case CLFLAG_INT: if(!(e[2].isRational() && e[2].getRational().isInteger())) throw EvalException("OPTION: flag "+name+" expects an integer value"); flags.setFlag(name, e[2].getRational().getInt()); break; case CLFLAG_STRING: if(!e[2].isString()) throw EvalException("OPTION: flag "+name+" expects a string value"); flags.setFlag(name, e[2].getString()); break; default: throw EvalException("OPTION: the type of flag "+name +" is not supported by the OPTION commnand"); break; } d_vc->reprocessFlags(); } break; case GET_VALUE: { ExprMap m; d_vc->getConcreteModel(m); if (d_vc->getFlags()["printResults"].getBool()) { cout << "("; } for(int i = 0; i < e[1].arity(); ++i) { Expr res = d_vc->getValue(d_vc->parseExpr(e[1][i])); if (d_vc->getFlags()["printResults"].getBool()) { cout << res; if(i < e[1].arity() - 1) { cout << endl; } } } if (d_vc->getFlags()["printResults"].getBool()) { cout << ")" << endl; } break; } case GET_ASSIGNMENT: { ExprMap m; d_vc->getConcreteModel(m); Expr res = d_vc->getAssignment(); if (d_vc->getFlags()["printResults"].getBool()) { cout << res << endl; cout << flush; } break; } case DUMP_PROOF: { Proof p = d_vc->getProof(); if (d_vc->getFlags()["printResults"].getBool()) { cout << p << endl; cout << flush; } break; } case DUMP_ASSUMPTIONS: { // Assumption tracking vector assertions; bool b = d_vc->inconsistent(assertions); DebugAssert(b, "not inconsistent"); if (d_vc->getFlags()["printResults"].getBool()) { if(assertions.size() == 0) { cout << "% No relevant assumptions\n"; } else { cout << "% Relevant assumptions:\n"; for (unsigned i = 0; i < assertions.size(); i++) { cout << Expr(ASSERT, assertions[i]) << "\n"; } } cout << endl << flush; } break; } case DUMP_TCC: { const Expr& tcc = d_vc->getTCC(); if (d_vc->getFlags()["printResults"].getBool()) { if(tcc.isNull()) cout << "% No TCC is avaialble" << endl; else cout << "% TCC for the last declaration, ASSERT, or QUERY:\n\n" << tcc << endl; } break; } case DUMP_TCC_ASSUMPTIONS: { vector assertions; d_vc->getAssumptionsTCC(assertions); if (d_vc->getFlags()["printResults"].getBool()) { if(assertions.size() == 0) { cout << "% No relevant assumptions\n"; } else { cout << "% Relevant assumptions for the last TCC:\n"; for (unsigned i = 0; i < assertions.size(); i++) { cout << Expr(ASSERT, assertions[i]) << "\n"; } } cout << endl << flush; } break; } case DUMP_TCC_PROOF: { const Proof& tcc = d_vc->getProofTCC(); if (d_vc->getFlags()["printResults"].getBool()) { if(tcc.isNull()) cout << "% No TCC is avaialble" << endl; else cout << "% Proof of TCC for the last declaration, ASSERT, or QUERY:\n\n" << tcc << endl; } break; } case DUMP_CLOSURE: { const Expr& cl = d_vc->getClosure(); if (d_vc->getFlags()["printResults"].getBool()) { if(cl.isNull()) cout << "% No closure is avaialble" << endl; else cout << "% Closure for the last QUERY:\n\n" << cl << endl; } break; } case DUMP_CLOSURE_PROOF: { const Proof& cl = d_vc->getProofClosure(); if (d_vc->getFlags()["printResults"].getBool()) { if(cl.isNull()) cout << "% No closure is avaialble" << endl; else cout << "% Proof of closure for the last QUERY:\n\n" << cl << endl; } break; } case ECHO: if(e.arity() != 2) throw EvalException("ECHO: wrong number of arguments: " + e.toString()); if(!e[1].isString()) throw EvalException("ECHO: the argument must be a string: " +e.toString()); if (d_vc->getFlags()["printResults"].getBool()) { cout << e[1].getString(); cout << endl << flush; } break; case SEQ: { Expr::iterator i=e.begin(), iend=e.end(); ++i; // Skip "SEQ" symbol bool success = true; for(; i!=iend; ++i) { try { success = success && evaluateCommand(*i); } catch(ResetException& e) { if (++i == iend) throw e; throw EvalException("RESET can only be the last command in a sequence"); } } return success; } case ARITH_VAR_ORDER: { if (e.arity() <= 2) throw EvalException("ARITH_VAR_ORDER takes at least two arguments"); Expr smaller; Expr bigger = d_vc->parseExpr(e[1]); for (int i = 2; i < e.arity(); i ++) { smaller = bigger; bigger = d_vc->parseExpr(e[i]); if (!d_vc->addPairToArithOrder(smaller, bigger)) throw EvalException("ARITH_VAR_ORDER only takes arithmetic terms"); } return true; } case ANNOTATION: { for (int i = 1; i < e.arity(); ++i) { if (e[i].arity() == 1) { d_vc->logAnnotation(Expr(ANNOTATION, e[i][0])); } else { DebugAssert(e[i].arity() == 2, "Expected arity 2"); d_vc->logAnnotation(Expr(ANNOTATION, e[i][0], e[i][1])); } } break; } case INCLUDE: { // read in the specified file if(e.arity() != 2) throw EvalException("INCLUDE takes exactly one string argument"); if(!e[1].isString()) throw EvalException("INCLUDE requires a string argument"); ifstream fs; fs.open(e[1].getString().c_str(),ios::in); if(!fs.is_open()) { fs.close(); throw EvalException("File "+e[1].getString()+" does not exist"); } fs.close(); d_vc->loadFile(e[1].getString(), d_vc->getEM()->getInputLang(), d_vc->getFlags()["interactive"].getBool(), true /* nested call */); break; } case HELP: cout << "Use the -help command-line option for help." << endl; break; case DUMP_SIG: case DBG: case SUBSTITUTE: case GET_CHILD: case GET_TYPE: case CHECK_TYPE: case FORGET: case CALL: default: throw EvalException("Unknown command: " + e.toString()); break; } TRACE_MSG("commands", "evaluateCommand => true }"); return true; } void VCCmd::processCommands() { bool error(false); try { bool success(true); while(success) { try { success = evaluateNext(); } catch (ResetException& e) { if (d_calledFromParser) { throw EvalException("RESET not supported within INCLUDEd file"); } d_parser->reset(); d_vc->reset(); success = true; } catch (EvalException& e) { error= true; cerr << "*** Eval Error:\n " << e << endl; } } } catch(Exception& e) { cerr << "*** Fatal exception:\n" << e << endl; error= true; } catch(...) { cerr << "*** Unknown fatal exception caught" << endl; error= true; } if (error) { d_parser->printLocation(cerr); cerr << ": this is the location of the error" << endl; } } cvc3-2.4.1/src/vcl/vcl.cpp0000644000175400017540000020500511624746725015137 0ustar mdetersmdeters/*****************************************************************************/ /*! * \file vcl.cpp * * Author: Clark Barrett * * Created: Tue Dec 31 18:27:11 2002 * *
* License to use, copy, modify, sell and/or distribute this software * and its documentation for any purpose is hereby granted without * royalty, subject to the terms and conditions defined in the \ref * LICENSE file provided with this distribution. * *
* */ /*****************************************************************************/ #include #include "os.h" #include "vcl.h" #include "parser.h" #include "vc_cmd.h" #include "search_simple.h" #include "search_fast.h" #include "search_sat.h" #include "theory_core.h" #include "theory_uf.h" #include "theory_arith_old.h" #include "theory_arith_new.h" #include "theory_arith3.h" #include "theory_bitvector.h" #include "theory_array.h" #include "theory_quant.h" #include "theory_records.h" #include "theory_simulate.h" #include "theory_datatype.h" #include "theory_datatype_lazy.h" #include "translator.h" #include "typecheck_exception.h" #include "eval_exception.h" #include "expr_transform.h" #include "theorem_manager.h" #include "assumptions.h" #include "parser_exception.h" using namespace std; using namespace CVC3; //namespace CVC3{ // VCL* myvcl; //} /////////////////////////////////////////////////////////////////////////////// // Static ValidityChecker methods /////////////////////////////////////////////////////////////////////////////// ValidityChecker* ValidityChecker::create(const CLFlags& flags) { return new VCL(flags); } CLFlags ValidityChecker::createFlags() { CLFlags flags; // We expect the user to type cvc3 -h to get help, which will set // the "help" flag to false; that's why it's initially true. // Overall system control flags flags.addFlag("timeout", CLFlag(0, "Kill cvc3 process after given number of seconds (0==no limit)")); flags.addFlag("stimeout", CLFlag(0, "Set time resource limit in tenths of seconds for a query(0==no limit)")); flags.addFlag("resource", CLFlag(0, "Set finite resource limit (0==no limit)")); flags.addFlag("mm", CLFlag("chunks", "Memory manager (chunks, malloc)")); // Information printing flags flags.addFlag("help",CLFlag(true, "print usage information and exit")); flags.addFlag("unsupported",CLFlag(true, "print usage for old/unsupported/experimental options")); flags.addFlag("version",CLFlag(true, "print version information and exit")); flags.addFlag("interactive", CLFlag(false, "Interactive mode")); flags.addFlag("stats", CLFlag(false, "Print run-time statistics")); flags.addFlag("seed", CLFlag(1, "Set the seed for random sequence")); flags.addFlag("printResults", CLFlag(true, "Print results of interactive commands.")); flags.addFlag("dump-log", CLFlag("", "Dump API call log in CVC3 input " "format to given file " "(off when file name is \"\")")); flags.addFlag("parse-only", CLFlag(false,"Parse the input, then exit.")); //Translation related flags flags.addFlag("expResult", CLFlag("", "For smtlib translation. Give the expected result", false)); flags.addFlag("category", CLFlag("unknown", "For smtlib translation. Give the category", false)); flags.addFlag("translate", CLFlag(false, "Produce a complete translation from " "the input language to output language. ")); flags.addFlag("real2int", CLFlag(false, "When translating, convert reals to integers.", false)); flags.addFlag("convertArith", CLFlag(false, "When translating, try to rewrite arith terms into smt-lib subset", false)); flags.addFlag("convert2diff", CLFlag("", "When translating, try to force into difference logic. Legal values are int and real.", false)); flags.addFlag("iteLiftArith", CLFlag(false, "For translation. If true, ite's are lifted out of arith exprs.", false)); flags.addFlag("convertArray", CLFlag(false, "For translation. If true, arrays are converted to uninterpreted functions if possible.", false)); flags.addFlag("combineAssump", CLFlag(false, "For translation. If true, assumptions are combined into the query.", false)); flags.addFlag("convert2array", CLFlag(false, "For translation. If true, try to convert to array-only theory", false)); flags.addFlag("convertToBV",CLFlag(0, "For translation. Set to nonzero to convert ints to bv's of that length", false)); flags.addFlag("convert-eq-iff",CLFlag(false, "Convert equality on Boolean expressions to iff.", false)); flags.addFlag("preSimplify",CLFlag(false, "Simplify each assertion or query before translating it", false)); flags.addFlag("dump-tcc", CLFlag(false, "Compute and dump TCC only")); flags.addFlag("trans-skip-pp", CLFlag(false, "Skip preprocess step in translation module", false)); flags.addFlag("trans-skip-difficulty", CLFlag(false, "Leave out difficulty attribute during translation to SMT v2.0", false)); flags.addFlag("promote", CLFlag(true, "Promote undefined logic combinations to defined logic combinations during translation to SMT", false)); // Parser related flags flags.addFlag("old-func-syntax",CLFlag(false, "Enable parsing of old-style function syntax", false)); // Pretty-printing related flags flags.addFlag("dagify-exprs", CLFlag(true, "Print expressions with sharing as DAGs")); flags.addFlag("lang", CLFlag("presentation", "Input language " "(presentation, smt, smt2, internal)")); flags.addFlag("output-lang", CLFlag("", "Output language " "(presentation, smtlib, simplify, internal, lisp, tptp, spass)")); flags.addFlag("indent", CLFlag(false, "Print expressions with indentation")); flags.addFlag("width", CLFlag(80, "Suggested line width for printing")); flags.addFlag("print-depth", CLFlag(-1, "Max. depth to print expressions ")); flags.addFlag("print-assump", CLFlag(false, "Print assumptions in Theorems ")); // Search Engine (SAT) related flags flags.addFlag("sat",CLFlag("minisat", "choose a SAT solver to use " "(sat, minisat)")); flags.addFlag("de",CLFlag("dfs", "choose a decision engine to use " "(dfs, sat)")); // Proofs and Assumptions flags.addFlag("proofs", CLFlag(false, "Produce proofs")); flags.addFlag("check-proofs", CLFlag(IF_DEBUG(true ||) false, "Check proofs on-the-fly")); flags.addFlag("minimizeClauses", CLFlag(false, "Use brute-force minimization of clauses", false)); flags.addFlag("dynack", CLFlag(false, "Use dynamic Ackermannization", false)); flags.addFlag("smart-clauses", CLFlag(true, "Learn multiple clauses per conflict")); // Core framework switches flags.addFlag("tcc", CLFlag(false, "Check TCCs for each ASSERT and QUERY")); flags.addFlag("cnf", CLFlag(true, "Convert top-level Boolean formulas to CNF", false)); flags.addFlag("ignore-cnf-vars", CLFlag(false, "Do not split on aux. CNF vars (with +cnf)", false)); flags.addFlag("orig-formula", CLFlag(false, "Preserve the original formula with +cnf (for splitter heuristics)", false)); flags.addFlag("liftITE", CLFlag(false, "Eagerly lift all ITE exprs")); flags.addFlag("iflift", CLFlag(false, "Translate if-then-else terms to CNF (with +cnf)", false)); flags.addFlag("circuit", CLFlag(false, "With +cnf, use circuit propagation", false)); flags.addFlag("un-ite-ify", CLFlag(false, "Unconvert ITE expressions", false)); flags.addFlag("ite-cond-simp", CLFlag(false, "Replace ITE condition by TRUE/FALSE in subexprs", false)); flags.addFlag("preprocess", CLFlag(true, "Preprocess queries")); flags.addFlag("pp-pushneg", CLFlag(false, "Push negation in preprocessor")); flags.addFlag("pp-bryant", CLFlag(false, "Enable Bryant algorithm for UF", false)); flags.addFlag("pp-budget", CLFlag(0, "Budget for new preprocessing step", false)); flags.addFlag("pp-care", CLFlag(true, "Enable care-set preprocessing step", false)); flags.addFlag("simp-and", CLFlag(false, "Rewrite x&y to x&y[x/true]", false)); flags.addFlag("simp-or", CLFlag(false, "Rewrite x|y to x|y[x/false]", false)); flags.addFlag("pp-batch", CLFlag(false, "Ignore assumptions until query, then process all at once")); flags.addFlag("no-save-model", CLFlag(false, "Do NOT save model assumptions in context after invalid / sat query")); flags.addFlag("internal::userSetNoSaveModel", CLFlag(false, "set if user gave +no-save-model or -no-save-model explicitly", false)); // Negate the query when translate into tptp flags.addFlag("negate-query", CLFlag(true, "Negate the query when translate into TPTP format"));; // Concrete model generation (counterexamples) flags flags.addFlag("counterexample", CLFlag(false, "Dump counterexample if formula is invalid or satisfiable")); flags.addFlag("model", CLFlag(false, "Dump model if formula is invalid or satisfiable")); flags.addFlag("unknown-check-model", CLFlag(false, "Try to generate model if formula is unknown")); flags.addFlag("applications", CLFlag(true, "Add relevant function applications and array accesses to the concrete countermodel")); // Debugging flags (only for the debug build) // #ifdef _CVC3_DEBUG_MODE vector > sv; flags.addFlag("trace", CLFlag(sv, "Tracing. Multiple flags add up.")); flags.addFlag("dump-trace", CLFlag("", "Dump debugging trace to " "given file (off when file name is \"\")")); // #endif // DP-specific flags // Arithmetic flags.addFlag("arith-new",CLFlag(false, "Use new arithmetic dp", false)); flags.addFlag("arith3",CLFlag(false, "Use old arithmetic dp that works well with combined theories", false)); flags.addFlag("var-order", CLFlag(false, "Use simple variable order in arith", false)); flags.addFlag("ineq-delay", CLFlag(0, "Accumulate this many inequalities before processing (-1 for don't process until necessary)")); flags.addFlag("nonlinear-sign-split", CLFlag(true, "Whether to split on the signs of nontrivial nonlinear terms")); flags.addFlag("grayshadow-threshold", CLFlag(-1, "Ignore gray shadows bigger than this (makes solver incomplete)")); flags.addFlag("pathlength-threshold", CLFlag(-1, "Ignore gray shadows bigger than this (makes solver incomplete)")); // Arrays flags.addFlag("liftReadIte", CLFlag(true, "Lift read of ite")); //for LFSC stuff, disable Tseitin CNF conversion, by Yeting flags.addFlag("cnf-formula", CLFlag(false, "The input must be in CNF. This option automatically enables '-de sat' and disable preprocess")); //for LFSC print out, by Yeting //flags.addFlag("lfsc", CLFlag(false, "the input is already in CNF. This option automatically enables -de sat and disable -preprocess")); // for LFSC print, allows different modes by Liana flags.addFlag("lfsc-mode", CLFlag(0, "lfsc mode 0: off, 1:normal, 2:cvc3-mimic etc.")); // Quantifiers flags.addFlag("max-quant-inst", CLFlag(200, "The maximum number of" " naive instantiations")); flags.addFlag("quant-new", CLFlag(true, "If this option is false, only naive instantiation is called")); flags.addFlag("quant-lazy", CLFlag(false, "Instantiate lazily", false)); flags.addFlag("quant-sem-match", CLFlag(false, "Attempt to match semantically when instantiating", false)); // flags.addFlag("quant-const-match", // CLFlag(true, "When matching semantically, only match with constants", false)); flags.addFlag("quant-complete-inst", CLFlag(false, "Try complete instantiation heuristic. +pp-batch will be automatically enabled")); flags.addFlag("quant-max-IL", CLFlag(100, "The maximum Instantiation Level allowed")); flags.addFlag("quant-inst-lcache", CLFlag(true, "Cache instantiations")); flags.addFlag("quant-inst-gcache", CLFlag(false, "Cache instantiations", false)); flags.addFlag("quant-inst-tcache", CLFlag(false, "Cache instantiations", false)); flags.addFlag("quant-inst-true", CLFlag(true, "Ignore true instantiations")); flags.addFlag("quant-pullvar", CLFlag(false, "Pull out vars", false)); flags.addFlag("quant-score", CLFlag(true, "Use instantiation level")); flags.addFlag("quant-polarity", CLFlag(false, "Use polarity ", false)); flags.addFlag("quant-eqnew", CLFlag(true, "Use new equality matching")); flags.addFlag("quant-max-score", CLFlag(0, "Maximum initial dynamic score")); flags.addFlag("quant-trans3", CLFlag(true, "Use trans heuristic")); flags.addFlag("quant-trans2", CLFlag(true, "Use trans2 heuristic")); flags.addFlag("quant-naive-num", CLFlag(1000, "Maximum number to call naive instantiation")); flags.addFlag("quant-naive-inst", CLFlag(true, "Use naive instantiation")); flags.addFlag("quant-man-trig", CLFlag(true, "Use manual triggers")); flags.addFlag("quant-gfact", CLFlag(false, "Send facts to core directly", false)); flags.addFlag("quant-glimit", CLFlag(1000, "Limit for gfacts", false)); flags.addFlag("print-var-type", //by yeting, as requested by Sascha Boehme for proofs CLFlag(false, "Print types for bound variables")); //Bitvectors flags.addFlag("bv32-flag", CLFlag(false, "assume that all bitvectors are 32bits with no overflow", false)); // Uninterpreted Functions flags.addFlag("trans-closure", CLFlag(false,"enables transitive closure of binary relations", false)); // Datatypes flags.addFlag("dt-smartsplits", CLFlag(true, "enables smart splitting in datatype theory", false)); flags.addFlag("dt-lazy", CLFlag(false, "lazy splitting on datatypes", false)); return flags; } ValidityChecker* ValidityChecker::create() { return new VCL(createFlags()); } /////////////////////////////////////////////////////////////////////////////// // VCL private methods /////////////////////////////////////////////////////////////////////////////// Theorem3 VCL::deriveClosure(const Theorem3& thm) { vector assump; set assumpSet; // Compute the vector of assumptions for thm, and iteratively move // the assumptions to the RHS until done. Each closure step may // introduce new assumptions from the proofs of TCCs, so those need // to be dealt with in the same way, until no assumptions remain. Theorem3 res = thm; vector tccs; while(true) { { const Assumptions& a(res.getAssumptionsRef()); if (a.empty()) break; assump.clear(); assumpSet.clear(); Assumptions::iterator i=a.begin(), iend=a.end(); if(i!=iend) i->clearAllFlags(); // Collect the assumptions of 'res' *without* TCCs for(; i!=iend; ++i) getAssumptionsRec(*i, assumpSet, false); // Build the vectors of assumptions and TCCs if(getFlags()["tcc"].getBool()) { tccs.clear(); for(set::iterator i=assumpSet.begin(), iend=assumpSet.end(); i!=iend; ++i) { assump.push_back(i->thm().getExpr()); tccs.push_back(i->tcc()); } } } // Derive the closure res = d_se->getCommonRules()->implIntro3(res, assump, tccs); } return res; } //! Recursive assumption graph traversal to find user assumptions /*! * If an assumption has a TCC, traverse the proof of TCC and add its * assumptions to the set recursively. */ void VCL::getAssumptionsRec(const Theorem& thm, set& assumptions, bool addTCCs) { if(thm.isNull() || thm.isRefl() || thm.isFlagged()) return; thm.setFlag(); if(thm.isAssump()) { if(d_userAssertions->count(thm.getExpr())>0) { const UserAssertion& a = (*d_userAssertions)[thm.getExpr()]; assumptions.insert(a); if(addTCCs) { DebugAssert(!a.tcc().isNull(), "getAssumptionsRec(a=" +a.thm().toString()+", thm = "+thm.toString()+")"); getAssumptionsRec(a.tcc(), assumptions, true); } } else { // it's a splitter UserAssertion a(thm, Theorem(), d_nextIdx++); assumptions.insert(a); } } else { const Assumptions& a(thm.getAssumptionsRef()); for(Assumptions::iterator i=a.begin(), iend=a.end(); i!=iend; ++i) getAssumptionsRec(*i, assumptions, addTCCs); } } void VCL::getAssumptions(const Assumptions& a, vector& assumptions) { set assumpSet; if(a.empty()) return; Assumptions::iterator i=a.begin(), iend=a.end(); if(i!=iend) i->clearAllFlags(); for(; i!=iend; ++i) getAssumptionsRec(*i, assumpSet, getFlags()["tcc"].getBool()); // Order assumptions by their creation time for(set::iterator i=assumpSet.begin(), iend=assumpSet.end(); i!=iend; ++i) assumptions.push_back(i->thm().getExpr()); } IF_DEBUG( void VCL::dumpTrace(int scope) { vector fields; fields.push_back(strPair("scope", int2string(scope))); debugger.dumpTrace("scope", fields); } ) /////////////////////////////////////////////////////////////////////////////// // Public VCL methods /////////////////////////////////////////////////////////////////////////////// VCL::VCL(const CLFlags& flags) : d_flags(new CLFlags(flags)) { // Set the dependent flags so that they are consistent if ((*d_flags)["dump-tcc"].getBool()) { d_flags->setFlag("translate", true); d_flags->setFlag("pp-batch", true); d_flags->setFlag("tcc", true); } if ((*d_flags)["translate"].getBool()) { d_flags->setFlag("printResults", false); } if ((*d_flags)["pp-bryant"].getBool()) { d_flags->setFlag("pp-batch", true); } //added by Yeting if ((*d_flags)["quant-complete-inst"].getBool() && !(*d_flags)["translate"].getBool()) { d_flags->setFlag("pp-batch", true); } //added by Yeting if ((*d_flags)["cnf-formula"].getBool()) { d_flags->setFlag("de", "sat"); d_flags->setFlag("preprocess", false); } IF_DEBUG( // Initialize the global debugger CVC3::debugger.init(&((*d_flags)["trace"].getStrVec()), &((*d_flags)["dump-trace"].getString())); ) init(); } void VCL::init() { d_nextIdx = 0; d_statistics = new Statistics(); d_cm = new ContextManager(); // Initialize the database of user assertions. It has to be // initialized after d_cm. d_userAssertions = new(true) CDMap(getCurrentContext()); d_batchedAssertions = new(true) CDList(getCurrentContext()); d_batchedAssertionsIdx = new(true) CDO(getCurrentContext(), 0); d_em = new ExprManager(d_cm, *d_flags); d_tm = new TheoremManager(d_cm, d_em, *d_flags); d_em->setTM(d_tm); d_translator = new Translator(d_em, (*d_flags)["translate"].getBool(), (*d_flags)["real2int"].getBool(), (*d_flags)["convertArith"].getBool(), (*d_flags)["convert2diff"].getString(), (*d_flags)["iteLiftArith"].getBool(), (*d_flags)["expResult"].getString(), (*d_flags)["category"].getString(), (*d_flags)["convertArray"].getBool(), (*d_flags)["combineAssump"].getBool(), (*d_flags)["convertToBV"].getInt()); d_dump = d_translator->start((*d_flags)["dump-log"].getString()); d_theoryCore = new TheoryCore(d_cm, d_em, d_tm, d_translator, *d_flags, *d_statistics); DebugAssert(d_theories.size() == 0, "Expected empty theories array"); d_theories.push_back(d_theoryCore); // Fast rewriting of literals is done by setting their find to true or false. falseExpr().setFind(d_theoryCore->reflexivityRule(falseExpr())); trueExpr().setFind(d_theoryCore->reflexivityRule(trueExpr())); d_theories.push_back(d_theoryUF = new TheoryUF(d_theoryCore)); if ((*d_flags)["arith-new"].getBool()) { d_theories.push_back(d_theoryArith = new TheoryArithNew(d_theoryCore)); } else if ((*d_flags)["arith3"].getBool()) { d_theories.push_back(d_theoryArith = new TheoryArith3(d_theoryCore)); } else { d_theories.push_back(d_theoryArith = new TheoryArithOld(d_theoryCore)); } d_theoryCore->getExprTrans()->setTheoryArith(d_theoryArith); d_theories.push_back(d_theoryArray = new TheoryArray(d_theoryCore)); d_theories.push_back(d_theoryRecords = new TheoryRecords(d_theoryCore)); d_theories.push_back(d_theorySimulate = new TheorySimulate(d_theoryCore)); d_theories.push_back(d_theoryBitvector = new TheoryBitvector(d_theoryCore)); if ((*d_flags)["dt-lazy"].getBool()) { d_theories.push_back(d_theoryDatatype = new TheoryDatatypeLazy(d_theoryCore)); } else { d_theories.push_back(d_theoryDatatype = new TheoryDatatype(d_theoryCore)); } d_theories.push_back(d_theoryQuant = new TheoryQuant(d_theoryCore)); d_translator->setTheoryCore(d_theoryCore); d_translator->setTheoryUF(d_theoryUF); d_translator->setTheoryArith(d_theoryArith); d_translator->setTheoryArray(d_theoryArray); d_translator->setTheoryQuant(d_theoryQuant); d_translator->setTheoryRecords(d_theoryRecords); d_translator->setTheorySimulate(d_theorySimulate); d_translator->setTheoryBitvector(d_theoryBitvector); d_translator->setTheoryDatatype(d_theoryDatatype); // Must be created after TheoryCore, since it needs it. // When we have more than one search engine, select one to create // based on flags const string& satEngine = (*d_flags)["sat"].getString(); if (satEngine == "simple") d_se = new SearchSimple(d_theoryCore); else if (satEngine == "fast") d_se = new SearchEngineFast(d_theoryCore); else if (satEngine == "sat" || satEngine == "minisat") d_se = new SearchSat(d_theoryCore, satEngine); else throw CLException("Unrecognized SAT solver name: " +(*d_flags)["sat"].getString()); // Initial scope level should be 1 d_cm->push(); d_stackLevel = new(true) CDO(d_cm->getCurrentContext(), 0); d_theoryCore->setResourceLimit((unsigned)((*d_flags)["resource"].getInt())); d_theoryCore->setTimeLimit((unsigned)((*d_flags)["stimeout"].getInt())); // myvcl = this; } void VCL::destroy() { popto(0); d_cm->popto(0); delete d_stackLevel; free(d_stackLevel); d_translator->finish(); delete d_translator; TRACE_MSG("delete", "Deleting SearchEngine {"); delete d_se; TRACE_MSG("delete", "Finished deleting SearchEngine }"); // This map contains expressions and theorems; delete it before // d_em, d_tm, and d_cm. TRACE_MSG("delete", "Deleting d_userAssertions {"); delete d_batchedAssertionsIdx; free(d_batchedAssertionsIdx); delete d_batchedAssertions; free(d_batchedAssertions); delete d_userAssertions; free(d_userAssertions); TRACE_MSG("delete", "Finished deleting d_userAssertions }"); // and set these to null so their destructors don't blow up d_lastQuery = Theorem3(); d_lastQueryTCC = Theorem(); d_lastClosure = Theorem3(); // Delete ExprManager BEFORE TheoremManager, since Exprs use Theorems TRACE_MSG("delete", "Clearing d_em {"); d_em->clear(); d_tm->clear(); TRACE_MSG("delete", "Finished clearing d_em }"); for(size_t i=d_theories.size(); i!= 0; ) { --i; string name(d_theories[i]->getName()); TRACE("delete", "Deleting Theory[", name, "] {"); delete d_theories[i]; TRACE("delete", "Finished deleting Theory[", name, "] }"); } d_theories.clear(); // TheoremManager does not call ~Theorem() destructors, and only // releases memory. At worst, we'll lose some Assumptions. TRACE_MSG("delete", "Deleting d_tm {"); delete d_tm; TRACE_MSG("delete", "Finished deleting d_tm }"); TRACE_MSG("delete", "Deleting d_em {"); delete d_em; TRACE_MSG("delete", "Finished deleting d_em }"); TRACE_MSG("delete", "Deleting d_cm {"); delete d_cm; TRACE_MSG("delete", "Finished deleting d_cm }"); delete d_statistics; TRACE_MSG("delete", "Finished deleting d_statistics }"); } VCL::~VCL() { destroy(); TRACE_MSG("delete", "Deleting d_flags [end of ~VCL()]"); delete d_flags; // No more TRACE-ing after this point (it needs d_flags) // Finalize the global debugger, // otherwise applications with more than one instance of VCL // may use refer to deallocated flags (e.g. test6 uses 2 VCLs) IF_DEBUG( CVC3::debugger.finalize(); ) } void VCL::reprocessFlags() { if (d_se->getName() != (*d_flags)["sat"].getString()) { delete d_se; const string& satEngine = (*d_flags)["sat"].getString(); if (satEngine == "simple") d_se = new SearchSimple(d_theoryCore); else if (satEngine == "fast") d_se = new SearchEngineFast(d_theoryCore); else if (satEngine == "sat" || satEngine == "minisat") d_se = new SearchSat(d_theoryCore, satEngine); else throw CLException("Unrecognized SAT solver name: " +(*d_flags)["sat"].getString()); } int arithCur; if (d_theoryArith->getName() == "ArithmeticOld") arithCur = 1; else if (d_theoryArith->getName() == "ArithmeticNew") arithCur = 2; else { DebugAssert(d_theoryArith->getName() == "Arithmetic3", "unexpected name"); arithCur = 3; } int arithNext; if ((*d_flags)["arith-new"].getBool()) arithNext = 2; else if ((*d_flags)["arith3"].getBool()) arithNext = 3; else arithNext = 1; if (arithCur != arithNext) { delete d_theoryArith; switch (arithNext) { case 1: d_theoryArith = new TheoryArithOld(d_theoryCore); break; case 2: d_theoryArith = new TheoryArithNew(d_theoryCore); break; case 3: d_theoryArith = new TheoryArith3(d_theoryCore); break; } d_theories[2] = d_theoryArith; d_translator->setTheoryArith(d_theoryArith); } if ((*d_flags)["dump-tcc"].getBool()) { d_flags->setFlag("translate", true); d_flags->setFlag("pp-batch", true); d_flags->setFlag("tcc", true); } if ((*d_flags)["translate"].getBool()) { d_flags->setFlag("printResults", false); } if ((*d_flags)["pp-bryant"].getBool()) { d_flags->setFlag("pp-batch", true); } //added by Yeting if ((*d_flags)["quant-complete-inst"].getBool() && !(*d_flags)["translate"].getBool()) { d_flags->setFlag("pp-batch", true); } if ((*d_flags)["cnf-formula"].getBool()) { d_flags->setFlag("de", "sat"); d_flags->setFlag("preprocess", false); } //TODO: handle more flags } TheoryCore* VCL::core(){ return d_theoryCore; } Type VCL::boolType(){ return d_theoryCore->boolType(); } Type VCL::realType() { return d_theoryArith->realType(); } Type VCL::intType() { return d_theoryArith->intType(); } Type VCL::subrangeType(const Expr& l, const Expr& r) { return d_theoryArith->subrangeType(l, r); } Type VCL::subtypeType(const Expr& pred, const Expr& witness) { return d_theoryCore->newSubtypeExpr(pred, witness); } Type VCL::tupleType(const Type& type0, const Type& type1) { vector types; types.push_back(type0); types.push_back(type1); return d_theoryRecords->tupleType(types); } Type VCL::tupleType(const Type& type0, const Type& type1, const Type& type2) { vector types; types.push_back(type0); types.push_back(type1); types.push_back(type2); return d_theoryRecords->tupleType(types); } Type VCL::tupleType(const vector& types) { return d_theoryRecords->tupleType(types); } Type VCL::recordType(const string& field, const Type& type) { vector fields; vector kids; fields.push_back(field); kids.push_back(type); return Type(d_theoryRecords->recordType(fields, kids)); } Type VCL::recordType(const string& field0, const Type& type0, const string& field1, const Type& type1) { vector fields; vector kids; fields.push_back(field0); fields.push_back(field1); kids.push_back(type0); kids.push_back(type1); sort2(fields, kids); return Type(d_theoryRecords->recordType(fields, kids)); } Type VCL::recordType(const string& field0, const Type& type0, const string& field1, const Type& type1, const string& field2, const Type& type2) { vector fields; vector kids; fields.push_back(field0); fields.push_back(field1); fields.push_back(field2); kids.push_back(type0); kids.push_back(type1); kids.push_back(type2); sort2(fields, kids); return Type(d_theoryRecords->recordType(fields, kids)); } Type VCL::recordType(const vector& fields, const vector& types) { DebugAssert(fields.size() == types.size(), "VCL::recordType: number of fields is different \n" "from the number of types"); // Create copies of the vectors to sort them vector fs(fields); vector ts(types); sort2(fs, ts); return Type(d_theoryRecords->recordType(fs, ts)); } Type VCL::dataType(const string& name, const string& constructor, const vector& selectors, const vector& types) { vector constructors; constructors.push_back(constructor); vector > selectorsVec; selectorsVec.push_back(selectors); vector > typesVec; typesVec.push_back(types); return dataType(name, constructors, selectorsVec, typesVec); } Type VCL::dataType(const string& name, const vector& constructors, const vector >& selectors, const vector >& types) { Expr res = d_theoryDatatype->dataType(name, constructors, selectors, types); if(d_dump) { d_translator->dump(res); } return Type(res[0]); } void VCL::dataType(const vector& names, const vector >& constructors, const vector > >& selectors, const vector > >& types, vector& returnTypes) { Expr res = d_theoryDatatype->dataType(names, constructors, selectors, types); if(d_dump) { d_translator->dump(res); } for (int i = 0; i < res.arity(); ++i) { returnTypes.push_back(Type(res[i])); } } Type VCL::arrayType(const Type& typeIndex, const Type& typeData) { return ::arrayType(typeIndex, typeData); } Type VCL::bitvecType(int n) { return d_theoryBitvector->newBitvectorType(n); } Type VCL::funType(const Type& typeDom, const Type& typeRan) { return typeDom.funType(typeRan); } Type VCL::funType(const vector& typeDom, const Type& typeRan) { DebugAssert(typeDom.size() >= 1, "VCL::funType: missing domain types"); return Type::funType(typeDom, typeRan); } Type VCL::createType(const string& typeName) { if(d_dump) { d_translator->dump(Expr(TYPE, listExpr(idExpr(typeName)))); } return d_theoryCore->newTypeExpr(typeName); } Type VCL::createType(const string& typeName, const Type& def) { if (d_dump) { d_translator->dump(Expr(TYPE, idExpr(typeName), def.getExpr()), true); } return d_theoryCore->newTypeExpr(typeName, def); } Type VCL::lookupType(const string& typeName) { return d_theoryCore->lookupTypeExpr(typeName); } Expr VCL::varExpr(const string& name, const Type& type) { // Check if the ofstream is open (as opposed to the command line flag) if(d_dump) { d_translator->dump(Expr(CONST, idExpr(name), type.getExpr())); } return d_theoryCore->newVar(name, type); } Expr VCL::varExpr(const string& name, const Type& type, const Expr& def) { // Check if the ofstream is open (as opposed to the command line flag) if(d_dump) { d_translator->dump(Expr(CONST, idExpr(name), type.getExpr(), def), true); } // Prove the TCCs of the definition if(getFlags()["tcc"].getBool()) { Type tpDef(def.getType()), tpVar(type); // Make sure that def is in the subtype of tpVar; that is, prove // FORALL (x: tpDef): x = def => typePred(tpVar)(x) if(tpDef != tpVar) { // Typecheck the base types if(getBaseType(tpDef) != getBaseType(type)) { throw TypecheckException("Type mismatch in constant definition:\n" "Constant "+name+ " is declared with type:\n " +type.toString() +"\nBut the type of definition is\n " +tpDef.toString()); } TRACE("tccs", "CONST def: "+name+" : "+tpVar.toString() +" := : ", tpDef, ";"); vector boundVars; boundVars.push_back(boundVarExpr(name, "tcc", tpDef)); Expr body(boundVars[0].eqExpr(def).impExpr(getTypePred(tpVar, boundVars[0]))); Expr quant(forallExpr(boundVars, body)); try { checkTCC(quant); } catch(TypecheckException&) { throw TypecheckException ("Type mismatch in constant definition:\n" "Constant "+name+ " is declared with type:\n " +type.toString() +"\nBut the type of definition is\n " +def.getType().toString() +"\n\n which is not a subtype of the constant"); } } } return d_theoryCore->newVar(name, type, def); } Expr VCL::lookupVar(const string& name, Type* type) { return d_theoryCore->lookupVar(name, type); } Type VCL::getType(const Expr& e) { return e.getType(); } Type VCL::getBaseType(const Expr& e) { return d_theoryCore->getBaseType(e); } Type VCL::getBaseType(const Type& t) { return d_theoryCore->getBaseType(t); } Expr VCL::getTypePred(const Type&t, const Expr& e) { return d_theoryCore->getTypePred(t, e); } Expr VCL::stringExpr(const string& str) { return getEM()->newStringExpr(str); } Expr VCL::idExpr(const string& name) { return Expr(ID, stringExpr(name)); } Expr VCL::listExpr(const vector& kids) { return Expr(RAW_LIST, kids, getEM()); } Expr VCL::listExpr(const Expr& e1) { return Expr(RAW_LIST, e1); } Expr VCL::listExpr(const Expr& e1, const Expr& e2) { return Expr(RAW_LIST, e1, e2); } Expr VCL::listExpr(const Expr& e1, const Expr& e2, const Expr& e3) { return Expr(RAW_LIST, e1, e2, e3); } Expr VCL::listExpr(const string& op, const vector& kids) { vector newKids; newKids.push_back(idExpr(op)); newKids.insert(newKids.end(), kids.begin(), kids.end()); return listExpr(newKids); } Expr VCL::listExpr(const string& op, const Expr& e1) { return Expr(RAW_LIST, idExpr(op), e1); } Expr VCL::listExpr(const string& op, const Expr& e1, const Expr& e2) { return Expr(RAW_LIST, idExpr(op), e1, e2); } Expr VCL::listExpr(const string& op, const Expr& e1, const Expr& e2, const Expr& e3) { vector kids; kids.push_back(idExpr(op)); kids.push_back(e1); kids.push_back(e2); kids.push_back(e3); return listExpr(kids); } void VCL::printExpr(const Expr& e) { printExpr(e, cout); } void VCL::printExpr(const Expr& e, ostream& os) { os << e << endl; } Expr VCL::parseExpr(const Expr& e) { return d_theoryCore->parseExprTop(e); } Type VCL::parseType(const Expr& e) { return Type(d_theoryCore->parseExpr(e)); } Expr VCL::importExpr(const Expr& e) { return d_em->rebuild(e); } Type VCL::importType(const Type& t) { return Type(d_em->rebuild(t.getExpr())); } void VCL::cmdsFromString(const std::string& s, InputLanguage lang=PRESENTATION_LANG) { stringstream ss(s,stringstream::in); return loadFile(ss,lang,false); } Expr VCL::exprFromString(const std::string& s) { stringstream ss("PRINT " + s + ";",stringstream::in); Parser p(this,d_translator,PRESENTATION_LANG,ss); Expr e = p.next(); if( e.isNull() ) { throw ParserException("Parser result is null: '" + s + "'"); } DebugAssert(e.getKind() == RAW_LIST, "Expected list expression"); DebugAssert(e.arity() == 2, "Expected two children"); return parseExpr(e[1]); } Expr VCL::trueExpr() { return d_em->trueExpr(); } Expr VCL::falseExpr() { return d_em->falseExpr(); } Expr VCL::notExpr(const Expr& child) { return !child; } Expr VCL::andExpr(const Expr& left, const Expr& right) { return left && right; } Expr VCL::andExpr(const vector& children) { if (children.size() == 0) throw Exception("andExpr requires at least one child"); return Expr(AND, children); } Expr VCL::orExpr(const Expr& left, const Expr& right) { return left || right; } Expr VCL::orExpr(const vector& children) { if (children.size() == 0) throw Exception("orExpr requires at least one child"); return Expr(OR, children); } Expr VCL::impliesExpr(const Expr& hyp, const Expr& conc) { return hyp.impExpr(conc); } Expr VCL::iffExpr(const Expr& left, const Expr& right) { return left.iffExpr(right); } Expr VCL::eqExpr(const Expr& child0, const Expr& child1) { return child0.eqExpr(child1); } Expr VCL::distinctExpr(const std::vector& children) { return Expr(DISTINCT, children); } Expr VCL::iteExpr(const Expr& ifpart, const Expr& thenpart, const Expr& elsepart) { return ifpart.iteExpr(thenpart, elsepart); } Op VCL::createOp(const string& name, const Type& type) { if (!type.isFunction()) throw Exception("createOp: expected function type"); if(d_dump) { d_translator->dump(Expr(CONST, idExpr(name), type.getExpr())); } return d_theoryCore->newFunction(name, type, getFlags()["trans-closure"].getBool()); } Op VCL::createOp(const string& name, const Type& type, const Expr& def) { if (!type.isFunction()) throw TypecheckException ("Type error in createOp:\n" "Constant "+name+ " is declared with type:\n " +type.toString() +"\n which is not a function type"); if (getBaseType(type) != getBaseType(def.getType())) throw TypecheckException ("Type mismatch in createOp:\n" "Function "+name+ " is declared with type:\n " +type.toString() +"\nBut the type of definition is\n " +def.getType().toString() +"\n\n which does not match"); if(d_dump) { d_translator->dump(Expr(CONST, idExpr(name), type.getExpr(), def), true); } // Prove the TCCs of the definition if(getFlags()["tcc"].getBool()) { Type tpDef(def.getType()); // Make sure that def is within the subtype; that is, prove // FORALL (xs: argType): typePred_{return_type}(def(xs)) if(tpDef != type) { vector boundVars; for (int i = 0; i < type.arity()-1; ++i) { boundVars.push_back(d_em->newBoundVarExpr(type[i])); } Expr app = Expr(def.mkOp(), boundVars); Expr body(getTypePred(type[type.arity()-1], app)); Expr quant(forallExpr(boundVars, body)); Expr tcc = quant.andExpr(d_theoryCore->getTCC(quant)); // Query the subtyping formula bool typesMatch = true; try { checkTCC(tcc); } catch (TypecheckException&) { typesMatch = false; } if(!typesMatch) { throw TypecheckException ("Type mismatch in createOp:\n" "Function "+name+ " is declared with type:\n " +type.toString() +"\nBut the definition is\n " +def.toString() +"\n\nwhose type could not be proved to be a subtype"); } } } return d_theoryCore->newFunction(name, type, def); } Op VCL::lookupOp(const string& name, Type* type) { return d_theoryCore->lookupFunction(name, type); } Expr VCL::funExpr(const Op& op, const Expr& child) { return Expr(op, child); } Expr VCL::funExpr(const Op& op, const Expr& left, const Expr& right) { return Expr(op, left, right); } Expr VCL::funExpr(const Op& op, const Expr& child0, const Expr& child1, const Expr& child2) { return Expr(op, child0, child1, child2); } Expr VCL::funExpr(const Op& op, const vector& children) { return Expr(op, children); } bool VCL::addPairToArithOrder(const Expr& smaller, const Expr& bigger) { if (d_dump) { d_translator->dump(Expr(ARITH_VAR_ORDER, smaller, bigger), true); } return d_theoryArith->addPairToArithOrder(smaller, bigger); } Expr VCL::ratExpr(int n, int d) { DebugAssert(d != 0,"denominator cannot be 0"); return d_em->newRatExpr(Rational(n,d)); } Expr VCL::ratExpr(const string& n, const string& d, int base) { return d_em->newRatExpr(Rational(n.c_str(), d.c_str(), base)); } Expr VCL::ratExpr(const string& n, int base) { string::size_type pos = n.rfind("."); if (pos == string::npos) { return d_em->newRatExpr(Rational(n.c_str(), base)); } string afterdec = n.substr(pos+1); string beforedec = n.substr(0, pos); if (afterdec.size() == 0 || beforedec.size() == 0) { throw Exception("Cannot convert string to rational: "+n); } pos = beforedec.rfind("."); if (pos != string::npos) { throw Exception("Cannot convert string to rational: "+n); } Rational r = Rational(beforedec.c_str(), base); Rational fracPart = Rational(afterdec.c_str(), base); if( r < 0 || ((r == 0) && (beforedec.rfind("-") != string::npos)) ) { r = r - (fracPart / pow(afterdec.size(), (Rational)base)); } else { r = r + (fracPart / pow(afterdec.size(), (Rational)base)); } return d_em->newRatExpr(r); } Expr VCL::uminusExpr(const Expr& child) { return -child; } Expr VCL::plusExpr(const Expr& left, const Expr& right) { return left + right; } Expr VCL::plusExpr(const std::vector& children) { return Expr(PLUS, children); } Expr VCL::minusExpr(const Expr& left, const Expr& right) { return left - right; } Expr VCL::multExpr(const Expr& left, const Expr& right) { return left * right; } Expr VCL::powExpr(const Expr& x, const Expr& n) { return ::powExpr(n, x); } Expr VCL::divideExpr(const Expr& num, const Expr& denom) { return ::divideExpr(num,denom); } Expr VCL::ltExpr(const Expr& left, const Expr& right) { return ::ltExpr(left, right); } Expr VCL::leExpr(const Expr& left, const Expr& right) { return ::leExpr(left, right); } Expr VCL::gtExpr(const Expr& left, const Expr& right) { return ::gtExpr(left, right); } Expr VCL::geExpr(const Expr& left, const Expr& right) { return ::geExpr(left, right); } Expr VCL::recordExpr(const string& field, const Expr& expr) { vector fields; vector kids; kids.push_back(expr); fields.push_back(field); return d_theoryRecords->recordExpr(fields, kids); } Expr VCL::recordExpr(const string& field0, const Expr& expr0, const string& field1, const Expr& expr1) { vector fields; vector kids; fields.push_back(field0); fields.push_back(field1); kids.push_back(expr0); kids.push_back(expr1); sort2(fields, kids); return d_theoryRecords->recordExpr(fields, kids); } Expr VCL::recordExpr(const string& field0, const Expr& expr0, const string& field1, const Expr& expr1, const string& field2, const Expr& expr2) { vector fields; vector kids; fields.push_back(field0); fields.push_back(field1); fields.push_back(field2); kids.push_back(expr0); kids.push_back(expr1); kids.push_back(expr2); sort2(fields, kids); return d_theoryRecords->recordExpr(fields, kids); } Expr VCL::recordExpr(const vector& fields, const vector& exprs) { DebugAssert(fields.size() > 0, "VCL::recordExpr()"); DebugAssert(fields.size() == exprs.size(),"VCL::recordExpr()"); // Create copies of the vectors to sort them vector fs(fields); vector es(exprs); sort2(fs, es); return d_theoryRecords->recordExpr(fs, es); } Expr VCL::recSelectExpr(const Expr& record, const string& field) { return d_theoryRecords->recordSelect(record, field); } Expr VCL::recUpdateExpr(const Expr& record, const string& field, const Expr& newValue) { return d_theoryRecords->recordUpdate(record, field, newValue); } Expr VCL::readExpr(const Expr& array, const Expr& index) { return Expr(READ, array, index); } Expr VCL::writeExpr(const Expr& array, const Expr& index, const Expr& newValue) { return Expr(WRITE, array, index, newValue); } Expr VCL::newBVConstExpr(const std::string& s, int base) { return d_theoryBitvector->newBVConstExpr(s, base); } Expr VCL::newBVConstExpr(const std::vector& bits) { return d_theoryBitvector->newBVConstExpr(bits); } Expr VCL::newBVConstExpr(const Rational& r, int len) { return d_theoryBitvector->newBVConstExpr(r, len); } Expr VCL::newConcatExpr(const Expr& t1, const Expr& t2) { return d_theoryBitvector->newConcatExpr(t1, t2); } Expr VCL::newConcatExpr(const std::vector& kids) { return d_theoryBitvector->newConcatExpr(kids); } Expr VCL::newBVExtractExpr(const Expr& e, int hi, int low) { return d_theoryBitvector->newBVExtractExpr(e, hi, low); } Expr VCL::newBVNegExpr(const Expr& t1) { return d_theoryBitvector->newBVNegExpr(t1); } Expr VCL::newBVAndExpr(const Expr& t1, const Expr& t2) { return d_theoryBitvector->newBVAndExpr(t1, t2); } Expr VCL::newBVAndExpr(const std::vector& kids) { return d_theoryBitvector->newBVAndExpr(kids); } Expr VCL::newBVOrExpr(const Expr& t1, const Expr& t2) { return d_theoryBitvector->newBVOrExpr(t1, t2); } Expr VCL::newBVOrExpr(const std::vector& kids) { return d_theoryBitvector->newBVOrExpr(kids); } Expr VCL::newBVXorExpr(const Expr& t1, const Expr& t2) { return d_theoryBitvector->newBVXorExpr(t1, t2); } Expr VCL::newBVXorExpr(const std::vector& kids) { return d_theoryBitvector->newBVXorExpr(kids); } Expr VCL::newBVXnorExpr(const Expr& t1, const Expr& t2) { return d_theoryBitvector->newBVXnorExpr(t1, t2); } Expr VCL::newBVXnorExpr(const std::vector& kids) { return d_theoryBitvector->newBVXnorExpr(kids); } Expr VCL::newBVNandExpr(const Expr& t1, const Expr& t2) { return d_theoryBitvector->newBVNandExpr(t1, t2); } Expr VCL::newBVNorExpr(const Expr& t1, const Expr& t2) { return d_theoryBitvector->newBVNorExpr(t1, t2); } Expr VCL::newBVCompExpr(const Expr& t1, const Expr& t2) { return d_theoryBitvector->newBVCompExpr(t1, t2); } Expr VCL::newBVLTExpr(const Expr& t1, const Expr& t2) { return d_theoryBitvector->newBVLTExpr(t1, t2); } Expr VCL::newBVLEExpr(const Expr& t1, const Expr& t2) { return d_theoryBitvector->newBVLEExpr(t1, t2); } Expr VCL::newBVSLTExpr(const Expr& t1, const Expr& t2) { return d_theoryBitvector->newBVSLTExpr(t1, t2); } Expr VCL::newBVSLEExpr(const Expr& t1, const Expr& t2) { return d_theoryBitvector->newBVSLEExpr(t1, t2); } Expr VCL::newSXExpr(const Expr& t1, int len) { return d_theoryBitvector->newSXExpr(t1, len); } Expr VCL::newBVUminusExpr(const Expr& t1) { return d_theoryBitvector->newBVUminusExpr(t1); } Expr VCL::newBVSubExpr(const Expr& t1, const Expr& t2) { return d_theoryBitvector->newBVSubExpr(t1, t2); } Expr VCL::newBVPlusExpr(int numbits, const std::vector& k) { return d_theoryBitvector->newBVPlusPadExpr(numbits, k); } Expr VCL::newBVPlusExpr(int numbits, const Expr& t1, const Expr& t2) { std::vector k; k.push_back(t1); k.push_back(t2); return newBVPlusExpr(numbits, k); } Expr VCL::newBVMultExpr(int numbits, const Expr& t1, const Expr& t2) { return d_theoryBitvector->newBVMultPadExpr(numbits, t1, t2); } Expr VCL::newBVUDivExpr(const Expr& t1, const Expr& t2) { return d_theoryBitvector->newBVUDivExpr(t1, t2); } Expr VCL::newBVURemExpr(const Expr& t1, const Expr& t2) { return d_theoryBitvector->newBVURemExpr(t1, t2); } Expr VCL::newBVSDivExpr(const Expr& t1, const Expr& t2) { return d_theoryBitvector->newBVSDivExpr(t1, t2); } Expr VCL::newBVSRemExpr(const Expr& t1, const Expr& t2) { return d_theoryBitvector->newBVSRemExpr(t1, t2); } Expr VCL::newBVSModExpr(const Expr& t1, const Expr& t2) { return d_theoryBitvector->newBVSModExpr(t1, t2); } Expr VCL::newFixedLeftShiftExpr(const Expr& t1, int r) { return d_theoryBitvector->newFixedLeftShiftExpr(t1, r); } Expr VCL::newFixedConstWidthLeftShiftExpr(const Expr& t1, int r) { return d_theoryBitvector->newFixedConstWidthLeftShiftExpr(t1, r); } Expr VCL::newFixedRightShiftExpr(const Expr& t1, int r) { return d_theoryBitvector->newFixedRightShiftExpr(t1, r); } Expr VCL::newBVSHL(const Expr& t1, const Expr& t2) { return Expr(BVSHL, t1, t2); } Expr VCL::newBVLSHR(const Expr& t1, const Expr& t2) { return Expr(BVLSHR, t1, t2); } Expr VCL::newBVASHR(const Expr& t1, const Expr& t2) { return Expr(BVASHR, t1, t2); } Rational VCL::computeBVConst(const Expr& e) { return d_theoryBitvector->computeBVConst(e); } Expr VCL::tupleExpr(const vector& exprs) { DebugAssert(exprs.size() > 0, "VCL::tupleExpr()"); return d_theoryRecords->tupleExpr(exprs); } Expr VCL::tupleSelectExpr(const Expr& tuple, int index) { return d_theoryRecords->tupleSelect(tuple, index); } Expr VCL::tupleUpdateExpr(const Expr& tuple, int index, const Expr& newValue) { return d_theoryRecords->tupleUpdate(tuple, index, newValue); } Expr VCL::datatypeConsExpr(const string& constructor, const vector& args) { return d_theoryDatatype->datatypeConsExpr(constructor, args); } Expr VCL::datatypeSelExpr(const string& selector, const Expr& arg) { return d_theoryDatatype->datatypeSelExpr(selector, arg); } Expr VCL::datatypeTestExpr(const string& constructor, const Expr& arg) { return d_theoryDatatype->datatypeTestExpr(constructor, arg); } Expr VCL::boundVarExpr(const string& name, const string& uid, const Type& type) { return d_em->newBoundVarExpr(name, uid, type); } Expr VCL::forallExpr(const vector& vars, const Expr& body) { DebugAssert(vars.size() > 0, "VCL::foralLExpr()"); return d_em->newClosureExpr(FORALL, vars, body); } Expr VCL::forallExpr(const vector& vars, const Expr& body, const Expr& trigger) { DebugAssert(vars.size() > 0, "VCL::foralLExpr()"); return d_em->newClosureExpr(FORALL, vars, body, trigger); } Expr VCL::forallExpr(const vector& vars, const Expr& body, const vector& triggers) { DebugAssert(vars.size() > 0, "VCL::foralLExpr()"); return d_em->newClosureExpr(FORALL, vars, body, triggers); } Expr VCL::forallExpr(const vector& vars, const Expr& body, const vector >& triggers) { DebugAssert(vars.size() > 0, "VCL::foralLExpr()"); return d_em->newClosureExpr(FORALL, vars, body, triggers); } void VCL::setTriggers(const Expr& e, const vector< vector >& triggers) { e.setTriggers(triggers); } void VCL::setTriggers(const Expr& e, const vector& triggers) { e.setTriggers(triggers); } void VCL::setTrigger(const Expr& e, const Expr& trigger) { e.setTrigger(trigger); } void VCL::setMultiTrigger(const Expr& e, const vector& multiTrigger) { e.setMultiTrigger(multiTrigger); } Expr VCL::existsExpr(const vector& vars, const Expr& body) { return d_em->newClosureExpr(EXISTS, vars, body); } Op VCL::lambdaExpr(const vector& vars, const Expr& body) { return d_em->newClosureExpr(LAMBDA, vars, body).mkOp(); } Op VCL::transClosure(const Op& op) { const string& name = op.getExpr().getName(); return d_em->newSymbolExpr(name, TRANS_CLOSURE).mkOp(); } Expr VCL::simulateExpr(const Expr& f, const Expr& s0, const vector& inputs, const Expr& n) { vector kids; kids.push_back(f); kids.push_back(s0); kids.insert(kids.end(), inputs.begin(), inputs.end()); kids.push_back(n); return Expr(SIMULATE, kids); } void VCL::setResourceLimit(unsigned limit) { d_theoryCore->setResourceLimit(limit); } Theorem VCL::checkTCC(const Expr& tcc) { Theorem tccThm; d_se->push(); QueryResult res = d_se->checkValid(tcc, tccThm); switch (res) { case VALID: d_lastQueryTCC = tccThm; d_se->pop(); break; case INVALID: throw TypecheckException("Failed TCC:\n\n " +tcc.toString() +"\n\nWhich simplified to:\n\n " +simplify(tcc).toString() +"\n\nAnd the last formula is not valid " "in the current context."); case ABORT: throw TypecheckException("Budget exceeded:\n\n " "Unable to verify TCC:\n\n " +tcc.toString() +"\n\nWhich simplified to:\n\n " +simplify(tcc).toString()); case UNKNOWN: throw TypecheckException("Result unknown:\n\n " "Unable to verify TCC:\n\n " +tcc.toString() +"\n\nWhich simplified to:\n\n " +simplify(tcc).toString() +"\n\nAnd the last formula is unknown " "in the current context."); default: FatalAssert(false, "Unexpected case"); } return tccThm; } void VCL::assertFormula(const Expr& e) { if (getFlags()["no-save-model"].getBool() && d_modelStackPushed) { d_modelStackPushed = false; pop(); } // Typecheck the user input if(!e.getType().isBool()) { throw TypecheckException("Non-BOOLEAN formula in ASSERT:\n " +Expr(ASSERT, e).toString() +"\nDerived type of the formula:\n " +e.getType().toString()); } if (getFlags()["pp-batch"].getBool()) { d_batchedAssertions->push_back(e); } else { // Check if the ofstream is open (as opposed to the command line flag) if(d_dump) { Expr e2 = e; if (getFlags()["preSimplify"].getBool()) { e2 = d_theoryCore->getExprTrans()->preprocess(e).getRHS(); } if (d_translator->dumpAssertion(e2)) return; } TRACE("vclassertFormula", "VCL::assertFormula(", e, ") {"); // See if e was already asserted before if(d_userAssertions->count(e) > 0) { TRACE_MSG("vclassertFormula", "VCL::assertFormula[repeated assertion] => }"); return; } // Check the validity of the TCC Theorem tccThm; if(getFlags()["tcc"].getBool()) { Expr tcc(d_theoryCore->getTCC(e)); tccThm = checkTCC(tcc); } Theorem thm = d_se->newUserAssumption(e); (*d_userAssertions)[e] = UserAssertion(thm, tccThm, d_nextIdx++); } TRACE_MSG("vclassertFormula", "VCL::assertFormula => }"); } void VCL::registerAtom(const Expr& e) { //TODO: add to interactive interface d_se->registerAtom(e); } Expr VCL::getImpliedLiteral() { //TODO: add to interactive interface Theorem thm = d_se->getImpliedLiteral(); if (thm.isNull()) return Expr(); return thm.getExpr(); } Expr VCL::simplify(const Expr& e) { //TODO: add to interactive interface return simplifyThm(e).getRHS(); } Theorem VCL::simplifyThm(const Expr& e) { e.getType(); Theorem res = d_theoryCore->getExprTrans()->preprocess(e); Theorem simpThm = d_theoryCore->simplify(res.getRHS()); res = d_theoryCore->transitivityRule(res, simpThm); return res; } QueryResult VCL::query(const Expr& e) { TRACE("query", "VCL::query(", e,") {"); if (getFlags()["no-save-model"].getBool()) { if(d_modelStackPushed) { d_modelStackPushed = false; pop(); } push(); d_modelStackPushed = true; } // Typecheck the user input if(!e.getType().isBool()) { throw TypecheckException("Non-BOOLEAN formula in QUERY:\n " +Expr(QUERY, e).toString() +"\nDerived type of the formula:\n " +e.getType().toString()); } Expr qExpr = e; if (getFlags()["pp-batch"].getBool()) { // Add batched assertions vector kids; for (; (*d_batchedAssertionsIdx) < d_batchedAssertions->size(); (*d_batchedAssertionsIdx) = (*d_batchedAssertionsIdx) + 1) { kids.push_back((*d_batchedAssertions)[(*d_batchedAssertionsIdx)]); } if (kids.size() > 0) { qExpr = kids.size() == 1 ? kids[0] : Expr(AND, kids); qExpr = qExpr.impExpr(e); } } if (d_dump && !getFlags()["dump-tcc"].getBool()) { Expr e2 = qExpr; if (getFlags()["preSimplify"].getBool()) { e2 = d_theoryCore->getExprTrans()->preprocess(qExpr).getRHS(); } if (d_translator->dumpQuery(e2)) return UNKNOWN; } // Check the validity of the TCC Theorem tccThm = d_se->getCommonRules()->trueTheorem(); if(getFlags()["tcc"].getBool()) { Expr tcc(d_theoryCore->getTCC(qExpr)); if (getFlags()["dump-tcc"].getBool()) { Expr e2 = tcc; if (getFlags()["preSimplify"].getBool()) { e2 = d_theoryCore->getExprTrans()->preprocess(tcc).getRHS(); } if (d_translator->dumpQuery(e2)) return UNKNOWN; } // FIXME: we have to guarantee that the TCC of 'tcc' is always valid tccThm = checkTCC(tcc); } Theorem res; QueryResult qres = d_se->checkValid(qExpr, res); switch (qres) { case VALID: d_lastQuery = d_se->getCommonRules()->queryTCC(res, tccThm); break; default: d_lastQueryTCC = Theorem(); d_lastQuery = Theorem3(); d_lastClosure = Theorem3(); } TRACE("query", "VCL::query => ", qres == VALID ? "VALID" : qres == INVALID ? "INVALID" : qres == ABORT ? "ABORT" : "UNKNOWN", " }"); if (d_dump) d_translator->dumpQueryResult(qres); return qres; } QueryResult VCL::checkUnsat(const Expr& e) { return query(e.negate()); } QueryResult VCL::checkContinue() { if(d_dump) { d_translator->dump(d_em->newLeafExpr(CONTINUE), true); } vector assertions; d_se->getCounterExample(assertions); Theorem thm; if (assertions.size() == 0) { return d_se->restart(falseExpr(), thm); } Expr eAnd = assertions.size() == 1 ? assertions[0] : andExpr(assertions); return d_se->restart(!eAnd, thm); } QueryResult VCL::restart(const Expr& e) { if (d_dump) { d_translator->dump(Expr(RESTART, e), true); } Theorem thm; return d_se->restart(e, thm); } void VCL::returnFromCheck() { //TODO: add to interactive interface d_se->returnFromCheck(); } void VCL::getUserAssumptions(vector& assumptions) { // TODO: add to interactive interface d_se->getUserAssumptions(assumptions); } void VCL::getInternalAssumptions(vector& assumptions) { // TODO: add to interactive interface d_se->getInternalAssumptions(assumptions); } void VCL::getAssumptions(vector& assumptions) { if(d_dump) { d_translator->dump(d_em->newLeafExpr(ASSUMPTIONS), true); } d_se->getAssumptions(assumptions); } //yeting, for proof translation Expr VCL::getProofQuery() { if (d_lastQuery.isNull()){ throw EvalException ("Invalid Query,n"); } return d_lastQuery.getExpr(); // Theorem thm = d_se->lastThm(); // if (thm.isNull()) return; // thm.getLeafAssumptions(assumptions); } void VCL::getAssumptionsUsed(vector& assumptions) { throw EvalException ("getAssumptionsUsed not currently supported"); if(d_dump) { d_translator->dump(d_em->newLeafExpr(DUMP_ASSUMPTIONS), true); } Theorem thm = d_se->lastThm(); if (thm.isNull()) return; thm.getLeafAssumptions(assumptions); } void VCL::getCounterExample(vector& assertions, bool inOrder) { if(d_dump) { d_translator->dump(d_em->newLeafExpr(COUNTEREXAMPLE), true); } if (!(*d_flags)["translate"].getBool()) d_se->getCounterExample(assertions, inOrder); } void VCL::getConcreteModel(ExprMap & m) { if(d_dump) { d_translator->dump(d_em->newLeafExpr(COUNTERMODEL), true); } if (!(*d_flags)["translate"].getBool()) d_se->getConcreteModel(m); } QueryResult VCL::tryModelGeneration() { if (!d_theoryCore->incomplete()) throw Exception("Model generation should be called only after an UNKNOWN result"); QueryResult qres = UNKNOWN; int scopeLevel = d_cm->scopeLevel(); try { while (qres == UNKNOWN) { Theorem thm; d_se->push(); // Try to generate the model if (d_se->tryModelGeneration(thm)) // If success, we are satisfiable qres = INVALID; else { // Generate the clause to get rid of the faults vector assumptions; thm.getLeafAssumptions(assumptions, true /*negate*/); if (!thm.getExpr().isFalse()) assumptions.push_back(thm.getExpr()); // Pop back to where we were while (d_cm->scopeLevel() > scopeLevel) d_se->pop(); // Restart with the new clause qres = restart(orExpr(assumptions)); // Keep this level scopeLevel = d_cm->scopeLevel(); } } } catch (Exception& e) { // Pop back to where we were while (d_cm->scopeLevel() > scopeLevel) d_se->pop(); } return qres; } FormulaValue VCL::value(const Expr& e) { DebugAssert(!e.isTerm(), "vcl::value: e is not a formula"); return d_se->getValue(e); } bool VCL::inconsistent(vector& assumptions) { // TODO: add to interactive interface if (d_theoryCore->inconsistent()) { // TODO: do we need local getAssumptions? getAssumptions(d_theoryCore->inconsistentThm().getAssumptionsRef(), assumptions); return true; } return false; } bool VCL::inconsistent() { return d_theoryCore->inconsistent(); } bool VCL::incomplete() { // TODO: add to interactive interface // Return true only after a failed query return (d_lastQuery.isNull() && d_theoryCore->incomplete()); } bool VCL::incomplete(vector& reasons) { // TODO: add to interactive interface // Return true only after a failed query return (d_lastQuery.isNull() && d_theoryCore->incomplete(reasons)); } Proof VCL::getProof() { if(d_dump) { d_translator->dump(d_em->newLeafExpr(DUMP_PROOF), true); } if(d_lastQuery.isNull()) throw EvalException ("Method getProof() (or command DUMP_PROOF)\n" " must be called only after a Valid QUERY"); return d_se->getProof(); } Expr VCL::getAssignment() { if(d_dump) { d_translator->dump(d_em->newLeafExpr(GET_ASSIGNMENT), true); } return d_theoryCore->getAssignment(); } Expr VCL::getValue(Expr e) { if(d_dump) { d_translator->dump(Expr(GET_VALUE, e), true); } return simplify(e); } Expr VCL::getTCC(){ static Expr null; if(d_dump) { d_translator->dump(d_em->newLeafExpr(DUMP_TCC), true); } if(d_lastQueryTCC.isNull()) return null; else return d_lastQueryTCC.getExpr(); } void VCL::getAssumptionsTCC(vector& assumptions) { if(d_dump) { d_translator->dump(d_em->newLeafExpr(DUMP_TCC_ASSUMPTIONS), true); } if(d_lastQuery.isNull()) throw EvalException ("Method getAssumptionsTCC() (or command DUMP_TCC_ASSUMPTIONS)\n" " must be called only after a Valid QUERY"); getAssumptions(d_lastQueryTCC.getAssumptionsRef(), assumptions); } Proof VCL::getProofTCC() { static Proof null; if(d_dump) { d_translator->dump(d_em->newLeafExpr(DUMP_TCC_PROOF), true); } if(d_lastQueryTCC.isNull()) return null; else return d_lastQueryTCC.getProof(); } Expr VCL::getClosure() { static Expr null; if(d_dump) { d_translator->dump(d_em->newLeafExpr(DUMP_CLOSURE), true); } if(d_lastClosure.isNull() && !d_lastQuery.isNull()) { // Construct the proof of closure and cache it in d_lastClosure d_lastClosure = deriveClosure(d_lastQuery); } if(d_lastClosure.isNull()) return null; else return d_lastClosure.getExpr(); } Proof VCL::getProofClosure() { static Proof null; if(d_dump) { d_translator->dump(d_em->newLeafExpr(DUMP_CLOSURE_PROOF), true); } if(d_lastClosure.isNull() && !d_lastQuery.isNull()) { // Construct the proof of closure and cache it in d_lastClosure d_lastClosure = deriveClosure(d_lastQuery); } if(d_lastClosure.isNull()) return null; else return d_lastClosure.getProof(); } int VCL::stackLevel() { return d_stackLevel->get(); } void VCL::push() { if (getFlags()["no-save-model"].getBool() && d_modelStackPushed) { d_modelStackPushed = false; pop(); } else if (d_dump) { d_translator->dump(d_em->newLeafExpr(PUSH), true); } d_se->push(); d_stackLevel->set(stackLevel()+1); } void VCL::pop() { if (getFlags()["no-save-model"].getBool() && d_modelStackPushed) { d_modelStackPushed = false; pop(); } else if (d_dump) { d_translator->dump(d_em->newLeafExpr(POP), true); } if (stackLevel() == 0) { throw EvalException ("POP called with no previous call to PUSH"); } int level = stackLevel(); while (level == stackLevel()) d_se->pop(); } void VCL::popto(int toLevel) { // Check if the ofstream is open (as opposed to the command line flag) if(d_dump) { d_translator->dump(Expr(POPTO, ratExpr(toLevel, 1)), true); } if (toLevel < 0) toLevel = 0; while (stackLevel() > toLevel) { d_se->pop(); } } int VCL::scopeLevel() { return d_cm->scopeLevel(); } void VCL::pushScope() { throw EvalException ("Scope-level push/pop is no longer supported"); d_cm->push(); if(d_dump) { d_translator->dump(d_em->newLeafExpr(PUSH_SCOPE), true); } IF_DEBUG(if((*d_flags)["dump-trace"].getString() != "") dumpTrace(scopeLevel());) } void VCL::popScope() { throw EvalException ("Scope-level push/pop is no longer supported"); if(d_dump) { d_translator->dump(d_em->newLeafExpr(POP_SCOPE), true); } if (scopeLevel() == 1) { cout << "Cannot POP from scope level 1" << endl; } else d_cm->pop(); IF_DEBUG(if((*d_flags)["dump-trace"].getString() != "") dumpTrace(scopeLevel());) } void VCL::poptoScope(int toLevel) { throw EvalException ("Scope-level push/pop is no longer supported"); if(d_dump) { d_translator->dump(Expr(POPTO_SCOPE, ratExpr(toLevel, 1)), true); } if (toLevel < 1) { d_cm->popto(0); d_cm->push(); } else d_cm->popto(toLevel); IF_DEBUG(if((*d_flags)["dump-trace"].getString() != "") dumpTrace(scopeLevel());) } Context* VCL::getCurrentContext() { return d_cm->getCurrentContext(); } void VCL::reset() { destroy(); init(); } void VCL::logAnnotation(const Expr& annot) { if (d_dump) { d_translator->dump(annot); } } void VCL::loadFile(const string& fileName, InputLanguage lang, bool interactive, bool calledFromParser) { // TODO: move these? Parser parser(this, d_translator, lang, interactive, fileName); VCCmd cmd(this, &parser, calledFromParser); cmd.processCommands(); } void VCL::loadFile(istream& is, InputLanguage lang, bool interactive) { // TODO: move these? Parser parser(this, d_translator, lang, is, interactive); VCCmd cmd(this, &parser); cmd.processCommands(); } // Verbosity: <= 0 = print nothing, only calculate // 1 = only print current level // n = print n recursive levels unsigned long VCL::getMemory(int verbosity) { unsigned long memSelf = sizeof(VCL); unsigned long mem = 0; mem += d_cm->getMemory(verbosity - 1); mem += d_em->getMemory(verbosity - 1); // mem += d_tm->getMemory(verbosity - 1); // mem += d_se->getMemory(verbosity - 1); // mem += d_theoryCore->getMemory(verbosity - 1); // mem += d_theoryUF->getMemory(verbosity - 1); // mem += d_theoryArith->getMemory(verbosity - 1); // mem += d_theoryArray->getMemory(verbosity - 1); // mem += d_theoryQuant->getMemory(verbosity - 1); // mem += d_theoryRecords->getMemory(verbosity - 1); // mem += d_theorySimulate->getMemory(verbosity - 1); // mem += d_theoryBitvector->getMemory(verbosity - 1); // mem += d_theoryDatatype->getMemory(verbosity - 1); // mem += d_translator->getMemory(verbosity - 1); // mem += getMemoryVec(verbosity, d_theories, false, true); // mem += d_flags->getMemory(verbosity - 1); // mem += d_stackLevel->getMemory(verbosity - 1); // mem += d_statistics->getMemory(verbosity - 1); // mem += d_userAssertions->getMemory(verbosity - 1); // mem += d_batchedAssertions->getMemory(verbosity - 1); // mem += d_batchedAssertionsIdx->getMemory(verbosity - 1); //TODO: how to get memory for Expr and Theorems? MemoryTracker::print("VCL", verbosity, memSelf, mem); return mem + memSelf; } void VCL::setTimeLimit(unsigned limit) { d_theoryCore->setTimeLimit(limit); } cvc3-2.4.1/src/sat/0000775000175400017540000000000011630011320013617 5ustar mdetersmdeterscvc3-2.4.1/src/sat/sat_proof.h0000664000175400017540000000724211277111610016003 0ustar mdetersmdeters/*****************************************************************************/ /*! *\file sat_proof.h *\brief Sat solver proof representation * * Author: Alexander Fuchs * * Created: Sun Dec 07 11:09:00 2007 * *
* * License to use, copy, modify, sell and/or distribute this software * and its documentation for any purpose is hereby granted without * royalty, subject to the terms and conditions defined in the \ref * LICENSE file provided with this distribution. * *
*/ /*****************************************************************************/ #ifndef _cvc3__sat__proof_h_ #define _cvc3__sat__proof_h_ #include "theorem.h" #include namespace SAT { // a node in a resolution tree, either: // - a leaf // then d_clause is a clause added to the sat solver by the cvc controller; // the other values are empty // - a binary node // then the node represents the clause which can be derived by resolution // between its left and right parent on d_lit, // where d_left contains d_lit and d_right contains the negation of d_lit class SatProofNode { private: CVC3::Theorem d_theorem; SatProofNode* d_left; SatProofNode* d_right; SAT::Lit d_lit; CVC3::Proof d_proof; // by yeting, to store the proof. We do not need to set a null value to proof bcause this is done by the constructor of proof public: SatProofNode(CVC3::Theorem theorem) : d_theorem(theorem), d_left(NULL), d_right(NULL){ DebugAssert(!theorem.isNull(), "SatProofNode: constructor"); } //we can modify the constructor of SatProofNode(clause) to store the clauses //add a method to return all clauses here SatProofNode(SatProofNode* left, SatProofNode* right, SAT::Lit lit) : d_left(left), d_right(right), d_lit(lit) { DebugAssert(d_left != NULL, "SatProofNode: constructor"); DebugAssert(d_right != NULL, "SatProofNode: constructor"); } bool isLeaf() { return !d_theorem.isNull(); } CVC3::Theorem getLeaf() { DebugAssert(isLeaf(), "SatProofNode: getLeaf"); return d_theorem; } SatProofNode* getLeftParent() { DebugAssert(!isLeaf(), "SatProofNode: getLeftParent"); return d_left; } SatProofNode* getRightParent() { DebugAssert(!isLeaf(), "SatProofNode: getRightParent"); return d_right; } SAT::Lit getLit() { DebugAssert(!isLeaf(), "SatProofNode: getLit"); return d_lit; } bool hasNodeProof() {return !d_proof.isNull();}; CVC3::Proof getNodeProof() {DebugAssert(!d_proof.isNull(), "SatProofNode: nodeProof get null"); return d_proof;} void setNodeProof(CVC3::Proof pf) { d_proof=pf;} }; // a proof of the clause d_root class SatProof { private: SatProofNode* d_root; std::list d_nodes; public: SatProof() : d_root(NULL) { }; ~SatProof() { for (std::list::iterator i = d_nodes.begin(); i != d_nodes.end(); ++i) { delete(*i); } } // build proof // ownership of created node remains with SatProof SatProofNode* registerLeaf(CVC3::Theorem theorem) { SatProofNode* node = new SatProofNode(theorem); d_nodes.push_back(node); return node; } // ownership of created node remains with SatProof SatProofNode* registerNode(SatProofNode* left, SatProofNode* right, SAT::Lit l) { SatProofNode* node = new SatProofNode(left, right, l); d_nodes.push_back(node); return node; } void setRoot(SatProofNode* root) { d_root = root; } // access proof // ownership of all nodes remains with SatProof SatProofNode* getRoot() { DebugAssert(d_root != NULL, "null root found in getRoot"); return d_root; } }; } #endif cvc3-2.4.1/src/sat/Makefile0000664000175400017540000000143010673337471015305 0ustar mdetersmdeters################################################## # About this Makefile # # This Makefile depends on Makefile.opts ################################################## MODULE = sat SRC = $(EXTRA_SAT_CPP) \ cnf.cpp \ cnf_manager.cpp \ cnf_theorem_producer.cpp \ dpllt_basic.cpp \ sat_api.cpp \ dpllt_minisat.cpp \ minisat_types.cpp \ minisat_derivation.cpp \ minisat_solver.cpp HEADERS = $(EXTRA_SAT_HEADERS) \ cnf_rules.h \ cnf_theorem_producer.h \ sat_proof.h \ minisat_global.h \ minisat_heap.h \ minisat_types.h \ minisat_varorder.h \ minisat_derivation.h \ minisat_solver.h LIBRARY=libsat.a EXTRAFLAGS=$(DPLL_BASIC) include ../../Makefile.local cvc3-2.4.1/src/sat/cnf.cpp0000664000175400017540000001054310716213261015110 0ustar mdetersmdeters/*****************************************************************************/ /*! *\file cnf.cpp *\brief Implementation of classes used for generic CNF formulas * * Author: Clark Barrett * * Created: Mon Dec 12 22:16:11 2005 * *
* * License to use, copy, modify, sell and/or distribute this software * and its documentation for any purpose is hereby granted without * royalty, subject to the terms and conditions defined in the \ref * LICENSE file provided with this distribution. * *
*/ /*****************************************************************************/ #include "cnf.h" using namespace std; using namespace CVC3; using namespace SAT; unsigned SAT::Clause::getMaxVar() const { unsigned max = 0; const_iterator i, iend; for (i = begin(), iend = end(); i != iend; ++i) { DebugAssert(!(*i).isNull(), "Null literal found in clause"); if (unsigned((*i).getVar()) > max) max = unsigned((*i).getVar()); } return max; } void SAT::Clause::print() const { if (isSatisfied()) cout << "*"; const_iterator i, iend; for (i = begin(), iend = end(); i != iend; ++i) { if ((*i).isNull()) cout << "NULL"; else if ((*i).isFalse()) cout << "F"; else if ((*i).isTrue()) cout << "T"; else { if (!(*i).isPositive()) cout << "-"; cout << (*i).getVar(); } cout << " "; } cout << endl; } void CNF_Formula::copy(const CNF_Formula& cnf) { setNumVars(0); Clause* c = d_current; // Don't use iterators in case cnf == *this unsigned i, iend; Clause::const_iterator j, jend; for (i = 0, iend = cnf.numClauses(); i != iend; ++i) { newClause(); for (j = cnf[i].begin(), jend = cnf[i].end(); j != jend; ++j) { addLiteral(*j); } Clause oldClause = cnf[i]; // CVC3::Theorem clauseThm = oldClause.getClauseTheorem(); CVC3::Theorem clauseThm = cnf[i].getClauseTheorem(); getCurrentClause().setClauseTheorem(clauseThm);//by yeting if (cnf[i].isUnit()) registerUnit(); if (&(cnf[i]) == cnf.d_current) c = d_current; } d_current = c; } void CNF_Formula::print() const { const_iterator i, iend; for (i = begin(), iend = end(); i != iend; ++i) { (*i).print(); } } const CNF_Formula& CNF_Formula::operator+=(const CNF_Formula& cnf) { Clause* c = d_current; // Don't use iterators in case cnf == *this unsigned i, iend; Clause::const_iterator j, jend; for (i = 0, iend = cnf.numClauses(); i != iend; ++i) { newClause(); for (j = cnf[i].begin(), jend = cnf[i].end(); j != jend; ++j) { addLiteral(*j); } Clause oldClause = cnf[i]; CVC3::Theorem clauseThm = oldClause.getClauseTheorem(); getCurrentClause().setClauseTheorem(clauseThm);//by yeting if (cnf[i].isUnit()) registerUnit(); } d_current = c; return *this; } const CNF_Formula& CNF_Formula::operator+=(const Clause& c) { Clause* cur = d_current; newClause(); Clause::const_iterator j, jend; for (j=c.begin(), jend = c.end(); j != jend; ++j) { addLiteral(*j); } Clause oldClause = c; CVC3::Theorem clauseThm = oldClause.getClauseTheorem(); getCurrentClause().setClauseTheorem(clauseThm);//by yeting if (c.isUnit()) registerUnit(); d_current = cur; return *this; } void CNF_Formula_Impl::newClause() { d_formula.resize(d_formula.size()+1); d_current = &(d_formula.back()); } void CNF_Formula_Impl::registerUnit() { DebugAssert(d_current->size()==1,"Expected unit clause"); d_current->setUnit(); Lit l = *(d_current->begin()); d_lits[l.getID()] = true; } void CNF_Formula_Impl::simplify() { deque::iterator i, iend; Clause::const_iterator j, jend; for (i = d_formula.begin(), iend = d_formula.end(); i != iend; ++i) { if ((*i).isUnit()) continue; for (j=(*i).begin(), jend = (*i).end(); j != jend; ++j) { if ((*j).isTrue()) { (*i).setSatisfied(); break; } hash_map::iterator it = d_lits.find((*j).getID()); if (it != d_lits.end()) { (*i).setSatisfied(); break; } } } } void CNF_Formula_Impl::reset() { d_formula.clear(); d_lits.clear(); d_current = NULL; d_numVars = 0; } void CD_CNF_Formula::newClause() { //TODO: don't call constructor twice d_current = &(d_formula.push_back(Clause())); } void CD_CNF_Formula::registerUnit() { DebugAssert(d_current->size()==1,"Expected unit clause"); d_current->setUnit(); } cvc3-2.4.1/src/sat/minisat_derivation.h0000664000175400017540000001701410675225354017711 0ustar mdetersmdeters/*****************************************************************************/ /*! *\file minisat_derivation.h *\brief MiniSat proof logging * * Author: Alexander Fuchs * * Created: Sun Dec 07 11:09:00 2007 * *
* * License to use, copy, modify, sell and/or distribute this software * and its documentation for any purpose is hereby granted without * royalty, subject to the terms and conditions defined in the \ref * LICENSE file provided with this distribution. * *
*/ /*****************************************************************************/ #ifndef _cvc3__sat__minisat_derivation_h_ #define _cvc3__sat__minisat_derivation_h_ #include "minisat_types.h" #include #include #include #include #include #include #include namespace SAT { class SatProof; } namespace MiniSat { // a resolution inference as a sequence of binary resolution steps class Inference { public: typedef std::vector > TSteps; private: // id of first clause int d_start; // binary resolution step: // result of previous step (or d_start) // on literal with next clause (given by id) TSteps d_steps; public: Inference(int clauseID) : d_start(clauseID) { // std::cout << "Start inference: " << clauseID << std::endl; }; void add(Lit lit, int clauseID) { d_steps.push_back(std::make_pair(lit, clauseID)); }; void add(Lit lit, Clause* clause) { add(lit, clause->id()); }; int getStart() const { return d_start; } const TSteps& getSteps() const { return d_steps; } // returns steps as a lits: clauseId0 literal0.toString clauseID1 ... std::string toString() const; }; class Solver; // Heavily based on the proof logging version of MiniSat (1.14p) // // Note: this implementation keeps the whole derivation in memory - // for many problems this is not feasible. // should provide an alternative implementation that logs the derivation // to a file and constructs the proof from it. class Derivation { public: typedef Hash::hash_map TClauses; typedef Hash::hash_set TInputClauses; typedef Hash::hash_map TInferences; private: // mapping from id to clause TClauses d_clauses; // as an additional check, explicitely mark which clauses are input clauses // by adding their id to this set. // // as an invariant an id should be either in d_inferences or d_inputClauses, // as a clause does exactly have no inference attached if it is an input clause. TInputClauses d_inputClauses; // unit clauses derived with computeRootReason // mapping from index of literal to clause TClauses d_unitClauses; // mapping from clause id to the inference it was derived by TInferences d_inferences; // clauses removed from the solver std::deque d_removedClauses; // empty clause of derivation, if derived Clause* d_emptyClause; public: Derivation() : d_emptyClause(NULL) {}; ~Derivation(); // note: allow for duplicate insertion of clauses registerClause and registerInputClause, // as this can happen in the current implementation // for theory clauses which are inconsistent on insertion. // register a new clause void registerClause(Clause* clause) { // std::cout << "register clause : " << clause->id() << " : " << clause->toString() << std::endl; //IF_DEBUG ( if (d_clauses.contains(clause->id())) { // if clause with id does already exist, // then it must be a simplification of the original clause Clause* old = d_clauses[clause->id()]; FatalAssert(old->size() == clause->size(), "MiniSat::Derivation::registerClause: new clause of different size than old clause of same id"); std::set oldS; for (int i = 0; i < old->size(); ++i) { oldS.insert((*old)[i]); } for (int i = 0; i < clause->size(); ++i) { FatalAssert(oldS.find((*clause)[i]) != oldS.end(), "MiniSat::Derivation::registerClause: new clause not subset of old clause of same id"); oldS.erase((*clause)[i]); } FatalAssert(oldS.empty(), "MiniSat::Derivation::registerClause: old clause not subset of new clause of same id"); } //) d_clauses[clause->id()] = clause; }; // mark clause as input clause, i.e. true without premises void registerInputClause(int clauseID) { // std::cout << "registerInputClause: " << clauseID << std::endl; d_inputClauses.insert(clauseID); }; // clause has been removed from the solver or created internally in Derivation, // so store it here for later garbage collection. void removedClause(Clause* clause) { FatalAssert(clause != NULL, "MiniSat::derivation:removedClause: NULL"); d_removedClauses.push_back(clause); }; // register the inference of a clause; takes ownership of inference void registerInference(int clauseID, Inference* inference) { FatalAssert(!d_inferences.contains(clauseID), "MiniSat::Derivation::registerInference: inference for clauseID already registered"); // std::cout << "Register inference: " << clauseID << " : " << inference->toString() << std::endl; d_inferences[clauseID] = inference; }; // implied is a literal that is implied at the root level. // return the id of the implying unit clause [literal], if it exists. // // otherwise derive it from its reasons and return the new clause id. // derived unit clauses are stored internally, independently of the Solver // // may resolve theory implications with Solver::resolveTheoryImplication int computeRootReason(Lit implied, Solver* solver); // register the empty clause (or a clause falsified in the root level) // showing that the clause set is unsatisfiable. // // if clause is not the empty clause, the empty clause is derived from it, // possible using computeRootReason void finish(Clause* clause, Solver* solver); // print the derivation of the given clause // // output is of the form: // ID D : L1 ... Ln : C1 K1 C2 K2 ... Cm // where: // ID - the id of a clause // D - 'I' for an input clause, 'D' for a clause derived from other clauses // Li - the clause literals // Ci Ki - the clause is derived from these clauses by binary resolution on the given literals // // factoring is done after each resolution step, i.e. duplicate literals are removed from the clause. // // example: // 3 D : +12 -2 -33 : 1 +10 2 // says that the clause with the id 3 consists of the literals +12, -2, -33, // and was derived by resolution between the clauses with ids 1 and 2, // where the literal +10 is in clause 1 and -10 is in clause 2. // // for example, 1 may be the clause +12 +10 -2, and 2 may be -10 -2 -33, // which resolved on +10 yield the clause +12 -2 -2 -33, // which after factoring simplified to +12 -2 -33. void printDerivation(Clause* clause); // print the derivation of the empty clause. void printDerivation(); // for debugging only void checkDerivation(Clause* clause); // creates a new proof; ownership transferred to caller SAT::SatProof* createProof(); SAT::SatProof* createProof(Clause* clause); // see Solver::push - clauseID is the highest currently used clause id void push(int clauseID); // see Solver::pop - clauseID corresponds to a clause id used in a push void pop(int clauseID); }; } #endif cvc3-2.4.1/src/sat/minisat_heap.h0000664000175400017540000001071710640364437016463 0ustar mdetersmdeters/*****************************************************************************/ /*! *\file minisat_heap.h *\brief MiniSat internal heap implementation * * Author: Alexander Fuchs * * Created: Fri Sep 08 11:04:00 2006 * *
* * License to use, copy, modify, sell and/or distribute this software * and its documentation for any purpose is hereby granted without * royalty, subject to the terms and conditions defined in the \ref * LICENSE file provided with this distribution. * *
*/ /*****************************************************************************/ /******************************************************************************************[Heap.h] MiniSat -- Copyright (c) 2003-2005, Niklas Een, Niklas Sorensson Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. **************************************************************************************************/ #ifndef _cvc3__minisat__heap_h_ #define _cvc3__minisat__heap_h_ //================================================================================================= #include "debug.h" #include // provides a heap over ints namespace MiniSat { static inline int left (int i) { return i+i; } static inline int right (int i) { return i+i + 1; } static inline int parent(int i) { return i >> 1; } template class Heap { public: C comp; vec heap; // heap of ints vec indices; // int -> index in heap inline void percolateUp(int i) { int x = heap[i]; while (parent(i) != 0 && comp(x,heap[parent(i)])){ heap[i] = heap[parent(i)]; indices[heap[i]] = i; i = parent(i); } heap [i] = x; indices[x] = i; } inline void percolateDown(int i) { int x = heap[i]; while (left(i) < heap.size()){ int child = right(i) < heap.size() && comp(heap[right(i)],heap[left(i)]) ? right(i) : left(i); if (!comp(heap[child],x)) break; heap[i] = heap[child]; indices[heap[i]] = i; i = child; } heap [i] = x; indices[x] = i; } bool ok(int n) { return n >= 0 && n < (int)indices.size(); } public: Heap(C c) : comp(c) { heap.push(-1); } void setBounds (int size) { DebugAssert(size >= 0, "MiniSat::Heap::setBounds"); indices.growTo(size,0); } bool inHeap (int n) { DebugAssert(ok(n), "MiniSat::Heap::inHeap"); return indices[n] != 0; } void increase (int n){ DebugAssert(ok(n), "MiniSat::Heap::increase: ok"); DebugAssert(inHeap(n), "MiniSat::Heap::increase: inHeap"); percolateUp(indices[n]); } bool empty () { return heap.size() == 1; } void insert(int n) { DebugAssert(n > 0, "MiniSat::Heap::insert: inserting invalid var id"); if (!inHeap(n)) { DebugAssert(ok(n), "MiniSat::Heap::insert: ok"); indices[n] = heap.size(); heap.push(n); percolateUp(indices[n]); } } int getMin() { int r = heap[1]; DebugAssert(r > 0, "MiniSatHeap:getmin: invalid var id"); heap[1] = heap.last(); indices[heap[1]] = 1; indices[r] = 0; heap.pop(); if (heap.size() > 1) percolateDown(1); return r; } bool heapProperty() { return heapProperty(1); } bool heapProperty(int i) { return (size_t)i >= heap.size() || ((parent(i) == 0 || !comp(heap[i],heap[parent(i)])) && heapProperty(left(i)) && heapProperty(right(i))); } }; } //================================================================================================= #endif cvc3-2.4.1/src/sat/cnf_theorem_producer.h0000664000175400017540000000352011352431445020203 0ustar mdetersmdeters/*****************************************************************************/ /*! *\file cnf_theorem_producer.h *\brief Implementation of CNF_Rules API * * Author: Clark Barrett * * Created: Thu Jan 5 05:33:42 2006 * *
* * License to use, copy, modify, sell and/or distribute this software * and its documentation for any purpose is hereby granted without * royalty, subject to the terms and conditions defined in the \ref * LICENSE file provided with this distribution. * *
* */ /*****************************************************************************/ #ifndef _cvc3__sat__cnf_theorem_producer_h_ #define _cvc3__sat__cnf_theorem_producer_h_ #include "theorem_producer.h" #include "cnf_rules.h" #include "command_line_flags.h" namespace CVC3 { class CNF_TheoremProducer : public CNF_Rules, public TheoremProducer { const CLFlags& d_flags; const bool& d_smartClauses; public: CNF_TheoremProducer(TheoremManager* tm, const CLFlags& flags) : TheoremProducer(tm), d_flags(flags), d_smartClauses(flags["smart-clauses"].getBool()) { } ~CNF_TheoremProducer() { } void getSmartClauses(const Theorem& thm, std::vector& clauses); void learnedClauses(const Theorem& thm, std::vector& clauses, bool newLemma); Theorem CNFAddUnit(const Theorem& thm); Theorem CNFConvert(const Expr & e, const Theorem& thm); Theorem ifLiftRule(const Expr& e, int itePos); Theorem CNFtranslate(const Expr& before, const Expr& after, std::string reason, int pos, const std::vector& thms) ; Theorem CNFITEtranslate(const Expr& before, const std::vector& after, const std::vector& thms, int pos) ; }; // end of class CNF_TheoremProducer } // end of namespace CVC3 #endif cvc3-2.4.1/src/sat/cnf_rules.h0000664000175400017540000000423111352431445015767 0ustar mdetersmdeters/*****************************************************************************/ /*! * \file cnf_rules.h * \brief Abstract proof rules for CNF conversion * * Author: Clark Barrett * * Created: Thu Jan 5 05:24:45 2006 * *
* * License to use, copy, modify, sell and/or distribute this software * and its documentation for any purpose is hereby granted without * royalty, subject to the terms and conditions defined in the \ref * LICENSE file provided with this distribution. * *
* */ /*****************************************************************************/ #ifndef _cvc3__sat__cnf_rules_h_ #define _cvc3__sat__cnf_rules_h_ namespace CVC3 { class Theorem; /*! \defgroup CNF_Rules Proof Rules for the Search Engines * \ingroup CNF */ //! API to the CNF proof rules /*! \ingroup CNF_Rules */ class CNF_Rules { /*! \addtogroup CNF_Rules * @{ */ public: //! Destructor virtual ~CNF_Rules() { } // A_1,...,A_n |- B ==> |- (OR !A_1 ... !A_n B) /*! @brief Learned clause rule: \f[\frac{A_1,\ldots,A_n\vdash B} {\vdash\neg A_1\vee\cdots\vee \neg A_n\vee B}\f] * * \param thm is the theorem * \f$ A_1,\ldots,A_n\vdash B\f$ * Each \f$A_i\f$ and \f$B\f$ should be literals * \f$B\f$ can also be \f$\mathrm{FALSE}\f$ */ virtual void learnedClauses(const Theorem& thm, std::vector&, bool newLemma) = 0; //! |- P(_, ITE(cond,a,b), _) <=> ITE(cond,Pred(_, a, _),Pred(_, b, _)) virtual Theorem ifLiftRule(const Expr& e, int itePos) = 0; virtual Theorem CNFAddUnit(const Theorem& thm) = 0 ; virtual Theorem CNFConvert(const Expr& e, const Theorem& thm) = 0 ; virtual Theorem CNFtranslate(const Expr& before, const Expr& after, std::string reason, int pos, const std::vector& thms) = 0; virtual Theorem CNFITEtranslate(const Expr& before, const std::vector& after, const std::vector& thms, int pos) = 0; /*! @} */ // end of CNF_Rules }; // end of class CNF_Rules } // end of namespace CVC3 #endif cvc3-2.4.1/src/sat/minisat_types.h0000664000175400017540000001544610775422236016717 0ustar mdetersmdeters/*****************************************************************************/ /*! *\file minisat_types.h *\brief MiniSat internal types * * Author: Alexander Fuchs * * Created: Fri Sep 08 11:04:00 2006 * *
* * License to use, copy, modify, sell and/or distribute this software * and its documentation for any purpose is hereby granted without * royalty, subject to the terms and conditions defined in the \ref * LICENSE file provided with this distribution. * *
*/ /*****************************************************************************/ /***********************************************************************************[SolverTypes.h] MiniSat -- Copyright (c) 2003-2005, Niklas Een, Niklas Sorensson Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. **************************************************************************************************/ #ifndef _cvc3__minisat__types_h_ #define _cvc3__minisat__types_h_ //================================================================================================= // Variables, literals, clause IDs: #include "minisat_global.h" #include "theorem.h" #include namespace MiniSat { // NOTE! Variables are just integers. No abstraction here. They should be chosen from 0..N, // so that they can be used as array indices. // CVC additionally requires that N >= 2. typedef int Var; const int var_Undef = -1; class Lit { int x; explicit Lit(int index) : x(index) {} // (lit_Undef) public: Lit() : x(2*var_Undef) {} // (lit_Undef) explicit Lit(Var var, bool sgn) : x((var+var) + (int)sgn) {} Lit operator~ () const { return Lit(x ^ 1); }; bool sign () const { return x & 1; }; int var () const { return x >> 1; }; int index () const { return x; }; static Lit toLit (int i) { return Lit(i); }; Lit unsign() const { return Lit(x & ~1); }; static Lit id (Lit p, bool sgn) { return Lit(p.x ^ (int)sgn); }; bool operator == (const Lit q) const { return index() == q.index(); }; bool operator != (const Lit q) const { return !(operator==(q)); }; // '<' guarantees that p, ~p are adjacent in the ordering.; bool operator < (const Lit q) const { return index() < q.index(); } unsigned int hash() const { return (unsigned int)x; } std::string toString() const { std::ostringstream buffer; if (sign()) buffer << "+"; else buffer << "-"; buffer << var(); return buffer.str(); } int toDimacs() const { return sign() ? -var() - 1 : var() + 1; } }; const Lit lit_Undef(var_Undef, false); // }- Useful special constants. const Lit lit_Error(var_Undef, true ); // } // Clause -- a simple class for representing a clause: class Clause { unsigned int d_size_learnt; int d_id; int d_pushID; float d_activity; // The derivation of this SAT clause CVC3::Theorem d_theorem; Lit d_data[1]; static Clause* s_decision; static Clause* s_theoryImplication; public: // NOTE: This constructor cannot be used directly, // it doesn't allocate enough memory for d_data[]. // // using the hand-made allocator allows to allocate the data[] // like a static array within clause instead of as a pointer to the array. // this shows significant performance improvements Clause(bool learnt, const std::vector& ps, CVC3::Theorem theorem, int id, int pushID) { d_size_learnt = (ps.size() << 1) | (int)learnt; d_id = id; d_pushID = pushID; d_activity = 0; d_theorem = theorem; for (std::vector::size_type i = 0; i < ps.size(); i++) d_data[i] = ps[i]; } // -- use this function instead: friend Clause* Clause_new(const std::vector& ps, CVC3::Theorem theorem, int id); friend Clause* Lemma_new(const std::vector& ps, int id, int pushID); int size () const { return d_size_learnt >> 1; } bool learnt () const { return d_size_learnt & 1; } Lit operator [] (int i) const { return d_data[i]; } Lit& operator [] (int i) { return d_data[i]; } // intended to be unique id per clause, > 0, or clauseIDNull int id () const { return d_id; } // used with Solver::push/pop: // this is the highest id of all clauses used in the regression / // resolution / creation of this lemma int pushID () const { return d_pushID; } float activity () const { DebugAssert(learnt(), "MiniSat::Types:activity: not a lemma"); return d_activity; } void setActivity (float activity) { DebugAssert(learnt(), "MiniSat::Types:setActivity: not a lemma"); d_activity = activity; } void toLit (std::vector& literals) const; CVC3::Theorem getTheorem() const { return d_theorem; }; static int ClauseIDNull() { return 0; } // special Clause, used to mark that an implication is a decision, id = -1. static Clause* Decision(); // special Clause, used to mark that an implication is a theory implication // and that the explanation has not been retrieved yet, id = -2. static Clause* TheoryImplication(); std::string toString() const { if (size() == 0) return ""; std::ostringstream buffer; buffer << d_data[0].toString(); for (int j = 1; j < size(); ++j) { buffer << " " << d_data[j].toString(); } return buffer.str(); } bool contains(Lit l) { for (int i = 0; i < size(); ++i) { if (d_data[i] == l) return true; } return false; } }; Clause* Clause_new(const std::vector& ps, CVC3::Theorem theorem, int id); Clause* Lemma_new(const std::vector& ps, int id, int pushID); } //================================================================================================= #endif cvc3-2.4.1/src/sat/dpllt_basic.cpp0000664000175400017540000003334611103725113016623 0ustar mdetersmdeters/*****************************************************************************/ /*! *\file dpllt_basic.cpp *\brief Basic implementation of dpllt module using generic sat solver * * Author: Clark Barrett * * Created: Mon Dec 12 19:09:43 2005 * *
* * License to use, copy, modify, sell and/or distribute this software * and its documentation for any purpose is hereby granted without * royalty, subject to the terms and conditions defined in the \ref * LICENSE file provided with this distribution. * *
*/ /*****************************************************************************/ #include "dpllt_basic.h" #include "cnf.h" #include "sat_api.h" #include "exception.h" using namespace std; using namespace CVC3; using namespace SAT; //int level_ = 0; static void SATDLevelHook(void *cookie, int change) { //cout << "backtrack to: " << level_ << " " << change << endl; //level_ += change; // cout<<"decision level called"<(cookie); for (; change > 0; change--) { db->theoryAPI()->push(); } for (; change < 0; change++) { db->theoryAPI()->pop(); } } static SatSolver::Lit SATDecisionHook(void *cookie, bool *done) { // cout<<"sat decision called"<(cookie); if (db->theoryAPI()->outOfResources()) { // Tell SAT solver to exit with satisfiable result *done = true; return SatSolver::Lit(); } if (!db->decider()) { // Tell SAT solver to make its own choice if (!*done) return SatSolver::Lit(); } else { Lit lit = db->decider()->makeDecision(); if (!lit.isNull()) { //cout << "Split: " << lit.getVar().getIndex() << endl; // Tell SAT solver which literal to split on *done = false; return db->cvc2SAT(lit); } } CNF_Formula_Impl cnf; DPLLT::ConsistentResult result; result = db->theoryAPI()->checkConsistent(cnf, true); if (result == DPLLT::MAYBE_CONSISTENT) { IF_DEBUG(bool added = ) db->theoryAPI()->getNewClauses(cnf); DebugAssert(added, "Expected new clauses"); db->addNewClauses(cnf); *done = true; SatSolver::Lit l; l.id = 0; return l; } else if (result == DPLLT::INCONSISTENT) { db->addNewClauses(cnf); } // Tell SAT solver that we are done *done = true; return SatSolver::Lit(); } static void SATAssignmentHook(void *cookie, SatSolver::Var var, int value) { // cout<<"assignment called"<(cookie); TRACE("DPLL Assign", var.id, " := ", value); if (value == 0) db->theoryAPI()->assertLit(Lit(db->satSolver()->GetVarIndex(var), false)); else if (value == 1) db->theoryAPI()->assertLit(Lit(db->satSolver()->GetVarIndex(var), true)); else return; CNF_Formula_Impl cnf; DPLLT::ConsistentResult result; result = db->theoryAPI()->checkConsistent(cnf, false); if (result == DPLLT::INCONSISTENT) { db->addNewClauses(cnf); } } static void SATDeductionHook(void *cookie) { // cout<<"deduction called"<(cookie); Clause c; CNF_Formula_Impl cnf; if (db->theoryAPI()->getNewClauses(cnf)) { db->addNewClauses(cnf); cnf.reset(); } Lit l = db->theoryAPI()->getImplication(); while (!l.isNull()) { db->theoryAPI()->getExplanation(l, cnf); db->addNewClauses(cnf); cnf.reset(); l = db->theoryAPI()->getImplication(); } } void DPLLTBasic::createManager() { d_mng = SatSolver::Create(); d_mng->RegisterDLevelHook(SATDLevelHook, this); d_mng->RegisterDecisionHook(SATDecisionHook, this); d_mng->RegisterAssignmentHook(SATAssignmentHook, this); d_mng->RegisterDeductionHook(SATDeductionHook, this); } void DPLLTBasic::generate_CDB (CNF_Formula_Impl& cnf) { CNF_Formula::const_iterator i, iend; Clause::const_iterator j, jend; vector clause; if (cnf.numVars() > unsigned(d_mng->NumVariables())) { d_mng->AddVariables(cnf.numVars() - d_mng->NumVariables()); } cnf.simplify(); for (i = cnf.end()-1, iend = cnf.begin()-1; i != iend; --i) { //for (i = cnf.begin(), iend = cnf.end(); i != iend; i++) { if ((*i).isSatisfied()) continue; for (j = (*i).begin(), jend = (*i).end(); j != jend; ++j) { if (!(*j).isFalse()) clause.push_back(cvc2SAT(*j)); } if (clause.size() != 0) { d_mng->AddClause(clause); clause.clear(); } } } void DPLLTBasic::handle_result(SatSolver::SATStatus outcome) { const char * result = "UNKNOWN"; switch (outcome) { case SatSolver::SATISFIABLE: // if (d_printStats) { // cout << "Instance satisfiable" << endl; // for (int i=1, sz = d_mng->NumVariables(); i <= sz; ++i) { // switch(d_mng->GetVarAssignment(d_mng->GetVar(i))) { // case -1: // cout <<"("<< i<<")"; break; // case 0: // cout << "-" << i; break; // case 1: // cout << i ; break; // default: // throw Exception("Unknown variable value state"); // } // cout << " "; // } // cout << endl; // } result = "SAT"; break; case SatSolver::UNSATISFIABLE: result = "UNSAT"; if (d_printStats) cout << "Instance unsatisfiable" << endl; break; case SatSolver::BUDGET_EXCEEDED: result = "ABORT : TIME OUT"; cout << "Time out, unable to determine the satisfiablility of the instance"; cout << endl; break; case SatSolver::OUT_OF_MEMORY: result = "ABORT : MEM OUT"; cout << "Memory out, unable to determing the satisfiablility of the instance"; cout << endl; break; default: throw Exception("DPLTBasic::handle_result: Unknown outcome"); } if (d_printStats) d_mng->PrintStatistics(); } void DPLLTBasic::verify_solution() { // Used to check that all clauses are true, but our decision maker // may ignore some clauses that are no longer relevant, so now we check to // make sure no clause is false. for (SatSolver::Clause cl = d_mng->GetFirstClause(); !cl.IsNull(); cl = d_mng->GetNextClause(cl)) { vector lits; d_mng->GetClauseLits(cl, &lits); for (; lits.size() != 0;) { SatSolver::Lit lit = lits.back(); SatSolver::Var var = d_mng->GetVarFromLit(lit); int sign = d_mng->GetPhaseFromLit(lit); int var_value = d_mng->GetVarAssignment(var); if( (var_value == 1 && sign == 0) || (var_value == 0 && sign == 1) || (var_value == -1) ) break; lits.pop_back(); } DebugAssert(lits.size() != 0, "DPLLTBasic::verify_solution failed"); } } DPLLTBasic::DPLLTBasic(TheoryAPI* theoryAPI, Decider* decider, ContextManager* cm, bool printStats) : DPLLT(theoryAPI, decider), d_cm(cm), d_ready(true), d_printStats(printStats), d_pushLevel(cm->getCurrentContext(), 0), d_readyPrev(cm->getCurrentContext(), true), d_prevStackSize(cm->getCurrentContext(), 0), d_prevAStackSize(cm->getCurrentContext(), 0) { createManager(); d_cnf = new CNF_Formula_Impl(); d_assertions = new CD_CNF_Formula(d_cm->getCurrentContext()); } DPLLTBasic::~DPLLTBasic() { if (d_assertions) delete d_assertions; if (d_cnf) delete d_cnf; if (d_mng) delete d_mng; while (d_assertionsStack.size() > 0) { d_assertions = d_assertionsStack.back(); d_assertionsStack.pop_back(); delete d_assertions; } while (d_mngStack.size() > 0) { d_mng = d_mngStack.back(); d_mngStack.pop_back(); delete d_mng; d_cnf = d_cnfStack.back(); d_cnfStack.pop_back(); delete d_cnf; } } void DPLLTBasic::addNewClause(const Clause& c) { DebugAssert(c.size() > 0, "Expected non-empty clause"); DebugAssert(c.getMaxVar() <= unsigned(d_mng->NumVariables()), "Expected no new variables"); vector lits; for (Clause::const_iterator i = c.begin(), iend = c.end(); i < iend; ++i) { if (!(*i).isFalse()) lits.push_back(cvc2SAT(*i)); } satSolver()->AddClause(lits); (*d_cnf) += c; } void DPLLTBasic::addNewClauses(CNF_Formula_Impl& cnf) { CNF_Formula::const_iterator i, iend; Clause::const_iterator j, jend; vector clause; if (cnf.numVars() > unsigned(d_mng->NumVariables())) { d_mng->AddVariables(cnf.numVars() - d_mng->NumVariables()); } cnf.simplify(); for (i = cnf.end()-1, iend = cnf.begin()-1; i != iend; --i) { //for (i = cnf.begin(), iend = cnf.end(); i != iend; i++) { if ((*i).isSatisfied()) continue; for (j = (*i).begin(), jend = (*i).end(); j != jend; ++j) { if (!(*j).isFalse()) clause.push_back(cvc2SAT(*j)); } if (clause.size() != 0) { d_mng->AddClause(clause); clause.clear(); } } generate_CDB(cnf); (*d_cnf) += cnf; } void DPLLTBasic::push() { d_theoryAPI->push(); d_pushLevel = d_pushLevel + 1; d_prevStackSize = d_mngStack.size(); d_prevAStackSize = d_assertionsStack.size(); d_readyPrev = d_ready; } void DPLLTBasic::pop() { unsigned pushLevel = d_pushLevel; unsigned prevStackSize = d_prevStackSize; unsigned prevAStackSize = d_prevAStackSize; bool readyPrev = d_readyPrev; while (d_assertionsStack.size() > prevAStackSize) { delete d_assertions; d_assertions = d_assertionsStack.back(); d_assertionsStack.pop_back(); } while (d_mngStack.size() > prevStackSize) { delete d_mng; delete d_cnf; d_mng = d_mngStack.back(); d_mngStack.pop_back(); d_cnf = d_cnfStack.back(); d_cnfStack.pop_back(); DebugAssert(d_mngStack.size() == d_cnfStack.size(), "size mismatch"); } if (d_mngStack.size() == 0) { if (readyPrev && !d_ready) { delete d_mng; delete d_cnf; createManager(); d_cnf = new CNF_Formula_Impl(); d_ready = true; } else { DebugAssert(readyPrev == d_ready, "Unexpected ready values"); } } else { DebugAssert(!d_ready, "Expected ready to be false"); } while (d_pushLevel == pushLevel) d_theoryAPI->pop(); } std::vector DPLLTBasic::getCurAssignments(){ std::vector nothing; return nothing; } std::vector > DPLLTBasic::getCurClauses(){ std::vector > nothing; return nothing; } void DPLLTBasic::addAssertion(const CNF_Formula& cnf) { // Immediately assert unit clauses CNF_Formula::const_iterator i, iend; Clause::const_iterator j, jend; for (i = cnf.end()-1, iend = cnf.begin()-1; i != iend; --i) { if ((*i).isUnit()) { j = (*i).begin(); d_theoryAPI->assertLit(*j); } } // Accumulate assertions in d_assertions (*d_assertions) += cnf; } QueryResult DPLLTBasic::checkSat(const CNF_Formula& cnf) { SatSolver::SATStatus result; if (!d_ready) { // Copy current formula d_cnfStack.push_back(d_cnf); d_cnf = new CNF_Formula_Impl(*d_cnf); // make unit clauses for current assignment int value; for (int i = 1; i <= d_mng->NumVariables(); ++i) { value = d_mng->GetVarAssignment(d_mng->GetVar(i)); if (value == 1) { d_cnf->newClause(); d_cnf->addLiteral(Lit(i)); } else if (value == 0) { d_cnf->newClause(); d_cnf->addLiteral(Lit(i, false)); } } // Create new manager d_mngStack.push_back(d_mng); DebugAssert(d_mngStack.size() == d_cnfStack.size(), "size mismatch"); createManager(); } d_ready = false; if (d_assertions) (*d_cnf) += (*d_assertions); (*d_cnf) += cnf; generate_CDB(*d_cnf); d_theoryAPI->push(); result = d_mng->Satisfiable(true); if (result == SatSolver::SATISFIABLE && theoryAPI()->outOfResources()) result = SatSolver::BUDGET_EXCEEDED; // Print result if (result == SatSolver::SATISFIABLE) { verify_solution(); if (d_assertions->numClauses() > 0) { d_assertionsStack.push_back(d_assertions); d_assertions = new CD_CNF_Formula(d_cm->getCurrentContext()); } } handle_result (result); if (result == SatSolver::UNSATISFIABLE) { d_theoryAPI->pop(); delete d_mng; delete d_cnf; if (d_mngStack.size() == 0) { createManager(); d_cnf = new CNF_Formula_Impl(); d_ready = true; } else { d_mng = d_mngStack.back(); d_mngStack.pop_back(); d_cnf = d_cnfStack.back(); d_cnfStack.pop_back(); DebugAssert(d_mngStack.size() == d_cnfStack.size(), "size mismatch"); } } return (result == SatSolver::UNSATISFIABLE ? UNSATISFIABLE : result == SatSolver::SATISFIABLE ? SATISFIABLE : ABORT); } QueryResult DPLLTBasic::continueCheck(const CNF_Formula& cnf) { SatSolver::SATStatus result; if (d_ready) { throw Exception ("continueCheck should be called after a previous satisfiable result"); } if (d_assertions->numClauses() > 0) { throw Exception ("a check cannot be continued if new assertions have been made"); } CNF_Formula_Impl cnfImpl(cnf); generate_CDB(cnfImpl); (*d_cnf) += cnfImpl; result = d_mng->Continue(); if (result == SatSolver::SATISFIABLE && theoryAPI()->outOfResources()) result = SatSolver::BUDGET_EXCEEDED; // Print result if (result == SatSolver::SATISFIABLE) verify_solution(); handle_result (result); if (result == SatSolver::UNSATISFIABLE) { d_theoryAPI->pop(); delete d_mng; delete d_cnf; if (d_mngStack.size() == 0) { createManager(); d_cnf = new CNF_Formula_Impl(); d_ready = true; } else { d_mng = d_mngStack.back(); d_mngStack.pop_back(); d_cnf = d_cnfStack.back(); d_cnfStack.pop_back(); DebugAssert(d_mngStack.size() == d_cnfStack.size(), "size mismatch"); } } return (result == SatSolver::UNSATISFIABLE ? UNSATISFIABLE : result == SatSolver::SATISFIABLE ? SATISFIABLE : ABORT); } CVC3::Proof DPLLTBasic::getSatProof(CNF_Manager* cnfManager, CVC3::TheoryCore* core){ CVC3::Proof temp; return temp; } cvc3-2.4.1/src/sat/minisat_solver.h0000664000175400017540000006630411356544153017063 0ustar mdetersmdeters/*****************************************************************************/ /*! *\file minisat_solver.h *\brief Adaptation of MiniSat to DPLL(T) * * Author: Alexander Fuchs * * Created: Fri Sep 08 11:04:00 2006 * *
* * License to use, copy, modify, sell and/or distribute this software * and its documentation for any purpose is hereby granted without * royalty, subject to the terms and conditions defined in the \ref * LICENSE file provided with this distribution. * *
*/ /*****************************************************************************/ /****************************************************************************************[Solver.h] MiniSat -- Copyright (c) 2003-2005, Niklas Een, Niklas Sorensson Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. **************************************************************************************************/ #ifndef _cvc3__minisat_h_ #define _cvc3__minisat_h_ #include "minisat_types.h" #include "minisat_varorder.h" #include "minisat_derivation.h" #include "dpllt.h" #include #include #include #include #include "hash_set.h" // changes to MiniSat for CVC integration: // 1) Decision heuristics // 2) Theory clauses // 3) Theory conflicts // 4) Theory implications // 5) binary clause trick // // in more detail: // 1) Decision heuristics // if a CVC decider is given (d_decider), // it is used instead of MiniSat's decision heuristics // to choose the next decision literal. // // 2) Theory clauses // any number of clauses can be added at any decision level. // see explanations for d_conflict and d_pendingClauses // // 3) Theory conflicts // theory conflicts are just treated as conflicting theory clauses // // 4) Theory implications // can be treated just as theory clauses if their explanation is retrieved immediately. // otherwise, Clause::TheoryImplication() is used as a reason // and the computation level is assumed to be the decision level, // until the explanation is retrieved (see d_theoryExplanations). // other changes: // - binary clause trick // MiniSat sometimes (watched literal, implication reason) // used a pointer to a clause to represent a unary clause. // the lowest bit was used to distinguish between a pointer, // and the integer representing the literal of the unit clause. // this saved memory and a pointer derefence. // while this is reported to increase the performance by about 10%-20%, // it also complicated the code. removing it didn't show any // worse performance, so this trick was dropped. // // - store all clauses // MiniSat stored unit and binary clauses only implicitly, // in the context and the watched literal data. // without the binary clause trick binary clauses have to be stored explicitly in d_clauses anyway. // mostly for consistency and simplicity unary clauses are stored expicitly as well. // not-so-convincing reasons are that this makes it also simpler to handle conflicting // theory unit clauses (see insertClause()) by giving the reason // (although one could use NULL instead, // but this would then complicate proof logging which is based on clause ids), // and that it helps to retrieve the clause set independently of the assignment. // (currently this is neither needed for DPLLT::checkSat nor DPLLT::continueCheck, // the two operations in DPLLTMiniSat which use MiniSat) // trying this out didn't show too much of an improvement, so it's not done. namespace MiniSat { // assume that all stl containers use the same size type // and define it here once and for all typedef std::vector::size_type size_type; // /// conversions between MiniSat and CVC data types: /// // both MiniSat and CVC use integers for variables and literals. // CVC uses the integer's sign as the literals sign, // while MiniSat doubles the id and uses only positive numbers // (to be able to use them as array indizes). // e.g, for the variable p with the number 2, // CVC represents +p as 3 and -p as -3, // while MiniSat represents +p as 5 and -p as 4. // // unifying this representation is probably not worth doing, // as, first, conversion happens only at the interface level, // and second, no memory can be saved as a literal is just an integer. inline Var cvcToMiniSat(const SAT::Var& var) { return var.getIndex(); } inline SAT::Var miniSatToCVC(Var var) { return SAT::Var(var); } inline Lit cvcToMiniSat(const SAT::Lit& literal) { return MiniSat::Lit(cvcToMiniSat(literal.getVar()), literal.isPositive()); } inline SAT::Lit miniSatToCVC(Lit literal) { return SAT::Lit(miniSatToCVC(literal.var()), literal.sign()); } // converts cvc clause into MiniSat literal list // returns true on permanently satisfied clause, i.e. clause containing 'true' bool cvcToMiniSat(const SAT::Clause& clause, std::vector& literals); //================================================================================================= // MiniSat -- the main class: struct SolverStats { int64_t starts, decisions, propagations, conflicts, theory_conflicts, max_level; int64_t clauses_literals, learnts_literals, max_literals, del_clauses, del_lemmas, db_simpl, lm_simpl, debug; SolverStats() : starts(0), decisions(0), propagations(0), conflicts(0), theory_conflicts(0), max_level(0), clauses_literals(0), learnts_literals(0), max_literals(0), del_clauses(0), del_lemmas(0), db_simpl(0), lm_simpl(0), debug(0) { } }; // solver state at a push, needed so that a pop can revert to that state struct PushEntry { // the highest id of all clauses known - // clauses with higher id must have been added after the push int d_clauseID; // size of d_trail size_type d_trailSize; size_type d_qhead; size_type d_thead; // conflict detected in initial propagation phase of push bool d_ok; PushEntry(int clauseID, size_type trailSize, size_type qhead, size_type thead, bool ok) : d_clauseID(clauseID), d_trailSize(trailSize), d_qhead(qhead), d_thead(thead), d_ok(ok) {} }; struct SearchParams { double var_decay, clause_decay, random_var_freq; // (reasonable values are: 0.95, 0.999, 0.02) SearchParams(double v = 1, double c = 1, double r = 0) : var_decay(v), clause_decay(c), random_var_freq(r) { } }; class Solver { /// variables protected: // level before first decision static const int d_rootLevel = 0; /// status // a search() has been started bool d_inSearch; // if false, then the clause set is unsatisfiable. bool d_ok; // this clause is conflicting with the current context // // it is not necessary to store more than one conflicting clause. // if there are several conflicting clauses, // they must all have been become conflicting at the same decision level, // as in a conflicting state no decision is made. // // after backtracking on any of these conflicting clauses, // the others are also not conflicting anymore, // if the conflict really was due to the current decision level. // // this is only not the case if theory clauses are involved. // i) a conflicting theory clause is added to d_pendingClauses instead of the clause set. // it will be only moved to the clause set if it is not conflicting, // otherwise it (or some other conflicting clause) will be used for backtracking. // ii) progapations based on new theory clauses may actually be already valid // in a previous level, not only in the current decision level. // on backtracking this will be kept in the part of the trail which has to be propagated, // and be propagated again after backtracking, // thus the conflict will be computed again. // // this scheme also allows to stop the propagation as soon as one conflict clause is found, // and backtrack only in this one, instead of searching for all conflicting clauses. // // the only attempt at picking a good conflict clause is to pick the shortest one. // looking at the lowest backjumping level is probably(?) too expensive. Clause* d_conflict; /// variable assignments, and pending propagations // mapping from literals to clauses in which a literal is watched, // literal.index() is used as the index std::vector > d_watches; // The current assignments (lbool:s stored as char:s), indexed by var std::vector d_assigns; // Assignment stack; stores all assigments made in the order they were made. // as theory clause and theory implications can add propagations // which are valid at earlier levels this list is _not_ necessarily ordered by level. std::vector d_trail; // Separator indices for different decision levels in 'trail', // i.e. d_trail[trail_lim[i]] is the i.th decision std::vector d_trail_lim; // 'd_trail_pos[var]' is the variable's position in 'trail[]' // used for proof logging std::vector d_trail_pos; // head of propagation queue as index into the trail: // the context is the trail up to trail[qhead - 1], // the propagation queue is trail[qhead] to its end. size_type d_qhead; // like d_qhead for theories: // only the literals up to trail[thead - 1] have been asserted to the theories. size_type d_thead; // 'reason[var]' is the clause that implied the variables current value, // or Clause::Decision() for a decision , // resp. (Clause::TheoryImplication()) for a theory implication with lazy explanation retrieval std::vector d_reason; // 'level[var]' is the decision level at which assignment was made. // except when the literal is a theory implication and the explanation // has not been retrieved yet. Then, this is the level of the literal's // assertion, and its real level will be computed during conflict analysis. std::vector d_level; // Variables // the variables registered before the first push // and at each push level (with registerVar), // i.e. the variables occurring in the clauses at each push level. // cumulative, i.e. the variables registered in a push level // are the union of the variables registered at it and any previous level. std::vector > d_registeredVars; /// Clauses // clause id counter int d_clauseIDCounter; // problem clauses (input clauses, theory clauses, explanations of theory implications). std::vector d_clauses; // learnt clauses (conflict clauses) std::vector d_learnts; /// Temporary clauses // these are clauses which were already conflicting when added. // so, first the solver has to backtrack, // then they can be added in a consistent state. std::queue d_pendingClauses; // these clauses are explanations for theory propagations which have been // retrieved to regress a conflict. they are gathered for the regression // in analyze, and then deleted on backtracking in backtrack. std::stack > d_theoryExplanations; /// Push / Pop // pushes std::vector d_pushes; // lemmas kept after a pop, to add with the next push std::vector d_popLemmas; // for each variable the highest pushID of the clauses used for its implication. // for a decision or theory implication with unknown explanation this is max_int, // for a unit clause as the reason it is the clauses pushID, // for any other reason it is the max of the d_pushIDs of the literals // falsifying the literals of the reason clause // // thus, an approximation for checking if a clause literal is permanently // falsified/satisfied even after pops (as long as the clause is not popped itself), // is that the implication level of the literal it the root level, // and that clauses' pushID is <= the d_pushIDs value of the literal. // // this can be used for simplifcation of clauses, lemma minimization, // and keeping propagated literals after a pop. std::vector d_pushIDs; // :TODO: unify var -> x arrays into one with a varInfo data structure: // d_assigns, d_reason, d_level, d_pushIDs, d_activity // probably not: d_trail_pos, d_analyze_seen // number of queued pop requests unsigned int d_popRequests; /// heuristics // heuristics for keeping lemmas // Amount to bump next clause with. double d_cla_inc; // INVERSE decay factor for clause activity: stores 1/decay. double d_cla_decay; // heuristics for variable decisions // A heuristic measurement of the activity of a variable. std::vector d_activity; // Amount to bump next variable with. double d_var_inc; // INVERSE decay factor for variable activity: stores 1/decay. // Use negative value for static variable order. double d_var_decay; // Keeps track of the decision variable order. VarOrder d_order; // heuristics for clause/lemma database cleanup // Number of top-level assignments since last execution of 'simplifyDB()'. int d_simpDB_assigns; // Remaining number of propagations that must be made before next execution of 'simplifyDB()'. int64_t d_simpDB_props; // Number of lemmas after last execution of 'reduceDB()'. int d_simpRD_learnts; /// CVC interface // CVC theory API SAT::DPLLT::TheoryAPI* d_theoryAPI; // CVC decision heuristic SAT::DPLLT::Decider* d_decider; /// proof logging // log derivation, to create a resolution proof from a closed derivation tree proof Derivation* d_derivation; /// Mode of operation: // Restart frequency etc. SearchParams d_default_params; // Controls conflict clause minimization. true by default. bool d_expensive_ccmin; /// Temporaries (to reduce allocation overhead). // Each variable is prefixed by the method in which is used: std::vector d_analyze_seen; std::vector d_analyze_stack; std::vector d_analyze_redundant; // solver statistics SolverStats d_stats; protected: /// Search: // the current decision level int decisionLevel() const { return (int)d_trail_lim.size(); } // decision on p bool assume(Lit p); // queue a literal for propagation, at decisionLevel implied by reason bool enqueue(Lit fact, int decisionLevel, Clause* reason); // propagate a literal (the head of the propagation queue) void propagate(); // perform a lookahead on the best split literals. // this is done on the propositional level only, without involving theories. void propLookahead(const SearchParams& params); /// Conflict handling // conflict analysis: returns conflict clause and level to backtrack to // clause implies its first literal in level out_btlevel Clause* analyze(int& out_btlevel); // conflict analysis: conflict clause minimization (helper method for 'analyze()') void analyze_minimize(std::vector& out_learnt, Inference* inference, int& pushID); // conflict analysis: conflict clause minimization (helper method for 'analyze()') bool analyze_removable(Lit p, unsigned int min_level, int pushID); // backtrack to level, add conflict clause void backtrack(int level, Clause* clause); // is the current state conflicting, i.e. is there a conflicting clause? bool isConflicting() const; // mark this clause as conflicting void updateConflict(Clause* clause); // returns the level in which this clause implies its first literal. // precondition: all clause literals except for the first must be falsified. int getImplicationLevel(const Clause& clause) const; // returns the level in which this clause became falsified // (or at least fully assigned). // precondition: no clause literal is undefined. int getConflictLevel(const Clause& clause) const; // if this literal is a theory implied literal and its explanation has not been retrieved, // then this is done now and the literal's reason is updated. // precondition: literal must be a propagated literal void resolveTheoryImplication(Lit literal); /// unit propagation // return the watched clauses for a literal std::vector& getWatches(Lit literal) { return d_watches[literal.index()]; }; // return the watched clauses for a literal const std::vector& getWatches(Lit literal) const { return d_watches[literal.index()]; }; // adds a watch to a clause literal // precondition: literal must be one of the first two literals in clause void addWatch(Lit literal, Clause* clause) { getWatches(literal).push_back(clause); }; // removes the clause from the list of watched clauses void removeWatch(std::vector& ws, Clause* elem); /// Operations on clauses: // registers a variable - any variable has to be registered before it is used in the search. void registerVar(Var var); // checks if a variable is already registered (pop can remove a variable) bool isRegistered(Var var); // creates/adds a clause or a lemma and returns it; registers all variables, // used by all other addClause methods void addClause(std::vector& literals, CVC3::Theorem theorem, int clauseID); // adds a clause or a lemma to the solver, watched lists, and checks if it is unit/conflicting // clause activity heuristics are updated. // precondition: all variables are registered // precondition: a lemma is propagating its first literal void insertClause(Clause* clause); // add a lemma which has not been computed just now (see push(), createFrom()), // so it is not necessary propagating (which is assumed by insertClause()) void insertLemma(const Clause* lemma, int clauseID, int pushID); // simplify clause based on root level assignment // precondition: all variables are registered bool simplifyClause(std::vector& literals, int clausePushID) const; // order a clause such that it is consistent with the current assignment, // i.e. the two first literals can be taken as the watched literals. // precondition: all variables are registered void orderClause(std::vector& literals) const; // deallocate a clause, and removes it from watches if just_dealloc is false void remove(Clause* c, bool just_dealloc = false); // assuming that the literal is implied at the root level: // will the literal be assigned as long as the clause exists, even over pops? bool isImpliedAt(Lit lit, int clausePushID) const; // is this clause permanently satisfied? bool isPermSatisfied(Clause* c) const; // Push / Pop // sets the d_pushIDs entry of var implied by from void setPushID(Var var, Clause* from); // returns the d_pushIDs entry of a var // makes only sense for a var with a defined value int getPushID(Var var) const { return d_pushIDs[var]; } int getPushID(Lit lit) const { return getPushID(lit.var()); } // pop the most recent push void pop(); void popClauses(const PushEntry& pushEntry, std::vector& clauses); /// Activity: void varBumpActivity(Lit p) { if (d_var_decay < 0) return; // (negative decay means static variable order -- don't bump) if ( (d_activity[p.var()] += d_var_inc) > 1e100 ) varRescaleActivity(); d_order.update(p.var()); } void varDecayActivity () { if (d_var_decay >= 0) d_var_inc *= d_var_decay; } void varRescaleActivity(); void claDecayActivity() { d_cla_inc *= d_cla_decay; } void claRescaleActivity() ; void claBumpActivity (Clause* c) { float act = c->activity() + (float)d_cla_inc; c->setActivity(act); if (act > 1e20) claRescaleActivity(); } /// debugging // are all clauses (excluding lemmas) satisfied? bool allClausesSatisfied(); // checks that the first two literals of a clause are watched void checkWatched(const Clause& clause) const; void checkWatched() const; // checks that for each clause one of these holds: // 1) the first two literals are undefined // 2) one of the first two literals is satisfied // 3) the first literal is undefined and all other literals are falsified // 4) all literals are falsified void checkClause(const Clause& clause) const; void checkClauses() const; // checks that each literal in the context(trail) is either // 1) a decision // 2) or implied by previous context literals void checkTrail() const; // print the current propagation step void protocolPropagation() const; public: /// Initialization // assumes that this is the SAT solver in control of CVC theories, // so it immediately pushs a new theory context. // // uses MiniSat's internal decision heuristics if decider is NULL // // if logDerivation then the derivation will be logged in getDerivation(), // which provides a prove if the empty clause is derived. Solver(SAT::DPLLT::TheoryAPI* theoryAPI, SAT::DPLLT::Decider* decider, bool logDerivation); // copies clauses, assignment as unit clauses, and lemmas // will be in root level static Solver* createFrom(const Solver* solver); // releases all memory, but does not pop theories. // this is according to the semantics expected by CVC: // is the solver detects unsatisfiability, it pops all theory levels. // otherwise the caller is responsible for resetting the theory levels. ~Solver(); /// problem specification // converts cvc clause into MiniSat clause with the given id. // returns NULL on permanently satisfied clause, i.e. clause containing 'true' Clause* cvcToMiniSat(const SAT::Clause& clause, int id); // adds a unit clause given as a literal void addClause(Lit p, CVC3::Theorem theorem); // adds a (copy of) clause, uses original clause id if wished void addClause(const Clause& clause, bool keepClauseID); // adds a CVC clause void addClause(const SAT::Clause& clause, bool isTheoryClause); // adds a CVC formula void addFormula(const SAT::CNF_Formula& cnf, bool isTheoryClause); // returns a unique id for a new clause // (addClause will then use the negation for theory clauses) int nextClauseID() { FatalAssert(d_clauseIDCounter >= 0, "MiniSat::Solver::nextClauseID: overflow"); return d_clauseIDCounter++; }; // removes permanently satisfied clauses void simplifyDB(); // removes 'bad' lemmas void reduceDB(); /// search // (continue) search with current clause set and context // until model is found (in d_trail), or unsatisfiability detected. // // between two calls clauses may be added, // but everything else (including the theories) should remain untouched. // // the prover becomes essentially unusable if unsatisfiability is detected, // only data may be retrieved (clauses, statistics, proof, ...) CVC3::QueryResult search(); // returns a resolution proof for unsatisfiability if // - createProof was true in the call to the constructor // - the last call to search returned status UNSATISFIABLE // returns NULL otherwise Derivation* getProof(); // is the solver currently in a search state? // i.e. search() has been called and not been undone by a pop request. bool inSearch() const { return d_inSearch && d_popRequests == 0; } // is the solver in a consistent state? bool isConsistent() const { return !isConflicting(); } /// Push / Pop // push the current solver state // can only be done when solver is not already in a search (inSearch()). void push(); // pop all theory levels pushed by the solver, // i.e. all (current) decision levels of the solver. void popTheories(); // request to pop theories - all request are done when doPops is called void requestPop(); // perform all pop requests (calls to requestPop) void doPops(); // has there been a push which hasn't been (requested to be) undone yet? bool inPush() const { return d_pushes.size() > d_popRequests; } /// clauses / assignment // get the current value of a variable/literal lbool getValue(Var x) const { return toLbool(d_assigns[x]); } lbool getValue(Lit p) const { return p.sign() ? getValue(p.var()) : ~getValue(p.var()); } // get the assignment level of a variable/literal (which should have a value) int getLevel(Var var) const { return d_level[var]; }; int getLevel(Lit lit) const { return getLevel(lit.var()); }; // set the assignment level of a variable/literal void setLevel(Var var, int level) { d_level[var] = level; }; void setLevel(Lit lit, int level) { setLevel(lit.var(), level); }; // this clause is the reason for a propagation and thus can't be removed // precondition: the first literal of the reason clause must be the propagated literal bool isReason(const Clause* c) const { return c->size() > 0 && d_reason[((*c)[0]).var()] == c; } // returns the implication reason of a variable (its value must be defined) Clause* getReason(Var var) const { return d_reason[var]; }; // like getReason, but if resolveTheoryImplication is true, // then additionaly if literal is a theory implication resolveTheoryImplication() is called. Clause* getReason(Lit literal, bool resolveTheoryImplication = true); // the current clause set const std::vector& getClauses() const { return d_clauses; } // the current lemma set const std::vector& getLemmas() const { return d_learnts; } // the current variable assignments const std::vector& getTrail() const { return d_trail; } // the derivation, logged if != NULL Derivation* getDerivation() { return d_derivation; } /// Statistics // derivation statistics const SolverStats& getStats() const { return d_stats; } // number of assigned variabels (context size) int nAssigns() const { return d_trail.size(); } // number of stored clauses (does not include clauses removed by simplifyDB) int nClauses() const { return d_clauses.size(); } // number of stored lemmas (forgotten lemmas are not counted) int nLearnts() const { return d_learnts.size(); } // variable with the highest id + 1 // not necessaribly the number of variables, if they are not enumerated without gap int nVars() const { return d_assigns.size(); } /// String representation: // literal id, sign, current assignment as string std::string toString(Lit literal, bool showAssignment) const; // clause as string, showAssignment true -> show current assignment of each literal std::string toString(const std::vector& clause, bool showAssignment) const; // clause as string, showAssignment true -> show current assignment of each literal std::string toString(const Clause& clause, bool showAssignment) const; // prints lemmas, clauses, assignment to cout void printState() const; // output the clause set and context in DIMACS format void printDIMACS() const; std::vector curAssigns() ; std::vector > curClauses(); }; } //================================================================================================= #endif cvc3-2.4.1/src/sat/sat_api.cpp0000664000175400017540000000412710540372615015767 0ustar mdetersmdeters/////////////////////////////////////////////////////////////////////////////// // // // File: sat_api.cpp // // Author: Clark Barrett // // Created: 2002 // // Description: Implementation of SatSolver class // // // /////////////////////////////////////////////////////////////////////////////// #include "sat_api.h" using namespace std; #ifndef DPLL_BASIC SatSolver *SatSolver::Create() { return NULL; } #endif void SatSolver::PrintStatistics(ostream & os) { int val; float time; os << "Number of Variables\t\t\t" << NumVariables() << endl; val = GetNumLiterals(); if (val != -1) os << "Number of Literals\t\t\t" << val << endl; os << "Number of Clauses\t\t\t" << NumClauses() << endl; val = GetBudgetUsed(); if (val != -1) os << "Budget Used\t\t\t\t" << val << endl; val = GetMemUsed(); if (val != -1) os << "Memory Used\t\t\t\t" << val << endl; val = GetMaxDLevel(); if (val != -1) os << "Maximum Decision Level\t\t\t" << val << endl; val = GetNumDecisions(); if (val != -1) os << "Number of Decisions\t\t\t" << val << endl; val = GetNumImplications(); if (val != -1) os << "Number of Implications\t\t\t" << val << endl; val = GetNumConflicts(); if (val != -1) os << "Number of Conflicts\t\t\t" << val << endl; val = GetNumExtConflicts(); if (val != -1) os << "Number of External Conflicts\t\t" << val << endl; val = GetNumDeletedClauses(); if (val != -1) os << "Number of Deleted Clauses\t\t" << val << endl; val = GetNumDeletedLiterals(); if (val != -1) os << "Number of Deleted Literals\t\t" << val << endl; time = GetTotalTime(); if (time != -1) os << endl << "Total Run Time\t\t\t\t" << time << endl; time = GetSATTime(); if (time != -1) os << "Time spent in SAT\t\t\t" << time << endl; } cvc3-2.4.1/src/sat/minisat_types.cpp0000664000175400017540000000360411021277472017236 0ustar mdetersmdeters/*****************************************************************************/ /*! *\file minisat_types.cpp *\brief MiniSat internal types * * Author: Alexander Fuchs * * Created: Fri Sep 08 11:04:00 2006 * *
* * License to use, copy, modify, sell and/or distribute this software * and its documentation for any purpose is hereby granted without * royalty, subject to the terms and conditions defined in the \ref * LICENSE file provided with this distribution. * *
*/ /*****************************************************************************/ #include "minisat_types.h" using namespace std; namespace MiniSat { // static class members Clause* Clause::s_decision = NULL; Clause* Clause::s_theoryImplication = NULL; const int clause_mem_base = sizeof(unsigned int) + 2 * sizeof(int) + sizeof(float) + sizeof (CVC3::Theorem); void* malloc_clause(const vector& ps) { return xmalloc (clause_mem_base + sizeof(Lit) * (max(size_t(1), ps.size()))); } Clause* Clause_new(const vector& ps, CVC3::Theorem theorem, int id) { void* mem = malloc_clause(ps); return new (mem) Clause(false, ps, theorem, id, id); } Clause* Lemma_new(const vector& ps, int id, int pushID) { void* mem = malloc_clause(ps); return new (mem) Clause(true, ps, CVC3::Theorem(), id, pushID); } Clause* Clause::Decision() { if (s_decision == NULL) { vector lits; s_decision = Clause_new(lits, CVC3::Theorem(), -1); } return s_decision; } Clause* Clause::TheoryImplication() { if (s_theoryImplication == NULL) { vector lits; s_theoryImplication = Clause_new(lits, CVC3::Theorem(), -2); } return s_theoryImplication; } void Clause::toLit(vector& literals) const { for (int i = 0; i < size(); ++i) { literals.push_back(d_data[i]); } } } cvc3-2.4.1/src/sat/minisat_global.h0000664000175400017540000002132610640364437017004 0ustar mdetersmdeters/*****************************************************************************/ /*! *\file minisat_global.h *\brief MiniSat global functions * * Author: Alexander Fuchs * * Created: Fri Sep 08 11:04:00 2006 * *
* * License to use, copy, modify, sell and/or distribute this software * and its documentation for any purpose is hereby granted without * royalty, subject to the terms and conditions defined in the \ref * LICENSE file provided with this distribution. * *
*/ /*****************************************************************************/ /****************************************************************************************[Global.h] MiniSat -- Copyright (c) 2003-2005, Niklas Een, Niklas Sorensson Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. **************************************************************************************************/ #ifndef _cvc3__minisat__global_h_ #define _cvc3__minisat__global_h_ //================================================================================================= // Basic Types & Minor Things: // provides lbool and vec #include "debug.h" #include #include #include #include #include #include namespace MiniSat { template static inline T min(T x, T y) { return (x < y) ? x : y; } template static inline T max(T x, T y) { return (x > y) ? x : y; } template struct STATIC_ASSERTION_FAILURE; template <> struct STATIC_ASSERTION_FAILURE{}; #define TEMPLATE_FAIL STATIC_ASSERTION_FAILURE() //================================================================================================= // 'malloc()'-style memory allocation -- never returns NULL; aborts instead: template static inline T* xmalloc(size_t size) { T* tmp = (T*)malloc(size * sizeof(T)); DebugAssert(size == 0 || tmp != NULL, "Minisat::Global::xmalloc"); return tmp; } template static inline T* xrealloc(T* ptr, size_t size) { T* tmp = (T*)realloc((void*)ptr, size * sizeof(T)); DebugAssert(size == 0 || tmp != NULL, "Minisat::Global::xrealloc"); return tmp; } template static inline void xfree(T *ptr) { if (ptr != NULL) free((void*)ptr); } //================================================================================================= // Random numbers: // Returns a random float 0 <= x < 1. Seed must never be 0. static inline double drand(double& seed) { seed *= 1389796; int q = (int)(seed / 2147483647); seed -= (double)q * 2147483647; return seed / 2147483647; } // Returns a random integer 0 <= x < size. Seed must never be 0. static inline int irand(double& seed, int size) { return (int)(drand(seed) * size); } //================================================================================================= // 'vec' -- automatically resizable arrays (via 'push()' method): // NOTE! Don't use this vector on datatypes that cannot be re-located in memory (with realloc) template class vec { T* data; int sz; int cap; void init(int size, const T& pad); void grow(int min_cap); public: // Types: typedef int Key; typedef T Datum; // Constructors: vec(void) : data(NULL) , sz(0) , cap(0) { } vec(int size) : data(NULL) , sz(0) , cap(0) { growTo(size); } vec(int size, const T& pad) : data(NULL) , sz(0) , cap(0) { growTo(size, pad); } vec(T* array, int size) : data(array), sz(size), cap(size) { } // (takes ownership of array -- will be deallocated with 'xfree()') ~vec(void) { clear(true); } // Ownership of underlying array: T* release (void) { T* ret = data; data = NULL; sz = 0; cap = 0; return ret; } operator T* (void) { return data; } // (unsafe but convenient) operator const T* (void) const { return data; } // Size operations: int size (void) const { return sz; } void shrink (int nelems) { DebugAssert(nelems <= sz, "MiniSat::vec::shrink"); for (int i = 0; i < nelems; i++) sz--, data[sz].~T(); } void pop (void) { sz--, data[sz].~T(); } void growTo (int size); void growTo (int size, const T& pad); void clear (bool dealloc = false); void capacity (int size) { grow(size); } // Stack interface: void push (void) { if (sz == cap) grow(sz+1); new (&data[sz]) T() ; sz++; } void push (const T& elem) { if (sz == cap) grow(sz+1); new (&data[sz]) T(elem); sz++; } const T& last (void) const { return data[sz-1]; } T& last (void) { return data[sz-1]; } // Vector interface: const T& operator [] (int index) const { return data[index]; } T& operator [] (int index) { return data[index]; } // Don't allow copying (error prone): vec& operator = (vec& other) { TEMPLATE_FAIL; } vec (vec& other) { TEMPLATE_FAIL; } // Duplicatation (preferred instead): void copyTo(vec& copy) const { copy.clear(); copy.growTo(sz); for (int i = 0; i < sz; i++) new (©[i]) T(data[i]); } void moveTo(vec& dest) { dest.clear(true); dest.data = data; dest.sz = sz; dest.cap = cap; data = NULL; sz = 0; cap = 0; } }; template void vec::grow(int min_cap) { if (min_cap <= cap) return; if (cap == 0) cap = (min_cap >= 2) ? min_cap : 2; else do cap = (cap*3+1) >> 1; while (cap < min_cap); data = xrealloc(data, cap); } template void vec::growTo(int size, const T& pad) { if (sz >= size) return; grow(size); for (int i = sz; i < size; i++) new (&data[i]) T(pad); sz = size; } template void vec::growTo(int size) { if (sz >= size) return; grow(size); for (int i = sz; i < size; i++) new (&data[i]) T(); sz = size; } template void vec::clear(bool dealloc) { if (data != NULL){ for (int i = 0; i < sz; i++) data[i].~T(); sz = 0; if (dealloc) xfree(data), data = NULL, cap = 0; } } //================================================================================================= // Lifted booleans: class lbool { int value; explicit lbool(int v) : value(v) { } public: lbool() : value(0) { } lbool(bool x) : value((int)x*2-1) { } int toInt(void) const { return value; } bool operator == (const lbool& other) const { return value == other.value; } bool operator != (const lbool& other) const { return value != other.value; } lbool operator ~ (void) const { return lbool(-value); } friend int toInt (lbool l); friend lbool toLbool(int v); }; inline int toInt (lbool l) { return l.toInt(); } inline lbool toLbool(int v) { return lbool(v); } const lbool l_True = toLbool( 1); const lbool l_False = toLbool(-1); const lbool l_Undef = toLbool( 0); //================================================================================================= // Relation operators -- extend definitions from '==' and '<' #ifndef __SGI_STL_INTERNAL_RELOPS // (be aware of SGI's STL implementation...) #define __SGI_STL_INTERNAL_RELOPS template static inline bool operator != (const T& x, const T& y) { return !(x == y); } template static inline bool operator > (const T& x, const T& y) { return y < x; } template static inline bool operator <= (const T& x, const T& y) { return !(y < x); } template static inline bool operator >= (const T& x, const T& y) { return !(x < y); } #endif } //================================================================================================= #endif cvc3-2.4.1/src/sat/minisat_varorder.h0000664000175400017540000001112111356544153017360 0ustar mdetersmdeters/*****************************************************************************/ /*! *\file minisat_varorder.h *\brief MiniSat decision heuristics * * Author: Alexander Fuchs * * Created: Fri Sep 08 11:04:00 2006 * *
* * License to use, copy, modify, sell and/or distribute this software * and its documentation for any purpose is hereby granted without * royalty, subject to the terms and conditions defined in the \ref * LICENSE file provided with this distribution. * *
*/ /*****************************************************************************/ /**************************************************************************************[VarOrder.h] MiniSat -- Copyright (c) 2003-2005, Niklas Een, Niklas Sorensson Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. **************************************************************************************************/ #ifndef _cvc3__minisat__varorder_h_ #define _cvc3__minisat__varorder_h_ //================================================================================================= #include "minisat_types.h" #include "minisat_heap.h" #include #include // implements the decision heuristics by using a heap over variable ids (which are ints) namespace MiniSat { struct VarOrder_lt { const std::vector& activity; bool operator () (Var x, Var y) { return activity[x] > activity[y]; } VarOrder_lt(const std::vector& act) : activity(act) { } }; class VarOrder { const std::vector& assigns; // var->val. Pointer to external assignment table. const std::vector& activity; // var->act. Pointer to external activity table. Heap heap; double random_seed; // For the internal random number generator public: VarOrder(const std::vector& ass, const std::vector& act) : assigns(ass), activity(act), heap(VarOrder_lt(act)), random_seed(91648253) { } inline void newVar(void); inline void newVar(int varIndex); inline void update(Var x); // Called when variable increased in activity. inline void undo(Var x); // Called when variable is unassigned and may be selected again. inline Var select(double random_freq =.0); // Selects a new, unassigned variable (or 'var_Undef' if none exists). }; void VarOrder::newVar(void) { heap.setBounds(assigns.size()); heap.insert(assigns.size()-1); } void VarOrder::newVar(int varIndex) { heap.setBounds(assigns.size()); heap.insert(varIndex); } void VarOrder::update(Var x) { if (heap.inHeap(x)) heap.increase(x); } void VarOrder::undo(Var x) { if (!heap.inHeap(x)) heap.insert(x); } Var VarOrder::select(double random_var_freq) { // Random decision: /* if (drand(random_seed) < random_var_freq && !heap.empty()){ Var next = irand(random_seed,assigns.size()); // find var which is not undefined or in the heap while (toLbool(assigns[next]) == l_Undef && !heap.inHeap(next)) { next = irand(random_seed,assigns.size()); } if (toLbool(assigns[next]) == l_Undef) { return next; } // cvc does not necessarily use all variable ids without gaps, // so need to check if the picked id is a valid variable. //if (toLbool(assigns[next]) == l_Undef && heap.inHeap(next)) { // return next; //} } */ // Activity based decision: while (!heap.empty()){ Var next = heap.getMin(); if (toLbool(assigns[next]) == l_Undef) return next; } return var_Undef; } } //================================================================================================= #endif cvc3-2.4.1/src/sat/cnf_theorem_producer.cpp0000664000175400017540000002336711353736703020557 0ustar mdetersmdeters/*****************************************************************************/ /*! *\file cnf_theorem_producer.cpp *\brief Implementation of CNF_TheoremProducer * * Author: Clark Barrett * * Created: Thu Jan 5 05:49:24 2006 * *
* * License to use, copy, modify, sell and/or distribute this software * and its documentation for any purpose is hereby granted without * royalty, subject to the terms and conditions defined in the \ref * LICENSE file provided with this distribution. * *
* */ /*****************************************************************************/ #include "cnf_manager.h" #define _CVC3_TRUSTED_ #include "cnf_theorem_producer.h" using namespace std; using namespace CVC3; using namespace SAT; ///////////////////////////////////////////////////////////////////////////// // class CNF_Manager trusted methods ///////////////////////////////////////////////////////////////////////////// CNF_Rules* CNF_Manager::createProofRules(TheoremManager* tm, const CLFlags& flags) { return new CNF_TheoremProducer(tm, flags); } ///////////////////////////////////////////////////////////////////////////// // Proof rules ///////////////////////////////////////////////////////////////////////////// void CNF_TheoremProducer::getSmartClauses(const Theorem& thm, vector& clauses) { // DebugAssert(!thm.getExpr().isDeductionLiteral(), "Expected unproved expr"); vector assumptions; thm.clearAllFlags(); thm.GetSatAssumptions(assumptions); // Proof pf; // if (withProof()) { // pf = newPf("learned_clause_smart", thm.getProof()); // } Theorem thm2; vector TempVec; vector pfs; if (!thm.getExpr().isFalse()) { TempVec.push_back(thm.getExpr()); pfs.push_back(thm.getProof()); } for (vector::size_type i = 0; i < assumptions.size(); i++) { if (thm.getExpr() == assumptions[i].getExpr()) { // skip this clause as it is trivial if (!(assumptions[i].isAssump())) { getSmartClauses(assumptions[i], clauses); } return; } TempVec.push_back(assumptions[i].getExpr().negate()); pfs.push_back(assumptions[i].getProof()); } Proof pf; if (TempVec.size() == 1){ if (withProof()) { pf = newPf("learned_clause_smart", TempVec[0], pfs); } thm2 = newTheorem(TempVec[0], Assumptions::emptyAssump(), pf); } else if (TempVec.size() > 1) { if (withProof()) { pf = newPf("learned_clause_smart", Expr(OR, TempVec), pfs); } thm2 = newTheorem(Expr(OR, TempVec), Assumptions::emptyAssump(), pf); } else { FatalAssert(false, "Should be unreachable"); } thm2.setQuantLevel(thm.getQuantLevel()); clauses.push_back(thm2); // thm.getExpr().setDeductionLiteral(); for (vector::iterator itr = assumptions.begin(); itr != assumptions.end(); itr++) { if (!((*itr).isAssump())) {// && !(*itr).getExpr().isDeductionLiteral()) { getSmartClauses((*itr), clauses); } } } void CNF_TheoremProducer::learnedClauses(const Theorem& thm, vector& clauses, bool newLemma) { IF_DEBUG(if(debugger.trace("cnf proofs")) { ostream& os = debugger.getOS(); os << "learnedClause {" << endl; os << thm; }) if (!newLemma && d_smartClauses) { getSmartClauses(thm, clauses); return; } // if (newLemma || d_flags["dynack"].getInt() <= 0) { // if (NewClausel == true) { // return; // } vector assumptions; Proof pf; thm.getLeafAssumptions(assumptions, true /*negate*/); vector::iterator iend = assumptions.end(); for (vector::iterator i = assumptions.begin(); i != iend; ++i) { DebugAssert(i->isAbsLiteral(), "Expected only literal assumptions"); } if (!thm.getExpr().isFalse()) assumptions.push_back(thm.getExpr()); DebugAssert(assumptions.size() > 0, "Expected at least one entry"); Theorem thm2; if (assumptions.size() == 1) { if(withProof()) { pf = newPf("learned_clause", thm.getProof()); } thm2 = newTheorem(assumptions[0], Assumptions::emptyAssump(), pf); } else { Expr clauseExpr = Expr(OR, assumptions); if(withProof()) { pf = newPf("learned_clause", thm.getProof()); } thm2 = newTheorem(clauseExpr, Assumptions::emptyAssump(), pf); } thm2.setQuantLevel(thm.getQuantLevel()); clauses.push_back(thm2); // } // else { // vector congruences; // thm.getAssumptionsAndCong(assumptions, congruences, true /*negate*/); // vector::iterator i = assumptions.begin(), iend = assumptions.end(); // for (; i != iend; ++i) { // DebugAssert(i->isAbsLiteral(), "Expected only literal assumptions"); // } // if (!thm.getExpr().isFalse()) // assumptions.push_back(thm.getExpr()); // if(withProof()) { // pf = newPf("learned_clause", thm.getProof()); // } // DebugAssert(assumptions.size() > 0, "Expected at least one entry"); // Theorem thm2; // if (assumptions.size() == 1) { // Expr clauseExpr = assumptions[0]; // if(withProof()) { // pf = newPf("learned_clause", clauseExpr, thm.getProof()); // } // thm2 = newTheorem(clauseExpr, Assumptions::emptyAssump(), pf); // } // else { // Expr clauseExpr = Expr(OR, assumptions); // if(withProof()) { // pf = newPf("learned_clause", clauseExpr, thm.getProof()); // } // thm2 = newTheorem(clauseExpr, Assumptions::emptyAssump(), pf); // } // thm2.setQuantLevel(thm.getQuantLevel()); // clauses.push_back(thm2); // for (i = congruences.begin(), iend = congruences.end(); i != iend; ++i) { // if (withProof()) { // pf = newPf("congruence", *i); // } // thm2 = newTheorem(*i, Assumptions::emptyAssump(), pf); // thm2.setQuantLevel(thm.getQuantLevel()); // clauses.push_back(thm2); // } // } } Theorem CNF_TheoremProducer::ifLiftRule(const Expr& e, int itePos) { if(CHECK_PROOFS) { CHECK_SOUND(e.getType().isBool(), "CNF_TheoremProducer::ifLiftRule(" "input must be a Predicate: e = " + e.toString()+")"); CHECK_SOUND(itePos >= 0, "itePos negative"+int2string(itePos)); CHECK_SOUND(e.arity() > itePos && e[itePos].isITE(), "CNF_TheoremProducer::ifLiftRule(" "input does not have an ITE: e = " + e.toString()+")"); } const Expr& ite = e[itePos]; const Expr& cond = ite[0]; const Expr& t1 = ite[1]; const Expr& t2 = ite[2]; if(CHECK_PROOFS) { CHECK_SOUND(cond.getType().isBool(), "CNF_TheoremProducer::ifLiftRule(" "input does not have an ITE: e = " + e.toString()+")"); } vector k1 = e.getKids(); Op op(e.getOp()); k1[itePos] = t1; Expr pred1 = Expr(op, k1); k1[itePos] = t2; Expr pred2 = Expr(op, k1); Expr resultITE = cond.iteExpr(pred1, pred2); Proof pf; if (withProof()) pf = newPf("if_lift_rule", e, resultITE, d_em->newRatExpr(itePos)); return newRWTheorem(e, resultITE, Assumptions::emptyAssump(), pf); } Theorem CNF_TheoremProducer::CNFtranslate(const Expr& before, const Expr& after, std::string reason, int pos, const vector& thms) { //well, this is assert the e as a theorem without any justification. //change this as soon as possible // cout << "###" << before; Proof pf; if (withProof()){ vector chs ; chs.push_back(d_em->newStringExpr(reason)); chs.push_back(before); chs.push_back(after); chs.push_back(d_em->newRatExpr(pos)); vector pfs; for(vector::const_iterator i = thms.begin(), iend= thms.end(); i != iend; i++){ pfs.push_back((*i).getProof()); } pf = newPf("CNF", chs, pfs ); } return newTheorem(after, Assumptions(thms), pf); } Theorem CNF_TheoremProducer::CNFITEtranslate(const Expr& before, const vector& after, const vector& thms, int pos){ DebugAssert(3 == after.size(), "why this happens"); DebugAssert(3 == thms.size(), "why this happens"); Proof pf; if (withProof()){ DebugAssert(thms[0].getRHS() == after[0] , "this never happens"); DebugAssert(thms[1].getRHS() == after[1] , "this never happens"); DebugAssert(thms[2].getRHS() == after[2] , "this never happens"); DebugAssert(thms[0].getLHS() == before[0] , "this never happens"); DebugAssert(thms[1].getLHS() == before[1] , "this never happens"); DebugAssert(thms[2].getLHS() == before[2] , "this never happens"); vector chs ; chs.push_back(before); chs.push_back(after[0]); chs.push_back(after[1]); chs.push_back(after[2]); chs.push_back(d_em->newRatExpr(pos)); vector pfs; pfs.push_back(thms[0].getProof()); pfs.push_back(thms[1].getProof()); pfs.push_back(thms[2].getProof()); pf = newPf("CNFITE", chs, pfs ); } Expr newe0 = after[0]; Expr afterExpr = newe0.iteExpr(after[1],after[2]); //we should produce a newRWTheorm whenever possible and then use iffmp rule to get the desired result return newTheorem(afterExpr, Assumptions(thms), pf); } // because the way of cnf translation, add unit means the theorem from other parts of cvc3, not from cnf translation Theorem CNF_TheoremProducer::CNFAddUnit(const Theorem& thm){ //wrap the thm so the hol light translator know this Proof pf; if (withProof()){ pf = newPf("cnf_add_unit", thm.getExpr(), thm.getProof() ); } return newTheorem(thm.getExpr(), thm.getAssumptionsRef(), pf); } Theorem CNF_TheoremProducer::CNFConvert(const Expr& e, const Theorem& thm){ //wrap the thm so the hol light translator know this Proof pf; if (withProof()){ pf = newPf("cnf_convert", e, thm.getExpr(), thm.getProof() ); } DebugAssert(thm.getExpr().isOr(),"convert is not or exprs"); return newTheorem(thm.getExpr(), thm.getAssumptionsRef(), pf); } cvc3-2.4.1/src/sat/cnf_manager.cpp0000664000175400017540000005103711353534536016616 0ustar mdetersmdeters/*****************************************************************************/ /*! *\file cnf_manager.cpp *\brief Implementation of CNF_Manager * * Author: Clark Barrett * * Created: Thu Jan 5 02:30:02 2006 * *
* * License to use, copy, modify, sell and/or distribute this software * and its documentation for any purpose is hereby granted without * royalty, subject to the terms and conditions defined in the \ref * LICENSE file provided with this distribution. * *
*/ /*****************************************************************************/ #include "cnf_manager.h" #include "cnf_rules.h" #include "common_proof_rules.h" #include "theorem_manager.h" #include "vc.h" #include "command_line_flags.h" using namespace std; using namespace CVC3; using namespace SAT; CNF_Manager::CNF_Manager(TheoremManager* tm, Statistics& statistics, const CLFlags& flags) : d_vc(NULL), d_commonRules(tm->getRules()), // d_theorems(tm->getCM()->getCurrentContext()), d_clauseIdNext(0), // d_translated(tm->getCM()->getCurrentContext()), d_bottomScope(-1), d_statistics(statistics), d_flags(flags), d_nullExpr(tm->getEM()->getNullExpr()), d_cnfCallback(NULL) { d_rules = createProofRules(tm, flags); // Push dummy varinfo onto d_varInfo since Var's are indexed from 1 not 0 Varinfo v; d_varInfo.push_back(v); if (flags["minimizeClauses"].getBool()) { CLFlags flags = ValidityChecker::createFlags(); flags.setFlag("minimizeClauses",false); d_vc = ValidityChecker::create(flags); } } CNF_Manager::~CNF_Manager() { if (d_vc) delete d_vc; delete d_rules; } void CNF_Manager::registerAtom(const Expr& e, const Theorem& thm) { DebugAssert(!e.isRegisteredAtom() || e.isUserRegisteredAtom(), "Atom already registered"); if (d_cnfCallback && !e.isRegisteredAtom()) d_cnfCallback->registerAtom(e, thm); } Theorem CNF_Manager::replaceITErec(const Expr& e, Var v, bool translateOnly) { // Quick exit for atomic expressions if (e.isAtomic()) return d_commonRules->reflexivityRule(e); // Check cache Theorem thm; bool foundInCache = false; ExprHashMap::iterator iMap = d_iteMap.find(e); if (iMap != d_iteMap.end()) { thm = (*iMap).second; foundInCache = true; } if (e.getKind() == ITE) { // Replace non-Bool ITE expressions DebugAssert(!e.getType().isBool(), "Expected non-Bool ITE"); // generate e = x for new x if (!foundInCache) thm = d_commonRules->varIntroSkolem(e); Theorem thm2 = d_commonRules->symmetryRule(thm); thm2 = d_commonRules->iffMP(thm2, d_rules->ifLiftRule(thm2.getExpr(), 1)); d_translateQueueVars.push_back(v); d_translateQueueThms.push_back(thm2); d_translateQueueFlags.push_back(translateOnly); } else { // Recursively traverse, replacing ITE's vector thms; vector changed; unsigned index = 0; Expr::iterator i, iend; if (foundInCache) { for(i = e.begin(), iend = e.end(); i!=iend; ++i, ++index) { replaceITErec(*i, v, translateOnly); } } else { for(i = e.begin(), iend = e.end(); i!=iend; ++i, ++index) { thm = replaceITErec(*i, v, translateOnly); if (!thm.isRefl()) { thms.push_back(thm); changed.push_back(index); } } if(changed.size() > 0) { thm = d_commonRules->substitutivityRule(e, changed, thms); } else thm = d_commonRules->reflexivityRule(e); } } // Update cache and return if (!foundInCache) d_iteMap[e] = thm; return thm; } Expr CNF_Manager::concreteExpr(const CVC3::Expr& e, const Lit& literal){ if ( e.isTrue() || e.isFalse() || (e.isNot() && (e[0].isTrue() || e[0].isFalse()))) return e; else return concreteLit(literal); } Theorem CNF_Manager::concreteThm(const CVC3::Expr& ine){ Theorem ret = d_iteMap[ine]; if (ret.isNull()) { ret = d_commonRules->reflexivityRule(ine); } return ret; } Lit CNF_Manager::translateExprRec(const Expr& e, CNF_Formula& cnf, const Theorem& thmIn) { if (e.isFalse()) return Lit::getFalse(); if (e.isTrue()) return Lit::getTrue(); if (e.isNot()) return !translateExprRec(e[0], cnf, thmIn); ExprHashMap::iterator iMap = d_cnfVars.find(e); if (e.isTranslated()) { DebugAssert(iMap != d_cnfVars.end(), "Translated expr should be in map"); return Lit((*iMap).second); } else e.setTranslated(d_bottomScope); Var v(int(d_varInfo.size())); bool translateOnly = false; if (iMap != d_cnfVars.end()) { v = (*iMap).second; translateOnly = true; d_varInfo[v].fanouts.clear(); } else { d_varInfo.resize(v+1); d_varInfo.back().expr = e; d_cnfVars[e] = v; } Expr::iterator i, iend; bool isAnd = false; switch (e.getKind()) { case AND: isAnd = true; case OR: { vector lits; unsigned idx; for (i = e.begin(), iend = e.end(); i != iend; ++i) { lits.push_back(translateExprRec(*i, cnf, thmIn)); } vector new_chls; vector thms; for (idx = 0; idx < lits.size(); ++idx) { new_chls.push_back(concreteExpr(e[idx],lits[idx])); thms.push_back(concreteThm(e[idx])); } Expr after = (isAnd ? Expr(AND,new_chls) : Expr(OR,new_chls)) ; // DebugAssert(concreteExpr(e,Lit(v)) == e,"why here"); for (idx = 0; idx < lits.size(); ++idx) { cnf.newClause(); cnf.addLiteral(Lit(v),isAnd); cnf.addLiteral(lits[idx], !isAnd); // DebugAssert(concreteExpr(e[idx],lits[idx]) == e[idx], "why here"); std::string reasonStr = (isAnd ? "and_mid" : "or_mid"); cnf.getCurrentClause().setClauseTheorem(d_rules->CNFtranslate(e, after, reasonStr, idx,thms)); // by yeting } cnf.newClause(); cnf.addLiteral(Lit(v),!isAnd); for (idx = 0; idx < lits.size(); ++idx) { cnf.addLiteral(lits[idx], isAnd); } std::string reasonStr = (isAnd ? "and_final" : "or_final") ; cnf.getCurrentClause().setClauseTheorem(d_rules->CNFtranslate(e, after, reasonStr, 0, thms)); // by yeting DebugAssert(!d_flags["cnf-formula"].getBool(), "Found impossible case when cnf-formula is enabled"); break; } case IMPLIES: { Lit arg0 = translateExprRec(e[0], cnf, thmIn); Lit arg1 = translateExprRec(e[1], cnf, thmIn); vector thms; thms.push_back(concreteThm(e[0])); thms.push_back(concreteThm(e[1])); Expr left = (concreteExpr(e[0],arg0)); Expr right = (concreteExpr(e[1],arg1)); Expr after = left.impExpr(right); // DebugAssert(concreteExpr(e, Lit(v)) == e, "why here"); // DebugAssert(concreteExpr(e[0], arg0) == e[0], "why here"); // DebugAssert(concreteExpr(e[1], arg1) == e[1], "why here"); cnf.newClause(); cnf.addLiteral(Lit(v)); cnf.addLiteral(arg0); cnf.getCurrentClause().setClauseTheorem( d_rules->CNFtranslate(e, after, "imp", 0,thms)); // by yeting cnf.newClause(); cnf.addLiteral(Lit(v)); cnf.addLiteral(arg1,true); cnf.getCurrentClause().setClauseTheorem( d_rules->CNFtranslate(e, after, "imp", 1, thms)); // by yeting cnf.newClause(); cnf.addLiteral(Lit(v),true); cnf.addLiteral(arg0,true); cnf.addLiteral(arg1); cnf.getCurrentClause().setClauseTheorem( d_rules->CNFtranslate(e, after, "imp", 2,thms)); // by yeting DebugAssert(!d_flags["cnf-formula"].getBool(), "Found impossible case when cnf-formula is enabled"); break; } case IFF: { Lit arg0 = translateExprRec(e[0], cnf, thmIn); Lit arg1 = translateExprRec(e[1], cnf, thmIn); // DebugAssert(concreteExpr(e, Lit(v)) == e, "why here"); // DebugAssert(concreteExpr(e[0], arg0) == e[0], "why here"); // DebugAssert(concreteExpr(e[1], arg1) == e[1], "why here"); vector thms; thms.push_back(concreteThm(e[0])); thms.push_back(concreteThm(e[1])); Expr left = (concreteExpr(e[0],arg0)); Expr right = (concreteExpr(e[1],arg1)); Expr after = left.iffExpr(right); cnf.newClause(); cnf.addLiteral(Lit(v)); cnf.addLiteral(arg0); cnf.addLiteral(arg1); cnf.getCurrentClause().setClauseTheorem(d_rules->CNFtranslate(e, after, "iff", 0, thms)); // by yeting cnf.newClause(); cnf.addLiteral(Lit(v)); cnf.addLiteral(arg0,true); cnf.addLiteral(arg1,true); cnf.getCurrentClause().setClauseTheorem(d_rules->CNFtranslate(e, after, "iff", 1, thms)); // by yeting cnf.newClause(); cnf.addLiteral(Lit(v),true); cnf.addLiteral(arg0,true); cnf.addLiteral(arg1); cnf.getCurrentClause().setClauseTheorem(d_rules->CNFtranslate(e, after, "iff", 2, thms)); // by yeting cnf.newClause(); cnf.addLiteral(Lit(v),true); cnf.addLiteral(arg0); cnf.addLiteral(arg1,true); cnf.getCurrentClause().setClauseTheorem(d_rules->CNFtranslate(e, after, "iff", 3, thms)); // by yeting DebugAssert(!d_flags["cnf-formula"].getBool(), "Found impossible case when cnf-formula is enabled"); break; } case XOR: { Lit arg0 = translateExprRec(e[0], cnf, thmIn); Lit arg1 = translateExprRec(e[1], cnf, thmIn); // DebugAssert(concreteExpr(e, Lit(v)) == e, "why here"); // DebugAssert(concreteExpr(e[0], arg0) == e[0], "why here"); // DebugAssert(concreteExpr(e[1], arg1) == e[1], "why here"); vector thms; thms.push_back(concreteThm(e[0])); thms.push_back(concreteThm(e[1])); Expr left = (concreteExpr(e[0],arg0)); Expr right = (concreteExpr(e[1],arg1)); Expr after = left.xorExpr(right); cnf.newClause(); cnf.addLiteral(Lit(v),true); cnf.addLiteral(arg0); cnf.addLiteral(arg1); cnf.getCurrentClause().setClauseTheorem(d_rules->CNFtranslate(e, after, "xor", 0, thms)); // by yeting cnf.newClause(); cnf.addLiteral(Lit(v),true); cnf.addLiteral(arg0,true); cnf.addLiteral(arg1,true); cnf.getCurrentClause().setClauseTheorem(d_rules->CNFtranslate(e, after, "xor", 1, thms)); // by yeting cnf.newClause(); cnf.addLiteral(Lit(v)); cnf.addLiteral(arg0,true); cnf.addLiteral(arg1); cnf.getCurrentClause().setClauseTheorem(d_rules->CNFtranslate(e, after, "xor", 2, thms)); // by yeting cnf.newClause(); cnf.addLiteral(Lit(v)); cnf.addLiteral(arg0); cnf.addLiteral(arg1,true); cnf.getCurrentClause().setClauseTheorem(d_rules->CNFtranslate(e, after, "xor", 3,thms)); // by yeting DebugAssert(!d_flags["cnf-formula"].getBool(), "Found impossible case when cnf-formula is enabled"); break; } case ITE: { Lit arg0 = translateExprRec(e[0], cnf, thmIn); Lit arg1 = translateExprRec(e[1], cnf, thmIn); Lit arg2 = translateExprRec(e[2], cnf, thmIn); Expr aftere0 = concreteExpr(e[0], arg0); Expr aftere1 = concreteExpr(e[1], arg1); Expr aftere2 = concreteExpr(e[2], arg2); vector after ; after.push_back(aftere0); after.push_back(aftere1); after.push_back(aftere2); Theorem e0thm; Theorem e1thm; Theorem e2thm; { e0thm = d_iteMap[e[0]]; if (e0thm.isNull()) e0thm = d_commonRules->reflexivityRule(e[0]); e1thm = d_iteMap[e[1]]; if (e1thm.isNull()) e1thm = d_commonRules->reflexivityRule(e[1]); e2thm = d_iteMap[e[2]]; if (e2thm.isNull()) e2thm = d_commonRules->reflexivityRule(e[2]); } vector thms ; thms.push_back(e0thm); thms.push_back(e1thm); thms.push_back(e2thm); cnf.newClause(); cnf.addLiteral(Lit(v),true); cnf.addLiteral(arg0); cnf.addLiteral(arg2); cnf.getCurrentClause().setClauseTheorem(d_rules->CNFITEtranslate(e, after,thms, 1)); // by yeting cnf.newClause(); cnf.addLiteral(Lit(v)); cnf.addLiteral(arg0); cnf.addLiteral(arg2,true); cnf.getCurrentClause().setClauseTheorem(d_rules->CNFITEtranslate(e, after,thms, 2)); // by yeting cnf.newClause(); cnf.addLiteral(Lit(v)); cnf.addLiteral(arg0,true); cnf.addLiteral(arg1,true); cnf.getCurrentClause().setClauseTheorem(d_rules->CNFITEtranslate(e, after,thms, 3)); // by yeting cnf.newClause(); cnf.addLiteral(Lit(v),true); cnf.addLiteral(arg0,true); cnf.addLiteral(arg1); cnf.getCurrentClause().setClauseTheorem(d_rules->CNFITEtranslate(e, after,thms, 4)); // by yeting cnf.newClause(); cnf.addLiteral(Lit(v)); cnf.addLiteral(arg1,true); cnf.addLiteral(arg2,true); cnf.getCurrentClause().setClauseTheorem(d_rules->CNFITEtranslate(e, after,thms, 5)); // by yeting cnf.newClause(); cnf.addLiteral(Lit(v),true); cnf.addLiteral(arg1); cnf.addLiteral(arg2); cnf.getCurrentClause().setClauseTheorem(d_rules->CNFITEtranslate(e, after,thms, 6)); // by yeting DebugAssert(!d_flags["cnf-formula"].getBool(), "Found impossible case when cnf-formula is enabled"); break; } default: { DebugAssert(!e.isAbsAtomicFormula() || d_varInfo[v].expr == e, "Corrupted Varinfo"); if (e.isAbsAtomicFormula()) { registerAtom(e, thmIn); return Lit(v); } DebugAssert(!d_flags["cnf-formula"].getBool(), "Found impossible case when cnf-formula is enabled"); Theorem thm = replaceITErec(e, v, translateOnly); const Expr& e2 = thm.getRHS(); DebugAssert(e2.isAbsAtomicFormula(), "Expected AbsAtomicFormula"); if (e2.isTranslated()) { // Ugly corner case: we happen to create an expression that has been // created before. We remove the current variable and fix up the // translation stack. if (translateOnly) { DebugAssert(v == d_cnfVars[e2], "Expected literal match"); } else { d_varInfo.resize(v); while (!d_translateQueueVars.empty() && d_translateQueueVars.back() == v) { d_translateQueueVars.pop_back(); } DebugAssert(d_cnfVars.find(e2) != d_cnfVars.end(), "Expected existing literal"); v = d_cnfVars[e2]; d_cnfVars[e] = v; while (d_translateQueueVars.size() < d_translateQueueThms.size()) { d_translateQueueVars.push_back(v); } } } else { e2.setTranslated(d_bottomScope); // Corner case: don't register reflexive equality if (!e2.isEq() || e2[0] != e2[1]) registerAtom(e2, thmIn); if (!translateOnly) { if (d_cnfVars.find(e2) == d_cnfVars.end()) { d_varInfo[v].expr = e2; d_cnfVars[e2] = v; } else { // Same corner case in an untranslated expr d_varInfo.resize(v); while (!d_translateQueueVars.empty() && d_translateQueueVars.back() == v) { d_translateQueueVars.pop_back(); } v = d_cnfVars[e2]; d_cnfVars[e] = v; while (d_translateQueueVars.size() < d_translateQueueThms.size()) { d_translateQueueVars.push_back(v); } } } } return Lit(v); } } // Record fanins / fanouts Lit l; for (i = e.begin(), iend = e.end(); i != iend; ++i) { l = getCNFLit(*i); DebugAssert(!l.isNull(), "Expected non-null literal"); if (!translateOnly) d_varInfo[v].fanins.push_back(l); if (l.isVar()) d_varInfo[l.getVar()].fanouts.push_back(v); } return Lit(v); } Lit CNF_Manager::translateExpr(const Theorem& thmIn, CNF_Formula& cnf) { Lit l; Var v; Expr e = thmIn.getExpr(); Theorem thm; bool translateOnly; Lit ret = translateExprRec(e, cnf, thmIn); while (d_translateQueueVars.size()) { v = d_translateQueueVars.front(); d_translateQueueVars.pop_front(); thm = d_translateQueueThms.front(); d_translateQueueThms.pop_front(); translateOnly = d_translateQueueFlags.front(); d_translateQueueFlags.pop_front(); l = translateExprRec(thm.getExpr(), cnf, thmIn); cnf.newClause(); cnf.addLiteral(l); cnf.registerUnit(); Theorem newThm = d_rules->CNFAddUnit(thm); // d_theorems.insert(d_clauseIdNext, thm); // cnf.getCurrentClause().setClauseTheorem(thmIn); // by yeting cnf.getCurrentClause().setClauseTheorem(newThm); // by yeting /* cout<<"set clause theorem 1" << thm << endl; cout<<"set clause theorem 2 " << thmIn << endl; cout<<"set clause print" ; cnf.getCurrentClause().print() ; cout<& newLits) { if (lb == ub) { newLits.push_back(lb); return; } unsigned new_lb = (ub-lb+1)/2 + lb; unsigned index; QueryResult res; d_vc->push(); for (index = new_lb; index <= ub; ++index) { d_vc->assertFormula(e2[index].negate()); } res = d_vc->query(d_vc->falseExpr()); d_vc->pop(); if (res == VALID) { cons(new_lb, ub, e2, newLits); return; } unsigned new_ub = new_lb-1; d_vc->push(); for (index = lb; index <= new_ub; ++index) { d_vc->assertFormula(e2[index].negate()); } res = d_vc->query(d_vc->falseExpr()); if (res == VALID) { d_vc->pop(); cons(lb, new_ub, e2, newLits); return; } cons(new_lb, ub, e2, newLits); d_vc->pop(); d_vc->push(); for (index = 0; index < newLits.size(); ++index) { d_vc->assertFormula(e2[newLits[index]].negate()); } cons(lb, new_ub, e2, newLits); d_vc->pop(); } void CNF_Manager::convertLemma(const Theorem& thm, CNF_Formula& cnf) { DebugAssert(cnf.empty(), "Expected empty cnf"); vector clauses; d_rules->learnedClauses(thm, clauses, false); vector::iterator i = clauses.begin(), iend = clauses.end(); for (; i < iend; ++i) { // for dumping lemmas: cnf.newClause(); Expr e = (*i).getExpr(); if (!e.isOr()) { DebugAssert(!getCNFLit(e).isNull(), "Unknown literal"); cnf.addLiteral(getCNFLit(e)); cnf.registerUnit(); cnf.getCurrentClause().setClauseTheorem(d_rules->CNFAddUnit(*i)); } else { Expr::iterator jend = e.end(); for (Expr::iterator j = e.begin(); j != jend; ++j) { DebugAssert(!getCNFLit(*j).isNull(), "Unknown literal"); cnf.addLiteral(getCNFLit(*j)); } cnf.getCurrentClause().setClauseTheorem(d_rules->CNFConvert(e, *i)); } } } Lit CNF_Manager::addAssumption(const Theorem& thm, CNF_Formula& cnf) { if (d_flags["cnf-formula"].getBool()) { Expr e = thm.getExpr(); DebugAssert(e.isOr() || (e.isNot() && e[0].isFalse()) || (e.isNot() && e[0].isTrue()), "expr:" + e.toString() + " is not an OR Expr or Ture or False" ); cnf.newClause(); if (e.isOr()){ for (int i = 0; i < e.arity(); i++){ Lit l = (translateExprRec(e[i], cnf, thm)); cnf.addLiteral(l); } cnf.getCurrentClause().setClauseTheorem(thm); return translateExprRec(e[0], cnf, thm) ;; } else { Lit l = translateExpr(thm, cnf); cnf.addLiteral(l); cnf.registerUnit(); cnf.getCurrentClause().setClauseTheorem(thm); return l; } } Lit l = translateExpr(thm, cnf); cnf.newClause(); cnf.addLiteral(l); cnf.registerUnit(); // if(concreteLit(l) != thm.getExpr()){ // cout<<"fail addunit 3" << endl; // } Theorem newThm = d_rules->CNFAddUnit(thm); // d_theorems[d_clauseIdNext] = thm; cnf.getCurrentClause().setClauseTheorem(newThm); // by yeting /* cout<<"set clause theorem addassumption" << thm << endl; cout<<"set clause print" ; cnf.getCurrentClause().print() ; cout< clauses; d_rules->learnedClauses(thm, clauses, true); DebugAssert(clauses.size() == 1, "expected single clause"); Lit l = translateExpr(clauses[0], cnf); cnf.newClause(); cnf.addLiteral(l); cnf.registerUnit(); // if(concreteLit(l) != clauses[0].getExpr()){ // cout<<"fail addunit 4" << endl; // } Theorem newThm = d_rules->CNFAddUnit(clauses[0]); // d_theorems.insert(d_clauseIdNext, clause); cnf.getCurrentClause().setClauseTheorem(newThm); //by yeting /* cout<<"set clause theorem addlemma" << thm << endl; cout<<"set clause print" ; cnf.getCurrentClause().print() ; cout< * * License to use, copy, modify, sell and/or distribute this software * and its documentation for any purpose is hereby granted without * royalty, subject to the terms and conditions defined in the \ref * LICENSE file provided with this distribution. * *
*/ /*****************************************************************************/ /****************************************************************************************[Solver.C] MiniSat -- Copyright (c) 2003-2005, Niklas Een, Niklas Sorensson Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. **************************************************************************************************/ #include "minisat_solver.h" #include "minisat_types.h" #include #include #include using namespace std; using namespace MiniSat; /// /// Constants /// // if true do propositional propagation to exhaustion // before asserting propagated literals to the theories. // that is, a SAT propagation is not immediately asserted to the theories as well, // but only when the SAT core has to do a decision. // // this way a branch may be closed propositionally only, // which avoids work on the theory part, // and introduction of new theory clauses and implications. const bool defer_theory_propagation = true; /// theory implications // retrieve explanations of theory implications eagerly // and store them right away as clauses const bool eager_explanation = true; // if explanations for theory implications are retrieved lazily // during regressions, should they be added as clauses? // // only used if eager_explanation is false. const bool keep_lazy_explanation = true; /// pushes // determines which theory operations are done, // when unit propagation is done to exhaustion at the root level // because a push is done. // if true then assert propositional propagations to theories as well // (this is done anyway when defer_theory_propagation is false) const bool push_theory_propagation = true; // if push_theory_propagation is also true, // retrieve and propagate theory implications as well const bool push_theory_implication = true; // if push_theory_propagation is also true, // retrieve and add theory clauses as well (and handle their propagations) const bool push_theory_clause = true; // the number of literals considered in propLookahead() const vector::size_type prop_lookahead = 1; // print the derivation const bool protocol = false; //const bool protocol = true; // perform expensive assertion checks const bool debug_full = false; /// /// conversions between MiniSat and CVC data types: /// bool MiniSat::cvcToMiniSat(const SAT::Clause& clause, std::vector& literals) { // register all clause literals SAT::Clause::const_iterator j, jend; for (j = clause.begin(), jend = clause.end(); j != jend; ++j) { const SAT::Lit& literal = *j; // simplify based on true/false literals if (literal.isTrue()) return false; if (!literal.isFalse()) literals.push_back(cvcToMiniSat(literal)); } return true; } Clause* Solver::cvcToMiniSat(const SAT::Clause& clause, int id) { vector literals; if (MiniSat::cvcToMiniSat(clause, literals)) { if (getDerivation() != NULL) return Clause_new(literals, clause.getClauseTheorem(), id); else return Clause_new(literals, CVC3::Theorem(), id); } else { return NULL; } } /// Initialization Solver::Solver(SAT::DPLLT::TheoryAPI* theoryAPI, SAT::DPLLT::Decider* decider, bool logDerivation) : d_inSearch(false), d_ok(true), d_conflict(NULL), d_qhead (0), d_thead (0), d_registeredVars (1), d_clauseIDCounter (3), // -1 and -2 are used in Clause for special clauses, // and negative ids are in general used for theory clauses, // so avoid overlap by setting 3 as the possible first clause id. d_popRequests (0), d_cla_inc (1), d_cla_decay (1), d_var_inc (1), d_var_decay (1), d_order (d_assigns, d_activity), d_simpDB_assigns (0), d_simpDB_props (0), d_simpRD_learnts (0), d_theoryAPI(theoryAPI), d_decider(decider), d_derivation(NULL), d_default_params(SearchParams(0.95, 0.999, 0.02)), d_expensive_ccmin(true) { if (logDerivation) d_derivation = new Derivation(); } // add a lemma which has not been computed just now (see push(), createFrom()), // so it is not necessarily propagating void Solver::insertLemma(const Clause* lemma, int clauseID, int pushID) { // need to add lemmas manually, // as addClause/insertClause assume that the lemma has just been computed and is propagating, // and as we want to keep the activity. vector literals; lemma->toLit(literals); // If a lemma is based purely on theory lemmas (i.e. theory clauses), // then in backtracking those theory lemmas might be retracted, // and literals occurring in the lemma might not occur in any remaining clauses. // When creating a new solver based on an existing instance // (i.e. in continuing the search after finding a model), // then those literals have to be registered here. for (vector::const_iterator i = literals.begin(); i != literals.end(); ++i) { registerVar(i->var()); } // While lemma simplification might be nice to have, // this poses a problem with derivation recording, // as we would also have to modify the derivation of the original // lemma towards a derivation of the new lemma. // In the case of a new solver inheriting the lemmas of the previous solver // the lemma is registered for the first time in the derivation. // In the case where the lemma was kept over a push the old lemma // is registered with the derivation, but about to be removed from memory (xfree). // So the simplest thing is to just replace any previous registration of the // lemma with a new identical lemma, and not do any simplification at all. //if (!simplifyClause(literals, clauseID)) { // ensure that order is appropriate for watched literals orderClause(literals); Clause* newLemma = Lemma_new(literals, clauseID, pushID); if (getDerivation() != NULL) getDerivation()->registerClause(newLemma); newLemma->setActivity(lemma->activity()); // add to watches and lemmas if (newLemma->size() >= 2) { addWatch(~(*newLemma)[0], newLemma); addWatch(~(*newLemma)[1], newLemma); } d_learnts.push_back(newLemma); d_stats.learnts_literals += newLemma->size(); // unsatisfiable if (newLemma->size() == 0 || getValue((*newLemma)[0]) == l_False) { updateConflict(newLemma); } // propagate if (newLemma->size() == 1 || getValue((*newLemma)[1]) == l_False) { if (!enqueue((*newLemma)[0], d_rootLevel, newLemma)) { DebugAssert(false, "MiniSat::Solver::insertLemma: conflicting/implying lemma"); } } //} } Solver* Solver::createFrom(const Solver* oldSolver) { Solver* solver = new MiniSat::Solver(oldSolver->d_theoryAPI, oldSolver->d_decider, oldSolver->d_derivation != NULL); // reuse literal activity // assigning d_activity before the clauses are added // will automatically rebuild d_order in the right way. solver->d_cla_inc = oldSolver->d_cla_inc; solver->d_var_inc = oldSolver->d_var_inc; solver->d_activity = oldSolver->d_activity; // build the current formula // add the formula and assignment from the previous solver // first assignment, as this contains only unit clauses, then clauses, // as these are immediately simplified by the assigned unit clauses // get the old assignment const vector& trail = oldSolver->getTrail(); for (vector::const_iterator i = trail.begin(); i != trail.end(); ++i) { //:TODO: use special clause as reason instead of NULL solver->addClause(*i, CVC3::Theorem()); } // get the old clause set const vector& clauses = oldSolver->getClauses(); for (vector::const_iterator i = clauses.begin(); i != clauses.end(); ++i) { solver->addClause(**i, false); } // get the old lemmas const vector& lemmas = oldSolver->getLemmas(); for (vector::const_iterator i = lemmas.begin(); !solver->isConflicting() && i != lemmas.end(); ++i) { // can use clauseID for clause id as well as push id - // after all this is the root level, so all lemmas are ok in any push level anyway int clauseID = solver->nextClauseID(); solver->insertLemma(*i, clauseID, clauseID); } return solver; } Solver::~Solver() { for (vector::const_iterator i = d_learnts.begin(); i != d_learnts.end(); ++i) remove(*i, true); for (vector::const_iterator i = d_clauses.begin(); i != d_clauses.end(); ++i) remove(*i, true); while (!d_pendingClauses.empty()) { xfree(d_pendingClauses.front()); d_pendingClauses.pop(); } while (!d_theoryExplanations.empty()) { xfree(d_theoryExplanations.top().second); d_theoryExplanations.pop(); } delete d_derivation; } /// /// String representation // std::string Solver::toString(Lit literal, bool showAssignment) const { ostringstream buffer; buffer << literal.toString(); if (showAssignment) { if (getValue(literal) == l_True) buffer << "(+)"; else if (getValue(literal) == l_False) buffer << "(-)"; } return buffer.str(); } std::string Solver::toString(const std::vector& clause, bool showAssignment) const { ostringstream buffer; for (size_type j = 0; j < clause.size(); ++j) { buffer << toString(clause[j], showAssignment) << " "; } buffer << endl; return buffer.str(); } std::string Solver::toString(const Clause& clause, bool showAssignment) const { std::vector literals; clause.toLit(literals); return toString(literals, showAssignment); } std::vector Solver::curAssigns(){ vector res; cout << "current Assignment: " << endl; for (size_type i = 0; i < d_trail.size(); ++i) { res.push_back(miniSatToCVC(d_trail[i])); } return res; } std::vector > Solver::curClauses(){ std::vector > res; cout << "current Clauses: " << endl; for (size_t i = 0; i < d_clauses.size(); ++i) { std::vector oneClause; oneClause.clear(); for (int j = 0; j < (*d_clauses[i]).size(); ++j) { oneClause.push_back(miniSatToCVC((*d_clauses[i])[j])); } res.push_back(oneClause); } return res; } void Solver::printState() const { cout << "Lemmas: " << endl; for (size_type i = 0; i < d_learnts.size(); ++i) { cout << toString(*(d_learnts[i]), true); } cout << endl; cout << "Clauses: " << endl; for (size_type i = 0; i < d_clauses.size(); ++i) { cout << toString(*(d_clauses[i]), true); } cout << endl; cout << "Assignment: " << endl; // for (size_type i = 0; i < d_qhead; ++i) { for (size_type i = 0; i < d_trail.size(); ++i) { string split = ""; if (getReason(d_trail[i].var()) == Clause::Decision()) { split = "(S)"; } cout << toString(d_trail[i], false) << split << " "; } cout << endl; } void Solver::printDIMACS() const { int max_id = nVars(); int num_clauses = d_clauses.size() + d_trail.size();// + learnts.size() ; // header cout << "c minisat test" << endl; cout << "p cnf " << max_id << " " << num_clauses << endl; // clauses for (size_type i = 0; i < d_clauses.size(); ++i) { Clause& clause = *d_clauses[i]; for (int j = 0; j < clause.size(); ++j) { Lit lit = clause[j]; cout << toString(lit, false) << " "; } cout << "0" << endl; } // lemmas //for (int i = 0; i < learnts.size(); ++i) { // Clause& clause = *learnts[i]; // for (int j = 0; j < clause.size(); ++j) { // Lit lit = clause[j]; // cout << toString(lit, false) << " "; // } // cout << "0" << endl; //} // context for (vector::const_iterator i = d_trail.begin(); i != d_trail.end(); ++i) { Lit lit(*i); if (getReason(lit.var()) == Clause::Decision()) cout << toString(lit, false) << " 0" << endl; else cout << toString(lit, false) << " 0" << endl; } } /// Operations on clauses: bool Solver::isRegistered(Var var) { for (vector >::const_iterator i = d_registeredVars.begin(); i != d_registeredVars.end(); ++i) { if ((*i).count(var) > 0) return true; } return false; } // registers var with given index to all data structures void Solver::registerVar(Var index) { if (isRegistered(index)) return; // register variables to all data structures if (nVars() <= index) { // 2 * index + 1 will be accessed for neg. literal, // so we need + 1 fiels for 0 field d_watches .resize(2 * index + 2); d_reason .resize(index + 1, NULL); d_assigns .resize(index + 1, toInt(l_Undef)); d_level .resize(index + 1, -1); d_activity .resize(index + 1, 0); d_analyze_seen.resize(index + 1, 0); d_pushIDs .resize(index + 1, -1); if (d_derivation != NULL) d_trail_pos.resize(index + 1, d_trail.max_size()); } // register with internal variable selection heuristics d_order .newVar(index); // marks as registered DebugAssert(!d_registeredVars.empty(), "MiniSat::Solver::registerVar: d_registeredVars is empty"); d_registeredVars.back().insert(index); } void Solver::addClause(Lit p, CVC3::Theorem theorem) { vector literals; literals.push_back(p); addClause(literals, theorem, nextClauseID()); } void Solver::addClause(const SAT::Clause& clause, bool isTheoryClause) { vector literals; if (MiniSat::cvcToMiniSat(clause, literals)) { int clauseID = nextClauseID(); // theory clauses have negative ids: if (isTheoryClause) clauseID = -clauseID; CVC3::Theorem theorem; if (getDerivation() != NULL) { getDerivation()->registerInputClause(clauseID); theorem = clause.getClauseTheorem(); } addClause(literals, theorem, clauseID); } else { // ignore tautologies return; } } void Solver::addClause(const Clause& clause, bool keepClauseID) { vector literals; for (int i = 0; i < clause.size(); ++i) { literals.push_back(clause[i]); } if (keepClauseID) { addClause(literals, clause.getTheorem(), clause.id()); } else { addClause(literals, clause.getTheorem(), nextClauseID()); } } // Note: // tried to improve efficiency by asserting unit clauses first, // then clauses of size 2, and so on, // in the hope to immediately simplify or remove clauses. // // didn't work well with the theories, though, // lead to significant overhead, even when the derivation did not change much. // presumably as this interleaves clauses belonging to different 'groups', // which describe different concepts and are better handled in sequence // without interleaving them. void Solver::addFormula(const SAT::CNF_Formula& cnf, bool isTheoryClause) { SAT::CNF_Formula::const_iterator i, iend; // for comparison: this is the order used by -sat sat //for (i = cnf.end()-1, iend = cnf.begin()-1; i != iend; --i) { for (i = cnf.begin(), iend = cnf.end(); i != iend; i++) { // if(i->d_reason.isNull()){ // cout<<"found null thm in Solver::addFormula"<& literals, int clausePushID) const { // Check if clause is a tautology: p \/ -p \/ C: for (size_type i = 1; i < literals.size(); i++){ if (literals[i-1] == ~literals[i]){ return true; } } // Remove permanently satisfied clauses and falsified literals: size_type i, j; for (i = j = 0; i < literals.size(); i++) { bool rootAssign = ( getLevel(literals[i]) == d_rootLevel && isImpliedAt(literals[i], clausePushID) ); if (rootAssign && (getValue(literals[i]) == l_True)){ return true; } else if (rootAssign && (getValue(literals[i]) == l_False)){ ; } else{ literals[j++] = literals[i]; } } literals.resize(j); return false; } // need the invariant, that // a) either two undefined literals are chosen as watched literals, // or b) that after backtracking either a) kicks in // or the clause is still satisfied/unit // // so either: // - find two literals which are undefined or satisfied // - or find a literal that is satisfied or unsatisfied // and the most recently falsified literal // - or the two most recently falsified literals // and put these two literals at the first two positions void Solver::orderClause(vector& literals) const { if (literals.size() >= 2) { int first = 0; int levelFirst = getLevel(literals[first]); lbool valueFirst = getValue(literals[first]); int second = 1; int levelSecond = getLevel(literals[second]); lbool valueSecond = getValue(literals[second]); for (size_type i = 2; i < literals.size(); i++) { // found two watched or satisfied literals if (!(valueFirst == l_False) && !(valueSecond == l_False)) break; // check if new literal is better than the currently picked ones int levelNew = getLevel(literals[i]); lbool valueNew = getValue(literals[i]); // usable, take instead of previously chosen literal if (!(valueNew == l_False)) { if ((valueFirst == l_False) && (valueSecond == l_False)) { if (levelFirst > levelSecond) { second = i; levelSecond = levelNew; valueSecond = valueNew; } else { first = i; levelFirst = levelNew; valueFirst = valueNew; } } else if (valueFirst == l_False) { first = i; levelFirst = levelNew; valueFirst = valueNew; } else { second = i; levelSecond = levelNew; valueSecond = valueNew; } } // check if new pick was falsified more recently than the others else { if ((valueFirst == l_False) && (valueSecond == l_False)) { if ((levelNew > levelFirst) && (levelNew > levelSecond)) { if (levelSecond > levelFirst) { first = i; levelFirst = levelNew; valueFirst = valueNew; } else { second = i; levelSecond = levelNew; valueSecond = valueNew; } } else if (levelNew > levelFirst) { first = i; levelFirst = levelNew; valueFirst = valueNew; } else if (levelNew > levelSecond) { second = i; levelSecond = levelNew; valueSecond = valueNew; } } else if (valueFirst == l_False) { if (levelNew > levelFirst) { first = i; levelFirst = levelNew; valueFirst = valueNew; } } else { // valueSecond == l_false if (levelNew > levelSecond) { second = i; levelSecond = levelNew; valueSecond = valueNew; } } } } Lit swap = literals[0]; literals[0] = literals[first]; literals[first] = swap; swap = literals[1]; literals[1] = literals[second]; literals[second] = swap; // if a literal is satisfied, the first literal is satisfied, // otherwise if a literal is falsified, the second literal is falsified. if ( // satisfied literal at first position ((getValue(literals[0]) != l_True) && (getValue(literals[1]) == l_True)) || // falsified literal at second position (getValue(literals[0]) == l_False) ) { Lit swap = literals[0]; literals[0] = literals[1]; literals[1] = swap; } } } void Solver::addClause(vector& literals, CVC3::Theorem theorem, int clauseID) { // sort clause std::sort(literals.begin(), literals.end()); // remove duplicates vector::iterator end = std::unique(literals.begin(), literals.end()); literals.erase(end, literals.end()); // register var for each clause literal for (vector::const_iterator i = literals.begin(); i != literals.end(); ++i){ registerVar(i->var()); } // simplify clause vector simplified(literals); bool replaceReason = false; if (simplifyClause(simplified, clauseID)) { // it can happen that a unit clause was contradictory when it was added (in a non-root state). // then it was first added to list of pending clauses, // and the conflict analyzed and retracted: // this lead to the computation of a lemma which was used as a reason for the literal // instead of the unit clause itself. // so fix this here if (literals.size() == 1 && getReason(literals[0].var())->learnt()) { replaceReason = true; } else { // permanently satisfied clause return; } } // record derivation for a simplified clause if (getDerivation() != NULL && simplified.size() < literals.size()) { // register original clause as start of simplification Clause* c = Clause_new(literals, theorem, clauseID); getDerivation()->registerClause(c); getDerivation()->removedClause(c); // register simplification steps Inference* inference = new Inference(clauseID); size_type j = 0; for (size_type i = 0; i < literals.size(); ++i) { // literal removed in simplification if (j >= simplified.size() || literals[i] != simplified[j]) { inference->add(literals[i], getDerivation()->computeRootReason(~literals[i], this)); } // keep literal else { ++j; } } // register resolution leading to simplified clause clauseID = nextClauseID(); getDerivation()->registerInference(clauseID, inference); } // insert simplified clause orderClause(simplified); Clause* c; if (simplified.size() < literals.size()) { c = Clause_new(simplified, CVC3::Theorem(), clauseID); } else { c = Clause_new(simplified, theorem, clauseID); } // cout<<"clause size" << c->size() << endl << flush; insertClause(c); // cout<<"after clause size" << c->size() << endl << flush; if (replaceReason) { d_reason[literals[0].var()] = c; } // cout<<"after after clause size" << c->size() << endl << flush; } void Solver::insertClause(Clause* c) { // clause set is unsatisfiable if (!d_ok) { remove(c, true); return; } if (getDerivation() != NULL) getDerivation()->registerClause(c); if (c->size() == 0){ d_conflict = c; // for garbage collection: need to put clause somewhere if (!c->learnt()) { d_clauses.push_back(c); } else { d_learnts.push_back(c); } d_ok = false; return; } // process clause - // if clause is conflicting add it to pending clause and return // unit clause if (c->size() == 1) { if (!enqueue((*c)[0], d_rootLevel, c)) { // this backtracks to d_rootLevel, as reason c is just one literal, // which is immediately UIP, so c will be learned as a lemma as well. updateConflict(c); d_pendingClauses.push(c); return; } } // non-unit clause else { // ensure that for a lemma the second literal has the highest decision level if (c->learnt()){ DebugAssert(getValue((*c)[0]) == l_Undef, "MiniSat::Solver::insertClause: first literal of new lemma not undefined"); IF_DEBUG ( for (int i = 1; i < c->size(); ++i) { DebugAssert(getValue((*c)[i]) == l_False, "MiniSat::Solver::insertClause: lemma literal not false"); } ) // Put the second watch on the literal with highest decision level: int max_i = 1; int max = getLevel((*c)[1]); for (int i = 2; i < c->size(); i++) { if (getLevel((*c)[i]) > max) { max = getLevel((*c)[i]); max_i = i; } } Lit swap((*c)[1]); (*c)[1] = (*c)[max_i]; (*c)[max_i] = swap; // (newly learnt clauses should be considered active) claBumpActivity(c); } // satisfied if (getValue((*c)[0]) == l_True) { ; } // conflicting else if (getValue((*c)[0]) == l_False) { IF_DEBUG ( for (int i = 1; i < c->size(); ++i) { DebugAssert(getValue((*c)[i]) == l_False, "MiniSat::Solver::insertClause: bogus conflicting clause"); } ) updateConflict(c); d_pendingClauses.push(c); return; } // propagation else if (getValue((*c)[1]) == l_False) { DebugAssert(getValue((*c)[0]) == l_Undef, "MiniSat::Solver::insertClause: bogus propagating clause"); IF_DEBUG ( for (int i = 1; i < c->size(); ++i) { DebugAssert(getValue((*c)[i]) == l_False, "MiniSat::Solver::insertClause: bogus propagating clause"); } ) if (!enqueue((*c)[0], getImplicationLevel(*c), c)) { DebugAssert(false, "MiniSat::Solver::insertClause: conflicting/implying clause"); } } // Watch clause: addWatch(~(*c)[0], c); addWatch(~(*c)[1], c); } // clause is not conflicting, so insert it into the clause list. d_stats.max_literals += c->size(); if (!c->learnt()) { d_clauses.push_back(c); d_stats.clauses_literals += c->size(); } else { d_learnts.push_back(c); d_stats.learnts_literals += c->size(); } } // Disposes a clauses and removes it from watcher lists. // NOTE! Low-level; does NOT change the 'clauses' and 'learnts' vector. void Solver::remove(Clause* c, bool just_dealloc) { // no watches added for clauses of size < 2 if (!just_dealloc && c->size() >= 2){ removeWatch(getWatches(~(*c)[0]), c); removeWatch(getWatches(~(*c)[1]), c); } if (c->learnt()) d_stats.learnts_literals -= c->size(); else d_stats.clauses_literals -= c->size(); if (getDerivation() == NULL) xfree(c); else getDerivation()->removedClause(c); } /// Conflict handling // Pre-condition: 'elem' must exists in 'ws' OR 'ws' must be empty. void Solver::removeWatch(std::vector& ws, Clause* elem) { if (ws.size() == 0) return; // (skip lists that are already cleared) size_type j = 0; for (; ws[j] != elem; j++) { // want to find the right j, so the loop should be executed // and not wrapped in a debug guard DebugAssert(j < ws.size(), "MiniSat::Solver::removeWatch: elem not in watched list"); } ws[j] = ws.back(); ws.pop_back(); } // for a clause, of which the first literal is implied, // get the highest decision level of the implying literals, // i.e. the decision level from which on the literal is implied // // as theory clauses can be added at any time, // this is not necessarily the level of the second literal. // thus, all literals have to be checked. int Solver::getImplicationLevel(const Clause& clause) const { int currentLevel = decisionLevel(); int maxLevel = d_rootLevel; for (int i = 1; i < clause.size(); ++i) { DebugAssert(getValue(clause[i]) == l_False, "MiniSat::Solver::getImplicationLevelFull: literal not false"); int newLevel = getLevel(clause[i]); // highest possible level if (newLevel == currentLevel) return currentLevel; // highest level up to now if (newLevel > maxLevel) maxLevel = newLevel; } return maxLevel; } // like getImplicationLevel, but for all literals, // i.e. for conflicting instead of propagating clause int Solver::getConflictLevel(const Clause& clause) const { int decisionLevel = d_rootLevel; for (int i = 0; i < clause.size(); ++i) { DebugAssert(getValue(clause[i]) == l_False, "MiniSat::Solver::getConflictLevel: literal not false"); int newLevel = getLevel(clause[i]); if (newLevel > decisionLevel) decisionLevel = newLevel; } return decisionLevel; } Clause* Solver::getReason(Lit literal, bool _resolveTheoryImplication) { Var var = literal.var(); Clause* reason = d_reason[var]; if (!_resolveTheoryImplication) return reason; DebugAssert(reason != NULL, "MiniSat::getReason: reason[var] == NULL."); if (reason == Clause::TheoryImplication()) { if (getValue(literal) == l_True) resolveTheoryImplication(literal); else resolveTheoryImplication(~literal); reason = d_reason[var]; } DebugAssert(d_reason[var] != Clause::TheoryImplication(), "MiniSat::getReason: reason[var] == TheoryImplication."); return reason; } bool Solver::isConflicting() const { return (d_conflict != NULL); } void Solver::updateConflict(Clause* clause) { DebugAssert(clause != NULL, "MiniSat::updateConflict: clause == NULL."); IF_DEBUG ( for (int i = 0; i < clause->size(); ++i) { DebugAssert(getValue((*clause)[i]) == l_False, "MiniSat::Solver::updateConflict: literal not false"); } ) if ( (d_conflict == NULL) || (clause->size() < d_conflict->size()) ) { d_conflict = clause; } } // retrieve the explanation and update the implication level of a theory implied literal. // if necessary, do this recursively (bottom up) for the literals in the explanation. // assumes that the literal is true in the current context void Solver::resolveTheoryImplication(Lit literal) { if (eager_explanation) return; if (d_reason[literal.var()] == Clause::TheoryImplication()) { // instead of recursion put the theory implications to check in toRegress, // and the theory implications depending on them in toComplete stack toRegress; stack toComplete; toRegress.push(literal); SAT::Clause clauseCVC; while (!toRegress.empty()) { // get the explanation for the first theory implication literal = toRegress.top(); DebugAssert(getValue(literal) == l_True, "MiniSat::Solver::resolveTheoryImplication: literal is not true"); toRegress.pop(); FatalAssert(false, "Not implemented yet"); // d_theoryAPI->getExplanation(miniSatToCVC(literal), clauseCVC); Clause* explanation = cvcToMiniSat(clauseCVC, nextClauseID()); // must ensure that propagated literal is at first position for (int i = 0; i < (*explanation).size(); ++i) { if ((*explanation)[i] == literal) { MiniSat::Lit swap = (*explanation)[0]; (*explanation)[0] = (*explanation)[i]; (*explanation)[i] = swap; break; } } // assert that clause is implying the first literal IF_DEBUG( DebugAssert((*explanation)[0] == literal, "MiniSat::Solver::resolveTheoryImplication: literal not implied by clause 1"); DebugAssert(getValue((*explanation)[0]) == l_True, "MiniSat::Solver::resolveTheoryImplication: literal not implied by clause 2"); for (int i = 1; i < (*explanation).size(); ++i) { DebugAssert(getValue((*explanation)[i]) == l_False, "MiniSat::Solver::resolveTheoryImplication: literal not implied by clause 3"); } ) d_reason[literal.var()] = explanation; // if any of the reasons is also a theory implication, // then need to know its level first, so add it to toRegress for (int i = 1; i < (*explanation).size(); ++i) { if (d_reason[(*explanation)[i].var()] == Clause::TheoryImplication()) { toRegress.push((*explanation)[i]); } } // set literal and its explanation aside for later processing toComplete.push(explanation); } // now set the real implication levels after they have been resolved // std::pair pair; while (!toComplete.empty()) { Clause* explanation = toComplete.top(); toComplete.pop(); IF_DEBUG ( for (int i = 1; i < explanation->size(); ++i) { DebugAssert (d_reason[(*explanation)[i].var()] != Clause::TheoryImplication(), "MiniSat::Solver::resolveTheoryImplication: not done to completion"); } ) // update propagation information int level = getImplicationLevel(*explanation); setLevel((*explanation)[0], level); setPushID((*explanation)[0].var(), explanation); if (keep_lazy_explanation) { // the reason can be added to the clause set without any effect, // as the explanation implies the first literal, which is currently true // so neither propagation nor conflict are triggered, // only the correct literals are registered as watched literals. addClause(*explanation, true); xfree(explanation); } else { // store explanation for later deallocation d_theoryExplanations.push(std::make_pair(level, explanation)); } } } } /// Conflict handling Clause* Solver::analyze(int& out_btlevel) { DebugAssert(d_conflict != NULL, "MiniSat::Solver::analyze called when no conflict was detected"); // compute the correct decision level for theory propagated literals // // need to find the most recent implication level of any of the literals in d_conflict, // after updating conflict levels due to lazy retrieval of theory implications. // // that is, really need to do: // 1) assume that the currently highest known level is the UIP Level, // initially this is the decision level // 2) find a literal in the conflict clause whose real implication level is the UIP Level // 3) if their is no such literal, pick the new UIP level as the highest of their implication levels, // and repeat // // unfortunately, 2) is not that easy: // - if the literals' level is smaller than the UIP level the literal can be ignored // - otherwise, it might depend on theory implications, // who have just been assumed to be of the UIP level, but which in reality are of lower levels. // So, must check all literals the literal depends on, // until the real level of all of them is determined, // and thus also of the literal we are really interested in. // this can be stopped if the level must be lower than the (currently assumed) UIP level, // or if it is sure that the literal really has the UIP level. // but this is only the case if it depends on the decision literal of the UIP level. // // but how to find this out efficiently? // // so, this is done as an approximation instead: // 1) if the explanation of a (conflict clause) literal is known, stop and take the literal's level // 2) otherwise, retrieve its explanation, // and do 1) and 2) on each literal in the explanation. // then set the original literal's level to the highest level of its explanation. // // as an example, if we have: // - theory implication A in level n // - propositional implication B depending on A and literals below level n // - propositional implication C depending on B and literals below level n // then A, B, C will all be assumed to be of level n, // and if C is in a conflict it will be assumed to be of level n // in the conflict analysis // // this is fast to compute, // but it is not clear if starting from the real UIP level // would lead to a significantly better lemma for (int j = 0; j < d_conflict->size(); j++){ resolveTheoryImplication(~((*d_conflict)[j])); } int UIPLevel = getConflictLevel(*d_conflict); // clause literals to regress are marked by setting analyze_d_seen[var] // seen should be false for all variables IF_DEBUG ( for (size_type i = 0; i < d_analyze_seen.size(); ++i) { DebugAssert (d_analyze_seen[i] == 0, "MiniSat::Solver::analyze: analyze_seen is not clear at: " /*+ i*/); } ) // index into trail, regression is done chronologically (in combination with analyze_seen) int index = d_trail.size() - 1; // lemma is generated here; vector out_learnt; // number of literals to regress in current decision level int pathC = 0; // highest level below UIP level, i.e. the level to backtrack to out_btlevel = 0; // current literal to regress Lit p = lit_Undef; // derivation logging Inference* inference = NULL; if (getDerivation() != NULL) inference = new Inference(d_conflict->id()); // conflict clause is the initial clause to regress Clause* confl = d_conflict; d_conflict = NULL; // compute pushID as max pushID of all regressed clauses int pushID = confl->pushID(); // do until pathC == 1, i.e. UIP found if (confl->size() == 1) { out_learnt.push_back((*confl)[0]); } else { // leave room for the asserting literal - // we might get an empty lemma if a new clause is conflicting at the root level. if (UIPLevel != d_rootLevel) out_learnt.push_back(lit_Undef); do { DebugAssert (confl != Clause::Decision(), "MiniSat::Solver::analyze: no reason for conflict"); DebugAssert (confl != Clause::TheoryImplication(), "MiniSat::Solver::analyze: theory implication not resolved"); if (confl->learnt()) claBumpActivity(confl); // regress p for (int j = (p == lit_Undef) ? 0 : 1; j < confl->size(); j++){ Lit q = (*confl)[j]; DebugAssert(getValue(q) == l_False, "MiniSat::Solver::analyze: literal to regress is not false"); DebugAssert(getLevel(q) <= UIPLevel, "MiniSat::Solver::analyze: literal above UIP level"); // get explanation and compute implication level for theory implication resolveTheoryImplication(~q); // first time that q is in a reason, so process it if (!d_analyze_seen[q.var()]) { // q is falsified at root level, so it can be dropped if (getLevel(q) == d_rootLevel) { d_analyze_redundant.push_back(q); d_analyze_seen[q.var()] = 1; } else { varBumpActivity(q); d_analyze_seen[q.var()] = 1; // mark q to regress if (getLevel(q) == UIPLevel) pathC++; // add q to lemma else{ out_learnt.push_back(q); out_btlevel = max(out_btlevel, getLevel(q)); } } } } // for clause conflicting at root level pathC can be 0 right away if (pathC == 0) break; // pick next literal in UIP level to regress. // as trail is not ordered wrt. implication level (theory clause/ implications), // check also if the next literal is really from the UIP level. while (!d_analyze_seen[d_trail[index].var()] || (getLevel(d_trail[index])) != UIPLevel) { --index; } --index; // this could theoretically happen if UIP Level is 0, // but should be catched as then the conflict clause // is simplified to the empty clause. DebugAssert(index >= -1, "MiniSat::Solver::analyze: index out of bound"); // set up p to be regressed p = d_trail[index+1]; d_analyze_seen[p.var()] = 0; pathC--; confl = getReason(p); pushID = max(pushID, confl->pushID()); if (getDerivation() != NULL && pathC > 0) inference->add(~p, confl); } while (pathC > 0); // add the UIP - except in root level, here all literals have been resolved. if (UIPLevel != d_rootLevel) out_learnt[0] = ~p; } // check that the UIP has been found IF_DEBUG ( DebugAssert ((out_learnt.size() == 0 && UIPLevel == d_rootLevel) || getLevel(out_learnt[0]) == UIPLevel, "MiniSat::Solver::analyze: backtracked past UIP level."); for (size_type i = 1; i < out_learnt.size(); ++i) { DebugAssert (getLevel(out_learnt[i]) < UIPLevel, "MiniSat::Solver::analyze: conflict clause contains literal from UIP level or higher."); } ) analyze_minimize(out_learnt, inference, pushID); // clear seen for lemma for (vector::const_iterator j = out_learnt.begin(); j != out_learnt.end(); ++j) { d_analyze_seen[j->var()] = 0; } // finish logging of conflict clause generation int clauseID = nextClauseID(); if (getDerivation() != NULL) getDerivation()->registerInference(clauseID, inference); return Lemma_new(out_learnt, clauseID, pushID); } class lastToFirst_lt { // Helper class to 'analyze' -- order literals from last to first occurance in 'trail[]'. const vector& d_trail_pos; public: lastToFirst_lt(const vector& trail_pos) : d_trail_pos(trail_pos) {} bool operator () (Lit p, Lit q) { return d_trail_pos[p.var()] > d_trail_pos[q.var()]; } }; void Solver::analyze_minimize(vector& out_learnt, Inference* inference, int& pushID) { // for empty clause current analyze_minimize will actually do something wrong if (out_learnt.size() > 1) { // literals removed from out_learnt in conflict clause minimization, // including reason literals which had to be removed as well // (except for literals implied at root level). size_type i, j; // 1) Simplify conflict clause (a lot): // drop a literal if it is implied by the remaining lemma literals: // that is, as in 2), but also recursively taking the reasons // for the implying clause, and their reasone, and so on into consideration. if (d_expensive_ccmin){ // (maintain an abstraction of levels involved in conflict) unsigned int min_level = 0; for (i = 1; i < out_learnt.size(); i++) min_level |= 1 << (getLevel(out_learnt[i]) & 31); for (i = j = 1; i < out_learnt.size(); i++) { Lit lit(out_learnt[i]); if (getReason(lit) == Clause::Decision() || !analyze_removable(lit, min_level, pushID)) out_learnt[j++] = lit; } } // 2) Simplify conflict clause (a little): // drop a literal if it is implied by the remaining lemma literals: // that is, if the other literals of its implying clause // are falsified by the other lemma literals. else { for (i = j = 1; i < out_learnt.size(); i++) { Lit lit(out_learnt[i]); Clause& c = *getReason(lit); if (&c == Clause::Decision()) { out_learnt[j++] = lit; } else { bool keep = false; // all literals of the implying clause must be: for (int k = 1; !keep && k < c.size(); k++) { if ( // already part of the lemma !d_analyze_seen[c[k].var()] && // or falsified in the root level getLevel(c[k]) != d_rootLevel ) { // failed, can't remove lit out_learnt[j++] = lit; keep = true; } } if (!keep) { d_analyze_redundant.push_back(lit); } } } } out_learnt.resize(j); } // clean seen for simplification and log derivation // do this in reverse chronological order of variable assignment // in combination with removing duplication literals after each resolution step // this allows to resolve on each literal only once, // as it depends only on literals (its clause contains only literals) // which were assigned earlier. if (getDerivation() != NULL) { std::sort(d_analyze_redundant.begin(), d_analyze_redundant.end(), lastToFirst_lt(d_trail_pos)); } for (vector::const_iterator i = d_analyze_redundant.begin(); i != d_analyze_redundant.end(); ++i) { Lit lit(*i); d_analyze_seen[lit.var()] = 0; // if this literal is falsified in the root level, // but not implied in the current push level, // and the lemma is currently valid in levels lower than the current push level, // then don't remove the literal. // instead move it to the end of the lemma, // so that it won't hurt performance. if (out_learnt.size() > 0 // found the empty clause, so remove all literals && getLevel(lit) == d_rootLevel && getPushID(lit) > pushID && !d_pushes.empty() && getPushID(lit) > d_pushes.front().d_clauseID ) { out_learnt.push_back(lit); continue; } // update the push level and the derivation wrt. the removed literal pushID = max(pushID, getPushID(lit)); if (getDerivation() != NULL) { // resolve on each removed literal with its reason if (getLevel(lit) == d_rootLevel) { inference->add(lit, getDerivation()->computeRootReason(~lit, this)); } else { Clause* reason = getReason(lit); inference->add(lit, reason); } } } d_analyze_redundant.clear(); } // Check if 'p' can be removed. 'min_level' is used to abort early if visiting literals at a level that cannot be removed. // // 'p' can be removed if it depends only on literals // on which they other conflict clause literals do depend as well. bool Solver::analyze_removable(Lit p, unsigned int min_level, int pushID) { DebugAssert(getReason(p) != Clause::Decision(), "MiniSat::Solver::analyze_removable: p is a decision."); d_analyze_stack.clear(); d_analyze_stack.push_back(p); int top = d_analyze_redundant.size(); while (d_analyze_stack.size() > 0){ DebugAssert(getReason(d_analyze_stack.back()) != Clause::Decision(), "MiniSat::Solver::analyze_removable: stack var is a decision."); DebugAssert(getReason(d_analyze_stack.back()) != Clause::TheoryImplication(), "MiniSat::Solver::analyze_removable: stack var is an unresolved theory implication."); Clause& c = *getReason(d_analyze_stack.back()); d_analyze_stack.pop_back(); for (int i = 1; i < c.size(); i++) { Lit p = c[i]; // ignore literals already considered or implied at root level if (!d_analyze_seen[p.var()]) { if (getLevel(p) == d_rootLevel) { d_analyze_redundant.push_back(p); d_analyze_seen[p.var()] = 1; } else { // min_level is a precheck, // only try to remove literals which might be implied, // at least wrt. to the abstraction min_level if (getReason(p) != Clause::Decision() && ((1 << (getLevel(p) & 31)) & min_level) != 0){ d_analyze_seen[p.var()] = 1; d_analyze_stack.push_back(p); d_analyze_redundant.push_back(p); } else { // failed, so undo changes to seen literals/redundant and return for (size_type j = top; j < d_analyze_redundant.size(); ++j) { d_analyze_seen[d_analyze_redundant[j].var()] = 0; } d_analyze_redundant.resize(top); return false; } } } } } d_analyze_redundant.push_back(p); return true; } bool Solver::isImpliedAt(Lit lit, int clausePushID) const { return // literal asserted before first push (d_pushes.empty() || getPushID(lit) <= d_pushes.front().d_clauseID) || // or literal depends only on clauses added before given clause getPushID(lit) < clausePushID; } // Can assume everything has been propagated! (esp. the first two literals are != l_False, unless // the clause is binary and satisfied, in which case the first literal is true) // Returns True if clause is satisfied (will be removed), False otherwise. // bool Solver::isPermSatisfied(Clause* c) const { for (int i = 0; i < c->size(); i++){ Lit lit((*c)[i]); if (getValue(lit) == l_True && getLevel(lit) == d_rootLevel && isImpliedAt(lit, c->pushID()) ) return true; } return false; } // a split decision, returns FALSE if immediate conflict. bool Solver::assume(Lit p) { d_trail_lim.push_back(d_trail.size()); d_stats.max_level = std::max(d_trail_lim.size(), size_type(d_stats.max_level)); return enqueue(p, decisionLevel(), Clause::Decision()); } // Revert to the state at given level, assert conflict clause and pending clauses void Solver::backtrack(int toLevel, Clause* learnt_clause) { DebugAssert (decisionLevel() > toLevel, "MiniSat::Solver::backtrack: backtrack not to previous level"); // backtrack theories DebugAssert(toLevel >= d_rootLevel, "MiniSat::Solver::backtrack: backtrack beyond root level"); for (int i = toLevel; i < decisionLevel(); ++i) { d_theoryAPI->pop(); } // backtrack trail int trail_size = d_trail.size(); int trail_jump = d_trail_lim[toLevel]; int first_invalid = d_trail_lim[toLevel]; for (int c = first_invalid; c < trail_size; ++c) { Var x = d_trail[c].var(); // only remove enqueued elements which are not still implied after backtracking if (getLevel(x) > toLevel) { //setLevel(x, -1); d_assigns[x] = toInt(l_Undef); d_reason [x] = NULL; //d_pushIDs[x] = -1; d_order.undo(x); } else { d_trail[first_invalid] = d_trail[c]; if (d_derivation != NULL) d_trail_pos[x] = first_invalid; ++first_invalid; } } // shrink queue d_trail.resize(first_invalid); d_trail_lim.resize(toLevel); d_qhead = trail_jump; d_thead = d_qhead; // insert lemma // we want to insert the lemma before the original conflicting clause, // so that propagation is done on the lemma instead of that clause. // as that clause might be a theory clause in d_pendingClauses, // the lemma has to be inserted before the pending clauses are added. insertClause(learnt_clause); // enqueue clauses which were conflicting in previous assignment while (!isConflicting() && !d_pendingClauses.empty()) { Clause* c = d_pendingClauses.front(); d_pendingClauses.pop(); addClause(*c, true); xfree(c); } // deallocate explanations for theory implications // which have been retracted and are thus not needed anymore. // // not necessarily ordered by level, // so stackwise deallocation by level does not necessarily remove // all possible explanations as soon as possible. // still, should be a good enough compromise between speed and completeness. bool done = false; while (!done && !d_theoryExplanations.empty()) { std::pair pair = d_theoryExplanations.top(); if (pair.first > toLevel) { d_theoryExplanations.pop(); remove(pair.second, true); } else { done = true; } } } /*_________________________________________________________________________________________________ | | enqueue : (p : Lit) (from : Clause*) -> [bool] | | Description: | Puts a new fact on the propagation queue as well as immediately updating the variable's value. | Should a conflict arise, FALSE is returned. | | Input: | p - The fact to enqueue | decisionLevel - The level from which on this propagation/decision holds. | if a clause is added in a non-root level, there might be propagations | which are not only valid in the current, but also earlier levels. | from - [Optional] Fact propagated from this (currently) unit clause. Stored in 'reason[]'. | Default value is NULL (no reason). | GClause::s_theoryImplication means theory implication where explanation | has not been retrieved yet. | | Output: | TRUE if fact was enqueued without conflict, FALSE otherwise. |________________________________________________________________________________________________@*/ bool Solver::enqueue(Lit p, int decisionLevel, Clause* from) { lbool value(getValue(p)); if (value != l_Undef) { return value != l_False; } else { Var var(p.var()); d_assigns[var] = toInt(lbool(p.sign())); setLevel(var, decisionLevel); d_reason [var] = from; setPushID(var, from); d_trail.push_back(p); if (d_derivation != NULL) d_trail_pos[var] = d_trail.size(); return true; } } /*_________________________________________________________________________________________________ | | propagate : [void] -> [Clause*] | | Description: | Propagates one enqueued fact. If a conflict arises, updateConflict is called. |________________________________________________________________________________________________@*/ // None: // // due to theory clauses and lazy retrieval of theory implications we get propagations // out of any chronological order. // therefore it is not guaranteed that in a propagating clause // the first two literals (the watched literals) have the highest decision level. // // this doesn't matter, though, it suffices to ensure that // if there are less than two undefined literals in a clause, // than these are at the first two positions? // // Reasoning, for eager retrieval of explanations for theory implications: // case analysis for first two positions: // 1) TRUE, TRUE // then the clause is satisfied until after backtracking // the first two literals are undefined, or we get case 2) TRUE, FALSE // // 2) TRUE, FALSE // if TRUE is true because it is a theory implication of FALSE, // this is fine, as TRUE and FALSE will be backtracked at the same time, // and then both literals will be undefined. // // this holds in general if TRUE was set before FALSE was set, // so this case is fine. // // and TRUE can't be set after FALSE was set, // as this would imply that all other literals are falsified as well // (otherwise the FALSE literal would be replace by an undefined/satisfied literal), // and then TRUE would be implied at the same level as FALSE // // 3) FALSE, TRUE // can not happen, falsifying the first literal will reorder this to TRUE, FALSE // // 4) FALSE, FALSE // Both literals must be falsified at the current level, // as falsifying one triggers unit propagation on the other in the same level. // so after backtracking both are undefined. // // // now, if explanations for theory implications are retrieved lazily, // then the level in which a literal was set might change later on. // i.e. first it is assumed to be of the level in which the theory implication happened, // but later on, when checking its explanation, // the real level might be calculated to be an earlier level. // // this means, when the original level was L and the real level is K, // that this literal is going to be undefined when backtracking before L, // but is immediately propagated again if the new level is >= K. // this is done until level K is reached, // then this literal behaves like any ordinary literal. // (ensured by backtrack) // // case analysis for first two positions: // 1) TRUE, TRUE // same as before // // 2) TRUE, FALSE // the new case is that TRUE was initially of level <= FALSE, // but now FALSE is set to a level < TRUE. // // then when on backtracking TRUE is unset, // FALSE will also be unset, but then right away be set to FALSE again, // so they work fine as watched literals. // // 3) FALSE, TRUE // same as before // // 4) FALSE, FALSE // if the level of both literals is unchanged, // changes in other literals don't matter, // as after backtracking both are undefined (same as before) // // if for one of the two (or both) the level is changed, // after backtracking it will be falsified again immediately, // and the watched literal works as expected: // either the other literal is propagated, // or there is now an undefined literal in the rest of the clause // which becomes the new watched literal. // // changes in the rest of the clause are of no consequence, // as they are assumed to be false in the conflict level, // changes in their level do not change this, // and after backtracking they are again taken into consideration // for finding a new watched literal. // // so, even for lazy retrieval of theory implication explanations // there is no need to explicitly set the 2nd watched literal // to the most recently falsified one. void Solver::propagate() { Lit p = d_trail[d_qhead++]; // 'p' is enqueued fact to propagate. vector& ws = getWatches(p); d_stats.propagations++; --d_simpDB_props; if (getLevel(p) == d_rootLevel) ++d_simpDB_assigns; // propagate p to theories if (!defer_theory_propagation) { d_theoryAPI->assertLit(miniSatToCVC(p)); ++d_thead; } vector::iterator j = ws.begin(); vector::iterator i = ws.begin(); vector::iterator end = ws.end(); while (i != end) { Clause& c = **i; ++i; // Make sure the false literal is data[1]: Lit false_lit = ~p; if (c[0] == false_lit) { c[0] = c[1]; c[1] = false_lit; } Lit first = c[0]; lbool val = getValue(first); // If 0th watch is true, then clause is already satisfied. if (val == l_True) { DebugAssert(getValue(c[0]) == l_True && getValue(c[1]) == l_False, "MiniSat::Solver:::propagate: True/False"); *j = &c; ++j; } // Look for new watch: else { for (int k = 2; k < c.size(); k++) { if (getValue(c[k]) != l_False) { c[1] = c[k]; c[k] = false_lit; addWatch(~c[1], &c); goto FoundWatch; } } // Did not find watch -- clause is unit under assignment: // check that all other literals are false IF_DEBUG( for (int z = 1; z < c.size(); ++z) { DebugAssert(getValue(c[z]) == l_False, "MiniSat::Solver:::propagate: Unit Propagation"); } ) *j = &c; ++j; if (!enqueue(first, getImplicationLevel(c), &c)){ // clause is conflicting updateConflict(&c); d_qhead = d_trail.size(); // remove gap created by watches for which a new watch has been picked if (i != j) ws.erase(j, i); return; } FoundWatch:; } } // remove gap created by watches for which a new watch has been picked ws.erase(j, ws.end()); } /*_________________________________________________________________________________________________ | | reduceDB : () -> [void] | | Description: | Remove half of the learnt clauses, minus the clauses locked by the current assignment. Locked | clauses are clauses that are reason to some assignment. Binary clauses are never removed. |________________________________________________________________________________________________@*/ struct reduceDB_lt { bool operator () (Clause* x, Clause* y) { return x->size() > 2 && (y->size() == 2 || x->activity() < y->activity()); } }; void Solver::reduceDB() { d_stats.lm_simpl++; size_type i, j; double extra_lim = d_cla_inc / d_learnts.size(); // Remove any clause below this activity std::sort(d_learnts.begin(), d_learnts.end(), reduceDB_lt()); for (i = j = 0; i < d_learnts.size() / 2; i++){ if (d_learnts[i]->size() > 2 && !isReason(d_learnts[i])) remove(d_learnts[i]); else d_learnts[j++] = d_learnts[i]; } for (; i < d_learnts.size(); i++){ if (d_learnts[i]->size() > 2 && !isReason(d_learnts[i]) && d_learnts[i]->activity() < extra_lim) remove(d_learnts[i]); else d_learnts[j++] = d_learnts[i]; } d_learnts.resize(d_learnts.size() - (i - j), NULL); d_stats.del_lemmas += (i - j); d_simpRD_learnts = d_learnts.size(); } /*_________________________________________________________________________________________________ | | simplifyDB : [void] -> [bool] | | Description: | Simplify the clause database according to the current top-level assigment. Currently, the only | thing done here is the removal of satisfied clauses, but more things can be put here. |________________________________________________________________________________________________@*/ void Solver::simplifyDB() { // clause set is unsatisfiable if (isConflicting()) return; // need to do propagation to exhaustion before watches can be removed below. // e.g. in a <- b, c, where b an c are satisfied by unit clauses, // and b and c have been added to the propagation queue, // but not propagated yet: then the watches are not evaluated yet, // and a has not been propapagated. // thus by removing the watches on b and c, // the propagation of a would be lost. DebugAssert(d_qhead == d_trail.size(), "MiniSat::Solver::simplifyDB: called while propagation queue was not empty"); d_stats.db_simpl++; // Clear watcher lists: // could do that only for literals which are implied permanently, // but we don't know that anymore with the push/pop interface: // even if the push id of a literal is less than the first push clause id, // it might depend on theory clauses, // which will be retracted after a pop, // so that the literal is not implied anymore. // thus, this faster way of cleaning watches can not be used, // instead they have to removed per clause below /* Lit lit; for (vector::const_iterator i = d_trail.begin(); i != d_trail.end(); ++i) { lit = *i; if (getLevel(lit) == d_rootLevel && // must be in the root push (d_pushes.empty() || getPushID(lit) <= d_pushes.front().d_clauseID) ) { getWatches(lit).clear(); getWatches(~(lit)).clear(); } } */ // Remove satisfied clauses: for (int type = 0; type < 2; type++){ vector& cs = type ? d_learnts : d_clauses; size_type j = 0; bool satisfied = false; for (vector::const_iterator i = cs.begin(); i != cs.end(); ++i) { Clause* clause = *i; if (isReason(clause)) { cs[j++] = clause; } else { satisfied = false; // falsified = 0; int k = 0; int end = clause->size() - 1; // skip the already permanently falsified tail // clause should not be permanently falsified, // as simplifyDB should only be called in a consistent state. while ( (getLevel((*clause)[end]) == d_rootLevel) && (getValue((*clause)[end]) == l_False)) { DebugAssert(end > 0, "MiniSat::Solver::simplifyDB: permanently falsified clause found"); --end; } while (k < end) { Lit lit((*clause)[k]); if (getLevel(lit) != d_rootLevel) { ++k; } else if (getValue(lit) == l_True) { if (isImpliedAt(lit, clause->pushID())) { satisfied = true; break; } else { ++k; } } else if (k > 1 && getValue(lit) == l_False) { --end; (*clause)[k] = (*clause)[end]; (*clause)[end] = lit; } else { ++k; } } if (satisfied) { d_stats.del_clauses++; remove(clause); } else { cs[j++] = clause; } } // isReason also ensures that unit clauses are kept /* if (!isReason(clause) && isPermSatisfied(clause)) { d_stats.del_clauses++; remove(clause); } else { cs[j++] = clause; }*/ } cs.resize(j); } d_simpDB_assigns = 0; d_simpDB_props = d_stats.clauses_literals + d_stats.learnts_literals; } void Solver::protocolPropagation() const { if (protocol) { Lit lit(d_trail[d_qhead]); cout << "propagate: " << decisionLevel() << " : " << lit.index() << endl; cout << "propagate: " << decisionLevel() << " : " << toString(lit, true) << " at: " << getLevel(lit); if (getReason(lit.var()) != Clause::Decision()) cout << " from: " << toString(*getReason(lit.var()), true); cout << endl; } } void Solver::propLookahead(const SearchParams& params) { // retrieve the best vars according to the heuristic vector nextVars(prop_lookahead); vector::size_type fetchedVars = 0; while (fetchedVars < nextVars.size()) { Var nextVar = d_order.select(params.random_var_freq); if (isRegistered(nextVar) || nextVar == var_Undef) { nextVars[fetchedVars] = nextVar; ++fetchedVars; } } // and immediately put the variables back for (vector::size_type i = 0; i < nextVars.size(); ++i) { if (nextVars[i] != var_Undef) d_order.undo(nextVars[i]); } // propagate on these vars int level = decisionLevel(); int first_invalid = d_trail.size(); for (vector::size_type i = 0; i < nextVars.size(); ++i) { Var nextVar = nextVars[i]; if (nextVar == var_Undef) continue; for (int sign = 0; sign < 2; ++sign) { // first propagate on +var, then on -var if (sign == 0) { assume(Lit(nextVar, true)); } else { assume(Lit(nextVar, false)); } while (d_qhead < d_trail.size() && !isConflicting()) { protocolPropagation(); propagate(); } // propagation found a conflict if (isConflicting()) return; // otherwise remove assumption and backtrack for (int i = d_trail.size() - 1; i >= first_invalid; --i) { Var x = d_trail[i].var(); d_assigns[x] = toInt(l_Undef); d_reason [x] = NULL; d_order.undo(x); } d_trail.resize(first_invalid); d_trail_lim.resize(level); d_qhead = first_invalid; } } } CVC3::QueryResult Solver::search() { DebugAssert(d_popRequests == 0, "MiniSat::Solver::search: pop requests pending"); DebugAssert(!d_pushes.empty(), "MiniSat::Solver::search: no push before search"); d_inSearch = true; SearchParams params(d_default_params); d_stats.starts++; d_var_decay = 1 / params.var_decay; d_cla_decay = 1 / params.clause_decay; if (protocol) printState(); // initial unit propagation has been done in push - // already unsatisfiable without search if (!d_ok) { if (getDerivation() != NULL) getDerivation()->finish(d_conflict, this); return CVC3::UNSATISFIABLE; } // main search loop SAT::Lit literal; SAT::CNF_Formula_Impl clauses; for (;;){ // if (d_learnts.size() == 1 && decisionLevel() == 3) printState(); // -1 needed if the current 'propagation' is a split DebugAssert(d_thead <= d_qhead, "MiniSat::Solver::search: thead <= qhead"); DebugAssert(d_trail_lim.size() == 0 || d_qhead >= (size_type)d_trail_lim[decisionLevel() - 1], "MiniSat::Solver::search: qhead >= trail_lim[decisionLevel()"); DebugAssert(d_trail_lim.size() == 0 || d_thead >= (size_type)d_trail_lim[decisionLevel() - 1], "MiniSat::Solver::search: thead >= trail_lim[decisionLevel()"); // 1. clause set detected to be unsatisfiable if (!d_ok) { d_stats.conflicts++; if (getDerivation() != NULL) getDerivation()->finish(d_conflict, this); return CVC3::UNSATISFIABLE; } // 2. out of resources, e.g. quantifier instantiation aborted if (d_theoryAPI->outOfResources()) { return CVC3::ABORT; } // 3. boolean conflict, backtrack if (d_conflict != NULL){ d_stats.conflicts++; // unsatisfiability detected if (decisionLevel() == d_rootLevel){ d_ok = false; if (getDerivation() != NULL) getDerivation()->finish(d_conflict, this); return CVC3::UNSATISFIABLE; } int backtrack_level; Clause* learnt_clause = analyze(backtrack_level); backtrack(backtrack_level, learnt_clause); if (protocol) { cout << "conflict clause: " << toString(*learnt_clause, true); clauses.print(); } varDecayActivity(); claDecayActivity(); if (protocol) { cout << "backtrack to: " << backtrack_level << endl; } } // 4. theory conflict - cheap theory consistency check else if (d_theoryAPI->checkConsistent(clauses, false) == SAT::DPLLT::INCONSISTENT) { if (protocol) { cout << "theory inconsistency: " << endl; clauses.print(); } d_stats.theory_conflicts++; addFormula(clauses, true); clauses.reset(); while (!isConflicting() && d_ok && d_qhead < d_trail.size() && !isConflicting()) { protocolPropagation(); propagate(); } DebugAssert(isConflicting(), "expected conflict"); } // 5. boolean propagation else if (d_qhead < d_trail.size()) { // do boolean propagation to exhaustion // before telling the theories about propagated literals if (defer_theory_propagation) { while (d_ok && d_qhead < d_trail.size() && !isConflicting()) { protocolPropagation(); propagate(); } } // immediately tell theories about boolean propagations else { protocolPropagation(); propagate(); } } // :TODO: move to 8. tell theories about new boolean propagations // problem: can lead to worse performance, // apparently then to many theory clauses are learnt, // so need to forget them (database cleanup), or limit them (subsumption test) else if (defer_theory_propagation && d_thead < d_qhead) { while (d_thead < d_qhead) { d_theoryAPI->assertLit(miniSatToCVC(d_trail[d_thead])); ++d_thead; } } // everything else else { DebugAssert(d_qhead == d_thead, "MiniSat::Solver::search: d_qhead != d_thead"); // 6. theory clauses if (d_theoryAPI->getNewClauses(clauses)) { if (protocol) { cout << "theory clauses: " << endl; clauses.print(); printState(); } addFormula(clauses, true); clauses.reset(); continue; } // 7. theory implication literal = d_theoryAPI->getImplication(); if (!literal.isNull()) { Lit lit = MiniSat::cvcToMiniSat(literal); if (protocol) { cout << "theory implication: " << lit.index() << endl; } if ( // get explanation now eager_explanation || // enqueue, and retrieve explanation (as a conflict clause) // only if this implication is responsible for a conflict. !enqueue(lit, decisionLevel(), Clause::TheoryImplication()) ) { d_theoryAPI->getExplanation(literal, clauses); if (protocol) { cout << "theory implication reason: " << endl; clauses.print(); } addFormula(clauses, true); clauses.reset(); } continue; } // // 8. tell theories about new boolean propagations // if (defer_theory_propagation && d_thead < d_qhead) { // d_theoryAPI->assertLit(miniSatToCVC(d_trail[d_thead])); // ++d_thead; // continue; // } // DebugAssert(d_qhead == d_thead, "MiniSat::Solver::search: d_qhead != d_thead"); // 9. boolean split Lit next = lit_Undef; // use CVC decider if (d_decider != NULL) { literal = d_decider->makeDecision(); if (!literal.isNull()) { next = MiniSat::cvcToMiniSat(literal); } } // use MiniSat's decision heuristic else { Var nextVar = d_order.select(params.random_var_freq); if (nextVar != var_Undef){ next = ~Lit(nextVar, false); } } if (next != lit_Undef) { // Simplify the set of problem clauses: // there must have been enough propagations in root level, // and no simplification too recently if (false && d_simpDB_props <= 0 && d_simpDB_assigns > (nAssigns() / 10)) { simplifyDB(); DebugAssert(d_ok, "MiniSat::Solver::search: simplifyDB resulted in conflict"); } // Reduce the set of learnt clauses: //if (nof_learnts >= 0 && learnts.size()-nAssigns() >= nof_learnts) //if (learnts.size()-nAssigns() >= nClauses() / 3) // don't remove lemmas unless there are a significant number //if (d_learnts.size() - nAssigns() < nClauses() / 3) //return; // don't remove lemmas unless there are lots of new ones // if (d_learnts.size() - nAssigns() < 3 * d_simpRD_learnts) // return; // :TODO: //reduceDB(); d_stats.decisions++; d_theoryAPI->push(); DebugAssert(getValue(next) == l_Undef, "MiniSat::Solver::search not undefined split variable chosen."); if (protocol) { cout << "Split: " << next.index() << endl; } // do lookahead based on MiniSat's decision heuristic if (d_decider != NULL) propLookahead(params); if (isConflicting()) { ++d_stats.debug; continue; } if (!assume(next)) { DebugAssert(false, "MiniSat::Solver::search contradictory split variable chosen."); } continue; } // 10. full theory consistency check SAT::DPLLT::ConsistentResult result = d_theoryAPI->checkConsistent(clauses, true); // inconsistency detected if (result == SAT::DPLLT::INCONSISTENT) { if (protocol) { cout << "theory conflict (FULL): " << endl; clauses.print(); printState(); } d_stats.theory_conflicts++; addFormula(clauses, true); clauses.reset(); while (!isConflicting() && d_ok && d_qhead < d_trail.size() && !isConflicting()) { protocolPropagation(); propagate(); } DebugAssert(isConflicting(), "expected conflict"); continue; } // perhaps consistent, new clauses added by theory propagation if (result == SAT::DPLLT::MAYBE_CONSISTENT) { if (d_theoryAPI->getNewClauses(clauses)) { if (protocol) { cout << "theory clauses: " << endl; clauses.print(); } addFormula(clauses, true); clauses.reset(); } // it can happen that after doing a full consistency check // there are actually no new theory clauses, // but then there will be new decisions in the next round. continue; } // consistent if (result == SAT::DPLLT::CONSISTENT) { DebugAssert(d_decider == NULL || d_decider->makeDecision().isNull(), "DPLLTMiniSat::search: consistent result, but decider not done yet."); DebugAssert(allClausesSatisfied(), "DPLLTMiniSat::search: consistent result, but not all clauses satisfied."); return CVC3::SATISFIABLE; } FatalAssert(false, "DPLLTMiniSat::search: unreachable"); return CVC3::SATISFIABLE; } } } /// Activity // Divide all variable activities by 1e100. // void Solver::varRescaleActivity() { for (int i = 0; i < nVars(); i++) d_activity[i] *= 1e-100; d_var_inc *= 1e-100; } // Divide all constraint activities by 1e100. // void Solver::claRescaleActivity() { for (vector::const_iterator i = d_learnts.begin(); i != d_learnts.end(); i++) { (*i)->setActivity((*i)->activity() * (float)1e-20); } d_cla_inc *= 1e-20; } /// /// expensive debug checks /// bool Solver::allClausesSatisfied() { if (!debug_full) return true; for (size_type i = 0; i < d_clauses.size(); ++i) { Clause& clause = *d_clauses[i]; int size = clause.size(); bool satisfied = false; for (int j = 0; j < size; ++j) { if (getValue(clause[j]) == l_True) { satisfied = true; break; } } if (!satisfied) { cout << "Clause not satisfied:" << endl; cout << toString(clause, true); for (int j = 0; j < size; ++j) { Lit lit = clause[j]; bool found = false; const vector& ws = getWatches(~lit); if (getLevel(lit) == d_rootLevel) { found = true; } else { for (size_type j = 0; !found && j < ws.size(); ++j) { if (ws[j] == &clause) { found = true; break; } } } if (found) { cout << " watched: " << toString(lit, true) << endl; } else { cout << "not watched: " << toString(lit, true) << endl; } } return false; } } return true; } void Solver::checkWatched(const Clause& clause) const { // unary clauses are not watched if (clause.size() < 2) return; for (int i = 0; i < 2; ++i) { Lit lit = clause[i]; bool found = false; const vector& ws = getWatches(~lit); // simplifyDB removes watches on permanently set literals if (getLevel(lit) == d_rootLevel) found = true; // search for clause in watches for (size_type j = 0; !found && j < ws.size(); ++j) { if (ws[j] == &clause) found = true; } if (!found) { printState(); cout << toString(clause, true) << " : " << toString(clause[i], false) << endl; FatalAssert(false, "MiniSat::Solver::checkWatched"); } } } void Solver::checkWatched() const { if (!debug_full) return; for (size_type i = 0; i < d_clauses.size(); ++i) { checkWatched(*d_clauses[i]); } for (size_type i = 0; i < d_learnts.size(); ++i) { checkWatched(*d_learnts[i]); } } void Solver::checkClause(const Clause& clause) const { // unary clauses are true anyway if (clause.size() < 2) return; // 1) the first two literals are undefined if (getValue(clause[0]) == l_Undef && getValue(clause[1]) == l_Undef) return; // 2) one of the first two literals is satisfied else if (getValue(clause[0]) == l_True || getValue(clause[1]) == l_True) return; // 3) the first literal is undefined and all other literals are falsified // 4) all literals are falsified else { bool ok = true; if (getValue(clause[0]) == l_True) ok = false; for (int j = 1; ok && j < clause.size(); ++j) { if (getValue(clause[j]) != l_False) { ok = false; } } if (ok) return; } printState(); cout << endl; cout << toString(clause, true) << endl; FatalAssert(false, "MiniSat::Solver::checkClause"); } void Solver::checkClauses() const { if (!debug_full) return; for (size_type i = 0; i < d_clauses.size(); ++i) { checkClause(*d_clauses[i]); } for (size_type i = 0; i < d_learnts.size(); ++i) { checkClause(*d_learnts[i]); } } void Solver::checkTrail() const { if (!debug_full) return; for (size_type i = 0; i < d_trail.size(); ++i) { Lit lit = d_trail[i]; Var var = lit.var(); Clause* reason = d_reason[var]; if (reason == Clause::Decision() || reason == Clause::TheoryImplication()) { } else { const Clause& clause = *reason; // check that the first clause literal is the implied literal FatalAssert(clause.size() > 0, "MiniSat::Solver::checkTrail: empty clause as reason for " /*+ var*/); FatalAssert(lit == clause[0], "MiniSat::Solver::checkTrail: incorrect reason for " /*+ var*/); FatalAssert(d_assigns[var] == toInt(lbool(lit.sign())), "MiniSat::Solver::checkTrail: incorrect value for " /*+ var*/); // check that other literals are in the trail before this literal and this literal's level for (int j = 1; j < clause.size(); ++j) { Lit clauseLit = clause[j]; Var clauseVar = clauseLit.var(); FatalAssert(getLevel(var) >= getLevel(clauseVar), "MiniSat::Solver::checkTrail: depends on later asserted literal " /*+ var*/); bool found = false; for (size_type k = 0; k < i; ++k) { if (d_trail[k] == ~clauseLit) { found = true; break; } } FatalAssert(found, "MiniSat::Solver::checkTrail: depends on literal not in context " /*+ var*/); } } } } void Solver::setPushID(Var var, Clause* from) { // check that var is implied by from DebugAssert(getReason(var) == from, "MiniSat::Solver::setPushID: wrong reason given"); int pushID = std::numeric_limits::max(); if (from != Clause::Decision() && from != Clause::TheoryImplication()) { pushID = from->pushID(); for (int i = 1; i < from->size(); ++i) { pushID = std::max(pushID, getPushID((*from)[i])); } } d_pushIDs[var] = pushID; } void Solver::push() { DebugAssert(!inSearch(), "MiniSat::Solver::push: already in search"); // inconsistency before this push, so nothing can happen after it, // so just mark this push as useless. // (can happen if before checkSat initial unit propagation finds an inconsistency) if (!d_ok) { d_pushes.push_back(PushEntry(-1, 0, 0, 0, true)); return; } d_registeredVars.resize(d_registeredVars.size() + 1); // reinsert lemmas kept over the last pop for (vector::const_iterator i = d_popLemmas.begin(); i != d_popLemmas.end(); ++i) { Clause* lemma = *i; insertLemma(lemma, lemma->id(), lemma->pushID()); d_stats.learnts_literals -= lemma->size(); remove(lemma, true); } d_popLemmas.clear(); // do propositional propagation to exhaustion, including the theory if (push_theory_propagation) { SAT::Lit literal; SAT::Clause clause; SAT::CNF_Formula_Impl clauses; // while more can be propagated while (!isConflicting() && (d_qhead < d_trail.size() || d_thead < d_qhead)) { // do propositional propagation to exhaustion while (!isConflicting() && d_qhead < d_trail.size()) { protocolPropagation(); propagate(); } // also propagate to theories right away if (defer_theory_propagation) { while (!isConflicting() && d_thead < d_qhead) { d_theoryAPI->assertLit(miniSatToCVC(d_trail[d_thead])); ++d_thead; } } // propagate a theory implication if (push_theory_implication) { literal = d_theoryAPI->getImplication(); if (!literal.isNull()) { Lit lit = MiniSat::cvcToMiniSat(literal); if (protocol) { cout << "theory implication: " << lit.index() << endl; } if ( // get explanation now eager_explanation || // enqueue, and retrieve explanation (as a conflict clause) // only if this implication is responsible for a conflict. !enqueue(lit, decisionLevel(), Clause::TheoryImplication()) ) { d_theoryAPI->getExplanation(literal, clauses); if (protocol) { cout << "theory implication reason: " << endl; clauses.print(); } addFormula(clauses, false); clauses.reset(); } continue; } } // add a theory clause // if (push_theory_clause && d_theoryAPI->getNewClauses(clauses)) { if (push_theory_clause ) { bool hasNewClauses = d_theoryAPI->getNewClauses(clauses); if(hasNewClauses){ if (protocol) { cout << "theory clauses: " << endl; clauses.print(); printState(); } addFormula(clauses, false); clauses.reset(); continue; } } } } // do propositional propagation to exhaustion, but only on the propositional level else { while (!isConflicting() && d_qhead < d_trail.size()) { protocolPropagation(); propagate(); } } simplifyDB(); // can happen that conflict is detected in propagate // but d_ok is not immediately set to false if (isConflicting()) d_ok = false; if (d_derivation != NULL) d_derivation->push(d_clauseIDCounter - 1); d_pushes.push_back(PushEntry(d_clauseIDCounter - 1, d_trail.size(), d_qhead, d_thead, d_ok)); } void Solver::requestPop() { DebugAssert(inPush(), "MiniSat::Solver::requestPop: no more pushes"); // pop theories on first pop of consistent solver, // for inconsistent solver this is done in dpllt_minisat before the pop if (d_popRequests == 0 && isConsistent()) popTheories(); ++d_popRequests; } void Solver::doPops() { if (d_popRequests == 0) return; while (d_popRequests > 1) { --d_popRequests; d_pushes.pop_back(); } pop(); } void Solver::popTheories() { for (int i = d_rootLevel; i < decisionLevel(); ++i) { d_theoryAPI->pop(); } } void Solver::popClauses(const PushEntry& pushEntry, vector& clauses) { size_type i = 0; while (i != clauses.size()) { // keep clause if (clauses[i]->pushID() >= 0 && clauses[i]->pushID() <= pushEntry.d_clauseID) { // cout << "solver keep : " << clauses[i]->id() << endl; // cout << "solver keep2 : " << clauses[i]->pushID() << endl; ++i; } // remove clause else { // cout << "solver pop : " << clauses[i]->id() << endl; remove(clauses[i]); clauses[i] = clauses.back(); clauses.pop_back(); } } } void Solver::pop() { DebugAssert(d_popRequests == 1, "Minisat::Solver::pop: d_popRequests != 1"); --d_popRequests; PushEntry pushEntry = d_pushes.back(); d_pushes.pop_back(); // solver was already inconsistent before the push if (pushEntry.d_clauseID == -1) { DebugAssert(!d_ok, "Minisat::Solver::pop: inconsistent push, but d_ok == true"); return; } // backtrack trail // // Note: // the entries that were added to the trail after the push, // and are kept over the pop, // are all based on propagating clauses/lemmas also kept after the push. // as they are not yet propagated yet, but only in the propagation queue, // watched literals will work fine. size_type first_invalid = pushEntry.d_trailSize; for (size_type i = pushEntry.d_trailSize; i != d_trail.size(); ++i) { Var x = d_trail[i].var(); //setLevel(x, -1); d_assigns[x] = toInt(l_Undef); d_reason [x] = NULL; //d_pushIDs[x] = -1; d_order.undo(x); } d_trail.resize(first_invalid); d_trail_lim.resize(0); d_qhead = pushEntry.d_qhead; d_thead = pushEntry.d_thead; // remove clauses added after push popClauses(pushEntry, d_clauses); // move all lemmas that are not already the reason for an implication // to pending lemmas - these are to be added when the next push is done. size_type i = 0; while (i != d_popLemmas.size()) { if (d_popLemmas[i]->pushID() <= pushEntry.d_clauseID) { ++i; } else { remove(d_popLemmas[i], true); d_popLemmas[i] = d_popLemmas.back(); d_popLemmas.pop_back(); } } i = 0; while (i != d_learnts.size()) { Clause* lemma = d_learnts[i]; // lemma is propagating, so it was already present before the push if (isReason(lemma)) { // cout << "solver keep lemma reason : " << lemma->id() << endl; // cout << "solver keep lemma reason2 : " << lemma->pushID() << endl; ++i; } // keep lemma? else { d_stats.learnts_literals -= lemma->size(); // lemma ok after push, mark it for reinsertion in the next push if (lemma->pushID() <= pushEntry.d_clauseID) { // cout << "solver keep lemma : " << lemma->id() << endl; // cout << "solver keep lemma2 : " << lemma->pushID() << endl; if (lemma->size() >= 2) { removeWatch(getWatches(~(*lemma)[0]), lemma); removeWatch(getWatches(~(*lemma)[1]), lemma); } d_popLemmas.push_back(lemma); } // lemma needs to be removed else { // cout << "solver pop lemma : " << lemma->id() << endl; remove(lemma); } d_learnts[i] = d_learnts.back(); d_learnts.pop_back(); } } d_stats.debug += d_popLemmas.size(); // remove all pending clauses and explanations while (!d_pendingClauses.empty()) { remove(d_pendingClauses.front(), true); d_pendingClauses.pop(); } while (!d_theoryExplanations.empty()) { remove(d_theoryExplanations.top().second, true); d_theoryExplanations.pop(); } // backtrack registered variables d_registeredVars.resize(d_pushes.size() + 1); if (pushEntry.d_ok) { // this needs to be done _after_ clauses have been removed above, // as it might deallocate removed clauses if (d_derivation != NULL) d_derivation->pop(pushEntry.d_clauseID); // not conflicting or in search anymore d_conflict = NULL; d_ok = true; d_inSearch = false; } else { DebugAssert(d_conflict != NULL, "MiniSat::Solver::pop: not in conflict 1"); DebugAssert(!d_ok, "MiniSat::Solver::pop: not in conflict 2"); } } cvc3-2.4.1/src/sat/dpllt_minisat.cpp0000664000175400017540000002725411331647742017225 0ustar mdetersmdeters/*****************************************************************************/ /*! *\file dpllt_minisat.cpp *\brief Implementation of dpllt module using MiniSat * * Author: Alexander Fuchs * * Created: Fri Sep 08 11:04:00 2006 * *
* * License to use, copy, modify, sell and/or distribute this software * and its documentation for any purpose is hereby granted without * royalty, subject to the terms and conditions defined in the \ref * LICENSE file provided with this distribution. * *
*/ /*****************************************************************************/ //we need this to use newPf #define _CVC3_TRUSTED_ #include "dpllt_minisat.h" #include "minisat_solver.h" #include "sat_proof.h" #include "theorem_producer.h" #include "exception.h" using namespace std; using namespace CVC3; using namespace SAT; DPLLTMiniSat::DPLLTMiniSat(TheoryAPI* theoryAPI, Decider* decider, bool printStats, bool createProof) : DPLLT(theoryAPI, decider), d_printStats(printStats), d_createProof(createProof), d_proof(NULL) { pushSolver(); } DPLLTMiniSat::~DPLLTMiniSat() { while (!d_solvers.empty()) { // don't pop theories, this is not allowed when cvc shuts down. delete (d_solvers.top()); d_solvers.pop(); } delete d_proof; } MiniSat::Solver* DPLLTMiniSat::getActiveSolver() { DebugAssert(!d_solvers.empty(), "DPLLTMiniSat::getActiveSolver: no solver"); return d_solvers.top(); } void DPLLTMiniSat::pushSolver() { if (d_solvers.empty()) { d_solvers.push(new MiniSat::Solver(d_theoryAPI, d_decider, d_createProof)); } else { d_solvers.push(MiniSat::Solver::createFrom(getActiveSolver())); } } QueryResult DPLLTMiniSat::search() { DebugAssert(d_solvers.size() > 0, "DPLLTMiniSat::search: no solver"); DebugAssert(getActiveSolver()->inPush(), "DPLLTMiniSat::search: solver not pushed"); // search MiniSat::Solver* solver = getActiveSolver(); QueryResult result = solver->search(); // print statistics if (d_printStats) { switch (result) { case SATISFIABLE: break; case UNSATISFIABLE: cout << "Instance unsatisfiable" << endl; break; case ABORT: cout << "aborted, unable to determine the satisfiablility of the instance" << endl; break; case UNKNOWN: cout << "unknown, unable to determing the satisfiablility of the instance" << endl; break; default: FatalAssert(false, "DPLTBasic::handle_result: Unknown outcome"); } cout << "Number of Decisions\t\t\t" << solver->getStats().decisions << endl; cout << "Number of Propagations\t\t\t" << solver->getStats().propagations << endl; cout << "Number of Propositional Conflicts\t" << (solver->getStats().conflicts - solver->getStats().theory_conflicts) << endl; cout << "Number of Theory Conflicts\t\t" << solver->getStats().theory_conflicts << endl; cout << "Number of Variables\t\t\t" << solver->nVars() << endl; cout << "Number of Literals\t\t\t" << (solver->getStats().clauses_literals + solver->getStats().learnts_literals) << endl; cout << "Max. Number of Literals\t\t\t" << solver->getStats().max_literals << endl; cout << "Number of Clauses\t\t\t" << solver->getClauses().size() << endl; cout << "Number of Lemmas\t\t\t" << solver->getLemmas().size() << endl; cout << "Max. Decision Level\t\t\t" << solver->getStats().max_level << endl; cout << "Number of Deleted Clauses\t\t" << solver->getStats().del_clauses << endl; cout << "Number of Deleted Lemmas\t\t" << solver->getStats().del_lemmas << endl; cout << "Number of Database Simplifications\t" << solver->getStats().db_simpl << endl; cout << "Number of Lemma Cleanups\t\t" << solver->getStats().lm_simpl << endl; cout << "Debug\t\t\t\t\t" << solver->getStats().debug << endl; } // the dpllt interface requires that for an unsat result // all theory pops are undone right away. if (result == UNSATISFIABLE) { // cout << "unsat" <getDerivation() != NULL, "DplltMiniSat::search: no proof"); d_proof = d_solvers.top()->getDerivation()->createProof(); } d_solvers.top()->popTheories(); d_theoryAPI->pop(); } return result; } QueryResult DPLLTMiniSat::checkSat(const CNF_Formula& cnf) { DebugAssert(d_solvers.size() > 0, "DPLLTMiniSat::checkSat: no solver"); // perform any requested solver pops getActiveSolver()->doPops(); DebugAssert(!getActiveSolver()->inSearch(), "DPLLTMiniSat::checkSat: solver already in search"); // required by dpllt interface: theory push before search d_theoryAPI->push(); // solver already in use, so create a new solver if (getActiveSolver()->inSearch()) { pushSolver(); } // add new formula and search getActiveSolver()->addFormula(cnf, false); return search(); } QueryResult DPLLTMiniSat::continueCheck(const CNF_Formula& cnf) { DebugAssert(d_solvers.size() > 0, "DPLLTMiniSat::continueCheck: no solver"); // if the current solver has no push, all its pushes have already been undone, // so remove it if (!getActiveSolver()->inPush()) { DebugAssert(!getActiveSolver()->inSearch(), "DPLLTMiniSat::continueCheck: solver without push in search"); delete getActiveSolver(); d_solvers.pop(); } // perform any requested solver pops getActiveSolver()->doPops(); DebugAssert(d_solvers.size() > 0, "DPLLTMiniSat::continueCheck: no solver (2)"); DebugAssert(getActiveSolver()->inPush(), "DPLLTMiniSat::continueCheck: solver not in push"); DebugAssert(getActiveSolver()->inSearch(), "DPLLTMiniSat::continueCheck: solver not in search"); // add new formula and search getActiveSolver()->addFormula(cnf, false); return search(); } void DPLLTMiniSat::push() { // perform any requested solver pops getActiveSolver()->doPops(); // if the current solver is already in a search, then create a new one if (getActiveSolver()->inSearch()) { pushSolver(); } getActiveSolver()->push(); d_theoryAPI->push(); } void DPLLTMiniSat::pop() { DebugAssert(d_solvers.size() > 0, "DPLLTMiniSat::pop: no solver"); // if the current solver has no push, all its pushes have already been undone, // so remove it if (!getActiveSolver()->inPush()) { DebugAssert(!getActiveSolver()->inSearch(), "DPLLTMiniSat::pop: solver without push in search"); delete getActiveSolver(); d_solvers.pop(); } DebugAssert(d_solvers.size() > 0, "DPLLTMiniSat::pop: no solver 2"); DebugAssert(getActiveSolver()->inPush(), "DPLLTMiniSat::pop: solver not in push"); // undo checkSat theory push for an invalid query. // for a valid query this is done in search right away. if (getActiveSolver()->inSearch() && getActiveSolver()->isConsistent()) { d_theoryAPI->pop(); } getActiveSolver()->requestPop(); d_theoryAPI->pop(); } std::vector DPLLTMiniSat::getCurAssignments(){ return getActiveSolver()->curAssigns(); } std::vector > DPLLTMiniSat::getCurClauses(){ return getActiveSolver()->curClauses(); } void DPLLTMiniSat::addAssertion(const CNF_Formula& cnf) { // perform any requested solver pops getActiveSolver()->doPops(); // if the current solver is already performing a search create a new solver if (getActiveSolver()->inSearch()) { pushSolver(); } getActiveSolver()->addFormula(cnf, false); // Immediately assert unit clauses - // the intention is to make these immediately available for interactive use for (CNF_Formula::const_iterator i = cnf.begin(); i != cnf.end(); ++i) { if ((*i).isUnit() && getActiveSolver()->isConsistent()) { d_theoryAPI->assertLit(*(*i).begin()); } } } Var::Val DPLLTMiniSat::getValue(Var var) { DebugAssert(d_solvers.size() > 0, "DPLLTMiniSat::getValue: should be called after a previous satisfiable result"); MiniSat::lbool value = getActiveSolver()->getValue(MiniSat::cvcToMiniSat(var)); if (value == MiniSat::l_True) return Var::TRUE_VAL; else if (value == MiniSat::l_False) return Var::FALSE_VAL; else return Var::UNKNOWN; } CVC3::Proof generateSatProof(SAT::SatProofNode* node, CNF_Manager* cnfManager, TheoremProducer* thmProducer){ if(node->hasNodeProof()) { return node->getNodeProof(); } if (node->isLeaf()){ /* //<<<<<<< dpllt_minisat.cpp SAT::Clause curClause = *(node->getLeaf()); DebugAssert(!curClause.isNull(), "Null clause found in generateSatProof"); cout << "get leaf clause " << curClause.getId() << endl; const CVC3::Theorem clauseThm = curClause.getClauseTheorem(); //======= */ const CVC3::Theorem clauseThm = node->getLeaf(); /* //>>>>>>> 1.14 */ DebugAssert(!clauseThm.isNull(), "Null thm found in generateSatProof"); node->setNodeProof(clauseThm.getProof()); // cout<<"set proof " << clauseThm.getProof() << endl; // cout<<"set proof for theorem " << clauseThm << endl; return clauseThm.getProof(); } else{ CVC3::Proof leftProof = generateSatProof(node->getLeftParent(), cnfManager, thmProducer); CVC3::Proof rightProof = generateSatProof(node->getRightParent(), cnfManager, thmProducer); if(node->getLeftParent() == node->getRightParent() ) cout<<"***error ********"< pfs; pfs.push_back(leftProof); pfs.push_back(rightProof); // if(leftProof == rightProof) cout<<"***********"<getLit(); Expr e = cnfManager->concreteLit(lit); Expr e_trans = cnfManager->concreteLit(lit,false); // cout<<"set lit "<newPf("bool_resolution", e_trans, pfs); node->setNodeProof(pf); return pf; } } void printSatProof(SAT::SatProofNode* node){ if (node->isLeaf()){ CVC3::Theorem theorem = node->getLeaf(); if(theorem.isNull()){ cout<<"theorem null"<>>>>>> 1.14 cout<<"--------------------" << endl; //<<<<<<< dpllt_minisat.cpp if(clauseThm.isNull()){ cout<<"leaf id " << clause.getId() << " # " << "NULL" << endl; } else{ cout<<"leaf id " << clause.getId() << " # " << clauseThm << endl; } */ /* //======= //>>>>>>> 1.14 */ } } else{ SAT::SatProofNode * leftNode = node->getLeftParent(); SAT::SatProofNode * rightNode = node->getRightParent(); printSatProof(leftNode); printSatProof(rightNode); } } CVC3::Proof DPLLTMiniSat::getSatProof(CNF_Manager* cnfManager, CVC3::TheoryCore* core){ SAT::SatProof* proof = getProof(); SAT::SatProofNode * rootNode = proof->getRoot(); // printSatProof(rootNode); CVC3::TheoremProducer* thmProducer = new TheoremProducer(core->getTM()); return generateSatProof(rootNode, cnfManager, thmProducer); } cvc3-2.4.1/src/sat/minisat_derivation.cpp0000664000175400017540000003507110775325763020255 0ustar mdetersmdeters/*****************************************************************************/ /*! *\file minisat_derivation.cpp *\brief MiniSat proof logging * * Author: Alexander Fuchs * * Created: Sun Dec 07 11:09:00 2007 * *
* * License to use, copy, modify, sell and/or distribute this software * and its documentation for any purpose is hereby granted without * royalty, subject to the terms and conditions defined in the \ref * LICENSE file provided with this distribution. * *
*/ /*****************************************************************************/ #include "minisat_derivation.h" #include "minisat_solver.h" #include "sat_proof.h" #include #include using namespace MiniSat; using namespace std; std::string Inference::toString() const { ostringstream buffer; buffer << getStart(); for (Inference::TSteps::const_iterator step = d_steps.begin(); step != d_steps.end(); ++step) { buffer << " " << step->first.toString() << " " << step->second; } return buffer.str(); } Derivation::~Derivation() { // deallocate generated unit clauses for (TClauses::iterator i = d_unitClauses.begin(); i != d_unitClauses.end(); ++i) { xfree(i->second); } // deallocate removed clauses for (std::deque::iterator i = d_removedClauses.begin(); i != d_removedClauses.end(); ++i) { xfree(*i); } // deallocate inferences for (TInferences::iterator i = d_inferences.begin(); i != d_inferences.end(); ++i) { delete i->second; } } int Derivation::computeRootReason(Lit implied, Solver* solver) { Clause* reason = solver->getReason(implied); // cout << "computeRootReason " << reason->id() << endl; FatalAssert(d_clauses.find(reason->id()) != d_clauses.end(), "MiniSat::Derivation::computeRootReason: implied reason not registered"); FatalAssert(reason == d_clauses.find(reason->id())->second, "MiniSat::Derivation::computeRootReason: implied reason not same as registered"); FatalAssert(reason != NULL, "MiniSat::Derivation::computeRootReason: implied reason is NULL"); FatalAssert(reason != Clause::Decision(), "MiniSat::Derivation::computeRootReason: implied is a decision"); FatalAssert((*reason)[0] == implied, "MiniSat::Derivation::computeRootReason: implied is not in its reason"); IF_DEBUG ( FatalAssert(solver->getValue((*reason)[0]) == l_True, "MiniSat::Derivation::computeRootReason: literal not implied (TRUE)"); for (int i = 1; i < reason->size(); ++i) { FatalAssert(solver->getValue((*reason)[i]) == l_False, "MiniSat::Derivation::computeRootReason: literal not implied (FALSE)"); } ) // already a unit clause, so done if (reason->size() == 1) { return reason->id(); } // already derived the unit clause internally TClauses::const_iterator iter = d_unitClauses.find(implied.index()); if (iter != d_unitClauses.end()) { return iter->second->id(); } // otherwise resolve the reason ... Inference* inference = new Inference(reason->id()); for (int i = 1; i < reason->size(); ++i) { Lit lit((*reason)[i]); inference->add(lit, computeRootReason(~lit, solver)); } // and create the new unit clause // (after resolve, so that clause ids are chronological wrt. inference) vector literals; literals.push_back(implied); Clause* unit = Clause_new(literals, CVC3::Theorem(), solver->nextClauseID()); d_unitClauses[implied.index()] = unit; // cout << "compute root reason : " << unit->id() << endl; registerClause(unit); registerInference(unit->id(), inference); return unit->id(); } void Derivation::finish(Clause* clause, Solver* solver) { FatalAssert(clause != NULL, "MiniSat::derivation:finish:"); // already the empty clause if (clause->size() == 0) { d_emptyClause = clause; } // derive the empty clause else { Inference* inference = new Inference(clause->id()); for (int i = 0; i < clause->size(); ++i) { Lit lit((*clause)[i]); inference->add(lit, computeRootReason(~lit, solver)); } vector literals; Clause* empty = Clause_new(literals, CVC3::Theorem(), solver->nextClauseID()); removedClause(empty); d_emptyClause = empty; registerClause(empty); registerInference(empty->id(), inference); } checkDerivation(clause); IF_DEBUG (checkDerivation(clause)); // cout << "PROOF_START" << endl; // printDerivation(); // cout << "PROOF_END" << endl; } void Derivation::checkDerivation(Clause* clause) { // find all relevant clauses // - relevant: set clauses used in derivation // - regress: relevant clauses whose antecedents have to be checked std::set relevant; std::set regress; regress.insert(clause->id()); while (!regress.empty()) { // pick next clause to derive - start from bottom, i.e. latest derived clause int clauseID = *(regress.rbegin()); regress.erase(clauseID); // move to clauses relevant for the derivation FatalAssert(relevant.count(clauseID) == 0, "Solver::printProof: already in relevant"); relevant.insert(clauseID); // process antecedents TInferences::const_iterator iter = d_inferences.find(clauseID); // input clause if (iter == d_inferences.end()) { FatalAssert(d_inputClauses.contains(clauseID), "Solver::printProof: clause without antecedents is not marked as input clause"); } else { Inference* inference = iter->second; regress.insert(inference->getStart()); const Inference::TSteps& steps = inference->getSteps(); for (Inference::TSteps::const_iterator step = steps.begin(); step != steps.end(); ++step) { regress.insert(step->second); } } } // check derivation for (std::set::iterator i = relevant.begin(); i != relevant.end(); ++i) { int clauseID = *i; FatalAssert(d_clauses.contains(clauseID), "MiniSat::Derivation::printProof: clause id in proof is not in clauses"); Clause* clause = d_clauses.find(clauseID)->second; Inference* inference = NULL; TInferences::const_iterator j = d_inferences.find(clauseID); if (j != d_inferences.end()) { inference = j->second; } FatalAssert(inference != NULL || d_inputClauses.contains(clauseID), "MiniSat::Derivation::printProof: derivation of input clause"); FatalAssert(inference == NULL || !d_inputClauses.contains(clauseID), "MiniSat::Derivation::printProof: no derivation for derived clause"); if (inference != NULL) { // cout << "Regress: " << clause->id() << " : " << clause->toString() << endl; FatalAssert(d_clauses.find(inference->getStart()) != d_clauses.end(), "MiniSat::Derivation::printProof: first not in clauses"); Clause* first = d_clauses.find(inference->getStart())->second; // cout << "Derived from : " << first->id() << " : " << first->toString() << endl; set derived; for (int i = 0; i < first->size(); ++i) { derived.insert((*first)[i]); } // retrace derivation for (Inference::TSteps::const_iterator step = inference->getSteps().begin(); step != inference->getSteps().end(); ++step) { Lit lit = step->first; // cout << " over " << lit.toString() << endl; // cout << "Derived from ... : " << step->second << " : " << d_clauses.find(step->second)->second->toString() << endl; FatalAssert(d_clauses.find(step->second) != d_clauses.end(), "MiniSat::Derivation::printProof: next not in clauses"); Clause* next = d_clauses.find(step->second)->second; FatalAssert(derived.find(lit) != derived.end(), "MiniSat::Derivation::printProof: lit not in derived"); FatalAssert(next->contains(~lit), "MiniSat::Derivation::printProof: ~lit not in next"); derived.erase(lit); for (int i = 0; i < next->size(); ++i) { if ((*next)[i] != ~lit) { derived.insert((*next)[i]); } } } // check that we got the expected clause for (int i = 0; i < clause->size(); ++i) { FatalAssert(derived.find((*clause)[i]) != derived.end(), "MiniSat::Derivation::printProof: didn't derive expected clause"); derived.erase((*clause)[i]); } FatalAssert(derived.empty(), "MiniSat::Derivation::printProof: didn't derive expected clause 2"); }; } } SAT::SatProof* Derivation::createProof() { FatalAssert(d_emptyClause != NULL, "MiniSat::Derivation:createProof: no empty clause"); FatalAssert(d_emptyClause->size() == 0, "MiniSat::Derivation:createProof: empty clause is not empty"); return createProof(d_emptyClause); } SAT::SatProof* Derivation::createProof(Clause* clause) { checkDerivation(clause); // IF_DEBUG (checkDerivation(clause)); // find all relevant clauses // - relevant: set clauses used in derivation // - regress: relevant clauses whose antecedents have to be checked std::set relevant; std::set regress; regress.insert(clause->id()); while (!regress.empty()) { // pick next clause to derive - start from bottom, i.e. latest derived clause int clauseID = *(regress.rbegin()); regress.erase(clauseID); relevant.insert(clauseID); // process antecedents TInferences::const_iterator iter = d_inferences.find(clauseID); // input clause if (iter != d_inferences.end()) { Inference* inference = iter->second; regress.insert(inference->getStart()); const Inference::TSteps& steps = inference->getSteps(); for (Inference::TSteps::const_iterator step = steps.begin(); step != steps.end(); ++step) { regress.insert(step->second); } } } // create proof SAT::SatProof* proof = new SAT::SatProof(); std::hash_map proofNodes; for (std::set::iterator i = relevant.begin(); i != relevant.end(); ++i) { int clauseID = *i; Clause* clause = d_clauses.find(clauseID)->second; Inference* inference = NULL; TInferences::const_iterator j = d_inferences.find(clauseID); if (j == d_inferences.end()) { /* <<<<<<< minisat_derivation.cpp FatalAssert(clause->getCvcClause() != NULL, "createProof: leaf without clause"); FatalAssert(clause->getCvcClause() != NULL, "createProof: leaf without clause"); proofNodes[clause->id()] = proof->registerLeaf(clause->getCvcClause()); // cout<<"cluase with :" << clause->id() << " ---> " ; // clause->getCvcClause()->print(); // cout << endl; ======= */ FatalAssert(!clause->getTheorem().isNull(), "createProof: leaf without clause"); proofNodes[clause->id()] = proof->registerLeaf(clause->getTheorem()); /* >>>>>>> 1.9 */ } else { inference = j->second; FatalAssert(proofNodes.contains(inference->getStart()), "createProof: contains inference start"); SAT::SatProofNode* left = proofNodes.find(inference->getStart())->second; const Inference::TSteps& steps = inference->getSteps(); for (Inference::TSteps::const_iterator step = steps.begin(); step != steps.end(); ++step) { FatalAssert(proofNodes.contains(step->second), "createProof: contains inference start"); SAT::SatProofNode* right = proofNodes.find(step->second)->second; left = proof->registerNode(left, right, miniSatToCVC(step->first)); } proofNodes[clause->id()] = left; } } proof->setRoot(proofNodes[clause->id()]); return proof; } void Derivation::printDerivation() { FatalAssert(d_emptyClause != NULL, "MiniSat::Derivation:printDerivation: no empty clause"); FatalAssert(d_emptyClause->size() == 0, "MiniSat::Derivation:printDerivation: empty clause is not empty"); printDerivation(d_emptyClause); } void Derivation::printDerivation(Clause* clause) { IF_DEBUG (checkDerivation(clause)); // find all relevant clauses // - relevant: set clauses used in derivation // - regress: relevant clauses whose antecedents have to be checked std::set relevant; std::set regress; regress.insert(clause->id()); while (!regress.empty()) { // pick next clause to derive - start from bottom, i.e. latest derived clause int clauseID = *(regress.rbegin()); regress.erase(clauseID); // move to clauses relevant for the derivation relevant.insert(clauseID); // process antecedents TInferences::const_iterator iter = d_inferences.find(clauseID); // input clause if (iter != d_inferences.end()) { Inference* inference = iter->second; regress.insert(inference->getStart()); const Inference::TSteps& steps = inference->getSteps(); for (Inference::TSteps::const_iterator step = steps.begin(); step != steps.end(); ++step) { regress.insert(step->second); } } } // print proof for (std::set::iterator i = relevant.begin(); i != relevant.end(); ++i) { int clauseID = *i; Clause* clause = d_clauses.find(clauseID)->second; Inference* inference = NULL; TInferences::const_iterator j = d_inferences.find(clauseID); if (j != d_inferences.end()) { inference = j->second; } // ID D : L1 ... Ln : C1 K1 C2 K2 ... Cm cout << clauseID; // input clause or derived clause? if (d_inputClauses.contains(clauseID)) { cout << " I "; } else { cout << " D "; } cout << ": " << clause->toString() << " : "; if (inference != NULL) cout << inference->toString(); cout << endl; } } void Derivation::push(int clauseID) { // cout << "derivation push: " << clauseID << endl; } void Derivation::pop(int clauseID) { // cout << "derivation pop: " << clauseID << endl; // remove all popped clauses TClauses::const_iterator i = d_clauses.begin(); while (i != d_clauses.end()) { Clause* clause = (*i).second; if ( // Warning: clause removal needs to be done // exactly the same way in minisat_solver!!! // remove theory lemmas // :TODO: can't do that: kept lemmas might depend on them // (!clause->learnt() && clause->pushID() < 0) // || // remove clauses added after the last push clause->pushID() > clauseID) { int id = clause->id(); // cout << "derivation pop now: " << id << endl; d_inputClauses.erase(id); d_inferences.erase(id); if (clause->size() == 1) { int index = (*clause)[0].index(); if (d_unitClauses.contains(index) && d_unitClauses[index] == clause) { d_unitClauses.erase(index); FatalAssert(!d_unitClauses.contains(index), "AHA"); } } i = d_clauses.erase(i); } else { ++i; } } // undo conflicting clause if (d_emptyClause != NULL && d_emptyClause->pushID() > clauseID) d_emptyClause = NULL; // delete popped and removed clauses std::deque::iterator j = d_removedClauses.begin(); while (j != d_removedClauses.end()) { if ((*j)->pushID() > clauseID) { xfree(*j); j = d_removedClauses.erase(j); } else { ++j; } } } cvc3-2.4.1/src/theory_arith/0000775000175400017540000000000011630011320015531 5ustar mdetersmdeterscvc3-2.4.1/src/theory_arith/Makefile0000664000175400017540000000110011033570665017204 0ustar mdetersmdeters################################################## # About this Makefile # # This Makefile depends on Makefile.opts ################################################## MODULE = theory_arith SRC = arith_theorem_producer_old.cpp \ arith_theorem_producer.cpp \ arith_theorem_producer3.cpp \ theory_arith.cpp \ theory_arith_old.cpp \ theory_arith_new.cpp \ theory_arith3.cpp HEADERS = arith_proof_rules.h \ arith_theorem_producer_old.h \ arith_theorem_producer.h \ arith_theorem_producer3.h \ arith_exception.h LIBRARY=libtheory_arith.a include ../../Makefile.local cvc3-2.4.1/src/theory_arith/arith_theorem_producer3.cpp0000664000175400017540000027702711203160611023100 0ustar mdetersmdeters/*****************************************************************************/ /*! * \file arith_theorem_producer.cpp * * Author: Vijay Ganesh, Sergey Berezin * * Created: Dec 13 02:09:04 GMT 2002 * *
* * License to use, copy, modify, sell and/or distribute this software * and its documentation for any purpose is hereby granted without * royalty, subject to the terms and conditions defined in the \ref * LICENSE file provided with this distribution. * *
* */ /*****************************************************************************/ // CLASS: ArithProofRules // // AUTHOR: Sergey Berezin, 12/11/2002 // AUTHOR: Vijay Ganesh, 05/30/2003 // // Description: TRUSTED implementation of arithmetic proof rules. // /////////////////////////////////////////////////////////////////////////////// // This code is trusted #define _CVC3_TRUSTED_ #include "arith_theorem_producer3.h" #include "theory_core.h" #include "theory_arith3.h" using namespace std; using namespace CVC3; //////////////////////////////////////////////////////////////////// // TheoryArith: trusted method for creating ArithTheoremProducer3 //////////////////////////////////////////////////////////////////// ArithProofRules* TheoryArith3::createProofRules3() { return new ArithTheoremProducer3(theoryCore()->getTM(), this); } //////////////////////////////////////////////////////////////////// // Canonization rules //////////////////////////////////////////////////////////////////// #define CLASS_NAME "ArithTheoremProducer3" // Rule for variables: e == 1 * e Theorem ArithTheoremProducer3::varToMult(const Expr& e) { Proof pf; if(withProof()) pf = newPf("var_to_mult", e); return newRWTheorem(e, (rat(1) * e), Assumptions::emptyAssump(), pf); } // Rule for unary minus: -e == (-1) * e Theorem ArithTheoremProducer3::uMinusToMult(const Expr& e) { Proof pf; if(withProof()) pf = newPf("uminus_to_mult", e); return newRWTheorem((-e), (rat(-1) * e), Assumptions::emptyAssump(), pf); } // ==> x - y = x + (-1) * y Theorem ArithTheoremProducer3::minusToPlus(const Expr& x, const Expr& y) { Proof pf; if(withProof()) pf = newPf("minus_to_plus", x, y); return newRWTheorem((x-y), (x + (rat(-1) * y)), Assumptions::emptyAssump(), pf); } // Rule for unary minus: -e == e/(-1) // This is to reduce the number of almost identical rules for uminus and div Theorem ArithTheoremProducer3::canonUMinusToDivide(const Expr& e) { Proof pf; if(withProof()) pf = newPf("canon_uminus", e); return newRWTheorem((-e), (e / rat(-1)), Assumptions::emptyAssump(), pf); } // Rules for division by constant // (c)/(d) ==> (c/d). When d==0, c/0 = 0 (our total extension). Theorem ArithTheoremProducer3::canonDivideConst(const Expr& c, const Expr& d) { // Make sure c and d are a const if(CHECK_PROOFS) { CHECK_SOUND(isRational(c), CLASS_NAME "::canonDivideConst:\n c not a constant: " + c.toString()); CHECK_SOUND(isRational(d), CLASS_NAME "::canonDivideConst:\n d not a constant: " + d.toString()); } Proof pf; if(withProof()) pf = newPf("canon_divide_const", c, d, d_hole); const Rational& dr = d.getRational(); return newRWTheorem((c/d), (rat(dr==0? 0 : (c.getRational()/dr))), Assumptions::emptyAssump(), pf); } // (c * x)/d ==> (c/d) * x, takes (c*x) and d Theorem ArithTheoremProducer3::canonDivideMult(const Expr& cx, const Expr& d) { // Check the format of c*x if(CHECK_PROOFS) { CHECK_SOUND(isMult(cx) && isRational(cx[0]), CLASS_NAME "::canonDivideMult:\n " "Not a (c * x) expression: " + cx.toString()); CHECK_SOUND(isRational(d), CLASS_NAME "::canonDivideMult:\n " "d is not a constant: " + d.toString()); } const Rational& dr = d.getRational(); Rational cdr(dr==0? 0 : (cx[0].getRational()/dr)); Expr cd(rat(cdr)); Proof pf; if(withProof()) pf = newPf("canon_divide_mult", cx[0], cx[1], d); // (c/d) may be == 1, so we also need to canonize 1*x to x if(cdr == 1) return newRWTheorem((cx/d), (cx[1]), Assumptions::emptyAssump(), pf); else if(cdr == 0) // c/0 == 0 case return newRWTheorem((cx/d), cd, Assumptions::emptyAssump(), pf); else return newRWTheorem((cx/d), (cd*cx[1]), Assumptions::emptyAssump(), pf); } // (+ t1 ... tn)/d ==> (+ (t1/d) ... (tn/d)) Theorem ArithTheoremProducer3::canonDividePlus(const Expr& sum, const Expr& d) { if(CHECK_PROOFS) { CHECK_SOUND(isPlus(sum) && sum.arity() >= 2 && isRational(sum[0]), CLASS_NAME "::canonUMinusPlus:\n " "Expr is not a canonical sum: " + sum.toString()); CHECK_SOUND(isRational(d), CLASS_NAME "::canonUMinusPlus:\n " "d is not a const: " + d.toString()); } // First, propagate '/d' down to the args Proof pf; if(withProof()) pf = newPf("canon_divide_plus", rat(sum.arity()), sum.begin(), sum.end()); vector newKids; for(Expr::iterator i=sum.begin(), iend=sum.end(); i!=iend; ++i) newKids.push_back((*i)/d); // (+ t1 ... tn)/d == (+ (t1/d) ... (tn/d)) return newRWTheorem((sum/d), (plusExpr(newKids)), Assumptions::emptyAssump(), pf); } // x/(d) ==> (1/d) * x, unless d == 1 Theorem ArithTheoremProducer3::canonDivideVar(const Expr& e, const Expr& d) { if(CHECK_PROOFS) { CHECK_SOUND(isRational(d), CLASS_NAME "::canonDivideVar:\n " "d is not a const: " + d.toString()); } Proof pf; if(withProof()) pf = newPf("canon_divide_var", e); const Rational& dr = d.getRational(); if(dr == 1) return newRWTheorem(e/d, e, Assumptions::emptyAssump(), pf); if(dr == 0) // e/0 == 0 (total extension of division) return newRWTheorem(e/d, d, Assumptions::emptyAssump(), pf); else return newRWTheorem(e/d, rat(1/dr) * e, Assumptions::emptyAssump(), pf); } // Multiplication // (MULT expr1 expr2 expr3 ...) // Each expr is in canonical form, i.e. it can be a // 1) Rational constant // 2) Arithmetic Leaf (var or term from another theory) // 3) (POW rational leaf) // where rational cannot be 0 or 1 // 4) (MULT rational mterm'_1 ...) where each mterm' is of type (2) or (3) // If rational == 1 then there should be at least two mterms // 5) (PLUS rational sterm_1 ...) where each sterm is of // type (2) or (3) or (4) // if rational == 0 then there should be at least two sterms Expr ArithTheoremProducer3::simplifiedMultExpr(std::vector & mulKids) { DebugAssert(mulKids.size() >= 1 && mulKids[0].isRational(), ""); if (mulKids.size() == 1) { return mulKids[0]; } if ((mulKids[0] == rat(1)) && mulKids.size() == 2) { return mulKids[1]; } else return multExpr(mulKids); } Expr ArithTheoremProducer3::canonMultConstMult(const Expr & c, const Expr & e) { // c is a rational // e is (MULT rat mterm'_1 ....) // assume that e2 is already in canonic form DebugAssert(c.isRational() && e.getKind() == MULT, ""); std::vector mulKids; DebugAssert ((e.arity() > 1) && (e[0].isRational()), "ArithTheoremProducer3::canonMultConstMult: " "a canonized MULT expression must have arity " "greater than 1: and first child must be " "rational " + e.toString()); Expr::iterator i = e.begin(); mulKids.push_back(rat(c.getRational() * (*i).getRational())); ++i; for(; i != e.end(); ++i) { mulKids.push_back(*i); } return simplifiedMultExpr(mulKids); } Expr ArithTheoremProducer3::canonMultConstPlus(const Expr & e1, const Expr & e2) { DebugAssert(e1.isRational() && e2.getKind() == PLUS && e2.arity() > 0, ""); // e1 is a rational // e2 is of the form (PLUS rational sterm1 sterm2 ...) // assume that e2 is already in canonic form std::vector thmPlusVector; Expr::iterator i = e2.begin(); for(; i!= e2.end(); ++i) { thmPlusVector.push_back(canonMultMtermMterm(e1*(*i))); } Theorem thmPlus1 = d_theoryArith->substitutivityRule(e2.getOp(), thmPlusVector); return thmPlus1.getRHS(); } Expr ArithTheoremProducer3::canonMultPowPow(const Expr & e1, const Expr & e2) { DebugAssert(e1.getKind() == POW && e2.getKind() == POW, ""); // (POW r1 leaf1) * (POW r2 leaf2) Expr leaf1 = e1[1]; Expr leaf2 = e2[1]; Expr can_expr; if (leaf1 == leaf2) { Rational rsum = e1[0].getRational() + e2[0].getRational(); if (rsum == 0) { return rat(1); } else if (rsum == 1) { return leaf1; } else { return powExpr(rat(rsum), leaf1); } } else { std::vector mulKids; mulKids.push_back(rat(1)); // the leafs should be put in decreasing order if (leaf1 < leaf2) { mulKids.push_back(e2); mulKids.push_back(e1); } else { mulKids.push_back(e1); mulKids.push_back(e2); } // FIXME: don't really need to simplify, just wrap up a MULT? return simplifiedMultExpr(mulKids); } } Expr ArithTheoremProducer3::canonMultPowLeaf(const Expr & e1, const Expr & e2) { DebugAssert(e1.getKind() == POW, ""); // (POW r1 leaf1) * leaf2 Expr leaf1 = e1[1]; Expr leaf2 = e2; Expr can_expr; if (leaf1 == leaf2) { Rational rsum = e1[0].getRational() + 1; if (rsum == 0) { return rat(1); } else if (rsum == 1) { return leaf1; } else { return powExpr(rat(rsum), leaf1); } } else { std::vector mulKids; mulKids.push_back(rat(1)); // the leafs should be put in decreasing order if (leaf1 < leaf2) { mulKids.push_back(e2); mulKids.push_back(e1); } else { mulKids.push_back(e1); mulKids.push_back(e2); } return simplifiedMultExpr(mulKids); } } Expr ArithTheoremProducer3::canonMultLeafLeaf(const Expr & e1, const Expr & e2) { // leaf1 * leaf2 Expr leaf1 = e1; Expr leaf2 = e2; Expr can_expr; if (leaf1 == leaf2) { return powExpr(rat(2), leaf1); } else { std::vector mulKids; mulKids.push_back(rat(1)); // the leafs should be put in decreasing order if (leaf1 < leaf2) { mulKids.push_back(e2); mulKids.push_back(e1); } else { mulKids.push_back(e1); mulKids.push_back(e2); } return simplifiedMultExpr(mulKids); } } Expr ArithTheoremProducer3::canonMultLeafOrPowMult(const Expr & e1, const Expr & e2) { DebugAssert(e2.getKind() == MULT, ""); // Leaf * (MULT rat1 mterm1 ...) // (POW r1 leaf1) * (MULT rat1 mterm1 ...) where // each mterm is a leaf or (POW r leaf). Furthermore the leafs // in the mterms are in descending order Expr leaf1 = e1.getKind() == POW ? e1[1] : e1; std::vector mulKids; DebugAssert(e2.arity() > 1, "MULT expr must have arity 2 or more"); Expr::iterator i = e2.begin(); // push the rational mulKids.push_back(*i); ++i; // Now i points to the first mterm for(; i != e2.end(); ++i) { Expr leaf2 = ((*i).getKind() == POW) ? (*i)[1] : (*i); if (leaf1 == leaf2) { Rational r1 = e1.getKind() == POW ? e1[0].getRational() : 1; Rational r2 = ((*i).getKind() == POW ? (*i)[0].getRational() : 1); // if r1 + r2 == 0 then it is the case of x^n * x^{-n} // So, nothing needs to be added if (r1 + r2 != 0) { if (r1 + r2 == 1) { mulKids.push_back(leaf1); } else { mulKids.push_back(powExpr(rat(r1 + r2), leaf1)); } } break; } // This ensures that the leaves in the mterms are also arranged // in decreasing order // Note that this will need to be changed if we want the order to // be increasing order. else if (leaf2 < leaf1) { mulKids.push_back(e1); mulKids.push_back(*i); break; } else // leaf1 < leaf2 mulKids.push_back(*i); } if (i == e2.end()) { mulKids.push_back(e1); } else { // e1 and *i have already been added for (++i; i != e2.end(); ++i) { mulKids.push_back(*i); } } return simplifiedMultExpr(mulKids); } // Local class for ordering monomials; note, that it flips the // ordering given by greaterthan(), to sort in ascending order. class MonomialLess { public: bool operator()(const Expr& e1, const Expr& e2) const { return ArithTheoremProducer3::greaterthan(e1,e2); } }; typedef map MonomMap; Expr ArithTheoremProducer3::canonCombineLikeTerms(const std::vector & sumExprs) { Rational constant = 0; MonomMap sumHashMap; vector sumKids; // Add each distinct mterm (not including the rational) into // an appropriate hash map entry std::vector::const_iterator i = sumExprs.begin(); for (; i != sumExprs.end(); ++i) { Expr mul = *i; if (mul.isRational()) { constant = constant + mul.getRational(); } else { switch (mul.getKind()) { case MULT: { std::vector mulKids; DebugAssert(mul.arity() > 1 && mul[0].isRational(),""); mulKids.push_back(rat(1)); Expr::iterator j = mul.begin(); ++j; for (; j!= mul.end(); ++j) { mulKids.push_back(*j); } // make sure that tempExpr is also in canonic form Expr tempExpr = mulKids.size() > 2 ? multExpr(mulKids): mulKids[1]; MonomMap::iterator i=sumHashMap.find(tempExpr); if (i == sumHashMap.end()) { sumHashMap[tempExpr] = mul[0].getRational(); } else { (*i).second += mul[0].getRational(); } } break; default: { MonomMap::iterator i=sumHashMap.find(mul); // covers the case of POW, leaf if (i == sumHashMap.end()) { sumHashMap[mul] = 1; } else { (*i).second += 1; } break; } } } } // Now transfer to sumKids sumKids.push_back(rat(constant)); MonomMap::iterator j = sumHashMap.begin(), jend=sumHashMap.end(); for(; j != jend; ++j) { if ((*j).second != 0) sumKids.push_back (canonMultMtermMterm(rat((*j).second) * (*j).first).getRHS()); } /* for (unsigned k = 0; k < sumKids.size(); ++k) { cout << "sumKids[" << k << "] = " << sumKids[k].toString() << endl; } */ // The ordering in map guarantees the correct order; no need to sort // std::sort(sumKids.begin(), sumKids.end(), greaterthan); if ((constant == 0) && (sumKids.size() == 2)) { return sumKids[1]; } else if (sumKids.size() == 1) { return sumKids[0]; } else return plusExpr(sumKids); } Expr ArithTheoremProducer3::canonMultLeafOrPowOrMultPlus(const Expr & e1, const Expr & e2) { DebugAssert(e2.getKind() == PLUS, ""); // Leaf * (PLUS rational sterm1 ...) // or // (POW n1 x1) * (PLUS rational sterm1 ...) // or // (MULT r1 m1 m2 ...) * (PLUS rational sterm1 ...) // assume that e1 and e2 are themselves canonized std::vector sumExprs; // Multiply each term in turn. Expr::iterator i = e2.begin(); for (; i != e2.end(); ++i) { sumExprs.push_back(canonMultMtermMterm(e1 * (*i)).getRHS()); } return canonCombineLikeTerms(sumExprs); } Expr ArithTheoremProducer3::canonMultPlusPlus(const Expr & e1, const Expr & e2) { DebugAssert(e1.getKind() == PLUS && e2.getKind() == PLUS, ""); // (PLUS r1 .... ) * (PLUS r1' ...) // assume that e1 and e2 are themselves canonized std::vector sumExprs; // Multiply each term in turn. Expr::iterator i = e1.begin(); for (; i != e1.end(); ++i) { Expr::iterator j = e2.begin(); for (; j != e2.end(); ++j) { sumExprs.push_back(canonMultMtermMterm((*i) * (*j)).getRHS()); } } return canonCombineLikeTerms(sumExprs); } // The following produces a Theorem which is the result of multiplication // of two canonized mterms. e = e1*e2 Theorem ArithTheoremProducer3::canonMultMtermMterm(const Expr& e) { if(CHECK_PROOFS) { CHECK_SOUND(isMult(e) && e.arity() == 2, "canonMultMtermMterm: e = "+e.toString()); } Proof pf; Expr rhs; const Expr& e1 = e[0]; const Expr& e2 = e[1]; string cmmm = "canon_mult_mterm_mterm"; if (e1.isRational()) { // e1 is a Rational const Rational& c = e1.getRational(); if (c == 0) return canonMultZero(e2); else if (c == 1) return canonMultOne(e2); else { switch (e2.getKind()) { case RATIONAL_EXPR : // rat * rat return canonMultConstConst(e1,e2); break; // TODO case of leaf case POW: // rat * (POW rat leaf) // nothing to simplify return d_theoryArith->reflexivityRule (e); break; case MULT: rhs = canonMultConstMult(e1,e2); if(withProof()) pf = newPf(cmmm,e,rhs); return newRWTheorem(e, rhs, Assumptions::emptyAssump(), pf); break; case PLUS: rhs = canonMultConstPlus(e1,e2); if(withProof()) pf = newPf(cmmm,e,rhs); return newRWTheorem(e, rhs, Assumptions::emptyAssump(), pf); break; default: // TODO: I am going to assume that this is just a leaf // i.e., a variable or term from another theory return d_theoryArith->reflexivityRule(e); break; } } } else if (e1.getKind() == POW) { switch (e2.getKind()) { case RATIONAL_EXPR: // switch the order of the two arguments return canonMultMtermMterm(e2 * e1); break; case POW: rhs = canonMultPowPow(e1,e2); if(withProof()) pf = newPf(cmmm,e,rhs); return newRWTheorem(e,rhs, Assumptions::emptyAssump(), pf); break; case MULT: rhs = canonMultLeafOrPowMult(e1,e2); if(withProof()) pf = newPf(cmmm,e,rhs); return newRWTheorem(e, rhs, Assumptions::emptyAssump(), pf); break; case PLUS: rhs = canonMultLeafOrPowOrMultPlus(e1,e2); if(withProof()) pf = newPf(cmmm,e,rhs); return newRWTheorem(e, rhs, Assumptions::emptyAssump(), pf); break; default: rhs = canonMultPowLeaf(e1,e2); if(withProof()) pf = newPf(cmmm,e,rhs); return newRWTheorem(e,rhs, Assumptions::emptyAssump(), pf); break; } } else if (e1.getKind() == MULT) { switch (e2.getKind()) { case RATIONAL_EXPR: case POW: // switch the order of the two arguments return canonMultMtermMterm(e2 * e1); break; case MULT: { // (Mult r m1 m2 ...) (Mult r' m1' m2' ...) Expr result = e2; Expr::iterator i = e1.begin(); for (; i != e1.end(); ++i) { result = canonMultMtermMterm((*i) * result).getRHS(); } if(withProof()) pf = newPf(cmmm,e,result); return newRWTheorem(e, result, Assumptions::emptyAssump(), pf); } break; case PLUS: rhs = canonMultLeafOrPowOrMultPlus(e1,e2); if(withProof()) pf = newPf(cmmm,e,rhs); return newRWTheorem(e,rhs, Assumptions::emptyAssump(), pf); break; default: // leaf // switch the order of the two arguments return canonMultMtermMterm(e2 * e1); break; } } else if (e1.getKind() == PLUS) { switch (e2.getKind()) { case RATIONAL_EXPR: case POW: case MULT: // switch the order of the two arguments return canonMultMtermMterm(e2 * e1); break; case PLUS: rhs = canonMultPlusPlus(e1,e2); if(withProof()) pf = newPf(cmmm,e,rhs); return newRWTheorem(e, rhs, Assumptions::emptyAssump(), pf); break; default: // leaf // switch the order of the two arguments return canonMultMtermMterm(e2 * e1); break; } } else { // leaf switch (e2.getKind()) { case RATIONAL_EXPR: // switch the order of the two arguments return canonMultMtermMterm(e2 * e1); break; case POW: rhs = canonMultPowLeaf(e2,e1); if(withProof()) pf = newPf(cmmm,e,rhs); return newRWTheorem(e, rhs, Assumptions::emptyAssump(), pf); break; case MULT: rhs = canonMultLeafOrPowMult(e1,e2);; if(withProof()) pf = newPf(cmmm,e,rhs); return newRWTheorem(e, rhs, Assumptions::emptyAssump(), pf); break; case PLUS: rhs = canonMultLeafOrPowOrMultPlus(e1,e2); if(withProof()) pf = newPf(cmmm,e,rhs); return newRWTheorem(e, rhs, Assumptions::emptyAssump(), pf); break; default: // leaf * leaf rhs = canonMultLeafLeaf(e1,e2); if(withProof()) pf = newPf(cmmm,e,rhs); return newRWTheorem(e, rhs, Assumptions::emptyAssump(), pf); break; } } FatalAssert(false, "Unreachable"); return newRWTheorem(e, rhs, Assumptions::emptyAssump(), pf); } // (PLUS expr1 expr2 ...) where each expr is itself in canonic form Theorem ArithTheoremProducer3::canonPlus(const Expr& e) { Proof pf; if (withProof()) { pf = newPf("canon_plus", e); } DebugAssert(e.getKind() == PLUS, ""); // First flatten the PLUS std::vector sumKids; Expr::iterator i = e.begin(); for(; i != e.end(); ++i) { if ((*i).getKind() != PLUS) { sumKids.push_back(*i); } else { Expr::iterator j = (*i).begin(); for(; j != (*i).end(); ++j) sumKids.push_back(*j); } } Expr val = canonCombineLikeTerms(sumKids); if (withProof()) { pf = newPf("canon_plus", e, val); } return newRWTheorem(e, val, Assumptions::emptyAssump(), pf); } // (MULT expr1 expr2 ...) where each expr is itself in canonic form Theorem ArithTheoremProducer3::canonMult(const Expr& e) { Proof pf; DebugAssert(e.getKind() == MULT && e.arity() > 1, ""); Expr::iterator i = e.begin(); Expr result = *i; ++i; for (; i != e.end(); ++i) { result = canonMultMtermMterm(result * (*i)).getRHS(); } if (withProof()) { pf = newPf("canon_mult", e,result); } return newRWTheorem(e, result, Assumptions::emptyAssump(), pf); } Theorem ArithTheoremProducer3::canonInvertConst(const Expr& e) { if(CHECK_PROOFS) CHECK_SOUND(isRational(e), "expecting a rational: e = "+e.toString()); Proof pf; if (withProof()) { pf = newPf("canon_invert_const", e); } const Rational& er = e.getRational(); return newRWTheorem((rat(1)/e), rat(er==0? 0 : (1/er)), Assumptions::emptyAssump(), pf); } Theorem ArithTheoremProducer3::canonInvertLeaf(const Expr& e) { Proof pf; if (withProof()) { pf = newPf("canon_invert_leaf", e); } return newRWTheorem((rat(1)/e), powExpr(rat(-1), e), Assumptions::emptyAssump(), pf); } Theorem ArithTheoremProducer3::canonInvertPow(const Expr& e) { DebugAssert(e.getKind() == POW, "expecting a rational"+e[0].toString()); Proof pf; if (withProof()) { pf = newPf("canon_invert_pow", e); } if (e[0].getRational() == -1) return newRWTheorem((rat(1)/e), e[1], Assumptions::emptyAssump(), pf); else return newRWTheorem((rat(1)/e), powExpr(rat(-e[0].getRational()), e), Assumptions::emptyAssump(), pf); } Theorem ArithTheoremProducer3::canonInvertMult(const Expr& e) { DebugAssert(e.getKind() == MULT, "expecting a rational"+e[0].toString()); Proof pf; if (withProof()) { pf = newPf("canon_invert_mult", e); } DebugAssert(e.arity() > 1, "MULT should have arity > 1"+e.toString()); Expr result = canonInvert(e[0]).getRHS(); for (int i = 1; i < e.arity(); ++i) { result = canonMultMtermMterm(result * canonInvert(e[i]).getRHS()).getRHS(); } return newRWTheorem((rat(1)/e), result, Assumptions::emptyAssump(), pf); } // Given an expression e in Canonic form generate 1/e in canonic form // This function assumes that e is not a PLUS expression Theorem ArithTheoremProducer3::canonInvert(const Expr& e) { DebugAssert(e.getKind() != PLUS, "Cannot do inverse on a PLUS"+e.toString()); switch (e.getKind()) { case RATIONAL_EXPR: return canonInvertConst(e); break; case POW: return canonInvertPow(e); break; case MULT: return canonInvertMult(e); break; default: // leaf return canonInvertLeaf(e); break; } } Theorem ArithTheoremProducer3::moveSumConstantRight(const Expr& e) { // Check soundness of the rule if necessary if (CHECK_PROOFS) { CHECK_SOUND(isIneq(e) || e.isEq(), "moveSumConstantRight: input must be Eq or Ineq: " + e.toString()); CHECK_SOUND(isRational(e[0]) || isPlus(e[0]), "moveSumConstantRight: left side must be a canonised sum: " + e.toString()); CHECK_SOUND(isRational(e[1]) && e[1].getRational() == 0, "moveSumConstantRight: right side must be 0: " + e.toString()); } // The rational constant of the sum Rational r = 0; // The right hand side of the expression Expr right = e[0]; // The vector of sum terms vector sumTerms; // Get all the non rational children and if (!right.isRational()) for(Expr::iterator it = right.begin(); it != right.end(); it ++) { // If the term is rational then add the rational number to r if ((*it).isRational()) r = r + (*it).getRational(); // Otherwise just add the sumTerm to the sumTerms else sumTerms.push_back((*it)); } // Setup the new expression Expr transformed; if (sumTerms.size() > 1) // If the number of summands is > 1 return the sum of them transformed = Expr(e.getKind(), plusExpr(sumTerms), rat(-r)); else // Otherwise return the one summand as itself transformed = Expr(e.getKind(), sumTerms[0], rat(-r)); // If proof is needed set it up Proof pf; if (withProof()) pf = newPf("arithm_sum_constant_right", e); // Retrun the theorem explaining the transformation return newRWTheorem(e, transformed, Assumptions::emptyAssump(), pf); } Theorem ArithTheoremProducer3::canonDivide(const Expr& e) { DebugAssert(e.getKind() == DIVIDE, "Expecting Divide"+e.toString()); Proof pf; if (withProof()) { pf = newPf("canon_invert_divide", e); } Theorem thm = newRWTheorem(e, e[0]*(canonInvert(e[1]).getRHS()), Assumptions::emptyAssump(), pf); return d_theoryArith->transitivityRule(thm, canonMult(thm.getRHS())); } // Rules for multiplication // t*c ==> c*t, takes constant c and term t Theorem ArithTheoremProducer3::canonMultTermConst(const Expr& c, const Expr& t) { Proof pf; if(CHECK_PROOFS) { CHECK_SOUND(isRational(c), CLASS_NAME "::canonMultTermConst:\n " "c is not a constant: " + c.toString()); } if(withProof()) pf = newPf("canon_mult_term_const", c, t); return newRWTheorem((t*c), (c*t), Assumptions::emptyAssump(), pf); } // Rules for multiplication // t1*t2 ==> Error, takes t1 and t2 where both are non-constants Theorem ArithTheoremProducer3::canonMultTerm1Term2(const Expr& t1, const Expr& t2) { // Proof pf; // if(withProof()) pf = newPf("canon_mult_term1_term2", t1, t2); if(CHECK_PROOFS) { CHECK_SOUND(false, "Fatal Error: We don't support multiplication" "of two non constant terms at this time " + t1.toString() + " and " + t2.toString()); } return Theorem(); } // Rules for multiplication // 0*x = 0, takes x Theorem ArithTheoremProducer3::canonMultZero(const Expr& e) { Proof pf; if(withProof()) pf = newPf("canon_mult_zero", e); return newRWTheorem((rat(0)*e), rat(0), Assumptions::emptyAssump(), pf); } // Rules for multiplication // 1*x ==> x, takes x Theorem ArithTheoremProducer3::canonMultOne(const Expr& e) { Proof pf; if(withProof()) pf = newPf("canon_mult_one", e); return newRWTheorem((rat(1)*e), e, Assumptions::emptyAssump(), pf); } // Rules for multiplication // c1*c2 ==> c', takes constant c1*c2 Theorem ArithTheoremProducer3::canonMultConstConst(const Expr& c1, const Expr& c2) { Proof pf; if(CHECK_PROOFS) { CHECK_SOUND(isRational(c1), CLASS_NAME "::canonMultConstConst:\n " "c1 is not a constant: " + c1.toString()); CHECK_SOUND(isRational(c2), CLASS_NAME "::canonMultConstConst:\n " "c2 is not a constant: " + c2.toString()); } if(withProof()) pf = newPf("canon_mult_const_const", c1, c2); return newRWTheorem((c1*c2), rat(c1.getRational()*c2.getRational()), Assumptions::emptyAssump(), pf); } // Rules for multiplication // c1*(c2*t) ==> c'*t, takes c1 and c2 and t Theorem ArithTheoremProducer3::canonMultConstTerm(const Expr& c1, const Expr& c2,const Expr& t) { Proof pf; if(CHECK_PROOFS) { CHECK_SOUND(isRational(c1), CLASS_NAME "::canonMultConstTerm:\n " "c1 is not a constant: " + c1.toString()); CHECK_SOUND(isRational(c2), CLASS_NAME "::canonMultConstTerm:\n " "c2 is not a constant: " + c2.toString()); } if(withProof()) pf = newPf("canon_mult_const_term", c1, c2, t); return newRWTheorem(c1*(c2*t), rat(c1.getRational()*c2.getRational())*t, Assumptions::emptyAssump(), pf); } // Rules for multiplication // c1*(+ c2 v1 ...) ==> (+ c1c2 c1v1 ...), takes c1 and the sum Theorem ArithTheoremProducer3::canonMultConstSum(const Expr& c1, const Expr& sum) { Proof pf; std::vector sumKids; if(CHECK_PROOFS) { CHECK_SOUND(isRational(c1), CLASS_NAME "::canonMultConstTerm:\n " "c1 is not a constant: " + c1.toString()); CHECK_SOUND(PLUS == sum.getKind(), CLASS_NAME "::canonMultConstTerm:\n " "the kind must be a PLUS: " + sum.toString()); } Expr::iterator i = sum.begin(); for(; i != sum.end(); ++i) sumKids.push_back(c1*(*i)); Expr ret = plusExpr(sumKids); if(withProof()) pf = newPf("canon_mult_const_sum", c1, sum, ret); return newRWTheorem((c1*sum),ret , Assumptions::emptyAssump(), pf); } // c^n = c' (compute the constant power expression) Theorem ArithTheoremProducer3::canonPowConst(const Expr& e) { if(CHECK_PROOFS) { CHECK_SOUND(e.getKind() == POW && e.arity() == 2 && e[0].isRational() && e[1].isRational(), "ArithTheoremProducer3::canonPowConst("+e.toString()+")"); } const Rational& p = e[0].getRational(); const Rational& base = e[1].getRational(); if(CHECK_PROOFS) { CHECK_SOUND(p.isInteger(), "ArithTheoremProducer3::canonPowConst("+e.toString()+")"); } Expr res; if (base == 0 && p < 0) { res = rat(0); } else res = rat(pow(p, base)); Proof pf; if(withProof()) pf = newPf("canon_pow_const", e); return newRWTheorem(e, res, Assumptions::emptyAssump(), pf); } // Rules for addition // flattens the input. accepts a PLUS expr Theorem ArithTheoremProducer3::canonFlattenSum(const Expr& e) { Proof pf; std::vector sumKids; if(CHECK_PROOFS) { CHECK_SOUND(PLUS == e.getKind(), CLASS_NAME "::canonFlattenSum:\n" "input must be a PLUS:" + e.toString()); } Expr::iterator i = e.begin(); for(; i != e.end(); ++i){ if (PLUS != (*i).getKind()) sumKids.push_back(*i); else { Expr::iterator j = (*i).begin(); for(; j != (*i).end(); ++j) sumKids.push_back(*j); } } Expr ret = plusExpr(sumKids); if(withProof()) pf = newPf("canon_flatten_sum", e,ret); return newRWTheorem(e,ret, Assumptions::emptyAssump(), pf); } // Rules for addition // combine like terms. accepts a flattened PLUS expr Theorem ArithTheoremProducer3::canonComboLikeTerms(const Expr& e) { Proof pf; std::vector sumKids; ExprMap sumHashMap; Rational constant = 0; if(CHECK_PROOFS) { Expr::iterator k = e.begin(); for(; k != e.end(); ++k) CHECK_SOUND(!isPlus(*k), CLASS_NAME "::canonComboLikeTerms:\n" "input must be a flattened PLUS:" + k->toString()); } Expr::iterator i = e.begin(); for(; i != e.end(); ++i){ if(i->isRational()) constant = constant + i->getRational(); else { if (!isMult(*i)) { if(0 == sumHashMap.count((*i))) sumHashMap[*i] = 1; else sumHashMap[*i] += 1; } else { if(0 == sumHashMap.count((*i)[1])) sumHashMap[(*i)[1]] = (*i)[0].getRational(); else sumHashMap[(*i)[1]] = sumHashMap[(*i)[1]] + (*i)[0].getRational(); } } } sumKids.push_back(rat(constant)); ExprMap::iterator j = sumHashMap.begin(); for(; j != sumHashMap.end(); ++j) { if(0 == (*j).second) ;//do nothing else if (1 == (*j).second) sumKids.push_back((*j).first); else sumKids.push_back(rat((*j).second) * (*j).first); } //constant is same as sumKids[0]. //corner cases: "0 + monomial" and "constant"(no monomials) Expr ret; if(2 == sumKids.size() && 0 == constant) ret = sumKids[1]; else if (1 == sumKids.size()) ret = sumKids[0]; else ret = plusExpr(sumKids); if(withProof()) pf = newPf("canon_combo_like_terms",e,ret); return newRWTheorem(e, ret, Assumptions::emptyAssump(), pf); } // 0 = (* e1 e2 ...) <=> 0 = e1 OR 0 = e2 OR ... Theorem ArithTheoremProducer3::multEqZero(const Expr& expr) { if (CHECK_PROOFS) { CHECK_SOUND(expr.isEq() && expr[0].isRational() && expr[0].getRational() == 0 && isMult(expr[1]) && expr[1].arity() > 1, "multEqZero invariant violated"+expr.toString()); } Proof pf; vector kids; Expr::iterator i = expr[1].begin(), iend = expr[1].end(); for (; i != iend; ++i) { kids.push_back(rat(0).eqExpr(*i)); } if (withProof()) { pf = newPf("multEqZero", expr); } return newRWTheorem(expr, Expr(OR, kids), Assumptions::emptyAssump(), pf); } // 0 = (^ c x) <=> false if c <=0 // <=> 0 = x if c > 0 Theorem ArithTheoremProducer3::powEqZero(const Expr& expr) { if (CHECK_PROOFS) { CHECK_SOUND(expr.isEq() && expr[0].isRational() && expr[0].getRational() == 0 && isPow(expr[1]) && expr[1].arity() == 2 && expr[1][0].isRational(), "powEqZero invariant violated"+expr.toString()); } Proof pf; if (withProof()) { pf = newPf("powEqZero", expr); } Rational r = expr[1][0].getRational(); Expr res; if (r <= 0) { res = d_em->falseExpr(); } else { res = rat(0).eqExpr(expr[1][1]); } return newRWTheorem(expr, res, Assumptions::emptyAssump(), pf); } // x^n = y^n <=> x = y (if n is odd) // x^n = y^n <=> x = y OR x = -y (if n is even) Theorem ArithTheoremProducer3::elimPower(const Expr& expr) { if (CHECK_PROOFS) { CHECK_SOUND(expr.isEq() && isPow(expr[0]) && isPow(expr[1]) && isIntegerConst(expr[0][0]) && expr[0][0].getRational() > 0 && expr[0][0] == expr[1][0], "elimPower invariant violated"+expr.toString()); } Proof pf; if (withProof()) { pf = newPf("elimPower", expr); } Rational r = expr[0][0].getRational(); Expr res = expr[0][1].eqExpr(expr[1][1]); if (r % 2 == 0) { res = res.orExpr(expr[0][1].eqExpr(-expr[1][1])); } return newRWTheorem(expr, res, Assumptions::emptyAssump(), pf); } // x^n = c <=> x = root (if n is odd and root^n = c) // x^n = c <=> x = root OR x = -root (if n is even and root^n = c) Theorem ArithTheoremProducer3::elimPowerConst(const Expr& expr, const Rational& root) { if (CHECK_PROOFS) { CHECK_SOUND(expr.isEq() && isPow(expr[0]) && isIntegerConst(expr[0][0]) && expr[0][0].getRational() > 0 && expr[1].isRational() && pow(expr[0][0].getRational(), root) == expr[1].getRational(), "elimPowerConst invariant violated"+expr.toString()); } Proof pf; if (withProof()) { pf = newPf("elimPowerConst", expr, rat(root)); } Rational r = expr[0][0].getRational(); Expr res = expr[0][1].eqExpr(rat(root)); if (r % 2 == 0) { res = res.orExpr(expr[0][1].eqExpr(rat(-root))); } return newRWTheorem(expr, res, Assumptions::emptyAssump(), pf); } // x^n = c <=> false (if n is even and c is negative) Theorem ArithTheoremProducer3::evenPowerEqNegConst(const Expr& expr) { if (CHECK_PROOFS) { CHECK_SOUND(expr.isEq() && isPow(expr[0]) && expr[1].isRational() && isIntegerConst(expr[0][0]) && expr[0][0].getRational() % 2 == 0 && expr[1].getRational() < 0, "evenPowerEqNegConst invariant violated"+expr.toString()); } Proof pf; if (withProof()) { pf = newPf("evenPowerEqNegConst", expr); } return newRWTheorem(expr, d_em->falseExpr(), Assumptions::emptyAssump(), pf); } // x^n = c <=> false (if x is an integer and c is not a perfect n power) Theorem ArithTheoremProducer3::intEqIrrational(const Expr& expr, const Theorem& isIntx) { if (CHECK_PROOFS) { CHECK_SOUND(expr.isEq() && isPow(expr[0]) && expr[1].isRational() && expr[1].getRational() != 0 && isIntegerConst(expr[0][0]) && expr[0][0].getRational() > 0 && ratRoot(expr[1].getRational(), expr[0][0].getRational().getUnsigned()) == 0, "intEqIrrational invariant violated"+expr.toString()); CHECK_SOUND(isIntPred(isIntx.getExpr()) && isIntx.getExpr()[0] == expr[0][1], "ArithTheoremProducer3::intEqIrrational:\n " "wrong integrality constraint:\n expr = " +expr.toString()+"\n isIntx = " +isIntx.getExpr().toString()); } const Assumptions& assump(isIntx.getAssumptionsRef()); Proof pf; if (withProof()) { pf = newPf("int_eq_irr", expr, isIntx.getProof()); } return newRWTheorem(expr, d_em->falseExpr(), assump, pf); } // e[0] kind e[1] <==> true when e[0] kind e[1], // false when e[0] !kind e[1], for constants only Theorem ArithTheoremProducer3::constPredicate(const Expr& e) { if(CHECK_PROOFS) { CHECK_SOUND(e.arity() == 2 && isRational(e[0]) && isRational(e[1]), CLASS_NAME "::constPredicate:\n " "non-const parameters: " + e.toString()); } Proof pf; bool result(false); int kind = e.getKind(); Rational r1 = e[0].getRational(), r2 = e[1].getRational(); switch(kind) { case EQ: result = (r1 == r2)?true : false; break; case LT: result = (r1 < r2)?true : false; break; case LE: result = (r1 <= r2)?true : false; break; case GT: result = (r1 > r2)?true : false; break; case GE: result = (r1 >= r2)?true : false; break; default: if(CHECK_PROOFS) { CHECK_SOUND(false, "ArithTheoremProducer3::constPredicate: wrong kind"); } break; } Expr ret = (result) ? d_em->trueExpr() : d_em->falseExpr(); if(withProof()) pf = newPf("const_predicate", e,ret); return newRWTheorem(e, ret, Assumptions::emptyAssump(), pf); } // e[0] kind e[1] <==> 0 kind e[1] - e[0] Theorem ArithTheoremProducer3::rightMinusLeft(const Expr& e) { Proof pf; int kind = e.getKind(); if(CHECK_PROOFS) { CHECK_SOUND((EQ==kind) || (LT==kind) || (LE==kind) || (GE==kind) || (GT==kind), "ArithTheoremProducer3::rightMinusLeft: wrong kind"); } if(withProof()) pf = newPf("right_minus_left",e); return newRWTheorem(e, Expr(e.getOp(), rat(0), e[1] - e[0]), Assumptions::emptyAssump(), pf); } // e[0] kind e[1] <==> 0 kind e[1] - e[0] Theorem ArithTheoremProducer3::leftMinusRight(const Expr& e) { Proof pf; int kind = e.getKind(); if(CHECK_PROOFS) { CHECK_SOUND((EQ==kind) || (LT==kind) || (LE==kind) || (GE==kind) || (GT==kind), "ArithTheoremProducer3::rightMinusLeft: wrong kind"); } if(withProof()) pf = newPf("left_minus_right",e); return newRWTheorem(e, Expr(e.getOp(), e[0] - e[1], rat(0)), Assumptions::emptyAssump(), pf); } // x kind y <==> x + z kind y + z Theorem ArithTheoremProducer3::plusPredicate(const Expr& x, const Expr& y, const Expr& z, int kind) { if(CHECK_PROOFS) { CHECK_SOUND((EQ==kind) || (LT==kind) || (LE==kind) || (GE==kind) || (GT==kind), "ArithTheoremProducer3::plusPredicate: wrong kind"); } Proof pf; Expr left = Expr(kind, x, y); Expr right = Expr(kind, x + z, y + z); if(withProof()) pf = newPf("plus_predicate",left,right); return newRWTheorem(left, right, Assumptions::emptyAssump(), pf); } // x = y <==> x * z = y * z Theorem ArithTheoremProducer3::multEqn(const Expr& x, const Expr& y, const Expr& z) { Proof pf; if(CHECK_PROOFS) CHECK_SOUND(z.isRational() && z.getRational() != 0, "ArithTheoremProducer3::multEqn(): multiplying equation by 0"); if(withProof()) pf = newPf("mult_eqn", x, y, z); return newRWTheorem(x.eqExpr(y), (x * z).eqExpr(y * z), Assumptions::emptyAssump(), pf); } // x = y <==> z=0 OR x * 1/z = y * 1/z Theorem ArithTheoremProducer3::divideEqnNonConst(const Expr& x, const Expr& y, const Expr& z) { Proof pf; if(withProof()) pf = newPf("mult_eqn_nonconst", x, y, z); return newRWTheorem(x.eqExpr(y), (z.eqExpr(rat(0))).orExpr((x / z).eqExpr(y / z)), Assumptions::emptyAssump(), pf); } // if z is +ve, return e[0] LT|LE|GT|GE e[1] <==> e[0]*z LT|LE|GT|GE e[1]*z // if z is -ve, return e[0] LT|LE|GT|GE e[1] <==> e[1]*z LT|LE|GT|GE e[0]*z Theorem ArithTheoremProducer3::multIneqn(const Expr& e, const Expr& z) { int kind = e.getKind(); if(CHECK_PROOFS) { CHECK_SOUND((LT==kind) || (LE==kind) || (GE==kind) || (GT==kind), "ArithTheoremProducer3::multIneqn: wrong kind"); CHECK_SOUND(z.isRational() && z.getRational() != 0, "ArithTheoremProducer3::multIneqn: " "z must be non-zero rational: " + z.toString()); } Op op(e.getOp()); Proof pf; Expr ret; if(0 < z.getRational()) ret = Expr(op, e[0]*z, e[1]*z); else ret = Expr(op, e[1]*z, e[0]*z); if(withProof()) pf = newPf("mult_ineqn", e, ret); return newRWTheorem(e, ret, Assumptions::emptyAssump(), pf); } Theorem ArithTheoremProducer3::eqToIneq(const Expr& e) { // Check soundness of the rule if necessary if (CHECK_PROOFS) CHECK_SOUND(e.isEq(), "eqToIneq: input must be an equality: " + e.toString()); // The proof object we will use Proof pf; // The parts of the equality x = y const Expr& x = e[0]; const Expr& y = e[1]; // Setup the proof if needed if (withProof()) pf = newPf("eqToIneq", e); // Retrun the theorem explaining the transformation return newRWTheorem(e, leExpr(x,y).andExpr(geExpr(x,y)), Assumptions::emptyAssump(), pf); } // "op1 GE|GT op2" <==> op2 LE|LT op1 Theorem ArithTheoremProducer3::flipInequality(const Expr& e) { Proof pf; if(CHECK_PROOFS) { CHECK_SOUND(isGT(e) || isGE(e), "ArithTheoremProducer3::flipInequality: wrong kind: " + e.toString()); } int kind = isGE(e) ? LE : LT; Expr ret = Expr(kind, e[1], e[0]); if(withProof()) pf = newPf("flip_inequality", e,ret); return newRWTheorem(e,ret, Assumptions::emptyAssump(), pf); } // NOT (op1 LT op2) <==> (op1 GE op2) // NOT (op1 LE op2) <==> (op1 GT op2) // NOT (op1 GT op2) <==> (op1 LE op2) // NOT (op1 GE op2) <==> (op1 LT op2) Theorem ArithTheoremProducer3::negatedInequality(const Expr& e) { const Expr& ineq = e[0]; if(CHECK_PROOFS) { CHECK_SOUND(e.isNot(), "ArithTheoremProducer3::negatedInequality: wrong kind: " + e.toString()); CHECK_SOUND(isIneq(ineq), "ArithTheoremProducer3::negatedInequality: wrong kind: " + (ineq).toString()); } Proof pf; if(withProof()) pf = newPf("negated_inequality", e); int kind; // NOT (op1 LT op2) <==> (op1 GE op2) // NOT (op1 LE op2) <==> (op1 GT op2) // NOT (op1 GT op2) <==> (op1 LE op2) // NOT (op1 GE op2) <==> (op1 LT op2) kind = isLT(ineq) ? GE : isLE(ineq) ? GT : isGT(ineq) ? LE : LT; return newRWTheorem(e, Expr(kind, ineq[0], ineq[1]), Assumptions::emptyAssump(), pf); } //takes two ineqs "|- alpha LT|LE t" and "|- t LT|LE beta" //and returns "|- alpha LT|LE beta" Theorem ArithTheoremProducer3::realShadow(const Theorem& alphaLTt, const Theorem& tLTbeta) { const Expr& expr1 = alphaLTt.getExpr(); const Expr& expr2 = tLTbeta.getExpr(); if(CHECK_PROOFS) { CHECK_SOUND((isLE(expr1) || isLT(expr1)) && (isLE(expr2) || isLT(expr2)), "ArithTheoremProducer3::realShadow: Wrong Kind: " + alphaLTt.toString() + tLTbeta.toString()); CHECK_SOUND(expr1[1] == expr2[0], "ArithTheoremProducer3::realShadow:" " t must be same for both inputs: " + expr1[1].toString() + " , " + expr2[0].toString()); } Assumptions a(alphaLTt, tLTbeta); int firstKind = expr1.getKind(); int secondKind = expr2.getKind(); int kind = (firstKind == secondKind) ? firstKind : LT; Proof pf; if(withProof()) { vector pfs; pfs.push_back(alphaLTt.getProof()); pfs.push_back(tLTbeta.getProof()); pf = newPf("real_shadow",expr1, expr2, pfs); } return newTheorem(Expr(kind, expr1[0], expr2[1]), a, pf); } //! alpha <= t <= alpha ==> t = alpha /*! takes two ineqs "|- alpha LE t" and "|- t LE alpha" and returns "|- t = alpha" */ Theorem ArithTheoremProducer3::realShadowEq(const Theorem& alphaLEt, const Theorem& tLEalpha) { const Expr& expr1 = alphaLEt.getExpr(); const Expr& expr2 = tLEalpha.getExpr(); if(CHECK_PROOFS) { CHECK_SOUND(isLE(expr1) && isLE(expr2), "ArithTheoremProducer3::realShadowLTLE: Wrong Kind: " + alphaLEt.toString() + tLEalpha.toString()); CHECK_SOUND(expr1[1] == expr2[0], "ArithTheoremProducer3::realShadowLTLE:" " t must be same for both inputs: " + alphaLEt.toString() + " , " + tLEalpha.toString()); CHECK_SOUND(expr1[0] == expr2[1], "ArithTheoremProducer3::realShadowLTLE:" " alpha must be same for both inputs: " + alphaLEt.toString() + " , " + tLEalpha.toString()); } Assumptions a(alphaLEt, tLEalpha); Proof pf; if(withProof()) { vector pfs; pfs.push_back(alphaLEt.getProof()); pfs.push_back(tLEalpha.getProof()); pf = newPf("real_shadow_eq", alphaLEt.getExpr(), tLEalpha.getExpr(), pfs); } return newRWTheorem(expr1[0], expr1[1], a, pf); } Theorem ArithTheoremProducer3::finiteInterval(const Theorem& aLEt, const Theorem& tLEac, const Theorem& isInta, const Theorem& isIntt) { const Expr& e1 = aLEt.getExpr(); const Expr& e2 = tLEac.getExpr(); if(CHECK_PROOFS) { CHECK_SOUND(isLE(e1) && isLE(e2), "ArithTheoremProducer3::finiteInterval:\n e1 = " +e1.toString()+"\n e2 = "+e2.toString()); // term 't' is the same in both inequalities CHECK_SOUND(e1[1] == e2[0], "ArithTheoremProducer3::finiteInterval:\n e1 = " +e1.toString()+"\n e2 = "+e2.toString()); // RHS in e2 is (a+c) CHECK_SOUND(isPlus(e2[1]) && e2[1].arity() == 2, "ArithTheoremProducer3::finiteInterval:\n e1 = " +e1.toString()+"\n e2 = "+e2.toString()); // term 'a' in LHS of e1 and RHS of e2 is the same CHECK_SOUND(e1[0] == e2[1][0], "ArithTheoremProducer3::finiteInterval:\n e1 = " +e1.toString()+"\n e2 = "+e2.toString()); // 'c' in the RHS of e2 is a positive integer constant CHECK_SOUND(e2[1][1].isRational() && e2[1][1].getRational().isInteger() && e2[1][1].getRational() >= 1, "ArithTheoremProducer3::finiteInterval:\n e1 = " +e1.toString()+"\n e2 = "+e2.toString()); // Integrality constraints const Expr& isIntaExpr = isInta.getExpr(); const Expr& isInttExpr = isIntt.getExpr(); CHECK_SOUND(isIntPred(isIntaExpr) && isIntaExpr[0] == e1[0], "Wrong integrality constraint:\n e1 = " +e1.toString()+"\n isInta = "+isIntaExpr.toString()); CHECK_SOUND(isIntPred(isInttExpr) && isInttExpr[0] == e1[1], "Wrong integrality constraint:\n e1 = " +e1.toString()+"\n isIntt = "+isInttExpr.toString()); } vector thms; thms.push_back(aLEt); thms.push_back(tLEac); thms.push_back(isInta); thms.push_back(isIntt); Assumptions a(thms); Proof pf; if(withProof()) { vector es; vector pfs; es.push_back(e1); es.push_back(e2); es.push_back(isInta.getExpr()); es.push_back(isIntt.getExpr()); pfs.push_back(aLEt.getProof()); pfs.push_back(tLEac.getProof()); pfs.push_back(isInta.getProof()); pfs.push_back(isIntt.getProof()); pf = newPf("finite_interval", es, pfs); } // Construct GRAY_SHADOW(t, a, 0, c) Expr g(grayShadow(e1[1], e1[0], 0, e2[1][1].getRational())); return newTheorem(g, a, pf); } // Dark & Gray shadows when a <= b Theorem ArithTheoremProducer3::darkGrayShadow2ab(const Theorem& betaLEbx, const Theorem& axLEalpha, const Theorem& isIntAlpha, const Theorem& isIntBeta, const Theorem& isIntx) { const Expr& expr1 = betaLEbx.getExpr(); const Expr& expr2 = axLEalpha.getExpr(); const Expr& isIntAlphaExpr = isIntAlpha.getExpr(); const Expr& isIntBetaExpr = isIntBeta.getExpr(); const Expr& isIntxExpr = isIntx.getExpr(); if(CHECK_PROOFS) { CHECK_SOUND(isLE(expr1) && isLE(expr2), "ArithTheoremProducer3::darkGrayShadow2ab: Wrong Kind: " + betaLEbx.toString() + axLEalpha.toString()); } const Expr& beta = expr1[0]; const Expr& bx = expr1[1]; const Expr& ax = expr2[0]; const Expr& alpha = expr2[1]; Rational a = isMult(ax)? ax[0].getRational() : 1; Rational b = isMult(bx)? bx[0].getRational() : 1; const Expr& x = isMult(ax)? ax[1] : ax; if(CHECK_PROOFS) { // Integrality constraints CHECK_SOUND(isIntPred(isIntAlphaExpr) && isIntAlphaExpr[0] == alpha, "ArithTheoremProducer3::darkGrayShadow2ab:\n " "wrong integrality constraint:\n alpha = " +alpha.toString()+"\n isIntAlpha = " +isIntAlphaExpr.toString()); CHECK_SOUND(isIntPred(isIntBetaExpr) && isIntBetaExpr[0] == beta, "ArithTheoremProducer3::darkGrayShadow2ab:\n " "wrong integrality constraint:\n beta = " +beta.toString()+"\n isIntBeta = " +isIntBetaExpr.toString()); CHECK_SOUND(isIntPred(isIntxExpr) && isIntxExpr[0] == x, "ArithTheoremProducer3::darkGrayShadow2ab:\n " "wrong integrality constraint:\n x = " +x.toString()+"\n isIntx = " +isIntxExpr.toString()); // Expressions ax and bx should match on x CHECK_SOUND(!isMult(ax) || ax.arity() == 2, "ArithTheoremProducer3::darkGrayShadow2ab:\n ax<=alpha: " + axLEalpha.toString()); CHECK_SOUND(!isMult(bx) || (bx.arity() == 2 && bx[1] == x), "ArithTheoremProducer3::darkGrayShadow2ab:\n beta<=bx: " +betaLEbx.toString() +"\n ax<=alpha: "+ axLEalpha.toString()); CHECK_SOUND(1 <= a && a <= b && 2 <= b, "ArithTheoremProducer3::darkGrayShadow2ab:\n beta<=bx: " +betaLEbx.toString() +"\n ax<=alpha: "+ axLEalpha.toString()); } vector thms; thms.push_back(betaLEbx); thms.push_back(axLEalpha); thms.push_back(isIntAlpha); thms.push_back(isIntBeta); thms.push_back(isIntx); Assumptions A(thms); Expr bAlpha = multExpr(rat(b), alpha); Expr aBeta = multExpr(rat(a), beta); Expr t = minusExpr(bAlpha, aBeta); Expr d = darkShadow(rat(a*b-1), t); Expr g = grayShadow(ax, alpha, -a+1, 0); Proof pf; if(withProof()) { vector exprs; exprs.push_back(expr1); exprs.push_back(expr2); exprs.push_back(d); exprs.push_back(g); vector pfs; pfs.push_back(betaLEbx.getProof()); pfs.push_back(axLEalpha.getProof()); pfs.push_back(isIntAlpha.getProof()); pfs.push_back(isIntBeta.getProof()); pfs.push_back(isIntx.getProof()); pf = newPf("dark_grayshadow_2ab", exprs, pfs); } return newTheorem((d || g), A, pf); } // Dark & Gray shadows when b <= a Theorem ArithTheoremProducer3::darkGrayShadow2ba(const Theorem& betaLEbx, const Theorem& axLEalpha, const Theorem& isIntAlpha, const Theorem& isIntBeta, const Theorem& isIntx) { const Expr& expr1 = betaLEbx.getExpr(); const Expr& expr2 = axLEalpha.getExpr(); const Expr& isIntAlphaExpr = isIntAlpha.getExpr(); const Expr& isIntBetaExpr = isIntBeta.getExpr(); const Expr& isIntxExpr = isIntx.getExpr(); if(CHECK_PROOFS) { CHECK_SOUND(isLE(expr1) && isLE(expr2), "ArithTheoremProducer3::darkGrayShadow2ba: Wrong Kind: " + betaLEbx.toString() + axLEalpha.toString()); } const Expr& beta = expr1[0]; const Expr& bx = expr1[1]; const Expr& ax = expr2[0]; const Expr& alpha = expr2[1]; Rational a = isMult(ax)? ax[0].getRational() : 1; Rational b = isMult(bx)? bx[0].getRational() : 1; const Expr& x = isMult(ax)? ax[1] : ax; if(CHECK_PROOFS) { // Integrality constraints CHECK_SOUND(isIntPred(isIntAlphaExpr) && isIntAlphaExpr[0] == alpha, "ArithTheoremProducer3::darkGrayShadow2ab:\n " "wrong integrality constraint:\n alpha = " +alpha.toString()+"\n isIntAlpha = " +isIntAlphaExpr.toString()); CHECK_SOUND(isIntPred(isIntBetaExpr) && isIntBetaExpr[0] == beta, "ArithTheoremProducer3::darkGrayShadow2ab:\n " "wrong integrality constraint:\n beta = " +beta.toString()+"\n isIntBeta = " +isIntBetaExpr.toString()); CHECK_SOUND(isIntPred(isIntxExpr) && isIntxExpr[0] == x, "ArithTheoremProducer3::darkGrayShadow2ab:\n " "wrong integrality constraint:\n x = " +x.toString()+"\n isIntx = " +isIntxExpr.toString()); // Expressions ax and bx should match on x CHECK_SOUND(!isMult(ax) || ax.arity() == 2, "ArithTheoremProducer3::darkGrayShadow2ba:\n ax<=alpha: " + axLEalpha.toString()); CHECK_SOUND(!isMult(bx) || (bx.arity() == 2 && bx[1] == x), "ArithTheoremProducer3::darkGrayShadow2ba:\n beta<=bx: " +betaLEbx.toString() +"\n ax<=alpha: "+ axLEalpha.toString()); CHECK_SOUND(1 <= b && b <= a && 2 <= a, "ArithTheoremProducer3::darkGrayShadow2ba:\n beta<=bx: " +betaLEbx.toString() +"\n ax<=alpha: "+ axLEalpha.toString()); } vector thms; thms.push_back(betaLEbx); thms.push_back(axLEalpha); thms.push_back(isIntAlpha); thms.push_back(isIntBeta); thms.push_back(isIntx); Assumptions A(thms); Proof pf; if(withProof()) { vector pfs; pfs.push_back(betaLEbx.getProof()); pfs.push_back(axLEalpha.getProof()); pfs.push_back(isIntAlpha.getProof()); pfs.push_back(isIntBeta.getProof()); pfs.push_back(isIntx.getProof()); pf = newPf("dark_grayshadow_2ba", betaLEbx.getExpr(), axLEalpha.getExpr(), pfs); } Expr bAlpha = multExpr(rat(b), alpha); Expr aBeta = multExpr(rat(a), beta); Expr t = minusExpr(bAlpha, aBeta); Expr d = darkShadow(rat(a*b-1), t); Expr g = grayShadow(bx, beta, 0, b-1); return newTheorem((d || g), A, pf); } /*! takes a dark shadow and expands it into an inequality. */ Theorem ArithTheoremProducer3::expandDarkShadow(const Theorem& darkShadow) { const Expr& theShadow = darkShadow.getExpr(); if(CHECK_PROOFS){ CHECK_SOUND(isDarkShadow(theShadow), "ArithTheoremProducer3::expandDarkShadow: not DARK_SHADOW: " + theShadow.toString()); } Proof pf; if(withProof()) pf = newPf("expand_dark_shadow", theShadow, darkShadow.getProof()); return newTheorem(leExpr(theShadow[0], theShadow[1]), darkShadow.getAssumptionsRef(), pf); } // takes a grayShadow (c1==c2) and expands it into an equality Theorem ArithTheoremProducer3::expandGrayShadow0(const Theorem& grayShadow) { const Expr& theShadow = grayShadow.getExpr(); if(CHECK_PROOFS) { CHECK_SOUND(isGrayShadow(theShadow), "ArithTheoremProducer3::expandGrayShadowConst0:" " not GRAY_SHADOW: " + theShadow.toString()); CHECK_SOUND(theShadow[2] == theShadow[3], "ArithTheoremProducer3::expandGrayShadow0: c1!=c2: " + theShadow.toString()); } Proof pf; if(withProof()) pf = newPf("expand_gray_shadowconst0", theShadow, grayShadow.getProof()); const Expr& v = theShadow[0]; const Expr& e = theShadow[1]; return newRWTheorem(v, e + theShadow[2], grayShadow.getAssumptionsRef(), pf); } // G ==> (G1 or G2) and (!G1 or !G2), // where G = G(x, e, c1, c2), // G1 = G(x,e,c1,c) // G2 = G(x,e,c+1,c2), // and c = floor((c1+c2)/2) // DEJAN: TRY THE MIDDLE IMMEDIATELY, WE MIGHT GET LUCKY Theorem ArithTheoremProducer3::splitGrayShadow(const Theorem& gThm) { const Expr& theShadow = gThm.getExpr(); if(CHECK_PROOFS) { CHECK_SOUND(isGrayShadow(theShadow), "ArithTheoremProducer3::expandGrayShadowConst: not a shadow" + theShadow.toString()); } const Rational& c1 = theShadow[2].getRational(); const Rational& c2 = theShadow[3].getRational(); if(CHECK_PROOFS) { CHECK_SOUND(c1.isInteger() && c2.isInteger() && c1 < c2, "ArithTheoremProducer3::expandGrayShadow: " + theShadow.toString()); } const Expr& v = theShadow[0]; const Expr& e = theShadow[1]; Proof pf; Rational c(floor((c1+c2) / 2)); Expr g1(grayShadow(v, e, c1, c)); Expr g2(grayShadow(v, e, c+1, c2)); if(withProof()){ vector exprs; exprs.push_back(theShadow); exprs.push_back(g1); exprs.push_back(g2); pf = newPf("split_gray_shadow", exprs, gThm.getProof()); } return newTheorem((g1 || g2) && (!g1 || !g2), gThm.getAssumptionsRef(), pf); } Theorem ArithTheoremProducer3::expandGrayShadow(const Theorem& gThm) { const Expr& theShadow = gThm.getExpr(); if(CHECK_PROOFS) { CHECK_SOUND(isGrayShadow(theShadow), "ArithTheoremProducer3::expandGrayShadowConst: not a shadow" + theShadow.toString()); } const Rational& c1 = theShadow[2].getRational(); const Rational& c2 = theShadow[3].getRational(); if(CHECK_PROOFS) { CHECK_SOUND(c1.isInteger() && c2.isInteger() && c1 < c2, "ArithTheoremProducer3::expandGrayShadow: " + theShadow.toString()); } const Expr& v = theShadow[0]; const Expr& e = theShadow[1]; Proof pf; if(withProof()) pf = newPf("expand_gray_shadow", theShadow, gThm.getProof()); Expr ineq1(leExpr(e+rat(c1), v)); Expr ineq2(leExpr(v, e+rat(c2))); return newTheorem(ineq1 && ineq2, gThm.getAssumptionsRef(), pf); } // Expanding GRAY_SHADOW(a*x, c, b), where c is a constant Theorem ArithTheoremProducer3::expandGrayShadowConst(const Theorem& gThm) { const Expr& theShadow = gThm.getExpr(); const Expr& ax = theShadow[0]; const Expr& cExpr = theShadow[1]; const Expr& bExpr = theShadow[2]; if(CHECK_PROOFS) { CHECK_SOUND(!isMult(ax) || ax[0].isRational(), "ArithTheoremProducer3::expandGrayShadowConst: " "'a' in a*x is not a const: " +theShadow.toString()); } Rational a = isMult(ax)? ax[0].getRational() : 1; if(CHECK_PROOFS) { CHECK_SOUND(isGrayShadow(theShadow), "ArithTheoremProducer3::expandGrayShadowConst: " "not a GRAY_SHADOW: " +theShadow.toString()); CHECK_SOUND(a.isInteger() && a >= 1, "ArithTheoremProducer3::expandGrayShadowConst: " "'a' is not integer: " +theShadow.toString()); CHECK_SOUND(cExpr.isRational(), "ArithTheoremProducer3::expandGrayShadowConst: " "'c' is not rational" +theShadow.toString()); CHECK_SOUND(bExpr.isRational() && bExpr.getRational().isInteger(), "ArithTheoremProducer3::expandGrayShadowConst: b not integer: " +theShadow.toString()); } const Rational& b = bExpr.getRational(); const Rational& c = cExpr.getRational(); Rational j = constRHSGrayShadow(c,b,a); // Compute sign(b)*j(c,b,a) Rational signB = (b>0)? 1 : -1; // |b| (absolute value of b) Rational bAbs = abs(b); const Assumptions& assump(gThm.getAssumptionsRef()); Proof pf; Theorem conc; // Conclusion of the rule if(bAbs < j) { if(withProof()) pf = newPf("expand_gray_shadow_const_0", theShadow, gThm.getProof()); conc = newTheorem(d_em->falseExpr(), assump, pf); } else if(bAbs < a+j) { if(withProof()) pf = newPf("expand_gray_shadow_const_1", theShadow, gThm.getProof()); conc = newRWTheorem(ax, rat(c+b-signB*j), assump, pf); } else { if(withProof()) pf = newPf("expand_gray_shadow_const", theShadow, gThm.getProof()); Expr newGrayShadow(Expr(GRAY_SHADOW, ax, cExpr, rat(b-signB*(a+j)))); conc = newTheorem(ax.eqExpr(rat(c+b-signB*j)).orExpr(newGrayShadow), assump, pf); } return conc; } Theorem ArithTheoremProducer3::grayShadowConst(const Theorem& gThm) { const Expr& g = gThm.getExpr(); bool checkProofs(CHECK_PROOFS); if(checkProofs) { CHECK_SOUND(isGrayShadow(g), "ArithTheoremProducer3::grayShadowConst(" +g.toString()+")"); } const Expr& ax = g[0]; const Expr& e = g[1]; const Rational& c1 = g[2].getRational(); const Rational& c2 = g[3].getRational(); Expr aExpr, x; d_theoryArith->separateMonomial(ax, aExpr, x); if(checkProofs) { CHECK_SOUND(e.isRational() && e.getRational().isInteger(), "ArithTheoremProducer3::grayShadowConst("+g.toString()+")"); CHECK_SOUND(aExpr.isRational(), "ArithTheoremProducer3::grayShadowConst("+g.toString()+")"); } const Rational& a = aExpr.getRational(); const Rational& c = e.getRational(); if(checkProofs) { CHECK_SOUND(a.isInteger() && a >= 2, "ArithTheoremProducer3::grayShadowConst("+g.toString()+")"); } Rational newC1 = ceil((c1+c)/a), newC2 = floor((c2+c)/a); Expr newG((newC1 > newC2)? d_em->falseExpr() : grayShadow(x, rat(0), newC1, newC2)); Proof pf; if(withProof()) pf = newPf("gray_shadow_const", g, newG, gThm.getProof()); return newTheorem(newG, gThm.getAssumptionsRef(), pf); } Rational ArithTheoremProducer3::constRHSGrayShadow(const Rational& c, const Rational& b, const Rational& a) { DebugAssert(c.isInteger() && b.isInteger() && a.isInteger() && b != 0, "ArithTheoremProducer3::constRHSGrayShadow: a, b, c must be ints"); if (b > 0) return mod(c+b, a); else return mod(a-(c+b), a); } /*! Takes a Theorem(\\alpha < \\beta) and returns * Theorem(\\alpha < \\beta <==> \\alpha <= \\beta -1) * where \\alpha and \\beta are integer expressions */ Theorem ArithTheoremProducer3::lessThanToLE(const Theorem& less, const Theorem& isIntLHS, const Theorem& isIntRHS, bool changeRight) { const Expr& ineq = less.getExpr(); const Expr& isIntLHSexpr = isIntLHS.getExpr(); const Expr& isIntRHSexpr = isIntRHS.getExpr(); if(CHECK_PROOFS) { CHECK_SOUND(isLT(ineq), "ArithTheoremProducer3::LTtoLE: ineq must be <"); // Integrality check CHECK_SOUND(isIntPred(isIntLHSexpr) && isIntLHSexpr[0] == ineq[0], "ArithTheoremProducer3::lessThanToLE: bad integrality check:\n" " ineq = "+ineq.toString()+"\n isIntLHS = " +isIntLHSexpr.toString()); CHECK_SOUND(isIntPred(isIntRHSexpr) && isIntRHSexpr[0] == ineq[1], "ArithTheoremProducer3::lessThanToLE: bad integrality check:\n" " ineq = "+ineq.toString()+"\n isIntRHS = " +isIntRHSexpr.toString()); } vector thms; thms.push_back(less); thms.push_back(isIntLHS); thms.push_back(isIntRHS); Assumptions a(thms); Proof pf; Expr le = changeRight? leExpr(ineq[0], ineq[1] + rat(-1)) : leExpr(ineq[0] + rat(1), ineq[1]); if(withProof()) { vector pfs; pfs.push_back(less.getProof()); pfs.push_back(isIntLHS.getProof()); pfs.push_back(isIntRHS.getProof()); pf = newPf(changeRight? "lessThan_To_LE_rhs" : "lessThan_To_LE_lhs", ineq,le, pfs); } return newRWTheorem(ineq, le, a, pf); } /*! \param eqn is an equation 0 = a.x or 0 = c + a.x * \param isIntx is a proof of IS_INTEGER(x) * * \return the theorem 0 = c + a.x <==> x=-c/a if -c/a is int else * return the theorem 0 = c + a.x <==> false. * * It also handles the special case of 0 = a.x <==> x = 0 */ Theorem ArithTheoremProducer3::intVarEqnConst(const Expr& eqn, const Theorem& isIntx) { const Expr& left(eqn[0]); const Expr& right(eqn[1]); const Expr& isIntxexpr(isIntx.getExpr()); if(CHECK_PROOFS) { CHECK_SOUND((isMult(right) && right[0].isRational()) || (right.arity() == 2 && isPlus(right) && right[0].isRational() && ((!isMult(right[1]) || right[1][0].isRational()))), "ArithTheoremProducer3::intVarEqnConst: " "rhs has a wrong format: " + right.toString()); CHECK_SOUND(left.isRational() && 0 == left.getRational(), "ArithTheoremProducer3:intVarEqnConst:left is not a zero: " + left.toString()); } // Integrality constraint Expr x(right); Rational a(1), c(0); if(isMult(right)) { Expr aExpr; d_theoryArith->separateMonomial(right, aExpr, x); a = aExpr.getRational(); } else { // right is a PLUS c = right[0].getRational(); Expr aExpr; d_theoryArith->separateMonomial(right[1], aExpr, x); a = aExpr.getRational(); } if(CHECK_PROOFS) { CHECK_SOUND(isIntPred(isIntxexpr) && isIntxexpr[0] == x, "ArithTheoremProducer3:intVarEqnConst: " "bad integrality constraint:\n right = " + right.toString()+"\n isIntx = "+isIntxexpr.toString()); CHECK_SOUND(a!=0, "ArithTheoremProducer3:intVarEqnConst: eqn = " +eqn.toString()); } const Assumptions& assump(isIntx.getAssumptionsRef()); /* Proof pf; if(withProof()) pf = newPf("int_const_eq", eqn, isIntx.getProof()); // Solve for x: x = r = -c/a Rational r(-c/a); if(r.isInteger()){ return newRWTheorem(eqn, x.eqExpr(rat(r)), assump, pf); else return newRWTheorem(eqn, d_em->falseExpr(), assump, pf); */ Proof pf; // Solve for x: x = r = -c/a Rational r(-c/a); if(r.isInteger()){ if(withProof()) pf = newPf("int_const_eq", eqn, x.eqExpr(rat(r)),isIntx.getProof()); return newRWTheorem(eqn, x.eqExpr(rat(r)), assump, pf); } else{ if(withProof()) pf = newPf("int_const_eq", eqn, d_em->falseExpr(),isIntx.getProof()); return newRWTheorem(eqn, d_em->falseExpr(), assump, pf); } } Expr ArithTheoremProducer3::create_t(const Expr& eqn) { const Expr& lhs = eqn[0]; DebugAssert(isMult(lhs), CLASS_NAME "create_t : lhs must be a MULT" + lhs.toString()); const Expr& x = lhs[1]; Rational m = lhs[0].getRational()+1; DebugAssert(m > 0, "ArithTheoremProducer3::create_t: m = "+m.toString()); vector kids; if(isPlus(eqn[1])) sumModM(kids, eqn[1], m, m); else kids.push_back(monomialModM(eqn[1], m, m)); kids.push_back(multExpr(rat(1/m), x)); return plusExpr(kids); } Expr ArithTheoremProducer3::create_t2(const Expr& lhs, const Expr& rhs, const Expr& sigma) { Rational m = lhs[0].getRational()+1; DebugAssert(m > 0, "ArithTheoremProducer3::create_t2: m = "+m.toString()); vector kids; if(isPlus(rhs)) sumModM(kids, rhs, m, -1); else { kids.push_back(rat(0)); // For canonical form Expr monom = monomialModM(rhs, m, -1); if(!monom.isRational()) kids.push_back(monom); else DebugAssert(monom.getRational() == 0, ""); } kids.push_back(rat(m)*sigma); return plusExpr(kids); } Expr ArithTheoremProducer3::create_t3(const Expr& lhs, const Expr& rhs, const Expr& sigma) { const Rational& a = lhs[0].getRational(); Rational m = a+1; DebugAssert(m > 0, "ArithTheoremProducer3::create_t3: m = "+m.toString()); vector kids; if(isPlus(rhs)) sumMulF(kids, rhs, m, 1); else { kids.push_back(rat(0)); // For canonical form Expr monom = monomialMulF(rhs, m, 1); if(!monom.isRational()) kids.push_back(monom); else DebugAssert(monom.getRational() == 0, ""); } kids.push_back(rat(-a)*sigma); return plusExpr(kids); } Rational ArithTheoremProducer3::modEq(const Rational& i, const Rational& m) { DebugAssert(m > 0, "ArithTheoremProducer3::modEq: m = "+m.toString()); Rational half(1,2); Rational res((i - m*(floor((i/m) + half)))); TRACE("arith eq", "modEq("+i.toString()+", "+m.toString()+") = ", res, ""); return res; } Rational ArithTheoremProducer3::f(const Rational& i, const Rational& m) { DebugAssert(m > 0, "ArithTheoremProducer3::f: m = "+m.toString()); Rational half(1,2); return (floor(i/m + half)+modEq(i,m)); } void ArithTheoremProducer3::sumModM(vector& summands, const Expr& sum, const Rational& m, const Rational& divisor) { DebugAssert(divisor != 0, "ArithTheoremProducer3::sumModM: divisor = " +divisor.toString()); Expr::iterator i = sum.begin(); DebugAssert(i != sum.end(), CLASS_NAME "::sumModM"); Rational C = i->getRational(); C = modEq(C,m)/divisor; summands.push_back(rat(C)); i++; for(Expr::iterator iend=sum.end(); i!=iend; ++i) { Expr monom = monomialModM(*i, m, divisor); if(!monom.isRational()) summands.push_back(monom); else DebugAssert(monom.getRational() == 0, ""); } } Expr ArithTheoremProducer3::monomialModM(const Expr& i, const Rational& m, const Rational& divisor) { DebugAssert(divisor != 0, "ArithTheoremProducer3::monomialModM: divisor = " +divisor.toString()); Expr res; if(isMult(i)) { Rational ai = i[0].getRational(); ai = modEq(ai,m)/divisor; if(0 == ai) res = rat(0); else if(1 == ai && i.arity() == 2) res = i[1]; else { vector kids = i.getKids(); kids[0] = rat(ai); res = multExpr(kids); } } else { // It's a single variable Rational ai = modEq(1,m)/divisor; if(1 == ai) res = i; else res = rat(ai)*i; } DebugAssert(!res.isNull(), "ArithTheoremProducer3::monomialModM()"); TRACE("arith eq", "monomialModM(i="+i.toString()+", m="+m.toString() +", div="+divisor.toString()+") = ", res, ""); return res; } void ArithTheoremProducer3::sumMulF(vector& summands, const Expr& sum, const Rational& m, const Rational& divisor) { DebugAssert(divisor != 0, "ArithTheoremProducer3::sumMulF: divisor = " +divisor.toString()); Expr::iterator i = sum.begin(); DebugAssert(i != sum.end(), CLASS_NAME "::sumModM"); Rational C = i->getRational(); C = f(C,m)/divisor; summands.push_back(rat(C)); i++; for(Expr::iterator iend=sum.end(); i!=iend; ++i) { Expr monom = monomialMulF(*i, m, divisor); if(!monom.isRational()) summands.push_back(monom); else DebugAssert(monom.getRational() == 0, ""); } } Expr ArithTheoremProducer3::monomialMulF(const Expr& i, const Rational& m, const Rational& divisor) { DebugAssert(divisor != 0, "ArithTheoremProducer3::monomialMulF: divisor = " +divisor.toString()); Rational ai = isMult(i) ? (i)[0].getRational() : 1; Expr xi = isMult(i) ? (i)[1] : (i); ai = f(ai,m)/divisor; if(0 == ai) return rat(0); if(1 == ai) return xi; return multExpr(rat(ai), xi); } // This recursive function accepts a term, t, and a 'map' of // substitutions [x1/t1, x2/t2,...,xn/tn]. it returns a t' which is // basically t[x1/t1,x2/t2...xn/tn] Expr ArithTheoremProducer3::substitute(const Expr& term, ExprMap& eMap) { ExprMap::iterator i, iend = eMap.end(); i = eMap.find(term); if(iend != i) return (*i).second; if (isMult(term)) { //in this case term is of the form c.x i = eMap.find(term[1]); if(iend != i) return term[0]*(*i).second; else return term; } if(isPlus(term)) { vector output; for(Expr::iterator j = term.begin(), jend = term.end(); j != jend; ++j) output.push_back(substitute(*j, eMap)); return plusExpr(output); } return term; } bool ArithTheoremProducer3::greaterthan(const Expr & l, const Expr & r) { // DebugAssert(l != r, ""); if (l==r) return false; switch(l.getKind()) { case RATIONAL_EXPR: DebugAssert(!r.isRational(), ""); return true; break; case POW: switch (r.getKind()) { case RATIONAL_EXPR: // TODO: // alternately I could return (not greaterthan(r,l)) return false; break; case POW: // x^n > y^n if x > y // x^n1 > x^n2 if n1 > n2 return ((r[1] < l[1]) || ((r[1]==l[1]) && (r[0].getRational() < l[0].getRational()))); break; case MULT: DebugAssert(r.arity() > 1, ""); DebugAssert((r.arity() > 2) || (r[1] != l), ""); if (r[1] == l) return false; return greaterthan(l, r[1]); break; case PLUS: DebugAssert(false, ""); return true; break; default: // leaf return ((r < l[1]) || ((r == l[1]) && l[0].getRational() > 1)); break; } break; case MULT: DebugAssert(l.arity() > 1, ""); switch (r.getKind()) { case RATIONAL_EXPR: return false; break; case POW: DebugAssert(l.arity() > 1, ""); DebugAssert((l.arity() > 2) || (l[1] != r), ""); // TODO: // alternately return (not greaterthan(r,l) return ((l[1] == r) || greaterthan(l[1], r)); break; case MULT: { DebugAssert(r.arity() > 1, ""); Expr::iterator i = l.begin(); Expr::iterator j = r.begin(); ++i; ++j; for (; i != l.end() && j != r.end(); ++i, ++j) { if (*i == *j) continue; return greaterthan(*i,*j); } DebugAssert(i != l.end() || j != r.end(), ""); if (i == l.end()) { // r is bigger return false; } else { // l is bigger return true; } } break; case PLUS: DebugAssert(false, ""); return true; break; default: // leaf DebugAssert((l.arity() > 2) || (l[1] != r), ""); return ((l[1] == r) || greaterthan(l[1], r)); break; } break; case PLUS: DebugAssert(false, ""); return true; break; default: // leaf switch (r.getKind()) { case RATIONAL_EXPR: return false; break; case POW: return ((r[1] < l) || ((r[1] == l) && (r[0].getRational() < 1))); break; case MULT: DebugAssert(r.arity() > 1, ""); DebugAssert((r.arity() > 2) || (r[1] != l), ""); if (l == r[1]) return false; return greaterthan(l,r[1]); break; case PLUS: DebugAssert(false, ""); return true; break; default: // leaf return (r < l); break; } break; } } /*! IS_INTEGER(x) |= EXISTS (y : INT) y = x * where x is not already known to be an integer. */ Theorem ArithTheoremProducer3::IsIntegerElim(const Theorem& isIntx) { Expr expr = isIntx.getExpr(); if (CHECK_PROOFS) { CHECK_SOUND(expr.getKind() == IS_INTEGER, "Expected IS_INTEGER predicate"); } expr = expr[0]; DebugAssert(!d_theoryArith->isInteger(expr), "Expected non-integer"); Assumptions a(isIntx); Proof pf; if (withProof()) { pf = newPf("isIntElim", isIntx.getProof()); } Expr newVar = d_em->newBoundVarExpr(d_theoryArith->intType()); Expr res = d_em->newClosureExpr(EXISTS, newVar, newVar.eqExpr(expr)); return newTheorem(res, a, pf); } Theorem ArithTheoremProducer3::eqElimIntRule(const Theorem& eqn, const Theorem& isIntx, const vector& isIntVars) { TRACE("arith eq", "eqElimIntRule(", eqn.getExpr(), ") {"); Proof pf; if(CHECK_PROOFS) CHECK_SOUND(eqn.isRewrite(), "ArithTheoremProducer3::eqElimInt: input must be an equation" + eqn.toString()); const Expr& lhs = eqn.getLHS(); const Expr& rhs = eqn.getRHS(); Expr a, x; d_theoryArith->separateMonomial(lhs, a, x); if(CHECK_PROOFS) { // Checking LHS const Expr& isIntxe = isIntx.getExpr(); CHECK_SOUND(isIntPred(isIntxe) && isIntxe[0] == x, "ArithTheoremProducer3::eqElimInt\n eqn = " +eqn.getExpr().toString() +"\n isIntx = "+isIntxe.toString()); CHECK_SOUND(isRational(a) && a.getRational().isInteger() && a.getRational() >= 2, "ArithTheoremProducer3::eqElimInt:\n lhs = "+lhs.toString()); // Checking RHS // It cannot be a division (we don't handle it) CHECK_SOUND(!isDivide(rhs), "ArithTheoremProducer3::eqElimInt:\n rhs = "+rhs.toString()); // If it's a single monomial, then it's the only "variable" if(!isPlus(rhs)) { Expr c, v; d_theoryArith->separateMonomial(rhs, c, v); CHECK_SOUND(isIntVars.size() == 1 && isIntPred(isIntVars[0].getExpr()) && isIntVars[0].getExpr()[0] == v && isRational(c) && c.getRational().isInteger(), "ArithTheoremProducer3::eqElimInt:\n rhs = "+rhs.toString() +"isIntVars.size = "+int2string(isIntVars.size())); } else { // RHS is a plus CHECK_SOUND(isIntVars.size() + 1 == (size_t)rhs.arity(), "ArithTheoremProducer3::eqElimInt: rhs = "+rhs.toString()); // Check the free constant CHECK_SOUND(isRational(rhs[0]) && rhs[0].getRational().isInteger(), "ArithTheoremProducer3::eqElimInt: rhs = "+rhs.toString()); // Check the vars for(size_t i=0, iend=isIntVars.size(); iseparateMonomial(rhs[i+1], c, v); const Expr& isInt(isIntVars[i].getExpr()); CHECK_SOUND(isIntPred(isInt) && isInt[0] == v && isRational(c) && c.getRational().isInteger(), "ArithTheoremProducer3::eqElimInt:\n rhs["+int2string(i+1) +"] = "+rhs[i+1].toString() +"\n isInt = "+isInt.toString()); } } } // Creating a fresh bound variable static int varCount(0); Expr newVar = d_em->newBoundVarExpr("_int_var", int2string(varCount++)); newVar.setType(intType()); Expr t2 = create_t2(lhs, rhs, newVar); Expr t3 = create_t3(lhs, rhs, newVar); vector vars; vars.push_back(newVar); Expr res = d_em->newClosureExpr(EXISTS, vars, x.eqExpr(t2) && rat(0).eqExpr(t3)); vector thms(isIntVars); thms.push_back(isIntx); thms.push_back(eqn); Assumptions assump(thms); if(withProof()) { vector pfs; pfs.push_back(eqn.getProof()); pfs.push_back(isIntx.getProof()); vector::const_iterator i=isIntVars.begin(), iend=isIntVars.end(); for(; i!=iend; ++i) pfs.push_back(i->getProof()); pf = newPf("eq_elim_int", eqn.getExpr(), res, pfs); } Theorem thm(newTheorem(res, assump, pf)); TRACE("arith eq", "eqElimIntRule => ", thm.getExpr(), " }"); return thm; } Theorem ArithTheoremProducer3::isIntConst(const Expr& e) { Proof pf; if(CHECK_PROOFS) { CHECK_SOUND(isIntPred(e) && e[0].isRational(), "ArithTheoremProducer3::isIntConst(e = " +e.toString()+")"); } if(withProof()) pf = newPf("is_int_const", e); bool isInt = e[0].getRational().isInteger(); return newRWTheorem(e, isInt? d_em->trueExpr() : d_em->falseExpr(), Assumptions::emptyAssump(), pf); } Theorem ArithTheoremProducer3::equalLeaves1(const Theorem& thm) { Proof pf; const Expr& e = thm.getRHS(); if (CHECK_PROOFS) { CHECK_SOUND(e[1].getKind() == RATIONAL_EXPR && e[1].getRational() == Rational(0) && e[0].getKind() == PLUS && e[0].arity() == 3 && e[0][0].getKind() == RATIONAL_EXPR && e[0][0].getRational() == Rational(0) && e[0][1].getKind() == MULT && e[0][1].arity() == 2 && e[0][1][0].getKind() == RATIONAL_EXPR && e[0][1][0].getRational() == Rational(-1), "equalLeaves1"); } if (withProof()) { vector pfs; pfs.push_back(thm.getProof()); pf = newPf("equalLeaves1", e, pfs); } return newRWTheorem(e, e[0][1][1].eqExpr(e[0][2]), thm.getAssumptionsRef(), pf); } Theorem ArithTheoremProducer3::equalLeaves2(const Theorem& thm) { Proof pf; const Expr& e = thm.getRHS(); if (CHECK_PROOFS) { CHECK_SOUND(e[0].getKind() == RATIONAL_EXPR && e[0].getRational() == Rational(0) && e[1].getKind() == PLUS && e[1].arity() == 3 && e[1][0].getKind() == RATIONAL_EXPR && e[1][0].getRational() == Rational(0) && e[1][1].getKind() == MULT && e[1][1].arity() == 2 && e[1][1][0].getKind() == RATIONAL_EXPR && e[1][1][0].getRational() == Rational(-1), "equalLeaves2"); } if (withProof()) { vector pfs; pfs.push_back(thm.getProof()); pf = newPf("equalLeaves2", e, pfs); } return newRWTheorem(e, e[1][1][1].eqExpr(e[1][2]), thm.getAssumptionsRef(), pf); } Theorem ArithTheoremProducer3::equalLeaves3(const Theorem& thm) { Proof pf; const Expr& e = thm.getRHS(); if (CHECK_PROOFS) { CHECK_SOUND(e[1].getKind() == RATIONAL_EXPR && e[1].getRational() == Rational(0) && e[0].getKind() == PLUS && e[0].arity() == 3 && e[0][0].getKind() == RATIONAL_EXPR && e[0][0].getRational() == Rational(0) && e[0][2].getKind() == MULT && e[0][2].arity() == 2 && e[0][2][0].getKind() == RATIONAL_EXPR && e[0][2][0].getRational() == Rational(-1), "equalLeaves3"); } if (withProof()) { vector pfs; pfs.push_back(thm.getProof()); pf = newPf("equalLeaves3", e, pfs); } return newRWTheorem(e, e[0][2][1].eqExpr(e[0][1]), thm.getAssumptionsRef(), pf); } Theorem ArithTheoremProducer3::equalLeaves4(const Theorem& thm) { Proof pf; const Expr& e = thm.getRHS(); if (CHECK_PROOFS) { CHECK_SOUND(e[0].getKind() == RATIONAL_EXPR && e[0].getRational() == Rational(0) && e[1].getKind() == PLUS && e[1].arity() == 3 && e[1][0].getKind() == RATIONAL_EXPR && e[1][0].getRational() == Rational(0) && e[1][2].getKind() == MULT && e[1][2].arity() == 2 && e[1][2][0].getKind() == RATIONAL_EXPR && e[1][2][0].getRational() == Rational(-1), "equalLeaves4"); } if (withProof()) { vector pfs; pfs.push_back(thm.getProof()); pf = newPf("equalLeaves4", e, pfs); } return newRWTheorem(e, e[1][2][1].eqExpr(e[1][1]), thm.getAssumptionsRef(), pf); } Theorem ArithTheoremProducer3::diseqToIneq(const Theorem& diseq) { Proof pf; const Expr& e = diseq.getExpr(); if(CHECK_PROOFS) { CHECK_SOUND(e.isNot() && e[0].isEq(), "ArithTheoremProducer3::diseqToIneq: expected disequality:\n" " e = "+e.toString()); } const Expr& x = e[0][0]; const Expr& y = e[0][1]; if(withProof()) pf = newPf(e, diseq.getProof()); return newTheorem(ltExpr(x,y).orExpr(gtExpr(x,y)), diseq.getAssumptionsRef(), pf); } Theorem ArithTheoremProducer3::dummyTheorem(const Expr& e) { Proof pf; return newRWTheorem(e, d_em->trueExpr(), Assumptions::emptyAssump(), pf); } Theorem ArithTheoremProducer3::oneElimination(const Expr& e) { // Check soundness if (CHECK_PROOFS) CHECK_SOUND(isMult(e) && e.arity() == 2 && e[0].isRational() && e[0].getRational() == 1, "oneElimination: input must be a multiplication by one" + e.toString()); // The proof object that we will us Proof pf; // Setup the proof if needed if (withProof()) pf = newPf("oneElimination", e); // Return the rewrite theorem that explains the phenomenon return newRWTheorem(e, e[1], Assumptions::emptyAssump(), pf); } Theorem ArithTheoremProducer3::clashingBounds(const Theorem& lowerBound, const Theorem& upperBound) { // Get the expressions const Expr& lowerBoundExpr = lowerBound.getExpr(); const Expr& upperBoundExpr = upperBound.getExpr(); // Check soundness if (CHECK_PROOFS) { CHECK_SOUND(isLE(lowerBoundExpr) || isLT(lowerBoundExpr), "clashingBounds: lowerBound should be >= or > " + lowerBoundExpr.toString()); CHECK_SOUND(isGE(upperBoundExpr) || isGT(upperBoundExpr), "clashingBounds: upperBound should be <= or < " + upperBoundExpr.toString()); CHECK_SOUND(lowerBoundExpr[0].isRational(), "clashingBounds: lowerBound left side should be a rational " + lowerBoundExpr.toString()); CHECK_SOUND(upperBoundExpr[0].isRational(), "clashingBounds: upperBound left side should be a rational " + upperBoundExpr.toString()); CHECK_SOUND(lowerBoundExpr[1] == upperBoundExpr[1], "clashingBounds: bounds not on the same term " + lowerBoundExpr.toString() + ", " + upperBoundExpr.toString()); // Get the bounds Rational lowerBoundR = lowerBoundExpr[0].getRational(); Rational upperBoundR = upperBoundExpr[0].getRational(); if (isLE(lowerBoundExpr) && isGE(upperBoundExpr)) { CHECK_SOUND(upperBoundR < lowerBoundR, "clashingBounds: bounds are satisfiable"); } else { CHECK_SOUND(upperBoundR <= lowerBoundR, "clashingBounds: bounds are satisfiable"); } } // The proof object that we will use Proof pf; // Setup the proof if needed if (withProof()) pf = newPf("clashingBounds", lowerBoundExpr, upperBoundExpr); // Put the bounds expressions in the assumptions Assumptions assumptions; assumptions.add(lowerBound); assumptions.add(upperBound); // Return the theorem return newTheorem(d_em->falseExpr(), assumptions, pf); } Theorem ArithTheoremProducer3::addInequalities(const Theorem& thm1, const Theorem& thm2) { // Get the expressions of the theorem const Expr& expr1 = thm1.getExpr(); const Expr& expr2 = thm2.getExpr(); // Check soundness if (CHECK_PROOFS) { CHECK_SOUND(isIneq(expr1), "addInequalities: expecting an inequality for thm1, got " + expr1.toString()); CHECK_SOUND(isIneq(expr2), "addInequalities: expecting an inequality for thm2, got " + expr2.toString()); if (isLE(expr1) || isLT(expr1)) CHECK_SOUND(isLE(expr2) || isLT(expr2), "addInequalities: expr2 should be <(=) also " + expr2.toString()); if (isGE(expr1) || isGT(expr1)) CHECK_SOUND(isGE(expr2) || isGT(expr2), "addInequalities: expr2 should be >(=) also" + expr2.toString()); } // Create the assumptions Assumptions a(thm1, thm2); // Get the kinds of the inequalitites int kind1 = expr1.getKind(); int kind2 = expr2.getKind(); // Set-up the resulting inequality int kind = (kind1 == kind2) ? kind1 : ((kind1 == LT) || (kind2 == LT))? LT : GT; // Create the proof object Proof pf; if(withProof()) { vector pfs; pfs.push_back(thm1.getProof()); pfs.push_back(thm2.getProof()); pf = newPf("addInequalities", expr1, expr2, pfs); } // Create the new expressions Expr leftSide = plusExpr(expr1[0], expr2[0]); Expr rightSide = plusExpr(expr1[1], expr2[1]); // Return the theorem return newTheorem(Expr(kind, leftSide, rightSide), a, pf); } Theorem ArithTheoremProducer3::implyWeakerInequality(const Expr& expr1, const Expr& expr2) { // Check soundness if (CHECK_PROOFS) { // Both must be inequalitites CHECK_SOUND(isIneq(expr1), "implyWeakerInequality: expr1 should be an inequality" + expr1.toString()); CHECK_SOUND(isIneq(expr2), "implyWeakerInequality: expr1 should be an inequality" + expr2.toString()); // Should be of the same type if (isLE(expr1) || isLT(expr1)) CHECK_SOUND(isLE(expr2) || isLT(expr2), "implyWeakerInequality: expr2 should be <(=) also " + expr2.toString()); if (isGE(expr1) || isGT(expr1)) CHECK_SOUND(isGE(expr2) || isGT(expr2), "implyWeakerInequality: expr2 should be >(=) also" + expr2.toString()); // Left sides must be rational numbers CHECK_SOUND(expr1[0].isRational(), "implyWeakerInequality: expr1 should have a rational on the left side" + expr1.toString()); CHECK_SOUND(expr2[0].isRational(), "implyWeakerInequality: expr2 should have a rational on the left side" + expr2.toString()); // Right sides must be identical CHECK_SOUND(expr1[1] == expr2[1], "implyWeakerInequality: the expression must be the same" + expr1.toString() + " and " + expr2.toString()); Rational expr1rat = expr1[0].getRational(); Rational expr2rat = expr2[0].getRational(); // Check the bounds if (isLE(expr1) || isLT(expr2)) { CHECK_SOUND(expr2rat < expr1rat, "implyWeakerInequality: the implication doesn't apply" + expr1.toString() + " and " + expr2.toString()); } else { CHECK_SOUND(expr2rat <= expr1rat, "implyWeakerInequality: the implication doesn't apply" + expr1.toString() + " and " + expr2.toString()); } if (isGE(expr1) || isGT(expr2)) { CHECK_SOUND(expr2rat > expr1rat, "implyWeakerInequality: the implication doesn't apply" + expr1.toString() + " and " + expr2.toString()); } else { CHECK_SOUND(expr2rat >= expr1rat, "implyWeakerInequality: the implication doesn't apply" + expr1.toString() + " and " + expr2.toString()); } } // Create the proof object Proof pf; if(withProof()) pf = newPf("implyWeakerInequality", expr1, expr2); // Return the theorem return newTheorem(expr1.impExpr(expr2), Assumptions::emptyAssump(), pf); } Theorem ArithTheoremProducer3::implyNegatedInequality(const Expr& expr1, const Expr& expr2) { // Check soundness if (CHECK_PROOFS) { CHECK_SOUND(isIneq(expr1), "implyNegatedInequality: lowerBound should be an inequality " + expr1.toString()); CHECK_SOUND(isIneq(expr2), "implyNegatedInequality: upperBound should be be an inequality " + expr2.toString()); CHECK_SOUND(expr1[0].isRational(), "implyNegatedInequality: lowerBound left side should be a rational " + expr1.toString()); CHECK_SOUND(expr2[0].isRational(), "implyNegatedInequality: upperBound left side should be a rational " + expr2.toString()); CHECK_SOUND(expr1[1] == expr2[1], "implyNegatedInequality: bounds not on the same term " + expr1.toString() + ", " + expr2.toString()); // Get the bounds Rational lowerBoundR = expr1[0].getRational(); Rational upperBoundR = expr2[0].getRational(); if (isLE(expr1) && isGE(expr2)) CHECK_SOUND(upperBoundR < lowerBoundR, "implyNegatedInequality: cant imply negation" + expr1.toString() + ", " + expr2.toString()); if (isLT(expr1) || isGT(expr2)) CHECK_SOUND(upperBoundR <= lowerBoundR, "implyNegatedInequality: cant imply negation" + expr1.toString() + ", " + expr2.toString()); if (isGE(expr1) && isLE(expr2)) CHECK_SOUND(upperBoundR > lowerBoundR, "implyNegatedInequality: cant imply negation" + expr1.toString() + ", " + expr2.toString()); if (isGT(expr1) || isLT(expr2)) CHECK_SOUND(upperBoundR >= lowerBoundR, "implyNegatedInequality: cant imply negation" + expr1.toString() + ", " + expr2.toString()); } // The proof object that we will use Proof pf; if (withProof()) pf = newPf("implyNegatedInequality", expr1, expr2); // Return the theorem return newTheorem(expr1.impExpr(expr2.negate()), Assumptions::emptyAssump(), pf); } Theorem ArithTheoremProducer3::trustedRewrite(const Expr& expr1, const Expr& expr2) { // The proof object that we will us Proof pf; // Setup the proof if needed if (withProof()) pf = newPf("trustedRewrite", expr1, expr2); // Return the rewrite theorem that explains the phenomenon return newRWTheorem(expr1, expr2, Assumptions::emptyAssump(), pf); } Theorem ArithTheoremProducer3::integerSplit(const Expr& intVar, const Rational& intPoint) { // Check soundness if (CHECK_PROOFS) { CHECK_SOUND(intPoint.isInteger(), "integerSplit: we can only split on integer points, given" + intPoint.toString()); } // Create the expression const Expr& split = Expr(IS_INTEGER, intVar).impExpr(leExpr(intVar, rat(intPoint)).orExpr(geExpr(intVar, rat(intPoint + 1)))); // The proof object that we will use Proof pf; if (withProof()) pf = newPf("integerSplit", intVar, rat(intPoint)); // Return the theorem return newTheorem(split, Assumptions::emptyAssump(), pf); } Theorem ArithTheoremProducer3::rafineStrictInteger(const Theorem& isIntConstrThm, const Expr& constr) { // Check soundness if (CHECK_PROOFS) { // Right side of the constraint should correspond to the proved integer expression CHECK_SOUND(isIneq(constr), "rafineStrictInteger: expected a constraint got : " + constr.toString()); CHECK_SOUND(isIntConstrThm.getExpr()[0] == constr[1], "rafineStrictInteger: proof of intger doesn't correspond to the constarint right side"); CHECK_SOUND(constr[0].isRational(), "rafineStrictInteger: right side of the constraint muts be a rational"); } // Get the contraint bound Rational bound = constr[0].getRational(); // Get the kind of the constraint int kind = constr.getKind(); // If the bound is strict, make it non-strict switch (kind) { case LT: kind = LE; if (bound.isInteger()) bound ++; // 3 < x --> 4 <= x else bound = ceil(bound); // 3.4 < x --> 4 <= x break; case LE: kind = LE; if (!bound.isInteger()) bound = ceil(bound); // 3.5 <= x --> 4 <= x break; case GT: kind = GE; if (bound.isInteger()) bound --; // 3 > x --> 2 >= x else bound = floor(bound); // 3.4 > x --> 3 >= x break; case GE: kind = GE; if (!bound.isInteger()) bound = floor(bound); // 3.4 >= x --> 3 >= x break; } // The new constraint Expr newConstr(kind, rat(bound), constr[1]); // Pick up the assumptions from the integer proof const Assumptions& assump(isIntConstrThm.getAssumptionsRef()); // Construct the proof object if necessary Proof pf; if (withProof()) pf = newPf("rafineStrictInteger", constr, isIntConstrThm.getProof()); // Return the rewrite theorem that explains the phenomenon return newRWTheorem(constr, newConstr, assump, pf); } Theorem ArithTheoremProducer3::splitGrayShadowSmall(const Theorem& gThm) { DebugAssert(false, "Not implemented!!!"); return Theorem(); } Theorem ArithTheoremProducer3::implyWeakerInequalityDiffLogic(const std::vector& antecedentThms, const Expr& implied) { DebugAssert(false, "Not implemented!!!"); return Theorem(); } Theorem ArithTheoremProducer3::implyNegatedInequalityDiffLogic(const std::vector& antecedentThms, const Expr& implied) { DebugAssert(false, "Not implemented!!!"); return Theorem(); } Theorem ArithTheoremProducer3::expandGrayShadowRewrite(const Expr& theShadow) { DebugAssert(false, "Not implemented!!!"); return Theorem(); } Theorem ArithTheoremProducer3::compactNonLinearTerm(const Expr& nonLinear) { DebugAssert(false, "Not implemented!!!"); return Theorem(); } Theorem ArithTheoremProducer3::nonLinearIneqSignSplit(const Theorem& ineqThm) { DebugAssert(false, "Not implemented!!!"); return Theorem(); } Theorem ArithTheoremProducer3::implyDiffLogicBothBounds(const Expr& x, std::vector& c1_le_x, Rational c1, std::vector& x_le_c2, Rational c2) { DebugAssert(false, "Not implemented!!!"); return Theorem(); } Theorem ArithTheoremProducer3::addInequalities(const vector& thms) { DebugAssert(false, "Not implemented!!!"); return Theorem(); } Theorem ArithTheoremProducer3::powerOfOne(const Expr& e) { DebugAssert(false, "Not implemented!!!"); return Theorem(); } // // This one is here just to compile... the code is in old arithmetic Theorem ArithTheoremProducer3::simpleIneqInt(const Expr& ineq, const Theorem& isIntRHS) { DebugAssert(false, "Not implemented!!!"); return Theorem(); } // Given: // 0 = c + t // where t is integer and c is not // deduce bot Theorem ArithTheoremProducer3::intEqualityRationalConstant(const Theorem& isIntConstrThm, const Expr& constr) { DebugAssert(false, "Not implemented!!!"); return Theorem(); } Theorem ArithTheoremProducer3::cycleConflict(const vector& inequalitites) { DebugAssert(false, "Not implemented!!!"); return Theorem(); } Theorem ArithTheoremProducer3::implyEqualities(const vector& inequalitites) { DebugAssert(false, "Not implemented!!!"); return Theorem(); } /*! Takes a Theorem(\\alpha < \\beta) and returns * Theorem(\\alpha < \\beta <==> \\alpha <= \\beta -1) * where \\alpha and \\beta are integer expressions */ Theorem ArithTheoremProducer3::lessThanToLERewrite(const Expr& ineq, const Theorem& isIntLHS, const Theorem& isIntRHS, bool changeRight) { const Expr& isIntLHSexpr = isIntLHS.getExpr(); const Expr& isIntRHSexpr = isIntRHS.getExpr(); if(CHECK_PROOFS) { CHECK_SOUND(isLT(ineq), "ArithTheoremProducerOld::LTtoLE: ineq must be <"); // Integrality check CHECK_SOUND(isIntPred(isIntLHSexpr) && isIntLHSexpr[0] == ineq[0], "ArithTheoremProducerOld::lessThanToLE: bad integrality check:\n" " ineq = "+ineq.toString()+"\n isIntLHS = " +isIntLHSexpr.toString()); CHECK_SOUND(isIntPred(isIntRHSexpr) && isIntRHSexpr[0] == ineq[1], "ArithTheoremProducerOld::lessThanToLE: bad integrality check:\n" " ineq = "+ineq.toString()+"\n isIntRHS = " +isIntRHSexpr.toString()); } vector thms; thms.push_back(isIntLHS); thms.push_back(isIntRHS); Assumptions a(thms); Proof pf; Expr le = changeRight? leExpr(ineq[0], ineq[1] + rat(-1)) : leExpr(ineq[0] + rat(1), ineq[1]); if(withProof()) { vector pfs; pfs.push_back(isIntLHS.getProof()); pfs.push_back(isIntRHS.getProof()); pf = newPf(changeRight? "lessThan_To_LE_rhs" : "lessThan_To_LE_lhs", le, pfs); } return newRWTheorem(ineq, le, a, pf); } cvc3-2.4.1/src/theory_arith/theory_arith_new.cpp0000664000175400017540000041061111410616733021631 0ustar mdetersmdeters/*****************************************************************************/ /*! * \file theory_arith_new.cpp * * Author: Dejan Jovanovic * * Created: Thu Jun 14 13:42:00 2007 * *
* * License to use, copy, modify, sell and/or distribute this software * and its documentation for any purpose is hereby granted without * royalty, subject to the terms and conditions defined in the \ref * LICENSE file provided with this distribution. * *
* */ /*****************************************************************************/ #include "theory_arith_new.h" #include "arith_proof_rules.h" //#include "arith_expr.h" #include "arith_exception.h" #include "typecheck_exception.h" #include "eval_exception.h" #include "parser_exception.h" #include "smtlib_exception.h" #include "theory_core.h" #include "command_line_flags.h" using namespace std; using namespace CVC3; /////////////////////////////////////////////////////////////////////////////// // TheoryArithNew::FreeConst Methods // /////////////////////////////////////////////////////////////////////////////// namespace CVC3 { ostream& operator<<(ostream& os, const TheoryArithNew::FreeConst& fc) { os << "FreeConst(r=" << fc.getConst() << ", " << (fc.strict()? "strict" : "non-strict") << ")"; return os; } /////////////////////////////////////////////////////////////////////////////// // TheoryArithNew::Ineq Methods // /////////////////////////////////////////////////////////////////////////////// ostream& operator<<(ostream& os, const TheoryArithNew::Ineq& ineq) { os << "Ineq(" << ineq.ineq().getExpr() << ", isolated on " << (ineq.varOnRHS()? "RHS" : "LHS") << ", const = " << ineq.getConst() << ")"; return os; } } // End of namespace CVC3 /////////////////////////////////////////////////////////////////////////////// // TheoryArithNew Private Methods // /////////////////////////////////////////////////////////////////////////////// Theorem TheoryArithNew::isIntegerThm(const Expr& e) { // Quick check if(isReal(e.getType())) return Theorem(); // Try harder return isIntegerDerive(Expr(IS_INTEGER, e), typePred(e)); } Theorem TheoryArithNew::isIntegerDerive(const Expr& isIntE, const Theorem& thm) { const Expr& e = thm.getExpr(); // We found it! if(e == isIntE) return thm; Theorem res; // If the theorem is an AND, look inside each child if(e.isAnd()) { int i, iend=e.arity(); for(i=0; iandElim(thm, i)); if(!res.isNull()) return res; } } return res; } bool TheoryArithNew::kidsCanonical(const Expr& e) { if(isLeaf(e)) return true; bool res(true); for(int i=0; res && iuMinusToMult(e[0]); // Get the resulting epression Expr e2 = result.getRHS(); // Canonise the resulting expression and combine the theorems result = transitivityRule(result, canon(e2)); // UMINUS case break break; } // e[0] + e[1] case PLUS: // Call the canonPlus procedure to canonise + result = d_rules->canonPlus(e); // PLUS case break break; // e[0] - e[1] case MINUS: { // Arity of the minus should be exactly 2 (TODO: looks useless, maybe remove) DebugAssert(e.arity() == 2," "); // This produces e[0] + (-1)*e[1], we have to canonize it in 2 steps Theorem minus_eq_sum = d_rules->minusToPlus(e[0], e[1]); // The resulting sum expression Expr sum(minus_eq_sum.getRHS()); // Canonise the sum[1] Theorem thm(canon(sum[1])); // If the sum[1] sayed the same, canonise the sum expression if(thm.getLHS() == thm.getRHS()) result = canonThm(minus_eq_sum); // The sum changed; do the work else { // Substitute and try to canonise again Theorem sum_eq_canon = canonThm(substitutivityRule(sum, 1, thm)); // Combine the results, and thats it result = transitivityRule(minus_eq_sum, sum_eq_canon); } // MINUS case break break; } // e[0] * e[1] case MULT: // Canonise using the canonMult() proof rule result = d_rules->canonMult(e); // MULT case break break; // e[0] DIV e[1] case DIVIDE: { // Division by 0 is OK (total extension, protected by TCCs) // if (e[1].isRational() && e[1].getRational() == 0) // throw ArithException("Divide by 0 error in "+e.toString()); if (e[1].getKind() == PLUS) throw ArithException("Divide by a PLUS expression not handled in" + e.toString()); // Canonise the divite using canonDivide() method result = d_rules->canonDivide(e); // DIVIDE case break break; } // e[0]^e[1] case POW : // If we are raising to a constant rational call canonPowConst() proof rule if(e[1].isRational()) result = d_rules->canonPowConst(e); // Othervise just return the same expression else result = reflexivityRule(e); // POW case break break; default: // How did we get here (TODO: check if need to throw and exception), anyhow, just return the reflexivity rule result = reflexivityRule(e); // Default break break; } // Finished with the canonisation, trace the result in the debug version TRACE("arith","canon => ",result," }"); // Return the resulting theorem return result; } Theorem TheoryArithNew::canonSimplify(const Expr& e) { // Trace the function on the arith trace flag TRACE("arith", "canonSimplify(", e, ") {"); // Assert that all the kids must be already canonical //DebugAssert(kidsCanonical(e), "TheoryArithNew::canonSimplify("+e.toString()+")"); // Assert that all the leaves must be simplified //DebugAssert(leavesAreSimp(e), "Expected leaves to be simplified"); // Make a copy of the expression Expr tmp(e); // Canonise the expresion Theorem thm = canon(e); // If the new simplified expression has a find, use it (TODO: Check whats going on here) if(thm.getRHS().hasFind()) thm = transitivityRule(thm, find(thm.getRHS())); // We shouldn't rely on simplification in this function anymore DebugAssert(thm.getRHS() == simplifyExpr(thm.getRHS()), "canonSimplify("+e.toString()+")\n"+"canon(e) = "+thm.getRHS().toString()+"\nsimplify(canon(e)) = "+simplifyExpr(thm.getRHS()).toString()); // Trace the resulting theorem TRACE("arith", "canonSimplify =>", thm, " }"); // Return the theorem return thm; } /*! accepts a theorem, canonizes it, applies iffMP and substituvity to * derive the canonized thm */ Theorem TheoryArithNew::canonPred(const Theorem& thm) { vector thms; DebugAssert(thm.getExpr().arity() == 2, "TheoryArithNew::canonPred: bad theorem: "+thm.toString()); Expr e(thm.getExpr()); thms.push_back(canonSimplify(e[0])); thms.push_back(canonSimplify(e[1])); return iffMP(thm, substitutivityRule(e.getOp(), thms)); } /** * Accepts an equivalence theorem, canonizes the subexpressions, applies transitivity and substituvity to derive the canonized theorem. * * @param thm equivalence theorem * @return the canonised expression theorem */ Theorem TheoryArithNew::canonPredEquiv(const Theorem& thm) { vector thms; // Vector to hold the simplified versions of e[0] and e[1] // Arity of the expression should be 2 DebugAssert(thm.getRHS().arity() == 2, "TheoryArithNew::canonPredEquiv: bad theorem: " + thm.toString()); // Get the expression of the theorem Expr e(thm.getRHS()); // Simplify both sides of the equivalence thms.push_back(canonSimplify(e[0])); thms.push_back(canonSimplify(e[1])); // Return the theorem substituting e[0] and e[1] with their simplified versions return transitivityRule(thm, substitutivityRule(e.getOp(), thms)); } /*! accepts an equivalence theorem whose RHS is a conjunction, * canonizes it, applies iffMP and substituvity to derive the * canonized thm */ Theorem TheoryArithNew::canonConjunctionEquiv(const Theorem& thm) { vector thms; return thm; } /*! Pseudo-code for doSolve. (Input is an equation) (output is a Theorem) * -# translate e to the form e' = 0 * -# if (e'.isRational()) then {if e' != 0 return false else true} * -# a for loop checks if all the variables are integers. * - if not isolate a suitable real variable and call processRealEq(). * - if all variables are integers then isolate suitable variable * and call processIntEq(). */ Theorem TheoryArithNew::doSolve(const Theorem& thm) { const Expr& e = thm.getExpr(); TRACE("arith eq","doSolve(",e,") {"); DebugAssert(thm.isRewrite(), "thm = "+thm.toString()); Theorem eqnThm; vector thms; // Move LHS to the RHS, if necessary if(e[0].isRational() && e[0].getRational() == 0) eqnThm = thm; else { eqnThm = iffMP(thm, d_rules->rightMinusLeft(e)); eqnThm = canonPred(eqnThm); } // eqnThm is of the form 0 = e' // 'right' is of the form e' Expr right = eqnThm.getRHS(); // Check for trivial equation if (right.isRational()) { Theorem result = iffMP(eqnThm, d_rules->constPredicate(eqnThm.getExpr())); TRACE("arith eq","doSolve => ",result," }"); return result; } //normalize eqnThm = iffMP(eqnThm, normalize(eqnThm.getExpr())); right = eqnThm.getRHS(); //eqn is of the form 0 = e' and is normalized where 'right' denotes e' //FIXME: change processRealEq to accept equations as well instead of theorems if(!isInteger(right)) { Theorem res; try { res = processRealEq(eqnThm); } catch(ArithException& e) { res = symmetryRule(eqnThm); // Flip to e' = 0 TRACE("arith eq", "doSolve: failed to solve an equation: ", e, ""); IF_DEBUG(debugger.counter("FAILED to solve real equalities")++;) setIncomplete("Non-linear arithmetic inequalities"); } IF_DEBUG(debugger.counter("solved real equalities")++;) TRACE("arith eq", "doSolve [real] => ", res, " }"); return res; } else { Theorem res = processIntEq(eqnThm); IF_DEBUG(debugger.counter("solved int equalities")++;) TRACE("arith eq", "doSolve [int] => ", res, " }"); return res; } } /*! pick a monomial for the input equation. This function is used only * if the equation is an integer equation. Choose the monomial with * the smallest absolute value of coefficient. */ Expr TheoryArithNew::pickIntEqMonomial(const Expr& right) { DebugAssert(isPlus(right) && right.arity() > 2, "TheoryArithNew::pickIntEqMonomial right is wrong :-): " + right.toString()); DebugAssert(right[0].isRational(), "TheoryArithNew::pickIntEqMonomial. right[0] must be const" + right.toString()); DebugAssert(isInteger(right), "TheoryArithNew::pickIntEqMonomial: right is of type int: " + right.toString()); //right is of the form "C + a1x1 + ... + anxn". min is initialized //to a1 Expr::iterator i = right.begin(); i++; //skip 'C' Rational min = isMult(*i) ? abs((*i)[0].getRational()) : 1; Expr pickedMon = *i; for(Expr::iterator iend = right.end(); i != iend; ++i) { Rational coeff = isMult(*i) ? abs((*i)[0].getRational()) : 1; if(min > coeff) { min = coeff; pickedMon = *i; } } return pickedMon; } /*! input is e1=e2<==>0=e' Theorem and some of the vars in e' are of * type REAL. isolate one of them and send back to framework. output * is "e1=e2 <==> var = e''" Theorem. */ Theorem TheoryArithNew::processRealEq(const Theorem& eqn) { Expr right = eqn.getRHS(); // Find variable to isolate and store it in left. Pick the largest // (according to the total ordering) variable. FIXME: change from // total ordering to the ordering we devised for inequalities. // TODO: I have to pick a variable that appears as a variable in the // term but does not appear as a variable anywhere else. The variable // must appear as a single leaf and not in a MULT expression with some // other variables and nor in a POW expression. bool found = false; Expr left; if (isPlus(right)) { for(int i = right.arity()-1; i>=0; --i) { Expr c = right[i]; if(isRational(c)) continue; if(!isInteger(c)) { if (isLeaf(c) || ((isMult(c) && c.arity() == 2 && isLeaf(c[1])))) { int numoccurs = 0; Expr leaf = isLeaf(c) ? c : c[1]; for (int j = 0; j < right.arity(); ++j) { if (j!= i && isLeafIn(leaf, right[j]) // && leaf.subExprOf(right[j]) ) { numoccurs++; break; } } if (!numoccurs) { left = c; found = true; break; } } } } } else if ((isMult(right) && right.arity() == 2 && isLeaf(right[1])) || isLeaf(right)) { left = right; found = true; } if (!found) { // TODO: // throw an arithmetic exception that this cannot be done. throw ArithException("Can't find a leaf for solve in "+eqn.toString()); } Rational r = -1; if (isMult(left)) { DebugAssert(left.arity() == 2, "only leaf should be chosen as lhs"); DebugAssert(left[0].getRational() != 0, "left = "+left.toString()); r = -1/left[0].getRational(); left = left[1]; } DebugAssert(isReal(getBaseType(left)) && !isInteger(left), "TheoryArithNew::ProcessRealEq: left is integer:\n left = " +left.toString()); // Normalize equation so that coefficient of the monomial // corresponding to "left" in eqn[1] is -1 Theorem result(iffMP(eqn, d_rules->multEqn(eqn.getLHS(), eqn.getRHS(), rat(r)))); result = canonPred(result); // Isolate left result = iffMP(result, d_rules->plusPredicate(result.getLHS(), result.getRHS(), left, EQ)); result = canonPred(result); TRACE("arith","processRealEq => ",result," }"); return result; } /*! * \param eqn is a single equation 0 = e * \return an equivalent Theorem (x = t AND 0 = e'), or just x = t */ Theorem TheoryArithNew::processSimpleIntEq(const Theorem& eqn) { TRACE("arith eq", "processSimpleIntEq(", eqn.getExpr(), ") {"); DebugAssert(eqn.isRewrite(), "TheoryArithNew::processSimpleIntEq: eqn must be equality" + eqn.getExpr().toString()); Expr right = eqn.getRHS(); DebugAssert(eqn.getLHS().isRational() && 0 == eqn.getLHS().getRational(), "TheoryArithNew::processSimpleIntEq: LHS must be 0:\n" + eqn.getExpr().toString()); //recall that 0 = c case is already handled in doSolve() function. if(isMult(right)) { //here we take care of special case 0=c.x Expr c,x; separateMonomial(right, c, x); Theorem isIntx(isIntegerThm(x)); DebugAssert(!isIntx.isNull(), "right = "+right.toString()); Theorem res(iffMP(eqn, d_rules->intVarEqnConst(eqn.getExpr(), isIntx))); TRACE("arith eq", "processSimpleIntEq[0 = a*x] => ", res, " }"); return res; } else if(isPlus(right)) { if(2 == right.arity()) { //we take care of special cases like 0 = c + a.x, 0 = c + x, Expr c,x; separateMonomial(right[1], c, x); Theorem isIntx(isIntegerThm(x)); DebugAssert(!isIntx.isNull(), "right = "+right.toString() +"\n x = "+x.toString()); Theorem res(iffMP(eqn, d_rules->intVarEqnConst(eqn.getExpr(), isIntx))); TRACE("arith eq", "processSimpleIntEq[0 = c + a*x] => ", res, " }"); return res; } DebugAssert(right.arity() > 2, "TheoryArithNew::processSimpleIntEq: RHS is not in correct form:" +eqn.getExpr().toString()); // Pick a suitable monomial. isolated can be of the form x, a.x, -a.x Expr isolated = pickIntEqMonomial(right); TRACE("arith eq", "processSimpleIntEq: isolated = ", isolated, ""); // First, we compute the 'sign factor' with which to multiply the // eqn. if the coeff of isolated is positive (i.e. 'isolated' is // of the form x or a.x where a>0 ) then r must be -1 and if coeff // of 'isolated' is negative, r=1. Rational r = isMult(isolated) ? ((isolated[0].getRational() > 0) ? -1 : 1) : -1; Theorem result; if (-1 == r) { // r=-1 and hence 'isolated' is 'x' or 'a.x' where a is // positive. modify eqn (0=e') to the equation (0=canon(-1*e')) result = iffMP(eqn, d_rules->multEqn(eqn.getLHS(), right, rat(r))); result = canonPred(result); Expr e = result.getRHS(); // Isolate the 'isolated' result = iffMP(result, d_rules->plusPredicate(result.getLHS(),result.getRHS(), isolated, EQ)); } else { //r is 1 and hence isolated is -a.x. Make 'isolated' positive. const Rational& minusa = isolated[0].getRational(); Rational a = -1*minusa; isolated = (a == 1)? isolated[1] : rat(a) * isolated[1]; // Isolate the 'isolated' result = iffMP(eqn, d_rules->plusPredicate(eqn.getLHS(), right,isolated,EQ)); } // Canonize the result result = canonPred(result); //if isolated is 'x' or 1*x, then return result else continue processing. if(!isMult(isolated) || isolated[0].getRational() == 1) { TRACE("arith eq", "processSimpleIntEq[x = rhs] => ", result, " }"); return result; } else { DebugAssert(isMult(isolated) && isolated[0].getRational() >= 2, "TheoryArithNew::processSimpleIntEq: isolated must be mult " "with coeff >= 2.\n isolated = " + isolated.toString()); // Compute IS_INTEGER() for lhs and rhs Expr lhs = result.getLHS(); Expr rhs = result.getRHS(); Expr a, x; separateMonomial(lhs, a, x); Theorem isIntLHS = isIntegerThm(x); vector isIntRHS; if(!isPlus(rhs)) { // rhs is a MULT Expr c, v; separateMonomial(rhs, c, v); isIntRHS.push_back(isIntegerThm(v)); DebugAssert(!isIntRHS.back().isNull(), ""); } else { // rhs is a PLUS DebugAssert(isPlus(rhs), "rhs = "+rhs.toString()); DebugAssert(rhs.arity() >= 2, "rhs = "+rhs.toString()); Expr::iterator i=rhs.begin(), iend=rhs.end(); ++i; // Skip the free constant for(; i!=iend; ++i) { Expr c, v; separateMonomial(*i, c, v); isIntRHS.push_back(isIntegerThm(v)); DebugAssert(!isIntRHS.back().isNull(), ""); } } // Derive (EXISTS (x:INT): x = t2 AND 0 = t3) result = d_rules->eqElimIntRule(result, isIntLHS, isIntRHS); // Skolemize the quantifier result = getCommonRules()->skolemize(result); // Canonize t2 and t3 generated by this rule DebugAssert(result.getExpr().isAnd() && result.getExpr().arity() == 2, "processSimpleIntEq: result = "+result.getExpr().toString()); Theorem thm1 = canonPred(getCommonRules()->andElim(result, 0)); Theorem thm2 = canonPred(getCommonRules()->andElim(result, 1)); Theorem newRes = getCommonRules()->andIntro(thm1, thm2); if(newRes.getExpr() != result.getExpr()) result = newRes; TRACE("arith eq", "processSimpleIntEq => ", result, " }"); return result; } } else { // eqn is 0 = x. Flip it and return Theorem result = symmetryRule(eqn); TRACE("arith eq", "processSimpleIntEq[x = 0] => ", result, " }"); return result; } } /*! input is e1=e2<==>0=e' Theorem and all of the vars in e' are of * type INT. isolate one of them and send back to framework. output * is "e1=e2 <==> var = e''" Theorem and some associated equations in * solved form. */ Theorem TheoryArithNew::processIntEq(const Theorem& eqn) { TRACE("arith eq", "processIntEq(", eqn.getExpr(), ") {"); // Equations in the solved form. std::vector solvedAndNewEqs; Theorem newEq(eqn), result; bool done(false); do { result = processSimpleIntEq(newEq); // 'result' is of the from (x1=t1) AND 0=t' if(result.isRewrite()) { solvedAndNewEqs.push_back(result); done = true; } else if(!result.getExpr().isFalse()) { DebugAssert(result.getExpr().isAnd() && result.getExpr().arity() == 2, "TheoryArithNew::processIntEq("+eqn.getExpr().toString() +")\n result = "+result.getExpr().toString()); solvedAndNewEqs.push_back(getCommonRules()->andElim(result, 0)); newEq = getCommonRules()->andElim(result, 1); } else done = true; } while(!done); Theorem res; if(result.getExpr().isFalse()) res = result; else res = solvedForm(solvedAndNewEqs); TRACE("arith eq", "processIntEq => ", res.getExpr(), " }"); return res; } /*! * Takes a vector of equations and for every equation x_i=t_i * substitutes t_j for x_j in t_i for all j>i. This turns the system * of equations into a solved form. * * Assumption: variables x_j may appear in the RHS terms t_i ONLY for * i=j. */ Theorem TheoryArithNew::solvedForm(const vector& solvedEqs) { DebugAssert(solvedEqs.size() > 0, "TheoryArithNew::solvedForm()"); // Trace code TRACE_MSG("arith eq", "TheoryArithNew::solvedForm:solvedEqs(\n ["); IF_DEBUG(if(debugger.trace("arith eq")) { for(vector::const_iterator j = solvedEqs.begin(), jend=solvedEqs.end(); j!=jend;++j) TRACE("arith eq", "", j->getExpr(), ",\n "); }) TRACE_MSG("arith eq", " ]) {"); // End of Trace code vector::const_reverse_iterator i = solvedEqs.rbegin(), iend = solvedEqs.rend(); // Substitution map: a variable 'x' is mapped to a Theorem x=t. // This map accumulates the resulting solved form. ExprMap subst; for(; i!=iend; ++i) { if(i->isRewrite()) { Theorem thm = substAndCanonize(*i, subst); TRACE("arith eq", "solvedForm: subst["+i->getLHS().toString()+"] = ", thm.getExpr(), ""); subst[i->getLHS()] = thm; } else { // This is the FALSE case: just return the contradiction DebugAssert(i->getExpr().isFalse(), "TheoryArithNew::solvedForm: an element of solvedEqs must " "be either EQ or FALSE: "+i->toString()); return *i; } } // Now we've collected the solved form in 'subst'. Wrap it up into // a conjunction and return. vector thms; for(ExprMap::iterator i=subst.begin(), iend=subst.end(); i!=iend; ++i) thms.push_back(i->second); if (thms.size() > 1) return getCommonRules()->andIntro(thms); else return thms.back(); } /*! * ASSUMPTION: 't' is a fully canonized arithmetic term, and every * element of subst is a fully canonized equation of the form x=e, * indexed by the LHS variable. */ Theorem TheoryArithNew::substAndCanonize(const Expr& t, ExprMap& subst) { TRACE("arith eq", "substAndCanonize(", t, ") {"); // Quick and dirty check: return immediately if subst is empty if(subst.empty()) { Theorem res(reflexivityRule(t)); TRACE("arith eq", "substAndCanonize[subst empty] => ", res, " }"); return res; } // Check if we can substitute 't' directly ExprMap::iterator i = subst.find(t), iend=subst.end(); if(i!=iend) { TRACE("arith eq", "substAndCanonize[subst] => ", i->second, " }"); return i->second; } // The base case: t is an i-leaf if(isLeaf(t)) { Theorem res(reflexivityRule(t)); TRACE("arith eq", "substAndCanonize[i-leaf] => ", res, " }"); return res; } // 't' is an arithmetic term; recurse into the children vector thms; vector changed; for(unsigned j=0, jend=t.arity(); j!=jend; ++j) { Theorem thm = substAndCanonize(t[j], subst); if(thm.getRHS() != t[j]) { thm = canonThm(thm); thms.push_back(thm); changed.push_back(j); } } // Do the actual substitution and canonize the result Theorem res; if(thms.size() > 0) { res = substitutivityRule(t, changed, thms); res = canonThm(res); } else res = reflexivityRule(t); TRACE("arith eq", "substAndCanonize => ", res, " }"); return res; } /*! * ASSUMPTION: 't' is a fully canonized equation of the form x = t, * and so is every element of subst, indexed by the LHS variable. */ Theorem TheoryArithNew::substAndCanonize(const Theorem& eq, ExprMap& subst) { // Quick and dirty check: return immediately if subst is empty if(subst.empty()) return eq; DebugAssert(eq.isRewrite(), "TheoryArithNew::substAndCanonize: t = " +eq.getExpr().toString()); const Expr& t = eq.getRHS(); // Do the actual substitution in the term t Theorem thm = substAndCanonize(t, subst); // Substitution had no result: return the original equation if(thm.getRHS() == t) return eq; // Otherwise substitute the result into the equation vector thms; vector changed; thms.push_back(thm); changed.push_back(1); return iffMP(eq, substitutivityRule(eq.getExpr(), changed, thms)); } void TheoryArithNew::updateStats(const Rational& c, const Expr& v) { TRACE("arith ineq", "updateStats("+c.toString()+", ", v, ")"); if(c > 0) { if(d_countRight.count(v) > 0) d_countRight[v] = d_countRight[v] + 1; else d_countRight[v] = 1; } else if(d_countLeft.count(v) > 0) d_countLeft[v] = d_countLeft[v] + 1; else d_countLeft[v] = 1; } void TheoryArithNew::updateStats(const Expr& monomial) { Expr c, m; separateMonomial(monomial, c, m); updateStats(c.getRational(), m); } void TheoryArithNew::addToBuffer(const Theorem& thm) { // First, turn the inequality into 0 < rhs // FIXME: check if this can be optimized away Theorem result(thm); const Expr& e = thm.getExpr(); // int kind = e.getKind(); if(!(e[0].isRational() && e[0].getRational() == 0)) { result = iffMP(result, d_rules->rightMinusLeft(e)); result = canonPred(result); } TRACE("arith ineq", "addToBuffer(", result.getExpr(), ")"); // Push it into the buffer d_buffer.push_back(thm); // Collect the statistics about variables const Expr& rhs = thm.getExpr()[1]; if(isPlus(rhs)) for(Expr::iterator i=rhs.begin(), iend=rhs.end(); i!=iend; ++i) updateStats(*i); else // It's a monomial updateStats(rhs); } Expr TheoryArithNew::computeNormalFactor(const Expr& right, NormalizationType type) { // Strategy: compute f = lcm(d1...dn)/gcd(c1...cn), where the RHS is of the form c1/d1*x1 + ... + cn/dn*xn or a rational // The expression must be canonised, i.e. it is a sum or a rational DebugAssert(isRational(right) || isPlus(right),"TheoryArithNew::computeNormalFactor: " + right.toString() + "wrong kind"); // The factor we will compute Rational factor; // Sign of the factor int sign = 0; // In case the expression is a PLUS expression find the gcd if(isPlus(right)) { // Vector of numerators and denominators vector nums, denoms; // Pass throught the sum and pick up the integers for(int i = 0, iend = right.arity(); i < iend; i ++) { Rational c(1); // The rational constant of the current summand // If rational or multiplicatino set c to be the apropriate rational switch(right[i].getKind()) { case RATIONAL_EXPR: // Sum term is just a rational, so just add it c = abs(right[i].getRational()); break; case MULT: // Sum term is involves multiplication c = right[i][0].getRational(); // If this is the first one (sign is still not set) set the sign depending on the sign of the term if (!sign) { // If the normalization type is NORMALIZE_UNIT just return the invese of the first if (type == NORMALIZE_UNIT) return rat(1/c); // Set the sign otherwise sign = (c > 0 ? 1 : -1); } // Constant should be positive for lcd and gcd computation c = abs(c); break; default: // Stays 1 or everything else break; } // Add the demoninator and the numerator to the apropriate vectors nums.push_back(c.getNumerator()); denoms.push_back(c.getDenominator()); } // Compute the gcd of all the numerators Rational gcd_nums = gcd(nums); // x/0 == 0 in our model, as a total extension of arithmetic. The // particular value of x/0 is irrelevant, since the DP is guarded // by the top-level TCCs, and it is safe to return any value in // cases when terms are undefined. factor = (gcd_nums == 0)? 0 : (sign * lcm(denoms) / gcd_nums); } else // The expression is a rational, just return 1 factor = 1; // Return the reational expression representing the factor return rat(factor); } bool TheoryArithNew::lessThanVar(const Expr& isolatedMonomial, const Expr& var2) { DebugAssert(!isRational(var2) && !isRational(isolatedMonomial), "TheoryArithNew::findMaxVar: isolatedMonomial cannot be rational" + isolatedMonomial.toString()); Expr c, var0, var1; separateMonomial(isolatedMonomial, c, var0); separateMonomial(var2, c, var1); return var0 < var1; } void TheoryArithNew::separateMonomial(const Expr& e, Expr& c, Expr& var) { TRACE("separateMonomial", "separateMonomial(", e, ")"); DebugAssert(!isPlus(e), "TheoryArithNew::separateMonomial(e = "+e.toString()+")"); if(isMult(e)) { DebugAssert(e.arity() >= 2, "TheoryArithNew::separateMonomial(e = "+e.toString()+")"); c = e[0]; if(e.arity() == 2) var = e[1]; else { vector kids = e.getKids(); kids[0] = rat(1); var = multExpr(kids); } } else { c = rat(1); var = e; } DebugAssert(c.isRational(), "TheoryArithNew::separateMonomial(e = " +e.toString()+", c = "+c.toString()+")"); DebugAssert(!isMult(var) || (var[0].isRational() && var[0].getRational()==1), "TheoryArithNew::separateMonomial(e = " +e.toString()+", var = "+var.toString()+")"); } //returns true if e1 < e2, else false(i.e e2 < e1 or e1,e2 are not //comparable) bool TheoryArithNew::VarOrderGraph::lessThan(const Expr& e1, const Expr& e2) { d_cache.clear(); //returns true if e1 is in the subtree rooted at e2 implying e1 < e2 return dfs(e1,e2); } //returns true if e1 is in the subtree rooted at e2 implying e1 < e2 bool TheoryArithNew::VarOrderGraph::dfs(const Expr& e1, const Expr& e2) { if(e1 == e2) return true; if(d_cache.count(e2) > 0) return false; if(d_edges.count(e2) == 0) return false; d_cache[e2] = true; vector& e2Edges = d_edges[e2]; vector::iterator i = e2Edges.begin(); vector::iterator iend = e2Edges.end(); //if dfs finds e1 then i != iend else i is equal to iend for(; i != iend && !dfs(e1,*i); ++i); return (i != iend); } void TheoryArithNew::VarOrderGraph::selectSmallest(vector& v1, vector& v2) { int v1Size = v1.size(); vector v3(v1Size); for(int j=0; j < v1Size; ++j) v3[j] = false; for(int j=0; j < v1Size; ++j) { if(v3[j]) continue; for(int i =0; i < v1Size; ++i) { if((i == j) || v3[i]) continue; if(lessThan(v1[i],v1[j])) { v3[j] = true; break; } } } vector new_v1; for(int j = 0; j < v1Size; ++j) if(!v3[j]) v2.push_back(v1[j]); else new_v1.push_back(v1[j]); v1 = new_v1; } void TheoryArithNew::VarOrderGraph::selectLargest(const vector& v1, vector& v2) { int v1Size = v1.size(); vector v3(v1Size); for(int j=0; j < v1Size; ++j) v3[j] = false; for(int j=0; j < v1Size; ++j) { if(v3[j]) continue; for(int i =0; i < v1Size; ++i) { if((i == j) || v3[i]) continue; if(lessThan(v1[j],v1[i])) { v3[j] = true; break; } } } for(int j = 0; j < v1Size; ++j) if(!v3[j]) v2.push_back(v1[j]); } /////////////////////////////////////////////////////////////////////////////// // TheoryArithNew Public Methods // /////////////////////////////////////////////////////////////////////////////// TheoryArithNew::TheoryArithNew(TheoryCore* core) : TheoryArith(core, "ArithmeticNew"), d_diseq(core->getCM()->getCurrentContext()), d_diseqIdx(core->getCM()->getCurrentContext(), 0, 0), d_inModelCreation(core->getCM()->getCurrentContext(), false, 0), d_freeConstDB(core->getCM()->getCurrentContext()), d_buffer(core->getCM()->getCurrentContext()), // Initialize index to 0 at scope 0 d_bufferIdx(core->getCM()->getCurrentContext(), 0, 0), d_bufferThres(&(core->getFlags()["ineq-delay"].getInt())), d_countRight(core->getCM()->getCurrentContext()), d_countLeft(core->getCM()->getCurrentContext()), d_sharedTerms(core->getCM()->getCurrentContext()), d_sharedVars(core->getCM()->getCurrentContext()), consistent(core->getCM()->getCurrentContext()), lowerBound(core->getCM()->getCurrentContext()), upperBound(core->getCM()->getCurrentContext()), beta(core->getCM()->getCurrentContext()), assertedExprCount(core->getCM()->getCurrentContext()), integer_lemma(core->getCM()->getCurrentContext()) { IF_DEBUG(d_diseq.setName("CDList[TheoryArithNew::d_diseq]");) IF_DEBUG(d_buffer.setName("CDList[TheoryArithNew::d_buffer]");) IF_DEBUG(d_bufferIdx.setName("CDList[TheoryArithNew::d_bufferIdx]");) getEM()->newKind(REAL, "_REAL", true); getEM()->newKind(INT, "_INT", true); getEM()->newKind(SUBRANGE, "_SUBRANGE", true); getEM()->newKind(UMINUS, "_UMINUS"); getEM()->newKind(PLUS, "_PLUS"); getEM()->newKind(MINUS, "_MINUS"); getEM()->newKind(MULT, "_MULT"); getEM()->newKind(DIVIDE, "_DIVIDE"); getEM()->newKind(POW, "_POW"); getEM()->newKind(INTDIV, "_INTDIV"); getEM()->newKind(MOD, "_MOD"); getEM()->newKind(LT, "_LT"); getEM()->newKind(LE, "_LE"); getEM()->newKind(GT, "_GT"); getEM()->newKind(GE, "_GE"); getEM()->newKind(IS_INTEGER, "_IS_INTEGER"); getEM()->newKind(NEGINF, "_NEGINF"); getEM()->newKind(POSINF, "_POSINF"); getEM()->newKind(DARK_SHADOW, "_DARK_SHADOW"); getEM()->newKind(GRAY_SHADOW, "_GRAY_SHADOW"); getEM()->newKind(REAL_CONST, "_REAL_CONST"); vector kinds; kinds.push_back(REAL); kinds.push_back(INT); kinds.push_back(SUBRANGE); kinds.push_back(IS_INTEGER); kinds.push_back(UMINUS); kinds.push_back(PLUS); kinds.push_back(MINUS); kinds.push_back(MULT); kinds.push_back(DIVIDE); kinds.push_back(POW); kinds.push_back(INTDIV); kinds.push_back(MOD); kinds.push_back(LT); kinds.push_back(LE); kinds.push_back(GT); kinds.push_back(GE); kinds.push_back(RATIONAL_EXPR); kinds.push_back(NEGINF); kinds.push_back(POSINF); kinds.push_back(DARK_SHADOW); kinds.push_back(GRAY_SHADOW); kinds.push_back(REAL_CONST); registerTheory(this, kinds, true); d_rules = createProofRules(); d_realType = Type(getEM()->newLeafExpr(REAL)); d_intType = Type(getEM()->newLeafExpr(INT)); consistent = SATISFIABLE; assertedExprCount = 0; } // Destructor: delete the proof rules class if it's present TheoryArithNew::~TheoryArithNew() { if(d_rules != NULL) delete d_rules; // Clear the inequality databases for(ExprMap *>::iterator i=d_inequalitiesRightDB.begin(), iend=d_inequalitiesRightDB.end(); i!=iend; ++i) { delete (i->second); free(i->second); } for(ExprMap *>::iterator i=d_inequalitiesLeftDB.begin(), iend=d_inequalitiesLeftDB.end(); i!=iend; ++i) { delete (i->second); free (i->second); } } void TheoryArithNew::collectVars(const Expr& e, vector& vars, set& cache) { // Check the cache first if(cache.count(e) > 0) return; // Not processed yet. Cache the expression and proceed cache.insert(e); if(isLeaf(e)) vars.push_back(e); else for(Expr::iterator i=e.begin(), iend=e.end(); i!=iend; ++i) collectVars(*i, vars, cache); } void TheoryArithNew::processFiniteInterval(const Theorem& alphaLEax, const Theorem& bxLEbeta) { const Expr& ineq1(alphaLEax.getExpr()); const Expr& ineq2(bxLEbeta.getExpr()); DebugAssert(isLE(ineq1), "TheoryArithNew::processFiniteInterval: ineq1 = " +ineq1.toString()); DebugAssert(isLE(ineq2), "TheoryArithNew::processFiniteInterval: ineq2 = " +ineq2.toString()); // If the inequalities are not integer, just return (nothing to do) if(!isInteger(ineq1[0]) || !isInteger(ineq1[1]) || !isInteger(ineq2[0]) || !isInteger(ineq2[1])) return; const Expr& ax = ineq1[1]; const Expr& bx = ineq2[0]; DebugAssert(!isPlus(ax) && !isRational(ax), "TheoryArithNew::processFiniteInterval:\n ax = "+ax.toString()); DebugAssert(!isPlus(bx) && !isRational(bx), "TheoryArithNew::processFiniteInterval:\n bx = "+bx.toString()); Expr a = isMult(ax)? ax[0] : rat(1); Expr b = isMult(bx)? bx[0] : rat(1); Theorem thm1(alphaLEax), thm2(bxLEbeta); // Multiply the inequalities by 'b' and 'a', and canonize them, if necessary if(a != b) { thm1 = canonPred(iffMP(alphaLEax, d_rules->multIneqn(ineq1, b))); thm2 = canonPred(iffMP(bxLEbeta, d_rules->multIneqn(ineq2, a))); } // Check that a*beta - b*alpha == c > 0 const Expr& alphaLEt = thm1.getExpr(); const Expr& alpha = alphaLEt[0]; const Expr& t = alphaLEt[1]; const Expr& beta = thm2.getExpr()[1]; Expr c = canon(beta - alpha).getRHS(); if(c.isRational() && c.getRational() >= 1) { // This is a finite interval. First, derive t <= alpha + c: // canon(alpha+c) => (alpha+c == beta) ==> [symmetry] beta == alpha+c // Then substitute that in thm2 Theorem bEQac = symmetryRule(canon(alpha + c)); // Substitute beta == alpha+c for the second child of thm2 vector changed; vector thms; changed.push_back(1); thms.push_back(bEQac); Theorem tLEac = substitutivityRule(thm2.getExpr(), changed, thms); tLEac = iffMP(thm2, tLEac); // Derive and enqueue the finite interval constraint Theorem isInta(isIntegerThm(alpha)); Theorem isIntt(isIntegerThm(t)); enqueueFact(d_rules->finiteInterval(thm1, tLEac, isInta, isIntt)); } } void TheoryArithNew::processFiniteIntervals(const Expr& x) { // If x is not integer, do not bother if(!isInteger(x)) return; // Process every pair of the opposing inequalities for 'x' ExprMap *>::iterator iLeft, iRight; iLeft = d_inequalitiesLeftDB.find(x); if(iLeft == d_inequalitiesLeftDB.end()) return; iRight = d_inequalitiesRightDB.find(x); if(iRight == d_inequalitiesRightDB.end()) return; // There are some opposing inequalities; get the lists CDList& ineqsLeft = *(iLeft->second); CDList& ineqsRight = *(iRight->second); // Get the sizes of the lists size_t sizeLeft = ineqsLeft.size(); size_t sizeRight = ineqsRight.size(); // Process all the pairs of the opposing inequalities for(size_t l=0; lwithout * caching until it hits a node that is already setup. Be * careful on what expressions you are calling it. */ void TheoryArithNew::setupRec(const Expr& e) { if(e.hasFind()) return; // First, set up the kids recursively for (int k = 0; k < e.arity(); ++k) { setupRec(e[k]); } // Create a find pointer for e e.setFind(reflexivityRule(e)); e.setEqNext(reflexivityRule(e)); // And call our own setup() setup(e); } /*! * Keep track of all finitely bounded integer variables in shared * terms. * * When a new shared term t is reported, all of its variables x1...xn * are added to the set d_sharedVars. * * For each newly added variable x, check all of its opposing * inequalities, find out all the finite bounds and assert the * corresponding GRAY_SHADOW constraints. * * When projecting integer inequalities, the database d_sharedVars is * consulted, and if the variable is in it, check the shadows for * being a finite interval, and produce the additional GRAY_SHADOW * constraints. */ void TheoryArithNew::addSharedTerm(const Expr& e) { d_sharedTerms[e] = true; /* set cache; // Aux. cache for collecting i-leaves vector vars; // Vector of vars in e collectVars(e, vars, cache); for(vector::iterator i=vars.begin(), iend=vars.end(); i!=iend; ++i) { if(d_sharedVars.count(*i) == 0) { TRACE("arith shared", "TheoryArithNew::addSharedTerm: new var = ", *i, ""); processFiniteIntervals(*i); d_sharedVars[*i]=true; } } */ } void TheoryArithNew::refineCounterExample() { d_inModelCreation = true; TRACE("model", "refineCounterExample[TheoryArithNew] ", "", "{"); CDMap::iterator it = d_sharedTerms.begin(), it2, iend = d_sharedTerms.end(); // Add equalities over all pairs of shared terms as suggested // splitters. Notice, that we want to split on equality // (positively) first, to reduce the size of the model. for(; it!=iend; ++it) { // Copy by value: the elements in the pair from *it are NOT refs in CDMap Expr e1 = (*it).first; for(it2 = it, ++it2; it2!=iend; ++it2) { Expr e2 = (*it2).first; DebugAssert(isReal(getBaseType(e1)), "TheoryArithNew::refineCounterExample: e1 = "+e1.toString() +"\n type(e1) = "+e1.getType().toString()); if(findExpr(e1) != findExpr(e2)) { DebugAssert(isReal(getBaseType(e2)), "TheoryArithNew::refineCounterExample: e2 = "+e2.toString() +"\n type(e2) = "+e2.getType().toString()); Expr eq = simplifyExpr(e1.eqExpr(e2)); if (!eq.isBoolConst()) addSplitter(eq); } } } TRACE("model", "refineCounterExample[Theory::Arith] ", "", "}"); } void TheoryArithNew::findRationalBound(const Expr& varSide, const Expr& ratSide, const Expr& var, Rational &r) { Expr c, x; separateMonomial(varSide, c, x); DebugAssert(findExpr(c).isRational(), "seperateMonomial failed"); DebugAssert(findExpr(ratSide).isRational(), "smallest variable in graph, should not have variables" " in inequalities: "); DebugAssert(x == var, "separateMonomial found different variable: " + var.toString()); r = findExpr(ratSide).getRational() / findExpr(c).getRational(); } bool TheoryArithNew::findBounds(const Expr& e, Rational& lub, Rational& glb) { bool strictLB=false, strictUB=false; bool right = (d_inequalitiesRightDB.count(e) > 0 && d_inequalitiesRightDB[e]->size() > 0); bool left = (d_inequalitiesLeftDB.count(e) > 0 && d_inequalitiesLeftDB[e]->size() > 0); int numRight = 0, numLeft = 0; if(right) { //rationals less than e CDList * ratsLTe = d_inequalitiesRightDB[e]; for(unsigned int i=0; isize(); i++) { DebugAssert((*ratsLTe)[i].varOnRHS(), "variable on wrong side!"); Expr ineq = (*ratsLTe)[i].ineq().getExpr(); Expr leftSide = ineq[0], rightSide = ineq[1]; Rational r; findRationalBound(rightSide, leftSide, e , r); if(numRight==0 || r>glb){ glb = r; strictLB = isLT(ineq); } numRight++; } TRACE("model", " =>Lower bound ", glb.toString(), ""); } if(left) { //rationals greater than e CDList * ratsGTe = d_inequalitiesLeftDB[e]; for(unsigned int i=0; isize(); i++) { DebugAssert((*ratsGTe)[i].varOnLHS(), "variable on wrong side!"); Expr ineq = (*ratsGTe)[i].ineq().getExpr(); Expr leftSide = ineq[0], rightSide = ineq[1]; Rational r; findRationalBound(leftSide, rightSide, e, r); if(numLeft==0 || rUpper bound ", lub.toString(), ""); } if(!left && !right) { lub = 0; glb = 0; } if(!left && right) {lub = glb +2;} if(!right && left) {glb = lub-2;} DebugAssert(glb <= lub, "Greatest lower bound needs to be smaller " "than least upper bound"); return strictLB; } void TheoryArithNew::assignVariables(std::vector&v) { int count = 0; while (v.size() > 0) { std::vector bottom; d_graph.selectSmallest(v, bottom); TRACE("model", "Finding variables to assign. Iteration # ", count, ""); for(unsigned int i = 0; i& v) { d_inModelCreation = true; vector reps; TRACE("model", "Arith=>computeModel ", "", "{"); for(unsigned int i=0; i is defined by: ", findExpr(e) , ""); } } assignVariables(reps); TRACE("model", "Arith=>computeModel", "", "}"); d_inModelCreation = false; } // For any arith expression 'e', if the subexpressions are assigned // concrete values, then find(e) must already be a concrete value. void TheoryArithNew::computeModel(const Expr& e, vector& vars) { DebugAssert(findExpr(e).isRational(), "TheoryArithNew::computeModel(" +e.toString()+")\n e is not assigned concrete value.\n" +" find(e) = "+findExpr(e).toString()); assignValue(simplify(e)); vars.push_back(e); } /*! accepts a rewrite theorem over eqn|ineqn and normalizes it * and returns a theorem to that effect. assumes e is non-trivial * i.e. e is not '0=const' or 'const=0' or '0 <= const' etc. */ Theorem TheoryArithNew::normalize(const Expr& e, NormalizationType type) { //e is an eqn or ineqn. e is not a trivial eqn or ineqn //trivial means 0 = const or 0 <= const. // Trace the normalization on the arithm trace flag TRACE("arith", "normalize(", e, ") {"); // The constraint must be an equality or inequality DebugAssert(isIneq(e), "normalize: input must be an inequality: " + e.toString()); // The right side must be a sum or a multiplication DebugAssert(isPlus(e[1]) || (isMult(e[1]) && e[1][0].isRational()), "normalize: right side must be a sum or a mult: " + e.toString()); // The left side must be 0 DebugAssert(e[0].isRational() && 0 == e[0].getRational(), "normalize: e[0] must be 0" + e.toString()); // Compute the factor to use for normalizing the inequality Expr factor; // If a mult, just take the coefficient if (isMult(e[1])) factor = rat(1/e[1][0].getRational()); // Otherwise compute it else factor = computeNormalFactor(e[1], type); // Trace the rezult on the arith flag TRACE("arith", "normalize: factor = ", factor, ""); // The theorem we will be creating (reflexivity, just in case) Theorem thm; // Now multiply the equality by the factor, unless it is 1 if(factor.getRational() != 1) switch(e.getKind()) { case LE: case LT: case GE: case GT: // Multiply inequality by the factor thm = d_rules->multIneqn(e, factor); // And canonize the result thm = canonPredEquiv(thm); // Inequalities case break break; default: // How did we get here FatalAssert(false, "normalize: control should not reach here" + e.toString()); // Default case break break; } else // If rational is 1 then nothing to be done thm = reflexivityRule(e); // Trace the resulting theorem on the arith trace flag TRACE("arith", "normalize => ", thm, " }"); // Return the explaining theorem return(thm); } Theorem TheoryArithNew::normalize(const Theorem& eIffEqn, NormalizationType type) { return transitivityRule(eIffEqn, normalize(eIffEqn.getRHS(), type)); } Theorem TheoryArithNew::rafineIntegerConstraints(const Theorem& thm) { // The resulting theorem Theorem result = thm; // Get the constraint const Expr& constr = result.getRHS(); // Get the proof that this constraint is an integer constraint Theorem isIntConstraintThm = isIntegerThm(constr[1]); // If not an integer, just return the same theorem if (isIntConstraintThm.isNull()) return result; // Trace the integer TRACE("integer", "TheoryArithNew::rafineIntegerConstraints(", constr, ")"); TRACE("integer", "TheoryArithNew::rafineIntegerConstraints: int proof:", isIntConstraintThm, ""); // Get the left-hand of the constraint (the rational) Rational r = constr[0].getRational(); // If it is a strict inequality, make it non-strict if (constr.getKind() == LT || constr.getKind() == GT || !r.isInteger()) result = transitivityRule(result, d_rules->rafineStrictInteger(isIntConstraintThm, constr)); // Return the result return result; } Theorem TheoryArithNew::rewrite(const Expr& e) { // Leaves are assumeed to be already simplified //DebugAssert(leavesAreSimp(e), "Expected leaves to be simplified"); // Trace the rewrites on the arith flag TRACE("arith", "TheoryArithNew::rewrite(", e, ") {"); // The resulting theorem object Theorem thm; // Are we in the NOT expression bool isNot = false; // If the expression is not a term, i.e a literal if (!e.isTerm()) { // If the expression is not a literal just return the reflexivity theorem if (!e.isAbsLiteral()) { // Set the expression REWRITE NORMAL FLAG e.setRewriteNormal(); // Create the reflaxivity rule thm = reflexivityRule(e); // Trace the non-literal rewrite TRACE("arith", "TheoryArithNew::rewrite[non-literal] => ", thm, " }"); // Return the theorem return thm; } // Its a literal, switch the arithmetic relations for rewrite switch(e.getKind()) { // Equality case EQ: { // Rewrite equality as two inequalities thm = d_rules->eqToIneq(e); Expr andExpr = thm.getRHS(); // Rewrite the left inequality Expr leExpr = andExpr[0]; const Theorem& thmLeft = simplify(leExpr); // Rewrite the right inequality Expr geExpr = andExpr[1]; const Theorem& thmRight = simplify(geExpr); // Do the substitution thm = transitivityRule(thm, substitutivityRule(andExpr, thmLeft, thmRight)); // EQ case break break; } // Negation of an atomic formula case NOT: // If here, the equality should have already been rewritten as two disequalitites DebugAssert(e[0].getKind() != EQ, "TheoryArithNew::rewrite, not expecting equality under negation"); // Negate the inequality and continue with the normal case thm = d_rules->negatedInequality(e); // IMPORTANT, LE, LT, GE, GT MUST BE UNDER THIS isNot = true; case LT: case GT: case LE: case GE: // Move everything to the right side if (isNot) thm = transitivityRule(thm, d_rules->rightMinusLeft(thm.getRHS())); else thm = d_rules->rightMinusLeft(e); // Canonise children again thm = canonPredEquiv(thm); // If a trivial inequation just return true or false if ((thm.getRHS())[1].isRational()) thm = transitivityRule(thm, d_rules->constPredicate(thm.getRHS())); else { // It's a non-trivial inequation // Normalize the inequality thm = normalize(thm, NORMALIZE_UNIT); // Get the left and right side const Expr& normalised = thm.getRHS(); const Expr& rightSide = normalised[1]; const Expr& leftSide = normalised[0]; // If the right side is a sum, move the rational to the right side if (isPlus(rightSide)) { // Check if the fist of the sum is a rational if (rightSide[0].isRational()) { // Add the negative constant to both sides thm = transitivityRule(thm, d_rules->plusPredicate(leftSide, rightSide, rat(-rightSide[0].getRational()), thm.getRHS().getKind())); // Canonize the left side const Theorem& thmLeft = d_rules->canonPlus(thm.getRHS()[0]); // Canonize the right side const Theorem& thmRight = d_rules->canonPlus(thm.getRHS()[1]); // Sunstitute the canonised into the expression thm = transitivityRule(thm, substitutivityRule(thm.getRHS(), thmLeft, thmRight)); } } } // If a strict inequality on integers, or bounded by a non-integer, rafine it to a non-strict one // thm = rafineIntegerConstraints(thm); // EQ, LE, LT, GE, GT case break break; case IS_INTEGER: // TRACE TRACE("integer", "Got ", e.toString(), ""); TRACE("integer", "Type ", e[0].getType().toString(), ""); // TODO: What with the integers thm = d_rules->dummyTheorem(e); // IS_INTEGER case break break; default: // How did we get here FatalAssert(false, "Theory_Arith::rewrite: control should not reach here"); // default break break; } // End relation case } else { // Expression is a term // Terms that don't contain formulas are canonised via the canon() function if (e.isAtomic()) thm = canon(e); // Otherwise just return the same expression else thm = reflexivityRule(e); } // Compact the theorem into one rule //thm = d_rules->trustedRewrite(e, thm.getRHS()); // Arith canonization is idempotent, the theory should stay the same if (theoryOf(thm.getRHS()) == this) thm.getRHS().setRewriteNormal(); // Finished, trace the end of rewrite on the arith flag TRACE("arith", "TheoryArithNew::rewrite => ", thm, " }"); // Return the final theorem return thm; } void TheoryArithNew::setup(const Expr& e) { //If the expression is not a term but rather a predicate if (!e.isTerm()) { // If not or equality, just return if (e.isNot() || e.isEq()) return; // TODO: Integer::eqToIneq if (isIntPred(e)) return; // Check if the expression is canonised as (SUM t1 ... tn) @ b DebugAssert(isIneq(e) && e[0].isRational(), "TheoryArithNew::setup: b @ (sum t1 ... tn) :" + e.toString()); // Add the sum to the notify list of e e[1].addToNotify(this, e); } else { // The arity of the expression int arity(e.arity()); // Go through all the children and add this expression to their notify lists for (int k = 0 ; k < arity; k ++) { // Add the to the notify list of the children e[k].addToNotify(this, e); // Trace this notification add TRACE("arith setup", "e["+int2string(k)+"]: ", *(e[k].getNotify()), ""); } } } void TheoryArithNew::update(const Theorem& e, const Expr& d) { if (inconsistent()) return; IF_DEBUG(debugger.counter("arith update total")++;) if (!d.hasFind()) return; if (isIneq(d)) { // Substitute e[1] for e[0] in d and enqueue new inequality DebugAssert(e.getLHS() == d[1], "Mismatch"); Theorem thm = find(d); // DebugAssert(thm.getRHS() == trueExpr(), "Expected find = true"); vector changed; vector children; changed.push_back(1); children.push_back(e); Theorem thm2 = substitutivityRule(d, changed, children); if (thm.getRHS() == trueExpr()) { enqueueFact(iffMP(getCommonRules()->iffTrueElim(thm), thm2)); } else { enqueueFact(getCommonRules()->iffFalseElim( transitivityRule(symmetryRule(thm2), thm))); } IF_DEBUG(debugger.counter("arith update ineq")++;) } else if (find(d).getRHS() == d) { // Substitute e[1] for e[0] in d and assert the result equal to d Theorem thm = canonSimp(d); TRACE("arith", "TheoryArithNew::update(): thm = ", thm, ""); DebugAssert(leavesAreSimp(thm.getRHS()), "updateHelper error: " +thm.getExpr().toString()); assertEqualities(transitivityRule(thm, rewrite(thm.getRHS()))); IF_DEBUG(debugger.counter("arith update find(d)=d")++;) } } Theorem TheoryArithNew::solve(const Theorem& thm) { DebugAssert(thm.isRewrite() && thm.getLHS().isTerm(), ""); const Expr& lhs = thm.getLHS(); const Expr& rhs = thm.getRHS(); // Check for already solved equalities. // Have to be careful about the types: integer variable cannot be // assigned a real term. Also, watch for e[0] being a subexpression // of e[1]: this would create an unsimplifiable expression. if (isLeaf(lhs) && !isLeafIn(lhs, rhs) && (lhs.getType() != intType() || isInteger(rhs)) // && !e[0].subExprOf(e[1]) ) return thm; // Symmetric version is already solved if (isLeaf(rhs) && !isLeafIn(rhs, lhs) && (rhs.getType() != intType() || isInteger(lhs)) // && !e[1].subExprOf(e[0]) ) return symmetryRule(thm); return doSolve(thm); } void TheoryArithNew::computeModelTerm(const Expr& e, std::vector& v) { switch(e.getKind()) { case RATIONAL_EXPR: // Skip the constants break; case PLUS: case MULT: case DIVIDE: case POW: // This is not a variable; extract the variables from children for(Expr::iterator i=e.begin(), iend=e.end(); i!=iend; ++i) // getModelTerm(*i, v); v.push_back(*i); break; default: { // Otherwise it's a variable. Check if it has a find pointer Expr e2(findExpr(e)); if(e==e2) { TRACE("model", "TheoryArithNew::computeModelTerm(", e, "): a variable"); // Leave it alone (it has no descendants) // v.push_back(e); } else { TRACE("model", "TheoryArithNew::computeModelTerm("+e.toString() +"): has find pointer to ", e2, ""); v.push_back(e2); } } } } Expr TheoryArithNew::computeTypePred(const Type& t, const Expr& e) { Expr tExpr = t.getExpr(); switch(tExpr.getKind()) { case INT: return Expr(IS_INTEGER, e); case SUBRANGE: { std::vector kids; kids.push_back(Expr(IS_INTEGER, e)); kids.push_back(leExpr(tExpr[0], e)); kids.push_back(leExpr(e, tExpr[1])); return andExpr(kids); } default: return e.getEM()->trueExpr(); } } void TheoryArithNew::checkAssertEqInvariant(const Theorem& e) { return; } void TheoryArithNew::checkType(const Expr& e) { switch (e.getKind()) { case INT: case REAL: if (e.arity() > 0) { throw Exception("Ill-formed arithmetic type: "+e.toString()); } break; case SUBRANGE: if (e.arity() != 2 || !isIntegerConst(e[0]) || !isIntegerConst(e[1]) || e[0].getRational() > e[1].getRational()) { throw Exception("bad SUBRANGE type expression"+e.toString()); } break; default: DebugAssert(false, "Unexpected kind in TheoryArithNew::checkType" +getEM()->getKindName(e.getKind())); } } Cardinality TheoryArithNew::finiteTypeInfo(Expr& e, Unsigned& n, bool enumerate, bool computeSize) { Cardinality card = CARD_INFINITE; switch (e.getKind()) { case SUBRANGE: { card = CARD_FINITE; Expr typeExpr = e; if (enumerate) { Rational r = typeExpr[0].getRational() + n; if (r <= typeExpr[1].getRational()) { e = rat(r); } else e = Expr(); } if (computeSize) { Rational r = typeExpr[1].getRational() - typeExpr[0].getRational() + 1; n = r.getUnsigned(); } break; } default: break; } return card; } void TheoryArithNew::computeType(const Expr& e) { switch (e.getKind()) { case REAL_CONST: e.setType(d_realType); break; case RATIONAL_EXPR: if(e.getRational().isInteger()) e.setType(d_intType); else e.setType(d_realType); break; case UMINUS: case PLUS: case MINUS: case MULT: case POW: { bool isInt = true; for(int k = 0; k < e.arity(); ++k) { if(d_realType != getBaseType(e[k])) throw TypecheckException("Expecting type REAL with `" + getEM()->getKindName(e.getKind()) + "',\n"+ "but got a " + getBaseType(e[k]).toString()+ " for:\n" + e.toString()); if(isInt && !isInteger(e[k])) isInt = false; } if(isInt) e.setType(d_intType); else e.setType(d_realType); break; } case DIVIDE: { Expr numerator = e[0]; Expr denominator = e[1]; if (getBaseType(numerator) != d_realType || getBaseType(denominator) != d_realType) { throw TypecheckException("Expecting only REAL types with `DIVIDE',\n" "but got " + getBaseType(numerator).toString()+ " and " + getBaseType(denominator).toString() + " for:\n" + e.toString()); } if(denominator.isRational() && 1 == denominator.getRational()) e.setType(numerator.getType()); else e.setType(d_realType); break; } case LT: case LE: case GT: case GE: case GRAY_SHADOW: // Need to know types for all exprs -Clark // e.setType(boolType()); // break; case DARK_SHADOW: for (int k = 0; k < e.arity(); ++k) { if (d_realType != getBaseType(e[k])) throw TypecheckException("Expecting type REAL with `" + getEM()->getKindName(e.getKind()) + "',\n"+ "but got a " + getBaseType(e[k]).toString()+ " for:\n" + e.toString()); } e.setType(boolType()); break; case IS_INTEGER: if(d_realType != getBaseType(e[0])) throw TypecheckException("Expected type REAL, but got " +getBaseType(e[0]).toString() +"\n\nExpr = "+e.toString()); e.setType(boolType()); break; default: DebugAssert(false,"TheoryArithNew::computeType: unexpected expression:\n " +e.toString()); break; } } Type TheoryArithNew::computeBaseType(const Type& t) { IF_DEBUG(int kind = t.getExpr().getKind();) DebugAssert(kind==INT || kind==REAL || kind==SUBRANGE, "TheoryArithNew::computeBaseType("+t.toString()+")"); return realType(); } Expr TheoryArithNew::computeTCC(const Expr& e) { Expr tcc(Theory::computeTCC(e)); switch(e.getKind()) { case DIVIDE: DebugAssert(e.arity() == 2, ""); return tcc.andExpr(!(e[1].eqExpr(rat(0)))); default: return tcc; } } /////////////////////////////////////////////////////////////////////////////// //parseExprOp: //translating special Exprs to regular EXPR?? /////////////////////////////////////////////////////////////////////////////// Expr TheoryArithNew::parseExprOp(const Expr& e) { TRACE("parser", "TheoryArithNew::parseExprOp(", e, ")"); //std::cout << "Were here"; // If the expression is not a list, it must have been already // parsed, so just return it as is. switch(e.getKind()) { case ID: { int kind = getEM()->getKind(e[0].getString()); switch(kind) { case NULL_KIND: return e; // nothing to do case REAL: case INT: case NEGINF: case POSINF: return getEM()->newLeafExpr(kind); default: DebugAssert(false, "Bad use of bare keyword: "+e.toString()); return e; } } case RAW_LIST: break; // break out of switch, do the hard work default: return e; } DebugAssert(e.getKind() == RAW_LIST && e.arity() > 0, "TheoryArithNew::parseExprOp:\n e = "+e.toString()); const Expr& c1 = e[0][0]; int kind = getEM()->getKind(c1.getString()); switch(kind) { case UMINUS: { if(e.arity() != 2) throw ParserException("UMINUS requires exactly one argument: " +e.toString()); return uminusExpr(parseExpr(e[1])); } case PLUS: { vector k; Expr::iterator i = e.begin(), iend=e.end(); // Skip first element of the vector of kids in 'e'. // The first element is the operator. ++i; // Parse the kids of e and push them into the vector 'k' for(; i!=iend; ++i) k.push_back(parseExpr(*i)); return plusExpr(k); } case MINUS: { if(e.arity() == 2) return uminusExpr(parseExpr(e[1])); else if(e.arity() == 3) return minusExpr(parseExpr(e[1]), parseExpr(e[2])); else throw ParserException("MINUS requires one or two arguments:" +e.toString()); } case MULT: { vector k; Expr::iterator i = e.begin(), iend=e.end(); // Skip first element of the vector of kids in 'e'. // The first element is the operator. ++i; // Parse the kids of e and push them into the vector 'k' for(; i!=iend; ++i) k.push_back(parseExpr(*i)); return multExpr(k); } case POW: { return powExpr(parseExpr(e[1]), parseExpr(e[2])); } case DIVIDE: { return divideExpr(parseExpr(e[1]), parseExpr(e[2])); } case LT: { return ltExpr(parseExpr(e[1]), parseExpr(e[2])); } case LE: { return leExpr(parseExpr(e[1]), parseExpr(e[2])); } case GT: { return gtExpr(parseExpr(e[1]), parseExpr(e[2])); } case GE: { return geExpr(parseExpr(e[1]), parseExpr(e[2])); } case INTDIV: case MOD: case SUBRANGE: { vector k; Expr::iterator i = e.begin(), iend=e.end(); // Skip first element of the vector of kids in 'e'. // The first element is the operator. ++i; // Parse the kids of e and push them into the vector 'k' for(; i!=iend; ++i) k.push_back(parseExpr(*i)); return Expr(kind, k, e.getEM()); } case IS_INTEGER: { if(e.arity() != 2) throw ParserException("IS_INTEGER requires exactly one argument: " +e.toString()); return Expr(IS_INTEGER, parseExpr(e[1])); } default: DebugAssert(false, "TheoryArithNew::parseExprOp: invalid input " + e.toString()); break; } return e; } /////////////////////////////////////////////////////////////////////////////// // Pretty-printing // /////////////////////////////////////////////////////////////////////////////// ExprStream& TheoryArithNew::print(ExprStream& os, const Expr& e) { switch(os.lang()) { case SIMPLIFY_LANG: switch(e.getKind()) { case RATIONAL_EXPR: e.print(os); break; case SUBRANGE: os <<"ERROR:SUBRANGE:not supported in Simplify\n"; break; case IS_INTEGER: os <<"ERROR:IS_INTEGER:not supported in Simplify\n"; break; case PLUS: { int i=0, iend=e.arity(); os << "(+ "; if(i!=iend) os << e[i]; ++i; for(; i!=iend; ++i) os << " " << e[i]; os << ")"; break; } case MINUS: os << "(- " << e[0] << " " << e[1]<< ")"; break; case UMINUS: os << "-" << e[0] ; break; case MULT: { int i=0, iend=e.arity(); os << "(* " ; if(i!=iend) os << e[i]; ++i; for(; i!=iend; ++i) os << " " << e[i]; os << ")"; break; } case POW: os << "(" << push << e[1] << space << "^ " << e[0] << push << ")"; break; case DIVIDE: os << "(" << push << e[0] << space << "/ " << e[1] << push << ")"; break; case LT: if (isInt(e[0].getType()) || isInt(e[1].getType())) { } os << "(< " << e[0] << " " << e[1] <<")"; break; case LE: os << "(<= " << e[0] << " " << e[1] << ")"; break; case GT: os << "(> " << e[0] << " " << e[1] << ")"; break; case GE: os << "(>= " << e[0] << " " << e[1] << ")"; break; case DARK_SHADOW: case GRAY_SHADOW: os <<"ERROR:SHADOW:not supported in Simplify\n"; break; default: // Print the top node in the default LISP format, continue with // pretty-printing for children. e.print(os); break; } break; // end of case SIMPLIFY_LANG case TPTP_LANG: switch(e.getKind()) { case RATIONAL_EXPR: e.print(os); break; case SUBRANGE: os <<"ERROR:SUBRANGE:not supported in TPTP\n"; break; case IS_INTEGER: os <<"ERROR:IS_INTEGER:not supported in TPTP\n"; break; case PLUS: { if(!isInteger(e[0])){ os<<"ERRPR:plus only supports inteters now in TPTP\n"; break; } int i=0, iend=e.arity(); if(iend <=1){ os<<"ERROR,plus must have more than two numbers in TPTP\n"; break; } for(i=0; i <= iend-2; ++i){ os << "$plus_int("; os << e[i] << ","; } os<< e[iend-1]; for(i=0 ; i <= iend-2; ++i){ os << ")"; } break; } case MINUS: os << "(- " << e[0] << " " << e[1]<< ")"; break; case UMINUS: os << "-" << e[0] ; break; case MULT: { int i=0, iend=e.arity(); os << "(* " ; if(i!=iend) os << e[i]; ++i; for(; i!=iend; ++i) os << " " << e[i]; os << ")"; break; } case POW: os << "(" << push << e[1] << space << "^ " << e[0] << push << ")"; break; case DIVIDE: os << "(" << push << e[0] << space << "/ " << e[1] << push << ")"; break; case LT: if (isInt(e[0].getType()) || isInt(e[1].getType())) { } os << "(< " << e[0] << " " << e[1] <<")"; break; case LE: os << "(<= " << e[0] << " " << e[1] << ")"; break; case GT: os << "(> " << e[0] << " " << e[1] << ")"; break; case GE: os << "(>= " << e[0] << " " << e[1] << ")"; break; case DARK_SHADOW: case GRAY_SHADOW: os <<"ERROR:SHADOW:not supported in TPTP\n"; break; default: // Print the top node in the default LISP format, continue with // pretty-printing for children. e.print(os); break; } break; // end of case TPTP_LANG case PRESENTATION_LANG: switch(e.getKind()) { case REAL: case INT: case RATIONAL_EXPR: case NEGINF: case POSINF: e.print(os); break; case SUBRANGE: if(e.arity() != 2) e.printAST(os); else os << "[" << push << e[0] << ".." << e[1] << push << "]"; break; case IS_INTEGER: if(e.arity() == 1) os << "IS_INTEGER(" << push << e[0] << push << ")"; else e.printAST(os); break; case PLUS: { int i=0, iend=e.arity(); os << "(" << push; if(i!=iend) os << e[i]; ++i; for(; i!=iend; ++i) os << space << "+ " << e[i]; os << push << ")"; break; } case MINUS: os << "(" << push << e[0] << space << "- " << e[1] << push << ")"; break; case UMINUS: os << "-(" << push << e[0] << push << ")"; break; case MULT: { int i=0, iend=e.arity(); os << "(" << push; if(i!=iend) os << e[i]; ++i; for(; i!=iend; ++i) os << space << "* " << e[i]; os << push << ")"; break; } case POW: os << "(" << push << e[1] << space << "^ " << e[0] << push << ")"; break; case DIVIDE: os << "(" << push << e[0] << space << "/ " << e[1] << push << ")"; break; case LT: if (isInt(e[0].getType()) || isInt(e[1].getType())) { } os << "(" << push << e[0] << space << "< " << e[1] << push << ")"; break; case LE: os << "(" << push << e[0] << space << "<= " << e[1] << push << ")"; break; case GT: os << "(" << push << e[0] << space << "> " << e[1] << push << ")"; break; case GE: os << "(" << push << e[0] << space << ">= " << e[1] << push << ")"; break; case DARK_SHADOW: os << "DARK_SHADOW(" << push << e[0] << ", " << space << e[1] << push << ")"; break; case GRAY_SHADOW: os << "GRAY_SHADOW(" << push << e[0] << "," << space << e[1] << "," << space << e[2] << "," << space << e[3] << push << ")"; break; default: // Print the top node in the default LISP format, continue with // pretty-printing for children. e.printAST(os); break; } break; // end of case PRESENTATION_LANG case SMTLIB_LANG: case SMTLIB_V2_LANG: { switch(e.getKind()) { case REAL_CONST: printRational(os, e[0].getRational(), true); break; case RATIONAL_EXPR: printRational(os, e.getRational()); break; case REAL: os << "Real"; break; case INT: os << "Int"; break; case SUBRANGE: throw SmtlibException("TheoryArithNew::print: SMTLIB: SUBRANGE not implemented"); // if(e.arity() != 2) e.print(os); // else // os << "(" << push << "SUBRANGE" << space << e[0] // << space << e[1] << push << ")"; break; case IS_INTEGER: if(e.arity() == 1) os << "(" << push << "IsInt" << space << e[0] << push << ")"; else throw SmtlibException("TheoryArithNew::print: SMTLIB: IS_INTEGER used unexpectedly"); break; case PLUS: { if(e.arity() == 1 && os.lang() == SMTLIB_V2_LANG) { os << e[0]; } else { os << "(" << push << "+"; Expr::iterator i = e.begin(), iend = e.end(); for(; i!=iend; ++i) { os << space << (*i); } os << push << ")"; } break; } case MINUS: { os << "(" << push << "- " << e[0] << space << e[1] << push << ")"; break; } case UMINUS: { os << "(" << push << "-" << space << e[0] << push << ")"; break; } case MULT: { int i=0, iend=e.arity(); if(iend == 1 && os.lang() == SMTLIB_V2_LANG) { os << e[0]; } else { for(; i!=iend; ++i) { if (i < iend-1) { os << "(" << push << "*"; } os << space << e[i]; } for (i=0; i < iend-1; ++i) os << push << ")"; } break; } case POW: throw SmtlibException("TheoryArithNew::print: SMTLIB: POW not supported"); // os << "(" << push << "^ " << e[1] << space << e[0] << push << ")"; break; case DIVIDE: { throw SmtlibException("TheoryArithNew::print: SMTLIB: unexpected use of DIVIDE"); break; } case LT: { Rational r; os << "(" << push << "<" << space; os << e[0] << space << e[1] << push << ")"; break; } case LE: { Rational r; os << "(" << push << "<=" << space; os << e[0] << space << e[1] << push << ")"; break; } case GT: { Rational r; os << "(" << push << ">" << space; os << e[0] << space << e[1] << push << ")"; break; } case GE: { Rational r; os << "(" << push << ">=" << space; os << e[0] << space << e[1] << push << ")"; break; } case DARK_SHADOW: throw SmtlibException("TheoryArithNew::print: SMTLIB: DARK_SHADOW not supported"); os << "(" << push << "DARK_SHADOW" << space << e[0] << space << e[1] << push << ")"; break; case GRAY_SHADOW: throw SmtlibException("TheoryArithNew::print: SMTLIB: GRAY_SHADOW not supported"); os << "GRAY_SHADOW(" << push << e[0] << "," << space << e[1] << "," << space << e[2] << "," << space << e[3] << push << ")"; break; default: throw SmtlibException("TheoryArithNew::print: SMTLIB: default not supported"); // Print the top node in the default LISP format, continue with // pretty-printing for children. e.printAST(os); break; } break; // end of case SMTLIB_LANG } case LISP_LANG: switch(e.getKind()) { case REAL: case INT: case RATIONAL_EXPR: case NEGINF: case POSINF: e.print(os); break; case SUBRANGE: if(e.arity() != 2) e.printAST(os); else os << "(" << push << "SUBRANGE" << space << e[0] << space << e[1] << push << ")"; break; case IS_INTEGER: if(e.arity() == 1) os << "(" << push << "IS_INTEGER" << space << e[0] << push << ")"; else e.printAST(os); break; case PLUS: { int i=0, iend=e.arity(); os << "(" << push << "+"; for(; i!=iend; ++i) os << space << e[i]; os << push << ")"; break; } case MINUS: //os << "(" << push << e[0] << space << "- " << e[1] << push << ")"; os << "(" << push << "- " << e[0] << space << e[1] << push << ")"; break; case UMINUS: os << "(" << push << "-" << space << e[0] << push << ")"; break; case MULT: { int i=0, iend=e.arity(); os << "(" << push << "*"; for(; i!=iend; ++i) os << space << e[i]; os << push << ")"; break; } case POW: os << "(" << push << "^ " << e[1] << space << e[0] << push << ")"; break; case DIVIDE: os << "(" << push << "/ " << e[0] << space << e[1] << push << ")"; break; case LT: os << "(" << push << "< " << e[0] << space << e[1] << push << ")"; break; case LE: os << "(" << push << "<= " << e[0] << space << e[1] << push << ")"; break; case GT: os << "(" << push << "> " << e[1] << space << e[0] << push << ")"; break; case GE: os << "(" << push << ">= " << e[0] << space << e[1] << push << ")"; break; case DARK_SHADOW: os << "(" << push << "DARK_SHADOW" << space << e[0] << space << e[1] << push << ")"; break; case GRAY_SHADOW: os << "(" << push << "GRAY_SHADOW" << space << e[0] << space << e[1] << space << e[2] << space << e[3] << push << ")"; break; default: // Print the top node in the default LISP format, continue with // pretty-printing for children. e.printAST(os); break; } break; // end of case LISP_LANG default: // Print the top node in the default LISP format, continue with // pretty-printing for children. e.printAST(os); } return os; } /////////////////////////////////////////////////////////////////////////////// // SIMPLEX SOLVER // /////////////////////////////////////////////////////////////////////////////// bool TheoryArithNew::isBasic(const Expr& x) const { // If it is on the right side of the tableaux the it is basic, non-basic otherwise return (tableaux.find(x) != tableaux.end()); } void TheoryArithNew::pivot(const Expr& x_r, const Expr& x_s) { // Check that the variable is non-basic DebugAssert(isBasic(x_r), "TheoryArithNew::pivot, given variable should be basic" + x_r.toString()); DebugAssert(!isBasic(x_s), "TheoryArithNew::pivot, given variable should be non-basic" + x_s.toString()); // If trace is on for the simplex, print it out TRACE("simplex", "TheoryArithNew::pivot(", x_r.toString() + ", " + x_s.toString(), ")"); // Get the iterator that points to the expression of x_r TebleauxMap::iterator it = tableaux.find(x_r); // Get the expresiion of x_r Theorem x_r_Theorem = (*it).second; // Erase the x_r expression from the tableaux tableaux.erase(x_r); // TODO: Add erase by iterator to ExprHashMap // Update the dependencies updateDependenciesRemove(x_r, x_r_Theorem.getExpr()[1]); // Construct the expresison (theorem) of x_s const Theorem& x_s_Theorem = pivotRule(x_r_Theorem, x_s); // Replace all occurances of x_s with x_s_Expression substAndCanonizeTableaux(x_s_Theorem); // Update the dependencies updateDependenciesAdd(x_s, x_s_Theorem.getExpr()[1]); // Add the expression of x_s to the map tableaux[x_s] = x_s_Theorem; } void TheoryArithNew::update(const Expr& x_i, const EpsRational& v) { // Check that the variable is non-basic DebugAssert(tableaux.find(x_i) == tableaux.end(), "TheoryArithNew::update, given variable should be non-basic" + x_i.toString()); // If trace is on for the simplex, print it out TRACE("simplex", "TheoryArithNew::update(", x_i.toString() + ", " + v.toString(), ")"); // Remember the value of the x_i variable EpsRational old_value = getBeta(x_i); // If there are dependent variables then do the work DependenciesMap::iterator find = dependenciesMap.find(x_i); if (find != dependenciesMap.end()) { // Go through all the variables that depend on x_i const set& dependent = (*find).second; set::const_iterator it = dependent.begin(); set::const_iterator it_end = dependent.end(); // Fix the values of all the variables while (it != it_end) { // Get the current variable const Expr& x_j = *it; // Get the tableaux coefficient of the of x_i in the row of x_j (the right side ofg the tableaux expression) const Rational& a_ji = getTableauxEntry(x_j, x_i); // Update the beta valuation EpsRational b(getBeta(x_j)); // TODO: not necessary, beta's are all setup now EpsRational x_j_new = beta[x_j] = b + (v - old_value) * a_ji; // Check if the variable is sat or unsat under the new assignment if (x_j_new < getLowerBound(x_j) || getUpperBound(x_j) < x_j_new) unsatBasicVariables.insert(x_j); else unsatBasicVariables.erase(x_j); // Go to the next one it ++; } } // Set the new value to x_i (x_i) is non_basic, no need to add to unsat set) beta[x_i] = v; } void TheoryArithNew::pivotAndUpdate(const Expr& x_i, const Expr& x_j, const EpsRational& v) { // Variable x_i should be a basic variable (left side of the tableaux) and x_j should be non_basic DebugAssert(tableaux.find(x_i) != tableaux.end(), "TheoryArithNew::pivotAndUpdate, " + x_i.toString() + " should be a basic variable"); DebugAssert(tableaux.find(x_j) == tableaux.end(), "TheoryArithNew::pivotAndUpdate, " + x_j.toString() + " should be a non-basic variable"); // If trace is on for the simplex, print it out TRACE("simplex", "TheoryArithNew::pivotAndUpdate(", x_i.toString() + ", " + x_j.toString() + ", " + v.toString(), ")"); // The a_ij coefficient of the tableaux const Rational& a_ij = getTableauxEntry(x_i, x_j); // Let theta be the adjustment coefficient EpsRational theta((v - getBeta(x_i))/a_ij); // Set the new value to x_i (x_i becomes non-basic, hance sat) beta[x_i] = v; // x_i becomes non-basic, no need ==> it is sat unsatBasicVariables.erase(x_i); // Set the new value to x_j EpsRational b = getBeta(x_j); EpsRational new_x_j = beta[x_j] = b + theta; // Check if the variable is sat or unsat under the new assignment if (new_x_j < getLowerBound(x_j) || getUpperBound(x_j) < new_x_j) unsatBasicVariables.insert(x_j); else unsatBasicVariables.erase(x_j); // Go through all the variables that depend on x_j, and update their value (there will be at least one, i.e. x_i) // TODO: maybe optimise const set& dependent = (*dependenciesMap.find(x_j)).second; set::const_iterator it = dependent.begin(); set::const_iterator it_end = dependent.end(); // Go throught all the basic variables while (it != it_end) { // Get the current variable const Expr& x_k = *it; // If the basic variable is different from x_i update its value if (x_k != x_i) { // Get the a_kj coefficient from the tableaux const Rational& a_kj = getTableauxEntry(x_k, x_j); // Adjust the value (check fort sat/unsat, x_k is basic) b = getBeta(x_k); EpsRational x_k_new = beta[x_k] = b + theta * a_kj; // Check if the variable is sat or unsat under the new assignment if (x_k_new < getLowerBound(x_k) || getUpperBound(x_k) < x_k_new) unsatBasicVariables.insert(x_k); else unsatBasicVariables.erase(x_k); } // Go to the next one it ++; } // Last thing to do, pivot x_i and x_j pivot(x_i, x_j); } QueryResult TheoryArithNew::assertUpper(const Expr& x_i, const EpsRational& c, const Theorem& thm) { // If trace is on for the simplex, print it out TRACE("simplex", "TheoryArithNew::assertUpper(", x_i.toString() + ", " + c.toString(), ")"); // Check if the given expression is actually a variable DebugAssert(isLeaf(x_i), "TheoryArithNew::assertUpper wrong kind, expected an arithmetic leaf (variable) got " + x_i.toString()); // Check if the upper bound is worse then the last one if (getUpperBound(x_i) <= c) return (consistent == UNKNOWN? UNKNOWN : SATISFIABLE); // If the new bound is lower then the lower bound */ if (c < getLowerBound(x_i)) { // Create the explaining theorem explanation = d_rules->clashingBounds(getLowerBoundThm(x_i), thm); // Return unsatisfiable return UNSATISFIABLE; } // Since it is a tighter bound, propagate what can be propagate = true; // Set the new upper bound */ upperBound[x_i] = BoundInfo(c, thm); // If within the new bounds, return the previous state if (getBeta(x_i) <= c) return (consistent == UNKNOWN? UNKNOWN : SATISFIABLE); // Otherwise, if the variable is non-basic then update it's value if (!isBasic(x_i)) update(x_i, c); // Else its basic, and non-sat, add to the unsat set else unsatBasicVariables.insert(x_i); // Everything went fine, return OK (not complete, means not UNSAT) return UNKNOWN; } QueryResult TheoryArithNew::assertLower(const Expr& x_i, const EpsRational& c, const Theorem& thm) { // Check if the given expression is actually a variable DebugAssert(isLeaf(x_i), "TheoryArithNew::assertLower wrong kind, expected an arithmetic leaf (variable) got " + x_i.toString()); // If trace is on for the simplex, print it out TRACE("simplex", "TheoryArithNew::assertLower(", x_i.toString() + ", " + c.toString(), ")"); // Check if the upper bound is worse then the last one if (c <= getLowerBound(x_i)) return (consistent == UNKNOWN? UNKNOWN : SATISFIABLE); // Since it is a tighter bound, propagate what can be propagate = true; // If the new bound is lower then the bound */ if (c > getUpperBound(x_i)) { // Create the explaining theorem explanation = d_rules->clashingBounds(thm, getUpperBoundThm(x_i)); // Return unsatisfiable return UNSATISFIABLE; } // Set the new upper bound */ lowerBound[x_i] = BoundInfo(c, thm); // If within the new bounds, return the previous state if (c <= getBeta(x_i)) return (consistent == UNKNOWN? UNKNOWN : SATISFIABLE); // Otherwise, if the variable is non-basic then update it's value if (!isBasic(x_i)) update(x_i, c); // Else its basic, and non-sat, add to the unsat set else unsatBasicVariables.insert(x_i); // Everything went fine, return OK (not complete, means not UNSAT) return UNKNOWN; } QueryResult TheoryArithNew::assertEqual(const Expr& x_i, const EpsRational& c, const Theorem& thm) { // Assert the upper bound consistent = assertUpper(x_i, c, thm); // TODO: thm: = |- <= // If the return value is UNSAT return UNSAT if (consistent == UNSATISFIABLE) return UNSATISFIABLE; // Assert the lower bound consistent = assertLower(x_i, c, thm); // TODO: thm: = |- >= // Return the consistency return consistent; } void TheoryArithNew::checkSat(bool fullEffort) { // We should not be here if inconsistent DebugAssert(consistent != UNSATISFIABLE, "TheoryArithNew::checkSat : we are UNSAT before entering?!?!"); // Trace the check sat if simplex flag is on TRACE("simplex", "TheoryArithNew::checkSat(fullEffort=",fullEffort? "true" : "false", ")"); // Check if by backtracking we have more fresh variables than we expect if (assertedExprCount < assertedExpr.size()) updateFreshVariables(); // Do the simplex search if the database is not satisfiable (if inconsistent, we will not be here); if (consistent != SATISFIABLE || fullEffort) consistent = checkSatSimplex(); // If the result is inconsistent set the inconsistent flag if (consistent == UNSATISFIABLE) setInconsistent(explanation); // If we are not - consistent, check the integer satisfiability // if (consistent == SATISFIABLE) { // // If we asserted a lemma and it hasn't been processed yet, we just don't do anything // Theorem integer_lemma_thm = integer_lemma; // if (!integer_lemma_thm.isNull()) { // if (simplify(integer_lemma_thm.getExpr()).getRHS() == getEM()->trueExpr()) // consistent = checkSatInteger(); // else // consistent = UNKNOWN; // } else // // Lemma was not asserted, check integer sat // consistent = checkSatInteger(); // } // Trace the check sat if simplex flag is on TRACE("simplex", "TheoryArithNew::checkSat ==> ", consistent == UNSATISFIABLE? "UNSATISFIABLE" : "SATISFIABLE", ""); } QueryResult TheoryArithNew::checkSatInteger() { // Trace the check sat if simplex flag is on TRACE("simplex", "TheoryArithNew::checkSatInteger()", "", ""); // At this point we are REAL satisfiable, so we have to check the integers set::iterator x_i_it = intVariables.begin(); set::iterator x_i_it_end = intVariables.end(); // cerr << "Integer vars: "; // while (x_i_it != x_i_it_end) { // cerr << *x_i_it << " "; // ++ x_i_it; // } // cerr << endl; // // x_i_it = intVariables.begin(); // x_i_it_end = intVariables.end(); while (x_i_it != x_i_it_end) { // Get the left-hand variable of the tableaux const Expr& x_i = (*x_i_it); // Only do work for unsat integer variables if (isInteger(x_i)) { // Get the current assignment of x_i const EpsRational& beta = getBeta(x_i); // Check if it is an integer if (beta.isInteger()) { ++ x_i_it; continue; } // Since the variable is not an integer, split on it being <= [beta] and >= [beta] + 1 integer_lemma = d_rules->integerSplit(x_i, beta.getFloor()); TRACE("integer", "TheoryArithNew::checkSatInteger ==> lemma : ", integer_lemma, ""); enqueueFact(integer_lemma); // One split should be enough, return unknown return UNKNOWN; } // Go to the next row ++ x_i_it; } // We came through, huh, we are sat return SATISFIABLE; } QueryResult TheoryArithNew::checkSatSimplex() { Expr x_i; // The basic variable we will use EpsRational x_i_Value; // The current value of the variable x_i Expr x_j; // The non-basic variable we will use EpsRational x_j_Value; // The current value of the variable x_j Rational a_ij; // The coefficient wwhen expanding x_i using x_j in the tableaux bool x_j_Found; // Did we find a suitable one EpsRational l_i; // Lower bound of x_i EpsRational u_i; // Upper bound of x_i // Trace the size of the tableaux and the unsat TRACE("arith_atoms", "Tableaux size: ", tableaux.size(), ""); TRACE("arith_atoms", "UNSAT vars: ", unsatBasicVariables.size(), ""); // The main loop while (unsatBasicVariables.size()) { // The first unsat variable information x_i = *unsatBasicVariables.begin(); TebleauxMap::iterator it = tableaux.find(x_i); x_i_Value = getBeta(x_i); l_i = getLowerBound(x_i); u_i = getUpperBound(x_i); // If the variable doesn't obey the lower bound if (l_i > x_i_Value) { // Did we find a suitable x_j, NOT YET x_j_Found = false; // Find the smalles non-basic x_j that can improve x_i const Expr& x_i_RightSide = (*it).second.getExpr()[1]; int non_basics_i_end = x_i_RightSide.arity(); for(int non_basics_i = 0; non_basics_i < non_basics_i_end; ++ non_basics_i) { // Get the info on the current variable x_j = x_i_RightSide[non_basics_i][1]; a_ij = x_i_RightSide[non_basics_i][0].getRational(); x_j_Value = getBeta(x_j); // If there is slack for improving x_i using x_j then do it if (a_ij > 0) { if (x_j_Value < getUpperBound(x_j)) { x_j_Found = true; break; } } else { if (x_j_Value > getLowerBound(x_j)) { x_j_Found = true; break; } } } // If none of the variables allows for slack, the tableaux is unsatisfiable if (!x_j_Found) { // Generate the explanation explanation = getLowerBoundExplanation(it); // Return unsat return UNSATISFIABLE; } // Otherwise do pivotAndUpdate and continue with the loop pivotAndUpdate(x_i, x_j, l_i); } else // If the variable doesn't obey the upper bound if (x_i_Value > u_i) { // Did we find a suitable x_j, NOT YET x_j_Found = false; // Find the smalles non-basic x_j that can improve x_i const Expr& x_i_RightSide = (*it).second.getExpr()[1]; int non_basics_i_end = x_i_RightSide.arity(); for(int non_basics_i = 0; non_basics_i < non_basics_i_end; ++ non_basics_i) { // Get the info on the current variable x_j = x_i_RightSide[non_basics_i][1]; a_ij = x_i_RightSide[non_basics_i][0].getRational(); x_j_Value = getBeta(x_j); // If there is slack for improving x_i using x_j then do it if (a_ij < 0) { if (x_j_Value < getUpperBound(x_j)) { x_j_Found = true; break; } } else if (x_j_Value > getLowerBound(x_j)) { x_j_Found = true; break; } } // If none of the variables allows for slack, the tableaux is unsatisfiable if (!x_j_Found) { // Generate the explanation explanation = getUpperBoundExplanation(it); // Return unsat return UNSATISFIABLE; } // Otherwise do pivotAndUpdate and continue with the loop pivotAndUpdate(x_i, x_j, u_i); } else // Due to backtracking a unsat might become sat, just erase it unsatBasicVariables.erase(x_i); // If trace is on, printout the current valuation and the tableaux TRACE("simplex", "TheoryArithNew::checkSatSimplex ==> new tableaux : \n", tableauxAsString(), ""); TRACE("simplex", "TheoryArithNew::checkSatSimplex ==> new bounds : \n", boundsAsString(), ""); TRACE("simplex", "TheoryArithNew::checkSatSimplex ==> unsat : \n", unsatAsString(), ""); }; // Since there is no more unsat constraints we are satisfiable return SATISFIABLE; } Rational TheoryArithNew::getTableauxEntry(const Expr& x_i, const Expr& x_j) { return findCoefficient(x_j, tableaux[x_i].getExpr()[1]); } const Rational& TheoryArithNew::findCoefficient(const Expr& var, const Expr& expr) { // The zero coefficient static Rational zeroCoefficient(0); // The given expression must be a sum DebugAssert(isPlus(expr), "TheoryArithNew::findCoefficient : expression must be a sum : " + expr.toString()); // Go through the sum and find the coefficient int left = 0; int right = expr.arity() - 1; int i; while (left <= right) { // Take the middle one i = (left + right ) / 2; // Current expression const Expr& mult = expr[i]; // Every summand must be a multiplication with a rational DebugAssert(isMult(mult) && isRational(mult[0]), "TheoryArithNew::findCoefficient : expression must be a sum of multiplications: " + expr.toString()); // If the variable is the same return the coefficient int cmp = compare(mult[1], var); if (cmp == 0) return mult[0].getRational(); else if (cmp > 0) left = i + 1; else right = i - 1; } // Not found, return 0 return zeroCoefficient; } TheoryArithNew::EpsRational TheoryArithNew::getLowerBound(const Expr& x) const { // Try and find the lower bound in the map CDMap::iterator find = lowerBound.find(x); // If not found return +infinity as the default value, othervise return the value if (find == lowerBound.end()) return EpsRational::MinusInfinity; else return (*find).second.bound; } TheoryArithNew::EpsRational TheoryArithNew::getUpperBound(const Expr& x) const { // Try and find the upper bound in the map CDMap::iterator find = upperBound.find(x); // If not found return -infinity as the default value, othervise return the value if (find == upperBound.end()) return EpsRational::PlusInfinity; else return (*find).second.bound; } Theorem TheoryArithNew::getLowerBoundThm(const Expr& x) const { // Try and find the upper bound in the map CDMap::iterator find = lowerBound.find(x); // It has to be found DebugAssert(find != lowerBound.end(), "TheoryArithNew::getLowerBoundThm, theorem not found for " + x.toString()); // Return the bound theorem return (*find).second.theorem; } Theorem TheoryArithNew::getUpperBoundThm(const Expr& x) const { // Try and find the upper bound in the map CDMap::iterator find = upperBound.find(x); // It has to be found DebugAssert(find != upperBound.end(), "TheoryArithNew::getUpperBoundThm, theorem not found for " + x.toString()); // Return the bound theorem return (*find).second.theorem; } TheoryArithNew::EpsRational TheoryArithNew::getBeta(const Expr& x) { // Try to find the beta value in the map CDMap::iterator find = beta.find(x); if (find == beta.end()) { // If not found return 0 (no need for sat/unsat, it's allways sat) return beta[x] = EpsRational::Zero; // Check if the variable is sat or unsat under the new assignment if (EpsRational::Zero < getLowerBound(x) || getUpperBound(x) < EpsRational::Zero) unsatBasicVariables.insert(x); else unsatBasicVariables.erase(x); } else // If found, just return it return (*find).second; } void TheoryArithNew::assertFact(const Theorem& assertThm) { // Get the expression to be asserted const Expr& expr = assertThm.getExpr(); // If tracing arithmetic, print out the expression to be asserted TRACE("simplex", "TheoryArithNew::assertFact(", expr, ")"); TRACE("simplex", "asserted: ", assertedExpr.size(), ""); TRACE("simplex", "counted: ", assertedExprCount, ""); TRACE("arith_atoms", "Assert: ", expr.toString(), ""); // Check if by backtracking we have more fresh variables than we expect if (assertedExprCount < assertedExpr.size()) updateFreshVariables(); // Get the constraint partsreturn const Expr& leftSide = expr[0]; // The left side of the constraint const Expr& rightSide = expr[1]; // The right side of the constraint int kind = expr.getKind(); // The relational symbol, should be one of LT, LE, GT, GE. EQ was rewritten as LE and GE so its not here // The expression must be an inequality (sum a_1*x_1 .. a_n*x_n) @ b DebugAssert(isIneq(expr) , "TheoryArithNew::assertFact wrong kind, expected inequality" + expr.toString()); DebugAssert(isPlus(rightSide) || (isMult(rightSide) && isRational(rightSide[0]) && isLeaf(rightSide[1])), "TheoryArithNew::assertFact wrong kind, expected sum on the right side opr a simple 1*x" + expr.toString()); DebugAssert(isRational(leftSide), "TheoryArithNew::assertFact wrong kind, expected rational on the right side" + expr.toString()); // Get the rational value on the right side Rational leftSideValue = leftSide.getRational(); // The rational bound on the constraint Rational c = leftSideValue; // The variable to be constrained Expr var; // Theorem of the assertion Theorem assert = assertThm; // For now we have that leftSide @ (c1x1 + c2x2 + ... cnxn) = rightSide // If rightSide is not a sum constraint is atomic (leftSide @ a*x) if (!isPlus(rightSide)) { // Tee left side in this case should be 1*x DebugAssert(rightSide[0].isRational() && rightSide[0].getRational() == 1, "TheoryArithNew::assertFact, left side should be multiplication by one"); // Change the assert theorem to remove the 1*x to x assert = iffMP(assert, substitutivityRule(expr, reflexivityRule(leftSide), d_rules->oneElimination(rightSide))); // The variable will just be x1 (if var is not already present in the tableaux, it will be non-basic) var = rightSide[1]; // IMPORTANT!!!, when giving explanations, it should be of the same form // If an integer, add it to the integer set if (isInteger(var)) intVariables.insert(var); } else { // Get the theorem that corresponds to the introduction of the new variable var = leftSide const Theorem& introductionThm = getVariableIntroThm(rightSide); // Take the new variable out var = introductionThm.getExpr()[0]; // Change the theorem for the assertion so that it involves the new variable, i.e. c < rightSide, var = rightSide |- c < var assert = iffMP(assertThm, substitutivityRule(expr, 1, symmetryRule(introductionThm))); // Insert all the integer variables into the integer set if (isInteger(var)) { intVariables.insert(var); int i_end = rightSide.arity(); for(int i = 0; i < i_end; ++ i) intVariables.insert(rightSide[i][1]); } else { int i_end = rightSide.arity(); for(int i = 0; i < i_end; ++ i) if (isInteger(rightSide[i][1])) intVariables.insert(rightSide[i][1]); } } // Make the BoundInfo object for theory propagation EpsRational bound; // By default we don't propagate propagate = false; // Remember the old bound EpsRational oldBound; // Finnaly assert the right constraint switch (kind) { case LT: oldBound = getLowerBound(var); // c < var, convert to c + epsilon <= var and assert it consistent = assertLower(var, bound = EpsRational(c, +1), assert); break; case LE: oldBound = getLowerBound(var); // c <= var, assert the lower bound consistent = assertLower(var, bound = c, assert); break; case GT: oldBound = getUpperBound(var); // c > var, convert to c - epsilon >= var and assert it consistent = assertUpper(var, bound = EpsRational(c, -1), assert); break; case GE: oldBound = getUpperBound(var); // c >= var, assert the upper bound consistent = assertUpper(var, bound = c, assert); break; case EQ: // c == var, assert the equality consistent = assertEqual(var, bound = c, assert); // For now, don't propagate anything propagate = false; // TODO: some propagation is in place here (negations) break; default: //How did we get here FatalAssert(false, "Theory_Arith::assertFact, control should not reach here"); break; } // If tracing arithmetic, print out the new tableaux and the current bounds TRACE("simplex", "TheoryArithNew::assertFact ==> ", consistent == UNSATISFIABLE? "UNSATISFIABLE" : consistent == UNKNOWN? "UNKNOWN" : "SATISFIABLE", ""); TRACE("simplex", "TheoryArithNew::assertFact ==> new tableaux : \n", tableauxAsString(), ""); TRACE("simplex", "TheoryArithNew::assertFact ==> new bounds : \n", boundsAsString(), ""); TRACE("simplex", "TheoryArithNew::assertFact ==> unsat : \n", unsatAsString(), ""); // If the result is inconsistent set the inconsistent flag if (consistent == UNSATISFIABLE) setInconsistent(explanation); // Not inconsistent, propagate all from this assertion if (propagate) propagateTheory(assertThm.getExpr(), bound, oldBound); } Theorem TheoryArithNew::getVariableIntroThm(const Expr& rightSide) { // Try to find the expression in the map TebleauxMap::iterator find = freshVariables.find(rightSide); // If not in tableaux, add it and assign it a new variable if (find == freshVariables.end()) { // Get the common rules CommonProofRules* c_rules = getCommonRules(); // Create a new variable (\exists x . rightSide = x) Theorem thm = c_rules->varIntroRule(rightSide); // Skolemise it, to get an equality (\exists x . rightSide = x) <==> rightSide = c, then infer |- rightSide = c thm = c_rules->iffMP(thm, c_rules->skolemizeRewrite(thm.getExpr())); // Reverse the equality into standard form thm = symmetryRule(thm); // Add the theorem to the variable introduction map (this is the theorem we return) Theorem returnThm = freshVariables[rightSide] = thm; // Now, flatten the equality modulo tableaux thm = substAndCanonizeModTableaux(thm); // Get the skolem constant that was introduced (|- c = leftSide) const Expr& var = thm.getExpr()[0]; // Also add it to the tableaux tableaux[var] = thm; // Update the dependencies updateDependenciesAdd(var, thm.getExpr()[1]); // Add it to the expressions map assertedExpr.push_back(Expr(EQ, var, rightSide)); assertedExprCount = assertedExprCount + 1; // Compute the value of the new variable using the tableaux updateValue(var, rightSide); // Return the variable return returnThm; } // Otherwise we have it, so return it return (*find).second; } void TheoryArithNew::updateValue(const Expr& var, const Expr& e) { // The initial value EpsRational varValue(0); // Go through the sum and compute the value int i_end = e.arity(); for (int i = 0; i < i_end; ++ i) varValue += getBeta(e[i][1]) * e[i][0].getRational(); // Update the beta beta[var] = varValue; // Check if the variable is sat or unsat under the new assignment if (varValue < getLowerBound(var) || getUpperBound(var) < varValue) unsatBasicVariables.insert(var); else unsatBasicVariables.erase(var); } string TheoryArithNew::tableauxAsString() const { // The string we are building string str; // Start from the begining TebleauxMap::const_iterator row = tableaux.begin(); TebleauxMap::const_iterator row_end = tableaux.end(); // Print all the rows while (row != tableaux.end()) { // Print the equality str = str + ((*row).second).getExpr().toString() + "\n"; // Continue to the next row row ++; } // Return the string representation return str; } string TheoryArithNew::unsatAsString() const { // The string we are building string str; // Start from the begining set::const_iterator it = unsatBasicVariables.begin(); set::const_iterator it_end = unsatBasicVariables.end(); // Print all the rows while (it != it_end) { // Print the equality str = str + (*it).toString() + " "; // Continue to the next row it ++; } // Return the string representation return str; } string TheoryArithNew::boundsAsString() { // The string we are building string str; // Set containing all the variables set all_variables; // Go throught the tableaux and pick up all the variables TebleauxMap::const_iterator it = tableaux.begin(); TebleauxMap::const_iterator it_end = tableaux.end(); for(; it != it_end; it ++) { // Add the basic variable to the set all_variables.insert((*it).first); // Go through all the expression variables and add them to the set const Expr& rightSide = (*it).second.getExpr()[1]; int term_i_end = rightSide.arity(); for(int term_i = 0; term_i < term_i_end; ++ term_i) all_variables.insert(rightSide[term_i][1]); } // Go throught the bounds map and pickup all the variables CDMap::iterator bounds_it; for (bounds_it = lowerBound.begin(); bounds_it != lowerBound.end(); bounds_it ++) all_variables.insert((*bounds_it).first); for (bounds_it = upperBound.begin(); bounds_it != upperBound.end(); bounds_it ++) all_variables.insert((*bounds_it).first); // Start from the begining set::iterator var_it = all_variables.begin(); set::iterator var_it_end = all_variables.end(); // Print all the rows while (var_it != var_it_end) { // The current variable const Expr& var = *var_it; // Print the equality str += getLowerBound(var).toString() + " <= " + var.toString() + "(" + getBeta(var).toString() + ") <= " + getUpperBound(var).toString() + "\n"; // Continue to the next variable var_it ++; } // Return the string representation return str; } // The infinity constant const TheoryArithNew::EpsRational TheoryArithNew::EpsRational::PlusInfinity(PLUS_INFINITY); // The negative infinity constant const TheoryArithNew::EpsRational TheoryArithNew::EpsRational::MinusInfinity(MINUS_INFINITY); // The negative infinity constant const TheoryArithNew::EpsRational TheoryArithNew::EpsRational::Zero; Theorem TheoryArithNew::substAndCanonizeModTableaux(const Theorem& eq) { // If subst is empty, just return if(tableaux.empty()) return eq; // Get the expression of the equality const Expr& eqExpr = eq.getExpr(); // Check if the equality if in the canonic form DebugAssert(eqExpr.getKind() == EQ, "TheoryArithNew::substAndCanonize, expected equality " + eqExpr.toString()); // Get the left side of the equality const Expr& rightSide = eqExpr[1]; // Do the actual substitution in the eqExpr Theorem thm = substAndCanonizeModTableaux(rightSide); // If the substitution had no result just return the original equation if(thm.getRHS() == rightSide) return eq; // Return the theorem return iffMP(eq, substitutivityRule(eq.getExpr(), 1, thm)); } Theorem TheoryArithNew::substAndCanonizeModTableaux(const Expr& sum) { Theorem res; // The resulting theorem vector thms; // The theorems of the changed terms for the substitution vector changed; // The indices of the changed terms for the substitution // Trace the canonisation TRACE("simplex", "TheoryArithNew::substAndCanonizeModTableaux(", sum, ")"); // Check if the equality if in the canonic form DebugAssert(sum.getKind() == PLUS, "TheoryArithNew::substAndCanonize, expected sum " + sum.toString()); // Go throught the sum and try to substitute the variables int term_index_end = sum.arity(); for(int term_index = 0; term_index < term_index_end; ++ term_index) { const Expr& term = sum[term_index]; // The current term expression (a*x) const Expr& var = term[1]; // The variable of the current term // Find the variable in the map TebleauxMap::iterator find = tableaux.find(var); // If found, substitute it if (find != tableaux.end()) { // Substitute the variable Theorem termTheorem = canonThm(substitutivityRule(term, 1, (*find).second)); // Check that the result is not trivial DebugAssert(termTheorem.getExpr() != term, "substAndCanonizeModTableaux: got the same term in substitution"); // Push it to the theorems vector thms.push_back(termTheorem); // Add the index to the changed vector changed.push_back(term_index); } } // Do the actual substitution and canonize the result if(thms.size() > 0) { // Substitute the changed subterms into the term res = substitutivityRule(sum, changed, thms); // Canonise the result res = canonThm(res); } else // Nothing happened, just return the reflexivity res = reflexivityRule(sum); // Return the result return res; } void TheoryArithNew::substAndCanonizeTableaux(const Theorem& eq) { Theorem result; // The explaining theorem // Trace TRACE("simplex", "TheoryArithNew::substAndCanonizeTableaux(", eq.getExpr(), ")"); // Get the expression of the equality const Expr& eqExpr = eq.getExpr(); // Check if the equality if in the canonic form DebugAssert(eqExpr.getKind() == EQ, "TheoryArithNew::substAndCanonize, expected equality " + eqExpr.toString()); // Get the variable of the substitution const Expr& var = eqExpr[0]; // Check if there are variables that depend on x_j DependenciesMap::iterator find = dependenciesMap.find(var); if (find != dependenciesMap.end()) { // Go through all the variables that depend on x_j, and update their value set& dependent = (*find).second; set::iterator it = dependent.begin(); set::iterator it_end = dependent.end(); for(; it != it_end; ++ it) { // Get the expression and the right side of the row from the tableaux const Expr& leftSide = *it; TebleauxMap::iterator row = tableaux.find(leftSide); const Expr& rowExpr = (*row).second.getExpr(); const Expr& rowRightSide = rowExpr[1]; // Go through the sum and try to substitute int right = rowRightSide.arity() - 1; int left = 0; int term_i; while (left <= right) { // Get the middle one term_i = (left + right) / 2; // Get the comparison of the variables int cmp = compare(rowRightSide[term_i][1], var); // If the variable is found if (cmp == 0) { // Do the substitution and canonise result = canonThm(substitutivityRule(rowRightSide[term_i], 1, eq)); // Do the substitution and canonise in the sum result = canonThm(substitutivityRule(rowRightSide, term_i, result)); // Do the substitution result = substitutivityRule(rowExpr, 1, result); // Get the new expression const Expr& newRowRightSide = result.getRHS()[1]; // Update the dependencies of the varriables in the expression updateDependencies(rowRightSide, newRowRightSide, leftSide, var); // That's it, remember the new row (*row).second = iffMP((*row).second, result); // Variables don't repeat, we can just break out break; } else if (cmp > 0) left = term_i + 1; else right = term_i - 1; } } // Now nobody depends on var anymore, just erase it dependent.clear(); } } Theorem TheoryArithNew::pivotRule(const Theorem& eq, const Expr& var) { Theorem result; // The theorem explaining the result // Get the expression const Expr& eqExpr = eq.getExpr(); const Expr& right_side = eqExpr[1]; const Expr& left_side = eqExpr[0]; // Trace if askedTheorem canonLeft = d_rules->canonMult(thm.getExpr()[0]); TRACE("simplex", "TheoryArithNew::pivotRule(", eqExpr.toString() + ", ", var.toString() + ")"); // Eq must be an equation with the sum on the left side and a leaf on the right side (variable) DebugAssert(eqExpr.getKind() == EQ, "TheoryArithNew::pivotRule, expected an equality : " + eqExpr.toString()); DebugAssert(right_side.getKind() == PLUS, "TheoryArithNew::pivotRule, expected a sum on the left-hand side : " + eqExpr.toString()); DebugAssert(isLeaf(left_side), "TheoryArithNew::pivotRule, expected a leaf (variable) on the right-hand side : " + eqExpr.toString()); // Find the term of var in the left-hand side of eq int term_i_end = right_side.arity(); for(int term_i = 0; term_i < term_i_end; ++ term_i) // If found do the stuff if (right_side[term_i][1] == var) { // This is the term we need and the rational we need const Expr& termExpr = right_side[term_i]; const Expr& termVar = termExpr[1]; const Rational& termRat = termExpr[0].getRational(); // Construct the expression we will add to the equality const Expr& minusTermExpr = multExpr(rat(-termRat), termVar); const Expr& minusVarExpr = multExpr(rat(-1), left_side); // Add the above expressions to the to the equality result = iffMP(eq, d_rules->plusPredicate(left_side, right_side, plusExpr(minusTermExpr, minusVarExpr), EQ)); // Canonise the right-hand side result = transitivityRule(result, canon(result.getExpr()[1])); // Canonise the left-hand side result = transitivityRule(symmetryRule(canon(result.getExpr()[0])), result); // Multiply by the inverse of the rational constant (negated and ^-1) result = iffMP(result, d_rules->multEqn(result.getExpr()[0], result.getExpr()[1], rat(-1/termRat))); // Canonise the left-hand side result = transitivityRule(result, canon(result.getExpr()[1])); // Canonise the right=hand side result = transitivityRule(symmetryRule(canon(result.getExpr()[0])), result); // Rewrite 1*x => x in the left-hand side result = transitivityRule(symmetryRule(d_rules->oneElimination(result.getExpr()[0])), result); // Trace the result TRACE("simplex", "TheoryArithNew::pivotRule ==> ", result.getExpr().toString(), ""); // We are done, there is just one variable there return result; } // If not found, there is something wrong DebugAssert(false, "TheoryArithNew::pivotRule, " + var.toString() + " does not occur in " + eqExpr.toString()); // Dummy return return result; } Theorem TheoryArithNew::getLowerBoundExplanation(const TebleauxMap::iterator& var_it) { vector upperBounds; // Vector of the upper-bound theorems // Get the tableaux theorem explaining the leftside = var Theorem tableauxTheorem = (*var_it).second; // Get the variable on the right side const Expr& var = (*var_it).first; // Get the expression involved (leftSide = var) const Expr& rightSide = tableauxTheorem.getExpr()[1]; // Go through the left side and pick up the apropriate lower and upper bounds int leftSide_i_end = rightSide.arity(); for(int leftSide_i = 0; leftSide_i < leftSide_i_end; ++ leftSide_i) { // Get the rational const Expr& a = rightSide[leftSide_i][0]; // Get the variable const Expr& x = rightSide[leftSide_i][1]; // The positive ones make up the upper bounds (x < u => a * x < a * u) if (a.getRational() > 0) { // Get the upper bound x < u Theorem thm = getUpperBoundThm(x); // Multiply if by a ==> u_i * a > x * a thm = iffMP(thm, d_rules->multIneqn(thm.getExpr(), a)); // Canonise the left and the right side Theorem canonRight = d_rules->canonMultTermConst(thm.getExpr()[1][1], thm.getExpr()[1][0]); Theorem canonLeft = d_rules->canonMultConstConst(thm.getExpr()[0][0], thm.getExpr()[0][1]); // Substitute the canonised to the inequality thm = iffMP(thm, substitutivityRule(thm.getExpr(), canonLeft, canonRight)); // Add the bound to the vector of upper bounds (|- c_x > a * x) upperBounds.push_back(thm); } // The negative ones make up the lower bounds (x > l => a * x < a * l) else { // Get the lower bound l < x Theorem thm = getLowerBoundThm(x); // Multiply if by a |- l * a < x * a thm = iffMP(thm, d_rules->multIneqn(thm.getExpr(), a)); // Canonise the left and the right side Theorem canonRight = d_rules->canonMultTermConst(thm.getExpr()[1][1], thm.getExpr()[1][0]); Theorem canonLeft = d_rules->canonMultConstConst(thm.getExpr()[0][0], thm.getExpr()[0][1]); // Substitute the canonised to the inequality thm = iffMP(thm, substitutivityRule(thm.getExpr(), canonLeft, canonRight)); // Add the bound to the vector of upper bounds (|- c_x > a * x) upperBounds.push_back(thm); } } // Add up all the inequalities to get a C = \sum c_i > rightSide Theorem sumInequalities = upperBounds[0]; for(unsigned int i = 1; i < upperBounds.size(); i ++) { // Add the inequalities sumInequalities = d_rules->addInequalities(sumInequalities, upperBounds[i]); // Canonise the left and the right side Theorem canonLeft = d_rules->canonPlus(sumInequalities.getExpr()[0]); Theorem canonRight = d_rules->canonPlus(sumInequalities.getExpr()[1]); // Substitute the canonised to the inequality sumInequalities = iffMP(sumInequalities, substitutivityRule(sumInequalities.getExpr(), canonLeft, canonRight)); } // Substitute to get C > rightSide ==> C > var Theorem varUpperBound = substitutivityRule(sumInequalities.getExpr(), 1, symmetryRule(tableauxTheorem)); // MP to get C > var varUpperBound = iffMP(sumInequalities, varUpperBound); // Get the lower bound on the rigth side variable (l_var < var) Theorem varLowerBound = getLowerBoundThm(var); // Return the clashing bound theorem return d_rules->clashingBounds(varLowerBound, varUpperBound); } Theorem TheoryArithNew::getUpperBoundExplanation(const TebleauxMap::iterator& var_it) { vector lowerBounds; // Vector of the upper-bound theorems // Get the tableaux theorem explaining the leftside = var Theorem tableauxTheorem = (*var_it).second; // Get the variable on the right side const Expr& var = (*var_it).first; // Get the expression involved (var = rightSide) const Expr& rightSide = tableauxTheorem.getExpr()[1]; // Trace if requested TRACE("explanations", "Generating explanation for the tableaux row ", tableauxTheorem.getExpr(), ""); // Go through the right side and pick up the apropriate lower and upper bounds int rightSide_i_end = rightSide.arity(); for(int rightSide_i = 0; rightSide_i < rightSide_i_end; ++ rightSide_i) { // Get the rational const Expr& a = rightSide[rightSide_i][0]; // Get the variable const Expr& x = rightSide[rightSide_i][1]; // The positive ones make up the lower bounds (x > l => a * x > a * l) if (a.getRational() > 0) { // Get the lower bound l < x Theorem thm = getLowerBoundThm(x); TRACE("explanations", "Got ", thm.getExpr(), ""); // Multiply if by a ==> l * a < x * a thm = iffMP(thm, d_rules->multIneqn(thm.getExpr(), a)); TRACE("explanations", "Got ", thm.getExpr(), ""); // Canonise the left and the right side Theorem canonRight = d_rules->canonMultTermConst(thm.getExpr()[1][1], thm.getExpr()[1][0]); Theorem canonLeft = d_rules->canonMultConstConst(thm.getExpr()[0][0], thm.getExpr()[0][1]); // Substitute the canonised to the inequality thm = iffMP(thm, substitutivityRule(thm.getExpr(), canonLeft, canonRight)); TRACE("explanations", "Got ", thm.getExpr(), ""); // Add the bound to the vector of upper bounds (|- c_x < a * x) lowerBounds.push_back(thm); } // The negative ones make up the upper bounds (x < u => a * x > a * u) else { // Get the upper bound u > x Theorem thm = getUpperBoundThm(x); TRACE("explanations", "Got ", thm.getExpr(), ""); // Multiply it by a |- u * a > x * a thm = iffMP(thm, d_rules->multIneqn(thm.getExpr(), a)); TRACE("explanations", "Got ", thm.getExpr(), ""); // Canonise the left and the right side Theorem canonRight = d_rules->canonMultTermConst(thm.getExpr()[1][1], thm.getExpr()[1][0]); Theorem canonLeft = d_rules->canonMultConstConst(thm.getExpr()[0][0], thm.getExpr()[0][1]); // Substitute the canonised to the inequality thm = iffMP(thm, substitutivityRule(thm.getExpr(), canonLeft, canonRight)); TRACE("explanations", "Got ", thm.getExpr(), ""); // Add the bound to the vector of upper bounds (|- c_x < a * x) lowerBounds.push_back(thm); } } // Add up all the inequalities to get a \sum c_i = C > rightSide Theorem sumInequalities = lowerBounds[0]; for(unsigned int i = 1; i < lowerBounds.size(); i ++) { // Add the inequalities sumInequalities = d_rules->addInequalities(sumInequalities, lowerBounds[i]); TRACE("explanations", "Got sum ", sumInequalities.getExpr(), ""); // Canonise the left and the right side Theorem canonLeft = d_rules->canonPlus(sumInequalities.getExpr()[0]); Theorem canonRight = d_rules->canonPlus(sumInequalities.getExpr()[1]); // Substitute the canonised to the inequality sumInequalities = iffMP(sumInequalities, substitutivityRule(sumInequalities.getExpr(), canonLeft, canonRight)); } // Trace if requested TRACE("explanations", "Got sum ", sumInequalities.getExpr(), ""); // Substitute to get C < leftSide ==> C < var Theorem varLowerBound = substitutivityRule(sumInequalities.getExpr(), 1, symmetryRule(tableauxTheorem)); // MP to get C < var varLowerBound = iffMP(sumInequalities, varLowerBound); // Trace if requested TRACE("explanations", "Got lower bound ", varLowerBound.getExpr(), ""); // Get the lower bound on the rigth side variable (var > l_var) Theorem varUpperBound = getUpperBoundThm(var); // Trace if requested TRACE("explanations", "Got upper bound ", varUpperBound.getExpr(), ""); TRACE("explanations", "The var value (", var, ")" + getBeta(var).toString()); // Return the clashing bound theorem return d_rules->clashingBounds(varLowerBound, varUpperBound); } void TheoryArithNew::updateFreshVariables() { unsigned int size = assertedExpr.size(); unsigned int i; for (i = assertedExprCount; i < size; ++ i) //Update the value updateValue(assertedExpr[i][0], assertedExpr[i][1]); // Update the asserted count to be the size of the vector assertedExprCount = i; } void TheoryArithNew::updateDependenciesAdd(const Expr& var, const Expr& sum) { // Trace it TRACE("tableaux_dep", "updateDependenciesAdd(", var.toString() + ", ", sum.toString() + ")"); // Go through the sum and add var to the dependencies of that term variable Expr::iterator term = sum.begin(); Expr::iterator term_end = sum.end(); for(; term != term_end; term ++) dependenciesMap[(*term)[1]].insert(var); } void TheoryArithNew::updateDependenciesRemove(const Expr& var, const Expr& sum) { // Trace it TRACE("tableaux_dep", "updateDependenciesRemove(", var.toString() + ", ", sum.toString() + ")"); // Go through the sum and remove var to the dependencies of that term variable Expr::iterator term = sum.begin(); Expr::iterator term_end = sum.end(); for(; term != term_end; term ++) dependenciesMap[(*term)[1]].erase(var); } void TheoryArithNew::updateDependencies(const Expr& oldSum, const Expr& newSum, const Expr& dependentVar, const Expr& skipVar) { // Trace it TRACE("tableaux_dep", "updateDependencies(", oldSum.toString() + ", " + newSum.toString() + ", " + dependentVar.toString(), ")"); // Since the sums are ordered by variables, we can just to a "merge sort" int oldSum_i = 0, newSum_i = 0; int oldSum_end = oldSum.arity(), newSum_end = newSum.arity(); // Get the first variables while (oldSum_i < oldSum_end && newSum_i < newSum_end) { // Get the variable references const Expr oldVar = oldSum[oldSum_i][1]; const Expr newVar = newSum[newSum_i][1]; // If variables equal, just skip, everything is ok if (oldVar == newVar) { ++ oldSum_i; ++ newSum_i; continue; } // Otherwise do the work with the smaller one if (oldVar > newVar) { // Old variable has dissapeared, remove dependent from its list if (oldVar != skipVar) dependenciesMap[oldVar].erase(dependentVar); // Move the old variable forward ++ oldSum_i; } else { // New variable has appeared, insert dependent to its list if (newVar != skipVar) dependenciesMap[newVar].insert(dependentVar); // Move the new variable forward ++ newSum_i; } } // If there is leftovers in the old sum, just do the removals while (oldSum_i < oldSum_end) { // Get the var, and increase the index const Expr& var = oldSum[oldSum_i ++][1]; // Update the dependency if (var != skipVar) dependenciesMap[var].erase(dependentVar); } while (newSum_i < newSum_end) { // Get the var, and increase the index const Expr& var = newSum[newSum_i ++][1]; // Update the dependency if (var != skipVar) dependenciesMap[var].insert(dependentVar); } } void TheoryArithNew::registerAtom(const Expr& e) { // Trace it TRACE("propagate_arith", "registerAtom(", e.toString(), ")"); TRACE("arith_atoms", "", e.toString(), ""); // If it is a atomic formula, add it to the map if (e.isAbsAtomicFormula()) { Expr rightSide = e[1]; int kind = e.getKind(); Rational leftSide = e[0].getRational(); // The eps bound we'll be using EpsRational bound; // Depending on the type of the inequality define the bound switch (kind) { case LT: bound = EpsRational(leftSide, +1); break; case LE: bound = leftSide; break; case GT: bound = EpsRational(leftSide, -1); break; case GE: bound = leftSide; break; default: // How did we get here FatalAssert(false, "TheoryArithNew::registerAtom: control should not reach here" + e.toString()); } // Bound has been set, now add the allBounds.insert(ExprBoundInfo(bound, e)); } // // Printout the current set of atoms in the set // cout << "ALL BOUNDS:" << endl; // BoundInfoSet::iterator it = allBounds.begin(); // while (it != allBounds.end()) { // cout << (*it).e << endl; // ++ it; // } } void TheoryArithNew::propagateTheory(const Expr& assertExpr, const EpsRational& bound, const EpsRational& oldBound) { // Trace it TRACE("propagate_arith", "propagateTheory(", assertExpr.toString() + ", " + bound.toString(), ")"); // Make the bound info object, so that we can search for it ExprBoundInfo boundInfo(bound, assertExpr); // Get the exression on the right side hand Expr rightSide = assertExpr[1]; // Get the kid of the disequality int kind = assertExpr.getKind(); // Check wheather the kind is one of LT, LE, GT, GE DebugAssert(kind == LT || kind == LE || kind == GT || kind == GE , "TheoryArithNew::propagateTheory : expected an inequality"); // If the bound is of the type LT or LE we go up if (kind == LT || kind == LE) { // Find the asserted fact in the set (it must be there) BoundInfoSet::iterator find = allBounds.lower_bound(boundInfo); BoundInfoSet::iterator find_end = allBounds.lower_bound(ExprBoundInfo(oldBound, assertExpr)); // If we are at the begining, or not found, just exit if (find == find_end) return; // Now, go up until reached wrong right side (skip the first one, its the same as given) while (find != find_end) { // Go up; -- find; // Get the theorem of the find const Expr& findExpr = (*find).e; // Get the bound of the find const EpsRational findRat = (*find).bound; // Get the kind of the expression in the theorem int findExprKind = findExpr.getKind(); // Check if the right sides are the same if (rightSide != findExpr[1]) break; // Construct the theorem object Theorem lemma; // Check the type and equeue the lemma if (findExprKind == LT || findExprKind == LE) // Imply the weaker inequality lemma = d_rules->implyWeakerInequality(assertExpr, findExpr); else // Imply the negation of the impossible inequality lemma = d_rules->implyNegatedInequality(assertExpr, findExpr); TRACE("propagate_arith", "lemma ==>", lemma.toString(), ""); TRACE("arith_atoms", "Propagate: ", lemma.getExpr().toString(), ""); // Put it across enqueueFact(lemma); } } // If the bound is of the type GT or GE we go down else { // Find the asserted fact in the set (it must be there) BoundInfoSet::iterator find = allBounds.upper_bound(boundInfo); BoundInfoSet::iterator find_end = allBounds.upper_bound(ExprBoundInfo(oldBound, assertExpr)); // Now, go down until reached wrong right side (skip the first one, its the same as given) while (find != find_end) { // Get the bound of the find const EpsRational findRat = (*find).bound; // Get the expression in the theorem const Expr& findExpr = (*find).e; int findExprKind = findExpr.getKind(); // Check if the right sides are the same if (rightSide != findExpr[1]) break; // Construct the theorem object Theorem lemma; // Check the type and equeue the lemma if (findExprKind == GT || findExprKind == GE) // Imply the weaker inequality lemma = d_rules->implyWeakerInequality(assertExpr, findExpr); else // Imply the negation of the impossible inequality (use oposite than above) lemma = d_rules->implyNegatedInequality(assertExpr, findExpr); TRACE("propagate_arith", "lemma ==>", lemma.toString(), ""); TRACE("arith_atoms", "Propagate: ", lemma.getExpr().toString(), ""); // Put it across enqueueFact(lemma); // Go to the next one ++ find; } } } Theorem TheoryArithNew::deriveGomoryCut(const Expr& x_i) { Theorem res; // CHECK IF APPLICABLE DebugAssert(isBasic(x_i), "TheoryArithNew::deriveGomoryCut variable must be a basic variable : " + x_i.toString()); DebugAssert(intVariables.count(x_i) > 0, "TheoryArithNew::deriveGomoryCut variable must be a basic variable : " + x_i.toString()); // Get the rational value of x_i Rational x_i_Value = getBeta(x_i).getRational(); // Compute f_0 Rational f_0 = x_i_Value - floor(x_i_Value); return res; } cvc3-2.4.1/src/theory_arith/theory_arith.cpp0000644000175400017540000001703211624745441020764 0ustar mdetersmdeters/*****************************************************************************/ /*! * \file theory_arith.cpp * * Author: Clark Barrett, Vijay Ganesh. * * Created: Fri Jan 17 18:39:18 2003 * *
* * License to use, copy, modify, sell and/or distribute this software * and its documentation for any purpose is hereby granted without * royalty, subject to the terms and conditions defined in the \ref * LICENSE file provided with this distribution. * *
* */ /*****************************************************************************/ #include "theory_arith.h" #include "theory_core.h" #include "translator.h" using namespace std; using namespace CVC3; Theorem TheoryArith::canonRec(const Expr& e) { if (isLeaf(e)) return reflexivityRule(e); int ar = e.arity(); if (ar > 0) { vector newChildrenThm; vector changed; for(int k = 0; k < ar; ++k) { // Recursively canonize the kids Theorem thm = canonRec(e[k]); if (thm.getLHS() != thm.getRHS()) { newChildrenThm.push_back(thm); changed.push_back(k); } } if(changed.size() > 0) { return canonThm(substitutivityRule(e, changed, newChildrenThm)); } } return canon(e); } void TheoryArith::printRational(ExprStream& os, const Rational& r, bool printAsReal) { // Print rational if (r.isInteger()) { if (r < 0) { if (os.lang() == SPASS_LANG) { os << "-" << (-r).toString(); if (printAsReal) os << ".0"; } else { os << "(" << push; if (os.lang() == SMTLIB_LANG) { os << "~"; } else { os << "-"; } os << space << (-r).toString(); if (printAsReal) os << ".0"; os << push << ")"; } } else { os << r.toString(); if (printAsReal) os << ".0"; } } else { os << "(" << push << "/ "; Rational tmp = r.getNumerator(); if (tmp < 0) { if (os.lang() == SPASS_LANG) { os << "-" << (-tmp).toString(); if (printAsReal) os << ".0"; } else { os << "(" << push; if (os.lang() == SMTLIB_LANG) { os << "~"; } else { os << "-"; } os << space << (-tmp).toString(); if (printAsReal) os << ".0"; os << push << ")"; } } else { os << tmp.toString(); if (printAsReal) os << ".0"; } os << space; tmp = r.getDenominator(); DebugAssert(tmp > 0 && tmp.isInteger(), "Unexpected rational denominator"); os << tmp.toString(); if (printAsReal) os << ".0"; os << push << ")"; } } bool TheoryArith::isAtomicArithTerm(const Expr& e) { switch (e.getKind()) { case RATIONAL_EXPR: return true; case ITE: return false; case UMINUS: case PLUS: case MINUS: case MULT: case DIVIDE: case POW: case INTDIV: case MOD: { int i=0, iend=e.arity(); for(; i!=iend; ++i) { if (!isAtomicArithTerm(e[i])) return false; } break; } default: break; } return true; } bool TheoryArith::isAtomicArithFormula(const Expr& e) { switch (e.getKind()) { case LT: case GT: case LE: case GE: case EQ: return isAtomicArithTerm(e[0]) && isAtomicArithTerm(e[1]); } return false; } bool TheoryArith::isSyntacticRational(const Expr& e, Rational& r) { if (e.getKind() == REAL_CONST) { r = e[0].getRational(); return true; } else if (e.isRational()) { r = e.getRational(); return true; } else if (isUMinus(e)) { if (isSyntacticRational(e[0], r)) { r = -r; return true; } } else if (isDivide(e)) { Rational num; if (isSyntacticRational(e[0], num)) { Rational den; if (isSyntacticRational(e[1], den)) { if (den != 0) { r = num / den; return true; } } } } return false; } Expr TheoryArith::rewriteToDiff(const Expr& e) { Expr tmp = e[0] - e[1]; tmp = canonRec(tmp).getRHS(); switch (tmp.getKind()) { case RATIONAL_EXPR: { Rational r = tmp.getRational(); switch (e.getKind()) { case LT: if (r < 0) return trueExpr(); else return falseExpr(); case LE: if (r <= 0) return trueExpr(); else return falseExpr(); case GT: if (r > 0) return trueExpr(); else return falseExpr(); case GE: if (r >= 0) return trueExpr(); else return falseExpr(); case EQ: if (r == 0) return trueExpr(); else return falseExpr(); } } case MULT: DebugAssert(tmp[0].isRational(), "Unexpected term structure from canon"); if (tmp[0].getRational() != -1) return e; return Expr(e.getOp(), theoryCore()->getTranslator()->zeroVar() - tmp[1], rat(0)); case PLUS: { DebugAssert(tmp[0].isRational(), "Unexpected term structure from canon"); Rational c = tmp[0].getRational(); Expr x, y; if (tmp.arity() == 2) { if (tmp[1].getKind() == MULT) { x = theoryCore()->getTranslator()->zeroVar(); y = tmp[1]; } else { x = tmp[1]; y = rat(-1) * theoryCore()->getTranslator()->zeroVar(); } } else if (tmp.arity() == 3) { if (tmp[1].getKind() == MULT) { x = tmp[2]; y = tmp[1]; } else if (tmp[2].getKind() == MULT) { x = tmp[1]; y = tmp[2]; } else return e; } else return e; if (x.getKind() == MULT) return e; DebugAssert(y[0].isRational(), "Unexpected term structure from canon"); if (y[0].getRational() != -1) return e; return Expr(e.getOp(), x - y[1], getEM()->newRatExpr(-c)); } default: return Expr(e.getOp(), tmp - theoryCore()->getTranslator()->zeroVar(), rat(0)); break; } return e; } Theorem TheoryArith::canonSimp(const Expr& e) { DebugAssert(canonRec(e).getRHS() == e, "canonSimp expects input to be canonized"); int ar = e.arity(); if (isLeaf(e)) return find(e); if (ar > 0) { vector newChildrenThm; vector changed; Theorem thm; for (int k = 0; k < ar; ++k) { thm = canonSimp(e[k]); if (thm.getLHS() != thm.getRHS()) { newChildrenThm.push_back(thm); changed.push_back(k); } } if(changed.size() > 0) { thm = canonThm(substitutivityRule(e, changed, newChildrenThm)); return transitivityRule(thm, find(thm.getRHS())); } else return find(e); } return find(e); } bool TheoryArith::recursiveCanonSimpCheck(const Expr& e) { if (e.hasFind()) return true; if (e != canonSimp(e).getRHS()) return false; Expr::iterator i = e.begin(), iend = e.end(); for (; i != iend; ++i) if (!recursiveCanonSimpCheck(*i)) return false; return true; } bool TheoryArith::leavesAreNumConst(const Expr& e) { DebugAssert(e.isTerm() || (e.isPropAtom() && theoryOf(e) == this), "Expected term or arith prop atom"); if (e.validTerminalsConstFlag()) { return e.getTerminalsConstFlag(); } if (e.isRational()) { e.setTerminalsConstFlag(true); return true; } if (e.isAtomic() && isLeaf(e)) { e.setTerminalsConstFlag(false); return false; } DebugAssert(e.arity() > 0, "Expected non-zero arity"); int k = 0; if (e.isITE()) { k = 1; } for (; k < e.arity(); ++k) { if (!leavesAreNumConst(e[k])) { e.setTerminalsConstFlag(false); return false; } } e.setTerminalsConstFlag(true); return true; } cvc3-2.4.1/src/theory_arith/arith_theorem_producer_old.cpp0000644000175400017540000036165411624746723023676 0ustar mdetersmdeters/*****************************************************************************/ /*! * \file arith_theorem_producer.cpp * * Author: Vijay Ganesh, Sergey Berezin * * Created: Dec 13 02:09:04 GMT 2002 * *
* * License to use, copy, modify, sell and/or distribute this software * and its documentation for any purpose is hereby granted without * royalty, subject to the terms and conditions defined in the \ref * LICENSE file provided with this distribution. * *
* */ /*****************************************************************************/ // CLASS: ArithProofRules // // AUTHOR: Sergey Berezin, 12/11/2002 // AUTHOR: Vijay Ganesh, 05/30/2003 // // Description: TRUSTED implementation of arithmetic proof rules. // /////////////////////////////////////////////////////////////////////////////// // This code is trusted #define _CVC3_TRUSTED_ #include "arith_theorem_producer_old.h" #include "theory_core.h" #include "theory_arith_old.h" #include using namespace std; using namespace CVC3; //////////////////////////////////////////////////////////////////// // TheoryArith: trusted method for creating ArithTheoremProducerOld //////////////////////////////////////////////////////////////////// ArithProofRules* TheoryArithOld::createProofRulesOld() { return new ArithTheoremProducerOld(theoryCore()->getTM(), this); } //////////////////////////////////////////////////////////////////// // Canonization rules //////////////////////////////////////////////////////////////////// #define CLASS_NAME "ArithTheoremProducerOld" // Rule for variables: e == 1 * e Theorem ArithTheoremProducerOld::varToMult(const Expr& e) { Proof pf; if(withProof()) pf = newPf("var_to_mult", e); return newRWTheorem(e, (rat(1) * e), Assumptions::emptyAssump(), pf); } // Rule for unary minus: -e == (-1) * e Theorem ArithTheoremProducerOld::uMinusToMult(const Expr& e) { Proof pf; if(withProof()) pf = newPf("uminus_to_mult", e); return newRWTheorem((-e), (rat(-1) * e), Assumptions::emptyAssump(), pf); } // ==> x - y = x + (-1) * y Theorem ArithTheoremProducerOld::minusToPlus(const Expr& x, const Expr& y) { Proof pf; if(withProof()) pf = newPf("minus_to_plus", x, y); return newRWTheorem((x-y), (x + (rat(-1) * y)), Assumptions::emptyAssump(), pf); } // Rule for unary minus: -e == e/(-1) // This is to reduce the number of almost identical rules for uminus and div Theorem ArithTheoremProducerOld::canonUMinusToDivide(const Expr& e) { Proof pf; if(withProof()) pf = newPf("canon_uminus", e); return newRWTheorem((-e), (e / rat(-1)), Assumptions::emptyAssump(), pf); } // Rules for division by constant // (c)/(d) ==> (c/d). When d==0, c/0 = 0 (our total extension). Theorem ArithTheoremProducerOld::canonDivideConst(const Expr& c, const Expr& d) { // Make sure c and d are a const if(CHECK_PROOFS) { CHECK_SOUND(isRational(c), CLASS_NAME "::canonDivideConst:\n c not a constant: " + c.toString()); CHECK_SOUND(isRational(d), CLASS_NAME "::canonDivideConst:\n d not a constant: " + d.toString()); } Proof pf; if(withProof()) pf = newPf("canon_divide_const", c, d, d_hole); const Rational& dr = d.getRational(); return newRWTheorem((c/d), (rat(dr==0? 0 : (c.getRational()/dr))), Assumptions::emptyAssump(), pf); } // (c * x)/d ==> (c/d) * x, takes (c*x) and d Theorem ArithTheoremProducerOld::canonDivideMult(const Expr& cx, const Expr& d) { // Check the format of c*x if(CHECK_PROOFS) { CHECK_SOUND(isMult(cx) && isRational(cx[0]), CLASS_NAME "::canonDivideMult:\n " "Not a (c * x) expression: " + cx.toString()); CHECK_SOUND(isRational(d), CLASS_NAME "::canonDivideMult:\n " "d is not a constant: " + d.toString()); } const Rational& dr = d.getRational(); Rational cdr(dr==0? 0 : (cx[0].getRational()/dr)); Expr cd(rat(cdr)); Proof pf; if(withProof()) pf = newPf("canon_divide_mult", cx[0], cx[1], d); // (c/d) may be == 1, so we also need to canonize 1*x to x if(cdr == 1) return newRWTheorem((cx/d), (cx[1]), Assumptions::emptyAssump(), pf); else if(cdr == 0) // c/0 == 0 case return newRWTheorem((cx/d), cd, Assumptions::emptyAssump(), pf); else return newRWTheorem((cx/d), (cd*cx[1]), Assumptions::emptyAssump(), pf); } // (+ t1 ... tn)/d ==> (+ (t1/d) ... (tn/d)) Theorem ArithTheoremProducerOld::canonDividePlus(const Expr& sum, const Expr& d) { if(CHECK_PROOFS) { CHECK_SOUND(isPlus(sum) && sum.arity() >= 2 && isRational(sum[0]), CLASS_NAME "::canonUMinusPlus:\n " "Expr is not a canonical sum: " + sum.toString()); CHECK_SOUND(isRational(d), CLASS_NAME "::canonUMinusPlus:\n " "d is not a const: " + d.toString()); } // First, propagate '/d' down to the args Proof pf; if(withProof()) pf = newPf("canon_divide_plus", rat(sum.arity()), sum.begin(), sum.end()); vector newKids; for(Expr::iterator i=sum.begin(), iend=sum.end(); i!=iend; ++i) newKids.push_back((*i)/d); // (+ t1 ... tn)/d == (+ (t1/d) ... (tn/d)) return newRWTheorem((sum/d), (plusExpr(newKids)), Assumptions::emptyAssump(), pf); } // x/(d) ==> (1/d) * x, unless d == 1 Theorem ArithTheoremProducerOld::canonDivideVar(const Expr& e, const Expr& d) { if(CHECK_PROOFS) { CHECK_SOUND(isRational(d), CLASS_NAME "::canonDivideVar:\n " "d is not a const: " + d.toString()); } Proof pf; if(withProof()) pf = newPf("canon_divide_var", e); const Rational& dr = d.getRational(); if(dr == 1) return newRWTheorem(e/d, e, Assumptions::emptyAssump(), pf); if(dr == 0) // e/0 == 0 (total extension of division) return newRWTheorem(e/d, d, Assumptions::emptyAssump(), pf); else return newRWTheorem(e/d, rat(1/dr) * e, Assumptions::emptyAssump(), pf); } // Multiplication // (MULT expr1 expr2 expr3 ...) // Each expr is in canonical form, i.e. it can be a // 1) Rational constant // 2) Arithmetic Leaf (var or term from another theory) // 3) (POW rational leaf) // where rational cannot be 0 or 1 // 4) (MULT rational mterm'_1 ...) where each mterm' is of type (2) or (3) // If rational == 1 then there should be at least two mterms // 5) (PLUS rational sterm_1 ...) where each sterm is of // type (2) or (3) or (4) // if rational == 0 then there should be at least two sterms Expr ArithTheoremProducerOld::simplifiedMultExpr(std::vector & mulKids) { DebugAssert(mulKids.size() >= 1 && mulKids[0].isRational(), ""); if (mulKids.size() == 1) { return mulKids[0]; } if ((mulKids[0] == rat(1)) && mulKids.size() == 2) { return mulKids[1]; } else return multExpr(mulKids); } Expr ArithTheoremProducerOld::canonMultConstMult(const Expr & c, const Expr & e) { // c is a rational // e is (MULT rat mterm'_1 ....) // assume that e2 is already in canonic form DebugAssert(c.isRational() && e.getKind() == MULT, ""); std::vector mulKids; DebugAssert ((e.arity() > 1) && (e[0].isRational()), "ArithTheoremProducerOld::canonMultConstMult: " "a canonized MULT expression must have arity " "greater than 1: and first child must be " "rational " + e.toString()); Expr::iterator i = e.begin(); mulKids.push_back(rat(c.getRational() * (*i).getRational())); ++i; for(; i != e.end(); ++i) { mulKids.push_back(*i); } return simplifiedMultExpr(mulKids); } Expr ArithTheoremProducerOld::canonMultConstPlus(const Expr & e1, const Expr & e2) { DebugAssert(e1.isRational() && e2.getKind() == PLUS && e2.arity() > 0, ""); // e1 is a rational // e2 is of the form (PLUS rational sterm1 sterm2 ...) // assume that e2 is already in canonic form std::vector thmPlusVector; Expr::iterator i = e2.begin(); for(; i!= e2.end(); ++i) { thmPlusVector.push_back(canonMultMtermMterm(e1*(*i))); } Theorem thmPlus1 = d_theoryArith->substitutivityRule(e2.getOp(), thmPlusVector); return thmPlus1.getRHS(); } Expr ArithTheoremProducerOld::canonMultPowPow(const Expr & e1, const Expr & e2) { DebugAssert(e1.getKind() == POW && e2.getKind() == POW, ""); // (POW r1 leaf1) * (POW r2 leaf2) Expr leaf1 = e1[1]; Expr leaf2 = e2[1]; Expr can_expr; if (leaf1 == leaf2) { Rational rsum = e1[0].getRational() + e2[0].getRational(); if (rsum == 0) { return rat(1); } else if (rsum == 1) { return leaf1; } else { return powExpr(rat(rsum), leaf1); } } else { std::vector mulKids; mulKids.push_back(rat(1)); // the leafs should be put in decreasing order if (leaf1 < leaf2) { mulKids.push_back(e2); mulKids.push_back(e1); } else { mulKids.push_back(e1); mulKids.push_back(e2); } // FIXME: don't really need to simplify, just wrap up a MULT? return simplifiedMultExpr(mulKids); } } Expr ArithTheoremProducerOld::canonMultPowLeaf(const Expr & e1, const Expr & e2) { DebugAssert(e1.getKind() == POW, ""); // (POW r1 leaf1) * leaf2 Expr leaf1 = e1[1]; Expr leaf2 = e2; Expr can_expr; if (leaf1 == leaf2) { Rational rsum = e1[0].getRational() + 1; if (rsum == 0) { return rat(1); } else if (rsum == 1) { return leaf1; } else { return powExpr(rat(rsum), leaf1); } } else { std::vector mulKids; mulKids.push_back(rat(1)); // the leafs should be put in decreasing order if (leaf1 < leaf2) { mulKids.push_back(e2); mulKids.push_back(e1); } else { mulKids.push_back(e1); mulKids.push_back(e2); } return simplifiedMultExpr(mulKids); } } Expr ArithTheoremProducerOld::canonMultLeafLeaf(const Expr & e1, const Expr & e2) { // leaf1 * leaf2 Expr leaf1 = e1; Expr leaf2 = e2; Expr can_expr; if (leaf1 == leaf2) { return powExpr(rat(2), leaf1); } else { std::vector mulKids; mulKids.push_back(rat(1)); // the leafs should be put in decreasing order if (leaf1 < leaf2) { mulKids.push_back(e2); mulKids.push_back(e1); } else { mulKids.push_back(e1); mulKids.push_back(e2); } return simplifiedMultExpr(mulKids); } } Expr ArithTheoremProducerOld::canonMultLeafOrPowMult(const Expr & e1, const Expr & e2) { DebugAssert(e2.getKind() == MULT, ""); // Leaf * (MULT rat1 mterm1 ...) // (POW r1 leaf1) * (MULT rat1 mterm1 ...) where // each mterm is a leaf or (POW r leaf). Furthermore the leafs // in the mterms are in descending order Expr leaf1 = e1.getKind() == POW ? e1[1] : e1; std::vector mulKids; DebugAssert(e2.arity() > 1, "MULT expr must have arity 2 or more"); Expr::iterator i = e2.begin(); // push the rational mulKids.push_back(*i); ++i; // Now i points to the first mterm for(; i != e2.end(); ++i) { Expr leaf2 = ((*i).getKind() == POW) ? (*i)[1] : (*i); if (leaf1 == leaf2) { Rational r1 = e1.getKind() == POW ? e1[0].getRational() : 1; Rational r2 = ((*i).getKind() == POW ? (*i)[0].getRational() : 1); // if r1 + r2 == 0 then it is the case of x^n * x^{-n} // So, nothing needs to be added if (r1 + r2 != 0) { if (r1 + r2 == 1) { mulKids.push_back(leaf1); } else { mulKids.push_back(powExpr(rat(r1 + r2), leaf1)); } } break; } // This ensures that the leaves in the mterms are also arranged // in decreasing order // Note that this will need to be changed if we want the order to // be increasing order. else if (leaf2 < leaf1) { mulKids.push_back(e1); mulKids.push_back(*i); break; } else // leaf1 < leaf2 mulKids.push_back(*i); } if (i == e2.end()) { mulKids.push_back(e1); } else { // e1 and *i have already been added for (++i; i != e2.end(); ++i) { mulKids.push_back(*i); } } return simplifiedMultExpr(mulKids); } // Local class for ordering monomials; note, that it flips the // ordering given by greaterthan(), to sort in ascending order. class MonomialLess { public: bool operator()(const Expr& e1, const Expr& e2) const { return ArithTheoremProducerOld::greaterthan(e1,e2); } }; typedef map MonomMap; Expr ArithTheoremProducerOld::canonCombineLikeTerms(const std::vector & sumExprs) { Rational constant = 0; MonomMap sumHashMap; vector sumKids; // Add each distinct mterm (not including the rational) into // an appropriate hash map entry std::vector::const_iterator i = sumExprs.begin(); for (; i != sumExprs.end(); ++i) { Expr mul = *i; if (mul.isRational()) { constant = constant + mul.getRational(); } else { switch (mul.getKind()) { case MULT: { std::vector mulKids; DebugAssert(mul.arity() > 1 && mul[0].isRational(),""); mulKids.push_back(rat(1)); Expr::iterator j = mul.begin(); ++j; for (; j!= mul.end(); ++j) { mulKids.push_back(*j); } // make sure that tempExpr is also in canonic form Expr tempExpr = mulKids.size() > 2 ? multExpr(mulKids): mulKids[1]; MonomMap::iterator i=sumHashMap.find(tempExpr); if (i == sumHashMap.end()) { sumHashMap[tempExpr] = mul[0].getRational(); } else { (*i).second += mul[0].getRational(); } } break; default: { MonomMap::iterator i=sumHashMap.find(mul); // covers the case of POW, leaf if (i == sumHashMap.end()) { sumHashMap[mul] = 1; } else { (*i).second += 1; } break; } } } } // Now transfer to sumKids sumKids.push_back(rat(constant)); MonomMap::iterator j = sumHashMap.begin(), jend=sumHashMap.end(); for(; j != jend; ++j) { if ((*j).second != 0) sumKids.push_back (canonMultMtermMterm(rat((*j).second) * (*j).first).getRHS()); } /* for (unsigned k = 0; k < sumKids.size(); ++k) { cout << "sumKids[" << k << "] = " << sumKids[k].toString() << endl; } */ // The ordering in map guarantees the correct order; no need to sort // std::sort(sumKids.begin(), sumKids.end(), greaterthan); if ((constant == 0) && (sumKids.size() == 2)) { return sumKids[1]; } else if (sumKids.size() == 1) { return sumKids[0]; } else return plusExpr(sumKids); } Expr ArithTheoremProducerOld::canonMultLeafOrPowOrMultPlus(const Expr & e1, const Expr & e2) { DebugAssert(e2.getKind() == PLUS, ""); // Leaf * (PLUS rational sterm1 ...) // or // (POW n1 x1) * (PLUS rational sterm1 ...) // or // (MULT r1 m1 m2 ...) * (PLUS rational sterm1 ...) // assume that e1 and e2 are themselves canonized std::vector sumExprs; // Multiply each term in turn. Expr::iterator i = e2.begin(); for (; i != e2.end(); ++i) { sumExprs.push_back(canonMultMtermMterm(e1 * (*i)).getRHS()); } return canonCombineLikeTerms(sumExprs); } Expr ArithTheoremProducerOld::canonMultPlusPlus(const Expr & e1, const Expr & e2) { DebugAssert(e1.getKind() == PLUS && e2.getKind() == PLUS, ""); // (PLUS r1 .... ) * (PLUS r1' ...) // assume that e1 and e2 are themselves canonized std::vector sumExprs; // Multiply each term in turn. Expr::iterator i = e1.begin(); for (; i != e1.end(); ++i) { Expr::iterator j = e2.begin(); for (; j != e2.end(); ++j) { sumExprs.push_back(canonMultMtermMterm((*i) * (*j)).getRHS()); } } return canonCombineLikeTerms(sumExprs); } // The following produces a Theorem which is the result of multiplication // of two canonized mterms. e = e1*e2 Theorem ArithTheoremProducerOld::canonMultMtermMterm(const Expr& e) { if(CHECK_PROOFS) { CHECK_SOUND(isMult(e) && e.arity() == 2, "canonMultMtermMterm: e = "+e.toString()); } Proof pf; Expr rhs; const Expr& e1 = e[0]; const Expr& e2 = e[1]; string cmmm = "canon_mult_mterm_mterm"; if (e1.isRational()) { // e1 is a Rational const Rational& c = e1.getRational(); if (c == 0) return canonMultZero(e2); else if (c == 1) return canonMultOne(e2); else { switch (e2.getKind()) { case RATIONAL_EXPR : // rat * rat return canonMultConstConst(e1,e2); break; // TODO case of leaf case POW: // rat * (POW rat leaf) // nothing to simplify return d_theoryArith->reflexivityRule (e); break; case MULT: rhs = canonMultConstMult(e1,e2); if(withProof()) pf = newPf(cmmm,e,rhs); return newRWTheorem(e, rhs, Assumptions::emptyAssump(), pf); break; case PLUS: rhs = canonMultConstPlus(e1,e2); if(withProof()) pf = newPf(cmmm,e,rhs); return newRWTheorem(e, rhs, Assumptions::emptyAssump(), pf); break; default: // TODO: I am going to assume that this is just a leaf // i.e., a variable or term from another theory return d_theoryArith->reflexivityRule(e); break; } } } else if (e1.getKind() == POW) { switch (e2.getKind()) { case RATIONAL_EXPR: // switch the order of the two arguments return canonMultMtermMterm(e2 * e1); break; case POW: rhs = canonMultPowPow(e1,e2); if(withProof()) pf = newPf(cmmm,e,rhs); return newRWTheorem(e,rhs, Assumptions::emptyAssump(), pf); break; case MULT: rhs = canonMultLeafOrPowMult(e1,e2); if(withProof()) pf = newPf(cmmm,e,rhs); return newRWTheorem(e, rhs, Assumptions::emptyAssump(), pf); break; case PLUS: rhs = canonMultLeafOrPowOrMultPlus(e1,e2); if(withProof()) pf = newPf(cmmm,e,rhs); return newRWTheorem(e, rhs, Assumptions::emptyAssump(), pf); break; default: rhs = canonMultPowLeaf(e1,e2); if(withProof()) pf = newPf(cmmm,e,rhs); return newRWTheorem(e,rhs, Assumptions::emptyAssump(), pf); break; } } else if (e1.getKind() == MULT) { switch (e2.getKind()) { case RATIONAL_EXPR: case POW: // switch the order of the two arguments return canonMultMtermMterm(e2 * e1); break; case MULT: { // (Mult r m1 m2 ...) (Mult r' m1' m2' ...) Expr result = e2; Expr::iterator i = e1.begin(); for (; i != e1.end(); ++i) { result = canonMultMtermMterm((*i) * result).getRHS(); } if(withProof()) pf = newPf(cmmm,e,result); return newRWTheorem(e, result, Assumptions::emptyAssump(), pf); } break; case PLUS: rhs = canonMultLeafOrPowOrMultPlus(e1,e2); if(withProof()) pf = newPf(cmmm,e,rhs); return newRWTheorem(e,rhs, Assumptions::emptyAssump(), pf); break; default: // leaf // switch the order of the two arguments return canonMultMtermMterm(e2 * e1); break; } } else if (e1.getKind() == PLUS) { switch (e2.getKind()) { case RATIONAL_EXPR: case POW: case MULT: // switch the order of the two arguments return canonMultMtermMterm(e2 * e1); break; case PLUS: rhs = canonMultPlusPlus(e1,e2); if(withProof()) pf = newPf(cmmm,e,rhs); return newRWTheorem(e, rhs, Assumptions::emptyAssump(), pf); break; default: // leaf // switch the order of the two arguments return canonMultMtermMterm(e2 * e1); break; } } else { // leaf switch (e2.getKind()) { case RATIONAL_EXPR: // switch the order of the two arguments return canonMultMtermMterm(e2 * e1); break; case POW: rhs = canonMultPowLeaf(e2,e1); if(withProof()) pf = newPf(cmmm,e,rhs); return newRWTheorem(e, rhs, Assumptions::emptyAssump(), pf); break; case MULT: rhs = canonMultLeafOrPowMult(e1,e2);; if(withProof()) pf = newPf(cmmm,e,rhs); return newRWTheorem(e, rhs, Assumptions::emptyAssump(), pf); break; case PLUS: rhs = canonMultLeafOrPowOrMultPlus(e1,e2); if(withProof()) pf = newPf(cmmm,e,rhs); return newRWTheorem(e, rhs, Assumptions::emptyAssump(), pf); break; default: // leaf * leaf rhs = canonMultLeafLeaf(e1,e2); if(withProof()) pf = newPf(cmmm,e,rhs); return newRWTheorem(e, rhs, Assumptions::emptyAssump(), pf); break; } } FatalAssert(false, "Unreachable"); return newRWTheorem(e, rhs, Assumptions::emptyAssump(), pf); } // (PLUS expr1 expr2 ...) where each expr is itself in canonic form Theorem ArithTheoremProducerOld::canonPlus(const Expr& e) { Proof pf; if (withProof()) { pf = newPf("canon_plus", e); } DebugAssert(e.getKind() == PLUS, ""); // First flatten the PLUS std::vector sumKids; Expr::iterator i = e.begin(); for(; i != e.end(); ++i) { if ((*i).getKind() != PLUS) { sumKids.push_back(*i); } else { Expr::iterator j = (*i).begin(); for(; j != (*i).end(); ++j) sumKids.push_back(*j); } } Expr val = canonCombineLikeTerms(sumKids); if (withProof()) { pf = newPf("canon_plus", e, val); } return newRWTheorem(e, val, Assumptions::emptyAssump(), pf); } // (MULT expr1 expr2 ...) where each expr is itself in canonic form Theorem ArithTheoremProducerOld::canonMult(const Expr& e) { Proof pf; TRACE("arith canon", "canonMult(", e.toString(), ")"); DebugAssert(e.getKind() == MULT && e.arity() > 1, ""); Expr::iterator i = e.begin(); Expr result = *i; ++i; for (; i != e.end(); ++i) { result = canonMultMtermMterm(result * (*i)).getRHS(); } if (withProof()) { pf = newPf("canon_mult", e,result); } // If multiplicative sign split is on do it if (d_theoryArith->nonlinearSignSplit()) { // Add the sign splits Expr positive = d_em->trueExpr(); Expr negative = d_em->falseExpr(); vector zero; // we do the case split if it's not trivial int count_non_trivial = 0; int count_constants = 0; // a1*a2*...*an is positive if there is an even number of negative ones // a1*a2*...*an is negative if there is an odd number of negative ones for (i = e.begin(); i != e.end(); ++i) { Expr current = (*i); if (isPlus(current)) count_non_trivial ++; if (current.isRational()) count_constants ++; if (isPow(current) && current[0].getRational() < 0) { // Bail on negative powers, it's normalization count_non_trivial = 0; break; } zero.push_back(current.eqExpr(rat(0))); positive = Expr(XOR, positive, ltExpr(current, rat(0))); negative = Expr(XOR, negative, ltExpr(current, rat(0))); } if (count_non_trivial > 0 && !count_constants == (e.arity() - 1)) { // Any of the factors is zero Expr zero_lemma = orExpr(zero).iffExpr(result.eqExpr(rat(0))); Expr positive_lemma = positive.impExpr(geExpr(result, rat(0))); Expr negative_lemma = negative.impExpr(leExpr(result, rat(0))); Expr lemma = positive_lemma.andExpr(negative_lemma.andExpr(zero_lemma)); Proof split_pf; if (withProof()) split_pf = newPf("multiplicative_sign_split", e, lemma); Theorem case_split_thm = newTheorem(lemma, Assumptions::emptyAssump(), split_pf); TRACE("arith nonlinear", "adding sign split: ", lemma, ""); d_theoryArith->addMultiplicativeSignSplit(case_split_thm); } } return newRWTheorem(e, result, Assumptions::emptyAssump(), pf); } Theorem ArithTheoremProducerOld::canonInvertConst(const Expr& e) { if(CHECK_PROOFS) CHECK_SOUND(isRational(e), "expecting a rational: e = "+e.toString()); Proof pf; if (withProof()) { pf = newPf("canon_invert_const", e); } const Rational& er = e.getRational(); return newRWTheorem((rat(1)/e), rat(er==0? 0 : (1/er)), Assumptions::emptyAssump(), pf); } Theorem ArithTheoremProducerOld::canonInvertLeaf(const Expr& e) { Proof pf; if (withProof()) { pf = newPf("canon_invert_leaf", e); } return newRWTheorem((rat(1)/e), powExpr(rat(-1), e), Assumptions::emptyAssump(), pf); } Theorem ArithTheoremProducerOld::canonInvertPow(const Expr& e) { DebugAssert(e.getKind() == POW, "expecting a rational"+e[0].toString()); Proof pf; if (withProof()) { pf = newPf("canon_invert_pow", e); } if (e[0].getRational() == -1) return newRWTheorem((rat(1)/e), e[1], Assumptions::emptyAssump(), pf); else return newRWTheorem((rat(1)/e), powExpr(rat(-e[0].getRational()), e[1]), Assumptions::emptyAssump(), pf); } Theorem ArithTheoremProducerOld::canonInvertMult(const Expr& e) { DebugAssert(e.getKind() == MULT, "expecting a rational"+e[0].toString()); Proof pf; if (withProof()) { pf = newPf("canon_invert_mult", e); } DebugAssert(e.arity() > 1, "MULT should have arity > 1"+e.toString()); Expr result = canonInvert(e[0]).getRHS(); for (int i = 1; i < e.arity(); ++i) { result = canonMultMtermMterm(result * canonInvert(e[i]).getRHS()).getRHS(); } return newRWTheorem((rat(1)/e), result, Assumptions::emptyAssump(), pf); } // Given an expression e in Canonic form generate 1/e in canonic form // This function assumes that e is not a PLUS expression Theorem ArithTheoremProducerOld::canonInvert(const Expr& e) { DebugAssert(e.getKind() != PLUS, "Cannot do inverse on a PLUS"+e.toString()); switch (e.getKind()) { case RATIONAL_EXPR: return canonInvertConst(e); break; case POW: return canonInvertPow(e); break; case MULT: return canonInvertMult(e); break; default: // leaf return canonInvertLeaf(e); break; } } Theorem ArithTheoremProducerOld::moveSumConstantRight(const Expr& e) { // Check soundness of the rule if necessary if (CHECK_PROOFS) { CHECK_SOUND(isIneq(e) || e.isEq(), "moveSumConstantRight: input must be Eq or Ineq: " + e.toString()); CHECK_SOUND(isRational(e[0]) || isPlus(e[0]), "moveSumConstantRight: left side must be a canonised sum: " + e.toString()); CHECK_SOUND(isRational(e[1]) && e[1].getRational() == 0, "moveSumConstantRight: right side must be 0: " + e.toString()); } // The rational constant of the sum Rational r = 0; // The right hand side of the expression Expr right = e[0]; // The vector of sum terms vector sumTerms; // Get all the non rational children and if (!right.isRational()) for(Expr::iterator it = right.begin(); it != right.end(); it ++) { // If the term is rational then add the rational number to r if ((*it).isRational()) r = r + (*it).getRational(); // Otherwise just add the sumTerm to the sumTerms else sumTerms.push_back((*it)); } // Setup the new expression Expr transformed; if (sumTerms.size() > 1) // If the number of summands is > 1 return the sum of them transformed = Expr(e.getKind(), plusExpr(sumTerms), rat(-r)); else // Otherwise return the one summand as itself transformed = Expr(e.getKind(), sumTerms[0], rat(-r)); // If proof is needed set it up Proof pf; if (withProof()) pf = newPf("arithm_sum_constant_right", e); // Retrun the theorem explaining the transformation return newRWTheorem(e, transformed, Assumptions::emptyAssump(), pf); } Theorem ArithTheoremProducerOld::canonDivide(const Expr& e) { DebugAssert(e.getKind() == DIVIDE, "Expecting Divide"+e.toString()); Proof pf; if (withProof()) { pf = newPf("canon_invert_divide", e); } Theorem thm = newRWTheorem(e, e[0]*(canonInvert(e[1]).getRHS()), Assumptions::emptyAssump(), pf); return d_theoryArith->transitivityRule(thm, canonMult(thm.getRHS())); } // Rules for multiplication // t*c ==> c*t, takes constant c and term t Theorem ArithTheoremProducerOld::canonMultTermConst(const Expr& c, const Expr& t) { Proof pf; if(CHECK_PROOFS) { CHECK_SOUND(isRational(c), CLASS_NAME "::canonMultTermConst:\n " "c is not a constant: " + c.toString()); } if(withProof()) pf = newPf("canon_mult_term_const", c, t); return newRWTheorem((t*c), (c*t), Assumptions::emptyAssump(), pf); } // Rules for multiplication // t1*t2 ==> Error, takes t1 and t2 where both are non-constants Theorem ArithTheoremProducerOld::canonMultTerm1Term2(const Expr& t1, const Expr& t2) { // Proof pf; // if(withProof()) pf = newPf("canon_mult_term1_term2", t1, t2); if(CHECK_PROOFS) { CHECK_SOUND(false, "Fatal Error: We don't support multiplication" "of two non constant terms at this time " + t1.toString() + " and " + t2.toString()); } return Theorem(); } // Rules for multiplication // 0*x = 0, takes x Theorem ArithTheoremProducerOld::canonMultZero(const Expr& e) { Proof pf; if(withProof()) pf = newPf("canon_mult_zero", e); return newRWTheorem((rat(0)*e), rat(0), Assumptions::emptyAssump(), pf); } // Rules for multiplication // 1*x ==> x, takes x Theorem ArithTheoremProducerOld::canonMultOne(const Expr& e) { Proof pf; if(withProof()) pf = newPf("canon_mult_one", e); return newRWTheorem((rat(1)*e), e, Assumptions::emptyAssump(), pf); } // Rules for multiplication // c1*c2 ==> c', takes constant c1*c2 Theorem ArithTheoremProducerOld::canonMultConstConst(const Expr& c1, const Expr& c2) { Proof pf; if(CHECK_PROOFS) { CHECK_SOUND(isRational(c1), CLASS_NAME "::canonMultConstConst:\n " "c1 is not a constant: " + c1.toString()); CHECK_SOUND(isRational(c2), CLASS_NAME "::canonMultConstConst:\n " "c2 is not a constant: " + c2.toString()); } if(withProof()) pf = newPf("canon_mult_const_const", c1, c2); return newRWTheorem((c1*c2), rat(c1.getRational()*c2.getRational()), Assumptions::emptyAssump(), pf); } // Rules for multiplication // c1*(c2*t) ==> c'*t, takes c1 and c2 and t Theorem ArithTheoremProducerOld::canonMultConstTerm(const Expr& c1, const Expr& c2,const Expr& t) { Proof pf; if(CHECK_PROOFS) { CHECK_SOUND(isRational(c1), CLASS_NAME "::canonMultConstTerm:\n " "c1 is not a constant: " + c1.toString()); CHECK_SOUND(isRational(c2), CLASS_NAME "::canonMultConstTerm:\n " "c2 is not a constant: " + c2.toString()); } if(withProof()) pf = newPf("canon_mult_const_term", c1, c2, t); return newRWTheorem(c1*(c2*t), rat(c1.getRational()*c2.getRational())*t, Assumptions::emptyAssump(), pf); } // Rules for multiplication // c1*(+ c2 v1 ...) ==> (+ c1c2 c1v1 ...), takes c1 and the sum Theorem ArithTheoremProducerOld::canonMultConstSum(const Expr& c1, const Expr& sum) { Proof pf; std::vector sumKids; if(CHECK_PROOFS) { CHECK_SOUND(isRational(c1), CLASS_NAME "::canonMultConstTerm:\n " "c1 is not a constant: " + c1.toString()); CHECK_SOUND(PLUS == sum.getKind(), CLASS_NAME "::canonMultConstTerm:\n " "the kind must be a PLUS: " + sum.toString()); } Expr::iterator i = sum.begin(); for(; i != sum.end(); ++i) sumKids.push_back(c1*(*i)); Expr ret = plusExpr(sumKids); if(withProof()) pf = newPf("canon_mult_const_sum", c1, sum, ret); return newRWTheorem((c1*sum),ret , Assumptions::emptyAssump(), pf); } // c^n = c' (compute the constant power expression) Theorem ArithTheoremProducerOld::canonPowConst(const Expr& e) { if(CHECK_PROOFS) { CHECK_SOUND(e.getKind() == POW && e.arity() == 2 && e[0].isRational() && e[1].isRational(), "ArithTheoremProducerOld::canonPowConst("+e.toString()+")"); } const Rational& p = e[0].getRational(); const Rational& base = e[1].getRational(); if(CHECK_PROOFS) { CHECK_SOUND(p.isInteger(), "ArithTheoremProducerOld::canonPowConst("+e.toString()+")"); } Expr res; if (base == 0 && p < 0) { res = rat(0); } else res = rat(pow(p, base)); Proof pf; if(withProof()) pf = newPf("canon_pow_const", e, res); return newRWTheorem(e, res, Assumptions::emptyAssump(), pf); } // Rules for addition // flattens the input. accepts a PLUS expr Theorem ArithTheoremProducerOld::canonFlattenSum(const Expr& e) { Proof pf; std::vector sumKids; if(CHECK_PROOFS) { CHECK_SOUND(PLUS == e.getKind(), CLASS_NAME "::canonFlattenSum:\n" "input must be a PLUS:" + e.toString()); } Expr::iterator i = e.begin(); for(; i != e.end(); ++i){ if (PLUS != (*i).getKind()) sumKids.push_back(*i); else { Expr::iterator j = (*i).begin(); for(; j != (*i).end(); ++j) sumKids.push_back(*j); } } Expr ret = plusExpr(sumKids); if(withProof()) pf = newPf("canon_flatten_sum", e,ret); return newRWTheorem(e,ret, Assumptions::emptyAssump(), pf); } // Rules for addition // combine like terms. accepts a flattened PLUS expr Theorem ArithTheoremProducerOld::canonComboLikeTerms(const Expr& e) { Proof pf; std::vector sumKids; ExprMap sumHashMap; Rational constant = 0; if(CHECK_PROOFS) { Expr::iterator k = e.begin(); for(; k != e.end(); ++k) CHECK_SOUND(!isPlus(*k), CLASS_NAME "::canonComboLikeTerms:\n" "input must be a flattened PLUS:" + k->toString()); } Expr::iterator i = e.begin(); for(; i != e.end(); ++i){ if(i->isRational()) constant = constant + i->getRational(); else { if (!isMult(*i)) { if(0 == sumHashMap.count((*i))) sumHashMap[*i] = 1; else sumHashMap[*i] += 1; } else { if(0 == sumHashMap.count((*i)[1])) sumHashMap[(*i)[1]] = (*i)[0].getRational(); else sumHashMap[(*i)[1]] = sumHashMap[(*i)[1]] + (*i)[0].getRational(); } } } sumKids.push_back(rat(constant)); ExprMap::iterator j = sumHashMap.begin(); for(; j != sumHashMap.end(); ++j) { if(0 == (*j).second) ;//do nothing else if (1 == (*j).second) sumKids.push_back((*j).first); else sumKids.push_back(rat((*j).second) * (*j).first); } //constant is same as sumKids[0]. //corner cases: "0 + monomial" and "constant"(no monomials) Expr ret; if(2 == sumKids.size() && 0 == constant) ret = sumKids[1]; else if (1 == sumKids.size()) ret = sumKids[0]; else ret = plusExpr(sumKids); if(withProof()) pf = newPf("canon_combo_like_terms",e,ret); return newRWTheorem(e, ret, Assumptions::emptyAssump(), pf); } // 0 = (* e1 e2 ...) <=> 0 = e1 OR 0 = e2 OR ... Theorem ArithTheoremProducerOld::multEqZero(const Expr& expr) { Proof pf; vector kids; int side = expr[0].isRational() ? 1 : 0; vector non_zero; Expr::iterator i = expr[side].begin(), iend = expr[side].end(); for (; i != iend; ++i) { Expr x = *i; // If a rational it can't be 0, so it is false, i.e. just skip it if (x.isRational()) { CHECK_SOUND(x.getRational() != 0, "multEqZero: once of the constants is 0"); } else { Expr leaf = x; if (isPow(x)) { // We assume that 1 / 0 = 0 for simplicity and totality. // Divisions by zero that affect the result can be identified by enabling TCCs. // if (x[0].getRational() < 0) { // non_zero.push_back(x[1].eqExpr(rat(0)).notExpr()); // continue; // } // else leaf = x[1]; } if (leaf >= rat(0)) kids.push_back(leaf.eqExpr(rat(0))); else kids.push_back(rat(0).eqExpr(leaf)); } } Expr newExpr; if (kids.size() == 1) newExpr = kids[0]; else newExpr = Expr(OR, kids); if (withProof()) { pf = newPf("multEqZero", expr); } // if (non_zero.size() == 0) return newRWTheorem(expr, newExpr, Assumptions::emptyAssump(), pf); // else return newRWTheorem(expr, Expr(OR, kids).andExpr(Expr(AND, non_zero)), Assumptions::emptyAssump(), pf); } // 0 = (^ c x) <=> false if c <=0 // <=> 0 = x if c > 0 Theorem ArithTheoremProducerOld::powEqZero(const Expr& expr) { if (CHECK_PROOFS) { CHECK_SOUND(expr.isEq() && expr[0].isRational() && expr[0].getRational() == 0 && isPow(expr[1]) && expr[1].arity() == 2 && expr[1][0].isRational(), "powEqZero invariant violated"+expr.toString()); } Proof pf; if (withProof()) { pf = newPf("powEqZero", expr); } Rational r = expr[1][0].getRational(); Expr res; if (r <= 0) { res = d_em->falseExpr(); } else { res = rat(0).eqExpr(expr[1][1]); } return newRWTheorem(expr, res, Assumptions::emptyAssump(), pf); } // x^n - y^n = 0 <=> x = y (if n is odd) // x^n - y^n = 0 <=> x = y OR x = -y (if n is even) Theorem ArithTheoremProducerOld::elimPower(const Expr& expr) { Expr power1, power2; bool ok = d_theoryArith->isPowersEquality(expr, power1, power2); if (CHECK_PROOFS) CHECK_SOUND(ok, "elimPower invariant violated"+expr.toString()); Proof pf; if (withProof()) pf = newPf("elimPower", expr); Rational r = power1[0].getRational(); Expr res = power1[1].eqExpr(power2[1]); if (r % 2 == 0) res = res.orExpr(power1[1].eqExpr(-power2[1])); return newRWTheorem(expr, res, Assumptions::emptyAssump(), pf); } // x^n = c <=> x = root (if n is odd and root^n = c) // x^n = c <=> x = root OR x = -root (if n is even and root^n = c) Theorem ArithTheoremProducerOld::elimPowerConst(const Expr& expr, const Rational& root) { if (CHECK_PROOFS) CHECK_SOUND(expr.isEq(), "elimPowerConst invariant violated" + expr.toString()); Rational constant; Expr power; bool ok = d_theoryArith->isPowerEquality(expr, constant, power); if (CHECK_PROOFS) { CHECK_SOUND(ok, "elimPowerConst invariant violated" + expr.toString()); CHECK_SOUND(pow(power[0].getRational(), root) == constant, "elimPowerConst invariant violated" + expr.toString()); } Proof pf; if (withProof()) pf = newPf("elimPowerConst", expr, rat(root)); Rational r = power[0].getRational(); Expr res = power[1].eqExpr(rat(root)); if (r % 2 == 0) res = res.orExpr(power[1].eqExpr(rat(-root))); return newRWTheorem(expr, res, Assumptions::emptyAssump(), pf); } // x^n = c <=> false (if n is even and c is negative) Theorem ArithTheoremProducerOld::evenPowerEqNegConst(const Expr& expr) { if (CHECK_PROOFS) CHECK_SOUND(expr.isEq(), "evenPowerEqNegConst, expecting equality, got " + expr.toString()); Rational constant; Expr power; bool ok = d_theoryArith->isPowerEquality(expr, constant, power); if (CHECK_PROOFS) { CHECK_SOUND(ok, "evenPowerEqNegConst invariant violated" + expr.toString()); CHECK_SOUND(constant < 0, "evenPowerEqNegConst invariant violated" + expr.toString()); CHECK_SOUND(power[0].getRational().isInteger() && power[0].getRational() % 2 == 0, "evenPowerEqNegConst invariant violated" + expr.toString()); } Proof pf; if (withProof()) pf = newPf("evenPowerEqNegConst", expr); return newRWTheorem(expr, d_em->falseExpr(), Assumptions::emptyAssump(), pf); } // x^n = c <=> ` (if x is an integer and c is not a perfect n power) Theorem ArithTheoremProducerOld::intEqIrrational(const Expr& expr, const Theorem& isIntx) { if (CHECK_PROOFS) CHECK_SOUND(expr.isEq(), "intEqIrrational invariant violated" + expr.toString()); Rational constant; Expr power; bool ok = d_theoryArith->isPowerEquality(expr, constant, power); if (CHECK_PROOFS) { CHECK_SOUND(ok, "intEqIrrational invariant violated" + expr.toString()); CHECK_SOUND(constant != 0, "intEqIrrational invariant violated" + expr.toString()); CHECK_SOUND(power[0].getRational() > 0, "intEqIrrational invariant violated" + expr.toString()); CHECK_SOUND(ratRoot(constant, power[0].getRational().getUnsigned()) == 0, "intEqIrrational invariant violated" + expr.toString()); CHECK_SOUND(isIntPred(isIntx.getExpr()) && isIntx.getExpr()[0] == expr[0], "intEqIrrational invariant violated" + isIntx.getExpr()[0].toString()); } const Assumptions& assump(isIntx.getAssumptionsRef()); Proof pf; if (withProof()) pf = newPf("int_eq_irr", expr, isIntx.getProof()); return newRWTheorem(expr, d_em->falseExpr(), assump, pf); } // e[0] kind e[1] <==> true when e[0] kind e[1], // false when e[0] !kind e[1], for constants only Theorem ArithTheoremProducerOld::constPredicate(const Expr& e) { if(CHECK_PROOFS) { CHECK_SOUND(e.arity() == 2 && isRational(e[0]) && isRational(e[1]), CLASS_NAME "::constPredicate:\n " "non-const parameters: " + e.toString()); } Proof pf; bool result(false); int kind = e.getKind(); Rational r1 = e[0].getRational(), r2 = e[1].getRational(); switch(kind) { case EQ: result = (r1 == r2)?true : false; break; case LT: result = (r1 < r2)?true : false; break; case LE: result = (r1 <= r2)?true : false; break; case GT: result = (r1 > r2)?true : false; break; case GE: result = (r1 >= r2)?true : false; break; default: if(CHECK_PROOFS) { CHECK_SOUND(false, "ArithTheoremProducerOld::constPredicate: wrong kind"); } break; } Expr ret = (result) ? d_em->trueExpr() : d_em->falseExpr(); if(withProof()) pf = newPf("const_predicate", e,ret); return newRWTheorem(e, ret, Assumptions::emptyAssump(), pf); } // e[0] kind e[1] <==> 0 kind e[1] - e[0] Theorem ArithTheoremProducerOld::rightMinusLeft(const Expr& e) { Proof pf; int kind = e.getKind(); if(CHECK_PROOFS) { CHECK_SOUND((EQ==kind) || (LT==kind) || (LE==kind) || (GE==kind) || (GT==kind), "ArithTheoremProducerOld::rightMinusLeft: wrong kind"); } if(withProof()) pf = newPf("right_minus_left",e); return newRWTheorem(e, Expr(e.getOp(), rat(0), e[1] - e[0]), Assumptions::emptyAssump(), pf); } // e[0] kind e[1] <==> 0 kind e[1] - e[0] Theorem ArithTheoremProducerOld::leftMinusRight(const Expr& e) { Proof pf; int kind = e.getKind(); if(CHECK_PROOFS) { CHECK_SOUND((EQ==kind) || (LT==kind) || (LE==kind) || (GE==kind) || (GT==kind), "ArithTheoremProducerOld::rightMinusLeft: wrong kind"); } if(withProof()) pf = newPf("left_minus_right",e); return newRWTheorem(e, Expr(e.getOp(), e[0] - e[1], rat(0)), Assumptions::emptyAssump(), pf); } // x kind y <==> x + z kind y + z Theorem ArithTheoremProducerOld::plusPredicate(const Expr& x, const Expr& y, const Expr& z, int kind) { if(CHECK_PROOFS) { CHECK_SOUND((EQ==kind) || (LT==kind) || (LE==kind) || (GE==kind) || (GT==kind), "ArithTheoremProducerOld::plusPredicate: wrong kind"); } Proof pf; Expr left = Expr(kind, x, y); Expr right = Expr(kind, x + z, y + z); if(withProof()) pf = newPf("plus_predicate",left,right); return newRWTheorem(left, right, Assumptions::emptyAssump(), pf); } // x = y <==> x * z = y * z Theorem ArithTheoremProducerOld::multEqn(const Expr& x, const Expr& y, const Expr& z) { Proof pf; if(CHECK_PROOFS) CHECK_SOUND(z.isRational() && z.getRational() != 0, "ArithTheoremProducerOld::multEqn(): multiplying equation by 0"); if(withProof()) pf = newPf("mult_eqn", x, y, z); return newRWTheorem(x.eqExpr(y), (x * z).eqExpr(y * z), Assumptions::emptyAssump(), pf); } // x = y <==> z=0 OR x * 1/z = y * 1/z Theorem ArithTheoremProducerOld::divideEqnNonConst(const Expr& x, const Expr& y, const Expr& z) { Proof pf; if(withProof()) pf = newPf("mult_eqn_nonconst", x, y, z); return newRWTheorem(x.eqExpr(y), (z.eqExpr(rat(0))).orExpr((x / z).eqExpr(y / z)), Assumptions::emptyAssump(), pf); } // if z is +ve, return e[0] LT|LE|GT|GE e[1] <==> e[0]*z LT|LE|GT|GE e[1]*z // if z is -ve, return e[0] LT|LE|GT|GE e[1] <==> e[1]*z LT|LE|GT|GE e[0]*z Theorem ArithTheoremProducerOld::multIneqn(const Expr& e, const Expr& z) { int kind = e.getKind(); if(CHECK_PROOFS) { CHECK_SOUND((LT==kind) || (LE==kind) || (GE==kind) || (GT==kind), "ArithTheoremProducerOld::multIneqn: wrong kind"); CHECK_SOUND(z.isRational() && z.getRational() != 0, "ArithTheoremProducerOld::multIneqn: " "z must be non-zero rational: " + z.toString()); } Op op(e.getOp()); Proof pf; Expr ret; if(0 < z.getRational()) ret = Expr(op, e[0]*z, e[1]*z); else ret = Expr(op, e[1]*z, e[0]*z); if(withProof()) pf = newPf("mult_ineqn", e, ret); return newRWTheorem(e, ret, Assumptions::emptyAssump(), pf); } // // If expr: // If b > 0 then (0 <= a + bx) <==> (0 <= floor(a/b) + x) // b < 0 then (0 <= a + bx) <==> (0 >= ceil(a/b) + x) // b > 0 then (0 >= a + bx) <==> (0 >= ceil(a/b) + x) // b < 0 then (0 >= a + bx) <==> (0 <= floor(a/b) + x) // Theorem ArithTheoremProducerOld::simpleIneqInt(const Expr& ineq, const Theorem& isIntRHS) { // Get the inequality parts Expr lhs = ineq[0]; Expr rhs = ineq[1]; // Get the kind of the inequality int kind = ineq.getKind(); if(CHECK_PROOFS) { // isIntRHS should be an int proof of rhs const Expr& isIntRHSExpr = isIntRHS.getExpr(); CHECK_SOUND(isIntPred(isIntRHSExpr) && isIntRHSExpr[0] == rhs, "ArithTheoremProducerOld::multSimpleIneqnInt: not an integer proof of rhs"); // It's an inequality CHECK_SOUND((LT == kind) || (LE==kind) || (GE==kind) || (GT==kind), "ArithTheoremProducerOld::multSimpleIneqnInt: wrong kind"); // Left-hand side is 0 CHECK_SOUND(lhs.isRational() && lhs.getRational() == 0, "ArithTheoremProducerOld::multSimpleIneqnInt: left-hand side must be 0"); // Tight hand side is a sum (a + b*x) where a and b are integers, x is a var CHECK_SOUND(isPlus(rhs), "ArithTheoremProducerOld::multSimpleIneqnInt: right-hand side must be a plus"); CHECK_SOUND(rhs.arity() == 2, "ArithTheoremProducerOld::multSimpleIneqnInt: right-hand side a simple plus"); Expr a = rhs[0]; // Should be an integer Expr bx = rhs[1]; // Should be an integer multiplied by a variable // a is an integer CHECK_SOUND(a.isRational() && a.getRational().isInteger(), "ArithTheoremProducerOld::multSimpleIneqnInt: right-hand side a simple plus of a constant"); // bx should be a multiplication of an intgere and a variable CHECK_SOUND(isMult(bx) && bx.arity() == 2, "ArithTheoremProducerOld::multSimpleIneqnInt: right-hand side a simple plus of and a multiplication"); Expr b = bx[0]; Expr x = bx[1]; // b should be an integer CHECK_SOUND(b.isRational() && b.getRational().isInteger(), "ArithTheoremProducerOld::multSimpleIneqnInt: right-hand side a simple plus of and a multiplication of a constant"); // x should be a variable CHECK_SOUND(x.isVar(), "ArithTheoremProducerOld::multSimpleIneqnInt: right-hand side a simple plus of and a multiplication of a constant and a leaf"); // GCD(a, b) should be 1 //CHECK_SOUND(gcd(a.getRational(), b.getRational()) == 1, "ArithTheoremProducerOld::multSimpleIneqnInt: inequation not normalized!!!"); } Proof pf; if(withProof()) { vector pfs; pfs.push_back(isIntRHS.getProof()); pf = newPf("simpleineqint", ineq, pf); } Rational a = rhs[0].getRational(); Rational b = rhs[1][0].getRational(); Expr x = rhs[1][1]; Rational new_const; Expr ret; switch (kind) { case LT: if (b > 0) { new_const = floor(a/b); if (new_const != 0) ret = Expr(kind, rat(0), rat(new_const) + x); else ret = Expr(kind, rat(0), x); } else { new_const = ceil(a/b); //ret = geExpr(rat(0), rat(new_const) + x); if (new_const != 0) ret = Expr(kind, rat(0), rat(-new_const) + rat(-1)*x); else ret = Expr(kind, rat(0), rat(-1)*x); } break; break; case LE: if (b > 0) { new_const = floor(a/b); if (new_const != 0) ret = Expr(kind, rat(0), rat(new_const) + x); else ret = Expr(kind, rat(0), x); } else { new_const = ceil(a/b); //ret = geExpr(rat(0), rat(new_const) + x); if (new_const != 0) ret = Expr(kind, rat(0), rat(-new_const) + rat(-1)*x); else ret = Expr(kind, rat(0), rat(-1)*x); } break; case GE: case GT: // Setup the result kind if (kind == GT) kind = LT; else kind = LE; if (b > 0) { new_const = ceil(a/b); //ret = geExpr(rat(0), rat(new_const) + x); if (new_const != 0) ret = Expr(kind, rat(0), rat(-new_const) + rat(-1)*x); else ret = Expr(kind, rat(0), rat(-1)*x); } else { new_const = floor(a/b); if (new_const != 0) ret = Expr(kind, rat(0), rat(new_const) + x); else ret = Expr(kind, rat(0), x); } break; } // Return the new theorem return newRWTheorem(ineq, ret, Assumptions::emptyAssump(), pf); } Theorem ArithTheoremProducerOld::eqToIneq(const Expr& e) { // Check soundness of the rule if necessary if (CHECK_PROOFS) CHECK_SOUND(e.isEq(), "eqToIneq: input must be an equality: " + e.toString()); // The proof object we will use Proof pf; // The parts of the equality x = y const Expr& x = e[0]; const Expr& y = e[1]; // Setup the proof if needed if (withProof()) pf = newPf("eqToIneq", e); // Retrun the theorem explaining the transformation return newRWTheorem(e, leExpr(x,y).andExpr(geExpr(x,y)), Assumptions::emptyAssump(), pf); } // "op1 GE|GT op2" <==> op2 LE|LT op1 Theorem ArithTheoremProducerOld::flipInequality(const Expr& e) { Proof pf; if(CHECK_PROOFS) { CHECK_SOUND(isGT(e) || isGE(e), "ArithTheoremProducerOld::flipInequality: wrong kind: " + e.toString()); } int kind = isGE(e) ? LE : LT; Expr ret = Expr(kind, e[1], e[0]); if(withProof()) pf = newPf("flip_inequality", e,ret); return newRWTheorem(e,ret, Assumptions::emptyAssump(), pf); } // NOT (op1 LT op2) <==> (op1 GE op2) // NOT (op1 LE op2) <==> (op1 GT op2) // NOT (op1 GT op2) <==> (op1 LE op2) // NOT (op1 GE op2) <==> (op1 LT op2) Theorem ArithTheoremProducerOld::negatedInequality(const Expr& e) { const Expr& ineq = e[0]; if(CHECK_PROOFS) { CHECK_SOUND(e.isNot(), "ArithTheoremProducerOld::negatedInequality: wrong kind: " + e.toString()); CHECK_SOUND(isIneq(ineq), "ArithTheoremProducerOld::negatedInequality: wrong kind: " + (ineq).toString()); } Proof pf; if(withProof()) pf = newPf("negated_inequality", e); int kind; // NOT (op1 LT op2) <==> (op1 GE op2) // NOT (op1 LE op2) <==> (op1 GT op2) // NOT (op1 GT op2) <==> (op1 LE op2) // NOT (op1 GE op2) <==> (op1 LT op2) kind = isLT(ineq) ? GE : isLE(ineq) ? GT : isGT(ineq) ? LE : LT; return newRWTheorem(e, Expr(kind, ineq[0], ineq[1]), Assumptions::emptyAssump(), pf); } //takes two ineqs "|- alpha LT|LE t" and "|- t LT|LE beta" //and returns "|- alpha LT|LE beta" Theorem ArithTheoremProducerOld::realShadow(const Theorem& alphaLTt, const Theorem& tLTbeta) { const Expr& expr1 = alphaLTt.getExpr(); const Expr& expr2 = tLTbeta.getExpr(); if(CHECK_PROOFS) { CHECK_SOUND((isLE(expr1) || isLT(expr1)) && (isLE(expr2) || isLT(expr2)), "ArithTheoremProducerOld::realShadow: Wrong Kind: " + alphaLTt.toString() + tLTbeta.toString()); CHECK_SOUND(expr1[1] == expr2[0], "ArithTheoremProducerOld::realShadow:" " t must be same for both inputs: " + expr1[1].toString() + " , " + expr2[0].toString()); } Assumptions a(alphaLTt, tLTbeta); int firstKind = expr1.getKind(); int secondKind = expr2.getKind(); int kind = (firstKind == secondKind) ? firstKind : LT; Proof pf; if(withProof()) { vector pfs; pfs.push_back(alphaLTt.getProof()); pfs.push_back(tLTbeta.getProof()); pf = newPf("real_shadow",expr1, expr2, pfs); } return newTheorem(Expr(kind, expr1[0], expr2[1]), a, pf); } //! alpha <= t <= alpha ==> t = alpha /*! takes two ineqs "|- alpha LE t" and "|- t LE alpha" and returns "|- t = alpha" */ Theorem ArithTheoremProducerOld::realShadowEq(const Theorem& alphaLEt, const Theorem& tLEalpha) { const Expr& expr1 = alphaLEt.getExpr(); const Expr& expr2 = tLEalpha.getExpr(); if(CHECK_PROOFS) { CHECK_SOUND(isLE(expr1) && isLE(expr2), "ArithTheoremProducerOld::realShadowLTLE: Wrong Kind: " + alphaLEt.toString() + tLEalpha.toString()); CHECK_SOUND(expr1[1] == expr2[0], "ArithTheoremProducerOld::realShadowLTLE:" " t must be same for both inputs: " + alphaLEt.toString() + " , " + tLEalpha.toString()); CHECK_SOUND(expr1[0] == expr2[1], "ArithTheoremProducerOld::realShadowLTLE:" " alpha must be same for both inputs: " + alphaLEt.toString() + " , " + tLEalpha.toString()); } Assumptions a(alphaLEt, tLEalpha); Proof pf; if(withProof()) { vector pfs; pfs.push_back(alphaLEt.getProof()); pfs.push_back(tLEalpha.getProof()); pf = newPf("real_shadow_eq", alphaLEt.getExpr(), tLEalpha.getExpr(), pfs); } return newRWTheorem(expr1[0], expr1[1], a, pf); } Theorem ArithTheoremProducerOld::finiteInterval(const Theorem& aLEt, const Theorem& tLEac, const Theorem& isInta, const Theorem& isIntt) { const Expr& e1 = aLEt.getExpr(); const Expr& e2 = tLEac.getExpr(); if(CHECK_PROOFS) { CHECK_SOUND(isLE(e1) && isLE(e2), "ArithTheoremProducerOld::finiteInterval:\n e1 = " +e1.toString()+"\n e2 = "+e2.toString()); // term 't' is the same in both inequalities CHECK_SOUND(e1[1] == e2[0], "ArithTheoremProducerOld::finiteInterval:\n e1 = " +e1.toString()+"\n e2 = "+e2.toString()); // RHS in e2 is (a+c) CHECK_SOUND(isPlus(e2[1]) && e2[1].arity() == 2, "ArithTheoremProducerOld::finiteInterval:\n e1 = " +e1.toString()+"\n e2 = "+e2.toString()); // term 'a' in LHS of e1 and RHS of e2 is the same CHECK_SOUND(e1[0] == e2[1][0], "ArithTheoremProducerOld::finiteInterval:\n e1 = " +e1.toString()+"\n e2 = "+e2.toString()); // 'c' in the RHS of e2 is a positive integer constant CHECK_SOUND(e2[1][1].isRational() && e2[1][1].getRational().isInteger() && e2[1][1].getRational() >= 1, "ArithTheoremProducerOld::finiteInterval:\n e1 = " +e1.toString()+"\n e2 = "+e2.toString()); // Integrality constraints const Expr& isIntaExpr = isInta.getExpr(); const Expr& isInttExpr = isIntt.getExpr(); CHECK_SOUND(isIntPred(isIntaExpr) && isIntaExpr[0] == e1[0], "Wrong integrality constraint:\n e1 = " +e1.toString()+"\n isInta = "+isIntaExpr.toString()); CHECK_SOUND(isIntPred(isInttExpr) && isInttExpr[0] == e1[1], "Wrong integrality constraint:\n e1 = " +e1.toString()+"\n isIntt = "+isInttExpr.toString()); } vector thms; thms.push_back(aLEt); thms.push_back(tLEac); thms.push_back(isInta); thms.push_back(isIntt); Assumptions a(thms); Proof pf; if(withProof()) { vector es; vector pfs; es.push_back(e1); es.push_back(e2); es.push_back(isInta.getExpr()); es.push_back(isIntt.getExpr()); pfs.push_back(aLEt.getProof()); pfs.push_back(tLEac.getProof()); pfs.push_back(isInta.getProof()); pfs.push_back(isIntt.getProof()); pf = newPf("finite_interval", es, pfs); } // Construct GRAY_SHADOW(t, a, 0, c) Expr g(grayShadow(e1[1], e1[0], 0, e2[1][1].getRational())); return newTheorem(g, a, pf); } // Dark & Gray shadows when a <= b Theorem ArithTheoremProducerOld::darkGrayShadow2ab(const Theorem& betaLEbx, const Theorem& axLEalpha, const Theorem& isIntAlpha, const Theorem& isIntBeta, const Theorem& isIntx) { const Expr& expr1 = betaLEbx.getExpr(); const Expr& expr2 = axLEalpha.getExpr(); const Expr& isIntAlphaExpr = isIntAlpha.getExpr(); const Expr& isIntBetaExpr = isIntBeta.getExpr(); const Expr& isIntxExpr = isIntx.getExpr(); if(CHECK_PROOFS) { CHECK_SOUND(isLE(expr1) && isLE(expr2), "ArithTheoremProducerOld::darkGrayShadow2ab: Wrong Kind: " + betaLEbx.toString() + axLEalpha.toString()); } const Expr& beta = expr1[0]; const Expr& bx = expr1[1]; const Expr& ax = expr2[0]; const Expr& alpha = expr2[1]; Expr a_expr, b_expr, x; d_theoryArith->separateMonomial(ax, a_expr, x); d_theoryArith->separateMonomial(bx, b_expr, x); Rational a = a_expr.getRational(); Rational b = b_expr.getRational(); if(CHECK_PROOFS) { // Integrality constraints CHECK_SOUND(isIntPred(isIntAlphaExpr) && isIntAlphaExpr[0] == alpha, "ArithTheoremProducerOld::darkGrayShadow2ab:\n " "wrong integrality constraint:\n alpha = " +alpha.toString()+"\n isIntAlpha = " +isIntAlphaExpr.toString()); CHECK_SOUND(isIntPred(isIntBetaExpr) && isIntBetaExpr[0] == beta, "ArithTheoremProducerOld::darkGrayShadow2ab:\n " "wrong integrality constraint:\n beta = " +beta.toString()+"\n isIntBeta = " +isIntBetaExpr.toString()); CHECK_SOUND(isIntPred(isIntxExpr) && isIntxExpr[0] == x, "ArithTheoremProducerOld::darkGrayShadow2ab:\n " "wrong integrality constraint:\n x = " +x.toString()+"\n isIntx = " +isIntxExpr.toString()); // NOT FOR NONLINEAR: Expressions ax and bx should match on x // CHECK_SOUND(!isMult(ax) || ax.arity() == 2, // "ArithTheoremProducerOld::darkGrayShadow2ab:\n ax<=alpha: " + // axLEalpha.toString()); // CHECK_SOUND(!isMult(bx) || (bx.arity() == 2 && bx[1] == x), // "ArithTheoremProducerOld::darkGrayShadow2ab:\n beta<=bx: " // +betaLEbx.toString() // +"\n ax<=alpha: "+ axLEalpha.toString()); CHECK_SOUND(1 <= a && a <= b && 2 <= b, "ArithTheoremProducerOld::darkGrayShadow2ab:\n beta<=bx: " +betaLEbx.toString() +"\n ax<=alpha: "+ axLEalpha.toString()); } vector thms; thms.push_back(betaLEbx); thms.push_back(axLEalpha); thms.push_back(isIntAlpha); thms.push_back(isIntBeta); thms.push_back(isIntx); Assumptions A(thms); Expr bAlpha = multExpr(rat(b), alpha); Expr aBeta = multExpr(rat(a), beta); Expr t = minusExpr(bAlpha, aBeta); Expr d = geExpr(t, rat(a*b-1)); Expr g = grayShadow(ax, alpha, -a+1, 0); Proof pf; if(withProof()) { vector exprs; exprs.push_back(expr1); exprs.push_back(expr2); exprs.push_back(d); exprs.push_back(g); vector pfs; pfs.push_back(betaLEbx.getProof()); pfs.push_back(axLEalpha.getProof()); pfs.push_back(isIntAlpha.getProof()); pfs.push_back(isIntBeta.getProof()); pfs.push_back(isIntx.getProof()); pf = newPf("dark_grayshadow_2ab", exprs, pfs); } return newTheorem((d || g), A, pf); } // Dark & Gray shadows when b <= a Theorem ArithTheoremProducerOld::darkGrayShadow2ba(const Theorem& betaLEbx, const Theorem& axLEalpha, const Theorem& isIntAlpha, const Theorem& isIntBeta, const Theorem& isIntx) { const Expr& expr1 = betaLEbx.getExpr(); const Expr& expr2 = axLEalpha.getExpr(); const Expr& isIntAlphaExpr = isIntAlpha.getExpr(); const Expr& isIntBetaExpr = isIntBeta.getExpr(); const Expr& isIntxExpr = isIntx.getExpr(); if(CHECK_PROOFS) { CHECK_SOUND(isLE(expr1) && isLE(expr2), "ArithTheoremProducerOld::darkGrayShadow2ba: Wrong Kind: " + betaLEbx.toString() + axLEalpha.toString()); } const Expr& beta = expr1[0]; const Expr& bx = expr1[1]; const Expr& ax = expr2[0]; const Expr& alpha = expr2[1]; Expr a_expr, b_expr, x; d_theoryArith->separateMonomial(ax, a_expr, x); d_theoryArith->separateMonomial(bx, b_expr, x); Rational a = a_expr.getRational(); Rational b = b_expr.getRational(); if(CHECK_PROOFS) { // Integrality constraints CHECK_SOUND(isIntPred(isIntAlphaExpr) && isIntAlphaExpr[0] == alpha, "ArithTheoremProducerOld::darkGrayShadow2ab:\n " "wrong integrality constraint:\n alpha = " +alpha.toString()+"\n isIntAlpha = " +isIntAlphaExpr.toString()); CHECK_SOUND(isIntPred(isIntBetaExpr) && isIntBetaExpr[0] == beta, "ArithTheoremProducerOld::darkGrayShadow2ab:\n " "wrong integrality constraint:\n beta = " +beta.toString()+"\n isIntBeta = " +isIntBetaExpr.toString()); CHECK_SOUND(isIntPred(isIntxExpr) && isIntxExpr[0] == x, "ArithTheoremProducerOld::darkGrayShadow2ab:\n " "wrong integrality constraint:\n x = " +x.toString()+"\n isIntx = " +isIntxExpr.toString()); // NOT FOR NONLINEAR: Expressions ax and bx should match on x // CHECK_SOUND(!isMult(ax) || ax.arity() == 2, // "ArithTheoremProducerOld::darkGrayShadow2ba:\n ax<=alpha: " + // axLEalpha.toString()); // CHECK_SOUND(!isMult(bx) || (bx.arity() == 2 && bx[1] == x), // "ArithTheoremProducerOld::darkGrayShadow2ba:\n beta<=bx: " // +betaLEbx.toString() // +"\n ax<=alpha: "+ axLEalpha.toString()); CHECK_SOUND(1 <= b && b <= a && 2 <= a, "ArithTheoremProducerOld::darkGrayShadow2ba:\n beta<=bx: " +betaLEbx.toString() +"\n ax<=alpha: "+ axLEalpha.toString()); } vector thms; thms.push_back(betaLEbx); thms.push_back(axLEalpha); thms.push_back(isIntAlpha); thms.push_back(isIntBeta); thms.push_back(isIntx); Assumptions A(thms); Proof pf; if(withProof()) { vector pfs; pfs.push_back(betaLEbx.getProof()); pfs.push_back(axLEalpha.getProof()); pfs.push_back(isIntAlpha.getProof()); pfs.push_back(isIntBeta.getProof()); pfs.push_back(isIntx.getProof()); pf = newPf("dark_grayshadow_2ba", betaLEbx.getExpr(), axLEalpha.getExpr(), pfs); } Expr bAlpha = multExpr(rat(b), alpha); Expr aBeta = multExpr(rat(a), beta); Expr t = minusExpr(bAlpha, aBeta); Expr d = geExpr(t, rat(a*b-1)); Expr g = grayShadow(bx, beta, 0, b-1); return newTheorem((d || g), A, pf); } /*! takes a dark shadow and expands it into an inequality. */ Theorem ArithTheoremProducerOld::expandDarkShadow(const Theorem& darkShadow) { const Expr& theShadow = darkShadow.getExpr(); if(CHECK_PROOFS){ CHECK_SOUND(isDarkShadow(theShadow), "ArithTheoremProducerOld::expandDarkShadow: not DARK_SHADOW: " + theShadow.toString()); } Proof pf; if(withProof()) pf = newPf("expand_dark_shadow", theShadow, darkShadow.getProof()); return newTheorem(leExpr(theShadow[0], theShadow[1]), darkShadow.getAssumptionsRef(), pf); } // takes a grayShadow (c1==c2) and expands it into an equality Theorem ArithTheoremProducerOld::expandGrayShadow0(const Theorem& grayShadow) { const Expr& theShadow = grayShadow.getExpr(); if(CHECK_PROOFS) { CHECK_SOUND(isGrayShadow(theShadow), "ArithTheoremProducerOld::expandGrayShadowConst0:" " not GRAY_SHADOW: " + theShadow.toString()); CHECK_SOUND(theShadow[2] == theShadow[3], "ArithTheoremProducerOld::expandGrayShadow0: c1!=c2: " + theShadow.toString()); } Proof pf; if(withProof()) pf = newPf("expand_gray_shadowconst0", theShadow, grayShadow.getProof()); const Expr& v = theShadow[0]; const Expr& e = theShadow[1]; return newRWTheorem(v, e + theShadow[2], grayShadow.getAssumptionsRef(), pf); } // G ==> (G1 or G2) and (!G1 or !G2), // where G = G(x, e, c1, c2), // G1 = G(x,e,c1,c) // G2 = G(x,e,c+1,c2), // and c = floor((c1+c2)/2) Theorem ArithTheoremProducerOld::splitGrayShadow(const Theorem& gThm) { const Expr& theShadow = gThm.getExpr(); if(CHECK_PROOFS) { CHECK_SOUND(isGrayShadow(theShadow), "ArithTheoremProducerOld::expandGrayShadowConst: not a shadow" + theShadow.toString()); } const Rational& c1 = theShadow[2].getRational(); const Rational& c2 = theShadow[3].getRational(); if(CHECK_PROOFS) { CHECK_SOUND(c1.isInteger() && c2.isInteger() && c1 < c2, "ArithTheoremProducerOld::expandGrayShadow: " + theShadow.toString()); } const Expr& v = theShadow[0]; const Expr& e = theShadow[1]; Proof pf; Rational c(floor((c1+c2) / 2)); Expr g1(grayShadow(v, e, c1, c)); Expr g2(grayShadow(v, e, c+1, c2)); if(withProof()){ vector exprs; exprs.push_back(theShadow); exprs.push_back(g1); exprs.push_back(g2); pf = newPf("split_gray_shadow", exprs, gThm.getProof()); } return newTheorem((g1 || g2) && (!g1 || !g2), gThm.getAssumptionsRef(), pf); } Theorem ArithTheoremProducerOld::expandGrayShadow(const Theorem& gThm) { const Expr& theShadow = gThm.getExpr(); if(CHECK_PROOFS) { CHECK_SOUND(isGrayShadow(theShadow), "ArithTheoremProducerOld::expandGrayShadowConst: not a shadow" + theShadow.toString()); } const Rational& c1 = theShadow[2].getRational(); const Rational& c2 = theShadow[3].getRational(); if(CHECK_PROOFS) { CHECK_SOUND(c1.isInteger() && c2.isInteger() && c1 < c2, "ArithTheoremProducerOld::expandGrayShadow: " + theShadow.toString()); } const Expr& v = theShadow[0]; const Expr& e = theShadow[1]; Proof pf; if(withProof()) pf = newPf("expand_gray_shadow", theShadow, gThm.getProof()); Expr ineq1(leExpr(e+rat(c1), v)); Expr ineq2(leExpr(v, e+rat(c2))); return newTheorem(ineq1 && ineq2, gThm.getAssumptionsRef(), pf); } // Expanding GRAY_SHADOW(a*x, c, b), where c is a constant Theorem ArithTheoremProducerOld::expandGrayShadowConst(const Theorem& gThm) { const Expr& theShadow = gThm.getExpr(); const Expr& ax = theShadow[0]; const Expr& cExpr = theShadow[1]; const Expr& bExpr = theShadow[2]; if(CHECK_PROOFS) { CHECK_SOUND(!isMult(ax) || ax[0].isRational(), "ArithTheoremProducerOld::expandGrayShadowConst: " "'a' in a*x is not a const: " +theShadow.toString()); } Rational a = isMult(ax)? ax[0].getRational() : 1; if(CHECK_PROOFS) { CHECK_SOUND(isGrayShadow(theShadow), "ArithTheoremProducerOld::expandGrayShadowConst: " "not a GRAY_SHADOW: " +theShadow.toString()); CHECK_SOUND(a.isInteger() && a >= 1, "ArithTheoremProducerOld::expandGrayShadowConst: " "'a' is not integer: " +theShadow.toString()); CHECK_SOUND(cExpr.isRational(), "ArithTheoremProducerOld::expandGrayShadowConst: " "'c' is not rational" +theShadow.toString()); CHECK_SOUND(bExpr.isRational() && bExpr.getRational().isInteger(), "ArithTheoremProducerOld::expandGrayShadowConst: b not integer: " +theShadow.toString()); } const Rational& b = bExpr.getRational(); const Rational& c = cExpr.getRational(); Rational j = constRHSGrayShadow(c,b,a); // Compute sign(b)*j(c,b,a) Rational signB = (b>0)? 1 : -1; // |b| (absolute value of b) Rational bAbs = abs(b); const Assumptions& assump(gThm.getAssumptionsRef()); Proof pf; Theorem conc; // Conclusion of the rule if(bAbs < j) { if(withProof()) pf = newPf("expand_gray_shadow_const_0", theShadow, gThm.getProof()); conc = newTheorem(d_em->falseExpr(), assump, pf); } else if(bAbs < a+j) { if(withProof()) pf = newPf("expand_gray_shadow_const_1", theShadow, gThm.getProof()); conc = newRWTheorem(ax, rat(c+b-signB*j), assump, pf); } else { if(withProof()) pf = newPf("expand_gray_shadow_const", theShadow, gThm.getProof()); Expr newGrayShadow(Expr(GRAY_SHADOW, ax, cExpr, rat(b-signB*(a+j)))); conc = newTheorem(ax.eqExpr(rat(c+b-signB*j)).orExpr(newGrayShadow), assump, pf); } return conc; } Theorem ArithTheoremProducerOld::grayShadowConst(const Theorem& gThm) { const Expr& g = gThm.getExpr(); bool checkProofs(CHECK_PROOFS); if(checkProofs) { CHECK_SOUND(isGrayShadow(g), "ArithTheoremProducerOld::grayShadowConst(" +g.toString()+")"); } const Expr& ax = g[0]; const Expr& e = g[1]; const Rational& c1 = g[2].getRational(); const Rational& c2 = g[3].getRational(); Expr aExpr, x; d_theoryArith->separateMonomial(ax, aExpr, x); if(checkProofs) { CHECK_SOUND(e.isRational() && e.getRational().isInteger(), "ArithTheoremProducerOld::grayShadowConst("+g.toString()+")"); CHECK_SOUND(aExpr.isRational(), "ArithTheoremProducerOld::grayShadowConst("+g.toString()+")"); } const Rational& a = aExpr.getRational(); const Rational& c = e.getRational(); if(checkProofs) { CHECK_SOUND(a.isInteger() && a >= 2, "ArithTheoremProducerOld::grayShadowConst("+g.toString()+")"); } Rational newC1 = ceil((c1+c)/a), newC2 = floor((c2+c)/a); Expr newG((newC1 > newC2)? d_em->falseExpr() : grayShadow(x, rat(0), newC1, newC2)); Proof pf; if(withProof()) pf = newPf("gray_shadow_const", g, newG, gThm.getProof()); return newTheorem(newG, gThm.getAssumptionsRef(), pf); } Rational ArithTheoremProducerOld::constRHSGrayShadow(const Rational& c, const Rational& b, const Rational& a) { DebugAssert(c.isInteger() && b.isInteger() && a.isInteger() && b != 0, "ArithTheoremProducerOld::constRHSGrayShadow: a, b, c must be ints"); if (b > 0) return mod(c+b, a); else return mod(a-(c+b), a); } /*! Takes a Theorem(\\alpha < \\beta) and returns * Theorem(\\alpha < \\beta <==> \\alpha <= \\beta -1) * where \\alpha and \\beta are integer expressions */ Theorem ArithTheoremProducerOld::lessThanToLE(const Theorem& less, const Theorem& isIntLHS, const Theorem& isIntRHS, bool changeRight) { const Expr& ineq = less.getExpr(); const Expr& isIntLHSexpr = isIntLHS.getExpr(); const Expr& isIntRHSexpr = isIntRHS.getExpr(); if(CHECK_PROOFS) { CHECK_SOUND(isLT(ineq), "ArithTheoremProducerOld::LTtoLE: ineq must be <"); // Integrality check CHECK_SOUND(isIntPred(isIntLHSexpr) && isIntLHSexpr[0] == ineq[0], "ArithTheoremProducerOld::lessThanToLE: bad integrality check:\n" " ineq = "+ineq.toString()+"\n isIntLHS = " +isIntLHSexpr.toString()); CHECK_SOUND(isIntPred(isIntRHSexpr) && isIntRHSexpr[0] == ineq[1], "ArithTheoremProducerOld::lessThanToLE: bad integrality check:\n" " ineq = "+ineq.toString()+"\n isIntRHS = " +isIntRHSexpr.toString()); } vector thms; thms.push_back(less); thms.push_back(isIntLHS); thms.push_back(isIntRHS); Assumptions a(thms); Proof pf; Expr le = changeRight? leExpr(ineq[0], ineq[1] + rat(-1)) : leExpr(ineq[0] + rat(1), ineq[1]); if(withProof()) { vector pfs; pfs.push_back(less.getProof()); pfs.push_back(isIntLHS.getProof()); pfs.push_back(isIntRHS.getProof()); pf = newPf(changeRight? "lessThan_To_LE_rhs" : "lessThan_To_LE_lhs", ineq,le, pfs); } return newRWTheorem(ineq, le, a, pf); } /*! \param eqn is an equation 0 = a.x or 0 = c + a.x * \param isIntx is a proof of IS_INTEGER(x) * * \return the theorem 0 = c + a.x <==> x=-c/a if -c/a is int else * return the theorem 0 = c + a.x <==> false. * * It also handles the special case of 0 = a.x <==> x = 0 */ Theorem ArithTheoremProducerOld::intVarEqnConst(const Expr& eqn, const Theorem& isIntx) { const Expr& left(eqn[0]); const Expr& right(eqn[1]); const Expr& isIntxexpr(isIntx.getExpr()); if(CHECK_PROOFS) { CHECK_SOUND((isMult(right) && right[0].isRational()) || (right.arity() == 2 && isPlus(right) && right[0].isRational() && ((!isMult(right[1]) || right[1][0].isRational()))), "ArithTheoremProducerOld::intVarEqnConst: " "rhs has a wrong format: " + right.toString()); CHECK_SOUND(left.isRational() && 0 == left.getRational(), "ArithTheoremProducerOld:intVarEqnConst:left is not a zero: " + left.toString()); } // Integrality constraint Expr x(right); Rational a(1), c(0); if(isMult(right)) { Expr aExpr; d_theoryArith->separateMonomial(right, aExpr, x); a = aExpr.getRational(); } else { // right is a PLUS c = right[0].getRational(); Expr aExpr; d_theoryArith->separateMonomial(right[1], aExpr, x); a = aExpr.getRational(); } if(CHECK_PROOFS) { CHECK_SOUND(isIntPred(isIntxexpr) && isIntxexpr[0] == x, "ArithTheoremProducerOld:intVarEqnConst: " "bad integrality constraint:\n right = " + right.toString()+"\n isIntx = "+isIntxexpr.toString()); CHECK_SOUND(a!=0, "ArithTheoremProducerOld:intVarEqnConst: eqn = " +eqn.toString()); } const Assumptions& assump(isIntx.getAssumptionsRef()); /* Proof pf; if(withProof()) pf = newPf("int_const_eq", eqn, isIntx.getProof()); // Solve for x: x = r = -c/a Rational r(-c/a); if(r.isInteger()){ return newRWTheorem(eqn, x.eqExpr(rat(r)), assump, pf); else return newRWTheorem(eqn, d_em->falseExpr(), assump, pf); */ Proof pf; // Solve for x: x = r = -c/a Rational r(-c/a); if(r.isInteger()){ if(withProof()) pf = newPf("int_const_eq", eqn, x.eqExpr(rat(r)),isIntx.getProof()); return newRWTheorem(eqn, x.eqExpr(rat(r)), assump, pf); } else{ if(withProof()) pf = newPf("int_const_eq", eqn, d_em->falseExpr(),isIntx.getProof()); return newRWTheorem(eqn, d_em->falseExpr(), assump, pf); } } Expr ArithTheoremProducerOld::create_t(const Expr& eqn) { const Expr& lhs = eqn[0]; DebugAssert(isMult(lhs), CLASS_NAME "create_t : lhs must be a MULT" + lhs.toString()); const Expr& x = lhs[1]; Rational m = lhs[0].getRational()+1; DebugAssert(m > 0, "ArithTheoremProducerOld::create_t: m = "+m.toString()); vector kids; if(isPlus(eqn[1])) sumModM(kids, eqn[1], m, m); else kids.push_back(monomialModM(eqn[1], m, m)); kids.push_back(multExpr(rat(1/m), x)); return plusExpr(kids); } Expr ArithTheoremProducerOld::create_t2(const Expr& lhs, const Expr& rhs, const Expr& sigma) { Rational m = lhs[0].getRational()+1; DebugAssert(m > 0, "ArithTheoremProducerOld::create_t2: m = "+m.toString()); vector kids; if(isPlus(rhs)) sumModM(kids, rhs, m, -1); else { kids.push_back(rat(0)); // For canonical form Expr monom = monomialModM(rhs, m, -1); if(!monom.isRational()) kids.push_back(monom); else DebugAssert(monom.getRational() == 0, ""); } kids.push_back(rat(m)*sigma); return plusExpr(kids); } Expr ArithTheoremProducerOld::create_t3(const Expr& lhs, const Expr& rhs, const Expr& sigma) { const Rational& a = lhs[0].getRational(); Rational m = a+1; DebugAssert(m > 0, "ArithTheoremProducerOld::create_t3: m = "+m.toString()); vector kids; if(isPlus(rhs)) sumMulF(kids, rhs, m, 1); else { kids.push_back(rat(0)); // For canonical form Expr monom = monomialMulF(rhs, m, 1); if(!monom.isRational()) kids.push_back(monom); else DebugAssert(monom.getRational() == 0, ""); } kids.push_back(rat(-a)*sigma); return plusExpr(kids); } Rational ArithTheoremProducerOld::modEq(const Rational& i, const Rational& m) { DebugAssert(m > 0, "ArithTheoremProducerOld::modEq: m = "+m.toString()); Rational half(1,2); Rational res((i - m*(floor((i/m) + half)))); TRACE("arith eq", "modEq("+i.toString()+", "+m.toString()+") = ", res, ""); return res; } Rational ArithTheoremProducerOld::f(const Rational& i, const Rational& m) { DebugAssert(m > 0, "ArithTheoremProducerOld::f: m = "+m.toString()); Rational half(1,2); return (floor(i/m + half)+modEq(i,m)); } void ArithTheoremProducerOld::sumModM(vector& summands, const Expr& sum, const Rational& m, const Rational& divisor) { DebugAssert(divisor != 0, "ArithTheoremProducerOld::sumModM: divisor = " +divisor.toString()); Expr::iterator i = sum.begin(); DebugAssert(i != sum.end(), CLASS_NAME "::sumModM"); Rational C = i->getRational(); C = modEq(C,m)/divisor; summands.push_back(rat(C)); i++; for(Expr::iterator iend=sum.end(); i!=iend; ++i) { Expr monom = monomialModM(*i, m, divisor); if(!monom.isRational()) summands.push_back(monom); else DebugAssert(monom.getRational() == 0, ""); } } Expr ArithTheoremProducerOld::monomialModM(const Expr& i, const Rational& m, const Rational& divisor) { DebugAssert(divisor != 0, "ArithTheoremProducerOld::monomialModM: divisor = " +divisor.toString()); Expr res; if(isMult(i)) { Rational ai = i[0].getRational(); ai = modEq(ai,m)/divisor; if(0 == ai) res = rat(0); else if(1 == ai && i.arity() == 2) res = i[1]; else { vector kids = i.getKids(); kids[0] = rat(ai); res = multExpr(kids); } } else { // It's a single variable Rational ai = modEq(1,m)/divisor; if(1 == ai) res = i; else res = rat(ai)*i; } DebugAssert(!res.isNull(), "ArithTheoremProducerOld::monomialModM()"); TRACE("arith eq", "monomialModM(i="+i.toString()+", m="+m.toString() +", div="+divisor.toString()+") = ", res, ""); return res; } void ArithTheoremProducerOld::sumMulF(vector& summands, const Expr& sum, const Rational& m, const Rational& divisor) { DebugAssert(divisor != 0, "ArithTheoremProducerOld::sumMulF: divisor = " +divisor.toString()); Expr::iterator i = sum.begin(); DebugAssert(i != sum.end(), CLASS_NAME "::sumModM"); Rational C = i->getRational(); C = f(C,m)/divisor; summands.push_back(rat(C)); i++; for(Expr::iterator iend=sum.end(); i!=iend; ++i) { Expr monom = monomialMulF(*i, m, divisor); if(!monom.isRational()) summands.push_back(monom); else DebugAssert(monom.getRational() == 0, ""); } } Expr ArithTheoremProducerOld::monomialMulF(const Expr& i, const Rational& m, const Rational& divisor) { DebugAssert(divisor != 0, "ArithTheoremProducerOld::monomialMulF: divisor = " +divisor.toString()); Rational ai = isMult(i) ? (i)[0].getRational() : 1; Expr xi = isMult(i) ? (i)[1] : (i); ai = f(ai,m)/divisor; if(0 == ai) return rat(0); if(1 == ai) return xi; return multExpr(rat(ai), xi); } // This recursive function accepts a term, t, and a 'map' of // substitutions [x1/t1, x2/t2,...,xn/tn]. it returns a t' which is // basically t[x1/t1,x2/t2...xn/tn] Expr ArithTheoremProducerOld::substitute(const Expr& term, ExprMap& eMap) { ExprMap::iterator i, iend = eMap.end(); i = eMap.find(term); if(iend != i) return (*i).second; if (isMult(term)) { //in this case term is of the form c.x i = eMap.find(term[1]); if(iend != i) return term[0]*(*i).second; else return term; } if(isPlus(term)) { vector output; for(Expr::iterator j = term.begin(), jend = term.end(); j != jend; ++j) output.push_back(substitute(*j, eMap)); return plusExpr(output); } return term; } bool ArithTheoremProducerOld::greaterthan(const Expr & l, const Expr & r) { // DebugAssert(l != r, ""); if (l==r) return false; switch(l.getKind()) { case RATIONAL_EXPR: DebugAssert(!r.isRational(), ""); return true; break; case POW: switch (r.getKind()) { case RATIONAL_EXPR: // TODO: // alternately I could return (not greaterthan(r,l)) return false; break; case POW: // x^n > y^n if x > y // x^n1 > x^n2 if n1 > n2 return ((r[1] < l[1]) || ((r[1]==l[1]) && (r[0].getRational() < l[0].getRational()))); break; case MULT: DebugAssert(r.arity() > 1, ""); DebugAssert((r.arity() > 2) || (r[1] != l), ""); if (r[1] == l) return false; return greaterthan(l, r[1]); break; case PLUS: DebugAssert(false, ""); return true; break; default: // leaf return ((r < l[1]) || ((r == l[1]) && l[0].getRational() > 1)); break; } break; case MULT: DebugAssert(l.arity() > 1, ""); switch (r.getKind()) { case RATIONAL_EXPR: return false; break; case POW: DebugAssert(l.arity() > 1, ""); DebugAssert((l.arity() > 2) || (l[1] != r), ""); // TODO: // alternately return (not greaterthan(r,l) return ((l[1] == r) || greaterthan(l[1], r)); break; case MULT: { DebugAssert(r.arity() > 1, ""); Expr::iterator i = l.begin(); Expr::iterator j = r.begin(); ++i; ++j; for (; i != l.end() && j != r.end(); ++i, ++j) { if (*i == *j) continue; return greaterthan(*i,*j); } DebugAssert(i != l.end() || j != r.end(), ""); if (i == l.end()) { // r is bigger return false; } else { // l is bigger return true; } } break; case PLUS: DebugAssert(false, ""); return true; break; default: // leaf DebugAssert((l.arity() > 2) || (l[1] != r), ""); return ((l[1] == r) || greaterthan(l[1], r)); break; } break; case PLUS: DebugAssert(false, ""); return true; break; default: // leaf switch (r.getKind()) { case RATIONAL_EXPR: return false; break; case POW: return ((r[1] < l) || ((r[1] == l) && (r[0].getRational() < 1))); break; case MULT: DebugAssert(r.arity() > 1, ""); DebugAssert((r.arity() > 2) || (r[1] != l), ""); if (l == r[1]) return false; return greaterthan(l,r[1]); break; case PLUS: DebugAssert(false, ""); return true; break; default: // leaf return (r < l); break; } break; } } /*! IS_INTEGER(x) |= EXISTS (y : INT) y = x * where x is not already known to be an integer. */ Theorem ArithTheoremProducerOld::IsIntegerElim(const Theorem& isIntx) { Expr expr = isIntx.getExpr(); if (CHECK_PROOFS) { CHECK_SOUND(expr.getKind() == IS_INTEGER, "Expected IS_INTEGER predicate"); } expr = expr[0]; DebugAssert(!d_theoryArith->isInteger(expr), "Expected non-integer"); Assumptions a(isIntx); Proof pf; if (withProof()) { pf = newPf("isIntElim", isIntx.getProof()); } Expr newVar = d_em->newBoundVarExpr(d_theoryArith->intType()); Expr res = d_em->newClosureExpr(EXISTS, newVar, newVar.eqExpr(expr)); return newTheorem(res, a, pf); } Theorem ArithTheoremProducerOld::eqElimIntRule(const Theorem& eqn, const Theorem& isIntx, const vector& isIntVars) { TRACE("arith eq", "eqElimIntRule(", eqn.getExpr(), ") {"); Proof pf; if(CHECK_PROOFS) CHECK_SOUND(eqn.isRewrite(), "ArithTheoremProducerOld::eqElimInt: input must be an equation" + eqn.toString()); const Expr& lhs = eqn.getLHS(); const Expr& rhs = eqn.getRHS(); Expr a, x; d_theoryArith->separateMonomial(lhs, a, x); if(CHECK_PROOFS) { // Checking LHS const Expr& isIntxe = isIntx.getExpr(); CHECK_SOUND(isIntPred(isIntxe) && isIntxe[0] == x, "ArithTheoremProducerOld::eqElimInt\n eqn = " +eqn.getExpr().toString() +"\n isIntx = "+isIntxe.toString()); CHECK_SOUND(isRational(a) && a.getRational().isInteger() && a.getRational() >= 2, "ArithTheoremProducerOld::eqElimInt:\n lhs = "+lhs.toString()); // Checking RHS // It cannot be a division (we don't handle it) CHECK_SOUND(!isDivide(rhs), "ArithTheoremProducerOld::eqElimInt:\n rhs = "+rhs.toString()); // If it's a single monomial, then it's the only "variable" if(!isPlus(rhs)) { Expr c, v; d_theoryArith->separateMonomial(rhs, c, v); CHECK_SOUND(isIntVars.size() == 1 && isIntPred(isIntVars[0].getExpr()) && isIntVars[0].getExpr()[0] == v && isRational(c) && c.getRational().isInteger(), "ArithTheoremProducerOld::eqElimInt:\n rhs = "+rhs.toString() +"isIntVars.size = "+int2string(isIntVars.size())); } else { // RHS is a plus CHECK_SOUND(isIntVars.size() + 1 == (size_t)rhs.arity(), "ArithTheoremProducerOld::eqElimInt: rhs = "+rhs.toString()); // Check the free constant CHECK_SOUND(isRational(rhs[0]) && rhs[0].getRational().isInteger(), "ArithTheoremProducerOld::eqElimInt: rhs = "+rhs.toString()); // Check the vars for(size_t i=0, iend=isIntVars.size(); iseparateMonomial(rhs[i+1], c, v); const Expr& isInt(isIntVars[i].getExpr()); CHECK_SOUND(isIntPred(isInt) && isInt[0] == v && isRational(c) && c.getRational().isInteger(), "ArithTheoremProducerOld::eqElimInt:\n rhs["+int2string(i+1) +"] = "+rhs[i+1].toString() +"\n isInt = "+isInt.toString()); } } } // Creating a fresh bound variable static int varCount(0); Expr newVar = d_em->newBoundVarExpr("_int_var", int2string(varCount++)); newVar.setType(intType()); Expr t2 = create_t2(lhs, rhs, newVar); Expr t3 = create_t3(lhs, rhs, newVar); vector vars; vars.push_back(newVar); Expr res = d_em->newClosureExpr(EXISTS, vars, x.eqExpr(t2) && rat(0).eqExpr(t3)); vector thms(isIntVars); thms.push_back(isIntx); thms.push_back(eqn); Assumptions assump(thms); if(withProof()) { vector pfs; pfs.push_back(eqn.getProof()); pfs.push_back(isIntx.getProof()); vector::const_iterator i=isIntVars.begin(), iend=isIntVars.end(); for(; i!=iend; ++i) pfs.push_back(i->getProof()); pf = newPf("eq_elim_int", eqn.getExpr(), res, pfs); } Theorem thm(newTheorem(res, assump, pf)); TRACE("arith eq", "eqElimIntRule => ", thm.getExpr(), " }"); return thm; } Theorem ArithTheoremProducerOld::isIntConst(const Expr& e) { Proof pf; if(CHECK_PROOFS) { CHECK_SOUND(isIntPred(e) && e[0].isRational(), "ArithTheoremProducerOld::isIntConst(e = " +e.toString()+")"); } if(withProof()) pf = newPf("is_int_const", e); bool isInt = e[0].getRational().isInteger(); return newRWTheorem(e, isInt? d_em->trueExpr() : d_em->falseExpr(), Assumptions::emptyAssump(), pf); } Theorem ArithTheoremProducerOld::equalLeaves1(const Theorem& thm) { Proof pf; const Expr& e = thm.getRHS(); if (CHECK_PROOFS) { CHECK_SOUND(e[1].getKind() == RATIONAL_EXPR && e[1].getRational() == Rational(0) && e[0].getKind() == PLUS && e[0].arity() == 3 && e[0][0].getKind() == RATIONAL_EXPR && e[0][0].getRational() == Rational(0) && e[0][1].getKind() == MULT && e[0][1].arity() == 2 && e[0][1][0].getKind() == RATIONAL_EXPR && e[0][1][0].getRational() == Rational(-1), "equalLeaves1"); } if (withProof()) { vector pfs; pfs.push_back(thm.getProof()); pf = newPf("equalLeaves1", e, pfs); } return newRWTheorem(e, e[0][1][1].eqExpr(e[0][2]), thm.getAssumptionsRef(), pf); } Theorem ArithTheoremProducerOld::equalLeaves2(const Theorem& thm) { Proof pf; const Expr& e = thm.getRHS(); if (CHECK_PROOFS) { CHECK_SOUND(e[0].getKind() == RATIONAL_EXPR && e[0].getRational() == Rational(0) && e[1].getKind() == PLUS && e[1].arity() == 3 && e[1][0].getKind() == RATIONAL_EXPR && e[1][0].getRational() == Rational(0) && e[1][1].getKind() == MULT && e[1][1].arity() == 2 && e[1][1][0].getKind() == RATIONAL_EXPR && e[1][1][0].getRational() == Rational(-1), "equalLeaves2"); } if (withProof()) { vector pfs; pfs.push_back(thm.getProof()); pf = newPf("equalLeaves2", e, pfs); } return newRWTheorem(e, e[1][1][1].eqExpr(e[1][2]), thm.getAssumptionsRef(), pf); } Theorem ArithTheoremProducerOld::equalLeaves3(const Theorem& thm) { Proof pf; const Expr& e = thm.getRHS(); if (CHECK_PROOFS) { CHECK_SOUND(e[1].getKind() == RATIONAL_EXPR && e[1].getRational() == Rational(0) && e[0].getKind() == PLUS && e[0].arity() == 3 && e[0][0].getKind() == RATIONAL_EXPR && e[0][0].getRational() == Rational(0) && e[0][2].getKind() == MULT && e[0][2].arity() == 2 && e[0][2][0].getKind() == RATIONAL_EXPR && e[0][2][0].getRational() == Rational(-1), "equalLeaves3"); } if (withProof()) { vector pfs; pfs.push_back(thm.getProof()); pf = newPf("equalLeaves3", e, pfs); } return newRWTheorem(e, e[0][2][1].eqExpr(e[0][1]), thm.getAssumptionsRef(), pf); } Theorem ArithTheoremProducerOld::equalLeaves4(const Theorem& thm) { Proof pf; const Expr& e = thm.getRHS(); if (CHECK_PROOFS) { CHECK_SOUND(e[0].getKind() == RATIONAL_EXPR && e[0].getRational() == Rational(0) && e[1].getKind() == PLUS && e[1].arity() == 3 && e[1][0].getKind() == RATIONAL_EXPR && e[1][0].getRational() == Rational(0) && e[1][2].getKind() == MULT && e[1][2].arity() == 2 && e[1][2][0].getKind() == RATIONAL_EXPR && e[1][2][0].getRational() == Rational(-1), "equalLeaves4"); } if (withProof()) { vector pfs; pfs.push_back(thm.getProof()); pf = newPf("equalLeaves4", e, pfs); } return newRWTheorem(e, e[1][2][1].eqExpr(e[1][1]), thm.getAssumptionsRef(), pf); } Theorem ArithTheoremProducerOld::diseqToIneq(const Theorem& diseq) { Proof pf; const Expr& e = diseq.getExpr(); if(CHECK_PROOFS) { CHECK_SOUND(e.isNot() && e[0].isEq(), "ArithTheoremProducerOld::diseqToIneq: expected disequality:\n" " e = "+e.toString()); } const Expr& x = e[0][0]; const Expr& y = e[0][1]; if(withProof()) pf = newPf(e, diseq.getProof()); return newTheorem(ltExpr(x,y).orExpr(gtExpr(x,y)), diseq.getAssumptionsRef(), pf); } Theorem ArithTheoremProducerOld::dummyTheorem(const Expr& e) { Proof pf; return newRWTheorem(e, d_em->trueExpr(), Assumptions::emptyAssump(), pf); } Theorem ArithTheoremProducerOld::oneElimination(const Expr& e) { // Check soundness if (CHECK_PROOFS) CHECK_SOUND(isMult(e) && e.arity() == 2 && e[0].isRational() && e[0].getRational() == 1, "oneElimination: input must be a multiplication by one" + e.toString()); // The proof object that we will us Proof pf; // Setup the proof if needed if (withProof()) pf = newPf("oneElimination", e); // Return the rewrite theorem that explains the phenomenon return newRWTheorem(e, e[1], Assumptions::emptyAssump(), pf); } Theorem ArithTheoremProducerOld::clashingBounds(const Theorem& lowerBound, const Theorem& upperBound) { // Get the expressions const Expr& lowerBoundExpr = lowerBound.getExpr(); const Expr& upperBoundExpr = upperBound.getExpr(); // Check soundness if (CHECK_PROOFS) { CHECK_SOUND(isLE(lowerBoundExpr) || isLT(lowerBoundExpr), "clashingBounds: lowerBound should be >= or > " + lowerBoundExpr.toString()); CHECK_SOUND(isGE(upperBoundExpr) || isGT(upperBoundExpr), "clashingBounds: upperBound should be <= or < " + upperBoundExpr.toString()); CHECK_SOUND(lowerBoundExpr[0].isRational(), "clashingBounds: lowerBound left side should be a rational " + lowerBoundExpr.toString()); CHECK_SOUND(upperBoundExpr[0].isRational(), "clashingBounds: upperBound left side should be a rational " + upperBoundExpr.toString()); CHECK_SOUND(lowerBoundExpr[1] == upperBoundExpr[1], "clashingBounds: bounds not on the same term " + lowerBoundExpr.toString() + ", " + upperBoundExpr.toString()); // Get the bounds Rational lowerBoundR = lowerBoundExpr[0].getRational(); Rational upperBoundR = upperBoundExpr[0].getRational(); if (isLE(lowerBoundExpr) && isGE(upperBoundExpr)) { CHECK_SOUND(upperBoundR < lowerBoundR, "clashingBounds: bounds are satisfiable"); } else { CHECK_SOUND(upperBoundR <= lowerBoundR, "clashingBounds: bounds are satisfiable"); } } // The proof object that we will use Proof pf; // Setup the proof if needed if (withProof()) pf = newPf("clashingBounds", lowerBoundExpr, upperBoundExpr); // Put the bounds expressions in the assumptions Assumptions assumptions; assumptions.add(lowerBound); assumptions.add(upperBound); // Return the theorem return newTheorem(d_em->falseExpr(), assumptions, pf); } Theorem ArithTheoremProducerOld::addInequalities(const Theorem& thm1, const Theorem& thm2) { // Get the expressions of the theorem const Expr& expr1 = thm1.getExpr(); const Expr& expr2 = thm2.getExpr(); // Check soundness if (CHECK_PROOFS) { CHECK_SOUND(isIneq(expr1), "addInequalities: expecting an inequality for thm1, got " + expr1.toString()); CHECK_SOUND(isIneq(expr2), "addInequalities: expecting an inequality for thm2, got " + expr2.toString()); if (isLE(expr1) || isLT(expr1)) CHECK_SOUND(isLE(expr2) || isLT(expr2), "addInequalities: expr2 should be <(=) also " + expr2.toString()); if (isGE(expr1) || isGT(expr1)) CHECK_SOUND(isGE(expr2) || isGT(expr2), "addInequalities: expr2 should be >(=) also" + expr2.toString()); } // Create the assumptions Assumptions a(thm1, thm2); // Get the kinds of the inequalitites int kind1 = expr1.getKind(); int kind2 = expr2.getKind(); // Set-up the resulting inequality int kind = (kind1 == kind2) ? kind1 : ((kind1 == LT) || (kind2 == LT))? LT : GT; // Create the proof object Proof pf; if(withProof()) { vector pfs; pfs.push_back(thm1.getProof()); pfs.push_back(thm2.getProof()); pf = newPf("addInequalities", expr1, expr2, pfs); } // Create the new expressions Expr leftSide = plusExpr(expr1[0], expr2[0]); Expr rightSide = plusExpr(expr1[1], expr2[1]); // Return the theorem return newTheorem(Expr(kind, leftSide, rightSide), a, pf); } // // 0 <= c1 + t // ==> 0 <= c2 + t // if c2 > c1 Theorem ArithTheoremProducerOld::implyWeakerInequality(const Expr& expr1, const Expr& expr2) { // Check soundness if (CHECK_PROOFS) { // Both must be inequalitites CHECK_SOUND(isIneq(expr1), "implyWeakerInequality: expr1 should be an inequality" + expr1.toString()); CHECK_SOUND(isIneq(expr2), "implyWeakerInequality: expr1 should be an inequality" + expr2.toString()); // Left sides must be zero CHECK_SOUND(expr1[0].isRational() && expr1[0].getRational() == 0, "implyWeakerInequality: expr1 should have a rational on the left side" + expr1.toString()); CHECK_SOUND(expr2[0].isRational() && expr2[0].getRational() == 0, "implyWeakerInequality: expr2 should have a rational on the left side" + expr2.toString()); // Get the expr1 monomials and constant 0 <= c1 + t1 Rational c1 = 0; vector t1_children; if (isPlus(expr1[1])) { int start_i = 0; if (expr1[1][0].isRational()) { start_i = 1; c1 = expr1[1][0].getRational(); } int end_i = expr1[1].arity(); for(int i = start_i; i < end_i; i ++) { const Expr& term = expr1[1][i]; t1_children.push_back(term); } } else t1_children.push_back(expr1[1]); Expr t1 = (t1_children.size() > 1 ? plusExpr(t1_children) : t1_children[0]); // Get the expr1 monomials and constant 0 <= c1 + t1 Rational c2 = 0; vector t2_children; if (isPlus(expr2[1])) { int start_i = 0; if (expr2[1][0].isRational()) { start_i = 1; c2 = expr2[1][0].getRational(); } int end_i = expr2[1].arity(); for(int i = start_i; i < end_i; i ++) { const Expr& term = expr2[1][i]; t2_children.push_back(term); } } else t2_children.push_back(expr2[1]); Expr t2 = (t2_children.size() > 1 ? plusExpr(t2_children) : t2_children[0]); CHECK_SOUND(t2 == t1, "implyWeakerInequality: terms different " + t1.toString() + " vs " + t2.toString()); CHECK_SOUND(c2 > c1 || (c2 == c1 && !(expr1.getKind() == LE && expr2.getKind() == LT)), "implyWeakerInequality: c2 is not bigger than c1" + expr1.toString() + " --> " + expr2.toString()); } // Create the proof object Proof pf; if(withProof()) pf = newPf("implyWeakerInequality", expr1, expr2); // Return the theorem return newTheorem(expr1.impExpr(expr2), Assumptions::emptyAssump(), pf); } // Takes // Expr1: 0 <= c1 + t1 // Expr2: 0 <= c2 + t2 (t2 is -t1) // if c1 + c2 < 0 then Expr1 => !Expr2 // Theorem ArithTheoremProducerOld::implyNegatedInequality(const Expr& expr1, const Expr& expr2) { // Check soundness // Check soundness if (CHECK_PROOFS) { // Both must be inequalitites CHECK_SOUND(isIneq(expr1), "implyNegatedInequality: expr1 should be an inequality" + expr1.toString()); CHECK_SOUND(isIneq(expr2), "implyNegatedInequality: expr1 should be an inequality" + expr2.toString()); // Left sides must be zero CHECK_SOUND(expr1[0].isRational() && expr1[0].getRational() == 0, "implyNegatedInequality: expr1 should have a rational on the left side" + expr1.toString()); CHECK_SOUND(expr2[0].isRational() && expr2[0].getRational() == 0, "implyNegatedInequality: expr2 should have a rational on the left side" + expr2.toString()); // Get the expr1 monomials and constant 0 <= c1 + t1 Rational c1 = 0; vector t1_children; if (isPlus(expr1[1])) { int start_i = 0; if (expr1[1][0].isRational()) { start_i = 1; c1 = expr1[1][0].getRational(); } int end_i = expr1[1].arity(); for(int i = start_i; i < end_i; i ++) { const Expr& term = expr1[1][i]; t1_children.push_back(term); } } else t1_children.push_back(expr1[1]); Expr t1 = (t1_children.size() > 1 ? plusExpr(t1_children) : t1_children[0]); // Get the expr1 monomials and constant 0 <= c1 + t1 Rational c2 = 0; vector t2_children; if (isPlus(expr2[1])) { int start_i = 0; if (expr2[1][0].isRational()) { start_i = 1; c2 = expr2[1][0].getRational(); } int end_i = expr2[1].arity(); for(int i = start_i; i < end_i; i ++) { const Expr& term = expr2[1][i]; t2_children.push_back(term); } } else t2_children.push_back(expr2[1]); Expr t2 = (t2_children.size() > 1 ? plusExpr(t2_children) : t2_children[0]); // t1 shoud be -t2 if (isPlus(t1) && isPlus(t2)) { CHECK_SOUND(t1.arity() == t2.arity(), "implyNegatedInequality: t1 should be -t2 : " + t1.toString() + " vs " + t2.toString()); for (int i = 0; i < t1.arity(); i++) { Expr term_t1 = t1[i]; Expr term_t2 = t2[i]; Rational t1_c = (isMult(term_t1) ? term_t1[0].getRational() : 1); term_t1 = (isMult(term_t1) ? term_t1[1] : term_t1); Rational t2_c = (isMult(term_t2) ? term_t2[0].getRational() : 1); term_t2 = (isMult(term_t2) ? term_t2[1] : term_t2); CHECK_SOUND(t1_c == - t2_c, "implyNegatedInequality: t1 should be -t2 : " + t1.toString() + " vs " + t2.toString()); CHECK_SOUND(term_t1 == term_t2, "implyNegatedInequality: t1 should be -t2 : " + t1.toString() + " vs " + t2.toString()); } } else { Rational t1_c = (isMult(t1) ? t1[0].getRational() : 1); Expr term_t1 = (isMult(t1) ? t1[1] : t1); Rational t2_c = (isMult(t2) ? t2[0].getRational() : 1); Expr term_t2 = (isMult(t2) ? t2[1] : t2); CHECK_SOUND(t1_c == - t2_c, "implyNegatedInequality: t1 should be -t2 : " + t1.toString() + " vs " + t2.toString()); CHECK_SOUND(term_t1 == term_t2, "implyNegatedInequality: t1 should be -t2 : " + t1.toString() + " vs " + t2.toString()); } int kind1 = expr1.getKind(); int kind2 = expr2.getKind(); bool bothStrict = kind1 == LT && kind2 == LT; CHECK_SOUND(c1 + c2 < 0 || (c1 + c2 == 0 && bothStrict), "implyNegatedInequality: sum of constants not negative!"); } // The proof object that we will use Proof pf; if (withProof()) pf = newPf("implyNegatedInequality", expr1, expr2, expr2.negate()); // Return the theorem return newTheorem(expr1.impExpr(expr2.negate()), Assumptions::emptyAssump(), pf); } Theorem ArithTheoremProducerOld::trustedRewrite(const Expr& expr1, const Expr& expr2) { // The proof object that we will us Proof pf; // Setup the proof if needed if (withProof()) pf = newPf("trustedRewrite", expr1, expr2); // Return the rewrite theorem that explains the phenomenon return newRWTheorem(expr1, expr2, Assumptions::emptyAssump(), pf); } Theorem ArithTheoremProducerOld::integerSplit(const Expr& intVar, const Rational& intPoint) { // Check soundness if (CHECK_PROOFS) { CHECK_SOUND(intPoint.isInteger(), "integerSplit: we can only split on integer points, given" + intPoint.toString()); } // Create the expression const Expr& split = Expr(IS_INTEGER, intVar).impExpr(leExpr(intVar, rat(intPoint)).orExpr(geExpr(intVar, rat(intPoint + 1)))); // The proof object that we will use Proof pf; if (withProof()) pf = newPf("integerSplit", intVar, rat(intPoint)); // Return the theorem return newTheorem(split, Assumptions::emptyAssump(), pf); } // // Changed from the new arithmetic, takes // 0 op c + t, where t is an integer expression but c is a rational // or 0 op x, where x is a leaf // Theorem ArithTheoremProducerOld::rafineStrictInteger(const Theorem& isIntConstrThm, const Expr& constr) { // Check soundness if (CHECK_PROOFS) { // Right side of the constraint should correspond to the proved integer expression CHECK_SOUND(isIneq(constr), "rafineStrictInteger: expected a constraint got : " + constr.toString()); CHECK_SOUND(constr[0].isRational() && constr[0].getRational() == 0, "rafineStrictInteger: left hand side must be 0"); CHECK_SOUND(d_theoryArith->isLeaf(constr[1]) || constr[1][0].isRational(), "rafineStrictInteger: right side of the constraint must be a leaf or a sum, with the first one a rational"); // We have to check that the non-constant children of inequality correspond to the integrality theorem's children Expr intSum = isIntConstrThm.getExpr()[0]; Expr ineqSum = constr[1]; if (isPlus(intSum)) { int i, j; for (i = 0, j = 1; i < intSum.arity() && j < ineqSum.arity(); i ++, j ++) if (!(intSum[i] == ineqSum[j])) break; CHECK_SOUND(i == intSum.arity() && j == ineqSum.arity(), "rafineStrictInteger: proof of intger doesn't correspond to the constarint right side"); } else CHECK_SOUND(intSum == ineqSum || intSum == ineqSum[1], "rafineStrictInteger: proof of intger doesn't correspond to the constarint right side:" + intSum.getString() + " vs " + ineqSum[1].getString()); } // Get the contraint bound Rational c = (isPlus(constr[1]) ? constr[1][0].getRational() : 0); // Get the kind of the constraint int kind = constr.getKind(); // If the bound is strict, make it non-strict switch (kind) { case LT: kind = LE; if (c.isInteger()) c --; // 0 < 3 + x --> 0 <= 2 + x else c = floor(c); // 0 < 3.4 + x --> 0 <= 3 + x break; case LE: kind = LE; if (!c.isInteger()) c = floor(c); // 0 <= 3.5 + x --> 0 <= 3 + x break; case GT: kind = GE; if (c.isInteger()) c ++; // 0 > 3 + x --> 0 >= 4 + x else c = ceil(c); // 0 > 3.4 + x --> 0 >= 4 + x break; case GE: kind = GE; if (!c.isInteger()) c = ceil(c); // 0 >= 3.4 + x --> 4 >= x break; } // The new constraint vector newChildren; if (isPlus(constr[1])) { for (int i = 0; i < constr[1].arity(); i ++) if (constr[1][i].isRational()) newChildren.push_back(rat(c)); else newChildren.push_back(constr[1][i]); } else { if (c != 0) newChildren.push_back(rat(c)); newChildren.push_back(constr[1]); } Expr newSum = newChildren.size() > 1 ? plusExpr(newChildren) : newChildren[0]; Expr newConstr(kind, rat(0), newSum); // Pick up the assumptions from the integer proof const Assumptions& assump(isIntConstrThm.getAssumptionsRef()); // Construct the proof object if necessary Proof pf; if (withProof()) pf = newPf("rafineStrictInteger", constr,newConstr, isIntConstrThm.getProof()); // Return the rewrite theorem that explains the phenomenon return newRWTheorem(constr, newConstr, assump, pf); } // Given: // 0 = c + t // where t is integer and c is not // deduce bot Theorem ArithTheoremProducerOld::intEqualityRationalConstant(const Theorem& isIntConstrThm, const Expr& constr) { // Check soundness if (CHECK_PROOFS) { // Right side of the constraint should correspond to the proved integer expression CHECK_SOUND(constr.getKind() == EQ, "intEqualityRationalConstant: expected a constraint got : " + constr.toString()); bool sum_on_rhs = (constr[0].isRational() && constr[0].getRational() == 0); bool sum_on_lhs = (constr[1].isRational() && constr[1].getRational() == 0); CHECK_SOUND((sum_on_rhs && !sum_on_lhs) ||(!sum_on_rhs && sum_on_lhs), "intEqualityRationalConstant: left or right hand side must be 0"); CHECK_SOUND((sum_on_rhs && constr[1][0].isRational() && !constr[1][0].getRational().isInteger()) || (sum_on_lhs && constr[0][0].isRational() && !constr[0][0].getRational().isInteger()), "intEqualityRationalConstant: left or right side of the constraint must be a sum, with the first one a rational (non integer)"); // We have to check that the non-constant children of inequality correspond to the integrality theorem's children Expr intSum = isIntConstrThm.getExpr()[0]; Expr eqSum = (sum_on_lhs ? constr[0] : constr[1]); if (isPlus(intSum)) { int i, j; for (i = 0, j = 1; i < intSum.arity() && j < eqSum.arity(); i ++, j ++) if (!(intSum[i] == eqSum[j])) break; CHECK_SOUND(i == intSum.arity() && j == eqSum.arity(), "intEqualityRationalConstant: proof of intger doesn't correspond to the constarint right side"); } else CHECK_SOUND(intSum == eqSum[1], "intEqualityRationalConstant: proof of intger doesn't correspond to the constarint right side:" + intSum.getString() + " vs " + eqSum[1].getString()); } const Assumptions& assump(isIntConstrThm.getAssumptionsRef()); // Construct the proof object if necessary Proof pf; if (withProof()) pf = newPf("intEqualityRationalConstant", constr, isIntConstrThm.getProof()); // Return the rewrite theorem that explains the phenomenon return newRWTheorem(constr, d_em->falseExpr(), assump, pf); } Theorem ArithTheoremProducerOld::cycleConflict(const vector& inequalitites) { Proof pf; if(withProof()) { vector es; vector pfs; for(unsigned i = 0; i < inequalitites.size(); i++) { es.push_back(inequalitites[i].getExpr()); pfs.push_back(inequalitites[i].getProof()); } pf = newPf("cycleConflict", es, pfs); } Assumptions a; for(unsigned i = 0; i < inequalitites.size(); i ++) a.add(inequalitites[i]); return newTheorem(d_em->falseExpr(), a, pf); } Theorem ArithTheoremProducerOld::implyEqualities(const std::vector& inequalities) { Assumptions a; vector conjuncts; for(unsigned i = 0; i < inequalities.size(); i ++) { a.add(inequalities[i]); Expr inequality = inequalities[i].getExpr(); Expr equality = inequality[0].eqExpr(inequality[1]); conjuncts.push_back(equality); } Proof pf; if(withProof()) { vector es; vector pfs; for(unsigned i = 0; i < inequalities.size(); i++) { es.push_back(inequalities[i].getExpr()); pfs.push_back(inequalities[i].getProof()); } pf = newPf("implyEqualities", Expr(RAW_LIST,conjuncts),Expr(RAW_LIST,es), pfs); } return newTheorem(andExpr(conjuncts), a, pf); } /*! Takes a Theorem(\\alpha < \\beta) and returns * Theorem(\\alpha < \\beta <==> \\alpha <= \\beta -1) * where \\alpha and \\beta are integer expressions */ Theorem ArithTheoremProducerOld::lessThanToLERewrite(const Expr& ineq, const Theorem& isIntLHS, const Theorem& isIntRHS, bool changeRight) { const Expr& isIntLHSexpr = isIntLHS.getExpr(); const Expr& isIntRHSexpr = isIntRHS.getExpr(); if(CHECK_PROOFS) { CHECK_SOUND(isLT(ineq), "ArithTheoremProducerOld::LTtoLE: ineq must be <"); // Integrality check CHECK_SOUND(isIntPred(isIntLHSexpr) && isIntLHSexpr[0] == ineq[0], "ArithTheoremProducerOld::lessThanToLE: bad integrality check:\n" " ineq = "+ineq.toString()+"\n isIntLHS = " +isIntLHSexpr.toString()); CHECK_SOUND(isIntPred(isIntRHSexpr) && isIntRHSexpr[0] == ineq[1], "ArithTheoremProducerOld::lessThanToLE: bad integrality check:\n" " ineq = "+ineq.toString()+"\n isIntRHS = " +isIntRHSexpr.toString()); } vector thms; thms.push_back(isIntLHS); thms.push_back(isIntRHS); Assumptions a(thms); Proof pf; Expr le = changeRight? leExpr(ineq[0], ineq[1] + rat(-1)) : leExpr(ineq[0] + rat(1), ineq[1]); if(withProof()) { vector pfs; pfs.push_back(isIntLHS.getProof()); pfs.push_back(isIntRHS.getProof()); pf = newPf(changeRight? "lessThan_To_LE_rhs_rwr" : "lessThan_To_LE_lhs_rwr", ineq, le, pfs); } return newRWTheorem(ineq, le, a, pf); } // G ==> (G1 or G2) and (!G1 or !G2), // where G = G(x, e, c1, c2), // V x = e + i, for i in c1 .. c2 Theorem ArithTheoremProducerOld::splitGrayShadowSmall(const Theorem& gThm) { const Expr& theShadow = gThm.getExpr(); if(CHECK_PROOFS) { CHECK_SOUND(isGrayShadow(theShadow), "ArithTheoremProducerOld::expandGrayShadowConst: not a shadow" + theShadow.toString()); } const Rational& c1 = theShadow[2].getRational(); const Rational& c2 = theShadow[3].getRational(); if(CHECK_PROOFS) { CHECK_SOUND(c1.isInteger() && c2.isInteger() && c1 < c2, "ArithTheoremProducerOld::expandGrayShadow: " + theShadow.toString()); } const Expr& v = theShadow[0]; const Expr& e = theShadow[1]; vector disjuncts; for (int i = c1.getInt(); i <= c2.getInt(); i ++) { Expr disjunct = v.eqExpr(e + rat(i)); disjuncts.push_back(disjunct); } Expr bigOr = orExpr(disjuncts); Proof pf; if(withProof()){ vector exprs; exprs.push_back(theShadow); exprs.push_back(bigOr); pf = newPf("split_gray_shadow", exprs, gThm.getProof()); } return newTheorem(bigOr, gThm.getAssumptionsRef(), pf); } Theorem ArithTheoremProducerOld::implyWeakerInequalityDiffLogic(const std::vector& antecedentThms, const Expr& implied) { Proof pf; if(withProof()) { vector es; vector pfs; for(unsigned i = 0; i < antecedentThms.size(); i++) { es.push_back(antecedentThms[i].getExpr()); pfs.push_back(antecedentThms[i].getProof()); } pf = newPf("implyWeakerInequalityDiffLogic", implied, Expr(RAW_LIST,es), pfs); } Assumptions a; for(unsigned i = 0; i < antecedentThms.size(); i ++) { a.add(antecedentThms[i]); } return newTheorem(implied, a, pf); } Theorem ArithTheoremProducerOld::implyNegatedInequalityDiffLogic(const std::vector& antecedentThms, const Expr& implied) { Proof pf; if(withProof()) { vector es; vector pfs; for(unsigned i = 0; i < antecedentThms.size(); i++) { es.push_back(antecedentThms[i].getExpr()); pfs.push_back(antecedentThms[i].getProof()); } pf = newPf("implyNegatedInequalityDiffLogic",implied.notExpr(), Expr(RAW_LIST, es), pfs); } Assumptions a; for(unsigned i = 0; i < antecedentThms.size(); i ++) { a.add(antecedentThms[i]); } return newTheorem(implied.notExpr(), a, pf); } Theorem ArithTheoremProducerOld::expandGrayShadowRewrite(const Expr& theShadow) { if(CHECK_PROOFS) { CHECK_SOUND(isGrayShadow(theShadow), "ArithTheoremProducerOld::expandGrayShadowConst: not a shadow" + theShadow.toString()); } const Rational& c1 = theShadow[2].getRational(); const Rational& c2 = theShadow[3].getRational(); if(CHECK_PROOFS) { CHECK_SOUND(c1.isInteger() && c2.isInteger() && c1 < c2, "ArithTheoremProducerOld::expandGrayShadow: " + theShadow.toString()); } const Expr& v = theShadow[0]; const Expr& e = theShadow[1]; Proof pf; if(withProof()) pf = newPf("expand_gray_shadow", theShadow); Expr ineq1(leExpr(e+rat(c1), v)); Expr ineq2(leExpr(v, e+rat(c2))); return newRWTheorem(theShadow, ineq1 && ineq2, Assumptions::emptyAssump(), pf); } Theorem ArithTheoremProducerOld::compactNonLinearTerm(const Expr& nonLinear) { // The set of common leaves multiset commonLeaves; bool first = true; // Go through the terms and intersect the leaf sets for (int i = 0; i < nonLinear.arity(); i ++) { if (!nonLinear[i].isRational()) { // Get the current monomial Expr monomial = nonLinear[i]; // A set to keep the variables multiset currentLeaves; // Get the set of leaves in this term if (isMult(monomial)) { for (int j = 0; j < monomial.arity(); j ++) if (!monomial[j].isRational()) { if (isPow(monomial[j])) { for (int p = 0; p < monomial[j][0].getRational().getInt(); p ++) currentLeaves.insert(monomial[j][1]); } else currentLeaves.insert(monomial[j]); } } else if (isPow(monomial)) { for (int p = 0; p < monomial[0].getRational().getInt(); p ++) currentLeaves.insert(monomial[1]); } else currentLeaves.insert(monomial); // And intersect them if (first) { commonLeaves.swap(currentLeaves); first = false; } else { multiset intersectLeaves; set_intersection(currentLeaves.begin(), currentLeaves.end(), commonLeaves.begin(), commonLeaves.end(), insert_iterator< multiset > (intersectLeaves, intersectLeaves.begin())); intersectLeaves.swap(commonLeaves); } } } Expr result; if (commonLeaves.size() > 0) { // The constant to add in the beginnings Expr constant = rat(0); // The sum of of the rest when we pullout the common factors vector sumChildren; // Go through them again and construct the sum of the rest for (int i = 0; i < nonLinear.arity(); i ++) { if (!nonLinear[i].isRational()) { // Get the current monomial Expr monomial = nonLinear[i]; // A set to keep the variables multiset currentChildren; // Get the set of childrent of this multiplication if (isMult(monomial)) { for (int j = 0; j < monomial.arity(); j ++) if (isPow(monomial[j])) { for (int p = 0; p < monomial[j][0].getRational().getInt(); p ++) currentChildren.insert(monomial[j][1]); } else currentChildren.insert(monomial[j]); } else if (isPow(monomial)) { for (int p = 0; p < monomial[0].getRational().getInt(); p ++) currentChildren.insert(monomial[1]); } else currentChildren.insert(monomial); // Take the difference and construct a multiplication multiset diffChildren; set_difference(currentChildren.begin(), currentChildren.end(), commonLeaves.begin(), commonLeaves.end(), insert_iterator< multiset > (diffChildren, diffChildren.begin())); // Go create another sumChildren element if (diffChildren.size() == 1) { sumChildren.push_back(*diffChildren.begin()); } else if (diffChildren.size() == 0) { sumChildren.push_back(rat(1)); } else { multiset::iterator it = diffChildren.begin(); multiset::iterator it_end = diffChildren.end(); vector multChildren; while (it != it_end) { multChildren.push_back(*it); it ++; } sumChildren.push_back(multExpr(multChildren)); } } else constant = nonLinear[i]; } // The children of the final multiplication vector multChildren; multChildren.push_back(plusExpr(sumChildren)); multiset::iterator it = commonLeaves.begin(); multiset::iterator it_end = commonLeaves.end(); for (; it != it_end; it ++) multChildren.push_back(*it); result = plusExpr(constant, multExpr(multChildren)); } else { // We have no common leaves to take out result = nonLinear; } Proof pf; if(withProof()) pf = newPf("compactNonlinear", nonLinear, result); return newRWTheorem(nonLinear, result, Assumptions::emptyAssump(), pf); } // // -c <= x1*x2*...*xn // if c = 0 then "only even number of x_i's can be negative" or one of them is zero // x1 = 0 or x2 = 0 or ... or xn = 0 // or (x1 // else "only only even number of x_i's can be negative" and none of them is zero" Theorem ArithTheoremProducerOld::nonLinearIneqSignSplit(const Theorem& ineqThm) { // Get the inequality Expr ineq = ineqThm.getExpr(); Expr rhs = ineq[1]; // Get the constant Rational c = (isMult(rhs) ? 0 : rhs[0].getRational()); if(CHECK_PROOFS) { CHECK_SOUND(c <= 0, "ArithTheoremProducerOld::nonLinearIneqSignSplit: " + ineq.toString()); CHECK_SOUND(isMult(rhs) || (isPlus(rhs) && rhs.arity() == 2), "ArithTheoremProducerOld::nonLinearIneqSignSplit: " + ineq.toString()); } Expr signXor = d_em->trueExpr(); Expr mult = (isMult(rhs) ? rhs : rhs[1]); for (int i = 0; i < mult.arity(); i ++) { Expr term = mult[i]; if (isPow(term) && term[0].getRational() < 0) term = Expr(POW, -term[0], term[1]); signXor = Expr(XOR, signXor, ltExpr(term, rat(0))); } if (c == 0 && ineq.getKind() == LE) { Expr zeroOr = d_em->falseExpr(); for (int i = 0; i < mult.arity(); i ++) { Expr term = mult[i]; zeroOr = zeroOr.orExpr(term.eqExpr(rat(0))); } signXor = zeroOr.orExpr(signXor); } Proof pf; if(withProof()) { vector exprs; exprs.push_back(ineq); exprs.push_back(signXor); pf = newPf("nonLinearIneqSignSplit", exprs, ineqThm.getProof()); } Assumptions assumptions; assumptions.add(ineqThm); return newTheorem(signXor, assumptions, pf); } Theorem ArithTheoremProducerOld::implyDiffLogicBothBounds(const Expr& x, std::vector& c1_le_x, Rational c1, std::vector& x_le_c2, Rational c2) { Proof pf; if(withProof()) { vector es; vector pfs; for(unsigned i = 0; i < c1_le_x.size(); i++) { es.push_back(c1_le_x[i].getExpr()); pfs.push_back(c1_le_x[i].getProof()); } for(unsigned i = 0; i < x_le_c2.size(); i++) { es.push_back(x_le_c2[i].getExpr()); pfs.push_back(x_le_c2[i].getProof()); } pf = newPf("implyDiffLogicBothBounds", es, pfs); } Assumptions a; for(unsigned i = 0; i < x_le_c2.size(); i ++) { a.add(c1_le_x[i]); } for(unsigned i = 0; i < x_le_c2.size(); i ++) { a.add(c1_le_x[i]); } Expr implied = grayShadow(x, rat(0), c1, c2); return newTheorem(implied, a, pf); } Theorem ArithTheoremProducerOld::addInequalities(const vector& thms) { // Check soundness if (CHECK_PROOFS) { for (unsigned i = 0; i < thms.size(); i ++) { Expr expr = thms[i].getExpr(); CHECK_SOUND(isIneq(expr), "addInequalities: expecting an inequality for, got " + expr.toString()); CHECK_SOUND(isLE(expr) || isLT(expr), "addInequalities: expr should be <(=) " + expr.toString()); } } // Create the assumptions Assumptions a; for (unsigned i = 0; i < thms.size(); i ++) a.add(thms[i]); // Get the kinds of the inequalitites int kind = LE; for (unsigned i = 0; i < thms.size(); i ++) if (thms[i].getExpr().getKind() == LT) kind = LT; // Create the proof object Proof pf; if(withProof()) { vector pfs; vector exps; for (unsigned i = 0; i < thms.size(); i ++) { pfs.push_back(thms[i].getProof()); exps.push_back(thms[i].getExpr()); } pf = newPf("addInequalities", exps, pfs); } // Create the new expressions vector summandsLeft; vector summandsRight; for (unsigned i = 0; i < thms.size(); i ++) { summandsLeft.push_back(thms[i].getExpr()[0]); summandsRight.push_back(thms[i].getExpr()[1]); } Expr leftSide = plusExpr(summandsLeft); Expr rightSide = plusExpr(summandsRight); // Return the theorem return newTheorem(Expr(kind, leftSide, rightSide), a, pf); } // x^1 <-> x Theorem ArithTheoremProducerOld::powerOfOne(const Expr& e) { if(CHECK_PROOFS) { CHECK_SOUND(isPow(e), "ArithTheoremProducerOld::powerOfOne: not a power expression" + e.toString()); CHECK_SOUND(e[0].isRational() && e[0].getRational() == 1, "ArithTheoremProducerOld::powerOfOne: not a power of 1" + e.toString()); } Proof pf; if(withProof()) pf = newPf("power_of_one", e); return newRWTheorem(e, e[1], Assumptions::emptyAssump(), pf); } void ArithTheoremProducerOld::getLeaves(const Expr& e, set& s, ExprHashMap& cache) { if (e.isRational()) { s.insert(e.getRational()); return; } if (e.isAtomic() && d_theoryArith->isLeaf(e)) { return; } ExprHashMap::iterator it = cache.find(e); if (it != cache.end()) return; cache[e] = true; DebugAssert(e.arity() > 0, "Expected non-zero arity"); int k = 0; if (e.isITE()) { k = 1; } for (; k < e.arity(); ++k) { getLeaves(e[k], s, cache); } } Theorem ArithTheoremProducerOld::rewriteLeavesConst(const Expr& e) { DebugAssert(e.isPropAtom() && d_theoryArith->leavesAreNumConst(e), "invariant violated"); DebugAssert(e.getKind() == EQ || e.getKind() == LT || e.getKind() == LE || e.getKind() == GT || e.getKind() == GE, "Unexpected kind"); set lhs, rhs; ExprHashMap cache; getLeaves(e[0], lhs, cache); cache.clear(); getLeaves(e[1], rhs, cache); Expr res; switch (e.getKind()) { case EQ: { set common; set_intersection(lhs.begin(), lhs.end(), rhs.begin(), rhs.end(), inserter(common, common.begin())); if (common.empty()) { res = d_em->falseExpr(); } break; } case LT: { set::iterator it; it = lhs.end(); --it; if ((*it) < (*(rhs.begin()))) { res = d_em->trueExpr(); } else { it = rhs.end(); --it; if ((*it) <= (*(lhs.begin()))) { res = d_em->falseExpr(); } } break; } case LE: { set::iterator it; it = lhs.end(); --it; if ((*it) <= (*(rhs.begin()))) { res = d_em->trueExpr(); } else { it = rhs.end(); --it; if ((*it) < (*(lhs.begin()))) { res = d_em->falseExpr(); break; } } break; } case GT: { set::iterator it; it = rhs.end(); --it; if ((*(lhs.begin())) > (*it)) { res = d_em->trueExpr(); } else { it = lhs.end(); --it; if ((*(rhs.begin())) >= (*it)) { res = d_em->falseExpr(); } } break; } case GE: { set::iterator it; it = rhs.end(); --it; if ((*(lhs.begin())) >= (*it)) { res = d_em->trueExpr(); } else { it = lhs.end(); --it; if ((*(rhs.begin())) > (*it)) { res = d_em->falseExpr(); } } break; } default: break; } if (res.isNull()) return d_theoryArith->reflexivityRule(e); else { Proof pf; if(withProof()) pf = newPf("rewrite_leaves_const", e); return newRWTheorem(e, res, Assumptions::emptyAssump(), pf); } } cvc3-2.4.1/src/theory_arith/arith_theorem_producer.cpp0000664000175400017540000031171311304373437023022 0ustar mdetersmdeters/*****************************************************************************/ /*! * \file arith_theorem_producer.cpp * * Author: Vijay Ganesh, Sergey Berezin * * Created: Dec 13 02:09:04 GMT 2002 * *
* * License to use, copy, modify, sell and/or distribute this software * and its documentation for any purpose is hereby granted without * royalty, subject to the terms and conditions defined in the \ref * LICENSE file provided with this distribution. * *
* */ /*****************************************************************************/ // CLASS: ArithProofRules // // AUTHOR: Sergey Berezin, 12/11/2002 // AUTHOR: Vijay Ganesh, 05/30/2003 // // Description: TRUSTED implementation of arithmetic proof rules. // /////////////////////////////////////////////////////////////////////////////// // This code is trusted #define _CVC3_TRUSTED_ #include "arith_theorem_producer.h" #include "theory_core.h" #include "theory_arith_new.h" using namespace std; using namespace CVC3; //////////////////////////////////////////////////////////////////// // TheoryArith: trusted method for creating ArithTheoremProducer //////////////////////////////////////////////////////////////////// ArithProofRules* TheoryArithNew::createProofRules() { return new ArithTheoremProducer(theoryCore()->getTM(), this); } //////////////////////////////////////////////////////////////////// // Canonization rules //////////////////////////////////////////////////////////////////// #define CLASS_NAME "ArithTheoremProducer" // Rule for variables: e == 1 * e Theorem ArithTheoremProducer::varToMult(const Expr& e) { Proof pf; if(withProof()) pf = newPf("var_to_mult", e); return newRWTheorem(e, (rat(1) * e), Assumptions::emptyAssump(), pf); } // Rule for unary minus: -e == (-1) * e Theorem ArithTheoremProducer::uMinusToMult(const Expr& e) { // The proof object to use Proof pf; // If the proof is needed set it up if(withProof()) pf = newPf("uminus_to_mult", e); // Return the rewrite theorem explaining the rewrite return newRWTheorem((-e), (rat(-1) * e), Assumptions::emptyAssump(), pf); } // ==> x - y = x + (-1) * y Theorem ArithTheoremProducer::minusToPlus(const Expr& x, const Expr& y) { // The proof object to use Proof pf; // If proof is needed, set it up if (withProof()) pf = newPf("minus_to_plus", x, y); // Return a new rewrite theorem describing the change return newRWTheorem((x-y), (x + (rat(-1) * y)), Assumptions::emptyAssump(), pf); } // Rule for unary minus: -e == e/(-1) // This is to reduce the number of almost identical rules for uminus and div Theorem ArithTheoremProducer::canonUMinusToDivide(const Expr& e) { Proof pf; if(withProof()) pf = newPf("canon_uminus", e); return newRWTheorem((-e), (e / rat(-1)), Assumptions::emptyAssump(), pf); } // Rules for division by constant // (c)/(d) ==> (c/d). When d==0, c/0 = 0 (our total extension). Theorem ArithTheoremProducer::canonDivideConst(const Expr& c, const Expr& d) { // Make sure c and d are a const if(CHECK_PROOFS) { CHECK_SOUND(isRational(c), CLASS_NAME "::canonDivideConst:\n c not a constant: " + c.toString()); CHECK_SOUND(isRational(d), CLASS_NAME "::canonDivideConst:\n d not a constant: " + d.toString()); } Proof pf; if(withProof()) pf = newPf("canon_divide_const", c, d, d_hole); const Rational& dr = d.getRational(); return newRWTheorem((c/d), (rat(dr==0? 0 : (c.getRational()/dr))), Assumptions::emptyAssump(), pf); } // (c * x)/d ==> (c/d) * x, takes (c*x) and d Theorem ArithTheoremProducer::canonDivideMult(const Expr& cx, const Expr& d) { // Check the format of c*x if(CHECK_PROOFS) { CHECK_SOUND(isMult(cx) && isRational(cx[0]), CLASS_NAME "::canonDivideMult:\n " "Not a (c * x) expression: " + cx.toString()); CHECK_SOUND(isRational(d), CLASS_NAME "::canonDivideMult:\n " "d is not a constant: " + d.toString()); } const Rational& dr = d.getRational(); Rational cdr(dr==0? 0 : (cx[0].getRational()/dr)); Expr cd(rat(cdr)); Proof pf; if(withProof()) pf = newPf("canon_divide_mult", cx[0], cx[1], d); // (c/d) may be == 1, so we also need to canonize 1*x to x if(cdr == 1) return newRWTheorem((cx/d), (cx[1]), Assumptions::emptyAssump(), pf); else if(cdr == 0) // c/0 == 0 case return newRWTheorem((cx/d), cd, Assumptions::emptyAssump(), pf); else return newRWTheorem((cx/d), (cd*cx[1]), Assumptions::emptyAssump(), pf); } // (+ t1 ... tn)/d ==> (+ (t1/d) ... (tn/d)) Theorem ArithTheoremProducer::canonDividePlus(const Expr& sum, const Expr& d) { if(CHECK_PROOFS) { CHECK_SOUND(isPlus(sum) && sum.arity() >= 2 && isRational(sum[0]), CLASS_NAME "::canonUMinusPlus:\n " "Expr is not a canonical sum: " + sum.toString()); CHECK_SOUND(isRational(d), CLASS_NAME "::canonUMinusPlus:\n " "d is not a const: " + d.toString()); } // First, propagate '/d' down to the args Proof pf; if(withProof()) pf = newPf("canon_divide_plus", rat(sum.arity()), sum.begin(), sum.end()); vector newKids; for(Expr::iterator i=sum.begin(), iend=sum.end(); i!=iend; ++i) newKids.push_back((*i)/d); // (+ t1 ... tn)/d == (+ (t1/d) ... (tn/d)) return newRWTheorem((sum/d), (plusExpr(newKids)), Assumptions::emptyAssump(), pf); } // x/(d) ==> (1/d) * x, unless d == 1 Theorem ArithTheoremProducer::canonDivideVar(const Expr& e, const Expr& d) { if(CHECK_PROOFS) { CHECK_SOUND(isRational(d), CLASS_NAME "::canonDivideVar:\n " "d is not a const: " + d.toString()); } Proof pf; if(withProof()) pf = newPf("canon_divide_var", e); const Rational& dr = d.getRational(); if(dr == 1) return newRWTheorem(e/d, e, Assumptions::emptyAssump(), pf); if(dr == 0) // e/0 == 0 (total extension of division) return newRWTheorem(e/d, d, Assumptions::emptyAssump(), pf); else return newRWTheorem(e/d, rat(1/dr) * e, Assumptions::emptyAssump(), pf); } // Multiplication // (MULT expr1 expr2 expr3 ...) // Each expr is in canonical form, i.e. it can be a // 1) Rational constant // 2) Arithmetic Leaf (var or term from another theory) // 3) (POW rational leaf) // where rational cannot be 0 or 1 // 4) (MULT rational mterm'_1 ...) where each mterm' is of type (2) or (3) // If rational == 1 then there should be at least two mterms // 5) (PLUS rational sterm_1 ...) where each sterm is of // type (2) or (3) or (4) // if rational == 0 then there should be at least two sterms Expr ArithTheoremProducer::simplifiedMultExpr(std::vector & mulKids) { // Check that the number of kids is at least 1 and that the first one is rational DebugAssert(mulKids.size() >= 1 && mulKids[0].isRational(), ""); // If the number of kids is only one, return the kid, no multiplication is necessary if (mulKids.size() == 1) return mulKids[0]; // Otherwise return the multiplication of given expression else return multExpr(mulKids); } Expr ArithTheoremProducer::canonMultConstMult(const Expr & c, const Expr & e) { // The constant must be a rational and e must be a multiplication DebugAssert(c.isRational() && e.getKind() == MULT, "ArithTheoremProducer::canonMultConstMult: c must be a rational a e must be a MULT"); // Multiplication must include a rational multiplier DebugAssert ((e.arity() > 1) && (e[0].isRational()), "arith_theorem_producer::canonMultConstMult: a canonized MULT expression must have \ arity greater than 1: and first child must be rational " + e.toString()); // The kids of the new multiplication std::vector mulKids; // Create new multiplication expression, multiplying the constant with the given constant Expr::iterator i = e.begin(); mulKids.push_back(rat(c.getRational() * (*i).getRational())); // All the rest, just push them to the kids vector for(i ++; i != e.end(); i ++) mulKids.push_back(*i); // Return the simplified multiplication expression return simplifiedMultExpr(mulKids); } Expr ArithTheoremProducer::canonMultConstPlus(const Expr & e1, const Expr & e2) { // e1 must be a rational and e2 must be a sum in canonic form DebugAssert(e1.isRational() && e2.getKind() == PLUS && e2.arity() > 0, ""); // Vector to hold all the sum terms std::vector thmPlusVector; // Go through all the sum terms and multiply them with the constant for(Expr::iterator i = e2.begin(); i != e2.end(); i++) thmPlusVector.push_back(canonMultMtermMterm(e1*(*i))); // Substitute the canonized terms into the sum Theorem thmPlus1 = d_theoryArith->substitutivityRule(e2.getOp(), thmPlusVector); // Return the resulting expression return thmPlus1.getRHS(); } Expr ArithTheoremProducer::canonMultPowPow(const Expr & e1, const Expr & e2) { DebugAssert(e1.getKind() == POW && e2.getKind() == POW, ""); // (POW r1 leaf1) * (POW r2 leaf2) Expr leaf1 = e1[1]; Expr leaf2 = e2[1]; Expr can_expr; if (leaf1 == leaf2) { Rational rsum = e1[0].getRational() + e2[0].getRational(); if (rsum == 0) { return rat(1); } else if (rsum == 1) { return leaf1; } else { return powExpr(rat(rsum), leaf1); } } else { std::vector mulKids; mulKids.push_back(rat(1)); // the leafs should be put in decreasing order if (leaf1 < leaf2) { mulKids.push_back(e2); mulKids.push_back(e1); } else { mulKids.push_back(e1); mulKids.push_back(e2); } // FIXME: don't really need to simplify, just wrap up a MULT? return simplifiedMultExpr(mulKids); } } Expr ArithTheoremProducer::canonMultPowLeaf(const Expr & e1, const Expr & e2) { DebugAssert(e1.getKind() == POW, ""); // (POW r1 leaf1) * leaf2 Expr leaf1 = e1[1]; Expr leaf2 = e2; Expr can_expr; if (leaf1 == leaf2) { Rational rsum = e1[0].getRational() + 1; if (rsum == 0) { return rat(1); } else if (rsum == 1) { return leaf1; } else { return powExpr(rat(rsum), leaf1); } } else { std::vector mulKids; mulKids.push_back(rat(1)); // the leafs should be put in decreasing order if (leaf1 < leaf2) { mulKids.push_back(e2); mulKids.push_back(e1); } else { mulKids.push_back(e1); mulKids.push_back(e2); } return simplifiedMultExpr(mulKids); } } Expr ArithTheoremProducer::canonMultLeafLeaf(const Expr & e1, const Expr & e2) { // leaf1 * leaf2 Expr leaf1 = e1; Expr leaf2 = e2; Expr can_expr; if (leaf1 == leaf2) { return powExpr(rat(2), leaf1); } else { std::vector mulKids; mulKids.push_back(rat(1)); // the leafs should be put in decreasing order if (leaf1 < leaf2) { mulKids.push_back(e2); mulKids.push_back(e1); } else { mulKids.push_back(e1); mulKids.push_back(e2); } return simplifiedMultExpr(mulKids); } } Expr ArithTheoremProducer::canonMultLeafOrPowMult(const Expr & e1, const Expr & e2) { DebugAssert(e2.getKind() == MULT, ""); // Leaf * (MULT rat1 mterm1 ...) // (POW r1 leaf1) * (MULT rat1 mterm1 ...) where // each mterm is a leaf or (POW r leaf). Furthermore the leafs // in the mterms are in descending order Expr leaf1 = e1.getKind() == POW ? e1[1] : e1; std::vector mulKids; DebugAssert(e2.arity() > 1, "MULT expr must have arity 2 or more"); Expr::iterator i = e2.begin(); // push the rational mulKids.push_back(*i); ++i; // Now i points to the first mterm for(; i != e2.end(); ++i) { Expr leaf2 = ((*i).getKind() == POW) ? (*i)[1] : (*i); if (leaf1 == leaf2) { Rational r1 = e1.getKind() == POW ? e1[0].getRational() : 1; Rational r2 = ((*i).getKind() == POW ? (*i)[0].getRational() : 1); // if r1 + r2 == 0 then it is the case of x^n * x^{-n} // So, nothing needs to be added if (r1 + r2 != 0) { if (r1 + r2 == 1) { mulKids.push_back(leaf1); } else { mulKids.push_back(powExpr(rat(r1 + r2), leaf1)); } } break; } // This ensures that the leaves in the mterms are also arranged // in decreasing order // Note that this will need to be changed if we want the order to // be increasing order. else if (leaf2 < leaf1) { mulKids.push_back(e1); mulKids.push_back(*i); break; } else // leaf1 < leaf2 mulKids.push_back(*i); } if (i == e2.end()) { mulKids.push_back(e1); } else { // e1 and *i have already been added for (++i; i != e2.end(); ++i) { mulKids.push_back(*i); } } return simplifiedMultExpr(mulKids); } // Local class for ordering monomials; note, that it flips the // ordering given by greaterthan(), to sort in ascending order. class MonomialLess { public: bool operator()(const Expr& e1, const Expr& e2) const { return ArithTheoremProducer::greaterthan(e1,e2); } }; typedef map MonomMap; Expr ArithTheoremProducer::canonCombineLikeTerms(const std::vector & sumExprs) { Rational constant = 0; // The constant at the begining of the sum MonomMap sumHashMap; // The hash map of the summands, so that we can gather them and sum in the right order vector sumKids; // The kids of the sum // Add each distinct mterm (not including the rational) into an appropriate hash map entry std::vector::const_iterator i = sumExprs.begin(); std::vector::const_iterator i_end = sumExprs.end(); for (; i != i_end; i++) { // Take the current expression (it must be a multiplication, a leaf or a rational number) Expr mul = *i; // If it's a rational, just add it to the constant factor c if (mul.isRational()) constant = constant + mul.getRational(); else { // Depending on the type of the expression decide what to do with this sum term switch (mul.getKind()) { // Multiplication is case MULT: { // The multiplication must be of arity > 1 and the first one must be rational DebugAssert(mul.arity() > 1 && mul[0].isRational(),"If sum term is multiplication it must have the first term a rational, and at least another one"); // Get the rational constant of multiplication Rational r = mul[0].getRational(); // Make a new multiplication term with a 1 instead of the rational r vector newKids; // Copy the children to the newKids vector (including the rational) for(Expr::iterator m = mul.begin(); m != mul.end(); m ++) newKids.push_back(*m); // Change the rational to 1 newKids[0] = rat(1); // Make the newMul expression Expr newMul = multExpr(newKids); // Find the term in the hashmap, so that we can add the coefficient (a*t + b*t = (a+b)*t) MonomMap::iterator i = sumHashMap.find(newMul); // If not found, just add the rational to the hash map if (i == sumHashMap.end()) sumHashMap[newMul] = r; // Otherwise, add it to the existing coefficient else (*i).second += r; // MULT case break break; } default: { // Find the term in the hashmap (add the 1*mul for being canonical) MonomMap::iterator i = sumHashMap.find(multExpr(rat(1), mul)); // covers the case of POW, leaf if (i == sumHashMap.end()) sumHashMap[multExpr(rat(1), mul)] = 1; else (*i).second += 1; // Default break break; } } } } // Now transfer to sumKids, first adding the rational constant if different from 0 (b + a_1*x_1 + a_2*x_2 + ... + a_n*x_n) if (constant != 0) sumKids.push_back(rat(constant)); // After the constant, add all the other summands, in the right order (the hashmap order) MonomMap::iterator j = sumHashMap.begin(), jend=sumHashMap.end(); for(; j != jend; j++) { // If the corresponding coefficient is non-zero, add the term to the sum if ((*j).second != 0) { // Again, make a new multiplication term with a the coefficient instead of the rational one (1) vector newKids; // Copy the children to the newKids vector (including the rational) for(Expr::iterator m = (*j).first.begin(); m != (*j).first.end(); m ++) newKids.push_back(*m); // Change the rational to the summed rationals for this term newKids[0] = rat((*j).second); // Make the newMul expression and add it to the sum sumKids.push_back(multExpr(newKids)); } } // If the whole sum is only the constant, the whole sum is only the constant (TODO: CLEAN THIS UP, ITS HORRIBLE) if (constant != 0 && sumKids.size() == 1) return sumKids[0]; // If the constant is 0 and there is only one more summand, return only the summand if (constant == 0 && sumKids.size() == 1) return sumKids[0]; // If the constant is 0 and there are no summands, return 0 if (constant == 0 && sumKids.size() == 0) return rat(0); // Otherwise return the sum of the sumkids return plusExpr(sumKids); } Expr ArithTheoremProducer::canonMultLeafOrPowOrMultPlus(const Expr & e1, const Expr & e2) { DebugAssert(e2.getKind() == PLUS, ""); // Leaf * (PLUS rational sterm1 ...) // or // (POW n1 x1) * (PLUS rational sterm1 ...) // or // (MULT r1 m1 m2 ...) * (PLUS rational sterm1 ...) // assume that e1 and e2 are themselves canonized std::vector sumExprs; // Multiply each term in turn. Expr::iterator i = e2.begin(); for (; i != e2.end(); ++i) { sumExprs.push_back(canonMultMtermMterm(e1 * (*i)).getRHS()); } return canonCombineLikeTerms(sumExprs); } Expr ArithTheoremProducer::canonMultPlusPlus(const Expr & e1, const Expr & e2) { DebugAssert(e1.getKind() == PLUS && e2.getKind() == PLUS, ""); // (PLUS r1 .... ) * (PLUS r1' ...) // assume that e1 and e2 are themselves canonized std::vector sumExprs; // Multiply each term in turn. Expr::iterator i = e1.begin(); for (; i != e1.end(); ++i) { Expr::iterator j = e2.begin(); for (; j != e2.end(); ++j) { sumExprs.push_back(canonMultMtermMterm((*i) * (*j)).getRHS()); } } return canonCombineLikeTerms(sumExprs); } // The following produces a Theorem which is the result of multiplication // of two canonized mterms. e = e1*e2 Theorem ArithTheoremProducer::canonMultMtermMterm(const Expr& e) { // Check if the rule is sound if(CHECK_PROOFS) { CHECK_SOUND(isMult(e) && e.arity() == 2, "canonMultMtermMterm: e = " + e.toString()); } // The proof we are using Proof pf; // The resulting expression Expr rhs; // Get the parts of the multiplication const Expr& e1 = e[0]; const Expr& e2 = e[1]; // The name of the proof string cmmm = "canon_mult_mterm_mterm"; if (e1.isRational()) { // e1 is a Rational const Rational& c = e1.getRational(); if (c == 0) return canonMultZero(e2); else if (c == 1) return canonMultOne(e2); else { switch (e2.getKind()) { case RATIONAL_EXPR : // rat * rat return canonMultConstConst(e1,e2); break; // TODO case of leaf case POW: // rat * (POW rat leaf) // nothing to simplify return d_theoryArith->reflexivityRule (e); break; case MULT: rhs = canonMultConstMult(e1,e2); if(withProof()) pf = newPf(cmmm,e,rhs); return newRWTheorem(e, rhs, Assumptions::emptyAssump(), pf); break; case PLUS: rhs = canonMultConstPlus(e1,e2); if(withProof()) pf = newPf(cmmm,e,rhs); return newRWTheorem(e, rhs, Assumptions::emptyAssump(), pf); break; default: // TODO: I am going to assume that this is just a leaf // i.e., a variable or term from another theory return d_theoryArith->reflexivityRule(e); break; } } } else if (e1.getKind() == POW) { switch (e2.getKind()) { case RATIONAL_EXPR: // switch the order of the two arguments return canonMultMtermMterm(e2 * e1); break; case POW: rhs = canonMultPowPow(e1,e2); if(withProof()) pf = newPf(cmmm,e,rhs); return newRWTheorem(e,rhs, Assumptions::emptyAssump(), pf); break; case MULT: rhs = canonMultLeafOrPowMult(e1,e2); if(withProof()) pf = newPf(cmmm,e,rhs); return newRWTheorem(e, rhs, Assumptions::emptyAssump(), pf); break; case PLUS: rhs = canonMultLeafOrPowOrMultPlus(e1,e2); if(withProof()) pf = newPf(cmmm,e,rhs); return newRWTheorem(e, rhs, Assumptions::emptyAssump(), pf); break; default: rhs = canonMultPowLeaf(e1,e2); if(withProof()) pf = newPf(cmmm,e,rhs); return newRWTheorem(e,rhs, Assumptions::emptyAssump(), pf); break; } } else if (e1.getKind() == MULT) { switch (e2.getKind()) { case RATIONAL_EXPR: case POW: // switch the order of the two arguments return canonMultMtermMterm(e2 * e1); break; case MULT: { // (Mult r m1 m2 ...) (Mult r' m1' m2' ...) Expr result = e2; Expr::iterator i = e1.begin(); for (; i != e1.end(); ++i) { result = canonMultMtermMterm((*i) * result).getRHS(); } if(withProof()) pf = newPf(cmmm,e,result); return newRWTheorem(e, result, Assumptions::emptyAssump(), pf); } break; case PLUS: rhs = canonMultLeafOrPowOrMultPlus(e1,e2); if(withProof()) pf = newPf(cmmm,e,rhs); return newRWTheorem(e,rhs, Assumptions::emptyAssump(), pf); break; default: // leaf // switch the order of the two arguments return canonMultMtermMterm(e2 * e1); break; } } else if (e1.getKind() == PLUS) { switch (e2.getKind()) { case RATIONAL_EXPR: case POW: case MULT: // switch the order of the two arguments return canonMultMtermMterm(e2 * e1); break; case PLUS: rhs = canonMultPlusPlus(e1,e2); if(withProof()) pf = newPf(cmmm,e,rhs); return newRWTheorem(e, rhs, Assumptions::emptyAssump(), pf); break; default: // leaf // switch the order of the two arguments return canonMultMtermMterm(e2 * e1); break; } } else { // leaf switch (e2.getKind()) { case RATIONAL_EXPR: // switch the order of the two arguments return canonMultMtermMterm(e2 * e1); break; case POW: rhs = canonMultPowLeaf(e2,e1); if(withProof()) pf = newPf(cmmm,e,rhs); return newRWTheorem(e, rhs, Assumptions::emptyAssump(), pf); break; case MULT: rhs = canonMultLeafOrPowMult(e1,e2);; if(withProof()) pf = newPf(cmmm,e,rhs); return newRWTheorem(e, rhs, Assumptions::emptyAssump(), pf); break; case PLUS: rhs = canonMultLeafOrPowOrMultPlus(e1,e2); if(withProof()) pf = newPf(cmmm,e,rhs); return newRWTheorem(e, rhs, Assumptions::emptyAssump(), pf); break; default: // leaf * leaf rhs = canonMultLeafLeaf(e1,e2); if(withProof()) pf = newPf(cmmm,e,rhs); return newRWTheorem(e, rhs, Assumptions::emptyAssump(), pf); break; } } FatalAssert(false, "Unreachable"); return newRWTheorem(e, rhs, Assumptions::emptyAssump(), pf); } // (PLUS expr1 expr2 ...) where each expr is itself in canonic form Theorem ArithTheoremProducer::canonPlus(const Expr& e) { // Create the proof object in case we need it Proof pf; // The operation must be PLUS DebugAssert(e.getKind() == PLUS, ""); // Add all the summands to the sumKids vector std::vector sumKids; Expr::iterator i = e.begin(); for(; i != e.end(); ++i) { if ((*i).getKind() != PLUS) sumKids.push_back(*i); else { // If the kid is also a sum, add it to the sumKids vector (no need for recursion, kids are already canonized) Expr::iterator j = (*i).begin(); for(; j != (*i).end(); ++j) sumKids.push_back(*j); } } // Combine all the kids to sum (gather the same variables and stuff) Expr val = canonCombineLikeTerms(sumKids); // If proofs needed set it up with starting expression and the value if (withProof()) { pf = newPf("canon_plus", e, val); } // Return the explaining rewrite theorem return newRWTheorem(e, val, Assumptions::emptyAssump(), pf); } // (MULT expr1 expr2 ...) where each expr is itself in canonic form Theorem ArithTheoremProducer::canonMult(const Expr& e) { // The proof we might need Proof pf; // Expression must be of kind MULT DebugAssert(e.getKind() == MULT && e.arity() > 1, ""); // Get the first operand of the multiplication Expr::iterator i = e.begin(); // Set the result to the first element Expr result = *i; // Skip to the next one ++i; // For all the other elements for (; i != e.end(); ++i) { // Multiply each element into the result result = canonMultMtermMterm(result * (*i)).getRHS(); } // If the proof is needed, create one if (withProof()) { pf = newPf("canon_mult", e,result); } // Return a new rewrite theorem with the result return newRWTheorem(e, result, Assumptions::emptyAssump(), pf); } Theorem ArithTheoremProducer::canonInvertConst(const Expr& e) { if(CHECK_PROOFS) CHECK_SOUND(isRational(e), "expecting a rational: e = "+e.toString()); Proof pf; if (withProof()) { pf = newPf("canon_invert_const", e); } const Rational& er = e.getRational(); return newRWTheorem((rat(1)/e), rat(er==0? 0 : (1/er)), Assumptions::emptyAssump(), pf); } Theorem ArithTheoremProducer::canonInvertLeaf(const Expr& e) { Proof pf; if (withProof()) { pf = newPf("canon_invert_leaf", e); } return newRWTheorem((rat(1)/e), powExpr(rat(-1), e), Assumptions::emptyAssump(), pf); } Theorem ArithTheoremProducer::canonInvertPow(const Expr& e) { DebugAssert(e.getKind() == POW, "expecting a rational"+e[0].toString()); Proof pf; if (withProof()) { pf = newPf("canon_invert_pow", e); } if (e[0].getRational() == -1) return newRWTheorem((rat(1)/e), e[1], Assumptions::emptyAssump(), pf); else return newRWTheorem((rat(1)/e), powExpr(rat(-e[0].getRational()), e), Assumptions::emptyAssump(), pf); } Theorem ArithTheoremProducer::canonInvertMult(const Expr& e) { DebugAssert(e.getKind() == MULT, "expecting a rational"+e[0].toString()); Proof pf; if (withProof()) { pf = newPf("canon_invert_mult", e); } DebugAssert(e.arity() > 1, "MULT should have arity > 1"+e.toString()); Expr result = canonInvert(e[0]).getRHS(); for (int i = 1; i < e.arity(); ++i) { result = canonMultMtermMterm(result * canonInvert(e[i]).getRHS()).getRHS(); } return newRWTheorem((rat(1)/e), result, Assumptions::emptyAssump(), pf); } // Given an expression e in Canonic form generate 1/e in canonic form // This function assumes that e is not a PLUS expression Theorem ArithTheoremProducer::canonInvert(const Expr& e) { DebugAssert(e.getKind() != PLUS, "Cannot do inverse on a PLUS"+e.toString()); switch (e.getKind()) { case RATIONAL_EXPR: return canonInvertConst(e); break; case POW: return canonInvertPow(e); break; case MULT: return canonInvertMult(e); break; default: // leaf return canonInvertLeaf(e); break; } } Theorem ArithTheoremProducer::canonDivide(const Expr& e) { // The expression should be of type DIVIDE DebugAssert(e.getKind() == DIVIDE, "Expecting Divide"+e.toString()); // The proof if we need one Proof pf; // If the proof is needed make it if (withProof()) { pf = newPf("canon_invert_divide", e); } // Rewrite e[0] / e[1] as e[0]*(e[1])^-1 Theorem thm = newRWTheorem(e, e[0]*(canonInvert(e[1]).getRHS()), Assumptions::emptyAssump(), pf); // Return the proof with canonizing the above multiplication return d_theoryArith->transitivityRule(thm, canonMult(thm.getRHS())); } // Rules for multiplication // t*c ==> c*t, takes constant c and term t Theorem ArithTheoremProducer::canonMultTermConst(const Expr& c, const Expr& t) { Proof pf; if(CHECK_PROOFS) { CHECK_SOUND(isRational(c), CLASS_NAME "::canonMultTermConst:\n " "c is not a constant: " + c.toString()); } if(withProof()) pf = newPf("canon_mult_term_const", c, t); return newRWTheorem((t*c), (c*t), Assumptions::emptyAssump(), pf); } // Rules for multiplication // t1*t2 ==> Error, takes t1 and t2 where both are non-constants Theorem ArithTheoremProducer::canonMultTerm1Term2(const Expr& t1, const Expr& t2) { // Proof pf; // if(withProof()) pf = newPf("canon_mult_term1_term2", t1, t2); if(CHECK_PROOFS) { CHECK_SOUND(false, "Fatal Error: We don't support multiplication" "of two non constant terms at this time " + t1.toString() + " and " + t2.toString()); } return Theorem(); } // Rules for multiplication // 0*x = 0, takes x Theorem ArithTheoremProducer::canonMultZero(const Expr& e) { Proof pf; if(withProof()) pf = newPf("canon_mult_zero", e); return newRWTheorem((rat(0)*e), rat(0), Assumptions::emptyAssump(), pf); } // Rules for multiplication // 1*x ==> x, takes x (if x is other than a leaf) // otherwise 1*x ==> 1*x Theorem ArithTheoremProducer::canonMultOne(const Expr& e) { // Setup the proof object Proof pf; if(withProof()) pf = newPf("canon_mult_one", e); // If it is a leaf multiply it by one if (d_theoryArith->isLeaf(e)) return d_theoryArith->reflexivityRule (rat(1)*e); // Otherwise, just return the expression itself return newRWTheorem((rat(1)*e), e, Assumptions::emptyAssump(), pf); } // Rules for multiplication // c1*c2 ==> c', takes constant c1*c2 Theorem ArithTheoremProducer::canonMultConstConst(const Expr& c1, const Expr& c2) { Proof pf; if(CHECK_PROOFS) { CHECK_SOUND(isRational(c1), CLASS_NAME "::canonMultConstConst:\n " "c1 is not a constant: " + c1.toString()); CHECK_SOUND(isRational(c2), CLASS_NAME "::canonMultConstConst:\n " "c2 is not a constant: " + c2.toString()); } if(withProof()) pf = newPf("canon_mult_const_const", c1, c2); return newRWTheorem((c1*c2), rat(c1.getRational()*c2.getRational()), Assumptions::emptyAssump(), pf); } // Rules for multiplication // c1*(c2*t) ==> c'*t, takes c1 and c2 and t Theorem ArithTheoremProducer::canonMultConstTerm(const Expr& c1, const Expr& c2,const Expr& t) { Proof pf; if(CHECK_PROOFS) { CHECK_SOUND(isRational(c1), CLASS_NAME "::canonMultConstTerm:\n " "c1 is not a constant: " + c1.toString()); CHECK_SOUND(isRational(c2), CLASS_NAME "::canonMultConstTerm:\n " "c2 is not a constant: " + c2.toString()); } if(withProof()) pf = newPf("canon_mult_const_term", c1, c2, t); return newRWTheorem(c1*(c2*t), rat(c1.getRational()*c2.getRational())*t, Assumptions::emptyAssump(), pf); } // Rules for multiplication // c1*(+ c2 v1 ...) ==> (+ c1c2 c1v1 ...), takes c1 and the sum Theorem ArithTheoremProducer::canonMultConstSum(const Expr& c1, const Expr& sum) { Proof pf; std::vector sumKids; if(CHECK_PROOFS) { CHECK_SOUND(isRational(c1), CLASS_NAME "::canonMultConstTerm:\n " "c1 is not a constant: " + c1.toString()); CHECK_SOUND(PLUS == sum.getKind(), CLASS_NAME "::canonMultConstTerm:\n " "the kind must be a PLUS: " + sum.toString()); } Expr::iterator i = sum.begin(); for(; i != sum.end(); ++i) sumKids.push_back(c1*(*i)); Expr ret = plusExpr(sumKids); if(withProof()) pf = newPf("canon_mult_const_sum", c1, sum, ret); return newRWTheorem((c1*sum),ret , Assumptions::emptyAssump(), pf); } // c^n = c' (compute the constant power expression) Theorem ArithTheoremProducer::canonPowConst(const Expr& e) { if(CHECK_PROOFS) { CHECK_SOUND(e.getKind() == POW && e.arity() == 2 && e[0].isRational() && e[1].isRational(), "ArithTheoremProducer::canonPowConst("+e.toString()+")"); } const Rational& p = e[0].getRational(); const Rational& base = e[1].getRational(); if(CHECK_PROOFS) { CHECK_SOUND(p.isInteger(), "ArithTheoremProducer::canonPowConst("+e.toString()+")"); } Expr res; if (base == 0 && p < 0) { res = rat(0); } else res = rat(pow(p, base)); Proof pf; if(withProof()) pf = newPf("canon_pow_const", e); return newRWTheorem(e, res, Assumptions::emptyAssump(), pf); } // Rules for addition // flattens the input. accepts a PLUS expr Theorem ArithTheoremProducer::canonFlattenSum(const Expr& e) { Proof pf; std::vector sumKids; if(CHECK_PROOFS) { CHECK_SOUND(PLUS == e.getKind(), CLASS_NAME "::canonFlattenSum:\n" "input must be a PLUS:" + e.toString()); } Expr::iterator i = e.begin(); for(; i != e.end(); ++i){ if (PLUS != (*i).getKind()) sumKids.push_back(*i); else { Expr::iterator j = (*i).begin(); for(; j != (*i).end(); ++j) sumKids.push_back(*j); } } Expr ret = plusExpr(sumKids); if(withProof()) pf = newPf("canon_flatten_sum", e,ret); return newRWTheorem(e,ret, Assumptions::emptyAssump(), pf); } // Rules for addition // combine like terms. accepts a flattened PLUS expr Theorem ArithTheoremProducer::canonComboLikeTerms(const Expr& e) { Proof pf; std::vector sumKids; ExprMap sumHashMap; Rational constant = 0; if(CHECK_PROOFS) { Expr::iterator k = e.begin(); for(; k != e.end(); ++k) CHECK_SOUND(!isPlus(*k), CLASS_NAME "::canonComboLikeTerms:\n" "input must be a flattened PLUS:" + k->toString()); } Expr::iterator i = e.begin(); for(; i != e.end(); ++i){ if(i->isRational()) constant = constant + i->getRational(); else { if (!isMult(*i)) { if(0 == sumHashMap.count((*i))) sumHashMap[*i] = 1; else sumHashMap[*i] += 1; } else { if(0 == sumHashMap.count((*i)[1])) sumHashMap[(*i)[1]] = (*i)[0].getRational(); else sumHashMap[(*i)[1]] = sumHashMap[(*i)[1]] + (*i)[0].getRational(); } } } sumKids.push_back(rat(constant)); ExprMap::iterator j = sumHashMap.begin(); for(; j != sumHashMap.end(); ++j) { if(0 == (*j).second) ;//do nothing else if (1 == (*j).second) sumKids.push_back((*j).first); else sumKids.push_back(rat((*j).second) * (*j).first); } //constant is same as sumKids[0]. //corner cases: "0 + monomial" and "constant"(no monomials) Expr ret; if(2 == sumKids.size() && 0 == constant) ret = sumKids[1]; else if (1 == sumKids.size()) ret = sumKids[0]; else ret = plusExpr(sumKids); if(withProof()) pf = newPf("canon_combo_like_terms",e,ret); return newRWTheorem(e, ret, Assumptions::emptyAssump(), pf); } // 0 = (* e1 e2 ...) <=> 0 = e1 OR 0 = e2 OR ... Theorem ArithTheoremProducer::multEqZero(const Expr& expr) { if (CHECK_PROOFS) { CHECK_SOUND(expr.isEq() && expr[0].isRational() && expr[0].getRational() == 0 && isMult(expr[1]) && expr[1].arity() > 1, "multEqZero invariant violated"+expr.toString()); } Proof pf; vector kids; Expr::iterator i = expr[1].begin(), iend = expr[1].end(); for (; i != iend; ++i) { kids.push_back(rat(0).eqExpr(*i)); } if (withProof()) { pf = newPf("multEqZero", expr); } return newRWTheorem(expr, Expr(OR, kids), Assumptions::emptyAssump(), pf); } // 0 = (^ c x) <=> false if c <=0 // <=> 0 = x if c > 0 Theorem ArithTheoremProducer::powEqZero(const Expr& expr) { if (CHECK_PROOFS) { CHECK_SOUND(expr.isEq() && expr[0].isRational() && expr[0].getRational() == 0 && isPow(expr[1]) && expr[1].arity() == 2 && expr[1][0].isRational(), "powEqZero invariant violated"+expr.toString()); } Proof pf; if (withProof()) { pf = newPf("powEqZero", expr); } Rational r = expr[1][0].getRational(); Expr res; if (r <= 0) { res = d_em->falseExpr(); } else { res = rat(0).eqExpr(expr[1][1]); } return newRWTheorem(expr, res, Assumptions::emptyAssump(), pf); } // x^n = y^n <=> x = y (if n is odd) // x^n = y^n <=> x = y OR x = -y (if n is even) Theorem ArithTheoremProducer::elimPower(const Expr& expr) { if (CHECK_PROOFS) { CHECK_SOUND(expr.isEq() && isPow(expr[0]) && isPow(expr[1]) && isIntegerConst(expr[0][0]) && expr[0][0].getRational() > 0 && expr[0][0] == expr[1][0], "elimPower invariant violated"+expr.toString()); } Proof pf; if (withProof()) { pf = newPf("elimPower", expr); } Rational r = expr[0][0].getRational(); Expr res = expr[0][1].eqExpr(expr[1][1]); if (r % 2 == 0) { res = res.orExpr(expr[0][1].eqExpr(-expr[1][1])); } return newRWTheorem(expr, res, Assumptions::emptyAssump(), pf); } // x^n = c <=> x = root (if n is odd and root^n = c) // x^n = c <=> x = root OR x = -root (if n is even and root^n = c) Theorem ArithTheoremProducer::elimPowerConst(const Expr& expr, const Rational& root) { if (CHECK_PROOFS) { CHECK_SOUND(expr.isEq() && isPow(expr[0]) && isIntegerConst(expr[0][0]) && expr[0][0].getRational() > 0 && expr[1].isRational() && pow(expr[0][0].getRational(), root) == expr[1].getRational(), "elimPowerConst invariant violated"+expr.toString()); } Proof pf; if (withProof()) { pf = newPf("elimPowerConst", expr, rat(root)); } Rational r = expr[0][0].getRational(); Expr res = expr[0][1].eqExpr(rat(root)); if (r % 2 == 0) { res = res.orExpr(expr[0][1].eqExpr(rat(-root))); } return newRWTheorem(expr, res, Assumptions::emptyAssump(), pf); } // x^n = c <=> false (if n is even and c is negative) Theorem ArithTheoremProducer::evenPowerEqNegConst(const Expr& expr) { if (CHECK_PROOFS) { CHECK_SOUND(expr.isEq() && isPow(expr[0]) && expr[1].isRational() && isIntegerConst(expr[0][0]) && expr[0][0].getRational() % 2 == 0 && expr[1].getRational() < 0, "evenPowerEqNegConst invariant violated"+expr.toString()); } Proof pf; if (withProof()) { pf = newPf("evenPowerEqNegConst", expr); } return newRWTheorem(expr, d_em->falseExpr(), Assumptions::emptyAssump(), pf); } // x^n = c <=> false (if x is an integer and c is not a perfect n power) Theorem ArithTheoremProducer::intEqIrrational(const Expr& expr, const Theorem& isIntx) { if (CHECK_PROOFS) { CHECK_SOUND(expr.isEq() && isPow(expr[0]) && expr[1].isRational() && expr[1].getRational() != 0 && isIntegerConst(expr[0][0]) && expr[0][0].getRational() > 0 && ratRoot(expr[1].getRational(), expr[0][0].getRational().getUnsigned()) == 0, "intEqIrrational invariant violated"+expr.toString()); CHECK_SOUND(isIntPred(isIntx.getExpr()) && isIntx.getExpr()[0] == expr[0][1], "ArithTheoremProducerOld::intEqIrrational:\n " "wrong integrality constraint:\n expr = " +expr.toString()+"\n isIntx = " +isIntx.getExpr().toString()); } const Assumptions& assump(isIntx.getAssumptionsRef()); Proof pf; if (withProof()) { pf = newPf("int_eq_irr", expr, isIntx.getProof()); } return newRWTheorem(expr, d_em->falseExpr(), assump, pf); } // e[0] kind e[1] <==> true when e[0] kind e[1], // false when e[0] !kind e[1], for constants only Theorem ArithTheoremProducer::constPredicate(const Expr& e) { if(CHECK_PROOFS) { CHECK_SOUND(e.arity() == 2 && isRational(e[0]) && isRational(e[1]), CLASS_NAME "::constPredicate:\n " "non-const parameters: " + e.toString()); } Proof pf; bool result(false); int kind = e.getKind(); Rational r1 = e[0].getRational(), r2 = e[1].getRational(); switch(kind) { case EQ: result = (r1 == r2)?true : false; break; case LT: result = (r1 < r2)?true : false; break; case LE: result = (r1 <= r2)?true : false; break; case GT: result = (r1 > r2)?true : false; break; case GE: result = (r1 >= r2)?true : false; break; default: if(CHECK_PROOFS) { CHECK_SOUND(false, "ArithTheoremProducer::constPredicate: wrong kind"); } break; } Expr ret = (result) ? d_em->trueExpr() : d_em->falseExpr(); if(withProof()) pf = newPf("const_predicate", e,ret); return newRWTheorem(e, ret, Assumptions::emptyAssump(), pf); } // e[0] kind e[1] <==> 0 kind e[1] - e[0] Theorem ArithTheoremProducer::rightMinusLeft(const Expr& e) { Proof pf; int kind = e.getKind(); if(CHECK_PROOFS) { CHECK_SOUND((EQ==kind) || (LT==kind) || (LE==kind) || (GE==kind) || (GT==kind), "ArithTheoremProduder::rightMinusLeft: wrong kind"); } if(withProof()) pf = newPf("right_minus_left",e); return newRWTheorem(e, Expr(e.getOp(), rat(0), e[1] - e[0]), Assumptions::emptyAssump(), pf); } // e[0] kind e[1] <==> 0 kind e[1] - e[0] Theorem ArithTheoremProducer::leftMinusRight(const Expr& e) { Proof pf; int kind = e.getKind(); if(CHECK_PROOFS) { CHECK_SOUND((EQ==kind) || (LT==kind) || (LE==kind) || (GE==kind) || (GT==kind), "ArithTheoremProduder::rightMinusLeft: wrong kind"); } if(withProof()) pf = newPf("left_minus_right",e); return newRWTheorem(e, Expr(e.getOp(), e[0] - e[1], rat(0)), Assumptions::emptyAssump(), pf); } // x kind y <==> x + z kind y + z Theorem ArithTheoremProducer::plusPredicate(const Expr& x, const Expr& y, const Expr& z, int kind) { if(CHECK_PROOFS) { CHECK_SOUND((EQ==kind) || (LT==kind) || (LE==kind) || (GE==kind) || (GT==kind), "ArithTheoremProduder::plusPredicate: wrong kind"); } Proof pf; Expr left = Expr(kind, x, y); Expr right = Expr(kind, x + z, y + z); if(withProof()) pf = newPf("plus_predicate",left,right); return newRWTheorem(left, right, Assumptions::emptyAssump(), pf); } // x = y <==> x * z = y * z Theorem ArithTheoremProducer::multEqn(const Expr& x, const Expr& y, const Expr& z) { Proof pf; if(CHECK_PROOFS) CHECK_SOUND(z.isRational() && z.getRational() != 0, "ArithTheoremProducer::multEqn(): multiplying equation by 0"); if(withProof()) pf = newPf("mult_eqn", x, y, z); return newRWTheorem(x.eqExpr(y), (x * z).eqExpr(y * z), Assumptions::emptyAssump(), pf); } // x = y <==> z=0 OR x * 1/z = y * 1/z Theorem ArithTheoremProducer::divideEqnNonConst(const Expr& x, const Expr& y, const Expr& z) { Proof pf; if(withProof()) pf = newPf("mult_eqn_nonconst", x, y, z); return newRWTheorem(x.eqExpr(y), (z.eqExpr(rat(0))).orExpr((x / z).eqExpr(y / z)), Assumptions::emptyAssump(), pf); } // if z is +ve, return e[0] LT|LE|GT|GE e[1] <==> e[0]*z LT|LE|GT|GE e[1]*z // if z is -ve, return e[0] LT|LE|GT|GE e[1] <==> e[1]*z LT|LE|GT|GE e[0]*z Theorem ArithTheoremProducer::multIneqn(const Expr& e, const Expr& z) { // Check the proofs in necessary if(CHECK_PROOFS) { CHECK_SOUND(isIneq(e), "ArithTheoremProduder::multIneqn: wrong kind"); CHECK_SOUND(z.isRational() && z.getRational() != 0, "ArithTheoremProduder::multIneqn: z must be non-zero rational: " + z.toString()); } // Operation of the expression Op op(e.getOp()); // Calculate the returning expression Expr ret; // If constant is positive, just multiply both sides if(0 < z.getRational()) ret = Expr(op, e[0]*z, e[1]*z); else // The constant is negative, reverse the relation switch (e.getKind()) { case LE: ret = geExpr(e[0]*z, e[1]*z); break; case LT: ret = gtExpr(e[0]*z, e[1]*z); break; case GE: ret = leExpr(e[0]*z, e[1]*z); break; case GT: ret = ltExpr(e[0]*z, e[1]*z); break; default: //TODO: exception, we shouldn't be here break; } // If we need the proof, set it up Proof pf; if(withProof()) pf = newPf("mult_ineqn", e, ret); // Return the explaining rewrite theorem return newRWTheorem(e, ret, Assumptions::emptyAssump(), pf); } //// multiply a canonised expression e = e[0] @ 0 with a constant c //Theorem ArithTheoremProducer::multConst(const Expr& e, const Rational c) //{ // // The proof object // Proof pf; // // // The resulting expression // Expr ret; // // // If expression is just a rational multiply it and thats it // if (e[0].isRational()) // ret = rat(e[0].getRational() * c); // // The expression is a canonised sum, multiply each one // else { // // Vector to hold all the sum children // vector sumKids; // // // Put all the sum children to the sumKids vector // for(Expression::iterator m = e[0].begin(); m != e[0].end(); m ++) { // // The current term in the sum // const Expr& sumTerm = (*m); // // // If the child is rational, just multiply it // if (sumTerm.isRational()) sumKids.push_back(rat(sumTerm.getRational() * c)); // // Otherwise multiply the coefficient with c and add it to the sumKids (TODO: Is the multiplication binary???) // else sumKids.pushBack(multExpr(rat(c * sumTerm[0].getRational()), sumTerm[1])); // } // // // The resulting expression is the sum of the sumKids // ret = plusExpr(sumKids); // } // // // If proof is needed set it up // if(withProof()) pf = newPf("arith_mult_const", e, ret); // // // Return the theorem explaining the multiplication // return newRWTheorem(e, ret, Assumptions::emptyAssump(), pf); //} // "op1 GE|GT op2" <==> op2 LE|LT op1 Theorem ArithTheoremProducer::flipInequality(const Expr& e) { Proof pf; if(CHECK_PROOFS) { CHECK_SOUND(isGT(e) || isGE(e), "ArithTheoremProducer::flipInequality: wrong kind: " + e.toString()); } int kind = isGE(e) ? LE : LT; Expr ret = Expr(kind, e[1], e[0]); if(withProof()) pf = newPf("flip_inequality", e,ret); return newRWTheorem(e,ret, Assumptions::emptyAssump(), pf); } // NOT (op1 LT op2) <==> (op1 GE op2) // NOT (op1 LE op2) <==> (op1 GT op2) // NOT (op1 GT op2) <==> (op1 LE op2) // NOT (op1 GE op2) <==> (op1 LT op2) Theorem ArithTheoremProducer::negatedInequality(const Expr& e) { const Expr& ineq = e[0]; if(CHECK_PROOFS) { CHECK_SOUND(e.isNot(), "ArithTheoremProducer::negatedInequality: wrong kind: " + e.toString()); CHECK_SOUND(isIneq(ineq), "ArithTheoremProducer::negatedInequality: wrong kind: " + (ineq).toString()); } Proof pf; if(withProof()) pf = newPf("negated_inequality", e); int kind; // NOT (op1 LT op2) <==> (op1 GE op2) // NOT (op1 LE op2) <==> (op1 GT op2) // NOT (op1 GT op2) <==> (op1 LE op2) // NOT (op1 GE op2) <==> (op1 LT op2) kind = isLT(ineq) ? GE : isLE(ineq) ? GT : isGT(ineq) ? LE : LT; return newRWTheorem(e, Expr(kind, ineq[0], ineq[1]), Assumptions::emptyAssump(), pf); } //takes two ineqs "|- alpha LT|LE t" and "|- t LT|LE beta" //and returns "|- alpha LT|LE beta" Theorem ArithTheoremProducer::realShadow(const Theorem& alphaLTt, const Theorem& tLTbeta) { const Expr& expr1 = alphaLTt.getExpr(); const Expr& expr2 = tLTbeta.getExpr(); if(CHECK_PROOFS) { CHECK_SOUND((isLE(expr1) || isLT(expr1)) && (isLE(expr2) || isLT(expr2)), "ArithTheoremProducer::realShadow: Wrong Kind: " + alphaLTt.toString() + tLTbeta.toString()); CHECK_SOUND(expr1[1] == expr2[0], "ArithTheoremProducer::realShadow:" " t must be same for both inputs: " + expr1[1].toString() + " , " + expr2[0].toString()); } Assumptions a(alphaLTt, tLTbeta); int firstKind = expr1.getKind(); int secondKind = expr2.getKind(); int kind = (firstKind == secondKind) ? firstKind : LT; Proof pf; if(withProof()) { vector pfs; pfs.push_back(alphaLTt.getProof()); pfs.push_back(tLTbeta.getProof()); pf = newPf("real_shadow",expr1, expr2, pfs); } return newTheorem(Expr(kind, expr1[0], expr2[1]), a, pf); } //! alpha <= t <= alpha ==> t = alpha /*! takes two ineqs "|- alpha LE t" and "|- t LE alpha" and returns "|- t = alpha" */ Theorem ArithTheoremProducer::realShadowEq(const Theorem& alphaLEt, const Theorem& tLEalpha) { const Expr& expr1 = alphaLEt.getExpr(); const Expr& expr2 = tLEalpha.getExpr(); if(CHECK_PROOFS) { CHECK_SOUND(isLE(expr1) && isLE(expr2), "ArithTheoremProducer::realShadowLTLE: Wrong Kind: " + alphaLEt.toString() + tLEalpha.toString()); CHECK_SOUND(expr1[1] == expr2[0], "ArithTheoremProducer::realShadowLTLE:" " t must be same for both inputs: " + alphaLEt.toString() + " , " + tLEalpha.toString()); CHECK_SOUND(expr1[0] == expr2[1], "ArithTheoremProducer::realShadowLTLE:" " alpha must be same for both inputs: " + alphaLEt.toString() + " , " + tLEalpha.toString()); } Assumptions a(alphaLEt, tLEalpha); Proof pf; if(withProof()) { vector pfs; pfs.push_back(alphaLEt.getProof()); pfs.push_back(tLEalpha.getProof()); pf = newPf("real_shadow_eq", alphaLEt.getExpr(), tLEalpha.getExpr(), pfs); } return newRWTheorem(expr1[0], expr1[1], a, pf); } Theorem ArithTheoremProducer::finiteInterval(const Theorem& aLEt, const Theorem& tLEac, const Theorem& isInta, const Theorem& isIntt) { const Expr& e1 = aLEt.getExpr(); const Expr& e2 = tLEac.getExpr(); if(CHECK_PROOFS) { CHECK_SOUND(isLE(e1) && isLE(e2), "ArithTheoremProducer::finiteInterval:\n e1 = " +e1.toString()+"\n e2 = "+e2.toString()); // term 't' is the same in both inequalities CHECK_SOUND(e1[1] == e2[0], "ArithTheoremProducer::finiteInterval:\n e1 = " +e1.toString()+"\n e2 = "+e2.toString()); // RHS in e2 is (a+c) CHECK_SOUND(isPlus(e2[1]) && e2[1].arity() == 2, "ArithTheoremProducer::finiteInterval:\n e1 = " +e1.toString()+"\n e2 = "+e2.toString()); // term 'a' in LHS of e1 and RHS of e2 is the same CHECK_SOUND(e1[0] == e2[1][0], "ArithTheoremProducer::finiteInterval:\n e1 = " +e1.toString()+"\n e2 = "+e2.toString()); // 'c' in the RHS of e2 is a positive integer constant CHECK_SOUND(e2[1][1].isRational() && e2[1][1].getRational().isInteger() && e2[1][1].getRational() >= 1, "ArithTheoremProducer::finiteInterval:\n e1 = " +e1.toString()+"\n e2 = "+e2.toString()); // Integrality constraints const Expr& isIntaExpr = isInta.getExpr(); const Expr& isInttExpr = isIntt.getExpr(); CHECK_SOUND(isIntPred(isIntaExpr) && isIntaExpr[0] == e1[0], "Wrong integrality constraint:\n e1 = " +e1.toString()+"\n isInta = "+isIntaExpr.toString()); CHECK_SOUND(isIntPred(isInttExpr) && isInttExpr[0] == e1[1], "Wrong integrality constraint:\n e1 = " +e1.toString()+"\n isIntt = "+isInttExpr.toString()); } vector thms; thms.push_back(aLEt); thms.push_back(tLEac); thms.push_back(isInta); thms.push_back(isIntt); Assumptions a(thms); Proof pf; if(withProof()) { vector es; vector pfs; es.push_back(e1); es.push_back(e2); es.push_back(isInta.getExpr()); es.push_back(isIntt.getExpr()); pfs.push_back(aLEt.getProof()); pfs.push_back(tLEac.getProof()); pfs.push_back(isInta.getProof()); pfs.push_back(isIntt.getProof()); pf = newPf("finite_interval", es, pfs); } // Construct GRAY_SHADOW(t, a, 0, c) Expr g(grayShadow(e1[1], e1[0], 0, e2[1][1].getRational())); return newTheorem(g, a, pf); } // Dark & Gray shadows when a <= b Theorem ArithTheoremProducer::darkGrayShadow2ab(const Theorem& betaLEbx, const Theorem& axLEalpha, const Theorem& isIntAlpha, const Theorem& isIntBeta, const Theorem& isIntx) { const Expr& expr1 = betaLEbx.getExpr(); const Expr& expr2 = axLEalpha.getExpr(); const Expr& isIntAlphaExpr = isIntAlpha.getExpr(); const Expr& isIntBetaExpr = isIntBeta.getExpr(); const Expr& isIntxExpr = isIntx.getExpr(); if(CHECK_PROOFS) { CHECK_SOUND(isLE(expr1) && isLE(expr2), "ArithTheoremProducer::darkGrayShadow2ab: Wrong Kind: " + betaLEbx.toString() + axLEalpha.toString()); } const Expr& beta = expr1[0]; const Expr& bx = expr1[1]; const Expr& ax = expr2[0]; const Expr& alpha = expr2[1]; Rational a = isMult(ax)? ax[0].getRational() : 1; Rational b = isMult(bx)? bx[0].getRational() : 1; const Expr& x = isMult(ax)? ax[1] : ax; if(CHECK_PROOFS) { // Integrality constraints CHECK_SOUND(isIntPred(isIntAlphaExpr) && isIntAlphaExpr[0] == alpha, "ArithTheoremProducer::darkGrayShadow2ab:\n " "wrong integrality constraint:\n alpha = " +alpha.toString()+"\n isIntAlpha = " +isIntAlphaExpr.toString()); CHECK_SOUND(isIntPred(isIntBetaExpr) && isIntBetaExpr[0] == beta, "ArithTheoremProducer::darkGrayShadow2ab:\n " "wrong integrality constraint:\n beta = " +beta.toString()+"\n isIntBeta = " +isIntBetaExpr.toString()); CHECK_SOUND(isIntPred(isIntxExpr) && isIntxExpr[0] == x, "ArithTheoremProducer::darkGrayShadow2ab:\n " "wrong integrality constraint:\n x = " +x.toString()+"\n isIntx = " +isIntxExpr.toString()); // Expressions ax and bx should match on x CHECK_SOUND(!isMult(ax) || ax.arity() == 2, "ArithTheoremProducer::darkGrayShadow2ab:\n ax<=alpha: " + axLEalpha.toString()); CHECK_SOUND(!isMult(bx) || (bx.arity() == 2 && bx[1] == x), "ArithTheoremProducer::darkGrayShadow2ab:\n beta<=bx: " +betaLEbx.toString() +"\n ax<=alpha: "+ axLEalpha.toString()); CHECK_SOUND(1 <= a && a <= b && 2 <= b, "ArithTheoremProducer::darkGrayShadow2ab:\n beta<=bx: " +betaLEbx.toString() +"\n ax<=alpha: "+ axLEalpha.toString()); } vector thms; thms.push_back(betaLEbx); thms.push_back(axLEalpha); thms.push_back(isIntAlpha); thms.push_back(isIntBeta); thms.push_back(isIntx); Assumptions A(thms); Expr bAlpha = multExpr(rat(b), alpha); Expr aBeta = multExpr(rat(a), beta); Expr t = minusExpr(bAlpha, aBeta); Expr d = darkShadow(rat(a*b-1), t); Expr g = grayShadow(ax, alpha, -a+1, 0); Proof pf; if(withProof()) { vector exprs; exprs.push_back(expr1); exprs.push_back(expr2); exprs.push_back(d); exprs.push_back(g); vector pfs; pfs.push_back(betaLEbx.getProof()); pfs.push_back(axLEalpha.getProof()); pfs.push_back(isIntAlpha.getProof()); pfs.push_back(isIntBeta.getProof()); pfs.push_back(isIntx.getProof()); pf = newPf("dark_grayshadow_2ab", exprs, pfs); } return newTheorem((d || g) && (!d || !g), A, pf); } // Dark & Gray shadows when b <= a Theorem ArithTheoremProducer::darkGrayShadow2ba(const Theorem& betaLEbx, const Theorem& axLEalpha, const Theorem& isIntAlpha, const Theorem& isIntBeta, const Theorem& isIntx) { const Expr& expr1 = betaLEbx.getExpr(); const Expr& expr2 = axLEalpha.getExpr(); const Expr& isIntAlphaExpr = isIntAlpha.getExpr(); const Expr& isIntBetaExpr = isIntBeta.getExpr(); const Expr& isIntxExpr = isIntx.getExpr(); if(CHECK_PROOFS) { CHECK_SOUND(isLE(expr1) && isLE(expr2), "ArithTheoremProducer::darkGrayShadow2ba: Wrong Kind: " + betaLEbx.toString() + axLEalpha.toString()); } const Expr& beta = expr1[0]; const Expr& bx = expr1[1]; const Expr& ax = expr2[0]; const Expr& alpha = expr2[1]; Rational a = isMult(ax)? ax[0].getRational() : 1; Rational b = isMult(bx)? bx[0].getRational() : 1; const Expr& x = isMult(ax)? ax[1] : ax; if(CHECK_PROOFS) { // Integrality constraints CHECK_SOUND(isIntPred(isIntAlphaExpr) && isIntAlphaExpr[0] == alpha, "ArithTheoremProducer::darkGrayShadow2ab:\n " "wrong integrality constraint:\n alpha = " +alpha.toString()+"\n isIntAlpha = " +isIntAlphaExpr.toString()); CHECK_SOUND(isIntPred(isIntBetaExpr) && isIntBetaExpr[0] == beta, "ArithTheoremProducer::darkGrayShadow2ab:\n " "wrong integrality constraint:\n beta = " +beta.toString()+"\n isIntBeta = " +isIntBetaExpr.toString()); CHECK_SOUND(isIntPred(isIntxExpr) && isIntxExpr[0] == x, "ArithTheoremProducer::darkGrayShadow2ab:\n " "wrong integrality constraint:\n x = " +x.toString()+"\n isIntx = " +isIntxExpr.toString()); // Expressions ax and bx should match on x CHECK_SOUND(!isMult(ax) || ax.arity() == 2, "ArithTheoremProducer::darkGrayShadow2ba:\n ax<=alpha: " + axLEalpha.toString()); CHECK_SOUND(!isMult(bx) || (bx.arity() == 2 && bx[1] == x), "ArithTheoremProducer::darkGrayShadow2ba:\n beta<=bx: " +betaLEbx.toString() +"\n ax<=alpha: "+ axLEalpha.toString()); CHECK_SOUND(1 <= b && b <= a && 2 <= a, "ArithTheoremProducer::darkGrayShadow2ba:\n beta<=bx: " +betaLEbx.toString() +"\n ax<=alpha: "+ axLEalpha.toString()); } vector thms; thms.push_back(betaLEbx); thms.push_back(axLEalpha); thms.push_back(isIntAlpha); thms.push_back(isIntBeta); thms.push_back(isIntx); Assumptions A(thms); Proof pf; if(withProof()) { vector pfs; pfs.push_back(betaLEbx.getProof()); pfs.push_back(axLEalpha.getProof()); pfs.push_back(isIntAlpha.getProof()); pfs.push_back(isIntBeta.getProof()); pfs.push_back(isIntx.getProof()); pf = newPf("dark_grayshadow_2ba", betaLEbx.getExpr(), axLEalpha.getExpr(), pfs); } Expr bAlpha = multExpr(rat(b), alpha); Expr aBeta = multExpr(rat(a), beta); Expr t = minusExpr(bAlpha, aBeta); Expr d = darkShadow(rat(a*b-1), t); Expr g = grayShadow(bx, beta, 0, b-1); return newTheorem((d || g) && (!d || !g), A, pf); } /*! takes a dark shadow and expands it into an inequality. */ Theorem ArithTheoremProducer::expandDarkShadow(const Theorem& darkShadow) { const Expr& theShadow = darkShadow.getExpr(); if(CHECK_PROOFS){ CHECK_SOUND(isDarkShadow(theShadow), "ArithTheoremProducer::expandDarkShadow: not DARK_SHADOW: " + theShadow.toString()); } Proof pf; if(withProof()) pf = newPf("expand_dark_shadow", theShadow, darkShadow.getProof()); return newTheorem(leExpr(theShadow[0], theShadow[1]), darkShadow.getAssumptionsRef(), pf); } // takes a grayShadow (c1==c2) and expands it into an equality Theorem ArithTheoremProducer::expandGrayShadow0(const Theorem& grayShadow) { const Expr& theShadow = grayShadow.getExpr(); if(CHECK_PROOFS) { CHECK_SOUND(isGrayShadow(theShadow), "ArithTheoremProducer::expandGrayShadowConst0:" " not GRAY_SHADOW: " + theShadow.toString()); CHECK_SOUND(theShadow[2] == theShadow[3], "ArithTheoremProducer::expandGrayShadow0: c1!=c2: " + theShadow.toString()); } Proof pf; if(withProof()) pf = newPf("expand_gray_shadowconst0", theShadow, grayShadow.getProof()); const Expr& v = theShadow[0]; const Expr& e = theShadow[1]; return newRWTheorem(v, e + theShadow[2], grayShadow.getAssumptionsRef(), pf); } // G ==> (G1 or G2) and (!G1 or !G2), // where G = G(x, e, c1, c2), // G1 = G(x,e,c1,c) // G2 = G(x,e,c+1,c2), // and c = floor((c1+c2)/2) Theorem ArithTheoremProducer::splitGrayShadow(const Theorem& gThm) { const Expr& theShadow = gThm.getExpr(); if(CHECK_PROOFS) { CHECK_SOUND(isGrayShadow(theShadow), "ArithTheoremProducer::expandGrayShadowConst: not a shadow" + theShadow.toString()); } const Rational& c1 = theShadow[2].getRational(); const Rational& c2 = theShadow[3].getRational(); if(CHECK_PROOFS) { CHECK_SOUND(c1.isInteger() && c2.isInteger() && c1 < c2, "ArithTheoremProducer::expandGrayShadow: " + theShadow.toString()); } const Expr& v = theShadow[0]; const Expr& e = theShadow[1]; Proof pf; Rational c(floor((c1+c2) / 2)); Expr g1(grayShadow(v, e, c1, c)); Expr g2(grayShadow(v, e, c+1, c2)); if(withProof()){ vector exprs; exprs.push_back(theShadow); exprs.push_back(g1); exprs.push_back(g2); pf = newPf("split_gray_shadow", exprs, gThm.getProof()); } return newTheorem((g1 || g2) && (!g1 || !g2), gThm.getAssumptionsRef(), pf); } Theorem ArithTheoremProducer::expandGrayShadow(const Theorem& gThm) { const Expr& theShadow = gThm.getExpr(); if(CHECK_PROOFS) { CHECK_SOUND(isGrayShadow(theShadow), "ArithTheoremProducer::expandGrayShadowConst: not a shadow" + theShadow.toString()); } const Rational& c1 = theShadow[2].getRational(); const Rational& c2 = theShadow[3].getRational(); if(CHECK_PROOFS) { CHECK_SOUND(c1.isInteger() && c2.isInteger() && c1 < c2, "ArithTheoremProducer::expandGrayShadow: " + theShadow.toString()); } const Expr& v = theShadow[0]; const Expr& e = theShadow[1]; Proof pf; if(withProof()) pf = newPf("expand_gray_shadow", theShadow, gThm.getProof()); Expr ineq1(leExpr(e+rat(c1), v)); Expr ineq2(leExpr(v, e+rat(c2))); return newTheorem(ineq1 && ineq2, gThm.getAssumptionsRef(), pf); } // Expanding GRAY_SHADOW(a*x, c, b), where c is a constant Theorem ArithTheoremProducer::expandGrayShadowConst(const Theorem& gThm) { const Expr& theShadow = gThm.getExpr(); const Expr& ax = theShadow[0]; const Expr& cExpr = theShadow[1]; const Expr& bExpr = theShadow[2]; if(CHECK_PROOFS) { CHECK_SOUND(!isMult(ax) || ax[0].isRational(), "ArithTheoremProducer::expandGrayShadowConst: " "'a' in a*x is not a const: " +theShadow.toString()); } Rational a = isMult(ax)? ax[0].getRational() : 1; if(CHECK_PROOFS) { CHECK_SOUND(isGrayShadow(theShadow), "ArithTheoremProducer::expandGrayShadowConst: " "not a GRAY_SHADOW: " +theShadow.toString()); CHECK_SOUND(a.isInteger() && a >= 1, "ArithTheoremProducer::expandGrayShadowConst: " "'a' is not integer: " +theShadow.toString()); CHECK_SOUND(cExpr.isRational(), "ArithTheoremProducer::expandGrayShadowConst: " "'c' is not rational" +theShadow.toString()); CHECK_SOUND(bExpr.isRational() && bExpr.getRational().isInteger(), "ArithTheoremProducer::expandGrayShadowConst: b not integer: " +theShadow.toString()); } const Rational& b = bExpr.getRational(); const Rational& c = cExpr.getRational(); Rational j = constRHSGrayShadow(c,b,a); // Compute sign(b)*j(c,b,a) Rational signB = (b>0)? 1 : -1; // |b| (absolute value of b) Rational bAbs = abs(b); const Assumptions& assump(gThm.getAssumptionsRef()); Proof pf; Theorem conc; // Conclusion of the rule if(bAbs < j) { if(withProof()) pf = newPf("expand_gray_shadow_const_0", theShadow, gThm.getProof()); conc = newTheorem(d_em->falseExpr(), assump, pf); } else if(bAbs < a+j) { if(withProof()) pf = newPf("expand_gray_shadow_const_1", theShadow, gThm.getProof()); conc = newRWTheorem(ax, rat(c+b-signB*j), assump, pf); } else { if(withProof()) pf = newPf("expand_gray_shadow_const", theShadow, gThm.getProof()); Expr newGrayShadow(Expr(GRAY_SHADOW, ax, cExpr, rat(b-signB*(a+j)))); conc = newTheorem(ax.eqExpr(rat(c+b-signB*j)).orExpr(newGrayShadow), assump, pf); } return conc; } Theorem ArithTheoremProducer::grayShadowConst(const Theorem& gThm) { const Expr& g = gThm.getExpr(); bool checkProofs(CHECK_PROOFS); if(checkProofs) { CHECK_SOUND(isGrayShadow(g), "ArithTheoremProducer::grayShadowConst(" +g.toString()+")"); } const Expr& ax = g[0]; const Expr& e = g[1]; const Rational& c1 = g[2].getRational(); const Rational& c2 = g[3].getRational(); Expr aExpr, x; d_theoryArith->separateMonomial(ax, aExpr, x); if(checkProofs) { CHECK_SOUND(e.isRational() && e.getRational().isInteger(), "ArithTheoremProducer::grayShadowConst("+g.toString()+")"); CHECK_SOUND(aExpr.isRational(), "ArithTheoremProducer::grayShadowConst("+g.toString()+")"); } const Rational& a = aExpr.getRational(); const Rational& c = e.getRational(); if(checkProofs) { CHECK_SOUND(a.isInteger() && a >= 2, "ArithTheoremProducer::grayShadowConst("+g.toString()+")"); } Rational newC1 = ceil((c1+c)/a), newC2 = floor((c2+c)/a); Expr newG((newC1 > newC2)? d_em->falseExpr() : grayShadow(x, rat(0), newC1, newC2)); Proof pf; if(withProof()) pf = newPf("gray_shadow_const", g, newG, gThm.getProof()); return newTheorem(newG, gThm.getAssumptionsRef(), pf); } Rational ArithTheoremProducer::constRHSGrayShadow(const Rational& c, const Rational& b, const Rational& a) { DebugAssert(c.isInteger() && b.isInteger() && a.isInteger() && b != 0, "ArithTheoremProducer::constRHSGrayShadow: a, b, c must be ints"); if (b > 0) return mod(c+b, a); else return mod(a-(c+b), a); } /*! Takes a Theorem(\\alpha < \\beta) and returns * Theorem(\\alpha < \\beta <==> \\alpha <= \\beta -1) * where \\alpha and \\beta are integer expressions */ Theorem ArithTheoremProducer::lessThanToLE(const Theorem& less, const Theorem& isIntLHS, const Theorem& isIntRHS, bool changeRight) { const Expr& ineq = less.getExpr(); const Expr& isIntLHSexpr = isIntLHS.getExpr(); const Expr& isIntRHSexpr = isIntRHS.getExpr(); if(CHECK_PROOFS) { CHECK_SOUND(isLT(ineq), "ArithTheoremProducer::LTtoLE: ineq must be <"); // Integrality check CHECK_SOUND(isIntPred(isIntLHSexpr) && isIntLHSexpr[0] == ineq[0], "ArithTheoremProducer::lessThanToLE: bad integrality check:\n" " ineq = "+ineq.toString()+"\n isIntLHS = " +isIntLHSexpr.toString()); CHECK_SOUND(isIntPred(isIntRHSexpr) && isIntRHSexpr[0] == ineq[1], "ArithTheoremProducer::lessThanToLE: bad integrality check:\n" " ineq = "+ineq.toString()+"\n isIntRHS = " +isIntRHSexpr.toString()); } vector thms; thms.push_back(less); thms.push_back(isIntLHS); thms.push_back(isIntRHS); Assumptions a(thms); Proof pf; Expr le = changeRight? leExpr(ineq[0], ineq[1] + rat(-1)) : leExpr(ineq[0] + rat(1), ineq[1]); if(withProof()) { vector pfs; pfs.push_back(less.getProof()); pfs.push_back(isIntLHS.getProof()); pfs.push_back(isIntRHS.getProof()); pf = newPf(changeRight? "lessThan_To_LE_rhs" : "lessThan_To_LE_lhs", ineq, le, pfs); } return newRWTheorem(ineq, le, a, pf); } /*! \param eqn is an equation 0 = a.x or 0 = c + a.x * \param isIntx is a proof of IS_INTEGER(x) * * \return the theorem 0 = c + a.x <==> x=-c/a if -c/a is int else * return the theorem 0 = c + a.x <==> false. * * It also handles the special case of 0 = a.x <==> x = 0 */ Theorem ArithTheoremProducer::intVarEqnConst(const Expr& eqn, const Theorem& isIntx) { const Expr& left(eqn[0]); const Expr& right(eqn[1]); const Expr& isIntxexpr(isIntx.getExpr()); if(CHECK_PROOFS) { CHECK_SOUND((isMult(right) && right[0].isRational()) || (right.arity() == 2 && isPlus(right) && right[0].isRational() && ((!isMult(right[1]) || right[1][0].isRational()))), "ArithTheoremProducer::intVarEqnConst: " "rhs has a wrong format: " + right.toString()); CHECK_SOUND(left.isRational() && 0 == left.getRational(), "ArithTheoremProducer:intVarEqnConst:left is not a zero: " + left.toString()); } // Integrality constraint Expr x(right); Rational a(1), c(0); if(isMult(right)) { Expr aExpr; d_theoryArith->separateMonomial(right, aExpr, x); a = aExpr.getRational(); } else { // right is a PLUS c = right[0].getRational(); Expr aExpr; d_theoryArith->separateMonomial(right[1], aExpr, x); a = aExpr.getRational(); } if(CHECK_PROOFS) { CHECK_SOUND(isIntPred(isIntxexpr) && isIntxexpr[0] == x, "ArithTheoremProducer:intVarEqnConst: " "bad integrality constraint:\n right = " + right.toString()+"\n isIntx = "+isIntxexpr.toString()); CHECK_SOUND(a!=0, "ArithTheoremProducer:intVarEqnConst: eqn = " +eqn.toString()); } const Assumptions& assump(isIntx.getAssumptionsRef()); Proof pf; if(withProof()) pf = newPf("int_const_eq", eqn, isIntx.getProof()); // Solve for x: x = r = -c/a Rational r(-c/a); if(r.isInteger()) return newRWTheorem(eqn, x.eqExpr(rat(r)), assump, pf); else return newRWTheorem(eqn, d_em->falseExpr(), assump, pf); } Expr ArithTheoremProducer::create_t(const Expr& eqn) { const Expr& lhs = eqn[0]; DebugAssert(isMult(lhs), CLASS_NAME "create_t : lhs must be a MULT" + lhs.toString()); const Expr& x = lhs[1]; Rational m = lhs[0].getRational()+1; DebugAssert(m > 0, "ArithTheoremProducer::create_t: m = "+m.toString()); vector kids; if(isPlus(eqn[1])) sumModM(kids, eqn[1], m, m); else kids.push_back(monomialModM(eqn[1], m, m)); kids.push_back(multExpr(rat(1/m), x)); return plusExpr(kids); } Expr ArithTheoremProducer::create_t2(const Expr& lhs, const Expr& rhs, const Expr& sigma) { Rational m = lhs[0].getRational()+1; DebugAssert(m > 0, "ArithTheoremProducer::create_t2: m = "+m.toString()); vector kids; if(isPlus(rhs)) sumModM(kids, rhs, m, -1); else { kids.push_back(rat(0)); // For canonical form Expr monom = monomialModM(rhs, m, -1); if(!monom.isRational()) kids.push_back(monom); else DebugAssert(monom.getRational() == 0, ""); } kids.push_back(rat(m)*sigma); return plusExpr(kids); } Expr ArithTheoremProducer::create_t3(const Expr& lhs, const Expr& rhs, const Expr& sigma) { const Rational& a = lhs[0].getRational(); Rational m = a+1; DebugAssert(m > 0, "ArithTheoremProducer::create_t3: m = "+m.toString()); vector kids; if(isPlus(rhs)) sumMulF(kids, rhs, m, 1); else { kids.push_back(rat(0)); // For canonical form Expr monom = monomialMulF(rhs, m, 1); if(!monom.isRational()) kids.push_back(monom); else DebugAssert(monom.getRational() == 0, ""); } kids.push_back(rat(-a)*sigma); return plusExpr(kids); } Rational ArithTheoremProducer::modEq(const Rational& i, const Rational& m) { DebugAssert(m > 0, "ArithTheoremProducer::modEq: m = "+m.toString()); Rational half(1,2); Rational res((i - m*(floor((i/m) + half)))); TRACE("arith eq", "modEq("+i.toString()+", "+m.toString()+") = ", res, ""); return res; } Rational ArithTheoremProducer::f(const Rational& i, const Rational& m) { DebugAssert(m > 0, "ArithTheoremProducer::f: m = "+m.toString()); Rational half(1,2); return (floor(i/m + half)+modEq(i,m)); } void ArithTheoremProducer::sumModM(vector& summands, const Expr& sum, const Rational& m, const Rational& divisor) { DebugAssert(divisor != 0, "ArithTheoremProducer::sumModM: divisor = " +divisor.toString()); Expr::iterator i = sum.begin(); DebugAssert(i != sum.end(), CLASS_NAME "::sumModM"); Rational C = i->getRational(); C = modEq(C,m)/divisor; summands.push_back(rat(C)); i++; for(Expr::iterator iend=sum.end(); i!=iend; ++i) { Expr monom = monomialModM(*i, m, divisor); if(!monom.isRational()) summands.push_back(monom); else DebugAssert(monom.getRational() == 0, ""); } } Expr ArithTheoremProducer::monomialModM(const Expr& i, const Rational& m, const Rational& divisor) { DebugAssert(divisor != 0, "ArithTheoremProducer::monomialModM: divisor = " +divisor.toString()); Expr res; if(isMult(i)) { Rational ai = i[0].getRational(); ai = modEq(ai,m)/divisor; if(0 == ai) res = rat(0); else if(1 == ai && i.arity() == 2) res = i[1]; else { vector kids = i.getKids(); kids[0] = rat(ai); res = multExpr(kids); } } else { // It's a single variable Rational ai = modEq(1,m)/divisor; if(1 == ai) res = i; else res = rat(ai)*i; } DebugAssert(!res.isNull(), "ArithTheoremProducer::monomialModM()"); TRACE("arith eq", "monomialModM(i="+i.toString()+", m="+m.toString() +", div="+divisor.toString()+") = ", res, ""); return res; } void ArithTheoremProducer::sumMulF(vector& summands, const Expr& sum, const Rational& m, const Rational& divisor) { DebugAssert(divisor != 0, "ArithTheoremProducer::sumMulF: divisor = " +divisor.toString()); Expr::iterator i = sum.begin(); DebugAssert(i != sum.end(), CLASS_NAME "::sumModM"); Rational C = i->getRational(); C = f(C,m)/divisor; summands.push_back(rat(C)); i++; for(Expr::iterator iend=sum.end(); i!=iend; ++i) { Expr monom = monomialMulF(*i, m, divisor); if(!monom.isRational()) summands.push_back(monom); else DebugAssert(monom.getRational() == 0, ""); } } Expr ArithTheoremProducer::monomialMulF(const Expr& i, const Rational& m, const Rational& divisor) { DebugAssert(divisor != 0, "ArithTheoremProducer::monomialMulF: divisor = " +divisor.toString()); Rational ai = isMult(i) ? (i)[0].getRational() : 1; Expr xi = isMult(i) ? (i)[1] : (i); ai = f(ai,m)/divisor; if(0 == ai) return rat(0); if(1 == ai) return xi; return multExpr(rat(ai), xi); } // This recursive function accepts a term, t, and a 'map' of // substitutions [x1/t1, x2/t2,...,xn/tn]. it returns a t' which is // basically t[x1/t1,x2/t2...xn/tn] Expr ArithTheoremProducer::substitute(const Expr& term, ExprMap& eMap) { ExprMap::iterator i, iend = eMap.end(); i = eMap.find(term); if(iend != i) return (*i).second; if (isMult(term)) { //in this case term is of the form c.x i = eMap.find(term[1]); if(iend != i) return term[0]*(*i).second; else return term; } if(isPlus(term)) { vector output; for(Expr::iterator j = term.begin(), jend = term.end(); j != jend; ++j) output.push_back(substitute(*j, eMap)); return plusExpr(output); } return term; } bool ArithTheoremProducer::greaterthan(const Expr & l, const Expr & r) { // DebugAssert(l != r, ""); if (l==r) return false; switch(l.getKind()) { case RATIONAL_EXPR: DebugAssert(!r.isRational(), ""); return true; break; case POW: switch (r.getKind()) { case RATIONAL_EXPR: // TODO: // alternately I could return (not greaterthan(r,l)) return false; break; case POW: // x^n > y^n if x > y // x^n1 > x^n2 if n1 > n2 return ((r[1] < l[1]) || ((r[1]==l[1]) && (r[0].getRational() < l[0].getRational()))); break; case MULT: DebugAssert(r.arity() > 1, ""); DebugAssert((r.arity() > 2) || (r[1] != l), ""); if (r[1] == l) return false; return greaterthan(l, r[1]); break; case PLUS: DebugAssert(false, ""); return true; break; default: // leaf return ((r < l[1]) || ((r == l[1]) && l[0].getRational() > 1)); break; } break; case MULT: DebugAssert(l.arity() > 1, ""); switch (r.getKind()) { case RATIONAL_EXPR: return false; break; case POW: DebugAssert(l.arity() > 1, ""); DebugAssert((l.arity() > 2) || (l[1] != r), ""); // TODO: // alternately return (not greaterthan(r,l) return ((l[1] == r) || greaterthan(l[1], r)); break; case MULT: { DebugAssert(r.arity() > 1, ""); Expr::iterator i = l.begin(); Expr::iterator j = r.begin(); ++i; ++j; for (; i != l.end() && j != r.end(); ++i, ++j) { if (*i == *j) continue; return greaterthan(*i,*j); } DebugAssert(i != l.end() || j != r.end(), ""); if (i == l.end()) { // r is bigger return false; } else { // l is bigger return true; } } break; case PLUS: DebugAssert(false, ""); return true; break; default: // leaf DebugAssert((l.arity() > 2) || (l[1] != r), ""); return ((l[1] == r) || greaterthan(l[1], r)); break; } break; case PLUS: DebugAssert(false, ""); return true; break; default: // leaf switch (r.getKind()) { case RATIONAL_EXPR: return false; break; case POW: return ((r[1] < l) || ((r[1] == l) && (r[0].getRational() < 1))); break; case MULT: DebugAssert(r.arity() > 1, ""); DebugAssert((r.arity() > 2) || (r[1] != l), ""); if (l == r[1]) return false; return greaterthan(l,r[1]); break; case PLUS: DebugAssert(false, ""); return true; break; default: // leaf return (r < l); break; } break; } } /*! IS_INTEGER(x) |= EXISTS (y : INT) y = x * where x is not already known to be an integer. */ Theorem ArithTheoremProducer::IsIntegerElim(const Theorem& isIntx) { Expr expr = isIntx.getExpr(); if (CHECK_PROOFS) { CHECK_SOUND(expr.getKind() == IS_INTEGER, "Expected IS_INTEGER predicate"); } expr = expr[0]; DebugAssert(!d_theoryArith->isInteger(expr), "Expected non-integer"); Assumptions a(isIntx); Proof pf; if (withProof()) { pf = newPf("isIntElim", isIntx.getProof()); } Expr newVar = d_em->newBoundVarExpr(d_theoryArith->intType()); Expr res = d_em->newClosureExpr(EXISTS, newVar, newVar.eqExpr(expr)); return newTheorem(res, a, pf); } Theorem ArithTheoremProducer::eqElimIntRule(const Theorem& eqn, const Theorem& isIntx, const vector& isIntVars) { TRACE("arith eq", "eqElimIntRule(", eqn.getExpr(), ") {"); Proof pf; if(CHECK_PROOFS) CHECK_SOUND(eqn.isRewrite(), "ArithTheoremProducer::eqElimInt: input must be an equation" + eqn.toString()); const Expr& lhs = eqn.getLHS(); const Expr& rhs = eqn.getRHS(); Expr a, x; d_theoryArith->separateMonomial(lhs, a, x); if(CHECK_PROOFS) { // Checking LHS const Expr& isIntxe = isIntx.getExpr(); CHECK_SOUND(isIntPred(isIntxe) && isIntxe[0] == x, "ArithTheoremProducer::eqElimInt\n eqn = " +eqn.getExpr().toString() +"\n isIntx = "+isIntxe.toString()); CHECK_SOUND(isRational(a) && a.getRational().isInteger() && a.getRational() >= 2, "ArithTheoremProducer::eqElimInt:\n lhs = "+lhs.toString()); // Checking RHS // It cannot be a division (we don't handle it) CHECK_SOUND(!isDivide(rhs), "ArithTheoremProducer::eqElimInt:\n rhs = "+rhs.toString()); // If it's a single monomial, then it's the only "variable" if(!isPlus(rhs)) { Expr c, v; d_theoryArith->separateMonomial(rhs, c, v); CHECK_SOUND(isIntVars.size() == 1 && isIntPred(isIntVars[0].getExpr()) && isIntVars[0].getExpr()[0] == v && isRational(c) && c.getRational().isInteger(), "ArithTheoremProducer::eqElimInt:\n rhs = "+rhs.toString() +"isIntVars.size = "+int2string(isIntVars.size())); } else { // RHS is a plus CHECK_SOUND(isIntVars.size() + 1 == (size_t)rhs.arity(), "ArithTheoremProducer::eqElimInt: rhs = "+rhs.toString()); // Check the free constant CHECK_SOUND(isRational(rhs[0]) && rhs[0].getRational().isInteger(), "ArithTheoremProducer::eqElimInt: rhs = "+rhs.toString()); // Check the vars for(size_t i=0, iend=isIntVars.size(); iseparateMonomial(rhs[i+1], c, v); const Expr& isInt(isIntVars[i].getExpr()); CHECK_SOUND(isIntPred(isInt) && isInt[0] == v && isRational(c) && c.getRational().isInteger(), "ArithTheoremProducer::eqElimInt:\n rhs["+int2string(i+1) +"] = "+rhs[i+1].toString() +"\n isInt = "+isInt.toString()); } } } // Creating a fresh bound variable static int varCount(0); Expr newVar = d_em->newBoundVarExpr("_int_var", int2string(varCount++)); newVar.setType(intType()); Expr t2 = create_t2(lhs, rhs, newVar); Expr t3 = create_t3(lhs, rhs, newVar); vector vars; vars.push_back(newVar); Expr res = d_em->newClosureExpr(EXISTS, vars, x.eqExpr(t2) && rat(0).eqExpr(t3)); vector thms(isIntVars); thms.push_back(isIntx); thms.push_back(eqn); Assumptions assump(thms); if(withProof()) { vector pfs; pfs.push_back(eqn.getProof()); pfs.push_back(isIntx.getProof()); vector::const_iterator i=isIntVars.begin(), iend=isIntVars.end(); for(; i!=iend; ++i) pfs.push_back(i->getProof()); pf = newPf("eq_elim_int", eqn.getExpr(), res , pfs); } Theorem thm(newTheorem(res, assump, pf)); TRACE("arith eq", "eqElimIntRule => ", thm.getExpr(), " }"); return thm; } Theorem ArithTheoremProducer::isIntConst(const Expr& e) { Proof pf; if(CHECK_PROOFS) { CHECK_SOUND(isIntPred(e) && e[0].isRational(), "ArithTheoremProducer::isIntConst(e = " +e.toString()+")"); } if(withProof()) pf = newPf("is_int_const", e); bool isInt = e[0].getRational().isInteger(); return newRWTheorem(e, isInt? d_em->trueExpr() : d_em->falseExpr(), Assumptions::emptyAssump(), pf); } Theorem ArithTheoremProducer::equalLeaves1(const Theorem& thm) { Proof pf; const Expr& e = thm.getRHS(); if (CHECK_PROOFS) { CHECK_SOUND(e[1].getKind() == RATIONAL_EXPR && e[1].getRational() == Rational(0) && e[0].getKind() == PLUS && e[0].arity() == 3 && e[0][0].getKind() == RATIONAL_EXPR && e[0][0].getRational() == Rational(0) && e[0][1].getKind() == MULT && e[0][1].arity() == 2 && e[0][1][0].getKind() == RATIONAL_EXPR && e[0][1][0].getRational() == Rational(-1), "equalLeaves1"); } if (withProof()) { vector pfs; pfs.push_back(thm.getProof()); pf = newPf("equalLeaves1", e, pfs); } return newRWTheorem(e, e[0][1][1].eqExpr(e[0][2]), thm.getAssumptionsRef(), pf); } Theorem ArithTheoremProducer::equalLeaves2(const Theorem& thm) { Proof pf; const Expr& e = thm.getRHS(); if (CHECK_PROOFS) { CHECK_SOUND(e[0].getKind() == RATIONAL_EXPR && e[0].getRational() == Rational(0) && e[1].getKind() == PLUS && e[1].arity() == 3 && e[1][0].getKind() == RATIONAL_EXPR && e[1][0].getRational() == Rational(0) && e[1][1].getKind() == MULT && e[1][1].arity() == 2 && e[1][1][0].getKind() == RATIONAL_EXPR && e[1][1][0].getRational() == Rational(-1), "equalLeaves2"); } if (withProof()) { vector pfs; pfs.push_back(thm.getProof()); pf = newPf("equalLeaves2", e, pfs); } return newRWTheorem(e, e[1][1][1].eqExpr(e[1][2]), thm.getAssumptionsRef(), pf); } Theorem ArithTheoremProducer::equalLeaves3(const Theorem& thm) { Proof pf; const Expr& e = thm.getRHS(); if (CHECK_PROOFS) { CHECK_SOUND(e[1].getKind() == RATIONAL_EXPR && e[1].getRational() == Rational(0) && e[0].getKind() == PLUS && e[0].arity() == 3 && e[0][0].getKind() == RATIONAL_EXPR && e[0][0].getRational() == Rational(0) && e[0][2].getKind() == MULT && e[0][2].arity() == 2 && e[0][2][0].getKind() == RATIONAL_EXPR && e[0][2][0].getRational() == Rational(-1), "equalLeaves3"); } if (withProof()) { vector pfs; pfs.push_back(thm.getProof()); pf = newPf("equalLeaves3", e, pfs); } return newRWTheorem(e, e[0][2][1].eqExpr(e[0][1]), thm.getAssumptionsRef(), pf); } Theorem ArithTheoremProducer::equalLeaves4(const Theorem& thm) { Proof pf; const Expr& e = thm.getRHS(); if (CHECK_PROOFS) { CHECK_SOUND(e[0].getKind() == RATIONAL_EXPR && e[0].getRational() == Rational(0) && e[1].getKind() == PLUS && e[1].arity() == 3 && e[1][0].getKind() == RATIONAL_EXPR && e[1][0].getRational() == Rational(0) && e[1][2].getKind() == MULT && e[1][2].arity() == 2 && e[1][2][0].getKind() == RATIONAL_EXPR && e[1][2][0].getRational() == Rational(-1), "equalLeaves4"); } if (withProof()) { vector pfs; pfs.push_back(thm.getProof()); pf = newPf("equalLeaves4", e, pfs); } return newRWTheorem(e, e[1][2][1].eqExpr(e[1][1]), thm.getAssumptionsRef(), pf); } Theorem ArithTheoremProducer::diseqToIneq(const Theorem& diseq) { Proof pf; const Expr& e = diseq.getExpr(); if(CHECK_PROOFS) { CHECK_SOUND(e.isNot() && e[0].isEq(), "ArithTheoremProducer::diseqToIneq: expected disequality:\n" " e = "+e.toString()); } const Expr& x = e[0][0]; const Expr& y = e[0][1]; if(withProof()) pf = newPf(e, diseq.getProof()); return newTheorem(ltExpr(x,y).orExpr(gtExpr(x,y)), diseq.getAssumptionsRef(), pf); } Theorem ArithTheoremProducer::moveSumConstantRight(const Expr& e) { // Check soundness of the rule if necessary if (CHECK_PROOFS) { CHECK_SOUND(isIneq(e) || e.isEq(), "moveSumConstantRight: input must be Eq or Ineq: " + e.toString()); CHECK_SOUND(isRational(e[0]) || isPlus(e[0]), "moveSumConstantRight: left side must be a canonised sum: " + e.toString()); CHECK_SOUND(isRational(e[1]) && e[1].getRational() == 0, "moveSumConstantRight: right side must be 0: " + e.toString()); } // The rational constant of the sum Rational r = 0; // The right hand side of the expression Expr right = e[0]; // The vector of sum terms vector sumTerms; // Get all the non rational children and if (!right.isRational()) for(Expr::iterator it = right.begin(); it != right.end(); it ++) { // If the term is rational then add the rational number to r if ((*it).isRational()) r = r + (*it).getRational(); // Otherwise just add the sumTerm to the sumTerms else sumTerms.push_back((*it)); } // Setup the new expression Expr transformed; if (sumTerms.size() > 1) // If the number of summands is > 1 return the sum of them transformed = Expr(e.getKind(), plusExpr(sumTerms), rat(-r)); else // Otherwise return the one summand as itself transformed = Expr(e.getKind(), sumTerms[0], rat(-r)); // If proof is needed set it up Proof pf; if (withProof()) pf = newPf("arithm_sum_constant_right", e); // Retrun the theorem explaining the transformation return newRWTheorem(e, transformed, Assumptions::emptyAssump(), pf); } Theorem ArithTheoremProducer::eqToIneq(const Expr& e) { // Check soundness of the rule if necessary if (CHECK_PROOFS) CHECK_SOUND(e.isEq(), "eqToIneq: input must be an equality: " + e.toString()); // The proof object we will use Proof pf; // The parts of the equality x = y const Expr& x = e[0]; const Expr& y = e[1]; // Setup the proof if needed if (withProof()) pf = newPf("eqToIneq", e); // Retrun the theorem explaining the transformation return newRWTheorem(e, leExpr(x,y).andExpr(geExpr(x,y)), Assumptions::emptyAssump(), pf); } Theorem ArithTheoremProducer::dummyTheorem(const Expr& e) { Proof pf; return newRWTheorem(e, d_em->trueExpr(), Assumptions::emptyAssump(), pf); } Theorem ArithTheoremProducer::oneElimination(const Expr& e) { // Check soundness if (CHECK_PROOFS) CHECK_SOUND(isMult(e) && e.arity() == 2 && e[0].isRational() && e[0].getRational() == 1, "oneElimination: input must be a multiplication by one" + e.toString()); // The proof object that we will us Proof pf; // Setup the proof if needed if (withProof()) pf = newPf("oneElimination", e); // Return the rewrite theorem that explains the phenomenon return newRWTheorem(e, e[1], Assumptions::emptyAssump(), pf); } Theorem ArithTheoremProducer::clashingBounds(const Theorem& lowerBound, const Theorem& upperBound) { // Get the expressions const Expr& lowerBoundExpr = lowerBound.getExpr(); const Expr& upperBoundExpr = upperBound.getExpr(); // Check soundness if (CHECK_PROOFS) { CHECK_SOUND(isLE(lowerBoundExpr) || isLT(lowerBoundExpr), "clashingBounds: lowerBound should be >= or > " + lowerBoundExpr.toString()); CHECK_SOUND(isGE(upperBoundExpr) || isGT(upperBoundExpr), "clashingBounds: upperBound should be <= or < " + upperBoundExpr.toString()); CHECK_SOUND(lowerBoundExpr[0].isRational(), "clashingBounds: lowerBound left side should be a rational " + lowerBoundExpr.toString()); CHECK_SOUND(upperBoundExpr[0].isRational(), "clashingBounds: upperBound left side should be a rational " + upperBoundExpr.toString()); CHECK_SOUND(lowerBoundExpr[1] == upperBoundExpr[1], "clashingBounds: bounds not on the same term " + lowerBoundExpr.toString() + ", " + upperBoundExpr.toString()); // Get the bounds Rational lowerBoundR = lowerBoundExpr[0].getRational(); Rational upperBoundR = upperBoundExpr[0].getRational(); if (isLE(lowerBoundExpr) && isGE(upperBoundExpr)) { CHECK_SOUND(upperBoundR < lowerBoundR, "clashingBounds: bounds are satisfiable"); } else { CHECK_SOUND(upperBoundR <= lowerBoundR, "clashingBounds: bounds are satisfiable"); } } // The proof object that we will use Proof pf; // Setup the proof if needed if (withProof()) pf = newPf("clashingBounds", lowerBoundExpr, upperBoundExpr); // Put the bounds expressions in the assumptions Assumptions assumptions; assumptions.add(lowerBound); assumptions.add(upperBound); // Return the theorem return newTheorem(d_em->falseExpr(), assumptions, pf); } Theorem ArithTheoremProducer::addInequalities(const Theorem& thm1, const Theorem& thm2) { // Get the expressions of the theorem const Expr& expr1 = thm1.getExpr(); const Expr& expr2 = thm2.getExpr(); // Check soundness if (CHECK_PROOFS) { CHECK_SOUND(isIneq(expr1), "addInequalities: expecting an inequality for thm1, got " + expr1.toString()); CHECK_SOUND(isIneq(expr2), "addInequalities: expecting an inequality for thm2, got " + expr2.toString()); if (isLE(expr1) || isLT(expr1)) CHECK_SOUND(isLE(expr2) || isLT(expr2), "addInequalities: expr2 should be <(=) also " + expr2.toString()); if (isGE(expr1) || isGT(expr1)) CHECK_SOUND(isGE(expr2) || isGT(expr2), "addInequalities: expr2 should be >(=) also" + expr2.toString()); } // Create the assumptions Assumptions a(thm1, thm2); // Get the kinds of the inequalitites int kind1 = expr1.getKind(); int kind2 = expr2.getKind(); // Set-up the resulting inequality int kind = (kind1 == kind2) ? kind1 : ((kind1 == LT) || (kind2 == LT))? LT : GT; // Create the proof object Proof pf; if(withProof()) { vector pfs; pfs.push_back(thm1.getProof()); pfs.push_back(thm2.getProof()); pf = newPf("addInequalities", expr1, expr2, pfs); } // Create the new expressions Expr leftSide = plusExpr(expr1[0], expr2[0]); Expr rightSide = plusExpr(expr1[1], expr2[1]); // Return the theorem return newTheorem(Expr(kind, leftSide, rightSide), a, pf); } Theorem ArithTheoremProducer::implyWeakerInequality(const Expr& expr1, const Expr& expr2) { // Check soundness if (CHECK_PROOFS) { // Both must be inequalitites CHECK_SOUND(isIneq(expr1), "implyWeakerInequality: expr1 should be an inequality" + expr1.toString()); CHECK_SOUND(isIneq(expr2), "implyWeakerInequality: expr1 should be an inequality" + expr2.toString()); bool type_less_than = true; // Should be of the same type if (isLE(expr1) || isLT(expr1)) CHECK_SOUND(isLE(expr2) || isLT(expr2), "implyWeakerInequality: expr2 should be <(=) also " + expr2.toString()); if (isGE(expr1) || isGT(expr1)) { CHECK_SOUND(isGE(expr2) || isGT(expr2), "implyWeakerInequality: expr2 should be >(=) also" + expr2.toString()); type_less_than = false; } // Left sides must be rational numbers CHECK_SOUND(expr1[0].isRational(), "implyWeakerInequality: expr1 should have a rational on the left side" + expr1.toString()); CHECK_SOUND(expr2[0].isRational(), "implyWeakerInequality: expr2 should have a rational on the left side" + expr2.toString()); // Right sides must be identical CHECK_SOUND(expr1[1] == expr2[1], "implyWeakerInequality: the expression must be the same" + expr1.toString() + " and " + expr2.toString()); Rational expr1rat = expr1[0].getRational(); Rational expr2rat = expr2[0].getRational(); // Check the bounds if (type_less_than) { if (isLE(expr1) || isLT(expr2)) { CHECK_SOUND(expr2rat < expr1rat, "implyWeakerInequality: the implication doesn't apply" + expr1.toString() + " and " + expr2.toString()); } else { CHECK_SOUND(expr2rat <= expr1rat, "implyWeakerInequality: the implication doesn't apply" + expr1.toString() + " and " + expr2.toString()); } } else { if (isGE(expr1) || isGT(expr2)) { CHECK_SOUND(expr2rat > expr1rat, "implyWeakerInequality: the implication doesn't apply" + expr1.toString() + " and " + expr2.toString()); } else { CHECK_SOUND(expr2rat >= expr1rat, "implyWeakerInequality: the implication doesn't apply" + expr1.toString() + " and " + expr2.toString()); } } } // Create the proof object Proof pf; if(withProof()) pf = newPf("implyWeakerInequality", expr1, expr2); // Return the theorem return newTheorem(expr1.impExpr(expr2), Assumptions::emptyAssump(), pf); } Theorem ArithTheoremProducer::implyNegatedInequality(const Expr& expr1, const Expr& expr2) { // Check soundness if (CHECK_PROOFS) { CHECK_SOUND(isIneq(expr1), "implyNegatedInequality: lowerBound should be an inequality " + expr1.toString()); CHECK_SOUND(isIneq(expr2), "implyNegatedInequality: upperBound should be be an inequality " + expr2.toString()); CHECK_SOUND(expr1[0].isRational(), "implyNegatedInequality: lowerBound left side should be a rational " + expr1.toString()); CHECK_SOUND(expr2[0].isRational(), "implyNegatedInequality: upperBound left side should be a rational " + expr2.toString()); CHECK_SOUND(expr1[1] == expr2[1], "implyNegatedInequality: bounds not on the same term " + expr1.toString() + ", " + expr2.toString()); // Get the bounds Rational lowerBoundR = expr1[0].getRational(); Rational upperBoundR = expr2[0].getRational(); if (isLE(expr1) && isGE(expr2)) CHECK_SOUND(upperBoundR < lowerBoundR, "implyNegatedInequality: cant imply negation" + expr1.toString() + ", " + expr2.toString()); if (isLT(expr1) || isGT(expr2)) CHECK_SOUND(upperBoundR <= lowerBoundR, "implyNegatedInequality: cant imply negation" + expr1.toString() + ", " + expr2.toString()); if (isGE(expr1) && isLE(expr2)) CHECK_SOUND(upperBoundR > lowerBoundR, "implyNegatedInequality: cant imply negation" + expr1.toString() + ", " + expr2.toString()); if (isGT(expr1) || isLT(expr2)) CHECK_SOUND(upperBoundR >= lowerBoundR, "implyNegatedInequality: cant imply negation" + expr1.toString() + ", " + expr2.toString()); } // The proof object that we will use Proof pf; if (withProof()) pf = newPf("implyNegatedInequality", expr1, expr2); // Return the theorem return newTheorem(expr1.impExpr(expr2.negate()), Assumptions::emptyAssump(), pf); } Theorem ArithTheoremProducer::trustedRewrite(const Expr& expr1, const Expr& expr2) { // The proof object that we will us Proof pf; // Setup the proof if needed if (withProof()) pf = newPf("trustedRewrite", expr1, expr2); // Return the rewrite theorem that explains the phenomenon return newRWTheorem(expr1, expr2, Assumptions::emptyAssump(), pf); } Theorem ArithTheoremProducer::integerSplit(const Expr& intVar, const Rational& intPoint) { // Check soundness if (CHECK_PROOFS) { CHECK_SOUND(intPoint.isInteger(), "integerSplit: we can only split on integer points, given" + intPoint.toString()); } // Create the expression const Expr& split = Expr(IS_INTEGER, intVar).impExpr(leExpr(intVar, rat(intPoint)).orExpr(geExpr(intVar, rat(intPoint + 1)))); // The proof object that we will use Proof pf; if (withProof()) pf = newPf("integerSplit", intVar, rat(intPoint)); // Return the theorem return newTheorem(split, Assumptions::emptyAssump(), pf); } Theorem ArithTheoremProducer::rafineStrictInteger(const Theorem& isIntConstrThm, const Expr& constr) { // Check soundness if (CHECK_PROOFS) { // Right side of the constraint should correspond to the proved integer expression CHECK_SOUND(isIneq(constr), "rafineStrictInteger: expected a constraint got : " + constr.toString()); CHECK_SOUND(isIntConstrThm.getExpr()[0] == constr[1], "rafineStrictInteger: proof of intger doesn't correspond to the constarint right side"); CHECK_SOUND(constr[0].isRational(), "rafineStrictInteger: right side of the constraint muts be a rational"); } // Get the contraint bound Rational bound = constr[0].getRational(); // Get the kind of the constraint int kind = constr.getKind(); // If the bound is strict, make it non-strict switch (kind) { case LT: kind = LE; if (bound.isInteger()) bound ++; // 3 < x --> 4 <= x else bound = ceil(bound); // 3.4 < x --> 4 <= x break; case LE: kind = LE; if (!bound.isInteger()) bound = ceil(bound); // 3.5 <= x --> 4 <= x break; case GT: kind = GE; if (bound.isInteger()) bound --; // 3 > x --> 2 >= x else bound = floor(bound); // 3.4 > x --> 3 >= x break; case GE: kind = GE; if (!bound.isInteger()) bound = floor(bound); // 3.4 >= x --> 3 >= x break; } // The new constraint Expr newConstr(kind, rat(bound), constr[1]); // Pick up the assumptions from the integer proof const Assumptions& assump(isIntConstrThm.getAssumptionsRef()); // Construct the proof object if necessary Proof pf; if (withProof()) pf = newPf("rafineStrictInteger", constr, newConstr,isIntConstrThm.getProof()); // Return the rewrite theorem that explains the phenomenon return newRWTheorem(constr, newConstr, assump, pf); } // // This one is here just to compile... the code is in old arithmetic Theorem ArithTheoremProducer::simpleIneqInt(const Expr& ineq, const Theorem& isIntRHS) { DebugAssert(false, "Not implemented!!!"); return Theorem(); } // Given: // 0 = c + t // where t is integer and c is not // deduce bot Theorem ArithTheoremProducer::intEqualityRationalConstant(const Theorem& isIntConstrThm, const Expr& constr) { DebugAssert(false, "Not implemented!!!"); return Theorem(); } Theorem ArithTheoremProducer::cycleConflict(const vector& inequalitites) { DebugAssert(false, "Not implemented!!!"); return Theorem(); } Theorem ArithTheoremProducer::implyEqualities(const vector& inequalitites) { DebugAssert(false, "Not implemented!!!"); return Theorem(); } /*! Takes a Theorem(\\alpha < \\beta) and returns * Theorem(\\alpha < \\beta <==> \\alpha <= \\beta -1) * where \\alpha and \\beta are integer expressions */ Theorem ArithTheoremProducer::lessThanToLERewrite(const Expr& ineq, const Theorem& isIntLHS, const Theorem& isIntRHS, bool changeRight) { const Expr& isIntLHSexpr = isIntLHS.getExpr(); const Expr& isIntRHSexpr = isIntRHS.getExpr(); if(CHECK_PROOFS) { CHECK_SOUND(isLT(ineq), "ArithTheoremProducerOld::LTtoLE: ineq must be <"); // Integrality check CHECK_SOUND(isIntPred(isIntLHSexpr) && isIntLHSexpr[0] == ineq[0], "ArithTheoremProducerOld::lessThanToLE: bad integrality check:\n" " ineq = "+ineq.toString()+"\n isIntLHS = " +isIntLHSexpr.toString()); CHECK_SOUND(isIntPred(isIntRHSexpr) && isIntRHSexpr[0] == ineq[1], "ArithTheoremProducerOld::lessThanToLE: bad integrality check:\n" " ineq = "+ineq.toString()+"\n isIntRHS = " +isIntRHSexpr.toString()); } vector thms; thms.push_back(isIntLHS); thms.push_back(isIntRHS); Assumptions a(thms); Proof pf; Expr le = changeRight? leExpr(ineq[0], ineq[1] + rat(-1)) : leExpr(ineq[0] + rat(1), ineq[1]); if(withProof()) { vector pfs; pfs.push_back(isIntLHS.getProof()); pfs.push_back(isIntRHS.getProof()); pf = newPf(changeRight? "lessThan_To_LE_rhs_rwr" : "lessThan_To_LE_lhs_rwr", ineq, le, pfs); } return newRWTheorem(ineq, le, a, pf); } Theorem ArithTheoremProducer::splitGrayShadowSmall(const Theorem& gThm) { DebugAssert(false, "Not implemented!!!"); return Theorem(); } Theorem ArithTheoremProducer::implyWeakerInequalityDiffLogic(const std::vector& antecedentThms, const Expr& implied) { DebugAssert(false, "Not implemented!!!"); return Theorem(); } Theorem ArithTheoremProducer::implyNegatedInequalityDiffLogic(const std::vector& antecedentThms, const Expr& implied) { DebugAssert(false, "Not implemented!!!"); return Theorem(); } Theorem ArithTheoremProducer::expandGrayShadowRewrite(const Expr& theShadow) { DebugAssert(false, "Not implemented!!!"); return Theorem(); } Theorem ArithTheoremProducer::compactNonLinearTerm(const Expr& nonLinear) { DebugAssert(false, "Not implemented!!!"); return Theorem(); } Theorem ArithTheoremProducer::nonLinearIneqSignSplit(const Theorem& ineqThm) { DebugAssert(false, "Not implemented!!!"); return Theorem(); } Theorem ArithTheoremProducer::implyDiffLogicBothBounds(const Expr& x, std::vector& c1_le_x, Rational c1, std::vector& x_le_c2, Rational c2) { DebugAssert(false, "Not implemented!!!"); return Theorem(); } Theorem ArithTheoremProducer::addInequalities(const vector& thms) { DebugAssert(false, "Not implemented!!!"); return Theorem(); } Theorem ArithTheoremProducer::powerOfOne(const Expr& e) { DebugAssert(false, "Not implemented!!!"); return Theorem(); } //////////////////////////////////////////////////////////////////// // Stubs for ArithProofRules //////////////////////////////////////////////////////////////////// Theorem ArithProofRules::rewriteLeavesConst(const Expr& e) { DebugAssert(false, "Not implemented!!!"); return Theorem(); } cvc3-2.4.1/src/theory_arith/theory_arith3.cpp0000664000175400017540000033046211410616733021050 0ustar mdetersmdeters/*****************************************************************************/ /*! * \file theory_arith3.cpp * * Author: Clark Barrett, Vijay Ganesh. * * Created: Fri Jan 17 18:39:18 2003 * *
* * License to use, copy, modify, sell and/or distribute this software * and its documentation for any purpose is hereby granted without * royalty, subject to the terms and conditions defined in the \ref * LICENSE file provided with this distribution. * *
* */ /*****************************************************************************/ #include "theory_arith3.h" #include "arith_proof_rules.h" //#include "arith_expr.h" #include "arith_exception.h" #include "typecheck_exception.h" #include "eval_exception.h" #include "parser_exception.h" #include "smtlib_exception.h" #include "theory_core.h" #include "command_line_flags.h" using namespace std; using namespace CVC3; /////////////////////////////////////////////////////////////////////////////// // TheoryArith3::FreeConst Methods // /////////////////////////////////////////////////////////////////////////////// namespace CVC3 { ostream& operator<<(ostream& os, const TheoryArith3::FreeConst& fc) { os << "FreeConst(r=" << fc.getConst() << ", " << (fc.strict()? "strict" : "non-strict") << ")"; return os; } /////////////////////////////////////////////////////////////////////////////// // TheoryArith3::Ineq Methods // /////////////////////////////////////////////////////////////////////////////// ostream& operator<<(ostream& os, const TheoryArith3::Ineq& ineq) { os << "Ineq(" << ineq.ineq().getExpr() << ", isolated on " << (ineq.varOnRHS()? "RHS" : "LHS") << ", const = " << ineq.getConst() << ")"; return os; } } // End of namespace CVC3 /////////////////////////////////////////////////////////////////////////////// // TheoryArith3 Private Methods // /////////////////////////////////////////////////////////////////////////////// Theorem TheoryArith3::isIntegerThm(const Expr& e) { // Quick check if(isReal(e.getType())) return Theorem(); // Try harder return isIntegerDerive(Expr(IS_INTEGER, e), typePred(e)); } Theorem TheoryArith3::isIntegerDerive(const Expr& isIntE, const Theorem& thm) { const Expr& e = thm.getExpr(); // We found it! if(e == isIntE) return thm; Theorem res; // If the theorem is an AND, look inside each child if(e.isAnd()) { int i, iend=e.arity(); for(i=0; iandElim(thm, i)); if(!res.isNull()) return res; } } return res; } const Rational& TheoryArith3::freeConstIneq(const Expr& ineq, bool varOnRHS) { DebugAssert(isIneq(ineq), "TheoryArith3::freeConstIneq("+ineq.toString()+")"); const Expr& e = varOnRHS? ineq[0] : ineq[1]; switch(e.getKind()) { case PLUS: return e[0].getRational(); case RATIONAL_EXPR: return e.getRational(); default: { // MULT, DIV, or Variable static Rational zero(0); return zero; } } } const TheoryArith3::FreeConst& TheoryArith3::updateSubsumptionDB(const Expr& ineq, bool varOnRHS, bool& subsumed) { TRACE("arith ineq", "TheoryArith3::updateSubsumptionDB(", ineq, ", var isolated on "+string(varOnRHS? "RHS" : "LHS")+")"); DebugAssert(isLT(ineq) || isLE(ineq), "TheoryArith3::updateSubsumptionDB(" +ineq.toString()+")"); // Indexing expression: same as ineq only without the free const Expr index; const Expr& t = varOnRHS? ineq[0] : ineq[1]; bool strict(isLT(ineq)); Rational c(0); if(isPlus(t)) { DebugAssert(t.arity() >= 2, "TheoryArith3::updateSubsumptionDB(" +ineq.toString()+")"); c = t[0].getRational(); // Extract the free const in ineq Expr newT; if(t.arity() == 2) { newT = t[1]; } else { vector kids; Expr::iterator i=t.begin(), iend=t.end(); for(++i; i!=iend; ++i) kids.push_back(*i); DebugAssert(kids.size() > 0, "kids.size = "+int2string(kids.size()) +", ineq = "+ineq.toString()); newT = plusExpr(kids); } if(varOnRHS) index = leExpr(newT, ineq[1]); else index = leExpr(ineq[0], newT); } else if(isRational(t)) { c = t.getRational(); if(varOnRHS) index = leExpr(rat(0), ineq[1]); else index = leExpr(ineq[0], rat(0)); } else if(isLT(ineq)) index = leExpr(ineq[0], ineq[1]); else index = ineq; // Now update the database, check for subsumption, and extract the constant CDMap::iterator i=d_freeConstDB.find(index), iend=d_freeConstDB.end(); if(i == iend) { subsumed = false; // Create a new entry CDOmap& obj = d_freeConstDB[index]; obj = FreeConst(c,strict); TRACE("arith ineq", "freeConstDB["+index.toString()+"] := ", obj, ""); return obj.get(); } else { CDOmap& obj = d_freeConstDB[index]; const FreeConst& fc = obj.get(); if(varOnRHS) { subsumed = (c < fc.getConst() || (c == fc.getConst() && (!strict || fc.strict()))); } else { subsumed = (c > fc.getConst() || (c == fc.getConst() && (strict || !fc.strict()))); } if(!subsumed) { obj = FreeConst(c,strict); TRACE("arith ineq", "freeConstDB["+index.toString()+"] := ", obj, ""); } return obj.get(); } } bool TheoryArith3::kidsCanonical(const Expr& e) { if(isLeaf(e)) return true; bool res(true); for(int i=0; res && iuMinusToMult(e[0]); Expr e2 = thm.getRHS(); result = transitivityRule(thm, canon(e2)); } break; case PLUS: /* { Theorem plusThm, plusThm1; plusThm = d_rules->canonFlattenSum(e); plusThm1 = d_rules->canonComboLikeTerms(plusThm.getRHS()); result = transitivityRule(plusThm,plusThm1); } */ result = d_rules->canonPlus(e); break; case MINUS: { DebugAssert(e.arity() == 2,""); Theorem minus_eq_sum = d_rules->minusToPlus(e[0], e[1]); // this produces e0 + (-1)*e1; we have to canonize it in 2 steps Expr sum(minus_eq_sum.getRHS()); Theorem thm(canon(sum[1])); if(thm.getLHS() == thm.getRHS()) result = canonThm(minus_eq_sum); // The sum changed; do the work else { vector changed; vector thms; changed.push_back(1); thms.push_back(thm); Theorem sum_eq_canon = canonThm(substitutivityRule(sum, changed, thms)); result = transitivityRule(minus_eq_sum, sum_eq_canon); } break; } case MULT: result = d_rules->canonMult(e); break; /* case MULT: { Theorem thmMult, thmMult1; Expr exprMult; Expr e0 = e[0]; Expr e1 = e[1]; if(e0.isRational()) { if(rat(0) == e0) result = d_rules->canonMultZero(e1); else if (rat(1) == e0) result = d_rules->canonMultOne(e1); else switch(e1.getKind()) { case RATIONAL_EXPR : result = d_rules->canonMultConstConst(e0,e1); break; case MULT: DebugAssert(e1[0].isRational(), "theory_arith::canon:\n " "canon:MULT:MULT child is not canonical: " + e1[0].toString()); thmMult = d_rules->canonMultConstTerm(e0,e1[0],e1[1]); result = transitivityRule(thmMult,canon(thmMult.getRHS())); break; case PLUS:{ Theorem thmPlus, thmPlus1; Expr ePlus; std::vector thmPlusVector; thmPlus = d_rules->canonMultConstSum(e0,e1); ePlus = thmPlus.getRHS(); Expr::iterator i = ePlus.begin(); for(;i != ePlus.end();++i) thmPlusVector.push_back(canon(*i)); thmPlus1 = substitutivityRule(PLUS, thmPlusVector); result = transitivityRule(thmPlus, thmPlus1); break; } default: result = reflexivityRule(e); break; } } else { if(e1.isRational()){ // canonMultTermConst just reverses the order of the const and the // term. Then canon is called again. Theorem t1 = d_rules->canonMultTermConst(e1,e0); result = transitivityRule(t1,canon(t1.getRHS())); } else // This is where the assertion for non-linear multiplication is // produced. result = d_rules->canonMultTerm1Term2(e0,e1); } break; } */ case DIVIDE:{ /* case DIVIDE:{ if (e[1].isRational()) { if (e[1].getRational() == 0) throw ArithException("Divide by 0 error in "+e.toString()); Theorem thm = d_rules->canonDivideVar(e[0], e[1]); Expr e2 = thm.getRHS(); result = transitivityRule(thm, canon(e2)); } else { // TODO: to be handled throw ArithException("Divide by a non-const not handled in "+e.toString()); } break; } */ // Division by 0 is OK (total extension, protected by TCCs) // if (e[1].isRational() && e[1].getRational() == 0) // throw ArithException("Divide by 0 error in "+e.toString()); if (e[1].getKind() == PLUS) throw ArithException("Divide by a PLUS expression not handled in"+e.toString()); result = d_rules->canonDivide(e); break; } case POW: if(e[1].isRational()) result = d_rules->canonPowConst(e); else result = reflexivityRule(e); break; default: result = reflexivityRule(e); break; } TRACE("arith canon","canon => ",result," }"); return result; } Theorem TheoryArith3::canonSimplify(const Expr& e) { TRACE("arith", "canonSimplify(", e, ") {"); DebugAssert(kidsCanonical(e), "TheoryArith3::canonSimplify("+e.toString()+")"); DebugAssert(leavesAreSimp(e), "Expected leaves to be simplified"); Expr tmp(e); Theorem thm = canon(e); if(thm.getRHS().hasFind()) thm = transitivityRule(thm, find(thm.getRHS())); // We shouldn't rely on simplification in this function anymore DebugAssert(thm.getRHS() == simplifyExpr(thm.getRHS()), "canonSimplify("+e.toString()+")\n" +"canon(e) = "+thm.getRHS().toString() +"\nsimplify(canon(e)) = "+simplifyExpr(thm.getRHS()).toString()); // if(tmp != thm.getRHS()) // thm = transitivityRule(thm, simplifyThm(thm.getRHS())); // while(tmp != thm.getRHS()) { // tmp = thm.getRHS(); // thm = canon(thm); // if(tmp != thm.getRHS()) // thm = transitivityRule(thm, simplifyThm(thm.getRHS())); // } TRACE("arith", "canonSimplify =>", thm, " }"); return thm; } /*! accepts a theorem, canonizes it, applies iffMP and substituvity to * derive the canonized thm */ Theorem TheoryArith3::canonPred(const Theorem& thm) { vector thms; DebugAssert(thm.getExpr().arity() == 2, "TheoryArith3::canonPred: bad theorem: "+thm.toString()); Expr e(thm.getExpr()); thms.push_back(canonSimplify(e[0])); thms.push_back(canonSimplify(e[1])); return iffMP(thm, substitutivityRule(e.getOp(), thms)); } /*! accepts an equivalence theorem, canonizes it, applies iffMP and * substituvity to derive the canonized thm */ Theorem TheoryArith3::canonPredEquiv(const Theorem& thm) { vector thms; DebugAssert(thm.getRHS().arity() == 2, "TheoryArith3::canonPredEquiv: bad theorem: "+thm.toString()); Expr e(thm.getRHS()); thms.push_back(canonSimplify(e[0])); thms.push_back(canonSimplify(e[1])); return transitivityRule(thm, substitutivityRule(e.getOp(), thms)); } /*! accepts an equivalence theorem whose RHS is a conjunction, * canonizes it, applies iffMP and substituvity to derive the * canonized thm */ Theorem TheoryArith3::canonConjunctionEquiv(const Theorem& thm) { vector thms; return thm; } /*! Pseudo-code for doSolve. (Input is an equation) (output is a Theorem) * -# translate e to the form e' = 0 * -# if (e'.isRational()) then {if e' != 0 return false else true} * -# a for loop checks if all the variables are integers. * - if not isolate a suitable real variable and call processRealEq(). * - if all variables are integers then isolate suitable variable * and call processIntEq(). */ Theorem TheoryArith3::doSolve(const Theorem& thm) { const Expr& e = thm.getExpr(); TRACE("arith eq","doSolve(",e,") {"); DebugAssert(thm.isRewrite(), "thm = "+thm.toString()); Theorem eqnThm; vector thms; // Move LHS to the RHS, if necessary if(e[0].isRational() && e[0].getRational() == 0) eqnThm = thm; else { eqnThm = iffMP(thm, d_rules->rightMinusLeft(e)); eqnThm = canonPred(eqnThm); } // eqnThm is of the form 0 = e' // 'right' is of the form e' Expr right = eqnThm.getRHS(); // Check for trivial equation if (right.isRational()) { Theorem result = iffMP(eqnThm, d_rules->constPredicate(eqnThm.getExpr())); TRACE("arith eq","doSolve => ",result," }"); return result; } //normalize eqnThm = iffMP(eqnThm, normalize(eqnThm.getExpr())); right = eqnThm.getRHS(); //eqn is of the form 0 = e' and is normalized where 'right' denotes e' //FIXME: change processRealEq to accept equations as well instead of theorems try { if (isMult(right)) { DebugAssert(right.arity() > 1, "Expected arity > 1"); if (right[0].isRational()) { Rational r = right[0].getRational(); if (r == 0) return getCommonRules()->trueTheorem(); else if (r == 1) { enqueueFact(iffMP(eqnThm, d_rules->multEqZero(eqnThm.getExpr()))); return getCommonRules()->trueTheorem(); } Theorem res = iffMP(eqnThm, d_rules->multEqn(eqnThm.getLHS(), right, rat(1/r))); res = canonPred(res); return doSolve(res); } else { enqueueFact(iffMP(eqnThm, d_rules->multEqZero(eqnThm.getExpr()))); return getCommonRules()->trueTheorem(); } } else if (isPow(right)) { DebugAssert(right.arity() == 2, "Expected arity 2"); if (right[0].isRational()) { return doSolve(iffMP(eqnThm, d_rules->powEqZero(eqnThm.getExpr()))); } throw ArithException("Can't solve exponential eqn: "+eqnThm.toString()); } else { if(!isInteger(right)) { return processRealEq(eqnThm); } else { return processIntEq(eqnThm); } } } catch(ArithException& e) { // Nonlinear heuristics Theorem res; if (isPlus(right)) { // Search for common factor if (right[0].getRational() == 0) { Expr::iterator i = right.begin(), iend = right.end(); ++i; set factors; set::iterator is, isend; getFactors(*i, factors); for (++i; i != iend; ++i) { set factors2; getFactors(*i, factors2); for (is = factors.begin(), isend = factors.end(); is != isend; ++is) { if (factors2.find(*is) == factors2.end()) { factors.erase(is); } } if (factors.empty()) break; } if (!factors.empty()) { enqueueFact(iffMP(eqnThm, d_rules->divideEqnNonConst(rat(0), right, *(factors.begin())))); return getCommonRules()->trueTheorem(); } } // Solve for something Expr isolated = right[1]; Rational coeff; if (isMult(isolated) && isolated[0].isRational()) { coeff = isolated[0].getRational(); DebugAssert(coeff != 0, "Expected nonzero coeff"); isolated = canon(isolated / rat(coeff)).getRHS(); } else coeff = 1; res = iffMP(eqnThm, d_rules->multEqn(rat(0), right, rat(-1/coeff))); res = canonPred(res); res = iffMP(res, d_rules->plusPredicate(res.getLHS(), res.getRHS(), isolated, EQ)); res = canonPred(res); // Look for equal powers if (isPow(res.getLHS())) { Expr left = res.getLHS(); if (isInteger(left[0])) { Rational pow = left[0].getRational(); if (pow > 1) { right = res.getRHS(); if (isPow(right) && right[0] == left[0]) { enqueueFact(iffMP(res, d_rules->elimPower(res.getExpr()))); return getCommonRules()->trueTheorem(); } else if (right.isRational()) { Rational r = right.getRational(); if (pow % 2 == 0 && r < 0) { return iffMP(res, d_rules->evenPowerEqNegConst(res.getExpr())); } DebugAssert(r != 0, "Expected nonzero const"); Rational root = ratRoot(r, pow.getUnsigned()); if (root != 0) { enqueueFact(iffMP(res, d_rules->elimPowerConst(res.getExpr(), root))); return getCommonRules()->trueTheorem(); } else if (isInt(left[1].getType())) { Theorem isIntx(isIntegerThm(left[1])); DebugAssert(!isIntx.isNull(), "left = "+left.toString()); return iffMP(res, d_rules->intEqIrrational(res.getExpr(), isIntx)); } } } } } } else { res = symmetryRule(eqnThm); // Flip to e' = 0 } TRACE("arith eq", "doSolve: failed to solve an equation: ", e, ""); IF_DEBUG(debugger.counter("FAILED to solve equalities")++;) setIncomplete("Non-linear arithmetic equalities"); return res; } FatalAssert(false, ""); return Theorem(); } /*! pick a monomial for the input equation. This function is used only * if the equation is an integer equation. Choose the monomial with * the smallest absolute value of coefficient. */ bool TheoryArith3::pickIntEqMonomial(const Expr& right, Expr& isolated, bool& nonlin) { DebugAssert(isPlus(right) && right.arity() > 1, "TheoryArith3::pickIntEqMonomial right is wrong :-): " + right.toString()); DebugAssert(right[0].isRational(), "TheoryArith3::pickIntEqMonomial. right[0] must be const" + right.toString()); DebugAssert(isInteger(right), "TheoryArith3::pickIntEqMonomial: right is of type int: " + right.toString()); //right is of the form "C + a1x1 + ... + anxn". min is initialized //to a1 Expr::iterator istart = right.begin(), iend = right.end(); istart++; Expr::iterator i = istart, j; bool found = false; nonlin = false; Rational min, coeff; Expr leaf; for(; i != iend; ++i) { if (isLeaf(*i)) { leaf = *i; coeff = 1; } else if (isMult(*i) && (*i).arity() == 2 && (*i)[0].isRational() && isLeaf((*i)[1])) { leaf = (*i)[1]; coeff = abs((*i)[0].getRational()); } else { nonlin = true; continue; } for (j = istart; j != iend; ++j) { if (j != i && isLeafIn(leaf, *j)) break; } if (j == iend) { if (!found || min > coeff) { min = coeff; isolated = *i; found = true; } } } return found; } /*! input is 0=e' Theorem and some of the vars in e' are of * type REAL. isolate one of them and send back to framework. output * is "var = e''" Theorem. */ Theorem TheoryArith3::processRealEq(const Theorem& eqn) { DebugAssert(eqn.getLHS().isRational() && eqn.getLHS().getRational() == 0, "processRealEq invariant violated"); Expr right = eqn.getRHS(); // Find variable to isolate and store it in left. Pick the largest // (according to the total ordering) variable. FIXME: change from // total ordering to the ordering we devised for inequalities. // TODO: I have to pick a variable that appears as a variable in the // term but does not appear as a variable anywhere else. The variable // must appear as a single leaf and not in a MULT expression with some // other variables and nor in a POW expression. bool found = false; Expr left; if (isPlus(right)) { for(int i = right.arity()-1; i>=0; --i) { Expr c = right[i]; if(isRational(c)) continue; if(!isInteger(c)) { if (isLeaf(c) || ((isMult(c) && c.arity() == 2 && isLeaf(c[1])))) { int numoccurs = 0; Expr leaf = isLeaf(c) ? c : c[1]; for (int j = 0; j < right.arity(); ++j) { if (j!= i && isLeafIn(leaf, right[j]) ) { numoccurs++; break; } } if (!numoccurs) { left = c; found = true; break; } } } } } else if ((isMult(right) && right.arity() == 2 && isLeaf(right[1])) || isLeaf(right)) { left = right; found = true; } if (!found) { throw ArithException("Can't find a leaf for solve in "+eqn.toString()); } Rational r = -1; if (isMult(left)) { DebugAssert(left.arity() == 2, "only leaf should be chosen as lhs"); DebugAssert(left[0].getRational() != 0, "left = "+left.toString()); r = -1/left[0].getRational(); left = left[1]; } DebugAssert(isReal(getBaseType(left)) && !isInteger(left), "TheoryArith3::ProcessRealEq: left is integer:\n left = " +left.toString()); // Normalize equation so that coefficient of the monomial // corresponding to "left" in eqn[1] is -1 Theorem result(iffMP(eqn, d_rules->multEqn(eqn.getLHS(), eqn.getRHS(), rat(r)))); result = canonPred(result); // Isolate left result = iffMP(result, d_rules->plusPredicate(result.getLHS(), result.getRHS(), left, EQ)); result = canonPred(result); TRACE("arith","processRealEq => ",result," }"); return result; } void TheoryArith3::getFactors(const Expr& e, set& factors) { switch (e.getKind()) { case RATIONAL_EXPR: break; case MULT: { Expr::iterator i = e.begin(), iend = e.end(); for (; i != iend; ++i) { getFactors(*i, factors); } break; } case POW: { DebugAssert(e.arity() == 2, "invariant violated"); if (!isIntegerConst(e[0]) || e[0].getRational() <= 0) { throw ArithException("not positive integer exponent in "+e.toString()); } if (isLeaf(e[1])) factors.insert(e[1]); break; } default: { DebugAssert(isLeaf(e), "expected leaf"); DebugAssert(factors.find(e) == factors.end(), "expected new entry"); factors.insert(e); break; } } } /*! * \param eqn is a single equation 0 = e * \return an equivalent Theorem (x = t AND 0 = e'), or just x = t */ Theorem TheoryArith3::processSimpleIntEq(const Theorem& eqn) { TRACE("arith eq", "processSimpleIntEq(", eqn.getExpr(), ") {"); DebugAssert(eqn.isRewrite(), "TheoryArith3::processSimpleIntEq: eqn must be equality" + eqn.getExpr().toString()); Expr right = eqn.getRHS(); DebugAssert(eqn.getLHS().isRational() && 0 == eqn.getLHS().getRational(), "TheoryArith3::processSimpleIntEq: LHS must be 0:\n" + eqn.getExpr().toString()); DebugAssert(!isMult(right) && !isPow(right), "should have been handled above"); if (isPlus(right)) { if (2 == right.arity() && (isLeaf(right[1]) || (isMult(right[1]) && right[1].arity() == 2 && right[1][0].isRational() && isLeaf(right[1][1])))) { //we take care of special cases like 0 = c + a.x, 0 = c + x, Expr c,x; separateMonomial(right[1], c, x); Theorem isIntx(isIntegerThm(x)); DebugAssert(!isIntx.isNull(), "right = "+right.toString() +"\n x = "+x.toString()); Theorem res(iffMP(eqn, d_rules->intVarEqnConst(eqn.getExpr(), isIntx))); TRACE("arith eq", "processSimpleIntEq[0 = c + a*x] => ", res, " }"); return res; } // Pick a suitable monomial. isolated can be of the form x, a.x, -a.x Expr isolated; bool nonlin; if (pickIntEqMonomial(right, isolated, nonlin)) { TRACE("arith eq", "processSimpleIntEq: isolated = ", isolated, ""); // First, we compute the 'sign factor' with which to multiply the // eqn. if the coeff of isolated is positive (i.e. 'isolated' is // of the form x or a.x where a>0 ) then r must be -1 and if coeff // of 'isolated' is negative, r=1. Rational r = isMult(isolated) ? ((isolated[0].getRational() > 0) ? -1 : 1) : -1; Theorem result; if (-1 == r) { // r=-1 and hence 'isolated' is 'x' or 'a.x' where a is // positive. modify eqn (0=e') to the equation (0=canon(-1*e')) result = iffMP(eqn, d_rules->multEqn(eqn.getLHS(), right, rat(r))); result = canonPred(result); Expr e = result.getRHS(); // Isolate the 'isolated' result = iffMP(result, d_rules->plusPredicate(result.getLHS(),result.getRHS(), isolated, EQ)); } else { //r is 1 and hence isolated is -a.x. Make 'isolated' positive. const Rational& minusa = isolated[0].getRational(); Rational a = -1*minusa; isolated = (a == 1)? isolated[1] : rat(a) * isolated[1]; // Isolate the 'isolated' result = iffMP(eqn, d_rules->plusPredicate(eqn.getLHS(), right,isolated,EQ)); } // Canonize the result result = canonPred(result); //if isolated is 'x' or 1*x, then return result else continue processing. if(!isMult(isolated) || isolated[0].getRational() == 1) { TRACE("arith eq", "processSimpleIntEq[x = rhs] => ", result, " }"); return result; } else if (!nonlin) { DebugAssert(isMult(isolated) && isolated[0].getRational() >= 2, "TheoryArith3::processSimpleIntEq: isolated must be mult " "with coeff >= 2.\n isolated = " + isolated.toString()); // Compute IS_INTEGER() for lhs and rhs Expr lhs = result.getLHS(); Expr rhs = result.getRHS(); Expr a, x; separateMonomial(lhs, a, x); Theorem isIntLHS = isIntegerThm(x); vector isIntRHS; if(!isPlus(rhs)) { // rhs is a MULT Expr c, v; separateMonomial(rhs, c, v); isIntRHS.push_back(isIntegerThm(v)); DebugAssert(!isIntRHS.back().isNull(), ""); } else { // rhs is a PLUS DebugAssert(isPlus(rhs), "rhs = "+rhs.toString()); DebugAssert(rhs.arity() >= 2, "rhs = "+rhs.toString()); Expr::iterator i=rhs.begin(), iend=rhs.end(); ++i; // Skip the free constant for(; i!=iend; ++i) { Expr c, v; separateMonomial(*i, c, v); isIntRHS.push_back(isIntegerThm(v)); DebugAssert(!isIntRHS.back().isNull(), ""); } } // Derive (EXISTS (x:INT): x = t2 AND 0 = t3) result = d_rules->eqElimIntRule(result, isIntLHS, isIntRHS); // Skolemize the quantifier result = getCommonRules()->skolemize(result); // Canonize t2 and t3 generated by this rule DebugAssert(result.getExpr().isAnd() && result.getExpr().arity() == 2, "processSimpleIntEq: result = "+result.getExpr().toString()); Theorem thm1 = canonPred(getCommonRules()->andElim(result, 0)); Theorem thm2 = canonPred(getCommonRules()->andElim(result, 1)); Theorem newRes = getCommonRules()->andIntro(thm1, thm2); if(newRes.getExpr() != result.getExpr()) result = newRes; TRACE("arith eq", "processSimpleIntEq => ", result, " }"); return result; } } throw ArithException("Can't find a leaf for solve in "+eqn.toString()); } else { // eqn is 0 = x. Flip it and return Theorem result = symmetryRule(eqn); TRACE("arith eq", "processSimpleIntEq[x = 0] => ", result, " }"); return result; } } /*! input is 0=e' Theorem and all of the vars in e' are of * type INT. isolate one of them and send back to framework. output * is "var = e''" Theorem and some associated equations in * solved form. */ Theorem TheoryArith3::processIntEq(const Theorem& eqn) { TRACE("arith eq", "processIntEq(", eqn.getExpr(), ") {"); // Equations in the solved form. std::vector solvedAndNewEqs; Theorem newEq(eqn), result; bool done(false); do { result = processSimpleIntEq(newEq); // 'result' is of the from (x1=t1) AND 0=t' if(result.isRewrite()) { solvedAndNewEqs.push_back(result); done = true; } else if (result.getExpr().isBoolConst()) { done = true; } else { DebugAssert(result.getExpr().isAnd() && result.getExpr().arity() == 2, "TheoryArith3::processIntEq("+eqn.getExpr().toString() +")\n result = "+result.getExpr().toString()); solvedAndNewEqs.push_back(getCommonRules()->andElim(result, 0)); newEq = getCommonRules()->andElim(result, 1); } } while(!done); Theorem res; if (result.getExpr().isFalse()) res = result; else if (solvedAndNewEqs.size() > 0) res = solvedForm(solvedAndNewEqs); else res = result; TRACE("arith eq", "processIntEq => ", res.getExpr(), " }"); return res; } /*! * Takes a vector of equations and for every equation x_i=t_i * substitutes t_j for x_j in t_i for all j>i. This turns the system * of equations into a solved form. * * Assumption: variables x_j may appear in the RHS terms t_i ONLY for * i=j. */ Theorem TheoryArith3::solvedForm(const vector& solvedEqs) { DebugAssert(solvedEqs.size() > 0, "TheoryArith3::solvedForm()"); // Trace code TRACE_MSG("arith eq", "TheoryArith3::solvedForm:solvedEqs(\n ["); IF_DEBUG(if(debugger.trace("arith eq")) { for(vector::const_iterator j = solvedEqs.begin(), jend=solvedEqs.end(); j!=jend;++j) TRACE("arith eq", "", j->getExpr(), ",\n "); }) TRACE_MSG("arith eq", " ]) {"); // End of Trace code vector::const_reverse_iterator i = solvedEqs.rbegin(), iend = solvedEqs.rend(); // Substitution map: a variable 'x' is mapped to a Theorem x=t. // This map accumulates the resulting solved form. ExprMap subst; for(; i!=iend; ++i) { if(i->isRewrite()) { Theorem thm = substAndCanonize(*i, subst); TRACE("arith eq", "solvedForm: subst["+i->getLHS().toString()+"] = ", thm.getExpr(), ""); subst[i->getLHS()] = thm; } else { // This is the FALSE case: just return the contradiction DebugAssert(i->getExpr().isFalse(), "TheoryArith3::solvedForm: an element of solvedEqs must " "be either EQ or FALSE: "+i->toString()); return *i; } } // Now we've collected the solved form in 'subst'. Wrap it up into // a conjunction and return. vector thms; for(ExprMap::iterator i=subst.begin(), iend=subst.end(); i!=iend; ++i) thms.push_back(i->second); if (thms.size() > 1) return getCommonRules()->andIntro(thms); else return thms.back(); } /*! * ASSUMPTION: 't' is a fully canonized arithmetic term, and every * element of subst is a fully canonized equation of the form x=e, * indexed by the LHS variable. */ Theorem TheoryArith3::substAndCanonize(const Expr& t, ExprMap& subst) { TRACE("arith eq", "substAndCanonize(", t, ") {"); // Quick and dirty check: return immediately if subst is empty if(subst.empty()) { Theorem res(reflexivityRule(t)); TRACE("arith eq", "substAndCanonize[subst empty] => ", res, " }"); return res; } // Check if we can substitute 't' directly ExprMap::iterator i = subst.find(t), iend=subst.end(); if(i!=iend) { TRACE("arith eq", "substAndCanonize[subst] => ", i->second, " }"); return i->second; } // The base case: t is an i-leaf if(isLeaf(t)) { Theorem res(reflexivityRule(t)); TRACE("arith eq", "substAndCanonize[i-leaf] => ", res, " }"); return res; } // 't' is an arithmetic term; recurse into the children vector thms; vector changed; for(unsigned j=0, jend=t.arity(); j!=jend; ++j) { Theorem thm = substAndCanonize(t[j], subst); if(thm.getRHS() != t[j]) { thm = canonThm(thm); thms.push_back(thm); changed.push_back(j); } } // Do the actual substitution and canonize the result Theorem res; if(thms.size() > 0) { res = substitutivityRule(t, changed, thms); res = canonThm(res); } else res = reflexivityRule(t); TRACE("arith eq", "substAndCanonize => ", res, " }"); return res; } /*! * ASSUMPTION: 't' is a fully canonized equation of the form x = t, * and so is every element of subst, indexed by the LHS variable. */ Theorem TheoryArith3::substAndCanonize(const Theorem& eq, ExprMap& subst) { // Quick and dirty check: return immediately if subst is empty if(subst.empty()) return eq; DebugAssert(eq.isRewrite(), "TheoryArith3::substAndCanonize: t = " +eq.getExpr().toString()); const Expr& t = eq.getRHS(); // Do the actual substitution in the term t Theorem thm = substAndCanonize(t, subst); // Substitution had no result: return the original equation if(thm.getRHS() == t) return eq; // Otherwise substitute the result into the equation vector thms; vector changed; thms.push_back(thm); changed.push_back(1); return iffMP(eq, substitutivityRule(eq.getExpr(), changed, thms)); } void TheoryArith3::processBuffer() { // Process the inequalities in the buffer bool varOnRHS; for(; !inconsistent() && d_bufferIdx < d_buffer.size(); d_bufferIdx = d_bufferIdx+1) { const Theorem& ineqThm = d_buffer[d_bufferIdx]; // Skip this inequality if it is stale if(isStale(ineqThm.getExpr())) continue; Theorem thm1 = isolateVariable(ineqThm, varOnRHS); const Expr& ineq = thm1.getExpr(); if((ineq).isFalse()) setInconsistent(thm1); else if(!ineq.isTrue()) { // Check that the variable is indeed isolated correctly DebugAssert(varOnRHS? !isPlus(ineq[1]) : !isPlus(ineq[0]), "TheoryArith3::processBuffer(): bad result from " "isolateVariable:\nineq = "+ineq.toString()); // and project the inequality projectInequalities(thm1, varOnRHS); } } } void TheoryArith3::updateStats(const Rational& c, const Expr& v) { TRACE("arith ineq", "updateStats("+c.toString()+", ", v, ")"); // Dejan: update the max coefficient of the variable if (c < 0) { // Goes to the left side CDMap::iterator maxFind = maxCoefficientLeft.find(v); if (maxFind == maxCoefficientLeft.end()) maxCoefficientLeft[v] = - c; else if ((*maxFind).second < -c) (*maxFind).second = -c; } else { // Stays on the right side CDMap::iterator maxFind = maxCoefficientRight.find(v); if (maxFind == maxCoefficientRight.end()) maxCoefficientRight[v] = c; else if((*maxFind).second < c) (*maxFind).second = c; } if(c > 0) { if(d_countRight.count(v) > 0) d_countRight[v] = d_countRight[v] + 1; else d_countRight[v] = 1; } else if(d_countLeft.count(v) > 0) d_countLeft[v] = d_countLeft[v] + 1; else d_countLeft[v] = 1; } void TheoryArith3::updateStats(const Expr& monomial) { Expr c, m; separateMonomial(monomial, c, m); updateStats(c.getRational(), m); } void TheoryArith3::addToBuffer(const Theorem& thm) { // First, turn the inequality into 0 < rhs // FIXME: check if this can be optimized away Theorem result(thm); const Expr& e = thm.getExpr(); // int kind = e.getKind(); if(!(e[0].isRational() && e[0].getRational() == 0)) { result = iffMP(result, d_rules->rightMinusLeft(e)); result = canonPred(result); } TRACE("arith ineq", "addToBuffer(", result.getExpr(), ")"); // Push it into the buffer d_buffer.push_back(thm); // Collect the statistics about variables const Expr& rhs = thm.getExpr()[1]; if(isPlus(rhs)) for(Expr::iterator i=rhs.begin(), iend=rhs.end(); i!=iend; ++i) updateStats(*i); else // It's a monomial updateStats(rhs); } Theorem TheoryArith3::isolateVariable(const Theorem& inputThm, bool& isolatedVarOnRHS) { Theorem result(inputThm); const Expr& e = inputThm.getExpr(); TRACE("arith","isolateVariable(",e,") {"); TRACE("arith ineq", "isolateVariable(", e, ") {"); //we assume all the children of e are canonized DebugAssert(isLT(e)||isLE(e), "TheoryArith3::isolateVariable: " + e.toString() + " wrong kind"); int kind = e.getKind(); DebugAssert(e[0].isRational() && e[0].getRational() == 0, "TheoryArith3::isolateVariable: theorem must be of " "the form 0 < rhs: " + inputThm.toString()); const Expr& zero = e[0]; Expr right = e[1]; // Check for trivial in-equation. if (right.isRational()) { result = iffMP(result, d_rules->constPredicate(e)); TRACE("arith ineq","isolateVariable => ",result.getExpr()," }"); TRACE("arith","isolateVariable => ",result," }"); return result; } // Normalization of inequality to make coefficients integer and // relatively prime. Expr factor(computeNormalFactor(right)); TRACE("arith", "isolateVariable: factor = ", factor, ""); DebugAssert(factor.getRational() > 0, "isolateVariable: factor="+factor.toString()); // Now multiply the inequality by the factor, unless it is 1 if(factor.getRational() != 1) { result = iffMP(result, d_rules->multIneqn(e, factor)); // And canonize the result result = canonPred(result); right = result.getExpr()[1]; } // Find monomial to isolate and store it in isolatedMonomial Expr isolatedMonomial = right; if (isPlus(right)) isolatedMonomial = pickMonomial(right); Rational r = -1; isolatedVarOnRHS = true; if (isMult(isolatedMonomial)) { r = ((isolatedMonomial[0].getRational()) >= 0)? -1 : 1; isolatedVarOnRHS = ((isolatedMonomial[0].getRational()) >= 0)? true : false; } isolatedMonomial = canon(rat(-1)*isolatedMonomial).getRHS(); // Isolate isolatedMonomial on to the LHS result = iffMP(result, d_rules->plusPredicate(zero, right, isolatedMonomial, kind)); // Canonize the resulting inequality result = canonPred(result); if(1 != r) { result = iffMP(result, d_rules->multIneqn(result.getExpr(), rat(r))); result = canonPred(result); } TRACE("arith ineq","isolateVariable => ",result.getExpr()," }"); TRACE("arith","isolateVariable => ",result," }"); return result; } Expr TheoryArith3::computeNormalFactor(const Expr& right) { // Strategy: compute f = lcm(d1...dn)/gcd(c1...cn), where the RHS is // of the form c1/d1*x1 + ... + cn/dn*xn Rational factor; if(isPlus(right)) { vector nums, denoms; for(int i=0, iend=right.arity(); i fc.getConst() || (c == fc.getConst() && strict && !fc.strict())); } bool res; if(subsumed) { res = true; TRACE("arith ineq", "isStale[subsumed] => ", res? "true" : "false", " }"); } else { res = isStale(ineqExpr); TRACE("arith ineq", "isStale[updated] => ", res? "true" : "false", " }"); } return res; } void TheoryArith3::separateMonomial(const Expr& e, Expr& c, Expr& var) { TRACE("separateMonomial", "separateMonomial(", e, ")"); DebugAssert(!isPlus(e), "TheoryArith3::separateMonomial(e = "+e.toString()+")"); if(isMult(e)) { DebugAssert(e.arity() >= 2, "TheoryArith3::separateMonomial(e = "+e.toString()+")"); c = e[0]; if(e.arity() == 2) var = e[1]; else { vector kids = e.getKids(); kids[0] = rat(1); var = multExpr(kids); } } else { c = rat(1); var = e; } DebugAssert(c.isRational(), "TheoryArith3::separateMonomial(e = " +e.toString()+", c = "+c.toString()+")"); DebugAssert(!isMult(var) || (var[0].isRational() && var[0].getRational()==1), "TheoryArith3::separateMonomial(e = " +e.toString()+", var = "+var.toString()+")"); } void TheoryArith3::projectInequalities(const Theorem& theInequality, bool isolatedVarOnRHS) { TRACE("arith ineq", "projectInequalities(", theInequality.getExpr(), ", isolatedVarOnRHS="+string(isolatedVarOnRHS? "true" : "false") +") {"); DebugAssert(isLE(theInequality.getExpr()) || isLT(theInequality.getExpr()), "TheoryArith3::projectIsolatedVar: "\ "theInequality is of the wrong form: " + theInequality.toString()); //TODO: DebugAssert to check if the isolatedMonomial is of the right //form and the whether we are indeed getting inequalities. Theorem theIneqThm(theInequality); Expr theIneq = theIneqThm.getExpr(); Theorem isIntLHS(isIntegerThm(theIneq[0])); Theorem isIntRHS(isIntegerThm(theIneq[1])); bool isInt = (!isIntLHS.isNull() && !isIntRHS.isNull()); // If the inequality is strict and integer, change it to non-strict if(isLT(theIneq) && isInt) { Theorem thm = d_rules->lessThanToLE(theInequality, isIntLHS, isIntRHS, !isolatedVarOnRHS); theIneqThm = canonPred(iffMP(theIneqThm, thm)); theIneq = theIneqThm.getExpr(); } Expr isolatedMonomial = isolatedVarOnRHS ? theIneq[1] : theIneq[0]; Expr monomialVar, a; separateMonomial(isolatedMonomial, a, monomialVar); bool subsumed; const FreeConst& bestConst = updateSubsumptionDB(theIneq, isolatedVarOnRHS, subsumed); if(subsumed) { IF_DEBUG(debugger.counter("subsumed inequalities")++;) TRACE("arith ineq", "subsumed inequality: ", theIneq, ""); } else { // If the isolated variable is actually a non-linear term, we are // incomplete if(isMult(monomialVar) || isPow(monomialVar)) setIncomplete("Non-linear arithmetic inequalities"); // First, we need to make sure the isolated inequality is // setup properly. // setupRec(theIneq[0]); // setupRec(theIneq[1]); theoryCore()->setupTerm(theIneq[0], this, theIneqThm); theoryCore()->setupTerm(theIneq[1], this, theIneqThm); // Add the inequality into the appropriate DB. ExprMap *>& db1 = isolatedVarOnRHS ? d_inequalitiesRightDB : d_inequalitiesLeftDB; ExprMap *>::iterator it1 = db1.find(monomialVar); if(it1 == db1.end()) { CDList * list = new(true) CDList(theoryCore()->getCM()->getCurrentContext()); list->push_back(Ineq(theIneqThm, isolatedVarOnRHS, bestConst)); db1[monomialVar] = list; } else ((*it1).second)->push_back(Ineq(theIneqThm, isolatedVarOnRHS, bestConst)); ExprMap *>& db2 = isolatedVarOnRHS ? d_inequalitiesLeftDB : d_inequalitiesRightDB; ExprMap *>::iterator it = db2.find(monomialVar); if(it == db2.end()) { TRACE_MSG("arith ineq", "projectInequalities[not in DB] => }"); return; } CDList& listOfDBIneqs = *((*it).second); Theorem betaLTt, tLTalpha, thm; for(size_t i = 0, iend=listOfDBIneqs.size(); i!=iend; ++i) { const Ineq& ineqEntry = listOfDBIneqs[i]; const Theorem& ineqThm = ineqEntry.ineq(); if(!isStale(ineqEntry)) { betaLTt = isolatedVarOnRHS ? theIneqThm : ineqThm; tLTalpha = isolatedVarOnRHS ? ineqThm : theIneqThm; thm = normalizeProjectIneqs(betaLTt, tLTalpha); IF_DEBUG(debugger.counter("real shadows")++;) // Check for TRUE and FALSE theorems Expr e(thm.getExpr()); if(e.isFalse()) { setInconsistent(thm); TRACE_MSG("arith ineq", "projectInequalities[inconsistent] => }"); return; } else { if(!e.isTrue() && !e.isEq()) addToBuffer(thm); else if(e.isEq()) enqueueFact(thm); } } else { IF_DEBUG(debugger.counter("stale inequalities")++;) } } } TRACE_MSG("arith ineq", "projectInequalities => }"); } Theorem TheoryArith3::normalizeProjectIneqs(const Theorem& ineqThm1, const Theorem& ineqThm2) { //ineq1 is of the form beta < b.x or beta < x [ or with <= ] //ineq2 is of the form a.x < alpha or x < alpha. Theorem betaLTt = ineqThm1, tLTalpha = ineqThm2; Expr ineq1 = betaLTt.getExpr(); Expr ineq2 = tLTalpha.getExpr(); Expr c,x; separateMonomial(ineq2[0], c, x); Theorem isIntx(isIntegerThm(x)); Theorem isIntBeta(isIntegerThm(ineq1[0])); Theorem isIntAlpha(isIntegerThm(ineq2[1])); bool isInt = !(isIntx.isNull() || isIntBeta.isNull() || isIntAlpha.isNull()); TRACE("arith ineq", "normalizeProjectIneqs(", ineq1, ", "+ineq2.toString()+") {"); DebugAssert((isLE(ineq1) || isLT(ineq1)) && (isLE(ineq2) || isLT(ineq2)), "TheoryArith3::normalizeProjectIneqs: Wrong Kind inputs: " + ineq1.toString() + ineq2.toString()); DebugAssert(!isPlus(ineq1[1]) && !isPlus(ineq2[0]), "TheoryArith3::normalizeProjectIneqs: Wrong Kind inputs: " + ineq1.toString() + ineq2.toString()); //compute the factors to multiply the two inequalities with //so that they get the form beta < t and t < alpha. Rational factor1 = 1, factor2 = 1; Rational b = isMult(ineq1[1]) ? (ineq1[1])[0].getRational() : 1; Rational a = isMult(ineq2[0]) ? (ineq2[0])[0].getRational() : 1; if(b != a) { factor1 = a; factor2 = b; } //if the ineqs are of type int then apply one of the gray //dark shadow rules. // FIXME: intResult should also be checked for immediate // optimizations, as those below for 'result'. Also, if intResult // is a single inequality, we may want to handle it similarly to the // 'result' rather than enqueuing directly. if(isInt && (a >= 2 || b >= 2)) { Theorem intResult; if(a <= b) intResult = d_rules->darkGrayShadow2ab(betaLTt, tLTalpha, isIntAlpha, isIntBeta, isIntx); else intResult = d_rules->darkGrayShadow2ba(betaLTt, tLTalpha, isIntAlpha, isIntBeta, isIntx); enqueueFact(intResult); // Fetch dark and gray shadows const Expr& DorG = intResult.getExpr(); DebugAssert(DorG.isOr() && DorG.arity()==2, "DorG = "+DorG.toString()); const Expr& D = DorG[0]; const Expr& G = DorG[1]; DebugAssert(D.getKind()==DARK_SHADOW, "D = "+D.toString()); DebugAssert(G.getKind()==GRAY_SHADOW, "G = "+G.toString()); // Set the higher splitter priority for dark shadow Expr tmp = simplifyExpr(D); if (!tmp.isBoolConst()) addSplitter(tmp, 5); // Also set a higher priority to the NEGATION of GRAY_SHADOW tmp = simplifyExpr(!G); if (!tmp.isBoolConst()) addSplitter(tmp, 1); IF_DEBUG(debugger.counter("dark+gray shadows")++;) } //actually normalize the inequalities if(1 != factor1) { std::vector thms1; Theorem thm2 = iffMP(betaLTt, d_rules->multIneqn(ineq1, rat(factor1))); betaLTt = canonPred(thm2); ineq1 = betaLTt.getExpr(); } if(1 != factor2) { std::vector thms1; Theorem thm2 = iffMP(tLTalpha, d_rules->multIneqn(ineq2, rat(factor2))); tLTalpha = canonPred(thm2); ineq2 = tLTalpha.getExpr(); } //IF_DEBUG(debugger.counter("real shadows")++;) Expr beta(ineq1[0]); Expr alpha(ineq2[1]); // In case of alpha <= t <= alpha, we generate t = alpha if(isLE(ineq1) && isLE(ineq2) && alpha == beta) { Theorem result = d_rules->realShadowEq(betaLTt, tLTalpha); TRACE("arith ineq", "normalizeProjectIneqs => ", result, " }"); return result; } // Check if this inequality is a finite interval if(isInt) processFiniteInterval(betaLTt, tLTalpha); //project the normalized inequalities. Theorem result = d_rules->realShadow(betaLTt, tLTalpha); // FIXME: Clark's changes. Is 'rewrite' more or less efficient? // result = iffMP(result, rewrite(result.getExpr())); // TRACE("arith ineq", "normalizeProjectIneqs => ", result, " }"); // Now, transform the result into 0 < rhs and see if rhs is a const Expr e(result.getExpr()); // int kind = e.getKind(); if(!(e[0].isRational() && e[0].getRational() == 0)) { result = iffMP(result, d_rules->rightMinusLeft(e)); result = canonPred(result); } //result is "0 kind e'". where e' is equal to canon(e[1]-e[0]) Expr right = result.getExpr()[1]; // Check for trivial inequality if (right.isRational()) result = iffMP(result, d_rules->constPredicate(result.getExpr())); TRACE("arith ineq", "normalizeProjectIneqs => ", result, " }"); return result; } Rational TheoryArith3::currentMaxCoefficient(Expr var) { bool foundLeft = false; bool foundRight = false; Rational leftMax = 1; Rational rightMax = 1; // If the coefitient was found earlier and fixed, just return it CDMap::iterator findFixed = fixedMaxCoefficient.find(var); if (findFixed != fixedMaxCoefficient.end()) return (*findFixed).second; // Find the biggest left side coefficient CDMap::iterator findMaxLeft = maxCoefficientLeft.find(var); if (findMaxLeft != maxCoefficientLeft.end()) { foundLeft = true; leftMax = (*findMaxLeft).second; } // CDMap::iterator findMaxRight = maxCoefficientRight.find(var); if (findMaxRight != maxCoefficientRight.end()) { foundRight = true; rightMax = (*findMaxRight).second; } if (foundLeft && foundRight) { if (leftMax < rightMax) return rightMax; else return leftMax; } return Rational(1) / (leftMax * rightMax); } void TheoryArith3::fixCurrentMaxCoefficient(Expr var, Rational max) { fixedMaxCoefficient[var] = max; } void TheoryArith3::selectSmallestByCoefficient(vector input, vector& output) { // Clear the output vector output.clear(); // Get the first variable, and set it as best Expr best_variable = input[0]; Rational best_coefficient = currentMaxCoefficient(best_variable); output.push_back(best_variable); for(unsigned int i = 1; i < input.size(); i ++) { // Get the current variable Expr current_variable = input[i]; // Get the current variable's max coefficient Rational current_coefficient = currentMaxCoefficient(current_variable); // If strictly better than the current best, remember it if ((current_coefficient < best_coefficient)) { best_variable = current_variable; best_coefficient = current_coefficient; output.clear(); } // If equal to the current best, push it to the stack if (current_coefficient == best_coefficient) output.push_back(current_variable); } // Fix the selected best coefficient fixCurrentMaxCoefficient(best_variable, best_coefficient); } Expr TheoryArith3::pickMonomial(const Expr& right) { DebugAssert(isPlus(right), "TheoryArith3::pickMonomial: Wrong Kind: " + right.toString()); if(theoryCore()->getFlags()["var-order"].getBool()) { Expr::iterator i = right.begin(); Expr isolatedMonomial = right[1]; //PLUS always has at least two elements and the first element is //always a constant. hence ++i in the initialization of the for //loop. for(++i; i != right.end(); ++i) if(lessThanVar(isolatedMonomial,*i)) isolatedMonomial = *i; return isolatedMonomial; } ExprMap var2monomial; vector vars; Expr::iterator i = right.begin(), iend = right.end(); for(;i != iend; ++i) { if(i->isRational()) continue; Expr c, var; separateMonomial(*i, c, var); var2monomial[var] = *i; vars.push_back(var); } vector largest; d_graph.selectLargest(vars, largest); DebugAssert(0 < largest.size(), "TheoryArith3::pickMonomial: selectLargest: failed!!!!"); // DEJAN: Rafine the largest by coefficient values vector largest_small_coeff; selectSmallestByCoefficient(largest, largest_small_coeff); DebugAssert(0 < largest_small_coeff.size(), "TheoryArith3::pickMonomial: selectLargestByCOefficient: failed!!!!"); size_t pickedVar = 0; // Pick the variable which will generate the fewest number of // projections size_t size = largest_small_coeff.size(); int minProjections = -1; if (size > 1) for(size_t k=0; k< size; ++k) { const Expr& var(largest_small_coeff[k]), monom(var2monomial[var]); // Grab the counters for the variable int nRight = (d_countRight.count(var) > 0)? d_countRight[var] : 0; int nLeft = (d_countLeft.count(var) > 0)? d_countLeft[var] : 0; int n(nRight*nLeft); TRACE("arith ineq", "pickMonomial: var=", var, ", nRight="+int2string(nRight)+", nLeft="+int2string(nLeft)); if(minProjections < 0 || minProjections > n) { minProjections = n; pickedVar = k; } TRACE("arith ineq", "Number of projections for "+var.toString()+" = ", n, ""); } const Expr& largestVar = largest_small_coeff[pickedVar]; // FIXME: TODO: update the counters (subtract counts for the vars // other than largestVar // Update the graph (all edges to the largest in the graph, not just the small coefficients). for(size_t k = 0; k < vars.size(); ++k) { if(vars[k] != largestVar) d_graph.addEdge(largestVar, vars[k]); } return var2monomial[largestVar]; } void TheoryArith3::VarOrderGraph::addEdge(const Expr& e1, const Expr& e2) { TRACE("arith var order", "addEdge("+e1.toString()+" > ", e2, ")"); DebugAssert(e1 != e2, "TheoryArith3::VarOrderGraph::addEdge(" +e1.toString()+", "+e2.toString()+")"); d_edges[e1].push_back(e2); } //returns true if e1 < e2, else false(i.e e2 < e1 or e1,e2 are not //comparable) bool TheoryArith3::VarOrderGraph::lessThan(const Expr& e1, const Expr& e2) { d_cache.clear(); //returns true if e1 is in the subtree rooted at e2 implying e1 < e2 return dfs(e1,e2); } //returns true if e1 is in the subtree rooted at e2 implying e1 < e2 bool TheoryArith3::VarOrderGraph::dfs(const Expr& e1, const Expr& e2) { if(e1 == e2) return true; if(d_cache.count(e2) > 0) return false; if(d_edges.count(e2) == 0) return false; d_cache[e2] = true; vector& e2Edges = d_edges[e2]; vector::iterator i = e2Edges.begin(); vector::iterator iend = e2Edges.end(); //if dfs finds e1 then i != iend else i is equal to iend for(; i != iend && !dfs(e1,*i); ++i); return (i != iend); } void TheoryArith3::VarOrderGraph::selectSmallest(vector& v1, vector& v2) { int v1Size = v1.size(); vector v3(v1Size); for(int j=0; j < v1Size; ++j) v3[j] = false; for(int j=0; j < v1Size; ++j) { if(v3[j]) continue; for(int i =0; i < v1Size; ++i) { if((i == j) || v3[i]) continue; if(lessThan(v1[i],v1[j])) { v3[j] = true; break; } } } vector new_v1; for(int j = 0; j < v1Size; ++j) if(!v3[j]) v2.push_back(v1[j]); else new_v1.push_back(v1[j]); v1 = new_v1; } void TheoryArith3::VarOrderGraph::selectLargest(const vector& v1, vector& v2) { int v1Size = v1.size(); vector v3(v1Size); for(int j=0; j < v1Size; ++j) v3[j] = false; for(int j=0; j < v1Size; ++j) { if(v3[j]) continue; for(int i =0; i < v1Size; ++i) { if((i == j) || v3[i]) continue; if(lessThan(v1[j],v1[i])) { v3[j] = true; break; } } } for(int j = 0; j < v1Size; ++j) if(!v3[j]) v2.push_back(v1[j]); } /////////////////////////////////////////////////////////////////////////////// // TheoryArith3 Public Methods // /////////////////////////////////////////////////////////////////////////////// TheoryArith3::TheoryArith3(TheoryCore* core) : TheoryArith(core, "Arithmetic3"), d_diseq(core->getCM()->getCurrentContext()), d_diseqIdx(core->getCM()->getCurrentContext(), 0, 0), d_inModelCreation(core->getCM()->getCurrentContext(), false, 0), d_freeConstDB(core->getCM()->getCurrentContext()), d_buffer(core->getCM()->getCurrentContext()), // Initialize index to 0 at scope 0 d_bufferIdx(core->getCM()->getCurrentContext(), 0, 0), d_bufferThres(&(core->getFlags()["ineq-delay"].getInt())), d_countRight(core->getCM()->getCurrentContext()), d_countLeft(core->getCM()->getCurrentContext()), d_sharedTerms(core->getCM()->getCurrentContext()), d_sharedVars(core->getCM()->getCurrentContext()), maxCoefficientLeft(core->getCM()->getCurrentContext()), maxCoefficientRight(core->getCM()->getCurrentContext()), fixedMaxCoefficient(core->getCM()->getCurrentContext()) { IF_DEBUG(d_diseq.setName("CDList[TheoryArith3::d_diseq]");) IF_DEBUG(d_buffer.setName("CDList[TheoryArith3::d_buffer]");) IF_DEBUG(d_bufferIdx.setName("CDList[TheoryArith3::d_bufferIdx]");) getEM()->newKind(REAL, "_REAL", true); getEM()->newKind(INT, "_INT", true); getEM()->newKind(SUBRANGE, "_SUBRANGE", true); getEM()->newKind(UMINUS, "_UMINUS"); getEM()->newKind(PLUS, "_PLUS"); getEM()->newKind(MINUS, "_MINUS"); getEM()->newKind(MULT, "_MULT"); getEM()->newKind(DIVIDE, "_DIVIDE"); getEM()->newKind(POW, "_POW"); getEM()->newKind(INTDIV, "_INTDIV"); getEM()->newKind(MOD, "_MOD"); getEM()->newKind(LT, "_LT"); getEM()->newKind(LE, "_LE"); getEM()->newKind(GT, "_GT"); getEM()->newKind(GE, "_GE"); getEM()->newKind(IS_INTEGER, "_IS_INTEGER"); getEM()->newKind(NEGINF, "_NEGINF"); getEM()->newKind(POSINF, "_POSINF"); getEM()->newKind(DARK_SHADOW, "_DARK_SHADOW"); getEM()->newKind(GRAY_SHADOW, "_GRAY_SHADOW"); getEM()->newKind(REAL_CONST, "_REAL_CONST"); vector kinds; kinds.push_back(REAL); kinds.push_back(INT); kinds.push_back(SUBRANGE); kinds.push_back(IS_INTEGER); kinds.push_back(UMINUS); kinds.push_back(PLUS); kinds.push_back(MINUS); kinds.push_back(MULT); kinds.push_back(DIVIDE); kinds.push_back(POW); kinds.push_back(INTDIV); kinds.push_back(MOD); kinds.push_back(LT); kinds.push_back(LE); kinds.push_back(GT); kinds.push_back(GE); kinds.push_back(RATIONAL_EXPR); kinds.push_back(NEGINF); kinds.push_back(POSINF); kinds.push_back(DARK_SHADOW); kinds.push_back(GRAY_SHADOW); kinds.push_back(REAL_CONST); registerTheory(this, kinds, true); d_rules = createProofRules3(); d_realType = Type(getEM()->newLeafExpr(REAL)); d_intType = Type(getEM()->newLeafExpr(INT)); } // Destructor: delete the proof rules class if it's present TheoryArith3::~TheoryArith3() { if(d_rules != NULL) delete d_rules; // Clear the inequality databases for(ExprMap *>::iterator i=d_inequalitiesRightDB.begin(), iend=d_inequalitiesRightDB.end(); i!=iend; ++i) { delete (i->second); free(i->second); } for(ExprMap *>::iterator i=d_inequalitiesLeftDB.begin(), iend=d_inequalitiesLeftDB.end(); i!=iend; ++i) { delete (i->second); free (i->second); } } void TheoryArith3::collectVars(const Expr& e, vector& vars, set& cache) { // Check the cache first if(cache.count(e) > 0) return; // Not processed yet. Cache the expression and proceed cache.insert(e); if(isLeaf(e)) vars.push_back(e); else for(Expr::iterator i=e.begin(), iend=e.end(); i!=iend; ++i) collectVars(*i, vars, cache); } void TheoryArith3::processFiniteInterval(const Theorem& alphaLEax, const Theorem& bxLEbeta) { const Expr& ineq1(alphaLEax.getExpr()); const Expr& ineq2(bxLEbeta.getExpr()); DebugAssert(isLE(ineq1), "TheoryArith3::processFiniteInterval: ineq1 = " +ineq1.toString()); DebugAssert(isLE(ineq2), "TheoryArith3::processFiniteInterval: ineq2 = " +ineq2.toString()); // If the inequalities are not integer, just return (nothing to do) if(!isInteger(ineq1[0]) || !isInteger(ineq1[1]) || !isInteger(ineq2[0]) || !isInteger(ineq2[1])) return; const Expr& ax = ineq1[1]; const Expr& bx = ineq2[0]; DebugAssert(!isPlus(ax) && !isRational(ax), "TheoryArith3::processFiniteInterval:\n ax = "+ax.toString()); DebugAssert(!isPlus(bx) && !isRational(bx), "TheoryArith3::processFiniteInterval:\n bx = "+bx.toString()); Expr a = isMult(ax)? ax[0] : rat(1); Expr b = isMult(bx)? bx[0] : rat(1); Theorem thm1(alphaLEax), thm2(bxLEbeta); // Multiply the inequalities by 'b' and 'a', and canonize them, if necessary if(a != b) { thm1 = canonPred(iffMP(alphaLEax, d_rules->multIneqn(ineq1, b))); thm2 = canonPred(iffMP(bxLEbeta, d_rules->multIneqn(ineq2, a))); } // Check that a*beta - b*alpha == c > 0 const Expr& alphaLEt = thm1.getExpr(); const Expr& alpha = alphaLEt[0]; const Expr& t = alphaLEt[1]; const Expr& beta = thm2.getExpr()[1]; Expr c = canon(beta - alpha).getRHS(); if(c.isRational() && c.getRational() >= 1) { // This is a finite interval. First, derive t <= alpha + c: // canon(alpha+c) => (alpha+c == beta) ==> [symmetry] beta == alpha+c // Then substitute that in thm2 Theorem bEQac = symmetryRule(canon(alpha + c)); // Substitute beta == alpha+c for the second child of thm2 vector changed; vector thms; changed.push_back(1); thms.push_back(bEQac); Theorem tLEac = substitutivityRule(thm2.getExpr(), changed, thms); tLEac = iffMP(thm2, tLEac); // Derive and enqueue the finite interval constraint Theorem isInta(isIntegerThm(alpha)); Theorem isIntt(isIntegerThm(t)); enqueueFact(d_rules->finiteInterval(thm1, tLEac, isInta, isIntt)); } } void TheoryArith3::processFiniteIntervals(const Expr& x) { // If x is not integer, do not bother if(!isInteger(x)) return; // Process every pair of the opposing inequalities for 'x' ExprMap *>::iterator iLeft, iRight; iLeft = d_inequalitiesLeftDB.find(x); if(iLeft == d_inequalitiesLeftDB.end()) return; iRight = d_inequalitiesRightDB.find(x); if(iRight == d_inequalitiesRightDB.end()) return; // There are some opposing inequalities; get the lists CDList& ineqsLeft = *(iLeft->second); CDList& ineqsRight = *(iRight->second); // Get the sizes of the lists size_t sizeLeft = ineqsLeft.size(); size_t sizeRight = ineqsRight.size(); // Process all the pairs of the opposing inequalities for(size_t l=0; lwithout * caching until it hits a node that is already setup. Be * careful on what expressions you are calling it. */ void TheoryArith3::setupRec(const Expr& e) { if(e.hasFind()) return; // First, set up the kids recursively for (int k = 0; k < e.arity(); ++k) { setupRec(e[k]); } // Create a find pointer for e e.setFind(reflexivityRule(e)); e.setEqNext(reflexivityRule(e)); // And call our own setup() setup(e); } void TheoryArith3::addSharedTerm(const Expr& e) { d_sharedTerms[e] = true; } void TheoryArith3::assertFact(const Theorem& e) { TRACE("arith assert", "assertFact(", e.getExpr().toString(), ")"); const Expr& expr = e.getExpr(); if (expr.isNot() && expr[0].isEq()) { IF_DEBUG(debugger.counter("[arith] received disequalities")++;) d_diseq.push_back(e); } else if (!expr.isEq()){ if (expr.isNot()) { // This can only be negation of dark or gray shadows, or // disequalities, which we ignore. Negations of inequalities // are handled in rewrite, we don't even receive them here. } else if(isDarkShadow(expr)) { enqueueFact(d_rules->expandDarkShadow(e)); IF_DEBUG(debugger.counter("received DARK_SHADOW")++;) } else if(isGrayShadow(expr)) { IF_DEBUG(debugger.counter("received GRAY_SHADOW")++;) const Rational& c1 = expr[2].getRational(); const Rational& c2 = expr[3].getRational(); const Expr& v = expr[0]; const Expr& ee = expr[1]; if(c1 == c2) enqueueFact(d_rules->expandGrayShadow0(e)); else { Theorem gThm(e); // Check if we can reduce the number of cases in G(ax,c,c1,c2) if(ee.isRational() && isMult(v) && v[0].isRational() && v[0].getRational() >= 2) { IF_DEBUG(debugger.counter("reduced const GRAY_SHADOW")++;) gThm = d_rules->grayShadowConst(e); } // (Possibly) new gray shadow const Expr& g = gThm.getExpr(); if(g.isFalse()) setInconsistent(gThm); else if(g[2].getRational() == g[3].getRational()) enqueueFact(d_rules->expandGrayShadow0(gThm)); else { // Assert c1+e <= v <= c2+e enqueueFact(d_rules->expandGrayShadow(gThm)); // Split G into 2 cases (binary search b/w c1 and c2) Theorem thm2 = d_rules->splitGrayShadow(gThm); enqueueFact(thm2); // Fetch the two gray shadows DebugAssert(thm2.getExpr().isAnd() && thm2.getExpr().arity()==2, "thm2 = "+thm2.getExpr().toString()); const Expr& G1orG2 = thm2.getExpr()[0]; DebugAssert(G1orG2.isOr() && G1orG2.arity()==2, "G1orG2 = "+G1orG2.toString()); const Expr& G1 = G1orG2[0]; const Expr& G2 = G1orG2[1]; DebugAssert(G1.getKind()==GRAY_SHADOW, "G1 = "+G1.toString()); DebugAssert(G2.getKind()==GRAY_SHADOW, "G2 = "+G2.toString()); // Split on the left disjunct first (keep the priority low) Expr tmp = simplifyExpr(G1); if (!tmp.isBoolConst()) addSplitter(tmp, 1); tmp = simplifyExpr(G2); if (!tmp.isBoolConst()) addSplitter(tmp, -1); } } } else { DebugAssert(isLE(expr) || isLT(expr) || isIntPred(expr), "expected LE or LT: "+expr.toString()); if(isLE(expr) || isLT(expr)) { IF_DEBUG(debugger.counter("recevied inequalities")++;) // Assert the equivalent negated inequality Theorem thm; if (isLE(expr)) thm = d_rules->negatedInequality(!gtExpr(expr[0],expr[1])); else thm = d_rules->negatedInequality(!geExpr(expr[0],expr[1])); thm = symmetryRule(thm); Theorem thm2 = simplify(thm.getRHS()[0]); DebugAssert(thm2.getLHS() != thm2.getRHS(), "Expected rewrite"); thm2 = getCommonRules()->substitutivityRule(thm.getRHS(), thm2); thm = transitivityRule(thm, thm2); enqueueFact(iffMP(e, thm)); // Buffer the inequality addToBuffer(e); TRACE("arith ineq", "buffer.size() = ", d_buffer.size(), ", index="+int2string(d_bufferIdx) +", threshold="+int2string(*d_bufferThres)); if((((int)d_buffer.size()) - (int)d_bufferIdx > *d_bufferThres) && !d_inModelCreation) processBuffer(); } else { IF_DEBUG(debugger.counter("arith IS_INTEGER")++;) } } } else { IF_DEBUG(debugger.counter("[arith] received t1=t2")++;) } } void TheoryArith3::checkSat(bool fullEffort) { // vector::const_iterator e; // vector::const_iterator eEnd; // TODO: convert back to use iterators TRACE("arith checksat", "checksat(", fullEffort? "true" : "false", ")"); TRACE("arith ineq", "TheoryArith3::checkSat(fullEffort=", fullEffort? "true" : "false", ")"); if (fullEffort) { while(!inconsistent() && d_bufferIdx < d_buffer.size()) processBuffer(); if(d_inModelCreation) { for(; d_diseqIdx < d_diseq.size(); d_diseqIdx = d_diseqIdx+1) { TRACE("model", "[arith] refining diseq: ", d_diseq[d_diseqIdx].getExpr() , ""); enqueueFact(d_rules->diseqToIneq(d_diseq[d_diseqIdx])); } } } } void TheoryArith3::refineCounterExample() { d_inModelCreation = true; TRACE("model", "refineCounterExample[TheoryArith3] ", "", "{"); CDMap::iterator it = d_sharedTerms.begin(), it2, iend = d_sharedTerms.end(); // Add equalities over all pairs of shared terms as suggested // splitters. Notice, that we want to split on equality // (positively) first, to reduce the size of the model. for(; it!=iend; ++it) { // Copy by value: the elements in the pair from *it are NOT refs in CDMap Expr e1 = (*it).first; for(it2 = it, ++it2; it2!=iend; ++it2) { Expr e2 = (*it2).first; DebugAssert(isReal(getBaseType(e1)), "TheoryArith3::refineCounterExample: e1 = "+e1.toString() +"\n type(e1) = "+e1.getType().toString()); if(findExpr(e1) != findExpr(e2)) { DebugAssert(isReal(getBaseType(e2)), "TheoryArith3::refineCounterExample: e2 = "+e2.toString() +"\n type(e2) = "+e2.getType().toString()); Expr eq = simplifyExpr(e1.eqExpr(e2)); if (!eq.isBoolConst()) addSplitter(eq); } } } TRACE("model", "refineCounterExample[Theory::Arith] ", "", "}"); } void TheoryArith3::findRationalBound(const Expr& varSide, const Expr& ratSide, const Expr& var, Rational &r) { Expr c, x; separateMonomial(varSide, c, x); DebugAssert(findExpr(c).isRational(), "seperateMonomial failed"); DebugAssert(findExpr(ratSide).isRational(), "smallest variable in graph, should not have variables" " in inequalities: "); DebugAssert(x == var, "separateMonomial found different variable: " + var.toString()); r = findExpr(ratSide).getRational() / findExpr(c).getRational(); } bool TheoryArith3::findBounds(const Expr& e, Rational& lub, Rational& glb) { bool strictLB=false, strictUB=false; bool right = (d_inequalitiesRightDB.count(e) > 0 && d_inequalitiesRightDB[e]->size() > 0); bool left = (d_inequalitiesLeftDB.count(e) > 0 && d_inequalitiesLeftDB[e]->size() > 0); int numRight = 0, numLeft = 0; if(right) { //rationals less than e CDList * ratsLTe = d_inequalitiesRightDB[e]; for(unsigned int i=0; isize(); i++) { DebugAssert((*ratsLTe)[i].varOnRHS(), "variable on wrong side!"); Expr ineq = (*ratsLTe)[i].ineq().getExpr(); Expr leftSide = ineq[0], rightSide = ineq[1]; Rational r; findRationalBound(rightSide, leftSide, e , r); if(numRight==0 || r>glb){ glb = r; strictLB = isLT(ineq); } numRight++; } TRACE("model", " =>Lower bound ", glb.toString(), ""); } if(left) { //rationals greater than e CDList * ratsGTe = d_inequalitiesLeftDB[e]; for(unsigned int i=0; isize(); i++) { DebugAssert((*ratsGTe)[i].varOnLHS(), "variable on wrong side!"); Expr ineq = (*ratsGTe)[i].ineq().getExpr(); Expr leftSide = ineq[0], rightSide = ineq[1]; Rational r; findRationalBound(leftSide, rightSide, e, r); if(numLeft==0 || rUpper bound ", lub.toString(), ""); } if(!left && !right) { lub = 0; glb = 0; } if(!left && right) {lub = glb +2;} if(!right && left) {glb = lub-2;} DebugAssert(glb <= lub, "Greatest lower bound needs to be smaller " "than least upper bound"); return strictLB; } void TheoryArith3::assignVariables(std::vector&v) { int count = 0; while (v.size() > 0) { std::vector bottom; d_graph.selectSmallest(v, bottom); TRACE("model", "Finding variables to assign. Iteration # ", count, ""); for(unsigned int i = 0; i& v) { d_inModelCreation = true; vector reps; TRACE("model", "Arith=>computeModel ", "", "{"); for(unsigned int i=0; i is defined by: ", findExpr(e) , ""); } } assignVariables(reps); TRACE("model", "Arith=>computeModel", "", "}"); d_inModelCreation = false; } // For any arith expression 'e', if the subexpressions are assigned // concrete values, then find(e) must already be a concrete value. void TheoryArith3::computeModel(const Expr& e, vector& vars) { DebugAssert(findExpr(e).isRational(), "TheoryArith3::computeModel(" +e.toString()+")\n e is not assigned concrete value.\n" +" find(e) = "+findExpr(e).toString()); assignValue(simplify(e)); vars.push_back(e); } /*! accepts a rewrite theorem over eqn|ineqn and normalizes it * and returns a theorem to that effect. assumes e is non-trivial * i.e. e is not '0=const' or 'const=0' or '0 <= const' etc. */ Theorem TheoryArith3::normalize(const Expr& e) { //e is an eqn or ineqn. e is not a trivial eqn or ineqn //trivial means 0 = const or 0 <= const. TRACE("arith", "normalize(", e, ") {"); DebugAssert(e.isEq() || isIneq(e), "normalize: input must be Eq or Ineq: " + e.toString()); DebugAssert(!isIneq(e) || (0 == e[0].getRational()), "normalize: if (e is ineq) then e[0] must be 0" + e.toString()); if(e.isEq()) { if(e[0].isRational()) { DebugAssert(0 == e[0].getRational(), "normalize: if e is Eq and e[0] is rat then e[0]==0"); } else { //if e[0] is not rational then e[1] must be rational. DebugAssert(e[1].isRational() && 0 == e[1].getRational(), "normalize: if e is Eq and e[1] is rat then e[1]==0\n" " e = "+e.toString()); } } Expr factor; if(e[0].isRational()) factor = computeNormalFactor(e[1]); else factor = computeNormalFactor(e[0]); TRACE("arith", "normalize: factor = ", factor, ""); DebugAssert(factor.getRational() > 0, "normalize: factor="+ factor.toString()); Theorem thm(reflexivityRule(e)); // Now multiply the equality by the factor, unless it is 1 if(factor.getRational() != 1) { int kind = e.getKind(); switch(kind) { case EQ: thm = d_rules->multEqn(e[0], e[1], factor); // And canonize the result thm = canonPredEquiv(thm); break; case LE: case LT: case GE: case GT: thm = d_rules->multIneqn(e, factor); // And canonize the result thm = canonPredEquiv(thm); break; default: // MS .net doesn't accept "..." + int ostringstream ss; ss << "normalize: control should not reach here " << kind; DebugAssert(false, ss.str()); break; } } TRACE("arith", "normalize => ", thm, " }"); return(thm); } Theorem TheoryArith3::normalize(const Theorem& eIffEqn) { return transitivityRule(eIffEqn, normalize(eIffEqn.getRHS())); } Theorem TheoryArith3::rewrite(const Expr& e) { DebugAssert(leavesAreSimp(e), "Expected leaves to be simplified"); TRACE("arith", "TheoryArith3::rewrite(", e, ") {"); Theorem thm; if (!e.isTerm()) { if (!e.isAbsLiteral()) { e.setRewriteNormal(); thm = reflexivityRule(e); TRACE("arith", "TheoryArith3::rewrite[non-literal] => ", thm, " }"); return thm; } switch(e.getKind()) { case EQ: { // canonical form for an equality of two leaves // is just l == r instead of 0 + (-1 * l) + r = 0. if (isLeaf(e[0]) && isLeaf(e[1])) thm = reflexivityRule(e); else { // Otherwise, it is "lhs = 0" //first convert e to the form 0=e' if((e[0].isRational() && e[0].getRational() == 0) || (e[1].isRational() && e[1].getRational() == 0)) //already in 0=e' or e'=0 form thm = reflexivityRule(e); else { thm = d_rules->rightMinusLeft(e); thm = canonPredEquiv(thm); } // Check for trivial equation if ((thm.getRHS())[0].isRational() && (thm.getRHS())[1].isRational()) { thm = transitivityRule(thm, d_rules->constPredicate(thm.getRHS())); } else { //else equation is non-trivial thm = normalize(thm); // Normalization may yield non-simplified terms thm = canonPredEquiv(thm); } } // Equations must be oriented such that lhs >= rhs as Exprs; // this ordering is given by operator<(Expr,Expr). const Expr& eq = thm.getRHS(); if(eq.isEq() && eq[0] < eq[1]) thm = transitivityRule(thm, getCommonRules()->rewriteUsingSymmetry(eq)); } break; case GRAY_SHADOW: case DARK_SHADOW: thm = reflexivityRule(e); break; case IS_INTEGER: { Theorem res(isIntegerDerive(e, typePred(e[0]))); if(!res.isNull()) thm = getCommonRules()->iffTrue(res); else thm = reflexivityRule(e); break; } case NOT: if (!isIneq(e[0])) //in this case we have "NOT of DARK or GRAY_SHADOW." thm = reflexivityRule(e); else { //In this case we have the "NOT of ineq". get rid of NOT //and then treat like an ineq thm = d_rules->negatedInequality(e); DebugAssert(isGE(thm.getRHS()) || isGT(thm.getRHS()), "Expected GE or GT"); thm = transitivityRule(thm, d_rules->flipInequality(thm.getRHS())); thm = transitivityRule(thm, d_rules->rightMinusLeft(thm.getRHS())); thm = canonPredEquiv(thm); // Check for trivial inequation if ((thm.getRHS())[1].isRational()) thm = transitivityRule(thm, d_rules->constPredicate(thm.getRHS())); else { //else ineq is non-trivial thm = normalize(thm); // Normalization may yield non-simplified terms thm = canonPredEquiv(thm); } } break; case LE: case LT: case GE: case GT: if (isGE(e) || isGT(e)) { thm = d_rules->flipInequality(e); thm = transitivityRule(thm, d_rules->rightMinusLeft(thm.getRHS())); } else thm = d_rules->rightMinusLeft(e); thm = canonPredEquiv(thm); // Check for trivial inequation if ((thm.getRHS())[1].isRational()) thm = transitivityRule(thm, d_rules->constPredicate(thm.getRHS())); else { // ineq is non-trivial thm = normalize(thm); thm = canonPredEquiv(thm); } break; default: DebugAssert(false, "Theory_Arith::rewrite: control should not reach here"); break; } } else { if (e.isAtomic()) thm = canon(e); else thm = reflexivityRule(e); } // Arith canonization is idempotent if (theoryOf(thm.getRHS()) == this) thm.getRHS().setRewriteNormal(); TRACE("arith", "TheoryArith3::rewrite => ", thm, " }"); return thm; } void TheoryArith3::setup(const Expr& e) { if (!e.isTerm()) { if (e.isNot() || e.isEq() || isDarkShadow(e) || isGrayShadow(e)) return; if(e.getKind() == IS_INTEGER) { e[0].addToNotify(this, e); return; } DebugAssert((isLT(e)||isLE(e)) && e[0].isRational() && e[0].getRational() == 0, "TheoryArith3::setup: expected 0 < rhs:" + e.toString()); e[1].addToNotify(this, e); return; } int k(0), ar(e.arity()); for ( ; k < ar; ++k) { e[k].addToNotify(this, e); TRACE("arith setup", "e["+int2string(k)+"]: ", *(e[k].getNotify()), ""); } } void TheoryArith3::update(const Theorem& e, const Expr& d) { if (inconsistent()) return; IF_DEBUG(debugger.counter("arith update total")++;) if (!d.hasFind()) return; if (isIneq(d)) { // Substitute e[1] for e[0] in d and enqueue new inequality DebugAssert(e.getLHS() == d[1], "Mismatch"); Theorem thm = find(d); // DebugAssert(thm.getRHS() == trueExpr(), "Expected find = true"); vector changed; vector children; changed.push_back(1); children.push_back(e); Theorem thm2 = substitutivityRule(d, changed, children); if (thm.getRHS() == trueExpr()) { enqueueFact(iffMP(getCommonRules()->iffTrueElim(thm), thm2)); } else { enqueueFact(getCommonRules()->iffFalseElim( transitivityRule(symmetryRule(thm2), thm))); } IF_DEBUG(debugger.counter("arith update ineq")++;) } else if (find(d).getRHS() == d) { Theorem thm = canonSimp(d); TRACE("arith", "TheoryArith3::update(): thm = ", thm, ""); DebugAssert(leavesAreSimp(thm.getRHS()), "updateHelper error: " +thm.getExpr().toString()); assertEqualities(transitivityRule(thm, rewrite(thm.getRHS()))); IF_DEBUG(debugger.counter("arith update find(d)=d")++;) } } Theorem TheoryArith3::solve(const Theorem& thm) { DebugAssert(thm.isRewrite() && thm.getLHS().isTerm(), ""); const Expr& lhs = thm.getLHS(); const Expr& rhs = thm.getRHS(); // Check for already solved equalities. // Have to be careful about the types: integer variable cannot be // assigned a real term. Also, watch for e[0] being a subexpression // of e[1]: this would create an unsimplifiable expression. if (isLeaf(lhs) && !isLeafIn(lhs, rhs) && (lhs.getType() != intType() || isInteger(rhs)) // && !e[0].subExprOf(e[1]) ) return thm; // Symmetric version is already solved if (isLeaf(rhs) && !isLeafIn(rhs, lhs) && (rhs.getType() != intType() || isInteger(lhs)) // && !e[1].subExprOf(e[0]) ) return symmetryRule(thm); return doSolve(thm); } void TheoryArith3::computeModelTerm(const Expr& e, std::vector& v) { switch(e.getKind()) { case RATIONAL_EXPR: // Skip the constants break; case PLUS: case MULT: case DIVIDE: case POW: // This is not a variable; extract the variables from children for(Expr::iterator i=e.begin(), iend=e.end(); i!=iend; ++i) // getModelTerm(*i, v); v.push_back(*i); break; default: { // Otherwise it's a variable. Check if it has a find pointer Expr e2(findExpr(e)); if(e==e2) { TRACE("model", "TheoryArith3::computeModelTerm(", e, "): a variable"); // Leave it alone (it has no descendants) // v.push_back(e); } else { TRACE("model", "TheoryArith3::computeModelTerm("+e.toString() +"): has find pointer to ", e2, ""); v.push_back(e2); } } } } Expr TheoryArith3::computeTypePred(const Type& t, const Expr& e) { Expr tExpr = t.getExpr(); switch(tExpr.getKind()) { case INT: return Expr(IS_INTEGER, e); case SUBRANGE: { std::vector kids; kids.push_back(Expr(IS_INTEGER, e)); kids.push_back(leExpr(tExpr[0], e)); kids.push_back(leExpr(e, tExpr[1])); return andExpr(kids); } default: return e.getEM()->trueExpr(); } } void TheoryArith3::checkAssertEqInvariant(const Theorem& e) { if (e.isRewrite()) { DebugAssert(e.getLHS().isTerm(), "Expected equation"); if (isLeaf(e.getLHS())) { // should be in solved form DebugAssert(!isLeafIn(e.getLHS(),e.getRHS()), "Not in solved form: lhs appears in rhs"); } else { DebugAssert(e.getLHS().hasFind(), "Expected lhs to have find"); DebugAssert(!leavesAreSimp(e.getLHS()), "Expected at least one unsimplified leaf on lhs"); } DebugAssert(canonSimp(e.getRHS()).getRHS() == e.getRHS(), "Expected canonSimp(rhs) = canonSimp(rhs)"); } else { Expr expr = e.getExpr(); if (expr.isFalse()) return; vector eqs; Theorem thm; int index, index2; for (index = 0; index < expr.arity(); ++index) { thm = getCommonRules()->andElim(e, index); eqs.push_back(thm); if (thm.getExpr().isFalse()) return; DebugAssert(eqs[index].isRewrite() && eqs[index].getLHS().isTerm(), "Expected equation"); } // Check for solved form for (index = 0; index < expr.arity(); ++index) { DebugAssert(isLeaf(eqs[index].getLHS()), "expected leaf on lhs"); DebugAssert(canonSimp(eqs[index].getRHS()).getRHS() == eqs[index].getRHS(), "Expected canonSimp(rhs) = canonSimp(rhs)"); DebugAssert(recursiveCanonSimpCheck(eqs[index].getRHS()), "Failed recursive canonSimp check"); for (index2 = 0; index2 < expr.arity(); ++index2) { DebugAssert(index == index2 || eqs[index].getLHS() != eqs[index2].getLHS(), "Not in solved form: repeated lhs"); DebugAssert(!isLeafIn(eqs[index].getLHS(),eqs[index2].getRHS()), "Not in solved form: lhs appears in rhs"); } } } } void TheoryArith3::checkType(const Expr& e) { switch (e.getKind()) { case INT: case REAL: if (e.arity() > 0) { throw Exception("Ill-formed arithmetic type: "+e.toString()); } break; case SUBRANGE: if (e.arity() != 2 || !isIntegerConst(e[0]) || !isIntegerConst(e[1]) || e[0].getRational() > e[1].getRational()) { throw Exception("bad SUBRANGE type expression"+e.toString()); } break; default: DebugAssert(false, "Unexpected kind in TheoryArith3::checkType" +getEM()->getKindName(e.getKind())); } } Cardinality TheoryArith3::finiteTypeInfo(Expr& e, Unsigned& n, bool enumerate, bool computeSize) { Cardinality card = CARD_INFINITE; switch (e.getKind()) { case SUBRANGE: { card = CARD_FINITE; Expr typeExpr = e; if (enumerate) { Rational r = typeExpr[0].getRational() + n; if (r <= typeExpr[1].getRational()) { e = rat(r); } else e = Expr(); } if (computeSize) { Rational r = typeExpr[1].getRational() - typeExpr[0].getRational() + 1; n = r.getUnsigned(); } break; } default: break; } return card; } void TheoryArith3::computeType(const Expr& e) { switch (e.getKind()) { case REAL_CONST: e.setType(d_realType); break; case RATIONAL_EXPR: if(e.getRational().isInteger()) e.setType(d_intType); else e.setType(d_realType); break; case UMINUS: case PLUS: case MINUS: case MULT: case POW: { bool isInt = true; for(int k = 0; k < e.arity(); ++k) { if(d_realType != getBaseType(e[k])) throw TypecheckException("Expecting type REAL with `" + getEM()->getKindName(e.getKind()) + "',\n"+ "but got a " + getBaseType(e[k]).toString()+ " for:\n" + e.toString()); if(isInt && !isInteger(e[k])) isInt = false; } if(isInt) e.setType(d_intType); else e.setType(d_realType); break; } case DIVIDE: { Expr numerator = e[0]; Expr denominator = e[1]; if (getBaseType(numerator) != d_realType || getBaseType(denominator) != d_realType) { throw TypecheckException("Expecting only REAL types with `DIVIDE',\n" "but got " + getBaseType(numerator).toString()+ " and " + getBaseType(denominator).toString() + " for:\n" + e.toString()); } if(denominator.isRational() && 1 == denominator.getRational()) e.setType(numerator.getType()); else e.setType(d_realType); break; } case LT: case LE: case GT: case GE: case GRAY_SHADOW: // Need to know types for all exprs -Clark // e.setType(boolType()); // break; case DARK_SHADOW: for (int k = 0; k < e.arity(); ++k) { if (d_realType != getBaseType(e[k])) throw TypecheckException("Expecting type REAL with `" + getEM()->getKindName(e.getKind()) + "',\n"+ "but got a " + getBaseType(e[k]).toString()+ " for:\n" + e.toString()); } e.setType(boolType()); break; case IS_INTEGER: if(d_realType != getBaseType(e[0])) throw TypecheckException("Expected type REAL, but got " +getBaseType(e[0]).toString() +"\n\nExpr = "+e.toString()); e.setType(boolType()); break; default: DebugAssert(false,"TheoryArith3::computeType: unexpected expression:\n " +e.toString()); break; } } Type TheoryArith3::computeBaseType(const Type& t) { IF_DEBUG(int kind = t.getExpr().getKind();) DebugAssert(kind==INT || kind==REAL || kind==SUBRANGE, "TheoryArith3::computeBaseType("+t.toString()+")"); return realType(); } Expr TheoryArith3::computeTCC(const Expr& e) { Expr tcc(Theory::computeTCC(e)); switch(e.getKind()) { case DIVIDE: DebugAssert(e.arity() == 2, ""); return tcc.andExpr(!(e[1].eqExpr(rat(0)))); default: return tcc; } } /////////////////////////////////////////////////////////////////////////////// //parseExprOp: //translating special Exprs to regular EXPR?? /////////////////////////////////////////////////////////////////////////////// Expr TheoryArith3::parseExprOp(const Expr& e) { TRACE("parser", "TheoryArith3::parseExprOp(", e, ")"); //std::cout << "Were here"; // If the expression is not a list, it must have been already // parsed, so just return it as is. switch(e.getKind()) { case ID: { int kind = getEM()->getKind(e[0].getString()); switch(kind) { case NULL_KIND: return e; // nothing to do case REAL: case INT: case NEGINF: case POSINF: return getEM()->newLeafExpr(kind); default: DebugAssert(false, "Bad use of bare keyword: "+e.toString()); return e; } } case RAW_LIST: break; // break out of switch, do the hard work default: return e; } DebugAssert(e.getKind() == RAW_LIST && e.arity() > 0, "TheoryArith3::parseExprOp:\n e = "+e.toString()); const Expr& c1 = e[0][0]; int kind = getEM()->getKind(c1.getString()); switch(kind) { case UMINUS: { if(e.arity() != 2) throw ParserException("UMINUS requires exactly one argument: " +e.toString()); return uminusExpr(parseExpr(e[1])); } case PLUS: { vector k; Expr::iterator i = e.begin(), iend=e.end(); // Skip first element of the vector of kids in 'e'. // The first element is the operator. ++i; // Parse the kids of e and push them into the vector 'k' for(; i!=iend; ++i) k.push_back(parseExpr(*i)); return plusExpr(k); } case MINUS: { if(e.arity() == 2) return uminusExpr(parseExpr(e[1])); else if(e.arity() == 3) return minusExpr(parseExpr(e[1]), parseExpr(e[2])); else throw ParserException("MINUS requires one or two arguments:" +e.toString()); } case MULT: { vector k; Expr::iterator i = e.begin(), iend=e.end(); // Skip first element of the vector of kids in 'e'. // The first element is the operator. ++i; // Parse the kids of e and push them into the vector 'k' for(; i!=iend; ++i) k.push_back(parseExpr(*i)); return multExpr(k); } case POW: { return powExpr(parseExpr(e[1]), parseExpr(e[2])); } case DIVIDE: { return divideExpr(parseExpr(e[1]), parseExpr(e[2])); } case LT: { return ltExpr(parseExpr(e[1]), parseExpr(e[2])); } case LE: { return leExpr(parseExpr(e[1]), parseExpr(e[2])); } case GT: { return gtExpr(parseExpr(e[1]), parseExpr(e[2])); } case GE: { return geExpr(parseExpr(e[1]), parseExpr(e[2])); } case INTDIV: case MOD: case SUBRANGE: { vector k; Expr::iterator i = e.begin(), iend=e.end(); // Skip first element of the vector of kids in 'e'. // The first element is the operator. ++i; // Parse the kids of e and push them into the vector 'k' for(; i!=iend; ++i) k.push_back(parseExpr(*i)); return Expr(kind, k, e.getEM()); } case IS_INTEGER: { if(e.arity() != 2) throw ParserException("IS_INTEGER requires exactly one argument: " +e.toString()); return Expr(IS_INTEGER, parseExpr(e[1])); } default: DebugAssert(false, "TheoryArith3::parseExprOp: invalid input " + e.toString()); break; } return e; } /////////////////////////////////////////////////////////////////////////////// // Pretty-printing // /////////////////////////////////////////////////////////////////////////////// ExprStream& TheoryArith3::print(ExprStream& os, const Expr& e) { switch(os.lang()) { case SIMPLIFY_LANG: switch(e.getKind()) { case RATIONAL_EXPR: e.print(os); break; case SUBRANGE: os <<"ERROR:SUBRANGE:not supported in Simplify\n"; break; case IS_INTEGER: os <<"ERROR:IS_INTEGER:not supported in Simplify\n"; break; case PLUS: { int i=0, iend=e.arity(); os << "(+ "; if(i!=iend) os << e[i]; ++i; for(; i!=iend; ++i) os << " " << e[i]; os << ")"; break; } case MINUS: os << "(- " << e[0] << " " << e[1]<< ")"; break; case UMINUS: os << "-" << e[0] ; break; case MULT: { int i=0, iend=e.arity(); os << "(* " ; if(i!=iend) os << e[i]; ++i; for(; i!=iend; ++i) os << " " << e[i]; os << ")"; break; } case POW: os << "(" << push << e[1] << space << "^ " << e[0] << push << ")"; break; case DIVIDE: os << "(" << push << e[0] << space << "/ " << e[1] << push << ")"; break; case LT: if (isInt(e[0].getType()) || isInt(e[1].getType())) { } os << "(< " << e[0] << " " << e[1] <<")"; break; case LE: os << "(<= " << e[0] << " " << e[1] << ")"; break; case GT: os << "(> " << e[0] << " " << e[1] << ")"; break; case GE: os << "(>= " << e[0] << " " << e[1] << ")"; break; case DARK_SHADOW: case GRAY_SHADOW: os <<"ERROR:SHADOW:not supported in Simplify\n"; break; default: // Print the top node in the default LISP format, continue with // pretty-printing for children. e.print(os); break; } break; // end of case SIMPLIFY_LANG case TPTP_LANG: switch(e.getKind()) { case RATIONAL_EXPR: e.print(os); break; case SUBRANGE: os <<"ERROR:SUBRANGE:not supported in TPTP\n"; break; case IS_INTEGER: os <<"ERROR:IS_INTEGER:not supported in TPTP\n"; break; case PLUS: { if(!isInteger(e[0])){ os<<"ERRPR:plus only supports inteters now in TPTP\n"; break; } int i=0, iend=e.arity(); if(iend <=1){ os<<"ERROR,plus must have more than two numbers in TPTP\n"; break; } for(i=0; i <= iend-2; ++i){ os << "$plus_int("; os << e[i] << ","; } os<< e[iend-1]; for(i=0 ; i <= iend-2; ++i){ os << ")"; } break; } case MINUS: if(!isInteger(e[0])){ os<<"ERRPR:arithmetic operations only support inteters now in TPTP\n"; break; } os << "$minus_int(" << e[0] << "," << e[1]<< ")"; break; case UMINUS: if(!isInteger(e[0])){ os<<"ERRPR:arithmetic operations only support inteters now in TPTP\n"; break; } os << "$uminus_int(" << e[0] <<")" ; break; case MULT: { if(!isInteger(e[0])){ os<<"ERRPR:times only supports inteters now in TPTP\n"; break; } int i=0, iend=e.arity(); if(iend <=1){ os<<"ERROR:times must have more than two numbers in TPTP\n"; break; } for(i=0; i <= iend-2; ++i){ os << "$times_int("; os << e[i] << ","; } os<< e[iend-1]; for(i=0 ; i <= iend-2; ++i){ os << ")"; } break; } case POW: if(!isInteger(e[0])){ os<<"ERRPR:arithmetic operations only support inteters now in TPTP\n"; break; } os << "$power_int(" << push << e[1] << space << "^ " << e[0] << push << ")"; break; case DIVIDE: if(!isInteger(e[0])){ os<<"ERRPR:arithmetic operations only support inteters now in TPTP\n"; break; } os << "divide_int(" < " << e[1] << push << ")"; break; case GE: os << "(" << push << e[0] << space << ">= " << e[1] << push << ")"; break; case DARK_SHADOW: os << "DARK_SHADOW(" << push << e[0] << ", " << space << e[1] << push << ")"; break; case GRAY_SHADOW: os << "GRAY_SHADOW(" << push << e[0] << "," << space << e[1] << "," << space << e[2] << "," << space << e[3] << push << ")"; break; default: // Print the top node in the default LISP format, continue with // pretty-printing for children. e.printAST(os); break; } break; // end of case PRESENTATION_LANG case SMTLIB_LANG: case SMTLIB_V2_LANG: { switch(e.getKind()) { case REAL_CONST: printRational(os, e[0].getRational(), true); break; case RATIONAL_EXPR: printRational(os, e.getRational()); break; case REAL: os << "Real"; break; case INT: os << "Int"; break; case SUBRANGE: throw SmtlibException("TheoryArith3::print: SMTLIB: SUBRANGE not implemented"); // if(e.arity() != 2) e.print(os); // else // os << "(" << push << "SUBRANGE" << space << e[0] // << space << e[1] << push << ")"; break; case IS_INTEGER: if(e.arity() == 1) os << "(" << push << "IsInt" << space << e[0] << push << ")"; else throw SmtlibException("TheoryArith3::print: SMTLIB: IS_INTEGER used unexpectedly"); break; case PLUS: { if(e.arity() == 1 && os.lang() == SMTLIB_V2_LANG) { os << e[0]; } else { os << "(" << push << "+"; Expr::iterator i = e.begin(), iend = e.end(); for(; i!=iend; ++i) { os << space << (*i); } os << push << ")"; } break; } case MINUS: { os << "(" << push << "- " << e[0] << space << e[1] << push << ")"; break; } case UMINUS: { os << "(" << push << "-" << space << e[0] << push << ")"; break; } case MULT: { int i=0, iend=e.arity(); if(iend == 1 && os.lang() == SMTLIB_V2_LANG) { os << e[0]; } else { for(; i!=iend; ++i) { if (i < iend-1) { os << "(" << push << "*"; } os << space << e[i]; } for (i=0; i < iend-1; ++i) os << push << ")"; } break; } case POW: throw SmtlibException("TheoryArith3::print: SMTLIB: POW not supported"); // os << "(" << push << "^ " << e[1] << space << e[0] << push << ")"; break; case DIVIDE: { throw SmtlibException("TheoryArith3::print: SMTLIB: unexpected use of DIVIDE"); break; } case LT: { Rational r; os << "(" << push << "<" << space; os << e[0] << space << e[1] << push << ")"; break; } case LE: { Rational r; os << "(" << push << "<=" << space; os << e[0] << space << e[1] << push << ")"; break; } case GT: { Rational r; os << "(" << push << ">" << space; os << e[0] << space << e[1] << push << ")"; break; } case GE: { Rational r; os << "(" << push << ">=" << space; os << e[0] << space << e[1] << push << ")"; break; } case DARK_SHADOW: throw SmtlibException("TheoryArith3::print: SMTLIB: DARK_SHADOW not supported"); os << "(" << push << "DARK_SHADOW" << space << e[0] << space << e[1] << push << ")"; break; case GRAY_SHADOW: throw SmtlibException("TheoryArith3::print: SMTLIB: GRAY_SHADOW not supported"); os << "GRAY_SHADOW(" << push << e[0] << "," << space << e[1] << "," << space << e[2] << "," << space << e[3] << push << ")"; break; default: throw SmtlibException("TheoryArith3::print: SMTLIB: default not supported"); // Print the top node in the default LISP format, continue with // pretty-printing for children. e.printAST(os); break; } break; // end of case SMTLIB_LANG } case LISP_LANG: switch(e.getKind()) { case REAL: case INT: case RATIONAL_EXPR: case NEGINF: case POSINF: e.print(os); break; case SUBRANGE: if(e.arity() != 2) e.printAST(os); else os << "(" << push << "SUBRANGE" << space << e[0] << space << e[1] << push << ")"; break; case IS_INTEGER: if(e.arity() == 1) os << "(" << push << "IS_INTEGER" << space << e[0] << push << ")"; else e.printAST(os); break; case PLUS: { int i=0, iend=e.arity(); os << "(" << push << "+"; for(; i!=iend; ++i) os << space << e[i]; os << push << ")"; break; } case MINUS: //os << "(" << push << e[0] << space << "- " << e[1] << push << ")"; os << "(" << push << "- " << e[0] << space << e[1] << push << ")"; break; case UMINUS: os << "(" << push << "-" << space << e[0] << push << ")"; break; case MULT: { int i=0, iend=e.arity(); os << "(" << push << "*"; for(; i!=iend; ++i) os << space << e[i]; os << push << ")"; break; } case POW: os << "(" << push << "^ " << e[1] << space << e[0] << push << ")"; break; case DIVIDE: os << "(" << push << "/ " << e[0] << space << e[1] << push << ")"; break; case LT: os << "(" << push << "< " << e[0] << space << e[1] << push << ")"; break; case LE: os << "(" << push << "<= " << e[0] << space << e[1] << push << ")"; break; case GT: os << "(" << push << "> " << e[1] << space << e[0] << push << ")"; break; case GE: os << "(" << push << ">= " << e[0] << space << e[1] << push << ")"; break; case DARK_SHADOW: os << "(" << push << "DARK_SHADOW" << space << e[0] << space << e[1] << push << ")"; break; case GRAY_SHADOW: os << "(" << push << "GRAY_SHADOW" << space << e[0] << space << e[1] << space << e[2] << space << e[3] << push << ")"; break; default: // Print the top node in the default LISP format, continue with // pretty-printing for children. e.printAST(os); break; } break; // end of case LISP_LANG default: // Print the top node in the default LISP format, continue with // pretty-printing for children. e.printAST(os); } return os; } cvc3-2.4.1/src/theory_arith/arith_exception.h0000664000175400017540000000236511267754362021127 0ustar mdetersmdeters/*****************************************************************************/ /*! * \file arith_exception.h * \brief An exception thrown by the arithmetic decision procedure. * * Author: Sergey Berezin * * Created: Fri May 23 15:42:21 2003 * *
* * License to use, copy, modify, sell and/or distribute this software * and its documentation for any purpose is hereby granted without * royalty, subject to the terms and conditions defined in the \ref * LICENSE file provided with this distribution. * *
* */ /*****************************************************************************/ #ifndef _cvc3__theory_arith__arith_exception_h_ #define _cvc3__theory_arith__arith_exception_h_ #include #include #include "exception.h" namespace CVC3 { class ArithException: public Exception { // protected: // std::string d_msg; public: // Constructors ArithException() { } ArithException(const std::string& msg): Exception(msg) { } ArithException(const char* msg): Exception(msg) { } // Destructor virtual ~ArithException() { } virtual std::string toString() const { return "Arithmetic error: " + d_msg; } }; // end of class ArithException } // end of namespace CVC3 #endif cvc3-2.4.1/src/theory_arith/arith_theorem_producer_old.h0000664000175400017540000003271611234135021023313 0ustar mdetersmdeters/*****************************************************************************/ /*! * \file arith_theorem_producer_old.h * \brief TRUSTED implementation of arithmetic proof rules * * Author: Vijay Ganesh, Sergey Berezin * * Created: Dec 13 02:09:04 GMT 2002 * *
* * License to use, copy, modify, sell and/or distribute this software * and its documentation for any purpose is hereby granted without * royalty, subject to the terms and conditions defined in the \ref * LICENSE file provided with this distribution. * *
* */ /*****************************************************************************/ #ifndef _cvc3__arith_theorem_producer_old_h_ #define _cvc3__arith_theorem_producer_old_h_ #include "arith_proof_rules.h" #include "theorem_producer.h" #include "theory_arith_old.h" namespace CVC3 { class ArithTheoremProducerOld: public ArithProofRules, public TheoremProducer { TheoryArithOld* d_theoryArith; private: /*! \name Auxiliary functions for eqElimIntRule() * Methods that compute the subterms used in eqElimIntRule() *@{ */ //! Compute the special modulus: i - m*floor(i/m+1/2) Rational modEq(const Rational& i, const Rational& m); //! Create the term 't'. See eqElimIntRule(). Expr create_t(const Expr& eqn); //! Create the term 't2'. See eqElimIntRule(). Expr create_t2(const Expr& lhs, const Expr& rhs, const Expr& t); //! Create the term 't3'. See eqElimIntRule(). Expr create_t3(const Expr& lhs, const Expr& rhs, const Expr& t); /*! @brief Takes sum = a_0 + a_1*x_1+...+a_n*x_n and returns the * vector of similar monomials (in 'summands') with coefficients * mod(a_i, m). If divide flag is true, the coefficients will be * mod(a_i,m)/m. */ void sumModM(std::vector& summands, const Expr& sum, const Rational& m, const Rational& divisor); Expr monomialModM(const Expr& e, const Rational& m, const Rational& divisor); void sumMulF(std::vector& summands, const Expr& sum, const Rational& m, const Rational& divisor); Expr monomialMulF(const Expr& e, const Rational& m, const Rational& divisor); //! Compute floor(i/m+1/2) + mod(i,m) Rational f(const Rational& i, const Rational& m); Expr substitute(const Expr& term, ExprMap& eMap); void getLeaves(const Expr& e, std::set& s, ExprHashMap& cache); /*@}*/ public: //! Constructor ArithTheoremProducerOld(TheoremManager* tm, TheoryArithOld* theoryArith): TheoremProducer(tm), d_theoryArith(theoryArith) { } //! Create Expr from Rational (for convenience) Expr rat(Rational r) { return d_em->newRatExpr(r); } Type realType() { return d_theoryArith->realType(); } Type intType() { return d_theoryArith->intType(); } //! Construct the dark shadow expression representing lhs <= rhs Expr darkShadow(const Expr& lhs, const Expr& rhs) { return d_theoryArith->darkShadow(lhs, rhs); } //! Construct the gray shadow expression representing c1 <= v - e <= c2 /*! Alternatively, v = e + i for some i s.t. c1 <= i <= c2 */ Expr grayShadow(const Expr& v, const Expr& e, const Rational& c1, const Rational& c2) { return d_theoryArith->grayShadow(v, e, c1, c2); } //////////////////////////////////////////////////////////////////// // Canonization rules //////////////////////////////////////////////////////////////////// // ==> x = 1 * x virtual Theorem varToMult(const Expr& e); // ==> -(e) = (-1) * e virtual Theorem uMinusToMult(const Expr& e); // ==> x - y = x + (-1) * y virtual Theorem minusToPlus(const Expr& x, const Expr& y); // Rule for unary minus: it just converts it to division by -1, virtual Theorem canonUMinusToDivide(const Expr& e); // Rules for division by constant 'd' // (c) / d ==> (c/d), takes c and d virtual Theorem canonDivideConst(const Expr& c, const Expr& d); // (c * x) / d ==> (c/d) * x, takes (c*x) and d virtual Theorem canonDivideMult(const Expr& cx, const Expr& d); // (+ c ...)/d ==> push division to all the coefficients. // The result is not canonical, but canonizing the summands will // make it canonical. // Takes (+ c ...) and d virtual Theorem canonDividePlus(const Expr& e, const Expr& d); // x / d ==> (1/d) * x, takes x and d virtual Theorem canonDivideVar(const Expr& e1, const Expr& e2); // Canon Rules for multiplication // TODO Deepak: // t1 * t2 where t1 and t2 are canonized expressions, i.e. it can be a // 1) Rational constant // 2) Arithmetic Leaf (var or term from another theory) // 3) (POW rational leaf) // 4) (MULT rational mterm'_1 ...) where each mterm' is of type (2) or (3) // 5) (PLUS rational sterm_1 sterm_2 ...) where each sterm is of // type (2) or (3) or (4) static bool greaterthan(const Expr &, const Expr &); virtual Expr simplifiedMultExpr(std::vector & mulKids); virtual Expr canonMultConstMult(const Expr & c, const Expr & e); virtual Expr canonMultConstPlus(const Expr & e1, const Expr & e2); virtual Expr canonMultPowPow(const Expr & e1, const Expr & e2); virtual Expr canonMultPowLeaf(const Expr & e1, const Expr & e2); virtual Expr canonMultLeafLeaf(const Expr & e1, const Expr & e2); virtual Expr canonMultLeafOrPowMult(const Expr & e1, const Expr & e2); virtual Expr canonCombineLikeTerms(const std::vector & sumExprs); virtual Expr canonMultLeafOrPowOrMultPlus(const Expr & e1, const Expr & e2); virtual Expr canonMultPlusPlus(const Expr & e1, const Expr & e2); virtual Theorem canonMultMtermMterm(const Expr& e); virtual Theorem canonPlus(const Expr & e); virtual Theorem canonInvertConst(const Expr & e); virtual Theorem canonInvertLeaf(const Expr & e); virtual Theorem canonInvertPow(const Expr & e); virtual Theorem canonInvertMult(const Expr & e); virtual Theorem canonInvert(const Expr & e); /** * Transform e = (SUM r t1 ... tn) @ 0 into (SUM t1 ... tn) @ -r. The first * sum term (r) must be a rational and t1 ... tn terms must be canonised. * * @param e the expression to transform * @return rewrite theorem representing the transformation */ virtual Theorem moveSumConstantRight(const Expr& e); /** e[0]/e[1] ==> e[0]*(e[1])^-1 */ virtual Theorem canonDivide(const Expr & e); /** Multiply out the operands of the multiplication (each of them is expected to be canonised */ virtual Theorem canonMult(const Expr & e); // t*c ==> c*t, takes constant c and term t virtual Theorem canonMultTermConst(const Expr& c, const Expr& t); // t1*t2 ==> Error, takes t1 and t2 where both are non-constants virtual Theorem canonMultTerm1Term2(const Expr& t1, const Expr& t2); // 0*t ==> 0, takes 0*t virtual Theorem canonMultZero(const Expr& e); // 1*t ==> t, takes 1*t virtual Theorem canonMultOne(const Expr& e); // c1*c2 ==> c', takes constant c1*c2 virtual Theorem canonMultConstConst(const Expr& c1, const Expr& c2); // c1*(c2*t) ==> c'*t, takes c1 and c2 and t virtual Theorem canonMultConstTerm(const Expr& c1, const Expr& c2, const Expr&t); // c1*(+ c2 v1 ...) ==> (+ c' c1v1 ...), takes c1 and the sum virtual Theorem canonMultConstSum(const Expr& c1, const Expr& sum); // c^n = c' (compute the constant power expression) virtual Theorem canonPowConst(const Expr& pow); // Rules for addition // flattens the input. accepts a PLUS expr virtual Theorem canonFlattenSum(const Expr& e); // Rules for addition // combine like terms. accepts a flattened PLUS expr virtual Theorem canonComboLikeTerms(const Expr& e); // 0 = (* e1 e2 ...) <=> 0 = e1 OR 0 = e2 OR ... virtual Theorem multEqZero(const Expr& expr); // 0 = (^ c x) <=> false if c <=0 // <=> 0 = x if c > 0 virtual Theorem powEqZero(const Expr& expr); // x^n = y^n <=> x = y (if n is odd) // x^n = y^n <=> x = y OR x = -y (if n is even) virtual Theorem elimPower(const Expr& expr); // x^n = c <=> x = root (if n is odd and root^n = c) // x^n = c <=> x = root OR x = -root (if n is even and root^n = c) virtual Theorem elimPowerConst(const Expr& expr, const Rational& root); // x^n = c <=> false (if n is even and c is negative) virtual Theorem evenPowerEqNegConst(const Expr& expr); // x^n = c <=> false (if x is an integer and c is not a perfect n power) virtual Theorem intEqIrrational(const Expr& expr, const Theorem& isInt); // e[0] kind e[1] <==> true when e[0] kind e[1], // false when e[0] !kind e[1], for constants only virtual Theorem constPredicate(const Expr& e); // e[0] kind e[1] <==> 0 kind e[1] - e[0] virtual Theorem rightMinusLeft(const Expr& e); // e[0] kind e[1] <==> e[0] - e[1] kind 0 virtual Theorem leftMinusRight(const Expr& e); // x kind y <==> x + z kind y + z virtual Theorem plusPredicate(const Expr& x, const Expr& y, const Expr& z, int kind); // x = y <==> x * z = y * z virtual Theorem multEqn(const Expr& x, const Expr& y, const Expr& z); // x = y <==> z=0 OR x * 1/z = y * 1/z virtual Theorem divideEqnNonConst(const Expr& x, const Expr& y, const Expr& z); // if z is +ve, return e[0] LT|LE|GT|GE e[1] <==> e[0]*z LT|LE|GT|GE e[1]*z // if z is -ve, return e[0] LT|LE|GT|GE e[1] <==> e[1]*z LT|LE|GT|GE e[0]*z virtual Theorem multIneqn(const Expr& e, const Expr& z); // x = y ==> x <= y and x >= y virtual Theorem eqToIneq(const Expr& e); // "op1 GE|GT op2" <==> op2 LE|LT op1 virtual Theorem flipInequality(const Expr& e); // NOT (op1 LT op2) <==> (op1 GE op2) // NOT (op1 LE op2) <==> (op1 GT op2) // NOT (op1 GT op2) <==> (op1 LE op2) // NOT (op1 GE op2) <==> (op1 LT op2) Theorem negatedInequality(const Expr& e); Theorem realShadow(const Theorem& alphaLTt, const Theorem& tLTbeta); Theorem realShadowEq(const Theorem& alphaLEt, const Theorem& tLEalpha); Theorem finiteInterval(const Theorem& aLEt, const Theorem& tLEac, const Theorem& isInta, const Theorem& isIntt); Theorem darkGrayShadow2ab(const Theorem& betaLEbx, const Theorem& axLEalpha, const Theorem& isIntAlpha, const Theorem& isIntBeta, const Theorem& isIntx); Theorem darkGrayShadow2ba(const Theorem& betaLEbx, const Theorem& axLEalpha, const Theorem& isIntAlpha, const Theorem& isIntBeta, const Theorem& isIntx); Theorem expandDarkShadow(const Theorem& darkShadow); Theorem expandGrayShadow0(const Theorem& grayShadow); Theorem splitGrayShadow(const Theorem& grayShadow); Theorem splitGrayShadowSmall(const Theorem& grayShadow); Theorem expandGrayShadow(const Theorem& grayShadow); Theorem expandGrayShadowConst(const Theorem& grayShadow); Theorem grayShadowConst(const Theorem& g); //! Implements j(c,b,a) /*! accepts 3 integers a,b,c and returns * (b > 0)? (c+b) mod a : (a - (c+b)) mod a */ Rational constRHSGrayShadow(const Rational& c, const Rational& b, const Rational& a); Theorem lessThanToLE(const Theorem& less, const Theorem& isIntLHS, const Theorem& isIntRHS, bool changeRight); Theorem lessThanToLERewrite(const Expr& ineq, const Theorem& isIntLHS, const Theorem& isIntRHS, bool changeRight); Theorem intVarEqnConst(const Expr& eqn, const Theorem& isIntx); Theorem IsIntegerElim(const Theorem& isIntx); Theorem eqElimIntRule(const Theorem& eqn, const Theorem& isIntx, const std::vector& isIntVars); Theorem isIntConst(const Expr& e); Theorem equalLeaves1(const Theorem& e); Theorem equalLeaves2(const Theorem& e); Theorem equalLeaves3(const Theorem& e); Theorem equalLeaves4(const Theorem& e); Theorem diseqToIneq(const Theorem& diseq); Theorem dummyTheorem(const Expr& e); Theorem oneElimination(const Expr& x); Theorem clashingBounds(const Theorem& lowerBound, const Theorem& upperBound); Theorem addInequalities(const Theorem& thm1, const Theorem& thm2); Theorem addInequalities(const std::vector& thms); Theorem implyWeakerInequality(const Expr& expr1, const Expr& expr2); Theorem implyNegatedInequality(const Expr& expr1, const Expr& expr2); Theorem integerSplit(const Expr& intVar, const Rational& intPoint); Theorem trustedRewrite(const Expr& expr1, const Expr& expr2); Theorem rafineStrictInteger(const Theorem& isIntConstrThm, const Expr& constr); Theorem simpleIneqInt(const Expr& ineq, const Theorem& isIntRHS); Theorem intEqualityRationalConstant(const Theorem& isIntConstrThm, const Expr& constr); Theorem cycleConflict(const std::vector& inequalitites); Theorem implyEqualities(const std::vector& inequalities); Theorem implyWeakerInequalityDiffLogic(const std::vector& antecedentThms, const Expr& implied); Theorem implyNegatedInequalityDiffLogic(const std::vector& antecedentThms, const Expr& implied); Theorem expandGrayShadowRewrite(const Expr& theShadow); Theorem compactNonLinearTerm(const Expr& nonLinear); Theorem nonLinearIneqSignSplit(const Theorem& ineqThm); Theorem implyDiffLogicBothBounds(const Expr& x, std::vector& c1_le_x, Rational c1, std::vector& x_le_c2, Rational c2); Theorem powerOfOne(const Expr& e); Theorem rewriteLeavesConst(const Expr& e); }; // end of class ArithTheoremProducerOld } // end of namespace CVC3 #endif cvc3-2.4.1/src/theory_arith/theory_arith_old.cpp0000644000175400017540000061076711630011152021616 0ustar mdetersmdeters/*****************************************************************************/ /*! * \file theory_arith_old.cpp * * Author: Clark Barrett, Vijay Ganesh. * * Created: Fri Jan 17 18:39:18 2003 * *
* * License to use, copy, modify, sell and/or distribute this software * and its documentation for any purpose is hereby granted without * royalty, subject to the terms and conditions defined in the \ref * LICENSE file provided with this distribution. * *
* */ /*****************************************************************************/ #include "theory_arith_old.h" #include "arith_proof_rules.h" //#include "arith_expr.h" #include "arith_exception.h" #include "typecheck_exception.h" #include "eval_exception.h" #include "parser_exception.h" #include "smtlib_exception.h" #include "theory_core.h" #include "command_line_flags.h" //TODO: remove this dependency #include "../theory_core/core_proof_rules.h" using namespace std; using namespace CVC3; /////////////////////////////////////////////////////////////////////////////// // TheoryArithOld::FreeConst Methods // /////////////////////////////////////////////////////////////////////////////// namespace CVC3 { ostream& operator<<(ostream& os, const TheoryArithOld::FreeConst& fc) { os << "FreeConst(r=" << fc.getConst() << ", " << (fc.strict()? "strict" : "non-strict") << ")"; return os; } /////////////////////////////////////////////////////////////////////////////// // TheoryArithOld::Ineq Methods // /////////////////////////////////////////////////////////////////////////////// ostream& operator<<(ostream& os, const TheoryArithOld::Ineq& ineq) { os << "Ineq(" << ineq.ineq().getExpr() << ", isolated on " << (ineq.varOnRHS()? "RHS" : "LHS") << ", const = " << ineq.getConst() << ")"; return os; } } // End of namespace CVC3 /////////////////////////////////////////////////////////////////////////////// // TheoryArithOld Private Methods // /////////////////////////////////////////////////////////////////////////////// Theorem TheoryArithOld::isIntegerThm(const Expr& e) { // Quick checks Type t = e.getType(); if (isReal(t)) return Theorem(); if (isInt(t)) return typePred(e); // Try harder return isIntegerDerive(Expr(IS_INTEGER, e), typePred(e)); } Theorem TheoryArithOld::isIntegerDerive(const Expr& isIntE, const Theorem& thm) { const Expr& e = thm.getExpr(); // We found it! if(e == isIntE) return thm; Theorem res; // If the theorem is an AND, look inside each child if(e.isAnd()) { int i, iend=e.arity(); for(i=0; iandElim(thm, i)); if(!res.isNull()) return res; } } return res; } const Rational& TheoryArithOld::freeConstIneq(const Expr& ineq, bool varOnRHS) { DebugAssert(isIneq(ineq), "TheoryArithOld::freeConstIneq("+ineq.toString()+")"); const Expr& e = varOnRHS? ineq[0] : ineq[1]; switch(e.getKind()) { case PLUS: return e[0].getRational(); case RATIONAL_EXPR: return e.getRational(); default: { // MULT, DIV, or Variable static Rational zero(0); return zero; } } } const TheoryArithOld::FreeConst& TheoryArithOld::updateSubsumptionDB(const Expr& ineq, bool varOnRHS, bool& subsumed) { TRACE("arith ineq", "TheoryArithOld::updateSubsumptionDB(", ineq, ", var isolated on "+string(varOnRHS? "RHS" : "LHS")+")"); DebugAssert(isLT(ineq) || isLE(ineq), "TheoryArithOld::updateSubsumptionDB(" +ineq.toString()+")"); // Indexing expression: same as ineq only without the free const Expr index; const Expr& t = varOnRHS? ineq[0] : ineq[1]; bool strict(isLT(ineq)); Rational c(0); if(isPlus(t)) { DebugAssert(t.arity() >= 2, "TheoryArithOld::updateSubsumptionDB(" +ineq.toString()+")"); c = t[0].getRational(); // Extract the free const in ineq Expr newT; if(t.arity() == 2) { newT = t[1]; } else { vector kids; Expr::iterator i=t.begin(), iend=t.end(); kids.push_back(rat(0)); for(++i; i!=iend; ++i) kids.push_back(*i); DebugAssert(kids.size() > 0, "kids.size = "+int2string(kids.size()) +", ineq = "+ineq.toString()); newT = plusExpr(kids); } if(varOnRHS) index = leExpr(rat(0), canonSimplify(ineq[1] - newT).getRHS()); else index = leExpr(canonSimplify(ineq[0]-newT).getRHS(), rat(0)); } else if(isRational(t)) { c = t.getRational(); if(varOnRHS) index = leExpr(rat(0), ineq[1]); else index = leExpr(ineq[0], rat(0)); } else if(isLT(ineq)) index = leExpr(ineq[0], ineq[1]); else index = ineq; // Now update the database, check for subsumption, and extract the constant CDMap::iterator i=d_freeConstDB.find(index), iend=d_freeConstDB.end(); if(i == iend) { subsumed = false; // Create a new entry CDOmap& obj = d_freeConstDB[index]; obj = FreeConst(c,strict); TRACE("arith ineq", "freeConstDB["+index.toString()+"] := ", obj, ""); return obj.get(); } else { CDOmap& obj = d_freeConstDB[index]; const FreeConst& fc = obj.get(); if(varOnRHS) { subsumed = (c < fc.getConst() || (c == fc.getConst() && (!strict || fc.strict()))); } else { subsumed = (c > fc.getConst() || (c == fc.getConst() && (strict || !fc.strict()))); } if(!subsumed) { obj = FreeConst(c,strict); TRACE("arith ineq", "freeConstDB["+index.toString()+"] := ", obj, ""); } return obj.get(); } } bool TheoryArithOld::kidsCanonical(const Expr& e) { if(isLeaf(e)) return true; bool res(true); for(int i=0; res && iuMinusToMult(e[0]); Expr e2 = thm.getRHS(); result = transitivityRule(thm, canon(e2)); } break; case PLUS: /* { Theorem plusThm, plusThm1; plusThm = d_rules->canonFlattenSum(e); plusThm1 = d_rules->canonComboLikeTerms(plusThm.getRHS()); result = transitivityRule(plusThm,plusThm1); } */ result = d_rules->canonPlus(e); break; case MINUS: { DebugAssert(e.arity() == 2,""); Theorem minus_eq_sum = d_rules->minusToPlus(e[0], e[1]); // this produces e0 + (-1)*e1; we have to canonize it in 2 steps Expr sum(minus_eq_sum.getRHS()); Theorem thm(canon(sum[1])); if(thm.getLHS() == thm.getRHS()) result = canonThm(minus_eq_sum); // The sum changed; do the work else { vector changed; vector thms; changed.push_back(1); thms.push_back(thm); Theorem sum_eq_canon = canonThm(substitutivityRule(sum, changed, thms)); result = transitivityRule(minus_eq_sum, sum_eq_canon); } break; } case MULT: result = d_rules->canonMult(e); break; /* case MULT: { Theorem thmMult, thmMult1; Expr exprMult; Expr e0 = e[0]; Expr e1 = e[1]; if(e0.isRational()) { if(rat(0) == e0) result = d_rules->canonMultZero(e1); else if (rat(1) == e0) result = d_rules->canonMultOne(e1); else switch(e1.getKind()) { case RATIONAL_EXPR : result = d_rules->canonMultConstConst(e0,e1); break; case MULT: DebugAssert(e1[0].isRational(), "theory_arith::canon:\n " "canon:MULT:MULT child is not canonical: " + e1[0].toString()); thmMult = d_rules->canonMultConstTerm(e0,e1[0],e1[1]); result = transitivityRule(thmMult,canon(thmMult.getRHS())); break; case PLUS:{ Theorem thmPlus, thmPlus1; Expr ePlus; std::vector thmPlusVector; thmPlus = d_rules->canonMultConstSum(e0,e1); ePlus = thmPlus.getRHS(); Expr::iterator i = ePlus.begin(); for(;i != ePlus.end();++i) thmPlusVector.push_back(canon(*i)); thmPlus1 = substitutivityRule(PLUS, thmPlusVector); result = transitivityRule(thmPlus, thmPlus1); break; } default: result = reflexivityRule(e); break; } } else { if(e1.isRational()){ // canonMultTermConst just reverses the order of the const and the // term. Then canon is called again. Theorem t1 = d_rules->canonMultTermConst(e1,e0); result = transitivityRule(t1,canon(t1.getRHS())); } else // This is where the assertion for non-linear multiplication is // produced. result = d_rules->canonMultTerm1Term2(e0,e1); } break; } */ case DIVIDE:{ /* case DIVIDE:{ if (e[1].isRational()) { if (e[1].getRational() == 0) throw ArithException("Divide by 0 error in "+e.toString()); Theorem thm = d_rules->canonDivideVar(e[0], e[1]); Expr e2 = thm.getRHS(); result = transitivityRule(thm, canon(e2)); } else { // TODO: to be handled throw ArithException("Divide by a non-const not handled in "+e.toString()); } break; } */ // Division by 0 is OK (total extension, protected by TCCs) // if (e[1].isRational() && e[1].getRational() == 0) // throw ArithException("Divide by 0 error in "+e.toString()); if (e[1].getKind() == PLUS) throw ArithException("Divide by a PLUS expression not handled in"+e.toString()); result = d_rules->canonDivide(e); break; } case POW: if(e[1].isRational()) result = d_rules->canonPowConst(e); else { // x ^ 1 --> x if (e[0].isRational() && e[0].getRational() == 1) { result = d_rules->powerOfOne(e); } else result = reflexivityRule(e); } break; default: result = reflexivityRule(e); break; } TRACE("arith canon","canon => ",result," }"); return result; } Theorem TheoryArithOld::canonSimplify(const Expr& e) { TRACE("arith simplify", "canonSimplify(", e, ") {"); DebugAssert(kidsCanonical(e), "TheoryArithOld::canonSimplify("+e.toString()+")"); DebugAssert(leavesAreSimp(e), "Expected leaves to be simplified"); Expr tmp(e); Theorem thm = canon(e); if(thm.getRHS().hasFind()) thm = transitivityRule(thm, find(thm.getRHS())); // We shouldn't rely on simplification in this function anymore DebugAssert(thm.getRHS() == simplifyExpr(thm.getRHS()), "canonSimplify("+e.toString()+")\n" +"canon(e) = "+thm.getRHS().toString() +"\nsimplify(canon(e)) = "+simplifyExpr(thm.getRHS()).toString()); // if(tmp != thm.getRHS()) // thm = transitivityRule(thm, simplifyThm(thm.getRHS())); // while(tmp != thm.getRHS()) { // tmp = thm.getRHS(); // thm = canon(thm); // if(tmp != thm.getRHS()) // thm = transitivityRule(thm, simplifyThm(thm.getRHS())); // } TRACE("arith", "canonSimplify =>", thm, " }"); return thm; } /*! accepts a theorem, canonizes it, applies iffMP and substituvity to * derive the canonized thm */ Theorem TheoryArithOld::canonPred(const Theorem& thm) { vector thms; DebugAssert(thm.getExpr().arity() == 2, "TheoryArithOld::canonPred: bad theorem: "+thm.toString()); Expr e(thm.getExpr()); thms.push_back(canonSimplify(e[0])); thms.push_back(canonSimplify(e[1])); Theorem result = iffMP(thm, substitutivityRule(e.getOp(), thms)); return result; } /*! accepts an equivalence theorem, canonizes it, applies iffMP and * substituvity to derive the canonized thm */ Theorem TheoryArithOld::canonPredEquiv(const Theorem& thm) { vector thms; DebugAssert(thm.getRHS().arity() == 2, "TheoryArithOld::canonPredEquiv: bad theorem: "+thm.toString()); Expr e(thm.getRHS()); thms.push_back(canonSimplify(e[0])); thms.push_back(canonSimplify(e[1])); Theorem result = transitivityRule(thm, substitutivityRule(e.getOp(), thms)); return result; } /*! accepts an equivalence theorem whose RHS is a conjunction, * canonizes it, applies iffMP and substituvity to derive the * canonized thm */ Theorem TheoryArithOld::canonConjunctionEquiv(const Theorem& thm) { vector thms; return thm; } /*! Pseudo-code for doSolve. (Input is an equation) (output is a Theorem) * -# translate e to the form e' = 0 * -# if (e'.isRational()) then {if e' != 0 return false else true} * -# a for loop checks if all the variables are integers. * - if not isolate a suitable real variable and call processRealEq(). * - if all variables are integers then isolate suitable variable * and call processIntEq(). */ Theorem TheoryArithOld::doSolve(const Theorem& thm) { const Expr& e = thm.getExpr(); if (e.isTrue() || e.isFalse()) return thm; TRACE("arith eq","doSolve(",e,") {"); DebugAssert(thm.isRewrite(), "thm = "+thm.toString()); Theorem eqnThm; vector thms; // Move LHS to the RHS, if necessary if(e[0].isRational() && e[0].getRational() == 0) eqnThm = thm; else { eqnThm = iffMP(thm, d_rules->rightMinusLeft(e)); eqnThm = canonPred(eqnThm); } // eqnThm is of the form 0 = e' // 'right' is of the form e' Expr right = eqnThm.getRHS(); // Check for trivial equation if (right.isRational()) { Theorem result = iffMP(eqnThm, d_rules->constPredicate(eqnThm.getExpr())); TRACE("arith eq","doSolve => ",result," }"); return result; } //normalize eqnThm = iffMP(eqnThm, normalize(eqnThm.getExpr())); TRACE("arith eq","doSolve => ",eqnThm.getExpr()," }"); right = eqnThm.getRHS(); //eqn is of the form 0 = e' and is normalized where 'right' denotes e' //FIXME: change processRealEq to accept equations as well instead of theorems try { if (isMult(right)) { DebugAssert(right.arity() > 1, "Expected arity > 1"); if (right[0].isRational()) { Rational r = right[0].getRational(); if (r == 0) return getCommonRules()->trueTheorem(); else if (r == 1) { enqueueFact(iffMP(eqnThm, d_rules->multEqZero(eqnThm.getExpr()))); return getCommonRules()->trueTheorem(); } Theorem res = iffMP(eqnThm, d_rules->multEqn(eqnThm.getLHS(), right, rat(1/r))); res = canonPred(res); return doSolve(res); } else { enqueueFact(iffMP(eqnThm, d_rules->multEqZero(eqnThm.getExpr()))); return getCommonRules()->trueTheorem(); } } else if (isPow(right)) { DebugAssert(right.arity() == 2, "Expected arity 2"); if (right[0].isRational()) { return doSolve(iffMP(eqnThm, d_rules->powEqZero(eqnThm.getExpr()))); } throw ArithException("Can't solve exponential eqn: "+eqnThm.toString()); } else { if(!isInteger(right)) { return processRealEq(eqnThm); } else { return processIntEq(eqnThm); } } } catch(ArithException& e) { FatalAssert(false, "We should never get here!!! : " + e.toString()); // // Nonlinear bail out // Theorem res; // if (isPlus(right)) { // // Solve for something // // Try to simulate groebner basis by picking the highest term // Expr isolated = right[1]; // int isolated_degree = termDegree(isolated); // for (int i = 2; i < right.arity(); i ++) { // int degree = termDegree(right[i]); // if (degree > isolated_degree) { // isolated = right[i]; // isolated_degree = degree; // } // } // Rational coeff; // if (isMult(isolated) && isolated[0].isRational()) { // coeff = isolated[0].getRational(); // DebugAssert(coeff != 0, "Expected nonzero coeff"); // isolated = canon(isolated / rat(coeff)).getRHS(); // } else coeff = 1; // res = iffMP(eqnThm, d_rules->multEqn(rat(0), right, rat(-1/coeff))); // res = canonPred(res); // res = iffMP(res, d_rules->plusPredicate(res.getLHS(), res.getRHS(), isolated, EQ)); // res = canonPred(res); // TRACE("arith nonlinear", "solved for: ", res.getExpr(), ""); // } else // res = symmetryRule(eqnThm); // Flip to e' = 0 // TRACE("arith eq", "doSolve: failed to solve an equation: ", e, ""); // IF_DEBUG(debugger.counter("FAILED to solve equalities")++;) // setIncomplete("Non-linear arithmetic equalities"); // // // Since we are forgetting about this equation, setup for updates // TRACE("arith nonlinear", "adding setup to ", eqnThm.getExpr(), ""); // setupRec(eqnThm.getExpr()); // return getCommonRules()->trueTheorem(); } FatalAssert(false, ""); return Theorem(); } /*! pick a monomial for the input equation. This function is used only * if the equation is an integer equation. Choose the monomial with * the smallest absolute value of coefficient. */ bool TheoryArithOld::pickIntEqMonomial(const Expr& right, Expr& isolated, bool& nonlin) { DebugAssert(isPlus(right) && right.arity() > 1, "TheoryArithOld::pickIntEqMonomial right is wrong :-): " + right.toString()); DebugAssert(right[0].isRational(), "TheoryArithOld::pickIntEqMonomial. right[0] must be const" + right.toString()); // DebugAssert(isInteger(right), // "TheoryArithOld::pickIntEqMonomial: right is of type int: " + // right.toString()); //right is of the form "C + a1x1 + ... + anxn". min is initialized //to a1 Expr::iterator istart = right.begin(), iend = right.end(); istart++; Expr::iterator i = istart, j; bool found = false; nonlin = false; Rational min, coeff; Expr leaf; for(; i != iend; ++i) { if (isLeaf(*i)) { leaf = *i; coeff = 1; } else if (isMult(*i) && (*i).arity() == 2 && (*i)[0].isRational() && isLeaf((*i)[1])) { leaf = (*i)[1]; coeff = abs((*i)[0].getRational()); } else { nonlin = true; continue; } for (j = istart; j != iend; ++j) { if (j != i && isLeafIn(leaf, *j)) break; } if (j == iend) { if (!found || min > coeff) { min = coeff; isolated = *i; found = true; } } } return found; } /*! input is 0=e' Theorem and some of the vars in e' are of * type REAL. isolate one of them and send back to framework. output * is "var = e''" Theorem. */ Theorem TheoryArithOld::processRealEq(const Theorem& eqn) { DebugAssert(eqn.getLHS().isRational() && eqn.getLHS().getRational() == 0, "processRealEq invariant violated"); Expr right = eqn.getRHS(); // Find variable to isolate and store it in left. Pick the largest // (according to the total ordering) variable. FIXME: change from // total ordering to the ordering we devised for inequalities. // TODO: I have to pick a variable that appears as a variable in the // term but does not appear as a variable anywhere else. The variable // must appear as a single leaf and not in a MULT expression with some // other variables and nor in a POW expression. bool found = false; Expr left; if (isPlus(right)) { DebugAssert(right[0].isRational(), "Expected first term to be rational"); for(int i = 1, iend = right.arity(); i < iend; ++i) { Expr c = right[i]; DebugAssert(!isRational(c), "Expected non-rational"); if(!isInteger(c)) { if (isLeaf(c) || ((isMult(c) && c.arity() == 2 && isLeaf(c[1])))) { Expr leaf = isLeaf(c) ? c : c[1]; int j; for (j = 1; j < iend; ++j) { if (j!= i && isLeafIn(leaf, right[j]) ) { break; } } if (j == iend) { left = c; found = true; break; } } } } } else if ((isMult(right) && right.arity() == 2 && isLeaf(right[1])) || isLeaf(right)) { left = right; found = true; } if (!found) { // The only way we can not get an isolated in the reals is if all of them // are non-linear. In this case we might have some integers to solve for // so we try that. The integer solver shouldn't be able to solve for the // reals, as they are not solvable and we should be safe. One of such // examples is if some constant ITE got skolemized and we have an equation // like SKOLEM = x^2 (bug79), in which case we should solve for the SKOLEM // where skolem is an INT variable. if (isNonlinearEq(eqn.getExpr())) return processIntEq(eqn); else throw ArithException("Can't find a leaf for solve in "+eqn.toString()); } Rational r = -1; if (isMult(left)) { DebugAssert(left.arity() == 2, "only leaf should be chosen as lhs"); DebugAssert(left[0].getRational() != 0, "left = "+left.toString()); r = -1/left[0].getRational(); left = left[1]; } DebugAssert(isReal(getBaseType(left)) && !isInteger(left), "TheoryArithOld::ProcessRealEq: left is integer:\n left = " +left.toString()); // Normalize equation so that coefficient of the monomial // corresponding to "left" in eqn[1] is -1 Theorem result(iffMP(eqn, d_rules->multEqn(eqn.getLHS(), eqn.getRHS(), rat(r)))); result = canonPred(result); // Isolate left result = iffMP(result, d_rules->plusPredicate(result.getLHS(), result.getRHS(), left, EQ)); result = canonPred(result); TRACE("arith","processRealEq => ",result," }"); return result; } void TheoryArithOld::getFactors(const Expr& e, set& factors) { switch (e.getKind()) { case RATIONAL_EXPR: break; case MULT: { Expr::iterator i = e.begin(), iend = e.end(); for (; i != iend; ++i) { getFactors(*i, factors); } break; } case POW: { DebugAssert(e.arity() == 2, "invariant violated"); if (!isIntegerConst(e[0]) || e[0].getRational() <= 0) { throw ArithException("not positive integer exponent in "+e.toString()); } if (isLeaf(e[1])) factors.insert(e[1]); break; } default: { DebugAssert(isLeaf(e), "expected leaf"); DebugAssert(factors.find(e) == factors.end(), "expected new entry"); factors.insert(e); break; } } } /*! * \param eqn is a single equation 0 = e * \return an equivalent Theorem (x = t AND 0 = e'), or just x = t */ Theorem TheoryArithOld::processSimpleIntEq(const Theorem& eqn) { TRACE("arith eq", "processSimpleIntEq(", eqn.getExpr(), ") {"); DebugAssert(eqn.isRewrite(), "TheoryArithOld::processSimpleIntEq: eqn must be equality" + eqn.getExpr().toString()); Expr right = eqn.getRHS(); DebugAssert(eqn.getLHS().isRational() && 0 == eqn.getLHS().getRational(), "TheoryArithOld::processSimpleIntEq: LHS must be 0:\n" + eqn.getExpr().toString()); DebugAssert(!isMult(right) && !isPow(right), "should have been handled above"); if (isPlus(right)) { if (2 == right.arity() && (isLeaf(right[1]) || (isMult(right[1]) && right[1].arity() == 2 && right[1][0].isRational() && isLeaf(right[1][1])))) { //we take care of special cases like 0 = c + a.x, 0 = c + x, Expr c,x; separateMonomial(right[1], c, x); Theorem isIntx(isIntegerThm(x)); DebugAssert(!isIntx.isNull(), "right = "+right.toString() +"\n x = "+x.toString()); Theorem res(iffMP(eqn, d_rules->intVarEqnConst(eqn.getExpr(), isIntx))); TRACE("arith eq", "processSimpleIntEq[0 = c + a*x] => ", res, " }"); return res; } // Pick a suitable monomial. isolated can be of the form x, a.x, -a.x Expr isolated; bool nonlin; if (pickIntEqMonomial(right, isolated, nonlin)) { TRACE("arith eq", "processSimpleIntEq: isolated = ", isolated, ""); // First, we compute the 'sign factor' with which to multiply the // eqn. if the coeff of isolated is positive (i.e. 'isolated' is // of the form x or a.x where a>0 ) then r must be -1 and if coeff // of 'isolated' is negative, r=1. Rational r = isMult(isolated) ? ((isolated[0].getRational() > 0) ? -1 : 1) : -1; Theorem result; if (-1 == r) { // r=-1 and hence 'isolated' is 'x' or 'a.x' where a is // positive. modify eqn (0=e') to the equation (0=canon(-1*e')) result = iffMP(eqn, d_rules->multEqn(eqn.getLHS(), right, rat(r))); result = canonPred(result); Expr e = result.getRHS(); // Isolate the 'isolated' result = iffMP(result, d_rules->plusPredicate(result.getLHS(),result.getRHS(), isolated, EQ)); } else { //r is 1 and hence isolated is -a.x. Make 'isolated' positive. const Rational& minusa = isolated[0].getRational(); Rational a = -1*minusa; isolated = (a == 1)? isolated[1] : rat(a) * isolated[1]; // Isolate the 'isolated' result = iffMP(eqn, d_rules->plusPredicate(eqn.getLHS(), right,isolated,EQ)); } // Canonize the result result = canonPred(result); //if isolated is 'x' or 1*x, then return result else continue processing. if(!isMult(isolated) || isolated[0].getRational() == 1) { TRACE("arith eq", "processSimpleIntEq[x = rhs] => ", result, " }"); return result; } else if (!nonlin) { DebugAssert(isMult(isolated) && isolated[0].getRational() >= 2, "TheoryArithOld::processSimpleIntEq: isolated must be mult " "with coeff >= 2.\n isolated = " + isolated.toString()); // Compute IS_INTEGER() for lhs and rhs Expr lhs = result.getLHS(); Expr rhs = result.getRHS(); Expr a, x; separateMonomial(lhs, a, x); Theorem isIntLHS = isIntegerThm(x); vector isIntRHS; if(!isPlus(rhs)) { // rhs is a MULT Expr c, v; separateMonomial(rhs, c, v); isIntRHS.push_back(isIntegerThm(v)); DebugAssert(!isIntRHS.back().isNull(), ""); } else { // rhs is a PLUS DebugAssert(isPlus(rhs), "rhs = "+rhs.toString()); DebugAssert(rhs.arity() >= 2, "rhs = "+rhs.toString()); Expr::iterator i=rhs.begin(), iend=rhs.end(); ++i; // Skip the free constant for(; i!=iend; ++i) { Expr c, v; separateMonomial(*i, c, v); isIntRHS.push_back(isIntegerThm(v)); DebugAssert(!isIntRHS.back().isNull(), ""); } } // Derive (EXISTS (x:INT): x = t2 AND 0 = t3) result = d_rules->eqElimIntRule(result, isIntLHS, isIntRHS); // Skolemize the quantifier result = getCommonRules()->skolemize(result); // Canonize t2 and t3 generated by this rule DebugAssert(result.getExpr().isAnd() && result.getExpr().arity() == 2, "processSimpleIntEq: result = "+result.getExpr().toString()); Theorem thm1 = canonPred(getCommonRules()->andElim(result, 0)); Theorem thm2 = canonPred(getCommonRules()->andElim(result, 1)); Theorem newRes = getCommonRules()->andIntro(thm1, thm2); if(newRes.getExpr() != result.getExpr()) result = newRes; TRACE("arith eq", "processSimpleIntEq => ", result, " }"); return result; } } throw ArithException("Can't find a leaf for solve in "+eqn.toString()); } else { // eqn is 0 = x. Flip it and return Theorem result = symmetryRule(eqn); TRACE("arith eq", "processSimpleIntEq[x = 0] => ", result, " }"); return result; } } /*! input is 0=e' Theorem and all of the vars in e' are of * type INT. isolate one of them and send back to framework. output * is "var = e''" Theorem and some associated equations in * solved form. */ Theorem TheoryArithOld::processIntEq(const Theorem& eqn) { TRACE("arith eq", "processIntEq(", eqn.getExpr(), ") {"); // Equations in the solved form. std::vector solvedAndNewEqs; Theorem newEq(eqn), result; bool done(false); do { result = processSimpleIntEq(newEq); // 'result' is of the from (x1=t1) AND 0=t' if(result.isRewrite()) { solvedAndNewEqs.push_back(result); done = true; } else if (result.getExpr().isBoolConst()) { done = true; } else { DebugAssert(result.getExpr().isAnd() && result.getExpr().arity() == 2, "TheoryArithOld::processIntEq("+eqn.getExpr().toString() +")\n result = "+result.getExpr().toString()); solvedAndNewEqs.push_back(getCommonRules()->andElim(result, 0)); newEq = getCommonRules()->andElim(result, 1); } } while(!done); Theorem res; if (result.getExpr().isFalse()) res = result; else if (solvedAndNewEqs.size() > 0) res = solvedForm(solvedAndNewEqs); else res = result; TRACE("arith eq", "processIntEq => ", res.getExpr(), " }"); return res; } /*! * Takes a vector of equations and for every equation x_i=t_i * substitutes t_j for x_j in t_i for all j>i. This turns the system * of equations into a solved form. * * Assumption: variables x_j may appear in the RHS terms t_i ONLY for * i=j. */ Theorem TheoryArithOld::solvedForm(const vector& solvedEqs) { DebugAssert(solvedEqs.size() > 0, "TheoryArithOld::solvedForm()"); // Trace code TRACE_MSG("arith eq", "TheoryArithOld::solvedForm:solvedEqs(\n ["); IF_DEBUG(if(debugger.trace("arith eq")) { for(vector::const_iterator j = solvedEqs.begin(), jend=solvedEqs.end(); j!=jend;++j) TRACE("arith eq", "", j->getExpr(), ",\n "); }) TRACE_MSG("arith eq", " ]) {"); // End of Trace code vector::const_reverse_iterator i = solvedEqs.rbegin(), iend = solvedEqs.rend(); // Substitution map: a variable 'x' is mapped to a Theorem x=t. // This map accumulates the resulting solved form. ExprMap subst; for(; i!=iend; ++i) { if(i->isRewrite()) { Theorem thm = substAndCanonize(*i, subst); TRACE("arith eq", "solvedForm: subst["+i->getLHS().toString()+"] = ", thm.getExpr(), ""); subst[i->getLHS()] = thm; } else { // This is the FALSE case: just return the contradiction DebugAssert(i->getExpr().isFalse(), "TheoryArithOld::solvedForm: an element of solvedEqs must " "be either EQ or FALSE: "+i->toString()); return *i; } } // Now we've collected the solved form in 'subst'. Wrap it up into // a conjunction and return. vector thms; for(ExprMap::iterator i=subst.begin(), iend=subst.end(); i!=iend; ++i) thms.push_back(i->second); if (thms.size() > 1) return getCommonRules()->andIntro(thms); else return thms.back(); } /*! * ASSUMPTION: 't' is a fully canonized arithmetic term, and every * element of subst is a fully canonized equation of the form x=e, * indexed by the LHS variable. */ Theorem TheoryArithOld::substAndCanonize(const Expr& t, ExprMap& subst) { TRACE("arith eq", "substAndCanonize(", t, ") {"); // Quick and dirty check: return immediately if subst is empty if(subst.empty()) { Theorem res(reflexivityRule(t)); TRACE("arith eq", "substAndCanonize[subst empty] => ", res, " }"); return res; } // Check if we can substitute 't' directly ExprMap::iterator i = subst.find(t), iend=subst.end(); if(i!=iend) { TRACE("arith eq", "substAndCanonize[subst] => ", i->second, " }"); return i->second; } // The base case: t is an i-leaf if(isLeaf(t)) { Theorem res(reflexivityRule(t)); TRACE("arith eq", "substAndCanonize[i-leaf] => ", res, " }"); return res; } // 't' is an arithmetic term; recurse into the children vector thms; vector changed; for(unsigned j=0, jend=t.arity(); j!=jend; ++j) { Theorem thm = substAndCanonize(t[j], subst); if(thm.getRHS() != t[j]) { thm = canonThm(thm); thms.push_back(thm); changed.push_back(j); } } // Do the actual substitution and canonize the result Theorem res; if(thms.size() > 0) { res = substitutivityRule(t, changed, thms); res = canonThm(res); } else res = reflexivityRule(t); TRACE("arith eq", "substAndCanonize => ", res, " }"); return res; } /*! * ASSUMPTION: 't' is a fully canonized equation of the form x = t, * and so is every element of subst, indexed by the LHS variable. */ Theorem TheoryArithOld::substAndCanonize(const Theorem& eq, ExprMap& subst) { // Quick and dirty check: return immediately if subst is empty if(subst.empty()) return eq; DebugAssert(eq.isRewrite(), "TheoryArithOld::substAndCanonize: t = " +eq.getExpr().toString()); const Expr& t = eq.getRHS(); // Do the actual substitution in the term t Theorem thm = substAndCanonize(t, subst); // Substitution had no result: return the original equation if(thm.getRHS() == t) return eq; // Otherwise substitute the result into the equation vector thms; vector changed; thms.push_back(thm); changed.push_back(1); return iffMP(eq, substitutivityRule(eq.getExpr(), changed, thms)); } void TheoryArithOld::processBuffer() { // Process the inequalities in the buffer bool varOnRHS; // If we are in difference logic only, just return if (diffLogicOnly) return; while (!inconsistent() && (d_bufferIdx_0 < d_buffer_0.size() || d_bufferIdx_1 < d_buffer_1.size() || d_bufferIdx_2 < d_buffer_2.size() || d_bufferIdx_3 < d_buffer_3.size())) { // Get the unprojected inequality Theorem ineqThm; if (d_bufferIdx_0 < d_buffer_0.size()) { ineqThm = d_buffer_0[d_bufferIdx_0]; d_bufferIdx_0 = d_bufferIdx_0 + 1; } else if (d_bufferIdx_1 < d_buffer_1.size()) { ineqThm = d_buffer_1[d_bufferIdx_1]; d_bufferIdx_1 = d_bufferIdx_1 + 1; } else if (d_bufferIdx_2 < d_buffer_2.size()) { ineqThm = d_buffer_2[d_bufferIdx_2]; d_bufferIdx_2 = d_bufferIdx_2 + 1; } else { ineqThm = d_buffer_3[d_bufferIdx_3]; d_bufferIdx_3 = d_bufferIdx_3 + 1; } // // Skip this inequality if it is stale // if(isStale(ineqThm.getExpr())) { // TRACE("arith buffer", "processBuffer(", ineqThm.getExpr(), ")... skipping stale"); // continue; // } // Dejan: project the finds, not the originals (if not projected already) const Expr& inequality = ineqThm.getExpr(); Theorem inequalityFindThm = inequalityToFind(ineqThm, true); Expr inequalityFind = inequalityFindThm.getExpr(); // if (inequality != inequalityFind) // enqueueFact(inequalityFindThm); TRACE("arith buffer", "processing: ", inequality, ""); TRACE("arith buffer", "with find : ", inequalityFind, ""); if (!isIneq(inequalityFind)) { TRACE("arith buffer", "find not an inequality... ", "", "skipping"); continue; } if (alreadyProjected.find(inequalityFind) != alreadyProjected.end()) { TRACE("arith buffer", "already projected ... ", "", "skipping"); continue; } // We put the dummy for now, isolate variable will set it properly (or the find's one) // This one is just if the find is different. If the find is different // We will not check it again in update, so we're fine Expr dummy; alreadyProjected[inequality] = dummy; if (inequality != inequalityFind) { alreadyProjected[inequalityFind] = dummy; Expr rhs = inequalityFind[1]; // Collect the statistics about variables if(isPlus(rhs)) { for(Expr::iterator i=rhs.begin(), iend=rhs.end(); i!=iend; ++i) { Expr monomial = *i; updateStats(monomial); } } else // It's a monomial updateStats(rhs); } // See if this one is subsumed by a stronger inequality // c1 <= t1, t2 <= c2 Rational c1, c2; Expr t1, t2; // Every term in the buffer has to have a lower bound set!!! // Except for the ones that changed the find extractTermsFromInequality(inequalityFind, c1, t1, c2, t2); if (termLowerBound.find(t1) != termLowerBound.end() && c1 != termLowerBound[t1]) { TRACE("arith ineq", "skipping because stronger bounds asserted ", inequalityFind.toString(), ":" + t1.toString()); DebugAssert(termLowerBoundThm.find(t1) != termLowerBoundThm.end(), "No lower bound on asserted atom!!! " + t1.toString()); Theorem strongerBound = termLowerBoundThm[t1]; //enqueueFact(d_rules->implyWeakerInequality(strongerBound.getExpr(), inequalityFindThm.getExpr())); continue; } Theorem thm1 = isolateVariable(inequalityFindThm, varOnRHS); const Expr& ineq = thm1.getExpr(); if (ineq.isFalse()) setInconsistent(thm1); else if(!ineq.isTrue()) { // Check that the variable is indeed isolated correctly DebugAssert(varOnRHS? !isPlus(ineq[1]) : !isPlus(ineq[0]), "TheoryArithOld::processBuffer(): bad result from isolateVariable:\nineq = "+ineq.toString()); // Update the constained maps updateConstrained(inequalityFindThm.getExpr()); // and project the inequality projectInequalities(thm1, varOnRHS); } } } void TheoryArithOld::updateStats(const Rational& c, const Expr& v) { TRACE("arith stats", "updateStats("+c.toString()+", ", v, ")"); // we can get numbers as checking for variables is not possible (nonlinear stuff) if (v.isRational()) return; if (v.getType() != d_realType) { // Dejan: update the max coefficient of the variable if (c < 0) { // Goes to the left side ExprMap::iterator maxFind = maxCoefficientLeft.find(v); if (maxFind == maxCoefficientLeft.end()) { maxCoefficientLeft[v] = - c; TRACE("arith stats", "max left", "", ""); } else if ((*maxFind).second < -c) { TRACE("arith stats", "max left", "", ""); maxCoefficientLeft[v] = -c; } } else { // Stays on the right side ExprMap::iterator maxFind = maxCoefficientRight.find(v); if (maxFind == maxCoefficientRight.end()) { maxCoefficientRight[v] = c; TRACE("arith stats", "max right", "", ""); } else if((*maxFind).second < c) { TRACE("arith stats", "max right", "", ""); maxCoefficientRight[v] = c; } } } if(c > 0) { if(d_countRight.count(v) > 0) d_countRight[v] = d_countRight[v] + 1; else d_countRight[v] = 1; } else if(d_countLeft.count(v) > 0) d_countLeft[v] = d_countLeft[v] + 1; else d_countLeft[v] = 1; } void TheoryArithOld::updateStats(const Expr& monomial) { Expr c, m; separateMonomial(monomial, c, m); updateStats(c.getRational(), m); } int TheoryArithOld::extractTermsFromInequality(const Expr& inequality, Rational& c1, Expr& t1, Rational& c2, Expr& t2) { TRACE("arith extract", "extract(", inequality.toString(), ")"); DebugAssert(isIneq(inequality), "extractTermsFromInequality: expexting an inequality got: " + inequality.getString() + ")"); Expr rhs = inequality[1]; c1 = 0; // Extract the non-constant term (both sides) vector positive_children, negative_children; if (isPlus(rhs)) { int start_i = 0; if (rhs[0].isRational()) { start_i = 1; c1 = -rhs[0].getRational(); } int end_i = rhs.arity(); for(int i = start_i; i < end_i; i ++) { const Expr& term = rhs[i]; positive_children.push_back(term); negative_children.push_back(canon(multExpr(rat(-1),term)).getRHS()); } } else { positive_children.push_back(rhs); negative_children.push_back(canon(multExpr(rat(-1), rhs)).getRHS()); } int num_vars = positive_children.size(); // c1 <= t1 t1 = (num_vars > 1 ? canon(plusExpr(positive_children)).getRHS() : positive_children[0]); // c2 is the upper bound on t2 : t2 <= c2 c2 = -c1; t2 = (num_vars > 1 ? canon(plusExpr(negative_children)).getRHS() : negative_children[0]); TRACE("arith extract", "extract: ", c1.toString() + " <= ", t1.toString()); return num_vars; } bool TheoryArithOld::addToBuffer(const Theorem& thm, bool priority) { TRACE("arith buffer", "addToBuffer(", thm.getExpr().toString(), ")"); Expr ineq = thm.getExpr(); const Expr& rhs = thm.getExpr()[1]; bool nonLinear = false; Rational nonLinearConstant = 0; Expr compactNonLinear; Theorem compactNonLinearThm; // Collect the statistics about variables and check for non-linearity if(isPlus(rhs)) { for(Expr::iterator i=rhs.begin(), iend=rhs.end(); i!=iend; ++i) { Expr monomial = *i; updateStats(monomial); // check for non-linear if (isMult(monomial)) { if ((monomial[0].isRational() && monomial.arity() >= 3) || (!monomial[0].isRational() && monomial.arity() >= 2) || (monomial.arity() == 2 && isPow(monomial[1]))) nonLinear = true; } } if (nonLinear) { compactNonLinearThm = d_rules->compactNonLinearTerm(rhs); compactNonLinear = compactNonLinearThm.getRHS(); } } else // It's a monomial { updateStats(rhs); if (isMult(rhs)) if ((rhs[0].isRational() && rhs.arity() >= 3) || (!rhs[0].isRational() && rhs.arity() >= 2) || (rhs.arity() == 2 && isPow(rhs[1]))) { nonLinear = true; compactNonLinear = rhs; compactNonLinearThm = reflexivityRule(compactNonLinear); } } if (bufferedInequalities.find(ineq) != bufferedInequalities.end()) { TRACE("arith buffer", "addToBuffer()", "", "... already in db"); if (formulaAtoms.find(ineq) != formulaAtoms.end()) { TRACE("arith buffer", "it's a formula atom, enqueuing.", "", ""); enqueueFact(thm); } return false; } if (nonLinear && (isMult(rhs) || compactNonLinear != rhs)) { TRACE("arith nonlinear", "compact version of ", rhs, " is " + compactNonLinear.toString()); // Replace the rhs with the compacted nonlinear term Theorem thm1 = (compactNonLinear != rhs ? iffMP(thm, substitutivityRule(ineq, 1, compactNonLinearThm)) : thm); // Now, try to deduce the signednes of multipliers Rational c = (isMult(rhs) ? 0 : compactNonLinear[0].getRational()); // We can deduct the signs if the constant is not bigger than 0 if (c <= 0) { thm1 = d_rules->nonLinearIneqSignSplit(thm1); TRACE("arith nonlinear", "spliting on signs : ", thm1.getExpr(), ""); enqueueFact(thm1); } } // Get c1, c2, t1, t2 such that c1 <= t1 and t2 <= c2 Expr t1, t2; Rational c1, c2; int num_vars = extractTermsFromInequality(ineq, c1, t1, c2, t2); // If 2 variable, do add to difference logic (allways, just in case) bool factIsDiffLogic = false; if (num_vars <= 2) { TRACE("arith diff", t2, " < ", c2); // c1 <= t1, check if difference logic // t1 of the form 0 + ax + by Expr ax = (num_vars == 2 ? t2[1] : t2); Expr a_expr, x; separateMonomial(ax, a_expr, x); Rational a = a_expr.getRational(); Expr by = (num_vars == 2 ? t2[2] : (a < 0 ? zero : rat(-1)*zero)); Expr b_expr, y; separateMonomial(by, b_expr, y); Rational b = b_expr.getRational(); // Check for non-linear if (!isLeaf(x) || !isLeaf(y)) setIncomplete("Non-linear arithmetic inequalities"); if (a == 1 && b == -1) { diffLogicGraph.addEdge(x, y, c2, thm); factIsDiffLogic = true; } else if (a == -1 && b == 1) { diffLogicGraph.addEdge(y, x, c2, thm); factIsDiffLogic = true; } // Not difference logic, put it in the 3 or more vars buffer else { diffLogicOnly = false; TRACE("arith diff", "not diff logic", thm.getExpr().toString(), ""); } if (diffLogicGraph.isUnsat()) { TRACE("diff unsat", "UNSAT", " : ", diffLogicGraph.getUnsatTheorem()); setInconsistent(diffLogicGraph.getUnsatTheorem()); return false; } } else { diffLogicOnly = false; TRACE("arith diff", "not diff logic", thm.getExpr().toString(), ""); } // For now we treat all the bound as LE, weaker CDMap::iterator find_lower = termLowerBound.find(t1); if (find_lower != termLowerBound.end()) { // found bound c <= t1 Rational found_c = (*find_lower).second; // If found c is bigger than the new one, we are done if (c1 <= found_c && !(found_c == c1 && ineq.getKind() == LT)) { TRACE("arith buffer", "addToBuffer()", "", "... lower_bound subsumed"); // Removed assert. Can happen that an atom is not asserted yet, and get's implied as // a formula atom and then asserted here. it's fine //DebugAssert(!thm.isAssump(), "Should have been propagated: " + ineq.toString() + ""); return false; } else { Theorem oldLowerBound = termLowerBoundThm[t1]; Expr oldIneq = oldLowerBound.getExpr(); if (formulaAtoms.find(oldIneq) != formulaAtoms.end()) enqueueFact(getCommonRules()->implMP(thm, d_rules->implyWeakerInequality(ineq, oldIneq))); termLowerBound[t1] = c1; termLowerBoundThm[t1] = thm; } } else { termLowerBound[t1] = c1; termLowerBoundThm[t1] = thm; } CDMap::iterator find_upper = termUpperBound.find(t2); if (find_upper != termUpperBound.end()) { // found bound t2 <= c Rational found_c = (*find_upper).second; // If found c is smaller than the new one, we are done if (found_c <= c2 && !(found_c == c2 && ineq.getKind() == LT)) { TRACE("arith buffer", "addToBuffer()", "", "... upper_bound subsumed"); //DebugAssert(!thm.isAssump(), "Should have been propagated: " + ineq.toString() + ""); return false; } else { termUpperBound[t2] = c2; termUpperBoundThm[t2] = thm; } } else { termUpperBound[t2] = c2; termUpperBoundThm[t2] = thm; } // See if the bounds on the term can infer conflict or equality if (termUpperBound.find(t1) != termUpperBound.end() && termLowerBound.find(t1) != termLowerBound.end() && termUpperBound[t1] <= termLowerBound[t1]) { Theorem thm1 = termUpperBoundThm[t1]; Theorem thm2 = termLowerBoundThm[t1]; TRACE("arith propagate", "adding inequalities: ", thm1.getExpr().toString(), " with " + thm2.getExpr().toString()); enqueueFact(d_rules->addInequalities(thm1, thm2)); } else if (termUpperBound.find(t2) != termUpperBound.end() && termLowerBound.find(t2) != termLowerBound.end() && termUpperBound[t2] <= termLowerBound[t2]) { Theorem thm1 = termUpperBoundThm[t2]; Theorem thm2 = termLowerBoundThm[t2]; TRACE("arith propagate", "adding inequalities: ", thm1.getExpr().toString(), " with " + thm2.getExpr().toString()); enqueueFact(d_rules->addInequalities(thm1, thm2)); } if (true) { // See if we can propagate anything to the formula atoms // c1 <= t1 ===> c <= t1 for c < c1 AtomsMap::iterator find = formulaAtomLowerBound.find(t1); AtomsMap::iterator find_end = formulaAtomLowerBound.end(); if (find != find_end) { set< pair >::iterator bounds = (*find).second.begin(); set< pair >::iterator bounds_end = (*find).second.end(); while (bounds != bounds_end) { TRACE("arith atoms", "trying propagation", ineq, (*bounds).second); const Expr& implied = (*bounds).second; // Try to do some theory propagation if ((*bounds).first < c1 || (!(ineq.getKind() == LE && implied.getKind() == LT) && (*bounds).first == c1)) { // c1 <= t1 => c <= t1 (for c <= c1) // c1 < t1 => c <= t1 (for c <= c1) // c1 <= t1 => c < t1 (for c < c1) Theorem impliedThm = getCommonRules()->implMP(thm, d_rules->implyWeakerInequality(ineq, implied)); enqueueFact(impliedThm); } bounds ++; } } // // c1 <= t1 ==> !(t1 <= c) for c < c1 // ==> !(-c <= t2) // i.e. all coefficient in in the implied are opposite of t1 find = formulaAtomUpperBound.find(t1); find_end = formulaAtomUpperBound.end(); if (find != find_end) { set< pair >::iterator bounds = (*find).second.begin(); set< pair >::iterator bounds_end = (*find).second.end(); while (bounds != bounds_end) { TRACE("arith atoms", "trying propagation", ineq, (*bounds).second); const Expr& implied = (*bounds).second; // Try to do some theory propagation if ((*bounds).first < c1) { Theorem impliedThm = getCommonRules()->implMP(thm, d_rules->implyNegatedInequality(ineq, implied)); enqueueFact(impliedThm); } bounds ++; } } } // Register this as a resource theoryCore()->getResource(); // If out of resources, bail out if (theoryCore()->outOfResources()) return false; // Checking because we could have projected it as a find of some other // equation if (alreadyProjected.find(ineq) == alreadyProjected.end()) { // We buffer it if it's not marked for not buffering if (dontBuffer.find(ineq) == dontBuffer.end()) { // We give priority to the one that can produce a conflict if (priority) d_buffer_0.push_back(thm); else { // Push it into the buffer (one var) if (num_vars == 1) d_buffer_1.push_back(thm); else if (num_vars == 2) d_buffer_2.push_back(thm); else d_buffer_3.push_back(thm); } if (factIsDiffLogic) diff_logic_size = diff_logic_size + 1; } } // Remember that it's in the buffer bufferedInequalities[ineq] = thm; // Since we care about this atom, lets set it up if (!ineq.hasFind()) theoryCore()->setupTerm(ineq, this, thm); return true; } Theorem TheoryArithOld::isolateVariable(const Theorem& inputThm, bool& isolatedVarOnRHS) { Theorem result(inputThm); const Expr& e = inputThm.getExpr(); TRACE("arith","isolateVariable(",e,") {"); TRACE("arith ineq", "isolateVariable(", e, ") {"); //we assume all the children of e are canonized DebugAssert(isLT(e)||isLE(e), "TheoryArithOld::isolateVariable: " + e.toString() + " wrong kind"); int kind = e.getKind(); DebugAssert(e[0].isRational() && e[0].getRational() == 0, "TheoryArithOld::isolateVariable: theorem must be of " "the form 0 < rhs: " + inputThm.toString()); const Expr& zero = e[0]; Expr right = e[1]; // Check for trivial in-equation. if (right.isRational()) { result = iffMP(result, d_rules->constPredicate(e)); TRACE("arith ineq","isolateVariable => ",result.getExpr()," }"); TRACE("arith","isolateVariable => ",result," }"); return result; } // Normalization of inequality to make coefficients integer and // relatively prime. Expr factor(computeNormalFactor(right, false)); TRACE("arith", "isolateVariable: factor = ", factor, ""); DebugAssert(factor.getRational() > 0, "isolateVariable: factor="+factor.toString()); // Now multiply the inequality by the factor, unless it is 1 if(factor.getRational() != 1) { result = iffMP(result, d_rules->multIneqn(e, factor)); // And canonize the result result = canonPred(result); result = rafineInequalityToInteger(result); right = result.getExpr()[1]; } // Find monomial to isolate and store it in isolatedMonomial Expr isolatedMonomial = right; if (isPlus(right)) isolatedMonomial = pickMonomial(right); TRACE("arith ineq", "isolatedMonomial => ",isolatedMonomial,""); // Set the correct isolated monomial // Now, if something gets updated, but this monomial is not changed, we don't // Have to rebuffer it as the projection will still be accurate when updated alreadyProjected[e] = isolatedMonomial; Rational r = -1; isolatedVarOnRHS = true; if (isMult(isolatedMonomial)) { r = ((isolatedMonomial[0].getRational()) >= 0)? -1 : 1; isolatedVarOnRHS = ((isolatedMonomial[0].getRational()) >= 0)? true : false; } isolatedMonomial = canon(rat(-1)*isolatedMonomial).getRHS(); TRACE("arith ineq", "-(isolatedMonomial) => ",isolatedMonomial,""); // Isolate isolatedMonomial on to the LHS result = iffMP(result, d_rules->plusPredicate(zero, right, isolatedMonomial, kind)); // Canonize the resulting inequality TRACE("arith ineq", "resutl => ",result,""); result = canonPred(result); if(1 != r) { result = iffMP(result, d_rules->multIneqn(result.getExpr(), rat(r))); result = canonPred(result); } TRACE("arith ineq","isolateVariable => ",result.getExpr()," }"); TRACE("arith","isolateVariable => ",result," }"); return result; } Expr TheoryArithOld::computeNormalFactor(const Expr& right, bool normalizeConstants) { // Strategy: compute f = lcm(d1...dn)/gcd(c1...cn), where the RHS is // of the form c1/d1*x1 + ... + cn/dn*xn Rational factor; if(isPlus(right)) { vector nums, denoms; for(int i=0, iend=right.arity(); i fc.getConst() || (c == fc.getConst() && strict && !fc.strict())); } bool res; if(subsumed) { res = true; TRACE("arith ineq", "isStale[subsumed] => ", res? "true" : "false", " }"); } else { res = isStale(ineqExpr); TRACE("arith ineq", "isStale[updated] => ", res? "true" : "false", " }"); } return res; } void TheoryArithOld::separateMonomial(const Expr& e, Expr& c, Expr& var) { TRACE("separateMonomial", "separateMonomial(", e, ")"); DebugAssert(!isPlus(e), "TheoryArithOld::separateMonomial(e = "+e.toString()+")"); if(isMult(e)) { DebugAssert(e.arity() >= 2, "TheoryArithOld::separateMonomial(e = "+e.toString()+")"); c = e[0]; if(e.arity() == 2) var = e[1]; else { vector kids = e.getKids(); kids[0] = rat(1); var = multExpr(kids); } } else { c = rat(1); var = e; } DebugAssert(c.isRational(), "TheoryArithOld::separateMonomial(e = " +e.toString()+", c = "+c.toString()+")"); DebugAssert(!isMult(var) || (var[0].isRational() && var[0].getRational()==1), "TheoryArithOld::separateMonomial(e = " +e.toString()+", var = "+var.toString()+")"); } void TheoryArithOld::projectInequalities(const Theorem& theInequality, bool isolatedVarOnRHS) { TRACE("arith project", "projectInequalities(", theInequality.getExpr(), ", isolatedVarOnRHS="+string(isolatedVarOnRHS? "true" : "false") +") {"); DebugAssert(isLE(theInequality.getExpr()) || isLT(theInequality.getExpr()), "TheoryArithOld::projectIsolatedVar: "\ "theInequality is of the wrong form: " + theInequality.toString()); //TODO: DebugAssert to check if the isolatedMonomial is of the right //form and the whether we are indeed getting inequalities. Theorem theIneqThm(theInequality); Expr theIneq = theIneqThm.getExpr(); // If the inequality is strict and integer, change it to non-strict if(isLT(theIneq)) { Theorem isIntLHS(isIntegerThm(theIneq[0])); Theorem isIntRHS(isIntegerThm(theIneq[1])); if ((!isIntLHS.isNull() && !isIntRHS.isNull())) { Theorem thm = d_rules->lessThanToLE(theInequality, isIntLHS, isIntRHS, !isolatedVarOnRHS); theIneqThm = canonPred(iffMP(theIneqThm, thm)); theIneq = theIneqThm.getExpr(); } } Expr isolatedMonomial = isolatedVarOnRHS ? theIneq[1] : theIneq[0]; Expr monomialVar, a; separateMonomial(isolatedMonomial, a, monomialVar); bool subsumed; const FreeConst& bestConst = updateSubsumptionDB(theIneq, isolatedVarOnRHS, subsumed); if(subsumed) { IF_DEBUG(debugger.counter("subsumed inequalities")++;) TRACE("arith ineq", "subsumed inequality: ", theIneq, ""); } else { // If the isolated variable is actually a non-linear term, we are // incomplete if(isMult(monomialVar) || isPow(monomialVar)) setIncomplete("Non-linear arithmetic inequalities"); // First, we need to make sure the isolated inequality is // setup properly. // setupRec(theIneq[0]); // setupRec(theIneq[1]); theoryCore()->setupTerm(theIneq[0], this, theIneqThm); theoryCore()->setupTerm(theIneq[1], this, theIneqThm); // Add the inequality into the appropriate DB. ExprMap *>& db1 = isolatedVarOnRHS ? d_inequalitiesRightDB : d_inequalitiesLeftDB; ExprMap *>::iterator it1 = db1.find(monomialVar); if(it1 == db1.end()) { CDList * list = new(true) CDList(theoryCore()->getCM()->getCurrentContext()); list->push_back(Ineq(theIneqThm, isolatedVarOnRHS, bestConst)); db1[monomialVar] = list; } else ((*it1).second)->push_back(Ineq(theIneqThm, isolatedVarOnRHS, bestConst)); ExprMap *>& db2 = isolatedVarOnRHS ? d_inequalitiesLeftDB : d_inequalitiesRightDB; ExprMap *>::iterator it = db2.find(monomialVar); if(it == db2.end()) { TRACE_MSG("arith ineq", "projectInequalities[not in DB] => }"); return; } CDList& listOfDBIneqs = *((*it).second); Theorem betaLTt, tLTalpha, thm; for(int i = listOfDBIneqs.size() - 1; !inconsistent() && i >= 0; --i) { const Ineq& ineqEntry = listOfDBIneqs[i]; const Theorem& ineqThm = ineqEntry.ineq(); //inequalityToFind(ineqEntry.ineq(), isolatedVarOnRHS); // ineqExntry might be stale if(!isStale(ineqEntry)) { betaLTt = isolatedVarOnRHS ? theIneqThm : ineqThm; tLTalpha = isolatedVarOnRHS ? ineqThm : theIneqThm; thm = normalizeProjectIneqs(betaLTt, tLTalpha); if (thm.isNull()) continue; IF_DEBUG(debugger.counter("real shadows")++;) // Check for TRUE and FALSE theorems Expr e(thm.getExpr()); if(e.isFalse()) { setInconsistent(thm); TRACE_MSG("arith ineq", "projectInequalities[inconsistent] => }"); return; } else { if(!e.isTrue() && !e.isEq()) { // setup the term so that it comes out in updates addToBuffer(thm, false); } else if(e.isEq()) enqueueFact(thm); } } else { IF_DEBUG(debugger.counter("stale inequalities")++;) } } } TRACE_MSG("arith ineq", "projectInequalities => }"); } Theorem TheoryArithOld::normalizeProjectIneqs(const Theorem& ineqThm1, const Theorem& ineqThm2) { //ineq1 is of the form beta < b.x or beta < x [ or with <= ] //ineq2 is of the form a.x < alpha or x < alpha. Theorem betaLTt = ineqThm1, tLTalpha = ineqThm2; Expr ineq1 = betaLTt.getExpr(); Expr ineq2 = tLTalpha.getExpr(); Expr c,x; separateMonomial(ineq2[0], c, x); Theorem isIntx(isIntegerThm(x)); Theorem isIntBeta(isIntegerThm(ineq1[0])); Theorem isIntAlpha(isIntegerThm(ineq2[1])); bool isInt = !(isIntx.isNull() || isIntBeta.isNull() || isIntAlpha.isNull()); TRACE("arith ineq", "normalizeProjectIneqs(", ineq1, ", "+ineq2.toString()+") {"); DebugAssert((isLE(ineq1) || isLT(ineq1)) && (isLE(ineq2) || isLT(ineq2)), "TheoryArithOld::normalizeProjectIneqs: Wrong Kind inputs: " + ineq1.toString() + ineq2.toString()); DebugAssert(!isPlus(ineq1[1]) && !isPlus(ineq2[0]), "TheoryArithOld::normalizeProjectIneqs: Wrong Kind inputs: " + ineq1.toString() + ineq2.toString()); //compute the factors to multiply the two inequalities with //so that they get the form beta < t and t < alpha. Rational factor1 = 1, factor2 = 1; Rational b = isMult(ineq1[1]) ? (ineq1[1])[0].getRational() : 1; Rational a = isMult(ineq2[0]) ? (ineq2[0])[0].getRational() : 1; if(b != a) { factor1 = a; factor2 = b; } //if the ineqs are of type int then apply one of the gray //dark shadow rules. // FIXME: intResult should also be checked for immediate // optimizations, as those below for 'result'. Also, if intResult // is a single inequality, we may want to handle it similarly to the // 'result' rather than enqueuing directly. if(isInt && (a >= 2 || b >= 2)) { Theorem intResult; if(a <= b) intResult = d_rules->darkGrayShadow2ab(betaLTt, tLTalpha, isIntAlpha, isIntBeta, isIntx); else intResult = d_rules->darkGrayShadow2ba(betaLTt, tLTalpha, isIntAlpha, isIntBeta, isIntx); enqueueFact(intResult); // Fetch dark and gray shadows const Expr& DorG = intResult.getExpr(); DebugAssert(DorG.isOr() && DorG.arity()==2, "DorG = "+DorG.toString()); const Expr& G = DorG[1]; DebugAssert(G.getKind()==GRAY_SHADOW, "G = "+G.toString()); // Set the higher splitter priority for dark shadow // Expr tmp = simplifyExpr(D); // if (!tmp.isBoolConst()) // addSplitter(tmp, 5); // Also set a higher priority to the NEGATION of GRAY_SHADOW Expr tmp = simplifyExpr(!G); if (!tmp.isBoolConst()) addSplitter(tmp, 1); IF_DEBUG(debugger.counter("dark+gray shadows")++;) // Dejan: Let's forget about the real shadow, we are doing integers // /return intResult; } //actually normalize the inequalities if(1 != factor1) { Theorem thm2 = iffMP(betaLTt, d_rules->multIneqn(ineq1, rat(factor1))); betaLTt = canonPred(thm2); ineq1 = betaLTt.getExpr(); } if(1 != factor2) { Theorem thm2 = iffMP(tLTalpha, d_rules->multIneqn(ineq2, rat(factor2))); tLTalpha = canonPred(thm2); ineq2 = tLTalpha.getExpr(); } //IF_DEBUG(debugger.counter("real shadows")++;) Expr beta(ineq1[0]); Expr alpha(ineq2[1]); // In case of alpha <= t <= alpha, we generate t = alpha if(isLE(ineq1) && isLE(ineq2) && alpha == beta) { Theorem result = d_rules->realShadowEq(betaLTt, tLTalpha); TRACE("arith ineq", "normalizeProjectIneqs => ", result, " }"); return result; } // Check if this inequality is a finite interval // if(isInt) // processFiniteInterval(betaLTt, tLTalpha); // // Only do the real shadow if a and b = 1 // if (isInt && a > 1 && b > 1) // return Theorem(); //project the normalized inequalities. Theorem result = d_rules->realShadow(betaLTt, tLTalpha); // FIXME: Clark's changes. Is 'rewrite' more or less efficient? // result = iffMP(result, rewrite(result.getExpr())); // TRACE("arith ineq", "normalizeProjectIneqs => ", result, " }"); // Now, transform the result into 0 < rhs and see if rhs is a const Expr e(result.getExpr()); // int kind = e.getKind(); if(!(e[0].isRational() && e[0].getRational() == 0)) result = iffMP(result, d_rules->rightMinusLeft(e)); result = canonPred(result); //result is "0 kind e'". where e' is equal to canon(e[1]-e[0]) Expr right = result.getExpr()[1]; // Check for trivial inequality if (right.isRational()) result = iffMP(result, d_rules->constPredicate(result.getExpr())); else result = normalize(result); TRACE("arith ineq", "normalizeProjectIneqs => ", result, " }"); return result; } Rational TheoryArithOld::currentMaxCoefficient(Expr var) { // We prefer real variables if (var.getType() == d_realType) return -100; // Find the biggest left side coefficient ExprMap::iterator findMaxLeft = maxCoefficientLeft.find(var); Rational leftMax = -1; if (findMaxLeft != maxCoefficientLeft.end()) leftMax = (*findMaxLeft).second; // ExprMap::iterator findMaxRight = maxCoefficientRight.find(var); Rational rightMax = -1; if (findMaxRight != maxCoefficientRight.end()) rightMax = (*findMaxRight).second; // What is the max coefficient // If one is undefined, dont take it. My first thought was to project away unbounded // ones, but it happens that you get another constraint on it later and the hell breaks // loose if they have big coefficients. Rational returnValue; if (leftMax == -1) returnValue = rightMax; else if (rightMax == -1) returnValue = leftMax; else if (leftMax < rightMax) returnValue = rightMax; else returnValue = leftMax; TRACE("arith stats", "max coeff of ", var.toString(), ": " + returnValue.toString() + "(left=" + leftMax.toString() + ",right=" + rightMax.toString()); return returnValue; } void TheoryArithOld::fixCurrentMaxCoefficient(Expr var, Rational max) { fixedMaxCoefficient[var] = max; } void TheoryArithOld::selectSmallestByCoefficient(const vector& input, vector& output) { // Clear the output vector output.clear(); // Get the first variable, and set it as best Expr best_variable = input[0]; Rational best_coefficient = currentMaxCoefficient(best_variable); output.push_back(best_variable); for(unsigned int i = 1; i < input.size(); i ++) { // Get the current variable Expr current_variable = input[i]; // Get the current variable's max coefficient Rational current_coefficient = currentMaxCoefficient(current_variable); // If strictly better than the current best, remember it if ((current_coefficient < best_coefficient)) { best_variable = current_variable; best_coefficient = current_coefficient; output.clear(); } // If equal to the current best, push it to the stack (in 10% range) if (current_coefficient == best_coefficient) output.push_back(current_variable); } // Fix the selected best coefficient //fixCurrentMaxCoefficient(best_variable, best_coefficient); } Expr TheoryArithOld::pickMonomial(const Expr& right) { DebugAssert(isPlus(right), "TheoryArithOld::pickMonomial: Wrong Kind: " + right.toString()); if(theoryCore()->getFlags()["var-order"].getBool()) { Expr::iterator i = right.begin(); Expr isolatedMonomial = right[1]; //PLUS always has at least two elements and the first element is //always a constant. hence ++i in the initialization of the for //loop. for(++i; i != right.end(); ++i) if(lessThanVar(isolatedMonomial,*i)) isolatedMonomial = *i; return isolatedMonomial; } ExprMap var2monomial; vector vars; Expr::iterator i = right.begin(), iend = right.end(); for(;i != iend; ++i) { if(i->isRational()) continue; Expr c, var; separateMonomial(*i, c, var); var2monomial[var] = *i; vars.push_back(var); } vector largest; d_graph.selectLargest(vars, largest); DebugAssert(0 < largest.size(), "TheoryArithOld::pickMonomial: selectLargest: failed!!!!"); // DEJAN: Rafine the largest by coefficient values vector largest_small_coeff; selectSmallestByCoefficient(largest, largest_small_coeff); DebugAssert(0 < largest_small_coeff.size(), "TheoryArithOld::pickMonomial: selectLargestByCOefficient: failed!!!!"); size_t pickedVar = 0; // Pick the variable which will generate the fewest number of // projections size_t size = largest_small_coeff.size(); int minProjections = -1; if (size > 1) for(size_t k=0; k< size; ++k) { const Expr& var(largest_small_coeff[k]), monom(var2monomial[var]); // Grab the counters for the variable int nRight = (d_countRight.count(var) > 0)? d_countRight[var] : 0; int nLeft = (d_countLeft.count(var) > 0)? d_countLeft[var] : 0; int n(nRight*nLeft); TRACE("arith ineq", "pickMonomial: var=", var, ", nRight="+int2string(nRight)+", nLeft="+int2string(nLeft)); if(minProjections < 0 || minProjections > n) { minProjections = n; pickedVar = k; } TRACE("arith ineq", "Number of projections for "+var.toString()+" = ", n, ""); } const Expr& largestVar = largest_small_coeff[pickedVar]; // FIXME: TODO: update the counters (subtract counts for the vars // other than largestVar // Update the graph (all edges to the largest in the graph, not just the small coefficients). for(size_t k = 0; k < vars.size(); ++k) { if(vars[k] != largestVar) d_graph.addEdge(largestVar, vars[k]); } TRACE("arith buffer", "picked var : ", var2monomial[largestVar].toString(), ""); return var2monomial[largestVar]; } void TheoryArithOld::VarOrderGraph::addEdge(const Expr& e1, const Expr& e2) { TRACE("arith var order", "addEdge("+e1.toString()+" > ", e2, ")"); DebugAssert(e1 != e2, "TheoryArithOld::VarOrderGraph::addEdge(" +e1.toString()+", "+e2.toString()+")"); d_edges[e1].push_back(e2); } //returns true if e1 < e2, else false(i.e e2 < e1 or e1,e2 are not //comparable) bool TheoryArithOld::VarOrderGraph::lessThan(const Expr& e1, const Expr& e2) { d_cache.clear(); //returns true if e1 is in the subtree rooted at e2 implying e1 < e2 return dfs(e1,e2); } //returns true if e1 is in the subtree rooted at e2 implying e1 < e2 bool TheoryArithOld::VarOrderGraph::dfs(const Expr& e1, const Expr& e2) { if(e1 == e2) return true; if(d_cache.count(e2) > 0) return false; if(d_edges.count(e2) == 0) return false; d_cache[e2] = true; vector& e2Edges = d_edges[e2]; vector::iterator i = e2Edges.begin(); vector::iterator iend = e2Edges.end(); //if dfs finds e1 then i != iend else i is equal to iend for(; i != iend && !dfs(e1,*i); ++i); return (i != iend); } void TheoryArithOld::VarOrderGraph::dfs(const Expr& v, vector& output_list) { TRACE("arith shared", "dfs(", v.toString(), ")"); // If visited already we are done if (d_cache.count(v) > 0) return; // Dfs further if(d_edges.count(v) != 0) { // We have edges, so lets dfs it further vector& vEdges = d_edges[v]; vector::iterator e = vEdges.begin(); vector::iterator e_end = vEdges.end(); while (e != e_end) { dfs(*e, output_list); e ++; } } // Mark as visited and add to the output list d_cache[v] = true; output_list.push_back(v); } void TheoryArithOld::VarOrderGraph::getVerticesTopological(vector& output_list) { // Clear the cache d_cache.clear(); output_list.clear(); // Go through all the vertices and run a dfs from them ExprMap< vector >::iterator v_it = d_edges.begin(); ExprMap< vector >::iterator v_it_end = d_edges.end(); while (v_it != v_it_end) { // Run dfs from this vertex dfs(v_it->first, output_list); // Go to the next one v_it ++; } } void TheoryArithOld::VarOrderGraph::selectSmallest(vector& v1, vector& v2) { int v1Size = v1.size(); vector v3(v1Size); for(int j=0; j < v1Size; ++j) v3[j] = false; for(int j=0; j < v1Size; ++j) { if(v3[j]) continue; for(int i =0; i < v1Size; ++i) { if((i == j) || v3[i]) continue; if(lessThan(v1[i],v1[j])) { v3[j] = true; break; } } } vector new_v1; for(int j = 0; j < v1Size; ++j) if(!v3[j]) v2.push_back(v1[j]); else new_v1.push_back(v1[j]); v1 = new_v1; } void TheoryArithOld::VarOrderGraph::selectLargest(const vector& v1, vector& v2) { int v1Size = v1.size(); vector v3(v1Size); for(int j=0; j < v1Size; ++j) v3[j] = false; for(int j=0; j < v1Size; ++j) { if(v3[j]) continue; for(int i =0; i < v1Size; ++i) { if((i == j) || v3[i]) continue; if(lessThan(v1[j],v1[i])) { v3[j] = true; break; } } } for(int j = 0; j < v1Size; ++j) if(!v3[j]) v2.push_back(v1[j]); } /////////////////////////////////////////////////////////////////////////////// // TheoryArithOld Public Methods // /////////////////////////////////////////////////////////////////////////////// TheoryArithOld::TheoryArithOld(TheoryCore* core) : TheoryArith(core, "ArithmeticOld"), d_diseq(core->getCM()->getCurrentContext()), d_diseqIdx(core->getCM()->getCurrentContext(), 0, 0), diseqSplitAlready(core->getCM()->getCurrentContext()), d_inModelCreation(core->getCM()->getCurrentContext(), false, 0), d_freeConstDB(core->getCM()->getCurrentContext()), d_buffer_0(core->getCM()->getCurrentContext()), d_buffer_1(core->getCM()->getCurrentContext()), d_buffer_2(core->getCM()->getCurrentContext()), d_buffer_3(core->getCM()->getCurrentContext()), // Initialize index to 0 at scope 0 d_bufferIdx_0(core->getCM()->getCurrentContext(), 0, 0), d_bufferIdx_1(core->getCM()->getCurrentContext(), 0, 0), d_bufferIdx_2(core->getCM()->getCurrentContext(), 0, 0), d_bufferIdx_3(core->getCM()->getCurrentContext(), 0, 0), diff_logic_size(core->getCM()->getCurrentContext(), 0, 0), d_bufferThres(&(core->getFlags()["ineq-delay"].getInt())), d_splitSign(&(core->getFlags()["nonlinear-sign-split"].getBool())), d_grayShadowThres(&(core->getFlags()["grayshadow-threshold"].getInt())), d_countRight(core->getCM()->getCurrentContext()), d_countLeft(core->getCM()->getCurrentContext()), d_sharedTerms(core->getCM()->getCurrentContext()), d_sharedTermsList(core->getCM()->getCurrentContext()), d_sharedVars(core->getCM()->getCurrentContext()), bufferedInequalities(core->getCM()->getCurrentContext()), termLowerBound(core->getCM()->getCurrentContext()), termLowerBoundThm(core->getCM()->getCurrentContext()), termUpperBound(core->getCM()->getCurrentContext()), termUpperBoundThm(core->getCM()->getCurrentContext()), alreadyProjected(core->getCM()->getCurrentContext()), dontBuffer(core->getCM()->getCurrentContext()), diffLogicOnly(core->getCM()->getCurrentContext(), true, 0), diffLogicGraph(0, core, 0, core->getCM()->getCurrentContext()), shared_index_1(core->getCM()->getCurrentContext(), 0, 0), shared_index_2(core->getCM()->getCurrentContext(), 0, 0), termUpperBounded(core->getCM()->getCurrentContext()), termLowerBounded(core->getCM()->getCurrentContext()), d_varConstrainedPlus(core->getCM()->getCurrentContext()), d_varConstrainedMinus(core->getCM()->getCurrentContext()), termConstrainedBelow(core->getCM()->getCurrentContext()), termConstrainedAbove(core->getCM()->getCurrentContext()) { IF_DEBUG(d_diseq.setName("CDList[TheoryArithOld::d_diseq]");) IF_DEBUG(d_buffer_0.setName("CDList[TheoryArithOld::d_buffer_0]");) IF_DEBUG(d_buffer_1.setName("CDList[TheoryArithOld::d_buffer_1]");) IF_DEBUG(d_buffer_2.setName("CDList[TheoryArithOld::d_buffer_2]");) IF_DEBUG(d_buffer_3.setName("CDList[TheoryArithOld::d_buffer_3]");) IF_DEBUG(d_bufferIdx_1.setName("CDList[TheoryArithOld::d_bufferIdx_0]");) IF_DEBUG(d_bufferIdx_1.setName("CDList[TheoryArithOld::d_bufferIdx_1]");) IF_DEBUG(d_bufferIdx_2.setName("CDList[TheoryArithOld::d_bufferIdx_2]");) IF_DEBUG(d_bufferIdx_3.setName("CDList[TheoryArithOld::d_bufferIdx_3]");) getEM()->newKind(REAL, "_REAL", true); getEM()->newKind(INT, "_INT", true); getEM()->newKind(SUBRANGE, "_SUBRANGE", true); getEM()->newKind(UMINUS, "_UMINUS"); getEM()->newKind(PLUS, "_PLUS"); getEM()->newKind(MINUS, "_MINUS"); getEM()->newKind(MULT, "_MULT"); getEM()->newKind(DIVIDE, "_DIVIDE"); getEM()->newKind(POW, "_POW"); getEM()->newKind(INTDIV, "_INTDIV"); getEM()->newKind(MOD, "_MOD"); getEM()->newKind(LT, "_LT"); getEM()->newKind(LE, "_LE"); getEM()->newKind(GT, "_GT"); getEM()->newKind(GE, "_GE"); getEM()->newKind(IS_INTEGER, "_IS_INTEGER"); getEM()->newKind(NEGINF, "_NEGINF"); getEM()->newKind(POSINF, "_POSINF"); getEM()->newKind(DARK_SHADOW, "_DARK_SHADOW"); getEM()->newKind(GRAY_SHADOW, "_GRAY_SHADOW"); getEM()->newKind(REAL_CONST, "_REAL_CONST"); d_kinds.push_back(REAL); d_kinds.push_back(INT); d_kinds.push_back(SUBRANGE); d_kinds.push_back(IS_INTEGER); d_kinds.push_back(UMINUS); d_kinds.push_back(PLUS); d_kinds.push_back(MINUS); d_kinds.push_back(MULT); d_kinds.push_back(DIVIDE); d_kinds.push_back(POW); d_kinds.push_back(INTDIV); d_kinds.push_back(MOD); d_kinds.push_back(LT); d_kinds.push_back(LE); d_kinds.push_back(GT); d_kinds.push_back(GE); d_kinds.push_back(RATIONAL_EXPR); d_kinds.push_back(NEGINF); d_kinds.push_back(POSINF); d_kinds.push_back(DARK_SHADOW); d_kinds.push_back(GRAY_SHADOW); d_kinds.push_back(REAL_CONST); registerTheory(this, d_kinds, true); d_rules = createProofRulesOld(); diffLogicGraph.setRules(d_rules); diffLogicGraph.setArith(this); d_realType = Type(getEM()->newLeafExpr(REAL)); d_intType = Type(getEM()->newLeafExpr(INT)); // Make the zero variable Theorem thm_exists_zero = getCommonRules()->varIntroSkolem(rat(0)); zero = thm_exists_zero.getExpr()[1]; } // Destructor: delete the proof rules class if it's present TheoryArithOld::~TheoryArithOld() { if(d_rules != NULL) delete d_rules; // Clear the inequality databases for(ExprMap *>::iterator i=d_inequalitiesRightDB.begin(), iend=d_inequalitiesRightDB.end(); i!=iend; ++i) { delete (i->second); free(i->second); } for(ExprMap *>::iterator i=d_inequalitiesLeftDB.begin(), iend=d_inequalitiesLeftDB.end(); i!=iend; ++i) { delete (i->second); free (i->second); } unregisterTheory(this, d_kinds, true); } void TheoryArithOld::collectVars(const Expr& e, vector& vars, set& cache) { // Check the cache first if(cache.count(e) > 0) return; // Not processed yet. Cache the expression and proceed cache.insert(e); if(isLeaf(e)) vars.push_back(e); else for(Expr::iterator i=e.begin(), iend=e.end(); i!=iend; ++i) collectVars(*i, vars, cache); } void TheoryArithOld::processFiniteInterval (const Theorem& alphaLEax, const Theorem& bxLEbeta) { const Expr& ineq1(alphaLEax.getExpr()); const Expr& ineq2(bxLEbeta.getExpr()); DebugAssert(isLE(ineq1), "TheoryArithOld::processFiniteInterval: ineq1 = " +ineq1.toString()); DebugAssert(isLE(ineq2), "TheoryArithOld::processFiniteInterval: ineq2 = " +ineq2.toString()); // If the inequalities are not integer, just return (nothing to do) if(!isInteger(ineq1[0]) || !isInteger(ineq1[1]) || !isInteger(ineq2[0]) || !isInteger(ineq2[1])) return; const Expr& ax = ineq1[1]; const Expr& bx = ineq2[0]; DebugAssert(!isPlus(ax) && !isRational(ax), "TheoryArithOld::processFiniteInterval:\n ax = "+ax.toString()); DebugAssert(!isPlus(bx) && !isRational(bx), "TheoryArithOld::processFiniteInterval:\n bx = "+bx.toString()); Expr a = isMult(ax)? ax[0] : rat(1); Expr b = isMult(bx)? bx[0] : rat(1); Theorem thm1(alphaLEax), thm2(bxLEbeta); // Multiply the inequalities by 'b' and 'a', and canonize them, if necessary if(a != b) { thm1 = canonPred(iffMP(alphaLEax, d_rules->multIneqn(ineq1, b))); thm2 = canonPred(iffMP(bxLEbeta, d_rules->multIneqn(ineq2, a))); } // Check that a*beta - b*alpha == c > 0 const Expr& alphaLEt = thm1.getExpr(); const Expr& alpha = alphaLEt[0]; const Expr& t = alphaLEt[1]; const Expr& beta = thm2.getExpr()[1]; Expr c = canon(beta - alpha).getRHS(); if(c.isRational() && c.getRational() >= 1) { // This is a finite interval. First, derive t <= alpha + c: // canon(alpha+c) => (alpha+c == beta) ==> [symmetry] beta == alpha+c // Then substitute that in thm2 Theorem bEQac = symmetryRule(canon(alpha + c)); // Substitute beta == alpha+c for the second child of thm2 vector changed; vector thms; changed.push_back(1); thms.push_back(bEQac); Theorem tLEac = substitutivityRule(thm2.getExpr(), changed, thms); tLEac = iffMP(thm2, tLEac); // Derive and enqueue the finite interval constraint Theorem isInta(isIntegerThm(alpha)); Theorem isIntt(isIntegerThm(t)); if (d_sharedTerms.find(thm1.getExpr()[1]) != d_sharedTerms.end()) enqueueFact(d_rules->finiteInterval(thm1, tLEac, isInta, isIntt)); } } void TheoryArithOld::processFiniteIntervals(const Expr& x) { // If x is not integer, do not bother if(!isInteger(x)) return; // Process every pair of the opposing inequalities for 'x' ExprMap *>::iterator iLeft, iRight; iLeft = d_inequalitiesLeftDB.find(x); if(iLeft == d_inequalitiesLeftDB.end()) return; iRight = d_inequalitiesRightDB.find(x); if(iRight == d_inequalitiesRightDB.end()) return; // There are some opposing inequalities; get the lists CDList& ineqsLeft = *(iLeft->second); CDList& ineqsRight = *(iRight->second); // Get the sizes of the lists size_t sizeLeft = ineqsLeft.size(); size_t sizeRight = ineqsRight.size(); // Process all the pairs of the opposing inequalities for(size_t l=0; lwithout * caching until it hits a node that is already setup. Be * careful on what expressions you are calling it. */ void TheoryArithOld::setupRec(const Expr& e) { if(e.hasFind()) return; // First, set up the kids recursively for (int k = 0; k < e.arity(); ++k) { setupRec(e[k]); } // Create a find pointer for e e.setFind(reflexivityRule(e)); e.setEqNext(reflexivityRule(e)); // And call our own setup() setup(e); } void TheoryArithOld::addSharedTerm(const Expr& e) { return; if (d_sharedTerms.find(e) == d_sharedTerms.end()) { d_sharedTerms[e] = true; d_sharedTermsList.push_back(e); } } void TheoryArithOld::assertFact(const Theorem& e) { TRACE("arith assert", "assertFact(", e.getExpr().toString(), ")"); // Pick up any multiplicative case splits and enqueue them for (unsigned i = 0; i < multiplicativeSignSplits.size(); i ++) enqueueFact(multiplicativeSignSplits[i]); multiplicativeSignSplits.clear(); const Expr& expr = e.getExpr(); if (expr.isNot() && expr[0].isEq()) { IF_DEBUG(debugger.counter("[arith] received disequalities")++;) d_diseq.push_back(e); } else if (!expr.isEq()){ if (expr.isNot()) { // If expr[0] is asserted to *not* be an integer, we track it // so we will detect if it ever becomes equal to an integer. if (expr[0].getKind() == IS_INTEGER) { expr[0][0].addToNotify(this, expr[0]); } // This can only be negation of dark or gray shadows, or // disequalities, which we ignore. Negations of inequalities // are handled in rewrite, we don't even receive them here. } else if(isDarkShadow(expr)) { enqueueFact(d_rules->expandDarkShadow(e)); IF_DEBUG(debugger.counter("received DARK_SHADOW")++;) } else if(isGrayShadow(expr)) { IF_DEBUG(debugger.counter("received GRAY_SHADOW")++;) const Rational& c1 = expr[2].getRational(); const Rational& c2 = expr[3].getRational(); // If gray shadow bigger than the treshold, we are done if (*d_grayShadowThres > -1 && (c2 - c1 > *d_grayShadowThres)) { setIncomplete("Some gray shadows ignored due to threshold"); return; } const Expr& v = expr[0]; const Expr& ee = expr[1]; if(c1 == c2) enqueueFact(d_rules->expandGrayShadow0(e)); else { Theorem gThm(e); // Check if we can reduce the number of cases in G(ax,c,c1,c2) if(ee.isRational() && isMult(v) && v[0].isRational() && v[0].getRational() >= 2) { IF_DEBUG(debugger.counter("reduced const GRAY_SHADOW")++;) gThm = d_rules->grayShadowConst(e); } // (Possibly) new gray shadow const Expr& g = gThm.getExpr(); if(g.isFalse()) setInconsistent(gThm); else if(g[2].getRational() == g[3].getRational()) enqueueFact(d_rules->expandGrayShadow0(gThm)); else if(g[3].getRational() - g[2].getRational() <= 5) { // Assert c1+e <= v <= c2+e enqueueFact(d_rules->expandGrayShadow(gThm)); // Split G into 2 cases x = l_bound and the other Theorem thm2 = d_rules->splitGrayShadowSmall(gThm); enqueueFact(thm2); } else { // Assert c1+e <= v <= c2+e enqueueFact(d_rules->expandGrayShadow(gThm)); // Split G into 2 cases (binary search b/w c1 and c2) Theorem thm2 = d_rules->splitGrayShadow(gThm); enqueueFact(thm2); } } } else { DebugAssert(isLE(expr) || isLT(expr) || isIntPred(expr), "expected LE or LT: "+expr.toString()); if(isLE(expr) || isLT(expr)) { IF_DEBUG(debugger.counter("recevied inequalities")++;) // Buffer the inequality addToBuffer(e); unsigned total_buf_size = d_buffer_0.size() + d_buffer_1.size() + d_buffer_2.size() + d_buffer_3.size(); unsigned processed = d_bufferIdx_0 + d_bufferIdx_1 + d_bufferIdx_2 + d_bufferIdx_3; TRACE("arith ineq", "buffer.size() = ", total_buf_size, ", index="+int2string(processed) +", threshold="+int2string(*d_bufferThres)); if(!diffLogicOnly && *d_bufferThres >= 0 && (total_buf_size > *d_bufferThres + processed) && !d_inModelCreation) { processBuffer(); } } else { IF_DEBUG(debugger.counter("arith IS_INTEGER")++;) if (!isInteger(expr[0])) { enqueueFact(d_rules->IsIntegerElim(e)); } } } } else { IF_DEBUG(debugger.counter("[arith] received t1=t2")++;) // const Expr lhs = e.getExpr()[0]; // const Expr rhs = e.getExpr()[1]; // // CDMap::iterator l_bound_find = termLowerBound[lhs]; // if (l_bound_find != termLowerBound.end()) { // Rational lhs_bound = (*l_bound_find).second; // CDMap::iterator l_bound_find_rhs = termLowerBound[rhs]; // if (l_bound_find_rhs != termLowerBound.end()) { // // } else { // // Add the new bound for the rhs // termLowerBound[rhs] = lhs_bound; // termLowerBoundThm = // } // // } } } void TheoryArithOld::checkSat(bool fullEffort) { // vector::const_iterator e; // vector::const_iterator eEnd; // TODO: convert back to use iterators TRACE("arith checksat", "checksat(fullEffort = ", fullEffort? "true, modelCreation = " : "false, modelCreation = ", (d_inModelCreation ? "true)" : "false)")); TRACE("arith ineq", "TheoryArithOld::checkSat(fullEffort=", fullEffort? "true" : "false", ")"); if (fullEffort) { // Process the buffer if necessary if (!inconsistent()) processBuffer(); if (!inconsistent()) { // If in model creation we might have to reconsider some of the dis-equalities if (d_inModelCreation) d_diseqIdx = 0; // Now go and try to split for(; d_diseqIdx < d_diseq.size(); d_diseqIdx = d_diseqIdx+1) { // Get the disequality theorem and the expression Theorem diseqThm = d_diseq[d_diseqIdx]; Expr diseq = diseqThm.getExpr(); // If we split on this one already if (diseqSplitAlready.find(diseq) != diseqSplitAlready.end()) { TRACE("arith::unconstrained", "checking disequaliy: ", diseq[0] , " already split"); continue; } // Get the equality Expr eq = diseq[0]; // Get the left-hand-side and the right-hands side Expr lhs = eq[0]; Expr rhs = eq[1]; TRACE("arith::unconstrained", "checking disequaliy: ", lhs.eqExpr(rhs) , ""); DebugAssert(lhs.hasFind() && rhs.hasFind(), "Part of dis-equality has no find!"); lhs = find(lhs).getRHS(); rhs = find(rhs).getRHS(); TRACE("arith::unconstrained", "checking disequaliy: ", lhs.eqExpr(rhs) , " after find"); // If the value of the equality is already determined by instantiation, we just skip it // This can happen a lot as we infer equalities in difference logic if (lhs.isRational() && rhs.isRational()) { TRACE("arith::unconstrained", "checking disequaliy: ", lhs.eqExpr(rhs) , " skipping"); continue; } // We can allow ourselfs not to care about specific values if we are // not in model creation or it's not an integer constraint if (!d_inModelCreation) { bool unconstrained = isUnconstrained(lhs) || isUnconstrained(rhs); if (unconstrained) { TRACE("arith::unconstrained", "checking disequaliy: ", lhs.eqExpr(rhs) , " unconstrained skipping"); continue; } bool intConstraint = !isIntegerThm(lhs).isNull() && !isIntegerThm(rhs).isNull(); if (!intConstraint) { TRACE("arith::unconstrained", "checking disequaliy: ", lhs.eqExpr(rhs) , " not integer skipping"); continue; } } TRACE("arith::unconstrained", "checking disequaliy: ", lhs.eqExpr(rhs) , " splitting"); // We don't know the value of the disequality, split on it (for now) Theorem lemma = d_rules->diseqToIneq(diseqThm); // Enqueue it enqueueFact(lemma); // Mark it as split already diseqSplitAlready[diseq] = true; } } IF_DEBUG( { bool dejans_printouts = false; if (dejans_printouts) { cerr << "Disequalities after CheckSat" << endl; for (unsigned i = 0; i < d_diseq.size(); i ++) { Expr diseq = d_diseq[i].getExpr(); Expr d_find = find(diseq[0]).getRHS(); cerr << diseq.toString() << ":" << d_find.toString() << endl; } cerr << "Arith Buffer after CheckSat (0)" << endl; for (unsigned i = 0; i < d_buffer_0.size(); i ++) { Expr ineq = d_buffer_0[i].getExpr(); Expr rhs = find(ineq[1]).getRHS(); cerr << ineq.toString() << ":" << rhs.toString() << endl; } cerr << "Arith Buffer after CheckSat (1)" << endl; for (unsigned i = 0; i < d_buffer_1.size(); i ++) { Expr ineq = d_buffer_1[i].getExpr(); Expr rhs = find(ineq[1]).getRHS(); cerr << ineq.toString() << ":" << rhs.toString() << endl; } cerr << "Arith Buffer after CheckSat (2)" << endl; for (unsigned i = 0; i < d_buffer_2.size(); i ++) { Expr ineq = d_buffer_2[i].getExpr(); Expr rhs = find(ineq[1]).getRHS(); cerr << ineq.toString() << ":" << rhs.toString() << endl; } cerr << "Arith Buffer after CheckSat (3)" << endl; for (unsigned i = 0; i < d_buffer_3.size(); i ++) { Expr ineq = d_buffer_3[i].getExpr(); Expr rhs = find(ineq[1]).getRHS(); cerr << ineq.toString() << ":" << rhs.toString() << endl; } } } ) } } void TheoryArithOld::refineCounterExample() { d_inModelCreation = true; TRACE("model", "refineCounterExample[TheoryArithOld] ", "", "{"); CDMap::iterator it = d_sharedTerms.begin(), it2, iend = d_sharedTerms.end(); // Add equalities over all pairs of shared terms as suggested // splitters. Notice, that we want to split on equality // (positively) first, to reduce the size of the model. for(; it!=iend; ++it) { // Copy by value: the elements in the pair from *it are NOT refs in CDMap Expr e1 = (*it).first; for(it2 = it, ++it2; it2!=iend; ++it2) { Expr e2 = (*it2).first; DebugAssert(isReal(getBaseType(e1)), "TheoryArithOld::refineCounterExample: e1 = "+e1.toString() +"\n type(e1) = "+e1.getType().toString()); if(findExpr(e1) != findExpr(e2)) { DebugAssert(isReal(getBaseType(e2)), "TheoryArithOld::refineCounterExample: e2 = "+e2.toString() +"\n type(e2) = "+e2.getType().toString()); Expr eq = simplifyExpr(e1.eqExpr(e2)); if (!eq.isBoolConst()) { addSplitter(eq); } } } } TRACE("model", "refineCounterExample[Theory::Arith] ", "", "}"); } void TheoryArithOld::findRationalBound(const Expr& varSide, const Expr& ratSide, const Expr& var, Rational &r) { Expr c, x; separateMonomial(varSide, c, x); if (!findExpr(ratSide).isRational() && isNonlinearEq(ratSide.eqExpr(rat(0)))) throw ArithException("Could not generate the model due to non-linear arithmetic"); DebugAssert(findExpr(c).isRational(), "seperateMonomial failed"); DebugAssert(findExpr(ratSide).isRational(), "smallest variable in graph, should not have variables" " in inequalities: "); DebugAssert(x == var, "separateMonomial found different variable: " + var.toString()); r = findExpr(ratSide).getRational() / findExpr(c).getRational(); } bool TheoryArithOld::findBounds(const Expr& e, Rational& lub, Rational& glb) { bool strictLB=false, strictUB=false; bool right = (d_inequalitiesRightDB.count(e) > 0 && d_inequalitiesRightDB[e]->size() > 0); bool left = (d_inequalitiesLeftDB.count(e) > 0 && d_inequalitiesLeftDB[e]->size() > 0); int numRight = 0, numLeft = 0; if(right) { //rationals less than e CDList * ratsLTe = d_inequalitiesRightDB[e]; for(unsigned int i=0; isize(); i++) { DebugAssert((*ratsLTe)[i].varOnRHS(), "variable on wrong side!"); Expr ineq = (*ratsLTe)[i].ineq().getExpr(); Expr leftSide = ineq[0], rightSide = ineq[1]; Rational r; findRationalBound(rightSide, leftSide, e , r); if(numRight==0 || r>glb){ glb = r; strictLB = isLT(ineq); } numRight++; } TRACE("model", " =>Lower bound ", glb.toString(), ""); } if(left) { //rationals greater than e CDList * ratsGTe = d_inequalitiesLeftDB[e]; for(unsigned int i=0; isize(); i++) { DebugAssert((*ratsGTe)[i].varOnLHS(), "variable on wrong side!"); Expr ineq = (*ratsGTe)[i].ineq().getExpr(); Expr leftSide = ineq[0], rightSide = ineq[1]; Rational r; findRationalBound(leftSide, rightSide, e, r); if(numLeft==0 || rUpper bound ", lub.toString(), ""); } if(!left && !right) { lub = 0; glb = 0; } if(!left && right) {lub = glb +2;} if(!right && left) {glb = lub-2;} DebugAssert(glb <= lub, "Greatest lower bound needs to be smaller " "than least upper bound"); return strictLB; } void TheoryArithOld::assignVariables(std::vector&v) { int count = 0; if (diffLogicOnly) { // Compute the model diffLogicGraph.computeModel(); // Get values for the variables for (unsigned i = 0; i < v.size(); i ++) { Expr x = v[i]; assignValue(x, rat(diffLogicGraph.getValuation(x))); } // Done return; } while (v.size() > 0) { std::vector bottom; d_graph.selectSmallest(v, bottom); TRACE("model", "Finding variables to assign. Iteration # ", count, ""); for(unsigned int i = 0; i& v) { d_inModelCreation = true; vector reps; TRACE("model", "Arith=>computeModel ", "", "{"); for(unsigned int i=0; i is defined by: ", findExpr(e) , ""); } } assignVariables(reps); TRACE("model", "Arith=>computeModel", "", "}"); d_inModelCreation = false; } // For any arith expression 'e', if the subexpressions are assigned // concrete values, then find(e) must already be a concrete value. void TheoryArithOld::computeModel(const Expr& e, vector& vars) { DebugAssert(findExpr(e).isRational(), "TheoryArithOld::computeModel(" +e.toString()+")\n e is not assigned concrete value.\n" +" find(e) = "+findExpr(e).toString()); assignValue(simplify(e)); vars.push_back(e); } Theorem TheoryArithOld::checkIntegerEquality(const Theorem& thm) { // Check if this is a rewrite theorem bool rewrite = thm.isRewrite(); // If it's an integer theorem, then rafine it to integer domain Expr eq = (rewrite ? thm.getRHS() : thm.getExpr()); TRACE("arith rafine", "TheoryArithOld::checkIntegerEquality(", eq, ")"); DebugAssert(eq.getKind() == EQ, "checkIntegerEquality: must be an equality"); // Trivial equalities, we don't care if (!isPlus(eq[1]) && !isPlus(eq[0])) return thm; Expr old_sum = (isPlus(eq[1]) ? eq[1] : eq[0]); // Get the sum part vector children; bool const_is_integer = true; // Assuming only one constant is present (canon called before this) for (int i = 0; i < old_sum.arity(); i ++) if (!old_sum[i].isRational()) children.push_back(old_sum[i]); else const_is_integer = old_sum[i].getRational().isInteger(); // If the constants are integers, we don't care if (const_is_integer) return thm; Expr sum = (children.size() > 1 ? plusExpr(children) : children[0]); // Check for integer of the remainder of the sum Theorem isIntegerEquality = isIntegerThm(sum); // If it is an integer, it's unsat if (!isIntegerEquality.isNull()) { Theorem false_thm = d_rules->intEqualityRationalConstant(isIntegerEquality, eq); if (rewrite) return transitivityRule(thm, false_thm); else return iffMP(thm, false_thm); } else return thm; } Theorem TheoryArithOld::rafineInequalityToInteger(const Theorem& thm) { // Check if this is a rewrite theorem bool rewrite = thm.isRewrite(); // If it's an integer theorem, then rafine it to integer domain Expr ineq = (rewrite ? thm.getRHS() : thm.getExpr()); TRACE("arith rafine", "TheoryArithOld::rafineInequalityToInteger(", ineq, ")"); DebugAssert(isIneq(ineq), "rafineInequalityToInteger: must be an inequality"); // Trivial inequalities are rafined // if (!isPlus(ineq[1])) return thm; // Get the sum part vector children; if (isPlus(ineq[1])) { for (int i = 0; i < ineq[1].arity(); i ++) if (!ineq[1][i].isRational()) children.push_back(ineq[1][i]); } else children.push_back(ineq[1]); Expr sum = (children.size() > 1 ? plusExpr(children) : children[0]); // Check for integer of the remainder of the sum Theorem isIntegerInequality = isIntegerThm(sum); // If it is an integer, do rafine it if (!isIntegerInequality.isNull()) { Theorem rafine = d_rules->rafineStrictInteger(isIntegerInequality, ineq); TRACE("arith rafine", "TheoryArithOld::rafineInequalityToInteger()", "=>", rafine.getRHS()); if (rewrite) return canonPredEquiv(transitivityRule(thm, rafine)); else return canonPred(iffMP(thm, rafine)); } else return thm; } /*! accepts a rewrite theorem over eqn|ineqn and normalizes it * and returns a theorem to that effect. assumes e is non-trivial * i.e. e is not '0=const' or 'const=0' or '0 <= const' etc. */ Theorem TheoryArithOld::normalize(const Expr& e) { //e is an eqn or ineqn. e is not a trivial eqn or ineqn //trivial means 0 = const or 0 <= const. TRACE("arith normalize", "normalize(", e, ") {"); DebugAssert(e.isEq() || isIneq(e), "normalize: input must be Eq or Ineq: " + e.toString()); DebugAssert(!isIneq(e) || (0 == e[0].getRational()), "normalize: if (e is ineq) then e[0] must be 0" + e.toString()); if(e.isEq()) { if(e[0].isRational()) { DebugAssert(0 == e[0].getRational(), "normalize: if e is Eq and e[0] is rat then e[0]==0"); } else { //if e[0] is not rational then e[1] must be rational. DebugAssert(e[1].isRational() && 0 == e[1].getRational(), "normalize: if e is Eq and e[1] is rat then e[1]==0\n" " e = "+e.toString()); } } Expr factor; if(e[0].isRational()) factor = computeNormalFactor(e[1], false); else factor = computeNormalFactor(e[0], false); TRACE("arith normalize", "normalize: factor = ", factor, ""); DebugAssert(factor.getRational() > 0, "normalize: factor="+ factor.toString()); Theorem thm(reflexivityRule(e)); // Now multiply the equality by the factor, unless it is 1 if(factor.getRational() != 1) { int kind = e.getKind(); switch(kind) { case EQ: //TODO: DEJAN FIX thm = d_rules->multEqn(e[0], e[1], factor); // And canonize the result thm = canonPredEquiv(thm); // If this is an equation of the form 0 = c + sum, c is not integer, but sum is // then equation has no solutions thm = checkIntegerEquality(thm); break; case LE: case LT: case GE: case GT: { thm = d_rules->multIneqn(e, factor); // And canonize the result thm = canonPredEquiv(thm); // Try to rafine to integer domain thm = rafineInequalityToInteger(thm); break; } default: // MS .net doesn't accept "..." + int ostringstream ss; ss << "normalize: control should not reach here " << kind; DebugAssert(false, ss.str()); break; } } else if (e.getKind() == EQ) thm = checkIntegerEquality(thm); TRACE("arith normalize", "normalize => ", thm, " }"); return(thm); } Theorem TheoryArithOld::normalize(const Theorem& eIffEqn) { if (eIffEqn.isRewrite()) return transitivityRule(eIffEqn, normalize(eIffEqn.getRHS())); else return iffMP(eIffEqn, normalize(eIffEqn.getExpr())); } Theorem TheoryArithOld::rewrite(const Expr& e) { DebugAssert(leavesAreSimp(e), "Expected leaves to be simplified"); TRACE("arith", "TheoryArithOld::rewrite(", e, ") {"); Theorem thm; if (!e.isTerm()) { if (!e.isAbsLiteral()) { if (e.isPropAtom() && leavesAreNumConst(e)) { if (e.getSize() < 200) { Expr eNew = e; thm = reflexivityRule(eNew); while (eNew.containsTermITE()) { thm = transitivityRule(thm, getCommonRules()->liftOneITE(eNew)); DebugAssert(!thm.isRefl(), "Expected non-reflexive"); thm = transitivityRule(thm, theoryCore()->getCoreRules()->rewriteIteCond(thm.getRHS())); thm = transitivityRule(thm, simplify(thm.getRHS())); eNew = thm.getRHS(); } } else { thm = d_rules->rewriteLeavesConst(e); if (thm.isRefl()) { e.setRewriteNormal(); } else { thm = transitivityRule(thm, simplify(thm.getRHS())); } } // if (!thm.getRHS().isBoolConst()) { // e.setRewriteNormal(); // thm = reflexivityRule(e); // } } else { e.setRewriteNormal(); thm = reflexivityRule(e); } TRACE("arith", "TheoryArithOld::rewrite[non-literal] => ", thm, " }"); return thm; } switch(e.getKind()) { case EQ: { // canonical form for an equality of two leaves // is just l == r instead of 0 + (-1 * l) + r = 0. if (isLeaf(e[0]) && isLeaf(e[1])) thm = reflexivityRule(e); else { // Otherwise, it is "lhs = 0" //first convert e to the form 0=e' if((e[0].isRational() && e[0].getRational() == 0) || (e[1].isRational() && e[1].getRational() == 0)) //already in 0=e' or e'=0 form thm = reflexivityRule(e); else { thm = d_rules->rightMinusLeft(e); thm = canonPredEquiv(thm); } // Check for trivial equation if ((thm.getRHS())[0].isRational() && (thm.getRHS())[1].isRational()) { thm = transitivityRule(thm, d_rules->constPredicate(thm.getRHS())); } else { //else equation is non-trivial thm = normalize(thm); // Normalization may yield non-simplified terms if (!thm.getRHS().isBoolConst()) thm = canonPredEquiv(thm); } } // Equations must be oriented such that lhs >= rhs as Exprs; // this ordering is given by operator<(Expr,Expr). const Expr& eq = thm.getRHS(); if(eq.isEq() && eq[0] < eq[1]) thm = transitivityRule(thm, getCommonRules()->rewriteUsingSymmetry(eq)); // Check if the equation is nonlinear Expr nonlinearEq = thm.getRHS(); if (nonlinearEq.isEq() && isNonlinearEq(nonlinearEq)) { TRACE("arith nonlinear", "nonlinear eq rewrite: ", nonlinearEq, ""); Expr left = nonlinearEq[0]; Expr right = nonlinearEq[1]; // Check for multiplicative equations, i.e. x*y = 0 if (isNonlinearSumTerm(left) && right.isRational() && right.getRational() == 0) { Theorem eq_thm = d_rules->multEqZero(nonlinearEq); thm = transitivityRule(thm, eq_thm); thm = transitivityRule(thm, theoryCore()->simplify(thm.getRHS())); break; } // Heuristics for a sum if (isPlus(left)) { // Search for common factor if (left[0].getRational() == 0) { Expr::iterator i = left.begin(), iend = left.end(); ++ i; set factors; set::iterator is, isend; getFactors(*i, factors); for (++i; i != iend; ++i) { set factors2; getFactors(*i, factors2); for (is = factors.begin(), isend = factors.end(); is != isend;) { if (factors2.find(*is) == factors2.end()) { factors.erase(is ++); } else ++ is; } if (factors.empty()) break; } if (!factors.empty()) { thm = transitivityRule(thm, d_rules->divideEqnNonConst(left, rat(0), *(factors.begin()))); // got (factor != 0) OR (left / factor = right / factor), need to simplify thm = transitivityRule(thm, simplify(thm.getRHS())); TRACE("arith nonlinear", "nonlinear eq rewrite (factoring): ", thm.getRHS(), ""); break; } } // Look for equal powers (eq in the form of c + pow1 - pow2 = 0) Rational constant; Expr power1; Expr power2; if (isPowersEquality(nonlinearEq, power1, power2)) { // Eliminate the powers thm = transitivityRule(thm, d_rules->elimPower(nonlinearEq)); thm = transitivityRule(thm, simplify(thm.getRHS())); TRACE("arith nonlinear", "nonlinear eq rewrite (equal powers): ", thm.getRHS(), ""); break; } else // Look for one power equality (c - pow = 0); if (isPowerEquality(nonlinearEq, constant, power1)) { Rational pow1 = power1[0].getRational(); if (pow1 % 2 == 0 && constant < 0) { thm = transitivityRule(thm, d_rules->evenPowerEqNegConst(nonlinearEq)); TRACE("arith nonlinear", "nonlinear eq rewrite (even power = negative): ", thm.getRHS(), ""); break; } DebugAssert(constant != 0, "Expected nonzero const"); Rational root = ratRoot(constant, pow1.getUnsigned()); if (root != 0) { thm = transitivityRule(thm, d_rules->elimPowerConst(nonlinearEq, root)); thm = transitivityRule(thm, simplify(thm.getRHS())); TRACE("arith nonlinear", "nonlinear eq rewrite (rational root): ", thm.getRHS(), ""); break; } else { Theorem isIntPower(isIntegerThm(left)); if (!isIntPower.isNull()) { thm = transitivityRule(thm, d_rules->intEqIrrational(nonlinearEq, isIntPower)); TRACE("arith nonlinear", "nonlinear eq rewrite (irational root): ", thm.getRHS(), ""); break; } } } } // Non-solvable nonlinear equations are rewritten as conjunction of inequalities if ( (nonlinearEq[0].arity() > 1 && !canPickEqMonomial(nonlinearEq[0])) || (nonlinearEq[1].arity() > 1 && !canPickEqMonomial(nonlinearEq[1])) ) { thm = transitivityRule(thm, d_rules->eqToIneq(nonlinearEq)); thm = transitivityRule(thm, simplify(thm.getRHS())); TRACE("arith nonlinear", "nonlinear eq rewrite (not solvable): ", thm.getRHS(), ""); break; } } } break; case GRAY_SHADOW: case DARK_SHADOW: thm = reflexivityRule(e); break; case IS_INTEGER: { Theorem res(isIntegerDerive(e, typePred(e[0]))); if(!res.isNull()) thm = getCommonRules()->iffTrue(res); else thm = reflexivityRule(e); break; } case NOT: if (!isIneq(e[0])) //in this case we have "NOT of DARK or GRAY_SHADOW." thm = reflexivityRule(e); else { //In this case we have the "NOT of ineq". get rid of NOT //and then treat like an ineq thm = d_rules->negatedInequality(e); DebugAssert(isGE(thm.getRHS()) || isGT(thm.getRHS()), "Expected GE or GT"); thm = transitivityRule(thm, d_rules->flipInequality(thm.getRHS())); thm = transitivityRule(thm, d_rules->rightMinusLeft(thm.getRHS())); thm = canonPredEquiv(thm); // If the inequality is strict and integer, change it to non-strict Expr theIneq = thm.getRHS(); if(isLT(theIneq)) { // Check if integer Theorem isIntLHS(isIntegerThm(theIneq[0])); Theorem isIntRHS(isIntegerThm(theIneq[1])); bool isInt = (!isIntLHS.isNull() && !isIntRHS.isNull()); if (isInt) { thm = canonPredEquiv( transitivityRule(thm, d_rules->lessThanToLERewrite(theIneq, isIntLHS, isIntRHS, true))); } } // Check for trivial inequation if ((thm.getRHS())[1].isRational()) thm = transitivityRule(thm, d_rules->constPredicate(thm.getRHS())); else { //else ineq is non-trivial thm = normalize(thm); // Normalization may yield non-simplified terms thm = canonPredEquiv(thm); } } break; case LT: case GT: case LE: case GE: { if (isGE(e) || isGT(e)) { thm = d_rules->flipInequality(e); thm = transitivityRule(thm, d_rules->rightMinusLeft(thm.getRHS())); } else thm = d_rules->rightMinusLeft(e); thm = canonPredEquiv(thm); // If the inequality is strict and integer, change it to non-strict Expr theIneq = thm.getRHS(); if(isLT(theIneq)) { // Check if integer Theorem isIntLHS(isIntegerThm(theIneq[0])); Theorem isIntRHS(isIntegerThm(theIneq[1])); bool isInt = (!isIntLHS.isNull() && !isIntRHS.isNull()); if (isInt) { thm = canonPredEquiv( transitivityRule(thm, d_rules->lessThanToLERewrite(theIneq, isIntLHS, isIntRHS, true))); } } // Check for trivial inequation if ((thm.getRHS())[1].isRational()) thm = transitivityRule(thm, d_rules->constPredicate(thm.getRHS())); else { // ineq is non-trivial thm = normalize(thm); thm = canonPredEquiv(thm); if (thm.getRHS()[1].isRational()) thm = transitivityRule(thm, d_rules->constPredicate(thm.getRHS())); } break; } default: DebugAssert(false, "Theory_Arith::rewrite: control should not reach here"); break; } } else { if (e.isAtomic()) thm = canon(e); else thm = reflexivityRule(e); } // TODO: this needs to be reviewed, esp for non-linear case // Arith canonization is idempotent if (theoryOf(thm.getRHS()) == this) thm.getRHS().setRewriteNormal(); TRACE("arith", "TheoryArithOld::rewrite => ", thm, " }"); return thm; } void TheoryArithOld::setup(const Expr& e) { if (!e.isTerm()) { if (e.isNot()) return; // if(e.getKind() == IS_INTEGER) { // e[0].addToNotify(this, e); // return; // } if (isIneq(e)) { DebugAssert((isLT(e)||isLE(e)) && e[0].isRational() && e[0].getRational() == 0, "TheoryArithOld::setup: expected 0 < rhs:" + e.toString()); e[1].addToNotify(this, e); } else { // if (e.isEq()) { // // Nonlinear solved equations // if (isNonlinearEq(e) && e[0].isRational() && e[0].getRational() == 0) // e[0].addToNotify(this, e); // } // // DebugAssert(isGrayShadow(e), "TheoryArithOld::setup: expected grayshadow" + e.toString()); // // // Do not add the variable, just the subterm e[0].addToNotify(this, e); // e[1].addToNotify(this, e); } return; } int k(0), ar(e.arity()); for ( ; k < ar; ++k) { e[k].addToNotify(this, e); TRACE("arith setup", "e["+int2string(k)+"]: ", *(e[k].getNotify()), ""); } } void TheoryArithOld::update(const Theorem& e, const Expr& d) { TRACE("arith update", "update on " + d.toString() + " with ", e.getRHS().toString(), "."); if (inconsistent()) return; // We accept atoms without find, but only inequalities (they come from the buffer) DebugAssert(d.hasFind() || isIneq(d), "update on a non-inequality term/atom"); IF_DEBUG(debugger.counter("arith update total")++;) // if (isGrayShadow(d)) { // TRACE("shadow update", "updating index of " + d.toString() + " with ", e.getRHS().toString(), "."); // // // Substitute e[1] for e[0] in d and enqueue new shadow // DebugAssert(e.getLHS() == d[1], "Mismatch"); // Theorem thm = find(d); // // // DebugAssert(thm.getRHS() == trueExpr(), "Expected find = true"); // vector changed; // vector children; // changed.push_back(1); // children.push_back(e); // Theorem thm2 = substitutivityRule(d, changed, children); // if (thm.getRHS() == trueExpr()) { // enqueueFact(iffMP(getCommonRules()->iffTrueElim(thm), thm2)); // } // else { // enqueueFact(getCommonRules()->iffFalseElim( // transitivityRule(symmetryRule(thm2), thm))); // } // IF_DEBUG(debugger.counter("arith update ineq")++;) // } // else if (isIneq(d)) { // Substitute e[1] for e[0] in d and enqueue new inequality DebugAssert(e.getLHS() == d[1], "Mismatch"); Theorem thm; if (d.hasFind()) thm = find(d); // bool diff_logic = false; // Expr new_rhs = e.getRHS(); // if (!isPlus(new_rhs)) { // if (isLeaf(new_rhs)) diff_logic = true; // } // else { // int arity = new_rhs.arity(); // if (arity == 2) { // if (new_rhs[0].isRational()) diff_logic = true; // else { // Expr ax = new_rhs[0], a, x; // Expr by = new_rhs[1], b, y; // separateMonomial(ax, a, x); // separateMonomial(by, b, y); // if ((a.getRational() == 1 && b.getRational() == -1) || // (a.getRational() == -1 && b.getRational() == 1)) // diff_logic = true; // } // } else { // if (arity == 3 && new_rhs[0].isRational()) { // Expr ax = new_rhs[1], a, x; // Expr by = new_rhs[2], b, y; // separateMonomial(ax, a, x); // separateMonomial(by, b, y); // if ((a.getRational() == 1 && b.getRational() == -1) || // (a.getRational() == -1 && b.getRational() == 1)) // diff_logic = true; // } // } // } // DebugAssert(thm.getRHS() == trueExpr(), "Expected find = true"); vector changed; vector children; changed.push_back(1); children.push_back(e); Theorem thm2 = substitutivityRule(d, changed, children); Expr newIneq = thm2.getRHS(); // If this inequality is bufferred but not yet projected, just wait for it // but don't add the find to the buffer as it will be projected as a find // We DO want it to pass through all the buffer stuff but NOT get into the buffer // NOTE: this means that the difference logic WILL get processed if ((thm.isNull() || thm.getRHS() != falseExpr()) && bufferedInequalities.find(d) != bufferedInequalities.end() && alreadyProjected.find(d) == alreadyProjected.end()) { TRACE("arith update", "simplified but not projected : ", thm2.getRHS(), ""); dontBuffer[thm2.getRHS()] = true; } if (thm.isNull()) { // This hy is in the buffer, not in the core // if it has been projected, than it's parent has been projected and will get reprojected // accuratlz. If it has not been projected, we don't care it's still there TRACE("arith update", "in udpate, but no find", "", ""); if (bufferedInequalities.find(d) != bufferedInequalities.end()) { if (thm2.getRHS()[1].isRational()) enqueueFact(iffMP(bufferedInequalities[d], thm2)); else if (alreadyProjected.find(d) != alreadyProjected.end()) { // the parent will get reprojected alreadyProjected[d] = d; } } } else if (thm.getRHS() == trueExpr()) { if (!newIneq[1].isRational() || newIneq[1].getRational() <= 0) enqueueFact(iffMP(getCommonRules()->iffTrueElim(thm), thm2)); } else { enqueueFact(getCommonRules()->iffFalseElim( transitivityRule(symmetryRule(thm2), thm))); } IF_DEBUG(debugger.counter("arith update ineq")++;) } else if (d.isEq()) { TRACE("arith nonlinear", "TheoryArithOld::update() on equality ", d, ""); // We get equalitites from the non-solve nonlinear equations // only the right hand sides get updated vector changed; vector children; changed.push_back(0); children.push_back(e); Theorem thm = substitutivityRule(d, changed, children); Expr newEq = thm.getRHS(); Theorem d_find = find(d); if (d_find.getRHS() == trueExpr()) enqueueFact(iffMP(getCommonRules()->iffTrueElim(d_find), thm)); else enqueueFact(getCommonRules()->iffFalseElim(transitivityRule(symmetryRule(thm), d_find))); } else if (d.getKind() == IS_INTEGER) { // This should only happen if !d has been asserted DebugAssert(e.getRHS() == findExpr(d[0]), "Unexpected"); if (isInteger(e.getRHS())) { Theorem thm = substitutivityRule(d, find(d[0])); thm = transitivityRule(symmetryRule(find(d)), thm); thm = iffMP(thm, simplify(thm.getExpr())); setInconsistent(thm); } else { e.getRHS().addToNotify(this, d); } } else if (find(d).getRHS() == d) { // Theorem thm = canonSimp(d); // TRACE("arith", "TheoryArithOld::update(): thm = ", thm, ""); // DebugAssert(leavesAreSimp(thm.getRHS()), "updateHelper error: " // +thm.getExpr().toString()); // assertEqualities(transitivityRule(thm, rewrite(thm.getRHS()))); // IF_DEBUG(debugger.counter("arith update find(d)=d")++;) Theorem thm = simplify(d); // If the original is was a shared term, add this one as as a shared term also if (d_sharedTerms.find(d) != d_sharedTerms.end()) addSharedTerm(thm.getRHS()); DebugAssert(thm.getRHS().isAtomic(), "Expected atomic"); assertEqualities(thm); } } Theorem TheoryArithOld::solve(const Theorem& thm) { DebugAssert(thm.isRewrite() && thm.getLHS().isTerm(), ""); const Expr& lhs = thm.getLHS(); const Expr& rhs = thm.getRHS(); // Check for already solved equalities. // Have to be careful about the types: integer variable cannot be // assigned a real term. Also, watch for e[0] being a subexpression // of e[1]: this would create an unsimplifiable expression. if (isLeaf(lhs) && !isLeafIn(lhs, rhs) && (!isInteger(lhs) || isInteger(rhs)) // && !e[0].subExprOf(e[1]) ) return thm; // Symmetric version is already solved if (isLeaf(rhs) && !isLeafIn(rhs, lhs) && (!isInteger(rhs) || isInteger(lhs)) // && !e[1].subExprOf(e[0]) ) return symmetryRule(thm); return doSolve(thm); } void TheoryArithOld::computeModelTerm(const Expr& e, std::vector& v) { switch(e.getKind()) { case RATIONAL_EXPR: // Skip the constants break; case PLUS: case MULT: case DIVIDE: case POW: // This is not a variable; extract the variables from children for(Expr::iterator i=e.begin(), iend=e.end(); i!=iend; ++i) // getModelTerm(*i, v); v.push_back(*i); break; default: { // Otherwise it's a variable. Check if it has a find pointer Expr e2(findExpr(e)); if(e==e2) { TRACE("model", "TheoryArithOld::computeModelTerm(", e, "): a variable"); // Leave it alone (it has no descendants) // v.push_back(e); } else { TRACE("model", "TheoryArithOld::computeModelTerm("+e.toString() +"): has find pointer to ", e2, ""); v.push_back(e2); } } } } Expr TheoryArithOld::computeTypePred(const Type& t, const Expr& e) { Expr tExpr = t.getExpr(); switch(tExpr.getKind()) { case INT: return Expr(IS_INTEGER, e); case SUBRANGE: { std::vector kids; kids.push_back(Expr(IS_INTEGER, e)); kids.push_back(leExpr(tExpr[0], e)); kids.push_back(leExpr(e, tExpr[1])); return andExpr(kids); } default: return e.getEM()->trueExpr(); } } void TheoryArithOld::checkAssertEqInvariant(const Theorem& e) { if (e.isRewrite()) { DebugAssert(e.getLHS().isTerm(), "Expected equation"); if (isLeaf(e.getLHS())) { // should be in solved form DebugAssert(!isLeafIn(e.getLHS(),e.getRHS()), "Not in solved form: lhs appears in rhs"); } else { DebugAssert(e.getLHS().hasFind(), "Expected lhs to have find"); DebugAssert(!leavesAreSimp(e.getLHS()), "Expected at least one unsimplified leaf on lhs"); } DebugAssert(canonSimp(e.getRHS()).getRHS() == e.getRHS(), "Expected canonSimp(rhs) = canonSimp(rhs)"); } else { Expr expr = e.getExpr(); if (expr.isFalse()) return; vector eqs; Theorem thm; int index, index2; for (index = 0; index < expr.arity(); ++index) { thm = getCommonRules()->andElim(e, index); eqs.push_back(thm); if (thm.getExpr().isFalse()) return; DebugAssert(eqs[index].isRewrite() && eqs[index].getLHS().isTerm(), "Expected equation"); } // Check for solved form for (index = 0; index < expr.arity(); ++index) { DebugAssert(isLeaf(eqs[index].getLHS()), "expected leaf on lhs"); DebugAssert(canonSimp(eqs[index].getRHS()).getRHS() == eqs[index].getRHS(), "Expected canonSimp(rhs) = canonSimp(rhs)"); DebugAssert(recursiveCanonSimpCheck(eqs[index].getRHS()), "Failed recursive canonSimp check"); for (index2 = 0; index2 < expr.arity(); ++index2) { DebugAssert(index == index2 || eqs[index].getLHS() != eqs[index2].getLHS(), "Not in solved form: repeated lhs"); DebugAssert(!isLeafIn(eqs[index].getLHS(),eqs[index2].getRHS()), "Not in solved form: lhs appears in rhs"); } } } } void TheoryArithOld::checkType(const Expr& e) { switch (e.getKind()) { case INT: case REAL: if (e.arity() > 0) { throw Exception("Ill-formed arithmetic type: "+e.toString()); } break; case SUBRANGE: if (e.arity() != 2 || !isIntegerConst(e[0]) || !isIntegerConst(e[1]) || e[0].getRational() > e[1].getRational()) { throw Exception("bad SUBRANGE type expression"+e.toString()); } break; default: DebugAssert(false, "Unexpected kind in TheoryArithOld::checkType" +getEM()->getKindName(e.getKind())); } } Cardinality TheoryArithOld::finiteTypeInfo(Expr& e, Unsigned& n, bool enumerate, bool computeSize) { Cardinality card = CARD_INFINITE; switch (e.getKind()) { case SUBRANGE: { card = CARD_FINITE; Expr typeExpr = e; if (enumerate) { Rational r = typeExpr[0].getRational() + n; if (r <= typeExpr[1].getRational()) { e = rat(r); } else e = Expr(); } if (computeSize) { Rational r = typeExpr[1].getRational() - typeExpr[0].getRational() + 1; n = r.getUnsigned(); } break; } default: break; } return card; } void TheoryArithOld::computeType(const Expr& e) { switch (e.getKind()) { case REAL_CONST: e.setType(d_realType); break; case RATIONAL_EXPR: if(e.getRational().isInteger()) e.setType(d_intType); else e.setType(d_realType); break; case UMINUS: case PLUS: case MINUS: case MULT: case POW: { bool isInt = true; for(int k = 0; k < e.arity(); ++k) { if(d_realType != getBaseType(e[k])) throw TypecheckException("Expecting type REAL with `" + getEM()->getKindName(e.getKind()) + "',\n"+ "but got a " + getBaseType(e[k]).toString()+ " for:\n" + e.toString()); if(isInt && !isInteger(e[k])) isInt = false; } if(isInt) e.setType(d_intType); else e.setType(d_realType); break; } case DIVIDE: { Expr numerator = e[0]; Expr denominator = e[1]; if (getBaseType(numerator) != d_realType || getBaseType(denominator) != d_realType) { throw TypecheckException("Expecting only REAL types with `DIVIDE',\n" "but got " + getBaseType(numerator).toString()+ " and " + getBaseType(denominator).toString() + " for:\n" + e.toString()); } if(denominator.isRational() && 1 == denominator.getRational()) e.setType(numerator.getType()); else e.setType(d_realType); break; } case LT: case LE: case GT: case GE: case GRAY_SHADOW: // Need to know types for all exprs -Clark // e.setType(boolType()); // break; case DARK_SHADOW: for (int k = 0; k < e.arity(); ++k) { if (d_realType != getBaseType(e[k])) throw TypecheckException("Expecting type REAL with `" + getEM()->getKindName(e.getKind()) + "',\n"+ "but got a " + getBaseType(e[k]).toString()+ " for:\n" + e.toString()); } e.setType(boolType()); break; case IS_INTEGER: if(d_realType != getBaseType(e[0])) throw TypecheckException("Expected type REAL, but got " +getBaseType(e[0]).toString() +"\n\nExpr = "+e.toString()); e.setType(boolType()); break; default: DebugAssert(false,"TheoryArithOld::computeType: unexpected expression:\n " +e.toString()); break; } } Type TheoryArithOld::computeBaseType(const Type& t) { IF_DEBUG(int kind = t.getExpr().getKind();) DebugAssert(kind==INT || kind==REAL || kind==SUBRANGE, "TheoryArithOld::computeBaseType("+t.toString()+")"); return realType(); } Expr TheoryArithOld::computeTCC(const Expr& e) { Expr tcc(Theory::computeTCC(e)); switch(e.getKind()) { case DIVIDE: DebugAssert(e.arity() == 2, ""); return tcc.andExpr(!(e[1].eqExpr(rat(0)))); default: return tcc; } } /////////////////////////////////////////////////////////////////////////////// //parseExprOp: //translating special Exprs to regular EXPR?? /////////////////////////////////////////////////////////////////////////////// Expr TheoryArithOld::parseExprOp(const Expr& e) { //TRACE("parser", "TheoryArithOld::parseExprOp(", e, ")"); //std::cout << "Were here"; // If the expression is not a list, it must have been already // parsed, so just return it as is. switch(e.getKind()) { case ID: { int kind = getEM()->getKind(e[0].getString()); switch(kind) { case NULL_KIND: return e; // nothing to do case REAL: case INT: case NEGINF: case POSINF: return getEM()->newLeafExpr(kind); default: DebugAssert(false, "Bad use of bare keyword: "+e.toString()); return e; } } case RAW_LIST: break; // break out of switch, do the hard work default: return e; } DebugAssert(e.getKind() == RAW_LIST && e.arity() > 0, "TheoryArithOld::parseExprOp:\n e = "+e.toString()); const Expr& c1 = e[0][0]; int kind = getEM()->getKind(c1.getString()); switch(kind) { case UMINUS: { if(e.arity() != 2) throw ParserException("UMINUS requires exactly one argument: " +e.toString()); return uminusExpr(parseExpr(e[1])); } case PLUS: { vector k; Expr::iterator i = e.begin(), iend=e.end(); // Skip first element of the vector of kids in 'e'. // The first element is the operator. ++i; // Parse the kids of e and push them into the vector 'k' for(; i!=iend; ++i) k.push_back(parseExpr(*i)); return plusExpr(k); } case MINUS: { if(e.arity() == 2) { if (false && (getEM()->getInputLang() == SMTLIB_LANG || getEM()->getInputLang() == SMTLIB_V2_LANG)) { throw ParserException("Unary Minus should use '~' instead of '-' in SMT-LIB expr:" +e.toString()); } else { return uminusExpr(parseExpr(e[1])); } } else if(e.arity() == 3) return minusExpr(parseExpr(e[1]), parseExpr(e[2])); else throw ParserException("MINUS requires one or two arguments:" +e.toString()); } case MULT: { vector k; Expr::iterator i = e.begin(), iend=e.end(); // Skip first element of the vector of kids in 'e'. // The first element is the operator. ++i; // Parse the kids of e and push them into the vector 'k' for(; i!=iend; ++i) k.push_back(parseExpr(*i)); return multExpr(k); } case POW: { return powExpr(parseExpr(e[1]), parseExpr(e[2])); } case DIVIDE: { return divideExpr(parseExpr(e[1]), parseExpr(e[2])); } case LT: { return ltExpr(parseExpr(e[1]), parseExpr(e[2])); } case LE: { return leExpr(parseExpr(e[1]), parseExpr(e[2])); } case GT: { return gtExpr(parseExpr(e[1]), parseExpr(e[2])); } case GE: { return geExpr(parseExpr(e[1]), parseExpr(e[2])); } case INTDIV: case MOD: case SUBRANGE: { vector k; Expr::iterator i = e.begin(), iend=e.end(); // Skip first element of the vector of kids in 'e'. // The first element is the operator. ++i; // Parse the kids of e and push them into the vector 'k' for(; i!=iend; ++i) k.push_back(parseExpr(*i)); return Expr(kind, k, e.getEM()); } case IS_INTEGER: { if(e.arity() != 2) throw ParserException("IS_INTEGER requires exactly one argument: " +e.toString()); return Expr(IS_INTEGER, parseExpr(e[1])); } default: DebugAssert(false, "TheoryArithOld::parseExprOp: invalid input " + e.toString()); break; } return e; } /////////////////////////////////////////////////////////////////////////////// // Pretty-printing // /////////////////////////////////////////////////////////////////////////////// ExprStream& TheoryArithOld::print(ExprStream& os, const Expr& e) { switch(os.lang()) { case SIMPLIFY_LANG: switch(e.getKind()) { case RATIONAL_EXPR: e.print(os); break; case SUBRANGE: os <<"ERROR:SUBRANGE:not supported in Simplify\n"; break; case IS_INTEGER: os <<"ERROR:IS_INTEGER:not supported in Simplify\n"; break; case PLUS: { int i=0, iend=e.arity(); os << "(+ "; if(i!=iend) os << e[i]; ++i; for(; i!=iend; ++i) os << " " << e[i]; os << ")"; break; } case MINUS: os << "(- " << e[0] << " " << e[1]<< ")"; break; case UMINUS: os << "-" << e[0] ; break; case MULT: { int i=0, iend=e.arity(); os << "(* " ; if(i!=iend) os << e[i]; ++i; for(; i!=iend; ++i) os << " " << e[i]; os << ")"; break; } case POW: os << "(" << push << e[1] << space << "^ " << e[0] << push << ")"; break; case DIVIDE: os << "(" << push << e[0] << space << "/ " << e[1] << push << ")"; break; case LT: if (isInt(e[0].getType()) || isInt(e[1].getType())) { } os << "(< " << e[0] << " " << e[1] <<")"; break; case LE: os << "(<= " << e[0] << " " << e[1] << ")"; break; case GT: os << "(> " << e[0] << " " << e[1] << ")"; break; case GE: os << "(>= " << e[0] << " " << e[1] << ")"; break; case DARK_SHADOW: case GRAY_SHADOW: os <<"ERROR:SHADOW:not supported in Simplify\n"; break; default: // Print the top node in the default LISP format, continue with // pretty-printing for children. e.print(os); break; } break; // end of case SIMPLIFY_LANG case TPTP_LANG: switch(e.getKind()) { case RATIONAL_EXPR: e.print(os); break; case SUBRANGE: os <<"ERROR:SUBRANGE:not supported in TPTP\n"; break; case IS_INTEGER: os <<"ERROR:IS_INTEGER:not supported in TPTP\n"; break; case PLUS: { if(!isInteger(e[0])){ os<<"ERRPR:plus only supports inteters now in TPTP\n"; break; } int i=0, iend=e.arity(); if(iend <=1){ os<<"ERROR,plus must have more than two numbers in TPTP\n"; break; } for(i=0; i <= iend-2; ++i){ os << "$plus_int("; os << e[i] << ","; } os<< e[iend-1]; for(i=0 ; i <= iend-2; ++i){ os << ")"; } break; } case MINUS: if(!isInteger(e[0])){ os<<"ERRPR:arithmetic operations only support inteters now in TPTP\n"; break; } os << "$minus_int(" << e[0] << "," << e[1]<< ")"; break; case UMINUS: if(!isInteger(e[0])){ os<<"ERRPR:arithmetic operations only support inteters now in TPTP\n"; break; } os << "$uminus_int(" << e[0] <<")" ; break; case MULT: { if(!isInteger(e[0])){ os<<"ERRPR:times only supports inteters now in TPTP\n"; break; } int i=0, iend=e.arity(); if(iend <=1){ os<<"ERROR:times must have more than two numbers in TPTP\n"; break; } for(i=0; i <= iend-2; ++i){ os << "$times_int("; os << e[i] << ","; } os<< e[iend-1]; for(i=0 ; i <= iend-2; ++i){ os << ")"; } break; } case POW: if(!isInteger(e[0])){ os<<"ERRPR:arithmetic operations only support inteters now in TPTP\n"; break; } os << "$power_int(" << push << e[1] << space << "^ " << e[0] << push << ")"; break; case DIVIDE: if(!isInteger(e[0])){ os<<"ERRPR:arithmetic operations only support inteters now in TPTP\n"; break; } os << "divide_int(" < " << e[1] << push << ")"; break; case GE: os << "(" << push << e[0] << space << ">= " << e[1] << push << ")"; break; case DARK_SHADOW: os << "DARK_SHADOW(" << push << e[0] << ", " << space << e[1] << push << ")"; break; case GRAY_SHADOW: os << "GRAY_SHADOW(" << push << e[0] << "," << space << e[1] << "," << space << e[2] << "," << space << e[3] << push << ")"; break; default: // Print the top node in the default LISP format, continue with // pretty-printing for children. e.printAST(os); break; } break; // end of case PRESENTATION_LANG case SPASS_LANG: { switch(e.getKind()) { case REAL_CONST: printRational(os, e[0].getRational(), true); break; case RATIONAL_EXPR: printRational(os, e.getRational()); break; case REAL: throw SmtlibException("TheoryArithOld::print: SPASS: REAL not implemented"); break; case INT: throw SmtlibException("TheoryArithOld::print: SPASS: INT not implemented"); break; case SUBRANGE: throw SmtlibException("TheoryArithOld::print: SPASS: SUBRANGE not implemented"); break; case IS_INTEGER: throw SmtlibException("TheoryArithOld::print: SPASS: IS_INTEGER not implemented"); case PLUS: { int arity = e.arity(); if(2 == arity) { os << push << "plus(" << e[0] << "," << space << e[1] << push << ")"; } else if(2 < arity) { for (int i = 0 ; i < arity - 2; i++){ os << push << "plus("; os << e[i] << "," << space; } os << push << "plus(" << e[arity - 2] << "," << space << e[arity - 1] << push << ")"; for (int i = 0 ; i < arity - 2; i++){ os << push << ")"; } } else { throw SmtlibException("TheoryArithOld::print: SPASS: Less than two arguments for plus"); } break; } case MINUS: { os << push << "plus(" << e[0] << "," << space << push << "mult(-1," << space << e[1] << push << ")" << push << ")"; break; } case UMINUS: { os << push << "plus(0," << space << push << "mult(-1," << space << e[0] << push << ")" << push << ")"; break; } case MULT: { int arity = e.arity(); if (2 == arity){ os << push << "mult(" << e[0] << "," << space << e[1] << push << ")"; } else if (2 < arity){ for (int i = 0 ; i < arity - 2; i++){ os << push << "mult("; os << e[i] << "," << space; } os << push << "mult(" << e[arity - 2] << "," << space << e[arity - 1] << push << ")"; for (int i = 0 ; i < arity - 2; i++){ os << push << ")"; } } else{ throw SmtlibException("TheoryArithOld::print: SPASS: Less than two arguments for mult"); } break; } case POW: if (e[0].isRational() && e[0].getRational().isInteger()) { int i=0, iend=e[0].getRational().getInt(); for(; i!=iend; ++i) { if (i < iend-2) { os << push << "mult("; } os << e[1] << "," << space; } os << push << "mult(" << e[1] << "," << space << e[1]; for (i=0; i < iend-1; ++i) { os << push << ")"; } } else { throw SmtlibException("TheoryArithOld::print: SPASS: POW not supported: " + e.toString(PRESENTATION_LANG)); } break; case DIVIDE: { os << "ERROR "<< endl;break; throw SmtlibException("TheoryArithOld::print: SPASS: unexpected use of DIVIDE"); break; } case LT: { Rational r; os << push << "ls(" << space; os << e[0] << "," << space << e[1] << push << ")"; break; } case LE: { Rational r; os << push << "le(" << space; os << e[0] << "," << space << e[1] << push << ")"; break; } case GT: { Rational r; os << push << "gs(" << space; os << e[0] << "," << space << e[1] << push << ")"; break; } case GE: { Rational r; os << push << "ge(" << space; os << e[0] << "," << space << e[1] << push << ")"; break; } default: throw SmtlibException("TheoryArithOld::print: SPASS: default not supported"); } break; // end of case SPASS_LANG } case SMTLIB_LANG: case SMTLIB_V2_LANG: { switch(e.getKind()) { case REAL_CONST: printRational(os, e[0].getRational(), true); break; case RATIONAL_EXPR: printRational(os, e.getRational()); break; case REAL: os << "Real"; break; case INT: os << "Int"; break; case SUBRANGE: throw SmtlibException("TheoryArithOld::print: SMTLIB: SUBRANGE not implemented"); // if(e.arity() != 2) e.print(os); // else // os << "(" << push << "SUBRANGE" << space << e[0] // << space << e[1] << push << ")"; break; case IS_INTEGER: if(e.arity() == 1) { if (os.lang() == SMTLIB_LANG) { os << "(" << push << "IsInt" << space << e[0] << push << ")"; } else { os << "(" << push << "is_int" << space << e[0] << push << ")"; } } else throw SmtlibException("TheoryArithOld::print: SMTLIB: IS_INTEGER used unexpectedly"); break; case PLUS: { if(e.arity() == 1 && os.lang() == SMTLIB_V2_LANG) { os << e[0]; } else { os << "(" << push << "+"; Expr::iterator i = e.begin(), iend = e.end(); for(; i!=iend; ++i) { os << space << (*i); } os << push << ")"; } break; } case MINUS: { os << "(" << push << "- " << e[0] << space << e[1] << push << ")"; break; } case UMINUS: { if (os.lang() == SMTLIB_LANG) { os << "(" << push << "~" << space << e[0] << push << ")"; } else { os << "(" << push << "-" << space << e[0] << push << ")"; } break; } case MULT: { int i=0, iend=e.arity(); if(iend == 1 && os.lang() == SMTLIB_V2_LANG) { os << e[0]; } else { for(; i!=iend; ++i) { if (i < iend-1) { os << "(" << push << "*"; } os << space << e[i]; } for (i=0; i < iend-1; ++i) os << push << ")"; } break; } case POW: if (e[0].isRational() && e[0].getRational().isInteger()) { int i=0, iend=e[0].getRational().getInt(); for(; i!=iend; ++i) { if (i < iend-1) { os << "(" << push << "*"; } os << space << e[1]; } for (i=0; i < iend-1; ++i) os << push << ")"; } else throw SmtlibException("TheoryArithOld::print: SMTLIB: POW not supported: " + e.toString(PRESENTATION_LANG)); // os << "(" << push << "^ " << e[1] << space << e[0] << push << ")"; break; case DIVIDE: { throw SmtlibException("TheoryArithOld::print: SMTLIB: unexpected use of DIVIDE"); break; } case LT: { Rational r; os << "(" << push << "<" << space; os << e[0] << space << e[1] << push << ")"; break; } case LE: { Rational r; os << "(" << push << "<=" << space; os << e[0] << space << e[1] << push << ")"; break; } case GT: { Rational r; os << "(" << push << ">" << space; os << e[0] << space << e[1] << push << ")"; break; } case GE: { Rational r; os << "(" << push << ">=" << space; os << e[0] << space << e[1] << push << ")"; break; } case DARK_SHADOW: throw SmtlibException("TheoryArithOld::print: SMTLIB: DARK_SHADOW not supported"); os << "(" << push << "DARK_SHADOW" << space << e[0] << space << e[1] << push << ")"; break; case GRAY_SHADOW: throw SmtlibException("TheoryArithOld::print: SMTLIB: GRAY_SHADOW not supported"); os << "GRAY_SHADOW(" << push << e[0] << "," << space << e[1] << "," << space << e[2] << "," << space << e[3] << push << ")"; break; default: throw SmtlibException("TheoryArithOld::print: SMTLIB: default not supported"); // Print the top node in the default LISP format, continue with // pretty-printing for children. e.printAST(os); break; } break; // end of case SMTLIB_LANG } case LISP_LANG: switch(e.getKind()) { case REAL: case INT: case RATIONAL_EXPR: case NEGINF: case POSINF: e.print(os); break; case SUBRANGE: if(e.arity() != 2) e.printAST(os); else os << "(" << push << "SUBRANGE" << space << e[0] << space << e[1] << push << ")"; break; case IS_INTEGER: if(e.arity() == 1) os << "(" << push << "IS_INTEGER" << space << e[0] << push << ")"; else e.printAST(os); break; case PLUS: { int i=0, iend=e.arity(); os << "(" << push << "+"; for(; i!=iend; ++i) os << space << e[i]; os << push << ")"; break; } case MINUS: //os << "(" << push << e[0] << space << "- " << e[1] << push << ")"; os << "(" << push << "- " << e[0] << space << e[1] << push << ")"; break; case UMINUS: os << "(" << push << "-" << space << e[0] << push << ")"; break; case MULT: { int i=0, iend=e.arity(); os << "(" << push << "*"; for(; i!=iend; ++i) os << space << e[i]; os << push << ")"; break; } case POW: os << "(" << push << "^ " << e[1] << space << e[0] << push << ")"; break; case DIVIDE: os << "(" << push << "/ " << e[0] << space << e[1] << push << ")"; break; case LT: os << "(" << push << "< " << e[0] << space << e[1] << push << ")"; break; case LE: os << "(" << push << "<= " << e[0] << space << e[1] << push << ")"; break; case GT: os << "(" << push << "> " << e[1] << space << e[0] << push << ")"; break; case GE: os << "(" << push << ">= " << e[0] << space << e[1] << push << ")"; break; case DARK_SHADOW: os << "(" << push << "DARK_SHADOW" << space << e[0] << space << e[1] << push << ")"; break; case GRAY_SHADOW: os << "(" << push << "GRAY_SHADOW" << space << e[0] << space << e[1] << space << e[2] << space << e[3] << push << ")"; break; default: // Print the top node in the default LISP format, continue with // pretty-printing for children. e.printAST(os); break; } break; // end of case LISP_LANG default: // Print the top node in the default LISP format, continue with // pretty-printing for children. e.printAST(os); } return os; } Theorem TheoryArithOld::inequalityToFind(const Theorem& inequalityThm, bool normalizeRHS) { // Which side of the inequality int index = (normalizeRHS ? 1 : 0); TRACE("arith find", "inequalityToFind(", int2string(index) + ", " + inequalityThm.getExpr().toString(), ")"); // Get the inequality expression const Expr& inequality = inequalityThm.getExpr(); // The theorem we will return Theorem inequalityFindThm; // If the inequality side has a find if (inequality[index].hasFind()) { // Get the find of the rhs (lhs) Theorem rhsFindThm = inequality[index].getFind(); // Get the theorem simplifys the find (in case the updates haven't updated all the finds yet // Fixed with d_theroyCore.inUpdate() rhsFindThm = transitivityRule(rhsFindThm, simplify(rhsFindThm.getRHS())); // If not the same as the original Expr rhsFind = rhsFindThm.getRHS(); if (rhsFind != inequality[index]) { // Substitute in the inequality vector changed; vector children; changed.push_back(index); children.push_back(rhsFindThm); rhsFindThm = iffMP(inequalityThm, substitutivityRule(inequality, changed, children)); // If on the left-hand side, we are done if (index == 0) inequalityFindThm = rhsFindThm; else // If on the right-hand side and left-hand side is 0, normalize it if (inequality[0].isRational() && inequality[0].getRational() == 0) inequalityFindThm = normalize(rhsFindThm); else inequalityFindThm = rhsFindThm; } else inequalityFindThm = inequalityThm; } else inequalityFindThm = inequalityThm; TRACE("arith find", "inequalityToFind ==>", inequalityFindThm.getExpr(), ""); return inequalityFindThm; } void TheoryArithOld::registerAtom(const Expr& e) { // Trace it TRACE("arith atoms", "registerAtom(", e.toString(), ")"); // Mark it formulaAtoms[e] = true; // If it is a atomic formula, add it to the map if (e.isAbsAtomicFormula() && isIneq(e)) { Expr rightSide = e[1]; Rational leftSide = e[0].getRational(); //Get the terms for : c1 op t1 and t2 -op c2 Expr t1, t2; Rational c1, c2; extractTermsFromInequality(e, c1, t1, c2, t2); if (true) { TRACE("arith atoms", "registering lower bound for ", t1.toString(), " = " + c1.toString() + ")"); formulaAtomLowerBound[t1].insert(pair(c1, e)); // See if the bounds on the registered term can infered from already asserted facts CDMap::iterator lowerBoundFind = termLowerBound.find(t1); if (lowerBoundFind != termLowerBound.end()) { Rational boundValue = (*lowerBoundFind).second; Theorem boundThm = termLowerBoundThm[t1]; Expr boundIneq = boundThm.getExpr(); if (boundValue > c1 || (boundValue == c1 && !(boundIneq.getKind() == LE && e.getKind() == LT))) { enqueueFact(getCommonRules()->implMP(boundThm, d_rules->implyWeakerInequality(boundIneq, e))); } } // See if the bounds on the registered term can falsified from already asserted facts CDMap::iterator upperBoundFind = termUpperBound.find(t1); if (upperBoundFind != termUpperBound.end()) { Rational boundValue = (*upperBoundFind).second; Theorem boundThm = termUpperBoundThm[t1]; Expr boundIneq = boundThm.getExpr(); if (boundValue < c1 || (boundValue == c1 && boundIneq.getKind() == LT && e.getKind() == LT)) { enqueueFact(getCommonRules()->implMP(boundThm, d_rules->implyNegatedInequality(boundIneq, e))); } } TRACE("arith atoms", "registering upper bound for ", t2.toString(), " = " + c2.toString() + ")"); formulaAtomUpperBound[t2].insert(pair(c2, e)); } } } TheoryArithOld::DifferenceLogicGraph::DifferenceLogicGraph(TheoryArithOld* arith, TheoryCore* core, ArithProofRules* rules, Context* context) : d_pathLenghtThres(&(core->getFlags()["pathlength-threshold"].getInt())), arith(arith), core(core), rules(rules), unsat_theorem(context), biggestEpsilon(context, 0, 0), smallestPathDifference(context, 1, 0), leGraph(context), varInCycle(context) { } Theorem TheoryArithOld::DifferenceLogicGraph::getUnsatTheorem() { return unsat_theorem; } bool TheoryArithOld::DifferenceLogicGraph::isUnsat() { return !getUnsatTheorem().isNull(); } bool TheoryArithOld::DifferenceLogicGraph::existsEdge(const Expr& x, const Expr& y) { Expr index = x - y; Graph::iterator find_le = leGraph.find(index); if (find_le != leGraph.end()) { EdgeInfo edge_info = (*find_le).second; if (edge_info.isDefined()) return true; } return false; } bool TheoryArithOld::DifferenceLogicGraph::inCycle(const Expr& x) { return (varInCycle.find(x) != varInCycle.end()); } TheoryArithOld::DifferenceLogicGraph::Graph::ElementReference TheoryArithOld::DifferenceLogicGraph::getEdge(const Expr& x, const Expr& y) { Expr index = x - y; Graph::ElementReference edge_info = leGraph[index]; // If a new edge and x != y, then add vertices to the apropriate lists if (x != y && !edge_info.get().isDefined()) { // Adding a new edge, take a resource core->getResource(); EdgesList::iterator y_it = incomingEdges.find(y); if (y_it == incomingEdges.end() || (*y_it).second == 0) { CDList* list = new(true) CDList(core->getCM()->getCurrentContext()); list->push_back(x); incomingEdges[y] = list; } else ((*y_it).second)->push_back(x); EdgesList::iterator x_it = outgoingEdges.find(x); if (x_it == outgoingEdges.end() || (*x_it).second == 0) { CDList* list = new(true) CDList(core->getCM()->getCurrentContext()); list->push_back(y); outgoingEdges[x] = list; } else ((*x_it).second)->push_back(y); } return edge_info; } TheoryArithOld::DifferenceLogicGraph::EpsRational TheoryArithOld::DifferenceLogicGraph::getEdgeWeight(const Expr& x, const Expr& y) { if (!existsEdge(x, y)) return EpsRational::PlusInfinity; else { EdgeInfo edgeInfo = getEdge(x, y).get(); return edgeInfo.length; } } void TheoryArithOld::DifferenceLogicGraph::addEdge(const Expr& x, const Expr& y, const Rational& bound, const Theorem& edge_thm) { TRACE("arith diff", x, " --> ", y); DebugAssert(x != y, "addEdge, given two equal expressions!"); if (isUnsat()) return; // If out of resources, bail out if (core->outOfResources()) return; // Get the kind of the inequality (NOTE isNull -- for model computation we add a vertex with no theorem) // FIXME: Later, add a debug assert for the theorem that checks that this variable is cvc3diffLogicSource int kind = (edge_thm.isNull() ? LE : edge_thm.getExpr().getKind()); DebugAssert(kind == LT || kind == LE, "addEdge, not an <= or 0 && rationalDifference < smallestPathDifference) { smallestPathDifference = rationalDifference; TRACE("diff model", "smallest path difference : ", smallestPathDifference, ""); } } Rational newEpsilon = - c.getEpsilon(); if (newEpsilon > biggestEpsilon) { biggestEpsilon = newEpsilon; TRACE("diff model", "biggest epsilon : ", biggestEpsilon, ""); } // Set the edge info edgeInfo.length = c; edgeInfo.explanation = edge_thm; edgeInfo.path_length_in_edges = 1; edgeInfoRef = edgeInfo; // Try simple cycle x --> y --> x, to keep invariants (no cycles or one negative) if (existsEdge(y, x)) { varInCycle[x] = true; varInCycle[y] = true; tryUpdate(x, y, x); if (isUnsat()) return; } // For all edges coming into x, z ---> x, update z ---> y and add updated ones to the updated_in_y vector CDList* in_x = incomingEdges[x]; vector updated_in_y; updated_in_y.push_back(x); // If there if (in_x) { IF_DEBUG(int total = 0; int updated = 0;); for (unsigned it = 0; it < in_x->size() && !isUnsat(); it ++) { const Expr& z = (*in_x)[it]; if (z != arith->zero && z.hasFind() && core->find(z).getRHS() != z) continue; if (z != y && z != x && x != y) { IF_DEBUG(total ++;); TRACE("diff update", "trying with ", z.toString() + " --> ", x.toString()); if (tryUpdate(z, x, y)) { updated_in_y.push_back(z); IF_DEBUG(updated++;); } } } TRACE("diff updates", "Updates : ", int2string(updated), " of " + int2string(total)); } // For all edges coming into y, z_1 ---> y, and all edges going out of y, y ---> z_2, update z1 --> z_2 CDList* out_y = outgoingEdges[y]; if (out_y) for (unsigned it_z1 = 0; it_z1 < updated_in_y.size() && !isUnsat(); it_z1 ++) { for (unsigned it_z2 = 0; it_z2 < out_y->size() && !isUnsat(); it_z2 ++) { const Expr& z1 = updated_in_y[it_z1]; const Expr& z2 = (*out_y)[it_z2]; if (z2 != arith->zero && z2.hasFind() && core->find(z2).getRHS() != z2) continue; if (z1 != z2 && z1 != y && z2 != y) tryUpdate(z1, y, z2); } } } else { TRACE("arith propagate", "could have propagated ", edge_thm.getExpr(), edge_thm.isAssump() ? " ASSUMPTION " : "not assumption"); } } void TheoryArithOld::DifferenceLogicGraph::getEdgeTheorems(const Expr& x, const Expr& z, const EdgeInfo& edgeInfo, std::vector& outputTheorems) { TRACE("arith diff", "Getting theorems from ", x, " to " + z.toString() + " length = " + edgeInfo.length.toString() + ", edge_length = " + int2string(edgeInfo.path_length_in_edges)); if (edgeInfo.path_length_in_edges == 1) { DebugAssert(x == sourceVertex || z == sourceVertex || !edgeInfo.explanation.isNull(), "Edge from " + x.toString() + " to " + z.toString() + " has no theorem!"); if (x != sourceVertex && z != sourceVertex) outputTheorems.push_back(edgeInfo.explanation); } else { const Expr& y = edgeInfo.in_path_vertex; EdgeInfo x_y = getEdge(x, y); DebugAssert(x_y.isDefined(), "getEdgeTheorems: the cycle edge is not defined!"); EdgeInfo y_z = getEdge(y, z); DebugAssert(y_z.isDefined(), "getEdgeTheorems: the cycle edge is not defined!"); getEdgeTheorems(x, y, x_y, outputTheorems); getEdgeTheorems(y, z, y_z, outputTheorems); } } void TheoryArithOld::DifferenceLogicGraph::analyseConflict(const Expr& x, int kind) { // Get the cycle info Graph::ElementReference x_x_cycle_ref = getEdge(x, x); EdgeInfo x_x_cycle = x_x_cycle_ref.get(); DebugAssert(x_x_cycle.isDefined(), "analyseConflict: the cycle edge is not defined!"); // Vector to keep the theorems in vector inequalities; // Get the theorems::analyse getEdgeTheorems(x, x, x_x_cycle, inequalities); // Set the unsat theorem unsat_theorem = rules->cycleConflict(inequalities); TRACE("diff unsat", "negative cycle : ", int2string(inequalities.size()), " vertices."); } bool TheoryArithOld::DifferenceLogicGraph::tryUpdate(const Expr& x, const Expr& y, const Expr& z) { // x -> y -> z, if z -> x they are all in a cycle if (existsEdge(z, x)) { varInCycle[x] = true; varInCycle[y] = true; varInCycle[z] = true; } //Get all the edges Graph::ElementReference x_y_le_ref = getEdge(x, y); EdgeInfo x_y_le = x_y_le_ref; if (*d_pathLenghtThres >= 0 && x_y_le.path_length_in_edges > *d_pathLenghtThres) return false; Graph::ElementReference y_z_le_ref = getEdge(y, z); EdgeInfo y_z_le = y_z_le_ref; if (*d_pathLenghtThres >= 0 && y_z_le.path_length_in_edges > *d_pathLenghtThres) return false; Graph::ElementReference x_z_le_ref = getEdge(x, z); EdgeInfo x_z_le = x_z_le_ref; bool cycle = (x == z); bool updated = false; // Try <= + <= --> <= if (!isUnsat() && x_y_le.isDefined() && y_z_le.isDefined()) { EpsRational combined_length = x_y_le.length + y_z_le.length; int combined_edge_length = x_y_le.path_length_in_edges + y_z_le.path_length_in_edges; if (!x_z_le.isDefined() || combined_length < x_z_le.length || (combined_length == x_z_le.length && (combined_edge_length < x_z_le.path_length_in_edges))) { if (!cycle || combined_length <= EpsRational::Zero) { if (!cycle || combined_length < EpsRational::Zero) { // Remember the path differences if (!cycle) { EpsRational difference = x_z_le.length - combined_length; Rational rationalDifference = difference.getRational(); Rational newEpsilon = - x_z_le.length.getEpsilon(); if (rationalDifference > 0 && rationalDifference < smallestPathDifference) { smallestPathDifference = rationalDifference; TRACE("diff model", "smallest path difference : ", smallestPathDifference, ""); } if (newEpsilon > biggestEpsilon) { biggestEpsilon = newEpsilon; TRACE("diff model", "biggest epsilon : ", biggestEpsilon, ""); } } // If we have a constraint among two integers variables strenghten it bool addAndEnqueue = false; if (core->okToEnqueue() && !combined_length.isInteger()) if (x.getType() == arith->intType() && z.getType() == arith->intType()) addAndEnqueue = true; x_z_le.length = combined_length; x_z_le.path_length_in_edges = combined_edge_length; x_z_le.in_path_vertex = y; x_z_le_ref = x_z_le; if (addAndEnqueue) { vector pathTheorems; getEdgeTheorems(x, z, x_z_le, pathTheorems); core->enqueueFact(rules->addInequalities(pathTheorems)); } TRACE("arith diff", x.toString() + " -- > " + z.toString(), " : ", combined_length.toString()); updated = true; } else if (core->okToEnqueue()) { // 0 length cycle vector antecedentThms; getEdgeTheorems(x, y, x_y_le, antecedentThms); getEdgeTheorems(y, z, y_z_le, antecedentThms); core->enqueueFact(rules->implyEqualities(antecedentThms)); } // Try to propagate somthing in the original formula if (updated && !cycle && x != sourceVertex && z != sourceVertex && core->okToEnqueue()) arith->tryPropagate(x, z, x_z_le, LE); } if (cycle && combined_length < EpsRational::Zero) analyseConflict(x, LE); } } return updated; } void TheoryArithOld::DifferenceLogicGraph::expandSharedTerm(const Expr& x) { } TheoryArithOld::DifferenceLogicGraph::~DifferenceLogicGraph() { for (EdgesList::iterator it = incomingEdges.begin(), it_end = incomingEdges.end(); it != it_end; it ++) { if ((*it).second) { delete (*it).second; free ((*it).second); } } for (EdgesList::iterator it = outgoingEdges.begin(), it_end = outgoingEdges.end(); it != it_end; it ++) { if ((*it).second) { delete (*it).second; free ((*it).second); } } } void TheoryArithOld::tryPropagate(const Expr& x, const Expr& y, const DifferenceLogicGraph::EdgeInfo& x_y_edge, int kind) { TRACE("diff atoms", "trying propagation", " x = " + x.toString(), " y = " + y.toString()); // bail on non representative terms (we don't pass non-representative terms) // if (x.hasFind() && find(x).getRHS() != x) return; // if (y.hasFind() && find(y).getRHS() != y) return; // given edge x - z (kind) lenth // Make the index (c1 <= y - x) vector t1_summands; t1_summands.push_back(rat(0)); if (y != zero) t1_summands.push_back(y); // We have to canonize in case it is nonlinear // nonlinear terms are canonized with a constants --> 1*x*y, hence (-1)*1*x*y will not be canonical if (x != zero) t1_summands.push_back(canon(rat(-1)*x).getRHS()); Expr t1 = canon(plusExpr(t1_summands)).getRHS(); TRACE("diff atoms", "trying propagation", " t1 = " + t1.toString(), ""); // The constant c1 <= y - x Rational c1 = - x_y_edge.length.getRational(); // See if we can propagate anything to the formula atoms // c1 <= t1 ===> c <= t1 for c < c1 AtomsMap::iterator find = formulaAtomLowerBound.find(t1); AtomsMap::iterator find_end = formulaAtomLowerBound.end(); if (find != find_end) { set< pair >::iterator bounds = (*find).second.begin(); set< pair >::iterator bounds_end = (*find).second.end(); while (bounds != bounds_end) { const Expr& implied = (*bounds).second; // Try to do some theory propagation if ((*bounds).first < c1 || (implied.getKind() == LE && (*bounds).first == c1)) { TRACE("diff atoms", "found propagation", "", ""); // c1 <= t1 => c <= t1 (for c <= c1) // c1 < t1 => c <= t1 (for c <= c1) // c1 <= t1 => c < t1 (for c < c1) vector antecedentThms; diffLogicGraph.getEdgeTheorems(x, y, x_y_edge, antecedentThms); Theorem impliedThm = d_rules->implyWeakerInequalityDiffLogic(antecedentThms, implied); enqueueFact(impliedThm); } bounds ++; } } // // c1 <= t1 ==> !(t1 <= c) for c < c1 // ==> !(-c <= t2) // i.e. all coefficient in in the implied are opposite of t1 find = formulaAtomUpperBound.find(t1); find_end = formulaAtomUpperBound.end(); if (find != find_end) { set< pair >::iterator bounds = (*find).second.begin(); set< pair >::iterator bounds_end = (*find).second.end(); while (bounds != bounds_end) { const Expr& implied = (*bounds).second; // Try to do some theory propagation if ((*bounds).first < c1) { TRACE("diff atoms", "found negated propagation", "", ""); vector antecedentThms; diffLogicGraph.getEdgeTheorems(x, y, x_y_edge, antecedentThms); Theorem impliedThm = d_rules->implyNegatedInequalityDiffLogic(antecedentThms, implied); enqueueFact(impliedThm); } bounds ++; } } } void TheoryArithOld::DifferenceLogicGraph::computeModel() { // If source vertex is null, create it if (sourceVertex.isNull()) { Theorem thm_exists_zero = arith->getCommonRules()->varIntroSkolem(arith->zero); sourceVertex = thm_exists_zero.getExpr()[1]; } // The empty theorem to pass around Theorem thm; // Add an edge to all the vertices EdgesList::iterator vertexIt = incomingEdges.begin(); EdgesList::iterator vertexItEnd = incomingEdges.end(); for (; vertexIt != vertexItEnd; vertexIt ++) { Expr vertex = (*vertexIt).first; if (core->find(vertex).getRHS() != vertex) continue; if (vertex != sourceVertex && !existsEdge(sourceVertex, vertex)) addEdge(sourceVertex, vertex, 0, thm); } vertexIt = outgoingEdges.begin(); vertexItEnd = outgoingEdges.end(); for (; vertexIt != vertexItEnd; vertexIt ++) { Expr vertex = (*vertexIt).first; if (core->find(vertex).getRHS() != vertex) continue; if (vertex != sourceVertex && !existsEdge(sourceVertex, vertex)) addEdge(sourceVertex, vertex, 0, thm); } // Also add an edge to cvcZero if (!existsEdge(sourceVertex, arith->zero)) addEdge(sourceVertex, arith->zero, 0, thm); // For the < edges we will have a small enough epsilon to add // So, we will upper-bound the number of vertices and then divide // the smallest edge with that number so as to not be able to bypass } Rational TheoryArithOld::DifferenceLogicGraph::getValuation(const Expr& x) { // For numbers, return it's value if (x.isRational()) return x.getRational(); // For the source vertex, we don't care if (x == sourceVertex) return 0; // The path from source to targer vertex Graph::ElementReference x_le_c_ref = getEdge(sourceVertex, x); EdgeInfo x_le_c = x_le_c_ref; // The path from source to zero (adjusment) Graph::ElementReference zero_le_c_ref = getEdge(sourceVertex, arith->zero); EdgeInfo zero_le_c = zero_le_c_ref; TRACE("diff model", "zero adjustment: ", zero_le_c.length.getRational(), ""); TRACE("diff model", "zero adjustment (eps): ", zero_le_c.length.getEpsilon(), ""); // Value adjusted with the epsilon Rational epsAdjustment = (biggestEpsilon > 0 ? (x_le_c.length.getEpsilon() - zero_le_c.length.getEpsilon()) * smallestPathDifference / (2 * (biggestEpsilon + 1)) : 0); Rational value = x_le_c.length.getRational() + epsAdjustment; TRACE("diff model" , "biggest epsilon: ", biggestEpsilon, ""); TRACE("diff model" , "smallestPathDifference: ", smallestPathDifference, ""); TRACE("diff model" , "x_le_c.getEpsilon: ", x_le_c.length.getEpsilon(), ""); TRACE("diff model" , "x_le_c.length: ", x_le_c.length.getRational(), ""); // Value adjusted with the shift for zero value = zero_le_c.length.getRational() - value; TRACE("diff model", "Value of ", x, " : " + value.toString()); // Return it return value; } // The infinity constant const TheoryArithOld::DifferenceLogicGraph::EpsRational TheoryArithOld::DifferenceLogicGraph::EpsRational::PlusInfinity(PLUS_INFINITY); // The negative infinity constant const TheoryArithOld::DifferenceLogicGraph::EpsRational TheoryArithOld::DifferenceLogicGraph::EpsRational::MinusInfinity(MINUS_INFINITY); // The negative infinity constant const TheoryArithOld::DifferenceLogicGraph::EpsRational TheoryArithOld::DifferenceLogicGraph::EpsRational::Zero; void TheoryArithOld::addMultiplicativeSignSplit(const Theorem& case_split_thm) { multiplicativeSignSplits.push_back(case_split_thm); } bool TheoryArithOld::addPairToArithOrder(const Expr& smaller, const Expr& bigger) { TRACE("arith var order", "addPairToArithOrder(" + smaller.toString(), ", ", bigger.toString() + ")"); // We only accept arithmetic terms if (!isReal(smaller.getType()) && !isInt(smaller.getType())) return false; if (!isReal(bigger.getType()) && !isInt(bigger.getType())) return false; // We don't want to introduce loops FatalAssert(!d_graph.lessThan(smaller, bigger), "The pair (" + bigger.toString() + "," + smaller.toString() + ") is already in the order"); // Update the graph d_graph.addEdge(smaller, bigger); return true; } bool TheoryArithOld::isNonlinearSumTerm(const Expr& term) { if (isPow(term)) return true; if (!isMult(term)) return false; int vars = 0; for (int j = 0; j < term.arity(); j ++) if (isPow(term[j])) return true; else if (isLeaf(term[j])) { vars ++; if (vars > 1) return true; } return false; } bool TheoryArithOld::isNonlinearEq(const Expr& e) { DebugAssert(e.isEq(), "TheoryArithOld::isNonlinear: expecting an equation" + e.toString()); const Expr& lhs = e[0]; const Expr& rhs = e[1]; if (isNonlinearSumTerm(lhs) || isNonlinearSumTerm(rhs)) return true; // Check the right-hand side for (int i = 0; i < lhs.arity(); i ++) if (isNonlinearSumTerm(lhs[i])) return true; // Check the left hand side for (int i = 0; i < rhs.arity(); i ++) if (isNonlinearSumTerm(rhs[i])) return true; return false; } bool TheoryArithOld::isPowersEquality(const Expr& eq, Expr& power1, Expr& power2) { // equality should be in the form 0 + x1^n - x2^n = 0 DebugAssert(eq.isEq(), "TheoryArithOld::isPowersEquality, expecting an equality got " + eq.toString()); if (!isPlus(eq[0])) return false; if (eq[0].arity() != 3) return false; if (!(eq[0][0].isRational()) || !(eq[0][0].getRational() == 0)) return false; // Process the first term Expr term1 = eq[0][1]; Rational term1_c; if (isPow(term1)) { term1_c = 1; power1 = term1; } else if (isMult(term1) && term1.arity() == 2) { if (term1[0].isRational()) { term1_c = term1[0].getRational(); if (isPow(term1[1])) { if (term1_c == 1) power1 = term1[1]; else if (term1_c == -1) power2 = term1[1]; else return false; } else return false; } else return false; } else return false; // Process the second term Expr term2 = eq[0][2]; Rational term2_c; if (isPow(term2)) { term2_c = 1; power1 = term2; } else if (isMult(term2) && term2.arity() == 2) { if (term2[0].isRational()) { term2_c = term2[0].getRational(); if (isPow(term2[1])) { if (term2_c == 1) power1 = term2[1]; else if (term2_c == -1) power2 = term2[1]; else return false; } else return false; } else return false; } else return false; // Check that they are of opposite signs if (term1_c == term2_c) return false; // Check that the powers are equal numbers if (!power1[0].isRational()) return false; if (!power2[0].isRational()) return false; if (power1[0].getRational() != power2[0].getRational()) return false; // Everything is fine return true; } bool TheoryArithOld::isPowerEquality(const Expr& eq, Rational& constant, Expr& power1) { DebugAssert(eq.isEq(), "TheoryArithOld::isPowerEquality, expecting an equality got " + eq.toString()); if (!isPlus(eq[0])) return false; if (eq[0].arity() != 2) return false; if (!eq[0][0].isRational()) return false; constant = eq[0][0].getRational(); Expr term = eq[0][1]; if (isPow(term)) { power1 = term; constant = -constant; } else if (isMult(term) && term.arity() == 2) { if (term[0].isRational() && isPow(term[1])) { Rational term2_c = term[0].getRational(); if (term2_c == 1) { power1 = term[1]; constant = -constant; } else if (term2_c == -1) { power1 = term[1]; return true; } else return false; } else return false; } else return false; // Check that the power is an integer if (!power1[0].isRational()) return false; if (!power1[0].getRational().isInteger()) return false; return true; } int TheoryArithOld::termDegree(const Expr& e) { if (isLeaf(e)) return 1; if (isPow(e)) return termDegree(e[1]) * e[0].getRational().getInt(); if (isMult(e)) { int degree = 0; for (int i = 0; i < e.arity(); i ++) degree += termDegree(e[i]); return degree; } return 0; } bool TheoryArithOld::canPickEqMonomial(const Expr& right) { DebugAssert(right.arity() > 1, "TheoryArithOld::canPickEqMonomial, expecting > 1 child, got " + right.arity()); Expr::iterator istart = right.begin(); Expr::iterator iend = right.end(); // Skip the first one istart++; for(Expr::iterator i = istart; i != iend; ++i) { Expr leaf; Rational coeff; // Check if linear term if (isLeaf(*i)) { leaf = *i; coeff = 1; } else if (isMult(*i) && (*i).arity() == 2 && (*i)[0].isRational() && isLeaf((*i)[1])) { leaf = (*i)[1]; coeff = abs((*i)[0].getRational()); } else continue; // If integer, must be coeff 1/-1 if (!isIntegerThm(leaf).isNull()) if (coeff != 1 && coeff != -1) continue; // Check if a leaf in other ones Expr::iterator j; for (j = istart; j != iend; ++j) if (j != i && isLeafIn(leaf, *j)) break; if (j == iend) return true; } return false; } bool TheoryArithOld::isBounded(const Expr& t, BoundsQueryType queryType) { TRACE("arith shared", "isBounded(", t.toString(), ")"); return hasUpperBound(t, queryType) && hasLowerBound(t, queryType); } TheoryArithOld::DifferenceLogicGraph::EpsRational TheoryArithOld::getUpperBound(const Expr& t, BoundsQueryType queryType) { TRACE("arith shared", "getUpperBound(", t.toString(), ")"); // If t is a constant it's bounded if (t.isRational()) { TRACE("arith shared", "getUpperBound(", t.toString(), ") ==> " + t.getRational().toString()); return t.getRational(); } // If buffered, just return it CDMap::iterator find_t = termUpperBounded.find(t); if (find_t != termUpperBounded.end()) { TRACE("arith shared", "getUpperBound(", t.toString(), ") ==> " + (*find_t).second.toString()); return (*find_t).second; } else if (queryType == QueryWithCacheAll) { // Asked for cache query, so no bound is found TRACE("arith shared", "getUpperBound(", t.toString(), ") ==> +inf"); return DifferenceLogicGraph::EpsRational::PlusInfinity; } // Assume it's not bounded DifferenceLogicGraph::EpsRational upperBound = DifferenceLogicGraph::EpsRational::PlusInfinity; // We always buffer the leaves, so all that's left are the terms if (!isLeaf(t)) { if (isMult(t)) { // We only handle linear terms if (!isNonlinearSumTerm(t)) { // Separate the multiplication Expr c, v; separateMonomial(t, c, v); // Get the upper-bound for the variable if (c.getRational() > 0) upperBound = getUpperBound(v); else upperBound = getLowerBound(v); if (upperBound.isFinite()) upperBound = upperBound * c.getRational(); else upperBound = DifferenceLogicGraph::EpsRational::PlusInfinity; } } else if (isPlus(t)) { // If one of them is unconstrained then the term itself is unconstrained upperBound = DifferenceLogicGraph::EpsRational::Zero; for (int i = 0; i < t.arity(); i ++) { Expr t_i = t[i]; DifferenceLogicGraph::EpsRational t_i_upperBound = getUpperBound(t_i, queryType); if (t_i_upperBound.isFinite()) upperBound = upperBound + t_i_upperBound; else { upperBound = DifferenceLogicGraph::EpsRational::PlusInfinity; // Not-bounded, check for constrained if (queryType == QueryWithCacheLeavesAndConstrainedComputation) { for(; i < t.arity() && isConstrainedAbove(t[i], QueryWithCacheLeaves); i ++); if (i == t.arity()) { TRACE("arith shared", "getUpperBound(", t.toString(), ") ==> constrained"); termConstrainedAbove[t] = true; } break; } else break; } } } } // Buffer it if (upperBound.isFinite()) { termUpperBounded[t] = upperBound; termConstrainedAbove[t] = true; } // Return if bounded or not TRACE("arith shared", "getUpperBound(", t.toString(), ") ==> " + upperBound.toString()); return upperBound; } TheoryArithOld::DifferenceLogicGraph::EpsRational TheoryArithOld::getLowerBound(const Expr& t, BoundsQueryType queryType) { TRACE("arith shared", "getLowerBound(", t.toString(), ")"); // If t is a constant it's bounded if (t.isRational()) { TRACE("arith shared", "getLowerBound(", t.toString(), ") ==> " + t.getRational().toString()); return t.getRational(); } // If buffered, just return it CDMap::iterator t_find = termLowerBounded.find(t); if (t_find != termLowerBounded.end()) { TRACE("arith shared", "getLowerBound(", t.toString(), ") ==> " + (*t_find).second.toString()); return (*t_find).second; } else if (queryType == QueryWithCacheAll) { // Asked for cache query, so no bound is found TRACE("arith shared", "getLowerBound(", t.toString(), ") ==> -inf"); return DifferenceLogicGraph::EpsRational::MinusInfinity; } // Assume it's not bounded DifferenceLogicGraph::EpsRational lowerBound = DifferenceLogicGraph::EpsRational::MinusInfinity; // Leaves are always buffered if (!isLeaf(t)) { if (isMult(t)) { // We only handle linear terms if (!isNonlinearSumTerm(t)) { // Separate the multiplication Expr c, v; separateMonomial(t, c, v); // Get the upper-bound for the variable if (c.getRational() > 0) lowerBound = getLowerBound(v); else lowerBound = getUpperBound(v); if (lowerBound.isFinite()) lowerBound = lowerBound * c.getRational(); else lowerBound = DifferenceLogicGraph::EpsRational::MinusInfinity; } } else if (isPlus(t)) { // If one of them is unconstrained then the term itself is unconstrained lowerBound = DifferenceLogicGraph::EpsRational::Zero; for (int i = 0; i < t.arity(); i ++) { Expr t_i = t[i]; DifferenceLogicGraph::EpsRational t_i_lowerBound = getLowerBound(t_i, queryType); if (t_i_lowerBound.isFinite()) lowerBound = lowerBound + t_i_lowerBound; else { lowerBound = DifferenceLogicGraph::EpsRational::MinusInfinity; // Not-bounded, check for constrained if (queryType == QueryWithCacheLeavesAndConstrainedComputation) { for(; i < t.arity() && isConstrainedBelow(t[i], QueryWithCacheLeaves); i ++); if (i == t.arity()) { TRACE("arith shared", "getLowerBound(", t.toString(), ") ==> constrained"); termConstrainedBelow[t] = true; } break; } else break; } } } } // Buffer it if (lowerBound.isFinite()) { termLowerBounded[t] = lowerBound; termConstrainedBelow[t] = true; } // Return if bounded or not TRACE("arith shared", "getLowerBound(", t.toString(), ") ==> " + lowerBound.toString()); return lowerBound; } int TheoryArithOld::computeTermBounds() { int computeTermBoundsConstrainedCount = 0; vector sorted_vars; // Get the variables in the topological order if (!diffLogicOnly) d_graph.getVerticesTopological(sorted_vars); // Or if difference logic only, just get them else { diffLogicGraph.getVariables(sorted_vars); IF_DEBUG( diffLogicGraph.writeGraph(cerr); ) } // Go in the reverse topological order and try to see if the vats are constrained/bounded for (int i = sorted_vars.size() - 1; i >= 0; i --) { // Get the variable Expr v = sorted_vars[i]; // If the find is not identity, skip it if (v.hasFind() && find(v).getRHS() != v) continue; TRACE("arith shared", "processing: ", v.toString(), ""); // If the variable is not an integer, it's unconstrained, unless we are in model generation if (isIntegerThm(v).isNull() && !d_inModelCreation) continue; // We only do the computation if the variable is not already constrained if (!isConstrained(v, QueryWithCacheAll)) { // Recall if we already computed the constraint bool constrainedAbove = isConstrained(v, QueryWithCacheAll); // See if it's bounded from above in the difference graph DifferenceLogicGraph::EpsRational upperBound = diffLogicGraph.getEdgeWeight(v, zero); if (!constrainedAbove) constrainedAbove = upperBound.isFinite(); // Try to refine the bound by checking projected inequalities if (!diffLogicOnly) { ExprMap *>::iterator v_left_find = d_inequalitiesLeftDB.find(v); // If not constraint from one side, it's unconstrained if (v_left_find != d_inequalitiesLeftDB.end()) { // Check right hand side for an unconstrained variable CDList*& left_list = (*v_left_find).second; if (left_list && left_list->size() > 0) { for (unsigned ineq_i = 0; ineq_i < left_list->size(); ineq_i ++) { // Get the inequality Ineq ineq = (*left_list)[ineq_i]; // Get the right-hand side (v <= rhs) Expr rhs = ineq.ineq().getExpr()[1]; // If rhs changed, skip it if (rhs.hasFind() && find(rhs).getRHS() != rhs) continue; // Compute the upper bound while DifferenceLogicGraph::EpsRational currentUpperBound = getUpperBound(rhs, (constrainedAbove ? QueryWithCacheLeaves : QueryWithCacheLeavesAndConstrainedComputation)); if (currentUpperBound.isFinite() && (!upperBound.isFinite() || currentUpperBound < upperBound)) { upperBound = currentUpperBound; constrainedAbove = true; } // If not constrained, check if right-hand-side is constrained if (!constrainedAbove) constrainedAbove = isConstrainedAbove(rhs, QueryWithCacheAll); } } } } // Difference logic case (no projections) else if (!constrainedAbove) { // If there is no incoming edges, then the variable is not constrained if (!diffLogicGraph.hasIncoming(v)) constrainedAbove = false; // If there is a cycle from t to t, all the variables // in the graph are constrained by each-other (we could // choose one, but it's too complicated) else if (diffLogicGraph.inCycle(v)) constrainedAbove = true; // Otherwise, since there is no bounds, and the cycles // can be shifted (since one of them can be taken as // unconstrained), we can assume that the variables is // not constrained. Conundrum here is that when in model-generation // we actually should take it as constrained so that it's // split on and we are on the safe side else constrainedAbove = d_inModelCreation; } // Cache the upper bound and upper constrained computation if (constrainedAbove) termConstrainedAbove[v] = true; if (upperBound.isFinite()) termUpperBounded[v] = upperBound; // Recall the below computation if it's there bool constrainedBelow = isConstrainedBelow(v, QueryWithCacheAll); // See if it's bounded from below in the difference graph DifferenceLogicGraph::EpsRational lowerBound = diffLogicGraph.getEdgeWeight(zero, v); if (lowerBound.isFinite()) lowerBound = -lowerBound; else lowerBound = DifferenceLogicGraph::EpsRational::MinusInfinity; if (!constrainedBelow) constrainedBelow = lowerBound.isFinite(); // Try to refine the bound by checking projected inequalities if (!diffLogicOnly) { ExprMap *>::iterator v_right_find = d_inequalitiesRightDB.find(v); // If not constraint from one side, it's unconstrained if (v_right_find != d_inequalitiesRightDB.end()) { // Check right hand side for an unconstrained variable CDList*& right_list = (*v_right_find).second; if (right_list && right_list->size() > 0) { for (unsigned ineq_i = 0; ineq_i < right_list->size(); ineq_i ++) { // Get the inequality Ineq ineq = (*right_list)[ineq_i]; // Get the right-hand side (lhs <= 0) Expr lhs = ineq.ineq().getExpr()[0]; // If lhs has changed, skip it if (lhs.hasFind() && find(lhs).getRHS() != lhs) continue; // Compute the lower bound DifferenceLogicGraph::EpsRational currentLowerBound = getLowerBound(lhs, (constrainedBelow ? QueryWithCacheLeaves : QueryWithCacheLeavesAndConstrainedComputation)); if (currentLowerBound.isFinite() && (!lowerBound.isFinite() || currentLowerBound > lowerBound)) { lowerBound = currentLowerBound; constrainedBelow = true; } // If not constrained, check if right-hand-side is constrained if (!constrainedBelow) constrainedBelow = isConstrainedBelow(lhs, QueryWithCacheAll); } } } } // Difference logic case (no projections) else if (!constrainedBelow) { // If there is no incoming edges, then the variable is not constrained if (!diffLogicGraph.hasOutgoing(v)) constrainedBelow = false; // If there is a cycle from t to t, all the variables // in the graph are constrained by each-other (we could // choose one, but it's too complicated) else if (diffLogicGraph.inCycle(v)) constrainedBelow = true; // Otherwise, since there is no bounds, and the cycles // can be shifted (since one of them can be taken as // unconstrained), we can assume that the variables is // not constrained. Conundrum here is that when in model-generation // we actually should take it as constrained so that it's // split on and we are on the safe side else constrainedBelow = d_inModelCreation; } // Cache the lower bound and lower constrained computation if (constrainedBelow) termConstrainedBelow[v] = true; if (lowerBound.isFinite()) termLowerBounded[v] = lowerBound; // Is this variable constrained if (constrainedAbove && constrainedBelow) computeTermBoundsConstrainedCount ++; TRACE("arith shared", (constrainedAbove && constrainedBelow ? "constrained " : "unconstrained "), "", ""); } else computeTermBoundsConstrainedCount ++; } TRACE("arith shared", "number of constrained variables : ", int2string(computeTermBoundsConstrainedCount), " of " + int2string(sorted_vars.size())); return computeTermBoundsConstrainedCount; } bool TheoryArithOld::isConstrainedAbove(const Expr& t, BoundsQueryType queryType) { TRACE("arith shared", "isConstrainedAbove(", t.toString(), ")"); // Rational numbers are constrained if (t.isRational()) { TRACE("arith shared", "isConstrainedAbove() ==> true", "", ""); return true; } // Look it up in the cache CDMap::iterator t_find = termConstrainedAbove.find(t); if (t_find != termConstrainedAbove.end()) { TRACE("arith shared", "isConstrainedAbove() ==> true", "", ""); return true; } else if (queryType == QueryWithCacheAll) { TRACE("arith shared", "isConstrainedAbove() ==> false", "", ""); return false; } bool constrainedAbove = true; if (isLeaf(t)) { // Leaves are always cached constrainedAbove = false; } else { if (isMult(t)) { // Non-linear terms are constrained by default // we only deal with the linear stuff if (!isNonlinearSumTerm(t)) { // Separate the multiplication Expr c, v; separateMonomial(t, c, v); // Check if the variable is constrained if (c.getRational() > 0) constrainedAbove = isConstrainedAbove(v, queryType); else constrainedAbove = isConstrainedBelow(v, queryType); } } else if (isPlus(t)) { // If one of them is unconstrained then the term itself is unconstrained for (int i = 0; i < t.arity() && constrainedAbove; i ++) if (!isConstrainedAbove(t[i])) constrainedAbove = false; } } // Remember it if (constrainedAbove) termConstrainedAbove[t] = true; TRACE("arith shared", "isConstrainedAbove() ==> ", constrainedAbove ? "true" : "false", ""); // Return in return constrainedAbove; } bool TheoryArithOld::isConstrainedBelow(const Expr& t, BoundsQueryType queryType) { TRACE("arith shared", "isConstrainedBelow(", t.toString(), ")"); // Rational numbers are constrained if (t.isRational()) return true; // Look it up in the cache CDMap::iterator t_find = termConstrainedBelow.find(t); if (t_find != termConstrainedBelow.end()) { TRACE("arith shared", "isConstrainedBelow() ==> true", "", ""); return true; } else if (queryType == QueryWithCacheAll) { TRACE("arith shared", "isConstrainedBelow() ==> false", "", ""); return false; } bool constrainedBelow = true; if (isLeaf(t)) { // Leaves are always cached constrainedBelow = false; } else { if (isMult(t)) { // Non-linear terms are constrained by default // we only deal with the linear stuff if (!isNonlinearSumTerm(t)) { // Separate the multiplication Expr c, v; separateMonomial(t, c, v); // Check if the variable is constrained if (c.getRational() > 0) constrainedBelow = isConstrainedBelow(v, queryType); else constrainedBelow = isConstrainedAbove(v, queryType); } } else if (isPlus(t)) { // If one of them is unconstrained then the term itself is unconstrained constrainedBelow = true; for (int i = 0; i < t.arity() && constrainedBelow; i ++) if (!isConstrainedBelow(t[i])) constrainedBelow = false; } } // Cache it if (constrainedBelow) termConstrainedBelow[t] = true; TRACE("arith shared", "isConstrainedBelow() ==> ", constrainedBelow ? "true" : "false", ""); // Return it return constrainedBelow; } bool TheoryArithOld::isConstrained(const Expr& t, bool intOnly, BoundsQueryType queryType) { TRACE("arith shared", "isConstrained(", t.toString(), ")"); // For the reals we consider them unconstrained if not asked for full check if (intOnly && isIntegerThm(t).isNull()) return false; bool result = (isConstrainedAbove(t, queryType) && isConstrainedBelow(t, queryType)); TRACE("arith shared", "isConstrained(", t.toString(), (result ? ") ==> true " : ") ==> false ") ); return result; } bool TheoryArithOld::DifferenceLogicGraph::hasIncoming(const Expr& x) { EdgesList::iterator find_x = incomingEdges.find(x); // No edges at all meaning no incoming if (find_x == incomingEdges.end()) return false; // The pointer being null, also no incoming CDList*& list = (*find_x).second; if (!list) return false; // If in model creation, source vertex goes to all vertices if (sourceVertex.isNull()) return list->size() > 0; else return list->size() > 1; } bool TheoryArithOld::DifferenceLogicGraph::hasOutgoing(const Expr& x) { EdgesList::iterator find_x = outgoingEdges.find(x); // No edges at all meaning no incoming if (find_x == outgoingEdges.end()) return false; // The pointer being null, also no incoming CDList*& list = (*find_x).second; if (!list) return false; // If the list is not empty we have outgoing edges return list->size() > 0; } void TheoryArithOld::DifferenceLogicGraph::getVariables(vector& variables) { set vars_set; EdgesList::iterator incoming_it = incomingEdges.begin(); EdgesList::iterator incoming_it_end = incomingEdges.end(); while (incoming_it != incoming_it_end) { Expr var = (*incoming_it).first; if (var != sourceVertex) vars_set.insert(var); incoming_it ++; } EdgesList::iterator outgoing_it = outgoingEdges.begin(); EdgesList::iterator outgoing_it_end = outgoingEdges.end(); while (outgoing_it != outgoing_it_end) { Expr var = (*outgoing_it).first; if (var != sourceVertex) vars_set.insert(var); outgoing_it ++; } set::iterator set_it = vars_set.begin(); set::iterator set_it_end = vars_set.end(); while (set_it != set_it_end) { variables.push_back(*set_it); set_it ++; } } void TheoryArithOld::DifferenceLogicGraph::writeGraph(ostream& out) { return; out << "digraph G {" << endl; EdgesList::iterator incoming_it = incomingEdges.begin(); EdgesList::iterator incoming_it_end = incomingEdges.end(); while (incoming_it != incoming_it_end) { Expr var_u = (*incoming_it).first; CDList* edges = (*incoming_it).second; if (edges) for (unsigned edge_i = 0; edge_i < edges->size(); edge_i ++) { Expr var_v = (*edges)[edge_i]; out << var_u.toString() << " -> " << var_v.toString() << endl; } incoming_it ++; } out << "}" << endl; } bool TheoryArithOld::isUnconstrained(const Expr& t) { if (isPlus(t)) { for (int i = 0; i < t.arity(); ++ i) { if (isUnconstrained(t[i])) { TRACE("arith::unconstrained", "isUnconstrained(", t, ") => true (subterm)"); return true; } } } else { Expr c, var; separateMonomial(t, c, var); if (var.isRational()) { TRACE("arith::unconstrained", "isUnconstrained(", t, ") => false (rational)"); return false; } if (isMult(var)) { TRACE("arith::unconstrained", "isUnconstrained(", t, ") => false (multiplication)"); return false; } if (diffLogicOnly) { if (!diffLogicGraph.hasIncoming(var) || !diffLogicGraph.hasOutgoing(var)) { return true; } } else if (d_varConstrainedPlus.find(var) == d_varConstrainedPlus.end() || d_varConstrainedMinus.find(var) == d_varConstrainedMinus.end()) { return true; } } TRACE("arith::unconstrained", "isUnconstrained(", t, ") => false"); return false; } void TheoryArithOld::updateConstrained(const Expr& t) { TRACE("arith::unconstrained", "updateConstrained(", t, ")"); if (isIneq(t)) { updateConstrained(t[1]); } else if (isPlus(t)) { for (int i = 0; i < t.arity(); ++ i) { updateConstrained(t[i]); } } else { Expr c, var; separateMonomial(t, c, var); if (var.isRational() || isMult(var)) { return; } if (c.getRational() < 0) { d_varConstrainedMinus[var] = true; } else { d_varConstrainedPlus[var] = true; } } } cvc3-2.4.1/src/theory_arith/arith_theorem_producer.h0000664000175400017540000003273011234135021022451 0ustar mdetersmdeters/*****************************************************************************/ /*! * \file arith_theorem_producer.h * \brief TRUSTED implementation of arithmetic proof rules * * Author: Vijay Ganesh, Sergey Berezin * * Created: Dec 13 02:09:04 GMT 2002 * *
* * License to use, copy, modify, sell and/or distribute this software * and its documentation for any purpose is hereby granted without * royalty, subject to the terms and conditions defined in the \ref * LICENSE file provided with this distribution. * *
* */ /*****************************************************************************/ #ifndef _cvc3__arith_theorem_producer_h_ #define _cvc3__arith_theorem_producer_h_ #include "arith_proof_rules.h" #include "theorem_producer.h" #include "theory_arith_new.h" namespace CVC3 { class TheoryArithNew; class ArithTheoremProducer: public ArithProofRules, public TheoremProducer { TheoryArithNew* d_theoryArith; private: /*! \name Auxiliary functions for eqElimIntRule() * Methods that compute the subterms used in eqElimIntRule() *@{ */ //! Compute the special modulus: i - m*floor(i/m+1/2) Rational modEq(const Rational& i, const Rational& m); //! Create the term 't'. See eqElimIntRule(). Expr create_t(const Expr& eqn); //! Create the term 't2'. See eqElimIntRule(). Expr create_t2(const Expr& lhs, const Expr& rhs, const Expr& t); //! Create the term 't3'. See eqElimIntRule(). Expr create_t3(const Expr& lhs, const Expr& rhs, const Expr& t); /*! @brief Takes sum = a_0 + a_1*x_1+...+a_n*x_n and returns the * vector of similar monomials (in 'summands') with coefficients * mod(a_i, m). If divide flag is true, the coefficients will be * mod(a_i,m)/m. */ void sumModM(std::vector& summands, const Expr& sum, const Rational& m, const Rational& divisor); Expr monomialModM(const Expr& e, const Rational& m, const Rational& divisor); void sumMulF(std::vector& summands, const Expr& sum, const Rational& m, const Rational& divisor); Expr monomialMulF(const Expr& e, const Rational& m, const Rational& divisor); //! Compute floor(i/m+1/2) + mod(i,m) Rational f(const Rational& i, const Rational& m); Expr substitute(const Expr& term, ExprMap& eMap); /*@}*/ public: //! Constructor ArithTheoremProducer(TheoremManager* tm, TheoryArithNew* theoryArith): TheoremProducer(tm), d_theoryArith(theoryArith) { } //! Create Expr from Rational (for convenience) Expr rat(Rational r) { return d_em->newRatExpr(r); } Type realType() { return d_theoryArith->realType(); } Type intType() { return d_theoryArith->intType(); } //! Construct the dark shadow expression representing lhs <= rhs Expr darkShadow(const Expr& lhs, const Expr& rhs) { return d_theoryArith->darkShadow(lhs, rhs); } //! Construct the gray shadow expression representing c1 <= v - e <= c2 /*! Alternatively, v = e + i for some i s.t. c1 <= i <= c2 */ Expr grayShadow(const Expr& v, const Expr& e, const Rational& c1, const Rational& c2) { return d_theoryArith->grayShadow(v, e, c1, c2); } //////////////////////////////////////////////////////////////////// // Canonization rules //////////////////////////////////////////////////////////////////// // ==> x = 1 * x virtual Theorem varToMult(const Expr& e); // ==> -(e) = (-1) * e virtual Theorem uMinusToMult(const Expr& e); // ==> x - y = x + (-1) * y virtual Theorem minusToPlus(const Expr& x, const Expr& y); // Rule for unary minus: it just converts it to division by -1, virtual Theorem canonUMinusToDivide(const Expr& e); // Rules for division by constant 'd' // (c) / d ==> (c/d), takes c and d virtual Theorem canonDivideConst(const Expr& c, const Expr& d); // (c * x) / d ==> (c/d) * x, takes (c*x) and d virtual Theorem canonDivideMult(const Expr& cx, const Expr& d); // (+ c ...)/d ==> push division to all the coefficients. // The result is not canonical, but canonizing the summands will // make it canonical. // Takes (+ c ...) and d virtual Theorem canonDividePlus(const Expr& e, const Expr& d); // x / d ==> (1/d) * x, takes x and d virtual Theorem canonDivideVar(const Expr& e1, const Expr& e2); // Canon Rules for multiplication // TODO Deepak: // t1 * t2 where t1 and t2 are canonized expressions, i.e. it can be a // 1) Rational constant // 2) Arithmetic Leaf (var or term from another theory) // 3) (POW rational leaf) // 4) (MULT rational mterm'_1 ...) where each mterm' is of type (2) or (3) // 5) (PLUS rational sterm_1 sterm_2 ...) where each sterm is of // type (2) or (3) or (4) static bool greaterthan(const Expr &, const Expr &); virtual Expr simplifiedMultExpr(std::vector & mulKids); virtual Expr canonMultConstMult(const Expr & c, const Expr & e); virtual Expr canonMultConstPlus(const Expr & e1, const Expr & e2); virtual Expr canonMultPowPow(const Expr & e1, const Expr & e2); virtual Expr canonMultPowLeaf(const Expr & e1, const Expr & e2); virtual Expr canonMultLeafLeaf(const Expr & e1, const Expr & e2); virtual Expr canonMultLeafOrPowMult(const Expr & e1, const Expr & e2); virtual Expr canonCombineLikeTerms(const std::vector & sumExprs); virtual Expr canonMultLeafOrPowOrMultPlus(const Expr & e1, const Expr & e2); virtual Expr canonMultPlusPlus(const Expr & e1, const Expr & e2); virtual Theorem canonMultMtermMterm(const Expr& e); virtual Theorem canonPlus(const Expr & e); virtual Theorem canonInvertConst(const Expr & e); virtual Theorem canonInvertLeaf(const Expr & e); virtual Theorem canonInvertPow(const Expr & e); virtual Theorem canonInvertMult(const Expr & e); virtual Theorem canonInvert(const Expr & e); /** * Transform e = (SUM r t1 ... tn) @ 0 into (SUM t1 ... tn) @ -r. The first * sum term (r) must be a rational and t1 ... tn terms must be canonised. * * @param e the expression to transform * @return rewrite theorem representing the transformation */ virtual Theorem moveSumConstantRight(const Expr& e); /** e[0]/e[1] ==> e[0]*(e[1])^-1 */ virtual Theorem canonDivide(const Expr & e); /** Multiply out the operands of the multiplication (each of them is expected to be canonised */ virtual Theorem canonMult(const Expr & e); // t*c ==> c*t, takes constant c and term t virtual Theorem canonMultTermConst(const Expr& c, const Expr& t); // t1*t2 ==> Error, takes t1 and t2 where both are non-constants virtual Theorem canonMultTerm1Term2(const Expr& t1, const Expr& t2); // 0*t ==> 0, takes 0*t virtual Theorem canonMultZero(const Expr& e); // 1*t ==> t, takes 1*t virtual Theorem canonMultOne(const Expr& e); // c1*c2 ==> c', takes constant c1*c2 virtual Theorem canonMultConstConst(const Expr& c1, const Expr& c2); // c1*(c2*t) ==> c'*t, takes c1 and c2 and t virtual Theorem canonMultConstTerm(const Expr& c1, const Expr& c2, const Expr&t); // c1*(+ c2 v1 ...) ==> (+ c' c1v1 ...), takes c1 and the sum virtual Theorem canonMultConstSum(const Expr& c1, const Expr& sum); // c^n = c' (compute the constant power expression) virtual Theorem canonPowConst(const Expr& pow); // Rules for addition // flattens the input. accepts a PLUS expr virtual Theorem canonFlattenSum(const Expr& e); // Rules for addition // combine like terms. accepts a flattened PLUS expr virtual Theorem canonComboLikeTerms(const Expr& e); // 0 = (* e1 e2 ...) <=> 0 = e1 OR 0 = e2 OR ... virtual Theorem multEqZero(const Expr& expr); // 0 = (^ c x) <=> false if c <=0 // <=> 0 = x if c > 0 virtual Theorem powEqZero(const Expr& expr); // x^n = y^n <=> x = y (if n is odd) // x^n = y^n <=> x = y OR x = -y (if n is even) virtual Theorem elimPower(const Expr& expr); // x^n = c <=> x = root (if n is odd and root^n = c) // x^n = c <=> x = root OR x = -root (if n is even and root^n = c) virtual Theorem elimPowerConst(const Expr& expr, const Rational& root); // x^n = c <=> false (if n is even and c is negative) virtual Theorem evenPowerEqNegConst(const Expr& expr); // x^n = c <=> false (if x is an integer and c is not a perfect n power) virtual Theorem intEqIrrational(const Expr& expr, const Theorem& isInt); // e[0] kind e[1] <==> true when e[0] kind e[1], // false when e[0] !kind e[1], for constants only virtual Theorem constPredicate(const Expr& e); // e[0] kind e[1] <==> 0 kind e[1] - e[0] virtual Theorem rightMinusLeft(const Expr& e); // e[0] kind e[1] <==> e[0] - e[1] kind 0 virtual Theorem leftMinusRight(const Expr& e); // x kind y <==> x + z kind y + z virtual Theorem plusPredicate(const Expr& x, const Expr& y, const Expr& z, int kind); // x = y <==> x * z = y * z virtual Theorem multEqn(const Expr& x, const Expr& y, const Expr& z); // x = y <==> z=0 OR x * 1/z = y * 1/z virtual Theorem divideEqnNonConst(const Expr& x, const Expr& y, const Expr& z); // if z is +ve, return e[0] LT|LE|GT|GE e[1] <==> e[0]*z LT|LE|GT|GE e[1]*z // if z is -ve, return e[0] LT|LE|GT|GE e[1] <==> e[1]*z LT|LE|GT|GE e[0]*z virtual Theorem multIneqn(const Expr& e, const Expr& z); // x = y ==> x <= y and x >= y virtual Theorem eqToIneq(const Expr& e); // "op1 GE|GT op2" <==> op2 LE|LT op1 virtual Theorem flipInequality(const Expr& e); // NOT (op1 LT op2) <==> (op1 GE op2) // NOT (op1 LE op2) <==> (op1 GT op2) // NOT (op1 GT op2) <==> (op1 LE op2) // NOT (op1 GE op2) <==> (op1 LT op2) Theorem negatedInequality(const Expr& e); Theorem realShadow(const Theorem& alphaLTt, const Theorem& tLTbeta); Theorem realShadowEq(const Theorem& alphaLEt, const Theorem& tLEalpha); Theorem finiteInterval(const Theorem& aLEt, const Theorem& tLEac, const Theorem& isInta, const Theorem& isIntt); Theorem darkGrayShadow2ab(const Theorem& betaLEbx, const Theorem& axLEalpha, const Theorem& isIntAlpha, const Theorem& isIntBeta, const Theorem& isIntx); Theorem darkGrayShadow2ba(const Theorem& betaLEbx, const Theorem& axLEalpha, const Theorem& isIntAlpha, const Theorem& isIntBeta, const Theorem& isIntx); Theorem expandDarkShadow(const Theorem& darkShadow); Theorem expandGrayShadow0(const Theorem& grayShadow); Theorem splitGrayShadow(const Theorem& grayShadow); Theorem splitGrayShadowSmall(const Theorem& grayShadow); Theorem expandGrayShadow(const Theorem& grayShadow); Theorem expandGrayShadowConst(const Theorem& grayShadow); Theorem grayShadowConst(const Theorem& g); //! Implements j(c,b,a) /*! accepts 3 integers a,b,c and returns * (b > 0)? (c+b) mod a : (a - (c+b)) mod a */ Rational constRHSGrayShadow(const Rational& c, const Rational& b, const Rational& a); Theorem lessThanToLE(const Theorem& less, const Theorem& isIntLHS, const Theorem& isIntRHS, bool changeRight); Theorem lessThanToLERewrite(const Expr& ineq, const Theorem& isIntLHS, const Theorem& isIntRHS, bool changeRight); Theorem intVarEqnConst(const Expr& eqn, const Theorem& isIntx); Theorem IsIntegerElim(const Theorem& isIntx); Theorem eqElimIntRule(const Theorem& eqn, const Theorem& isIntx, const std::vector& isIntVars); Theorem isIntConst(const Expr& e); Theorem equalLeaves1(const Theorem& e); Theorem equalLeaves2(const Theorem& e); Theorem equalLeaves3(const Theorem& e); Theorem equalLeaves4(const Theorem& e); Theorem diseqToIneq(const Theorem& diseq); Theorem dummyTheorem(const Expr& e); Theorem oneElimination(const Expr& x); Theorem clashingBounds(const Theorem& lowerBound, const Theorem& upperBound); Theorem addInequalities(const Theorem& thm1, const Theorem& thm2); Theorem addInequalities(const std::vector& thms); Theorem implyWeakerInequality(const Expr& expr1, const Expr& expr2); Theorem implyNegatedInequality(const Expr& expr1, const Expr& expr2); Theorem integerSplit(const Expr& intVar, const Rational& intPoint); Theorem trustedRewrite(const Expr& expr1, const Expr& expr2); Theorem rafineStrictInteger(const Theorem& isIntConstrThm, const Expr& constr); Theorem simpleIneqInt(const Expr& ineq, const Theorem& isIntRHS); Theorem intEqualityRationalConstant(const Theorem& isIntConstrThm, const Expr& constr); Theorem cycleConflict(const std::vector& inequalitites); Theorem implyEqualities(const std::vector& inequalities); Theorem implyWeakerInequalityDiffLogic(const std::vector& antecedentThms, const Expr& implied); Theorem implyNegatedInequalityDiffLogic(const std::vector& antecedentThms, const Expr& implied); Theorem expandGrayShadowRewrite(const Expr& theShadow); Theorem compactNonLinearTerm(const Expr& nonLinear); Theorem nonLinearIneqSignSplit(const Theorem& ineqThm); Theorem implyDiffLogicBothBounds(const Expr& x, std::vector& c1_le_x, Rational c1, std::vector& x_le_c2, Rational c2); Theorem powerOfOne(const Expr& e); }; // end of class ArithTheoremProducer } // end of namespace CVC3 #endif cvc3-2.4.1/src/theory_arith/arith_theorem_producer3.h0000664000175400017540000003272011203160611022532 0ustar mdetersmdeters/*****************************************************************************/ /*! * \file arith_theorem_producer3.h * \brief TRUSTED implementation of arithmetic proof rules * * Author: Vijay Ganesh, Sergey Berezin * * Created: Dec 13 02:09:04 GMT 2002 * *
* * License to use, copy, modify, sell and/or distribute this software * and its documentation for any purpose is hereby granted without * royalty, subject to the terms and conditions defined in the \ref * LICENSE file provided with this distribution. * *
* */ /*****************************************************************************/ #ifndef _cvc3__arith_theorem_producer3_h_ #define _cvc3__arith_theorem_producer3_h_ #include "arith_proof_rules.h" #include "theorem_producer.h" #include "theory_arith3.h" namespace CVC3 { class TheoryArith3; class ArithTheoremProducer3: public ArithProofRules, public TheoremProducer { TheoryArith3* d_theoryArith; private: /*! \name Auxiliary functions for eqElimIntRule() * Methods that compute the subterms used in eqElimIntRule() *@{ */ //! Compute the special modulus: i - m*floor(i/m+1/2) Rational modEq(const Rational& i, const Rational& m); //! Create the term 't'. See eqElimIntRule(). Expr create_t(const Expr& eqn); //! Create the term 't2'. See eqElimIntRule(). Expr create_t2(const Expr& lhs, const Expr& rhs, const Expr& t); //! Create the term 't3'. See eqElimIntRule(). Expr create_t3(const Expr& lhs, const Expr& rhs, const Expr& t); /*! @brief Takes sum = a_0 + a_1*x_1+...+a_n*x_n and returns the * vector of similar monomials (in 'summands') with coefficients * mod(a_i, m). If divide flag is true, the coefficients will be * mod(a_i,m)/m. */ void sumModM(std::vector& summands, const Expr& sum, const Rational& m, const Rational& divisor); Expr monomialModM(const Expr& e, const Rational& m, const Rational& divisor); void sumMulF(std::vector& summands, const Expr& sum, const Rational& m, const Rational& divisor); Expr monomialMulF(const Expr& e, const Rational& m, const Rational& divisor); //! Compute floor(i/m+1/2) + mod(i,m) Rational f(const Rational& i, const Rational& m); Expr substitute(const Expr& term, ExprMap& eMap); /*@}*/ public: //! Constructor ArithTheoremProducer3(TheoremManager* tm, TheoryArith3* theoryArith): TheoremProducer(tm), d_theoryArith(theoryArith) { } //! Create Expr from Rational (for convenience) Expr rat(Rational r) { return d_em->newRatExpr(r); } Type realType() { return d_theoryArith->realType(); } Type intType() { return d_theoryArith->intType(); } //! Construct the dark shadow expression representing lhs <= rhs Expr darkShadow(const Expr& lhs, const Expr& rhs) { return d_theoryArith->darkShadow(lhs, rhs); } //! Construct the gray shadow expression representing c1 <= v - e <= c2 /*! Alternatively, v = e + i for some i s.t. c1 <= i <= c2 */ Expr grayShadow(const Expr& v, const Expr& e, const Rational& c1, const Rational& c2) { return d_theoryArith->grayShadow(v, e, c1, c2); } //////////////////////////////////////////////////////////////////// // Canonization rules //////////////////////////////////////////////////////////////////// // ==> x = 1 * x virtual Theorem varToMult(const Expr& e); // ==> -(e) = (-1) * e virtual Theorem uMinusToMult(const Expr& e); // ==> x - y = x + (-1) * y virtual Theorem minusToPlus(const Expr& x, const Expr& y); // Rule for unary minus: it just converts it to division by -1, virtual Theorem canonUMinusToDivide(const Expr& e); // Rules for division by constant 'd' // (c) / d ==> (c/d), takes c and d virtual Theorem canonDivideConst(const Expr& c, const Expr& d); // (c * x) / d ==> (c/d) * x, takes (c*x) and d virtual Theorem canonDivideMult(const Expr& cx, const Expr& d); // (+ c ...)/d ==> push division to all the coefficients. // The result is not canonical, but canonizing the summands will // make it canonical. // Takes (+ c ...) and d virtual Theorem canonDividePlus(const Expr& e, const Expr& d); // x / d ==> (1/d) * x, takes x and d virtual Theorem canonDivideVar(const Expr& e1, const Expr& e2); // Canon Rules for multiplication // TODO Deepak: // t1 * t2 where t1 and t2 are canonized expressions, i.e. it can be a // 1) Rational constant // 2) Arithmetic Leaf (var or term from another theory) // 3) (POW rational leaf) // 4) (MULT rational mterm'_1 ...) where each mterm' is of type (2) or (3) // 5) (PLUS rational sterm_1 sterm_2 ...) where each sterm is of // type (2) or (3) or (4) static bool greaterthan(const Expr &, const Expr &); virtual Expr simplifiedMultExpr(std::vector & mulKids); virtual Expr canonMultConstMult(const Expr & c, const Expr & e); virtual Expr canonMultConstPlus(const Expr & e1, const Expr & e2); virtual Expr canonMultPowPow(const Expr & e1, const Expr & e2); virtual Expr canonMultPowLeaf(const Expr & e1, const Expr & e2); virtual Expr canonMultLeafLeaf(const Expr & e1, const Expr & e2); virtual Expr canonMultLeafOrPowMult(const Expr & e1, const Expr & e2); virtual Expr canonCombineLikeTerms(const std::vector & sumExprs); virtual Expr canonMultLeafOrPowOrMultPlus(const Expr & e1, const Expr & e2); virtual Expr canonMultPlusPlus(const Expr & e1, const Expr & e2); virtual Theorem canonMultMtermMterm(const Expr& e); virtual Theorem canonPlus(const Expr & e); virtual Theorem canonInvertConst(const Expr & e); virtual Theorem canonInvertLeaf(const Expr & e); virtual Theorem canonInvertPow(const Expr & e); virtual Theorem canonInvertMult(const Expr & e); virtual Theorem canonInvert(const Expr & e); /** * Transform e = (SUM r t1 ... tn) @ 0 into (SUM t1 ... tn) @ -r. The first * sum term (r) must be a rational and t1 ... tn terms must be canonised. * * @param e the expression to transform * @return rewrite theorem representing the transformation */ virtual Theorem moveSumConstantRight(const Expr& e); /** e[0]/e[1] ==> e[0]*(e[1])^-1 */ virtual Theorem canonDivide(const Expr & e); /** Multiply out the operands of the multiplication (each of them is expected to be canonised */ virtual Theorem canonMult(const Expr & e); // t*c ==> c*t, takes constant c and term t virtual Theorem canonMultTermConst(const Expr& c, const Expr& t); // t1*t2 ==> Error, takes t1 and t2 where both are non-constants virtual Theorem canonMultTerm1Term2(const Expr& t1, const Expr& t2); // 0*t ==> 0, takes 0*t virtual Theorem canonMultZero(const Expr& e); // 1*t ==> t, takes 1*t virtual Theorem canonMultOne(const Expr& e); // c1*c2 ==> c', takes constant c1*c2 virtual Theorem canonMultConstConst(const Expr& c1, const Expr& c2); // c1*(c2*t) ==> c'*t, takes c1 and c2 and t virtual Theorem canonMultConstTerm(const Expr& c1, const Expr& c2, const Expr&t); // c1*(+ c2 v1 ...) ==> (+ c' c1v1 ...), takes c1 and the sum virtual Theorem canonMultConstSum(const Expr& c1, const Expr& sum); // c^n = c' (compute the constant power expression) virtual Theorem canonPowConst(const Expr& pow); // Rules for addition // flattens the input. accepts a PLUS expr virtual Theorem canonFlattenSum(const Expr& e); // Rules for addition // combine like terms. accepts a flattened PLUS expr virtual Theorem canonComboLikeTerms(const Expr& e); // 0 = (* e1 e2 ...) <=> 0 = e1 OR 0 = e2 OR ... virtual Theorem multEqZero(const Expr& expr); // 0 = (^ c x) <=> false if c <=0 // <=> 0 = x if c > 0 virtual Theorem powEqZero(const Expr& expr); // x^n = y^n <=> x = y (if n is odd) // x^n = y^n <=> x = y OR x = -y (if n is even) virtual Theorem elimPower(const Expr& expr); // x^n = c <=> x = root (if n is odd and root^n = c) // x^n = c <=> x = root OR x = -root (if n is even and root^n = c) virtual Theorem elimPowerConst(const Expr& expr, const Rational& root); // x^n = c <=> false (if n is even and c is negative) virtual Theorem evenPowerEqNegConst(const Expr& expr); // x^n = c <=> false (if x is an integer and c is not a perfect n power) virtual Theorem intEqIrrational(const Expr& expr, const Theorem& isInt); // e[0] kind e[1] <==> true when e[0] kind e[1], // false when e[0] !kind e[1], for constants only virtual Theorem constPredicate(const Expr& e); // e[0] kind e[1] <==> 0 kind e[1] - e[0] virtual Theorem rightMinusLeft(const Expr& e); // e[0] kind e[1] <==> e[0] - e[1] kind 0 virtual Theorem leftMinusRight(const Expr& e); // x kind y <==> x + z kind y + z virtual Theorem plusPredicate(const Expr& x, const Expr& y, const Expr& z, int kind); // x = y <==> x * z = y * z virtual Theorem multEqn(const Expr& x, const Expr& y, const Expr& z); // x = y <==> z=0 OR x * 1/z = y * 1/z virtual Theorem divideEqnNonConst(const Expr& x, const Expr& y, const Expr& z); // if z is +ve, return e[0] LT|LE|GT|GE e[1] <==> e[0]*z LT|LE|GT|GE e[1]*z // if z is -ve, return e[0] LT|LE|GT|GE e[1] <==> e[1]*z LT|LE|GT|GE e[0]*z virtual Theorem multIneqn(const Expr& e, const Expr& z); // x = y ==> x <= y and x >= y virtual Theorem eqToIneq(const Expr& e); // "op1 GE|GT op2" <==> op2 LE|LT op1 virtual Theorem flipInequality(const Expr& e); // NOT (op1 LT op2) <==> (op1 GE op2) // NOT (op1 LE op2) <==> (op1 GT op2) // NOT (op1 GT op2) <==> (op1 LE op2) // NOT (op1 GE op2) <==> (op1 LT op2) Theorem negatedInequality(const Expr& e); Theorem realShadow(const Theorem& alphaLTt, const Theorem& tLTbeta); Theorem realShadowEq(const Theorem& alphaLEt, const Theorem& tLEalpha); Theorem finiteInterval(const Theorem& aLEt, const Theorem& tLEac, const Theorem& isInta, const Theorem& isIntt); Theorem darkGrayShadow2ab(const Theorem& betaLEbx, const Theorem& axLEalpha, const Theorem& isIntAlpha, const Theorem& isIntBeta, const Theorem& isIntx); Theorem darkGrayShadow2ba(const Theorem& betaLEbx, const Theorem& axLEalpha, const Theorem& isIntAlpha, const Theorem& isIntBeta, const Theorem& isIntx); Theorem expandDarkShadow(const Theorem& darkShadow); Theorem expandGrayShadow0(const Theorem& grayShadow); Theorem splitGrayShadow(const Theorem& grayShadow); Theorem splitGrayShadowSmall(const Theorem& grayShadow); Theorem expandGrayShadow(const Theorem& grayShadow); Theorem expandGrayShadowConst(const Theorem& grayShadow); Theorem grayShadowConst(const Theorem& g); //! Implements j(c,b,a) /*! accepts 3 integers a,b,c and returns * (b > 0)? (c+b) mod a : (a - (c+b)) mod a */ Rational constRHSGrayShadow(const Rational& c, const Rational& b, const Rational& a); Theorem lessThanToLE(const Theorem& less, const Theorem& isIntLHS, const Theorem& isIntRHS, bool changeRight); Theorem lessThanToLERewrite(const Expr& ineq, const Theorem& isIntLHS, const Theorem& isIntRHS, bool changeRight); Theorem intVarEqnConst(const Expr& eqn, const Theorem& isIntx); Theorem IsIntegerElim(const Theorem& isIntx); Theorem eqElimIntRule(const Theorem& eqn, const Theorem& isIntx, const std::vector& isIntVars); Theorem isIntConst(const Expr& e); Theorem equalLeaves1(const Theorem& e); Theorem equalLeaves2(const Theorem& e); Theorem equalLeaves3(const Theorem& e); Theorem equalLeaves4(const Theorem& e); Theorem diseqToIneq(const Theorem& diseq); Theorem dummyTheorem(const Expr& e); Theorem oneElimination(const Expr& x); Theorem clashingBounds(const Theorem& lowerBound, const Theorem& upperBound); Theorem addInequalities(const Theorem& thm1, const Theorem& thm2); Theorem addInequalities(const std::vector& thms); Theorem implyWeakerInequality(const Expr& expr1, const Expr& expr2); Theorem implyNegatedInequality(const Expr& expr1, const Expr& expr2); Theorem integerSplit(const Expr& intVar, const Rational& intPoint); Theorem trustedRewrite(const Expr& expr1, const Expr& expr2); Theorem rafineStrictInteger(const Theorem& isIntConstrThm, const Expr& constr); Theorem simpleIneqInt(const Expr& ineq, const Theorem& isIntRHS); Theorem intEqualityRationalConstant(const Theorem& isIntConstrThm, const Expr& constr); Theorem cycleConflict(const std::vector& inequalitites); Theorem implyEqualities(const std::vector& inequalities); Theorem implyWeakerInequalityDiffLogic(const std::vector& antecedentThms, const Expr& implied); Theorem implyNegatedInequalityDiffLogic(const std::vector& antecedentThms, const Expr& implied); Theorem expandGrayShadowRewrite(const Expr& theShadow); Theorem compactNonLinearTerm(const Expr& nonLinear); Theorem nonLinearIneqSignSplit(const Theorem& ineqThm); Theorem implyDiffLogicBothBounds(const Expr& x, std::vector& c1_le_x, Rational c1, std::vector& x_le_c2, Rational c2); Theorem powerOfOne(const Expr& e); }; // end of class ArithTheoremProducer3 } // end of namespace CVC3 #endif cvc3-2.4.1/src/theory_arith/arith_proof_rules.h0000664000175400017540000004304111234135021021437 0ustar mdetersmdeters/*****************************************************************************/ /*! * \file arith_proof_rules.h * \brief Arithmetic proof rules * * Author: Vijay Ganesh, Sergey Berezin * * Created: Dec 13 02:09:04 GMT 2002 * *
* * License to use, copy, modify, sell and/or distribute this software * and its documentation for any purpose is hereby granted without * royalty, subject to the terms and conditions defined in the \ref * LICENSE file provided with this distribution. * *
* */ /*****************************************************************************/ #ifndef _cvc3__arith_proof_rules_h_ #define _cvc3__arith_proof_rules_h_ #include namespace CVC3 { class Theorem; class Expr; class Rational; class ArithProofRules { public: // Destructor virtual ~ArithProofRules() { } //////////////////////////////////////////////////////////////////// // Canonization rules //////////////////////////////////////////////////////////////////// //! ==> e = 1 * e virtual Theorem varToMult(const Expr& e) = 0; //! ==> -(e) = (-1) * e virtual Theorem uMinusToMult(const Expr& e) = 0; //! ==> x - y = x + (-1) * y virtual Theorem minusToPlus(const Expr& x, const Expr& y) = 0; //! -(e) ==> e / (-1); takes 'e' /*! Canon Rule for unary minus: it just converts it to division by * -1, the result is not yet canonical: */ virtual Theorem canonUMinusToDivide(const Expr& e) = 0; /** * Transform e = (SUM r t1 ... tn) @ 0 into (SUM t1 ... tn) @ -r. The first * sum term (r) must be a rational and t1 ... tn terms must be canonised. * * @param e the expression to transform * @return rewrite theorem representing the transformation */ virtual Theorem moveSumConstantRight(const Expr& e) = 0; //! (c) / d ==> (c/d), takes c and d /*! Canon Rules for division by constant 'd' */ virtual Theorem canonDivideConst(const Expr& c, const Expr& d) = 0; //! (c * x) / d ==> (c/d) * x, takes (c*x) and d virtual Theorem canonDivideMult(const Expr& cx, const Expr& d) = 0; //! (+ c ...)/d ==> push division to all the coefficients. /*! The result is not canonical, but canonizing the summands will * make it canonical. * Takes (+ c ...) and d */ virtual Theorem canonDividePlus(const Expr& e, const Expr& d) = 0; //! x / d ==> (1/d) * x, takes x and d virtual Theorem canonDivideVar(const Expr& e, const Expr& d) = 0; // Canon Rules for multiplication // TODO Deepak: // e == t1 * t2 where t1 and t2 are canonized expressions, i.e. it can be a // 1) Rational constant // 2) Arithmetic Leaf (var or term from another theory) // 3) (POW rational leaf) // 4) (MULT rational mterm'_1 ...) where each mterm' is of type (2) or (3) // 5) (PLUS rational sterm_1 sterm_2 ...) where each sterm is of // type (2) or (3) or (4) virtual Theorem canonMultMtermMterm(const Expr& e) = 0; //! Canonize (PLUS t1 ... tn) virtual Theorem canonPlus(const Expr & e) = 0; //! Canonize (MULT t1 ... tn) virtual Theorem canonMult(const Expr & e) = 0; //! ==> 1/e = e' where e' is canonical; takes e. virtual Theorem canonInvert(const Expr & e) = 0; //! Canonize t1/t2 virtual Theorem canonDivide(const Expr & e) = 0; //! t*c ==> c*t, takes constant c and term t virtual Theorem canonMultTermConst(const Expr& c, const Expr& t) = 0; //! t1*t2 ==> Error, takes t1 and t2 where both are non-constants virtual Theorem canonMultTerm1Term2(const Expr& t1, const Expr& t2) = 0; //! 0*t ==> 0, takes 0*t virtual Theorem canonMultZero(const Expr& e) = 0; //! 1*t ==> t, takes 1*t virtual Theorem canonMultOne(const Expr& e) = 0; //! c1*c2 ==> c', takes constant c1*c2 virtual Theorem canonMultConstConst(const Expr& c1, const Expr& c2) = 0; //! c1*(c2*t) ==> c'*t, takes c1 and c2 and t virtual Theorem canonMultConstTerm(const Expr& c1, const Expr& c2, const Expr&t) = 0; //! c1*(+ c2 v1 ...) ==> (+ c' c1v1 ...), takes c1 and the sum virtual Theorem canonMultConstSum(const Expr& c1, const Expr& sum) = 0; //! c^n = c' (compute the constant power expression) virtual Theorem canonPowConst(const Expr& pow) = 0; // Rules for addition //! flattens the input. accepts a PLUS expr virtual Theorem canonFlattenSum(const Expr& e) = 0; //! combine like terms. accepts a flattened PLUS expr virtual Theorem canonComboLikeTerms(const Expr& e) = 0; // 0 = (* e1 e2 ...) <=> 0 = e1 OR 0 = e2 OR ... virtual Theorem multEqZero(const Expr& expr) = 0; // 0 = (^ c x) <=> false if c <=0 // <=> 0 = x if c > 0 virtual Theorem powEqZero(const Expr& expr) = 0; // x^n = y^n <=> x = y (if n is odd) // x^n = y^n <=> x = y OR x = -y (if n is even) virtual Theorem elimPower(const Expr& expr) = 0; // x^n = c <=> x = root (if n is odd and root^n = c) // x^n = c <=> x = root OR x = -root (if n is even and root^n = c) virtual Theorem elimPowerConst(const Expr& expr, const Rational& root) = 0; // x^n = c <=> false (if n is even and c is negative) virtual Theorem evenPowerEqNegConst(const Expr& expr) = 0; // x^n = c <=> false (if x is an integer and c is not a perfect n power) virtual Theorem intEqIrrational(const Expr& expr, const Theorem& isInt) = 0; //! e0 \@ e1 <==> true | false, where \@ is {=,<,<=,>,>=} /*! \param e takes e is (e0\@e1) where e0 and e1 are constants */ virtual Theorem constPredicate(const Expr& e) = 0; //! e[0] @ e[1] <==> 0 @ e[1] - e[0], where @ is {=,<,<=,>,>=} virtual Theorem rightMinusLeft(const Expr& e) = 0; //! e[0] @ e[1] <==> e[0] - e[1] @ 0, where @ is {=,<,<=,>,>=} virtual Theorem leftMinusRight(const Expr& e) = 0; //! x @ y <==> x + z @ y + z, where @ is {=,<,<=,>,>=} (given as 'kind') virtual Theorem plusPredicate(const Expr& x, const Expr& y, const Expr& z, int kind) = 0; //! x = y <==> x * z = y * z, where z is a non-zero constant virtual Theorem multEqn(const Expr& x, const Expr& y, const Expr& z) = 0; // x = y <==> z=0 OR x * 1/z = y * 1/z virtual Theorem divideEqnNonConst(const Expr& x, const Expr& y, const Expr& z) = 0; //! Multiplying inequation by a non-zero constant /*! * z>0 ==> e[0] @ e[1] <==> e[0]*z @ e[1]*z * * z<0 ==> e[0] @ e[1] <==> e[1]*z @ e[0]*z * * for @ in {<,<=,>,>=}: */ virtual Theorem multIneqn(const Expr& e, const Expr& z) = 0; //! x = y ==> x <= y and x >= y virtual Theorem eqToIneq(const Expr& e) = 0; //! "op1 GE|GT op2" <==> op2 LE|LT op1 virtual Theorem flipInequality(const Expr& e) = 0; //! Propagating negation over <,<=,>,>= /*! NOT (op1 < op2) <==> (op1 >= op2) * * NOT (op1 <= op2) <==> (op1 > op2) * * NOT (op1 > op2) <==> (op1 <= op2) * * NOT (op1 >= op2) <==> (op1 < op2) */ virtual Theorem negatedInequality(const Expr& e) = 0; //! Real shadow: a <(=) t, t <(=) b ==> a <(=) b virtual Theorem realShadow(const Theorem& alphaLTt, const Theorem& tLTbeta) = 0; //! Projecting a tight inequality: alpha <= t <= alpha ==> t = alpha virtual Theorem realShadowEq(const Theorem& alphaLEt, const Theorem& tLEalpha) = 0; //! Finite interval for integers: a <= t <= a + c ==> G(t, a, 0, c) virtual Theorem finiteInterval(const Theorem& aLEt, const Theorem& tLEac, const Theorem& isInta, const Theorem& isIntt) = 0; //! Dark & Gray shadows when a <= b /*! takes two integer ineqs (i.e. all vars are ints) * "|- beta <= b.x" and "|- a.x <= alpha" and checks if "1 <= a <= b" * and returns (D or G) and (!D or !G), where * D = Dark_Shadow(ab-1, b.alpha - a.beta), * G = Gray_Shadow(a.x, alpha, -(a-1), 0). */ virtual Theorem darkGrayShadow2ab(const Theorem& betaLEbx, const Theorem& axLEalpha, const Theorem& isIntAlpha, const Theorem& isIntBeta, const Theorem& isIntx)=0; //! Dark & Gray shadows when b <= a /*! takes two integer ineqs (i.e. all vars are ints) * "|- beta <= b.x" and "|- a.x <= alpha" and checks if "1 <= b < a" * and returns (D or G) and (!D or !G), where * D = Dark_Shadow(ab-1, b.alpha - a.beta), * G = Gray_Shadow(b.x, beta, 0, b-1). */ virtual Theorem darkGrayShadow2ba(const Theorem& betaLEbx, const Theorem& axLEalpha, const Theorem& isIntAlpha, const Theorem& isIntBeta, const Theorem& isIntx)=0; //! DARK_SHADOW(t1, t2) ==> t1 <= t2 virtual Theorem expandDarkShadow(const Theorem& darkShadow)=0; //! GRAY_SHADOW(v, e, c, c) ==> v=e+c. virtual Theorem expandGrayShadow0(const Theorem& g)=0; // [used to be] GRAY_SHADOW(t1, t2, i) ==> t1 = t2+i OR // GRAY_SHADOW(t1, t2, i+/-1) //! G(x, e, c1, c2) ==> (G1 or G2) and (!G1 or !G2) /*! Here G1 = G(x,e,c1,c), * G2 = G(x,e,c+1,c2), * and c = floor((c1+c2)/2). */ virtual Theorem splitGrayShadow(const Theorem& g)=0; virtual Theorem splitGrayShadowSmall(const Theorem& g)=0; //! G(x, e, c1, c2) ==> e+c1 <= x AND x <= e+c2 virtual Theorem expandGrayShadow(const Theorem& g)=0; //! Optimized rules: GRAY_SHADOW(a*x, c, c1, c2) ==> [expansion] /*! Implements three versions of the rule: * * \f[\frac{\mathrm{GRAY\_SHADOW}(ax,c,c1,c2)} * {ax = c + i - \mathrm{sign}(i)\cdot j(c,i,a) * \lor GRAY\_SHADOW(ax, c, i-\mathrm{sign}(i)\cdot (a+j(c,i,a)))}\f] * * where the conclusion may become FALSE or without the * GRAY_SHADOW part, depending on the values of a, c and i. */ virtual Theorem expandGrayShadowConst(const Theorem& g)=0; //! |- G(ax, c, c1, c2) ==> |- G(x, 0, ceil((c1+c)/a), floor((c2+c)/a)) /*! In the case the new c1 > c2, return |- FALSE */ virtual Theorem grayShadowConst(const Theorem& g)=0; //! a,b: INT; a < b ==> a <= b-1 [or a+1 <= b] /*! Takes a Theorem(\\alpha < \\beta) and returns * Theorem(\\alpha < \\beta <==> \\alpha <= \\beta -1) * or Theorem(\\alpha < \\beta <==> \\alpha + 1 <= \\beta), * depending on which side must be changed (changeRight flag) */ virtual Theorem lessThanToLE(const Theorem& less, const Theorem& isIntLHS, const Theorem& isIntRHS, bool changeRight)=0; virtual Theorem lessThanToLERewrite(const Expr& ineq, const Theorem& isIntLHS, const Theorem& isIntRHS, bool changeRight) = 0; /*! \param eqn is an equation 0 = a.x or 0 = c + a.x, where x is integer * \param isIntx is a proof of IS_INTEGER(x) * * \return the theorem 0 = c + a.x <==> x=-c/a if -c/a is int else * return the theorem 0 = c + a.x <==> false. * * It also handles the special case of 0 = a.x <==> x = 0 */ virtual Theorem intVarEqnConst(const Expr& eqn, const Theorem& isIntx) = 0; /*! IS_INTEGER(x) <=> EXISTS (y : INT) y = x * where x is not already known to be an integer. */ virtual Theorem IsIntegerElim(const Theorem& isIntx) = 0; /*! @brief Equality elimination rule for integers: * \f[\frac{\mathsf{int}(a\cdot x)\quad * \mathsf{int}(C+\sum_{i=1}^{n}a_{i}\cdot x_{i})} * {a\cdot x=C+\sum_{i=1}^{n}a_{i}\cdot x_{i} * \quad\equiv\quad x=t_{2}\wedge 0=t_{3}} * \f] * See the detailed description for explanations. * * This rule implements a step in the iterative algorithm for * eliminating integer equality. The terms in the rule are * defined as follows: * * \f[\begin{array}{rcl} * t_{2} & = & * -(C\ \mathbf{mod}\ m+\sum_{i=1}^{n}(a_{i}\ \mathbf{mod}\ m) * \cdot x_{i}-m\cdot\sigma(t))\\ & & \\ * t_{3} & = & * \mathbf{f}(C,m)+\sum_{i=1}^{n}\mathbf{f}(a_{i},m)\cdot x_{i} * -a\cdot\sigma(t)\\ & & \\ * t & = & * (C\ \mathbf{mod}\ m+\sum_{i=1}^{n}(a_{i}\ \mathbf{mod}\ m) * \cdot x_{i}+x)/m\\ & & \\ * m & = & a+1\\ & & \\ * \mathbf{f}(i,m) & = & \left\lfloor \frac{i}{m} * +\frac{1}{2}\right\rfloor +i\ \mathbf{mod}\ m\\ & & \\ * i\ \mathbf{mod}\ m & = & i-m\left\lfloor\frac{i}{m} * +\frac{1}{2}\right\rfloor * \end{array} * \f] * * All the variables and coefficients are integer, and a >= 2. * * \param eqn is the equation * \f[a\cdot x = C + \sum_{i=1}^n a_i\cdot x_i.\f] * */ /* virtual Theorem eqElimIntRule(const Expr& eqn, const Theorem& isIntLHS, const Theorem& isIntRHS) = 0; //! a <=> b ==> c AND a <=> c AND b. Takes "a <=> b" and "c". virtual Theorem cANDaIffcANDb(const Theorem& thm, const Expr& solvedEq) = 0; virtual Theorem substSolvedFormRule(const Expr& e1, ExprMap& eMap) = 0; virtual Theorem aANDcIffbANDc(const Theorem& thm, const Expr& newEq) = 0; */ /////////////////////////////////////////////////////////////////////// // Alternative implementation of integer equality elimination /////////////////////////////////////////////////////////////////////// /*! @brief * \f[\frac{\Gamma\models ax=t\quad * \Gamma'\models\mathsf{int}(x)\quad * \{\Gamma_i\models\mathsf{int}(x_i) | x_i\mbox{ is var in }t\}} * {\Gamma,\Gamma',\bigcup_i\Gamma_i\models * \exists (y:\mathrm{int}).\ x=t_2(y)\wedge 0=t_3(y)} * \f] * See detailed docs for more information. * * This rule implements a step in the iterative algorithm for * eliminating integer equality. The terms in the rule are * defined as follows: * * \f[\begin{array}{rcl} * t & = & C+\sum_{i=1}^na_{i}\cdot x_{i}\\ * t_{2}(y) & = & * -(C\ \mathbf{mod}\ m+\sum_{i=1}^{n}(a_{i}\ \mathbf{mod}\ m) * \cdot x_{i}-m\cdot y)\\ & & \\ * t_{3}(y) & = & * \mathbf{f}(C,m)+\sum_{i=1}^{n}\mathbf{f}(a_{i},m)\cdot x_{i} * -a\cdot y\\ & & \\ * m & = & a+1\\ & & \\ * \mathbf{f}(i,m) & = & \left\lfloor \frac{i}{m} * +\frac{1}{2}\right\rfloor +i\ \mathbf{mod}\ m\\ & & \\ * i\ \mathbf{mod}\ m & = & i-m\left\lfloor\frac{i}{m} * +\frac{1}{2}\right\rfloor * \end{array} * \f] * * All the variables and coefficients are integer, and a >= 2. * * \param eqn is the equation ax=t: * \f[a\cdot x = C + \sum_{i=1}^n a_i\cdot x_i.\f] * * \param isIntx is a Theorem deriving the integrality of the * LHS variable: IS_INTEGER(x) * * \param isIntVars is a vector of Theorems deriving the * integrality of all variables on the RHS */ virtual Theorem eqElimIntRule(const Theorem& eqn, const Theorem& isIntx, const std::vector& isIntVars) = 0; /*! * @brief return e <=> TRUE/FALSE for e == IS_INTEGER(c), where c * is a constant * * \param e is a predicate IS_INTEGER(c) where c is a rational constant */ virtual Theorem isIntConst(const Expr& e) = 0; virtual Theorem equalLeaves1(const Theorem& thm) = 0; virtual Theorem equalLeaves2(const Theorem& thm) = 0; virtual Theorem equalLeaves3(const Theorem& thm) = 0; virtual Theorem equalLeaves4(const Theorem& thm) = 0; //! x /= y ==> (x < y) OR (x > y) /*! Used in concrete model generation */ virtual Theorem diseqToIneq(const Theorem& diseq) = 0; virtual Theorem dummyTheorem(const Expr& e) = 0; virtual Theorem oneElimination(const Expr& x) = 0; virtual Theorem clashingBounds(const Theorem& lowerBound, const Theorem& upperBound) = 0; virtual Theorem addInequalities(const Theorem& thm1, const Theorem& thm2) = 0; virtual Theorem addInequalities(const std::vector& thms) = 0; virtual Theorem implyWeakerInequality(const Expr& expr1, const Expr& expr2) = 0; virtual Theorem implyNegatedInequality(const Expr& expr1, const Expr& expr2) = 0; virtual Theorem integerSplit(const Expr& intVar, const Rational& intPoint) = 0; virtual Theorem trustedRewrite(const Expr& expr1, const Expr& expr2) = 0; virtual Theorem rafineStrictInteger(const Theorem& isIntConstrThm, const Expr& constr) = 0; virtual Theorem simpleIneqInt(const Expr& ineq, const Theorem& isIntRHS) = 0; virtual Theorem intEqualityRationalConstant(const Theorem& isIntConstrThm, const Expr& constr) = 0; virtual Theorem cycleConflict(const std::vector& inequalitites) = 0; virtual Theorem implyEqualities(const std::vector& inequalities) = 0; virtual Theorem implyWeakerInequalityDiffLogic(const std::vector& antecedentThms, const Expr& implied) = 0; virtual Theorem implyNegatedInequalityDiffLogic(const std::vector& antecedentThms, const Expr& implied) = 0; virtual Theorem expandGrayShadowRewrite(const Expr& theShadow) = 0; virtual Theorem compactNonLinearTerm(const Expr& nonLinear) = 0; virtual Theorem nonLinearIneqSignSplit(const Theorem& ineqThm) = 0; virtual Theorem implyDiffLogicBothBounds(const Expr& x, std::vector& c1_le_x, Rational c1, std::vector& x_le_c2, Rational c2) = 0; virtual Theorem powerOfOne(const Expr& e) = 0; virtual Theorem rewriteLeavesConst(const Expr& e); }; // end of class ArithProofRules } // end of namespace CVC3 #endif cvc3-2.4.1/src/theory_datatype/0000775000175400017540000000000011630011320016235 5ustar mdetersmdeterscvc3-2.4.1/src/theory_datatype/Makefile0000664000175400017540000000062010533133654017713 0ustar mdetersmdeters################################################## # About this Makefile # # This Makefile depends on Makefile.opts ################################################## MODULE = theory_datatype SRC = datatype_theorem_producer.cpp theory_datatype.cpp theory_datatype_lazy.cpp HEADERS = datatype_proof_rules.h \ datatype_theorem_producer.h LIBRARY=libtheory_datatype.a include ../../Makefile.local cvc3-2.4.1/src/theory_datatype/datatype_theorem_producer.cpp0000664000175400017540000001130010466450542024220 0ustar mdetersmdeters/*****************************************************************************/ /*! *\file datatype_theorem_producer.cpp *\brief TRUSTED implementation of recursive datatype rules * * Author: Clark Barrett * * Created: Mon Jan 10 15:43:39 2005 * *
* * License to use, copy, modify, sell and/or distribute this software * and its documentation for any purpose is hereby granted without * royalty, subject to the terms and conditions defined in the \ref * LICENSE file provided with this distribution. * *
* */ /*****************************************************************************/ // This code is trusted #define _CVC3_TRUSTED_ #include "datatype_theorem_producer.h" #include "theory_datatype.h" #include "theory_core.h" using namespace std; using namespace CVC3; //////////////////////////////////////////////////////////////////// // TheoryDatatype: trusted method for creating DatatypeTheoremProducer //////////////////////////////////////////////////////////////////// DatatypeProofRules* TheoryDatatype::createProofRules() { return new DatatypeTheoremProducer(this); } //////////////////////////////////////////////////////////////////// // Proof rules //////////////////////////////////////////////////////////////////// Theorem DatatypeTheoremProducer::dummyTheorem(const CDList& facts, const Expr& e) { vector thmVec; for (unsigned i = 0; i < facts.size(); ++i) thmVec.push_back(facts[i]); Assumptions a(thmVec); Proof pf; return newTheorem(e, a, pf); } Theorem DatatypeTheoremProducer::rewriteSelCons(const CDList& facts, const Expr& e) { if (CHECK_PROOFS) { CHECK_SOUND(isSelector(e), "Selector expected"); CHECK_SOUND(d_theoryDatatype->canCollapse(e), "Expected canCollapse"); } Proof pf; Expr t; pair selectorInfo = d_theoryDatatype->getSelectorInfo(e.getOpExpr()); if (isConstructor(e[0]) && selectorInfo.first == getConstructor(e[0])) { t = e[0][selectorInfo.second]; } else { Expr selTypeExpr = e.getOpExpr().getType().getExpr(); Type type = Type(selTypeExpr[selTypeExpr.arity()-1]); t = d_theoryDatatype->getConstant(type); } if (withProof()) pf = newPf("rewriteSelCons", e, t); if (!isConstructor(e[0])) { vector thmVec; for (unsigned i = 0; i < facts.size(); ++i) thmVec.push_back(facts[i]); Assumptions a(thmVec); return newRWTheorem(e, t, a, pf); } else { return newRWTheorem(e, t, Assumptions::emptyAssump(), pf); } } Theorem DatatypeTheoremProducer::rewriteTestCons(const Expr& e) { if (CHECK_PROOFS) { CHECK_SOUND(isTester(e), "Tester expected"); CHECK_SOUND(isConstructor(e[0]), "Expected Test(Cons)"); } Proof pf; Expr t; Expr cons = d_theoryDatatype->getConsForTester(e.getOpExpr()); if (cons == getConstructor(e[0])) { t = d_theoryDatatype->trueExpr(); } else { t = d_theoryDatatype->falseExpr(); } if (withProof()) pf = newPf("rewriteTestCons", e, t); return newRWTheorem(e, t, Assumptions::emptyAssump(), pf); } Theorem DatatypeTheoremProducer::decompose(const Theorem& e) { if (CHECK_PROOFS) { CHECK_SOUND(e.isRewrite(), "decompose: expected rewrite"); } const Expr& lhs = e.getLHS(); const Expr& rhs = e.getRHS(); if(CHECK_PROOFS) { CHECK_SOUND(isConstructor(lhs) && isConstructor(rhs) && lhs.isApply() && rhs.isApply() && lhs.getOpExpr() == rhs.getOpExpr() && lhs.arity() > 0 && lhs.arity() == rhs.arity(), "decompose precondition violated"); } Assumptions a(e); Proof pf; Expr res = lhs[0].eqExpr(rhs[0]); if (lhs.arity() > 1) { vector args; args.push_back(res); for (int i = 1; i < lhs.arity(); ++i) { args.push_back(lhs[i].eqExpr(rhs[i])); } res = andExpr(args); } if (withProof()) pf = newPf("decompose", e.getProof()); return newTheorem(res, a, pf); } Theorem DatatypeTheoremProducer::noCycle(const Expr& e) { if (CHECK_PROOFS) { CHECK_SOUND(isConstructor(e) && e.isApply() && e.arity() > 0, "noCycle: expected constructor with children"); } Proof pf; Type t = e.getOpExpr().getType(); t = t[t.arity()-1]; const Op& reach = d_theoryDatatype->getReachablePredicate(t); vector args; args.push_back(!Expr(reach, e, e)); for (int i = 0; i < e.arity(); ++i) { if (isDatatype(e[i].getType()) && d_theoryDatatype->getReachablePredicate(e[i].getType()) == reach) args.push_back(Expr(reach, e, e[i])); } if (withProof()) pf = newPf("noCycle", e); return newTheorem(andExpr(args), Assumptions::emptyAssump(), pf); } cvc3-2.4.1/src/theory_datatype/theory_datatype.cpp0000644000175400017540000012102711624746724022201 0ustar mdetersmdeters/*****************************************************************************/ /*! *\file theory_datatype.cpp * * Author: Clark Barrett * * Created: Wed Dec 1 22:32:26 2004 * *
* * License to use, copy, modify, sell and/or distribute this software * and its documentation for any purpose is hereby granted without * royalty, subject to the terms and conditions defined in the \ref * LICENSE file provided with this distribution. * *
* */ /*****************************************************************************/ #include "theory_datatype.h" #include "datatype_proof_rules.h" #include "typecheck_exception.h" #include "parser_exception.h" #include "smtlib_exception.h" #include "theory_core.h" #include "theory_uf.h" #include "command_line_flags.h" using namespace std; using namespace CVC3; /////////////////////////////////////////////////////////////////////////////// // TheoryDatatype Public Methods // /////////////////////////////////////////////////////////////////////////////// TheoryDatatype::TheoryDatatype(TheoryCore* core) : Theory(core, "Datatypes"), d_labels(core->getCM()->getCurrentContext()), d_facts(core->getCM()->getCurrentContext()), d_splitters(core->getCM()->getCurrentContext()), d_splittersIndex(core->getCM()->getCurrentContext(), 0), d_splitterAsserted(core->getCM()->getCurrentContext(), false), d_smartSplits(core->getFlags()["dt-smartsplits"].getBool()) { d_rules = createProofRules(); // Register new local kinds with ExprManager getEM()->newKind(DATATYPE_DECL, "_DATATYPE_DECL"); getEM()->newKind(DATATYPE, "_DATATYPE", true); getEM()->newKind(CONSTRUCTOR, "_CONSTRUCTOR"); getEM()->newKind(SELECTOR, "_SELECTOR"); getEM()->newKind(TESTER, "_TESTER"); vector kinds; kinds.push_back(DATATYPE_DECL); kinds.push_back(DATATYPE); kinds.push_back(TESTER); kinds.push_back(CONSTRUCTOR); kinds.push_back(SELECTOR); registerTheory(this, kinds); } TheoryDatatype::~TheoryDatatype() { delete d_rules; } void TheoryDatatype::instantiate(const Expr& e, const Unsigned& u) { DebugAssert(!e.hasFind() || findExpr(e) == e, "datatype: instantiate: Expected find(e)=e"); if (isConstructor(e)) return; DebugAssert(u != 0 && (u & (u-1)) == 0, "datatype: instantiate: Expected single label in u"); DebugAssert(d_datatypes.find(getBaseType(e).getExpr()) != d_datatypes.end(), "datatype: instantiate: Unexpected type: "+getBaseType(e).toString() +"\n\n for expression: "+e.toString()); ExprMap& c = d_datatypes[getBaseType(e).getExpr()]; ExprMap::iterator c_it = c.begin(), c_end = c.end(); for (; c_it != c_end; ++c_it) { if ((u & (Unsigned(1) << (unsigned)(*c_it).second)) != 0) break; } DebugAssert(c_it != c_end, "datatype: instantiate: couldn't find constructor"); const Expr& cons = (*c_it).first; if (!cons.isFinite() && !e.isSelected()) return; Type consType = getBaseType(cons); if (consType.arity() == 1) { enqueueFact(d_rules->dummyTheorem(d_facts, e.eqExpr(cons))); return; } // create vars vector vars; for (int i = 0; i < consType.arity()-1; ++i) { vars.push_back(getEM()->newBoundVarExpr(consType[i])); } Expr e2 = getEM()->newClosureExpr(EXISTS, vars, e.eqExpr(Expr(cons.mkOp(), vars))); enqueueFact(d_rules->dummyTheorem(d_facts, e2)); } void TheoryDatatype::initializeLabels(const Expr& e, const Type& t) { DebugAssert(findExpr(e) == e, "datatype: initializeLabels: Expected find(e)=e"); DebugAssert(d_datatypes.find(t.getExpr()) != d_datatypes.end(), "Unknown datatype: "+t.getExpr().toString()); ExprMap& c = d_datatypes[t.getExpr()]; DebugAssert(d_labels.find(e) == d_labels.end(), "datatype: initializeLabels: expected unlabeled expr"); if (isConstructor(e)) { Expr cons = getConstructor(e); DebugAssert(c.find(cons) != c.end(), "datatype: initializeLabels: Couldn't find constructor " +cons.toString()); d_labels.insert(e, SmartCDO(theoryCore()->getCM()->getCurrentContext(), (Unsigned)1 << c[cons], 0)); } else { DebugAssert(c.size() > 0, "No constructors?"); Unsigned value = ((Unsigned)1 << c.size()) - 1; d_labels.insert(e, SmartCDO(theoryCore()->getCM()->getCurrentContext(), value, 0)); if (value == 1) instantiate(e, 1); else { if (!d_smartSplits || t.getExpr().isFinite()) d_splitters.push_back(e); } } } void TheoryDatatype::mergeLabels(const Theorem& thm, const Expr& e1, const Expr& e2) { DebugAssert(e2.hasFind() && findExpr(e2) == e2, "datatype: mergeLabels: Expected find(e2)=e2"); DebugAssert(d_labels.find(e1) != d_labels.end() && d_labels.find(e2) != d_labels.end(), "mergeLabels: expr is not labeled"); DebugAssert(getBaseType(e1) == getBaseType(e2), "Expected same type"); Unsigned u = d_labels[e2].get().get(); Unsigned uNew = u & d_labels[e1].get().get(); if (u != uNew) { if (!thm.isNull()) d_facts.push_back(thm); d_labels[e2].get().set(uNew); if (uNew == 0) setInconsistent(d_rules->dummyTheorem(d_facts, falseExpr())); } if (uNew != 0 && ((uNew - 1) & uNew) == 0) { instantiate(e2, uNew); } } void TheoryDatatype::mergeLabels(const Theorem& thm, const Expr& e, unsigned position, bool positive) { DebugAssert(e.hasFind() && findExpr(e) == e, "datatype: mergeLabels2: Expected find(e)=e"); DebugAssert(d_labels.find(e) != d_labels.end(), "mergeLabels2: expr is not labeled"); Unsigned u = d_labels[e].get().get(); Unsigned uNew = (Unsigned)1 << position; if (positive) { uNew = u & uNew; if (u == uNew) return; } else if ((u & uNew) != 0) uNew = u - uNew; else return; d_facts.push_back(thm); d_labels[e].get().set(uNew); if (uNew == 0) setInconsistent(d_rules->dummyTheorem(d_facts, falseExpr())); else if (((uNew - 1) & uNew) == 0) { instantiate(e, uNew); } } void TheoryDatatype::addSharedTerm(const Expr& e) { if (getBaseType(e).getExpr().getKind() == DATATYPE && d_labels.find(e) == d_labels.end()) { initializeLabels(e, getBaseType(e)); e.addToNotify(this, Expr()); } } void TheoryDatatype::assertFact(const Theorem& e) { if (!e.isRewrite()) { const Expr& expr = e.getExpr(); if (expr.getOpKind() == TESTER) { mergeLabels(e, expr[0], getConsPos(getConsForTester(expr.getOpExpr())), true); } else if (expr.isNot()) { if (expr[0].getOpKind() == TESTER) { mergeLabels(e, expr[0][0], getConsPos(getConsForTester(expr[0].getOpExpr())), false); } else if (expr[0].isEq() && getBaseType(expr[0][0]).getExpr().getKind() == DATATYPE) { // Propagate disequality down if (d_labels.find(expr[0][0]) == d_labels.end()) { initializeLabels(expr[0][0], getBaseType(expr[0][0])); expr[0][0].addToNotify(this, Expr()); } if (d_labels.find(expr[0][1]) == d_labels.end()) { initializeLabels(expr[0][1], getBaseType(expr[0][1])); expr[0][1].addToNotify(this, Expr()); } Unsigned u1 = d_labels[expr[0][0]].get().get(); Unsigned u2 = d_labels[expr[0][1]].get().get(); ExprMap& c = d_datatypes[getBaseType(expr[0][0]).getExpr()]; ExprMap::iterator c_it = c.begin(), c_end = c.end(); Expr bigConj; for (; c_it != c_end; ++c_it) { if ((u1 & u2 & ((Unsigned)1 << unsigned((*c_it).second))) != 0) { vector& selectors = d_constructorMap[(*c_it).first]; Expr conj; for (unsigned i = 0; i < selectors.size(); ++i) { Expr e1 = Expr(selectors[i].mkOp(), expr[0][0]); Expr e2 = e1.eqExpr(Expr(selectors[i].mkOp(), expr[0][1])); if (conj.isNull()) conj = e2; else conj = conj.andExpr(e2); } if (!conj.isNull()) { Expr e1 = datatypeTestExpr((*c_it).first.getName(), expr[0][0]); Expr e2 = datatypeTestExpr((*c_it).first.getName(), expr[0][1]); conj = (e1 && e2).impExpr(!conj); if (bigConj.isNull()) bigConj = conj; else bigConj = bigConj.andExpr(conj); } } } if (!bigConj.isNull()) { enqueueFact(d_rules->dummyTheorem(d_facts, expr.impExpr(bigConj))); } } } } } void TheoryDatatype::checkSat(bool fullEffort) { bool done = false; while (!done && d_splittersIndex < d_splitters.size()) { Expr e = d_splitters[d_splittersIndex]; if ((!d_smartSplits || getBaseType(e).getExpr().isFinite()) && findExpr(e) == e) { DebugAssert(d_labels.find(e) != d_labels.end(), "checkSat: expr is not labeled"); Unsigned u = d_labels[e].get().get(); if ((u & (u-1)) != 0) { done = true; DebugAssert(!d_splitterAsserted || !fullEffort, "splitter should have been resolved"); if (!d_splitterAsserted) { DebugAssert (d_datatypes.find(getBaseType(e).getExpr()) != d_datatypes.end(), "datatype: checkSat: Unexpected type: "+getBaseType(e).toString() +"\n\n for expression: "+e.toString()); ExprMap& c = d_datatypes[getBaseType(e).getExpr()]; ExprMap::iterator c_it = c.begin(), c_end = c.end(); vector vec; for (; c_it != c_end; ++c_it) { if ((u & ((Unsigned)1 << unsigned((*c_it).second))) != 0) { vec.push_back(datatypeTestExpr((*c_it).first.getName(), e)); } } DebugAssert(vec.size() > 1, "datatype: checkSat: expected 2 or more possible constructors"); enqueueFact(d_rules->dummyTheorem(d_facts, Expr(OR, vec))); d_splitterAsserted = true; } } } if (d_smartSplits && !done && isSelector(e)) { Expr f = findExpr(e[0]); DebugAssert(d_labels.find(f) != d_labels.end(), "checkSat: expr is not labeled"); Unsigned u = d_labels[f].get().get(); if ((u & (u-1)) != 0) { pair selectorInfo = getSelectorInfo(e.getOpExpr()); unsigned pos = getConsPos(selectorInfo.first); if ((u & ((Unsigned)1 << pos)) != 0) { done = true; DebugAssert(!d_splitterAsserted || !fullEffort, "splitter should have been resolved"); if (!d_splitterAsserted) { addSplitter(datatypeTestExpr(selectorInfo.first.getName(), f)); d_splitterAsserted = true; } } } } if (!done) { d_splitterAsserted = false; d_splittersIndex = d_splittersIndex + 1; } } } Theorem TheoryDatatype::rewrite(const Expr& e) { // TODO: UF rewrite? Theorem thm; if (isSelector(e)) { if (canCollapse(e)) { thm = d_rules->rewriteSelCons(d_facts, e); return transitivityRule(thm, simplify(thm.getRHS())); } } else if (isTester(e)) { if (isConstructor(e[0])) { return d_rules->rewriteTestCons(e); } } return reflexivityRule(e); } void TheoryDatatype::setup(const Expr& e) { if (getBaseType(e).getExpr().getKind() == DATATYPE && d_labels.find(e) == d_labels.end()) { initializeLabels(e, getBaseType(e)); e.addToNotify(this, Expr()); } if (e.getKind() != APPLY) return; if (isConstructor(e) && e.arity() > 0) { enqueueFact(d_rules->noCycle(e)); } if (isSelector(e)) { if (d_smartSplits) d_splitters.push_back(e); e[0].setSelected(); mergeLabels(Theorem(), e[0], e[0]); } setupCC(e); } void TheoryDatatype::update(const Theorem& e, const Expr& d) { if (d.isNull()) { const Expr& lhs = e.getLHS(); const Expr& rhs = e.getRHS(); if (isConstructor(lhs) && isConstructor(rhs) && lhs.isApply() && rhs.isApply() && lhs.getOpExpr() == rhs.getOpExpr()) { enqueueFact(d_rules->decompose(e)); } else { // Possible for rhs to never have been seen: initialize it here DebugAssert(getBaseType(rhs).getExpr().getKind() == DATATYPE, "Expected datatype"); if (d_labels.find(rhs) == d_labels.end()) { initializeLabels(rhs, getBaseType(rhs)); rhs.addToNotify(this, Expr()); } Theorem thm(e); if (lhs.isSelected() && !rhs.isSelected()) { d_facts.push_back(e); rhs.setSelected(); thm = Theorem(); } mergeLabels(thm, lhs, rhs); } } else { const Theorem& dEQdsig = d.getSig(); if (!dEQdsig.isNull()) { const Expr& dsig = dEQdsig.getRHS(); Theorem thm = updateHelper(d); const Expr& sigNew = thm.getRHS(); if (sigNew == dsig) return; dsig.setRep(Theorem()); if (isSelector(sigNew) && canCollapse(sigNew)) { d.setSig(Theorem()); enqueueFact(transitivityRule(thm, d_rules->rewriteSelCons(d_facts, sigNew))); } else if (isTester(sigNew) && isConstructor(sigNew[0])) { d.setSig(Theorem()); enqueueFact(transitivityRule(thm, d_rules->rewriteTestCons(sigNew))); } else { const Theorem& repEQsigNew = sigNew.getRep(); if (!repEQsigNew.isNull()) { d.setSig(Theorem()); enqueueFact(transitivityRule(repEQsigNew, symmetryRule(thm))); } else { int k, ar(d.arity()); for (k = 0; k < ar; ++k) { if (sigNew[k] != dsig[k]) { sigNew[k].addToNotify(this, d); } } d.setSig(thm); sigNew.setRep(thm); getEM()->invalidateSimpCache(); } } } } } Theorem TheoryDatatype::solve(const Theorem& e) { DebugAssert(e.isRewrite() && e.getLHS().isTerm(), "Expected equality"); const Expr& lhs = e.getLHS(); if (isConstructor(lhs) && !isConstructor(e.getRHS())) { return symmetryRule(e); } return e; } void TheoryDatatype::checkType(const Expr& e) { switch (e.getKind()) { case DATATYPE: { if (e.arity() != 1 || !e[0].isString()) throw Exception("Ill-formed datatype"+e.toString()); if (resolveID(e[0].getString()) != e) throw Exception("Unknown datatype"+e.toString()); break; } case CONSTRUCTOR: case SELECTOR: case TESTER: throw Exception("Non-type: "+e.toString()); default: FatalAssert(false, "Unexpected kind in TheoryDatatype::checkType" +getEM()->getKindName(e.getKind())); } } Cardinality TheoryDatatype::finiteTypeInfo(Expr& e, Unsigned& n, bool enumerate, bool computeSize) { DebugAssert(e.getKind() == DATATYPE, "Unexpected kind in TheoryDatatype::finiteTypeInfo"); if (d_getConstantStack.count(e) != 0) { return CARD_INFINITE; } d_getConstantStack[e] = true; Expr typeExpr = e; ExprMap& c = d_datatypes[typeExpr]; ExprMap::iterator c_it = c.begin(), c_end = c.end(); Cardinality card = CARD_FINITE, cardTmp; bool getSize = enumerate || computeSize; Unsigned totalSize = 0, thisSize, size; vector sizes; int j; // Loop through constructors, and check if each one only has a finite number // of possibilities for (; c_it != c_end; ++c_it) { const Expr& cons = (*c_it).first; Expr funType = cons.getType().getExpr(); thisSize = 1; for (j = 0; j < funType.arity()-1; ++j) { Expr e2 = funType[j]; cardTmp = theoryOf(e2)->finiteTypeInfo(e2, size, false, getSize); if (cardTmp == CARD_INFINITE) { card = CARD_INFINITE; break; } else if (cardTmp == CARD_UNKNOWN) { card = CARD_UNKNOWN; getSize = false; // Keep looking to see if we can determine it is infinite } else if (getSize) { thisSize = thisSize * size; // Give up if it gets too big if (thisSize > 1000000) thisSize = 0; if (thisSize == 0) { totalSize = 0; getSize = false; } } } if (card == CARD_INFINITE) break; if (getSize) { sizes.push_back(thisSize); totalSize = totalSize + thisSize; } } if (card == CARD_FINITE) { if (enumerate) { c_it = c.begin(); unsigned i = 0; for (; i < sizes.size(); ++i, ++c_it) { if (n < sizes[i]) { break; } else n = n - sizes[i]; } if (i == sizes.size() && n != 0) { e = Expr(); } else { const Expr& cons = (*c_it).first; Expr funType = cons.getType().getExpr(); if (funType.arity() == 1) { e = cons; } else { vector kids(funType.arity()-1); Unsigned thisSize; Unsigned elem; for (int j = funType.arity()-2; j >= 0; --j) { if (n == 0) { elem = 0; } else { thisSize = funType[j].typeSizeFinite(); elem = n % thisSize; n = n - elem; n = n / thisSize; } kids[j] = funType[j].typeEnumerateFinite(elem); } e = Expr(cons.mkOp(), kids); } } } if (computeSize) { n = totalSize; } } d_getConstantStack.erase(typeExpr); return card; } void TheoryDatatype::computeType(const Expr& e) { switch (e.getOpKind()) { case CONSTRUCTOR: case SELECTOR: case TESTER: { DebugAssert(e.isApply(), "Expected application"); Expr op = e.getOp().getExpr(); Type t = op.lookupType(); DebugAssert(!t.isNull(), "Expected operator to be well-typed"); if (t.getExpr().getKind() == DATATYPE) { if (e.arity() != 0) throw TypecheckException("Expected no children: "+e.toString()); e.setType(t); break; } else { DebugAssert(t.getExpr().getKind() == ARROW, "Expected function type"); if (e.arity() != t.getExpr().arity()-1) throw TypecheckException("Wrong number of children:\n"+e.toString()); Expr::iterator i = e.begin(), iend = e.end(); Expr::iterator j = t.getExpr().begin(); for (; i != iend; ++i, ++j) { if (getBaseType(*i) != getBaseType(Type(*j))) { throw TypecheckException("Type mismatch for expression:\n\n " + (*i).toString() + "\n\nhas the following type:\n\n " + (*i).getType().getExpr().toString() + "\n\nbut the expected type is:\n\n " + (*j).toString() + "\n\nin datatype function application:\n\n " + e.toString()); } } e.setType(*j); } break; } default: DebugAssert(false, "Unexpected kind in datatype::computeType: " +e.toString()); } } void TheoryDatatype::computeModelTerm(const Expr& e, std::vector& v) { } Expr TheoryDatatype::computeTCC(const Expr& e) { Expr tcc(Theory::computeTCC(e)); switch (e.getKind()) { case CONSTRUCTOR: DebugAssert(e.arity() == 0, "Expected leaf constructor"); return trueExpr(); case APPLY: { DebugAssert(e.isApply(), "Should be application"); Expr op(e.getOpExpr()); if (op.getKind() != SELECTOR) return tcc; DebugAssert(e.arity() == 1, "Expected single argument"); const std::pair& p = getSelectorInfo(op); Expr tester = datatypeTestExpr(p.first.getName(), e[0]); return tcc.andExpr(tester); } default: DebugAssert(false,"Unexpected type: "+e.toString()); return trueExpr(); } } /////////////////////////////////////////////////////////////////////////////// // Pretty-printing // /////////////////////////////////////////////////////////////////////////////// ExprStream& TheoryDatatype::print(ExprStream& os, const Expr& e) { switch (os.lang()) { case PRESENTATION_LANG: switch (e.getKind()) { case DATATYPE_DECL: { os << "DATATYPE" << endl; bool first(true); for (Expr::iterator i = e.begin(), iend = e.end(); i != iend; ++i) { if (first) first = false; else os << "," << endl; os << " " << push << *i << space << "= " << push; DebugAssert(d_datatypes.find(*i) != d_datatypes.end(), "Unknown datatype: "+(*i).toString()); ExprMap& c = d_datatypes[*i]; ExprMap::iterator c_it = c.begin(), c_end = c.end(); bool firstCons(true); for (; c_it != c_end; ++c_it) { if (!firstCons) { os << space << "| "; } else firstCons = false; const Expr& cons = (*c_it).first; os << cons; vector& sels = d_constructorMap[cons]; bool firstSel(true); for (unsigned j = 0; j < sels.size(); ++j) { if (firstSel) { firstSel = false; os << "("; } else { os << ", "; } os << sels[j] << space << ": "; os << sels[j].getType().getExpr()[1]; } if (!firstSel) { os << ")"; } } os << pop; } os << pop << endl; os << "END;"; break; } case DATATYPE: if (e.arity() == 1 && e[0].isString()) { os << e[0].getString(); } else e.printAST(os); break; case APPLY: os << e.getOpExpr(); if(e.arity() > 0) { os << "(" << push; bool first(true); for (Expr::iterator i=e.begin(), iend=e.end(); i!=iend; ++i) { if(first) first = false; else os << "," << space; os << *i; } os << push << ")"; } break; case CONSTRUCTOR: case SELECTOR: case TESTER: DebugAssert(e.isSymbol(), "Expected symbol"); os << e.getName(); break; default: DebugAssert(false, "TheoryDatatype::print: Unexpected kind: " +getEM()->getKindName(e.getKind())); } break; case SMTLIB_LANG: FatalAssert(false, "Not Implemented Yet"); break; case LISP_LANG: FatalAssert(false, "Not Implemented Yet"); break; default: e.printAST(os); break; } return os; } ////////////////////////////////////////////////////////////////////////////// //parseExprOp: //translating special Exprs to regular EXPR?? /////////////////////////////////////////////////////////////////////////////// Expr TheoryDatatype::parseExprOp(const Expr& e) { // If the expression is not a list, it must have been already // parsed, so just return it as is. if(RAW_LIST != e.getKind()) return e; DebugAssert(e.arity() > 0, "TheoryDatatype::parseExprOp:\n e = "+e.toString()); DebugAssert(e[0].getKind() == ID, "Expected ID kind for first elem in list expr"); const Expr& c1 = e[0][0]; int kind = getEM()->getKind(c1.getString()); switch(kind) { case DATATYPE: { DebugAssert(e.arity() > 1, "Empty DATATYPE expression\n" " (expected at least one datatype): "+e.toString()); vector names; vector allConstructorNames; vector constructorNames; vector allSelectorNames; vector selectorNames; vector selectorNamesKids; vector allTypes; vector types; vector typesKids; int i,j,k; Expr dt, constructor, selectors, selector; // Get names of datatypes ExprMap namesMap; for (i = 0; i < e.arity()-1; ++i) { dt = e[i+1]; DebugAssert(dt.getKind() == RAW_LIST && dt.arity() == 2, "Bad formed datatype expression" +dt.toString()); DebugAssert(dt[0].getKind() == ID, "Expected ID kind for datatype name" +dt.toString()); names.push_back(dt[0][0]); if (namesMap.count(dt[0][0]) != 0) { throw ParserException("Datatype name used more than once"+dt[0][0].getString()); } namesMap.insert(dt[0][0], true); } // Loop through datatypes for (i = 0; i < e.arity()-1; ++i) { dt = e[i+1]; DebugAssert(dt[1].getKind() == RAW_LIST && dt[1].arity() > 0, "Expected non-empty list for datatype constructors" +dt.toString()); dt = dt[1]; // Loop through constructors for this datatype for(j = 0; j < dt.arity(); ++j) { constructor = dt[j]; DebugAssert(constructor.getKind() == RAW_LIST && (constructor.arity() == 1 || constructor.arity() == 2), "Unexpected constructor"+constructor.toString()); DebugAssert(constructor[0].getKind() == ID, "Expected ID kind for constructor name" +constructor.toString()); constructorNames.push_back(constructor[0][0]); if (constructor.arity() == 2) { selectors = constructor[1]; DebugAssert(selectors.getKind() == RAW_LIST && selectors.arity() > 0, "Non-empty list expected as second argument of constructor:\n" +constructor.toString()); // Loop through selectors for this constructor for (k = 0; k < selectors.arity(); ++k) { selector = selectors[k]; DebugAssert(selector.getKind() == RAW_LIST && selector.arity() == 2, "Expected list of arity 2 for selector" +selector.toString()); DebugAssert(selector[0].getKind() == ID, "Expected ID kind for selector name" +selector.toString()); selectorNamesKids.push_back(selector[0][0]); if (selector[1].getKind() == ID && namesMap.count(selector[1][0]) > 0) { typesKids.push_back(selector[1][0]); } else { typesKids.push_back(parseExpr(selector[1])); } } selectorNames.push_back(Expr(RAW_LIST, selectorNamesKids)); selectorNamesKids.clear(); types.push_back(Expr(RAW_LIST, typesKids)); typesKids.clear(); } else { selectorNames.push_back(Expr(RAW_LIST, selectorNamesKids, getEM())); types.push_back(Expr(RAW_LIST, typesKids, getEM())); } } allConstructorNames.push_back(Expr(RAW_LIST, constructorNames)); constructorNames.clear(); allSelectorNames.push_back(Expr(RAW_LIST, selectorNames)); selectorNames.clear(); allTypes.push_back(Expr(RAW_LIST, types)); types.clear(); } return Expr(DATATYPE, Expr(RAW_LIST, names), Expr(RAW_LIST, allConstructorNames), Expr(RAW_LIST, allSelectorNames), Expr(RAW_LIST, allTypes)); } default: { throw ParserException("Unexpected datatype expression: "+e.toString()); } } return e; } Expr TheoryDatatype::dataType(const string& name, const vector& constructors, const vector >& selectors, const vector >& types) { vector names; vector > constructors2; vector > > selectors2; vector > > types2; names.push_back(name); constructors2.push_back(constructors); selectors2.push_back(selectors); types2.push_back(types); return dataType(names, constructors2, selectors2, types2); } // Elements of types are either the expr from an existing type or a string // naming one of the datatypes being defined Expr TheoryDatatype::dataType(const vector& names, const vector >& allConstructors, const vector > >& allSelectors, const vector > >& allTypes) { vector returnTypes; // bool wellFounded = false, infinite = false, bool thisWellFounded; if (names.size() != allConstructors.size() || allConstructors.size() != allSelectors.size() || allSelectors.size() != allTypes.size()) { throw TypecheckException ("dataType: vector sizes don't match"); } unsigned i, j, k; Expr e; // Create reachability predicate for constructor cycle detection vector funTypeArgs; funTypeArgs.push_back(Type::anyType(getEM())); funTypeArgs.push_back(Type::anyType(getEM())); Op op = newFunction("_reach_"+names[0], Type::funType(funTypeArgs, boolType()), true /* compute trans closure */); Op reach = getEM()->newSymbolExpr(op.getExpr().getName(), TRANS_CLOSURE).mkOp(); for (i = 0; i < names.size(); ++i) { e = resolveID(names[i]); if (!e.isNull()) { throw TypecheckException ("Attempt to define datatype "+names[i]+":\n " "This variable is already defined."); } e = Expr(DATATYPE, getEM()->newStringExpr(names[i])); installID(names[i], e); returnTypes.push_back(e); d_reach[e] = reach; } vector selectorVec; for (i = 0; i < names.size(); ++i) { const vector& constructors = allConstructors[i]; const vector >& selectors = allSelectors[i]; const vector >& types = allTypes[i]; if (constructors.size() == 0) { throw TypecheckException ("datatype: "+names[i]+": must have at least one constructor"); } if (constructors.size() != selectors.size() || selectors.size() != types.size()) { throw TypecheckException ("dataType: vector sizes at index "+int2string(i)+" don't match"); } ExprMap& constMap = d_datatypes[returnTypes[i]]; for (j = 0; j < constructors.size(); ++j) { Expr c = resolveID(constructors[j]); if (!c.isNull()) { throw TypecheckException ("Attempt to define datatype constructor "+constructors[j]+":\n " "This variable is already defined."); } c = getEM()->newSymbolExpr(constructors[j], CONSTRUCTOR); if (selectors[j].size() != types[j].size()) { throw TypecheckException ("dataType: constructor at index "+int2string(i)+", "+int2string(j)+ ": number of selectors does not match number of types"); } thisWellFounded = true; const vector& sels = selectors[j]; const vector& tps = types[j]; vector selTypes; Type t; Expr s; for (k = 0; k < sels.size(); ++k) { s = resolveID(sels[k]); if (!s.isNull()) { throw TypecheckException ("Attempt to define datatype selector "+sels[k]+":\n " "This variable is already defined."); } s = getEM()->newSymbolExpr(sels[k], SELECTOR); if (tps[k].isString()) { t = Type(resolveID(tps[k].getString())); if (t.isNull()) { throw TypecheckException ("Unable to resolve type identifier: "+tps[k].getString()); } } else t = Type(tps[k]); if (t.isBool()) { throw TypecheckException ("Cannot have BOOLEAN inside of datatype"); } else if (t.isFunction()) { throw TypecheckException ("Cannot have function inside of datatype"); } selTypes.push_back(Type(t)); s.setType(Type(returnTypes[i]).funType(Type(t))); if (isDatatype(Type(t)) && !t.getExpr().isWellFounded()) { thisWellFounded = false; } d_selectorMap[s] = pair(c,k); installID(sels[k], s); selectorVec.push_back(s); } if (thisWellFounded) c.setWellFounded(); if (selTypes.size() == 0) { c.setType(Type(returnTypes[i])); c.setFinite(); } else c.setType(Type::funType(selTypes, Type(returnTypes[i]))); installID(constructors[j], c); constMap[c] = j; d_constructorMap[c] = selectorVec; selectorVec.clear(); string testerString = "is_"+constructors[j]; e = resolveID(testerString); if (!e.isNull()) { throw TypecheckException ("Attempt to define datatype tester "+testerString+":\n " "This variable is already defined."); } e = getEM()->newSymbolExpr(testerString, TESTER); e.setType(Type(returnTypes[i]).funType(boolType())); d_testerMap[e] = c; installID(testerString, e); } } // Compute fixed point for wellfoundedness check bool changed, thisFinite; int firstNotWellFounded; do { changed = false; firstNotWellFounded = -1; for (i = 0; i < names.size(); ++i) { ExprMap& c = d_datatypes[returnTypes[i]]; ExprMap::iterator c_it = c.begin(), c_end = c.end(); thisWellFounded = false; thisFinite = true; for (; c_it != c_end; ++c_it) { const Expr& cons = (*c_it).first; Expr funType = getBaseType(cons).getExpr(); int j; if (!cons.isFinite()) { for (j = 0; j < funType.arity()-1; ++j) { if (!isDatatype(funType[j]) || !funType[j].isFinite()) break; } if (j == funType.arity()-1) { changed = true; cons.setFinite(); } else thisFinite = false; } if (cons.isWellFounded()) { thisWellFounded = true; continue; } for (j = 0; j < funType.arity()-1; ++j) { if (isDatatype(funType[j]) && !funType[j].isWellFounded()) break; } if (j == funType.arity()-1) { changed = true; cons.setWellFounded(); thisWellFounded = true; } } if (!thisWellFounded) { if (firstNotWellFounded == -1) firstNotWellFounded = i; } else { if (!returnTypes[i].isWellFounded()) { changed = true; returnTypes[i].setWellFounded(); } } if (thisFinite && !returnTypes[i].isFinite()) { changed = true; returnTypes[i].setFinite(); } } } while (changed); if (firstNotWellFounded >= 0) { // TODO: uninstall all ID's throw TypecheckException ("Datatype "+names[firstNotWellFounded]+" has no finite terms"); } return Expr(DATATYPE_DECL, returnTypes); } Expr TheoryDatatype::datatypeConsExpr(const string& constructor, const vector& args) { Expr e = resolveID(constructor); if (e.isNull()) throw Exception("datatype: unknown constructor: "+constructor); if (!(e.isSymbol() && e.getKind() == CONSTRUCTOR)) throw Exception("datatype: "+constructor+" resolves to: "+e.toString()+ "\nwhich is not a constructor"); if (args.size() == 0) return e; return Expr(e.mkOp(), args); } Expr TheoryDatatype::datatypeSelExpr(const string& selector, const Expr& arg) { Expr e = resolveID(selector); if (e.isNull()) throw Exception("datatype: unknown selector: "+selector); if (!(e.isSymbol() && e.getKind() == SELECTOR)) throw Exception("datatype: "+selector+" resolves to: "+e.toString()+ "\nwhich is not a selector"); return Expr(e.mkOp(), arg); } Expr TheoryDatatype::datatypeTestExpr(const string& constructor, const Expr& arg) { Expr e = resolveID("is_"+constructor); if (e.isNull()) throw Exception("datatype: unknown tester: is_"+constructor); if (!(e.isSymbol() && e.getKind() == TESTER)) throw Exception("datatype: is_"+constructor+" resolves to: "+e.toString()+ "\nwhich is not a tester"); return Expr(e.mkOp(), arg); } const pair& TheoryDatatype::getSelectorInfo(const Expr& e) { DebugAssert(e.getKind() == SELECTOR, "getSelectorInfo called on non-selector: " +e.toString()); DebugAssert(d_selectorMap.find(e) != d_selectorMap.end(), "Unknown selector: "+e.toString()); return d_selectorMap[e]; } Expr TheoryDatatype::getConsForTester(const Expr& e) { DebugAssert(e.getKind() == TESTER, "getConsForTester called on non-tester" +e.toString()); DebugAssert(d_testerMap.find(e) != d_testerMap.end(), "Unknown tester: "+e.toString()); return d_testerMap[e]; } unsigned TheoryDatatype::getConsPos(const Expr& e) { DebugAssert(e.getKind() == CONSTRUCTOR, "getConsPos called on non-constructor"); Type t = getBaseType(e); if (t.isFunction()) t = t[t.arity()-1]; DebugAssert(isDatatype(t), "Expected datatype"); DebugAssert(d_datatypes.find(t.getExpr()) != d_datatypes.end(), "Could not find datatype: "+t.toString()); ExprMap& constMap = d_datatypes[t.getExpr()]; DebugAssert(constMap.find(e) != constMap.end(), "Could not find constructor: "+e.toString()); return constMap[e]; } Expr TheoryDatatype::getConstant(const Type& t) { // if a cycle is detected, backtrack from this branch if (d_getConstantStack.count(t.getExpr()) != 0) { return Expr(); } DebugAssert(d_getConstantStack.size() < 1000, "TheoryDatatype::getconstant: too deep recursion depth"); d_getConstantStack[t.getExpr()] = true; if (isDatatype(t)) { DebugAssert(d_datatypes.find(t.getExpr()) != d_datatypes.end(), "Unknown datatype: "+t.getExpr().toString()); ExprMap& c = d_datatypes[t.getExpr()]; ExprMap::iterator i = c.begin(), iend = c.end(); for (; i != iend; ++i) { const Expr& cons = (*i).first; if (!getBaseType(cons).isFunction()) { d_getConstantStack.erase(t.getExpr()); return cons; } } for (i = c.begin(), iend = c.end(); i != iend; ++i) { const Expr& cons = (*i).first; Expr funType = getBaseType(cons).getExpr(); vector args; int j = 0; for (; j < funType.arity()-1; ++j) { Type t_j = Type(funType[j]); if (t_j == t || isDatatype(t_j)) break; args.push_back(getConstant(t_j)); DebugAssert(!args.back().isNull(), "Expected non-null"); } if (j == funType.arity()-1) { d_getConstantStack.erase(t.getExpr()); return Expr(cons.mkOp(), args); } } for (i = c.begin(), iend = c.end(); i != iend; ++i) { const Expr& cons = (*i).first; Expr funType = getBaseType(cons).getExpr(); vector args; int j = 0; for (; j < funType.arity()-1; ++j) { Type t_j = Type(funType[j]); if (t_j == t) break; args.push_back(getConstant(t_j)); if (args.back().isNull()) break; } if (j == funType.arity()-1) { d_getConstantStack.erase(t.getExpr()); return Expr(cons.mkOp(), args); } } FatalAssert(false, "Couldn't find constant for" +t.toString()); } DebugAssert(!t.isBool() && !t.isFunction(), "Expected non-bool, non-function type"); //TODO: this name could be an illegal identifier (i.e. could include spaces) string name = "datatype_"+t.getExpr().toString(); Expr e = resolveID(name); d_getConstantStack.erase(t.getExpr()); if (e.isNull()) return newVar(name, t); return e; } const Op& TheoryDatatype::getReachablePredicate(const Type& t) { DebugAssert(isDatatype(t), "Expected datatype"); DebugAssert(d_reach.find(t.getExpr()) != d_reach.end(), "Couldn't find reachable predicate"); return d_reach[t.getExpr()]; } bool TheoryDatatype::canCollapse(const Expr& e) { DebugAssert(isSelector(e), "canCollapse: Selector expression expected"); DebugAssert(e.arity() == 1, "expected arity 1"); if (isConstructor(e[0])) return true; if (d_labels.find(e[0]) == d_labels.end()) return false; DebugAssert(e[0].hasFind() && findExpr(e[0]) == e[0], "canCollapse: Expected find(e[0])=e[0]"); Unsigned u = d_labels[e[0]].get().get(); Expr cons = getSelectorInfo(e.getOpExpr()).first; Unsigned uCons = (Unsigned)1 << unsigned(getConsPos(cons)); if ((u & uCons) == 0) return true; return false; } cvc3-2.4.1/src/theory_datatype/datatype_proof_rules.h0000664000175400017540000000300610466450541022661 0ustar mdetersmdeters/*****************************************************************************/ /*! *\file datatype_proof_rules.h *\brief Abstract interface for recursive datatype proof rules * * Author: Clark Barrett * * Created: Mon Jan 10 15:40:24 2005 * *
* * License to use, copy, modify, sell and/or distribute this software * and its documentation for any purpose is hereby granted without * royalty, subject to the terms and conditions defined in the \ref * LICENSE file provided with this distribution. * *
* * CLASS: DatatypeProofRules * */ /*****************************************************************************/ #ifndef _cvc3__theory_datatype__datatype_proof_rules_h_ #define _cvc3__theory_datatype__datatype_proof_rules_h_ namespace CVC3 { class Expr; class Theorem; template class CDList; class DatatypeProofRules { public: // Destructor virtual ~DatatypeProofRules() { } //////////////////////////////////////////////////////////////////// // Proof rules //////////////////////////////////////////////////////////////////// virtual Theorem dummyTheorem(const CDList& facts, const Expr& e) = 0; virtual Theorem rewriteSelCons(const CDList& facts, const Expr& e) = 0; virtual Theorem rewriteTestCons(const Expr& e) = 0; virtual Theorem decompose(const Theorem& e) = 0; virtual Theorem noCycle(const Expr& e) = 0; }; // end of class DatatypeProofRules } // end of namespace CVC3 #endif cvc3-2.4.1/src/theory_datatype/datatype_theorem_producer.h0000664000175400017540000000304710466450542023676 0ustar mdetersmdeters/*****************************************************************************/ /*! *\file datatype_theorem_producer.h *\brief TRUSTED implementation of recursive datatype proof rules * * Author: Clark Barrett * * Created: Mon Jan 10 15:42:22 2005 * *
* * License to use, copy, modify, sell and/or distribute this software * and its documentation for any purpose is hereby granted without * royalty, subject to the terms and conditions defined in the \ref * LICENSE file provided with this distribution. * *
* * CLASS: DatatypeTheoremProducer * */ /*****************************************************************************/ #ifndef _cvc3__theory_datatype__datatype_theorem_producer_h_ #define _cvc3__theory_datatype__datatype_theorem_producer_h_ #include "datatype_proof_rules.h" #include "theorem_producer.h" #include "theory_datatype.h" #include "theory_core.h" namespace CVC3 { class DatatypeTheoremProducer: public DatatypeProofRules, public TheoremProducer { TheoryDatatype* d_theoryDatatype; private: public: //! Constructor DatatypeTheoremProducer(TheoryDatatype* theoryDatatype) : TheoremProducer(theoryDatatype->theoryCore()->getTM()), d_theoryDatatype(theoryDatatype) { } Theorem dummyTheorem(const CDList& facts, const Expr& e); Theorem rewriteSelCons(const CDList& facts, const Expr& e); Theorem rewriteTestCons(const Expr& e); Theorem decompose(const Theorem& e); Theorem noCycle(const Expr& e); }; // end of class DatatypeTheoremProducer } // end of namespace CVC3 #endif cvc3-2.4.1/src/theory_datatype/theory_datatype_lazy.cpp0000664000175400017540000002447211360164531023233 0ustar mdetersmdeters/*****************************************************************************/ /*! *\file theory_datatype_lazy.cpp * * Author: Clark Barrett * * Created: Wed Dec 1 22:32:26 2004 * *
* * License to use, copy, modify, sell and/or distribute this software * and its documentation for any purpose is hereby granted without * royalty, subject to the terms and conditions defined in the \ref * LICENSE file provided with this distribution. * *
* */ /*****************************************************************************/ #include "theory_datatype_lazy.h" #include "datatype_proof_rules.h" #include "typecheck_exception.h" #include "parser_exception.h" #include "smtlib_exception.h" #include "theory_core.h" #include "theory_uf.h" #include "command_line_flags.h" using namespace std; using namespace CVC3; /////////////////////////////////////////////////////////////////////////////// // TheoryDatatypeLazy Public Methods // /////////////////////////////////////////////////////////////////////////////// TheoryDatatypeLazy::TheoryDatatypeLazy(TheoryCore* core) : TheoryDatatype(core), d_processQueue(core->getCM()->getCurrentContext()), d_processQueueKind(core->getCM()->getCurrentContext()), d_processIndex(core->getCM()->getCurrentContext(), 0), d_typeComplete(core->getCM()->getCurrentContext(), false) { } void TheoryDatatypeLazy::instantiate(const Expr& e, const Unsigned& u) { DebugAssert(e.hasFind() && findExpr(e) == e, "datatype: instantiate: Expected find(e)=e"); if (isConstructor(e) || e.isTranslated()) return; DebugAssert(u != 0 && (u & (u-1)) == 0, "datatype: instantiate: Expected single label in u"); DebugAssert(d_datatypes.find(e.getType().getExpr()) != d_datatypes.end(), "datatype: instantiate: Unexpected type: "+e.getType().toString() +"\n\n for expression: "+e.toString()); ExprMap& c = d_datatypes[e.getType().getExpr()]; ExprMap::iterator c_it = c.begin(), c_end = c.end(); for (; c_it != c_end; ++c_it) { if ((u & ((Unsigned)1 << unsigned((*c_it).second))) != 0) break; } DebugAssert(c_it != c_end, "datatype: instantiate: couldn't find constructor"); Expr cons = (*c_it).first; if (!cons.isFinite() && !e.isSelected()) return; Type consType = cons.getType(); if (consType.arity() == 1) { d_processQueue.push_back(d_rules->dummyTheorem(d_facts, e.eqExpr(cons))); d_processQueueKind.push_back(ENQUEUE); return; } // create vars vector vars; for (int i = 0; i < consType.arity()-1; ++i) { vars.push_back(getEM()->newBoundVarExpr(consType[i])); } Expr e2 = getEM()->newClosureExpr(EXISTS, vars, e.eqExpr(Expr(cons.mkOp(), vars))); d_processQueue.push_back(d_rules->dummyTheorem(d_facts, e2)); d_processQueueKind.push_back(ENQUEUE); e.setTranslated(); } void TheoryDatatypeLazy::initializeLabels(const Expr& e, const Type& t) { DebugAssert(findExpr(e) == e, "datatype: initializeLabels: Expected find(e)=e"); DebugAssert(d_datatypes.find(t.getExpr()) != d_datatypes.end(), "Unknown datatype: "+t.getExpr().toString()); ExprMap& c = d_datatypes[t.getExpr()]; DebugAssert(d_labels.find(e) == d_labels.end(), "datatype: initializeLabels: expected unlabeled expr"); if (isConstructor(e)) { Expr cons = getConstructor(e); DebugAssert(c.find(cons) != c.end(), "datatype: initializeLabels: Couldn't find constructor " +cons.toString()); unsigned position = c[cons]; d_labels.insert(e, SmartCDO(theoryCore()->getCM()->getCurrentContext(), 1 << position, 0)); } else { DebugAssert(c.size() > 0, "No constructors?"); Unsigned value = ((Unsigned)1 << unsigned(c.size())) - 1; d_labels.insert(e, SmartCDO(theoryCore()->getCM()->getCurrentContext(), value, 0)); if (value == 1) instantiate(e, 1); else if (!d_typeComplete) { d_splitters.push_back(e); } } } void TheoryDatatypeLazy::mergeLabels(const Theorem& thm, const Expr& e1, const Expr& e2) { DebugAssert(e2.hasFind(), "datatype: mergeLabels: Expected hasFind(e2)"); Theorem fthm = find(e2); const Expr& f = fthm.getRHS(); DebugAssert(d_labels.find(e1) != d_labels.end() && d_labels.find(f) != d_labels.end(), "mergeLabels: expr is not labeled"); DebugAssert(e1.getType() == f.getType(), "Expected same type"); Unsigned u = d_labels[f].get().get(); Unsigned uNew = u & d_labels[e1].get().get(); if (u != uNew) { if (e2 != f) d_facts.push_back(fthm); if (!thm.isNull()) d_facts.push_back(thm); d_labels[f].get().set(uNew); if (uNew == 0) { setInconsistent(d_rules->dummyTheorem(d_facts, falseExpr())); return; } } if (uNew != 0 && ((uNew - 1) & uNew) == 0) { instantiate(f, uNew); } } void TheoryDatatypeLazy::mergeLabels(const Theorem& thm, const Expr& e, unsigned position, bool positive) { DebugAssert(e.hasFind(), "datatype: mergeLabels2: Expected hasFind(e)"); Theorem fthm = find(e); const Expr& f = fthm.getRHS(); DebugAssert(d_labels.find(f) != d_labels.end(), "mergeLabels2: expr is not labeled"); Unsigned u = d_labels[f].get().get(); Unsigned uNew = (Unsigned)1 << position; if (positive) { uNew = u & uNew; if (u == uNew) return; } else if ((u & uNew) != 0) uNew = u - uNew; else return; if (e != f) d_facts.push_back(fthm); d_facts.push_back(thm); d_labels[f].get().set(uNew); if (uNew == 0) setInconsistent(d_rules->dummyTheorem(d_facts, falseExpr())); else if (((uNew - 1) & uNew) == 0) { instantiate(f, uNew); } } void TheoryDatatypeLazy::checkSat(bool fullEffort) { bool done = false; while (!done && d_splittersIndex < d_splitters.size()) { Expr e = d_splitters[d_splittersIndex]; if (findExpr(e) == e) { DebugAssert(d_labels.find(e) != d_labels.end(), "checkSat: expr is not labeled"); Unsigned u = d_labels[e].get().get(); if ((u & (u-1)) != 0) { done = true; DebugAssert(!d_splitterAsserted || !fullEffort, "splitter should have been resolved"); if (!d_splitterAsserted) { DebugAssert (d_datatypes.find(e.getType().getExpr()) != d_datatypes.end(), "datatype: checkSat: Unexpected type: "+e.getType().toString() +"\n\n for expression: "+e.toString()); ExprMap& c = d_datatypes[e.getType().getExpr()]; ExprMap::iterator c_it = c.begin(), c_end = c.end(); for (; c_it != c_end; ++c_it) { if ((u & ((Unsigned)1 << unsigned((*c_it).second))) != 0) break; } DebugAssert(c_it != c_end, "datatype: checkSat: couldn't find constructor"); addSplitter(datatypeTestExpr((*c_it).first.getName(), e)); d_splitterAsserted = true; } } } if (!done) { d_splitterAsserted = false; d_splittersIndex = d_splittersIndex + 1; } } while (!done && d_processIndex < d_processQueue.size()) { d_typeComplete = true; Theorem e = d_processQueue[d_processIndex]; int kind = d_processQueueKind[d_processIndex]; switch (kind) { case MERGE1: { break; } case ENQUEUE: done = true; enqueueFact(e); break; case MERGE2: { const Expr& lhs = e.getLHS(); const Expr& rhs = e.getRHS(); Theorem thm(e); if (lhs.isSelected() && !rhs.isSelected()) { d_facts.push_back(e); rhs.setSelected(); thm = Theorem(); } mergeLabels(thm, lhs, rhs); break; } default: DebugAssert(false, "Unknown case"); } d_processIndex = d_processIndex + 1; } } void TheoryDatatypeLazy::setup(const Expr& e) { if (e.getType().getExpr().getKind() == DATATYPE && d_labels.find(e) == d_labels.end()) { initializeLabels(e, e.getType()); e.addToNotify(this, Expr()); } if (e.getKind() != APPLY) return; if (isConstructor(e) && e.arity() > 0) { d_processQueue.push_back(d_rules->noCycle(e)); d_processQueueKind.push_back(ENQUEUE); } if (isSelector(e)) { e[0].setSelected(); d_processQueue.push_back(reflexivityRule(e[0])); d_processQueueKind.push_back(MERGE2); } setupCC(e); } void TheoryDatatypeLazy::update(const Theorem& e, const Expr& d) { if (d.isNull()) { const Expr& lhs = e.getLHS(); const Expr& rhs = e.getRHS(); if (isConstructor(lhs) && isConstructor(rhs) && lhs.isApply() && rhs.isApply() && lhs.getOpExpr() == rhs.getOpExpr()) { d_processQueue.push_back(d_rules->decompose(e)); d_processQueueKind.push_back(ENQUEUE); } else { d_processQueue.push_back(e); d_processQueueKind.push_back(MERGE2); } } else { const Theorem& dEQdsig = d.getSig(); if (!dEQdsig.isNull()) { const Expr& dsig = dEQdsig.getRHS(); Theorem thm = updateHelper(d); const Expr& sigNew = thm.getRHS(); if (sigNew == dsig) return; dsig.setRep(Theorem()); if (isSelector(sigNew) && canCollapse(sigNew)) { d.setSig(Theorem()); d_processQueue.push_back(transitivityRule(thm, d_rules->rewriteSelCons(d_facts, sigNew))); d_processQueueKind.push_back(ENQUEUE); } else if (isTester(sigNew) && isConstructor(sigNew[0])) { d.setSig(Theorem()); d_processQueue.push_back(transitivityRule(thm, d_rules->rewriteTestCons(sigNew))); d_processQueueKind.push_back(ENQUEUE); } else { const Theorem& repEQsigNew = sigNew.getRep(); if (!repEQsigNew.isNull()) { d.setSig(Theorem()); d_processQueue.push_back(transitivityRule(repEQsigNew, symmetryRule(thm))); d_processQueueKind.push_back(ENQUEUE); } else { int k, ar(d.arity()); for (k = 0; k < ar; ++k) { if (sigNew[k] != dsig[k]) { sigNew[k].addToNotify(this, d); } } d.setSig(thm); sigNew.setRep(thm); getEM()->invalidateSimpCache(); } } } } } cvc3-2.4.1/src/cvc3/0000775000175400017540000000000011630011320013666 5ustar mdetersmdeterscvc3-2.4.1/src/cvc3/Makefile0000664000175400017540000000063711277122577015364 0ustar mdetersmdeters################################################## # About this Makefile # # This Makefile depends on Makefile.opts ################################################## MODULE = cvc3 SRC = main.cpp EXECUTABLE = $(PROJECTNAME) EXTRAFLAGS = -DVERSION=\"$(VERSION)\" LD_LIBS = -l$(PROJECTNAME) OTHER_DEPENDENCIES = $(TOP)/lib/$(PLATFORM_WITH_OPTIONS)/$(LIB_BASE_NAME).$(LIB_SUFFIX) include ../../Makefile.local cvc3-2.4.1/src/cvc3/main.cpp0000644000175400017540000002310311624746721015342 0ustar mdetersmdeters/*****************************************************************************/ /*! * \file main.cpp * \brief Main program for cvc3 * * Author: Clark Barrett * * Created: Wed Dec 4 17:21:10 2002 * *
* * License to use, copy, modify, sell and/or distribute this software * and its documentation for any purpose is hereby granted without * royalty, subject to the terms and conditions defined in the \ref * LICENSE file provided with this distribution. * *
* */ /*****************************************************************************/ #include #include #include #include "os.h" #include "vc.h" #include "parser.h" #include "vc_cmd.h" #include "command_line_flags.h" #include "statistics.h" #ifdef _MSC_VER #include #else #include #endif using namespace std; using namespace CVC3; static void parse_args(int argc, char **argv, CLFlags &flags, string& fileName); static void printUsage(const CLFlags& flags, bool followDisplay); // Our own name static string programName; static ValidityChecker* vc = NULL; IF_DEBUG(static DebugTimer* pRuntime = NULL;) #ifndef _MSC_VER void sighandler(int signum) { cerr << "\nInterrupted by signal " << signum; if(signum == SIGALRM) cerr << " (self-timeout)"; cerr << ". " << programName << " is aborting.\n"; // Print the debugging info IF_DEBUG(if (pRuntime != NULL) CVC3::debugger.setElapsed(*pRuntime);) IF_DEBUG(debugger.printAll();) if(vc != NULL && vc->getFlags()["stats"].getBool()) cout << vc->getStatistics() << endl; if(vc != NULL) { // If deletion causes another signal, don't keep trying. // This is here to ensure that logs are dumped, etc. ValidityChecker* toDelete = vc; vc = NULL; delete toDelete; } abort(); } #else DWORD WINAPI thread_timeout(PVOID timeout) { Sleep((int)timeout * 1000); cerr << "(self-timeout)." << endl; if(vc != NULL && vc->getFlags()["stats"].getBool()) cout << vc->getStatistics() << endl; if(vc != NULL) { // If deletion causes another signal, don't keep trying. // This is here to ensure that logs are dumped, etc. ValidityChecker* toDelete = vc; vc = NULL; delete toDelete; } ExitProcess(1); } #endif int main(int argc, char **argv) { CLFlags flags(ValidityChecker::createFlags()); programName = string(argv[0]); IF_DEBUG(DebugTimer runtime(CVC3::debugger.timer("total runtime"));) IF_DEBUG(pRuntime = &runtime;) #ifndef _MSC_VER signal(SIGINT, sighandler); signal(SIGTERM, sighandler); signal(SIGQUIT, sighandler); signal(SIGALRM, sighandler); signal(SIGSEGV, sighandler); #endif string fileName(""); try { parse_args(argc, argv, flags, fileName); } catch(Exception& e) { cerr << "*** " << e; cerr << "\n\nRun with -help option for usage information." << endl; exit(1); } // In SMT-LIBv2, don't save the model between distinct check-sats // (unless user specifically requested it) if(flags["lang"].getString() != "" && getLanguage(flags["lang"].getString()) == SMTLIB_V2_LANG && !flags["internal::userSetNoSaveModel"].getBool()) { flags.setFlag("no-save-model", true); } // Set the timeout, if given in the command line options int timeout = flags["timeout"].getInt(); if(timeout > 0) { #ifndef _MSC_VER alarm(timeout); #else // http://msdn2.microsoft.com/en-us/library/ms682453.aspx CreateThread(NULL, 0, thread_timeout, (PVOID)timeout, 0, NULL); #endif } /* * Create and run the validity checker */ // Debugging code may throw an exception try { vc = ValidityChecker::create(flags); } catch(Exception& e) { cerr << "*** Fatal exception: " << e << endl; exit(1); } // -h flag sets "help" to false (+h would make it true, but that's // not what the user normally types in). if(!vc->getFlags()["help"].getBool()) { printUsage(vc->getFlags(), true); return 0; } if(!vc->getFlags()["unsupported"].getBool()) { printUsage(vc->getFlags(), false); return 0; } #ifndef VERSION #define VERSION "unknown" #endif // Similarly, -version sets the flag "version" to false if(!vc->getFlags()["version"].getBool()) { cout << "This is CVC3 version " << VERSION IF_DEBUG( << " (debug build)") << "\n\n"; cout << "Copyright (C) 2003-2010 by the Board of Trustees of Leland Stanford Junior\n" "University, New York University, and the University of Iowa.\n\n" "THIS SOFTWARE PROVIDED AS-IS, WITHOUT ANY WARRANTIES. " "USE IT AT YOUR OWN RISK.\n" << endl; return 0; } try { // Calling getOutputLang() tests if the output language is // correctly specified; if not, an exception will be thrown InputLanguage outlang = vc->getEM()->getOutputLang(); if(outlang == SPASS_LANG && vc->getFlags()["translate"].getBool() && !vc->getFlags()["liftITE"].modified()) { // SPASS doesn't support ITE; make sure there are none vc->getFlags().setFlag("liftITE", true); } // Set the timer IF_DEBUG(CVC3::debugger.setCurrentTime(runtime);) // Read the input file vc->loadFile(fileName, vc->getEM()->getInputLang(), flags["interactive"].getBool()); } catch(Exception& e) { cerr << "*** Fatal exception: " << e << endl; exit(1); } IF_DEBUG(CVC3::debugger.setElapsed(runtime);) // Print the debugging info IF_DEBUG(debugger.printAll();) // Print statistics if(vc->getFlags()["stats"].getBool()) vc->printStatistics(); // Destruct the system TRACE_MSG("delete", "Deleting ValidityChecker [last trace from main.cpp]"); try { // The signal handler deletes the vc. If deletion segfaults, we don't // want to try it again. ValidityChecker* toDelete = vc; vc = NULL; delete toDelete; } catch(Exception& e) { cerr << "*** Fatal exception: " << e << endl; exit(1); } return 0; } void printUsage(const CLFlags& flags, bool followDisplay) { cout << "Usage: " << programName << " [options]\n" << programName << " will read the input from STDIN and \n" << "print the result on STDOUT.\n" << "Boolean (b) options are set 'on' by +option and 'off' by -option\n" << "(for instance, +model or -model).\n" << "Integer (i), string (s) and vector (v) options \n" << "require a parameter, e.g. -width 80\n" << "Also, (v) options can appear multiple times setting " << "args on and off,\n" << "as in +trace \"enable this\" -trace \"disable that\".\n" << "Option names can be abbreviated to the " << "shortest unambiguous prefix.\n\n" << "The options are:\n"; vector names; // Get all the names of options (they all match the empty string) flags.countFlags("", names); for(size_t i=0,iend=names.size(); i!=iend; ++i) { const CLFlag& f(flags[names[i]]); if (f.display() != followDisplay) continue; string tpStr; // Print type of the option string pref; // Print + or - in front of the option string name(names[i]); // Print name and optionally the value CLFlagType tp = f.getType(); switch(tp) { case CLFLAG_NULL: tpStr = "(null)"; break; case CLFLAG_BOOL: tpStr = "(b)"; pref = (f.getBool())? "+" : "-"; break; case CLFLAG_INT: tpStr = "(i)"; pref = "-"; name = name+" "+int2string(f.getInt()); break; case CLFLAG_STRING: tpStr = "(s)"; pref = "-"; name = name+" "+f.getString(); break; case CLFLAG_STRVEC: tpStr = "(v)"; pref = "-"; name = name; break; default: DebugAssert(false, "printUsage: unknown flag type"); } cout << " " << tpStr << " " << pref << setw(25); cout.setf(ios::left); cout << name << " " << f.getHelp() << "\n"; } cout << endl; } void parse_args(int argc, char **argv, CLFlags &flags, string& fileName) { /* skip 0'th argument */ argv++; argc--; bool seenFileName(false); for( ; argc > 0; argc--, argv++) { if((*argv)[0] == '-' || (*argv)[0] == '+') { // A command-line option vector names; bool val = ((*argv)[0] == '+'); size_t n = flags.countFlags((*argv)+1, names); if(n == 0) throw CLException(string(*argv) + " does not match any known option"); else if(n > 1) { ostringstream ss; ss << *argv << " is ambiguous. Possible matches are:\n"; for(size_t i=0,iend=names.size(); i!=iend; ++i) { ss << " " << names[i] << "\n"; } throw CLException(ss.str()); } else { string name = names[0]; if(name == "no-save-model") { flags.setFlag("internal::userSetNoSaveModel", true); } // Single match; process the option CLFlagType tp = flags[name].getType(); switch(tp) { case CLFLAG_BOOL: flags.setFlag(name, val); break; case CLFLAG_INT: argc--; if(argc <= 0) throw CLException(string(*argv)+" (-"+name +") expects an integer argument."); argv++; // FIXME: test for *argv being an integer string flags.setFlag(name, atoi(*argv)); break; case CLFLAG_STRING: argc--; if(argc <= 0) throw CLException(string(*argv)+" (-"+name +") expects a string argument."); argv++; flags.setFlag(name, *argv); break; case CLFLAG_STRVEC: argc--; if(argc <= 0) throw CLException(string(*argv)+" (-"+name +") expects a string argument."); argv++; flags.setFlag(name, pair(*argv,val)); break; default: DebugAssert(false, "parse_args: Bad flag type: "+int2string(tp)); } } } else if(seenFileName) { throw CLException("More than one file name given: "+fileName +" and "+string(*argv)); } else { fileName = string(*argv); seenFileName = true; } } } cvc3-2.4.1/src/parser/0000775000175400017540000000000011630011320014324 5ustar mdetersmdeterscvc3-2.4.1/src/parser/Makefile0000664000175400017540000000423511406210050015772 0ustar mdetersmdetersMODULE = parser LIBRARY=libparser.a # Do not optimize the parser code - it compiles forever in some gcc versions EXTRAFLAGS = -O0 TRANSIENT_CPP = \ parsePL.cpp lexPL.cpp \ parseLisp.cpp lexLisp.cpp \ parsesmtlib.cpp lexsmtlib.cpp \ parsesmtlib2.cpp lexsmtlib2.cpp TRANSIENT = $(TRANSIENT_CPP) \ parsePL_defs.h parsePL.output \ parseLisp_defs.h parseLisp.output \ parsesmtlib_defs.h parsesmtlib.output \ parsesmtlib2_defs.h parsesmtlib2.output SRC = $(TRANSIENT_CPP) parser.cpp HEADERS = parser_temp.h # The actual source files for the parser that we want to include in a # distribution SRC_ORIG = PL.lex PL.y Lisp.lex Lisp.y smtlib.lex smtlib.y smtlib2.lex smtlib2.y parser.cpp include ../../Makefile.local ################################################## # Rules for transient files ################################################## lexPL.cpp: PL.lex parsePL_defs.h $(LEX) $(LFLAGS) -I -PPL -olexPL.cpp PL.lex parsePL_defs.h: parsePL.cpp parsePL.cpp: PL.y $(YACC) $(YFLAGS) -o parsePL.cpp -p PL --debug -v PL.y @if [ -f parsePL.cpp.h ]; then mv parsePL.cpp.h parsePL.hpp; fi @mv parsePL.hpp parsePL_defs.h lexLisp.cpp: Lisp.lex parseLisp_defs.h $(LEX) $(LFLAGS) -I -PLisp -olexLisp.cpp Lisp.lex parseLisp_defs.h: parseLisp.cpp parseLisp.cpp: Lisp.y $(YACC) $(YFLAGS) -o parseLisp.cpp -p Lisp --debug -v Lisp.y @if [ -f parseLisp.cpp.h ]; then mv parseLisp.cpp.h parseLisp.hpp; fi @mv parseLisp.hpp parseLisp_defs.h lexsmtlib.cpp: smtlib.lex parsesmtlib_defs.h $(LEX) $(LFLAGS) -I -Psmtlib -olexsmtlib.cpp smtlib.lex parsesmtlib_defs.h: parsesmtlib.cpp parsesmtlib.cpp: smtlib.y $(YACC) $(YFLAGS) -o parsesmtlib.cpp -p smtlib --debug -v smtlib.y @if [ -f parsesmtlib.cpp.h ]; then mv parsesmtlib.cpp.h parsesmtlib.hpp; fi @mv parsesmtlib.hpp parsesmtlib_defs.h lexsmtlib2.cpp: smtlib2.lex parsesmtlib2_defs.h $(LEX) $(LFLAGS) -I -Psmtlib2 -olexsmtlib2.cpp smtlib2.lex parsesmtlib2_defs.h: parsesmtlib2.cpp parsesmtlib2.cpp: smtlib2.y $(YACC) $(YFLAGS) -o parsesmtlib2.cpp -p smtlib2 --debug -v smtlib2.y @if [ -f parsesmtlib2.cpp.h ]; then mv parsesmtlib2.cpp.h parsesmtlib2.hpp; fi @mv parsesmtlib2.hpp parsesmtlib2_defs.h cvc3-2.4.1/src/parser/parser.cpp0000664000175400017540000001665011413171425016350 0ustar mdetersmdeters/*****************************************************************************/ /*! * \file parser.cpp * \brief The top-level API to the parser. See parser.h for details. * * Author: Sergey Berezin * * Created: Wed Feb 5 11:46:57 2003 * *
* * License to use, copy, modify, sell and/or distribute this software * and its documentation for any purpose is hereby granted without * royalty, subject to the terms and conditions defined in the \ref * LICENSE file provided with this distribution. * *
* */ /*****************************************************************************/ #include #include #include "parser_temp.h" #include "parser.h" #include "parser_exception.h" #include "vc.h" #include "command_line_flags.h" using namespace std; // The communication entry points of the actual parsers // for presentation language (PL.y and PL.lex) extern int PLparse(); extern void *PL_createBuffer(int); extern void PL_deleteBuffer(void *); extern void PL_switchToBuffer(void *); extern int PL_bufSize(); extern void *PL_bufState(); void PL_setInteractive(bool); // for Lisp language (Lisp.y and Lisp.lex) extern int Lispparse(); extern void *Lisp_createBuffer(int); extern void Lisp_deleteBuffer(void *); extern void Lisp_switchToBuffer(void *); extern int Lisp_bufSize(); extern void *LispBufState(); void Lisp_setInteractive(bool); // for Lisp language (Lisp.y and Lisp.lex) extern int Lispparse(); extern void *Lisp_createBuffer(int); extern void Lisp_deleteBuffer(void *); extern void Lisp_switchToBuffer(void *); extern int Lisp_bufSize(); extern void *LispBufState(); void Lisp_setInteractive(bool); // for smtlib language (smtlib.y and smtlib.lex) extern int smtlibparse(); extern void *smtlib_createBuffer(int); extern void smtlib_deleteBuffer(void *); extern void smtlib_switchToBuffer(void *); extern int smtlib_bufSize(); extern void *smtlibBufState(); void smtlib_setInteractive(bool); // for smtlib language v2 (smtlib2.y and smtlib2.lex) extern int smtlib2parse(); extern void *smtlib2_createBuffer(int); extern void smtlib2_deleteBuffer(void *); extern void smtlib2_switchToBuffer(void *); extern int smtlib2_bufSize(); extern void *smtlib2BufState(); void smtlib2_setInteractive(bool); namespace CVC3 { // The global pointer to ParserTemp. Each instance of class Parser // sets this pointer before any calls to the lexer. We do it this // way because flex and bison use global vars, and we want each // Parser object to appear independent. // FIXME: This should probably go away eventually, when I figure out // flex++ -- Sergey. ParserTemp* parserTemp; int ParserTemp::error(const string& s) { throw ParserException(s); return 0; } // Internal storage class; I'll use member names without 'd_'s here class ParserData { public: // Which language to use InputLanguage lang; // Is the input given by the file name or as istream? bool useName; ParserTemp temp; // Internal buffer used by the parser void* buffer; }; // Constructors Parser::Parser(ValidityChecker* vc, Translator* translator, InputLanguage lang, bool interactive, const std::string& fileName) : d_data(new ParserData) { d_data->temp.vc = vc; d_data->temp.translator = translator; d_data->lang = lang; if(fileName == "") { // Use std::cin d_data->useName = false; d_data->temp.is = &cin; d_data->temp.fileName = "stdin"; d_data->temp.interactive = interactive; } else { // Open the file by name d_data->useName = true; d_data->temp.fileName = fileName; d_data->temp.is = new ifstream(fileName.c_str()); if (!(*d_data->temp.is)) { throw ParserException("File not found: "+fileName); } d_data->temp.interactive = false; } initParser(); } Parser::Parser(ValidityChecker* vc, Translator* translator, InputLanguage lang, std::istream& is, bool interactive) : d_data(new ParserData) { d_data->temp.vc = vc; d_data->temp.translator = translator; d_data->lang = lang; d_data->useName = false; d_data->temp.is = &is; d_data->temp.fileName = "stdin"; d_data->temp.interactive = interactive; initParser(); } // Destructor Parser::~Parser() { if(d_data->useName) // Stream is ours; delete it delete d_data->temp.is; deleteParser(); delete d_data; } // Initialize the actual parser void Parser::initParser() { switch(d_data->lang) { case PRESENTATION_LANG: d_data->buffer = PL_createBuffer(PL_bufSize()); d_data->temp.lineNum = 1; break; case LISP_LANG: d_data->buffer = Lisp_createBuffer(Lisp_bufSize()); d_data->temp.lineNum = 1; break; case SMTLIB_LANG: d_data->buffer = smtlib_createBuffer(smtlib_bufSize()); d_data->temp.lineNum = 1; break; case SMTLIB_V2_LANG: d_data->buffer = smtlib2_createBuffer(smtlib2_bufSize()); d_data->temp.lineNum = 1; // SMT2 uses '=' for IFF d_data->temp.vc->getFlags().setFlag("convert-eq-iff",true); break; default: FatalAssert(false, "Bad input language specified"); exit(1); } } // Clean up the parser's internal data structures void Parser::deleteParser() { switch(d_data->lang) { case PRESENTATION_LANG: PL_deleteBuffer(d_data->buffer); break; case LISP_LANG: Lisp_deleteBuffer(d_data->buffer); break; case SMTLIB_LANG: smtlib_deleteBuffer(d_data->buffer); break; case SMTLIB_V2_LANG: smtlib2_deleteBuffer(d_data->buffer); break; default: FatalAssert(false, "Bad input language specified"); } } Expr Parser::next() { // If no more commands are available, return a Null Expr if(d_data->temp.done) return Expr(); // Set the global var so the parser uses the right stream and EM parserTemp = &(d_data->temp); // Switch to our buffer, in case there are multiple instances of // the parser running try { switch(d_data->lang) { case PRESENTATION_LANG: PL_switchToBuffer(d_data->buffer); PL_setInteractive(d_data->temp.interactive); PLparse(); // Reset the prompt to the main one d_data->temp.setPrompt1(); break; case LISP_LANG: Lisp_switchToBuffer(d_data->buffer); Lisp_setInteractive(d_data->temp.interactive); Lispparse(); // Reset the prompt to the main one d_data->temp.setPrompt1(); break; case SMTLIB_LANG: smtlib_switchToBuffer(d_data->buffer); smtlib_setInteractive(d_data->temp.interactive); smtlibparse(); // Reset the prompt to the main one d_data->temp.setPrompt1(); break; case SMTLIB_V2_LANG: smtlib2_switchToBuffer(d_data->buffer); smtlib2_setInteractive(d_data->temp.interactive); smtlib2parse(); // Reset the prompt to the main one d_data->temp.setPrompt1(); break; default: { ostringstream ss; ss << "Bad input language specified: " << d_data->lang; DebugAssert(false, ss.str().c_str()); exit(1); } } } catch(Exception* e) { cerr << d_data->temp.fileName << ":" << d_data->temp.lineNum << ": " << e << endl; return Expr(); } return d_data->temp.expr; } bool Parser::done() const { return d_data->temp.done; } void Parser::printLocation(ostream & out) const { out << d_data->temp.fileName << ":" << d_data->temp.lineNum; } void Parser::reset() { d_data->temp.expr = Expr(); } } // end of namespace CVC3 cvc3-2.4.1/src/parser/PL.y0000664000175400017540000015750511254027064015064 0ustar mdetersmdeters%{ /*****************************************************************************/ /*! * \file PL.y * * Author: Sergey Berezin * * Created: Feb 06 03:00:43 GMT 2003 * *
* * License to use, copy, modify, sell and/or distribute this software * and its documentation for any purpose is hereby granted without * royalty, subject to the terms and conditions defined in the \ref * LICENSE file provided with this distribution. * *
* */ /*****************************************************************************/ /* PL.y Aaron Stump, 4/14/01 This file contains the bison code for the parser that reads in CVC commands in the presentation language (hence "PL"). */ #include "vc.h" #include "parser_exception.h" #include "parser_temp.h" #include "rational.h" // Exported shared data namespace CVC3 { extern ParserTemp* parserTemp; } // Define shortcuts for various things #define TMP CVC3::parserTemp #define EXPR CVC3::parserTemp->expr #define VC (CVC3::parserTemp->vc) #define RAT(args) CVC3::newRational args // Suppress the bogus warning suppression in bison (it generates // compile error) #undef __GNUC_MINOR__ /* stuff that lives in PL.lex */ extern int PLlex(void); int PLerror(const char *s) { std::ostringstream ss; ss << CVC3::parserTemp->fileName << ":" << CVC3::parserTemp->lineNum << ": " << s; return CVC3::parserTemp->error(ss.str()); } namespace CVC3 { // File-static auxiliary funcion to wrap accessors upto the index i // (not inclusive) around "e". Used to rebuild the UPDATE expressions. static Expr wrapAccessors(const Expr& e, const std::vector& accessors, const int i) { DebugAssert((int)accessors.size() >= i, "wrapAccessors: too few accessors"); Expr res(e); for(int j=0; jlistExpr(acc, res); break; case RAW_LIST: DebugAssert(acc.arity() == 2 && acc[0].getKind() == ID, "PL.y: wrong number of arguments in the accessor of WITH: " +acc.toString()); res = VC->listExpr(acc[0], res, acc[1]); break; default: DebugAssert(false, "PL.y: Bad accessor in WITH: "+acc.toString()); } } return res; } // Convert a complex WITH statement into a bunch of nested simple UPDATEs // Updator "e1 WITH accessors := e2" is represented as // (e1 (accessor1 accessor2 ... ) e2), where the accessors are: // (READ idx) // ID (datatype constructor's argument) // (RECORD_SELECT ID) // and (TUPLE_SELECT num). // We rebuild this into nested RECORD_UPDATE, WRITE, // TUPLE_UPDATE, and DATATYPE_UPDATE expressions. For example: // // e WITH [idx] car.f := newVal is transformed into // e WITH [idx] := (e[idx] WITH car := (car(e[idx]) WITH .f := newVal)) // which is represented as // (WRITE e idx // (DATATYPE_UPDATE (READ e idx) car // (RECORD_UPDATE (car (READ e idx)) f newVal))). // Here "car" and "f" are identifiers (ID "car") and (ID "f"). static Expr PLprocessUpdate(const CVC3::Expr& e, const CVC3::Expr& update) { TRACE("parser verbose", "PLprocessUpdate(", e, ") {"); DebugAssert(update.arity() == 2,"PL.y: Bad WITH statement: " +update.toString()); // Rebuild accessors: resolve ID in (READ (ID "name")) and leave // the rest alone TRACE("parser verbose", "PLprocessUpdate: update[0] = ", update[0], ""); std::vector acc; for(Expr::iterator i=update[0].begin(), iend=update[0].end(); i!=iend; ++i) { TRACE("parser verbose", "*i = ", *i, ""); acc.push_back(*i); } TRACE("parser verbose", "acc.size() = ", acc.size(), ""); TRACE("parser verbose", "accessors = ", VC->listExpr(acc), ""); // 'res' serves as the accumulator of updators; initially it is // newVal (which is update[1]). We run through accessors in reverse // order, wrapping this accumulator with the corresponding // updators. Expr res(update[1]); // Rebuilding the original expression "e" // The main loop for(int i=acc.size()-1; i>=0; i--) { Expr ac(acc[i]); // The current accessor TRACE("parser verbose", "ac["+int2string(i)+"] = ", ac, ""); // "e" with all preceding accessors Expr tmp(wrapAccessors(e, acc, i)); TRACE("parser verbose", "tmp = ", tmp, ""); switch(ac.getKind()) { case ID: // Datatype update res = VC->listExpr("_DATATYPE_UPDATE", tmp, ac, res); break; case RAW_LIST: { const std::string& kind = ac[0][0].getString(); if(kind == "_READ") // Array update res = VC->listExpr("_WRITE", tmp, ac[1], res); else if(kind == "_RECORD_SELECT") // Record update res = VC->listExpr("_RECORD_UPDATE", tmp, ac[1], res); else if(kind == "_TUPLE_SELECT") // Tuple element res = VC->listExpr("_TUPLE_UPDATE", tmp, ac[1], res); else DebugAssert(false, "PL.y: Bad accessor in WITH: "+ac.toString()); break; } default: DebugAssert(false, "PL.y: Bad accessor in WITH: "+ac.toString()); } } TRACE("parser verbose", "PLprocessUpdate => ", res, " }"); return res; } // Process a vector of simultaneous updates (from a single WITH) static Expr PLprocessUpdates(const CVC3::Expr& e, const std::vector& updates, size_t idx=0) { // Processed all the updates if(idx >= updates.size()) return e; return PLprocessUpdates(PLprocessUpdate(e, updates[idx]), updates, idx+1); } } // end of namespace CVC3 #define YYLTYPE_IS_TRIVIAL 1 #define YYMAXDEPTH 10485760 /* Prefer YYERROR_VERBOSE over %error-verbose to avoid errors in older bison */ #define YYERROR_VERBOSE 1 %} %union { std::string *str; CVC3::Expr *node; std::vector *vec; int kind; }; %start cmd /* strings are for better error messages. "_TOK" is so macros don't conflict with kind names */ %token DISTINCT_TOK "DISTINCT" %token AND_TOK "AND" %token ARRAY_TOK "ARRAY" %token BOOLEAN_TOK "BOOLEAN" %token DATATYPE_TOK "DATATYPE" %token ELSE_TOK "ELSE" %token ELSIF_TOK "ELSIF" %token END_TOK "END" %token ENDIF_TOK "ENDIF" %token EXISTS_TOK "EXISTS" %token FALSELIT_TOK "FALSE" %token FORALL_TOK "FORALL" %token IN_TOK "IN" %token IF_TOK "IF" %token LAMBDA_TOK "LAMBDA" %token SIMULATE_TOK "SIMULATE" %token LET_TOK "LET" %token NOT_TOK "NOT" %token IS_INTEGER_TOK "IS_INTEGER" %token OF_TOK "OF" %token OR_TOK "OR" %token REAL_TOK "REAL" %token INT_TOK "INT" %token SUBTYPE_TOK "SUBTYPE" %token BITVECTOR_TOK "BITVECTOR" %token THEN_TOK "THEN" %token TRUELIT_TOK "TRUE" %token TYPE_TOK "TYPE" %token WITH_TOK "WITH" %token XOR_TOK "XOR" %token TCC_TOK "TCC" %token PATTERN_TOK "PATTERN" %token '_' %token DONE_TOK %token DOTDOT_TOK ".." %token ASSIGN_TOK ":=" %token NEQ_TOK "/=" %token IMPLIES_TOK "=>" %token IFF_TOK "<=>" %token PLUS_TOK "+" %token MINUS_TOK "-" %token MULT_TOK "*" %token POW_TOK "^" %token DIV_TOK "/" %token MOD_TOK "MOD" %token INTDIV_TOK "DIV" %token LT_TOK "<" %token LE_TOK "<=" %token GT_TOK ">" %token GE_TOK ">=" %token FLOOR_TOK "FLOOR" %token LEFTSHIFT_TOK "<<" %token RIGHTSHIFT_TOK ">>" %token BVPLUS_TOK "BVPLUS" %token BVSUB_TOK "BVSUB" %token BVUDIV_TOK "BVUDIV" %token BVSDIV_TOK "BVSDIV" %token BVUREM_TOK "BVUREM" %token BVSREM_TOK "BVSREM" %token BVSMOD_TOK "BVSMOD" %token BVSHL_TOK "BVSHL" %token BVASHR_TOK "BVASHR" %token BVLSHR_TOK "BVLSHR" %token BVUMINUS_TOK "BVUMINUS" %token BVMULT_TOK "BVMULT" %token SQHASH_TOK "[#" %token HASHSQ_TOK "#]" %token PARENHASH_TOK "(#" %token HASHPAREN_TOK "#)" %token ARROW_TOK "->" %token BVNEG_TOK "~" %token BVAND_TOK "&" %token MID_TOK "|" %token BVXOR_TOK "BVXOR" %token BVNAND_TOK "BVNAND" %token BVNOR_TOK "BVNOR" %token BVCOMP_TOK "BVCOMP" %token BVXNOR_TOK "BVXNOR" %token CONCAT_TOK "@" %token BVTOINT_TOK "BVTOINT" %token INTTOBV_TOK "INTTOBV" %token BOOLEXTRACT_TOK "BOOLEXTRACT" %token BVLT_TOK "BVLT" %token BVGT_TOK "BVGT" %token BVLE_TOK "BVLE" %token BVGE_TOK "BVGE" %token SX_TOK "SX" %token BVZEROEXTEND_TOK "BVZEROEXTEND" %token BVREPEAT_TOK "BVREPEAT" %token BVROTL_TOK "BVROTL" %token BVROTR_TOK "BVROTR" %token BVSLT_TOK "BVSLT" %token BVSGT_TOK "BVSGT" %token BVSLE_TOK "BVSLE" %token BVSGE_TOK "BVSGE" /* commands given in prefix syntax */ %token ARITH_VAR_ORDER_TOK "ARITH_VAR_ORDER" %token ASSERT_TOK "ASSERT" %token QUERY_TOK "QUERY" %token CHECKSAT_TOK "CHECKSAT" %token CONTINUE_TOK "CONTINUE" %token RESTART_TOK "RESTART" %token HELP_TOK "HELP" %token DBG_TOK "DBG" %token TRACE_TOK "TRACE" %token UNTRACE_TOK "UNTRACE" %token OPTION_TOK "OPTION" %token TRANSFORM_TOK "TRANSFORM" %token PRINT_TOK "PRINT" %token PRINT_TYPE_TOK "PRINT_TYPE" %token CALL_TOK "CALL" %token ECHO_TOK "ECHO" %token INCLUDE_TOK "INCLUDE" %token DUMP_PROOF_TOK "DUMP_PROOF" %token DUMP_ASSUMPTIONS_TOK "DUMP_ASSUMPTIONS" %token DUMP_SIG_TOK "DUMP_SIG" %token DUMP_TCC_TOK "DUMP_TCC" %token DUMP_TCC_ASSUMPTIONS_TOK "DUMP_TCC_ASSUMPTIONS" %token DUMP_TCC_PROOF_TOK "DUMP_TCC_PROOF" %token DUMP_CLOSURE_TOK "DUMP_CLOSURE" %token DUMP_CLOSURE_PROOF_TOK "DUMP_CLOSURE_PROOF" %token WHERE_TOK "WHERE" %token ASSERTIONS_TOK "ASSERTIONS" %token ASSUMPTIONS_TOK "ASSUMPTIONS" %token COUNTEREXAMPLE_TOK "COUNTEREXAMPLE" %token COUNTERMODEL_TOK "COUNTERMODEL" %token PUSH_TOK "PUSH" %token POP_TOK "POP" %token POPTO_TOK "POPTO" %token PUSH_SCOPE_TOK "PUSH_SCOPE" %token POP_SCOPE_TOK "POP_SCOPE" %token POPTO_SCOPE_TOK "POPTO_SCOPE" %token RESET_TOK "RESET" %token CONTEXT_TOK "CONTEXT" %token FORGET_TOK "FORGET" %token GET_TYPE_TOK "GET_TYPE" %token CHECK_TYPE_TOK "CHECK_TYPE" %token GET_CHILD_TOK "GET_CHILD" %token GET_OP_TOK "GET_OP" %token SUBSTITUTE_TOK "SUBSTITUTE" %nonassoc ASSIGN_TOK IN_TOK %nonassoc FORALL_TOK EXISTS_TOK %left IFF_TOK %right IMPLIES_TOK %left OR_TOK XOR_TOK %left AND_TOK %left NOT_TOK %nonassoc '=' NEQ_TOK %nonassoc LE_TOK LT_TOK GE_TOK GT_TOK FLOOR_TOK %left PLUS_TOK MINUS_TOK %left MULT_TOK INTDIV_TOK DIV_TOK MOD_TOK %left POW_TOK %left WITH_TOK %left UMINUS_TOK %left CONCAT_TOK %left MID_TOK %left BVAND_TOK %left BVXOR_TOK %left BVNAND_TOK %left BVNOR_TOK BVCOMP_TOK %left BVXNOR_TOK %left BVNEG_TOK %left BVUMINUS_TOK BVPLUS_TOK BVSUB_TOK %left BVUDIV_TOK BVSDIV_TOK BVUREM_TOK BVSREM_TOK BVSMOD_TOK BVSHL_TOK BVASHR_TOK BVLSHR_TOK %left SX_TOK BVZEROEXTEND_TOK BVREPEAT_TOK BVROTL_TOK BVROTR_TOK %left LEFTSHIFT_TOK RIGHTSHIFT_TOK %nonassoc BVLT_TOK BVLE_TOK BVGT_TOK BVGE_TOK %nonassoc BVSLT_TOK BVSLE_TOK BVSGT_TOK BVSGE_TOK %right IS_INTEGER_TOK %left ARROW_TOK %nonassoc '[' %nonassoc '{' '.' '(' %nonassoc BITVECTOR_TOK %type FieldDecls TypeList IDs reverseIDs SingleDataTypes Constructors %type LetDecls TypeLetDecls BoundVarDecls ElseRest VarDecls %type Exprs AndExpr OrExpr Pattern Patterns %type RecordEntries UpdatePosition Updates %type Type /* IndexType */ TypeNotIdentifier TypeDef %type DataType SingleDataType Constructor %type FunctionType RecordType Real Int BitvectorType %type FieldDecl TupleType %type ArrayType ScalarType SubType BasicType SubrangeType %type LeftBound RightBound %type Expr Conditional UpdatePositionNode Update Lambda %type QuantExpr ArrayLiteral RecordLiteral RecordEntry TupleLiteral %type LetDecl LetExpr LetDeclsNode %type TypeLetDecl TypeLetExpr TypeLetDeclsNode %type BoundVarDecl BoundVarDeclNode VarDecl %type ConstDecl TypeDecl %type Identifier StringLiteral Numeral Binary Hex %type Assert Query Help Dbg Trace Option %type Transform Print Call Echo DumpCommand %type Include Where Push Pop PopTo %type Context Forget Get_Child Get_Op Get_Type Check_Type Substitute %type other_cmd %type Arith_Var_Order %token ID_TOK STRINGLIT_TOK NUMERAL_TOK HEX_TOK BINARY_TOK %% cmd : TypeDecl ';' { EXPR = *$1; delete $1; YYACCEPT; } | ConstDecl ';' { EXPR = *$1; delete $1; YYACCEPT; } | other_cmd ';' { EXPR = *$1; delete $1; YYACCEPT; } | ';' { EXPR = CVC3::Expr(); YYACCEPT; } | DONE_TOK { TMP->done = true; EXPR = CVC3::Expr(); YYACCEPT; } ; other_cmd : Assert { $$ = $1; } | Query { $$ = $1; } | Dbg { $$ = $1; } | Trace { $$ = $1; } | Option { $$ = $1; } | Help { $$ = $1; } | Transform { $$ = $1; } | Print { $$ = $1; } | Call { $$ = $1; } | Echo { $$ = $1; } | Include { $$ = $1; } | DumpCommand { $$ = $1; } | Where { $$ = $1; } | Push { $$ = $1; } | Pop { $$ = $1; } | PopTo { $$ = $1; } | Context { $$ = $1; } | Substitute { $$ = $1; } | Get_Child { $$ = $1; } | Get_Op { $$ = $1; } | Get_Type { $$ = $1; } | Check_Type { $$ = $1; } | Forget { $$ = $1; } | Arith_Var_Order { $$ = $1; } ; Arith_Var_Order : ARITH_VAR_ORDER_TOK '(' Exprs ')' { $$ = new CVC3::Expr(VC->listExpr("_ARITH_VAR_ORDER", *$3)); delete $3; } ; Assert : ASSERT_TOK Expr { $$ = new CVC3::Expr(VC->listExpr("_ASSERT", *$2)); delete $2; } ; Query : QUERY_TOK Expr { $$ = new CVC3::Expr(VC->listExpr("_QUERY", *$2)); delete $2; } | CHECKSAT_TOK Expr { $$ = new CVC3::Expr(VC->listExpr("_CHECKSAT", *$2)); delete $2; } | CHECKSAT_TOK { $$ = new CVC3::Expr(VC->listExpr(VC->idExpr("_CHECKSAT"))); } | CONTINUE_TOK { $$ = new CVC3::Expr(VC->listExpr(VC->idExpr("_CONTINUE"))); } | RESTART_TOK Expr { $$ = new CVC3::Expr(VC->listExpr("_RESTART", *$2)); delete $2; } ; Dbg : DBG_TOK StringLiteral { $$ = new CVC3::Expr(VC->listExpr("_DBG", *$2)); delete $2; } | DBG_TOK { $$ = new CVC3::Expr(VC->listExpr(VC->idExpr("_DBG"))); } ; Trace : TRACE_TOK StringLiteral { $$ = new CVC3::Expr(VC->listExpr("_TRACE", *$2)); delete $2; } | UNTRACE_TOK StringLiteral { $$ = new CVC3::Expr(VC->listExpr("_UNTRACE", *$2)); delete $2; } ; Option : OPTION_TOK StringLiteral Numeral { $$ = new CVC3::Expr(VC->listExpr("_OPTION", *$2, *$3)); delete $2; delete $3; } | OPTION_TOK StringLiteral MINUS_TOK Numeral { CVC3::Rational value= -$4->getRational(); CVC3::Expr e = CVC3::Expr(VC->ratExpr(value.toString())); $$ = new CVC3::Expr(VC->listExpr("_OPTION", *$2, e)); delete $2; delete $4; } | OPTION_TOK StringLiteral StringLiteral { $$ = new CVC3::Expr(VC->listExpr("_OPTION", *$2, *$3)); delete $2; delete $3; } ; Help : HELP_TOK StringLiteral { $$ = new CVC3::Expr(VC->listExpr("_HELP", *$2)); delete $2; } | HELP_TOK { $$ = new CVC3::Expr(VC->listExpr(VC->idExpr("_HELP"))); } ; Transform : TRANSFORM_TOK Expr { $$ = new CVC3::Expr(VC->listExpr("_TRANSFORM", *$2)); delete $2; } ; Print : PRINT_TOK Expr { $$ = new CVC3::Expr(VC->listExpr("_PRINT", *$2)); delete $2; } | PRINT_TYPE_TOK Type { $$ = new CVC3::Expr(VC->listExpr("_PRINT", *$2)); delete $2; } ; Call : CALL_TOK Identifier Expr { $$ = new CVC3::Expr(VC->listExpr("_CALL", *$2, *$3)); delete $2; delete $3; } ; Echo : ECHO_TOK StringLiteral { $$ = new CVC3::Expr(VC->listExpr("_ECHO", *$2)); delete $2; } | ECHO_TOK { $$ = new CVC3::Expr(VC->listExpr(VC->idExpr("_ECHO"))); } ; Include : INCLUDE_TOK StringLiteral { $$ = new CVC3::Expr(VC->listExpr("_INCLUDE", *$2)); delete $2; } ; DumpCommand : DUMP_PROOF_TOK { $$ = new CVC3::Expr(VC->listExpr(VC->idExpr("_DUMP_PROOF"))); } | DUMP_ASSUMPTIONS_TOK { $$ = new CVC3::Expr(VC->listExpr(VC->idExpr("_DUMP_ASSUMPTIONS"))); } | DUMP_SIG_TOK { $$ = new CVC3::Expr(VC->listExpr(VC->idExpr("_DUMP_SIG"))); } | DUMP_TCC_TOK { $$ = new CVC3::Expr(VC->listExpr(VC->idExpr("_DUMP_TCC"))); } | DUMP_TCC_ASSUMPTIONS_TOK { $$ = new CVC3::Expr(VC->listExpr(VC->idExpr("_DUMP_TCC_ASSUMPTIONS"))); } | DUMP_TCC_PROOF_TOK { $$ = new CVC3::Expr(VC->listExpr(VC->idExpr("_DUMP_TCC_PROOF"))); } | DUMP_CLOSURE_TOK { $$ = new CVC3::Expr(VC->listExpr(VC->idExpr("_DUMP_CLOSURE"))); } | DUMP_CLOSURE_PROOF_TOK { $$ = new CVC3::Expr(VC->listExpr(VC->idExpr("_DUMP_CLOSURE_PROOF"))); } ; Where : WHERE_TOK { $$ = new CVC3::Expr(VC->listExpr(VC->idExpr("_WHERE"))); } | ASSERTIONS_TOK { $$ = new CVC3::Expr(VC->listExpr(VC->idExpr("_ASSERTIONS"))); } | ASSUMPTIONS_TOK { $$ = new CVC3::Expr(VC->listExpr(VC->idExpr("_ASSUMPTIONS"))); } | COUNTEREXAMPLE_TOK { $$ = new CVC3::Expr(VC->listExpr(VC->idExpr("_COUNTEREXAMPLE"))); } | COUNTERMODEL_TOK { $$ = new CVC3::Expr(VC->listExpr(VC->idExpr("_COUNTERMODEL"))); } ; Push : PUSH_TOK Numeral { $$ = new CVC3::Expr(VC->listExpr("_PUSH", *$2)); delete $2; } | PUSH_TOK { $$ = new CVC3::Expr(VC->listExpr(VC->idExpr("_PUSH"))); } | PUSH_SCOPE_TOK Numeral { $$ = new CVC3::Expr(VC->listExpr("_PUSH_SCOPE", *$2)); delete $2; } | PUSH_SCOPE_TOK { $$ = new CVC3::Expr(VC->listExpr(VC->idExpr("_PUSH_SCOPE"))); } ; Pop : POP_TOK Numeral { $$ = new CVC3::Expr(VC->listExpr("_POP", *$2)); delete $2; } | POP_TOK { $$ = new CVC3::Expr(VC->listExpr(VC->idExpr("_POP"))); } | POP_SCOPE_TOK Numeral { $$ = new CVC3::Expr(VC->listExpr("_POP_SCOPE", *$2)); delete $2; } | POP_SCOPE_TOK { $$ = new CVC3::Expr(VC->listExpr(VC->idExpr("_POP_SCOPE"))); } ; PopTo : POPTO_TOK Numeral { $$ = new CVC3::Expr(VC->listExpr("_POPTO", *$2)); delete $2; } | POPTO_TOK { $$ = new CVC3::Expr(VC->listExpr(VC->idExpr("_POPTO"))); } | POPTO_SCOPE_TOK Numeral { $$ = new CVC3::Expr(VC->listExpr("_POPTO_SCOPE", *$2)); delete $2; } | POPTO_SCOPE_TOK { $$ = new CVC3::Expr(VC->listExpr(VC->idExpr("_POPTO_SCOPE"))); } | RESET_TOK { $$ = new CVC3::Expr(VC->listExpr(VC->idExpr("_RESET"))); } ; Context : CONTEXT_TOK StringLiteral { $$ = new CVC3::Expr(VC->listExpr("_CONTEXT", *$2)); delete $2; } | CONTEXT_TOK { $$ = new CVC3::Expr(VC->listExpr(VC->idExpr("_CONTEXT"))); } ; Forget : FORGET_TOK Identifier { $$ = new CVC3::Expr(VC->listExpr("_FORGET", *$2)); delete $2; } ; Get_Type : GET_TYPE_TOK Expr { $$ = new CVC3::Expr(VC->listExpr("_GET_TYPE", *$2)); delete $2; } ; Check_Type : CHECK_TYPE_TOK Expr ':' Type { $$ = new CVC3::Expr(VC->listExpr("_CHECK_TYPE",*$2, *$4)); delete $2; delete $4; } ; Get_Child : GET_CHILD_TOK Expr Numeral { $$ = new CVC3::Expr(VC->listExpr("_GET_CHILD", *$2, *$3)); delete $2; delete $3; } ; Get_Op : GET_OP_TOK Expr { $$ = new CVC3::Expr(VC->listExpr("_GET_CHILD", *$2)); delete $2; } ; Substitute : SUBSTITUTE_TOK Identifier ':' Type '=' Expr '[' Identifier ASSIGN_TOK Expr ']' { std::vector tmp; tmp.push_back(*$2); tmp.push_back(*$4); tmp.push_back(*$6); tmp.push_back(*$8); tmp.push_back(*$10); $$ = new CVC3::Expr(VC->listExpr("_SUBSTITUTE", tmp)); delete $2; delete $4; delete $6; delete $8; delete $10; } ; Identifier : ID_TOK { $$ = new CVC3::Expr(VC->idExpr(*$1)); delete $1; } ; StringLiteral : STRINGLIT_TOK { $$ = new CVC3::Expr(VC->stringExpr(*$1)); delete $1; } ; Numeral : NUMERAL_TOK { $$ = new CVC3::Expr(VC->ratExpr((*$1))); delete $1; } ; Binary : BINARY_TOK { $$ = new CVC3::Expr (VC->listExpr("_BVCONST", VC->stringExpr(*$1))); delete $1; } ; Hex : HEX_TOK { $$ = new CVC3::Expr (VC->listExpr("_BVCONST", VC->stringExpr(*$1), VC->ratExpr(16))); delete $1; } ; /* Grammar for Types */ Type : Identifier { $$ = $1; } | TypeNotIdentifier { $$ = $1; } ; TypeNotIdentifier: ArrayType { $$ = $1; } | FunctionType { $$ = $1; } | BasicType { $$ = $1; } | SubrangeType { $$ = $1; } | TupleType { $$ = $1; } | RecordType { $$ = $1; } | TypeLetExpr { $$ = $1; } | BitvectorType {$$ = $1;} | SubType { $$ = $1; } | '(' Type ')' { $$ = $2; } ; TypeDef : Type { $$ = $1; } | ScalarType { $$ = $1; } ; DataType : DATATYPE_TOK SingleDataTypes END_TOK { $$ = new CVC3::Expr( VC->listExpr("_TYPEDEF", VC->listExpr("_DATATYPE", *$2))); delete $2; } ; SingleDataTypes : SingleDataType { $$ = new std::vector; $$->push_back(*$1); delete $1; } | SingleDataTypes ',' SingleDataType { $1->push_back(*$3); $$ = $1; delete $3; } ; SingleDataType : Identifier '=' Constructors { $$ = new CVC3::Expr(VC->listExpr(*$1, VC->listExpr(*$3))); delete $1; delete $3; } ; Constructors : Constructor { $$ = new std::vector; $$->push_back(*$1); delete $1; } | Constructors MID_TOK Constructor { $1->push_back(*$3); $$ = $1; delete $3; } ; Constructor : Identifier { $$ = new CVC3::Expr(VC->listExpr(*$1)); delete $1; } | Identifier '(' VarDecls ')' { CVC3::Expr tmp = VC->listExpr(*$3); $$ = new CVC3::Expr(VC->listExpr(*$1, tmp)); delete $1; delete $3; } ; VarDecls : VarDecl { $$ = new std::vector; $$->push_back(*$1); delete $1; } | VarDecls ',' VarDecl { $1->push_back(*$3); $$ = $1; delete $3; } ; VarDecl : Identifier ':' Type { $$ = new CVC3::Expr(VC->listExpr(*$1, *$3)); delete $1; delete $3; } ; FunctionType : '[' Type ARROW_TOK Type ']' { // Old style functions $$ = new CVC3::Expr(VC->listExpr("_OLD_ARROW", *$2, *$4)); delete $2; delete $4; } | Type ARROW_TOK Type { std::vector temp; temp.push_back(*$1); temp.push_back(*$3); $$ = new CVC3::Expr(VC->listExpr("_ARROW", temp)); delete $1; delete $3; } | '(' TypeList ')' ARROW_TOK Type { $2->push_back(*$5); $$ = new CVC3::Expr(VC->listExpr("_ARROW", *$2)); delete $2; delete $5; } ; RecordType : SQHASH_TOK FieldDecls HASHSQ_TOK { $$ = new CVC3::Expr(VC->listExpr(*$2)); delete $2; } ; FieldDecls : FieldDecl { $$ = new std::vector; $$->push_back(VC->idExpr("_RECORD_TYPE")); $$->push_back(*$1); delete $1; } | FieldDecls ',' FieldDecl { $1->push_back(*$3); $$ = $1; delete $3; } ; FieldDecl : Identifier ':' Type { $$ = new CVC3::Expr(VC->listExpr(*$1, *$3)); delete $1; delete $3; } ; TupleType : '[' TypeList ']' { $$ = new CVC3::Expr(VC->listExpr("_TUPLE_TYPE", *$2)); delete $2; } ; TypeList : Type ',' Type { $$ = new std::vector; $$->push_back(*$1); $$->push_back(*$3); delete $1; delete $3; } | TypeList ',' Type { $1->push_back(*$3); $$ = $1; delete $3; } ; /* IndexType : SubrangeType { $$ = $1; } */ /* | Real /\* WART: maybe change to INTEGER when we */ /* get that working? *\/ */ /* | Int */ /* { $$ = $1; } */ /* | Identifier { $$ = $1; } */ /* ; */ ArrayType : ARRAY_TOK Type OF_TOK Type { $$ = new CVC3::Expr(VC->listExpr("_ARRAY", *$2, *$4)); delete $2; delete $4; } ; ScalarType : '{' IDs '}' { std::vector::iterator theIter = $2->begin(); $2->insert(theIter, VC->idExpr("_SCALARTYPE")); $$ = new CVC3::Expr(VC->listExpr(*$2)); delete $2; } ; SubType : SUBTYPE_TOK '(' Expr ')' { $$ = new CVC3::Expr(VC->listExpr("_SUBTYPE", *$3)); delete $3; } | SUBTYPE_TOK '(' Expr ',' Expr ')' { $$ = new CVC3::Expr(VC->listExpr("_SUBTYPE", *$3, *$5)); delete $3; delete $5; } ; BasicType : BOOLEAN_TOK { $$ = new CVC3::Expr(VC->idExpr("_BOOLEAN")); } | Real | Int ; BitvectorType : BITVECTOR_TOK '(' Numeral ')' { $$ = new CVC3::Expr(VC->listExpr("_BITVECTOR", *$3)); delete $3; } ; Real : REAL_TOK { $$ = new CVC3::Expr(VC->idExpr("_REAL")); } ; Int : INT_TOK { $$ = new CVC3::Expr(VC->idExpr("_INT")); } ; SubrangeType : '[' LeftBound DOTDOT_TOK RightBound ']' { $$ = new CVC3::Expr(VC->listExpr("_SUBRANGE", *$2, *$4)); delete $2; delete $4; } ; LeftBound : '_' { $$ = new CVC3::Expr(VC->listExpr(VC->idExpr("_NEGINF"))); } | Numeral { $$ = $1; } | MINUS_TOK Numeral { CVC3::Rational value= -$2->getRational(); $$ = new CVC3::Expr(VC->ratExpr(value.toString())); delete $2; } ; RightBound : '_' { $$ = new CVC3::Expr(VC->listExpr(VC->idExpr("_POSINF"))); } | Numeral { $$ = $1; } | MINUS_TOK Numeral { CVC3::Rational value= -$2->getRational(); $$ = new CVC3::Expr(VC->ratExpr(value.toString())); delete $2; } ; /* right recursive to eliminate a conflict. Reverses order? */ reverseIDs : Identifier { $$ = new std::vector; $$->push_back(*$1); delete $1; } | Identifier ',' reverseIDs { $3->push_back(*$1); $$ = $3; delete $1; } ; IDs : reverseIDs { $$ = new std::vector($1->rbegin(), $1->rend()); delete $1; } ; /* Grammar for exprs */ Expr : Identifier { $$ = $1; } | Numeral { $$ = $1; } | Binary { $$ = $1; } | Hex { $$ = $1; } | Expr '(' Exprs ')' { std::vector tmp; tmp.push_back(*$1); tmp.insert(tmp.end(), $3->begin(), $3->end()); $$ = new CVC3::Expr(VC->listExpr(tmp)); delete $1; delete $3; } | SIMULATE_TOK '(' Exprs ')' { $$ = new CVC3::Expr(VC->listExpr("_SIMULATE", *$3)); delete $3; } | Expr '[' Expr ']' { $$ = new CVC3::Expr(VC->listExpr("_READ", *$1, *$3)); delete $1; delete $3; } | Expr '.' Identifier { $$ = new CVC3::Expr(VC->listExpr("_RECORD_SELECT", *$1, *$3)); delete $1; delete $3; } | Expr '.' Numeral { $$ = new CVC3::Expr(VC->listExpr("_TUPLE_SELECT", *$1, *$3)); delete $1; delete $3; } | Expr WITH_TOK Updates { $$ = new CVC3::Expr(CVC3::PLprocessUpdates(*$1, *$3)); delete $1; delete $3; } | Lambda { $$ = $1; } | QuantExpr { $$ = $1; } | LetExpr { $$ = $1; } | ArrayLiteral { $$ = $1; } | RecordLiteral { $$ = $1; } | TupleLiteral { $$ = $1; } | Conditional { $$ = $1; } | TRUELIT_TOK { $$ = new CVC3::Expr(VC->idExpr("_TRUE_EXPR")); } | FALSELIT_TOK { $$ = new CVC3::Expr(VC->idExpr("_FALSE_EXPR")); } | MINUS_TOK Expr %prec UMINUS_TOK { if ($2->isRational()) { CVC3::Rational value= -$2->getRational(); $$= new CVC3::Expr(VC->ratExpr(value.toString())); } else $$ = new CVC3::Expr(VC->listExpr("_UMINUS", *$2)); delete $2; } | NOT_TOK Expr { $$ = new CVC3::Expr(VC->listExpr("_NOT", *$2)); delete $2; } | IS_INTEGER_TOK Expr { $$ = new CVC3::Expr(VC->listExpr("_IS_INTEGER", *$2)); delete $2; } | TCC_TOK '(' Expr ')' { $$ = new CVC3::Expr(VC->listExpr("_TCC", *$3)); delete $3; } | Expr '=' Expr { $$ = new CVC3::Expr(VC->listExpr("_EQ", *$1, *$3)); delete $1; delete $3; } | Expr NEQ_TOK Expr { $$ = new CVC3::Expr(VC->listExpr("_NEQ", *$1, *$3)); delete $1; delete $3; } | Expr XOR_TOK Expr { $$ = new CVC3::Expr(VC->listExpr("_XOR", *$1, *$3)); delete $1; delete $3; } | OrExpr %prec OR_TOK { $$ = new CVC3::Expr(VC->listExpr("_OR", *$1)); delete $1; } | AndExpr %prec AND_TOK { $$ = new CVC3::Expr(VC->listExpr("_AND", *$1)); delete $1; } | Expr IMPLIES_TOK Expr { $$ = new CVC3::Expr(VC->listExpr("_IMPLIES", *$1, *$3)); delete $1; delete $3; } | Expr IFF_TOK Expr { $$ = new CVC3::Expr(VC->listExpr("_IFF", *$1, *$3)); delete $1; delete $3; } | Expr PLUS_TOK Expr { $$ = new CVC3::Expr(VC->listExpr("_PLUS", *$1, *$3)); delete $1; delete $3; } | Expr MINUS_TOK Expr { $$ = new CVC3::Expr(VC->listExpr("_MINUS", *$1, *$3)); delete $1; delete $3; } | Expr MULT_TOK '(' Expr ',' Expr ')' { $$ = new CVC3::Expr(VC->listExpr("_TRANS_CLOSURE", *$1, *$4, *$6)); delete $1; delete $4; delete $6; } | Expr MULT_TOK Expr { $$ = new CVC3::Expr(VC->listExpr("_MULT", *$1, *$3)); delete $1; delete $3; } | Expr POW_TOK Expr { $$ = new CVC3::Expr(VC->listExpr("_POW", *$3, *$1)); delete $1; delete $3; } | Expr DIV_TOK Expr { $$ = new CVC3::Expr(VC->listExpr("_DIVIDE", *$1, *$3)); delete $1; delete $3; } // | Expr INTDIV_TOK Expr // { // $$ = new CVC3::Expr(VC->listExpr("_INTDIV", *$1, *$3)); // delete $1; // delete $3; // } // | Expr MOD_TOK Expr // { // $$ = new CVC3::Expr(VC->listExpr("_MOD", *$1, *$3)); // delete $1; // delete $3; // } | Expr GT_TOK Expr { $$ = new CVC3::Expr(VC->listExpr("_GT", *$1, *$3)); delete $1; delete $3; } | Expr GE_TOK Expr { $$ = new CVC3::Expr(VC->listExpr("_GE", *$1, *$3)); delete $1; delete $3; } | FLOOR_TOK '(' Expr ')' { $$ = new CVC3::Expr(VC->listExpr("_FLOOR", *$3)); delete $3; } | Expr LT_TOK Expr { $$ = new CVC3::Expr(VC->listExpr("_LT", *$1, *$3)); delete $1; delete $3; } | Expr LE_TOK Expr { $$ = new CVC3::Expr(VC->listExpr("_LE", *$1, *$3)); delete $1; delete $3; } | '(' Expr ')' { $$ = $2; } | BVNEG_TOK Expr { $$ = new CVC3::Expr(VC->listExpr("_BVNEG", *$2)); delete $2; } | Expr '[' NUMERAL_TOK ':' NUMERAL_TOK ']' { $$ = new CVC3::Expr (VC->listExpr("_EXTRACT", VC->ratExpr(*$3), VC->ratExpr(*$5), *$1)); delete $1; delete $3; delete $5; } | Expr BVAND_TOK Expr { $$ = new CVC3::Expr(VC->listExpr("_BVAND", *$1, *$3)); delete $1; delete $3; } | Expr MID_TOK Expr { $$ = new CVC3::Expr(VC->listExpr("_BVOR", *$1, *$3)); delete $1; delete $3; } | Expr LEFTSHIFT_TOK NUMERAL_TOK { $$ = new CVC3::Expr (VC->listExpr("_LEFTSHIFT", *$1, VC->ratExpr(*$3))); delete $1; delete $3; } | Expr RIGHTSHIFT_TOK NUMERAL_TOK { $$ = new CVC3::Expr (VC->listExpr("_RIGHTSHIFT", *$1, VC->ratExpr(*$3))); delete $1; delete $3; } | BVXOR_TOK '(' Expr ',' Expr ')' { $$ = new CVC3::Expr(VC->listExpr("_BVXOR", *$3, *$5)); delete $3; delete $5; } | BVNAND_TOK '(' Expr ',' Expr ')' { $$ = new CVC3::Expr(VC->listExpr("_BVNAND", *$3, *$5)); delete $3; delete $5; } | BVNOR_TOK '(' Expr ',' Expr ')' { $$ = new CVC3::Expr(VC->listExpr("_BVNOR", *$3, *$5)); delete $3; delete $5; } | BVCOMP_TOK '(' Expr ',' Expr ')' { $$ = new CVC3::Expr(VC->listExpr("_BVCOMP", *$3, *$5)); delete $3; delete $5; } | BVXNOR_TOK '(' Expr ',' Expr ')' { $$ = new CVC3::Expr(VC->listExpr("_BVXNOR", *$3, *$5)); delete $3; delete $5; } | SX_TOK '(' Expr ',' NUMERAL_TOK ')' { $$ = new CVC3::Expr(VC->listExpr("_SX",*$3,VC->ratExpr(*$5))); delete $3; delete $5; } | BVZEROEXTEND_TOK '(' Expr ',' NUMERAL_TOK ')' { $$ = new CVC3::Expr(VC->listExpr("_BVZEROEXTEND",VC->ratExpr(*$5),*$3)); delete $3; delete $5; } | BVREPEAT_TOK '(' Expr ',' NUMERAL_TOK ')' { $$ = new CVC3::Expr(VC->listExpr("_BVREPEAT",VC->ratExpr(*$5),*$3)); delete $3; delete $5; } | BVROTL_TOK '(' Expr ',' NUMERAL_TOK ')' { $$ = new CVC3::Expr(VC->listExpr("_BVROTL",VC->ratExpr(*$5),*$3)); delete $3; delete $5; } | BVROTR_TOK '(' Expr ',' NUMERAL_TOK ')' { $$ = new CVC3::Expr(VC->listExpr("_BVROTR",VC->ratExpr(*$5),*$3)); delete $3; delete $5; } | BVLT_TOK '(' Expr ',' Expr ')' { $$ = new CVC3::Expr(VC->listExpr("_BVLT", *$3, *$5)); delete $3; delete $5; } | BVGT_TOK '(' Expr ',' Expr ')' { $$ = new CVC3::Expr(VC->listExpr("_BVGT", *$3, *$5)); delete $3; delete $5; } | BVLE_TOK '(' Expr ',' Expr ')' { $$ = new CVC3::Expr(VC->listExpr("_BVLE", *$3, *$5)); delete $3; delete $5; } | BVGE_TOK '(' Expr ',' Expr ')' { $$ = new CVC3::Expr(VC->listExpr("_BVGE", *$3, *$5)); delete $3; delete $5; } | BVSLT_TOK '(' Expr ',' Expr ')' { $$ = new CVC3::Expr(VC->listExpr("_BVSLT", *$3, *$5)); delete $3; delete $5; } | BVSGT_TOK '(' Expr ',' Expr ')' { $$ = new CVC3::Expr(VC->listExpr("_BVSGT", *$3, *$5)); delete $3; delete $5; } | BVSLE_TOK '(' Expr ',' Expr ')' { $$ = new CVC3::Expr(VC->listExpr("_BVSLE", *$3, *$5)); delete $3; delete $5; } | BVSGE_TOK '(' Expr ',' Expr ')' { $$ = new CVC3::Expr(VC->listExpr("_BVSGE", *$3, *$5)); delete $3; delete $5; } | Expr CONCAT_TOK Expr { $$ = new CVC3::Expr(VC->listExpr("_CONCAT", *$1, *$3)); delete $1; delete $3; } | INTTOBV_TOK '(' Expr ',' NUMERAL_TOK ',' NUMERAL_TOK ')' { $$ = new CVC3::Expr (VC->listExpr("_INTTOBV", *$3, VC->ratExpr(*$5), VC->ratExpr(*$7))); delete $3; delete $5; delete $7; } | BVTOINT_TOK '(' Expr ')' { $$ = new CVC3::Expr(VC->listExpr("_BVTOINT", *$3)); delete $3; } | BOOLEXTRACT_TOK '(' Expr ',' NUMERAL_TOK ')' { //FIXME: this function is not to be exposed //to the user counterexamples containing //this function can be translated into //BV-EXTRACT and comparison with 0 or 1 $$ = new CVC3::Expr(VC->listExpr("_BOOLEXTRACT", *$3, VC->ratExpr(*$5))); delete $3; delete $5; } | BVPLUS_TOK '(' NUMERAL_TOK ',' Exprs ')' { std::vector k; k.push_back(VC->ratExpr(*$3)); k.insert(k.end(), $5->begin(), $5->end()); $$ = new CVC3::Expr(VC->listExpr("_BVPLUS", k)); delete $3; delete $5; } | BVSUB_TOK '(' NUMERAL_TOK ',' Expr ',' Expr ')' { $$ = new CVC3::Expr (VC->listExpr("_BVSUB", VC->ratExpr(*$3), *$5, *$7)); delete $3; delete $5; delete $7; } | BVUDIV_TOK '(' Expr ',' Expr ')' { $$ = new CVC3::Expr (VC->listExpr("_BVUDIV", *$3, *$5)); delete $3; delete $5; } | BVSDIV_TOK '(' Expr ',' Expr ')' { $$ = new CVC3::Expr (VC->listExpr("_BVSDIV", *$3, *$5)); delete $3; delete $5; } | BVUREM_TOK '(' Expr ',' Expr ')' { $$ = new CVC3::Expr (VC->listExpr("_BVUREM", *$3, *$5)); delete $3; delete $5; } | BVSREM_TOK '(' Expr ',' Expr ')' { $$ = new CVC3::Expr (VC->listExpr("_BVSREM", *$3, *$5)); delete $3; delete $5; } | BVSMOD_TOK '(' Expr ',' Expr ')' { $$ = new CVC3::Expr (VC->listExpr("_BVSMOD", *$3, *$5)); delete $3; delete $5; } | BVSHL_TOK '(' Expr ',' Expr ')' { $$ = new CVC3::Expr (VC->listExpr("_BVSHL", *$3, *$5)); delete $3; delete $5; } | BVASHR_TOK '(' Expr ',' Expr ')' { $$ = new CVC3::Expr (VC->listExpr("_BVASHR", *$3, *$5)); delete $3; delete $5; } | BVLSHR_TOK '(' Expr ',' Expr ')' { $$ = new CVC3::Expr (VC->listExpr("_BVLSHR", *$3, *$5)); delete $3; delete $5; } | BVUMINUS_TOK '(' Expr ')' { $$ = new CVC3::Expr(VC->listExpr("_BVUMINUS", *$3)); delete $3; } | BVMULT_TOK '(' NUMERAL_TOK ',' Expr ',' Expr ')' { $$ = new CVC3::Expr (VC->listExpr("_BVMULT", VC->ratExpr(*$3), *$5, *$7)); delete $3; delete $5; delete $7; } | DISTINCT_TOK '(' Exprs ')' { $$ = new CVC3::Expr(VC->listExpr("_DISTINCT", *$3)); delete $3; } ; AndExpr : AndExpr AND_TOK Expr { $1->push_back(*$3); $$ = $1; delete $3; } | Expr AND_TOK Expr { $$ = new std::vector; $$->push_back(*$1); $$->push_back(*$3); delete $1; delete $3; } ; OrExpr : OrExpr OR_TOK Expr { $1->push_back(*$3); $$ = $1; delete $3; } | Expr OR_TOK Expr { $$ = new std::vector; $$->push_back(*$1); $$->push_back(*$3); delete $1; delete $3; } ; Conditional : IF_TOK Expr THEN_TOK Expr ElseRest { $5->push_back(VC->listExpr(*$2, *$4)); $5->push_back(VC->idExpr("_COND")); /* at this point, the list for ElseRest is in reverse order from what it should be. */ std::vector tmp; tmp.insert(tmp.end(), $5->rbegin(), $5->rend()); $$ = new CVC3::Expr(VC->listExpr(tmp)); delete $2; delete $4; delete $5; } ; ElseRest : ELSE_TOK Expr ENDIF_TOK { $$ = new std::vector; $$->push_back(VC->listExpr("_ELSE",*$2)); delete $2; } | ELSIF_TOK Expr THEN_TOK Expr ElseRest { /* NOTE that we're getting the list built up in the reverse order here. We'll fix things when we produce a Conditional. */ $5->push_back(VC->listExpr(*$2, *$4)); $$ = $5; delete $2; delete $4; } ; Exprs : Expr { $$ = new std::vector; $$->push_back(*$1); delete $1; } | Exprs ',' Expr { $1->push_back(*$3); $$ = $1; delete $3; } ; Pattern : PATTERN_TOK '(' Exprs ')' ':' { $$ = $3; } Patterns : Pattern { $$ = new std::vector; $$->push_back(VC->listExpr(*$1)); delete $1; } | Patterns Pattern { $1->push_back(VC->listExpr(*$2)); $$ = $1; delete $2; } ; Update : UpdatePositionNode ASSIGN_TOK Expr { $$ = new CVC3::Expr(VC->listExpr(*$1, *$3)); delete $1; delete $3; } ; Updates : Update { $$ = new std::vector; $$->push_back(*$1); delete $1; } | Updates ',' Update { $$->push_back(*$3); delete $3; } ; UpdatePositionNode : UpdatePosition { $$ = new CVC3::Expr(VC->listExpr(*$1)); delete $1; } ; UpdatePosition : '[' Expr ']' { $$ = new std::vector; $$->push_back(VC->listExpr("_READ", *$2)); delete $2; } | Identifier { $$ = new std::vector; $$->push_back(*$1); delete $1; } | '.' Identifier { $$ = new std::vector; $$->push_back(VC->listExpr("_RECORD_SELECT", *$2)); delete $2; } | '.' Numeral { $$ = new std::vector; $$->push_back(VC->listExpr("_TUPLE_SELECT", *$2)); delete $2; } | UpdatePosition '[' Expr ']' { $1->push_back(VC->listExpr("_READ", *$3)); $$ = $1; delete $3; } | UpdatePosition Identifier { $1->push_back(*$2); $$ = $1; delete $2; } | UpdatePosition '.' Identifier { $1->push_back(VC->listExpr("_RECORD_SELECT",*$3)); $$ = $1; delete $3; } | UpdatePosition '.' Numeral { $1->push_back(VC->listExpr("_TUPLE_SELECT", *$3)); $$ = $1; delete $3; } ; Lambda : LAMBDA_TOK '(' BoundVarDecls ')' ':' Expr %prec ASSIGN_TOK { $$ = new CVC3::Expr(VC->listExpr("_LAMBDA", VC->listExpr(*$3), (*$6))); delete $3; delete $6; } ; QuantExpr : FORALL_TOK '(' BoundVarDecls ')' ':' Expr %prec FORALL_TOK { $$ = new CVC3::Expr(VC->listExpr("_FORALL", VC->listExpr(*$3), *$6)); delete $3; delete $6; } | FORALL_TOK '(' BoundVarDecls ')' ':' Patterns Expr %prec FORALL_TOK { $$ = new CVC3::Expr(VC->listExpr("_FORALL", VC->listExpr(*$3), *$7, VC->listExpr(*$6))); delete $3; delete $6; delete $7; } | EXISTS_TOK '(' BoundVarDecls ')' ':' Expr %prec EXISTS_TOK { $$ = new CVC3::Expr(VC->listExpr("_EXISTS", VC->listExpr(*$3), (*$6))); delete $3; delete $6; } ; | EXISTS_TOK '(' BoundVarDecls ')' ':' Patterns Expr %prec EXISTS_TOK { $$ = new CVC3::Expr(VC->listExpr("_EXISTS", VC->listExpr(*$3), *$7, VC->listExpr(*$6))); delete $3; delete $6; delete $7; } ArrayLiteral : ARRAY_TOK '(' BoundVarDecl ')' ':' Expr %prec ASSIGN_TOK { $$ = new CVC3::Expr (VC->listExpr("_ARRAY_LITERAL", *$3, *$6)); delete $3; delete $6; } ; RecordLiteral : PARENHASH_TOK RecordEntries HASHPAREN_TOK { $2->insert($2->begin(), VC->idExpr("_RECORD")); $$ = new CVC3::Expr(VC->listExpr(*$2)); delete $2; } ; RecordEntries : RecordEntry { $$ = new std::vector; $$->push_back(*$1); delete $1; } | RecordEntries ',' RecordEntry { $1->push_back(*$3); $$ = $1; delete $3; } ; RecordEntry : Identifier ASSIGN_TOK Expr { $$ = new CVC3::Expr(VC->listExpr(*$1, *$3)); delete $1; delete $3; } ; TupleLiteral : '(' Exprs ',' Expr ')' { $2->push_back(*$4); $2->insert($2->begin(),VC->idExpr("_TUPLE")); $$ = new CVC3::Expr(VC->listExpr(*$2)); delete $2; delete $4; } ; LetDeclsNode : LetDecls { $$ = new CVC3::Expr(VC->listExpr(*$1)); delete $1; } ; LetDecls : LetDecl { $$ = new std::vector; $$->push_back(*$1); delete $1; } | LetDecls ',' LetDecl { $1->push_back(*$3); $$ = $1; delete $3; } ; LetDecl : Identifier '=' Expr { $$ = new CVC3::Expr(VC->listExpr(*$1,*$3)); delete $1; delete $3; } | Identifier ':' Type '=' Expr { $$ = new CVC3::Expr(VC->listExpr(*$1,*$5)); delete $1; delete $3; delete $5; } ; LetExpr : LET_TOK LetDeclsNode IN_TOK Expr { $$ = new CVC3::Expr(VC->listExpr("_LET", *$2, *$4)); delete $2; delete $4; } ; TypeLetDeclsNode : TypeLetDecls { $$ = new CVC3::Expr(VC->listExpr(*$1)); delete $1; } ; TypeLetDecls : TypeLetDecl { $$ = new std::vector; $$->push_back(*$1); delete $1; } | TypeLetDecls ',' TypeLetDecl { $1->push_back(*$3); $$ = $1; delete $3; } ; TypeLetDecl : Identifier '=' Type { $$ = new CVC3::Expr(VC->listExpr(*$1, *$3)); delete $1; delete $3; } | Identifier ':' TYPE_TOK '=' Type { $$ = new CVC3::Expr(VC->listExpr(*$1,*$5)); delete $1; delete $5; } ; TypeLetExpr : LET_TOK TypeLetDeclsNode IN_TOK Type { $$ = new CVC3::Expr(VC->listExpr("_LET", *$2, *$4)); delete $2; delete $4; } ; BoundVarDecl : IDs ':' Type { $1->push_back(*$3); delete $3; $$ = new CVC3::Expr(VC->listExpr(*$1)); delete $1; } ; BoundVarDecls : BoundVarDecl { $$ = new std::vector; $$->push_back(*$1); delete $1; } | BoundVarDecls ',' BoundVarDecl { $1->push_back(*$3); $$ = $1; delete $3; } ; BoundVarDeclNode: BoundVarDecls { $$ = new CVC3::Expr(VC->listExpr(*$1)); delete $1; } ; ConstDecl : Identifier ':' Type '=' Expr { $$ = new CVC3::Expr(VC->listExpr("_CONST", *$1, *$3, *$5)); delete $1; delete $3; delete $5; } | Identifier ':' Type { $$ =new CVC3::Expr (VC->listExpr("_CONST", VC->listExpr(*$1), *$3)); delete $1; delete $3; } | Identifier '(' BoundVarDeclNode ')' ':' Type '=' Expr { std::vector tmp; tmp.push_back(VC->idExpr("_DEFUN")); tmp.push_back(*$1); tmp.push_back(*$3); tmp.push_back(*$6); tmp.push_back(*$8); $$ = new CVC3::Expr(VC->listExpr(tmp)); delete $1; delete $3; delete $6; delete $8; } | Identifier '(' BoundVarDeclNode ')' ':' Type { std::vector tmp; tmp.push_back(VC->idExpr("_DEFUN")); tmp.push_back(*$1); tmp.push_back(*$3); tmp.push_back(*$6); $$ = new CVC3::Expr(VC->listExpr(tmp)); delete $1; delete $3; delete $6; } | Identifier ',' IDs ':' Type { $3->insert($3->begin(), *$1); $$ = new CVC3::Expr(VC->listExpr("_CONST", VC->listExpr(*$3), *$5)); delete $1; delete $3; delete $5; } ; TypeDecl : DataType { $$ = $1; } | Identifier ':' TYPE_TOK '=' TypeDef { $$ = new CVC3::Expr(VC->listExpr("_TYPEDEF", *$1, *$5)); delete $1; delete $5; } | Identifier ':' TYPE_TOK { $$ =new CVC3::Expr(VC->listExpr("_TYPE", *$1)); delete $1; } | Identifier ',' IDs ':' TYPE_TOK { std::vector tmp; tmp.push_back(*$1); tmp.insert(tmp.end(), $3->begin(), $3->end()); $$ = new CVC3::Expr(VC->listExpr("_TYPE", tmp)); delete $1; delete $3; } ; %% cvc3-2.4.1/src/parser/smtlib.y0000644000175400017540000012407211604636626016043 0ustar mdetersmdeters%{ /*****************************************************************************/ /*! * \file smtlib.y * * Author: Clark Barrett * * Created: Apr 30 2005 * *
* * License to use, copy, modify, sell and/or distribute this software * and its documentation for any purpose is hereby granted without * royalty, subject to the terms and conditions defined in the \ref * LICENSE file provided with this distribution. * *
* */ /*****************************************************************************/ /* This file contains the bison code for the parser that reads in CVC commands in SMT-LIB language. */ #include "vc.h" #include "parser_exception.h" #include "parser_temp.h" #include "translator.h" #include "theory_arith.h" #include "command_line_flags.h" #include // Exported shared data namespace CVC3 { extern ParserTemp* parserTemp; } // Define shortcuts for various things #define TMP CVC3::parserTemp #define EXPR CVC3::parserTemp->expr #define VC (CVC3::parserTemp->vc) #define ARRAYSENABLED (CVC3::parserTemp->arrFlag) #define BVENABLED (CVC3::parserTemp->bvFlag) #define BVSIZE (CVC3::parserTemp->bvSize) #define RAT(args) CVC3::newRational args #define QUERYPARSED CVC3::parserTemp->queryParsed #define TRANSLATOR CVC3::parserTemp->translator // Suppress the bogus warning suppression in bison (it generates // compile error) #undef __GNUC_MINOR__ /* stuff that lives in smtlib.lex */ extern int smtliblex(void); int smtliberror(const char *s) { std::ostringstream ss; ss << CVC3::parserTemp->fileName << ":" << CVC3::parserTemp->lineNum << ": " << s; return CVC3::parserTemp->error(ss.str()); } #define YYLTYPE_IS_TRIVIAL 1 #define YYMAXDEPTH 10485760 %} %union { std::string *str; std::vector *strvec; CVC3::Expr *node; std::vector *vec; std::pair, std::vector > *pat_ann; }; %start cmd /* strings are for better error messages. "_TOK" is so macros don't conflict with kind names */ %type bench_attributes sort_symbs fun_symb_decls pred_symb_decls %type an_exprs an_formulas quant_vars an_terms fun_symb fun_pred_symb %type pattern %type benchmark bench_name bench_attribute %type status fun_symb_decl fun_sig pred_symb_decl pred_sig %type an_expr an_formula quant_var an_atom prop_atom %type an_term basic_term sort_symb pred_symb %type var fvar annotation %type logic_name quant_symb connective user_value attribute %type annotations %type patterns_annotations %token NUMERAL_TOK %token SYM_TOK %token ID_TOK %token STRING_TOK %token AR_SYMB %token USER_VAL_TOK %token COMMENT_TOK %token TRUE_TOK %token FALSE_TOK %token ITE_TOK %token NOT_TOK %token IMPLIES_TOK %token IF_THEN_ELSE_TOK %token AND_TOK %token OR_TOK %token XOR_TOK %token IFF_TOK %token EXISTS_TOK %token FORALL_TOK %token LET_TOK %token FLET_TOK %token NOTES_TOK %token CVC_COMMAND_TOK %token LOGIC_TOK %token COLON_TOK %token LBRACKET_TOK %token RBRACKET_TOK %token LCURBRACK_TOK %token RCURBRACK_TOK %token LPAREN_TOK %token RPAREN_TOK %token SAT_TOK %token UNSAT_TOK %token UNKNOWN_TOK %token ASSUMPTION_TOK %token FORMULA_TOK %token STATUS_TOK %token BENCHMARK_TOK %token SOURCE_TOK %token CATEGORY_TOK %token EXTRASORTS_TOK %token EXTRAFUNS_TOK %token EXTRAPREDS_TOK %token DOLLAR_TOK %token QUESTION_TOK %token DISTINCT_TOK %token EOF_TOK %token PAT_TOK %% cmd: benchmark { EXPR = *$1; delete $1; YYACCEPT; } ; benchmark: LPAREN_TOK BENCHMARK_TOK bench_name bench_attributes RPAREN_TOK { if (!QUERYPARSED) $4->push_back(CVC3::Expr(VC->listExpr("_CHECKSAT", CVC3::Expr(VC->idExpr("_TRUE_EXPR"))))); $$ = new CVC3::Expr(VC->listExpr("_SEQ",*$4)); delete $4; } | EOF_TOK { TMP->done = true; $$ = new CVC3::Expr(); } ; bench_name: SYM_TOK { TRANSLATOR->setBenchName(*$1); $$ = NULL; delete $1; } | ID_TOK { TRANSLATOR->setBenchName(*$1); $$ = NULL; delete $1; } ; bench_attributes: bench_attribute { $$ = new std::vector; if ($1) { $$->push_back(*$1); delete $1; } } | bench_attributes bench_attribute { $$ = $1; if ($2) { $$->push_back(*$2); delete $2; } } ; bench_attribute: COLON_TOK ASSUMPTION_TOK an_formula { $$ = new CVC3::Expr(VC->listExpr("_ASSERT", *$3)); delete $3; } | COLON_TOK FORMULA_TOK an_formula { $$ = new CVC3::Expr(VC->listExpr("_CHECKSAT", *$3)); QUERYPARSED = true; delete $3; } | COLON_TOK STATUS_TOK status { $$ = NULL; } | COLON_TOK SOURCE_TOK USER_VAL_TOK { TRANSLATOR->setSource(*$3); $$ = NULL; delete $3; } | COLON_TOK CATEGORY_TOK USER_VAL_TOK { TRANSLATOR->setCategory(*$3); $$ = NULL; delete $3; } | COLON_TOK LOGIC_TOK logic_name { ARRAYSENABLED = false; BVENABLED = false; CVC3::Expr cmd; if (*$3 == "QF_UF") { cmd = CVC3::Expr(VC->listExpr("_TYPE", VC->idExpr("U"))); } else if (*$3 == "QF_A" || *$3 == "QF_AX") { ARRAYSENABLED = true; std::vector tmp; tmp.push_back(VC->listExpr("_TYPE", VC->idExpr("Index"))); tmp.push_back(VC->listExpr("_TYPE", VC->idExpr("Element"))); tmp.push_back(VC->listExpr("_TYPEDEF", VC->idExpr("Array"), VC->listExpr("_ARRAY", VC->idExpr("Index"), VC->idExpr("Element")))); cmd = CVC3::Expr(VC->listExpr("_SEQ", tmp)); } else if (*$3 == "QF_AUFLIA" || *$3 == "AUFLIA") { ARRAYSENABLED = true; std::vector tmp; tmp.push_back(VC->listExpr("_TYPEDEF", VC->idExpr("Array"), VC->listExpr("_ARRAY", VC->idExpr("_INT"), VC->idExpr("_INT")))); cmd = CVC3::Expr(VC->listExpr("_SEQ", tmp)); } else if (*$3 == "QF_AUFLIRA" || *$3 == "AUFLIRA" || *$3 == "QF_AUFNIRA" || *$3 == "AUFNIRA") { ARRAYSENABLED = true; std::vector tmp; tmp.push_back(VC->listExpr("_TYPEDEF", VC->idExpr("Array1"), VC->listExpr("_ARRAY", VC->idExpr("_INT"), VC->idExpr("_REAL")))); tmp.push_back(VC->listExpr("_TYPEDEF", VC->idExpr("Array2"), VC->listExpr("_ARRAY", VC->idExpr("_INT"), VC->idExpr("Array1")))); cmd = CVC3::Expr(VC->listExpr("_SEQ", tmp)); } else if (*$3 == "QF_AUFBV" || *$3 == "QF_ABV") { ARRAYSENABLED = true; BVENABLED = true; // $$ = new CVC3::Expr(VC->listExpr("_TYPEDEF", VC->idExpr("Array"), // VC->listExpr("_ARRAY", // VC->listExpr("_BITVECTOR", VC->ratExpr(32)), // VC->listExpr("_BITVECTOR", VC->ratExpr(8))))); } else if (*$3 == "QF_BV" || *$3 == "QF_UFBV") { BVENABLED = true; } // This enables the new arith for QF_LRA, but this results in assertion failures in DEBUG mode // else if (*$3 == "QF_LRA") { // cmd = CVC3::Expr(VC->listExpr("_OPTION", VC->stringExpr("arith-new"), VC->ratExpr(1))); // } CVC3::Expr cmd2; if (*$3 == "AUFLIA" || *$3 == "AUFLIRA" || *$3 == "AUFNIRA" || *$3 == "LRA" || *$3 == "UFNIA") { cmd2 = CVC3::Expr(VC->listExpr("_OPTION", VC->stringExpr("quant-complete-inst"), VC->ratExpr(1))); } // e if (*$3 == "QF_NIA" || // *$3 == "QF_UFNRA") { // md2 = CVC3::Expr(VC->listExpr("_OPTION", VC->stringExpr("unknown-check-model"), VC->ratExpr(1))); // // else if (*$3 == "QF_LIA" || // *$3 == "QF_AUFLIA" || // *$3 == "QF_AX") { // cmd2 = CVC3::Expr(VC->listExpr("_OPTION", VC->stringExpr("pp-budget"), VC->ratExpr(5000))); // } if (cmd.isNull()) { if (cmd2.isNull()) { $$ = NULL; } else $$ = new CVC3::Expr(cmd2); } else { if (!cmd2.isNull()) { cmd = CVC3::Expr(VC->listExpr("_SEQ", cmd, cmd2)); } $$ = new CVC3::Expr(cmd); } delete $3; } | COLON_TOK EXTRASORTS_TOK LPAREN_TOK sort_symbs RPAREN_TOK { $$ = new CVC3::Expr(VC->listExpr("_TYPE", *$4)); delete $4; } | COLON_TOK EXTRAFUNS_TOK LPAREN_TOK fun_symb_decls RPAREN_TOK { $$ = new CVC3::Expr(VC->listExpr("_SEQ", *$4)); delete $4; } | COLON_TOK EXTRAPREDS_TOK LPAREN_TOK pred_symb_decls RPAREN_TOK { $$ = new CVC3::Expr(VC->listExpr("_SEQ", *$4)); delete $4; } | COLON_TOK NOTES_TOK STRING_TOK { $$ = new CVC3::Expr(VC->listExpr("_ANNOTATION", VC->listExpr(VC->stringExpr("notes"), VC->stringExpr(*$3)))); delete $3; } | COLON_TOK CVC_COMMAND_TOK STRING_TOK { $$ = new CVC3::Expr(VC->listExpr(VC->idExpr("_"+*$3))); delete $3; } | annotation { $$ = new CVC3::Expr(VC->listExpr("_ANNOTATION", *$1)); delete $1; } ; logic_name: SYM_TOK LBRACKET_TOK NUMERAL_TOK RBRACKET_TOK { BVSIZE = atoi($3->c_str()); delete $3; $$ = $1; } | SYM_TOK { $$ = $1; } ; status: SAT_TOK { TRANSLATOR->setStatus("sat"); $$ = NULL; } | UNSAT_TOK { TRANSLATOR->setStatus("unsat"); $$ = NULL; } | UNKNOWN_TOK { TRANSLATOR->setStatus("unknown"); $$ = NULL; } ; sort_symbs: sort_symb { $$ = new std::vector; $$->push_back(*$1); delete $1; } | sort_symbs sort_symb { $1->push_back(*$2); $$ = $1; delete $2; } ; fun_symb_decls: fun_symb_decl { $$ = new std::vector; $$->push_back(*$1); delete $1; } | fun_symb_decls fun_symb_decl { $1->push_back(*$2); $$ = $1; delete $2; } ; fun_symb_decl: LPAREN_TOK fun_sig annotations RPAREN_TOK { $$ = $2; delete $3; } | LPAREN_TOK fun_sig RPAREN_TOK { $$ = $2; } ; fun_sig: fun_symb sort_symbs { if ($2->size() == 1) { $$ = new CVC3::Expr(VC->listExpr("_CONST", VC->listExpr(*$1), (*$2)[0])); } else { CVC3::Expr tmp(VC->listExpr("_ARROW", *$2)); $$ = new CVC3::Expr(VC->listExpr("_CONST", VC->listExpr(*$1), tmp)); } delete $1; delete $2; } ; pred_symb_decls: pred_symb_decl { $$ = new std::vector; $$->push_back(*$1); delete $1; } | pred_symb_decls pred_symb_decl { $1->push_back(*$2); $$ = $1; delete $2; } ; pred_symb_decl: LPAREN_TOK pred_sig annotations RPAREN_TOK { $$ = $2; delete $3; } | LPAREN_TOK pred_sig RPAREN_TOK { $$ = $2; } ; pred_sig: pred_symb sort_symbs { std::vector tmp(*$2); tmp.push_back(VC->idExpr("_BOOLEAN")); CVC3::Expr tmp2(VC->listExpr("_ARROW", tmp)); $$ = new CVC3::Expr(VC->listExpr("_CONST", VC->listExpr(*$1), tmp2)); delete $1; delete $2; } | pred_symb { $$ = new CVC3::Expr(VC->listExpr("_CONST", VC->listExpr(*$1), VC->idExpr("_BOOLEAN"))); delete $1; } ; an_formulas: an_formula { $$ = new std::vector; $$->push_back(*$1); delete $1; } | an_formulas an_formula { $1->push_back(*$2); $$ = $1; delete $2; } ; an_formula: an_atom { $$ = $1; } | LPAREN_TOK connective an_formulas annotations RPAREN_TOK { $$ = new CVC3::Expr(VC->listExpr(*$2, *$3)); delete $2; delete $3; delete $4; } | LPAREN_TOK connective an_formulas RPAREN_TOK { $$ = new CVC3::Expr(VC->listExpr(*$2, *$3)); delete $2; delete $3; } | LPAREN_TOK quant_symb quant_vars an_formula patterns_annotations RPAREN_TOK { $$ = new CVC3::Expr(VC->listExpr(*$2, VC->listExpr(*$3), *$4, VC->listExpr((*$5).first))); delete $2; delete $3; delete $4; delete $5; } | LPAREN_TOK quant_symb quant_vars an_formula RPAREN_TOK { $$ = new CVC3::Expr(VC->listExpr(*$2, VC->listExpr(*$3), *$4)); delete $2; delete $3; delete $4; } | LPAREN_TOK LET_TOK LPAREN_TOK var an_term RPAREN_TOK an_formula annotations RPAREN_TOK { CVC3::Expr e(VC->listExpr(VC->listExpr(*$4, *$5))); $$ = new CVC3::Expr(VC->listExpr("_LET", e, *$7)); delete $4; delete $5; delete $7; delete $8; } | LPAREN_TOK LET_TOK LPAREN_TOK var an_term RPAREN_TOK an_formula RPAREN_TOK { CVC3::Expr e(VC->listExpr(VC->listExpr(*$4, *$5))); $$ = new CVC3::Expr(VC->listExpr("_LET", e, *$7)); delete $4; delete $5; delete $7; } | LPAREN_TOK FLET_TOK LPAREN_TOK fvar an_formula RPAREN_TOK an_formula annotations RPAREN_TOK { CVC3::Expr e(VC->listExpr(VC->listExpr(*$4, *$5))); $$ = new CVC3::Expr(VC->listExpr("_LET", e, *$7)); delete $4; delete $5; delete $7; delete $8; } | LPAREN_TOK FLET_TOK LPAREN_TOK fvar an_formula RPAREN_TOK an_formula RPAREN_TOK { CVC3::Expr e(VC->listExpr(VC->listExpr(*$4, *$5))); $$ = new CVC3::Expr(VC->listExpr("_LET", e, *$7)); delete $4; delete $5; delete $7; } ; patterns_annotations: pattern { $$ = new std::pair, std::vector >; $$->first.push_back(*$1); delete $1; } | annotation { $$ = new std::pair, std::vector >; $$->second.push_back(*$1); delete $1; } | patterns_annotations pattern { $1->first.push_back(*$2); $$ = $1; delete $2; } | patterns_annotations annotation { $1->second.push_back(*$2); $$ = $1; delete $2; } pattern: PAT_TOK LCURBRACK_TOK an_exprs RCURBRACK_TOK { $$ = new CVC3::Expr(VC->listExpr(*$3)); delete $3; } quant_vars: quant_var { $$ = new std::vector; $$->push_back(*$1); delete $1; } | quant_vars quant_var { $1->push_back(*$2); $$ = $1; delete $2; } ; quant_var: LPAREN_TOK var sort_symb RPAREN_TOK { $$ = new CVC3::Expr(VC->listExpr(*$2, *$3)); delete $2; delete $3; } ; quant_symb: EXISTS_TOK { $$ = new std::string("_EXISTS"); } | FORALL_TOK { $$ = new std::string("_FORALL"); } ; connective: NOT_TOK { $$ = new std::string("_NOT"); } | IMPLIES_TOK { $$ = new std::string("_IMPLIES"); } | IF_THEN_ELSE_TOK { $$ = new std::string("_IF"); } | AND_TOK { $$ = new std::string("_AND"); } | OR_TOK { $$ = new std::string("_OR"); } | XOR_TOK { $$ = new std::string("_XOR"); } | IFF_TOK { $$ = new std::string("_IFF"); } ; an_atom: prop_atom { $$ = $1; } | LPAREN_TOK prop_atom annotations RPAREN_TOK { $$ = $2; delete $3; } | LPAREN_TOK pred_symb an_terms annotations RPAREN_TOK { if ($4->size() == 1 && (*$4)[0].getName() == "transclose" && $3->size() == 2) { $$ = new CVC3::Expr(VC->listExpr("_TRANS_CLOSURE", *$2, (*$3)[0], (*$3)[1])); } else { std::vector tmp; tmp.push_back(*$2); tmp.insert(tmp.end(), $3->begin(), $3->end()); $$ = new CVC3::Expr(VC->listExpr(tmp)); } delete $2; delete $3; delete $4; } | LPAREN_TOK pred_symb an_terms RPAREN_TOK { std::vector tmp; tmp.push_back(*$2); tmp.insert(tmp.end(), $3->begin(), $3->end()); $$ = new CVC3::Expr(VC->listExpr(tmp)); delete $2; delete $3; } | LPAREN_TOK DISTINCT_TOK an_terms annotations RPAREN_TOK { $$ = new CVC3::Expr(VC->listExpr("_DISTINCT", *$3)); // std::vector tmp; // tmp.push_back(*$2); // tmp.insert(tmp.end(), $3->begin(), $3->end()); // $$ = new CVC3::Expr(VC->listExpr(tmp)); // for (unsigned i = 0; i < (*$3).size(); ++i) { // tmp.push_back(($3)[i]) // for (unsigned j = i+1; j < (*$3).size(); ++j) { // tmp.push_back(VC->listExpr("_NEQ", (*$3)[i], (*$3)[j])); // } // } // $$ = new CVC3::Expr(VC->listExpr("_AND", tmp)); delete $3; delete $4; } | LPAREN_TOK DISTINCT_TOK an_terms RPAREN_TOK { $$ = new CVC3::Expr(VC->listExpr("_DISTINCT", *$3)); // std::vector tmp; // for (unsigned i = 0; i < (*$3).size(); ++i) { // for (unsigned j = i+1; j < (*$3).size(); ++j) { // tmp.push_back(VC->listExpr("_NEQ", (*$3)[i], (*$3)[j])); // } // } // $$ = new CVC3::Expr(VC->listExpr("_AND", tmp)); delete $3; } ; prop_atom: TRUE_TOK { $$ = new CVC3::Expr(VC->idExpr("_TRUE_EXPR")); } | FALSE_TOK { $$ = new CVC3::Expr(VC->idExpr("_FALSE_EXPR")); } | fvar { $$ = $1; } | pred_symb { $$ = $1; } ; an_terms: an_term { $$ = new std::vector; $$->push_back(*$1); delete $1; } | an_terms an_term { $1->push_back(*$2); $$ = $1; delete $2; } ; an_term: basic_term { $$ = $1; } | LPAREN_TOK basic_term annotations RPAREN_TOK { $$ = $2; delete $3; } | LPAREN_TOK fun_symb an_terms annotations RPAREN_TOK { $2->insert($2->end(), $3->begin(), $3->end()); $$ = new CVC3::Expr(VC->listExpr(*$2)); delete $2; delete $3; delete $4; } | LPAREN_TOK fun_symb an_terms RPAREN_TOK { $2->insert($2->end(), $3->begin(), $3->end()); $$ = new CVC3::Expr(VC->listExpr(*$2)); delete $2; delete $3; } | LPAREN_TOK ITE_TOK an_formula an_term an_term annotations RPAREN_TOK { $$ = new CVC3::Expr(VC->listExpr("_IF", *$3, *$4, *$5)); delete $3; delete $4; delete $5; delete $6; } | LPAREN_TOK ITE_TOK an_formula an_term an_term RPAREN_TOK { $$ = new CVC3::Expr(VC->listExpr("_IF", *$3, *$4, *$5)); delete $3; delete $4; delete $5; } | LPAREN_TOK LET_TOK LPAREN_TOK var an_term RPAREN_TOK an_term annotations RPAREN_TOK { CVC3::Expr e(VC->listExpr(VC->listExpr(*$4, *$5))); $$ = new CVC3::Expr(VC->listExpr("_LET", e, *$7)); delete $4; delete $5; delete $7; delete $8; } | LPAREN_TOK LET_TOK LPAREN_TOK var an_term RPAREN_TOK an_term RPAREN_TOK { CVC3::Expr e(VC->listExpr(VC->listExpr(*$4, *$5))); $$ = new CVC3::Expr(VC->listExpr("_LET", e, *$7)); delete $4; delete $5; delete $7; } | LPAREN_TOK FLET_TOK LPAREN_TOK fvar an_formula RPAREN_TOK an_term annotations RPAREN_TOK { CVC3::Expr e(VC->listExpr(VC->listExpr(*$4, *$5))); $$ = new CVC3::Expr(VC->listExpr("_LET", e, *$7)); delete $4; delete $5; delete $7; delete $8; } | LPAREN_TOK FLET_TOK LPAREN_TOK fvar an_formula RPAREN_TOK an_term RPAREN_TOK { CVC3::Expr e(VC->listExpr(VC->listExpr(*$4, *$5))); $$ = new CVC3::Expr(VC->listExpr("_LET", e, *$7)); delete $4; delete $5; delete $7; } ; basic_term: var { $$ = $1; } | fun_symb { if ($1->size() == 1) { $$ = new CVC3::Expr(((*$1)[0])); } else { $$ = new CVC3::Expr(VC->listExpr(*$1)); } delete $1; } ; annotations: annotation { $$ = new std::vector; $$->push_back(*$1); delete $1; } | annotations annotation { $1->push_back(*$2); $$ = $1; delete $2; } ; annotation: attribute { $$ = new CVC3::Expr(VC->listExpr(VC->stringExpr(*$1))); delete $1; } | attribute user_value { $$ = new CVC3::Expr(VC->listExpr(VC->stringExpr(*$1), VC->stringExpr(*$2))); delete $1; delete $2; } ; user_value: USER_VAL_TOK { $$ = $1; } ; sort_symb: SYM_TOK LBRACKET_TOK NUMERAL_TOK RBRACKET_TOK { if (BVENABLED && *$1 == "BitVec") { $$ = new CVC3::Expr(VC->listExpr("_BITVECTOR", VC->ratExpr(*$3))); } else { $$ = new CVC3::Expr(VC->listExpr(*$1, VC->ratExpr(*$3))); } delete $1; delete $3; } | SYM_TOK LBRACKET_TOK NUMERAL_TOK COLON_TOK NUMERAL_TOK RBRACKET_TOK { if (BVENABLED && ARRAYSENABLED && *$1 == "Array") { $$ = new CVC3::Expr(VC->listExpr("_ARRAY", VC->listExpr("_BITVECTOR", VC->ratExpr(*$3)), VC->listExpr("_BITVECTOR", VC->ratExpr(*$5)))); } else { $$ = new CVC3::Expr(VC->listExpr(*$1, VC->ratExpr(*$3), VC->ratExpr(*$5))); } delete $1; delete $3; delete $5; } | SYM_TOK { if (*$1 == "Real") { $$ = new CVC3::Expr(VC->idExpr("_REAL")); } else if (*$1 == "Int") { $$ = new CVC3::Expr(VC->idExpr("_INT")); } else { $$ = new CVC3::Expr(VC->idExpr(*$1)); } delete $1; } ; pred_symb: SYM_TOK { if (BVENABLED && (*$1 == "bvlt" || *$1 == "bvult")) { $$ = new CVC3::Expr(VC->idExpr("_BVLT")); } else if (BVENABLED && (*$1 == "bvleq" || *$1 == "bvule")) { $$ = new CVC3::Expr(VC->idExpr("_BVLE")); } else if (BVENABLED && (*$1 == "bvgeq" || *$1 == "bvuge")) { $$ = new CVC3::Expr(VC->idExpr("_BVGE")); } else if (BVENABLED && (*$1 == "bvgt" || *$1 == "bvugt")) { $$ = new CVC3::Expr(VC->idExpr("_BVGT")); } else if (BVENABLED && *$1 == "bvslt") { $$ = new CVC3::Expr(VC->idExpr("_BVSLT")); } else if (BVENABLED && (*$1 == "bvsleq" || *$1 == "bvsle")) { $$ = new CVC3::Expr(VC->idExpr("_BVSLE")); } else if (BVENABLED && (*$1 == "bvsgeq" || *$1 == "bvsge")) { $$ = new CVC3::Expr(VC->idExpr("_BVSGE")); } else if (BVENABLED && *$1 == "bvsgt") { $$ = new CVC3::Expr(VC->idExpr("_BVSGT")); } else if (*$1 == "IsInt") { $$ = new CVC3::Expr(VC->idExpr("_IS_INTEGER")); } else { $$ = new CVC3::Expr(VC->idExpr(*$1)); } delete $1; } | AR_SYMB { if ($1->length() == 1) { switch ((*$1)[0]) { case '=': $$ = new CVC3::Expr(VC->idExpr("_EQ")); break; case '<': $$ = new CVC3::Expr(VC->idExpr("_LT")); break; case '>': $$ = new CVC3::Expr(VC->idExpr("_GT")); break; default: $$ = new CVC3::Expr(VC->idExpr(*$1)); break; } } else { if (*$1 == "<=") { $$ = new CVC3::Expr(VC->idExpr("_LE")); } else if (*$1 == ">=") { $$ = new CVC3::Expr(VC->idExpr("_GE")); } else $$ = new CVC3::Expr(VC->idExpr(*$1)); } delete $1; } ; fun_symb: SYM_TOK LBRACKET_TOK NUMERAL_TOK RBRACKET_TOK { $$ = new std::vector; if (BVENABLED && *$1 == "repeat") { $$->push_back(VC->idExpr("_BVREPEAT")); } else if (BVENABLED && *$1 == "zero_extend") { $$->push_back(VC->idExpr("_BVZEROEXTEND")); } else if (BVENABLED && *$1 == "sign_extend") { $$->push_back(VC->idExpr("_SX")); $$->push_back(VC->idExpr("_smtlib")); } else if (BVENABLED && *$1 == "rotate_left") { $$->push_back(VC->idExpr("_BVROTL")); } else if (BVENABLED && *$1 == "rotate_right") { $$->push_back(VC->idExpr("_BVROTR")); } else if (BVENABLED && $1->size() > 2 && (*$1)[0] == 'b' && (*$1)[1] == 'v') { int i = 2; while ((*$1)[i] >= '0' && (*$1)[i] <= '9') ++i; if ((*$1)[i] == '\0') { $$->push_back(VC->idExpr("_BVCONST")); $$->push_back(VC->ratExpr($1->substr(2), 10)); } else $$->push_back(VC->idExpr(*$1)); } else $$->push_back(VC->idExpr(*$1)); $$->push_back(VC->ratExpr(*$3)); delete $1; delete $3; } | SYM_TOK LBRACKET_TOK NUMERAL_TOK COLON_TOK NUMERAL_TOK RBRACKET_TOK { $$ = new std::vector; if (BVENABLED && *$1 == "extract") { $$->push_back(VC->idExpr("_EXTRACT")); } else $$->push_back(VC->idExpr(*$1)); $$->push_back(VC->ratExpr(*$3)); $$->push_back(VC->ratExpr(*$5)); delete $1; delete $3; delete $5; } | SYM_TOK { $$ = new std::vector; if (ARRAYSENABLED && *$1 == "select") { $$->push_back(VC->idExpr("_READ")); } else if (ARRAYSENABLED && *$1 == "store") { $$->push_back(VC->idExpr("_WRITE")); } else if (BVENABLED && *$1 == "bit0") { $$->push_back(VC->idExpr("_BVCONST")); $$->push_back(VC->ratExpr(0)); $$->push_back(VC->ratExpr(1)); } else if (BVENABLED && *$1 == "bit1") { $$->push_back(VC->idExpr("_BVCONST")); $$->push_back(VC->ratExpr(1)); $$->push_back(VC->ratExpr(1)); } else if (BVENABLED && *$1 == "concat") { $$->push_back(VC->idExpr("_CONCAT")); } else if (BVENABLED && *$1 == "bvnot") { $$->push_back(VC->idExpr("_BVNEG")); } else if (BVENABLED && *$1 == "bvand") { $$->push_back(VC->idExpr("_BVAND")); } else if (BVENABLED && *$1 == "bvor") { $$->push_back(VC->idExpr("_BVOR")); } else if (BVENABLED && *$1 == "bvneg") { $$->push_back(VC->idExpr("_BVUMINUS")); } else if (BVENABLED && *$1 == "bvadd") { $$->push_back(VC->idExpr("_BVPLUS")); } else if (BVENABLED && *$1 == "bvmul") { $$->push_back(VC->idExpr("_BVMULT")); } else if (BVENABLED && *$1 == "bvudiv") { $$->push_back(VC->idExpr("_BVUDIV")); } else if (BVENABLED && *$1 == "bvurem") { $$->push_back(VC->idExpr("_BVUREM")); } else if (BVENABLED && *$1 == "bvshl") { $$->push_back(VC->idExpr("_BVSHL")); } else if (BVENABLED && *$1 == "bvlshr") { $$->push_back(VC->idExpr("_BVLSHR")); } else if (BVENABLED && *$1 == "bvnand") { $$->push_back(VC->idExpr("_BVNAND")); } else if (BVENABLED && *$1 == "bvnor") { $$->push_back(VC->idExpr("_BVNOR")); } else if (BVENABLED && *$1 == "bvxor") { $$->push_back(VC->idExpr("_BVXOR")); } else if (BVENABLED && *$1 == "bvxnor") { $$->push_back(VC->idExpr("_BVXNOR")); } else if (BVENABLED && *$1 == "bvcomp") { $$->push_back(VC->idExpr("_BVCOMP")); } else if (BVENABLED && *$1 == "bvsub") { $$->push_back(VC->idExpr("_BVSUB")); } else if (BVENABLED && *$1 == "bvsdiv") { $$->push_back(VC->idExpr("_BVSDIV")); } else if (BVENABLED && *$1 == "bvsrem") { $$->push_back(VC->idExpr("_BVSREM")); } else if (BVENABLED && *$1 == "bvsmod") { $$->push_back(VC->idExpr("_BVSMOD")); } else if (BVENABLED && *$1 == "bvashr") { $$->push_back(VC->idExpr("_BVASHR")); } // For backwards compatibility: else if (BVENABLED && *$1 == "shift_left0") { $$->push_back(VC->idExpr("_CONST_WIDTH_LEFTSHIFT")); } else if (BVENABLED && *$1 == "shift_right0") { $$->push_back(VC->idExpr("_RIGHTSHIFT")); } else if (BVENABLED && *$1 == "sign_extend") { $$->push_back(VC->idExpr("_SX")); $$->push_back(VC->idExpr("_smtlib")); } // Bitvector constants else if (BVENABLED && $1->size() > 2 && (*$1)[0] == 'b' && (*$1)[1] == 'v') { bool done = false; if ((*$1)[2] >= '0' && (*$1)[2] <= '9') { int i = 3; while ((*$1)[i] >= '0' && (*$1)[i] <= '9') ++i; if ((*$1)[i] == '\0') { $$->push_back(VC->idExpr("_BVCONST")); $$->push_back(VC->ratExpr($1->substr(2), 10)); $$->push_back(VC->ratExpr(32)); done = true; } } else if ($1->size() > 5) { std::string s = $1->substr(0,5); if (s == "bvbin") { int i = 5; while ((*$1)[i] >= '0' && (*$1)[i] <= '1') ++i; if ((*$1)[i] == '\0') { $$->push_back(VC->idExpr("_BVCONST")); $$->push_back(VC->ratExpr($1->substr(5), 2)); $$->push_back(VC->ratExpr(i-5)); done = true; } } else if (s == "bvhex") { int i = 5; char c = (*$1)[i]; while ((c >= '0' && c <= '9') || (c >= 'a' && c <= 'f') || (c >= 'A' && c <= 'F')) { ++i; c =(*$1)[i]; } if ((*$1)[i] == '\0') { $$->push_back(VC->idExpr("_BVCONST")); $$->push_back(VC->ratExpr($1->substr(5), 16)); $$->push_back(VC->ratExpr(i-5)); done = true; } } } if (!done) $$->push_back(VC->idExpr(*$1)); } else { $$->push_back(VC->idExpr(*$1)); } delete $1; } | AR_SYMB { $$ = new std::vector; if ($1->length() == 1) { switch ((*$1)[0]) { case '+': $$->push_back(VC->idExpr("_PLUS")); break; case '-': $$->push_back(VC->idExpr("_MINUS")); break; case '*': $$->push_back(VC->idExpr("_MULT")); break; case '~': $$->push_back(VC->idExpr("_UMINUS")); break; case '/': $$->push_back(VC->idExpr("_DIVIDE")); break; // case '=': $$->push_back(VC->idExpr("_EQ")); break; // case '<': $$->push_back(VC->idExpr("_LT")); break; // case '>': $$->push_back(VC->idExpr("_GT")); break; default: $$->push_back(VC->idExpr(*$1)); } } // else { // if (*$1 == "<=") { // $$->push_back(VC->idExpr("_LE")); // } else if (*$1 == ">=") { // $$->push_back(VC->idExpr("_GE")); // } else $$->push_back(VC->idExpr(*$1)); // } delete $1; } | NUMERAL_TOK { $$ = new std::vector; CVC3::Expr e = VC->ratExpr(*$1); if(VC->getFlags()["translate"].getBool() && $1->find('.') != std::string::npos) { e = CVC3::Expr(CVC3::REAL_CONST, e); } $$->push_back(e); delete $1; } ; attribute: COLON_TOK SYM_TOK { $$ = $2; } ; var: QUESTION_TOK SYM_TOK { $$ = new CVC3::Expr(VC->idExpr("_"+*$2)); delete $2; } ; fvar: DOLLAR_TOK SYM_TOK { $$ = new CVC3::Expr(VC->idExpr("_"+*$2)); delete $2; } ; an_exprs: an_expr { $$ = new std::vector; $$->push_back(*$1); delete $1; } | an_exprs an_expr { $1->push_back(*$2); $$ = $1; delete $2; } ; an_expr: var { $$ = $1; } | fvar { $$ = $1; } | fun_pred_symb { if ($1->size() == 1) { $$ = new CVC3::Expr(((*$1)[0])); } else { $$ = new CVC3::Expr(VC->listExpr(*$1)); } delete $1; } | LPAREN_TOK NOT_TOK LPAREN_TOK fun_pred_symb an_terms annotations RPAREN_TOK RPAREN_TOK { $4->insert($4->end(), $5->begin(), $5->end()); $$ = new CVC3::Expr(VC->listExpr(*$4)); $$ = new CVC3::Expr(VC->listExpr("_NOT", *$$)); delete $4; delete $5; delete $6; } | LPAREN_TOK NOT_TOK LPAREN_TOK fun_pred_symb an_terms RPAREN_TOK RPAREN_TOK { $4->insert($4->end(), $5->begin(), $5->end()); $$ = new CVC3::Expr(VC->listExpr(*$4)); $$ = new CVC3::Expr(VC->listExpr("_NOT", *$$)); delete $4; delete $5; } | LPAREN_TOK fun_pred_symb an_terms annotations RPAREN_TOK { $2->insert($2->end(), $3->begin(), $3->end()); $$ = new CVC3::Expr(VC->listExpr(*$2)); delete $2; delete $3; delete $4; } | LPAREN_TOK fun_pred_symb an_terms RPAREN_TOK { $2->insert($2->end(), $3->begin(), $3->end()); $$ = new CVC3::Expr(VC->listExpr(*$2)); delete $2; delete $3; } | LPAREN_TOK LET_TOK LPAREN_TOK var an_term RPAREN_TOK an_expr annotations RPAREN_TOK { CVC3::Expr e(VC->listExpr(VC->listExpr(*$4, *$5))); $$ = new CVC3::Expr(VC->listExpr("_LET", e, *$7)); delete $4; delete $5; delete $7; delete $8; } | LPAREN_TOK LET_TOK LPAREN_TOK var an_term RPAREN_TOK an_expr RPAREN_TOK { CVC3::Expr e(VC->listExpr(VC->listExpr(*$4, *$5))); $$ = new CVC3::Expr(VC->listExpr("_LET", e, *$7)); delete $4; delete $5; delete $7; } | LPAREN_TOK FLET_TOK LPAREN_TOK fvar an_formula RPAREN_TOK an_expr annotations RPAREN_TOK { CVC3::Expr e(VC->listExpr(VC->listExpr(*$4, *$5))); $$ = new CVC3::Expr(VC->listExpr("_LET", e, *$7)); delete $4; delete $5; delete $7; delete $8; } | LPAREN_TOK FLET_TOK LPAREN_TOK fvar an_formula RPAREN_TOK an_expr RPAREN_TOK { CVC3::Expr e(VC->listExpr(VC->listExpr(*$4, *$5))); $$ = new CVC3::Expr(VC->listExpr("_LET", e, *$7)); delete $4; delete $5; delete $7; } ; fun_pred_symb: SYM_TOK LBRACKET_TOK NUMERAL_TOK RBRACKET_TOK { $$ = new std::vector; if (BVENABLED && *$1 == "repeat") { $$->push_back(VC->idExpr("_BVREPEAT")); } else if (BVENABLED && *$1 == "zero_extend") { $$->push_back(VC->idExpr("_BVZEROEXTEND")); } else if (BVENABLED && *$1 == "sign_extend") { $$->push_back(VC->idExpr("_SX")); $$->push_back(VC->idExpr("_smtlib")); } else if (BVENABLED && *$1 == "rotate_left") { $$->push_back(VC->idExpr("_BVROTL")); } else if (BVENABLED && *$1 == "rotate_right") { $$->push_back(VC->idExpr("_BVROTR")); } else if (BVENABLED && $1->size() > 2 && (*$1)[0] == 'b' && (*$1)[1] == 'v') { int i = 2; while ((*$1)[i] >= '0' && (*$1)[i] <= '9') ++i; if ((*$1)[i] == '\0') { $$->push_back(VC->idExpr("_BVCONST")); $$->push_back(VC->ratExpr($1->substr(2), 10)); } else $$->push_back(VC->idExpr(*$1)); } else $$->push_back(VC->idExpr(*$1)); $$->push_back(VC->ratExpr(*$3)); delete $1; delete $3; } | SYM_TOK LBRACKET_TOK NUMERAL_TOK COLON_TOK NUMERAL_TOK RBRACKET_TOK { $$ = new std::vector; if (BVENABLED && *$1 == "extract") { $$->push_back(VC->idExpr("_EXTRACT")); } else $$->push_back(VC->idExpr(*$1)); $$->push_back(VC->ratExpr(*$3)); $$->push_back(VC->ratExpr(*$5)); delete $1; delete $3; delete $5; } | SYM_TOK { $$ = new std::vector; if (ARRAYSENABLED && *$1 == "select") { $$->push_back(VC->idExpr("_READ")); } else if (ARRAYSENABLED && *$1 == "store") { $$->push_back(VC->idExpr("_WRITE")); } else if (BVENABLED && *$1 == "bit0") { $$->push_back(VC->idExpr("_BVCONST")); $$->push_back(VC->ratExpr(0)); $$->push_back(VC->ratExpr(1)); } else if (BVENABLED && *$1 == "bit1") { $$->push_back(VC->idExpr("_BVCONST")); $$->push_back(VC->ratExpr(1)); $$->push_back(VC->ratExpr(1)); } else if (BVENABLED && *$1 == "concat") { $$->push_back(VC->idExpr("_CONCAT")); } else if (BVENABLED && *$1 == "bvnot") { $$->push_back(VC->idExpr("_BVNEG")); } else if (BVENABLED && *$1 == "bvand") { $$->push_back(VC->idExpr("_BVAND")); } else if (BVENABLED && *$1 == "bvor") { $$->push_back(VC->idExpr("_BVOR")); } else if (BVENABLED && *$1 == "bvneg") { $$->push_back(VC->idExpr("_BVUMINUS")); } else if (BVENABLED && *$1 == "bvadd") { $$->push_back(VC->idExpr("_BVPLUS")); } else if (BVENABLED && *$1 == "bvmul") { $$->push_back(VC->idExpr("_BVMULT")); } else if (BVENABLED && *$1 == "bvudiv") { $$->push_back(VC->idExpr("_BVUDIV")); } else if (BVENABLED && *$1 == "bvurem") { $$->push_back(VC->idExpr("_BVUREM")); } else if (BVENABLED && *$1 == "bvshl") { $$->push_back(VC->idExpr("_BVSHL")); } else if (BVENABLED && *$1 == "bvlshr") { $$->push_back(VC->idExpr("_BVLSHR")); } else if (BVENABLED && *$1 == "bvnand") { $$->push_back(VC->idExpr("_BVNAND")); } else if (BVENABLED && *$1 == "bvnor") { $$->push_back(VC->idExpr("_BVNOR")); } else if (BVENABLED && *$1 == "bvxor") { $$->push_back(VC->idExpr("_BVXOR")); } else if (BVENABLED && *$1 == "bvxnor") { $$->push_back(VC->idExpr("_BVXNOR")); } else if (BVENABLED && *$1 == "bvcomp") { $$->push_back(VC->idExpr("_BVCOMP")); } else if (BVENABLED && *$1 == "bvsub") { $$->push_back(VC->idExpr("_BVSUB")); } else if (BVENABLED && *$1 == "bvsdiv") { $$->push_back(VC->idExpr("_BVSDIV")); } else if (BVENABLED && *$1 == "bvsrem") { $$->push_back(VC->idExpr("_BVSREM")); } else if (BVENABLED && *$1 == "bvsmod") { $$->push_back(VC->idExpr("_BVSMOD")); } else if (BVENABLED && *$1 == "bvashr") { $$->push_back(VC->idExpr("_BVASHR")); } // predicates else if (BVENABLED && (*$1 == "bvlt" || *$1 == "bvult")) { $$->push_back(VC->idExpr("_BVLT")); } else if (BVENABLED && (*$1 == "bvleq" || *$1 == "bvule")) { $$->push_back(VC->idExpr("_BVLE")); } else if (BVENABLED && (*$1 == "bvgeq" || *$1 == "bvuge")) { $$->push_back(VC->idExpr("_BVGE")); } else if (BVENABLED && (*$1 == "bvgt" || *$1 == "bvugt")) { $$->push_back(VC->idExpr("_BVGT")); } else if (BVENABLED && *$1 == "bvslt") { $$->push_back(VC->idExpr("_BVSLT")); } else if (BVENABLED && (*$1 == "bvsleq" || *$1 == "bvsle")) { $$->push_back(VC->idExpr("_BVSLE")); } else if (BVENABLED && (*$1 == "bvsgeq" || *$1 == "bvsge")) { $$->push_back(VC->idExpr("_BVSGE")); } else if (BVENABLED && *$1 == "bvsgt") { $$->push_back(VC->idExpr("_BVSGT")); } else if (*$1 == "IsInt") { $$->push_back(VC->idExpr("_IS_INTEGER")); } // For backwards compatibility: else if (BVENABLED && *$1 == "shift_left0") { $$->push_back(VC->idExpr("_CONST_WIDTH_LEFTSHIFT")); } else if (BVENABLED && *$1 == "shift_right0") { $$->push_back(VC->idExpr("_RIGHTSHIFT")); } else if (BVENABLED && *$1 == "sign_extend") { $$->push_back(VC->idExpr("_SX")); $$->push_back(VC->idExpr("_smtlib")); } // Bitvector constants else if (BVENABLED && $1->size() > 2 && (*$1)[0] == 'b' && (*$1)[1] == 'v') { bool done = false; if ((*$1)[2] >= '0' && (*$1)[2] <= '9') { int i = 3; while ((*$1)[i] >= '0' && (*$1)[i] <= '9') ++i; if ((*$1)[i] == '\0') { $$->push_back(VC->idExpr("_BVCONST")); $$->push_back(VC->ratExpr($1->substr(2), 10)); $$->push_back(VC->ratExpr(32)); done = true; } } else if ($1->size() > 5) { std::string s = $1->substr(0,5); if (s == "bvbin") { int i = 5; while ((*$1)[i] >= '0' && (*$1)[i] <= '1') ++i; if ((*$1)[i] == '\0') { $$->push_back(VC->idExpr("_BVCONST")); $$->push_back(VC->ratExpr($1->substr(5), 2)); $$->push_back(VC->ratExpr(i-5)); done = true; } } else if (s == "bvhex") { int i = 5; char c = (*$1)[i]; while ((c >= '0' && c <= '9') || (c >= 'a' && c <= 'f') || (c >= 'A' && c <= 'F')) { ++i; c =(*$1)[i]; } if ((*$1)[i] == '\0') { $$->push_back(VC->idExpr("_BVCONST")); $$->push_back(VC->ratExpr($1->substr(5), 16)); $$->push_back(VC->ratExpr(i-5)); done = true; } } } if (!done) $$->push_back(VC->idExpr(*$1)); } else { $$->push_back(VC->idExpr(*$1)); } delete $1; } | AR_SYMB { $$ = new std::vector; if ($1->length() == 1) { switch ((*$1)[0]) { case '+': $$->push_back(VC->idExpr("_PLUS")); break; case '-': $$->push_back(VC->idExpr("_MINUS")); break; case '*': $$->push_back(VC->idExpr("_MULT")); break; case '~': $$->push_back(VC->idExpr("_UMINUS")); break; case '/': $$->push_back(VC->idExpr("_DIVIDE")); break; case '=': $$->push_back(VC->idExpr("_EQ")); break; case '<': $$->push_back(VC->idExpr("_LT")); break; case '>': $$->push_back(VC->idExpr("_GT")); break; default: $$->push_back(VC->idExpr(*$1)); } } else { if (*$1 == "<=") { $$->push_back(VC->idExpr("_LE")); } else if (*$1 == ">=") { $$->push_back(VC->idExpr("_GE")); } else $$->push_back(VC->idExpr(*$1)); } delete $1; } | NUMERAL_TOK { $$ = new std::vector; CVC3::Expr e = VC->ratExpr(*$1); if(VC->getFlags()["translate"].getBool() && $1->find('.') != std::string::npos) { e = CVC3::Expr(CVC3::REAL_CONST, e); } $$->push_back(e); delete $1; } ; %% cvc3-2.4.1/src/parser/parser_temp.h0000664000175400017540000000457511366166033017053 0ustar mdetersmdeters/*****************************************************************************/ /*! * \file parser_temp.h * * Author: Sergey Berezin * * Created: Wed Feb 5 17:53:02 2003 * *
* * License to use, copy, modify, sell and/or distribute this software * and its documentation for any purpose is hereby granted without * royalty, subject to the terms and conditions defined in the \ref * LICENSE file provided with this distribution. * *
* * A class used to communicate with the actual parser. No one else * should use it. */ /*****************************************************************************/ #ifndef _cvc3__parser_temp_h_ #define _cvc3__parser_temp_h_ #include "expr.h" #include "exception.h" namespace CVC3 { class ValidityChecker; class Translator; class ParserTemp { private: // Counter for uniqueID of bound variables int d_uid; // The main prompt when running interactive std::string prompt1; // The interactive prompt in the middle of a multi-line command std::string prompt2; // The currently used prompt std::string prompt; public: ValidityChecker* vc; Translator* translator; std::istream* is; // The current input line int lineNum; // File name std::string fileName; // The last parsed Expr Expr expr; // Whether we are done or not bool done; // Whether we are running interactive bool interactive; // Whether arrays are enabled for smt-lib format bool arrFlag; // Whether bit-vectors are enabled for smt-lib format bool bvFlag; // Size of bit-vectors for smt-lib format int bvSize; // Did we encounter a formula query (smtlib) bool queryParsed; // Default constructor ParserTemp() : d_uid(0), prompt1("CVC> "), prompt2("- "), prompt("CVC> "), lineNum(1), done(false), arrFlag(false), queryParsed(false) { } // Parser error handling (implemented in parser.cpp) int error(const std::string& s); // Get the next uniqueID as a string std::string uniqueID() { std::ostringstream ss; ss << d_uid++; return ss.str(); } // Get the current prompt std::string getPrompt() { return prompt; } // Set the prompt to the main one void setPrompt1() { prompt = prompt1; } // Set the prompt to the secondary one void setPrompt2() { prompt = prompt2; } }; } // end of namespace CVC3 #endif cvc3-2.4.1/src/parser/Lisp.y0000664000175400017540000000623311103725114015441 0ustar mdetersmdeters%{ /*****************************************************************************/ /*! * \file PL.y * * Author: Mehul Trivedi * * Created: Aug 08 01:45:43 GMT 2004 * *
* * License to use, copy, modify, sell and/or distribute this software * and its documentation for any purpose is hereby granted without * royalty, subject to the terms and conditions defined in the \ref * LICENSE file provided with this distribution. * *
* */ /*****************************************************************************/ /* PL.y Mehul Trivedi, 8/14/04 This file contains the bison code for the parser that reads in CVC commands in lisp language. */ #include "vc.h" #include "parser_exception.h" #include "parser_temp.h" // Exported shared data namespace CVC3 { extern ParserTemp* parserTemp; } // Define shortcuts for various things #define TMP CVC3::parserTemp #define EXPR CVC3::parserTemp->expr #define VC (CVC3::parserTemp->vc) #define RAT(args) CVC3::newRational args // Suppress the bogus warning suppression in bison (it generates // compile error) #undef __GNUC_MINOR__ /* stuff that lives in Lisp.lex */ extern int Lisplex(void); int Lisperror(const char *s) { std::ostringstream ss; ss << CVC3::parserTemp->fileName << ":" << CVC3::parserTemp->lineNum << ": " << s; return CVC3::parserTemp->error(ss.str()); } #define YYLTYPE_IS_TRIVIAL 1 #define YYMAXDEPTH 10485760 %} %union { std::string *str; CVC3::Expr *node; std::vector *vec; int kind; }; %start cmd /* strings are for better error messages. "_TOK" is so macros don't conflict with kind names */ %token BINARY_TOK "0b" %token HEX_TOK "0x" %token DONE_TOK %type Exprs %type Identifier StringLiteral Numeral Binary Hex %type Expr %token ID_TOK STRINGLIT_TOK NUMERAL_TOK /*%token DONE*/ %% cmd : Expr { EXPR = *$1; delete $1; YYACCEPT; } ; Expr : Identifier { } | StringLiteral { } | Numeral { } | Binary { } | Hex { } | '(' Exprs ')' { $$ = new CVC3::Expr(VC->listExpr(*$2)); delete $2; } | DONE_TOK { TMP->done = true; EXPR = CVC3::Expr(); YYACCEPT; } ; Identifier : ID_TOK { $$ = new CVC3::Expr(VC->idExpr(*$1)); delete $1; } ; StringLiteral : STRINGLIT_TOK { $$ = new CVC3::Expr(VC->stringExpr(*$1)); delete $1; } ; Numeral : NUMERAL_TOK { $$ = new CVC3::Expr(VC->ratExpr((*$1))); delete $1; } ; Binary : BINARY_TOK NUMERAL_TOK { $$ = new CVC3::Expr(VC->stringExpr(*$2)); delete $2; } ; Hex : HEX_TOK NUMERAL_TOK { $$ = new CVC3::Expr(VC->ratExpr(*$2, 16)); delete $2; } ; Exprs : { $$ = new std::vector; } | Exprs Expr { $1->push_back(*$2); delete $2; } ; %% cvc3-2.4.1/src/parser/smtlib.lex0000664000175400017540000001565611565512536016373 0ustar mdetersmdeters%{ /*****************************************************************************/ /*! * \file smtlib.lex * * Author: Clark Barrett * * Created: 2005 * *
* * License to use, copy, modify, sell and/or distribute this software * and its documentation for any purpose is hereby granted without * royalty, subject to the terms and conditions defined in the \ref * LICENSE file provided with this distribution. * *
* */ /*****************************************************************************/ #include #include "parser_temp.h" #include "expr_manager.h" /* for the benefit of parsesmtlib_defs.h */ #include "parsesmtlib_defs.h" #include "debug.h" namespace CVC3 { extern ParserTemp* parserTemp; } extern int smtlib_inputLine; extern char *smtlibtext; extern int smtliberror (const char *msg); static int smtlibinput(std::istream& is, char* buf, int size) { int res; if(is) { // If interactive, read line by line; otherwise read as much as we // can gobble if(CVC3::parserTemp->interactive) { // Print the current prompt std::cout << CVC3::parserTemp->getPrompt() << std::flush; // Set the prompt to "middle of the command" one CVC3::parserTemp->setPrompt2(); // Read the line is.getline(buf, size-1); } else // Set the terminator char to 0 is.getline(buf, size-1, 0); // If failbit is set, but eof is not, it means the line simply // didn't fit; so we clear the state and keep on reading. bool partialStr = is.fail() && !is.eof(); if(partialStr) is.clear(); for(res = 0; resis, buf, max_size); int smtlib_bufSize() { return YY_BUF_SIZE; } YY_BUFFER_STATE smtlib_buf_state() { return YY_CURRENT_BUFFER; } /* some wrappers for methods that need to refer to a struct. These are used by CVC3::Parser. */ void *smtlib_createBuffer(int sz) { return (void *)smtlib_create_buffer(NULL, sz); } void smtlib_deleteBuffer(void *buf_state) { smtlib_delete_buffer((struct yy_buffer_state *)buf_state); } void smtlib_switchToBuffer(void *buf_state) { smtlib_switch_to_buffer((struct yy_buffer_state *)buf_state); } void *smtlib_bufState() { return (void *)smtlib_buf_state(); } void smtlib_setInteractive(bool is_interactive) { yy_set_interactive(is_interactive); } // File-static (local to this file) variables and functions static std::string _string_lit; static char escapeChar(char c) { switch(c) { case 'n': return '\n'; case 't': return '\t'; default: return c; } } // for now, we don't have subranges. // // ".." { return DOTDOT_TOK; } /*OPCHAR (['!#?\_$&\|\\@])*/ %} %option noyywrap %option nounput %option noreject %option noyymore %option yylineno %x COMMENT %x STRING_LITERAL %x USER_VALUE %s PAT_MODE LETTER ([a-zA-Z]) DIGIT ([0-9]) OPCHAR (['\.\_]) IDCHAR ({LETTER}|{DIGIT}|{OPCHAR}) %% [\n] { CVC3::parserTemp->lineNum++; } [ \t\r\f] { /* skip whitespace */ } {DIGIT}+"\."{DIGIT}+ { smtliblval.str = new std::string(smtlibtext); return NUMERAL_TOK; } {DIGIT}+ { smtliblval.str = new std::string(smtlibtext); return NUMERAL_TOK; } ";" { BEGIN COMMENT; } "\n" { BEGIN INITIAL; /* return to normal mode */ CVC3::parserTemp->lineNum++; } . { /* stay in comment mode */ } "\"" { BEGIN STRING_LITERAL; _string_lit.erase(_string_lit.begin(), _string_lit.end()); } "\\". { /* escape characters (like \n or \") */ _string_lit.insert(_string_lit.end(), escapeChar(smtlibtext[1])); } "\"" { BEGIN INITIAL; /* return to normal mode */ smtliblval.str = new std::string(_string_lit); return STRING_TOK; } . { _string_lit.insert(_string_lit.end(),*smtlibtext); } ":pat" { BEGIN PAT_MODE; return PAT_TOK;} "}" { BEGIN INITIAL; return RCURBRACK_TOK; } "{" { BEGIN USER_VALUE; _string_lit.erase(_string_lit.begin(), _string_lit.end()); } "\\"[{}] { /* escape characters */ _string_lit.insert(_string_lit.end(),smtlibtext[1]); } "}" { BEGIN INITIAL; /* return to normal mode */ smtliblval.str = new std::string(_string_lit); return USER_VAL_TOK; } "\n" { _string_lit.insert(_string_lit.end(),'\n'); CVC3::parserTemp->lineNum++; } . { _string_lit.insert(_string_lit.end(),*smtlibtext); } "true" { return TRUE_TOK; } "false" { return FALSE_TOK; } "ite" { return ITE_TOK; } "not" { return NOT_TOK; } "implies" { return IMPLIES_TOK; } "if_then_else" { return IF_THEN_ELSE_TOK; } "and" { return AND_TOK; } "or" { return OR_TOK; } "xor" { return XOR_TOK; } "iff" { return IFF_TOK; } "exists" { return EXISTS_TOK; } "forall" { return FORALL_TOK; } "let" { return LET_TOK; } "flet" { return FLET_TOK; } "notes" { return NOTES_TOK; } "cvc_command" { return CVC_COMMAND_TOK; } "logic" { return LOGIC_TOK; } "sat" { return SAT_TOK; } "unsat" { return UNSAT_TOK; } "unknown" { return UNKNOWN_TOK; } "assumption" { return ASSUMPTION_TOK; } "formula" { return FORMULA_TOK; } "status" { return STATUS_TOK; } "benchmark" { return BENCHMARK_TOK; } "source" { return SOURCE_TOK; } "category" { return CATEGORY_TOK; } "extrasorts" { return EXTRASORTS_TOK; } "extrafuns" { return EXTRAFUNS_TOK; } "extrapreds" { return EXTRAPREDS_TOK; } "distinct" { return DISTINCT_TOK; } ":pattern" { return PAT_TOK; } ":" { return COLON_TOK; } "\[" { return LBRACKET_TOK; } "\]" { return RBRACKET_TOK; } "{" { return LCURBRACK_TOK;} "}" { return RCURBRACK_TOK;} "(" { return LPAREN_TOK; } ")" { return RPAREN_TOK; } "$" { return DOLLAR_TOK; } "?" { return QUESTION_TOK; } [=<>&@#+\-*/%|~]+ { smtliblval.str = new std::string(smtlibtext); return AR_SYMB; } ({LETTER})({IDCHAR})* {smtliblval.str = new std::string(smtlibtext); return SYM_TOK; } ({IDCHAR})({IDCHAR})* {smtliblval.str = new std::string(smtlibtext); return ID_TOK; } <> { return EOF_TOK; } . { smtliberror("Illegal input character."); } %% cvc3-2.4.1/src/parser/PL.lex0000664000175400017540000002252111224726162015373 0ustar mdetersmdeters%{ /*****************************************************************************/ /*! * \file PL.lex * * Author: Sergey Berezin * * Created: Feb 06 03:00:43 GMT 2003 * *
* * License to use, copy, modify, sell and/or distribute this software * and its documentation for any purpose is hereby granted without * royalty, subject to the terms and conditions defined in the \ref * LICENSE file provided with this distribution. * *
* */ /*****************************************************************************/ #include #include "parser_temp.h" #include "expr_manager.h" /* for the benefit of parsePL_defs.h */ #include "parsePL_defs.h" #include "debug.h" namespace CVC3 { extern ParserTemp* parserTemp; } extern int PL_inputLine; extern char *PLtext; extern int PLerror (const char *msg); static int PLinput(std::istream& is, char* buf, int size) { int res; if(is) { // If interactive, read line by line; otherwise read as much as we // can gobble if(CVC3::parserTemp->interactive) { // Print the current prompt std::cout << CVC3::parserTemp->getPrompt() << std::flush; // Set the prompt to "middle of the command" one CVC3::parserTemp->setPrompt2(); // Read the line is.getline(buf, size-1); } else // Set the terminator char to 0 is.getline(buf, size-1, 0); // If failbit is set, but eof is not, it means the line simply // didn't fit; so we clear the state and keep on reading. bool partialStr = is.fail() && !is.eof(); if(partialStr) is.clear(); for(res = 0; resis, buf, max_size); int PL_bufSize() { return YY_BUF_SIZE; } YY_BUFFER_STATE PL_buf_state() { return YY_CURRENT_BUFFER; } /* some wrappers for methods that need to refer to a struct. These are used by CVC3::Parser. */ void *PL_createBuffer(int sz) { return (void *)PL_create_buffer(NULL, sz); } void PL_deleteBuffer(void *buf_state) { PL_delete_buffer((struct yy_buffer_state *)buf_state); } void PL_switchToBuffer(void *buf_state) { PL_switch_to_buffer((struct yy_buffer_state *)buf_state); } void *PL_bufState() { return (void *)PL_buf_state(); } void PL_setInteractive(bool is_interactive) { yy_set_interactive(is_interactive); } // File-static (local to this file) variables and functions static std::string _string_lit; static char escapeChar(char c) { switch(c) { case 'n': return '\n'; case 't': return '\t'; default: return c; } } // for now, we don't have subranges. // // ".." { return DOTDOT_TOK; } /*OPCHAR (['!#?\_$&\|\\@])*/ %} %option noyywrap %option nounput %option noreject %option noyymore %option yylineno %x COMMENT %x STRING_LITERAL LETTER ([a-zA-Z]) HEX ([0-9a-fA-F]) BITS ([0-1]) DIGIT ([0-9]) OPCHAR (['?\_$~]) ANYTHING ({LETTER}|{DIGIT}|{OPCHAR}) %% [\n] { CVC3::parserTemp->lineNum++; } [ \t\r\f] { /* skip whitespace */ } 0bin{BITS}+ {PLlval.str = new std::string(PLtext+4);return BINARY_TOK; } 0hex{HEX}+ {PLlval.str = new std::string(PLtext+4);return HEX_TOK; } {DIGIT}+ {PLlval.str = new std::string(PLtext);return NUMERAL_TOK; } "%" { BEGIN COMMENT; } "\n" { BEGIN INITIAL; /* return to normal mode */ CVC3::parserTemp->lineNum++; } . { /* stay in comment mode */ } "\"" { BEGIN STRING_LITERAL; _string_lit.erase(_string_lit.begin(), _string_lit.end()); } "\\". { /* escape characters (like \n or \") */ _string_lit.insert(_string_lit.end(), escapeChar(PLtext[1])); } "\"" { BEGIN INITIAL; /* return to normal mode */ PLlval.str = new std::string(_string_lit); return STRINGLIT_TOK; } . { _string_lit.insert(_string_lit.end(),*PLtext); } [()[\]{},.;:'!#?_=] { return PLtext[0]; } ".." { return DOTDOT_TOK; } ":=" { return ASSIGN_TOK; } "/=" { return NEQ_TOK; } "=>" { return IMPLIES_TOK; } "<=>" { return IFF_TOK; } "+" { return PLUS_TOK; } "-" { return MINUS_TOK; } "*" { return MULT_TOK; } "^" { return POW_TOK; } "/" { return DIV_TOK; } "MOD" { return MOD_TOK; } "DIV" { return INTDIV_TOK; } "<" { return LT_TOK; } "<=" { return LE_TOK; } ">" { return GT_TOK; } ">=" { return GE_TOK; } "FLOOR" { return FLOOR_TOK; } "[#" { return SQHASH_TOK; } "#]" { return HASHSQ_TOK; } "(#" { return PARENHASH_TOK; } "#)" { return HASHPAREN_TOK; } "->" { return ARROW_TOK; } "ARROW" { return ARROW_TOK; } "@" { return CONCAT_TOK;} "~" { return BVNEG_TOK;} "&" { return BVAND_TOK;} "|" { return MID_TOK;} "BVXOR" { return BVXOR_TOK;} "BVNAND" { return BVNAND_TOK;} "BVNOR" { return BVNOR_TOK;} "BVCOMP" { return BVCOMP_TOK;} "BVXNOR" { return BVXNOR_TOK;} "<<" { return LEFTSHIFT_TOK;} ">>" { return RIGHTSHIFT_TOK;} "BVSLT" { return BVSLT_TOK;} "BVSGT" { return BVSGT_TOK;} "BVSLE" { return BVSLE_TOK;} "BVSGE" { return BVSGE_TOK;} "SX" { return SX_TOK;} "BVZEROEXTEND" { return BVZEROEXTEND_TOK;} "BVREPEAT" { return BVREPEAT_TOK;} "BVROTL" { return BVROTL_TOK;} "BVROTR" { return BVROTR_TOK;} "BVLT" { return BVLT_TOK;} "BVGT" { return BVGT_TOK;} "BVLE" { return BVLE_TOK;} "BVGE" { return BVGE_TOK;} "DISTINCT" { return DISTINCT_TOK; } "BVTOINT" { return BVTOINT_TOK;} "INTTOBV" { return INTTOBV_TOK;} "BOOLEXTRACT" { return BOOLEXTRACT_TOK;} "BVPLUS" { return BVPLUS_TOK;} "BVUDIV" { return BVUDIV_TOK;} "BVSDIV" { return BVSDIV_TOK;} "BVUREM" { return BVUREM_TOK;} "BVSREM" { return BVSREM_TOK;} "BVSMOD" { return BVSMOD_TOK;} "BVSHL" { return BVSHL_TOK;} "BVASHR" { return BVASHR_TOK;} "BVLSHR" { return BVLSHR_TOK;} "BVSUB" { return BVSUB_TOK;} "BVUMINUS" { return BVUMINUS_TOK;} "BVMULT" { return BVMULT_TOK;} "AND" { return AND_TOK; } "ARRAY" { return ARRAY_TOK; } "BOOLEAN" { return BOOLEAN_TOK; } "DATATYPE" { return DATATYPE_TOK; } "ELSE" { return ELSE_TOK; } "ELSIF" { return ELSIF_TOK; } "END" { return END_TOK; } "ENDIF" { return ENDIF_TOK; } "EXISTS" { return EXISTS_TOK; } "FALSE" { return FALSELIT_TOK; } "FORALL" { return FORALL_TOK; } "IF" { return IF_TOK; } "IN" { return IN_TOK; } "LAMBDA" { return LAMBDA_TOK; } "SIMULATE" { return SIMULATE_TOK; } "LET" { return LET_TOK; } "NOT" { return NOT_TOK; } "IS_INTEGER" { return IS_INTEGER_TOK; } "OF" { return OF_TOK; } "OR" { return OR_TOK; } "REAL" { return REAL_TOK; } "INT" { return INT_TOK;} "SUBTYPE" { return SUBTYPE_TOK;} "BITVECTOR" { return BITVECTOR_TOK;} "THEN" { return THEN_TOK; } "TRUE" { return TRUELIT_TOK; } "TYPE" { return TYPE_TOK; } "WITH" { return WITH_TOK; } "XOR" { return XOR_TOK; } "TCC" { return TCC_TOK; } "PATTERN" { return PATTERN_TOK; } "ARITH_VAR_ORDER" { return ARITH_VAR_ORDER_TOK; } "ASSERT" { return ASSERT_TOK; } "QUERY" { return QUERY_TOK; } "CHECKSAT" { return CHECKSAT_TOK; } "CONTINUE" { return CONTINUE_TOK; } "RESTART" { return RESTART_TOK; } "DBG" { return DBG_TOK; } "TRACE" { return TRACE_TOK; } "UNTRACE" { return UNTRACE_TOK; } "OPTION" { return OPTION_TOK; } "HELP" { return HELP_TOK; } "TRANSFORM" { return TRANSFORM_TOK; } "PRINT" { return PRINT_TOK; } "PRINT_TYPE" { return PRINT_TYPE_TOK; } "CALL" { return CALL_TOK; } "ECHO" { return ECHO_TOK; } "INCLUDE" { return INCLUDE_TOK; } "DUMP_ASSUMPTIONS" { return DUMP_ASSUMPTIONS_TOK; } "DUMP_PROOF" { return DUMP_PROOF_TOK; } "DUMP_SIG" { return DUMP_SIG_TOK; } "DUMP_TCC" { return DUMP_TCC_TOK; } "DUMP_TCC_ASSUMPTIONS" { return DUMP_TCC_ASSUMPTIONS_TOK; } "DUMP_TCC_PROOF" { return DUMP_TCC_PROOF_TOK; } "DUMP_CLOSURE" { return DUMP_CLOSURE_TOK; } "DUMP_CLOSURE_PROOF" { return DUMP_CLOSURE_PROOF_TOK; } "WHERE" { return WHERE_TOK; } "ASSERTIONS" { return ASSERTIONS_TOK; } "ASSUMPTIONS" { return ASSUMPTIONS_TOK; } "COUNTEREXAMPLE" { return COUNTEREXAMPLE_TOK; } "COUNTERMODEL" { return COUNTERMODEL_TOK; } "PUSH" { return PUSH_TOK; } "POP" { return POP_TOK; } "POPTO" { return POPTO_TOK; } "PUSH_SCOPE" { return PUSH_SCOPE_TOK; } "POP_SCOPE" { return POP_SCOPE_TOK; } "POPTO_SCOPE" { return POPTO_SCOPE_TOK; } "RESET" { return RESET_TOK; } "CONTEXT" { return CONTEXT_TOK; } "FORGET" { return FORGET_TOK; } "GET_TYPE" { return GET_TYPE_TOK; } "CHECK_TYPE" { return CHECK_TYPE_TOK; } "GET_CHILD" { return GET_CHILD_TOK; } "GET_OP" { return GET_OP_TOK; } "SUBSTITUTE" { return SUBSTITUTE_TOK; } (({LETTER})|(_)({ANYTHING}))({ANYTHING})* { PLlval.str = new std::string(PLtext); return ID_TOK; } <> { return DONE_TOK; } . { PLerror("Illegal input character."); } %% cvc3-2.4.1/src/parser/Lisp.lex0000664000175400017540000001266311103725114015765 0ustar mdetersmdeters%{ /*****************************************************************************/ /*! * \file Lisp.lex * * Author: Sergey Berezin * * Created: Feb 06 03:00:43 GMT 2003 * *
* * License to use, copy, modify, sell and/or distribute this software * and its documentation for any purpose is hereby granted without * royalty, subject to the terms and conditions defined in the \ref * LICENSE file provided with this distribution. * *
* */ /*****************************************************************************/ #include #include "parser_temp.h" #include "expr_manager.h" /* for the benefit of parseLisp_defs.h */ #include "parseLisp_defs.h" #include "debug.h" namespace CVC3 { extern ParserTemp* parserTemp; } extern int Lisp_inputLine; extern char *Lisptext; extern int Lisperror (const char *msg); static int Lispinput(std::istream& is, char* buf, int size) { int res; if(is) { // If interactive, read line by line; otherwise read as much as we // can gobble if(CVC3::parserTemp->interactive) { // Print the current prompt std::cout << CVC3::parserTemp->getPrompt() << std::flush; // Set the prompt to "middle of the command" one CVC3::parserTemp->setPrompt2(); // Read the line is.getline(buf, size-1); } else // Set the terminator char to 0 is.getline(buf, size-1, 0); // If failbit is set, but eof is not, it means the line simply // didn't fit; so we clear the state and keep on reading. bool partialStr = is.fail() && !is.eof(); if(partialStr) is.clear(); for(res = 0; resis, buf, max_size); int Lisp_bufSize() { return YY_BUF_SIZE; } YY_BUFFER_STATE Lisp_buf_state() { return YY_CURRENT_BUFFER; } /* some wrappers for methods that need to refer to a struct. These are used by CVC3::Parser. */ void *Lisp_createBuffer(int sz) { return (void *)Lisp_create_buffer(NULL, sz); } void Lisp_deleteBuffer(void *buf_state) { Lisp_delete_buffer((struct yy_buffer_state *)buf_state); } void Lisp_switchToBuffer(void *buf_state) { Lisp_switch_to_buffer((struct yy_buffer_state *)buf_state); } void *Lisp_bufState() { return (void *)Lisp_buf_state(); } void Lisp_setInteractive(bool is_interactive) { yy_set_interactive(is_interactive); } // File-static (local to this file) variables and functions static std::string _string_lit; static char escapeChar(char c) { switch(c) { case 'n': return '\n'; case 't': return '\t'; default: return c; } } // for now, we don't have subranges. // // ".." { return DOTDOT_TOK; } /*OPCHAR (['!#?\_$&\|\\@])*/ %} %option noyywrap %option nounput %option noreject %option noyymore %option yylineno %x COMMENT %x STRING_LITERAL LETTER ([a-zA-Z]) DIGIT ([0-9]) OPCHAR (['!#?\_$\|]) ANYTHING ({LETTER}|{DIGIT}|{OPCHAR}) %% [\n] { CVC3::parserTemp->lineNum++; } [ \t\r\f] { /* skip whitespace */ } {DIGIT}+ { Lisplval.str = new std::string(Lisptext); return NUMERAL_TOK; } ";" { BEGIN COMMENT; } "\n" { BEGIN INITIAL; /* return to normal mode */ CVC3::parserTemp->lineNum++; } . { /* stay in comment mode */ } "\"" { BEGIN STRING_LITERAL; _string_lit.erase(_string_lit.begin(), _string_lit.end()); } "\\". { /* escape characters (like \n or \") */ _string_lit.insert(_string_lit.end(), escapeChar(Lisptext[1])); } "\"" { BEGIN INITIAL; /* return to normal mode */ Lisplval.str = new std::string(_string_lit); return STRINGLIT_TOK; } . { _string_lit.insert(_string_lit.end(),*Lisptext); } [().] { return Lisptext[0]; } "0b" { return BINARY_TOK;} "0x" { return HEX_TOK;} ".." { Lisplval.str = new std::string("DOTDOT"); return ID_TOK; } ":=" { Lisplval.str = new std::string("ASSIGN"); return ID_TOK; } "=" { Lisplval.str = new std::string("EQ"); return ID_TOK; } "/=" { Lisplval.str = new std::string("NEQ"); return ID_TOK; } "=>" { Lisplval.str = new std::string("IMPLIES"); return ID_TOK; } "<=>" { Lisplval.str = new std::string("IFF"); return ID_TOK; } "+" { Lisplval.str = new std::string("PLUS"); return ID_TOK; } "-" { Lisplval.str = new std::string("MINUS"); return ID_TOK; } "*" { Lisplval.str = new std::string("MULT"); return ID_TOK; } "^" { Lisplval.str = new std::string("POW"); return ID_TOK; } "/" { Lisplval.str = new std::string("DIV"); return ID_TOK; } "MOD" { Lisplval.str = new std::string("MOD"); return ID_TOK; } "<" { Lisplval.str = new std::string("LT"); return ID_TOK; } "<=" { Lisplval.str = new std::string("LE"); return ID_TOK; } ">=" { Lisplval.str = new std::string("GE"); return ID_TOK; } ">" { Lisplval.str = new std::string("GT"); return ID_TOK; } ({ANYTHING})+ { Lisplval.str = new std::string(Lisptext); return ID_TOK; } <> { return DONE_TOK; } . { Lisperror("Illegal input character."); } %% cvc3-2.4.1/src/parser/smtlib2.y0000644000175400017540000007517711624746722016141 0ustar mdetersmdeters%{ /*****************************************************************************/ /*! * \file smtlib2.y * * Author: Clark Barrett * * Created: Apr 30 2005 * *
* * License to use, copy, modify, sell and/or distribute this software * and its documentation for any purpose is hereby granted without * royalty, subject to the terms and conditions defined in the \ref * LICENSE file provided with this distribution. * *
* */ /*****************************************************************************/ /* This file contains the bison code for the parser that reads in CVC commands in SMT-LIB language. */ #include "vc.h" #include "parser_exception.h" #include "parser_temp.h" #include "translator.h" #include "kinds.h" #include "command_line_flags.h" #include "theory_arith.h" // Exported shared data namespace CVC3 { extern ParserTemp* parserTemp; } // Define shortcuts for various things #define TMP CVC3::parserTemp #define EXPR CVC3::parserTemp->expr #define VC (CVC3::parserTemp->vc) #define ARRAYSENABLED (CVC3::parserTemp->arrFlag) #define BVENABLED (CVC3::parserTemp->bvFlag) #define BVSIZE (CVC3::parserTemp->bvSize) #define RAT(args) CVC3::newRational args #define QUERYPARSED CVC3::parserTemp->queryParsed #define TRANSLATOR CVC3::parserTemp->translator // Suppress the bogus warning suppression in bison (it generates // compile error) #undef __GNUC_MINOR__ /* stuff that lives in smtlib2.lex */ extern int smtlib2lex(void); int smtlib2error(const char *s) { std::ostringstream ss; ss << CVC3::parserTemp->fileName << ":" << CVC3::parserTemp->lineNum << ": " << s; return CVC3::parserTemp->error(ss.str()); } #define YYLTYPE_IS_TRIVIAL 1 #define YYMAXDEPTH 10485760 // static hash_map *operators; %} %union { std::string *str; std::vector *strvec; CVC3::Expr *node; std::vector *vec; std::pair, std::vector > *pat_ann; }; %start command /* strings are for better error messages. "_TOK" is so macros don't conflict with kind names */ %type command command_aux non_keyword_sexpr sexpr term sort_symbol identifier binding sorted_var attribute %type sexprs sort_symbols sort_symbols_nonempty terms bindings sorted_vars attributes numerals %type quantifier %token DECIMAL_TOK %token INTEGER_TOK %token HEX_TOK %token BINARY_TOK %token SYM_TOK %token KEYWORD_TOK %token STRING_TOK %token ASSERT_TOK %token CHECKSAT_TOK %token PUSH_TOK %token POP_TOK %token DECLARE_FUN_TOK %token DECLARE_SORT_TOK %token GET_PROOF_TOK %token GET_ASSIGNMENT_TOK %token GET_VALUE_TOK %token GET_MODEL_TOK %token EXCLAMATION_TOK %token EXIT_TOK %token ITE_TOK %token LET_TOK %token LPAREN_TOK %token RPAREN_TOK %token SET_LOGIC_TOK %token SET_INFO_TOK %token UNDERSCORE_TOK %token EOF_TOK // Logic symbols /* %token AND_TOK */ /* %token AT_TOK */ /* %token DISTINCT_TOK */ /* %token DIV_TOK */ /* %token EQUAL_TOK */ %token EXISTS_TOK /* %token FALSE_TOK */ %token FORALL_TOK /* %token GREATER_THAN_TOK */ /* %token GREATER_THAN_EQ_TOK */ /* %token IFF_TOK */ /* %token IMPLIES_TOK */ /* %token LESS_THAN_TOK */ /* %token LESS_THAN_EQ_TOK */ /* %token MINUS_TOK */ /* %token NOT_TOK */ /* %token OR_TOK */ /* %token PERCENT_TOK */ /* %token PLUS_TOK */ /* %token POUND_TOK */ /* %token STAR_TOK */ /* %token TRUE_TOK */ /* %token XOR_TOK */ %% command: LPAREN_TOK command_aux RPAREN_TOK { EXPR = *$2; delete $2; YYACCEPT; } | EOF_TOK { TMP->done = true; EXPR = CVC3::Expr(); YYACCEPT; } ; command_aux: SET_LOGIC_TOK SYM_TOK { ARRAYSENABLED = false; BVENABLED = false; std::vector subCommands; /* Add the symbols of the core theory */ subCommands.push_back( VC->listExpr("_TYPEDEF", VC->idExpr("Bool"), VC->idExpr("_BOOLEAN")) ); subCommands.push_back( VC->listExpr("_CONST", VC->idExpr("true"), VC->idExpr("Bool"), VC->idExpr("_TRUE_EXPR")) ); subCommands.push_back( VC->listExpr("_CONST", VC->idExpr("false"), VC->idExpr("Bool"), VC->idExpr("_FALSE_EXPR")) ); if (*$2 == "QF_AX" || *$2 == "QF_AUFLIA" || *$2 == "AUFLIA" || *$2 == "QF_AUFLIRA" || *$2 == "AUFLIRA" || *$2 == "QF_AUFNIRA" || *$2 == "AUFNIRA" || *$2 == "QF_AUFBV" || *$2 == "QF_ABV") { ARRAYSENABLED = true; } if (*$2 == "QF_AUFBV" || *$2 == "QF_ABV" || *$2 == "QF_BV" || *$2 == "QF_UFBV") { BVENABLED = true; } /* Add the Int type for logics that include it */ if (*$2 == "AUFLIA" || *$2 == "AUFLIRA" || *$2 == "AUFNIRA" || *$2 == "QF_AUFLIA" || *$2 == "QF_IDL" || *$2 == "QF_LIA" || *$2 == "QF_NIA" || *$2 == "QF_UFIDL" || *$2 == "QF_UFLIA" || *$2 == "UFNIA" ) { subCommands.push_back( VC->listExpr("_TYPEDEF", VC->idExpr("Int"), VC->idExpr("_INT")) ); } /* Add the Real type for logics that include it */ if (*$2 == "AUFLIRA" || *$2 == "AUFNIRA" || *$2 == "LRA" || *$2 == "QF_RDL" || *$2 == "QF_LRA" || *$2 == "QF_NRA" || *$2 == "QF_UFLRA" || *$2 == "QF_UFNRA" || *$2 == "UFLRA" || *$2 == "QF_UFRDL" ) { subCommands.push_back( VC->listExpr("_TYPEDEF", VC->idExpr("Real"), VC->idExpr("_REAL")) ); } /* Enable complete instantiation heuristics */ if (*$2 == "AUFLIA" || *$2 == "AUFLIRA" || *$2 == "AUFNIRA" || *$2 == "LRA" || *$2 == "UFLRA" || *$2 == "UFNIA") { subCommands.push_back( VC->listExpr("_OPTION", VC->stringExpr("quant-complete-inst"), VC->ratExpr(1)) ); } $$ = new CVC3::Expr(VC->listExpr("_SEQ", subCommands)); delete $2; } | SET_INFO_TOK KEYWORD_TOK sexpr { $$ = NULL; if(*$2 == ":status") { TRANSLATOR->setStatus((*$3)[0].getString()); } else if(*$2 == ":source") { if($3->getKind() == CVC3::STRING_EXPR) { TRANSLATOR->setSource($3->getString()); } else if($3->getKind() == CVC3::ID) { TRANSLATOR->setSource((*$3)[0].getString()); } else { smtlib2error("bad type for set-info :source"); } } else if(*$2 == ":category") { TRANSLATOR->setCategory($3->getString()); } else if(*$2 == ":notes") { std::string notes; if($3->getKind() == CVC3::STRING_EXPR) { notes = $3->getString(); } else if($3->getKind() == CVC3::ID) { notes = (*$3)[0].getString(); } else { smtlib2error("bad type for set-info :notes"); } $$ = new CVC3::Expr(VC->listExpr("_ANNOTATION", VC->listExpr(VC->stringExpr("notes"), VC->stringExpr(notes)))); } delete $2; delete $3; if($$ == NULL) { $$ = new CVC3::Expr(); } } | DECLARE_SORT_TOK SYM_TOK INTEGER_TOK { $$ = new CVC3::Expr(VC->listExpr("_TYPE", VC->idExpr(*$2))); delete $2; } | DECLARE_FUN_TOK SYM_TOK LPAREN_TOK sort_symbols RPAREN_TOK sort_symbol { if ($4->size() == 0) { $$ = new CVC3::Expr(VC->listExpr("_CONST", VC->idExpr(*$2), (*$6))); } else { $4->push_back( *$6 ); CVC3::Expr tmp(VC->listExpr("_ARROW", *$4)); $$ = new CVC3::Expr(VC->listExpr("_CONST", VC->idExpr(*$2), tmp)); } delete $2; delete $4; delete $6; } | ASSERT_TOK term { $$ = new CVC3::Expr(VC->listExpr("_ASSERT", *$2)); delete $2; } | CHECKSAT_TOK { $$ = new CVC3::Expr(VC->listExpr("_CHECKSAT", CVC3::Expr(VC->idExpr("_TRUE_EXPR")))); } | PUSH_TOK INTEGER_TOK { $$ = new CVC3::Expr(VC->listExpr("_PUSH", CVC3::Expr(VC->ratExpr((*$2))))); } | POP_TOK INTEGER_TOK { $$ = new CVC3::Expr(VC->listExpr("_POP", CVC3::Expr(VC->ratExpr((*$2))))); } | GET_PROOF_TOK { $$ = new CVC3::Expr(VC->listExpr(VC->idExpr("_DUMP_PROOF"))); } | GET_ASSIGNMENT_TOK { $$ = new CVC3::Expr(VC->listExpr(VC->idExpr("_GET_ASSIGNMENT"))); } | GET_VALUE_TOK LPAREN_TOK terms RPAREN_TOK { $$ = new CVC3::Expr(VC->listExpr(VC->idExpr("_GET_VALUE"), VC->listExpr(*$3))); delete $3; } | GET_MODEL_TOK { $$ = new CVC3::Expr(VC->listExpr(VC->idExpr("_COUNTERMODEL"))); } | EXIT_TOK { TMP->done = true; $$ = new CVC3::Expr(); } ; sexprs: sexpr { $$ = new std::vector; $$->push_back(*$1); delete $1; } | sexprs sexpr { $1->push_back(*$2); $$ = $1; delete $2; } ; /* An S-expression that is not a keyword (NOTE: it may contain keywords in sub-expressions; it's just not *only* a keyword). */ non_keyword_sexpr: INTEGER_TOK { $$ = new CVC3::Expr(VC->ratExpr(*$1)); delete $1; } | DECIMAL_TOK { $$ = new CVC3::Expr(VC->ratExpr(*$1)); if(VC->getFlags()["translate"].getBool() && $1->find('.') != std::string::npos) { CVC3::Expr* e = $$; $$ = new CVC3::Expr(CVC3::REAL_CONST, *e); delete e; } delete $1; } | STRING_TOK { $$ = new CVC3::Expr(VC->stringExpr(*$1)); delete $1;} | SYM_TOK { $$ = new CVC3::Expr(VC->idExpr(*$1)); delete $1;} | LPAREN_TOK sexprs RPAREN_TOK { $$ = new CVC3::Expr(VC->listExpr(*$2)); delete $2; } ; sexpr: non_keyword_sexpr { $$ = $1; } | KEYWORD_TOK { $$ = new CVC3::Expr(VC->idExpr(*$1)); delete $1;} /* Possibly empty list of sort symbols */ sort_symbols: /* empty */ { $$ = new std::vector; } | sort_symbols_nonempty { $$ = $1; } ; sort_symbols_nonempty: sort_symbol { $$ = new std::vector; $$->push_back(*$1); delete $1; } | sort_symbols sort_symbol { $1->push_back(*$2); $$ = $1; delete $2; } ; sort_symbol: identifier { CVC3::Expr id = *$1; if( BVENABLED && id.isRawList() && id[0].getKind() == CVC3::ID && id[0][0].getString() == "BitVec" && id.arity() == 2 && id[1].isRational() ) { $$ = new CVC3::Expr( VC->listExpr("_BITVECTOR", id[1]) ); delete $1; } else { $$ = $1; } } | LPAREN_TOK identifier sort_symbols_nonempty RPAREN_TOK { CVC3::Expr id = *$2; if (ARRAYSENABLED && id.getKind() == CVC3::ID && id[0].getString() == "Array" && $3->size() == 2) { $$ = new CVC3::Expr( VC->listExpr("_ARRAY", *$3) ); } else { // FIXME: How to handle non-array parameterized types? $3->insert( $3->begin(), *$2 ); $$ = new CVC3::Expr( VC->listExpr(*$3) ); } delete $2; delete $3; } ; identifier: SYM_TOK { std::string id = *$1; /* If the id is a built-in operator, replace the text with the internal name. NOTE: the right way to do this would be would be with a hash_map or trie. */ if (id == "and") { id = "_AND"; } else if (id == "distinct") { id = "_DISTINCT"; } else if (id == "ite") { id = "_IF"; } else if (id == "/") { id = "_DIVIDE"; } else if (id == "=") { id = "_EQ"; } else if (id == ">") { id = "_GT"; } else if (id == ">=") { id = "_GE"; } else if (id == "=>") { id = "_IMPLIES"; } else if (id == "<") { id = "_LT"; } else if (id == "<=") { id = "_LE"; } else if (id == "-") { id = "_MINUS"; } else if (id == "not") { id = "_NOT"; } else if (id == "or") { id = "_OR"; } else if (id == "+") { id = "_PLUS"; } else if (id == "*") { id = "_MULT"; } else if (id == "is_int") { id = "_IS_INTEGER"; } else if (id == "xor") { id = "_XOR"; } else if (ARRAYSENABLED && id == "select") { id = "_READ"; } else if (ARRAYSENABLED && id == "store") { id = "_WRITE"; } else if (BVENABLED && id == "concat") { id = "_CONCAT"; } else if (BVENABLED && id == "bvadd") { id = "_BVPLUS"; } else if (BVENABLED && id == "bvand") { id = "_BVAND"; } else if (BVENABLED && id == "bvashr") { id = "_BVASHR"; } else if (BVENABLED && id == "bvcomp") { id = "_BVCOMP"; } else if (BVENABLED && id == "bvlshr") { id = "_BVLSHR"; } else if (BVENABLED && id == "bvmul") { id = "_BVMULT"; } else if (BVENABLED && id == "bvneg") { id = "_BVUMINUS"; } else if (BVENABLED && id == "bvnand") { id = "_BVNAND"; } else if (BVENABLED && id == "bvnot") { id = "_BVNEG"; } else if (BVENABLED && id == "bvnor") { id = "_BVNOR"; } else if (BVENABLED && id == "bvor") { id = "_BVOR"; } else if (BVENABLED && id == "bvshl") { id = "_BVSHL"; } else if (BVENABLED && id == "bvsdiv") { id = "_BVSDIV"; } else if (BVENABLED && id == "bvsge") { id = "_BVSGE"; } else if (BVENABLED && id == "bvsgt") { id = "_BVSGT"; } else if (BVENABLED && id == "bvsle") { id = "_BVSLE"; } else if (BVENABLED && id == "bvslt") { id = "_BVSLT"; } else if (BVENABLED && id == "bvsmod") { id = "_BVSMOD"; } else if (BVENABLED && id == "bvsrem") { id = "_BVSREM"; } else if (BVENABLED && id == "bvsub") { id = "_BVSUB"; } else if (BVENABLED && id == "bvudiv") { id = "_BVUDIV"; } else if (BVENABLED && id == "bvuge") { id = "_BVGE"; } else if (BVENABLED && id == "bvugt") { id = "_BVGT"; } else if (BVENABLED && id == "bvule") { id = "_BVLE"; } else if (BVENABLED && id == "bvult") { id = "_BVLT"; } else if (BVENABLED && id == "bvurem") { id = "_BVUREM"; } else if (BVENABLED && id == "bvxnor") { id = "_BVXNOR"; } else if (BVENABLED && id == "bvxor") { id = "_BVXOR"; } $$ = new CVC3::Expr( VC->idExpr( id ) ); delete $1; } | LPAREN_TOK UNDERSCORE_TOK SYM_TOK numerals RPAREN_TOK { std::string id = *$3; std::vector numerals = *$4; if (BVENABLED && id.size() > 2 && id[0] == 'b' && id[1] == 'v' && numerals.size() == 1) { DebugAssert( numerals[0].isRational() && numerals[0].getRational().isInteger(), "Illegal size argument to bit-vector constant." ); $$ = new CVC3::Expr( VC->listExpr("_BVCONST", VC->ratExpr(id.substr(2), 10), (*$4)[0]) ); } else { if (BVENABLED && id == "extract") { id = "_EXTRACT"; } else if (BVENABLED && id == "repeat") { id = "_BVREPEAT"; } else if (BVENABLED && id == "zero_extend") { id = "_BVZEROEXTEND"; } else if (BVENABLED && id == "sign_extend") { id = "_SX"; } else if (BVENABLED && id == "rotate_left") { id = "_BVROTL"; } else if (BVENABLED && id == "rotate_right") { id = "_BVROTR"; } $$ = new CVC3::Expr( VC->listExpr( id, *$4 ) ); } delete $3; delete $4; } ; /* a non-empty sequence of integers */ numerals: INTEGER_TOK { $$ = new std::vector; $$->push_back( VC->ratExpr(*$1) ); delete $1; } | numerals INTEGER_TOK { $1->push_back( VC->ratExpr(*$2) ); $$ = $1; delete $2; } ; /* A non-empty sequence of terms. */ terms: term { $$ = new std::vector; $$->push_back(*$1); delete $1; } | terms term { $1->push_back(*$2); $$ = $1; delete $2; } ; term: LPAREN_TOK identifier terms RPAREN_TOK { CVC3::Expr op = *$2; std::vector args = *$3; std::vector resultList; bool isId = op.getKind() == CVC3::ID; std::string opStr; if( isId ) { opStr = op[0].getString(); } if( isId && opStr == "_MINUS" && args.size() == 1 ) { resultList.push_back( VC->idExpr("_UMINUS") ); resultList.push_back( args[0] ); } else if( isId && ( opStr == "_AND" || opStr == "_OR" || opStr == "_XOR" || opStr == "_PLUS" || opStr == "_MULT" ) && args.size() == 1 ) { smtlib2error("[bin,N]-ary operator used in unary context"); } else { const int arity = op.arity(); isId = arity > 0 && op[0].getKind() == CVC3::ID; if( isId ) { opStr = op[0][0].getString(); } if( BVENABLED && arity == 3 && isId && opStr == "_EXTRACT" && op[1].isRational() && op[1].getRational().isInteger() && op[2].isRational() && op[2].getRational().isInteger() ) { resultList.push_back( op[0] ); resultList.push_back(op[1]); resultList.push_back(op[2]); } else if( BVENABLED && arity == 2 && isId && ( opStr == "_BVREPEAT" || opStr == "_BVZEROEXTEND" || opStr == "_BVROTL" || opStr == "_BVROTR" || opStr == "_SX" ) && op[1].isRational() && op[1].getRational().isInteger() ) { resultList.push_back( op[0] ); if( opStr == "_SX" ) { resultList.push_back(VC->idExpr("_smtlib")); } resultList.push_back(op[1]); } else { resultList.push_back(op); } resultList.insert( resultList.end(), args.begin(), args.end() ); } $$ = new CVC3::Expr(VC->listExpr(resultList)); delete $2; delete $3; } | LPAREN_TOK LET_TOK LPAREN_TOK bindings RPAREN_TOK term RPAREN_TOK { CVC3::Expr e(VC->listExpr(*$4)); $$ = new CVC3::Expr(VC->listExpr("_LET", e, *$6)); delete $4; delete $6; } | LPAREN_TOK quantifier LPAREN_TOK sorted_vars RPAREN_TOK term RPAREN_TOK { CVC3::Expr e(VC->listExpr(*$4)); CVC3::Expr body(*$6); DebugAssert( body.arity() > 0, "Empty quantifier body." ); if( body[0].isString() && body[0].getString() == "_ANNOTATION" ) { CVC3::Expr annots = body[2]; body = body[1]; // real body, stripping annot wrapper std::vector patterns; for( int i = 0; i < annots.arity(); ++i ) { DebugAssert( annots[i].arity() == 2 && annots[i][0].getKind() == CVC3::ID, "Illegal annotation." ); if( annots[i][0][0].getString() == ":pattern" ) { patterns.push_back( annots[i][1] ); } } $$ = new CVC3::Expr(VC->listExpr(*$2, e, body, VC->listExpr(patterns))); } else { $$ = new CVC3::Expr(VC->listExpr(*$2, e, body)); } delete $2; delete $4; delete $6; } | LPAREN_TOK EXCLAMATION_TOK term attributes RPAREN_TOK { $$ = new CVC3::Expr(VC->listExpr(VC->stringExpr("_ANNOTATION"), *$3, VC->listExpr(*$4))); delete $3; delete $4; } | identifier { $$ = $1; } | DECIMAL_TOK { $$ = new CVC3::Expr(VC->ratExpr(*$1)); if(VC->getFlags()["translate"].getBool() && $1->find('.') != std::string::npos) { CVC3::Expr* e = $$; $$ = new CVC3::Expr(CVC3::REAL_CONST, *e); delete e; } delete $1; } | INTEGER_TOK { $$ = new CVC3::Expr(VC->ratExpr(*$1)); delete $1; } | HEX_TOK { std::vector args; args.push_back(VC->idExpr("_BVCONST")); args.push_back(VC->ratExpr(*$1, 16)); args.push_back(VC->ratExpr(4 * $1->length())); $$ = new CVC3::Expr(VC->listExpr(args)); delete $1; } | BINARY_TOK { std::vector args; args.push_back(VC->idExpr("_BVCONST")); args.push_back(VC->ratExpr(*$1, 2)); args.push_back(VC->ratExpr($1->length())); $$ = new CVC3::Expr(VC->listExpr(args)); delete $1; } ; /* builtin: */ /* AND_TOK { $$ = new std::string("_AND"); } */ /* | DIV_TOK { $$ = new std::string("_DIVIDE"); } */ /* | DISTINCT_TOK { $$ = new std::string("_DISTINCT"); } */ /* | EQUAL_TOK { $$ = new std::string("_EQ"); } */ /* | GREATER_THAN_TOK { $$ = new std::string("_GT"); } */ /* | GREATER_THAN_EQ_TOK { $$ = new std::string("_GE"); } */ /* | IFF_TOK { $$ = new std::string("_IFF"); } */ /* | IMPLIES_TOK { $$ = new std::string("_IMPLIES"); } */ /* | ITE_TOK { $$ = new std::string("_IF"); } */ /* | LESS_THAN_TOK { $$ = new std::string("_LT"); } */ /* | LESS_THAN_EQ_TOK { $$ = new std::string("_LE"); } */ /* | MINUS_TOK { $$ = new std::string("_MINUS"); } */ /* | NOT_TOK { $$ = new std::string("_NOT"); } */ /* | OR_TOK { $$ = new std::string("_OR"); } */ /* | PLUS_TOK { $$ = new std::string("_PLUS"); } */ /* | STAR_TOK { $$ = new std::string("_MULT"); } */ /* | XOR_TOK { $$ = new std::string("_XOR"); } */ /* ; */ /* Returns a vector containing the operator and its arguments. This is necessary because of the behavior of certain parameterized operators (e.g., extract). */ /* op: */ /* builtin */ /* { */ /* $$ = new std::vector; */ /* $$->push_back( VC->idExpr(*$1) ); */ /* delete $1; */ /* } */ /* | identifier */ /* { */ /* $$ = new std::vector; */ /* CVC3::Expr id = *$1; */ /* if( id.getKind() == CVC3::ID ) { */ /* std::string fname = id[0].getString(); */ /* if (ARRAYSENABLED && fname == "select") { */ /* $$->push_back( VC->idExpr("_READ") ); */ /* } else if (ARRAYSENABLED && fname == "store") { */ /* $$->push_back( VC->idExpr("_WRITE") ); */ /* } else if (BVENABLED && fname == "concat") { */ /* $$->push_back( VC->idExpr("_CONCAT") ); */ /* } else if (BVENABLED && fname == "bvadd") { */ /* $$->push_back( VC->idExpr("_BVPLUS") ); */ /* } else if (BVENABLED && fname == "bvand") { */ /* $$->push_back( VC->idExpr("_BVAND") ); */ /* } else if (BVENABLED && fname == "bvashr") { */ /* $$->push_back( VC->idExpr("_BVASHR") ); */ /* } else if (BVENABLED && fname == "bvcomp") { */ /* $$->push_back( VC->idExpr("_BVCOMP") ); */ /* } else if (BVENABLED && fname == "bvlshr") { */ /* $$->push_back( VC->idExpr("_BVLSHR") ); */ /* } else if (BVENABLED && fname == "bvmul") { */ /* $$->push_back( VC->idExpr("_BVMULT") ); */ /* } else if (BVENABLED && fname == "bvneg") { */ /* $$->push_back( VC->idExpr("_BVUMINUS") ); */ /* } else if (BVENABLED && fname == "bvnand") { */ /* $$->push_back( VC->idExpr("_BVNAND") ); */ /* } else if (BVENABLED && fname == "bvnot") { */ /* $$->push_back( VC->idExpr("_BVNEG") ); */ /* } else if (BVENABLED && fname == "bvnor") { */ /* $$->push_back( VC->idExpr("_BVNOR") ); */ /* } else if (BVENABLED && fname == "bvor") { */ /* $$->push_back( VC->idExpr("_BVOR") ); */ /* } else if (BVENABLED && fname == "bvshl") { */ /* $$->push_back( VC->idExpr("_BVSHL") ); */ /* } else if (BVENABLED && fname == "bvsdiv") { */ /* $$->push_back( VC->idExpr("_BVSDIV") ); */ /* } else if (BVENABLED && fname == "bvsge") { */ /* $$->push_back( VC->idExpr("_BVSGE") ); */ /* } else if (BVENABLED && fname == "bvsgt") { */ /* $$->push_back( VC->idExpr("_BVSGT") ); */ /* } else if (BVENABLED && fname == "bvsle") { */ /* $$->push_back( VC->idExpr("_BVSLE") ); */ /* } else if (BVENABLED && fname == "bvslt") { */ /* $$->push_back( VC->idExpr("_BVSLT") ); */ /* } else if (BVENABLED && fname == "bvsrem") { */ /* $$->push_back( VC->idExpr("_BVSREM") ); */ /* } else if (BVENABLED && fname == "bvsub") { */ /* $$->push_back( VC->idExpr("_BVSUB") ); */ /* } else if (BVENABLED && fname == "bvudiv") { */ /* $$->push_back( VC->idExpr("_BVUDIV") ); */ /* } else if (BVENABLED && fname == "bvuge") { */ /* $$->push_back( VC->idExpr("_BVUGE") ); */ /* } else if (BVENABLED && fname == "bvugt") { */ /* $$->push_back( VC->idExpr("_BVUGT") ); */ /* } else if (BVENABLED && fname == "bvule") { */ /* $$->push_back( VC->idExpr("_BVULE") ); */ /* } else if (BVENABLED && fname == "bvult") { */ /* $$->push_back( VC->idExpr("_BVLT") ); */ /* } else if (BVENABLED && fname == "bvurem") { */ /* $$->push_back( VC->idExpr("_BVUREM") ); */ /* } else if (BVENABLED && fname == "bvxnor") { */ /* $$->push_back( VC->idExpr("_BVXNOR") ); */ /* } else if (BVENABLED && fname == "bvxor") { */ /* $$->push_back( VC->idExpr("_BVXOR") ); */ /* } else { */ /* $$->push_back( id ); */ /* } */ /* } else if( BVENABLED && */ /* id.arity() > 0 && */ /* id[0].getKind() == CVC3::ID ) { */ /* if( id.arity() == 3 && */ /* id[0][0].getString() == "extract" && */ /* id[1].isRational() && */ /* id[1].getRational().isInteger() && */ /* id[2].isRational() && */ /* id[2].getRational().isInteger() ) { */ /* $$->push_back( VC->idExpr("_EXTRACT") ); */ /* $$->push_back(id[1]); */ /* $$->push_back(id[2]); */ /* } else if( id.arity() == 2 && */ /* id[0][0].getString() == "repeat" && */ /* id[1].isRational() && */ /* id[1].getRational().isInteger() ) { */ /* $$->push_back( VC->idExpr("_BVREPEAT") ); */ /* $$->push_back(id[1]); */ /* } else if( id.arity() == 2 && */ /* id[0][0].getString() == "zero_extend" && */ /* id[1].isRational() && */ /* id[1].getRational().isInteger() ) { */ /* $$->push_back( VC->idExpr("_BVZEROEXTEND") ); */ /* $$->push_back(id[1]); */ /* } else if( id.arity() == 2 && */ /* id[0][0].getString() == "sign_extend" && */ /* id[1].isRational() && */ /* id[1].getRational().isInteger() ) { */ /* $$->push_back( VC->idExpr("_SX") ); */ /* $$->push_back(VC->idExpr("_smtlib")); */ /* $$->push_back(id[1]); */ /* } else if( id.arity() == 2 && */ /* id[0].getKind() == CVC3::ID && */ /* id[0][0].getString() == "rotate_left" && */ /* id[1].isRational() && */ /* id[1].getRational().isInteger() ) { */ /* $$->push_back( VC->idExpr("_BVROTL") ); */ /* $$->push_back(id[1]); */ /* } else if( id.arity() == 2 && */ /* id[0].getKind() == CVC3::ID && */ /* id[0][0].getString() == "rotate_right" && */ /* id[1].isRational() && */ /* id[1].getRational().isInteger() ) { */ /* $$->push_back( VC->idExpr("_BVROTR") ); */ /* $$->push_back(id[1]); */ /* } else { */ /* $$->push_back(id); */ /* } */ /* } else { */ /* $$->push_back(id); */ /* } */ /* delete $1; */ /* } */ /* ; */ quantifier: EXISTS_TOK { $$ = new std::string("_EXISTS"); } | FORALL_TOK { $$ = new std::string("_FORALL"); } ; /* A non-empty sequence of (var term) bindings */ bindings: binding { $$ = new std::vector; $$->push_back(*$1); delete $1; } | bindings binding { $1->push_back(*$2); $$ = $1; delete $2; } ; binding: LPAREN_TOK SYM_TOK term RPAREN_TOK { $$ = new CVC3::Expr( VC->listExpr(*$2, *$3) ); delete $2; delete $3; } ; /* A non-empty sequence of (var sort) decls */ sorted_vars: sorted_var { $$ = new std::vector; $$->push_back(*$1); delete $1; } | sorted_vars sorted_var { $1->push_back(*$2); $$ = $1; delete $2; } ; sorted_var: LPAREN_TOK SYM_TOK sort_symbol RPAREN_TOK { $$ = new CVC3::Expr(VC->listExpr(*$2, *$3)); delete $2; delete $3; } ; /* A non-empty sequence of attributes */ attributes: attribute { $$ = new std::vector; $$->push_back( *$1 ); delete $1; } | attributes attribute { $1->push_back( *$2 ); $$ = $1; delete $2; } ; attribute: KEYWORD_TOK { $$ = new CVC3::Expr( VC->idExpr(*$1) ); delete $1; } | KEYWORD_TOK SYM_TOK { $$ = new CVC3::Expr( VC->listExpr( VC->idExpr(*$1), VC->idExpr(*$2) ) ); delete $1; delete $2; } | KEYWORD_TOK INTEGER_TOK { $$ = new CVC3::Expr( VC->listExpr( VC->idExpr(*$1), VC->ratExpr(*$2) ) ); delete $1; delete $2; } | KEYWORD_TOK DECIMAL_TOK { $$ = new CVC3::Expr( VC->listExpr( VC->idExpr(*$1), VC->ratExpr(*$2) ) ); delete $1; delete $2; } | KEYWORD_TOK HEX_TOK { $$ = new CVC3::Expr( VC->listExpr( VC->idExpr(*$1), VC->ratExpr(*$2, 16) ) ); delete $1; delete $2; } | KEYWORD_TOK BINARY_TOK { $$ = new CVC3::Expr( VC->listExpr( VC->idExpr(*$1), VC->ratExpr(*$2, 2) ) ); delete $1; delete $2; } | KEYWORD_TOK STRING_TOK { $$ = new CVC3::Expr( VC->listExpr( VC->idExpr(*$1), VC->stringExpr(*$2) ) ); delete $1; delete $2; } | KEYWORD_TOK LPAREN_TOK terms RPAREN_TOK { // was "non_keyword_sexpr" above instead of "(terms)", but that breaks :pattern $$ = new CVC3::Expr( VC->listExpr( VC->idExpr(*$1), VC->listExpr(*$3) ) ); delete $1; delete $3; } ; %% cvc3-2.4.1/src/parser/smtlib2.lex0000644000175400017540000001511611624746722016444 0ustar mdetersmdeters%{ /*****************************************************************************/ /*! * \file smtlib2.lex * * Author: Christopher Conway * * Created: 2010 * *
* * License to use, copy, modify, sell and/or distribute this software * and its documentation for any purpose is hereby granted without * royalty, subject to the terms and conditions defined in the \ref * LICENSE file provided with this distribution. * *
* */ /*****************************************************************************/ #include #include "parser_temp.h" #include "expr_manager.h" /* for the benefit of parsesmtlib_defs.h */ #include "parsesmtlib2_defs.h" #include "debug.h" namespace CVC3 { extern ParserTemp* parserTemp; } extern int smtlib2_inputLine; extern char *smtlib2text; extern int smtlib2error (const char *msg); static int smtlib2input(std::istream& is, char* buf, int size) { int res; if(is) { // If interactive, read line by line; otherwise read as much as we // can gobble if(CVC3::parserTemp->interactive) { // Print the current prompt std::cout << CVC3::parserTemp->getPrompt() << std::flush; // Set the prompt to "middle of the command" one CVC3::parserTemp->setPrompt2(); // Read the line is.getline(buf, size-1); } else // Set the terminator char to 0 is.getline(buf, size-1, 0); // If failbit is set, but eof is not, it means the line simply // didn't fit; so we clear the state and keep on reading. bool partialStr = is.fail() && !is.eof(); if(partialStr) is.clear(); for(res = 0; resis, buf, max_size); int smtlib2_bufSize() { return YY_BUF_SIZE; } YY_BUFFER_STATE smtlib2_buf_state() { return YY_CURRENT_BUFFER; } /* some wrappers for methods that need to refer to a struct. These are used by CVC3::Parser. */ void *smtlib2_createBuffer(int sz) { return (void *)smtlib2_create_buffer(NULL, sz); } void smtlib2_deleteBuffer(void *buf_state) { smtlib2_delete_buffer((struct yy_buffer_state *)buf_state); } void smtlib2_switchToBuffer(void *buf_state) { smtlib2_switch_to_buffer((struct yy_buffer_state *)buf_state); } void *smtlib2_bufState() { return (void *)smtlib2_buf_state(); } void smtlib2_setInteractive(bool is_interactive) { yy_set_interactive(is_interactive); } // File-static (local to this file) variables and functions static std::string _string_lit; static std::string _symbol_text; static char escapeChar(char c) { switch(c) { case 'n': return '\n'; case 't': return '\t'; default: return c; } } // for now, we don't have subranges. // // ".." { return DOTDOT_TOK; } /*OPCHAR (['!#?\_$&\|\\@])*/ %} %option noyywrap %option nounput %option noreject %option noyymore %option yylineno %x COMMENT %x STRING_LITERAL %x SYMBOL %x USER_VALUE %s PAT_MODE LETTER ([a-zA-Z]) DIGIT ([0-9]) HEX_DIGIT ({DIGIT}|[a-fA-F]) BIN_DIGIT ([01]) SYMBOL_CHAR ([+\-*/=%?!.$_~&^<>@]) SIMPLE_SYMBOL (({LETTER}|{SYMBOL_CHAR})({LETTER}|{DIGIT}|{SYMBOL_CHAR})*) %% [\n] { CVC3::parserTemp->lineNum++; } [ \t\r\f] { /* skip whitespace */ } {DIGIT}+"\."{DIGIT}+ { smtlib2lval.str = new std::string(smtlib2text); return DECIMAL_TOK; } {DIGIT}+ { smtlib2lval.str = new std::string(smtlib2text); return INTEGER_TOK; } "#x"{HEX_DIGIT}+ { /* skip prefix in string value */ smtlib2lval.str = new std::string(smtlib2text+2); return HEX_TOK; } "#b"{BIN_DIGIT}+ { /* skip prefix in string value */ smtlib2lval.str = new std::string(smtlib2text+2); return BINARY_TOK; } ";" { BEGIN COMMENT; } "\n" { BEGIN INITIAL; /* return to normal mode */ CVC3::parserTemp->lineNum++; } . { /* stay in comment mode */ } "\"" { BEGIN STRING_LITERAL; _string_lit.erase(_string_lit.begin(), _string_lit.end()); } "\\". { /* escape characters (like \n or \") */ _string_lit.insert(_string_lit.end(), escapeChar(smtlib2text[1])); } "\"" { BEGIN INITIAL; /* return to normal mode */ smtlib2lval.str = new std::string(_string_lit); return STRING_TOK; } "\n" { // Include the \n and increment the line number _string_lit.insert(_string_lit.end(),*smtlib2text); CVC3::parserTemp->lineNum++; } . { _string_lit.insert(_string_lit.end(),*smtlib2text); } "|" { BEGIN SYMBOL; _symbol_text.erase(_symbol_text.begin(), _symbol_text.end()); } "|" { BEGIN INITIAL; /* return to normal mode */ smtlib2lval.str = new std::string(_symbol_text); return SYM_TOK; } "\n" { // Include the \n and increment the line number _symbol_text.insert(_symbol_text.end(),*smtlib2text); CVC3::parserTemp->lineNum++; } . { _symbol_text.insert(_symbol_text.end(),*smtlib2text); } /* Base SMT-LIB tokens */ "assert" { return ASSERT_TOK; } "check-sat" { return CHECKSAT_TOK; } "push" { return PUSH_TOK; } "pop" { return POP_TOK; } "declare-fun" { return DECLARE_FUN_TOK; } "declare-sort" { return DECLARE_SORT_TOK; } "get-proof" { return GET_PROOF_TOK; } "get-assignment" { return GET_ASSIGNMENT_TOK; } "get-value" { return GET_VALUE_TOK; } "get-model" { return GET_MODEL_TOK; } "!" { return EXCLAMATION_TOK; } "exit" { return EXIT_TOK; } "let" { return LET_TOK; } "(" { return LPAREN_TOK; } ")" { return RPAREN_TOK; } "set-logic" { return SET_LOGIC_TOK; } "set-info" { return SET_INFO_TOK; } "_" { return UNDERSCORE_TOK; } /* Logic symbols */ "exists" { return EXISTS_TOK; } "forall" { return FORALL_TOK; } {SIMPLE_SYMBOL} { smtlib2lval.str = new std::string(smtlib2text); return SYM_TOK; } ":"{SIMPLE_SYMBOL} { smtlib2lval.str = new std::string(smtlib2text); return KEYWORD_TOK; } <> { return EOF_TOK; } . { smtlib2error("Illegal input character."); } %% cvc3-2.4.1/src/cvc3.pc.in0000664000175400017540000000044711327624066014650 0ustar mdetersmdetersprefix=@prefix@ exec_prefix=@exec_prefix@ libdir=@libdir@ includedir=@includedir@ datarootdir=@prefix@/share datadir=@datadir@ Name: CVC3 Description: Automatic theorem prover for Satisfiability Modulo Theories (SMT) problems Version: @VERSION@ Libs: -L${libdir} -lcvc3 Cflags: -I${includedir} cvc3-2.4.1/src/search/0000775000175400017540000000000011630011320014275 5ustar mdetersmdeterscvc3-2.4.1/src/search/Util.cpp0000664000175400017540000001056711360753331015746 0ustar mdetersmdeters#include "Util.h" bool Obj::errsInit = false; ofstream Obj::errs; bool Obj::indentFlag = false; // helper utility functions void ajr_debug_print( const Expr& pf ) { for( int a=0; a=10 ) return false; else if( !isFlat( e[a] ) ) return false; } } return true; } void make_flatten_expr_h( const Expr& e, Expr& pe, const Expr& pec, bool pecDef, int knd ){ //cout << "Trav " << e << std::endl; if( e.getKind()==knd ){ make_flatten_expr_h( e[1], pe, pec, pecDef, knd ); if( e[0].getKind()==knd ){ make_flatten_expr_h( e[0], pe, pe, true, knd ); }else{ pe = Expr( knd, e[0], pe ); } }else{ if( pecDef ){ pe = Expr( knd, e, pec ); }else{ pe = e; } } } void make_flatten_expr( const Expr& e, Expr& pe, int knd ){ Expr pec; make_flatten_expr_h( e, pe, pec, false, knd ); } cvc3-2.4.1/src/search/decision_engine_caching.h0000664000175400017540000000235010466450543021270 0ustar mdetersmdeters/*****************************************************************************/ /*! * \file decision_engine_caching.h * *
* * License to use, copy, modify, sell and/or distribute this software * and its documentation for any purpose is hereby granted without * royalty, subject to the terms and conditions defined in the \ref * LICENSE file provided with this distribution. * *
* */ /*****************************************************************************/ #ifndef _cvc3__search__decision_engine_caching_h_ #define _cvc3__search__decision_engine_caching_h_ #include "decision_engine.h" namespace CVC3 { class DecisionEngineCaching : public DecisionEngine { class CacheEntry { public: Expr d_expr; int d_rank; int d_trust; CacheEntry() : d_rank(0), d_trust(0) {} }; int d_startLevel; int d_bottomLevel; int d_topLevel; bool d_topLevelLock; int d_height; std::vector d_cache; ExprMap d_index; protected: virtual bool isBetter(const Expr& e1, const Expr& e2); public: DecisionEngineCaching(TheoryCore* core, SearchImplBase* se); virtual ~DecisionEngineCaching() { } virtual Expr findSplitter(const Expr& e); virtual void goalSatisfied(); }; } #endif cvc3-2.4.1/src/search/Makefile0000664000175400017540000000172211360716164015761 0ustar mdetersmdeters################################################## # About this Makefile # # This Makefile depends on Makefile.opts ################################################## MODULE = search SRC = \ clause.cpp \ search_impl_base.cpp \ search.cpp \ search_fast.cpp \ search_theorem_producer.cpp \ search_sat.cpp \ search_simple.cpp \ variable.cpp \ circuit.cpp \ decision_engine.cpp \ decision_engine_dfs.cpp \ LFSCObject.cpp \ LFSCUtilProof.cpp \ LFSCBoolProof.cpp \ LFSCConvert.cpp \ LFSCLraProof.cpp \ LFSCPrinter.cpp \ LFSCProof.cpp \ TReturn.cpp \ Util.cpp # decision_engine_caching.cpp \ # decision_engine_mbtf.cpp HEADERS = search_rules.h search_theorem_producer.h decision_engine.h decision_engine_dfs.h decision_engine_caching.h decision_engine_mbtf.h Util.h TReturn.h Object.h LFSCUtilProof.h LFSCProof.h LFSCPrinter.h LFSCObject.h LFSCLraProof.h LFSCConvert.h LFSCBoolProof.h LIBRARY=libsearch.a EXTRAFLAGS=$(DPLL_BASIC) include ../../Makefile.local cvc3-2.4.1/src/search/LFSCConvert.cpp0000664000175400017540000022056211363745666017136 0ustar mdetersmdeters#include "LFSCConvert.h" #include "LFSCUtilProof.h" #include "LFSCBoolProof.h" #include "LFSCLraProof.h" std::map< Expr, int > vMap; LFSCConvert::LFSCConvert( int lfscm ) { nodeCount = 0; nodeCountTh = 0; unodeCount = 0; unodeCountTh = 0; ignore_theory_lemmas = lfsc_mode==22; } void LFSCConvert::convert( const Expr& pf ) { TReturn* tfinal = cvc3_to_lfsc( pf, false, false ); pfinal = tfinal->getLFSCProof(); //print out sat_lem if we are in clausal form if( tfinal->getProvesY()==3 ){ ostringstream os1, os2; os1 << "(satlem _ _ _ "; os2 << "(\\ @done @done))" << endl; pfinal = LFSCProofGeneric::Make( os1.str(), pfinal.get(), os2.str() ); } //print out all necessary proof let's pfinal = make_let_proof( pfinal.get() ); //double ratio = (double)( nodeCountTh )/double( nodeCount + nodeCountTh ); //cout << "Theory Node ratio : " << ratio << endl; //cout << "Node Count : " << nodeCount << endl; //cout << "Th Node Count : " << nodeCountTh << endl; //cout << "Total Count : " << ( nodeCount + nodeCountTh ) << endl; //cout << (double)( nodeCountTh )/double( nodeCount + nodeCountTh ) << endl; //cout << "uNode Count : " << unodeCount << endl; //cout << "Th uNode Count : " << unodeCountTh << endl; //cout << "LFSC proof count: " << LFSCProof::get_proof_counter() << endl; //cout << "getNumNodes : " << getNumNodes( pf, false ) << endl; //nnode_map.clear(); //cout << "getNumNodes(rc) : " << getNumNodes( pf, true ) << endl; //cout << "map size 1 : " << (int)d_th_trans_map[1].size() << endl; //cout << "map size 2 : " << (int)d_th_trans_map[0].size() << endl; //std::map< Expr, int >::iterator vmIt = vMap.begin(); //while( vmIt != vMap.end() ){ // cout << (*vmIt).first << ": " << (*vmIt).second << endl; // ++vmIt; //} //exit( 0 ); } // helper method to identify axioms of the form |- 0 = 0 bool LFSCConvert::isTrivialTheoryAxiom(const Expr& expr, bool checkBody){ if( expr[0]==d_plus_predicate_str || expr[0]==d_right_minus_left_str || expr[0]==d_minus_to_plus_str || expr[0]==d_mult_ineqn_str || expr[0]==d_canon_mult_str || expr[0]==d_canon_plus_str || expr[0]==d_flip_inequality_str || expr[0]==d_negated_inequality_str || expr[0]==d_rewrite_eq_symm_str || expr[0]==d_refl_str || expr[0]==d_mult_eqn_str || expr[0]==d_canon_invert_divide_str || expr[0]==d_rewrite_eq_refl_str || expr[0]==d_uminus_to_mult_str || expr[0]==d_rewrite_not_true_str || expr[0]==d_rewrite_not_false_str || expr[0]==d_int_const_eq_str ){ Expr pe; Expr yexpr; if( !checkBody || ( what_is_proven( expr, pe ) && getY( pe, yexpr ) ) ){ return true; }else{ //cout << "Trivial theory axiom with bad arguments : " << expr[0] << std::endl; } } return false; //FIXME: should rewrite_not_true be used in theory lemma? expr==d_rewrite_not_true_str } bool LFSCConvert::isTrivialBooleanAxiom(const Expr& expr) { return ( expr==d_rewrite_not_not_str ); } // *****NOTE that these rules must have a subproof expr[2] bool LFSCConvert::isIgnoredRule(const Expr& expr) { return ( expr==d_iff_not_false_str || expr==d_iff_true_str || expr==d_iff_false_elim_str || expr==d_iff_true_elim_str || expr==d_not_not_elim_str || expr==d_not_to_iff_str ); } TReturn* LFSCConvert::cvc3_to_lfsc(const Expr& pf, bool beneath_lc, bool rev_pol){ if( beneath_lc ) nodeCountTh++; else nodeCount++; if( lfsc_mode==5){ cvc3_mimic = cvc3_mimic_input || !beneath_lc; } int cvcm = cvc3_mimic ? 1 : 0; TReturn* tRetVal = NULL; //if( !tRetVal && cvcm==0 ){ // tRetVal = d_th_trans_map[1][pf]; //} if( d_th_trans_map[cvcm].find( pf )!=d_th_trans_map[cvcm].end() ){ tRetVal = d_th_trans_map[cvcm][pf]; if( d_th_trans_lam[cvcm].find( tRetVal )==d_th_trans_lam[cvcm].end() ){ if( debug_conv ) cout << "set th_trans" << std::endl; //set this TReturn to be lambda'ed into a let proof d_th_trans_lam[cvcm][tRetVal] = true; } return tRetVal; } if( beneath_lc ) unodeCountTh++; else unodeCount++; //if( (unodeCountTh + unodeCount)%10000==0 ) // cout << unodeCount << " " << unodeCountTh << endl; //if( pf.isSelected() ) // std::cout << "already did this one?" << std::endl; if( vMap.find( pf[0] )==vMap.end() ){ vMap[ pf[0] ] = 0; } vMap[ pf[0] ]++; std::vector< int > emptyL; std::vector< int > emptyLUsed; int yMode = -2; ostringstream ose; if( debug_conv ){ cout << "handle "; pf[0].print(); } Expr pfMod; int pfPat = get_proof_pattern( pf, pfMod ); if( pfPat==0 ) { if (pf[0] == d_CNF_str ){ RefPtr< LFSCProof > p = LFSCProof::Make_CNF( pf[2], pf[1], pf[4].getRational().getNumerator().getInt() ); if( p.get() ) { tRetVal = new TReturn( p.get(), emptyL, emptyLUsed, nullRat, false, 3 ); } } else if( pf[0] == d_CNFITE_str ){ if( pf[5].isRational() ){ RefPtr< LFSCProof > p = LFSCProof::Make_CNF( pf[1], d_ite_s, pf[5].getRational().getNumerator().getInt() ); if( p.get() ){ tRetVal = new TReturn( p.get(), emptyL, emptyLUsed, nullRat, false, 3 ); } } }else if( pf[0] == d_cnf_add_unit_str ){ TReturn* t = cvc3_to_lfsc( pf[2] ); yMode = TReturn::normalize_tr( pf[2], t, 3 ); if( yMode==3 ){ tRetVal = t; } } else if( pf[0] == d_cnf_convert_str ){ if( pf.arity()>3 ){ if( ignore_theory_lemmas && pf[3][0]==d_learned_clause_str ){ TReturn* t = make_trusted( pf ); tRetVal = new TReturn( LFSCClausify::Make( pf[1], t->getLFSCProof(), true ), emptyL, emptyLUsed, nullRat, false, 3 ); }else{ TReturn* t = cvc3_to_lfsc( pf[3],beneath_lc, rev_pol); if( TReturn::normalize_tr( pf[3], t, 3, rev_pol )==3 ){ RefPtr< LFSCProof > p = t->getLFSCProof(); tRetVal = new TReturn( p.get(), emptyL, emptyLUsed, nullRat, false, 3 ); } } } } else if( pf[0] == d_bool_res_str ){ //ajr_debug_print( pf ); TReturn* t1 = cvc3_to_lfsc( pf[2],beneath_lc, rev_pol); TReturn* t2 = cvc3_to_lfsc( pf[3],beneath_lc, rev_pol); //t1->getL( emptyL, emptyLUsed ); //t2->getL( emptyL, emptyLUsed ); TReturn::normalize_tr( pf[2], t1, 3, rev_pol ); TReturn::normalize_tr( pf[3], t2, 3, rev_pol ); if( t1->getProvesY()==3 && t2->getProvesY()==3 ){ tRetVal = new TReturn( LFSCBoolRes::Make( t1->getLFSCProof(), t2->getLFSCProof(), pf[1], pf ), emptyL, emptyLUsed, nullRat, false, 3 ); } } else if( pf[0] == d_minisat_proof_str ){ tRetVal = cvc3_to_lfsc( pf[2] ); } else if(pf[0]==d_assump_str){ //assumptions rule Expr ce = cascade_expr( pf[1] ); int val = queryM( ce ); RefPtr< LFSCProof > p; yMode = 0; if( d_assump_map.find( ce ) != d_assump_map.end() ){ //cout << "This is an assumption: " << pf[1] << std::endl; p = LFSCPfVar::Make( "@F", abs( val ) ); if( !cvc3_mimic ){ #ifndef LRA2_PRIME p = LFSCProof::Make_not_not_elim( pf[1], p.get() ); #endif } }else if( beneath_lc ){ p = LFSCPfVar::MakeV( abs( val ) ); if( cvc3_mimic ){ //ostringstream os1, os2; //os1 << "(spec "; //RefPtr< LFSCProof > ps = LFSCProofExpr::Make( pf[1] ); //os2 << ")"; //p = LFSCProofGeneric::Make( os1.str(), p.get(), ps.get(), os2.str() ); d_formulas_printed[queryAtomic( ce, true )] = true; } #ifdef OPTIMIZE p->assumeVarUsed = val; #else emptyLUsed.push_back( val ); #endif }else{ ostringstream os; os << "WARNING: Assuming a trusted formula: " << ce << std::endl; print_error( os.str().c_str(), cout ); int valT = queryM( ce, true, true ); p = LFSCPfVar::Make( "@T", abs( valT ) ); } if( beneath_lc ){ #ifdef OPTIMIZE p->assumeVar = val; #else emptyL.push_back( val ); #endif if( !cvc3_mimic ){ Expr ey; if( getY( ce, ey ) ){ p = LFSCLraPoly::Make( ce, p.get() ); yMode = 1; }else{ ostringstream os; os << "WARNING: Beneath a learned clause and Y is not defined for assumption " << pf[1] << std::endl; print_error( os.str().c_str(), cout ); } } } tRetVal = new TReturn( p.get(), emptyL, emptyLUsed, nullRat, false, yMode ); } else if( pf[0] == d_iff_trans_str ){ TReturn* t1 = cvc3_to_lfsc(pf[4],beneath_lc, rev_pol); #ifdef LRA2_PRIME if( ( isTrivialBooleanAxiom( pf[5][0] ) || pf[5][0]==d_rewrite_not_true_str ) && !cvc3_mimic && t1->getProvesY()==1 ){ #else if( ( isTrivialBooleanAxiom( pf[5][0] ) || pf[5][0]==d_rewrite_not_true_str ) && !cvc3_mimic ){ #endif tRetVal = t1; }else{ TReturn* t2 = cvc3_to_lfsc(pf[5],beneath_lc, rev_pol); t1->getL( emptyL, emptyLUsed ); t2->getL( emptyL, emptyLUsed ); yMode = TReturn::normalize_tret( pf[4], t1, pf[5], t2, rev_pol ); //case for arithmetic simplification if( yMode==1 ) { int knd2 = queryAtomic( pf[2] ).getKind(); int knd3 = queryAtomic( pf[3] ).getKind(); //if we have an equation on the RHS if( is_eq_kind( knd3 ) ) { RefPtr< LFSCProof > lfsc_pf = t1->getLFSCProof(); if( t2->hasRational() ) lfsc_pf = LFSCLraMulC::Make(t1->getLFSCProof(), t2->getRational(), EQ); LFSCLraAdd::Make( lfsc_pf.get(), t2->getLFSCProof(), EQ, EQ); Rational newR = t1->mult_rational( t2 ); tRetVal = new TReturn(lfsc_pf.get(), emptyL, emptyLUsed, t1->mult_rational( t2 ), t1->hasRational() || t2->hasRational(),1); } else if( knd3==FALSE_EXPR || knd3==TRUE_EXPR ) { #ifdef PRINT_MAJOR_METHODS cout << ";[M]: iff_trans, logical " << (knd3==TRUE_EXPR) << std::endl; #endif RefPtr< LFSCProof > p; if ( knd3==TRUE_EXPR ){ p = LFSCLraAdd::Make( t1->getLFSCProof(), t2->getLFSCProof(), EQ, is_eq_kind( knd2 ) ? get_normalized( knd2, true ) : EQ ); }else{ p = LFSCLraSub::Make( t2->getLFSCProof(), t1->getLFSCProof(), is_eq_kind( knd2 ) ? get_normalized( knd2, true ) : EQ, EQ ); } if( t1->hasRational() ){ Rational r = 1/t1->getRational(); p = LFSCLraMulC::Make( p.get(), r, is_eq_kind( knd2 ) ? get_normalized( knd2, true ) : EQ ); } tRetVal = new TReturn( p.get(), emptyL, emptyLUsed, nullRat, false, 1 ); } }else if( yMode == 3 ){ //#ifdef PRINT_MAJOR_METHODS // cout << ";[M]: iff_trans, boolean " << std::endl; //#endif // //resolving on the middle formula // RefPtr< LFSCProof > p; // if( rev_pol ){ // p = LFSCBoolRes::Make( t2->getLFSCProof(), t1->getLFSCProof(), pf[2], pf ); // }else{ // p = LFSCBoolRes::Make( t1->getLFSCProof(), t2->getLFSCProof(), pf[2], pf ); // } //tRetVal = new TReturn( p.get(), emptyL, emptyLUsed, 1, 1, 3 ); }else if( yMode == 0 || yMode==2 ){ ostringstream os1; os1 << "(" << (yMode==0 ? "iff" : "impl" ) << "_trans _ _ _ "; //if( yMode==2 && t1->getLFSCProof()->get_string_length()<100 ){ // os1 << "["; // t1->getLFSCProof()->print( os1, 0 ); // os1 << "]"; //} ostringstream os2; os2 << ")"; tRetVal = new TReturn( LFSCProofGeneric::Make( os1.str(), t1->getLFSCProof(), t2->getLFSCProof(), os2.str() ), emptyL, emptyLUsed, nullRat, false, yMode ); } } } else if (pf[0] == d_iff_mp_str ){ //iff_mp rule TReturn* t1 = cvc3_to_lfsc(pf[3],beneath_lc); #ifdef LRA2_PRIME if( isTrivialBooleanAxiom( pf[4][0] ) && !cvc3_mimic && t1->getProvesY()==1 ){ #else if( isTrivialBooleanAxiom( pf[4][0] ) && !cvc3_mimic ){ #endif tRetVal = t1; }else{ TReturn* t2 = cvc3_to_lfsc(pf[4],beneath_lc); t1->getL( emptyL, emptyLUsed ); t2->getL( emptyL, emptyLUsed ); if( t1->getProvesY()==1 && t2->getProvesY()==1 ) { yMode = 1; int knd = queryAtomic( pf[1] ).getKind(); int knd2 = queryAtomic( pf[2] ).getKind(); if( is_eq_kind( knd2 ) ) { RefPtr< LFSCProof > p = t1->getLFSCProof(); if( t2->hasRational() ) p = LFSCLraMulC::Make(p.get(), t2->getRational(), get_normalized( knd )); p = LFSCLraSub::Make( p.get(), t2->getLFSCProof(), get_normalized( knd ), EQ); tRetVal = new TReturn(p.get(), emptyL, emptyLUsed, t2->getRational(), t2->hasRational() , 1); }else if( knd2==FALSE_EXPR ){ //false case #ifdef PRINT_MAJOR_METHODS //cout << ";[M]: iff_mp, false" << std::endl; #endif //becomes a contradiction RefPtr< LFSCProof > p = t1->getLFSCProof(); p = LFSCLraAdd::Make( p.get(), t2->getLFSCProof(), get_normalized( knd ), get_normalized( knd, true ) ); p = LFSCLraContra::Make( p.get(), is_comparison( knd ) ? (int)GT : (int)DISTINCT ); tRetVal = new TReturn( p.get(), emptyL, emptyLUsed, nullRat, false, 1 ); } }else if( t2->getProvesY()==3 || t1->getProvesY()==3 ){ // yMode = TReturn::normalize_tret( pf[3], t1, pf[4], t2, rev_pol ); // if( yMode==3 ){ //#ifdef PRINT_MAJOR_METHODS // cout << ";[M]: iff_mp, boolean" << std::endl; //#endif // //do boolean resolution // tRetVal = new TReturn( LFSCBoolRes::Make( t1->getLFSCProof(), t2->getLFSCProof(), pf[1], pf ), // emptyL, emptyLUsed, nullRat, false, 3 ); // } }else{ if( t2->getProvesY()!=1 || TReturn::normalize_tr( pf[4], t2, 2, rev_pol )!=-1 ){ if( t1->getProvesY()!=1 || TReturn::normalize_tr( pf[3], t1, 2, rev_pol )!=-1 ){ ostringstream os1; os1 << "(" << (t2->getProvesY()==0 ? "iff" : "impl" ) << "_mp _ _ "; ostringstream os2; os2 << ")"; tRetVal = new TReturn( LFSCProofGeneric::Make( os1.str(), t1->getLFSCProof(), t2->getLFSCProof(), os2.str() ), emptyL, emptyLUsed, nullRat, false, 0 ); } } } } } else if(pf[0]==d_iff_symm_str ) { TReturn* t = cvc3_to_lfsc( pf[3], beneath_lc, !rev_pol ); yMode = t->getProvesY(); t->getL( emptyL, emptyLUsed ); if( yMode==1 ) { #ifdef PRINT_MAJOR_METHODS cout << ";[M]: iff_symm" << std::endl; #endif if( t->hasRational() ){ Rational r = 1/t->getRational(); //adding this Rational rNeg = -1/t->getRational(); RefPtr< LFSCProof > p = LFSCLraMulC::Make( t->getLFSCProof(), rNeg, EQ ); tRetVal = new TReturn( p.get(), emptyL, emptyLUsed, r, true, 1 ); }else{ Rational r = Rational( -1 ); RefPtr< LFSCProof > p = LFSCLraMulC::Make( t->getLFSCProof(), r, EQ ); tRetVal = new TReturn( p.get(), emptyL, emptyLUsed, nullRat, false, 1 ); } } else if( yMode==0 ) { tRetVal = new TReturn( LFSCProof::Make_mimic( pf, t->getLFSCProof(), 2 ), emptyL, emptyLUsed, t->getRational(), t->hasRational(), 0 ); } } else if(pf[0]==d_impl_mp_str){ // impl_mp rule // get subproofs TReturn* t1 = cvc3_to_lfsc(pf[3],beneath_lc); TReturn* t2 = cvc3_to_lfsc(pf[4],beneath_lc); t1->getL( emptyL, emptyLUsed ); t2->getL( emptyL, emptyLUsed ); yMode = TReturn::normalize_tret( pf[3], t1, pf[4], t2); if( yMode==1 ){ int knd1 = get_normalized( queryAtomic( pf[1] ).getKind() ); int knd2 = get_normalized( queryAtomic( pf[2] ).getKind() ); if( is_eq_kind( knd2 ) ) { #ifdef PRINT_MAJOR_METHODS cout << ";[M]: impl_mp" << std::endl; #endif RefPtr< LFSCProof > p1 = LFSCLraAdd::Make( t1->getLFSCProof(), t2->getLFSCProof(), knd1, knd2 ); // if non-homogenous case if( knd1 == GT && knd2 == GE ){ ostringstream os1; os1 <<"(>0_to_>=0_Real _"; ostringstream os2; os2 <<")"; p1 = LFSCProofGeneric::Make(os1.str(), p1.get(), os2.str()); p1->setChOp( GE ); } tRetVal = new TReturn(p1.get(), emptyL, emptyLUsed, nullRat, false, 1); }else{ cout << "Kind = " << kind_to_str( knd2 ) << std::endl; } } else { ostringstream os1, os2; os1 << "(impl_mp _ _ "; os2 << ")"; tRetVal = new TReturn( LFSCProofGeneric::Make( os1.str(), t1->getLFSCProof(), t2->getLFSCProof(), os2.str() ), emptyL, emptyLUsed, nullRat, false, 0); } } else if( pf[0]==d_basic_subst_op_str || pf[0]==d_basic_subst_op1_str ) { if( pf.arity()==5 ){ // get subproofs bool prevCvc3Mimic = cvc3_mimic; #ifdef LRA2_PRIME if( pf[1].getKind()==IFF || pf[1].getKind()==AND || pf[1].getKind()==OR && getNumNodes( pf )<=3 ){ #else if( pf[1].getKind()==IFF ){ #endif cvc3_mimic = true; } #ifdef PRINT_MAJOR_METHODS cout << ";[M]: basic_subst_op1 " << kind_to_str( pf[1].getKind() ) << std::endl; #endif //cvc3_mimic = (( pe1.getKind()==AND || pe1.getKind()==OR ) && getNumNodes( pf1 )<5 ) ? true : prevCvc3Mimic; TReturn* t1 = cvc3_to_lfsc(pf[3],beneath_lc, rev_pol); //cvc3_mimic = (( pe1.getKind()==AND || pe1.getKind()==OR ) && getNumNodes( pf2 )<5 ) ? true : prevCvc3Mimic; TReturn* t2 = cvc3_to_lfsc(pf[4],beneath_lc, rev_pol); cvc3_mimic = prevCvc3Mimic; tRetVal = do_bso( pf, beneath_lc, rev_pol, t1, t2, ose ); } } else if( pf[0]==d_basic_subst_op0_str ){ if( pf.arity()==4 ){ TReturn* t = cvc3_to_lfsc(pf[3],beneath_lc, !rev_pol); yMode = t->getProvesY(); t->getL( emptyL, emptyLUsed ); if( yMode==1 ){ if( pf[1].isNot() || pf[1].getKind()==UMINUS ){ if( !pf[2][0].isFalse() && !pf[2][0].isTrue() ){ RefPtr< LFSCProof > p = LFSCLraMulC::Make( t->getLFSCProof(), Rational( -1 ), EQ ); tRetVal = new TReturn( p.get(), emptyL, emptyLUsed, t->getRational(), t->hasRational(), 1 ); }else{ tRetVal = t; } } }else if( yMode==3 ){ }else if( yMode==2 ){ if( pf[1].isNot() ) //rev_pol should have switched things already tRetVal = t; }else if( yMode==0 ){ ostringstream os1; os1 << "(basic_subst_op0_" << kind_to_str( pf[1].getKind() ) << " _ _ "; ostringstream os2; os2 << ")"; tRetVal = new TReturn( LFSCProofGeneric::Make( os1.str(), t->getLFSCProof(), os2.str() ), emptyL, emptyLUsed, nullRat, false, 0 ); } } if( !tRetVal ){ ose << "subst0 kind = " << kind_to_str( pf[1].getKind() ) << std::endl; ose << "subst0 arity = " << pf.arity() << std::endl; } } else if( pf[0]==d_optimized_subst_op_str ) { if( pf[1].getKind()==ITE ){ #ifdef PRINT_MAJOR_METHODS cout << ";[M]: optimized_subst_op, ite " << std::endl; #endif //make reflexive proof of proven statement RefPtr< LFSCProof > p = LFSCProofExpr::Make( pf[1] ); ostringstream os1, os2; if( isFormula( pf[1] ) ){ os1 << "(iff_refl "; }else{ os1 << "(refl Real "; } os2 << ")"; p = LFSCProofGeneric::Make( os1.str(), p.get(), os2.str() ); bool success = true; for( int a=3; agetL( emptyL, emptyLUsed ); if( TReturn::normalize_tr( pf[a], t, 0 )==0 ){ if( type!=-1 ){ ostringstream os1, os2; os1 << "(optimized_subst_op_"; if( isFormula( pf[1] ) ) os1 << "ifte"; else os1 << "ite"; if( type==1 ) os1 << "_t1"; else if( type==2 ) os1 << "_t2"; os1 << " _ _ _ _ _ _ _ "; os2 << ")"; p = LFSCProofGeneric::Make( os1.str(), p.get(), t->getLFSCProof(), os2.str() ); success = true; } } } } } if( success ){ tRetVal = new TReturn( p.get(), emptyL, emptyLUsed, nullRat, false, 0 ); } }else if( pf[1].getKind()==PLUS ){ //cout << ";[M]: optimized_subst_op, plus " << std::endl; TReturn* t = cvc3_to_lfsc(pf[3],beneath_lc); yMode = t->getProvesY(); t->getL( emptyL, emptyLUsed ); if( t->getProvesY()==1 ){ tRetVal = t; }else{ //tRetVal = make_trusted( pf ); Expr pe; if( what_is_proven( pf[3], pe ) ) { if( pe.getKind()==EQ ) { ostringstream os1, os2; os1 << "(canonize_conv _ _ _ _ _ _ "; int pnt1 = queryMt( Expr( MINUS, pe[0], pe[1] ) ); int pnt2 = queryMt( Expr( MINUS, pf[1], pf[2] ) ); os1 << "@pnt" << pnt1 << " @pnt" << pnt2 << " "; os2 << ")"; pntNeeded[ pnt1 ] = true; pntNeeded[ pnt2 ] = true; tRetVal = new TReturn( LFSCProofGeneric::Make( os1.str(), t->getLFSCProof(), os2.str() ), emptyL, emptyLUsed, t->getRational(), t->hasRational(), 0 ); }else{ cout << "proving kind " << kind_to_str( pe.getKind() ) << std::endl; cout << pf[3][0] << " " << pe << std::endl; } } } }else{ //tRetVal = make_trusted( pf ); if( pf[1].arity()==pf.arity()-3 ){ #ifdef PRINT_MAJOR_METHODS cout << ";[M]: optimized_subst_op, cascade " << kind_to_str( pf[1].getKind() ) << std::endl; #endif Expr pfn = pf[pf.arity()-1]; Expr cf1 = pf[1][pf.arity()-4]; Expr cf2 = pf[2][pf.arity()-4]; tRetVal = cvc3_to_lfsc( pf[pf.arity()-1], beneath_lc, rev_pol ); for( int a=(int)pf.arity()-2; a>=3; a-- ){ cf1 = Expr( pf[1].getKind(), pf[1][a-3], cf1 ); cf2 = Expr( pf[2].getKind(), pf[2][a-3], cf2 ); std::vector < Expr > exprs; exprs.push_back( d_basic_subst_op1_str ); exprs.push_back( cf1 ); exprs.push_back( cf2 ); exprs.push_back( pf[a] ); exprs.push_back( pfn ); //cascade it, turn it into a different proof pfn = Expr(PF_APPLY, exprs ); TReturn* tc = cvc3_to_lfsc( pf[a], beneath_lc, rev_pol ); tRetVal = do_bso( pfn, beneath_lc, rev_pol, tc, tRetVal, ose ); } }else{ ose << "opt_subst_op arity pv1 = " << pf[1].arity() << " " << pf.arity()-3 << std::endl; ose << "opt_subst_op arity pv2 = " << pf[2].arity() << " " << pf.arity()-3 << std::endl; } } if( !tRetVal ){ for( int a=0; a=3 && pf[a].arity()>0 ){ ose << a << ": "; ose << pf[a][0] << std::endl; Expr pre; what_is_proven( pf[a], pre ); ose << "wip: " << pre << std::endl; }else{ ose << a << ": " << pf[a] << std::endl; } } //RefPtr< LFSCProof > p; //TReturn* curr = NULL; //for( int a=(int)(pf.arity()-1); a>=4; a-- ){ // TReturn* t = cvc3_to_lfsc(pf[a],beneath_lc); // if( curr ){ // int cyMode = TReturn::normalize_tret( // if( pf[1].getKind()==AND || pf[1].getKind()==OR ){ // ostringstream os1, os2; // os1 << "(optimized_subst_op_"; // if( yMode==2 ) // os1 << "impl_"; // os1 << kind_to_str( pf[1].getKind() ); // os1 << " _ _ _ _ "; // os2 << ")"; // p = LFSCProofGeneric::Make( os1.str(), p.get(), os2.str() ); // }else{ // curr = t; // } // tRetVal = new TReturn( p.get(), emptyL, emptyLUsed, nullRat, false, t->getProvesY() ); //} ose << "opt_subst_op kind = " << kind_to_str( pf[1].getKind() ) << std::endl; ose << "opt_subst_op arity = " << pf.arity() << std::endl; } } else if( pf[0]==d_eq_trans_str ){ // get subproofs TReturn* t1 = cvc3_to_lfsc(pf[5],beneath_lc); TReturn* t2 = cvc3_to_lfsc(pf[6],beneath_lc); t1->getL( emptyL, emptyLUsed ); t2->getL( emptyL, emptyLUsed ); yMode = TReturn::normalize_tret( pf[5], t1, pf[6], t2 ); if( yMode==1 ){ // merge literals tRetVal = new TReturn( LFSCLraAdd::Make( t1->getLFSCProof(), t2->getLFSCProof(), EQ, EQ ), emptyL, emptyLUsed, nullRat, false, 1 ); }else if( yMode==0 ){ std::vector< RefPtr< LFSCProof > > pfs; std::vector< string > strs; ostringstream os1, os2, os3; os1 << "(trans Real "; os2 << " "; os3 << ")"; pfs.push_back( LFSCProofExpr::Make( pf[2] ) ); pfs.push_back( LFSCProofExpr::Make( pf[3] ) ); pfs.push_back( LFSCProofExpr::Make( pf[4] ) ); pfs.push_back( t1->getLFSCProof() ); pfs.push_back( t2->getLFSCProof() ); strs.push_back( os1.str() ); strs.push_back( os2.str() ); strs.push_back( os2.str() ); strs.push_back( os2.str() ); strs.push_back( os2.str() ); strs.push_back( os3.str() ); tRetVal = new TReturn( LFSCProofGeneric::Make( pfs, strs ), emptyL, emptyLUsed, nullRat, false, 0 ); } } else if(pf[0] == d_eq_symm_str){ // eq_symm rule TReturn* t = cvc3_to_lfsc(pf[4],beneath_lc); t->getL( emptyL, emptyLUsed ); if( t->getProvesY()==1 ) { tRetVal = new TReturn(LFSCLraMulC::Make(t->getLFSCProof(), Rational( -1 ), EQ), emptyL, emptyLUsed, nullRat, false, 1); } else if( t->getProvesY()==0 ) { ostringstream os1, os2; os1 << "(symm Real _ _ "; os2 << ")"; tRetVal = new TReturn( LFSCProofGeneric::Make( os1.str(), t->getLFSCProof(), os2.str() ), emptyL, emptyLUsed, nullRat, false, 0); } } else if( pf[0]==d_real_shadow_str ) { // get subproofs TReturn* t1 = cvc3_to_lfsc(pf[3],beneath_lc); TReturn* t2 = cvc3_to_lfsc(pf[4],beneath_lc); t1->getL( emptyL, emptyLUsed ); t2->getL( emptyL, emptyLUsed ); yMode = TReturn::normalize_tret( pf[3], t1, pf[4], t2 ); if( yMode==1 ) { int op1 = get_normalized( queryAtomic( pf[1] ).getKind() ); int op2 = get_normalized( queryAtomic( pf[2] ).getKind() ); tRetVal = new TReturn( LFSCLraAdd::Make( t1->getLFSCProof(), t2->getLFSCProof(), op1, op2 ), emptyL, emptyLUsed, nullRat, false, 1 ); } else if( yMode==0 ) { ostringstream os1, os2; os1 << "(real_shadow_" << kind_to_str( pf[1].getKind() ); os1 << "_" << kind_to_str( pf[2].getKind() ); os1 << " _ _ _ "; os2 << ")"; tRetVal = new TReturn( LFSCProofGeneric::Make( os1.str(), t1->getLFSCProof(), t2->getLFSCProof(), os2.str() ), emptyL, emptyLUsed, nullRat, false, 0 ); } } else if( pf[0]==d_addInequalities_str ) { // get subproofs TReturn* t1 = cvc3_to_lfsc(pf[3],beneath_lc); TReturn* t2 = cvc3_to_lfsc(pf[4],beneath_lc); t1->getL( emptyL, emptyLUsed ); t2->getL( emptyL, emptyLUsed ); yMode = TReturn::normalize_tret( pf[3], t1, pf[4], t2 ); if( yMode==1 ) { tRetVal = new TReturn( LFSCLraAdd::Make( t1->getLFSCProof(), t2->getLFSCProof(), pf[1].getKind(), pf[2].getKind() ), emptyL, emptyLUsed, nullRat, false, 1 ); } else if( yMode==0 ) { ostringstream os1, os2; os1 << "(add_inequalities_" << kind_to_str( pf[1].getKind() ); os1 << "_" << kind_to_str( pf[2].getKind() ); os1 << " _ _ _ _ "; os2 << ")"; tRetVal = new TReturn( LFSCProofGeneric::Make( os1.str(), t1->getLFSCProof(), t2->getLFSCProof(), os2.str() ), emptyL, emptyLUsed, nullRat, false, 0 ); } } else if( pf[0] == d_real_shadow_eq_str){ TReturn* t1 = cvc3_to_lfsc(pf[3], beneath_lc); TReturn* t2 = cvc3_to_lfsc(pf[4], beneath_lc); t1->getL( emptyL, emptyLUsed ); t2->getL( emptyL, emptyLUsed ); yMode = TReturn::normalize_tret( pf[3], t1, pf[4], t2 ); if( yMode==1 ){ ostringstream os1, os2; os1 << "(lra_>=_>=_to_= _ _ "; os2 << ")"; RefPtr< LFSCProof > p = LFSCProofGeneric::Make( os1.str(), t1->getLFSCProof(), t2->getLFSCProof(), os2.str() ); p->setChOp( EQ ); tRetVal = new TReturn( p.get(), emptyL, emptyLUsed, nullRat, false, 1 ); }else if( yMode==0 || yMode==2 ){ ostringstream os1, os2; os1 << "(real_shadow_eq _ _"; os2 << ")"; tRetVal = new TReturn( LFSCProofGeneric::Make( os1.str(), t1->getLFSCProof(), t2->getLFSCProof(), os2.str() ), emptyL, emptyLUsed, nullRat, false, 0 ); } } else if( pf[0]==d_cycle_conflict_str ) { // get subproofs bool isErr = false; int n = ( pf.arity() - 1 )/2 + 1; std::vector < TReturn* > trets; for( int a=n; agetL( emptyL, emptyLUsed ); } } } //add them together if( !isErr ){ int currOp = get_normalized( pf[1].getKind() ); RefPtr< LFSCProof > p1 = trets[0]->getLFSCProof(); for( int a=1; a<(int)trets.size(); a++ ){ int op = get_normalized( pf[a+1].getKind() ); p1 = LFSCLraAdd::Make( trets[a]->getLFSCProof(), p1.get(), op, currOp ); if( op==GT ){ currOp = GT; }else if( op==GE ){ currOp = currOp==GT ? GT : GE; } } tRetVal = new TReturn( LFSCLraContra::Make( p1.get(), GT ), emptyL, emptyLUsed, nullRat, false, 0 ); } } else if( pf[0]==d_learned_clause_str ) { if( pf.arity()==2 ) { TReturn* t = cvc3_to_lfsc(pf[1],true); t->getL( emptyL, emptyLUsed ); RefPtr< LFSCProof > p = t->getLFSCProof(); Expr pe; what_is_proven( pf[1], pe ); bool success = true; if( !pe.isFalse() ){ success = false; if( TReturn::normalize_tr( pf[1], t, 3, false )==3 ) { p = t->getLFSCProof(); success = true; } #ifdef PRINT_MAJOR_METHODS cout << ";[M]: learned clause, not proven false" << std::endl; #endif } else if( cvc3_mimic && pf[1][0]!=d_cycle_conflict_str ) { ostringstream os1, os2; os1 << "(clausify_false "; os2 << ")"; p = LFSCProofGeneric::Make( os1.str(), p.get(), os2.str() ); } if( success ){ //ostringstream os1, os2; //if( debug_var ) // os1 << "LC:"; //we must close all proof-lets that contain free variables //p = make_let_proof( p.get(), emptyL, false ); #ifdef OPTIMIZE std::vector< int > assumes, assumesUsed; t->calcL( assumes, assumesUsed ); for( int a=0; a<(int)assumes.size(); a++ ){ p = LFSCAssume::Make( assumes[a], p.get(), true ); } #else for( int a=0; a<(int)emptyL.size(); a++ ){ p = LFSCAssume::Make( emptyL[a], p.get(), true ); } #endif emptyL.clear(); emptyLUsed.clear(); tRetVal = new TReturn( p.get(), emptyL, emptyLUsed, nullRat, false, 3 ); } } } else if( pf[0]==d_andE_str ) { TReturn* t = cvc3_to_lfsc(pf[3],beneath_lc); t->getL( emptyL, emptyLUsed ); if( t->getProvesY()==0 ) { int pos = pf[1].getRational().getNumerator().getInt(); RefPtr< LFSCProof > p = LFSCProof::Make_and_elim( pf[2], t->getLFSCProof(), pos, pf[2][pos] ); tRetVal = new TReturn( p.get(), emptyL, emptyLUsed, t->getRational(), t->hasRational(), 0 ); } else if( t->getProvesY()==3 ) { //need to use and CNF rules RefPtr< LFSCProof > p = LFSCProof::Make_CNF( pf[2], d_and_mid_s, pf[1].getRational().getNumerator().getInt() ); p = LFSCBoolRes::Make( t->getLFSCProof(), p.get(), pf[2], pf ); tRetVal = new TReturn( p.get(), emptyL, emptyLUsed, nullRat, false, 3 ); } } else if( pf[0]==d_rewrite_implies_str ) { if( !cvc3_mimic ) { Expr ei = Expr( IMPLIES, pf[1], pf[2] ); RefPtr< LFSCProof > p = LFSCProof::Make_CNF( ei, d_imp_s, 3 ); if( p.get() ) { tRetVal = new TReturn( p.get(), emptyL, emptyLUsed, nullRat, false, 3 ); } } else { //tRetVal = new TReturn( LFSCProofGeneric::MakeStr( "(rewrite_implies _ _)" ), emptyL, emptyLUsed, nullRat, false, 0 ); } } else if( pf[0]==d_rewrite_ite_same_str ) { ostringstream os1, os2; os1 << "(rewrite_ite_same "; RefPtr< LFSCProof > p1 = LFSCProofExpr::Make( pf[2] ); RefPtr< LFSCProof > p2 = LFSCProofExpr::Make( pf[3] ); os2 << ")"; tRetVal = new TReturn( LFSCProofGeneric::Make( os1.str(), p1.get(), p2.get(), os2.str() ), emptyL, emptyLUsed, nullRat, false, 0 ); } else if( pf[0]==d_rewrite_and_str || pf[0]==d_rewrite_or_str ) { //Expr e = Expr( IFF, pf[1], pf[2] ); bool isAnd = pf[0]==d_rewrite_and_str; if( pf[1].arity()==2 && pf[1][0]==pf[1][1] ){ //try to apply binary redundant rule ostringstream os1, os2 ; os1 << "(" << ( isAnd ? "and" : "or" ) << "_redundant "; RefPtr< LFSCProof > p = LFSCProofExpr::Make( pf[1][0] ); os2 << ")"; tRetVal = new TReturn( LFSCProofGeneric::Make( os1.str(), p.get(), os2.str() ), emptyL, emptyLUsed, nullRat, false, 0 ); }else if( isFlat( pf[2] ) ){ //try to do the normalize Expr e1 = cascade_expr( pf[1] ); Expr e2 = cascade_expr( pf[2] ); Expr pe; make_flatten_expr( e1, pe, pf[1].getKind() ); //cout << "we have an and normalize " << e1 << std::endl; //cout << "making and normalize for " << pe << std::endl; //cout << "this should be equal to " << e2 << std::endl; //cout << (pe==e2) << std::endl; if( pe==e2 ){ //standard and normalize ostringstream os1, os2; os1 << "(" << ( isAnd ? "and" : "or" ) << "_normalize _ "; os2 << ")"; RefPtr< LFSCProof > p = LFSCProofExpr::Make( pf[1] ); tRetVal = new TReturn( LFSCProofGeneric::Make( os1.str(), p.get(), os2.str() ), emptyL, emptyLUsed, nullRat, false, 0 ); } //else if( pf[1].arity()==2 ){ //try to normalize the symm version // Expr e1s = cascade_expr( Expr( pf[1].getKind(), pf[1][1], pf[1][0] ) ); // make_flatten_expr( e1s, pe, pf[1].getKind() ); // if( pe==e2 ){ // ostringstream oss1, oss2, oss3, oss4; // oss1 << "(iff_trans _ _ (" << ( isAnd ? "and" : "or" ); // oss1 << "_symm "; // RefPtr< LFSCProof > pex1 = LFSCProofExpr::Make( pf[1][0] ); // oss2 << " "; // RefPtr< LFSCProof > pex2 = LFSCProofExpr::Make( pf[1][1] ); // oss3 << ") " << "(" << ( isAnd ? "and" : "or" ) << "_normalize _ "; // RefPtr< LFSCProof > ps = LFSCProofExpr::Make( e1s ); // oss4 << "))"; // std::vector< RefPtr< LFSCProof > > pfs; // pfs.push_back( pex1.get() ); // pfs.push_back( pex2.get() ); // pfs.push_back( ps.get() ); // std::vector< string > strs; // strs.push_back( oss1.str() ); // strs.push_back( oss2.str() ); // strs.push_back( oss3.str() ); // strs.push_back( oss4.str() ); // tRetVal = new TReturn( LFSCProofGeneric::Make( pfs, strs ), emptyL, emptyLUsed, nullRat, false, 0 ); // } //} } if( !tRetVal ){ //going to have to trust it TReturn* t = make_trusted( pf ); //this code runs the normalize side condition, but ignores it (for consistency with proof checking times) ostringstream os1, os2; os1 << "(" << (isAnd ? "and" : "or" ) << "_nd _ _ _ "; os2 << ")"; tRetVal = new TReturn( LFSCProofGeneric::Make( os1.str(), t->getLFSCProof(), os2.str() ), emptyL, emptyLUsed, nullRat, false, 0 ); } } else if( pf[0]==d_rewrite_iff_symm_str ) { ostringstream os1, os2; os1 << "(rewrite_iff_symm "; RefPtr< LFSCProof > p1 = LFSCProofExpr::Make( pf[1] ); RefPtr< LFSCProof > p2 = LFSCProofExpr::Make( pf[2] ); os2 << ")"; tRetVal = new TReturn( LFSCProofGeneric::Make( os1.str(), p1.get(), p2.get(), os2.str() ), emptyL, emptyLUsed, nullRat, false, 0 ); } else if( pf[0]== d_implyEqualities_str){ if( pf.arity()==5 ){ TReturn* t1 = cvc3_to_lfsc(pf[3],beneath_lc); TReturn* t2 = cvc3_to_lfsc(pf[4],beneath_lc); t1->getL( emptyL, emptyLUsed ); t2->getL( emptyL, emptyLUsed ); if( TReturn::normalize_tr( pf[3], t1, 0 )==0 && TReturn::normalize_tr( pf[4], t2, 0 )==0 ) { Expr e1, e2; if( what_is_proven( pf[3], e1 ) && what_is_proven( pf[4], e2 ) ) { int m1 = queryMt( Expr( MINUS, e1[1], e1[0] ) ); int m2 = queryMt( Expr( MINUS, e2[1], e2[0] ) ); ostringstream os1, os2; os1<<"(imply_equalities _ _ _ _ _ _ "; os1 << "@pnt" << abs( m1 ) << " @pnt" << abs( m2 ) << " "; os2 << ")"; tRetVal = new TReturn( LFSCProofGeneric::Make( os1.str(), t1->getLFSCProof(), t2->getLFSCProof(), os2.str() ), emptyL, emptyLUsed, nullRat, false, 0 ); } } } } else if( pf[0]==d_implyWeakerInequality_str ) { #ifdef PRINT_MAJOR_METHODS //cout << ";[M]: imply weaker equality " << pf[1] << std::endl; #endif if( !cvc3_mimic ){ if( pf[1].arity()==2 && pf[2].arity()==2 && pf[1][1][0].isRational() && pf[2][1][0].isRational() ) { //Rational r = pf[1][1][0].getRational() - pf[2][1][0].getRational(); //tRetVal = new TReturn( LFSCLraAxiom::Make( r, GT ), emptyL, emptyLUsed, nullRat, false, 1 ); tRetVal = new TReturn( LFSCLraAxiom::MakeEq(), emptyL, emptyLUsed, nullRat, false, 1 ); } }else{ Rational r1, r2; ostringstream os1, os2; getRat(pf[1][1][0], r1); getRat(pf[2][1][0], r2); RefPtr p; os1 <<"(imply_weaker_inequality_" << kind_to_str( pf[1].getKind() ) << "_" << kind_to_str( pf[2].getKind() ); if(pf[1][1].arity() > 2) { vector t1_children; int start_i = 1; int end_i = pf[1][1].arity(); for(int i = start_i; i < end_i; i ++) { const Expr& term = pf[1][1][i]; t1_children.push_back(term); } p = LFSCProofExpr::Make(Expr(pf[1][1].getKind(), t1_children)); } else { p = LFSCProofExpr::Make(pf[1][1][1]); } os2<<" "; print_rational(r1, os2); os2 << " "; print_rational(r2, os2); os2<<")"; tRetVal = new TReturn( LFSCProofGeneric::Make( os1.str(), p.get(), os2.str() ), emptyL, emptyLUsed, nullRat, false, 0 ); } } else if( pf[0]==d_implyNegatedInequality_str ) { #ifdef PRINT_MAJOR_METHODS //cout << ";[M]: imply negated equality " << pf[1] << std::endl; #endif if( !cvc3_mimic ){ if( pf[1].arity()==2 && pf[2].arity()==2 && pf[1][1][0].isRational() && pf[2][1][0].isRational() ) { //Rational r = -( pf[1][1][0].getRational() + pf[2][1][0].getRational() ); //tRetVal = new TReturn( LFSCLraAxiom::Make( r, GT ), emptyL, emptyLUsed, nullRat, false, 1 ); tRetVal = new TReturn( LFSCLraAxiom::MakeEq(), emptyL, emptyLUsed, nullRat, false, 1 ); } }else{ Rational r1, r2; if( getRat( pf[1][1][0], r1 ) && getRat(pf[2][1][0], r2) ){ Expr ep = pf[1][1][1]; Rational negOne = Rational( -1 ); bool isNeg = false; if ( pf[1][1][1].getKind()==MULT && pf[1][1][1][0].isRational() && pf[1][1][1][0].getRational()==negOne ){ isNeg = true; if(pf[1][1].arity() > 2) { vector t1_children; int start_i = 1; int end_i = pf[1][1].arity(); for(int i = start_i; i < end_i; i ++) { const Expr& term = pf[1][1][i]; t1_children.push_back(term); } ep = Expr(pf[1][1].getKind(), t1_children); } else { ep = pf[1][1][1][1]; } } if(r1 == r2) { ostringstream os1, os2; os1 << "(imply_negated_inequality_<" << (isNeg ? "n" : "" ); os1 << " "; RefPtr< LFSCProof > p = LFSCProofExpr::Make( ep ); os2 << " "; print_rational( r1, os2 ); os2 << ")"; tRetVal = new TReturn( LFSCProofGeneric::Make( os1.str(), p.get(), os2.str() ), emptyL, emptyLUsed, nullRat, false, 0 ); }else{ ostringstream os1, os2; os1 << "(imply_negated_inequality_"; os1 << kind_to_str(pf[1].getKind()) << "_"< p = LFSCProofExpr::Make( ep ); os2 << " "; print_rational( r1, os2 ); os2 << " "; print_rational( r2, os2 ); os2 << ")"; tRetVal = new TReturn( LFSCProofGeneric::Make( os1.str(), p.get(), os2.str() ), emptyL, emptyLUsed, nullRat, false, 0 ); } } } } else if( pf[0]==d_rewrite_iff_str){ ostringstream os1, os2; // then it's just the iff_refl rule if(pf[1] == pf[2]){ os1 << "(iff_refl "; os2 << ")"; RefPtr< LFSCProof > p = LFSCProofExpr::Make( pf[1] ); tRetVal = new TReturn( LFSCProofGeneric::Make( os1.str(), p.get(), os2.str() ), emptyL, emptyLUsed, nullRat, false, 0 ); } if(pf[1] == d_pf_expr.getEM()->trueExpr()){ os1 << "(rewrite_iff_true_l "; RefPtr< LFSCProof > p1 = LFSCProofExpr::Make( pf[2] ); os2 << ")"; tRetVal = new TReturn( LFSCProofGeneric::Make( os1.str(), p1.get(), os2.str() ), emptyL, emptyLUsed, nullRat, false, 0 ); } if(pf[1] == d_pf_expr.getEM()->falseExpr()){ os1 << "(rewrite_iff_false_l "; RefPtr< LFSCProof > p1 = LFSCProofExpr::Make( pf[2] ); os2 << ")"; tRetVal = new TReturn( LFSCProofGeneric::Make( os1.str(), p1.get(), os2.str() ), emptyL, emptyLUsed, nullRat, false, 0 ); } if(pf[2] == d_pf_expr.getEM()->trueExpr()){ os1 << "(rewrite_iff_true_r "; RefPtr< LFSCProof > p1 = LFSCProofExpr::Make( pf[1] ); os2 << ")"; tRetVal = new TReturn( LFSCProofGeneric::Make( os1.str(), p1.get(), os2.str() ), emptyL, emptyLUsed, nullRat, false, 0 ); } if(pf[2] == d_pf_expr.getEM()->falseExpr()){ os1 << "(rewrite_iff_false_r "; RefPtr< LFSCProof > p1 = LFSCProofExpr::Make( pf[1] ); os2 << ")"; tRetVal = new TReturn( LFSCProofGeneric::Make( os1.str(), p1.get(), os2.str() ), emptyL, emptyLUsed, nullRat, false, 0 ); } if(pf[1].isNot() && pf[1][0] == pf[2]){ os1 << "(rewrite_iff_not_l "; RefPtr< LFSCProof > p1 = LFSCProofExpr::Make( pf[1][0] ); os2 << ")"; tRetVal = new TReturn( LFSCProofGeneric::Make( os1.str(), p1.get(), os2.str() ), emptyL, emptyLUsed, nullRat, false, 0 ); } if(pf[2].isNot() && pf[2][0] == pf[1]){ os1 << "(rewrite_iff_not_r "; RefPtr< LFSCProof > p1 = LFSCProofExpr::Make( pf[2][0] ); os2 << ")"; tRetVal = new TReturn( LFSCProofGeneric::Make( os1.str(), p1.get(), os2.str() ), emptyL, emptyLUsed, nullRat, false, 0 ); } // just flips them if(pf[1] < pf[2]){ os1 << "(rewrite_iff_symm "; RefPtr< LFSCProof > p1 = LFSCProofExpr::Make( pf[1] ); RefPtr< LFSCProof > p2 = LFSCProofExpr::Make( pf[2] ); os2 << ")"; tRetVal = new TReturn( LFSCProofGeneric::Make( os1.str(), p1.get(), p2.get(), os2.str() ), emptyL, emptyLUsed, nullRat, false, 0 ); } if( !tRetVal ){ os1 << "(iff_refl "; os2 << ")"; RefPtr< LFSCProof > p = LFSCProofExpr::Make( pf[1].iffExpr(pf[2]) ); tRetVal = new TReturn( LFSCProofGeneric::Make( os1.str(), p.get(), os2.str() ), emptyL, emptyLUsed, nullRat, false, 0 ); } } else if( isIgnoredRule( pf[0] ) ) { TReturn* t = cvc3_to_lfsc(pf[2],beneath_lc); yMode = t->getProvesY(); t->getL( emptyL, emptyLUsed ); if( !cvc3_mimic ) { if( yMode==1 ){ tRetVal = t; } } else { if( yMode==0 || yMode==2 ) { ostringstream os1, os2; os1 << "(" << pf[0] << (yMode==2 ? "_impl" : "" ) << " _ "; os2 << ")"; tRetVal = new TReturn( LFSCProofGeneric::Make( os1.str(), t->getLFSCProof(), os2.str() ), emptyL, emptyLUsed, t->getRational(), t->hasRational(), 0 ); } } } else if( isTrivialTheoryAxiom( pf ) ) { //find the rational multiplier for the axiom Rational r; bool hasRat = false; if( pf[0]==d_mult_ineqn_str || pf[0]==d_mult_eqn_str || pf[0]==d_rewrite_eq_symm_str || pf[0]==d_int_const_eq_str ){ if( pf[0]==d_mult_ineqn_str && pf[2].arity()==2 && pf[2][1].arity()==2 ){ if( pf[2][1][1].isRational() ){ r = pf[2][1][1].getRational(); hasRat = true; }else if( pf[2][1][0].isRational() ){ r = pf[2][1][0].getRational(); hasRat = true; } }else if( pf[0]==d_mult_eqn_str && pf[3].isRational() ){ r = pf[3].getRational(); hasRat = true; }else if( pf[0]==d_rewrite_eq_symm_str ){ r = -1; hasRat = true; }else if( pf[0]==d_int_const_eq_str ){ if( pf[1].getKind()==EQ && !pf[2].isFalse() ){ if( pf[1][1].getKind()==MULT && getRat( pf[1][1][0], r ) ){ r = -r; }else if( pf[1][1].getKind()==PLUS && pf[1][1][1].getKind()==MULT && getRat( pf[1][1][1][0], r ) ){ r = -r; }else{ r = -1; } hasRat = true; } } if( !hasRat ) { ose << pf[0] << ", Warning: Can't find rational multiplier " << std::endl; ose << pf[2] << std::endl; } } //handle the axiom - only do it if the term is polynomial normalizable if( !cvc3_mimic && isTrivialTheoryAxiom( pf, true ) ) { //ignore it if cvc3_mimic is false if( hasRat && r<0 && pf[0]==d_mult_ineqn_str ){ r = -r; } //if( debug_conv && !beneath_lc ){ // cout << "WARNING: Trivial theory axiom used, not underneath learned clause: " << pf[0] << std::endl; //} tRetVal = new TReturn( LFSCLraAxiom::MakeEq(), emptyL, emptyLUsed, r, hasRat, 1 ); }else{ //int val = queryM( pf[1] ); if( pf[0] == d_refl_str ) { if( isFormula( pf[1] ) ){ ostringstream os1, os2; os1 << "(iff_refl "; os2 << ")"; RefPtr< LFSCProof > p = LFSCProofExpr::Make( pf[1] ); tRetVal = new TReturn( LFSCProofGeneric::Make( os1.str(), p.get(), os2.str() ), emptyL, emptyLUsed, nullRat, false, 0 ); }else{ ostringstream os1, os2; os1 << "(refl Real "; os2 << ")"; RefPtr< LFSCProof > p = LFSCProofExpr::Make( pf[1] ); tRetVal = new TReturn( LFSCProofGeneric::Make( os1.str(), p.get(), os2.str() ), emptyL, emptyLUsed, nullRat, false, 0 ); } } else if( pf[0] == d_flip_inequality_str ) { ostringstream os1, os2; os1 << "(flip_inequality_" << kind_to_str( pf[1].getKind() ); os1 << "_" << kind_to_str( pf[2].getKind() ) << " "; os2 << ")"; RefPtr< LFSCProof > p1 = LFSCProofExpr::Make( pf[1][0] ); RefPtr< LFSCProof > p2 = LFSCProofExpr::Make( pf[1][1] ); tRetVal = new TReturn( LFSCProofGeneric::Make( os1.str(), p1.get(), p2.get(), os2.str() ), emptyL, emptyLUsed, nullRat, false, 0 ); } else if( pf[0] == d_right_minus_left_str ) { ostringstream os1, os2; os1 << "(right_minus_left_" << kind_to_str( pf[1].getKind() ) << " "; os2 << ")"; RefPtr< LFSCProof > p1 = LFSCProofExpr::Make( pf[1][0] ); RefPtr< LFSCProof > p2 = LFSCProofExpr::Make( pf[1][1] ); tRetVal = new TReturn( LFSCProofGeneric::Make( os1.str(), p1.get(), p2.get(), os2.str() ), emptyL, emptyLUsed, nullRat, false, 0 ); } else if( pf[0] == d_minus_to_plus_str ) { ostringstream os1, os2; os1 << "(minus_to_plus "; os2 << ")"; RefPtr< LFSCProof > p1 = LFSCProofExpr::Make( pf[1] ); RefPtr< LFSCProof > p2 = LFSCProofExpr::Make( pf[2] ); tRetVal = new TReturn( LFSCProofGeneric::Make( os1.str(), p1.get(), p2.get(), os2.str() ), emptyL, emptyLUsed, nullRat, false, 0 ); } else if( pf[0] == d_plus_predicate_str ) { ostringstream os1, os2; os1 << "(plus_predicate_" << kind_to_str( pf[1].getKind() ) << " "; std::vector< string > strs; std::vector< RefPtr< LFSCProof > > pfs; pfs.push_back( LFSCProofExpr::Make( pf[1][0] ) ); pfs.push_back( LFSCProofExpr::Make( pf[1][1] ) ); pfs.push_back( LFSCProofExpr::Make( pf[2][0][1] ) ); os2 << ")"; std::string spc( " " ); strs.push_back( os1.str() ); strs.push_back( spc ); strs.push_back( spc ); strs.push_back( os2.str() ); tRetVal = new TReturn( LFSCProofGeneric::Make( pfs, strs ), emptyL, emptyLUsed, nullRat, false, 0 ); } else if( pf[0] == d_canon_plus_str || pf[0]==d_canon_mult_str ) { int m = queryMt( Expr( MINUS, pf[1], pf[2] ) ); ostringstream os; os << "(canonize_= _ _ _ "; os << "@pnt" << m << ")"; pntNeeded[ m ] = true; tRetVal = new TReturn( LFSCProofGeneric::MakeStr( os.str().c_str() ), emptyL, emptyLUsed, nullRat, false, 0 ); } else if( pf[0] == d_canon_invert_divide_str ) { Rational r1 = Rational( 1 ); Expr er1 = d_pf_expr.getEM()->newRatExpr( pf[1][0].getRational() ); Expr er2 = d_pf_expr.getEM()->newRatExpr( r1/pf[1][1].getRational() ); //cout << "we have made " << er1 << " " << er2 << std::endl; int m = queryMt( Expr( MINUS, pf[1], Expr( MULT, er1, er2 )) ); ostringstream os; os << "(canonize_= _ _ _ "; os << "@pnt" << m << ")"; pntNeeded[ m ] = true; tRetVal = new TReturn( LFSCProofGeneric::MakeStr( os.str().c_str() ), emptyL, emptyLUsed, nullRat, false, 0 ); } else if( pf[0] == d_mult_ineqn_str && hasRat ) { ostringstream os1, os2; os1 << "(mult_ineqn_" << (r<0 ? "neg_" : ""); os1 << kind_to_str( pf[1].getKind() ) << " "; RefPtr< LFSCProof > p1 = LFSCProofExpr::Make( pf[1][0] ); RefPtr< LFSCProof > p2 = LFSCProofExpr::Make( pf[1][1] ); os2 << " "; print_rational( r, os2 ); os2 << ")"; tRetVal = new TReturn( LFSCProofGeneric::Make( os1.str(), p1.get(), p2.get(), os2.str() ), emptyL, emptyLUsed, nullRat, false, 0 ); } else if( pf[0] == d_mult_eqn_str && hasRat ) { ostringstream os1, os2; os1 << "(mult_eqn "; RefPtr< LFSCProof > p1 = LFSCProofExpr::Make( pf[1] ); RefPtr< LFSCProof > p2 = LFSCProofExpr::Make( pf[2] ); os2 << " "; print_rational( r, os2 ); os2 << ")"; tRetVal = new TReturn( LFSCProofGeneric::Make( os1.str(), p1.get(), p2.get(), os2.str() ), emptyL, emptyLUsed, nullRat, false, 0 ); } else if( pf[0] == d_negated_inequality_str ) { Expr e1 = queryAtomic( pf[1], true ); ostringstream os1, os2; os1 << "(negated_inequality_" << kind_to_str( e1.getKind() ); os1 << "_" << kind_to_str( get_not( e1.getKind() ) ) << " "; RefPtr< LFSCProof > p1 = LFSCProofExpr::Make( pf[1][0][0] ); RefPtr< LFSCProof > p2 = LFSCProofExpr::Make( pf[1][0][1] ); os2 << ")"; tRetVal = new TReturn( LFSCProofGeneric::Make( os1.str(), p1.get(), p2.get(), os2.str() ), emptyL, emptyLUsed, nullRat, false, 0 ); } else if( pf[0] == d_rewrite_eq_symm_str ) { ostringstream os1, os2; os1 << "(rewrite_eq_symm "; RefPtr< LFSCProof > p1 = LFSCProofExpr::Make( pf[2] ); RefPtr< LFSCProof > p2 = LFSCProofExpr::Make( pf[3] ); os2 << ")"; tRetVal = new TReturn( LFSCProofGeneric::Make( os1.str(), p1.get(), p2.get(), os2.str() ), emptyL, emptyLUsed, nullRat, false, 0 ); } else if( pf[0] == d_rewrite_eq_refl_str ) { ostringstream os1, os2; os1 << "(rewrite_eq_refl "; os2 << ")"; tRetVal = new TReturn( LFSCProofGeneric::Make( os1.str(), LFSCProofExpr::Make( pf[2] ), os2.str() ), emptyL, emptyLUsed, nullRat, false, 0 ); } else if( pf[0] == d_uminus_to_mult_str ) { if( pf[1].isRational() ) { ostringstream os; os << "(uminus_to_mult "; print_rational( pf[1].getRational(), os ); os << ")"; tRetVal = new TReturn( LFSCProofGeneric::MakeStr( os.str().c_str() ), emptyL, emptyLUsed, nullRat, false, 0 ); } } else if( pf[0] == d_rewrite_not_true_str ) { tRetVal = new TReturn( LFSCProofGeneric::MakeStr( "rewrite_not_true" ), emptyL, emptyLUsed, nullRat, false, 0 ); } else if( pf[0] == d_rewrite_not_false_str ) { tRetVal = new TReturn( LFSCProofGeneric::MakeStr( "rewrite_not_false" ), emptyL, emptyLUsed, nullRat, false, 0 ); } else if( pf[0] == d_int_const_eq_str ) { int m1 = queryMt( Expr( MINUS, pf[1][0], pf[1][1] ) ); int m2 = queryMt( Expr( MINUS, pf[2][0], pf[2][1] ) ); ostringstream os; os << "(canonize_iff _ _ _ _ _ _ @pnt" << m1 << " @pnt" << m2 << ")"; pntNeeded[ m1 ] = true; pntNeeded[ m2 ] = true; tRetVal = new TReturn( LFSCProofGeneric::MakeStr( os.str().c_str() ), emptyL, emptyLUsed, nullRat, false, 0 ); } } } else if( pf[0]==d_lessThan_To_LE_rhs_rwr_str ) { //FIXME: this introduces weirdness into the logic of completeness of the proof conversion //why is integer reasoning used in CVC3 QF_LRA proofs? if( !cvc3_mimic ) tRetVal = new TReturn( LFSCLraAxiom::MakeEq(), emptyL, emptyLUsed, nullRat, false, 1 ); else{ tRetVal = make_trusted( pf ); } } else if( pf[0]==d_rewrite_not_not_str ) { //note that "not not" is already taken care of FIXME #ifdef LRA2_PRIME tRetVal = new TReturn( LFSCProofGeneric::MakeStr("(rewrite_not_not _)"), emptyL, emptyLUsed, nullRat, false, 0 ); #else if( !cvc3_mimic ){ tRetVal = new TReturn( LFSCProofGeneric::MakeStr("(iff_refl _)"), emptyL, emptyLUsed, nullRat, false, 0 ); }else{ tRetVal = new TReturn( LFSCProofGeneric::MakeStr("(rewrite_not_not _)"), emptyL, emptyLUsed, nullRat, false, 0 ); } #endif } else if( isTrivialBooleanAxiom( pf[0] ) ) { if( !cvc3_mimic ){ tRetVal = new TReturn( LFSCLem::Make( queryM( pf[1] ) ), emptyL, emptyLUsed, nullRat, false, 3 ); }else{ } } else if( pf[0]==d_const_predicate_str ) { if( is_eq_kind( pf[1].getKind() ) ) { Rational r1, r2; //int knd = pf[2].isFalse() ? get_not( pf[1].getKind() ) : pf[1].getKind(); RefPtr< LFSCProof > p; if( getRat( pf[1][0], r1 ) && getRat( pf[1][1], r2 ) ){ #ifdef PRINT_MAJOR_METHODS cout << ";[M]: const_pred " << kind_to_str( pf[1].getKind() ); cout << " " << pf[2].isFalse(); cout << ", rp=" << rev_pol << ", cvc=" << cvc3_mimic << std::endl; #endif if( !cvc3_mimic ){ //if( rev_pol ){ // ostringstream ose1; // ose1 << "Warning: Const predicate, rev pol true" << std::endl; // print_warning( ose1.str().c_str() ); // knd = get_not( knd ); //} if( pf[1].getKind()==EQ ){ p = LFSCLraAxiom::MakeEq(); }else{ //Rational r = is_opposite( knd ) ? r2 - r1 : r1 - r2; //if( knd==GT ) // r = Rational( 1, 1000000 ); //if( knd==GE // r = Rational( 0 ); //p = LFSCLraAxiom::Make( r, get_normalized( knd ) ); p = LFSCLraAxiom::MakeEq(); } if( p.get() ){ tRetVal = new TReturn( p.get(), emptyL, emptyLUsed, nullRat, false, 1 ); } } else { ostringstream os; os << "(const_predicate_" << kind_to_str( pf[1].getKind() ); if( pf[2].getKind()==TRUE_EXPR ) os << "_t"; os << " "; print_rational( r1, os ); os << " "; print_rational( r2, os ); os << ")"; tRetVal = new TReturn( LFSCProofGeneric::MakeStr( os.str().c_str() ), emptyL, emptyLUsed, nullRat, false, 0 ); } }else{ ose << "ERROR: Could not find rational for const predicate" << std::endl; } } if( !tRetVal ) ose << "kind = " << kind_to_str( pf[1].getKind() ); } } else { //use Expr pfMod //switch( pfPat ) //{ //} if( pfPat==1 ) { ostringstream os1, os2, os3; os1 << "(ite_axiom "; os2 << " "; os3 << ")"; std::vector< string > strs; std::vector< RefPtr< LFSCProof > > pfs; strs.push_back( os1.str() ); pfs.push_back( LFSCProofExpr::Make( pf[1][0] ) ); strs.push_back( os2.str() ); pfs.push_back( LFSCProofExpr::Make( pf[1][1][1] ) ); strs.push_back( os2.str() ); pfs.push_back( LFSCProofExpr::Make( pf[1][2][1] ) ); strs.push_back( os3.str() ); RefPtr< LFSCProof > p = LFSCProofGeneric::Make( pfs, strs ); tRetVal = new TReturn( LFSCClausify::Make( pf[1], p.get() ), emptyL, emptyLUsed, nullRat, false, 3 ); }else{ ostringstream ose; ose << "WARNING: Unknown proof pattern [" << pfPat << "]"; print_error( ose.str().c_str(), cout ); //ostringstream os1; //os1 << "PROOF_PAT_" << pfPat; //tRetVal = new TReturn( LFSCProofGeneric::MakeStr( os1.str().c_str() ), emptyL, emptyLUsed, nullRat, false, 3 ); } } if( !tRetVal ){ static bool firstTime = true; if(pf.arity()>0 && (yMode!=-1 || firstTime ) ){ firstTime = false; ose << "Unknown proof rule (" << d_rules[pf[0]] << ") " << pf[0] << endl; ose << "YMode : "; if( yMode==-2 ) ose << "unknown"; else if( yMode==-1 ) ose << "fail"; else ose << yMode; ose << std::endl; if( rev_pol ) ose << "rev_pol = true" << std::endl; if( pfPat!=0 ) { ose << "proof pattern = " << pfPat << std::endl; } print_error( ose.str().c_str(), cout ); } tRetVal = new TReturn( LFSCProofGeneric::MakeUnk(), emptyL, emptyLUsed, nullRat, false, -1 ); } if( debug_conv ){ //cout << "print length = " << tRetVal->getLFSCProof()->get_string_length() << std::endl; cout << "...done " << pf[0] << " " << tRetVal->getProvesY() << std::endl; } if( debug_var ){ ostringstream os1, os2; os1 << "[" << pf[0]; if( pf[0]==d_basic_subst_op1_str || pf[0]==d_optimized_subst_op_str || pf[0]==d_basic_subst_op0_str || pf[0]==d_const_predicate_str || pf[0]==d_basic_subst_op_str ) os1 << "_" << kind_to_str( pf[1].getKind() ); if( pf[0]==d_const_predicate_str ) os1 << "_" << pf[2]; os1 << " "; os2 << "]"; std::vector< int > lv, lvUsed; tRetVal->getL( lv, lvUsed ); tRetVal = new TReturn( LFSCProofGeneric::Make( os1.str(), tRetVal->getLFSCProof(), os2.str(), true ), lv, lvUsed, tRetVal->getRational(), tRetVal->hasRational(), tRetVal->getProvesY() ); } //dont bother making small proofs into lambdas (length less than 30), or they are trivial if( !tRetVal->getLFSCProof()->isTrivial() && tRetVal->getLFSCProof()->get_string_length()>30 ) { d_th_trans[pf] = true; //if( !d_th_trans_map[cvcm][pf] && pf.isSelected() ){ // std::cout << "already selected" << std::endl; //} d_th_trans_map[cvcm][pf] = tRetVal; //pf.setSelected(); } //else if( tRetVal->getLFSCProof()->get_string_length()<=30 && getNumNodes( pf )>10 ){ // std::cout << "strange proof " << pf[0] << " " << getNumNodes( pf ) << std::endl; // tRetVal->getLFSCProof()->print( cout ); // cout << endl; //} //if( cvc3_mimic && ( tRetVal->getProvesY()==1 || tRetVal->getProvesY()==2 ) ){ // ostringstream ose; // ose << "Warning: After " << pf[0] << ", cvc_mimic, Ymode = " << tRetVal->getProvesY() << std::endl; // print_warning( ose.str().c_str() ); //} //if( tRetVal->getProvesY()==1 ){ // if( tRetVal->getLFSCProof()->checkOp()==-1 ){ // ostringstream ose; // ose << "Error: After " << pf[0] << ", check op failed. " << tRetVal->getLFSCProof()->getNumChildren() << std::endl; // ose << pf << std::endl; // tRetVal->getLFSCProof()->print_pf( ose ); // print_warning( ose.str().c_str() ); // } //} //if( tRetVal->getProvesY()==1 ){ // Expr pe; // Expr yexpr; // if( !what_is_proven( pf, pe ) || !getY( pe, yexpr ) ){ // ostringstream ose; // ose << "Warning: Bad yMode 1 formula after " << pf[0] << std::endl; // if( pe.isInitialized() ) // ose << pe << std::endl; // ose << pf << std::endl; // print_error( ose.str().c_str(), cout ); // } //} return tRetVal; } //look at the pattern of the proof, return relevant information in modE int LFSCConvert::get_proof_pattern( const Expr& pf, Expr& modE ) { if( pf[0]==d_cnf_add_unit_str ) { if( pf[2][0]==d_iff_mp_str ) { if( pf[2][3][0]==d_eq_symm_str && pf[2][4][0]==d_if_lift_rule_str ) { if( pf[2][3][4][0]==d_iff_mp_str ) { if( pf[2][3][4][3][0]==d_var_intro_str && pf[2][3][4][4][0]==d_assump_str ) { return 1; } } } } } return 0; } LFSCProof* LFSCConvert::make_let_proof( LFSCProof* p ) { if( debug_conv ) cout << "make let proof..." << std::endl; //std::map< TReturn*, bool >::iterator t_lbend = d_th_trans_lam.begin(), t_lb = d_th_trans_lam.end(); //--t_lb; if( !d_th_trans.empty() ){ //ExprMap< TReturn* >::iterator t_lb = d_th_trans.begin(), t_lbend = d_th_trans.end(); ExprMap< bool >::iterator t_lbend = d_th_trans.begin(), t_lb = d_th_trans.end(); --t_lb; while(t_lb != t_lbend){ for( int cvcm=0; cvcm<2; cvcm++ ){ if( d_th_trans_map[cvcm].find( (*t_lb).first )!= d_th_trans_map[cvcm].end() ) { TReturn* t = d_th_trans_map[cvcm][(*t_lb).first]; if( t ){ std::vector< int > lv; std::vector< int > lvUsed; #ifdef OPTIMIZE t->calcL( lv, lvUsed ); #else t->getL( lv, lvUsed ); #endif if( d_th_trans_lam[cvcm][t] ){ d_th_trans_lam[cvcm][t] = false; int lmt1 = LFSCProof::make_lambda( t->getLFSCProof() ); RefPtr< LFSCProof > pfV = LFSCPfVar::Make( "@l", lmt1 ); p = LFSCPfLet::Make( t->getLFSCProof(), (LFSCPfVar*)pfV.get(), p, t->getProvesY()!=3, lvUsed ); } } } } --t_lb; //t_lb++; } } if( debug_conv ) cout << "...done " << std::endl; return p; } TReturn* LFSCConvert::make_trusted( const Expr& pf ) { Expr e; std::vector< int > emptyL; std::vector< int > emptyLUsed; if( what_is_proven( pf, e ) ){ int valT = queryM( e, true, true ); return new TReturn( LFSCPfVar::Make( "@T", valT ), emptyL, emptyLUsed, nullRat, false, 0 ); }else{ return new TReturn( LFSCProofGeneric::MakeStr( "@T-unk" ), emptyL, emptyLUsed, nullRat, false, 0 ); } } TReturn* LFSCConvert::do_bso( const Expr& pf, bool beneath_lc, bool rev_pol, TReturn* t1, TReturn* t2, ostringstream& ose ) { std::vector< int > emptyL; std::vector< int > emptyLUsed; int yMode = -2; TReturn* tRetVal = NULL; // merge literals t1->getL( emptyL, emptyLUsed ); t2->getL( emptyL, emptyLUsed ); bool isErr = false; if( pf[1].getKind()==PLUS || pf[1].getKind()==MINUS || pf[1].getKind()==MULT || is_eq_kind( pf[1].getKind() ) ) { yMode = TReturn::normalize_tret( pf[3], t1, pf[4], t2, rev_pol ); if( yMode==1 ) { if( pf[1].getKind()==PLUS ) tRetVal = new TReturn( LFSCLraAdd::Make( t1->getLFSCProof(), t2->getLFSCProof(), EQ, EQ ), emptyL, emptyLUsed, nullRat, false, 1 ); else if( pf[1].getKind()==MINUS ) tRetVal = new TReturn( LFSCLraSub::Make( t1->getLFSCProof(), t2->getLFSCProof(), EQ, EQ ), emptyL, emptyLUsed, nullRat, false, 1 ); else if( pf[1].getKind()==MULT ){ #ifdef PRINT_MAJOR_METHODS cout << ";[M]: basic_subst_op1_* " << std::endl; #endif Rational r; if( getRat( pf[1][0], r ) ){ tRetVal = new TReturn( LFSCLraMulC::Make( t2->getLFSCProof(), r, EQ ), emptyL, emptyLUsed, nullRat, false, 1 ); }else if( getRat( pf[1][1], r ) ){ tRetVal = new TReturn( LFSCLraMulC::Make( t1->getLFSCProof(), r, EQ ), emptyL, emptyLUsed, nullRat, false, 1 ); }else{ print_error( "Could not find rational mult in basic_subst_op1", cout ); isErr = true; } }else if( is_eq_kind( pf[1].getKind() ) ){ RefPtr< LFSCProof > p; if( is_opposite( pf[1].getKind() ) ){ p = LFSCLraSub::Make( t2->getLFSCProof(), t1->getLFSCProof(), EQ, EQ ); }else{ p = LFSCLraSub::Make( t1->getLFSCProof(), t2->getLFSCProof(), EQ, EQ ); } tRetVal = new TReturn( p.get(), emptyL, emptyLUsed, nullRat, false, 1 ); } if( !tRetVal && debug_conv ){ cout << "basic_subst_op1: abort, have to normalize to 2, for " << kind_to_str( pf[1].getKind() ) << std::endl; } } } if( !tRetVal ){ if( !isErr ){ if( t1->getProvesY()==1 ){ TReturn::normalize_tr( pf[3], t1, 2, rev_pol ); } if( t2->getProvesY()==1 ){ TReturn::normalize_tr( pf[4], t2, 2, rev_pol ); } } yMode = TReturn::normalize_tret( pf[3], t1, pf[4], t2, rev_pol ); if( yMode==0 || yMode==2 ) { if( pf[1].getKind()==OR || pf[1].getKind()==AND || pf[1].getKind()==IFF || pf[1].getKind()==PLUS || is_eq_kind( pf[1].getKind() ) || pf[1].getKind()==MULT || pf[1].getKind()==MINUS ){ ostringstream os1, os2, os3; os1 << "(basic_subst_op1_"; if( yMode==2 ) os1 << "impl_"; os1 << kind_to_str( pf[1].getKind() ) << " "; os3 << " "; os2 << ")"; std::vector< string > strs; std::vector< RefPtr< LFSCProof > > pfs; strs.push_back( os1.str() ); pfs.push_back( LFSCProofExpr::Make( cascade_expr( pf[1][0] ), true ) ); strs.push_back( os3.str() ); pfs.push_back( LFSCProofExpr::Make( cascade_expr( pf[2][0] ), true ) ); strs.push_back( os3.str() ); pfs.push_back( LFSCProofExpr::Make( cascade_expr( pf[1][1] ), true ) ); strs.push_back( os3.str() ); pfs.push_back( LFSCProofExpr::Make( cascade_expr( pf[2][1] ), true ) ); strs.push_back( os3.str() ); pfs.push_back( t1->getLFSCProof() ); strs.push_back( os3.str() ); pfs.push_back( t2->getLFSCProof() ); strs.push_back( os2.str() ); tRetVal = new TReturn( LFSCProofGeneric::Make( pfs, strs ), emptyL, emptyLUsed, nullRat, false, yMode ); } } } if( !tRetVal ){ ose << pf[0] << endl; for( int a=0; a=3 ){ ose << a << ": " << pf[a][0] << std::endl; Expr pre; what_is_proven( pf[a], pre ); ose << "wip: " << pre << std::endl; }else{ ose << a << ": " << pf[a] << std::endl; } } ose << "subst kind = " << kind_to_str( pf[1].getKind() ) << std::endl; ose << "subst arity = " << pf.arity() << std::endl; } return tRetVal; } cvc3-2.4.1/src/search/Object.h0000664000175400017540000000505711363704204015700 0ustar mdetersmdeters#ifndef OBJ_H_ #define OBJ_H_ #include "theory_core.h" #include "theorem_manager.h" #include "common_proof_rules.h" #include "command_line_flags.h" #include "theory_arith.h" #include #define _CVC3_TRUSTED_ using namespace std; using namespace CVC3; //#define DEBUG_MEM_STATS // flag for testing some cvc3 custom made prof rules //#define PRINT_MAJOR_METHODS //#define LRA2_PRIME //#define OPTIMIZE //#define IGNORE_NORMALIZE //#define IGNORE_LETPF_VARS //#define IGNORE_PRINT_MULTI_LAMBDA //smart pointer class template class RefPtr { public: typedef T element_type; RefPtr() :_ptr(0L) {} RefPtr(T* t):_ptr(t) { if (_ptr) _ptr->Ref(); } RefPtr(const RefPtr& rp):_ptr(rp._ptr) { if (_ptr) _ptr->Ref(); } ~RefPtr() { if (_ptr) _ptr->Unref(); _ptr=0; } inline RefPtr& operator = (const RefPtr& rp){ if (_ptr==rp._ptr) return *this; T* tmp_ptr = _ptr; _ptr = rp._ptr; if (_ptr) _ptr->Ref(); if (tmp_ptr) tmp_ptr->Unref(); return *this; } inline RefPtr& operator = (T* ptr){ if (_ptr==ptr) return *this; T* tmp_ptr = _ptr; _ptr = ptr; if (_ptr) _ptr->Ref(); if (tmp_ptr) tmp_ptr->Unref(); return *this; } inline T& operator*() { return *_ptr; } inline const T& operator*() const { return *_ptr; } inline T* operator->() { return _ptr; } inline const T* operator->() const { return _ptr; } inline T* get() { return _ptr; } inline const T* get() const { return _ptr; } private: T* _ptr; }; //standard (reference pointer) object class Obj { protected: ostringstream oignore; int refCount; static bool errsInit; static ofstream errs; static bool indentFlag; void indent( std::ostream& s, int ind = 0 ){ if( ind>0 ) s << endl; if( indentFlag ){ for( int a=0; a * * License to use, copy, modify, sell and/or distribute this software * and its documentation for any purpose is hereby granted without * royalty, subject to the terms and conditions defined in the \ref * LICENSE file provided with this distribution. * *
*/ /*****************************************************************************/ #include "search_sat.h" #ifdef DPLL_BASIC #include "dpllt_basic.h" #endif #include "dpllt_minisat.h" #include "theory_core.h" #include "eval_exception.h" #include "typecheck_exception.h" #include "expr_transform.h" #include "search_rules.h" #include "command_line_flags.h" #include "theorem_manager.h" #include "theory.h" #include "debug.h" using namespace std; using namespace CVC3; using namespace SAT; namespace CVC3 { class SearchSatCoreSatAPI :public TheoryCore::CoreSatAPI { SearchSat* d_ss; public: SearchSatCoreSatAPI(SearchSat* ss) : d_ss(ss) {} ~SearchSatCoreSatAPI() {} void addLemma(const Theorem& thm, int priority, bool atBottomScope) { d_ss->addLemma(thm, priority, atBottomScope); } Theorem addAssumption(const Expr& assump) { return d_ss->newUserAssumption(assump); } void addSplitter(const Expr& e, int priority) { d_ss->addSplitter(e, priority); } bool check(const Expr& e); }; bool SearchSatCoreSatAPI::check(const Expr& e) { Theorem thm; d_ss->push(); QueryResult res = d_ss->check(e, thm); d_ss->pop(); return res == VALID; } class SearchSatTheoryAPI :public DPLLT::TheoryAPI { ContextManager* d_cm; SearchSat* d_ss; public: SearchSatTheoryAPI(SearchSat* ss) : d_cm(ss->theoryCore()->getCM()), d_ss(ss) {} ~SearchSatTheoryAPI() {} void push() { return d_cm->push(); } void pop() { return d_cm->pop(); } void assertLit(Lit l) { d_ss->assertLit(l); } SAT::DPLLT::ConsistentResult checkConsistent(CNF_Formula& cnf, bool fullEffort) { return d_ss->checkConsistent(cnf, fullEffort); } bool outOfResources() { return d_ss->theoryCore()->outOfResources(); } Lit getImplication() { return d_ss->getImplication(); } void getExplanation(Lit l, CNF_Formula& cnf) { return d_ss->getExplanation(l, cnf); } bool getNewClauses(CNF_Formula& cnf) { return d_ss->getNewClauses(cnf); } }; class SearchSatDecider :public DPLLT::Decider { SearchSat* d_ss; public: SearchSatDecider(SearchSat* ss) : d_ss(ss) {} ~SearchSatDecider() {} Lit makeDecision() { return d_ss->makeDecision(); } }; class SearchSatCNFCallback :public CNF_Manager::CNFCallback { SearchSat* d_ss; public: SearchSatCNFCallback(SearchSat* ss) : d_ss(ss) {} ~SearchSatCNFCallback() {} void registerAtom(const Expr& e, const Theorem& thm) { d_ss->theoryCore()->theoryOf(e)->registerAtom(e, thm); } }; } void SearchSat::restorePre() { if (d_core->getCM()->scopeLevel() == d_bottomScope) { DebugAssert(d_prioritySetBottomEntriesSizeStack.size() > 0, "Expected non-empty stack"); d_prioritySetBottomEntriesSize = d_prioritySetBottomEntriesSizeStack.back(); d_prioritySetBottomEntriesSizeStack.pop_back(); while (d_prioritySetBottomEntriesSize < d_prioritySetBottomEntries.size()) { d_prioritySet.erase(d_prioritySetBottomEntries.back()); d_prioritySetBottomEntries.pop_back(); } } } void SearchSat::restore() { while (d_prioritySetEntriesSize < d_prioritySetEntries.size()) { d_prioritySet.erase(d_prioritySetEntries.back()); d_prioritySetEntries.pop_back(); } while (d_pendingLemmasSize < d_pendingLemmas.size()) { d_pendingLemmas.pop_back(); d_pendingScopes.pop_back(); } while (d_varsUndoListSize < d_varsUndoList.size()) { d_vars[d_varsUndoList.back()] = SAT::Var::UNKNOWN; d_varsUndoList.pop_back(); } } bool SearchSat::recordNewRootLit(Lit lit, int priority, bool atBottomScope) { DebugAssert(d_prioritySetEntriesSize == d_prioritySetEntries.size() && d_prioritySetBottomEntriesSize == d_prioritySetBottomEntries.size(), "Size mismatch"); pair::iterator,bool> status = d_prioritySet.insert(LitPriorityPair(lit, priority)); if (!status.second) return false; if (!atBottomScope || d_bottomScope == d_core->getCM()->scopeLevel()) { d_prioritySetEntries.push_back(status.first); d_prioritySetEntriesSize = d_prioritySetEntriesSize + 1; } else { d_prioritySetBottomEntries.push_back(status.first); ++d_prioritySetBottomEntriesSize; } if (d_prioritySetStart.get() == d_prioritySet.end() || ((*status.first) < (*(d_prioritySetStart.get())))) d_prioritySetStart = status.first; return true; } void SearchSat::addLemma(const Theorem& thm, int priority, bool atBottomScope) { IF_DEBUG( string indentStr(theoryCore()->getCM()->scopeLevel(), ' '); TRACE("addLemma", indentStr, "AddLemma: ", thm.getExpr().toString(PRESENTATION_LANG)); ) // DebugAssert(!thm.getExpr().isAbsLiteral(), "Expected non-literal"); DebugAssert(d_pendingLemmasSize == d_pendingLemmas.size(), "Size mismatch"); DebugAssert(d_pendingLemmasSize == d_pendingScopes.size(), "Size mismatch"); DebugAssert(d_pendingLemmasNext <= d_pendingLemmas.size(), "Size mismatch"); d_pendingLemmas.push_back(pair(thm, priority)); d_pendingScopes.push_back(atBottomScope); d_pendingLemmasSize = d_pendingLemmasSize + 1; } void SearchSat::addSplitter(const Expr& e, int priority) { DebugAssert(!e.isEq() || e[0] != e[1], "Expected non-trivial splitter"); addLemma(d_commonRules->excludedMiddle(e), priority); } void SearchSat::assertLit(Lit l) { // DebugAssert(d_inCheckSat, "Should only be used as a call-back"); Expr e = d_cnfManager->concreteLit(l); IF_DEBUG( string indentStr(theoryCore()->getCM()->scopeLevel(), ' '); string val = " := "; std::stringstream ss; ss<getCM()->scopeLevel(); std::string temp; ss>>temp; if (l.isPositive()) val += "1"; else val += "0"; TRACE("assertLit", "", "", ""); TRACE("assertLitScope", indentStr, "Scope level = ", temp); TRACE("assertLit", indentStr, l.getVar(), val+": "+e.toString()); ) //======= // IF_DEBUG( // string indentStr(theoryCore()->getCM()->scopeLevel(), ' '); // string val = " := "; // if (l.isPositive()) val += "1"; else val += "0"; // TRACE("assertLit", indentStr, l.getVar(), val); // ) // This can happen if the SAT solver propagates a learned unit clause from a p bool isSATLemma = false; if (e.isNull()) { e = d_cnfManager->concreteLit(l, false); DebugAssert(!e.isNull(), "Expected known expr"); isSATLemma = true; TRACE("quant-level", "found null expr ",e, ""); } DebugAssert(!e.isNull(), "Expected known expr"); DebugAssert(!e.isIntAssumption() || getValue(l) == SAT::Var::TRUE_VAL, "internal assumptions should be true"); // This happens if the SAT solver has been restarted--it re-asserts its old assumptions if (e.isIntAssumption()) return; if (getValue(l) == SAT::Var::UNKNOWN) { setValue(l.getVar(), l.isPositive() ? Var::TRUE_VAL : Var::FALSE_VAL); } else { DebugAssert(!e.isAbsLiteral(), "invariant violated"); DebugAssert(getValue(l) == Var::TRUE_VAL, "invariant violated"); return; } if (!e.isAbsLiteral()) return; e.setIntAssumption(); Theorem thm = d_commonRules->assumpRule(e); if (isSATLemma) { CNF_Formula_Impl cnf; d_cnfManager->addAssumption(thm, cnf); } thm.setQuantLevel(theoryCore()->getQuantLevelForTerm(e.isNot() ? e[0] : e)); d_intAssumptions.push_back(thm); d_core->addFact(thm); } SAT::DPLLT::ConsistentResult SearchSat::checkConsistent(SAT::CNF_Formula& cnf, bool fullEffort) { DebugAssert(d_inCheckSat, "Should only be used as a call-back"); if (d_core->inconsistent()) { d_cnfManager->convertLemma(d_core->inconsistentThm(), cnf); if (d_cnfManager->numVars() > d_vars.size()) { d_vars.resize(d_cnfManager->numVars(), SAT::Var::UNKNOWN); } return DPLLT::INCONSISTENT; } if (fullEffort) { if (d_core->checkSATCore() && d_pendingLemmasNext == d_pendingLemmas.size() && d_lemmasNext == d_lemmas.numClauses()) { if (d_core->inconsistent()) { d_cnfManager->convertLemma(d_core->inconsistentThm(), cnf); if (d_cnfManager->numVars() > d_vars.size()) { d_vars.resize(d_cnfManager->numVars(), SAT::Var::UNKNOWN); } return DPLLT::INCONSISTENT; } else return DPLLT::CONSISTENT; } } return DPLLT::MAYBE_CONSISTENT; } Lit SearchSat::getImplication() { // DebugAssert(d_inCheckSat, "Should only be used as a call-back"); Lit l; Theorem imp = d_core->getImpliedLiteral(); while (!imp.isNull()) { l = d_cnfManager->getCNFLit(imp.getExpr()); DebugAssert(!l.isNull() || imp.getExpr().unnegate().isUserRegisteredAtom(), "implied literals should be registered by cnf or by user"); if (!l.isNull() && getValue(l) != Var::TRUE_VAL) { d_theorems.insert(imp.getExpr(), imp); break; } l.reset(); imp = d_core->getImpliedLiteral(); } return l; } void SearchSat::getExplanation(Lit l, SAT::CNF_Formula& cnf) { // DebugAssert(d_inCheckSat, "Should only be used as a call-back"); DebugAssert(cnf.empty(), "Expected empty cnf"); Expr e = d_cnfManager->concreteLit(l); CDMap::iterator i = d_theorems.find(e); DebugAssert(i != d_theorems.end(), "getExplanation: no explanation found"); d_cnfManager->convertLemma((*i).second, cnf); if (d_cnfManager->numVars() > d_vars.size()) { d_vars.resize(d_cnfManager->numVars(), SAT::Var::UNKNOWN); } } bool SearchSat::getNewClauses(CNF_Formula& cnf) { unsigned i; Lit l; for (i = d_pendingLemmasNext; i < d_pendingLemmas.size(); ++i) { l = d_cnfManager->addLemma(d_pendingLemmas[i].first, d_lemmas); if (!recordNewRootLit(l, d_pendingLemmas[i].second, d_pendingScopes[i])) { // Already have this lemma: delete it d_lemmas.deleteLast(); } } d_pendingLemmasNext = d_pendingLemmas.size(); if (d_cnfManager->numVars() > d_vars.size()) { d_vars.resize(d_cnfManager->numVars(), SAT::Var::UNKNOWN); } DebugAssert(d_lemmasNext <= d_lemmas.numClauses(), ""); if (d_lemmasNext == d_lemmas.numClauses()) return false; do { cnf += d_lemmas[d_lemmasNext]; d_lemmasNext = d_lemmasNext + 1; } while (d_lemmasNext < d_lemmas.numClauses()); return true; } Lit SearchSat::makeDecision() { DebugAssert(d_inCheckSat, "Should only be used as a call-back"); Lit litDecision; set::const_iterator i, iend; Lit lit; for (i = d_prioritySetStart, iend = d_prioritySet.end(); i != iend; ++i) { lit = (*i).getLit(); if (findSplitterRec(lit, getValue(lit), &litDecision)) { break; } } d_prioritySetStart = i; return litDecision; } bool SearchSat::findSplitterRec(Lit lit, Var::Val value, Lit* litDecision) { if (lit.isFalse() || lit.isTrue()) return false; unsigned i, n; Lit litTmp; Var varTmp; bool ret; Var v = lit.getVar(); DebugAssert(value != Var::UNKNOWN, "expected known value"); DebugAssert(getValue(lit) == value || getValue(lit) == Var::UNKNOWN, "invariant violated"); if (checkJustified(v)) return false; if (lit.isInverted()) { value = Var::invertValue(value); } if (d_cnfManager->numFanins(v) == 0) { if (getValue(v) != Var::UNKNOWN) { setJustified(v); return false; } else { *litDecision = Lit(v, value == Var::TRUE_VAL); return true; } } else if (d_cnfManager->concreteVar(v).isAbsAtomicFormula()) { // This node represents a predicate with embedded ITE's // We handle this case specially in order to catch the // corner case when a variable is in its own fanin. n = d_cnfManager->numFanins(v); for (i=0; i < n; ++i) { litTmp = d_cnfManager->getFanin(v, i); varTmp = litTmp.getVar(); DebugAssert(!litTmp.isInverted(),"Expected positive fanin"); if (checkJustified(varTmp)) continue; DebugAssert(d_cnfManager->concreteVar(varTmp).getKind() == ITE, "Expected ITE"); DebugAssert(getValue(varTmp) == Var::TRUE_VAL,"Expected TRUE"); Lit cIf = d_cnfManager->getFanin(varTmp,0); Lit cThen = d_cnfManager->getFanin(varTmp,1); Lit cElse = d_cnfManager->getFanin(varTmp,2); if (getValue(cIf) == Var::UNKNOWN) { if (getValue(cElse) == Var::TRUE_VAL || getValue(cThen) == Var::FALSE_VAL) { ret = findSplitterRec(cIf, Var::FALSE_VAL, litDecision); } else { ret = findSplitterRec(cIf, Var::TRUE_VAL, litDecision); } if (!ret) { cout << d_cnfManager->concreteVar(cIf.getVar()) << endl; DebugAssert(false,"No controlling input found (1)"); } return true; } else if (getValue(cIf) == Var::TRUE_VAL) { if (findSplitterRec(cIf, Var::TRUE_VAL, litDecision)) { return true; } if (cThen.getVar() != v && (getValue(cThen) == Var::UNKNOWN || getValue(cThen) == Var::TRUE_VAL) && findSplitterRec(cThen, Var::TRUE_VAL, litDecision)) { return true; } } else { if (findSplitterRec(cIf, Var::FALSE_VAL, litDecision)) { return true; } if (cElse.getVar() != v && (getValue(cElse) == Var::UNKNOWN || getValue(cElse) == Var::TRUE_VAL) && findSplitterRec(cElse, Var::TRUE_VAL, litDecision)) { return true; } } setJustified(varTmp); } if (getValue(v) != Var::UNKNOWN) { setJustified(v); return false; } else { *litDecision = Lit(v, value == Var::TRUE_VAL); return true; } } int kind = d_cnfManager->concreteVar(v).getKind(); Var::Val valHard = Var::FALSE_VAL; switch (kind) { case AND: valHard = Var::TRUE_VAL; case OR: if (value == valHard) { n = d_cnfManager->numFanins(v); for (i=0; i < n; ++i) { litTmp = d_cnfManager->getFanin(v, i); if (findSplitterRec(litTmp, valHard, litDecision)) { return true; } } DebugAssert(getValue(v) == valHard, "Output should be justified"); setJustified(v); return false; } else { Var::Val valEasy = Var::invertValue(valHard); n = d_cnfManager->numFanins(v); for (i=0; i < n; ++i) { litTmp = d_cnfManager->getFanin(v, i); if (getValue(litTmp) != valHard) { if (findSplitterRec(litTmp, valEasy, litDecision)) { return true; } DebugAssert(getValue(v) == valEasy, "Output should be justified"); setJustified(v); return false; } } DebugAssert(false, "No controlling input found (2)"); } break; case IMPLIES: DebugAssert(d_cnfManager->numFanins(v) == 2, "Expected 2 fanins"); if (value == Var::FALSE_VAL) { litTmp = d_cnfManager->getFanin(v, 0); if (findSplitterRec(litTmp, Var::TRUE_VAL, litDecision)) { return true; } litTmp = d_cnfManager->getFanin(v, 1); if (findSplitterRec(litTmp, Var::FALSE_VAL, litDecision)) { return true; } DebugAssert(getValue(v) == Var::FALSE_VAL, "Output should be justified"); setJustified(v); return false; } else { litTmp = d_cnfManager->getFanin(v, 0); if (getValue(litTmp) != Var::TRUE_VAL) { if (findSplitterRec(litTmp, Var::FALSE_VAL, litDecision)) { return true; } DebugAssert(getValue(v) == Var::TRUE_VAL, "Output should be justified"); setJustified(v); return false; } litTmp = d_cnfManager->getFanin(v, 1); if (getValue(litTmp) != Var::FALSE_VAL) { if (findSplitterRec(litTmp, Var::TRUE_VAL, litDecision)) { return true; } DebugAssert(getValue(v) == Var::TRUE_VAL, "Output should be justified"); setJustified(v); return false; } DebugAssert(false, "No controlling input found (3)"); } break; case IFF: { litTmp = d_cnfManager->getFanin(v, 0); Var::Val val = getValue(litTmp); if (val != Var::UNKNOWN) { if (findSplitterRec(litTmp, val, litDecision)) { return true; } if (value == Var::FALSE_VAL) val = Var::invertValue(val); litTmp = d_cnfManager->getFanin(v, 1); if (findSplitterRec(litTmp, val, litDecision)) { return true; } DebugAssert(getValue(v) == value, "Output should be justified"); setJustified(v); return false; } else { val = getValue(d_cnfManager->getFanin(v, 1)); if (val == Var::UNKNOWN) val = Var::FALSE_VAL; if (value == Var::FALSE_VAL) val = Var::invertValue(val); if (findSplitterRec(litTmp, val, litDecision)) { return true; } DebugAssert(false, "Unable to find controlling input (4)"); } break; } case XOR: { litTmp = d_cnfManager->getFanin(v, 0); Var::Val val = getValue(litTmp); if (val != Var::UNKNOWN) { if (findSplitterRec(litTmp, val, litDecision)) { return true; } if (value == Var::TRUE_VAL) val = Var::invertValue(val); litTmp = d_cnfManager->getFanin(v, 1); if (findSplitterRec(litTmp, val, litDecision)) { return true; } DebugAssert(getValue(v) == value, "Output should be justified"); setJustified(v); return false; } else { val = getValue(d_cnfManager->getFanin(v, 1)); if (val == Var::UNKNOWN) val = Var::FALSE_VAL; if (value == Var::TRUE_VAL) val = Var::invertValue(val); if (findSplitterRec(litTmp, val, litDecision)) { return true; } DebugAssert(false, "Unable to find controlling input (5)"); } break; } case ITE: { Lit cIf = d_cnfManager->getFanin(v, 0); Lit cThen = d_cnfManager->getFanin(v, 1); Lit cElse = d_cnfManager->getFanin(v, 2); if (getValue(cIf) == Var::UNKNOWN) { if (getValue(cElse) == value || getValue(cThen) == Var::invertValue(value)) { ret = findSplitterRec(cIf, Var::FALSE_VAL, litDecision); } else { ret = findSplitterRec(cIf, Var::TRUE_VAL, litDecision); } if (!ret) { cout << d_cnfManager->concreteVar(cIf.getVar()) << endl; DebugAssert(false,"No controlling input found (6)"); } return true; } else if (getValue(cIf) == Var::TRUE_VAL) { if (findSplitterRec(cIf, Var::TRUE_VAL, litDecision)) { return true; } if (cThen.isVar() && cThen.getVar() != v && (getValue(cThen) == Var::UNKNOWN || getValue(cThen) == value) && findSplitterRec(cThen, value, litDecision)) { return true; } } else { if (findSplitterRec(cIf, Var::FALSE_VAL, litDecision)) { return true; } if (cElse.isVar() && cElse.getVar() != v && (getValue(cElse) == Var::UNKNOWN || getValue(cElse) == value) && findSplitterRec(cElse, value, litDecision)) { return true; } } DebugAssert(getValue(v) == value, "Output should be justified"); setJustified(v); return false; } default: DebugAssert(false, "Unexpected Boolean operator"); break; } FatalAssert(false, "Should be unreachable"); return false; } QueryResult SearchSat::check(const Expr& e, Theorem& result, bool isRestart) { DebugAssert(d_dplltReady, "SAT solver is not ready"); if (isRestart && d_lastCheck.get().isNull()) { throw Exception ("restart called without former call to checkValid"); } DebugAssert(!d_inCheckSat, "checkValid should not be called recursively"); TRACE("searchsat", "checkValid: ", e, ""); if (!e.getType().isBool()) throw TypecheckException ("checking validity of a non-Boolean expression:\n\n " + e.toString() + "\n\nwhich has the following type:\n\n " + e.getType().toString()); Expr e2 = e; // Set up and quick exits if (isRestart) { while (e2.isNot() && e2[0].isNot()) e2 = e2[0][0]; if (e2.isTrue() || (e2.isNot() && e2[0].isFalse())) { result = d_lastValid; return INVALID; } if (e2.isFalse() || (e2.isNot() && e2[0].isTrue())) { pop(); //TODO: real theorem d_lastValid = d_commonRules->assumpRule(d_lastCheck); result = d_lastValid; return VALID; } } else { if (e.isTrue()) { d_lastValid = d_commonRules->trueTheorem(); result = d_lastValid; return VALID; } push(); d_bottomScope = d_core->getCM()->scopeLevel(); d_prioritySetBottomEntriesSizeStack.push_back(d_prioritySetBottomEntriesSize); d_lastCheck = e; e2 = !e; } Theorem thm; CNF_Formula_Impl cnf; QueryResult qres; d_cnfManager->setBottomScope(d_bottomScope); d_dplltReady = false; newUserAssumptionInt(e2, cnf, true); d_inCheckSat = true; getNewClauses(cnf); if (!isRestart && d_core->inconsistent()) { qres = UNSATISFIABLE; thm = d_rules->proofByContradiction(e, d_core->inconsistentThm()); pop(); d_lastValid = thm; d_cnfManager->setBottomScope(-1); d_inCheckSat = false; result = d_lastValid; return qres; } else { // Run DPLLT engine qres = isRestart ? d_dpllt->continueCheck(cnf) : d_dpllt->checkSat(cnf); } if (qres == UNSATISFIABLE) { DebugAssert(d_core->getCM()->scopeLevel() == d_bottomScope, "Expected unchanged context after unsat"); e2 = d_lastCheck; pop(); if (d_core->getTM()->withProof()) { Proof pf = d_dpllt->getSatProof(d_cnfManager, d_core); // std::cout<<"WITH PROOF:"<satProof(e2, pf); } else { d_lastValid = d_commonRules->assumpRule(d_lastCheck); } } else { DebugAssert(d_lemmasNext == d_lemmas.numClauses(), "Expected no lemmas after satisfiable check"); d_dplltReady = true; d_lastValid = Theorem(); if (qres == SATISFIABLE && d_core->incomplete()) qres = UNKNOWN; #ifdef _CVC3_DEBUG_MODE if( CVC3::debugger.trace("quant debug") ){ d_core->theoryOf(FORALL)->debug(1); } if( CVC3::debugger.trace("sat model unknown") ){ std::vector cur_assigns = d_dpllt->getCurAssignments(); cout<<"Current assignments"<concreteLit(l); string val = " := "; if (l.isPositive()) val += "1"; else val += "0"; cout< > cur_clauses = d_dpllt->getCurClauses(); cout<<"Current Clauses"<& allterms = d_core->getTerms(); cout<<"===========terms begin=========="<simplifyExpr(allterms[i])<<"|"<simplifyExpr(allterms[i])<<"|"<getKindName(allterms[i].getKind())<& allpreds = d_core->getPredicates(); cout<<"===========pred begin=========="<findExpr(allpreds[i])).isTrue()){ cout<<"ASSERT "<< allpreds[i] <<";" <findExpr(allpreds[i])<<"|"<getKindName(allpreds[i].getKind())<& allpreds = d_core->getPredicates(); for (size_t i=0; ifindExpr(allpreds[i])<<"|"<& allpreds = d_core->getPredicates(); for (size_t i=0; ifindExpr(allpreds[i])<<"|"<& allpreds = d_core->getPredicates(); cout<<"===========pred begin=========="<findExpr(allpreds[i])).isTrue()){ cout<<":assumption "<< allpreds[i] <<"" <findExpr(allpreds[i])<<"|"<getKindName(allpreds[i].getKind())<& allpreds = d_core->getPredicates(); cout<<"===========pred begin=========="<findExpr(allpreds[i])).isTrue()){ // if(cur.isExists()){ // continue; // } cout<<"ASSERT "<< allpreds[i] <<";" <findExpr(allpreds[i])).isFalse()){ // if (cur.isForall()){ // continue; // } cout<<"ASSERT (NOT "<< allpreds[i] <<");" <findExpr(allpreds[i])<<"|"<getKindName(allpreds[i].getKind())<setBottomScope(-1); d_inCheckSat = false; result = d_lastValid; return qres; } SearchSat::SearchSat(TheoryCore* core, const string& name) : SearchEngine(core), d_name(name), d_bottomScope(core->getCM()->getCurrentContext(), -1), d_lastCheck(core->getCM()->getCurrentContext()), d_lastValid(core->getCM()->getCurrentContext(), d_commonRules->trueTheorem()), d_userAssumptions(core->getCM()->getCurrentContext()), d_intAssumptions(core->getCM()->getCurrentContext()), d_idxUserAssump(core->getCM()->getCurrentContext(), 0), d_decider(NULL), d_theorems(core->getCM()->getCurrentContext()), d_inCheckSat(false), d_lemmas(core->getCM()->getCurrentContext()), d_pendingLemmasSize(core->getCM()->getCurrentContext(), 0), d_pendingLemmasNext(core->getCM()->getCurrentContext(), 0), d_lemmasNext(core->getCM()->getCurrentContext(), 0), d_varsUndoListSize(core->getCM()->getCurrentContext(), 0), d_prioritySetStart(core->getCM()->getCurrentContext()), d_prioritySetEntriesSize(core->getCM()->getCurrentContext(), 0), d_prioritySetBottomEntriesSize(0), d_lastRegisteredVar(core->getCM()->getCurrentContext(), 0), d_dplltReady(core->getCM()->getCurrentContext(), true), d_nextImpliedLiteral(core->getCM()->getCurrentContext(), 0), d_restorer(core->getCM()->getCurrentContext(), this) { d_cnfManager = new CNF_Manager(core->getTM(), core->getStatistics(), core->getFlags()); d_cnfCallback = new SearchSatCNFCallback(this); d_cnfManager->registerCNFCallback(d_cnfCallback); d_coreSatAPI = new SearchSatCoreSatAPI(this); core->registerCoreSatAPI(d_coreSatAPI); d_theoryAPI = new SearchSatTheoryAPI(this); if (core->getFlags()["de"].getString() == "dfs") d_decider = new SearchSatDecider(this); if (core->getFlags()["sat"].getString() == "sat") { #ifdef DPLL_BASIC d_dpllt = new DPLLTBasic(d_theoryAPI, d_decider, core->getCM(), core->getFlags()["stats"].getBool()); #else throw CLException("SAT solver 'sat' not supported in this build"); #endif } else if (core->getFlags()["sat"].getString() == "minisat") { d_dpllt = new DPLLTMiniSat(d_theoryAPI, d_decider, core->getFlags()["stats"].getBool(), core->getTM()->withProof()); } else { throw CLException("Unrecognized SAT solver name: " + (core->getFlags()["sat"].getString())); } d_prioritySetStart = d_prioritySet.end(); } SearchSat::~SearchSat() { delete d_dpllt; delete d_decider; delete d_theoryAPI; delete d_coreSatAPI; delete d_cnfCallback; delete d_cnfManager; } void SearchSat::registerAtom(const Expr& e) { e.setUserRegisteredAtom(); if (!e.isRegisteredAtom()) d_core->registerAtom(e, Theorem()); } Theorem SearchSat::getImpliedLiteral(void) { Theorem imp; while (d_nextImpliedLiteral < d_core->numImpliedLiterals()) { imp = d_core->getImpliedLiteralByIndex(d_nextImpliedLiteral); d_nextImpliedLiteral = d_nextImpliedLiteral + 1; if (imp.getExpr().unnegate().isUserRegisteredAtom()) return imp; } return Theorem(); } void SearchSat::returnFromCheck() { if (d_bottomScope < 0) { throw Exception ("returnFromCheck called with no previous invalid call to checkValid"); } pop(); } static void setRecursiveInUserAssumption(const Expr& e, int scope) { if (e.inUserAssumption()) return; for (int i = 0; i < e.arity(); ++i) { setRecursiveInUserAssumption(e[i], scope); } e.setInUserAssumption(scope); } void SearchSat::newUserAssumptionIntHelper(const Theorem& thm, CNF_Formula_Impl& cnf, bool atBottomScope) { Expr e = thm.getExpr(); if (e.isAnd()) { for (int i = 0; i < e.arity(); ++i) { newUserAssumptionIntHelper(d_commonRules->andElim(thm, i), cnf, atBottomScope); } } else { if ( ! d_core->getFlags()["cnf-formula"].getBool()) { if (!recordNewRootLit(d_cnfManager->addAssumption(thm, cnf), 0, atBottomScope)) { cnf.deleteLast(); } } else{ d_cnfManager->addAssumption(thm, cnf); } // if cnf-formula is enabled, d_cnfManager->addAssumption returns a random literal, not a RootLit. A random lit can make recordNewRootLit return false, which in turn makes cnf.deleteLast() to delete the last clause, which is not correct. } } Theorem SearchSat::newUserAssumptionInt(const Expr& e, CNF_Formula_Impl& cnf, bool atBottomScope) { DebugAssert(!d_inCheckSat, "User assumptions should be added before calling checkSat"); Theorem thm; int scope; if (atBottomScope) scope = d_bottomScope; else scope = -1; setRecursiveInUserAssumption(e, scope); if (!isAssumption(e)) { e.setUserAssumption(scope); thm = d_commonRules->assumpRule(e, scope); d_userAssumptions.push_back(thm, scope); if (atBottomScope && d_bottomScope != d_core->getCM()->scopeLevel()) { //TODO: run preprocessor without using context-dependent information //TODO: this will break if we have stuff like the BVDIV rewrite that needs to get enqueued during preprocessing newUserAssumptionIntHelper(thm, cnf, true); } else { Theorem thm2 = d_core->getExprTrans()->preprocess(thm); Expr e2 = thm2.getExpr(); if (e2.isFalse()) { d_core->addFact(thm2); return thm; } else if (!e2.isTrue()) { newUserAssumptionIntHelper(thm2, cnf, false); } } if (d_cnfManager->numVars() > d_vars.size()) { d_vars.resize(d_cnfManager->numVars(), SAT::Var::UNKNOWN); } } return thm; } Theorem SearchSat::newUserAssumption(const Expr& e) { CNF_Formula_Impl cnf; Theorem thm = newUserAssumptionInt(e, cnf, false); d_dpllt->addAssertion(cnf); return thm; } void SearchSat::getUserAssumptions(vector& assumptions) { for(CDList::const_iterator i=d_userAssumptions.begin(), iend=d_userAssumptions.end(); i!=iend; ++i) assumptions.push_back((*i).getExpr()); } void SearchSat::getInternalAssumptions(vector& assumptions) { for(CDList::const_iterator i=d_intAssumptions.begin(), iend=d_intAssumptions.end(); i!=iend; ++i) assumptions.push_back((*i).getExpr()); } void SearchSat::getAssumptions(vector& assumptions) { CDList::const_iterator iU=d_userAssumptions.begin(), iUend=d_userAssumptions.end(), iI = d_intAssumptions.begin(), iIend=d_intAssumptions.end(); while (true) { if (iI == iIend) { if (iU == iUend) break; assumptions.push_back((*iU).getExpr()); ++iU; } else if (iU == iUend) { Expr intAssump = (*iI).getExpr(); if (!intAssump.isUserAssumption()) { assumptions.push_back(intAssump); } ++iI; } else { if ((*iI).getScope() <= (*iU).getScope()) { Expr intAssump = (*iI).getExpr(); if (!intAssump.isUserAssumption()) { assumptions.push_back(intAssump); } ++iI; } else { assumptions.push_back((*iU).getExpr()); ++iU; } } } } bool SearchSat::isAssumption(const Expr& e) { return e.isUserAssumption() || e.isIntAssumption(); } void SearchSat::getCounterExample(vector& assumptions, bool inOrder) { if (!d_lastValid.get().isNull()) { throw Exception("Expected last query to be invalid"); } getInternalAssumptions(assumptions); } Proof SearchSat::getProof() { if(!d_core->getTM()->withProof()) throw EvalException ("getProof cannot be called without proofs activated"); if(d_lastValid.get().isNull()) throw EvalException ("getProof must be called only after a successful check"); if(d_lastValid.get().isNull()) return Proof(); else return d_lastValid.get().getProof(); } cvc3-2.4.1/src/search/search_theorem_producer.h0000664000175400017540000001513011345602014021352 0ustar mdetersmdeters/*****************************************************************************/ /*! * \file search_theorem_producer.h * \brief Implementation API to proof rules for the simple search engine * * Author: Sergey Berezin * * Created: Mon Feb 24 14:48:03 2003 * *
* * License to use, copy, modify, sell and/or distribute this software * and its documentation for any purpose is hereby granted without * royalty, subject to the terms and conditions defined in the \ref * LICENSE file provided with this distribution. * *
* */ /*****************************************************************************/ #ifndef _cvc3__search__search_theorem_producer_h_ #define _cvc3__search__search_theorem_producer_h_ #include "theorem_producer.h" #include "search_rules.h" namespace CVC3 { class CommonProofRules; class SearchEngineTheoremProducer : public SearchEngineRules, public TheoremProducer { private: CommonProofRules* d_commonRules; void verifyConflict(const Theorem& thm, TheoremMap& m); void checkSoundNoSkolems(const Expr& e, ExprMap& visited, const ExprMap& skolems); void checkSoundNoSkolems(const Theorem& t, ExprMap& visited, const ExprMap& skolems); public: SearchEngineTheoremProducer(TheoremManager* tm); // Destructor virtual ~SearchEngineTheoremProducer() { } // Proof by contradiction: !A |- FALSE ==> |- A. "!A" doesn't // have to be present in the assumptions. virtual Theorem proofByContradiction(const Expr& a, const Theorem& pfFalse); // Similar rule, only negation introduction: // A |- FALSE ==> !A virtual Theorem negIntro(const Expr& not_a, const Theorem& pfFalse); // Case split: u1:A |- C, u2:!A |- C ==> |- C virtual Theorem caseSplit(const Expr& a, const Theorem& a_proves_c, const Theorem& not_a_proves_c); /*! Eliminate skolem axioms: * Gamma, Delta |- false => Gamma|- false * where Delta is a set of skolem axioms {|-Exists(x) phi (x) => phi(c)} * and gamma does not contain any of the skolem constants c. */ virtual Theorem eliminateSkolemAxioms(const Theorem& tFalse, const std::vector& delta); // Conflict clause rule: // Gamma, A_1,...,A_n |- B ==> Gamma |- (OR B !A_1 ... !A_n) // The assumptions A_i are given by the vector 'lits'. // If B==FALSE, it is omitted from the result. // NOTE: here "!A_i" means an inverse of A_i, not just a negation. // That is, if A_i is NOT C, then !A_i is C. // NOTE: Theorems with same expressions must // be eliminated before passing as lits. virtual Theorem conflictClause(const Theorem& thm, const std::vector& lits, const std::vector& gamma); // "Cut" rule: { G_i |- A_i }; G', { A_i } |- B ==> union(G_i)+G' |- B. virtual Theorem cutRule(const std::vector& thmsA, const Theorem& as_prove_b); // "Unit propagation" rule: // G_j |- !l_j, j in [1..n]-{i} // G |- (OR l_1 ... l_i ... l_n) ==> G, G_j |- l_i virtual Theorem unitProp(const std::vector& thms, const Theorem& clause, unsigned i); // "Conflict" rule (all literals in a clause become FALSE) // { G_j |- !l_j, j in [1..n] } , G |- (OR l_1 ... l_n) ==> FALSE virtual Theorem conflictRule(const std::vector& thms, const Theorem& clause); // Unit propagation for AND virtual Theorem propAndrAF(const Theorem& andr_th, bool left, const Theorem& b_th); virtual Theorem propAndrAT(const Theorem& andr_th, const Theorem& l_th, const Theorem& r_th); virtual void propAndrLRT(const Theorem& andr_th, const Theorem& a_th, Theorem* l_th, Theorem* r_th); virtual Theorem propAndrLF(const Theorem& andr_th, const Theorem& a_th, const Theorem& r_th); virtual Theorem propAndrRF(const Theorem& andr_th, const Theorem& a_th, const Theorem& l_th); // Conflicts for AND virtual Theorem confAndrAT(const Theorem& andr_th, const Theorem& a_th, bool left, const Theorem& b_th); virtual Theorem confAndrAF(const Theorem& andr_th, const Theorem& a_th, const Theorem& l_th, const Theorem& r_th); // Unit propagation for IFF virtual Theorem propIffr(const Theorem& iffr_th, int p, const Theorem& a_th, const Theorem& b_th); // Conflicts for IFF virtual Theorem confIffr(const Theorem& iffr_th, const Theorem& i_th, const Theorem& l_th, const Theorem& r_th); // Unit propagation for ITE virtual Theorem propIterIte(const Theorem& iter_th, bool left, const Theorem& if_th, const Theorem& then_th); virtual void propIterIfThen(const Theorem& iter_th, bool left, const Theorem& ite_th, const Theorem& then_th, Theorem* if_th, Theorem* else_th); virtual Theorem propIterThen(const Theorem& iter_th, const Theorem& ite_th, const Theorem& if_th); // Conflicts for ITE virtual Theorem confIterThenElse(const Theorem& iter_th, const Theorem& ite_th, const Theorem& then_th, const Theorem& else_th); virtual Theorem confIterIfThen(const Theorem& iter_th, bool left, const Theorem& ite_th, const Theorem& if_th, const Theorem& then_th); // CNF Rules Theorem andCNFRule(const Theorem& thm); Theorem orCNFRule(const Theorem& thm); Theorem impCNFRule(const Theorem& thm); Theorem iffCNFRule(const Theorem& thm); Theorem iteCNFRule(const Theorem& thm); Theorem iteToClauses(const Theorem& ite); Theorem iffToClauses(const Theorem& iff); //theorrm for minisat proofs, by yeting Theorem satProof(const Expr& queryExpr, const Proof& satProof); ///////////////////////////////////////////////////////////////////////// //// helper functions for CNF (Conjunctive Normal Form) conversion ///////////////////////////////////////////////////////////////////////// private: Theorem opCNFRule(const Theorem& thm, int kind, const std::string& ruleName); Expr convertToCNF(const Expr& v, const Expr & phi); //! checks if phi has v in local cache of opCNFRule, if so reuse v. /*! similarly for ( ! ... ! (phi)) */ Expr findInLocalCache(const Expr& i, ExprMap& localCache, std::vector& boundVars); }; // end of class SearchEngineRules } // end of namespace CVC3 #endif cvc3-2.4.1/src/search/LFSCBoolProof.h0000664000175400017540000001025411363704204017036 0ustar mdetersmdeters#ifndef LFSC_BOOL_PROOF_H_ #define LFSC_BOOL_PROOF_H_ #include "LFSCProof.h" class LFSCBoolRes : public LFSCProof { private: RefPtr< LFSCProof > d_children[2]; int d_var; bool d_col; LFSCBoolRes(LFSCProof* pf1, LFSCProof* pf2, int v, bool col): LFSCProof(), d_var(v), d_col(col){ d_children[0] = pf1; d_children[1] = pf2; } virtual ~LFSCBoolRes(){} long int get_length(){ return 10 + d_children[0]->get_string_length() + d_children[1]->get_string_length(); } public: virtual LFSCBoolRes* AsLFSCBoolRes(){ return this; } void print_pf( std::ostream& s, int ind = 0 ); void print_struct( std::ostream& s, int ind = 0 ); //standard Make static LFSCProof* Make(LFSCProof* pf1, LFSCProof* pf2, int v, bool col); // make the boolean resolution proof, where p1 corresponds to pf1, p2 corresponds to pf2 //res is the expression to resolve upon static LFSCProof* Make( LFSCProof* p1, LFSCProof* p2, const Expr& res, const Expr& pf, bool cascadeOr = false ); //make the boolean resolution collection proof, where e is what to resolve static LFSCProof* MakeC( LFSCProof* p, const Expr& res ); LFSCProof* clone() { return new LFSCBoolRes( d_children[0].get(), d_children[1].get(), d_var, d_col ); } int getNumChildren() { return 2; } LFSCProof* getChild( int n ) { return d_children[n].get(); } int checkBoolRes( std::vector< int >& clause ); }; class LFSCLem : public LFSCProof { private: int d_var; LFSCLem( int v ) : LFSCProof(), d_var( v ) {} virtual ~LFSCLem(){} long int get_length() { return 10; } public: virtual LFSCLem* AsLFSCLem(){ return this; } void print_pf( std::ostream& s, int ind = 0 ){ s << "(lem _ _ @a" << abs( d_var ) << ")"; } void print_struct( std::ostream& s, int ind = 0 ){ s << "(lem " << d_var << ")"; } static LFSCProof* Make(int v){ return new LFSCLem( v ); } bool IsTrivial() { return true; } LFSCProof* clone() { return new LFSCLem( d_var ); } int checkBoolRes( std::vector< int >& clause ){ clause.push_back( -d_var ); clause.push_back( d_var ); return 0; } }; class LFSCClausify : public LFSCProof { private: friend class LFSCPrinter; int d_var; RefPtr< LFSCProof > d_pf; LFSCClausify( int v, LFSCProof* pf ) : LFSCProof(), d_var( v ), d_pf( pf ){} virtual ~LFSCClausify(){} long int get_length() { return 10 + d_pf->get_string_length(); } //this should be called by Make static LFSCProof* Make_i( const Expr& e, LFSCProof* p, std::vector< Expr >& exprs, const Expr& end ); public: virtual LFSCClausify* AsLFSCClausify(){ return this; } void print_pf( std::ostream& s, int ind = 0 ); void print_struct( std::ostream& s, int ind = 0 ){ s << "(clausify " << d_var << ")"; } //standard Make static LFSCProof* Make( int v, LFSCProof* pf ){ return new LFSCClausify( v, pf ); } // input : a formula e, and a proof of that formula p. static LFSCProof* Make( const Expr& e, LFSCProof* p, bool cascadeOr = false ); //clone LFSCProof* clone() { return new LFSCClausify( d_var, d_pf.get() ); } int getNumChildren() { return 1; } LFSCProof* getChild( int n ) { return d_pf.get(); } int checkBoolRes( std::vector< int >& clause ){ d_pf->checkBoolRes( clause ); clause.push_back( d_var ); return 0; } }; class LFSCAssume : public LFSCProof { private: int d_var; RefPtr< LFSCProof > d_pf; bool d_assm; int d_type; LFSCAssume( int v, LFSCProof* pf, bool assm, int type ) : LFSCProof(), d_var( v ), d_pf( pf ), d_assm( assm ), d_type( type ){} virtual ~LFSCAssume(){} long int get_length() { return 10 + d_pf->get_string_length(); } public: virtual LFSCAssume* AsLFSCAssume(){ return this; } void print_pf( std::ostream& s, int ind = 0 ); void print_struct( std::ostream& s, int ind = 0 ); static LFSCProof* Make( int v, LFSCProof* pf, bool assm = true, int type=3 ){ return new LFSCAssume( v, pf, assm, type ); } LFSCProof* clone() { return new LFSCAssume( d_var, d_pf.get(), d_assm, d_type ); } int getNumChildren() { return 1; } LFSCProof* getChild( int n ) { return d_pf.get(); } int checkBoolRes( std::vector< int >& clause ){ if( d_type==3 ){ d_pf->checkBoolRes( clause ); clause.push_back( -d_var ); } return 0; } }; #endif cvc3-2.4.1/src/search/search_rules.h0000664000175400017540000002122210716213262017141 0ustar mdetersmdeters/*****************************************************************************/ /*! * \file search_rules.h * \brief Abstract proof rules interface to the simple search engine * * Author: Sergey Berezin * * Created: Mon Feb 24 14:19:48 2003 * *
* * License to use, copy, modify, sell and/or distribute this software * and its documentation for any purpose is hereby granted without * royalty, subject to the terms and conditions defined in the \ref * LICENSE file provided with this distribution. * *
* */ /*****************************************************************************/ #ifndef _cvc3__search__search_rules_h_ #define _cvc3__search__search_rules_h_ namespace CVC3 { class Theorem; class Expr; /*! \defgroup SE_Rules Proof Rules for the Search Engines * \ingroup SE */ //! API to the proof rules for the Search Engines /*! \ingroup SE_Rules */ class SearchEngineRules { /*! \addtogroup SE_Rules * @{ */ public: //! Destructor virtual ~SearchEngineRules() { } /*! Eliminate skolem axioms: * Gamma, Delta |- false => Gamma|- false * where Delta is a set of skolem axioms {|-Exists(x) phi (x) => phi(c)} * and gamma does not contain any of the skolem constants c. */ virtual Theorem eliminateSkolemAxioms(const Theorem& tFalse, const std::vector& delta) = 0; // !A |- FALSE ==> |- A /*! @brief Proof by contradiction: \f[\frac{\Gamma, \neg A \vdash\mathrm{FALSE}}{\Gamma \vdash A}\f] */ /*! \f$\neg A\f$ does not have to be present in the assumptions. * \param a is the assumption \e A * * \param pfFalse is the theorem \f$\Gamma, \neg A \vdash\mathrm{FALSE}\f$ */ virtual Theorem proofByContradiction(const Expr& a, const Theorem& pfFalse) = 0; // A |- FALSE ==> !A /*! @brief Negation introduction: \f[\frac{\Gamma, A \vdash\mathrm{FALSE}}{\Gamma\vdash\neg A}\f] */ /*! * \param not_a is the formula \f$\neg A\f$. We pass the negation * \f$\neg A\f$, and not just \e A, for efficiency: building * \f$\neg A\f$ is more expensive (due to uniquifying pointers in * Expr package) than extracting \e A from \f$\neg A\f$. * * \param pfFalse is the theorem \f$\Gamma, A \vdash\mathrm{FALSE}\f$ */ virtual Theorem negIntro(const Expr& not_a, const Theorem& pfFalse) = 0; // u1:A |- C, u2:!A |- C ==> |- C /*! @brief Case split: \f[\frac{\Gamma_1, A\vdash C \quad \Gamma_2, \neg A\vdash C} {\Gamma_1\cup\Gamma_2\vdash C}\f] */ /*! * \param a is the assumption A to split on * * \param a_proves_c is the theorem \f$\Gamma_1, A\vdash C\f$ * * \param not_a_proves_c is the theorem \f$\Gamma_2, \neg A\vdash C\f$ */ virtual Theorem caseSplit(const Expr& a, const Theorem& a_proves_c, const Theorem& not_a_proves_c) = 0; // Gamma, A_1,...,A_n |- FALSE ==> Gamma |- (OR !A_1 ... !A_n) /*! @brief Conflict clause rule: \f[\frac{\Gamma,A_1,\ldots,A_n\vdash\mathrm{FALSE}} {\Gamma\vdash\neg A_1\vee\cdots\vee \neg A_n}\f] */ /*! * \param thm is the theorem * \f$\Gamma,A_1,\ldots,A_n\vdash\mathrm{FALSE}\f$ * * \param lits is the vector of literals Ai. * They must be present in the set of assumptions of \e thm. * * \param gamma FIXME: document this!! */ virtual Theorem conflictClause(const Theorem& thm, const std::vector& lits, const std::vector& gamma) = 0; // "Cut" rule: { G_i |- A_i }; G', { A_i } |- B ==> union(G_i)+G' |- B. /*! @brief Cut rule: \f[\frac{\Gamma_1\vdash A_1\quad\cdots\quad\Gamma_n\vdash A_n \quad \Gamma', A_1,\ldots,A_n\vdash B} {\bigcup_{i=1}^n\Gamma_i\cup\Gamma'\vdash B}\f] */ /*! * \param thmsA is a vector of theorems \f$\Gamma_i\vdash A_i\f$ * * \param as_prove_b is the theorem * \f$\Gamma', A_1,\ldots,A_n\vdash B\f$ * (the name means "A's prove B") */ virtual Theorem cutRule(const std::vector& thmsA, const Theorem& as_prove_b) = 0; // { G_j |- !A_j, j in [1..n]-{i} } // G |- (OR A_1 ... A_i ... A_n) ==> G, G_j |- A_i /*! @brief Unit propagation rule: \f[\frac{\Gamma_j\vdash\neg A_j\mbox{ for }j\in[1\ldots n]-\{i\} \quad \Gamma\vdash A_1\vee\cdots\vee A_n} {\bigcup_{j\in[1\ldots n]-\{i\}}\Gamma_j\cup\Gamma\vdash A_i}\f] */ /*! * \param clause is the proof of the clause \f$ \Gamma\vdash * A_1\vee\cdots\vee A_n\f$ * * \param i is the index (0..n-1) of the literal to be unit-propagated * * \param thms is the vector of theorems \f$\Gamma_j\vdash\neg * A_j\f$ for all literals except Ai */ virtual Theorem unitProp(const std::vector& thms, const Theorem& clause, unsigned i) = 0; // { G_j |- !A_j, j in [1..n] } , G |- (OR A_1 ... A_n) ==> FALSE /*! @brief "Conflict" rule (all literals in a clause become FALSE) \f[\frac{\Gamma_j\vdash\neg A_j\mbox{ for }j\in[1\ldots n] \quad \Gamma\vdash A_1\vee\cdots\vee A_n} {\bigcup_{j\in[1\ldots n]}\Gamma_j\cup\Gamma \vdash\mathrm{FALSE}}\f] */ /*! * \param clause is the proof of the clause \f$ \Gamma\vdash * A_1\vee\cdots\vee A_n\f$ * * \param thms is the vector of theorems \f$\Gamma_j\vdash\neg * A_j\f$ */ virtual Theorem conflictRule(const std::vector& thms, const Theorem& clause) = 0; // Unit propagation for AND virtual Theorem propAndrAF(const Theorem& andr_th, bool left, const Theorem& b_th) = 0; virtual Theorem propAndrAT(const Theorem& andr_th, const Theorem& l_th, const Theorem& r_th) = 0; virtual void propAndrLRT(const Theorem& andr_th, const Theorem& a_th, Theorem* l_th, Theorem* r_th) = 0; virtual Theorem propAndrLF(const Theorem& andr_th, const Theorem& a_th, const Theorem& r_th) = 0; virtual Theorem propAndrRF(const Theorem& andr_th, const Theorem& a_th, const Theorem& l_th) = 0; // Conflicts for AND virtual Theorem confAndrAT(const Theorem& andr_th, const Theorem& a_th, bool left, const Theorem& b_th) = 0; virtual Theorem confAndrAF(const Theorem& andr_th, const Theorem& a_th, const Theorem& l_th, const Theorem& r_th) = 0; // Unit propagation for IFF virtual Theorem propIffr(const Theorem& iffr_th, int p, const Theorem& a_th, const Theorem& b_th) = 0; // Conflicts for IFF virtual Theorem confIffr(const Theorem& iffr_th, const Theorem& i_th, const Theorem& l_th, const Theorem& r_th) = 0; // Unit propagation for ITE virtual Theorem propIterIte(const Theorem& iter_th, bool left, const Theorem& if_th, const Theorem& then_th) = 0; virtual void propIterIfThen(const Theorem& iter_th, bool left, const Theorem& ite_th, const Theorem& then_th, Theorem* if_th, Theorem* else_th) = 0; virtual Theorem propIterThen(const Theorem& iter_th, const Theorem& ite_th, const Theorem& if_th) = 0; // Conflict for ITE virtual Theorem confIterThenElse(const Theorem& iter_th, const Theorem& ite_th, const Theorem& then_th, const Theorem& else_th) = 0; virtual Theorem confIterIfThen(const Theorem& iter_th, bool left, const Theorem& ite_th, const Theorem& if_th, const Theorem& then_th) = 0; // CNF Rules //! AND(x1,...,xn) <=> v |- CNF[AND(x1,...,xn) <=> v] virtual Theorem andCNFRule(const Theorem& thm) = 0; //! OR(x1,...,xn) <=> v |- CNF[OR(x1,...,xn) <=> v] virtual Theorem orCNFRule(const Theorem& thm) = 0; //! (x1 => x2) <=> v |- CNF[(x1 => x2) <=> v] virtual Theorem impCNFRule(const Theorem& thm) = 0; //! (x1 <=> x2) <=> v |- CNF[(x1 <=> x2) <=> v] virtual Theorem iffCNFRule(const Theorem& thm) = 0; //! ITE(c, x1, x2) <=> v |- CNF[ITE(c, x1, x2) <=> v] virtual Theorem iteCNFRule(const Theorem& thm) = 0; //! ITE(c, f1, f2) |- (NOT c OR f1) AND (c OR f2) virtual Theorem iteToClauses(const Theorem& ite) = 0; //! e1 <=> e2 |- (NOT e1 OR e2) AND (e1 OR NOT e2) virtual Theorem iffToClauses(const Theorem& iff) = 0; virtual Theorem satProof(const Expr& queryExpr, const Proof& satProof) = 0; /*! @} */ // end of SE_Rules }; // end of class SearchEngineRules } // end of namespace CVC3 #endif cvc3-2.4.1/src/search/variable.cpp0000664000175400017540000002755310656155011016617 0ustar mdetersmdeters/*****************************************************************************/ /*! * \file variable.cpp * \brief Implementation of class Variable; see variable.h for detail. * * Author: Sergey Berezin * * Created: Fri Apr 25 12:30:17 2003 * *
* * License to use, copy, modify, sell and/or distribute this software * and its documentation for any purpose is hereby granted without * royalty, subject to the terms and conditions defined in the \ref * LICENSE file provided with this distribution. * *
* */ /*****************************************************************************/ #include #include "variable.h" #include "search_rules.h" #include "memory_manager_chunks.h" #include "memory_manager_malloc.h" using namespace std; namespace CVC3 { /////////////////////////////////////////////////////////////////////// // class Variable methods /////////////////////////////////////////////////////////////////////// // Constructors Variable::Variable(VariableManager* vm, const Expr& e) : d_val(vm->newVariableValue(e)) { d_val->d_refcount++; } Variable::Variable(const Variable& l): d_val(l.d_val) { if(!isNull()) d_val->d_refcount++; } // Destructor Variable::~Variable() { if(!isNull()) { if(--(d_val->d_refcount) == 0) d_val->d_vm->gc(d_val); } } // Assignment Variable& Variable::operator=(const Variable& l) { if(&l == this) return *this; // Self-assignment if(!isNull()) { if(--(d_val->d_refcount) == 0) d_val->d_vm->gc(d_val); } d_val = l.d_val; if(!isNull()) d_val->d_refcount++; return *this; } const Expr& Variable::getExpr() const { static Expr null; if(isNull()) return null; return d_val->getExpr(); } const Expr& Variable::getNegExpr() const { static Expr null; if(isNull()) return null; return d_val->getNegExpr(); } // IMPORTANT: Value can be -1 (false), 1 (true), or 0 (unresolved) int Variable::getValue() const { if(isNull()) return 0; return d_val->getValue(); } int Variable::getScope() const { if(isNull()) return 0; return d_val->getScope(); } const Theorem& Variable::getTheorem() const { static Theorem null; if(isNull()) return null; return d_val->getTheorem(); } const Clause& Variable::getAntecedent() const { static Clause null; if(isNull()) return null; return d_val->getAntecedent(); } int Variable::getAntecedentIdx() const { if(isNull()) return 0; return d_val->getAntecedentIdx(); } const Theorem& Variable::getAssumpThm() const { static Theorem null; if(isNull()) return null; return d_val->getAssumpThm(); } // Setting the attributes: it can be either derived from the // antecedent clause, or by a theorem. The scope level is set to // the current scope. void Variable::setValue(int val, const Clause& c, int idx) { DebugAssert(!isNull(), "Variable::setValue(antecedent): var is NULL"); d_val->setValue(val, c, idx); } // The theorem's expr must be the same as the variable's expr or // its negation void Variable::setValue(const Theorem& thm) { DebugAssert(!isNull(), "Variable::setValue(Theorem): var is NULL"); d_val->setValue(thm, thm.getScope()); } void Variable::setValue(const Theorem& thm, int scope) { DebugAssert(!isNull(), "Variable::setValue(Theorem,scope): var is NULL"); d_val->setValue(thm, scope); } void Variable::setAssumpThm(const Theorem& a, int scope) { DebugAssert(!isNull(), "Variable::setAssumpThm(): var is NULL"); d_val->setAssumpThm(a, scope); } // Derive the theorem for either the variable or its negation. If // the value is set by a theorem, that theorem is returned; // otherwise a unit propagation rule is applied to the antecedent // clause, and the theorem is cached for a quick access later. Theorem Variable::deriveTheorem() const { return deriveThmRec(false); } Theorem Variable::deriveThmRec(bool checkAssump) const { DebugAssert(!isNull(), "Variable::deriveTheorem(): called on Null"); DebugAssert(getValue() != 0, "Variable::deriveTheorem(): value is not set: " + toString()); if(!getTheorem().isNull()) return getTheorem(); if(checkAssump && !getAssumpThm().isNull()) return getAssumpThm(); // Have to derive the theorem Clause c(getAntecedent()); int idx(getAntecedentIdx()); const vector& lits = c.getLiterals(); // Theorems for the other literals in the antecedent clause vector thms; int size(lits.size()); // Derive theorems recursively for(int i=0; id_vm->getRules()->unitProp(thms, c.getTheorem(), idx); else thm = d_val->d_vm->getRules()->conflictRule(thms, c.getTheorem()); IF_DEBUG(Expr e(thm.getExpr());) DebugAssert(e == getExpr() || (e.isNot() && e[0] == getExpr()), "Variable::deriveTheorem: bad theorem derived: expr =" + toString() + ", thm = " + thm.toString()); // Cache the result d_val->setValue(thm, getScope()); return thm; } string Variable::toString() const { ostringstream ss; ss << *this; return ss.str(); } // Friend methods ostream& operator<<(ostream& os, const Variable& l) { return os << (*l.d_val); } /////////////////////////////////////////////////////////////////////// // class Literal methods /////////////////////////////////////////////////////////////////////// string Literal::toString() const { ostringstream ss; ss << *this; return ss.str(); } ostream& operator<<(ostream& os, const Literal& l) { os << "Lit(" << (l.isNegative()? "!" : "") << l.getVar(); // Attributes os << ", count=" << l.count() << ", score=" << l.score(); return os << ")"; } /////////////////////////////////////////////////////////////////////// // class VariableValue methods /////////////////////////////////////////////////////////////////////// // Destructor VariableValue::~VariableValue() { if(d_val!=NULL) { delete d_val; free(d_val); d_val = NULL; } if(d_scope!=NULL) { delete d_scope; free(d_scope); d_scope = NULL; } if(d_thm!=NULL) { delete d_thm; free(d_thm); d_thm = NULL; } if(d_ante!=NULL) { delete d_ante; free(d_ante); d_ante = NULL; } if(d_anteIdx!=NULL) { delete d_anteIdx; free(d_anteIdx); d_anteIdx = NULL; } if(d_assump!=NULL) { delete d_assump; free(d_assump); d_assump = NULL; } } // Setting the attributes: it can be either derived from the // antecedent clause, or by a theorem void VariableValue::setValue(int val, const Clause& c, int idx) { if(d_val==NULL) { // Make sure d_val==0 all the way to scope 0 d_val = new(true) CDO(d_vm->getCM()->getCurrentContext(), 0, 0); IF_DEBUG(d_val->setName("CDO[VariableValue::d_val]");) } if(d_scope==NULL) { d_scope = new(true) CDO(d_vm->getCM()->getCurrentContext()); IF_DEBUG(d_scope->setName("CDO[VariableValue::d_scope]");) } if(d_ante==NULL) { d_ante = new(true) CDO(d_vm->getCM()->getCurrentContext()); IF_DEBUG(d_ante->setName("CDO[VariableValue::d_ante]");) } if(d_anteIdx==NULL) { d_anteIdx = new(true) CDO(d_vm->getCM()->getCurrentContext()); IF_DEBUG(d_anteIdx->setName("CDO[VariableValue::d_anteIdx]");) } // Compute the scope from the antecedent clause // Assume the clause is valid exactly at the bottom scope int scope(c.getScope()); for(int i=0, iend=c.size(); i!=iend; ++i) { if(i!=idx) { int s(c[i].getScope()); if(s > scope) scope = s; DebugAssert(c[i].getValue() != 0, "VariableValue::setValue(ante): literal has no value: " "i="+int2string(i)+" in\n clause = " +c.toString()); } } d_val->set(val, scope); d_scope->set(scope, scope); // d_vm->getCM()->scopeLevel(); d_ante->set(c, scope); d_anteIdx->set(idx, scope); // Set the theorem to null, to clean up the old value if(!getTheorem().isNull()) d_thm->set(Theorem(), scope); IF_DEBUG(Expr l((idx == -1)? getExpr().getEM()->falseExpr() : c[idx].getExpr());) DebugAssert((val > 0 && l == getExpr()) || (val < 0 && l.isNot() && l[0] == getExpr()), "VariableValue::setValue(val = " + int2string(val) + ", c = " + c.toString() + ", idx = " + int2string(idx) + "):\n expr = " + getExpr().toString() + "\n literal = " + l.toString()); } // The theorem's expr must be the same as the variable's expr or // its negation void VariableValue::setValue(const Theorem& thm, int scope) { if(d_val==NULL) { // Make sure d_val==0 all the way to scope 0 d_val = new(true) CDO(d_vm->getCM()->getCurrentContext(),0,0); IF_DEBUG(d_val->setName("CDO[VariableValue::d_val]");) } if(d_scope==NULL) { d_scope = new(true) CDO(d_vm->getCM()->getCurrentContext()); IF_DEBUG(d_scope->setName("CDO[VariableValue::d_scope]");) } if(d_thm==NULL) { d_thm = new(true) CDO(d_vm->getCM()->getCurrentContext()); IF_DEBUG(d_thm->setName("CDO[VariableValue::d_thm]");) } Expr e(thm.getExpr()); int val(0); if(e == d_expr) val = 1; else { DebugAssert(e.isNot() && e[0] == d_expr, "VariableValue::setValue(thm = " + thm.toString() + "): expr = " + d_expr.toString()); val = -1; } // Set the values on that scope d_val->set(val, scope); d_scope->set(scope, scope); // d_vm->getCM()->scopeLevel(); d_thm->set(thm, scope); // Set clause to null, to clean up the old value if(!getAntecedent().isNull()) d_ante->set(Clause(), scope); } void VariableValue::setAssumpThm(const Theorem& thm, int scope) { if(d_assump==NULL) { // Make sure d_val==0 all the way to scope 0 d_assump = new(true) CDO(d_vm->getCM()->getCurrentContext()); IF_DEBUG(d_val->setName("CDO[VariableValue::d_val]");) } d_assump->set(thm, scope); } ostream& operator<<(ostream& os, const VariableValue& v) { os << "Var(" << v.getExpr() << " = " << v.getValue(); if(v.getValue() != 0) { os << " @ " << v.getScope(); if(!v.getTheorem().isNull()) os << "; " << v.getTheorem(); else if(!v.getAntecedent().isNull()) { os << "; #" << v.getAntecedentIdx() << " in " << CompactClause(v.getAntecedent()); } } return os << ")"; } /////////////////////////////////////////////////////////////////////// // class VariableManager methods /////////////////////////////////////////////////////////////////////// // Creating unique VariableValue VariableValue* VariableManager::newVariableValue(const Expr& e) { VariableValue vv(this, e); VariableValueSet::iterator i(d_varSet.find(&vv)), iend(d_varSet.end()); if(i != iend) return (*i); // No such variable, create and insert one VariableValue* p_vv(new(d_mm) VariableValue(this, e)); d_varSet.insert(p_vv); return p_vv; } // Constructor VariableManager::VariableManager(ContextManager* cm, SearchEngineRules* rules, const string& mmFlag) : d_cm(cm), d_rules(rules), d_disableGC(false), d_postponeGC(false) { if(mmFlag == "chunks") d_mm = new MemoryManagerChunks(sizeof(VariableValue)); else d_mm = new MemoryManagerMalloc(); d_notifyObj = new VariableManagerNotifyObj(this, d_cm->getCurrentContext()); } // Destructor VariableManager::~VariableManager() { delete d_notifyObj; // Delete the remaining variables d_disableGC = true; vector vars; for(VariableValueSet::iterator i=d_varSet.begin(), iend=d_varSet.end(); i!=iend; ++i) { vars.push_back(*i); // delete(*i); // No need to free memory; we'll delete the entire d_mm // d_mm->deleteData(*i); } d_varSet.clear(); for(vector::iterator i=vars.begin(), iend=vars.end(); i!=iend; ++i) delete *i; delete d_mm; } // Garbage collect VariableValue pointer void VariableManager::gc(VariableValue* v) { if(!d_disableGC) { d_varSet.erase(v); if(d_postponeGC) d_deleted.push_back(v); else { delete v; d_mm->deleteData(v); } } } void VariableManager::resumeGC() { d_postponeGC = false; while(d_deleted.size() > 0) { VariableValue* v = d_deleted.back(); d_deleted.pop_back(); delete v; d_mm->deleteData(v); } } } // end of namespace CVC3 cvc3-2.4.1/src/search/circuit.cpp0000664000175400017540000001554410466450543016500 0ustar mdetersmdeters/*****************************************************************************/ /*! * \file circuit.cpp * \brief Circuit class * *
* * License to use, copy, modify, sell and/or distribute this software * and its documentation for any purpose is hereby granted without * royalty, subject to the terms and conditions defined in the \ref * LICENSE file provided with this distribution. * *
* */ /*****************************************************************************/ #include "circuit.h" #include "search_fast.h" #include "search_rules.h" using namespace std; namespace CVC3 { Circuit::Circuit(SearchEngineFast* se, const Theorem& thm) : d_thm(thm) { const Expr& e = d_thm.getExpr(); for (int i = 0; i < e.arity(); i++) { d_lits[i] = e[i].isNot() ? Literal(Variable(se->d_vm, e[i][0]), false) : Literal(Variable(se->d_vm, e[i]), true); se->d_circuitsByExpr[e[i]].push_back(this); se->d_circuitsByExpr[e[i].negate()].push_back(this); } } #define vals3(a, b, c) ((a) + 1 + ((b) + 1) * 3 + ((c) + 1) * 9) #define vals4(a, b, c, d) (vals3(a, b, c) + ((d) + 1) * 27) bool Circuit::propagate(SearchEngineFast* se) { int v0 = d_lits[0].getValue(); int v1 = d_lits[1].getValue(); int v2 = d_lits[2].getValue(); int v3 = d_lits[3].getValue(); const Theorem& t0 = d_lits[0].getTheorem(); const Theorem& t1 = d_lits[1].getTheorem(); const Theorem& t2 = d_lits[2].getTheorem(); const Theorem& t3 = d_lits[3].getTheorem(); int values = d_thm.getExpr().arity() == 3 ? vals3(v0, v1, v2) : vals4(v0, v1, v2, v3); Theorem thm; Theorem thm2; switch (d_thm.getExpr().getKind()) { case AND_R: switch (values) { case vals3(0,0,0): case vals3(0,0,1): case vals3(0,1,0): case vals3(1,1,1): case vals3(-1,0,0): case vals3(-1,0,-1): case vals3(-1,1,-1): case vals3(-1,-1,0): case vals3(-1,-1,1): case vals3(-1,-1,-1): break; case vals3(0,0,-1): case vals3(0,1,-1): case vals3(0,-1,0): case vals3(0,-1,1): case vals3(0,-1,-1): // simp thm = se->d_rules->propAndrAF(d_thm, v1 == -1, v1 == -1 ? t1 : t2); break; case vals3(0,1,1): // simp thm = se->d_rules->propAndrAT(d_thm, t1, t2); break; case vals3(1,1,0): case vals3(1,0,1): case vals3(1,0,0): // split cases to avoid doing extra work? se->d_rules->propAndrLRT(d_thm, t0, &thm, &thm2); break; case vals3(-1,0,1): thm = se->d_rules->propAndrLF(d_thm, t0, t2); break; case vals3(-1,1,0): thm = se->d_rules->propAndrRF(d_thm, t0, t1); break; case vals3(1,0,-1): case vals3(1,1,-1): case vals3(1,-1,0): case vals3(1,-1,1): case vals3(1,-1,-1): se->d_conflictTheorem = se->d_rules->confAndrAT(d_thm, t0, v1 == -1, v1 == -1 ? t1 : t2); return false; case vals3(-1,1,1): se->d_conflictTheorem = se->d_rules->confAndrAF(d_thm, t0, t1, t2); return false; } break; case IFF_R: switch (values) { case vals3(0,0,0): case vals3(0,0,1): case vals3(0,0,-1): case vals3(0,1,0): case vals3(0,-1,0): case vals3(1,0,0): case vals3(1,1,1): case vals3(1,-1,-1): case vals3(-1,0,0): case vals3(-1,1,-1): case vals3(-1,-1,1): break; case vals3(0,1,1): case vals3(0,-1,-1): case vals3(0,1,-1): case vals3(0,-1,1): // simp thm = se->d_rules->propIffr(d_thm, 0, t1, t2); break; case vals3(1,0,1): case vals3(-1,0,-1): case vals3(1,0,-1): case vals3(-1,0,1): thm = se->d_rules->propIffr(d_thm, 1, t0, t2); break; case vals3(1,1,0): case vals3(-1,-1,0): case vals3(1,-1,0): case vals3(-1,1,0): thm = se->d_rules->propIffr(d_thm, 2, t0, t1); break; case vals3(1,1,-1): case vals3(1,-1,1): case vals3(-1,1,1): case vals3(-1,-1,-1): se->d_conflictTheorem = se->d_rules->confIffr(d_thm, t0, t1, t2); return false; } break; case ITE_R: switch (values) { case vals4(0,0,0,0): case vals4(0,0,0,1): case vals4(0,0,0,-1): case vals4(0,0,1,0): case vals4(0,0,1,1): case vals4(0,0,1,-1): case vals4(0,0,-1,0): case vals4(0,0,-1,1): case vals4(0,0,-1,-1): case vals4(0,1,0,0): case vals4(0,1,0,1): case vals4(0,1,0,-1): case vals4(0,-1,0,0): case vals4(0,-1,1,0): case vals4(0,-1,-1,0): case vals4(1,0,0,0): case vals4(1,0,0,1): case vals4(1,0,1,0): case vals4(1,0,1,1): case vals4(1,1,1,0): case vals4(1,1,1,1): case vals4(1,1,1,-1): case vals4(1,-1,0,1): case vals4(1,-1,1,1): case vals4(1,-1,-1,1): case vals4(-1,0,0,0): case vals4(-1,0,0,-1): case vals4(-1,0,-1,0): case vals4(-1,0,-1,-1): case vals4(-1,1,-1,0): case vals4(-1,1,-1,1): case vals4(-1,1,-1,-1): case vals4(-1,-1,0,-1): case vals4(-1,-1,1,-1): case vals4(-1,-1,-1,-1): break; case vals4(0,1,1,0): case vals4(0,1,1,1): case vals4(0,1,1,-1): case vals4(0,1,-1,0): case vals4(0,1,-1,1): case vals4(0,1,-1,-1): case vals4(0,-1,0,-1): case vals4(0,-1,1,-1): case vals4(0,-1,-1,-1): case vals4(0,-1,0,1): case vals4(0,-1,1,1): case vals4(0,-1,-1,1): // simp thm = se->d_rules->propIterIte(d_thm, v1 == 1, t1, v1 == 1 ? t2 : t3); break; case vals4(1,0,0,-1): case vals4(1,0,1,-1): case vals4(1,0,-1,0): case vals4(1,0,-1,1): case vals4(-1,0,0,1): case vals4(-1,0,1,0): case vals4(-1,0,1,-1): case vals4(-1,0,-1,1): se->d_rules->propIterIfThen(d_thm, v0 == -v2, t0, v0 == -v2 ? t2 : t3, &thm, &thm2); break; case vals4(1,1,0,0): case vals4(1,1,0,1): case vals4(1,1,0,-1): case vals4(1,-1,0,0): case vals4(1,-1,1,0): case vals4(1,-1,-1,0): case vals4(-1,1,0,0): case vals4(-1,1,0,1): case vals4(-1,1,0,-1): case vals4(-1,-1,0,0): case vals4(-1,-1,1,0): case vals4(-1,-1,-1,0): thm = se->d_rules->propIterThen(d_thm, t0, t1); break; case vals4(1,0,-1,-1): case vals4(-1,0,1,1): case vals4(-1,1,1,1): case vals4(1,1,-1,-1): se->d_conflictTheorem = se->d_rules->confIterThenElse(d_thm, t0, t2, t3); return false; case vals4(1,1,-1,0): case vals4(1,1,-1,1): case vals4(1,-1,0,-1): case vals4(1,-1,1,-1): case vals4(1,-1,-1,-1): case vals4(-1,1,1,0): case vals4(-1,1,1,-1): case vals4(-1,-1,0,1): case vals4(-1,-1,1,1): case vals4(-1,-1,-1,1): se->d_conflictTheorem = se->d_rules->confIterIfThen(d_thm, v1 == 1, t0, t1, v1 == 1 ? t2 : t3); return false; } break; default: DebugAssert(false, "unhandled circuit"); } if (!thm.isNull() && se->newLiteral(thm.getExpr()).getValue() == 0) { se->d_core->addFact(thm); se->recordFact(thm); se->d_literals.push_back(se->newLiteral(thm.getExpr())); se->d_circuitPropCount++; } if (!thm2.isNull() && se->newLiteral(thm2.getExpr()).getValue() == 0) { se->d_core->addFact(thm2); se->recordFact(thm2); se->d_literals.push_back(se->newLiteral(thm2.getExpr())); se->d_circuitPropCount++; } return true; } } // namespace CVC3 cvc3-2.4.1/src/search/LFSCUtilProof.cpp0000664000175400017540000001103611363704204017412 0ustar mdetersmdeters#include "LFSCUtilProof.h" #include "LFSCPrinter.h" //LFSCProofExpr ... void LFSCProofExpr::initialize(){ printer->set_print_expr( d_e ); } void LFSCProofExpr::print_pf( std::ostream& s, int ind ){ if( isHole ) s << "_"; else{ //HACK (forces unary minus to be printed properly) //bool prev_cvc3_mimic = cvc3_mimic; //cvc3_mimic = true; printer->print_expr( d_e, s ); //cvc3_mimic = prev_cvc3_mimic; } } LFSCProofExpr::LFSCProofExpr( const Expr& e, bool isH ){ d_e = cascade_expr( e ); initialize(); isHole = isH; } //LFSCPfVar ... std::map< int, RefPtr< LFSCProof > > LFSCPfVar::vMap; LFSCProof* LFSCPfVar::Make( const char* c, int v ) { ostringstream os; os << c << v; return new LFSCPfVar( os.str() ); } LFSCProof* LFSCPfVar::MakeV( int v ) { RefPtr< LFSCProof > pf = vMap[v]; if( !pf.get() ){ pf = Make( "@v", v ); vMap[v] = pf.get(); } return pf.get(); } //LFSCPfLambda ... void LFSCPfLambda::print_pf( std::ostream& s, int ind ) { if( abstVal.get() ){ lambdaPrintMap[abstVal.get()] = pfV.get(); } s << "(\\ "; pfV->print( s ); //s << " _ (: bottom "; s << " "; body->print( s ); s << ")"; if( abstVal.get() ){ lambdaPrintMap[abstVal.get()] = NULL; } } //LFSCProofGeneric ... long int LFSCProofGeneric::get_length(){ long int sum = 0; for( int a=0; a<(int)d_str.size(); a++ ){ if( !debug_str ) sum += d_str[a].length(); if( a<(int)d_pf.size() ) sum += d_pf[a]->get_string_length(); } return sum; } void LFSCProofGeneric::print_pf( std::ostream& s, int ind ){ for( int a=0; a<(int)d_str.size(); a++ ){ s << d_str[a]; if( a<(int)d_pf.size() ){ d_pf[a]->print( s, d_pf.size()<3 ? ind+1 : 0 ); } } } LFSCProof* LFSCProofGeneric::Make( string str_pre, LFSCProof* sub_pf, string str_post, bool db_str ) { vector< RefPtr< LFSCProof > > d_pfs; d_pfs.push_back( sub_pf ); vector< string > d_strs; d_strs.push_back( str_pre ); d_strs.push_back( str_post ); return new LFSCProofGeneric( d_pfs, d_strs, db_str ); } LFSCProof* LFSCProofGeneric::Make( string str_pre, LFSCProof* sub_pf1, LFSCProof* sub_pf2, string str_post, bool db_str ) { vector< RefPtr< LFSCProof > > d_pfs; d_pfs.push_back( sub_pf1 ); d_pfs.push_back( sub_pf2 ); vector< string > d_strs; string str_empty(" "); d_strs.push_back( str_pre ); d_strs.push_back( str_empty ); d_strs.push_back( str_post ); return new LFSCProofGeneric( d_pfs, d_strs, db_str ); } LFSCProof* LFSCProofGeneric::MakeStr( const char* c, bool db_str) { vector< RefPtr< LFSCProof > > d_pfs; vector< string > d_strs; string str( c ); d_strs.push_back( str ); return new LFSCProofGeneric( d_pfs, d_strs, db_str ); } //LFSCPfLet LFSCPfLet::LFSCPfLet( LFSCProof* letPf, LFSCPfVar* pv, LFSCProof* body, bool isTh, std::vector< int >& fv ) : LFSCProof(), d_letPf( letPf ), d_pv( pv ),d_body( body ),d_isTh( isTh ){ d_letPfRpl = letPf; d_pvRpl = pv; #ifndef IGNORE_LETPF_VARS //modify letPf and rpl based on fv for(int a=0; a<(int)fv.size(); a++ ){ ostringstream os1, os2; //if( d_isTh ){ os1 << "(impl_intro _ _ "; os2 << ")"; //}else{ //} RefPtr< LFSCProof > pv1 = LFSCPfVar::Make( "@@v", abs( fv[a] ) ); RefPtr< LFSCProof > pv2 = LFSCPfVar::MakeV( abs( fv[a] ) ); d_letPfRpl = LFSCPfLambda::Make( (LFSCPfVar*)pv1.get(), d_letPfRpl.get(), pv2.get() ); d_letPfRpl = LFSCProofGeneric::Make( os1.str(), d_letPfRpl.get(), os2.str() ); } for( int a=(int)fv.size()-1; a>=0; a-- ){ ostringstream os1, os2; os1 << "(impl_elim _ _ "; os2 << ")"; RefPtr< LFSCProof > pv2 = LFSCPfVar::MakeV( abs( fv[a] ) ); d_pvRpl = LFSCProofGeneric::Make( os1.str(), pv2.get(), d_pvRpl.get(), os2.str() ); } #endif } void LFSCPfLet::print_pf( std::ostream& s, int ind ){ //fill holes if this proof is already abstracted if( d_pvRpl.get()!=d_pv.get() ){ d_letPfRpl->fillHoles(); } s << "(" << (d_isTh ? "th_let_pf _ " : "satlem _ _ _ " ); d_letPfRpl->print( s ); s << "(\\ "; d_pv->print( s ); s << " " << endl; lambdaPrintMap[d_letPf.get()]=d_pvRpl.get(); d_body->print( s, ind ); lambdaPrintMap[d_letPf.get()]=NULL; s << "))"; } void LFSCPfLet::print_struct( std::ostream& s, int ind ){ s << "(satlem "; d_letPf->print_structure( s, ind+1 ); s << "(\\ "; d_pv->print_structure( s ); s << " "; lambdaPrintMap[d_letPf.get()]=d_pv.get(); d_body->print_structure( s, ind+1 ); lambdaPrintMap[d_letPf.get()]=NULL; s << ")"; } cvc3-2.4.1/src/search/LFSCProof.h0000664000175400017540000000674311363704204016232 0ustar mdetersmdeters#ifndef LFSC_PROOF_H_ #define LFSC_PROOF_H_ #include "LFSCObject.h" ////////////////////////////////// /// LFSC Proof Class & subclasses ////////////////////////////////// class LFSCProofExpr; class LFSCLraAdd; class LFSCLraSub; class LFSCLraMulC; class LFSCLraAxiom; class LFSCLraContra; class LFSCLraPoly; class LFSCBoolRes; class LFSCLem; class LFSCClausify; class LFSCAssume; class LFSCProofGeneric; class LFSCPfVar; class LFSCPfLambda; class LFSCPfLet; class LFSCProof : public LFSCObj{ protected: static int pf_counter; static std::map< LFSCProof*, int > lambdaMap; static std::map< LFSCProof*, LFSCProof* > lambdaPrintMap; int printCounter; LFSCProof* rplProof; static int lambdaCounter; long int strLen; int chOp; int assumeVar; int assumeVarUsed; std::vector< int > br; bool brComputed; LFSCProof(); virtual long int get_length() { return 0; } virtual ~LFSCProof(){} public: virtual LFSCProofExpr* AsLFSCProofExpr(){ return NULL; } virtual LFSCLraAdd* AsLFSCLraAdd(){ return NULL; } virtual LFSCLraSub* AsLFSCLraSub(){ return NULL; } virtual LFSCLraMulC* AsLFSCLraMulC(){ return NULL; } virtual LFSCLraAxiom* AsLFSCLraAxiom(){ return NULL; } virtual LFSCLraContra* AsLFSCLraContra(){ return NULL; } virtual LFSCLraPoly* AsLFSCLraPoly(){ return NULL; } virtual LFSCBoolRes* AsLFSCBoolRes(){ return NULL; } virtual LFSCLem* AsLFSCLem(){ return NULL; } virtual LFSCClausify* AsLFSCClausify(){ return NULL; } virtual LFSCAssume* AsLFSCAssume(){ return NULL; } virtual LFSCProofGeneric* AsLFSCProofGeneric(){ return NULL; } virtual LFSCPfVar* AsLFSCPfVar(){ return NULL; } virtual LFSCPfLambda* AsLFSCPfLambda(){ return NULL; } virtual LFSCPfLet* AsLFSCPfLet(){ return NULL; } virtual bool isLraMulC() { return false; } static int make_lambda( LFSCProof* p ){ if( lambdaMap[p]==0 ){ lambdaMap[p] = lambdaCounter; lambdaCounter++; } return lambdaMap[p]; } void print( std::ostream& s, int ind = 0 ); virtual void print_pf( std::ostream& s, int ind = 0 )=0; virtual bool isTrivial() { return false; } long int get_string_length() { if( strLen<0 ){ strLen = get_length(); //to prevent overflow for( int a=0; aget_string_length() ){ strLen = getChild( a )->get_string_length(); } } } return strLen; } void print_structure( std::ostream& s, int ind = 0 ); virtual void print_struct( std::ostream& s, int ind = 0 ){ static int psCounter = 0; s << "P" << psCounter; psCounter++; } void setRplProof( LFSCProof* p ) { rplProof = p; } virtual void fillHoles(); #ifdef OPTIMIZE void calcL( std::vector< int >& lget, std::vector< int >& lgetu ); #endif friend class LFSCPrinter; virtual LFSCProof* clone() = 0; virtual int getNumChildren() { return 0; } virtual LFSCProof* getChild( int n ) { return NULL; } virtual int checkOp(); int getChOp(){ return chOp; } void setChOp( int c ) { chOp = c; } virtual int checkBoolRes( std::vector< int >& clause ){ return 0; } //proof making methods public: static LFSCProof* Make_CNF( const Expr& form, const Expr& reason, int pos ); static LFSCProof* Make_not_not_elim( const Expr& pf, LFSCProof* p ); static LFSCProof* Make_mimic( const Expr& pf, LFSCProof* p, int numHoles ); static LFSCProof* Make_and_elim( const Expr& form, LFSCProof* p, int n, const Expr& expected ); static int get_proof_counter() { return pf_counter; } }; #endif cvc3-2.4.1/src/search/decision_engine_dfs.h0000664000175400017540000000276310466450543020460 0ustar mdetersmdeters/*****************************************************************************/ /*! * \file decision_engine_dfs.h * * Author: Clark Barrett * * Created: Fri Jul 11 13:04:25 2003 * *
* * License to use, copy, modify, sell and/or distribute this software * and its documentation for any purpose is hereby granted without * royalty, subject to the terms and conditions defined in the \ref * LICENSE file provided with this distribution. * *
* */ /*****************************************************************************/ #ifndef _cvc3__search__decision_engine_dfs_h_ #define _cvc3__search__decision_engine_dfs_h_ #include "decision_engine.h" namespace CVC3 { /*****************************************************************************/ /*! *\anchor de_dfs *\class DecisionEngineDFS *\brief Decision Engine for use with the Search Engine *\ingroup DE * * Author: Clark Barrett * * Created: Fri Jul 11 16:34:22 2003 * */ /*****************************************************************************/ class DecisionEngineDFS : public DecisionEngine { protected: virtual bool isBetter(const Expr& e1, const Expr& e2); public: //! Constructor DecisionEngineDFS(TheoryCore* core, SearchImplBase* se); virtual ~DecisionEngineDFS() { } /*! @brief Find the next splitter. \return Null Expr if no splitter is found. */ virtual Expr findSplitter(const Expr& e); //! Search should call this when it derives 'false' virtual void goalSatisfied(); }; } #endif cvc3-2.4.1/src/search/LFSCPrinter.cpp0000664000175400017540000003323611363704204017120 0ustar mdetersmdeters#include "LFSCPrinter.h" LFSCPrinter::LFSCPrinter( Expr pf_expr, Expr qExpr, std::vector assumps, int lfscm, CommonProofRules* commonRules ): d_user_assumptions(assumps), d_common_pf_rules(commonRules){ printer = this; if( !qExpr.isFalse() ){ d_user_assumptions.push_back( cascade_expr( Expr( NOT, qExpr ) ) ); } Obj::initialize(); let_i = 1; LFSCObj::initialize( pf_expr, lfscm ); converter = new LFSCConvert( lfscm ); } /////////////////////////////////////// // main print method /////////////////////////////////////// void LFSCPrinter::print_LFSC( const Expr& pf ) { ostringstream cparen; //(AJR-1) Print the input formula and (: bottom ascription cout << "(check " << endl; cparen << ")"; // collecting variables from assumptions std::vector::iterator a = d_user_assumptions.begin(), aend = d_user_assumptions.end(); while(a!=aend){ Expr ce = cascade_expr( *a ); queryM( ce ); d_assump_map[ ce ] = true; collect_vars(*a); a++; } //////scan for the assumptions //std::vector< Expr > assumps; //collect_assumptions( pf, assumps ); ////we must record skolemizations //for( int a=1; a<(int)assumps.size(); a++ ){ // if( !d_assump_map[ assumps[a] ] ){ // ostringstream ose; // ose << "Unexpected non-discharged assumption " << assumps[a]; // print_error( ose.str().c_str(), cout ); // } //} //printing variables ExprMap::iterator v = input_vars.begin(), vend = input_vars.end(); while(v!= vend){ cout<<"(% "<<(*v).first<<" var_real"<convert( pf ); //make the let map for input formulas a = d_user_assumptions.begin(); while(a!=aend){ make_let_map( cascade_expr( *a ) ); a++; } //make the let map for trusted formulas ExprMap::iterator j = d_trusted.begin(), jend = d_trusted.end(); while( j != jend){ make_let_map( cascade_expr( (*j).first ) ); j++; } //make the let map for output atomic formulas and terms ExprMap::iterator j2 = d_formulas_printed.begin(), j2end = d_formulas_printed.end(); while( j2 != j2end){ if( (*j2).second ){ make_let_map( cascade_expr( (*j2).first ) ); } j2++; } //j = d_terms.begin(), jend = d_terms.end(); //while( j != jend){ // make_let_map((*j).first); // j++; //} ////output skolem vars //j = skolem_vars.begin(), jend = skolem_vars.end(); //while( j != jend ){ // if( (*j).second!=0 ){ // cout<<"(% "<<(*j).first<<" var_real"<print_structure( cout ); }else lambda_pf->print( cout ); cout << endl; //print closing parentheses cout << cparen.str() << endl; } void LFSCPrinter::print_poly_norm(const Expr& expr, std::ostream& s, bool pnRat, bool ratNeg ){ // if +, -, etc. if(expr.arity()==2 ){ if( expr.getKind()==MULT ){ ostringstream cparen; int nrIndex = -1; //the non-rational child for( int a=0; a<2; a++ ){ if( nrIndex==-1 ) { Expr ec = expr[a]; bool rNeg = ratNeg; while( ec.getKind()==UMINUS ){ ec = ec[0]; if( !cvc3_mimic ) rNeg = !rNeg; } if( ec.isRational() || ec.getKind()==DIVIDE ) { s<<"(pn_mul_"; if( cvc3_mimic && expr[a].getKind()==UMINUS ){ s << "u-_"; } s<< "c_" << ( a==0 ? "L" : "R" ); s<<" _ _ _ "; print_poly_norm( ec, s, false, rNeg ); s << " "; nrIndex = (1-a); cparen << ")"; } } } if( nrIndex==-1 ) { ostringstream ose; ose << "ERROR: Multiplying by non-constant " << expr; print_error( ose.str().c_str(), s ); } else { print_poly_norm(expr[nrIndex],s); } s << cparen.str(); } else if( expr.getKind()==DIVIDE ) { //this should be 2 constants if( expr[0].isRational() && expr[1].isRational() ) { if( pnRat ) s<<"(pn_const "; Rational r = expr[0].getRational(); print_rational_divide( ratNeg ? -r : r, expr[1].getRational(), s ); if( pnRat ) s << ")"; } else { print_error("ERROR: Pn Dividing by non-constant", s ); } } else { //TODO: checks for appropriate op //cout<<"e0 and e1"<2){ //cout<<"term debug"< kids = expr.getKids(); vector::iterator i = kids.begin(), iend= kids.end(); while(i+1!=iend){ s<<"("<1 ){ if( d_print_map[e]==0 ){ d_print_map[e] = let_i; let_i++; } d_print_visited_map[e] = true; } } } cvc3-2.4.1/src/search/LFSCLraProof.cpp0000664000175400017540000000750411363704204017220 0ustar mdetersmdeters#include "LFSCLraProof.h" //LFSCLraAdd ... void LFSCLraAdd::print_pf( std::ostream& s, int ind ) { s<<"(lra_add_"; s <print(s, ind+1); s<<" "; d_children[1]->print(s, ind+1); s<<")"; } LFSCProof* LFSCLraAdd::Make(LFSCProof* pf1, LFSCProof* pf2, int op1, int op2) { if( pf1->isTrivial() ) return pf2; else if( pf2->isTrivial() ) return pf1; else{ op1 = pf1->checkOp()!=-1 ? pf1->checkOp() : op1; op2 = pf2->checkOp()!=-1 ? pf2->checkOp() : op2; if( get_knd_order( op1 )>get_knd_order( op2 ) ) return Make( pf2, pf1, op2, op1 ); else return new LFSCLraAdd( pf1, pf2, op1, op2 ); } } // LFSCLraAxiom ... RefPtr< LFSCProof > LFSCLraAxiom::eq; LFSCProof* LFSCLraAxiom::MakeEq(){ if( !eq.get() ){ eq = new LFSCLraAxiom( EQ ); } return eq.get(); } void LFSCLraAxiom::print_pf( std::ostream& s, int ind ) { s<<"(lra_axiom_" << kind_to_str(d_op); if( d_op!= EQ ){ s << " "; print_rational( d_r, s ); } s<<")"; } //LFSCLraMulC ... void LFSCLraMulC::print_pf( std::ostream& s, int ind ) { s <<"(lra_mul_c_"<print( s, ind+1 ); s << ")"; } LFSCProof* LFSCLraMulC::Make(LFSCProof* pf, Rational r, int op) { if( pf->isTrivial() || r==1 ) return pf; else if( pf->AsLFSCLraMulC() ){ Rational rt = r*pf->AsLFSCLraMulC()->d_r; if( rt==1 ) return pf->AsLFSCLraMulC()->d_pf.get(); else return new LFSCLraMulC( pf->AsLFSCLraMulC()->d_pf.get(), rt, op ); }else return new LFSCLraMulC( pf, r, op ); } //LFSCLraSub ... void LFSCLraSub::print_pf( std::ostream& s, int ind ){ s <<"(lra_sub_"<print(s, ind+1); s <<" "; d_children[1]->print(s, ind+1); s <<")"; } LFSCProof* LFSCLraSub::Make(LFSCProof* pf1, LFSCProof* pf2, int op1, int op2){ if( pf2->isTrivial() ) return pf1; else if( pf1->isTrivial() ){ Rational r = Rational( -1 ); return LFSCLraMulC::Make( pf2, r, op2 ); }else return new LFSCLraSub( pf1, pf2, op1, op2 ); } //LFSCLraPoly ... void LFSCLraPoly::print_pf( std::ostream& s, int ind ){ if( d_var<0 ){ s << "(lra_not_" << kind_to_str(get_normalized( d_op )); s << "_to_" << kind_to_str(get_normalized( get_not( d_op ) )); s << " _ _"; } s << " (poly_form"; if( d_var<0 ) s << "_not"; s << " _ _ @pn" << abs( d_var ) << " "; d_pf->print( s, ind ); s << ")"; if( d_var<0 ) s << ")"; } LFSCProof* LFSCLraPoly::Make( const Expr& e, LFSCProof* p ) { Expr e1 = queryAtomic( e ); Expr eb = queryAtomic( e, true ); if( is_eq_kind( e1.getKind() ) ) { int m = queryM( e ); //get the required term that is needed to normalize Expr et; if( is_opposite( eb.getKind() ) ) et = Expr( MINUS, eb[1], eb[0] ); else et = Expr( MINUS, eb[0], eb[1] ); //et.print(); //get the polynomial normalization proof number int valT = queryMt( et ); //store it in d_pn_form (this will setup the proper pn*) d_pn_form[eb] = valT; p = LFSCLraPoly::Make( p, m, eb.getKind() ); p->setChOp( get_normalized( e1.getKind() ) ); return p; //if( m<0 ) //{ // os << "(lra_not_" << kind_to_str(get_normalized( eb.getKind() )); // os << "_to_" << kind_to_str(get_normalized( get_not( eb.getKind() ) )); // os << " _ _"; // os2 << ")"; //} //os << " (poly_form"; //if( m<0 ) // os << "_not"; //os << " _ _ @pn" << abs( m ) << " "; //os2 << ")"; } else { ostringstream ose; ose << "ERROR:make_polynomial_proof: Trying to make non-atomic " << e1 << " " << e.isNot() << std::endl; ose << e << std::endl; print_error( ose.str().c_str(), cout ); return NULL; } } cvc3-2.4.1/src/search/decision_engine.cpp0000664000175400017540000001063210466450543020151 0ustar mdetersmdeters/*****************************************************************************/ /*! * \file decision_engine.cpp * \brief Decision Engine * * Author: Clark Barrett * * Created: Sun Jul 13 22:44:55 2003 * *
* * License to use, copy, modify, sell and/or distribute this software * and its documentation for any purpose is hereby granted without * royalty, subject to the terms and conditions defined in the \ref * LICENSE file provided with this distribution. * *
* */ /*****************************************************************************/ #include "decision_engine.h" #include "theory_core.h" #include "search.h" using namespace std; using namespace CVC3; DecisionEngine::DecisionEngine(TheoryCore* core, SearchImplBase* se) : d_core(core), d_se(se), d_splitters(core->getCM()->getCurrentContext()), d_splitterCount(core->getStatistics().counter("splitters")) { IF_DEBUG(d_splitters.setName("CDList[SearchEngineDefault.d_splitters]");) } /*****************************************************************************/ /*! * Function: DecisionEngine::findSplitterRec * * Author: Clark Barrett * * Created: Sun Jul 13 22:47:06 2003 * * Search the expression e (depth-first) for an atomic formula. Note that in * order to support the "simplify in-place" option, each sub-expression is * checked to see if it has a find pointer, and if it does, the find is * followed instead of continuing to recurse on the given expression. * \return a NULL expr if no atomic formula is found. */ /*****************************************************************************/ Expr DecisionEngine::findSplitterRec(const Expr& e) { Expr best; if(d_visited.count(e) > 0) return d_visited[e]; if (e.isTrue() || e.isFalse() || e.isAtomic() || !d_se->isGoodSplitter(e)) { d_visited[e] = best; return best; } if (e.isAbsAtomicFormula()) { d_visited[e] = e; return e; } ExprMap::iterator it = d_bestByExpr.find(e); if (it != d_bestByExpr.end()) { d_visited[e] = it->second; return it->second; } vector order(e.arity()); int i = 0; if (e.isITE()) { order[i++] = 0; order[i++] = 1;//e.getHighestKid(); // always 1 or 2 order[i++] = 2;//3 - e.getHighestKid(); } else { if (e.arity() > 0) { order[i++] = 0;//e.getHighestKid(); for (int k = 0; k < e.arity(); ++k) if (k != 0)//e.getHighestKid()) order[i++] = k; } } for (int k = 0; k < e.arity(); k++) { Expr splitter = findSplitterRec(d_core->findExpr(e[order[k]])); if (!splitter.isNull() && (best.isNull() || isBetter(splitter, best))) best = splitter; } d_bestByExpr[e] = best; d_visited[e] = best; return best; } /*****************************************************************************/ /*! * Function: DecisionEngine::pushDecision * * Author: Clark Barrett * * Created: Sun Jul 13 22:55:16 2003 * * \param splitter * \param whichCase If true, increment the splitter count and assert the * splitter. If false, do NOT increment the splitter count and assert the * negation of the splitter. Defaults to true. */ /*****************************************************************************/ void DecisionEngine::pushDecision(Expr splitter, bool whichCase) { string stCase = whichCase ? "TRUE" : "FALSE"; if (whichCase) d_splitterCount++; d_core->getCM()->push(); TRACE("search trace", "Asserting splitter("+stCase+"): ", splitter, ""); TRACE("search", "Asserting splitter("+stCase+"): ", splitter, ""); d_splitters.push_back(splitter); if (!whichCase) splitter = splitter.negate(); Theorem thm = d_se->newIntAssumption(splitter); d_core->addFact(thm); // Search engine needs to know what original facts it derived or // split on, so that we don't split on them twice. addFact() may // simplify these facts before calling addLiteralFact() and lose // this information. There is no reason to add non-literals though, // as we never split on them directly. if(thm.getExpr().isAbsLiteral()) d_se->addLiteralFact(thm); } void DecisionEngine::popDecision() { d_core->getCM()->pop(); TRACE("search trace", "Pop: scope level =", d_core->getCM()->scopeLevel(), ""); } void DecisionEngine::popTo(int dl) { d_core->getCM()->popto(dl); TRACE("search trace", "Popto: scope level =", d_core->getCM()->scopeLevel(), ""); } Expr DecisionEngine::lastSplitter() { return d_splitters.back(); } cvc3-2.4.1/src/search/search_theorem_producer.cpp0000664000175400017540000013247611363704204021726 0ustar mdetersmdeters/*****************************************************************************/ /*! * \file search_theorem_producer.cpp * \brief Implementation of the proof rules for the simple search engine * * Author: Sergey Berezin * * Created: Mon Feb 24 14:51:51 2003 * *
* * License to use, copy, modify, sell and/or distribute this software * and its documentation for any purpose is hereby granted without * royalty, subject to the terms and conditions defined in the \ref * LICENSE file provided with this distribution. * *
* */ /*****************************************************************************/ #include "search.h" #include "theory_core.h" #include "theorem_manager.h" #include "common_proof_rules.h" #include "command_line_flags.h" #include "theory_arith.h" // UNCOMMENT THIS FOR LFSC #include "LFSCPrinter.h" // by liana for LFSC conversion #define _CVC3_TRUSTED_ #include "search_theorem_producer.h" using namespace std; using namespace CVC3; ///////////////////////////////////////////////////////////////////////////// // class SearchEngine trusted methods ///////////////////////////////////////////////////////////////////////////// SearchEngineRules* SearchEngine::createRules() { return new SearchEngineTheoremProducer(d_core->getTM()); } // hack for printing original assumptions in LFSC by liana bool lfsc_called = false; SearchEngine* search_engine; SearchEngineRules* SearchEngine::createRules(SearchEngine* s_eng) { search_engine = s_eng; return new SearchEngineTheoremProducer(d_core->getTM()); } SearchEngineTheoremProducer::SearchEngineTheoremProducer(TheoremManager* tm) : TheoremProducer(tm), d_commonRules(tm->getRules()) { } ///////////////////////////////////////////////////////////////////////////// // Proof rules ///////////////////////////////////////////////////////////////////////////// // Proof by contradiction: !A |- FALSE ==> |- A. "!A" doesn't // have to be present in the assumptions. Theorem SearchEngineTheoremProducer::proofByContradiction(const Expr& a, const Theorem& pfFalse) { if(CHECK_PROOFS) CHECK_SOUND(pfFalse.getExpr().isFalse(), "proofByContradiction: pfFalse = : " + pfFalse.toString()); Expr not_a(!a); Assumptions assump(pfFalse.getAssumptionsRef() - not_a); Proof pf; if(withProof()) { // TODO: optimize with 1 traversal? Theorem thm(pfFalse.getAssumptionsRef()[not_a]); Proof u; // proof label for !aLFSCL if(!thm.isNull()) u = thm.getProof(); // Proof compaction: if u is Null, use "FALSE => A" rule if(u.isNull()){ pf = newPf("false_implies_anything", a, pfFalse.getProof()); if(!lfsc_called){ satProof(a, pf); } } else pf = newPf("pf_by_contradiction", a, // LAMBDA-abstraction (LAMBDA (u: !a): pfFalse) newPf(u, not_a, pfFalse.getProof())); } return newTheorem(a, assump, pf); } // Similar rule, only negation introduction: // A |- FALSE ==> !A Theorem SearchEngineTheoremProducer::negIntro(const Expr& not_a, const Theorem& pfFalse) { if(CHECK_PROOFS) { CHECK_SOUND(pfFalse.getExpr().isFalse(), "negIntro: pfFalse = : " + pfFalse.toString()); CHECK_SOUND(not_a.isNot(), "negIntro: not_a = "+not_a.toString()); } Expr a(not_a[0]); Assumptions assump(pfFalse.getAssumptionsRef() - a); Proof pf; if(withProof()) { Theorem thm(pfFalse.getAssumptionsRef()[a]); Proof u; // proof label for 'a' if(!thm.isNull()) u = thm.getProof(); // Proof compaction: if u is Null, use "FALSE => !A" rule if(u.isNull()) pf = newPf("false_implies_anything", not_a, pfFalse.getProof()); else pf = newPf("neg_intro", not_a, // LAMBDA-abstraction (LAMBDA (u: a): pfFalse) newPf(u, a, pfFalse.getProof())); } return newTheorem(not_a, assump, pf); } // Case split: u1:A |- C, u2:!A |- C ==> |- C Theorem SearchEngineTheoremProducer::caseSplit(const Expr& a, const Theorem& a_proves_c, const Theorem& not_a_proves_c) { Expr c(a_proves_c.getExpr()); if(CHECK_PROOFS) { CHECK_SOUND(c == not_a_proves_c.getExpr(), "caseSplit: conclusions differ:\n positive case C = " + c.toString() + "\n negative case C = " + not_a_proves_c.getExpr().toString()); // The opposite assumption should not appear in the theorems // Actually, this doesn't violate soundness, no reason to check // CHECK_SOUND(a_proves_c.getAssumptions()[!a].isNull(), // "caseSplit: wrong assumption: " + (!a).toString() // +"\n in "+a_proves_c.toString()); // CHECK_SOUND(not_a_proves_c.getAssumptions()[a].isNull(), // "caseSplit: wrong assumption: " + a.toString() // +"\n in "+not_a_proves_c.toString()); } const Assumptions& a1(a_proves_c.getAssumptionsRef()); const Assumptions& a2(not_a_proves_c.getAssumptionsRef()); Assumptions a3 = a1 - a; Assumptions a4 = a2 - !a; // Proof compaction: if either theorem proves C without a or !a, // then just use that theorem. This only works if assumptions are // active. if (a1 == a3) return a_proves_c; if (a2 == a4) return not_a_proves_c; // No easy way out. Do the work. Proof pf; a3.add(a4); if(withProof()) { // Create lambda-abstractions vector pfs; pfs.push_back(newPf(a1[a].getProof(), a, a_proves_c.getProof())); pfs.push_back(newPf(a2[!a].getProof(), !a, not_a_proves_c.getProof())); pf = newPf("case_split", a, c, pfs); } return newTheorem(c, a3, pf); } // Conflict clause rule: // Gamma, A_1,...,A_n |- B ==> Gamma |- (OR B A_1 ... A_n) // The assumptions A_i are given by the vector 'lits'. // If B==FALSE, it is omitted from the result. // NOTE: here "!A_i" means an inverse of A_i, not just a negation. // That is, if A_i is NOT C, then !A_i is C. // verification function used by conflictClause void SearchEngineTheoremProducer::verifyConflict(const Theorem& thm, TheoremMap& m) { const Assumptions& a(thm.getAssumptionsRef()); const Assumptions::iterator iend = a.end(); for (Assumptions::iterator i = a.begin(); i != iend; ++i) { CHECK_SOUND(!i->isNull(), "SearchEngineTheoremProducer::conflictClause: " "Found null theorem"); if (!i->isRefl() && !i->isFlagged()) { i->setFlag(); if (m.count(*i) == 0) { CHECK_SOUND(!i->isAssump(), "SearchEngineTheoremProducer::conflictClause: " "literal and gamma sets do not form a complete " "cut of Theorem assumptions. Stray theorem: \n" +i->toString()); verifyConflict(*i, m); } else { m[*i] = true; } } } } Theorem SearchEngineTheoremProducer:: conflictClause(const Theorem& thm, const vector& lits, const vector& gamma) { // TRACE("search proofs", "conflictClause(", thm.getExpr(), ") {"); IF_DEBUG(if(debugger.trace("search proofs")) { ostream& os = debugger.getOS(); os << "lits = ["; for(vector::const_iterator i=lits.begin(), iend=lits.end(); i!=iend; ++i) os << i->getExpr() << ",\n"; os << "]\n\ngamma = ["; for(vector::const_iterator i=gamma.begin(), iend=gamma.end(); i!=iend; ++i) os << i->getExpr() << ",\n"; os << "]" << endl; }); bool checkProofs(CHECK_PROOFS); // This rule only makes sense when runnnig with assumptions if(checkProofs) { CHECK_SOUND(withAssumptions(), "conflictClause: called while running without assumptions"); } // Assumptions aOrig(thm.getAssumptions()); vector literals; vector u; // Vector of proof labels literals.reserve(lits.size() + 1); u.reserve(lits.size()); const vector::const_iterator iend = lits.end(); for(vector::const_iterator i=lits.begin(); i!=iend; ++i) { Expr neg(i->getExpr().negate()); literals.push_back(neg); if(withProof()) u.push_back(i->getProof()); } if(checkProofs) { TheoremMap m; // TRACE_MSG("search proofs", "adding gamma to m: {"); for(vector::const_iterator i = gamma.begin(); i != gamma.end(); ++i) { // TRACE("search proofs", "m[", *i, "]"); m[*i] = false; } // TRACE_MSG("search proofs", "}"); for(vector::const_iterator i = lits.begin(); i!=iend; ++i) { // TRACE("search proofs", "check lit: ", *i, ""); CHECK_SOUND(m.count(*i) == 0, "SearchEngineTheoremProducer::conflictClause: " "literal and gamma sets are not disjoint: lit = " +i->toString()); m[*i] = false; } thm.clearAllFlags(); verifyConflict(thm, m); TheoremMap::iterator t = m.begin(), tend = m.end(); for (; t != tend; ++t) { CHECK_SOUND(t->second == true, "SearchEngineTheoremProducer::conflictClause: " "literal or gamma set contains extra element : " + t->first.toString()); } } Assumptions a(gamma); if(!thm.getExpr().isFalse()) literals.push_back(thm.getExpr()); Proof pf; if(withProof()) { if(lits.size()>0) { vector assump; // If assumptions are not leaves, we need to create new // variables for them and substitute them for their proofs in // the proof term ExprHashMap subst; DebugAssert(u.size() == lits.size(), ""); for(size_t i=0, iend=lits.size(); i ", res.getExpr(), " }"); return res; } // Theorem // SearchEngineTheoremProducer:: // conflictClause(const Theorem& thm, const vector& lits) { // bool checkProofs(CHECK_PROOFS); // // This rule only makes sense when runnnig with assumptions // if(checkProofs) { // CHECK_SOUND(withAssumptions(), // "conflictClause: called while running without assumptions"); // } // Assumptions aOrig(thm.getAssumptions()); // vector literals; // vector negations; // vector u; // Vector of proof labels // literals.reserve(lits.size() + 1); // negations.reserve(lits.size()); // u.reserve(lits.size()); // for(vector::const_iterator i=lits.begin(), iend=lits.end(); // i!=iend; ++i) { // Expr neg(i->isNot()? (*i)[0] : !(*i)); // if(checkProofs) // CHECK_SOUND(!aOrig[neg].isNull(), // "SearchEngineTheoremProducer::conflictClause: " // "literal is not in the set of assumptions: neg = " // +neg.toString() + "\n Theorem = " + thm.toString()); // literals.push_back(*i); // negations.push_back(neg); // if(withProof()) u.push_back(aOrig[neg].getProof()); // } // Assumptions a = aOrig - negations; // if(!thm.getExpr().isFalse()) // literals.push_back(thm.getExpr()); // Proof pf; // if(withProof()) { // if(lits.size()>0) // pf = newPf("conflict_clause", newPf(u, literals, thm.getProof())); // else // pf = newPf("false_to_empty_or", thm.getProof()); // } // // Use ExprManager in newExpr, since literals may be empty // return newTheorem(Expr(d_em, OR, literals), a, pf); // } // "Cut" rule: { G_i |- A_i }; G', { A_i } |- B ==> union(G_i)+G' |- B. Theorem SearchEngineTheoremProducer:: cutRule(const vector& thmsA, const Theorem& as_prove_b) { if(CHECK_PROOFS) CHECK_SOUND(withAssumptions(), "cutRule called without assumptions activated"); // Optimization: use only those theorems that occur in B's assumptions. // *** No, take it back, it's a mis-optimization. Most of the time, // cutRule is applied when we *know* thmsA are present in the // assumptions of 'as_proof_b'. Proof pf; vector exprs; exprs.reserve(thmsA.size() + 1); const vector::const_iterator iend = thmsA.end(); for(vector::const_iterator i=thmsA.begin(); i!=iend; ++i) { exprs.push_back(i->getExpr()); } Assumptions a(thmsA); // add the As a.add(as_prove_b.getAssumptionsRef() - exprs); // Add G' if(withProof()) { vector pfs; pfs.reserve(thmsA.size() + 1); for(vector::const_iterator i = thmsA.begin(); i != iend; ++i) { pfs.push_back(i->getProof()); } exprs.push_back(as_prove_b.getExpr()); pfs.push_back(as_prove_b.getProof()); pf = newPf("cut_rule",exprs,pfs); } return newTheorem(as_prove_b.getExpr(), a, pf); } void SearchEngineTheoremProducer::checkSoundNoSkolems(const Expr& e, ExprMap& visited, const ExprMap& skolems) { if(visited.count(e)>0) return; else visited[e] = true; CHECK_SOUND(skolems.count(e) == 0, "skolem constant found in axioms of false theorem: " + e.toString()); for(Expr::iterator it = e.begin(), end = e.end(); it!= end; ++it) checkSoundNoSkolems(*it, visited, skolems); if(e.getKind() == FORALL || e.getKind() == EXISTS) checkSoundNoSkolems(e.getBody(), visited, skolems); } void SearchEngineTheoremProducer::checkSoundNoSkolems(const Theorem& t, ExprMap& visited, const ExprMap& skolems) { if(t.isRefl() || t.isFlagged()) return; t.setFlag(); if(t.isAssump()) checkSoundNoSkolems(t.getExpr(), visited, skolems); else { const Assumptions& a(t.getAssumptionsRef()); Assumptions::iterator it = a.begin(), end = a.end(); for(; it!=end; ++it) checkSoundNoSkolems(*it, visited, skolems); } } /*! Eliminate skolem axioms: * Gamma, Delta |- false => Gamma|- false * where Delta is a set of skolem axioms {|-Exists(x) phi (x) => phi(c)} * and gamma does not contain any of the skolem constants c. */ Theorem SearchEngineTheoremProducer::eliminateSkolemAxioms(const Theorem& tFalse, const std::vector& delta) { TRACE("skolem", "=>eliminateSkolemAxioms ", delta.size(), "{"); if(delta.empty()) { TRACE("skolem", "eliminateSkolemAxioms","" , "}"); return tFalse; } const Expr& falseExpr = tFalse.getExpr(); if(CHECK_PROOFS) { CHECK_SOUND(falseExpr.isFalse(), "eliminateSkolemAxiom called on non-false theorem"); ExprMap visited; ExprMap skolems; vector::const_iterator it = delta.begin(), end = delta.end(); for(; it!=end; ++it) { CHECK_SOUND(it->isRewrite(), "eliminateSkolemAxioms(): Skolem axiom is not " "an IFF: "+it->toString()); const Expr& ex = it->getLHS(); CHECK_SOUND(ex.isExists(), "Did not receive skolem axioms in Delta" " of eliminateSkolemAxioms" + it->toString()); // Collect the Skolem constants for further soundness checks for(unsigned int j=0; jnewLeafExpr(sk_var.mkOp()); } skolems[sk_var] = true; TRACE("skolem", ">> Eliminating variable: ", sk_var, "<<"); } } tFalse.clearAllFlags(); checkSoundNoSkolems(tFalse, visited, skolems); } Proof pf; if(!withProof()) return tFalse; else { Proof origFalse = tFalse.getProof(); std::vectorskolemizeLabels; std::vector exprs; for(unsigned int i=0; i& thms, const Theorem& clause, unsigned i) { Expr e(clause.getExpr()); if(CHECK_PROOFS) { // Soundness check: first, check the form of the 'clause' theorem CHECK_SOUND(e.isOr() && e.arity() > (int)i, "SearchEngineTheoremProducer::unitProp: bad theorem or i=" +int2string(i)+" > arity="+int2string(e.arity()) +" in clause = " + clause.toString()); // Now, check correspondence of thms to the disjunction CHECK_SOUND(((int)thms.size()) == e.arity() - 1, "SearchEngineTheoremProducer::unitProp: " "wrong number of theorems" "\n thms.size = " + int2string(thms.size()) +"\n clause.arity = " + int2string(e.arity())); for(unsigned j=0,k=0; j pfs; vector exprs; exprs.push_back(andr_th.getExpr()); exprs.push_back(b_th.getExpr()); pfs.push_back(andr_th.getProof()); pfs.push_back(b_th.getProof()); // can we note which branch to take? pf = newPf("prop_andr_af", exprs, pfs); } return newTheorem(andr_e[0].negate(), a, pf); } Theorem SearchEngineTheoremProducer::propAndrAT(const Theorem& andr_th, const Theorem& l_th, const Theorem& r_th) { const Expr& andr_e(andr_th.getExpr()); if(CHECK_PROOFS) { CHECK_SOUND(andr_e.getKind() == AND_R && l_th.proves(andr_e[1]) && r_th.proves(andr_e[2]), "SearchEngineTheoremProducer::propAndrAT"); } Assumptions a(andr_th, l_th); a.add(r_th); Proof pf; if(withProof()) { vector pfs; vector exprs; exprs.push_back(andr_th.getExpr()); exprs.push_back(l_th.getExpr()); exprs.push_back(r_th.getExpr()); pfs.push_back(andr_th.getProof()); pfs.push_back(l_th.getProof()); pfs.push_back(r_th.getProof()); pf = newPf("prop_andr_at", exprs, pfs); } return newTheorem(andr_e[0], a, pf); } void SearchEngineTheoremProducer::propAndrLRT(const Theorem& andr_th, const Theorem& a_th, Theorem* l_th, Theorem* r_th) { const Expr& andr_e(andr_th.getExpr()); if(CHECK_PROOFS) { CHECK_SOUND(andr_e.getKind() == AND_R && a_th.proves(andr_e[0]), "SearchEngineTheoremProducer::propAndrLRT"); } Assumptions a(andr_th, a_th); Proof pf; if(withProof()) { vector pfs; vector exprs; exprs.push_back(andr_th.getExpr()); exprs.push_back(a_th.getExpr()); pfs.push_back(andr_th.getProof()); pfs.push_back(a_th.getProof()); pf = newPf("prop_andr_lrt", exprs, pfs); } if (l_th) *l_th = newTheorem(andr_e[1], a, pf); if (r_th) *r_th = newTheorem(andr_e[2], a, pf); } Theorem SearchEngineTheoremProducer::propAndrLF(const Theorem& andr_th, const Theorem& a_th, const Theorem& r_th) { const Expr& andr_e(andr_th.getExpr()); if(CHECK_PROOFS) { CHECK_SOUND(andr_e.getKind() == AND_R && a_th.refutes(andr_e[0]) && r_th.proves(andr_e[2]), "SearchEngineTheoremProducer::propAndrLF"); } Assumptions a(andr_th, a_th); a.add(r_th); Proof pf; if(withProof()) { vector pfs; vector exprs; exprs.push_back(andr_th.getExpr()); exprs.push_back(a_th.getExpr()); exprs.push_back(r_th.getExpr()); pfs.push_back(andr_th.getProof()); pfs.push_back(a_th.getProof()); pfs.push_back(r_th.getProof()); pf = newPf("prop_andr_lf", exprs, pfs); } return newTheorem(andr_e[1].negate(), a, pf); } Theorem SearchEngineTheoremProducer::propAndrRF(const Theorem& andr_th, const Theorem& a_th, const Theorem& l_th) { const Expr& andr_e(andr_th.getExpr()); if(CHECK_PROOFS) { CHECK_SOUND(andr_e.getKind() == AND_R && a_th.refutes(andr_e[0]) && l_th.proves(andr_e[1]), "SearchEngineTheoremProducer::propAndrRF"); } Assumptions a(andr_th, a_th); a.add(l_th); Proof pf; if(withProof()) { vector pfs; vector exprs; exprs.push_back(andr_th.getExpr()); exprs.push_back(a_th.getExpr()); exprs.push_back(l_th.getExpr()); pfs.push_back(andr_th.getProof()); pfs.push_back(a_th.getProof()); pfs.push_back(l_th.getProof()); pf = newPf("prop_andr_rf", exprs, pfs); } return newTheorem(andr_e[2].negate(), a, pf); } Theorem SearchEngineTheoremProducer::confAndrAT(const Theorem& andr_th, const Theorem& a_th, bool left, const Theorem& b_th) { const Expr& andr_e(andr_th.getExpr()); if(CHECK_PROOFS) { CHECK_SOUND(andr_e.getKind() == AND_R && a_th.proves(andr_e[0]) && ((left && b_th.refutes(andr_e[1])) || (!left && b_th.refutes(andr_e[2]))), "SearchEngineTheoremProducer::confAndrAT"); } Assumptions a(andr_th, a_th); a.add(b_th); Proof pf; if(withProof()) { vector pfs; vector exprs; exprs.push_back(andr_th.getExpr()); exprs.push_back(a_th.getExpr()); exprs.push_back(b_th.getExpr()); pfs.push_back(andr_th.getProof()); pfs.push_back(a_th.getProof()); pfs.push_back(b_th.getProof()); // can we note which branch to take? pf = newPf("conf_andr_at", exprs, pfs); } return newTheorem(d_em->falseExpr(), a, pf); } Theorem SearchEngineTheoremProducer::confAndrAF(const Theorem& andr_th, const Theorem& a_th, const Theorem& l_th, const Theorem& r_th) { const Expr& andr_e(andr_th.getExpr()); if(CHECK_PROOFS) { CHECK_SOUND(andr_e.getKind() == AND_R && a_th.refutes(andr_e[0]) && l_th.proves(andr_e[1]) && r_th.proves(andr_e[2]), "SearchEngineTheoremProducer::confAndrAF"); } Assumptions a; Proof pf; if(withAssumptions()) { a.add(andr_th); a.add(a_th); a.add(l_th); a.add(r_th); } if(withProof()) { vector pfs; vector exprs; exprs.push_back(andr_th.getExpr()); exprs.push_back(a_th.getExpr()); exprs.push_back(l_th.getExpr()); exprs.push_back(r_th.getExpr()); pfs.push_back(andr_th.getProof()); pfs.push_back(a_th.getProof()); pfs.push_back(l_th.getProof()); pfs.push_back(r_th.getProof()); pf = newPf("conf_andr_af", exprs, pfs); } return newTheorem(d_em->falseExpr(), a, pf); } Theorem SearchEngineTheoremProducer::propIffr(const Theorem& iffr_th, int p, const Theorem& a_th, const Theorem& b_th) { int a(-1), b(-1); if(CHECK_PROOFS) CHECK_SOUND(p == 0 || p == 1 || p == 2, "SearchEngineTheoremProducer::propIffr: p=" +int2string(p)); switch (p) { case 0: a = 1; b = 2; break; case 1: a = 0; b = 2; break; case 2: a = 0; b = 1; break; } const Expr& iffr_e(iffr_th.getExpr()); bool v0 = a_th.proves(iffr_e[a]); bool v1 = b_th.proves(iffr_e[b]); if (CHECK_PROOFS) { CHECK_SOUND(iffr_e.getKind() == IFF_R && (v0 || a_th.refutes(iffr_e[a])) && (v1 || b_th.refutes(iffr_e[b])), "SearchEngineTheoremProducer::propIffr"); } Assumptions aa; Proof pf; if (withAssumptions()) { aa.add(iffr_th); aa.add(a_th); aa.add(b_th); } if (withProof()) { vector pfs; vector exprs; exprs.push_back(iffr_th.getExpr()); exprs.push_back(a_th.getExpr()); exprs.push_back(b_th.getExpr()); pfs.push_back(iffr_th.getProof()); pfs.push_back(a_th.getProof()); pfs.push_back(b_th.getProof()); pf = newPf("prop_iffr", exprs, pfs); } return newTheorem(v0 == v1 ? iffr_e[p] : iffr_e[p].negate(), aa, pf); } Theorem SearchEngineTheoremProducer::confIffr(const Theorem& iffr_th, const Theorem& i_th, const Theorem& l_th, const Theorem& r_th) { const Expr& iffr_e(iffr_th.getExpr()); bool v0 = i_th.proves(iffr_e[0]); bool v1 = l_th.proves(iffr_e[1]); bool v2 = r_th.proves(iffr_e[2]); if (CHECK_PROOFS) { CHECK_SOUND(iffr_e.getKind() == IFF_R && (v0 || i_th.refutes(iffr_e[0])) && (v1 || l_th.refutes(iffr_e[1])) && (v2 || r_th.refutes(iffr_e[2])) && ((v0 && v1 != v2) || (!v0 && v1 == v2)), "SearchEngineTheoremProducer::confIffr"); } Assumptions a; Proof pf; if (withAssumptions()) { a.add(iffr_th); a.add(i_th); a.add(l_th); a.add(r_th); } if (withProof()) { vector pfs; vector exprs; exprs.push_back(iffr_th.getExpr()); exprs.push_back(i_th.getExpr()); exprs.push_back(l_th.getExpr()); exprs.push_back(r_th.getExpr()); pfs.push_back(iffr_th.getProof()); pfs.push_back(i_th.getProof()); pfs.push_back(l_th.getProof()); pfs.push_back(r_th.getProof()); pf = newPf("conf_iffr", exprs, pfs); } return newTheorem(d_em->falseExpr(), a, pf); } Theorem SearchEngineTheoremProducer::propIterIte(const Theorem& iter_th, bool left, const Theorem& if_th, const Theorem& then_th) { const Expr& iter_e(iter_th.getExpr()); bool v0 = if_th.proves(iter_e[1]); bool v1 = then_th.proves(iter_e[left ? 2 : 3]); if (CHECK_PROOFS) { CHECK_SOUND(iter_e.getKind() == ITE_R && (v0 || if_th.refutes(iter_e[1])) && (v1 || then_th.refutes(iter_e[left ? 2 : 3])) && v0 == left, "SearchEngineTheoremProducer::propIterIte"); } Assumptions a; Proof pf; if (withAssumptions()) { a.add(iter_th); a.add(if_th); a.add(then_th); } if (withProof()) { vector pfs; vector exprs; exprs.push_back(iter_th.getExpr()); exprs.push_back(if_th.getExpr()); exprs.push_back(then_th.getExpr()); pfs.push_back(iter_th.getProof()); pfs.push_back(if_th.getProof()); pfs.push_back(then_th.getProof()); pf = newPf("prop_iter_ite", exprs, pfs); } return newTheorem(v1 ? iter_e[0] : iter_e[0].negate(), a, pf); } void SearchEngineTheoremProducer::propIterIfThen(const Theorem& iter_th, bool left, const Theorem& ite_th, const Theorem& then_th, Theorem* if_th, Theorem* else_th) { const Expr& iter_e(iter_th.getExpr()); bool v0 = ite_th.proves(iter_e[0]); bool v1 = then_th.proves(iter_e[left ? 2 : 3]); if (CHECK_PROOFS) { CHECK_SOUND(iter_e.getKind() == ITE_R && (v0 || ite_th.refutes(iter_e[0])) && (v1 || then_th.refutes(iter_e[left ? 2 : 3])) && v0 != v1, "SearchEngineTheoremProducer::propIterIfThen"); } Assumptions a; Proof pf; if (withAssumptions()) { a.add(iter_th); a.add(ite_th); a.add(then_th); } if (withProof()) { vector pfs; vector exprs; exprs.push_back(iter_th.getExpr()); exprs.push_back(ite_th.getExpr()); exprs.push_back(then_th.getExpr()); pfs.push_back(iter_th.getProof()); pfs.push_back(ite_th.getProof()); pfs.push_back(then_th.getExpr()); pf = newPf("prop_iter_if_then", exprs, pfs); } if (if_th) *if_th = newTheorem(left ? iter_e[1].negate() : iter_e[1], a, pf); if (else_th) *else_th = newTheorem(v0 ? iter_e[left ? 3 : 2] : iter_e[left ? 3 : 2].negate(), a, pf); } Theorem SearchEngineTheoremProducer::propIterThen(const Theorem& iter_th, const Theorem& ite_th, const Theorem& if_th) { const Expr& iter_e(iter_th.getExpr()); bool v0 = ite_th.proves(iter_e[0]); bool v1 = if_th.proves(iter_e[1]); if (CHECK_PROOFS) { CHECK_SOUND(iter_e.getKind() == ITE_R && (v0 || ite_th.refutes(iter_e[0])) && (v1 || if_th.refutes(iter_e[1])), "SearchEngineTheoremProducer::propIterThen"); } Assumptions a; Proof pf; if (withAssumptions()) { a.add(iter_th); a.add(ite_th); a.add(if_th); } if (withProof()) { vector pfs; vector exprs; exprs.push_back(iter_th.getExpr()); exprs.push_back(ite_th.getExpr()); exprs.push_back(if_th.getExpr()); pfs.push_back(iter_th.getProof()); pfs.push_back(ite_th.getProof()); pfs.push_back(if_th.getExpr()); pf = newPf("prop_iter_then", exprs, pfs); } return newTheorem(v1 ? (v0 ? iter_e[2] : iter_e[2].negate()) : (v0 ? iter_e[3] : iter_e[3].negate()), a, pf); } Theorem SearchEngineTheoremProducer::confIterThenElse(const Theorem& iter_th, const Theorem& ite_th, const Theorem& then_th, const Theorem& else_th) { const Expr& iter_e(iter_th.getExpr()); bool v0 = ite_th.proves(iter_e[0]); bool v1 = then_th.proves(iter_e[2]); bool v2 = else_th.proves(iter_e[3]); if (CHECK_PROOFS) { CHECK_SOUND(iter_e.getKind() == ITE_R && (v0 || ite_th.refutes(iter_e[0])) && (v1 || then_th.refutes(iter_e[2])) && (v2 || else_th.refutes(iter_e[3])) && ((v0 && !v1 && !v2) || (!v0 && v1 && v2)), "SearchEngineTheoremProducer::confIterThenElse"); } Assumptions a; Proof pf; if (withAssumptions()) { a.add(iter_th); a.add(ite_th); a.add(then_th); a.add(else_th); } if (withProof()) { vector pfs; vector exprs; exprs.push_back(iter_th.getExpr()); exprs.push_back(ite_th.getExpr()); exprs.push_back(then_th.getExpr()); exprs.push_back(else_th.getExpr()); pfs.push_back(iter_th.getProof()); pfs.push_back(ite_th.getProof()); pfs.push_back(then_th.getExpr()); pfs.push_back(else_th.getExpr()); pf = newPf("conf_iter_then_else", exprs, pfs); } return newTheorem(d_em->falseExpr(), a, pf); } Theorem SearchEngineTheoremProducer::confIterIfThen(const Theorem& iter_th, bool left, const Theorem& ite_th, const Theorem& if_th, const Theorem& then_th) { const Expr& iter_e(iter_th.getExpr()); bool v0 = ite_th.proves(iter_e[0]); bool v1 = if_th.proves(iter_e[1]); bool v2 = then_th.proves(iter_e[left ? 2 : 3]); if (CHECK_PROOFS) { CHECK_SOUND(iter_e.getKind() == ITE_R && (v0 || ite_th.refutes(iter_e[0])) && (v1 || if_th.refutes(iter_e[1])) && (v2 || then_th.refutes(iter_e[left ? 2 : 3])) && v1 == left && v0 != v2, "SearchEngineTheoremProducer::confIterThenElse"); } Assumptions a; Proof pf; if (withAssumptions()) { a.add(iter_th); a.add(ite_th); a.add(if_th); a.add(then_th); } if (withProof()) { vector pfs; vector exprs; exprs.push_back(iter_th.getExpr()); exprs.push_back(ite_th.getExpr()); exprs.push_back(if_th.getExpr()); exprs.push_back(then_th.getExpr()); pfs.push_back(iter_th.getProof()); pfs.push_back(ite_th.getProof()); pfs.push_back(if_th.getExpr()); pfs.push_back(then_th.getExpr()); pf = newPf("conf_iter_then_else", exprs, pfs); } return newTheorem(d_em->falseExpr(), a, pf); } // "Conflict" rule (all literals in a clause become FALSE) // { G_j |- !l_j, j in [1..n] } , G |- (OR l_1 ... l_n) ==> FALSE Theorem SearchEngineTheoremProducer::conflictRule(const std::vector& thms, const Theorem& clause) { Expr e(clause.getExpr()); if(CHECK_PROOFS) { // Soundness check: first, check the form of the 'clause' theorem CHECK_SOUND(e.isOr(), "SearchEngineTheoremProducer::unitProp: " "bad theorem in clause = "+clause.toString()); // Now, check correspondence of thms to the disjunction CHECK_SOUND(((int)thms.size()) == e.arity(), "SearchEngineTheoremProducer::conflictRule: " "wrong number of theorems" "\n thms.size = " + int2string(thms.size()) +"\n clause.arity = " + int2string(e.arity())); for(unsigned j=0; jfalseExpr(), a, pf); } /////////////////////////////////////////////////////////////////////// //// Conjunctive Normal Form (CNF) proof rules /////////////////////////////////////////////////////////////////////// Theorem SearchEngineTheoremProducer::andCNFRule(const Theorem& thm) { return opCNFRule(thm, AND, "and_cnf_rule"); } Theorem SearchEngineTheoremProducer::orCNFRule(const Theorem& thm) { return opCNFRule(thm, OR, "or_cnf_rule"); } Theorem SearchEngineTheoremProducer::impCNFRule(const Theorem& thm) { return opCNFRule(thm, IMPLIES, "implies_cnf_rule"); } Theorem SearchEngineTheoremProducer::iffCNFRule(const Theorem& thm) { return opCNFRule(thm, IFF, "iff_cnf_rule"); } Theorem SearchEngineTheoremProducer::iteCNFRule(const Theorem& thm) { return opCNFRule(thm, ITE, "ite_cnf_rule"); } Theorem SearchEngineTheoremProducer::iteToClauses(const Theorem& ite) { const Expr& iteExpr = ite.getExpr(); if(CHECK_PROOFS) { CHECK_SOUND(iteExpr.isITE() && iteExpr.getType().isBool(), "SearchEngineTheoremProducer::iteToClauses("+iteExpr.toString() +")\n Argument must be a Boolean ITE"); } const Expr& cond = iteExpr[0]; const Expr& t1 = iteExpr[1]; const Expr& t2 = iteExpr[2]; Proof pf; if(withProof()) pf = newPf("ite_to_clauses", iteExpr, ite.getProof()); return newTheorem((cond.negate() || t1) && (cond || t2), ite.getAssumptionsRef(), pf); } Theorem SearchEngineTheoremProducer::iffToClauses(const Theorem& iff) { if(CHECK_PROOFS) { CHECK_SOUND(iff.isRewrite() && iff.getLHS().getType().isBool(), "SearchEngineTheoremProducer::iffToClauses("+iff.getExpr().toString() +")\n Argument must be a Boolean IFF"); } const Expr& t1 = iff.getLHS(); const Expr& t2 = iff.getRHS(); Proof pf; if(withProof()) pf = newPf("iff_to_clauses", iff.getExpr(), iff.getProof()); return newTheorem((t1.negate() || t2) && (t1 || t2.negate()), iff.getAssumptionsRef(), pf); } ///////////////////////////////////////////////////////////////////////// //// helper functions for CNF (Conjunctive Normal Form) conversion ///////////////////////////////////////////////////////////////////////// Theorem SearchEngineTheoremProducer::opCNFRule(const Theorem& thm, int kind, const string& ruleName) { TRACE("mycnf", "opCNFRule["+d_em->getKindName(kind)+"](", thm.getExpr(), ") {"); ExprMap localCache; if(CHECK_PROOFS) { Expr phiIffVar = thm.getExpr(); CHECK_SOUND(phiIffVar.isIff(), "SearchEngineTheoremProducer::opCNFRule(" +d_em->getKindName(kind)+"): " "input must be an IFF: thm = " + phiIffVar.toString()); CHECK_SOUND(phiIffVar[0].getKind() == kind, "SearchEngineTheoremProducer::opCNFRule(" +d_em->getKindName(kind)+"): " "input phi has wrong kind: thm = " + phiIffVar.toString()); CHECK_SOUND(phiIffVar[0] != phiIffVar[1], "SearchEngineTheoremProducer::opCNFRule(" +d_em->getKindName(kind)+"): " "wrong input thm = " + phiIffVar.toString()); for(Expr::iterator it=phiIffVar[0].begin(), itend=phiIffVar[0].end(); it!=itend;++it){ CHECK_SOUND(phiIffVar[1] != *it, "SearchEngineTheoremProducer::opCNFRule(" +d_em->getKindName(kind)+"): " "wrong input thm = " + phiIffVar.toString()); } } const Expr& phi = thm.getExpr()[0]; const Expr& phiVar = thm.getExpr()[1]; std::vector boundVars; std::vector boundVarsAndLiterals; std::vector equivs; for(Expr::iterator i=phi.begin(), iend=phi.end(); i != iend; i++) { // First, strip the negation and check if the formula is atomic Expr tmp(*i); while(tmp.isNot()) tmp = tmp[0]; if(tmp.isPropAtom()) boundVarsAndLiterals.push_back(*i); else boundVarsAndLiterals.push_back(findInLocalCache(*i, localCache, boundVars)); } for(ExprMap::iterator it=localCache.begin(), itend=localCache.end(); it != itend; it++) { DebugAssert((*it).second.isIff(), "SearchEngineTheoremProducer::opCNFRule: " + (*it).second.toString()); DebugAssert(!(*it).second[0].isPropLiteral() && (*it).second[1].isAbsLiteral(), "SearchEngineTheoremProducer::opCNFRule: " + (*it).second.toString()); equivs.push_back((*it).second); } DebugAssert(boundVarsAndLiterals.size() == (unsigned)phi.arity(), "SearchEngineTheoremProducer::opCNFRule: " "wrong size of boundvars: phi = " + phi.toString()); DebugAssert(boundVars.size() == equivs.size(), "SearchEngineTheoremProducer::opCNFRule: " "wrong size of boundvars: phi = " + phi.toString()); Expr cnfInput = phi.arity() > 0 ? Expr(phi.getOp(), boundVarsAndLiterals) : phi; Expr result = convertToCNF(phiVar, cnfInput); if(boundVars.size() > 0) result = d_em->newClosureExpr(EXISTS, boundVars, result.andExpr(andExpr(equivs))); Proof pf; if(withProof()) pf = newPf(ruleName, thm.getExpr(), thm.getProof()); Theorem res(newTheorem(result, thm.getAssumptionsRef(), pf)); TRACE("mycnf", "opCNFRule["+d_em->getKindName(kind)+"] => ", res.getExpr(), " }"); return res; } //! produces the CNF for the formula v <==> phi Expr SearchEngineTheoremProducer::convertToCNF(const Expr& v, const Expr & phi) { //we assume that v \iff phi. v is the newVar corresponding to phi Expr::iterator i = phi.begin(), iend = phi.end(); std::vector clauses; std::vector lastClause; switch(phi.getKind()) { case AND: { const Expr& negV = v.negate(); lastClause.push_back(v); for(;i!=iend; ++i) { lastClause.push_back(i->negate()); } clauses.push_back(orExpr(lastClause)); } break; case OR:{ lastClause.push_back(v.negate()); for(;i!=iend; ++i) { clauses.push_back(v.orExpr(i->negate())); lastClause.push_back(*i); } clauses.push_back(orExpr(lastClause)); } break; case IFF: { const Expr& v1 = phi[0]; const Expr& v2 = phi[1]; Expr negV = v.negate(); Expr negv1 = v1.negate(); Expr negv2 = v2.negate(); clauses.push_back(Expr(OR, negV, negv1, v2)); clauses.push_back(Expr(OR, negV, v1, negv2)); clauses.push_back(Expr(OR, v, v1, v2)); clauses.push_back(Expr(OR, v, negv1, negv2)); } break; case IMPLIES:{ const Expr& v1 = phi[0]; const Expr& v2 = phi[1]; Expr negV = v.negate(); Expr negv1 = v1.negate(); Expr negv2 = v2.negate(); clauses.push_back(Expr(OR, negV, negv1, v2)); clauses.push_back(v.orExpr(v1)); clauses.push_back(v.orExpr(negv2)); } break; case ITE: { const Expr& v1 = phi[0]; const Expr& v2 = phi[1]; const Expr& v3 = phi[2]; const Expr& negV = v.negate(); const Expr& negv1 = v1.negate(); const Expr& negv2 = v2.negate(); const Expr& negv3 = v3.negate(); clauses.push_back(Expr(OR, negV, negv1, v2)); clauses.push_back(Expr(OR, negV, v1, v3)); clauses.push_back(Expr(OR, v, negv1, negv2)); clauses.push_back(Expr(OR, v, v1, negv3)); } break; default: DebugAssert(false, "SearchEngineTheoremProducer::convertToCNF: " "bad operator in phi = "+phi.toString()); break; } return andExpr(clauses); } /////////////////////////////////////////////////////////////////////// // helper functions for CNF converters /////////////////////////////////////////////////////////////////////// Expr SearchEngineTheoremProducer::findInLocalCache(const Expr& i, ExprMap& localCache, vector& boundVars) { TRACE("mycnf", "findInLocalCache(", i.toString(), ") { "); Expr boundVar; unsigned int negationDepth = 0; ExprMap::iterator it; Expr phi = i; while(phi.isNot()) { phi = phi[0]; negationDepth++; } it = localCache.find(phi); Expr v; if(it != localCache.end()) { v = ((*it).second)[1]; IF_DEBUG(debugger.counter("CNF Local Cache Hits")++;) } else { v = d_em->newBoundVarExpr(i.getType()); boundVars.push_back(v); localCache[phi] = phi.iffExpr(v); } if(negationDepth % 2 != 0) v = !v; TRACE("mycnf", "findInLocalCache => ", v, " }"); return v; } // for LFSC proof style, by yeting // theorem for minisat generated proofs, by yeting Theorem SearchEngineTheoremProducer::satProof(const Expr& queryExpr, const Proof& satProof) { Proof pf; if(withProof()) pf = newPf("minisat_proof", queryExpr, satProof); if ((d_tm->getFlags()["lfsc-mode"]).getInt()!= 0) { // UNCOMMENT THIS FOR LFSC if(!lfsc_called){ int lfscm = (d_tm->getFlags()["lfsc-mode"]).getInt(); std::vector assumps; search_engine->getUserAssumptions(assumps); Expr pf_expr = pf.getExpr()[2] ; if( lfscm == -1 ){ cout << "CVC3 Proof: "; cout << pf.getExpr() << endl; }else{ LFSCPrinter* lfsc_printer = new LFSCPrinter(pf_expr, queryExpr, assumps, lfscm, d_commonRules); lfsc_printer->print_LFSC(pf_expr); lfsc_called = true; exit( 0 ); } } } return newTheorem(queryExpr, Assumptions::emptyAssump() , pf); } // LocalWords: clc cvc3-2.4.1/src/search/decision_engine.h0000664000175400017540000000436610466450544017626 0ustar mdetersmdeters/*****************************************************************************/ /*! * \file decision_engine.h * * Author: Clark Barrett * * Created: Fri Jul 11 13:04:25 2003 * *
* * License to use, copy, modify, sell and/or distribute this software * and its documentation for any purpose is hereby granted without * royalty, subject to the terms and conditions defined in the \ref * LICENSE file provided with this distribution. * *
* */ /*****************************************************************************/ #ifndef _cvc3__search__decision_engine_h_ #define _cvc3__search__decision_engine_h_ #include "statistics.h" #include "search_fast.h" namespace CVC3 { class DecisionEngine { /***************************************************************************/ /*! *\defgroup DE Decision Engine *\brief Decision Engine, used by Search Engine *\ingroup SE *@{ */ /***************************************************************************/ protected: TheoryCore* d_core; //!< Pointer to core theory SearchImplBase* d_se; //!< Pointer to search engine //! List of currently active splitters CDList d_splitters; //! Total number of splitters StatCounter d_splitterCount; ExprMap d_bestByExpr; //! Visited cache for findSplitterRec traversal. /*! Must be emptied in every findSplitter() call. */ ExprMap d_visited; Expr findSplitterRec(const Expr& e); virtual bool isBetter(const Expr& e1, const Expr& e2) = 0; public: DecisionEngine(TheoryCore* core, SearchImplBase* se); virtual ~DecisionEngine() { } /*! @brief Finds a splitter inside a non const expression. The expression passed in must not be a boolean constant, otherwise a DebugAssert will occur. \return Null Expr if passed in a Null Expr. */ virtual Expr findSplitter(const Expr& e) = 0; //! Push context and record the splitter void pushDecision(Expr splitter, bool whichCase=true); //! Pop last decision (and context) void popDecision(); //! Pop to given scope void popTo(int dl); //! Return the last known splitter. Expr lastSplitter(); //! Search should call this when it derives 'false' virtual void goalSatisfied() = 0; /*@}*/ // End of DE group }; } #endif cvc3-2.4.1/src/search/TReturn.cpp0000664000175400017540000004123211363704204016423 0ustar mdetersmdeters#include "TReturn.h" #include "LFSCUtilProof.h" #include "LFSCLraProof.h" #include "LFSCBoolProof.h" #include "LFSCPrinter.h" TReturn::TReturn(LFSCProof* lfsc_pf, std::vector& L, std::vector& Lused, Rational r, bool hasR, int pvY): d_lfsc_pf(lfsc_pf), d_c( r ), d_provesY(pvY){ d_hasRt = hasR; for( int a=0; a<(int)L.size(); a++ ) d_L.push_back( L[a] ); for( int a=0; a<(int)Lused.size(); a++ ) d_L_used.push_back( Lused[a] ); #ifdef DEBUG_MEM_STATS static int counter = 0; counter++; cout << "make a tret " << counter << std::endl; #endif lcalced = false; } Rational TReturn::mult_rational( TReturn* lhs ) { if( !hasRational() && lhs->hasRational() ) return lhs->mult_rational( this ); else if( hasRational() ){ if( lhs->hasRational() ) return d_c*lhs->d_c; else return d_c; }else return lhs->d_c; } void TReturn::getL( std::vector< int >& lget, std::vector< int >& lgetu ){ #ifndef OPTIMIZE std::vector< int >::iterator i; for( int a=0; a<(int)d_L.size(); a++ ){ i = std::find( lget.begin(), lget.end(), d_L[a] ); if( i==lget.end() ){ lget.push_back( d_L[a] ); } } for( int a=0; a<(int)d_L_used.size(); a++ ){ i = std::find( lgetu.begin(), lgetu.end(), d_L_used[a] ); if( i==lgetu.end() ){ lgetu.push_back( d_L_used[a] ); } } #endif } #ifdef OPTIMIZE void TReturn::calcL( std::vector< int >& lget, std::vector< int >& lgetu ){ if( !lcalced ){ d_L.clear(); d_L_used.clear(); d_lfsc_pf->calcL( d_L, d_L_used ); lcalced = true; } std::vector< int >::iterator i; for( int a=0; a<(int)d_L.size(); a++ ){ i = std::find( lget.begin(), lget.end(), d_L[a] ); if( i==lget.end() ){ lget.push_back( d_L[a] ); } } for( int a=0; a<(int)d_L_used.size(); a++ ){ i = std::find( lgetu.begin(), lgetu.end(), d_L_used[a] ); if( i==lgetu.end() ){ lgetu.push_back( d_L_used[a] ); } } } #endif // make it so that the two TReturns agree on what they are proving // t1 proves pf1, Y( pf1 ), or Y2( pf1 ) // t2 proves pf2, Y( pf2 ), or Y2( pf2 ) // on return, t1->d_proveY should equal t2->d_proveY int TReturn::normalize_tret( const Expr& pf1, TReturn*& t1, const Expr& pf2, TReturn*& t2, bool rev_pol ) { if( t1->getProvesY()!=t2->getProvesY() ) { if( t1->getProvesY()>t2->getProvesY() ) return normalize_tret( pf2, t2, pf1, t1, rev_pol ); else { if( debug_conv ) cout << "normalizing proofs " << t1->getProvesY() << " " << t2->getProvesY() << " " << rev_pol << std::endl; if( t1->getProvesY()==0 && t2->getProvesY()==2 ) normalize_tr( pf1, t1, 2, rev_pol ); if( t1->getProvesY()==1 && t2->getProvesY()==2 ) normalize_tr( pf1, t1, 2, rev_pol ); if( t1->getProvesY()==0 && t2->getProvesY()==1 ){ if( normalize_tr( pf1, t1, 1, rev_pol, false )==-1 ){ //try to go 0 to 1 (optional) if( normalize_tr( pf2, t2, 0, rev_pol, false )==-1 ){ //try to go 1 to 0 immediately (optional) normalize_tr( pf1, t1, 2, rev_pol ); normalize_tr( pf2, t2, 2, rev_pol ); } } } if( t2->getProvesY()==3 ){ normalize_tr( pf1, t1, 3, rev_pol ); } if( t1->getProvesY()!=t2->getProvesY() ){ ostringstream os; os << "ERROR:normalize_tret: Could not normalize proofs " << t1->getProvesY() << " " << t2->getProvesY() << std::endl; os << pf1[0] << " " << pf2[0] << std::endl; print_error( os.str().c_str(), cout ); return -1; }else{ return t1->getProvesY(); } } } return t1->getProvesY(); } int TReturn::normalize_tr( const Expr& pf1, TReturn*& t1, int y, bool rev_pol, bool printErr ) { TReturn* torig = t1; int chOp = t1->getLFSCProof()->getChOp(); std::vector< int > emptyL; std::vector< int > emptyLUsed; t1->getL( emptyL, emptyLUsed ); if( t1->getProvesY()!=y ) { if( debug_conv ){ cout << "normalizing tr " << t1->getProvesY() << " to " << y << " rev_pol = " << rev_pol << std::endl; } Expr e; if( what_is_proven( pf1, e ) ) { e = queryElimNotNot( e ); if( rev_pol ){ if( e.isIff() ){ //cout << "Warning: rev_pol called on IFF, 0 normalize to " << y << std::endl; e = Expr( IFF, e[1], e[0] ); }else if( e.isImpl() ){ e = Expr( IMPLIES, e[1], e[0] ); } } Expr eb = queryAtomic( e, true ); if( y==3 ) { if( t1->getProvesY()!=2 ){ if( normalize_tr( pf1, t1, 2, rev_pol )==-1 ){ return -1; } } if( e.isIff() ){ e = Expr( IMPLIES, e[0], e[1] ); } //clausify what t1 is proving t1 = new TReturn( LFSCClausify::Make( e, t1->getLFSCProof() ), emptyL, emptyLUsed, nullRat, false, 3 ); } else if( y==1 ) { if( t1->getProvesY()==0 || t1->getProvesY()==2 ){ if( can_pnorm( eb ) ) { t1 = new TReturn( LFSCLraPoly::Make( e, t1->getLFSCProof() ), emptyL, emptyLUsed, t1->getRational(), t1->hasRational(), 1 ); }else{ //cout << "nrt kind = " << kind_to_str( eb.getKind() ) << std::endl; } } } else if( y==0 ) { if( is_eq_kind( eb.getKind() ) ){ normalize_to_tf( e, t1, 0 ); }else if( e[0]==e[1] ){ ostringstream os1, os2; os1 << "(iff_refl "; RefPtr< LFSCProof > p = LFSCProofExpr::Make( e[0] ); os2 << ")"; t1 = new TReturn( LFSCProofGeneric::Make( os1.str(), p.get(), os2.str() ), emptyL, emptyLUsed, nullRat, false, 0 ); }else{ if( t1->getProvesY()==1 ){ #ifdef PRINT_MAJOR_METHODS cout << ";[M]: Normalize 1 to 0, iff" << std::endl; #endif if( e[1].isFalse() ) { Expr ea = Expr( NOT, e[0] ); normalize_to_tf( ea, t1, 0 ); ostringstream os1, os2; os1 << "(" << ( e[0].getKind()==NOT ? "not_to_iff" : "iff_not_false" ); os1 << " _ "; os2 << ")"; t1 = new TReturn( LFSCProofGeneric::Make( os1.str(), t1->getLFSCProof(), os2.str() ), emptyL, emptyLUsed, nullRat, false, 0 ); } else if( e[1].isTrue() ) { normalize_to_tf( e[0], t1, 0 ); ostringstream os1, os2; os1 << "(iff_true _ "; os2 << ")"; t1 = new TReturn( LFSCProofGeneric::Make( os1.str(), t1->getLFSCProof(), os2.str() ), emptyL, emptyLUsed, nullRat, false, 0 ); } else if( printErr ) { TReturn* torg = new TReturn( LFSCPfVar::Make( "@V", 0 ), emptyL, emptyLUsed, t1->getRational(), t1->hasRational(), t1->getProvesY() ); TReturn *ti1, *ti2; TReturn* to = torg; if( normalize_tr( pf1, to, 2, rev_pol ) ) { ti1 = to; to = torg; if( normalize_tr( pf1, to, 2, !rev_pol ) ) { ti2 = to; ostringstream os1, os2, os3, os4; os1 << "(impl_elim _ _ "; os2 << "(impl_intro _ _ (\\ @V0 (iff_intro _ _ "; os3 << " "; os4 << "))))"; std::vector< RefPtr< LFSCProof > > pfs; pfs.push_back( t1->getLFSCProof() ); pfs.push_back( ti1->getLFSCProof() ); pfs.push_back( ti2->getLFSCProof() ); std::vector< string > strs; strs.push_back( os1.str() ); strs.push_back( os2.str() ); strs.push_back( os3.str() ); strs.push_back( os4.str() ); t1 = new TReturn( LFSCProofGeneric::Make( pfs, strs ), emptyL, emptyLUsed, nullRat, false, 0 ); } } } } } } else if( y==2 ) { if( t1->getProvesY()==0 ) { RefPtr< LFSCProof > p; if( e.isIff() ){ ostringstream os1, os2; os1 << "(iff_elim_1 _ _ "; os2 << ")"; p = LFSCProofGeneric::Make( os1.str(), t1->getLFSCProof(), os2.str() ); }else{ //cout << "actually I can just drop it " << e << std::endl; p = t1->getLFSCProof(); } t1 = new TReturn( p.get(), emptyL, emptyLUsed, nullRat, false, 2 ); } else if( t1->getProvesY()==1 ) { if( is_eq_kind( eb.getKind() ) ){ normalize_to_tf( e, t1, 2 ); }else if( e.isIff() || e.isImpl() ){ Expr eatom1 = queryAtomic( e[0] ); Expr eatom2 = queryAtomic( e[1] ); //Expr ebase1 = queryAtomic( eatom1, true ); //Expr ebase2 = queryAtomic( eatom2, true ); int val1 = queryM( e[0] ); int val2 = queryM( e[1] ); int k1 = eatom1.getKind(); int k2 = eatom2.getKind(); if( e[0]==e[1] ){ ostringstream os; os << "(impl_refl_atom" << (val1<0 ? "_not" : "" ); os << " _ _ @a" << abs( val1 ) << ")"; //d_formulas_printed[queryAtomic( e[0], true )] = true; t1 = new TReturn( LFSCProofGeneric::MakeStr( os.str().c_str()), emptyL, emptyLUsed, nullRat, false, 2 ); }else if( eatom2.isFalse() || eatom2.isTrue() ){ if( eatom1.getKind()==eatom2.getKind() ) { #ifdef PRINT_MAJOR_METHODS cout << ";[M]: Normalize 1 to 2, iff/impl double logical iff" << std::endl; #endif if( e[0]!=e[1] ){ ostringstream ose; ose << "Warning: normalize logical atoms, not equal "; ose << e[0] << " " << e[1] << std::endl; print_error( ose.str().c_str(), cout ); } ostringstream os; os << "impl_refl_" << ( eatom2.isFalse() ? "false" : "true" ); t1 = new TReturn( LFSCProofGeneric::MakeStr(os.str().c_str()), emptyL, emptyLUsed, nullRat, false, 2 ); } else if( eatom2.isTrue() ) { normalize_to_tf( e[0], t1, 2 ); ostringstream oss1, oss2; oss1 << "(iff_true_impl _ "; oss2 << ")"; t1 = new TReturn( LFSCProofGeneric::Make( oss1.str(), t1->getLFSCProof(), oss2.str() ), emptyL, emptyLUsed, nullRat, false, 2 ); } else if( eatom2.isFalse() ) { #ifdef PRINT_MAJOR_METHODS // cout << ";[M]: Normalize 1 to 2, iff/impl logical iff" << std::endl; #endif //make proof for assumption RefPtr< LFSCProof > p = LFSCPfVar::Make( "@v", abs( val1 ) ); p = LFSCLraPoly::Make( e[0], p.get() ); p = LFSCLraAdd::Make( p.get(), t1->getLFSCProof(), get_normalized( k1 ), get_normalized( k1, true ) ); p = LFSCLraContra::Make( p.get(), is_comparison( k1 ) ? (int)GT : (int)DISTINCT ); ostringstream oss1, oss2; //oss1 << std::endl << "this is a normalization proof of " << e[0] << "->" << e[1] << std::endl; //oss1 << "or a proof of " << eatom1 << " -> " << eatom2 << std::endl; oss1 << "(impl_intro"; // << ( eatom2.isTrue() ? "_not" : "" ); oss1 << " _ _ (\\ @v" << abs( val1 ) << " "; oss1 << "(bottom_elim "; printer->print_formula( e[1], oss1 ); oss1 << " "; oss2 << ")))"; p = LFSCProofGeneric::Make( oss1.str(), p.get(), oss2.str() ); //p = LFSCAssume::Make( val1, p.get(), false, 1 ); t1 = new TReturn( p.get(), emptyL, emptyLUsed, nullRat, false, 2 ); } } else if( is_eq_kind( k1 ) && is_eq_kind( k2 ) ) { #ifdef PRINT_MAJOR_METHODS //cout << ";[M]: Normalize 1 to 2, iff/impl" << std::endl; #endif RefPtr< LFSCProof > p; //assume1 ostringstream os1, os2; //os1 << "this is a normalization proof of " << e[0] << "->" << e[1] << std::endl; //os1 << "or a proof of " << eatom1 << " -> " << eatom2 << std::endl; os1 << "(impl_intro"; os1 << " _ _ (\\ "; os1 << "@v" << abs( val1 ) << " "; os2 << "))"; //make proof for assumption RefPtr< LFSCProof > p1 = LFSCPfVar::Make( "@v", abs( val1 ) ); RefPtr< LFSCProof > p2 = LFSCPfVar::Make( "@v", abs( val2 ) ); //convert to polynomial proofs p1 = LFSCLraPoly::Make( e[0], p1.get() ); Expr ea2 = Expr( NOT, e[1] ); p2 = LFSCLraPoly::Make( ea2, p2.get() ); if( t1->hasRational() ){ if( rev_pol ) p2 = LFSCLraMulC::Make( p2.get(), t1->getRational(), get_normalized( k2, true ) ); else p1 = LFSCLraMulC::Make( p1.get(), t1->getRational(), get_normalized( k1 ) ); } p = LFSCLraAdd::Make( p1.get(), p2.get(), get_normalized( k1 ), get_normalized( k2, true ) ); p = LFSCLraSub::Make( p.get(), t1->getLFSCProof(), is_comparison( k1 ) ? (int)GT : (int)DISTINCT, EQ ); p = LFSCLraContra::Make( p.get(), is_comparison( k1 ) ? (int)GT : (int)DISTINCT ); p = LFSCAssume::Make( val2, p.get(), false, 1 ); p = LFSCProofGeneric::Make( os1.str(), p.get(), os2.str() ); t1 = new TReturn( p.get(), emptyL, emptyLUsed, nullRat, false, 2 ); } else { ostringstream ose; ose << "NTret 12 could not handle " << eatom1 << " " << eatom2; print_error( ose.str().c_str(), cout ); } } } } } } t1->getLFSCProof()->setChOp( chOp ); if( t1->getProvesY()!=y ) { if( printErr || debug_conv ){ ostringstream ose; ose << "Failed normalize_tr " << t1->getProvesY() << " " << y << std::endl; Expr e; if( what_is_proven( pf1, e ) ) ose << "proven_expr = " << e << std::endl; print_error( ose.str().c_str(), cout ); } return -1; } else { #ifdef IGNORE_NORMALIZE t1 = new TReturn( torig->getLFSCProof(), emptyL, emptyLUsed, torig->getRational(), torig->hasRational(), y ); t1->getLFSCProof()->setChOp( chOp ); return t1->getProvesY(); #else return t1->getProvesY(); #endif } } void TReturn::normalize_to_tf( const Expr& e, TReturn*& t1, int y ) { int chOp = t1->getLFSCProof()->getChOp(); if( t1->getProvesY()!=1 ){ ostringstream ose; ose << "Bad mode for norm to tf " << t1->getProvesY() << std::endl; print_error( ose.str().c_str(), cout ); } std::vector< int > emptyL; std::vector< int > emptyLUsed; t1->getL( emptyL, emptyLUsed ); if( t1->getLFSCProof()->AsLFSCLraPoly() && false ) { #ifdef PRINT_MAJOR_METHODS cout << ";[M]: Normalize 1 to " << y << ", simplify case" << std::endl; #endif t1 = new TReturn( t1->getLFSCProof()->getChild( 0 ), emptyL, emptyLUsed, nullRat, false, y ); } else { #ifdef PRINT_MAJOR_METHODS cout << ";[M]: Normalize 1 to " << y << ", iff/impl, atom" << std::endl; #endif Expr eatom = queryAtomic( e ); int val = queryM( e ); int knd = eatom.getKind(); //make proof for assumption RefPtr< LFSCProof > p = LFSCPfVar::Make( "@v", abs( val ) ); //convert to polynomial proof Expr ea = Expr( NOT, e ); p = LFSCLraPoly::Make( ea, p.get() ); p = LFSCLraContra::Make( LFSCLraAdd::Make( p.get(), t1->getLFSCProof(), get_normalized( knd, (val<0) ), get_normalized( knd, !(val<0) ) ), is_comparison( knd ) ? (int)GT : (int)DISTINCT ); p = LFSCAssume::Make( val, p.get(), false, 1 ); //ostringstream os1, os2; //os1 << "This is the atomization of " << e << ":"; //os2 << " "; //p = LFSCProofGeneric::Make( os1.str(), p.get(), os2.str() ); //we have concluded e t1 = new TReturn( p.get(), emptyL, emptyLUsed, nullRat, false, y ); } t1->getLFSCProof()->setChOp( chOp ); } cvc3-2.4.1/src/search/LFSCObject.cpp0000664000175400017540000006407011363745667016725 0ustar mdetersmdeters#include "LFSCObject.h" LFSCPrinter* LFSCObj::printer; int LFSCObj::formula_i = 1; int LFSCObj::term_i = 1; int LFSCObj::trusted_i = 1; int LFSCObj::tnorm_i = 1; bool LFSCObj::debug_conv; bool LFSCObj::debug_var; bool LFSCObj::cvc3_mimic; bool LFSCObj::cvc3_mimic_input; int LFSCObj::lfsc_mode; Rational LFSCObj::nullRat; ExprMap< int > LFSCObj::nnode_map; ExprMap< Expr > LFSCObj::cas_map; ExprMap< Expr > LFSCObj::skolem_vars; ExprMap< bool > LFSCObj::temp_visited; ExprMap LFSCObj::d_formulas; ExprMap LFSCObj::d_trusted; ExprMap LFSCObj::d_pn; ExprMap LFSCObj::d_pn_form; ExprMap< int > LFSCObj::d_terms; ExprMap LFSCObj::input_vars; ExprMap LFSCObj::input_preds; std::map< int, bool > LFSCObj::pntNeeded; ExprMap LFSCObj::d_formulas_printed; Expr LFSCObj::d_pf_expr; ExprMap LFSCObj::d_assump_map; //differentiate between variables and rules ExprMap LFSCObj::d_rules; //boolean resultion rules Expr LFSCObj::d_bool_res_str; Expr LFSCObj::d_assump_str; Expr LFSCObj::d_iff_mp_str; Expr LFSCObj::d_impl_mp_str; Expr LFSCObj::d_iff_trans_str; Expr LFSCObj::d_real_shadow_str; Expr LFSCObj::d_cycle_conflict_str; Expr LFSCObj::d_real_shadow_eq_str; Expr LFSCObj::d_basic_subst_op_str; Expr LFSCObj::d_mult_ineqn_str; Expr LFSCObj::d_right_minus_left_str; Expr LFSCObj::d_eq_trans_str; Expr LFSCObj::d_eq_symm_str; Expr LFSCObj::d_canon_plus_str; Expr LFSCObj::d_refl_str; Expr LFSCObj::d_cnf_convert_str; Expr LFSCObj::d_learned_clause_str; Expr LFSCObj::d_minus_to_plus_str; Expr LFSCObj::d_plus_predicate_str; Expr LFSCObj::d_negated_inequality_str; Expr LFSCObj::d_flip_inequality_str; Expr LFSCObj::d_optimized_subst_op_str; Expr LFSCObj::d_iff_true_elim_str; Expr LFSCObj::d_basic_subst_op1_str; Expr LFSCObj::d_basic_subst_op0_str; Expr LFSCObj::d_canon_mult_str; Expr LFSCObj::d_canon_invert_divide_str; Expr LFSCObj::d_iff_true_str; Expr LFSCObj::d_mult_eqn_str; Expr LFSCObj::d_rewrite_eq_symm_str; Expr LFSCObj::d_implyWeakerInequality_str; Expr LFSCObj::d_implyWeakerInequalityDiffLogic_str; Expr LFSCObj::d_imp_mp_str; Expr LFSCObj::d_rewrite_implies_str; Expr LFSCObj::d_rewrite_or_str; Expr LFSCObj::d_rewrite_and_str; Expr LFSCObj::d_rewrite_iff_symm_str; Expr LFSCObj::d_iff_not_false_str; Expr LFSCObj::d_iff_false_str; Expr LFSCObj::d_iff_false_elim_str; Expr LFSCObj::d_not_to_iff_str; Expr LFSCObj::d_not_not_elim_str; Expr LFSCObj::d_const_predicate_str; Expr LFSCObj::d_rewrite_not_not_str; Expr LFSCObj::d_rewrite_not_true_str; Expr LFSCObj::d_rewrite_not_false_str; Expr LFSCObj::d_if_lift_rule_str; Expr LFSCObj::d_CNFITE_str; Expr LFSCObj::d_var_intro_str; Expr LFSCObj::d_int_const_eq_str; Expr LFSCObj::d_rewrite_eq_refl_str; Expr LFSCObj::d_iff_symm_str; Expr LFSCObj::d_rewrite_iff_str; Expr LFSCObj::d_implyNegatedInequality_str; Expr LFSCObj::d_uminus_to_mult_str; Expr LFSCObj::d_lessThan_To_LE_rhs_rwr_str; Expr LFSCObj::d_rewrite_ite_same_str; Expr LFSCObj::d_andE_str; Expr LFSCObj::d_implyEqualities_str; Expr LFSCObj::d_CNF_str; Expr LFSCObj::d_cnf_add_unit_str; Expr LFSCObj::d_minisat_proof_str; Expr LFSCObj::d_or_final_s; Expr LFSCObj::d_and_final_s; Expr LFSCObj::d_ite_s; Expr LFSCObj::d_iff_s; Expr LFSCObj::d_imp_s; Expr LFSCObj::d_or_mid_s; Expr LFSCObj::d_and_mid_s; Expr LFSCObj::d_addInequalities_str; void LFSCObj::initialize( const Expr& pf_expr, int lfscm ) { lfsc_mode = lfscm; cvc3_mimic = lfsc_mode==2 || lfsc_mode==7 || (lfsc_mode>=20 && lfsc_mode <= 29 ); cvc3_mimic_input = cvc3_mimic; debug_conv = lfsc_mode%10 == 0; debug_var = lfsc_mode>10 && ( lfsc_mode%10 == 1 ); d_pf_expr = pf_expr; // initialize rules d_bool_res_str = pf_expr.getEM()->newVarExpr("bool_resolution"); d_assump_str = pf_expr.getEM()->newVarExpr("assumptions"); d_iff_mp_str = pf_expr.getEM()->newVarExpr("iff_mp"); d_impl_mp_str = pf_expr.getEM()->newVarExpr("impl_mp"); d_iff_trans_str = pf_expr.getEM()->newVarExpr("iff_trans"); d_real_shadow_str = pf_expr.getEM()->newVarExpr("real_shadow"); d_cycle_conflict_str = pf_expr.getEM()->newVarExpr("cycleConflict"); d_real_shadow_eq_str = pf_expr.getEM()->newVarExpr("real_shadow_eq"); d_basic_subst_op_str = pf_expr.getEM()->newVarExpr("basic_subst_op"); d_mult_ineqn_str = pf_expr.getEM()->newVarExpr("mult_ineqn"); d_flip_inequality_str = pf_expr.getEM()->newVarExpr("flip_inequality"); d_right_minus_left_str = pf_expr.getEM()->newVarExpr("right_minus_left"); d_eq_trans_str = pf_expr.getEM()->newVarExpr("eq_trans"); d_eq_symm_str = pf_expr.getEM()->newVarExpr("eq_symm"); d_canon_plus_str = pf_expr.getEM()->newVarExpr("canon_plus"); d_refl_str = pf_expr.getEM()->newVarExpr("refl"); d_cnf_convert_str = pf_expr.getEM()->newVarExpr("cnf_convert"); d_learned_clause_str = pf_expr.getEM()->newVarExpr("learned_clause"); d_minus_to_plus_str = pf_expr.getEM()->newVarExpr("minus_to_plus"); d_plus_predicate_str = pf_expr.getEM()->newVarExpr("plus_predicate"); d_flip_inequality_str = pf_expr.getEM()->newVarExpr("flip_inequality"); d_negated_inequality_str = pf_expr.getEM()->newVarExpr("negated_inequality"); d_iff_true_elim_str = pf_expr.getEM()->newVarExpr("iff_true_elim"); d_basic_subst_op1_str= pf_expr.getEM()->newVarExpr("basic_subst_op1"); d_basic_subst_op0_str= pf_expr.getEM()->newVarExpr("basic_subst_op0"); d_canon_mult_str= pf_expr.getEM()->newVarExpr("canon_mult"); d_canon_invert_divide_str= pf_expr.getEM()->newVarExpr("canon_invert_divide"); d_iff_true_str= pf_expr.getEM()->newVarExpr("iff_true"); d_mult_eqn_str= pf_expr.getEM()->newVarExpr("mult_eqn"); d_rewrite_eq_symm_str= pf_expr.getEM()->newVarExpr("rewrite_eq_symm"); d_optimized_subst_op_str= pf_expr.getEM()->newVarExpr("optimized_subst_op"); d_implyWeakerInequality_str= pf_expr.getEM()->newVarExpr("implyWeakerInequality"); d_implyWeakerInequalityDiffLogic_str = pf_expr.getEM()->newVarExpr("implyWeakerInequalityDiffLogic"); d_imp_mp_str= pf_expr.getEM()->newVarExpr("impl_mp"); d_rewrite_implies_str = pf_expr.getEM()->newVarExpr("rewrite_implies"); d_rewrite_or_str = pf_expr.getEM()->newVarExpr("rewrite_or"); d_rewrite_and_str = pf_expr.getEM()->newVarExpr("rewrite_and"); d_rewrite_iff_symm_str = pf_expr.getEM()->newVarExpr("rewrite_iff_symm"); d_iff_not_false_str = pf_expr.getEM()->newVarExpr("iff_not_false"); d_iff_false_str = pf_expr.getEM()->newVarExpr("iff_false"); d_iff_false_elim_str = pf_expr.getEM()->newVarExpr("iff_false_elim"); d_not_to_iff_str = pf_expr.getEM()->newVarExpr("not_to_iff"); d_not_not_elim_str = pf_expr.getEM()->newVarExpr("not_not_elim"); d_const_predicate_str = pf_expr.getEM()->newVarExpr("const_predicate"); d_rewrite_not_not_str = pf_expr.getEM()->newVarExpr("rewrite_not_not"); d_rewrite_not_true_str = pf_expr.getEM()->newVarExpr("rewrite_not_true"); d_rewrite_not_false_str = pf_expr.getEM()->newVarExpr("rewrite_not_false"); d_if_lift_rule_str = pf_expr.getEM()->newVarExpr("if_lift_rule"); d_CNFITE_str = pf_expr.getEM()->newVarExpr("CNFITE"); d_var_intro_str = pf_expr.getEM()->newVarExpr("var_intro"); d_int_const_eq_str = pf_expr.getEM()->newVarExpr("int_const_eq"); d_rewrite_eq_refl_str = pf_expr.getEM()->newVarExpr("rewrite_eq_refl"); d_iff_symm_str = pf_expr.getEM()->newVarExpr("iff_symm"); d_rewrite_iff_str = pf_expr.getEM()->newVarExpr("rewrite_iff"); d_implyNegatedInequality_str = pf_expr.getEM()->newVarExpr("implyNegatedInequality"); d_uminus_to_mult_str = pf_expr.getEM()->newVarExpr("uminus_to_mult"); d_lessThan_To_LE_rhs_rwr_str = pf_expr.getEM()->newVarExpr("lessThan_To_LE_rhs_rwr"); d_CNF_str = pf_expr.getEM()->newVarExpr("CNF"); d_cnf_add_unit_str = pf_expr.getEM()->newVarExpr("cnf_add_unit"); d_minisat_proof_str = pf_expr.getEM()->newVarExpr("minisat_proof"); d_rewrite_ite_same_str = pf_expr.getEM()->newVarExpr("rewrite_ite_same"); d_andE_str = pf_expr.getEM()->newVarExpr("andE"); d_implyEqualities_str = pf_expr.getEM()->newVarExpr("implyEqualities"); d_addInequalities_str = pf_expr.getEM()->newVarExpr("addInequalities"); //reasons for CNF d_or_final_s = pf_expr.getEM()->newStringExpr("or_final"); d_and_final_s = pf_expr.getEM()->newStringExpr("and_final"); d_ite_s = pf_expr.getEM()->newStringExpr("ite"); d_iff_s = pf_expr.getEM()->newStringExpr("iff"); d_imp_s = pf_expr.getEM()->newStringExpr("imp"); d_or_mid_s = pf_expr.getEM()->newStringExpr("or_mid"); d_and_mid_s = pf_expr.getEM()->newStringExpr("and_mid"); // add them to d_rules d_rules[d_iff_mp_str]=true; d_rules[d_impl_mp_str]=true; d_rules[d_iff_trans_str]=true; d_rules[d_real_shadow_str]=true; d_rules[d_cycle_conflict_str]=true; d_rules[d_real_shadow_eq_str]=true; d_rules[d_basic_subst_op_str]=true; d_rules[d_mult_ineqn_str]=true; d_rules[d_flip_inequality_str]=true; d_rules[d_right_minus_left_str]=true; d_rules[d_eq_trans_str]=true; d_rules[d_eq_symm_str]=true; d_rules[d_canon_plus_str]=true; d_rules[d_refl_str]=true; d_rules[d_cnf_convert_str]=true; d_rules[d_learned_clause_str]=true; d_rules[d_bool_res_str] = true; d_rules[d_assump_str] = true; d_rules[d_minus_to_plus_str] = true; d_rules[d_minus_to_plus_str] = true; d_rules[d_plus_predicate_str] = true; d_rules[d_flip_inequality_str] = true; d_rules[d_negated_inequality_str] = true; d_rules[d_iff_true_elim_str] = true; d_rules[d_basic_subst_op1_str] = true; d_rules[d_basic_subst_op0_str] = true; d_rules[d_canon_mult_str] = true; d_rules[d_canon_invert_divide_str] = true; d_rules[d_iff_true_str] = true; d_rules[d_mult_eqn_str] = true; d_rules[d_rewrite_eq_symm_str] = true; d_rules[d_optimized_subst_op_str] = true; d_rules[d_implyWeakerInequality_str] = true; d_rules[d_implyWeakerInequalityDiffLogic_str] = true; d_rules[d_imp_mp_str] = true; d_rules[d_addInequalities_str] = true; d_rules[d_rewrite_implies_str] = true; d_rules[d_rewrite_or_str] = true; d_rules[d_rewrite_and_str] = true; d_rules[d_rewrite_iff_symm_str] = true; d_rules[d_iff_not_false_str] = true; d_rules[d_iff_false_str] = true; d_rules[d_iff_false_elim_str] = true; d_rules[d_not_to_iff_str] = true; d_rules[d_not_not_elim_str] = true; d_rules[d_const_predicate_str] = true; d_rules[d_rewrite_not_not_str] = true; d_rules[d_rewrite_not_true_str] = true; d_rules[d_rewrite_not_false_str] = true; d_rules[d_if_lift_rule_str] = true; d_rules[d_CNFITE_str] = true; d_rules[d_var_intro_str] = true; d_rules[d_int_const_eq_str] = true; d_rules[d_rewrite_eq_refl_str] = true; d_rules[d_iff_symm_str] = true; d_rules[d_rewrite_iff_str] = true; d_rules[d_implyNegatedInequality_str] = true; d_rules[d_uminus_to_mult_str] = true; d_rules[d_lessThan_To_LE_rhs_rwr_str] = true; d_rules[d_CNF_str] = true; d_rules[d_cnf_add_unit_str] = true; d_rules[d_minisat_proof_str] = true; d_rules[d_andE_str] = true; d_rules[d_implyEqualities_str] = true; d_rules[d_rewrite_ite_same_str] = true; } int LFSCObj::getNumNodes( const Expr& pf, bool recount ){ if( pf.arity()>0 && d_rules[pf[0]] ){ if( nnode_map.find( pf )==nnode_map.end() ){ int sum=0; for( int a=1; a0 ){ ce = cascade_expr( e[e.arity()-1] ); for( int a=e.arity()-2; a>=0; a-- ){ ce = Expr( e.getKind(), cascade_expr( e[a] ), ce ); } }else{ return e; } cas_map[e] = ce; return ce; } } void LFSCObj::define_skolem_vars( const Expr& e ) { if( e.arity()>0 && d_rules[ e[0] ] && !temp_visited[e] ) { temp_visited[e] = true; if( e[0] == d_assump_str ) { if( e[1].isIff() && e[1][1].isEq() && e[1][1][1].getKind()==SKOLEM_VAR ){ Expr ce = cascade_expr( e[1][1][0] ); skolem_vars[ e[1][1][1] ] = ce; //store it in the tmap queryT( ce ); }else{ Expr ce = cascade_expr( e[1] ); if( !d_assump_map[ ce ] ){ ostringstream ose; ose << "Unexpected non-discharged assumption " << ce; print_error( ose.str().c_str(), cout ); } } } if( e[0]!=d_learned_clause_str ){ for( int a=1; afalseExpr(); return e; }else if( e[0].isFalse() ){ e = d_pf_expr.getEM()->trueExpr(); return e; }else if( is_eq_kind( e[0].getKind() ) ){ return Expr( get_not( e[0].getKind() ), e[0][1], e[0][0] ); } } } return e; } int LFSCObj::queryM(const Expr& expr, bool add, bool trusted) { //cout << "query : " << expr << endl; bool neg = false; Expr e = cascade_expr( queryElimNotNot( expr ) ); if( !trusted ){ if( e.isNot() ){ neg = true; e = e[0]; } int val = d_formulas[e]; if( val==0 && add ) { if( !e.isInitialized() ){ print_error( "WARNING: uninitialized e in query", cout ); } d_formulas[e] = formula_i; val = formula_i; formula_i++; } return val*(neg ? -1 : 1 ); }else{ int val = d_trusted[e]; if( val==0 && add ){ d_trusted[e] = trusted_i; val = trusted_i; trusted_i++; } return val; } } int LFSCObj::queryMt(const Expr& expr) { Expr ce = cascade_expr( expr ); if( !can_pnorm( ce ) ){ ostringstream os; os << "ERROR: cannot make polynomial normalization for " << ce << std::endl; print_error( os.str().c_str(), cout ); } int val = d_pn[ce]; if( val==0 ) { d_pn[ce] = tnorm_i; val = tnorm_i; tnorm_i++; } return val; } int LFSCObj::queryT( const Expr& e ) { Expr ce = cascade_expr( e ); int val = d_terms[ce]; if( val==0 ){ d_terms[ce] = term_i; val = term_i; term_i++; } return val; } bool LFSCObj::getY( const Expr& e, Expr& pe, bool doIff, bool doLogic ) { //cout << "getY = " << e << std::endl; Expr ea = queryAtomic( e ); if( is_eq_kind( ea.getKind() ) ){ //must be able to pnorm it if( can_pnorm( ea[0] ) && can_pnorm( ea[1] ) ){ if( is_opposite( ea.getKind() ) ){ pe = Expr( get_normalized( ea.getKind() ), ea[1], ea[0] ); }else{ pe = ea; } return true; }else{ ostringstream ose; ose << "Can't pnorm " << ea[0] << " " << ea[1] << std::endl; print_error( ose.str().c_str(), cout ); } } if( doIff ){ if( e.arity()==2 ) { Expr pe1; Expr pe2; if ( e.isIff() ){ if( getY( e[1], pe2, false ) ){ if( getY( e[0], pe1, false, pe2.getKind()==TRUE_EXPR || pe2.getKind()==FALSE_EXPR ) ){ if( pe2.getKind()==TRUE_EXPR ){ pe = pe1; return true; }else if( pe1.getKind()==FALSE_EXPR ){ pe = d_pf_expr.getEM()->trueExpr(); return true; } if( pe1.getKind()==pe2.getKind() ){ pe = Expr( EQ, Expr( MINUS, pe1[0], pe2[0] ), Expr( MINUS, pe1[1], pe2[1] ) ); } return true; } } } else if( e.isImpl() ){ if( getY( e[1], pe2, false, false ) ){ if( getY( e[0], pe1, false, false ) ){ if( is_comparison( pe1.getKind() ) && is_comparison( pe2.getKind() ) ){ pe = Expr( pe1.getKind()==GT && pe2.getKind()==GT ? GT : GE, Expr( MINUS, pe1[0], pe2[0] ), Expr( MINUS, pe1[1], pe2[1] ) ); } return true; } } } } } if( doLogic ){ if( ea.isFalse() ){ pe = d_pf_expr.getEM()->trueExpr(); return true; }else if( ea.isTrue() ){ pe = ea; return true; } } return false; } bool LFSCObj::isFormula( const Expr& e ) { return ( is_eq_kind( e.getKind() ) || e.isAnd() || e.isOr() || e.isImpl() || e.isIff() || e.isFalse() || e.isTrue() || e.isNot() || ( e.getKind()==ITE && isFormula( e[1] ) ) || ( input_preds.find( e )!=input_preds.end() ) ); } bool LFSCObj::can_pnorm( const Expr& e ) { if( is_eq_kind( e.getKind() ) ){ return can_pnorm( e[0] ) && can_pnorm( e[1] ); }else if( e.getKind()==PLUS || e.getKind()==MINUS || e.getKind()==MULT || e.getKind()==DIVIDE ){ return can_pnorm( e[0] ) && can_pnorm( e[1] ); }else if( e.getKind()==UMINUS ){ return can_pnorm( e[0] ); }else if( e.isRational() ){ return true; }else if( e.getKind()==ITE ){ queryT( e ); return true; }else if( e.isVar() && input_preds.find( e )==input_preds.end() ){ return true; } return false; } bool LFSCObj::what_is_proven( const Expr& pf, Expr& pe ) { if(pf.arity()>0 ){ if(d_rules[pf[0]]&&pf[0].getKind()==UCONST){ if( pf[0] == d_assump_str || pf[0] == d_cnf_add_unit_str || pf[0]== d_cnf_convert_str || pf[0] == d_iff_true_elim_str ){ pe = pf[1]; return true; } else if( pf[0] == d_canon_plus_str || pf[0]==d_canon_mult_str ){ pe = Expr( EQ, pf[1], pf[2] ); return true; } else if( pf[0] == d_canon_invert_divide_str ) { Rational r1 = Rational( 1 ); Expr er1 = d_pf_expr.getEM()->newRatExpr( pf[1][0].getRational() ); Expr er2 = d_pf_expr.getEM()->newRatExpr( r1/pf[1][1].getRational() ); pe = Expr( EQ, pf[1], Expr( MULT, er1, er2 ) ); return true; } else if( pf[0] == d_iff_trans_str ) { pe = Expr( IFF, pf[1], pf[3] ); return true; } else if( pf[0] == d_iff_mp_str || pf[0] == d_impl_mp_str) { pe = pf[2]; return true; } else if( pf[0] == d_eq_trans_str ) { pe = Expr( EQ, pf[2], pf[4] ); return true; } else if( pf[0] == d_eq_symm_str ) { pe = Expr( EQ, pf[3], pf[2] ); return true; } else if( pf[0] == d_basic_subst_op_str || pf[0] == d_rewrite_and_str || pf[0] == d_rewrite_or_str || pf[0] == d_lessThan_To_LE_rhs_rwr_str || pf[0] == d_mult_ineqn_str || pf[0] == d_plus_predicate_str || pf[0] == d_flip_inequality_str || pf[0] == d_int_const_eq_str || pf[0] == d_const_predicate_str ) { pe = Expr( IFF, pf[1], pf[2] ); return true; } else if (pf[0] == d_iff_symm_str){ pe = pf[2].iffExpr(pf[1]); return true; } else if( pf[0] == d_basic_subst_op0_str ) { if( pf[1].getKind()==UMINUS ){ pe = Expr( EQ, pf[1], pf[2] ); return true; }else if( pf[1].getKind()==NOT ){ pe = Expr( IFF, pf[1], pf[2] ); return true; } } else if( pf[0] == d_mult_eqn_str ) { pe = Expr( IFF, Expr( EQ, pf[1], pf[2] ), Expr( EQ, Expr( MULT, pf[1], pf[3] ), Expr( MULT, pf[2], pf[3] ) ) ); return true; } else if( pf[0] == d_real_shadow_str ) { pe = Expr( ( pf[1].getKind()==LE && pf[2].getKind()==LE ) ? LE : LT, pf[1][0], pf[2][1] ); return true; } else if(pf[0] == d_real_shadow_eq_str){ pe = Expr(EQ, pf[2][0], pf[2][1]); return true; } else if( pf[0] == d_optimized_subst_op_str || pf[0] == d_basic_subst_op1_str ) { if( pf[1].getKind()==AND || pf[1].getKind()==OR || pf[1].getKind()==IFF || is_eq_kind( pf[1].getKind() ) || ( pf[1].getKind()==ITE && isFormula( pf[1] ) ) ){ pe = Expr( IFF, pf[1], pf[2] ); return true; }else if( pf[1].getKind()==ITE || pf[1].getKind()==PLUS || pf[1].getKind()==MINUS || pf[1].getKind()==MULT ){ pe = Expr( EQ, pf[1], pf[2] ); return true; } } else if( pf[0] == d_andE_str ) { pe = pf[2][ pf[1].getRational().getNumerator().getInt() ]; return true; } else if( pf[0] == d_rewrite_implies_str ) { Expr e1 = Expr( IMPLIES, pf[1], pf[2] ); Expr e2 = Expr( NOT, pf[1] ); Expr e3 = Expr( OR, e2, pf[2] ); pe = Expr( IFF, e1, e3 ); return true; } else if( pf[0] == d_rewrite_eq_symm_str ) { Expr e1 = Expr( EQ, pf[2], pf[3] ); Expr e2 = Expr( EQ, pf[3], pf[2] ); pe = Expr( IFF, e1, e2 ); return true; } else if( pf[0] == d_rewrite_iff_symm_str ) { Expr e1 = Expr( IFF, pf[1], pf[2] ); Expr e2 = Expr( IFF, pf[2], pf[1] ); pe = Expr( IFF, e1, e2 ); return true; } else if( pf[0] == d_rewrite_ite_same_str ) { pe = Expr( EQ, Expr( ITE, pf[2], pf[3], pf[3] ), pf[3] ); return true; } else if( pf[0] == d_rewrite_eq_refl_str ) { pe = Expr( IFF, Expr( EQ, pf[2], pf[2] ), d_pf_expr.getEM()->trueExpr() ); return true; } else if( pf[0] == d_refl_str ) { if( isFormula( pf[1] ) ) pe = Expr( IFF, pf[1], pf[1] ); else pe = Expr( EQ, pf[1], pf[1] ); return true; } else if( pf[0] == d_rewrite_not_not_str ) { Expr e1 = Expr( NOT, pf[1] ); pe = Expr( NOT, e1 ); return true; } else if( pf[0] == d_not_to_iff_str ) { pe = Expr( IFF, Expr( NOT, pf[1] ), d_pf_expr.getEM()->falseExpr() ); return true; } else if( pf[0] == d_minus_to_plus_str ) { Expr er1 = d_pf_expr.getEM()->newRatExpr( Rational( -1 ) ); pe = Expr( EQ, Expr( MINUS, pf[1], pf[2] ), Expr( PLUS, pf[1], Expr( MULT, er1, pf[2] ) ) ); return true; } else if( pf[0] == d_right_minus_left_str ) { Expr er1 = d_pf_expr.getEM()->newRatExpr( Rational( 0 ) ); Expr e1 = Expr( pf[1].getKind(), er1, Expr( MINUS, pf[1][1], pf[1][0] ) ); pe = Expr(IFF, pf[1], e1); return true; } else if( pf[0] == d_negated_inequality_str ) { pe = Expr( IFF, pf[1], Expr( get_not( pf[1][0].getKind() ), pf[1][0][0], pf[1][0][1] ) ); return true; } else if( pf[0] == d_iff_false_elim_str ) { pe = queryElimNotNot( Expr( NOT, pf[1] ) ); return true; } else if( pf[0] == d_iff_true_str ) { pe = Expr( IFF, pf[1], d_pf_expr.getEM()->trueExpr() ); return true; } else if( pf[0] == d_iff_not_false_str ) { pe = Expr( IFF, queryElimNotNot( Expr( NOT, pf[1] ) ), d_pf_expr.getEM()->falseExpr() ); return true; } else if( pf[0] == d_uminus_to_mult_str ) { Expr er1 = d_pf_expr.getEM()->newRatExpr( Rational( -1 ) ); pe = Expr( EQ, Expr( UMINUS, pf[1] ), Expr( MULT, er1, pf[1] ) ); return true; } else if( pf[0] == d_rewrite_not_true_str ) { pe = Expr( IFF, Expr( NOT, d_pf_expr.getEM()->trueExpr() ), d_pf_expr.getEM()->falseExpr() ); return true; } else if( pf[0] == d_rewrite_not_false_str ) { pe = Expr( IFF, Expr( NOT, d_pf_expr.getEM()->falseExpr() ), d_pf_expr.getEM()->trueExpr() ); return true; } else if( pf[0] == d_cycle_conflict_str ) { pe = d_pf_expr.getEM()->falseExpr(); return true; } else if(pf[0] == d_implyNegatedInequality_str) { pe = pf[1].impExpr(pf[3]); return true; } else if(pf[0] == d_implyWeakerInequality_str){ pe = pf[1].impExpr(pf[2]); return true; } else if( pf[0] == d_rewrite_iff_symm_str ) { Expr e1 = Expr( IFF, pf[1], pf[2] ); Expr e2 = Expr( IFF, pf[2], pf[1] ); pe = Expr( IFF, e1, e2 ); return true; } else if( pf[0] == d_rewrite_iff_str){ Expr e = Expr( IFF, pf[1], pf[2]); Expr e_true = d_pf_expr.getEM()->trueExpr(); Expr e_false = d_pf_expr.getEM()->falseExpr(); if(pf[1] == pf[2]){ pe = e.iffExpr(d_pf_expr.getEM()->trueExpr()); return true; } if(pf[1] == e_true){ pe = e.iffExpr(e_true); return true; } if(pf[1] == e_false){ pe = e.iffExpr(e_false); return true; } if(pf[1].isNot() && pf[1][0] == pf[2]){ pe = e.iffExpr(pf[2].negate()); return true; } if(pf[2] == e_true){ pe = e.iffExpr(e_true); return true; } if(pf[2] == e_false){ pe = e.iffExpr(e_false); return true; } if(pf[2].isNot() && pf[2][0] == pf[1]){ pe = e.iffExpr(pf[1].negate()); return true; } if(pf[1] < pf[2]){ Expr e_sym = Expr(IFF, pf[2], pf[1]); pe = e.iffExpr(e_sym); return true; } pe = e.iffExpr(e); return true; } else if(pf[0] == d_implyEqualities_str){ pe = Expr(AND, pf[1][0]); return true; } } } ostringstream ose; ose << "What_is_proven, unknown: (" << d_rules[pf[0]] << "): " << pf[0]; print_error( ose.str().c_str(), cout ); return false; } cvc3-2.4.1/src/search/LFSCPrinter.h0000664000175400017540000000344311363704204016562 0ustar mdetersmdeters#ifndef LFSC_PRINTER_H_ #define LFSC_PRINTER_H_ #include "TReturn.h" #include "LFSCConvert.h" class LFSCPrinter : public LFSCObj{ private: //user assumptions std::vector d_user_assumptions; //the converter object RefPtr< LFSCConvert > converter; //count for lets int let_i; //common proof rules (need this?) CommonProofRules* d_common_pf_rules; //for printing formulas ExprMap d_print_map; ExprMap d_print_visited_map; //make the expr into possible let's void make_let_map( const Expr& e ); //print the polynomial normalization void print_poly_norm(const Expr& expr, std::ostream& s, bool pnRat = true, bool ratNeg = false ); void print_terms_h(const Expr& expr,std::ostream& s ); void print_formula_h(const Expr& clause, std::ostream& s ); public: LFSCPrinter(const Expr pf_expr, Expr qExpr, std::vector assumps, int lfscm, CommonProofRules* commonRules); //print the LFSC proof for the cvc3 proof void print_LFSC(const Expr& pf_expr); //this is an expression that will be printed void set_print_expr( const Expr& expr ) { make_let_map( expr ); } //print expression void print_expr(const Expr& expr, std::ostream& s){ if( isFormula( expr ) ) print_formula( expr, s ); else print_terms( expr, s ); } //print formula void print_formula(const Expr& clause, std::ostream& s ){ //if( clause!=cascade_expr( clause, false ) ) // cout << "Warning: printing non-cascaded formula " << clause << std::endl; print_formula_h( cascade_expr( clause ), s ); } //print term void print_terms(const Expr& expr,std::ostream& s ){ //if( expr!=cascade_expr( expr, false ) ) // cout << "Warning: printing non-cascaded term " << expr << std::endl; print_terms_h( cascade_expr( expr ), s ); } }; #endif cvc3-2.4.1/src/search/search_impl_base.cpp0000664000175400017540000006211411004130325020267 0ustar mdetersmdeters/*****************************************************************************/ /*! * \file search_impl_base.cpp * * Author: Clark Barrett, Vijay Ganesh (CNF Converter) * * Created: Fri Jan 17 14:19:54 2003 * *
* * License to use, copy, modify, sell and/or distribute this software * and its documentation for any purpose is hereby granted without * royalty, subject to the terms and conditions defined in the \ref * LICENSE file provided with this distribution. * *
* */ /*****************************************************************************/ #include "search_impl_base.h" #include "theory.h" #include "eval_exception.h" #include "search_rules.h" #include "variable.h" #include "command_line_flags.h" #include "statistics.h" #include "theorem_manager.h" #include "expr_transform.h" #include "assumptions.h" using namespace std; namespace CVC3 { class CoreSatAPI_implBase :public TheoryCore::CoreSatAPI { SearchImplBase* d_se; public: CoreSatAPI_implBase(SearchImplBase* se) : d_se(se) {} virtual ~CoreSatAPI_implBase() {} virtual void addLemma(const Theorem& thm, int priority, bool atBottomScope) { d_se->addFact(thm); } virtual Theorem addAssumption(const Expr& assump) { return d_se->newIntAssumption(assump); } virtual void addSplitter(const Expr& e, int priority) { d_se->addSplitter(e, priority); } virtual bool check(const Expr& e); }; bool CoreSatAPI_implBase::check(const Expr& e) { Theorem thm; int scope = d_se->theoryCore()->getCM()->scopeLevel(); d_se->theoryCore()->getCM()->push(); QueryResult res = d_se->checkValid(e, thm); d_se->theoryCore()->getCM()->popto(scope); return res == VALID; } } using namespace CVC3; // class SearchImplBase::Splitter methods // Constructor SearchImplBase::Splitter::Splitter(const Literal& lit): d_lit(lit) { d_lit.count()++; TRACE("Splitter", "Splitter(", d_lit, ")"); } // Copy constructor SearchImplBase::Splitter::Splitter(const SearchImplBase::Splitter& s) : d_lit(s.d_lit) { d_lit.count()++; TRACE("Splitter", "Splitter[copy](", d_lit, ")"); } // Assignment SearchImplBase::Splitter& SearchImplBase::Splitter::operator=(const SearchImplBase::Splitter& s) { if(this == &s) return *this; // Self-assignment d_lit.count()--; d_lit = s.d_lit; d_lit.count()++; TRACE("Splitter", "Splitter[assign](", d_lit, ")"); return *this; } // Destructor SearchImplBase::Splitter::~Splitter() { d_lit.count()--; TRACE("Splitter", "~Splitter(", d_lit, ")"); } //! Constructor SearchImplBase::SearchImplBase(TheoryCore* core) : SearchEngine(core), d_bottomScope(core->getCM()->getCurrentContext()), d_dpSplitters(core->getCM()->getCurrentContext()), d_lastValid(d_commonRules->trueTheorem()), d_assumptions(core->getCM()->getCurrentContext()), d_cnfCache(core->getCM()->getCurrentContext()), d_cnfVars(core->getCM()->getCurrentContext()), d_cnfOption(&(core->getFlags()["cnf"].getBool())), d_ifLiftOption(&(core->getFlags()["iflift"].getBool())), d_ignoreCnfVarsOption(&(core->getFlags()["ignore-cnf-vars"].getBool())), d_origFormulaOption(&(core->getFlags()["orig-formula"].getBool())), d_enqueueCNFCache(core->getCM()->getCurrentContext()), d_applyCNFRulesCache(core->getCM()->getCurrentContext()), d_replaceITECache(core->getCM()->getCurrentContext()) { d_vm = new VariableManager(core->getCM(), d_rules, core->getFlags()["mm"].getString()); IF_DEBUG(d_assumptions.setName("CDList[SearchImplBase::d_assumptions]");) d_coreSatAPI_implBase = new CoreSatAPI_implBase(this); core->registerCoreSatAPI(d_coreSatAPI_implBase); } //! Destructor SearchImplBase::~SearchImplBase() { delete d_coreSatAPI_implBase; delete d_vm; } // Returns a new theorem if e has not already been asserted, otherwise returns // a NULL theorem. Theorem SearchImplBase::newUserAssumption(const Expr& e) { Theorem thm; CDMap::iterator i(d_assumptions.find(e)); IF_DEBUG(if(debugger.trace("search verbose")) { ostream& os(debugger.getOS()); os << "d_assumptions = ["; for(CDMap::iterator i=d_assumptions.begin(), iend=d_assumptions.end(); i!=iend; ++i) { debugger.getOS() << "(" << (*i).first << " => " << (*i).second << "), "; } os << "]" << endl; }) if(i!=d_assumptions.end()) { TRACE("search verbose", "newUserAssumption(", e, "): assumption already exists"); } else { thm = d_commonRules->assumpRule(e); d_assumptions[e] = thm; e.setUserAssumption(); TRACE("search verbose", "newUserAssumption(", thm, "): created new assumption"); } if (!thm.isNull()) d_core->addFact(d_core->getExprTrans()->preprocess(thm)); return thm; } // Same as newUserAssertion, except it's an error to assert something that's // already been asserted. Theorem SearchImplBase::newIntAssumption(const Expr& e) { Theorem thm = d_commonRules->assumpRule(e); Expr atom = e.isNot() ? e[0] : e; thm.setQuantLevel(theoryCore()->getQuantLevelForTerm(atom)); newIntAssumption(thm); return thm; } void SearchImplBase::newIntAssumption(const Theorem& thm) { DebugAssert(!d_assumptions.count(thm.getExpr()), "newIntAssumption: repeated assertion: "+thm.getExpr().toString()); d_assumptions[thm.getExpr()] = thm; thm.getExpr().setIntAssumption(); TRACE("search verbose", "newIntAssumption(", thm, "): new assumption"); } void SearchImplBase::getUserAssumptions(vector& assumptions) { for(CDMap::orderedIterator i=d_assumptions.orderedBegin(), iend=d_assumptions.orderedEnd(); i!=iend; ++i) if ((*i).first.isUserAssumption()) assumptions.push_back((*i).first); } void SearchImplBase::getInternalAssumptions(std::vector& assumptions) { for(CDMap::orderedIterator i=d_assumptions.orderedBegin(), iend=d_assumptions.orderedEnd(); i!=iend; ++i) if ((*i).first.isIntAssumption()) assumptions.push_back((*i).first); } void SearchImplBase::getAssumptions(std::vector& assumptions) { for(CDMap::orderedIterator i=d_assumptions.orderedBegin(), iend=d_assumptions.orderedEnd(); i!=iend; ++i) assumptions.push_back((*i).first); } bool SearchImplBase::isAssumption(const Expr& e) { return d_assumptions.count(e) > 0; } void SearchImplBase::addCNFFact(const Theorem& thm, bool fromCore) { TRACE("addCNFFact", "addCNFFact(", thm.getExpr(), ") {"); if(thm.isAbsLiteral()) { addLiteralFact(thm); // These literals are derived, and should also be reported to the core. if(!fromCore) d_core->enqueueFact(thm); } else { addNonLiteralFact(thm); } TRACE_MSG("addCNFFact", "addCNFFact => }"); } void SearchImplBase::addFact(const Theorem& thm) { TRACE("search addFact", "SearchImplBase::addFact(", thm.getExpr(), ") {"); if(*d_cnfOption) enqueueCNF(thm); else addCNFFact(thm, true); TRACE_MSG("search addFact", "SearchImplBase::addFact => }"); } void SearchImplBase::addSplitter(const Expr& e, int priority) { DebugAssert(e.isAbsLiteral(), "SearchImplBase::addSplitter("+e.toString()+")"); d_dpSplitters.push_back(Splitter(newLiteral(e))); } void SearchImplBase::getCounterExample(vector& assertions, bool inOrder) { if(!d_core->getTM()->withAssumptions()) throw EvalException ("Method getCounterExample() (or command COUNTEREXAMPLE) cannot be used\n" " without assumptions activated"); if(!d_lastValid.isNull()) throw EvalException ("Method getCounterExample() (or command COUNTEREXAMPLE)\n" " must be called only after failed QUERY"); getInternalAssumptions(assertions); /* if(!d_lastCounterExample.empty()) { if (inOrder) { for(CDMap::orderedIterator i=d_assumptions.orderedBegin(), iend=d_assumptions.orderedEnd(); i!=iend; ++i) { if (d_lastCounterExample.find((*i).first) != d_lastCounterExample.end()) { assertions.push_back((*i).first); } } DebugAssert(assertions.size()==d_lastCounterExample.size(), "getCounterExample: missing assertion"); } else { ExprHashMap::iterator i=d_lastCounterExample.begin(), iend = d_lastCounterExample.end(); for(; i!=iend; ++i) assertions.push_back((*i).first); } } */ } Proof SearchImplBase::getProof() { if(!d_core->getTM()->withProof()) throw EvalException ("DUMP_PROOF cannot be used without proofs activated"); if(d_lastValid.isNull()) throw EvalException ("DUMP_PROOF must be called only after successful QUERY"); // Double-check for optimized version if(d_lastValid.isNull()) return Proof(); return d_lastValid.getProof(); } const Assumptions& SearchImplBase::getAssumptionsUsed() { if(!d_core->getTM()->withAssumptions()) throw EvalException ("DUMP_ASSUMPTIONS cannot be used without assumptions activated"); if(d_lastValid.isNull()) throw EvalException ("DUMP_ASSUMPTIONS must be called only after successful QUERY"); // Double-check for optimized version if(d_lastValid.isNull()) return Assumptions::emptyAssump(); return d_lastValid.getAssumptionsRef(); } /*! * Given a proof of FALSE ('res') from an assumption 'e', derive the * proof of the inverse of e. * * \param res is a proof of FALSE * \param e is the assumption used in the above proof */ void SearchImplBase::processResult(const Theorem& res, const Expr& e) { // Result must be either Null (== SAT) or false (== unSAT) DebugAssert(res.isNull() || res.getExpr().isFalse(), "processResult: bad input" + res.toString()); if(res.isNull()) { // Didn't prove valid (if CVC-lite is complete, it means invalid). // The assumptions for the counterexample must have been already // set by checkSAT(). d_lastValid = Theorem(); // Reset last proof // Remove !e, keep just the counterexample d_lastCounterExample.erase(!e); if (e.isNot()) d_lastCounterExample.erase(e[0]); } else { // Proved valid Theorem res2 = d_rules->eliminateSkolemAxioms(res, d_commonRules->getSkolemAxioms()); if(e.isNot()) d_lastValid = d_rules->negIntro(e, res2); else d_lastValid = d_rules->proofByContradiction(e, res2); d_lastCounterExample.clear(); // Reset counterexample } } QueryResult SearchImplBase::checkValid(const Expr& e, Theorem& result) { d_commonRules->clearSkolemAxioms(); QueryResult qres = checkValidInternal(e); result = d_lastValid; return qres; } QueryResult SearchImplBase::restart(const Expr& e, Theorem& result) { QueryResult qres = restartInternal(e); result = d_lastValid; return qres; } void SearchImplBase::enqueueCNF(const Theorem& beta) { TRACE("mycnf", "enqueueCNF(", beta, ") {"); if(*d_origFormulaOption) addCNFFact(beta); enqueueCNFrec(beta); TRACE_MSG("mycnf", "enqueueCNF => }"); } void SearchImplBase::enqueueCNFrec(const Theorem& beta) { Theorem theta = beta; TRACE("mycnf","enqueueCNFrec(", theta.getExpr(), ") { "); TRACE("cnf-clauses", "enqueueCNF call", theta.getExpr(), ""); // The theorem scope shouldn't be higher than current DebugAssert(theta.getScope() <= scopeLevel(), "\n theta.getScope()="+int2string(theta.getScope()) +"\n scopeLevel="+int2string(scopeLevel()) +"\n e = "+theta.getExpr().toString()); Expr thetaExpr = theta.getExpr(); if(d_enqueueCNFCache.count(thetaExpr) > 0) { TRACE_MSG("mycnf", "enqueueCNFrec[cached] => }"); return; } d_enqueueCNFCache[thetaExpr] = true; // // Strip double negations first while(thetaExpr.isNot() && thetaExpr[0].isNot()) { theta = d_commonRules->notNotElim(theta); thetaExpr = theta.getExpr(); // Cache all the derived theorems too d_enqueueCNFCache[thetaExpr] = true; } // Check for a propositional literal if(thetaExpr.isPropLiteral()) { theta = d_commonRules->iffMP(theta, replaceITE(thetaExpr)); DebugAssert(!*d_ifLiftOption || theta.isAbsLiteral(), "Must be a literal: theta = " +theta.getExpr().toString()); addCNFFact(theta); TRACE_MSG("mycnf", "enqueueCNFrec[literal] => }"); TRACE("cnf-clauses", "literal with proofs(", theta.getExpr(), ")"); return; } thetaExpr = theta.getExpr(); // Obvious optimizations for AND and OR switch(thetaExpr.getKind()) { case AND: // Split up the top-level conjunction and translate individually for(int i=0; iandElim(theta, i)); TRACE_MSG("mycnf", "enqueueCNFrec[AND] => }"); return; case OR: { // Check if we are already in CNF (ignoring ITEs in the terms), // and if we are, translate term ITEs on the way bool cnf(true); TRACE("bv mycnf", "enqueueCNFrec[OR] ( ", theta.getExpr().toString(), ")"); for(Expr::iterator i=thetaExpr.begin(),iend=thetaExpr.end(); i!=iend && cnf; i++) { if(!(*i).isPropLiteral()) cnf = false; } if(cnf) { vector thms; vector changed; unsigned int cc=0; for(Expr::iterator i=thetaExpr.begin(),iend=thetaExpr.end(); i!=iend; i++,cc++) { Theorem thm = replaceITE(*i); if(thm.getLHS() != thm.getRHS()) { thms.push_back(thm); changed.push_back(cc); } } if(changed.size() > 0) { Theorem rewrite = d_commonRules->substitutivityRule(theta.getExpr(), changed, thms); theta = d_commonRules->iffMP(theta, rewrite); } addCNFFact(theta); TRACE_MSG("mycnf", "enqueueCNFrec[cnf] => }"); return; } break; } case IFF: { // Check for "var <=> phi" and "phi <=> var" const Expr& t0 = thetaExpr[0]; const Expr& t1 = thetaExpr[1]; if(t1.isPropLiteral()) { if(!t1.isAbsLiteral()) theta = d_commonRules->transitivityRule(theta, replaceITE(t1)); applyCNFRules(theta); return; } else if(thetaExpr[0].isPropLiteral()) { theta = d_commonRules->symmetryRule(theta); if(!t0.isAbsLiteral()) theta = d_commonRules->transitivityRule(theta, replaceITE(t0)); applyCNFRules(theta); return; } break; } case ITE: if(thetaExpr[0].isPropLiteral() && thetaExpr[1].isPropLiteral() && thetaExpr[2].isPropLiteral()) { // Replace ITEs vector thms; vector changed; for(int c=0, cend=thetaExpr.arity(); c }"); return; } // std::vector clauses; Theorem result; // (\phi <==> v) result = d_commonRules->varIntroSkolem(theta.getExpr()); TRACE("mycnf", "enqueueCNFrec: varIntroSkolem => ", result.getExpr(), " @ "+int2string(result.getScope()) +" (current="+int2string(scopeLevel())+")"); //result = skolemize(result, false); TRACE("mycnf", "enqueueCNFrec: skolemize => ", result.getExpr(), " @ "+int2string(result.getScope()) +" (current="+int2string(scopeLevel())+")"); DebugAssert(result.isRewrite(), "SearchImplBase::CNF(): result = "+result.toString()); DebugAssert(!result.getLHS().isPropLiteral() && result.getRHS().isPropLiteral(), "SearchImplBase::CNF(): result = "+result.toString()); DebugAssert(result.getLHS() == theta.getExpr(), "SearchImplBase::CNF(): result = "+result.toString() +"\n theta = "+theta.toString()); //enqueue v Theorem var(d_commonRules->iffMP(theta, result)); // Add variable to the set of CNF vars d_cnfVars[var.getExpr()] = true; TRACE("mycnf", "enqueueCNFrec: theta = ", theta.getExpr(), " @ "+int2string(theta.getScope()) +" (current="+int2string(scopeLevel())+")"); TRACE("mycnf", "enqueueCNFrec: var = ", var.getExpr(), " @ "+int2string(var.getScope()) +" (current="+int2string(scopeLevel())+")"); DebugAssert(var.isAbsLiteral(), "var = "+var.getExpr().toString()); addCNFFact(var); // phi <=> v addToCNFCache(result); applyCNFRules(result); TRACE_MSG("mycnf", "enqueueCNFrec => }"); } /*! * \param thm is the input of the form phi <=> v */ void SearchImplBase::applyCNFRules(const Theorem& thm) { TRACE("mycnf", "applyCNFRules(", thm.getExpr(), ") { "); Theorem result = thm; DebugAssert(result.isRewrite(), "SearchImplBase::applyCNFRules: input must be an iff: " + result.getExpr().toString()); Expr lhs = result.getLHS(); Expr rhs = result.getRHS(); DebugAssert(rhs.isAbsLiteral(), "SearchImplBase::applyCNFRules: rhs of input must be literal: " + result.getExpr().toString()); // Eliminate negation first while(result.getLHS().isNot()) result = d_commonRules->iffContrapositive(result); lhs = result.getLHS(); rhs = result.getRHS(); CDMap::iterator it = d_applyCNFRulesCache.find(lhs); if(it == d_applyCNFRulesCache.end()) d_applyCNFRulesCache[lhs] = true; else { TRACE_MSG("mycnf","applyCNFRules[temp cache] => }"); return; } // Catch the trivial case v1 <=> v2 if(lhs.isPropLiteral()) { if(!lhs.isAbsLiteral()) { Theorem replaced = d_commonRules->symmetryRule(replaceITE(lhs)); result = d_commonRules->transitivityRule(replaced, result); lhs = result.getLHS(); DebugAssert(rhs == result.getRHS(), "applyCNFRules [literal lhs]\n result = " +result.getExpr().toString() +"\n rhs = "+rhs.toString()); } Theorem thm = d_rules->iffToClauses(result); DebugAssert(thm.getExpr().isAnd() && thm.getExpr().arity()==2, "applyCNFRules [literal lhs]\n thm = " +thm.getExpr().toString()); addCNFFact(d_commonRules->andElim(thm, 0)); addCNFFact(d_commonRules->andElim(thm, 1)); return; } // Check the kids in e[0], replace them with cache[e[0][i]], rebuild thm vector changed; vector substitutions; int c=0; for(Expr::iterator j = lhs.begin(), jend = lhs.end(); j!=jend; ++c,++j) { const Expr& phi = *j; if(!phi.isPropLiteral()) { Theorem phiIffVar = findInCNFCache(phi); if(phiIffVar.isNull()) { // Create a new variable for this child phiIffVar = d_commonRules->varIntroSkolem(phi); addToCNFCache(phiIffVar); } DebugAssert(phiIffVar.isRewrite(), "SearchImplBase::applyCNFRules: result = " + result.toString()); DebugAssert(phi == phiIffVar.getLHS(), "SearchImplBase::applyCNFRules:\n phi = " + phi.toString() + "\n\n phiIffVar = " + phiIffVar.toString()); DebugAssert(phiIffVar.getRHS().isAbsLiteral(), "SearchImplBase::applyCNFRules: phiIffVar = " + phiIffVar.toString()); changed.push_back(c); substitutions.push_back(phiIffVar); applyCNFRules(phiIffVar); } } if(changed.size() > 0) { Theorem subst = d_commonRules->substitutivityRule(lhs, changed, substitutions); subst = d_commonRules->symmetryRule(subst); result = d_commonRules->transitivityRule(subst, result); } switch(result.getLHS().getKind()) { case AND: result = d_rules->andCNFRule(result); break; case OR: result = d_rules->orCNFRule(result); break; case IFF: result = d_rules->iffCNFRule(result); break; case IMPLIES: result = d_rules->impCNFRule(result); break; case ITE: result = d_rules->iteCNFRule(result); break; default: DebugAssert(false, "SearchImplBase::applyCNFRules: " "the input operator must be and|or|iff|imp|ite\n result = " + result.getLHS().toString()); break; } // FIXME: eliminate this once debugged Theorem clauses(result); // Enqueue the clauses DebugAssert(!clauses.isNull(), "Oops!.."); DebugAssert(clauses.getExpr().isAnd(), "clauses = " +clauses.getExpr().toString()); // The clauses may containt term ITEs, and we need to translate those for(int i=0, iend=clauses.getExpr().arity(); iandElim(clauses,i)); addCNFFact(clause); } TRACE_MSG("mycnf","applyCNFRules => }"); } bool SearchImplBase::isClause(const Expr& e) { if(e.isAbsLiteral()) return true; if(!e.isOr()) return false; bool cnf(true); for(Expr::iterator i=e.begin(), iend=e.end(); i!=iend && cnf; ++i) cnf = (*i).isAbsLiteral(); return cnf; } bool SearchImplBase::isPropClause(const Expr& e) { if(e.isPropLiteral()) return true; if(!e.isOr()) return false; bool cnf(true); for(Expr::iterator i=e.begin(), iend=e.end(); i!=iend && cnf; ++i) cnf = (*i).isPropLiteral(); return cnf; } bool SearchImplBase::isGoodSplitter(const Expr& e) { if(!*d_ignoreCnfVarsOption) return true; TRACE("isGoodSplitter", "isGoodSplitter(", e, ") {"); // Check for var being an auxiliary CNF variable const Expr& var = e.isNot()? e[0] : e; bool res(!isCNFVar(var)); TRACE("isGoodSplitter", "isGoodSplitter => ", res? "true" : "false", " }"); return res; } void SearchImplBase::addToCNFCache(const Theorem& thm) { TRACE("mycnf", "addToCNFCache(", thm.getExpr(), ")"); d_core->getStatistics().counter("CNF New Vars")++; Theorem result = thm; DebugAssert(result.isRewrite(), "SearchImplBase::addToCNFCache: input must be an iff: " + result.getExpr().toString()); // Record the CNF variable d_cnfVars[thm.getRHS()] = true; Theorem t(thm); Expr phi = thm.getLHS(); while(phi.isNot()) { t = d_commonRules->iffContrapositive(thm); phi = phi[0]; } DebugAssert(d_cnfCache.count(phi) == 0, "thm = "+thm.getExpr().toString() + "\n t = "+ t.getExpr().toString()); //d_cnfCache.insert(phi, t); d_cnfCache.insert(phi, t, d_bottomScope); } Theorem SearchImplBase::findInCNFCache(const Expr& e) { TRACE("mycnf", "findInCNFCache(", e, ") { "); Expr phi(e); int numNegs(0); // Strip all the top-level negations from e while(phi.isNot()) { phi = phi[0]; numNegs++; } CDMap::iterator it = d_cnfCache.find(phi); if(it != d_cnfCache.end()) { // IF_DEBUG(debugger.counter("CNF cache hits")++;) d_core->getStatistics().counter("CNF cache hits")++; Theorem thm = (*it).second; DebugAssert(thm.isRewrite() && thm.getLHS() == phi, "SearchImplBase::findInCNFCache: thm must be an iff: " + thm.getExpr().toString()); // Now put all the negations back. If the number of negations is // odd, first transform phi<=>v into !phi<=>!v. Then apply // !!phi<=>phi rewrite as many times as needed. if(numNegs % 2 != 0) { thm = d_commonRules->iffContrapositive(thm); numNegs--; } for(; numNegs > 0; numNegs-=2) { Theorem t = d_commonRules->rewriteNotNot(!!(thm.getLHS())); thm = d_commonRules->transitivityRule(t,thm); } DebugAssert(numNegs == 0, "numNegs = "+int2string(numNegs)); TRACE("mycnf", "findInCNFCache => ", thm.getExpr(), " }"); return thm; } TRACE_MSG("mycnf", "findInCNFCache => null }"); return Theorem(); } /*! * Strategy: * * For a given atomic formula phi(ite(c, t1, t2)) which depends on a * term ITE, generate an equisatisfiable formula: * * phi(x) & ite(c, t1=x, t2=x), * * where x is a new variable. * * The phi(x) part will be generated by the caller, and our job is to * assert the 'ite(c, t1=x, t2=x)', and return a rewrite theorem * phi(ite(c, t1, t2)) <=> phi(x). */ Theorem SearchImplBase::replaceITE(const Expr& e) { TRACE("replaceITE","replaceITE(", e, ") { "); Theorem res; CDMap::iterator i=d_replaceITECache.find(e), iend=d_replaceITECache.end(); if(i!=iend) { TRACE("replaceITE", "replaceITE[cached] => ", (*i).second, " }"); return (*i).second; } if(e.isAbsLiteral()) res = d_core->rewriteLiteral(e); else res = d_commonRules->reflexivityRule(e); // If 'res' is e<=>phi, and the resulting formula phi is not a // literal, introduce a new variable x, enqueue phi<=>x, and return // e<=>x. if(!res.getRHS().isPropLiteral()) { Theorem varThm(findInCNFCache(res.getRHS())); if(varThm.isNull()) { varThm = d_commonRules->varIntroSkolem(res.getRHS()); Theorem var; if(res.isRewrite()) var = d_commonRules->transitivityRule(res,varThm); else var = d_commonRules->iffMP(res,varThm); //d_cnfVars[var.getExpr()] = true; //addCNFFact(var); addToCNFCache(varThm); } applyCNFRules(varThm); //enqueueCNFrec(varThm); res = d_commonRules->transitivityRule(res, varThm); } d_replaceITECache[e] = res; TRACE("replaceITE", "replaceITE => ", res, " }"); return res; } cvc3-2.4.1/src/search/clause.cpp0000664000175400017540000001354111153264564016305 0ustar mdetersmdeters/*****************************************************************************/ /*! * \file clause.cpp * \brief Implementation of class Clause * * Author: Sergey Berezin * * Created: Mon Apr 28 17:20:23 2003 * *
* * License to use, copy, modify, sell and/or distribute this software * and its documentation for any purpose is hereby granted without * royalty, subject to the terms and conditions defined in the \ref * LICENSE file provided with this distribution. * *
* */ /*****************************************************************************/ #include "clause.h" #include "theory_core.h" using namespace std; namespace CVC3 { //////////////////////////////////////////////////////////////////////// // class ClauseValue methods //////////////////////////////////////////////////////////////////////// // Constructor: takes the main clause theorem which must be a // disjunction of literals and have no assumptions. ClauseValue::ClauseValue(TheoryCore* core, VariableManager* vm, const Theorem& clause, int scope) : d_refcount(0), d_refcountOwner(0), d_thm(clause), d_scope(scope), // This backtrackable member is initialized in the first scope // (which is #0) d_sat(core->getCM()->getCurrentContext(), false, 0), d_deleted(false) { // Check the clause DebugAssert(clause.getExpr().isOr(), "Clause(): bad clause given: " + clause.toString()); // DebugAssert(clause.getExpr().arity()>0, "Clause(): empty clause: " // + clause.toString()); // Initialize watched literals to the edges with directions // pointing outwards d_wp[0]=0; d_dir[0]=-1; d_wp[1] = clause.getExpr().arity()-1; d_dir[1]=1; // Initialize the literals Expr c(clause.getExpr()); d_literals.reserve(c.arity()); for(Expr::iterator i=c.begin(), iend=c.end(); i!=iend; ++i) { int val(i->isNot()? -1 : 1); Variable v(vm, (val < 0)? (*i)[0] : (*i)); Literal l(v, val > 0); d_literals.push_back(l); // Update the literal's count for splitter heuristics l.count()++; } IF_DEBUG(d_sat.setName("CDO[Clause.d_sat]");) } ClauseValue::~ClauseValue() { TRACE_MSG("search literals", "~ClauseValue() {"); FatalAssert(d_refcount == 0, "~ClauseValue: non-zero refcount: " + int2string(d_refcount)); if(!d_deleted) { // Update the literal counts for splitter heuristics for(vector::iterator i=d_literals.begin(), iend=d_literals.end(); i!=iend; ++i) { i->count()--; IF_DEBUG(if(i->count() == 0) TRACE("search literals", "Null count for ", *i, "");) } } TRACE_MSG("search literals", "~ClauseValue() => }"); } //////////////////////////////////////////////////////////////////////// // class Clause methods //////////////////////////////////////////////////////////////////////// // Destructor Clause::~Clause() { if(d_clause != NULL) { FatalAssert(d_clause->d_refcount > 0, "~Clause: non-positive refcount: " + int2string(d_clause->d_refcount)); if(--(d_clause->d_refcount) == 0) delete d_clause; } } void Clause::markDeleted() const { TRACE("search literals", "Clause::markDeleted(", CompactClause(*this), ") {"); DebugAssert(!isNull(), "Clause::markDeleted()"); if(!d_clause->d_deleted) { d_clause->d_deleted = true; // Update the literal counts for splitter heuristics for(vector::iterator i=d_clause->d_literals.begin(), iend=d_clause->d_literals.end(); i!=iend; ++i) { i->count()--; IF_DEBUG(if(i->count() == 0) TRACE("search literals", "Null count for ", *i, "");) } } TRACE_MSG("search literals", "Clause::markDeleted => }"); } // Assignment operator Clause& Clause::operator=(const Clause& c) { if(&c == this) return *this; // Self-assignment if(d_clause != NULL) { DebugAssert(d_clause->d_refcount > 0, "Clause::operator=: non-positive refcount: " + int2string(d_clause->d_refcount)); if(--(d_clause->d_refcount) == 0) delete d_clause; } d_clause = c.d_clause; if(d_clause != NULL) d_clause->d_refcount++; return *this; } // Printing string Clause::toString() const { std::ostringstream ss; ss << *this; return ss.str(); } ostream& operator<<(ostream& os, const Clause& c) { if(c.isNull()) return os << "Clause[Null]"; os << "Clause["; if(c.deleted()) os << "DELETED "; os << c.id(); IF_DEBUG(if(c.getFile() != "") os << ", " << c.getFile() << ":" << c.getLine();) os << "](" << c.getTheorem() << ";\n"; if(c.wp(0) == c.wp(1)) os << "WARNING: wp[0] = wp[1]\n"; for(unsigned i=0; i 0)? "=>" : "<=") << " "; else if(c.wp(1) == i) os << "wp[1]" << ((c.dir(1) > 0)? "=>" : "<=") << " "; else os << " "; os << c[i] << ";\n"; } return os << ((c.sat())? "Clause is SAT" : "") << ")"; } static void printLit(ostream& os, const Literal& l) { if(l.isNegative()) os << "!"; os << l.getVar().getExpr(); int val(l.getValue()); if(val != 0) os << "=" << val << "@" << l.getScope(); } ostream& operator<<(std::ostream& os, const CompactClause& c) { const vector& lits = c.d_clause.getLiterals(); int wp0(c.d_clause.wp(0)), wp1(c.d_clause.wp(1)); int i=0, iend=c.d_clause.size(); os << "Clause["; if(c.d_clause.deleted()) os << "*DELETED* "; if(c.d_clause.owners() > 0) os << "owned(" << c.d_clause.owners() << ") "; if(i!=iend) { if(i==wp0 || i==wp1) os << "*"; printLit(os, lits[i]); ++i; } for(; i!=iend; ++i) { os << ", "; if(i==wp0 || i==wp1) os << "*"; printLit(os, lits[i]); } os << "]"; return os; } string CompactClause::toString() const { ostringstream ss; ss << (*this); return ss.str(); } #ifdef _CVC3_DEBUG_MODE bool CVC3::Clause::wpCheck() const { if (sat(true)) return true; return (getLiteral(wp(0)).getValue() == 0 && getLiteral(wp(1)).getValue() == 0); } #endif } // end of namespace CVC3 cvc3-2.4.1/src/search/search.cpp0000664000175400017540000000706011351741373016273 0ustar mdetersmdeters/*****************************************************************************/ /*! * \file search.cpp * * Author: Clark Barrett, Vijay Ganesh (CNF Converter) * * Created: Fri Jan 17 14:19:54 2003 * *
* * License to use, copy, modify, sell and/or distribute this software * and its documentation for any purpose is hereby granted without * royalty, subject to the terms and conditions defined in the \ref * LICENSE file provided with this distribution. * *
* */ /*****************************************************************************/ #include "search.h" #include "search_rules.h" #include "theory_core.h" #include "eval_exception.h" #include "theorem_manager.h" #include "command_line_flags.h" using namespace CVC3; using namespace std; //! Constructor SearchEngine::SearchEngine(TheoryCore* core) : d_core(core), d_commonRules(core->getTM()->getRules()) { const CLFlags& flg = (core->getTM()->getFlags()); if (flg["lfsc-mode"].getInt()!= 0){ d_rules = createRules(this); } else d_rules = createRules(); } //! Destructor SearchEngine::~SearchEngine() { delete d_rules; } bool SearchEngine::tryModelGeneration(Theorem& thm) { if(!lastThm().isNull()) throw EvalException("Method tryModelGenereation() (or command COUNTERMODEL)\n must be called only after failed QUERY"); // Save the scope level, to recover on errors push(); d_core->collectBasicVars(); bool success = d_core->refineCounterExample(thm); if (!success) { pop(); return false; } QueryResult qres = checkValid(d_core->falseExpr(), thm); if(qres == VALID) { pop(); return false; } success = d_core->buildModel(thm); if (!success) { pop(); return false; } qres = checkValid(d_core->falseExpr(), thm); if(qres == VALID) { pop(); return false; } return true; } void SearchEngine::getConcreteModel(ExprMap& m) { TRACE("model" , "Building a concrete model", "", "{"); if(!lastThm().isNull()) throw EvalException ("Method getConcreteModel() (or command COUNTERMODEL)\n" " must be called only after failed QUERY"); // Save the scope level, to recover on errors push(); d_core->collectBasicVars(); try { d_core->refineCounterExample(); } catch(Exception& e) { // Clean up and re-throw the exception pop(); throw e; } Theorem thm; QueryResult qres = checkValid(d_core->falseExpr(), thm); if(qres == VALID) { vector assump; getAssumptions(assump); d_core->inconsistentThm().getLeafAssumptions(assump); Expr a = Expr(RAW_LIST, assump, d_core->getEM()); pop(); throw Exception ("Model Creation failed after refining counterexample\n" "due to the following assumptions:\n " +a.toString() +"\n\nYou might be using an incomplete fragment of the theory"); } // else if (qres != INVALID) { // throw EvalException // ("Unable to build concrete model"); // } try { d_core->buildModel(m); } catch(Exception& e) { // Clean up and re-throw the exception pop(); throw e; } qres = checkValid(d_core->falseExpr(), thm); if(qres == VALID) { vector assump; getAssumptions(assump); Expr a = Expr(RAW_LIST, assump, d_core->getEM()); pop(); throw Exception ("Model Creation failed due to the following assumptions:\n" +a.toString() +"\n\nYou might be using an incomplete fragment of the theory"); } // else if (qres != INVALID) { // throw EvalException // ("Unable to build concrete model"); // } TRACE("model" , "Building a concrete model", "", "}"); } cvc3-2.4.1/src/search/search_simple.cpp0000664000175400017540000001512610565673025017652 0ustar mdetersmdeters/*****************************************************************************/ /*! * \file search_simple.cpp * * Author: Clark Barrett * * Created: Sat Mar 29 21:59:36 2003 * *
* * License to use, copy, modify, sell and/or distribute this software * and its documentation for any purpose is hereby granted without * royalty, subject to the terms and conditions defined in the \ref * LICENSE file provided with this distribution. * *
* */ /*****************************************************************************/ #include "search_simple.h" #include "theory_core.h" #include "typecheck_exception.h" #include "search_rules.h" #include "decision_engine_dfs.h" //#include "decision_engine_caching.h" //#include "decision_engine_mbtf.h" #include "expr_transform.h" #include "command_line_flags.h" using namespace std; using namespace CVC3; QueryResult SearchSimple::checkValidRec(Theorem& thm) { if (d_core->outOfResources()) return ABORT; TRACE_MSG("search", "checkValidRec() {"); if (d_core->inconsistent()) { TRACE("search", "checkValidRec => ", d_core->inconsistentThm(), " (context inconsistent) }"); d_decisionEngine->goalSatisfied(); thm = d_core->inconsistentThm(); return UNSATISFIABLE; } Theorem e = d_goal.get(); bool workingOnGoal = true; if (d_goal.get().getExpr().isTrue()) { e = d_nonLiterals.get(); workingOnGoal = false; } Theorem simp = simplify(e); Expr rhs = simp.getExpr(); if (rhs.hasFind()) { simp = d_commonRules->iffMP(simp, d_core->find(rhs)); rhs = simp.getExpr(); } if (workingOnGoal) d_goal.set(simp); else d_nonLiterals.set(simp); if (rhs.isFalse()) { TRACE("search", "checkValidRec => ", simp, " (rhs=false) }"); d_decisionEngine->goalSatisfied(); thm = simp; return UNSATISFIABLE; } else if (rhs.isTrue()) { if (workingOnGoal || !d_core->checkSATCore()) { return checkValidRec(thm); } TRACE("search", "checkValidRec => ", "Null (true)", "}"); thm = Theorem(); return SATISFIABLE; } Expr splitter = d_decisionEngine->findSplitter(rhs); DebugAssert(!splitter.isNull(), "Expected splitter"); d_decisionEngine->pushDecision(splitter); QueryResult qres = checkValidRec(thm); if (qres == UNSATISFIABLE) { d_decisionEngine->popDecision(); d_decisionEngine->pushDecision(splitter, false); Theorem thm2; qres = checkValidRec(thm2); if (qres == UNSATISFIABLE) { d_decisionEngine->popDecision(); thm = d_rules->caseSplit(splitter, thm, thm2); return qres; } thm = thm2; return qres; } return qres; } SearchSimple::SearchSimple(TheoryCore* core) : SearchImplBase(core), d_name("simple"), d_goal(core->getCM()->getCurrentContext()), d_nonLiterals(core->getCM()->getCurrentContext()), d_simplifiedThm(core->getCM()->getCurrentContext()) { // if (core->getFlags()["de"].getString() == "caching") // d_decisionEngine = new DecisionEngineCaching(core, this); // else if (core->getFlags()["de"].getString() == "mbtf") // d_decisionEngine = new DecisionEngineMBTF(core, this); // else d_decisionEngine = new DecisionEngineDFS(core, this); d_goal.set(d_commonRules->trueTheorem()); d_nonLiterals.set(d_commonRules->trueTheorem()); } SearchSimple::~SearchSimple() { delete d_decisionEngine; } QueryResult SearchSimple::checkValidMain(const Expr& e2) { Theorem thm; QueryResult qres = checkValidRec(thm); if (qres == SATISFIABLE && d_core->incomplete()) qres = UNKNOWN; if (qres == SATISFIABLE) { DebugAssert(d_goal.get().getExpr().isTrue(), "checkValid: Expected true goal"); vector a; d_goal.get().getLeafAssumptions(a); d_lastCounterExample.clear(); for (vector::iterator i=a.begin(), iend=a.end(); i != iend; ++i) { d_lastCounterExample[*i] = true; } } else if (qres != UNSATISFIABLE) return qres; processResult(thm, e2); if (qres == UNSATISFIABLE) { TRACE_MSG("search terse", "checkValid => true}"); TRACE("search", "checkValid => true; theorem = ", d_lastValid, "}"); Theorem e_iff_e2(d_commonRules->iffContrapositive(d_simplifiedThm)); d_lastValid = d_commonRules->iffMP(d_lastValid, d_commonRules->symmetryRule(e_iff_e2)); d_core->getCM()->pop(); } else { TRACE_MSG("search terse", "checkValid => false}"); TRACE_MSG("search", "checkValid => false; }"); } return qres; } QueryResult SearchSimple::checkValidInternal(const Expr& e) { DebugAssert(d_goal.get().getExpr().isTrue(),"checkValid: Expected true goal"); DebugAssert(d_nonLiterals.get().getExpr().isTrue(),"checkValid: Expected true nonLiterals"); TRACE("search", "checkValid(", e, ") {"); TRACE_MSG("search terse", "checkValid() {"); if (!e.getType().isBool()) { throw TypecheckException ("checking validity of a non-boolean expression:\n\n " + e.toString() + "\n\nwhich has the following type:\n\n " + e.getType().toString()); } // A successful query should leave the context unchanged d_core->getCM()->push(); d_bottomScope = scopeLevel(); d_simplifiedThm.set(d_core->getExprTrans()->preprocess(e.negate())); TRACE("search", "checkValid: simplifiedThm = ", d_simplifiedThm, ""); const Expr& not_e2 = d_simplifiedThm.get().getRHS(); Expr e2 = not_e2.negate(); // Assert not_e2 if it's not already asserted TRACE_MSG("search terse", "checkValid: Asserting !e: "); TRACE("search", "checkValid: Asserting !e: ", not_e2, ""); Theorem not_e2_thm; if(d_assumptions.count(not_e2) == 0) { not_e2_thm = newUserAssumption(not_e2); } else { not_e2_thm = d_assumptions[not_e2]; } d_core->addFact(not_e2_thm); d_goal.set(not_e2_thm); return checkValidMain(e2); } QueryResult SearchSimple::restartInternal(const Expr& e) { TRACE("search", "restart(", e, ") {"); TRACE_MSG("search terse", "restart() {"); if (!e.getType().isBool()) { throw TypecheckException ("argument to restart is a non-boolean expression:\n\n " + e.toString() + "\n\nwhich has the following type:\n\n " + e.getType().toString()); } if (d_bottomScope == 0) { throw Exception("Call to restart with no current query"); } d_core->getCM()->popto(d_bottomScope); Expr e2 = d_simplifiedThm.get().getRHS().negate(); TRACE_MSG("search terse", "restart: Asserting e: "); TRACE("search", "restart: Asserting e: ", e, ""); if(d_assumptions.count(e) == 0) { d_core->addFact(newUserAssumption(e)); } return checkValidMain(e2); } void SearchSimple::addNonLiteralFact(const Theorem& thm) { d_nonLiterals.set(d_commonRules->andIntro(d_nonLiterals.get(), thm)); } cvc3-2.4.1/src/search/LFSCLraProof.h0000664000175400017540000001207611363704204016665 0ustar mdetersmdeters#ifndef LFSC_LRA_PROOF_H_ #define LFSC_LRA_PROOF_H_ #include "LFSCProof.h" // lra_add_~_~ class LFSCLraAdd: public LFSCProof{ private: RefPtr< LFSCProof > d_children[2]; int d_op1, d_op2; LFSCLraAdd(LFSCProof* pf1, LFSCProof* pf2, int op1, int op2): LFSCProof(), d_op1(op1), d_op2(op2){ d_children[0] = pf1; d_children[1] = pf2; } virtual ~LFSCLraAdd(){} long int get_length(){ return 20 + d_children[0]->get_string_length() + d_children[1]->get_string_length(); } public: virtual LFSCLraAdd* AsLFSCLraAdd(){ return this; } void print_pf( std::ostream& s, int ind = 0 ); static LFSCProof* Make(LFSCProof* pf1, LFSCProof* pf2, int op1, int op2); LFSCProof* clone() { return new LFSCLraAdd( d_children[0].get(), d_children[1].get(), d_op1, d_op2 ); } int getNumChildren() { return 2; } LFSCProof* getChild( int n ) { return d_children[n].get(); } int checkOp() { return get_knd_result( d_op1, d_op2 ); } }; // lra_~_axiom class LFSCLraAxiom: public LFSCProof{ private: static RefPtr< LFSCProof > eq; int d_op; Rational d_r; LFSCLraAxiom(int op ) : LFSCProof(), d_op(op){} LFSCLraAxiom(int op, Rational r): LFSCProof(), d_op(op), d_r(r){} virtual ~LFSCLraAxiom(){} long int get_length(){ return 15; } public: virtual LFSCLraAxiom* AsLFSCLraAxiom(){ return this; } void print_pf( std::ostream& s, int ind = 0 ); bool isTrivial() { return d_op==EQ; } static LFSCProof* MakeEq(); static LFSCProof* Make( Rational r, int op ){ return new LFSCLraAxiom( op,r ); } LFSCProof* clone() { return new LFSCLraAxiom( d_op, d_r ); } int checkOp() { return d_op; } }; // lra_mult_c class LFSCLraMulC: public LFSCProof{ private: RefPtr< LFSCProof > d_pf; Rational d_r; int d_op; // = | > | >= | distinct LFSCLraMulC(LFSCProof* pf, Rational r, int op): LFSCProof(), d_pf(pf), d_r(r), d_op(op){ d_op = pf->checkOp() != -1 ? pf->checkOp() : d_op; } virtual ~LFSCLraMulC(){} long int get_length(){ return 20 + d_pf->get_string_length(); } public: virtual LFSCLraMulC* AsLFSCLraMulC(){ return this; } bool isLraMulC() { return true; } void print_pf( std::ostream& s, int ind = 0 ); static LFSCProof* Make(LFSCProof* pf, Rational r, int op); LFSCProof* clone() { return new LFSCLraMulC( d_pf.get(), d_r, d_op ); } int getNumChildren() { return 1; } LFSCProof* getChild( int n ) { return d_pf.get(); } int checkOp() { return d_op; } }; // lra_sub_~_~ class LFSCLraSub: public LFSCProof{ private: RefPtr< LFSCProof > d_children[2]; int d_op1, d_op2; LFSCLraSub(LFSCProof* pf1, LFSCProof* pf2, int op1, int op2): LFSCProof(), d_op1(op1), d_op2(op2){ d_children[0] = pf1; d_children[1] = pf2; d_op1 = pf1->checkOp()!=-1 ? pf1->checkOp() : d_op1; d_op2 = pf2->checkOp()!=-1 ? pf2->checkOp() : d_op2; } virtual ~LFSCLraSub(){} long int get_length(){ return 20 + d_children[0]->get_string_length() + d_children[1]->get_string_length(); } public: virtual LFSCLraSub* AsLFSCLraSub(){ return this; } void print_pf( std::ostream& s, int ind = 0 ); static LFSCProof* Make(LFSCProof* pf1, LFSCProof* pf2, int op1, int op2); LFSCProof* clone() { return new LFSCLraSub( d_children[0].get(), d_children[1].get(), d_op1, d_op2 ); } int getNumChildren() { return 2; } LFSCProof* getChild( int n ) { return d_children[n].get(); } int checkOp() { return get_knd_result( d_op1, d_op2 ); } }; class LFSCLraPoly : public LFSCProof { private: RefPtr< LFSCProof > d_pf; int d_var; int d_op; LFSCLraPoly( LFSCProof* pf, int var, int op ) : LFSCProof(), d_pf( pf ), d_var( var ), d_op( op ){ d_op = pf->checkOp() != -1 ? pf->checkOp() : d_op; } virtual ~LFSCLraPoly(){} long int get_length(){ return 15 + d_pf->get_string_length(); } public: virtual LFSCLraPoly* AsLFSCLraPoly(){ return this; } void print_pf( std::ostream& s, int ind = 0 ); static LFSCProof* Make( LFSCProof* pf, int var, int op ){ return new LFSCLraPoly( pf, var, op ); } static LFSCProof* Make( const Expr& e, LFSCProof* p ); LFSCProof* clone() { return new LFSCLraPoly( d_pf.get(), d_var, d_op ); } int getNumChildren() { return 1; } LFSCProof* getChild( int n ) { return d_pf.get(); } int checkOp() { return get_normalized( d_op, d_var<0 ); } }; class LFSCLraContra : public LFSCProof { private: RefPtr< LFSCProof > d_pf; int d_op; LFSCLraContra( LFSCProof* pf, int op ) : LFSCProof(), d_pf( pf ), d_op( op ){ d_op = pf->checkOp() != -1 ? pf->checkOp() : d_op; } virtual ~LFSCLraContra(){} long int get_length(){ return 15 + d_pf->get_string_length(); } public: virtual LFSCLraContra* AsLFSCLraContra(){ return this; } void print_pf( std::ostream& s, int ind = 0 ){ s <<"(lra_contra_" << kind_to_str(d_op) << " _ "; d_pf->print( s, ind+1 ); s << ")"; } static LFSCProof* Make( LFSCProof* pf, int op ){ return new LFSCLraContra( pf, op ); } LFSCProof* clone() { return new LFSCLraContra( d_pf.get(), d_op ); } int getNumChildren() { return 1; } LFSCProof* getChild( int n ) { return d_pf.get(); } int checkOp() { return d_op; } }; #endif cvc3-2.4.1/src/search/LFSCProof.cpp0000664000175400017540000003057211363704204016562 0ustar mdetersmdeters#include "LFSCProof.h" #include "LFSCBoolProof.h" #include "LFSCUtilProof.h" int LFSCProof::pf_counter = 0; std::map< LFSCProof*, int > LFSCProof::lambdaMap; std::map< LFSCProof*, LFSCProof* > LFSCProof::lambdaPrintMap; int LFSCProof::lambdaCounter = 1; LFSCProof::LFSCProof() { pf_counter++; printCounter = 0; strLen = -1; rplProof = NULL; chOp = -1; brComputed = false; assumeVar = -1; assumeVarUsed = -1; } void LFSCProof::print( std::ostream& s, int ind ){ LFSCProof* p = rplProof ? rplProof : lambdaPrintMap[this]; if( p ){ p->print( s, ind ); }else{ if( lambdaMap.find( this )!=lambdaMap.end() && printCounter>0 ){ print_warning( "Warning: printing out lambda abstracted proof more than once"); #ifdef IGNORE_PRINT_MULTI_LAMBDA return; #endif } //if( printCounter>0 ){ // return; //} printCounter++; indent( s, ind ); print_pf( s, ind ); } } void LFSCProof::print_structure( std::ostream& s, int ind ){ LFSCProof* p = rplProof ? rplProof : lambdaPrintMap[this]; if( p ){ p->print( s, ind ); }else{ indent( s, ind ); if( lambdaMap.find( this )!=lambdaMap.end() && printCounter>0 ){ //just a warning, print it out in ose print_warning( "ERROR: printing out lambda abstracted proof more than once" ); #ifdef IGNORE_PRINT_MULTI_LAMBDA return; #endif } printCounter++; print_struct( s, ind ); } } void LFSCProof::fillHoles(){ //if( !is_lambda() ){ for( int a=0; afillHoles(); } //} } #ifdef OPTIMIZE void LFSCProof::calcL( std::vector< int >& lget, std::vector< int >& lgetu ){ for( int a=0; acalcL( lget, lgetu ); } if( assumeVar!=-1 && std::find( lget.begin(), lget.end(), assumeVar )==lget.end() ){ lget.push_back( assumeVar ); } if( assumeVarUsed!=-1 && std::find( lgetu.begin(), lgetu.end(), assumeVarUsed )==lgetu.end() ){ lgetu.push_back( assumeVarUsed ); } } #endif int LFSCProof::checkOp() { if( chOp!=-1 ) return chOp; if( getNumChildren()==1 ) return getChild( 0 )->checkOp(); else{ int ret = -1; for( int a=0; acheckOp(); if( a!=-1 ){ if( ret==-1 ) ret = a; else return -1; } } //cout << "fail case " << getNumChildren() << std::endl; return ret; } } LFSCProof* LFSCProof::Make_CNF( const Expr& form, const Expr& reason, int pos ) { Expr ec = cascade_expr( form ); #ifdef PRINT_MAJOR_METHODS cout << ";[M] CNF " << reason << " " << pos << std::endl; #endif int m = queryM( ec ); if( m>0 ) { ostringstream os1; ostringstream os2; RefPtr< LFSCProof > p; if( reason==d_or_final_s ) { #if 0 //this is the version that cascades //make the proof for the or p = LFSCPfVar::Make( "@v", abs(m) ); //clausify the or statement p = LFSCClausify::Make( ec, p.get(), true ); //return return LFSCAssume::Make( m, p.get(), true ); #else //this is the version that does not expand the last ostringstream oss1, oss2; p = LFSCPfVar::Make( "@v", abs(m) ); for( int a=(form.arity()-2); a>=0; a-- ){ int m1 = queryM( form[a] ); oss1 << "(or_elim_1 _ _ "; oss1 << ( m1<0 ? "(not_not_intro _ " : "" ); oss1 << "@v" << abs( m1 ); oss1 << ( m1<0 ? ") " : " " ); oss2 << ")"; } p = LFSCProofGeneric::Make( oss1.str(), p.get(), oss2.str() ); //p = LFSCClausify::Make( form[form.arity()-1], p.get() ); p = LFSCClausify::Make( queryM( form[form.arity()-1] ), p.get() ); for( int a=0; a<(form.arity()-1); a++ ){ p = LFSCAssume::Make( queryM( form[a] ), p.get(), false ); } return LFSCAssume::Make( m, p.get() ); #endif } else if( reason==d_and_final_s ) { #if 1 //this is the version that does not expand the last p = LFSCPfVar::Make( "@v", abs(m) ); os1 << "(contra _ "; for( int a=0; a assumes; Expr ce = cascade_expr( form ); Expr curr = ce; os1 << "(contra _ "; while( curr.getKind()==AND ){ os1 << "(and_intro _ _ "; os1 << "@v" << abs( queryM( curr[0] ) ) << " "; os2 << ")"; assumes.push_back( curr[0] ); curr = curr[1]; } os2 << " @v" << abs(m) << ")"; p = LFSCProofGeneric::Make( os1.str(), p.get(), os2.str() ); for( int a=0; a<(int)assumes.size(); a++ ){ p = LFSCAssume::Make( queryM( assumes[a] ), p.get() ); } return LFSCAssume::Make( m, p.get(), false ); #endif } else if( reason==d_imp_s ) { int m1 = queryM( ec[0] ); int m2 = queryM( ec[1] ); switch( pos ) { case 0: break; case 1: break; case 2: { //make a proof of the RHS ostringstream os; os << "(impl_elim _ _ @v" << abs( m1 ) << " @v" << abs( m ) << ")"; p = LFSCProofGeneric::MakeStr( os.str().c_str() ); //clausify the RHS p = LFSCClausify::Make( form[1], p.get() ); //cascadeOr? p = LFSCAssume::Make( queryM( ec[0] ), p.get() ); return LFSCAssume::Make( queryM( ec ), p.get() ); } break; } } else if( reason==d_ite_s ) { int m1 = queryM( ec[0] ); int m2 = queryM( ec[1] ); switch( pos ) { case 1: { ostringstream os; os << "(ite_elim_2" << (m1<0 ? "n" : "" ); os << " _ _ _ @v" << abs( m1 ) << " @v" << abs( m ) << ")"; p = LFSCProofGeneric::MakeStr( os.str().c_str() ); p = LFSCClausify::Make( form[2], p.get() ); p = LFSCAssume::Make( queryM( ec[0] ), p.get(), false ); return LFSCAssume::Make( queryM( ec ), p.get() ); } break; case 2: { ostringstream os; os << "(not_ite_elim_2 _ _ _ @v" << (m1<0 ? "n" : "" ); os << abs( m1 ) << " @v" << abs( m ) << ")"; p = LFSCProofGeneric::MakeStr( os.str().c_str() ); Expr e = Expr( NOT, form[2] ); p = LFSCClausify::Make( e, p.get() ); p = LFSCAssume::Make( queryM( ec[0] ), p.get(), false ); return LFSCAssume::Make( queryM( ec ), p.get(), false ); } break; case 3: { ostringstream os; os << "(not_ite_elim_1 _ _ _ @v" << abs( m1 ) << " @v" << abs( m ) << ")"; p = LFSCProofGeneric::MakeStr( os.str().c_str() ); Expr e = Expr( NOT, form[1] ); p = LFSCClausify::Make( e, p.get() ); p = LFSCAssume::Make( queryM( ec[0] ), p.get() ); return LFSCAssume::Make( queryM( ec ), p.get(), false ); } break; case 4: { ostringstream os; os << "(ite_elim_1";// << (m1<0 ? "n" : "" ); os << " _ _ _ @v" << abs( m1 ) << " @v" << abs( m ) << ")"; p = LFSCProofGeneric::MakeStr( os.str().c_str() ); p = LFSCClausify::Make( form[1], p.get() ); p = LFSCAssume::Make( queryM( ec[0] ), p.get() ); return LFSCAssume::Make( queryM( ec ), p.get() ); } break; case 5: { ostringstream os; os << "(not_ite_elim_3 _ _ _ @v" << abs( m2 ) << " @v" << abs( m ) << ")"; p = LFSCProofGeneric::MakeStr( os.str().c_str() ); Expr e = Expr( NOT, form[2] ); p = LFSCClausify::Make( e, p.get() ); p = LFSCAssume::Make( queryM( ec[1] ), p.get() ); return LFSCAssume::Make( queryM( ec ), p.get(), false ); } break; case 6: { ostringstream os; os << "(ite_elim_3";// << (m1<0 ? "n" : "" ); os << " _ _ _ @v" << abs( m2 ) << " @v" << abs( m ) << ")"; p = LFSCProofGeneric::MakeStr( os.str().c_str() ); p = LFSCClausify::Make( form[2], p.get() ); p = LFSCAssume::Make( queryM( ec[1] ), p.get(), false ); return LFSCAssume::Make( queryM( ec ), p.get() ); } break; } } else if( reason==d_iff_s ) { int m1 = queryM( ec[0] ); int m2 = queryM( ec[1] ); switch( pos ) { case 0: { ostringstream os; os << "(not_iff_elim_1 _ _ @v" << abs( m1 ) << " @v" << abs( m ) << ")"; p = LFSCProofGeneric::MakeStr( os.str().c_str() ); p = LFSCClausify::Make( form[1], p.get() ); p = LFSCAssume::Make( queryM( ec[0] ), p.get(), false ); return LFSCAssume::Make( queryM( ec ), p.get(), false ); } break; case 1: { ostringstream os; os << "(not_iff_elim_2 _ _ @v" << abs( m1 ) << " @v" << abs( m ) << ")"; p = LFSCProofGeneric::MakeStr( os.str().c_str() ); p = LFSCClausify::Make( Expr( NOT, form[1] ), p.get() ); p = LFSCAssume::Make( queryM( ec[0] ), p.get() ); return LFSCAssume::Make( queryM( ec ), p.get(), false ); } break; case 2: { ostringstream os; os << "(impl_elim _ _ @v" << abs( m1 ) << "(iff_elim_1 _ _ @v" << abs( m ) << "))"; p = LFSCProofGeneric::MakeStr( os.str().c_str() ); //clausify the RHS p = LFSCClausify::Make( form[1], p.get() ); //cascadeOr? p = LFSCAssume::Make( queryM( ec[0] ), p.get() ); return LFSCAssume::Make( queryM( ec ), p.get() ); } break; case 3: { ostringstream os; os << "(impl_elim _ _ @v" << abs( m2 ) << "(iff_elim_2 _ _ @v" << abs( m ) << "))"; p = LFSCProofGeneric::MakeStr( os.str().c_str() ); //clausify the RHS p = LFSCClausify::Make( form[0], p.get() ); //cascadeOr? p = LFSCAssume::Make( queryM( ec[1] ), p.get() ); return LFSCAssume::Make( m, p.get() ); } break; } } else if( reason==d_or_mid_s ) { ostringstream os1, os2; if( form[pos].isNot() ) os1 << "(not_not_elim _ "; os1 << "(or_elim" << ( (pos==form.arity()) ? "_end" : "" ); os1 << " _ _ " << pos << " "; os2 << ")"; if( form[pos].isNot() ) os2 << ")"; p = LFSCPfVar::Make( "@v", abs( m ) ); p = LFSCProofGeneric::Make( os1.str(), p.get(), os2.str() ); Expr ea = Expr( NOT, form[pos] ); p = LFSCClausify::Make( ea, p.get() ); return LFSCAssume::Make( m, p.get(), false ); } else if( reason==d_and_mid_s ) { //make a proof of the pos-th statement p = LFSCPfVar::Make( "@v", abs( m ) ); p = LFSCProof::Make_and_elim( form, p.get(), pos, form[pos] ); p = LFSCClausify::Make( form[pos], p.get() ); return LFSCAssume::Make( m, p.get() ); } } ostringstream ose; ose << "CNF, " << reason << " unknown position = " << pos << std::endl; print_error( ose.str().c_str(), cout ); return NULL; } LFSCProof* LFSCProof::Make_not_not_elim( const Expr& pf, LFSCProof* p ) { if( pf.isNot() && pf[0].isNot() ){ p = Make_not_not_elim( pf[0][0], p ); ostringstream os1, os2; os1 << "(not_not_elim _ "; os2 << ")"; p = LFSCProofGeneric::Make( os1.str(), p, os2.str() ); } return p; } LFSCProof* LFSCProof::Make_mimic( const Expr& pf, LFSCProof* p, int numHoles ) { ostringstream os1, os2; os1 << "("; os1 << pf[0]; for( int a=0; a1 ) { ostringstream os1, os2; os1 << "(and_elim"; if( n==form.arity()-1 ) os1 << "_end"; os1 << " _ _ " << n << " "; os2 << ")"; return LFSCProofGeneric::Make( os1.str(), p, os2.str() ); } else { return p; } } cvc3-2.4.1/src/search/decision_engine_mbtf.h0000664000175400017540000000232610466450544020630 0ustar mdetersmdeters/*****************************************************************************/ /*! * \file decision_engine_mbtf.h * *
* * License to use, copy, modify, sell and/or distribute this software * and its documentation for any purpose is hereby granted without * royalty, subject to the terms and conditions defined in the \ref * LICENSE file provided with this distribution. * *
* */ /*****************************************************************************/ #ifndef _cvc3__search__decision_engine_mbtf_h_ #define _cvc3__search__decision_engine_mbtf_h_ #include "decision_engine.h" namespace CVC3 { class DecisionEngineMBTF : public DecisionEngine { class CacheEntry { public: Expr d_expr; int d_rank; int d_trust; CacheEntry() : d_rank(0), d_trust(0) {} }; int d_startLevel; int d_bottomLevel; int d_topLevel; bool d_topLevelLock; int d_height; std::vector d_cache; ExprMap d_index; protected: virtual bool isBetter(const Expr& e1, const Expr& e2); public: DecisionEngineMBTF(TheoryCore* core, SearchImplBase* se); virtual ~DecisionEngineMBTF() { } virtual Expr findSplitter(const Expr& e); virtual void goalSatisfied(); }; } #endif cvc3-2.4.1/src/search/decision_engine_dfs.cpp0000664000175400017540000000437010656155011021000 0ustar mdetersmdeters/*****************************************************************************/ /*! * \file decision_engine_dfs.cpp * \brief Decision Engine * * Author: Clark Barrett * * Created: Sun Jul 13 22:44:55 2003 * *
* * License to use, copy, modify, sell and/or distribute this software * and its documentation for any purpose is hereby granted without * royalty, subject to the terms and conditions defined in the \ref * LICENSE file provided with this distribution. * *
* */ /*****************************************************************************/ #include "decision_engine_dfs.h" #include "theory_core.h" #include "search.h" using namespace std; using namespace CVC3; bool DecisionEngineDFS::isBetter(const Expr& e1, const Expr& e2) { return false; } /*****************************************************************************/ /*! * Function: DecisionEngineDFS::DecisionEngineDFS * * Author: Clark Barrett * * Created: Sun Jul 13 22:52:51 2003 * * Constructor */ /*****************************************************************************/ DecisionEngineDFS::DecisionEngineDFS(TheoryCore* core, SearchImplBase* se) : DecisionEngine(core, se) { } /*****************************************************************************/ /*! * Function: DecisionEngineDFS::findSplitter * * Author: Clark Barrett * * Created: Sun Jul 13 22:53:18 2003 * * Main function to choose the next splitter. * \return NULL if all known splitters are assigned. */ /*****************************************************************************/ Expr DecisionEngineDFS::findSplitter(const Expr& e) { TRACE("splitters verbose", "findSplitter(", e, ") {"); Expr splitter; // Null by default d_visited.clear(); if (!e.isNull()) { splitter = findSplitterRec(e); // It's OK not to find a splitter, since e may contain only "bad" // splitters, according to d_se->isGoodSplitter(e) // DebugAssert(!splitter.isNull(), // "findSplitter: can't find splitter in non-literal: " // + e.toString()); IF_DEBUG(if(!splitter.isNull()) debugger.counter("splitters from decision engine")++;) } TRACE("splitters verbose", "findSplitter => ", splitter, " }"); return splitter; } void DecisionEngineDFS::goalSatisfied() { } cvc3-2.4.1/src/search/LFSCBoolProof.cpp0000664000175400017540000001116011363704204017366 0ustar mdetersmdeters#include "LFSCBoolProof.h" #include "LFSCUtilProof.h" //LFSCBoolRes ... void LFSCBoolRes::print_pf( std::ostream& s, int ind ){ if( d_col ){ s << "(cRR _ _ _ _ @a" << abs( d_var ); s << " "; d_children[0]->print(s, ind+1); s <<" "; d_children[1]->print(s, ind+1); s <<")"; }else{ s <<"(" << (d_var>0 ? "R" : "Q" ) << " _ _ "; d_children[0]->print(s, ind+1); s <<" "; d_children[1]->print(s, ind+1); s <<" @b" << abs( d_var ) << ")"; } } void LFSCBoolRes::print_struct( std::ostream& s, int ind ){ s << "(res " << d_var; d_children[0]->print_structure(s, ind+1); s <<" "; d_children[1]->print_structure(s, ind+1); s << ")"; } LFSCProof* LFSCBoolRes::Make(LFSCProof* pf1, LFSCProof* pf2, int v, bool col){ if( pf1->isTrivial() ) return pf2; else if( pf2->isTrivial() ) return pf1; else return new LFSCBoolRes( pf1, pf2, v, col ); } int LFSCBoolRes::checkBoolRes( std::vector< int >& clause ){ std::vector< int > c[2]; for( int a=0; a<2; a++ ){ d_children[a]->checkBoolRes( c[a] ); bool success = false; for( int b=0; b<(int)c[a].size(); b++ ){ if( c[a][b]==d_var ){ c[a].erase( c[a].begin() + b, c[a].begin() + b + 1 ); b--; success = true; } } if( ! success ){ print_error( "A check-in failed ", cout ); return -1; } for( int b=0; b<(int)c[a].size(); b++ ){ if( std::find( clause.begin(), clause.end(), c[a][b] )==clause.end() ){ clause.push_back( c[a][b] ); } } } return 0; } LFSCProof* LFSCBoolRes::Make( LFSCProof* p1, LFSCProof* p2, const Expr& res, const Expr& pf, bool cascadeOr ) { Expr cres = cascade_expr( res ); if( cres.getKind()==OR && cascadeOr ) { return Make( MakeC( p1, cres ), p2, queryM( cres ), true ); } else if( cres.isNot() && cres[0].getKind()==OR && cascadeOr ) { return Make( MakeC( p2, cres[0] ), p1, queryM( cres[0] ), true ); } else if( cres.isNot() && cres[0].isNot() ) { ostringstream ose; ose << "Error: Resolving on double negation" << cres; print_error( ose.str().c_str(), cout ); } int m = queryM( cres ); //if( abs( m )==13 ){ // cout << endl; // debug_print_res_struct( pf, 0 ); //} //cout << "res on " << cres << std::endl; return Make( p1, p2, m, false ); } LFSCProof* LFSCBoolRes::MakeC( LFSCProof* p, const Expr& res ){ if( res.isOr() ){ ostringstream os1, os2; int m = queryM( res[0] ); os1 << "(c" << (m>0 ? "R" : "Q" ); os1 << " _ _ _ _ @a" << abs( m ); os2 << ")"; return LFSCProofGeneric::Make( os1.str(), MakeC( p, res[1] ), os2.str() ); }else{ ostringstream os1, os2; int m = queryM( res ); os1 << "(c" << (m>0 ? "R" : "Q" ); os1 << "0 _ _ _ @a" << abs( m ); os2 << ")"; return LFSCProofGeneric::Make( os1.str(), p, os2.str() ); } } // LFSCClausify ... void LFSCClausify::print_pf( std::ostream& s, int ind ){ s << "(clausify_form" << (d_var<0 ? "_not" : "") << " _ _ @a" << abs( d_var ) << " "; d_pf->print( s ); s << ")"; } //p should prove e, return a proof that is the clausal form for e LFSCProof* LFSCClausify::Make( const Expr& e, LFSCProof* p, bool cascadeOr ) { if( cascadeOr ){ std::vector< Expr > exprs; Expr end; if( e.arity()>0 ) end = cascade_expr( e[e.arity()-1] ); return Make_i( cascade_expr( e ), p, exprs, end ); }else{ return Make( queryM( e ), p ); } } LFSCProof* LFSCClausify::Make_i( const Expr& e, LFSCProof* p, std::vector< Expr >& exprs, const Expr& end ) { if( e.getKind()==OR && e!=end ) { exprs.push_back( e[0] ); return LFSCAssume::Make( queryM( e[0] ), Make_i( e[1], p, exprs, end ), false ); } else { for( int a=0; a<(int)exprs.size(); a++ ){ ostringstream os1, os2; os1 << "(or_elim_1 _ _ "; int m = queryM( exprs[a] ); //introduce double negation to satisfy or_elim requirement os1 << ( m<0 ? "(not_not_intro _ " : "" ); os1 << "@v" << abs( m ); os1 << ( m<0 ? ")" : "" ); os1 << " "; os2 << ")"; p = LFSCProofGeneric::Make( os1.str(), p, os2.str() ); } return Make( queryM( e ), p ); } } // LFSCAssume ... void LFSCAssume::print_pf( std::ostream& s, int ind ){ int m = d_assm ? d_var : -d_var; if( d_type==3 ) s << "(as" << (m>0 ? "t" : "f") << " _ _ _ @a" << abs( m ); else s << "(th_as" << (m>0 ? "t" : "f") << " _ "; s << " (\\ @v" << abs( m ) << " "; d_pf->print( s ); s << "))"; } void LFSCAssume::print_struct( std::ostream& s, int ind ){ s << "(as " << ( d_assm ? d_var : -d_var ); d_pf->print_structure( s, ind+1 ); s << ")"; } cvc3-2.4.1/src/search/LFSCUtilProof.h0000664000175400017540000001212511363704204017057 0ustar mdetersmdeters#ifndef LFSC_UTIL_PROOF_H_ #define LFSC_UTIL_PROOF_H_ #include "LFSCProof.h" class LFSCProofExpr : public LFSCProof { bool isHole; Expr d_e; LFSCProofExpr( const Expr& e, bool isH = false ); void initialize(); virtual ~LFSCProofExpr(){} long int get_length() { return 10; } public: virtual LFSCProofExpr* AsLFSCProofExpr(){ return this; } void print_pf( std::ostream& s, int ind ); static LFSCProof* Make( const Expr& e, bool isH = false ) { return new LFSCProofExpr( e, isH ); } LFSCProof* clone() { return new LFSCProofExpr( d_e, isHole ); } void fillHoles() { isHole = false; } }; class LFSCPfVar : public LFSCProof { private: static std::map< int, RefPtr< LFSCProof > > vMap; string name; LFSCPfVar( string nm ) : LFSCProof(), name( nm ){} virtual ~LFSCPfVar(){} long int get_length() { return name.length(); } public: virtual LFSCPfVar* AsLFSCPfVar(){ return this; } void print_pf( std::ostream& s, int ind = 0 ){ s << name; } void print_struct( std::ostream& s, int ind = 0 ){ s << name; } static LFSCProof* Make( const char* c, int v ); static LFSCProof* MakeV( int v ); LFSCProof* clone() { return new LFSCPfVar( name ); } }; class LFSCPfLambda : public LFSCProof { private: RefPtr< LFSCPfVar > pfV; RefPtr< LFSCProof > body; //just a placeholder. This is what the lambda abstracts. RefPtr< LFSCProof > abstVal; //constructor LFSCPfLambda( LFSCPfVar* v, LFSCProof* bd, LFSCProof* aVal = NULL ) : LFSCProof(), pfV( v ), body( bd ), abstVal( aVal ){} virtual ~LFSCPfLambda(){} long int get_length() { return 5 + pfV->get_string_length() + body->get_string_length(); } public: virtual LFSCPfLambda* AsLFSCPfLambda(){ return this; } void print_pf( std::ostream& s, int ind = 0 ); static LFSCProof* Make( LFSCPfVar* v, LFSCProof* bd, LFSCProof* aVal = NULL ){ return new LFSCPfLambda( v, bd, aVal ); } LFSCProof* clone() { return new LFSCPfLambda( pfV.get(), body.get(), abstVal.get() ); } int getNumChildren() { return 2; } LFSCProof* getChild( int n ) { return (n==0) ? (LFSCProof*)pfV.get() : body.get(); } }; // class LFSCProofGeneric : public LFSCProof{ private: vector< RefPtr< LFSCProof > > d_pf; vector< string > d_str; bool debug_str; //Proof in the form "S1.print(P1).S2.print(P2).....print(Pn).S{n+1}" LFSCProofGeneric( vector< RefPtr< LFSCProof > >& d_pfs, vector< string >& d_strs, bool db_str = false ) : LFSCProof(){ for( int a=0; a<(int)d_pfs.size(); a++ ) d_pf.push_back( d_pfs[a].get() ); for( int a=0; a<(int)d_strs.size(); a++ ) d_str.push_back( d_strs[a] ); debug_str = db_str; } virtual ~LFSCProofGeneric(){} long int get_length(); public: virtual LFSCProofGeneric* AsLFSCProofGeneric(){ return this; } void print_pf( std::ostream& s, int ind = 0 ); //Proof in the form "S1.print(P1).S2.print(P2).....print(Pn).S{n+1}" static LFSCProof* Make( vector< RefPtr< LFSCProof > >& d_pfs, std::vector< string >& d_strs, bool db_str = false ){ return new LFSCProofGeneric( d_pfs, d_strs, db_str ); } //proof printed in the form "S1.print(P1).S2" static LFSCProof* Make( string str_pre, LFSCProof* sub_pf, string str_post, bool db_str = false ); //proof printed in the form "S1.print(P1).print(P2).S2" static LFSCProof* Make( string str_pre, LFSCProof* sub_pf1, LFSCProof* sub_pf2, string str_post, bool db_str = false ); static LFSCProof* MakeStr( const char* c, bool db_str = false ); static LFSCProof* MakeUnk(){ return MakeStr( "unk" ); } LFSCProof* clone(){ return new LFSCProofGeneric( d_pf, d_str, debug_str ); } int getNumChildren() { return (int)d_pf.size(); } LFSCProof* getChild( int n ) { return d_pf[n].get(); } }; class LFSCPfLet : public LFSCProof{ private: RefPtr< LFSCProof > d_letPf; RefPtr< LFSCPfVar > d_pv; RefPtr< LFSCProof > d_body; //this should be equal to d_letPf, although it could be something else based on fv RefPtr< LFSCProof > d_letPfRpl; //this by default is d_pv, although it could be something else based on fv RefPtr< LFSCProof > d_pvRpl; bool d_isTh; LFSCPfLet( LFSCProof* letPf, LFSCPfVar* pv, LFSCProof* body, bool isTh, LFSCProof* letPfRpl, LFSCProof* pvRpl ) : LFSCProof(), d_letPf( letPf ),d_pv( pv ),d_body( body ),d_letPfRpl( letPfRpl ),d_pvRpl( pvRpl ),d_isTh( isTh ){} LFSCPfLet( LFSCProof* letPf, LFSCPfVar* pv, LFSCProof* body, bool isTh, std::vector< int >& fv ); virtual ~LFSCPfLet(){} long int get_length() { return 10 + d_letPf->get_string_length() + d_pv->get_string_length() + d_body->get_string_length(); } public: virtual LFSCPfLet* AsLFSCPfLet(){ return this; } void print_pf( std::ostream& s, int ind = 0 ); void print_struct( std::ostream& s, int ind = 0 ); static LFSCProof* Make( LFSCProof* letPf, LFSCPfVar* pv, LFSCProof* body, bool isTh, std::vector< int >& fv ){ return new LFSCPfLet( letPf, pv, body, isTh, fv ); } LFSCProof* clone() { return new LFSCPfLet( d_letPf.get(), d_pv.get(), d_body.get(), d_isTh, d_letPfRpl.get(), d_pvRpl.get() ); } //should not be part of the children structure. }; #endif cvc3-2.4.1/src/search/Util.h0000664000175400017540000000171211363704204015401 0ustar mdetersmdeters#ifndef UTIL_H_ #define UTIL_H_ #include "Object.h" // helper utility functions void ajr_debug_print( const Expr& pf ); string kind_to_str(int knd ); bool is_eq_kind( int knd ); bool is_smt_kind( int knd ); //equation types ( a ~ b ) that are normalized to (b-a) ~' 0 bool is_opposite( int knd ); bool is_comparison( int knd ); int get_not( int knd ); //order in LFSC signature for rules when order does not matter (such as lra_add) int get_knd_order( int knd ); int get_normalized( int knd, bool isnot = false ); //should only be called on normalized ops int get_knd_result( int knd1, int knd2 ); //print helpers void print_mpq(int num, int den, std::ostream& s ); void print_rational( const Rational& r, std::ostream& s ); void print_rational_divide( const Rational& n, const Rational& d, std::ostream& s ); bool getRat( const Expr& e, Rational& r ); bool isFlat( const Expr& e ); void make_flatten_expr( const Expr& e, Expr& pe, int knd ); #endif cvc3-2.4.1/src/search/TReturn.h0000664000175400017540000000411011363704204016062 0ustar mdetersmdeters#ifndef TRETURN_H_ #define TRETURN_H_ #include "LFSCProof.h" ////////////////////////////////////////// // TReturn = (p_lfsc, L, c) // implements transformation ///////////////////////////////////////// class TReturn : public LFSCObj { private: RefPtr< LFSCProof > d_lfsc_pf; // literals (we only store the indices) i corresponds to v_i and -i to not v_i std::vector d_L; // literals we use std::vector d_L_used; // constant Rational d_c; bool d_hasRt; // constructor //flag for whether d_lfsc_pf is proving //0: psi, //1: Y(psi) (arithmetic collapse) //2: Y2( psi ) (double implications are single implications) //3: clause( Y2( psi ) ) int d_provesY; bool lcalced; public: TReturn(LFSCProof* lfsc_pf, std::vector& L, std::vector& Lused, Rational r, bool hasR, int pvY); Rational mult_rational( TReturn* lhs ); void getL( std::vector< int >& lget, std::vector< int >& lgetu ); bool hasRational() { return d_hasRt; } Rational getRational() { return d_c; } LFSCProof* getLFSCProof(){ return d_lfsc_pf.get(); } int getProvesY() { return d_provesY; } bool hasFv() { return !d_L_used.empty(); } #ifdef OPTIMIZE void calcL( std::vector< int >& lget, std::vector< int >& lgetu ); #endif // make it so that the two TReturns agree on what they are proving // t1 corresponds to the conversion of pf1, proving psi, Y( ps1 ), or Y2( ps1 ) // t2 corresponds to the conversion of pf2, proving psi, Y( ps1 ), or Y2( ps1 ) // on return, t1->d_proveY should equal t2->d_proveY // this will return the mode they normalized on, -1 means fail static int normalize_tret( const Expr& pf1, TReturn*& t1, const Expr& pf2, TReturn*& t2, bool rev_pol = false ); //normalize TReturn to prove a certain type // this will return the mode it normalized on, -1 means fail static int normalize_tr( const Expr& pf1, TReturn*& t1, int y, bool rev_pol = false, bool printErr = true ); //normalize from polynomial formula to term formula atom static void normalize_to_tf( const Expr& pf, TReturn*& t1, int y ); }; #endif cvc3-2.4.1/src/search/LFSCObject.h0000664000175400017540000001303211363745667016362 0ustar mdetersmdeters#ifndef LFSC_OBJ_H_ #define LFSC_OBJ_H_ #include "Object.h" #include "Util.h" class LFSCPrinter; class LFSCObj : public Obj { public: LFSCObj(){} static void initialize( const Expr& pf_expr, int lfscm ); protected: //the printer object static LFSCPrinter* printer; //counters static int formula_i; static int trusted_i; static int term_i; static int tnorm_i; //options for the conversion static int lfsc_mode; static bool debug_conv; static bool debug_var; static bool cvc3_mimic; static bool cvc3_mimic_input; //null rational static Rational nullRat; //get number of nodes static ExprMap< int > nnode_map; static int getNumNodes( const Expr& pf, bool recount = false ); //cascade expr static ExprMap< Expr > cas_map; static Expr cascade_expr( const Expr& e ); //skolem variables static ExprMap< Expr > skolem_vars; //with the expr they point to static ExprMap< bool > temp_visited; static void define_skolem_vars( const Expr& e ); //is variable static bool isVar( const Expr& e ); //collect free variables static void collect_vars( const Expr& e, bool readPred = true ); protected: // this is actually the M map where M = {v_i -> non-negated formula} static ExprMap d_formulas; //trusted formulas static ExprMap d_trusted; // this is the M_t map where M_t = { v_i -> term } static ExprMap d_pn; //this is the equations that will use the d_pn map. They are mapped to the index of the pn_i they will use static ExprMap d_pn_form; //similar to m, but with terms static ExprMap d_terms; //input variables static ExprMap input_vars; //input predicates static ExprMap input_preds; //pnt that are needed to print static std::map< int, bool > pntNeeded; //atoms that must be printed static ExprMap d_formulas_printed; //original proof expression static Expr d_pf_expr; //assumptions static ExprMap d_assump_map; protected: //eliminate not not static Expr queryElimNotNot(const Expr& expr); //get base will get you the base formula, i.e. ~( a = b ) returns ( a = b ) //get base = false will get you the equivalent atomic, i.e. ~( a = b ) returns ( b != a ) static Expr queryAtomic(const Expr& expr, bool getBase = false ); //returns a integer v, +v means M( v ) = expr, -v means M( v ) = expr', where expr := NOT expr' //add is whether or not to add it to M, or just query static int queryM(const Expr& expr, bool add = true, bool trusted = false); //returns an integer v, where M_t( v ) = expr static int queryMt(const Expr& expr); //similar to m, but this time it is with terms static int queryT( const Expr& e ); //get Y static bool getY( const Expr& e, Expr& pe, bool doIff = true, bool doLogic = true ); //is this expr a formula static bool isFormula( const Expr& e ); //can this expr be polynomial normalized static bool can_pnorm( const Expr& e ); //what is proven static bool what_is_proven( const Expr& pf, Expr& pe ); protected: // differentiate between variables and rules static ExprMap d_rules; // boolean resultion rules static Expr d_bool_res_str; static Expr d_assump_str; // arithmetic rules static Expr d_iff_mp_str; static Expr d_impl_mp_str; static Expr d_iff_trans_str; static Expr d_real_shadow_str; static Expr d_cycle_conflict_str; static Expr d_real_shadow_eq_str; static Expr d_basic_subst_op_str; static Expr d_mult_ineqn_str; static Expr d_right_minus_left_str; static Expr d_eq_trans_str; static Expr d_eq_symm_str; static Expr d_canon_plus_str; static Expr d_refl_str; static Expr d_cnf_convert_str; static Expr d_learned_clause_str; static Expr d_minus_to_plus_str; static Expr d_plus_predicate_str; static Expr d_negated_inequality_str; static Expr d_flip_inequality_str; static Expr d_optimized_subst_op_str; static Expr d_iff_true_elim_str; static Expr d_basic_subst_op1_str; static Expr d_basic_subst_op0_str; static Expr d_canon_mult_str; static Expr d_canon_invert_divide_str; static Expr d_iff_true_str; static Expr d_mult_eqn_str; static Expr d_rewrite_eq_symm_str; static Expr d_implyWeakerInequality_str; static Expr d_implyWeakerInequalityDiffLogic_str; static Expr d_imp_mp_str; static Expr d_rewrite_implies_str; static Expr d_rewrite_or_str; static Expr d_rewrite_and_str; static Expr d_rewrite_iff_symm_str; static Expr d_iff_not_false_str; static Expr d_iff_false_str; static Expr d_iff_false_elim_str; static Expr d_not_to_iff_str; static Expr d_not_not_elim_str; static Expr d_const_predicate_str; static Expr d_rewrite_not_not_str; static Expr d_rewrite_not_true_str; static Expr d_rewrite_not_false_str; static Expr d_if_lift_rule_str; static Expr d_CNFITE_str; static Expr d_var_intro_str; static Expr d_int_const_eq_str; static Expr d_rewrite_eq_refl_str; static Expr d_iff_symm_str; static Expr d_rewrite_iff_str; static Expr d_implyNegatedInequality_str; static Expr d_uminus_to_mult_str; static Expr d_lessThan_To_LE_rhs_rwr_str; static Expr d_rewrite_ite_same_str; static Expr d_andE_str; static Expr d_implyEqualities_str; static Expr d_addInequalities_str; //CNF rules static Expr d_CNF_str; static Expr d_cnf_add_unit_str; static Expr d_minisat_proof_str; //reasons for CNF static Expr d_or_final_s; static Expr d_and_final_s; static Expr d_ite_s; static Expr d_iff_s; static Expr d_imp_s; static Expr d_or_mid_s; static Expr d_and_mid_s; }; #endif cvc3-2.4.1/src/search/search_fast.cpp0000664000175400017540000021012011153264564017303 0ustar mdetersmdeters/////////////////////////////////////////////////////////////////////////////// /*! * \file search_fast.cpp * * Author: Mark Zavislak * Undergraduate * Stanford University * * Created: Mon Jul 21 23:52:39 UTC 2003 * *
* * License to use, copy, modify, sell and/or distribute this software * and its documentation for any purpose is hereby granted without * royalty, subject to the terms and conditions defined in the \ref * LICENSE file provided with this distribution. * *
*/ /////////////////////////////////////////////////////////////////////////////// #include "search_fast.h" #include "typecheck_exception.h" #include "search_rules.h" #include "command_line_flags.h" #include "cdmap.h" #include "decision_engine_dfs.h" //#include "decision_engine_caching.h" //#include "decision_engine_mbtf.h" #include "expr_transform.h" #include "assumptions.h" using namespace CVC3; using namespace std; //! When set to true, match Chaff behavior as close as possible #define followChaff false void SearchEngineFast::ConflictClauseManager::setRestorePoint() { TRACE("conflict clauses", "ConflictClauseManager::setRestorePoint(): scope=", d_se->scopeLevel(), ""); d_se->d_conflictClauseStack.push_back(new deque()); d_se->d_conflictClauses = d_se->d_conflictClauseStack.back(); d_restorePoints.push_back(d_se->scopeLevel()); } void SearchEngineFast::ConflictClauseManager::notify() { if (d_restorePoints.size() > 0) { int scope = d_restorePoints.back(); if (scope > d_se->scopeLevel()) { TRACE("conflict clauses", "ConflictClauseManager::notify(): restore to scope ", scope, ""); d_restorePoints.pop_back(); while (d_se->d_conflictClauses->size() > 0) d_se->d_conflictClauses->pop_back(); delete d_se->d_conflictClauseStack.back(); d_se->d_conflictClauseStack.pop_back(); d_se->d_conflictClauses = d_se->d_conflictClauseStack.back(); } } } //! Constructor SearchEngineFast::SearchEngineFast(TheoryCore* core) : SearchImplBase(core), d_name("fast"), d_unitPropCount(core->getStatistics().counter("unit propagations")), d_circuitPropCount(core->getStatistics().counter("circuit propagations")), d_conflictCount(core->getStatistics().counter("conflicts")), d_conflictClauseCount(core->getStatistics().counter("conflict clauses")), d_clauses(core->getCM()->getCurrentContext()), d_unreportedLits(core->getCM()->getCurrentContext()), d_unreportedLitsHandled(core->getCM()->getCurrentContext()), d_nonLiterals(core->getCM()->getCurrentContext()), d_nonLiteralsSaved(core->getCM()->getCurrentContext()), d_simplifiedThm(core->getCM()->getCurrentContext()), d_nonlitQueryStart(core->getCM()->getCurrentContext()), d_nonlitQueryEnd(core->getCM()->getCurrentContext()), d_clausesQueryStart(core->getCM()->getCurrentContext()), d_clausesQueryEnd(core->getCM()->getCurrentContext()), d_conflictClauseManager(core->getCM()->getCurrentContext(), this), d_literalSet(core->getCM()->getCurrentContext()), d_useEnqueueFact(false), d_inCheckSAT(false), d_litsAlive(core->getCM()->getCurrentContext()), d_litsMaxScorePos(0), d_splitterCount(0), d_litSortCount(0), d_berkminFlag(false) { // if (core->getFlags()["de"].getString() == "caching") // d_decisionEngine = new DecisionEngineCaching(core, this); // else if (core->getFlags()["de"].getString() == "mbtf") // d_decisionEngine = new DecisionEngineMBTF(core, this); // else d_decisionEngine = new DecisionEngineDFS(core, this); IF_DEBUG ( d_nonLiterals.setName("CDList[SearchEngineDefault.d_nonLiterals]"); d_clauses.setName("CDList[SearchEngineDefault.d_clauses]"); ) d_conflictClauseStack.push_back(new deque()); d_conflictClauses = d_conflictClauseStack.back(); } //! Destructor /*! We own the proof rules (d_rules) and the variable manager (d_vm); delete them. */ SearchEngineFast::~SearchEngineFast() { for (unsigned i=0; i < d_circuits.size(); i++) delete d_circuits[i]; delete d_decisionEngine; for(size_t i=0, iend=d_conflictClauseStack.size(); i >& SearchEngineFast::wp(const Literal& literal) { // return d_wp[literal.getExpr()]; return literal.wp(); } #ifdef _CVC3_DEBUG_MODE static void checkAssump(const Theorem& t, const Theorem& orig, const CDMap& assumptions) { const Assumptions& a(t.getAssumptionsRef()); const Assumptions::iterator iend = a.end(); if(!(!t.isAssump() || assumptions.count(t.getExpr()) > 0)) orig.printDebug(); DebugAssert((!t.isAssump() || assumptions.count(t.getExpr()) > 0), "checkAssump: found stray theorem:\n " + t.toString()); if(t.isAssump()) return; for (Assumptions::iterator i = a.begin(); i != iend; ++i) { if (!i->isFlagged()) { i->setFlag(); // comparing only TheoremValue pointers in .find() checkAssump(*i, orig, assumptions); } } } /*! @brief Check that assumptions in the result of checkValid() are a subset of assertions */ /*! Only defined in the debug build. * \ingroup SE_Default */ static void checkAssumpDebug(const Theorem& res, const CDMap& assumptions) { // FIXME: (jimz) will need to traverse graph if(!res.withAssumptions()) return; res.clearAllFlags(); checkAssump(res, res, assumptions); } #endif //////////////////////////// // New Search Engine Code // //////////////////////////// QueryResult SearchEngineFast::checkSAT() { d_inCheckSAT=true; QueryResult result = UNSATISFIABLE; if (!bcp()) { // run an initial bcp DebugAssert(d_factQueue.empty(), "checkSAT()"); if (!fixConflict()) goto checkSATfinalize; } while (!d_core->outOfResources()) { if (split()) { // if we were able to split successfully // Run BCP while (!bcp()) { // while bcp finds conflicts DebugAssert(d_factQueue.empty(), "checkSAT()"); d_decisionEngine->goalSatisfied(); // Try to fix those conflicts by rolling back contexts and // adding new conflict clauses to help in the future. if (!fixConflict()) goto checkSATfinalize; } } // Now we couldn't find a splitter. This may have been caused by // other reasons, so we allow them to be processed here. else { result = SATISFIABLE; break; } } checkSATfinalize: d_inCheckSAT = false; if (d_core->outOfResources()) result = ABORT; else if (result == SATISFIABLE && d_core->incomplete()) result = UNKNOWN; return result; } /* There are different heurisitics for splitters available. We would * normally try to use the new generic decision class, but initially * we want this just to work, and so we use a custom decision class * that knows about this particular search engine. We can realize * this same behavior using the existing mechanism by having a * decision subclass dynamic_cast the received SearchEngine pointer as * a SearchEngineFast and work from there. However, as of this time I * do not plan on supporting the nextClause() and nextNonClause() * functionality, as they don't make much sense in this kind of modern * solver. It may make more sense to have the solver and it's literal * splitting heuristic tightly connected, but leaving the nonLiteral * splitting heurisitic separate, since it is generally independent of * the search mechanism. * * By this point we've already guaranteed that we need to split: no * unit clauses, and no conflicts. The procedure is as follows. Ask * the decision engine for an expression to split on. The decision * engine dutifully returns an expression. We craft an assumption out * of this and assert it to the core (after making sure d_assumptions * has a copy). * * If no splitters are available, we still have to let the decision * procedures have a final chance at showing the context is * inconsistent by calling checkSATcore(). If we get a false out of * this, we have to continue processing, so the context is left * unchanged, no splitter is chosen, and we return true to let the * bcp+conflict processing have another chance. If we get true, then * the problem is SAT and we are done, so we return false. * * Otherwise, we obtain the splitter, then ship it back off to the * decision engine for processing. */ bool SearchEngineFast::split() { TRACE_MSG("search basic", "Choosing splitter"); Expr splitter = findSplitter(); if (splitter.isNull()) { TRACE_MSG("search basic", "No splitter"); bool res(d_core->inconsistent() || !d_core->checkSATCore()); if(!res) { d_splitterCount = 0; // Force resorting splitters next time res = !bcp(); } return res; } Literal l(newLiteral(splitter)); Theorem simp; if(l.getValue() != 0) { // The literal is valid at a lower scope than it has been derived, // and therefore, it was lost after a scope pop. Reassert it here. simp = l.deriveTheorem(); d_literals.push_back((l.getValue() == 1)? l : !l); d_core->addFact(simp); return true; } else { simp = d_core->simplify(splitter); Expr e = simp.getRHS(); if(e.isBoolConst()) { IF_DEBUG(debugger.counter("splitter simplified to TRUE or FALSE")++;) if(e.isTrue()) simp = d_commonRules->iffTrueElim(simp); else { if(splitter.isNot()) simp = d_commonRules->notNotElim(d_commonRules->iffFalseElim(simp)); else simp = d_commonRules->iffFalseElim(simp); } TRACE("search full", "Simplified candidate: ", splitter.toString(), ""); TRACE("search full", " to: ", simp.getExpr().toString(), ""); // Send this literal to DPs and enqueue it for BCP d_core->addFact(simp); addLiteralFact(simp); DebugAssert(l.getValue()!=0, "SearchFast::split(): l = "+l.toString()); return true; } } TRACE("search terse", "Asserting splitter: #" +int2string(d_core->getStatistics().counter("splitters"))+": ", splitter, ""); d_decisionEngine->pushDecision(splitter); return true; } //! Total order on literals for the initial sort /*! Used for debugging, to match Chaff's behavior as close as possible and track any discrepancies or inefficiencies. */ // static bool compareInitial(const Literal& l1, const Literal& l2) { // Expr lit1 = l1.getVar().getExpr(); // Expr lit2 = l2.getVar().getExpr(); // if(lit1.hasOp() && lit2.hasOp()) { // int i = atoi(&(lit1.getOp().getName().c_str()[2])); // int j = atoi(&(lit2.getOp().getName().c_str()[2])); // return (i < j); // } // else // return (l1.score() > l2.score()); // } //! Ordering on literals, used to sort them by score static inline bool compareLits(const Literal& l1, const Literal& l2) { return (l1.score() > l2.score()); } IF_DEBUG(static string lits2str(const vector& lits) { ostringstream ss; ss << "\n["; for(vector::const_iterator i=lits.begin(), iend=lits.end(); i!=iend; ++i) ss << *i << "\n "; ss << "\n]"; return ss.str(); }) /*! * Recompute the scores for all known literals. This is a relatively * expensive procedure, so it should not be called too often. * Currently, it is called once per 100 splitters. */ void SearchEngineFast::updateLitScores(bool firstTime) { TRACE("search literals", "updateLitScores(size=", d_litsByScores.size(), ") {"); unsigned count, score; if (firstTime && followChaff) { ::stable_sort(d_litsByScores.begin(), d_litsByScores.end(), compareLits); } for(size_t i=0; i< d_litsByScores.size(); ++i) { // Reading by value, since we'll be modifying the attributes. Literal lit = d_litsByScores[i]; // First, clean up the unused literals while(lit.count()==0 && i+1 < d_litsByScores.size()) { TRACE("search literals", "Removing lit["+int2string(i)+"] = ", lit, " from d_litsByScores"); // Remove this literal from the list lit.added()=false; lit = d_litsByScores.back(); d_litsByScores[i] = lit; d_litsByScores.pop_back(); } // Take care of the last literal in the vector if(lit.count()==0 && i+1 == d_litsByScores.size()) { TRACE("search literals", "Removing last lit["+int2string(i)+"] = ", lit, " from d_litsByScores"); lit.added()=false; d_litsByScores.pop_back(); break; // Break out of the loop -- no more literals to process } TRACE("search literals", "Updating lit["+int2string(i)+"] = ", lit, " {"); DebugAssert(lit == d_litsByScores[i], "lit = "+lit.toString()); DebugAssert(lit.added(), "lit = "+lit.toString()); DebugAssert(lit.count()>0, "lit = "+lit.toString()); count = lit.count(); unsigned& countPrev = lit.countPrev(); int& scoreRef = lit.score(); score = scoreRef/2 + count - countPrev; scoreRef = score; countPrev = count; TRACE("search literals", "Updated lit["+int2string(i)+"] = ", lit, " }"); // Literal neglit(!lit); // count = neglit.count(); // unsigned& negcountPrev = neglit.countPrev(); // unsigned& negscoreRef = neglit.score(); // negscore = negscoreRef/2 + count - negcountPrev; // negscoreRef = negscore; // negcountPrev = count; // if(negscore > score) d_litsByScores[i] = neglit; } ::stable_sort(d_litsByScores.begin(), d_litsByScores.end(), compareLits); d_litsMaxScorePos = 0; d_litSortCount=d_litsByScores.size(); TRACE("search splitters","updateLitScores => ", lits2str(d_litsByScores),""); TRACE("search literals", "updateLitScores(size=", d_litsByScores.size(), ") => }"); } void SearchEngineFast::updateLitCounts(const Clause& c) { TRACE("search literals", "updateLitCounts(", CompactClause(c), ") {"); for(unsigned i=0; i ", lits2str(d_litsByScores),""); TRACE_MSG("search literals", "updateLitCounts => }"); } Expr SearchEngineFast::findSplitter() { TRACE_MSG("splitters", "SearchEngineFast::findSplitter() {"); Expr splitter; // Null by default unsigned i; // if we have a conflict clause, pick the one inside with the // best ac(z) score (from the most recent conflict clause) // if (d_berkminFlag && !d_conflictClauses.empty()) if (d_berkminFlag && !d_conflictClauses->empty()) { unsigned sCount = 0; std::deque::reverse_iterator foundUnsat = d_conflictClauses->rend(); for (std::deque::reverse_iterator i = d_conflictClauses->rbegin(); i != d_conflictClauses->rend(); ++i) { ++sCount; if (!((Clause)*i).sat(true)) { foundUnsat = i; break; } } if (foundUnsat != d_conflictClauses->rend()) { Clause &topClause = *foundUnsat; int numLits = topClause.size(); int bestScore = 0; int bestLit = -1; unsigned numChoices = 0; for (int i = 0; i < numLits; ++i) { const Literal& lit = topClause[i]; if (lit.getValue() != 0) continue; if (bestLit == -1) bestLit = i; ++numChoices; int s = lit.score(); if (s > bestScore) { bestLit = i; bestScore = s; } } if (bestLit != -1) { splitter = topClause[bestLit].getExpr(); IF_DEBUG(debugger.counter("BerkMin heuristic")++;) TRACE("splitters", "SearchEngineFast::findSplitter()[berkmin] => ", splitter, " }"); return splitter; } } } /* // Search for DP-specific splitters for(CDMapOrdered::iterator i=d_dpSplitters.begin(), iend=d_dpSplitters.end(); i!=iend; ++i) { Expr e((*i).first.expr); if(e.isBoolConst() || d_core->find(e).getRHS().isBoolConst()) continue; return e; } */ for (int i = d_nonLiterals.size()-1; i >= 0; --i) { const Expr& e = d_nonLiterals[i].get().getExpr(); if (e.isTrue()) continue; // if (d_nonLiteralSimplified[thm.getExpr()]) continue; DebugAssert(!e.isBoolConst(), "Expected non-bool const"); DebugAssert(d_core->simplifyExpr(e) == e, "Expected non-literal to be simplified:\n e = " +e.toString()+"\n simplify(e) = " +d_core->simplifyExpr(e).toString()); splitter = d_decisionEngine->findSplitter(e); //DebugAssert(!splitter.isNull(), // "findSplitter: can't find splitter in non-literal: " // + e.toString()); if (splitter.isNull()) continue; IF_DEBUG(debugger.counter("splitters from non-literals")++;) TRACE("splitters", "SearchEngineFast::findSplitter()[non-lit] => ", splitter, " }"); return splitter; } // Update the scores: we are about to choose a splitter based on them if (d_splitterCount <= 0) { updateLitScores(false); // d_splitterCount = d_litsByScores.size(); // if(d_splitterCount > 100) d_splitterCount = 0x10; } else d_splitterCount--; // pick splitter based on score for (i=d_litsMaxScorePos; isimplifyExpr(splitter).isBoolConst()) continue; if(splitterLit.getValue() != 0) continue; splitter = splitterLit.getExpr(); // Skip auxiliary CNF vars if(!isGoodSplitter(splitter)) continue; d_litsMaxScorePos = i+1; IF_DEBUG(debugger.counter("splitters from literals")++;) TRACE("splitters", "d_litsMaxScorePos: ", d_litsMaxScorePos, ""); TRACE("splitters", "SearchEngineFast::findSplitter()[lit] => ", splitter, " }"); return splitter; } TRACE_MSG("splitters", "SearchEngineFast::findSplitter()[not found] => Null }"); return Expr(); } void SearchEngineFast::recordFact(const Theorem& thm) { Literal l(newLiteral(thm.getExpr())); if(l.getValue() == 0) { l.setValue(thm, thm.getScope()); IF_DEBUG(debugger.counter("recordFact adds unreported lit")++;) d_unreportedLits.insert(l.getExpr(),thm,thm.getScope()); } else if (l.getValue() == 1 && l.getScope() > thm.getScope()) { // Cannot do this, it will trigger DebugAssert // l.setValue(thm,thm.getScope()); IF_DEBUG(debugger.counter("recordFact adds unreported lit")++;) d_unreportedLits.insert(l.getExpr(),thm,thm.getScope()); } else if(l.getValue() < 0) { // Contradiction, bcp will die anyway if(l.isNegative()) setInconsistent(d_commonRules->contradictionRule(l.deriveTheorem(), thm)); else setInconsistent(d_commonRules->contradictionRule(thm, l.deriveTheorem())); } //else if (thm.getScope() < scopeLevel()) // d_unreportedLits.insert(l.getExpr(),l,thm.getScope()); } #ifdef _CVC3_DEBUG_MODE void SearchEngineFast::fullCheck() { for (unsigned i = 0; i < d_clauses.size(); ++i) { if (!((Clause)d_clauses[i]).sat()) { bool sat = false; const Clause &theClause = d_clauses[i]; unsigned numLits = theClause.size(); unsigned numChoices = 0; for (unsigned j = 0; !sat && j < numLits; ++j) { if (theClause[j].getValue() == 0) ++numChoices; else if (theClause[j].getValue() == 1) sat = true; } if (sat) continue; if (numChoices <= 1 || !theClause.wpCheck()) { CVC3::debugger.getOS() << CompactClause(theClause) << endl; CVC3::debugger.getOS() << theClause.toString() << endl; } DebugAssert(numChoices > 1, "BCP postcondition violated: unsat or unit clause(s)"); DebugAssert(theClause.wpCheck(), "Watchpointers broken"); } } if (!d_conflictClauses->empty()) { for (std::deque::reverse_iterator i = d_conflictClauses->rbegin(); i != d_conflictClauses->rend(); ++i) { if (!((Clause)*i).sat()) { bool sat = false; Clause &theClause = *i; unsigned numLits = theClause.size(); unsigned numChoices = 0; for (unsigned j = 0; !sat && j < numLits; ++j) { if (theClause[j].getValue() == 0) ++numChoices; else if (theClause[j].getValue() == 1) sat = true; } if (sat) continue; if (numChoices <= 1 || !theClause.wpCheck()) { CVC3::debugger.getOS() << CompactClause(theClause) << endl; CVC3::debugger.getOS() << theClause.toString() << endl; } DebugAssert(numChoices > 1, "BCP postcondition violated: unsat or unit conflict clause(s)"); DebugAssert(theClause.wpCheck(), "Watchpointers broken"); } } } } #endif void SearchEngineFast::clearLiterals() { TRACE_MSG("search literals", "clearLiterals()"); d_literals.clear(); } bool SearchEngineFast::bcp() { TRACE("search bcp", "bcp@"+int2string(scopeLevel())+"(#lits=", d_literals.size(), ") {"); IF_DEBUG(TRACE_MSG("search bcp", "literals=[\n"); for(size_t i=0,iend=d_literals.size(); i::iterator i = d_unreportedLits.begin(), iend = d_unreportedLits.end(); for (; i != iend; ++i) { if (d_unreportedLitsHandled[(*i).first]) continue; Theorem thm((*i).second); Literal l(newLiteral(thm.getExpr())); DebugAssert(l.getValue() != -1, "Bad unreported literal: "+l.toString()); if(l.getValue() == 0) l.setValue(thm, scopeLevel()); IF_DEBUG(debugger.counter("re-assert unreported lits")++;) DebugAssert(l.getExpr().isAbsLiteral(), "bcp(): pushing non-literal to d_literals:\n " +l.getExpr().toString()); // The literal may be set to 1, but not on the list; push it here // explicitly d_literals.push_back(l); //recordFact((*i).second.getTheorem()); enqueueFact(thm); d_unreportedLitsHandled[(*i).first] = true; } */ while (newInfo) { IF_DEBUG(debugger.counter("BCP: while(newInfo)")++;) TRACE_MSG("search bcp", "while(newInfo) {"); newInfo = false; while(!d_core->inconsistent() && d_literals.size() > 0) { for(unsigned i=0; !d_core->inconsistent() && i >& wps = wp(l); TRACE("search props", "Appears in ", wps.size(), " clauses."); for(unsigned j=0; j false }}"); return false; } } } vector& cps = d_circuitsByExpr[l.getExpr()]; for (vector::iterator it = cps.begin(), end = cps.end(); it < end; it++) { if (!(*it)->propagate(this)) { clearFacts(); DebugAssert(d_factQueue.empty(), "bcp(): conflict-2"); TRACE_MSG("search bcp", "bcp[circuit propagate] => false }}"); return false; } } } // Finished with BCP* (without DPs). clearLiterals(); // Now, propagate the facts to DPs and repeat ((BCP*); DP) step if(!d_core->inconsistent()) commitFacts(); } if (d_core->inconsistent()) { d_conflictTheorem = d_core->inconsistentThm(); clearFacts(); TRACE_MSG("search bcp", "bcp[DP conflict] => false }}"); return false; } else TRACE("search basic", "Processed ", d_literals.size(), " propagations"); IF_DEBUG(fullCheck();) clearLiterals(); bool dfs_heuristic = (d_core->getFlags()["de"].getString() == "dfs"); TRACE("search dfs", "DFS is ", (dfs_heuristic? "on" : "off"), " (de = "+d_core->getFlags()["de"].getString()+") {"); // When DFS heuristic is used, simplify the nonliterals only until // there is a completely simplified one on top of the stack, or // all of the non-literals are gone. Start from the end of the // list (top of the stack), since that's where the splitter is // most likely chosen. This way we are likely to hit something // that simplifies very soon. size_t origSize = d_nonLiterals.size(); bool done(false); for(int i=origSize-1; !done && !d_core->inconsistent() && i>=0; --i) { const Theorem& thm = d_nonLiterals[i].get(); const Expr& e = thm.getExpr(); TRACE("search dfs", "Simplifying non-literal", e, ""); if (e.isTrue()) { // if (d_nonLiteralSimplified[thm.getExpr()]) { IF_DEBUG(debugger.counter("BCP: simplified non-literals: skipped [stale]")++;) TRACE_MSG("search bcp", "}[continue]// end of while(newInfo)"); continue; } IF_DEBUG(debugger.counter("BCP: simplified non-literals")++;) Theorem simpThm = simplify(thm); Expr simp = simpThm.getExpr(); if(simp != e) { IF_DEBUG(debugger.counter("BCP: simplified non-literals: changed")++;) newInfo = true; // d_nonLiteralSimplified[thm.getExpr()] = true; if (!simp.isFalse()) { while (simp.isExists()) { simpThm = d_commonRules->skolemize(simpThm); simp = simpThm.getExpr(); } if (simp.isAbsLiteral()) { enqueueFact(simpThm); commitFacts(); } d_nonLiterals[i] = simpThm; if(dfs_heuristic) { // Something has changed, time to stop this loop. If we // also get a new non-literal on top of the stack, and no // new literals, then stop the entire BCP (since that // non-literal is guaranteed to be fully simplified). done = true; if(d_nonLiterals.size() > origSize && d_literals.empty()) newInfo = false; } } else setInconsistent(simpThm); } else if (dfs_heuristic) done = true; } TRACE("search dfs", "End of non-literal simplification: newInfo = ", (newInfo? "true" : "false"), " }}"); if (d_core->inconsistent()) { d_conflictTheorem = d_core->inconsistentThm(); DebugAssert(d_factQueue.empty(), "bcp(): inconsistent (nonLits)"); TRACE_MSG("search bcp", "bcp[nonCNF conflict] => false }}"); return false; } TRACE_MSG("search bcp", "}// end of while(newInfo)"); } IF_DEBUG(fullCheck();) DebugAssert(d_factQueue.empty(), "bcp(): end"); TRACE_MSG("search bcp", "bcp => true }"); return true; } // True if successfully propagated. False if conflict. bool SearchEngineFast::propagate(const Clause &c, int idx, bool& wpUpdated) { TRACE("search propagate", "propagate(", CompactClause(c), ", idx = "+int2string(idx)+") {"); DebugAssert(idx==0 || idx==1, "propagate(): bad index = "+int2string(idx)); // The current watched literal must be set to FALSE, unless the // clause is of size 1 DebugAssert((c.size() == 1) || c.watched(idx).getValue() < 0, "propagate(): this literal must be FALSE: c.watched(" +int2string(idx)+")\n c = "+c.toString()); wpUpdated = false; int lit = c.wp(idx), otherLit = c.wp(1-idx); int dir = c.dir(idx); int size = c.size(); while(true) { TRACE_MSG("search propagate", "propagate: lit="+int2string(lit) +", otherLit="+int2string(otherLit)+", dir="+int2string(dir)); lit += dir; if(lit < 0 || lit >= size) { // hit the edge if(dir == c.dir(idx)) { // Finished first half of the clause, do the other half lit = c.wp(idx); dir = -dir; continue; } // All literals are false, except for the other watched literal. // Check its value. Literal l(c[otherLit]); if(l.getValue() < 0) { // a conflict //Literal ff(newLiteral(d_vcl->getEM()->falseExpr())); //ff.setValue(1, c, -1); //d_lastBCPConflict = ff; vector thms; for (unsigned i = 0; i < c.size(); ++i) thms.push_back(c[i].getTheorem()); d_conflictTheorem = d_rules->conflictRule(thms,c.getTheorem()); TRACE("search propagate", "propagate[", CompactClause(c), "] => false }"); return false; } else if(l.getValue() == 0) { DebugAssert(c.size() > 1 && l.getExpr().isAbsLiteral(), "BCP: Expr should be literal"); d_unitPropCount++; c.markSat(); // Let's prove the new literal instead of playing assumption games unitPropagation(c,otherLit); //l.setValue(1, c, otherLit); //d_core->addFact(createAssumption(l)); TRACE("search propagate", "propagate[", CompactClause(c), "] => true }"); return true; } else { c.markSat(); TRACE("search propagate", "propagate[", CompactClause(c), "] => true }"); return true; } } // If it's the other watched literal, skip it if(lit == otherLit) continue; Literal l(c[lit]); int val(l.getValue()); // if it is false, keep looking if(val < 0) continue; // OPTIMIZATION: if lit is TRUE, mark the clause SAT and give up. // FIXME: this is different from Chaff. Make sure it doesn't harm // the performance. if(val > 0) { c.markSat(); // return true; } // Now the value of 'lit' is unknown. Set the watch pointer to // this literal, if it is indeed a literal (it may be any formula // in a pseudo-clause), and update the direction. c.wp(idx, lit); c.dir(idx, dir); DebugAssert(c.watched(idx).getValue() >= 0, "Bad watched literals in clause:\n" +CompactClause(c).toString()); // Get the expression of the literal's inverse Literal inv(!c[lit]); // If it is indeed a literal, update the watch pointers DebugAssert(inv.getExpr().isAbsLiteral(), "Expr should be literal: inv = " +inv.getExpr().toString()); // Add the new watched literal to the watch pointer list pair p(c, idx); wp(inv).push_back(p); // Signal to remove the old watch pointer wpUpdated = true; TRACE("search propagate", "propagate[", CompactClause(c), "] => true }"); return true; } } void SearchEngineFast::unitPropagation(const Clause &c, unsigned idx) { vector thms; for (unsigned i = 0; i < c.size(); ++i) if (i != idx) { thms.push_back(c[i].getTheorem()); DebugAssert(!thms.back().isNull(), "unitPropagation(idx = "+int2string(idx)+", i = " +int2string(i)+",\n"+c.toString()+")"); } Theorem thm(d_rules->unitProp(thms,c.getTheorem(),idx)); enqueueFact(thm); // d_core->addFact(thm); // recordFact(thm); DebugAssert(thm.isAbsLiteral(), "unitPropagation(): pushing non-literal to d_literals:\n " +thm.getExpr().toString()); Literal l(newLiteral(thm.getExpr())); DebugAssert(l.getValue() == 1, "unitPropagation: bad literal: " +l.toString()); d_literals.push_back(l); } bool SearchEngineFast::fixConflict() { TRACE_MSG("search basic", "FixConflict"); Theorem res, conf; d_conflictCount++; TRACE("conflicts", "found conflict # ", d_conflictCount, ""); IF_DEBUG(if(debugger.trace("impl graph verbose")) { d_conflictTheorem.printDebug(); }) if (scopeLevel() == d_bottomScope) return false; else if(d_conflictTheorem.getScope() <= d_bottomScope) { d_decisionEngine->popTo(d_bottomScope); d_litsMaxScorePos = 0; // from decision engine clearLiterals(); return false; } traceConflict(d_conflictTheorem); if (d_lastConflictScope <= d_bottomScope) return false; // If we have unit conflict clauses, then we have to bounce back to // the original scope and assert them. if(d_unitConflictClauses.size() > 0) { TRACE_MSG("search basic", "Found unit conflict clause"); d_decisionEngine->popTo(d_bottomScope); d_litsMaxScorePos = 0; // from decision engine clearLiterals(); for (vector::reverse_iterator i = d_unitConflictClauses.rbegin(); i != d_unitConflictClauses.rend(); ++i) { //IF_DEBUG(checkAssumpDebug(i->getTheorem(), d_assumptions);) // The theorem of *i is, most likely, (OR lit); rewrite it to just `lit' Theorem thm = i->getTheorem(); if(thm.getExpr().isOr()) thm = d_commonRules->iffMP(thm, d_commonRules->rewriteOr(thm.getExpr())); enqueueFact(thm); commitFacts(); // Make sure facts propagate to DPs } d_unitConflictClauses.clear(); return true; // Let bcp take care of the rest. } // Otherwise, we need to make our failure driven assertion. DebugAssert(!d_lastConflictClause.isNull(), ""); // We need to calculate the backtracking level. We do this by // examining the decision levels of all the literals involved in the // last conflict clause. Clause &c = d_lastConflictClause; Literal unit_lit; unsigned idx=0; unsigned current_dl = d_lastConflictScope; unsigned back_dl = d_bottomScope; for (unsigned i = 0; i < c.size(); ++i) { unsigned dl = c[i].getVar().getScope(); if (dl < current_dl) { if (dl > back_dl) back_dl = dl; } else { DebugAssert(unit_lit.getExpr().isNull(), "Only one lit from the current decision level is allowed.\n" "current_dl=" +int2string(current_dl)+", scopeLevel=" +int2string(scopeLevel()) +"\n l1 = " +unit_lit.toString() +"\n l2 = "+c[i].toString() +"\nConflict clause: "+c.toString()); unit_lit = c[i]; idx = i; } } // Now we have the backtracking decision level. DebugAssert(!unit_lit.getExpr().isNull(),"Need to have an FDA in " "conflict clause: "+c.toString()); d_decisionEngine->popTo(back_dl); d_litsMaxScorePos = 0; // from decision engine clearLiterals(); unitPropagation(c,idx); commitFacts(); // Make sure facts propagate to DPs return true; } void SearchEngineFast::enqueueFact(const Theorem& thm) { // d_core->addFact(thm); TRACE("search props", "SearchEngineFast::enqueueFact(", thm.getExpr(), ") {"); if(thm.isAbsLiteral()) { addLiteralFact(thm); } d_factQueue.push_back(thm); TRACE_MSG("search props", "SearchEngineFast::enqueueFact => }"); } void SearchEngineFast::setInconsistent(const Theorem& thm) { TRACE_MSG("search props", "SearchEngineFast::setInconsistent()"); d_factQueue.clear(); IF_DEBUG(debugger.counter("conflicts from SAT solver")++;) d_core->setInconsistent(thm); } void SearchEngineFast::commitFacts() { for(vector::iterator i=d_factQueue.begin(), iend=d_factQueue.end(); i!=iend; ++i) { TRACE("search props", "commitFacts(", i->getExpr(), ")"); if(d_useEnqueueFact) d_core->enqueueFact(*i); else d_core->addFact(*i); } d_factQueue.clear(); } void SearchEngineFast::clearFacts() { TRACE_MSG("search props", "clearFacts()"); d_factQueue.clear(); } void SearchEngineFast::addNewClause(Clause &c) { DebugAssert(c.size() > 1, "New clauses should have size > 1"); d_clauses.push_back(c); updateLitCounts(c); // Set up the watch pointers to this clause: find two unassigned // literals (otherwise we shouldn't even receive it as a clause) size_t i=0, iend=c.size(); for(; i& lits, vector& gamma, vector& fringe, int& pending) { // Decrease the fan-out count int fanOutCount(thm.getCachedValue() - 1); thm.setCachedValue(fanOutCount); bool wasFlagged(thm.isFlagged()); thm.setFlag(); DebugAssert(fanOutCount >= 0, "analyzeUIPs(): node visited too many times: " +thm.toString()); if(fanOutCount == 0) { if(thm.getExpandFlag()) { if(wasFlagged) { TRACE("impl graph", "pending.erase(", thm.getExpr(), ")"); DebugAssert(pending > 0, "analyzeUIPs(): pending set shouldn't be empty here"); pending--; } TRACE("impl graph", "fringe.insert(", thm.getExpr(), ")"); fringe.push_back(thm); } else if(thm.getLitFlag()) { DebugAssert(thm.isAbsLiteral(), "analyzeUIPs(): bad flag on " +thm.toString()); if(wasFlagged) { TRACE("impl graph", "pending.erase(", thm.getExpr(), ")"); DebugAssert(pending > 0, "analyzeUIPs(): pending set shouldn't be empty here"); pending--; } TRACE("impl graph", "lits.insert(", thm.getExpr(), ")"); lits.push_back(thm); } else { if(!wasFlagged) { TRACE("impl graph", "gamma.insert(", thm.getExpr(), ")"); gamma.push_back(thm); } else { TRACE("impl graph", "already in gamma: ", thm.getExpr(), ""); } } } else { // Fan-out count is non-zero if(thm.getExpandFlag()) { // Too early to expand; stash in pending if(!wasFlagged) { pending++; TRACE("impl graph", "pending.insert(", thm.getExpr(), ")"); } else { TRACE("impl graph", "already in pending: ", thm.getExpr(), ""); } } else if(thm.getLitFlag()) { // It's a literal which goes into pending if(!wasFlagged) { pending++; TRACE("impl graph", "pending.insert(", thm.getExpr(), ")"); } else { TRACE("impl graph", "already in pending: ", thm.getExpr(), ""); } } else { if(!wasFlagged) { TRACE("impl graph", "gamma.insert(", thm.getExpr(), ")"); gamma.push_back(thm); } else { TRACE("impl graph", "already in gamma: ", thm.getExpr(), ""); } } } // FIXME: uniquify theorems in lits, gamma, and fringe by // expression; the smallest scope theorem should supersede all the // duplicates. Question: can we do it safely, without breaking the // UIP algorithm? } /*! Finding UIPs (Unique Implication Pointers) This is basically the same as finding hammocks of the subset of the implication graph composed of only the nodes from the current scope. A hammock is a portion of the graph which has a single source and/or sink such that removing that single node makes the graph disconnected. Conceptually, the algorithm maintains four sets of nodes: literals (named lits), gamma, fringe, and pending. Literals are nodes whose expressions will become literals in the conflict clause of the current hammock, and the nodes in gamma are assumptions from which such conflict clause theorem is derived. Nodes in fringe are intermediate nodes which are ready to be "expanded" (see the algorithm description below). The pending nodes are those which are not yet ready to be processed (they later become literal or fringe nodes). These sets are maintained as vectors, and are updated in such a way that the nodes in the vectors never repeat. The exception is the pending set, for which only a size counter is maintained. A node belongs to the pending set if it has been visited (isFlagged() method), and its fan-out count is non-zero (stored in the cache, getCachedValue()). In other words, pending nodes are those that have been visited, but not sufficient number of times. Also, fringe is maintained as a pair of vectors. One vector is always the current fringe, and the other one is built when the current is processed. When processing of the current fringe is finished, it is cleared, and the other vector becomes the current fringe (that is, they swap roles). A node is expanded if it is marked for expansion (getExpandFlag()). If its fan-out count is not yet zero, it is added to the set of pending nodes. If a node has a literal flag (getLitFlag()), it goes into literals when its fan-out count reaches zero. Since this will be the last time the node is visited, it is added to the vector only once. A node neither marked for expansion nor with the literal flag goes into the gamma set. It is added the first time the node is visited (isFlagged() returns false), and therefore, is added to the vector only once. This is an important distinction from the other sets, since a gamma-node may be used by several conflict clauses. Clearing the gamma set after each UIP requires both clearing the vector and resetting all flags (clearAllFlags()). The algorithm
  1. Initially, the fringe contains exactly the predecessors of falseThm from the current scope which are ready to be expanded (fan-out count is zero). All the other predecessors of falseThm go to the appropriate sets of literals, gamma, and pending.
  2. If fringe.size() <= 1 and the set of pending nodes is empty, then the element in the fringe (if it's non-empty) is a UIP. Generate a conflict clause from the UIP and the literals (using gamma as the set of assumptions), empty the sets, and continue with the next step. Note, that the UIP remains in the fringe, and will be expanded in the next step. The important exception: if the only element in the fringe is marked for expansion, then this is a false UIP (the SAT solver doesn't know about this node), and it should not appear in the conflict clause. In this case, simply proceed to step 3 as if nothing happened.
  3. If fringe.size()==0, stop (the set of pending nodes must also be empty at this point). Otherwise, for *every* node in the fringe, decrement the fan-out for each of its predecessors, and empty the fringe. Take the predecessors from the current scope, and add those to the fringe for which fan-out count is zero, and remove them from the set of pending nodes. Add the other predecessors from the current scope to the set of pending nodes. Add the remaining predecessors (not from the current scope) to the literals or gamma, as appropriate. Continue with step 2.
*/ void SearchEngineFast::analyzeUIPs(const Theorem &falseThm, int conflictScope) { TRACE("impl graph", "analyzeUIPs(scope = ", conflictScope, ") {"); vector fringe[2]; // 2-element array of vectors (new & curr. fringe) unsigned curr(0), next(1); int pending(0); vector lits; vector gamma; Theorem start = falseThm; d_lastConflictClause = Clause(); d_lastConflictScope = conflictScope; start.clearAllFlags(); TRACE("search full", "Analysing UIPs at level: ", conflictScope, ""); // Initialize all the sets const Assumptions& a=start.getAssumptionsRef(); for(Assumptions::iterator i=a.begin(), iend=a.end(); i!=iend; ++i) { processNode(*i, lits, gamma, fringe[curr], pending); } while (true) { TRACE_MSG("impl graph", "analyzeUIPs(): fringe size = " +int2string(fringe[curr].size()) +", pending size = "+int2string(pending)); // Wrap up a conflict clause if: // (1) There are no pending nodes // (2) The fringe has at most one element // (3) If fringe is not empty, its node should not be flagged for expansion if(fringe[curr].size() <= 1 && pending == 0 && (fringe[curr].size() == 0 || !fringe[curr].back().getExpandFlag())) { // Found UIP or end of graph. Generate conflict clause. if(fringe[curr].size() > 0) lits.push_back(fringe[curr].back()); IF_DEBUG(if(debugger.trace("impl graph")) { ostream& os = debugger.getOS(); os << "Creating conflict clause:" << "\n start: " << start.getExpr() << "\n Lits: [\n"; for(size_t i=0; iconflictClause(start, lits, gamma); d_conflictClauseCount++; // Generate the actual clause and set it up Clause c(d_core, d_vm, clause, d_bottomScope, __FILE__, __LINE__); updateLitCounts(c); if (c.size() > 1) { // Set the watched pointers to the two literals with the // highest scopes int firstLit = 0; int secondLit = 1; int firstDL = c[0].getScope(); int secondDL = c[1].getScope(); // Invariant: firstDL >= secondDL if(firstDL < secondDL) { firstLit=1; secondLit=0; int tmp(secondDL); secondDL=firstDL; firstDL=tmp; } for(unsigned i = 2; i < c.size(); ++i) { int cur = c[i].getScope(); if(cur >= firstDL) { secondLit=firstLit; secondDL=firstDL; firstLit=i; firstDL=cur; } else if(cur > secondDL) { secondLit=i; secondDL=cur; } } c.wp(0, firstLit); c.wp(1, secondLit); // Add the watch pointers to the d_wp lists for(int i=0; i<=1; i++) { // Negated watched literal Literal l(!c.watched(i)); // Add the pointer to l's list pair p(c, i); wp(l).push_back(p); } } TRACE("conflict clauses", "Conflict clause #"+int2string(d_conflictClauseCount) +": ", CompactClause(c), ""); if(c.size() == 1) { // Unit clause: stash it for later unit propagation TRACE("conflict clauses", "analyzeUIPs(): unit clause: ", CompactClause(c), ""); d_unitConflictClauses.push_back(c); } else { TRACE("conflict clauses", "analyzeUIPs(): conflict clause ", CompactClause(c), ""); DebugAssert(c.getScope() <= d_bottomScope, "Conflict clause should be at bottom scope."); d_conflictClauses->push_back(c); if (d_lastConflictClause.isNull()) { d_lastConflictClause = c; // IF_DEBUG(for(unsigned i=0; i 0) { // This was a UIP. Leave it in the fringe for later expansion. IF_DEBUG(debugger.counter("UIPs")++;) start = fringe[curr].back(); lits.clear(); gamma.clear(); start.clearAllFlags(); } else { // No more conflict clauses, we are done. This is the only // way this function can return. TRACE_MSG("impl graph", "analyzeUIPs => }"); return; } } // Now expand all the nodes in the fringe for(vector::iterator i=fringe[curr].begin(), iend=fringe[curr].end(); i!=iend; ++i) { const Assumptions& a=i->getAssumptionsRef(); for(Assumptions::iterator j=a.begin(), jend=a.end(); j!=jend; ++j) { processNode(*j, lits, gamma, fringe[next], pending); } } // Swap the current and next fringes fringe[curr].clear(); curr = 1 - curr; next = 1 - next; IF_DEBUG(if(pending > 0 && fringe[curr].size()==0) falseThm.printDebug();) DebugAssert(pending == 0 || fringe[curr].size() > 0, "analyzeUIPs(scope = " +int2string(conflictScope)+"): empty fringe"); } } //////////////////////////////// // End New Search Engine Code // //////////////////////////////// //! Redefine the counterexample generation. /*! FIXME: for now, it just dumps all the assumptions (same as * getAssumptions()). Eventually, it will simplify the related * formulas to TRUE, merge all the generated assumptions into * d_lastCounterExample, and call the parent's method. */ void SearchEngineFast::getCounterExample(std::vector& assertions) { // This will not add anything, since the counterexample is empty, // but will check if we are allowed to be called SearchImplBase::getCounterExample(assertions); getAssumptions(assertions); } //! Notify the search engine about a new non-literal fact. /*! It should be called by TheoryCore::assertFactCore(). * * If the fact is an AND, we split it into individual conjuncts and * add them individually. * * If the fact is an OR, we check whether it's a CNF clause; that is, * whether all disjuncts are literals. If they are, we add it as a * CNF clause. * * Otherwise add the fact to d_nonLiterals as it is. */ void SearchEngineFast::addNonLiteralFact(const Theorem& thm) { TRACE("search", "addNonLiteralFact(", thm, ") {"); TRACE("search", "d_nonLiteralsSaved.size()=",d_nonLiteralsSaved.size(), "@"+int2string(scopeLevel())); //IF_DEBUG(checkAssumpDebug(thm, d_assumptions);) const Expr& e(thm.getExpr()); if(d_nonLiteralsSaved.count(e) > 0) { // We've seen this non-literal before. TRACE_MSG("search", "addNonLiteralFact[skipping] => }"); IF_DEBUG(debugger.counter("skipped repeated non-literals")++;) return; } // Save the non-literal d_nonLiteralsSaved[e]=thm; bool isCNFclause(false); // Split conjunctions into individual assertions and add them to the // appropriate lists int k = e.getKind(); if (k == AND_R || k == IFF_R || k == ITE_R) { d_circuits.push_back(new Circuit(this, thm)); } else if(e.isAnd()) { for(int i=0, iend=e.arity(); iandElim(thm, i)); // Call enqueueFact(), not addFact(), since we are called from // addFact() here if(e[i].isAbsLiteral()) { d_core->enqueueFact(t_i); } else addNonLiteralFact(t_i); } } else { int unsetLits(0); // Count the number of unset literals size_t unitLit(0); // If the #unsetLits==1, this is the only unset literal vector thms; // collect proofs of !l_i for unit prop. if(e.isOr()) { isCNFclause = true; for(int i=0; isCNFclause && i 0) // The entire clause is true; ignore it return; if(l.getValue() == 0) { // Found unset literal unsetLits++; unitLit = i; } else // Literal is false, collect the theorem for it thms.push_back(l.deriveTheorem()); } } } if(isCNFclause) { DebugAssert(e.arity() > 1, "Clause should have more than one literal"); // Check if clause is unit or unsat if(unsetLits==0) { // Contradiction TRACE("search", "contradictory clause:\n", CompactClause(Clause(d_core, d_vm, thm, scopeLevel())),""); setInconsistent(d_rules->conflictRule(thms, thm)); } else if(unsetLits==1) { // Unit clause: propagate literal TRACE("search", "unit clause, unitLit = "+int2string(unitLit)+":\n", CompactClause(Clause(d_core, d_vm, thm, scopeLevel())),""); d_core->enqueueFact(d_rules->unitProp(thms, thm, unitLit)); } else { // Wrap up the clause Clause c(d_core, d_vm, thm, scopeLevel(), __FILE__, __LINE__); IF_DEBUG(debugger.counter("CNF clauses added")++;) TRACE("search", "addNonLiteralFact: adding CNF: ", c, ""); addNewClause(c); } } else { TRACE("search", "addNonLiteralFact: adding non-literal: ", thm, ""); IF_DEBUG(debugger.counter("added non-literals")++;) d_nonLiterals.push_back(SmartCDO(d_core->getCM()->getCurrentContext(), thm)); // d_nonLiteralSimplified[thm.getExpr()] = false; } } TRACE_MSG("search", "addNonLiteralFact => }"); } //! Notify the search engine about a new literal fact. /*! It should be called by TheoryCore::assertFactCore() */ void SearchEngineFast::addLiteralFact(const Theorem& thm) { TRACE("search", "addLiteralFact(", thm, ")"); // Save the value of the flag to restore it later bool useEF(d_useEnqueueFact); d_useEnqueueFact=true; DebugAssert(thm.isAbsLiteral(), "addLiteralFact: not a literal: " + thm.toString()); //IF_DEBUG(checkAssumpDebug(thm, d_assumptions);) Literal l(newLiteral(thm.getExpr())); TRACE("search", "addLiteralFact: literal = ", l, ""); // Only add the literal if it doesn't have any value; otherwise it's // either a contradiction, or it must already be in the list // FIXME: why did we need thm.getScope() != 0 ??? if ((l.getValue() == 0 /* && thm.getScope() != 0 */) /* || (l.getValue() == 1 && l.getScope() > thm.getScope()) */) { l.setValue(thm, scopeLevel()); DebugAssert(l.getExpr().isAbsLiteral(), "addLiteralFact(): pushing non-literal to d_literals:\n " +l.getExpr().toString()); DebugAssert(l.getValue() == 1, "addLiteralFact(): l = "+l.toString()); d_literals.push_back(l); d_literalSet.insert(l.getExpr(),l); // Immediately propagate the literal with BCP, unless the SAT // solver is already running if(!d_inCheckSAT) bcp(); // if (thm.getScope() != scopeLevel()) { // IF_DEBUG(debugger.counter("addLiteralFact adds unreported lit")++;) // d_unreportedLits.insert(l.getExpr(),thm,thm.getScope()); // } } else if(l.getValue() < 0) { // Contradiction, bcp will die anyway if(l.isNegative()) setInconsistent(d_commonRules->contradictionRule(l.deriveTheorem(), thm)); else setInconsistent(d_commonRules->contradictionRule(thm, l.deriveTheorem())); } d_useEnqueueFact=useEF; } /*! @brief Redefine newIntAssumption(): we need to add the new theorem * to the appropriate Literal */ Theorem SearchEngineFast::newIntAssumption(const Expr& e) { Theorem thm(SearchImplBase::newIntAssumption(e)); DebugAssert(thm.isAssump(), "Splitter should be an assumption:" + thm.toString()); TRACE("search full", "Splitter: ", thm.toString(), ""); const Expr& expr = thm.getExpr(); Literal l(newLiteral(expr)); if(l.getValue() == 0) { l.setValue(thm, scopeLevel()); if(l.getExpr().isAbsLiteral()) { DebugAssert(l.getValue() == 1, "newIntAssumption(): l = "+l.toString()); d_literals.push_back(l); } else d_litsAlive.push_back(l); } return thm; } bool SearchEngineFast::isAssumption(const Expr& e) { return (SearchImplBase::isAssumption(e) || (d_nonLiteralsSaved.count(e) > 0)); } void SearchEngineFast::addSplitter(const Expr& e, int priority) { // SearchEngine::addSplitter(e, priority); DebugAssert(e.isAbsLiteral(), "SearchEngineFast::addSplitter("+e.toString()+")"); Literal lit(newLiteral(e)); d_dpSplitters.push_back(Splitter(lit)); if(priority != 0) { d_litSortCount--; lit.score() += priority*10; } if(!lit.added()) { TRACE("search literals", "addSplitter(): adding literal ", lit, " to d_litsByScores"); d_litsByScores.push_back(lit); lit.added()=true; if(priority == 0) d_litSortCount--; } if(d_litSortCount < 0) { ::stable_sort(d_litsByScores.begin(), d_litsByScores.end(), compareLits); d_litSortCount=d_litsByScores.size(); } TRACE("search splitters","addSplitter => ", lits2str(d_litsByScores),""); } QueryResult SearchEngineFast::checkValidMain(const Expr& e2) { // Propagate the literals asserted before checkValid() for(CDMap::iterator i=d_literalSet.begin(), iend=d_literalSet.end(); i!=iend; ++i) d_literals.push_back((*i).second); // Run the SAT solver QueryResult result = checkSAT(); Theorem res; if (result == UNSATISFIABLE) res = d_conflictTheorem; else if (result == SATISFIABLE) { // Set counter-example vector a; unsigned i; Theorem thm; d_lastCounterExample.clear(); for (i=d_nonlitQueryStart; i < d_nonlitQueryEnd; ++i) { thm = d_nonLiterals[i].get(); DebugAssert(thm.getExpr().isTrue(), "original nonLiteral doesn't simplify to true"); thm.getLeafAssumptions(a); for (vector::iterator i=a.begin(), iend=a.end(); i != iend; ++i) { d_lastCounterExample[*i] = true; } a.clear(); } for (i=d_clausesQueryStart; i < d_clausesQueryEnd; ++i) { thm = simplify(((Clause)d_clauses[i]).getTheorem()); DebugAssert(thm.getExpr().isTrue(), "original nonLiteral doesn't simplify to true"); thm.getLeafAssumptions(a); for (vector::iterator i=a.begin(), iend=a.end(); i != iend; ++i) { d_lastCounterExample[*i] = true; } a.clear(); } } else return result; processResult(res, e2); if (result == UNSATISFIABLE) { d_core->getCM()->popto(d_bottomScope); d_litsMaxScorePos = 0; // from decision engine // Clear data structures d_unitConflictClauses.clear(); clearLiterals(); clearFacts(); Theorem e_iff_e2(d_commonRules->iffContrapositive(d_simplifiedThm)); d_lastValid = d_commonRules->iffMP(d_lastValid, d_commonRules->symmetryRule(e_iff_e2)); IF_DEBUG(checkAssumpDebug(d_lastValid, d_assumptions);) TRACE_MSG("search terse", "checkValid => true}"); TRACE("search", "checkValid => true; theorem = ", d_lastValid, "}"); d_core->getCM()->pop(); } else { TRACE_MSG("search terse", "checkValid => false}"); TRACE_MSG("search", "checkValid => false; }"); DebugAssert(d_unitConflictClauses.size() == 0, "checkValid(): d_unitConflictClauses postcondition violated"); DebugAssert(d_literals.size() == 0, "checkValid(): d_literals postcondition violated"); DebugAssert(d_factQueue.empty(), "checkValid(): d_factQueue postcondition violated"); } return result; } QueryResult SearchEngineFast::checkValidInternal(const Expr& e) { DebugAssert(d_unitConflictClauses.size() == 0, "checkValid(): d_unitConflitClauses precondition violated"); DebugAssert(d_factQueue.empty(), "checkValid(): d_factQueue precondition violated"); TRACE("search", "checkValid(", e, ") {"); TRACE_MSG("search terse", "checkValid() {"); if (!e.getType().isBool()) { throw TypecheckException ("checking validity of a non-boolean expression:\n\n " + e.toString() + "\n\nwhich has the following type:\n\n " + e.getType().toString()); } // A successful query should leave the context unchanged d_core->getCM()->push(); d_conflictClauseManager.setRestorePoint(); d_bottomScope = scopeLevel(); // First, simplify the NEGATION of the given expression: that's what // we'll assert d_simplifiedThm = d_core->getExprTrans()->preprocess(e.negate()); TRACE("search", "checkValid: simplifiedThm = ", d_simplifiedThm, ""); const Expr& not_e2 = d_simplifiedThm.get().getRHS(); Expr e2 = not_e2.negate(); // Assert not_e2 if it's not already asserted TRACE_MSG("search terse", "checkValid: Asserting !e: "); TRACE("search", "checkValid: Asserting !e: ", not_e2, ""); Theorem not_e2_thm; d_nonlitQueryStart = d_nonLiterals.size(); d_clausesQueryStart = d_clauses.size(); if(d_assumptions.count(not_e2) == 0) { not_e2_thm = newUserAssumption(not_e2); } else { not_e2_thm = d_assumptions[not_e2]; } // d_core->addFact(not_e2_thm); d_nonlitQueryEnd = d_nonLiterals.size(); d_clausesQueryEnd = d_clauses.size(); // Reset the splitter counter. This will force a call to // updateLitScores() the first time we need to find a splitter, and // clean out junk from the previous calls to checkValid(). d_splitterCount=0; return checkValidMain(e2); } QueryResult SearchEngineFast::restartInternal(const Expr& e) { DebugAssert(d_unitConflictClauses.size() == 0, "restart(): d_unitConflitClauses precondition violated"); DebugAssert(d_factQueue.empty(), "restart(): d_factQueue precondition violated"); TRACE("search", "restart(", e, ") {"); TRACE_MSG("search terse", "restart() {"); if (!e.getType().isBool()) { throw TypecheckException ("argument to restart is a non-boolean expression:\n\n " + e.toString() + "\n\nwhich has the following type:\n\n " + e.getType().toString()); } if (d_bottomScope == 0) { throw Exception("Call to restart with no current query"); } d_core->getCM()->popto(d_bottomScope); Expr e2 = d_simplifiedThm.get().getRHS().negate(); TRACE_MSG("search terse", "restart: Asserting e: "); TRACE("search", "restart: Asserting e: ", e, ""); if(d_assumptions.count(e) == 0) { d_core->addFact(newUserAssumption(e)); } return checkValidMain(e2); } /*! * The purpose of this method is to mark up the assumption graph of * the FALSE Theorem (conflictThm) for the later UIP analysis. The * required flags for each assumption in the graph are: * * ExpandFlag: whether to "expand" the node or not; * that is, whether to consider the current node as a final assumption * (either as a conflict clause literal, or a context assumption from * \f$\Gamma\f$) * * LitFlag: the node (actually, its inverse) is a * literal of the conflict clause * * CachedValue: the "fanout" count, how many nodes in * the assumption graph are derived from the current node. * * INVARIANTS (after the method returns): * * -# The currect scope is the "true" conflict scope, * i.e. scopeLevel() == conflictThm.getScope() * -# The literals marked with LitFlag (CC literals) are known to the * SAT solver, i.e. their Literal class has a value == 1 * -# The only CC literal from the current scope is the latest splitter * * ASSUMPTIONS: * * -# The Theorem scope of an assumption is the same as its Literal scope; * i.e. if thm is a splitter, then * thm.getScope() == newLiteral(thm.getExpr()).getScope() * * Algorithm: * * First, backtrack to the scope level of the conflict. Then, * traverse the implication graph until we either hit a literal known * to the SAT solver at a lower scope: * newLiteral(e).getScope() }"); return; } // DFS stack vector stack; // Max assumption scope for the contradiction int maxScope(d_bottomScope); // Collect potential top-level splitters IF_DEBUG(vector splitters;) TRACE("impl graph", "traceConflict: maxScope = ", maxScope, ""); conflictThm.clearAllFlags(); conflictThm.setExpandFlag(true); conflictThm.setCachedValue(0); const Assumptions& assump = conflictThm.getAssumptionsRef(); for(Assumptions::iterator i=assump.begin(),iend=assump.end();i!=iend;++i) { TRACE("impl graph", "traceConflict: adding ", *i, ""); stack.push_back(*i); } // Do the non-recursive DFS, mark up the assumption graph IF_DEBUG(Literal maxScopeLit;) while(stack.size() > 0) { Theorem thm(stack.back()); stack.pop_back(); TRACE("impl graph", "traceConflict: while() { thm = ", thm, ""); if (thm.isFlagged()) { // We've seen this theorem before. Update fanout count. thm.setCachedValue(thm.getCachedValue() + 1); TRACE("impl graph", "Found again: ", thm.getExpr().toString(), ""); TRACE("impl graph", "With fanout: ", thm.getCachedValue(), ""); } else { // This is a new theorem. Process it. thm.setCachedValue(1); thm.setFlag(); thm.setLitFlag(false); // Clear this flag (it may be set later) bool expand(false); int scope = thm.getScope(); bool isAssump = thm.isAssump(); IF_DEBUG({ int s = scope; if(thm.isAbsLiteral()) { Literal l(newLiteral(thm.getExpr())); if(l.getValue() == 1) s = l.getScope(); } // maxScope will be reset: clear the splitters if(s > maxScope) splitters.clear(); }) if(thm.isAbsLiteral()) { Literal l(newLiteral(thm.getExpr())); bool isTrue(l.getValue()==1); if(isTrue) scope = l.getScope(); if(!isAssump && (!isTrue || scope == scopeLevel())) expand=true; else if(scope > d_bottomScope) {// Found a literal of a conflict clause IF_DEBUG(if(scope >= maxScope) splitters.push_back(thm);) thm.setLitFlag(true); } } else { DebugAssert(scope <= d_bottomScope || !isAssump, "SearchEngineFast::traceConflict: thm = " +thm.toString()); if(!isAssump && scope > d_bottomScope) expand=true; } if(scope > maxScope) { maxScope = scope; IF_DEBUG(maxScopeLit = newLiteral(thm.getExpr());) TRACE("impl graph", "traceConflict: maxScope = ", maxScope, ""); } if(expand) { DebugAssert(!thm.isAssump(), "traceConflict: thm = "+thm.toString()); thm.setExpandFlag(true); const Assumptions& assump = thm.getAssumptionsRef(); for(Assumptions::iterator i=assump.begin(),iend=assump.end(); i!=iend; ++i) { TRACE("impl graph", "traceConflict: adding ", *i, ""); stack.push_back(*i); } } else thm.setExpandFlag(false); } TRACE_MSG("impl graph", "traceConflict: end of while() }"); } IF_DEBUG(if(maxScope != scopeLevel()) conflictThm.printDebug();) DebugAssert(maxScope == scopeLevel(), "maxScope="+int2string(maxScope) +", scopeLevel()="+int2string(scopeLevel()) +"\n maxScopeLit = "+maxScopeLit.toString()); IF_DEBUG( if(!(maxScope == d_bottomScope || splitters.size() == 1)) { conflictThm.printDebug(); ostream& os = debugger.getOS(); os << "\n\nsplitters = ["; for(size_t i=0; i }"); } cvc3-2.4.1/src/search/LFSCConvert.h0000664000175400017540000000350711363704204016560 0ustar mdetersmdeters#ifndef LFSC_CONVERT_H_ #define LFSC_CONVERT_H_ #include "TReturn.h" class LFSCConvert : public LFSCObj { private: //the converted LFSCProof RefPtr< LFSCProof > pfinal; // translations of proofs for cvc3_to_lfsc : if a proof has already been done, // return the TReturn store for it ExprMap d_th_trans; ExprMap d_th_trans_map[2]; // these are the current TReturns we need to make into lambdas std::map d_th_trans_lam[2]; //counts for theory/non-theory int nodeCount; int nodeCountTh; int unodeCount; int unodeCountTh; //whether to ignore theory lemmas bool ignore_theory_lemmas; // other helper methods bool isTrivialTheoryAxiom(const Expr& expr, bool checkBody = false ); bool isTrivialBooleanAxiom(const Expr& expr); bool isIgnoredRule(const Expr& expr); // main method to implement T transformation: // cvc3 proof syntax tree to lfsc proof syntax tree // beneath_lc is whether you are beneath a learned clause // rev_pol is whether you should prove ~psi2 V psi1 in the provesY = 2 case (reverse the implication) TReturn* cvc3_to_lfsc(const Expr& pf, bool beneath_lc = false, bool rev_pol=false); TReturn* cvc3_to_lfsc_h(const Expr& pf, bool beneath_lc = false, bool rev_pol=false); //do basic subst op procedure TReturn* do_bso( const Expr& pf, bool beneath_lc, bool rev_pol, TReturn* t1, TReturn* t2, ostringstream& ose ); //get proof type int get_proof_pattern( const Expr& pf, Expr& modE ); //make the let proof LFSCProof* make_let_proof( LFSCProof* p ); //make trusted TReturn* make_trusted( const Expr& pf ); virtual ~LFSCConvert(){} public: LFSCConvert( int lfscm ); //main conversion function void convert( const Expr& pf ); //get the results LFSCProof* getLFSCProof() { return pfinal.get(); } }; #endif cvc3-2.4.1/src/util/0000775000175400017540000000000011630011320014005 5ustar mdetersmdeterscvc3-2.4.1/src/util/Makefile0000664000175400017540000000055711000741171015461 0ustar mdetersmdeters################################################## # About this Makefile # # This Makefile depends on Makefile.opts ################################################## MODULE = util SRC = debug.cpp \ statistics.cpp \ rational.cpp \ rational-native.cpp \ rational-gmp.cpp LIBRARY = libcvc_util.a EXTRAFLAGS = $(RATIONAL_FLAGS) include ../../Makefile.local cvc3-2.4.1/src/util/rational-native.cpp0000664000175400017540000006576711406445266017660 0ustar mdetersmdeters/*****************************************************************************/ /*! * \file rational-native.cpp * * \brief Implementation of class Rational using native (bounded * precision) computer arithmetic * * Author: Sergey Berezin * * Created: Mon Jul 28 12:18:03 2003 * *
* License to use, copy, modify, sell and/or distribute this software * and its documentation for any purpose is hereby granted without * royalty, subject to the terms and conditions defined in the \ref * LICENSE file provided with this distribution. * *
* */ /*****************************************************************************/ #ifdef RATIONAL_NATIVE #include "compat_hash_set.h" #include "rational.h" // For atol() (ASCII to long) #include #include #include #include #include #define OVERFLOW_MSG "\nThis is NOT a bug, but an explicit feature to preserve soundness\nwhen CVC3 uses native computer arithmetic (finite precision). To\navoid these types of errors, please recompile CVC3 with GMP library." namespace CVC3 { using namespace std; //! Add two integers and check for overflows static long int plus(long int x, long int y) { long int res = x+y; FatalAssert(((x > 0) != (y > 0)) || ((x > 0) == (res > 0)), "plus(x,y): arithmetic overflow" OVERFLOW_MSG); return res; } //! Add two integers and check for overflows static unsigned long uplus(unsigned long x, unsigned long y) { unsigned long res = x+y; FatalAssert(res >= x && res >= y, "uplus(x,y): arithmetic overflow" OVERFLOW_MSG); return res; } //! Subtract two unsigned integers and check for overflows static unsigned long unsigned_minus(unsigned long x, unsigned long y) { unsigned long res = x-y; FatalAssert(res <= x, "unsigned_minus(x,y): arithmetic overflow" OVERFLOW_MSG); return res; } //! Multiply two unsigned integers and check for overflows static unsigned long umult(unsigned long x, unsigned long y) { unsigned long res = x*y; FatalAssert(res == 0 || res/x == y, "umult(x,y): arithmetic overflow" OVERFLOW_MSG); return res; } //! Shift two unsigned integers and check for overflow static unsigned long ushift(unsigned long x, unsigned y) { FatalAssert(y < (unsigned)numeric_limits::digits, "ushift(x,y): arithmetic overflow" OVERFLOW_MSG); unsigned long res = (x << y); FatalAssert((res >> y) == x, "ushift(x,y): arithmetic overflow" OVERFLOW_MSG); return res; } //! Compute GCD using Euclid's algorithm (from Aaron Stump's code) static unsigned long ugcd(unsigned long n1, unsigned long n2) { DebugAssert(n1!=0 && n2!=0, "gcd("+int2string(n1)+", "+int2string(n2)+"): bad args"); if (n1 < n2) { long int tmp = n1; n1 = n2; n2 = tmp; } // at this point, n1 >= n2 long int r = n1 % n2; if (!r) return n2; return ugcd(n2, r); } //! Unary minus which checks for overflows static long int uminus(long int x) { FatalAssert(x == 0 || x != -x, "uminus(x): arithmetic overflow" OVERFLOW_MSG); return -x; } //! Multiply two integers and check for overflows static long int mult(long int x, long int y) { long int res = x*y; FatalAssert(x==0 || res/x == y, "mult(x,y): arithmetic overflow" OVERFLOW_MSG); return res; } //! Compute GCD using Euclid's algorithm (from Aaron Stump's code) static long int gcd(long int n1, long int n2) { DebugAssert(n1!=0 && n2!=0, "gcd("+int2string(n1)+", "+int2string(n2)+"): bad args"); // First, make the arguments positive if(n1 < 0) n1 = uminus(n1); if(n2 < 0) n2 = uminus(n2); if (n1 < n2) { long int tmp = n1; n1 = n2; n2 = tmp; } // at this point, n1 >= n2 long int r = n1 % n2; if (!r) return n2; return gcd(n2, r); } //! Compute LCM static long int lcm(long int n1, long int n2) { long int g = gcd(n1,n2); return mult(n1/g, n2); } static long int ulcm(unsigned long n1, unsigned long n2) { long int g = ugcd(n1,n2); return umult(n1/g, n2); } // Implementation of the forward-declared internal class class Rational::Impl { long int d_num; //!< Numerator long int d_denom; //!< Denominator //! Make the rational number canonical void canonicalize(); public: //! Default Constructor Impl(): d_num(0), d_denom(1) { } //! Copy constructor Impl(const Impl &x) : d_num(x.d_num), d_denom(x.d_denom) { } //! Constructor from unsigned long Impl(unsigned long n) :d_num(n), d_denom(1) { FatalAssert(d_num >= 0, "Rational::Impl(unsigned long) - arithmetic overflow"); } //! Constructor from a pair of integers Impl(long int n, long int d): d_num(n), d_denom(d) { canonicalize(); } //! Constructor from a string Impl(const string &n, int base); //! Constructor from a pair of strings Impl(const string &n, const string& d, int base); // Destructor virtual ~Impl() { } //! Get numerator long int getNum() const { return d_num; } //! Get denominator long int getDen() const { return d_denom; } //! Unary minus Impl operator-() const; //! Equality friend bool operator==(const Impl& x, const Impl& y) { return (x.d_num == y.d_num && x.d_denom == y.d_denom); } //! Dis-equality friend bool operator!=(const Impl& x, const Impl& y) { return (x.d_num != y.d_num || x.d_denom != y.d_denom); } /*! * Compare x=n1/d1 and y=n2/d2 as n1*f2 < n2*f1, where f1=d1/f, * f2=d2/f, and f=lcm(d1,d2) */ friend bool operator<(const Impl& x, const Impl& y) { Impl diff(x-y); return diff.d_num < 0; } friend bool operator<=(const Impl& x, const Impl& y) { return (x == y || x < y); } friend bool operator>(const Impl& x, const Impl& y) { Impl diff(x-y); return diff.d_num > 0; } friend bool operator>=(const Impl& x, const Impl& y) { return (x == y || x > y); } /*! Addition of x=n1/d1 and y=n2/d2: n1*g2 + n2*g1, where g1=d1/g, * g2=d2/g, and g=lcm(d1,d2) */ friend Impl operator+(const Impl& x, const Impl& y) { long int d1(x.getDen()), d2(y.getDen()); long int f(lcm(d1,d2)), f1(f/d1), f2(f/d2); long int n = plus(mult(x.getNum(), f1), mult(y.getNum(), f2)); return Impl(n, f); } friend Impl operator-(const Impl& x, const Impl& y) { TRACE("rational", "operator-(", x, ", "+y.toString()+")"); long int d1(x.getDen()), d2(y.getDen()); long int f(lcm(d1,d2)), f1(f/d1), f2(f/d2); long int n = plus(mult(x.getNum(), f1), uminus(mult(y.getNum(), f2))); Impl res(n, f); TRACE("rational", " => ", res, ""); return res; } /*! * Multiplication of x=n1/d1, y=n2/d2: * (n1/g1)*(n2/g2)/(d1/g2)*(d2/g1), where g1=gcd(n1,d2) and * g2=gcd(n2,d1) */ friend Impl operator*(const Impl& x, const Impl& y) { long int n1(x.getNum()), d1(x.getDen()), n2(y.getNum()), d2(y.getDen()); long int g1(n1? gcd(n1,d2) : 1), g2(n2? gcd(n2,d1) : 1); long int n(mult(n1/g1, n2/g2)), d(mult(d1/g2, d2/g1)); return Impl(n,d); } /*! * Division of x=n1/d1, y=n2/d2: * (n1/g1)*(d2/g2)/(d1/g2)*(n2/g1), where g1=gcd(n1,n2) and * g2=gcd(d1,d2) */ friend Impl operator/(const Impl& x, const Impl& y) { long int n1(x.getNum()), d1(x.getDen()), n2(y.getNum()), d2(y.getDen()); DebugAssert(n2 != 0, "Impl::operator/: divisor is 0"); long int g1(n1? gcd(n1,n2) : 1), g2(gcd(d1,d2)); long int n(n1? mult(n1/g1, d2/g2) : 0), d(n1? mult(d1/g2, n2/g1) : 1); return Impl(n,d); } friend Impl operator%(const Impl& x, const Impl& y) { DebugAssert(x.getDen() == 1 && y.getDen() == 1, "Impl % Impl: x and y must be integers"); return Impl(x.getNum() % y.getNum(), 1); } //! Print to string string toString(int base = 10) const { ostringstream ss; if (d_num == 0) ss << "0"; else if (base == 10) { ss << d_num; if (d_denom != 1) ss << "/" << d_denom; } else { vector vec; long num = d_num; while (num) { vec.push_back(num % base); num = num / base; } while (!vec.empty()) { if (base > 10 && vec.back() > 10) { ss << (char)('A' + (vec.back()-10)); } else ss << vec.back(); vec.pop_back(); } if(d_denom != 1) { ss << "/"; if (d_denom == 0) ss << "0"; else { num = d_denom; while (num) { vec.push_back(num % base); num = num / base; } while (!vec.empty()) { if (base > 10 && vec.back() > 10) { ss << (char)('A' + (vec.back()-10)); } else ss << vec.back(); vec.pop_back(); } } } } return(ss.str()); } //! Printing to ostream friend ostream& operator<<(ostream& os, const Rational::Impl& n) { return os << n.toString(); } }; // Make the rational number canonical void Rational::Impl::canonicalize() { DebugAssert(d_denom != 0, "Rational::Impl::canonicalize: bad denominator: " +int2string(d_denom)); if(d_num == 0) { d_denom = 1; } else { if(d_denom < 0) { d_num = uminus(d_num); d_denom = uminus(d_denom); } long int d = gcd(d_num, d_denom); if(d != 1) { d_num /= d; d_denom /= d; } } } // Constructor from a string Rational::Impl::Impl(const string &n, int base) { size_t i, iend; for(i=0,iend=n.size(); igetNum(), y.d_n->getNum()), 1)); } Rational gcd(const vector &v) { long int g(1); if(v.size() > 0) { checkInt(v[0], "gcd(vector[0])"); g = v[0].d_n->getNum(); } for(size_t i=1; i)"); if(g == 0) g = v[i].d_n->getNum(); else if(v[i].d_n->getNum() != 0) g = gcd(g, v[i].d_n->getNum()); } return Rational(Rational::Impl(g,1)); } Rational lcm(const Rational &x, const Rational &y) { long int g; checkInt(x, "lcm(*x*,y)"); checkInt(y, "lcm(x,*y*)"); g = lcm(x.d_n->getNum(), y.d_n->getNum()); return Rational(Rational::Impl(g, 1)); } Rational lcm(const vector &v) { long int g(1); for(size_t i=0; i)"); if(v[i].d_n->getNum() != 0) g = lcm(g, v[i].d_n->getNum()); } return Rational(Rational::Impl(g,1)); } Rational abs(const Rational &x) { long int n(x.d_n->getNum()); if(n>=0) return x; return Rational(Rational::Impl(-n, x.d_n->getDen())); } Rational floor(const Rational &x) { if(x.d_n->getDen() == 1) return x; long int n = x.d_n->getNum(); long int nAbs = (n<0)? uminus(n) : n; long int q = nAbs / x.d_n->getDen(); if(n < 0) q = plus(uminus(q), -1); return Rational(Rational::Impl(q,1)); } Rational ceil(const Rational &x) { if(x.d_n->getDen() == 1) return x; long int n = x.d_n->getNum(); long int nAbs = (n<0)? -n : n; long int q = nAbs / x.d_n->getDen(); if(n > 0) q = plus(q, 1); else q = uminus(q); return Rational(Rational::Impl(q,1)); } Rational mod(const Rational &x, const Rational &y) { checkInt(x, "mod(*x*,y)"); checkInt(y, "mod(x,*y*)"); long int r = x.d_n->getNum() % y.d_n->getNum(); return(Rational(Rational::Impl(r,1))); } Rational intRoot(const Rational& base, unsigned long int n) { checkInt(base, "intRoot(*x*,y)"); checkInt(n, "intRoot(x,*y*)"); double b = base.d_n->getNum(); double root = n; root = 1/root; b = ::pow(b, root); long res = (long) ::floor(b); if (::pow((long double)res, (int)n) == base.d_n->getNum()) { return Rational(Rational::Impl(res,1)); } return Rational(Rational::Impl((long)0,(long)1)); } string Rational::toString(int base) const { return(d_n->toString(base)); } size_t Rational::hash() const { std::hash h; return h(toString().c_str()); } void Rational::print() const { cout << (*this) << endl; } // Unary minus Rational Rational::operator-() const { return Rational(Rational::Impl(-(d_n->getNum()), d_n->getDen())); } Rational &Rational::operator+=(const Rational &n2) { *this = (*this) + n2; return *this; } Rational &Rational::operator-=(const Rational &n2) { *this = (*this) - n2; return *this; } Rational &Rational::operator*=(const Rational &n2) { *this = (*this) * n2; return *this; } Rational &Rational::operator/=(const Rational &n2) { *this = (*this) / n2; return *this; } int Rational::getInt() const { checkInt(*this, "getInt()"); long int res = d_n->getNum(); FatalAssert(res >= INT_MIN && res <= INT_MAX, "Rational::getInt(): arithmetic overflow on "+toString() + OVERFLOW_MSG); return (int)res; } unsigned int Rational::getUnsigned() const { checkInt(*this, "getUnsigned()"); long int res = d_n->getNum(); FatalAssert(res >= 0 && res <= (long int)UINT_MAX, "Rational::getUnsigned(): arithmetic overflow on " + toString() + OVERFLOW_MSG); return (unsigned int)res; } #ifdef _DEBUG_RATIONAL_ void Rational::printStats() { int &num_created = getCreated(); int &num_deleted = getDeleted(); if(num_created % 1000 == 0 || num_deleted % 1000 == 0) { std::cerr << "Rational(" << *d_n << "): created " << num_created << ", deleted " << num_deleted << ", currently alive " << num_created-num_deleted << std::endl; } } #endif bool operator==(const Rational &n1, const Rational &n2) { return(*n1.d_n == *n2.d_n); } bool operator<(const Rational &n1, const Rational &n2) { return(*n1.d_n < *n2.d_n); } bool operator<=(const Rational &n1, const Rational &n2) { return(*n1.d_n <= *n2.d_n); } bool operator>(const Rational &n1, const Rational &n2) { return(*n1.d_n > *n2.d_n); } bool operator>=(const Rational &n1, const Rational &n2) { return(*n1.d_n >= *n2.d_n); } bool operator!=(const Rational &n1, const Rational &n2) { return(*n1.d_n != *n2.d_n); } Rational operator+(const Rational &n1, const Rational &n2) { return Rational(Rational::Impl(*n1.d_n + *n2.d_n)); } Rational operator-(const Rational &n1, const Rational &n2) { return Rational(Rational::Impl((*n1.d_n) - (*n2.d_n))); } Rational operator*(const Rational &n1, const Rational &n2) { return Rational(Rational::Impl((*n1.d_n) * (*n2.d_n))); } Rational operator/(const Rational &n1, const Rational &n2) { return Rational(Rational::Impl(*n1.d_n / *n2.d_n)); } Rational operator%(const Rational &n1, const Rational &n2) { return Rational(Rational::Impl(*n1.d_n % *n2.d_n)); } // Implementation of the forward-declared internal class class Unsigned::Impl { unsigned long d_num; public: //! Default Constructor Impl(): d_num(0) { } //! Copy constructor Impl(const Impl &x) : d_num(x.d_num) { } //! Constructor from an unsigned integer Impl(unsigned long n): d_num(n) { } //! Constructor from an int Impl(int n): d_num(n) { FatalAssert(n >= 0, "Attempt to create Unsigned from negative integer"); } //! Constructor from a string Impl(const string &n, int base); // Destructor virtual ~Impl() { } //! Get unsigned unsigned long getUnsigned() const { return d_num; } //! Equality friend bool operator==(const Impl& x, const Impl& y) { return (x.d_num == y.d_num); } //! Dis-equality friend bool operator!=(const Impl& x, const Impl& y) { return (x.d_num != y.d_num); } friend bool operator<(const Impl& x, const Impl& y) { return x.d_num < y.d_num; } friend bool operator<=(const Impl& x, const Impl& y) { return (x.d_num <= y.d_num); } friend bool operator>(const Impl& x, const Impl& y) { return x.d_num > y.d_num; } friend bool operator>=(const Impl& x, const Impl& y) { return x.d_num >= y.d_num; } friend Impl operator+(const Impl& x, const Impl& y) { return Impl(uplus(x.d_num, y.d_num)); } friend Impl operator-(const Impl& x, const Impl& y) { unsigned long n = unsigned_minus(x.d_num, y.d_num); Impl res(n); return res; } friend Impl operator*(const Impl& x, const Impl& y) { unsigned long n(umult(x.d_num, y.d_num)); return Impl(n); } friend Impl operator/(const Impl& x, const Impl& y) { DebugAssert(y.d_num != 0, "Impl::operator/: divisor is 0"); unsigned long n(x.d_num / y.d_num); return Impl(n); } friend Impl operator%(const Impl& x, const Impl& y) { DebugAssert(y.d_num != 0, "Impl % Impl: y must be non-zero"); return Impl(x.d_num % y.d_num); } friend Impl operator<<(const Impl& x, unsigned y) { unsigned long n(ushift(x.d_num, y)); return Impl(n); } friend Impl operator&(const Impl& x, const Impl& y) { return Impl(x.d_num & y.d_num); } //! Print to string string toString(int base = 10) const { ostringstream ss; if (d_num == 0) ss << "0"; else if (base == 10) { ss << d_num; } else { vector vec; long num = d_num; while (num) { vec.push_back(num % base); num = num / base; } while (!vec.empty()) { if (base > 10 && vec.back() > 10) { ss << (char)('A' + (vec.back()-10)); } else ss << vec.back(); vec.pop_back(); } } return(ss.str()); } //! Printing to ostream friend ostream& operator<<(ostream& os, const Unsigned::Impl& n) { return os << n.toString(); } }; // Constructor from a pair of strings Unsigned::Impl::Impl(const string &n, int base) { d_num = strtoul(n.c_str(), NULL, base); FatalAssert(d_num != ULONG_MAX, "Unsigned::Impl(string): arithmetic overflow:" "n = "+n+", base="+int2string(base) +OVERFLOW_MSG); } //! Default constructor Unsigned::Unsigned() : d_n(new Impl) { } //! Copy constructor Unsigned::Unsigned(const Unsigned &n) : d_n(new Impl(*n.d_n)) { } //! Private constructor Unsigned::Unsigned(const Impl& t): d_n(new Impl(t)) { } Unsigned::Unsigned(unsigned n): d_n(new Impl((unsigned long)n)) { } Unsigned::Unsigned(int n): d_n(new Impl(n)) { } // Constructors from strings Unsigned::Unsigned(const char* n, int base) : d_n(new Impl(string(n), base)) { } Unsigned::Unsigned(const string& n, int base) : d_n(new Impl(n, base)) { } // Destructor Unsigned::~Unsigned() { delete d_n; } // Assignment Unsigned& Unsigned::operator=(const Unsigned& n) { if(this == &n) return *this; delete d_n; d_n = new Impl(*n.d_n); return *this; } ostream &operator<<(ostream &os, const Unsigned &n) { return(os << n.toString()); } Unsigned gcd(const Unsigned &x, const Unsigned &y) { return Unsigned(Unsigned::Impl(ugcd(x.d_n->getUnsigned(), y.d_n->getUnsigned()))); } Unsigned gcd(const vector &v) { unsigned long g(1); if(v.size() > 0) { g = v[0].d_n->getUnsigned(); } for(size_t i=1; igetUnsigned(); else if(v[i].d_n->getUnsigned() != 0) g = ugcd(g, v[i].d_n->getUnsigned()); } return Unsigned(Unsigned::Impl(g)); } Unsigned lcm(const Unsigned &x, const Unsigned &y) { unsigned long g; g = ulcm(x.d_n->getUnsigned(), y.d_n->getUnsigned()); return Unsigned(Unsigned::Impl(g)); } Unsigned lcm(const vector &v) { unsigned long g(1); for(size_t i=0; igetUnsigned() != 0) g = ulcm(g, v[i].d_n->getUnsigned()); } return Unsigned(Unsigned::Impl(g)); } Unsigned mod(const Unsigned &x, const Unsigned &y) { unsigned long r = x.d_n->getUnsigned() % y.d_n->getUnsigned(); return(Unsigned(Unsigned::Impl(r))); } Unsigned intRoot(const Unsigned& base, unsigned long int n) { double b = base.d_n->getUnsigned(); double root = n; root = 1/root; b = ::pow(b, root); unsigned long res = (unsigned long) ::floor(b); if (::pow((long double)res, (int)n) == base.d_n->getUnsigned()) { return Unsigned(Unsigned::Impl(res)); } return Unsigned(Unsigned::Impl((unsigned long)0)); } string Unsigned::toString(int base) const { return(d_n->toString(base)); } size_t Unsigned::hash() const { std::hash h; return h(toString().c_str()); } void Unsigned::print() const { cout << (*this) << endl; } Unsigned &Unsigned::operator+=(const Unsigned &n2) { *this = (*this) + n2; return *this; } Unsigned &Unsigned::operator-=(const Unsigned &n2) { *this = (*this) - n2; return *this; } Unsigned &Unsigned::operator*=(const Unsigned &n2) { *this = (*this) * n2; return *this; } Unsigned &Unsigned::operator/=(const Unsigned &n2) { *this = (*this) / n2; return *this; } unsigned long Unsigned::getUnsigned() const { return d_n->getUnsigned(); } bool operator==(const Unsigned &n1, const Unsigned &n2) { return(*n1.d_n == *n2.d_n); } bool operator<(const Unsigned &n1, const Unsigned &n2) { return(*n1.d_n < *n2.d_n); } bool operator<=(const Unsigned &n1, const Unsigned &n2) { return(*n1.d_n <= *n2.d_n); } bool operator>(const Unsigned &n1, const Unsigned &n2) { return(*n1.d_n > *n2.d_n); } bool operator>=(const Unsigned &n1, const Unsigned &n2) { return(*n1.d_n >= *n2.d_n); } bool operator!=(const Unsigned &n1, const Unsigned &n2) { return(*n1.d_n != *n2.d_n); } Unsigned operator+(const Unsigned &n1, const Unsigned &n2) { return Unsigned(Unsigned::Impl(*n1.d_n + *n2.d_n)); } Unsigned operator-(const Unsigned &n1, const Unsigned &n2) { return Unsigned(Unsigned::Impl((*n1.d_n) - (*n2.d_n))); } Unsigned operator*(const Unsigned &n1, const Unsigned &n2) { return Unsigned(Unsigned::Impl((*n1.d_n) * (*n2.d_n))); } Unsigned operator/(const Unsigned &n1, const Unsigned &n2) { return Unsigned(Unsigned::Impl(*n1.d_n / *n2.d_n)); } Unsigned operator%(const Unsigned &n1, const Unsigned &n2) { return Unsigned(Unsigned::Impl(*n1.d_n % *n2.d_n)); } Unsigned operator<<(const Unsigned& n1, unsigned n2) { return Unsigned(Unsigned::Impl(*n1.d_n << n2)); } Unsigned operator&(const Unsigned& n1, const Unsigned& n2) { return Unsigned(Unsigned::Impl(*n1.d_n & *n2.d_n)); } Unsigned Rational::getUnsignedMP() const { checkInt(*this, "getUnsignedMP()"); long int res = d_n->getNum(); FatalAssert(res >= 0 && res <= (long int)UINT_MAX, "Rational::getUnsignedMP(): arithmetic overflow on " + toString() + OVERFLOW_MSG); return Unsigned((unsigned int)res); } } /* close namespace */ #endif cvc3-2.4.1/src/util/debug.cpp0000664000175400017540000002512611267754362015637 0ustar mdetersmdeters/*****************************************************************************/ /*! * \file debug.cpp * \brief Description: Implementation of debugging facilities. * * Author: Sergey Berezin * * Created: Fri Jan 31 11:48:37 2003 * *
* * License to use, copy, modify, sell and/or distribute this software * and its documentation for any purpose is hereby granted without * royalty, subject to the terms and conditions defined in the \ref * LICENSE file provided with this distribution. * *
* */ /*****************************************************************************/ #include #include #include #include "debug.h" using namespace std; namespace CVC3 { // Function for fatal exit. It just exits with code 1, but is // provided here for the debugger to set a breakpoint to. For this // reason, it is not inlined. CVC_DLL void fatalError(const std::string& file, int line, const std::string& cond, const std::string& msg) { cerr << "\n**** Fatal error in " << file << ":" << line << " (" << cond << ")\n" << msg << endl << flush; exit(1); } } // end of namespace CVC3 #ifdef _CVC3_DEBUG_MODE #include #include namespace CVC3 { // Similar to fatalError to raise an exception when DebugAssert fires. // This does not necessarily cause the program to quit. CVC_DLL void debugError(const std::string& file, int line, const std::string& cond, const std::string& msg) { ostringstream ss; ss << "in " << file << ":" << line << " (" << cond << ")\n" << msg; throw DebugException(ss.str()); } class DebugTime { public: clock_t d_clock; // Constructors DebugTime() { d_clock = 0; } DebugTime(const clock_t& clock): d_clock(clock) { } // Set time to zero void reset() { d_clock = 0; } // Incremental assignments DebugTime& operator+=(const DebugTime& t) { d_clock += t.d_clock; return *this; } DebugTime& operator-=(const DebugTime& t) { d_clock -= t.d_clock; return *this; } friend bool operator==(const DebugTime& t1, const DebugTime& t2); friend bool operator!=(const DebugTime& t1, const DebugTime& t2); friend bool operator<(const DebugTime& t1, const DebugTime& t2); friend bool operator>(const DebugTime& t1, const DebugTime& t2); friend bool operator<=(const DebugTime& t1, const DebugTime& t2); friend bool operator>=(const DebugTime& t1, const DebugTime& t2); friend ostream& operator<<(ostream& os, const DebugTime& t); }; DebugTime operator+(const DebugTime& t1, const DebugTime& t2) { DebugTime res(t1); res += t2; return res; } DebugTime operator-(const DebugTime& t1, const DebugTime& t2) { DebugTime res(t1); res -= t2; return res; } bool operator==(const DebugTime& t1, const DebugTime& t2) { return t1.d_clock == t2.d_clock; } bool operator!=(const DebugTime& t1, const DebugTime& t2) { return !(t1 == t2); } bool operator<(const DebugTime& t1, const DebugTime& t2) { return t1.d_clock < t2.d_clock; } bool operator>(const DebugTime& t1, const DebugTime& t2) { return t1.d_clock > t2.d_clock; } bool operator<=(const DebugTime& t1, const DebugTime& t2) { return t1.d_clock <= t2.d_clock; } bool operator>=(const DebugTime& t1, const DebugTime& t2) { return t1.d_clock >= t2.d_clock; } //////////////////////////////////////////////////////////////////////// // Class DebugTimer //////////////////////////////////////////////////////////////////////// // Destructor DebugTimer::~DebugTimer() { if(d_clean_time) delete d_time; } void Debug::init(const std::vector >* traceOptions, const std::string* dumpName) { d_traceOptions = traceOptions; d_dumpName = dumpName; } void Debug::finalize() { d_traceOptions = NULL; d_dumpName = NULL; } DebugFlag Debug::traceFlag(const char* name) { return traceFlag(std::string(name)); } void Debug::traceAll(bool enable) { traceFlag("ALL") = enable; } // Copy constructor: copy the *pointer* from public timers, and // value from private. The reason is, when you modify a public // timer, you want the changes to show in the central database and // everywhere else, whereas private timers are used as independent // temporary variables holding intermediate time values. DebugTimer::DebugTimer(const DebugTimer& timer) { d_clean_time = timer.d_clean_time; if(d_clean_time) { // We are copying a private timer; make our own copy d_time = new DebugTime(*timer.d_time); d_clean_time = true; } else { // This is a public timer; just grab the pointer d_time = timer.d_time; } } // Assignment: same logistics as for the copy constructor, but need // to take care of our own pointer DebugTimer& DebugTimer::operator=(const DebugTimer& timer) { // Check for self-assignment if(&timer == this) return *this; if(timer.d_clean_time) { // We are copying a private timer if(d_clean_time) // We already have a private pointer, reuse it *d_time = *timer.d_time; else { // Create a new storage d_time = new DebugTime(*timer.d_time); d_clean_time = true; } } else { // This is a public timer if(d_clean_time) // We own our pointer, clean it up first delete d_time; d_time = timer.d_time; d_clean_time = false; } return *this; } void DebugTimer::reset() { d_time->reset(); } DebugTimer& DebugTimer::operator+=(const DebugTimer& timer) { (*d_time) += *(timer.d_time); return *this; } DebugTimer& DebugTimer::operator-=(const DebugTimer& timer) { (*d_time) -= *(timer.d_time); return *this; } // These will produce new "private" timers DebugTimer DebugTimer::operator+(const DebugTimer& timer) { return DebugTimer(new DebugTime((*d_time) + (*timer.d_time)), true /* take the new DebugTime */); } DebugTimer DebugTimer::operator-(const DebugTimer& timer) { return DebugTimer(new DebugTime((*d_time) - (*timer.d_time)), true /* take the new DebugTime */); } // Comparisons bool operator==(const DebugTimer& t1, const DebugTimer& t2) { return(*t1.d_time == *t2.d_time); } bool operator!=(const DebugTimer& t1, const DebugTimer& t2) { return(*t1.d_time != *t2.d_time); } bool operator<(const DebugTimer& t1, const DebugTimer& t2) { return *t1.d_time < *t2.d_time; } bool operator>(const DebugTimer& t1, const DebugTimer& t2) { return *t1.d_time > *t2.d_time; } bool operator<=(const DebugTimer& t1, const DebugTimer& t2) { return *t1.d_time <= *t2.d_time; } bool operator>=(const DebugTimer& t1, const DebugTimer& t2) { return *t1.d_time >= *t2.d_time; } // Print the time and timer's values ostream& operator<<(ostream& os, const DebugTime& t) { int seconds = (int)(t.d_clock / CLOCKS_PER_SEC); int milliseconds = 1000 * int((((double)(t.d_clock % CLOCKS_PER_SEC)) / CLOCKS_PER_SEC)); os << seconds << "." << setfill('0') << setw(6) << milliseconds; return os; } ostream& operator<<(ostream& os, const DebugTimer& timer) { return(os << *timer.d_time); } //////////////////////////////////////////////////////////////////////// // Class Debug //////////////////////////////////////////////////////////////////////// // Destructor: destroy all the pointers in d_timers Debug::~Debug() { TimerMap::iterator i, iend; for(i = d_timers.begin(), iend = d_timers.end(); i != iend; ++i) delete (*i).second; if(d_osDumpTrace != NULL) delete d_osDumpTrace; } bool Debug::trace(const string& name) { // First, check if this flag was set in the command line. Walk the // vector backwards, so that the last +/-trace takes effect. if(d_traceOptions != NULL) { vector >::const_reverse_iterator i, iend; for(i=d_traceOptions->rbegin(), iend=d_traceOptions->rend(); i!=iend; ++i) if((*i).first == name || (*i).first == "ALL") return (*i).second; } return traceFlag(name) || traceFlag("ALL"); } DebugTimer Debug::timer(const string& name) { // See if we already have the timer if(d_timers.count(name) > 0) return(DebugTimer(d_timers[name])); else { // Create a new timer DebugTime *t = new DebugTime(); d_timers[name] = t; return DebugTimer(t); } } DebugTimer Debug::newTimer() { return DebugTimer(new DebugTime(), true /* take the pointer */); } void Debug::setCurrentTime(DebugTimer& timer) { *timer.d_time = clock(); } // Set the timer to the difference between current time and the // time stored in the timer: timer = currentTime - timer. // Intended to obtain the time interval since the last call to // setCurrentTime() with that timer. void Debug::setElapsed(DebugTimer& timer) { *timer.d_time -= DebugTime(clock()); } /*! If the stream is not initialized, open the file * If the filename is empty or "-", then return * cout (but do not initialize the stream in this case). */ ostream& Debug::getOSDumpTrace() { if(d_osDumpTrace != NULL) return *d_osDumpTrace; // Check if the flag has a file name in it if(*d_dumpName == "" || *d_dumpName == "-") return cout; d_osDumpTrace = new ofstream(d_dumpName->c_str()); return *d_osDumpTrace; } // Print an entry to the dump-sat file: free-form message void Debug::dumpTrace(const std::string& title, const std::vector >& fields) { ostream& os = getOSDumpTrace(); os << "[" << title << "]\n"; for(size_t i=0, iend=fields.size(); i 0) { os << endl << "************ Flags *************" << endl << endl; for(FlagMap::iterator i = d_flags.begin(), iend = d_flags.end(); i != iend; ++i) os << (*i).first << " = " << (*i).second << endl; } if(d_counters.size() > 0) { os << endl << "*********** Counters ***********" << endl << endl; for(CounterMap::iterator i = d_counters.begin(), iend = d_counters.end(); i != iend; ++i) os << (*i).first << " = " << (*i).second << endl; } if(d_timers.size() > 0) { os << endl << "************ Timers ************" << endl << endl; for(TimerMap::iterator i = d_timers.begin(), iend = d_timers.end(); i != iend; ++i) os << (*i).first << " = " << *((*i).second) << endl; } os << endl << "********************************" << endl << "**** End of Debugging Info *****" << endl << "********************************" << endl; } // Global debugger. It must be initialized in main() through its // init() method. CVC_DLL Debug debugger; } // end of namespace CVC3 #endif cvc3-2.4.1/src/util/rational-gmp.cpp0000644000175400017540000006043511547077347017145 0ustar mdetersmdeters/*****************************************************************************/ /*! * \file rational-gmp.cpp * * \brief Implementation of class Rational using GMP library (C interface) * * Author: Sergey Berezin * * Created: Mon Aug 4 10:06:04 2003 * *
* License to use, copy, modify, sell and/or distribute this software * and its documentation for any purpose is hereby granted without * royalty, subject to the terms and conditions defined in the \ref * LICENSE file provided with this distribution. * *
* */ /*****************************************************************************/ #ifdef RATIONAL_GMP #include "compat_hash_set.h" #include "rational.h" #include #include #include #include namespace CVC3 { using namespace std; //! Implementation of the forward-declared internal class class Rational::Impl { mpq_t d_n; //! Make the rational number canonical void canonicalize() { mpq_canonicalize(d_n); } public: //! Default Constructor Impl() { mpq_init(d_n); } //! Copy constructor (assumes x is canonicalized) Impl(const Impl &x) { mpq_init(d_n); mpq_set(d_n, x.d_n); } //! Constructor from mpq_t Impl(mpq_t n) { mpq_init(d_n); mpq_set(d_n, n); canonicalize(); } //! Constructor from a pair of mpz_t (integers) Impl(mpz_t n, mpz_t d) { mpq_init(d_n); mpq_set_num(d_n, n); mpq_set_den(d_n, d); canonicalize(); } //! Constructor from a single mpz_t (integer) Impl(mpz_t n) { mpq_init(d_n); mpq_set_num(d_n, n); canonicalize(); } //! Constructor from a pair of integers Impl(long int n, long int d); //! Constructor from a pair of unsigned integers Impl(unsigned int n, unsigned int d, unsigned int /* dummy arg */); //! Constructor from a string Impl(const string &n, int base); //! Constructor from a pair of strings Impl(const string &n, const string& d, int base); // Destructor virtual ~Impl() { mpq_clear(d_n); } //! Assignment Impl& operator=(const Impl& x) { if(this == &x) return *this; mpq_set(d_n, x.d_n); return *this; } //! Get numerator Impl getNum() const { return Impl(mpq_numref(const_cast(this)->d_n)); } //! Get denominator Impl getDen() const { return Impl(mpq_denref(const_cast(this)->d_n)); } int getInt() const { // Check for overflow static Impl min((int)INT_MIN, 1), max((int)INT_MAX, 1); FatalAssert(isInteger() && min <= *this && *this <= max, "Rational::getInt(): Arithmetic overflow for " +toString()); return mpz_get_si(mpq_numref(d_n)); } unsigned int getUnsigned() const { // Check for overflow static Impl min(0, 1, 0), max(UINT_MAX, 1, 0); FatalAssert(min <= *this && *this <= max, "Rational::getUnsigned(): Arithmetic overflow for " +toString()); return mpz_get_ui(mpq_numref(d_n)); } Unsigned getUnsignedMP() const; //! Unary minus Impl operator-() const; //! Get the floor Impl floor() const; //! Get the ceiling Impl ceil() const; //! Testing whether the denominator is 1 bool isInteger() const; //! Equality friend bool operator==(const Impl& x, const Impl& y) { return mpq_equal(x.d_n, y.d_n); } //! Dis-equality friend bool operator!=(const Impl& x, const Impl& y) { return !mpq_equal(x.d_n, y.d_n); } //! Less than friend bool operator<(const Impl& x, const Impl& y) { return mpq_cmp(x.d_n, y.d_n) < 0; } friend bool operator<=(const Impl& x, const Impl& y) { return mpq_cmp(x.d_n, y.d_n) <= 0; } friend bool operator>(const Impl& x, const Impl& y) { return mpq_cmp(x.d_n, y.d_n) > 0; } friend bool operator>=(const Impl& x, const Impl& y) { return mpq_cmp(x.d_n, y.d_n) >= 0; } //! Addition friend Impl operator+(const Impl& x, const Impl& y) { Impl res; mpq_add(res.d_n, x.d_n, y.d_n); return res; } //! Subtraction friend Impl operator-(const Impl& x, const Impl& y) { Impl res; mpq_sub(res.d_n, x.d_n, y.d_n); return res; } //! Multiplication friend Impl operator*(const Impl& x, const Impl& y) { Impl res; mpq_mul(res.d_n, x.d_n, y.d_n); return res; } //! Division friend Impl operator/(const Impl& x, const Impl& y) { Impl res; mpq_div(res.d_n, x.d_n, y.d_n); return res; } friend Impl operator%(const Impl& x, const Impl& y) { DebugAssert(x.isInteger() && y.isInteger(), "Impl % Impl: x and y must be integers"); mpz_t res; mpz_init(res); // Put the remainder directly into 'res' mpz_fdiv_r(res, mpq_numref(x.d_n), mpq_numref(y.d_n)); Impl r(res); mpz_clear(res); return r; } //! Compute the remainder of x/y friend Impl mod(const Impl& x, const Impl& y) { DebugAssert(x.isInteger() && y.isInteger(), "Rational::Impl::mod(): x="+x.toString() +", y="+y.toString()); mpz_t res; mpz_init(res); mpz_mod(res, mpq_numref(x.d_n), mpq_numref(y.d_n)); Impl r(res); mpz_clear(res); return r; } friend Impl intRoot(const Impl& x, unsigned long int y) { DebugAssert(x.isInteger(), "Rational::Impl::intRoot(): x="+x.toString()); mpz_t res; mpz_init(res); int exact = mpz_root(res, mpq_numref(x.d_n), y); if (!exact) { mpz_set_ui(res, 0); } Impl r(res); mpz_clear(res); return r; } friend Impl gcd(const Impl& x, const Impl& y) { DebugAssert(x.isInteger() && y.isInteger(), "Rational::Impl::gcd(): x="+x.toString() +", y="+y.toString()); TRACE("rational", "Impl::gcd(", x, ", "+y.toString()+") {"); mpz_t res; mpz_init(res); mpz_gcd(res, mpq_numref(x.d_n), mpq_numref(y.d_n)); Impl r(res); mpz_clear(res); TRACE("rational", "Impl::gcd => ", r, "}"); return r; } friend Impl lcm(const Impl& x, const Impl& y) { DebugAssert(x.isInteger() && y.isInteger(), "Rational::Impl::lcm(): x="+x.toString() +", y="+y.toString()); mpz_t res; mpz_init(res); mpz_lcm(res, mpq_numref(x.d_n), mpq_numref(y.d_n)); Impl r(res); mpz_clear(res); return r; } //! Print to string string toString(int base = 10) const { char* str = (char*)malloc(mpz_sizeinbase(mpq_numref(d_n), base) +mpz_sizeinbase(mpq_denref(d_n), base)+3); mpq_get_str(str, base, d_n); string res(str); free(str); return res; } }; // Constructor from a pair of integers Rational::Impl::Impl(long int n, long int d) { mpq_init(d_n); DebugAssert(d > 0, "Rational::Impl(long n, long d): d = "+int2string(d)); mpq_set_si(d_n, n, (unsigned long int)d); canonicalize(); } // Constructor from a pair of unsigned integers Rational::Impl::Impl(unsigned int n, unsigned int d, unsigned int /* dummy arg, to disambiguate */) { mpq_init(d_n); mpq_set_ui(d_n, n, (unsigned long int)d); canonicalize(); } // Constructor from a string Rational::Impl::Impl(const string &n, int base) { mpq_init(d_n); mpq_set_str(d_n, n.c_str(), base); canonicalize(); } // Constructor from a pair of strings Rational::Impl::Impl(const string &n, const string& d, int base) { mpq_init(d_n); mpq_set_str(d_n, (n+"/"+d).c_str(), base); canonicalize(); } Rational::Impl Rational::Impl::operator-() const { Impl res; mpq_neg(res.d_n, d_n); return res; } Rational::Impl Rational::Impl::floor() const { mpz_t res; mpz_init(res); mpz_fdiv_q(res, mpq_numref(d_n), mpq_denref(d_n)); Impl r(res); mpz_clear(res); return r; } Rational::Impl Rational::Impl::ceil() const { mpz_t res; mpz_init(res); mpz_cdiv_q(res, mpq_numref(d_n), mpq_denref(d_n)); Impl r(res); mpz_clear(res); return r; } bool Rational::Impl::isInteger() const { bool res(mpz_cmp_ui(mpq_denref(d_n), 1) == 0); TRACE("rational", "Impl::isInteger(", *this, ") => "+string(res? "true" : "false")); return res; } //! Default constructor Rational::Rational() : d_n(new Impl) { #ifdef _DEBUG_RATIONAL_ int &num_created = getCreated(); num_created++; printStats(); #endif } //! Copy constructor Rational::Rational(const Rational &n) : d_n(new Impl(*n.d_n)) { #ifdef _DEBUG_RATIONAL_ int &num_created = getCreated(); num_created++; printStats(); #endif } Rational::Rational(const Unsigned& n): d_n(new Impl(n.toString(), 10)) { #ifdef _DEBUG_RATIONAL_ int &num_created = getCreated(); num_created++; printStats(); #endif } //! Private constructor Rational::Rational(const Impl& t): d_n(new Impl(t)) { #ifdef _DEBUG_RATIONAL_ int &num_created = getCreated(); num_created++; printStats(); #endif } Rational::Rational(int n, int d): d_n(new Impl(n, d)) { #ifdef _DEBUG_RATIONAL_ int &num_created = getCreated(); num_created++; printStats(); #endif } // Constructors from strings Rational::Rational(const char* n, int base) : d_n(new Impl(string(n), base)) { #ifdef _DEBUG_RATIONAL_ int &num_created = getCreated(); num_created++; printStats(); #endif } Rational::Rational(const string& n, int base) : d_n(new Impl(n, base)) { #ifdef _DEBUG_RATIONAL_ int &num_created = getCreated(); num_created++; printStats(); #endif } Rational::Rational(const char* n, const char* d, int base) : d_n(new Impl(string(n), string(d), base)) { #ifdef _DEBUG_RATIONAL_ int &num_created = getCreated(); num_created++; printStats(); #endif } Rational::Rational(const string& n, const string& d, int base) : d_n(new Impl(n, d, base)) { #ifdef _DEBUG_RATIONAL_ int &num_created = getCreated(); num_created++; printStats(); #endif } // Destructor Rational::~Rational() { #ifdef _DEBUG_RATIONAL_ int &num_deleted = getDeleted(); num_deleted++; printStats(); #endif delete d_n; } // Get components Rational Rational::getNumerator() const { return Rational(d_n->getNum()); } Rational Rational::getDenominator() const { return Rational(d_n->getDen()); } bool Rational::isInteger() const { return d_n->isInteger(); } // Assignment Rational& Rational::operator=(const Rational& n) { if(this == &n) return *this; delete d_n; d_n = new Impl(*n.d_n); return *this; } ostream &operator<<(ostream &os, const Rational &n) { return(os << n.toString()); } //! Printing to ostream std::ostream& operator<<(std::ostream& os, const Rational::Impl& n) { return os << n.toString(); } // Check that argument is an int and print an error message otherwise static void checkInt(const Rational& n, const string& funName) { TRACE("rational", "checkInt(", n, ")"); DebugAssert(n.isInteger(), "CVC3::Rational::" + funName + ": argument is not an integer: " + n.toString()); } /* Computes gcd and lcm on *integer* values. Result is always a positive integer. In this implementation, it is guaranteed by GMP. */ Rational gcd(const Rational &x, const Rational &y) { checkInt(x, "gcd(*x*,y)"); checkInt(y, "gcd(x,*y*)"); return Rational(gcd(*x.d_n, *y.d_n)); } Rational gcd(const vector &v) { Rational::Impl g(1,1), zero; if(v.size() > 0) { checkInt(v[0], "gcd(vector[0])"); g = *v[0].d_n; } for(size_t i=1; i)"); if(g == zero) g = *(v[i].d_n); else if(*(v[i].d_n) != zero) g = gcd(g, *(v[i].d_n)); } return Rational(g); } Rational lcm(const Rational &x, const Rational &y) { checkInt(x, "lcm(*x*,y)"); checkInt(y, "lcm(x,*y*)"); return Rational(lcm(*x.d_n, *y.d_n)); } Rational lcm(const vector &v) { Rational::Impl g(1,1), zero; for(size_t i=0; i)"); if(*v[i].d_n != zero) g = lcm(g, *v[i].d_n); } return Rational(g); } Rational abs(const Rational &x) { if(x<0) return -x; return x; } Rational floor(const Rational &x) { return Rational(x.d_n->floor()); } Rational ceil(const Rational &x) { return Rational(x.d_n->ceil()); } Rational mod(const Rational &x, const Rational &y) { checkInt(x, "mod(*x*,y)"); checkInt(y, "mod(x,*y*)"); return(Rational(mod(*x.d_n, *y.d_n))); } Rational intRoot(const Rational& base, unsigned long int n) { checkInt(base, "intRoot(*x*,y)"); return Rational(intRoot(*base.d_n, n)); } string Rational::toString(int base) const { return(d_n->toString(base)); } size_t Rational::hash() const { std::hash h; return h(toString().c_str()); } void Rational::print() const { cout << (*this) << endl; } // Unary minus Rational Rational::operator-() const { return Rational(-(*d_n)); } Rational &Rational::operator+=(const Rational &n2) { *this = (*this) + n2; return *this; } Rational &Rational::operator-=(const Rational &n2) { *this = (*this) - n2; return *this; } Rational &Rational::operator*=(const Rational &n2) { *this = (*this) * n2; return *this; } Rational &Rational::operator/=(const Rational &n2) { *this = (*this) / n2; return *this; } int Rational::getInt() const { checkInt(*this, "getInt()"); return d_n->getInt(); } unsigned int Rational::getUnsigned() const { checkInt(*this, "getUnsigned()"); return d_n->getUnsigned(); } Unsigned Rational::getUnsignedMP() const { checkInt(*this, "getUnsignedMP()"); return d_n->getUnsignedMP(); } #ifdef _DEBUG_RATIONAL_ void Rational::printStats() { int &num_created = getCreated(); int &num_deleted = getDeleted(); if(num_created % 1000 == 0 || num_deleted % 1000 == 0) { std::cerr << "Rational(" << *d_n << "): created " << num_created << ", deleted " << num_deleted << ", currently alive " << num_created-num_deleted << std::endl; } } #endif bool operator==(const Rational &n1, const Rational &n2) { return(*n1.d_n == *n2.d_n); } bool operator<(const Rational &n1, const Rational &n2) { return(*n1.d_n < *n2.d_n); } bool operator<=(const Rational &n1, const Rational &n2) { return(*n1.d_n <= *n2.d_n); } bool operator>(const Rational &n1, const Rational &n2) { return(*n1.d_n > *n2.d_n); } bool operator>=(const Rational &n1, const Rational &n2) { return(*n1.d_n >= *n2.d_n); } bool operator!=(const Rational &n1, const Rational &n2) { return(*n1.d_n != *n2.d_n); } Rational operator+(const Rational &n1, const Rational &n2) { return Rational((*n1.d_n) + (*n2.d_n)); } Rational operator-(const Rational &n1, const Rational &n2) { return Rational((*n1.d_n) - (*n2.d_n)); } Rational operator*(const Rational &n1, const Rational &n2) { return Rational((*n1.d_n) * (*n2.d_n)); } Rational operator/(const Rational &n1, const Rational &n2) { return Rational((*n1.d_n) / (*n2.d_n)); } Rational operator%(const Rational &n1, const Rational &n2) { return Rational((*n1.d_n) % (*n2.d_n)); } //! Implementation of the forward-declared internal class class Unsigned::Impl { mpz_t d_n; public: //! Default Constructor Impl() { mpz_init(d_n); } //! Copy constructor (assumes x is canonicalized) Impl(const Impl &x) { mpz_init(d_n); mpz_set(d_n, x.d_n); } //! Constructor from mpz_t Impl(const mpz_t n) { mpz_init(d_n); mpz_set(d_n, n); } //! Constructor from an unsigned integer Impl(unsigned int n); //! Constructor from a string Impl(const string &n, int base); // Destructor virtual ~Impl() { mpz_clear(d_n); } //! Assignment Impl& operator=(const Impl& x) { if(this == &x) return *this; mpz_set(d_n, x.d_n); return *this; } int getInt() const { // Check for overflow static Impl max((int)INT_MAX); FatalAssert(*this <= max, "Unsigned::getInt(): Arithmetic overflow for " +toString()); return mpz_get_si(d_n); } unsigned long getUnsigned() const { // Check for overflow static Impl max(UINT_MAX); FatalAssert(*this <= max, "Unsigned::getUnsigned(): Arithmetic overflow for " +toString()); return mpz_get_ui(d_n); } //! Unary minus Impl operator-() const; //! Equality friend bool operator==(const Impl& x, const Impl& y) { return mpz_cmp(x.d_n, y.d_n) == 0; } //! Dis-equality friend bool operator!=(const Impl& x, const Impl& y) { return mpz_cmp(x.d_n, y.d_n) != 0; } //! Less than friend bool operator<(const Impl& x, const Impl& y) { return mpz_cmp(x.d_n, y.d_n) < 0; } friend bool operator<=(const Impl& x, const Impl& y) { return mpz_cmp(x.d_n, y.d_n) <= 0; } friend bool operator>(const Impl& x, const Impl& y) { return mpz_cmp(x.d_n, y.d_n) > 0; } friend bool operator>=(const Impl& x, const Impl& y) { return mpz_cmp(x.d_n, y.d_n) >= 0; } //! Addition friend Impl operator+(const Impl& x, const Impl& y) { Impl res; mpz_add(res.d_n, x.d_n, y.d_n); return res; } //! Subtraction friend Impl operator-(const Impl& x, const Impl& y) { Impl res; mpz_sub(res.d_n, x.d_n, y.d_n); return res; } //! Multiplication friend Impl operator*(const Impl& x, const Impl& y) { Impl res; mpz_mul(res.d_n, x.d_n, y.d_n); return res; } //! Division friend Impl operator/(const Impl& x, const Impl& y) { Impl res; mpz_div(res.d_n, x.d_n, y.d_n); return res; } friend Impl operator%(const Impl& x, const Impl& y) { mpz_t res; mpz_init(res); // Put the remainder directly into 'res' mpz_fdiv_r(res, x.d_n, y.d_n); Impl r(res); mpz_clear(res); return r; } friend Impl operator<<(const Impl& x, unsigned y) { mpz_t res; mpz_init(res); mpz_mul_2exp (res, x.d_n, y); Impl r(res); mpz_clear(res); return r; } friend Impl operator&(const Impl& x, const Impl& y) { mpz_t res; mpz_init(res); mpz_and (res, x.d_n, y.d_n); Impl r(res); mpz_clear(res); return r; } //! Compute the remainder of x/y friend Impl mod(const Impl& x, const Impl& y) { mpz_t res; mpz_init(res); mpz_mod(res, x.d_n, y.d_n); Impl r(res); mpz_clear(res); return r; } friend Impl intRoot(const Impl& x, unsigned long int y) { mpz_t res; mpz_init(res); int exact = mpz_root(res, x.d_n, y); if (!exact) { mpz_set_ui(res, 0); } Impl r(res); mpz_clear(res); return r; } friend Impl gcd(const Impl& x, const Impl& y) { mpz_t res; mpz_init(res); mpz_gcd(res, x.d_n, y.d_n); Impl r(res); mpz_clear(res); return r; } friend Impl lcm(const Impl& x, const Impl& y) { mpz_t res; mpz_init(res); mpz_lcm(res, x.d_n, y.d_n); Impl r(res); mpz_clear(res); return r; } //! Print to string string toString(int base = 10) const { char* str = (char*)malloc(mpz_sizeinbase(d_n, base)+2); mpz_get_str(str, base, d_n); string res(str); free(str); return res; } //! Printing to ostream friend ostream& operator<<(ostream& os, const Unsigned::Impl& n) { return os << n.toString(); } }; // Constructor from a pair of unsigned integers Unsigned::Impl::Impl(unsigned int n) { mpz_init(d_n); mpz_set_ui(d_n, n); } // Constructor from a string Unsigned::Impl::Impl(const string &n, int base) { mpz_init(d_n); mpz_set_str(d_n, n.c_str(), base); } Unsigned::Impl Unsigned::Impl::operator-() const { Impl res; mpz_neg(res.d_n, d_n); return res; } //! Default constructor Unsigned::Unsigned() : d_n(new Impl) { } //! Copy constructor Unsigned::Unsigned(const Unsigned &n) : d_n(new Impl(*n.d_n)) { } Unsigned::Unsigned(int n) : d_n(new Impl((unsigned)n)) { } Unsigned::Unsigned(unsigned n) : d_n(new Impl(n)) { } //! Private constructor Unsigned::Unsigned(const Impl& t): d_n(new Impl(t)) { } // Constructors from strings Unsigned::Unsigned(const char* n, int base) : d_n(new Impl(string(n), base)) { } Unsigned::Unsigned(const string& n, int base) : d_n(new Impl(n, base)) { } // Destructor Unsigned::~Unsigned() { delete d_n; } // Assignment Unsigned& Unsigned::operator=(const Unsigned& n) { if(this == &n) return *this; delete d_n; d_n = new Impl(*n.d_n); return *this; } ostream &operator<<(ostream &os, const Unsigned &n) { return(os << n.toString()); } // Check that argument is an int and print an error message otherwise /* Computes gcd and lcm on *integer* values. Result is always a positive integer. In this implementation, it is guaranteed by GMP. */ Unsigned gcd(const Unsigned &x, const Unsigned &y) { return Unsigned(gcd(*x.d_n, *y.d_n)); } Unsigned gcd(const vector &v) { Unsigned::Impl g(1), zero; if(v.size() > 0) { g = *v[0].d_n; } for(size_t i=1; i &v) { Unsigned::Impl g(1), zero; for(size_t i=0; itoString(base)); } size_t Unsigned::hash() const { std::hash h; return h(toString().c_str()); } void Unsigned::print() const { cout << (*this) << endl; } Unsigned &Unsigned::operator+=(const Unsigned &n2) { *this = (*this) + n2; return *this; } Unsigned &Unsigned::operator-=(const Unsigned &n2) { *this = (*this) - n2; return *this; } Unsigned &Unsigned::operator*=(const Unsigned &n2) { *this = (*this) * n2; return *this; } Unsigned &Unsigned::operator/=(const Unsigned &n2) { *this = (*this) / n2; return *this; } unsigned long Unsigned::getUnsigned() const { return d_n->getUnsigned(); } bool operator==(const Unsigned &n1, const Unsigned &n2) { return(*n1.d_n == *n2.d_n); } bool operator<(const Unsigned &n1, const Unsigned &n2) { return(*n1.d_n < *n2.d_n); } bool operator<=(const Unsigned &n1, const Unsigned &n2) { return(*n1.d_n <= *n2.d_n); } bool operator>(const Unsigned &n1, const Unsigned &n2) { return(*n1.d_n > *n2.d_n); } bool operator>=(const Unsigned &n1, const Unsigned &n2) { return(*n1.d_n >= *n2.d_n); } bool operator!=(const Unsigned &n1, const Unsigned &n2) { return(*n1.d_n != *n2.d_n); } Unsigned operator+(const Unsigned &n1, const Unsigned &n2) { return Unsigned((*n1.d_n) + (*n2.d_n)); } Unsigned operator-(const Unsigned &n1, const Unsigned &n2) { return Unsigned((*n1.d_n) - (*n2.d_n)); } Unsigned operator*(const Unsigned &n1, const Unsigned &n2) { return Unsigned((*n1.d_n) * (*n2.d_n)); } Unsigned operator/(const Unsigned &n1, const Unsigned &n2) { return Unsigned((*n1.d_n) / (*n2.d_n)); } Unsigned operator%(const Unsigned &n1, const Unsigned &n2) { return Unsigned((*n1.d_n) % (*n2.d_n)); } Unsigned operator<<(const Unsigned &n1, unsigned n2) { return Unsigned((*n1.d_n) << n2); } Unsigned operator&(const Unsigned &n1, const Unsigned &n2) { return Unsigned((*n1.d_n) & (*n2.d_n)); } Unsigned Rational::Impl::getUnsignedMP() const { return Unsigned(Unsigned::Impl(mpq_numref(d_n))); } } /* close namespace */ #endif cvc3-2.4.1/src/util/rational.cpp0000664000175400017540000003435011360164531016344 0ustar mdetersmdeters/*****************************************************************************/ /*! * \file rational.cpp * * Author: Sergey Berezin * * Created: Dec 12 22:00:18 GMT 2002 * *
* * License to use, copy, modify, sell and/or distribute this software * and its documentation for any purpose is hereby granted without * royalty, subject to the terms and conditions defined in the \ref * LICENSE file provided with this distribution. * *
* */ /*****************************************************************************/ // Class: Rational // Author: Sergey Berezin, 12/12/2002 (adapted from Bignum) // // Description: Implementation of class Rational. See comments in // rational.h file. /////////////////////////////////////////////////////////////////////////////// #ifdef RATIONAL_GMPXX #include #include "compat_hash_set.h" #include "rational.h" namespace CVC3 { using namespace std; // Implementation of the forward-declared internal class class Rational::Impl : public mpq_class { public: // mpz_class _n; // Constructors Impl() : mpq_class() { } // Constructor from integer // Impl(const mpz_class &x) : mpq_class(x) { } // Constructor from rational Impl(const mpq_class &x) : mpq_class(x) { } // Copy constructor Impl(const Impl &x) : mpq_class(x) { } // From pair of integers / strings Impl(int n, int d) : mpq_class(n,d) { canonicalize(); } Impl(const mpz_class& n, const mpz_class& d) : mpq_class(n,d) { canonicalize(); } // From string(s) Impl(const string &n, int base): mpq_class(n, base) { canonicalize(); } Impl(const string &n, const string& d, int base) : mpq_class(n + "/" + d, base) { canonicalize(); } // Destructor virtual ~Impl() { } // Getting numerator and denominator. DON NOT ASSIGN to the result mpz_class getNum() { return get_num(); } mpz_class getDen() { return get_den(); } }; // Constructors Rational::Rational() : d_n(new Impl) { #ifdef _DEBUG_RATIONAL_ int &num_created = getCreated(); num_created++; printStats(); #endif } // Copy constructor Rational::Rational(const Rational &n) : d_n(new Impl(*n.d_n)) { #ifdef _DEBUG_RATIONAL_ int &num_created = getCreated(); num_created++; printStats(); #endif } // Private constructor Rational::Rational(const Impl& t): d_n(new Impl(t)) { #ifdef _DEBUG_RATIONAL_ int &num_created = getCreated(); num_created++; printStats(); #endif } Rational::Rational(int n, int d): d_n(new Impl(n, d)) { #ifdef _DEBUG_RATIONAL_ int &num_created = getCreated(); num_created++; printStats(); #endif } // Constructors from strings Rational::Rational(const char* n, int base) : d_n(new Impl(string(n), base)) { #ifdef _DEBUG_RATIONAL_ int &num_created = getCreated(); num_created++; printStats(); #endif } Rational::Rational(const string& n, int base) : d_n(new Impl(n, base)) { #ifdef _DEBUG_RATIONAL_ int &num_created = getCreated(); num_created++; printStats(); #endif } Rational::Rational(const char* n, const char* d, int base) : d_n(new Impl(string(n), string(d), base)) { #ifdef _DEBUG_RATIONAL_ int &num_created = getCreated(); num_created++; printStats(); #endif } Rational::Rational(const string& n, const string& d, int base) : d_n(new Impl(n, d, base)) { #ifdef _DEBUG_RATIONAL_ int &num_created = getCreated(); num_created++; printStats(); #endif } // Destructor Rational::~Rational() { delete d_n; #ifdef _DEBUG_RATIONAL_ int &num_deleted = getDeleted(); num_deleted++; printStats(); #endif } // Get components Rational Rational::getNumerator() const { return Rational(Impl(d_n->getNum(), 1)); } Rational Rational::getDenominator() const { return Rational(Impl(d_n->getDen(), 1)); } bool Rational::isInteger() const { return 1 == d_n->getDen(); } // Assignment Rational& Rational::operator=(const Rational& n) { if(this == &n) return *this; delete d_n; d_n = new Impl(*n.d_n); return *this; } ostream &operator<<(ostream &os, const Rational &n) { return(os << n.toString()); } // Check that argument is an int and print an error message otherwise static void checkInt(const Rational& n, const string& funName) { DebugAssert(n.isInteger(), ("CVC3::Rational::" + funName + ": argument is not an integer: " + n.toString()).c_str()); } /* Computes gcd and lcm on *integer* values. Result is always a positive integer. In this implementation, it is guaranteed by GMP. */ Rational gcd(const Rational &x, const Rational &y) { mpz_class g; checkInt(x, "gcd(*x*,y)"); checkInt(y, "gcd(x,*y*)"); mpz_gcd(g.get_mpz_t(), x.d_n->get_num_mpz_t(), y.d_n->get_num_mpz_t()); return Rational(Rational::Impl(g,1)); } Rational gcd(const vector &v) { mpz_class g(1); if(v.size() > 0) { checkInt(v[0], "gcd(vector[0])"); g = v[0].d_n->getNum(); } for(unsigned i=1; i)"); if(*v[i].d_n != 0) mpz_gcd(g.get_mpz_t(), g.get_mpz_t(), v[i].d_n->get_num_mpz_t()); } return Rational(Rational::Impl(g,1)); } Rational lcm(const Rational &x, const Rational &y) { mpz_class g; checkInt(x, "lcm(*x*,y)"); checkInt(y, "lcm(x,*y*)"); mpz_lcm(g.get_mpz_t(), x.d_n->get_num_mpz_t(), y.d_n->get_num_mpz_t()); return Rational(Rational::Impl(g, 1)); } Rational lcm(const vector &v) { mpz_class g(1); for(unsigned i=0; i)"); if(*v[i].d_n != 0) mpz_lcm(g.get_mpz_t(), g.get_mpz_t(), v[i].d_n->get_num_mpz_t()); } return Rational(Rational::Impl(g,1)); } Rational abs(const Rational &x) { return Rational(Rational::Impl(abs(*x.d_n))); } Rational floor(const Rational &x) { mpz_class q; mpz_fdiv_q(q.get_mpz_t(), x.d_n->get_num_mpz_t(), x.d_n->get_den_mpz_t()); return Rational(Rational::Impl(q,1)); } Rational ceil(const Rational &x) { mpz_class q; mpz_cdiv_q(q.get_mpz_t(), x.d_n->get_num_mpz_t(), x.d_n->get_den_mpz_t()); return Rational(Rational::Impl(q,1)); } Rational mod(const Rational &x, const Rational &y) { checkInt(x, "mod(*x*,y)"); checkInt(y, "mod(x,*y*)"); mpz_class r; mpz_mod(r.get_mpz_t(), x.d_n->get_num_mpz_t(), y.d_n->get_num_mpz_t()); return(Rational(Rational::Impl(r,1))); } Rational intRoot(const Rational& base, unsigned long int n) { return Rational(Rational::Impl(0,1)); } string Rational::toString(int base) const { char *tmp = mpq_get_str(NULL, base, d_n->get_mpq_t()); string res(tmp); // delete tmp; free(tmp); return(res); } size_t Rational::hash() const { std::hash h; return h(toString().c_str()); } void Rational::print() const { cout << (*d_n) << endl; } // Unary minus Rational Rational::operator-() const { return Rational(Rational::Impl(- (*d_n))); } Rational &Rational::operator+=(const Rational &n2) { *d_n += (*n2.d_n); return *this; } Rational &Rational::operator-=(const Rational &n2) { *d_n -= (*n2.d_n); return *this; } Rational &Rational::operator*=(const Rational &n2) { *d_n *= (*n2.d_n); return *this; } Rational &Rational::operator/=(const Rational &n2) { *d_n /= (*n2.d_n); return *this; } int Rational::getInt() const { checkInt(*this, "getInt()"); return mpz_get_si(d_n->get_num_mpz_t()); } unsigned int Rational::getUnsigned() const { checkInt(*this, "getUnsigned()"); return mpz_get_ui(d_n->get_num_mpz_t()); } #ifdef _DEBUG_RATIONAL_ void Rational::printStats() { int &num_created = getCreated(); int &num_deleted = getDeleted(); if(num_created % 1000 == 0 || num_deleted % 1000 == 0) { std::cerr << "Rational(" << *d_n << "): created " << num_created << ", deleted " << num_deleted << ", currently alive " << num_created-num_deleted << std::endl; } } #endif bool operator==(const Rational &n1, const Rational &n2) { return(*n1.d_n == *n2.d_n); } bool operator<(const Rational &n1, const Rational &n2) { return(*n1.d_n < *n2.d_n); } bool operator<=(const Rational &n1, const Rational &n2) { return(*n1.d_n <= *n2.d_n); } bool operator>(const Rational &n1, const Rational &n2) { return(*n1.d_n > *n2.d_n); } bool operator>=(const Rational &n1, const Rational &n2) { return(*n1.d_n >= *n2.d_n); } bool operator!=(const Rational &n1, const Rational &n2) { return(*n1.d_n != *n2.d_n); } Rational operator+(const Rational &n1, const Rational &n2) { return Rational(Rational::Impl(*n1.d_n + *n2.d_n)); } Rational operator-(const Rational &n1, const Rational &n2) { return Rational(Rational::Impl((*n1.d_n) - (*n2.d_n))); } Rational operator*(const Rational &n1, const Rational &n2) { return Rational(Rational::Impl((*n1.d_n) * (*n2.d_n))); } Rational operator/(const Rational &n1, const Rational &n2) { return Rational(Rational::Impl(*n1.d_n / *n2.d_n)); } Rational operator%(const Rational &n1, const Rational &n2) { return Rational(Rational::Impl(*n1.d_n + *n2.d_n)); } // Implementation of the forward-declared internal class class Unsigned::Impl : public mpz_class { public: // mpz_class _n; // Constructors Impl() : mpz_class() { } // Constructor from integer // Impl(const mpz_class &x) : mpq_class(x) { } // Constructor from rational Impl(const mpz_class &x) : mpz_class(x) { } // Copy constructor Impl(const Impl &x) : mpz_class(x) { } // From pair of integers / strings Impl(int n) : mpz_class(n) { } Impl(const mpz_class& n, const mpz_class& d) : mpq_class(n,d) { canonicalize(); } // From string(s) Impl(const string &n, int base): mpz_class(n, base) { } // Destructor virtual ~Impl() { } }; // Constructors Unsigned::Unsigned() : d_n(new Impl) { } // Copy constructor Unsigned::Unsigned(const Unsigned &n) : d_n(new Impl(*n.d_n)) { } // Private constructor Unsigned::Unsigned(const Impl& t): d_n(new Impl(t)) { } // Constructors from strings Unsigned::Unsigned(const char* n, int base) : d_n(new Impl(string(n), base)) { } Unsigned::Unsigned(const string& n, int base) : d_n(new Impl(n, base)) { } // Destructor Unsigned::~Unsigned() { delete d_n; } // Assignment Unsigned& Unsigned::operator=(const Unsigned& n) { if(this == &n) return *this; delete d_n; d_n = new Impl(*n.d_n); return *this; } ostream &operator<<(ostream &os, const Unsigned &n) { return(os << n.toString()); } /* Computes gcd and lcm on *integer* values. Result is always a positive integer. In this implementation, it is guaranteed by GMP. */ Unsigned gcd(const Unsigned &x, const Unsigned &y) { mpz_class g; mpz_gcd(g, *(x.d_n), *(y.d_n)); return Unsigned(Unsigned::Impl(g)); } Unsigned gcd(const vector &v) { mpz_class g(1); if(v.size() > 0) { g = *(v[0].d_n); } for(unsigned i=1; i &v) { mpz_class g(1); for(unsigned i=0; i h; return h(toString().c_str()); } void Unsigned::print() const { cout << (*d_n) << endl; } // Unary minus Unsigned Unsigned::operator-() const { return Unsigned(Unsigned::Impl(- (*d_n))); } Unsigned &Unsigned::operator+=(const Unsigned &n2) { *d_n += (*n2.d_n); return *this; } Unsigned &Unsigned::operator-=(const Unsigned &n2) { *d_n -= (*n2.d_n); return *this; } Unsigned &Unsigned::operator*=(const Unsigned &n2) { *d_n *= (*n2.d_n); return *this; } Unsigned &Unsigned::operator/=(const Unsigned &n2) { *d_n /= (*n2.d_n); return *this; } int Unsigned::getInt() const { return mpz_get_si(*d_n); } unsigned int Unsigned::getUnsigned() const { return mpz_get_ui(*d_n); } bool operator==(const Unsigned &n1, const Unsigned &n2) { return(*n1.d_n == *n2.d_n); } bool operator<(const Unsigned &n1, const Unsigned &n2) { return(*n1.d_n < *n2.d_n); } bool operator<=(const Unsigned &n1, const Unsigned &n2) { return(*n1.d_n <= *n2.d_n); } bool operator>(const Unsigned &n1, const Unsigned &n2) { return(*n1.d_n > *n2.d_n); } bool operator>=(const Unsigned &n1, const Unsigned &n2) { return(*n1.d_n >= *n2.d_n); } bool operator!=(const Unsigned &n1, const Unsigned &n2) { return(*n1.d_n != *n2.d_n); } Unsigned operator+(const Unsigned &n1, const Unsigned &n2) { return Unsigned(Unsigned::Impl(*n1.d_n + *n2.d_n)); } Unsigned operator-(const Unsigned &n1, const Unsigned &n2) { return Unsigned(Unsigned::Impl((*n1.d_n) - (*n2.d_n))); } Unsigned operator*(const Unsigned &n1, const Unsigned &n2) { return Unsigned(Unsigned::Impl((*n1.d_n) * (*n2.d_n))); } Unsigned operator/(const Unsigned &n1, const Unsigned &n2) { return Unsigned(Unsigned::Impl(*n1.d_n / *n2.d_n)); } Unsigned operator%(const Unsigned &n1, const Unsigned &n2) { return Unsigned(Unsigned::Impl(*n1.d_n + *n2.d_n)); } }; /* close namespace */ #endif cvc3-2.4.1/src/util/statistics.cpp0000664000175400017540000000342610466450542016733 0ustar mdetersmdeters/*****************************************************************************/ /*! * \file statistics.cpp * \brief Description: Implementation of Statistics class * * Author: Sergey Berezin * * Created: Thu Jun 5 17:49:01 2003 * *
* License to use, copy, modify, sell and/or distribute this software * and its documentation for any purpose is hereby granted without * royalty, subject to the terms and conditions defined in the \ref * LICENSE file provided with this distribution. * *
* */ /*****************************************************************************/ #include "statistics.h" using namespace std; namespace CVC3 { //////////////////////////////////////////////////////////////////////// // Class Statistics //////////////////////////////////////////////////////////////////////// // Print all the collected data ostream& Statistics::printAll(ostream& os) const { // Flags os << endl << "********************************" << endl << "********* Statistics ***********" << endl << "********************************" << endl; StatFlagMap::const_iterator i = d_flags.begin(), iend = d_flags.end(); if(i!=iend) { os << endl << "************ Flags *************" << endl << endl; for(; i != iend; ++i) os << (*i).first << " = " << (*i).second << endl; } StatCounterMap::const_iterator j = d_counters.begin(), jend = d_counters.end(); if(j!=jend) { os << endl << "*********** Counters ***********" << endl << endl; for(; j != jend; ++j) os << (*j).first << " = " << (*j).second << endl; } os << endl << "********************************" << endl << "****** End of Statistics *******" << endl << "********************************" << endl; return os; } } // end of namespace CVC3 cvc3-2.4.1/README0000664000175400017540000000054511265752521013150 0ustar mdetersmdeters/*!\page README README This is a distribution of the CVC3 source code. Its use is governed by the terms set forth in the accompanying file \ref LICENSE. For instructions on compiling and installing the code, see \ref INSTALL. Other information and related links can be found at the CVC3 home page:
   http://www.cs.nyu.edu/acsys/cvc3
*/ cvc3-2.4.1/Makefile.local.in0000664000175400017540000000675011352231200015411 0ustar mdetersmdeters################################################## # Project-specific Makefile for including in each # module ################################################## #Inputs: MODULE, SRC, HEADERS, EXECUTABLE/LIBRARY #Optional inputs: CXXFLAGS, INCLUDE_DIR, LD_LIB_DIR, LD_LIBS, EXE_DIR ################################################## # Configuration options ################################################## #Whether to build static libraries and executable STATIC = @STATIC@ #Whether to optimize OPTIMIZED = @OPTIMIZED@ #Whether to build for gcov GCOV = @GCOV@ #Whether to build for gprof GPROF = @GPROF@ empty:= space:= $(empty) $(empty) path_escape = $(subst $(space),\$(space),$(1)) #Path to top directory ifndef TOP TOP = $(call path_escape,@TOP@) endif #CXX CXX = @CXX@ #LD LD = @LD@ #AR AR = @AR@ #CXXFLAGS CXXFLAGS := @CXXFLAGS@ #CPPFLAGS CPPFLAGS := @CPPFLAGS@ #LDFLAGS LDFLAGS = @LDFLAGS@ #LIBS LD_LIBS += @LIBS@ #Whether to build individual shared libraries BUILD_SHARED_LIB = @BUILD_SHARED_LIB@ LIB_MAJOR_VERSION= @LIB_MAJOR_VERSION@ LIB_MINOR_VERSION= @LIB_MINOR_VERSION@ LIB_TEENY_VERSION= @LIB_TEENY_VERSION@ LIB_COMPAT_VERSION= $(LIB_MAJOR_VERSION).$(LIB_MINOR_VERSION) LIB_VERSION= $(LIB_COMPAT_VERSION).$(LIB_TEENY_VERSION) #Whether to build the Java interface BUILD_JAVA = @BUILD_JAVA@ # Java compilers and compiler flags JAVAC = @JAVAC@ JAVAH = @JAVAH@ JAR = @JAR@ JAVA = @JAVA@ JFLAGS := @JFLAGS@ JREFLAGS := @JREFLAGS@ JAVA_INCLUDES = @JAVA_INCLUDES@ PYTHON = @PYTHON@ #Installation directories datarootdir = @datarootdir@ prefix=@prefix@ exec_prefix=@exec_prefix@ libdir=@libdir@ bindir=@bindir@ mandir=@mandir@ incdir=$(prefix)/include/$(PROJECTNAME) javadir=@javadir@ ################################################## # Platform-specific definitions ################################################## HOST_OS = @host_os@ HOST_CPU = @host_cpu@ EXEEXT=@EXEEXT@ #Name of platform ifndef PLATFORM PLATFORM := $(HOST_CPU)-$(HOST_OS) endif #Install INSTALL = @INSTALL@ INSTALL_FLAGS = @INSTALL_FLAGS@ #Shared/Static libraries SHARED = @SHARED@ STATIC_FLAG = @STATIC_FLAG@ DYNAMIC_FLAG = @DYNAMIC_FLAG@ STATIC_LIB_SUFFIX = @STATIC_LIB_SUFFIX@ SHARED_LIB_SUFFIX = @SHARED_LIB_SUFFIX@ LDCONFIG = @LDCONFIG@ ifeq ($(patsubst darwin%,,$(HOST_OS)),) MAC_OSX = 1 endif ifeq ($(patsubst cygwin%,,$(HOST_OS)),) CYGWIN = 1 endif ifeq ($(STATIC),0) ifeq ($(CYGWIN),) CXXFLAGS += -fPIC endif endif #Etags/Ebrowse ETAGS=@ETAGS@ EBROWSE=@EBROWSE@ #lex LEX = flex LFLAGS = # -i use this for a case-insensitive scanner #yacc YACC = bison YFLAGS = -d -y ifneq ($(CYGWIN),) ifeq ($(STATIC),) LIB_PREFIX = cyg else LIB_PREFIX = lib endif else LIB_PREFIX = lib endif ################################################## # Project-specific definitions ################################################## #Name of project library PROJECTNAME = cvc3 #Main library name LIB_BASE_NAME = $(LIB_PREFIX)$(PROJECTNAME) #Where to look for include files INCLUDE_DIR += -I. -I$(TOP)/src/include #Where to look for lib files LD_LIB_DIR = @LD_LIB_DIR@ -L$(LIB_DIR) VERSION = @VERSION@ WEBDIR = /usr/httpd/htdocs_cs/acsys/cvc3 RATIONAL_FLAGS = @RATIONAL_IMPL@ ifeq ($(RATIONAL_FLAGS),-DRATIONAL_NATIVE) PLATFORM := $(PLATFORM)-native-arith endif DPLL_BASIC = @DPLL_BASIC@ EXTRA_SAT_CPP = @EXTRA_SAT_CPP@ EXTRA_SAT_HEADERS = @EXTRA_SAT_HEADERS@ ################################################## # Include generic Makefile ################################################## include $(TOP)/Makefile.std cvc3-2.4.1/java/0000775000175400017540000000000011630011320013162 5ustar mdetersmdeterscvc3-2.4.1/java/Makefile0000664000175400017540000002327311424051745014651 0ustar mdetersmdeters# Makefile for creating the java wrapper around the cvc library # as well as a java command line client include ../Makefile.local ### Variables # package name PACKAGE = cvc3 # directories # source files: java, cpp SOURCE_PATH = src # header files: h HEADER_PATH = include # object files: class, o OBJ_PATH = obj # library files: so, jar REL_LIB_PATH = java/lib LIB_PATH = $(TOP)/$(REL_LIB_PATH) REL_ARCH_LIB_PATH = $(REL_LIB_PATH)/$(PLATFORM_WITH_OPTIONS) ARCH_LIB_PATH = $(TOP)/$(REL_ARCH_LIB_PATH) CPPFLAGS += $(JAVA_INCLUDES) ifneq ($(CYGWIN),) CPPFLAGS += '-D__int64=long long' endif ifeq ($(OPTIMIZED), 1) CXXFLAGS += -O2 else CXXFLAGS += -D_CVC3_DEBUG_MODE -g -O0 endif # Java compiler flags # - source 1.4 is needed for Escjava # - Xlint may be compiler dependent JFLAGS += -Xlint -g -source 1.4 # source files # java files of the library wrapper LIB_FILES = \ JniUtils \ Cvc3Exception TypecheckException SoundException EvalException \ CLException ParserException SmtlibException DebugException \ Embedded EmbeddedManager \ InputLanguage QueryResult SatResult FormulaValue \ Expr ExprMut ExprManager ExprManagerMut \ Type TypeMut Op OpMut Rational RationalMut \ Theorem TheoremMut Proof ProofMut Context ContextMut \ Flag Flags FlagsMut \ Statistics StatisticsMut ValidityChecker # java files of the test program TEST_FILES = Test # java files of the stand alone program PROG_FILES = TimeoutHandler Cvc3 # all java files, library and stand alone JAVA_FILES = $(LIB_FILES) $(TEST_FILES) $(PROG_FILES) # jni files of the library wrapper JNI_FILES = \ EmbeddedManager \ Expr ExprMut ExprManager \ Type TypeMut Op OpMut Rational RationalMut \ Theorem TheoremMut Proof ProofMut Context ContextMut \ Flag Flags FlagsMut \ Statistics StatisticsMut ValidityChecker # stub files IMPL_FILES = $(addsuffix _impl.cpp,$(JNI_FILES)) # generated files JNI_CPP_FILES = $(patsubst %,%.cpp,$(JNI_FILES)) # non-generated files SRC_CPP_FILES = JniUtils.cpp # all cpp files (to compile) CPP_FILES = $(SRC_CPP_FILES) $(JNI_CPP_FILES) HEADER_FILES = JniUtils.h PYTHON_FILES = run_all.py run_tests.py create_impl.py MANIFEST_FILES = Cvc3_manifest Test_manifest DIST_FILES = \ Makefile \ README \ $(addprefix $(SOURCE_PATH)/$(PACKAGE)/, \ $(addsuffix .java, $(JAVA_FILES)) \ $(IMPL_FILES) $(SRC_CPP_FILES)) \ $(addprefix $(HEADER_PATH)/$(PACKAGE)/, $(HEADER_FILES)) \ $(PYTHON_FILES) \ $(MANIFEST_FILES) # target files # java library files compiled to class files LIB_CLASS_FILES = $(patsubst %,%.class,$(LIB_FILES)) # test files compiled to class files TEST_CLASS_FILES = $(patsubst %,%.class,$(TEST_FILES)) # cvc3 standalone files compiled to class files PROG_CLASS_FILES = $(patsubst %,%.class,$(PROG_FILES)) # all compiled java files, library and stand alone CLASS_FILES = $(LIB_CLASS_FILES) $(TEST_CLASS_FILES) $(PROG_CLASS_FILES) # jni header files created from the library class files H_FILES = $(patsubst %,%.h,$(JNI_FILES)) # precompiled header files GCH_FILES = $(patsubst %.h,%.h.gch,$(H_FILES)) JniUtils.h.gch # cpp files compiled to object files JNI_O_FILES = $(patsubst %.cpp,%.o,$(JNI_CPP_FILES)) O_FILES = $(patsubst %.cpp,%.o,$(CPP_FILES)) # library files # cpp library LIB_PREFIX = lib LIB_JNI_NAME = $(LIB_PREFIX)cvc3jni ifneq ($(CYGWIN),) LIB_JNI_BASE = $(LIB_JNI_NAME).$(SHARED_LIB_SUFFIX) LIB_JNI = $(LIB_JNI_NAME)-$(subst .,-,$(LIB_VERSION)).$(SHARED_LIB_SUFFIX) LIB_JNI_COMPAT = $(LIB_JNI_NAME)-$(subst .,-,$(LIB_COMPAT_VERSION)).$(SHARED_LIB_SUFFIX) LIB_JNI_MAJOR = $(LIB_JNI_NAME)-$(subst .,-,$(LIB_MAJOR_VERSION)).$(SHARED_LIB_SUFFIX) else LIB_JNI_BASE = $(LIB_JNI_NAME).$(SHARED_LIB_SUFFIX) ifneq ($(MAC_OSX),) LIB_JNI = $(LIB_JNI_NAME).$(LIB_VERSION).$(SHARED_LIB_SUFFIX) LIB_JNI_COMPAT = $(LIB_JNI_NAME).$(LIB_COMPAT_VERSION).$(SHARED_LIB_SUFFIX) LIB_JNI_MAJOR = $(LIB_JNI_NAME).$(LIB_MAJOR_VERSION).$(SHARED_LIB_SUFFIX) else LIB_JNI = $(LIB_JNI_BASE).$(LIB_VERSION) LIB_JNI_COMPAT = $(LIB_JNI_BASE).$(LIB_COMPAT_VERSION) LIB_JNI_MAJOR = $(LIB_JNI_BASE).$(LIB_MAJOR_VERSION) endif endif # java library LIB_CVC3 = libcvc3-$(LIB_VERSION).jar # test alone PROG_TEST = cvc3test.jar # java stand alone PROG_CVC3 = cvc3.jar ### virtual file lookup paths #VPATH = src/cvc3/ vpath %.java $(SOURCE_PATH)/$(PACKAGE) vpath %.cpp $(SOURCE_PATH)/$(PACKAGE) vpath %.h $(HEADER_PATH)/$(PACKAGE) vpath %.h.gch $(HEADER_PATH)/$(PACKAGE) vpath %.class $(OBJ_PATH)/$(PACKAGE) vpath %.o $(OBJ_PATH)/$(PACKAGE) .PHONY: all classes headers objects libs libjni libcvc3 testlib cvc3 test regress print_src clean distclean %.d ### rules all: classes headers objects libs libs: libjni libcvc3 testlib cvc3 %.d: if [ ! -d $* ]; then mkdir -p $*; fi $(OBJ_PATH): $(OBJ_PATH).d $(LIB_PATH): $(LIB_PATH).d $(ARCH_LIB_PATH): $(ARCH_LIB_PATH).d # compile each java file classes: $(OBJ_PATH) $(CLASS_FILES) $(CLASS_FILES): %.class: %.java $(OBJ_PATH) $(JAVAC) $(JFLAGS) -sourcepath $(SOURCE_PATH) \ -d $(OBJ_PATH) $(SOURCE_PATH)/$(PACKAGE)/$*.java # create a jni header file for each library class file #headers: $(H_FILES) $(GCH_FILES) headers: $(OBJ_PATH) $(H_FILES) $(H_FILES): %.h: %.class $(OBJ_PATH) $(JAVAH) -jni -force -classpath $(OBJ_PATH) \ -o $(HEADER_PATH)/$(PACKAGE)/$*.h $(PACKAGE).$* # precompile headers $(GCH_FILES): %.h.gch: %.h $(CXX) $(CPPFLAGS) $(CXXFLAGS) \ -I ../src/include -I $(HEADER_PATH)/$(PACKAGE)/ \ -o $(HEADER_PATH)/$(PACKAGE)/$*.h.gch $(HEADER_PATH)/$(PACKAGE)/$*.h # compile each cpp file $(JNI_CPP_FILES): %.cpp: %_impl.cpp %.h JniUtils.h $(PYTHON) ./create_impl.py \ $(HEADER_PATH)/$(PACKAGE)/$*.h \ $(SOURCE_PATH)/$(PACKAGE)/$*_impl.cpp \ $(SOURCE_PATH)/$(PACKAGE)/$*.cpp objects: $(OBJ_PATH) $(O_FILES) $(O_FILES): %.o: %.cpp %.h $(OBJ_PATH) $(CXX) $(CPPFLAGS) $(CXXFLAGS) -c \ -I ../src/include -I $(HEADER_PATH)/$(PACKAGE)/ \ -o $(OBJ_PATH)/$(PACKAGE)/$*.o $(SOURCE_PATH)/$(PACKAGE)/$*.cpp # create the cpp jni wrapper library libjni: $(ARCH_LIB_PATH)/$(LIB_JNI) $(LIB_PATH)/$(LIB_JNI) $(ARCH_LIB_PATH)/$(LIB_JNI): $(O_FILES) $(ARCH_LIB_PATH) ifneq ($(MAC_OSX),) $(CXX) $(SHARED) $(CXXFLAGS) $(LDFLAGS) \ -install_name $(libdir)/$(LIB_JNI_MAJOR) \ -compatibility_version $(LIB_COMPAT_VERSION) \ -current_version $(LIB_VERSION) \ -L../lib $(OBJ_PATH)/$(PACKAGE)/*.o \ -o '$(ARCH_LIB_PATH)/$(LIB_JNI)' `` -lcvc3 $(LD_LIBS) else $(CXX) $(SHARED) $(CXXFLAGS) $(LDFLAGS) \ -Wl,-soname,$(LIB_JNI_COMPAT) \ -L ../lib $(OBJ_PATH)/$(PACKAGE)/*.o \ -o $(ARCH_LIB_PATH)/$(LIB_JNI) -lcvc3 $(LD_LIBS) ifeq ($(CYGWIN),) $(LDCONFIG) -nv $(ARCH_LIB_PATH) endif endif ln -sf $(LIB_JNI) $(ARCH_LIB_PATH)/$(LIB_JNI_COMPAT) ln -sf $(LIB_JNI) $(ARCH_LIB_PATH)/$(LIB_JNI_MAJOR) ln -sf $(LIB_JNI) $(ARCH_LIB_PATH)/$(LIB_JNI_BASE) # $(CXX) $(CPPFLAGS) $(CXXFLAGS) -shared \ #$(LIB_PATH)/$(LIB_JNI): $(O_FILES) # ar ruvs $(LIB_PATH)/libcvc3jni.a $(OBJ_PATH)/$(PACKAGE)/*.o # $(CXX) $(CXXFLAGS) -shared -Wl,-soname,$(LIB_JNI) \ # -L ../lib -lc -lcvc3 -lgmp \ # $(LIB_PATH)/libcvc3jni.a \ # -o $(LIB_PATH)/$(LIB_JNI) #ar ruvs /media/data/ESCJava/CVC3/cvc3/lib/linux-i686-debug/libvcl.a /media/data/ESCJava/CVC3/cvc3/obj/vcl/linux-i686-debug/vcl.o /media/data/ESCJava/CVC3/cvc3/obj/vcl/linux-i686-debug/vc_cmd.o $(LIB_PATH)/$(LIB_JNI): $(ARCH_LIB_PATH)/$(LIB_JNI) ln -sf $< $@ # [chris] ldconfig seems to just delete the .so's! # $(LDCONFIG) -nv '$(call dirx,$@)' ln -sf $(LIB_JNI) '$(call dirx,$@)/$(LIB_JNI_COMPAT)' ln -sf $(LIB_JNI) '$(call dirx,$@)/$(LIB_JNI_MAJOR)' ln -sf $(LIB_JNI) '$(call dirx,$@)/$(LIB_JNI_BASE)' # create the java wrapper library libcvc3: $(LIB_PATH) $(LIB_PATH)/$(LIB_CVC3) $(LIB_PATH)/$(LIB_CVC3): $(LIB_CLASS_FILES) cd $(OBJ_PATH) && $(JAR) cf ../../$(REL_LIB_PATH)/$(LIB_CVC3) $(PACKAGE)/*.class install: $(ARCH_LIB_PATH)/$(LIB_JNI) $(LIB_PATH)/$(LIB_CVC3) mkdir -p $(javadir) $(INSTALL) $(INSTALL_FLAGS) -m 644 $(LIB_PATH)/$(LIB_CVC3) $(javadir) mkdir -p $(libdir) $(INSTALL) $(INSTALL_FLAGS) -m 644 $(ARCH_LIB_PATH)/$(LIB_JNI) $(libdir) ln -sf $(LIB_JNI) $(libdir)/$(LIB_JNI_MAJOR) ln -sf $(LIB_JNI) $(libdir)/$(LIB_JNI_COMPAT) ln -sf $(LIB_JNI) $(libdir)/$(LIB_JNI_BASE) ifeq ($(MAC_OSX),) ifeq ($(CYGWIN),) $(LDCONFIG) -nv $(libdir) endif endif # chmod 644 $(libdir)/$(LIB_JNI) # create the java stand alone program cvc3: $(LIB_PATH) $(LIB_PATH)/$(PROG_CVC3) $(LIB_PATH)/$(PROG_CVC3): $(PROG_CLASS_FILES) $(JAR) -cmf Cvc3_manifest ../$(REL_LIB_PATH)/$(PROG_CVC3) @for i in $(PROG_CLASS_FILES); do \ echo $(JAR) -uf ../$(REL_LIB_PATH)/$(PROG_CVC3) -C $(OBJ_PATH) $(PACKAGE)/$$i; \ $(JAR) -uf ../$(REL_LIB_PATH)/$(PROG_CVC3) -C $(OBJ_PATH) $(PACKAGE)/$$i; \ done # create the test stand alone program testlib: $(LIB_PATH) $(LIB_PATH)/$(PROG_TEST) test: testlib $(JAVA) $(JREFLAGS) -Djava.library.path=../$(REL_ARCH_LIB_PATH) -ea -jar ../$(REL_LIB_PATH)/$(PROG_TEST) $(LIB_PATH)/$(PROG_TEST): $(TEST_CLASS_FILES) echo -e "Main-Class: cvc3/Test\nClass-Path: $(LIB_CVC3)\n" > Test_manifest $(JAR) -cmf Test_manifest ../$(REL_LIB_PATH)/$(PROG_TEST) @for i in $(TEST_CLASS_FILES); do \ echo $(JAR) -uf ../$(REL_LIB_PATH)/$(PROG_TEST) -C $(OBJ_PATH) $(PACKAGE)/$$i; \ $(JAR) -uf ../$(REL_LIB_PATH)/$(PROG_TEST) -C $(OBJ_PATH) $(PACKAGE)/$$i; \ done regress: cvc3 $(PYTHON) ./run_tests.py \ -vc '$(JAVA) $(JREFLAGS) -Djava.library.path=../$(REL_LIB_PATH) -ea -Xss100M -jar ../$(REL_LIB_PATH)/$(PROG_CVC3)' \ -t 15 -m 500 -l 4 ../benchmarks ifndef FILELIST FILELIST = /dev/null endif print_src: echo $(addprefix java/, $(DIST_FILES)) >> $(FILELIST) # echo $(patsubst %, src/include/%, $(HEADER_NAMES)) >> $(FILELIST) # clean up clean: $(OBJ_PATH) rm -f $(addprefix $(SOURCE_PATH)/$(PACKAGE)/, $(JNI_CPP_FILES)) rm -fr $(OBJ_PATH)/$(PACKAGE)/* rm -fr $(LIB_PATH)/* rm -f $(addprefix $(HEADER_PATH)/$(PACKAGE)/, $(H_FILES) $(GCH_FILES)) distclean: clean cvc3-2.4.1/java/create_impl.py0000664000175400017540000003471011276570664016060 0ustar mdetersmdeters#!/usr/bin/env python import sys import os import re ### output cpp file # qualifiers: # c : embedded constant # m : embedded mutable # n : native # plus: # v : vector # vv : vector vector # vvv : vector vector vector # types: # - native: void, bool, int, string # - objects: the rest def is_native(arg_qual): return (arg_qual[0] == 'n') def is_mutable(arg_qual): return (arg_qual[0] == 'm') def is_const(arg_qual): return (arg_qual[0] == 'c') def forall(p, s): for x in s: if not p(s): return False return True def check_arg_qual(arg_qual): return \ (is_native(arg_qual) or is_mutable(arg_qual) or is_const(arg_qual)) \ and \ forall(lambda q: q == 'v', arg_qual[1:]) def is_vector(arg_qual): return (len(arg_qual) > 1 and arg_qual[1] == 'v') def is_vector2(arg_qual): return (is_vector(arg_qual) and len(arg_qual) > 2 and arg_qual[2] == 'v') def is_vector3(arg_qual): return (is_vector2(arg_qual) and len(arg_qual) > 3 and arg_qual[3] == 'v') # returns the jni type corresponding to the pseudo type signature def arg_type_to_java((arg_qual, arg_type, arg_name)): check_arg_qual(arg_qual); if arg_type == "jobject": if (not is_native(arg_qual)) or is_vector(arg_qual): print("Error: native defined in implementation with qualifier: " + arg_qual) sys.exit(1) return "jobject" elif arg_type == "bool": if not is_native(arg_qual): print("Error: bool defined in implementation with qualifier: " + arg_qual) sys.exit(1) if is_vector(arg_qual): return "jbooleanArray" else: return "jboolean" elif arg_type == "int": if not is_native(arg_qual): print("Error: int defined in implementation with qualifier: " + arg_qual) sys.exit(1) if is_vector(arg_qual): return "jintArray" else: return "jint" elif arg_type == "string": if not is_native(arg_qual): print("Error: string defined in implementation with qualifier: " + arg_qual) sys.exit(1) if is_vector(arg_qual): return "jobjectArray" else: return "jstring" else: if is_vector(arg_qual): return "jobjectArray" else: return "jobject" def print_unembed_arg(cpp_file, (arg_qual, arg_type, arg_name)): check_arg_qual(arg_qual); if arg_type == "jobject": () elif arg_type == "bool": if is_vector3(arg_qual): cpp_file.write(" vector > > " + arg_name \ + "(toCppVVV(env, j" + arg_name + "));\n"); elif is_vector2(arg_qual): cpp_file.write(" vector > " + arg_name \ + "(toCppVV(env, j" + arg_name + "));\n"); elif is_vector(arg_qual): cpp_file.write(" vector " + arg_name \ + "(toCppV(env, j" + arg_name + "));\n"); else: cpp_file.write(" bool " + arg_name + "(j" + arg_name + ");\n"); elif arg_type == "int": if is_vector3(arg_qual): cpp_file.write(" vector > > " + arg_name \ + "(toCppVVV(env, j" + arg_name + "));\n"); elif is_vector2(arg_qual): cpp_file.write(" vector > " + arg_name \ + "(toCppVV(env, j" + arg_name + "));\n"); elif is_vector(arg_qual): cpp_file.write(" vector " + arg_name \ + "(toCppV(env, j" + arg_name + "));\n"); else: cpp_file.write(" int " + arg_name + "(j" + arg_name + ");\n"); elif arg_type == "string": if is_vector3(arg_qual): cpp_file.write(" vector > > " + arg_name \ + "(toCppVVV(env, j" + arg_name + "));\n"); elif is_vector2(arg_qual): cpp_file.write(" vector > " + arg_name \ + "(toCppVV(env, j" + arg_name + "));\n"); elif is_vector(arg_qual): cpp_file.write(" vector " + arg_name \ + "(toCppV(env, j" + arg_name + "));\n"); else: cpp_file.write(" string " + arg_name + "(toCpp(env, j" + arg_name + "));\n"); else: if is_vector3(arg_qual): cpp_file.write(" vector > > " + arg_name \ + "(toCppVVV<" + arg_type + ">(env, j" + arg_name + "));\n"); elif is_vector2(arg_qual): cpp_file.write(" vector > " + arg_name \ + "(toCppVV<" + arg_type + ">(env, j" + arg_name + "));\n"); elif is_vector(arg_qual): cpp_file.write(" vector<" + arg_type + "> " + arg_name \ + "(toCppV<" + arg_type + ">(env, j" + arg_name + "));\n"); elif is_const(arg_qual): cpp_file.write(" const " + arg_type + "* " + arg_name \ + " = unembed_const<" + arg_type + ">(env, j" + arg_name + ");\n"); else: cpp_file.write(" " + arg_type + "* " + arg_name \ + " = unembed_mut<" + arg_type + ">(env, j" + arg_name + ");\n"); def print_unembed_args(cpp_file, args): for arg in args: print_unembed_arg(cpp_file, arg) # check hat declaration and definition signatures match def match_signatures((decl_result, decl_args), (def_result, def_args, _)): if decl_result != def_result or len(decl_args) != len(def_args): return False for i in xrange(0, len(decl_args)): java_type = arg_type_to_java(def_args[i]) #print java_type if decl_args[i] != java_type: return False return True def print_header(cpp_file, includes): cpp_file.writelines(map(lambda name: "#include " + name + "\n", includes)) cpp_file.writelines( [ "#include \"JniUtils.h\"\n", "\n", "using namespace std;\n", "using namespace Java_cvc3_JniUtils;\n", "using namespace CVC3;\n", "\n" ]) def print_signature(cpp_file, name, result, args): arg_strings = ["JNIEnv* env", "jclass"] arg_strings.extend( \ map(lambda (argQual, argType, argName): \ arg_type_to_java((argQual, argType, argName)) \ + " j" + argName, args)) cpp_file.writelines([ "JNIEXPORT " + result + " JNICALL " + name + "\n", "(" + ", ".join(arg_strings) + ")\n"]) def print_definition(cpp_file, name, (result, args, body)): cpp_file.writelines(["extern \"C\"\n"]) print_signature(cpp_file, name, result, args) cpp_file.writelines([ "{\n", " try {\n"]) print_unembed_args(cpp_file, args) cpp_file.writelines([ " " + " ".join(body), " } catch (const Exception& e) {\n", " toJava(env, e);\n"]) if result in [ "jobject", "jobjectArray", "jstring" ]: cpp_file.writelines([" return NULL;\n"]) elif result == "jboolean": cpp_file.writelines([" return false;\n"]) elif result == "jint": cpp_file.writelines([" return -1;\n"]) elif result <> "void": print("BUG: return type " + result + " is not handled in print_definition") sys.exit(1) cpp_file.writelines([" };\n", "}\n\n"]) def print_cpp(cpp_name, declarations, definitions, includes): try: cpp_file = open(cpp_name, 'w') print_header(cpp_file, includes) #names = declarations.keys() #names.sort() for name in declarations[0]: if not definitions.has_key(name): #continue print("Error: " + name + " is declared in header" \ + " but not defined in implementation.") sys.exit(1) declaration = declarations[1][name] definition = definitions[name] definitions.pop(name) if not match_signatures(declaration, definition): print("Error: signature for " + name \ + " in definition and implementation do not match:") print declaration print (definition[0], definition[1]) sys.exit(1) print_definition(cpp_file, name, definition) if not len(definitions) == 0: print("Error: found definitions in implementation" \ " without declaration in header file:") print definitions sys.exit(1) except IOError, (error_nr, error_string): print ("Couldn't open " + cpp_name + ": " + error_string) sys.exit(0) ### header file function declarations # header file function declaration: # - name: function name # - result: result type # - args: list of argument types, except for the first two (JNIEnv*, jclass) def register_declaration(declarations, name, result, args): assert(not declarations[1].has_key(name)); declarations[0].append(name) declarations[1][name] = (result, args) # extract function signatures from generated JNI header file def read_header(header_name): # 0.: names of declared functions in same order as in input # 1.: map from names to signature declarations = ([], {}) try: header_file = open(header_name) line = header_file.readline() while (line): # look for start of signature # declaration will look like: # JNIEXPORT JNICALL (JNIENV *env, jclass, jobject); # with an optional linebreak before the parameter list, and # perhaps missing the "env" if re.search("^JNIEXPORT", line): # extract name and return type elements = re.sub('[,();]+',' ',line).split(); assert(elements[0] == "JNIEXPORT"); assert(elements[2] == "JNICALL"); name = elements[3] result = elements[1] # If there are no more elements on this line, # read and tokenize the next line if len(elements) > 4: elements = elements[4:] else: line = header_file.readline () elements = re.sub('[,();]+',' ',line).split(); # extract argument types assert(elements[0] == "JNIEnv"); assert(elements[1] == "*" or elements[1] == "*env"); assert(elements[2] == "jclass") args = elements[3:] register_declaration(declarations, name, result, args) line = header_file.readline () header_file.close() except IOError, (error_nr, error_string): print ("Couldn't open " + header_name + ": " + error_string) sys.exit(0) return declarations # function definitions: # cpp file function definition: # - name: function name # - result: result type # - args: list of pairs of argument types and argument names, # except for the first two (JNIEnv*, jclass) def register_definition(definitions, name, result, args, body): if definitions.has_key(name): print("Error: redefinition of " + name + " in implementation.") sys.exit(1) definitions[name] = (result, args, body) #print_definition(name, declarations[name]) # extract function definition from implementation file def read_impl(impl_name): definitions = {} includes = [] try: impl_file = open(impl_name) line = impl_file.readline() while (line): # look for include if re.search("^INCLUDE:", line): elements = line.split(); assert(len(elements) == 2); assert(elements[0] == "INCLUDE:") includes.append(elements[1]) line = impl_file.readline() #print line # look for start of definition elif re.search("^DEFINITION:", line): #print line, # get name elements = line.split(); if not (len(elements) == 2): print("Error: misformed signature: " + line) sys.exit(1) assert(elements[0] == "DEFINITION:") name = elements[1] # get signature line = impl_file.readline () elements = line.split(); assert(len(elements) > 0); if not (len(elements) % 3 == 1): print("Error: misformed signature for: " + name) print(line) sys.exit(1) result = elements.pop(0) args = [] while len(elements) > 0: argQual = elements.pop(0) argType = elements.pop(0) argName = elements.pop(0) args.append((argQual, argType, argName)) # get body body = [] line = impl_file.readline () while line and not re.search("^DEFINITION:", line): body.append(line) line = impl_file.readline() while body and body[len(body) - 1] == "\n": body.pop(len(body) - 1) assert(len(body) > 0) register_definition(definitions, name, result, args, body) else: line = impl_file.readline() impl_file.close() except IOError, (error_nr, error_string): print ("Couldn't open " + impl_name + ": " + error_string) sys.exit(0) return definitions, includes # read name of input file if (len(sys.argv) != 4): print("Expected path to header, implementation, and target file.") print("") print("./create_impl.py ") sys.exit(0) else: #print(sys.argv) header_name = sys.argv[1] impl_name = sys.argv[2] cpp_file = sys.argv[3] # extract information from header declarations = read_header(header_name) #print declarations # extract information from template definitions, includes = read_impl(impl_name) #print definitions # create implementation print_cpp(cpp_file, declarations, definitions, includes) cvc3-2.4.1/java/run_all.py0000664000175400017540000000072011070741376015212 0ustar mdetersmdeters#! /usr/bin/env python import os libs = [ "AUFLIA", "AUFLIRA", "AUFNIRA", "QF_AUFBV", "QF_AUFLIA", "QF_IDL", "QF_LIA", "QF_LRA", "QF_RDL", "QF_UF", "QF_UFBV32", "QF_UFIDL", "QF_UFLIA", ] for lib in libs: command = "./run_tests.py -vc 'java -esa -Xss100M -jar lib/cvc3.jar' -t 1 -m 500 -l 5 -lang smtlib /media/data/CVC/BENCHMARKS/SMTLIB/" + lib + " > out." + lib print command os.system(command) cvc3-2.4.1/java/include/0000775000175400017540000000000011630011320014605 5ustar mdetersmdeterscvc3-2.4.1/java/include/cvc3/0000775000175400017540000000000011630011320015443 5ustar mdetersmdeterscvc3-2.4.1/java/include/cvc3/JniUtils.h0000664000175400017540000002166211267471571017414 0ustar mdetersmdeters#ifndef _java__cvc3__jni_utils_h_ #define _java__cvc3__jni_utils_h_ #include #include #include #include #include "vcl.h" #include "hash_map.h" #include "exception.h" namespace Java_cvc3_JniUtils { /// Embedding of c++ objects in java objects // generic delete function for any type T template class DeleteEmbedded { public: static void deleteEmbedded(void* cobj) { delete (T*) cobj; } }; typedef void (*TDeleteEmbedded)(void*); // Encapsulates a c++ object so that: // - (un)embedding casting is type safe // - deallocation is automatic (if needed) // This has probably quit a bit of overhead, because now for each // wrapper object (even if only a temporary reference) an instance // of Embedded is created. // But considering the above two benefits it should be worth it // because it should simplify maintenance quite a bit, // as changes in the cvc API should lead to assertion failures // instead of strange bugs. class Embedded { private: // the actual embedded c++ object, // as void* to make Embedded independent of its type void* d_cobj; // the type info of d_cobj, // to make sure that later unembeddings are type safe // actually only needed in debugging, so might be guarded with IF_DEBUG const std::type_info& d_typeInfo; // the type correct delete function for d_cobj, // or NULL if this embedding is merely a reference // and not responsible for its deallocation TDeleteEmbedded d_delete; public: Embedded(void* cobj, const std::type_info& ti, TDeleteEmbedded del) : d_cobj(cobj), d_typeInfo(ti), d_delete(del) { assert(d_cobj != NULL); } ~Embedded() { assert(d_cobj != NULL); if (d_delete != NULL) d_delete(d_cobj); } const void* getCObj() const { return d_cobj; } const std::type_info& getType() const { return d_typeInfo; } }; // embed functions // embeds a c++ object of type T into a jobject // by first wrapping it into an Embedded object. template jobject embed(JNIEnv* env, T* cobj, const std::type_info& ti, TDeleteEmbedded del) { DebugAssert(cobj != NULL, "JniUtils::embed: null object given"); Embedded* embedded = new Embedded((void*)cobj, ti, del); return (jobject)env->NewDirectByteBuffer(embedded, sizeof(Embedded)); } // embeds a constant reference to a c++ object into a jobject template jobject embed_const_ref(JNIEnv* env, const T* cobj) { DebugAssert(cobj != NULL, "JniUtils::embed_const: null object given"); return embed(env, (T*) cobj, typeid(cobj), NULL); } // embeds a mutable reference to a c++ object into a jobject template jobject embed_mut_ref(JNIEnv* env, T* cobj) { DebugAssert(cobj != NULL, "JniUtils::embed_mut_ref: null object given"); return embed(env, (T*) cobj, typeid(cobj), NULL); } // embeds a fresh copy of a (probably temporary) c++ object into a jobject template jobject embed_copy(JNIEnv* env, const T& cobj) { DebugAssert(&cobj != NULL, "JniUtils::embed_copy: null object given"); T* copy = new T(cobj); assert(copy != NULL); return embed(env, copy, typeid(copy), &DeleteEmbedded::deleteEmbedded); } // embeds a c++ object into a jobject, // and takes over the responsibility to deallocate it template jobject embed_own(JNIEnv* env, T* cobj) { DebugAssert(&cobj != NULL, "JniUtils::embed_own: null object given"); return embed(env, cobj, typeid(cobj), &DeleteEmbedded::deleteEmbedded); } // unembed functions // extract Embedded* from a jobject Embedded* unembed(JNIEnv* env, jobject jobj); // extract a constant c++ object of type T from a jobject template const T* unembed_const(JNIEnv* env, jobject jobj) { Embedded* embedded = unembed(env, jobj); return (const T*) embedded->getCObj(); } // extract a mutable c++ object of type T from a jobject template T* unembed_mut(JNIEnv* env, jobject jobj) { Embedded* embedded = unembed(env, jobj); // check that the wrapped object is not const DebugAssert(embedded->getType() == typeid(T*), "JniUtils::unembed_mut: type mismatch"); return (T*) embedded->getCObj(); } // delete embedded // delete the Embedded object contained in a jobject, // and also destruct the wrapped c++ object if necessary. void deleteEmbedded(JNIEnv* env, jobject jobj); /// Conversions between c++ and java // bool bool toCpp(jboolean j); // string jstring toJava(JNIEnv* env, const std::string& cstring); jstring toJava(JNIEnv* env, const char* cstring); std::string toCpp(JNIEnv* env, const jstring& string); // enums jstring toJava(JNIEnv* env, CVC3::QueryResult result); jstring toJava(JNIEnv* env, CVC3::FormulaValue result); jstring toJava(JNIEnv* env, CVC3::InputLanguage result); CVC3::InputLanguage toCppInputLanguage(JNIEnv* env, const std::string& lang); // exceptions void toJava(JNIEnv* env, const CVC3::Exception& e); // vectors template jobjectArray toJavaVCopy(JNIEnv* env, const std::vector& v) { jobjectArray jarray = (jobjectArray) env->NewObjectArray( v.size(), env->FindClass("java/lang/Object"), NULL); for (int i = 0; i < v.size(); ++i) { env->SetObjectArrayElement(jarray, i, embed_copy(env, v[i])); } return jarray; } template jobjectArray toJavaVConstRef(JNIEnv* env, const std::vector& v) { jobjectArray jarray = (jobjectArray) env->NewObjectArray( v.size(), env->FindClass("java/lang/Object"), NULL); for (int i = 0; i < v.size(); ++i) { env->SetObjectArrayElement(jarray, i, embed_const_ref(env, &v[i])); } return jarray; } template jobjectArray toJavaVVConstRef(JNIEnv* env, const std::vector >& v) { jobjectArray jarray = (jobjectArray) env->NewObjectArray(v.size(), env->FindClass("[Ljava/lang/Object;"), NULL); for (int i = 0; i < v.size(); ++i) { env->SetObjectArrayElement(jarray, i, toJavaVConstRef(env, v[i])); } return jarray; } template std::vector toCppV(JNIEnv* env, const jobjectArray& jarray) { std::vector v; int length = env->GetArrayLength(jarray); for (int i = 0; i < length; ++i) { v.push_back(*unembed_const(env, env->GetObjectArrayElement(jarray, i))); } return v; } template std::vector > toCppVV(JNIEnv* env, const jobjectArray& jarray) { std::vector > v; int length = env->GetArrayLength(jarray); for (int i = 0; i < length; ++i) { jobjectArray jsub = static_cast(env->GetObjectArrayElement(jarray, i)); v.push_back(toCppV(env, jsub)); } return v; } template std::vector > > toCppVVV(JNIEnv* env, const jobjectArray& jarray) { std::vector > > v; int length = env->GetArrayLength(jarray); for (int i = 0; i < length; ++i) { jobjectArray jsub = static_cast(env->GetObjectArrayElement(jarray, i)); v.push_back(toCppVV(env, jsub)); } return v; } // string vectors std::vector toCppV(JNIEnv* env, const jobjectArray& jarray); std::vector > toCppVV(JNIEnv* env, const jobjectArray& jarray); std::vector > > toCppVVV(JNIEnv* env, const jobjectArray& jarray); jobjectArray toJavaV(JNIEnv* env, const std::vector& v); // primitive vectors std::vector toCppV(JNIEnv* env, const jbooleanArray& jarray); // hash map template jobjectArray toJavaHCopy(JNIEnv* env, const Hash::hash_map& hm) { jobjectArray jarray = (jobjectArray) env->NewObjectArray( hm.size() * 2, env->FindClass("java/lang/Object"), NULL); int i = 0; typename Hash::hash_map::const_iterator it; for (it = hm.begin(); it != hm.end(); ++it) { assert(i < env->GetArrayLength(jarray)); env->SetObjectArrayElement(jarray, i, embed_copy(env, it->first)); ++i; assert(i < env->GetArrayLength(jarray)); env->SetObjectArrayElement(jarray, i, embed_copy(env, it->second)); ++i; } return jarray; } template jobjectArray toJavaHCopy(JNIEnv* env, const CVC3::ExprMap& hm) { jobjectArray jarray = (jobjectArray) env->NewObjectArray( hm.size() * 2, env->FindClass("java/lang/Object"), NULL); int i = 0; typename CVC3::ExprMap::const_iterator it; for (it = hm.begin(); it != hm.end(); ++it) { assert(i < env->GetArrayLength(jarray)); env->SetObjectArrayElement(jarray, i, embed_copy(env, it->first)); ++i; assert(i < env->GetArrayLength(jarray)); env->SetObjectArrayElement(jarray, i, embed_copy(env, it->second)); ++i; } return jarray; } } #endif cvc3-2.4.1/java/Test_manifest0000664000175400017540000000006511423122037015723 0ustar mdetersmdetersMain-Class: cvc3/Test Class-Path: libcvc3-2.3.0.jar cvc3-2.4.1/java/src/0000775000175400017540000000000011630011320013751 5ustar mdetersmdeterscvc3-2.4.1/java/src/cvc3/0000775000175400017540000000000011630011320014607 5ustar mdetersmdeterscvc3-2.4.1/java/src/cvc3/Op_impl.cpp0000664000175400017540000000057011423121756016733 0ustar mdetersmdetersINCLUDE: DEFINITION: Java_cvc3_Op_jniEquals jboolean c Op op1 c Op op2 return *op1 == *op2; DEFINITION: Java_cvc3_Op_jniToString jstring c Op op return toJava(env, op->toString()); DEFINITION: Java_cvc3_Op_jniGetExpr jobject c Op op return embed_const_ref(env, &op->getExpr()); DEFINITION: Java_cvc3_Op_jniIsNull jboolean c Op op return op->isNull(); cvc3-2.4.1/java/src/cvc3/Expr.java0000664000175400017540000004000211314253512016376 0ustar mdetersmdeterspackage cvc3; import java.util.*; public class Expr extends Embedded { // jni methods private static native boolean jniEquals(Object Expr1, Object Expr2) throws Cvc3Exception; private static native String jniToString(Object Expr) throws Cvc3Exception; private static native void jniPrint(Object Expr, String InputLanguage, boolean dagify) throws Cvc3Exception; private static native int jniHash(Object Expr) throws Cvc3Exception; private static native String jniGetKind(Object Expr) throws Cvc3Exception; private static native boolean jniIsFalse(Object Expr) throws Cvc3Exception; private static native boolean jniIsTrue(Object Expr) throws Cvc3Exception; private static native boolean jniIsBoolConst(Object Expr) throws Cvc3Exception; private static native boolean jniIsVar(Object Expr) throws Cvc3Exception; private static native boolean jniIsBoundVar(Object Expr) throws Cvc3Exception; private static native boolean jniIsString(Object Expr) throws Cvc3Exception; private static native boolean jniIsClosure(Object Expr) throws Cvc3Exception; private static native boolean jniIsQuantifier(Object Expr) throws Cvc3Exception; private static native boolean jniIsLambda(Object Expr) throws Cvc3Exception; private static native boolean jniIsApply(Object Expr) throws Cvc3Exception; private static native boolean jniIsSymbol(Object Expr) throws Cvc3Exception; private static native boolean jniIsTheorem(Object Expr) throws Cvc3Exception; private static native boolean jniIsType(Object Expr) throws Cvc3Exception; private static native boolean jniIsTerm(Object Expr) throws Cvc3Exception; private static native boolean jniIsAtomic(Object Expr) throws Cvc3Exception; private static native boolean jniIsAtomicFormula(Object Expr) throws Cvc3Exception; private static native boolean jniIsAbsAtomicFormula(Object Expr) throws Cvc3Exception; private static native boolean jniIsLiteral(Object Expr) throws Cvc3Exception; private static native boolean jniIsAbsLiteral(Object Expr) throws Cvc3Exception; private static native boolean jniIsBoolConnective(Object Expr) throws Cvc3Exception; private static native boolean jniIsPropAtom(Object Expr) throws Cvc3Exception; private static native boolean jniIsPropLiteral(Object Expr) throws Cvc3Exception; private static native boolean jniIsArrayLiteral(Object Expr) throws Cvc3Exception; private static native boolean jniIsEq(Object Expr) throws Cvc3Exception; private static native boolean jniIsNot(Object Expr) throws Cvc3Exception; private static native boolean jniIsAnd(Object Expr) throws Cvc3Exception; private static native boolean jniIsOr(Object Expr) throws Cvc3Exception; private static native boolean jniIsITE(Object Expr) throws Cvc3Exception; private static native boolean jniIsIff(Object Expr) throws Cvc3Exception; private static native boolean jniIsImpl(Object Expr) throws Cvc3Exception; private static native boolean jniIsXor(Object Expr) throws Cvc3Exception; private static native boolean jniIsForall(Object Expr) throws Cvc3Exception; private static native boolean jniIsExists(Object Expr) throws Cvc3Exception; private static native boolean jniIsRational(Object Expr) throws Cvc3Exception; private static native boolean jniIsUminus(Object Expr) throws Cvc3Exception; private static native boolean jniIsPlus(Object Expr) throws Cvc3Exception; private static native boolean jniIsMinus(Object Expr) throws Cvc3Exception; private static native boolean jniIsMult(Object Expr) throws Cvc3Exception; private static native boolean jniIsPow(Object Expr) throws Cvc3Exception; private static native boolean jniIsDivide(Object Expr) throws Cvc3Exception; private static native boolean jniIsLt(Object Expr) throws Cvc3Exception; private static native boolean jniIsLe(Object Expr) throws Cvc3Exception; private static native boolean jniIsGt(Object Expr) throws Cvc3Exception; private static native boolean jniIsGe(Object Expr) throws Cvc3Exception; private static native boolean jniIsSkolem(Object Expr) throws Cvc3Exception; private static native boolean jniIsRead(Object Expr) throws Cvc3Exception; private static native boolean jniIsWrite(Object Expr) throws Cvc3Exception; private static native String jniGetName(Object Expr) throws Cvc3Exception; private static native String jniGetUid(Object Expr) throws Cvc3Exception; private static native String jniGetString(Object Expr) throws Cvc3Exception; private static native Object[] jniGetVars(Object Expr) throws Cvc3Exception; private static native Object jniGetExistential(Object Expr) throws Cvc3Exception; private static native int jniGetBoundIndex(Object Expr) throws Cvc3Exception; private static native Object jniGetBody(Object Expr) throws Cvc3Exception; private static native Object jniGetRational(Object Expr) throws Cvc3Exception; private static native Object[][] jniGetTriggers(Object Expr) throws Cvc3Exception; private static native Object jniGetTheorem(Object Expr) throws Cvc3Exception; private static native Object jniGetType(Object Expr) throws Cvc3Exception; private static native Object jniMkOp(Object Expr) throws Cvc3Exception; private static native Object jniGetOp(Object Expr) throws Cvc3Exception; private static native Object jniGetOpExpr(Object Expr) throws Cvc3Exception; private static native boolean jniIsNull(Object Expr) throws Cvc3Exception; private static native int jniArity(Object Expr) throws Cvc3Exception; private static native Object jniGetKid(Object Expr, int i) throws Cvc3Exception; private static native Object[] jniGetKids(Object Expr) throws Cvc3Exception; private static native Object jniSubstExpr(Object Expr, Object[] oldExprs, Object[] newExprs) throws Cvc3Exception; private static native boolean jniIsBvLt(Object Expr) throws Cvc3Exception; private static native boolean jniIsBvLe(Object Expr) throws Cvc3Exception; private static native boolean jniIsBvGt(Object Expr) throws Cvc3Exception; private static native boolean jniIsBvGe(Object Expr) throws Cvc3Exception; private static native boolean jniIsBvPlus(Object Expr) throws Cvc3Exception; private static native boolean jniIsBvSub(Object Expr) throws Cvc3Exception; private static native boolean jniIsBvConst(Object Expr) throws Cvc3Exception; private static native boolean jniIsBvExtract(Object Expr) throws Cvc3Exception; private static native boolean jniIsBvConcat(Object Expr) throws Cvc3Exception; /// Constructor public Expr(Object Expr, EmbeddedManager embeddedManager) { super(Expr, embeddedManager); } /// API (immutable) // 'Problem' with equals/hashCode: // this is based on the wrapped c++ expressions. // as a consequence two Expr objects are equal iff // the wrapped expression is equal, // and are indistinguishable for example in a HashMap. public boolean equals(Object o) { if (this == o) return true; if (!(o instanceof Expr)) return false; boolean result = false; try { result = jniEquals(embedded(), ((Embedded)o).embedded()); } catch (Cvc3Exception e) { assert(false); } return result; } // must return the same hash code for two objects if equals returns true public int hashCode() { try { if (!jniIsNull(embedded())) { return jniHash(embedded()); } } catch (Cvc3Exception e) { assert(false); } assert(false); return 0; } public Expr subst(List oldExprs, List newExprs) throws Cvc3Exception { assert(JniUtils.listInstanceof(oldExprs, Expr.class)); assert(JniUtils.listInstanceof(newExprs, Expr.class)); return new Expr(jniSubstExpr(embedded(), JniUtils.unembedList(oldExprs), JniUtils.unembedList(newExprs)), embeddedManager()); } public String toString() { String result = ""; try { result = jniToString(embedded()); } catch (Cvc3Exception e) { assert(false); } return result; } public void print(InputLanguage lang, boolean dagify) throws Cvc3Exception { jniPrint(embedded(), lang.toString(), dagify); } public void print(boolean dagify) throws Cvc3Exception { print(InputLanguage.PRESENTATION, dagify); } public void print() throws Cvc3Exception { print(false); } public String getKind() throws Cvc3Exception { return jniGetKind(embedded()); } // Core expression testers public boolean isFalse() throws Cvc3Exception { return jniIsFalse(embedded()); } public boolean isTrue() throws Cvc3Exception { return jniIsTrue(embedded()); } public boolean isBooleanConst() throws Cvc3Exception { return jniIsBoolConst(embedded()); } public boolean isVar() throws Cvc3Exception { return jniIsVar(embedded()); } public boolean isBoundVar() throws Cvc3Exception { return jniIsBoundVar(embedded()); } public boolean isString() throws Cvc3Exception { return jniIsString(embedded()); } public boolean isClosure() throws Cvc3Exception { return jniIsClosure(embedded()); } public boolean isQuantifier() throws Cvc3Exception { return jniIsQuantifier(embedded()); } public boolean isLambda() throws Cvc3Exception { return jniIsLambda(embedded()); } public boolean isApply() throws Cvc3Exception { return jniIsApply(embedded()); } public boolean isSymbol() throws Cvc3Exception { return jniIsSymbol(embedded()); } public boolean isTheorem() throws Cvc3Exception { return jniIsTheorem(embedded()); } public boolean isType() throws Cvc3Exception { return jniIsType(embedded()); } public boolean isTerm() throws Cvc3Exception { return jniIsTerm(embedded()); } public boolean isAtomic() throws Cvc3Exception { return jniIsAtomic(embedded()); } public boolean isAtomicFormula() throws Cvc3Exception { return jniIsAtomicFormula(embedded()); } public boolean isAbsAtomicFormula() throws Cvc3Exception { return jniIsAbsAtomicFormula(embedded()); } public boolean isLiteral() throws Cvc3Exception { return jniIsLiteral(embedded()); } public boolean isAbsLiteral() throws Cvc3Exception { return jniIsAbsLiteral(embedded()); } public boolean isBoolConnective() throws Cvc3Exception { return jniIsBoolConnective(embedded()); } public boolean isPropAtom() throws Cvc3Exception { return jniIsPropAtom(embedded()); } public boolean isPropLiteral() throws Cvc3Exception { return jniIsPropLiteral(embedded()); } public boolean isArrayLiteral() throws Cvc3Exception { return jniIsArrayLiteral(embedded()); } public boolean isEq() throws Cvc3Exception { return jniIsEq(embedded()); } public boolean isNot() throws Cvc3Exception { return jniIsNot(embedded()); } public boolean isAnd() throws Cvc3Exception { return jniIsAnd(embedded()); } public boolean isOr() throws Cvc3Exception { return jniIsOr(embedded()); } public boolean isITE() throws Cvc3Exception { return jniIsITE(embedded()); } public boolean isIff() throws Cvc3Exception { return jniIsIff(embedded()); } public boolean isImpl() throws Cvc3Exception { return jniIsImpl(embedded()); } public boolean isXor() throws Cvc3Exception { return jniIsXor(embedded()); } public boolean isForall() throws Cvc3Exception { return jniIsForall(embedded()); } public boolean isExists() throws Cvc3Exception { return jniIsExists(embedded()); } public boolean isRational() throws Cvc3Exception { return jniIsRational(embedded()); } public boolean isUminus() throws Cvc3Exception { return jniIsUminus(embedded()); } public boolean isPlus() throws Cvc3Exception { return jniIsPlus(embedded()); } public boolean isMinus() throws Cvc3Exception { return jniIsMinus(embedded()); } public boolean isMult() throws Cvc3Exception { return jniIsMult(embedded()); } public boolean isPow() throws Cvc3Exception { return jniIsPow(embedded()); } public boolean isDivide() throws Cvc3Exception { return jniIsDivide(embedded()); } public boolean isLt() throws Cvc3Exception { return jniIsLt(embedded()); } public boolean isLe() throws Cvc3Exception { return jniIsLe(embedded()); } public boolean isGt() throws Cvc3Exception { return jniIsGt(embedded()); } public boolean isGe() throws Cvc3Exception { return jniIsGe(embedded()); } public boolean isSkolem() throws Cvc3Exception { return jniIsSkolem(embedded()); } public boolean isRead() throws Cvc3Exception { return jniIsRead(embedded()); } public boolean isWrite() throws Cvc3Exception { return jniIsWrite(embedded()); } public boolean isBvLe() throws Cvc3Exception { return jniIsBvLe(embedded()); } public boolean isBvLt() throws Cvc3Exception { return jniIsBvLt(embedded()); } public boolean isBvGe() throws Cvc3Exception { return jniIsBvGe(embedded()); } public boolean isBvGt() throws Cvc3Exception { return jniIsBvGt(embedded()); } public boolean isBvPlus() throws Cvc3Exception { return jniIsBvPlus(embedded()); } public boolean isBvSub() throws Cvc3Exception { return jniIsBvSub(embedded()); } public boolean isBvConstant() throws Cvc3Exception { return jniIsBvConst(embedded()); } public boolean isBvConcat() throws Cvc3Exception { return jniIsBvConcat(embedded()); } public boolean isBvExtract() throws Cvc3Exception { return jniIsBvExtract(embedded()); } public String getName() throws Cvc3Exception { assert(!jniIsNull(embedded())); return jniGetName(embedded()); } public String getUid() throws Cvc3Exception { assert(jniIsBoundVar(embedded())); return jniGetUid(embedded()); } public String getString() throws Cvc3Exception { assert(jniIsString(embedded())); return jniGetString(embedded()); } public List getVars() throws Cvc3Exception { assert(jniIsClosure(embedded())); Object[] vars = jniGetVars(embedded()); return JniUtils.embedList(vars, Expr.class, embeddedManager()); } public List getTriggers() throws Cvc3Exception { assert (jniIsClosure(embedded())); return JniUtils.embedListList(jniGetTriggers(embedded()), Expr.class, embeddedManager()); } public Expr getExistential() throws Cvc3Exception { assert(jniIsSkolem(embedded())); return new Expr(jniGetExistential(embedded()), embeddedManager()); } public int getBoundIndex() throws Cvc3Exception { assert(jniIsSkolem(embedded())); return jniGetBoundIndex(embedded()); } public Expr getBody() throws Cvc3Exception { assert(jniIsClosure(embedded())); return new Expr(jniGetBody(embedded()), embeddedManager()); } public Rational getRational() throws Cvc3Exception { assert(isRational()); return new Rational(jniGetRational(embedded()), embeddedManager()); } public Theorem getTheorem() throws Cvc3Exception { assert(jniIsTheorem(embedded())); return new Theorem(jniGetTheorem(embedded()), embeddedManager()); } public TypeMut getType() throws Cvc3Exception { return new TypeMut(jniGetType(embedded()), embeddedManager()); } public OpMut mkOp() throws Cvc3Exception { return new OpMut(jniMkOp(embedded()), embeddedManager()); } public OpMut getOp() throws Cvc3Exception { return new OpMut(jniGetOp(embedded()), embeddedManager()); } public ExprMut getOpExpr() throws Cvc3Exception { return new ExprMut(jniGetOpExpr(embedded()), embeddedManager()); } public boolean isNull() throws Cvc3Exception { return jniIsNull(embedded()); } public int arity() throws Cvc3Exception { return jniArity(embedded()); } public Expr getChild(int i) throws Cvc3Exception { assert(i >= 0 && i < arity()); return new Expr(jniGetKid(embedded(), i), embeddedManager()); } public List getChildren() throws Cvc3Exception { return JniUtils.embedList(jniGetKids(embedded()), Expr.class, embeddedManager()); } } cvc3-2.4.1/java/src/cvc3/InputLanguage.java0000664000175400017540000000203211070741372020231 0ustar mdetersmdeterspackage cvc3; import java.util.*; /** See comments about mapping c++ enums to java in QueryResult */ public class InputLanguage { private final String d_lang; private InputLanguage(String lang) { d_lang = lang; } // names of c++ enum values public static final InputLanguage PRESENTATION = new InputLanguage("PRESENTATION"); public static final InputLanguage SMTLIB = new InputLanguage("SMTLIB"); public static final InputLanguage LISP = new InputLanguage("LISP"); // the InputLanguage corresponding to a c++ enum value by name public static InputLanguage get(String value) throws DebugException { if (value.equals(PRESENTATION.toString())) { return PRESENTATION; } else if (value.equals(SMTLIB.toString())) { return SMTLIB; } else if (value.equals(LISP.toString())) { return LISP; } else { throw new DebugException("InputLanguage.constructor: unknown enum value: " + value); } } // the InputLanguage's c++ enum value public String toString() { return d_lang; } } cvc3-2.4.1/java/src/cvc3/TheoremMut.java0000664000175400017540000000046311070741371017564 0ustar mdetersmdeterspackage cvc3; import java.util.*; public class TheoremMut extends Theorem { // jni methods /// Constructor // create embedded object public TheoremMut(Object TheoremMut, EmbeddedManager embeddedManager) { super(TheoremMut, embeddedManager); } /// API (mutable) } cvc3-2.4.1/java/src/cvc3/Expr_impl.cpp0000664000175400017540000001675211314253512017277 0ustar mdetersmdetersINCLUDE: INCLUDE: INCLUDE: INCLUDE: DEFINITION: Java_cvc3_Expr_jniEquals jboolean c Expr expr1 c Expr expr2 return *expr1 == *expr2; DEFINITION: Java_cvc3_Expr_jniToString jstring c Expr expr return toJava(env, expr->toString()); DEFINITION: Java_cvc3_Expr_jniPrint void c Expr expr n string lang n bool dagify dagify ? expr->pprint() : expr->pprintnodag(); DEFINITION: Java_cvc3_Expr_jniHash jint c Expr expr return expr->hash(); DEFINITION: Java_cvc3_Expr_jniGetKind jstring c Expr expr return toJava(env, expr->getEM()->getKindName( expr->getKind() )); DEFINITION: Java_cvc3_Expr_jniIsFalse jboolean c Expr expr return expr->isFalse(); DEFINITION: Java_cvc3_Expr_jniIsTrue jboolean c Expr expr return expr->isTrue(); DEFINITION: Java_cvc3_Expr_jniIsBoolConst jboolean c Expr expr return expr->isBoolConst(); DEFINITION: Java_cvc3_Expr_jniIsVar jboolean c Expr expr return expr->isVar(); DEFINITION: Java_cvc3_Expr_jniIsBoundVar jboolean c Expr expr return expr->isBoundVar(); DEFINITION: Java_cvc3_Expr_jniIsString jboolean c Expr expr return expr->isString(); DEFINITION: Java_cvc3_Expr_jniIsClosure jboolean c Expr expr return expr->isClosure(); DEFINITION: Java_cvc3_Expr_jniIsQuantifier jboolean c Expr expr return expr->isQuantifier(); DEFINITION: Java_cvc3_Expr_jniIsLambda jboolean c Expr expr return expr->isLambda(); DEFINITION: Java_cvc3_Expr_jniIsApply jboolean c Expr expr return expr->isApply(); DEFINITION: Java_cvc3_Expr_jniIsSymbol jboolean c Expr expr return expr->isSymbol(); DEFINITION: Java_cvc3_Expr_jniIsTheorem jboolean c Expr expr return expr->isTheorem(); DEFINITION: Java_cvc3_Expr_jniIsType jboolean c Expr expr return expr->isType(); DEFINITION: Java_cvc3_Expr_jniIsTerm jboolean c Expr expr return expr->isTerm(); DEFINITION: Java_cvc3_Expr_jniIsAtomic jboolean c Expr expr return expr->isAtomic(); DEFINITION: Java_cvc3_Expr_jniIsAtomicFormula jboolean c Expr expr return expr->isAtomicFormula(); DEFINITION: Java_cvc3_Expr_jniIsAbsAtomicFormula jboolean c Expr expr return expr->isAbsAtomicFormula(); DEFINITION: Java_cvc3_Expr_jniIsLiteral jboolean c Expr expr return expr->isLiteral(); DEFINITION: Java_cvc3_Expr_jniIsAbsLiteral jboolean c Expr expr return expr->isAbsLiteral(); DEFINITION: Java_cvc3_Expr_jniIsBoolConnective jboolean c Expr expr return expr->isBoolConnective(); DEFINITION: Java_cvc3_Expr_jniIsPropAtom jboolean c Expr expr return expr->isPropAtom(); DEFINITION: Java_cvc3_Expr_jniIsPropLiteral jboolean c Expr expr return expr->isPropLiteral(); DEFINITION: Java_cvc3_Expr_jniIsArrayLiteral jboolean c Expr expr return CVC3::isArrayLiteral(*expr); DEFINITION: Java_cvc3_Expr_jniIsEq jboolean c Expr expr return expr->isEq(); DEFINITION: Java_cvc3_Expr_jniIsNot jboolean c Expr expr return expr->isNot(); DEFINITION: Java_cvc3_Expr_jniIsAnd jboolean c Expr expr return expr->isAnd(); DEFINITION: Java_cvc3_Expr_jniIsOr jboolean c Expr expr return expr->isOr(); DEFINITION: Java_cvc3_Expr_jniIsITE jboolean c Expr expr return expr->isITE(); DEFINITION: Java_cvc3_Expr_jniIsIff jboolean c Expr expr return expr->isIff(); DEFINITION: Java_cvc3_Expr_jniIsImpl jboolean c Expr expr return expr->isImpl(); DEFINITION: Java_cvc3_Expr_jniIsXor jboolean c Expr expr return expr->isXor(); DEFINITION: Java_cvc3_Expr_jniIsForall jboolean c Expr expr return expr->isForall(); DEFINITION: Java_cvc3_Expr_jniIsExists jboolean c Expr expr return expr->isExists(); DEFINITION: Java_cvc3_Expr_jniIsRational jboolean c Expr expr return expr->isRational(); DEFINITION: Java_cvc3_Expr_jniIsUminus jboolean c Expr expr return expr->getKind() == UMINUS; DEFINITION: Java_cvc3_Expr_jniIsPlus jboolean c Expr expr return expr->getKind() == PLUS; DEFINITION: Java_cvc3_Expr_jniIsMinus jboolean c Expr expr return expr->getKind() == MINUS; DEFINITION: Java_cvc3_Expr_jniIsMult jboolean c Expr expr return expr->getKind() == MULT; DEFINITION: Java_cvc3_Expr_jniIsPow jboolean c Expr expr return expr->getKind() == POW; DEFINITION: Java_cvc3_Expr_jniIsDivide jboolean c Expr expr return expr->getKind() == DIVIDE; DEFINITION: Java_cvc3_Expr_jniIsLt jboolean c Expr expr return expr->getKind() == LT; DEFINITION: Java_cvc3_Expr_jniIsLe jboolean c Expr expr return expr->getKind() == LE; DEFINITION: Java_cvc3_Expr_jniIsGt jboolean c Expr expr return expr->getKind() == GT; DEFINITION: Java_cvc3_Expr_jniIsGe jboolean c Expr expr return expr->getKind() == GE; DEFINITION: Java_cvc3_Expr_jniIsSkolem jboolean c Expr expr return expr->isSkolem(); DEFINITION: Java_cvc3_Expr_jniIsRead jboolean c Expr expr return expr->getKind() == READ; DEFINITION: Java_cvc3_Expr_jniIsWrite jboolean c Expr expr return expr->getKind() == WRITE; DEFINITION: Java_cvc3_Expr_jniGetName jstring c Expr expr return toJava(env, expr->getName()); DEFINITION: Java_cvc3_Expr_jniGetUid jstring c Expr expr return toJava(env, expr->getUid()); DEFINITION: Java_cvc3_Expr_jniGetString jstring c Expr expr return toJava(env, expr->getString()); DEFINITION: Java_cvc3_Expr_jniGetVars jobjectArray c Expr expr return toJavaVConstRef(env, expr->getVars()); DEFINITION: Java_cvc3_Expr_jniGetExistential jobject c Expr expr return embed_const_ref(env, &expr->getExistential()); DEFINITION: Java_cvc3_Expr_jniGetBoundIndex jint c Expr expr return expr->getBoundIndex(); DEFINITION: Java_cvc3_Expr_jniGetBody jobject c Expr expr return embed_const_ref(env, &expr->getBody()); DEFINITION: Java_cvc3_Expr_jniGetRational jobject c Expr expr return embed_const_ref(env, &expr->getRational()); DEFINITION: Java_cvc3_Expr_jniGetTriggers jobjectArray c Expr expr return toJavaVVConstRef(env, expr->getTriggers()); DEFINITION: Java_cvc3_Expr_jniGetTheorem jobject c Expr expr return embed_const_ref(env, &expr->getTheorem()); DEFINITION: Java_cvc3_Expr_jniGetType jobject c Expr expr return embed_copy(env, expr->getType()); DEFINITION: Java_cvc3_Expr_jniMkOp jobject c Expr expr return embed_copy(env, expr->mkOp()); DEFINITION: Java_cvc3_Expr_jniGetOp jobject c Expr expr return embed_copy(env, expr->getOp()); DEFINITION: Java_cvc3_Expr_jniGetOpExpr jobject c Expr expr return embed_copy(env, expr->getOpExpr()); DEFINITION: Java_cvc3_Expr_jniIsNull jboolean c Expr expr return expr->isNull(); DEFINITION: Java_cvc3_Expr_jniArity jint c Expr expr return expr->arity(); DEFINITION: Java_cvc3_Expr_jniGetKid jobject c Expr expr n int i return embed_const_ref(env, &((*expr)[ji])); DEFINITION: Java_cvc3_Expr_jniGetKids jobjectArray c Expr expr return toJavaVConstRef(env, expr->getKids()); DEFINITION: Java_cvc3_Expr_jniSubstExpr jobject c Expr e cv Expr oldExprs cv Expr newExprs return embed_copy(env, e->substExpr(oldExprs,newExprs)); DEFINITION: Java_cvc3_Expr_jniIsBvLt jboolean c Expr expr return expr->getKind() == BVLT; DEFINITION: Java_cvc3_Expr_jniIsBvLe jboolean c Expr expr return expr->getKind() == BVLE; DEFINITION: Java_cvc3_Expr_jniIsBvGt jboolean c Expr expr return expr->getKind() == BVGT; DEFINITION: Java_cvc3_Expr_jniIsBvGe jboolean c Expr expr return expr->getKind() == BVGE; DEFINITION: Java_cvc3_Expr_jniIsBvPlus jboolean c Expr expr return expr->getKind() == BVPLUS; DEFINITION: Java_cvc3_Expr_jniIsBvSub jboolean c Expr expr return expr->getKind() == BVSUB; DEFINITION: Java_cvc3_Expr_jniIsBvConst jboolean c Expr expr return expr->getKind() == BVCONST; DEFINITION: Java_cvc3_Expr_jniIsBvExtract jboolean c Expr expr return expr->getKind() == EXTRACT; DEFINITION: Java_cvc3_Expr_jniIsBvConcat jboolean c Expr expr return expr->getKind() == CONCAT; cvc3-2.4.1/java/src/cvc3/ExprManager_impl.cpp0000664000175400017540000000042511070741374020567 0ustar mdetersmdetersDEFINITION: Java_cvc3_ExprManager_jniGetInputLanguage jstring c ExprManager exprManager return toJava(env, exprManager->getInputLang()); DEFINITION: Java_cvc3_ExprManager_jniGetOutputLanguage jstring c ExprManager exprManager return toJava(env, exprManager->getOutputLang()); cvc3-2.4.1/java/src/cvc3/Rational_impl.cpp0000664000175400017540000000471711314036371020132 0ustar mdetersmdetersINCLUDE: DEFINITION: Java_cvc3_Rational_jniRational1 jobject n int n n int d return embed_copy(env, Rational(n, d)); DEFINITION: Java_cvc3_Rational_jniRational2 jobject n string n n int d return embed_copy(env, Rational(n, d)); DEFINITION: Java_cvc3_Rational_jniRational3 jobject n string n n string d n int base return embed_copy(env, Rational(n, d, base)); DEFINITION: Java_cvc3_Rational_jniEquals jboolean c Rational r1 c Rational r2 return *r1 == *r2; DEFINITION: Java_cvc3_Rational_jniToString jstring c Rational r return toJava(env, r->toString()); DEFINITION: Java_cvc3_Rational_jniHash jint c Rational r return r->hash(); DEFINITION: Java_cvc3_Rational_jniIsLt jboolean c Rational r1 c Rational r2 return *r1 < *r2; DEFINITION: Java_cvc3_Rational_jniIsLe jboolean c Rational r1 c Rational r2 return *r1 <= *r2; DEFINITION: Java_cvc3_Rational_jniIsGt jboolean c Rational r1 c Rational r2 return *r1 > *r2; DEFINITION: Java_cvc3_Rational_jniIsGe jboolean c Rational r1 c Rational r2 return *r1 >= *r2; DEFINITION: Java_cvc3_Rational_jniPlus jobject c Rational r1 c Rational r2 return embed_copy(env, *r1 + *r2); DEFINITION: Java_cvc3_Rational_jniMinus jobject c Rational r1 c Rational r2 return embed_copy(env, *r1 + *r2); DEFINITION: Java_cvc3_Rational_jniMult jobject c Rational r1 c Rational r2 return embed_copy(env, *r1 + *r2); DEFINITION: Java_cvc3_Rational_jniDivide jobject c Rational r1 c Rational r2 return embed_copy(env, *r1 + *r2); DEFINITION: Java_cvc3_Rational_jniMod jobject c Rational r1 c Rational r2 return embed_copy(env, *r1 % *r2); DEFINITION: Java_cvc3_Rational_jniGetNumerator jobject c Rational r return embed_copy(env, r->getNumerator()); DEFINITION: Java_cvc3_Rational_jniGetDenominator jobject c Rational r return embed_copy(env, r->getDenominator()); DEFINITION: Java_cvc3_Rational_jniIsInteger jboolean c Rational r return r->isInteger(); DEFINITION: Java_cvc3_Rational_jniGetInteger jint c Rational r return r->getInt(); DEFINITION: Java_cvc3_Rational_jniGcd jobject c Rational r1 c Rational r2 return embed_copy(env, gcd(*r1, *r2)); DEFINITION: Java_cvc3_Rational_jniLcm jobject c Rational r1 c Rational r2 return embed_copy(env, lcm(*r1, *r2)); DEFINITION: Java_cvc3_Rational_jniAbs jobject c Rational r return embed_copy(env, abs(*r)); DEFINITION: Java_cvc3_Rational_jniFloor jobject c Rational r return embed_copy(env, floor(*r)); DEFINITION: Java_cvc3_Rational_jniCeil jobject c Rational r return embed_copy(env, ceil(*r)); cvc3-2.4.1/java/src/cvc3/EvalException.java0000664000175400017540000000036511070741371020242 0ustar mdetersmdeterspackage cvc3; import java.util.*; /** mirrors CVC3::EvalException */ public class EvalException extends Cvc3Exception { private final static long serialVersionUID = 1L; public EvalException(String message) { super(message); } } cvc3-2.4.1/java/src/cvc3/StatisticsMut_impl.cpp0000664000175400017540000000000011070741372021161 0ustar mdetersmdeterscvc3-2.4.1/java/src/cvc3/OpMut_impl.cpp0000664000175400017540000000000011070741373017406 0ustar mdetersmdeterscvc3-2.4.1/java/src/cvc3/ContextMut_impl.cpp0000664000175400017540000000000011070741370020451 0ustar mdetersmdeterscvc3-2.4.1/java/src/cvc3/Embedded.java0000664000175400017540000000553511175701365017176 0ustar mdetersmdeterspackage cvc3; import java.util.*; import java.io.*; /** Wrapper for a c++ object as a java Object. see README for details on garbage collection, i.e. interplay of delete, finalize, and EmbeddedManager to destruct the embedded c++ object. */ public abstract class Embedded { // load jni c++ library static { System.loadLibrary("cvc3jni"); /* // for debugging: stop here by waiting for a key press, // and attach c++ debugger System.out.println("Loadded cvc3jni"); try { BufferedReader br = new BufferedReader(new InputStreamReader(System.in)); br.readLine(); } catch (IOException ioe) { } */ } /// Attributes // embedded object protected Object d_embedded; // embedded object manager private final EmbeddedManager d_embeddedManager; /// Constructor // initialize with embedded object and EmbeddedManager // if EmbeddedManager is null then delete must be called before // Embedded is garbage collected protected Embedded(Object Embedded, EmbeddedManager embeddedManager) { //System.out.println("Create: Embedded"); assert(Embedded != null); d_embedded = Embedded; d_embeddedManager = embeddedManager; } // access to embedded c++ object public synchronized Object embedded() { return d_embedded; } // access to EmbeddedManager (might be null if none used) public EmbeddedManager embeddedManager() { return d_embeddedManager; } // check if already destructed // (or queued for destruction in embeddedManager) public synchronized boolean isDeleted() { return (d_embedded == null); } // delete embedded object or enqueue it for deletion public synchronized void delete() throws Cvc3Exception { if (isDeleted()) return; // no embedded manager, so should be in main thread: // destruct right away if (d_embeddedManager == null) { EmbeddedManager.jniDelete(d_embedded); } // could be in finalizer, so queue in embeddedManager; // unless the embeddedManager is already deleted, // then its (and this') ValidityChecker has been delete. // assuming this is an Expr or a Theorem it's embedded object // has then already been deleted as well. else { synchronized(d_embeddedManager) { if (!d_embeddedManager.isDeleted()) { d_embeddedManager.register(this); } } } d_embedded = null; } // ensure that delete is called if finalization occurs public void finalize() throws Throwable { try { // no embeddedManager, so deleted should have been called if (d_embeddedManager == null) { if (d_embedded != null) { assert(false); // System.out.println("Embedded.Finalizer: should never be called"); throw new Error("Embedded.Finalizer: should never be called"); } } else if (!d_embeddedManager.isDeleted()) { delete(); } } finally { super.finalize(); } } } cvc3-2.4.1/java/src/cvc3/Cvc3Exception.java0000664000175400017540000000034011274366153020151 0ustar mdetersmdeterspackage cvc3; /** mirrors CVC3::Exception */ public class Cvc3Exception extends RuntimeException { private final static long serialVersionUID = 1L; public Cvc3Exception(String message) { super(message); } } cvc3-2.4.1/java/src/cvc3/ValidityChecker.java0000664000175400017540000017537611423601465020566 0ustar mdetersmdeterspackage cvc3; import java.util.*; import cvc3.Expr; import cvc3.JniUtils; public class ValidityChecker extends Embedded { // jni methods private static native Object jniCreate1() throws Cvc3Exception; private static native Object jniCreate2(Object Flags) throws Cvc3Exception; private static native Object jniCreateFlags() throws Cvc3Exception; private static native Object jniGetFlags(Object ValidityChecker) throws Cvc3Exception; private static native Object jniBoolType(Object ValidityChecker) throws Cvc3Exception; private static native Object jniRealType(Object ValidityChecker) throws Cvc3Exception; private static native Object jniIntType(Object ValidityChecker) throws Cvc3Exception; private static native Object jniSubrangeType(Object ValidityChecker, Object lExpr, Object rExpr) throws Cvc3Exception; private static native Object jniSubtypeType(Object ValidityChecker, Object predExpr, Object witnessExpr) throws Cvc3Exception; private static native Object jniTupleType1(Object ValidityChecker, Object Type0, Object Type1) throws Cvc3Exception; private static native Object jniTupleType2(Object ValidityChecker, Object Type0, Object Type1, Object Type2) throws Cvc3Exception; private static native Object jniTupleType3(Object ValidityChecker, Object[] Types) throws Cvc3Exception; private static native Object jniRecordType1(Object ValidityChecker, String field, Object Type) throws Cvc3Exception; private static native Object jniRecordType2(Object ValidityChecker, String field0, Object Type0, String field1, Object Type1) throws Cvc3Exception; private static native Object jniRecordType3(Object ValidityChecker, String field0, Object Type0, String field1, Object Type1, String field2, Object Type2) throws Cvc3Exception; private static native Object jniRecordType4(Object ValidityChecker, Object[] fields, Object[] types) throws Cvc3Exception; private static native Object jniDataType1(Object ValidityChecker, String name, String constructor, Object[] selectors, Object[] types) throws Cvc3Exception; private static native Object jniDataType2(Object ValidityChecker, String name, Object[] constructors, Object[] selectors, Object[] types) throws Cvc3Exception; private static native Object[] jniDataType3(Object ValidityChecker, Object[] names, Object[] constructors, Object[] selectors, Object[] types) throws Cvc3Exception; private static native Object jniAnyType(Object ValidityChecker) throws Cvc3Exception; private static native Object jniArrayLiteral(Object ValidityChecker, Object indexVar, Object bodyExpr) throws Cvc3Exception; private static native Object jniArrayType(Object ValidityChecker, Object TypeIndex, Object TypeData) throws Cvc3Exception; private static native Object jniBitvecType(Object ValidityChecker, int n) throws Cvc3Exception; private static native Object jniFunType1(Object ValidityChecker, Object typeDom, Object TypeRan) throws Cvc3Exception; private static native Object jniFunType2(Object ValidityChecker, Object[] typeDom, Object TypeRan) throws Cvc3Exception; private static native Object jniCreateType1(Object ValidityChecker, String typeName) throws Cvc3Exception; private static native Object jniCreateType2(Object ValidityChecker, String typeName, Object TypeDef) throws Cvc3Exception; private static native Object jniLookupType(Object ValidityChecker, String typeName) throws Cvc3Exception; private static native Object jniGetExprManager(Object ValidityChecker) throws Cvc3Exception; private static native Object jniNullExpr(Object ValidityChecker) throws Cvc3Exception; private static native Object jniVarExpr1(Object ValidityChecker, String name, Object Type) throws Cvc3Exception; private static native Object jniVarExpr2(Object ValidityChecker, String name, Object Type, Object defExpr) throws Cvc3Exception; private static native Object jniBoundVarExpr(Object ValidityChecker, String name, String uid, Object Type) throws Cvc3Exception; /*private static native Object jniBoundVarExpr2(Object ValidityChecker, Object Type) throws Cvc3Exception; */ private static native Object jniLookupVar(Object ValidityChecker, String name) throws Cvc3Exception; private static native Object jniLookupOp(Object ValidityChecker, String name) throws Cvc3Exception; private static native Object jniGetType(Object ValidityChecker, Object Expr) throws Cvc3Exception; private static native Object jniGetBaseType1(Object ValidityChecker, Object Expr) throws Cvc3Exception; private static native Object jniGetBaseType2(Object ValidityChecker, Object Type) throws Cvc3Exception; private static native Object jniGetTypePred(Object ValidityChecker, Object Type, Object Expr) throws Cvc3Exception; private static native Object jniStringExpr(Object ValidityChecker, String str) throws Cvc3Exception; private static native Object jniIdExpr(Object ValidityChecker, String name) throws Cvc3Exception; private static native Object jniListExpr1(Object ValidityChecker, Object[] kids) throws Cvc3Exception; private static native Object jniListExpr2(Object ValidityChecker, Object Expr1) throws Cvc3Exception; private static native Object jniListExpr3(Object ValidityChecker, Object Expr1, Object Expr2) throws Cvc3Exception; private static native Object jniListExpr4(Object ValidityChecker, Object Expr1, Object Expr2, Object Expr3) throws Cvc3Exception; private static native Object jniListExpr5(Object ValidityChecker, String op, Object[] kids) throws Cvc3Exception; private static native Object jniListExpr6(Object ValidityChecker, String op, Object Expr1) throws Cvc3Exception; private static native Object jniListExpr7(Object ValidityChecker, String op, Object Expr1, Object Expr2) throws Cvc3Exception; private static native Object jniListExpr8(Object ValidityChecker, String op, Object Expr1, Object Expr2, Object Expr3) throws Cvc3Exception; private static native void jniPrintExpr(Object ValidityChecker, Object Expr) throws Cvc3Exception; private static native Object jniParseExpr(Object ValidityChecker, Object Expr) throws Cvc3Exception; private static native Object jniParseType(Object ValidityChecker, Object Expr) throws Cvc3Exception; private static native Object jniImportExpr(Object ValidityChecker, Object Expr) throws Cvc3Exception; private static native Object jniImportType(Object ValidityChecker, Object Type) throws Cvc3Exception; private static native void jniCmdsFromString(Object ValidityChecker, String s) throws Cvc3Exception; private static native Object jniExprFromString(Object ValidityChecker, String s) throws Cvc3Exception; private static native Object jniTrueExpr(Object ValidityChecker) throws Cvc3Exception; private static native Object jniFalseExpr(Object ValidityChecker) throws Cvc3Exception; private static native Object jniNotExpr(Object ValidityChecker, Object Expr) throws Cvc3Exception; private static native Object jniAndExpr1(Object ValidityChecker, Object ExprLeft, Object ExprRight) throws Cvc3Exception; private static native Object jniAndExpr2(Object ValidityChecker, Object[] ExprChildren) throws Cvc3Exception; private static native Object jniOrExpr1(Object ValidityChecker, Object ExprLeft, Object ExprRight) throws Cvc3Exception; private static native Object jniOrExpr2(Object ValidityChecker, Object[] Exprchildren) throws Cvc3Exception; private static native Object jniImpliesExpr(Object ValidityChecker, Object ExprHyp, Object ExprConc) throws Cvc3Exception; private static native Object jniIffExpr(Object ValidityChecker, Object ExprLeft, Object ExprRight) throws Cvc3Exception; private static native Object jniEqExpr(Object ValidityChecker, Object Expr1, Object Expr2) throws Cvc3Exception; private static native Object jniDistinctExpr(Object ValidityChecker, Object[] ExprChildren) throws Cvc3Exception; private static native Object jniIteExpr(Object ValidityChecker, Object ExprIf, Object ExprThen, Object ExprElse) throws Cvc3Exception; private static native Object jniCreateOp1(Object ValidityChecker, String name, Object Type) throws Cvc3Exception; private static native Object jniCreateOp2(Object ValidityChecker, String name, Object Type, Object ExprDef) throws Cvc3Exception; private static native Object jniEqOp() throws Cvc3Exception; private static native Object jniLtOp() throws Cvc3Exception; private static native Object jniLeOp() throws Cvc3Exception; private static native Object jniGtOp() throws Cvc3Exception; private static native Object jniGeOp() throws Cvc3Exception; private static native Object jniPlusOp() throws Cvc3Exception; private static native Object jniMinusOp() throws Cvc3Exception; private static native Object jniMultOp() throws Cvc3Exception; private static native Object jniDivideOp() throws Cvc3Exception; private static native Object jniFunExpr1(Object ValidityChecker, Object Op, Object Expr) throws Cvc3Exception; private static native Object jniFunExpr2(Object ValidityChecker, Object Op, Object ExprLeft, Object ExprRight) throws Cvc3Exception; private static native Object jniFunExpr3(Object ValidityChecker, Object Op, Object Expr1, Object Expr2, Object Expr3) throws Cvc3Exception; private static native Object jniFunExpr4(Object ValidityChecker, Object Op, Object[] ExprChildren) throws Cvc3Exception; private static native Object jniRatExpr1(Object ValidityChecker, int n, int d) throws Cvc3Exception; private static native Object jniRatExpr2(Object ValidityChecker, String n, String d, int base) throws Cvc3Exception; private static native Object jniRatExpr3(Object ValidityChecker, String n, int base) throws Cvc3Exception; private static native Object jniUminusExpr(Object ValidityChecker, Object Expr) throws Cvc3Exception; private static native Object jniPlusExpr1(Object ValidityChecker, Object Exprleft, Object ExprRight) throws Cvc3Exception; private static native Object jniPlusExpr2(Object ValidityChecker, Object[] kids) throws Cvc3Exception; private static native Object jniMinusExpr(Object ValidityChecker, Object ExprLeft, Object ExprRight) throws Cvc3Exception; private static native Object jniMultExpr(Object ValidityChecker, Object ExprLeft, Object ExprRight) throws Cvc3Exception; private static native Object jniPowExpr(Object ValidityChecker, Object ExprX, Object ExprN) throws Cvc3Exception; private static native Object jniDivideExpr(Object ValidityChecker, Object ExprNumerator, Object ExprDenominator) throws Cvc3Exception; private static native Object jniLtExpr(Object ValidityChecker, Object ExprLeft, Object ExprRight) throws Cvc3Exception; private static native Object jniLeExpr(Object ValidityChecker, Object ExprLeft, Object ExprRight) throws Cvc3Exception; private static native Object jniGtExpr(Object ValidityChecker, Object ExprLeft, Object ExprRight) throws Cvc3Exception; private static native Object jniGeExpr(Object ValidityChecker, Object ExprLeft, Object ExprRight) throws Cvc3Exception; private static native Object jniRecordExpr1(Object ValidityChecker, String field, Object Expr) throws Cvc3Exception; private static native Object jniRecordExpr2(Object ValidityChecker, String field1, Object Expr1, String field2, Object Expr2) throws Cvc3Exception; private static native Object jniRecordExpr3(Object ValidityChecker, String field1, Object Expr1, String field2, Object Expr2, String field3, Object Expr3) throws Cvc3Exception; private static native Object jniRecordExpr4(Object ValidityChecker, Object[] StringFields, Object[] Exprs) throws Cvc3Exception; private static native Object jniRecSelectExpr(Object ValidityChecker, Object ExprRecord, String field) throws Cvc3Exception; private static native Object jniRecUpdateExpr(Object ValidityChecker, Object ExprRecord, String field, Object ExprNewValue) throws Cvc3Exception; private static native Object jniReadExpr(Object ValidityChecker, Object ExprArray, Object ExprIndex) throws Cvc3Exception; private static native Object jniWriteExpr(Object ValidityChecker, Object ExprArray, Object ExprIndex, Object ExprNewValue) throws Cvc3Exception; private static native Object jniNewBVConstExpr1(Object ValidityChecker, String s, int base) throws Cvc3Exception; private static native Object jniNewBVConstExpr2(Object ValidityChecker, boolean[] bits) throws Cvc3Exception; private static native Object jniNewBVConstExpr3(Object ValidityChecker, Object RationalR, int len) throws Cvc3Exception; private static native Object jniNewConcatExpr1(Object ValidityChecker, Object Expr1, Object Expr2) throws Cvc3Exception; private static native Object jniNewConcatExpr2(Object ValidityChecker, Object[] Exprkids) throws Cvc3Exception; private static native Object jniNewBVExtractExpr(Object ValidityChecker, Object ExprE, int hi, int low) throws Cvc3Exception; private static native Object jniNewBVNegExpr(Object ValidityChecker, Object Expr1) throws Cvc3Exception; private static native Object jniNewBVAndExpr1(Object ValidityChecker, Object Expr1, Object Expr2) throws Cvc3Exception; private static native Object jniNewBVAndExpr2(Object ValidityChecker, Object[] ExprKids) throws Cvc3Exception; private static native Object jniNewBVOrExpr1(Object ValidityChecker, Object Expr1, Object Expr2) throws Cvc3Exception; private static native Object jniNewBVOrExpr2(Object ValidityChecker, Object[] ExprKids) throws Cvc3Exception; private static native Object jniNewBVXorExpr1(Object ValidityChecker, Object Expr1, Object Expr2) throws Cvc3Exception; private static native Object jniNewBVXorExpr2(Object ValidityChecker, Object[] ExprKids) throws Cvc3Exception; private static native Object jniNewBVXnorExpr1(Object ValidityChecker, Object Expr1, Object Expr2) throws Cvc3Exception; private static native Object jniNewBVXnorExpr2(Object ValidityChecker, Object[] ExprKids) throws Cvc3Exception; private static native Object jniNewBVNandExpr(Object ValidityChecker, Object Expr1, Object Expr2) throws Cvc3Exception; private static native Object jniNewBVNorExpr(Object ValidityChecker, Object Expr1, Object Expr2) throws Cvc3Exception; private static native Object jniNewBVLTExpr(Object ValidityChecker, Object Expr1, Object Expr2) throws Cvc3Exception; private static native Object jniNewBVLEExpr(Object ValidityChecker, Object Expr1, Object Expr2) throws Cvc3Exception; private static native Object jniNewBVSLTExpr(Object ValidityChecker, Object Expr1, Object Expr2) throws Cvc3Exception; private static native Object jniNewBVSLEExpr(Object ValidityChecker, Object Expr1, Object Expr2) throws Cvc3Exception; private static native Object jniNewSXExpr(Object ValidityChecker, Object Expr1, int len) throws Cvc3Exception; private static native Object jniNewBVUminusExpr(Object ValidityChecker, Object Expr) throws Cvc3Exception; private static native Object jniNewBVSubExpr(Object ValidityChecker, Object Expr1, Object Expr2) throws Cvc3Exception; private static native Object jniNewBVPlusExpr(Object ValidityChecker, int numbits, Object[] ExprK) throws Cvc3Exception; private static native Object jniNewBVMultExpr(Object ValidityChecker, int numbits, Object Expr1, Object Expr2) throws Cvc3Exception; private static native Object jniNewBVUDivExpr(Object ValidityChecker, Object left, Object right) throws Cvc3Exception; private static native Object jniNewBVURemExpr(Object ValidityChecker, Object left, Object right) throws Cvc3Exception; private static native Object jniNewBVSDivExpr(Object ValidityChecker, Object left, Object right) throws Cvc3Exception; private static native Object jniNewBVSRemExpr(Object ValidityChecker, Object left, Object right) throws Cvc3Exception; private static native Object jniNewBVSModExpr(Object ValidityChecker, Object left, Object right) throws Cvc3Exception; private static native Object jniNewBVSHL(Object ValidityChecker, Object left, Object right) throws Cvc3Exception; private static native Object jniNewBVLSHR(Object ValidityChecker, Object left, Object right) throws Cvc3Exception; private static native Object jniNewBVASHR(Object ValidityChecker, Object left, Object right) throws Cvc3Exception; private static native Object jniNewFixedLeftShiftExpr(Object ValidityChecker, Object Expr1, int r) throws Cvc3Exception; private static native Object jniNewFixedConstWidthLeftShiftExpr(Object ValidityChecker, Object Expr1, int r) throws Cvc3Exception; private static native Object jniNewFixedRightShiftExpr(Object ValidityChecker, Object Expr1, int r) throws Cvc3Exception; private static native Object jniComputeBVConst(Object ValidityChecker, Object Expr) throws Cvc3Exception; private static native Object jniTupleExpr(Object ValidityChecker, Object[] Exprs) throws Cvc3Exception; private static native Object jniTupleSelectExpr(Object ValidityChecker, Object ExprTuple, int index) throws Cvc3Exception; private static native Object jniTupleUpdateExpr(Object ValidityChecker, Object ExprTuple, int index, Object ExprNewValue) throws Cvc3Exception; private static native Object jniDatatypeConsExpr(Object ValidityChecker, String constructor, Object[] ExprArgs) throws Cvc3Exception; private static native Object jniDatatypeSelExpr(Object ValidityChecker, String selector, Object ExprArg) throws Cvc3Exception; private static native Object jniDatatypeTestExpr(Object ValidityChecker, String constructor, Object ExprArg) throws Cvc3Exception; private static native Object jniForallExpr1(Object ValidityChecker, Object[] ExprVars, Object ExprBody) throws Cvc3Exception; private static native Object jniForallExpr2(Object ValidityChecker, Object[] ExprVars, Object ExprBody, Object ExprTrigger) throws Cvc3Exception; private static native Object jniForallExpr3(Object ValidityChecker, Object[] ExprVars, Object ExprBody, Object[] ExprTriggers) throws Cvc3Exception; private static native Object jniForallExpr4(Object ValidityChecker, Object[] ExprVars, Object ExprBody, Object[][] ExprTriggers) throws Cvc3Exception; private static native void jniSetTrigger(Object ValidityChecker, Object ExprClosure, Object ExprTrigger) throws Cvc3Exception; private static native void jniSetTriggers(Object ValidityChecker, Object ExprClosure, Object[] ExprTriggers) throws Cvc3Exception; private static native void jniSetTriggers2(Object ValidityChecker, Object ExprClosure, Object[][] ExprTriggers) throws Cvc3Exception; private static native void jniSetMultiTrigger(Object ValidityChecker, Object ExprClosure, Object[] ExprMultiTrigger) throws Cvc3Exception; private static native Object jniExistsExpr(Object ValidityChecker, Object[] ExprVars, Object ExprBody) throws Cvc3Exception; private static native Object jniLambdaExpr(Object ValidityChecker, Object[] ExprVars, Object ExprBody) throws Cvc3Exception; private static native Object jniTransClosure(Object ValidityChecker, Object Op) throws Cvc3Exception; private static native Object jniSimulateExpr(Object ValidityChecker, Object ExprF, Object ExprS, Object[] ExprInputs, Object ExprN) throws Cvc3Exception; private static native void jniSetResourceLimit(Object ValidityChecker, int limit) throws Cvc3Exception; private static native void jniAssertFormula(Object ValidityChecker, Object Expr) throws Cvc3Exception; private static native void jniRegisterAtom(Object ValidityChecker, Object Expr) throws Cvc3Exception; private static native Object jniGetImpliedLiteral(Object ValidityChecker) throws Cvc3Exception; private static native Object jniSimplify(Object ValidityChecker, Object Expr) throws Cvc3Exception; private static native String jniQuery(Object ValidityChecker, Object Expr) throws Cvc3Exception; private static native String jniCheckUnsat(Object ValidityChecker, Object Expr) throws Cvc3Exception; private static native String jniCheckContinue(Object ValidityChecker) throws Cvc3Exception; private static native String jniRestart(Object ValidityChecker, Object Expr) throws Cvc3Exception; private static native void jniReturnFromCheck(Object ValidityChecker) throws Cvc3Exception; private static native Object[] jniGetUserAssumptions(Object ValidityChecker) throws Cvc3Exception; private static native Object[] jniGetInternalAssumptions(Object ValidityChecker) throws Cvc3Exception; private static native Object[] jniGetAssumptions(Object ValidityChecker) throws Cvc3Exception; private static native Object[] jniGetAssumptionsUsed(Object ValidityChecker) throws Cvc3Exception; private static native Object[] jniGetCounterExample(Object ValidityChecker, boolean inOrder) throws Cvc3Exception; private static native Object[] jniGetConcreteModel(Object ValidityChecker) throws Cvc3Exception; private static native String jniGetValue(Object ValidityChecker, Object Expr) throws Cvc3Exception; private static native boolean jniInconsistent1(Object ValidityChecker) throws Cvc3Exception; private static native Object[] jniInconsistent2(Object ValidityChecker) throws Cvc3Exception; private static native boolean jniIncomplete1(Object ValidityChecker) throws Cvc3Exception; private static native Object[] jniIncomplete2(Object ValidityChecker) throws Cvc3Exception; private static native Object jniGetProof(Object ValidityChecker) throws Cvc3Exception; private static native Object jniGetTCC(Object ValidityChecker) throws Cvc3Exception; private static native Object[] jniGetAssumptionsTCC(Object ValidityChecker) throws Cvc3Exception; private static native Object jniGetProofTCC(Object ValidityChecker) throws Cvc3Exception; private static native Object jniGetClosure(Object ValidityChecker) throws Cvc3Exception; private static native Object jniGetProofClosure(Object ValidityChecker) throws Cvc3Exception; private static native int jniStackLevel(Object ValidityChecker) throws Cvc3Exception; private static native void jniPush(Object ValidityChecker) throws Cvc3Exception; private static native void jniPop(Object ValidityChecker) throws Cvc3Exception; private static native void jniPopTo(Object ValidityChecker, int stackLevel) throws Cvc3Exception; private static native int jniScopeLevel(Object ValidityChecker) throws Cvc3Exception; private static native void jniPushScope(Object ValidityChecker) throws Cvc3Exception; private static native void jniPopScope(Object ValidityChecker) throws Cvc3Exception; private static native void jniPopToScope(Object ValidityChecker, int scopeLevel) throws Cvc3Exception; private static native Object jniGetCurrentContext(Object ValidityChecker) throws Cvc3Exception; private static native void jniLoadFile1(Object ValidityChecker, String fileName, String lang) throws Cvc3Exception; private static native Object jniGetStatistics(Object ValidityChecker) throws Cvc3Exception; private static native void jniPrintStatistics(Object ValidityChecker) throws Cvc3Exception; private static native void jniSetTimeLimit(Object ValidityChecker, int limit) throws Cvc3Exception; // delete ValidityChecker, all expressions created using it, // and all embedded objects registered with its embeddedManager public synchronized void delete() throws Cvc3Exception { if (isDeleted()) return; //:TEST: embeddedManager().cleanUp(); embeddedManager().delete(); EmbeddedManager.jniDelete(embedded()); d_embedded = null; } // ensure that all embedded objects are deallocated eventually public void finalize() throws Throwable { try { if (!isDeleted()) { assert(false); // System.out.println("ValidityChecker.Finalizer: should never be called"); throw new Error("ValidityChecker.Finalizer: should never be called"); } } finally { super.finalize(); } } /// Constructor // create embedded object protected ValidityChecker(Object ValidityChecker) { super(ValidityChecker, new EmbeddedManager()); } /// API: ValidityChecker // Creation // delete must be called before ValidityChecker is garbage collected public static ValidityChecker create() throws Cvc3Exception { return new ValidityChecker(jniCreate1()); } // delete must be called before ValidityChecker is garbage collected public static ValidityChecker create(Flags flags) throws Cvc3Exception { return new ValidityChecker(jniCreate2(flags.embedded())); } // Flags // if embeddedManger is null then delete must be called before // the returned Flags is garbage collected public static FlagsMut createFlags(EmbeddedManager embeddedManager) throws Cvc3Exception { return new FlagsMut(jniCreateFlags(), embeddedManager); } public FlagsMut getFlags() throws Cvc3Exception { return new FlagsMut(jniGetFlags(embedded()), embeddedManager()); } // Type-related methods public TypeMut boolType() throws Cvc3Exception { return new TypeMut(jniBoolType(embedded()), embeddedManager()); } public TypeMut realType() throws Cvc3Exception { return new TypeMut(jniRealType(embedded()), embeddedManager()); } public TypeMut intType() throws Cvc3Exception { return new TypeMut(jniIntType(embedded()), embeddedManager()); } public TypeMut subrangeType(Expr l, Expr r) throws Cvc3Exception { return new TypeMut( jniSubrangeType(embedded(), l.embedded(), r.embedded()), embeddedManager()); } public TypeMut subtypeType(Expr pred, Expr witness) throws Cvc3Exception { return new TypeMut( jniSubtypeType(embedded(), pred.embedded(), witness.embedded()), embeddedManager()); } public TypeMut tupleType(Type type0, Type type1) throws Cvc3Exception { return new TypeMut( jniTupleType1(embedded(), type0.embedded(), type1.embedded()), embeddedManager()); } public TypeMut tupleType(Type type0, Type type1, Type type2) throws Cvc3Exception { return new TypeMut( jniTupleType2(embedded(), type0.embedded(), type1.embedded(), type2.embedded()), embeddedManager()); } public TypeMut tupleType(List types) throws Cvc3Exception { return new TypeMut( jniTupleType3(embedded(), JniUtils.unembedList(types)), embeddedManager()); } public TypeMut recordType(String field, Type type) throws Cvc3Exception { return new TypeMut( jniRecordType1(embedded(), field, type.embedded()), embeddedManager()); } public TypeMut recordType(String field0, Type type0, String field1, Type type1) throws Cvc3Exception { return new TypeMut( jniRecordType2(embedded(), field0, type0.embedded(), field1, type1.embedded()), embeddedManager()); } public TypeMut recordType(String field0, Type type0, String field1, Type type1, String field2, Type type2) throws Cvc3Exception { return new TypeMut( jniRecordType3(embedded(), field0, type0.embedded(), field1, type1.embedded(), field2, type2.embedded()), embeddedManager()); } public TypeMut recordType(List fields, List types) throws Cvc3Exception { assert(JniUtils.listInstanceof(fields, String.class)); return new TypeMut( jniRecordType4(embedded(), JniUtils.toArray(fields), JniUtils.unembedList(types)), embeddedManager()); } public TypeMut dataType(String name, String constructor, List selectors, List types) throws Cvc3Exception { assert(JniUtils.listInstanceof(selectors, String.class)); assert(JniUtils.listInstanceof(types, Expr.class)); return new TypeMut( jniDataType1(embedded(), name, constructor, JniUtils.toArray(selectors), JniUtils.unembedList(types)), embeddedManager()); } public TypeMut dataType(String name, String[] constructors, String[][] selectors, Expr[][] types) throws Cvc3Exception { return new TypeMut( jniDataType2(embedded(), name, constructors, selectors, JniUtils.unembedArrayArray(types)), embeddedManager()); } public TypeMut dataType(String name, List constructors, List selectors, List types) throws Cvc3Exception { assert(JniUtils.listInstanceof(constructors, String.class)); assert(JniUtils.listListInstanceof(selectors, String.class)); assert(JniUtils.listListInstanceof(types, Expr.class)); return new TypeMut( jniDataType2(embedded(), name, JniUtils.toArray(constructors), JniUtils.toArrayArray(selectors), JniUtils.unembedListList(types)), embeddedManager()); } public List dataType(List names, List constructors, List selectors, List types) throws Cvc3Exception { assert(JniUtils.listInstanceof(names, String.class)); assert(JniUtils.listListInstanceof(constructors, String.class)); assert(JniUtils.listListListInstanceof(selectors, String.class)); assert(JniUtils.listListListInstanceof(types, Expr.class)); Object[] dataTypes = jniDataType3(embedded(), JniUtils.toArray(names), JniUtils.toArrayArray(constructors), JniUtils.toArrayArrayArray(selectors), JniUtils.unembedListListList(types)); return JniUtils.embedList(dataTypes, TypeMut.class, embeddedManager()); } public ExprMut arrayLiteral(Expr var, Expr body) throws Cvc3Exception { return new ExprMut(jniArrayLiteral(embedded(), var.embedded(), body.embedded()),embeddedManager()); } public TypeMut anyType() throws Cvc3Exception { return new TypeMut(jniAnyType(embedded()),embeddedManager()); } public TypeMut arrayType(Type typeIndex, Type typeData) throws Cvc3Exception { return new TypeMut( jniArrayType(embedded(), typeIndex.embedded(), typeData.embedded()), embeddedManager()); } public TypeMut bitvecType(int n) throws Cvc3Exception { return new TypeMut( jniBitvecType(embedded(), n), embeddedManager()); } public TypeMut funType(Type typeDom, Type typeRange) throws Cvc3Exception { return new TypeMut( jniFunType1(embedded(), typeDom.embedded(), typeRange.embedded()), embeddedManager()); } public TypeMut funType(List typeDom, Type typeRange) throws Cvc3Exception { assert(JniUtils.listInstanceof(typeDom, Type.class)); return new TypeMut( jniFunType2(embedded(), JniUtils.unembedList(typeDom), typeRange.embedded()), embeddedManager()); } public TypeMut createType(String typeName) throws Cvc3Exception { return new TypeMut( jniCreateType1(embedded(), typeName), embeddedManager()); } public TypeMut createType(String typeName, Type typeDef) throws Cvc3Exception { return new TypeMut( jniCreateType2(embedded(), typeName, typeDef.embedded()), embeddedManager()); } public TypeMut lookupType(String typeName) throws Cvc3Exception { return new TypeMut( jniLookupType(embedded(), typeName), embeddedManager()); } // Expressions public ExprManagerMut getExprManager() throws Cvc3Exception { return new ExprManagerMut(jniGetExprManager(embedded()), embeddedManager()); } public Expr nullExpr() throws Cvc3Exception { return new Expr(jniNullExpr(embedded()), embeddedManager()); } public ExprMut varExpr(String name, Type type) throws Cvc3Exception { return new ExprMut( jniVarExpr1(embedded(), name, type.embedded()), embeddedManager()); } public ExprMut varExpr(String name, Type type, Expr def) throws Cvc3Exception { return new ExprMut( jniVarExpr2(embedded(), name, type.embedded(), def.embedded()), embeddedManager()); } public ExprMut boundVarExpr(String name, String uid, Type type) throws Cvc3Exception { return new ExprMut( jniBoundVarExpr(embedded(), name, uid, type.embedded()), embeddedManager()); } /* public ExprMut boundVarExpr(Type type) throws Cvc3Exception { return new ExprMut( jniBoundVarExpr(embedded(), type.embedded()), embeddedManager()); }*/ public ExprMut lookupVar(String name) throws Cvc3Exception { return new ExprMut( jniLookupVar(embedded(), name), embeddedManager()); } public OpMut lookupOp(String name) throws Cvc3Exception { return new OpMut( jniLookupOp(embedded(), name), embeddedManager()); } public TypeMut getType(Expr expr) throws Cvc3Exception { return new TypeMut( jniGetType(embedded(), expr.embedded()), embeddedManager()); } public TypeMut getBaseType(Expr expr) throws Cvc3Exception { return new TypeMut( jniGetBaseType1(embedded(), expr.embedded()), embeddedManager()); } public TypeMut getBaseType(Type type) throws Cvc3Exception { return new TypeMut( jniGetBaseType2(embedded(), type.embedded()), embeddedManager()); } public ExprMut getTypePred(Type type, Expr expr) throws Cvc3Exception { return new ExprMut( jniGetTypePred(embedded(), type.embedded(), expr.embedded()), embeddedManager()); } public ExprMut stringExpr(String str) throws Cvc3Exception { return new ExprMut( jniStringExpr(embedded(), str), embeddedManager()); } public ExprMut idExpr(String name) throws Cvc3Exception { return new ExprMut( jniIdExpr(embedded(), name), embeddedManager()); } public ExprMut listExpr(List kids) throws Cvc3Exception { assert(JniUtils.listInstanceof(kids, Expr.class)); return new ExprMut( jniListExpr1(embedded(), JniUtils.unembedList(kids)), embeddedManager()); } public ExprMut listExpr(Expr expr1) throws Cvc3Exception { return new ExprMut( jniListExpr2(embedded(), expr1.embedded()), embeddedManager()); } public ExprMut listExpr(Expr expr1, Expr expr2) throws Cvc3Exception { return new ExprMut( jniListExpr3(embedded(), expr1.embedded(), expr2.embedded()), embeddedManager()); } public ExprMut listExpr(Expr expr1, Expr expr2, Expr expr3) throws Cvc3Exception { return new ExprMut( jniListExpr4(embedded(), expr1.embedded(), expr2.embedded(), expr3.embedded()), embeddedManager()); } public ExprMut listExpr(String op, List kids) throws Cvc3Exception { assert(JniUtils.listInstanceof(kids, Expr.class)); return new ExprMut( jniListExpr5(embedded(), op, JniUtils.unembedList(kids)), embeddedManager()); } public ExprMut listExpr(String op, Expr expr1) throws Cvc3Exception { return new ExprMut( jniListExpr6(embedded(), op, expr1.embedded()), embeddedManager()); } public ExprMut listExpr(String op, Expr expr1, Expr expr2) throws Cvc3Exception { return new ExprMut( jniListExpr7(embedded(), op, expr1.embedded(), expr2.embedded()), embeddedManager()); } public ExprMut listExpr(String op, Expr expr1, Expr expr2, Expr expr3) throws Cvc3Exception { return new ExprMut( jniListExpr8(embedded(), op, expr1.embedded(), expr2.embedded(), expr3.embedded()), embeddedManager()); } public void printExpr(Expr expr) throws Cvc3Exception { jniPrintExpr(embedded(), expr.embedded()); } public ExprMut parseExpr(Expr expr) throws Cvc3Exception { return new ExprMut( jniParseExpr(embedded(), expr.embedded()), embeddedManager()); } public TypeMut parseType(Expr expr) throws Cvc3Exception { return new TypeMut( jniParseType(embedded(), expr.embedded()), embeddedManager()); } public ExprMut importExpr(Expr expr) throws Cvc3Exception { return new ExprMut( jniImportExpr(embedded(), expr.embedded()), embeddedManager()); } public TypeMut importType(Type type) throws Cvc3Exception { return new TypeMut( jniImportType(embedded(), type.embedded()), embeddedManager()); } public void cmdsFromString(String s) throws Cvc3Exception { jniCmdsFromString(embedded(), s); } public ExprMut exprFromString(String s) throws Cvc3Exception { return new ExprMut( jniExprFromString(embedded(), s), embeddedManager() ); } public ExprMut trueExpr() throws Cvc3Exception { return new ExprMut(jniTrueExpr(embedded()), embeddedManager()); } public ExprMut falseExpr() throws Cvc3Exception { return new ExprMut(jniFalseExpr(embedded()), embeddedManager()); } public ExprMut notExpr(Expr expr) throws Cvc3Exception { return new ExprMut( jniNotExpr(embedded(), expr.embedded()), embeddedManager()); } public ExprMut andExpr(Expr expr1, Expr expr2) throws Cvc3Exception { return new ExprMut( jniAndExpr1(embedded(), expr1.embedded(), expr2.embedded()), embeddedManager()); } public ExprMut andExpr(List children) throws Cvc3Exception { assert(JniUtils.listInstanceof(children, Expr.class)); return new ExprMut( jniAndExpr2(embedded(), JniUtils.unembedList(children)), embeddedManager()); } public ExprMut orExpr(Expr expr1, Expr expr2) throws Cvc3Exception { return new ExprMut( jniOrExpr1(embedded(), expr1.embedded(), expr2.embedded()), embeddedManager()); } public ExprMut orExpr(List children) throws Cvc3Exception { assert(JniUtils.listInstanceof(children, Expr.class)); return new ExprMut( jniOrExpr2(embedded(), JniUtils.unembedList(children)), embeddedManager()); } public ExprMut impliesExpr(Expr hyp, Expr conc) throws Cvc3Exception { return new ExprMut( jniImpliesExpr(embedded(), hyp.embedded(), conc.embedded()), embeddedManager()); } public ExprMut iffExpr(Expr left, Expr right) throws Cvc3Exception { return new ExprMut( jniIffExpr(embedded(), left.embedded(), right.embedded()), embeddedManager()); } public ExprMut eqExpr(Expr left, Expr right) throws Cvc3Exception { return new ExprMut( jniEqExpr(embedded(), left.embedded(), right.embedded()), embeddedManager()); } public ExprMut distinctExpr(List children) throws Cvc3Exception { assert(JniUtils.listInstanceof(children, Expr.class)); return new ExprMut( jniDistinctExpr(embedded(), JniUtils.unembedList(children)), embeddedManager()); } public ExprMut iteExpr(Expr ifPart, Expr thenPart, Expr elsePart) throws Cvc3Exception { return new ExprMut( jniIteExpr(embedded(), ifPart.embedded(), thenPart.embedded(), elsePart.embedded()), embeddedManager()); } public OpMut createOp(String name, Type type) throws Cvc3Exception { return new OpMut( jniCreateOp1(embedded(), name, type.embedded()), embeddedManager()); } public OpMut createOp(String name, Type type, Expr expr) throws Cvc3Exception { return new OpMut( jniCreateOp2(embedded(), name, type.embedded(), expr.embedded()), embeddedManager()); } // '=' public OpMut eqOp() throws Cvc3Exception { return new OpMut(jniEqOp(), embeddedManager()); } // '<' public OpMut ltOp() throws Cvc3Exception { return new OpMut(jniLtOp(), embeddedManager()); } // '<=' public OpMut leOp() throws Cvc3Exception { return new OpMut(jniLeOp(), embeddedManager()); } // '>' public OpMut gtOp() throws Cvc3Exception { return new OpMut(jniGtOp(), embeddedManager()); } // '>=' public OpMut geOp() throws Cvc3Exception { return new OpMut(jniGeOp(), embeddedManager()); } // '+' public OpMut plusOp() throws Cvc3Exception { return new OpMut(jniPlusOp(), embeddedManager()); } // '-' public OpMut minusOp() throws Cvc3Exception { return new OpMut(jniMinusOp(), embeddedManager()); } // '*' public OpMut multOp() throws Cvc3Exception { return new OpMut(jniMultOp(), embeddedManager()); } // '/' for rationals public OpMut divideOp() throws Cvc3Exception { return new OpMut(jniDivideOp(), embeddedManager()); } public ExprMut funExpr(Op op, Expr expr1) throws Cvc3Exception { return new ExprMut( jniFunExpr1(embedded(), op.embedded(), expr1.embedded()), embeddedManager()); } public ExprMut funExpr(Op op, Expr expr1, Expr expr2) throws Cvc3Exception { return new ExprMut( jniFunExpr2(embedded(), op.embedded(), expr1.embedded(), expr2.embedded()), embeddedManager()); } public ExprMut funExpr(Op op, Expr expr1, Expr expr2, Expr expr3) throws Cvc3Exception { return new ExprMut( jniFunExpr3(embedded(), op.embedded(), expr1.embedded(), expr2.embedded(), expr3.embedded()), embeddedManager()); } public ExprMut funExpr(Op op, List children) throws Cvc3Exception { assert(JniUtils.listInstanceof(children, Expr.class)); return new ExprMut( jniFunExpr4(embedded(), op.embedded(), JniUtils.unembedList(children)), embeddedManager()); } public ExprMut ratExpr(int n) throws Cvc3Exception { return ratExpr(n, 1); } public ExprMut ratExpr(int n, int d) throws Cvc3Exception { return new ExprMut( jniRatExpr1(embedded(), n, d), embeddedManager()); } public ExprMut ratExpr(String n, String d, int base) throws Cvc3Exception { return new ExprMut( jniRatExpr2(embedded(), n, d, base), embeddedManager()); } public ExprMut ratExpr(String n) throws Cvc3Exception { return ratExpr(n, 10); } public ExprMut ratExpr(String n, int base) throws Cvc3Exception { return new ExprMut( jniRatExpr3(embedded(), n, base), embeddedManager()); } public ExprMut uminusExpr(Expr expr) throws Cvc3Exception { return new ExprMut( jniUminusExpr(embedded(), expr.embedded()), embeddedManager()); } public ExprMut plusExpr(Expr left, Expr right) throws Cvc3Exception { return new ExprMut( jniPlusExpr1(embedded(), left.embedded(), right.embedded()), embeddedManager()); } public ExprMut plusExpr(List kids) throws Cvc3Exception { return new ExprMut( jniPlusExpr2(embedded(), JniUtils.unembedList(kids)), embeddedManager()); } public ExprMut minusExpr(Expr left, Expr right) throws Cvc3Exception { return new ExprMut( jniMinusExpr(embedded(), left.embedded(), right.embedded()), embeddedManager()); } public ExprMut multExpr(Expr left, Expr right) throws Cvc3Exception { return new ExprMut( jniMultExpr(embedded(), left.embedded(), right.embedded()), embeddedManager()); } public ExprMut powExpr(Expr x, Expr n) throws Cvc3Exception { return new ExprMut( jniPowExpr(embedded(), x.embedded(), n.embedded()), embeddedManager()); } public ExprMut divideExpr(Expr numerator, Expr denominator) throws Cvc3Exception { return new ExprMut( jniDivideExpr(embedded(), numerator.embedded(), denominator.embedded()), embeddedManager()); } public ExprMut ltExpr(Expr left, Expr right) throws Cvc3Exception { return new ExprMut( jniLtExpr(embedded(), left.embedded(), right.embedded()), embeddedManager()); } public ExprMut leExpr(Expr left, Expr right) throws Cvc3Exception { return new ExprMut( jniLeExpr(embedded(), left.embedded(), right.embedded()), embeddedManager()); } public ExprMut gtExpr(Expr left, Expr right) throws Cvc3Exception { return new ExprMut( jniGtExpr(embedded(), left.embedded(), right.embedded()), embeddedManager()); } public ExprMut geExpr(Expr left, Expr right) throws Cvc3Exception { return new ExprMut( jniGeExpr(embedded(), left.embedded(), right.embedded()), embeddedManager()); } public ExprMut recordExpr(String field, Expr expr) throws Cvc3Exception { return new ExprMut( jniRecordExpr1(embedded(), field, expr.embedded()), embeddedManager()); } public ExprMut recordExpr(String field1, Expr expr1, String field2, Expr expr2) throws Cvc3Exception { return new ExprMut( jniRecordExpr2(embedded(), field1, expr1.embedded(), field2, expr2.embedded()), embeddedManager()); } public ExprMut recordExpr(String field1, Expr expr1, String field2, Expr expr2, String field3, Expr expr3) throws Cvc3Exception { return new ExprMut( jniRecordExpr3(embedded(), field1, expr1.embedded(), field2, expr2.embedded(), field3, expr3.embedded()), embeddedManager()); } public ExprMut recordExpr(List fields, List exprs) throws Cvc3Exception { assert(JniUtils.listInstanceof(fields, String.class)); assert(JniUtils.listInstanceof(exprs, Expr.class)); return new ExprMut( jniRecordExpr4(embedded(), JniUtils.toArray(fields), JniUtils.unembedList(exprs)), embeddedManager()); } public ExprMut recSelectExpr(Expr record, String field) throws Cvc3Exception { return new ExprMut( jniRecSelectExpr(embedded(), record.embedded(), field), embeddedManager()); } public ExprMut recUpdateExpr(Expr record, String field, Expr newValue) throws Cvc3Exception { return new ExprMut( jniRecUpdateExpr(embedded(), record.embedded(), field, newValue.embedded()), embeddedManager()); } public ExprMut readExpr(Expr array, Expr index) throws Cvc3Exception { return new ExprMut( jniReadExpr(embedded(), array.embedded(), index.embedded()), embeddedManager()); } public ExprMut writeExpr(Expr array, Expr index, Expr newValue) throws Cvc3Exception { return new ExprMut( jniWriteExpr(embedded(), array.embedded(), index.embedded(), newValue.embedded()), embeddedManager()); } public ExprMut newBVConstExpr(String s) throws Cvc3Exception { return newBVConstExpr(s, 2); } public ExprMut newBVConstExpr(String s, int base) throws Cvc3Exception { return new ExprMut( jniNewBVConstExpr1(embedded(), s, base), embeddedManager()); } public ExprMut newBVConstExpr(boolean[] bits) throws Cvc3Exception { return new ExprMut( jniNewBVConstExpr2(embedded(), bits), embeddedManager()); } public ExprMut newBVConstExpr(Rational r, int len) throws Cvc3Exception { return new ExprMut( jniNewBVConstExpr3(embedded(), r.embedded(), len), embeddedManager()); } public ExprMut newConcatExpr(Expr expr1, Expr expr2) throws Cvc3Exception { return new ExprMut( jniNewConcatExpr1(embedded(), expr1.embedded(), expr2.embedded()), embeddedManager()); } public ExprMut newConcatExpr(List kids) throws Cvc3Exception { assert(JniUtils.listInstanceof(kids, Expr.class)); return new ExprMut( jniNewConcatExpr2(embedded(), JniUtils.unembedList(kids)), embeddedManager()); } public ExprMut newBVExtractExpr(Expr e, int hi, int low) throws Cvc3Exception { return new ExprMut( jniNewBVExtractExpr(embedded(), e.embedded(), hi, low), embeddedManager()); } public ExprMut newBVNegExpr(Expr expr) throws Cvc3Exception { return new ExprMut( jniNewBVNegExpr(embedded(), expr.embedded()), embeddedManager()); } public ExprMut newBVAndExpr(Expr expr1, Expr expr2) throws Cvc3Exception { return new ExprMut( jniNewBVAndExpr1(embedded(), expr1.embedded(), expr2.embedded()), embeddedManager()); } public ExprMut newBVAndExpr(List kids) throws Cvc3Exception { assert(JniUtils.listInstanceof(kids, Expr.class)); return new ExprMut( jniNewBVAndExpr2(embedded(), JniUtils.unembedList(kids)), embeddedManager()); } public ExprMut newBVOrExpr(Expr expr1, Expr expr2) throws Cvc3Exception { return new ExprMut( jniNewBVOrExpr1(embedded(), expr1.embedded(), expr2.embedded()), embeddedManager()); } public ExprMut newBVOrExpr(List kids) throws Cvc3Exception { assert(JniUtils.listInstanceof(kids, Expr.class)); return new ExprMut( jniNewBVOrExpr2(embedded(), JniUtils.unembedList(kids)), embeddedManager()); } public ExprMut newBVXorExpr(Expr expr1, Expr expr2) throws Cvc3Exception { return new ExprMut( jniNewBVXorExpr1(embedded(), expr1.embedded(), expr2.embedded()), embeddedManager()); } public ExprMut newBVXorExpr(List kids) throws Cvc3Exception { assert(JniUtils.listInstanceof(kids, Expr.class)); return new ExprMut( jniNewBVXorExpr2(embedded(), JniUtils.unembedList(kids)), embeddedManager()); } public ExprMut newBVXnorExpr(Expr expr1, Expr expr2) throws Cvc3Exception { return new ExprMut( jniNewBVXnorExpr1(embedded(), expr1.embedded(), expr2.embedded()), embeddedManager()); } public ExprMut newBVXnorExpr(List kids) throws Cvc3Exception { assert(JniUtils.listInstanceof(kids, Expr.class)); return new ExprMut( jniNewBVXnorExpr2(embedded(), JniUtils.unembedList(kids)), embeddedManager()); } public ExprMut newBVNandExpr(Expr expr1, Expr expr2) throws Cvc3Exception { return new ExprMut( jniNewBVNandExpr(embedded(), expr1.embedded(), expr2.embedded()), embeddedManager()); } public ExprMut newBVNorExpr(Expr expr1, Expr expr2) throws Cvc3Exception { return new ExprMut( jniNewBVNorExpr(embedded(), expr1.embedded(), expr2.embedded()), embeddedManager()); } public ExprMut newBVLTExpr(Expr expr1, Expr expr2) throws Cvc3Exception { return new ExprMut( jniNewBVLTExpr(embedded(), expr1.embedded(), expr2.embedded()), embeddedManager()); } public ExprMut newBVLEExpr(Expr expr1, Expr expr2) throws Cvc3Exception { return new ExprMut( jniNewBVLEExpr(embedded(), expr1.embedded(), expr2.embedded()), embeddedManager()); } public ExprMut newBVSLTExpr(Expr expr1, Expr expr2) throws Cvc3Exception { return new ExprMut( jniNewBVSLTExpr(embedded(), expr1.embedded(), expr2.embedded()), embeddedManager()); } public ExprMut newBVSLEExpr(Expr expr1, Expr expr2) throws Cvc3Exception { return new ExprMut( jniNewBVSLEExpr(embedded(), expr1.embedded(), expr2.embedded()), embeddedManager()); } public ExprMut newSXExpr(Expr expr, int len) throws Cvc3Exception { return new ExprMut( jniNewSXExpr(embedded(), expr.embedded(), len), embeddedManager()); } public ExprMut newBVUminusExpr(Expr expr) throws Cvc3Exception { return new ExprMut( jniNewBVUminusExpr(embedded(), expr.embedded()), embeddedManager()); } public ExprMut newBVSubExpr(Expr expr1, Expr expr2) throws Cvc3Exception { return new ExprMut( jniNewBVSubExpr(embedded(), expr1.embedded(), expr2.embedded()), embeddedManager()); } public ExprMut newBVPlusExpr(int numbits, List exprs) throws Cvc3Exception { assert(JniUtils.listInstanceof(exprs, Expr.class)); return new ExprMut( jniNewBVPlusExpr(embedded(), numbits, JniUtils.unembedList(exprs)), embeddedManager()); } public ExprMut newBVMultExpr(int numbits, Expr expr1, Expr expr2) throws Cvc3Exception { return new ExprMut( jniNewBVMultExpr(embedded(), numbits, expr1.embedded(), expr2.embedded()), embeddedManager()); } public ExprMut newBVUDivExpr(Expr left, Expr right) throws Cvc3Exception { return new ExprMut( jniNewBVUDivExpr(embedded(), left.embedded(), right.embedded()), embeddedManager()); } public ExprMut newBVURemExpr(Expr left, Expr right) throws Cvc3Exception { return new ExprMut( jniNewBVURemExpr(embedded(), left.embedded(), right.embedded()), embeddedManager()); } public ExprMut newBVSDivExpr(Expr left, Expr right) throws Cvc3Exception { return new ExprMut( jniNewBVSDivExpr(embedded(), left.embedded(), right.embedded()), embeddedManager()); } public ExprMut newBVSRemExpr(Expr left, Expr right) throws Cvc3Exception { return new ExprMut( jniNewBVSRemExpr(embedded(), left.embedded(), right.embedded()), embeddedManager()); } public ExprMut newBVSModExpr(Expr left, Expr right) throws Cvc3Exception { return new ExprMut( jniNewBVSModExpr(embedded(), left.embedded(), right.embedded()), embeddedManager()); } public ExprMut newBVSHL(Expr left, Expr right) throws Cvc3Exception { return new ExprMut( jniNewBVSHL(embedded(), left.embedded(), right.embedded()), embeddedManager()); } public ExprMut newBVLSHR(Expr left, Expr right) throws Cvc3Exception { return new ExprMut( jniNewBVLSHR(embedded(), left.embedded(), right.embedded()), embeddedManager()); } public ExprMut newBVASHR(Expr left, Expr right) throws Cvc3Exception { return new ExprMut( jniNewBVASHR(embedded(), left.embedded(), right.embedded()), embeddedManager()); } public ExprMut newFixedLeftShiftExpr(Expr expr, int r) throws Cvc3Exception { return new ExprMut( jniNewFixedLeftShiftExpr(embedded(), expr.embedded(), r), embeddedManager()); } public ExprMut newFixedConstWidthLeftShiftExpr(Expr expr, int r) throws Cvc3Exception { return new ExprMut( jniNewFixedConstWidthLeftShiftExpr(embedded(), expr.embedded(), r), embeddedManager()); } public ExprMut newFixedRightShiftExpr(Expr expr, int r) throws Cvc3Exception { return new ExprMut( jniNewFixedRightShiftExpr(embedded(), expr.embedded(), r), embeddedManager()); } public Rational computeBVConst(Expr expr) { Rational rat = new Rational( jniComputeBVConst(embedded(),expr.embedded()), embeddedManager()); assert( rat.isInteger() ); return rat; } public ExprMut tupleExpr(List exprs) throws Cvc3Exception { assert(JniUtils.listInstanceof(exprs, Expr.class)); return new ExprMut( jniTupleExpr(embedded(), JniUtils.unembedList(exprs)), embeddedManager()); } public ExprMut tupleSelectExpr(Expr tuple, int index) throws Cvc3Exception { return new ExprMut( jniTupleSelectExpr(embedded(), tuple.embedded(), index), embeddedManager()); } public ExprMut tupleUpdateExpr(Expr tuple, int index, Expr newValue) throws Cvc3Exception { return new ExprMut( jniTupleUpdateExpr(embedded(), tuple.embedded(), index, newValue.embedded()), embeddedManager()); } public ExprMut datatypeConsExpr(String constructor, List exprs) throws Cvc3Exception { assert(JniUtils.listInstanceof(exprs, Expr.class)); return new ExprMut( jniDatatypeConsExpr(embedded(), constructor, JniUtils.unembedList(exprs)), embeddedManager()); } public ExprMut datatypeSelExpr(String selector, Expr arg) throws Cvc3Exception { return new ExprMut( jniDatatypeSelExpr(embedded(), selector, arg.embedded()), embeddedManager()); } public ExprMut datatypeTestExpr(String constructor, Expr arg) throws Cvc3Exception { return new ExprMut( jniDatatypeTestExpr(embedded(), constructor, arg.embedded()), embeddedManager()); } public ExprMut forallExpr(List vars, Expr body) throws Cvc3Exception { assert(JniUtils.listInstanceof(vars, Expr.class)); return new ExprMut( jniForallExpr1(embedded(), JniUtils.unembedList(vars), body.embedded()), embeddedManager()); } public ExprMut forallExpr(List vars, Expr body, Expr trigger) throws Cvc3Exception { assert(JniUtils.listInstanceof(vars, Expr.class)); return new ExprMut( jniForallExpr2(embedded(), JniUtils.unembedList(vars), body.embedded(), trigger.embedded()), embeddedManager()); } public ExprMut forallExpr(List vars, Expr body, List triggers) throws Cvc3Exception { assert(JniUtils.listInstanceof(vars, Expr.class)); assert(JniUtils.listInstanceof(triggers, Expr.class)); return new ExprMut( jniForallExpr3(embedded(), JniUtils.unembedList(vars), body.embedded(), JniUtils.unembedList(triggers)), embeddedManager()); } public ExprMut forallExprMultiTriggers(List vars, Expr body, List multiTriggers) throws Cvc3Exception { assert (JniUtils.listInstanceof(vars, Expr.class)); assert (JniUtils.listListInstanceof(multiTriggers, Expr.class)); return new ExprMut(jniForallExpr4(embedded(), JniUtils.unembedList(vars), body.embedded(), JniUtils.unembedListList(multiTriggers)), embeddedManager()); } public void setTrigger(Expr closure, Expr trigger) throws Cvc3Exception { jniSetTrigger(embedded(), closure.embedded(), trigger.embedded()); } public void setTriggers(Expr closure, List triggers) throws Cvc3Exception { jniSetTriggers(embedded(), closure.embedded(), JniUtils.unembedList(triggers)); } public void setMultiTrigger(Expr closure, List multiTrigger) throws Cvc3Exception { jniSetMultiTrigger(embedded(), closure.embedded(), JniUtils.unembedList(multiTrigger)); } public void setMultiTriggers(Expr closure, List triggers) throws Cvc3Exception { jniSetTriggers2(embedded(), closure.embedded(), JniUtils.unembedListList(triggers)); } public ExprMut existsExpr(List vars, Expr body) throws Cvc3Exception { assert(JniUtils.listInstanceof(vars, Expr.class)); return new ExprMut( jniExistsExpr(embedded(), JniUtils.unembedList(vars), body.embedded()), embeddedManager()); } public OpMut lambdaExpr(List vars, Expr body) throws Cvc3Exception { assert(JniUtils.listInstanceof(vars, Expr.class)); return new OpMut( jniLambdaExpr(embedded(), JniUtils.unembedList(vars), body.embedded()), embeddedManager()); } public OpMut transClosure(Op p) throws Cvc3Exception { return new OpMut( jniTransClosure(embedded(), p.embedded()), embeddedManager()); } public ExprMut simulateExpr(Expr f, Expr s, List inputs, Expr n) throws Cvc3Exception { assert(JniUtils.listInstanceof(inputs, Expr.class)); return new ExprMut( jniSimulateExpr(embedded(), f.embedded(), s.embedded(), JniUtils.unembedList(inputs), n.embedded()), embeddedManager()); } public void setResourceLimit(int limit) throws Cvc3Exception { jniSetResourceLimit(embedded(), limit); } // Validity checking methods public void assertFormula(Expr expr) throws Cvc3Exception { embeddedManager().cleanUp(); jniAssertFormula(embedded(), expr.embedded()); embeddedManager().cleanUp(); } public void registerAtom(Expr expr) throws Cvc3Exception { jniRegisterAtom(embedded(), expr.embedded()); } public ExprMut getImpliedLiteral() throws Cvc3Exception { return new ExprMut( jniGetImpliedLiteral(embedded()), embeddedManager()); } public ExprMut simplify(Expr expr) throws Cvc3Exception { return new ExprMut( jniSimplify(embedded(), expr.embedded()), embeddedManager()); } public QueryResult query(Expr expr) throws Cvc3Exception { embeddedManager().cleanUp(); QueryResult result = QueryResult.get(jniQuery(embedded(), expr.embedded())); //:TEST: embeddedManager().cleanUp(); return result; } public SatResult checkUnsat(Expr expr) throws Cvc3Exception { embeddedManager().cleanUp(); SatResult result = SatResult.get(jniCheckUnsat(embedded(), expr.embedded())); //:TEST: embeddedManager().cleanUp(); return result; } public QueryResult checkContinue() throws Cvc3Exception { embeddedManager().cleanUp(); QueryResult result = QueryResult.get(jniCheckContinue(embedded())); //:TEST: embeddedManager().cleanUp(); return result; } public QueryResult restart(Expr expr) throws Cvc3Exception { embeddedManager().cleanUp(); QueryResult result = QueryResult.get(jniRestart(embedded(), expr.embedded())); //:TEST: embeddedManager().cleanUp(); return result; } public void returnFromCheck() throws Cvc3Exception { jniReturnFromCheck(embedded()); //:TEST: embeddedManager().cleanUp(); } public List getUserAssumptions() throws Cvc3Exception { Object[] assumptions = jniGetUserAssumptions(embedded()); return JniUtils.embedList(assumptions, ExprMut.class, embeddedManager()); } public List getInternalAssumptions() throws Cvc3Exception { Object[] assumptions = jniGetInternalAssumptions(embedded()); return JniUtils.embedList(assumptions, ExprMut.class, embeddedManager()); } public List getAssumptions() throws Cvc3Exception { Object[] assumptions = jniGetAssumptions(embedded()); return JniUtils.embedList(assumptions, ExprMut.class, embeddedManager()); } public List getAssumptionsUsed() throws Cvc3Exception { Object[] assumptions = jniGetAssumptionsUsed(embedded()); return JniUtils.embedList(assumptions, ExprMut.class, embeddedManager()); } public List getCounterExample() throws Cvc3Exception { return getCounterExample(true); } public List getCounterExample(boolean inOrder) throws Cvc3Exception { Object[] assumptions = jniGetCounterExample(embedded(), inOrder); return JniUtils.embedList(assumptions, ExprMut.class, embeddedManager()); } public HashMap getConcreteModel() throws Cvc3Exception { Object[] model = jniGetConcreteModel(embedded()); return JniUtils.embedHashMap(model, Expr.class, Expr.class, embeddedManager()); } public FormulaValue getValue(Expr expr) throws Cvc3Exception { return FormulaValue.get(jniGetValue(embedded(), expr.embedded())); } public boolean inconsistent() throws Cvc3Exception { return jniInconsistent1(embedded()); } // makes only sense if inconsistent is true public List inconsistentReasons() throws Cvc3Exception { Object[] assumptions = jniInconsistent2(embedded()); return JniUtils.embedList(assumptions, ExprMut.class, embeddedManager()); } public boolean incomplete() throws Cvc3Exception { return jniIncomplete1(embedded()); } // makes only sense if incomplete is true public List incompleteReasons() throws Cvc3Exception { Object[] assumptions = jniIncomplete2(embedded()); return JniUtils.embedList(assumptions, String.class, embeddedManager()); } public ProofMut getProof() throws Cvc3Exception { return new ProofMut( jniGetProof(embedded()), embeddedManager()); } public ExprMut getTCC() throws Cvc3Exception { return new ExprMut( jniGetTCC(embedded()), embeddedManager()); } public List getAssumptionsTCC() throws Cvc3Exception { Object[] assumptions = jniGetAssumptionsTCC(embedded()); return JniUtils.embedList(assumptions, ExprMut.class, embeddedManager()); } public ProofMut getProofTCC() throws Cvc3Exception { return new ProofMut( jniGetProofTCC(embedded()), embeddedManager()); } public ExprMut getClosure() throws Cvc3Exception { return new ExprMut( jniGetClosure(embedded()), embeddedManager()); } public ProofMut getProofClosure() throws Cvc3Exception { return new ProofMut( jniGetProofClosure(embedded()), embeddedManager()); } // Context Methods public int stackLevel() throws Cvc3Exception { return jniStackLevel(embedded()); } public void push() throws Cvc3Exception { jniPush(embedded()); } public void pop() throws Cvc3Exception { jniPop(embedded()); //:TEST: embeddedManager().cleanUp(); } public void popTo(int stackLevel) throws Cvc3Exception { jniPopTo(embedded(), stackLevel); //:TEST: embeddedManager().cleanUp(); } public int scopeLevel() throws Cvc3Exception { return jniScopeLevel(embedded()); } public void pushScope() throws Cvc3Exception { jniPushScope(embedded()); } public void popScope() throws Cvc3Exception { jniPopScope(embedded()); } public void popToScope(int scopeLevel) throws Cvc3Exception { jniPopToScope(embedded(), scopeLevel); } public ContextMut getCurrentContext() throws Cvc3Exception { return new ContextMut( jniGetCurrentContext(embedded()), embeddedManager()); } // Reading Files public void loadFile(String fileName) throws Cvc3Exception { loadFile(fileName, InputLanguage.PRESENTATION); } public void loadFile(String fileName, InputLanguage lang) throws Cvc3Exception { jniLoadFile1(embedded(), fileName, lang.toString()); } // Reporting Statistics public void printStatistics() throws Cvc3Exception { jniPrintStatistics(embedded()); } public StatisticsMut getStatistics() throws Cvc3Exception { return new StatisticsMut( jniGetStatistics(embedded()), embeddedManager()); } public void setTimeLimit(int limit) throws Cvc3Exception { jniSetTimeLimit(embedded(), limit); } } cvc3-2.4.1/java/src/cvc3/SoundException.java0000664000175400017540000000037011070741367020444 0ustar mdetersmdeterspackage cvc3; import java.util.*; /** mirrors CVC3::SoundException */ public class SoundException extends Cvc3Exception { private final static long serialVersionUID = 1L; public SoundException(String message) { super(message); } } cvc3-2.4.1/java/src/cvc3/Flag.java0000664000175400017540000000334111070741366016346 0ustar mdetersmdeterspackage cvc3; import java.util.*; public class Flag extends Embedded { // jni methods private static native boolean jniIsNull(Object Flag) throws Cvc3Exception; private static native boolean jniIsBool(Object Flag) throws Cvc3Exception; private static native boolean jniIsInt(Object Flag) throws Cvc3Exception; private static native boolean jniIsString(Object Flag) throws Cvc3Exception; private static native boolean jniIsStringVec(Object Flag) throws Cvc3Exception; private static native boolean jniGetBool(Object Flag) throws Cvc3Exception; private static native int jniGetInt(Object Flag) throws Cvc3Exception; private static native String jniGetString(Object Flag) throws Cvc3Exception; private static native String jniGetHelp(Object Flag) throws Cvc3Exception; /// Constructor // create embedded object public Flag(Object Flag, EmbeddedManager embeddedManager) { super(Flag, embeddedManager); } /// API immutable boolean isNull() throws Cvc3Exception { return jniIsNull(embedded()); } boolean isBool() throws Cvc3Exception { return jniIsBool(embedded()); } boolean isInt() throws Cvc3Exception { return jniIsInt(embedded()); } boolean isString() throws Cvc3Exception { return jniIsString(embedded()); } boolean isStringVec() throws Cvc3Exception { return jniIsStringVec(embedded()); } boolean getBool() throws Cvc3Exception { return jniGetBool(embedded()); } int getInt() throws Cvc3Exception { return jniGetInt(embedded()); } String getString() throws Cvc3Exception { return jniGetString(embedded()); } String getHelp() throws Cvc3Exception { return jniGetHelp(embedded()); } } cvc3-2.4.1/java/src/cvc3/RationalMut_impl.cpp0000664000175400017540000000000011070741372020600 0ustar mdetersmdeterscvc3-2.4.1/java/src/cvc3/Proof.java0000664000175400017540000000037011070741365016560 0ustar mdetersmdeterspackage cvc3; import java.util.*; public class Proof extends Embedded { // jni methods /// Constructor public Proof(Object Proof, EmbeddedManager embeddedManager) { super(Proof, embeddedManager); } /// API (immutable) } cvc3-2.4.1/java/src/cvc3/ExprMut_impl.cpp0000664000175400017540000000000011070741373017746 0ustar mdetersmdeterscvc3-2.4.1/java/src/cvc3/ValidityChecker_impl.cpp0000664000175400017540000007451311423601466021440 0ustar mdetersmdetersINCLUDE: INCLUDE: INCLUDE: DEFINITION: Java_cvc3_ValidityChecker_jniCreate1 jobject return embed_own(env, VCL::create()); DEFINITION: Java_cvc3_ValidityChecker_jniCreate2 jobject c CLFlags flags return embed_own(env, VCL::create(*flags)); DEFINITION: Java_cvc3_ValidityChecker_jniCreateFlags jobject return embed_copy(env, ValidityChecker::createFlags()); DEFINITION: Java_cvc3_ValidityChecker_jniGetFlags jobject c ValidityChecker vc return embed_mut_ref(env, &vc->getFlags()); DEFINITION: Java_cvc3_ValidityChecker_jniBoolType jobject m ValidityChecker vc return embed_copy(env, vc->boolType()); DEFINITION: Java_cvc3_ValidityChecker_jniRealType jobject m ValidityChecker vc return embed_copy(env, vc->realType()); DEFINITION: Java_cvc3_ValidityChecker_jniIntType jobject m ValidityChecker vc return embed_copy(env, vc->intType()); DEFINITION: Java_cvc3_ValidityChecker_jniSubrangeType jobject m ValidityChecker vc c Expr l c Expr r return embed_copy(env, vc->subrangeType(*l, *r)); DEFINITION: Java_cvc3_ValidityChecker_jniSubtypeType jobject m ValidityChecker vc c Expr pred c Expr witness return embed_copy(env, vc->subtypeType(*pred, *witness)); DEFINITION: Java_cvc3_ValidityChecker_jniTupleType1 jobject m ValidityChecker vc c Type type0 c Type type1 return embed_copy(env, vc->tupleType(*type0, *type1)); DEFINITION: Java_cvc3_ValidityChecker_jniTupleType2 jobject m ValidityChecker vc c Type type0 c Type type1 c Type type2 return embed_copy(env, vc->tupleType(*type0, *type1, *type2)); DEFINITION: Java_cvc3_ValidityChecker_jniTupleType3 jobject m ValidityChecker vc cv Type types return embed_copy(env, vc->tupleType(types)); DEFINITION: Java_cvc3_ValidityChecker_jniRecordType1 jobject m ValidityChecker vc n string field c Type type return embed_copy(env, vc->recordType(field, *type)); DEFINITION: Java_cvc3_ValidityChecker_jniRecordType2 jobject m ValidityChecker vc n string field0 c Type type0 n string field1 c Type type1 return embed_copy(env, vc->recordType(field0, *type0, field1, *type1)); DEFINITION: Java_cvc3_ValidityChecker_jniRecordType3 jobject m ValidityChecker vc n string field0 c Type type0 n string field1 c Type type1 n string field2 c Type type2 return embed_copy(env, vc->recordType(field0, *type0, field1, *type1, field2, *type2)); DEFINITION: Java_cvc3_ValidityChecker_jniRecordType4 jobject m ValidityChecker vc nv string fields cv Type types return embed_copy(env, vc->recordType(fields, types)); DEFINITION: Java_cvc3_ValidityChecker_jniDataType1 jobject m ValidityChecker vc n string name n string constructor nv string selectors cv Expr types return embed_copy(env, vc->dataType(name, constructor, selectors, types)); DEFINITION: Java_cvc3_ValidityChecker_jniDataType2 jobject m ValidityChecker vc n string name nv string constructors nvv string selectors cvv Expr types return embed_copy(env, vc->dataType(name, constructors, selectors, types)); DEFINITION: Java_cvc3_ValidityChecker_jniDataType3 jobjectArray m ValidityChecker vc nv string names nvv string constructors nvvv string selectors cvvv Expr types vector result; vc->dataType(names, constructors, selectors, types, result); return toJavaVCopy(env, result); DEFINITION: Java_cvc3_ValidityChecker_jniAnyType jobject m ValidityChecker vc return embed_copy(env, Type::anyType(vc->getEM())); DEFINITION: Java_cvc3_ValidityChecker_jniArrayLiteral jobject m ValidityChecker vc c Expr indexVar c Expr bodyExpr return embed_copy(env, CVC3::arrayLiteral(*indexVar, *bodyExpr)); DEFINITION: Java_cvc3_ValidityChecker_jniArrayType jobject m ValidityChecker vc c Type typeIndex c Type typeData return embed_copy(env, vc->arrayType(*typeIndex, *typeData)); DEFINITION: Java_cvc3_ValidityChecker_jniBitvecType jobject m ValidityChecker vc n int n return embed_copy(env, vc->bitvecType(n)); DEFINITION: Java_cvc3_ValidityChecker_jniFunType1 jobject m ValidityChecker vc c Type typeDom c Type typeRange return embed_copy(env, vc->funType(*typeDom, *typeRange)); DEFINITION: Java_cvc3_ValidityChecker_jniFunType2 jobject m ValidityChecker vc cv Type typeDom c Type typeRange return embed_copy(env, vc->funType(typeDom, *typeRange)); DEFINITION: Java_cvc3_ValidityChecker_jniCreateType1 jobject m ValidityChecker vc n string typeName return embed_copy(env, vc->createType(typeName)); DEFINITION: Java_cvc3_ValidityChecker_jniCreateType2 jobject m ValidityChecker vc n string typeName c Type typeDef return embed_copy(env, vc->createType(typeName, *typeDef)); DEFINITION: Java_cvc3_ValidityChecker_jniLookupType jobject m ValidityChecker vc n string typeName return embed_copy(env, vc->lookupType(typeName)); DEFINITION: Java_cvc3_ValidityChecker_jniGetExprManager jobject m ValidityChecker vc return embed_mut_ref(env, vc->getEM()); DEFINITION: Java_cvc3_ValidityChecker_jniNullExpr jobject m ValidityChecker vc return embed_copy(env, Expr()); DEFINITION: Java_cvc3_ValidityChecker_jniVarExpr1 jobject m ValidityChecker vc n string name c Type type return embed_copy(env, vc->varExpr(name, *type)); DEFINITION: Java_cvc3_ValidityChecker_jniVarExpr2 jobject m ValidityChecker vc n string name c Type type c Expr def return embed_copy(env, vc->varExpr(name, *type, *def)); DEFINITION: Java_cvc3_ValidityChecker_jniBoundVarExpr jobject m ValidityChecker vc n string name n string uid c Type type return embed_copy(env, vc->boundVarExpr(name, uid, *type)); DEFINITION: Java_cvc3_ValidityChecker_jniLookupVar jobject m ValidityChecker vc n string name Type* type = new Type; jobject result = embed_copy(env, vc->lookupVar(name, type)); delete type; return result; DEFINITION: Java_cvc3_ValidityChecker_jniLookupOp jobject m ValidityChecker vc n string name Type* type = new Type; jobject result = embed_copy(env, vc->lookupOp(name, type)); delete type; return result; DEFINITION: Java_cvc3_ValidityChecker_jniGetType jobject m ValidityChecker vc c Expr expr return embed_copy(env, vc->getType(*expr)); DEFINITION: Java_cvc3_ValidityChecker_jniGetBaseType1 jobject m ValidityChecker vc c Expr expr return embed_copy(env, vc->getBaseType(*expr)); DEFINITION: Java_cvc3_ValidityChecker_jniGetBaseType2 jobject m ValidityChecker vc c Type type return embed_copy(env, vc->getBaseType(*type)); DEFINITION: Java_cvc3_ValidityChecker_jniGetTypePred jobject m ValidityChecker vc c Type type c Expr expr return embed_copy(env, vc->getTypePred(*type, *expr)); DEFINITION: Java_cvc3_ValidityChecker_jniStringExpr jobject m ValidityChecker vc n string str return embed_copy(env, vc->stringExpr(str)); DEFINITION: Java_cvc3_ValidityChecker_jniIdExpr jobject m ValidityChecker vc n string name return embed_copy(env, vc->idExpr(name)); DEFINITION: Java_cvc3_ValidityChecker_jniListExpr1 jobject m ValidityChecker vc cv Expr kids return embed_copy(env, vc->listExpr(kids)); DEFINITION: Java_cvc3_ValidityChecker_jniListExpr2 jobject m ValidityChecker vc c Expr expr1 return embed_copy(env, vc->listExpr(*expr1)); DEFINITION: Java_cvc3_ValidityChecker_jniListExpr3 jobject m ValidityChecker vc c Expr expr1 c Expr expr2 return embed_copy(env, vc->listExpr(*expr1, *expr2)); DEFINITION: Java_cvc3_ValidityChecker_jniListExpr4 jobject m ValidityChecker vc c Expr expr1 c Expr expr2 c Expr expr3 return embed_copy(env, vc->listExpr(*expr1, *expr2, *expr3)); DEFINITION: Java_cvc3_ValidityChecker_jniListExpr5 jobject m ValidityChecker vc n string op cv Expr kids return embed_copy(env, vc->listExpr(op, kids)); DEFINITION: Java_cvc3_ValidityChecker_jniListExpr6 jobject m ValidityChecker vc n string op c Expr expr1 return embed_copy(env, vc->listExpr(op, *expr1)); DEFINITION: Java_cvc3_ValidityChecker_jniListExpr7 jobject m ValidityChecker vc n string op c Expr expr1 c Expr expr2 return embed_copy(env, vc->listExpr(op, *expr1, *expr2)); DEFINITION: Java_cvc3_ValidityChecker_jniListExpr8 jobject m ValidityChecker vc n string op c Expr expr1 c Expr expr2 c Expr expr3 return embed_copy(env, vc->listExpr(op, *expr1, *expr2, *expr3)); DEFINITION: Java_cvc3_ValidityChecker_jniPrintExpr void m ValidityChecker vc c Expr expr vc->printExpr(*expr); DEFINITION: Java_cvc3_ValidityChecker_jniParseExpr jobject m ValidityChecker vc c Expr expr return embed_copy(env, vc->parseExpr(*expr)); DEFINITION: Java_cvc3_ValidityChecker_jniParseType jobject m ValidityChecker vc c Expr expr return embed_copy(env, vc->parseType(*expr)); DEFINITION: Java_cvc3_ValidityChecker_jniImportExpr jobject m ValidityChecker vc c Expr expr return embed_copy(env, vc->importExpr(*expr)); DEFINITION: Java_cvc3_ValidityChecker_jniImportType jobject m ValidityChecker vc c Type type return embed_copy(env, vc->importType(*type)); DEFINITION: Java_cvc3_ValidityChecker_jniCmdsFromString void m ValidityChecker vc n string s vc->cmdsFromString(s); DEFINITION: Java_cvc3_ValidityChecker_jniExprFromString jobject m ValidityChecker vc n string s return embed_copy(env, vc->exprFromString(s)); DEFINITION: Java_cvc3_ValidityChecker_jniTrueExpr jobject m ValidityChecker vc return embed_copy(env, vc->trueExpr()); DEFINITION: Java_cvc3_ValidityChecker_jniFalseExpr jobject m ValidityChecker vc return embed_copy(env, vc->falseExpr()); DEFINITION: Java_cvc3_ValidityChecker_jniNotExpr jobject m ValidityChecker vc c Expr expr return embed_copy(env, vc->notExpr(*expr)); DEFINITION: Java_cvc3_ValidityChecker_jniAndExpr1 jobject m ValidityChecker vc c Expr expr1 c Expr expr2 return embed_copy(env, vc->andExpr(*expr1, *expr2)); DEFINITION: Java_cvc3_ValidityChecker_jniAndExpr2 jobject m ValidityChecker vc cv Expr children return embed_copy(env, vc->andExpr(children)); DEFINITION: Java_cvc3_ValidityChecker_jniOrExpr1 jobject m ValidityChecker vc c Expr expr1 c Expr expr2 return embed_copy(env, vc->orExpr(*expr1, *expr2)); DEFINITION: Java_cvc3_ValidityChecker_jniOrExpr2 jobject m ValidityChecker vc cv Expr children return embed_copy(env, vc->orExpr(children)); DEFINITION: Java_cvc3_ValidityChecker_jniImpliesExpr jobject m ValidityChecker vc c Expr expr1 c Expr expr2 return embed_copy(env, vc->impliesExpr(*expr1, *expr2)); DEFINITION: Java_cvc3_ValidityChecker_jniIffExpr jobject m ValidityChecker vc c Expr expr1 c Expr expr2 return embed_copy(env, vc->iffExpr(*expr1, *expr2)); DEFINITION: Java_cvc3_ValidityChecker_jniEqExpr jobject m ValidityChecker vc c Expr expr1 c Expr expr2 return embed_copy(env, vc->eqExpr(*expr1, *expr2)); DEFINITION: Java_cvc3_ValidityChecker_jniDistinctExpr jobject m ValidityChecker vc cv Expr children return embed_copy(env, vc->distinctExpr(children)); DEFINITION: Java_cvc3_ValidityChecker_jniIteExpr jobject m ValidityChecker vc c Expr expr1 c Expr expr2 c Expr expr3 return embed_copy(env, vc->iteExpr(*expr1, *expr2, *expr3)); DEFINITION: Java_cvc3_ValidityChecker_jniCreateOp1 jobject m ValidityChecker vc n string name c Type type return embed_copy(env, vc->createOp(name, *type)); DEFINITION: Java_cvc3_ValidityChecker_jniCreateOp2 jobject m ValidityChecker vc n string name c Type type c Expr expr return embed_copy(env, vc->createOp(name, *type, *expr)); DEFINITION: Java_cvc3_ValidityChecker_jniEqOp jobject return embed_copy(env, Op(EQ)); DEFINITION: Java_cvc3_ValidityChecker_jniLtOp jobject return embed_copy(env, Op(LT)); DEFINITION: Java_cvc3_ValidityChecker_jniLeOp jobject return embed_copy(env, Op(LE)); DEFINITION: Java_cvc3_ValidityChecker_jniGtOp jobject return embed_copy(env, Op(GT)); DEFINITION: Java_cvc3_ValidityChecker_jniGeOp jobject return embed_copy(env, Op(GE)); DEFINITION: Java_cvc3_ValidityChecker_jniPlusOp jobject return embed_copy(env, Op(PLUS)); DEFINITION: Java_cvc3_ValidityChecker_jniMinusOp jobject return embed_copy(env, Op(MINUS)); DEFINITION: Java_cvc3_ValidityChecker_jniMultOp jobject return embed_copy(env, Op(MULT)); DEFINITION: Java_cvc3_ValidityChecker_jniDivideOp jobject return embed_copy(env, Op(DIVIDE)); DEFINITION: Java_cvc3_ValidityChecker_jniFunExpr1 jobject m ValidityChecker vc c Op op c Expr expr1 return embed_copy(env, vc->funExpr(*op, *expr1)); DEFINITION: Java_cvc3_ValidityChecker_jniFunExpr2 jobject m ValidityChecker vc c Op op c Expr expr1 c Expr expr2 return embed_copy(env, vc->funExpr(*op, *expr1, *expr2)); DEFINITION: Java_cvc3_ValidityChecker_jniFunExpr3 jobject m ValidityChecker vc c Op op c Expr expr1 c Expr expr2 c Expr expr3 return embed_copy(env, vc->funExpr(*op, *expr1, *expr2, *expr3)); DEFINITION: Java_cvc3_ValidityChecker_jniFunExpr4 jobject m ValidityChecker vc c Op op cv Expr children return embed_copy(env, vc->funExpr(*op, children)); DEFINITION: Java_cvc3_ValidityChecker_jniRatExpr1 jobject m ValidityChecker vc n int n n int d return embed_copy(env, vc->ratExpr(n, d)); DEFINITION: Java_cvc3_ValidityChecker_jniRatExpr2 jobject m ValidityChecker vc n string n n string d n int base return embed_copy(env, vc->ratExpr(n, d, base)); DEFINITION: Java_cvc3_ValidityChecker_jniRatExpr3 jobject m ValidityChecker vc n string n n int base return embed_copy(env, vc->ratExpr(n, base)); DEFINITION: Java_cvc3_ValidityChecker_jniUminusExpr jobject m ValidityChecker vc c Expr expr return embed_copy(env, vc->uminusExpr(*expr)); DEFINITION: Java_cvc3_ValidityChecker_jniPlusExpr1 jobject m ValidityChecker vc c Expr expr1 c Expr expr2 return embed_copy(env, vc->plusExpr(*expr1, *expr2)); DEFINITION: Java_cvc3_ValidityChecker_jniPlusExpr2 jobject m ValidityChecker vc cv Expr kids return embed_copy(env, vc->plusExpr(kids)); DEFINITION: Java_cvc3_ValidityChecker_jniMinusExpr jobject m ValidityChecker vc c Expr expr1 c Expr expr2 return embed_copy(env, vc->minusExpr(*expr1, *expr2)); DEFINITION: Java_cvc3_ValidityChecker_jniMultExpr jobject m ValidityChecker vc c Expr expr1 c Expr expr2 return embed_copy(env, vc->multExpr(*expr1, *expr2)); DEFINITION: Java_cvc3_ValidityChecker_jniPowExpr jobject m ValidityChecker vc c Expr expr1 c Expr expr2 return embed_copy(env, vc->powExpr(*expr1, *expr2)); DEFINITION: Java_cvc3_ValidityChecker_jniDivideExpr jobject m ValidityChecker vc c Expr expr1 c Expr expr2 return embed_copy(env, vc->divideExpr(*expr1, *expr2)); DEFINITION: Java_cvc3_ValidityChecker_jniLtExpr jobject m ValidityChecker vc c Expr expr1 c Expr expr2 return embed_copy(env, vc->ltExpr(*expr1, *expr2)); DEFINITION: Java_cvc3_ValidityChecker_jniLeExpr jobject m ValidityChecker vc c Expr expr1 c Expr expr2 return embed_copy(env, vc->leExpr(*expr1, *expr2)); DEFINITION: Java_cvc3_ValidityChecker_jniGtExpr jobject m ValidityChecker vc c Expr expr1 c Expr expr2 return embed_copy(env, vc->gtExpr(*expr1, *expr2)); DEFINITION: Java_cvc3_ValidityChecker_jniGeExpr jobject m ValidityChecker vc c Expr expr1 c Expr expr2 return embed_copy(env, vc->geExpr(*expr1, *expr2)); DEFINITION: Java_cvc3_ValidityChecker_jniRecordExpr1 jobject m ValidityChecker vc n string field c Expr expr return embed_copy(env, vc->recordExpr(field, *expr)); DEFINITION: Java_cvc3_ValidityChecker_jniRecordExpr2 jobject m ValidityChecker vc n string field1 c Expr expr1 n string field2 c Expr expr2 return embed_copy(env, vc->recordExpr(field1, *expr1, field2, *expr2)); DEFINITION: Java_cvc3_ValidityChecker_jniRecordExpr3 jobject m ValidityChecker vc n string field1 c Expr expr1 n string field2 c Expr expr2 n string field3 c Expr expr3 return embed_copy(env, vc->recordExpr(field1, *expr1, field2, *expr2, field2, *expr2)); DEFINITION: Java_cvc3_ValidityChecker_jniRecordExpr4 jobject m ValidityChecker vc nv string fields cv Expr exprs return embed_copy(env, vc->recordExpr(fields, exprs)); DEFINITION: Java_cvc3_ValidityChecker_jniRecSelectExpr jobject m ValidityChecker vc c Expr record n string field return embed_copy(env, vc->recSelectExpr(*record, field)); DEFINITION: Java_cvc3_ValidityChecker_jniRecUpdateExpr jobject m ValidityChecker vc c Expr record n string field c Expr update return embed_copy(env, vc->recUpdateExpr(*record, field, *update)); DEFINITION: Java_cvc3_ValidityChecker_jniReadExpr jobject m ValidityChecker vc c Expr array c Expr index return embed_copy(env, vc->readExpr(*array, *index)); DEFINITION: Java_cvc3_ValidityChecker_jniWriteExpr jobject m ValidityChecker vc c Expr array c Expr index c Expr value return embed_copy(env, vc->writeExpr(*array, *index, *value)); DEFINITION: Java_cvc3_ValidityChecker_jniNewBVConstExpr1 jobject m ValidityChecker vc n string s n int base return embed_copy(env, vc->newBVConstExpr(s, jbase)); DEFINITION: Java_cvc3_ValidityChecker_jniNewBVConstExpr2 jobject m ValidityChecker vc nv bool bits return embed_copy(env, vc->newBVConstExpr(bits)); DEFINITION: Java_cvc3_ValidityChecker_jniNewBVConstExpr3 jobject m ValidityChecker vc c Rational rational n int len return embed_copy(env, vc->newBVConstExpr(*rational, len)); DEFINITION: Java_cvc3_ValidityChecker_jniNewConcatExpr1 jobject m ValidityChecker vc c Expr expr1 c Expr expr2 return embed_copy(env, vc->newConcatExpr(*expr1, *expr2)); DEFINITION: Java_cvc3_ValidityChecker_jniNewConcatExpr2 jobject m ValidityChecker vc cv Expr kids return embed_copy(env, vc->newConcatExpr(kids)); DEFINITION: Java_cvc3_ValidityChecker_jniNewBVExtractExpr jobject m ValidityChecker vc c Expr expr n int hi n int low return embed_copy(env, vc->newBVExtractExpr(*expr, hi, low)); DEFINITION: Java_cvc3_ValidityChecker_jniNewBVNegExpr jobject m ValidityChecker vc c Expr expr return embed_copy(env, vc->newBVNegExpr(*expr)); DEFINITION: Java_cvc3_ValidityChecker_jniNewBVAndExpr1 jobject m ValidityChecker vc c Expr expr1 c Expr expr2 return embed_copy(env, vc->newBVAndExpr(*expr1, *expr2)); DEFINITION: Java_cvc3_ValidityChecker_jniNewBVAndExpr2 jobject m ValidityChecker vc cv Expr kids return embed_copy(env, vc->newBVAndExpr(kids)); DEFINITION: Java_cvc3_ValidityChecker_jniNewBVOrExpr1 jobject m ValidityChecker vc c Expr expr1 c Expr expr2 return embed_copy(env, vc->newBVOrExpr(*expr1, *expr2)); DEFINITION: Java_cvc3_ValidityChecker_jniNewBVOrExpr2 jobject m ValidityChecker vc cv Expr kids return embed_copy(env, vc->newBVOrExpr(kids)); DEFINITION: Java_cvc3_ValidityChecker_jniNewBVXorExpr1 jobject m ValidityChecker vc c Expr expr1 c Expr expr2 return embed_copy(env, vc->newBVXorExpr(*expr1, *expr2)); DEFINITION: Java_cvc3_ValidityChecker_jniNewBVXorExpr2 jobject m ValidityChecker vc cv Expr kids return embed_copy(env, vc->newBVXorExpr(kids)); DEFINITION: Java_cvc3_ValidityChecker_jniNewBVXnorExpr1 jobject m ValidityChecker vc c Expr expr1 c Expr expr2 return embed_copy(env, vc->newBVXnorExpr(*expr1, *expr2)); DEFINITION: Java_cvc3_ValidityChecker_jniNewBVXnorExpr2 jobject m ValidityChecker vc cv Expr kids return embed_copy(env, vc->newBVXnorExpr(kids)); DEFINITION: Java_cvc3_ValidityChecker_jniNewBVNandExpr jobject m ValidityChecker vc c Expr expr1 c Expr expr2 return embed_copy(env, vc->newBVNandExpr(*expr1, *expr2)); DEFINITION: Java_cvc3_ValidityChecker_jniNewBVNorExpr jobject m ValidityChecker vc c Expr expr1 c Expr expr2 return embed_copy(env, vc->newBVNorExpr(*expr1, *expr2)); DEFINITION: Java_cvc3_ValidityChecker_jniNewBVLTExpr jobject m ValidityChecker vc c Expr expr1 c Expr expr2 return embed_copy(env, vc->newBVLTExpr(*expr1, *expr2)); DEFINITION: Java_cvc3_ValidityChecker_jniNewBVLEExpr jobject m ValidityChecker vc c Expr expr1 c Expr expr2 return embed_copy(env, vc->newBVLEExpr(*expr1, *expr2)); DEFINITION: Java_cvc3_ValidityChecker_jniNewBVSLTExpr jobject m ValidityChecker vc c Expr expr1 c Expr expr2 return embed_copy(env, vc->newBVSLTExpr(*expr1, *expr2)); DEFINITION: Java_cvc3_ValidityChecker_jniNewBVSLEExpr jobject m ValidityChecker vc c Expr expr1 c Expr expr2 return embed_copy(env, vc->newBVSLEExpr(*expr1, *expr2)); DEFINITION: Java_cvc3_ValidityChecker_jniNewSXExpr jobject m ValidityChecker vc c Expr expr n int len return embed_copy(env, vc->newSXExpr(*expr, len)); DEFINITION: Java_cvc3_ValidityChecker_jniNewBVUminusExpr jobject m ValidityChecker vc c Expr expr return embed_copy(env, vc->newBVUminusExpr(*expr)); DEFINITION: Java_cvc3_ValidityChecker_jniNewBVSubExpr jobject m ValidityChecker vc c Expr expr1 c Expr expr2 return embed_copy(env, vc->newBVSubExpr(*expr1, *expr2)); DEFINITION: Java_cvc3_ValidityChecker_jniNewBVPlusExpr jobject m ValidityChecker vc n int numbits cv Expr exprs return embed_copy(env, vc->newBVPlusExpr(numbits, exprs)); DEFINITION: Java_cvc3_ValidityChecker_jniNewBVMultExpr jobject m ValidityChecker vc n int numbits c Expr expr1 c Expr expr2 return embed_copy(env, vc->newBVMultExpr(numbits, *expr1, *expr2)); DEFINITION: Java_cvc3_ValidityChecker_jniNewBVUDivExpr jobject m ValidityChecker vc c Expr expr1 c Expr expr2 return embed_copy(env, vc->newBVUDivExpr(*expr1, *expr2)); DEFINITION: Java_cvc3_ValidityChecker_jniNewBVURemExpr jobject m ValidityChecker vc c Expr expr1 c Expr expr2 return embed_copy(env, vc->newBVURemExpr(*expr1, *expr2)); DEFINITION: Java_cvc3_ValidityChecker_jniNewBVSDivExpr jobject m ValidityChecker vc c Expr expr1 c Expr expr2 return embed_copy(env, vc->newBVSDivExpr(*expr1, *expr2)); DEFINITION: Java_cvc3_ValidityChecker_jniNewBVSRemExpr jobject m ValidityChecker vc c Expr expr1 c Expr expr2 return embed_copy(env, vc->newBVSRemExpr(*expr1, *expr2)); DEFINITION: Java_cvc3_ValidityChecker_jniNewBVSModExpr jobject m ValidityChecker vc c Expr expr1 c Expr expr2 return embed_copy(env, vc->newBVSModExpr(*expr1, *expr2)); DEFINITION: Java_cvc3_ValidityChecker_jniNewBVSHL jobject m ValidityChecker vc c Expr expr1 c Expr expr2 return embed_copy(env, vc->newBVSHL(*expr1, *expr2)); DEFINITION: Java_cvc3_ValidityChecker_jniNewBVLSHR jobject m ValidityChecker vc c Expr expr1 c Expr expr2 return embed_copy(env, vc->newBVLSHR(*expr1, *expr2)); DEFINITION: Java_cvc3_ValidityChecker_jniNewBVASHR jobject m ValidityChecker vc c Expr expr1 c Expr expr2 return embed_copy(env, vc->newBVASHR(*expr1, *expr2)); DEFINITION: Java_cvc3_ValidityChecker_jniNewFixedLeftShiftExpr jobject m ValidityChecker vc c Expr expr n int r return embed_copy(env, vc->newFixedLeftShiftExpr(*expr, r)); DEFINITION: Java_cvc3_ValidityChecker_jniNewFixedConstWidthLeftShiftExpr jobject m ValidityChecker vc c Expr expr n int r return embed_copy(env, vc->newFixedConstWidthLeftShiftExpr(*expr, r)); DEFINITION: Java_cvc3_ValidityChecker_jniNewFixedRightShiftExpr jobject m ValidityChecker vc c Expr expr n int r return embed_copy(env, vc->newFixedRightShiftExpr(*expr, r)); DEFINITION: Java_cvc3_ValidityChecker_jniComputeBVConst jobject m ValidityChecker vc c Expr expr return embed_copy(env, vc->computeBVConst(*expr)); DEFINITION: Java_cvc3_ValidityChecker_jniTupleExpr jobject m ValidityChecker vc cv Expr exprs return embed_copy(env, vc->tupleExpr(exprs)); DEFINITION: Java_cvc3_ValidityChecker_jniTupleSelectExpr jobject m ValidityChecker vc c Expr tuple n int index return embed_copy(env, vc->tupleSelectExpr(*tuple, index)); DEFINITION: Java_cvc3_ValidityChecker_jniTupleUpdateExpr jobject m ValidityChecker vc c Expr tuple n int index c Expr value return embed_copy(env, vc->tupleUpdateExpr(*tuple, index, *value)); DEFINITION: Java_cvc3_ValidityChecker_jniDatatypeConsExpr jobject m ValidityChecker vc n string constructor cv Expr exprs return embed_copy(env, vc->datatypeConsExpr(constructor, exprs)); DEFINITION: Java_cvc3_ValidityChecker_jniDatatypeSelExpr jobject m ValidityChecker vc n string selector c Expr expr return embed_copy(env, vc->datatypeSelExpr(selector, *expr)); DEFINITION: Java_cvc3_ValidityChecker_jniDatatypeTestExpr jobject m ValidityChecker vc n string constructor c Expr expr return embed_copy(env, vc->datatypeTestExpr(constructor, *expr)); DEFINITION: Java_cvc3_ValidityChecker_jniForallExpr1 jobject m ValidityChecker vc cv Expr vars c Expr body return embed_copy(env, vc->forallExpr(vars, *body)); DEFINITION: Java_cvc3_ValidityChecker_jniForallExpr2 jobject m ValidityChecker vc cv Expr vars c Expr body c Expr trigger return embed_copy(env, vc->forallExpr(vars, *body, *trigger)); DEFINITION: Java_cvc3_ValidityChecker_jniForallExpr3 jobject m ValidityChecker vc cv Expr vars c Expr body cv Expr triggers return embed_copy(env, vc->forallExpr(vars, *body, triggers)); DEFINITION: Java_cvc3_ValidityChecker_jniForallExpr4 jobject m ValidityChecker vc cv Expr vars c Expr body cvv Expr triggers return embed_copy(env, vc->forallExpr(vars, *body, triggers)); DEFINITION: Java_cvc3_ValidityChecker_jniSetTrigger void m ValidityChecker vc c Expr closure c Expr trigger vc->setTrigger(*closure, *trigger); DEFINITION: Java_cvc3_ValidityChecker_jniSetTriggers void m ValidityChecker vc c Expr closure cv Expr triggers vc->setTriggers(*closure, triggers); DEFINITION: Java_cvc3_ValidityChecker_jniSetTriggers2 void m ValidityChecker vc c Expr closure cvv Expr triggers vc->setTriggers(*closure, triggers); DEFINITION: Java_cvc3_ValidityChecker_jniSetMultiTrigger void m ValidityChecker vc c Expr closure cv Expr multiTrigger vc->setMultiTrigger(*closure, multiTrigger); DEFINITION: Java_cvc3_ValidityChecker_jniExistsExpr jobject m ValidityChecker vc cv Expr vars c Expr body return embed_copy(env, vc->existsExpr(vars, *body)); DEFINITION: Java_cvc3_ValidityChecker_jniLambdaExpr jobject m ValidityChecker vc cv Expr vars c Expr body return embed_copy(env, vc->lambdaExpr(vars, *body)); DEFINITION: Java_cvc3_ValidityChecker_jniTransClosure jobject m ValidityChecker vc c Op p return embed_copy(env, vc->transClosure(*p)); DEFINITION: Java_cvc3_ValidityChecker_jniSimulateExpr jobject m ValidityChecker vc c Expr f c Expr s cv Expr inputs c Expr n return embed_copy(env, vc->simulateExpr(*f, *s, inputs, *n)); DEFINITION: Java_cvc3_ValidityChecker_jniSetResourceLimit void m ValidityChecker vc n int limit vc->setResourceLimit(limit); DEFINITION: Java_cvc3_ValidityChecker_jniAssertFormula void m ValidityChecker vc c Expr expr vc->assertFormula(*expr); DEFINITION: Java_cvc3_ValidityChecker_jniRegisterAtom void m ValidityChecker vc c Expr expr vc->registerAtom(*expr); DEFINITION: Java_cvc3_ValidityChecker_jniGetImpliedLiteral jobject m ValidityChecker vc return embed_copy(env, vc->getImpliedLiteral()); DEFINITION: Java_cvc3_ValidityChecker_jniSimplify jobject m ValidityChecker vc c Expr expr return embed_copy(env, vc->simplify(*expr)); DEFINITION: Java_cvc3_ValidityChecker_jniQuery jstring m ValidityChecker vc c Expr expr return toJava(env, vc->query(*expr)); DEFINITION: Java_cvc3_ValidityChecker_jniCheckUnsat jstring m ValidityChecker vc c Expr expr return toJava(env, vc->checkUnsat(*expr)); DEFINITION: Java_cvc3_ValidityChecker_jniCheckContinue jstring m ValidityChecker vc return toJava(env, vc->checkContinue()); DEFINITION: Java_cvc3_ValidityChecker_jniRestart jstring m ValidityChecker vc c Expr expr return toJava(env, vc->restart(*expr)); DEFINITION: Java_cvc3_ValidityChecker_jniReturnFromCheck void m ValidityChecker vc vc->returnFromCheck(); DEFINITION: Java_cvc3_ValidityChecker_jniGetUserAssumptions jobjectArray m ValidityChecker vc vector result; vc->getUserAssumptions(result); return toJavaVCopy(env, result); DEFINITION: Java_cvc3_ValidityChecker_jniGetInternalAssumptions jobjectArray m ValidityChecker vc vector result; vc->getInternalAssumptions(result); return toJavaVCopy(env, result); DEFINITION: Java_cvc3_ValidityChecker_jniGetAssumptions jobjectArray m ValidityChecker vc vector result; vc->getAssumptions(result); return toJavaVCopy(env, result); DEFINITION: Java_cvc3_ValidityChecker_jniGetAssumptionsUsed jobjectArray m ValidityChecker vc vector result; vc->getAssumptionsUsed(result); return toJavaVCopy(env, result); DEFINITION: Java_cvc3_ValidityChecker_jniGetCounterExample jobjectArray m ValidityChecker vc n bool inOrder vector result; vc->getCounterExample(result, inOrder); return toJavaVCopy(env, result); DEFINITION: Java_cvc3_ValidityChecker_jniGetValue jstring m ValidityChecker vc c Expr expr return toJava(env, vc->value(*expr)); DEFINITION: Java_cvc3_ValidityChecker_jniGetConcreteModel jobjectArray m ValidityChecker vc ExprMap result; vc->getConcreteModel(result); return toJavaHCopy(env, result); DEFINITION: Java_cvc3_ValidityChecker_jniInconsistent1 jboolean m ValidityChecker vc return vc->inconsistent(); DEFINITION: Java_cvc3_ValidityChecker_jniInconsistent2 jobjectArray m ValidityChecker vc vector result; bool inconsistent = vc->inconsistent(result); assert(inconsistent); return toJavaVCopy(env, result); DEFINITION: Java_cvc3_ValidityChecker_jniIncomplete1 jboolean m ValidityChecker vc return vc->incomplete(); DEFINITION: Java_cvc3_ValidityChecker_jniIncomplete2 jobjectArray m ValidityChecker vc vector result; bool incomplete = vc->incomplete(result); assert(incomplete); return toJavaVCopy(env, result); DEFINITION: Java_cvc3_ValidityChecker_jniGetProof jobject m ValidityChecker vc return embed_copy(env, vc->getProof()); DEFINITION: Java_cvc3_ValidityChecker_jniGetTCC jobject m ValidityChecker vc return embed_copy(env, vc->getTCC()); DEFINITION: Java_cvc3_ValidityChecker_jniGetAssumptionsTCC jobjectArray m ValidityChecker vc vector result; vc->getAssumptionsTCC(result); return toJavaVCopy(env, result); DEFINITION: Java_cvc3_ValidityChecker_jniGetProofTCC jobject m ValidityChecker vc return embed_copy(env, vc->getProofTCC()); DEFINITION: Java_cvc3_ValidityChecker_jniGetClosure jobject m ValidityChecker vc return embed_copy(env, vc->getClosure()); DEFINITION: Java_cvc3_ValidityChecker_jniGetProofClosure jobject m ValidityChecker vc return embed_copy(env, vc->getProofClosure()); DEFINITION: Java_cvc3_ValidityChecker_jniStackLevel jint m ValidityChecker vc return vc->stackLevel(); DEFINITION: Java_cvc3_ValidityChecker_jniPush void m ValidityChecker vc vc->push(); DEFINITION: Java_cvc3_ValidityChecker_jniPop void m ValidityChecker vc vc->pop(); DEFINITION: Java_cvc3_ValidityChecker_jniPopTo void m ValidityChecker vc n int stackLevel vc->popto(stackLevel); DEFINITION: Java_cvc3_ValidityChecker_jniScopeLevel jint m ValidityChecker vc return vc->scopeLevel(); DEFINITION: Java_cvc3_ValidityChecker_jniPushScope void m ValidityChecker vc vc->pushScope(); DEFINITION: Java_cvc3_ValidityChecker_jniPopScope void m ValidityChecker vc vc->popScope(); DEFINITION: Java_cvc3_ValidityChecker_jniPopToScope void m ValidityChecker vc n int stackLevel vc->poptoScope(stackLevel); DEFINITION: Java_cvc3_ValidityChecker_jniGetCurrentContext jobject m ValidityChecker vc return embed_mut_ref(env, vc->getCurrentContext()); DEFINITION: Java_cvc3_ValidityChecker_jniLoadFile1 void m ValidityChecker vc n string fileName n string lang vc->loadFile(fileName, toCppInputLanguage(env, lang), false); DEFINITION: Java_cvc3_ValidityChecker_jniGetStatistics jobject m ValidityChecker vc return embed_mut_ref(env, &vc->getStatistics()); DEFINITION: Java_cvc3_ValidityChecker_jniPrintStatistics void m ValidityChecker vc vc->printStatistics(); DEFINITION: Java_cvc3_ValidityChecker_jniSetTimeLimit void m ValidityChecker vc n int n vc->setTimeLimit((unsigned int)n); cvc3-2.4.1/java/src/cvc3/TypecheckException.java0000664000175400017540000000040411070741374021267 0ustar mdetersmdeterspackage cvc3; import java.util.*; /** mirrors CVC3::TypecheckException */ public class TypecheckException extends Cvc3Exception { private final static long serialVersionUID = 1L; public TypecheckException(String message) { super(message); } } cvc3-2.4.1/java/src/cvc3/Theorem.java0000664000175400017540000000040011070741365017070 0ustar mdetersmdeterspackage cvc3; import java.util.*; public class Theorem extends Embedded { // jni methods /// Constructor public Theorem(Object Theorem, EmbeddedManager embeddedManager) { super(Theorem, embeddedManager); } /// API (immutable) } cvc3-2.4.1/java/src/cvc3/Cvc3.java0000664000175400017540000001517511070741374016302 0ustar mdetersmdeterspackage cvc3; import java.util.*; class Cvc3 { static boolean useObjManager = false; static void timeoutHandler(Object o) { System.out.println("self-timeout."); System.exit(1); } public static void main(String args[]) throws Cvc3Exception { ValidityChecker vc = null; FlagsMut flags = null; try { flags = ValidityChecker.createFlags(null); // parse input String fileName = ""; try { fileName = parse_args(args, flags); } catch(CLException e) { System.err.print("*** " + e); System.err.println("\n\nRun with -help option for usage information."); System.exit(1); } // Set the timeout, if given in the command line options int timeout = flags.getFlag("timeout").getInt(); if (timeout > 0) { new Timer().schedule(new TimeoutHandler(), timeout * 1000); } /* * Create and run the validity checker */ // Debugging code may throw an exception vc = ValidityChecker.create(flags); flags.delete(); // -h flag sets "help" to false (+h would make it true, but that's // not what the user normally types in). if(!vc.getFlags().getFlag("help").getBool()) { String programName = "cvc3"; //:TODO: printUsage(vc.getFlags(), programName); System.exit(0); } // Similarly, -version sets the flag "version" to false if(!vc.getFlags().getFlag("version").getBool()) { System.out.println("This is CVC3 version " + "UNKNOWN"); //:TODO: System.out.println("Copyright (C) 2003-2006 by the Board of Trustees of Leland Stanford Junior"); System.out.println("University, New York University, and the University of Iowa."); System.out.println(); System.out.print("THIS SOFTWARE PROVIDED AS-IS, WITHOUT ANY WARRANTIES. "); System.out.println("USE IT AT YOUR OWN RISK."); System.out.println(); System.exit(0); } // Test if the output language is correctly specified; if not, an // exception will be thrown vc.getExprManager().getOutputLanguage(); // Read the input file vc.loadFile(fileName, vc.getExprManager().getInputLanguage()); // Print statistics if (vc.getFlags().getFlag("stats").getBool()) { vc.printStatistics(); } } catch (Cvc3Exception e) { System.err.println("*** Fatal exception: " + e); System.exit(1); } finally { if (flags != null) flags.delete(); if (vc != null) vc.delete(); } // to avoid waiting for timer to finish System.exit(0); } // evaluates command line flags, returns problem file name public static String parse_args(String[] args, FlagsMut flags) throws Cvc3Exception { // keep track that exactly one file name is given String fileName = ""; boolean seenFileName = false; // iterate over the arguments for (int i = 0; i < args.length; ++i) { String arg = args[i]; // A command-line option if (arg.startsWith("-") || arg.startsWith("+")) { List names = flags.getFlags(arg.substring(1)); // no match if (names.size() == 0) throw new CLException(arg + " does not match any known option"); // ambiguous else if (names.size() > 1) { StringBuffer s = new StringBuffer(); s.append(arg + " is ambiguous. Possible matches are:\n"); for (Iterator name = names.iterator(); name.hasNext(); ) { s.append(" " + name.next() + "\n"); } throw new CLException(s.toString()); } // Single match; process the option by name, type, and parameters else { String name = (String) names.iterator().next(); boolean val = arg.startsWith("+"); Flag flag = flags.getFlag(name); if (flag.isBool()) { flags.setFlag(name, val); } else if (flag.isInt()) { ++i; if (i >= args.length) throw new CLException (arg + " (-" + name + ") expects an integer argument."); int parameter = Integer.parseInt(args[i]); flags.setFlag(name, parameter); } else if (flag.isString()) { ++i; if (i >= args.length) throw new CLException (arg + " (-" + name + ") expects a string argument."); flags.setFlag(name, args[i]); } // else if (flag.isStringVec()) // { // bool hasMore = iter.MoveNext(); // if (!hasMore) // { // throw new CLException // (arg + " (-" + name + ") expects a string argument."); // } // flags.setFlag(name, (string)iter.Current, val); // } else { throw new CLException("parse_args: Bad flag : " + name); } } } // no flag, so should be a file name // second no flag argument else if(seenFileName) { throw new CLException("More than one file name given: " + fileName + " and " + arg); } // first no flag argument else { fileName = arg; seenFileName = true; } } return fileName; } public static void printUsage(Flags flags, String programName) throws Cvc3Exception { System.out.println("Usage: " + programName + " [options]"); System.out.println(programName + " will read the input from STDIN and "); System.out.println("print the result on STDOUT."); System.out.println("Boolean (b) options are set 'on' by +option and 'off' by -option"); System.out.println("(for instance, +sat or -sat)."); System.out.println("Integer (i), string (s) and vector (v) options "); System.out.println("require a parameter, e.g. -width 80"); System.out.println("Also, (v) options can appear multiple times setting args on and off,"); System.out.println("as in +trace \"enable this\" -trace \"disable that\"."); System.out.println("Option names can be abbreviated to the shortest unambiguous prefix."); System.out.println(); System.out.println("The options are:"); // Get all the names of options (they all match the empty string) List names = flags.getFlags(""); for (Iterator i = names.iterator(); i.hasNext(); ) { String name = (String) i.next(); Flag flag = flags.getFlag(name); String prefix = ""; if (flag.isNull()) { prefix = " (null)"; } else if (flag.isBool()) { String enabled = flag.getBool() ? "+" : "-"; prefix = " (b) " + enabled + name; } else if (flag.isInt()) { prefix = " (i) -" + name + " " + flag.getInt(); } else if (flag.isString()) { prefix = " (s) -" + name + " " + flag.getString(); } else if (flag.isStringVec()) { prefix = " (s) -" + name; } else { assert(false); } while (prefix.length() < 21) { prefix += " "; } System.out.println(prefix + " " + flag.getHelp()); } System.out.println(); } } cvc3-2.4.1/java/src/cvc3/EmbeddedManager.java0000664000175400017540000000407611175701365020470 0ustar mdetersmdeterspackage cvc3; import java.util.*; /** Helps to enforce deallocation of a set of embedded objects See also Embedded.java Cvc3 requires on the C++ level that the ValidityChecker is destructed last, after all other Cvc3 objects (i.e. subclasses of Embedded). A 'simple' (but not too cheap) way to achieve this effect of deterministic deallocation in Java without introducing much error prone code is to register all embedded objects (except for the ValidityChecker) with an EmbeddedManager. When the ValidityChecker is deleted/finalized it uses the EmbeddedManager to destruct all other Cvc3 objects first. */ public class EmbeddedManager { // jni methods // call the destructor of the c++ object public static native void jniDelete(Object Embedded) throws Cvc3Exception; // c++ objects which have been registered for deletion private List d_deleted; /// Constructor // delete must be called before EmbeddedManager is garbage collected public EmbeddedManager() { d_deleted = new ArrayList(); } /// Methods // true iff delete has been called public synchronized boolean isDeleted() { return (d_deleted == null); } // signals that the ValidityChecker destructs itself public synchronized void delete() throws Cvc3Exception { d_deleted = null; } // registers a c++ object for deletion public synchronized void register(Embedded embedded) { d_deleted.add(embedded.embedded()); } // destruct all registered objects public synchronized void cleanUp() throws Cvc3Exception { assert(!isDeleted()); Iterator i = d_deleted.iterator(); while (i.hasNext()) { jniDelete(i.next()); } d_deleted.clear(); } // ensure that all embedded objects are deallocated eventually public void finalize() throws Throwable { try { if (!isDeleted()) { assert(false); // System.out.println("EmbeddedManager.Finalizer: should never be called"); throw new Error("EmbeddedManager.Finalizer: should never be called"); } } finally { super.finalize(); } } } cvc3-2.4.1/java/src/cvc3/FlagsMut.java0000664000175400017540000000243411070741364017217 0ustar mdetersmdeterspackage cvc3; import java.util.*; public class FlagsMut extends Flags { // jni methods private static native void jniSetFlag1(Object Flags, String name, boolean value) throws Cvc3Exception; private static native void jniSetFlag2(Object Flags, String name, int value) throws Cvc3Exception; private static native void jniSetFlag3(Object Flags, String name, String value) throws Cvc3Exception; private static native void jniSetFlag4(Object Flags, String map, String name, boolean value) throws Cvc3Exception; /// Constructor // create embedded object public FlagsMut(Object FlagsMut, EmbeddedManager embeddedManager) { super(FlagsMut, embeddedManager); } /// API (mutable) public void setFlag(String name, boolean value) throws Cvc3Exception { jniSetFlag1(embedded(), name, value); } public void setFlag(String name, int value) throws Cvc3Exception { jniSetFlag2(embedded(), name, value); } public void setFlag(String name, String value) throws Cvc3Exception { jniSetFlag3(embedded(), name, value); } // flag representing set of options, e.g. trace public void setFlag(String map, String name, boolean value) throws Cvc3Exception { jniSetFlag4(embedded(), map, name, value); } } cvc3-2.4.1/java/src/cvc3/ProofMut.java0000664000175400017540000000045111070741374017246 0ustar mdetersmdeterspackage cvc3; import java.util.*; public class ProofMut extends Proof { // jni methods /// Constructor // create embedded object public ProofMut(Object ProofMut, EmbeddedManager embeddedManager) { super(ProofMut, embeddedManager); } /// API (mutable) } cvc3-2.4.1/java/src/cvc3/Flags.java0000664000175400017540000000161611070741367016535 0ustar mdetersmdeterspackage cvc3; import java.util.*; public abstract class Flags extends Embedded { // jni methods private static native Object[] jniGetFlags(Object Flags, String prefix) throws Cvc3Exception; private static native Object jniGetFlag(Object Flags, String name) throws Cvc3Exception; /// Constructor // create embedded object public Flags(Object Flags, EmbeddedManager embeddedManager) { super(Flags, embeddedManager); } /// API (immutable) // get names of all flags starting with prefix public List getFlags(String prefix) throws Cvc3Exception { Object[] flags = jniGetFlags(embedded(), prefix); assert(flags instanceof String[]); return Arrays.asList(flags); } // get the value of a flag by name (without prefix -/+) public Flag getFlag(String name) throws Cvc3Exception { return new Flag(jniGetFlag(embedded(), name), embeddedManager()); } } cvc3-2.4.1/java/src/cvc3/Type.java0000664000175400017540000000652611327620043016417 0ustar mdetersmdeterspackage cvc3; public class Type extends Embedded { // jni methods private static native boolean jniIsAny(Object Type) throws Cvc3Exception; private static native boolean jniIsArray(Object Type) throws Cvc3Exception; private static native boolean jniIsBitvector(Object Type) throws Cvc3Exception; private static native boolean jniIsBool(Object Type) throws Cvc3Exception; private static native boolean jniIsDatatype(Object Type) throws Cvc3Exception; private static native boolean jniIsFunction(Object Type) throws Cvc3Exception; private static native boolean jniIsNull(Object Type) throws Cvc3Exception; private static native boolean jniIsSubtype(Object Type) throws Cvc3Exception; private static native Object jniGetExpr(Object Type) throws Cvc3Exception; private static native int jniArity(Object Type) throws Cvc3Exception; private static native Type jniGetChild(Object Type, int i) throws Cvc3Exception; private static native boolean jniEquals(Object Type1, Object Type2) throws Cvc3Exception; private static native String jniToString(Object Type) throws Cvc3Exception; private static native Object jniConstr(Object expr) throws Cvc3Exception; public static Type valueOf(Expr expr) throws Cvc3Exception { return new Type(jniConstr(expr.embedded()), expr.embeddedManager()); } /// Constructor public Type(Object Type, EmbeddedManager embeddedManager) { super(Type, embeddedManager); } /// API (immutable) public boolean isAny() throws Cvc3Exception { return jniIsAny(embedded()); } public boolean isArray() throws Cvc3Exception { return jniIsArray(embedded()); } public boolean isBitvector() throws Cvc3Exception { return jniIsBitvector(embedded()); } public boolean isBoolean() throws Cvc3Exception { return jniIsBool(embedded()); } public boolean isDatatype() throws Cvc3Exception { return jniIsDatatype(embedded()); } public boolean isFunction() throws Cvc3Exception { return jniIsFunction(embedded()); } public boolean isNull() throws Cvc3Exception { return jniIsNull(embedded()); } public boolean isSubtype() throws Cvc3Exception { return jniIsSubtype(embedded()); } public Expr getExpr() throws Cvc3Exception { return new Expr(jniGetExpr(embedded()), embeddedManager()); } public int arity() throws Cvc3Exception { return jniArity(embedded()); } public Type getChild(int i) throws Cvc3Exception { assert(i >= 0 && i < arity()); return new Type(jniGetChild(embedded(), i), embeddedManager()); } // Printing public String toString() { String result = ""; try { result = jniToString(embedded()); } catch (Cvc3Exception e) { System.out.println(e); assert(false); } return result; } public boolean equals(Object o) { if (this == o) return true; if (!(o instanceof Type)) return false; boolean result = false; try { result = jniEquals(embedded(), ((Embedded)o).embedded()); } catch (Cvc3Exception e) { assert(false); } return result; } // must return the same hash code for two exprs if equals returns true public int hashCode() { try { return getExpr().hashCode(); } catch (Cvc3Exception e) { assert(false); } assert(false); return 0; } } cvc3-2.4.1/java/src/cvc3/RationalMut.java0000664000175400017540000000047011070741370017727 0ustar mdetersmdeterspackage cvc3; import java.util.*; public class RationalMut extends Rational { // jni methods /// Constructor // create embedded object public RationalMut(Object RationalMut, EmbeddedManager embeddedManager) { super(RationalMut, embeddedManager); } /// API (mutable) } cvc3-2.4.1/java/src/cvc3/ContextMut.java0000664000175400017540000000046311070741374017610 0ustar mdetersmdeterspackage cvc3; import java.util.*; public class ContextMut extends Context { // jni methods /// Constructor // create embedded object public ContextMut(Object ContextMut, EmbeddedManager embeddedManager) { super(ContextMut, embeddedManager); } /// API (mutable) } cvc3-2.4.1/java/src/cvc3/ExprManager.java0000664000175400017540000000133411070741372017703 0ustar mdetersmdeterspackage cvc3; import java.util.*; public class ExprManager extends Embedded { // jni methods private static native String jniGetInputLanguage(Object ExprManager) throws Cvc3Exception; private static native String jniGetOutputLanguage(Object ExprManager) throws Cvc3Exception; /// Constructor public ExprManager(Object ExprManager, EmbeddedManager embeddedManager) { super(ExprManager, embeddedManager); } /// API (immutable) public InputLanguage getInputLanguage() throws Cvc3Exception { return InputLanguage.get(jniGetInputLanguage(embedded())); } public InputLanguage getOutputLanguage() throws Cvc3Exception { return InputLanguage.get(jniGetOutputLanguage(embedded())); } } cvc3-2.4.1/java/src/cvc3/FlagsMut_impl.cpp0000664000175400017540000000100611070741370020070 0ustar mdetersmdetersDEFINITION: Java_cvc3_FlagsMut_jniSetFlag1 void m CLFlags flags n string name n bool value flags->setFlag(name, value); DEFINITION: Java_cvc3_FlagsMut_jniSetFlag2 void m CLFlags flags n string name n int value flags->setFlag(name, value); DEFINITION: Java_cvc3_FlagsMut_jniSetFlag3 void m CLFlags flags n string name n string value flags->setFlag(name, value); DEFINITION: Java_cvc3_FlagsMut_jniSetFlag4 void m CLFlags flags n string map n string name n bool value flags->setFlag(map, std::make_pair(name, value)); cvc3-2.4.1/java/src/cvc3/ProofMut_impl.cpp0000664000175400017540000000000011070741372020114 0ustar mdetersmdeterscvc3-2.4.1/java/src/cvc3/Rational.java0000664000175400017540000001473611314036371017252 0ustar mdetersmdeterspackage cvc3; import java.util.*; public class Rational extends Embedded { // jni methods private static native Object jniRational1(int n, int d) throws Cvc3Exception; private static native Object jniRational2(String n, int base) throws Cvc3Exception; private static native Object jniRational3(String n, String d, int base) throws Cvc3Exception; private static native boolean jniEquals(Object Rational1, Object Rational2) throws Cvc3Exception; private static native String jniToString(Object Rational) throws Cvc3Exception; private static native int jniHash(Object Rational) throws Cvc3Exception; private static native boolean jniIsLe(Object Rational1, Object Rational2) throws Cvc3Exception; private static native boolean jniIsLt(Object Rational1, Object Rational2) throws Cvc3Exception; private static native boolean jniIsGe(Object Rational1, Object Rational2) throws Cvc3Exception; private static native boolean jniIsGt(Object Rational1, Object Rational2) throws Cvc3Exception; private static native Object jniPlus(Object Rational1, Object Rational2) throws Cvc3Exception; private static native Object jniMinus(Object Rational1, Object Rational2) throws Cvc3Exception; private static native Object jniMult(Object Rational1, Object Rational2) throws Cvc3Exception; private static native Object jniDivide(Object Rational1, Object Rational2) throws Cvc3Exception; private static native Object jniMod(Object Rational1, Object Rational2) throws Cvc3Exception; private static native Object jniGetNumerator(Object Rational) throws Cvc3Exception; private static native Object jniGetDenominator(Object Rational) throws Cvc3Exception; private static native boolean jniIsInteger(Object Rational) throws Cvc3Exception; private static native int jniGetInteger(Object Rational) throws Cvc3Exception; private static native Object jniGcd(Object Rational1, Object Rational2) throws Cvc3Exception; private static native Object jniLcm(Object Rational1, Object Rational2) throws Cvc3Exception; private static native Object jniAbs(Object Rational) throws Cvc3Exception; private static native Object jniFloor(Object Rational) throws Cvc3Exception; private static native Object jniCeil(Object Rational) throws Cvc3Exception; /// Constructor public Rational(Object Rational, EmbeddedManager embeddedManager) { super(Rational, embeddedManager); } public Rational(int n, EmbeddedManager embeddedManager) throws Cvc3Exception { this(jniRational1(n, 10), embeddedManager); } public Rational(int n, int d, EmbeddedManager embeddedManager) throws Cvc3Exception { this(jniRational1(n, d), embeddedManager); } public Rational(String n, EmbeddedManager embeddedManager) throws Cvc3Exception { this(jniRational2(n, 10), embeddedManager); } public Rational(String n, int base, EmbeddedManager embeddedManager) throws Cvc3Exception { this(jniRational2(n, base), embeddedManager); } public Rational(String n, String d, EmbeddedManager embeddedManager) throws Cvc3Exception { this(jniRational3(n, d, 10), embeddedManager); } public Rational(String n, String d, int base, EmbeddedManager embeddedManager) throws Cvc3Exception { this(jniRational3(n, d, base), embeddedManager); } /// API (immutable) // 'Problem' with equals/hashCode: // this is based on the wrapped c++ expressions. // as a consequence two Expr objects are equal iff // the wrapped expression is equal, // and are indistinguishable for example in a HashMap. public boolean equals(Object o) { if (this == o) return true; if (!(o instanceof Rational)) return false; boolean result = false; try { result = jniEquals(embedded(), ((Embedded)o).embedded()); } catch (Cvc3Exception e) { assert(false); } return result; } // must return the same hash code for two objects if equals returns true public int hashCode() { try { return jniHash(embedded()); } catch (Cvc3Exception e) { assert(false); } assert(false); return 0; } public String toString() { String result = ""; try { result = jniToString(embedded()); } catch (Cvc3Exception e) { assert(false); } return result; } public boolean isLt(Rational r) throws Cvc3Exception { return jniIsLt(embedded(), r.embedded()); } public boolean isLe(Rational r) throws Cvc3Exception { return jniIsLe(embedded(), r.embedded()); } public boolean isGt(Rational r) throws Cvc3Exception { return jniIsGt(embedded(), r.embedded()); } public boolean isGe(Rational r) throws Cvc3Exception { return jniIsGe(embedded(), r.embedded()); } public Rational plus(Rational r) throws Cvc3Exception { return new Rational(jniPlus(embedded(), r.embedded()), embeddedManager()); } public Rational minus(Rational r) throws Cvc3Exception { return new Rational(jniPlus(embedded(), r.embedded()), embeddedManager()); } public Rational mult(Rational r) throws Cvc3Exception { return new Rational(jniPlus(embedded(), r.embedded()), embeddedManager()); } public Rational divide(Rational r) throws Cvc3Exception { return new Rational(jniPlus(embedded(), r.embedded()), embeddedManager()); } public Rational mod(Rational r) throws Cvc3Exception { return new Rational(jniPlus(embedded(), r.embedded()), embeddedManager()); } public Rational getNumerator() throws Cvc3Exception { return new Rational(jniGetNumerator(embedded()), embeddedManager()); } public Rational getDenominator() throws Cvc3Exception { return new Rational(jniGetDenominator(embedded()), embeddedManager()); } public boolean isInteger() throws Cvc3Exception { return jniIsInteger(embedded()); } public int getInteger() throws Cvc3Exception { assert(isInteger()); return jniGetInteger(embedded()); } public Rational gcd(Rational r) throws Cvc3Exception { return new Rational(jniGcd(embedded(), r.embedded()), embeddedManager()); } public Rational lcm(Rational r) throws Cvc3Exception { return new Rational(jniLcm(embedded(), r.embedded()), embeddedManager()); } public Rational abs() throws Cvc3Exception { return new Rational(jniAbs(embedded()), embeddedManager()); } public Rational floor() throws Cvc3Exception { return new Rational(jniFloor(embedded()), embeddedManager()); } public Rational ceil() throws Cvc3Exception { return new Rational(jniCeil(embedded()), embeddedManager()); } } cvc3-2.4.1/java/src/cvc3/EmbeddedManager_impl.cpp0000664000175400017540000000013611070741371021336 0ustar mdetersmdetersDEFINITION: Java_cvc3_EmbeddedManager_jniDelete void n jobject obj deleteEmbedded(env, jobj); cvc3-2.4.1/java/src/cvc3/Type_impl.cpp0000664000175400017540000000270211327620044017272 0ustar mdetersmdetersINCLUDE: "kinds.h" INCLUDE: "type.h" INCLUDE: "theory_array.h" INCLUDE: "theory_bitvector.h" INCLUDE: "theory_datatype.h" DEFINITION: Java_cvc3_Type_jniConstr jobject c Expr expr return embed_copy(env, Type(*expr)); DEFINITION: Java_cvc3_Type_jniIsAny jboolean c Type type return type->getExpr().getKind() == ANY_TYPE; DEFINITION: Java_cvc3_Type_jniIsArray jboolean c Type type return type->getExpr().getKind() == ARRAY; DEFINITION: Java_cvc3_Type_jniIsBitvector jboolean c Type type return type->getExpr().getKind() == BITVECTOR; DEFINITION: Java_cvc3_Type_jniIsBool jboolean c Type type return type->isBool(); DEFINITION: Java_cvc3_Type_jniIsDatatype jboolean c Type type return ::isDatatype(*type); DEFINITION: Java_cvc3_Type_jniIsFunction jboolean c Type type return type->isFunction(); DEFINITION: Java_cvc3_Type_jniIsNull jboolean c Type type return type->isNull(); DEFINITION: Java_cvc3_Type_jniIsSubtype jboolean c Type type return type->isSubtype(); DEFINITION: Java_cvc3_Type_jniGetExpr jobject c Type type return embed_const_ref(env, &type->getExpr()); DEFINITION: Java_cvc3_Type_jniArity jint c Type type return type->arity(); DEFINITION: Java_cvc3_Type_jniGetChild jobject c Type type n int i return embed_copy(env, (*type)[i]); DEFINITION: Java_cvc3_Type_jniEquals jboolean c Type type1 c Type type2 return *type1 == *type2; DEFINITION: Java_cvc3_Type_jniToString jstring c Type type return toJava(env, type->toString()); cvc3-2.4.1/java/src/cvc3/OpMut.java0000664000175400017540000000043211070741371016533 0ustar mdetersmdeterspackage cvc3; import java.util.*; public class OpMut extends Op { // jni methods /// Constructor // create embedded object public OpMut(Object OpMut, EmbeddedManager embeddedManager) { super(OpMut, embeddedManager); } /// API (mutable) } cvc3-2.4.1/java/src/cvc3/ParserException.java0000664000175400017540000000037311070741371020606 0ustar mdetersmdeterspackage cvc3; import java.util.*; /** mirrors CVC3::ParserException */ public class ParserException extends Cvc3Exception { private final static long serialVersionUID = 1L; public ParserException(String message) { super(message); } } cvc3-2.4.1/java/src/cvc3/QueryResult.java0000664000175400017540000000304711203110441017762 0ustar mdetersmdeterspackage cvc3; import java.util.*; /** * QueryResult is an enum in Cvc3, but as we have to use java 1.4 we have to * use one of the usual tricks instead of java's Enum. * * To be independent of changes of the actual values of the c++ enum elements * they are passed by name from the JNI interface, so that changing them will * violently break the code (though unfortunately only at runtime). */ public class QueryResult { private final String d_result; private QueryResult(String result) { d_result = result; } // value constants public static final QueryResult INVALID = new QueryResult("INVALID"); public static final QueryResult VALID = new QueryResult("VALID"); public static final QueryResult ABORT = new QueryResult("ABORT"); public static final QueryResult UNKNOWN = new QueryResult("UNKNOWN"); // names of c++ enum values, CVC3 maps INVALID->SAT and VALID->UNSAT private static Map valueMap = new HashMap() { { put("SATISFIABLE", INVALID); put("UNSATISFIABLE", VALID); put("UNKNOWN", UNKNOWN); put("ABORT", ABORT); } public static final long serialVersionUID = 1L; }; // the QueryResult corresponding to a c++ enum value by name public static QueryResult get(String value) throws DebugException { QueryResult queryResult = (QueryResult) valueMap.get(value); if (queryResult == null) { throw new DebugException("QueryResult.constructor: unknown enum value: " + value); } return queryResult; } public String toString() { return d_result; } } cvc3-2.4.1/java/src/cvc3/Test.java0000664000175400017540000017355311273046736016435 0ustar mdetersmdeterspackage cvc3; import java.util.*; class Test { public static void main(String args[]) { int regressLevel = 3; if (args.length > 1) { regressLevel = Integer.parseInt(args[0]); } boolean allPassed = true; System.out.println("Running API test, regress level = " + regressLevel); try { System.out.println("\ntest():"); allPassed = test() && allPassed; System.out.println("\n}\ntest1():"); allPassed = test1() && allPassed; System.out.println("\n}\ntest2():"); allPassed = test2() && allPassed; System.out.println("\n}\ntest3():"); allPassed = test3() && allPassed; System.out.println("\n}\ntest4():"); allPassed = test4() && allPassed; if (regressLevel > 0) { System.out.println("\n}\n\ntest5():"); allPassed = test5() && allPassed; } System.out.println("\n}\ntest6():"); allPassed = test6() && allPassed; System.out.println("\n}\ntest7():"); allPassed = test7() && allPassed; System.out.println("\n}\ntest8():"); allPassed = test8() && allPassed; System.out.println("\n}\ntest9():"); allPassed = test9(10 * regressLevel + 10) && allPassed; System.out.println("\n}\nbvtest9():"); allPassed = bvtest9(regressLevel*3+2) && allPassed; // Test for obvious memory leaks int limit = 100 * regressLevel + 10; for (int i = 0; i < limit; ++i) { if (i % 100 == 0) System.out.println("test10[" + i + "]"); allPassed = test10() && allPassed; } System.out.println("\n}\ntest11():"); allPassed = test11() && allPassed; System.out.println("\n}\ntest12():"); allPassed = test12() && allPassed; System.out.println("\n}\ntest13():"); allPassed = test13() && allPassed; System.out.println("\n}\ntest14():"); allPassed = test14() && allPassed; System.out.println("\n}\ntest15():"); allPassed = test15() && allPassed; System.out.println("\n}\ntest16():"); allPassed = test16() && allPassed; System.out.println("\n}\ntest17():"); allPassed = test17() && allPassed; System.out.println("\n}\ntest18():"); allPassed = test18() && allPassed; System.out.println("\n}\ntest19():"); allPassed = test19() && allPassed; System.out.println("\n}\ntest22():"); allPassed = test22() && allPassed; System.out.println("\n}\ntest23():"); allPassed = test23() && allPassed; /* :TODO: if (regressLevel > 1) { System.out.println("\n}\ntestgeorge1():"); George.testgeorge1(); System.out.println("\n}\ntestgeorge2():"); George.testgeorge2(); System.out.println("\n}\ntestgeorge3():"); George.testgeorge3(); System.out.println("\n}\ntestgeorge4():"); George.testgeorge4(); System.out.println("\n}\ntestgeorge5():"); George.testgeorge5(); } */ System.out.println("\n}\ntestNonlinearBV():"); allPassed = testNonlinearBV() && allPassed; System.out.println("\n}\ntestDistinct():"); allPassed = testDistinct() && allPassed; System.out.println("\n}"); } catch (Exception e) { System.out.println("*** Exception caught: \n" + e); e.printStackTrace(System.out); allPassed = false; } if (allPassed) { System.out.println("Program exits successfully."); } else { System.out.println("Program exits with error status = " + allPassed + "."); } System.exit(allPassed ? 0 : 1); } public static void DebugAssert(boolean condition, String message) throws Cvc3Exception { if (!condition) { throw new DebugException(message); } } // Check whether e is valid public static boolean check(ValidityChecker vc, Expr e) throws Cvc3Exception { return check(vc, e, true); } public static boolean check(ValidityChecker vc, Expr e, boolean verbose) throws Cvc3Exception { if(verbose) { System.out.println("Query: " + e.toString()); } QueryResult result = vc.query(e); if (result == QueryResult.VALID) { if (verbose) System.out.println("Valid\n"); return true; } else if (result == QueryResult.INVALID) { if (verbose) System.out.println("Invalid\n"); return false; } if (verbose) System.out.println("Returned neither valid nor invalid\n"); return false; } public static void printResult(QueryResult result) throws Cvc3Exception { if (result == QueryResult.VALID) { System.out.println("Result Valid"); } else if (result == QueryResult.INVALID) { System.out.println("Result Invalid"); } else if (result == QueryResult.UNKNOWN) { System.out.println("Result Unknown"); } else if (result == QueryResult.ABORT) { System.out.println("Aborted"); } else { assert(false); } } // Make a new assertion - disposes expression public static void newAssertion(ValidityChecker vc, Expr e) throws Cvc3Exception { System.out.println("Assert: " + e); vc.assertFormula(e); } public static boolean test() throws Cvc3Exception { ValidityChecker vc = null; try { vc = ValidityChecker.create(); Type it = vc.intType(); //int Op f = vc.createOp("f", vc.funType(it, it)); Expr z = vc.varExpr("z", it); Expr e = vc.funExpr(f, vc.funExpr(f, z)); e = e.getChild(0); Expr f2 = vc.funExpr(f, e); Expr f3 = vc.funExpr(f, f2); DebugAssert(!e.equals(f2) && !e.equals(f3), "Refcount problems"); Expr x = vc.boundVarExpr("x", "0", it); //x0:int List xs = new ArrayList(); xs.add(x); // Op lxsx = vc.lambdaExpr(xs, x); //\. x0:int Expr y = vc.ratExpr(1, 1); //1 List ys = new ArrayList(); ys.add(y); //<1> Expr lxsxy = vc.funExpr(lxsx, y); //(\. x0:int)1 Expr lxsxys = vc.funExpr(lxsx, ys); //(\. x0:int)<1> System.out.println("Lambda application: " + lxsxy); System.out.println("Simplified: " + vc.simplify(lxsxy)); return true; } catch (Exception e) { System.out.println("*** Exception caught in test(): \n" + e); e.printStackTrace(System.out); return false; } finally { if (vc != null) vc.delete(); } } public static boolean test1() throws Cvc3Exception { // It is important that all Expr objects are deleted before vc is // deleted. Therefore, we enclose them in a scope of try{ }catch // block. // // Also, vc methods may throw an Exception, and we want to delete vc // even in those exceptional cases. ValidityChecker vc = null; FlagsMut flags = null; try { flags = ValidityChecker.createFlags(null); flags.setFlag("dagify-exprs",false); flags.setFlag("dump-log", ".test1.cvc"); vc = ValidityChecker.create(flags); boolean b = check(vc, vc.trueExpr()); DebugAssert(b, "Should be valid"); vc.push(); b = check(vc, vc.falseExpr()); DebugAssert(!b, "Should be invalid"); vc.pop(); // Check p OR ~p Expr p = vc.varExpr("p", vc.boolType()); Expr e = vc.orExpr(p, vc.notExpr(p)); b = check(vc, e); DebugAssert(b, "Should be valid"); // Check x = y . f(x) = f(y) Expr x = vc.varExpr("x", vc.realType()); Expr y = vc.varExpr("y", vc.realType()); Type real2real = vc.funType(vc.realType(), vc.realType()); Op f = vc.createOp("f", real2real); Expr fx = vc.funExpr(f, x); Expr fy = vc.funExpr(f, y); e = vc.impliesExpr(vc.eqExpr(x,y),vc.eqExpr(fx, fy)); b = check(vc, e); DebugAssert(b, "Should be valid"); // Check f(x) = f(y) . x = y e = vc.impliesExpr(vc.eqExpr(fx,fy),vc.eqExpr(x, y)); int scopeLevel = vc.scopeLevel(); vc.push(); b = check(vc, e); DebugAssert(!b, "Should be invalid"); // Get counter-example System.out.println("Scope level: " + vc.scopeLevel()); System.out.println("Counter-example:"); List assertions = vc.getCounterExample(); for (int i = 0; i < assertions.size(); ++i) { System.out.println((Expr)assertions.get(i)); } System.out.println("End of counter-example"); System.out.println(); // Reset to initial scope System.out.println("Resetting"); vc.pop(); DebugAssert(scopeLevel == vc.scopeLevel(), "scope error"); System.out.println("Scope level: " + vc.scopeLevel()); System.out.println(); // Check w = x & x = y & y = z & f(x) = f(y) & x = 1 & z = 2 Expr w = vc.varExpr("w", vc.realType()); Expr z = vc.varExpr("z", vc.realType()); System.out.println("Push Scope"); System.out.println(); vc.push(); newAssertion(vc, vc.eqExpr(w, x)); newAssertion(vc, vc.eqExpr(x, y)); newAssertion(vc, vc.eqExpr(y, z)); newAssertion(vc, vc.eqExpr(fx, fy)); newAssertion(vc, vc.eqExpr(x, vc.ratExpr(1))); System.out.println("simplify(w) = " + vc.simplify(w)); DebugAssert(vc.simplify(w).equals(vc.ratExpr(1)), "Expected simplify(w) = 1"); newAssertion(vc, vc.eqExpr(z, vc.ratExpr(2))); System.out.println("Inconsistent?: " + vc.inconsistent()); System.out.println("Assumptions Used:"); assertions = vc.inconsistentReasons(); for (int i = 0; i < assertions.size(); ++i) { System.out.println((Expr)assertions.get(i)); } System.out.println("Pop Scope"); System.out.println(); vc.pop(); System.out.println("simplify(w) = " + vc.simplify(w)); DebugAssert(vc.simplify(w).equals(w), "Expected simplify(w) = w"); System.out.println("Inconsistent?: " + vc.inconsistent()); return true; } catch (Exception e) { System.out.println("*** Exception caught in test1(): \n" + e); e.printStackTrace(System.out); return false; } finally { if (vc != null) vc.delete(); if (flags != null) flags.delete(); } } public static boolean test2() throws Cvc3Exception { ValidityChecker vc = null; FlagsMut flags = null; try { flags = ValidityChecker.createFlags(null); flags.setFlag("dagify-exprs",false); vc = ValidityChecker.create(flags); Expr bexpr = vc.varExpr("b", vc.intType()); vc.assertFormula(vc.ltExpr(bexpr, vc.ratExpr(10))); Expr c = vc.varExpr("c", vc.intType()); vc.assertFormula(vc.orExpr(vc.eqExpr(c, vc.ratExpr(0)), vc.eqExpr(c, vc.ratExpr(1)))); boolean b = check(vc, vc.leExpr(bexpr, vc.ratExpr(10))); DebugAssert(b, "Should be valid"); b = check(vc, vc.falseExpr()); DebugAssert(!b, "Should be invalid"); vc.returnFromCheck(); // Check x = y . g(x,y) = g(y,x) Expr x = vc.varExpr("x", vc.realType()); Expr y = vc.varExpr("y", vc.realType()); Type real = vc.realType(); List RxR = new ArrayList(); RxR.add(real); RxR.add(real); Type realxreal2real = vc.funType(RxR, real); Op g = vc.createOp("g", realxreal2real); Expr gxy = vc.funExpr(g, x, y); Expr gyx = vc.funExpr(g, y, x); Expr e = vc.impliesExpr(vc.eqExpr(x,y),vc.eqExpr(gxy, gyx)); b = check(vc, e); DebugAssert(b, "Should be valid"); Op h = vc.createOp("h", realxreal2real); Expr hxy = vc.funExpr(h, x, y); Expr hyx = vc.funExpr(h, y, x); e = vc.impliesExpr(vc.eqExpr(x,y),vc.eqExpr(hxy, hyx)); b = check(vc, e); DebugAssert(b, "Should be valid"); return true; } catch (Exception e) { System.out.println("*** Exception caught in test2(): \n" + e); e.printStackTrace(System.out); return false; } finally { if (vc != null) vc.delete(); if (flags != null) flags.delete(); } } public static ExprMut ltLex(ValidityChecker vc, Expr i1, Expr i2, Expr j1, Expr j2) throws Cvc3Exception { Expr res = vc.ltExpr(i1, j1); return vc.orExpr(res, vc.andExpr(vc.eqExpr(i1, j1), vc.ltExpr(i2, j2))); } public static ExprMut createTestFormula(ValidityChecker vc, Expr i1, Expr i2, Expr r1, Expr r2) throws Cvc3Exception { Expr lt1 = ltLex(vc, r1, r2, i1, i2); Expr lt2 = ltLex(vc, i2, i1, r2, r1); return vc.andExpr(lt1, lt2); } public static boolean test3() throws Cvc3Exception { ValidityChecker vc = null; FlagsMut flags = null; try { flags = ValidityChecker.createFlags(null); flags.setFlag("dagify-exprs",false); vc = ValidityChecker.create(flags); Expr i = vc.varExpr("i", vc.realType()); Expr j = vc.varExpr("j", vc.realType()); Expr k = vc.varExpr("k", vc.realType()); Expr one = vc.ratExpr(1); Expr test = createTestFormula(vc, i, j, vc.minusExpr(i, one), vc.minusExpr(j, k)); System.out.println("Trying test: " + test); vc.push(); QueryResult result = vc.query(test); if (result == QueryResult.VALID) { System.out.println("Test Valid"); vc.pop(); } else { List assertions = vc.getCounterExample(); System.out.println("Test Invalid Under Conditions:"); for (int index = 0; index < assertions.size(); ++index) { System.out.println(assertions.get(index)); } // Try assertions one by one for (int index = 0; index < assertions.size(); ++index) { Expr condition = vc.notExpr((Expr)assertions.get(index)); System.out.println("Trying test under condition: " + condition); vc.pop(); vc.push(); printResult(vc.query(vc.impliesExpr(condition, test))); } } return true; } catch (Exception e) { System.out.println("*** Exception caught in test3(): \n" + e); e.printStackTrace(System.out); return false; } finally { if (vc != null) vc.delete(); if (flags != null) flags.delete(); } } public static boolean test4() throws Cvc3Exception { ValidityChecker vc = null; FlagsMut flags = null; try { flags = ValidityChecker.createFlags(null); flags.setFlag("dagify-exprs",false); vc = ValidityChecker.create(flags); Expr i = vc.varExpr("i", vc.realType()); Expr j = vc.varExpr("j", vc.realType()); Expr k = vc.varExpr("k", vc.realType()); Expr one = vc.ratExpr(1); Expr test = createTestFormula(vc, i, j, vc.minusExpr(i, one), vc.minusExpr(j, k)); System.out.println("Trying test: " + test); vc.push(); QueryResult result = vc.query(test); if (result == QueryResult.VALID) { System.out.println("Test Valid"); } else { List assertions = vc.getCounterExample(); System.out.println("Test Invalid Under Conditions:"); for (int index = 0; index < assertions.size(); ++index) { System.out.println(assertions.get(index)); } // Try assertions one by one for (int index = 0; index < assertions.size(); ++index) { Expr condition = vc.notExpr((Expr)assertions.get(index)); System.out.println("Trying test under condition: " + condition); vc.pop(); vc.push(); printResult(vc.query(vc.impliesExpr(condition, test))); } } return true; } catch (Exception e) { System.out.println("*** Exception caught in test4(): \n" + e); e.printStackTrace(System.out); return false; } finally { if (vc != null) vc.delete(); if (flags != null) flags.delete(); } } public static void findLeaves(Expr e, List l) throws Cvc3Exception { int ar = e.arity(); if (ar > 0) { for (int i = 0; i < ar; ++i) { findLeaves(e.getChild(i), l); } return; } l.add(e); } public static boolean hasij(Expr e, Expr i, Expr j) throws Cvc3Exception { int ar = e.arity(); if (ar > 0) { for (int k = 0; k < ar; ++k) if (hasij(e.getChild(k), i, j)) return true; return false; } if (e.equals(i) || e.equals(j)) return true; return false; } public static Expr plusExpr(ValidityChecker vc, List kids) throws Cvc3Exception { if (kids.size() == 0) return vc.ratExpr(0); else if (kids.size() == 1) return (Expr)kids.get(0); else if (kids.size() == 2) return vc.plusExpr((Expr)kids.get(0), (Expr)kids.get(1)); else { Expr r = (Expr)kids.get(kids.size() - 1); kids.remove(kids.size() - 1); return vc.plusExpr(plusExpr(vc, kids), r); } } public static boolean test5() throws Cvc3Exception { ValidityChecker vc = null; FlagsMut flags = null; try { flags = ValidityChecker.createFlags(null); flags.setFlag("dagify-exprs",false); vc = ValidityChecker.create(flags); Expr i = vc.varExpr("i1", vc.realType()); Expr j = vc.varExpr("i2", vc.realType()); Expr p = vc.varExpr("p", vc.realType()); Expr q = vc.varExpr("q", vc.realType()); Expr r = vc.varExpr("r", vc.realType()); Expr a = vc.varExpr("arb_addr", vc.realType()); Expr N = vc.varExpr("N", vc.realType()); Expr M = vc.varExpr("M", vc.arrayType(vc.realType(), vc.realType())); Expr M2 = vc.writeExpr(M, vc.plusExpr(q, i), vc.readExpr(M, vc.plusExpr(r, i))); Expr M1 = vc.writeExpr(M, vc.plusExpr(p, j), vc.readExpr(M, vc.plusExpr(r, j))); Expr e = vc.eqExpr(vc.readExpr(vc.writeExpr(M2, vc.plusExpr(p, j), vc.readExpr(M2, vc.plusExpr(r, j))), a), vc.readExpr(vc.writeExpr(M1, vc.plusExpr(q, i), vc.readExpr(M1, vc.plusExpr(r, i))), a)); Expr one = vc.ratExpr(1); Expr zero = vc.ratExpr(0); Expr qmp = vc.minusExpr(q, p); Expr qmr = vc.minusExpr(q, r); List hyp = new ArrayList(); hyp.add(vc.ltExpr(i, j)); // hyp.add(vc.orExpr(vc.geExpr(qmp, N), vc.leExpr(qmp, zero))); // hyp.add(vc.orExpr(vc.geExpr(qmr, N), vc.leExpr(qmr, zero))); Expr test = vc.impliesExpr(vc.andExpr(hyp), e); Expr query; System.out.println("Checking verification condition:" + test); vc.push(); QueryResult result = vc.query(test); if (result == QueryResult.VALID) { System.out.println("Test Valid"); } else { List conditions = new ArrayList(); int req; List assertions = vc.getCounterExample(); System.out.println("Invalid Under Conditions:"); for (int index = 0; index < assertions.size(); ++index) { if (((Expr)assertions.get(index)).equals(vc.notExpr(test))) { for (; index < assertions.size()-1; ++index) { assertions.set(index, assertions.get(index+1)); } assertions.remove(assertions.size() - 1); break; } } for (int index = 0; index < assertions.size(); ++index) { System.out.println(assertions.get(index)); } System.out.println(); // Try assertions one by one for (int index = 0; index < assertions.size(); ++index) { e = (Expr)assertions.get(index); // Check condition for eligibility if (e.isNot()) { System.out.println("Condition ineligible: negation: " + e); System.out.println(); continue; } if (e.isEq()) { req = 2; } else req = 1; List leaves = new ArrayList(); findLeaves(e, leaves); for (int index2 = 0; index2 < leaves.size(); ++index2) { if (!((Expr)leaves.get(index2)).isVar() || ((Expr)leaves.get(index2)).equals(i) || ((Expr)leaves.get(index2)).equals(j) || ((Expr)leaves.get(index2)).equals(a)) continue; req--; } if (req > 0) { System.out.println("Condition ineligible: not enough non-loop variables: " + e); System.out.println(); continue; } System.out.println("Condition selected: " + e); System.out.println(); conditions.add(vc.notExpr(e)); System.out.println("Trying verification condition with hypothesis: " + vc.andExpr(conditions)); vc.pop(); vc.push(); query = vc.impliesExpr(vc.andExpr(conditions), test); result = vc.query(test); if (result == QueryResult.VALID) { System.out.println("Result Valid"); break; } else { assertions = vc.getCounterExample(); System.out.println("Invalid Under Conditions:"); for (int index2 = 0; index2 < assertions.size(); ++index2) { if (((Expr)assertions.get(index2)).equals(vc.notExpr(query))) { for (; index2 < assertions.size()-1; ++index2) { assertions.set(index2, assertions.get(index2+1)); } assertions.remove(assertions.size() - 1); break; } } for (int index2 = 0; index2 < assertions.size(); ++index2) { System.out.println(assertions.get(index2)); } System.out.println(); index = assertions.size(); } } System.out.println(); System.out.println("Attempting to remove loop variables"); // replace loop variables in conditions List newConditions = new ArrayList(); List newPlus = new ArrayList(); boolean foundi, foundj, negi, negj; Expr minusone = vc.ratExpr(-1); int index; for (index = 0; index < conditions.size(); ++index) { if (((Expr)conditions.get(index)).getChild(0).isEq()) { e = vc.simplify( vc.minusExpr(((Expr)conditions.get(index)).getChild(0).getChild(0), ((Expr)conditions.get(index)).getChild(0).getChild(1))); if (hasij(e, i, j)) { if (e.isPlus()) { newPlus.clear(); newPlus.add(e.getChild(0)); foundi = foundj = negi = negj = false; for (int index2 = 1; index2 < e.arity(); index2++) { Expr term = e.getChild(index2); if (term.equals(i) && !foundi) foundi = true; else if (term.equals(j) && !foundj) { foundj = true; negj = true; } else if (term.isMult() && term.getChild(0).equals(minusone) && term.getChild(1).equals(i) && !foundi) { foundi = true; negi = true; } else if (term.isMult() && term.getChild(0).equals(minusone) && term.getChild(1).equals(j) && !foundj) foundj = true; else newPlus.add(term); } if (foundi && foundj && (negi && negj || (!negi && !negj))) { e = plusExpr(vc, newPlus); if (negi && negj) e = vc.uminusExpr(e); e = vc.simplify(e); if (!hasij(e, i, j)) { newConditions.add(vc.orExpr(vc.geExpr(e, N), vc.leExpr(e, zero))); continue; } } } System.out.println("Unable to remove loop variables:" + e); break; } } newConditions.add(conditions.get(index)); } if (index == conditions.size()) { System.out.println("Loop variables successfully removed:"); Expr cond = (newConditions.size()>0)? vc.andExpr(newConditions) : vc.trueExpr(); System.out.println(cond); List loopConditions = new ArrayList(); loopConditions.add(cond); loopConditions.add(vc.geExpr(i, one)); loopConditions.add(vc.geExpr(j, one)); loopConditions.add(vc.leExpr(i, N)); loopConditions.add(vc.leExpr(j, N)); vc.pop(); vc.push(); System.out.println("Final query"); printResult(vc.query(vc.impliesExpr(vc.andExpr(loopConditions), test))); } } return true; } catch (Exception e) { System.out.println("*** Exception caught in test5(): \n" + e); e.printStackTrace(System.out); return false; } finally { if (vc != null) vc.delete(); if (flags != null) flags.delete(); } } public static boolean test6() throws Cvc3Exception { ValidityChecker vc1 = null; ValidityChecker vc2 = null; try { vc1 = ValidityChecker.create(); vc2 = ValidityChecker.create(); Type real1 = vc1.realType(); Expr x1 = vc1.varExpr("x", real1); Expr y1 = vc1.boundVarExpr("y", "0", real1); System.out.println("vc1 variables: " + x1 + ", " + y1); Expr x2 = vc2.varExpr("x", vc2.importType(real1)); Expr y2 = vc2.boundVarExpr("y", "0", vc2.realType()); System.out.println("vc2 variables: " + x2 + ", " + y2); System.out.println("vars imported to vc2 from vc1: " + vc2.importExpr(x1) + ", " + vc2.importExpr(y1)); Expr t1 = vc1.trueExpr(); Expr and1 = vc1.andExpr(t1, vc1.falseExpr()); Op f1 = vc1.createOp("f", vc1.funType(real1, real1)); Expr fx1 = vc1.funExpr(f1, x1); Expr f5_1 = vc1.funExpr(f1, vc1.ratExpr(5,1)); Type rt1 = vc1.recordType("foo", real1, "bar", real1); Expr r1 = vc1.recordExpr("foo", fx1, "bar", f5_1); Expr r1_eq = vc1.eqExpr(r1, vc1.recUpdateExpr(r1, "foo", f5_1)); Type art1 = vc1.arrayType(real1, rt1); Expr ar1 = vc1.varExpr("ar", art1); Expr ar_eq1 = vc1.eqExpr(vc1.writeExpr(ar1, x1, r1), ar1); Expr query1 = vc1.eqExpr(vc1.recSelectExpr(vc1.readExpr(ar1, x1), "foo"), vc1.recSelectExpr(r1, "bar")); System.out.println("*** VC #1:"); newAssertion(vc1, r1_eq); newAssertion(vc1, ar_eq1); check(vc1, query1); System.out.println("*** VC #2:"); newAssertion(vc2, vc2.importExpr(r1_eq)); newAssertion(vc2, vc2.importExpr(ar_eq1)); check(vc2, vc2.importExpr(query1)); return true; } catch (Exception e) { System.out.println("*** Exception caught in test6(): \n" + e); e.printStackTrace(System.out); return false; } finally { if (vc1 != null) vc1.delete(); if (vc2 != null) vc2.delete(); } } public static boolean test7() throws Cvc3Exception { ValidityChecker vc1 = null; ValidityChecker vc2 = null; try { vc1 = ValidityChecker.create(); vc2 = ValidityChecker.create(); Expr e1 = vc1.varExpr("e1", vc1.realType()); Expr e2 = vc2.varExpr("e2", vc2.realType()); newAssertion(vc2, vc2.eqExpr(vc2.importExpr(e1), e2)); return true; } catch (Exception e) { System.out.println("*** Exception caught in test7(): \n" + e); e.printStackTrace(System.out); return false; } finally { if (vc1 != null) vc1.delete(); if (vc2 != null) vc2.delete(); } } public static boolean test8() throws Cvc3Exception { ValidityChecker vc = null; try { vc = ValidityChecker.create(); List vec = new ArrayList(); vec.add(vc.boundVarExpr("x", "x", vc.realType())); Expr lambda = vc.lambdaExpr(vec, vc.falseExpr()).getExpr(); try { Type t = vc.subtypeType(lambda, vc.nullExpr()); DebugAssert(false, "Typechecking exception expected"); } catch(TypecheckException e) { // fall through } return true; } catch (Exception e) { System.out.println("*** Exception caught in test5(): \n" + e); e.printStackTrace(System.out); return false; } finally { if (vc != null) vc.delete(); } } public static ExprMut adder(ValidityChecker vc, Expr a, Expr b, Expr c) throws Cvc3Exception { return vc.notExpr(vc.iffExpr(vc.notExpr(vc.iffExpr(a,b)),c)); } public static ExprMut carry(ValidityChecker vc, Expr a, Expr b, Expr c) throws Cvc3Exception { return vc.orExpr(vc.andExpr(a,b), vc.orExpr(vc.andExpr(b,c),vc.andExpr(a,c))); } public static List add(ValidityChecker vc, List a, List b) throws Cvc3Exception { int N = a.size(); Expr c = vc.falseExpr(); List sum = new ArrayList(); for (int i = 0; i < N; i++) { sum.add(adder(vc,(Expr)a.get(i),(Expr)b.get(i),c)); c = carry(vc,(Expr)a.get(i),(Expr)b.get(i),c); } return sum; } public static ExprMut vectorEq(ValidityChecker vc, List a, List b) throws Cvc3Exception { int N = a.size(); ExprMut result = vc.trueExpr(); for (int i = 0; i < N; i++) { result = vc.andExpr(result, vc.iffExpr((Expr)a.get(i), (Expr)b.get(i))); } return result; } public static boolean test9(int N) throws Cvc3Exception { ValidityChecker vc = null; try { vc = ValidityChecker.create(); int i; List a = new ArrayList(); List b = new ArrayList(); for (i=0; i < N; i++) { a.add(vc.varExpr("a" + Integer.toString(i), vc.boolType())); b.add(vc.varExpr("b" + Integer.toString(i), vc.boolType())); } List sum1 = add(vc,a,b); List sum2 = add(vc,b,a); Expr q = vectorEq(vc,sum1,sum2); check(vc, q); // Proof p = vc.getProof(); return true; } catch (Exception e) { System.out.println("*** Exception caught in test9(): \n" + e); e.printStackTrace(System.out); return false; } finally { if (vc != null) vc.delete(); } } public static boolean test22() throws Cvc3Exception { ValidityChecker vc = null; try { vc = ValidityChecker.create(); Type intType = vc.intType(); Type fType = vc.funType(intType, intType); Op f = vc.createOp("f", fType); Expr x = vc.varExpr("x", intType); Expr fx = vc.exprFromString("f(x)"); Expr p = vc.exprFromString("FORALL (x:INT) : x < f(x)"); List patternvv = new ArrayList(); List patternv = new ArrayList(); patternv.add(fx); patternvv.add(patternv); vc.setTriggers(p, patternv); DebugAssert(patternvv.equals(p.getTriggers()), "Expected p.getTriggers() == patternvv: " + p.toString()); vc.setMultiTriggers(p, patternvv); DebugAssert(patternvv.equals(p.getTriggers()), "Expected p.getTriggers() == patternvv: " + p.toString()); List vars = new ArrayList(); vars.add(x); Expr r = vc.forallExpr(vars, vc.ltExpr(x, fx), patternv); DebugAssert(patternvv.equals(r.getTriggers()), "Expected r.getTriggers() == patternvv: " + r.toString()); Expr s = vc.exprFromString("FORALL (x:INT) : x > f(x)"); vc.setTrigger(s, fx); List trigsvv = s.getTriggers(); DebugAssert(trigsvv.size() == 1, "Expected s.getTriggers().size() == 1: " + trigsvv.size()); List trigsv = (List)trigsvv.get(0); DebugAssert(trigsv.size() == 1, "Expected s.getTriggers()[0].size() == 1: " + trigsv.size()); DebugAssert(fx.equals(trigsv.get(0)), "Expected s.getTriggers()[0][0] == fx: " + (trigsv.get(0))); Expr t = vc.exprFromString("FORALL (x:INT) : x > f(x)"); vc.setMultiTrigger(t, patternv); trigsvv = t.getTriggers(); DebugAssert(trigsvv.size() == 1, "Expected t.getTriggers().size() == 1: " + trigsvv.size()); trigsv = (List)trigsvv.get(0); DebugAssert(trigsv.size() == 1, "Expected t.getTriggers()[0].size() == 1: " + trigsv.size()); DebugAssert(fx.equals(trigsv.get(0)), "Expected t.getTriggers()[0][0] == fx: " + (trigsv.get(0))); Expr u = vc.forallExprMultiTriggers(vars, vc.ltExpr(x, fx), patternvv); DebugAssert(patternvv.equals(u.getTriggers()), "Expected u.getTriggers() == patternvv: " + u.toString()); } catch (Exception e) { System.out.println("*** Exception caught in test22(): \n" + e); e.printStackTrace(System.out); return false; } finally { if (vc != null) vc.delete(); } return true; } private static boolean test23() throws Cvc3Exception { ValidityChecker vc = null; try { vc = ValidityChecker.create(); Type intType = vc.intType(); Expr x = vc.varExpr("x",intType); Expr y= vc.varExpr("y",intType); Expr a = vc.varExpr("a",intType); Expr b = vc.varExpr("b",intType); Expr s = vc.exprFromString("x < y"); Expr t = vc.exprFromString("a < b"); System.out.println( "s=" + s + "\nt=" + t ); List oldExprs = new ArrayList(), newExprs = new ArrayList(); oldExprs.add(x); oldExprs.add(y); newExprs.add(a); newExprs.add(b); Expr u = s.subst(oldExprs,newExprs); System.out.println( "u=" + u ); DebugAssert( t.equals(u), "Expected t==u" ); } catch(Throwable e) { System.out.println( "*** Exception caught in test23(): "); e.printStackTrace(System.out); return false; } finally { if (vc != null) vc.delete(); } return true; } public static ExprMut bvadder(ValidityChecker vc, Expr a, Expr b, Expr c) throws Cvc3Exception { return vc.newBVXorExpr(a, vc.newBVXorExpr(b, c)); } public static ExprMut bvcarry(ValidityChecker vc, Expr a, Expr b, Expr c) throws Cvc3Exception { return vc.newBVOrExpr(vc.newBVAndExpr(a,b), vc.newBVOrExpr(vc.newBVAndExpr(b,c),vc.newBVAndExpr(a,c))); } public static List bvadd(ValidityChecker vc, List a, List b) throws Cvc3Exception { int N=a.size(); Expr c = vc.newBVConstExpr(new Rational(0, vc.embeddedManager()), 1); List sum = new ArrayList(); for (int i = 0; i < N; i++) { sum.add(bvadder(vc,(Expr)a.get(i),(Expr)b.get(i),c)); c = bvcarry(vc,(Expr)a.get(i),(Expr)b.get(i),c); } return sum; } public static ExprMut bvvectorEq(ValidityChecker vc, List a, List b) throws Cvc3Exception { int N = a.size(); ExprMut result = vc.newBVConstExpr("1"); for (int i = 0; i < N; i++) { result = vc.newBVAndExpr(result, vc.newBVXnorExpr((Expr)a.get(i), (Expr)b.get(i))); } return result; } public static boolean bvtest9(int N) throws Cvc3Exception { ValidityChecker vc = null; try { vc = ValidityChecker.create(); Expr a, b, sum1; a = vc.varExpr("a", vc.bitvecType(N)); b = vc.varExpr("b", vc.bitvecType(N)); List kids = new ArrayList(); kids.add(a); kids.add(b); sum1 = vc.newBVPlusExpr(N, kids); List avec = new ArrayList(); List bvec = new ArrayList(); List sum1vec = new ArrayList(); for (int i = 0; i < N; i++) { avec.add(vc.newBVExtractExpr(a, i, i)); bvec.add(vc.newBVExtractExpr(b, i, i)); sum1vec.add(vc.newBVExtractExpr(sum1, i, i)); } List sum2 = bvadd(vc,avec,bvec); Expr q = bvvectorEq(vc,sum1vec,sum2); check(vc, vc.eqExpr(q,vc.newBVConstExpr("1"))); return true; } catch (Exception e) { System.out.println("*** Exception caught in bvtest9(): \n" + e); e.printStackTrace(System.out); return false; } finally { if (vc != null) vc.delete(); } } public static boolean test10() throws Cvc3Exception { ValidityChecker vc = null; try { vc = ValidityChecker.create(); Expr x = vc.varExpr("x", vc.realType()); Expr y = vc.varExpr("y", vc.realType()); Type real = vc.realType(); List RxR = new ArrayList(); RxR.add(real); RxR.add(real); Type realxreal2real = vc.funType(RxR, real); Op g = vc.createOp("g", realxreal2real); Expr gxy = vc.funExpr(g, x, y); Expr gyx = vc.funExpr(g, y, x); Expr ia = vc.eqExpr(x,y); Expr ib = vc.eqExpr(gxy, gyx); Expr e = vc.impliesExpr(vc.eqExpr(x,y),vc.eqExpr(gxy, gyx)); check(vc, e, false); Op h = vc.createOp("h", realxreal2real); Expr hxy = vc.funExpr(h, x, y); Expr hyx = vc.funExpr(h, y, x); e = vc.impliesExpr(vc.eqExpr(x,y),vc.eqExpr(hxy, hyx)); check(vc, e, false); return true; } catch (Exception e) { System.out.println("*** Exception caught in test10(): \n" + e); e.printStackTrace(System.out); return false; } finally { if (vc != null) vc.delete(); } } public static int printImpliedLiterals(ValidityChecker vc) throws Cvc3Exception { int count = 0; System.out.println("Implied Literals:"); Expr impLit = vc.getImpliedLiteral(); while (!impLit.isNull()) { ++count; System.out.println(impLit); impLit = vc.getImpliedLiteral(); } return count; } public static boolean test11() throws Cvc3Exception { ValidityChecker vc = null; try { vc = ValidityChecker.create(); Expr x = vc.varExpr("x", vc.realType()); Expr y = vc.varExpr("y", vc.realType()); Expr z = vc.varExpr("z", vc.realType()); Type real = vc.realType(); Type real2real = vc.funType(real, real); Type real2bool = vc.funType(real, vc.boolType()); Op f = vc.createOp("f", real2real); Op p = vc.createOp("p", real2bool); Expr fx = vc.funExpr(f, x); Expr fy = vc.funExpr(f, y); Expr px = vc.funExpr(p, x); Expr py = vc.funExpr(p, y); Expr xeqy = vc.eqExpr(x, y); Expr yeqx = vc.eqExpr(y, x); Expr xeqz = vc.eqExpr(x, z); Expr zeqx = vc.eqExpr(z, x); Expr yeqz = vc.eqExpr(y, z); Expr zeqy = vc.eqExpr(z, y); int c; vc.registerAtom(vc.eqExpr(x,vc.ratExpr(0,1))); vc.registerAtom(xeqy); vc.registerAtom(yeqx); vc.registerAtom(xeqz); vc.registerAtom(zeqx); vc.registerAtom(yeqz); vc.registerAtom(zeqy); vc.registerAtom(px); vc.registerAtom(py); vc.registerAtom(vc.eqExpr(fx, fy)); System.out.println("Push"); vc.push(); System.out.println("Assert x = y"); vc.assertFormula(xeqy); c = printImpliedLiterals(vc); DebugAssert(c==3,"Implied literal error 0"); System.out.println("Push"); vc.push(); System.out.println("Assert x /= z"); vc.assertFormula(vc.notExpr(xeqz)); c = printImpliedLiterals(vc); DebugAssert(c==4,"Implied literal error 1"); System.out.println("Pop"); vc.pop(); System.out.println("Push"); vc.push(); System.out.println("Assert y /= z"); vc.assertFormula(vc.notExpr(yeqz)); c = printImpliedLiterals(vc); DebugAssert(c==4,"Implied literal error 2"); System.out.println("Pop"); vc.pop(); System.out.println("Push"); vc.push(); System.out.println("Assert p(x)"); vc.assertFormula(px); c = printImpliedLiterals(vc); DebugAssert(c==2,"Implied literal error 3"); System.out.println("Pop"); vc.pop(); System.out.println("Push"); vc.push(); System.out.println("Assert p(y)"); vc.assertFormula(py); c = printImpliedLiterals(vc); DebugAssert(c==2,"Implied literal error 4"); System.out.println("Pop"); vc.pop(); System.out.println("Pop"); vc.pop(); System.out.println("Push"); vc.push(); System.out.println("Assert y = x"); vc.assertFormula(yeqx); c = printImpliedLiterals(vc); DebugAssert(c==3,"Implied literal error 5"); System.out.println("Pop"); vc.pop(); System.out.println("Push"); vc.push(); System.out.println("Assert p(x)"); vc.assertFormula(px); c = printImpliedLiterals(vc); DebugAssert(c==1,"Implied literal error 6"); System.out.println("Assert x = y"); vc.assertFormula(xeqy); c = printImpliedLiterals(vc); DebugAssert(c==4,"Implied literal error 7"); System.out.println("Pop"); vc.pop(); System.out.println("Push"); vc.push(); System.out.println("Assert NOT p(x)"); vc.assertFormula(vc.notExpr(px)); c = printImpliedLiterals(vc); DebugAssert(c==1,"Implied literal error 8"); System.out.println("Assert x = y"); vc.assertFormula(xeqy); c = printImpliedLiterals(vc); DebugAssert(c==4,"Implied literal error 9"); System.out.println("Pop"); vc.pop(); return true; } catch (Exception e) { System.out.println("*** Exception caught in test11(): \n" + e); e.printStackTrace(System.out); return false; } finally { if (vc != null) vc.delete(); } } public static boolean test12() throws Cvc3Exception { ValidityChecker vc = null; try { vc = ValidityChecker.create(); Type realType = vc.realType(); Type intType = vc.intType(); Type boolType = vc.boolType(); vc.push(); int initial_layer = vc.stackLevel(); int initial_scope = vc.scopeLevel(); Expr exprObj_trueID = vc.trueExpr(); Expr exprObj_falseID = vc.notExpr(vc.trueExpr()); vc.popTo(initial_layer); DebugAssert(vc.scopeLevel() == initial_scope, "Expected no change"); DebugAssert(vc.stackLevel() == initial_layer, "Expected no change"); // TODO: what happens if we push and then popscope? return true; } catch (Exception e) { System.out.println("*** Exception caught in test12(): \n" + e); e.printStackTrace(System.out); return false; } finally { if (vc != null) vc.delete(); } } public static boolean test13() throws Cvc3Exception { ValidityChecker vc = null; FlagsMut flags = null; try { flags = ValidityChecker.createFlags(null); flags.setFlag("dagify-exprs",false); flags.setFlag("dump-log", ".test13.cvc"); vc = ValidityChecker.create(flags); Expr rat_one = vc.ratExpr(1); Expr rat_two = vc.ratExpr(2); Expr rat_minus_one = vc.ratExpr(-1); QueryResult query_result; query_result = vc.query(vc.eqExpr(rat_two,rat_one)); System.out.println("2=1 " + query_result); query_result = vc.query(vc.eqExpr(rat_two,rat_minus_one)); System.out.println("2=-1 " + query_result); return true; } catch (Exception e) { System.out.println("*** Exception caught in test13(): \n" + e); e.printStackTrace(System.out); return false; } finally { if (vc != null) vc.delete(); if (flags != null) flags.delete(); } } public static Expr func1(ValidityChecker vc) throws Cvc3Exception { // local Expr 'tmp' Expr tmp = vc.varExpr("tmp", vc.boolType()); return vc.trueExpr(); } public static boolean test14() throws Cvc3Exception { ValidityChecker vc = null; try { vc = ValidityChecker.create(); // func call: ok Expr test1 = func1(vc); // func call: fail Expr test2 = func1(vc); return true; } catch (Exception e) { System.out.println("*** Exception caught in test13(): \n" + e); e.printStackTrace(System.out); return false; } finally { if (vc != null) vc.delete(); } } public static boolean test15() throws Cvc3Exception { ValidityChecker vc = null; FlagsMut flags = null; try { flags = ValidityChecker.createFlags(null); flags.setFlag("dagify-exprs",false); vc = ValidityChecker.create(flags); /***************************************************** * array declaration * *****************************************************/ // array: index type Type index_type = vc.subrangeType(vc.ratExpr(0), vc.ratExpr(3)); // array: data type Type data_type = vc.subrangeType(vc.ratExpr(0), vc.ratExpr(3)); // array type: [0 .. 3] of 0 .. 3 Type array_type = vc.arrayType(index_type, data_type); Expr arr = vc.varExpr("array", array_type); // array: [1,1,0,0] arr = vc.writeExpr(arr, vc.ratExpr(0), vc.ratExpr(1)); arr = vc.writeExpr(arr, vc.ratExpr(1), vc.ratExpr(1)); arr = vc.writeExpr(arr, vc.ratExpr(2), vc.ratExpr(0)); arr = vc.writeExpr(arr, vc.ratExpr(3), vc.ratExpr(0)); /***************************************************** * forall Expr * *****************************************************/ // for loop: index Expr id = vc.boundVarExpr("id", "0", vc.subrangeType(vc.ratExpr(0), vc.ratExpr(2))); List vars = new ArrayList(); vars.add(id); // for loop: body Expr for_body = vc.leExpr(vc.readExpr(arr, id), vc.readExpr(arr, vc.plusExpr(id, vc.ratExpr(1)))); // forall expr Expr forall_expr = vc.forallExpr(vars, for_body); vc.push(); check(vc, forall_expr); System.out.println("Scope level: " + vc.scopeLevel()); System.out.println("Counter-example:"); List assertions = vc.getCounterExample(); for (int i = 0; i < assertions.size(); ++i) { System.out.println(assertions.get(i)); } System.out.println("End of counter-example"); System.out.println(""); vc.pop(); /***************************************************** * manual expansion * *****************************************************/ Expr e1 = vc.leExpr(vc.readExpr(arr, vc.ratExpr(0)), vc.readExpr(arr, vc.ratExpr(1))); Expr e2 = vc.leExpr(vc.readExpr(arr, vc.ratExpr(1)), vc.readExpr(arr, vc.ratExpr(2))); Expr e3 = vc.leExpr(vc.readExpr(arr, vc.ratExpr(2)), vc.readExpr(arr, vc.ratExpr(3))); Expr manual_expr = vc.andExpr(e1, vc.andExpr(e2, e3)); /***************************************************** * exists Expr * *****************************************************/ // exists: index Expr id_ex = vc.varExpr("id_ex", vc.subrangeType(vc.ratExpr(0), vc.ratExpr(2))); List vars_ex = new ArrayList(); vars_ex.add(id_ex); // exists: body Expr ex_body = vc.gtExpr(vc.readExpr(arr, id_ex), vc.readExpr(arr, vc.plusExpr(id_ex, vc.ratExpr(1)))); // exists expr Expr ex_expr = vc.existsExpr(vars_ex, ex_body); /***************************************************** * ??? forall <==> manual expansion * *****************************************************/ System.out.println("Checking forallExpr <==> manual expansion ..."); if (vc.query(vc.iffExpr(forall_expr, manual_expr)) == QueryResult.VALID) System.out.println(" -- yes."); else { System.out.println(" -- no, with counter examples as "); List assert1 = vc.getCounterExample(); for (int i = 0; i < assert1.size(); i ++) System.out.println(assert1.get(i)); } System.out.println(); /***************************************************** * ??? !forall <==> existsExpr * *****************************************************/ System.out.println(); System.out.println("Checking !forallExpr <==> existsExpr ..."); if (vc.query(vc.iffExpr(vc.notExpr(forall_expr), ex_expr)) == QueryResult.VALID) System.out.println(" -- yes."); else if (vc.incomplete()) { System.out.println(" -- incomplete:"); List reasons = vc.incompleteReasons(); for (int i = 0; i < reasons.size(); ++i) System.out.println(reasons.get(i)); } else { System.out.println(" -- no, with counter examples as "); List assert2 = vc.getCounterExample(); for (int i = 0; i < assert2.size(); i ++) System.out.println(assert2.get(i)); } System.out.println(); System.out.println("End of testcases."); System.out.println(); return true; } catch (Exception e) { System.out.println("*** Exception caught in test15(): \n" + e); e.printStackTrace(System.out); return false; } finally { if (vc != null) vc.delete(); if (flags != null) flags.delete(); } } public static boolean test16() throws Cvc3Exception { ValidityChecker vc = null; try { vc = ValidityChecker.create(); Type zto100 = vc.subrangeType(vc.ratExpr(0), vc.ratExpr(100)); Expr mem = vc.varExpr("mem", vc.arrayType(zto100, vc.intType())); Expr a = vc.varExpr("a", zto100); Expr b = vc.varExpr("b", zto100); Expr lhs = vc.readExpr(vc.writeExpr(mem, a, vc.ratExpr(30)), b); Expr rhs = vc.readExpr(vc.writeExpr(mem, b, vc.ratExpr(40)), a); Expr q = vc.impliesExpr(vc.notExpr(vc.eqExpr(a, b)), vc.eqExpr(lhs, rhs)); check(vc, q); System.out.println("Scope level: " + vc.scopeLevel()); System.out.println("Counter-example:"); List assertions = vc.getCounterExample(); DebugAssert(assertions.size() > 0, "Expected non-empty counter-example"); for (int i = 0; i < assertions.size(); ++i) { System.out.println(assertions.get(i)); } System.out.println("End of counter-example"); System.out.println(); HashMap m = vc.getConcreteModel(); if(m.isEmpty()) System.out.println(" Did not find concrete model for any vars"); else { System.out.println("%Satisfiable Variable Assignment: %"); Iterator it = m.entrySet().iterator(); while(it.hasNext()) { Map.Entry next = (Map.Entry)it.next(); Expr eq; Expr key = (Expr)next.getKey(); Expr value = (Expr)next.getValue(); if (key.getType().isBoolean()) { DebugAssert(value.isBooleanConst(), "Bad variable assignement: e = "+ key +"\n\n val = "+ value); if(value.isTrue()) eq = key; else eq = vc.notExpr(key); } else eq = vc.eqExpr(key, value); //:TODO:System.out.println(Expr(ASSERT, eq)); System.out.println(eq); } } return true; } catch (Exception e) { System.out.println("*** Exception caught in test16(): \n" + e); e.printStackTrace(System.out); return false; } finally { if (vc != null) vc.delete(); } } public static boolean test17() throws Cvc3Exception { ValidityChecker vc = null; try { vc = ValidityChecker.create(); try { List selectors = new ArrayList(); List types = new ArrayList(); selectors.add("car"); types.add(vc.intType().getExpr()); selectors.add("cdr"); types.add(vc.stringExpr("list")); Type badList = vc.dataType("list", "cons", selectors, types); DebugAssert(false, "Typechecking exception expected"); } catch(TypecheckException e) { // fall through } vc.delete(); vc = ValidityChecker.create(); { List constructors = new ArrayList(); List selectors = new ArrayList(); List selectors0 = new ArrayList(); List selectors1 = new ArrayList(); selectors.add(selectors0); selectors.add(selectors1); List types = new ArrayList(); List types0 = new ArrayList(); List types1 = new ArrayList(); types.add(types0); types.add(types1); constructors.add("cons"); selectors0.add("car"); types0.add(vc.intType().getExpr()); selectors0.add("cdr"); types0.add(vc.stringExpr("list")); constructors.add("null"); Type list = vc.dataType("list", constructors, selectors, types); Expr x = vc.varExpr("x", vc.intType()); Expr y = vc.varExpr("y", list); List args = new ArrayList(); args.add(x); args.add(y); Expr cons = vc.datatypeConsExpr("cons", args); Expr sel = vc.datatypeSelExpr("car", cons); boolean b = check(vc, vc.eqExpr(sel, x)); DebugAssert(b, "Should be valid"); } vc.delete(); vc = ValidityChecker.create(); try { List names = new ArrayList(); List constructors = new ArrayList(); List constructors0 = new ArrayList(); List constructors1 = new ArrayList(); constructors.add(constructors0); constructors.add(constructors1); List selectors = new ArrayList(); List selectors0 = new ArrayList(); List selectors1 = new ArrayList(); List selectors00 = new ArrayList(); List selectors10 = new ArrayList(); selectors.add(selectors0); selectors0.add(selectors00); selectors.add(selectors1); selectors1.add(selectors10); List types = new ArrayList(); List types0 = new ArrayList(); List types1 = new ArrayList(); List types00 = new ArrayList(); List types10 = new ArrayList(); types.add(types0); types0.add(types00); types.add(types1); types1.add(types10); names.add("list1"); constructors0.add("cons1"); selectors00.add("car1"); types00.add(vc.intType().getExpr()); selectors00.add("cdr1"); types00.add(vc.stringExpr("list2")); names.add("list2"); constructors1.add("cons2"); selectors10.add("car2"); types10.add(vc.intType().getExpr()); selectors10.add("cdr2"); types10.add(vc.stringExpr("list1")); constructors1.add("null"); List returnTypes = vc.dataType(names, constructors, selectors, types); Type list1 = (Type)returnTypes.get(0); Type list2 = (Type)returnTypes.get(1); Expr x = vc.varExpr("x", vc.intType()); Expr y = vc.varExpr("y", list2); Expr z = vc.varExpr("z", list1); List args = new ArrayList(); args.add(x); args.add(y); Expr cons1 = vc.datatypeConsExpr("cons1", args); Expr isnull = vc.datatypeTestExpr("null", y); Expr hyp = vc.andExpr(vc.eqExpr(z, cons1), isnull); Expr nullE = vc.datatypeConsExpr("null", new ArrayList()); args = new ArrayList(); args.add(x); args.add(nullE); Expr cons1_2 = vc.datatypeConsExpr("cons1", args); boolean b = check(vc, vc.impliesExpr(hyp, vc.eqExpr(z, cons1_2))); DebugAssert(b, "Should be valid"); } catch(TypecheckException e) { // fall through } vc.delete(); vc = ValidityChecker.create(); { List constructors = new ArrayList(); List selectors = new ArrayList(); selectors.add(new ArrayList()); selectors.add(new ArrayList()); List types = new ArrayList(); types.add(new ArrayList()); types.add(new ArrayList()); constructors.add("A"); constructors.add("B"); Type two = vc.dataType("two", constructors, selectors, types); Expr x = vc.varExpr("x", two); Expr y = vc.varExpr("y", two); Expr z = vc.varExpr("z", two); List args = new ArrayList(); args.add(vc.notExpr(vc.eqExpr(x,y))); args.add(vc.notExpr(vc.eqExpr(y,z))); args.add(vc.notExpr(vc.eqExpr(x,z))); boolean b = check(vc, vc.notExpr(vc.andExpr(args))); DebugAssert(b, "Should be valid"); } return true; } catch (Exception e) { System.out.println("*** Exception caught in test17(): \n" + e); e.printStackTrace(System.out); return false; } finally { if (vc != null) vc.delete(); } } public static boolean test18() throws Cvc3Exception { ValidityChecker vc = null; FlagsMut flags = null; try { flags = ValidityChecker.createFlags(null); flags.setFlag("tcc", true); vc = ValidityChecker.create(flags); List names = new ArrayList(); List constructors = new ArrayList(); List constructors0 = new ArrayList(); List constructors1 = new ArrayList(); List constructors2 = new ArrayList(); constructors.add(constructors0); constructors.add(constructors1); constructors.add(constructors2); List selectors = new ArrayList(); List selectors0 = new ArrayList(); List selectors1 = new ArrayList(); List selectors2 = new ArrayList(); List selectors00 = new ArrayList(); List selectors01 = new ArrayList(); List selectors10 = new ArrayList(); List selectors11 = new ArrayList(); List selectors20 = new ArrayList(); List selectors21 = new ArrayList(); selectors.add(selectors0); selectors0.add(selectors00); selectors0.add(selectors01); selectors.add(selectors1); selectors1.add(selectors10); selectors1.add(selectors11); selectors.add(selectors2); selectors2.add(selectors20); selectors2.add(selectors21); List types = new ArrayList(); List types0 = new ArrayList(); List types1 = new ArrayList(); List types2 = new ArrayList(); List types00 = new ArrayList(); List types01 = new ArrayList(); List types10 = new ArrayList(); List types11 = new ArrayList(); List types20 = new ArrayList(); List types21 = new ArrayList(); types.add(types0); types0.add(types00); types0.add(types01); types.add(types1); types1.add(types10); types1.add(types11); types.add(types2); types2.add(types20); types2.add(types21); names.add("nat"); constructors0.add("zero"); constructors0.add("succ"); selectors01.add("pred"); types01.add(vc.stringExpr("nat")); names.add("list"); constructors1.add("cons"); selectors10.add("car"); types10.add(vc.stringExpr("tree")); selectors10.add("cdr"); types10.add(vc.stringExpr("list")); constructors1.add("null"); names.add("tree"); constructors2.add("leaf"); constructors2.add("node"); selectors21.add("data"); types21.add(vc.stringExpr("nat")); selectors21.add("children"); types21.add(vc.stringExpr("list")); List returnTypes = vc.dataType(names, constructors, selectors, types); Type nat = (Type)returnTypes.get(0); Type listType = (Type)returnTypes.get(1); Type tree = (Type)returnTypes.get(2); Expr x = vc.varExpr("x", nat); List args = new ArrayList(); Expr zero = vc.datatypeConsExpr("zero", args); Expr nullE = vc.datatypeConsExpr("null", args); Expr leaf = vc.datatypeConsExpr("leaf", args); vc.push(); try { check(vc, vc.notExpr(vc.eqExpr(zero, nullE))); DebugAssert(false, "Should have caught tcc exception"); } catch (TypecheckException e) { } vc.pop(); args.add(vc.datatypeSelExpr("pred",x)); Expr spx = vc.datatypeConsExpr("succ", args); Expr spxeqx = vc.eqExpr(spx, x); vc.push(); try { check(vc, spxeqx); DebugAssert(false, "Should have caught tcc exception"); } catch(TypecheckException e) { } vc.pop(); boolean b = check(vc, vc.impliesExpr(vc.datatypeTestExpr("succ", x), spxeqx)); DebugAssert(b, "Should be valid"); b = check(vc, vc.orExpr(vc.datatypeTestExpr("zero", x), vc.datatypeTestExpr("succ", x))); DebugAssert(b, "Should be valid"); Expr y = vc.varExpr("y", nat); Expr xeqy = vc.eqExpr(x, y); args.clear(); args.add(x); Expr sx = vc.datatypeConsExpr("succ", args); args.clear(); args.add(y); Expr sy = vc.datatypeConsExpr("succ", args); Expr sxeqsy = vc.eqExpr(sx,sy); b = check(vc, vc.impliesExpr(xeqy, sxeqsy)); DebugAssert(b, "Should be valid"); b = check(vc, vc.notExpr(vc.eqExpr(sx, zero))); DebugAssert(b, "Should be valid"); b = check(vc, vc.impliesExpr(sxeqsy, xeqy)); DebugAssert(b, "Should be valid"); b = check(vc, vc.notExpr(vc.eqExpr(sx, x))); DebugAssert(b, "Should be valid"); return true; } catch (Exception e) { System.out.println("*** Exception caught in test18(): \n" + e); e.printStackTrace(System.out); return false; } finally { if (vc != null) vc.delete(); if (flags != null) flags.delete(); } } public static boolean test19() throws Cvc3Exception { ValidityChecker vc = null; FlagsMut flags = null; try { flags = ValidityChecker.createFlags(null); flags.setFlag("dagify-exprs",false); vc = ValidityChecker.create(flags); Type RealType= vc.realType(); Type IntType= vc.intType(); Type BoolType= vc.boolType(); Type PtrType = RealType; Type HeapType = vc.arrayType(PtrType, RealType); // ----------------- //ASSERT(FORALL (CVCi: REAL): (Hs[CVCi] = Ht[CVCi])); //QUERY(Hs[(t6 + (3 * 1))] = Ht[(t6 + (3 * 1))]); Expr Ad = vc.boundVarExpr("CVCi", "CVCi", RealType); Expr Hs = vc.varExpr("Hs", HeapType); Expr Ht = vc.varExpr("Ht", HeapType); Expr t6 = vc.varExpr("t6", RealType); List Vars = new ArrayList(); Vars.add(Ad); // Body = (Hs[Ad] = Ht[Ad]) Expr Body = vc.eqExpr(vc.readExpr(Hs, Ad), vc.readExpr(Ht, Ad)); //A = forall (~i:REAL): Body Expr A = vc.forallExpr(Vars, Body); // Q = (Hs[t6] = Ht[t6]) Expr Q = vc.eqExpr(vc.readExpr(Hs, t6), vc.readExpr(Ht, t6)); // ----------- CHECK A . Q vc.push(); vc.assertFormula(A); System.out.println("Checking formula " + Q); System.out.println(" in context " + A); QueryResult Succ = vc.query(Q); DebugAssert(Succ == QueryResult.VALID, "Expected valid formula"); return true; } catch (Exception e) { System.out.println("*** Exception caught in test19(): \n" + e); e.printStackTrace(System.out); return false; } finally { if (vc != null) vc.delete(); if (flags != null) flags.delete(); } } public static boolean testNonlinearBV() throws Cvc3Exception { ValidityChecker vc = null; FlagsMut flags = null; try { flags = ValidityChecker.createFlags(null); flags.setFlag("dagify-exprs",false); vc = ValidityChecker.create(flags); int bvLength = 8; Rational zero = new Rational(0, vc.embeddedManager()); Expr x = vc.varExpr("x", vc.bitvecType(bvLength)); Expr y = vc.varExpr("y", vc.bitvecType(bvLength)); Expr bv0 = vc.newBVConstExpr(zero, bvLength); // BVUDIV vc.push(); System.out.println("Checking BVUDIV:"); Expr udiv = vc.newBVUDivExpr(x, y); Expr umult = vc.newBVMultExpr(bvLength, udiv, y); Expr test = vc.eqExpr(bv0, y); boolean result = check(vc, vc.impliesExpr(vc.notExpr(test), vc.newBVLEExpr(umult, x)), true); DebugAssert(result, "Expected valid formula"); vc.pop(); // BVUREM vc.push(); System.out.println("Checking BVUREM:"); Expr urem = vc.newBVURemExpr(x, y); result = check(vc, vc.impliesExpr(vc.notExpr(test), vc.newBVLTExpr(urem, y)), true); DebugAssert(result, "Expected valid formula"); vc.pop(); // BVSDIV vc.push(); System.out.println("Checking BVSDIV:"); Expr sdiv = vc.newBVSDivExpr(x, y); Expr smult = vc.newBVMultExpr(bvLength, sdiv, y); Expr signed_test = vc.newBVSLEExpr(bv0, x); signed_test = vc.andExpr(signed_test, vc.newBVSLTExpr(bv0, y)); result = check(vc, vc.impliesExpr(signed_test, vc.newBVSLEExpr(smult, x)), true); DebugAssert(result, "Expected valid formula"); vc.pop(); // BVSREM vc.push(); System.out.println("Checking BVSREM:"); Expr srem = vc.newBVSRemExpr(x, y); result = check(vc, vc.impliesExpr(signed_test, vc.newBVLTExpr(srem, y)), true); DebugAssert(result, "Expected valid formula"); vc.pop(); // BVSMOD vc.push(); System.out.println("Checking BVSMOD:"); Expr smod = vc.newBVSModExpr(x, y); result = check(vc, vc.impliesExpr(signed_test, vc.newBVLTExpr(smod, y)), true); DebugAssert(result, "Expected valid formula"); vc.pop(); return true; } catch (Exception e) { System.out.println("*** Exception caught in test19(): \n" + e); e.printStackTrace(System.out); return false; } finally { if (vc != null) vc.delete(); if (flags != null) flags.delete(); } } public static boolean testDistinct() throws Cvc3Exception { ValidityChecker vc = null; FlagsMut flags = null; try { flags = ValidityChecker.createFlags(null); vc = ValidityChecker.create(flags); int bvLength = 2; int elements_count = bvLength*bvLength + 1; List elements = new ArrayList(); for (int i = 0; i < elements_count; i ++) elements.add(vc.varExpr("x" + i, vc.bitvecType(bvLength))); Expr distinct = vc.distinctExpr(elements); boolean result = check(vc, vc.notExpr(distinct), true); DebugAssert(result, "Expected valid formula"); return true; } catch (Exception e) { System.out.println("*** Exception caught in test19(): \n" + e); e.printStackTrace(System.out); return false; } finally { if (vc != null) vc.delete(); if (flags != null) flags.delete(); } } } cvc3-2.4.1/java/src/cvc3/Context_impl.cpp0000664000175400017540000000000011070741365017767 0ustar mdetersmdeterscvc3-2.4.1/java/src/cvc3/Context.java0000664000175400017540000000040011070741366017112 0ustar mdetersmdeterspackage cvc3; import java.util.*; public class Context extends Embedded { // jni methods /// Constructor public Context(Object Context, EmbeddedManager embeddedManager) { super(Context, embeddedManager); } /// API (immutable) } cvc3-2.4.1/java/src/cvc3/Statistics.java0000664000175400017540000000041411070741364017623 0ustar mdetersmdeterspackage cvc3; import java.util.*; public class Statistics extends Embedded { // jni methods /// Constructor public Statistics(Object Statistics, EmbeddedManager embeddedManager) { super(Statistics, embeddedManager); } /// API (immutable) } cvc3-2.4.1/java/src/cvc3/ExprManagerMut.java0000664000175400017540000000043411070741374020373 0ustar mdetersmdeterspackage cvc3; import java.util.*; public class ExprManagerMut extends ExprManager { // jni methods /// Constructor public ExprManagerMut(Object ExprManagerMut, EmbeddedManager embeddedManager) { super(ExprManagerMut, embeddedManager); } /// API (mutable) } cvc3-2.4.1/java/src/cvc3/TimeoutHandler.java0000664000175400017540000000031511070741367020420 0ustar mdetersmdeterspackage cvc3; import java.util.*; // used to enforce timeout in class Cvc3 class TimeoutHandler extends TimerTask { public void run() { System.out.println("self-timeout."); System.exit(1); } } cvc3-2.4.1/java/src/cvc3/Op.java0000664000175400017540000000265511423121756016057 0ustar mdetersmdeterspackage cvc3; import java.util.*; public class Op extends Embedded { // jni methods private static native boolean jniEquals(Object Expr1, Object Expr2) throws Cvc3Exception; private static native String jniToString(Object Expr) throws Cvc3Exception; private static native Object jniGetExpr(Object op) throws Cvc3Exception; private static native boolean jniIsNull(Object Op) throws Cvc3Exception; /// Constructor public Op(Object Op, EmbeddedManager embeddedManager) { super(Op, embeddedManager); } /// API (immutable) public boolean equals(Object o) { if (this == o) return true; if (!(o instanceof Op)) return false; boolean result = false; try { result = jniEquals(embedded(), ((Embedded)o).embedded()); } catch (Cvc3Exception e) { assert(false); } return result; } // must return the same hash code for two objects if equals returns true public int hashCode() { try { return getExpr().hashCode(); } catch (Cvc3Exception e) { assert(false); } return 0; } public String toString() { String result = ""; try { result = jniToString(embedded()); } catch (Cvc3Exception e) { assert(false); } return result; } public ExprMut getExpr() throws Cvc3Exception { return new ExprMut(jniGetExpr(embedded()), embeddedManager()); } public boolean isNull() throws Cvc3Exception { return jniIsNull(embedded()); } } cvc3-2.4.1/java/src/cvc3/ExprMut.java0000664000175400017540000000044411070741373017100 0ustar mdetersmdeterspackage cvc3; import java.util.*; public class ExprMut extends Expr { // jni methods /// Constructor // create embedded object public ExprMut(Object ExprMut, EmbeddedManager embeddedManager) { super(ExprMut, embeddedManager); } /// API (mutable) } cvc3-2.4.1/java/src/cvc3/JniUtils.cpp0000664000175400017540000001277611276107701017110 0ustar mdetersmdeters#include "JniUtils.h" #include #include #include #include #include #include using namespace std; using namespace CVC3; namespace Java_cvc3_JniUtils { /// Embedding of c++ objects in java objects Embedded* unembed(JNIEnv* env, jobject jobj) { Embedded* embedded = (Embedded*) env->GetDirectBufferAddress(jobj); DebugAssert(embedded != NULL, "JniUtils::unembed: embedded object is NULL"); return embedded; } void deleteEmbedded(JNIEnv* env, jobject jobj) { Embedded* embedded = unembed(env, jobj); DebugAssert(embedded != NULL, "JniUtils::deleteEmbedded: embedded object is NULL"); delete embedded; } /// Conversions between c++ and java bool toCpp(jboolean j) { return (bool)j; } jstring toJava(JNIEnv* env, const string& cstring) { return env->NewStringUTF(cstring.c_str()); } jstring toJava(JNIEnv* env, const char* cstring) { return env->NewStringUTF(cstring); } string toCpp(JNIEnv* env, const jstring& jstring) { const char* cstring = env->GetStringUTFChars(jstring, NULL); string string(cstring); env->ReleaseStringUTFChars(jstring, cstring); return string; } jstring toJava(JNIEnv* env, CVC3::QueryResult result) { switch (result) { case SATISFIABLE: return toJava(env, "SATISFIABLE"); case UNSATISFIABLE: return toJava(env, "UNSATISFIABLE"); case ABORT: return toJava(env, "ABORT"); case UNKNOWN: return toJava(env, "UNKNOWN"); } DebugAssert(false, "JniUtils::toJava(QueryResult): unreachable"); } jstring toJava(JNIEnv* env, CVC3::FormulaValue result) { switch (result) { case TRUE_VAL: return toJava(env, "TRUE_VAL"); case FALSE_VAL: return toJava(env, "FALSE_VAL"); case UNKNOWN_VAL: return toJava(env, "UNKNOWN_VAL"); } DebugAssert(false, "JniUtils::toJava(FormulaValue): unreachable"); } jstring toJava(JNIEnv* env, CVC3::InputLanguage lang) { switch (lang) { case PRESENTATION_LANG: return toJava(env, "PRESENTATION"); case SMTLIB_LANG: return toJava(env, "SMTLIB"); case LISP_LANG: return toJava(env, "LISP"); } DebugAssert(false, "JniUtils::toJava(InputLanguage): unreachable"); } InputLanguage toCppInputLanguage(JNIEnv* env, const string& lang) { if (lang.compare("PRESENTATION") == 0) { return PRESENTATION_LANG; } else if (lang.compare("SMTLIB") == 0) { return SMTLIB_LANG; } else if (lang.compare("LISP") == 0) { return LISP_LANG; } DebugAssert(false, "JniUtils::toCpp(InputLanguage): unreachable"); } void toJava(JNIEnv* env, const Exception& e) { string exceptionName("cvc3/"); if (dynamic_cast(&e) != NULL) { exceptionName += "TypecheckException"; } else if (dynamic_cast(&e) != NULL) { exceptionName += "SoundException"; } else if (dynamic_cast(&e) != NULL) { exceptionName += "EvalException"; } else if (dynamic_cast(&e) != NULL) { exceptionName += "CLException"; } else if (dynamic_cast(&e) != NULL) { exceptionName += "ParserException"; } else if (dynamic_cast(&e) != NULL) { exceptionName += "SmtlibException"; } else if (dynamic_cast(&e) != NULL) { exceptionName += "DebugException"; } else { exceptionName += "Cvc3Exception"; } jclass exceptionClass = env->FindClass(exceptionName.c_str()); DebugAssert(exceptionClass != NULL, string("JniUtils::toJava(Exception): unknown class") + exceptionName); // queues up the exception in the Java layer env->ThrowNew(exceptionClass, e.toString().c_str()); } vector toCppV(JNIEnv* env, const jobjectArray& jarray) { vector v; int length = env->GetArrayLength(jarray); for (int i = 0; i < length; ++i) { v.push_back(toCpp(env, (jstring)env->GetObjectArrayElement(jarray, i))); } return v; } vector > toCppVV(JNIEnv* env, const jobjectArray& jarray) { vector > v; int length = env->GetArrayLength(jarray); for (int i = 0; i < length; ++i) { jobjectArray jsub = static_cast(env->GetObjectArrayElement(jarray, i)); v.push_back(toCppV(env, jsub)); } return v; } vector > > toCppVVV(JNIEnv* env, const jobjectArray& jarray) { vector > > v; int length = env->GetArrayLength(jarray); for (int i = 0; i < length; ++i) { jobjectArray jsub = static_cast(env->GetObjectArrayElement(jarray, i)); v.push_back(toCppVV(env, jsub)); } return v; } jobjectArray toJavaV(JNIEnv* env, const vector& v) { jobjectArray jarray = (jobjectArray) env->NewObjectArray( v.size(), env->FindClass("java/lang/String"), env->NewStringUTF("")); for(int i = 0; i < v.size(); ++i) { env->SetObjectArrayElement(jarray, i, toJava(env, v[i])); } return jarray; } vector toCppV(JNIEnv* env, const jbooleanArray& jarray) { int length = env->GetArrayLength(jarray); jboolean* jboolean = env->GetBooleanArrayElements(jarray, NULL); vector v; for (int i = 0; i < length; ++i) { v.push_back(jboolean[i]); } env->ReleaseBooleanArrayElements(jarray, jboolean, JNI_ABORT); return v; } } cvc3-2.4.1/java/src/cvc3/Proof_impl.cpp0000664000175400017540000000000011070741372017426 0ustar mdetersmdeterscvc3-2.4.1/java/src/cvc3/CLException.java0000664000175400017540000000035011070741365017646 0ustar mdetersmdeterspackage cvc3; import java.util.*; /** mirrors CVC3::CLException */ class CLException extends Cvc3Exception { private final static long serialVersionUID = 1L; public CLException(String message) { super(message); } } cvc3-2.4.1/java/src/cvc3/FormulaValue.java0000664000175400017540000000175611070741373020105 0ustar mdetersmdeterspackage cvc3; import java.util.*; /** A truth value of a formula. */ public class FormulaValue { private final String d_result; protected FormulaValue(String result) { d_result = result; } // names of c++ enum values public static final FormulaValue TRUE = new FormulaValue("TRUE_VAL"); public static final FormulaValue FALSE = new FormulaValue("FALSE_VAL"); public static final FormulaValue UNKNOWN = new FormulaValue("UNKNOWN_VAL"); // the FormulaValue corresponding to a c++ enum value by name public static FormulaValue get(String value) throws DebugException { if (value.equals(TRUE.toString())) { return TRUE; } else if (value.equals(FALSE.toString())) { return FALSE; } else if (value.equals(UNKNOWN.toString())) { return UNKNOWN; } else { throw new DebugException("FormulaValue.constructor: unknown enum value: " + value); } } // the FormulaValue's c++ enum value public String toString() { return d_result; } } cvc3-2.4.1/java/src/cvc3/JniUtils.java0000664000175400017540000001413611272411146017234 0ustar mdetersmdeterspackage cvc3; import java.util.*; import java.lang.reflect.Constructor; public class JniUtils { // check that list is an instance of a class - // generics would avoid that public static boolean listInstanceof(List list, Class c) { Iterator i = list.iterator(); while (i.hasNext()) { if (!(c.isInstance(i.next()))) return false; } return true; } public static boolean listListInstanceof(List listList, Class c) { Iterator i = listList.iterator(); while (i.hasNext()) { Object list = i.next(); assert(list instanceof List); if (!(listInstanceof((List)list, c))) return false; } return true; } public static boolean listListListInstanceof(List listListList, Class c) { Iterator i = listListList.iterator(); while (i.hasNext()) { Object list = i.next(); assert(list instanceof List); if (!(listListInstanceof((List)list, c))) return false; } return true; } // embed an array of c++ objects in a list public static List embedList(Object[] cobjects, Class c, EmbeddedManager embeddedManager) { List embedded = new ArrayList(); try { Class[] argsC = new Class[2]; argsC[0] = Object.class; argsC[1] = EmbeddedManager.class; Constructor constr = c.getConstructor(argsC); Object[] args = new Object[2]; for (int i = 0; i < cobjects.length; ++i) { args[0] = cobjects[i]; args[1] = embeddedManager; embedded.add(constr.newInstance(args)); } } catch (NoSuchMethodException e) { System.out.println(e); assert(false); } catch (InstantiationException e) { System.out.println(e); assert(false); } catch (IllegalAccessException e) { System.out.println(e); assert(false); } catch (java.lang.reflect.InvocationTargetException e) { System.out.println(e); assert(false); } return embedded; } public static List embedListList(Object[][] cobjects, Class c, EmbeddedManager embeddedManager) { List embedded = new ArrayList(cobjects.length); for (int i = 0; i < cobjects.length; ++i) { Object[] cobject = cobjects[i]; embedded.add( embedList(cobject,c,embeddedManager) ); } return embedded; } // embed an array of c++ objects in a hash map public static HashMap embedHashMap(Object[] cobjects, Class ck, Class cv, EmbeddedManager embeddedManager) { HashMap embedded = new HashMap(cobjects.length / 2); try { Class[] argsCK = new Class[2]; argsCK[0] = Object.class; argsCK[1] = EmbeddedManager.class; Constructor constrK = ck.getConstructor(argsCK); Class[] argsCV = new Class[2]; argsCV[0] = Object.class; argsCV[1] = EmbeddedManager.class; Constructor constrV = cv.getConstructor(argsCV); Object[] argsK = new Object[2]; Object[] argsV = new Object[2]; for (int i = 0; i < cobjects.length; ++i) { argsK[0] = cobjects[i]; argsK[1] = embeddedManager; ++i; assert(i < cobjects.length); argsV[0] = cobjects[i]; argsV[1] = embeddedManager; embedded.put(constrK.newInstance(argsK), constrV.newInstance(argsV)); } } catch (NoSuchMethodException e) { System.out.println(e); assert(false); } catch (InstantiationException e) { System.out.println(e); assert(false); } catch (IllegalAccessException e) { System.out.println(e); assert(false); } catch (java.lang.reflect.InvocationTargetException e) { System.out.println(e); assert(false); } return embedded; } // unembed a list of Embedded objects to a list public static Object[] unembedList(List embedded) { Object[] unembedded = new Object[embedded.size()]; for (int i = 0; i < embedded.size(); ++i) { assert(embedded.get(i) instanceof Embedded); unembedded[i] = ((Embedded)embedded.get(i)).embedded(); } return unembedded; } public static Object[][] unembedListList(List embedded) { Object[][] unembedded = new Object[embedded.size()][]; for (int i = 0; i < embedded.size(); ++i) { Object list = embedded.get(i); assert(list instanceof List); unembedded[i] = unembedList((List)list); } return unembedded; } public static Object[][][] unembedListListList(List embedded) { Object[][][] unembedded = new Object[embedded.size()][][]; for (int i = 0; i < embedded.size(); ++i) { Object list = embedded.get(i); assert(list instanceof List); unembedded[i] = unembedListList((List)list); } return unembedded; } // unembed a list of Embedded objects to a list public static Object[] unembedArray(Object[] embedded) { Object[] unembedded = new Object[embedded.length]; for (int i = 0; i < embedded.length; ++i) { assert(embedded[i] instanceof Embedded); unembedded[i] = ((Embedded)embedded[i]).embedded(); } return unembedded; } public static Object[] unembedArrayArray(Object[][] embedded) { Object[] unembedded = new Object[embedded.length]; for (int i = 0; i < embedded.length; ++i) { unembedded[i] = unembedArray(embedded[i]); } return unembedded; } public static Object[] unembedArrayArrayArray(Object[][][] embedded) { Object[] unembedded = new Object[embedded.length]; for (int i = 0; i < embedded.length; ++i) { unembedded[i] = unembedArrayArray(embedded[i]); } return unembedded; } // copy a list of strings to a list public static Object[] toArray(List list) { assert(listInstanceof(list, String.class)); assert(list.isEmpty() || !listInstanceof(list, Embedded.class)); return list.toArray(); } public static Object[] toArrayArray(List listList) { Object[] arrayArray = new Object[listList.size()]; for (int i = 0; i < listList.size(); ++i) { Object list = listList.get(i); assert(list instanceof List); arrayArray[i] = toArray(((List)list)); } return arrayArray; } public static Object[] toArrayArrayArray(List listListList) { Object[] arrayArrayArray = new Object[listListList.size()]; for (int i = 0; i < listListList.size(); ++i) { Object list = listListList.get(i); assert(list instanceof List); arrayArrayArray[i] = toArrayArray((List)list); } return arrayArrayArray; } } cvc3-2.4.1/java/src/cvc3/TheoremMut_impl.cpp0000664000175400017540000000000011070741367020436 0ustar mdetersmdeterscvc3-2.4.1/java/src/cvc3/Theorem_impl.cpp0000664000175400017540000000000011070741373017745 0ustar mdetersmdeterscvc3-2.4.1/java/src/cvc3/Flag_impl.cpp0000664000175400017540000000156511070741375017236 0ustar mdetersmdetersDEFINITION: Java_cvc3_Flag_jniIsNull jboolean c CLFlag flag return (flag->getType() == CLFLAG_NULL); DEFINITION: Java_cvc3_Flag_jniIsBool jboolean c CLFlag flag return (flag->getType() == CLFLAG_BOOL); DEFINITION: Java_cvc3_Flag_jniIsInt jboolean c CLFlag flag return (flag->getType() == CLFLAG_INT); DEFINITION: Java_cvc3_Flag_jniIsString jboolean c CLFlag flag return (flag->getType() == CLFLAG_STRING); DEFINITION: Java_cvc3_Flag_jniIsStringVec jboolean c CLFlag flag return (flag->getType() == CLFLAG_STRVEC); DEFINITION: Java_cvc3_Flag_jniGetBool jboolean c CLFlag flag return flag->getBool(); DEFINITION: Java_cvc3_Flag_jniGetInt jint c CLFlag flag return flag->getInt(); DEFINITION: Java_cvc3_Flag_jniGetString jstring c CLFlag flag return toJava(env, flag->getString()); DEFINITION: Java_cvc3_Flag_jniGetHelp jstring c CLFlag flag return toJava(env, flag->getHelp()); cvc3-2.4.1/java/src/cvc3/Statistics_impl.cpp0000664000175400017540000000000011070741365020475 0ustar mdetersmdeterscvc3-2.4.1/java/src/cvc3/TypeMut.java0000664000175400017540000000044411070741370017100 0ustar mdetersmdeterspackage cvc3; import java.util.*; public class TypeMut extends Type { // jni methods /// Constructor // create embedded object public TypeMut(Object TypeMut, EmbeddedManager embeddedManager) { super(TypeMut, embeddedManager); } /// API (mutable) } cvc3-2.4.1/java/src/cvc3/SatResult.java0000664000175400017540000000275211133225371017421 0ustar mdetersmdeterspackage cvc3; import java.util.*; /** * SatResult is derived from the QueryResult enum in Cvc3, but as we have to * use java 1.4 we have to use one of the usual tricks instead of java's Enum. * * To be independent of changes of the actual values of the c++ enum elements * they are passed by name from the JNI interface, so that changing them will * violently break the code (though unfortunately only at runtime). */ public class SatResult { private final String d_result; private SatResult(String result) { d_result = result; } // names of c++ enum values public static final SatResult SATISFIABLE = new SatResult("SATISFIABLE"); public static final SatResult UNSATISFIABLE = new SatResult("UNSATISFIABLE"); public static final SatResult ABORT = new SatResult("ABORT"); public static final SatResult UNKNOWN = new SatResult("UNKNOWN"); // the SatResult corresponding to a c++ enum value by name public static SatResult get(String value) throws DebugException { if (value.equals(SATISFIABLE.toString())) { return SATISFIABLE; } else if (value.equals(UNSATISFIABLE.toString())) { return UNSATISFIABLE; } else if (value.equals(ABORT.toString())) { return ABORT; } else if (value.equals(UNKNOWN.toString())) { return UNKNOWN; } else { throw new DebugException("SatResult.constructor: unknown enum value: " + value); } } // the SatResult's c++ enum value public String toString() { return d_result; } } cvc3-2.4.1/java/src/cvc3/Flags_impl.cpp0000664000175400017540000000053611070741371017412 0ustar mdetersmdetersDEFINITION: Java_cvc3_Flags_jniGetFlags jobjectArray c CLFlags flags n string prefix // get flag names vector names; flags->countFlags(prefix, names); return toJavaV(env, names); DEFINITION: Java_cvc3_Flags_jniGetFlag jobject c CLFlags flags n string name const CLFlag& flag = flags->getFlag(name); return embed_const_ref(env, &flag); cvc3-2.4.1/java/src/cvc3/StatisticsMut.java0000664000175400017540000000050211070741366020311 0ustar mdetersmdeterspackage cvc3; import java.util.*; public class StatisticsMut extends Statistics { // jni methods /// Constructor // create embedded object public StatisticsMut(Object StatisticsMut, EmbeddedManager embeddedManager) { super(StatisticsMut, embeddedManager); } /// API (mutable) } cvc3-2.4.1/java/src/cvc3/SmtlibException.java0000664000175400017540000000037311070741367020611 0ustar mdetersmdeterspackage cvc3; import java.util.*; /** mirrors CVC3::SmtlibException */ public class SmtlibException extends Cvc3Exception { private final static long serialVersionUID = 1L; public SmtlibException(String message) { super(message); } } cvc3-2.4.1/java/src/cvc3/TypeMut_impl.cpp0000664000175400017540000000000011070741364017751 0ustar mdetersmdeterscvc3-2.4.1/java/src/cvc3/DebugException.java0000664000175400017540000000037011070741366020401 0ustar mdetersmdeterspackage cvc3; import java.util.*; /** mirrors CVC3::DebugException */ public class DebugException extends Cvc3Exception { private final static long serialVersionUID = 1L; public DebugException(String message) { super(message); } } cvc3-2.4.1/java/README0000664000175400017540000005525411422402741014067 0ustar mdetersmdetersJava Interface for CVC3 ----------------------- This document describes the Java wrapper for the CVC3 library. Table of contents: 1 Outline 2 Files 3 Installation 3.1 Required Software 3.2 Building the interface 3.3 Binaries 3.4 Installation 3.5 Execution 3.6 Testing 4 Architecture 4.1 Embedding a C++ Class: the Mapping Layer 4.2 Embedding a C++ Class: in a Java Class 4.3 Garbage Collection 4.4 Constant vs. Mutable 4.5 Data Conversions 4.6 Native Methods 5 Status 5.1 ToDo 5.2 Testing 5.3 Problems 6 Frequenty Asked Questions 6.1 Why does my application segfault when calling into CVC3 library? 7 Reporting Bugs 1 Outline --------- As CVC is written in C++, JNI is used to access it from Java. see: http://java.sun.com/developer/onlineTraining/Programming/JDCBook/jni.html This consists of: - writing a Java wrapper class for each exported C++ class, which declares each method exported from CVC3 as native - implementing each declared native function in c, which consists of calling the actual CVC3 function and taking care of data conversion and destruction. (let's call this the mapping layer) 2 Files ------- The whole source has been added as a new top level directory 'java' in CVC3. The main directory contains: - README - Makefile, create_impl.py: create the binaries - Cvc3_manifest, Test_manifest: manifest files for Java libraries - run_tests.py, run_all.py: test scripts All source files are located in src/cvc3, all header files in include/cvc3, all compiled binaries in obj/cvc3, and all libraries in lib. The cvc3 prefix is due to the Java files being in the name space Cvc3, which must be mimicked in the directory structure. For each exported CVC class A there exist the source files: - src/A.java, mirroring A's interface in Java - src/A.cpp, using CVC's A to implement the native functions used in A.java Derived files are: - include/A.h, an automatically generated header file corresponding to the native functions declared in A.java - the compiled classes and functions obj/A.class, obj/A.o Additional source files are: - src/JniUtils.java, src/JniUtils.h, src/JniUtils.cpp: taking care of common conversion operations between Java and cpp - src/Embedded.java, src/EmbeddedManager.java: taking care of garbage collection of C++ objects - src/Cvc3.java: a command line tool built on top of the wrapper - src/Test.java: mirroring CVC's C++ interface tests built on top of the wrapper 3 Installation -------------- 3.1 Required Software --------------------- This is Linux only, in addition to CVC3's usual requirements a JDK 1.4.2 or higher is needed. Because the interface is developed for integration into EscJava, and EscJava needs to run on a Java 1.4 vm, the source is restricted to Java 1.4 features as well (i.e. no generics, no enums, ...). 3.2 Building the interface ------------------ The interface can be build alongside CVC3 using the --enable-java configuration option. The configuration script refers to the environment variables JAVAC, JAVAH, JAR, and CXX to set up the standard Java and C++ compiler commands. It refers to the environment variable JFLAGS for default Java compiler flags. It refers to the variable javadir for the installation directory of the CVC3 Java library. The configuration options --with-java-home and --with-java-includes can be used to specify the path to the directories containing the JDK installation and JNI header files, respectively. You must build CVC3 as a dynamic library to use the Java interface. For example, you might configure the build by running the following in the top-level CVC3 directory: ./configure --enable-dynamic --enable-java Detailed instructions are in ../INSTALL. NOTE: The Java interface depends on the "build type" (e.g., "optimized", "debug) of CVC3. If you choose to re-configure and re-build CVC3 with a different build type, you must run "make clean" in the current directory and re-build the interface (cleaning and rebuilding the entire CVC3 package will suffice). 3.3 Binaries ------------ The compiled binaries are put in lib/ : Two dynamic libraries: - libcvc3jni.so: the wrapper library containing the implementations of native functions - libcvc3-X.Y.Z.jar (where "X.Y.Z" is the version of CVC3): the Java library containing the Java wrapper classes Two Java programs: - cvc3.jar: a Java program mirroring the CVC3 command line version - cvc3test.jar: a Java program mirroring the CVC3 C++ interface tests 3.4 Installation ---------------- "make install" copies libcvc3jni.so into the same directory as libcvc3.so (by default, /usr/local/lib) and the Java library into the directory specified by javadir (by default, /usr/local/java). 3.5 Execution ------------- To access the library, you must add the file libcvc3-X.Y.Z.jar (where "X.Y.Z" is the CVC3 version) to the classpath (e.g., by setting the CLASSPATH environment variable) and both libcvc3.so and libcvc3jni.so to the runtime library path (e.g., by setting the LD_LIBRARY_PATH environment variable and the java.library.path JVM system variable). For example, to compile the class Client.java: javac -cp lib/libcvc3.jar Client.java To run: export LD_LIBRARY_PATH=/path/to/cvc3/libs java -Djava.library.path=/path/to/cvc3/libs -cp lib/libcvc3.jar Client Note that libcvc3.so and libcvc3jni.so may be installed into different directories, so that LD_LIBRARY_PATH may need to include multiple paths. For example, export LD_LIBRARY_PATH=/usr/local/lib:/usr/local/java/lib The cvc3.jar can be used the same way as the cvc3 command line tool, but instead of cvc3 file the command (from the java directory) is java -jar lib/cvc3.jar file To enable debug assertions add the option -ea, to avoid stack overflows it might be necessary to increase the stack limit: -Xss10M (see 5.3 Problems), which gives: java -ea -Xss10M -jar lib/cvc3.jar file Running cvc3.jar will cause loading of the dynamic libraries: 1. libcvc3-X.Y.Z.jar, as CVC3 uses the Java wrapper classes 2. libcvc3jni.so, as it implements the native functions declared in libcvc3-X.Y.Z.jar 3. libcvc3.so, as it is used by libcvc3jni.so 3.6 Testing ----------- The tests in CVC3's test project can be run (except for the george tests) with make test The regression tests with: make regress Smtlib tests with: ./run_tests.py -vc 'java -ea -Xss100M -jar lib/cvc3.jar' -t 5 -m 500 -l 5 -lang smtlib Or (after editing the paths and options in run_all.py) with: ./run_all.py 4 Architecture -------------- 4.1 Embedding a C++ Class: the Mapping Layer -------------------------------------------- A CVC object needs to be accessed/wrapped by a Java object. Thus, it must be mapped somehow to Java's type system. One way to do this would be to use integers representing objects. Then in the mapping layer an object C would be mapped to its integer id i, which would be stored in its Java wrapper object J. When a method of C needs to be accessed, J passes i back to the mapping layer, which retrieves C and calls the requested method. One problem with this approach is the need for mapping data structures. If these are global they need to be thread safe in case several ValidityCheckers are active at the same time. If they are local, they must be stored in J as well, and given as an additional argument to the wrapper layer. The mapping itself is an unsafe type cast from int to an arbitrary class, which might lead to subtle bugs if the interface changes (e.g. from mutable to immutable for some returned value, see 4.4 Constant vs. Mutable). Because of this an object is exported as a pointer to the Java level. This is possible using a DirectByteBuffer, which can store a real pointer, not a long or int which would introduce a dependency on the architecture. Now no mapping data structures are needed. In reality an object C is embedded in another object of class Embedded, which additionally stores C's type_info and a specialized delete function. (see include/cvc3/JniUtils.h). The type_info is used only for debugging purposes, to make sure that when extracting C it is casted to the correct type. The delete function is specialized for C's type as well. When the wrapping is only by reference, i.e. the object is still owned by CVC and not by the Java wrapper, then the delete operation will do nothing. Combined this allows all Java wrapper classes to call the same delete function on their embedded a C++ object, as it is actually of type Embedded, and Embedded knows how to delete the real wrapped C++ object. 4.2 Embedding a C++ Class: in a Java Class ------------------------------------------ Wrapping a CVC object C in a Java object J is done using the following scheme, where the abstract Java class Embedded is used as the base class for all wrapper objects: - Embedded contains C as an Object (kind of like void*), which is actually the Embedded C++ class described in 4.1. - J subclasses Embedded - J's constructor takes C as an argument (of type Object) - A call to a method of C is mirrored as a method of J, which calls a native function taking C as its argument. Example: a wrapper for the CVC class Type exporting the method isBool Embedded.java: public abstract class Embedded { // embedded C++ object private Object d_embedded; // access to embedded C++ object public synchronized Object embedded() { return d_embedded; } } Type.java: public class Type extends Embedded { // jni methods private static native boolean jniIsBool(Object Type); /// Constructor public Type(Object Type) { super(Type); } /// API boolean isBoolean() { return jniIsBool(embedded()); } } Type.cpp: implements jniIsBool to call isBool on the given Type object The benefit of subclassing Embedded is: - there is exactly one class which deals with pointers - it deals with garbage collection as well, by storing an EmbeddedManager and providing an appropriate finalizer (see 4.3 Garbage Collection) 4.3 Garbage Collection ---------------------- As a CVC object C is wrapped in a Java object J, - C must exist while J is used - C must be destructed at some point after J is not used anymore. In the simplest cases this can be achieved by: a) Require the user to explicitly call some destructor function on J which will destruct C. This is inconvenient and error prone from the user's point of view. b) Never destruct C objects. This is fine for a one time use of CVC, e.g. in the command line tool, but not in an incremental setting (EscJava) c) Do nothing except for explicitly destructing the ValidityChecker. This will automatically destruct all expressions and theorems constructed using this ValidityChecker (or: its expression and theorem manager), but not other object as e.g. proofs. These still have to be destructed explicitly as in a), and the comment in b) still applies. d) try to use Java's garbage collector to improve on a) or c). I tried to go with d), because of the problems listed in a) and b). That is, when J is garbage collected its finalizer does something to trigger the destruction of C. Now, the problem is that Java's finalizer runs in its own thread, parallel to the main thread, while CVC is not thread safe. (There are actually six threads when running cvc.jar). Thus, race conditions might be introduced by the code executed in destructors, and in fact one for sure exists: the reference counting done by CVC to implement its internal memory management of expressions (triggered during testing). (Another potential problem is memory allocation: using the malloc memory manager should be fine, as malloc/free are supposed to be thread safe, but what about the chunk memory manager? I don't think there is a problem and haven't observed one, but I am not sure if it's really safe.) Therefore access to CVC has to be serialized, i.e. the destruction of C requested in the finalization of J has to be executed in the main thread as far as CVC is concerned. To achieve this, there exists the class EmbeddedManager, which servers as this synchronization point. The constructor of Embedded (of which J is a subclass) takes an EmbeddedManager as an argument, and whenever it is is finalized, it registers the reference to C with its EmbeddedManager. The EmbeddedManager can be asked to destruct all registered objects at any time - but by convention from the main thread only. This is supposed to be done either explicitly by the user (at any convenient times), or implicitly when the ValidityChecker is destructed (which works only for expressions and theorems). Thus a typical usage pattern would be: ValidityChecker vc = null; try { vc = ValidityChecker.create(); ... vc.assertFormula(...); ... vc.push() Expr x = ... Expr y = ... vc.query(vc.impliesExpr(x, y)); vc.pop() ... } finally { if (vc != null) vc.delete(); } All intermediate expressions are garbage collected when not needed anymore, and only the ValidityChecker is garbage collected explicitly using vc.delete(). As Embedded implements delete(), it can be called on each wrapper class including Expr do mark it for destruction. To actually destruct the wrapped C object the EmbeddedManager must be told so (e.g. after vc.pop() ): vc.embeddedManager().cleanUp(); Note: Having Embedded and thus all wrapper classes implement a finalizer is potentially expensive, but that's the best solution I found. 4.4 Constant vs. Mutable ------------------------ const C++ objects are immutable, but this has no counterpart in Java. To mirror this effect, each CVC class C is represented by two Java classes, J and JMut: - J implements the immutable interface of C, i.e. the const methods - JMut subclasses J and adds the non-const methods of C Thus when a CVC method returns a const object C, then the Java method returns the corresponding object J, but if plain C is returned then Java returns JMut. Note: Except for ValidityChecker I defined J and JMut for each wrapped class, even if it might only be intended for constant use. 4.5 Data Conversions -------------------- 'Native' types (int, boolean, string) are converted between C++ and Java in the standard way. Wrapped classes are handled as described in the previous sections. Collection types are mapped in an expensive way, by using the native types on the C++ (vector, hash_map) and the Java (List, HashMap) side, and Arrays in between, as those can be used most easily in JNI. Note: There might be more efficient ways using more sophisticated method calls building up C++ collections from the Java side and vice versa, but for lack of time and preference of simplicity I did not look into that. C++ enums have no real counterpart in Java 1.4, so a standard way of simulating them was used (see e.g. QueryResult.java). For each enum value the Java wrapper has a final static instance, whose name is the name of the value as a string. This mapping of enums to strings serves to make sure that there is no dependency on the integers chosen to represent the enums, as well as to guard against changes of the enum: new unknown values will be caught at runtime and trigger an assertion failure. CVC uses exceptions, but C++ exceptions are not compatible with Java exceptions. Therefore each native function is guarded by a try .. catch, and in case an exception is thrown it is mapped to a Java exception which is thrown instead. All mapping functions are defined in the JniUtils files: src/cvc3/JniUtils.java, src/cvc3/JniUtils.cpp, include/cvc3/JniUtils.h 4.6 Native Methods ------------------ For each exported method M of a CVC class C wrapped by the Java class J there must be: - the declaration of native method jniM in J - the implementation of jniM in the mapping layer, which results in calling M The jni compiler will create a header file for all native methods declared in J, but it is up to us to implement them in the mapping layer. This can be problematic, as g++ does - neither check that all functions declared in a header file are actually defined anywhere - nor if for some defined function there exists a declaration in a header file But to avoid code decay a tight 1:1 coupling is convenient here, esp. as the header files are generated automatically. Note: Esp. as at least with some compilers there seems to be some strange behavior when there are several native functions with the same name but different signatures on the Java side. This is resolved by name mangling in the header file, but apparently confusion can arise if there exists an implementation using the unmangled name. Then the linker might use it instead of any of the mangled names. This occurred as methods are exported as needed, one by one, leading to exactly this situation where the header and its implementation were out of synch. To avoid this the script create_impl.py is used, which checks a header file against an implementation file, to ensure that there is a 1:1 mapping between declarations and definitions. Furthermore, a lot of the code of the mapping layer is basically the same for each function. It consists of a signature, some extractions and wrappings of embedded objects, and some exception handling code. To avoid this repetitive work and ease changes of common functions, the implementation C.cpp of the native functions declared in J.java are generated using create_impl.py, from a concise description of its signature plus the actual function body from C_impl.cpp. The specification of a function consists of two lines plus the body, e.g.: DEFINITION: Java_cvc3_ValidityChecker_jniRecordExpr4 jobject m ValidityChecker vc nv string fields cv Expr exprs return embed_copy(env, vc->recordExpr(fields, exprs)); Line 1 states that the definition of the function Java_cvc3_ValidityChecker_jniRecordExpr4 follows. Line 2 states that its signature is: - returns a jobject - the 1. argument is a mutable ValidityChecker instance called vc: ValidityChecker vc - the 2. argument is a string array called fields: String[] fields - the 3. argument is an immutable Expr array called exprs: const Expr[] fields Line 3 (and follows) contain the actual function body In general each argument is a triple consisting of: 1. n: for a native type (int, boolean, String, ...) m: for a mutable embedded type c: for an immutable embedded type In addition the suffix v declares it to be an array of the above (vv and vvv are also possible) 2. Type: the CVC type 3. Name: any string The actual code generated for the above specification is: extern "C" JNIEXPORT jobject JNICALL Java_cvc3_ValidityChecker_jniRecordExpr4 (JNIEnv* env, jclass, jobject jvc, jobjectArray jfields, jobjectArray jexprs) { try { ValidityChecker* vc = unembed_mut(env, jvc); vector fields(toCppV(env, jfields)); vector exprs(toCppV(env, jexprs)); return embed_copy(env, vc->recordExpr(fields, exprs)); } catch (const Exception& e) { toJava(env, e); }; } unembed, embed, and toJava are mapping functions (see 4.5. Data Conversions) 5 Status -------- 5.1 ToDo -------- The Makefile does its job reasonably well, but it: - should be able to automatically figure out some variables - should be smarter about what to redo after changes - should be possible to switch between debug and optimized builds without a clean all - the different projects should be separated more cleanly Only classes and methods needed for the cvc3.jar and cvc3test.jar are currently exported, many methods which are probably going to be needed in applications are missing. Sometimes assert is used in the mapping layer. This should be replaced by DebugAssert, so that the exception is forwarded to the Java wrapper instead of crashing the whole program. 5.2 Testing ----------- Pentium M, Ubuntu 7.10, g++ 4.1.3, jdk 1.6.0_03: Passes cvc3test.jar and CVC3's benchmarks with 5s timeout in optimized + debug Pentium(R) 4 hyperthreaded, RHEL WS 4, g++ 3.4.6 20060404, jdk 1.5.0_06 1.6.0_03 Passes cvc3test.jar and CVC3's benchmarks with 5s timeout in optimized + debug Passes smtlib in debug with 1s timeout XEON 4, RHEL WS 3, g++ 4.2.2, 1.4.2_12 1.6.0_03 Passes cvc3test.jar and CVC3's benchmarks with 5s timeout in optimized + debug Passes smtlib in optimized with 1s timeout At least I think they pass, I think all the remaining crashes are due to the timeout problem described in 5.3 Problems. 5.3 Problems ------------ A timeout in cvc3.jar can trigger a segfault (this wasn't counted as a fault in 5.2 Testing). This seems to happen from time to time in debug mode, rarer in optimized. My guess is that it is due to calling System.exit in a thread different from the main thread. For some reason the stack size is a problem, it sometimes needs to be a lot higher in the Java integration than it needs to be for the pure C++ program (I had the same problem with the C# port). It can be changed by using Java with the option -Xss10M (e.g. needed for QF_IDL/mathsat/post_office/PO2-8-PO2.smt) Sometimes even 100M might be needed - something must go seriously wrong here. The option -XX:StackShadowPages is also supposed to help, but it didn't in my tests. see: http://java.sun.com/javase/6/webnotes/trouble/TSG-VM/html/gbyzx.html Debugging can be tricky, as one needs a debugger for the Java bytecode, and another debugger for the C++ object code. I tried only jswat on the Java side, and the only debugger that worked for me on the C++ side was zero (i.e. does not crash, break points and stepping works). The steps to take are: 0. To make the program stop, enable the wait-for-keypress code in Embedded.java 1. Start the jvm, make it listen for a debugger, and suspend it: java -Xmx400m -Xms400m -Xdebug -Xnoagent -Djava.compiler=none \ -Xrunjdwp:transport=dt_socket,server=y,suspend=y \ -jar ... lib/cvc3.jar ... 2. Attach jswat to it, set a break point, continue 3. Now it hits the stop point activated in 0; attach zero, set break point, continue Even when not caring about the Java part, just running zero on the Java program didn't work, steps 0, 1, and 3 were still necessary. see: http://www.ibm.com/developerworks/java/library/j-jnidebug/index.html http://www.kineteksystems.com/white-papers/mixedjavaandc.html 6 Frequently Asked Questions ---------------------------- 6.1 Why does my application segfault when calling into CVC3 library? -------------------------------------------------------------------- Make sure that the version of libcvc3.so found at runtime has the same "build type" as the Java interface. There are binary incompatabilities between "debug" and "optimized" versions of the CVC3 library. The Java interface picks up the build type from ../Makefile.local. If CVC3 is re-configured with a new build type, the interface must be re-compiled (i.e., run "make clean" then "make" in the current directory). If the build types match, then the segfault is probably a bug. 7 Reporting Bugs ---------------- Please report bugs via Bugzilla: http://cs.nyu.edu/acsys/bugs/ cvc3-2.4.1/java/run_tests.py0000664000175400017540000007467011070741375015622 0ustar mdetersmdeters#!/usr/bin/env python import sys, os, re, math, time #, signal #import resource # Alexander Fuchs # update of run_test: # - works also under windows # - measures cpu time, not wall clock time, per test case # - works also for smtlib directories # BROKEN: # doesn't work as intended, due to problems on windows. # so time measurement is actually not as accurate as hoped for. # documentation taken from run_tests.py: # Run regression tests of a given level (default: 0, meaning # minimum amount of tests). The higher the regression level, the more # tests to run, and the harder they get. # Each test may contain information about its regression level, # expected outcome, expected runtime, whether it produces a proof, # etc. in the format given below. This script will scan the first 100 # lines of each test and try to collect this information. # If some info is not found, defaults are assumed. Default regression # level is 0, expected runtime is unbounded, outcome is undefined # (whatever it returns is OK), proof should be produced if outcome is # Valid, and if it is produced, it'll be verified. # Test info is given in the comments; here are examples # # %%% Regression level = 2 # %%% Result = Valid %% or Invalid, or Unknown # %%% Runtime = 10 %% in seconds # %%% Proof = yes %% or 'no', if it doesn't produce a proof # %%% Language = presentation %% or 'internal' # The number of '%' and following spaces can vary, case is not # important. Any text after the value is ignored. Any comments that # are not recognized are also ignored. ### Constants # :TODO: @TOP@ with configure, WIN # general setup #TEST_PATH = "/home/alexander/d/CVC/REPOSITORY/cvc3_fix/cvc3/testcases" #RUN_PATH = "/home/alexander/d/CVC/REPOSITORY/FRESH/cvc3/bin" #os.environ["PATH"] = RUN_PATH + ":" + os.environ["PATH"] # max. number of lines to read from the testcase file # when looking for info comments MAX_INFO_LINES = 100 # for printing, the width of the label column WIDTH = 24 PRINT_SUMMARY = 1 # valid problem file extensions FILE_EXTENSIONS = ["cvc", "cvc3", "svc", "smt", "lisp", "lsp"] # command line options OPT_VERBOSE = "v" OPT_QUIET = "q" OPT_LEVEL = "l" OPT_TIMEOUT = "t" OPT_MEMOUT = "m" OPT_CHECK_TIMEOUT = "rt" OPT_LANG = "lang" OPT_VC = "vc" # test case options PRO_LEVEL = "l" PRO_LANG = "lang" PRO_TIMEOUT = "t" PRO_RESULT = "result" #alarm_pipe = None #alarm_raised = False #def alarmHandler(signum, frame): # raise 'Timeout' #alarm_pipe.close() #alarm_raise = True #signal.signal(signal.SIGALRM, alarmHandler) # while 1: # try: # signal.alarm(5) # t = sys.stdin.readline() # signal.alarm(0) # print t # except 'Timeout': # print "too slow" ### helper functions #def find def forall (pred, seq): return reduce(lambda acc, x: acc and pred(x), seq, True) def exists (pred, seq): return reduce(lambda acc, x: acc or pred(x), seq, False) def find (pred, seq): for x in seq: if pred(x): return x ### time def cut_time (time): return math.floor ((time * 10) + 0.5) / 10 def get_children_time (): #print(os.times()) (_, _, child_system_time, child_user_time, _) = os.times() return child_system_time + child_user_time def get_start_time (): return get_children_time() def get_used_time (start_time): end_time = get_children_time() return cut_time(end_time - start_time) ### configuration # default values for options optionsDefault = { OPT_VERBOSE : True, OPT_LEVEL : 0, OPT_TIMEOUT : 0, OPT_MEMOUT : 0, OPT_CHECK_TIMEOUT : False, OPT_LANG : "all", OPT_VC : "cvc3", } # precedence order of options is: # 1. defined as command line options # 2. defined in problem file # 3. defined as default in optionsDefault # otherwise fail class Config: def __init__ (self, options, prover_options): # configuration options for this script self.options = options # options to be passed to the prover self.prover_options = prover_options # option: name of option whose value is requested # optionsProblem: options specified in the current problem def get (self, option, optionsProblem = None): if self.options.has_key(option): return self.options[option] elif optionsProblem != None and optionsProblem.has_key(option): return optionsProblem[option] elif optionsDefault.has_key(option): return optionsDefault[option] else: raise ("unknown option: " + str(option)) def getProverOptions (self): return self.prover_options ### evaluation of option settings per problem file def match_line(key, line): match = re.search("^(;|\s|%|#)*" + key + "\s*=\s*(?P\S+)", line) if match != None: return match.group("value").lower() # Read the first 'maxInfoLines' of the problem specification # and fetch information from the comments def get_problem_opt (name): #print ("get_problem_opt" + " " + name); options = {} prover_options = [] try: problem_file = open (name) lines = 0 # readline will just return "\n" after EOF while (lines < MAX_INFO_LINES): lines += 1 line = problem_file.readline() match = match_line("Regression level", line) if match != None: try: options[PRO_LEVEL] = int(match) except ValueError: sys.stderr.write("Regression level requires an integer argument, got : " + match + " in " + name + "\n") continue match = match_line("Result", line) if match != None: if match in ["valid", "invalid", "satisfiable", "unsatisfiable", "unknown"]: options[PRO_RESULT] = match else: sys.stderr.write("Result has invalid argument: " + match + " in " + name + "\n") continue match = re.search("^\s*:status\s*(?P\S+)", line) if match != None: match = match.group("value").lower() if match == "unsat": options[PRO_RESULT] = "unsat" #options[PRO_RESULT] = "unsatisfiable" elif match == "sat": options[PRO_RESULT] = "sat" #options[PRO_RESULT] = "satisfiable" elif match == "unknown": options[PRO_RESULT] = "unknown" else: sys.stderr.write("status has invalid argument: " + match + " in " + name + "\n") match = match_line("Runtime", line) if match != None: try: options[PRO_TIMEOUT] = int(match) except ValueError: sys.stderr.write("Runtime requires an integer argument, got : " + match + " in " + name + "\n") continue match = match_line("Language", line) if match != None: options[PRO_LANG] = match continue match = match_line("Program Options", line) if match != None: prover_options = match.split() continue problem_file.close () except IOError, (error_nr, error_string): print ("Couldn't open " + name + " : " + error_string) return (options, prover_options) # If regression level is not set, make it 3. So, if a lower level # is requested, only explicitly marked tests will be run. if not options.has_key(PRO_LEVEL): options[PRO_LEVEL] = 3 # If the input language is not defined, guess it by extension if not options.has_key(PRO_LANG): ext = find(lambda x: name.endswith(x), FILE_EXTENSIONS) if ext == None: sys.stderr.write("Couldn't determine language of " + name + "\n") elif ext == "cvc" or ext == "cvc3" or ext == "svc": options[PRO_LANG] = "presentation" elif ext == "smt": options[PRO_LANG] = "smtlib" elif ext == "lisp" or ext == "lsp": options[PRO_LANG] = "lisp" else: sys.stderr.write("unexpected extension " + ext + " in " + name + "\n") return (options, prover_options) ### command line parameters optionsHelp = { "-h" : "Print this help and exit", "-" + OPT_VERBOSE : "Be verbose (default, opposite of -q)", "-" + OPT_QUIET : "Quiet mode (opposite of -v)", "-" + OPT_LEVEL + " n" : "Set regression level (default 0, the easiest level)", "-" + OPT_TIMEOUT + " secs" : "Run each executable for at most 'secs' seconds [0 = no limit]", "-" + OPT_MEMOUT + " MB" : "Abort if memory limit is exceeded [0 = no limit]", "+" + OPT_CHECK_TIMEOUT: "Check that each test finishes within the specified runtime", "-" + OPT_CHECK_TIMEOUT: "Do not check whether test finishes within the specified runtime (default)", "-" + OPT_LANG + " name" : "Use the named input language only (default=all)", "-" + OPT_VC + " prog" : "Use prog to run tests (default=cvc3)", } usageString = \ '''run_tests.py [ options ] [ test1 test2 ... ] [ -- [ command line options ] ]" Run regression tests. Concrete test files or directories with test files should be specified by name with a full path or relative path to the current directory. If none specified, all subdirectories are searched for test files. Subdirectories are searched recursively, but symbolic links do directories are not followed. Default running mode is overriden by test specs; test specs are overriden by command line options."''' ### command line parameter evaluation # conversion of an argument from string to int def to_int(option, value): try: return int(value) except ValueError: sys.stderr.write("Option " + option + " requires an integer argument, got : " + value + " \n") sys.exit(1) # increment the position in sys.argv def next_argument(i, option): i += 1 if i > sys.argv: sys.stderr.write("Option " + option + " requires an argument\n") sys.stderr.write("Run run_tests -h for help\n") sys.exit(1) return i # evaluate sys.argv def eval_arguments (): # results of argument evaluation: # options for this script options = {} # list of testcases to run testcases = [] # prover options prover_options = [] i = 1 while i < len(sys.argv): # first we expect options for the script, # then after "--" options for the prover. if sys.argv[i] == "--": i += 1 prover_options = sys.argv[i:] break elif sys.argv[i] == "-h": print(usageString) for (option, help_string) in optionsHelp.iteritems(): print(option.ljust(12) + help_string) sys.exit() elif sys.argv[i] == "+" + OPT_CHECK_TIMEOUT: options[OPT_CHECK_TIMEOUT] = True elif sys.argv[i] == "-" + OPT_CHECK_TIMEOUT: options[OPT_CHECK_TIMEOUT] = False elif sys.argv[i] == "-" + OPT_VERBOSE: options[OPT_VERBOSE] = True elif sys.argv[i] == "-" + OPT_QUIET: options[OPT_VERBOSE] = False elif sys.argv[i] == "-" + OPT_LANG: i = next_argument(i, sys.argv[i]) options[OPT_LANG] = sys.argv[i] elif sys.argv[i] == "-" + OPT_LEVEL: i = next_argument(i, sys.argv[i]) options[OPT_LEVEL] = to_int(OPT_LEVEL, sys.argv[i]) elif sys.argv[i] == "-" + OPT_TIMEOUT: i = next_argument(i, sys.argv[i]) options[OPT_TIMEOUT] = to_int(OPT_TIMEOUT, sys.argv[i]) elif sys.argv[i] == "-" + OPT_MEMOUT: i = next_argument(i, sys.argv[i]) options[OPT_MEMOUT] = to_int(OPT_MEMOUT, sys.argv[i]) elif sys.argv[i] == "-" + OPT_VC: i = next_argument(i, sys.argv[i]) options[OPT_VC] = sys.argv[i] # This must be a testcase name else: testcases.append(sys.argv[i]) i = i + 1 return (options, testcases, prover_options) ### get test cases # 'enumeration' RES_TESTS, RES_TIME, RES_CORRECT, RES_PROBLEMATIC, RES_INCORRECT, \ RES_FAILED, RES_TIMEOUT, RES_MEMOUT, RES_ARITH, RES_TOO_LONG, RES_MUCH_TOO_LONG, RES_TOO_FAST, \ RES_MUCH_TOO_FAST, RES_LANG, RES_STRANGE = range(15) def create_results (): results = {} results[RES_TESTS] = 0 results[RES_TIME] = 0 results[RES_CORRECT] = 0 results[RES_PROBLEMATIC] = 0 results[RES_INCORRECT] = [] results[RES_FAILED] = [] results[RES_TIMEOUT] = [] results[RES_MEMOUT] = [] results[RES_ARITH] = [] results[RES_TOO_LONG] = [] results[RES_MUCH_TOO_LONG] = [] results[RES_TOO_FAST] = [] results[RES_MUCH_TOO_FAST] = [] results[RES_LANG] = [] results[RES_STRANGE] = [] return results ### run tests # is file name a test case name? def is_test_case(config, problem_options): # a test case if problem_options.has_key(PRO_LANG): # either all or this particular language must be ok return config.get(OPT_LANG) == "all" or config.get(OPT_LANG) == problem_options[PRO_LANG] # unknown file type else: return 0 def run_test (config, name, results, check_lang = False): (problem_options, problem_prover_options) = get_problem_opt(name) # if is_test_case(config, problem_options): # Check regression level if problem_options[PRO_LEVEL] > config.get(OPT_LEVEL): # Regression level of this test is too high; skip it return # Print the testcase name print("=" * WIDTH) print(name + " : ") # Print some testcase specific info print_test_info(config, problem_options, problem_prover_options) # setup prover arguments arguments = [] arguments.append(config.get(OPT_VC)) # we don't check for proofs anyway, so we disable them arguments.append("-proofs") # set language if problem_options[PRO_LANG] != "representation": arguments.append("-lang") arguments.append(problem_options[PRO_LANG]) # add general prover options for arg in config.getProverOptions(): arguments.append(arg) # add problem specific prover options for arg in problem_prover_options: arguments.append(arg) if config.get(OPT_TIMEOUT) > 0: arguments.append("-timeout"); arguments.append(repr(config.get(OPT_TIMEOUT))) arguments.append(name) # redirect error to stdout arguments.append(" 2>&1") command = " ".join(arguments) #print("***") print("Running " + command) print #print("***"); #reader, writer = os.pipe() #start_time = get_start_time() start_time = time.time() pipe = os.popen(command); #global alarm_pipe #global alarm_raised #if config.get(OPT_TIMEOUT) > 0: #alarm_pipe = pipe #alarm_raised = False #signal.alarm(config.get(OPT_TIMEOUT)) #pid = os.fork() # if pid == 0: # try: # # set_resource_limits # #if config.get(OPT_TIMEOUT) > 0: # # resource.setrlimit (resource.RLIMIT_CPU, (config.get(OPT_TIMEOUT), config.get(OPT_TIMEOUT))) # #if config.get(OPT_MEMOUT) > 0: # # MEMORY_LIMIT = config.get(OPT_MEMOUT) * 1024 * 1024 # # resource.setrlimit (resource.RLIMIT_AS, (MEMORY_LIMIT, MEMORY_LIMIT)) # # forward output to parent process # os.close(reader) # os.dup2(writer, sys.stdout.fileno ()) # os.dup2(writer, sys.stderr.fileno ()) # # run prover # os.execvp(arguments[0], arguments) # except OSError, (error_nr, error_string): # sys.stderr.write("Error in executing '" + command + "': " + error_string + "\n") # sys.exit(error_nr) # else: #os.wait() #os.close(writer) results[RES_TESTS] += 1 # run prover #os.execvp(config.get(OPT_VC), arguments) #pipe = os.popen(command) #pipe = os.fdopen(reader, 'r') # check output result = None resultError = None resultTimeout = False resultMemout = False resultArith = False #:TODO: select on pipe with timeout #try: if True: for line in pipe: print line, if line.startswith("*** Out of memory") \ or line.startswith("Out of memory") \ or line.startswith("terminate called after throwing an instance of 'std::bad_alloc'"): resultMemout = True # cvc timout: cygwin/.net if line.startswith("Interrupted by signal 14 (self-timeout).") or line.startswith("self-timeout"): resultTimeout = True if line.count("arithmetic overflow"): resultArith = True # get only first result if result == None: chomped = line.rstrip().lower() if chomped in ["valid.", "invalid.", "satisfiable.", "unsatisfiable.", "unknown.", "unsat.", "sat."]: result = chomped[:-1] elif chomped in ["unknown", "unsat", "sat"]: result = chomped #except 'Timeout': # resultTimeout = True # pipe.close() # exit_val = -1 #signal.alarm(0) #if alarm_raised: # alarm_pipe = None # alarm_raised = False # resultTimeout = True #else: #if not resultTimeout: exit_val = pipe.close() #(_, exit_val) = os.wait () #used_time = get_used_time(start_time) end_time = time.time() used_time = cut_time(end_time - start_time) # check run time print("Program Runtime: " + str(used_time) + " sec"), if result != None: results[RES_TIME] += used_time if config.get(OPT_CHECK_TIMEOUT) and problem_options.has_key(PRO_TIMEOUT): expected_time = problem_options[PRO_TIMEOUT] if used_time > expected_time: if used_time > 10 * expected_time: results[RES_MUCH_TOO_LONG].append(name) print(" MUCH") print(" LONGER than expected: " + str(expected_time) + " sec") results[RES_TOO_LONG].append(name) results[RES_PROBLEMATIC] += 1 elif ((problem_options[OPT_TIMEOUT] >= 4 and expected_time <= 4 and used_time < expected_time - 2) or (used_time > 15 and used_time <= (17 * expected_time) / 20)): if used_time <= expected_time / 2: results[RES_MUCH_TOO_FAST].append(name) print(" MUCH") print(" FASTER than expected: " + str(expected_time) + " sec") results[RES_TOO_LONG].append(name) results[RES_PROBLEMATIC] += 1 print # check prover status # resource out: memory if resultMemout: results[RES_MEMOUT].append(name) resultError = RES_MEMOUT print("*** Out of memory ") # resource out: arithmetic precision elif resultArith: results[RES_ARITH].append(name) resultError = RES_ARITH print("*** arithmetic overflow ") # resource out: time - at least on my linux version ... is this defined somewhere? elif resultTimeout or (exit_val == 9 and config.get(OPT_TIMEOUT) > 0 and used_time >= config.get(OPT_TIMEOUT)): results[RES_TIMEOUT].append(name) resultError = RES_TIMEOUT print("*** Timed out ") elif exit_val != None: if config.get(OPT_TIMEOUT) == 0 and config.get(OPT_MEMOUT) == 0: results[RES_FAILED].append(name) print("*** FAILED with exit code " + str(exit_val)) sys.stderr.write("Warning, unexpected termination with exit code " + str(exit_val) + "\n") else: results[RES_FAILED].append(name) print("*** FAILED with exit code " + str(exit_val)) sys.stderr.write("Warning, unexpected termination with exit code " + str(exit_val) + "\n") # check that computed result is the expected result elif problem_options.has_key(PRO_RESULT): if result == None: results[RES_FAILED].append(name) sys.stdout.write("FAILED (no result, expected " + problem_options[PRO_RESULT] + ")\n") sys.stderr.write("FAILED (no result, expected " + problem_options[PRO_RESULT] + ")\n") elif problem_options[PRO_RESULT] != result: if result == "unknown": results[RES_STRANGE].append(name) results[RES_PROBLEMATIC] += 1 sys.stdout.write("Warning, expected " + problem_options[PRO_RESULT] + " but got unknown\n") sys.stderr.write("Warning, expected " + problem_options[PRO_RESULT] + " but got unknown\n") elif problem_options[PRO_RESULT] == "unknown": results[RES_STRANGE].append(name) results[RES_PROBLEMATIC] += 1 sys.stdout.write("Warning, expected unknown but got " + result + "\n") sys.stderr.write("Warning, expected unknown but got " + result + "\n") else: results[RES_INCORRECT].append(name) resultError = RES_INCORRECT sys.stdout.write("FAILED (incorrect result, expected " + problem_options[PRO_RESULT] + " but got " + result + ")\n") sys.stderr.write("FAILED (incorrect result, expected " + problem_options[PRO_RESULT] + " but got " + result + ")\n") else: results[RES_CORRECT] += 1 print("Result is correct") # any result is fine, as we don't know the correct result elif result != None: results[RES_CORRECT] += 1 print("Result is correct") # no result else: results[RES_STRANGE].append(name) results[RES_PROBLEMATIC] += 1 print("No result") if PRINT_SUMMARY: short_name = os.path.basename(name) if result != None: printResult = result elif resultError == RES_INCORRECT: printResult = "unsound:" elif resultError == RES_TIMEOUT: printResult = "timeout" elif resultError == RES_MEMOUT: printResult = "memout" elif resultError == RES_ARITH: printResult = "arith_overflow" else: printResult = "???" print("SUMMARY: " + name) print((short_name + " ").ljust(40) + (printResult + " ").ljust(20) + str(used_time)) elif check_lang: results[RES_LANG].append(name) results[RES_PROBLEMATIC] += 1 else: print("IGNORE " + name) sys.stdout.flush() # expects strings, potentially with number def cmpStrNum(x, y): if x == y: return 0 # find first different character xLength = len(x) yLength = len(y) index = 0 while (index < xLength and index < yLength): if x[index] == y[index]: index += 1 elif (not x[index].isdigit()) or (not y[index].isdigit()): return cmp(x[index], y[index]) # compare as numbers else: # find start of number start = index while start >= 0 and x[start].isdigit(): start -= 1 start += 1 xEnd = index while xEnd < xLength and x[xEnd].isdigit(): xEnd += 1 yEnd = index while yEnd < yLength and y[yEnd].isdigit(): yEnd += 1 xNum = int(x[start:xEnd]) yNum = int(y[start:yEnd]) return cmp(xNum, yNum) # one string is prefix of the other if index >= xLength: return -1 if index >= yLength: return 1 else: raise ("cmpStrNum: " + x + " " + y) # find all test cases in directory def find_test_case((config, results), dir_name, files_in_dir): files_in_dir.sort(cmpStrNum) for file_name in files_in_dir: file_path = os.path.join (dir_name, file_name) if os.path.isfile (file_path) and exists(lambda x: file_name.endswith(x), FILE_EXTENSIONS): run_test(config, file_path, results) def run_tests(config, test_cases): #test_cases.sort() results = create_results() for test_case in test_cases: # if a file, try it if os.path.isfile(test_case): run_test(config, test_case, results, True) # else traverse subdirectories elif os.path.isdir(test_case): os.path.walk(test_case, find_test_case, (config, results)) else: sys.stderr.write("*** WARNING: cannot find testcase " + test_case + " : no such file or directory\n") return results ### printing def print_setup(config): if config.get(OPT_VERBOSE): print("*" * WIDTH) # get prover to use (and remove eol) prover = os.popen("which " + config.get(OPT_VC)).readline()[:-1] print("Prover: ".ljust(WIDTH) + prover) print("Regression level: ".ljust(WIDTH) + repr(config.get(OPT_LEVEL))) print("Language: ".ljust(WIDTH) + config.get(OPT_LANG)) if(config.get(OPT_TIMEOUT) > 0): print("Time limit per test: ".ljust(WIDTH) + str(config.get(OPT_TIMEOUT)) + " sec") if(config.get(OPT_MEMOUT) > 0): print("Memory limit per test: ".ljust(WIDTH) + str(config.get(OPT_MEMOUT)) + " MB") #print("PATH = ", $ENV{'PATH'}) print("*" * WIDTH) def print_test_info (config, problem_options, problem_prover_options): if config.get(OPT_VERBOSE): print("Language: " + problem_options[PRO_LANG]) if config.get(OPT_CHECK_TIMEOUT) and problem_options.has_key(PRO_TIMEOUT): print("Expected runtime: " + problem_options[PRO_TIMEOUT] + " sec") if problem_options.has_key(PRO_RESULT): print("Expected result: " + problem_options[PRO_RESULT]) print("Program options: " + " ".join(config.getProverOptions() + problem_prover_options)) def print_end (config, results): print print("Statistics:") print("Total tests run: " + repr(results[RES_TESTS])); print("Total running time: " + repr(results[RES_TIME]) + " sec") if config.get(OPT_VERBOSE) and results[RES_TESTS] > 0: print print("Detailed Statistics:") print("Correct results: ".ljust(WIDTH) + repr(results[RES_CORRECT])); print("Incorrect: ".ljust(WIDTH) + repr(len(results[RES_INCORRECT]))); print("Problematic cases: ".ljust(WIDTH) + repr(results[RES_PROBLEMATIC])) print("Timed out: ".ljust(WIDTH) + repr(len(results[RES_TIMEOUT]))); print("Out of memory: ".ljust(WIDTH) + repr(len(results[RES_MEMOUT]))); print("Arithmetic overflow: ".ljust(WIDTH) + repr(len(results[RES_ARITH]))); print("Failed: ".ljust(WIDTH) + repr(len(results[RES_FAILED]))); test_cases = results[RES_FAILED] if len(test_cases) > 0: print("Failed tests: " + repr(len(test_cases))) for test_case in test_cases: print(" " + test_case) test_cases = results[RES_INCORRECT] if len(test_cases) > 0: print("Tests with wrong results [" + repr(len(test_cases)) + "]:") for test_case in test_cases: print(" " + test_case) test_cases = results[RES_STRANGE] if len(test_cases) > 0: print("Strange results [" + repr(len(test_cases)) + "]:") for test_case in test_cases: print(" " + test_case) test_cases = results[RES_TIMEOUT] if len(test_cases) > 0: print("Tests timed out [" + repr(len(test_cases)) + "]:") for test_case in test_cases: print(" " + test_case) test_cases = results[RES_MEMOUT] if len(test_cases) > 0: print("Tests out of memory [" + repr(len(test_cases)) + "]:") for test_case in test_cases: print(" " + test_case) test_cases = results[RES_ARITH] if len(test_cases) > 0: print("Arithmetic overflow [" + repr(len(test_cases)) + "]:") for test_case in test_cases: print(" " + test_case) test_cases = results[RES_TOO_FAST] if len(test_cases) > 0: print("Tests running faster than expected [" + repr(len(test_cases)) + "]:") for test_case in test_cases: print(" " + test_case) test_cases = results[RES_MUCH_TOO_FAST] if len(test_cases) > 0: print("...including tests running at least twice as fast as expected [" + repr(len(test_cases)) + "]:") for test_case in test_cases: print(" " + test_case) test_cases = results[RES_TOO_LONG] if len(test_cases) > 0: print("Tests running longer [" + repr(len(test_cases)) + "]:") for test_case in test_cases: print(" " + test_case) test_cases = results[RES_MUCH_TOO_LONG] if len(test_cases) > 0: print("...including tests running WAT too long [" + repr(len(test_cases)) + "]:") for test_case in test_cases: print(" " + test_case) test_cases = results[RES_LANG] if len(test_cases) > 0: print("Tests with wrong input language [" + repr(len(test_cases)) + "]:") for test_case in test_cases: print(" " + test_case) ### main def main (): # evaluate command line (options, test_cases, prover_options) = eval_arguments() config = Config(options, prover_options) # run the prover on all test cases print_setup(config) results = run_tests(config, test_cases) print_end(config, results) main () cvc3-2.4.1/java/Cvc3_manifest0000664000175400017540000000005611070741376015615 0ustar mdetersmdetersMain-Class: cvc3/Cvc3 Class-Path: libcvc3.jar cvc3-2.4.1/PEOPLE0000664000175400017540000000153010466450540013170 0ustar mdetersmdetersThe following individuals have contributed code to CVC3 ------------------------------------------------------------ Clark Barrett, New York University Alexander Fuchs, University of Iowa Yeting Ge, New York Univeristy George Hagen, University of Iowa The following individuals contributed code to CVC Lite before it became CVC3 ------------------------------------------------------------ Clark Barrett, New York University Sergey Berezin, Stanford University Cristian Cadar, Stanford University Jake Donham, New York University Yeting Ge, New York Univeristy Vijay Ganesh, Stanford University Deepak Goyal, Calypto Ying Hu, New York University Sean McLaughlin, New York University Mehul Trivedi, Stanford University Michael Veksler, Technion, Israel Daniel Wichs, Stanford University Mark Zavislak, Stanford University Jim Zhuang, Stanford University cvc3-2.4.1/Makefile.std0000664000175400017540000002221211260724552014512 0ustar mdetersmdeters################################################## # Makefile.std # Aaron Stump, Spring 1998 # Modified by Clark Barrett, Spring 2005 ################################################## ################################################## # # This Makefile can be included by other Makefiles # to get certain rules defined. This Makefile # assumes the following (items marked with # '**' cannot be left undefined, but all others # can be). Note that you should define at most one # of LIBRARY or EXECUTABLE # # ** 1. $(SRC) gives the names of all the # source (*.cpp) files for your target. # 2. $(OTHER_OBJ) gives the names of any # object files that should be linked in # with the executable or library but # not themselves built. # 3. $(HEADERS) gives the names of all # the header files for your target. # 4. $(EXECUTABLE) gives the name of the # executable you're trying to compile, # if you're trying to compile an # executable. # 5. $(LIBRARY) gives the name of the # library you're trying to compile, # if you're trying to compile a library. # 6. if $(OPTIMIZED) is defined, an optimized # target is built. Otherwise, a debug # target is built. # 7. The options listed below have defaults # that you may want to override. ################################################## # # To review: # # What rule should delete the dynamic cvc3 binary? clean or spotty # What rule should delete the dynamic libs? clean or spotty # What rule should delete the dynamic link libcvc3.dylib in libs? clean or spotty # What rule should delete logs? (regressions.log) clean or distclean # What rule should delete autoconf-generated files? distclean # (config.log, config.status, configure, autom4ta.cache) # What rule should delete configure-generated files? distclean # (those derived from *.in: # ./bin/cvc2smt.in ./bin/libmerge.in ./bin/run_tests.in ./doc/Doxyfile.in # ./doc/Makefile.in ./LICENSE.in ./Makefile.local.in) # test/Makefile's clean should delete test/obj/**/*.o, test/bin/**/test # testc/Makefile's clean ... # cleaning test1.cvc? # How about library version information? ################################################## # Force shell to Bash so we can rely on some process management # tricks like ${PIPESTATUS[0]} and <( ... ) for process redirection SHELL = /bin/bash ################################################## # Special versions of dir/notdir built-ins that # can handle paths with spaces # Note that, unlike dir/notdir, these functions # take a *single* path and assume that any spaces # are part of the path (they need not be escaped). ################################################## s? = $(subst $(empty) ,?,$(1)) ?s = $(subst ?, ,$(1)) notdirx = $(call ?s,$(notdir $(call s?,$(1)))) dirx = $(call ?s,$(dir $(call s?,$(1)))) ################################################## # Compute flags and platform based on options ################################################## #Default platform is generic ifndef PLATFORM PLATFORM := generic endif ifeq ($(SMTCOMP),1) LOCAL_CXXFLAGS = -O9 -funroll-all-loops -fexpensive-optimizations DEBUG_PLATFORM =-smtcomp else ifeq ($(OPTGDB),1) LOCAL_CXXFLAGS = -g DEBUG_PLATFORM = -optgdb else ifeq ($(OPTDEBUG),1) LOCAL_CXXFLAGS = -O2 -D_CVC3_DEBUG_MODE DEBUG_PLATFORM = -optdbg else ifeq ($(OPTIMIZED),1) LOCAL_CXXFLAGS = -O2 DEBUG_PLATFORM = else LOCAL_CXXFLAGS = -D_CVC3_DEBUG_MODE -g -O0 DEBUG_PLATFORM = -debug endif endif endif endif ifeq ($(GCOV),1) LOCAL_CXXFLAGS += -fprofile-arcs -ftest-coverage GTOOLS_PLATFORM = -gcov else ifeq ($(GPROF),1) LOCAL_CXXFLAGS += -pg GTOOLS_PLATFORM = -gprof endif endif PLATFORM_WITH_OPTIONS = $(PLATFORM)$(DEBUG_PLATFORM)$(GTOOLS_PLATFORM) ################################################## # Set variables to defaults if not already set ################################################## ifdef BASE_DIR SRC_DIR = $(BASE_DIR) OBJ_DIR = $(BASE_DIR)/obj/$(PLATFORM_WITH_OPTIONS) else BASE_DIR=$(TOP) endif ifndef SRC_DIR SRC_DIR = $(TOP)/src/$(MODULE) endif ifndef OBJ_DIR OBJ_DIR = $(TOP)/obj/$(MODULE)/$(PLATFORM_WITH_OPTIONS) endif ifndef EXE_DIR EXE_DIR=$(BASE_DIR)/bin/$(PLATFORM_WITH_OPTIONS) endif ifndef LIB_DIR LIB_DIR = $(TOP)/lib/$(PLATFORM_WITH_OPTIONS) endif #Default C++ suffix is cpp ifndef CPPSUFFIX CPPSUFFIX = cpp endif #Default compiler/linker is g++ ifndef CXX CXX = g++ endif #Default linker is same as CXX ifndef LD LD = $(CXX) endif #Default include directory is current directory ifndef INCLUDE_DIR INCLUDE_DIR=-I. endif #Default directory for link libraries is current directory ifndef LD_LIB_DIR LD_LIB_DIR=-L. endif #If TRANSIENT is defined, clean will remove those files #automatically. By default, no transient files. ifndef TRANSIENT TRANSIENT= endif #Default is to build individual shared libraries ifndef BUILD_SHARED_LIB BUILD_SHARED_LIB=1 endif LOCAL_CXXFLAGS += -Wall $(INCLUDE_DIR) ifdef EXTRAFLAGS LOCAL_CXXFLAGS += $(EXTRAFLAGS) endif ################################################## # Objects from Sources ################################################## OBJ = $(patsubst %.$(CPPSUFFIX), $(OBJ_DIR)/%.o, $(SRC)) $(OBJ_DIR)/%.o : %.$(CPPSUFFIX) @mkdir -p $(OBJ_DIR) $(CXX) $(CXXFLAGS) $(LOCAL_CXXFLAGS) $(CPPFLAGS) -c $< -o '$@' ################################################## # executables and libraries ################################################## .PHONY: all depend clean real_clean spotty print_src ifeq ($(STATIC),1) STATIC_FLAG_TARGET = $(STATIC_FLAG) LIB_SUFFIX = $(STATIC_LIB_SUFFIX) EXE_DIR_STATIC_OR_DYNAMIC = $(EXE_DIR)/static else STATIC_FLAG_TARGET = LIB_SUFFIX = $(SHARED_LIB_SUFFIX) EXE_DIR_STATIC_OR_DYNAMIC = $(EXE_DIR) endif ifdef EXECUTABLE # Compile executable BUILD_SPECIFIC_TARGET = $(EXE_DIR_STATIC_OR_DYNAMIC)/$(EXECUTABLE)$(EXEEXT) BUILD_INDEPENDENT_TARGET = $(BASE_DIR)/bin/$(EXECUTABLE)$(EXEEXT) all: $(MAKE) $(BUILD_SPECIFIC_TARGET) @rm -f $(BUILD_INDEPENDENT_TARGET) ln -sf $(BUILD_SPECIFIC_TARGET) $(BUILD_INDEPENDENT_TARGET) $(BUILD_SPECIFIC_TARGET): $(OBJ) $(OTHER_OBJ) $(OTHER_DEPENDENCIES) @mkdir -p $(EXE_DIR_STATIC_OR_DYNAMIC) $(LD) $(STATIC_FLAG_TARGET) $(CXXFLAGS) $(LOCAL_CXXFLAGS) $(LDFLAGS) -o '$@' $(OBJ) \ $(OTHER_OBJ) $(LD_LIB_DIR) $(LD_LIBS) else ifdef LIBRARY # Compile library SHARED_LIBRARY = $(patsubst %.$(STATIC_LIB_SUFFIX),%.$(SHARED_LIB_SUFFIX),$(LIBRARY)) STATIC_LIB_TARGET = $(LIB_DIR)/$(LIBRARY) SHARED_LIB_TARGET = $(LIB_DIR)/$(SHARED_LIBRARY) BUILD_SPECIFIC_TARGET = $(STATIC_LIB_TARGET) ifneq ($(STATIC),1) ifeq ($(BUILD_SHARED_LIB),1) BUILD_SPECIFIC_TARGET += $(SHARED_LIB_TARGET) endif endif all: $(BUILD_SPECIFIC_TARGET) $(SHARED_LIB_TARGET): $(OBJ) $(OTHER_OBJ) @mkdir -p $(LIB_DIR) $(CXX) $(SHARED) -o '$@' $(OBJ) $(OTHER_OBJ) $(STATIC_LIB_TARGET): $(OBJ) $(OTHER_OBJ) @mkdir -p $(LIB_DIR) ar ruvs '$@' $(OBJ) $(OTHER_OBJ) @#ranlib '$@' else LIB_OR_EXE = 0 endif endif ifeq ($(LIB_OR_EXE),0) else ################################################## # depend ################################################## MAKEFILE_DEPS=$(OBJ_DIR)/Makefile.deps MAKEFILE_DEPS_TMP=$(OBJ_DIR)/Makefile.tmp MAKEFILE_DEPS_TMP2=$(OBJ_DIR)/Makefile.tmp2 ifndef MY_DEPEND depend: $(SRC) $(HEADERS) $(OTHER_DEPEND) @mkdir -p $(OBJ_DIR) @-rm -f $(MAKEFILE_DEPS) $(MAKEFILE_DEPS_TMP) $(MAKEFILE_DEPS_TMP2) @echo '# Dependencies for C++ files' >> $(MAKEFILE_DEPS_TMP) @echo >> $(MAKEFILE_DEPS_TMP) @echo "Making dependencies for $(SRC)" $(CXX) -M $(CXXFLAGS) $(LOCAL_CXXFLAGS) $(CPPFLAGS) $(SRC) >> $(MAKEFILE_DEPS_TMP) @echo >> $(MAKEFILE_DEPS_TMP) @sed -e '/^.*:/ s#^#$(OBJ_DIR)/#' < $(MAKEFILE_DEPS_TMP) > $(MAKEFILE_DEPS_TMP2) @cat $(MAKEFILE_DEPS_TMP2) > $(MAKEFILE_DEPS) @rm -f $(MAKEFILE_DEPS_TMP) $(MAKEFILE_DEPS_TMP2) endif $(MAKEFILE_DEPS): $(SRC) $(HEADERS) $(OTHER_DEPENDENCY_MAKEFILES) @mkdir -p $(OBJ_DIR) @touch $(MAKEFILE_DEPS) @$(MAKE) --no-print-directory depend ################################################## # clean # # Remove all generated files. ################################################## clean: $(MAKEFILE_DEPS) rm -f $(OBJ) $(BUILD_SPECIFIC_TARGET) $(TRANSIENT) $(MAKEFILE_DEPS) \ $(MAKEFILE_DEPS_TMP) $(MAKEFILE_DEPS_TMP2) $(BUILD_INDEPENDENT_TARGET) distclean: rm -f $(TRANSIENT) ################################################## # spotty # # Remove just the executable or library ################################################## spotty: rm -f $(BUILD_SPECIFIC_TARGET) $(BUILD_INDEPENDENT_TARGET) ################################################## # print_src # # Print all the source files (*.cpp and *.h) for the module ################################################## ifndef FILELIST FILELIST = /dev/null endif # Normally, *.cpp files are the sources. However, if SRC includes # dynamically generated files (e.g. parser files from *.lex and # *.yacc), then SRC_ORIG must be defined to include the true source # files. ifndef SRC_ORIG SRC_ORIG = $(SRC) endif print_src: echo "Collecting files from " src/$(MODULE) @echo $(patsubst %, src/$(MODULE)/%, $(SRC_ORIG)) \ $(patsubst %, src/$(MODULE)/%, $(HEADERS)) \ src/$(MODULE)/Makefile \ >> $(FILELIST) -include $(MAKEFILE_DEPS) endif cvc3-2.4.1/doc/0000775000175400017540000000000011630011320013006 5ustar mdetersmdeterscvc3-2.4.1/doc/theory_api.dox0000664000175400017540000020664510607034533015720 0ustar mdetersmdeters/*! \page theory_api_howto HOWTO Write a Decision Procedure Note: This document is under construction. Some newer aspects of adding a decision procedure are not yet documented here. Please let us know if you have a question that is not answered here. \section theory_api_contents Contents
  • \ref theory_api_prelim
    • \ref theory_api_files
    • \ref theory_api_naming
    • \ref theory_api_general
  • \ref theory_api_addnew
    • \ref theory_api_start
    • \ref theory_api_config
    • \ref theory_api_header
    • \ref theory_api_expr
      • \ref theory_api_kind_decl
      • \ref theory_api_kind_reg
      • \ref theory_api_expr_subclass
      • \ref theory_api_methods
  • \ref theory_api_invars
    • \ref theory_api_flow
    • \ref theory_api_backtrack
    • \ref theory_api_ileaves
    • \ref theory_api_inputs
      • \ref theory_api_assertFact
      • \ref theory_api_checkSat
      • \ref theory_api_setup
      • \ref theory_api_update
      • \ref theory_api_addSharedTerm
      • \ref theory_api_rewrite
      • \ref theory_api_solve
      • \ref theory_api_computeType
      • \ref theory_api_computeTCC
      • \ref theory_api_notifyInconsistent
      • \ref theory_api_print
      • \ref theory_api_parseExprOp
    • \ref theory_api_outputs
      • \ref theory_api_enqueueFact
      • \ref theory_api_setInconsistent
      • \ref theory_api_simplifyThm
      • \ref theory_api_enqueueEquality
      • \ref theory_api_inconsistentThm
      • \ref theory_api_isTerm
      • \ref theory_api_isLiteral
      • \ref theory_api_isAtomic
      • \ref theory_api_updateHelper
      • \ref theory_api_getType
      • \ref theory_api_getTCC
      • \ref theory_api_parseExpr
  • \ref theory_api_proofs
    • \ref theory_api_proof_classes
    • \ref theory_api_proof_rule
\section theory_api_prelim Preliminaries and Coding Guidelines \subsection theory_api_files Directory Structure and Files Each theory (a.k.a. decision procedure, or DP) must reside in a directory src/theory_foo (where foo is the theory name). All the sounce files and Makefile.in must be in that directory, except for some shared header files, which must reside in the common directory src/include. In particular, theory_foo.h must be placed in src/include. The master source file for a theory should be called theory_foo.cpp. Typically, a new theory needs its own set of proof rules, which are implemented as three files: foo_proof_rules.h, foo_theorem_producer.h, and foo_theorem_producer.cpp. The first one is the abstract interface to the rules, which the untrusted DP code can \#include. The other two files implement this abstract API, and comprise the trusted part of the code. All these files should be placed in src/theory_foo. \subsection theory_api_naming Naming Convensions Each individual theory is a subclass of a Theory class, and therefore, its name should be class TheoryFoo. A theory may define several methods for creating expressions in theory_foo.h. Typically, they are named as barExpr(), bazExpr(), etc. For instance, theory_arith.h defines plusExpr(), minusExpr(), etc. These functions are most useful if they are declared as non-member functions (not part of the class TheoryFoo), since then they can be called directly by the CVC3 library users. It is also convenient to define testers like isBar() and isBaz(), which return true for the corresponding expressions. For example, theory_arith.h defines isPlus(), isMinus(), etc. Of course, the rest of the code should follow our general naming and coding guidelines described at length in the project FAQ: http://verify.stanford.edu/savannah/faq/?group_id=1&question=How_Do_I_Become_A_CVC3_Developer.txt . \subsection theory_api_general General Guidelines The Theory API is designed to minimize the changes in the central (core) files when adding a new theory. Ideally, only src/vcl/vcl.cpp file needs to be modified to add a constructor call to the new theory. Everything else --- kinds, special expression subclasses, types, etc. --- can (and should) be defined locally in the theory-specific files. There are several important guidelines for writing proof rules specific to your theory:
  • Each proof rule must be mathematically sound.
  • It is a mortal sin to introduce a proof rule without a proper doxygen comment concisely and clearly describing what it does.
  • The code must contain enough CHECK_SOUND checks to guarantee that all the premises are of the right form, and all the side conditions of the rule are satisfied. That is, if these soundness checks pass, then the rule application is guaranteed to be sound mathematically.
  • Keep the code in each rule as clean and simple as possible, so that the correctness of the implementation w.r.t. the mathematical formulation can be easily checked by manual inspection. That is, many simple and independent rules are strongly preferred to a few big mega-rules.
  • Avoid calling other proof rules from within a proof rule. Rule of thumb: if your rule has to use other rules, most likely, it is a strategy (a derived rule), and should be implemented in the untrusted part of the code (e.g. in theory_foo.cpp).
More details are given in the separate \ref theory_api_proofs "section on proof rules". Finally, and most importantly: document your code!! Every method, variable, class, or type should have a doxygen-style comment with at least a brief description: \verbatim //! Convert Blah expression to Baz value Baz Blah2Baz(const Blah& b); \endverbatim Imagine telling such a description to your colleague who has very faint idea of what you are coding. If a brief description does not make sense to him/her, or the function does something non-trivial or non-obvious, add a longer description: \verbatim //! Convert Blah expression to Baz value /*! * Recursively descend into Blah, collect every Foo-leaf, order them in * the descending order of Baz-ability, and wrap into the Baz expression. * * \param b is a non-trivial Blah value (otherwise we assert-fail). */ Baz Blah2Baz(const Blah& b); \endverbatim Often it is convenient to keep the brief description in the *.h file, and the long description in the corresponding *.cpp file. The only exceptions are the \ref theory_api "Theory API methods", for which no documentation is necessary, since these are already documented in theory.h. \section theory_api_addnew Adding New Theory \subsection theory_api_start Before You Start... ...Make sure you have a very good idea about what your new decision procedure is supposed to do, why it is useful, and what exactly it decides. Next, write down all the definitions mathematically and phrase the scope of the new theory in terms of a logic with a particular signature (the set of predefined interpreted and uninterpreted symbols that belong to this theory). Make sure this signature is disjoint from all the other theories (this is very important, since CVC3 is based on Nelson-Oppen combination result, and requires signatures to be disjoint). Your decision procedure should decide inconsistency of a set of formulas in the above logic. Make sure you actually know an algorithm for that. While it is possible to add undecidable or incomplete theories to CVC3 (and we already have some), those should only be used for a very good reason. Otherwise, make sure you know that your algorithm is sound, complete, and terminating. Take the above algorithm and make it an online one. That is, your algorithm should be able to accept a new formula at any point in time, and perform some incremental computation to take that formula into account. This is usually the most complicated step as far as the math is concerned. I will explain this step in detail in section \ref theory_api_invars "Theory API" below. If you are adding your theory to the official CVC3 code base, discuss your ideas on the mailing list! Yes, do it, I mean it. If you do not, we will notice your sneaky additions right away, and will ask many difficult questions in public. So, you may as well just announce it yourself. \subsection theory_api_config Configure and Makefiles Now you are ready to begin. Pick a name for your new theory, say, Foo, and do the following steps. - Create a new CVS branch. You already know how to do this, right? If not, read the FAQ: http://verify.stanford.edu/savannah/faq/?group=vergrp . Read it NOW. - Create a directory src/theory_foo, add it to CVS - Create the following files (either empty or copy them from an existing theory), and add them to your new CVS branch:
In src/include/
theory_foo.h
In src/theory_foo/
theory_foo.cpp
Makefile.in
If your new theory needs to create new custom proof rules, also create
in src/theory_foo/
foo_proof_rules.h
foo_theorem_producer.h
foo_theorem_producer.cpp
While you at it, add the required header comment to each source file (*.h and *.cpp), with the appropriately modified file name, author, date, and an optional description after the license excerpt. Look at any existing source file for a template. - Edit src/theory_foo/Makefile.in appropriately (look for a template from some other theory, for example, theory_array). You need to modify the values of: - LIBRARY - LOCAL_OBJ_DIR and LOCAL_SRC_DIR - SRC - HEADERS (if you created any *.h files in src/theory_foo/, such as foo_proof_rules.h). - Edit src/Makefile.in (it is a common Makefile for all theories): - Add theory_foo.h to HEADER_NAMES - Add cd theory_foo \&\& \$(MAKE) \$(TARGET) to build: target - Add theory_foo entry to CVC_LIB_NAMES - Edit configure.in: - Add an entry \$CVC_SRC_SUBDIR/theory_foo/Makefile to CVC_OUTPUT_FILES variable - Run autoheader, autoconf, ./configure. - Edit src/vcl/vcl.cpp to add a call to your theory's constructor: - Add \#include "theory_foo.h" at the top; - Add d_theories.push_back(new TheoryFoo(this)); to the end of VCL::VCL() constructor. File src/vcl/vcl.cpp is the only source file in the core of CVC3 that you really need to touch in order to add a new theory. If you have to do something else, you are either doing it wrong, or there better be a very good reason for it. Now you are all set for compiling your new code, except that there is no code to compile yet... \subsection theory_api_header Header File: theory_foo.h The easiest way to start is to use an existing theory_whatever.h file as a template. This header file should declare the following elements:
  • class TheoryFoo as a subclass of Theory;
  • Non-member (global) functions for creating expressions in your theory, and possibly, testers for those expressions; for instance: plusExpr(), multExpr(), ..., isPlus(), isMult(), ...
  • Optionally, declaration of new kinds (an enum type) used in the above expressions.
Declaration of TheoryFoo class is required. Kinds and functions for creating new expressions are only needed if you want the end-user of the CVC3 library to be able to create expressions from your theory and/or refer to their kinds directly. This is not always desirable. For instance, you may want to generate special terms or predicates that only make sense as temporary storage of information for your theory. The DARK_SHADOW and GRAY_SHADOW operators are good examples from the arithmetic theory. You have no clue what I'm talking about? That's right, you get it. \subsection theory_api_expr Kinds, Expressions, and Types The purpose of a new theory (or a decision procedure) is to extend the existing logic of CVC3 with new interpreted, and sometimes uninterpreted, operators and symbols. These new symbols comprise a signature of the theory, and it must be disjoint from the signatures of the other theories. In code, the new symbols and operators translate into new kinds of expressions. That is, new kinds and new values of the Expr class. A kind is a natural number which uniquely determines what sort of expression it is (variable, uninterpreted function symbol, specific operator like plus, minus, a type expression, etc.). Kinds are also used to define your theory's signature, and hence, they must be unique to your theory. In the simplest case, a kind represents the entire expression or type. Examples are simple types (like REAL and INT) and some constants (e.g. TRUE and FALSE). More typically, however, a kind represents an operator (PLUS, MINUS, ...), and children of an expression of that kind are the arguments of that operator. Finally, some kinds are used by more complex expressions with additional non-term attributes. For example, REC_LITERAL is used by record expressions { f1=e1, f2=e2, ... } whose children are the values of the fields (e1, e2, ...), and an additional attribute is the vector of field names: (f1, f2, ...). Other examples are quantifiers and lambda-terms. Such expressions require not only a new kind declaration, but also a special subclass of ExprValue (see below). \subsection theory_api_kind_decl Kind Declaration Kinds are declared as elements of an enum type (with doxygen comments): \verbatim //! Local kinds of TheoryFoo typedef enum { FOO_TYPE = 3500, //!< Type FOO for the elements of this theory BAR, //!< The binary (x | y) operator, where x,y: FOO BAZ, //!< Unary buzz(x) predicate BLEAH //!< An internal auxiliary term } FooKind; \endverbatim Notice, that the numbering in this example starts from 3500. This can be any integer which ensures that the new kinds do not clash with the existing kinds in other theories. Pick a random one, see if your kinds don't clash with others. You can check this either by inspecting src/include/kinds.h (the cental declaration of core kinds) and all the other theories, or compile and run cvc3 to see if you get an error message about kinds registered twice. The above type declaration of FooKind can be either in src/include/theory_foo.h (usually the best place), or in some header file in src/theory_foo/ directory, depending on whether you want to expose your kinds to the end library user or not. In the latter case, do not forget to add that header file to the HEADERS variable in your Makefile.in (see the \ref theory_api_config "previous section"). \subsection theory_api_kind_reg Kind Registration New kinds must be registered with the expression manager, which is done in your theory's constructor (see the \ref theory_api_methods "next section"). Registration is done by calling newKind() method of ExprManager for each kind: \verbatim getEM()->newKind(FOO_TYPE, "FOO"); getEM()->newKind(BAR, "||"); .... \endverbatim The string in the second argument is for printing the kind by the pretty-printer, and also for parsing, that is, turning a string back into a number (the kind). \subsection theory_api_expr_subclass New Expression Subclasses Sometimes an expression has a more complicated structure than a fixed operator with arguments, and more sophisticated data structures are necessary to represent it. CVC3 has an API for declaring and registering a new expression subclass just for that purpose. An expression subclass is a subclass of \ref ExprValue "ExprValue". You can declare it where appropriate in your theory files, using the same judgement as for the kinds. The new subclass needs to be registered with \c ExprManager by calling registerSubclass() method. A subclass of ExprValue must implement the following methods: \verbatim size_t computeHash() const; size_t getMMIndex() const; int isGeneric() const { return getMMIndex(); } bool isGeneric(int idx) const { return (idx == getMMIndex()); } // Syntactic equality of two expressions bool operator==(const ExprValue& ev2) const; // Make a clean copy of itself using the given memory manager ExprValue* copy(MemoryManager* mm, ExprIndex idx = 0); \endverbatim Also, each subclass must overload new() and delete() as follows: \verbatim void* operator new(size_t, MemoryManager* mm) { return mm->newData(); } void operator delete(void*) { } \endverbatim Subclasses may overload other virtual methods of ExprValue as needed. For instance, arity(), getKids(), ExprValueGenericAttr "getXXXAttr"(), etc. Some standard attribute access functions can also be overloaded, e.g. getString(), getRational(). However, you should not overload testers such as isRecord(), isVar() and such (unless you really know what you are doing), since the core relies on specific properties of the corresponding subclasses. For example, let us say that the auxiliary term BLEAH in TheoryFoo needs a string attribute, which is a part of expression, but is not a child (and not even a term in the logic), and an integer attribute which is not part of the expression (e.g. it is needed for marking expressions during the algorithm run). An example of a new subclass for this expression is the following: \verbatim class BleahExpr: public ExprValue { private: string d_str; //!< Data field; defines the value of expression int d_int; //!< An attribute size_t d_MMIndex; //!< The registration index for ExprManager public: //! Constructor BleahExpr(ExprManager* em, const string& str, size_t mmIndex, ExprIndex idx = 0) : ExprValue(em, ARRAY_VAR, idx), d_str(str), d_int(0), d_MMIndex(mmIndex) { } //! String attribute (part of expression) const std::string& getString() const { return d_str; } //! Integer attribute (not part of expression) int& getIntAttr(int idx) { return d_int; } size_t getIntAttrSize() const { return 1; } ExprValue* copy(MemoryManager* mm, ExprIndex idx = 0) const { return new(mm) BleahExpr(d_em, d_str, d_MMIndex, idx); } size_t computeHash() const { return PRIME*ExprValue::hash(BLEAH)+s_charHash(d_str.c_str()); } size_t getMMIndex() const { return d_MMIndex; } size_t isGeneric() const { return getMMIndex(); } bool isGeneric(size_t idx) const { return (idx == getMMIndex()); } // Only compare the string, not the integer attribute bool operator==(const ExprValue& ev2) const { if(ev2.getMMIndex() != d_MMIndex) return false; return (d_str == ev2.getString()); } void* operator new(size_t, MemoryManager* mm) { return mm->newData(); } void operator delete(void*) { } }; \endverbatim Registration of this subclass generates a memory manager index, which must be stored somewhere, usually in a class variable of TheoryFoo, say d_bleahIdx of type size_t. Registration in this case should be done in the constructor of TheoryFoo: \verbatim d_bleahIndex = getEM()->registerSubclass(sizeof(BleahExpr)); \endverbatim The approved and recommended way of creating expressions of BLEAH kind is the following: \verbatim Expr bleahExpr(const string& s) { BleahExpr av(d_em, s, d_BleahIndex); return newExpr(&av); } \endverbatim Using the new expression is now very easy: \verbatim Expr bleah = bleahExpr("cow moo"), b2 = bleahExpr("asdfqwerty"); bleah.getIntAttr(0) = 42; if(bleah != b2) cout << bleah.getString() << b2.getIntAttr(0) << endl; \endverbatim Note that it is impossible to define a non-member expression creation function for BleahExpr, since the memory manager index is stored in the class-local variable of TheoryFoo. And don't even think of using a static variable to work around this limitation. In general, you should NEVER store anything in a static variable, since it may violate thread-safety of the library. Before you ever think of using a static variable for anything, think what happens if someone creates two copies of the system (with two different sets of expression and memory managers). Is it safe to share this variable among several system instances? In the case of the memory manager index, the answer is definitely not. One possible fix for this problem is to bind the memory manager to the kind(s) that the subclass uses. Let us know if you really need this feature, and it will be implemented. \subsection theory_api_methods Constructor and API Methods The only constructor for your new theory should have the following declaration: \verbatim TheoryFoo(VCL* vcl); \endverbatim The constructor has to: - Initialize the base class, - Register new kinds and expression subclasses (if any) with ExprManager, - Collect the kinds which belong to the new theory in a vector, and register the theory (method registerTheory()) with these kinds, - Initialize theory-specific data structures, if needed. Here is a typical example of the constructor implementation: \verbatim TheoryFoo::TheoryFoo(VCL *vcl): Theory(vcl, "Foo") { d_rules = createProofRules(vcl); // instantiate our own rules // Register new local kinds with ExprManager getEM()->newKind(FOO_TYPE, "FOO"); getEM()->newKind(BAR, "||"); getEM()->newKind(BAZ, "BAZ"); getEM()->newKind(BLEAH, "BLEAH"); // Register our expression subclass d_bleahIndex = getEM()->registerSubclass(sizeof(BleahExpr)); vector kinds; kinds.push_back(FOO_TYPE); kinds.push_back(BAR); kinds.push_back(BAZ); kinds.push_back(BLEAH); registerTheory(this, kinds); } \endverbatim The following \ref theory_api "Theory API methods" are required in the subclass: \verbatim void assertFact(const Theorem& e); void checkSat(bool fullEffort); void computeType(const Expr& e); \endverbatim Other methods are optional, but often needed: \verbatim Theorem rewrite(const Expr& e); void setup(const Expr& e); void update(const Theorem& e, const Expr& d); ExprStream& print(ExprStream& os, const Expr& e); Expr parseExprOp(const Expr& e); \endverbatim Finally, a few other methods are rarely needed in practice: \verbatim void addSharedTerm(const Expr& e); Theorem solve(const Theorem& e); void notifyInconsistent(const Theorem& thm); Expr computeTCC(const Expr& e); \endverbatim The next section describes these API methods in more detail. You are also strongly encouraged to \ref theory_api "read the documentation" on each of these methods. \section theory_api_invars Theory API: The Very Important Invariants \subsection theory_api_flow High-Level Information Flow Every decision procedure communicates with the CVC3 Core interactively through several methods, most of which belong to the Theory class. Generally, those methods that your theory class re-implements carry information from the core, and others add new information generated in the DP to the core. Some methods (like rewrite() and solve()) return information through their return values. The chart below shows the flow of information to and from the decision procedure, and which parts of the core are responsible for collecting and generating it. Thick lines represent the most important methods, and dashed lines represent methods used only for very special occasions. \image html theory_api_flow.jpg \image latex theory_api_flow.eps "Flow of facts in CVC3" width=6in The most straightforward path of information, once it gets to the core through the external user input, is the following. First, all the relevant terms are typechecked (computeType() method). This method implements a step in the recursive typechecking algorithm, where the current expression is typechecked based on its structure and the types of its children. Typechecking of children is done by calling getType() or getBaseType(). The latter computes the largest supertype of the expression; for instance, the exact type of x may be a subrange 0..5, which is a subtype of INT, but its base type is REAL. Exact and base types are cached on expressions, and are computed on demand. An important property of computeType() is that it must not only compute the exact type of the expression, but also verify that all subexpressions are type-correct, relative to their base types. For instance, x = y has type BOOLEAN, and it is only type-correct if getBaseType(x) == getBaseType(y). If this property is violated, TypecheckException must be thrown with the appropriate message. Note, that the exact types of x and y may be different, and even disjoint. After the type checking, Type Correctness Conditions (TCCs) are generated and checked. TCC is a formula which is true if and only if any partial function in the original formula is used safely according to the Kleene semantics. That is, every partial function is either applied only to the arguments in its domain, or its value does not influence the value of the formula. TCCs are computed recursively by computeTCC() and getTCC() methods, very similar to computing the types. If your theory does not introduce partial functions explicitly (like division in arithmetic), then you do not need to re-implement computeTCC() in your theory; the default implementation will do the job. TCCs have a nice property that if they are true in the current context, then the corresponding user formulas can be safely interpreted by the total 2-valued models. Hence, computeTCC() is the only Theory API method that deals with partiality. All other methods consider any formula to be total (no partial functions) and 2-valued (only TRUE or FALSE, no undefined values. Once TCC has been proven valid in the current context, the new fact (formula) goes to the SAT solver, and if it is a literal (atomic formula or its negation), it is submitted to the decision procedure through assertFact(). The decision procedure processes this fact, updates its internal data structures, and possibly reports a contradiction (setInconsistent()) or new facts (enqueueFact(), and in special cases, enqueueEquality()). This completes the main loop of information flow. Note, that both enqueueFact() and setInconsistent() deliver information to the same place in the core, except that reporting the conflict bypasses the queue, and is taken care of immediately, rather than after all the previously enqueued facts are processed. This is the primary reason for having these two functions separated (as opposed to having only enqueueFact()). Inside this main loop, rewrite() and solve() are called to transform (or simplify) the facts before they reach the rest of the core. Normally, these functions do not have side-effects (except for caching results), and return new (simplified) facts through their return values. When the SAT solver runs out of facts, and the context is still satisfiable, it calls checkSat() with fullEffort==true. At this point, the decision procedure must determine whether all the information it has seen so far makes the context satisfiable or not w.r.t. its theory. Just like in the case of assertFact(), it may either report a contradiction, or enqueue a new fact. If any new fact is enqueued, it starts the main loop again. If checkSat() does not generate any new facts and does not find a contradiction, the core stops and reports the context to be satisfiable. Method checkSat() is also called every time the fact queue becomes empty, before the SAT solver asserts a new splitter. In this case, the fullEffort argument is set to false, and the decision procedure is not required to do anything. Many DPs, however, choose to perform some relatively inexpensive checks to detect inconsistencies and/or new facts, which increases performance. Similarly, if a new fact is enqueued, the main loop continues (without the SAT solver asserting new splitters) until the queue is empty. In CVC3, every term (non-formula expression) has a canonical representative in the union-find database. This database represents the equivalence classes of terms w.r.t. logical equality. All the terms in the formulas passing through the core are simplified by replacing them with their canonical representatives. Often, a decision procedure wants to be notified when a subexpression changes its canonical representative. For instance, if the DP has seen an term 2*x+3*y, and x has changed its representative to y+2, then it is important to conclude that 2*x+3*y == 2*(y+2) + 3*y == 5*y+4. For this purpose, the core maintains the notify list data structure, which is interfaced through setup() and update() methods. Every term in the core must be setup, and as a part of that process, the method setup() of the appropriate DP is called. Here the decision procedure has a chance to register notification requests related to the given expression. These requests are added to the notify lists of the relevant expressions using Expr::addToNotify() member method. Normally, a DP wants to be notified when immediate children of the expression change. For instance, for an expression 2*x, if the variable x changes, the arithmetic DP wants to be notified about it. Therefore, in the setup(2*x) call, it adds 2*x to the notify list of x by calling x.addToNotify(this, 2*x). The first argument (this) is the reference to the current Theory subclass. Later, when x changes its canonical representative, say, to y+2, its notify list is consulted, and the update(x==y+2, 2*x) call is made. The first argument is a directed equality informing the DP of what has changed, and the second is the expression for which this change is relevant. In this particular example, update() will enqueue a new fact: 2*x==2*y+4. Similarly, when 2*x+3*y is being setup, its immediate children (2*x and 3*y) get the entire expression added to their notify lists. Later, when 2*x changes its canonical representative to 2*y+4 due to the previous update() call, another update() call is made with 2*x==2*y+4 for 2*x+3*y, and a new fact is enqueued: 2*x+3*y==5*y+4, and so on. Note, that the notify list mechanism is not restricted to only immediate children. For instance, for high-degree monomials in non-linear arithmetics (e.g. x^2*y) it makes sense to register them with all factors (in this case, x, x^2, y, and x*y) which are not necessarily subexpressions of the original monomial (x^2*y). Finally, sometimes a decision procedure may want to know that the current context has become inconsistent, and this what notifyInconsistent() call is for. To date, only the quantifier theory uses it to find out which instantiations were useful in producing a conflict. Most likely, you do not need it. \subsection theory_api_backtrack Backtracking Data Structures Up to this point, the description assumed that new facts are always added to the current logical context, and never removed. This, of course, is not true in reality, since when a conflict is found, the SAT solver will backtrack, and restore the context to what it was before the assertion of a splitter. In particular, this means that each decision procedure needs to restore all its internal state to the same point. You may have noticed that there is no Theory API call to signal such backtracking. How the heck can a DP restore the state if it does not know when the core backtracks? The trick used in CVC3 is actually quite simple and elegant: DP does not have to know about backtracking, it indeed works under the assumption that facts can only be added to the context. However, all of its internal state must be stored in backtracking data structures, which backtrack automatically with the core. Such backtracking data structures are called context-dependent objects (CDO). There are currently three pre-defined context-dependent data structures: CDO (context-dependent object, cdo.h), CDList (backtracking stack, cdlist.h), and CDMap (backtracking map, similar to STL map, cdmap.h). Class CDO is a templated class for any C++ class which can be cleanly copied with operator=() and copy constructor, and which have the default constructor (this is how these objects are saved and restored on backtracking). CDO is best suited for individual variables (array indices, Expr or Theorem variables, etc.). Class CDList is a backtracking stack, and its API is very similar to that of STL vector. You can push_back() elements onto the stack, check the size() of the stack, and look up individual elements with operator[]. You cannot, however, modify or remove elements from the list. Keep in mind, that the size of the list may change between the API method calls, which means, you should keep any persistent indices to the list in backtracking variables (CDO). Class CDMap is a templated class very similar to STL map. You can add new key-value pairs to it, you can modify the value under a key, but you cannot remove a pair from the map. Let me repeat this again: all persistent data in a decision procedure MUST be stored in backtracking data structures! There are some rare exceptions to the rule (like storing the Expr representing the value "0" to avoid re-building it), but generally, you do not even want to know about backtracking. It is all done under the hood, and you should not care. \subsection theory_api_ileaves Variables and Foreign Terms (i-Leaves) Any subterm that your decision procedure cannot recognize must be treated as a variable. This is a very important point, and it may cause a long-lasting confusion for the beginning developers if not understood from the start. Read it carefully, several times, until you are sure you never forget it, even if I wake you up in the middle of the night. What CVC3 knows as a "variable" has nothing to do with what a decision procedure considers a "variable." These two are not very much related. A variable (or an i-leaf) from the DP point of view is either a CVC3 variable, or a shared term from some other theory. For instance, in 2*arr[idx]-3*y, the subterm arr[idx] belongs to the theory of arrays, and therefore, is a variable (an i-leaf) as far as the theory of arithmetic is concerned. Similarly, y is a variable in the theory of arithmetic, because it is also a CVC3 variable. Such a definition does not provide a direct test for an i-leaf. Instead, you have to check whether this term is one of "yours" (one that your theory knows about), which is usually determined by the expression kind. If not, then it is a variable, as far as your theory is concerned. But never make any assumptions about an i-leaf; it can be any expression whatsoever, and Expr::isVar() tester will not necessarily return true for it. In other words, there is no such thing as a variable in your theory. There are only terms you cannot recognize, which you treat as variables. \subsection theory_api_inputs Methods Reimplemented in a Subclass \subsection theory_api_assertFact assertFact() There are no tricky invariants for this method. The only important property is that all the facts that are submitted to the DP through this call become part of the logical context which the DP must check for satisfiability. Mathematically, the asserted fact \f$\phi\f$ is added to the logical context \f$\Gamma\f$, and the job of the decision procedure is to check whether \f$\Gamma\f$ is satisfiable or not; in other words, we are solving the problem \f$\Gamma\models\bot\f$. When the decision procedure receives a new fact \f$\phi\f$, it may either save this fact in its internal database for later processing, or may immediately process it, and possibly derive new facts \f$\{\psi_1,\ldots,\psi_k\}\f$ from \f$\phi\f$ and submit them back to the core (enqueueFact()). In the case when the set of derived facts is equisatisfiable with the original fact \f$\phi\f$, the decision procedure does not need to keep \f$\phi\f$ in its database; the completeness will still be preserved. For instance, if the DP receives r1=r2, where r1 and r2 are records with fields f1 and f2, then the two facts r1.f1=r2.f1 and r1.f2=r2.f2 (equalities of the individual fields) together are logically equivalent to the original fact r1=r2, and therefore, enqueuing them is sufficient for preserving completeness. The original fact need not be saved. \subsection theory_api_checkSat checkSat(bool fullEffort) The most important invariant (for completeness) is that when fullEffort is true, the DP must do all the work that it has postponed to find out if the current context is indeed satisfiable. In particular, if satisfiability can be achieved by making some of the shared terms equal, it must be done at this time (see \ref theory_api_addSharedTerm for more info on shared terms). This call is your last warning: if you do not act now, the whole system will stop and notify the user. However, the worst that can happen is that CVC3 becomes incomplete (it may report InValid when the query is actually valid). It still remains sound, however. That is, the Valid answer will still be correct. When fullEffort is false, the DP may choose to do as much or as little work as it wants. \subsection theory_api_setup setup() Add the given expression e to the notify list of all the expressions t1...tn whose change would affect the value of e. Normally, such expressions are the immediate children of e. Whenever the canonical representative of any ti changes in the union-find database, a corresponding call to update() will be made, and the DP will have a chance to re-process the expression e to keep it up-to-date. \subsection theory_api_update update() The property of this call is similar to assertFact(): the new fact becomes part of the logical context. However, the facts it receives do not necessarily belong to your theory, and are only reported because you asked the core to do so in setup(). Also, the new equalities that update() derives must be submitted through enqueueEquality() call. This also means that the right-hand side of the submitted equalities must be fully simplified. See \ref theory_api_enqueueEquality for more information. \subsection theory_api_addSharedTerm addSharedTerm() A term is called shared if it belongs to theory X, and appears as an i-leaf in a term from theory Y (that is, it's a Y-leaf). In this case, the term is shared by theories X and Y. For example, in 2*arr[idx]-3 the subterm arr[idx] belongs to the theory of arrays, but the entire term is an arithmetic expression; hence, arr[idx] is a shared term. When such a term appears in the system, the core notifies both theories about the term. Completeness of the CVC3 framework relies on the invariant that decision procedures propagate all the equalities between shared terms that can be derived in the current logical context. Often, the algorithms in DPs are designed to propagate all the equalities automatically (over all terms, including shared). In this case, addSharedTerm() need not be re-implemented. In some cases, however, the DP has to take extra effort to satisfy the above invariant, and it is more efficient to restrict this extra effort only to the set of shared terms. In this case, addSharedTerm() needs to collect the set of shared terms in a database (which, of course, has to be \ref theory_api_backtrack "backtrackable"), and use it in the checkSat() call. \subsection theory_api_rewrite rewrite(Expr e) This function must return a rewrite Theorem of the form e==e1 (or e<=>e1 if e is a formula), where e1 is a logically equivalent term or formula. This function can assume that all the immediate children of e are already completely simplified and rewritten. The same property must hold for the result of the rewrite. Another invariant that rewrite() has to preserve is that if the result of a rewrite is an equality (you return e<=>(e1==e2)), then in the resulting equality e1 >= e2 w.r.t. operator>=(Expr, Expr), the fixed total ordering on all expressions given by the expression manager. This invariant is important for termination of the simplifier, since equalities in CVC3 are used as (directed) rewrite rules, replacing the left-hand side (e1) with the right-hand side (e2). The core will call the rewrite() function iteratively on the right-hand side of the result, until the expression does not change. However, if the rewriting algorithm can guarantee that in a particular case no further rewrites from this theory will change the expression, the result can be flagged as a normal rewrite. In this case, the core will not call rewrite() again, resulting in better performance. The property that the expression indeed does not change with further rewrites is checked in the "debug" build, and any violation triggers assertion failures with ``Simplify Error 1'' and ``Simplify Error 2'' messages. It is important to understand that the iterative call to rewrite() only applies to the top-level node, and not to subexpressions. That is, if rewrite() changes the subexpressions (and not only the top-level operator), then it may violate another invariant that all the children of the result are completely rewritten and simplified. If this invariant cannot be guaranteed, then rewrite() needs to call simplifyThm() method explicitly. Here is an example of a rewrite function: \verbatim Theorem TheoryFoo::rewrite(const Expr& e) { Theorem res; if(isBar(e)) { res = reflexivityRule(e); res.getRHS().setRewriteNormal(); // No more rewrites needed } else { // May need to rewrite several times res = < do real work > } return res; } \endverbatim \subsection theory_api_solve solve(Theorem e) This method takes an equality e (as a Theorem object) and turns it into a logically equivalent solved form: a conjunction of fully simplified equalities, possibly existentially quantified. The terms on the left-hand sides cannot appear on any of the right-hand side terms, and every free variable in the solved form is also a free variable of e. (New variables in the solved form must be existentially quantified). According to Clark Barrett's Ph.D. thesis, only one theory is allowed to have a solver. In CVC3, such theory is the theory of arithmetic. The restriction to a single solver in CVC3 is somewhat relaxed, and several theories can have their own solvers, provided that the solved form that such a secondary solver generates is also a solved form w.r.t. the theory of arithmetic. This is the only asymmetric and non-local invariant in the core of Theory API. \subsection theory_api_computeType computeType() The basic CVC3 type checking mechanism is a simple recursive descent into the term structure, and it is implemented as a getType() method in the base Theory class. When computing a type of an expression e, this method determines which DP owns the expression, and calls the appropriate computeType() method, which is expected to check the expression for type consistency, and return the exact type of the expression. The return type is then cached as an attribute on the expression e for a fast look-up in the subsequent calls to getType(). Each decision procedure must implement computeType() method for all of its operators. For example, the theory of records has an operator for constructing record literals, for extracting a field of a record, and for updating a field of a record. This means that computeType() needs to be able to compute the types for these three operators, and verify that all subexpressions are of expected types. Since subtypes in CVC3 are handled by TCCs, type consistency at this stage is only checked with respect to the base types, which is returned by getBaseType() method provided by the base Theory class. For example, if a record expression e has a field foo of type INT, and the expression is a record update e WITH .foo := t, where t is of type REAL, then this expression is considered well-typed, since the base types of both INT and REAL is REAL. An important property of computeType() is that it must not only compute the exact type of the expression, but also verify that all subexpressions are type-correct, relative to their base types. For instance, x = y has type BOOLEAN, and it is only type-correct if getBaseType(x) == getBaseType(y). If this property is violated, TypecheckException must be thrown with the appropriate message. Note, that the exact types of x and y may be different, and even disjoint. \subsection theory_api_computeTCC computeTCC() Type Correctness Condition (TCC) for an expression e (which can be either a term or a formula) is a formula De such that De is true if and only if e is defined (or denoting) in the current logical context. For example, an expression x/y is undefined when y=0, and is defined otherwise. Therefore, \f$D_{x/y}\equiv y\ne 0\f$. \subsection theory_api_notifyInconsistent notifyInconsistent() \subsection theory_api_print print() The most important property of this method is that the printed expressions have to be parsable by the appropriate CVC3 parser. That is, CVC3 must be able to read what it prints. The recursive call to the global pretty-printer is implemented through the overloaded operator<< for ExprStream. Read the documentation on ExprStream class before coding. Once coded, test your printer code! Print all the kinds of expressions from your theory, make the expressions large and complex, interspersed with terms from other theories, etc. Make sure it both looks good, and CVC3 can read every term it prints. Here's an example of the print() method: \verbatim ExprStream& TheoryFoo::print(ExprStream& os, const Expr& e) { switch(os.lang()) { case PRESENTATION_LANG: switch(e.getKind()) { case ARROW: os << "[" << push << e[0] << space << "-> " << e[1] << push << "]"; break; case EQ: os << "(" << push << e[0] << space << "= " << e[1] << push << ")"; break; case NOT: os << "NOT " << e[0]; break; ................. default: // Print the top node in the default LISP format, continue with // pretty-printing for children. e.print(os); } break; // end of case PRESENTATION_LANGUAGE case INTERNAL_LANG: .................. break; // end of case INTERNAL_LANG default: // Print the top node in the default LISP format, continue with // pretty-printing for children. e.print(os); } return os; } \endverbatim \subsection theory_api_parseExprOp parseExprOp() This method is not used yet, and is likely to change in the near future. \subsection theory_api_outputs Methods Provided by Theory API The Theory API consists not only of methods to re-implement in the subclass, but it also provides convenient methods in the base class which subclasses can readily use. These methods subdivide into the following categories:
  • Methods for sending information to the core from a theory (a decision procedure),
  • \ref theory_api_core_proof_rules "Common proof rules",
  • Other convenient methods.
\subsection theory_api_enqueueFact enqueueFact() Normally, a decision procedure should use this and only this method for reporting newly derived facts back to the core. The only exception is a contradiction (a FALSE Theorem), which should be reported through setInconsistent() method for efficiency. Other exceptions include facts derived by the update() function, which may be reported through \ref theory_api_enqueueEquality. \subsection theory_api_setInconsistent setInconsistent() Similar to \ref theory_api_enqueueFact, except that it requires the new Theorem to be FALSE (a contradiction). This method is used for more efficient processing of the derived contradiction, bypassing the fact queue. \subsection theory_api_simplifyThm simplifyThm() and simplify() In rare cases, a decision procedure may want to simplify a given expression w.r.t. the current context, and this is the function to call. Be careful! This method may call your own \ref theory_api_rewrite method recursively. It is also a relatively expensive function to call, so avoid it if possible. \subsection theory_api_enqueueEquality enqueueEquality() This function can be used in \ref theory_api_update to propagate the equalities induced by the given equality e1==e2 as the argument to update(). In CVC3, equalities are treated as directional, meaning that left-hand side is always being replaced by the right-hand side. This means that if in the expression d there is a subexpression e1, then it must be replaced by e2. It also means that the resulting expression d2 must be reported to be equal to the original one as d==d2, and not the other way around. Since the core may occasionally swap equalities submitted through \ref theory_api_enqueueFact (for termination reasons), it is important to submit the above equality by-passing the swapping engine. This is where enqueueEquality() is useful. Invariant: enqueueEquality() expects the argument to be a Theorem of the form e1==e2, where e2 is a fully simplified expression in the current context. That is, e2 == simplify(e2). You are responsible for maintaining this invariant in your decision procedure. \subsection theory_api_inconsistentThm inconsistentThm() and inconsistent() If the context is inconsistent, the inconsistent() method returns true, and inconsistentThm() returns the Theorem of FALSE (a proof of the contradiction). \subsection theory_api_isTerm isTerm() Tests whether the given expression is a term (as opposed to a formula). \subsection theory_api_isLiteral isLiteral() Tests whether the given formula is a literal (is an atomic formula or its negation). \subsection theory_api_isAtomic isAtomic() Tests whether the given term or formula is atomic. In CVC3 it means that the expression does not contain formulas as subexpressions (for instance, as conditions in the IF-THEN-ELSE operator). This method is relatively expensive when called for the first time, but it caches the result in the Expr attributes, so the amortized complexity tends to be rather low. \subsection theory_api_updateHelper updateHelper() This method replaces all the immediate children of the given expression by their canonical representatives w.r.t. the union-find database, and returns the corresponding Theorem e==e1. This function is convenient to use inside \ref theory_api_update for rewriting d, the expression being updated. However, it only works when the changed subexpression in d is its immediate child. \subsection theory_api_getType getType() \subsection theory_api_getTCC getTCC() \subsection theory_api_parseExpr parseExpr() \section theory_api_proofs Proof Rules: The Trusted Core Every proven formula (or fact) in CVC3 appears in the form of a Theorem. Values of type Theorem have a special property: they cannot be constructed in any way but through the proof rules. This is implemented by making all the constructors of this class private. The only exception is the default constructor, which creates a null theorem, and it can only be used to create uninitialized variables of type Theorem, and assign them later. A proof rule is a function which takes premises (previously generated theorems) and other parameters, and generates a new theorem. The implementation of proof rules comprises the trusted core of CVC3, and the soundness of the tool relies entirely on the soundness of this core. In other words, no matter what the bulk of the code does, if CVC3 derives the validity of a particular fact, it is guaranteed that that theorem is indeed valid, provided the trusted implementation is correct and sound. For this reason, it is prudent to keep the trusted core reasonably small, and more importantly, keep each proof rule clean and simple, so that the correctness of the rule itself (mathematically) and its implementation can be easily verified by manual inspection. For the same reason, every rule must be thoroughly documented. It's a very good idea to include a LaTeX formula for the proof rule that a function implements. Keep in mind that reverse-engineering the mathematical meaning of a proof rule is a daunting task, especially if the code is rather long and complex. Check out src/include/common_proof_rules.h for examples. \subsection theory_api_proof_classes Hierarchy of Classes Like anything else in CVC3, there is an API for implementing proof rules defined by the class TheoremProducer. This class provides two protected methods, newTheorem() and newRWTheorem(), to its subclasses, which can create arbitrary Theorem values. Therefore, a part of the code is considered trusted whenever the file contains \#include "theorem_producer.h" statement in it. To enforce this, theorem_producer.h requires a macro symbol _CVC3_TRUSTED_ to be defined (otherwise, a compiler warning is generated). Important: the _CVC3_TRUSTED_ symbol must be defined only in *.cpp files, and never in *.h, to prevent accidental inclusion of theorem_producer.h, and thus, inadvertently making large portions of code trusted. Exporting the proof rules to the untrusted code (class TheoryFoo) is implemented through the custom API in foo_proof_rules.h (abstract class FooProofRules), whose pure methods are the proof rules. This header file does not include theorem_producer.h, and therefore, is suitable for inclusion by untrusted code. The implementation of FooProofRules consists of the implementation API: foo_theorem_producer.h (class FooTheoremProducer, inherits from FooProofRules and TheoremProducer), and the implementation proper in foo_theorem_producer.cpp. Normally, theorem_producer.h is included from foo_theorem_producer.h (to declare FooTheoremProducer as a subclass of TheoremProducer), and foo_theorem_producer.h is included from foo_theorem_producer.cpp: \verbatim // File foo_proof_rules.h class FooProofRules { .... }; \endverbatim \verbatim // File foo_theorem_producer.h #include "theorem_producer.h" class FooTheoremProducer: public FooProofRules, public TheoremProducer { .... }; \endverbatim \verbatim // File foo_theorem_producer.cpp #define _CVC3_TRUSTED_ #include "foo_theorem_producer.h" .... \endverbatim In order for the theory code to use the proof rules, a pointer to FooProofRules is declared in the TheoryFoo class: \verbatim // File theory_foo.h class FooProofRules; class TheoryFoo: public Theory { ...... FooProofRules* d_rules; //! Create an instance of FooProofRules class FooProofRules* createProofRules(VCL* vcl); ..... }; \endverbatim Since instantiating FooProofRules requires creating a new object of class FooTheoremProducer, which belongs to trusted part of the code, the implementation of createProofRules() method needs to be in foo_theorem_producer.cpp, rather than in theory_foo.cpp. This is the only exception to the rule that everything declared in a X.h file must be implemented in the corresponding X.cpp file in CVC3. \verbatim // File foo_theorem_producer.cpp ...... FooProofRules* TheoryFoo::createProofRules(VCL* vcl) { return new FooTheoremProducer(vcl); } ..... \endverbatim In the TheoryFoo() constructor, the class variable d_rules is initialized by calling createProofRules(): \verbatim // File theory_foo.cpp ..... TheoryFoo::TheoryFoo(VCL* vcl): Theory(vcl, "Foo") { ..... d_rules = createProofRules(vcl); ..... } // Destructor: destroy the proof rules class TheoryFoo::~TheoryFoo() { delete d_rules; } ..... \endverbatim \subsection theory_api_proof_rule Implementing a Proof Rule Each function implementing a proof rule has several components:
  • Soundness check(s),
  • The actual computation of the result,
  • Building assumptions,
  • Building a proof,
  • Constructing a new Theorem object.
There is a special macro CHECK_SOUND(cond, message) for checking the soundness conditions. If the condition cond does not evaluate to true, then a SoundException is thrown with the message string. For efficiency, the user may decide to skip the soundness checks. In order to honor this decision, all soundness checks must be supressed when the CHECK_PROOFS macro evaluates to false: \verbatim if(CHECK_PROOFS) { CHECK_SOUND(denominator != 0, "TheoryArith: Division rule: denominator == 0"); } \endverbatim Soundness checks play the most important role in making CVC3 sound. Your implementation must guarantee that if all soundness checks pass, then the rule is indeed sound to apply, and the theorem you generate at the end is indeed a theorem. Soundness checks include verifying that the premises (Theorems given as arguments) are of the expected format, and all the additional parameters satisfy all the side conditions of the proof rule. Soundness checks must be complete and self-sufficient (bullet-proof) within the rule; that is, no matter how the rule is called and with which arguments, there should be no way for the rule to generate an invalid theorem. Even if the untrusted code which calls the rule does all the necessary checks, you have to do them again inside the rule. This is the whole point of the code being trusted: it cannot go wrong, no matter what happens outside. In case of CVC3, this means that any non-null Theorem object represents a valid theorem, no matter how this theorem was generated. The main component of a Theorem object is a formula (returned by Theorem::getExpr()), which is valid in the appropriate logical context. The logical context is defined by the set of assumptions carried along in the Theorem object. Mathematically, a theorem object represents a sequent \f$\Gamma\vdash\phi\f$, where \f$\Gamma\f$ is the set of assumptions (formulas assumed to be true), and \f$\phi\f$ is the theorem itself, the formula which logically follows from \f$\Gamma\f$. Typically, an inference rule has the following format: \f[\frac{\Gamma_1\vdash\phi_1\quad\cdots\quad\Gamma_n\vdash\phi_n} {\Gamma_1,\ldots,\Gamma_n\vdash\psi}\f] where the assumptions of the conclusion are the union of all the assumptions from the premises. The easiest way to compute the set of assumptions for the conclusion is to use the overloaded method merge() provided by the theorem.h API. This way you do not have to bother about the internal representation of assumptions. Keep in mind, that CVC3 may be running in the mode without assumptions (for efficiency), which can be queried by withAssumptions() method: \verbatim Theorem fooRule(const Theorem& prem1, const Theorem& prem2) { ..... Assumptions a; if(withAssumptions()) a = merge(prem1, prem2); .... } \endverbatim If the rule accepts more than two premises, you can merge assumptions by passing the vector of all premises to the merge() method. When there is only one premis, the simplest way is to make a clean copy of the assumptions from the premis: \verbatim if(withAssumptions()) a = premis.getAssumptionsCopy(); \endverbatim Occasionally, one needs to remove assumptions from the set, as in the following rule: \f[\frac{\Gamma_1\vdash\alpha\quad \Gamma_2, \alpha\vdash\phi} {\Gamma_1, \Gamma_2\vdash\phi}\mbox{Cut}\f] In this case, you can use the overloaded operator-() for class Assumptions: \verbatim Theorem cutRule(const Theorem& alpha, const Theorem& phi) { ..... Assumptions a; if(withAssumptions()) a = (phi.getAssumptions() - alpha.getExpr()) + alpha.getAssumptions(); .... } \endverbatim Remember, however, that due to the internal representation used in CVC3, removing an assumption is quite expensive, while merging is very cheap. Also, if the soundness of your rule relies on the presence (or absence) of certain assumptions in premises, the first thing you need to check for is that withAssumptions() returns true (otherwise there is no way to determine the soundness of the rule, so it should not be called in the mode without assumptions). In the above rule, if the assumption \f$\alpha\f$ were required to be present for soundness of the rule, one could check it as follows: \verbatim const Expr& alphaExpr = alpha.getExpr(); const Assumptions& phiAssump = phi.getAssumptionsRef(); if(CHECK_PROOFS) { CHECK_SOUND(withAssumptions(), "TheoryFoo::cutRule: called without assumptions!"); CHECK_SOUND(!phiAssump[alphaExpr].isNull(), "TheoryFoo::cutRule: alpha is not an assumption of phi"); } \endverbatim It is extremely important that assumptions are computed correctly when withAssumptions() returns true, since assumptions are used by the SAT solver in the core framework, and are absolutely crucial for the results to be correct (or sound). Remember, that assumptions represent the logical context where the theorem is true, and if they are not computed properly, the entire theorem may become invalid. Each Theorem object carries a proof of itself in the form of a Proof object. Proofs are relatively expensive to generate (they take up extra space and somewhat slow down the rule execution), and therefore, it is the user's privilege to turn them off. For this reason, all proof generation code must be guarded by the method withProof(), similarly to withAssumptions(). CVC3 uses a version of Natural Deduction as its logical basis, and exploits the idea of Curry-Howard isomorphism to represent proofs as terms over function symbols representing proof rules. A ``type'' of a proof term is the formula (theorem) derived by the corresponding proof. The correctness of a proof in this framework corresponds to the proof term being ``well-typed.'' The TheoremProducer API provides an overloaded method newPf() for building proof terms. The first argument of (almost) any newPf() version is the name of the proof rule (string), and the rest are the arguments (parameters as Expr values, and the proofs of the rule's premises). The key idea in building a proof term for the rule is to provide enough information in the proof term to be able to re-run the rule again with exactly the same arguments. For instance, a proof term for the following rule: \f[\frac{\Gamma_1\vdash x < y \quad \Gamma_2\vdash y < z} {\Gamma_1, \Gamma_2\vdash x < z}\mbox{project} \f] can be constructed as follows: \verbatim Theorem projectRule(const Theorem& xLTy, const Theorem& yLTz) { ..... Proof pf; if(withProof()) { vector exprs; vector pfs; exprs.push_back(xLTy.getExpr()); exprs.push_back(yLTz.getExpr()); pfs.push_back(xLTy.getProof()); pfs.push_back(yLTz.getProof()); pf = newPf("project", exprs, pfs); } ..... } \endverbatim It is a very good idea to describe the proof object arguments in the proof rule documentation (doxygen comments) in foo_proof_rules.h file. Note, that the proof object does not carry around any information about the assumptions. This is because all the assumptions are present implicitly as ``types'' of bound proof variables in LAMBDA-terms. I skip the description of this issue in the current version of this document, as it is rather subtle, and there is a 99\% chance that you do not need to know that for your DP. Finally, creating the resulting theorem in the proof rule is usually done by calling newTheorem(conclusionExpr, a, pf), where a is the Assumptions variable, and pf is the proof term. There is a special class of proof rules called rewrite rules in CVC3. These are proof rules without premises (axioms) whose conclusion is of the form expr1 = expr2 or frm1 <=> frm2. These rules are so ubiquitous in the system that there is a special optimized constructor for the corresponding theorems: newRWTheorem(expr1, expr2, a, pf). Note: the Theorem object constructed by the rewrite rule has a different internal representation from the "normal" Theorem object. Therefore, constructing a rewrite theorem with newTheorem(expr1.eqExpr(expr2), a, pf) will result in a run-time error. Make sure that if your theorem is a rewrite theorem (an equality = or equivalence <=>), then it must be constructed using the newRWTheorem() method. I did not mention anything about computing the expression for the conclusion of the rule, but it should be fairly obvious how to do this. Remember, that each proof rule should be coded as concisely and as cleanly as possible, to ensure the effectiveness of manual inspection. Remember, this is a trusted part of the code. Keep It Simple, Stupid. :-) Sergey Berezin / berezin AT stanford DOT edu */ cvc3-2.4.1/doc/mainpage.dox0000664000175400017540000000057310642515211015322 0ustar mdetersmdeters/*! \mainpage CVC3 Documentation User's Manual: - \ref user_doc Documentation Files From the Source Code Distribution: - \ref README - \ref LICENSE - \ref INSTALL Go back to the CVC3 Home Page
*/ cvc3-2.4.1/doc/Makefile.in0000664000175400017540000000105010542124112015054 0ustar mdetersmdetersDOXYGEN=@DOXYGEN@ # DOXYTAG=@DOXYTAG@ FIG=theory_api_flow.fig JPG=$(patsubst %.fig, %.jpg, $(FIG)) EPS=$(patsubst %.fig, %.eps, $(FIG)) all: doc doc: $(JPG) $(EPS) ifdef DOXYGEN $(DOXYGEN) Doxyfile # ifdef DOXYTAG # cd html; $(DOXYTAG) -s search.idx # endif else @echo "doxygen is not configured; no documentation will be generated" endif %.jpg: %.fig @FIG2DEV@ -L jpeg $< $@ %.eps: %.fig @FIG2DEV@ -L eps $< $@ install: @echo "Sorry, Docs installation is not implemented yet" distclean: @rm -f Doxyfile *.eps *.jpg Makefile @rm -rf html cvc3-2.4.1/doc/devel.dox0000664000175400017540000000025410466450544014647 0ustar mdetersmdeters/*! \page devel_doc The CVC Development Environment

Coding Guidelines

Documentation Guidelines

Compilation scripts

Regressions

*/ cvc3-2.4.1/doc/Doxyfile.in0000664000175400017540000014653211301577136015155 0ustar mdetersmdeters# Doxyfile 1.5.2 # This file describes the settings to be used by the documentation system # doxygen (www.doxygen.org) for a project # # All text after a hash (#) is considered a comment and will be ignored # The format is: # TAG = value [value, ...] # For lists items can also be appended using: # TAG += value [value, ...] # Values that contain spaces should be placed between quotes (" ") #--------------------------------------------------------------------------- # Project related configuration options #--------------------------------------------------------------------------- # This tag specifies the encoding used for all characters in the config file that # follow. The default is UTF-8 which is also the encoding used for all text before # the first occurrence of this tag. Doxygen uses libiconv (or the iconv built into # libc) for the transcoding. See http://www.gnu.org/software/libiconv for the list of # possible encodings. DOXYFILE_ENCODING = UTF-8 # The PROJECT_NAME tag is a single word (or a sequence of words surrounded # by quotes) that should identify the project. PROJECT_NAME = CVC3 # The PROJECT_NUMBER tag can be used to enter a project or revision number. # This could be handy for archiving the generated documentation or # if some version control system is used. PROJECT_NUMBER = # The OUTPUT_DIRECTORY tag is used to specify the (relative or absolute) # base path where the generated documentation will be put. # If a relative path is entered, it will be relative to the location # where doxygen was started. If left blank the current directory will be used. OUTPUT_DIRECTORY = # If the CREATE_SUBDIRS tag is set to YES, then doxygen will create # 4096 sub-directories (in 2 levels) under the output directory of each output # format and will distribute the generated files over these directories. # Enabling this option can be useful when feeding doxygen a huge amount of # source files, where putting all generated files in the same directory would # otherwise cause performance problems for the file system. CREATE_SUBDIRS = NO # The OUTPUT_LANGUAGE tag is used to specify the language in which all # documentation generated by doxygen is written. Doxygen will use this # information to generate all constant output in the proper language. # The default language is English, other supported languages are: # Afrikaans, Arabic, Brazilian, Catalan, Chinese, Chinese-Traditional, # Croatian, Czech, Danish, Dutch, Finnish, French, German, Greek, Hungarian, # Italian, Japanese, Japanese-en (Japanese with English messages), Korean, # Korean-en, Lithuanian, Norwegian, Polish, Portuguese, Romanian, Russian, # Serbian, Slovak, Slovene, Spanish, Swedish, and Ukrainian. OUTPUT_LANGUAGE = English # If the BRIEF_MEMBER_DESC tag is set to YES (the default) Doxygen will # include brief member descriptions after the members that are listed in # the file and class documentation (similar to JavaDoc). # Set to NO to disable this. BRIEF_MEMBER_DESC = YES # If the REPEAT_BRIEF tag is set to YES (the default) Doxygen will prepend # the brief description of a member or function before the detailed description. # Note: if both HIDE_UNDOC_MEMBERS and BRIEF_MEMBER_DESC are set to NO, the # brief descriptions will be completely suppressed. REPEAT_BRIEF = YES # This tag implements a quasi-intelligent brief description abbreviator # that is used to form the text in various listings. Each string # in this list, if found as the leading text of the brief description, will be # stripped from the text and the result after processing the whole list, is # used as the annotated text. Otherwise, the brief description is used as-is. # If left blank, the following values are used ("$name" is automatically # replaced with the name of the entity): "The $name class" "The $name widget" # "The $name file" "is" "provides" "specifies" "contains" # "represents" "a" "an" "the" ABBREVIATE_BRIEF = # If the ALWAYS_DETAILED_SEC and REPEAT_BRIEF tags are both set to YES then # Doxygen will generate a detailed section even if there is only a brief # description. ALWAYS_DETAILED_SEC = NO # If the INLINE_INHERITED_MEMB tag is set to YES, doxygen will show all # inherited members of a class in the documentation of that class as if those # members were ordinary class members. Constructors, destructors and assignment # operators of the base classes will not be shown. INLINE_INHERITED_MEMB = NO # If the FULL_PATH_NAMES tag is set to YES then Doxygen will prepend the full # path before files name in the file list and in the header files. If set # to NO the shortest path that makes the file name unique will be used. FULL_PATH_NAMES = NO # If the FULL_PATH_NAMES tag is set to YES then the STRIP_FROM_PATH tag # can be used to strip a user-defined part of the path. Stripping is # only done if one of the specified strings matches the left-hand part of # the path. The tag can be used to show relative paths in the file list. # If left blank the directory from which doxygen is run is used as the # path to strip. STRIP_FROM_PATH = # The STRIP_FROM_INC_PATH tag can be used to strip a user-defined part of # the path mentioned in the documentation of a class, which tells # the reader which header file to include in order to use a class. # If left blank only the name of the header file containing the class # definition is used. Otherwise one should specify the include paths that # are normally passed to the compiler using the -I flag. STRIP_FROM_INC_PATH = # If the SHORT_NAMES tag is set to YES, doxygen will generate much shorter # (but less readable) file names. This can be useful is your file systems # doesn't support long names like on DOS, Mac, or CD-ROM. SHORT_NAMES = NO # If the JAVADOC_AUTOBRIEF tag is set to YES then Doxygen # will interpret the first line (until the first dot) of a JavaDoc-style # comment as the brief description. If set to NO, the JavaDoc # comments will behave just like the Qt-style comments (thus requiring an # explicit @brief command for a brief description. JAVADOC_AUTOBRIEF = NO # The MULTILINE_CPP_IS_BRIEF tag can be set to YES to make Doxygen # treat a multi-line C++ special comment block (i.e. a block of //! or /// # comments) as a brief description. This used to be the default behaviour. # The new default is to treat a multi-line C++ comment block as a detailed # description. Set this tag to YES if you prefer the old behaviour instead. MULTILINE_CPP_IS_BRIEF = NO # If the DETAILS_AT_TOP tag is set to YES then Doxygen # will output the detailed description near the top, like JavaDoc. # If set to NO, the detailed description appears after the member # documentation. DETAILS_AT_TOP = NO # If the INHERIT_DOCS tag is set to YES (the default) then an undocumented # member inherits the documentation from any documented member that it # re-implements. INHERIT_DOCS = YES # If the SEPARATE_MEMBER_PAGES tag is set to YES, then doxygen will produce # a new page for each member. If set to NO, the documentation of a member will # be part of the file/class/namespace that contains it. SEPARATE_MEMBER_PAGES = NO # The TAB_SIZE tag can be used to set the number of spaces in a tab. # Doxygen uses this value to replace tabs by spaces in code fragments. TAB_SIZE = 2 # This tag can be used to specify a number of aliases that acts # as commands in the documentation. An alias has the form "name=value". # For example adding "sideeffect=\par Side Effects:\n" will allow you to # put the command \sideeffect (or @sideeffect) in the documentation, which # will result in a user-defined paragraph with heading "Side Effects:". # You can put \n's in the value part of an alias to insert newlines. ALIASES = # Set the OPTIMIZE_OUTPUT_FOR_C tag to YES if your project consists of C # sources only. Doxygen will then generate output that is more tailored for C. # For instance, some of the names that are used will be different. The list # of all members will be omitted, etc. OPTIMIZE_OUTPUT_FOR_C = NO # Set the OPTIMIZE_OUTPUT_JAVA tag to YES if your project consists of Java # sources only. Doxygen will then generate output that is more tailored for Java. # For instance, namespaces will be presented as packages, qualified scopes # will look different, etc. OPTIMIZE_OUTPUT_JAVA = NO # If you use STL classes (i.e. std::string, std::vector, etc.) but do not want to # include (a tag file for) the STL sources as input, then you should # set this tag to YES in order to let doxygen match functions declarations and # definitions whose arguments contain STL classes (e.g. func(std::string); v.s. # func(std::string) {}). This also make the inheritance and collaboration # diagrams that involve STL classes more complete and accurate. BUILTIN_STL_SUPPORT = YES # If you use Microsoft's C++/CLI language, you should set this option to YES to # enable parsing support. CPP_CLI_SUPPORT = NO # If member grouping is used in the documentation and the DISTRIBUTE_GROUP_DOC # tag is set to YES, then doxygen will reuse the documentation of the first # member in the group (if any) for the other members of the group. By default # all members of a group must be documented explicitly. DISTRIBUTE_GROUP_DOC = YES # Set the SUBGROUPING tag to YES (the default) to allow class member groups of # the same type (for instance a group of public functions) to be put as a # subgroup of that type (e.g. under the Public Functions section). Set it to # NO to prevent subgrouping. Alternatively, this can be done per class using # the \nosubgrouping command. SUBGROUPING = YES #--------------------------------------------------------------------------- # Build related configuration options #--------------------------------------------------------------------------- # If the EXTRACT_ALL tag is set to YES doxygen will assume all entities in # documentation are documented, even if no documentation was available. # Private class members and static file members will be hidden unless # the EXTRACT_PRIVATE and EXTRACT_STATIC tags are set to YES EXTRACT_ALL = YES # If the EXTRACT_PRIVATE tag is set to YES all private members of a class # will be included in the documentation. EXTRACT_PRIVATE = YES # If the EXTRACT_STATIC tag is set to YES all static members of a file # will be included in the documentation. EXTRACT_STATIC = YES # If the EXTRACT_LOCAL_CLASSES tag is set to YES classes (and structs) # defined locally in source files will be included in the documentation. # If set to NO only classes defined in header files are included. EXTRACT_LOCAL_CLASSES = YES # This flag is only useful for Objective-C code. When set to YES local # methods, which are defined in the implementation section but not in # the interface are included in the documentation. # If set to NO (the default) only methods in the interface are included. EXTRACT_LOCAL_METHODS = NO # If the HIDE_UNDOC_MEMBERS tag is set to YES, Doxygen will hide all # undocumented members of documented classes, files or namespaces. # If set to NO (the default) these members will be included in the # various overviews, but no documentation section is generated. # This option has no effect if EXTRACT_ALL is enabled. HIDE_UNDOC_MEMBERS = NO # If the HIDE_UNDOC_CLASSES tag is set to YES, Doxygen will hide all # undocumented classes that are normally visible in the class hierarchy. # If set to NO (the default) these classes will be included in the various # overviews. This option has no effect if EXTRACT_ALL is enabled. HIDE_UNDOC_CLASSES = NO # If the HIDE_FRIEND_COMPOUNDS tag is set to YES, Doxygen will hide all # friend (class|struct|union) declarations. # If set to NO (the default) these declarations will be included in the # documentation. HIDE_FRIEND_COMPOUNDS = NO # If the HIDE_IN_BODY_DOCS tag is set to YES, Doxygen will hide any # documentation blocks found inside the body of a function. # If set to NO (the default) these blocks will be appended to the # function's detailed documentation block. HIDE_IN_BODY_DOCS = NO # The INTERNAL_DOCS tag determines if documentation # that is typed after a \internal command is included. If the tag is set # to NO (the default) then the documentation will be excluded. # Set it to YES to include the internal documentation. INTERNAL_DOCS = NO # If the CASE_SENSE_NAMES tag is set to NO then Doxygen will only generate # file names in lower-case letters. If set to YES upper-case letters are also # allowed. This is useful if you have classes or files whose names only differ # in case and if your file system supports case sensitive file names. Windows # and Mac users are advised to set this option to NO. CASE_SENSE_NAMES = YES # If the HIDE_SCOPE_NAMES tag is set to NO (the default) then Doxygen # will show members with their full class and namespace scopes in the # documentation. If set to YES the scope will be hidden. HIDE_SCOPE_NAMES = NO # If the SHOW_INCLUDE_FILES tag is set to YES (the default) then Doxygen # will put a list of the files that are included by a file in the documentation # of that file. SHOW_INCLUDE_FILES = YES # If the INLINE_INFO tag is set to YES (the default) then a tag [inline] # is inserted in the documentation for inline members. INLINE_INFO = YES # If the SORT_MEMBER_DOCS tag is set to YES (the default) then doxygen # will sort the (detailed) documentation of file and class members # alphabetically by member name. If set to NO the members will appear in # declaration order. SORT_MEMBER_DOCS = NO # If the SORT_BRIEF_DOCS tag is set to YES then doxygen will sort the # brief documentation of file, namespace and class members alphabetically # by member name. If set to NO (the default) the members will appear in # declaration order. SORT_BRIEF_DOCS = NO # If the SORT_BY_SCOPE_NAME tag is set to YES, the class list will be # sorted by fully-qualified names, including namespaces. If set to # NO (the default), the class list will be sorted only by class name, # not including the namespace part. # Note: This option is not very useful if HIDE_SCOPE_NAMES is set to YES. # Note: This option applies only to the class list, not to the # alphabetical list. SORT_BY_SCOPE_NAME = NO # The GENERATE_TODOLIST tag can be used to enable (YES) or # disable (NO) the todo list. This list is created by putting \todo # commands in the documentation. GENERATE_TODOLIST = YES # The GENERATE_TESTLIST tag can be used to enable (YES) or # disable (NO) the test list. This list is created by putting \test # commands in the documentation. GENERATE_TESTLIST = YES # The GENERATE_BUGLIST tag can be used to enable (YES) or # disable (NO) the bug list. This list is created by putting \bug # commands in the documentation. GENERATE_BUGLIST = YES # The GENERATE_DEPRECATEDLIST tag can be used to enable (YES) or # disable (NO) the deprecated list. This list is created by putting # \deprecated commands in the documentation. GENERATE_DEPRECATEDLIST= YES # The ENABLED_SECTIONS tag can be used to enable conditional # documentation sections, marked by \if sectionname ... \endif. ENABLED_SECTIONS = # The MAX_INITIALIZER_LINES tag determines the maximum number of lines # the initial value of a variable or define consists of for it to appear in # the documentation. If the initializer consists of more lines than specified # here it will be hidden. Use a value of 0 to hide initializers completely. # The appearance of the initializer of individual variables and defines in the # documentation can be controlled using \showinitializer or \hideinitializer # command in the documentation regardless of this setting. MAX_INITIALIZER_LINES = 30 # Set the SHOW_USED_FILES tag to NO to disable the list of files generated # at the bottom of the documentation of classes and structs. If set to YES the # list will mention the files that were used to generate the documentation. SHOW_USED_FILES = YES # If the sources in your project are distributed over multiple directories # then setting the SHOW_DIRECTORIES tag to YES will show the directory hierarchy # in the documentation. The default is NO. SHOW_DIRECTORIES = NO # The FILE_VERSION_FILTER tag can be used to specify a program or script that # doxygen should invoke to get the current version for each file (typically from the # version control system). Doxygen will invoke the program by executing (via # popen()) the command , where is the value of # the FILE_VERSION_FILTER tag, and is the name of an input file # provided by doxygen. Whatever the program writes to standard output # is used as the file version. See the manual for examples. FILE_VERSION_FILTER = #--------------------------------------------------------------------------- # configuration options related to warning and progress messages #--------------------------------------------------------------------------- # The QUIET tag can be used to turn on/off the messages that are generated # by doxygen. Possible values are YES and NO. If left blank NO is used. QUIET = NO # The WARNINGS tag can be used to turn on/off the warning messages that are # generated by doxygen. Possible values are YES and NO. If left blank # NO is used. WARNINGS = YES # If WARN_IF_UNDOCUMENTED is set to YES, then doxygen will generate warnings # for undocumented members. If EXTRACT_ALL is set to YES then this flag will # automatically be disabled. WARN_IF_UNDOCUMENTED = YES # If WARN_IF_DOC_ERROR is set to YES, doxygen will generate warnings for # potential errors in the documentation, such as not documenting some # parameters in a documented function, or documenting parameters that # don't exist or using markup commands wrongly. WARN_IF_DOC_ERROR = YES # This WARN_NO_PARAMDOC option can be abled to get warnings for # functions that are documented, but have no documentation for their parameters # or return value. If set to NO (the default) doxygen will only warn about # wrong or incomplete parameter documentation, but not about the absence of # documentation. WARN_NO_PARAMDOC = NO # The WARN_FORMAT tag determines the format of the warning messages that # doxygen can produce. The string should contain the $file, $line, and $text # tags, which will be replaced by the file and line number from which the # warning originated and the warning text. Optionally the format may contain # $version, which will be replaced by the version of the file (if it could # be obtained via FILE_VERSION_FILTER) WARN_FORMAT = "$file:$line: $text" # The WARN_LOGFILE tag can be used to specify a file to which warning # and error messages should be written. If left blank the output is written # to stderr. WARN_LOGFILE = #--------------------------------------------------------------------------- # configuration options related to the input files #--------------------------------------------------------------------------- # The INPUT tag can be used to specify the files and/or directories that contain # documented source files. You may enter file names like "myfile.cpp" or # directories like "/usr/src/myproject". Separate the files or directories # with spaces. INPUT = . \ ../src \ ../README \ ../LICENSE \ ../INSTALL # \ # ../windows/README \ # ../windows/INSTALL # This tag can be used to specify the character encoding of the source files that # doxygen parses. Internally doxygen uses the UTF-8 encoding, which is also the default # input encoding. Doxygen uses libiconv (or the iconv built into libc) for the transcoding. # See http://www.gnu.org/software/libiconv for the list of possible encodings. INPUT_ENCODING = UTF-8 # If the value of the INPUT tag contains directories, you can use the # FILE_PATTERNS tag to specify one or more wildcard pattern (like *.cpp # and *.h) to filter out the source-files in the directories. If left # blank the following patterns are tested: # *.c *.cc *.cxx *.cpp *.c++ *.java *.ii *.ixx *.ipp *.i++ *.inl *.h *.hh *.hxx # *.hpp *.h++ *.idl *.odl *.cs *.php *.php3 *.inc *.m *.mm *.py FILE_PATTERNS = *.h \ *.cpp \ *.dox # The RECURSIVE tag can be used to turn specify whether or not subdirectories # should be searched for input files as well. Possible values are YES and NO. # If left blank NO is used. RECURSIVE = YES # The EXCLUDE tag can be used to specify files and/or directories that should # excluded from the INPUT source files. This way you can easily exclude a # subdirectory from a directory tree whose root is specified with the INPUT tag. EXCLUDE = devel.dox \ theory_api.dox # The EXCLUDE_SYMLINKS tag can be used select whether or not files or # directories that are symbolic links (a Unix filesystem feature) are excluded # from the input. EXCLUDE_SYMLINKS = NO # If the value of the INPUT tag contains directories, you can use the # EXCLUDE_PATTERNS tag to specify one or more wildcard patterns to exclude # certain files from those directories. Note that the wildcards are matched # against the file with absolute path, so to exclude all test directories # for example use the pattern */test/* EXCLUDE_PATTERNS = parse*.cpp \ parse*_defs.h \ lex*.cpp \ c_interface*.* # The EXCLUDE_SYMBOLS tag can be used to specify one or more symbol names # (namespaces, classes, functions, etc.) that should be excluded from the output. # The symbol name can be a fully qualified name, a word, or if the wildcard * is used, # a substring. Examples: ANamespace, AClass, AClass::ANamespace, ANamespace::*Test EXCLUDE_SYMBOLS = # The EXAMPLE_PATH tag can be used to specify one or more files or # directories that contain example code fragments that are included (see # the \include command). EXAMPLE_PATH = # If the value of the EXAMPLE_PATH tag contains directories, you can use the # EXAMPLE_PATTERNS tag to specify one or more wildcard pattern (like *.cpp # and *.h) to filter out the source-files in the directories. If left # blank all files are included. EXAMPLE_PATTERNS = # If the EXAMPLE_RECURSIVE tag is set to YES then subdirectories will be # searched for input files to be used with the \include or \dontinclude # commands irrespective of the value of the RECURSIVE tag. # Possible values are YES and NO. If left blank NO is used. EXAMPLE_RECURSIVE = NO # The IMAGE_PATH tag can be used to specify one or more files or # directories that contain image that are included in the documentation (see # the \image command). IMAGE_PATH = @TOP@/doc # The INPUT_FILTER tag can be used to specify a program that doxygen should # invoke to filter for each input file. Doxygen will invoke the filter program # by executing (via popen()) the command , where # is the value of the INPUT_FILTER tag, and is the name of an # input file. Doxygen will then use the output that the filter program writes # to standard output. If FILTER_PATTERNS is specified, this tag will be # ignored. INPUT_FILTER = # The FILTER_PATTERNS tag can be used to specify filters on a per file pattern # basis. Doxygen will compare the file name with each pattern and apply the # filter if there is a match. The filters are a list of the form: # pattern=filter (like *.cpp=my_cpp_filter). See INPUT_FILTER for further # info on how filters are used. If FILTER_PATTERNS is empty, INPUT_FILTER # is applied to all files. FILTER_PATTERNS = # If the FILTER_SOURCE_FILES tag is set to YES, the input filter (if set using # INPUT_FILTER) will be used to filter the input files when producing source # files to browse (i.e. when SOURCE_BROWSER is set to YES). FILTER_SOURCE_FILES = NO #--------------------------------------------------------------------------- # configuration options related to source browsing #--------------------------------------------------------------------------- # If the SOURCE_BROWSER tag is set to YES then a list of source files will # be generated. Documented entities will be cross-referenced with these sources. # Note: To get rid of all source code in the generated output, make sure also # VERBATIM_HEADERS is set to NO. SOURCE_BROWSER = YES # Setting the INLINE_SOURCES tag to YES will include the body # of functions and classes directly in the documentation. INLINE_SOURCES = NO # Setting the STRIP_CODE_COMMENTS tag to YES (the default) will instruct # doxygen to hide any special comment blocks from generated source code # fragments. Normal C and C++ comments will always remain visible. STRIP_CODE_COMMENTS = NO # If the REFERENCED_BY_RELATION tag is set to YES (the default) # then for each documented function all documented # functions referencing it will be listed. REFERENCED_BY_RELATION = YES # If the REFERENCES_RELATION tag is set to YES (the default) # then for each documented function all documented entities # called/used by that function will be listed. REFERENCES_RELATION = YES # If the REFERENCES_LINK_SOURCE tag is set to YES (the default) # and SOURCE_BROWSER tag is set to YES, then the hyperlinks from # functions in REFERENCES_RELATION and REFERENCED_BY_RELATION lists will # link to the source code. Otherwise they will link to the documentstion. REFERENCES_LINK_SOURCE = YES # If the USE_HTAGS tag is set to YES then the references to source code # will point to the HTML generated by the htags(1) tool instead of doxygen # built-in source browser. The htags tool is part of GNU's global source # tagging system (see http://www.gnu.org/software/global/global.html). You # will need version 4.8.6 or higher. USE_HTAGS = NO # If the VERBATIM_HEADERS tag is set to YES (the default) then Doxygen # will generate a verbatim copy of the header file for each class for # which an include is specified. Set to NO to disable this. VERBATIM_HEADERS = YES #--------------------------------------------------------------------------- # configuration options related to the alphabetical class index #--------------------------------------------------------------------------- # If the ALPHABETICAL_INDEX tag is set to YES, an alphabetical index # of all compounds will be generated. Enable this if the project # contains a lot of classes, structs, unions or interfaces. ALPHABETICAL_INDEX = YES # If the alphabetical index is enabled (see ALPHABETICAL_INDEX) then # the COLS_IN_ALPHA_INDEX tag can be used to specify the number of columns # in which this list will be split (can be a number in the range [1..20]) COLS_IN_ALPHA_INDEX = 5 # In case all classes in a project start with a common prefix, all # classes will be put under the same header in the alphabetical index. # The IGNORE_PREFIX tag can be used to specify one or more prefixes that # should be ignored while generating the index headers. IGNORE_PREFIX = CVC3:: #--------------------------------------------------------------------------- # configuration options related to the HTML output #--------------------------------------------------------------------------- # If the GENERATE_HTML tag is set to YES (the default) Doxygen will # generate HTML output. GENERATE_HTML = YES # The HTML_OUTPUT tag is used to specify where the HTML docs will be put. # If a relative path is entered the value of OUTPUT_DIRECTORY will be # put in front of it. If left blank `html' will be used as the default path. HTML_OUTPUT = html # The HTML_FILE_EXTENSION tag can be used to specify the file extension for # each generated HTML page (for example: .htm,.php,.asp). If it is left blank # doxygen will generate files with .html extension. HTML_FILE_EXTENSION = .html # The HTML_HEADER tag can be used to specify a personal HTML header for # each generated HTML page. If it is left blank doxygen will generate a # standard header. HTML_HEADER = # The HTML_FOOTER tag can be used to specify a personal HTML footer for # each generated HTML page. If it is left blank doxygen will generate a # standard footer. HTML_FOOTER = # The HTML_STYLESHEET tag can be used to specify a user-defined cascading # style sheet that is used by each HTML page. It can be used to # fine-tune the look of the HTML output. If the tag is left blank doxygen # will generate a default style sheet. Note that doxygen will try to copy # the style sheet file to the HTML output directory, so don't put your own # stylesheet in the HTML output directory as well, or it will be erased! HTML_STYLESHEET = # If the HTML_ALIGN_MEMBERS tag is set to YES, the members of classes, # files or namespaces will be aligned in HTML using tables. If set to # NO a bullet list will be used. HTML_ALIGN_MEMBERS = NO # If the GENERATE_HTMLHELP tag is set to YES, additional index files # will be generated that can be used as input for tools like the # Microsoft HTML help workshop to generate a compressed HTML help file (.chm) # of the generated HTML documentation. GENERATE_HTMLHELP = NO # If the GENERATE_HTMLHELP tag is set to YES, the CHM_FILE tag can # be used to specify the file name of the resulting .chm file. You # can add a path in front of the file if the result should not be # written to the html output directory. CHM_FILE = # If the GENERATE_HTMLHELP tag is set to YES, the HHC_LOCATION tag can # be used to specify the location (absolute path including file name) of # the HTML help compiler (hhc.exe). If non-empty doxygen will try to run # the HTML help compiler on the generated index.hhp. HHC_LOCATION = # If the GENERATE_HTMLHELP tag is set to YES, the GENERATE_CHI flag # controls if a separate .chi index file is generated (YES) or that # it should be included in the master .chm file (NO). GENERATE_CHI = NO # If the GENERATE_HTMLHELP tag is set to YES, the BINARY_TOC flag # controls whether a binary table of contents is generated (YES) or a # normal table of contents (NO) in the .chm file. BINARY_TOC = NO # The TOC_EXPAND flag can be set to YES to add extra items for group members # to the contents of the HTML help documentation and to the tree view. TOC_EXPAND = NO # The DISABLE_INDEX tag can be used to turn on/off the condensed index at # top of each HTML page. The value NO (the default) enables the index and # the value YES disables it. DISABLE_INDEX = NO # This tag can be used to set the number of enum values (range [1..20]) # that doxygen will group on one line in the generated HTML documentation. ENUM_VALUES_PER_LINE = 4 # If the GENERATE_TREEVIEW tag is set to YES, a side panel will be # generated containing a tree-like index structure (just like the one that # is generated for HTML Help). For this to work a browser that supports # JavaScript, DHTML, CSS and frames is required (for instance Mozilla 1.0+, # Netscape 6.0+, Internet explorer 5.0+, or Konqueror). Windows users are # probably better off using the HTML help feature. GENERATE_TREEVIEW = NO # If the treeview is enabled (see GENERATE_TREEVIEW) then this tag can be # used to set the initial width (in pixels) of the frame in which the tree # is shown. TREEVIEW_WIDTH = 250 #--------------------------------------------------------------------------- # configuration options related to the LaTeX output #--------------------------------------------------------------------------- # If the GENERATE_LATEX tag is set to YES (the default) Doxygen will # generate Latex output. GENERATE_LATEX = NO # The LATEX_OUTPUT tag is used to specify where the LaTeX docs will be put. # If a relative path is entered the value of OUTPUT_DIRECTORY will be # put in front of it. If left blank `latex' will be used as the default path. LATEX_OUTPUT = latex # The LATEX_CMD_NAME tag can be used to specify the LaTeX command name to be # invoked. If left blank `latex' will be used as the default command name. LATEX_CMD_NAME = latex # The MAKEINDEX_CMD_NAME tag can be used to specify the command name to # generate index for LaTeX. If left blank `makeindex' will be used as the # default command name. MAKEINDEX_CMD_NAME = makeindex # If the COMPACT_LATEX tag is set to YES Doxygen generates more compact # LaTeX documents. This may be useful for small projects and may help to # save some trees in general. COMPACT_LATEX = NO # The PAPER_TYPE tag can be used to set the paper type that is used # by the printer. Possible values are: a4, a4wide, letter, legal and # executive. If left blank a4wide will be used. PAPER_TYPE = letter # The EXTRA_PACKAGES tag can be to specify one or more names of LaTeX # packages that should be included in the LaTeX output. EXTRA_PACKAGES = amsmath # The LATEX_HEADER tag can be used to specify a personal LaTeX header for # the generated latex document. The header should contain everything until # the first chapter. If it is left blank doxygen will generate a # standard header. Notice: only use this tag if you know what you are doing! LATEX_HEADER = # If the PDF_HYPERLINKS tag is set to YES, the LaTeX that is generated # is prepared for conversion to pdf (using ps2pdf). The pdf file will # contain links (just like the HTML output) instead of page references # This makes the output suitable for online browsing using a pdf viewer. PDF_HYPERLINKS = NO # If the USE_PDFLATEX tag is set to YES, pdflatex will be used instead of # plain latex in the generated Makefile. Set this option to YES to get a # higher quality PDF documentation. USE_PDFLATEX = NO # If the LATEX_BATCHMODE tag is set to YES, doxygen will add the \\batchmode. # command to the generated LaTeX files. This will instruct LaTeX to keep # running if errors occur, instead of asking the user for help. # This option is also used when generating formulas in HTML. LATEX_BATCHMODE = NO # If LATEX_HIDE_INDICES is set to YES then doxygen will not # include the index chapters (such as File Index, Compound Index, etc.) # in the output. LATEX_HIDE_INDICES = NO #--------------------------------------------------------------------------- # configuration options related to the RTF output #--------------------------------------------------------------------------- # If the GENERATE_RTF tag is set to YES Doxygen will generate RTF output # The RTF output is optimized for Word 97 and may not look very pretty with # other RTF readers or editors. GENERATE_RTF = NO # The RTF_OUTPUT tag is used to specify where the RTF docs will be put. # If a relative path is entered the value of OUTPUT_DIRECTORY will be # put in front of it. If left blank `rtf' will be used as the default path. RTF_OUTPUT = rtf # If the COMPACT_RTF tag is set to YES Doxygen generates more compact # RTF documents. This may be useful for small projects and may help to # save some trees in general. COMPACT_RTF = NO # If the RTF_HYPERLINKS tag is set to YES, the RTF that is generated # will contain hyperlink fields. The RTF file will # contain links (just like the HTML output) instead of page references. # This makes the output suitable for online browsing using WORD or other # programs which support those fields. # Note: wordpad (write) and others do not support links. RTF_HYPERLINKS = NO # Load stylesheet definitions from file. Syntax is similar to doxygen's # config file, i.e. a series of assignments. You only have to provide # replacements, missing definitions are set to their default value. RTF_STYLESHEET_FILE = # Set optional variables used in the generation of an rtf document. # Syntax is similar to doxygen's config file. RTF_EXTENSIONS_FILE = #--------------------------------------------------------------------------- # configuration options related to the man page output #--------------------------------------------------------------------------- # If the GENERATE_MAN tag is set to YES (the default) Doxygen will # generate man pages GENERATE_MAN = NO # The MAN_OUTPUT tag is used to specify where the man pages will be put. # If a relative path is entered the value of OUTPUT_DIRECTORY will be # put in front of it. If left blank `man' will be used as the default path. MAN_OUTPUT = man # The MAN_EXTENSION tag determines the extension that is added to # the generated man pages (default is the subroutine's section .3) MAN_EXTENSION = .3 # If the MAN_LINKS tag is set to YES and Doxygen generates man output, # then it will generate one additional man file for each entity # documented in the real man page(s). These additional files # only source the real man page, but without them the man command # would be unable to find the correct page. The default is NO. MAN_LINKS = NO #--------------------------------------------------------------------------- # configuration options related to the XML output #--------------------------------------------------------------------------- # If the GENERATE_XML tag is set to YES Doxygen will # generate an XML file that captures the structure of # the code including all documentation. GENERATE_XML = NO # The XML_OUTPUT tag is used to specify where the XML pages will be put. # If a relative path is entered the value of OUTPUT_DIRECTORY will be # put in front of it. If left blank `xml' will be used as the default path. XML_OUTPUT = xml # The XML_SCHEMA tag can be used to specify an XML schema, # which can be used by a validating XML parser to check the # syntax of the XML files. XML_SCHEMA = # The XML_DTD tag can be used to specify an XML DTD, # which can be used by a validating XML parser to check the # syntax of the XML files. XML_DTD = # If the XML_PROGRAMLISTING tag is set to YES Doxygen will # dump the program listings (including syntax highlighting # and cross-referencing information) to the XML output. Note that # enabling this will significantly increase the size of the XML output. XML_PROGRAMLISTING = YES #--------------------------------------------------------------------------- # configuration options for the AutoGen Definitions output #--------------------------------------------------------------------------- # If the GENERATE_AUTOGEN_DEF tag is set to YES Doxygen will # generate an AutoGen Definitions (see autogen.sf.net) file # that captures the structure of the code including all # documentation. Note that this feature is still experimental # and incomplete at the moment. GENERATE_AUTOGEN_DEF = NO #--------------------------------------------------------------------------- # configuration options related to the Perl module output #--------------------------------------------------------------------------- # If the GENERATE_PERLMOD tag is set to YES Doxygen will # generate a Perl module file that captures the structure of # the code including all documentation. Note that this # feature is still experimental and incomplete at the # moment. GENERATE_PERLMOD = NO # If the PERLMOD_LATEX tag is set to YES Doxygen will generate # the necessary Makefile rules, Perl scripts and LaTeX code to be able # to generate PDF and DVI output from the Perl module output. PERLMOD_LATEX = NO # If the PERLMOD_PRETTY tag is set to YES the Perl module output will be # nicely formatted so it can be parsed by a human reader. This is useful # if you want to understand what is going on. On the other hand, if this # tag is set to NO the size of the Perl module output will be much smaller # and Perl will parse it just the same. PERLMOD_PRETTY = YES # The names of the make variables in the generated doxyrules.make file # are prefixed with the string contained in PERLMOD_MAKEVAR_PREFIX. # This is useful so different doxyrules.make files included by the same # Makefile don't overwrite each other's variables. PERLMOD_MAKEVAR_PREFIX = #--------------------------------------------------------------------------- # Configuration options related to the preprocessor #--------------------------------------------------------------------------- # If the ENABLE_PREPROCESSING tag is set to YES (the default) Doxygen will # evaluate all C-preprocessor directives found in the sources and include # files. ENABLE_PREPROCESSING = YES # If the MACRO_EXPANSION tag is set to YES Doxygen will expand all macro # names in the source code. If set to NO (the default) only conditional # compilation will be performed. Macro expansion can be done in a controlled # way by setting EXPAND_ONLY_PREDEF to YES. MACRO_EXPANSION = YES # If the EXPAND_ONLY_PREDEF and MACRO_EXPANSION tags are both set to YES # then the macro expansion is limited to the macros specified with the # PREDEFINED and EXPAND_AS_DEFINED tags. EXPAND_ONLY_PREDEF = YES # If the SEARCH_INCLUDES tag is set to YES (the default) the includes files # in the INCLUDE_PATH (see below) will be search if a #include is found. SEARCH_INCLUDES = YES # The INCLUDE_PATH tag can be used to specify one or more directories that # contain include files that are not input files but should be processed by # the preprocessor. INCLUDE_PATH = # You can use the INCLUDE_FILE_PATTERNS tag to specify one or more wildcard # patterns (like *.h and *.hpp) to filter out the header-files in the # directories. If left blank, the patterns specified with FILE_PATTERNS will # be used. INCLUDE_FILE_PATTERNS = # The PREDEFINED tag can be used to specify one or more macro names that # are defined before the preprocessor is started (similar to the -D option of # gcc). The argument of the tag is a list of macros of the form: name # or name=definition (no spaces). If the definition and the = are # omitted =1 is assumed. To prevent a macro definition from being # undefined via #undef or recursively expanded use the := operator # instead of the = operator. PREDEFINED = DEBUG \ DOXYGEN # If the MACRO_EXPANSION and EXPAND_ONLY_PREDEF tags are set to YES then # this tag can be used to specify a list of macro names that should be expanded. # The macro definition that is found in the sources will be used. # Use the PREDEFINED tag if you want to use a different macro definition. EXPAND_AS_DEFINED = IF_DEBUG # If the SKIP_FUNCTION_MACROS tag is set to YES (the default) then # doxygen's preprocessor will remove all function-like macros that are alone # on a line, have an all uppercase name, and do not end with a semicolon. Such # function macros are typically used for boiler-plate code, and will confuse # the parser if not removed. SKIP_FUNCTION_MACROS = YES #--------------------------------------------------------------------------- # Configuration::additions related to external references #--------------------------------------------------------------------------- # The TAGFILES option can be used to specify one or more tagfiles. # Optionally an initial location of the external documentation # can be added for each tagfile. The format of a tag file without # this location is as follows: # TAGFILES = file1 file2 ... # Adding location for the tag files is done as follows: # TAGFILES = file1=loc1 "file2 = loc2" ... # where "loc1" and "loc2" can be relative or absolute paths or # URLs. If a location is present for each tag, the installdox tool # does not have to be run to correct the links. # Note that each tag file must have a unique name # (where the name does NOT include the path) # If a tag file is not located in the directory in which doxygen # is run, you must also specify the path to the tagfile here. TAGFILES = # When a file name is specified after GENERATE_TAGFILE, doxygen will create # a tag file that is based on the input files it reads. GENERATE_TAGFILE = # If the ALLEXTERNALS tag is set to YES all external classes will be listed # in the class index. If set to NO only the inherited external classes # will be listed. ALLEXTERNALS = NO # If the EXTERNAL_GROUPS tag is set to YES all external groups will be listed # in the modules index. If set to NO, only the current project's groups will # be listed. EXTERNAL_GROUPS = YES # The PERL_PATH should be the absolute path and name of the perl script # interpreter (i.e. the result of `which perl'). PERL_PATH = /usr/bin/perl #--------------------------------------------------------------------------- # Configuration options related to the dot tool #--------------------------------------------------------------------------- # If the CLASS_DIAGRAMS tag is set to YES (the default) Doxygen will # generate a inheritance diagram (in HTML, RTF and LaTeX) for classes with base # or super classes. Setting the tag to NO turns the diagrams off. Note that # this option is superseded by the HAVE_DOT option below. This is only a # fallback. It is recommended to install and use dot, since it yields more # powerful graphs. CLASS_DIAGRAMS = YES # You can define message sequence charts within doxygen comments using the \msc # command. Doxygen will then run the mscgen tool (see http://www.mcternan.me.uk/mscgen/) to # produce the chart and insert it in the documentation. The MSCGEN_PATH tag allows you to # specify the directory where the mscgen tool resides. If left empty the tool is assumed to # be found in the default search path. MSCGEN_PATH = # If set to YES, the inheritance and collaboration graphs will hide # inheritance and usage relations if the target is undocumented # or is not a class. HIDE_UNDOC_RELATIONS = YES # If you set the HAVE_DOT tag to YES then doxygen will assume the dot tool is # available from the path. This tool is part of Graphviz, a graph visualization # toolkit from AT&T and Lucent Bell Labs. The other options in this section # have no effect if this option is set to NO (the default) HAVE_DOT = @HAVE_DOT@ # If the CLASS_GRAPH and HAVE_DOT tags are set to YES then doxygen # will generate a graph for each documented class showing the direct and # indirect inheritance relations. Setting this tag to YES will force the # the CLASS_DIAGRAMS tag to NO. CLASS_GRAPH = YES # If the COLLABORATION_GRAPH and HAVE_DOT tags are set to YES then doxygen # will generate a graph for each documented class showing the direct and # indirect implementation dependencies (inheritance, containment, and # class references variables) of the class with other documented classes. COLLABORATION_GRAPH = YES # If the GROUP_GRAPHS and HAVE_DOT tags are set to YES then doxygen # will generate a graph for groups, showing the direct groups dependencies GROUP_GRAPHS = YES # If the UML_LOOK tag is set to YES doxygen will generate inheritance and # collaboration diagrams in a style similar to the OMG's Unified Modeling # Language. UML_LOOK = YES # If set to YES, the inheritance and collaboration graphs will show the # relations between templates and their instances. TEMPLATE_RELATIONS = YES # If the ENABLE_PREPROCESSING, SEARCH_INCLUDES, INCLUDE_GRAPH, and HAVE_DOT # tags are set to YES then doxygen will generate a graph for each documented # file showing the direct and indirect include dependencies of the file with # other documented files. INCLUDE_GRAPH = YES # If the ENABLE_PREPROCESSING, SEARCH_INCLUDES, INCLUDED_BY_GRAPH, and # HAVE_DOT tags are set to YES then doxygen will generate a graph for each # documented header file showing the documented files that directly or # indirectly include this file. INCLUDED_BY_GRAPH = YES # If the CALL_GRAPH and HAVE_DOT tags are set to YES then doxygen will # generate a call dependency graph for every global function or class method. # Note that enabling this option will significantly increase the time of a run. # So in most cases it will be better to enable call graphs for selected # functions only using the \callgraph command. CALL_GRAPH = NO # If the CALLER_GRAPH and HAVE_DOT tags are set to YES then doxygen will # generate a caller dependency graph for every global function or class method. # Note that enabling this option will significantly increase the time of a run. # So in most cases it will be better to enable caller graphs for selected # functions only using the \callergraph command. CALLER_GRAPH = NO # If the GRAPHICAL_HIERARCHY and HAVE_DOT tags are set to YES then doxygen # will graphical hierarchy of all classes instead of a textual one. GRAPHICAL_HIERARCHY = YES # If the DIRECTORY_GRAPH, SHOW_DIRECTORIES and HAVE_DOT tags are set to YES # then doxygen will show the dependencies a directory has on other directories # in a graphical way. The dependency relations are determined by the #include # relations between the files in the directories. DIRECTORY_GRAPH = YES # The DOT_IMAGE_FORMAT tag can be used to set the image format of the images # generated by dot. Possible values are png, jpg, or gif # If left blank png will be used. DOT_IMAGE_FORMAT = gif # The tag DOT_PATH can be used to specify the path where the dot tool can be # found. If left blank, it is assumed the dot tool can be found in the path. DOT_PATH = # The DOTFILE_DIRS tag can be used to specify one or more directories that # contain dot files that are included in the documentation (see the # \dotfile command). DOTFILE_DIRS = # The MAX_DOT_GRAPH_MAX_NODES tag can be used to set the maximum number of # nodes that will be shown in the graph. If the number of nodes in a graph # becomes larger than this value, doxygen will truncate the graph, which is # visualized by representing a node as a red box. Note that doxygen will always # show the root nodes and its direct children regardless of this setting. DOT_GRAPH_MAX_NODES = 1 # Set the DOT_TRANSPARENT tag to YES to generate images with a transparent # background. This is disabled by default, which results in a white background. # Warning: Depending on the platform used, enabling this option may lead to # badly anti-aliased labels on the edges of a graph (i.e. they become hard to # read). DOT_TRANSPARENT = NO # Set the DOT_MULTI_TARGETS tag to YES allow dot to generate multiple output # files in one run (i.e. multiple -o and -T options on the command line). This # makes dot run faster, but since only newer versions of dot (>1.8.10) # support this, this feature is disabled by default. DOT_MULTI_TARGETS = NO # If the GENERATE_LEGEND tag is set to YES (the default) Doxygen will # generate a legend page explaining the meaning of the various boxes and # arrows in the dot generated graphs. GENERATE_LEGEND = YES # If the DOT_CLEANUP tag is set to YES (the default) Doxygen will # remove the intermediate dot files that are used to generate # the various graphs. DOT_CLEANUP = YES #--------------------------------------------------------------------------- # Configuration::additions related to the search engine #--------------------------------------------------------------------------- # The SEARCHENGINE tag specifies whether or not a search engine should be # used. If set to NO the values of all tags below this one will be ignored. SEARCHENGINE = NO cvc3-2.4.1/doc/userdoc.dox0000644000175400017540000022604411604636622015217 0ustar mdetersmdeters/*! \page user_doc The CVC3 User's Manual Contents
  • \ref user_doc_what_is_cvc3
  • \ref user_doc_command_line
  • \ref user_doc_pres_lang
    • \ref user_doc_pres_lang_types
      • \ref user_doc_pres_lang_real_type
      • \ref user_doc_pres_lang_bitvec_types
      • \ref user_doc_pres_lang_unint_types
      • \ref user_doc_pres_lang_bool_type
      • \ref user_doc_pres_lang_fun_types
      • \ref user_doc_pres_lang_array_types
      • \ref user_doc_pres_lang_tuple_types
      • \ref user_doc_pres_lang_record_types
      • \ref user_doc_pres_lang_data_types
      • \ref user_doc_pres_lang_typing
    • \ref user_doc_pres_lang_expr
      • \ref user_doc_pres_lang_expr_logic
      • \ref user_doc_pres_lang_expr_unint
      • \ref user_doc_pres_lang_expr_arith
      • \ref user_doc_pres_lang_expr_bit
      • \ref user_doc_pres_lang_expr_arr
      • \ref user_doc_pres_lang_expr_dat
      • \ref user_doc_pres_lang_expr_rec_tup
    • \ref user_doc_pres_lang_commands
      • \ref user_doc_pres_lang_commands_query
      • \ref user_doc_pres_lang_commands_checksat
      • \ref user_doc_pres_lang_commands_restart
    • \ref user_doc_pres_lang_patterns
    • \ref user_doc_pres_lang_subtypes
      • \ref user_doc_pres_lang_subtyping
      • \ref user_doc_pres_lang_tccs
  • \ref user_doc_smtlib_lang
\section user_doc_what_is_cvc3 What is CVC3? CVC3 is an automated validity checker for a many-sorted (i.e., typed) first-order logic with built-in theories, including some support for quantifiers, partial functions, and predicate subtypes. The current built-in theories are the theories of:
  • equality over free (aka uninterpreted) function and predicate symbols,
  • real and integer linear arithmetic (with some support for non-linear arithmetic),
  • bit vectors,
  • arrays,
  • tuples,
  • records,
  • user-defined inductive datatypes.
CVC3 checks whether a given formula \f$\phi\f$ is valid in the built-in theories under a given set \f$\Gamma\f$ of assumptions. More precisely, it checks whether \f[\Gamma\models_T \phi\f] that is, whether \f$\phi\f$ is a logical consequence of the union \f$T\f$ of the built-in theories and the set of formulas \f$\Gamma\f$. Roughly speaking, when \f$\phi\f$ is universal and all the formulas in \f$\Gamma\f$ are existential (i.e., when \f$\phi\f$ and \f$\Gamma\f$ contain at most universal, respectively existential, quantifiers), CVC3 is in fact a decision procedure: it is always guaranteed (well, modulo bugs and memory limits) to return a correct "valid" or "invalid" answer. In all other cases, CVC3 is sound but incomplete: it will never say that an invalid formula is valid but it may either never return or give up and return "unknown" in some cases when \f$\Gamma \models_T \phi\f$. When CVC3 returns "valid" it can return a formal proof of the validity of \f$\phi\f$ under the logical context \f$\Gamma\f$, together with the subset \f$\Gamma'\f$ of \f$\Gamma\f$ used in the proof, such that \f$\Gamma'\models_T \phi\f$. When CVC3 returns "invalid" it can return, in the current terminology, both a counter-example to \f$\phi\f$'s validity under \f$\Gamma\f$ and a counter-model. Both a counter-example and a counter-models are a set \f$\Delta\f$ of additional formulas consistent with \f$\Gamma\f$ in \f$T\f$, but entailing the negation of \f$\phi\f$. In formulas:
\f$\Gamma \cup \Delta \not\models_T \mathit{false}\f$ and \f$\Gamma \cup \Delta \models_T \lnot \phi\f$.
The difference is that a counter-model is given as a set of equations providing a concrete assignment of values for the free symbols in \f$\Gamma\f$ and \f$\phi\f$ (see \ref user_doc_pres_lang_commands_query for more details). CVC3 can be used in two modes: as a library or as a command-line executable (implemented as a command-line interface to the library). Interfaces to the library are available in C/C++, Java and .NET. This manual mainly describes the command-line interface on a unix-type platform. \section user_doc_command_line Running CVC3 from a Command Line Assuming you have properly installed CVC3 on your machine (check the \ref INSTALL section for that), you will have an executable file called cvc3. It reads the input (a sequence of commands) from the standard input and prints the results on the standard output. Errors and some other messages (e.g. debugging traces) are printed on the standard error. Typically, the input to cvc3 is saved in a file and redirected to the executable, or given on a command line: \verbatim # Reading from standard input: cvc3 < input-file.cvc # Reading directly from file: cvc3 input-file.cvc \endverbatim Notice that, for efficiency, CVC3 uses input buffers, and the input is not always processed immediately after each command. Therefore, if you want to type the commands interactively and receive immediate feedback, use the +interactive option (can be shortened to +int): \verbatim cvc3 +int \endverbatim Run cvc3 -h for more information on the available options. The command line front-end of CVC3 supports two input languages.
  • CVC3's own presentation language whose syntax was initially inspired by the PVS and SAL systems and is almost identical to the input language of CVC and CVC Lite, the predecessors of CVC3;
  • the standard language promoted by the SMT-LIB initiative for SMT-LIB benchmarks.
We describe the input languages next, concentrating mostly on the first. \section user_doc_pres_lang Presentation Input Language The input language consists of a sequence of symbol declarations and commands, each followed by a semicolon (;). Any text after the first occurrence of a percent character and to the end of the current line is a comment: \verbatim %%% This is a CVC3 comment \endverbatim \subsection user_doc_pres_lang_types Type system CVC3's type system includes a set of built-in types which can be expanded with additional user-defined types. The type system consists of value types, non-value types and subtypes of value types, all of which are interpreted as sets. For convenience, we will sometimes identify below the interpretation of a type with the type itself. Value types consist of atomic types and structured types. The atomic types are \f$\mathrm{REAL}\f$, \f$\mathrm{BITVECTOR}(n)\f$ for all \f$n > 0\f$, as well as user-defined atomic types (also called uninterpreted types). The structured types are array, tuple, and record types, as well as ML-style user-defined (inductive) datatypes. Non-value types consist of the type \f$\mathrm{BOOLEAN}\f$ and function types. Subtypes include the built-in subtype \f$\mathrm{INT}\f$ of \f$\mathrm{REAL}\f$ and are covered in the \ref user_doc_pres_lang_subtypes section below. \subsubsection user_doc_pres_lang_real_type REAL Type The \f$\mathrm{REAL}\f$ type is interpreted as the set of rational numbers. The name \f$\mathrm{REAL}\f$ is justified by the fact that a CVC3 formula is valid in the theory of rational numbers iff it is valid in the theory of real numbers. \subsubsection user_doc_pres_lang_bitvec_types Bit Vector Types For every positive numeral n, the type \f$\mathrm{BITVECTOR}(n)\f$ is interpreted as the set of all bit vectors of size n. \subsubsection user_doc_pres_lang_unint_types User-defined Atomic Types User-defined atomic types are each interpreted as a set of unspecified cardinality but disjoint from any other type. They are created by declarations like the following: \verbatim % User declarations of atomic types: MyBrandNewType: TYPE; Apples, Oranges: TYPE; \endverbatim \subsubsection user_doc_pres_lang_bool_type BOOLEAN Type The \f$\mathrm{BOOLEAN}\f$ type is, perhaps confusingly, the type of CVC3 formulas, not the two-element set of Boolean values. The fact that \f$\mathrm{BOOLEAN}\f$ is not a value type in practice means that it is not possible for function symbols in CVC3 to have a arguments of type \f$\mathrm{BOOLEAN}\f$. The reason is that CVC3 follows the two-tiered structure of classical first-order logic that distinguishes between formulas and terms, and allows terms to occur in formulas but not vice versa. (An exception is the IF-THEN-ELSE construct, see later.) The only difference is that, syntactically, formulas in CVC3 are terms of type \f$\mathrm{BOOLEAN}\f$. A function symbol f then can have \f$\mathrm{BOOLEAN}\f$ as its return type. But that is just CVC3's way, inherited from the previous systems of the CVC family, to say that f is a predicate symbol. CVC3 does have a type that behaves like a Boolean Value type, that is, a value type with only two elements and with the usual Boolean operations defined on it: it is BITVECTOR(1). \subsubsection user_doc_pres_lang_fun_types Function Types All structured types are actually families of types. Function (\f$\to\f$) types are created by the mixfix type constructors \f[ \begin{array}{l} \_ \to \_ \\[1ex] (\ \_\ ,\ \_\ ) \to \_ \\[1ex] (\ \_\ ,\ \_\ ,\ \_\ ) \to \_ \\[1ex] \ldots \end{array} \f] whose arguments can be instantiated by any value (sub)type, with the addition that the last argument can also be \f$\mathrm{BOOLEAN}\f$. \verbatim % Function type declarations UnaryFunType: TYPE = INT -> REAL; BinaryFunType: TYPE = (REAL, REAL) -> ARRAY REAL OF REAL; TernaryFunType: TYPE = (REAL, BITVECTOR(4), INT) -> BOOLEAN; \endverbatim A function type of the form \f$(T_1, \ldots, T_n) \to T\f$ with \f$n > 0\f$ is interpreted as the set of all total functions from the Cartesian product \f$T_1 \times \cdots \times T_n\f$ to \f$T\f$ when \f$T\f$ is not \f$\mathrm{BOOLEAN}\f$. Otherwise, it is interpreted as the set of all relations over \f$T_1 \times \cdots \times T_n\f$ The example above also shows how to introduce type names. A name like UnaryFunType above is just an abbreviation for the type \f$\mathrm{INT} \to \mathrm{REAL}\f$ and can be used interchangeably with it.
In general, any type defined by a type expression E can be given a name with the declaration: \verbatim name : TYPE = E; \endverbatim \subsubsection user_doc_pres_lang_array_types Array Types Array types are created by the mixfix type constructors \f$\mathrm{ARRAY}\ \_\ \mathrm{OF}\ \_\f$ whose arguments can be instantiated by any value type. \verbatim T1 : TYPE; % Array types: ArrayType1: TYPE = ARRAY T1 OF REAL; ArrayType2: TYPE = ARRAY INT OF (ARRAY INT OF REAL); ArrayType3: TYPE = ARRAY [INT, INT] OF INT; \endverbatim An array type of the form \f$\mathrm{ARRAY}\ T_1\ \mathrm{OF}\ T_2\f$ is interpreted as the set of all total maps from \f$T_1\f$ to \f$T_2\f$. The main conceptual difference with the type \f$T_1 \to T_2\f$ is that arrays, contrary to functions, are first-class objects of the language: they can be arguments or results of functions. Moreover, array types come equipped with an update operation. \subsubsection user_doc_pres_lang_tuple_types Tuple Types Tuple types are created by the mixfix type constructors \f[ \begin{array}{l} [\ \_\ ] \\[1ex] [\ \_\ ,\ \_\ ] \\[1ex] [\ \_\ ,\ \_\ \ ,\ \_\ ] \\[1ex] \ldots \end{array} \f] whose arguments can be instantiated by any value type. \verbatim % Tuple declaration TupleType: TYPE = [ REAL, ArrayType1, [INT, INT] ]; \endverbatim A tuple type of the form \f$[T_1, \ldots, T_n]\f$ is interpreted as the Cartesian product \f$T_1 \times \cdots \times T_n\f$. Note that while the types \f$(T_1, \ldots, T_n) \to T\f$ and \f$[T_1 \times \cdots \times T_n] \to T\f$ are semantically equivalent, they are operationally different in CVC3. The first is the type of functions that take n arguments, while the second is the type of functions of 1 argument of type n-tuple. \subsubsection user_doc_pres_lang_record_types Record Types Similar to, but more general than tuple types, record types are created by type constructors of the form \f[ [\#\ l_1: \_\ ,\ \ldots\ ,\ l_n: \_\ \#] \f] where \f$n > 0\f$, \f$l_1,\ldots, l_n\f$ are field labels, and the arguments can be instantiated with any value types. \verbatim % Record declaration RecordType: TYPE = [# number: INT, value: REAL, info: TupleType #]; \endverbatim The order of the fields in a record type is meaningful. In other words, permuting the field names gives a different type. Note that records are non-recursive. For instance, it is not possible to declare a record type called Person containing a field of type Person. Recursive types are provided in CVC3 as ML-style datatypes. \subsubsection user_doc_pres_lang_data_types Inductive Data Types Inductive datatypes are created by declarations of the form \f[ \begin{array}{l} \mathrm{DATATYPE} \\ \ \ \mathit{type\_name}_1 = C_{1,1} \mid C_{1,2} \mid \cdots \mid C_{1,m_1}, \\ \ \ \mathit{type\_name}_2 = C_{2,1} \mid C_{2,2} \mid \cdots \mid C_{2,m_2}, \\ \ \ \vdots \\ \ \ \mathit{type\_name}_n = C_{n,1} \mid C_{n,2} \mid \cdots \mid C_{n,m_n} \\ \mathrm{END}; \end{array} \f] Each of the \f$C_{ij}\f$ is either a constant symbol or an expression of the form \f[ \mathit{cons}(\ \mathit{sel}_1: T_1,\ \ldots,\ \mathit{sel}_k: T_k\ ) \f] where \f$T_1, \ldots, T_k\f$ are any value types or type names for value types, including any \f$\mathit{type\_name}_i\f$. Such declarations introduce for the datatype: - constructor symbols \f$cons\f$ of type \f$(T_1, \ldots, T_k) \to \mathit{type\_name}_i\f$, - selector symbols \f$\mathit{sel}_j\f$ of type \f$\mathit{type\_name}_i \to T_j\f$, and - tester symbols \f$\mathit{is\_cons}\f$ of type \f$\mathit{type\_name}_i \to \mathrm{BOOLEAN}\f$. Here are some examples of datatype declarations: \verbatim % simple enumeration type % implicitly defined are the testers: is_red, is_yellow and is_blue % (similarly for the other datatypes) DATATYPE PrimaryColor = red | yellow | blue END; % infinite set of pairwise distinct values ...v(-1), v(0), v(1), ... DATATYPE Id = v (id: INT) END; % ML-style integer lists DATATYPE IntList = nil | cons (head: INT, tail: IntList) END; % ASTs DATATYPE Term = var (index: INT) | apply (arg_1: Term, arg_2: Term) | lambda (arg: INT, body: Term) END; % Trees DATATYPE Tree = tree (value: REAL, children: TreeList), TreeList = nil_tl | cons_tl (first_t1: Tree, rest_t1: TreeList) END; \endverbatim Constructor, selector and tester symbols defined for a datatype have global scope. So, for instance, it is not possible for two different datatypes to use the same name for a constructor. A datatype is interpreted as a term algebra constructed by the constructor symbols over some sets of generators. For example, the datatype IntList is interpreted as the set of all terms constructed with nil and cons over the integers. Because of this semantics, CVC3 allows only inductive datatypes, that is, datatypes whose values are essentially (labeled, ordered) finite trees. Infinite structures such as streams or even finite but cyclic ones such as circular lists are then excluded. For instance, none of the following declarations define inductive datatypes, and are rejected by CVC3: \verbatim DATATYPE IntStream = s (first:INT, rest: IntStream) END; DATATYPE RationalTree = node1 (first_child1: RationalTree) | node2 (first_child2: RationalTree, second_child2:RationalTree) END; DATATYPE T1 = c1 (s1: T2), T2 = c2 (s2: T1) END; \endverbatim In concrete, a declaration of \f$n \geq 1\f$ datatypes \f$T_1, \ldots, T_n\f$ will be rejected if for any one of the types \f$T_1, \ldots, T_n\f$, it is impossible to build a finite term of that type using only the constructors of \f$T_1, \ldots, T_n\f$ and free constants of type other than \f$T_1, \ldots, T_n\f$. Datatypes are the only types for which the user also chooses names for the built-in operations defined on the type for: - constructing a value (with the constructors), - extracting components from a value (with the selectors), or - checking if a value was constructed with a certain constructor or not (with the testers). For all the other types, CVC3 provides predefined names for the built-in operations on the type. \subsubsection user_doc_pres_lang_typing Type Checking In essence, CVC3 terms are statically typed at the level of types--as opposed to subtypes--according to the usual rules of first-order many-sorted logic (the typing rules for formulas are analogous): - each variable has one associated (non-function) type, - each constant symbol has one associated (non-function) type, - each function symbol has one or more associated function types, - the type of a term consisting just of a variable or a constant symbol is the type associated to that variable or constant symbol, - the term obtained by applying a function symbol \f$f\f$ to the terms \f$t_1, \ldots, t_n\f$ is \f$T\f$ if \f$f\f$ has type \f$(T_1, \ldots, T_n) \to T\f$ and each \f$t_i\f$ has type \f$T_i\f$. Attempting to enter an ill-typed term will result in an error. The main difference with standard many-sorted logic is that some built-in symbols are parametrically polymorphic. For instance the function symbol for extracting the element of any array has type \f$(\mathit{ARRAY}\ T_1\ \mathit{OF}\ T_2,\; T_1) \to T_2\f$ for all types \f$T_1, T_2\f$ not containing function or predicate types. \subsection user_doc_pres_lang_expr Terms and Formulas In addition to type expressions, CVC3 has expressions for terms and formulas (i.e., terms of type \f$\mathrm{BOOLEAN}\f$). By and large, these are standard first-order terms built out of (typed) variables, predefined theory-specific operators, free (i.e., user-defined) function symbols, and quantifiers. Extensions include an if-then-else operator, lambda abstractions, and local symbol declarations, as illustrated below. Note that these extensions still keep CVC3's language first-order. In particular, lambda abstractions are restricted to take and return only terms of a value type. Similarly, quantifiers can only quantify variables of a value type. Free function symbols include constant symbols and predicate symbols, respectively nullary function symbols and function symbols with a \f$\mathrm{BOOLEAN}\f$ return type. Free symbols are introduced with global declarations of the form \f$f_1, \ldots, f_m: T;\f$ where \f$m > 0\f$, \f$f_i\f$ are the names of the symbols and \f$T\f$ is their type: \verbatim % integer constants a, b, c: INT; % real constants x,y,z: REAL; % unary function f1: REAL -> REAL; % binary function f2: (REAL, INT) -> REAL; % unary function with a tuple argument f3: [INT, REAL] -> BOOLEAN; % binary predicate p: (INT, REAL) -> BOOLEAN; % Propositional "variables" P,Q; BOOLEAN; \endverbatim Like type declarations, such free symbol declarations have global scope and must be unique. In other words, it is not possible to globally declare a symbol more than once. This entails among other things that free symbols cannot be overloaded with different types. As with types, a new free symbol can be defined as the name of a term of the corresponding type. With constant symbols this is done with a declaration of the form \f$f:T = t;\f$ : \verbatim c: INT; i: INT = 5 + 3*c; j: REAL = 3/4; t: [REAL, INT] = (2/3, -4); r: [# key: INT, value: REAL #] = (# key := 4, value := (c + 1)/2 #); f: BOOLEAN = FORALL (x:INT): x <= 0 OR x > c ; \endverbatim A restriction on constants of type \f$\mathit{BOOLEAN}\f$ is that their value can only be a closed formula, that is, a formula with no free variables. A term and its name can be used interchangeably in later expressions. Named terms are often useful for shared subterms (terms used several times in different places) since their use can make the input exponentially more concise. Named terms are processed very efficiently by CVC3. It is much more efficient to associate a complex term with a name directly rather than to declare a constant and later assert that it is equal to the same term. This point will be explained in more detail later in section \ref user_doc_pres_lang_commands. More generally, in CVC3 one can associate a term to function symbols of any arity. For non-constant function symbols this is done with a declaration of the form \f[ f:(T_1, \ldots, T_n) \to T = \mathrm{LAMBDA}(x_1:T_1, \ldots, x:T_n): t\;; \f] where \f$t\f$ is any term of type \f$T\f$ with free variables in \f$\{x_1, \ldots, x_n\}\f$. The lambda binder has the usual semantics and conforms to the usual lexical scoping rules: within the term \f$t\f$ the declaration of the symbols \f$x_1, \ldots, x_n\f$ as local variables of respective type \f$T_1, \ldots, T_n\f$ hides any previous, global declaration of those symbols. As a general shorthand, when \f$k\f$ consecutive types \f$T_i, \ldots, T_{i+k-1}\f$ in the lambda expression \f$\mathrm{LAMBDA}(x_1:T_1, \ldots, x:T_n): t\f$ are identical, the syntax \f$\mathrm{LAMBDA}(x_1:T_1, \ldots, x_i,\ldots, x_{i+k-1}:T_i,\ldots, x:T_n): t\f$ is also allowed. \verbatim % Global declaration of x as a unary function symbol x: REAL -> REAL; % Local declarations of x as a constant symbol f: REAL -> REAL = LAMBDA (x: REAL): 2*x + 3; p: (INT, INT) -> BOOLEAN = LAMBDA (x,i: INT): i*x - 1 > 0; g: (REAL, INT) -> [REAL, INT] = LAMBDA (x: REAL, i:INT): (x + 1, i - 3); \endverbatim Constant and function symbols can also be declared locally anywhere within a term by means of a let binder. This is done with a declaration of the form \f[ \begin{array}{rl} \mathrm{LET} & f_1 = t_1, \\ & \vdots \\ & f_n = t_m \\ \mathrm{IN} & t ; \end{array} \f] for constant symbols, and of the form \f[ \begin{array}{rlcl} \mathrm{LET} & f_1 & = &\mathrm{LAMBDA}(x^1_1:T^1_1, \ldots, x^{n_1}_1:T^{n_1}_1):\; t_1, \\ & & \vdots & \\ & f_m & = & \mathrm{LAMBDA}(x^1_m:T^1_m, \ldots, x^{n_m}_m:T^{n_m}_m):\; t_m \\ \mathrm{IN} & t ; \end{array} \f] for non-constant symbols. Let binders can be nested arbitrarily and follow the usual lexical scoping rules. \verbatim t: REAL = LET g = LAMBDA(x:INT): x + 1, x1 = 42, x2 = 2*x1 + 7/2 IN (LET x3 = g(x1) IN x3 + x2) / x1; \endverbatim Note that the same symbol = is used, unambiguously, in the syntax of global declarations, let declarations, and as a predicate symbol. In addition to user-defined symbols, CVC3 terms can use a number of predefined symbols: the logical symbols as well as theory symbols, function symbols belonging to one of the built-in theories. They are described next, with the theory symbols grouped by theory. \subsubsection user_doc_pres_lang_expr_logic Logical Symbols The logical symbols in CVC3's language include the equality and disequality predicate symbols, respectively written as = and /=, the multiarity disequality symbol DISTINCT, together with the logical constants TRUE, FALSE, the connectives NOT, AND, OR, XOR, =>, <=>, and the first-order quantifiers EXISTS and FORALL, all with the standard many-sorted logic semantics. The binary connectives have infix syntax and type \f$(\mathrm{BOOLEAN},\mathrm{BOOLEAN}) \to \mathrm{BOOLEAN}\f$. The symbols = and /=, which are also infix, are instead polymorphic, having type \f$(T,T) \to \mathrm{BOOLEAN}\f$ for every predefined or user-defined value type \f$T\f$. They are interpreted respectively as the identity relation and its complement. The \f$\mathrm{DISTINCT}\f$ symbol is both overloaded and polymorphic. It has type \f$(T,...,T) \to \mathrm{BOOLEAN}\f$ for every tuple \f$(T,...,T)\f$ of length \f$n > 0\f$ where \f$T\f$ is a predefined or user-defined value type. For each \f$n > 0\f$, it is interpreteted as the relation that holds exactly for tuples of pairwise distinct elements. The syntax for quantifiers is similar to that of the lambda binder. Here is an example of a formula built just of these logical symbols and variables: \verbatim A, B: TYPE; quant: BOOLEAN = FORALL (x,y: A, i,j,k: B): i = j AND i /= k => EXISTS (z: A): x /= z OR z /= y; \endverbatim Binding and scoping of quantified variables follows the same rules as in let expressions. In particular, a quantifier will shadow in its scope any constant and function symbols with the same name as one of the variables it quantifies: \verbatim A: TYPE; i,j: INT; % The first occurrence of i and of j in f are constant symbols, % the others are variables. f: BOOLEAN = i = j AND FORALL (i,j: A): i = j OR i /= j; \endverbatim Optionally, it is also possible to specify instantiation patterns for quantified variables. The general syntax for a quantified formula \f$\psi\f$ with patterns is \f[ Q\:(x_1:T_1, \ldots, x_k:T_k):\; p_1: \ldots\; p_n:\; \varphi \f] where \f$n \geq 0\f$, \f$Q\f$ is either \f$\mathrm{FORALL}\f$ or \f$\mathrm{EXISTS}\f$, \f$\varphi\f$ is a term of type \f$\mathrm{BOOLEAN}\f$, and each of the \f$p_i\f$'s, a pattern for the quantifier \f$Q\:(x_1:T_1, \ldots, x_k:T_k)\f$, has the form \f[ \mathrm{PATTERN}\; (t_1, \ldots, t_m) \f] where \f$m > 0\f$ and \f$t_1, \ldots, t_m\f$ are arbitrary binder-free terms (no lets, no quantifiers). Those terms can contain (free) variables, typically, but not exclusively, drawn from \f$x_1, \ldots, x_k\f$. (Additional variables can occur if \f$\psi\f$ occurs in a bigger formula binding those variables.) \verbatim A: TYPE; b, c: A; p, q: A -> BOOLEAN; r: (A, A) -> BOOLEAN; ASSERT FORALL (x0, x1, x2: A): PATTERN (r(x0, x1), r(x1, x2)): (r(x0, x1) AND r(x1, x2)) => r(x0, x2) ; ASSERT FORALL (x: A): PATTERN (r(x, b)): PATTERN (r(x, c)): p(x) => q(x) ; ASSERT EXISTS (y: A): FORALL (x: A): PATTERN (r(x, y), p(y)): r(x, y) => q(x) ; \endverbatim Patterns have no logical meaning: adding them to a formula does not change its semantics. Their purpose is purely operational, as explained in Section \ref user_doc_pres_lang_patterns. In addition to these constructs, CVC3 also has a general mixfix conditional operator of the form \f[ \mathrm{IF}\ b\ \mathrm{THEN}\ t\ \mathrm{ELSIF}\ b_1\ \mathrm{THEN}\ t_1\ \ldots\ \mathrm{ELSIF}\ b_n\ \mathrm{THEN}\ t_n\ \mathrm{ELSE}\ t_{n+1}\ \mathrm{ENDIF} \f] with \f$n \geq 0\f$ where \f$b, b_1, \ldots, b_n\f$ are terms of type \f$\mathrm{BOOLEAN}\f$ and \f$t, t_1, \ldots, t_n, t_{n+1}\f$ are terms of the same value type \f$T\f$: \verbatim % Conditional term x,y,z,w:REAL; t: REAL = IF x > 0 THEN y ELSIF x >= 1 THEN z ELSIF x > 2 THEN w ELSE 2/3 ENDIF; \endverbatim \subsubsection user_doc_pres_lang_expr_unint User-defined Functions and Types The theory of user-defined functions is in effect a family of theories of equality parametrized by the atomic types and the free symbols a user can define during a run of CVC3. The theory's function symbols consist of all and only the user-defined free symbols. \subsubsection user_doc_pres_lang_expr_arith Arithmetic The real arithmetic theory has predefined symbols for the usual arithmetic constants and operators over the type \f$\mathrm{REAL}\f$, each with the expected type: all numerals 0, 1, ..., as well as - (both unary and binary), +, *, /, <, >, <=, >=. Rational values can be expressed in fractional form: e.g., 1/2, 3/4, etc. The size of numerals used in the representation of natural and rational numbers is unbounded (or more accurately, bounded only by the amount of available memory). \subsubsection user_doc_pres_lang_expr_bit Bit vectors The bit vector theory has a large number of predefined function symbols denoting various bit vector operators. We describe the operators and their semantics informally below, often omitting a specification of their type, which should be easy to infer. The operators' names are overloaded in the obvious way. For instance, the same name is used for each \f$m,n > 0\f$ for the operator that takes a bit vector of size \f$m\f$ and one of size \f$n\f$ and returns their concatenation. For each size \f$n\f$, there are \f$2^n\f$ elements in the type \f$\mathrm{BITVECTOR}(n)\f$. These elements can be named using constant symbols or bit vector constants. Each element in the domain is named by two different constant symbols: once in binary and once in hexadecimal format. Binary constant symbols start with the characters 0bin and continue with the representation of the vector in the usual binary format (as an \f$n\f$-string over the characters 0,1). Hexadecimal constant symbols start with the characters 0hex and continue with the representation of the vector in usual hexadecimal format (as an \f$n\f$-string over the characters 0,...,9,a,...,f). \verbatim Binary constant Corresponding hexadecimal constant ----------------------------------------------------------- 0bin0000111101010000 0hex0f50 \endverbatim In the binary representation, the rightmost bit is the least significant bit (LSB) of the vector and the leftmost bit is the most significant bit (MSB). The index of the LSB in the bit vector is 0 and the index of the MSB is n-1 for an n-bit constant. This convention extends to all bit vector expressions in the natural way. Bit vector operators are categorized into word-level, bitwise, arithmetic, and comparison operators. \verbatim WORD-LEVEL OPERATORS: Description Symbol Example ==================================================================== Concatenation _ @ _ 0bin01@0bin0 (= 0bin010) Extraction _ [i:j] 0bin0011[3:1] (= 0bin001) Left shift _ << k 0bin0011 << 3 (= 0bin0011000) Right shift _ >> k 0bin1000 >> 3 (= 0bin0001) Sign extension SX(_,k) SX(0bin100, 5) (= 0bin11100) Zero extension BVZEROEXTEND(_,k) BVZEROEXTEND(0bin1,3) (= 0bin0001) Repeat BVREPEAT(_,k) BVREPEAT(0bin10,3) (= 0bin101010) Rotate left BVROTL(_,k) BVROTL(0bin101,1) (= 0bin011) Rotate right BVROTR(_,k) BVROTR(0bin101,1) (= 0bin110) \endverbatim For each \f$m,n > 0\f$ there is - one infix concatenation operator, taking an \f$m\f$-bit vector \f$v_1\f$ and an \f$n\f$-bit vector \f$v_2\f$ and returning the \f$(m+n)\f$-bit concatenation of \f$v_1\f$ and \f$v_2\f$; - one postfix extraction operator \f$[i:j]\f$ for each \f$i, j\f$ with \f$n > i >= j >= 0\f$, taking an \f$n\f$-bit vector \f$v\f$ and returning the \f$(i-j+1)\f$-bit subvector of \f$v\f$ at positions \f$i\f$ through \f$j\f$ (inclusive); - one postfix left shift operator \f$<< k\f$ for each \f$k >= 0\f$, taking an \f$n\f$-bit vector \f$v\f$ and returning the \f$(n+k)\f$-bit concatenation of \f$v\f$ with the \f$k\f$-bit zero vector; - one postfix right shift operator \f$>> k\f$ for each \f$k >= 0\f$, taking an \f$n\f$-bit vector \f$v\f$ and returning the \f$n\f$-bit concatenation of the \f$k\f$-bit zero bit vector with \f$v[n-1:k]\f$; - one mixfix sign extension operator \f$\mathrm{SX}(\_, k)\f$ for each \f$k >= n\f$, taking an \f$n\f$-bit vector \f$v\f$ and returning the \f$k\f$-bit concatenation of \f$k-n\f$ copies of the MSB of \f$v\f$ and \f$v\f$. - one mixfix zero extension operator \f$\mathrm{BVZEROEXTEND}(\_, k)\f$ for each \f$k >= 1\f$, taking an \f$n\f$-bit vector \f$v\f$ and returning the \f$n+k\f$-bit concatenation of \f$k\f$ zeroes and \f$v\f$. - one mixfix repeat operator \f$\mathrm{BVREPEAT}(\_, k)\f$ for each \f$k >= 1\f$, taking an \f$n\f$-bit vector \f$v\f$ and returning the \f$n*k\f$-bit concatenation of \f$k\f$ copies of \f$v\f$. - one mixfix rotate left operator \f$\mathrm{BVROTL}(\_, k)\f$ for each \f$k >= 0\f$, taking an \f$n\f$-bit vector \f$v\f$ and returning the \f$(n)\f$-bit vector obtained by rotating the bits of \f$v\f$ left \f$k\f$ times, where a single rotation means removing the MSB and concatenating it as the new LSB. - one mixfix rotate right operator \f$\mathrm{BVROTR}(\_, k)\f$ for each \f$k >= 0\f$, taking an \f$n\f$-bit vector \f$v\f$ and returning the \f$(n)\f$-bit vector obtained by rotating the bits of \f$v\f$ right \f$k\f$ times, where a single rotation means removing the LSB and concatenating it as the new MSB. \verbatim BITWISE OPERATORS: Description Symbol ============================== Bitwise AND _ & _ Bitwise OR _ | _ Bitwise NOT ~ _ Bitwise XOR BVXOR(_,_) Bitwise NAND BVNAND(_,_) Bitwise NOR BVNOR(_,_) Bitwise XNOR BVXNOR(_,_) Bitwise Compare BVCOMP(_,_) \endverbatim For each \f$n > 0\f$ there are operators with the names and syntax above, performing the usual bitwise Boolean operations on \f$n\f$-bit arguments. All produce \f$n\f$-bit results except for \f$\mathrm{BVCOMP}\f$ which always produces a 1-bit result: \f$\mathrm{0bin1}\f$ if its two arguments are equal and \f$\mathrm{0bin0}\f$ otherwise. \verbatim ARITHMETIC OPERATORS: Description Symbol ======================================== Bit vector addition BVPLUS(k,_,_,...) Bit vector multiplication BVMULT(k,_,_) Bit vector negation BVUMINUS(_) Bit vector subtraction BVSUB(k,_,_) Bit vector left shift BVSHL(_,_) Bit vector arith shift right BVASHR(_,_) Bit vector logic shift right BVLSHR(_,_) Bit vector unsigned divide BVUDIV(_,_) Bit vector signed divide BVSDIV(_,_) Bit vector unsigned remainder BVUREM(_,_) Bit vector signed remainder BVSREM(_,_) Bit vector signed modulus BVSMOD(_,_) \endverbatim For each \f$n > 0\f$ and \f$k > 0\f$ there is - one addition operator \f$\mathrm{BVPLUS}(k,\_, \_, \ldots)\f$, taking two or more bit vectors of arbitrary size, and returning the \f$(k)\f$ least significant bits of their sum. - one multiplication operator \f$\mathrm{BVMULT}(k,\_, \_)\f$, taking two bit vectors \f$v_1\f$ and \f$v_2\f$, and returning the \f$k\f$ least significant bits of their product. - one prefix negation operator \f$\mathrm{BVUMINUS}(\_)\f$, taking an \f$n\f$-bit vector \f$v\f$ and returning the \f$n\f$-bit vector \f$\mathrm{BVPLUS}(n,\verb|~|v,\mathrm{0bin1})\f$. - one subtraction operator \f$\mathrm{BVSUB}(k,\_, \_)\f$, taking two bit vectors \f$v_1\f$ and \f$v_2\f$, and returning the \f$k\f$-bit vector \f$\mathrm{BVPLUS}(k,v_1,\mathrm{BVUMINUS}(v'))\f$ where \f$v'\f$ is \f$v_2\f$ if the size of \f$v_2\f$ is greater than or equal to \f$k\f$, and \f$v_2\f$ extended to size \f$k\f$ by concatenating zeroes in the most significant bits otherwise. - one left shift operator \f$\mathrm{BVSHL}(\_, \_)\f$, taking two \f$n\f$-bit vectors \f$v_1\f$ and \f$v_2\f$, and returning the \f$n\f$-bit vector obtained by creating a vector of zeroes whose length is the value of \f$v_2\f$, concatenating this vector onto the least significant bits of \f$v_1\f$, and then taking the least significant \f$n\f$ bits of the result. - one arithmetic shift right operator \f$\mathrm{BVASHR}(\_, \_)\f$, taking two \f$n\f$-bit vectors \f$v_1\f$ and \f$v_2\f$, and returning the \f$n\f$-bit vector obtained by creating a vector whose length is the value of \f$v_2\f$ and each of whose bits has the same value as the MSB of \f$v_1\f$, concatenating this vector onto the most significant bits of \f$v_1\f$, and then taking the most significant \f$n\f$ bits of the result. - one logical shift right operator \f$\mathrm{BVLSHR}(\_, \_)\f$, taking two \f$n\f$-bit vectors \f$v_1\f$ and \f$v_2\f$, and returning the \f$n\f$-bit vector obtained by creating a vector of zeroes whose length is the value of \f$v_2\f$, concatenating this vector onto the most significant bits of \f$v_1\f$, and then taking the most significant \f$n\f$ bits of the result. - one unsigned integer division operator \f$\mathrm{BVUDIV}(\_, \_)\f$, taking two \f$n\f$-bit vectors \f$v_1\f$ and \f$v_2\f$, and returning the \f$n\f$-bit vector that is the largest integer value that can be multiplied by the integer value of \f$v_2\f$ to obtain an integer less than or equal to the integer value of \f$v_1\f$. - one signed integer division operator \f$\mathrm{BVSDIV}(\_, \_)\f$. - one unsigned integer remainder operator \f$\mathrm{BVUREM}(\_, \_)\f$. - one signed integer remainder operator \f$\mathrm{BVSREM}(\_, \_)\f$ (sign follows dividend). - one signed integer modulus operator \f$\mathrm{BVSMOD}(\_, \_)\f$ (sign follows divisor). For precise definitions of the last four operators, we refer the reader to the equivalent operators defined in the SMT-LIB QF_BV logic (\ref user_doc_smtlib_lang). CVC3 does not have dedicated operators for multiplexers. However, specific multiplexers can be easily defined with the aid of conditional terms. \verbatim % Example of 2-to-1 multiplexer mp: (BITVECTOR(1), BITVECTOR(1), BITVECTOR(1)) -> BITVECTOR(1) = LAMBDA (s,x,y : BITVECTOR(1)): IF s = 0bin0 THEN x ELSE y ENDIF; \endverbatim In addition to equality and disequality, CVC3 provides the following comparison operators. \verbatim COMPARISON OPERATORS: Description Symbol =================================== Less than BVLT(_,_) Less than or equal to BVLE(_,_) Greater than BVGT(_,_) Greater than equal to BVGE(_,_) Signed less than BVSLT(_,_) Signed less than or equal to BVSLE(_,_) Signed greater than BVSGT(_,_) Signed greater than equal to BVSGE(_,_) \endverbatim For each \f$m, n > 0\f$ there is - one prefix "less than" operator \f$\mathrm{BVLT}(\_, \_)\f$, taking an \f$m\f$-bit vector \f$v_1\f$ and an \f$n\f$-bit vector \f$v_2\f$, and having the value \f$\mathrm{TRUE}\f$ iff the zero-extension of \f$v_1\f$ to \f$k\f$ bits is less than the zero-extension of \f$v_2\f$ to \f$k\f$ bits, where \f$k\f$ is the maximum of \f$m\f$ and \f$n\f$. - one prefix "less than or equal to" operator \f$\mathrm{BVLE}(\_, \_)\f$, taking an \f$m\f$-bit vector \f$v_1\f$ and an \f$n\f$-bit vector \f$v_2\f$, and having the value \f$\mathrm{TRUE}\f$ iff the zero-extension of \f$v_1\f$ to \f$k\f$ bits is less than or equal to the zero-extension of \f$v_2\f$ to \f$k\f$ bits, where \f$k\f$ is the maximum of \f$m\f$ and \f$n\f$. - one prefix "greater than" operator \f$\mathrm{BVGT}(\_, \_)\f$, taking an \f$m\f$-bit vector \f$v_1\f$ and an \f$n\f$-bit vector \f$v_2\f$, and having the same value as \f$\mathrm{BVLT}(v_2, v_1)\f$. - one prefix "greater than or equal to" operator \f$\mathrm{BVGE}(\_, \_)\f$, taking an \f$m\f$-bit vector \f$v_1\f$ and an \f$n\f$-bit vector \f$v_2\f$, and having the same value as \f$\mathrm{BVLE}(v_2, v_1)\f$. The signed operators are similar except that the values being compared are considered to be signed bit vector representations (in 2's complement) of integers. Following are some example CVC3 input formulas involving bit vector expressions Example 1 illustrates the use of arithmetic, word-level and bitwise NOT operations: \verbatim x : BITVECTOR(5); y : BITVECTOR(4); yy : BITVECTOR(3); QUERY BVPLUS(9, x@0bin0000, (0bin000@(~y)@0bin11))[8:4] = BVPLUS(5, x, ~(y[3:2])) ; \endverbatim Example 2 illustrates the use of arithmetic, word-level and multiplexer terms: \verbatim bv : BITVECTOR(10); a : BOOLEAN; QUERY 0bin01100000[5:3]=(0bin1111001@bv[0:0])[4:2] AND 0bin1@(IF a THEN 0bin0 ELSE 0bin1 ENDIF) = (IF a THEN 0bin110 ELSE 0bin011 ENDIF)[1:0] ; \endverbatim Example 3 illustrates the use of bitwise operations: \verbatim x, y, z, t, q : BITVECTOR(1024); ASSERT x = ~x; ASSERT x&y&t&z&q = x; ASSERT x|y = t; ASSERT BVXOR(x,~x) = t; QUERY FALSE; \endverbatim Example 4 illustrates the use of predicates and all the arithmetic operations: \verbatim x, y : BITVECTOR(4); ASSERT x = 0hex5; ASSERT y = 0bin0101; QUERY BVMULT(8,x,y)=BVMULT(8,y,x) AND NOT(BVLT(x,y)) AND BVLE(BVSUB(8,x,y), BVPLUS(8, x, BVUMINUS(x))) AND x = BVSUB(4, BVUMINUS(x), BVPLUS(4, x,0hex1)) ; \endverbatim Example 5 illustrates the use of shift functions \verbatim x, y : BITVECTOR(8); z, t : BITVECTOR(12); ASSERT x = 0hexff; ASSERT z = 0hexff0; QUERY z = x << 4; QUERY (z >> 4)[7:0] = x; \endverbatim \subsubsection user_doc_pres_lang_expr_arr Arrays The theory of arrays is a parametric theory of (total) unary functions. It comes equipped with polymorphic selection and update operators, respectively
\f$\_[\_]\f$ and \f$\_\ \mathrm{WITH}\ [\_]\ := \_\f$
with the usual semantics. For each index type \f$T_1\f$ and element type \f$T_2\f$, the first operator maps an array from \f$T_1\f$ to \f$T_2\f$ and an index into it (i.e., a value of type \f$T_1\f$) to the element of type \f$T_2\f$ "stored" into the array at that index. The second maps an array \f$a\f$ from \f$T_1\f$ to \f$T_2\f$, an index \f$i\f$, and a \f$T_2\f$-element \f$e\f$ to the array that stores \f$e\f$ at index \f$i\f$ and is otherwise identical to \f$a\f$. Since arrays are just maps, equality between them is extensional: for two arrays of the same type to be different they have to store differ elements in at least one place. Sequential updates can be chained with the syntax \f$\_\ \mathrm{WITH}\ [\_]\ := \_, \ldots, [\_]\ := \_\f$. \verbatim A: TYPE = ARRAY INT OF REAL; a: A; i: INT = 4; % selection: elem: REAL = a[i]; % update a1: A = a WITH [10] := 1/2; % sequential update % (syntactic sugar for (a WITH [10] := 2/3) WITH [42] := 3/2) a2: A = a WITH [10] := 2/3, [42] := 3/2; \endverbatim \subsubsection user_doc_pres_lang_expr_dat Datatypes The theory of datatypes is in fact a family of theories parametrized by a datatype declaration specifying constructors and selectors for a particular datatype. No built-in operators other than equality and disequality are provided for this family in the presentation language. Each datatype declaration, however, generates constructor, selector and tester operators as described in Section \ref user_doc_pres_lang_data_types. \subsubsection user_doc_pres_lang_expr_rec_tup Tuples and Records Although they are currently implemented separately in CVC3, semantically both records and tuples can be seen as special instances of datatypes. In fact, a record of type \f$[\# l_0:T_0, \ldots, l_n:T_n \#]\f$ could be equivalently modeled as, say, the datatype \f[ \begin{array}{l} \mathrm{DATATYPE} \\ \ \ \mathrm{Record} = \mathit{rec}(l_0:T_0, \ldots, l_n:T_n) \\ \mathrm{END}; \end{array} \f] Tuples could be seen in turn as special cases of records where the field names are the numbers from 0 to the length of the tuple minus 1. Currently, however, tuples and records have their own syntax for constructor and selector operators. Records of type \f$[\# l_0:T_0, \ldots, l_n:T_n \#]\f$ have the associated built-in constructor \f$(\#\ l_0 := \_, \ldots, l_n := \_\ \#)\f$ whose arguments must be terms of type \f$T_0, \ldots, T_n\f$, respectively. Tuples of type \f$[\ T_0, \ldots, T_n\ ]\f$ have the associated built-in constructor \f$(\ \_, \ldots, \_\ )\f$ whose arguments must be terms of type \f$T_0, \ldots, T_n\f$, respectively. The selector operators on records and tuples follows a dot notation syntax. \verbatim % Record construction and field selection Item: TYPE = [# key: INT, weight: REAL #]; x: Item = (# key := 23, weight := 43/10 #); k: INT = x.key; v: REAL = x.weight; % Tuple construction and projection y: [REAL,INT,REAL] = ( 4/5, 9, 11/9 ); first_elem: REAL = y.0; third_elem: REAL = y.2; \endverbatim Differently from datatypes, records and tuples are also provided with built-in update operators similar in syntax and semantics to the update operator for arrays. More precisely, for each record type \f$[\#\ l_0:T_0, \ldots, l_n:T_n\ \#]\f$ and each \f$i=0, \ldots, n\f$, CVC3 provides the operator \f[ \_\ \mathrm{WITH}\ .l_i\ := \_ \f] The operator maps a record \f$r\f$ of that type and a value \f$v\f$ of type \f$T_i\f$ to the record that stores \f$v\f$ in field \f$l_i\f$ and is otherwise identical to \f$r\f$. Analogously, for each tuple type \f$[T_0, \ldots, T_n]\f$ and each \f$i=0, \ldots, n\f$, CVC3 provides the operator \f[ \_\ \mathrm{WITH}\ .i\ := \_ \f] \verbatim % Record updates Item: TYPE = [# key: INT, weight: REAL #]; x: Item = (# key := 23, weight := 43/10 #); x1: Item = x WITH .weight := 48; % Tuple updates Tup: TYPE = [REAL,INT,REAL]; y: Tup = ( 4/5, 9, 11/9 ); y1: Tup = y WITH .1 := 3; \endverbatim Updates to a nested component can be combined in a single WITH operator: \verbatim Cache: TYPE = ARRAY [0..100] OF [# addr: INT, data: REAL #]; State: TYPE = [# pc: INT, cache: Cache #]; s0: State; s1: State = s0 WITH .cache[10].data := 2/3; \endverbatim Note that, differently from updates on arrays, tuple and record updates are just additional syntactic sugar. For instance, the record x1 and tuple y1 defined above could have been equivalently defined as follows: \verbatim % Record updates Item: TYPE = [# key: INT, weight: REAL #]; x: Item = (# key := 23, weight := 43/10 #); x1: Item = (# key := x.key, weight := 48 #); % Tuple updates Tup: TYPE = [REAL,INT,REAL]; y: Tup = ( 4/5, 9, 11/9 ); y1: Tup = ( y.0, 3, y.1 ); \endverbatim \subsection user_doc_pres_lang_commands Commands In addition to declarations of types and constants, the CVC3 input language contains the following commands: - ASSERT \f$F\f$ -- Add the formula \f$F\f$ to the current logical context \f$\Gamma\f$. - QUERY \f$F\f$ -- Check if the formula \f$F\f$ is valid in the current logical context: \f$\Gamma\models_T F\f$. - CHECKSAT \f$F\f$ -- Check if the formula is satisfiable in the current logical context: \f$\Gamma\cup\{F\} \not\models_T \mathit{false}\f$. - WHERE -- Print all the assumptions in the current logical context \f$\Gamma\f$. - COUNTEREXAMPLE -- After an invalid QUERY or satisfiable CHECKSAT, print the context that is a witness for invalidity/satisfiability. - COUNTERMODEL -- After an invalid QUERY or satisfiable CHECKSAT, print a model that makes the formula invalid/satisfiable. The model is in terms of concrete values for each free symbol. - CONTINUE -- Search for a counter-example different from the current one (after an invalid QUERY or satisfiable CHECKSAT). - RESTART \f$F\f$ -- Restart an invalid QUERY or satisfiable CHECKSAT with the additional assumption \f$F\f$. - PUSH -- Save (checkpoint) the current state of the system. - POP -- Restore the system to the state it was in right before the last call to PUSH - POPTO \f$n\f$-- Restore the system to the state it was in right before the most recent call to PUSH made from stack level \f$n\f$. Note that the current stack level is printed as part of the output of the WHERE command. - TRANSFORM \f$F\f$ -- Simplify \f$F\f$ and print the result. - PRINT \f$F\f$ -- Parse and print back the expression \f$F\f$. - OPTION option value -- Set the command-line option flag option to value. Note that option is given as a string enclosed in double-quotes and value as an integer. The remaining commands take a single argument, given as a string enclosed in double-quotes. - TRACE flag -- Turn on tracing for the debug flag flag. - UNTRACE flag -- Turn off tracing for the debug flag flag. - ECHO string -- Print string - INCLUDE filename -- Read commands from the file filename. Here, we explain some of the above commands in more detail. \subsubsection user_doc_pres_lang_commands_query QUERY The command QUERY \f$F\f$ invokes the core functionality of CVC3 to check the validity of the formula \f$F\f$ with respect to the assertions made thus far (\f$\Gamma\f$). \f$F\f$ should be a formula as described in \ref user_doc_pres_lang_expr. There are three possible answers. - When the answer is "Valid", this means that \f$\Gamma \models_T F\f$. After a valid query, the logical context \f$\Gamma\f$ is exactly as it was before the query. - When the answer is "Invalid", this means that \f$\Gamma \not\models_T F\f$. In other words, there is a model of \f$T\f$ satisfying \f$\Gamma \cup \{\neg F\}\f$. After an invalid query, the logical context \f$\Gamma\f$ is augmented with new literals \f$\Delta\f$ such that \f$\Gamma\cup\Delta\f$ is consistent in the theory \f$T\f$, but \f$\Gamma\cup\Delta\models_T \neg F\f$. In fact, in this case \f$\Gamma\cup\Delta\f$ propositionally satisfies \f$\neg f\f$. We call the new context \f$\Gamma\cup\Delta\f$ a counterexample for \f$F\f$. - An answer of "Unknown" is very similar to an answer of "Invalid" in that additional literals are added to the context which propositionally falsify the query formula \f$F\f$. The difference is that because CVC3 is incomplete for some theories, it cannot guarantee in this case that \f$\Gamma\cup\Delta\f$ is actually consistent in \f$T\f$. The only sources of incompleteness in CVC3 are non-linear arithmetic and quantifiers. Counterexamples can be printed out using WHERE or COUNTEREXAMPLE commands. WHERE always prints out all of \f$\Gamma\cup C\f$. COUNTEREXAMPLE may sometimes be more selective, printing a subset of those formulas from the context which are sufficient for a counterexample. Since the QUERY command may modify the current context, if you need to check several formulas in a row in the same context, it is a good idea to surround every QUERY command by PUSH and POP in order to preserve the context: \verbatim PUSH; QUERY ; POP; \endverbatim \subsubsection user_doc_pres_lang_commands_checksat CHECKSAT The command CHECKSAT \f$F\f$ behaves identically to QUERY \f$\neg F\f$. \subsubsection user_doc_pres_lang_commands_restart RESTART The command RESTART \f$F\f$ can only be invoked after an invalid query. For example: \verbatim QUERY ; Invalid. RESTART ; \endverbatim The behavior of the above command will be identical to the following: \verbatim PUSH; QUERY ; POP; ASSERT ; QUERY ; \endverbatim The advantage of using the RESTART command is that it may be much more efficient than the above command sequence. This is because when the RESTART command is used, CVC3 will re-use what it has learned rather than starting over from scratch. \subsection user_doc_pres_lang_patterns Instantiation Patterns CVC3 processes each universally quantified formula in the current context by generating instances of the formula obtained by replacing its universal variables with ground terms. Patterns restrict the choice of ground terms for the quantified variables, with the goal of controlling the potential explosion of ground instances. In essence, adding patterns to a formula is a way for the user to tell CVC3 to focus only on certain instances which, in the user's opinion, will be most helpful during a proof. In more detail, patterns have the following effect on formulas that are found in the logical context or get later added to it while CVC3 is trying to prove the validity of some formula \f$\varphi\f$. If a formula in the current context starts with an existential quantifier, CVC3 Skolemizes it, that is, replaces it in the context by the formula obtained by substituting the existentially quantified variables by fresh constants and dropping the quantifier. Any patterns for the existential quantifier are simply ignored. If a formula starts with a universal quantifier \f$\mathrm{FORALL}\; (x_1:T_1, \ldots, x_n:T_n)\f$, CVC3 adds to the context a number of instances of the formula---with the goal of using them to prove the query \f$\varphi\f$ valid. An instance is obtained by replacing each \f$x_i\f$ with a ground term of the same type occurring in one of the formulas in the context, and dropping the universal quantifier. If \f$x_i\f$ occurs in a pattern \f$\mathrm{PATTERN}\; (t_1, \ldots, t_m)\f$ for the quantifier, it will be instantiated only with terms obtained by simultaneously matching all the terms in the pattern against ground terms in the current context \f$\Gamma\f$. Specifically, the matching process produces one or more substitutions \f$\sigma\f$ for the variables in \f$(t_1, \ldots, t_m)\f$ which satisfy the following invariant: for each \f$i = 1, \ldots, m\f$, \f$\sigma(t_i)\f$ is a ground term and there is a ground term \f$s_i\f$ in \f$\Gamma\f$ such that \f$\Gamma \models_T \sigma(t_i) = s_i\f$. The variables of \f$(x_1:T_1, \ldots, x_n:T_n)\f$ that occur in the pattern are instantiated only with those substitutions (while any remaining variables are instantiated arbitrarily). The Skolemized version or the added instances of a context formula may themselves start with a quantifier. The same instantiation process is applied to them too, recursively. Note that the matching mechanism is not limited to syntactic matching but is modulo the equations asserted in the context. Because of decidability and/or efficiency limitations, the matching process is not exhaustive. CVC3 will typically miss some substitutions that satisfy the invariant above. As a consequence, it might fail to prove the validity of the query formula \f$\varphi\f$, which makes CVC3 incomplete for contexts containing quantified formulas. It should be noted though that exhaustive matching, which can be achieved simply by not specifying any patterns, does not yield completeness anyway since the instantiation of universal variables is still restricted to just the ground terms in the context (whereas in general additional ground terms might be needed). \subsection user_doc_pres_lang_subtypes Subtypes CVC3's language includes the definition of subtypes of value types by means of predicate subtyping. A subtype \f$T_p\f$ of a (sub)type \f$T\f$ is defined as a subset of \f$T\f$ that satisfies an associated predicate \f$p\f$. More precisely, if \f$p\f$ is a term of type \f$T \to \mathrm{BOOLEAN}\f$, then for every model of \f$p\f$ (among the models of CVC3's built-in theories), \f$T_P\f$ is the extension of \f$p\f$, that is, the set of all and only the elements of \f$T\f$ that satisfy the predicate \f$p\f$. Subtypes like \f$T_p\f$ above can be defined by the user with a declaration of the form: \f[ \mathit{subtype\_name}: \mathrm{TYPE} = \mathrm{SUBTYPE}(p) \f] where \f$p\f$ is either just a (previously declared) predicate symbol of type \f$T \to \mathrm{BOOLEAN}\f$ or a lambda abstraction of the form \f$\lambda x:T.\; \varphi\f$ where \f$\varphi\f$ is any CVC3 formula whose set of free variables contains at most \f$x\f$. Here are some examples of subtype declarations: \verbatim Animal: TYPE; fish : Animal; is_fish: Animal -> BOOLEAN; ASSERT is_fish(fish); % Fish is a subtype of Animal: Fish: TYPE = SUBTYPE(is_fish); shark : Fish; is_shark: Fish -> BOOLEAN; ASSERT is_shark(shark); % Shark is a subtype of Fish: Shark: TYPE = SUBTYPE(is_shark); % Subtypes of REAL AllReals: TYPE = SUBTYPE(LAMBDA (x:REAL): TRUE); NonNegReal: TYPE = SUBTYPE(LAMBDA (x:REAL): x >= 0); % Subtypes of INT DivisibleBy3: TYPE = SUBTYPE(LAMBDA (x:INT): EXISTS (y:INT): x = 3 * y); \endverbatim CVC3 provides integers as a built-in subtype \f$INT\f$ of \f$REAL\f$. \f$INT\f$ is a subtype and not a base type in order to allow mixed real/integer terms without having to use coercion functions such as \f$\mathrm{int\_to\_real}:\mathrm{INT} \to \mathrm{REAL}\f$ \f$\mathrm{real\_to\_int}:\mathrm{REAL} \to \mathrm{INT}\f$ between terms of the two types. It is built-in because it is not definable by means of a first-order predicate. Note that, with the syntax introduced so far, it seems that it may be possible to define empty subtypes, that is, subtypes with no values at all. For example: \verbatim NoReals: TYPE = SUBTYPE(LAMBDA (x:REAL): FALSE); \endverbatim However, any attempt to do this results in an error. This is because CVC3's logic assumes types are not empty. In fact, each time a subtype \f$S\f$ is declared CVC3 tries to prove that the subtype is non-empty; more precisely, that it is non-empty in every model of the current context. This is done simply by attempting to prove the validity of a formula of the form \f$\exists\, x:T.\; p(x)\f$ where \f$T\f$ is the value type of which \f$S\f$ is a subtype, and \f$p\f$ is the predicate defining \f$S\f$. If CVC3 succeeds, the declaration is accepted. If it fails, CVC3 will issue a type exception and reject the declaration. CVC3 might fail to prove the non-emptyness of a subtype either because the type is indeed empty in some models or because of CVC3's incompleteness over quantified formulas. Consider the following examples: \verbatim Animal: TYPE; is_fish: Animal -> BOOLEAN; % Fish is a subtype of Animal: Fish: TYPE = SUBTYPE(is_fish); Interval_0_1: TYPE = SUBTYPE(LAMBDA (x:REAL): 0 < x AND x < 1); % Subtypes of [REAL, REAL] StraightLine: TYPE = SUBTYPE(LAMBDA (x:[REAL,REAL]): 3*x.0 + 2*x.1 + 6 = 0); % Constant ARRAY subtype ConstArray: TYPE = SUBTYPE(LAMBDA (a: ARRAY INT OF REAL): EXISTS (x:REAL): FORALL (i:INT): a[i] = x); \endverbatim Each of these subtype declarations is rejected. For instance, the declaration of Fish is rejected because there are models of CVC3's background theory in which is_fish has an empty extension. To fix that it is enough to introduce a free constant of type Animal and assert that it is a Fish as we did above. In the case of Interval_0_1 and Straightline, however, the type is indeed non-empty in every model, but CVC3 is unable to prove it. In such cases, the user can help CVC3 by explicitly providing a witness value for the subtype. This is done with this alternative syntax for subtype declarations: \f[ \mathit{subtype\_name}: \mathrm{TYPE} = \mathrm{SUBTYPE}(p,t) \f] where \f$p\f$ is again a unary predicate and \f$t\f$ is a term (denoting an element) that satisfies \f$p\f$. The following subtype declarations with witnesses are accepted by CVC3. \verbatim % Subtypes of REAL with witness Interval_0_1: TYPE = SUBTYPE(LAMBDA (x:REAL): 0 < x AND x < 1, 1/2); StraightLine: TYPE = SUBTYPE(LAMBDA (x:[REAL,REAL]): 3*x.0 + 2*x.1 + 6 = 0, (0, -3)); \endverbatim We observe that the declaration of ConstArray in the first example is rightly rejected under the empty context because the subtype can be empty in some models. However, even under contexts that exclude this possibility CVC3 is still unable to to prove the subtype's non-emptyness. Again, a declaration with witness helps in this case. Example: \verbatim zero_array: ARRAY INT OF REAL; ASSERT FORALL (i:INT): zero_array[i] = 0; % At this point the context includes the constant array zero_array % and the declaration below is accepted. ConstArray: TYPE = SUBTYPE(LAMBDA (a: ARRAY INT OF REAL): EXISTS (x:REAL): FORALL (i:INT): a[i] = x, zero_array); \endverbatim Adding witnesses to declarations to overcome CVC3's incompleteness is an adequate, practical solution in most cases. For additional convenience (when defining array types, for example) CVC3 has a special syntax for specifying subtypes that are finite ranges of \f$INT\f$. This is however just syntactic sugar. \verbatim % subrange type FiniteRangeArray: TYPE = ARRAY [-10..10] OF REAL; % equivalent but less readable formulations FiniteRange: TYPE = SUBTYPE(LAMBDA (x:INT): -10 <= x AND x <= 10); FiniteRangeArray2: TYPE = ARRAY FiniteRange OF REAL; FiniteRangeArray3: TYPE = ARRAY SUBTYPE(LAMBDA (x:INT): -10 <= x AND x <= 10) OF REAL; \endverbatim \subsubsection user_doc_pres_lang_subtyping Subtype Checking The subtype relation between a subtype and its immediate supertype is transitive. This implies that every subtype is a subtype of some value type, and so every term can be given a unique value type. This is important because as far as type checking is concerned, subtypes are ignored by CVC3. By default, static type checking is enforced only at the level of maximal supertypes, and subtypes play a role only during validity checking. In essence, for every ground term of the form \f$f(t_1, \ldots, t_n)\f$ with \f$i \geq 0\f$ in the logical context, whenever \f$f\f$ has type \f$(S_1, \ldots, S_n) \to S\f$ where \f$S\f$ is a subtype defined by a predicate \f$p\f$, CVC3 adds to the context the assertion \f$p(f(t_1, \ldots, t_n))\f$ constraining \f$f(t_1, \ldots, t_n)\f$ to be a value in \f$S\f$. This leads to correct answers by CVC3, provided that all ground terms are well-subtyped in the logical context of the query; that is, if for all terms like \f$f(t_1, \ldots, t_n)\f$ above the logical context entails that \f$t_i\f$ is a value of \f$S_i\f$. When that is not the case, CVC3 may return spurious countermodels to a query, that is, countermodels that do not respect the subtyping constraints. For example, after the following declarations: \verbatim Pos: TYPE = SUBTYPE(LAMBDA (x: REAL): x > 0, 1); Neg: TYPE = SUBTYPE(LAMBDA (x: REAL): x < 0, -1); a: Pos; b: REAL; f: Pos -> Neg = LAMBDA (x:Pos): -x; \endverbatim CVC3 will reply "Valid", as it should, to the command: \verbatim QUERY f(a) < 0; \endverbatim However it will reply "Invalid" to the command: \verbatim QUERY f(b) < 0; \endverbatim or to: \verbatim QUERY f(-4) < 0; \endverbatim for that matter, instead of complaining in either case that the query is not well-subtyped. (The query is ill-subtyped in the first case because there are models of the empty context in which the constant b is a non-positive rational; in the second case because in all models of the context the term -4 is non-positive.) In contrast, the command sequence \verbatim ASSERT b > 2*a + 3; QUERY f(b) < 0; \endverbatim say, produces the correct expected answer because in this case b is indeed positive in every model of the logical context. Semantically, CVC3's behavior is justified as follows. Consider, just for simplicity (the general case is analogous), a function symbol \f$f\f$ of type \f$S_1 \to T_2\f$ where \f$S_1\f$ is a subtype of some value type \f$T_1\f$. Instead of interpreting \f$S_1\f$ as partial function that is total over \f$S_1\f$ and undefined outside \f$S_1\f$, CVC3's interprets it as a total function from \f$T_1\f$ to \f$T_2\f$ whose behavior outside \f$S_1\f$ is specified in an arbitrary, but fixed, way. The specification of the behavior outside \f$S_1\f$ is internal to CVC3 and can, from case to case, go from being completely empty, which means that CVC3 will allow any possible way to extend \f$f\f$ from \f$S_1\f$ to \f$T_1\f$, to strong enough to allow only one way to extend \f$f\f$. The choice depends just on internal implementation considerations, with the understanding that the user is not really interested in \f$f\f$'s behavior outside \f$S_1\f$ anyway. A simple example of this approach is given by the arithmetic division operation /. Mathematically division is a partial function from \f$\mathrm{REAL} \times \mathrm{REAL}\f$ to \f$\mathrm{REAL}\f$ undefined over pairs in \f$\mathrm{REAL} \times \{0\}\f$. CVC3 views / as a total function from \f$\mathrm{REAL} \times \mathrm{REAL}\f$ to \f$\mathrm{REAL}\f$ that maps pairs in \f$\mathrm{REAL} \times \{0\}\f$ to \f$0\f$ and is defined as usual otherwise. In other words, CVC3 extends the theory of rational numbers with the axiom \f$\forall\; x:\mathrm{REAL}.\; x/0 = 0\f$. Under this view, queries like \verbatim x: REAL; QUERY x/0 = 0 ; QUERY 3/x = 3/x ; \endverbatim are perfectly legitimate. Indeed the first formula is valid because in each model of the empty context, x/0 is interpreted as zero and = is interpreted as the identity relation. The second formula is valid, more generally, because for each interpretation of x the two arguments of = will evaluate to the same rational number. CVC3 will answer accordingly in both cases. While this behavior is logically correct, it may be counter-intuitive to users, especially in applications that intend to give CVC3 only well-subtyped formulas. For these applications it is more useful to the user to get a type error from CVC3 as soon as it receives an ill-subtyped assertion or query, such as for instance the two queries above. This feature is provided in CVC3 by using the command-line option +tcc. The mechanism for checking well-subtypedness is described below. \subsubsection user_doc_pres_lang_tccs Type Correctness Conditions CVC3 uses an algorithm based on Type Correctness Conditions, TCCs for short, to determine if a term or formula is well-subtyped. This of course requires first an adequate notion of well-subtypedness. To introduce that notion, let us start with the following definition where \f$T\f$ is the union of CVC3's background theories. Let us say that a (well-typed) term \f$t\f$ containing no proper subterms of type \f$\mathrm{BOOLEAN}\f$ is well-subtyped in a model \f$M\f$ of \f$T\f$ (assigning an interpretation to all the free symbols and free variables of \f$t\f$) if - \f$t\f$ is a constant or a variable, or - it is of the form \f$f(t_1, \ldots, t_n)\f$ where \f$f\f$ has type \f$(S_1, \ldots, S_n) \to S\f$ and each \f$t_i\f$ is well-subtyped in \f$M\f$ and interpreted as a value of \f$S_i\f$. Note that this inductive definition includes the case in which the term is an atomic formula. Then we can say that an atomic formula is well-subtyped in a logical context \f$\Gamma\f$ if it is well-subtyped in every model of \f$\Gamma\f$ and \f$T\f$. While this seems like a sensible definition of well-subtypedness for atomic formulas, it is not obvious how to extend it properly to non-atomic formulas. For example, defining a non-atomic formula to be well-subtyped in a model if all of its atoms are well-subtyped is too stringent. Perfectly reasonable formulas like \f[ y > 0 \;\Rightarrow\; x/y = z \f] with \f$x\f$, \f$y\f$, and \f$z\f$ free constants (or free variables) of type \f$\mathrm{REAL}\f$, say, would not be well-subtyped in the empty context because there are models of \f$T\f$ in which the atom \f$x/y = z\f$ is not well-subtyped (namely, those that interpret \f$y\f$ as zero). A better definition can be given by treating logical connectives non-strictly with respect to ill-subtypedness. More formally, but considering for simplicity only formulas built with atoms, negation and disjunction connectives, and existential quantifiers (the missing cases are analogous), we define a non-atomic formula \f$\phi\f$ to be well-subtyped in a model \f$M\f$ of \f$T\f$ if one of the following holds: - \f$\phi\f$ has the form \f$\lnot \phi_1\f$ and \f$\phi_1\f$ is well-subtyped in \f$M\f$; - \f$\phi\f$ has the form \f$\phi_1 \lor \phi_2\f$ and (i) both \f$\phi_1\f$ and \f$\phi_2\f$ are well-subtyped in \f$M\f$ or (ii) \f$\phi_1\f$ holds and is well-subtyped in \f$M\f$ or (iii) \f$\phi_2\f$ holds and is well-subtyped in \f$M\f$; - \f$\phi\f$ has the form \f$\exists\:x.\; \phi_1\f$ and (i) \f$\phi_1\f$ holds and is well-subtyped in some model \f$M'\f$ that differs from \f$M\f$ at most in the interpretation of \f$x\f$ or (ii) \f$\phi_1\f$ is well-subtyped in every such model \f$M'\f$. In essence, this definition is saying that for well-subtypedness in a model it is irrelevant if a formula \f$\phi\f$ has an ill-subtyped subformula, as long as the truth value of \f$\phi\f$ is independent from the truth value of that subformula. Now we can say in general that a CVC3 formula is well-subtyped in a context \f$\Gamma\f$ if it is well-subtyped in every model of \f$\Gamma\f$ and \f$T\f$. According to this definition, the previous formula \f$y > 0 \;\Rightarrow\; x/y = z\f$, which is equivalent to \f$\lnot(y > 0) \;\lor\; x/y = z\f$, is well-subtyped in the empty context. In fact, in all the models of \f$T\f$ that interpret \f$y\f$ as zero, the subformula \f$\lnot(y > 0)\f$ is true and well-subtyped; in all the others, both \f$\lnot(y > 0)\f$ and \f$x/y = z\f$ are well-subtyped. This notion of well-subtypedness has a number of properties that make it fairly robust. One is that it is invariant with respect to equivalence in a context: for every context \f$\Gamma\f$ and formulas \f$\phi, \phi'\f$ such that \f$\Gamma \models_T \phi \Leftrightarrow \phi'\f$, the first formula is well-subtyped in \f$\Gamma\f$ if and only if the second is. Perhaps the most important property, however, is that the definition can be effectively reflected into CVC3's logic itself: there is a procedure that for any CVC3 formula \f$\phi\f$ can compute a well-subtyped formula \f$\Delta_\phi\f$, a type correctness condition for \f$\phi\f$, such that \f$\phi\f$ is well-subtyped in a context \f$\Gamma\f$ if and only if \f$\Gamma \models_T \Delta_\phi\f$. This has the nice consequence that the very inference engine of CVC3 can be used to check the well-subtypedness of CVC3 formulas. When called with the TCC option on (by using the command-line option +tcc), CVC3 behaves as follows. Whenever it receives an ASSERT or QUERY command, the system computes the TCC of the asserted formula or query and checks its validity in the current context (for ASSERTs, before the formula is added to the logical context). If it is able to prove the TCC valid, it just adds the asserted formula to the context or checks the validity of the query formula. If it is unable to prove the TCC valid, it raises an ill-subtypedness exception and aborts. It is worth pointing out that, since CVC3 checks the validity of an asserted formula in the current logical context at the time of the assertion, the order in which formulas are asserted makes a difference. For instance, attempting to enter the following sequence of commands: \verbatim f: [0..100] -> INT; x: [5..10]; y: REAL; ASSERT f(y + 3/2) < 15; ASSERT y + 1/2 = x; \endverbatim results in a TCC failure for the first assertion because the context right before it does not entail that the term y + 3/2 is in the range 0..100. In contrast, the sequence \verbatim f: [0..100] -> INT; x: [5..10]; y: REAL; ASSERT y + 1/2 = x; ASSERT f(y + 3/2) < 15; \endverbatim is accepted because each of the formulas above is well-subtyped at the time of its assertion. Note that the assertion of both formulas together in the empty context with \verbatim ASSERT f(y + 3/2) < 15 AND y + 1/2 = x \endverbatim or with \verbatim ASSERT y + 1/2 = x AND f(y + 3/2) < 15 \endverbatim is also accepted because the conjunction of the two formulas is well-subtyped in the empty context. \section user_doc_smtlib_lang SMT-LIB Input Language CVC3 is able to read and execute queries in the SMT-LIB format. Specifically, when called with the option -lang smt it accepts as input an SMT-LIB benchmark belonging to one of the SMT-LIB sublogics. For a well-formed input benchmark, CVC3 returns the string "sat", "unsat" or "unknown", depending on whether it can prove the benchmark satisfiable, unsatisfiable, or neither. At the time of this writing CVC3 supported all SMT-LIB sublogics. We refer the reader to the SMT-LIB website for information on SMT-LIB, its formats, its logics, and its on-line library of benchmarks. */ cvc3-2.4.1/doc/theory_api_flow.fig0000664000175400017540000001214510466450544016717 0ustar mdetersmdeters#FIG 3.2 Landscape Center Inches Letter 100.00 Single -2 1200 2 5 1 1 1 0 7 50 0 -1 4.000 0 0 1 0 8315.625 4800.000 8175 4725 8475 4800 8175 4875 2 1 1.00 60.00 120.00 5 1 1 1 0 7 50 0 -1 4.000 0 0 1 0 8315.625 5250.000 8175 5175 8475 5250 8175 5325 2 1 1.00 60.00 120.00 6 3150 4500 4650 5550 2 2 0 1 0 7 50 0 -1 0.000 0 0 -1 0 0 5 3150 4500 4650 4500 4650 5550 3150 5550 3150 4500 4 0 0 50 0 0 16 0.0000 4 210 915 3442 5085 addFact()\001 -6 6 2250 3075 3675 3975 6 2325 3300 3525 3825 4 0 0 50 0 0 16 0.0000 4 165 1140 2362 3487 Union-Find\001 4 0 0 50 0 0 16 0.0000 4 165 885 2362 3772 Database\001 -6 2 4 0 1 0 7 50 0 -1 0.000 0 0 7 0 0 5 3637 3975 3637 3075 2287 3075 2287 3975 3637 3975 -6 6 3150 6150 4575 6450 2 2 0 1 0 7 50 0 -1 0.000 0 0 -1 0 0 5 3150 6450 4575 6450 4575 6150 3150 6150 3150 6450 4 0 0 50 0 0 12 0.0000 4 180 795 3465 6345 fact queue\001 -6 6 2175 2325 3975 2700 2 2 0 1 0 7 50 0 -1 0.000 0 0 -1 0 0 5 2175 2325 3975 2325 3975 2700 2175 2700 2175 2325 4 0 0 50 0 0 12 0.0000 4 180 825 2662 2557 Notify List\001 -6 6 3825 2925 5250 4125 6 4200 3300 4875 3825 4 0 0 50 0 0 16 0.0000 4 165 465 4237 3487 SAT\001 4 0 0 50 0 0 16 0.0000 4 165 600 4237 3772 solver\001 -6 2 3 0 1 0 7 50 0 -1 0.000 0 0 0 0 0 7 5212 3525 4874 2940 4200 2940 3862 3525 4200 4110 4874 4110 5212 3525 -6 6 9225 3825 10425 4425 4 0 0 50 0 0 20 0.0000 4 195 990 9262 4087 Decision\001 4 0 0 50 0 0 20 0.0000 4 195 1155 9262 4417 Procedure\001 -6 2 1 0 3 0 7 50 0 -1 0.000 0 0 -1 1 0 4 2 1 2.00 60.00 120.00 4650 4650 6375 4650 6375 3750 8175 3750 2 1 0 3 0 7 50 0 -1 0.000 0 0 -1 1 0 5 2 1 2.00 60.00 120.00 9000 5700 9000 7275 5250 7275 5250 6300 4575 6300 2 1 0 1 0 7 50 0 -1 4.000 0 0 -1 1 0 5 2 1 1.00 60.00 120.00 3150 6300 2925 6300 2925 5925 3900 5925 3900 5550 2 1 0 1 0 7 50 0 -1 4.000 0 0 -1 1 0 2 2 1 1.00 60.00 120.00 3300 4500 3300 3975 2 1 0 1 0 7 50 0 -1 4.000 0 0 -1 1 0 2 2 1 1.00 60.00 120.00 4500 4500 4500 4125 2 1 0 1 0 7 50 0 -1 4.000 0 0 -1 1 0 2 2 1 1.00 60.00 120.00 3000 3075 3000 2700 2 1 0 3 0 7 50 0 -1 0.000 0 0 -1 1 0 5 2 1 2.00 60.00 120.00 9600 5700 9600 7575 2550 7575 2550 5325 3150 5325 2 1 1 1 0 7 50 0 -1 4.000 0 0 -1 1 0 5 2 1 1.00 60.00 120.00 10275 5700 10275 7950 2100 7950 2100 4950 3075 4950 2 1 0 1 0 7 50 0 -1 4.000 0 0 -1 1 0 4 2 1 1.00 60.00 120.00 4650 4800 6600 4800 6600 4275 8175 4275 2 1 0 1 0 7 50 0 -1 4.000 0 0 -1 1 0 4 2 1 1.00 60.00 120.00 4650 5025 6825 5025 6825 4725 8175 4725 2 1 0 1 0 7 50 0 -1 4.000 0 0 -1 1 0 4 2 1 1.00 60.00 120.00 3150 2325 3150 450 10425 450 10425 2625 2 1 1 1 0 7 50 0 -1 4.000 0 0 -1 1 0 4 2 1 1.00 60.00 120.00 4800 2925 4800 1500 8700 1500 8700 2625 2 1 0 1 0 7 50 0 -1 4.000 0 0 -1 1 0 2 2 1 1.00 60.00 120.00 4650 5250 8175 5250 2 1 0 1 0 7 50 0 -1 4.000 0 0 -1 1 0 2 2 1 1.00 60.00 120.00 4650 5475 8175 5475 2 1 1 1 0 7 50 0 -1 4.000 0 0 -1 1 0 3 2 1 1.00 60.00 120.00 8175 5475 10950 5475 10950 5700 2 1 0 1 0 7 50 0 -1 4.000 0 0 -1 1 0 5 2 1 1.00 60.00 120.00 10950 5700 10950 8250 1725 8250 1725 2550 2175 2550 2 1 0 3 0 7 50 0 -1 0.000 0 0 -1 1 0 4 2 1 2.00 60.00 120.00 4575 2925 4575 1125 9300 1125 9300 2625 2 1 0 3 0 7 50 0 -1 0.000 0 0 -1 1 0 4 2 1 2.00 60.00 120.00 4350 2925 4350 825 9750 825 9750 2625 2 2 1 3 0 6 60 0 36 8.000 0 0 -1 0 0 5 1350 1725 6150 1725 6150 6900 1350 6900 1350 1725 2 2 1 3 0 6 60 0 36 8.000 0 0 -1 0 0 5 8175 2625 11550 2625 11550 5700 8175 5700 8175 2625 2 1 0 1 0 7 50 0 -1 0.000 0 0 -1 1 0 2 2 1 1.00 60.00 120.00 75 4725 3150 4725 2 1 0 3 0 7 50 0 -1 0.000 0 0 -1 1 0 6 2 1 1.00 60.00 120.00 8400 5700 8400 6075 5250 6075 5250 5925 4350 5925 4350 5550 2 1 1 1 0 7 50 0 -1 4.000 0 0 -1 1 0 4 2 1 1.00 60.00 120.00 4650 4575 6000 4575 6000 3375 8175 3375 2 1 1 1 0 7 50 0 -1 4.000 0 0 -1 1 0 8 2 1 1.00 60.00 120.00 8625 5700 8625 6450 5625 6450 5625 6225 5100 6225 5100 6075 4125 6075 4125 5550 2 1 1 1 0 7 50 0 -1 4.000 0 0 -1 1 0 4 2 1 1.00 60.00 120.00 8175 3375 8625 3375 9150 4575 8625 5700 2 1 1 1 0 7 50 0 -1 4.000 0 0 -1 1 0 4 2 1 1.00 60.00 120.00 8175 3750 8400 3750 8775 4650 8400 5700 4 0 0 50 0 0 20 0.0000 4 195 555 1575 2250 Core\001 4 0 0 50 0 0 14 0.0000 4 195 1350 6525 3675 computeType()\001 4 0 0 50 0 0 14 0.0000 4 195 1275 7575 7200 enqueueFact()\001 4 0 0 50 0 0 14 0.0000 4 195 1455 7575 7500 setInconsistent()\001 4 0 0 50 0 0 14 0.0000 4 195 1590 7575 7875 enqueueEquality()\001 4 0 0 50 0 0 14 0.0000 4 195 1560 6675 4200 addSharedTerm()\001 4 0 0 50 0 0 14 0.0000 4 195 780 7050 4650 rewrite()\001 4 0 0 50 0 0 14 0.0000 4 195 600 7200 5100 solve()\001 4 0 0 50 0 0 14 0.0000 4 195 1680 7125 1425 notifyInconsistent()\001 4 0 0 50 0 0 14 0.0000 4 195 1065 8775 675 assertFact()\001 4 0 0 50 0 0 14 0.0000 4 195 960 8025 1050 checkSat()\001 4 0 0 50 0 0 14 0.0000 4 195 735 9525 375 update()\001 4 0 0 50 0 0 14 0.0000 4 195 615 7200 5625 setup()\001 4 0 0 50 0 0 14 0.0000 4 195 1785 7575 8175 Expr::addToNotify()\001 4 0 0 50 0 0 14 0.0000 4 195 840 150 4650 user input\001 4 0 0 50 0 0 12 0.0000 4 180 1140 6525 3300 computeTCC()\001 4 0 0 50 0 0 12 0.0000 4 180 735 7200 6375 getTCC()\001 4 0 0 50 0 0 12 0.0000 4 180 2055 6225 6000 getType() / getBaseType()\001 cvc3-2.4.1/INSTALL0000664000175400017540000004636611443757411013335 0ustar mdetersmdeters/*! \page INSTALL INSTALL Contents:
  • \ref quickstart
  • \ref requirements
  • \ref advanced
  • \ref installing
  • \ref documentation
  • \ref faq
  • \ref help
\section quickstart Quick Start You can download a source distribution of %CVC3 from the CVC3 downloads page. Save the source archive as cvc3.tar.gz in the directory of your choice and extract the contents using your favorite archive program (you can use tar xzvf cvc3.tar.gz from a terminal). This will create a directory containing the source of %CVC3, normally called cvc3-XXX. In the following we will denote the this directory as $CVC3_SRC. To build %CVC3, open your favorite terminal program and run the following sequence of commands
   cd $CVC3_SRC
   ./configure
   make
If any part of the build process fails, please read the following section for more information. A successful build will create a library libcvc3 in the $CVC3_SRC/lib directory, and an executable cvc3 in the $CVC3_SRC/bin directory (these are symbolic links to the actual files which are stored in architecture- and configuration-dependent subdirectories). The directory $CVC3_SRC/test contains an example program using the %CVC3 library libcvc3. To try it out, run the following commands in the terminal:
   cd test
   make
   bin/test
By default, make will build optimized code, static libraries, and a static executable. To build the "debug" version (much slower but with more error checking) use the following configuration command instead:
   ./configure --with-build=debug
In case you prefer to build shared libraries (and thus a much smaller executable), use the following configuration command:
  ./configure --enable-dynamic
If you do choose to buld the shared libraries, you must set your LD_LIBRARY_PATH environment variable to $CVC3_SRC/lib before running %CVC3 or using the shared libraries. Alternatively, these and other options can be changed by editing the Makefile.local file after running configure. However, be aware that re-running configure will overwrite any changes you have made to Makefile.local. \section requirements Requirements %CVC3 has the following build dependencies:
  • GCC version 3.0 or later
  • Bash
  • Flex
  • Bison
  • GMP (recommended)
  • A Python interpreter (optional, for Java support)
  • A Java compiler (optional, for Java support)
All of these tools are available from common package repositories (e.g., Debian, Ubuntu, Red Hat, Cygwin). \section advanced Advanced Configuration The configure script checks for the components needed to build %CVC3. If for some reason, the configure script is missing or doesn't run on your platform, you can recreate it from configure.ac by running autoconf. As the configure script runs, if something is not found, it complains. configure looks for components in standard locations and also uses several environment variables that you can set to help it find things. In particular, you can set CPPFLAGS to "-I $includeDir" if you have headers in a nonstandard directory $includeDir, and LDFLAGS to "-L $libDir" if you have libraries in a nonstandard directory $libDir. Alternatively you can pass these directories to the configure script using the following command
    ./configure --with-extra-includes=$includeDir --with-extra-libs=$libDir
Run ./configure --help for a list of all such environment variables and options.

GMP

One of the components %CVC3 depends on is the GNU Multiple Precision (GMP) library. Many Unix-like distributions include gmp packages. If you do not have GMP installed or your installation does not work, we recommend that you install it manually: 1. Download the GMP source code from http://gmplib.org/ 2. Unpack the sources, and from the root-directory of the GMP source code, run
   ./configure 
   make
On some Solaris machines, you may need to configure GMP with
   ./configure ABI=32
to make the resulting GMP library compatible with the %CVC3 libraries. The reason for this is that the default ABI that gcc chooses in %CVC3 compilation is not necessarily the default ABI that the GMP configure script selects, and one of them may need to be adjusted. 3. Now, either install GMP system-wide (make install), or supply the appropriate values for CPPFLAGS and LDFLAGS to the %CVC3 configure script. If for some reason, you do not want to use GMP, you can configure %CVC3 to use native arithmetic by running:
   ./configure --with-arith=native
If you compile %CVC3 with native arithmetic, it is possible that %CVC3 may fail as the result of arithmetic overflow. If an overflow occurs, you will get an error message and %CVC3 will abort.

Java interface

Note: The Java interface is experimental. The API may change in future releases. To build the Java interface to %CVC3, use the --enable-java configuration option. The configuration script refers to the environment variables JAVAC, JAVAH, JAR, and CXX to set up the standard Java and C++ compiler commands. It refers to the environment variable JFLAGS for default Java compiler flags. It refers to the variable javadir for the installation directory of the CVC3 Java library. The configuration options --with-java-home and --with-java-includes can be used to specify the path to the directories containing the JDK installation and JNI header files, respectively. You must build %CVC3 as a dynamic library to use the Java interface. For example, you might configure the build by running the following in the top-level %CVC3 directory:
    ./configure --enable-dynamic --enable-java
Note: The Java interface depends on the "build type" (e.g., "optimized", "debug") of %CVC3. If you choose to re-configure and re-build %CVC3 with a different build type, you must run "make clean" in the current directory and re-build the interface (cleaning and rebuilding the entire %CVC3 package will suffice).

Using the Java interface

To access the library, you must add the file libcvc3-X.Y.Z.jar (where "X.Y.Z" is the CVC3 version) to the classpath (e.g., by setting the CLASSPATH environment variable) and both libcvc3.so and libcvc3jni.so to the runtime library path (e.g., by setting the LD_LIBRARY_PATH environment variable java.library.path JVM variable). For example, to compile the class Client.java:
    javac -cp lib/libcvc3-X.Y.Z.jar Client.java
To run:
  export LD_LIBRARY_PATH=/path/to/cvc3/libs
  java -Djava.library.path=/path/to/cvc3/libs -cp lib/libcvc3-X.Y.Z.jar Client

Mac OS X

Mac OS X uses DYLD_LIBRARY_PATH in place of LD_LIBRARY_PATH. On Intel Macs, by default, %CVC3 compiles in 32-bit or 64-bit mode based on the compiler's default. If you want to build as one or the other in particular (for example, to match your libgmp installation), put CXXFLAGS=-m32 (and JREFLAGS=-d32, if you are compiling the Java bindings) in the environment when you run configure. To run regression testing (make regress), you'll need GNU time. We suggest you install MacPorts (from macports.org) and then the "gtime" package. You'll need also a libgmp installation. libgmp can be downloaded from gmplib.org. If you install it in a nonstandard location (with ./configure --prefix=...) you'll need to give this location to CVC3 when you configure it: ./configure --with-extra-includes=...--with-extra-libs=... or it may not find your installation of libgmp.

Cygwin

In order to use GMP on Cygwin, make sure the following packages are installed: gmp, libgmp-devel, libgmp3, bison, flex, and make, as well as standard UNIX tools. On Windows, it's common to have directory names with embedded spaces. This can be problematic for the CVC3 build system. Therefore on Cygwin we recommend symbolically linking to names without embedded spaces, something like the following:
  $ pwd
  /home/ACSys Group
  $ ln -s 'ACSys Group' /home/acsys
  $ export HOME=/home/acsys
  $ cd
  $ pwd
  /home/acsys
  $ cd cvc3
  $ ./configure --prefix=/home/acsys/cvc3.installation ...etc...
On Windows, Sun's JDK doesn't install the Java compiler "javac" into the standard path for executables. If you want to build Java bindings, you'll need to point CVC3 to it. Again using symbolic linking as above:
  $ pwd
  /home/acsys/cvc3
  $ ln -s '/cygdrive/c/Program Files' /programs
  $ ./configure --enable-java --with-java-home=/programs/Java/jdk1.6.0_16 ...
Such symbolic linking (and in general using cygwin full paths) may cause problems with non-cygwin programs. In particular, if you have Windows emacs installed (instead of cygwin's emacs), you have a version of etags that may give errors at the end of the install. These errors (about source files not existing when in fact they do) shouldn't break the build (make won't complain and bomb out; it's just that these are at the very end of the build, so it looks like they are causing problems) and can be safely ignored.

64-bit Platforms

When building %CVC3 on 64-bit platforms, you must compile %CVC3 in the same mode as any libraries it uses. For example, if GMP is compiled in 64-bit mode, then %CVC3 must compiled in 64-bit mode as well. The configuration script will try to infer the correct compilation settings. You can run ./config.guess to see the default platform type: $ ./config.guess i686-pc-linux-gnu You can use the --build argument to configure to override the default. For example, to compile in 64-bit mode on a x86-64 CPU, you can use ./configure --build=x86_64-pc-linux-gnu.

LLVM

Note: Compiling %CVC3 with LLVM is not supported and may cause runtime errors. To compile with LLVM, run configure with the options:
./configure CXX=llvm-gcc LIBS='-lstdc++'

Other Configuration Options

Other configuration options include where to install the results of "make install" (see below), what type of build to use (optimized, debug, gprof, or gcov), and whether to use static or dynamic libraries. For help on these options, type
 
./configure --help 
configure creates the file Makefile.local which stores all of the configuration information. If you want to customize your build without re-running configure, or if you want to customize it in a way that configure does not allow, you can do it by editing Makefile.local. For example, you can build a debug, gprof version by editing Makefile.local and setting OPTIMIZED to 0 and GPROF to 1 (by default, gprof runs with an optimized executable). Note that for most configuration options, the objects, libraries, and executables are stored in a configuration-dependent directory, with only symbolic links being stored in the main bin and lib directories. This allows you to easily maintain multiple configurations and multiple platforms using the same source tree.

Additional make options

To rebuild dependencies, type:
 
    make depend 
To remove just the executable or libraries in the current configuration, type:
 
    make spotty 
To remove in addition all object files and makefile dependencies for the current configuration, type:
 
    make clean 
To remove all files that are not part of the distribution (including all object, library, and executables built for any configuration or platform), type:
 
    make distclean 
To build a tarball distribution of the current source tree, type:
 
    make dist 
\section installing Installing CVC3 To install %CVC3 system-wide, (assuming you have already run configure) run:
    make install
Installation depends on two configuration options: prefix and exec_prefix. By default, both are set to /usr/local, but these can be overridden by specifying the correct arguments to configure or by editing Makefile.local. Installation copies all necessary header files to $prefix/include/cvc3. It installs the library libcvc3 in $exec_prefix/lib and the executable cvc3 in $exec_prefix/bin. By default, a static library and executable are installed. If you want to install shared library versions, configure for shared libraries as described above. \section documentation Documentation To build HTML documentation, run

   make doc

Then open doc/html/index.html in your favorite browser. \section faq Frequently Asked Questions

Configuration Errors

libgmp.a is not found

Make sure the GMP library is in your LD_LIBRARY_PATH and gmp.h is in your CPATH (or use the --with-extra-lib and --with-extra-include arguments to ./configure). If your paths are properly configured and you are compiling for a 64-bit architecture, you may have a 32/64-bit mismatch. Check the binary type of the GMP library using the file utility. For example, running file on a 32-bit Linux GMP shared library will return:
    $ file /usr/lib/libgmp.so.3.4.2
    /usr/lib/libgmp.so.3.4.2: ELF 32-bit LSB shared object, Intel 80386, version 1 (SYSV), dynamically linked, stripped
You can use the --build arguments to ./configure to set the target binary type for %CVC3. For example, ./configure --build=i686-linux-gnu or ./configure --build=x86_64-linux-gnu.

Unable to locate Java directories

Set the JAVA_HOME environment variable or use the --with-java-home argument to ./configure. Some typical JAVA_HOME settings are as follows (where X.Y.Z is the version number of the installed Java runtime).
Platform JAVA_HOME Notes
Debian/Ubuntu Linux /usr/lib/jvm/default-java Install the default-jre or default-jre-headless package
Fedora Linux /usr/java/jreX.Y.Z
Mac OS X /System/Library/Frameworks/JavaVM.framework/Home
Windows C:\\Program Files\\Java\\jdkX.Y.Z

Runtime Errors (CVC3 library)

Segmentation fault when running a dynamically-linked executable.

This can be caused by a mismatched "build type". The debug and optimized version of the %CVC3 shared library are not binary compatible. If you are linking against a debug version of the shared library, you must define the symbol _CVC3_DEBUG_MODE during compilation. E.g., add -D_CVC3_DEBUG_MODE to CXXARGS.

Fatal error: Mis-handled the ref. counting

This can be cause by a number of problems. Make sure that all Expr objects are out of scope or have been manually deleted before deleting the ValidityChecker.

Exception in thread "main" java.lang.UnsatisfiedLinkError: no cvc3jni in java.library.path

The Java runtime was not able to find the %CVC3 JNI library. Use java -Djava.library.path=PATH_TO_CVC3JNI, where PATH_TO_CVC3JNI is the directory containing the file libcvc3jni.so.

Exception in thread "main" java.lang.UnsatisfiedLinkError: libcvc3jni.so.x.y.z

The Java runtime was not able to satisfy the link dependencies of the %CVC3 JNI library. Make sure that the %CVC3 and GMP libraries are in your LD_LIBRARY_PATH. If your paths are properly configured and you are compiling for a 64-bit architecture, you may have a 32/64-bit mismatch. Make sure the JVM is running in the same mode as the %CVC3 library using the -d32 or -d64 argument to java.

On Mac: terminate called after throwing an instance of 'CVC3::TypecheckException'

This appears to be a bug in certain versions of GCC distributed by Apple. Upgrade to XCode 3.1.2 or later (GCC version "4.0.1 (Apple Inc. build 5490)") or configure with CXXFLAGS=-01. \section help Getting help If you find a problem with the instructions in this installation guide, please send email to cvc-bugs@cs.nyu.edu. */ cvc3-2.4.1/bin/0000775000175400017540000000000011630011320013011 5ustar mdetersmdeterscvc3-2.4.1/bin/run_tests.in0000664000175400017540000004224311265705475015425 0ustar mdetersmdeters#!@PERL@ -w # Run regression tests of a given level (default: 0, meaning # minimum amount of tests). The higher the regression level, the more # tests to run, and the harder they get. # Each test may contain information about its regression level, # expected outcome, expected runtime, whether it produces a proof, # etc. in the format given below. This script will scan the first 100 # lines of each test and try to collect this information. # If some info is not found, defaults are assumed. Default regression # level is 0, expected runtime is unbounded, outcome is undefined # (whatever it returns is OK), proof should be produced if outcome is # Valid, and if it is produced, it'll be verified. # Test info is given in the comments; here are examples # # %%% Regression level = 2 # %%% Result = Valid %% or Invalid, or Unknown # %%% Runtime = 10 %% in seconds # %%% Proof = yes %% or 'no', if it doesn't produce a proof # %%% Language = presentation %% or 'internal' # The number of '%' and following spaces can vary, case is not # important. Any text after the value is ignored. Any comments that # are not recognized are also ignored. use strict; my %optionsHelp = ("-h" => "Print this help and exit", "-v" => "Be verbose (default, opposite of -q)", "-q" => "Quiet mode (opposite of -v)", "-l n" => "Set regression level (default 0, the easiest level)", "+rt" => "Check that each test finishes within the specified runtime", "-rt" => "Do not check whether test finishes within the specified runtime (default)", # "+proofs" => "Produce and verify proofs", # "-proofs" => "Do not produce / verify proofs (default)", "-lang name" => "Use the named input language only (default=all)", "-t secs" => "Run each executable for at most 'secs' seconds [0 = no limit]", "-vc prog" => "Use \"prog\" to run tests (default=cvc3)", "-pfc prog" => "Use \"prog\" to run a proof checker (default=true)" ); my $usageString = "run_tests [ options ] [ test1 test2 ... ] [ -- [ command line options ] ] Run regression tests. Concrete test files or directories with test files should be specified by name with a full path or relative path to the current directory. If none specified, all subdirectories are searched for test files. Default running mode is overriden by test specs; test specs are overriden by command line options. Options: " . join("\n ", map { sprintf("%-9s %s", $_, $optionsHelp{$_}) } keys(%optionsHelp)); # Database of default values for options my %optionsDefault = ("level" => 0, "verbose" => 1, "rt" => 0, "proofs" => 0, "lang" => "all", "runpath" => "@TOP@/bin/", "vc" => "cvc3", # Program names "pfc" => "true", "testpath" => "@TOP@/testcases", "tempdir" => "/tmp", # max. number of lines to read from the testcase file # when looking for info comments "maxInfoLines" => 100, # Runtime limit; 0 = no limit "time" => 0, # Additional command line options "clOptions" => ""); # Database of command line options. Initially, they are undefined my %options = (); # The list of testcases to run my @testcases = (); # Temporary array for options my @clOptions = (); # State is either "own" or "prog", meaning that we're reading either # our own or prog's options. my $argState = "own"; for(my $i=0; $i <= $#ARGV; $i++) { if($argState eq "own") { if($ARGV[$i] eq "--") { $argState = "prog"; } elsif($ARGV[$i] eq "-h") { print($usageString, "\n"); exit 0; } elsif($ARGV[$i] eq "+rt") { $options{'rt'} = 1; } elsif($ARGV[$i] eq "-rt") { $options{'rt'} = 0; } elsif($ARGV[$i] eq "+proofs") { $options{'proofs'} = 1; } elsif($ARGV[$i] eq "-proofs") { $options{'proofs'} = 0; } elsif($ARGV[$i] eq "-v") { $options{'verbose'} = 1; } elsif($ARGV[$i] eq "-q") { $options{'verbose'} = 0; } elsif($ARGV[$i] eq "-lang") { if(++$i>$#ARGV) { print STDERR "Option -lang requires an argument.\n"; print STDERR "Run run_tests -h for help\n"; exit 1; } $options{'lang'} = $ARGV[$i]; } elsif($ARGV[$i] eq "-l") { if(++$i>$#ARGV) { print STDERR "Option -l requires an argument.\n"; print STDERR "Run run_tests -h for help\n"; exit 1; } $options{'level'} = $ARGV[$i]; } elsif($ARGV[$i] eq "-t") { if(++$i>$#ARGV) { print STDERR "Option -t requires an argument.\n"; print STDERR "Run run_tests -h for help\n"; exit 1; } $options{'time'} = $ARGV[$i]; } elsif($ARGV[$i] eq "-vc") { if(++$i>$#ARGV) { print STDERR "Option -vc requires an argument.\n"; print STDERR "Run run_tests -h for help\n"; exit 1; } $options{'vc'} = $ARGV[$i]; } elsif($ARGV[$i] eq "-pfc") { if(++$i>$#ARGV) { print STDERR "Option -pfc requires an argument.\n"; print STDERR "Run run_tests -h for help\n"; exit 1; } $options{'pfc'} = $ARGV[$i]; } else { # This must be a testcase name push @testcases, $ARGV[$i]; } } elsif($argState eq "prog") { push @clOptions, $ARGV[$i]; } else { die "BUG: Bad argState: $argState"; } } if($#clOptions >= 0) { $options{'clOptions'} = join(" ", map { "\"" . $_ . "\"" } @clOptions); } # Compute the value of the option: first check the command line # option, then the supplied database (by ref. as the second arg), then # default values database. If it cannot find definition, it is a bug, # and the script is stopped. sub getOpt { my ($name, $dbRef) = @_; return $options{$name} if(defined($options{$name})); return $dbRef->{$name} if(defined($dbRef) && defined($dbRef->{$name})); return $optionsDefault{$name} if(defined($optionsDefault{$name})); # Option value is not found die "getOpt($name): option is undefined"; } my $verbose = getOpt('verbose'); # Set the path my $systemPath = "."; if(defined($ENV{'PATH'})) { $systemPath = $ENV{'PATH'}; } $ENV{'PATH'} = getOpt('runpath') . ":" . $systemPath; if($verbose) { print "*********\n"; print("Regression level: ", getOpt('level'), "\n"); print("Language: ", getOpt('lang'), "\n"); print("Whether to produce / check proofs: ", (defined($options{'proofs'}))? (($options{'proofs'})? "yes" : "no") : "depends on testcase", "\n"); if(getOpt('time') > 0) { print("Time limit per test: ", getOpt('time'), " sec\n"); } print("PATH = ", $ENV{'PATH'}, "\n"); print "*********\n"; } my $tmpdir = getOpt('tempdir') . "/run_tests_tmp-$$"; my $currdir = `pwd`; my $prog = getOpt('vc'); my $pfc = getOpt('pfc'); my $level = getOpt('level'); my $lang = getOpt('lang'); my $rt = getOpt('rt'); # Read the first 'maxInfoLines' of the testcase and fetch information # from the comments sub getTestOpt { my ($name) = @_; # This is what we return my %db = (); open IN, $name or die "Cannot open $name: $?"; for(my $lines = getOpt('maxInfoLines'), my $str = ; defined($str) && $lines > 0; $lines--, $str = ) { if($str =~ /^(;|\s|%|\#)*Regression level\s*=\s*(\d+)/i) { $db{'level'} = $2; } if($str =~ /^(;|\s|%|\#)*Result\s*=\s*(Valid|Invalid|Satisfiable|Unsatisfiable|Unknown)/i) { $db{'result'} = lc $2; } if($str =~ /^( |\t)*:status\s*(unsat|sat|unknown)/i) { $db{'result'} = lc $2; } if($str =~ /^(;|\s|%|\#)*Runtime\s*=\s*(\d+)/i) { $db{'runtime'} = $2; } if($str =~ /^(;|\s|%|\#)*Proof\s*=\s*(yes|no)/i) { if($2 eq "yes") { $db{'proofs'} = 1; } else { $db{'proofs'} = 0; } } if($str =~ /^(;|\s|%|\#)*SAT mode\s*=\s*(on|off)/i) { if($2 eq "on") { $db{'sat'} = 1; } else { $db{'sat'} = 0; } } if($str =~ /^(;|\s|%|\#)*Language\s*=\s*(.*)$/i) { $db{'lang'} = lc $2; } if($str =~ /^(;|\s|%|\#)*Program Options\s*=\s*(.*)$/i) { $db{'clOptions'} = $2; } } close IN; # If regression level is not set, make it 3. So, if a lower level # is requested, only explicitly marked tests will be run. if(!defined($db{'level'})) { $db{'level'}=3; } # If the input language is not defined, guess it by extension if(!defined($db{'lang'})) { if($name =~ /\.(cvc|svc)$/) { $db{'lang'} = "presentation"; } elsif($name =~ /\.(li?sp)$/) { $db{'lang'} = "internal"; } elsif($name =~ /\.(smt)$/) { $db{'lang'} = "smtlib"; } } return %db; } # Total number of tests run my $testsTotal=0; # Total number of proofs checked by pfc my $proofsChecked=0; # Total number of tests with problems (each test is counted at most once) my $testsProblems=0; ### Database of results # It is a hash mapping problem keys to arrays of testcase names. # Only problematic testcase are inserted here. # Keys are: fail, result, proof, noproof (no proof generated when should), # time, timeTooMuch, lang (wrong language), # error (program reported errors, but didn't die) my %testsDB=(); # Search for a string element in the array ref, and return 1 if found, 0 if not sub findStringElement { my ($el, $aRef) = @_; foreach my $v (@{$aRef}) { if($v eq $el) { return 1; } } return 0; } # Add a testcase to the set of problematic runs. # Args: # test is the full or relative path to the test file # lang is the input language (not used currently) # problem is the name of the problem the testcase exhibits sub addProblem { my ($test, $lang, $problem) = @_; my $aRef = $testsDB{$problem}; if(!defined($aRef)) { $aRef=[ ]; } if(!findStringElement($test, $aRef)) { $testsDB{$problem} = [@{$aRef}, $test]; } } # Total running time my $totalTime = time; my $totalRunningTime = 0; my $defaultDir = `pwd`; $defaultDir =~ s/\n//; foreach my $testcase (@testcases) { chdir $defaultDir or die "Cannot chdir to $defaultDir: $?"; my @testcasesTmp = (); if(-f $testcase) { push @testcasesTmp, $testcase; } elsif(-d $testcase) { # Compute the list of files for testcases opendir(TESTS, $testcase) or die "Cannot open directory $testcase: $?"; @testcasesTmp = grep { /[.]([sc]vcl?|li?sp|smt)$/ && -f "$testcase/$_" } readdir(TESTS); closedir TESTS; @testcasesTmp = map { "$testcase/$_" } @testcasesTmp; } else { print("*** WARNING: cannot find testcase $testcase: ", "no such file or directory\n"); } for(my $i=0; $i<=$#testcasesTmp; $i++) { my $name = $testcasesTmp[$i]; my $file = "$defaultDir/$name"; my $hasProblem=0; if(!(-f $file)) { print "WARNING: no such file: $file\n"; next; } my %opt = getTestOpt($file); # Check regression level if(defined($opt{'level'}) && $level < $opt{'level'}) { # Regression level of this test is too high; skip it next; } # Print the testcase name print("===============================================\n", $testcasesTmp[$i], ":\n"); # Check the input language if (!defined($opt{'lang'})) { print "Unknown language, skipping $testcasesTmp[$i]\n"; $hasProblem=1; addProblem($name, $lang, 'lang'); next; } if($lang ne "all" && $lang ne $opt{'lang'}) { print "Wrong input language, skipping $testcasesTmp[$i]\n"; $hasProblem=1; addProblem($name, $lang, 'lang'); next; } my $checkProofs = getOpt('proofs', \%opt); my $expRuntime = $opt{'runtime'}; my $expResult = $opt{'result'}; my $clOptions = getOpt('clOptions', \%opt); my $language = $opt{'lang'}; # Print some testcase specific info if($verbose) { print("Language: $language\n"); print("Checking proofs: ", ($checkProofs)? "yes" : "no", "\n"); if($rt && defined($expRuntime)) { print("Expected runtime: ", $expRuntime, " sec\n"); } if(defined($expResult)) { print("Expected result: ", $expResult, "\n"); } if($clOptions =~ /\S/) { print("Program options: ", $clOptions, "\n"); } } # Create a temporary dir, but first delete it; there may be # junk there system("/bin/rm -rf $tmpdir"); mkdir $tmpdir or print "Cannot create directory $tmpdir\n"; chdir $tmpdir or die "Cannot chdir to $tmpdir: $?"; # Compute arguments my @progArgs = (); push @progArgs, ($checkProofs)? "+proofs" : "-proofs"; if($language ne "presentation") { push @progArgs, "-lang $language"; } push @progArgs, $clOptions; my $progArgs = join(" ", @progArgs); # Now, run the sucker my $timeMax = getOpt('time'); my $timeLimit = ($timeMax > 0)? "-t $timeMax" : ""; my $limits = "ulimit -c 0 -d 1000000 -m 1000000 ". "-s 50000 -v 1000000 $timeLimit"; # Windows ulimit dies if you pass -m $limits = "ulimit -c 0 -d 1000000 -s 50000 -v 1000000 $timeLimit" if `uname -o` eq 'Cygwin'; my $logging = ($verbose)? " 2>&1 | tee output" : "> output 2>&1"; my $timing = "'@TIME@' -f \"User+Sys Time: %U+%S\" "; if($verbose) { print "***\n"; print "Running '$prog' $progArgs < '$file'\n"; print "***\n"; } my $time = time; my $exitVal = system("$limits; $timing '$prog' $progArgs " . "< '$file' $logging"); $time = time - $time; # OK, let's see what happened $testsTotal++; # Printing runtime print "Elapsed Runtime: $time sec\n"; # Parsing the output open IN, "output" or die "Cannot open `pwd`/output: $?"; my $str; my $result=""; while(defined($str=)) { # Find at least one valid result if($result ne "valid" && $str =~ /^(Valid|In[Vv]alid|Satisfiable|Unsatisfiable|Unknown|unsat|sat|unknown)/) { $result=lc $1; } # Exit value may be masked by the shell pipe. Fish it # out from the output if($str =~ /^(Interrupted|Segmentation|Bus error|.*exception|.*Fatal error|.*std::bad_alloc)/) { $exitVal = $1; } if($str =~ /^User\+Sys Time: (\d+\.\d\d)\+(\d+\.\d\d)/) { $time = $1+$2; print "Program Runtime: $time"; $totalRunningTime = $totalRunningTime + $time; } } close IN; if($rt && defined($expRuntime)) { if($time > $expRuntime) { if($time > 10*$expRuntime) { print " MUCH"; addProblem($name, $lang, 'timeTooMuch'); } print " LONGER than expected: $expRuntime sec"; $hasProblem=1; addProblem($name, $lang, 'time'); } elsif(($expRuntime >= 4 && $expRuntime <= 15 && $time <= $expRuntime-2) || ($expRuntime > 15 && $time <= (17*$expRuntime)/20)) { if($time <= $expRuntime/2) { print " MUCH"; addProblem($name, $lang, 'timeTooFast'); } print " FASTER than expected: $expRuntime sec"; addProblem($name, $lang, 'timeFast'); $hasProblem=1; } } print "\n"; if($exitVal ne "0") { print "*** FAILED with exit code $exitVal\n"; $hasProblem=1; addProblem($name, $lang, 'fail'); } # Checking for errors # if($hasErrors) { # $hasProblem=1; # addProblem($name, $lang, 'error'); # print "ERRORS in the test\n"; # } # Printing result diagnostics if(defined($expResult)) { if($expResult ne $result) { $hasProblem=1; if($result eq "") { addProblem($name, $lang, 'fail'); print("FAILED (no result, expected $expResult)\n"); } else { addProblem($name, $lang, 'result'); print("WRONG RESULT (", $result, " instead of $expResult)\n"); } } else { print "Result is correct\n"; } } $testsProblems += $hasProblem; print("=============== End of testcase ===============\n"); } } $totalTime = time - $totalTime; print "\nStatistics:\n"; print "Total tests run: $testsTotal\n"; print "Total running time: $totalRunningTime sec\n"; print "Total elapsed time: $totalTime sec\n"; print "Total number of proofs checked: $proofsChecked\n"; print "Problematic cases: $testsProblems\n"; if($testsProblems > 0 && $verbose) { my $aref; print "\nDetailed Statistics:\n"; $aref=$testsDB{'fail'}; if(defined($aref)) { my @a = @{$aref}; printf("Failed tests [%d]:\n", $#a+1); foreach my $n (@a) { print " $n\n"; } } # $aref=$testsDB{'error'}; # if(defined($aref)) { # my @a = @{$aref}; # printf("Tests with errors [%d]:\n", $#a+1); # foreach my $n (@a) { print " $n\n"; } # } $aref=$testsDB{'result'}; if(defined($aref)) { my @a = @{$aref}; printf("Tests with wrong results [%d]:\n", $#a+1); foreach my $n (@a) { print " $n\n"; } } $aref=$testsDB{'proof'}; if(defined($aref)) { my @a = @{$aref}; printf("Tests with failed proofs [%d]:\n", $#a+1); foreach my $n (@a) { print " $n\n"; } } $aref=$testsDB{'noproof'}; if(defined($aref)) { my @a = @{$aref}; printf("Tests that should have proofs but don't [%d]:\n", $#a+1); foreach my $n (@a) { print " $n\n"; } } $aref=$testsDB{'timeFast'}; if(defined($aref)) { my @a = @{$aref}; printf("Tests running faster than expected [%d]:\n", $#a+1); foreach my $n (@a) { print " $n\n"; } } $aref=$testsDB{'timeTooFast'}; if(defined($aref)) { my @a = @{$aref}; printf("...including tests running at least twice as fast as expected [%d]:\n", $#a+1); foreach my $n (@a) { print " $n\n"; } } $aref=$testsDB{'time'}; if(defined($aref)) { my @a = @{$aref}; printf("Tests running longer [%d]:\n", $#a+1); foreach my $n (@a) { print " $n\n"; } } $aref=$testsDB{'timeTooMuch'}; if(defined($aref)) { my @a = @{$aref}; printf("...including tests running WAY too long [%d]:\n", $#a+1); foreach my $n (@a) { print " $n\n"; } } $aref=$testsDB{'lang'}; if(defined($aref)) { my @a = @{$aref}; printf("Tests with wrong input language [%d]:\n", $#a+1); foreach my $n (@a) { print " $n\n"; } } } # Delete temporary dir if there is one system("/bin/rm -rf $tmpdir"); exit ($testsProblems > 0 ? 2 : 0); cvc3-2.4.1/bin/unpack.in0000664000175400017540000000532011133167436014644 0ustar mdetersmdeters#!@PERL@ -w # Merges several static libraries (*.a) into a single library. Tries # to maintain the order of the members as it was in the original # libraries. Multiple members of the same name may be present in # different input libraries and correctly packaged. However, if # multiple members with the same name reside in the same input # library, only the last one will be used. use strict; my $usageString = "unpack.pl lib1.a lib2.a ... Unpacks all .o files from lib1.a, lib2.a, etc into and prints the list of .o files on the standard output"; if($#ARGV < 1) { print STDERR "temp dir and at least 1 input name must be given.\n"; print STDERR "$usageString\n"; exit 1; } my $tmpDir = $ARGV[0]; my @inFiles = @ARGV[1..$#ARGV]; my $currDir = `pwd`; $currDir =~ s/\n//g; # Create the database of members: mappings of each file to the # respective library name, and to the list of members in the original # order my %libName=(); my %members=(); my $countLibs=0; my $countMembers=0; # List of input files without repetition my @tmp = (); for(my $i=0; $i<=$#inFiles; $i++) { # Skip the library if we've seen it already if(!defined($libName{$inFiles[$i]})) { push @tmp, $inFiles[$i]; $countLibs++; if($inFiles[$i] =~ m/lib(\w+).a$/) { $libName{$inFiles[$i]} = $1; my $lines=`ar t '$inFiles[$i]'`; my @lines = split(/\n/, $lines); $countMembers += ($#lines + 1); $members{$inFiles[$i]} = [@lines]; } else { print STDERR "Weird library name: $inFiles[$i]; skipping it"; } } else { print STDERR "Repeated input (ignored): $inFiles[$i]\n"; } } print STDERR "Found $countMembers members in $countLibs libraries\n"; # Update the list of input files (remove repetitions) @inFiles = @tmp; # Given a possibly relative path, compute the full path sub fullPath { my ($name) = @_; if($name =~ m@^/@) { # It's already the full path return $name; } else { return "$currDir/$name"; } } # Unpack files and create the list of members with relative paths into tmpDir my @allMembers=(); mkdir($tmpDir, 0755) or die "Cannot create $tmpDir/: $?"; for(my $i=0; $i<=$#inFiles; $i++) { my $libName = $libName{$inFiles[$i]}; my $file = fullPath($inFiles[$i]); print STDERR "Unpacking $libName\n"; mkdir("$tmpDir/$libName", 0755) or die "Cannot create $tmpDir/$libName: $?"; system("cd '$tmpDir/$libName'; ar x '$file'") && die "Cannot extract from archive $file: $?"; my @names=@{$members{$inFiles[$i]}}; for(my $j=0; $j<=$#names; $j++) { if ($names[$j] =~ /^.*\.o/i) { push @allMembers, "'$tmpDir/$libName/$names[$j]'"; } } } # Create the list of all members my $allMembers = join(" ", @allMembers); print "$allMembers"; cvc3-2.4.1/bin/cvc2smt.in0000664000175400017540000003546310533133646014756 0ustar mdetersmdeters#!@PERL@ -w # Convert CVC to SMT format. This script was adapted from the CVC3 regression # script and thus has a lot of kruft, but it works. use strict; my %optionsHelp = ("-h" => "Print this help and exit", "-v" => "Be verbose (default, opposite of -q)", "-q" => "Quiet mode (opposite of -v)", "-lang name" => "Use the named input language only (default=all)", "-t secs" => "Run each executable for at most 'secs' seconds [0 = no limit]", "-vc prog" => "Use \"prog\" to run CVC3 (default=cvc3)", ); my $usageString = "run_tests [ options ] [ test1 test2 ... ] [ -- [ cvc3 options ] ] Run CVC to SMT-LIB format converter. Concrete CVC files or directories with CVC files should be specified by name with a full path or relative path to the current directory. If none specified, all subdirectories are searched for test files. Options: " . join("\n ", map { sprintf("%-9s %s", $_, $optionsHelp{$_}) } keys(%optionsHelp)); # Database of default values for options my %optionsDefault = ("level" => 3, "verbose" => 1, "rt" => 0, "proofs" => 0, "lang" => "all", "cvcpath" => "@TOP@/bin", "vc" => "cvc3", # Program names "pfc" => "true", "cvctemp" => "/tmp", # max. number of lines to read from the testcase file # when looking for info comments "maxInfoLines" => 100, # Runtime limit; 0 = no limit "time" => 0, # Additional command line options to cvc "cvcOptions" => ""); # Database of command line options. Initially, they are undefined my %options = (); # The list of testcases to run my @testcases = (); # Temporary array for CVC options my @cvcOptions = (); # State is either "own" or "cvc", meaning that we're reading either # our own or cvc's options. my $argState = "own"; for(my $i=0; $i <= $#ARGV; $i++) { if($argState eq "own") { if($ARGV[$i] eq "--") { $argState = "cvc"; } elsif($ARGV[$i] eq "-h") { print($usageString, "\n"); exit 0; } elsif($ARGV[$i] eq "+rt") { $options{'rt'} = 1; } elsif($ARGV[$i] eq "-rt") { $options{'rt'} = 0; } elsif($ARGV[$i] eq "+proofs") { $options{'proofs'} = 1; } elsif($ARGV[$i] eq "-proofs") { $options{'proofs'} = 0; } elsif($ARGV[$i] eq "-v") { $options{'verbose'} = 1; } elsif($ARGV[$i] eq "-q") { $options{'verbose'} = 0; } elsif($ARGV[$i] eq "-lang") { if(++$i>$#ARGV) { print STDERR "Option -lang requires an argument.\n"; print STDERR "Run run_tests -h for help\n"; exit 1; } $options{'lang'} = $ARGV[$i]; } elsif($ARGV[$i] eq "-l") { if(++$i>$#ARGV) { print STDERR "Option -l requires an argument.\n"; print STDERR "Run run_tests -h for help\n"; exit 1; } $options{'level'} = $ARGV[$i]; } elsif($ARGV[$i] eq "-t") { if(++$i>$#ARGV) { print STDERR "Option -t requires an argument.\n"; print STDERR "Run run_tests -h for help\n"; exit 1; } $options{'time'} = $ARGV[$i]; } elsif($ARGV[$i] eq "-vc") { if(++$i>$#ARGV) { print STDERR "Option -vc requires an argument.\n"; print STDERR "Run run_tests -h for help\n"; exit 1; } $options{'vc'} = $ARGV[$i]; } elsif($ARGV[$i] eq "-pfc") { if(++$i>$#ARGV) { print STDERR "Option -pfc requires an argument.\n"; print STDERR "Run run_tests -h for help\n"; exit 1; } $options{'pfc'} = $ARGV[$i]; } else { # This must be a testcase name push @testcases, $ARGV[$i]; } } elsif($argState eq "cvc") { push @cvcOptions, $ARGV[$i]; } else { die "BUG: Bad argState: $argState"; } } if($#cvcOptions >= 0) { $options{'cvcOptions'} = join(" ", map { "\"" . $_ . "\"" } @cvcOptions); } # Compute the value of the option: first check the command line # option, then the supplied database (by ref. as the second arg), then # default values database. If it cannot find definition, it is a bug, # and the script is stopped. sub getOpt { my ($name, $dbRef) = @_; return $options{$name} if(defined($options{$name})); return $dbRef->{$name} if(defined($dbRef) && defined($dbRef->{$name})); return $optionsDefault{$name} if(defined($optionsDefault{$name})); # Option value is not found die "getOpt($name): option is undefined"; } my $verbose = getOpt('verbose'); # Set the path my $systemPath = "."; if(defined($ENV{'PATH'})) { $systemPath = $ENV{'PATH'}; } $ENV{'PATH'} = getOpt('cvcpath') . ":" . $systemPath; if($verbose) { print "*********\n"; print("Regression level: ", getOpt('level'), "\n"); print("Language: ", getOpt('lang'), "\n"); print("Whether to produce / check proofs: ", (defined($options{'proofs'}))? (($options{'proofs'})? "yes" : "no") : "depends on testcase", "\n"); if(getOpt('time') > 0) { print("Time limit per test: ", getOpt('time'), " sec\n"); } print("PATH = ", $ENV{'PATH'}, "\n"); print "*********\n"; } my $tmpdir = getOpt('cvctemp') . "/cvctmp-$$"; my $currdir = `pwd`; my $cvc = getOpt('vc'); my $pfc = getOpt('pfc'); my $level = getOpt('level'); my $lang = getOpt('lang'); my $rt = getOpt('rt'); # Read the first 'maxInfoLines' of the testcase and fetch information # from the comments sub getTestOpt { my ($name) = @_; # This is what we return my %db = (); open IN, $name or die "Cannot open $name: $?"; for(my $lines = getOpt('maxInfoLines'), my $str = ; defined($str) && $lines > 0; $lines--, $str = ) { if($str =~ /^(\s|%|\#)*Regression level\s*=\s*(\d+)/i) { $db{'level'} = $2; } if($str =~ /^(\s|%|\#)*Result\s*=\s*(Valid|Invalid|Satisfiable|Unsatisfiable|Unknown)/i) { $db{'result'} = lc $2; } if($str =~ /^(\s|%|\#)*Runtime\s*=\s*(\d+)/i) { $db{'runtime'} = $2; } if($str =~ /^(\s|%|\#)*Proof\s*=\s*(yes|no)/i) { if($2 eq "yes") { $db{'proofs'} = 1; } else { $db{'proofs'} = 0; } } if($str =~ /^(\s|%|\#)*SAT mode\s*=\s*(on|off)/i) { if($2 eq "on") { $db{'sat'} = 1; } else { $db{'sat'} = 0; } } if($str =~ /^(\s|%|\#)*Language\s*=\s*((\w|\d|\_)+)/i) { $db{'lang'} = lc $2; } if($str =~ /^(\s|%|\#)*CVC Options\s*=\s*(.*)$/i) { $db{'cvcOptions'} = $2; } } close IN; # If regression level is not set, make it 3. So, if a lower level # is requested, only explicitly marked tests will be run. if(!defined($db{'level'})) { $db{'level'}=0; } # If the input language is not defined, guess it by extension if($name =~ /^(.*)\.(cvcl|cvc|svc)$/) { if (!defined($db{'lang'})) { $db{'lang'} = "presentation"; } $db{'name'} = $1; } elsif($name =~ /^(.*)\.(li?sp)$/) { if (!defined($db{'lang'})) { $db{'lang'} = "internal"; } $db{'name'} = $1; } elsif($name =~ /^(.*)\.(smt|snt)$/) { if (!defined($db{'lang'})) { $db{'lang'} = "smtlib"; } $db{'name'} = $1; } else { if (!defined($db{'lang'})) { $db{'lang'} = "unknown"; } if ($name =~ /^(.*)$/) { $db{'name'} = $1; } else { $db{'name'} = "Unknown"; } } return %db; } # Total number of tests run my $testsTotal=0; # Total number of proofs checked by pfc my $proofsChecked=0; # Total number of tests with problems (each test is counted at most once) my $testsProblems=0; ### Database of results # It is a hash mapping problem keys to arrays of testcase names. # Only problematic testcase are inserted here. # Keys are: fail, result, proof, noproof (no proof generated when should), # time, timeTooMuch, lang (wrong language), # error (cvc reported errors, but didn't die) my %testsDB=(); # Search for a string element in the array ref, and return 1 if found, 0 if not sub findStringElement { my ($el, $aRef) = @_; foreach my $v (@{$aRef}) { if($v eq $el) { return 1; } } return 0; } # Add a testcase to the set of problematic runs. # Args: # test is the full or relative path to the test file # lang is the input language (not used currently) # problem is the name of the problem the testcase exhibits sub addProblem { my ($test, $lang, $problem) = @_; my $aRef = $testsDB{$problem}; if(!defined($aRef)) { $aRef=[ ]; } if(!findStringElement($test, $aRef)) { $testsDB{$problem} = [@{$aRef}, $test]; } } # Total running time my $totalTime = time; my $defaultDir = `pwd`; $defaultDir =~ s/\n//; foreach my $testcase (@testcases) { chdir $defaultDir or die "Cannot chdir to $defaultDir: $?"; my @testcasesTmp = (); if(-f $testcase) { push @testcasesTmp, $testcase; } elsif(-d $testcase) { # Compute the list of files for testcases opendir(TESTS, $testcase) or die "Cannot open directory $testcase: $?"; @testcasesTmp = grep { /[.]([sc]vc|li?sp|s[mn]t)$/ && -f "$testcase/$_" } readdir(TESTS); closedir TESTS; @testcasesTmp = map { "$testcase/$_" } @testcasesTmp; } else { print("*** WARNING: cannot find testcase $testcase: ", "no such file or directory\n"); } for(my $i=0; $i<=$#testcasesTmp; $i++) { my $name = $testcasesTmp[$i]; my $file = "$defaultDir/$name"; my $hasProblem=0; if(!(-f $file)) { print "WARNING: no such file: $file\n"; next; } my %opt = getTestOpt($file); # Check regression level if(defined($opt{'level'}) && $level < $opt{'level'}) { # Regression level of this test is too high; skip it next; } # Print the testcase name print("===============================================\n", $testcasesTmp[$i], ":\n"); # Check the input language if($lang ne "all" && defined($opt{'lang'}) && $lang ne $opt{'lang'}) { print "Wrong input language, skipping $testcasesTmp[$i]\n"; $hasProblem=1; addProblem($name, $lang, 'lang'); next; } if ($lang eq "all" && $opt{'lang'} eq "unknown") { print "Unknown input language, skipping $testcasesTmp[$i]\n"; $hasProblem=1; addProblem($name, $lang, 'lang'); next; } my $checkProofs = getOpt('proofs', \%opt); my $expRuntime = $opt{'runtime'}; my $cvcOptions = getOpt('cvcOptions', \%opt); # Print some testcase specific info if($verbose) { print("Language: $lang\n"); print("Checking proofs: ", ($checkProofs)? "yes" : "no", "\n"); if($rt && defined($expRuntime)) { print("Expected runtime: ", $expRuntime, " sec\n"); } if($cvcOptions =~ /\S/) { print("CVC options: ", $cvcOptions, "\n"); } } # Create a temporary dir, but first delete it; there may be # junk there system("/bin/rm -rf $tmpdir"); mkdir $tmpdir or die "Cannot create directory $tmpdir: $?"; chdir $tmpdir or die "Cannot chdir to $tmpdir: $?"; # Compute cvc arguments my @cvcArgs = (); push @cvcArgs, "+old-func-syntax -tcc -output-lang smtlib +translate -dump-log $opt{'name'}.smt -indent"; if (defined($opt{'result'}) && $opt{'result'} ne "") { push @cvcArgs, "-expResult $opt{'result'}"; } push @cvcArgs, ($checkProofs)? "+proofs" : "-proofs"; if($opt{'lang'} ne "presentation") { push @cvcArgs, "-lang $opt{'lang'}"; } push @cvcArgs, $cvcOptions; my $cvcArgs = join(" ", @cvcArgs); # Now, run the sucker my $timeMax = getOpt('time'); my $timeLimit = ($timeMax > 0)? "-t $timeMax" : ""; my $limits = "ulimit -c 0 -d 200000 -m 200000 ". "-s 200000 -v 200000 $timeLimit"; my $logging = ($verbose)? " 2>&1 | tee output" : "> output 2>&1"; my $timing = ($verbose)? "time " : ""; if($verbose) { print "***\n"; print "Running $cvc $cvcArgs < $file\n"; print "***\n"; } my $time = time; my $exitVal = system("$limits; $timing $cvc $cvcArgs " . "< $file $logging"); $time = time - $time; # OK, let's see what happened $testsTotal++; # Printing runtime print "Runtime: $time sec"; if($rt && defined($expRuntime)) { if($time > $expRuntime) { if($time > 10*$expRuntime) { print " MUCH"; addProblem($name, $lang, 'timeTooMuch'); } print " LONGER than expected: $expRuntime sec"; $hasProblem=1; addProblem($name, $lang, 'time'); } elsif($expRuntime >= 5 && $time < $expRuntime/2) { print " much FASTER than expected: $expRuntime sec"; addProblem($name, $lang, 'timeFast'); $hasProblem=1; } } print "\n"; # Parsing the output open IN, "output" or die "Cannot open `pwd`/output: $?"; my $str; my $result=""; my $hasErrors=0; while(defined($str=)) { # Find at least one valid result if($result ne "valid" && $str =~ /^(Valid|In[Vv]alid|Unknown)./) { $result=lc $1; } # CVC exit value may be masked by the shell pipe. Fish it # out from the output if($str =~ /^(Interrupted|Segmentation|Bus error|Floating point exception|.*exception)/) { $exitVal = $1; } if($str =~ /^(\*|\s)*((parse\s+)?[Ee]rror)/) { $hasErrors=1; } } close IN; if($exitVal ne "0") { print "*** CVC FAILED with exit code $exitVal\n"; $hasProblem=1; addProblem($name, $lang, 'fail'); } # Checking for errors if($hasErrors) { $hasProblem=1; addProblem($name, $lang, 'error'); print "ERRORS in the test\n"; } $testsProblems += $hasProblem; print("=============== End of testcase ===============\n"); } } $totalTime = time - $totalTime; print "\nStatistics:\n"; print "Total tests run: $testsTotal\n"; print "Total running time: $totalTime sec\n"; print "Total number of proofs checked: $proofsChecked\n"; print "Problematic cases: $testsProblems\n"; if($testsProblems > 0 && $verbose) { my $aref; print "\nDetailed Statistics:\n"; $aref=$testsDB{'fail'}; if(defined($aref)) { my @a = @{$aref}; printf("Failed tests [%d]:\n", $#a+1); foreach my $n (@a) { print " $n\n"; } } $aref=$testsDB{'error'}; if(defined($aref)) { my @a = @{$aref}; printf("Tests with errors [%d]:\n", $#a+1); foreach my $n (@a) { print " $n\n"; } } $aref=$testsDB{'result'}; if(defined($aref)) { my @a = @{$aref}; printf("Tests with wrong results [%d]:\n", $#a+1); foreach my $n (@a) { print " $n\n"; } } $aref=$testsDB{'proof'}; if(defined($aref)) { my @a = @{$aref}; printf("Tests with failed proofs [%d]:\n", $#a+1); foreach my $n (@a) { print " $n\n"; } } $aref=$testsDB{'noproof'}; if(defined($aref)) { my @a = @{$aref}; printf("Tests that should have proofs but don't [%d]:\n", $#a+1); foreach my $n (@a) { print " $n\n"; } } $aref=$testsDB{'timeFast'}; if(defined($aref)) { my @a = @{$aref}; printf("Tests running at least twice as fast as expected [%d]:\n", $#a+1); foreach my $n (@a) { print " $n\n"; } } $aref=$testsDB{'time'}; if(defined($aref)) { my @a = @{$aref}; printf("Tests running longer [%d]:\n", $#a+1); foreach my $n (@a) { print " $n\n"; } } $aref=$testsDB{'timeTooMuch'}; if(defined($aref)) { my @a = @{$aref}; printf("...including tests running WAY too long [%d]:\n", $#a+1); foreach my $n (@a) { print " $n\n"; } } $aref=$testsDB{'lang'}; if(defined($aref)) { my @a = @{$aref}; printf("Tests with wrong input language [%d]:\n", $#a+1); foreach my $n (@a) { print " $n\n"; } } } # Delete temporary dir if there is one system("/bin/rm -rf $tmpdir"); exit ($testsProblems > 0 ? 2 : 0); cvc3-2.4.1/VERSION0000664000175400017540000000000611630011320013305 0ustar mdetersmdeters2.4.1 cvc3-2.4.1/install-sh0000775000175400017540000003246411154061001014260 0ustar mdetersmdeters#!/bin/sh # install - install a program, script, or datafile scriptversion=2006-12-25.00 # This originates from X11R5 (mit/util/scripts/install.sh), which was # later released in X11R6 (xc/config/util/install.sh) with the # following copyright and license. # # Copyright (C) 1994 X Consortium # # Permission is hereby granted, free of charge, to any person obtaining a copy # of this software and associated documentation files (the "Software"), to # deal in the Software without restriction, including without limitation the # rights to use, copy, modify, merge, publish, distribute, sublicense, and/or # sell copies of the Software, and to permit persons to whom the Software is # furnished to do so, subject to the following conditions: # # The above copyright notice and this permission notice shall be included in # all copies or substantial portions of the Software. # # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE # X CONSORTIUM BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN # AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNEC- # TION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. # # Except as contained in this notice, the name of the X Consortium shall not # be used in advertising or otherwise to promote the sale, use or other deal- # ings in this Software without prior written authorization from the X Consor- # tium. # # # FSF changes to this file are in the public domain. # # Calling this script install-sh is preferred over install.sh, to prevent # `make' implicit rules from creating a file called install from it # when there is no Makefile. # # This script is compatible with the BSD install script, but was written # from scratch. nl=' ' IFS=" "" $nl" # set DOITPROG to echo to test this script # Don't use :- since 4.3BSD and earlier shells don't like it. doit=${DOITPROG-} if test -z "$doit"; then doit_exec=exec else doit_exec=$doit fi # Put in absolute file names if you don't have them in your path; # or use environment vars. chgrpprog=${CHGRPPROG-chgrp} chmodprog=${CHMODPROG-chmod} chownprog=${CHOWNPROG-chown} cmpprog=${CMPPROG-cmp} cpprog=${CPPROG-cp} mkdirprog=${MKDIRPROG-mkdir} mvprog=${MVPROG-mv} rmprog=${RMPROG-rm} stripprog=${STRIPPROG-strip} posix_glob='?' initialize_posix_glob=' test "$posix_glob" != "?" || { if (set -f) 2>/dev/null; then posix_glob= else posix_glob=: fi } ' posix_mkdir= # Desired mode of installed file. mode=0755 chgrpcmd= chmodcmd=$chmodprog chowncmd= mvcmd=$mvprog rmcmd="$rmprog -f" stripcmd= src= dst= dir_arg= dst_arg= copy_on_change=false no_target_directory= usage="\ Usage: $0 [OPTION]... [-T] SRCFILE DSTFILE or: $0 [OPTION]... SRCFILES... DIRECTORY or: $0 [OPTION]... -t DIRECTORY SRCFILES... or: $0 [OPTION]... -d DIRECTORIES... In the 1st form, copy SRCFILE to DSTFILE. In the 2nd and 3rd, copy all SRCFILES to DIRECTORY. In the 4th, create DIRECTORIES. Options: --help display this help and exit. --version display version info and exit. -c (ignored) -C install only if different (preserve the last data modification time) -d create directories instead of installing files. -g GROUP $chgrpprog installed files to GROUP. -m MODE $chmodprog installed files to MODE. -o USER $chownprog installed files to USER. -s $stripprog installed files. -t DIRECTORY install into DIRECTORY. -T report an error if DSTFILE is a directory. Environment variables override the default commands: CHGRPPROG CHMODPROG CHOWNPROG CMPPROG CPPROG MKDIRPROG MVPROG RMPROG STRIPPROG " while test $# -ne 0; do case $1 in -c) ;; -C) copy_on_change=true;; -d) dir_arg=true;; -g) chgrpcmd="$chgrpprog $2" shift;; --help) echo "$usage"; exit $?;; -m) mode=$2 case $mode in *' '* | *' '* | *' '* | *'*'* | *'?'* | *'['*) echo "$0: invalid mode: $mode" >&2 exit 1;; esac shift;; -o) chowncmd="$chownprog $2" shift;; -s) stripcmd=$stripprog;; -t) dst_arg=$2 shift;; -T) no_target_directory=true;; --version) echo "$0 $scriptversion"; exit $?;; --) shift break;; -*) echo "$0: invalid option: $1" >&2 exit 1;; *) break;; esac shift done if test $# -ne 0 && test -z "$dir_arg$dst_arg"; then # When -d is used, all remaining arguments are directories to create. # When -t is used, the destination is already specified. # Otherwise, the last argument is the destination. Remove it from $@. for arg do if test -n "$dst_arg"; then # $@ is not empty: it contains at least $arg. set fnord "$@" "$dst_arg" shift # fnord fi shift # arg dst_arg=$arg done fi if test $# -eq 0; then if test -z "$dir_arg"; then echo "$0: no input file specified." >&2 exit 1 fi # It's OK to call `install-sh -d' without argument. # This can happen when creating conditional directories. exit 0 fi if test -z "$dir_arg"; then trap '(exit $?); exit' 1 2 13 15 # Set umask so as not to create temps with too-generous modes. # However, 'strip' requires both read and write access to temps. case $mode in # Optimize common cases. *644) cp_umask=133;; *755) cp_umask=22;; *[0-7]) if test -z "$stripcmd"; then u_plus_rw= else u_plus_rw='% 200' fi cp_umask=`expr '(' 777 - $mode % 1000 ')' $u_plus_rw`;; *) if test -z "$stripcmd"; then u_plus_rw= else u_plus_rw=,u+rw fi cp_umask=$mode$u_plus_rw;; esac fi for src do # Protect names starting with `-'. case $src in -*) src=./$src;; esac if test -n "$dir_arg"; then dst=$src dstdir=$dst test -d "$dstdir" dstdir_status=$? else # Waiting for this to be detected by the "$cpprog $src $dsttmp" command # might cause directories to be created, which would be especially bad # if $src (and thus $dsttmp) contains '*'. if test ! -f "$src" && test ! -d "$src"; then echo "$0: $src does not exist." >&2 exit 1 fi if test -z "$dst_arg"; then echo "$0: no destination specified." >&2 exit 1 fi dst=$dst_arg # Protect names starting with `-'. case $dst in -*) dst=./$dst;; esac # If destination is a directory, append the input filename; won't work # if double slashes aren't ignored. if test -d "$dst"; then if test -n "$no_target_directory"; then echo "$0: $dst_arg: Is a directory" >&2 exit 1 fi dstdir=$dst dst=$dstdir/`basename "$src"` dstdir_status=0 else # Prefer dirname, but fall back on a substitute if dirname fails. dstdir=` (dirname "$dst") 2>/dev/null || expr X"$dst" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ X"$dst" : 'X\(//\)[^/]' \| \ X"$dst" : 'X\(//\)$' \| \ X"$dst" : 'X\(/\)' \| . 2>/dev/null || echo X"$dst" | sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ s//\1/ q } /^X\(\/\/\)[^/].*/{ s//\1/ q } /^X\(\/\/\)$/{ s//\1/ q } /^X\(\/\).*/{ s//\1/ q } s/.*/./; q' ` test -d "$dstdir" dstdir_status=$? fi fi obsolete_mkdir_used=false if test $dstdir_status != 0; then case $posix_mkdir in '') # Create intermediate dirs using mode 755 as modified by the umask. # This is like FreeBSD 'install' as of 1997-10-28. umask=`umask` case $stripcmd.$umask in # Optimize common cases. *[2367][2367]) mkdir_umask=$umask;; .*0[02][02] | .[02][02] | .[02]) mkdir_umask=22;; *[0-7]) mkdir_umask=`expr $umask + 22 \ - $umask % 100 % 40 + $umask % 20 \ - $umask % 10 % 4 + $umask % 2 `;; *) mkdir_umask=$umask,go-w;; esac # With -d, create the new directory with the user-specified mode. # Otherwise, rely on $mkdir_umask. if test -n "$dir_arg"; then mkdir_mode=-m$mode else mkdir_mode= fi posix_mkdir=false case $umask in *[123567][0-7][0-7]) # POSIX mkdir -p sets u+wx bits regardless of umask, which # is incompatible with FreeBSD 'install' when (umask & 300) != 0. ;; *) tmpdir=${TMPDIR-/tmp}/ins$RANDOM-$$ trap 'ret=$?; rmdir "$tmpdir/d" "$tmpdir" 2>/dev/null; exit $ret' 0 if (umask $mkdir_umask && exec $mkdirprog $mkdir_mode -p -- "$tmpdir/d") >/dev/null 2>&1 then if test -z "$dir_arg" || { # Check for POSIX incompatibilities with -m. # HP-UX 11.23 and IRIX 6.5 mkdir -m -p sets group- or # other-writeable bit of parent directory when it shouldn't. # FreeBSD 6.1 mkdir -m -p sets mode of existing directory. ls_ld_tmpdir=`ls -ld "$tmpdir"` case $ls_ld_tmpdir in d????-?r-*) different_mode=700;; d????-?--*) different_mode=755;; *) false;; esac && $mkdirprog -m$different_mode -p -- "$tmpdir" && { ls_ld_tmpdir_1=`ls -ld "$tmpdir"` test "$ls_ld_tmpdir" = "$ls_ld_tmpdir_1" } } then posix_mkdir=: fi rmdir "$tmpdir/d" "$tmpdir" else # Remove any dirs left behind by ancient mkdir implementations. rmdir ./$mkdir_mode ./-p ./-- 2>/dev/null fi trap '' 0;; esac;; esac if $posix_mkdir && ( umask $mkdir_umask && $doit_exec $mkdirprog $mkdir_mode -p -- "$dstdir" ) then : else # The umask is ridiculous, or mkdir does not conform to POSIX, # or it failed possibly due to a race condition. Create the # directory the slow way, step by step, checking for races as we go. case $dstdir in /*) prefix='/';; -*) prefix='./';; *) prefix='';; esac eval "$initialize_posix_glob" oIFS=$IFS IFS=/ $posix_glob set -f set fnord $dstdir shift $posix_glob set +f IFS=$oIFS prefixes= for d do test -z "$d" && continue prefix=$prefix$d if test -d "$prefix"; then prefixes= else if $posix_mkdir; then (umask=$mkdir_umask && $doit_exec $mkdirprog $mkdir_mode -p -- "$dstdir") && break # Don't fail if two instances are running concurrently. test -d "$prefix" || exit 1 else case $prefix in *\'*) qprefix=`echo "$prefix" | sed "s/'/'\\\\\\\\''/g"`;; *) qprefix=$prefix;; esac prefixes="$prefixes '$qprefix'" fi fi prefix=$prefix/ done if test -n "$prefixes"; then # Don't fail if two instances are running concurrently. (umask $mkdir_umask && eval "\$doit_exec \$mkdirprog $prefixes") || test -d "$dstdir" || exit 1 obsolete_mkdir_used=true fi fi fi if test -n "$dir_arg"; then { test -z "$chowncmd" || $doit $chowncmd "$dst"; } && { test -z "$chgrpcmd" || $doit $chgrpcmd "$dst"; } && { test "$obsolete_mkdir_used$chowncmd$chgrpcmd" = false || test -z "$chmodcmd" || $doit $chmodcmd $mode "$dst"; } || exit 1 else # Make a couple of temp file names in the proper directory. dsttmp=$dstdir/_inst.$$_ rmtmp=$dstdir/_rm.$$_ # Trap to clean up those temp files at exit. trap 'ret=$?; rm -f "$dsttmp" "$rmtmp" && exit $ret' 0 # Copy the file name to the temp name. (umask $cp_umask && $doit_exec $cpprog "$src" "$dsttmp") && # and set any options; do chmod last to preserve setuid bits. # # If any of these fail, we abort the whole thing. If we want to # ignore errors from any of these, just make sure not to ignore # errors from the above "$doit $cpprog $src $dsttmp" command. # { test -z "$chowncmd" || $doit $chowncmd "$dsttmp"; } && { test -z "$chgrpcmd" || $doit $chgrpcmd "$dsttmp"; } && { test -z "$stripcmd" || $doit $stripcmd "$dsttmp"; } && { test -z "$chmodcmd" || $doit $chmodcmd $mode "$dsttmp"; } && # If -C, don't bother to copy if it wouldn't change the file. if $copy_on_change && old=`LC_ALL=C ls -dlL "$dst" 2>/dev/null` && new=`LC_ALL=C ls -dlL "$dsttmp" 2>/dev/null` && eval "$initialize_posix_glob" && $posix_glob set -f && set X $old && old=:$2:$4:$5:$6 && set X $new && new=:$2:$4:$5:$6 && $posix_glob set +f && test "$old" = "$new" && $cmpprog "$dst" "$dsttmp" >/dev/null 2>&1 then rm -f "$dsttmp" else # Rename the file to the real destination. $doit $mvcmd -f "$dsttmp" "$dst" 2>/dev/null || # The rename failed, perhaps because mv can't rename something else # to itself, or perhaps because mv is so ancient that it does not # support -f. { # Now remove or move aside any old file at destination location. # We try this two ways since rm can't unlink itself on some # systems and the destination file might be busy for other # reasons. In this case, the final cleanup might fail but the new # file should still install successfully. { test ! -f "$dst" || $doit $rmcmd -f "$dst" 2>/dev/null || { $doit $mvcmd -f "$dst" "$rmtmp" 2>/dev/null && { $doit $rmcmd -f "$rmtmp" 2>/dev/null; :; } } || { echo "$0: cannot unlink or rename $dst" >&2 (exit 1); exit 1 } } && # Now rename the file to the real destination. $doit $mvcmd "$dsttmp" "$dst" } fi || exit 1 trap '' 0 fi done # Local variables: # eval: (add-hook 'write-file-hooks 'time-stamp) # time-stamp-start: "scriptversion=" # time-stamp-format: "%:y-%02m-%02d.%02H" # time-stamp-end: "$" # End: cvc3-2.4.1/config.guess0000775000175400017540000012753411154061000014576 0ustar mdetersmdeters#! /bin/sh # Attempt to guess a canonical system name. # Copyright (C) 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999, # 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008 # Free Software Foundation, Inc. timestamp='2008-01-23' # This file is free software; you can redistribute it and/or modify it # under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, but # WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU # General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program; if not, write to the Free Software # Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, MA # 02110-1301, USA. # # As a special exception to the GNU General Public License, if you # distribute this file as part of a program that contains a # configuration script generated by Autoconf, you may include it under # the same distribution terms that you use for the rest of that program. # Originally written by Per Bothner . # Please send patches to . Submit a context # diff and a properly formatted ChangeLog entry. # # This script attempts to guess a canonical system name similar to # config.sub. If it succeeds, it prints the system name on stdout, and # exits with 0. Otherwise, it exits with 1. # # The plan is that this can be called by configure scripts if you # don't specify an explicit build system type. me=`echo "$0" | sed -e 's,.*/,,'` usage="\ Usage: $0 [OPTION] Output the configuration name of the system \`$me' is run on. Operation modes: -h, --help print this help, then exit -t, --time-stamp print date of last modification, then exit -v, --version print version number, then exit Report bugs and patches to ." version="\ GNU config.guess ($timestamp) Originally written by Per Bothner. Copyright (C) 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008 Free Software Foundation, Inc. This is free software; see the source for copying conditions. There is NO warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE." help=" Try \`$me --help' for more information." # Parse command line while test $# -gt 0 ; do case $1 in --time-stamp | --time* | -t ) echo "$timestamp" ; exit ;; --version | -v ) echo "$version" ; exit ;; --help | --h* | -h ) echo "$usage"; exit ;; -- ) # Stop option processing shift; break ;; - ) # Use stdin as input. break ;; -* ) echo "$me: invalid option $1$help" >&2 exit 1 ;; * ) break ;; esac done if test $# != 0; then echo "$me: too many arguments$help" >&2 exit 1 fi trap 'exit 1' 1 2 15 # CC_FOR_BUILD -- compiler used by this script. Note that the use of a # compiler to aid in system detection is discouraged as it requires # temporary files to be created and, as you can see below, it is a # headache to deal with in a portable fashion. # Historically, `CC_FOR_BUILD' used to be named `HOST_CC'. We still # use `HOST_CC' if defined, but it is deprecated. # Portable tmp directory creation inspired by the Autoconf team. set_cc_for_build=' trap "exitcode=\$?; (rm -f \$tmpfiles 2>/dev/null; rmdir \$tmp 2>/dev/null) && exit \$exitcode" 0 ; trap "rm -f \$tmpfiles 2>/dev/null; rmdir \$tmp 2>/dev/null; exit 1" 1 2 13 15 ; : ${TMPDIR=/tmp} ; { tmp=`(umask 077 && mktemp -d "$TMPDIR/cgXXXXXX") 2>/dev/null` && test -n "$tmp" && test -d "$tmp" ; } || { test -n "$RANDOM" && tmp=$TMPDIR/cg$$-$RANDOM && (umask 077 && mkdir $tmp) ; } || { tmp=$TMPDIR/cg-$$ && (umask 077 && mkdir $tmp) && echo "Warning: creating insecure temp directory" >&2 ; } || { echo "$me: cannot create a temporary directory in $TMPDIR" >&2 ; exit 1 ; } ; dummy=$tmp/dummy ; tmpfiles="$dummy.c $dummy.o $dummy.rel $dummy" ; case $CC_FOR_BUILD,$HOST_CC,$CC in ,,) echo "int x;" > $dummy.c ; for c in cc gcc c89 c99 ; do if ($c -c -o $dummy.o $dummy.c) >/dev/null 2>&1 ; then CC_FOR_BUILD="$c"; break ; fi ; done ; if test x"$CC_FOR_BUILD" = x ; then CC_FOR_BUILD=no_compiler_found ; fi ;; ,,*) CC_FOR_BUILD=$CC ;; ,*,*) CC_FOR_BUILD=$HOST_CC ;; esac ; set_cc_for_build= ;' # This is needed to find uname on a Pyramid OSx when run in the BSD universe. # (ghazi@noc.rutgers.edu 1994-08-24) if (test -f /.attbin/uname) >/dev/null 2>&1 ; then PATH=$PATH:/.attbin ; export PATH fi UNAME_MACHINE=`(uname -m) 2>/dev/null` || UNAME_MACHINE=unknown UNAME_RELEASE=`(uname -r) 2>/dev/null` || UNAME_RELEASE=unknown UNAME_SYSTEM=`(uname -s) 2>/dev/null` || UNAME_SYSTEM=unknown UNAME_VERSION=`(uname -v) 2>/dev/null` || UNAME_VERSION=unknown # Note: order is significant - the case branches are not exclusive. case "${UNAME_MACHINE}:${UNAME_SYSTEM}:${UNAME_RELEASE}:${UNAME_VERSION}" in *:NetBSD:*:*) # NetBSD (nbsd) targets should (where applicable) match one or # more of the tupples: *-*-netbsdelf*, *-*-netbsdaout*, # *-*-netbsdecoff* and *-*-netbsd*. For targets that recently # switched to ELF, *-*-netbsd* would select the old # object file format. This provides both forward # compatibility and a consistent mechanism for selecting the # object file format. # # Note: NetBSD doesn't particularly care about the vendor # portion of the name. We always set it to "unknown". sysctl="sysctl -n hw.machine_arch" UNAME_MACHINE_ARCH=`(/sbin/$sysctl 2>/dev/null || \ /usr/sbin/$sysctl 2>/dev/null || echo unknown)` case "${UNAME_MACHINE_ARCH}" in armeb) machine=armeb-unknown ;; arm*) machine=arm-unknown ;; sh3el) machine=shl-unknown ;; sh3eb) machine=sh-unknown ;; sh5el) machine=sh5le-unknown ;; *) machine=${UNAME_MACHINE_ARCH}-unknown ;; esac # The Operating System including object format, if it has switched # to ELF recently, or will in the future. case "${UNAME_MACHINE_ARCH}" in arm*|i386|m68k|ns32k|sh3*|sparc|vax) eval $set_cc_for_build if echo __ELF__ | $CC_FOR_BUILD -E - 2>/dev/null \ | grep __ELF__ >/dev/null then # Once all utilities can be ECOFF (netbsdecoff) or a.out (netbsdaout). # Return netbsd for either. FIX? os=netbsd else os=netbsdelf fi ;; *) os=netbsd ;; esac # The OS release # Debian GNU/NetBSD machines have a different userland, and # thus, need a distinct triplet. However, they do not need # kernel version information, so it can be replaced with a # suitable tag, in the style of linux-gnu. case "${UNAME_VERSION}" in Debian*) release='-gnu' ;; *) release=`echo ${UNAME_RELEASE}|sed -e 's/[-_].*/\./'` ;; esac # Since CPU_TYPE-MANUFACTURER-KERNEL-OPERATING_SYSTEM: # contains redundant information, the shorter form: # CPU_TYPE-MANUFACTURER-OPERATING_SYSTEM is used. echo "${machine}-${os}${release}" exit ;; *:OpenBSD:*:*) UNAME_MACHINE_ARCH=`arch | sed 's/OpenBSD.//'` echo ${UNAME_MACHINE_ARCH}-unknown-openbsd${UNAME_RELEASE} exit ;; *:ekkoBSD:*:*) echo ${UNAME_MACHINE}-unknown-ekkobsd${UNAME_RELEASE} exit ;; *:SolidBSD:*:*) echo ${UNAME_MACHINE}-unknown-solidbsd${UNAME_RELEASE} exit ;; macppc:MirBSD:*:*) echo powerpc-unknown-mirbsd${UNAME_RELEASE} exit ;; *:MirBSD:*:*) echo ${UNAME_MACHINE}-unknown-mirbsd${UNAME_RELEASE} exit ;; alpha:OSF1:*:*) case $UNAME_RELEASE in *4.0) UNAME_RELEASE=`/usr/sbin/sizer -v | awk '{print $3}'` ;; *5.*) UNAME_RELEASE=`/usr/sbin/sizer -v | awk '{print $4}'` ;; esac # According to Compaq, /usr/sbin/psrinfo has been available on # OSF/1 and Tru64 systems produced since 1995. I hope that # covers most systems running today. This code pipes the CPU # types through head -n 1, so we only detect the type of CPU 0. ALPHA_CPU_TYPE=`/usr/sbin/psrinfo -v | sed -n -e 's/^ The alpha \(.*\) processor.*$/\1/p' | head -n 1` case "$ALPHA_CPU_TYPE" in "EV4 (21064)") UNAME_MACHINE="alpha" ;; "EV4.5 (21064)") UNAME_MACHINE="alpha" ;; "LCA4 (21066/21068)") UNAME_MACHINE="alpha" ;; "EV5 (21164)") UNAME_MACHINE="alphaev5" ;; "EV5.6 (21164A)") UNAME_MACHINE="alphaev56" ;; "EV5.6 (21164PC)") UNAME_MACHINE="alphapca56" ;; "EV5.7 (21164PC)") UNAME_MACHINE="alphapca57" ;; "EV6 (21264)") UNAME_MACHINE="alphaev6" ;; "EV6.7 (21264A)") UNAME_MACHINE="alphaev67" ;; "EV6.8CB (21264C)") UNAME_MACHINE="alphaev68" ;; "EV6.8AL (21264B)") UNAME_MACHINE="alphaev68" ;; "EV6.8CX (21264D)") UNAME_MACHINE="alphaev68" ;; "EV6.9A (21264/EV69A)") UNAME_MACHINE="alphaev69" ;; "EV7 (21364)") UNAME_MACHINE="alphaev7" ;; "EV7.9 (21364A)") UNAME_MACHINE="alphaev79" ;; esac # A Pn.n version is a patched version. # A Vn.n version is a released version. # A Tn.n version is a released field test version. # A Xn.n version is an unreleased experimental baselevel. # 1.2 uses "1.2" for uname -r. echo ${UNAME_MACHINE}-dec-osf`echo ${UNAME_RELEASE} | sed -e 's/^[PVTX]//' | tr 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz'` exit ;; Alpha\ *:Windows_NT*:*) # How do we know it's Interix rather than the generic POSIX subsystem? # Should we change UNAME_MACHINE based on the output of uname instead # of the specific Alpha model? echo alpha-pc-interix exit ;; 21064:Windows_NT:50:3) echo alpha-dec-winnt3.5 exit ;; Amiga*:UNIX_System_V:4.0:*) echo m68k-unknown-sysv4 exit ;; *:[Aa]miga[Oo][Ss]:*:*) echo ${UNAME_MACHINE}-unknown-amigaos exit ;; *:[Mm]orph[Oo][Ss]:*:*) echo ${UNAME_MACHINE}-unknown-morphos exit ;; *:OS/390:*:*) echo i370-ibm-openedition exit ;; *:z/VM:*:*) echo s390-ibm-zvmoe exit ;; *:OS400:*:*) echo powerpc-ibm-os400 exit ;; arm:RISC*:1.[012]*:*|arm:riscix:1.[012]*:*) echo arm-acorn-riscix${UNAME_RELEASE} exit ;; arm:riscos:*:*|arm:RISCOS:*:*) echo arm-unknown-riscos exit ;; SR2?01:HI-UX/MPP:*:* | SR8000:HI-UX/MPP:*:*) echo hppa1.1-hitachi-hiuxmpp exit ;; Pyramid*:OSx*:*:* | MIS*:OSx*:*:* | MIS*:SMP_DC-OSx*:*:*) # akee@wpdis03.wpafb.af.mil (Earle F. Ake) contributed MIS and NILE. if test "`(/bin/universe) 2>/dev/null`" = att ; then echo pyramid-pyramid-sysv3 else echo pyramid-pyramid-bsd fi exit ;; NILE*:*:*:dcosx) echo pyramid-pyramid-svr4 exit ;; DRS?6000:unix:4.0:6*) echo sparc-icl-nx6 exit ;; DRS?6000:UNIX_SV:4.2*:7* | DRS?6000:isis:4.2*:7*) case `/usr/bin/uname -p` in sparc) echo sparc-icl-nx7; exit ;; esac ;; sun4H:SunOS:5.*:*) echo sparc-hal-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'` exit ;; sun4*:SunOS:5.*:* | tadpole*:SunOS:5.*:*) echo sparc-sun-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'` exit ;; i86pc:SunOS:5.*:* | i86xen:SunOS:5.*:*) echo i386-pc-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'` exit ;; sun4*:SunOS:6*:*) # According to config.sub, this is the proper way to canonicalize # SunOS6. Hard to guess exactly what SunOS6 will be like, but # it's likely to be more like Solaris than SunOS4. echo sparc-sun-solaris3`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'` exit ;; sun4*:SunOS:*:*) case "`/usr/bin/arch -k`" in Series*|S4*) UNAME_RELEASE=`uname -v` ;; esac # Japanese Language versions have a version number like `4.1.3-JL'. echo sparc-sun-sunos`echo ${UNAME_RELEASE}|sed -e 's/-/_/'` exit ;; sun3*:SunOS:*:*) echo m68k-sun-sunos${UNAME_RELEASE} exit ;; sun*:*:4.2BSD:*) UNAME_RELEASE=`(sed 1q /etc/motd | awk '{print substr($5,1,3)}') 2>/dev/null` test "x${UNAME_RELEASE}" = "x" && UNAME_RELEASE=3 case "`/bin/arch`" in sun3) echo m68k-sun-sunos${UNAME_RELEASE} ;; sun4) echo sparc-sun-sunos${UNAME_RELEASE} ;; esac exit ;; aushp:SunOS:*:*) echo sparc-auspex-sunos${UNAME_RELEASE} exit ;; # The situation for MiNT is a little confusing. The machine name # can be virtually everything (everything which is not # "atarist" or "atariste" at least should have a processor # > m68000). The system name ranges from "MiNT" over "FreeMiNT" # to the lowercase version "mint" (or "freemint"). Finally # the system name "TOS" denotes a system which is actually not # MiNT. But MiNT is downward compatible to TOS, so this should # be no problem. atarist[e]:*MiNT:*:* | atarist[e]:*mint:*:* | atarist[e]:*TOS:*:*) echo m68k-atari-mint${UNAME_RELEASE} exit ;; atari*:*MiNT:*:* | atari*:*mint:*:* | atarist[e]:*TOS:*:*) echo m68k-atari-mint${UNAME_RELEASE} exit ;; *falcon*:*MiNT:*:* | *falcon*:*mint:*:* | *falcon*:*TOS:*:*) echo m68k-atari-mint${UNAME_RELEASE} exit ;; milan*:*MiNT:*:* | milan*:*mint:*:* | *milan*:*TOS:*:*) echo m68k-milan-mint${UNAME_RELEASE} exit ;; hades*:*MiNT:*:* | hades*:*mint:*:* | *hades*:*TOS:*:*) echo m68k-hades-mint${UNAME_RELEASE} exit ;; *:*MiNT:*:* | *:*mint:*:* | *:*TOS:*:*) echo m68k-unknown-mint${UNAME_RELEASE} exit ;; m68k:machten:*:*) echo m68k-apple-machten${UNAME_RELEASE} exit ;; powerpc:machten:*:*) echo powerpc-apple-machten${UNAME_RELEASE} exit ;; RISC*:Mach:*:*) echo mips-dec-mach_bsd4.3 exit ;; RISC*:ULTRIX:*:*) echo mips-dec-ultrix${UNAME_RELEASE} exit ;; VAX*:ULTRIX*:*:*) echo vax-dec-ultrix${UNAME_RELEASE} exit ;; 2020:CLIX:*:* | 2430:CLIX:*:*) echo clipper-intergraph-clix${UNAME_RELEASE} exit ;; mips:*:*:UMIPS | mips:*:*:RISCos) eval $set_cc_for_build sed 's/^ //' << EOF >$dummy.c #ifdef __cplusplus #include /* for printf() prototype */ int main (int argc, char *argv[]) { #else int main (argc, argv) int argc; char *argv[]; { #endif #if defined (host_mips) && defined (MIPSEB) #if defined (SYSTYPE_SYSV) printf ("mips-mips-riscos%ssysv\n", argv[1]); exit (0); #endif #if defined (SYSTYPE_SVR4) printf ("mips-mips-riscos%ssvr4\n", argv[1]); exit (0); #endif #if defined (SYSTYPE_BSD43) || defined(SYSTYPE_BSD) printf ("mips-mips-riscos%sbsd\n", argv[1]); exit (0); #endif #endif exit (-1); } EOF $CC_FOR_BUILD -o $dummy $dummy.c && dummyarg=`echo "${UNAME_RELEASE}" | sed -n 's/\([0-9]*\).*/\1/p'` && SYSTEM_NAME=`$dummy $dummyarg` && { echo "$SYSTEM_NAME"; exit; } echo mips-mips-riscos${UNAME_RELEASE} exit ;; Motorola:PowerMAX_OS:*:*) echo powerpc-motorola-powermax exit ;; Motorola:*:4.3:PL8-*) echo powerpc-harris-powermax exit ;; Night_Hawk:*:*:PowerMAX_OS | Synergy:PowerMAX_OS:*:*) echo powerpc-harris-powermax exit ;; Night_Hawk:Power_UNIX:*:*) echo powerpc-harris-powerunix exit ;; m88k:CX/UX:7*:*) echo m88k-harris-cxux7 exit ;; m88k:*:4*:R4*) echo m88k-motorola-sysv4 exit ;; m88k:*:3*:R3*) echo m88k-motorola-sysv3 exit ;; AViiON:dgux:*:*) # DG/UX returns AViiON for all architectures UNAME_PROCESSOR=`/usr/bin/uname -p` if [ $UNAME_PROCESSOR = mc88100 ] || [ $UNAME_PROCESSOR = mc88110 ] then if [ ${TARGET_BINARY_INTERFACE}x = m88kdguxelfx ] || \ [ ${TARGET_BINARY_INTERFACE}x = x ] then echo m88k-dg-dgux${UNAME_RELEASE} else echo m88k-dg-dguxbcs${UNAME_RELEASE} fi else echo i586-dg-dgux${UNAME_RELEASE} fi exit ;; M88*:DolphinOS:*:*) # DolphinOS (SVR3) echo m88k-dolphin-sysv3 exit ;; M88*:*:R3*:*) # Delta 88k system running SVR3 echo m88k-motorola-sysv3 exit ;; XD88*:*:*:*) # Tektronix XD88 system running UTekV (SVR3) echo m88k-tektronix-sysv3 exit ;; Tek43[0-9][0-9]:UTek:*:*) # Tektronix 4300 system running UTek (BSD) echo m68k-tektronix-bsd exit ;; *:IRIX*:*:*) echo mips-sgi-irix`echo ${UNAME_RELEASE}|sed -e 's/-/_/g'` exit ;; ????????:AIX?:[12].1:2) # AIX 2.2.1 or AIX 2.1.1 is RT/PC AIX. echo romp-ibm-aix # uname -m gives an 8 hex-code CPU id exit ;; # Note that: echo "'`uname -s`'" gives 'AIX ' i*86:AIX:*:*) echo i386-ibm-aix exit ;; ia64:AIX:*:*) if [ -x /usr/bin/oslevel ] ; then IBM_REV=`/usr/bin/oslevel` else IBM_REV=${UNAME_VERSION}.${UNAME_RELEASE} fi echo ${UNAME_MACHINE}-ibm-aix${IBM_REV} exit ;; *:AIX:2:3) if grep bos325 /usr/include/stdio.h >/dev/null 2>&1; then eval $set_cc_for_build sed 's/^ //' << EOF >$dummy.c #include main() { if (!__power_pc()) exit(1); puts("powerpc-ibm-aix3.2.5"); exit(0); } EOF if $CC_FOR_BUILD -o $dummy $dummy.c && SYSTEM_NAME=`$dummy` then echo "$SYSTEM_NAME" else echo rs6000-ibm-aix3.2.5 fi elif grep bos324 /usr/include/stdio.h >/dev/null 2>&1; then echo rs6000-ibm-aix3.2.4 else echo rs6000-ibm-aix3.2 fi exit ;; *:AIX:*:[456]) IBM_CPU_ID=`/usr/sbin/lsdev -C -c processor -S available | sed 1q | awk '{ print $1 }'` if /usr/sbin/lsattr -El ${IBM_CPU_ID} | grep ' POWER' >/dev/null 2>&1; then IBM_ARCH=rs6000 else IBM_ARCH=powerpc fi if [ -x /usr/bin/oslevel ] ; then IBM_REV=`/usr/bin/oslevel` else IBM_REV=${UNAME_VERSION}.${UNAME_RELEASE} fi echo ${IBM_ARCH}-ibm-aix${IBM_REV} exit ;; *:AIX:*:*) echo rs6000-ibm-aix exit ;; ibmrt:4.4BSD:*|romp-ibm:BSD:*) echo romp-ibm-bsd4.4 exit ;; ibmrt:*BSD:*|romp-ibm:BSD:*) # covers RT/PC BSD and echo romp-ibm-bsd${UNAME_RELEASE} # 4.3 with uname added to exit ;; # report: romp-ibm BSD 4.3 *:BOSX:*:*) echo rs6000-bull-bosx exit ;; DPX/2?00:B.O.S.:*:*) echo m68k-bull-sysv3 exit ;; 9000/[34]??:4.3bsd:1.*:*) echo m68k-hp-bsd exit ;; hp300:4.4BSD:*:* | 9000/[34]??:4.3bsd:2.*:*) echo m68k-hp-bsd4.4 exit ;; 9000/[34678]??:HP-UX:*:*) HPUX_REV=`echo ${UNAME_RELEASE}|sed -e 's/[^.]*.[0B]*//'` case "${UNAME_MACHINE}" in 9000/31? ) HP_ARCH=m68000 ;; 9000/[34]?? ) HP_ARCH=m68k ;; 9000/[678][0-9][0-9]) if [ -x /usr/bin/getconf ]; then sc_cpu_version=`/usr/bin/getconf SC_CPU_VERSION 2>/dev/null` sc_kernel_bits=`/usr/bin/getconf SC_KERNEL_BITS 2>/dev/null` case "${sc_cpu_version}" in 523) HP_ARCH="hppa1.0" ;; # CPU_PA_RISC1_0 528) HP_ARCH="hppa1.1" ;; # CPU_PA_RISC1_1 532) # CPU_PA_RISC2_0 case "${sc_kernel_bits}" in 32) HP_ARCH="hppa2.0n" ;; 64) HP_ARCH="hppa2.0w" ;; '') HP_ARCH="hppa2.0" ;; # HP-UX 10.20 esac ;; esac fi if [ "${HP_ARCH}" = "" ]; then eval $set_cc_for_build sed 's/^ //' << EOF >$dummy.c #define _HPUX_SOURCE #include #include int main () { #if defined(_SC_KERNEL_BITS) long bits = sysconf(_SC_KERNEL_BITS); #endif long cpu = sysconf (_SC_CPU_VERSION); switch (cpu) { case CPU_PA_RISC1_0: puts ("hppa1.0"); break; case CPU_PA_RISC1_1: puts ("hppa1.1"); break; case CPU_PA_RISC2_0: #if defined(_SC_KERNEL_BITS) switch (bits) { case 64: puts ("hppa2.0w"); break; case 32: puts ("hppa2.0n"); break; default: puts ("hppa2.0"); break; } break; #else /* !defined(_SC_KERNEL_BITS) */ puts ("hppa2.0"); break; #endif default: puts ("hppa1.0"); break; } exit (0); } EOF (CCOPTS= $CC_FOR_BUILD -o $dummy $dummy.c 2>/dev/null) && HP_ARCH=`$dummy` test -z "$HP_ARCH" && HP_ARCH=hppa fi ;; esac if [ ${HP_ARCH} = "hppa2.0w" ] then eval $set_cc_for_build # hppa2.0w-hp-hpux* has a 64-bit kernel and a compiler generating # 32-bit code. hppa64-hp-hpux* has the same kernel and a compiler # generating 64-bit code. GNU and HP use different nomenclature: # # $ CC_FOR_BUILD=cc ./config.guess # => hppa2.0w-hp-hpux11.23 # $ CC_FOR_BUILD="cc +DA2.0w" ./config.guess # => hppa64-hp-hpux11.23 if echo __LP64__ | (CCOPTS= $CC_FOR_BUILD -E - 2>/dev/null) | grep __LP64__ >/dev/null then HP_ARCH="hppa2.0w" else HP_ARCH="hppa64" fi fi echo ${HP_ARCH}-hp-hpux${HPUX_REV} exit ;; ia64:HP-UX:*:*) HPUX_REV=`echo ${UNAME_RELEASE}|sed -e 's/[^.]*.[0B]*//'` echo ia64-hp-hpux${HPUX_REV} exit ;; 3050*:HI-UX:*:*) eval $set_cc_for_build sed 's/^ //' << EOF >$dummy.c #include int main () { long cpu = sysconf (_SC_CPU_VERSION); /* The order matters, because CPU_IS_HP_MC68K erroneously returns true for CPU_PA_RISC1_0. CPU_IS_PA_RISC returns correct results, however. */ if (CPU_IS_PA_RISC (cpu)) { switch (cpu) { case CPU_PA_RISC1_0: puts ("hppa1.0-hitachi-hiuxwe2"); break; case CPU_PA_RISC1_1: puts ("hppa1.1-hitachi-hiuxwe2"); break; case CPU_PA_RISC2_0: puts ("hppa2.0-hitachi-hiuxwe2"); break; default: puts ("hppa-hitachi-hiuxwe2"); break; } } else if (CPU_IS_HP_MC68K (cpu)) puts ("m68k-hitachi-hiuxwe2"); else puts ("unknown-hitachi-hiuxwe2"); exit (0); } EOF $CC_FOR_BUILD -o $dummy $dummy.c && SYSTEM_NAME=`$dummy` && { echo "$SYSTEM_NAME"; exit; } echo unknown-hitachi-hiuxwe2 exit ;; 9000/7??:4.3bsd:*:* | 9000/8?[79]:4.3bsd:*:* ) echo hppa1.1-hp-bsd exit ;; 9000/8??:4.3bsd:*:*) echo hppa1.0-hp-bsd exit ;; *9??*:MPE/iX:*:* | *3000*:MPE/iX:*:*) echo hppa1.0-hp-mpeix exit ;; hp7??:OSF1:*:* | hp8?[79]:OSF1:*:* ) echo hppa1.1-hp-osf exit ;; hp8??:OSF1:*:*) echo hppa1.0-hp-osf exit ;; i*86:OSF1:*:*) if [ -x /usr/sbin/sysversion ] ; then echo ${UNAME_MACHINE}-unknown-osf1mk else echo ${UNAME_MACHINE}-unknown-osf1 fi exit ;; parisc*:Lites*:*:*) echo hppa1.1-hp-lites exit ;; C1*:ConvexOS:*:* | convex:ConvexOS:C1*:*) echo c1-convex-bsd exit ;; C2*:ConvexOS:*:* | convex:ConvexOS:C2*:*) if getsysinfo -f scalar_acc then echo c32-convex-bsd else echo c2-convex-bsd fi exit ;; C34*:ConvexOS:*:* | convex:ConvexOS:C34*:*) echo c34-convex-bsd exit ;; C38*:ConvexOS:*:* | convex:ConvexOS:C38*:*) echo c38-convex-bsd exit ;; C4*:ConvexOS:*:* | convex:ConvexOS:C4*:*) echo c4-convex-bsd exit ;; CRAY*Y-MP:*:*:*) echo ymp-cray-unicos${UNAME_RELEASE} | sed -e 's/\.[^.]*$/.X/' exit ;; CRAY*[A-Z]90:*:*:*) echo ${UNAME_MACHINE}-cray-unicos${UNAME_RELEASE} \ | sed -e 's/CRAY.*\([A-Z]90\)/\1/' \ -e y/ABCDEFGHIJKLMNOPQRSTUVWXYZ/abcdefghijklmnopqrstuvwxyz/ \ -e 's/\.[^.]*$/.X/' exit ;; CRAY*TS:*:*:*) echo t90-cray-unicos${UNAME_RELEASE} | sed -e 's/\.[^.]*$/.X/' exit ;; CRAY*T3E:*:*:*) echo alphaev5-cray-unicosmk${UNAME_RELEASE} | sed -e 's/\.[^.]*$/.X/' exit ;; CRAY*SV1:*:*:*) echo sv1-cray-unicos${UNAME_RELEASE} | sed -e 's/\.[^.]*$/.X/' exit ;; *:UNICOS/mp:*:*) echo craynv-cray-unicosmp${UNAME_RELEASE} | sed -e 's/\.[^.]*$/.X/' exit ;; F30[01]:UNIX_System_V:*:* | F700:UNIX_System_V:*:*) FUJITSU_PROC=`uname -m | tr 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz'` FUJITSU_SYS=`uname -p | tr 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz' | sed -e 's/\///'` FUJITSU_REL=`echo ${UNAME_RELEASE} | sed -e 's/ /_/'` echo "${FUJITSU_PROC}-fujitsu-${FUJITSU_SYS}${FUJITSU_REL}" exit ;; 5000:UNIX_System_V:4.*:*) FUJITSU_SYS=`uname -p | tr 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz' | sed -e 's/\///'` FUJITSU_REL=`echo ${UNAME_RELEASE} | tr 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz' | sed -e 's/ /_/'` echo "sparc-fujitsu-${FUJITSU_SYS}${FUJITSU_REL}" exit ;; i*86:BSD/386:*:* | i*86:BSD/OS:*:* | *:Ascend\ Embedded/OS:*:*) echo ${UNAME_MACHINE}-pc-bsdi${UNAME_RELEASE} exit ;; sparc*:BSD/OS:*:*) echo sparc-unknown-bsdi${UNAME_RELEASE} exit ;; *:BSD/OS:*:*) echo ${UNAME_MACHINE}-unknown-bsdi${UNAME_RELEASE} exit ;; *:FreeBSD:*:*) case ${UNAME_MACHINE} in pc98) echo i386-unknown-freebsd`echo ${UNAME_RELEASE}|sed -e 's/[-(].*//'` ;; amd64) echo x86_64-unknown-freebsd`echo ${UNAME_RELEASE}|sed -e 's/[-(].*//'` ;; *) echo ${UNAME_MACHINE}-unknown-freebsd`echo ${UNAME_RELEASE}|sed -e 's/[-(].*//'` ;; esac exit ;; i*:CYGWIN*:*) echo ${UNAME_MACHINE}-pc-cygwin exit ;; *:MINGW*:*) echo ${UNAME_MACHINE}-pc-mingw32 exit ;; i*:windows32*:*) # uname -m includes "-pc" on this system. echo ${UNAME_MACHINE}-mingw32 exit ;; i*:PW*:*) echo ${UNAME_MACHINE}-pc-pw32 exit ;; *:Interix*:[3456]*) case ${UNAME_MACHINE} in x86) echo i586-pc-interix${UNAME_RELEASE} exit ;; EM64T | authenticamd) echo x86_64-unknown-interix${UNAME_RELEASE} exit ;; IA64) echo ia64-unknown-interix${UNAME_RELEASE} exit ;; esac ;; [345]86:Windows_95:* | [345]86:Windows_98:* | [345]86:Windows_NT:*) echo i${UNAME_MACHINE}-pc-mks exit ;; i*:Windows_NT*:* | Pentium*:Windows_NT*:*) # How do we know it's Interix rather than the generic POSIX subsystem? # It also conflicts with pre-2.0 versions of AT&T UWIN. Should we # UNAME_MACHINE based on the output of uname instead of i386? echo i586-pc-interix exit ;; i*:UWIN*:*) echo ${UNAME_MACHINE}-pc-uwin exit ;; amd64:CYGWIN*:*:* | x86_64:CYGWIN*:*:*) echo x86_64-unknown-cygwin exit ;; p*:CYGWIN*:*) echo powerpcle-unknown-cygwin exit ;; prep*:SunOS:5.*:*) echo powerpcle-unknown-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'` exit ;; *:GNU:*:*) # the GNU system echo `echo ${UNAME_MACHINE}|sed -e 's,[-/].*$,,'`-unknown-gnu`echo ${UNAME_RELEASE}|sed -e 's,/.*$,,'` exit ;; *:GNU/*:*:*) # other systems with GNU libc and userland echo ${UNAME_MACHINE}-unknown-`echo ${UNAME_SYSTEM} | sed 's,^[^/]*/,,' | tr '[A-Z]' '[a-z]'``echo ${UNAME_RELEASE}|sed -e 's/[-(].*//'`-gnu exit ;; i*86:Minix:*:*) echo ${UNAME_MACHINE}-pc-minix exit ;; arm*:Linux:*:*) eval $set_cc_for_build if echo __ARM_EABI__ | $CC_FOR_BUILD -E - 2>/dev/null \ | grep -q __ARM_EABI__ then echo ${UNAME_MACHINE}-unknown-linux-gnu else echo ${UNAME_MACHINE}-unknown-linux-gnueabi fi exit ;; avr32*:Linux:*:*) echo ${UNAME_MACHINE}-unknown-linux-gnu exit ;; cris:Linux:*:*) echo cris-axis-linux-gnu exit ;; crisv32:Linux:*:*) echo crisv32-axis-linux-gnu exit ;; frv:Linux:*:*) echo frv-unknown-linux-gnu exit ;; ia64:Linux:*:*) echo ${UNAME_MACHINE}-unknown-linux-gnu exit ;; m32r*:Linux:*:*) echo ${UNAME_MACHINE}-unknown-linux-gnu exit ;; m68*:Linux:*:*) echo ${UNAME_MACHINE}-unknown-linux-gnu exit ;; mips:Linux:*:*) eval $set_cc_for_build sed 's/^ //' << EOF >$dummy.c #undef CPU #undef mips #undef mipsel #if defined(__MIPSEL__) || defined(__MIPSEL) || defined(_MIPSEL) || defined(MIPSEL) CPU=mipsel #else #if defined(__MIPSEB__) || defined(__MIPSEB) || defined(_MIPSEB) || defined(MIPSEB) CPU=mips #else CPU= #endif #endif EOF eval "`$CC_FOR_BUILD -E $dummy.c 2>/dev/null | sed -n ' /^CPU/{ s: ::g p }'`" test x"${CPU}" != x && { echo "${CPU}-unknown-linux-gnu"; exit; } ;; mips64:Linux:*:*) eval $set_cc_for_build sed 's/^ //' << EOF >$dummy.c #undef CPU #undef mips64 #undef mips64el #if defined(__MIPSEL__) || defined(__MIPSEL) || defined(_MIPSEL) || defined(MIPSEL) CPU=mips64el #else #if defined(__MIPSEB__) || defined(__MIPSEB) || defined(_MIPSEB) || defined(MIPSEB) CPU=mips64 #else CPU= #endif #endif EOF eval "`$CC_FOR_BUILD -E $dummy.c 2>/dev/null | sed -n ' /^CPU/{ s: ::g p }'`" test x"${CPU}" != x && { echo "${CPU}-unknown-linux-gnu"; exit; } ;; or32:Linux:*:*) echo or32-unknown-linux-gnu exit ;; ppc:Linux:*:*) echo powerpc-unknown-linux-gnu exit ;; ppc64:Linux:*:*) echo powerpc64-unknown-linux-gnu exit ;; alpha:Linux:*:*) case `sed -n '/^cpu model/s/^.*: \(.*\)/\1/p' < /proc/cpuinfo` in EV5) UNAME_MACHINE=alphaev5 ;; EV56) UNAME_MACHINE=alphaev56 ;; PCA56) UNAME_MACHINE=alphapca56 ;; PCA57) UNAME_MACHINE=alphapca56 ;; EV6) UNAME_MACHINE=alphaev6 ;; EV67) UNAME_MACHINE=alphaev67 ;; EV68*) UNAME_MACHINE=alphaev68 ;; esac objdump --private-headers /bin/sh | grep ld.so.1 >/dev/null if test "$?" = 0 ; then LIBC="libc1" ; else LIBC="" ; fi echo ${UNAME_MACHINE}-unknown-linux-gnu${LIBC} exit ;; parisc:Linux:*:* | hppa:Linux:*:*) # Look for CPU level case `grep '^cpu[^a-z]*:' /proc/cpuinfo 2>/dev/null | cut -d' ' -f2` in PA7*) echo hppa1.1-unknown-linux-gnu ;; PA8*) echo hppa2.0-unknown-linux-gnu ;; *) echo hppa-unknown-linux-gnu ;; esac exit ;; parisc64:Linux:*:* | hppa64:Linux:*:*) echo hppa64-unknown-linux-gnu exit ;; s390:Linux:*:* | s390x:Linux:*:*) echo ${UNAME_MACHINE}-ibm-linux exit ;; sh64*:Linux:*:*) echo ${UNAME_MACHINE}-unknown-linux-gnu exit ;; sh*:Linux:*:*) echo ${UNAME_MACHINE}-unknown-linux-gnu exit ;; sparc:Linux:*:* | sparc64:Linux:*:*) echo ${UNAME_MACHINE}-unknown-linux-gnu exit ;; vax:Linux:*:*) echo ${UNAME_MACHINE}-dec-linux-gnu exit ;; x86_64:Linux:*:*) echo x86_64-unknown-linux-gnu exit ;; xtensa*:Linux:*:*) echo ${UNAME_MACHINE}-unknown-linux-gnu exit ;; i*86:Linux:*:*) # The BFD linker knows what the default object file format is, so # first see if it will tell us. cd to the root directory to prevent # problems with other programs or directories called `ld' in the path. # Set LC_ALL=C to ensure ld outputs messages in English. ld_supported_targets=`cd /; LC_ALL=C ld --help 2>&1 \ | sed -ne '/supported targets:/!d s/[ ][ ]*/ /g s/.*supported targets: *// s/ .*// p'` case "$ld_supported_targets" in elf32-i386) TENTATIVE="${UNAME_MACHINE}-pc-linux-gnu" ;; a.out-i386-linux) echo "${UNAME_MACHINE}-pc-linux-gnuaout" exit ;; coff-i386) echo "${UNAME_MACHINE}-pc-linux-gnucoff" exit ;; "") # Either a pre-BFD a.out linker (linux-gnuoldld) or # one that does not give us useful --help. echo "${UNAME_MACHINE}-pc-linux-gnuoldld" exit ;; esac # Determine whether the default compiler is a.out or elf eval $set_cc_for_build sed 's/^ //' << EOF >$dummy.c #include #ifdef __ELF__ # ifdef __GLIBC__ # if __GLIBC__ >= 2 LIBC=gnu # else LIBC=gnulibc1 # endif # else LIBC=gnulibc1 # endif #else #if defined(__INTEL_COMPILER) || defined(__PGI) || defined(__SUNPRO_C) || defined(__SUNPRO_CC) LIBC=gnu #else LIBC=gnuaout #endif #endif #ifdef __dietlibc__ LIBC=dietlibc #endif EOF eval "`$CC_FOR_BUILD -E $dummy.c 2>/dev/null | sed -n ' /^LIBC/{ s: ::g p }'`" test x"${LIBC}" != x && { echo "${UNAME_MACHINE}-pc-linux-${LIBC}" exit } test x"${TENTATIVE}" != x && { echo "${TENTATIVE}"; exit; } ;; i*86:DYNIX/ptx:4*:*) # ptx 4.0 does uname -s correctly, with DYNIX/ptx in there. # earlier versions are messed up and put the nodename in both # sysname and nodename. echo i386-sequent-sysv4 exit ;; i*86:UNIX_SV:4.2MP:2.*) # Unixware is an offshoot of SVR4, but it has its own version # number series starting with 2... # I am not positive that other SVR4 systems won't match this, # I just have to hope. -- rms. # Use sysv4.2uw... so that sysv4* matches it. echo ${UNAME_MACHINE}-pc-sysv4.2uw${UNAME_VERSION} exit ;; i*86:OS/2:*:*) # If we were able to find `uname', then EMX Unix compatibility # is probably installed. echo ${UNAME_MACHINE}-pc-os2-emx exit ;; i*86:XTS-300:*:STOP) echo ${UNAME_MACHINE}-unknown-stop exit ;; i*86:atheos:*:*) echo ${UNAME_MACHINE}-unknown-atheos exit ;; i*86:syllable:*:*) echo ${UNAME_MACHINE}-pc-syllable exit ;; i*86:LynxOS:2.*:* | i*86:LynxOS:3.[01]*:* | i*86:LynxOS:4.0*:*) echo i386-unknown-lynxos${UNAME_RELEASE} exit ;; i*86:*DOS:*:*) echo ${UNAME_MACHINE}-pc-msdosdjgpp exit ;; i*86:*:4.*:* | i*86:SYSTEM_V:4.*:*) UNAME_REL=`echo ${UNAME_RELEASE} | sed 's/\/MP$//'` if grep Novell /usr/include/link.h >/dev/null 2>/dev/null; then echo ${UNAME_MACHINE}-univel-sysv${UNAME_REL} else echo ${UNAME_MACHINE}-pc-sysv${UNAME_REL} fi exit ;; i*86:*:5:[678]*) # UnixWare 7.x, OpenUNIX and OpenServer 6. case `/bin/uname -X | grep "^Machine"` in *486*) UNAME_MACHINE=i486 ;; *Pentium) UNAME_MACHINE=i586 ;; *Pent*|*Celeron) UNAME_MACHINE=i686 ;; esac echo ${UNAME_MACHINE}-unknown-sysv${UNAME_RELEASE}${UNAME_SYSTEM}${UNAME_VERSION} exit ;; i*86:*:3.2:*) if test -f /usr/options/cb.name; then UNAME_REL=`sed -n 's/.*Version //p' /dev/null >/dev/null ; then UNAME_REL=`(/bin/uname -X|grep Release|sed -e 's/.*= //')` (/bin/uname -X|grep i80486 >/dev/null) && UNAME_MACHINE=i486 (/bin/uname -X|grep '^Machine.*Pentium' >/dev/null) \ && UNAME_MACHINE=i586 (/bin/uname -X|grep '^Machine.*Pent *II' >/dev/null) \ && UNAME_MACHINE=i686 (/bin/uname -X|grep '^Machine.*Pentium Pro' >/dev/null) \ && UNAME_MACHINE=i686 echo ${UNAME_MACHINE}-pc-sco$UNAME_REL else echo ${UNAME_MACHINE}-pc-sysv32 fi exit ;; pc:*:*:*) # Left here for compatibility: # uname -m prints for DJGPP always 'pc', but it prints nothing about # the processor, so we play safe by assuming i386. echo i386-pc-msdosdjgpp exit ;; Intel:Mach:3*:*) echo i386-pc-mach3 exit ;; paragon:*:*:*) echo i860-intel-osf1 exit ;; i860:*:4.*:*) # i860-SVR4 if grep Stardent /usr/include/sys/uadmin.h >/dev/null 2>&1 ; then echo i860-stardent-sysv${UNAME_RELEASE} # Stardent Vistra i860-SVR4 else # Add other i860-SVR4 vendors below as they are discovered. echo i860-unknown-sysv${UNAME_RELEASE} # Unknown i860-SVR4 fi exit ;; mini*:CTIX:SYS*5:*) # "miniframe" echo m68010-convergent-sysv exit ;; mc68k:UNIX:SYSTEM5:3.51m) echo m68k-convergent-sysv exit ;; M680?0:D-NIX:5.3:*) echo m68k-diab-dnix exit ;; M68*:*:R3V[5678]*:*) test -r /sysV68 && { echo 'm68k-motorola-sysv'; exit; } ;; 3[345]??:*:4.0:3.0 | 3[34]??A:*:4.0:3.0 | 3[34]??,*:*:4.0:3.0 | 3[34]??/*:*:4.0:3.0 | 4400:*:4.0:3.0 | 4850:*:4.0:3.0 | SKA40:*:4.0:3.0 | SDS2:*:4.0:3.0 | SHG2:*:4.0:3.0 | S7501*:*:4.0:3.0) OS_REL='' test -r /etc/.relid \ && OS_REL=.`sed -n 's/[^ ]* [^ ]* \([0-9][0-9]\).*/\1/p' < /etc/.relid` /bin/uname -p 2>/dev/null | grep 86 >/dev/null \ && { echo i486-ncr-sysv4.3${OS_REL}; exit; } /bin/uname -p 2>/dev/null | /bin/grep entium >/dev/null \ && { echo i586-ncr-sysv4.3${OS_REL}; exit; } ;; 3[34]??:*:4.0:* | 3[34]??,*:*:4.0:*) /bin/uname -p 2>/dev/null | grep 86 >/dev/null \ && { echo i486-ncr-sysv4; exit; } ;; m68*:LynxOS:2.*:* | m68*:LynxOS:3.0*:*) echo m68k-unknown-lynxos${UNAME_RELEASE} exit ;; mc68030:UNIX_System_V:4.*:*) echo m68k-atari-sysv4 exit ;; TSUNAMI:LynxOS:2.*:*) echo sparc-unknown-lynxos${UNAME_RELEASE} exit ;; rs6000:LynxOS:2.*:*) echo rs6000-unknown-lynxos${UNAME_RELEASE} exit ;; PowerPC:LynxOS:2.*:* | PowerPC:LynxOS:3.[01]*:* | PowerPC:LynxOS:4.0*:*) echo powerpc-unknown-lynxos${UNAME_RELEASE} exit ;; SM[BE]S:UNIX_SV:*:*) echo mips-dde-sysv${UNAME_RELEASE} exit ;; RM*:ReliantUNIX-*:*:*) echo mips-sni-sysv4 exit ;; RM*:SINIX-*:*:*) echo mips-sni-sysv4 exit ;; *:SINIX-*:*:*) if uname -p 2>/dev/null >/dev/null ; then UNAME_MACHINE=`(uname -p) 2>/dev/null` echo ${UNAME_MACHINE}-sni-sysv4 else echo ns32k-sni-sysv fi exit ;; PENTIUM:*:4.0*:*) # Unisys `ClearPath HMP IX 4000' SVR4/MP effort # says echo i586-unisys-sysv4 exit ;; *:UNIX_System_V:4*:FTX*) # From Gerald Hewes . # How about differentiating between stratus architectures? -djm echo hppa1.1-stratus-sysv4 exit ;; *:*:*:FTX*) # From seanf@swdc.stratus.com. echo i860-stratus-sysv4 exit ;; i*86:VOS:*:*) # From Paul.Green@stratus.com. echo ${UNAME_MACHINE}-stratus-vos exit ;; *:VOS:*:*) # From Paul.Green@stratus.com. echo hppa1.1-stratus-vos exit ;; mc68*:A/UX:*:*) echo m68k-apple-aux${UNAME_RELEASE} exit ;; news*:NEWS-OS:6*:*) echo mips-sony-newsos6 exit ;; R[34]000:*System_V*:*:* | R4000:UNIX_SYSV:*:* | R*000:UNIX_SV:*:*) if [ -d /usr/nec ]; then echo mips-nec-sysv${UNAME_RELEASE} else echo mips-unknown-sysv${UNAME_RELEASE} fi exit ;; BeBox:BeOS:*:*) # BeOS running on hardware made by Be, PPC only. echo powerpc-be-beos exit ;; BeMac:BeOS:*:*) # BeOS running on Mac or Mac clone, PPC only. echo powerpc-apple-beos exit ;; BePC:BeOS:*:*) # BeOS running on Intel PC compatible. echo i586-pc-beos exit ;; SX-4:SUPER-UX:*:*) echo sx4-nec-superux${UNAME_RELEASE} exit ;; SX-5:SUPER-UX:*:*) echo sx5-nec-superux${UNAME_RELEASE} exit ;; SX-6:SUPER-UX:*:*) echo sx6-nec-superux${UNAME_RELEASE} exit ;; SX-7:SUPER-UX:*:*) echo sx7-nec-superux${UNAME_RELEASE} exit ;; SX-8:SUPER-UX:*:*) echo sx8-nec-superux${UNAME_RELEASE} exit ;; SX-8R:SUPER-UX:*:*) echo sx8r-nec-superux${UNAME_RELEASE} exit ;; Power*:Rhapsody:*:*) echo powerpc-apple-rhapsody${UNAME_RELEASE} exit ;; *:Rhapsody:*:*) echo ${UNAME_MACHINE}-apple-rhapsody${UNAME_RELEASE} exit ;; *:Darwin:*:*) UNAME_PROCESSOR=`uname -p` || UNAME_PROCESSOR=unknown case $UNAME_PROCESSOR in unknown) UNAME_PROCESSOR=powerpc ;; esac echo ${UNAME_PROCESSOR}-apple-darwin${UNAME_RELEASE} exit ;; *:procnto*:*:* | *:QNX:[0123456789]*:*) UNAME_PROCESSOR=`uname -p` if test "$UNAME_PROCESSOR" = "x86"; then UNAME_PROCESSOR=i386 UNAME_MACHINE=pc fi echo ${UNAME_PROCESSOR}-${UNAME_MACHINE}-nto-qnx${UNAME_RELEASE} exit ;; *:QNX:*:4*) echo i386-pc-qnx exit ;; NSE-?:NONSTOP_KERNEL:*:*) echo nse-tandem-nsk${UNAME_RELEASE} exit ;; NSR-?:NONSTOP_KERNEL:*:*) echo nsr-tandem-nsk${UNAME_RELEASE} exit ;; *:NonStop-UX:*:*) echo mips-compaq-nonstopux exit ;; BS2000:POSIX*:*:*) echo bs2000-siemens-sysv exit ;; DS/*:UNIX_System_V:*:*) echo ${UNAME_MACHINE}-${UNAME_SYSTEM}-${UNAME_RELEASE} exit ;; *:Plan9:*:*) # "uname -m" is not consistent, so use $cputype instead. 386 # is converted to i386 for consistency with other x86 # operating systems. if test "$cputype" = "386"; then UNAME_MACHINE=i386 else UNAME_MACHINE="$cputype" fi echo ${UNAME_MACHINE}-unknown-plan9 exit ;; *:TOPS-10:*:*) echo pdp10-unknown-tops10 exit ;; *:TENEX:*:*) echo pdp10-unknown-tenex exit ;; KS10:TOPS-20:*:* | KL10:TOPS-20:*:* | TYPE4:TOPS-20:*:*) echo pdp10-dec-tops20 exit ;; XKL-1:TOPS-20:*:* | TYPE5:TOPS-20:*:*) echo pdp10-xkl-tops20 exit ;; *:TOPS-20:*:*) echo pdp10-unknown-tops20 exit ;; *:ITS:*:*) echo pdp10-unknown-its exit ;; SEI:*:*:SEIUX) echo mips-sei-seiux${UNAME_RELEASE} exit ;; *:DragonFly:*:*) echo ${UNAME_MACHINE}-unknown-dragonfly`echo ${UNAME_RELEASE}|sed -e 's/[-(].*//'` exit ;; *:*VMS:*:*) UNAME_MACHINE=`(uname -p) 2>/dev/null` case "${UNAME_MACHINE}" in A*) echo alpha-dec-vms ; exit ;; I*) echo ia64-dec-vms ; exit ;; V*) echo vax-dec-vms ; exit ;; esac ;; *:XENIX:*:SysV) echo i386-pc-xenix exit ;; i*86:skyos:*:*) echo ${UNAME_MACHINE}-pc-skyos`echo ${UNAME_RELEASE}` | sed -e 's/ .*$//' exit ;; i*86:rdos:*:*) echo ${UNAME_MACHINE}-pc-rdos exit ;; esac #echo '(No uname command or uname output not recognized.)' 1>&2 #echo "${UNAME_MACHINE}:${UNAME_SYSTEM}:${UNAME_RELEASE}:${UNAME_VERSION}" 1>&2 eval $set_cc_for_build cat >$dummy.c < # include #endif main () { #if defined (sony) #if defined (MIPSEB) /* BFD wants "bsd" instead of "newsos". Perhaps BFD should be changed, I don't know.... */ printf ("mips-sony-bsd\n"); exit (0); #else #include printf ("m68k-sony-newsos%s\n", #ifdef NEWSOS4 "4" #else "" #endif ); exit (0); #endif #endif #if defined (__arm) && defined (__acorn) && defined (__unix) printf ("arm-acorn-riscix\n"); exit (0); #endif #if defined (hp300) && !defined (hpux) printf ("m68k-hp-bsd\n"); exit (0); #endif #if defined (NeXT) #if !defined (__ARCHITECTURE__) #define __ARCHITECTURE__ "m68k" #endif int version; version=`(hostinfo | sed -n 's/.*NeXT Mach \([0-9]*\).*/\1/p') 2>/dev/null`; if (version < 4) printf ("%s-next-nextstep%d\n", __ARCHITECTURE__, version); else printf ("%s-next-openstep%d\n", __ARCHITECTURE__, version); exit (0); #endif #if defined (MULTIMAX) || defined (n16) #if defined (UMAXV) printf ("ns32k-encore-sysv\n"); exit (0); #else #if defined (CMU) printf ("ns32k-encore-mach\n"); exit (0); #else printf ("ns32k-encore-bsd\n"); exit (0); #endif #endif #endif #if defined (__386BSD__) printf ("i386-pc-bsd\n"); exit (0); #endif #if defined (sequent) #if defined (i386) printf ("i386-sequent-dynix\n"); exit (0); #endif #if defined (ns32000) printf ("ns32k-sequent-dynix\n"); exit (0); #endif #endif #if defined (_SEQUENT_) struct utsname un; uname(&un); if (strncmp(un.version, "V2", 2) == 0) { printf ("i386-sequent-ptx2\n"); exit (0); } if (strncmp(un.version, "V1", 2) == 0) { /* XXX is V1 correct? */ printf ("i386-sequent-ptx1\n"); exit (0); } printf ("i386-sequent-ptx\n"); exit (0); #endif #if defined (vax) # if !defined (ultrix) # include # if defined (BSD) # if BSD == 43 printf ("vax-dec-bsd4.3\n"); exit (0); # else # if BSD == 199006 printf ("vax-dec-bsd4.3reno\n"); exit (0); # else printf ("vax-dec-bsd\n"); exit (0); # endif # endif # else printf ("vax-dec-bsd\n"); exit (0); # endif # else printf ("vax-dec-ultrix\n"); exit (0); # endif #endif #if defined (alliant) && defined (i860) printf ("i860-alliant-bsd\n"); exit (0); #endif exit (1); } EOF $CC_FOR_BUILD -o $dummy $dummy.c 2>/dev/null && SYSTEM_NAME=`$dummy` && { echo "$SYSTEM_NAME"; exit; } # Apollos put the system type in the environment. test -d /usr/apollo && { echo ${ISP}-apollo-${SYSTYPE}; exit; } # Convex versions that predate uname can use getsysinfo(1) if [ -x /usr/convex/getsysinfo ] then case `getsysinfo -f cpu_type` in c1*) echo c1-convex-bsd exit ;; c2*) if getsysinfo -f scalar_acc then echo c32-convex-bsd else echo c2-convex-bsd fi exit ;; c34*) echo c34-convex-bsd exit ;; c38*) echo c38-convex-bsd exit ;; c4*) echo c4-convex-bsd exit ;; esac fi cat >&2 < in order to provide the needed information to handle your system. config.guess timestamp = $timestamp uname -m = `(uname -m) 2>/dev/null || echo unknown` uname -r = `(uname -r) 2>/dev/null || echo unknown` uname -s = `(uname -s) 2>/dev/null || echo unknown` uname -v = `(uname -v) 2>/dev/null || echo unknown` /usr/bin/uname -p = `(/usr/bin/uname -p) 2>/dev/null` /bin/uname -X = `(/bin/uname -X) 2>/dev/null` hostinfo = `(hostinfo) 2>/dev/null` /bin/universe = `(/bin/universe) 2>/dev/null` /usr/bin/arch -k = `(/usr/bin/arch -k) 2>/dev/null` /bin/arch = `(/bin/arch) 2>/dev/null` /usr/bin/oslevel = `(/usr/bin/oslevel) 2>/dev/null` /usr/convex/getsysinfo = `(/usr/convex/getsysinfo) 2>/dev/null` UNAME_MACHINE = ${UNAME_MACHINE} UNAME_RELEASE = ${UNAME_RELEASE} UNAME_SYSTEM = ${UNAME_SYSTEM} UNAME_VERSION = ${UNAME_VERSION} EOF exit 1 # Local variables: # eval: (add-hook 'write-file-hooks 'time-stamp) # time-stamp-start: "timestamp='" # time-stamp-format: "%:y-%02m-%02d" # time-stamp-end: "'" # End: