summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--.travis.yml36
-rw-r--r--COPYING21
-rw-r--r--Makefile.am10
-rw-r--r--Makefile.builds.in4
-rw-r--r--NEWS3
-rw-r--r--config/cvc4.m43
-rw-r--r--configure.ac32
-rw-r--r--examples/README19
-rw-r--r--examples/api/Makefile.am9
-rw-r--r--examples/api/datatypes.cpp103
-rw-r--r--examples/api/java/Datatypes.java103
-rw-r--r--examples/api/java/Makefile.am2
-rw-r--r--library_versions1
-rw-r--r--proofs/lfsc_checker/.gitignore16
-rw-r--r--proofs/lfsc_checker/AUTHORS5
-rw-r--r--proofs/lfsc_checker/COPYING17
-rw-r--r--proofs/lfsc_checker/INSTALL370
-rw-r--r--proofs/lfsc_checker/Makefile.am30
-rw-r--r--proofs/lfsc_checker/NEWS9
-rw-r--r--proofs/lfsc_checker/README83
-rw-r--r--proofs/lfsc_checker/check.cpp1383
-rw-r--r--proofs/lfsc_checker/check.h167
-rw-r--r--proofs/lfsc_checker/chunking_memory_management.h157
-rw-r--r--proofs/lfsc_checker/code.cpp1377
-rw-r--r--proofs/lfsc_checker/code.h15
-rw-r--r--proofs/lfsc_checker/configure.ac47
-rw-r--r--proofs/lfsc_checker/expr.cpp966
-rw-r--r--proofs/lfsc_checker/expr.h367
-rw-r--r--proofs/lfsc_checker/libwriter.cpp238
-rw-r--r--proofs/lfsc_checker/libwriter.h28
-rw-r--r--proofs/lfsc_checker/main.cpp139
-rw-r--r--proofs/lfsc_checker/position.h30
-rw-r--r--proofs/lfsc_checker/print_smt2.cpp122
-rw-r--r--proofs/lfsc_checker/print_smt2.h17
-rw-r--r--proofs/lfsc_checker/scccode.cpp609
-rw-r--r--proofs/lfsc_checker/scccode.h27
-rw-r--r--proofs/lfsc_checker/sccwriter.cpp977
-rw-r--r--proofs/lfsc_checker/sccwriter.h86
-rw-r--r--proofs/lfsc_checker/trie.cpp24
-rw-r--r--proofs/lfsc_checker/trie.h129
-rw-r--r--proofs/signatures/Makefile.am34
-rwxr-xr-xproofs/signatures/example.plf232
-rwxr-xr-xproofs/signatures/sat.plf254
-rwxr-xr-xproofs/signatures/smt.plf168
-rwxr-xr-xproofs/signatures/th_arrays.plf53
-rwxr-xr-xproofs/signatures/th_base.plf180
-rw-r--r--src/Makefile.am10
-rw-r--r--src/cvc4.i1
-rw-r--r--src/main/command_executor.cpp22
-rw-r--r--src/main/command_executor_portfolio.cpp22
-rw-r--r--src/main/driver_unified.cpp7
-rwxr-xr-xsrc/options/mkoptions48
-rw-r--r--src/parser/smt2/Smt2.g8
-rw-r--r--src/printer/ast/ast_printer.cpp4
-rw-r--r--src/printer/cvc/cvc_printer.cpp5
-rw-r--r--src/printer/smt2/smt2_printer.cpp5
-rw-r--r--src/proof/cnf_proof.cpp52
-rw-r--r--src/proof/cnf_proof.h42
-rw-r--r--src/proof/proof.h2
-rw-r--r--src/proof/proof_manager.cpp73
-rw-r--r--src/proof/proof_manager.h67
-rw-r--r--src/proof/sat_proof.cpp466
-rw-r--r--src/proof/sat_proof.h136
-rw-r--r--src/proof/theory_proof.cpp229
-rw-r--r--src/proof/theory_proof.h21
-rw-r--r--src/prop/minisat/core/Solver.cc44
-rw-r--r--src/smt/options8
-rw-r--r--src/smt/smt_engine.cpp70
-rw-r--r--src/smt/smt_engine.h12
-rw-r--r--src/smt/smt_engine.i2
-rw-r--r--src/smt/smt_engine_check_proof.cpp95
-rw-r--r--src/smt/smt_engine_scope.h10
-rw-r--r--src/theory/quantifiers/first_order_model.cpp249
-rw-r--r--src/theory/quantifiers/first_order_model.h73
-rw-r--r--src/theory/quantifiers/full_model_check.cpp33
-rw-r--r--src/theory/quantifiers/full_model_check.h2
-rw-r--r--src/theory/quantifiers/model_builder.cpp29
-rw-r--r--src/theory/quantifiers/model_engine.cpp20
-rw-r--r--src/theory/quantifiers/model_engine.h1
-rw-r--r--src/theory/quantifiers/modes.cpp23
-rw-r--r--src/theory/quantifiers/modes.h16
-rw-r--r--src/theory/quantifiers/options36
-rw-r--r--src/theory/quantifiers/options_handlers.h51
-rwxr-xr-xsrc/theory/quantifiers/qinterval_builder.cpp1111
-rwxr-xr-xsrc/theory/quantifiers/qinterval_builder.h155
-rw-r--r--src/theory/quantifiers/term_database.cpp10
-rw-r--r--src/theory/quantifiers_engine.cpp8
-rw-r--r--src/theory/strings/kinds7
-rw-r--r--src/theory/strings/theory_strings.cpp119
-rw-r--r--src/theory/strings/theory_strings.h5
-rw-r--r--src/theory/strings/theory_strings_preprocess.cpp21
-rw-r--r--src/theory/strings/theory_strings_rewriter.cpp40
-rw-r--r--src/theory/strings/theory_strings_type_rules.h42
-rw-r--r--src/theory/theory.h7
-rw-r--r--src/theory/theory_engine.cpp1
-rw-r--r--src/theory/uf/equality_engine.cpp217
-rw-r--r--src/theory/uf/equality_engine.h38
-rw-r--r--src/theory/uf/equality_engine_types.h29
-rw-r--r--src/theory/uf/options6
-rw-r--r--src/theory/uf/theory_uf.cpp11
-rw-r--r--src/theory/uf/theory_uf_model.cpp32
-rw-r--r--src/theory/uf/theory_uf_strong_solver.cpp159
-rw-r--r--src/theory/uf/theory_uf_strong_solver.h22
-rw-r--r--src/util/Makefile.am3
-rw-r--r--src/util/datatype.cpp6
-rw-r--r--src/util/datatype.h73
-rw-r--r--src/util/datatype.i128
-rw-r--r--src/util/proof.i5
-rw-r--r--src/util/regexp.h19
-rw-r--r--test/regress/regress0/Makefile.am4
-rw-r--r--test/regress/regress0/arith/Makefile.am4
-rw-r--r--test/regress/regress0/arith/integers/Makefile.am4
-rw-r--r--test/regress/regress0/arrays/Makefile.am4
-rw-r--r--test/regress/regress0/aufbv/Makefile.am4
-rw-r--r--test/regress/regress0/auflia/Makefile.am4
-rw-r--r--test/regress/regress0/boolean.cvc1
-rw-r--r--test/regress/regress0/bv/Makefile.am4
-rw-r--r--test/regress/regress0/bv/core/Makefile.am4
-rw-r--r--test/regress/regress0/datatypes/Makefile.am4
-rw-r--r--test/regress/regress0/datatypes/empty_tuprec.cvc2
-rw-r--r--test/regress/regress0/decision/Makefile.am4
-rw-r--r--test/regress/regress0/fmf/Makefile.am4
-rw-r--r--test/regress/regress0/fmf/PUZ001+1.smt22
-rw-r--r--test/regress/regress0/hole6.cvc1
-rw-r--r--test/regress/regress0/lemmas/Makefile.am4
-rw-r--r--test/regress/regress0/precedence/Makefile.am4
-rw-r--r--test/regress/regress0/preprocess/Makefile.am4
-rw-r--r--test/regress/regress0/push-pop/Makefile.am4
-rw-r--r--test/regress/regress0/push-pop/arith/Makefile.am4
-rw-r--r--test/regress/regress0/push-pop/boolean/Makefile.am4
-rw-r--r--test/regress/regress0/quantifiers/Makefile.am4
-rw-r--r--test/regress/regress0/rewriterules/Makefile.am4
-rw-r--r--test/regress/regress0/strings/Makefile.am4
-rw-r--r--test/regress/regress0/strings/substr001.smt24
-rw-r--r--test/regress/regress0/tptp/Makefile.am4
-rw-r--r--test/regress/regress0/uf/Makefile.am4
-rw-r--r--test/regress/regress0/uflia/Makefile.am4
-rw-r--r--test/regress/regress0/uflra/Makefile.am4
-rw-r--r--test/regress/regress0/unconstrained/Makefile.am4
-rw-r--r--test/regress/regress0/wiki.05.cvc1
-rw-r--r--test/regress/regress1/Makefile.am4
-rw-r--r--test/regress/regress1/arith/Makefile.am4
-rw-r--r--test/regress/regress2/Makefile.am4
-rw-r--r--test/regress/regress3/Makefile.am4
-rwxr-xr-xtest/regress/run_regression79
145 files changed, 11585 insertions, 1591 deletions
diff --git a/.travis.yml b/.travis.yml
index f351e8a41..9b8482c00 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -4,9 +4,11 @@ compiler:
- gcc
- clang
env:
- - TRAVIS_CVC4_CONFIG='production --enable-language-bindings=java,c'
- - TRAVIS_CVC4_CONFIG='debug --enable-language-bindings=java,c'
- - TRAVIS_CVC4_DISTCHECK=yes
+ - TRAVIS_CVC4=yes TRAVIS_CVC4_CONFIG='production --enable-language-bindings=java,c'
+ - TRAVIS_CVC4=yes TRAVIS_CVC4_CONFIG='debug --enable-language-bindings=java,c'
+ - TRAVIS_CVC4=yes TRAVIS_CVC4_DISTCHECK=yes
+ - TRAVIS_LFSC=yes
+ - TRAVIS_LFSC=yes TRAVIS_LFSC_DISTCHECK=yes
before_install:
# dhart/ppa is for cxxtest package, which doesn't appear officially until quantal
- travis_retry sudo apt-add-repository -y ppa:dhart/ppa
@@ -17,17 +19,29 @@ before_script:
- export PATH=$PATH:$JAVA_HOME/bin
- export JAVA_CPPFLAGS=-I$JAVA_HOME/include
- ./autogen.sh
- - echo $TRAVIS_CVC4_CONFIG
- - normal="$(echo -e '\033[0m')" red="$normal$(echo -e '\033[01;31m')" green="$normal$(echo -e '\033[01;32m')"
- - ./configure --enable-unit-testing --enable-proof --with-portfolio $TRAVIS_CVC4_CONFIG || (echo; cat builds/config.log; echo; echo "${red}CONFIGURE FAILED${normal}"; exit 1)
script:
- normal="$(echo -e '\033[0m')" red="$normal$(echo -e '\033[01;31m')" green="$normal$(echo -e '\033[01;32m')"
- - if [ -n "$TRAVIS_CVC4_DISTCHECK" ]; then
- make -j2 distcheck CVC4_REGRESSION_ARGS='--no-early-exit' || (echo; echo "${red}DISTCHECK FAILED${normal}"; echo; exit 1);
+ - if [ -n "$TRAVIS_CVC4" ]; then
+ echo "CVC4 config - $TRAVIS_CVC4_CONFIG" &&
+ (./configure --enable-unit-testing --enable-proof --with-portfolio $TRAVIS_CVC4_CONFIG || (echo; cat builds/config.log; echo; echo "${red}CONFIGURE FAILED${normal}"; exit 1)) &&
+ if [ -n "$TRAVIS_CVC4_DISTCHECK" ]; then
+ make -j2 distcheck CVC4_REGRESSION_ARGS='--no-early-exit' || (echo; echo "${red}DISTCHECK FAILED${normal}"; echo; exit 1);
+ else
+ (make -j2 check CVC4_REGRESSION_ARGS='--no-early-exit' || (echo; echo "${red}BUILD/TEST FAILED${normal}"; echo; exit 1)) &&
+ (make check BINARY=pcvc4 CVC4_REGRESSION_ARGS='--fallback-sequential --no-early-exit' RUN_REGRESSION_ARGS= || (echo; echo "${red}PORTFOLIO TEST FAILED${normal}"; echo; exit 1)) &&
+ (make -j2 examples || (echo; echo "${red}COULD NOT BUILD EXAMPLES${normal}"; echo; exit 1));
+ fi;
+ elif [ -n "$TRAVIS_LFSC" ]; then
+ cd proofs/lfsc_checker &&
+ (./configure || (echo; cat builds/config.log; echo; echo "${red}CONFIGURE FAILED${normal}"; exit 1)) &&
+ if [ -n "$TRAVIS_LFSC_DISTCHECK" ]; then
+ make -j2 distcheck || (echo; echo "${red}LFSC DISTCHECK FAILED${normal}"; echo; exit 1);
+ else
+ make -j2 || (echo; echo "${red}LFSC BUILD FAILED${normal}"; echo; exit 1);
+ fi;
else
- (make -j2 check CVC4_REGRESSION_ARGS='--no-early-exit' || (echo; echo "${red}BUILD/TEST FAILED${normal}"; echo; exit 1)) &&
- (make check BINARY=pcvc4 CVC4_REGRESSION_ARGS='--fallback-sequential --no-early-exit' || (echo; echo "${red}PORTFOLIO TEST FAILED${normal}"; echo; exit 1)) &&
- (make -j2 examples || (echo; echo "${red}COULD NOT BUILD EXAMPLES${normal}"; echo; exit 1));
+ echo "${red}Unknown Travis-CI configuration${normal}";
+ exit 1;
fi &&
(echo; echo "${green}EVERYTHING SEEMED TO PASS!${normal}")
matrix:
diff --git a/COPYING b/COPYING
index c02b10910..4bccb1d13 100644
--- a/COPYING
+++ b/COPYING
@@ -272,3 +272,24 @@ you build a version of CVC4 that uses no GPLed libraries, configure CVC4 with
the "--bsd" option before building (which is the default). CVC4 can then be
used in contexts where you want to license CVC4 under the (modified) BSD
license.
+
+CVC4 sources incorporate those of the LFSC proof checker, which is
+covered by the following license:
+
+ LFSC is copyright (C) 2012, 2013 The University of Iowa. All rights
+ reserved.
+
+ LFSC is open-source; distribution is under the terms of the modified
+ BSD license.
+
+ 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.
diff --git a/Makefile.am b/Makefile.am
index 41586cbe7..55c357def 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -5,8 +5,13 @@ AM_CXXFLAGS = -Wall -Wno-unknown-pragmas
AUTOMAKE_OPTIONS = foreign
ACLOCAL_AMFLAGS = -I config
-SUBDIRS = src test contrib
-DIST_SUBDIRS = $(SUBDIRS) examples
+SUBDIRS_BASE = src test contrib
+if CVC4_PROOF
+ SUBDIRS = proofs/signatures proofs/lfsc_checker $(SUBDIRS_BASE)
+else
+ SUBDIRS = $(SUBDIRS_BASE)
+endif
+DIST_SUBDIRS = proofs/signatures proofs/lfsc_checker $(SUBDIRS_BASE) examples
.PHONY: examples
examples: all
@@ -126,6 +131,7 @@ EXTRA_DIST = \
doc/options.3cvc_template.in \
doc/libcvc4parser.3.in \
doc/libcvc4compat.3.in
+
man_MANS = \
doc/cvc4.1 \
doc/pcvc4.1 \
diff --git a/Makefile.builds.in b/Makefile.builds.in
index 33df24f95..296e5a974 100644
--- a/Makefile.builds.in
+++ b/Makefile.builds.in
@@ -192,12 +192,12 @@ endif
# The descent into "src" with target "check" is to build check
# prerequisites (e.g. CHECK_PROGRAMS, CHECK_LTLIBRARIES, ...).
-check test units:
+check test units: all
(cd $(CURRENT_BUILD)/src && $(MAKE) check)
+(cd $(CURRENT_BUILD)/test && $(MAKE) $@)
systemtests regress: all
+(cd $(CURRENT_BUILD)/test && $(MAKE) $@)
-units%:
+units%: all
(cd $(CURRENT_BUILD)/src && $(MAKE) check)
+(cd $(CURRENT_BUILD)/test && $(MAKE) units TEST_PREFIX=$(subst units:,,$@))
regress%: all
diff --git a/NEWS b/NEWS
index 05234ebff..f0159f4a1 100644
--- a/NEWS
+++ b/NEWS
@@ -4,6 +4,7 @@ Changes since 1.3
=================
* Timed statistics are now properly updated even on process abort.
+* The LFSC proof checker has been incorporated into CVC4 sources.
* By default, CVC4 builds in "production" mode (optimized, with fewer
internal checks on). The common alternative is a "debug" build, which
is much slower. By default, CVC4 builds with no GPL'ed dependences.
@@ -11,6 +12,8 @@ Changes since 1.3
configure with "--enable-gpl --best", which links against GPL'ed
libraries that improve usability and performance. For details on
licensing and dependences, see the README file.
+* Small API adjustments to Datatypes to even out the API and make it
+ function better in Java.
* Better automatic handling of output language setting when using CVC4
via API. Previously, the "automatic" language setting was sometimes
(though not always) defaulting to the internal "AST" language; it
diff --git a/config/cvc4.m4 b/config/cvc4.m4
index 7c2f6c82d..40e2054e6 100644
--- a/config/cvc4.m4
+++ b/config/cvc4.m4
@@ -42,6 +42,9 @@ handle_option() {
handle_option --with-cln
return
;;
+ -enable-proofs|--enable-proofs)
+ ac_option='--enable-proof'
+ ;;
-*|*=*)
;;
production|production-*|debug|debug-*|competition|competition-*)
diff --git a/configure.ac b/configure.ac
index 24ebf95f8..bf1e0dd0c 100644
--- a/configure.ac
+++ b/configure.ac
@@ -2,8 +2,8 @@
# Process this file with autoconf to produce a configure script.
m4_define(_CVC4_MAJOR, 1) dnl version (major)
-m4_define(_CVC4_MINOR, 3) dnl version (minor)
-m4_define(_CVC4_RELEASE, 1) dnl version (alpha)
+m4_define(_CVC4_MINOR, 4) dnl version (minor)
+m4_define(_CVC4_RELEASE, 0) dnl version (alpha)
m4_define(_CVC4_EXTRAVERSION, [-prerelease]) dnl version (extra)
m4_define(_CVC4_RELEASE_STRING, _CVC4_MAJOR[.]_CVC4_MINOR[]m4_if(_CVC4_RELEASE,[0],,[.]_CVC4_RELEASE)_CVC4_EXTRAVERSION) dnl version string
@@ -16,6 +16,7 @@ AC_CONFIG_SRCDIR([src/include/cvc4_public.h])
AC_CONFIG_AUX_DIR([config])
AC_CONFIG_MACRO_DIR([config])
AC_CONFIG_LIBOBJ_DIR([src/lib])
+AC_CONFIG_SUBDIRS([proofs/lfsc_checker])
m4_ifdef([AM_SILENT_RULES],[AM_SILENT_RULES([yes])])
@@ -533,6 +534,7 @@ AC_MSG_RESULT([$enable_proof])
if test "$enable_proof" = yes; then
CVC4CPPFLAGS="${CVC4CPPFLAGS:+$CVC4CPPFLAGS }-DCVC4_PROOF"
fi
+AM_CONDITIONAL([CVC4_PROOF], [test "$enable_proof" = yes])
AC_MSG_CHECKING([whether to optimize libcvc4])
@@ -896,29 +898,13 @@ if test "$CVC4_CONFIGURE_IN_BUILDS" = yes -a -n "$CXXTEST"; then
esac
fi
-AC_ARG_VAR(LFSC, [path to LFSC proof checker])
-AC_ARG_VAR(LFSCARGS, [arguments to pass to LFSC proof checker])
-if test -z "$LFSC"; then
- AC_CHECK_PROGS(LFSC, lfsc, [], [])
-else
- AC_CHECK_PROG(LFSC, "$LFSC", [], [])
-fi
-AM_CONDITIONAL([PROOF_REGRESSIONS], [test -n "$LFSC" -a "$enable_proof" = yes])
-if test -n "$LFSC" -a "$enable_proof" = yes; then
- TESTS_ENVIRONMENT="${TESTS_ENVIRONMENT:+$TESTS_ENVIRONMENT }LFSC=\"$LFSC $LFSCARGS\""
+TESTS_ENVIRONMENT=
+RUN_REGRESSION_ARGS=
+if test "$enable_proof" = yes; then
RUN_REGRESSION_ARGS="${RUN_REGRESSION_ARGS:+$RUN_REGRESSION_ARGS }--proof"
fi
AC_SUBST([TESTS_ENVIRONMENT])
AC_SUBST([RUN_REGRESSION_ARGS])
-if test -z "$LFSC"; then
- support_proof_tests='no, lfsc proof checker unavailable'
-elif test "$enable_proof" = yes; then
- support_proof_tests='yes, proof regression tests enabled'
-else
- support_proof_tests='no, proof-generation disabled for this build'
-fi
-AC_SUBST([LFSC])
-AC_SUBST([LFSCARGS])
CXXTESTGEN=
AC_PATH_PROG(CXXTESTGEN, cxxtestgen.pl, [], [$CXXTEST:$PATH])
@@ -1290,7 +1276,8 @@ AC_SUBST(MAN_DATE)
AC_CONFIG_FILES([
Makefile.builds
- Makefile]
+ Makefile
+ proofs/signatures/Makefile]
m4_esyscmd([find contrib src test examples -name Makefile.am | grep -v '^contrib/theoryskel/' | grep -v '^contrib/alttheoryskel/' | sort | sed 's,\.am$,,'])
)
@@ -1428,7 +1415,6 @@ Dumping : $enable_dumping
Muzzle : $enable_muzzle
Unit tests : $support_unit_tests
-Proof tests : $support_proof_tests
gcov support : $enable_coverage
gprof support: $enable_profiling
diff --git a/examples/README b/examples/README
index 246388085..d64ed3469 100644
--- a/examples/README
+++ b/examples/README
@@ -10,6 +10,12 @@ world" examples, and do not fully demonstrate the interfaces, but
function as a starting point to using simple expressions and solving
functionality through each library.
+*** Targetted examples
+
+The "api" directory contains some more specifically-targetted
+examples (for bitvectors, for arithmetic, etc.). The "api/java"
+directory contains the same examples in Java.
+
*** Installing example source code
Examples are not automatically installed by "make install". If you
@@ -21,13 +27,8 @@ in /usr/local/share/doc/cvc4/examples).
*** Building examples
Examples can be built as a separate step, after building CVC4 from
-source. After building CVC4, you can run "make examples" (or just
-"make" from *inside* the examples directory). You'll find the built
-binaries in builds/examples (or just in "examples" if you configured a
-build directory outside of the source tree).
-
-Many of the language bindings examples (python, ocaml, ruby, etc.) do
-not need to be compiled to run. These are not compiled by
-"make"---see the comments in the files for ideas on how to run them.
+source. After building CVC4, you can run "make examples". You'll
+find the built binaries in builds/examples (or just in "examples" if
+you configured a build directory outside of the source tree).
--- Morgan Deters <mdeters@cs.nyu.edu> Wed, 03 Oct 2012 15:47:33 -0400
+-- Morgan Deters <mdeters@cs.nyu.edu> Tue, 24 Dec 2013 09:12:59 -0500
diff --git a/examples/api/Makefile.am b/examples/api/Makefile.am
index 6dba17b05..0d0236376 100644
--- a/examples/api/Makefile.am
+++ b/examples/api/Makefile.am
@@ -10,8 +10,8 @@ noinst_PROGRAMS = \
helloworld \
combination \
bitvectors \
- bitvectors_and_arrays
-
+ bitvectors_and_arrays \
+ datatypes
noinst_DATA =
@@ -40,6 +40,11 @@ bitvectors_SOURCES = \
bitvectors_LDADD = \
@builddir@/../../src/libcvc4.la
+datatypes_SOURCES = \
+ datatypes.cpp
+datatypes_LDADD = \
+ @builddir@/../../src/libcvc4.la
+
# for installation
examplesdir = $(docdir)/$(subdir)
examples_DATA = $(DIST_SOURCES) $(EXTRA_DIST)
diff --git a/examples/api/datatypes.cpp b/examples/api/datatypes.cpp
new file mode 100644
index 000000000..dea83a95a
--- /dev/null
+++ b/examples/api/datatypes.cpp
@@ -0,0 +1,103 @@
+/********************* */
+/*! \file datatypes.cpp
+ ** \verbatim
+ ** Original author: Morgan Deters
+ ** Major contributors: none
+ ** Minor contributors (to current version): none
+ ** This file is part of the CVC4 project.
+ ** Copyright (c) 2009-2013 New York University and The University of Iowa
+ ** See the file COPYING in the top-level source directory for licensing
+ ** information.\endverbatim
+ **
+ ** \brief An example of using inductive datatypes in CVC4
+ **
+ ** An example of using inductive datatypes in CVC4.
+ **/
+
+#include <iostream>
+#include "smt/smt_engine.h" // for use with make examples
+#include "util/language.h" // for use with make examples
+//#include <cvc4/cvc4.h> // To follow the wiki
+
+using namespace CVC4;
+
+int main() {
+ ExprManager em;
+ SmtEngine smt(&em);
+
+ // This example builds a simple "cons list" of integers, with
+ // two constructors, "cons" and "nil."
+
+ // Building a datatype consists of two steps. First, the datatype
+ // is specified. Second, it is "resolved"---at which point function
+ // symbols are assigned to its constructors, selectors, and testers.
+
+ Datatype consListSpec("list"); // give the datatype a name
+ DatatypeConstructor cons("cons");
+ cons.addArg("head", em.integerType());
+ cons.addArg("tail", DatatypeSelfType()); // a list
+ consListSpec.addConstructor(cons);
+ DatatypeConstructor nil("nil");
+ consListSpec.addConstructor(nil);
+
+ std::cout << "spec is:" << std::endl
+ << consListSpec << std::endl;
+
+ // Keep in mind that "Datatype" is the specification class for
+ // datatypes---"Datatype" is not itself a CVC4 Type. Now that
+ // our Datatype is fully specified, we can get a Type for it.
+ // This step resolves the "SelfType" reference and creates
+ // symbols for all the constructors, etc.
+
+ DatatypeType consListType = em.mkDatatypeType(consListSpec);
+
+ // Now our old "consListSpec" is useless--the relevant information
+ // has been copied out, so we can throw that spec away. We can get
+ // the complete spec for the datatype from the DatatypeType, and
+ // this Datatype object has constructor symbols (and others) filled in.
+
+ const Datatype& consList = consListType.getDatatype();
+
+ // e = cons 0 nil
+ //
+ // Here, consList["cons"] gives you the DatatypeConstructor. To get
+ // the constructor symbol for application, use .getConstructor("cons"),
+ // which is equivalent to consList["cons"].getConstructor(). Note that
+ // "nil" is a constructor too, so it needs to be applied with
+ // APPLY_CONSTRUCTOR, even though it has no arguments.
+ Expr e = em.mkExpr(kind::APPLY_CONSTRUCTOR,
+ consList.getConstructor("cons"),
+ em.mkConst(Rational(0)),
+ em.mkExpr(kind::APPLY_CONSTRUCTOR,
+ consList.getConstructor("nil")));
+
+ std::cout << "e is " << e << std::endl
+ << "type of cons is " << consList.getConstructor("cons").getType()
+ << std::endl
+ << "type of nil is " << consList.getConstructor("nil").getType()
+ << std::endl;
+
+ // e2 = head(cons 0 nil), and of course this can be evaluated
+ //
+ // Here we first get the DatatypeConstructor for cons (with
+ // consList["cons"]) in order to get the "head" selector symbol
+ // to apply.
+ Expr e2 = em.mkExpr(kind::APPLY_SELECTOR,
+ consList["cons"].getSelector("head"),
+ e);
+
+ std::cout << "e2 is " << e2 << std::endl
+ << "simplify(e2) is " << smt.simplify(e2)
+ << std::endl << std::endl;
+
+ // You can also iterate over a Datatype to get all its constructors,
+ // and over a DatatypeConstructor to get all its "args" (selectors)
+ for(Datatype::iterator i = consList.begin(); i != consList.end(); ++i) {
+ std::cout << "ctor: " << *i << std::endl;
+ for(DatatypeConstructor::iterator j = (*i).begin(); j != (*i).end(); ++j) {
+ std::cout << " + arg: " << *j << std::endl;
+ }
+ }
+
+ return 0;
+}
diff --git a/examples/api/java/Datatypes.java b/examples/api/java/Datatypes.java
new file mode 100644
index 000000000..9406031c1
--- /dev/null
+++ b/examples/api/java/Datatypes.java
@@ -0,0 +1,103 @@
+/********************* */
+/*! \file Datatypes.java
+ ** \verbatim
+ ** Original author: Morgan Deters
+ ** Major contributors: none
+ ** Minor contributors (to current version): none
+ ** This file is part of the CVC4 project.
+ ** Copyright (c) 2009-2013 New York University and The University of Iowa
+ ** See the file COPYING in the top-level source directory for licensing
+ ** information.\endverbatim
+ **
+ ** \brief An example of using inductive datatypes in CVC4 (Java version)
+ **
+ ** An example of using inductive datatypes in CVC4 (Java version).
+ **/
+
+import edu.nyu.acsys.CVC4.*;
+import java.util.Iterator;
+
+public class Datatypes {
+ public static void main(String[] args) {
+ System.loadLibrary("cvc4jni");
+
+ ExprManager em = new ExprManager();
+ SmtEngine smt = new SmtEngine(em);
+
+ // This example builds a simple "cons list" of integers, with
+ // two constructors, "cons" and "nil."
+
+ // Building a datatype consists of two steps. First, the datatype
+ // is specified. Second, it is "resolved"---at which point function
+ // symbols are assigned to its constructors, selectors, and testers.
+
+ Datatype consListSpec = new Datatype("list"); // give the datatype a name
+ DatatypeConstructor cons = new DatatypeConstructor("cons");
+ cons.addArg("head", em.integerType());
+ cons.addArg("tail", new DatatypeSelfType()); // a list
+ consListSpec.addConstructor(cons);
+ DatatypeConstructor nil = new DatatypeConstructor("nil");
+ consListSpec.addConstructor(nil);
+
+ System.out.println("spec is:");
+ System.out.println(consListSpec);
+
+ // Keep in mind that "Datatype" is the specification class for
+ // datatypes---"Datatype" is not itself a CVC4 Type. Now that
+ // our Datatype is fully specified, we can get a Type for it.
+ // This step resolves the "SelfType" reference and creates
+ // symbols for all the constructors, etc.
+
+ DatatypeType consListType = em.mkDatatypeType(consListSpec);
+
+ // Now our old "consListSpec" is useless--the relevant information
+ // has been copied out, so we can throw that spec away. We can get
+ // the complete spec for the datatype from the DatatypeType, and
+ // this Datatype object has constructor symbols (and others) filled in.
+
+ Datatype consList = consListType.getDatatype();
+
+ // e = cons 0 nil
+ //
+ // Here, consList.get("cons") gives you the DatatypeConstructor
+ // (just as consList["cons"] does in C++). To get the constructor
+ // symbol for application, use .getConstructor("cons"), which is
+ // equivalent to consList.get("cons").getConstructor(). Note that
+ // "nil" is a constructor too, so it needs to be applied with
+ // APPLY_CONSTRUCTOR, even though it has no arguments.
+ Expr e = em.mkExpr(Kind.APPLY_CONSTRUCTOR,
+ consList.getConstructor("cons"),
+ em.mkConst(new Rational(0)),
+ em.mkExpr(Kind.APPLY_CONSTRUCTOR,
+ consList.getConstructor("nil")));
+
+ System.out.println("e is " + e);
+ System.out.println("type of cons is " +
+ consList.getConstructor("cons").getType());
+ System.out.println("type of nil is " +
+ consList.getConstructor("nil").getType());
+
+ // e2 = head(cons 0 nil), and of course this can be evaluated
+ //
+ // Here we first get the DatatypeConstructor for cons (with
+ // consList.get("cons") in order to get the "head" selector
+ // symbol to apply.
+ Expr e2 = em.mkExpr(Kind.APPLY_SELECTOR,
+ consList.get("cons").getSelector("head"),
+ e);
+
+ System.out.println("e2 is " + e2);
+ System.out.println("simplify(e2) is " + smt.simplify(e2));
+ System.out.println();
+
+ // You can also iterate over a Datatype to get all its constructors,
+ // and over a DatatypeConstructor to get all its "args" (selectors)
+ for(Iterator<DatatypeConstructor> i = consList.iterator(); i.hasNext();) {
+ DatatypeConstructor ctor = i.next();
+ System.out.println("ctor: " + ctor);
+ for(Iterator j = ctor.iterator(); j.hasNext();) {
+ System.out.println(" + arg: " + j.next());
+ }
+ }
+ }
+}
diff --git a/examples/api/java/Makefile.am b/examples/api/java/Makefile.am
index f4b8f1043..7216d758e 100644
--- a/examples/api/java/Makefile.am
+++ b/examples/api/java/Makefile.am
@@ -8,6 +8,7 @@ noinst_DATA += \
Combination.class \
HelloWorld.class \
LinearArith.class \
+ Datatypes.class \
PipedInput.class
endif
@@ -21,6 +22,7 @@ EXTRA_DIST = \
Combination.java \
HelloWorld.java \
LinearArith.java \
+ Datatypes.java \
PipedInput.java
# for installation
diff --git a/library_versions b/library_versions
index 7c519729b..865ea8d77 100644
--- a/library_versions
+++ b/library_versions
@@ -55,3 +55,4 @@
1\.3-prerelease libcvc4:2:0:0 libcvc4parser:2:0:0 libcvc4compat:2:0:0 libcvc4bindings:2:0:0
1\.3 libcvc4:2:0:0 libcvc4parser:2:0:0 libcvc4compat:2:0:0 libcvc4bindings:2:0:0
1\.3\.1-prerelease libcvc4:2:0:0 libcvc4parser:2:0:0 libcvc4compat:2:0:0 libcvc4bindings:2:0:0
+1\.4-prerelease libcvc4:2:0:0 libcvc4parser:2:0:0 libcvc4compat:2:0:0 libcvc4bindings:2:0:0
diff --git a/proofs/lfsc_checker/.gitignore b/proofs/lfsc_checker/.gitignore
new file mode 100644
index 000000000..1f799d15a
--- /dev/null
+++ b/proofs/lfsc_checker/.gitignore
@@ -0,0 +1,16 @@
+/autom4te.cache
+/stamp-h
+/config.h.in
+/config.log
+/config.status
+/config.cache
+/libtool
+/stamp-h1
+.dep
+Makefile.in
+/configure
+/aclocal.m4
+*~
+\#*\#
+/config/
+*.swp
diff --git a/proofs/lfsc_checker/AUTHORS b/proofs/lfsc_checker/AUTHORS
new file mode 100644
index 000000000..0bd0a37b0
--- /dev/null
+++ b/proofs/lfsc_checker/AUTHORS
@@ -0,0 +1,5 @@
+The core authors and designers of the LFSC proof checker are:
+
+ Andy Reynolds
+ Aaron Stump
+
diff --git a/proofs/lfsc_checker/COPYING b/proofs/lfsc_checker/COPYING
new file mode 100644
index 000000000..b220a3147
--- /dev/null
+++ b/proofs/lfsc_checker/COPYING
@@ -0,0 +1,17 @@
+LFSC is copyright (C) 2012, 2013 The University of Iowa.
+All rights reserved.
+
+LFSC is open-source; distribution is under the terms of the modified
+BSD license.
+
+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.
diff --git a/proofs/lfsc_checker/INSTALL b/proofs/lfsc_checker/INSTALL
new file mode 100644
index 000000000..a1e89e18a
--- /dev/null
+++ b/proofs/lfsc_checker/INSTALL
@@ -0,0 +1,370 @@
+Installation Instructions
+*************************
+
+Copyright (C) 1994-1996, 1999-2002, 2004-2011 Free Software Foundation,
+Inc.
+
+ Copying and distribution of this file, with or without modification,
+are permitted in any medium without royalty provided the copyright
+notice and this notice are preserved. This file is offered as-is,
+without warranty of any kind.
+
+Basic Installation
+==================
+
+ Briefly, the shell commands `./configure; make; make install' should
+configure, build, and install this package. The following
+more-detailed instructions are generic; see the `README' file for
+instructions specific to this package. Some packages provide this
+`INSTALL' file but do not implement all of the features documented
+below. The lack of an optional feature in a given package is not
+necessarily a bug. More recommendations for GNU packages can be found
+in *note Makefile Conventions: (standards)Makefile Conventions.
+
+ The `configure' shell script attempts to guess correct values for
+various system-dependent variables used during compilation. It uses
+those values to create a `Makefile' in each directory of the package.
+It may also create one or more `.h' files containing system-dependent
+definitions. Finally, it creates a shell script `config.status' that
+you can run in the future to recreate the current configuration, and a
+file `config.log' containing compiler output (useful mainly for
+debugging `configure').
+
+ It can also use an optional file (typically called `config.cache'
+and enabled with `--cache-file=config.cache' or simply `-C') that saves
+the results of its tests to speed up reconfiguring. Caching is
+disabled by default to prevent problems with accidental use of stale
+cache files.
+
+ If you need to do unusual things to compile the package, please try
+to figure out how `configure' could check whether to do them, and mail
+diffs or instructions to the address given in the `README' so they can
+be considered for the next release. If you are using the cache, and at
+some point `config.cache' contains results you don't want to keep, you
+may remove or edit it.
+
+ The file `configure.ac' (or `configure.in') is used to create
+`configure' by a program called `autoconf'. You need `configure.ac' if
+you want to change it or regenerate `configure' using a newer version
+of `autoconf'.
+
+ The simplest way to compile this package is:
+
+ 1. `cd' to the directory containing the package's source code and type
+ `./configure' to configure the package for your system.
+
+ Running `configure' might take a while. While running, it prints
+ some messages telling which features it is checking for.
+
+ 2. Type `make' to compile the package.
+
+ 3. Optionally, type `make check' to run any self-tests that come with
+ the package, generally using the just-built uninstalled binaries.
+
+ 4. Type `make install' to install the programs and any data files and
+ documentation. When installing into a prefix owned by root, it is
+ recommended that the package be configured and built as a regular
+ user, and only the `make install' phase executed with root
+ privileges.
+
+ 5. Optionally, type `make installcheck' to repeat any self-tests, but
+ this time using the binaries in their final installed location.
+ This target does not install anything. Running this target as a
+ regular user, particularly if the prior `make install' required
+ root privileges, verifies that the installation completed
+ correctly.
+
+ 6. You can remove the program binaries and object files from the
+ source code directory by typing `make clean'. To also remove the
+ files that `configure' created (so you can compile the package for
+ a different kind of computer), type `make distclean'. There is
+ also a `make maintainer-clean' target, but that is intended mainly
+ for the package's developers. If you use it, you may have to get
+ all sorts of other programs in order to regenerate files that came
+ with the distribution.
+
+ 7. Often, you can also type `make uninstall' to remove the installed
+ files again. In practice, not all packages have tested that
+ uninstallation works correctly, even though it is required by the
+ GNU Coding Standards.
+
+ 8. Some packages, particularly those that use Automake, provide `make
+ distcheck', which can by used by developers to test that all other
+ targets like `make install' and `make uninstall' work correctly.
+ This target is generally not run by end users.
+
+Compilers and Options
+=====================
+
+ Some systems require unusual options for compilation or linking that
+the `configure' script does not know about. Run `./configure --help'
+for details on some of the pertinent environment variables.
+
+ You can give `configure' initial values for configuration parameters
+by setting variables in the command line or in the environment. Here
+is an example:
+
+ ./configure CC=c99 CFLAGS=-g LIBS=-lposix
+
+ *Note Defining Variables::, for more details.
+
+Compiling For Multiple Architectures
+====================================
+
+ You can compile the package for more than one kind of computer at the
+same time, by placing the object files for each architecture in their
+own directory. To do this, you can use GNU `make'. `cd' to the
+directory where you want the object files and executables to go and run
+the `configure' script. `configure' automatically checks for the
+source code in the directory that `configure' is in and in `..'. This
+is known as a "VPATH" build.
+
+ With a non-GNU `make', it is safer to compile the package for one
+architecture at a time in the source code directory. After you have
+installed the package for one architecture, use `make distclean' before
+reconfiguring for another architecture.
+
+ On MacOS X 10.5 and later systems, you can create libraries and
+executables that work on multiple system types--known as "fat" or
+"universal" binaries--by specifying multiple `-arch' options to the
+compiler but only a single `-arch' option to the preprocessor. Like
+this:
+
+ ./configure CC="gcc -arch i386 -arch x86_64 -arch ppc -arch ppc64" \
+ CXX="g++ -arch i386 -arch x86_64 -arch ppc -arch ppc64" \
+ CPP="gcc -E" CXXCPP="g++ -E"
+
+ This is not guaranteed to produce working output in all cases, you
+may have to build one architecture at a time and combine the results
+using the `lipo' tool if you have problems.
+
+Installation Names
+==================
+
+ By default, `make install' installs the package's commands under
+`/usr/local/bin', include files under `/usr/local/include', etc. You
+can specify an installation prefix other than `/usr/local' by giving
+`configure' the option `--prefix=PREFIX', where PREFIX must be an
+absolute file name.
+
+ You can specify separate installation prefixes for
+architecture-specific files and architecture-independent files. If you
+pass the option `--exec-prefix=PREFIX' to `configure', the package uses
+PREFIX as the prefix for installing programs and libraries.
+Documentation and other data files still use the regular prefix.
+
+ In addition, if you use an unusual directory layout you can give
+options like `--bindir=DIR' to specify different values for particular
+kinds of files. Run `configure --help' for a list of the directories
+you can set and what kinds of files go in them. In general, the
+default for these options is expressed in terms of `${prefix}', so that
+specifying just `--prefix' will affect all of the other directory
+specifications that were not explicitly provided.
+
+ The most portable way to affect installation locations is to pass the
+correct locations to `configure'; however, many packages provide one or
+both of the following shortcuts of passing variable assignments to the
+`make install' command line to change installation locations without
+having to reconfigure or recompile.
+
+ The first method involves providing an override variable for each
+affected directory. For example, `make install
+prefix=/alternate/directory' will choose an alternate location for all
+directory configuration variables that were expressed in terms of
+`${prefix}'. Any directories that were specified during `configure',
+but not in terms of `${prefix}', must each be overridden at install
+time for the entire installation to be relocated. The approach of
+makefile variable overrides for each directory variable is required by
+the GNU Coding Standards, and ideally causes no recompilation.
+However, some platforms have known limitations with the semantics of
+shared libraries that end up requiring recompilation when using this
+method, particularly noticeable in packages that use GNU Libtool.
+
+ The second method involves providing the `DESTDIR' variable. For
+example, `make install DESTDIR=/alternate/directory' will prepend
+`/alternate/directory' before all installation names. The approach of
+`DESTDIR' overrides is not required by the GNU Coding Standards, and
+does not work on platforms that have drive letters. On the other hand,
+it does better at avoiding recompilation issues, and works well even
+when some directory options were not specified in terms of `${prefix}'
+at `configure' time.
+
+Optional Features
+=================
+
+ If the package supports it, you can cause programs to be installed
+with an extra prefix or suffix on their names by giving `configure' the
+option `--program-prefix=PREFIX' or `--program-suffix=SUFFIX'.
+
+ Some packages pay attention to `--enable-FEATURE' options to
+`configure', where FEATURE indicates an optional part of the package.
+They may also pay attention to `--with-PACKAGE' options, where PACKAGE
+is something like `gnu-as' or `x' (for the X Window System). The
+`README' should mention any `--enable-' and `--with-' options that the
+package recognizes.
+
+ For packages that use the X Window System, `configure' can usually
+find the X include and library files automatically, but if it doesn't,
+you can use the `configure' options `--x-includes=DIR' and
+`--x-libraries=DIR' to specify their locations.
+
+ Some packages offer the ability to configure how verbose the
+execution of `make' will be. For these packages, running `./configure
+--enable-silent-rules' sets the default to minimal output, which can be
+overridden with `make V=1'; while running `./configure
+--disable-silent-rules' sets the default to verbose, which can be
+overridden with `make V=0'.
+
+Particular systems
+==================
+
+ On HP-UX, the default C compiler is not ANSI C compatible. If GNU
+CC is not installed, it is recommended to use the following options in
+order to use an ANSI C compiler:
+
+ ./configure CC="cc -Ae -D_XOPEN_SOURCE=500"
+
+and if that doesn't work, install pre-built binaries of GCC for HP-UX.
+
+ HP-UX `make' updates targets which have the same time stamps as
+their prerequisites, which makes it generally unusable when shipped
+generated files such as `configure' are involved. Use GNU `make'
+instead.
+
+ On OSF/1 a.k.a. Tru64, some versions of the default C compiler cannot
+parse its `<wchar.h>' header file. The option `-nodtk' can be used as
+a workaround. If GNU CC is not installed, it is therefore recommended
+to try
+
+ ./configure CC="cc"
+
+and if that doesn't work, try
+
+ ./configure CC="cc -nodtk"
+
+ On Solaris, don't put `/usr/ucb' early in your `PATH'. This
+directory contains several dysfunctional programs; working variants of
+these programs are available in `/usr/bin'. So, if you need `/usr/ucb'
+in your `PATH', put it _after_ `/usr/bin'.
+
+ On Haiku, software installed for all users goes in `/boot/common',
+not `/usr/local'. It is recommended to use the following options:
+
+ ./configure --prefix=/boot/common
+
+Specifying the System Type
+==========================
+
+ There may be some features `configure' cannot figure out
+automatically, but needs to determine by the type of machine the package
+will run on. Usually, assuming the package is built to be run on the
+_same_ architectures, `configure' can figure that out, but if it prints
+a message saying it cannot guess the machine type, give it the
+`--build=TYPE' option. TYPE can either be a short name for the system
+type, such as `sun4', or a canonical name which has the form:
+
+ CPU-COMPANY-SYSTEM
+
+where SYSTEM can have one of these forms:
+
+ OS
+ KERNEL-OS
+
+ See the file `config.sub' for the possible values of each field. If
+`config.sub' isn't included in this package, then this package doesn't
+need to know the machine type.
+
+ If you are _building_ compiler tools for cross-compiling, you should
+use the option `--target=TYPE' to select the type of system they will
+produce code for.
+
+ If you want to _use_ a cross compiler, that generates code for a
+platform different from the build platform, you should specify the
+"host" platform (i.e., that on which the generated programs will
+eventually be run) with `--host=TYPE'.
+
+Sharing Defaults
+================
+
+ If you want to set default values for `configure' scripts to share,
+you can create a site shell script called `config.site' that gives
+default values for variables like `CC', `cache_file', and `prefix'.
+`configure' looks for `PREFIX/share/config.site' if it exists, then
+`PREFIX/etc/config.site' if it exists. Or, you can set the
+`CONFIG_SITE' environment variable to the location of the site script.
+A warning: not all `configure' scripts look for a site script.
+
+Defining Variables
+==================
+
+ Variables not defined in a site shell script can be set in the
+environment passed to `configure'. However, some packages may run
+configure again during the build, and the customized values of these
+variables may be lost. In order to avoid this problem, you should set
+them in the `configure' command line, using `VAR=value'. For example:
+
+ ./configure CC=/usr/local2/bin/gcc
+
+causes the specified `gcc' to be used as the C compiler (unless it is
+overridden in the site shell script).
+
+Unfortunately, this technique does not work for `CONFIG_SHELL' due to
+an Autoconf bug. Until the bug is fixed you can use this workaround:
+
+ CONFIG_SHELL=/bin/bash /bin/bash ./configure CONFIG_SHELL=/bin/bash
+
+`configure' Invocation
+======================
+
+ `configure' recognizes the following options to control how it
+operates.
+
+`--help'
+`-h'
+ Print a summary of all of the options to `configure', and exit.
+
+`--help=short'
+`--help=recursive'
+ Print a summary of the options unique to this package's
+ `configure', and exit. The `short' variant lists options used
+ only in the top level, while the `recursive' variant lists options
+ also present in any nested packages.
+
+`--version'
+`-V'
+ Print the version of Autoconf used to generate the `configure'
+ script, and exit.
+
+`--cache-file=FILE'
+ Enable the cache: use and save the results of the tests in FILE,
+ traditionally `config.cache'. FILE defaults to `/dev/null' to
+ disable caching.
+
+`--config-cache'
+`-C'
+ Alias for `--cache-file=config.cache'.
+
+`--quiet'
+`--silent'
+`-q'
+ Do not print messages saying which checks are being made. To
+ suppress all normal output, redirect it to `/dev/null' (any error
+ messages will still be shown).
+
+`--srcdir=DIR'
+ Look for the package's source code in directory DIR. Usually
+ `configure' can determine that directory automatically.
+
+`--prefix=DIR'
+ Use DIR as the installation prefix. *note Installation Names::
+ for more details, including other options available for fine-tuning
+ the installation locations.
+
+`--no-create'
+`-n'
+ Run the configure checks, but stop before creating any output
+ files.
+
+`configure' also accepts some other, not widely useful, options. Run
+`configure --help' for more details.
+
diff --git a/proofs/lfsc_checker/Makefile.am b/proofs/lfsc_checker/Makefile.am
new file mode 100644
index 000000000..ff483f5fb
--- /dev/null
+++ b/proofs/lfsc_checker/Makefile.am
@@ -0,0 +1,30 @@
+AM_CXXFLAGS = -Wall -Wno-deprecated
+
+bin_PROGRAMS = lfsc-checker
+
+lfsc_checker_SOURCES = \
+ main.cpp
+lfsc_checker_LDADD = \
+ @builddir@/liblfsc_checker.la
+
+noinst_LTLIBRARIES = liblfsc_checker.la
+
+liblfsc_checker_la_SOURCES = \
+ check.cpp \
+ check.h \
+ chunking_memory_management.h \
+ code.cpp \
+ code.h \
+ expr.cpp \
+ expr.h \
+ libwriter.cpp \
+ libwriter.h \
+ position.h \
+ print_smt2.cpp \
+ print_smt2.h \
+ scccode.cpp \
+ scccode.h \
+ sccwriter.cpp \
+ sccwriter.h \
+ trie.cpp \
+ trie.h
diff --git a/proofs/lfsc_checker/NEWS b/proofs/lfsc_checker/NEWS
new file mode 100644
index 000000000..1a357ab4c
--- /dev/null
+++ b/proofs/lfsc_checker/NEWS
@@ -0,0 +1,9 @@
+This file contains a summary of important user-visible changes to the
+LFSC proof checker.
+
+Changes since pre-1.0 (unversioned) releases
+============================================
+
+* Incorporated the LFSC checker into the CVC4 project.
+
+-- Morgan Deters <mdeters@cs.nyu.edu> Thu, 12 Dec 2013 18:16:08 -0500
diff --git a/proofs/lfsc_checker/README b/proofs/lfsc_checker/README
new file mode 100644
index 000000000..5073569bc
--- /dev/null
+++ b/proofs/lfsc_checker/README
@@ -0,0 +1,83 @@
+lfsc: a high-performance LFSC proof checker.
+
+Andy Reynolds and Aaron Stump
+
+----------------------------------------------------------------------
+Command line parameters for LFSC:
+
+lfsc [sig_1 .... sig_n] [opts_1...opts_n]
+
+[sig_1 .... sig_n] are signature files, and options [opts_1...opts_n]
+are any of the following:
+
+--compile-scc : Write out all side conditions contained in signatures
+ specified on the command line to files scccode.h, scccode.cpp (see
+ below for example)
+
+--run-scc : Run proof checking with compiled side condition code (see
+ below).
+
+--compile-scc-debug : Write side condition code to scccode.h,
+ scccode.cpp that contains print statements (for debugging running of
+ side condition code).
+
+
+
+
+Typical usage:
+
+./src/opt/lfsc [sig_1 .... sig_n] [proof] [opts_1...opts_n]
+
+A proof is typically specified at the end of the list of input files
+in file [proof]. This will tell LFSC to type check the proof term in
+the file [proof]. The extension (*.plf) is commonly used for both
+user signature files and proof files.
+
+
+
+
+Side condition code compilation:
+
+LFSC may be used with side condition code compilation. This will take
+all side conditions ("program" constructs) in the user signature and
+produce equivalent C++ code in the output files scccode.h,
+scccode.cpp.
+
+An example for QF_IDL running with side condition code compilation:
+
+(1) In the src/ directory, run LFSC with the command line parameters:
+
+./opt/lfsc ../sat-tests/sat.plf ../sat-tests/smt.plf \
+ ../sat-tests/cnf_conv.plf ../sat-tests/th_base.plf \
+ ../sat-tests/th_idl.plf --compile-scc
+
+This will produce scccode.h and scccode.cpp in the working directory
+where lfsc was run (here, src/).
+
+(2) Recompile the code base for lfsc. This will produce a copy of the
+LFSC executable that is capable of calling side conditions directly as
+compiled C++.
+
+(3) To check a proof.plf* with side condition code compilation, run
+LFSC with the command line parameters:
+
+./opt/lfsc ../sat-tests/sat.plf ../sat-tests/smt.plf \
+ ../sat-tests/cnf_conv.plf ../sat-tests/th_base.plf \
+ ../sat-tests/th_idl.plf --run-scc proof.plf
+
+
+
+*Note that this proof must be compatible with the proof checking
+ signature. The proof generator is responsible for producing a proof
+ in the proper format that can be checked by the proof signature
+ specified when running LFSC.
+
+For example, in the case of CLSAT in the QF_IDL logic, older proofs
+(proofs produced before Feb 2009) may be incompatible with the newest
+version of the resolution checking signature (sat.plf). The newest
+version of CLSAT -- which can be checked out from the Iowa repository
+with
+
+svn co https://svn.divms.uiowa.edu/repos/clc/clsat/trunk clsat
+
+should produce proofs compatible with the current version of sat.plf.
diff --git a/proofs/lfsc_checker/check.cpp b/proofs/lfsc_checker/check.cpp
new file mode 100644
index 000000000..8ef114115
--- /dev/null
+++ b/proofs/lfsc_checker/check.cpp
@@ -0,0 +1,1383 @@
+#include "position.h"
+#include "check.h"
+#include "code.h"
+#include "expr.h"
+#include "trie.h"
+#include "sccwriter.h"
+#include "libwriter.h"
+#ifndef _MSC_VER
+#include <libgen.h>
+#endif
+#include <stack>
+#include <string.h>
+#include <time.h>
+#include "scccode.h"
+#include "print_smt2.h"
+
+using namespace std;
+#ifndef _MSC_VER
+using namespace __gnu_cxx;
+#endif
+
+int linenum = 1;
+int colnum = 1;
+const char *filename = 0;
+FILE *curfile = 0;
+
+//#define USE_HASH_MAPS
+
+symmap2 progs;
+std::vector< Expr* > ascHoles;
+
+#ifdef USE_HASH_MAPS
+hash_map<string, Expr *> symbols;
+hash_map<string, Expr *> symbol_types;
+#else
+Trie<pair<Expr *, Expr *> > *symbols = new Trie<pair<Expr *, Expr *> >;
+#endif
+
+hash_map<string, bool > imports;
+std::map<SymExpr*, int > mark_map;
+std::vector< std::pair< std::string, std::pair<Expr *, Expr *> > > local_sym_names;
+
+Expr *not_defeq1 = 0;
+Expr *not_defeq2 = 0;
+
+bool tail_calls = true;
+bool big_check = true;
+
+void report_error(const string &msg) {
+ if (filename) {
+ Position p(filename,linenum,colnum);
+ p.print(cout);
+ }
+ cout << "\n";
+ cout << msg;
+ cout << "\n";
+ if (not_defeq1 && not_defeq2) {
+ cout << "The following terms are not definitionally equal:\n1. ";
+ not_defeq1->print(cout);
+ cout << "\n2. ";
+ not_defeq2->print(cout);
+ }
+ cout.flush();
+ _exit(1);
+}
+
+Expr *call_run_code(Expr *code) {
+ if (dbg_prog) {
+ cout << "[Running ";
+ code->print(cout);
+ cout << "\n";
+ }
+ Expr *computed_result = run_code(code);
+ if (dbg_prog) {
+ cout << "] returning ";
+ if (computed_result)
+ computed_result->print(cout);
+ else
+ cout << "fail";
+ cout << "\n";
+ }
+ return computed_result;
+}
+
+char our_getc_c = 0;
+
+int IDBUF_LEN = 2048;
+char idbuf[2048];
+
+Expr *statType = new CExpr(TYPE, 0);
+Expr *statKind = new CExpr(KIND, 0);
+Expr *statMpz = new CExpr(MPZ,0);
+Expr *statMpq = new CExpr(MPQ,0);
+
+int open_parens = 0;
+
+// only call in check()
+void eat_rparen() {
+ eat_char(')');
+ open_parens--;
+}
+
+void eat_excess(int prev) {
+ while(open_parens > prev)
+ eat_rparen();
+}
+
+/* There are four cases for check():
+
+1. expected=0, create is false: check() sets computed to be the classifier of
+ the checked term.
+
+2. expected=0, create is true: check() returns
+ the checked expression and sets computed to be its classifier.
+
+3. expected is non-null, create is false: check returns NULL.
+
+4. expected is non-null, create is true: check returns the term that
+ was checked.
+
+We consume the reference for expected, to enable tail calls in the
+application case.
+
+If is_hole is NULL, then the expression parsed may not be a hole.
+Otherwise, it may be, and we will set *is_hole to true if it is
+(but leave *is_hole alone if it is not).
+
+*/
+
+bool allow_run = false;
+int app_rec_level = 0;
+
+Expr *check(bool create, Expr *expected, Expr **computed = NULL,
+ bool *is_hole = 0, bool return_pos = false, bool inAsc = false ) {
+ start_check:
+ //std::cout << "check code ";
+ //if( expected )
+ // expected->print( std::cout );
+ //std::cout << std::endl;
+ char d = non_ws();
+ switch(d) {
+ case '(': {
+
+ open_parens++;
+
+ char c = non_ws();
+ switch (c) {
+ case EOF:
+ report_error("Unexpected end of file.");
+ break;
+ case '!': { // the pi case
+ string id(prefix_id());
+#ifdef DEBUG_SYM_NAMES
+ Expr *sym = new SymSExpr(id,SYMS_EXPR);
+#else
+ Expr *sym = new SymExpr(id);
+ //std::cout << "name " << id << " " << sym << std::endl;
+#endif
+ allow_run = true;
+ int prevo = open_parens;
+ Expr *domain = check(true, statType);
+ eat_excess(prevo);
+ allow_run = false;
+#ifdef USE_HASH_MAPS
+ Expr *prev = symbols[id];
+ Expr *prevtp = symbol_types[id];
+ symbols[id] = sym;
+ symbol_types[id] = domain;
+#else
+ pair<Expr *,Expr *>prev =
+ symbols->insert(id.c_str(),pair<Expr *,Expr *>(sym,domain));
+#endif
+ if (expected)
+ expected->inc();
+ Expr *range = check(create, expected, computed, NULL, return_pos);
+ eat_excess(prevo);
+ eat_rparen();
+
+#ifdef USE_HASH_MAPS
+ symbols[id] = prev;
+ symbol_types[id] = prevtp;
+#else
+ symbols->insert(id.c_str(),prev);
+#endif
+ if (expected) {
+ int o = expected->followDefs()->getop();
+ expected->dec();
+ if (o != TYPE && o != KIND)
+ report_error(string("The expected classifier for a pi abstraction")
+ +string("is neither \"type\" nor \"kind\".\n")
+ +string("1. the expected classifier: ")
+ +expected->toString());
+ if (create){
+ CExpr* ret = new CExpr(PI, sym, domain, range);
+ ret->calc_free_in();
+ return ret;
+ }
+ return 0;
+ }
+ else {
+ if (create){
+ CExpr* ret = new CExpr(PI, sym, domain, range);
+ ret->calc_free_in();
+ return ret;
+ }
+ int o = (*computed)->followDefs()->getop();
+ if (o != TYPE && o != KIND)
+ report_error(string("The classifier for the range of a pi")
+ +string("abstraction is neither \"type\" nor ")
+ +string("\"kind\".\n1. the computed classifier: ")
+ +range->toString());
+ return 0;
+ }
+ }
+ case '%': { // the case for big lambda
+ if (expected || create || !return_pos || !big_check)
+ report_error(string("Big lambda abstractions can only be used")
+ +string("in the return position of a \"bigcheck\"\n")
+ +string("command."));
+ string id(prefix_id());
+#ifdef DEBUG_SYM_NAMES
+ SymExpr *sym = new SymSExpr(id, SYMS_EXPR);
+#else
+ SymExpr *sym = new SymExpr(id);
+ //std::cout << "name " << id << " " << sym << std::endl;
+#endif
+
+ int prevo = open_parens;
+ Expr *expected_domain = check(true, statType);
+ eat_excess(prevo);
+
+#ifdef USE_HASH_MAPS
+ Expr *prev = symbols[id];
+ Expr *prevtp = symbol_types[id];
+ symbols[id] = sym;
+ symbol_types[id] = expected_domain;
+#else
+ pair<Expr *, Expr *> prevpr =
+ symbols->insert(id.c_str(), pair<Expr *, Expr *>(sym,expected_domain));
+ Expr *prev = prevpr.first;
+ Expr *prevtp = prevpr.second;
+#endif
+ expected_domain->inc(); // because we have stored it in the symbol table
+
+ //will clean up local sym name eventually
+ local_sym_names.push_back( std::pair< std::string, std::pair<Expr *, Expr *> >( id, prevpr ) );
+ if (prev)
+ prev->dec();
+ if (prevtp)
+ prevtp->dec();
+ create = false;
+ expected = NULL;
+ // computed unchanged
+ is_hole = NULL;
+ // return_pos unchanged
+
+ // note we will not store the proper return type in computed.
+
+ goto start_check;
+ }
+
+ case '\\': { // the lambda case
+ if (!expected)
+ report_error(string("We are computing a type for a lambda ")
+ +string("abstraction, but we can only check\n")
+ +string("such against a type. Try inserting an ")
+ +string("ascription (using ':').\n"));
+ Expr *orig_expected = expected;
+ expected = expected->followDefs();
+ if (expected->getop() != PI)
+ report_error(string("We are type-checking a lambda abstraction, but\n")
+ +string("the expected type is not a pi abstraction.\n")
+ +string("1. The expected type: ") + expected->toString());
+ string id(prefix_id());
+#ifdef DEBUG_SYM_NAMES
+ SymExpr *sym = new SymSExpr(id, SYMS_EXPR);
+#else
+ SymExpr *sym = new SymExpr(id);
+ //std::cout << "name " << id << " " << sym << std::endl;
+#endif
+
+ CExpr *pitp = (CExpr *)expected;
+ Expr *expected_domain = pitp->kids[1];
+ Expr *expected_range = pitp->kids[2];
+ SymExpr *pivar = (SymExpr *)pitp->kids[0];
+ if (expected_range->followDefs()->getop() == TYPE)
+ report_error(string("The expected classifier for a lambda abstraction")
+ +string(" a kind, not a type.\n")
+ +string("1. The expected classifier: ")
+ +expected->toString());
+
+ /* we need to map the pivar to the new sym, because in our
+ higher-order matching we may have (_ x) to unify with t.
+ The x must be something from an expected type, since only these
+ can have holes. We want to map expected vars x to computed vars y,
+ so that we can set the hole to be \ y t, where t contains ys but
+ not xs. */
+
+#ifdef USE_HASH_MAPS
+ Expr *prev = symbols[id];
+ Expr *prevtp = symbol_types[id];
+ symbols[id] = sym;
+ symbol_types[id] = expected_domain;
+#else
+ pair<Expr *, Expr *> prevpr =
+ symbols->insert(id.c_str(), pair<Expr *, Expr *>(sym,expected_domain));
+ Expr *prev = prevpr.first;
+ Expr *prevtp = prevpr.second;
+#endif
+ Expr *prev_pivar_val = pivar->val;
+ sym->inc();
+ pivar->val = sym;
+
+ expected_domain->inc(); // because we have stored it in the symbol table
+ expected_range->inc(); // because we will pass it to a recursive call
+
+ if (tail_calls && big_check && return_pos && !create) {
+ //will clean up local sym name eventually
+ local_sym_names.push_back( std::pair< std::string, std::pair<Expr *, Expr *> >( id, prevpr ) );
+ if (prev_pivar_val)
+ prev_pivar_val->dec();
+ if (prev)
+ prev->dec();
+ if (prevtp)
+ prevtp->dec();
+ orig_expected->dec();
+ create = false;
+ expected = expected_range;
+ computed = NULL;
+ is_hole = NULL;
+ // return_pos unchanged
+ goto start_check;
+ }
+ else {
+
+ int prev = open_parens;
+ Expr *range = check(create, expected_range, NULL, NULL, return_pos);
+ eat_excess(prev);
+ eat_rparen();
+
+#ifdef USE_HASH_MAPS
+ symbols[id] = prev;
+ symbol_types[id] = prevtp;
+#else
+ symbols->insert(id.c_str(), prevpr);
+#endif
+ expected_domain->dec(); // because removed from the symbol table now
+
+ pivar->val = prev_pivar_val;
+
+ orig_expected->dec();
+
+ sym->dec(); // the pivar->val reference
+ if (create)
+ return new CExpr(LAM, sym, range);
+ sym->dec(); // the symbol table reference, otherwise in the new LAM
+ return 0;
+ }
+ }
+ case '^': { // the run case
+ if (!allow_run || !create || !expected)
+ report_error(string("A run expression (operator \"^\") appears in")
+ +string(" a disallowed position."));
+
+ Expr *code = read_code();
+ //string errstr = (string("The first argument in a run expression must be")
+ // +string(" a call to a program.\n1. the argument: ")
+ // +code->toString());
+
+ /* determine expected type of the result term, and make sure
+ the code term is an allowed one. */
+#if 0
+ Expr *progret;
+ if (code->isArithTerm())
+ progret = statMpz;
+ else {
+ if (code->getop() != APP)
+ report_error(errstr);
+
+ CExpr *call = (CExpr *)code;
+
+ // prog is not known to be a SymExpr yet
+ CExpr *prog = (CExpr *)call->get_head();
+
+ if (prog->getop() != PROG)
+ report_error(errstr);
+
+ progret = prog->kids[0]->get_body();
+ }
+#else
+ Expr *progret = NULL;
+ if (code->isArithTerm())
+ progret = statMpz;
+ else {
+ if (code->getop() == APP)
+ {
+ CExpr *call = (CExpr *)code;
+
+ // prog is not known to be a SymExpr yet
+ CExpr *prog = (CExpr *)call->get_head();
+
+ if (prog->getop() == PROG)
+ progret = prog->kids[0]->get_body();
+ }
+ }
+#endif
+ /* determine expected type of the result term, and make sure
+ the code term is an allowed one. */
+ //Expr* progret = check_code( code );
+
+ /* the next term cannot be a hole where run expressions are introduced.
+ When they are checked in applications, it can be. */
+ int prev = open_parens;
+ if( progret )
+ progret->inc();
+ Expr *trm = check(true, progret);
+ eat_excess(prev);
+ eat_rparen();
+
+ if (expected->getop() != TYPE)
+ report_error(string("The expected type for a run expression is not ")
+ +string("\"type\".\n")
+ +string("1. The expected type: ")+expected->toString());
+ expected->dec();
+ return new CExpr(RUN, code, trm);
+ }
+
+ case ':': { // the ascription case
+ statType->inc();
+ int prev = open_parens;
+ Expr *tp = check(true, statType, NULL, NULL, false, true );
+ eat_excess(prev);
+
+ if (!expected)
+ tp->inc();
+
+ Expr *trm = check(create, tp, NULL, NULL, return_pos);
+ eat_excess(prev);
+ eat_rparen();
+ if (expected) {
+ if (!expected->defeq(tp))
+ report_error(string("The expected type does not match the ")
+ +string("ascribed type in an ascription.\n")
+ +string("1. The expected type: ")+expected->toString()
+ +string("\n2. The ascribed type: ")+tp->toString());
+
+ // no need to dec tp, since it was consumed by the call to check
+ expected->dec();
+ if (create)
+ return trm;
+ trm->dec();
+ return 0;
+ }
+ else {
+ *computed = tp;
+ if (create)
+ return trm;
+ return 0;
+ }
+ }
+ case '@': { // the local definition case
+ string id(prefix_id());
+#ifdef DEBUG_SYM_NAMES
+ SymExpr *sym = new SymSExpr(id, SYMS_EXPR);
+#else
+ SymExpr *sym = new SymExpr(id);
+#endif
+ int prev_open = open_parens;
+ Expr *tp_of_trm;
+ Expr *trm = check(true, NULL, &tp_of_trm);
+ eat_excess(prev_open);
+
+ sym->val = trm;
+
+#ifdef USE_HASH_MAPS
+ Expr *prev = symbols[id];
+ Expr *prevtp = symbol_types[id];
+ symbols[id] = sym;
+ symbol_types[id] = tp_of_trm;
+#else
+ pair<Expr *, Expr *> prevpr =
+ symbols->insert(id.c_str(), pair<Expr *, Expr *>(sym,tp_of_trm));
+ Expr *prev = prevpr.first;
+ Expr *prevtp = prevpr.second;
+#endif
+
+ if (tail_calls && big_check && return_pos && !create) {
+ if (prev)
+ prev->dec();
+ if (prevtp)
+ prevtp->dec();
+ // all parameters to check() unchanged here
+ goto start_check;
+ }
+ else {
+ int prev_open = open_parens;
+ Expr *body = check(create, expected, computed, is_hole, return_pos);
+ eat_excess(prev_open);
+ eat_rparen();
+
+#ifdef USE_HASH_MAPS
+ symbols[id] = prev;
+ symbol_types[id] = prevtp;
+#else
+ symbols->insert(id.c_str(), prevpr);
+#endif
+ tp_of_trm->dec(); // because removed from the symbol table now
+
+ sym->dec();
+ return body;
+ }
+ }
+ case '~': {
+ int prev = open_parens;
+ Expr *e = check(create, expected, computed, is_hole, return_pos);
+ eat_excess(prev);
+ eat_rparen();
+
+ // this has been only very lightly tested -- ads.
+
+ if (expected) {
+ if (expected != statMpz && expected != statMpq)
+ report_error("Negative sign where an numeric expression is expected.");
+ }
+ else {
+ if ((*computed) != statMpz && (*computed) != statMpq)
+ report_error("Negative sign where an numeric expression is expected.");
+ }
+
+ if (create) {
+ if (e->getclass() == INT_EXPR)
+ {
+ IntExpr *ee = (IntExpr *)e;
+ mpz_neg(ee->n, ee->n);
+ return ee;
+ }
+ else if( e->getclass() == RAT_EXPR )
+ {
+ RatExpr *ee = (RatExpr *)e;
+ mpq_neg(ee->n, ee->n);
+ return ee;
+ }
+ else
+ {
+ report_error("Negative sign with expr that is not an int. literal.");
+ }
+ }
+ else
+ return 0;
+ }
+ default: { // the application case
+ our_ungetc(c);
+ Expr *head_computed;
+ int prev = open_parens;
+ Expr *headtrm = check(create,0,&head_computed);
+ eat_excess(prev);
+
+ CExpr *headtp = (CExpr *)head_computed->followDefs();
+ headtp->inc();
+ head_computed->dec();
+ if ( headtp->cloned()) {
+ // we must clone
+ Expr *orig_headtp = headtp;
+ headtp = (CExpr *)headtp->clone();
+ orig_headtp->dec();
+ }
+ else
+ headtp->setcloned();
+#ifdef DEBUG_APPS
+ char tmp[100];
+ sprintf(tmp,"(%d) ", app_rec_level++);
+ cout << tmp << "{ headtp = ";
+ headtp->debug();
+#endif
+ char c;
+ vector<HoleExpr *> holes;
+ vector<bool> free_holes;
+ while ((c = non_ws()) != ')') {
+ our_ungetc(c);
+ if (headtp->getop() != PI)
+ report_error(string("The type of an applied term is not ")
+ + string("a pi-type.\n")
+ + string("\n1. the type of the term: ")
+ + headtp->toString()
+ + (headtrm ? (string("\n2. the term: ")
+ + headtrm->toString())
+ : string("")));
+ SymExpr *headtp_var = (SymExpr *)headtp->kids[0];
+ Expr *headtp_domain = headtp->kids[1];
+ Expr *headtp_range = headtp->kids[2];
+ if (headtp_domain->getop() == RUN) {
+ CExpr *run = (CExpr *)headtp_domain;
+ Expr *code = run->kids[0];
+ Expr *expected_result = run->kids[1];
+ Expr *computed_result = call_run_code(code);
+ if (!computed_result)
+ report_error(string("A side condition failed.\n")
+ +string("1. the side condition: ")
+ +code->toString());
+ if (!expected_result->defeq(computed_result))
+ report_error(string("The expected result of a side condition ")
+ +string("does not match the computed result.\n")
+ +string("1. expected result: ")
+ +expected_result->toString()
+ +string("\n2. computed result: ")
+ +computed_result->toString());
+ computed_result->dec();
+ }
+ else {
+ // check an argument
+ bool var_in_range = headtp->get_free_in();//headtp_range->free_in(headtp_var);
+ bool arg_is_hole = false;
+ bool consumed_arg = false;
+
+ bool create_arg = (create || var_in_range);
+
+ headtp_domain->inc();
+
+ if (tail_calls && !create_arg && headtp_range->getop() != PI) {
+ // we can make a tail call to check() here.
+
+ if (expected) {
+ if (!expected->defeq(headtp_range))
+ report_error(string("The type expected for an application ")
+ + string("does not match the computed type.\n")
+ + string("1. The expected type: ")
+ + expected->toString()
+ + string("\n2. The computed type: ")
+ + headtp_range->toString()
+ + (headtrm ? (string("\n3. the application: ")
+ + headtrm->toString())
+ : string("")));
+ expected->dec();
+ }
+ else {
+ headtp_range->inc();
+ *computed = headtp_range;
+ }
+
+ headtp->dec();
+
+ // same as below
+ for (int i = 0, iend = holes.size(); i < iend; i++) {
+ if (!holes[i]->val)
+ /* if the hole is free in the domain, we will be filling
+ it in when we make our tail call, since the domain
+ is the expected type for the argument */
+ if (!headtp_domain->free_in(holes[i]))
+ report_error(string("A hole was left unfilled after ")
+ +string("checking an application.\n"));
+ holes[i]->dec();
+ }
+
+ create = false;
+ expected = headtp_domain;
+ computed = NULL;
+ is_hole = NULL; // the argument cannot be a hole
+ // return_pos is unchanged
+
+#ifdef DEBUG_APPS
+ cout << "Making tail call.\n";
+#endif
+
+ goto start_check;
+ }
+
+ Expr *arg = check(create_arg, headtp_domain, NULL, &arg_is_hole);
+ eat_excess(prev);
+ if (create) {
+#ifndef USE_FLAT_APP
+ headtrm = new CExpr(APP, headtrm, arg);
+#else
+ headtrm = Expr::make_app( headtrm, arg );
+#endif
+ consumed_arg = true;
+ }
+ if (var_in_range) {
+ Expr *tmp = arg->followDefs();
+ tmp->inc();
+ headtp_var->val = tmp;
+ }
+ if (arg_is_hole) {
+ if (consumed_arg)
+ arg->inc();
+ else
+ consumed_arg = true; // not used currently
+#ifdef DEBUG_HOLES
+ cout << "An argument is a hole: ";
+ arg->debug();
+#endif
+ holes.push_back((HoleExpr *)arg);
+ }
+ }
+ headtp_range->inc();
+ headtp->dec();
+ headtp = (CExpr *)headtp_range;
+ }
+ open_parens--;
+
+ // check for remaining RUN in the head's type after all the arguments
+
+ if (headtp->getop() == PI && headtp->kids[1]->getop() == RUN) {
+ CExpr *run = (CExpr *)headtp->kids[1];
+ Expr *code = run->kids[0]->followDefs();
+ Expr *expected_result = run->kids[1];
+ Expr *computed_result = call_run_code(code);
+ if (!computed_result)
+ report_error(string("A side condition failed.\n")
+ +string("1. the side condition: ")+code->toString());
+ if (!expected_result->defeq(computed_result))
+ report_error(string("The expected result of a side condition ")
+ +string("does not match the computed result.\n")
+ +string("1. expected result: ")
+ +expected_result->toString()
+ +string("\n2. computed result: ")
+ +computed_result->toString());
+ Expr *tmp = headtp->kids[2];
+ tmp->inc();
+ headtp->dec();
+ headtp = (CExpr *)tmp;
+ computed_result->dec();
+ }
+
+#ifdef DEBUG_APPS
+ for (int i = 0, iend = holes.size(); i < iend; i++) {
+ cout << tmp << "hole ";
+ holes[i]->debug();
+ }
+ cout << "}";
+ app_rec_level--;
+#endif
+
+ Expr *ret = 0;
+ if (expected) {
+ if (!expected->defeq(headtp)){
+ report_error(string("The type expected for an application does not")
+ + string(" match the computed type.(2) \n")
+ + string("1. The expected type: ")
+ + expected->toString()
+ + string("\n2. The computed type: ")
+ + headtp->toString()
+ + (headtrm ? (string("\n3. the application: ")
+ + headtrm->toString())
+ : string("")));
+
+ }
+ expected->dec();
+ headtp->dec();
+ if (create)
+ ret = headtrm;
+ }
+ else {
+ *computed = headtp;
+ if (create)
+ ret = headtrm;
+ }
+
+ /* do this check here to give the defeq() call above a
+ chance to fill in some holes */
+ for (int i = 0, iend = holes.size(); i < iend; i++) {
+ if (!holes[i]->val){
+ if( inAsc ){
+#ifdef DEBUG_HOLES
+ std::cout << "Ascription Hole: ";
+ holes[i]->print( std::cout );
+ std::cout << std::endl;
+#endif
+ ascHoles.push_back( holes[i] );
+ }else{
+ report_error(string("A hole was left unfilled after checking")
+ +string(" an application (2).\n"));
+ }
+ }
+ holes[i]->dec();
+ }
+
+ return ret;
+
+ } // end application case
+ }
+ }
+ case EOF:
+ report_error("Unexpected end of file.");
+ break;
+
+ case '_':
+ if (!is_hole)
+ report_error("A hole is being used in a disallowed position.");
+ *is_hole = true;
+ if (expected)
+ expected->dec();
+ return new HoleExpr();
+ case '0':
+ case '1':
+ case '2':
+ case '3':
+ case '4':
+ case '5':
+ case '6':
+ case '7':
+ case '8':
+ case '9': {
+ our_ungetc(d);
+ string v;
+ char c;
+ while (isdigit(c = our_getc()))
+ v.push_back(c);
+ bool parseMpq = false;
+ string v2;
+ if( c=='/' )
+ {
+ parseMpq = true;
+ v.push_back( c );
+ while(isdigit(c = our_getc()))
+ v.push_back(c);
+ }
+ our_ungetc(c);
+
+
+ Expr *i = 0;
+ if (create) {
+ if( parseMpq )
+ {
+ mpq_t num;
+ mpq_init(num);
+ if (mpq_set_str(num,v.c_str(),10) == -1)
+ report_error("Error reading a numeral.");
+ i = new RatExpr(num);
+ }
+ else
+ {
+ mpz_t num;
+ if (mpz_init_set_str(num,v.c_str(),10) == -1)
+ report_error("Error reading a numeral.");
+ i = new IntExpr(num);
+ }
+ }
+
+ if (expected) {
+ if( ( !parseMpq && expected != statMpz ) || ( parseMpq && expected != statMpq ) )
+ report_error(string("We parsed a numeric literal, but were ")
+ +string("expecting a term of a different type.\n")
+ +string("1. the expected type: ")+expected->toString());
+ expected->dec();
+ if (create)
+ return i;
+ return 0;
+ }
+ else {
+ if( parseMpq )
+ {
+ statMpq->inc();
+ *computed = statMpq;
+ if (create)
+ return i;
+ return statMpq;
+ }
+ else
+ {
+ statMpz->inc();
+ *computed = statMpz;
+ if (create)
+ return i;
+ return statMpz;
+ }
+ }
+ }
+ default: {
+ our_ungetc(d);
+ string id(prefix_id());
+#ifdef USE_HASH_MAPS
+ Expr *ret = symbols[id];
+ Expr *rettp = symbol_types[id];
+#else
+ pair<Expr *, Expr *> p = symbols->get(id.c_str());
+ Expr *ret = p.first;
+ Expr *rettp = p.second;
+#endif
+ if (!ret)
+ report_error(string("Undeclared identifier: ")+id);
+ if (expected) {
+ if (!expected->defeq(rettp))
+ report_error(string("The type expected for a symbol does not")
+ + string(" match the symbol's type.\n")
+ + string("1. The symbol: ")
+ + id
+ + string("\n2. The expected type: ")
+ + expected->toString()
+ + string("\n3. The symbol's type: ")
+ + rettp->toString());
+ expected->dec();
+ if (create) {
+ ret->inc();
+ return ret;
+ }
+ return 0;
+ }
+ else {
+ if( computed ){
+ *computed = rettp;
+ (*computed)->inc();
+ }
+ if (create) {
+ ret->inc();
+ return ret;
+ }
+ return 0;
+ }
+ }
+ }
+
+ report_error("Unexpected operator at the start of a term.");
+ return 0;
+}
+
+#ifdef USE_HASH_MAPS
+void discard_old_symbol(const string &id) {
+ Expr *tmp = symbols[id];
+ if (tmp)
+ tmp->dec();
+ tmp = symbol_types[id];
+ if (tmp)
+ tmp->dec();
+}
+#endif
+
+int check_time;
+
+void check_file(const char *_filename, args a, sccwriter* scw, libwriter* lw) {
+ int prev_linenum = linenum;
+ int prev_colnum = colnum;
+ const char *prev_filename = filename;
+ FILE * prev_curfile = curfile;
+
+ // from code.h
+ dbg_prog = a.show_runs;
+ run_scc = a.run_scc;
+ tail_calls = !a.no_tail_calls;
+
+
+ char *f;
+ if (strcmp(_filename,"stdin") == 0) {
+ curfile = stdin;
+ f = strdup(_filename);
+ }
+ else {
+ if (prev_curfile) {
+ f = strdup(prev_filename);
+#ifdef _MSC_VER
+ std::string str( f );
+ for( int n=str.length(); n>=0; n-- ){
+ if( str[n]=='\\' || str[n]=='/' ){
+ str = str.erase( n, str.length()-n );
+ break;
+ }
+ }
+ char *tmp = (char*)str.c_str();
+#else
+ char *tmp = dirname(f);
+#endif
+ delete f;
+ f = new char[strlen(tmp) + 10 + strlen(_filename)];
+ strcpy(f,tmp);
+ strcat(f,"/");
+ strcat(f,_filename);
+ }
+ else
+ f = strdup(_filename);
+ curfile = fopen(f,"r");
+ if (!curfile)
+ report_error(string("Could not open file \"")
+ + string(f)
+ + string("\" for reading.\n"));
+ }
+
+ linenum = 1;
+ colnum = 1;
+ filename = f;
+
+ char c;
+ while ((c = non_ws()) && c!=EOF ) {
+ if( c == '(' )
+ {
+ char d;
+ switch ((d = non_ws())) {
+ case 'd':
+ char b;
+ if ((b = our_getc()) != 'e')
+ report_error(string("Unexpected start of command."));
+
+ switch ((b = our_getc())) {
+ case 'f': {// expecting "define"
+
+ if (our_getc() != 'i' || our_getc() != 'n' || our_getc() != 'e')
+ report_error(string("Unexpected start of command."));
+
+ string id(prefix_id());
+ Expr *ttp;
+ int prevo = open_parens;
+ Expr *t = check(true, 0, &ttp, NULL, true);
+ eat_excess(prevo);
+
+ int o = ttp->followDefs()->getop();
+ if (o == KIND)
+ report_error(string("Kind-level definitions are not supported.\n"));
+ SymSExpr *s = new SymSExpr(id);
+ s->val = t;
+#ifdef USE_HASH_MAPS
+ discard_old_symbol(id);
+ symbols[id] = s;
+ symbol_types[id] = ttp;
+#else
+ pair<Expr *, Expr *> prev =
+ symbols->insert(id.c_str(), pair<Expr *, Expr *>(s,ttp));
+ if (prev.first)
+ prev.first->dec();
+ if (prev.second)
+ prev.second->dec();
+#endif
+ break;
+ }
+ case 'c': {// expecting "declare"
+ if (our_getc() != 'l' || our_getc() != 'a' || our_getc() != 'r'
+ || our_getc() != 'e')
+ report_error(string("Unexpected start of command."));
+
+ string id(prefix_id());
+ Expr *ttp;
+ int prevo = open_parens;
+ Expr *t = check(true, 0, &ttp, NULL, true);
+ eat_excess(prevo);
+
+ ttp = ttp->followDefs();
+ if (ttp->getop() != TYPE && ttp->getop() != KIND)
+ report_error(string("The expression declared for \"")
+ +id+string("\" is neither\na type nor a kind.\n")
+ +string("1. The expression: ")
+ +t->toString()
+ +string("\n2. Its classifier (should be \"type\" ")
+ +string("or \"kind\"): ")+ttp->toString());
+ ttp->dec();
+ SymSExpr *s = new SymSExpr(id);
+#ifdef USE_HASH_MAPS
+ discard_old_symbol(id);
+ symbols[id] = s;
+ symbol_types[id] = t;
+#else
+ pair<Expr *, Expr *> prev =
+ symbols->insert(id.c_str(), pair<Expr *, Expr *>(s,t));
+ if( lw )
+ lw->add_symbol( s, t );
+ if (prev.first)
+ prev.first->dec();
+ if (prev.second)
+ prev.second->dec();
+#endif
+ break;
+ }
+ default:
+ report_error(string("Unexpected start of command."));
+ } // switch((b = our_getc())) following "de"
+ break;
+ case 'c': {
+ if (our_getc() != 'h' || our_getc() != 'e' || our_getc() != 'c' || our_getc() != 'k')
+ report_error(string("Unexpected start of command."));
+ if( run_scc ){
+ init_compiled_scc();
+ }
+ Expr *computed;
+ big_check = true;
+ int prev = open_parens;
+ (void)check(false, 0, &computed, NULL, true);
+
+ //print out ascription holes
+ for( int a=0; a<(int)ascHoles.size(); a++ ){
+#ifdef PRINT_SMT2
+ print_smt2( ascHoles[a], std::cout );
+#else
+ ascHoles[a]->print( std::cout );
+#endif
+ std::cout << std::endl;
+ }
+ if( !ascHoles.empty() )
+ std::cout << std::endl;
+ ascHoles.clear();
+
+ //clean up local symbols
+ for( int a=0; a<(int)local_sym_names.size(); a++ ){
+#ifdef USE_HASH_MAPS
+#else
+ symbols->insert( local_sym_names[a].first.c_str(), local_sym_names[a].second );
+#endif
+ }
+ local_sym_names.clear();
+ mark_map.clear();
+
+ eat_excess(prev);
+
+ computed->dec();
+ //cleanup();
+ //exit(0);
+ break;
+ }
+ case 'o': { // opaque case
+ if (our_getc() != 'p' || our_getc() != 'a' || our_getc() != 'q'
+ || our_getc() != 'u' || our_getc() != 'e')
+ report_error(string("Unexpected start of command."));
+
+ string id(prefix_id());
+ Expr *ttp;
+ int prevo = open_parens;
+ (void)check(false, 0, &ttp, NULL, true);
+ eat_excess(prevo);
+
+ int o = ttp->followDefs()->getop();
+ if (o == KIND)
+ report_error(string("Kind-level definitions are not supported.\n"));
+ SymSExpr *s = new SymSExpr(id);
+#ifdef USE_HASH_MAPS
+ discard_old_symbol(id);
+ symbols[id] = s;
+ symbol_types[id] = ttp;
+#else
+ pair<Expr *, Expr *> prev =
+ symbols->insert(id.c_str(), pair<Expr *, Expr *>(s,ttp));
+ if (prev.first)
+ prev.first->dec();
+ if (prev.second)
+ prev.second->dec();
+#endif
+ break;
+ }
+ case 'r': { // run case
+ if (our_getc() != 'u' || our_getc() != 'n')
+ report_error(string("Unexpected start of command."));
+ Expr *code = read_code();
+ check_code(code);
+ cout << "[Running-sc ";
+ code->print(cout);
+ Expr *tmp = run_code(code);
+ cout << "] = \n";
+ if (tmp) {
+ tmp->print(cout);
+ tmp->dec();
+ }
+ else
+ cout << "fail";
+ cout << "\n";
+ code->dec();
+ break;
+ }
+ case 'p': { // program case
+ if (our_getc() != 'r' || our_getc() != 'o' || our_getc() != 'g'
+ || our_getc() != 'r' || our_getc() != 'a' || our_getc() != 'm')
+ report_error(string("Unexpected start of command."));
+
+ string progstr(prefix_id());
+ SymSExpr *prog = new SymSExpr(progstr);
+ if (progs.find(progstr) != progs.end())
+ report_error(string("Redeclaring program ")+progstr+string("."));
+ progs[progstr] = prog;
+ eat_char('(');
+ char d;
+ vector<Expr *> vars;
+ vector<Expr *> tps;
+ Expr *tmp;
+ while ((d = non_ws()) != ')') {
+ our_ungetc(d);
+ eat_char('(');
+ string varstr = prefix_id();
+#ifdef USE_HASH_MAPS
+ if (symbols.find(varstr) != symbols.end())
+#else
+ if (symbols->get(varstr.c_str()).first != NULL)
+#endif
+ report_error(string("A program variable is already declared")
+ +string(" (as a constant).\n1. The variable: ")
+ +varstr);
+ Expr *var = new SymSExpr(varstr);
+ vars.push_back(var);
+ statType->inc();
+ int prev = open_parens;
+ Expr *tp = check(true, NULL, &tmp, 0, true);
+ if( tp->getclass()==SYMS_EXPR ){
+#ifdef USE_HASH_MAPS
+ Expr *tptp = symbol_types[((SymSExpr*)tp)->s];
+#else
+ pair<Expr *, Expr *> p = symbols->get(((SymSExpr*)tp)->s.c_str());
+ Expr *tptp = p.second;
+#endif
+ if( !tptp->isType( statType ) ){
+ report_error(string("Bad argument for side condition"));
+ }
+ }else{
+ if (!tp->isDatatype()){
+ report_error(string("Type for a program variable is not a ")
+ +string("datatype.\n1. the type: ")+tp->toString());
+ }
+ }
+ eat_excess(prev);
+
+ tps.push_back(tp);
+ eat_char(')');
+
+#ifdef USE_HASH_MAPS
+ symbols[varstr] = var;
+ symbol_types[varstr] = tp;
+#else
+ symbols->insert(varstr.c_str(), pair<Expr *, Expr *>(var,tp));
+#endif
+ }
+
+ if (!vars.size())
+ report_error("A program lacks input variables.");
+
+ statType->inc();
+ int prev = open_parens;
+ Expr *progtp = check(true,statType,&tmp,0, true);
+ eat_excess(prev);
+
+ if (!progtp->isDatatype())
+ report_error(string("Return type for a program is not a")
+ +string(" datatype.\n1. the type: ")+progtp->toString());
+
+ Expr *progcode = read_code();
+
+ for (int i = vars.size() - 1, iend = 0; i >= iend; i--) {
+ vars[i]->inc(); // used below for the program code (progcode)
+ progtp = new CExpr(PI, vars[i], tps[i], progtp);
+ progtp->calc_free_in();
+ }
+
+ // just put the type here for type checking. Make sure progtp is kid 0.
+ prog->val = new CExpr(PROG, progtp);
+
+ check_code(progcode);
+
+ progcode = new CExpr(PROG, progtp, new CExpr(PROGVARS, vars), progcode);
+ //if compiling side condition code, give this code to the side condition code writer
+ if( a.compile_scc ){
+ if( scw ){
+ scw->add_scc( progstr, (CExpr*)progcode );
+ }
+ }
+
+ // remove the variables from the symbol table.
+ for (int i = 0, iend = vars.size(); i < iend; i++) {
+ string &s = ((SymSExpr *)vars[i])->s;
+
+#ifdef USE_HASH_MAPS
+ symbols[s] = NULL;
+ symbol_types[s] = NULL;
+#else
+ symbols->insert(s.c_str(), pair<Expr*,Expr*>(NULL,NULL));
+#endif
+ }
+
+ progtp->inc();
+ prog->val->dec();
+
+ prog->val = progcode;
+
+ break;
+ }
+
+ default:
+ report_error(string("Unexpected start of command."));
+ } // switch((d = non_ws())
+
+ eat_char(')');
+ } // while
+ else
+ {
+ if( c != ')' )
+ {
+ char c2[2];
+ c2[1] = 0;
+ c2[0] = c;
+ string syn = string("Bad syntax (mismatched parentheses?): ");
+ syn.append(string(c2));
+ report_error(syn);
+ }
+ }
+ }
+ free(f);
+ if (curfile != stdin)
+ fclose(curfile);
+ linenum = prev_linenum;
+ colnum = prev_colnum;
+ filename = prev_filename;
+ curfile = prev_curfile;
+
+}
+
+class Deref : public Trie<pair<Expr *, Expr *> >::Cleaner {
+public:
+ ~Deref() {}
+ void clean(pair<Expr *, Expr *> p) {
+ Expr *tmp = p.first;
+ if (tmp) {
+#ifdef DEBUG
+ cout << "Cleaning up ";
+ tmp->debug();
+#endif
+ tmp->dec();
+ }
+ tmp = p.second;
+ if (tmp) {
+#ifdef DEBUG
+ cout << " : ";
+ tmp->debug();
+#endif
+ tmp->dec();
+ }
+#ifdef DEBUG
+ cout << "\n";
+#endif
+ }
+};
+
+template <>
+Trie<pair<Expr *, Expr *> >::Cleaner *
+Trie<pair<Expr *, Expr *> >::cleaner = new Deref;
+
+void cleanup() {
+ symmap::iterator i, iend;
+#ifdef USE_HASH_MAPS
+ Expr *tmp;
+ for (i = symbols.begin(), iend = symbols.end(); i != iend; i++) {
+ tmp = i->second;
+ if (tmp) {
+#ifdef DEBUG
+ cout << "Cleaning up " << i->first << " : ";
+ tmp->debug();
+#endif
+ tmp->dec();
+ }
+ }
+ for (i = symbol_types.begin(), iend = symbol_types.end(); i != iend; i++) {
+ tmp = i->second;
+ if (tmp) {
+#ifdef DEBUG
+ cout << "Cleaning up " << i->first << " : ";
+ tmp->debug();
+#endif
+ tmp->dec();
+ }
+ }
+#else
+ delete symbols;
+#endif
+
+ // clean up programs
+
+ symmap2::iterator j, jend;
+ for (j = progs.begin(), jend = progs.end(); j != jend; j++) {
+ SymExpr *p = j->second;
+ if (p) {
+ Expr *progcode = p->val;
+ p->val = NULL;
+ progcode->dec();
+ p->dec();
+ }
+ }
+}
+
+void init() {
+#ifdef USE_HASH_MAPS
+ string tp("type");
+ symbols[tp] = statType;
+ symbol_types[tp] = statKind;
+ string mpz("mpz");
+ symbols[mpz] = statMpz;
+ symbol_types[mpz] = statType;
+ statType->inc();
+ sym
+#else
+ symbols->insert("type", pair<Expr *, Expr *>(statType, statKind));
+ statType->inc();
+ symbols->insert("mpz", pair<Expr *, Expr *>(statMpz, statType));
+ symbols->insert("mpq", pair<Expr *, Expr *>(statMpq, statType));
+#endif
+}
diff --git a/proofs/lfsc_checker/check.h b/proofs/lfsc_checker/check.h
new file mode 100644
index 000000000..a70599b0f
--- /dev/null
+++ b/proofs/lfsc_checker/check.h
@@ -0,0 +1,167 @@
+#ifndef SC2_CHECK_H
+#define SC2_CHECK_H
+
+#include "expr.h"
+#include "trie.h"
+
+#ifdef _MSC_VER
+#include <hash_map>
+#include <stdio.h>
+#else
+#include <ext/hash_map>
+#endif
+
+#include <stack>
+#include <string>
+#include <map>
+
+// see the help message in main.cpp for explanation
+typedef struct args {
+ std::vector<std::string> files;
+ bool show_runs;
+ bool no_tail_calls;
+ bool compile_scc;
+ bool compile_scc_debug;
+ bool run_scc;
+ bool use_nested_app;
+ bool compile_lib;
+} args;
+
+extern int check_time;
+
+class sccwriter;
+class libwriter;
+
+void init();
+
+void check_file(const char *_filename, args a, sccwriter* scw = NULL, libwriter* lw = NULL);
+
+void cleanup();
+
+extern char our_getc_c;
+
+void report_error(const std::string &);
+
+extern int linenum;
+extern int colnum;
+extern const char *filename;
+extern FILE *curfile;
+
+inline void our_ungetc(char c) {
+ if (our_getc_c != 0)
+ report_error("Internal error: our_ungetc buffer full");
+ our_getc_c = c;
+ if (c == '\n') {
+ linenum--;
+ colnum=-1;
+ }
+ else
+ colnum--;
+}
+
+inline char our_getc() {
+ char c;
+ if (our_getc_c > 0) {
+ c = our_getc_c;
+ our_getc_c = 0;
+ }
+ else{
+#ifndef __linux__
+ c = fgetc(curfile);
+#else
+ c = fgetc_unlocked(curfile);
+#endif
+ }
+ switch(c) {
+ case '\n':
+ linenum++;
+#ifdef DEBUG_LINES
+ std::cout << "line " << linenum << "." << std::endl;
+#endif
+ colnum = 1;
+ break;
+ case EOF:
+ break;
+ default:
+ colnum++;
+ }
+
+ return c;
+}
+
+// return the next character that is not whitespace
+inline char non_ws() {
+ char c;
+ while(isspace(c = our_getc()));
+ if (c == ';') {
+ // comment to end of line
+ while((c = our_getc()) != '\n' && c != EOF);
+ return non_ws();
+ }
+ return c;
+}
+
+inline void eat_char(char expected) {
+ if (non_ws() != expected) {
+ char tmp[80];
+ sprintf(tmp,"Expecting a \'%c\'",expected);
+ report_error(tmp);
+ }
+}
+
+extern int IDBUF_LEN;
+extern char idbuf[];
+
+inline const char *prefix_id() {
+ int i = 0;
+ char c = idbuf[i++] = non_ws();
+ while (!isspace(c) && c != '(' && c != ')' && c != EOF) {
+ if (i == IDBUF_LEN)
+ report_error("Identifier is too long");
+
+ idbuf[i++] = c = our_getc();
+ }
+ our_ungetc(c);
+ idbuf[i-1] = 0;
+ return idbuf;
+}
+
+#ifdef _MSC_VER
+typedef std::hash_map<std::string, Expr *> symmap;
+typedef std::hash_map<std::string, SymExpr *> symmap2;
+#else
+typedef __gnu_cxx::hash_map<std::string, Expr *> symmap;
+typedef __gnu_cxx::hash_map<std::string, SymExpr *> symmap2;
+#endif
+extern symmap2 progs;
+extern std::vector< Expr* > ascHoles;
+
+#ifdef USE_HASH_MAPS
+extern symmap symbols;
+extern symmap symbol_types;
+#else
+extern Trie<std::pair<Expr *, Expr *> > *symbols;
+#endif
+
+extern std::map<SymExpr*, int > mark_map;
+
+extern std::vector< std::pair< std::string, std::pair<Expr *, Expr *> > > local_sym_names;
+
+#ifndef _MSC_VER
+namespace __gnu_cxx
+{
+ template<> struct hash< std::string >
+ {
+ size_t operator()( const std::string& x ) const
+ {
+ return hash< const char* >()( x.c_str() );
+ }
+ };
+}
+#endif
+
+extern Expr *statMpz;
+extern Expr *statMpq;
+extern Expr *statType;
+
+#endif
diff --git a/proofs/lfsc_checker/chunking_memory_management.h b/proofs/lfsc_checker/chunking_memory_management.h
new file mode 100644
index 000000000..bdf938d32
--- /dev/null
+++ b/proofs/lfsc_checker/chunking_memory_management.h
@@ -0,0 +1,157 @@
+///////////////////////////////////////////////////////////////////////////////
+// //
+// Copyright (C) 2002 by the Board of Trustees of Leland Stanford //
+// Junior University. See LICENSE for details. //
+// //
+///////////////////////////////////////////////////////////////////////////////
+/* chunking_memory_management.h
+ Aaron Stump, 6/11/99
+
+ This file contains macros that allow you easily to add chunking
+ memory management for classes.
+
+ RCS Version: $Id: chunking_memory_management.h,v 1.1 2004/11/12 16:26:19 stump Exp $
+
+*/
+#ifndef _chunking_memory_management_h_
+#define _chunking_memory_management_h_
+
+#include <assert.h>
+
+/************************************************************************
+ * MACRO: ADD_CHUNKING_MEMORY_MANAGEMENT_H()
+ * Aaron Stump, 6/11/99
+ *
+ * ABSTRACT: This macro should be called exactly once inside the body
+ * of the declaration of the class THE_CLASS to add chunking memory
+ * management for the class. That class should not itself declare the
+ * operators new and delete. The macro
+ * C_MACROS__ADD_CHUNKING_MEMORY_MANAGEMENT_CC should be called with
+ * the same value for THE_CLASS in a .cc file for that class.
+ *
+ * NOTE that the access specifier will be public after calling this
+ * macro.
+ *
+ * THE_FIELD is a field of the class to use for the next pointer in the
+ * free list data structure. It can be of any type, but must have enough
+ * space to hold a pointer.
+ ************************************************************************/
+#define C_MACROS__ADD_CHUNKING_MEMORY_MANAGEMENT_H(THE_CLASS,THE_FIELD) \
+private:\
+ static unsigned C_MACROS__CHUNK_SIZE;\
+ static unsigned C_MACROS__BLOCK_SIZE;\
+ static void *C_MACROS__freelist;\
+ static bool C_MACROS__initialized;\
+ static char *C_MACROS__next_free_block;\
+ static char *C_MACROS__end_of_current_chunk;\
+ \
+ static void C_MACROS__allocate_new_chunk();\
+\
+public:\
+ static void C_MACROS__init_chunks() {\
+ if (!C_MACROS__initialized) {\
+ C_MACROS__allocate_new_chunk();\
+ C_MACROS__initialized = true;\
+ }\
+ }\
+\
+ static void *operator new(size_t size, void *h = NULL);\
+ static void operator delete(void *ptr)\
+
+
+/************************************************************************
+ * MACRO: ADD_CHUNKING_MEMORY_MANAGEMENT_CC()
+ * Aaron Stump, 6/11/99
+ *
+ * ABSTRACT: This macro should be called exactly once in a .cc file
+ * for the class THE_CLASS to add chunking memory management for the
+ * class. This macro should be called with the same value for
+ * THE_CLASS as was used in calling
+ * C_MACROS__ADD_CHUNKING_MEMORY_MANAGEMENT_H in the body of the
+ * declaration of THE_CLASS. THE_CHUNK_SIZE is the number of blocks
+ * of memory to get at once using malloc(). A block is the portion
+ * of memory needed for one instance of THE_CLASS.
+ *
+ *
+ * IMPLEMENTATION:
+ ************************************************************************
+ * FUNCTION: allocate_new_chunk()
+ * Aaron Stump, 6/8/99
+ *
+ * ABSTRACT: This method allocates a new chunk of memory to use for
+ * allocating instances of THE_CLASS.
+ ************************************************************************
+ * FUNCTION: new()
+ * Aaron Stump, 6/8/99
+ *
+ * ABSTRACT: This allocator uses chunks for more efficient allocation.
+ ************************************************************************
+ * FUNCTION: delete()
+ * Aaron Stump, 6/8/99
+ *
+ * ABSTRACT: This delete() puts the chunk pointed to by ptr on the
+ * freelist.
+ ************************************************************************
+ * Chunking_Memory_Management_Initializer and its static instance are used
+ * to call the static init_chunks() method for THE_CLASS.
+ ************************************************************************/
+#define C_MACROS__ADD_CHUNKING_MEMORY_MANAGEMENT_CC(THE_CLASS,THE_FIELD,THE_CHUNK_SIZE) \
+unsigned THE_CLASS::C_MACROS__CHUNK_SIZE = THE_CHUNK_SIZE;\
+\
+unsigned THE_CLASS::C_MACROS__BLOCK_SIZE = sizeof(THE_CLASS);\
+\
+void * THE_CLASS::C_MACROS__freelist = NULL;\
+char * THE_CLASS::C_MACROS__next_free_block = NULL;\
+char * THE_CLASS::C_MACROS__end_of_current_chunk = NULL;\
+bool THE_CLASS::C_MACROS__initialized = false;\
+\
+void \
+THE_CLASS::C_MACROS__allocate_new_chunk() {\
+\
+ unsigned tmp = C_MACROS__CHUNK_SIZE * C_MACROS__BLOCK_SIZE;\
+ char *chunk = (char *)malloc(tmp);\
+ \
+ assert (chunk != NULL); \
+\
+ C_MACROS__next_free_block = chunk;\
+ C_MACROS__end_of_current_chunk = chunk + tmp;\
+}\
+\
+void * \
+THE_CLASS::operator new(size_t size, void *h) {\
+ (void)size; /* size should always be _BLOCK_SIZE */\
+\
+ if (h != NULL)\
+ /* we're being told what memory we should use */\
+ return h;\
+\
+ char *new_block;\
+\
+ if (C_MACROS__freelist) {\
+ /* we have a block on the freelist that we can use */\
+ new_block = (char *)C_MACROS__freelist; \
+ C_MACROS__freelist = (void *)((THE_CLASS *)new_block)->THE_FIELD; \
+ }\
+ else {\
+ /* we have to get a new block from a chunk (which we may */\
+ /* have to allocate*/\
+ \
+ if (C_MACROS__next_free_block == C_MACROS__end_of_current_chunk)\
+ C_MACROS__allocate_new_chunk();\
+ \
+ new_block = C_MACROS__next_free_block;\
+ C_MACROS__next_free_block += C_MACROS__BLOCK_SIZE;\
+ }\
+ \
+ return new_block;\
+}\
+\
+void \
+THE_CLASS::operator delete(void *ptr) {\
+ void **f = (void **)&((THE_CLASS *)ptr)->THE_FIELD; \
+ *f = C_MACROS__freelist; \
+ C_MACROS__freelist = ptr; \
+}
+
+#endif
+
diff --git a/proofs/lfsc_checker/code.cpp b/proofs/lfsc_checker/code.cpp
new file mode 100644
index 000000000..225700580
--- /dev/null
+++ b/proofs/lfsc_checker/code.cpp
@@ -0,0 +1,1377 @@
+#include "check.h"
+#include "code.h"
+#include <string>
+
+#include "scccode.h"
+
+using namespace std;
+
+string *eat_str(const char *str, bool check_end = true) {
+ string *s = new string();
+ char c, d;
+ while ((c = *str++)) {
+ d = our_getc();
+ if (c != d) {
+ our_ungetc(d);
+ return s;
+ }
+ s->push_back(d);
+ }
+
+ if (check_end &&
+ (d = our_getc()) != ' ' && d != '(' && d != '\n' && d != '\t') {
+ our_ungetc(d);
+ return s;
+ }
+
+ delete s;
+ return 0;
+}
+
+SymSExpr *read_ctor() {
+ string id(prefix_id());
+#ifdef USE_HASH_TABLES
+ Expr *s = symbols[id];
+ Expr *stp = symbol_types[id];
+#else
+ pair<Expr *, Expr *> p = symbols->get(id.c_str());
+ Expr *s = p.first;
+ Expr *stp = p.second;
+#endif
+
+ if (!stp)
+ report_error("Undeclared identifier parsing a pattern.");
+
+ if (s->getclass() != SYMS_EXPR || ((SymExpr *)s)->val)
+ report_error("The head of a pattern is not a constructor.");
+
+ s->inc();
+
+ return (SymSExpr *)s;
+}
+
+Expr *read_case() {
+ eat_char('(');
+ Expr *pat = NULL;
+ vector<SymSExpr *> vars;
+
+#ifdef USE_HASH_MAPS
+ vector<Expr *>prevs;
+#else
+ vector<pair<Expr *,Expr *> >prevs;
+#endif
+ char d = non_ws();
+ switch(d) {
+ case '(': {
+ // parse application
+ SymSExpr *s = read_ctor();
+ pat = s;
+ char c;
+ while ((c = non_ws()) != ')') {
+ our_ungetc(c);
+ string varstr(prefix_id());
+ SymSExpr *var = new SymSExpr(varstr);
+ vars.push_back(var);
+#ifdef USE_HASH_MAPS
+ prevs.push_back(symbols[varstr]);
+ symbols[varstr] = var;
+#else
+ prevs.push_back(symbols->insert(varstr.c_str(),
+ pair<Expr *, Expr *>(var,NULL)));
+#endif
+#ifndef USE_FLAT_APP
+ pat = new CExpr(APP,pat,var);
+#else
+ pat = Expr::make_app(pat,var);
+#endif
+ }
+ break;
+ }
+ // default case
+ case 'd': {
+ delete eat_str("efault");
+ }
+ break;
+ case EOF:
+ report_error("Unexpected end of file parsing a pattern.");
+ break;
+ default:
+ // could be an identifier
+ our_ungetc(d);
+ pat = read_ctor();
+ break;
+ }
+
+ Expr *ret = read_code();
+ if( pat )
+ ret = new CExpr(CASE, pat, ret);
+
+ for (int i = 0, iend = prevs.size(); i < iend; i++) {
+ string &s = vars[i]->s;
+#ifdef USE_HASH_MAPS
+ symbols[s] = prevs[i];
+#else
+ symbols->insert(s.c_str(), prevs[i]);
+#endif
+ }
+
+ eat_char(')');
+
+ return ret;
+}
+
+Expr *read_code() {
+ string *pref = NULL;
+ char d = non_ws();
+ switch(d) {
+ case '(':
+ {
+ char c = non_ws();
+ switch (c)
+ {
+ case 'd':
+ {
+ our_ungetc('d');
+ pref = eat_str("do");
+ if (pref)
+ break;
+ Expr *ret = read_code();
+ while ((c = non_ws()) != ')') {
+ our_ungetc(c);
+ ret = new CExpr(DO,ret,read_code());
+ }
+ return ret;
+ }
+ case 'f':
+ {
+ our_ungetc('f');
+ pref = eat_str("fail");
+ if (pref)
+ break;
+
+ Expr *c = read_code();
+ eat_char(')');
+
+ //do we need to check this???
+ //if (c->getclass() != SYMS_EXPR || ((SymExpr *)c)->val)
+ // report_error(string("\"fail\" must be used with a (undefined) base ")
+ // +string("type.\n1. the expression used: "+c->toString()));
+
+ return new CExpr(FAIL, c);
+ }
+ case 'l':
+ {
+ our_ungetc('l');
+ pref = eat_str("let");
+ if (pref)
+ break;
+
+ string id(prefix_id());
+ SymSExpr *var = new SymSExpr(id);
+
+ Expr *t1 = read_code();
+
+#ifdef USE_HASH_MAPS
+ Expr *prev = symbols[id];
+ symbols[id] = var;
+#else
+ pair<Expr *, Expr *> prev =
+ symbols->insert(id.c_str(), pair<Expr *, Expr *>(var,NULL));
+#endif
+
+ Expr *t2 = read_code();
+
+#ifdef USE_HASH_MAPS
+ symbols[id] = prev;
+#else
+ symbols->insert(id.c_str(), prev);
+#endif
+ eat_char(')');
+ return new CExpr(LET, var, t1, t2);
+ }
+ case 'i':
+ {
+ our_ungetc('i');
+ pref = eat_str("ifmarked",false);
+ if (pref)
+ break;
+#ifndef MARKVAR_32
+ Expr *e1 = read_code();
+ Expr *e2 = read_code();
+ Expr *e3 = read_code();
+ Expr *ret = new CExpr(IFMARKED, e1, e2, e3);
+#else
+ int index = read_index();
+ Expr *e1 = read_code();
+ Expr *e2 = read_code();
+ Expr *e3 = read_code();
+ Expr *ret = NULL;
+ if( index>=1 && index<=32 )
+ {
+ ret = new CExpr( IFMARKED, new IntExpr( index-1 ), e1, e2, e3 );
+ }
+ else
+ {
+ std::cout << "Can't make IFMARKED with index = " << index << std::endl;
+ }
+ Expr::markedCount++;
+ //Expr *ret = new CExpr(IFMARKED, e1, e2, e3);
+#endif
+ eat_char(')');
+ return ret;
+ }
+ case 'm':
+ {
+ char c;
+ switch ((c = our_getc()))
+ {
+ case 'a':
+ {
+ char cc;
+ switch ((cc = our_getc())) {
+ case 't':
+ {
+ our_ungetc('t');
+ pref = eat_str("tch");
+ if (pref) {
+ pref->insert(0,"ma");
+ break;
+ }
+ vector<Expr *> cases;
+ cases.push_back(read_code()); // the scrutinee
+ while ((c = non_ws()) != ')' && c != 'd') {
+ our_ungetc(c);
+ cases.push_back(read_case());
+ }
+ if (cases.size() == 1) // counting scrutinee
+ report_error("A match has no cases.");
+ if (c == 'd') {
+ // we have a default case
+ //delete eat_str("efault");
+ our_ungetc(c);
+ cases.push_back(read_case());
+ }
+ return new CExpr(MATCH,cases);
+ }
+ case 'r':
+ {
+ our_ungetc('r');
+ pref = eat_str("rkvar", false);
+ if (pref) {
+ pref->insert(0,"ma");
+ break;
+ }
+ #ifndef MARKVAR_32
+ Expr *ret = new CExpr(MARKVAR,read_code());
+ #else
+ int index = read_index();
+ CExpr* ret = NULL;
+ if( index>=1 && index<=32 )
+ {
+ ret = new CExpr( MARKVAR, new IntExpr( index-1 ), read_code() );
+ }
+ else
+ {
+ std::cout << "Can't make MARKVAR with index = " << index << std::endl;
+ }
+ Expr::markedCount++;
+ //Expr *ret = new CExpr(MARKVAR,read_code());
+ #endif
+
+ eat_char(')');
+ return ret;
+ }
+ default:
+ our_ungetc(c);
+ pref = new string("ma");
+ break;
+ }
+ }
+ case 'p':
+ {
+ our_ungetc('p');
+ pref = eat_str("p_",false);
+ if (pref) {
+ pref->insert(0,"m");
+ break;
+ }
+ char c = our_getc();
+ switch(c) {
+ case 'a':
+ {
+ our_ungetc('a');
+ pref = eat_str("add");
+ if (pref) {
+ pref->insert(0,"mp_");
+ break;
+ }
+ Expr* e1 = read_code();
+ Expr* e2 = read_code();
+ Expr *ret = new CExpr(ADD, e1, e2);
+ eat_char(')');
+ return ret;
+ }
+ case 'n':
+ {
+ our_ungetc('n');
+ pref = eat_str("neg");
+ if (pref) {
+ pref->insert(0,"mp_");
+ break;
+ }
+
+ Expr *ret = new CExpr(NEG, read_code());
+ eat_char(')');
+ return ret;
+ }
+ case 'i':
+ { // mpz_if_neg
+ char c = our_getc();
+ if( c=='f' )
+ {
+ c = our_getc();
+ switch( c )
+ {
+ case 'n': {
+ our_ungetc('n');
+ pref = eat_str("neg");
+ if( pref ) {
+ pref->insert(0,"mp_if");
+ break;
+ }
+ Expr* e1 = read_code();
+ Expr* e2 = read_code();
+ Expr* e3 = read_code();
+ Expr* ret = new CExpr(IFNEG, e1, e2, e3 );
+ eat_char(')');
+ return ret;
+ }
+ case 'z': {
+ our_ungetc('z');
+ pref = eat_str("zero");
+ if( pref ) {
+ pref->insert(0,"mp_if");
+ break;
+ }
+ Expr* e1 = read_code();
+ Expr* e2 = read_code();
+ Expr* e3 = read_code();
+ Expr* ret = new CExpr(IFZERO, e1, e2, e3 );
+ eat_char(')');
+ return ret;
+ }
+ default:
+ our_ungetc(c);
+ pref = new string("mp_if");
+ break;
+ }
+ }
+ else
+ {
+ our_ungetc(c);
+ pref = new string("mp_i");
+ break;
+ }
+ }
+ case 'm':
+ {
+ our_ungetc('m');
+ pref = eat_str("mul");
+ if( pref ){
+ pref->insert(0,"mp_");
+ break;
+ }
+ Expr* e1 = read_code();
+ Expr* e2 = read_code();
+ Expr* ret = new CExpr(MUL, e1, e2 );
+ eat_char(')');
+ return ret;
+ }
+ case 'd':
+ {
+ our_ungetc('d');
+ pref = eat_str("div");
+ if( pref ){
+ pref->insert(0,"mp_");
+ break;
+ }
+ Expr* e1 = read_code();
+ Expr* e2 = read_code();
+ Expr* ret = new CExpr(DIV, e1, e2 );
+ eat_char(')');
+ return ret;
+ }
+ default:
+ our_ungetc(c);
+ pref = new string("mp_");
+ break;
+ }
+ }
+ default:
+ our_ungetc(c);
+ pref = new string("m");
+ break;
+ }
+ break;
+ }
+ case '~': {
+ Expr *e = read_code();
+ if( e->getclass()==INT_EXPR )
+ {
+ IntExpr *ee = (IntExpr *)e;
+ mpz_neg(ee->n, ee->n);
+ eat_char(')');
+ return ee;
+ }
+ else if( e->getclass() == RAT_EXPR )
+ {
+ RatExpr *ee = (RatExpr *)e;
+ mpq_neg(ee->n, ee->n);
+ eat_char(')');
+ return ee;
+ }
+ else
+ {
+ report_error("Negative sign with expr that is not an int. literal.");
+ }
+ }
+ case 'c':
+ {
+ our_ungetc('c');
+ pref = eat_str("compare");
+ if (pref)
+ break;
+ Expr *e1 = read_code();
+ Expr *e2 = read_code();
+ Expr *e3 = read_code();
+ Expr *e4 = read_code();
+ eat_char(')');
+ return new CExpr(COMPARE, e1, e2, e3, e4);
+ }
+ break;
+ case EOF:
+ report_error("Unexpected end of file.");
+ break;
+ default:
+ { // the application case
+ our_ungetc(c);
+ break;
+ }
+ }
+ // parse application
+ if (pref)
+ // we have eaten part of the name of an applied identifier
+ pref->append(prefix_id());
+ else
+ pref = new string(prefix_id());
+
+ Expr *ret = progs[*pref];
+ if (!ret)
+#ifdef USE_HASH_TABLES
+ ret = symbols[*pref];
+#else
+ ret = symbols->get(pref->c_str()).first;
+#endif
+
+ if (!ret)
+ report_error(string("Undeclared identifier at head of an application: ")
+ +*pref);
+
+ ret->inc();
+ delete pref;
+
+ while ((c = non_ws()) != ')') {
+ our_ungetc(c);
+#ifndef USE_FLAT_APP
+ ret = new CExpr(APP,ret,read_code());
+#else
+ Expr* ke = read_code();
+ ret = Expr::make_app(ret,ke);
+#endif
+ }
+ return ret;
+ } // end case '('
+ case EOF:
+ report_error("Unexpected end of file.");
+ break;
+ case '_':
+ report_error("Holes may not be used in code.");
+ return NULL;
+ case '0':
+ case '1':
+ case '2':
+ case '3':
+ case '4':
+ case '5':
+ case '6':
+ case '7':
+ case '8':
+ case '9':
+ {
+ our_ungetc(d);
+ string v;
+ char c;
+ while (isdigit(c = our_getc()))
+ v.push_back(c);
+ bool parseMpq = false;
+ if( c=='/' )
+ {
+ parseMpq = true;
+ v.push_back(c);
+ while(isdigit(c = our_getc()))
+ v.push_back(c);
+ }
+ our_ungetc(c);
+ if( parseMpq )
+ {
+ mpq_t num;
+ mpq_init(num);
+ if (mpq_set_str(num,v.c_str(),10) == -1 )
+ report_error("Error reading a mpq numeral.");
+
+ Expr* e = new RatExpr( num );
+ return e;
+ }
+ else
+ {
+ mpz_t num;
+ if (mpz_init_set_str(num,v.c_str(),10) == -1)
+ report_error("Error reading a numeral.");
+ return new IntExpr(num);
+ }
+ }
+ default:
+ {
+ our_ungetc(d);
+ string id(prefix_id());
+#ifdef USE_HASH_MAPS
+ Expr *ret = symbols[id];
+#else
+ pair<Expr *, Expr *> p = symbols->get(id.c_str());
+ Expr *ret = p.first;
+#endif
+ if (!ret)
+ ret = progs[id];
+ if (!ret)
+ report_error(string("Undeclared identifier: ")+id);
+ ret->inc();
+ return ret;
+ }
+ }
+ report_error("Unexpected operator in a piece of code.");
+ return 0;
+}
+
+// the input is owned by the caller, the output by us (so do not dec it).
+Expr *check_code(Expr *_e) {
+ CExpr *e = (CExpr *)_e;
+ switch (e->getop()) {
+ case NOT_CEXPR:
+ switch (e->getclass()) {
+ case INT_EXPR:
+ return statMpz;
+ case RAT_EXPR:
+ return statMpq;
+ case SYM_EXPR: {
+ report_error("Internal error: an LF variable is encountered in code");
+ break;
+ }
+ case SYMS_EXPR: {
+#ifdef USE_HASH_MAPS
+ Expr *tp = symbol_types[((SymSExpr *)e)->s];
+#else
+ Expr *tp = symbols->get(((SymSExpr *)e)->s.c_str()).second;
+#endif
+ if (!tp)
+ report_error(string("A symbol is missing a type in a piece of code.")
+ +string("\n1. the symbol: ")+((SymSExpr *)e)->s);
+ return tp;
+ }
+ case HOLE_EXPR:
+ report_error("Encountered a hole unexpectedly in code.");
+ default:
+ report_error("Unrecognized form of expr in code.");
+ }
+ case APP: {
+#ifdef USE_FLAT_APP
+ Expr* h = e->kids[0]->followDefs();
+ vector<Expr *> argtps;
+ int counter = 1;
+ while( e->kids[counter] )
+ {
+ argtps.push_back( check_code( e->kids[counter] ) );
+ counter++;
+ }
+ int iend = counter-1;
+#else
+ vector<Expr *> args;
+ Expr *h = (Expr *)e->collect_args(args);
+
+ int iend = args.size();
+ vector<Expr *> argtps(iend);
+ for (int i = 0; i < iend; i++)
+ argtps[i] = check_code(args[i]);
+#endif
+
+ Expr *tp = NULL;
+ if (h->getop() == PROG){
+ tp = ((CExpr *)h)->kids[0];
+ }else {
+#ifdef USE_HASH_MAPS
+ tp = symbol_types[((SymSExpr *)h)->s];
+#else
+ tp = symbols->get(((SymSExpr *)h)->s.c_str()).second;
+#endif
+ }
+
+ if (!tp)
+ report_error(string("The head of an application is missing a type in ")
+ +string("code.\n1. the application: ")+e->toString());
+
+ tp = tp->followDefs();
+
+ if (tp->getop() != PI)
+ report_error(string("The head of an application does not have ")
+ +string("functional type in code.")
+ +string("\n1. the application: ")+e->toString());
+
+ CExpr *cur = (CExpr *)tp;
+ int i = 0;
+ while (cur->getop() == PI) {
+ if (i >= iend)
+ report_error(string("A function is not being fully applied in code.\n")
+ +string("1. the application: ")+e->toString()
+ +string("\n2. its (functional) type: ")+cur->toString());
+ if( argtps[i]->getop()==APP )
+ argtps[i] = ((CExpr*)argtps[i])->kids[0];
+ if (argtps[i] != cur->kids[1]) {
+ char buf[1024];
+ sprintf(buf,"%d",i);
+ report_error(string("Type mismatch for argument ")
+ + string(buf)
+ + string(" in application in code.\n")
+ + string("1. the application: ")+e->toString()
+ + string("\n2. the head's type: ")+tp->toString()
+#ifdef USE_FLAT_APP
+ + string("\n3. the argument: ")+e->kids[i+1]->toString()
+#else
+ + string("\n3. the argument: ")+args[i]->toString()
+#endif
+ + string("\n4. computed type: ")+argtps[i]->toString()
+ + string("\n5. expected type: ")
+ +cur->kids[1]->toString());
+ }
+
+ //if (cur->kids[2]->free_in((SymExpr *)cur->kids[0]))
+ if( cur->get_free_in() ){
+ cur->calc_free_in();
+ //are you sure?
+ if( cur->get_free_in() )
+ report_error(string("A dependently typed function is being applied in")
+ +string(" code.\n1. the application: ")+e->toString()
+ +string("\n2. the head's type: ")+tp->toString());
+ //ok, reset the mark
+ cur->setexmark();
+ }
+
+ i++;
+ cur = (CExpr *)cur->kids[2];
+ }
+ if (i < iend)
+ report_error(string("A function is being fully applied to too many ")
+ +string("arguments in code.\n")
+ +string("1. the application: ")+e->toString()
+ +string("\n2. the head's type: ")+tp->toString());
+
+
+ return cur;
+ }
+ //is this right?
+ case MPZ:
+ return statType;
+ break;
+ case MPQ:
+ return statType;
+ break;
+ case DO:
+ check_code(e->kids[0]);
+ return check_code(e->kids[1]);
+
+ case LET: {
+ SymSExpr * var = (SymSExpr *)e->kids[0];
+
+ Expr *tp1 = check_code(e->kids[1]);
+
+#ifdef USE_HASH_MAPS
+ Expr *prevtp = symbol_types[var->s];
+ symbol_types[var->s] = tp1;
+#else
+ pair<Expr *, Expr *> prev =
+ symbols->insert(var->s.c_str(), pair<Expr *, Expr *>(NULL,tp1));
+#endif
+
+ Expr *tp2 = check_code(e->kids[2]);
+
+#ifdef USE_HASH_MAPS
+ symbol_types[var->s] = prevtp;
+#else
+ symbols->insert(var->s.c_str(), prev);
+#endif
+
+ return tp2;
+ }
+
+ case ADD:
+ case MUL:
+ case DIV:
+ {
+ Expr *tp0 = check_code(e->kids[0]);
+ Expr *tp1 = check_code(e->kids[1]);
+
+ if (tp0 != statMpz && tp0 != statMpq )
+ report_error(string("Argument to mp_[arith] does not have type \"mpz\" or \"mpq\".\n")
+ +string("1. the argument: ")+e->kids[0]->toString()
+ +string("\n1. its type: ")+tp0->toString());
+
+ if (tp0 != tp1)
+ report_error(string("Arguments to mp_[arith] have differing types.\n")
+ +string("1. argument 1: ")+e->kids[0]->toString()
+ +string("\n1. its type: ")+tp0->toString()
+ +string("2. argument 2: ")+e->kids[1]->toString()
+ +string("\n2. its type: ")+tp1->toString());
+
+ return tp0;
+ }
+
+ case NEG: {
+ Expr *tp0 = check_code(e->kids[0]);
+ if (tp0 != statMpz && tp0 != statMpq )
+ report_error(string("Argument to mp_neg does not have type \"mpz\" or \"mpq\".\n")
+ +string("1. the argument: ")+e->kids[0]->toString()
+ +string("\n1. its type: ")+tp0->toString());
+
+ return tp0;
+ }
+
+ case IFNEG:
+ case IFZERO: {
+ Expr *tp0 = check_code(e->kids[0]);
+ if (tp0 != statMpz && tp0 != statMpq)
+ report_error(string("Argument to mp_if does not have type \"mpz\" or \"mpq\".\n")
+ +string("1. the argument: ")+e->kids[0]->toString()
+ +string("\n1. its type: ")+tp0->toString());
+
+ SymSExpr *tp1 = (SymSExpr *)check_code(e->kids[1]);
+ SymSExpr *tp2 = (SymSExpr *)check_code(e->kids[2]);
+ if (tp1->getclass() != SYMS_EXPR || tp1->val || tp1 != tp2)
+ report_error(string("\"mp_if\" used with expressions that do not ")
+ +string("have equal simple datatypes\nfor their types.\n")
+ +string("0. 0'th expression: ")+e->kids[0]->toString()
+ +string("\n1. first expression: ")+e->kids[1]->toString()
+ +string("\n2. second expression: ")+e->kids[2]->toString()
+ +string("\n3. first expression's type: ")+tp1->toString()
+ +string("\n4. second expression's type: ")+tp2->toString());
+ return tp1;
+ }
+
+ case FAIL: {
+ Expr *tp = check_code(e->kids[0]);
+ if (tp != statType)
+ report_error(string("\"fail\" is used with an expression which is ")
+ +string("not a type.\n1. the expression :")
+ +e->kids[0]->toString()
+ +string("\n2. its type: ")+tp->toString());
+ return e->kids[0];
+ }
+ case MARKVAR: {
+ SymSExpr *tp = (SymSExpr *)check_code(e->kids[1]);
+
+ Expr* tptp = NULL;
+
+ if (tp->getclass() == SYMS_EXPR && !tp->val){
+#ifdef USE_HASH_MAPS
+ tptp = symbol_types[tp->s];
+#else
+ tptp = symbols->get(tp->s.c_str()).second;
+#endif
+ }
+
+ if (!tptp->isType( statType )){
+ string errstr = (string("\"markvar\" is used with an expression which ")
+ +string("cannot be a lambda-bound variable.\n")
+ +string("1. the expression :")
+ +e->kids[1]->toString()
+ +string("\n2. its type: ")+tp->toString());
+ report_error(errstr);
+ }
+
+ return tp;
+ }
+
+ case IFMARKED:
+ {
+ SymSExpr *tp = (SymSExpr *)check_code(e->kids[1]);
+
+ Expr* tptp = NULL;
+
+ if (tp->getclass() == SYMS_EXPR && !tp->val){
+#ifdef USE_HASH_MAPS
+ tptp = symbol_types[tp->s];
+#else
+ tptp = symbols->get(tp->s.c_str()).second;
+#endif
+ }
+
+ if (!tptp->isType( statType ) ){
+ string errstr = (string("\"ifmarked\" is used with an expression which ")
+ +string("cannot be a lambda-bound variable.\n")
+ +string("1. the expression :")
+ +e->kids[1]->toString()
+ +string("\n2. its type: ")+tp->toString());
+ report_error(errstr);
+ }
+
+ SymSExpr *tp1 = (SymSExpr *)check_code(e->kids[2]);
+ SymSExpr *tp2 = (SymSExpr *)check_code(e->kids[3]);
+ if (tp1->getclass() != SYMS_EXPR || tp1->val || tp1 != tp2)
+ report_error(string("\"ifmarked\" used with expressions that do not ")
+ +string("have equal simple datatypes\nfor their types.\n")
+ +string("0. 0'th expression: ")+e->kids[1]->toString()
+ +string("\n1. first expression: ")+e->kids[2]->toString()
+ +string("\n2. second expression: ")+e->kids[3]->toString()
+ +string("\n3. first expression's type: ")+tp1->toString()
+ +string("\n4. second expression's type: ")+tp2->toString());
+ return tp1;
+ }
+ case COMPARE:
+ {
+ SymSExpr *tp0 = (SymSExpr *)check_code(e->kids[0]);
+ if (tp0->getclass() != SYMS_EXPR || tp0->val){
+ string errstr0 = (string("\"compare\" is used with a first expression which ")
+ +string("cannot be a lambda-bound variable.\n")
+ +string("1. the expression :")
+ +e->kids[0]->toString()
+ +string("\n2. its type: ")+tp0->toString());
+ report_error(errstr0);
+ }
+
+ SymSExpr *tp1 = (SymSExpr *)check_code(e->kids[1]);
+
+ if (tp1->getclass() != SYMS_EXPR || tp1->val){
+ string errstr1 = (string("\"compare\" is used with a second expression which ")
+ +string("cannot be a lambda-bound variable.\n")
+ +string("1. the expression :")
+ +e->kids[1]->toString()
+ +string("\n2. its type: ")+tp1->toString());
+ report_error(errstr1);
+ }
+
+ SymSExpr *tp2 = (SymSExpr *)check_code(e->kids[2]);
+ SymSExpr *tp3 = (SymSExpr *)check_code(e->kids[3]);
+ if (tp2->getclass() != SYMS_EXPR || tp2->val || tp2 != tp3)
+ report_error(string("\"compare\" used with expressions that do not ")
+ +string("have equal simple datatypes\nfor their types.\n")
+ +string("\n1. first expression: ")+e->kids[2]->toString()
+ +string("\n2. second expression: ")+e->kids[3]->toString()
+ +string("\n3. first expression's type: ")+tp2->toString()
+ +string("\n4. second expression's type: ")+tp3->toString());
+ return tp2;
+ }
+ case MATCH:
+ {
+ SymSExpr *scruttp = (SymSExpr *)check_code(e->kids[0]);
+ Expr *tptp = NULL;
+ if (scruttp->getclass() == SYMS_EXPR && !scruttp->val){
+#ifdef USE_HASH_MAPS
+ tptp = symbol_types[scruttp->s];
+#else
+ tptp = symbols->get(scruttp->s.c_str()).second;
+#endif
+ }
+ if (!tptp->isType( statType )){
+ string errstr = (string("The scrutinee of a match is not ")
+ +string("a plain piece of data.\n")
+ +string("1. the scrutinee: ")
+ +e->kids[0]->toString()
+ +string("\n2. its type: ")+scruttp->toString());
+ report_error(errstr);
+ }
+
+ int i = 1;
+ Expr **cur = &e->kids[i];
+ Expr *mtp = NULL;
+ Expr *c_or_default;
+ CExpr *c;
+ while ((c_or_default = *cur++)) {
+ Expr *tp = NULL;
+ CExpr *pat = NULL;
+ if (c_or_default->getop() != CASE)
+ // this is the default of the MATCH
+ tp = check_code(c_or_default);
+ else {
+ // this is a CASE of the MATCH
+ c = (CExpr *)c_or_default;
+ pat = (CExpr *)c->kids[0]; // might be just a SYMS_EXPR
+ if (pat->getclass() == SYMS_EXPR)
+ tp = check_code(c->kids[1]);
+ else {
+ // extend type context and then check the body of the case
+#ifdef USE_HASH_MAPS
+ vector<Expr *>prevs;
+#else
+ vector<pair<Expr *,Expr *> >prevs;
+#endif
+ vector<Expr *> vars;
+ SymSExpr *ctor = (SymSExpr *)pat->collect_args(vars);
+#ifdef USE_HASH_MAPS
+ CExpr *ctortp = (CExpr *)symbol_types[ctor->s];
+#else
+ CExpr *ctortp = (CExpr *)symbols->get(ctor->s.c_str()).second;
+#endif
+ CExpr *curtp = ctortp;
+ for (int i = 0, iend = vars.size(); i < iend; i++) {
+ if ( curtp->followDefs()->getop() != PI)
+ report_error(string("Too many arguments to a constructor in")
+ +string(" a pattern.\n1. the pattern: ")
+ +pat->toString()
+ +string("\n2. the head's type: "
+ +ctortp->toString()));
+#ifdef USE_HASH_MAPS
+ prevs.push_back(symbol_types[((SymSExpr *)vars[i])->s]);
+ symbol_types[((SymSExpr *)vars[i])] = curtp->followDefs()->kids[1];
+#else
+ prevs.push_back
+ (symbols->insert(((SymSExpr *)vars[i])->s.c_str(),
+ pair<Expr *, Expr *>(NULL,
+ ((CExpr *)(curtp->followDefs()))->kids[1])));
+#endif
+ curtp = (CExpr *)((CExpr *)(curtp->followDefs()))->kids[2];
+ }
+
+ tp = check_code(c->kids[1]);
+
+ for (int i = 0, iend = prevs.size(); i < iend; i++) {
+#ifdef USE_HASH_MAPS
+ symbol_types[((SymSExpr *)vars[i])->s] = prevs[i];
+#else
+ symbols->insert(((SymSExpr *)vars[i])->s.c_str(), prevs[i]);
+#endif
+ }
+ }
+ }
+
+ // check that the type for the body of this case -- or the default value --
+ // matches the type for the previous case if we had one.
+
+ if (!mtp)
+ mtp = tp;
+ else
+ if (mtp != tp)
+ report_error(string("Types for bodies of match cases or the default differ.")
+ +string("\n1. type for first case's body: ")
+ +mtp->toString()
+ +(pat == NULL ? string("\n2. type for the default")
+ : (string("\n2. type for the body of case for ")
+ +pat->toString()))
+ +string(": ")+tp->toString());
+
+ }
+
+ return mtp;
+ }
+ } // end switch
+
+ report_error("Type checking an unrecognized form of code (internal error).");
+ return NULL;
+}
+
+bool dbg_prog;
+bool run_scc;
+int dbg_prog_indent_lvl = 0;
+
+void dbg_prog_indent(std::ostream &os) {
+ for (int i = 0; i < dbg_prog_indent_lvl; i++)
+ os << " ";
+}
+
+Expr *run_code(Expr *_e) {
+ start_run_code:
+ CExpr *e = (CExpr *)_e;
+ if( e )
+ {
+ //std::cout << ". ";
+ //e->print( std::cout );
+ //std::cout << std::endl;
+ //std::cout << e->getop() << " " << e->getclass() << std::endl;
+ }
+ switch (e->getop()) {
+ case NOT_CEXPR:
+ switch(e->getclass()) {
+ case INT_EXPR:
+ case RAT_EXPR:
+ e->inc();
+ return e;
+ case HOLE_EXPR: {
+ Expr *tmp = e->followDefs();
+ if (tmp == e)
+ report_error("Encountered an unfilled hole running code.");
+ tmp->inc();
+ return tmp;
+ }
+ case SYMS_EXPR:
+ case SYM_EXPR: {
+ Expr *tmp = e->followDefs();
+ //std::cout << "follow def = ";
+ //tmp->print( std::cout );
+ //std::cout << std::endl;
+ if (tmp == e) {
+ e->inc();
+ return e;
+ }
+ tmp->inc();
+ return tmp;
+ }
+ }
+ case FAIL:
+ return NULL;
+ case DO: {
+ Expr *tmp = run_code(e->kids[0]);
+ if (!tmp)
+ return NULL;
+ tmp->dec();
+ _e = e->kids[1];
+ goto start_run_code;
+ }
+ case LET: {
+ Expr *r0 = run_code(e->kids[1]);
+ if (!r0)
+ return NULL;
+ SymExpr *var = (SymExpr *)e->kids[0];
+ Expr *prev = var->val;
+ var->val = r0;
+ Expr *r1 = run_code(e->kids[2]);
+ var->val = prev;
+ r0->dec();
+ return r1;
+ }
+ case ADD:
+ case MUL:
+ case DIV:
+ {
+ Expr *r1 = run_code(e->kids[0]);
+ if (!r1)
+ return NULL;
+ Expr *r2 = run_code(e->kids[1]);
+ if (!r2)
+ return NULL;
+ if( r1->getclass()==INT_EXPR && r2->getclass()==INT_EXPR )
+ {
+ mpz_t r;
+ mpz_init(r);
+ if( e->getop()==ADD )
+ mpz_add(r, ((IntExpr *)r1)->n, ((IntExpr *)r2)->n);
+ else if( e->getop()==MUL )
+ mpz_mul(r, ((IntExpr *)r1)->n, ((IntExpr *)r2)->n);
+ else if( e->getop()==DIV )
+ mpz_cdiv_q(r, ((IntExpr *)r1)->n, ((IntExpr *)r2)->n);
+ r1->dec();
+ r2->dec();
+ return new IntExpr(r);
+ }
+ else if( r1->getclass()==RAT_EXPR && r2->getclass()==RAT_EXPR )
+ {
+ mpq_t q;
+ mpq_init(q);
+ if( e->getop()==ADD )
+ mpq_add(q, ((RatExpr *)r1)->n, ((RatExpr *)r2)->n);
+ else if( e->getop()==MUL )
+ mpq_mul(q, ((RatExpr *)r1)->n, ((RatExpr *)r2)->n);
+ else if( e->getop()==DIV )
+ mpq_div(q, ((RatExpr *)r1)->n, ((RatExpr *)r2)->n);
+ r1->dec();
+ r2->dec();
+ return new RatExpr(q);
+ }
+ else
+ {
+ //std::cout << "An arithmetic operation failed. " << r1->getclass() << " " << r2->getclass() << std::endl;
+ r1->dec();
+ r2->dec();
+ return NULL;
+ }
+ }
+ case NEG: {
+ Expr *r1 = run_code(e->kids[0]);
+ if (!r1)
+ return NULL;
+ if (r1->getclass() == INT_EXPR) {
+ mpz_t r;
+ mpz_init(r);
+ mpz_neg(r, ((IntExpr *)r1)->n);
+ r1->dec();
+ return new IntExpr(r);
+ }
+ else if( r1->getclass() == RAT_EXPR ) {
+ mpq_t q;
+ mpq_init(q);
+ mpq_neg(q, ((RatExpr *)r1)->n);
+ r1->dec();
+ return new RatExpr(q);
+ }
+ else
+ {
+ std::cout << "An arithmetic negation failed. " << r1->getclass() << std::endl;
+ //((SymSExpr*)r1)->val->print( std::cout );
+ std::cout << ((SymSExpr*)r1)->val << std::endl;
+ r1->dec();
+ return NULL;
+ }
+ }
+ case IFNEG:
+ case IFZERO:{
+ Expr *r1 = run_code(e->kids[0]);
+ if (!r1)
+ return NULL;
+
+ bool cond;
+ if( r1->getclass() == INT_EXPR ){
+ if( e->getop() == IFNEG )
+ cond = mpz_sgn( ((IntExpr *)r1)->n )<0;
+ else if( e->getop() == IFZERO )
+ cond = mpz_sgn( ((IntExpr *)r1)->n )==0;
+ }else if( r1->getclass() == RAT_EXPR ){
+ if( e->getop() == IFNEG )
+ cond = mpq_sgn( ((RatExpr *)r1)->n )<0;
+ else if( e->getop() == IFZERO )
+ cond = mpq_sgn( ((RatExpr *)r1)->n )==0;
+ }
+ else
+ {
+ std::cout << "An arithmetic if-expression failed. " << r1->getclass() << std::endl;
+ r1->dec();
+ return NULL;
+ }
+ r1->dec();
+
+
+ if( cond )
+ _e = e->kids[1];
+ else
+ _e = e->kids[2];
+ goto start_run_code;
+ }
+ case IFMARKED: {
+ Expr *r1 = run_code(e->kids[1]);
+ if (!r1)
+ return NULL;
+ if(r1->getclass() != SYM_EXPR && r1->getclass() != SYMS_EXPR ){
+ r1->dec();
+ return NULL;
+ }
+#ifndef MARKVAR_32
+ if (r1->getexmark()) {
+#else
+ if(((SymExpr*)r1)->getmark( ((IntExpr*)e->kids[0])->get_num() ) ){
+#endif
+ r1->dec();
+ _e = e->kids[2];
+ goto start_run_code;
+ }
+ // else
+ r1->dec();
+ _e = e->kids[3];
+ goto start_run_code;
+ }
+ case COMPARE:
+ {
+ Expr *r1 = run_code(e->kids[0]);
+ if (!r1)
+ return NULL;
+ if (r1->getclass() != SYM_EXPR && r1->getclass() != SYMS_EXPR) {
+ r1->dec();
+ return NULL;
+ }
+ Expr *r2 = run_code(e->kids[1]);
+ if (!r2)
+ return NULL;
+ if (r2->getclass() != SYM_EXPR && r2->getclass() != SYMS_EXPR) {
+ r2->dec();
+ return NULL;
+ }
+ if( r1<r2 ){
+ r1->dec();
+ _e = e->kids[2];
+ goto start_run_code;
+ }
+ //else
+ r2->dec();
+ _e = e->kids[3];
+ goto start_run_code;
+ }
+ case MARKVAR: {
+ Expr *r1 = run_code(e->kids[1]);
+ if (!r1)
+ return NULL;
+ if (r1->getclass() != SYM_EXPR && r1->getclass() != SYMS_EXPR) {
+ r1->dec();
+ return NULL;
+ }
+#ifndef MARKVAR_32
+ if (r1->getexmark())
+ r1->clearexmark();
+ else
+ r1->setexmark();
+#else
+ if(((SymExpr*)r1)->getmark( ((IntExpr*)e->kids[0])->get_num() ) )
+ ((SymExpr*)r1)->clearmark( ((IntExpr*)e->kids[0])->get_num() );
+ else
+ ((SymExpr*)r1)->setmark( ((IntExpr*)e->kids[0])->get_num() );
+#endif
+ return r1;
+ }
+ case MATCH: {
+ Expr *scrut = run_code(e->kids[0]);
+ if (!scrut)
+ return 0;
+ vector<Expr *> args;
+ Expr *hd = scrut->collect_args(args);
+ Expr **cases = &e->kids[1];
+ CExpr *c;
+ Expr *c_or_default;
+ while ((c_or_default = *cases++)) {
+
+ if (c_or_default->getop() != CASE){
+ //std::cout << "run the default " << std::endl;
+ //c_or_default->print( std::cout );
+ // this is the default of the MATCH
+ return run_code(c_or_default);
+ }
+
+ // this is a CASE of the MATCH
+ CExpr *c = (CExpr *)c_or_default;
+ Expr *p = c->kids[0];
+ if (hd == p->get_head()) {
+ vector<Expr *> vars;
+ p->collect_args(vars);
+ int jend = args.size();
+ vector<Expr *> old_vals(jend);
+ for (int j = 0; j < jend; j++) {
+ SymExpr *var = (SymExpr *)vars[j];
+ old_vals[j] = var->val;
+ var->val = args[j];
+ args[j]->inc();
+ }
+ scrut->dec();
+ Expr *ret = run_code(c->kids[1] /* the body of the case */);
+ for (int j = 0; j < jend; j++) {
+ ((SymExpr *)vars[j])->val = old_vals[j];
+ args[j]->dec();
+ }
+ return ret;
+ }
+ }
+ break;
+ }
+ case APP: {
+ Expr *tmp = e->whr();
+ if (e != tmp) {
+ _e = tmp;
+ goto start_run_code;
+ }
+
+ // e is in weak head normal form
+
+ vector<Expr *> args;
+ Expr *hd = e->collect_args(args);
+ for (int i = 0, iend = args.size(); i < iend; i++)
+ if (!(args[i] = run_code(args[i]))) {
+ for (int j = 0; j < i; j++)
+ args[j]->dec();
+ return NULL;
+ }
+ if (hd->getop() != PROG) {
+ hd->inc();
+ Expr *tmp = Expr::build_app(hd,args);
+ return tmp;
+ }
+
+ CExpr *prog = (CExpr *)hd;
+ Expr **cur = ((CExpr *)prog->kids[1])->kids;
+ vector<Expr *> old_vals;
+ SymExpr *var;
+ int i = 0;
+
+ if( run_scc && e->get_head( false )->getclass()==SYMS_EXPR )
+ {
+ //std::cout << "running " << ((SymSExpr*)e->get_head( false ))->s.c_str() << " with " << (int)args.size() << " arguments" << std::endl;
+//#ifndef USE_FLAT_APP
+// for( int a=0; a<(int)args.size(); a++ )
+// {
+// args[a] = CExpr::convert_to_flat_app( args[a] );
+// }
+//#endif
+ Expr *ret = run_compiled_scc( e->get_head( false ), args );
+ for (int i = 0, iend = args.size(); i < iend; i++) {
+ args[i]->dec();
+ }
+//#ifndef USE_FLAT_APP
+// ret = CExpr::convert_to_tree_app( ret );
+//#endif
+ //ret->inc();
+ return ret;
+ }
+ else
+ {
+ while((var = (SymExpr *)*cur++)) {
+ old_vals.push_back(var->val);
+ var->val = args[i++];
+ }
+
+ if (dbg_prog) {
+ dbg_prog_indent(cout);
+ cout << "[";
+ e->print(cout);
+ cout << "\n";
+ }
+ dbg_prog_indent_lvl++;
+
+ Expr *ret = run_code(prog->kids[2]);
+
+ dbg_prog_indent_lvl--;
+ if (dbg_prog) {
+ dbg_prog_indent(cout);
+ cout << "= ";
+ if (ret)
+ ret->print(cout);
+ else
+ cout << "fail";
+ cout << "]\n";
+ }
+
+ cur = ((CExpr *)prog->kids[1])->kids;
+ i = 0;
+ while((var = (SymExpr *)*cur++)) {
+ args[i]->dec();
+ var->val = old_vals[i++];
+ }
+ return ret;
+ }
+ }
+ } // end switch
+ return NULL;
+}
+
+int read_index()
+{
+ int index = 1;
+ string v;
+ char c;
+ while (isdigit(c = our_getc()))
+ v.push_back(c);
+ our_ungetc(c);
+ if( v.length()>0 )
+ {
+ index = atoi( v.c_str() );
+ }
+ return index;
+} \ No newline at end of file
diff --git a/proofs/lfsc_checker/code.h b/proofs/lfsc_checker/code.h
new file mode 100644
index 000000000..9d00a6378
--- /dev/null
+++ b/proofs/lfsc_checker/code.h
@@ -0,0 +1,15 @@
+#ifndef SC2_CODE_H
+#define SC2_CODE_H
+
+#include "expr.h"
+
+Expr *read_code();
+Expr *check_code(Expr *); // compute the type for the given code
+Expr *run_code(Expr *);
+
+int read_index();
+
+extern bool dbg_prog;
+extern bool run_scc;
+
+#endif
diff --git a/proofs/lfsc_checker/configure.ac b/proofs/lfsc_checker/configure.ac
new file mode 100644
index 000000000..5f4353664
--- /dev/null
+++ b/proofs/lfsc_checker/configure.ac
@@ -0,0 +1,47 @@
+# -*- Autoconf -*-
+# Process this file with autoconf to produce a configure script.
+
+AC_PREREQ([2.61])
+AC_INIT([lfsc-checker], [1.0], [cvc-bugs@cs.nyu.edu])
+AC_CONFIG_SRCDIR([libwriter.h])
+AC_CONFIG_AUX_DIR([config])
+AC_CONFIG_MACRO_DIR([config])
+AC_CONFIG_HEADERS([config.h])
+AM_INIT_AUTOMAKE([1.11 foreign no-define tar-pax])
+LT_INIT
+
+AC_CANONICAL_BUILD
+AC_CANONICAL_HOST
+AC_CANONICAL_TARGET
+
+m4_ifdef([AM_SILENT_RULES],[AM_SILENT_RULES([yes])])
+
+# on by default
+AM_MAINTAINER_MODE([enable])
+
+# turn off static lib building by default
+AC_ENABLE_SHARED
+AC_DISABLE_STATIC
+
+# Checks for programs.
+AC_PROG_CXX
+AC_PROG_CC
+
+# Checks for libraries.
+# FIXME: Replace `main' with a function in `-lgmp':
+AC_CHECK_LIB([gmp], [__gmpz_init])
+
+# Checks for header files.
+AC_CHECK_HEADERS([stdlib.h string.h])
+
+# Checks for typedefs, structures, and compiler characteristics.
+AC_HEADER_STDBOOL
+AC_C_INLINE
+AC_TYPE_SIZE_T
+
+# Checks for library functions.
+AC_FUNC_MALLOC
+AC_CHECK_FUNCS([strdup])
+
+AC_CONFIG_FILES([Makefile])
+AC_OUTPUT
diff --git a/proofs/lfsc_checker/expr.cpp b/proofs/lfsc_checker/expr.cpp
new file mode 100644
index 000000000..7ffc6469a
--- /dev/null
+++ b/proofs/lfsc_checker/expr.cpp
@@ -0,0 +1,966 @@
+#include "expr.h"
+#include <stdlib.h>
+#include <sstream>
+#ifdef _MSC_VER
+#include <algorithm>
+#endif
+#include "check.h"
+
+using namespace std;
+
+int HoleExpr::next_id = 0;
+int Expr::markedCount = 0;
+
+C_MACROS__ADD_CHUNKING_MEMORY_MANAGEMENT_CC(CExpr,kids,32768);
+
+//C_MACROS__ADD_CHUNKING_MEMORY_MANAGEMENT_CC(IntCExpr,_n,32768);
+
+#define USE_HOLE_PATH_COMPRESSION
+
+void Expr::debug() {
+ print(cout);
+ /*
+ cout << "\nAt " << this << "\n";
+ cout << "marked = " << getmark() << "\n";
+ */
+ cout << "\n";
+ cout.flush();
+}
+
+bool destroy_progs = false;
+
+#define destroydec(rr) \
+ do { \
+ Expr *r = rr; \
+ int ref = r->data >> 9; \
+ ref = ref - 1; \
+ r->debugrefcnt(ref,DEC); \
+ if (ref == 0) { \
+ _e = r; \
+ goto start_destroy; \
+ } \
+ else \
+ r->data = (ref << 9) | (r->data & 511); \
+ } while(0)
+
+
+void Expr::destroy(Expr *_e, bool dec_kids) {
+ start_destroy:
+ switch (_e->getclass()) {
+ case INT_EXPR:
+ delete (IntExpr *)_e;
+ break;
+ case SYMS_EXPR: {
+ SymSExpr *e = (SymSExpr *)_e;
+ if (e->val && e->val->getop() != PROG) {
+ Expr *tmp = e->val;
+ delete e;
+ destroydec(tmp);
+ }
+ else
+ delete e;
+ break;
+ }
+ case SYM_EXPR: {
+ SymExpr *e = (SymExpr *)_e;
+ if (e->val && e->val->getop() != PROG) {
+ Expr *tmp = e->val;
+ delete e;
+ destroydec(tmp);
+ }
+ else
+ delete e;
+ break;
+ }
+ case HOLE_EXPR: {
+ HoleExpr *e = (HoleExpr *)_e;
+ if (e->val) {
+ Expr *tmp = e->val;
+ delete e;
+ destroydec(tmp);
+ }
+ else
+ delete e;
+ break;
+ }
+ case CEXPR: {
+ CExpr *e = (CExpr *)_e;
+ if (dec_kids) {
+ Expr **cur = e->kids;
+ Expr *tmp;
+ while((tmp = *cur++)) {
+ if (*cur)
+ tmp->dec();
+ else {
+ delete e;
+ destroydec(tmp);
+ break;
+ }
+ }
+ }
+ else
+ delete e;
+ break;
+ }
+ }
+}
+
+Expr *Expr::clone() {
+ switch (getclass()) {
+ case INT_EXPR:
+ case RAT_EXPR:
+ inc();
+ return this;
+ case SYMS_EXPR:
+ case SYM_EXPR: {
+ SymExpr *e = (SymExpr *)this;
+ if (e->val)
+ if (e->val->getop() != PROG)
+ return e->val->clone();
+ e->inc();
+ return e;
+ }
+ case HOLE_EXPR: {
+ HoleExpr *e = (HoleExpr *)this;
+ if (e->val)
+ return e->val->clone();
+ e->inc();
+ return e;
+ }
+ case CEXPR: {
+ CExpr *e = (CExpr *)this;
+ int op = e->getop();
+ switch(op) {
+ case LAM: {
+#ifdef DEBUG_SYM_NAMES
+ SymSExpr *var = (SymSExpr *)e->kids[0];
+ SymSExpr *newvar = new SymSExpr(*var,SYMS_EXPR);
+#else
+ SymExpr *var = (SymExpr *)e->kids[0];
+ SymExpr *newvar = new SymExpr(*var);
+#endif
+ Expr *prev = var->val;
+ var->val = newvar;
+ Expr *bod = e->kids[1]->clone();
+ var->val = prev;
+ return new CExpr(LAM,newvar,bod);
+ }
+ case PI: {
+#ifdef DEBUG_SYM_NAMES
+ SymSExpr *var = (SymSExpr *)e->kids[0];
+ SymSExpr *newvar = new SymSExpr(*var,SYMS_EXPR);
+#else
+ SymExpr *var = (SymExpr *)e->kids[0];
+ SymExpr *newvar = new SymExpr(*var);
+#endif
+ Expr *tp = e->kids[1]->clone();
+ Expr *prev = var->val;
+ var->val = newvar;
+ Expr *bod = e->kids[2]->clone();
+ var->val = prev;
+ Expr* ret = new CExpr(PI,newvar,tp,bod);
+ if( data&256 )
+ ret->data |=256;
+ return ret;
+ }
+ default: {
+ Expr **cur = e->kids;
+ Expr *tmp;
+ int size = 0;
+ while((*cur++))
+ size++;
+ Expr **kids = new Expr*[size+1];
+ kids[size]=0;
+ cur = e->kids;
+ bool diff_kid = false;
+ int i = 0;
+ while((tmp = *cur++)) {
+ Expr *c = tmp->clone();
+ diff_kid |= (c != tmp);
+ kids[i++] = c;
+ }
+ if (diff_kid)
+ return new CExpr(op, true /* dummy */, kids);
+ for (int i = 0, iend = size; i != iend; i++)
+ kids[i]->dec();
+ delete[] kids;
+ e->inc();
+ return e;
+ }
+ }
+ }
+ }
+ return 0; // should never be reached
+}
+
+
+Expr* Expr::build_app(Expr *hd, const std::vector<Expr *> &args, int start) {
+#ifndef USE_FLAT_APP
+ Expr *ret = hd;
+ for (int i = start, iend = args.size(); i < iend; i++)
+ ret = new CExpr(APP,ret,args[i]);
+ return ret;
+#else
+ if( start>=(int)args.size() )
+ return hd;
+ else
+ {
+ CExpr *ret = new CExpr( APP );
+ ret->kids = new Expr* [args.size()-start+2];
+ ret->kids[0] = hd;
+ for (int i = start, iend = args.size(); i < iend; i++)
+ ret->kids[i-start+1] = args[i];
+ ret->kids[args.size()-start+1] = NULL;
+ return ret;
+ }
+#endif
+}
+
+Expr* Expr::make_app(Expr* e1, Expr* e2 )
+{
+ //std::cout << "make app from ";
+ //e1->print( std::cout );
+ //std::cout << " ";
+ //e2->print( std::cout );
+ //std::cout << std::endl;
+ CExpr *ret;
+ if( e1->getclass()==CEXPR ){
+ int counter = 0;
+ while( ((CExpr*)e1)->kids[counter] ){
+ counter++;
+ }
+ ret = new CExpr( APP );
+ ret->kids = new Expr* [counter+2];
+ counter = 0;
+ while( ((CExpr*)e1)->kids[counter] ){
+ ret->kids[counter] = ((CExpr*)e1)->kids[counter];
+ counter++;
+ }
+ ret->kids[counter] = e2;
+ ret->kids[counter+1] = NULL;
+ }else{
+ ret = new CExpr( APP, e1, e2 );
+ }
+ //ret->print( std::cout );
+ //std::cout << std::endl;
+ return ret;
+}
+
+int Expr::cargCount = 0;
+
+Expr *Expr::collect_args(std::vector<Expr *> &args, bool follow_defs) {
+ //cargCount++;
+ //if( cargCount%1000==0)
+ //std::cout << cargCount << std::endl;
+#ifndef USE_FLAT_APP
+ CExpr *e = (CExpr *)this;
+ args.reserve(16);
+ while( e->getop() == APP ) {
+ args.push_back(e->kids[1]);
+ e = (CExpr *)e->kids[0];
+ if (follow_defs)
+ e = (CExpr *)e->followDefs();
+ }
+ std::reverse(args.begin(),args.end());
+ return e;
+#else
+ CExpr *e = (CExpr *)this;
+ args.reserve(16);
+ if( e->getop()==APP ){
+ int counter = 1;
+ while( e->kids[counter] ) {
+ args.push_back(e->kids[counter]);
+ counter++;
+ }
+ e = (CExpr*)e->kids[0];
+ }
+ if (follow_defs)
+ return e->followDefs();
+ else
+ return e;
+#endif
+}
+
+Expr *Expr::get_head(bool follow_defs) {
+ CExpr *e = (CExpr *)this;
+ while( e->getop() == APP ) {
+ e = (CExpr *)e->kids[0];
+ if (follow_defs)
+ e = (CExpr *)e->followDefs();
+ }
+ return e;
+}
+
+Expr *Expr::get_body(int op, bool follow_defs) {
+ CExpr *e = (CExpr *)this;
+ while( e->getop() == op ) {
+ e = (CExpr *)e->kids[2];
+ if (follow_defs)
+ e = (CExpr *)e->followDefs();
+ }
+ return e;
+}
+
+// if the return value is different from this, then it is a new reference
+Expr *CExpr::whr() {
+ vector<Expr *> args;
+ if (get_head()->getop() == LAM) {
+ CExpr *head = (CExpr *)collect_args(args, true);
+ Expr *cloned_head;
+ if (head->cloned()) {
+ // we must clone
+ head = (CExpr *)head->clone();
+ cloned_head = head;
+ }
+ else {
+ head->setcloned();
+ cloned_head = 0;
+ }
+ int i = 0;
+ int iend = args.size();
+
+ /* we will end up incrementing the ref count for all the args,
+ since each is either pointed to by a var (following a
+ beta-reduction), or else just an argument in the new
+ application we build below. */
+
+ do {
+ Expr *tmp = args[i++]->followDefs();
+ ((SymExpr *)head->kids[0])->val = tmp;
+ tmp->inc();
+ head = (CExpr *)head->kids[1];
+ } while(head->getop() == LAM && i < iend);
+ for (; i < iend; i++)
+ args[i]->inc();
+ head->inc();
+ if (cloned_head)
+ cloned_head->dec();
+ return build_app(head,args,i);
+ }
+ else
+ return this;
+}
+
+Expr* CExpr::convert_to_tree_app( Expr* e )
+{
+ if( e->getop()==APP )
+ {
+ std::vector< Expr* > kds;
+ int counter = 1;
+ while( ((CExpr*)e)->kids[counter] )
+ {
+ kds.push_back( convert_to_tree_app( ((CExpr*)e)->kids[counter] ) );
+ counter++;
+ }
+ Expr* app = Expr::build_app( e->get_head(), kds );
+ //app->inc();
+ return app;
+ }
+ else
+ {
+ return e;
+ }
+}
+
+Expr* CExpr::convert_to_flat_app( Expr* e )
+{
+ if( e->getop()==APP )
+ {
+ std::vector< Expr* > args;
+ Expr* hd = ((CExpr*)e)->collect_args( args );
+ CExpr* nce = new CExpr( APP );
+ nce->kids = new Expr *[(int)args.size()+2];
+ nce->kids[0] = hd;
+ for( int a=0; a<(int)args.size(); a++ )
+ {
+ nce->kids[a+1] = convert_to_flat_app( args[a] );
+ }
+ nce->kids[(int)args.size()+1] = 0;
+ nce->inc();
+ return nce;
+ }
+ else
+ {
+ return e;
+ }
+}
+
+bool Expr::defeq(Expr *e) {
+
+ /* we handle a few special cases up front, where this Expr might
+ equal e, even though they have different opclass (i.e., different
+ structure). */
+
+ if (this == e)
+ return true;
+ int op1 = getop();
+ int op2 = e->getop();
+ switch (op1) {
+ case ASCRIBE:
+ return ((CExpr *)this)->kids[0]->defeq(e);
+ case APP: {
+ Expr *tmp = ((CExpr *)this)->whr();
+ if (tmp != this) {
+ bool b = tmp->defeq(e);
+ tmp->dec();
+ return b;
+ }
+ if (get_head()->getclass() == HOLE_EXPR) {
+ vector<Expr *> args;
+ Expr *head = collect_args(args, true);
+ Expr *t = e;
+ t->inc();
+ for (int i = 0, iend = args.size(); i < iend; i++) {
+ // don't worry about SYMS_EXPR's, since we should not be in code here.
+ if (args[i]->getclass() != SYM_EXPR || args[i]->getexmark())
+ /* we cannot fill the hole in this case. Either this is not
+ a variable or we are using a variable again. */
+ return false;
+ SymExpr *v = (SymExpr *)args[i];
+
+ // we may have been mapping from expected var v to a computed var
+ Expr *tmp = (v->val ? v->val : v);
+
+ tmp->inc();
+ t = new CExpr(LAM, tmp, t);
+ args[i]->setexmark();
+ }
+ for (int i = 0, iend = args.size(); i < iend; i++)
+ args[i]->clearexmark();
+#ifdef DEBUG_HOLES
+ cout << "Filling hole ";
+ head->debug();
+ cout << "with ";
+ t->debug();
+#endif
+ ((HoleExpr *)head)->val = t;
+ return true;
+ }
+ break;
+ }
+ case NOT_CEXPR:
+ switch (getclass()) {
+ case HOLE_EXPR: {
+ HoleExpr *h = (HoleExpr *)this;
+ if (h->val)
+ return h->val->defeq(e);
+#ifdef DEBUG_HOLES
+ cout << "Filling hole ";
+ h->debug();
+ cout << "with ";
+ e->debug();
+#endif
+#ifdef USE_HOLE_PATH_COMPRESSION
+ Expr *tmp = e->followDefs();
+#else
+ Expr *tmp = e;
+#endif
+ h->val = tmp;
+ tmp->inc();
+ return true;
+ }
+ case SYMS_EXPR:
+ case SYM_EXPR: {
+ SymExpr *s = (SymExpr *)this;
+ if (s->val)
+ return s->val->defeq(e);
+ break;
+ }
+ }
+ break;
+ }
+
+ switch (op2) {
+ case ASCRIBE:
+ return defeq(((CExpr *)e)->kids[0]);
+ case APP: {
+ Expr *tmp = ((CExpr *)e)->whr();
+ if (tmp != e) {
+ bool b = defeq(tmp);
+ tmp->dec();
+ return b;
+ }
+ break;
+ }
+ case NOT_CEXPR:
+ switch (e->getclass()) {
+ case HOLE_EXPR: {
+ HoleExpr *h = (HoleExpr *)e;
+ if (h->val)
+ return defeq(h->val);
+
+#ifdef DEBUG_HOLES
+ cout << "Filling hole ";
+ h->debug();
+ cout << "with ";
+ debug();
+#endif
+#ifdef USE_HOLE_PATH_COMPRESSION
+ Expr *tmp = followDefs();
+#else
+ Expr *tmp = this;
+#endif
+ h->val = tmp;
+ tmp->inc();
+ return true;
+ }
+ case SYMS_EXPR:
+ case SYM_EXPR: {
+ SymExpr *s = (SymExpr *)e;
+ if (s->val)
+ return defeq(s->val);
+ break;
+ }
+ }
+ break;
+ }
+
+ /* at this point, e1 and e2 must have the same opclass if they are
+ to be equal. */
+
+ if (op1 != op2)
+ return false;
+
+ if (op1 == NOT_CEXPR) {
+ switch(getclass()) {
+ case INT_EXPR: {
+ IntExpr *i1 = (IntExpr *)this;
+ IntExpr *i2 = (IntExpr *)e;
+ return (mpz_cmp(i1->n,i2->n) == 0);
+ }
+ case RAT_EXPR: {
+ RatExpr *r1 = (RatExpr *)this;
+ RatExpr *r2 = (RatExpr *)e;
+ return (mpq_cmp(r1->n,r2->n) == 0);
+ }
+ case SYMS_EXPR:
+ case SYM_EXPR:
+ return (this == e);
+ }
+ }
+
+ /* Now op1 and op2 must both be CExprs, and must have the same op to be
+ equal. */
+
+ CExpr *e1 = (CExpr *)this;
+ CExpr *e2 = (CExpr *)e;
+
+ int last = 1;
+ switch (op1) {
+ case PI:
+ if (!e1->kids[1]->defeq(e2->kids[1]))
+ return false;
+ last++;
+ // fall through to LAM case
+ case LAM: {
+
+ /* It is critical that we point e1's var. (v1) back to e2's (call
+ it v2). The reason this is critical is that we assume any
+ holes are in e1. So we could end up with (_ v1) = t. We wish
+ to fill _ in this case with (\ v2 t). If v2 pointed to v1, we
+ could not return (\ v1 t), because the fact that v2 points to
+ v1 would then be lost.
+ */
+ SymExpr *v1 = (SymExpr *)e1->kids[0];
+ Expr *prev_v1_val = v1->val;
+ v1->val = e2->kids[0]->followDefs();
+ bool bodies_equal = e1->kids[last]->defeq(e2->kids[last]);
+ v1->val = prev_v1_val;
+ return bodies_equal;
+ }
+ case APP:
+#ifndef USE_FLAT_APP
+ return (e1->kids[0]->defeq(e2->kids[0]) &&
+ e1->kids[1]->defeq(e2->kids[1]));
+#else
+ {
+ int counter = 0;
+ while( e1->kids[counter] ){
+ if( !e2->kids[counter] || !e1->kids[counter]->defeq( e2->kids[counter] ) )
+ return false;
+ counter++;
+ }
+ return e2->kids[counter]==NULL;
+ }
+#endif
+ case TYPE:
+ case KIND:
+ case MPZ:
+ // already checked that both exprs have the same opclass.
+ return true;
+ } // switch(op1)
+
+ return false; // never reached.
+}
+
+int Expr::fiCounter = 0;
+
+bool Expr::free_in(Expr *x) {
+ //fiCounter++;
+ //if( fiCounter%1==0 )
+ // std::cout << fiCounter << std::endl;
+ switch(getop()) {
+ case NOT_CEXPR:
+ switch (getclass()) {
+ case HOLE_EXPR: {
+ HoleExpr *h = (HoleExpr *)this;
+ if (h->val)
+ return h->val->free_in(x);
+ return (h == x);
+ }
+ case SYMS_EXPR:
+ case SYM_EXPR: {
+ SymExpr *s = (SymExpr *)this;
+ if (s->val && s->val->getclass() == HOLE_EXPR)
+ /* we do not need to follow the "val" pointer except in this
+ one case, when x is a hole (which we do not bother to check
+ here) */
+ return s->val->free_in(x);
+ return (s == x);
+ }
+ case INT_EXPR:
+ return false;
+ }
+ break;
+ case LAM:
+ case PI:
+ if (x == ((CExpr *)this)->kids[0])
+ return false;
+ // fall through
+ default: {
+ // must be a CExpr
+ CExpr *e = (CExpr *)this;
+ Expr *tmp;
+ Expr **cur = e->kids;
+ while ((tmp = *cur++))
+ if (tmp->free_in(x))
+ return true;
+ return false;
+ }
+ }
+ return false; // should not be reached
+}
+
+void Expr::calc_free_in(){
+ data &= ~256;
+ data |= 256*((CExpr *)this)->kids[2]->free_in( ((CExpr *)this)->kids[0] );
+}
+
+string Expr::toString() {
+ ostringstream oss;
+ print(oss);
+ return oss.str();
+}
+
+static void print_kids(ostream &os, Expr **kids) {
+ Expr *tmp;
+ while ((tmp = *kids++)) {
+ os << " ";
+ tmp->print(os);
+ }
+}
+
+static void print_vector(ostream &os, const vector<Expr *> &v) {
+ for(int i = 0, iend = v.size(); i < iend; i++) {
+ os << " ";
+ v[i]->print(os);
+ }
+}
+
+void Expr::print(ostream &os) {
+ CExpr *e = (CExpr *)this; // for CEXPR cases
+
+ //std::cout << e->getop() << " ";
+ /*
+#ifdef DEBUG_REFCNT
+ os << "<";
+ char tmp[10];
+ sprintf(tmp,"%d",getrefcnt());
+ os << tmp << "> ";
+#endif
+*/
+
+ switch(getop()) {
+ case NOT_CEXPR: {
+ switch(getclass()) {
+ case INT_EXPR:
+ {
+ IntExpr *e = (IntExpr *)this;
+ if (mpz_sgn(e->n) < 0) {
+ os << "(~ ";
+ mpz_t tmp;
+ mpz_init(tmp);
+ mpz_neg(tmp,e->n);
+ char *s = mpz_get_str(0,10,tmp);
+ os << s;
+ free(s);
+ mpz_clear(tmp);
+ os << ")";
+ //os << "mpz";
+ }
+ else {
+ char *s = mpz_get_str(0,10,e->n);
+ os << s;
+ free(s);
+ //os << "mpz";
+ }
+ break;
+ }
+ case RAT_EXPR:
+ {
+ RatExpr *e = (RatExpr *)this;
+ char *s = mpq_get_str(0,10,e->n);
+ os << s;
+ if (mpq_sgn(e->n) < 0) {
+ os << "(~ ";
+ mpq_t tmp;
+ mpq_init(tmp);
+ mpq_neg(tmp,e->n);
+ char *s = mpq_get_str(0,10,tmp);
+ os << s;
+ free(s);
+ mpq_clear(tmp);
+ os << ")";
+ }
+ else {
+ char *s = mpq_get_str(0,10,e->n);
+ os << s;
+ free(s);
+ }
+ break;
+ }
+#ifndef DEBUG_SYM_NAMES
+ case SYM_EXPR:
+ {
+ SymExpr *e = (SymExpr *)this;
+ if (e->val) {
+ if (e->val->getop() == PROG) {
+ os << e;
+#ifdef DEBUG_SYMS
+ os << "[PROG]";
+#endif
+ }else{
+#ifdef DEBUG_SYMS
+ os << e;
+ os << "[SYM ";
+#endif
+ e->val->print(os);
+#ifdef DEBUG_SYMS
+ os << "]";
+#endif
+ }
+ }
+ else
+ os << e;
+ break;
+ }
+#else
+ case SYM_EXPR: /* if we are debugging sym names, then
+ SYM_EXPRs are really SymSExprs. */
+#endif
+ case SYMS_EXPR: {
+ SymSExpr *e = (SymSExpr *)this;
+ if (e->val) {
+ if (e->val->getop() == PROG) {
+ os << e->s;
+#ifdef DEBUG_SYMS
+ os << "[PROG]";
+#endif
+ }else{
+#ifdef DEBUG_SYMS
+ os << e->s;
+ os << "[SYM ";
+#endif
+ e->val->print(os);
+#ifdef DEBUG_SYMS
+ os << "]";
+#endif
+ }
+ }
+ else
+ os << e->s;
+ break;
+ }
+ case HOLE_EXPR:
+ {
+ HoleExpr *e = (HoleExpr *)this;
+ if (e->val) {
+#ifdef DEBUG_SYMS
+ os << "_" << "[HOLE ";
+#endif
+ e->val->print(os);
+#ifdef DEBUG_SYMS
+ os << "]";
+#endif
+ }else {
+ os << "_";
+#ifdef DEBUG_HOLE_NAMES
+ char tmp[100];
+ sprintf(tmp,"%d",e->id);
+ os << "[ " << tmp << "]";
+#else
+ os << "[ " << e << "]";
+#endif
+ }
+ break;
+ }
+ default:
+ os << "; unrecognized form of expr";
+ break;
+ }
+ break;
+ } // case NOT_CEXPR
+ case APP: {
+ os << "(";
+ vector<Expr *> args;
+ Expr *head = collect_args(args, false /* follow_defs */);
+ head->print(os);
+ print_vector(os, args);
+ os << ")";
+ break;
+ }
+ case LAM:
+ os << "(\\";
+ print_kids(os, e->kids);
+ os << ")";
+ break;
+ case PI:
+ os << "(!";
+ print_kids(os, e->kids);
+ os << ")";
+ break;
+ case TYPE:
+ os << "type";
+ break;
+ case KIND:
+ os << "kind";
+ break;
+ case MPZ:
+ os << "mpz";
+ break;
+ case MPQ:
+ os << "mpq";
+ break;
+ case ADD:
+ os << "(mp_add";
+ print_kids(os,e->kids);
+ os << ")";
+ break;
+ case MUL:
+ os << "(mp_mul";
+ print_kids(os,e->kids);
+ os << ")";
+ break;
+ case DIV:
+ os << "(mp_div";
+ print_kids(os,e->kids);
+ os << ")";
+ break;
+ case NEG:
+ os << "(mp_neg";
+ print_kids(os,e->kids);
+ os << ")";
+ break;
+ case IFNEG:
+ os << "(ifneg";
+ print_kids(os,e->kids);
+ os << ")";
+ break;
+ case IFZERO:
+ os << "(ifzero";
+ print_kids(os,e->kids);
+ os << ")";
+ break;
+ case RUN:
+ os << "(run";
+ print_kids(os,e->kids);
+ os << ")";
+ break;
+ case PROG:
+ os << "(prog";
+ print_kids(os,e->kids);
+ os << ")";
+ break;
+ case PROGVARS:
+ os << "(";
+ print_kids(os,e->kids);
+ os << ")";
+ break;
+ case MATCH:
+ os << "(match";
+ print_kids(os,e->kids);
+ os << ")";
+ break;
+ case CASE:
+ os << "(";
+ print_kids(os,e->kids);
+ os << ")";
+ break;
+ case LET:
+ os << "(let";
+ print_kids(os,e->kids);
+ os << ")";
+ break;
+ case DO:
+ os << "(do";
+ print_kids(os,e->kids);
+ os << ")";
+ break;
+ case IFMARKED:
+ os << "(ifmarked";
+ print_kids(os,e->kids);
+ os << ")";
+ break;
+ case COMPARE:
+ os << "(compare";
+ print_kids(os,e->kids);
+ os << ")";
+ break;
+ case MARKVAR:
+ os << "(markvar";
+ print_kids(os,e->kids);
+ os << ")";
+ break;
+ case FAIL:
+ os << "(fail ";
+ print_kids(os, e->kids);
+ os << ")";
+ break;
+ case ASCRIBE:
+ os << "(:";
+ print_kids(os, e->kids);
+ os << ")";
+ break;
+ default:
+ os << "; unrecognized form of expr(2) " << getop() << " " << getclass();
+ } // switch(getop())
+}
+
+bool Expr::isType( Expr* statType ){
+ Expr* typ = this;
+ while( typ!=statType ){
+ if( typ->getop()==PI ){
+ typ = ((CExpr*)typ)->kids[2];
+ }else{
+ return false;
+ }
+ }
+ return true;
+}
+
+int SymExpr::symmCount = 0;
+#ifdef MARKVAR_32
+int SymExpr::mark()
+{
+ if( mark_map.find( this )== mark_map.end() )
+ {
+ symmCount++;
+ mark_map[this] = 0;
+ }
+ return mark_map[this];
+}
+void SymExpr::smark( int m )
+{
+ mark_map[this] = m;
+}
+#endif \ No newline at end of file
diff --git a/proofs/lfsc_checker/expr.h b/proofs/lfsc_checker/expr.h
new file mode 100644
index 000000000..32a62ab33
--- /dev/null
+++ b/proofs/lfsc_checker/expr.h
@@ -0,0 +1,367 @@
+#ifndef sc2__expr_h
+#define sc2__expr_h
+
+#include "gmp.h"
+#include <string>
+#include <vector>
+#include <iostream>
+#include <map>
+#include "chunking_memory_management.h"
+
+#define USE_FLAT_APP
+#define MARKVAR_32
+#define DEBUG_SYM_NAMES
+//#define DEBUG_SYMS
+
+// Expr class
+enum { CEXPR = 0,
+ INT_EXPR,
+ RAT_EXPR,
+ HOLE_EXPR,
+ SYM_EXPR,
+ SYMS_EXPR };
+
+// operators for CExprs
+enum { NOT_CEXPR = 0, // for INT_EXPR, HOLE_EXPR, SYM_EXPR, SYMS_EXPR
+ APP,
+ PI,
+ LAM,
+ TYPE,
+ KIND,
+ ASCRIBE,
+ MPZ,
+ MPQ,
+
+ PROG,
+ PROGVARS,
+ MATCH,
+ CASE,
+ PAT,
+ DO,
+ ADD,
+ MUL,
+ DIV,
+ NEG,
+ IFNEG,
+ IFZERO,
+ LET,
+ RUN,
+ FAIL,
+ MARKVAR,
+ IFMARKED,
+ COMPARE
+};
+
+class SymExpr;
+
+class Expr {
+protected:
+ /* bits 0-2: Expr class
+ bits 3-7: operator
+ bit 8: a flag for already cloned, free_in calculation
+ bits 9-31: ref count*/
+ int data;
+
+ void destroy(bool dec_kids);
+
+ enum { INC, DEC, CREATE };
+ void debugrefcnt(int ref, int what) {
+#ifdef DEBUG_REFCNT
+ std::cout << "[";
+ debug();
+ switch(what) {
+ case INC:
+ std::cout << " inc to ";
+ break;
+ case DEC:
+ std::cout << " dec to ";
+ break;
+ case CREATE:
+ std::cout << " creating]\n";
+ return;
+ }
+ char tmp[10];
+ sprintf(tmp,"%d",ref);
+ std::cout << tmp << "]\n";
+#else
+ (void)ref;
+ (void)what;
+#endif
+ }
+
+ Expr(int _class, int _op)
+ : data(1 << 9 /* refcount 1, not cloned */| (_op << 3) | _class)
+ { }
+
+public:
+ static int markedCount;
+ inline Expr* followDefs();
+ inline int getclass() const { return data & 7; }
+ int getexmark() const { return data & 256; }
+ void setexmark() { data |= 256; }
+ void clearexmark() { data &= ~256; }
+ inline int getop() const { return (data >> 3) & 31; }
+ int cloned() const { return data & 256; }
+ void setcloned() { data |= 256; }
+
+ inline int getrefcnt() { return data >> 9; }
+ inline void inc() {
+ int ref = getrefcnt();
+ //static int iCounter = 0;
+ //iCounter++;
+ //if( iCounter%10000==0 ){
+ // //print( std::cout );
+ // std::cout << " " << ref << std::endl;
+ //}
+ ref = ref<4194303 ? ref + 1 : ref;
+ debugrefcnt(ref,INC);
+ data = (ref << 9) | (data & 511);
+ }
+ static void destroy(Expr *, bool);
+ inline void dec(bool dec_kids = true) {
+ int ref = getrefcnt();
+ ref = ref - 1;
+ debugrefcnt(ref,DEC);
+ if (ref == 0)
+ destroy(this,dec_kids);
+ else
+ data = (ref << 9) | (data & 511);
+ }
+
+ //must pass statType (the expr representing "type") to this function
+ bool isType( Expr* statType );
+
+ inline bool isDatatype() {
+ return getclass() == SYMS_EXPR || getop() == MPZ || getop() == MPQ;
+ }
+ inline bool isArithTerm() {
+ return getop() == ADD || getop() == NEG;
+ }
+
+ static Expr *build_app(Expr *hd, const std::vector<Expr *> &args,
+ int start = 0);
+
+ static Expr *make_app(Expr* e1, Expr* e2 );
+
+ /* if this is an APP, return the head, and store the args in args.
+ If follow_defs is true, we proceed through defined heads;
+ otherwise not. */
+ Expr *collect_args(std::vector<Expr *> &args, bool follow_defs = true);
+
+ Expr *get_head(bool follow_defs = true);
+
+ Expr *get_body(int op = PI, bool follow_defs = true);
+
+ std::string toString();
+
+ void print(std::ostream &);
+ void debug();
+
+ /* check whether or not this expr is alpha equivalent to e. If this
+ expr contains unfilled holes, fill them as we go. We do not fill
+ holes in e. We do not take responsibility for the reference to
+ this nor the reference to e. */
+ bool defeq(Expr *e);
+
+ /* return a clone of this expr. All abstractions are really duplicated
+ in memory. Other expressions may not actually be duplicated in
+ memory, but their refcounts will be incremented. */
+ Expr *clone();
+
+ // x can be a SymExpr or a HoleExpr.
+ bool free_in(Expr *x);
+ bool get_free_in() { return data & 256; }
+ void calc_free_in();
+
+ static int cargCount;
+ static int fiCounter;
+};
+
+class CExpr : public Expr {
+public:
+ C_MACROS__ADD_CHUNKING_MEMORY_MANAGEMENT_H(CExpr,kids);
+
+ Expr **kids;
+ ~CExpr() {
+ delete[] kids;
+ }
+ CExpr(int _op) : Expr(CEXPR, _op), kids() {
+ kids = new Expr *[1];
+ kids[0] = 0;
+ debugrefcnt(1,CREATE);
+ }
+ CExpr(int _op, Expr *e1) : Expr(CEXPR, _op), kids() {
+ kids = new Expr *[2];
+ kids[0] = e1;
+ kids[1] = 0;
+ debugrefcnt(1,CREATE);
+ }
+ CExpr(int _op, Expr *e1, Expr *e2)
+ : Expr(CEXPR, _op), kids() {
+ kids = new Expr *[3];
+ kids[0] = e1;
+ kids[1] = e2;
+ kids[2] = 0;
+ debugrefcnt(1,CREATE);
+ }
+ CExpr(int _op, Expr *e1, Expr *e2, Expr *e3)
+ : Expr(CEXPR, _op), kids() {
+ kids = new Expr *[4];
+ kids[0] = e1;
+ kids[1] = e2;
+ kids[2] = e3;
+ kids[3] = 0;
+ debugrefcnt(1,CREATE);
+ }
+ CExpr(int _op, Expr *e1, Expr *e2, Expr *e3, Expr *e4)
+ : Expr(CEXPR, _op), kids() {
+ kids = new Expr *[5];
+ kids[0] = e1;
+ kids[1] = e2;
+ kids[2] = e3;
+ kids[3] = e4;
+ kids[4] = 0;
+ debugrefcnt(1,CREATE);
+ }
+ CExpr(int _op, const std::vector<Expr *> &_kids)
+ : Expr(CEXPR, _op), kids() {
+ int i, iend = _kids.size();
+ kids = new Expr *[iend + 1];
+ for (i = 0; i < iend; i++)
+ kids[i] = _kids[i];
+ kids[i] = 0;
+ debugrefcnt(1,CREATE);
+ }
+
+ // _kids must be null-terminated.
+ CExpr(int _op, bool dummy, Expr **_kids) : Expr(CEXPR, _op), kids(_kids) {
+ (void)dummy;
+ debugrefcnt(1,CREATE);
+ }
+
+ Expr *whr();
+
+ static Expr* convert_to_tree_app( Expr* ce );
+ static Expr* convert_to_flat_app( Expr* ce );
+};
+
+class IntExpr : public Expr {
+ public:
+ mpz_t n;
+ ~IntExpr() {
+ mpz_clear(n);
+ }
+ IntExpr(mpz_t _n) : Expr(INT_EXPR, 0), n() {
+ mpz_init_set(n,_n);
+ debugrefcnt(1,CREATE);
+ }
+ IntExpr(signed long int _n ) : Expr(INT_EXPR, 0), n() {
+ mpz_init_set_si( n, _n );
+ }
+
+ unsigned long int get_num() { return mpz_get_ui( n ); }
+};
+
+class RatExpr : public Expr {
+ public:
+ mpq_t n;
+ ~RatExpr() {
+ mpq_clear(n);
+ }
+ RatExpr(mpq_t _n) : Expr(RAT_EXPR, 0), n() {
+ mpq_init( n );
+ mpq_set(n,_n);
+ debugrefcnt(1,CREATE);
+ mpq_canonicalize( n );
+ }
+ RatExpr(signed long int _n1, unsigned long int _n2 ) : Expr(RAT_EXPR, 0), n() {
+ mpq_init( n );
+ mpq_set_si( n, _n1, _n2 );
+ mpq_canonicalize( n );
+ }
+};
+
+class SymExpr : public Expr {
+ public:
+ Expr *val; // may be set by beta-reduction and clone().
+ static int symmCount;
+
+ SymExpr(std::string _s, int theclass = SYM_EXPR)
+ : Expr(theclass, 0), val(0)
+ {
+ (void)_s;
+ if (theclass == SYM_EXPR)
+ debugrefcnt(1,CREATE);
+ }
+ SymExpr(const SymExpr &e, int theclass = SYM_EXPR)
+ : Expr(theclass, 0), val(0)
+ {
+ (void)e;
+ if (theclass == SYM_EXPR)
+ debugrefcnt(1,CREATE);
+ }
+#ifdef MARKVAR_32
+private:
+ int mark();
+ void smark( int m );
+public:
+ int getmark( int i = 0 ) { return (mark() >> i)&1; }
+ void setmark( int i = 0 ) { smark( mark() | (1 << i) ); }
+ void clearmark( int i = 0 ) { smark( mark() & ~(1 << i) ); }
+#endif
+};
+
+class SymSExpr : public SymExpr {
+ public:
+ std::string s;
+ SymSExpr(std::string _s, int theclass = SYMS_EXPR)
+ : SymExpr(_s, theclass), s(_s)
+ {
+ debugrefcnt(1,CREATE);
+ }
+ SymSExpr(const SymSExpr &e, int theclass = SYMS_EXPR)
+ : SymExpr(e, theclass), s(e.s)
+ {
+ debugrefcnt(1,CREATE);
+ }
+};
+
+class HoleExpr : public Expr {
+ static int next_id;
+public:
+#ifdef DEBUG_HOLE_NAMES
+ int id;
+#endif
+ HoleExpr()
+ : Expr(HOLE_EXPR, 0), val(0)
+ {
+#ifdef DEBUG_HOLE_NAMES
+ id = next_id++;
+#endif
+ debugrefcnt(1,CREATE);
+ }
+ Expr *val; // may be set during subst(), defeq(), and clone().
+};
+
+inline Expr * Expr::followDefs() {
+ switch(getclass()) {
+ case HOLE_EXPR: {
+ HoleExpr *h = (HoleExpr *)this;
+ if (h->val)
+ return h->val->followDefs();
+ break;
+ }
+ case SYMS_EXPR:
+ case SYM_EXPR: {
+ SymExpr *h = (SymExpr *)this;
+ if (h->val)
+ return h->val->followDefs();
+ break;
+ }
+ }
+
+ return this;
+}
+
+#endif
+
diff --git a/proofs/lfsc_checker/libwriter.cpp b/proofs/lfsc_checker/libwriter.cpp
new file mode 100644
index 000000000..49e9bbaad
--- /dev/null
+++ b/proofs/lfsc_checker/libwriter.cpp
@@ -0,0 +1,238 @@
+#include "libwriter.h"
+#include <sstream>
+#include <algorithm>
+#include <fstream>
+
+void libwriter::get_var_name( const std::string& n, std::string& nn ) {
+ nn = std::string( n.c_str() );
+ for( int i = 0; i <(int)n.length(); i++ ){
+ char c = n[i];
+ if (c <= 47)
+ c += 65;
+ else if (c >= 58 && c <= 64)
+ c += 97-58;
+ if ((c >= 91 && c <= 94) || c == 96)
+ c += 104-91;
+ else if (c >= 123)
+ c -= 4;
+ nn[i] = c;
+ }
+}
+
+void libwriter::write_file()
+{
+ //std::cout << "write lib" << std::endl;
+ std::ostringstream os_enum;
+ std::ostringstream os_print;
+ std::ostringstream os_constructor_h;
+ std::ostringstream os_constructor_c;
+
+ for ( int a=0; a<(int)syms.size(); a++ ) {
+ //std::cout << "sym #" << (a+1) << ": ";
+ //std::cout << ((SymSExpr*)syms[a])->s.c_str() << std::endl;
+ //defs[a]->print( std::cout );
+ //std::cout << std::endl;
+
+ if( defs[a]->getclass()==CEXPR ){
+ //calculate which arguments are required for input
+ std::vector< Expr* > args;
+ std::vector< bool > argsNeed;
+ std::vector< Expr* > argTypes;
+ CExpr* c = ((CExpr*)defs[a]);
+ while( c->getop()==PI ){
+ //std::cout << c->kids[0] << std::endl;
+ if( ((CExpr*)c->kids[1])->getop()!=RUN ){
+ args.push_back( c->kids[0] );
+ argsNeed.push_back( true );
+ argTypes.push_back( c->kids[1] );
+ }
+ for( int b=0; b<(int)args.size(); b++ ){
+ if( argsNeed[b] ){
+ if( ((CExpr*)c->kids[1])->getop()==RUN ){
+ if( ((CExpr*)c->kids[1])->kids[1]->free_in( args[b] ) ){
+ argsNeed[b] = false;
+ }
+ }else{
+ if( c->kids[1]->free_in( args[b] ) ){
+ argsNeed[b] = false;
+ }
+ }
+ }
+ }
+ c = (CExpr*)(c->kids[2]);
+ }
+
+ //record if this declares a judgement
+ if( ((CExpr*)defs[a])->getop()==PI && c->getop()==TYPE ){
+ //std::cout << "This is a judgement" << std::endl;
+ judgements.push_back( syms[a] );
+ //record if this declares a proof rule
+ }else if( c->getclass()==CEXPR && std::find( judgements.begin(), judgements.end(), c->kids[0] )!=judgements.end() ){
+ std::cout << "Handle rule: " << ((SymSExpr*)syms[a])->s.c_str() << std::endl;
+ //std::cout << "These are required to input:" << std::endl;
+ //for( int b=0; b<(int)args.size(); b++ ){
+ // if( argsNeed[b] ){
+ // std::cout << ((SymSExpr*)args[b])->s.c_str() << std::endl;
+ // }
+ //}
+ os_enum << " rule_" << ((SymSExpr*)syms[a])->s.c_str() << "," << std::endl;
+
+ os_print << " case rule_" << ((SymSExpr*)syms[a])->s.c_str() << ": os << \"";
+ os_print << ((SymSExpr*)syms[a])->s.c_str() << "\";break;" << std::endl;
+
+ std::ostringstream os_args;
+ os_args << "(";
+ bool firstTime = true;
+ for( int b=0; b<(int)args.size(); b++ ){
+ if( argsNeed[b] ){
+ if( !firstTime )
+ os_args << ",";
+ std::string str;
+ get_var_name( ((SymSExpr*)args[b])->s, str );
+ os_args << " LFSCProof* " << str.c_str();
+ firstTime = false;
+ }
+ }
+ if( !firstTime ){
+ os_args << " ";
+ }
+ os_args << ")";
+
+ os_constructor_h << " static LFSCProof* make_" << ((SymSExpr*)syms[a])->s.c_str();
+ os_constructor_h << os_args.str().c_str() << ";" << std::endl;
+
+ os_constructor_c << "LFSCProof* LFSCProof::make_" << ((SymSExpr*)syms[a])->s.c_str();
+ os_constructor_c << os_args.str().c_str() << "{" << std::endl;
+ os_constructor_c << " LFSCProof **kids = new LFSCProof *[" << (int)args.size()+1 << "];" << std::endl;
+ for( int b=0; b<(int)args.size(); b++ ){
+ os_constructor_c << " kids[" << b << "] = ";
+ if( argsNeed[b] ){
+ std::string str;
+ get_var_name( ((SymSExpr*)args[b])->s, str );
+ os_constructor_c << str.c_str();
+ }else{
+ os_constructor_c << "hole";
+ }
+ os_constructor_c << ";" << std::endl;
+ }
+ os_constructor_c << " kids[" << (int)args.size() << "] = 0;" << std::endl;
+ os_constructor_c << " return new LFSCProofC( rule_" << ((SymSExpr*)syms[a])->s.c_str() << ", kids );" << std::endl;
+ os_constructor_c << "}" << std::endl << std::endl;
+ }
+ }
+
+ //write the header
+ static std::string filename( "lfsc_proof" );
+ std::fstream fsh;
+ std::string fnameh( filename );
+ fnameh.append(".h");
+ fsh.open( fnameh.c_str(), std::ios::out );
+
+ fsh << "#ifndef LFSC_PROOF_LIB_H" << std::endl;
+ fsh << "#define LFSC_PROOF_LIB_H" << std::endl;
+ fsh << std::endl;
+ fsh << "#include <string>" << std::endl;
+ fsh << std::endl;
+ fsh << "class LFSCProof{" << std::endl;
+ fsh << "protected:" << std::endl;
+ fsh << " enum{" << std::endl;
+ fsh << os_enum.str().c_str();
+ fsh << " };" << std::endl;
+ fsh << " static LFSCProof* hole;" << std::endl;
+ fsh << " LFSCProof(){}" << std::endl;
+ fsh << "public:" << std::endl;
+ fsh << " virtual ~LFSCProof(){}" << std::endl;
+ fsh << " static void init();" << std::endl;
+ fsh << std::endl;
+ fsh << " //functions to build LFSC proofs" << std::endl;
+ fsh << os_constructor_h.str().c_str();
+ fsh << std::endl;
+ fsh << " virtual void set_child( int i, LFSCProof* e ) {}" << std::endl;
+ fsh << " virtual void print( std::ostream& os ){}" << std::endl;
+ fsh << "};" << std::endl;
+ fsh << std::endl;
+ fsh << "class LFSCProofC : public LFSCProof{" << std::endl;
+ fsh << " short id;" << std::endl;
+ fsh << " LFSCProof **kids;" << std::endl;
+ fsh << "public:" << std::endl;
+ fsh << " LFSCProofC( short d_id, LFSCProof **d_kids ) : id( d_id ), kids( d_kids ){}" << std::endl;
+ fsh << " void set_child( int i, LFSCProof* e ) { kids[i] = e; }" << std::endl;
+ fsh << " void print( std::ostream& os );" << std::endl;
+ fsh << "};" << std::endl;
+ fsh << std::endl;
+ fsh << "class LFSCProofSym : public LFSCProof{" << std::endl;
+ fsh << "private:" << std::endl;
+ fsh << " std::string s;" << std::endl;
+ fsh << " LFSCProofSym( std::string ss ) : s( ss ){}" << std::endl;
+ fsh << "public:" << std::endl;
+ fsh << " static LFSCProofSym* make( std::string ss ) { return new LFSCProofSym( ss ); }" << std::endl;
+ fsh << " static LFSCProofSym* make( const char* ss ) { return new LFSCProofSym( std::string( ss ) ); }" << std::endl;
+ fsh << " ~LFSCProofSym(){}" << std::endl;
+ fsh << " void print( std::ostream& os ) { os << s.c_str(); }" << std::endl;
+ fsh << "};" << std::endl;
+ fsh << std::endl;
+ fsh << "class LFSCProofLam : public LFSCProof{" << std::endl;
+ fsh << " LFSCProofSym* var;" << std::endl;
+ fsh << " LFSCProof* body;" << std::endl;
+ fsh << " LFSCProof* typ;" << std::endl;
+ fsh << " LFSCProofLam( LFSCProofSym* d_var, LFSCProof* d_body, LFSCProof* d_typ ) : var( d_var ), body( d_body ), typ( d_typ ){}" << std::endl;
+ fsh << "public:" << std::endl;
+ fsh << " static LFSCProof* make( LFSCProofSym* d_var, LFSCProof* d_body, LFSCProof* d_typ = NULL ) {" << std::endl;
+ fsh << " return new LFSCProofLam( d_var, d_body, d_typ );" << std::endl;
+ fsh << " }" << std::endl;
+ fsh << " ~LFSCProofLam(){}" << std::endl;
+ fsh << std::endl;
+ fsh << " void print( std::ostream& os );" << std::endl;
+ fsh << "};" << std::endl;
+ fsh << std::endl;
+ fsh << "#endif" << std::endl;
+
+ //write the cpp
+ std::fstream fsc;
+ std::string fnamec( filename );
+ fnamec.append(".cpp");
+ fsc.open( fnamec.c_str(), std::ios::out );
+
+ fsc << "#include \"lfsc_proof.h\"" << std::endl;
+ fsc << std::endl;
+ fsc << "LFSCProof* LFSCProof::hole = NULL;" << std::endl;
+ fsc << std::endl;
+ fsc << "void LFSCProof::init(){" << std::endl;
+ fsc << " hole = LFSCProofSym::make( \"_\" );" << std::endl;
+ fsc << "}" << std::endl;
+ fsc << std::endl;
+ fsc << "void LFSCProofC::print( std::ostream& os ){" << std::endl;
+ fsc << " os << \"(\";" << std::endl;
+ fsc << " switch( id ){" << std::endl;
+ fsc << os_print.str().c_str();
+ fsc << " }" << std::endl;
+ fsc << " int counter = 0;" << std::endl;
+ fsc << " while( kids[counter] ){" << std::endl;
+ fsc << " os << \" \";" << std::endl;
+ fsc << " kids[counter]->print( os );" << std::endl;
+ fsc << " counter++;" << std::endl;
+ fsc << " }" << std::endl;
+ fsc << " os << \")\";" << std::endl;
+ fsc << "}" << std::endl;
+ fsc << std::endl;
+ fsc << "void LFSCProofLam::print( std::ostream& os ){" << std::endl;
+ fsc << " os << \"(\";" << std::endl;
+ fsc << " if( typ ){" << std::endl;
+ fsc << " os << \"% \";" << std::endl;
+ fsc << " }else{" << std::endl;
+ fsc << " os << \"\\\\ \";" << std::endl;
+ fsc << " }" << std::endl;
+ fsc << " var->print( os );" << std::endl;
+ fsc << " if( typ ){" << std::endl;
+ fsc << " os << \" \";" << std::endl;
+ fsc << " typ->print( os );" << std::endl;
+ fsc << " }" << std::endl;
+ fsc << " os << std::endl;" << std::endl;
+ fsc << " body->print( os );" << std::endl;
+ fsc << " os << \")\";" << std::endl;
+ fsc << "}" << std::endl;
+ fsc << std::endl;
+ fsc << os_constructor_c.str().c_str();
+ fsc << std::endl;
+ }
+}
diff --git a/proofs/lfsc_checker/libwriter.h b/proofs/lfsc_checker/libwriter.h
new file mode 100644
index 000000000..093cf541b
--- /dev/null
+++ b/proofs/lfsc_checker/libwriter.h
@@ -0,0 +1,28 @@
+#ifndef LIB_WRITER_H
+#define LIB_WRITER_H
+
+#include "expr.h"
+#include <map>
+
+class libwriter
+{
+private:
+ std::vector< Expr* > syms;
+ std::vector< Expr* > defs;
+
+ std::vector< Expr* > judgements;
+ //get the variable name
+ void get_var_name( const std::string& n, std::string& nn );
+public:
+ libwriter(){}
+ virtual ~libwriter(){}
+
+ void add_symbol( Expr* s, Expr* t ) {
+ syms.push_back( s );
+ defs.push_back( t );
+ }
+
+ void write_file();
+};
+
+#endif
diff --git a/proofs/lfsc_checker/main.cpp b/proofs/lfsc_checker/main.cpp
new file mode 100644
index 000000000..80f36e69f
--- /dev/null
+++ b/proofs/lfsc_checker/main.cpp
@@ -0,0 +1,139 @@
+#include "expr.h"
+#include "check.h"
+#include <signal.h>
+#include "sccwriter.h"
+#include "libwriter.h"
+#include <time.h>
+
+using namespace std;
+
+args a;
+
+static void parse_args(int argc, char **argv, args &a)
+{
+ char *arg0 = *argv;
+
+ /* skip 0'th argument */
+ argv++;
+ argc--;
+
+ while (argc) {
+
+ if ((strncmp("-h", *argv, 2) == 0) ||
+ (strncmp("--h", *argv, 3) == 0)) {
+ cout << "Usage: " << arg0 << " [options] infile1 ...infile_n\n";
+ cout << "If no infiles are named on the command line, input is read\n"
+ << "from stdin. Specifying the infile \"stdin\" will also read\n"
+ << "from stdin. Options are:\n\n";
+ cout << "--show-runs: print debugging information for runs of side condition code\n";
+ cout << "--compile-scc: compile side condition code\n";
+ cout << "--compile-scc-debug: compile debug versions of side condition code\n";
+ cout << "--run-scc: use compiled side condition code\n";
+ exit(0);
+ }
+ else if(strcmp("--show-runs", *argv) == 0) {
+ argc--; argv++;
+ a.show_runs = true;
+ }
+ else if(strcmp("--no-tail-calls", *argv) == 0) {
+ // this is just for debugging.
+ argc--; argv++;
+ a.no_tail_calls = true;
+ }
+ else if( strcmp("--compile-scc", *argv) == 0 ){
+ argc--; argv++;
+ a.compile_scc = true;
+ a.compile_scc_debug = false;
+ }
+ else if( strcmp("--compile-scc-debug", *argv) == 0 )
+ {
+ argc--; argv++;
+ a.compile_scc = true;
+ a.compile_scc_debug = true;
+ }
+ else if( strcmp("--compile-lib", *argv) == 0 )
+ {
+ argc--; argv++;
+ a.compile_lib = true;
+ }
+ else if( strcmp("--run-scc", *argv) == 0 ){
+ argc--; argv++;
+ a.run_scc = true;
+ }
+ else if( strcmp("--use-nested-app", *argv) == 0 ){
+ argc--; argv++;
+ a.use_nested_app = true; //not implemented yet
+ }else {
+ a.files.push_back(*argv);
+ argc--; argv++;
+ }
+ }
+}
+
+void sighandler(int /* signum */) {
+ cerr << "\nInterrupted. sc is aborting.\n";
+ exit(1);
+}
+
+int main(int argc, char **argv) {
+
+ a.show_runs = false;
+ a.no_tail_calls = false;
+ a.compile_scc = false;
+ a.run_scc = false;
+ a.use_nested_app = false;
+
+ signal(SIGINT, sighandler);
+
+ parse_args(argc, argv, a);
+
+ init();
+
+ check_time = (int)clock();
+
+ if (a.files.size()) {
+ sccwriter* scw = NULL;
+ libwriter* lw = NULL;
+ if( a.compile_scc ){
+ scw = new sccwriter( a.compile_scc_debug ? opt_write_call_debug : 0 );
+ }
+ if( a.compile_lib ){
+ lw = new libwriter;
+ }
+ /* process the files named */
+ int i = 0, iend = a.files.size();
+ for (; i < iend; i++) {
+ const char *filename = a.files[i].c_str();
+ check_file(filename, a, scw, lw);
+ }
+ if( scw ){
+ scw->write_file();
+ delete scw;
+ }
+ if( lw ){
+#ifdef DEBUG_SYM_NAMES
+ lw->write_file();
+ delete lw;
+#else
+ std::cout << "ERROR libwriter: Must compile LFSC with DEBUG_SYM_NAMES flag (see Expr.h)" << std::endl;
+#endif
+ }
+ }
+ else
+ check_file("stdin", a);
+
+ //std::cout << "time = " << (int)clock() - t << std::endl;
+ //while(1){}
+
+#ifdef DEBUG
+ cout << "Clearing globals.\n";
+ cout.flush();
+
+ cleanup();
+ a.files.clear();
+#endif
+
+ std::cout << "time = " << (int)clock() - check_time << std::endl;
+ std::cout << "sym count = " << SymExpr::symmCount << std::endl;
+ std::cout << "marked count = " << Expr::markedCount << std::endl;
+}
diff --git a/proofs/lfsc_checker/position.h b/proofs/lfsc_checker/position.h
new file mode 100644
index 000000000..a5c51ffc6
--- /dev/null
+++ b/proofs/lfsc_checker/position.h
@@ -0,0 +1,30 @@
+#ifndef sc2__position_h
+#define sc2__position_h
+
+#include <iostream>
+#include <stdio.h>
+
+class Position {
+public:
+ const char *filename;
+ int linenum;
+ int colnum;
+
+ Position(const char *_f, int l, int c) : filename(_f), linenum(l), colnum(c)
+ {}
+ void print(std::ostream &os) {
+ os << filename;
+ if (colnum == -1) {
+ char tmp[1024];
+ sprintf(tmp, ", line %d, end of column: ", linenum);
+ os << tmp;
+ }
+ else {
+ char tmp[1024];
+ sprintf(tmp, ", line %d, column %d: ", linenum, colnum);
+ os << tmp;
+ }
+ }
+};
+
+#endif
diff --git a/proofs/lfsc_checker/print_smt2.cpp b/proofs/lfsc_checker/print_smt2.cpp
new file mode 100644
index 000000000..bf068c248
--- /dev/null
+++ b/proofs/lfsc_checker/print_smt2.cpp
@@ -0,0 +1,122 @@
+#include "print_smt2.h"
+
+#ifdef PRINT_SMT2
+
+void print_smt2( Expr* p, std::ostream& s, short mode )
+{
+ switch( p->getclass() )
+ {
+ case CEXPR:
+ {
+ switch( p->getop() )
+ {
+ case APP:
+ {
+ std::vector<Expr *> args;
+ Expr *head = p->collect_args(args, false);
+ short newMode = get_mode( head );
+ if( is_smt2_poly_formula( head ) )
+ {
+ s << "(";
+ head->print( s );
+ s << " ";
+ print_smt2( args[1], s, newMode );
+ s << " ";
+ print_smt2( args[2], s, newMode );
+ s << ")";
+ }
+ else if( ( mode==2 || mode==3 ) && mode==newMode )
+ {
+ print_smt2( args[0], s, newMode );
+ s << " ";
+ print_smt2( args[1], s, newMode );
+ }
+ else if( newMode==1 )
+ {
+ if( mode!=1 || newMode!=mode ){
+ s << "(";
+ }
+ print_smt2( args[2], s, newMode );
+ s << " ";
+ print_smt2( args[3], s, 0 );
+ if( mode!=1 || newMode!=mode ){
+ s << ")";
+ }
+ }
+ else
+ {
+ s << "(";
+ switch( newMode )
+ {
+ case 4: s << "=>";break;
+ default: head->print( s );break;
+ }
+ s << " ";
+ for( int a=0; a<(int)args.size(); a++ ){
+ print_smt2( args[a], s, newMode );
+ if( a!=args.size()-1 )
+ s << " ";
+ }
+ s << ")";
+ }
+ }
+ break;
+ default:
+ std::cout << "Unhandled op " << p->getop() << std::endl;
+ break;
+ }
+ }
+ break;
+ case HOLE_EXPR:
+ {
+ HoleExpr *e = (HoleExpr *)p;
+ if( e->val ){
+ print_smt2( e->val, s, mode );
+ }else{
+ s << "_";
+ }
+ }
+ break;
+ case SYMS_EXPR:
+ case SYM_EXPR:
+ if( ((SymExpr*)p)->val )
+ print_smt2( ((SymExpr*)p)->val, s, mode );
+ else
+ p->print( s );
+ break;
+ default:
+ std::cout << "Unhandled class " << p->getclass() << std::endl;
+ break;
+ }
+}
+
+bool is_smt2_poly_formula( Expr* e )
+{
+ if( e->getclass()==SYMS_EXPR )
+ {
+ SymSExpr* s = (SymSExpr*)e;
+ static std::string eq("=");
+ static std::string distinct("distinct");
+ return s->s==eq || s->s==distinct;
+ }else{
+ return false;
+ }
+}
+
+short get_mode( Expr* e )
+{
+ if( e->getclass()==SYMS_EXPR ){
+ SymSExpr* s = (SymSExpr*)e;
+ static std::string applys("apply");
+ if ( s->s==applys ) return 1;
+ static std::string ands("and");
+ if ( s->s==ands ) return 2;
+ static std::string ors("or");
+ if ( s->s==ors ) return 3;
+ static std::string impls("impl");
+ if ( s->s==impls ) return 4;
+ }
+ return 0;
+}
+
+#endif
diff --git a/proofs/lfsc_checker/print_smt2.h b/proofs/lfsc_checker/print_smt2.h
new file mode 100644
index 000000000..c70b1dfa4
--- /dev/null
+++ b/proofs/lfsc_checker/print_smt2.h
@@ -0,0 +1,17 @@
+#ifndef PRINT_SMT2_H
+#define PRINT_SMT2_H
+
+#define PRINT_SMT2
+
+#include "expr.h"
+
+#ifdef PRINT_SMT2
+void print_smt2( Expr* p, std::ostream& s, short mode = 0 );
+
+bool is_smt2_poly_formula( Expr* p );
+short get_mode( Expr* p );
+
+#endif
+
+
+#endif
diff --git a/proofs/lfsc_checker/scccode.cpp b/proofs/lfsc_checker/scccode.cpp
new file mode 100644
index 000000000..cff762a08
--- /dev/null
+++ b/proofs/lfsc_checker/scccode.cpp
@@ -0,0 +1,609 @@
+#include "scccode.h"
+
+Expr* e_pos;
+Expr* e_neg;
+Expr* e_tt;
+Expr* e_ff;
+Expr* e_cln;
+Expr* e_clc;
+Expr* e_concat;
+Expr* e_clr;
+Expr* e_litvar;
+Expr* e_litpol;
+Expr* e_notb;
+Expr* e_iffb;
+Expr* e_clear_mark;
+Expr* e_append;
+Expr* e_simplify_clause_h;
+Expr* e_simplify_clause;
+
+void init_compiled_scc(){
+ e_pos = symbols->get("pos").first;
+ e_neg = symbols->get("neg").first;
+ e_tt = symbols->get("tt").first;
+ e_ff = symbols->get("ff").first;
+ e_cln = symbols->get("cln").first;
+ e_clc = symbols->get("clc").first;
+ e_concat = symbols->get("concat").first;
+ e_clr = symbols->get("clr").first;
+ e_litvar = progs["litvar"];
+ e_litpol = progs["litpol"];
+ e_notb = progs["notb"];
+ e_iffb = progs["iffb"];
+ e_clear_mark = progs["clear_mark"];
+ e_append = progs["append"];
+ e_simplify_clause_h = progs["simplify_clause_h"];
+ e_simplify_clause = progs["simplify_clause"];
+}
+
+Expr* run_compiled_scc( Expr* p, std::vector< Expr* >& args ){
+ if( p==e_litvar ){
+ return f_litvar( args[0] );
+ }else if( p==e_litpol ){
+ return f_litpol( args[0] );
+ }else if( p==e_notb ){
+ return f_notb( args[0] );
+ }else if( p==e_iffb ){
+ return f_iffb( args[0], args[1] );
+ }else if( p==e_clear_mark ){
+ return f_clear_mark( args[0] );
+ }else if( p==e_append ){
+ return f_append( args[0], args[1] );
+ }else if( p==e_simplify_clause_h ){
+ return f_simplify_clause_h( args[0], args[1] );
+ }else if( p==e_simplify_clause ){
+ return f_simplify_clause( args[0] );
+ }else{
+ return NULL;
+ }
+}
+
+Expr* f_litvar( Expr* l ){
+ Expr* e0;
+ l->inc();
+ Expr* e1 = l->followDefs()->get_head();
+ Expr* e2;
+ e2 = e_pos;
+ e2->inc();
+ Expr* e3;
+ e3 = e_neg;
+ e3->inc();
+ if( e1==e2 ){
+ Expr* x = ((CExpr*)l->followDefs())->kids[1];
+ e0 = x;
+ e0->inc();
+ }else if( e1==e3 ){
+ Expr* x = ((CExpr*)l->followDefs())->kids[1];
+ e0 = x;
+ e0->inc();
+ }else{
+ std::cout << "Could not find match for expression in function f_litvar ";
+ e1->print( std::cout );
+ std::cout << std::endl;
+ exit( 1 );
+ }
+ l->dec();
+ e2->dec();
+ e3->dec();
+ return e0;
+}
+
+Expr* f_litpol( Expr* l ){
+ Expr* e0;
+ l->inc();
+ Expr* e1 = l->followDefs()->get_head();
+ Expr* e2;
+ e2 = e_pos;
+ e2->inc();
+ Expr* e3;
+ e3 = e_neg;
+ e3->inc();
+ if( e1==e2 ){
+ Expr* x = ((CExpr*)l->followDefs())->kids[1];
+ e0 = e_tt;
+ e0->inc();
+ }else if( e1==e3 ){
+ Expr* x = ((CExpr*)l->followDefs())->kids[1];
+ e0 = e_ff;
+ e0->inc();
+ }else{
+ std::cout << "Could not find match for expression in function f_litpol ";
+ e1->print( std::cout );
+ std::cout << std::endl;
+ exit( 1 );
+ }
+ l->dec();
+ e2->dec();
+ e3->dec();
+ return e0;
+}
+
+Expr* f_notb( Expr* b ){
+ Expr* e0;
+ b->inc();
+ Expr* e1 = b->followDefs()->get_head();
+ Expr* e2;
+ e2 = e_ff;
+ e2->inc();
+ Expr* e3;
+ e3 = e_tt;
+ e3->inc();
+ if( e1==e2 ){
+ e0 = e_tt;
+ e0->inc();
+ }else if( e1==e3 ){
+ e0 = e_ff;
+ e0->inc();
+ }else{
+ std::cout << "Could not find match for expression in function f_notb ";
+ e1->print( std::cout );
+ std::cout << std::endl;
+ exit( 1 );
+ }
+ b->dec();
+ e2->dec();
+ e3->dec();
+ return e0;
+}
+
+Expr* f_iffb( Expr* b1, Expr* b2 ){
+ Expr* e0;
+ b1->inc();
+ Expr* e1 = b1->followDefs()->get_head();
+ Expr* e2;
+ e2 = e_tt;
+ e2->inc();
+ Expr* e3;
+ e3 = e_ff;
+ e3->inc();
+ if( e1==e2 ){
+ e0 = b2;
+ e0->inc();
+ }else if( e1==e3 ){
+ b2->inc();
+ e0 = f_notb( b2 );
+ b2->dec();
+ }else{
+ std::cout << "Could not find match for expression in function f_iffb ";
+ e1->print( std::cout );
+ std::cout << std::endl;
+ exit( 1 );
+ }
+ b1->dec();
+ e2->dec();
+ e3->dec();
+ return e0;
+}
+
+Expr* f_clear_mark( Expr* v ){
+ Expr* e0;
+ v->inc();
+ if ( ((SymExpr*)v->followDefs())->getmark(0)){
+ v->inc();
+ if ( ((SymExpr*)v->followDefs())->getmark(0))
+ ((SymExpr*)v->followDefs())->clearmark(0);
+ else
+ ((SymExpr*)v->followDefs())->setmark(0);
+ e0 = v;
+ e0->inc();
+ v->dec();
+ }else{
+ e0 = v;
+ e0->inc();
+ }
+ v->dec();
+ return e0;
+}
+
+Expr* f_append( Expr* c1, Expr* c2 ){
+ Expr* e0;
+ c1->inc();
+ Expr* e1 = c1->followDefs()->get_head();
+ Expr* e2;
+ e2 = e_cln;
+ e2->inc();
+ Expr* e3;
+ e3 = e_clc;
+ e3->inc();
+ if( e1==e2 ){
+ e0 = c2;
+ e0->inc();
+ }else if( e1==e3 ){
+ Expr* l = ((CExpr*)c1->followDefs())->kids[1];
+ Expr* c1h = ((CExpr*)c1->followDefs())->kids[2];
+ l->inc();
+ Expr* e4;
+ c1h->inc();
+ c2->inc();
+ e4 = f_append( c1h, c2 );
+ c1h->dec();
+ c2->dec();
+ static Expr* e5;
+ e5 = e_clc;
+ e5->inc();
+ e0 = new CExpr( APP, e5, l, e4 );
+ }else{
+ std::cout << "Could not find match for expression in function f_append ";
+ e1->print( std::cout );
+ std::cout << std::endl;
+ exit( 1 );
+ }
+ c1->dec();
+ e2->dec();
+ e3->dec();
+ return e0;
+}
+
+Expr* f_simplify_clause_h( Expr* pol, Expr* c ){
+ Expr* e0;
+ c->inc();
+ Expr* e1 = c->followDefs()->get_head();
+ Expr* e2;
+ e2 = e_cln;
+ e2->inc();
+ Expr* e3;
+ e3 = e_clc;
+ e3->inc();
+ Expr* e4;
+ e4 = e_concat;
+ e4->inc();
+ Expr* e5;
+ e5 = e_clr;
+ e5->inc();
+ if( e1==e2 ){
+ e0 = e_cln;
+ e0->inc();
+ }else if( e1==e3 ){
+ Expr* l = ((CExpr*)c->followDefs())->kids[1];
+ Expr* c1 = ((CExpr*)c->followDefs())->kids[2];
+ Expr* v;
+ l->inc();
+ v = f_litvar( l );
+ l->dec();
+ Expr* e6;
+ Expr* e7;
+ l->inc();
+ e7 = f_litpol( l );
+ l->dec();
+ pol->inc();
+ e6 = f_iffb( e7, pol );
+ e7->dec();
+ pol->dec();
+ Expr* e8 = e6->followDefs()->get_head();
+ Expr* e9;
+ e9 = e_tt;
+ e9->inc();
+ Expr* e10;
+ e10 = e_ff;
+ e10->inc();
+ if( e8==e9 ){
+ Expr* m;
+ v->inc();
+ if ( ((SymExpr*)v->followDefs())->getmark(0)){
+ m = e_tt;
+ m->inc();
+ }else{
+ Expr* e11;
+ v->inc();
+ if ( ((SymExpr*)v->followDefs())->getmark(0))
+ ((SymExpr*)v->followDefs())->clearmark(0);
+ else
+ ((SymExpr*)v->followDefs())->setmark(0);
+ e11 = v;
+ e11->inc();
+ v->dec();
+ e11->dec();
+ m = e_ff;
+ m->inc();
+ }
+ v->dec();
+ Expr* ch;
+ pol->inc();
+ c1->inc();
+ ch = f_simplify_clause_h( pol, c1 );
+ pol->dec();
+ c1->dec();
+ m->inc();
+ Expr* e12 = m->followDefs()->get_head();
+ Expr* e13;
+ e13 = e_tt;
+ e13->inc();
+ Expr* e14;
+ e14 = e_ff;
+ e14->inc();
+ if( e12==e13 ){
+ Expr* e15;
+ v->inc();
+ if ( ((SymExpr*)v->followDefs())->getmark(1)){
+ e15 = v;
+ e15->inc();
+ }else{
+ v->inc();
+ if ( ((SymExpr*)v->followDefs())->getmark(1))
+ ((SymExpr*)v->followDefs())->clearmark(1);
+ else
+ ((SymExpr*)v->followDefs())->setmark(1);
+ e15 = v;
+ e15->inc();
+ v->dec();
+ }
+ v->dec();
+ e15->dec();
+ e0 = ch;
+ e0->inc();
+ }else if( e12==e14 ){
+ Expr* e16;
+ Expr* e17;
+ v->inc();
+ if ( ((SymExpr*)v->followDefs())->getmark(1)){
+ v->inc();
+ if ( ((SymExpr*)v->followDefs())->getmark(1))
+ ((SymExpr*)v->followDefs())->clearmark(1);
+ else
+ ((SymExpr*)v->followDefs())->setmark(1);
+ e17 = v;
+ e17->inc();
+ v->dec();
+ }else{
+ e17 = v;
+ e17->inc();
+ }
+ v->dec();
+ e17->dec();
+ v->inc();
+ if ( ((SymExpr*)v->followDefs())->getmark(0))
+ ((SymExpr*)v->followDefs())->clearmark(0);
+ else
+ ((SymExpr*)v->followDefs())->setmark(0);
+ e16 = v;
+ e16->inc();
+ v->dec();
+ e16->dec();
+ l->inc();
+ ch->inc();
+ static Expr* e18;
+ e18 = e_clc;
+ e18->inc();
+ e0 = new CExpr( APP, e18, l, ch );
+ }else{
+ std::cout << "Could not find match for expression in function f_simplify_clause_h ";
+ e12->print( std::cout );
+ std::cout << std::endl;
+ exit( 1 );
+ }
+ m->dec();
+ e13->dec();
+ e14->dec();
+ ch->dec();
+ m->dec();
+ }else if( e8==e10 ){
+ l->inc();
+ Expr* e19;
+ pol->inc();
+ c1->inc();
+ e19 = f_simplify_clause_h( pol, c1 );
+ pol->dec();
+ c1->dec();
+ static Expr* e20;
+ e20 = e_clc;
+ e20->inc();
+ e0 = new CExpr( APP, e20, l, e19 );
+ }else{
+ std::cout << "Could not find match for expression in function f_simplify_clause_h ";
+ e8->print( std::cout );
+ std::cout << std::endl;
+ exit( 1 );
+ }
+ e6->dec();
+ e9->dec();
+ e10->dec();
+ v->dec();
+ }else if( e1==e4 ){
+ Expr* c1 = ((CExpr*)c->followDefs())->kids[1];
+ Expr* c2 = ((CExpr*)c->followDefs())->kids[2];
+ pol->inc();
+ Expr* e21 = pol->followDefs()->get_head();
+ Expr* e22;
+ e22 = e_ff;
+ e22->inc();
+ Expr* e23;
+ e23 = e_tt;
+ e23->inc();
+ if( e21==e22 ){
+ Expr* e24;
+ pol->inc();
+ c1->inc();
+ e24 = f_simplify_clause_h( pol, c1 );
+ pol->dec();
+ c1->dec();
+ Expr* e25;
+ pol->inc();
+ c2->inc();
+ e25 = f_simplify_clause_h( pol, c2 );
+ pol->dec();
+ c2->dec();
+ static Expr* e26;
+ e26 = e_concat;
+ e26->inc();
+ e0 = new CExpr( APP, e26, e24, e25 );
+ }else if( e21==e23 ){
+ Expr* e27;
+ pol->inc();
+ c1->inc();
+ e27 = f_simplify_clause_h( pol, c1 );
+ pol->dec();
+ c1->dec();
+ Expr* e28;
+ pol->inc();
+ c2->inc();
+ e28 = f_simplify_clause_h( pol, c2 );
+ pol->dec();
+ c2->dec();
+ e0 = f_append( e27, e28 );
+ e27->dec();
+ e28->dec();
+ }else{
+ std::cout << "Could not find match for expression in function f_simplify_clause_h ";
+ e21->print( std::cout );
+ std::cout << std::endl;
+ exit( 1 );
+ }
+ pol->dec();
+ e22->dec();
+ e23->dec();
+ }else if( e1==e5 ){
+ Expr* l = ((CExpr*)c->followDefs())->kids[1];
+ Expr* c1 = ((CExpr*)c->followDefs())->kids[2];
+ Expr* e29;
+ Expr* e30;
+ l->inc();
+ e30 = f_litpol( l );
+ l->dec();
+ pol->inc();
+ e29 = f_iffb( e30, pol );
+ e30->dec();
+ pol->dec();
+ Expr* e31 = e29->followDefs()->get_head();
+ Expr* e32;
+ e32 = e_ff;
+ e32->inc();
+ Expr* e33;
+ e33 = e_tt;
+ e33->inc();
+ if( e31==e32 ){
+ l->inc();
+ Expr* e34;
+ pol->inc();
+ c1->inc();
+ e34 = f_simplify_clause_h( pol, c1 );
+ pol->dec();
+ c1->dec();
+ static Expr* e35;
+ e35 = e_clr;
+ e35->inc();
+ e0 = new CExpr( APP, e35, l, e34 );
+ }else if( e31==e33 ){
+ Expr* v;
+ l->inc();
+ v = f_litvar( l );
+ l->dec();
+ Expr* m;
+ v->inc();
+ if ( ((SymExpr*)v->followDefs())->getmark(0)){
+ m = e_tt;
+ m->inc();
+ }else{
+ Expr* e36;
+ v->inc();
+ if ( ((SymExpr*)v->followDefs())->getmark(0))
+ ((SymExpr*)v->followDefs())->clearmark(0);
+ else
+ ((SymExpr*)v->followDefs())->setmark(0);
+ e36 = v;
+ e36->inc();
+ v->dec();
+ e36->dec();
+ m = e_ff;
+ m->inc();
+ }
+ v->dec();
+ Expr* ch;
+ pol->inc();
+ c1->inc();
+ ch = f_simplify_clause_h( pol, c1 );
+ pol->dec();
+ c1->dec();
+ v->inc();
+ if ( ((SymExpr*)v->followDefs())->getmark(1)){
+ m->inc();
+ Expr* e37 = m->followDefs()->get_head();
+ Expr* e38;
+ e38 = e_tt;
+ e38->inc();
+ Expr* e39;
+ e39 = e_ff;
+ e39->inc();
+ if( e37==e38 ){
+ e0 = ch;
+ e0->inc();
+ }else if( e37==e39 ){
+ Expr* e40;
+ Expr* e41;
+ v->inc();
+ if ( ((SymExpr*)v->followDefs())->getmark(1))
+ ((SymExpr*)v->followDefs())->clearmark(1);
+ else
+ ((SymExpr*)v->followDefs())->setmark(1);
+ e41 = v;
+ e41->inc();
+ v->dec();
+ e41->dec();
+ v->inc();
+ if ( ((SymExpr*)v->followDefs())->getmark(0))
+ ((SymExpr*)v->followDefs())->clearmark(0);
+ else
+ ((SymExpr*)v->followDefs())->setmark(0);
+ e40 = v;
+ e40->inc();
+ v->dec();
+ e40->dec();
+ e0 = ch;
+ e0->inc();
+ }else{
+ std::cout << "Could not find match for expression in function f_simplify_clause_h ";
+ e37->print( std::cout );
+ std::cout << std::endl;
+ exit( 1 );
+ }
+ m->dec();
+ e38->dec();
+ e39->dec();
+ }else{
+ e0 = NULL;
+ }
+ v->dec();
+ ch->dec();
+ m->dec();
+ v->dec();
+ }else{
+ std::cout << "Could not find match for expression in function f_simplify_clause_h ";
+ e31->print( std::cout );
+ std::cout << std::endl;
+ exit( 1 );
+ }
+ e29->dec();
+ e32->dec();
+ e33->dec();
+ }else{
+ std::cout << "Could not find match for expression in function f_simplify_clause_h ";
+ e1->print( std::cout );
+ std::cout << std::endl;
+ exit( 1 );
+ }
+ c->dec();
+ e2->dec();
+ e3->dec();
+ e4->dec();
+ e5->dec();
+ return e0;
+}
+
+Expr* f_simplify_clause( Expr* c ){
+ Expr* e0;
+ static Expr* e1;
+ e1 = e_tt;
+ e1->inc();
+ Expr* e2;
+ static Expr* e3;
+ e3 = e_ff;
+ e3->inc();
+ c->inc();
+ e2 = f_simplify_clause_h( e3, c );
+ e3->dec();
+ c->dec();
+ e0 = f_simplify_clause_h( e1, e2 );
+ e1->dec();
+ e2->dec();
+ return e0;
+}
+
diff --git a/proofs/lfsc_checker/scccode.h b/proofs/lfsc_checker/scccode.h
new file mode 100644
index 000000000..6f5efc8b5
--- /dev/null
+++ b/proofs/lfsc_checker/scccode.h
@@ -0,0 +1,27 @@
+#ifndef SCC_CODE_H
+#define SCC_CODE_H
+
+#include "check.h"
+
+void init_compiled_scc();
+
+Expr* run_compiled_scc( Expr* p, std::vector< Expr* >& args );
+
+inline Expr* f_litvar( Expr* l );
+
+inline Expr* f_litpol( Expr* l );
+
+inline Expr* f_notb( Expr* b );
+
+inline Expr* f_iffb( Expr* b1, Expr* b2 );
+
+inline Expr* f_clear_mark( Expr* v );
+
+inline Expr* f_append( Expr* c1, Expr* c2 );
+
+inline Expr* f_simplify_clause_h( Expr* pol, Expr* c );
+
+inline Expr* f_simplify_clause( Expr* c );
+
+#endif
+
diff --git a/proofs/lfsc_checker/sccwriter.cpp b/proofs/lfsc_checker/sccwriter.cpp
new file mode 100644
index 000000000..d11a96b19
--- /dev/null
+++ b/proofs/lfsc_checker/sccwriter.cpp
@@ -0,0 +1,977 @@
+#include "sccwriter.h"
+
+#include <fstream>
+#include <sstream>
+
+int sccwriter::exprCount = 0;
+int sccwriter::strCount = 0;
+int sccwriter::argsCount = 0;
+int sccwriter::rnumCount = 0;
+
+int sccwriter::get_prog_index( const std::string& str )
+{
+ for( int a=0; a<(int)progNames.size(); a++ ){
+ if( progNames[a]==str ){
+ return a;
+ }
+ }
+ return -1;
+}
+
+int sccwriter::get_prog_index_by_expr( Expr* e )
+{
+ for( int a=0; a<(int)progPtrs.size(); a++ ){
+ if( progPtrs[a]==e ){
+ return a;
+ }
+ }
+ return -1;
+}
+
+bool sccwriter::is_var( const std::string& str )
+{
+ for( int a=0; a<(int)vars.size(); a++ ){
+ if( vars[a]==str ){
+ return true;
+ }
+ }
+ return false;
+}
+
+void sccwriter::add_global_sym( const std::string& str )
+{
+ for( int a=0; a<(int)globalSyms.size(); a++ ){
+ if( globalSyms[a]==str ){
+ return;
+ }
+ }
+ globalSyms.push_back( str );
+}
+
+void sccwriter::indent( std::ostream& os, int ind )
+{
+ for( int a=0; a<ind; a++ )
+ {
+ os << " ";
+ }
+}
+
+void sccwriter::write_function_header( std::ostream& os, int index, int opts )
+{
+ //write the function header
+ std::string fname;
+ get_function_name( progNames[index], fname );
+ os << "Expr* " << fname.c_str() << "( ";
+ CExpr* progvars = (CExpr*)get_prog( index )->kids[1];
+ int counter = 0;
+ //write each argument
+ while( progvars->kids[counter] )
+ {
+ if( counter!=0 )
+ {
+ os << ", ";
+ }
+ os << "Expr* ";
+ write_variable( ((SymSExpr*)progvars->kids[counter])->s, os );
+ //add to vars if options are set to do so
+ if( opts&opt_write_add_args )
+ {
+ vars.push_back( ((SymSExpr*)progvars->kids[counter])->s );
+ }
+ counter++;
+ }
+ os << " )";
+ if( opts&opt_write_call_debug )
+ {
+ os << "{" << std::endl;
+ indent( os, 1 );
+ os << "std::cout << \"Call function " << fname.c_str() << " with arguments \";" << std::endl;
+ counter = 0;
+ while( progvars->kids[counter] )
+ {
+ if( counter!=0 )
+ {
+ indent( os, 1 );
+ os << "std::cout << \", \";" << std::endl;
+ }
+ indent( os, 1 );
+ write_variable( ((SymSExpr*)progvars->kids[counter])->s, os );
+ os << "->print( std::cout );" << std::endl;
+ counter++;
+ }
+ indent( os, 1 );
+ os << "std::cout << std::endl;" << std::endl;
+ }
+}
+
+void sccwriter::get_function_name( const std::string& pname, std::string& fname )
+{
+ fname = std::string( "f_" );
+ fname.append( pname );
+}
+
+void sccwriter::write_variable( const std::string& n, std::ostream& os )
+{
+ std::string nn;
+ get_var_name( n, nn );
+ os << nn.c_str();
+}
+
+void sccwriter::get_var_name( const std::string& n, std::string& nn ) {
+ nn = std::string( n.c_str() );
+ for( int i = 0; i <(int)n.length(); i++ ){
+ char c = n[i];
+ if (c <= 47)
+ c += 65;
+ else if (c >= 58 && c <= 64)
+ c += 97-58;
+ if ((c >= 91 && c <= 94) || c == 96)
+ c += 104-91;
+ else if (c >= 123)
+ c -= 4;
+ nn[i] = c;
+ }
+}
+
+void sccwriter::write_file()
+{
+ static std::string filename( "scccode" );
+
+ //writer the h file
+ std::fstream fsh;
+ std::string fnameh( filename );
+ fnameh.append(".h");
+ fsh.open( fnameh.c_str(), std::ios::out );
+ //write the header in h
+ fsh << "#ifndef SCC_CODE_H" << std::endl;
+ fsh << "#define SCC_CODE_H" << std::endl << std::endl;
+ //include necessary files in h file
+ fsh << "#include \"check.h\"" << std::endl << std::endl;
+ //write the init function
+ fsh << "void init_compiled_scc();" << std::endl << std::endl;
+ //write the entry function
+ fsh << "Expr* run_compiled_scc( Expr* p, std::vector< Expr* >& args );" << std::endl << std::endl;
+ //write the side condition code functions
+ for( int n=0; n<(int)progs.size(); n++ )
+ {
+ //write the header in the h file
+ fsh << "inline ";
+ write_function_header( fsh, n );
+ fsh << ";" << std::endl << std::endl;
+ }
+ fsh << "#endif" << std::endl << std::endl;
+ fsh.close();
+
+
+ //writer the cpp code
+ std::fstream fsc;
+ std::string fnamec( filename );
+ fnamec.append(".cpp");
+ fsc.open( fnamec.c_str(), std::ios::out );
+ //include the h file in the cpp
+ fsc << "#include \"scccode.h\"" << std::endl << std::endl;
+ std::ostringstream fsc_funcs;
+ //write the side condition code functions
+ for( currProgram=0; currProgram<(int)progs.size(); currProgram++ )
+ {
+ //reset naming counters
+ vars.clear();
+ exprCount = 0;
+ strCount = 0;
+ argsCount = 0;
+ rnumCount = 0;
+
+ //for debugging
+ std::cout << "program #" << currProgram << " " << progNames[currProgram].c_str() << std::endl;
+
+ //write the function header
+ write_function_header( fsc_funcs, currProgram, opt_write_add_args|options );
+ if( (options&opt_write_call_debug)==0 )
+ {
+ fsc_funcs << "{" << std::endl;
+ }
+ //write the code
+ //std::vector< std::string > cleanVec;
+ //write_code( get_prog( n )->kids[2], fsc, 1, "return ", cleanVec );
+ //debug_write_code( progs[n].second->kids[2], fsc, 1 );
+ std::string expr;
+ write_expr( get_prog( currProgram )->kids[2], fsc_funcs, 1, expr );
+ indent( fsc_funcs, 1 );
+ fsc_funcs << "return " << expr.c_str() << ";" << std::endl;
+ fsc_funcs << "}" << std::endl << std::endl;
+ }
+ //write the predefined symbols necessary - symbols and progs
+ for( int a=0; a<(int)globalSyms.size(); a++ )
+ {
+ fsc << "Expr* e_" << globalSyms[a].c_str() << ";" << std::endl;
+ }
+ for( int a=0; a<(int)progs.size(); a++ )
+ {
+ fsc << "Expr* e_" << progNames[a].c_str() << ";" << std::endl;
+ }
+ fsc << std::endl;
+ //write the init function - initialize symbols and progs
+ fsc << "void init_compiled_scc(){" << std::endl;
+ for( int a=0; a<(int)globalSyms.size(); a++ )
+ {
+ indent( fsc, 1 );
+ fsc << "e_" << globalSyms[a].c_str() << " = symbols->get(\"" << globalSyms[a].c_str() << "\").first;" << std::endl;
+ }
+ for( int a=0; a<(int)progs.size(); a++ )
+ {
+ indent( fsc, 1 );
+ fsc << "e_" << progNames[a].c_str() << " = progs[\"" << progNames[a].c_str() << "\"];" << std::endl;
+ }
+ fsc << "}" << std::endl << std::endl;
+ fsc << "Expr* run_compiled_scc( Expr* p, std::vector< Expr* >& args ){" << std::endl;
+ //for( int n=0; n<(int)progs.size(); n++ ){
+ // indent( fsc, 1 );
+ // fsc << "static std::string s_" << progNames[n].c_str() << " = std::string( \"" << progNames[n].c_str() << "\" );" << std::endl;
+ //}
+ for( int n=0; n<(int)progs.size(); n++ ){
+ indent( fsc, 1 );
+ if( n!=0 ){
+ fsc << "}else ";
+ }
+ //for each function, test to see if the string matches the name of the function
+ fsc << "if( p==e_" << progNames[n].c_str() << " ){" << std::endl;
+ indent( fsc, 2 );
+ std::string fname;
+ get_function_name( progNames[n], fname );
+ //map the function to the proper function
+ fsc << "return " << fname.c_str() << "( ";
+ //write the arguments to the function from args
+ CExpr* progvars = (CExpr*)get_prog( n )->kids[1];
+ int counter = 0;
+ bool firstTime = true;
+ while( progvars->kids[counter] )
+ {
+ if( !firstTime )
+ {
+ fsc << ", ";
+ }
+ fsc << "args[" << counter << "]";
+ firstTime = false;
+ counter++;
+ }
+ fsc << " );" << std::endl;
+ }
+ indent( fsc, 1 );
+ fsc << "}else{" << std::endl;
+ indent( fsc, 2 );
+ //return null in the case the function could not be found
+ fsc << "return NULL;" << std::endl;
+ indent( fsc, 1 );
+ fsc << "}" << std::endl;
+ fsc << "}" << std::endl << std::endl;
+ fsc << fsc_funcs.str().c_str();
+
+ fsc.close();
+}
+
+void sccwriter::write_code( Expr* code, std::ostream& os, int ind, const char* retModStr, int opts )
+{
+ std::string retModString;
+ std::string incString;
+ if ( retModStr )
+ {
+ retModString = std::string( retModStr );
+ retModString.append( " = " );
+ incString = std::string( retModStr );
+ incString.append( "->inc();" );
+ }
+ switch( code->getclass() )
+ {
+ case INT_EXPR:
+ {
+ indent( os, ind );
+ os << retModString.c_str();
+ os << "new IntExpr( " << mpz_get_si( ((IntExpr*)code)->n ) << " );" << std::endl;
+ indent( os, ind );
+ os << incString.c_str() << std::endl;
+ }
+ break;
+ case RAT_EXPR:
+ {
+ mpz_t num, den;
+ mpz_init(num);
+ mpz_init(den);
+ mpq_get_num( num, ((RatExpr*)code)->n );
+ mpq_get_den( den, ((RatExpr*)code)->n );
+ indent( os, ind );
+ os << retModString.c_str();
+ os << "new RatExpr( " << mpz_get_si( num ) << ", " << mpz_get_si( den ) << " );" << std::endl;
+ indent( os, ind );
+ os << incString.c_str() << std::endl;
+ }
+ break;
+ case SYMS_EXPR:
+ {
+ //if it is a variable, simply write it to buffer
+ if( is_var( ((SymSExpr*)code)->s ) )
+ {
+ indent( os, ind );
+ os << retModString.c_str();
+ write_variable( ((SymSExpr*)code)->s.c_str(), os );
+ os << ";" << std::endl;
+ }
+ else //else must look at symbol lookup table
+ {
+ std::string var;
+ get_var_name( ((SymSExpr*)code)->s, var );
+ indent( os, ind );
+ os << retModString.c_str() << "e_" << var.c_str() << ";" << std::endl;
+ add_global_sym( var );
+ }
+ indent( os, ind );
+ os << incString.c_str() << std::endl;
+ }
+ break;
+ default:
+ switch( code->getop() )
+ {
+ case APP:
+ {
+ //collect the arguments
+ std::vector< Expr* > argVector;
+ code->collect_args( argVector );
+ //write the arguments
+ std::vector< std::string > args;
+ for( int a=0; a<(int)argVector.size(); a++ )
+ {
+ std::string expr;
+ write_expr( argVector[a], os, ind, expr );
+ args.push_back( expr );
+ }
+ //write_args( (CExpr*)code, os, ind, 1, args );
+ Expr* hd = code->get_head();
+ //map to a program in the case that it is a program
+ if( hd->getop()==PROG && get_prog_index_by_expr( hd )!=-1 )
+ {
+ indent( os, ind );
+ os << retModString << "f_" << progNames[ get_prog_index_by_expr( hd ) ].c_str() << "( ";
+ for( int a=0; a<(int)args.size(); a++ )
+ {
+ os << args[a].c_str();
+ if( a!=(int)( args.size()-1 ) ){
+ os << ", ";
+ }
+ }
+ os << " );" << std::endl;
+ for( int a=0; a<(int)args.size(); a++ )
+ {
+ write_dec( args[a], os, ind );
+ }
+ }
+ else
+ {
+#ifdef USE_FLAT_APP
+ std::string expr;
+ write_expr( hd, os, ind, expr );
+ indent( os, ind );
+ os << retModString << "new CExpr( APP, ";
+ os << expr.c_str() << ", ";
+ for( int a=0; a<(int)args.size(); a++ )
+ {
+ os << args[a].c_str();
+ if( a!=(int)( args.size()-1 ) ){
+ os << ", ";
+ }
+ }
+ os << " );" << std::endl;
+#else
+ std::string expr;
+ write_expr( hd, os, ind, expr );
+ indent( os, ind );
+ os << retModString;
+ for( int a=0; a<(int)args.size(); a++ )
+ {
+ os << "new CExpr( APP, ";
+ }
+ os << expr.c_str() << ", ";
+ for( int a=0; a<(int)args.size(); a++ )
+ {
+ os << args[a].c_str();
+ os << " )";
+ if( a!=(int)( args.size()-1 ) ){
+ os << ", ";
+ }
+ }
+ os << ";" << std::endl;
+#endif
+ //indent( os, ind );
+ //os << expr.c_str() << "->dec();" << std::endl;
+ }
+ }
+ break;
+ case MATCH:
+ {
+ //calculate the value for the expression
+ std::string expr;
+ write_expr( ((CExpr*)code)->kids[0], os, ind, expr );
+ //get the head
+ std::ostringstream sshd;
+ sshd << "e" << exprCount;
+ exprCount++;
+ indent( os, ind );
+ os << "Expr* " << sshd.str().c_str() << " = " << expr.c_str() << "->followDefs()->get_head();" << std::endl;
+ //write the arguments
+ std::vector< std::string > args;
+ write_args( (CExpr*)code, os, ind, 1, args );
+ bool encounterDefault = false;
+ //now make an if statement corresponding to the match
+ int a = 0;
+ while( ((CExpr*)code)->kids[a+1] )
+ {
+ indent( os, ind );
+ if( a!=0 ){
+ os << "}else";
+ }
+ if( ((CExpr*)code)->kids[a+1]->getop()!=CASE ){
+ encounterDefault = true;
+ os << "{" << std::endl;
+ //write the body of the case
+ write_code( ((CExpr*)code)->kids[a+1], os, ind+1, retModStr );
+ indent( os, ind );
+ os << "}" << std::endl;
+ }else{
+ if( a!=0 )
+ os << " ";
+ os << "if( " << sshd.str().c_str() << "==" << args[a].c_str() << " ){" << std::endl;
+ //collect args from the variable in the code
+ std::ostringstream ssargs;
+ ssargs << "args" << argsCount;
+ argsCount++;
+#ifndef USE_FLAT_APP
+ indent( os, ind+1 );
+ os << "std::vector< Expr* > " << ssargs.str().c_str() << ";" << std::endl;
+ indent( os, ind+1 );
+ os << expr.c_str() << "->followDefs()->collect_args( " << ssargs.str().c_str() << " );" << std::endl;
+#endif
+ //set the variables defined in the pattern equal to the arguments
+ std::vector< Expr* > caseArgs;
+ ((CExpr*)((CExpr*)code)->kids[a+1])->kids[0]->collect_args( caseArgs );
+ for( int b=0; b<(int)caseArgs.size(); b++ )
+ {
+ indent( os, ind+1 );
+ os << "Expr* ";
+ write_variable( ((SymSExpr*)caseArgs[b])->s.c_str(), os );
+#ifdef USE_FLAT_APP
+ os << " = ((CExpr*)" << expr.c_str() << "->followDefs())->kids[" << b+1 << "];" << std::endl;
+#else
+ os << " = " << ssargs.str().c_str() << "[" << b << "];" << std::endl;
+#endif
+ vars.push_back( ((SymSExpr*)caseArgs[b])->s );
+ }
+ //write the body of the case
+ write_code( ((CExpr*)code)->kids[a+1], os, ind+1, retModStr, opt_write_case_body );
+ }
+ a++;
+ }
+ if( !encounterDefault )
+ {
+ indent( os, ind );
+ os << "}else{" << std::endl;
+ indent( os, ind + 1 );
+ os << "std::cout << \"Could not find match for expression in function f_";
+ os << progNames[currProgram].c_str() << " \";" << std::endl;
+ indent( os, ind + 1 );
+ os << sshd.str().c_str() << "->print( std::cout );" << std::endl;
+ indent( os, ind + 1 );
+ os << "std::cout << std::endl;" << std::endl;
+ indent( os, ind + 1 );
+ os << "exit( 1 );" << std::endl;
+ indent( os, ind );
+ os << "}" << std::endl;
+ }
+ write_dec( expr, os, ind );
+ for( int a=0; a<(int)args.size(); a++ )
+ {
+ write_dec( args[a], os, ind );
+ }
+ }
+ break;
+ case CASE:
+ if( opts&opt_write_case_body )
+ {
+ write_code( ((CExpr*)code)->kids[1], os, ind, retModStr );
+ }
+ else
+ {
+ write_code( ((CExpr*)code)->kids[0]->get_head(), os, ind, retModStr );
+ }
+ break;
+ case DO:
+ {
+ //write each of the children in sequence
+ int counter = 0;
+ while( ((CExpr*)code)->kids[counter] )
+ {
+ if( ((CExpr*)code)->kids[counter+1]==NULL )
+ {
+ write_code( ((CExpr*)code)->kids[counter], os, ind, retModStr );
+ }
+ else
+ {
+ std::string expr;
+ write_expr( ((CExpr*)code)->kids[counter], os, ind, expr );
+ //clean up memory
+ write_dec( expr, os, ind );
+ }
+ counter++;
+ }
+ }
+ break;
+ case LET:
+ {
+ indent( os, ind );
+ os << "Expr* ";
+ write_variable( ((SymSExpr*)((CExpr*)code)->kids[0])->s, os );
+ os << ";" << std::endl;
+ std::ostringstream ss;
+ write_variable( ((SymSExpr*)((CExpr*)code)->kids[0])->s, ss );
+ write_code( ((CExpr*)code)->kids[1], os, ind, ss.str().c_str() );
+ //add it to the variables
+ vars.push_back( ((SymSExpr*)((CExpr*)code)->kids[0])->s );
+ write_code( ((CExpr*)code)->kids[2], os, ind, retModStr );
+ //clean up memory
+ indent( os, ind );
+ write_variable( ((SymSExpr*)((CExpr*)code)->kids[0])->s, os );
+ os << "->dec();" << std::endl;
+ }
+ break;
+ case FAIL:
+ {
+ indent( os, ind );
+ os << retModString.c_str() << "NULL;" << std::endl;
+ }
+ break;
+#ifndef MARKVAR_32
+ case MARKVAR:
+ {
+ //calculate the value for the expression
+ std::string expr;
+ write_expr( ((CExpr*)code)->kids[0], os, ind, expr, opt_write_check_sym_expr );
+ //set the mark on the expression
+ indent( os, ind );
+ os << "if (" << expr.c_str() << "->followDefs()->getmark())" << std::endl;
+ indent( os, ind+1 );
+ os << expr.c_str() << "->followDefs()->clearmark();" << std::endl;
+ indent( os, ind );
+ os << "else" << std::endl;
+ indent( os, ind+1 );
+ os << expr.c_str() << "->followDefs()->setmark();" << std::endl;
+ //write the return if necessary
+ if( retModStr!=NULL ){
+ indent( os, ind );
+ os << retModString.c_str() << expr.c_str() << ";" << std::endl;
+ indent( os, ind );
+ os << incString.c_str() << std::endl;
+ }
+ write_dec( expr, os, ind );
+ }
+ break;
+ case IFMARKED:
+ {
+ //calculate the value for the expression
+ std::string expr;
+ write_expr( ((CExpr*)code)->kids[0], os, ind, expr, opt_write_check_sym_expr );
+ //if mark is set, write code for kids[1]
+ indent( os, ind );
+ os << "if (" << expr.c_str() << "->followDefs()->getmark()){" << std::endl;
+ write_code( ((CExpr*)code)->kids[1], os, ind+1, retModStr );
+ //else write code for kids[2]
+ indent( os, ind );
+ os << "}else{" << std::endl;
+ write_code( ((CExpr*)code)->kids[2], os, ind+1, retModStr );
+ indent( os, ind );
+ os << "}" << std::endl;
+ //clean up memory
+ write_dec( expr, os, ind );
+ }
+ break;
+#else
+ case MARKVAR:
+ {
+ //calculate the value for the expression
+ std::string expr;
+ write_expr( ((CExpr*)code)->kids[1], os, ind, expr, opt_write_check_sym_expr );
+ //set the mark on the expression
+ indent( os, ind );
+ os << "if ( ((SymExpr*)" << expr.c_str() << "->followDefs())->getmark(";
+ os << ((IntExpr*)((CExpr*)code)->kids[0])->get_num() << "))" << std::endl;
+ indent( os, ind+1 );
+ os << "((SymExpr*)" << expr.c_str() << "->followDefs())->clearmark(";
+ os << ((IntExpr*)((CExpr*)code)->kids[0])->get_num() << ");" << std::endl;
+ indent( os, ind );
+ os << "else" << std::endl;
+ indent( os, ind+1 );
+ os << "((SymExpr*)" << expr.c_str() << "->followDefs())->setmark(";
+ os << ((IntExpr*)((CExpr*)code)->kids[0])->get_num() << ");" << std::endl;
+ //write the return if necessary
+ if( retModStr!=NULL ){
+ indent( os, ind );
+ os << retModString.c_str() << expr.c_str() << ";" << std::endl;
+ indent( os, ind );
+ os << incString.c_str() << std::endl;
+ }
+ write_dec( expr, os, ind );
+ }
+ break;
+ case COMPARE:
+ {
+ std::string expr1, expr2;
+ write_expr( ((CExpr*)code)->kids[0], os, ind, expr1, opt_write_check_sym_expr );
+ write_expr( ((CExpr*)code)->kids[1], os, ind, expr2, opt_write_check_sym_expr );
+ indent( os, ind );
+ os << "if( ((SymExpr*)" << expr1.c_str() << ")->followDefs() < ((SymExpr*)" << expr2.c_str() << ")->followDefs() ){" << std::endl;
+ write_code( ((CExpr*)code)->kids[2], os, ind+1, retModStr );
+ indent( os, ind );
+ os << "}else{" << std::endl;
+ write_code( ((CExpr*)code)->kids[3], os, ind+1, retModStr );
+ indent( os, ind );
+ os << "}" << std::endl;
+ //clean up memory
+ write_dec( expr1, os, ind );
+ write_dec( expr2, os, ind );
+ }
+ break;
+ case IFMARKED:
+ {
+ //calculate the value for the expression
+ std::string expr;
+ write_expr( ((CExpr*)code)->kids[1], os, ind, expr, opt_write_check_sym_expr );
+ //if mark is set, write code for kids[1]
+ indent( os, ind );
+ os << "if ( ((SymExpr*)" << expr.c_str() << "->followDefs())->getmark(";
+ os << ((IntExpr*)((CExpr*)code)->kids[0])->get_num() << ")){" << std::endl;
+ write_code( ((CExpr*)code)->kids[2], os, ind+1, retModStr );
+ //else write code for kids[2]
+ indent( os, ind );
+ os << "}else{" << std::endl;
+ write_code( ((CExpr*)code)->kids[3], os, ind+1, retModStr );
+ indent( os, ind );
+ os << "}" << std::endl;
+ //clean up memory
+ write_dec( expr, os, ind );
+ }
+ break;
+#endif
+ case ADD:
+ case MUL:
+ case DIV:
+ {
+ //calculate the value for the first expression
+ std::string expr1;
+ write_expr( ((CExpr*)code)->kids[0], os, ind, expr1 );
+ //calculate the value for the second expression
+ std::string expr2;
+ write_expr( ((CExpr*)code)->kids[1], os, ind, expr2 );
+ std::ostringstream ss;
+ ss << "rnum" << rnumCount;
+ rnumCount++;
+ indent( os, ind );
+ os << "if( " << expr1.c_str() << "->followDefs()->getclass()==INT_EXPR ){" << std::endl;
+ indent( os, ind+1 );
+ os << "mpz_t " << ss.str().c_str() << ";" << std::endl;
+ indent( os, ind+1 );
+ os << "mpz_init(" << ss.str().c_str() << ");" << std::endl;
+ indent( os, ind+1 );
+ os << "mpz_";
+ if( code->getop()==ADD )
+ os << "add";
+ else
+ os << "mul";
+ os << "( " << ss.str().c_str() << ", ((IntExpr*)" << expr1.c_str() << "->followDefs())->n, ((IntExpr*)" << expr2.c_str() << "->followDefs())->n);" << std::endl;
+ indent( os, ind+1 );
+ os << retModString.c_str() << "new IntExpr(" << ss.str().c_str() << ");" << std::endl;
+ indent( os, ind );
+ os << "}else if( " << expr1.c_str() << "->followDefs()->getclass()==RAT_EXPR ){" << std::endl;
+ indent( os, ind+1 );
+ os << "mpq_t " << ss.str().c_str() << ";" << std::endl;
+ indent( os, ind+1 );
+ os << "mpq_init(" << ss.str().c_str() << ");" << std::endl;
+ indent( os, ind+1 );
+ os << "mpq_";
+ if( code->getop()==ADD )
+ os << "add";
+ else if( code->getop()==MUL )
+ os << "mul";
+ else
+ os << "div";
+ os << "( " << ss.str().c_str() << ", ((RatExpr*)" << expr1.c_str() << "->followDefs())->n, ((RatExpr*)" << expr2.c_str() << "->followDefs())->n);" << std::endl;
+ indent( os, ind+1 );
+ os << retModString.c_str() << "new RatExpr(" << ss.str().c_str() << ");" << std::endl;
+ indent( os, ind );
+ os << "}" << std::endl;
+ //clean up memory
+ write_dec( expr1, os, ind );
+ write_dec( expr2, os, ind );
+ }
+ break;
+ case NEG:
+ {
+ //calculate the value for the first expression
+ std::string expr1;
+ write_expr( ((CExpr*)code)->kids[0], os, ind, expr1 );
+ std::ostringstream ss;
+ ss << "rnum" << rnumCount;
+ rnumCount++;
+ indent( os, ind );
+ os << "if( " << expr1.c_str() << "->followDefs()->getclass()==INT_EXPR ){" << std::endl;
+ indent( os, ind+1 );
+ os << "mpz_t " << ss.str().c_str() << ";" << std::endl;
+ indent( os, ind+1 );
+ os << "mpz_init(" << ss.str().c_str() << ");" << std::endl;
+ indent( os, ind+1 );
+ os << "mpz_neg( " << ss.str().c_str() << ", ((IntExpr*)" << expr1.c_str() << "->followDefs())->n );" << std::endl;
+ indent( os, ind+1 );
+ os << retModString.c_str() << "new IntExpr(" << ss.str().c_str() << ");" << std::endl;
+ indent( os, ind );
+ os << "}else if( " << expr1.c_str() << "->followDefs()->getclass()==RAT_EXPR ){" << std::endl;
+ indent( os, ind+1 );
+ os << "mpq_t " << ss.str().c_str() << ";" << std::endl;
+ indent( os, ind+1 );
+ os << "mpq_init(" << ss.str().c_str() << ");" << std::endl;
+ indent( os, ind+1 );
+ os << "mpq_neg( " << ss.str().c_str() << ", ((RatExpr*)" << expr1.c_str() << "->followDefs())->n );" << std::endl;
+ indent( os, ind+1 );
+ os << retModString.c_str() << "new RatExpr(" << ss.str().c_str() << ");" << std::endl;
+ indent( os, ind );
+ os << "}" << std::endl;
+ //clean up memory
+ write_dec( expr1, os, ind );
+ }
+ break;
+ case IFNEG:
+ case IFZERO:
+ {
+ std::string expr1;
+ write_expr( ((CExpr*)code)->kids[0], os, ind, expr1 );
+ indent( os, ind );
+ os << "if( " << expr1.c_str() << "->followDefs()->getclass()==INT_EXPR ){" << std::endl;
+ indent( os, ind+1 );
+ os << "if( mpz_sgn( ((IntExpr *)" << expr1.c_str() << "->followDefs())->n ) ";
+ if( code->getop()==IFNEG )
+ os << "<";
+ else
+ os << "==";
+ os << " 0 ){" << std::endl;
+ write_code( ((CExpr*)code)->kids[1], os, ind+2, retModStr );
+ indent( os, ind+1 );
+ os << "}else{" << std::endl;
+ write_code( ((CExpr*)code)->kids[2], os, ind+2, retModStr );
+ indent( os, ind+1 );
+ os << "}" << std::endl;
+ indent( os, ind );
+ os << "}else if( " << expr1.c_str() << "->followDefs()->getclass()==RAT_EXPR ){" << std::endl;
+ indent( os, ind+1 );
+ os << "if( mpq_sgn( ((RatExpr *)" << expr1.c_str() << "->followDefs())->n ) ";
+ if( code->getop()==IFNEG )
+ os << "<";
+ else
+ os << "==";
+ os << " 0 ){" << std::endl;
+ write_code( ((CExpr*)code)->kids[1], os, ind+2, retModStr );
+ indent( os, ind+1 );
+ os << "}else{" << std::endl;
+ write_code( ((CExpr*)code)->kids[2], os, ind+2, retModStr );
+ indent( os, ind+1 );
+ os << "}" << std::endl;
+ indent( os, ind );
+ os << "}" << std::endl;
+ //clean up memory
+ write_dec( expr1, os, ind );
+ }
+ break;
+ case RUN:/*?*/break;
+ case PI:/*?*/break;
+ case LAM:/*?*/break;
+ case TYPE:/*?*/break;
+ case KIND:/*?*/break;
+ case ASCRIBE:/*?*/break;
+ case MPZ:/*?*/break;
+ case PROG:/*?*/break;
+ case PROGVARS:/*?*/break;
+ case PAT:/*?*/break;
+ }
+ break;
+ }
+}
+
+void sccwriter::write_args( CExpr* code, std::ostream& os, int ind, int childCounter,
+ std::vector< std::string >& args, int opts )
+{
+ bool encounterCase = false;
+ while( code->kids[childCounter] &&
+ (!encounterCase || code->kids[childCounter]->getop()==CASE ) )
+ {
+ encounterCase = encounterCase || code->kids[childCounter]->getop()==CASE;
+ if( code->kids[childCounter]->getclass()==SYMS_EXPR )
+ {
+ args.push_back( ((SymSExpr*)code->kids[childCounter])->s );
+ }
+ else
+ {
+ //calculate the value for the argument
+ std::string expr;
+ write_expr( code->kids[childCounter], os, ind, expr, opts );
+ args.push_back( expr );
+ }
+ childCounter++;
+ }
+}
+
+void sccwriter::write_expr( Expr* code, std::ostream& os, int ind, std::string& expr, int opts )
+{
+ if( code->getclass()==SYMS_EXPR && is_var( ((SymSExpr*)code)->s ) )
+ {
+ get_var_name( ((SymSExpr*)code)->s, expr );
+ indent( os, ind );
+ os << expr.c_str() << "->inc();" << std::endl;
+ }
+ else
+ {
+ std::ostringstream ss;
+ ss << "e" << exprCount;
+ exprCount++;
+ //declare the expression
+ indent( os, ind );
+ if( code->getclass()==SYMS_EXPR && !is_var( ((SymSExpr*)code)->s ) )
+ {
+ os << "static ";
+ }
+ os << "Expr* " << ss.str().c_str() << ";" << std::endl;
+ //write the expression
+ std::ostringstream ss2;
+ ss2 << ss.str().c_str();
+ write_code( code, os, ind, ss2.str().c_str(), opts );
+
+ //if is not a sym expression, then decrement the expression and return null
+ if( opts&opt_write_check_sym_expr )
+ {
+ indent( os, ind );
+ os << "if (" << expr.c_str() << "->getclass() != SYM_EXPR) {" << std::endl;
+ indent( os, ind+1 );
+ os << "exit( 1 );" << std::endl;
+ indent( os, ind );
+ os << "}" << std::endl;
+ }
+
+ expr = std::string( ss.str().c_str() );
+ vars.push_back( expr );
+ }
+ //increment the counter for memory management
+ //indent( os, ind );
+ //os << expr.c_str() << "->inc();" << std::endl;
+}
+
+void sccwriter::write_dec( const std::string& expr, std::ostream& os, int ind )
+{
+ bool wd = true;
+ if( wd )
+ {
+ indent( os, ind );
+ os << expr.c_str() << "->dec();" << std::endl;
+ }
+}
+
+void sccwriter::debug_write_code( Expr* code, std::ostream& os, int ind )
+{
+ indent( os, ind );
+ switch( code->getclass() )
+ {
+ case INT_EXPR:
+ os << "int_expr";
+ break;
+ case HOLE_EXPR:
+ os << "hole_expr";
+ break;
+ case SYM_EXPR:
+ os << "sym_expr";
+ break;
+ case SYMS_EXPR:
+ os << "syms_expr: " << ((SymSExpr*)code)->s.c_str();
+ break;
+ default:
+ switch( code->getop() )
+ {
+ case APP:
+ os << "app";
+ break;
+ case PI:
+ os << "pi";
+ break;
+ case LAM:
+ os << "lam";
+ break;
+ case TYPE:
+ os << "type";
+ break;
+ case KIND:
+ os << "kind";
+ break;
+ case ASCRIBE:
+ os << "ascribe";
+ break;
+ case MPZ:
+ os << "mpz";
+ break;
+ case PROG:
+ os << "prog";
+ break;
+ case PROGVARS:
+ os << "progvars";
+ break;
+ case MATCH:
+ os << "match";
+ break;
+ case CASE:
+ os << "case";
+ break;
+ case PAT:
+ os << "pat";
+ break;
+ case DO:
+ os << "do";
+ break;
+ case ADD:
+ os << "add";
+ break;
+ case NEG:
+ os << "neg";
+ break;
+ case LET:
+ os << "let";
+ break;
+ case RUN:
+ os << "run";
+ break;
+ case FAIL:
+ os << "fail";
+ break;
+ case MARKVAR:
+ os << "markvar";
+ break;
+ case IFMARKED:
+ os << "ifmarked";
+ break;
+ case COMPARE:
+ os << "compare";
+ break;
+ default:
+ os << "???";
+ break;
+ }
+ }
+ os << std::endl;
+ if( code->getop()!=0 )
+ {
+ CExpr* ce = (CExpr*)code;
+ int counter = 0;
+ while( ce->kids[counter] ){
+ debug_write_code( ce->kids[counter], os, ind+1 );
+ counter++;
+ }
+ }
+}
diff --git a/proofs/lfsc_checker/sccwriter.h b/proofs/lfsc_checker/sccwriter.h
new file mode 100644
index 000000000..f8922934f
--- /dev/null
+++ b/proofs/lfsc_checker/sccwriter.h
@@ -0,0 +1,86 @@
+#ifndef SCC_WRITER_H
+#define SCC_WRITER_H
+
+#include "expr.h"
+#include <vector>
+#include "check.h"
+
+enum
+{
+ opt_write_case_body = 0x00000001,
+ opt_write_check_sym_expr = 0x00000002,
+ opt_write_add_args = 0x000000004,
+ opt_write_no_inc = 0x00000008,
+
+ opt_write_call_debug = 0x00000010,
+ opt_write_nested_app = 0x00000020,
+};
+
+class sccwriter
+{
+private:
+ //options
+ int options;
+ //programs to write to file
+ symmap progs;
+ //list of indicies in progs
+ std::vector< Expr* > progPtrs;
+ std::vector< std::string > progNames;
+ int currProgram;
+ //current variables in the scope
+ std::vector< std::string > vars;
+ //global variables stored for lookups
+ std::vector< std::string > globalSyms;
+ //symbols that must be dec'ed
+ std::vector< std::string > decSyms;
+ //get program
+ CExpr* get_prog( int n ) { return (CExpr*)progs[ progNames[n] ]; }
+ //get index for string
+ int get_prog_index_by_expr( Expr* e );
+ int get_prog_index( const std::string& str );
+ //is variable in current scope
+ bool is_var( const std::string& str );
+ //add global sym
+ void add_global_sym( const std::string& str );
+ //expression count
+ static int exprCount;
+ //string count
+ static int strCount;
+ //args count
+ static int argsCount;
+ //num count
+ static int rnumCount;
+ //indent
+ static void indent( std::ostream& os, int ind );
+ //write function header
+ void write_function_header( std::ostream& os, int index, int opts = 0 );
+ void write_code( Expr* code, std::ostream& os, int ind, const char* retModStr, int opts = 0 );
+ //write all children starting at child counter to stream, store in Expr* e_...e_;
+ void write_args( CExpr* code, std::ostream& os, int ind, int childCounter, std::vector< std::string >& args, int opts = 0 );
+ //write expression - store result of code into e_ for some Expr* e_;
+ void write_expr( Expr* code, std::ostream& os, int ind, std::string& expr, int opts = 0 );
+ //write variable
+ void write_variable( const std::string& n, std::ostream& os );
+ //get function name
+ void get_function_name( const std::string& pname, std::string& fname );
+ //get the variable name
+ void get_var_name( const std::string& n, std::string& nn );
+ //write dec
+ void write_dec( const std::string& expr, std::ostream& os, int ind );
+public:
+ sccwriter( int opts = 0 ) : options( opts ){}
+ virtual ~sccwriter(){}
+
+ void add_scc( const std::string& pname, Expr* exp ) {
+ //progs.push_back( std::pair< std::string, CExpr* >( pname, exp ) );
+ progs[pname] = exp;
+ progPtrs.push_back( exp );
+ progNames.push_back( pname );
+ }
+
+ void write_file();
+ //write code
+ static void debug_write_code( Expr* code, std::ostream& os, int ind );
+};
+
+#endif
diff --git a/proofs/lfsc_checker/trie.cpp b/proofs/lfsc_checker/trie.cpp
new file mode 100644
index 000000000..fedb508b0
--- /dev/null
+++ b/proofs/lfsc_checker/trie.cpp
@@ -0,0 +1,24 @@
+#include "trie.h"
+#include <iostream>
+
+class Simple : public Trie<int>::Cleaner {
+public:
+ ~Simple() {}
+ void clean(int p) {
+ (void)p;
+ }
+};
+
+template <>
+Trie<int>::Cleaner *Trie<int>::cleaner = new Simple;
+
+void unit_test_trie() {
+ Trie<int> t;
+ t.insert("a", 1);
+ t.insert("b", 2);
+ t.insert("abc", 3);
+ t.insert("b", 0);
+ std::cout << "a: " << t.get("a") << "\n";
+ std::cout << "b: " << t.get("b") << "\n";
+ std::cout << "abc: " << t.get("abc") << "\n";
+}
diff --git a/proofs/lfsc_checker/trie.h b/proofs/lfsc_checker/trie.h
new file mode 100644
index 000000000..094a9060a
--- /dev/null
+++ b/proofs/lfsc_checker/trie.h
@@ -0,0 +1,129 @@
+#ifndef sc2__trie_h
+#define sc2__trie_h
+
+#include <vector>
+#include <string.h>
+#include <stdlib.h>
+
+template<class Data>
+class Trie {
+protected:
+ char *str;
+ Data d;
+ bool using_next;
+ std::vector<Trie<Data> *> next;
+
+ // s is assumed to be non-empty (and non-null)
+ Data insert_next(const char *s, const Data &x) {
+ unsigned c = s[0];
+ if (c >= next.size()) {
+ using_next = true;
+ next.resize(c+1);
+ next[c] = new Trie<Data>;
+ }
+ else if (!next[c])
+ next[c] = new Trie<Data>;
+
+ return next[c]->insert(&s[1], x);
+ }
+
+ // s is assumed to be non-empty (and non-null)
+ Data get_next(const char *s) {
+ unsigned c = s[0];
+ if (c >= next.size())
+ return Data();
+ Trie<Data> *n = next[c];
+ if (!n)
+ return Data();
+ return n->get(&s[1]);
+ }
+
+public:
+ Trie() : str(), d(), using_next(false), next() { }
+
+ ~Trie();
+
+ class Cleaner {
+ public:
+ virtual ~Cleaner() {}
+ virtual void clean(Data d) = 0;
+ };
+
+ static Cleaner *cleaner;
+
+ bool eqstr(const char *s1, const char *s2) {
+ while (*s1 && *s2) {
+ if (*s1++ != *s2++)
+ return false;
+ }
+ return (*s1 == *s2);
+ }
+
+ Data get(const char *s) {
+ if (!s[0] && (!str || !str[0]))
+ return d;
+ if (str && eqstr(str,s))
+ return d;
+ if (using_next)
+ return get_next(s);
+ return Data();
+ }
+
+ Data insert(const char *s, const Data &x) {
+ if (s[0] == 0) {
+ // we need to insert x right here.
+ if (str) {
+ if (str[0] == 0) {
+ // we need to replace d with x
+ Data old = d;
+ d = x;
+ return old;
+ }
+ // we need to push str into next.
+ (void)insert_next(str,d);
+ free(str);
+ }
+ str = strdup(s);
+ d = x;
+ return Data();
+ }
+
+ if (str) {
+ // cannot store x here
+ if (str[0] != 0) {
+ insert_next(str,d);
+ free(str);
+ str = 0;
+ d = Data();
+ }
+ return insert_next(s,x);
+ }
+
+ if (using_next)
+ // also cannot store x here
+ return insert_next(s,x);
+
+ // we can insert x here as an optimization
+ str = strdup(s);
+ d = x;
+ return Data();
+ }
+
+};
+
+template<class Data>
+Trie<Data>::~Trie()
+{
+ cleaner->clean(d);
+ for (int i = 0, iend = next.size(); i < iend; i++) {
+ Trie *t = next[i];
+ if (t)
+ delete t;
+ }
+ if (str)
+ free(str);
+}
+
+extern void unit_test_trie();
+
+#endif
diff --git a/proofs/signatures/Makefile.am b/proofs/signatures/Makefile.am
new file mode 100644
index 000000000..610990ba2
--- /dev/null
+++ b/proofs/signatures/Makefile.am
@@ -0,0 +1,34 @@
+# These CORE_PLFs are combined to give a "master signature" against
+# which proofs are checked internally when using --check-proofs. To
+# add support for more theories, just list them here in the same order
+# you would to the LFSC proof-checker binary.
+#
+CORE_PLFS = sat.plf smt.plf th_base.plf
+
+noinst_LTLIBRARIES = libsignatures.la
+
+dist_pkgdata_DATA = \
+ $(CORE_PLFS)
+
+libsignatures_la_SOURCES = \
+ signatures.cpp
+
+BUILT_SOURCES = \
+ signatures.cpp
+
+signatures.cpp: $(CORE_PLFS)
+ $(AM_V_GEN)( \
+ echo "namespace CVC4 {"; \
+ echo "namespace proof {"; \
+ echo; \
+ echo "extern const char *const plf_signatures;"; \
+ echo "const char *const plf_signatures = \"\\"; \
+ cat $+ | sed 's,\\,\\\\,g;s,",\\",g;s,$$,\\n\\,g'; \
+ echo "\";"; \
+ echo; \
+ echo "} /* CVC4::proof namespace */"; \
+ echo "} /* CVC4 namespace */"; \
+ ) > $@
+
+EXTRA_DIST = \
+ example.plf
diff --git a/proofs/signatures/example.plf b/proofs/signatures/example.plf
index 5df1f31c3..ab690eb51 100755
--- a/proofs/signatures/example.plf
+++ b/proofs/signatures/example.plf
@@ -1,116 +1,116 @@
-; to check, run : lfsc sat.plf smt.plf th_base.plf example.plf
-
-; --------------------------------------------------------------------------------
-; input :
-; ( a = b )
-; ( b = f(c) )
-; ( a != f(c) V a != b )
-
-; theory lemma (by transitivity) :
-; ( a != b V b != f(c) V a = f(c) )
-
-
-; With the theory lemma, the input is unsatisfiable.
-; --------------------------------------------------------------------------------
-
-
-
-(check
-(% s sort
-(% a (term s)
-(% b (term s)
-(% c (term s)
-(% f (term (arrow s s))
-
-; -------------------- declaration of input formula -----------------------------------
-
-(% A1 (th_holds (= s a b))
-(% A2 (th_holds (= s b (apply _ _ f c)))
-(% A3 (th_holds (or (not (= s a (apply _ _ f c))) (not (= s a b))))
-
-
-; ------------------- specify that the following is a proof of the empty clause -----------------
-
-(: (holds cln)
-
-; ---------- use atoms (a1, a2, a3) to map theory literals to boolean literals (v1, v2, v3) ------
-
-(decl_atom (= s a b) (\ v1 (\ a1
-(decl_atom (= s b (apply _ _ f c)) (\ v2 (\ a2
-(decl_atom (= s a (apply _ _ f c)) (\ v3 (\ a3
-
-
-; --------------------------- proof of theory lemma ---------------------------------------------
-
-(satlem _ _
-(ast _ _ _ a1 (\ l1
-(ast _ _ _ a2 (\ l2
-(asf _ _ _ a3 (\ l3
-(clausify_false
-
-; this should be a proof of l1 ^ l2 ^ ~l3 => false
-; this is done by theory proof rules (currently just use "trust")
-
- trust
-
-))))))) (\ CT
-; CT is the clause ( ~v1 V ~v2 V v3 )
-
-; -------------------- clausification of input formulas -----------------------------------------
-
-(satlem _ _
-(asf _ _ _ a1 (\ l1
-(clausify_false
-
-; input formula A1 is ( ~l1 )
-; the following should be a proof of l1 ^ ( ~l1 ) => false
-; this is done by natural deduction rules
-
- (contra _ A1 l1)
-
-))) (\ C1
-; C1 is the clause ( v1 )
-
-
-(satlem _ _
-(asf _ _ _ a2 (\ l2
-(clausify_false
-
-; input formula A2 is ( ~l2 )
-; the following should be a proof of l2 ^ ( ~l2 ) => false
-; this is done by natural deduction rules
-
- (contra _ A2 l2)
-
-))) (\ C2
-; C2 is the clause ( v2 )
-
-
-(satlem _ _
-(ast _ _ _ a3 (\ l3
-(ast _ _ _ a1 (\ l1
-(clausify_false
-
-; input formula A3 is ( ~a3 V ~a1 )
-; the following should be a proof of a3 ^ a1 ^ ( ~a3 V ~a1 ) => false
-; this is done by natural deduction rules
-
- (contra _ l1 (or_elim_1 _ _ (not_not_intro _ l3) A3))
-
-))))) (\ C3
-; C3 is the clause ( ~v3 V ~v1 )
-
-
-
-; -------------------- resolution proof ------------------------------------------------------------
-
-(satlem_simplify _ _ _
-
-(R _ _ C1
-(R _ _ C2
-(R _ _ CT C3 v3) v2) v1)
-
-(\ x x))
-
-))))))))))))))))))))))))))
-) \ No newline at end of file
+; to check, run : lfsc sat.plf smt.plf th_base.plf example.plf
+
+; --------------------------------------------------------------------------------
+; input :
+; ( a = b )
+; ( b = f(c) )
+; ( a != f(c) V a != b )
+
+; theory lemma (by transitivity) :
+; ( a != b V b != f(c) V a = f(c) )
+
+
+; With the theory lemma, the input is unsatisfiable.
+; --------------------------------------------------------------------------------
+
+
+
+(check
+(% s sort
+(% a (term s)
+(% b (term s)
+(% c (term s)
+(% f (term (arrow s s))
+
+; -------------------- declaration of input formula -----------------------------------
+
+(% A1 (th_holds (= s a b))
+(% A2 (th_holds (= s b (apply _ _ f c)))
+(% A3 (th_holds (or (not (= s a (apply _ _ f c))) (not (= s a b))))
+
+
+; ------------------- specify that the following is a proof of the empty clause -----------------
+
+(: (holds cln)
+
+; ---------- use atoms (a1, a2, a3) to map theory literals to boolean literals (v1, v2, v3) ------
+
+(decl_atom (= s a b) (\ v1 (\ a1
+(decl_atom (= s b (apply _ _ f c)) (\ v2 (\ a2
+(decl_atom (= s a (apply _ _ f c)) (\ v3 (\ a3
+
+
+; --------------------------- proof of theory lemma ---------------------------------------------
+
+(satlem _ _
+(ast _ _ _ a1 (\ l1
+(ast _ _ _ a2 (\ l2
+(asf _ _ _ a3 (\ l3
+(clausify_false
+
+; this should be a proof of l1 ^ l2 ^ ~l3 => false
+; this is done by theory proof rules (currently just use "trust")
+
+ trust
+
+))))))) (\ CT
+; CT is the clause ( ~v1 V ~v2 V v3 )
+
+; -------------------- clausification of input formulas -----------------------------------------
+
+(satlem _ _
+(asf _ _ _ a1 (\ l1
+(clausify_false
+
+; input formula A1 is ( ~l1 )
+; the following should be a proof of l1 ^ ( ~l1 ) => false
+; this is done by natural deduction rules
+
+ (contra _ A1 l1)
+
+))) (\ C1
+; C1 is the clause ( v1 )
+
+
+(satlem _ _
+(asf _ _ _ a2 (\ l2
+(clausify_false
+
+; input formula A2 is ( ~l2 )
+; the following should be a proof of l2 ^ ( ~l2 ) => false
+; this is done by natural deduction rules
+
+ (contra _ A2 l2)
+
+))) (\ C2
+; C2 is the clause ( v2 )
+
+
+(satlem _ _
+(ast _ _ _ a3 (\ l3
+(ast _ _ _ a1 (\ l1
+(clausify_false
+
+; input formula A3 is ( ~a3 V ~a1 )
+; the following should be a proof of a3 ^ a1 ^ ( ~a3 V ~a1 ) => false
+; this is done by natural deduction rules
+
+ (contra _ l1 (or_elim_1 _ _ (not_not_intro _ l3) A3))
+
+))))) (\ C3
+; C3 is the clause ( ~v3 V ~v1 )
+
+
+
+; -------------------- resolution proof ------------------------------------------------------------
+
+(satlem_simplify _ _ _
+
+(R _ _ C1
+(R _ _ C2
+(R _ _ CT C3 v3) v2) v1)
+
+(\ x x))
+
+))))))))))))))))))))))))))
+)
diff --git a/proofs/signatures/sat.plf b/proofs/signatures/sat.plf
index 09255f612..5e2f1cc44 100755
--- a/proofs/signatures/sat.plf
+++ b/proofs/signatures/sat.plf
@@ -1,127 +1,127 @@
-(declare bool type)
-(declare tt bool)
-(declare ff bool)
-
-(declare var type)
-
-(declare lit type)
-(declare pos (! x var lit))
-(declare neg (! x var lit))
-
-(declare clause type)
-(declare cln clause)
-(declare clc (! x lit (! c clause clause)))
-
-; constructs for general clauses for R, Q, satlem
-
-(declare concat (! c1 clause (! c2 clause clause)))
-(declare clr (! l lit (! c clause clause)))
-
-; code to check resolutions
-
-(program append ((c1 clause) (c2 clause)) clause
- (match c1 (cln c2) ((clc l c1') (clc l (append c1' c2)))))
-
-; we use marks as follows:
-; -- mark 1 to record if we are supposed to remove a positive occurrence of the variable.
-; -- mark 2 to record if we are supposed to remove a negative occurrence of the variable.
-; -- mark 3 if we did indeed remove the variable positively
-; -- mark 4 if we did indeed remove the variable negatively
-(program simplify_clause ((c clause)) clause
- (match c
- (cln cln)
- ((clc l c1)
- (match l
- ; Set mark 1 on v if it is not set, to indicate we should remove it.
- ; After processing the rest of the clause, set mark 3 if we were already
- ; supposed to remove v (so if mark 1 was set when we began). Clear mark3
- ; if we were not supposed to be removing v when we began this call.
- ((pos v)
- (let m (ifmarked v tt (do (markvar v) ff))
- (let c' (simplify_clause c1)
- (match m
- (tt (do (ifmarked3 v v (markvar3 v)) c'))
- (ff (do (ifmarked3 v (markvar3 v) v) (markvar v) (clc l c')))))))
- ; the same as the code for tt, but using different marks.
- ((neg v)
- (let m (ifmarked2 v tt (do (markvar2 v) ff))
- (let c' (simplify_clause c1)
- (match m
- (tt (do (ifmarked4 v v (markvar4 v)) c'))
- (ff (do (ifmarked4 v (markvar4 v) v) (markvar2 v) (clc l c')))))))))
- ((concat c1 c2) (append (simplify_clause c1) (simplify_clause c2)))
- ((clr l c1)
- (match l
- ; set mark 1 to indicate we should remove v, and fail if
- ; mark 3 is not set after processing the rest of the clause
- ; (we will set mark 3 if we remove a positive occurrence of v).
- ((pos v)
- (let m (ifmarked v tt (do (markvar v) ff))
- (let m3 (ifmarked3 v (do (markvar3 v) tt) ff)
- (let c' (simplify_clause c1)
- (ifmarked3 v (do (match m3 (tt v) (ff (markvar3 v)))
- (match m (tt v) (ff (markvar v))) c')
- (fail clause))))))
- ; same as the tt case, but with different marks.
- ((neg v)
- (let m2 (ifmarked2 v tt (do (markvar2 v) ff))
- (let m4 (ifmarked4 v (do (markvar4 v) tt) ff)
- (let c' (simplify_clause c1)
- (ifmarked4 v (do (match m4 (tt v) (ff (markvar4 v)))
- (match m2 (tt v) (ff (markvar2 v))) c')
- (fail clause))))))
- ))))
-
-
-; resolution proofs
-
-(declare holds (! c clause type))
-
-(declare R (! c1 clause (! c2 clause
- (! u1 (holds c1)
- (! u2 (holds c2)
- (! n var
- (holds (concat (clr (pos n) c1)
- (clr (neg n) c2)))))))))
-
-(declare Q (! c1 clause (! c2 clause
- (! u1 (holds c1)
- (! u2 (holds c2)
- (! n var
- (holds (concat (clr (neg n) c1)
- (clr (pos n) c2)))))))))
-
-(declare satlem_simplify
- (! c1 clause
- (! c2 clause
- (! c3 clause
- (! u1 (holds c1)
- (! r (^ (simplify_clause c1) c2)
- (! u2 (! x (holds c2) (holds c3))
- (holds c3))))))))
-
-(declare satlem
- (! c clause
- (! c2 clause
- (! u (holds c)
- (! u2 (! v (holds c) (holds c2))
- (holds c2))))))
-
-; A little example to demonstrate simplify_clause.
-; It can handle nested clr's of both polarities,
-; and correctly cleans up marks when it leaves a
-; clr or clc scope. Uncomment and run with
-; --show-runs to see it in action.
-;
-; (check
-; (% v1 var
-; (% u1 (holds (concat (clr (neg v1) (clr (pos v1) (clc (pos v1) (clr (pos v1) (clc (pos v1) (clc (neg v1) cln))))))
-; (clc (pos v1) (clc (pos v1) cln))))
-; (satlem _ _ _ u1 (\ x x))))))
-
-
-;(check
-; (% v1 var
-; (% u1 (holds (clr (neg v1) (concat (clc (neg v1) cln)
-; (clr (neg v1) (clc (neg v1) cln)))))
-; (satlem _ _ _ u1 (\ x x)))))) \ No newline at end of file
+(declare bool type)
+(declare tt bool)
+(declare ff bool)
+
+(declare var type)
+
+(declare lit type)
+(declare pos (! x var lit))
+(declare neg (! x var lit))
+
+(declare clause type)
+(declare cln clause)
+(declare clc (! x lit (! c clause clause)))
+
+; constructs for general clauses for R, Q, satlem
+
+(declare concat (! c1 clause (! c2 clause clause)))
+(declare clr (! l lit (! c clause clause)))
+
+; code to check resolutions
+
+(program append ((c1 clause) (c2 clause)) clause
+ (match c1 (cln c2) ((clc l c1') (clc l (append c1' c2)))))
+
+; we use marks as follows:
+; -- mark 1 to record if we are supposed to remove a positive occurrence of the variable.
+; -- mark 2 to record if we are supposed to remove a negative occurrence of the variable.
+; -- mark 3 if we did indeed remove the variable positively
+; -- mark 4 if we did indeed remove the variable negatively
+(program simplify_clause ((c clause)) clause
+ (match c
+ (cln cln)
+ ((clc l c1)
+ (match l
+ ; Set mark 1 on v if it is not set, to indicate we should remove it.
+ ; After processing the rest of the clause, set mark 3 if we were already
+ ; supposed to remove v (so if mark 1 was set when we began). Clear mark3
+ ; if we were not supposed to be removing v when we began this call.
+ ((pos v)
+ (let m (ifmarked v tt (do (markvar v) ff))
+ (let c' (simplify_clause c1)
+ (match m
+ (tt (do (ifmarked3 v v (markvar3 v)) c'))
+ (ff (do (ifmarked3 v (markvar3 v) v) (markvar v) (clc l c')))))))
+ ; the same as the code for tt, but using different marks.
+ ((neg v)
+ (let m (ifmarked2 v tt (do (markvar2 v) ff))
+ (let c' (simplify_clause c1)
+ (match m
+ (tt (do (ifmarked4 v v (markvar4 v)) c'))
+ (ff (do (ifmarked4 v (markvar4 v) v) (markvar2 v) (clc l c')))))))))
+ ((concat c1 c2) (append (simplify_clause c1) (simplify_clause c2)))
+ ((clr l c1)
+ (match l
+ ; set mark 1 to indicate we should remove v, and fail if
+ ; mark 3 is not set after processing the rest of the clause
+ ; (we will set mark 3 if we remove a positive occurrence of v).
+ ((pos v)
+ (let m (ifmarked v tt (do (markvar v) ff))
+ (let m3 (ifmarked3 v (do (markvar3 v) tt) ff)
+ (let c' (simplify_clause c1)
+ (ifmarked3 v (do (match m3 (tt v) (ff (markvar3 v)))
+ (match m (tt v) (ff (markvar v))) c')
+ (fail clause))))))
+ ; same as the tt case, but with different marks.
+ ((neg v)
+ (let m2 (ifmarked2 v tt (do (markvar2 v) ff))
+ (let m4 (ifmarked4 v (do (markvar4 v) tt) ff)
+ (let c' (simplify_clause c1)
+ (ifmarked4 v (do (match m4 (tt v) (ff (markvar4 v)))
+ (match m2 (tt v) (ff (markvar2 v))) c')
+ (fail clause))))))
+ ))))
+
+
+; resolution proofs
+
+(declare holds (! c clause type))
+
+(declare R (! c1 clause (! c2 clause
+ (! u1 (holds c1)
+ (! u2 (holds c2)
+ (! n var
+ (holds (concat (clr (pos n) c1)
+ (clr (neg n) c2)))))))))
+
+(declare Q (! c1 clause (! c2 clause
+ (! u1 (holds c1)
+ (! u2 (holds c2)
+ (! n var
+ (holds (concat (clr (neg n) c1)
+ (clr (pos n) c2)))))))))
+
+(declare satlem_simplify
+ (! c1 clause
+ (! c2 clause
+ (! c3 clause
+ (! u1 (holds c1)
+ (! r (^ (simplify_clause c1) c2)
+ (! u2 (! x (holds c2) (holds c3))
+ (holds c3))))))))
+
+(declare satlem
+ (! c clause
+ (! c2 clause
+ (! u (holds c)
+ (! u2 (! v (holds c) (holds c2))
+ (holds c2))))))
+
+; A little example to demonstrate simplify_clause.
+; It can handle nested clr's of both polarities,
+; and correctly cleans up marks when it leaves a
+; clr or clc scope. Uncomment and run with
+; --show-runs to see it in action.
+;
+; (check
+; (% v1 var
+; (% u1 (holds (concat (clr (neg v1) (clr (pos v1) (clc (pos v1) (clr (pos v1) (clc (pos v1) (clc (neg v1) cln))))))
+; (clc (pos v1) (clc (pos v1) cln))))
+; (satlem _ _ _ u1 (\ x x))))))
+
+
+;(check
+; (% v1 var
+; (% u1 (holds (clr (neg v1) (concat (clc (neg v1) cln)
+; (clr (neg v1) (clc (neg v1) cln)))))
+; (satlem _ _ _ u1 (\ x x))))))
diff --git a/proofs/signatures/smt.plf b/proofs/signatures/smt.plf
index 75bfc442f..bbee2d49b 100755
--- a/proofs/signatures/smt.plf
+++ b/proofs/signatures/smt.plf
@@ -3,15 +3,14 @@
; SMT syntax and semantics (not theory-specific)
;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+; depends on sat.plf
(declare formula type)
(declare th_holds (! f formula type))
-; constants
+; standard logic definitions
(declare true formula)
(declare false formula)
-
-; logical connectives
(declare not (! f formula formula))
(declare and (! f1 formula (! f2 formula formula)))
(declare or (! f1 formula (! f2 formula formula)))
@@ -21,24 +20,19 @@
(declare ifte (! b formula (! f1 formula (! f2 formula formula))))
; terms
-(declare sort type) ; sort in the theory
-(declare arrow (! s1 sort (! s2 sort sort))) ; function constructor
-
+(declare sort type)
(declare term (! t sort type)) ; declared terms in formula
-(declare apply (! s1 sort
- (! s2 sort
- (! t1 (term (arrow s1 s2))
- (! t2 (term s1)
- (term s2))))))
-
+; standard definitions for =, ite, let and flet
+(declare = (! s sort
+ (! x (term s)
+ (! y (term s)
+ formula))))
(declare ite (! s sort
(! f formula
(! t1 (term s)
(! t2 (term s)
(term s))))))
-
-; let/flet
(declare let (! s sort
(! t (term s)
(! f (! v (term s) formula)
@@ -47,38 +41,52 @@
(! f2 (! v formula formula)
formula)))
-; predicates
-(declare = (! s sort
- (! x (term s)
- (! y (term s)
- formula))))
-
-; To avoid duplicating some of the rules (e.g., cong), we will view
-; applications of predicates as terms of sort "Bool".
+; We view applications of predicates as terms of sort "Bool".
; Such terms can be injected as atomic formulas using "p_app".
-
(declare Bool sort) ; the special sort for predicates
(declare p_app (! x (term Bool) formula)) ; propositional application of term
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
-; Examples
+;
+; CNF Clausification
+;
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+
+; binding between an LF var and an (atomic) formula
+(declare atom (! v var (! p formula type)))
+
+(declare decl_atom
+ (! f formula
+ (! u (! v var
+ (! a (atom v f)
+ (holds cln)))
+ (holds cln))))
-; an example of "(p1 or p2(0)) and t1=t2(1)"
-;(! p1 (term Bool)
-;(! p2 (term (arrow Int Bool))
-;(! t1 (term Int)
-;(! t2 (term (arrow Int Int))
-;(! F (th_holds (and (or (p_app p1) (p_app (apply _ _ p2 0)))
-; (= _ t1 (apply _ _ t2 1))))
-; ...
+; clausify a formula directly
+(declare clausify_form
+ (! f formula
+ (! v var
+ (! a (atom v f)
+ (! u (th_holds f)
+ (holds (clc (pos v) cln)))))))
+
+(declare clausify_form_not
+ (! f formula
+ (! v var
+ (! a (atom v f)
+ (! u (th_holds (not f))
+ (holds (clc (neg v) cln)))))))
+
+(declare clausify_false
+ (! u (th_holds false)
+ (holds cln)))
-; another example of "p3(a,b)"
-;(! a (term Int)
-;(! b (term Int)
-;(! p3 (term (arrow Int (arrow Int Bool))) ; arrow is right assoc.
-;(! F (th_holds (p_app (apply _ _ (apply _ _ p3 a) b))) ; apply is left assoc.
-; ...
+(declare th_let_pf
+ (! f formula
+ (! u (th_holds f)
+ (! u2 (! v (th_holds f) (holds cln))
+ (holds cln)))))
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
@@ -102,7 +110,7 @@
(! f formula
(! u (th_holds f)
(th_holds (not (not f))))))
-
+
(declare not_not_elim
(! f formula
(! u (th_holds (not (not f)))
@@ -116,14 +124,14 @@
(! u1 (th_holds (not f1))
(! u2 (th_holds (or f1 f2))
(th_holds f2))))))
-
+
(declare or_elim_2
(! f1 formula
(! f2 formula
(! u1 (th_holds (not f2))
(! u2 (th_holds (or f1 f2))
(th_holds f1))))))
-
+
;; and elimination
(declare and_elim_1
@@ -131,13 +139,13 @@
(! f2 formula
(! u (th_holds (and f1 f2))
(th_holds f1)))))
-
+
(declare and_elim_2
(! f1 formula
(! f2 formula
(! u (th_holds (and f1 f2))
(th_holds f2)))))
-
+
;; not impl elimination
(declare not_impl_elim_1
@@ -145,18 +153,18 @@
(! f2 formula
(! u (th_holds (not (impl f1 f2)))
(th_holds f1)))))
-
+
(declare not_impl_elim_2
(! f1 formula
(! f2 formula
(! u (th_holds (not (impl f1 f2)))
(th_holds (not f2))))))
-
+
;; impl elimination
(declare impl_intro (! f1 formula
(! f2 formula
- (! i1 (! u (th_holds f1)
+ (! i1 (! u (th_holds f1)
(th_holds f2))
(th_holds (impl f1 f2))))))
@@ -164,9 +172,9 @@
(! f1 formula
(! f2 formula
(! u1 (th_holds f1)
- (! u2 (th_holds (impl f1 f2))
+ (! u2 (th_holds (impl f1 f2))
(th_holds f2))))))
-
+
;; iff elimination
(declare iff_elim_1
@@ -174,7 +182,7 @@
(! f2 formula
(! u1 (th_holds (iff f1 f2))
(th_holds (impl f1 f2))))))
-
+
(declare iff_elim_2
(! f1 formula
(! f2 formula
@@ -204,7 +212,7 @@
(! u1 (th_holds a)
(! u2 (th_holds (ifte a b c))
(th_holds b)))))))
-
+
(declare ite_elim_2
(! a formula
(! b formula
@@ -212,7 +220,7 @@
(! u1 (th_holds (not a))
(! u2 (th_holds (ifte a b c))
(th_holds c)))))))
-
+
(declare ite_elim_3
(! a formula
(! b formula
@@ -220,7 +228,7 @@
(! u1 (th_holds (not b))
(! u2 (th_holds (ifte a b c))
(th_holds c)))))))
-
+
(declare ite_elim_2n
(! a formula
(! b formula
@@ -236,7 +244,7 @@
(! u1 (th_holds a)
(! u2 (th_holds (not (ifte a b c)))
(th_holds (not b))))))))
-
+
(declare not_ite_elim_2
(! a formula
(! b formula
@@ -244,7 +252,7 @@
(! u1 (th_holds (not a))
(! u2 (th_holds (not (ifte a b c)))
(th_holds (not c))))))))
-
+
(declare not_ite_elim_3
(! a formula
(! b formula
@@ -252,7 +260,7 @@
(! u1 (th_holds b)
(! u2 (th_holds (not (ifte a b c)))
(th_holds (not c))))))))
-
+
(declare not_ite_elim_2n
(! a formula
(! b formula
@@ -260,14 +268,42 @@
(! u1 (th_holds a)
(! u2 (th_holds (not (ifte (not a) b c)))
(th_holds (not c))))))))
+
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+;
+; For theory lemmas
+; - make a series of assumptions and then derive a contradiction (or false)
+; - then the assumptions yield a formula like "v1 -> v2 -> ... -> vn -> false"
+; - In CNF, it becomes a clause: "~v1, ~v2, ..., ~vn"
+;
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+
+(declare ast
+ (! v var
+ (! f formula
+ (! C clause
+ (! r (atom v f) ;this is specified
+ (! u (! o (th_holds f)
+ (holds C))
+ (holds (clc (neg v) C))))))))
+
+(declare asf
+ (! v var
+ (! f formula
+ (! C clause
+ (! r (atom v f)
+ (! u (! o (th_holds (not f))
+ (holds C))
+ (holds (clc (pos v) C))))))))
-
-
-;; How to do CNF for disjunctions of theory literals.
+
+
+
+;; Example:
;;
-;; Given theory literals F1....Fn, and an input formula A of the form (th_holds (or F1 (or F2 .... (or F{n-1} Fn))))).
+;; Given theory literals (F1....Fn), and an input formula A of the form (th_holds (or F1 (or F2 .... (or F{n-1} Fn))))).
;;
-;; We introduce atoms a1...an for literals F1...Fn, mapping them to boolean literals v1...vn.
+;; We introduce atoms (a1,...,an) to map boolean literals (v1,...,vn) top literals (F1,...,Fn).
;; Do this at the beginning of the proof:
;;
;; (decl_atom F1 (\ v1 (\ a1
@@ -275,7 +311,7 @@
;; ....
;; (decl_atom Fn (\ vn (\ an
;;
-;; Our input A is clausified by the following proof:
+;; A is then clausified by the following proof:
;;
;;(satlem _ _
;;(asf _ _ _ a1 (\ l1
@@ -287,14 +323,14 @@
;; (contra _
;; (or_elim_1 _ _ l{n-1}
;; ...
-;; (or_elim_1 _ _ l2
+;; (or_elim_1 _ _ l2
;; (or_elim_1 _ _ l1 A))))) ln)
;;
;;))))))) (\ C
;;
;; We now have the free variable C, which should be the clause (v1 V ... V vn).
;;
-;; We also need to consider the polarity of literals, say we have A of the form (th_holds (or (not F1) (or F2 (not F3)))).
+;; Polarity of literals should be considered, say we have A of the form (th_holds (or (not F1) (or F2 (not F3)))).
;; Where necessary, we use "ast" instead of "asf", introduce negations by "not_not_intro" for pattern matching, and flip
;; the arguments of contra:
;;
@@ -305,9 +341,11 @@
;;(clausify_false
;;
;; (contra _ l3
-;; (or_elim_1 _ _ l2
+;; (or_elim_1 _ _ l2
;; (or_elim_1 _ _ (not_not_intro l1) A))))
;;
;;))))))) (\ C
;;
-;; C should be the clause (~v1 V v2 V ~v3 ) \ No newline at end of file
+;; C should be the clause (~v1 V v2 V ~v3 )
+
+
diff --git a/proofs/signatures/th_arrays.plf b/proofs/signatures/th_arrays.plf
new file mode 100755
index 000000000..6e0e6438d
--- /dev/null
+++ b/proofs/signatures/th_arrays.plf
@@ -0,0 +1,53 @@
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+;
+; Theory of Arrays
+;
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+; depdends on : th_base.plf
+
+; sorts
+
+(declare array (! s1 sort (! s2 sort sort))) ; s1 is index, s2 is element
+
+; functions
+(declare write (! s1 sort
+ (! s2 sort
+ (! t1 (term (array s1 s2))
+ (! t2 (term s1)
+ (! t3 (term s2)
+ (term (array s1 s2))))))))
+(declare read (! s1 sort
+ (! s2 sort
+ (! t1 (term (array s1 s2))
+ (! t2 (term s1)
+ (term s2))))))
+
+; inference rules
+(declare row1 (! s1 sort
+ (! s2 sort
+ (! t1 (term (array s1 s2))
+ (! t2 (term s1)
+ (! t3 (term s2)
+ (th_holds (= _ (read (write t1 t2 t3) t2) t3))))))))
+
+
+(declare row (! s1 sort
+ (! s2 sort
+ (! t1 (term (array s1 s2))
+ (! t2 (term s1)
+ (! t3 (term s1)
+ (! t4 (term s2)
+ (! u (th_holds (not (= _ t2 t3)))
+ (th_holds (= _ (read (write t1 t2 t4) t3) (read t1 t3))))))))))
+
+(declare ext (! s1 sort
+ (! s2 sort
+ (! f formula
+ (! t1 (term (array s1 s2))
+ (! t2 (term (array s1 s2))
+ (! u (th_holds (not (= _ t1 t2)))
+ (! u1 (! k (term s1)
+ (! u2 (th_holds (not (= _ (read t1 k) (read t2 k))))
+ (th_holds f)))
+ (th_holds f)))))))))
+ \ No newline at end of file
diff --git a/proofs/signatures/th_base.plf b/proofs/signatures/th_base.plf
index e66990de4..977409b6a 100755
--- a/proofs/signatures/th_base.plf
+++ b/proofs/signatures/th_base.plf
@@ -1,107 +1,73 @@
-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
-;
-; Atomization / Clausification
-;
-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
-
-; binding between an LF var and an (atomic) formula
-(declare atom (! v var (! p formula type)))
-
-(declare decl_atom
- (! f formula
- (! u (! v var
- (! a (atom v f)
- (holds cln)))
- (holds cln))))
-
-; direct clausify
-(declare clausify_form
- (! f formula
- (! v var
- (! a (atom v f)
- (! u (th_holds f)
- (holds (clc (pos v) cln)))))))
-
-(declare clausify_form_not
- (! f formula
- (! v var
- (! a (atom v f)
- (! u (th_holds (not f))
- (holds (clc (neg v) cln)))))))
-
-(declare clausify_false
- (! u (th_holds false)
- (holds cln)))
-
-
-(declare th_let_pf
- (! f formula
- (! u (th_holds f)
- (! u2 (! v (th_holds f) (holds cln))
- (holds cln)))))
-
-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
-;
-; Theory reasoning
-; - make a series of assumptions and then derive a contradiction (or false)
-; - then the assumptions yield a formula like "v1 -> v2 -> ... -> vn -> false"
-; - In CNF, it becomes a clause: "~v1, ~v2, ..., ~vn"
-;
-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
-
-(declare ast
- (! v var
- (! f formula
- (! C clause
- (! r (atom v f) ;this is specified
- (! u (! o (th_holds f)
- (holds C))
- (holds (clc (neg v) C))))))))
-
-(declare asf
- (! v var
- (! f formula
- (! C clause
- (! r (atom v f)
- (! u (! o (th_holds (not f))
- (holds C))
- (holds (clc (pos v) C))))))))
-
-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
-;
-; Theory of Equality and Congruence Closure
-;
-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
-
-; temporary :
-(declare trust (th_holds false))
-
-(declare refl
- (! s sort
- (! t (term s)
- (th_holds (= s t t)))))
-
-(declare symm (! s sort
- (! x (term s)
- (! y (term s)
- (! u (th_holds (= _ x y))
- (th_holds (= _ y x)))))))
-
-(declare trans (! s sort
- (! x (term s)
- (! y (term s)
- (! z (term s)
- (! u (th_holds (= _ x y))
- (! u (th_holds (= _ y z))
- (th_holds (= _ x z)))))))))
-
-(declare cong (! s1 sort
- (! s2 sort
- (! a1 (term (arrow s1 s2))
- (! b1 (term (arrow s1 s2))
- (! a2 (term s1)
- (! b2 (term s1)
- (! u1 (th_holds (= _ a1 b1))
- (! u2 (th_holds (= _ a2 b2))
- (th_holds (= _ (apply _ _ a1 a2) (apply _ _ b1 b2))))))))))))
-
+
+
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+;
+; Theory of Equality and Congruence Closure
+;
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+; depends on : smt.plf
+
+; sorts :
+
+(declare arrow (! s1 sort (! s2 sort sort))) ; function constructor
+
+; functions :
+
+(declare apply (! s1 sort
+ (! s2 sort
+ (! t1 (term (arrow s1 s2))
+ (! t2 (term s1)
+ (term s2))))))
+
+
+; inference rules :
+
+(declare trust (th_holds false)) ; temporary
+
+(declare refl
+ (! s sort
+ (! t (term s)
+ (th_holds (= s t t)))))
+
+(declare symm (! s sort
+ (! x (term s)
+ (! y (term s)
+ (! u (th_holds (= _ x y))
+ (th_holds (= _ y x)))))))
+
+(declare trans (! s sort
+ (! x (term s)
+ (! y (term s)
+ (! z (term s)
+ (! u (th_holds (= _ x y))
+ (! u (th_holds (= _ y z))
+ (th_holds (= _ x z)))))))))
+
+(declare cong (! s1 sort
+ (! s2 sort
+ (! a1 (term (arrow s1 s2))
+ (! b1 (term (arrow s1 s2))
+ (! a2 (term s1)
+ (! b2 (term s1)
+ (! u1 (th_holds (= _ a1 b1))
+ (! u2 (th_holds (= _ a2 b2))
+ (th_holds (= _ (apply _ _ a1 a2) (apply _ _ b1 b2))))))))))))
+
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+; Examples
+
+; an example of "(p1 or p2(0)) and t1=t2(1)"
+;(! p1 (term Bool)
+;(! p2 (term (arrow Int Bool))
+;(! t1 (term Int)
+;(! t2 (term (arrow Int Int))
+;(! F (th_holds (and (or (p_app p1) (p_app (apply _ _ p2 0)))
+; (= _ t1 (apply _ _ t2 1))))
+; ...
+
+; another example of "p3(a,b)"
+;(! a (term Int)
+;(! b (term Int)
+;(! p3 (term (arrow Int (arrow Int Bool))) ; arrow is right assoc.
+;(! F (th_holds (p_app (apply _ _ (apply _ _ p3 a) b))) ; apply is left assoc.
+; ...
diff --git a/src/Makefile.am b/src/Makefile.am
index 3637cb089..eda6acd6b 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -16,7 +16,7 @@ AM_CPPFLAGS = \
-D__BUILDING_CVC4LIB \
-D __STDC_LIMIT_MACROS \
-D __STDC_FORMAT_MACROS \
- -I@builddir@ -I@srcdir@/include -I@srcdir@
+ -I@builddir@ -I@srcdir@/include -I@srcdir@ -I@top_srcdir@/proofs/lfsc_checker
AM_CXXFLAGS = -Wall -Wno-unknown-pragmas -Wno-parentheses $(FLAG_VISIBILITY_HIDDEN)
SUBDIRS = lib options expr util prop/minisat prop/bvminisat . parser compat bindings main
@@ -104,6 +104,7 @@ libcvc4_la_SOURCES = \
prop/sat_solver_registry.cpp \
prop/options_handlers.h \
smt/smt_engine.cpp \
+ smt/smt_engine_check_proof.cpp \
smt/smt_engine.h \
smt/model_postprocessor.cpp \
smt/model_postprocessor.h \
@@ -290,6 +291,8 @@ libcvc4_la_SOURCES = \
theory/quantifiers/relevant_domain.cpp \
theory/quantifiers/symmetry_breaking.h \
theory/quantifiers/symmetry_breaking.cpp \
+ theory/quantifiers/qinterval_builder.h \
+ theory/quantifiers/qinterval_builder.cpp \
theory/quantifiers/options_handlers.h \
theory/rewriterules/theory_rewriterules_rules.h \
theory/rewriterules/theory_rewriterules_rules.cpp \
@@ -393,6 +396,11 @@ libcvc4_la_LIBADD = \
@builddir@/expr/libexpr.la \
@builddir@/prop/minisat/libminisat.la \
@builddir@/prop/bvminisat/libbvminisat.la
+if CVC4_PROOF
+libcvc4_la_LIBADD += \
+ @top_builddir@/proofs/lfsc_checker/liblfsc_checker.la \
+ @top_builddir@/proofs/signatures/libsignatures.la
+endif
if CVC4_NEEDS_REPLACEMENT_FUNCTIONS
libcvc4_la_LIBADD += \
diff --git a/src/cvc4.i b/src/cvc4.i
index ec3aa43cb..aadbc374d 100644
--- a/src/cvc4.i
+++ b/src/cvc4.i
@@ -269,6 +269,7 @@ std::set<JavaInputStreamAdapter*> CVC4::JavaInputStreamAdapter::s_adapters;
%include "util/record.i"
%include "util/regexp.i"
%include "util/uninterpreted_constant.i"
+%include "util/proof.i"
%include "expr/kind.i"
%include "expr/expr.i"
diff --git a/src/main/command_executor.cpp b/src/main/command_executor.cpp
index 467b150d3..485a478d8 100644
--- a/src/main/command_executor.cpp
+++ b/src/main/command_executor.cpp
@@ -76,14 +76,20 @@ bool CommandExecutor::doCommandSingleton(Command* cmd)
if(q != NULL) {
d_result = res = q->getResult();
}
- // dump the model if option is set
- if( status &&
- d_options[options::produceModels] &&
- d_options[options::dumpModels] &&
- ( res.asSatisfiabilityResult() == Result::SAT ||
- (res.isUnknown() && res.whyUnknown() == Result::INCOMPLETE) ) ) {
- Command* gm = new GetModelCommand();
- status = doCommandSingleton(gm);
+ // dump the model/proof if option is set
+ if(status) {
+ if( d_options[options::produceModels] &&
+ d_options[options::dumpModels] &&
+ ( res.asSatisfiabilityResult() == Result::SAT ||
+ (res.isUnknown() && res.whyUnknown() == Result::INCOMPLETE) ) ) {
+ Command* gm = new GetModelCommand();
+ status = doCommandSingleton(gm);
+ } else if( d_options[options::proof] &&
+ d_options[options::dumpProofs] &&
+ res.asSatisfiabilityResult() == Result::UNSAT ) {
+ Command* gp = new GetProofCommand();
+ status = doCommandSingleton(gp);
+ }
}
return status;
}
diff --git a/src/main/command_executor_portfolio.cpp b/src/main/command_executor_portfolio.cpp
index 971aa2131..24469c668 100644
--- a/src/main/command_executor_portfolio.cpp
+++ b/src/main/command_executor_portfolio.cpp
@@ -213,7 +213,6 @@ bool CommandExecutorPortfolio::doCommandSingleton(Command* cmd)
if(d_lastWinner != 0) delete cmdExported;
return ret;
} else if(mode == 1) { // portfolio
-
d_seq->addCommand(cmd->clone());
// We currently don't support changing number of threads for each
@@ -327,7 +326,26 @@ bool CommandExecutorPortfolio::doCommandSingleton(Command* cmd)
lemmaSharingCleanup();
delete[] fns;
- return portfolioReturn.second;
+
+ bool status = portfolioReturn.second;
+
+ // dump the model/proof if option is set
+ if(status) {
+ if( d_options[options::produceModels] &&
+ d_options[options::dumpModels] &&
+ ( d_result.asSatisfiabilityResult() == Result::SAT ||
+ (d_result.isUnknown() && d_result.whyUnknown() == Result::INCOMPLETE) ) ) {
+ Command* gm = new GetModelCommand();
+ status = doCommandSingleton(gm);
+ } else if( d_options[options::proof] &&
+ d_options[options::dumpProofs] &&
+ d_result.asSatisfiabilityResult() == Result::UNSAT ) {
+ Command* gp = new GetProofCommand();
+ status = doCommandSingleton(gp);
+ }
+ }
+
+ return status;
} else if(mode == 2) {
Command* cmdExported =
d_lastWinner == 0 ?
diff --git a/src/main/driver_unified.cpp b/src/main/driver_unified.cpp
index d1baaa2e9..bf66629dd 100644
--- a/src/main/driver_unified.cpp
+++ b/src/main/driver_unified.cpp
@@ -108,6 +108,10 @@ int runCvc4(int argc, char* argv[], Options& opts) {
! opts[options::threadArgv].empty() ) {
throw OptionException("Thread options cannot be used with sequential CVC4. Please build and use the portfolio binary `pcvc4'.");
}
+# else
+ if( opts[options::checkProofs] ) {
+ throw OptionException("Cannot run portfolio in check-proofs mode.");
+ }
# endif
progName = opts[options::binary_name].c_str();
@@ -201,8 +205,7 @@ int runCvc4(int argc, char* argv[], Options& opts) {
<< "Notice: ...the experimental --incremental-parallel option.\n";
exprMgr = new ExprManager(opts);
pExecutor = new CommandExecutor(*exprMgr, opts);
- }
- else {
+ } else {
exprMgr = new ExprManager(threadOpts[0]);
pExecutor = new CommandExecutorPortfolio(*exprMgr, opts, threadOpts);
}
diff --git a/src/options/mkoptions b/src/options/mkoptions
index 65a49afa6..087af0ef6 100755
--- a/src/options/mkoptions
+++ b/src/options/mkoptions
@@ -241,6 +241,7 @@ function handle_option {
predicates=
links=
links_alternate=
+ smt_links=
options_already_documented=false
alternate_options_already_documented=false
@@ -412,10 +413,28 @@ function handle_option {
links_alternate="${links_alternate} $(echo "${args[$i]}" | sed 's,[^/]*/,,')"
else
links="${links} ${args[$i]}"
- links_alternate="${links_alternate} ${args[$i]}"
fi
done
;;
+ :link-smt)
+ j=0
+ while [ $(($i+1)) -lt ${#args[@]} ] && ! expr "${args[$(($i+1))]}" : '\:' &>/dev/null; do
+ let ++i
+ let ++j
+ if [ $j -eq 3 ]; then
+ echo "$kf:$lineno: error: attribute :link-smt can only take two arguments" >&2
+ exit 1
+ fi
+ if expr "${args[$i]}" : '.*/' &>/dev/null; then
+ echo "$kf:$lineno: error: attribute :link-smt cannot take alternates" >&2
+ exit 1
+ fi
+ smt_links="${smt_links} ${args[$i]}"
+ done
+ if [ $j -eq 1 ]; then
+ smt_links="${smt_links} \"true\""
+ fi
+ ;;
:include)
while [ $(($i+1)) -lt ${#args[@]} ] && ! expr "${args[$(($i+1))]}" : '\:' &>/dev/null; do
let ++i
@@ -544,14 +563,33 @@ template <> bool Options::wasSetByUser(options::${internal}__option_t) const { r
fi
run_links=
run_links_alternate=
+ run_smt_links=
+ if [ -n "$links" -a -z "$smt_links" -a -n "$smtname" ]; then
+ echo "$kf:$lineno: warning: $smtname has no :link-smt, but equivalent command-line has :link" >&2
+ elif [ -n "$smt_links" -a -z "$links" ] && [ -n "$short_option" -o -n "$short_option_alternate" -o -n "$long_option" -o "$long_option_alternate" ]; then
+ echo "$kf:$lineno: warning: $smtname has a :link-smt, but equivalent command-line has no :link" >&2
+ fi
if [ -n "$links" ]; then
+ # command-line links
for link in $links; do
run_links="$run_links
#line $lineno \"$kf\"
preemptGetopt(extra_argc, extra_argv, \"$link\");"
done
fi
+ if [ -n "$smt_links" ]; then
+ # smt links
+ smt_links=($smt_links)
+ i=0
+ while [ $i -lt ${#smt_links[@]} ]; do
+ run_smt_links="$run_smt_links
+#line $lineno \"$kf\"
+ smt->setOption(std::string(\"${smt_links[$i]}\"), SExpr(${smt_links[$(($i+1))]}));"
+ i=$((i+2))
+ done
+ fi
if [ -n "$links_alternate" ]; then
+ # command-line links
for link in $links_alternate; do
run_links_alternate="$run_links_alternate
#line $lineno \"$kf\"
@@ -732,7 +770,7 @@ template <> options::${internal}__option_t::type runHandlerAndPredicates(options
#line $lineno \"$kf\"
if(key == \"$smtname\") {
#line $lineno \"$kf\"
- Options::current().assignBool(options::$internal, \"$smtname\", optionarg == \"true\", smt);$run_links
+ Options::current().assignBool(options::$internal, \"$smtname\", optionarg == \"true\", smt);$run_smt_links
return;
}"
elif [ -n "$expect_arg" -a "$internal" != - ]; then
@@ -749,7 +787,7 @@ template <> options::${internal}__option_t::type runHandlerAndPredicates(options
#line $lineno \"$kf\"
if(key == \"$smtname\") {
#line $lineno \"$kf\"
- Options::current().assign(options::$internal, \"$smtname\", optionarg, smt);$run_links
+ Options::current().assign(options::$internal, \"$smtname\", optionarg, smt);$run_smt_links
return;
}"
elif [ -n "$expect_arg" ]; then
@@ -764,7 +802,7 @@ template <> options::${internal}__option_t::type runHandlerAndPredicates(options
#line $lineno \"$kf\"
if(key == \"$smtname\") {
#line $lineno \"$kf\"
- $run_handlers$run_links
+ $run_handlers$run_smt_links
return;
}"
else
@@ -779,7 +817,7 @@ template <> options::${internal}__option_t::type runHandlerAndPredicates(options
#line $lineno \"$kf\"
if(key == \"$smtname\") {
#line $lineno \"$kf\"
- $run_handlers$run_links
+ $run_handlers$run_smt_links
return;
}"
fi
diff --git a/src/parser/smt2/Smt2.g b/src/parser/smt2/Smt2.g
index 022c4a069..39329e424 100644
--- a/src/parser/smt2/Smt2.g
+++ b/src/parser/smt2/Smt2.g
@@ -1252,6 +1252,8 @@ builtinOp[CVC4::Kind& kind]
| STRCON_TOK { $kind = CVC4::kind::STRING_CONCAT; }
| STRLEN_TOK { $kind = CVC4::kind::STRING_LENGTH; }
| STRSUB_TOK { $kind = CVC4::kind::STRING_SUBSTR; }
+ | STRCTN_TOK { $kind = CVC4::kind::STRING_STRCTN; }
+ | STRCAT_TOK { $kind = CVC4::kind::STRING_CHARAT; }
| STRINRE_TOK { $kind = CVC4::kind::STRING_IN_REGEXP; }
| STRTORE_TOK { $kind = CVC4::kind::STRING_TO_REGEXP; }
| RECON_TOK { $kind = CVC4::kind::REGEXP_CONCAT; }
@@ -1625,7 +1627,11 @@ INT2BV_TOK : 'int2bv';
//STRCST_TOK : 'str.cst';
STRCON_TOK : 'str.++';
STRLEN_TOK : 'str.len';
-STRSUB_TOK : 'str.sub' ;
+STRSUB_TOK : 'str.substr' ;
+STRCTN_TOK : 'str.contain' ;
+STRCAT_TOK : 'str.at' ;
+//STRIDOF_TOK : 'str.indexof' ;
+//STRREPL_TOK : 'str.repalce' ;
STRINRE_TOK : 'str.in.re';
STRTORE_TOK : 'str.to.re';
RECON_TOK : 're.++';
diff --git a/src/printer/ast/ast_printer.cpp b/src/printer/ast/ast_printer.cpp
index 8ab5c121d..72bfa5603 100644
--- a/src/printer/ast/ast_printer.cpp
+++ b/src/printer/ast/ast_printer.cpp
@@ -153,6 +153,7 @@ void AstPrinter::toStream(std::ostream& out, const Command* c,
tryToStream<GetModelCommand>(out, c) ||
tryToStream<GetAssignmentCommand>(out, c) ||
tryToStream<GetAssertionsCommand>(out, c) ||
+ tryToStream<GetProofCommand>(out, c) ||
tryToStream<SetBenchmarkStatusCommand>(out, c) ||
tryToStream<SetBenchmarkLogicCommand>(out, c) ||
tryToStream<SetInfoCommand>(out, c) ||
@@ -307,6 +308,9 @@ static void toStream(std::ostream& out, const GetAssignmentCommand* c) throw() {
static void toStream(std::ostream& out, const GetAssertionsCommand* c) throw() {
out << "GetAssertions()";
}
+static void toStream(std::ostream& out, const GetProofCommand* c) throw() {
+ out << "GetProof()";
+}
static void toStream(std::ostream& out, const SetBenchmarkStatusCommand* c) throw() {
out << "SetBenchmarkStatus(" << c->getStatus() << ")";
}
diff --git a/src/printer/cvc/cvc_printer.cpp b/src/printer/cvc/cvc_printer.cpp
index b0dfbbd67..ca463d10b 100644
--- a/src/printer/cvc/cvc_printer.cpp
+++ b/src/printer/cvc/cvc_printer.cpp
@@ -776,6 +776,7 @@ void CvcPrinter::toStream(std::ostream& out, const Command* c,
tryToStream<GetModelCommand>(out, c) ||
tryToStream<GetAssignmentCommand>(out, c) ||
tryToStream<GetAssertionsCommand>(out, c) ||
+ tryToStream<GetProofCommand>(out, c) ||
tryToStream<SetBenchmarkStatusCommand>(out, c) ||
tryToStream<SetBenchmarkLogicCommand>(out, c) ||
tryToStream<SetInfoCommand>(out, c) ||
@@ -1031,6 +1032,10 @@ static void toStream(std::ostream& out, const GetAssertionsCommand* c) throw() {
out << "WHERE;";
}
+static void toStream(std::ostream& out, const GetProofCommand* c) throw() {
+ out << "DUMP_PROOF;";
+}
+
static void toStream(std::ostream& out, const SetBenchmarkStatusCommand* c) throw() {
out << "% (set-info :status " << c->getStatus() << ")";
}
diff --git a/src/printer/smt2/smt2_printer.cpp b/src/printer/smt2/smt2_printer.cpp
index b743ba70e..c56d87da6 100644
--- a/src/printer/smt2/smt2_printer.cpp
+++ b/src/printer/smt2/smt2_printer.cpp
@@ -577,6 +577,7 @@ void Smt2Printer::toStream(std::ostream& out, const Command* c,
tryToStream<GetModelCommand>(out, c) ||
tryToStream<GetAssignmentCommand>(out, c) ||
tryToStream<GetAssertionsCommand>(out, c) ||
+ tryToStream<GetProofCommand>(out, c) ||
tryToStream<SetBenchmarkStatusCommand>(out, c) ||
tryToStream<SetBenchmarkLogicCommand>(out, c) ||
tryToStream<SetInfoCommand>(out, c) ||
@@ -858,6 +859,10 @@ static void toStream(std::ostream& out, const GetAssertionsCommand* c) throw() {
out << "(get-assertions)";
}
+static void toStream(std::ostream& out, const GetProofCommand* c) throw() {
+ out << "(get-proof)";
+}
+
static void toStream(std::ostream& out, const SetBenchmarkStatusCommand* c) throw() {
out << "(set-info :status " << c->getStatus() << ")";
}
diff --git a/src/proof/cnf_proof.cpp b/src/proof/cnf_proof.cpp
index 8e9c4cd21..39e802b62 100644
--- a/src/proof/cnf_proof.cpp
+++ b/src/proof/cnf_proof.cpp
@@ -32,37 +32,45 @@ CnfProof::CnfProof(CnfStream* stream)
Expr CnfProof::getAtom(prop::SatVariable var) {
- prop::SatLiteral lit (var);
- Node node = d_cnfStream->getNode(lit);
+ prop::SatLiteral lit (var);
+ Node node = d_cnfStream->getNode(lit);
Expr atom = node.toExpr();
- return atom;
+ return atom;
}
CnfProof::~CnfProof() {
}
+LFSCCnfProof::iterator LFSCCnfProof::begin_atom_mapping() {
+ return iterator(*this, ProofManager::currentPM()->begin_vars());
+}
+
+LFSCCnfProof::iterator LFSCCnfProof::end_atom_mapping() {
+ return iterator(*this, ProofManager::currentPM()->end_vars());
+}
+
void LFSCCnfProof::printAtomMapping(std::ostream& os, std::ostream& paren) {
ProofManager::var_iterator it = ProofManager::currentPM()->begin_vars();
ProofManager::var_iterator end = ProofManager::currentPM()->end_vars();
-
+
for (;it != end; ++it) {
os << "(decl_atom ";
-
+
if (ProofManager::currentPM()->getLogic().compare("QF_UF") == 0) {
Expr atom = getAtom(*it);
- LFSCTheoryProof::printFormula(atom, os);
+ LFSCTheoryProof::printTerm(atom, os);
} else {
// print fake atoms for all other logics
- os << "true ";
+ os << "true ";
}
os << " (\\ " << ProofManager::getVarName(*it) << " (\\ " << ProofManager::getAtomName(*it) << "\n";
- paren << ")))";
+ paren << ")))";
}
}
void LFSCCnfProof::printClauses(std::ostream& os, std::ostream& paren) {
- printInputClauses(os, paren);
+ printInputClauses(os, paren);
printTheoryLemmas(os, paren);
}
@@ -70,51 +78,49 @@ void LFSCCnfProof::printInputClauses(std::ostream& os, std::ostream& paren) {
os << " ;; Input Clauses \n";
ProofManager::clause_iterator it = ProofManager::currentPM()->begin_input_clauses();
ProofManager::clause_iterator end = ProofManager::currentPM()->end_input_clauses();
-
+
for (; it != end; ++it) {
ClauseId id = it->first;
const prop::SatClause* clause = it->second;
os << "(satlem _ _ ";
- std::ostringstream clause_paren;
+ std::ostringstream clause_paren;
printClause(*clause, os, clause_paren);
os << " (clausify_false trust)" << clause_paren.str();
- os << "( \\ " << ProofManager::getInputClauseName(id) << "\n";
- paren << "))";
+ os << "( \\ " << ProofManager::getInputClauseName(id) << "\n";
+ paren << "))";
}
}
void LFSCCnfProof::printTheoryLemmas(std::ostream& os, std::ostream& paren) {
- os << " ;; Theory Lemmas \n";
+ os << " ;; Theory Lemmas \n";
ProofManager::clause_iterator it = ProofManager::currentPM()->begin_lemmas();
ProofManager::clause_iterator end = ProofManager::currentPM()->end_lemmas();
-
+
for (; it != end; ++it) {
ClauseId id = it->first;
const prop::SatClause* clause = it->second;
os << "(satlem _ _ ";
- std::ostringstream clause_paren;
+ std::ostringstream clause_paren;
printClause(*clause, os, clause_paren);
os << " (clausify_false trust)" << clause_paren.str();
- os << "( \\ " << ProofManager::getLemmaClauseName(id) <<"\n";
- paren << "))";
+ os << "( \\ " << ProofManager::getLemmaClauseName(id) <<"\n";
+ paren << "))";
}
}
void LFSCCnfProof::printClause(const prop::SatClause& clause, std::ostream& os, std::ostream& paren) {
for (unsigned i = 0; i < clause.size(); ++i) {
prop::SatLiteral lit = clause[i];
- prop::SatVariable var = lit.getSatVariable();
+ prop::SatVariable var = lit.getSatVariable();
if (lit.isNegated()) {
os << "(ast _ _ _ " << ProofManager::getAtomName(var) <<" (\\ " << ProofManager::getLitName(lit) << " ";
- paren << "))";
+ paren << "))";
} else {
os << "(asf _ _ _ " << ProofManager::getAtomName(var) <<" (\\ " << ProofManager::getLitName(lit) << " ";
- paren << "))";
+ paren << "))";
}
}
}
-
} /* CVC4 namespace */
-
diff --git a/src/proof/cnf_proof.h b/src/proof/cnf_proof.h
index 9a2dbe655..0a932f906 100644
--- a/src/proof/cnf_proof.h
+++ b/src/proof/cnf_proof.h
@@ -13,7 +13,7 @@
**
** A manager for CnfProofs.
**
- **
+ **
**/
#ifndef __CVC4__CNF_PROOF_H
@@ -25,36 +25,68 @@
#include <ext/hash_set>
#include <ext/hash_map>
-#include <iostream>
+#include <iostream>
namespace CVC4 {
namespace prop {
-class CnfStream;
+ class CnfStream;
}
+class CnfProof;
+
+class AtomIterator {
+ CnfProof& d_cnf;
+ ProofManager::var_iterator d_it;
+
+public:
+ AtomIterator(CnfProof& cnf, const ProofManager::var_iterator& it)
+ : d_cnf(cnf), d_it(it)
+ {}
+ inline Expr operator*();
+ AtomIterator& operator++() { ++d_it; return *this; }
+ AtomIterator operator++(int) { AtomIterator x = *this; ++d_it; return x; }
+ bool operator==(const AtomIterator& it) const { return &d_cnf == &it.d_cnf && d_it == it.d_it; }
+ bool operator!=(const AtomIterator& it) const { return !(*this == it); }
+};/* class AtomIterator */
+
class CnfProof {
protected:
CVC4::prop::CnfStream* d_cnfStream;
Expr getAtom(prop::SatVariable var);
+ friend class AtomIterator;
public:
CnfProof(CVC4::prop::CnfStream* cnfStream);
+ typedef AtomIterator iterator;
+ virtual iterator begin_atom_mapping() = 0;
+ virtual iterator end_atom_mapping() = 0;
+
virtual void printAtomMapping(std::ostream& os, std::ostream& paren) = 0;
virtual void printClauses(std::ostream& os, std::ostream& paren) = 0;
- virtual ~CnfProof();
+ virtual ~CnfProof();
};
-class LFSCCnfProof: public CnfProof {
+class LFSCCnfProof : public CnfProof {
void printInputClauses(std::ostream& os, std::ostream& paren);
void printTheoryLemmas(std::ostream& os, std::ostream& paren);
void printClause(const prop::SatClause& clause, std::ostream& os, std::ostream& paren);
+
public:
LFSCCnfProof(CVC4::prop::CnfStream* cnfStream)
: CnfProof(cnfStream)
{}
+
+ virtual iterator begin_atom_mapping();
+ virtual iterator end_atom_mapping();
+
virtual void printAtomMapping(std::ostream& os, std::ostream& paren);
virtual void printClauses(std::ostream& os, std::ostream& paren);
};
+inline Expr AtomIterator::operator*() {
+ return d_cnf.getAtom(*d_it);
+}
+
} /* CVC4 namespace */
+
#endif /* __CVC4__CNF_PROOF_H */
diff --git a/src/proof/proof.h b/src/proof/proof.h
index 02f8f7684..e3b776cce 100644
--- a/src/proof/proof.h
+++ b/src/proof/proof.h
@@ -23,7 +23,7 @@
#ifdef CVC4_PROOF
# define PROOF(x) if(options::proof()) { x; }
-# define NULLPROOF(x) (options::proof())? x : NULL
+# define NULLPROOF(x) (options::proof()) ? x : NULL
# define PROOF_ON() options::proof()
#else /* CVC4_PROOF */
# define PROOF(x)
diff --git a/src/proof/proof_manager.cpp b/src/proof/proof_manager.cpp
index 110e6b79a..14a82b17b 100644
--- a/src/proof/proof_manager.cpp
+++ b/src/proof/proof_manager.cpp
@@ -28,14 +28,10 @@ namespace CVC4 {
std::string append(const std::string& str, uint64_t num) {
std::ostringstream os;
- os << str << num;
- return os.str();
+ os << str << num;
+ return os.str();
}
-
-bool ProofManager::isInitialized = false;
-ProofManager* ProofManager::proofManager = NULL;
-
ProofManager::ProofManager(ProofFormat format):
d_satProof(NULL),
d_cnfProof(NULL),
@@ -50,41 +46,43 @@ ProofManager::~ProofManager() {
delete d_cnfProof;
delete d_theoryProof;
delete d_fullProof;
- for (IdToClause::iterator it = d_inputClauses.begin(); it != d_inputClauses.end(); ++it) {
- delete it->second;
+
+ for(IdToClause::iterator it = d_inputClauses.begin();
+ it != d_inputClauses.end();
+ ++it) {
+ delete it->second;
}
- for (IdToClause::iterator it = d_theoryLemmas.begin(); it != d_theoryLemmas.end(); ++it) {
- delete it->second;
+
+ for(IdToClause::iterator it = d_theoryLemmas.begin();
+ it != d_theoryLemmas.end();
+ ++it) {
+ delete it->second;
}
- // FIXME: memory leak because there are deleted theory lemmas that were not used in the
- // SatProof
+
+ // FIXME: memory leak because there are deleted theory lemmas that
+ // were not used in the SatProof
}
ProofManager* ProofManager::currentPM() {
- if (isInitialized) {
- return proofManager;
- } else {
- proofManager = new ProofManager();
- isInitialized = true;
- return proofManager;
- }
+ return smt::currentProofManager();
}
Proof* ProofManager::getProof(SmtEngine* smt) {
- if (currentPM()->d_fullProof != NULL)
+ if (currentPM()->d_fullProof != NULL) {
return currentPM()->d_fullProof;
+ }
Assert (currentPM()->d_format == LFSC);
currentPM()->d_fullProof = new LFSCProof(smt,
(LFSCSatProof*)getSatProof(),
(LFSCCnfProof*)getCnfProof(),
- (LFSCTheoryProof*)getTheoryProof());
+ (LFSCTheoryProof*)getTheoryProof());
return currentPM()->d_fullProof;
}
SatProof* ProofManager::getSatProof() {
Assert (currentPM()->d_satProof);
- return currentPM()->d_satProof;
+ return currentPM()->d_satProof;
}
CnfProof* ProofManager::getCnfProof() {
@@ -107,7 +105,7 @@ void ProofManager::initSatProof(Minisat::Solver* solver) {
void ProofManager::initCnfProof(prop::CnfStream* cnfStream) {
Assert (currentPM()->d_cnfProof == NULL);
Assert (currentPM()->d_format == LFSC);
- currentPM()->d_cnfProof = new LFSCCnfProof(cnfStream);
+ currentPM()->d_cnfProof = new LFSCCnfProof(cnfStream);
}
void ProofManager::initTheoryProof() {
@@ -126,8 +124,8 @@ std::string ProofManager::getLitName(prop::SatLiteral lit) {return append("l", l
void ProofManager::addClause(ClauseId id, const prop::SatClause* clause, ClauseKind kind) {
for (unsigned i = 0; i < clause->size(); ++i) {
- prop::SatLiteral lit = clause->operator[](i);
- d_propVars.insert(lit.getSatVariable());
+ prop::SatLiteral lit = clause->operator[](i);
+ d_propVars.insert(lit.getSatVariable());
}
if (kind == INPUT) {
d_inputClauses.insert(std::make_pair(id, clause));
@@ -138,11 +136,11 @@ void ProofManager::addClause(ClauseId id, const prop::SatClause* clause, ClauseK
}
void ProofManager::addAssertion(Expr formula) {
- d_inputFormulas.insert(formula);
+ d_inputFormulas.insert(formula);
}
void ProofManager::setLogic(const std::string& logic_string) {
- d_logic = logic_string;
+ d_logic = logic_string;
}
@@ -158,17 +156,24 @@ LFSCProof::LFSCProof(SmtEngine* smtEngine, LFSCSatProof* sat, LFSCCnfProof* cnf,
void LFSCProof::toStream(std::ostream& out) {
smt::SmtScope scope(d_smtEngine);
std::ostringstream paren;
- out << "(check \n";
- if (ProofManager::currentPM()->getLogic().compare("QF_UF") == 0) {
- d_theoryProof->printAssertions(out, paren);
+ out << "(check\n";
+ if (d_theoryProof == NULL) {
+ d_theoryProof = new LFSCTheoryProof();
+ }
+ for(LFSCCnfProof::iterator i = d_cnfProof->begin_atom_mapping();
+ i != d_cnfProof->end_atom_mapping();
+ ++i) {
+ d_theoryProof->addDeclaration(*i);
}
- out << "(: (holds cln) \n";
+ d_theoryProof->printAssertions(out, paren);
+ out << "(: (holds cln)\n";
d_cnfProof->printAtomMapping(out, paren);
d_cnfProof->printClauses(out, paren);
- d_satProof->printResolutions(out, paren);
+ d_satProof->printResolutions(out, paren);
paren <<")))\n;;";
- out << paren.str();
+ out << paren.str();
+ out << "\n";
}
-} /* CVC4 namespace */
+} /* CVC4 namespace */
diff --git a/src/proof/proof_manager.h b/src/proof/proof_manager.h
index e33f1a63f..ab8a7b2bc 100644
--- a/src/proof/proof_manager.h
+++ b/src/proof/proof_manager.h
@@ -9,11 +9,9 @@
** See the file COPYING in the top-level source directory for licensing
** information.\endverbatim
**
- ** \brief A manager for Proofs.
+ ** \brief A manager for Proofs
**
** A manager for Proofs.
- **
- **
**/
#include "cvc4_private.h"
@@ -21,7 +19,7 @@
#ifndef __CVC4__PROOF_MANAGER_H
#define __CVC4__PROOF_MANAGER_H
-#include <iostream>
+#include <iostream>
#include "proof/proof.h"
#include "util/proof.h"
@@ -29,15 +27,15 @@
// forward declarations
namespace Minisat {
class Solver;
-}
+}/* Minisat namespace */
namespace CVC4 {
namespace prop {
class CnfStream;
-}
+}/* CVC4::prop namespace */
-class SmtEngine;
+class SmtEngine;
typedef int ClauseId;
@@ -51,10 +49,10 @@ class LFSCCnfProof;
class LFSCTheoryProof;
namespace prop {
-typedef uint64_t SatVariable;
-class SatLiteral;
-typedef std::vector<SatLiteral> SatClause;
-}
+ typedef uint64_t SatVariable;
+ class SatLiteral;
+ typedef std::vector<SatLiteral> SatClause;
+}/* CVC4::prop namespace */
// different proof modes
enum ProofFormat {
@@ -64,7 +62,7 @@ enum ProofFormat {
std::string append(const std::string& str, uint64_t num);
-typedef __gnu_cxx::hash_map < ClauseId, const prop::SatClause* > IdToClause;
+typedef __gnu_cxx::hash_map < ClauseId, const prop::SatClause* > IdToClause;
typedef __gnu_cxx::hash_set<prop::SatVariable > VarSet;
typedef __gnu_cxx::hash_set<Expr, ExprHashFunction > ExprSet;
@@ -74,35 +72,36 @@ enum ClauseKind {
INPUT,
THEORY_LEMMA,
LEARNT
-};
+};/* enum ClauseKind */
class ProofManager {
SatProof* d_satProof;
CnfProof* d_cnfProof;
- TheoryProof* d_theoryProof;
+ TheoryProof* d_theoryProof;
// information that will need to be shared across proofs
IdToClause d_inputClauses;
IdToClause d_theoryLemmas;
ExprSet d_inputFormulas;
VarSet d_propVars;
-
- Proof* d_fullProof;
+
+ Proof* d_fullProof;
ProofFormat d_format;
-
- static ProofManager* proofManager;
- static bool isInitialized;
- ProofManager(ProofFormat format = LFSC);
- ~ProofManager();
+
protected:
std::string d_logic;
+
public:
+ ProofManager(ProofFormat format = LFSC);
+ ~ProofManager();
+
static ProofManager* currentPM();
- // initialization
- static void initSatProof(Minisat::Solver* solver);
+
+ // initialization
+ static void initSatProof(Minisat::Solver* solver);
static void initCnfProof(CVC4::prop::CnfStream* cnfStream);
static void initTheoryProof();
-
+
static Proof* getProof(SmtEngine* smt);
static SatProof* getSatProof();
static CnfProof* getCnfProof();
@@ -110,9 +109,9 @@ public:
// iterators over data shared by proofs
typedef IdToClause::const_iterator clause_iterator;
- typedef ExprSet::const_iterator assertions_iterator;
+ typedef ExprSet::const_iterator assertions_iterator;
typedef VarSet::const_iterator var_iterator;
-
+
clause_iterator begin_input_clauses() const { return d_inputClauses.begin(); }
clause_iterator end_input_clauses() const { return d_inputClauses.end(); }
@@ -124,10 +123,10 @@ public:
var_iterator begin_vars() const { return d_propVars.begin(); }
var_iterator end_vars() const { return d_propVars.end(); }
-
+
void addAssertion(Expr formula);
- void addClause(ClauseId id, const prop::SatClause* clause, ClauseKind kind);
-
+ void addClause(ClauseId id, const prop::SatClause* clause, ClauseKind kind);
+
// variable prefixes
static std::string getInputClauseName(ClauseId id);
static std::string getLemmaClauseName(ClauseId id);
@@ -136,7 +135,7 @@ public:
static std::string getVarName(prop::SatVariable var);
static std::string getAtomName(prop::SatVariable var);
static std::string getLitName(prop::SatLiteral lit);
-
+
void setLogic(const std::string& logic_string);
const std::string getLogic() const { return d_logic; }
};/* class ProofManager */
@@ -145,13 +144,13 @@ class LFSCProof : public Proof {
LFSCSatProof* d_satProof;
LFSCCnfProof* d_cnfProof;
LFSCTheoryProof* d_theoryProof;
- SmtEngine* d_smtEngine;
+ SmtEngine* d_smtEngine;
public:
- LFSCProof(SmtEngine* smtEngine, LFSCSatProof* sat, LFSCCnfProof* cnf, LFSCTheoryProof* theory);
+ LFSCProof(SmtEngine* smtEngine, LFSCSatProof* sat, LFSCCnfProof* cnf, LFSCTheoryProof* theory);
virtual void toStream(std::ostream& out);
virtual ~LFSCProof() {}
-};
-
+};/* class LFSCProof */
+
}/* CVC4 namespace */
#endif /* __CVC4__PROOF_MANAGER_H */
diff --git a/src/proof/sat_proof.cpp b/src/proof/sat_proof.cpp
index da9df0d42..3b5509ffb 100644
--- a/src/proof/sat_proof.cpp
+++ b/src/proof/sat_proof.cpp
@@ -25,7 +25,7 @@ using namespace Minisat;
using namespace CVC4::prop;
namespace CVC4 {
-/// some helper functions
+/// some helper functions
void printLit (Minisat::Lit l) {
Debug("proof:sat") << (sign(l) ? "-" : "") << var(l) + 1;
@@ -33,16 +33,16 @@ void printLit (Minisat::Lit l) {
void printClause (Minisat::Clause& c) {
for (int i = 0; i < c.size(); i++) {
- Debug("proof:sat") << (sign(c[i]) ? "-" : "") << var(c[i]) + 1 << " ";
+ Debug("proof:sat") << (sign(c[i]) ? "-" : "") << var(c[i]) + 1 << " ";
}
}
void printLitSet(const LitSet& s) {
for(LitSet::iterator it = s.begin(); it != s.end(); ++it) {
printLit(*it);
- Debug("proof:sat") << " ";
+ Debug("proof:sat") << " ";
}
- Debug("proof:sat") << endl;
+ Debug("proof:sat") << endl;
}
// purely debugging functions
@@ -52,39 +52,38 @@ void printDebug (Minisat::Lit l) {
void printDebug (Minisat::Clause& c) {
for (int i = 0; i < c.size(); i++) {
- Debug("proof:sat") << (sign(c[i]) ? "-" : "") << var(c[i]) + 1 << " ";
+ Debug("proof:sat") << (sign(c[i]) ? "-" : "") << var(c[i]) + 1 << " ";
}
Debug("proof:sat") << endl;
}
-int SatProof::d_idCounter = 0;
+int SatProof::d_idCounter = 0;
-/**
+/**
* Converts the clause associated to id to a set of literals
- *
+ *
* @param id the clause id
- * @param set the clause converted to a set of literals
+ * @param set the clause converted to a set of literals
*/
void SatProof::createLitSet(ClauseId id, LitSet& set) {
- Assert (set.empty());
+ Assert(set.empty());
if(isUnit(id)) {
set.insert(getUnit(id));
return;
}
if ( id == d_emptyClauseId) {
- return;
+ return;
}
CRef ref = getClauseRef(id);
- Assert (ref != CRef_Undef);
- Clause& c = d_solver->ca[ref];
+ Clause& c = getClause(ref);
for (int i = 0; i < c.size(); i++) {
- set.insert(c[i]);
+ set.insert(c[i]);
}
}
-/**
+/**
* Resolves clause1 and clause2 on variable var and stores the
* result in clause1
* @param v
@@ -93,36 +92,40 @@ void SatProof::createLitSet(ClauseId id, LitSet& set) {
*/
bool resolve(const Lit v, LitSet& clause1, LitSet& clause2, bool s) {
Assert(!clause1.empty());
- Assert(!clause2.empty());
- Lit var = sign(v) ? ~v : v;
+ Assert(!clause2.empty());
+ Lit var = sign(v) ? ~v : v;
if (s) {
// literal appears positive in the first clause
if( !clause2.count(~var)) {
- Debug("proof:sat") << "proof:resolve: Missing literal ";
- printLit(var);
- Debug("proof:sat") << endl;
- return false;
+ if(Debug.isOn("proof:sat")) {
+ Debug("proof:sat") << "proof:resolve: Missing literal ";
+ printLit(var);
+ Debug("proof:sat") << endl;
+ }
+ return false;
}
clause1.erase(var);
clause2.erase(~var);
for (LitSet::iterator it = clause2.begin(); it!= clause2.end(); ++it) {
- clause1.insert(*it);
+ clause1.insert(*it);
}
} else {
// literal appears negative in the first clause
if( !clause1.count(~var) || !clause2.count(var)) {
- Debug("proof:sat") << "proof:resolve: Missing literal ";
- printLit(var);
- Debug("proof:sat") << endl;
- return false;
+ if(Debug.isOn("proof:sat")) {
+ Debug("proof:sat") << "proof:resolve: Missing literal ";
+ printLit(var);
+ Debug("proof:sat") << endl;
+ }
+ return false;
}
clause1.erase(~var);
clause2.erase(var);
for (LitSet::iterator it = clause2.begin(); it!= clause2.end(); ++it) {
- clause1.insert(*it);
+ clause1.insert(*it);
}
}
- return true;
+ return true;
}
/// ResChain
@@ -135,16 +138,16 @@ ResChain::ResChain(ClauseId start) :
void ResChain::addStep(Lit lit, ClauseId id, bool sign) {
ResStep step(lit, id, sign);
- d_steps.push_back(step);
+ d_steps.push_back(step);
}
void ResChain::addRedundantLit(Lit lit) {
if (d_redundantLits) {
- d_redundantLits->insert(lit);
+ d_redundantLits->insert(lit);
} else {
d_redundantLits = new LitSet();
- d_redundantLits->insert(lit);
+ d_redundantLits->insert(lit);
}
}
@@ -156,7 +159,7 @@ ProofProxy::ProofProxy(SatProof* proof):
{}
void ProofProxy::updateCRef(CRef oldref, CRef newref) {
- d_proof->updateCRef(oldref, newref);
+ d_proof->updateCRef(oldref, newref);
}
@@ -183,27 +186,27 @@ SatProof::SatProof(Minisat::Solver* solver, bool checkRes) :
d_seenInput(),
d_seenLemmas()
{
- d_proxy = new ProofProxy(this);
+ d_proxy = new ProofProxy(this);
}
-/**
+/**
* Returns true if the resolution chain corresponding to id
* does resolve to the clause associated to id
- * @param id
- *
- * @return
+ * @param id
+ *
+ * @return
*/
bool SatProof::checkResolution(ClauseId id) {
if(d_checkRes) {
- bool validRes = true;
- Assert (d_resChains.find(id) != d_resChains.end());
+ bool validRes = true;
+ Assert(d_resChains.find(id) != d_resChains.end());
ResChain* res = d_resChains[id];
LitSet clause1;
createLitSet(res->getStart(), clause1);
- ResSteps& steps = res->getSteps();
+ ResSteps& steps = res->getSteps();
for (unsigned i = 0; i < steps.size(); i++) {
Lit var = steps[i].lit;
- LitSet clause2;
+ LitSet clause2;
createLitSet (steps[i].id, clause2);
bool res = resolve (var, clause1, clause2, steps[i].sign);
if(res == false) {
@@ -215,35 +218,38 @@ bool SatProof::checkResolution(ClauseId id) {
if (isUnit(id)) {
// special case if it was a unit clause
Lit unit = getUnit(id);
- validRes = clause1.size() == clause1.count(unit) && !clause1.empty();
- return validRes;
+ validRes = clause1.size() == clause1.count(unit) && !clause1.empty();
+ return validRes;
}
if (id == d_emptyClauseId) {
- return clause1.empty();
+ return clause1.empty();
}
CRef ref = getClauseRef(id);
- Assert (ref != CRef_Undef);
- Clause& c = d_solver->ca[ref];
+ Clause& c = getClause(ref);
for (int i = 0; i < c.size(); ++i) {
int count = clause1.erase(c[i]);
if (count == 0) {
- Debug("proof:sat") << "proof:checkResolution::literal not in computed result ";
- printLit(c[i]);
- Debug("proof:sat") << "\n";
- validRes = false;
+ if(Debug.isOn("proof:sat")) {
+ Debug("proof:sat") << "proof:checkResolution::literal not in computed result ";
+ printLit(c[i]);
+ Debug("proof:sat") << "\n";
+ }
+ validRes = false;
}
}
validRes = clause1.empty();
if (! validRes) {
- Debug("proof:sat") << "proof:checkResolution::Invalid Resolution, unremoved literals: \n";
- printLitSet(clause1);
- Debug("proof:sat") << "proof:checkResolution:: result should be: \n";
- printClause(c);
+ if(Debug.isOn("proof:sat")) {
+ Debug("proof:sat") << "proof:checkResolution::Invalid Resolution, unremoved literals: \n";
+ printLitSet(clause1);
+ Debug("proof:sat") << "proof:checkResolution:: result should be: \n";
+ printClause(c);
+ }
}
- return validRes;
-
+ return validRes;
+
} else {
- return true;
+ return true;
}
}
@@ -254,16 +260,16 @@ bool SatProof::checkResolution(ClauseId id) {
ClauseId SatProof::getClauseId(::Minisat::CRef ref) {
if(d_clauseId.find(ref) == d_clauseId.end()) {
- Debug("proof:sat") << "Missing clause \n";
+ Debug("proof:sat") << "Missing clause \n";
}
Assert(d_clauseId.find(ref) != d_clauseId.end());
- return d_clauseId[ref];
+ return d_clauseId[ref];
}
ClauseId SatProof::getClauseId(::Minisat::Lit lit) {
Assert(d_unitId.find(toInt(lit)) != d_unitId.end());
- return d_unitId[toInt(lit)];
+ return d_unitId[toInt(lit)];
}
Minisat::CRef SatProof::getClauseRef(ClauseId id) {
@@ -273,79 +279,85 @@ Minisat::CRef SatProof::getClauseRef(ClauseId id) {
<< (isUnit(id)? "Unit" : "") << endl;
}
Assert(d_idClause.find(id) != d_idClause.end());
- return d_idClause[id];
+ return d_idClause[id];
}
Clause& SatProof::getClause(CRef ref) {
- return d_solver->ca[ref];
+ Assert(ref != CRef_Undef);
+ Assert(ref >= 0 && ref < d_solver->ca.size());
+ return d_solver->ca[ref];
}
+
Minisat::Lit SatProof::getUnit(ClauseId id) {
- Assert (d_idUnit.find(id) != d_idUnit.end());
- return d_idUnit[id];
+ Assert(d_idUnit.find(id) != d_idUnit.end());
+ return d_idUnit[id];
}
bool SatProof::isUnit(ClauseId id) {
- return d_idUnit.find(id) != d_idUnit.end();
+ return d_idUnit.find(id) != d_idUnit.end();
}
bool SatProof::isUnit(::Minisat::Lit lit) {
- return d_unitId.find(toInt(lit)) != d_unitId.end();
+ return d_unitId.find(toInt(lit)) != d_unitId.end();
}
ClauseId SatProof::getUnitId(::Minisat::Lit lit) {
- Assert(isUnit(lit));
- return d_unitId[toInt(lit)];
+ Assert(isUnit(lit));
+ return d_unitId[toInt(lit)];
}
bool SatProof::hasResolution(ClauseId id) {
- return d_resChains.find(id) != d_resChains.end();
+ return d_resChains.find(id) != d_resChains.end();
}
bool SatProof::isInputClause(ClauseId id) {
- return (d_inputClauses.find(id) != d_inputClauses.end());
+ return (d_inputClauses.find(id) != d_inputClauses.end());
}
bool SatProof::isLemmaClause(ClauseId id) {
- return (d_lemmaClauses.find(id) != d_lemmaClauses.end());
+ return (d_lemmaClauses.find(id) != d_lemmaClauses.end());
}
void SatProof::print(ClauseId id) {
if (d_deleted.find(id) != d_deleted.end()) {
- Debug("proof:sat") << "del"<<id;
+ Debug("proof:sat") << "del"<<id;
} else if (isUnit(id)) {
- printLit(getUnit(id));
+ printLit(getUnit(id));
} else if (id == d_emptyClauseId) {
- Debug("proof:sat") << "empty "<< endl;
+ Debug("proof:sat") << "empty "<< endl;
}
else {
- CRef ref = getClauseRef(id);
- Assert (ref != CRef_Undef);
- printClause(d_solver->ca[ref]);
+ CRef ref = getClauseRef(id);
+ printClause(getClause(ref));
}
}
void SatProof::printRes(ClauseId id) {
Assert(hasResolution(id));
Debug("proof:sat") << "id "<< id <<": ";
- printRes(d_resChains[id]);
+ printRes(d_resChains[id]);
}
void SatProof::printRes(ResChain* res) {
ClauseId start_id = res->getStart();
- Debug("proof:sat") << "(";
- print(start_id);
+ if(Debug.isOn("proof:sat")) {
+ Debug("proof:sat") << "(";
+ print(start_id);
+ }
ResSteps& steps = res->getSteps();
for(unsigned i = 0; i < steps.size(); i++ ) {
Lit v = steps[i].lit;
ClauseId id = steps[i].id;
- Debug("proof:sat") << "[";
- printLit(v);
- Debug("proof:sat") << "] ";
- print(id);
+ if(Debug.isOn("proof:sat")) {
+ Debug("proof:sat") << "[";
+ printLit(v);
+ Debug("proof:sat") << "] ";
+ print(id);
+ }
}
Debug("proof:sat") << ") \n";
}
@@ -353,23 +365,23 @@ void SatProof::printRes(ResChain* res) {
/// registration methods
ClauseId SatProof::registerClause(::Minisat::CRef clause, ClauseKind kind) {
- Assert(clause != CRef_Undef);
+ Assert(clause != CRef_Undef);
ClauseIdMap::iterator it = d_clauseId.find(clause);
- if (it == d_clauseId.end()) {
- ClauseId newId = d_idCounter++;
- d_clauseId[clause]= newId;
- d_idClause[newId] =clause;
- if (kind == INPUT) {
- Assert (d_inputClauses.find(newId) == d_inputClauses.end());
- d_inputClauses.insert(newId);
- }
- if (kind == THEORY_LEMMA) {
- Assert (d_lemmaClauses.find(newId) == d_lemmaClauses.end());
- d_lemmaClauses.insert(newId);
- }
- }
- Debug("proof:sat:detailed") <<"registerClause CRef:" << clause <<" id:" << d_clauseId[clause] << " " << kind << "\n";
- return d_clauseId[clause];
+ if (it == d_clauseId.end()) {
+ ClauseId newId = d_idCounter++;
+ d_clauseId[clause] = newId;
+ d_idClause[newId] = clause;
+ if (kind == INPUT) {
+ Assert(d_inputClauses.find(newId) == d_inputClauses.end());
+ d_inputClauses.insert(newId);
+ }
+ if (kind == THEORY_LEMMA) {
+ Assert(d_lemmaClauses.find(newId) == d_lemmaClauses.end());
+ d_lemmaClauses.insert(newId);
+ }
+ }
+ Debug("proof:sat:detailed") <<"registerClause CRef:" << clause <<" id:" << d_clauseId[clause] << " " << kind << "\n";
+ return d_clauseId[clause];
}
ClauseId SatProof::registerUnitClause(::Minisat::Lit lit, ClauseKind kind) {
@@ -377,44 +389,42 @@ ClauseId SatProof::registerUnitClause(::Minisat::Lit lit, ClauseKind kind) {
if (it == d_unitId.end()) {
ClauseId newId = d_idCounter++;
d_unitId[toInt(lit)] = newId;
- d_idUnit[newId] = lit;
+ d_idUnit[newId] = lit;
if (kind == INPUT) {
- Assert (d_inputClauses.find(newId) == d_inputClauses.end());
- d_inputClauses.insert(newId);
+ Assert(d_inputClauses.find(newId) == d_inputClauses.end());
+ d_inputClauses.insert(newId);
}
if (kind == THEORY_LEMMA) {
- Assert (d_lemmaClauses.find(newId) == d_lemmaClauses.end());
- d_lemmaClauses.insert(newId);
+ Assert(d_lemmaClauses.find(newId) == d_lemmaClauses.end());
+ d_lemmaClauses.insert(newId);
}
-
}
- Debug("proof:sat:detailed") <<"registerUnitClause " << d_unitId[toInt(lit)] << " " << kind <<"\n";
- return d_unitId[toInt(lit)];
+ Debug("proof:sat:detailed") <<"registerUnitClause " << d_unitId[toInt(lit)] << " " << kind <<"\n";
+ return d_unitId[toInt(lit)];
}
void SatProof::removedDfs(::Minisat::Lit lit, LitSet* removedSet, LitVector& removeStack, LitSet& inClause, LitSet& seen) {
// if we already added the literal return
if (seen.count(lit)) {
- return;
+ return;
}
CRef reason_ref = d_solver->reason(var(lit));
if (reason_ref == CRef_Undef) {
seen.insert(lit);
- removeStack.push_back(lit);
- return;
+ removeStack.push_back(lit);
+ return;
}
- Assert (reason_ref != CRef_Undef);
- int size = d_solver->ca[reason_ref].size();
+ int size = getClause(reason_ref).size();
for (int i = 1; i < size; i++ ) {
- Lit v = d_solver->ca[reason_ref][i];
+ Lit v = getClause(reason_ref)[i];
if(inClause.count(v) == 0 && seen.count(v) == 0) {
removedDfs(v, removedSet, removeStack, inClause, seen);
}
}
if(seen.count(lit) == 0) {
- seen.insert(lit);
+ seen.insert(lit);
removeStack.push_back(lit);
}
}
@@ -427,39 +437,41 @@ void SatProof::removeRedundantFromRes(ResChain* res, ClauseId id) {
}
LitSet inClause;
- createLitSet(id, inClause);
-
+ createLitSet(id, inClause);
+
LitVector removeStack;
- LitSet seen;
+ LitSet seen;
for (LitSet::iterator it = removed->begin(); it != removed->end(); ++it) {
- removedDfs(*it, removed, removeStack, inClause, seen);
+ removedDfs(*it, removed, removeStack, inClause, seen);
}
-
+
for (int i = removeStack.size()-1; i >= 0; --i) {
Lit lit = removeStack[i];
CRef reason_ref = d_solver->reason(var(lit));
- ClauseId reason_id;
+ ClauseId reason_id;
if (reason_ref == CRef_Undef) {
Assert(isUnit(~lit));
- reason_id = getUnitId(~lit);
+ reason_id = getUnitId(~lit);
} else {
reason_id = registerClause(reason_ref);
}
res->addStep(lit, reason_id, !sign(lit));
}
- removed->clear();
+ removed->clear();
}
void SatProof::registerResolution(ClauseId id, ResChain* res) {
Assert(res != NULL);
removeRedundantFromRes(res, id);
- Assert(res->redundantRemoved());
+ Assert(res->redundantRemoved());
d_resChains[id] = res;
- printRes(id);
- if (d_checkRes) {
+ if(Debug.isOn("proof:sat")) {
+ printRes(id);
+ }
+ if(d_checkRes) {
Assert(checkResolution(id));
}
}
@@ -468,48 +480,46 @@ void SatProof::registerResolution(ClauseId id, ResChain* res) {
/// recording resolutions
void SatProof::startResChain(::Minisat::CRef start) {
- ClauseId id = getClauseId(start);
+ ClauseId id = getClauseId(start);
ResChain* res = new ResChain(id);
- d_resStack.push_back(res);
+ d_resStack.push_back(res);
}
void SatProof::addResolutionStep(::Minisat::Lit lit, ::Minisat::CRef clause, bool sign) {
ClauseId id = registerClause(clause);
ResChain* res = d_resStack.back();
- res->addStep(lit, id, sign);
+ res->addStep(lit, id, sign);
}
void SatProof::endResChain(CRef clause) {
Assert(d_resStack.size() > 0);
- ClauseId id = registerClause(clause);
+ ClauseId id = registerClause(clause);
ResChain* res = d_resStack.back();
registerResolution(id, res);
- d_resStack.pop_back();
+ d_resStack.pop_back();
}
void SatProof::endResChain(::Minisat::Lit lit) {
Assert(d_resStack.size() > 0);
- ClauseId id = registerUnitClause(lit);
+ ClauseId id = registerUnitClause(lit);
ResChain* res = d_resStack.back();
-
-
registerResolution(id, res);
- d_resStack.pop_back();
+ d_resStack.pop_back();
}
void SatProof::storeLitRedundant(::Minisat::Lit lit) {
Assert(d_resStack.size() > 0);
ResChain* res = d_resStack.back();
- res->addRedundantLit(lit);
+ res->addRedundantLit(lit);
}
-/// constructing resolutions
+/// constructing resolutions
void SatProof::resolveOutUnit(::Minisat::Lit lit) {
ClauseId id = resolveUnit(~lit);
ResChain* res = d_resStack.back();
- res->addStep(lit, id, !sign(lit));
+ res->addStep(lit, id, !sign(lit));
}
void SatProof::storeUnitResolution(::Minisat::Lit lit) {
@@ -520,28 +530,30 @@ ClauseId SatProof::resolveUnit(::Minisat::Lit lit) {
// first check if we already have a resolution for lit
if(isUnit(lit)) {
ClauseId id = getClauseId(lit);
- if(hasResolution(id) || isInputClause(id)) {
- return id;
- }
- Assert (false);
+ Assert(hasResolution(id) || isInputClause(id) || isLemmaClause(id));
+ return id;
}
CRef reason_ref = d_solver->reason(var(lit));
- Assert (reason_ref != CRef_Undef);
-
- ClauseId reason_id = registerClause(reason_ref);
-
- ResChain* res = new ResChain(reason_id);
- Clause& reason = d_solver->ca[reason_ref];
- for (int i = 0; i < reason.size(); i++) {
- Lit l = reason[i];
- if(lit != l) {
+ Assert(reason_ref != CRef_Undef);
+
+ ClauseId reason_id = registerClause(reason_ref);
+
+ ResChain* res = new ResChain(reason_id);
+ // Here, the call to resolveUnit() can reallocate memory in the
+ // clause allocator. So reload reason ptr each time.
+ Clause* reason = &getClause(reason_ref);
+ for (int i = 0;
+ i < reason->size();
+ i++, reason = &getClause(reason_ref)) {
+ Lit l = (*reason)[i];
+ if(lit != l) {
ClauseId res_id = resolveUnit(~l);
res->addStep(l, res_id, !sign(l));
}
}
- ClauseId unit_id = registerUnitClause(lit);
+ ClauseId unit_id = registerUnitClause(lit);
registerResolution(unit_id, res);
- return unit_id;
+ return unit_id;
}
void SatProof::toStream(std::ostream& out) {
@@ -549,50 +561,62 @@ void SatProof::toStream(std::ostream& out) {
Unimplemented("native proof printing not supported yet");
}
-void SatProof::storeUnitConflict(::Minisat::Lit conflict_lit) {
- Assert (!d_storedUnitConflict);
- d_unitConflictId = registerUnitClause(conflict_lit);
+void SatProof::storeUnitConflict(::Minisat::Lit conflict_lit, ClauseKind kind) {
+ Assert(!d_storedUnitConflict);
+ d_unitConflictId = registerUnitClause(conflict_lit, kind);
d_storedUnitConflict = true;
- Debug("proof:sat:detailed") <<"storeUnitConflict " << d_unitConflictId << "\n";
+ Debug("proof:sat:detailed") <<"storeUnitConflict " << d_unitConflictId << "\n";
}
void SatProof::finalizeProof(::Minisat::CRef conflict_ref) {
Assert(d_resStack.size() == 0);
- Assert (conflict_ref != ::Minisat::CRef_Undef);
- ClauseId conflict_id;
+ Assert(conflict_ref != ::Minisat::CRef_Undef);
+ ClauseId conflict_id;
if (conflict_ref == ::Minisat::CRef_Lazy) {
- Assert (d_storedUnitConflict);
- conflict_id = d_unitConflictId;
+ Assert(d_storedUnitConflict);
+ conflict_id = d_unitConflictId;
+
+ ResChain* res = new ResChain(conflict_id);
+ Lit lit = d_idUnit[conflict_id];
+ ClauseId res_id = resolveUnit(~lit);
+ res->addStep(lit, res_id, !sign(lit));
+
+ registerResolution(d_emptyClauseId, res);
+
+ return;
} else {
- Assert (!d_storedUnitConflict);
+ Assert(!d_storedUnitConflict);
conflict_id = registerClause(conflict_ref); //FIXME
}
- Debug("proof:sat") << "proof::finalizeProof Final Conflict ";
- print(conflict_id);
-
+ if(Debug.isOn("proof:sat")) {
+ Debug("proof:sat") << "proof::finalizeProof Final Conflict ";
+ print(conflict_id);
+ }
+
ResChain* res = new ResChain(conflict_id);
- Clause& conflict = d_solver->ca[conflict_ref] ;
- for (int i = 0; i < conflict.size(); ++i) {
- Lit lit = conflict[i];
+ // Here, the call to resolveUnit() can reallocate memory in the
+ // clause allocator. So reload conflict ptr each time.
+ Clause* conflict = &getClause(conflict_ref);
+ for (int i = 0;
+ i < conflict->size();
+ ++i, conflict = &getClause(conflict_ref)) {
+ Lit lit = (*conflict)[i];
ClauseId res_id = resolveUnit(~lit);
- res->addStep(lit, res_id, !sign(lit));
+ res->addStep(lit, res_id, !sign(lit));
}
registerResolution(d_emptyClauseId, res);
- // // FIXME: massive hack
- // Proof* proof = ProofManager::getProof();
- // proof->toStream(std::cout);
}
/// CRef manager
void SatProof::updateCRef(::Minisat::CRef oldref, ::Minisat::CRef newref) {
if (d_clauseId.find(oldref) == d_clauseId.end()) {
- return;
+ return;
}
ClauseId id = getClauseId(oldref);
- Assert (d_temp_clauseId.find(newref) == d_temp_clauseId.end());
- Assert (d_temp_idClause.find(id) == d_temp_idClause.end());
+ Assert(d_temp_clauseId.find(newref) == d_temp_clauseId.end());
+ Assert(d_temp_idClause.find(id) == d_temp_idClause.end());
d_temp_clauseId[newref] = id;
d_temp_idClause[id] = newref;
}
@@ -602,39 +626,39 @@ void SatProof::finishUpdateCRef() {
d_temp_clauseId.clear();
d_idClause.swap(d_temp_idClause);
- d_temp_idClause.clear();
+ d_temp_idClause.clear();
}
void SatProof::markDeleted(CRef clause) {
if (d_clauseId.find(clause) != d_clauseId.end()) {
ClauseId id = getClauseId(clause);
- Assert (d_deleted.find(id) == d_deleted.end());
+ Assert(d_deleted.find(id) == d_deleted.end());
d_deleted.insert(id);
if (isLemmaClause(id)) {
const Clause& minisat_cl = getClause(clause);
- SatClause* sat_cl = new SatClause();
- MinisatSatSolver::toSatClause(minisat_cl, *sat_cl);
- d_deletedTheoryLemmas.insert(std::make_pair(id, sat_cl));
+ SatClause* sat_cl = new SatClause();
+ MinisatSatSolver::toSatClause(minisat_cl, *sat_cl);
+ d_deletedTheoryLemmas.insert(std::make_pair(id, sat_cl));
}
}
}
void SatProof::constructProof() {
- collectClauses(d_emptyClauseId);
+ collectClauses(d_emptyClauseId);
}
std::string SatProof::clauseName(ClauseId id) {
ostringstream os;
if (isInputClause(id)) {
- os << ProofManager::getInputClauseName(id);
- return os.str();
- } else
+ os << ProofManager::getInputClauseName(id);
+ return os.str();
+ } else
if (isLemmaClause(id)) {
- os << ProofManager::getLemmaClauseName(id);
- return os.str();
+ os << ProofManager::getLemmaClauseName(id);
+ return os.str();
}else {
os << ProofManager::getLearntClauseName(id);
- return os.str();
+ return os.str();
}
}
@@ -643,58 +667,56 @@ void SatProof::addToProofManager(ClauseId id, ClauseKind kind) {
Minisat::Lit lit = getUnit(id);
prop::SatLiteral sat_lit = MinisatSatSolver::toSatLiteral(lit);
prop::SatClause* clause = new SatClause();
- clause->push_back(sat_lit);
- ProofManager::currentPM()->addClause(id, clause, kind);
- return;
+ clause->push_back(sat_lit);
+ ProofManager::currentPM()->addClause(id, clause, kind);
+ return;
}
-
+
if (isDeleted(id)) {
- Assert (kind == THEORY_LEMMA);
+ Assert(kind == THEORY_LEMMA);
SatClause* clause = d_deletedTheoryLemmas.find(id)->second;
- ProofManager::currentPM()->addClause(id, clause, kind);
- return;
+ ProofManager::currentPM()->addClause(id, clause, kind);
+ return;
}
-
+
CRef ref = getClauseRef(id);
const Clause& minisat_cl = getClause(ref);
SatClause* clause = new SatClause();
- MinisatSatSolver::toSatClause(minisat_cl, *clause);
- ProofManager::currentPM()->addClause(id, clause, kind);
+ MinisatSatSolver::toSatClause(minisat_cl, *clause);
+ ProofManager::currentPM()->addClause(id, clause, kind);
}
void SatProof::collectClauses(ClauseId id) {
if (d_seenLearnt.find(id) != d_seenLearnt.end()) {
- return;
+ return;
}
if (d_seenInput.find(id) != d_seenInput.end()) {
- return;
+ return;
}
if (d_seenLemmas.find(id) != d_seenLemmas.end()) {
- return;
+ return;
}
if (isInputClause(id)) {
- addToProofManager(id, INPUT);
+ addToProofManager(id, INPUT);
d_seenInput.insert(id);
- return;
- }
- else if (isLemmaClause(id)) {
- addToProofManager(id, THEORY_LEMMA);
+ return;
+ } else if (isLemmaClause(id)) {
+ addToProofManager(id, THEORY_LEMMA);
d_seenLemmas.insert(id);
- return;
- }
- else {
- d_seenLearnt.insert(id);
+ return;
+ } else {
+ d_seenLearnt.insert(id);
}
- Assert (d_resChains.find(id) != d_resChains.end());
+ Assert(d_resChains.find(id) != d_resChains.end());
ResChain* res = d_resChains[id];
ClauseId start = res->getStart();
collectClauses(start);
- ResSteps steps = res->getSteps();
- for(unsigned i = 0; i < steps.size(); i++) {
- collectClauses(steps[i].id);
+ ResSteps steps = res->getSteps();
+ for(size_t i = 0; i < steps.size(); i++) {
+ collectClauses(steps[i].id);
}
}
@@ -703,29 +725,29 @@ void SatProof::collectClauses(ClauseId id) {
void LFSCSatProof::printResolution(ClauseId id, std::ostream& out, std::ostream& paren) {
out << "(satlem_simplify _ _ _ ";
- ResChain* res = d_resChains[id];
+ ResChain* res = d_resChains[id];
ResSteps& steps = res->getSteps();
-
+
for (int i = steps.size()-1; i >= 0; i--) {
out << "(";
out << (steps[i].sign? "R" : "Q") << " _ _ ";
-
+
}
-
+
ClauseId start_id = res->getStart();
// WHY DID WE NEED THIS?
// if(isInputClause(start_id)) {
- // d_seenInput.insert(start_id);
+ // d_seenInput.insert(start_id);
// }
out << clauseName(start_id) << " ";
-
+
for(unsigned i = 0; i < steps.size(); i++) {
- out << clauseName(steps[i].id) << " "<<ProofManager::getVarName(MinisatSatSolver::toSatVariable(var(steps[i].lit))) <<")";
+ out << clauseName(steps[i].id) << " "<<ProofManager::getVarName(MinisatSatSolver::toSatVariable(var(steps[i].lit))) <<")";
}
-
+
if (id == d_emptyClauseId) {
out <<"(\\empty empty)";
- return;
+ return;
}
out << "(\\" << clauseName(id) << "\n"; // bind to lemma name
diff --git a/src/proof/sat_proof.h b/src/proof/sat_proof.h
index a4178f518..d555ca529 100644
--- a/src/proof/sat_proof.h
+++ b/src/proof/sat_proof.h
@@ -9,7 +9,7 @@
** See the file COPYING in the top-level source directory for licensing
** information.\endverbatim
**
- ** \brief Resolution proof
+ ** \brief Resolution proof
**
** Resolution proof
**/
@@ -43,11 +43,11 @@ namespace std {
namespace CVC4 {
-/**
+/**
* Helper debugging functions
*/
void printDebug(::Minisat::Lit l);
-void printDebug(::Minisat::Clause& c);
+void printDebug(::Minisat::Clause& c);
struct ResStep {
::Minisat::Lit lit;
@@ -60,8 +60,8 @@ struct ResStep {
{}
};/* struct ResStep */
-typedef std::vector< ResStep > ResSteps;
-typedef std::set < ::Minisat::Lit> LitSet;
+typedef std::vector< ResStep > ResSteps;
+typedef std::set < ::Minisat::Lit> LitSet;
class ResChain {
private:
@@ -72,7 +72,7 @@ public:
ResChain(ClauseId start);
void addStep(::Minisat::Lit, ClauseId, bool);
bool redundantRemoved() { return (d_redundantLits == NULL || d_redundantLits->empty()); }
- void addRedundantLit(::Minisat::Lit lit);
+ void addRedundantLit(::Minisat::Lit lit);
~ResChain();
// accessor methods
ClauseId getStart() { return d_start; }
@@ -83,16 +83,16 @@ public:
typedef std::hash_map < ClauseId, ::Minisat::CRef > IdCRefMap;
typedef std::hash_map < ::Minisat::CRef, ClauseId > ClauseIdMap;
typedef std::hash_map < ClauseId, ::Minisat::Lit> IdUnitMap;
-typedef std::hash_map < int, ClauseId> UnitIdMap; //FIXME
-typedef std::hash_map < ClauseId, ResChain*> IdResMap;
+typedef std::hash_map < int, ClauseId> UnitIdMap; //FIXME
+typedef std::hash_map < ClauseId, ResChain*> IdResMap;
typedef std::hash_set < ClauseId > IdHashSet;
-typedef std::vector < ResChain* > ResStack;
-typedef std::hash_map <ClauseId, prop::SatClause* > IdToSatClause;
-typedef std::set < ClauseId > IdSet;
-typedef std::vector < ::Minisat::Lit > LitVector;
+typedef std::vector < ResChain* > ResStack;
+typedef std::hash_map <ClauseId, prop::SatClause* > IdToSatClause;
+typedef std::set < ClauseId > IdSet;
+typedef std::vector < ::Minisat::Lit > LitVector;
typedef __gnu_cxx::hash_map<ClauseId, ::Minisat::Clause& > IdToMinisatClause;
-class SatProof;
+class SatProof;
class ProofProxy : public ProofProxyAbstract {
private:
@@ -103,31 +103,31 @@ public:
};/* class ProofProxy */
-class CnfProof;
+class CnfProof;
class SatProof {
protected:
::Minisat::Solver* d_solver;
- // clauses
+ // clauses
IdCRefMap d_idClause;
ClauseIdMap d_clauseId;
IdUnitMap d_idUnit;
UnitIdMap d_unitId;
IdHashSet d_deleted;
- IdToSatClause d_deletedTheoryLemmas;
- IdHashSet d_inputClauses;
- IdHashSet d_lemmaClauses;
- // resolutions
+ IdToSatClause d_deletedTheoryLemmas;
+ IdHashSet d_inputClauses;
+ IdHashSet d_lemmaClauses;
+ // resolutions
IdResMap d_resChains;
- ResStack d_resStack;
+ ResStack d_resStack;
bool d_checkRes;
-
- static ClauseId d_idCounter;
+
+ static ClauseId d_idCounter;
const ClauseId d_emptyClauseId;
const ClauseId d_nullId;
- // proxy class to break circular dependencies
+ // proxy class to break circular dependencies
ProofProxy* d_proxy;
-
+
// temporary map for updating CRefs
ClauseIdMap d_temp_clauseId;
IdCRefMap d_temp_idClause;
@@ -135,43 +135,43 @@ protected:
// unit conflict
ClauseId d_unitConflictId;
bool d_storedUnitConflict;
-public:
+public:
SatProof(::Minisat::Solver* solver, bool checkRes = false);
virtual ~SatProof() {}
protected:
- void print(ClauseId id);
+ void print(ClauseId id);
void printRes(ClauseId id);
- void printRes(ResChain* res);
-
+ void printRes(ResChain* res);
+
bool isInputClause(ClauseId id);
bool isLemmaClause(ClauseId id);
bool isUnit(ClauseId id);
- bool isUnit(::Minisat::Lit lit);
- bool hasResolution(ClauseId id);
- void createLitSet(ClauseId id, LitSet& set);
+ bool isUnit(::Minisat::Lit lit);
+ bool hasResolution(ClauseId id);
+ void createLitSet(ClauseId id, LitSet& set);
void registerResolution(ClauseId id, ResChain* res);
-
+
ClauseId getClauseId(::Minisat::CRef clause);
- ClauseId getClauseId(::Minisat::Lit lit);
+ ClauseId getClauseId(::Minisat::Lit lit);
::Minisat::CRef getClauseRef(ClauseId id);
::Minisat::Lit getUnit(ClauseId id);
- ClauseId getUnitId(::Minisat::Lit lit);
+ ClauseId getUnitId(::Minisat::Lit lit);
::Minisat::Clause& getClause(::Minisat::CRef ref);
virtual void toStream(std::ostream& out);
bool checkResolution(ClauseId id);
- /**
+ /**
* Constructs a resolution tree that proves lit
* and returns the ClauseId for the unit clause lit
* @param lit the literal we are proving
- *
- * @return
+ *
+ * @return
*/
ClauseId resolveUnit(::Minisat::Lit lit);
- /**
+ /**
* Does a depth first search on removed literals and adds the literals
- * to be removed in the proper order to the stack.
- *
+ * to be removed in the proper order to the stack.
+ *
* @param lit the literal we are recursing on
* @param removedSet the previously computed set of redundant literals
* @param removeStack the stack of literals in reverse order of resolution
@@ -181,71 +181,71 @@ protected:
public:
void startResChain(::Minisat::CRef start);
void addResolutionStep(::Minisat::Lit lit, ::Minisat::CRef clause, bool sign);
- /**
+ /**
* Pops the current resolution of the stack and stores it
* in the resolution map. Also registers the 'clause' parameter
- * @param clause the clause the resolution is proving
+ * @param clause the clause the resolution is proving
*/
void endResChain(::Minisat::CRef clause);
void endResChain(::Minisat::Lit lit);
- /**
- * Stores in the current derivation the redundant literals that were
- * eliminated from the conflict clause during conflict clause minimization.
- * @param lit the eliminated literal
+ /**
+ * Stores in the current derivation the redundant literals that were
+ * eliminated from the conflict clause during conflict clause minimization.
+ * @param lit the eliminated literal
*/
void storeLitRedundant(::Minisat::Lit lit);
/// update the CRef Id maps when Minisat does memory reallocation x
void updateCRef(::Minisat::CRef old_ref, ::Minisat::CRef new_ref);
void finishUpdateCRef();
-
- /**
+
+ /**
* Constructs the empty clause resolution from the final conflict
- *
- * @param conflict
+ *
+ * @param conflict
*/
void finalizeProof(::Minisat::CRef conflict);
- /// clause registration methods
+ /// clause registration methods
ClauseId registerClause(const ::Minisat::CRef clause, ClauseKind kind = LEARNT);
ClauseId registerUnitClause(const ::Minisat::Lit lit, ClauseKind kind = LEARNT);
- void storeUnitConflict(::Minisat::Lit lit);
-
- /**
+ void storeUnitConflict(::Minisat::Lit lit, ClauseKind kind = LEARNT);
+
+ /**
* Marks the deleted clauses as deleted. Note we may still use them in the final
- * resolution.
- * @param clause
+ * resolution.
+ * @param clause
*/
void markDeleted(::Minisat::CRef clause);
bool isDeleted(ClauseId id) { return d_deleted.find(id) != d_deleted.end(); }
- /**
+ /**
* Constructs the resolution of ~q and resolves it with the current
* resolution thus eliminating q from the current clause
* @param q the literal to be resolved out
*/
void resolveOutUnit(::Minisat::Lit q);
- /**
+ /**
* Constructs the resolution of the literal lit. Called when a clause
- * containing lit becomes satisfied and is removed.
- * @param lit
+ * containing lit becomes satisfied and is removed.
+ * @param lit
*/
- void storeUnitResolution(::Minisat::Lit lit);
-
+ void storeUnitResolution(::Minisat::Lit lit);
+
ProofProxy* getProxy() {return d_proxy; }
/**
- Constructs the SAT proof identifying the needed lemmas
+ Constructs the SAT proof identifying the needed lemmas
*/
void constructProof();
-
+
protected:
IdSet d_seenLearnt;
IdHashSet d_seenInput;
- IdHashSet d_seenLemmas;
-
+ IdHashSet d_seenLemmas;
+
inline std::string varName(::Minisat::Lit lit);
- inline std::string clauseName(ClauseId id);
+ inline std::string clauseName(ClauseId id);
void collectClauses(ClauseId id);
void addToProofManager(ClauseId id, ClauseKind kind);
@@ -253,7 +253,7 @@ public:
virtual void printResolutions(std::ostream& out, std::ostream& paren) = 0;
};/* class SatProof */
-class LFSCSatProof: public SatProof {
+class LFSCSatProof : public SatProof {
private:
void printResolution(ClauseId id, std::ostream& out, std::ostream& paren);
public:
diff --git a/src/proof/theory_proof.cpp b/src/proof/theory_proof.cpp
index 696bd8309..4ed00aaaa 100644
--- a/src/proof/theory_proof.cpp
+++ b/src/proof/theory_proof.cpp
@@ -26,9 +26,10 @@ TheoryProof::TheoryProof()
{}
void TheoryProof::addDeclaration(Expr term) {
- if (d_declarationCache.count(term))
+ if (d_declarationCache.count(term)) {
return;
-
+ }
+
Type type = term.getType();
if (type.isSort())
d_sortDeclarations.insert(type);
@@ -36,32 +37,14 @@ void TheoryProof::addDeclaration(Expr term) {
Expr function = term.getOperator();
d_termDeclarations.insert(function);
} else if (term.isVariable()) {
- Assert (type.isSort());
+ //Assert (type.isSort() || type.isBoolean());
d_termDeclarations.insert(term);
}
// recursively declare all other terms
for (unsigned i = 0; i < term.getNumChildren(); ++i) {
- addDeclaration(term[i]);
- }
- d_declarationCache.insert(term);
-}
-
-void LFSCTheoryProof::printTerm(Expr term, std::ostream& os) {
- if (term.isVariable()) {
- os << term;
- return;
- }
-
- Assert (term.getKind() == kind::APPLY_UF);
- Expr func = term.getOperator();
- for (unsigned i = 0; i < term.getNumChildren(); ++i) {
- os<< "(apply _ _ ";
- }
- os << func << " ";
- for (unsigned i = 0; i < term.getNumChildren(); ++i) {
- printTerm(term[i], os);
- os << ")";
+ addDeclaration(term[i]);
}
+ d_declarationCache.insert(term);
}
std::string toLFSCKind(Kind kind) {
@@ -70,71 +53,138 @@ std::string toLFSCKind(Kind kind) {
case kind::AND: return "and";
case kind::XOR: return "xor";
case kind::EQUAL: return "=";
+ case kind::IFF: return "iff";
case kind::IMPLIES: return "impl";
case kind::NOT: return "not";
default:
- Unreachable();
+ Unreachable();
}
}
-void LFSCTheoryProof::printFormula(Expr atom, std::ostream& os) {
- // should make this more general and overall sane
- Assert (atom.getType().isBoolean() && "Only printing booleans." );
- Kind kind = atom.getKind();
- // this is the only predicate we have
- if (kind == kind::EQUAL) {
- os << "(";
- os <<"= ";
- os << atom[0].getType() <<" ";
- printTerm(atom[0], os);
- os <<" ";
- printTerm(atom[1], os);
- os <<")";
- } else if ( kind == kind::DISTINCT) {
- os <<"(not (= ";
- os << atom[0].getType() <<" ";
- printTerm(atom[0], os);
- os <<" ";
- printTerm(atom[1], os);
- os <<"))";
- } else if ( kind == kind::OR ||
- kind == kind::AND ||
- kind == kind::XOR ||
- kind == kind::IMPLIES ||
- kind == kind::NOT) {
- // print the boolean operators
+void LFSCTheoryProof::printTerm(Expr term, std::ostream& os) {
+ if (term.isVariable()) {
+ if(term.getType().isBoolean()) {
+ os << "(p_app " << term << ")";
+ } else {
+ os << term;
+ }
+ return;
+ }
+
+ switch(Kind k = term.getKind()) {
+ case kind::APPLY_UF: {
+ if(term.getType().isBoolean()) {
+ os << "(p_app ";
+ }
+ Expr func = term.getOperator();
+ for (unsigned i = 0; i < term.getNumChildren(); ++i) {
+ os << "(apply _ _ ";
+ }
+ os << func << " ";
+ for (unsigned i = 0; i < term.getNumChildren(); ++i) {
+ printTerm(term[i], os);
+ os << ")";
+ }
+ if(term.getType().isBoolean()) {
+ os << ")";
+ }
+ return;
+ }
+
+ case kind::ITE:
+ os << (term.getType().isBoolean() ? "(ifte " : "(ite _ ");
+ printTerm(term[0], os);
+ os << " ";
+ printTerm(term[1], os);
+ os << " ";
+ printTerm(term[2], os);
+ os << ")";
+ return;
+
+ case kind::EQUAL:
os << "(";
- os << toLFSCKind(kind);
- if (atom.getNumChildren() > 2) {
+ os << "= ";
+ os << term[0].getType() << " ";
+ printTerm(term[0], os);
+ os << " ";
+ printTerm(term[1], os);
+ os << ")";
+ return;
+
+ case kind::DISTINCT:
+ os << "(not (= ";
+ os << term[0].getType() << " ";
+ printTerm(term[0], os);
+ os << " ";
+ printTerm(term[1], os);
+ os << "))";
+ return;
+
+ case kind::OR:
+ case kind::AND:
+ case kind::XOR:
+ case kind::IFF:
+ case kind::IMPLIES:
+ case kind::NOT:
+ // print the Boolean operators
+ os << "(" << toLFSCKind(k);
+ if(term.getNumChildren() > 2) {
+ // LFSC doesn't allow declarations with variable numbers of
+ // arguments, so we have to flatten these N-ary versions.
std::ostringstream paren;
os << " ";
- for (unsigned i =0; i < atom.getNumChildren(); ++i) {
- printFormula(atom[i], os);
+ for (unsigned i = 0; i < term.getNumChildren(); ++i) {
+ printTerm(term[i], os);
os << " ";
- if (i < atom.getNumChildren() - 2) {
- os << "("<< toLFSCKind(kind) << " ";
- paren << ")";
+ if(i < term.getNumChildren() - 2) {
+ os << "(" << toLFSCKind(k) << " ";
+ paren << ")";
}
}
- os << paren.str() <<")";
+ os << paren.str() << ")";
} else {
- // this is for binary and unary operators
- for (unsigned i = 0; i < atom.getNumChildren(); ++i) {
- os <<" ";
- printFormula(atom[i], os);
+ // this is for binary and unary operators
+ for (unsigned i = 0; i < term.getNumChildren(); ++i) {
+ os << " ";
+ printTerm(term[i], os);
+ }
+ os << ")";
+ }
+ return;
+
+ case kind::CONST_BOOLEAN:
+ os << (term.getConst<bool>() ? "true" : "false");
+ return;
+
+ case kind::CHAIN: {
+ // LFSC doesn't allow declarations with variable numbers of
+ // arguments, so we have to flatten chained operators, like =.
+ Kind op = term.getOperator().getConst<Chain>().getOperator();
+ size_t n = term.getNumChildren();
+ std::ostringstream paren;
+ for(size_t i = 1; i < n; ++i) {
+ if(i + 1 < n) {
+ os << "(" << toLFSCKind(kind::AND) << " ";
+ paren << ")";
+ }
+ os << "(" << toLFSCKind(op) << " ";
+ printTerm(term[i - 1], os);
+ os << " ";
+ printTerm(term[i], os);
+ os << ")";
+ if(i + 1 < n) {
+ os << " ";
}
- os <<")";
}
- } else if (kind == kind::CONST_BOOLEAN) {
- if (atom.getConst<bool>())
- os << "true";
- else
- os << "false";
+ os << paren.str();
+ return;
}
- else {
- std::cout << kind << "\n";
- Assert (false && "Unsupported kind");
+
+ default:
+ Unhandled(k);
}
+
+ Unreachable();
}
void LFSCTheoryProof::printAssertions(std::ostream& os, std::ostream& paren) {
@@ -142,56 +192,57 @@ void LFSCTheoryProof::printAssertions(std::ostream& os, std::ostream& paren) {
ProofManager::assertions_iterator it = ProofManager::currentPM()->begin_assertions();
ProofManager::assertions_iterator end = ProofManager::currentPM()->end_assertions();
- // collect declarations first
+ // collect declarations first
for(; it != end; ++it) {
- addDeclaration(*it);
+ addDeclaration(*it);
}
printDeclarations(os, paren);
it = ProofManager::currentPM()->begin_assertions();
for (; it != end; ++it) {
os << "(% A" << counter++ << " (th_holds ";
- printFormula(*it, os);
+ printTerm(*it, os);
os << ")\n";
- paren <<")";
+ paren << ")";
}
}
void LFSCTheoryProof::printDeclarations(std::ostream& os, std::ostream& paren) {
// declaring the sorts
for (SortSet::const_iterator it = d_sortDeclarations.begin(); it != d_sortDeclarations.end(); ++it) {
- os << "(% " << *it << " sort \n";
- paren << ")";
+ os << "(% " << *it << " sort\n";
+ paren << ")";
}
// declaring the terms
for (ExprSet::const_iterator it = d_termDeclarations.begin(); it != d_termDeclarations.end(); ++it) {
Expr term = *it;
- os << "(% " << term << " (term ";
- paren <<")";
+ os << "(% " << term << " ";
+ os << "(term ";
Type type = term.getType();
if (type.isFunction()) {
- std::ostringstream fparen;
+ std::ostringstream fparen;
FunctionType ftype = (FunctionType)type;
std::vector<Type> args = ftype.getArgTypes();
- args.push_back(ftype.getRangeType());
- os << "(arrow ";
+ args.push_back(ftype.getRangeType());
+ os << "(arrow";
for (unsigned i = 0; i < args.size(); i++) {
Type arg_type = args[i];
- Assert (arg_type.isSort());
- os << arg_type << " ";
+ //Assert (arg_type.isSort() || arg_type.isBoolean());
+ os << " " << arg_type;
if (i < args.size() - 2) {
- os << "(arrow ";
- fparen <<")";
+ os << " (arrow";
+ fparen << ")";
}
}
- os << fparen.str() << "))\n";
+ os << fparen.str() << "))\n";
} else {
Assert (term.isVariable());
- Assert (type.isSort());
+ //Assert (type.isSort() || type.isBoolean());
os << type << ")\n";
}
+ paren << ")";
}
-}
+}
diff --git a/src/proof/theory_proof.h b/src/proof/theory_proof.h
index 457023a59..0a7772a4b 100644
--- a/src/proof/theory_proof.h
+++ b/src/proof/theory_proof.h
@@ -13,7 +13,7 @@
**
** A manager for UfProofs.
**
- **
+ **
**/
@@ -24,33 +24,32 @@
#include "util/proof.h"
#include "expr/expr.h"
#include <ext/hash_set>
-#include <iostream>
+#include <iostream>
namespace CVC4 {
- typedef __gnu_cxx::hash_set<Type, TypeHashFunction > SortSet;
- typedef __gnu_cxx::hash_set<Expr, ExprHashFunction > ExprSet;
+ typedef __gnu_cxx::hash_set<Type, TypeHashFunction > SortSet;
+ typedef __gnu_cxx::hash_set<Expr, ExprHashFunction > ExprSet;
class TheoryProof {
protected:
ExprSet d_termDeclarations;
- SortSet d_sortDeclarations;
+ SortSet d_sortDeclarations;
ExprSet d_declarationCache;
-
- void addDeclaration(Expr atom);
+
public:
TheoryProof();
virtual ~TheoryProof() {}
virtual void printAssertions(std::ostream& os, std::ostream& paren) = 0;
+ void addDeclaration(Expr atom);
};
- class LFSCTheoryProof: public TheoryProof {
- static void printTerm(Expr term, std::ostream& os);
+ class LFSCTheoryProof : public TheoryProof {
void printDeclarations(std::ostream& os, std::ostream& paren);
public:
- static void printFormula(Expr atom, std::ostream& os);
+ static void printTerm(Expr term, std::ostream& os);
virtual void printAssertions(std::ostream& os, std::ostream& paren);
- };
+ };
} /* CVC4 namespace */
#endif /* __CVC4__THEORY_PROOF_H */
diff --git a/src/prop/minisat/core/Solver.cc b/src/prop/minisat/core/Solver.cc
index 16fa3ba60..610023b70 100644
--- a/src/prop/minisat/core/Solver.cc
+++ b/src/prop/minisat/core/Solver.cc
@@ -263,7 +263,7 @@ CRef Solver::reason(Var x) {
// Construct the reason
CRef real_reason = ca.alloc(explLevel, explanation, true);
- PROOF (ProofManager::getSatProof()->registerClause(real_reason, THEORY_LEMMA); );
+ PROOF (ProofManager::getSatProof()->registerClause(real_reason, THEORY_LEMMA); );
vardata[x] = VarData(real_reason, level(x), user_level(x), intro_level(x), trail_index(x));
clauses_removable.push(real_reason);
attachClause(real_reason);
@@ -324,7 +324,18 @@ bool Solver::addClause_(vec<Lit>& ps, bool removable)
} else {
// If all false, we're in conflict
if (ps.size() == falseLiteralsCount) {
+ if(PROOF_ON()) {
+ // Take care of false units here; otherwise, we need to
+ // construct the clause below to give to the proof manager
+ // as the final conflict.
+ if(falseLiteralsCount == 1) {
+ PROOF( ProofManager::getSatProof()->storeUnitConflict(ps[0], INPUT); )
+ PROOF( ProofManager::getSatProof()->finalizeProof(::Minisat::CRef_Lazy); )
+ return ok = false;
+ }
+ } else {
return ok = false;
+ }
}
CRef cr = CRef_Undef;
@@ -339,7 +350,13 @@ bool Solver::addClause_(vec<Lit>& ps, bool removable)
clauses_persistent.push(cr);
attachClause(cr);
- PROOF( ProofManager::getSatProof()->registerClause(cr, INPUT); )
+ if(PROOF_ON()) {
+ PROOF( ProofManager::getSatProof()->registerClause(cr, INPUT); )
+ if(ps.size() == falseLiteralsCount) {
+ PROOF( ProofManager::getSatProof()->finalizeProof(cr); )
+ return ok = false;
+ }
+ }
}
// Check if it propagates
@@ -347,8 +364,17 @@ bool Solver::addClause_(vec<Lit>& ps, bool removable)
if(assigns[var(ps[0])] == l_Undef) {
assert(assigns[var(ps[0])] != l_False);
uncheckedEnqueue(ps[0], cr);
- PROOF( if (ps.size() == 1) { ProofManager::getSatProof()->registerUnitClause(ps[0], INPUT); } )
- return ok = (propagate(CHECK_WITHOUT_THEORY) == CRef_Undef);
+ PROOF( if(ps.size() == 1) { ProofManager::getSatProof()->registerUnitClause(ps[0], INPUT); } );
+ CRef confl = propagate(CHECK_WITHOUT_THEORY);
+ if(! (ok = (confl == CRef_Undef)) ) {
+ if(ca[confl].size() == 1) {
+ PROOF( ProofManager::getSatProof()->storeUnitConflict(ca[confl][0], LEARNT); );
+ PROOF( ProofManager::getSatProof()->finalizeProof(::Minisat::CRef_Lazy); )
+ } else {
+ PROOF( ProofManager::getSatProof()->finalizeProof(confl); );
+ }
+ }
+ return ok;
} else return ok;
}
}
@@ -370,7 +396,7 @@ void Solver::attachClause(CRef cr) {
void Solver::detachClause(CRef cr, bool strict) {
const Clause& c = ca[cr];
- PROOF( ProofManager::getSatProof()->markDeleted(cr); )
+ PROOF( ProofManager::getSatProof()->markDeleted(cr); );
Debug("minisat") << "Solver::detachClause(" << c << ")" << std::endl;
assert(c.size() > 1);
@@ -1580,7 +1606,7 @@ CRef Solver::updateLemmas() {
vec<Lit>& lemma = lemmas[i];
// If it's an empty lemma, we have a conflict at zero level
if (lemma.size() == 0) {
- Assert (! PROOF_ON());
+ Assert (! PROOF_ON());
conflict = CRef_Lazy;
backtrackLevel = 0;
Debug("minisat::lemmas") << "Solver::updateLemmas(): found empty clause" << std::endl;
@@ -1630,13 +1656,15 @@ CRef Solver::updateLemmas() {
}
lemma_ref = ca.alloc(clauseLevel, lemma, removable);
- PROOF (ProofManager::getSatProof()->registerClause(lemma_ref, THEORY_LEMMA); );
+ PROOF( ProofManager::getSatProof()->registerClause(lemma_ref, THEORY_LEMMA); );
if (removable) {
clauses_removable.push(lemma_ref);
} else {
clauses_persistent.push(lemma_ref);
}
attachClause(lemma_ref);
+ } else {
+ PROOF( ProofManager::getSatProof()->registerUnitClause(lemma[0], THEORY_LEMMA); );
}
// If the lemma is propagating enqueue its literal (or set the conflict)
@@ -1650,7 +1678,7 @@ CRef Solver::updateLemmas() {
} else {
Debug("minisat::lemmas") << "Solver::updateLemmas(): unit conflict or empty clause" << std::endl;
conflict = CRef_Lazy;
- PROOF(ProofManager::getSatProof()->storeUnitConflict(lemma[0]););
+ PROOF( ProofManager::getSatProof()->storeUnitConflict(lemma[0]); );
}
} else {
Debug("minisat::lemmas") << "lemma size is " << lemma.size() << std::endl;
diff --git a/src/smt/options b/src/smt/options
index 05a138f60..b76822caf 100644
--- a/src/smt/options
+++ b/src/smt/options
@@ -22,12 +22,16 @@ option expandDefinitions expand-definitions bool :default false
always expand symbol definitions in output
common-option produceModels produce-models -m --produce-models bool :default false :predicate CVC4::smt::beforeSearch :predicate-include "smt/smt_engine.h"
support the get-value and get-model commands
-option checkModels check-models --check-models bool :predicate CVC4::smt::beforeSearch :predicate-include "smt/options_handlers.h"
+option checkModels check-models --check-models bool :link --produce-models --interactive :link-smt produce-models :link-smt interactive-mode :predicate CVC4::smt::beforeSearch :predicate-include "smt/options_handlers.h"
after SAT/INVALID/UNKNOWN, check that the generated model satisfies user assertions
-option dumpModels --dump-models bool :default false
+option dumpModels --dump-models bool :default false :link --produce-models
output models after every SAT/INVALID/UNKNOWN response
option proof produce-proofs --proof bool :default false :predicate CVC4::smt::proofEnabledBuild CVC4::smt::beforeSearch :predicate-include "smt/options_handlers.h"
turn on proof generation
+option checkProofs check-proofs --check-proofs bool :link --proof :link-smt produce-proofs :predicate CVC4::smt::beforeSearch :predicate-include "smt/options_handlers.h"
+ after UNSAT/VALID, machine-check the generated proof
+option dumpProofs --dump-proofs bool :default false :link --proof
+ output proofs after every UNSAT/VALID response
# this is just a placeholder for later; it doesn't show up in command-line options listings
undocumented-option unsatCores produce-unsat-cores --produce-unsat-cores bool :predicate CVC4::smt::unsatCoresEnabledBuild CVC4::smt::beforeSearch :predicate-include "smt/options_handlers.h"
turn on unsat core generation (NOT YET SUPPORTED)
diff --git a/src/smt/smt_engine.cpp b/src/smt/smt_engine.cpp
index 0fadca424..014d3c603 100644
--- a/src/smt/smt_engine.cpp
+++ b/src/smt/smt_engine.cpp
@@ -46,8 +46,10 @@
#include "theory/theory_engine.h"
#include "theory/bv/theory_bv_rewriter.h"
#include "proof/proof_manager.h"
+#include "main/options.h"
#include "util/proof.h"
#include "proof/proof.h"
+#include "proof/proof_manager.h"
#include "util/boolean_simplification.h"
#include "util/node_visitor.h"
#include "util/configuration.h"
@@ -157,6 +159,8 @@ struct SmtEngineStatistics {
IntStat d_numAssertionsPost;
/** time spent in checkModel() */
TimerStat d_checkModelTime;
+ /** time spent in checkProof() */
+ TimerStat d_checkProofTime;
/** time spent in PropEngine::checkSat() */
TimerStat d_solveTime;
/** time spent in pushing/popping */
@@ -183,11 +187,11 @@ struct SmtEngineStatistics {
d_numAssertionsPre("smt::SmtEngine::numAssertionsPreITERemoval", 0),
d_numAssertionsPost("smt::SmtEngine::numAssertionsPostITERemoval", 0),
d_checkModelTime("smt::SmtEngine::checkModelTime"),
+ d_checkProofTime("smt::SmtEngine::checkProofTime"),
d_solveTime("smt::SmtEngine::solveTime"),
d_pushPopTime("smt::SmtEngine::pushPopTime"),
d_processAssertionsTime("smt::SmtEngine::processAssertionsTime"),
d_simplifiedToFalse("smt::SmtEngine::simplifiedToFalse", 0)
-
{
StatisticsRegistry::registerStat(&d_definitionExpansionTime);
@@ -667,6 +671,7 @@ SmtEngine::SmtEngine(ExprManager* em) throw() :
d_decisionEngine(NULL),
d_theoryEngine(NULL),
d_propEngine(NULL),
+ d_proofManager(NULL),
d_definedFunctions(NULL),
d_assertionList(NULL),
d_assignments(NULL),
@@ -696,6 +701,8 @@ SmtEngine::SmtEngine(ExprManager* em) throw() :
d_statisticsRegistry = new StatisticsRegistry();
d_stats = new SmtEngineStatistics();
+ PROOF( d_proofManager = new ProofManager(); );
+
// We have mutual dependency here, so we add the prop engine to the theory
// engine later (it is non-essential there)
d_theoryEngine = new TheoryEngine(d_context, d_userContext, d_private->d_iteRemover, const_cast<const LogicInfo&>(d_logic));
@@ -763,7 +770,8 @@ void SmtEngine::finishInit() {
if(options::cumulativeMillisecondLimit() != 0) {
setTimeLimit(options::cumulativeMillisecondLimit(), true);
}
- PROOF( ProofManager::currentPM()->setLogic(d_logic.getLogicString()); );
+
+ PROOF( ProofManager::currentPM()->setLogic(d_logic.getLogicString()); );
}
void SmtEngine::finalOptionsAreSet() {
@@ -777,16 +785,11 @@ void SmtEngine::finalOptionsAreSet() {
}
if(options::checkModels()) {
- if(! options::produceModels()) {
- Notice() << "SmtEngine: turning on produce-models to support check-model" << endl;
- setOption("produce-models", SExpr("true"));
- }
if(! options::interactive()) {
- Notice() << "SmtEngine: turning on interactive-mode to support check-model" << endl;
+ Notice() << "SmtEngine: turning on interactive-mode to support check-models" << endl;
setOption("interactive-mode", SExpr("true"));
}
}
-
if(options::produceAssignments() && !options::produceModels()) {
Notice() << "SmtEngine: turning on produce-models to support produce-assignments" << endl;
setOption("produce-models", SExpr("true"));
@@ -1139,15 +1142,12 @@ void SmtEngine::setLogicInternal() throw() {
options::instWhenMode.set( INST_WHEN_LAST_CALL );
}
}
- if ( ! options::fmfInstGen.wasSetByUser()) {
- //if full model checking is on, disable inst-gen techniques
- if( options::fmfFullModelCheck() ){
- options::fmfInstGen.set( false );
- }
- }
if ( options::fmfBoundInt() ){
- //if bounded integers are set, must use full model check for MBQI
- options::fmfFullModelCheck.set( true );
+ if( options::mbqiMode()!=quantifiers::MBQI_NONE &&
+ options::mbqiMode()!=quantifiers::MBQI_FMC_INTERVAL ){
+ //if bounded integers are set, must use full model check for MBQI
+ options::mbqiMode.set( quantifiers::MBQI_FMC );
+ }
}
if( options::ufssSymBreak() ){
options::sortInference.set( true );
@@ -2503,7 +2503,7 @@ void SmtEnginePrivate::doMiplibTrick() {
const uint64_t mark = (*j).second;
const unsigned numVars = pos.getKind() == kind::AND ? pos.getNumChildren() : 1;
uint64_t expected = (uint64_t(1) << (1 << numVars)) - 1;
- expected = (expected == 0) ? -1 : expected;// fix for overflow
+ expected = (expected == 0) ? -1 : expected; // fix for overflow
Debug("miplib") << "[" << pos << "] => " << hex << mark << " expect " << expected << dec << endl;
Assert(pos.getKind() == kind::AND || pos.isVar());
if(mark != expected) {
@@ -2511,7 +2511,7 @@ void SmtEnginePrivate::doMiplibTrick() {
} else {
if(mark != 3) { // exclude single-var case; nothing to check there
uint64_t sz = (uint64_t(1) << checks[pos_var].size()) - 1;
- sz = (sz == 0) ? -1 : sz;// fix for overflow
+ sz = (sz == 0) ? -1 : sz; // fix for overflow
Assert(sz == mark, "expected size %u == mark %u", sz, mark);
for(size_t k = 0; k < checks[pos_var].size(); ++k) {
if((k & (k - 1)) != 0) {
@@ -2531,12 +2531,12 @@ void SmtEnginePrivate::doMiplibTrick() {
break;
}
} else {
- Assert(checks[pos_var][k] == 0, "checks[(%s,%s)][%u] should be 0, but it's %s", pos.toString().c_str(), var.toString().c_str(), k, checks[pos_var][k].toString().c_str());// we never set for single-positive-var
+ Assert(checks[pos_var][k] == 0, "checks[(%s,%s)][%u] should be 0, but it's %s", pos.toString().c_str(), var.toString().c_str(), k, checks[pos_var][k].toString().c_str()); // we never set for single-positive-var
}
}
}
if(!eligible) {
- eligible = true;// next is still eligible
+ eligible = true; // next is still eligible
continue;
}
@@ -2560,7 +2560,7 @@ void SmtEnginePrivate::doMiplibTrick() {
Node leq = Rewriter::rewrite(nm->mkNode(kind::LEQ, newVar, one));
d_assertionsToCheck.push_back(Rewriter::rewrite(geq.andNode(leq)));
SubstitutionMap nullMap(&d_fakeContext);
- Theory::PPAssertStatus status CVC4_UNUSED;// just for assertions
+ Theory::PPAssertStatus status CVC4_UNUSED; // just for assertions
status = d_smt.d_theoryEngine->solve(geq, nullMap);
Assert(status == Theory::PP_ASSERT_STATUS_UNSOLVED,
"unexpected solution from arith's ppAssert()");
@@ -3291,9 +3291,6 @@ Result SmtEngine::checkSat(const Expr& ex) throw(TypeCheckingException, ModalExc
finalOptionsAreSet();
doPendingPops();
-
- PROOF( ProofManager::currentPM()->addAssertion(ex); );
-
Trace("smt") << "SmtEngine::checkSat(" << ex << ")" << endl;
if(d_queryMade && !options::incrementalSolving()) {
@@ -3308,6 +3305,8 @@ Result SmtEngine::checkSat(const Expr& ex) throw(TypeCheckingException, ModalExc
e = d_private->substituteAbstractValues(Node::fromExpr(ex)).toExpr();
// Ensure expr is type-checked at this point.
ensureBoolean(e);
+ // Give it to proof manager
+ PROOF( ProofManager::currentPM()->addAssertion(e); );
}
// check to see if a postsolve() is pending
@@ -3358,6 +3357,13 @@ Result SmtEngine::checkSat(const Expr& ex) throw(TypeCheckingException, ModalExc
checkModel(/* hard failure iff */ ! r.isUnknown());
}
}
+ // Check that UNSAT results generate a proof correctly.
+ if(options::checkProofs()) {
+ if(r.asSatisfiabilityResult().isSat() == Result::UNSAT) {
+ TimerStat::CodeTimer checkProofTimer(d_stats->d_checkProofTime);
+ checkProof();
+ }
+ }
return r;
}/* SmtEngine::checkSat() */
@@ -3378,9 +3384,10 @@ Result SmtEngine::query(const Expr& ex) throw(TypeCheckingException, ModalExcept
// Substitute out any abstract values in ex
Expr e = d_private->substituteAbstractValues(Node::fromExpr(ex)).toExpr();
-
// Ensure that the expression is type-checked at this point, and Boolean
ensureBoolean(e);
+ // Give it to proof manager
+ PROOF( ProofManager::currentPM()->addAssertion(e.notExpr()); );
// check to see if a postsolve() is pending
if(d_needPostsolve) {
@@ -3428,6 +3435,13 @@ Result SmtEngine::query(const Expr& ex) throw(TypeCheckingException, ModalExcept
checkModel(/* hard failure iff */ ! r.isUnknown());
}
}
+ // Check that UNSAT results generate a proof correctly.
+ if(options::checkProofs()) {
+ if(r.asSatisfiabilityResult().isSat() == Result::UNSAT) {
+ TimerStat::CodeTimer checkProofTimer(d_stats->d_checkProofTime);
+ checkProof();
+ }
+ }
return r;
}/* SmtEngine::query() */
@@ -3437,7 +3451,9 @@ Result SmtEngine::assertFormula(const Expr& ex) throw(TypeCheckingException, Log
SmtScope smts(this);
finalOptionsAreSet();
doPendingPops();
- PROOF( ProofManager::currentPM()->addAssertion(ex););
+
+ PROOF( ProofManager::currentPM()->addAssertion(ex); );
+
Trace("smt") << "SmtEngine::assertFormula(" << ex << ")" << endl;
// Substitute out any abstract values in ex
@@ -3474,7 +3490,7 @@ Expr SmtEngine::simplify(const Expr& ex) throw(TypeCheckingException, LogicExcep
Expr e = d_private->substituteAbstractValues(Node::fromExpr(ex)).toExpr();
if( options::typeChecking() ) {
- e.getType(true);// ensure expr is type-checked at this point
+ e.getType(true); // ensure expr is type-checked at this point
}
// Make sure all preprocessing is done
diff --git a/src/smt/smt_engine.h b/src/smt/smt_engine.h
index 9655297b3..8e400468c 100644
--- a/src/smt/smt_engine.h
+++ b/src/smt/smt_engine.h
@@ -56,6 +56,8 @@ class SmtEngine;
class DecisionEngine;
class TheoryEngine;
+class ProofManager;
+
class Model;
class StatisticsRegistry;
@@ -83,6 +85,7 @@ namespace smt {
class BooleanTermConverter;
void beforeSearch(std::string, bool, SmtEngine*) throw(ModalException);
+ ProofManager* currentProofManager();
struct CommandCleanup;
typedef context::CDList<Command*, CommandCleanup> CommandList;
@@ -135,8 +138,11 @@ class CVC4_PUBLIC SmtEngine {
TheoryEngine* d_theoryEngine;
/** The propositional engine */
prop::PropEngine* d_propEngine;
+ /** The proof manager */
+ ProofManager* d_proofManager;
/** An index of our defined functions */
DefinedFunctionMap* d_definedFunctions;
+
/**
* The assertion list (before any conversion) for supporting
* getAssertions(). Only maintained if in interactive mode.
@@ -249,6 +255,11 @@ class CVC4_PUBLIC SmtEngine {
smt::SmtEnginePrivate* d_private;
/**
+ * Check that a generated Proof (via getProof()) checks.
+ */
+ void checkProof();
+
+ /**
* Check that a generated Model (via getModel()) actually satisfies
* all user assertions.
*/
@@ -322,6 +333,7 @@ class CVC4_PUBLIC SmtEngine {
friend class ::CVC4::smt::BooleanTermConverter;
friend ::CVC4::StatisticsRegistry* ::CVC4::stats::getStatisticsRegistry(SmtEngine*);
friend void ::CVC4::smt::beforeSearch(std::string, bool, SmtEngine*) throw(ModalException);
+ friend ProofManager* ::CVC4::smt::currentProofManager();
// to access d_modelCommands
friend class ::CVC4::Model;
friend class ::CVC4::theory::TheoryModel;
diff --git a/src/smt/smt_engine.i b/src/smt/smt_engine.i
index ff4105241..00c332bd1 100644
--- a/src/smt/smt_engine.i
+++ b/src/smt/smt_engine.i
@@ -43,8 +43,8 @@ SWIGEXPORT void JNICALL Java_edu_nyu_acsys_CVC4_SmtEngine_dlRef(JNIEnv* jenv, jc
}
%ignore CVC4::SmtEngine::setLogic(const char*);
-%ignore CVC4::SmtEngine::getProof;
%ignore CVC4::stats::getStatisticsRegistry(SmtEngine*);
%ignore CVC4::smt::beforeSearch(std::string, bool, SmtEngine*);
+%ignore CVC4::smt::currentProofManager();
%include "smt/smt_engine.h"
diff --git a/src/smt/smt_engine_check_proof.cpp b/src/smt/smt_engine_check_proof.cpp
new file mode 100644
index 000000000..a731ff024
--- /dev/null
+++ b/src/smt/smt_engine_check_proof.cpp
@@ -0,0 +1,95 @@
+/********************* */
+/*! \file smt_engine_check_proof.cpp
+ ** \verbatim
+ ** Original author: Morgan Deters
+ ** Major contributors: none
+ ** Minor contributors (to current version): none
+ ** This file is part of the CVC4 project.
+ ** Copyright (c) 2009-2013 New York University and The University of Iowa
+ ** See the file COPYING in the top-level source directory for licensing
+ ** information.\endverbatim
+ **
+ ** \brief [[ Add one-line brief description here ]]
+ **
+ ** [[ Add lengthier description here ]]
+ ** \todo document this file
+ **/
+
+#include "smt/smt_engine.h"
+#include "util/statistics_registry.h"
+#include "check.h"
+
+#include <cstdlib>
+#include <cstring>
+#include <fstream>
+#include <string>
+#include <unistd.h>
+
+using namespace CVC4;
+using namespace std;
+
+namespace CVC4 {
+
+namespace proof {
+ extern const char *const plf_signatures;
+}/* CVC4::proof namespace */
+
+namespace smt {
+
+class UnlinkProofFile {
+ string d_filename;
+public:
+ UnlinkProofFile(const char* filename) : d_filename(filename) {}
+ ~UnlinkProofFile() { unlink(d_filename.c_str()); }
+};/* class UnlinkProofFile */
+
+}/* CVC4::smt namespace */
+
+}/* CVC4 namespace */
+
+void SmtEngine::checkProof() {
+
+#ifdef CVC4_PROOF
+
+ Chat() << "generating proof..." << endl;
+
+ Proof* pf = getProof();
+
+ Chat() << "checking proof..." << endl;
+
+ if(!d_logic.isPure(theory::THEORY_BOOL) &&
+ !d_logic.isPure(theory::THEORY_UF)) {
+ // no checking for these yet
+ Notice() << "Notice: no proof-checking for non-UF proofs yet" << endl;
+ return;
+ }
+
+ char* pfFile = strdup("/tmp/cvc4_proof.XXXXXX");
+ int fd = mkstemp(pfFile);
+
+ // ensure this temp file is removed after
+ smt::UnlinkProofFile unlinker(pfFile);
+
+ ofstream pfStream(pfFile);
+ pfStream << proof::plf_signatures << endl;
+ pf->toStream(pfStream);
+ pfStream.close();
+ args a;
+ a.show_runs = false;
+ a.no_tail_calls = false;
+ a.compile_scc = false;
+ a.compile_scc_debug = false;
+ a.run_scc = false;
+ a.use_nested_app = false;
+ a.compile_lib = false;
+ init();
+ check_file(pfFile, args());
+ close(fd);
+
+#else /* CVC4_PROOF */
+
+ Unreachable("This version of CVC4 was built without proof support; cannot check proofs.");
+
+#endif /* CVC4_PROOF */
+
+}
diff --git a/src/smt/smt_engine_scope.h b/src/smt/smt_engine_scope.h
index 21644d3f4..2389181b5 100644
--- a/src/smt/smt_engine_scope.h
+++ b/src/smt/smt_engine_scope.h
@@ -22,10 +22,14 @@
#include "util/cvc4_assert.h"
#include "expr/node_manager.h"
#include "util/output.h"
+#include "proof/proof.h"
#pragma once
namespace CVC4 {
+
+class ProofManager;
+
namespace smt {
extern CVC4_THREADLOCAL(SmtEngine*) s_smtEngine_current;
@@ -35,6 +39,12 @@ inline SmtEngine* currentSmtEngine() {
return s_smtEngine_current;
}
+inline ProofManager* currentProofManager() {
+ Assert(PROOF_ON());
+ Assert(s_smtEngine_current != NULL);
+ return s_smtEngine_current->d_proofManager;
+}
+
class SmtScope : public NodeManagerScope {
/** The old NodeManager, to be restored on destruction. */
SmtEngine* d_oldSmtEngine;
diff --git a/src/theory/quantifiers/first_order_model.cpp b/src/theory/quantifiers/first_order_model.cpp
index bda124e96..797ca8f70 100644
--- a/src/theory/quantifiers/first_order_model.cpp
+++ b/src/theory/quantifiers/first_order_model.cpp
@@ -16,6 +16,8 @@
#include "theory/quantifiers/model_engine.h"
#include "theory/quantifiers/term_database.h"
#include "theory/quantifiers/quantifiers_attributes.h"
+#include "theory/quantifiers/full_model_check.h"
+#include "theory/quantifiers/qinterval_builder.h"
#define USE_INDEX_ORDERING
@@ -27,8 +29,9 @@ using namespace CVC4::theory;
using namespace CVC4::theory::quantifiers;
using namespace CVC4::theory::quantifiers::fmcheck;
-FirstOrderModel::FirstOrderModel( context::Context* c, std::string name ) : TheoryModel( c, name, true ),
-d_axiom_asserted( c, false ), d_forall_asserts( c ), d_isModelSet( c, false ){
+FirstOrderModel::FirstOrderModel(QuantifiersEngine * qe, context::Context* c, std::string name ) :
+TheoryModel( c, name, true ),
+d_qe( qe ), d_axiom_asserted( c, false ), d_forall_asserts( c ), d_isModelSet( c, false ){
}
@@ -66,16 +69,23 @@ Node FirstOrderModel::getCurrentModelValue( Node n, bool partial ) {
}
void FirstOrderModel::initialize( bool considerAxioms ) {
- processInitialize();
+ processInitialize( true );
//this is called after representatives have been chosen and the equality engine has been built
//for each quantifier, collect all operators we care about
for( int i=0; i<getNumAssertedQuantifiers(); i++ ){
Node f = getAssertedQuantifier( i );
+ processInitializeQuantifier( f );
+ if( d_quant_var_id.find( f )==d_quant_var_id.end() ){
+ for(unsigned i=0; i<f[0].getNumChildren(); i++){
+ d_quant_var_id[f][f[0][i]] = i;
+ }
+ }
if( considerAxioms || !f.hasAttribute(AxiomAttribute()) ){
//initialize relevant models within bodies of all quantifiers
initializeModelForTerm( f[1] );
}
}
+ processInitialize( false );
}
void FirstOrderModel::initializeModelForTerm( Node n ){
@@ -85,14 +95,30 @@ void FirstOrderModel::initializeModelForTerm( Node n ){
}
}
-FirstOrderModelIG::FirstOrderModelIG(context::Context* c, std::string name) : FirstOrderModel(c,name) {
+Node FirstOrderModel::getSomeDomainElement(TypeNode tn){
+ //check if there is even any domain elements at all
+ if (!d_rep_set.hasType(tn)) {
+ Trace("fmc-model-debug") << "Must create domain element for " << tn << "..." << std::endl;
+ Node mbt = d_qe->getTermDatabase()->getModelBasisTerm(tn);
+ d_rep_set.add(mbt);
+ }else if( d_rep_set.d_type_reps[tn].size()==0 ){
+ Message() << "empty reps" << std::endl;
+ exit(0);
+ }
+ return d_rep_set.d_type_reps[tn][0];
+}
+
+FirstOrderModelIG::FirstOrderModelIG(QuantifiersEngine * qe, context::Context* c, std::string name) :
+FirstOrderModel(qe, c,name) {
}
-void FirstOrderModelIG::processInitialize(){
- //rebuild models
- d_uf_model_tree.clear();
- d_uf_model_gen.clear();
+void FirstOrderModelIG::processInitialize( bool ispre ){
+ if( ispre ){
+ //rebuild models
+ d_uf_model_tree.clear();
+ d_uf_model_gen.clear();
+ }
}
void FirstOrderModelIG::processInitializeModelForTerm( Node n ){
@@ -143,7 +169,7 @@ void FirstOrderModelIG::resetEvaluate(){
// each n{ri->d_index[0]/x_0...ri->d_index[depIndex]/x_depIndex, */x_(depIndex+1) ... */x_n } is equivalent in the current model
int FirstOrderModelIG::evaluate( Node n, int& depIndex, RepSetIterator* ri ){
++d_eval_formulas;
- //Debug("fmf-eval-debug") << "Evaluate " << n << " " << phaseReq << std::endl;
+ Debug("fmf-eval-debug2") << "Evaluate " << n << std::endl;
//Notice() << "Eval " << n << std::endl;
if( n.getKind()==NOT ){
int val = evaluate( n[0], depIndex, ri );
@@ -421,7 +447,7 @@ void FirstOrderModelIG::makeEvalUfModel( Node n ){
d_eval_uf_model[n] = uf::UfModelTree( op, d_eval_term_index_order[n] );
d_uf_model_gen[op].makeModel( this, d_eval_uf_model[n] );
//Debug("fmf-index-order") << "Make model for " << n << " : " << std::endl;
- //d_eval_uf_model[n].debugPrint( "fmf-index-order", d_qe, 2 );
+ //d_eval_uf_model[n].debugPrint( std::cout, d_qe->getModel(), 2 );
}
}
}
@@ -513,10 +539,8 @@ Node FirstOrderModelIG::getCurrentUfModelValue( Node n, std::vector< Node > & ar
-
-
FirstOrderModelFmc::FirstOrderModelFmc(QuantifiersEngine * qe, context::Context* c, std::string name) :
-FirstOrderModel(c, name), d_qe(qe){
+FirstOrderModel(qe, c, name){
}
@@ -552,19 +576,21 @@ Node FirstOrderModelFmc::getCurrentUfModelValue( Node n, std::vector< Node > & a
return d_models[n.getOperator()]->evaluate(this, args);
}
-void FirstOrderModelFmc::processInitialize() {
- if( options::fmfFmcInterval() && intervalOp.isNull() ){
- std::vector< TypeNode > types;
- for(unsigned i=0; i<2; i++){
- types.push_back(NodeManager::currentNM()->integerType());
+void FirstOrderModelFmc::processInitialize( bool ispre ) {
+ if( ispre ){
+ if( options::mbqiMode()==quantifiers::MBQI_FMC_INTERVAL && intervalOp.isNull() ){
+ std::vector< TypeNode > types;
+ for(unsigned i=0; i<2; i++){
+ types.push_back(NodeManager::currentNM()->integerType());
+ }
+ TypeNode typ = NodeManager::currentNM()->mkFunctionType( types, NodeManager::currentNM()->integerType() );
+ intervalOp = NodeManager::currentNM()->mkSkolem( "interval_$$", typ, "op representing interval" );
}
- TypeNode typ = NodeManager::currentNM()->mkFunctionType( types, NodeManager::currentNM()->integerType() );
- intervalOp = NodeManager::currentNM()->mkSkolem( "interval_$$", typ, "op representing interval" );
- }
- for( std::map<Node, Def * >::iterator it = d_models.begin(); it != d_models.end(); ++it ){
- it->second->reset();
+ for( std::map<Node, Def * >::iterator it = d_models.begin(); it != d_models.end(); ++it ){
+ it->second->reset();
+ }
+ d_model_basis_rep.clear();
}
- d_model_basis_rep.clear();
}
void FirstOrderModelFmc::processInitializeModelForTerm(Node n) {
@@ -575,19 +601,6 @@ void FirstOrderModelFmc::processInitializeModelForTerm(Node n) {
}
}
-Node FirstOrderModelFmc::getSomeDomainElement(TypeNode tn){
- //check if there is even any domain elements at all
- if (!d_rep_set.hasType(tn)) {
- Trace("fmc-model-debug") << "Must create domain element for " << tn << "..." << std::endl;
- Node mbt = d_qe->getTermDatabase()->getModelBasisTerm(tn);
- d_rep_set.d_type_reps[tn].push_back(mbt);
- }else if( d_rep_set.d_type_reps[tn].size()==0 ){
- Message() << "empty reps" << std::endl;
- exit(0);
- }
- return d_rep_set.d_type_reps[tn][0];
-}
-
bool FirstOrderModelFmc::isStar(Node n) {
return n==getStar(n.getType());
@@ -603,7 +616,7 @@ Node FirstOrderModelFmc::getStar(TypeNode tn) {
Node FirstOrderModelFmc::getStarElement(TypeNode tn) {
Node st = getStar(tn);
- if( options::fmfFmcInterval() && tn.isInteger() ){
+ if( options::mbqiMode()==quantifiers::MBQI_FMC_INTERVAL && tn.isInteger() ){
st = getInterval( st, st );
}
return st;
@@ -684,3 +697,163 @@ bool FirstOrderModelFmc::isInRange( Node v, Node i ) {
return v==i;
}
}
+
+
+FirstOrderModelQInt::FirstOrderModelQInt(QuantifiersEngine * qe, context::Context* c, std::string name) :
+FirstOrderModel(qe, c, name) {
+
+}
+
+void FirstOrderModelQInt::processInitialize( bool ispre ) {
+ if( !ispre ){
+ Trace("qint-debug") << "Process initialize" << std::endl;
+ for( std::map<Node, QIntDef * >::iterator it = d_models.begin(); it != d_models.end(); ++it ) {
+ Node op = it->first;
+ TypeNode tno = op.getType();
+ Trace("qint-debug") << " Init " << op << " " << tno << std::endl;
+ for( unsigned i=0; i<tno.getNumChildren(); i++) {
+ //make sure a representative of the type exists
+ if( !d_rep_set.hasType( tno[i] ) ){
+ Node e = getSomeDomainElement( tno[i] );
+ Trace("qint-debug") << " * Initialize type " << tno[i] << ", add ";
+ Trace("qint-debug") << e << " " << e.getType() << std::endl;
+ //d_rep_set.add( e );
+ }
+ }
+ }
+ }
+}
+
+Node FirstOrderModelQInt::getFunctionValue(Node op, const char* argPrefix ) {
+ Trace("qint-debug") << "Get function value for " << op << std::endl;
+ TypeNode type = op.getType();
+ std::vector< Node > vars;
+ for( size_t i=0; i<type.getNumChildren()-1; i++ ){
+ std::stringstream ss;
+ ss << argPrefix << (i+1);
+ Node b = NodeManager::currentNM()->mkBoundVar( ss.str(), type[i] );
+ vars.push_back( b );
+ }
+ Node boundVarList = NodeManager::currentNM()->mkNode(kind::BOUND_VAR_LIST, vars);
+ Node curr = d_models[op]->getFunctionValue( this, vars );
+ Node fv = NodeManager::currentNM()->mkNode(kind::LAMBDA, boundVarList, curr);
+ Trace("qint-debug") << "Return " << fv << std::endl;
+ return fv;
+}
+
+Node FirstOrderModelQInt::getCurrentUfModelValue( Node n, std::vector< Node > & args, bool partial ) {
+ Debug("qint-debug") << "get curr uf value " << n << std::endl;
+ return d_models[n]->evaluate( this, args );
+}
+
+void FirstOrderModelQInt::processInitializeModelForTerm(Node n) {
+ Debug("qint-debug") << "process init " << n << " " << n.getKind() << std::endl;
+
+ if( n.getKind()==APPLY_UF || n.getKind()==VARIABLE || n.getKind()==SKOLEM ){
+ Node op = n.getKind()==APPLY_UF ? n.getOperator() : n;
+ if( d_models.find(op)==d_models.end()) {
+ Debug("qint-debug") << "init model for " << op << std::endl;
+ d_models[op] = new QIntDef;
+ }
+ }
+}
+
+Node FirstOrderModelQInt::getUsedRepresentative( Node n ) {
+ if( hasTerm( n ) ){
+ if( n.getType().isBoolean() ){
+ return areEqual(n, d_true) ? d_true : d_false;
+ }else{
+ return getRepresentative( n );
+ }
+ }else{
+ Trace("qint-debug") << "Get rep " << n << " " << n.getType() << std::endl;
+ Assert( d_rep_set.hasType( n.getType() ) && !d_rep_set.d_type_reps[n.getType()].empty() );
+ return d_rep_set.d_type_reps[n.getType()][0];
+ }
+}
+
+void FirstOrderModelQInt::processInitializeQuantifier( Node q ) {
+ if( d_var_order.find( q )==d_var_order.end() ){
+ d_var_order[q] = new QuantVarOrder( q );
+ d_var_order[q]->debugPrint("qint-var-order");
+ Trace("qint-var-order") << std::endl;
+ }
+}
+unsigned FirstOrderModelQInt::getOrderedNumVars( Node q ) {
+ //return q[0].getNumChildren();
+ return d_var_order[q]->getNumVars();
+}
+
+TypeNode FirstOrderModelQInt::getOrderedVarType( Node q, int i ) {
+ //return q[0][i].getType();
+ return d_var_order[q]->getVar( i ).getType();
+}
+
+int FirstOrderModelQInt::getOrderedVarNumToVarNum( Node q, int i ) {
+ return getVariableId( q, d_var_order[q]->getVar( i ) );
+}
+
+bool FirstOrderModelQInt::isLessThan( Node v1, Node v2 ) {
+ Assert( !v1.isNull() );
+ Assert( !v2.isNull() );
+ if( v1.getType().isSort() ){
+ Assert( getRepId( v1 )!=-1 );
+ Assert( getRepId( v2 )!=-1 );
+ int rid1 = d_rep_id[v1];
+ int rid2 = d_rep_id[v2];
+ return rid1<rid2;
+ }else{
+ return false;
+ }
+}
+
+Node FirstOrderModelQInt::getMin( Node v1, Node v2 ) {
+ return isLessThan( v1, v2 ) ? v1 : v2;
+}
+
+Node FirstOrderModelQInt::getMax( Node v1, Node v2 ) {
+ return isLessThan( v1, v2 ) ? v2 : v1;
+}
+
+Node FirstOrderModelQInt::getMaximum( TypeNode tn ) {
+ return d_max[tn];
+}
+
+Node FirstOrderModelQInt::getNext( TypeNode tn, Node v ) {
+ if( v.isNull() ){
+ return d_min[tn];
+ }else{
+ Assert( getRepId( v )!=-1 );
+ int rid = d_rep_id[v];
+ if( rid==(int)(d_rep_set.d_type_reps[tn].size()-1) ){
+ Assert( false );
+ return Node::null();
+ }else{
+ return d_rep_set.d_type_reps[tn][ rid+1 ];
+ }
+ }
+}
+Node FirstOrderModelQInt::getPrev( TypeNode tn, Node v ) {
+ if( v.isNull() ){
+ Assert( false );
+ return Node::null();
+ }else{
+ Assert( getRepId( v )!=-1 );
+ int rid = d_rep_id[v];
+ if( rid==0 ){
+ return Node::null();
+ }else{
+ return d_rep_set.d_type_reps[tn][ rid-1 ];
+ }
+ }
+}
+
+bool FirstOrderModelQInt::doMeet( Node l1, Node u1, Node l2, Node u2, Node& lr, Node& ur ) {
+ Trace("qint-debug2") << "doMeet " << l1 << "..." << u1 << " with " << l2 << "..." << u2 << std::endl;
+ Assert( !u1.isNull() );
+ Assert( !u2.isNull() );
+ lr = l1.isNull() ? l2 : ( l2.isNull() ? l1 : getMax( l1, l2 ) );
+ ur = getMin( u1, u2 );
+ //return lr==ur || lr.isNull() || isLessThan( lr, ur );
+ return lr.isNull() || isLessThan( lr, ur );
+}
diff --git a/src/theory/quantifiers/first_order_model.h b/src/theory/quantifiers/first_order_model.h
index b5bdff9ee..ab3a1aa52 100644
--- a/src/theory/quantifiers/first_order_model.h
+++ b/src/theory/quantifiers/first_order_model.h
@@ -33,16 +33,21 @@ class FirstOrderModelIG;
namespace fmcheck {
class FirstOrderModelFmc;
}
+class FirstOrderModelQInt;
class FirstOrderModel : public TheoryModel
{
-private:
+protected:
+ /** quant engine */
+ QuantifiersEngine * d_qe;
/** whether an axiom is asserted */
context::CDO< bool > d_axiom_asserted;
/** list of quantifiers asserted in the current context */
context::CDList<Node> d_forall_asserts;
/** is model set */
context::CDO< bool > d_isModelSet;
+ /** get variable id */
+ std::map< Node, std::map< Node, int > > d_quant_var_id;
/** get current model value */
virtual Node getCurrentUfModelValue( Node n, std::vector< Node > & args, bool partial ) = 0;
public: //for Theory Quantifiers:
@@ -57,20 +62,28 @@ public: //for Theory Quantifiers:
/** initialize model for term */
void initializeModelForTerm( Node n );
virtual void processInitializeModelForTerm( Node n ) = 0;
+ virtual void processInitializeQuantifier( Node q ) {}
public:
- FirstOrderModel( context::Context* c, std::string name );
+ FirstOrderModel(QuantifiersEngine * qe, context::Context* c, std::string name );
virtual ~FirstOrderModel(){}
virtual FirstOrderModelIG * asFirstOrderModelIG() { return NULL; }
virtual fmcheck::FirstOrderModelFmc * asFirstOrderModelFmc() { return NULL; }
+ virtual FirstOrderModelQInt * asFirstOrderModelQInt() { return NULL; }
// initialize the model
void initialize( bool considerAxioms = true );
- virtual void processInitialize() = 0;
+ virtual void processInitialize( bool ispre ) = 0;
/** mark model set */
void markModelSet() { d_isModelSet = true; }
/** is model set */
bool isModelSet() { return d_isModelSet; }
/** get current model value */
Node getCurrentModelValue( Node n, bool partial = false );
+ /** get variable id */
+ int getVariableId(Node f, Node n) {
+ return d_quant_var_id.find( f )!=d_quant_var_id.end() ? d_quant_var_id[f][n] : -1;
+ }
+ /** get some domain element */
+ Node getSomeDomainElement(TypeNode tn);
};/* class FirstOrderModel */
@@ -93,10 +106,10 @@ private:
Node getCurrentUfModelValue( Node n, std::vector< Node > & args, bool partial );
//the following functions are for evaluating quantifier bodies
public:
- FirstOrderModelIG(context::Context* c, std::string name);
+ FirstOrderModelIG(QuantifiersEngine * qe, context::Context* c, std::string name);
FirstOrderModelIG * asFirstOrderModelIG() { return this; }
// initialize the model
- void processInitialize();
+ void processInitialize( bool ispre );
//for initialize model
void processInitializeModelForTerm( Node n );
/** reset evaluation */
@@ -128,8 +141,6 @@ class FirstOrderModelFmc : public FirstOrderModel
{
friend class FullModelChecker;
private:
- /** quant engine */
- QuantifiersEngine * d_qe;
/** models for UF */
std::map<Node, Def * > d_models;
std::map<TypeNode, Node > d_model_basis_rep;
@@ -143,8 +154,7 @@ public:
FirstOrderModelFmc(QuantifiersEngine * qe, context::Context* c, std::string name);
FirstOrderModelFmc * asFirstOrderModelFmc() { return this; }
// initialize the model
- void processInitialize();
-
+ void processInitialize( bool ispre );
Node getFunctionValue(Node op, const char* argPrefix );
bool isStar(Node n);
@@ -152,7 +162,6 @@ public:
Node getStarElement(TypeNode tn);
bool isModelBasisTerm(Node n);
Node getModelBasisTerm(TypeNode tn);
- Node getSomeDomainElement(TypeNode tn);
bool isInterval(Node n);
Node getInterval( Node lb, Node ub );
bool isInRange( Node v, Node i );
@@ -161,6 +170,50 @@ public:
}
+class QIntDef;
+class QuantVarOrder;
+class FirstOrderModelQInt : public FirstOrderModel
+{
+ friend class QIntervalBuilder;
+private:
+ /** uf op to some representation */
+ std::map<Node, QIntDef * > d_models;
+ /** representatives to ids */
+ std::map< Node, int > d_rep_id;
+ std::map< TypeNode, Node > d_min;
+ std::map< TypeNode, Node > d_max;
+ /** quantifiers to information regarding variable ordering */
+ std::map<Node, QuantVarOrder * > d_var_order;
+ /** get current model value */
+ Node getCurrentUfModelValue( Node n, std::vector< Node > & args, bool partial );
+ void processInitializeModelForTerm(Node n);
+public:
+ FirstOrderModelQInt(QuantifiersEngine * qe, context::Context* c, std::string name);
+ FirstOrderModelQInt * asFirstOrderModelQInt() { return this; }
+ void processInitialize( bool ispre );
+ Node getFunctionValue(Node op, const char* argPrefix );
+
+ Node getUsedRepresentative( Node n );
+ int getRepId( Node n ) { return d_rep_id.find( n )==d_rep_id.end() ? -1 : d_rep_id[n]; }
+ bool isLessThan( Node v1, Node v2 );
+ Node getMin( Node v1, Node v2 );
+ Node getMax( Node v1, Node v2 );
+ Node getMinimum( TypeNode tn ) { return getNext( tn, Node::null() ); }
+ Node getMaximum( TypeNode tn );
+ bool isMinimum( Node n ) { return n==getMinimum( n.getType() ); }
+ bool isMaximum( Node n ) { return n==getMaximum( n.getType() ); }
+ Node getNext( TypeNode tn, Node v );
+ Node getPrev( TypeNode tn, Node v );
+ bool doMeet( Node l1, Node u1, Node l2, Node u2, Node& lr, Node& ur );
+ QuantVarOrder * getVarOrder( Node q ) { return d_var_order[q]; }
+
+ void processInitializeQuantifier( Node q ) ;
+ unsigned getOrderedNumVars( Node q );
+ TypeNode getOrderedVarType( Node q, int i );
+ int getOrderedVarNumToVarNum( Node q, int i );
+};
+
+
}/* CVC4::theory::quantifiers namespace */
}/* CVC4::theory namespace */
}/* CVC4 namespace */
diff --git a/src/theory/quantifiers/full_model_check.cpp b/src/theory/quantifiers/full_model_check.cpp
index 2f32ec5e6..c7d7b7415 100644
--- a/src/theory/quantifiers/full_model_check.cpp
+++ b/src/theory/quantifiers/full_model_check.cpp
@@ -60,9 +60,9 @@ bool EntryTrie::hasGeneralization( FirstOrderModelFmc * m, Node c, int index ) {
return true;
}
}
- if( !options::fmfFmcInterval() || !c[index].getType().isInteger() ){
+ if( options::mbqiMode()!=quantifiers::MBQI_FMC_INTERVAL || !c[index].getType().isInteger() ){
//for star: check if all children are defined and have generalizations
- if( options::fmfFmcCoverSimplify() && c[index]==st ){
+ if( c[index]==st ){ ///options::fmfFmcCoverSimplify()
//check if all children exist and are complete
int num_child_def = d_child.size() - (d_child.find(st)!=d_child.end() ? 1 : 0);
if( num_child_def==m->d_rep_set.getNumRepresentatives(tn) ){
@@ -92,7 +92,7 @@ int EntryTrie::getGeneralizationIndex( FirstOrderModelFmc * m, std::vector<Node>
return d_data;
}else{
int minIndex = -1;
- if( options::fmfFmcInterval() && inst[index].getType().isInteger() ){
+ if( options::mbqiMode()==quantifiers::MBQI_FMC_INTERVAL && inst[index].getType().isInteger() ){
for( std::map<Node,EntryTrie>::iterator it = d_child.begin(); it != d_child.end(); ++it ){
//if( !m->isInterval( it->first ) ){
// std::cout << "Not an interval during getGenIndex " << it->first << std::endl;
@@ -327,7 +327,7 @@ QModelBuilder( c, qe ){
bool FullModelChecker::optBuildAtFullModel() {
//need to build after full model has taken effect if we are constructing interval models
// this is because we need to have a constant in all integer equivalence classes
- return options::fmfFmcInterval();
+ return options::mbqiMode()==quantifiers::MBQI_FMC_INTERVAL;
}
void FullModelChecker::processBuildModel(TheoryModel* m, bool fullModel){
@@ -443,7 +443,7 @@ void FullModelChecker::processBuildModel(TheoryModel* m, bool fullModel){
Trace("fmc-warn") << "Warning : model has non-constant argument in model " << ri << std::endl;
}
children.push_back(ri);
- if( !options::fmfFmcInterval() || !ri.getType().isInteger() ){
+ if( options::mbqiMode()!=quantifiers::MBQI_FMC_INTERVAL || !ri.getType().isInteger() ){
if (fm->isModelBasisTerm(ri) ) {
ri = fm->getStar( ri.getType() );
}else{
@@ -485,7 +485,7 @@ void FullModelChecker::processBuildModel(TheoryModel* m, bool fullModel){
}
- if( options::fmfFmcInterval() ){
+ if( options::mbqiMode()==quantifiers::MBQI_FMC_INTERVAL ){
convertIntervalModel( fm, op );
}
@@ -588,7 +588,6 @@ bool FullModelChecker::doExhaustiveInstantiation( FirstOrderModel * fm, Node f,
std::vector< TypeNode > types;
for(unsigned i=0; i<f[0].getNumChildren(); i++){
types.push_back(f[0][i].getType());
- d_quant_var_id[f][f[0][i]] = i;
}
TypeNode typ = NodeManager::currentNM()->mkFunctionType( types, NodeManager::currentNM()->booleanType() );
Node op = NodeManager::currentNM()->mkSkolem( "fmc_$$", typ, "op created for full-model checking" );
@@ -599,7 +598,7 @@ bool FullModelChecker::doExhaustiveInstantiation( FirstOrderModel * fm, Node f,
initializeType( fmfmc, f[0][i].getType() );
}
- if( !options::fmfModelBasedInst() ){
+ if( options::mbqiMode()==MBQI_NONE ){
//just exhaustive instantiate
Node c = mkCondDefault( fmfmc, f );
d_quant_models[f].addEntry( fmfmc, c, d_false );
@@ -958,8 +957,8 @@ void FullModelChecker::doVariableEquality( FirstOrderModelFmc * fm, Node f, Def
}else{
TypeNode tn = eq[0].getType();
if( tn.isSort() ){
- int j = getVariableId(f, eq[0]);
- int k = getVariableId(f, eq[1]);
+ int j = fm->getVariableId(f, eq[0]);
+ int k = fm->getVariableId(f, eq[1]);
if( !fm->d_rep_set.hasType( tn ) ){
getSomeDomainElement( fm, tn ); //to verify the type is initialized
}
@@ -977,7 +976,7 @@ void FullModelChecker::doVariableEquality( FirstOrderModelFmc * fm, Node f, Def
}
void FullModelChecker::doVariableRelation( FirstOrderModelFmc * fm, Node f, Def & d, Def & dc, Node v) {
- int j = getVariableId(f, v);
+ int j = fm->getVariableId(f, v);
for (unsigned i=0; i<dc.d_cond.size(); i++) {
Node val = dc.d_value[i];
if( val.isNull() ){
@@ -1074,7 +1073,7 @@ void FullModelChecker::doUninterpretedCompose2( FirstOrderModelFmc * fm, Node f,
Trace("fmc-uf-process") << "Process " << v << std::endl;
bool bind_var = false;
if( !v.isNull() && v.getKind()==kind::BOUND_VARIABLE ){
- int j = getVariableId(f, v);
+ int j = fm->getVariableId(f, v);
Trace("fmc-uf-process") << v << " is variable #" << j << std::endl;
if (!fm->isStar(cond[j+1]) && !fm->isInterval(cond[j+1])) {
v = cond[j+1];
@@ -1084,7 +1083,7 @@ void FullModelChecker::doUninterpretedCompose2( FirstOrderModelFmc * fm, Node f,
}
if (bind_var) {
Trace("fmc-uf-process") << "bind variable..." << std::endl;
- int j = getVariableId(f, v);
+ int j = fm->getVariableId(f, v);
if( fm->isStar(cond[j+1]) ){
for (std::map<Node, EntryTrie>::iterator it = curr.d_child.begin(); it != curr.d_child.end(); ++it) {
cond[j+1] = it->first;
@@ -1104,7 +1103,7 @@ void FullModelChecker::doUninterpretedCompose2( FirstOrderModelFmc * fm, Node f,
}
}else{
if( !v.isNull() ){
- if( options::fmfFmcInterval() && v.getType().isInteger() ){
+ if( options::mbqiMode()==quantifiers::MBQI_FMC_INTERVAL && v.getType().isInteger() ){
for (std::map<Node, EntryTrie>::iterator it = curr.d_child.begin(); it != curr.d_child.end(); ++it) {
if( fm->isInRange( v, it->first ) ){
doUninterpretedCompose2(fm, f, entries, index+1, cond, val, it->second);
@@ -1166,7 +1165,7 @@ int FullModelChecker::isCompat( FirstOrderModelFmc * fm, std::vector< Node > & c
Trace("fmc-debug3") << "isCompat " << c << std::endl;
Assert(cond.size()==c.getNumChildren()+1);
for (unsigned i=1; i<cond.size(); i++) {
- if( options::fmfFmcInterval() && cond[i].getType().isInteger() ){
+ if( options::mbqiMode()==quantifiers::MBQI_FMC_INTERVAL && cond[i].getType().isInteger() ){
Node iv = doIntervalMeet( fm, cond[i], c[i-1], false );
if( iv.isNull() ){
return 0;
@@ -1185,7 +1184,7 @@ bool FullModelChecker::doMeet( FirstOrderModelFmc * fm, std::vector< Node > & co
Assert(cond.size()==c.getNumChildren()+1);
for (unsigned i=1; i<cond.size(); i++) {
if( cond[i]!=c[i-1] ) {
- if( options::fmfFmcInterval() && cond[i].getType().isInteger() ){
+ if( options::mbqiMode()==quantifiers::MBQI_FMC_INTERVAL && cond[i].getType().isInteger() ){
Node iv = doIntervalMeet( fm, cond[i], c[i-1] );
if( !iv.isNull() ){
cond[i] = iv;
@@ -1255,7 +1254,7 @@ Node FullModelChecker::mkCondDefault( FirstOrderModelFmc * fm, Node f) {
}
void FullModelChecker::mkCondDefaultVec( FirstOrderModelFmc * fm, Node f, std::vector< Node > & cond ) {
- Trace("fmc-debug") << "Make default vec, intervals = " << options::fmfFmcInterval() << std::endl;
+ Trace("fmc-debug") << "Make default vec, intervals = " << (options::mbqiMode()==quantifiers::MBQI_FMC_INTERVAL) << std::endl;
//get function symbol for f
cond.push_back(d_quant_cond[f]);
for (unsigned i=0; i<f[0].getNumChildren(); i++) {
diff --git a/src/theory/quantifiers/full_model_check.h b/src/theory/quantifiers/full_model_check.h
index 606392831..db5abb01e 100644
--- a/src/theory/quantifiers/full_model_check.h
+++ b/src/theory/quantifiers/full_model_check.h
@@ -92,7 +92,6 @@ protected:
std::map<Node, Node > d_quant_cond;
std::map< TypeNode, Node > d_array_cond;
std::map< Node, Node > d_array_term_cond;
- std::map<Node, std::map< Node, int > > d_quant_var_id;
std::map<Node, std::vector< int > > d_star_insts;
void initializeType( FirstOrderModelFmc * fm, TypeNode tn );
Node normalizeArgReps(FirstOrderModelFmc * fm, Node op, Node n);
@@ -138,7 +137,6 @@ public:
bool optBuildAtFullModel();
- int getVariableId(Node f, Node n) { return d_quant_var_id[f][n]; }
void debugPrintCond(const char * tr, Node n, bool dispStar = false);
void debugPrint(const char * tr, Node n, bool dispStar = false);
diff --git a/src/theory/quantifiers/model_builder.cpp b/src/theory/quantifiers/model_builder.cpp
index ea6f2d775..cb63ccd45 100644
--- a/src/theory/quantifiers/model_builder.cpp
+++ b/src/theory/quantifiers/model_builder.cpp
@@ -44,7 +44,7 @@ bool QModelBuilder::isQuantifierActive( Node f ) {
bool QModelBuilder::optUseModel() {
- return options::fmfModelBasedInst() || options::fmfBoundInt();
+ return options::mbqiMode()!=MBQI_NONE || options::fmfBoundInt();
}
void QModelBuilder::debugModel( FirstOrderModel* fm ){
@@ -124,6 +124,7 @@ Node QModelBuilderIG::getCurrentUfModelValue( FirstOrderModel* fm, Node n, std::
void QModelBuilderIG::processBuildModel( TheoryModel* m, bool fullModel ) {
FirstOrderModel* f = (FirstOrderModel*)m;
FirstOrderModelIG* fm = f->asFirstOrderModelIG();
+ Trace("model-engine-debug") << "Process build model, fullModel = " << fullModel << " " << optUseModel() << std::endl;
if( fullModel ){
Assert( d_curr_model==fm );
//update models
@@ -145,7 +146,7 @@ void QModelBuilderIG::processBuildModel( TheoryModel* m, bool fullModel ) {
reset( fm );
//only construct first order model if optUseModel() is true
if( optUseModel() ){
- Trace("model-engine-debug") << "Initializing quantifiers..." << std::endl;
+ Trace("model-engine-debug") << "Initializing " << fm->getNumAssertedQuantifiers() << " quantifiers..." << std::endl;
//check if any quantifiers are un-initialized
for( int i=0; i<fm->getNumAssertedQuantifiers(); i++ ){
Node f = fm->getAssertedQuantifier( i );
@@ -272,17 +273,15 @@ int QModelBuilderIG::initializeQuantifier( Node f, Node fp ){
++(d_statistics.d_num_quants_init);
}
//try to add it
- if( optInstGen() ){
- Trace("inst-fmf-init") << "Init: try to add match " << d_quant_basis_match[f] << std::endl;
- //add model basis instantiation
- if( d_qe->addInstantiation( fp, d_quant_basis_match[f], false, false, false ) ){
- d_quant_basis_match_added[f] = true;
- return 1;
- }else{
- //shouldn't happen usually, but will occur if x != y is a required literal for f.
- //Notice() << "No model basis for " << f << std::endl;
- d_quant_basis_match_added[f] = false;
- }
+ Trace("inst-fmf-init") << "Init: try to add match " << d_quant_basis_match[f] << std::endl;
+ //add model basis instantiation
+ if( d_qe->addInstantiation( fp, d_quant_basis_match[f], false, false, false ) ){
+ d_quant_basis_match_added[f] = true;
+ return 1;
+ }else{
+ //shouldn't happen usually, but will occur if x != y is a required literal for f.
+ //Notice() << "No model basis for " << f << std::endl;
+ d_quant_basis_match_added[f] = false;
}
}
return 0;
@@ -397,7 +396,6 @@ bool QModelBuilderIG::isTermActive( Node n ){
//do exhaustive instantiation
bool QModelBuilderIG::doExhaustiveInstantiation( FirstOrderModel * fm, Node f, int effort ) {
if( optUseModel() ){
-
RepSetIterator riter( d_qe, &(d_qe->getModel()->d_rep_set) );
if( riter.setQuantifier( f ) ){
FirstOrderModelIG * fmig = (FirstOrderModelIG*)d_qe->getModel();
@@ -418,6 +416,7 @@ bool QModelBuilderIG::doExhaustiveInstantiation( FirstOrderModel * fm, Node f, i
//if evaluate(...)==1, then the instantiation is already true in the model
// depIndex is the index of the least significant variable that this evaluation relies upon
depIndex = riter.getNumTerms()-1;
+ Debug("fmf-model-eval") << "We will evaluate " << d_qe->getTermDatabase()->getInstConstantBody( f ) << std::endl;
eval = fmig->evaluate( d_qe->getTermDatabase()->getInstConstantBody( f ), depIndex, &riter );
if( eval==1 ){
Debug("fmf-model-eval") << " Returned success with depIndex = " << depIndex << std::endl;
@@ -456,7 +455,7 @@ bool QModelBuilderIG::doExhaustiveInstantiation( FirstOrderModel * fm, Node f, i
d_statistics.d_eval_lits += fmig->d_eval_lits;
d_statistics.d_eval_lits_unknown += fmig->d_eval_lits_unknown;
}
- Trace("inst-fmf-ei") << "Finished: " << std::endl;
+ Trace("inst-fmf-ei") << "For " << f << ", finished: " << std::endl;
Trace("inst-fmf-ei") << " Inst Tried: " << d_triedLemmas << std::endl;
Trace("inst-fmf-ei") << " Inst Added: " << d_addedLemmas << std::endl;
if( d_addedLemmas>1000 ){
diff --git a/src/theory/quantifiers/model_engine.cpp b/src/theory/quantifiers/model_engine.cpp
index 99f5e8df6..f314584cd 100644
--- a/src/theory/quantifiers/model_engine.cpp
+++ b/src/theory/quantifiers/model_engine.cpp
@@ -21,6 +21,8 @@
#include "theory/quantifiers/first_order_model.h"
#include "theory/quantifiers/term_database.h"
#include "theory/quantifiers/quantifiers_attributes.h"
+#include "theory/quantifiers/full_model_check.h"
+#include "theory/quantifiers/qinterval_builder.h"
using namespace std;
using namespace CVC4;
@@ -34,11 +36,18 @@ using namespace CVC4::theory::inst;
ModelEngine::ModelEngine( context::Context* c, QuantifiersEngine* qe ) :
QuantifiersModule( qe ){
- if( options::fmfFullModelCheck() || options::fmfBoundInt() ){
+ Trace("model-engine-debug") << "Initialize model engine, mbqi : " << options::mbqiMode() << " " << options::fmfBoundInt() << std::endl;
+ if( options::mbqiMode()==MBQI_FMC || options::mbqiMode()==quantifiers::MBQI_FMC_INTERVAL || options::fmfBoundInt() ){
+ Trace("model-engine-debug") << "...make fmc builder." << std::endl;
d_builder = new fmcheck::FullModelChecker( c, qe );
- }else if( options::fmfNewInstGen() ){
+ }else if( options::mbqiMode()==MBQI_INTERVAL ){
+ Trace("model-engine-debug") << "...make interval builder." << std::endl;
+ d_builder = new QIntervalBuilder( c, qe );
+ }else if( options::mbqiMode()==MBQI_INST_GEN ){
+ Trace("model-engine-debug") << "...make inst-gen builder." << std::endl;
d_builder = new QModelBuilderInstGen( c, qe );
}else{
+ Trace("model-engine-debug") << "...make default model builder." << std::endl;
d_builder = new QModelBuilderDefault( c, qe );
}
@@ -203,7 +212,7 @@ int ModelEngine::checkModel(){
}
Trace("model-engine-debug") << "Do exhaustive instantiation..." << std::endl;
- int e_max = options::fmfFullModelCheck() && options::fmfModelBasedInst() ? 2 : 1;
+ int e_max = options::mbqiMode()==MBQI_FMC || options::mbqiMode()==MBQI_FMC_INTERVAL ? 2 : 1;
for( int e=0; e<e_max; e++) {
if (d_addedLemmas==0) {
for( int i=0; i<fm->getNumAssertedQuantifiers(); i++ ){
@@ -221,6 +230,8 @@ int ModelEngine::checkModel(){
if( optOneQuantPerRound() && d_addedLemmas>0 ){
break;
}
+ }else{
+ Trace("inst-fmf-ei") << "-> Inactive : " << f << std::endl;
}
}
}
@@ -239,11 +250,12 @@ void ModelEngine::exhaustiveInstantiate( Node f, int effort ){
d_builder->d_addedLemmas = 0;
d_builder->d_incomplete_check = false;
if( d_builder->doExhaustiveInstantiation( d_quantEngine->getModel(), f, effort ) ){
+ Trace("inst-fmf-ei") << "-> Builder determined instantiation(s)." << std::endl;
d_triedLemmas += d_builder->d_triedLemmas;
d_addedLemmas += d_builder->d_addedLemmas;
d_incomplete_check = d_incomplete_check || d_builder->d_incomplete_check;
}else{
- Trace("inst-fmf-ei") << "Exhaustive instantiate " << f << ", effort = " << effort << "..." << std::endl;
+ Trace("inst-fmf-ei") << "-> Exhaustive instantiate " << f << ", effort = " << effort << "..." << std::endl;
Debug("inst-fmf-ei") << " Instantiation Constants: ";
for( size_t i=0; i<f[0].getNumChildren(); i++ ){
Debug("inst-fmf-ei") << d_quantEngine->getTermDatabase()->getInstantiationConstant( f, i ) << " ";
diff --git a/src/theory/quantifiers/model_engine.h b/src/theory/quantifiers/model_engine.h
index 0c3c74b5f..fcbba7aee 100644
--- a/src/theory/quantifiers/model_engine.h
+++ b/src/theory/quantifiers/model_engine.h
@@ -20,7 +20,6 @@
#include "theory/quantifiers_engine.h"
#include "theory/quantifiers/model_builder.h"
#include "theory/theory_model.h"
-#include "theory/quantifiers/full_model_check.h"
#include "theory/quantifiers/relevant_domain.h"
namespace CVC4 {
diff --git a/src/theory/quantifiers/modes.cpp b/src/theory/quantifiers/modes.cpp
index 7da3b150f..10185914e 100644
--- a/src/theory/quantifiers/modes.cpp
+++ b/src/theory/quantifiers/modes.cpp
@@ -77,5 +77,28 @@ std::ostream& operator<<(std::ostream& out, theory::quantifiers::AxiomInstMode m
return out;
}
+std::ostream& operator<<(std::ostream& out, theory::quantifiers::MbqiMode mode) {
+ switch(mode) {
+ case theory::quantifiers::MBQI_DEFAULT:
+ out << "MBQI_DEFAULT";
+ break;
+ case theory::quantifiers::MBQI_NONE:
+ out << "MBQI_NONE";
+ break;
+ case theory::quantifiers::MBQI_INST_GEN:
+ out << "MBQI_INST_GEN";
+ break;
+ case theory::quantifiers::MBQI_FMC:
+ out << "MBQI_FMC";
+ break;
+ case theory::quantifiers::MBQI_INTERVAL:
+ out << "MBQI_INTERVAL";
+ break;
+ default:
+ out << "MbqiMode!UNKNOWN";
+ }
+ return out;
+}
+
}/* CVC4 namespace */
diff --git a/src/theory/quantifiers/modes.h b/src/theory/quantifiers/modes.h
index edf9c78fe..d5c755ad2 100644
--- a/src/theory/quantifiers/modes.h
+++ b/src/theory/quantifiers/modes.h
@@ -55,6 +55,22 @@ typedef enum {
AXIOM_INST_MODE_PRIORITY,
} AxiomInstMode;
+typedef enum {
+ /** default, mbqi from CADE 24 paper */
+ MBQI_DEFAULT,
+ /** no mbqi */
+ MBQI_NONE,
+ /** implementation that mimics inst-gen */
+ MBQI_INST_GEN,
+ /** mbqi from Section 5.4.2 of AJR thesis */
+ MBQI_FMC,
+ /** mbqi with integer intervals */
+ MBQI_FMC_INTERVAL,
+ /** mbqi with interval abstraction of uninterpreted sorts */
+ MBQI_INTERVAL,
+} MbqiMode;
+
+
}/* CVC4::theory::quantifiers namespace */
}/* CVC4::theory namespace */
diff --git a/src/theory/quantifiers/options b/src/theory/quantifiers/options
index 1eb98e7b7..190c7ddc9 100644
--- a/src/theory/quantifiers/options
+++ b/src/theory/quantifiers/options
@@ -76,9 +76,8 @@ option eagerInstQuant --eager-inst-quant bool :default false
option literalMatchMode --literal-matching=MODE CVC4::theory::quantifiers::LiteralMatchMode :default CVC4::theory::quantifiers::LITERAL_MATCH_NONE :include "theory/quantifiers/modes.h" :handler CVC4::theory::quantifiers::stringToLiteralMatchMode :handler-include "theory/quantifiers/options_handlers.h" :predicate CVC4::theory::quantifiers::checkLiteralMatchMode :predicate-include "theory/quantifiers/options_handlers.h"
choose literal matching mode
-option cbqi --enable-cbqi/--disable-cbqi bool :default false
- turns on counterexample-based quantifier instantiation [off by default]
-/turns off counterexample-based quantifier instantiation
+option cbqi --enable-cbqi bool :default false
+ turns on counterexample-based quantifier instantiation
option recurseCbqi --cbqi-recurse bool :default false
turns on recursive counterexample-based quantifier instantiation
@@ -95,36 +94,25 @@ option internalReps /--disable-quant-internal-reps bool :default true
option finiteModelFind --finite-model-find bool :default false
use finite model finding heuristic for quantifier instantiation
-option fmfModelBasedInst /--disable-fmf-mbqi bool :default true
- disable model-based quantifier instantiation for finite model finding
+option mbqiMode --mbqi=MODE CVC4::theory::quantifiers::MbqiMode :read-write :default CVC4::theory::quantifiers::MBQI_DEFAULT :include "theory/quantifiers/modes.h" :handler CVC4::theory::quantifiers::stringToMbqiMode :handler-include "theory/quantifiers/options_handlers.h" :predicate CVC4::theory::quantifiers::checkMbqiMode :predicate-include "theory/quantifiers/options_handlers.h"
+ choose mode for model-based quantifier instantiation
+option fmfOneInstPerRound --mbqi-one-inst-per-round bool :default false
+ only add one instantiation per quantifier per round for mbqi
+option fmfOneQuantPerRound --mbqi-one-quant-per-round bool :default false
+ only add instantiations for one quantifier per round for mbqi
-option fmfFullModelCheck --fmf-fmc bool :default false :read-write
- enable full model check for finite model finding
-option fmfFmcSimple /--disable-fmf-fmc-simple bool :default true
- disable simple models in full model check for finite model finding
-option fmfFmcCoverSimplify /--disable-fmf-fmc-cover-simplify bool :default true
- disable covering simplification of fmc models
-option fmfFmcInterval --fmf-fmc-interval bool :default false
- construct interval models for fmc models
-
-option fmfOneInstPerRound --fmf-one-inst-per-round bool :default false
- only add one instantiation per quantifier per round for fmf
-option fmfOneQuantPerRound --fmf-one-quant-per-round bool :default false
- only add instantiations for one quantifier per round for fmf
option fmfInstEngine --fmf-inst-engine bool :default false
use instantiation engine in conjunction with finite model finding
option fmfRelevantDomain --fmf-relevant-domain bool :default false
use relevant domain computation, similar to complete instantiation (Ge, deMoura 09)
-option fmfNewInstGen --fmf-new-inst-gen bool :default false
- use new inst gen technique for answering sat without exhaustive instantiation
-option fmfInstGen --fmf-inst-gen/--disable-fmf-inst-gen bool :read-write :default true
- enable Inst-Gen instantiation techniques for finite model finding (default)
-/disable Inst-Gen instantiation techniques for finite model finding
+option fmfInstGen /--disable-fmf-inst-gen bool :default true
+ disable Inst-Gen instantiation techniques for finite model finding
option fmfInstGenOneQuantPerRound --fmf-inst-gen-one-quant-per-round bool :default false
only perform Inst-Gen instantiation techniques on one quantifier per round
option fmfFreshDistConst --fmf-fresh-dc bool :default false
use fresh distinguished representative when applying Inst-Gen techniques
-
+option fmfFmcSimple /--disable-fmf-fmc-simple bool :default true
+ disable simple models in full model check for finite model finding
option fmfBoundInt --fmf-bound-int bool :default false
finite model finding on bounded integer quantification
diff --git a/src/theory/quantifiers/options_handlers.h b/src/theory/quantifiers/options_handlers.h
index 410578af0..4929fa60b 100644
--- a/src/theory/quantifiers/options_handlers.h
+++ b/src/theory/quantifiers/options_handlers.h
@@ -73,6 +73,31 @@ priority \n\
\n\
";
+static const std::string mbqiModeHelp = "\
+Model-based quantifier instantiation modes currently supported by the --mbqi option:\n\
+\n\
+default \n\
++ Default, use model-based quantifier instantiation algorithm from CADE 24 finite\n\
+ model finding paper.\n\
+\n\
+none \n\
++ Disable model-based quantifier instantiation.\n\
+\n\
+instgen \n\
++ Use instantiation algorithm that mimics Inst-Gen calculus. \n\
+\n\
+fmc \n\
++ Use algorithm from Section 5.4.2 of thesis Finite Model Finding in Satisfiability \n\
+ Modulo Theories.\n\
+\n\
+fmc-interval \n\
++ Same as fmc, but with intervals for models of integer functions.\n\
+\n\
+interval \n\
++ Use algorithm that abstracts domain elements as intervals. \n\
+\n\
+";
+
inline InstWhenMode stringToInstWhenMode(std::string option, std::string optarg, SmtEngine* smt) throw(OptionException) {
if(optarg == "pre-full") {
return INST_WHEN_PRE_FULL;
@@ -135,6 +160,32 @@ inline AxiomInstMode stringToAxiomInstMode(std::string option, std::string optar
}
}
+inline MbqiMode stringToMbqiMode(std::string option, std::string optarg, SmtEngine* smt) throw(OptionException) {
+ if(optarg == "default") {
+ return MBQI_DEFAULT;
+ } else if(optarg == "none") {
+ return MBQI_NONE;
+ } else if(optarg == "instgen") {
+ return MBQI_INST_GEN;
+ } else if(optarg == "fmc") {
+ return MBQI_FMC;
+ } else if(optarg == "fmc-interval") {
+ return MBQI_FMC_INTERVAL;
+ } else if(optarg == "interval") {
+ return MBQI_INTERVAL;
+ } else if(optarg == "help") {
+ puts(mbqiModeHelp.c_str());
+ exit(1);
+ } else {
+ throw OptionException(std::string("unknown option for --mbqi: `") +
+ optarg + "'. Try --mbqi help.");
+ }
+}
+
+inline void checkMbqiMode(std::string option, MbqiMode mode, SmtEngine* smt) throw(OptionException) {
+
+}
+
}/* CVC4::theory::quantifiers namespace */
}/* CVC4::theory namespace */
}/* CVC4 namespace */
diff --git a/src/theory/quantifiers/qinterval_builder.cpp b/src/theory/quantifiers/qinterval_builder.cpp
new file mode 100755
index 000000000..ce85cecc0
--- /dev/null
+++ b/src/theory/quantifiers/qinterval_builder.cpp
@@ -0,0 +1,1111 @@
+/********************* */
+/*! \file qinterval_builder.cpp
+ ** \verbatim
+ ** Original author: Andrew Reynolds
+ ** Major contributors: none
+ ** Minor contributors (to current version): none
+ ** This file is part of the CVC4 project.
+ ** Copyright (c) 2009-2013 New York University and The University of Iowa
+ ** See the file COPYING in the top-level source directory for licensing
+ ** information.\endverbatim
+ **
+ ** \brief Implementation of qinterval builder
+ **/
+
+
+#include "theory/quantifiers/qinterval_builder.h"
+
+using namespace std;
+using namespace CVC4;
+using namespace CVC4::kind;
+using namespace CVC4::context;
+using namespace CVC4::theory;
+using namespace CVC4::theory::quantifiers;
+
+//lower bound is exclusive
+//upper bound is inclusive
+
+struct QIntSort
+{
+ FirstOrderModelQInt * m;
+ bool operator() (Node i, Node j) {
+ return m->isLessThan( i, j );
+ }
+};
+
+void QIntDef::init_vec( FirstOrderModelQInt * m, Node q, std::vector< Node >& l, std::vector< Node >& u ) {
+ for( unsigned i=0; i<m->getOrderedNumVars( q ); i++ ){
+ l.push_back( Node::null() );
+ u.push_back( m->getMaximum( m->getOrderedVarType( q, i ) ) );
+ }
+}
+
+void QIntDef::debugPrint( const char * c, FirstOrderModelQInt * m, Node q, std::vector< Node >& l, std::vector< Node >& u )
+{
+ Trace(c) << "( ";
+ for( unsigned i=0; i<l.size(); i++ ){
+ if( i>0 ) Trace(c) << ", ";
+ //Trace(c) << l[i] << "..." << u[i];
+ int lindex = l[i].isNull() ? 0 : m->getRepId( l[i] ) + 1;
+ int uindex = m->getRepId( u[i] );
+ Trace(c) << lindex << "..." << uindex;
+ }
+ Trace(c) << " )";
+}
+
+
+int QIntDef::getEvIndex( FirstOrderModelQInt * m, Node n, bool exc ) {
+ if( n.isNull() ){
+ Assert( exc );
+ return 0;
+ }else{
+ int min = 0;
+ int max = (int)(d_def_order.size()-1);
+ while( min!=max ){
+ int index = (min+max)/2;
+ Assert( index>=0 && index<(int)d_def_order.size() );
+ if( n==d_def_order[index] ){
+ max = index;
+ min = index;
+ }else if( m->isLessThan( n, d_def_order[index] ) ){
+ max = index;
+ }else{
+ min = index+1;
+ }
+ }
+ if( n==d_def_order[min] && exc ){
+ min++;
+ }
+ Assert( min>=0 && min<(int)d_def_order.size() );
+ if( ( min!=0 && !m->isLessThan( d_def_order[min-1], n ) && ( !exc || d_def_order[min-1]!=n ) ) ||
+ ( ( exc || d_def_order[min]!=n ) && !m->isLessThan( n, d_def_order[min] ) ) ){
+ Debug("qint-error") << "ERR size : " << d_def_order.size() << ", exc : " << exc << std::endl;
+ for( unsigned i=0; i<d_def_order.size(); i++ ){
+ Debug("qint-error") << "ERR ch #" << i << " : " << d_def_order[i];
+ Debug("qint-error") << " " << m->getRepId( d_def_order[i] ) << std::endl;
+ }
+ Debug("qint-error") << " : " << n << " " << min << " " << m->getRepId( n ) << std::endl;
+ }
+
+ Assert( min==0 || m->isLessThan( d_def_order[min-1], n ) || ( exc && d_def_order[min-1]==n ) );
+ Assert( ( !exc && n==d_def_order[min] ) || m->isLessThan( n, d_def_order[min] ) );
+ return min;
+ }
+}
+
+void QIntDef::addEntry( FirstOrderModelQInt * m, Node q, std::vector< Node >& l, std::vector< Node >& u,
+ Node v, unsigned depth ) {
+ if( depth==0 ){
+ Trace("qint-compose-debug") << "Add entry ";
+ debugPrint( "qint-compose-debug", m, q, l, u );
+ Trace("qint-compose-debug") << " -> " << v << "..." << std::endl;
+ }
+ //Assert( false );
+ if( depth==u.size() ){
+ Assert( d_def_order.empty() );
+ Assert( v.isNull() || v.isConst() || ( v.getType().isSort() && m->getRepId( v )!=-1 ) );
+ d_def_order.push_back( v );
+ }else{
+ /*
+ if( !d_def_order.empty() &&
+ ( l[depth].isNull() || m->isLessThan( l[depth], d_def_order[d_def_order.size()-1] ) ) ){
+ int startEvIndex = getEvIndex( m, l[depth], true );
+ int endEvIndex;
+ if( m->isLessThan( u[depth], d_def_order[d_def_order.size()-1] ) ){
+ endEvIndex = getEvIndex( m, u[depth] );
+ }else{
+ endEvIndex = d_def_order.size()-1;
+ }
+ Trace("qint-compose-debug2") << this << " adding for bounds " << l[depth] << "..." << u[depth] << std::endl;
+ for( int i=startEvIndex; i<=endEvIndex; i++ ){
+ Trace("qint-compose-debug2") << this << " add entry " << d_def_order[i] << std::endl;
+ d_def[d_def_order[i]].addEntry( m, q, l, u, v, depth+1 );
+ }
+ }
+ if( !d_def_order.empty() &&
+ d_def.find(u[depth])==d_def.end() &&
+ !m->isLessThan( d_def_order[d_def_order.size()-1], u[depth] ) ){
+ Trace("qint-compose-debug2") << "Bad : depth : " << depth << std::endl;
+ }
+ Assert( d_def_order.empty() ||
+ d_def.find(u[depth])!=d_def.end() ||
+ m->isLessThan( d_def_order[d_def_order.size()-1], u[depth] ) );
+
+ if( d_def_order.empty() || m->isLessThan( d_def_order[d_def_order.size()-1], u[depth] ) ){
+ Trace("qint-compose-debug2") << this << " add entry new : " << u[depth] << std::endl;
+ d_def_order.push_back( u[depth] );
+ d_def[u[depth]].addEntry( m, q, l, u, v, depth+1 );
+ }
+ */
+ //%%%%%%
+ bool success = true;
+ int nnum = m->getVarOrder( q )->getNextNum( depth );
+ Node pl;
+ Node pu;
+ if( nnum!=-1 ){
+ Trace("qint-compose-debug2") << "...adding entry #" << depth << " is #" << nnum << std::endl;
+ //Assert( l[nnum].isNull() || l[nnum]==l[depth] || m->isLessThan( l[nnum], l[depth] ) );
+ //Assert( u[nnum]==u[depth] || m->isLessThan( u[depth], u[nnum] ) );
+ pl = l[nnum];
+ pu = u[nnum];
+ if( !m->doMeet( l[nnum], u[nnum], l[depth], u[depth], l[nnum], u[nnum] ) ){
+ success = false;
+ }
+ }
+ //%%%%%%
+ if( success ){
+ Node r = u[depth];
+ if( d_def.find( r )!=d_def.end() ){
+ d_def[r].addEntry( m, q, l, u, v, depth+1 );
+ }else{
+ if( !d_def_order.empty() &&
+ !m->isLessThan( d_def_order[d_def_order.size()-1], u[depth] ) ){
+ Trace("qint-compose-debug2") << "Bad : depth : " << depth << " ";
+ Trace("qint-compose-debug2") << d_def_order[d_def_order.size()-1] << " " << u[depth] << std::endl;
+ }
+ Assert( d_def_order.empty() || m->isLessThan( d_def_order[d_def_order.size()-1], r ) );
+ d_def_order.push_back( r );
+ d_def[r].addEntry( m, q, l, u, v, depth+1 );
+ }
+ }
+ if( nnum!=-1 ){
+ l[nnum] = pl;
+ u[nnum] = pu;
+ }
+ }
+}
+
+Node QIntDef::simplify_r( FirstOrderModelQInt * m, Node q, std::vector< Node >& il, std::vector< Node >& iu,
+ unsigned depth ) {
+ if( d_def.empty() ){
+ if( d_def_order.size()!=0 ){
+ Debug("qint-error") << "Simplify, size = " << d_def_order.size() << std::endl;
+ }
+ Assert( d_def_order.size()==1 );
+ return d_def_order[0];
+ }else{
+ Assert( !d_def_order.empty() );
+ std::vector< Node > newDefs;
+ Node curr;
+ for( unsigned i=0; i<d_def_order.size(); i++ ){
+ Node n = d_def[d_def_order[i]].simplify_r( m, q, il, iu, depth+1 );
+ if( i>0 ){
+ if( n==curr && !n.isNull() ){
+ d_def.erase( d_def_order[i-1] );
+ }else{
+ newDefs.push_back( d_def_order[i-1] );
+ }
+ }
+ curr = n;
+ }
+ newDefs.push_back( d_def_order[d_def_order.size()-1] );
+ d_def_order.clear();
+ d_def_order.insert( d_def_order.end(), newDefs.begin(), newDefs.end() );
+ return d_def_order.size()==1 ? curr : Node::null();
+ }
+}
+
+Node QIntDef::simplify( FirstOrderModelQInt * m, Node q ) {
+ std::vector< Node > l;
+ std::vector< Node > u;
+ if( !q.isNull() ){
+ //init_vec( m, q, l, u );
+ }
+ return simplify_r( m, q, l, u, 0 );
+}
+
+bool QIntDef::isTotal_r( FirstOrderModelQInt * m, Node q, std::vector< Node >& l, std::vector< Node >& u,
+ unsigned depth ) {
+ if( d_def_order.empty() ){
+ return false;
+ }else if( d_def.empty() ){
+ return true;
+ }else{
+ //get the current maximum
+ Node mx;
+ if( !q.isNull() ){
+ int pnum = m->getVarOrder( q )->getPrevNum( depth );
+ if( pnum!=-1 ){
+ mx = u[pnum];
+ }
+ }
+ if( mx.isNull() ){
+ mx = m->getMaximum( d_def_order[d_def_order.size()-1].getType() );
+ }
+ //if not current maximum
+ if( d_def_order[d_def_order.size()-1]!=mx ){
+ return false;
+ }else{
+ Node pu = u[depth];
+ for( unsigned i=0; i<d_def_order.size(); i++ ){
+ u[depth] = d_def_order[i];
+ if( !d_def[d_def_order[i]].isTotal_r( m, q, l, u, depth+1 ) ){
+ return false;
+ }
+ }
+ u[depth] = pu;
+ return true;
+ }
+ }
+}
+
+bool QIntDef::isTotal( FirstOrderModelQInt * m, Node q ) {
+ std::vector< Node > l;
+ std::vector< Node > u;
+ if( !q.isNull() ){
+ init_vec( m, q, l, u );
+ }
+ return isTotal_r( m, q, l, u, 0 );
+}
+
+void QIntDef::construct_compose_r( FirstOrderModelQInt * m, Node q,
+ std::vector< Node >& l, std::vector< Node >& u,
+ Node n, QIntDef * f,
+ std::vector< Node >& args,
+ std::map< unsigned, QIntDef >& children,
+ std::map< unsigned, Node >& bchildren,
+ QIntVarNumIndex& vindex, unsigned depth ) {
+ //check for short circuit
+ if( !f ){
+ if( !args.empty() ){
+ if( ( n.getKind()==OR && args[args.size()-1]==m->d_true ) ||
+ ( n.getKind()==AND && args[args.size()-1]==m->d_false ) ){
+ addEntry( m, q, l, u, args[args.size()-1] );
+ return;
+ }
+ }
+ }
+
+ for( unsigned i=0; i<depth; i++ ) { Trace("qint-compose") << " "; }
+ Trace("qint-compose") << (f ? "U" : "I" ) << "C( ";
+ for( unsigned i=0; i<l.size(); i++ ){
+ if( i>0 ) Trace("qint-compose") << ", ";
+ //Trace("qint-compose") << l[i] << "..." << u[i];
+ int lindex = l[i].isNull() ? 0 : m->getRepId( l[i] ) + 1;
+ int uindex = m->getRepId( u[i] );
+ Trace( "qint-compose" ) << lindex << "..." << uindex;
+ }
+ Trace("qint-compose") << " )...";
+
+ //finished?
+ if( ( f && f->d_def.empty() ) || args.size()==n.getNumChildren() ){
+ if( f ){
+ Assert( f->d_def_order.size()==1 );
+ Trace("qint-compose") << "UVALUE(" << f->d_def_order[0] << ")" << std::endl;
+ addEntry( m, q, l, u, f->d_def_order[0] );
+ }else{
+ Node nn;
+ bool nnSet = false;
+ for( unsigned i=0; i<args.size(); i++ ){
+ if( args[i].isNull() ){
+ nnSet = true;
+ break;
+ }
+ }
+ if( !nnSet ){
+ if( n.getKind()==EQUAL ){
+ nn = NodeManager::currentNM()->mkConst( args[0]==args[1] );
+ }else{
+ //apply the operator to args
+ nn = NodeManager::currentNM()->mkNode( n.getKind(), args );
+ nn = Rewriter::rewrite( nn );
+ }
+ }
+ Trace("qint-compose") << "IVALUE(" << nn << ")" << std::endl;
+ addEntry( m, q, l, u, nn );
+ Trace("qint-compose-debug2") << "...added entry." << std::endl;
+ }
+ }else{
+ //if a non-simple child
+ if( children.find( depth )!=children.end() ){
+ //***************************
+ Trace("qint-compose") << "compound child, recurse" << std::endl;
+ std::vector< int > currIndex;
+ std::vector< int > endIndex;
+ std::vector< Node > prevL;
+ std::vector< Node > prevU;
+ std::vector< QIntDef * > visited;
+ do{
+ Assert( currIndex.size()==visited.size() );
+
+ //populate the vectors
+ while( visited.size()<m->getOrderedNumVars( q ) ){
+ unsigned i = visited.size();
+ QIntDef * qq = visited.empty() ? &children[depth] : visited[i-1]->getChild( currIndex[i-1] );
+ visited.push_back( qq );
+ Node qq_mx = qq->getMaximum();
+ Trace("qint-compose-debug2") << "...Get ev indices " << i << " " << l[i] << " " << u[i] << std::endl;
+ currIndex.push_back( qq->getEvIndex( m, l[i], true ) );
+ Trace("qint-compose-debug2") << "...Done get curr index " << currIndex[currIndex.size()-1] << std::endl;
+ if( m->isLessThan( qq_mx, u[i] ) ){
+ endIndex.push_back( qq->getNumChildren()-1 );
+ }else{
+ endIndex.push_back( qq->getEvIndex( m, u[i] ) );
+ }
+ Trace("qint-compose-debug2") << "...Done get end index " << endIndex[endIndex.size()-1] << std::endl;
+ prevL.push_back( l[i] );
+ prevU.push_back( u[i] );
+ if( !m->doMeet( prevL[i], prevU[i],
+ qq->getLower( currIndex[i] ), qq->getUpper( currIndex[i] ), l[i], u[i] ) ){
+ Assert( false );
+ }
+ }
+ for( unsigned i=0; i<depth; i++ ) { Trace("qint-compose") << " "; }
+ for( unsigned i=0; i<currIndex.size(); i++ ){
+ Trace("qint-compose") << "[" << currIndex[i] << "/" << endIndex[i] << "]";
+ }
+ Trace("qint-compose") << std::endl;
+ //consider the current
+ int activeIndex = visited.size()-1;
+ QIntDef * qa = visited.empty() ? &children[depth] : visited[activeIndex]->getChild( currIndex[activeIndex] );
+ if( f ){
+ int fIndex = f->getEvIndex( m, qa->getValue() );
+ construct_compose_r( m, q, l, u, n, f->getChild( fIndex ), args, children, bchildren, vindex, depth+1 );
+ }else{
+ args.push_back( qa->getValue() );
+ construct_compose_r( m, q, l, u, n, f, args, children, bchildren, vindex, depth+1 );
+ args.pop_back();
+ }
+
+ //increment the index (if possible)
+ while( activeIndex>=0 && currIndex[activeIndex]==endIndex[activeIndex] ){
+ currIndex.pop_back();
+ endIndex.pop_back();
+ l[activeIndex] = prevL[activeIndex];
+ u[activeIndex] = prevU[activeIndex];
+ prevL.pop_back();
+ prevU.pop_back();
+ visited.pop_back();
+ activeIndex--;
+ }
+ if( activeIndex>=0 ){
+ for( unsigned i=0; i<depth; i++ ) { Trace("qint-compose") << " "; }
+ Trace("qint-compose-debug") << "Increment at " << activeIndex << std::endl;
+ currIndex[activeIndex]++;
+ if( !m->doMeet( prevL[activeIndex], prevU[activeIndex],
+ visited[activeIndex]->getLower( currIndex[activeIndex] ),
+ visited[activeIndex]->getUpper( currIndex[activeIndex] ),
+ l[activeIndex], u[activeIndex] ) ){
+ Assert( false );
+ }
+ }
+ }while( !visited.empty() );
+ //***************************
+ }else{
+ Assert( bchildren.find( depth )!=bchildren.end() );
+ Node v = bchildren[depth];
+ if( f ){
+ if( v.getKind()==BOUND_VARIABLE ){
+ int vn = vindex.d_var_num[depth];
+ Trace("qint-compose") << "variable #" << vn << ", recurse" << std::endl;
+ //int vn = m->getOrderedVarOccurId( q, n, depth );
+ Trace("qint-compose-debug") << "-process " << v << ", which is var #" << vn << std::endl;
+ Node lprev = l[vn];
+ Node uprev = u[vn];
+ //restrict to last variable in order
+ int pnum = m->getVarOrder( q )->getPrevNum( vn );
+ if( pnum!=-1 ){
+ Trace("qint-compose-debug") << "-restrict to var #" << pnum << " " << l[pnum] << " " << u[pnum] << std::endl;
+ l[vn] = l[pnum];
+ u[vn] = u[pnum];
+ }
+ int startIndex = f->getEvIndex( m, l[vn], true );
+ int endIndex = f->getEvIndex( m, u[vn] );
+ Trace("qint-compose-debug") << "--will process " << startIndex << " " << endIndex << std::endl;
+ for( int i=startIndex; i<=endIndex; i++ ){
+ if( m->doMeet( lprev, uprev, f->getLower( i ), f->getUpper( i ), l[vn], u[vn] ) ){
+ construct_compose_r( m, q, l, u, n, f->getChild( i ), args, children, bchildren, vindex, depth+1 );
+ }else{
+ Assert( false );
+ }
+ }
+ l[vn] = lprev;
+ u[vn] = uprev;
+ }else{
+ Trace("qint-compose") << "value, recurse" << std::endl;
+ //simple
+ int ei = f->getEvIndex( m, v );
+ construct_compose_r( m, q, l, u, n, f->getChild( ei ), args, children, bchildren, vindex, depth+1 );
+ }
+ }else{
+ Trace("qint-compose") << "value, recurse" << std::endl;
+ args.push_back( v );
+ construct_compose_r( m, q, l, u, n, f, args, children, bchildren, vindex, depth+1 );
+ args.pop_back();
+ }
+ }
+ }
+}
+
+
+void QIntDef::construct_enum_r( FirstOrderModelQInt * m, Node q, unsigned vn, unsigned depth, Node v ) {
+ if( depth==m->getOrderedNumVars( q ) ){
+ Assert( !v.isNull() );
+ d_def_order.push_back( v );
+ }else{
+ TypeNode tn = m->getOrderedVarType( q, depth );
+ //int vnum = m->getVarOrder( q )->getVar( depth )==
+ if( depth==vn ){
+ for( unsigned i=0; i<m->d_rep_set.d_type_reps[tn].size(); i++ ){
+ Node vv = m->d_rep_set.d_type_reps[tn][i];
+ d_def_order.push_back( vv );
+ d_def[vv].construct_enum_r( m, q, vn, depth+1, vv );
+ }
+ }else if( m->getVarOrder( q )->getVar( depth )==m->getVarOrder( q )->getVar( vn ) && depth>vn ){
+ d_def_order.push_back( v );
+ d_def[v].construct_enum_r( m, q, vn, depth+1, v );
+ }else{
+ Node mx = m->getMaximum( tn );
+ d_def_order.push_back( mx );
+ d_def[mx].construct_enum_r( m, q, vn, depth+1, v );
+ }
+ }
+}
+
+bool QIntDef::construct_enum( FirstOrderModelQInt * m, Node q, unsigned vn ) {
+ TypeNode tn = m->getOrderedVarType( q, vn );
+ if( tn.isSort() ){
+ construct_enum_r( m, q, vn, 0, Node::null() );
+ return true;
+ }else{
+ return false;
+ }
+}
+
+bool QIntDef::construct_compose( FirstOrderModelQInt * m, Node q, Node n, QIntDef * f,
+ std::map< unsigned, QIntDef >& children,
+ std::map< unsigned, Node >& bchildren, int varChCount,
+ QIntVarNumIndex& vindex ) {
+ Trace("qint-compose") << "Do " << (f ? "uninterpreted" : "interpreted");
+ Trace("qint-compose") << " compose, var count = " << varChCount << "..." << std::endl;
+ std::vector< Node > l;
+ std::vector< Node > u;
+ init_vec( m, q, l, u );
+ if( varChCount==0 || f ){
+ //standard (no variable child) interpreted compose, or uninterpreted compose
+ std::vector< Node > args;
+ construct_compose_r( m, q, l, u, n, f, args, children, bchildren, vindex, 0 );
+ }else{
+ //special cases
+ bool success = false;
+ int varIndex = ( bchildren.find( 0 )!=bchildren.end() && bchildren[0].getKind()==BOUND_VARIABLE ) ? 0 : 1;
+ if( varChCount>1 ){
+ if( n.getKind()==EQUAL ){
+ //make it an enumeration
+ unsigned vn = vindex.d_var_num[0];
+ if( children[0].construct_enum( m, q, vn ) ){
+ bchildren.erase( 0 );
+ varIndex = 1;
+ success = true;
+ }
+ }
+ }else{
+ success = n.getKind()==EQUAL;
+ }
+ if( success ){
+ int oIndex = varIndex==0 ? 1 : 0;
+ Node v = bchildren[varIndex];
+ unsigned vn = vindex.d_var_num[varIndex];
+ if( children.find( oIndex )==children.end() ){
+ Assert( bchildren.find( oIndex )!=bchildren.end() );
+ Node at = bchildren[oIndex];
+ Trace("qint-icompose") << "Basic child, " << at << " with var " << v << std::endl;
+ Node prev = m->getPrev( bchildren[oIndex].getType(), bchildren[oIndex] );
+ Node above = u[vn];
+ if( !prev.isNull() ){
+ u[vn] = prev;
+ addEntry( m, q, l, u, NodeManager::currentNM()->mkConst( false ) );
+ }
+ l[vn] = prev;
+ u[vn] = at;
+ addEntry( m, q, l, u, NodeManager::currentNM()->mkConst( true ) );
+ if( at!=above ){
+ l[vn] = at;
+ u[vn] = above;
+ addEntry( m, q, l, u, NodeManager::currentNM()->mkConst( false ) );
+ }
+ }else{
+ QIntDef * qid = &children[oIndex];
+ qid->debugPrint("qint-icompose", m, q );
+ Trace("qint-icompose") << " against variable..." << v << ", which is var #" << vn << std::endl;
+
+ TypeNode tn = v.getType();
+ QIntDefIter qdi( m, q, qid );
+ while( !qdi.isFinished() ){
+ std::vector< Node > us;
+ qdi.getUppers( us );
+ std::vector< Node > ls;
+ qdi.getLowers( ls );
+ qdi.debugPrint( "qint-icompose" );
+
+ Node n_below = ls[vn];
+ Node n_prev = m->getPrev( tn, qdi.getValue() );
+ Node n_at = qdi.getValue();
+ Node n_above = us[vn];
+ Trace("qint-icompose") << n_below << " < " << n_prev << " < " << n_at << " < " << n_above << std::endl;
+ if( n.getKind()==EQUAL ){
+ bool atLtAbove = m->isLessThan( n_at, n_above );
+ Node currL = n_below;
+ if( n_at==n_above || atLtAbove ){
+ //add for value (at-1)
+ if( !n_prev.isNull() && ( n_below.isNull() || m->isLessThan( n_below, n_prev ) ) ){
+ ls[vn] = currL;
+ us[vn] = n_prev;
+ currL = n_prev;
+ Trace("qint-icompose") << "-add entry(-) at " << ls[vn] << "..." << us[vn] << std::endl;
+ addEntry( m, q, ls, us, NodeManager::currentNM()->mkConst( false ) );
+ }
+ //add for value (at)
+ if( ( n_below.isNull() || m->isLessThan( n_below, n_at ) ) && atLtAbove ){
+ ls[vn] = currL;
+ us[vn] = n_at;
+ currL = n_at;
+ Trace("qint-icompose") << "-add entry(=) at " << ls[vn] << "..." << us[vn] << std::endl;
+ addEntry( m, q, ls, us, NodeManager::currentNM()->mkConst( true ) );
+ }
+ }
+ ls[vn] = currL;
+ us[vn] = n_above;
+ Trace("qint-icompose") << "-add entry(+) at " << ls[vn] << "..." << us[vn] << std::endl;
+ addEntry( m, q, ls, us, NodeManager::currentNM()->mkConst( n_at==n_above ) );
+ }else{
+ return false;
+ }
+ qdi.increment();
+
+ Trace("qint-icompose-debug") << "Now : " << std::endl;
+ debugPrint("qint-icompose-debug", m, q );
+ Trace("qint-icompose-debug") << std::endl;
+ }
+ }
+
+ Trace("qint-icompose") << "Result : " << std::endl;
+ debugPrint("qint-icompose", m, q );
+ Trace("qint-icompose") << std::endl;
+
+ }else{
+ return false;
+ }
+ }
+ Trace("qint-compose") << "Done i-compose" << std::endl;
+ return true;
+}
+
+
+void QIntDef::construct( FirstOrderModelQInt * m, std::vector< Node >& fapps, unsigned depth ) {
+ d_def.clear();
+ d_def_order.clear();
+ Assert( !fapps.empty() );
+ if( depth==fapps[0].getNumChildren() ){
+ //get representative in model for this term
+ Assert( fapps.size()>=1 );
+ Node r = m->getUsedRepresentative( fapps[0] );
+ d_def_order.push_back( r );
+ }else{
+ std::map< Node, std::vector< Node > > fapp_child;
+ //partition based on evaluations of fapps[1][depth]....fapps[n][depth]
+ for( unsigned i=0; i<fapps.size(); i++ ){
+ Node r = m->getUsedRepresentative( fapps[i][depth] );
+ fapp_child[r].push_back( fapps[i] );
+ }
+ //sort by QIntSort
+ for( std::map< Node, std::vector< Node > >::iterator it = fapp_child.begin(); it != fapp_child.end(); ++it ){
+ d_def_order.push_back( it->first );
+ }
+ QIntSort qis;
+ qis.m = m;
+ std::sort( d_def_order.begin(), d_def_order.end(), qis );
+ //construct children
+ for( unsigned i=0; i<d_def_order.size(); i++ ){
+ Node n = d_def_order[i];
+ if( i==d_def_order.size()-1 ){
+ d_def_order[i] = m->getMaximum( d_def_order[i].getType() );
+ }
+ Debug("qint-model-debug2") << "Construct for " << n << ", terms = " << fapp_child[n].size() << std::endl;
+ d_def[d_def_order[i]].construct( m, fapp_child[n], depth+1 );
+ }
+ }
+}
+
+Node QIntDef::getFunctionValue( FirstOrderModelQInt * m, std::vector< Node >& vars, unsigned depth ) {
+ if( d_def.empty() ){
+ Assert( d_def_order.size()==1 );
+ //must convert to actual domain constant
+ if( d_def_order[0].getType().isSort() ){
+ return m->d_rep_set.d_type_reps[ d_def_order[0].getType() ][ m->getRepId( d_def_order[0] ) ];
+ }else{
+ return m->getUsedRepresentative( d_def_order[0] );
+ }
+ }else{
+ TypeNode tn = vars[depth].getType();
+ Node curr;
+ int rep_id = m->d_rep_set.getNumRepresentatives( tn );
+ for( int i=(int)(d_def_order.size()-1); i>=0; i-- ){
+ int curr_rep_id = i==0 ? 0 : m->getRepId( d_def_order[i-1] )+1;
+ Node ccurr = d_def[d_def_order[i]].getFunctionValue( m, vars, depth+1 );
+ if( curr.isNull() ){
+ curr = ccurr;
+ }else{
+ std::vector< Node > c;
+ Assert( curr_rep_id<rep_id );
+ for( int j=curr_rep_id; j<rep_id; j++ ){
+ c.push_back( vars[depth].eqNode( m->d_rep_set.d_type_reps[tn][j] ) );
+ }
+ Node cond = c.size()==1 ? c[0] : NodeManager::currentNM()->mkNode( OR, c );
+ curr = NodeManager::currentNM()->mkNode( ITE, cond, ccurr, curr );
+ }
+ rep_id = curr_rep_id;
+ }
+ return curr;
+ }
+}
+
+Node QIntDef::evaluate_r( FirstOrderModelQInt * m, std::vector< Node >& reps, unsigned depth ) {
+ if( depth==reps.size() ){
+ Assert( d_def_order.size()==1 );
+ return d_def_order[0];
+ }else{
+ if( d_def.find( reps[depth] )!=d_def.end() ){
+ return d_def[reps[depth]].evaluate_r( m, reps, depth+1 );
+ }else{
+ int ei = getEvIndex( m, reps[depth] );
+ return d_def[d_def_order[ei]].evaluate_r( m, reps, depth+1 );
+ }
+ }
+}
+Node QIntDef::evaluate_n_r( FirstOrderModelQInt * m, Node n, unsigned depth ) {
+ if( depth==n.getNumChildren() ){
+ Assert( d_def_order.size()==1 );
+ return d_def_order[0];
+ }else{
+ Node r = m->getUsedRepresentative( n[depth] );
+ if( d_def.find( r )!=d_def.end() ){
+ return d_def[r].evaluate_n_r( m, n, depth+1 );
+ }else{
+ int ei = getEvIndex( m, r );
+ return d_def[d_def_order[ei]].evaluate_n_r( m, n, depth+1 );
+ }
+ }
+}
+
+
+
+QIntDef * QIntDef::getChild( unsigned i ) {
+ Assert( i<d_def_order.size() );
+ Assert( d_def.find( d_def_order[i] )!=d_def.end() );
+ return &d_def[ d_def_order[i] ];
+}
+
+void QIntDef::debugPrint( const char * c, FirstOrderModelQInt * m, Node q, int t ) {
+ /*
+ for( unsigned i=0; i<d_def_order.size(); i++ ){
+ for( int j=0; j<t; j++ ) { Trace(c) << " "; }
+ //Trace(c) << this << " ";
+ Trace(c) << d_def_order[i] << " : " << std::endl;
+ if( d_def.find( d_def_order[i] )!=d_def.end() ){
+ d_def[d_def_order[i]].debugPrint( c, m, t+1 );
+ }
+ }
+ */
+ //if( t==0 ){
+ QIntDefIter qdi( m, q, this );
+ while( !qdi.isFinished() ){
+ qdi.debugPrint( c, t );
+ qdi.increment();
+ }
+ //}
+}
+
+
+QIntDefIter::QIntDefIter( FirstOrderModelQInt * m, Node q, QIntDef * qid ) : d_fm( m ), d_q( q ){
+ resetIndex( qid );
+}
+
+void QIntDefIter::debugPrint( const char * c, int t ) {
+ //Trace( c ) << getSize() << " " << d_index_visited.size() << " ";
+ for( int j=0; j<t; j++ ) { Trace(c) << " "; }
+ std::vector< Node > l;
+ std::vector< Node > u;
+ getLowers( l );
+ getUppers( u );
+ QIntDef::debugPrint( c, d_fm, d_q, l, u );
+ Trace( c ) << " -> " << getValue() << std::endl;
+}
+
+void QIntDefIter::resetIndex( QIntDef * qid ){
+ //std::cout << "check : " << qid << " " << qid->d_def_order.size() << " " << qid->d_def.size() << std::endl;
+ if( !qid->d_def.empty() ){
+ //std::cout << "add to visited " << qid << std::endl;
+ d_index.push_back( 0 );
+ d_index_visited.push_back( qid );
+ resetIndex( qid->getChild( 0 ) );
+ }
+}
+
+bool QIntDefIter::increment( int index ) {
+ if( !isFinished() ){
+ index = index==-1 ? (int)(d_index.size()-1) : index;
+ while( (int)(d_index.size()-1)>index ){
+ //std::cout << "remove from visit 1 " << std::endl;
+ d_index.pop_back();
+ d_index_visited.pop_back();
+ }
+ while( index>=0 && d_index[index]>=(int)(d_index_visited[index]->d_def_order.size()-1) ){
+ //std::cout << "remove from visit " << d_index_visited[ d_index_visited.size()-1 ] << std::endl;
+ d_index.pop_back();
+ d_index_visited.pop_back();
+ index--;
+ }
+ if( index>=0 ){
+ //std::cout << "increment at index = " << index << std::endl;
+ d_index[index]++;
+ resetIndex( d_index_visited[index]->getChild( d_index[index] ) );
+ return true;
+ }else{
+ d_index.clear();
+ return false;
+ }
+ }else{
+ return false;
+ }
+}
+
+Node QIntDefIter::getLower( int index ) {
+ if( d_index[index]==0 && !d_q.isNull() ){
+ int pnum = d_fm->getVarOrder( d_q )->getPrevNum( index );
+ if( pnum!=-1 ){
+ return getLower( pnum );
+ }
+ }
+ return d_index_visited[index]->getLower( d_index[index] );
+}
+
+Node QIntDefIter::getUpper( int index ) {
+ return d_index_visited[index]->getUpper( d_index[index] );
+}
+
+void QIntDefIter::getLowers( std::vector< Node >& reps ) {
+ for( unsigned i=0; i<getSize(); i++ ){
+ bool added = false;
+ if( d_index[i]==0 && !d_q.isNull() ){
+ int pnum = d_fm->getVarOrder( d_q )->getPrevNum( i );
+ if( pnum!=-1 ){
+ added = true;
+ reps.push_back( reps[pnum] );
+ }
+ }
+ if( !added ){
+ reps.push_back( getLower( i ) );
+ }
+ }
+}
+
+void QIntDefIter::getUppers( std::vector< Node >& reps ) {
+ for( unsigned i=0; i<getSize(); i++ ){
+ reps.push_back( getUpper( i ) );
+ }
+}
+
+Node QIntDefIter::getValue() {
+ return d_index_visited[ d_index_visited.size()-1 ]->getChild( d_index[d_index.size()-1] )->getValue();
+}
+
+
+//------------------------variable ordering----------------------------
+
+QuantVarOrder::QuantVarOrder( Node q ) : d_q( q ) {
+ d_var_count = 0;
+ initialize( q[1], 0, d_var_occur );
+}
+
+int QuantVarOrder::initialize( Node n, int minVarIndex, QIntVarNumIndex& vindex ) {
+ if( n.getKind()!=FORALL ){
+ //std::vector< Node > vars;
+ //std::vector< int > args;
+ int procVarOn = n.getKind()==APPLY_UF ? 0 : 1;
+ for( int r=0; r<=procVarOn; r++ ){
+ for( unsigned i=0; i<n.getNumChildren(); i++ ){
+ if( n[i].getKind()==BOUND_VARIABLE && r==procVarOn ){
+ int occ_index = -1;
+ for( unsigned j=0; j<d_var_to_num[n[i]].size(); j++ ){
+ if( d_var_to_num[n[i]][j]>=minVarIndex ){
+ occ_index = d_var_to_num[n[i]][j];
+ }
+ }
+ if( occ_index==-1 ){
+ //need to assign new
+ d_num_to_var[d_var_count] = n[i];
+ if( !d_var_to_num[n[i]].empty() ){
+ int v = d_var_to_num[n[i]][ d_var_to_num[n[i]].size()-1 ];
+ d_num_to_prev_num[ d_var_count ] = v;
+ d_num_to_next_num[ v ] = d_var_count;
+ }
+ d_var_num_index[ d_var_count ] = d_var_to_num[n[i]].size();
+ d_var_to_num[n[i]].push_back( d_var_count );
+ occ_index = d_var_count;
+ d_var_count++;
+ }
+ vindex.d_var_num[i] = occ_index;
+ minVarIndex = occ_index;
+ }else if( r==0 ){
+ minVarIndex = initialize( n[i], minVarIndex, vindex.d_var_index[i] );
+ }
+ }
+ }
+ }
+ return minVarIndex;
+}
+
+bool QuantVarOrder::getInstantiation( FirstOrderModelQInt * m, std::vector< Node >& l, std::vector< Node >& u,
+ std::vector< Node >& inst ) {
+ Debug("qint-var-order-debug2") << "Get for " << d_q << " " << l.size() << " " << u.size() << std::endl;
+ for( unsigned i=0; i<d_q[0].getNumChildren(); i++ ){
+ Debug("qint-var-order-debug2") << "Get for " << d_q[0][i] << " " << d_var_to_num[d_q[0][i]].size() << std::endl;
+ Node ll = Node::null();
+ Node uu = m->getMaximum( d_q[0][i].getType() );
+ for( unsigned j=0; j<d_var_to_num[d_q[0][i]].size(); j++ ){
+ Debug("qint-var-order-debug2") << "Go " << j << std::endl;
+ Node cl = ll;
+ Node cu = uu;
+ int index = d_var_to_num[d_q[0][i]][j];
+ Debug("qint-var-order-debug2") << "Do meet for " << index << "..." << std::endl;
+ Debug("qint-var-order-debug2") << l[index] << " " << u[index] << " " << cl << " " << cu << std::endl;
+ if( !m->doMeet( l[index], u[index], cl, cu, ll, uu ) ){
+ Debug("qint-var-order-debug2") << "FAILED" << std::endl;
+ return false;
+ }
+ Debug("qint-var-order-debug2") << "Result : " << ll << " " << uu << std::endl;
+ }
+ Debug("qint-var-order-debug2") << "Got " << uu << std::endl;
+ inst.push_back( uu );
+ }
+ return true;
+}
+
+void QuantVarOrder::debugPrint( const char * c ) {
+ Trace( c ) << "Variable order for " << d_q << " is : " << std::endl;
+ debugPrint( c, d_q[1], d_var_occur );
+ Trace( c ) << std::endl;
+ for( unsigned i=0; i<d_q[0].getNumChildren(); i++ ){
+ Trace( c ) << d_q[0][i] << " : ";
+ for( unsigned j=0; j<d_var_to_num[d_q[0][i]].size(); j++ ){
+ Trace( c ) << d_var_to_num[d_q[0][i]][j] << " ";
+ }
+ Trace( c ) << std::endl;
+ }
+}
+
+void QuantVarOrder::debugPrint( const char * c, Node n, QIntVarNumIndex& vindex ) {
+ if( n.getKind()==FORALL ){
+ Trace(c) << "NESTED_QUANT";
+ }else{
+ Trace(c) << n.getKind() << "(";
+ for( unsigned i=0; i<n.getNumChildren(); i++ ){
+ if( i>0 ) Trace( c ) << ",";
+ Trace( c ) << " ";
+ if( n[i].getKind()==BOUND_VARIABLE ){
+ Trace(c) << "VAR[" << vindex.d_var_num[i] << "]";
+ }else{
+ debugPrint( c, n[i], vindex.d_var_index[i] );
+ }
+ if( i==n.getNumChildren()-1 ) Trace( c ) << " ";
+ }
+ Trace(c) << ")";
+ }
+}
+
+QIntervalBuilder::QIntervalBuilder( context::Context* c, QuantifiersEngine* qe ) :
+QModelBuilder( c, qe ){
+ d_true = NodeManager::currentNM()->mkConst( true );
+}
+
+
+//------------------------model construction----------------------------
+
+void QIntervalBuilder::processBuildModel(TheoryModel* m, bool fullModel) {
+ Trace("fmf-qint-debug") << "process build model " << fullModel << std::endl;
+ FirstOrderModel* f = (FirstOrderModel*)m;
+ FirstOrderModelQInt* fm = f->asFirstOrderModelQInt();
+ if( fullModel ){
+ Trace("qint-model") << "Construct model representation..." << std::endl;
+ //make function values
+ for( std::map<Node, QIntDef * >::iterator it = fm->d_models.begin(); it != fm->d_models.end(); ++it ) {
+ if( it->first.getType().getNumChildren()>1 ){
+ Trace("qint-model") << "Construct for " << it->first << "..." << std::endl;
+ m->d_uf_models[ it->first ] = fm->getFunctionValue( it->first, "$x" );
+ }
+ }
+ TheoryEngineModelBuilder::processBuildModel( m, fullModel );
+ //mark that the model has been set
+ fm->markModelSet();
+ //debug the model
+ debugModel( fm );
+ }else{
+ fm->initialize( d_considerAxioms );
+ //process representatives
+ fm->d_rep_id.clear();
+ fm->d_max.clear();
+ fm->d_min.clear();
+ Trace("qint-model") << std::endl << "Making representatives..." << std::endl;
+ for( std::map< TypeNode, std::vector< Node > >::iterator it = fm->d_rep_set.d_type_reps.begin();
+ it != fm->d_rep_set.d_type_reps.end(); ++it ){
+ if( it->first.isSort() ){
+ if( it->second.empty() ){
+ std::cout << "Empty rep for " << it->first << std::endl;
+ exit(0);
+ }
+ Trace("qint-model") << "Representatives for " << it->first << " : " << std::endl;
+ for( unsigned i=0; i<it->second.size(); i++ ){
+ Trace("qint-model") << i << " : " << it->second[i] << std::endl;
+ fm->d_rep_id[it->second[i]] = i;
+ }
+ fm->d_min[it->first] = it->second[0];
+ fm->d_max[it->first] = it->second[it->second.size()-1];
+ }else{
+ //TODO: enumerate?
+ }
+ }
+ Trace("qint-model") << std::endl << "Making function definitions..." << std::endl;
+ //construct the models for functions
+ for( std::map<Node, QIntDef * >::iterator it = fm->d_models.begin(); it != fm->d_models.end(); ++it ) {
+ Node f = it->first;
+ Trace("qint-model-debug") << "Building Model for " << f << std::endl;
+ //reset the model
+ //get all (non-redundant) f-applications
+ std::vector< Node > fapps;
+ Trace("qint-model-debug") << "Initial terms: " << std::endl;
+ for( size_t i=0; i<fm->d_uf_terms[f].size(); i++ ){
+ Node n = fm->d_uf_terms[f][i];
+ if( !n.getAttribute(NoMatchAttribute()) ){
+ Trace("qint-model-debug") << " " << n << std::endl;
+ fapps.push_back( n );
+ }
+ }
+ if( fapps.empty() ){
+ //choose arbitrary value
+ Node mbt = d_qe->getTermDatabase()->getModelBasisOpTerm(f);
+ Trace("qint-model-debug") << "Initial terms empty, add " << mbt << std::endl;
+ fapps.push_back( mbt );
+ }
+ //construct the interval model
+ it->second->construct( fm, fapps );
+ Trace("qint-model-debug") << "Definition for " << f << " : " << std::endl;
+ it->second->debugPrint("qint-model-debug", fm, Node::null() );
+
+ it->second->simplify( fm, Node::null() );
+ Trace("qint-model") << "(Simplified) definition for " << f << " : " << std::endl;
+ it->second->debugPrint("qint-model", fm, Node::null() );
+
+ if( Debug.isOn("qint-model-debug") ){
+ for( size_t i=0; i<fm->d_uf_terms[f].size(); i++ ){
+ Node e = it->second->evaluate_n( fm, fm->d_uf_terms[f][i] );
+ Debug("qint-model-debug") << fm->d_uf_terms[f][i] << " evaluates to " << e << std::endl;
+ Assert( fm->areEqual( e, fm->d_uf_terms[f][i] ) );
+ }
+ }
+ }
+ }
+}
+
+
+//--------------------model checking---------------------------------------
+
+//do exhaustive instantiation
+bool QIntervalBuilder::doExhaustiveInstantiation( FirstOrderModel * fm, Node q, int effort ) {
+ Trace("qint-check") << "exhaustive instantiation " << q << " " << effort << std::endl;
+ if (effort==0) {
+
+ FirstOrderModelQInt * fmqint = fm->asFirstOrderModelQInt();
+ QIntDef qid;
+ doCheck( fmqint, q, qid, q[1], fmqint->d_var_order[q]->d_var_occur );
+ //now process entries
+ Trace("qint-inst") << "Interpretation for " << q << " is : " << std::endl;
+ qid.debugPrint( "qint-inst", fmqint, q );
+ Trace("qint-inst") << std::endl;
+ Debug("qint-check-debug2") << "Make iterator..." << std::endl;
+ QIntDefIter qdi( fmqint, q, &qid );
+ while( !qdi.isFinished() ){
+ if( qdi.getValue()!=d_true ){
+ Debug("qint-check-debug2") << "Set up vectors..." << std::endl;
+ std::vector< Node > l;
+ std::vector< Node > u;
+ std::vector< Node > inst;
+ qdi.getLowers( l );
+ qdi.getUppers( u );
+ Debug("qint-check-debug2") << "Get instantiation..." << std::endl;
+ if( fmqint->d_var_order[q]->getInstantiation( fmqint, l, u, inst ) ){
+ Trace("qint-inst") << "** Instantiate with ";
+ //just add the instance
+ InstMatch m;
+ for( unsigned j=0; j<inst.size(); j++) {
+ m.set( d_qe, q, j, inst[j] );
+ Trace("qint-inst") << inst[j] << " ";
+ }
+ Trace("qint-inst") << std::endl;
+ d_triedLemmas++;
+ if( d_qe->addInstantiation( q, m ) ){
+ Trace("qint-inst") << " ...added instantiation." << std::endl;
+ d_addedLemmas++;
+ }else{
+ Trace("qint-inst") << " ...duplicate instantiation" << std::endl;
+ //verify that instantiation is witness for current entry
+ if( Debug.isOn("qint-check-debug2") ){
+ Debug("qint-check-debug2") << "Check if : ";
+ std::vector< Node > exp_inst;
+ for( unsigned i=0; i<fmqint->getOrderedNumVars( q ); i++ ){
+ int index = fmqint->getOrderedVarNumToVarNum( q, i );
+ exp_inst.push_back( inst[ index ] );
+ Debug("qint-check-debug2") << inst[index] << " ";
+ }
+ Debug("qint-check-debug2") << " evaluates to " << qdi.getValue() << std::endl;
+ Assert( qid.evaluate( fmqint, exp_inst )==qdi.getValue() );
+ }
+ }
+ }else{
+ Trace("qint-inst") << "** Spurious instantiation." << std::endl;
+ }
+ }
+ qdi.increment();
+ }
+ }
+ return true;
+}
+
+bool QIntervalBuilder::doCheck( FirstOrderModelQInt * m, Node q, QIntDef & qid, Node n,
+ QIntVarNumIndex& vindex ) {
+ Assert( n.getKind()!=FORALL );
+ std::map< unsigned, QIntDef > children;
+ std::map< unsigned, Node > bchildren;
+ int varChCount = 0;
+ for( unsigned i=0; i<n.getNumChildren(); i++ ){
+ if( n[i].getKind()==FORALL ){
+ bchildren[i] = Node::null();
+ }else if( n[i].getKind() == BOUND_VARIABLE ){
+ varChCount++;
+ bchildren[i] = n[i];
+ }else if( m->hasTerm( n[i] ) ){
+ bchildren[i] = m->getUsedRepresentative( n[i] );
+ }else{
+ if( !doCheck( m, q, children[i], n[i], vindex.d_var_index[i] ) ){
+ bchildren[i] = Node::null();
+ }
+ }
+ }
+ Trace("qint-check-debug") << "Compute Interpretation of " << n << " " << n.getKind() << std::endl;
+ if( n.getKind() == APPLY_UF || n.getKind() == VARIABLE || n.getKind() == SKOLEM ){
+ Node op = n.getKind() == APPLY_UF ? n.getOperator() : n;
+ //uninterpreted compose
+ qid.construct_compose( m, q, n, m->d_models[op], children, bchildren, varChCount, vindex );
+ }else if( !qid.construct_compose( m, q, n, NULL, children, bchildren, varChCount, vindex ) ){
+ Trace("qint-check-debug") << "** Cannot produce definition for " << n << std::endl;
+ return false;
+ }
+ Trace("qint-check-debug2") << "Definition for " << n << " is : " << std::endl;
+ qid.debugPrint("qint-check-debug2", m, q);
+ qid.simplify( m, q );
+ Trace("qint-check-debug") << "(Simplified) Definition for " << n << " is : " << std::endl;
+ qid.debugPrint("qint-check-debug", m, q);
+ Trace("qint-check-debug") << std::endl;
+ Assert( qid.isTotal( m, q ) );
+ return true;
+}
diff --git a/src/theory/quantifiers/qinterval_builder.h b/src/theory/quantifiers/qinterval_builder.h
new file mode 100755
index 000000000..8f48776cc
--- /dev/null
+++ b/src/theory/quantifiers/qinterval_builder.h
@@ -0,0 +1,155 @@
+/********************* */
+/*! \file qinterval_builder.h
+ ** \verbatim
+ ** Original author: Andrew Reynolds
+ ** Major contributors: none
+ ** Minor contributors (to current version): none
+ ** This file is part of the CVC4 project.
+ ** Copyright (c) 2009-2013 New York University and The University of Iowa
+ ** See the file COPYING in the top-level source directory for licensing
+ ** information.\endverbatim
+ **
+ ** \brief qinterval model class
+ **/
+
+#include "cvc4_private.h"
+
+#ifndef QINTERVAL_BUILDER
+#define QINTERVAL_BUILDER
+
+#include "theory/quantifiers/model_builder.h"
+#include "theory/quantifiers/first_order_model.h"
+
+namespace CVC4 {
+namespace theory {
+namespace quantifiers {
+
+class FirstOrderModelQInt;
+
+class QIntVarNumIndex
+{
+public:
+ std::map< int, int > d_var_num;
+ std::map< int, QIntVarNumIndex > d_var_index;
+};
+
+class QIntDef
+{
+private:
+ Node evaluate_r( FirstOrderModelQInt * m, std::vector< Node >& reps, unsigned depth );
+ Node evaluate_n_r( FirstOrderModelQInt * m, Node n, unsigned depth );
+ void construct_compose_r( FirstOrderModelQInt * m, Node q,
+ std::vector< Node >& l, std::vector< Node >& u, Node n, QIntDef * f,
+ std::vector< Node >& args,
+ std::map< unsigned, QIntDef >& children,
+ std::map< unsigned, Node >& bchildren,
+ QIntVarNumIndex& vindex,
+ unsigned depth );
+
+ void construct_enum_r( FirstOrderModelQInt * m, Node q, unsigned vn, unsigned depth, Node v );
+ int getEvIndex( FirstOrderModelQInt * m, Node n, bool exc = false );
+ void addEntry( FirstOrderModelQInt * m, Node q, std::vector< Node >& l, std::vector< Node >& u,
+ Node v, unsigned depth = 0 );
+ Node simplify_r( FirstOrderModelQInt * m, Node q, std::vector< Node >& il, std::vector< Node >& iu,
+ unsigned depth );
+ bool isTotal_r( FirstOrderModelQInt * m, Node q, std::vector< Node >& il, std::vector< Node >& iu,
+ unsigned depth );
+public:
+ QIntDef(){}
+ std::map< Node, QIntDef > d_def;
+ std::vector< Node > d_def_order;
+
+ void construct( FirstOrderModelQInt * m, std::vector< Node >& fapps, unsigned depth = 0 );
+ bool construct_compose( FirstOrderModelQInt * m, Node q, Node n, QIntDef * f,
+ std::map< unsigned, QIntDef >& children,
+ std::map< unsigned, Node >& bchildren, int varChCount,
+ QIntVarNumIndex& vindex );
+ bool construct_enum( FirstOrderModelQInt * m, Node q, unsigned vn );
+
+ Node evaluate( FirstOrderModelQInt * m, std::vector< Node >& reps ) { return evaluate_r( m, reps, 0 ); }
+ Node evaluate_n( FirstOrderModelQInt * m, Node n ) { return evaluate_n_r( m, n, 0 ); }
+
+ void debugPrint( const char * c, FirstOrderModelQInt * m, Node q, int t = 0 );
+ QIntDef * getChild( unsigned i );
+ Node getValue() { return d_def_order[0]; }
+ Node getLower( unsigned i ) { return i==0 ? Node::null() : d_def_order[i-1]; }
+ Node getUpper( unsigned i ) { return d_def_order[i]; }
+ Node getMaximum() { return d_def_order.empty() ? Node::null() : getUpper( d_def_order.size()-1 ); }
+ int getNumChildren() { return d_def_order.size(); }
+ bool isTotal( FirstOrderModelQInt * m, Node q );
+
+ Node simplify( FirstOrderModelQInt * m, Node q );
+ Node getFunctionValue( FirstOrderModelQInt * m, std::vector< Node >& vars, unsigned depth = 0 );
+
+ static void init_vec( FirstOrderModelQInt * m, Node q, std::vector< Node >& l, std::vector< Node >& u );
+ static void debugPrint( const char * c, FirstOrderModelQInt * m, Node q, std::vector< Node >& l, std::vector< Node >& u );
+};
+
+class QIntDefIter {
+private:
+ FirstOrderModelQInt * d_fm;
+ Node d_q;
+ void resetIndex( QIntDef * qid );
+public:
+ QIntDefIter( FirstOrderModelQInt * m, Node q, QIntDef * qid );
+ void debugPrint( const char * c, int t = 0 );
+ std::vector< QIntDef * > d_index_visited;
+ std::vector< int > d_index;
+ bool isFinished() { return d_index.empty(); }
+ bool increment( int index = -1 );
+ unsigned getSize() { return d_index.size(); }
+ Node getLower( int index );
+ Node getUpper( int index );
+ void getLowers( std::vector< Node >& reps );
+ void getUppers( std::vector< Node >& reps );
+ Node getValue();
+};
+
+
+class QuantVarOrder
+{
+private:
+ int initialize( Node n, int minVarIndex, QIntVarNumIndex& vindex );
+ int d_var_count;
+ Node d_q;
+ void debugPrint( const char * c, Node n, QIntVarNumIndex& vindex );
+public:
+ QuantVarOrder( Node q );
+ std::map< int, Node > d_num_to_var;
+ std::map< int, int > d_num_to_prev_num;
+ std::map< int, int > d_num_to_next_num;
+ std::map< Node, std::vector< int > > d_var_to_num;
+ std::map< int, int > d_var_num_index;
+ //std::map< Node, std::map< int, int > > d_var_occur;
+ //int getVarNum( Node n, int arg ) { return d_var_occur[n][arg]; }
+ unsigned getNumVars() { return d_var_count; }
+ Node getVar( int i ) { return d_num_to_var[i]; }
+ int getPrevNum( int i ) { return d_num_to_prev_num.find( i )!=d_num_to_prev_num.end() ? d_num_to_prev_num[i] : -1; }
+ int getNextNum( int i ) { return d_num_to_next_num.find( i )!=d_num_to_next_num.end() ? d_num_to_next_num[i] : -1; }
+ int getVarNumIndex( int i ) { return d_var_num_index[i]; }
+ bool getInstantiation( FirstOrderModelQInt * m, std::vector< Node >& l, std::vector< Node >& u,
+ std::vector< Node >& inst );
+ void debugPrint( const char * c );
+ QIntVarNumIndex d_var_occur;
+};
+
+class QIntervalBuilder : public QModelBuilder
+{
+private:
+ Node d_true;
+ bool doCheck( FirstOrderModelQInt * m, Node q, QIntDef & qid, Node n,
+ QIntVarNumIndex& vindex );
+public:
+ QIntervalBuilder( context::Context* c, QuantifiersEngine* qe );
+ //process build model
+ void processBuildModel(TheoryModel* m, bool fullModel);
+ //do exhaustive instantiation
+ bool doExhaustiveInstantiation( FirstOrderModel * fm, Node q, int effort );
+};
+
+
+}
+}
+}
+
+#endif \ No newline at end of file
diff --git a/src/theory/quantifiers/term_database.cpp b/src/theory/quantifiers/term_database.cpp
index e18a4e0dc..6b1368be1 100644
--- a/src/theory/quantifiers/term_database.cpp
+++ b/src/theory/quantifiers/term_database.cpp
@@ -146,6 +146,7 @@ void TermDb::addTerm( Node n, std::set< Node >& added, bool withinQuant ){
if( !d_func_map_trie[ it->first ].addTerm( d_quantEngine, n ) ){
NoMatchAttribute nma;
n.setAttribute(nma,true);
+ Debug("term-db-cong") << n << " is redundant." << std::endl;
congruentCount++;
}else{
nonCongruentCount++;
@@ -173,6 +174,7 @@ void TermDb::addTerm( Node n, std::set< Node >& added, bool withinQuant ){
if( !d_pred_map_trie[i][op].addTerm( d_quantEngine, en ) ){
NoMatchAttribute nma;
en.setAttribute(nma,true);
+ Debug("term-db-cong") << en << " is redundant." << std::endl;
congruentCount++;
}else{
nonCongruentCount++;
@@ -222,10 +224,14 @@ Node TermDb::getModelBasisOpTerm( Node op ){
TypeNode t = op.getType();
std::vector< Node > children;
children.push_back( op );
- for( size_t i=0; i<t.getNumChildren()-1; i++ ){
+ for( int i=0; i<(int)(t.getNumChildren()-1); i++ ){
children.push_back( getModelBasisTerm( t[i] ) );
}
- d_model_basis_op_term[op] = NodeManager::currentNM()->mkNode( APPLY_UF, children );
+ if( children.size()==1 ){
+ d_model_basis_op_term[op] = op;
+ }else{
+ d_model_basis_op_term[op] = NodeManager::currentNM()->mkNode( APPLY_UF, children );
+ }
}
return d_model_basis_op_term[op];
}
diff --git a/src/theory/quantifiers_engine.cpp b/src/theory/quantifiers_engine.cpp
index e9a69bd30..5def2a832 100644
--- a/src/theory/quantifiers_engine.cpp
+++ b/src/theory/quantifiers_engine.cpp
@@ -49,11 +49,15 @@ d_lemmas_produced_c(u){
d_eem = new EfficientEMatcher( this );
d_hasAddedLemma = false;
+ Trace("quant-engine-debug") << "Initialize model, mbqi : " << options::mbqiMode() << std::endl;
//the model object
- if( options::fmfFullModelCheck() || options::fmfBoundInt() ){
+ if( options::mbqiMode()==quantifiers::MBQI_FMC ||
+ options::mbqiMode()==quantifiers::MBQI_FMC_INTERVAL || options::fmfBoundInt() ){
d_model = new quantifiers::fmcheck::FirstOrderModelFmc( this, c, "FirstOrderModelFmc" );
+ }else if( options::mbqiMode()==quantifiers::MBQI_INTERVAL ){
+ d_model = new quantifiers::FirstOrderModelQInt( this, c, "FirstOrderModelQInt" );
}else{
- d_model = new quantifiers::FirstOrderModelIG( c, "FirstOrderModelIG" );
+ d_model = new quantifiers::FirstOrderModelIG( this, c, "FirstOrderModelIG" );
}
//add quantifiers modules
diff --git a/src/theory/strings/kinds b/src/theory/strings/kinds
index 20db916c9..a421d6fa8 100644
--- a/src/theory/strings/kinds
+++ b/src/theory/strings/kinds
@@ -11,12 +11,11 @@ typechecker "theory/strings/theory_strings_type_rules.h"
operator STRING_CONCAT 2: "string concat"
-
operator STRING_IN_REGEXP 2 "membership"
-
operator STRING_LENGTH 1 "string length"
-
operator STRING_SUBSTR 3 "string substr"
+operator STRING_STRCTN 2 "string contains"
+operator STRING_CHARAT 2 "string char at"
#sort CHAR_TYPE \
# Cardinality::INTEGERS \
@@ -104,6 +103,8 @@ typerule STRING_TO_REGEXP ::CVC4::theory::strings::StringToRegExpTypeRule
typerule STRING_CONCAT ::CVC4::theory::strings::StringConcatTypeRule
typerule STRING_LENGTH ::CVC4::theory::strings::StringLengthTypeRule
typerule STRING_SUBSTR ::CVC4::theory::strings::StringSubstrTypeRule
+typerule STRING_STRCTN ::CVC4::theory::strings::StringContainTypeRule
+typerule STRING_CHARAT ::CVC4::theory::strings::StringCharAtTypeRule
typerule STRING_IN_REGEXP ::CVC4::theory::strings::StringInRegExpTypeRule
diff --git a/src/theory/strings/theory_strings.cpp b/src/theory/strings/theory_strings.cpp
index 62e71327e..5f26b2f6a 100644
--- a/src/theory/strings/theory_strings.cpp
+++ b/src/theory/strings/theory_strings.cpp
@@ -43,6 +43,7 @@ TheoryStrings::TheoryStrings(context::Context* c, context::UserContext* u, Outpu
d_nf_pairs(c),
//d_var_lmin( c ),
//d_var_lmax( c ),
+ d_str_ctn( c ),
d_reg_exp_mem( c ),
d_curr_cardinality( c, 0 )
{
@@ -50,6 +51,7 @@ TheoryStrings::TheoryStrings(context::Context* c, context::UserContext* u, Outpu
//d_equalityEngine.addFunctionKind(kind::STRING_IN_REGEXP);
d_equalityEngine.addFunctionKind(kind::STRING_LENGTH);
d_equalityEngine.addFunctionKind(kind::STRING_CONCAT);
+ d_equalityEngine.addFunctionKind(kind::STRING_STRCTN);
d_zero = NodeManager::currentNM()->mkConst( Rational( 0 ) );
d_emptyString = NodeManager::currentNM()->mkConst( ::CVC4::String("") );
@@ -387,14 +389,13 @@ void TheoryStrings::check(Effort e) {
bool polarity;
TNode atom;
- if( !done() && !hasTerm( d_emptyString ) ){
+ if( !done() && !hasTerm( d_emptyString ) ) {
preRegisterTerm( d_emptyString );
}
// Trace("strings-process") << "Theory of strings, check : " << e << std::endl;
Trace("strings-check") << "Theory of strings, check : " << e << std::endl;
- while ( !done() && !d_conflict)
- {
+ while ( !done() && !d_conflict ) {
// Get all the assertions
Assertion assertion = get();
TNode fact = assertion.assertion;
@@ -406,7 +407,10 @@ void TheoryStrings::check(Effort e) {
//must record string in regular expressions
if ( atom.getKind() == kind::STRING_IN_REGEXP ) {
d_reg_exp_mem.push_back( assertion );
- }else if (atom.getKind() == kind::EQUAL) {
+ } else if (atom.getKind() == kind::STRING_STRCTN) {
+ d_str_ctn.push_back( assertion );
+ d_equalityEngine.assertPredicate(atom, polarity, fact);
+ } else if (atom.getKind() == kind::EQUAL) {
d_equalityEngine.assertEquality(atom, polarity, fact);
} else {
d_equalityEngine.assertPredicate(atom, polarity, fact);
@@ -417,24 +421,28 @@ void TheoryStrings::check(Effort e) {
bool addedLemma = false;
if( e == EFFORT_FULL && !d_conflict ) {
- addedLemma = checkLengths();
- Trace("strings-process") << "Done check (constant) lengths, addedLemma = " << addedLemma << ", d_conflict = " << d_conflict << std::endl;
- if( !addedLemma ){
- addedLemma = checkNormalForms();
- Trace("strings-process") << "Done check normal forms, addedLemma = " << addedLemma << ", d_conflict = " << d_conflict << std::endl;
- if(!d_conflict && !addedLemma) {
- addedLemma = checkLengthsEqc();
- Trace("strings-process") << "Done check lengths, addedLemma = " << addedLemma << ", d_conflict = " << d_conflict << std::endl;
- if(!d_conflict && !addedLemma) {
- addedLemma = checkCardinality();
- Trace("strings-process") << "Done check cardinality, addedLemma = " << addedLemma << ", d_conflict = " << d_conflict << std::endl;
- if( !d_conflict && !addedLemma ){
+ addedLemma = checkLengths();
+ Trace("strings-process") << "Done check (constant) lengths, addedLemma = " << addedLemma << ", d_conflict = " << d_conflict << std::endl;
+ if( !addedLemma ) {
+ addedLemma = checkNormalForms();
+ Trace("strings-process") << "Done check normal forms, addedLemma = " << addedLemma << ", d_conflict = " << d_conflict << std::endl;
+ if(!d_conflict && !addedLemma) {
+ addedLemma = checkLengthsEqc();
+ Trace("strings-process") << "Done check lengths, addedLemma = " << addedLemma << ", d_conflict = " << d_conflict << std::endl;
+ if(!d_conflict && !addedLemma) {
+ addedLemma = checkCardinality();
+ Trace("strings-process") << "Done check cardinality, addedLemma = " << addedLemma << ", d_conflict = " << d_conflict << std::endl;
+ if( !d_conflict && !addedLemma ) {
addedLemma = checkMemberships();
Trace("strings-process") << "Done check membership constraints, addedLemma = " << addedLemma << ", d_conflict = " << d_conflict << std::endl;
- }
- }
- }
- }
+ if( !d_conflict && !addedLemma ) {
+ addedLemma = checkInclusions();
+ Trace("strings-process") << "Done check inclusion constraints, addedLemma = " << addedLemma << ", d_conflict = " << d_conflict << std::endl;
+ }
+ }
+ }
+ }
+ }
}
Trace("strings-check") << "Theory of strings, done check : " << e << std::endl;
Trace("strings-process") << "Theory of strings, done check : " << e << std::endl;
@@ -2077,6 +2085,77 @@ bool TheoryStrings::checkMemberships() {
}
}
+bool TheoryStrings::checkInclusions() {
+ bool is_unk = false;
+ bool addedLemma = false;
+ for( unsigned i=0; i<d_str_ctn.size(); i++ ){
+ Node assertion = d_str_ctn[i];
+ Trace("strings-inc") << "We have inclusion assertion : " << assertion << std::endl;
+ Node atom = assertion.getKind()==kind::NOT ? assertion[0] : assertion;
+ bool polarity = assertion.getKind()!=kind::NOT;
+ if( polarity ) {
+ Assert( atom.getKind()==kind::STRING_STRCTN );
+ Node x = atom[0];
+ Node s = atom[1];
+ if( !areEqual( s, d_emptyString ) && !areEqual( s, x ) ) {
+ if(d_str_ctn_rewritten.find(atom) == d_str_ctn_rewritten.end()) {
+ // Add lemma
+ Node sk1 = NodeManager::currentNM()->mkSkolem( "sc1_$$", s.getType(), "created for inclusion" );
+ Node sk2 = NodeManager::currentNM()->mkSkolem( "sc2_$$", s.getType(), "created for inclusion" );
+ Node eq = Rewriter::rewrite( x.eqNode( NodeManager::currentNM()->mkNode( kind::STRING_CONCAT, sk1, s, sk2 ) ) );
+ sendLemma( assertion, eq, "inclusion" );
+ addedLemma = true;
+ d_str_ctn_rewritten[ atom ] = true;
+ } else {
+ Trace("strings-inc") << "... is already rewritten." << std::endl;
+ }
+ } else {
+ Trace("strings-inc") << "... is satisfied." << std::endl;
+ }
+ } else {
+ //TODO: negative inclusion
+ if( areEqual( atom[1], d_emptyString ) ) {
+ Node ant = NodeManager::currentNM()->mkNode( kind::AND, assertion, atom[1].eqNode( d_emptyString ) );
+ Node conc = Node::null();
+ sendLemma( ant, conc, "inclusion conflict 1" );
+ addedLemma = true;
+ } else if( areEqual( atom[1], atom[0] ) ) {
+ Node ant = NodeManager::currentNM()->mkNode( kind::AND, assertion, atom[1].eqNode( atom[0] ) );
+ Node conc = Node::null();
+ sendLemma( ant, conc, "inclusion conflict 2" );
+ addedLemma = true;
+ } else {
+ if( getLogicInfo().isQuantified() ){
+ if(d_str_ctn_rewritten.find(assertion) == d_str_ctn_rewritten.end()) {
+ Node b1 = NodeManager::currentNM()->mkBoundVar( atom[0].getType() );
+ Node b2 = NodeManager::currentNM()->mkBoundVar( atom[0].getType() );
+ Node bvar = NodeManager::currentNM()->mkNode( kind::BOUND_VAR_LIST, b1, b2 );
+ Node conc = NodeManager::currentNM()->mkNode( kind::FORALL, bvar,
+ atom[0].eqNode( NodeManager::currentNM()->mkNode( kind::STRING_CONCAT, b1, atom[1], b2 ) ).negate()
+ );
+ d_str_ctn_rewritten[ assertion ] = true;
+ sendLemma( assertion, conc, "negative inclusion" );
+ addedLemma = true;
+ }
+ } else {
+ Trace("strings-inc") << "Inclusion is incomplete due to " << assertion << "." << std::endl;
+ is_unk = true;
+ }
+ }
+ }
+ }
+ if( addedLemma ){
+ doPendingLemmas();
+ return true;
+ } else {
+ if( is_unk ){
+ Trace("strings-inc") << "Strings::inc: possibly incomplete." << std::endl;
+ d_out->setIncomplete();
+ }
+ return false;
+ }
+}
+
CVC4::String TheoryStrings::getHeadConst( Node x ) {
if( x.isConst() ) {
return x.getConst< String >();
diff --git a/src/theory/strings/theory_strings.h b/src/theory/strings/theory_strings.h
index 875f407c5..62524ee14 100644
--- a/src/theory/strings/theory_strings.h
+++ b/src/theory/strings/theory_strings.h
@@ -216,6 +216,7 @@ private:
bool checkCardinality();
bool checkInductiveEquations();
bool checkMemberships();
+ bool checkInclusions();
public:
void preRegisterTerm(TNode n);
@@ -269,6 +270,10 @@ private:
Node mkSplitEq( const char * c, const char * info, Node lhs, Node rhs, bool lgtZero );
int getMaxPossibleLength( Node x );
+ // Special String Functions
+ NodeList d_str_ctn;
+ std::map< Node, bool > d_str_ctn_rewritten;
+
// Regular Expression
private:
// regular expression memberships
diff --git a/src/theory/strings/theory_strings_preprocess.cpp b/src/theory/strings/theory_strings_preprocess.cpp
index ff01b1887..4d1643fbd 100644
--- a/src/theory/strings/theory_strings_preprocess.cpp
+++ b/src/theory/strings/theory_strings_preprocess.cpp
@@ -136,6 +136,27 @@ Node StringsPreprocess::simplify( Node t, std::vector< Node > &new_nodes ) {
} else {
throw LogicException("substring not supported in this release");
}
+ } else if( t.getKind() == kind::STRING_CHARAT ){
+ if(options::stringExp()) {
+ Node sk1 = NodeManager::currentNM()->mkSkolem( "ca1sym_$$", t.getType(), "created for charat" );
+ Node sk2 = NodeManager::currentNM()->mkSkolem( "ca2sym_$$", t.getType(), "created for charat" );
+ Node sk3 = NodeManager::currentNM()->mkSkolem( "ca3sym_$$", t.getType(), "created for charat" );
+ Node x = simplify( t[0], new_nodes );
+ Node x_eq_123 = NodeManager::currentNM()->mkNode( kind::EQUAL,
+ NodeManager::currentNM()->mkNode( kind::STRING_CONCAT, sk1, sk2, sk3 ), x );
+ new_nodes.push_back( x_eq_123 );
+ Node len_sk1_eq_i = NodeManager::currentNM()->mkNode( kind::EQUAL, t[1],
+ NodeManager::currentNM()->mkNode( kind::STRING_LENGTH, sk1 ) );
+ new_nodes.push_back( len_sk1_eq_i );
+ Node len_sk2_eq_1 = NodeManager::currentNM()->mkNode( kind::EQUAL, NodeManager::currentNM()->mkConst( Rational( 1 ) ),
+ NodeManager::currentNM()->mkNode( kind::STRING_LENGTH, sk2 ) );
+ new_nodes.push_back( len_sk2_eq_1 );
+
+ d_cache[t] = sk2;
+ retNode = sk2;
+ } else {
+ throw LogicException("string char at not supported in this release");
+ }
} else if( t.getNumChildren()>0 ){
std::vector< Node > cc;
if (t.getMetaKind() == kind::metakind::PARAMETERIZED) {
diff --git a/src/theory/strings/theory_strings_rewriter.cpp b/src/theory/strings/theory_strings_rewriter.cpp
index 0e37367bf..af19095a0 100644
--- a/src/theory/strings/theory_strings_rewriter.cpp
+++ b/src/theory/strings/theory_strings_rewriter.cpp
@@ -341,21 +341,35 @@ RewriteResponse TheoryStringsRewriter::postRewrite(TNode node) {
}
}
} else if(node.getKind() == kind::STRING_SUBSTR) {
- if(options::stringExp()) {
- if( node[0].isConst() && node[1].isConst() && node[2].isConst() ) {
- int i = node[1].getConst<Rational>().getNumerator().toUnsignedInt();
- int j = node[2].getConst<Rational>().getNumerator().toUnsignedInt();
- if( node[0].getConst<String>().size() >= (unsigned) (i + j) ) {
- retNode = NodeManager::currentNM()->mkConst( node[0].getConst<String>().substr(i, j) );
- } else {
- // TODO: some issues, must be guarded by users
- retNode = NodeManager::currentNM()->mkConst( false );
- }
+ if( node[0].isConst() && node[1].isConst() && node[2].isConst() ) {
+ int i = node[1].getConst<Rational>().getNumerator().toUnsignedInt();
+ int j = node[2].getConst<Rational>().getNumerator().toUnsignedInt();
+ if( node[0].getConst<String>().size() >= (unsigned) (i + j) ) {
+ retNode = NodeManager::currentNM()->mkConst( node[0].getConst<String>().substr(i, j) );
} else {
- //handled by preprocess
+ // TODO: some issues, must be guarded by users
+ retNode = NodeManager::currentNM()->mkConst( false );
+ }
+ }
+ } else if(node.getKind() == kind::STRING_STRCTN) {
+ if( node[0].isConst() && node[1].isConst() ) {
+ CVC4::String s = node[0].getConst<String>();
+ CVC4::String t = node[1].getConst<String>();
+ if( s.find(t) != std::string::npos ) {
+ retNode = NodeManager::currentNM()->mkConst( true );
+ } else {
+ retNode = NodeManager::currentNM()->mkConst( false );
+ }
+ }
+ } else if(node.getKind() == kind::STRING_CHARAT) {
+ if( node[0].isConst() && node[1].isConst() ) {
+ int i = node[1].getConst<Rational>().getNumerator().toUnsignedInt();
+ if( node[0].getConst<String>().size() > (unsigned) i ) {
+ retNode = NodeManager::currentNM()->mkConst( node[0].getConst<String>().substr(i, 1) );
+ } else {
+ // TODO: some issues, must be guarded by users
+ retNode = NodeManager::currentNM()->mkConst( false );
}
- } else {
- throw LogicException("substring not supported in this release");
}
} else if(node.getKind() == kind::STRING_IN_REGEXP) {
retNode = rewriteMembership(node);
diff --git a/src/theory/strings/theory_strings_type_rules.h b/src/theory/strings/theory_strings_type_rules.h
index d5019ab39..9d3197517 100644
--- a/src/theory/strings/theory_strings_type_rules.h
+++ b/src/theory/strings/theory_strings_type_rules.h
@@ -73,15 +73,51 @@ public:
if( check ){
TypeNode t = n[0].getType(check);
if (!t.isString()) {
- throw TypeCheckingExceptionPrivate(n, "expecting string terms in substr");
+ throw TypeCheckingExceptionPrivate(n, "expecting a string term in substr");
}
t = n[1].getType(check);
if (!t.isInteger()) {
- throw TypeCheckingExceptionPrivate(n, "expecting start int terms in substr");
+ throw TypeCheckingExceptionPrivate(n, "expecting a start int term in substr");
}
t = n[2].getType(check);
if (!t.isInteger()) {
- throw TypeCheckingExceptionPrivate(n, "expecting length int terms in substr");
+ throw TypeCheckingExceptionPrivate(n, "expecting a length int term in substr");
+ }
+ }
+ return nodeManager->stringType();
+ }
+};
+
+class StringContainTypeRule {
+public:
+ inline static TypeNode computeType(NodeManager* nodeManager, TNode n, bool check)
+ throw (TypeCheckingExceptionPrivate, AssertionException) {
+ if( check ){
+ TypeNode t = n[0].getType(check);
+ if (!t.isString()) {
+ throw TypeCheckingExceptionPrivate(n, "expecting an orginal string term in string contain");
+ }
+ t = n[1].getType(check);
+ if (!t.isString()) {
+ throw TypeCheckingExceptionPrivate(n, "expecting a target string term in string contain");
+ }
+ }
+ return nodeManager->booleanType();
+ }
+};
+
+class StringCharAtTypeRule {
+public:
+ inline static TypeNode computeType(NodeManager* nodeManager, TNode n, bool check)
+ throw (TypeCheckingExceptionPrivate, AssertionException) {
+ if( check ){
+ TypeNode t = n[0].getType(check);
+ if (!t.isString()) {
+ throw TypeCheckingExceptionPrivate(n, "expecting a string term in string char at");
+ }
+ t = n[1].getType(check);
+ if (!t.isInteger()) {
+ throw TypeCheckingExceptionPrivate(n, "expecting an integer string term in string char at");
}
}
return nodeManager->stringType();
diff --git a/src/theory/theory.h b/src/theory/theory.h
index fdd2d0518..43d35ac9d 100644
--- a/src/theory/theory.h
+++ b/src/theory/theory.h
@@ -254,6 +254,7 @@ protected:
, d_sharedTerms(satContext)
, d_out(&out)
, d_valuation(valuation)
+ , d_proofEnabled(false)
{
StatisticsRegistry::registerStat(&d_computeCareGraphTime);
}
@@ -299,6 +300,12 @@ protected:
void printFacts(std::ostream& os) const;
void debugPrintFacts() const;
+ /**
+ * Whether proofs are enabled
+ *
+ */
+ bool d_proofEnabled;
+
public:
/**
diff --git a/src/theory/theory_engine.cpp b/src/theory/theory_engine.cpp
index 7cf4d7ad9..c598fd01b 100644
--- a/src/theory/theory_engine.cpp
+++ b/src/theory/theory_engine.cpp
@@ -146,6 +146,7 @@ TheoryEngine::TheoryEngine(context::Context* context,
StatisticsRegistry::registerStat(&d_combineTheoriesTime);
d_true = NodeManager::currentNM()->mkConst<bool>(true);
d_false = NodeManager::currentNM()->mkConst<bool>(false);
+
PROOF (ProofManager::currentPM()->initTheoryProof(); );
d_iteUtilities = new ITEUtilities(d_iteRemover.getContainsVisitor());
diff --git a/src/theory/uf/equality_engine.cpp b/src/theory/uf/equality_engine.cpp
index cb44b42df..df1d2ebde 100644
--- a/src/theory/uf/equality_engine.cpp
+++ b/src/theory/uf/equality_engine.cpp
@@ -71,8 +71,8 @@ void EqualityEngine::init() {
addTermInternal(d_false);
d_trueId = getNodeId(d_true);
- d_falseId = getNodeId(d_false);
-}
+ d_falseId = getNodeId(d_false);
+}
EqualityEngine::~EqualityEngine() throw(AssertionException) {
free(d_triggerDatabase);
@@ -287,7 +287,7 @@ void EqualityEngine::addTermInternal(TNode t, bool isOperator) {
d_isConstant[result] = t.isConst();
// If interpreted, set the number of non-interpreted children
if (isInterpreted) {
- // How many children are not constants yet
+ // How many children are not constants yet
d_subtermsToEvaluate[result] = t.getNumChildren();
for (unsigned i = 0; i < t.getNumChildren(); ++ i) {
if (isConstant(getNodeId(t[i]))) {
@@ -316,11 +316,11 @@ void EqualityEngine::addTermInternal(TNode t, bool isOperator) {
for (TheoryId currentTheory = THEORY_FIRST; currentTheory != THEORY_LAST; ++ currentTheory) {
d_newSetTags = Theory::setInsert(currentTheory, d_newSetTags);
d_newSetTriggers[currentTheory] = tId;
- }
+ }
// Add it to the list for backtracking
d_triggerTermSetUpdates.push_back(TriggerSetUpdate(tId, null_set_id));
d_triggerTermSetUpdatesSize = d_triggerTermSetUpdatesSize + 1;
- // Mark the the new set as a trigger
+ // Mark the the new set as a trigger
d_nodeIndividualTrigger[tId] = newTriggerTermSet();
}
@@ -333,7 +333,7 @@ void EqualityEngine::addTermInternal(TNode t, bool isOperator) {
propagate();
Assert(hasTerm(t));
-
+
Debug("equality") << d_name << "::eq::addTermInternal(" << t << ") => " << result << std::endl;
}
@@ -419,12 +419,12 @@ void EqualityEngine::assertEquality(TNode eq, bool polarity, TNode reason) {
Debug("equality::trigger") << d_name << "::eq::addEquality(" << eq << "," << (polarity ? "true" : "false") << ")" << std::endl;
assertEqualityInternal(eq, d_false, reason);
- propagate();
-
+ propagate();
+
if (d_done) {
return;
}
-
+
// If both have constant representatives, we don't notify anyone
EqualityNodeId a = getNodeId(eq[0]);
EqualityNodeId b = getNodeId(eq[1]);
@@ -432,8 +432,8 @@ void EqualityEngine::assertEquality(TNode eq, bool polarity, TNode reason) {
EqualityNodeId bClassId = getEqualityNode(b).getFind();
if (d_isConstant[aClassId] && d_isConstant[bClassId]) {
return;
- }
-
+ }
+
// If we are adding a disequality, notify of the shared term representatives
EqualityNodeId eqId = getNodeId(eq);
TriggerTermSetRef aTriggerRef = d_nodeIndividualTrigger[aClassId];
@@ -443,16 +443,16 @@ void EqualityEngine::assertEquality(TNode eq, bool polarity, TNode reason) {
// The sets of trigger terms
TriggerTermSet& aTriggerTerms = getTriggerTermSet(aTriggerRef);
TriggerTermSet& bTriggerTerms = getTriggerTermSet(bTriggerRef);
- // Go through and notify the shared dis-equalities
- Theory::Set aTags = aTriggerTerms.tags;
- Theory::Set bTags = bTriggerTerms.tags;
+ // Go through and notify the shared dis-equalities
+ Theory::Set aTags = aTriggerTerms.tags;
+ Theory::Set bTags = bTriggerTerms.tags;
TheoryId aTag = Theory::setPop(aTags);
TheoryId bTag = Theory::setPop(bTags);
int a_i = 0, b_i = 0;
while (aTag != THEORY_LAST && bTag != THEORY_LAST) {
if (aTag < bTag) {
aTag = Theory::setPop(aTags);
- ++ a_i;
+ ++ a_i;
} else if (aTag > bTag) {
bTag = Theory::setPop(bTags);
++ b_i;
@@ -499,7 +499,7 @@ bool EqualityEngine::merge(EqualityNode& class1, EqualityNode& class2, std::vect
Debug("equality") << d_name << "::eq::merge(" << class1.getFind() << "," << class2.getFind() << ")" << std::endl;
Assert(triggersFired.empty());
-
+
++ d_stats.mergesCount;
EqualityNodeId class1Id = class1.getFind();
@@ -539,8 +539,8 @@ bool EqualityEngine::merge(EqualityNode& class1, EqualityNode& class2, std::vect
TaggedEqualitiesSet class1disequalitiesToNotify;
// Individual tags
- Theory::Set class1OnlyTags = Theory::setDifference(class1Tags, class2Tags);
- Theory::Set class2OnlyTags = Theory::setDifference(class2Tags, class1Tags);
+ Theory::Set class1OnlyTags = Theory::setDifference(class1Tags, class2Tags);
+ Theory::Set class2OnlyTags = Theory::setDifference(class2Tags, class1Tags);
// Only get disequalities if they are not both constant
if (!class1isConstant || !class2isConstant) {
@@ -590,9 +590,9 @@ bool EqualityEngine::merge(EqualityNode& class1, EqualityNode& class2, std::vect
Debug("equality") << d_name << "::eq::merge(" << class1.getFind() << "," << class2.getFind() << "): updating lookups of " << class2Id << std::endl;
do {
// Get the current node
- EqualityNode& currentNode = getEqualityNode(currentId);
+ EqualityNode& currentNode = getEqualityNode(currentId);
Debug("equality") << d_name << "::eq::merge(" << class1.getFind() << "," << class2.getFind() << "): updating lookups of node " << currentId << std::endl;
-
+
// Go through the uselist and check for congruences
UseListNodeId currentUseId = currentNode.getUseList();
while (currentUseId != null_uselist_id) {
@@ -604,7 +604,7 @@ bool EqualityEngine::merge(EqualityNode& class1, EqualityNode& class2, std::vect
const FunctionApplication& fun = d_applications[useNode.getApplicationId()].normalized;
// If it's interpreted and we can interpret
if (fun.isInterpreted() && class1isConstant && !d_isInternal[currentId]) {
- // Get the actual term id
+ // Get the actual term id
TNode term = d_nodes[funId];
subtermEvaluates(getNodeId(term));
}
@@ -622,16 +622,16 @@ bool EqualityEngine::merge(EqualityNode& class1, EqualityNode& class2, std::vect
// There is no representative, so we can add one, we remove this when backtracking
storeApplicationLookup(funNormalized, funId);
}
-
+
// Go to the next one in the use list
currentUseId = useNode.getNext();
}
-
+
// Move to the next node
currentId = currentNode.getNext();
} while (currentId != class2Id);
}
-
+
// Now merge the lists
class1.merge<true>(class2);
@@ -660,24 +660,24 @@ bool EqualityEngine::merge(EqualityNode& class1, EqualityNode& class2, std::vect
// Get the triggers
TriggerTermSet& class1triggers = getTriggerTermSet(class1triggerRef);
TriggerTermSet& class2triggers = getTriggerTermSet(class2triggerRef);
-
+
// Initialize the merged set
d_newSetTags = Theory::setUnion(class1triggers.tags, class2triggers.tags);
d_newSetTriggersSize = 0;
-
+
int i1 = 0;
int i2 = 0;
Theory::Set tags1 = class1triggers.tags;
Theory::Set tags2 = class2triggers.tags;
TheoryId tag1 = Theory::setPop(tags1);
TheoryId tag2 = Theory::setPop(tags2);
-
+
// Comparing the THEORY_LAST is OK because all other theories are
// smaller, and will therefore be preferred
- while (tag1 != THEORY_LAST || tag2 != THEORY_LAST)
+ while (tag1 != THEORY_LAST || tag2 != THEORY_LAST)
{
if (tag1 < tag2) {
- // copy tag1
+ // copy tag1
d_newSetTriggers[d_newSetTriggersSize++] = class1triggers.triggers[i1++];
tag1 = Theory::setPop(tags1);
} else if (tag1 > tag2) {
@@ -685,7 +685,7 @@ bool EqualityEngine::merge(EqualityNode& class1, EqualityNode& class2, std::vect
d_newSetTriggers[d_newSetTriggersSize++] = class2triggers.triggers[i2++];
tag2 = Theory::setPop(tags2);
} else {
- // copy tag1
+ // copy tag1
EqualityNodeId tag1id = d_newSetTriggers[d_newSetTriggersSize++] = class1triggers.triggers[i1++];
// since they are both tagged notify of merge
if (d_performNotify) {
@@ -698,17 +698,17 @@ bool EqualityEngine::merge(EqualityNode& class1, EqualityNode& class2, std::vect
tag1 = Theory::setPop(tags1);
tag2 = Theory::setPop(tags2);
}
- }
-
+ }
+
// Add the new trigger set, if different from previous one
if (class1triggers.tags != class2triggers.tags) {
// Add it to the list for backtracking
d_triggerTermSetUpdates.push_back(TriggerSetUpdate(class1Id, class1triggerRef));
d_triggerTermSetUpdatesSize = d_triggerTermSetUpdatesSize + 1;
- // Mark the the new set as a trigger
+ // Mark the the new set as a trigger
d_nodeIndividualTrigger[class1Id] = newTriggerTermSet();
- }
- }
+ }
+ }
}
// Everything fine
@@ -792,14 +792,14 @@ void EqualityEngine::backtrack() {
}
d_triggerTermSetUpdates.resize(d_triggerTermSetUpdatesSize);
}
-
+
if (d_equalityTriggers.size() > d_equalityTriggersCount) {
// Unlink the triggers from the lists
for (int i = d_equalityTriggers.size() - 1, i_end = d_equalityTriggersCount; i >= i_end; -- i) {
const Trigger& trigger = d_equalityTriggers[i];
d_nodeTriggers[trigger.classId] = trigger.nextTrigger;
}
- // Get rid of the triggers
+ // Get rid of the triggers
d_equalityTriggers.resize(d_equalityTriggersCount);
d_equalityTriggersOriginal.resize(d_equalityTriggersCount);
}
@@ -859,7 +859,7 @@ void EqualityEngine::backtrack() {
d_deducedDisequalityReasons.resize(d_deducedDisequalityReasonsSize);
d_deducedDisequalities.resize(d_deducedDisequalitiesSize);
}
-
+
}
void EqualityEngine::addGraphEdge(EqualityNodeId t1, EqualityNodeId t2, MergeReasonType type, TNode reason) {
@@ -892,7 +892,7 @@ std::string EqualityEngine::edgesToString(EqualityEdgeId edgeId) const {
return out.str();
}
-void EqualityEngine::explainEquality(TNode t1, TNode t2, bool polarity, std::vector<TNode>& equalities) const {
+void EqualityEngine::explainEquality(TNode t1, TNode t2, bool polarity, std::vector<TNode>& equalities, EqProof * eqp) const {
Debug("equality") << d_name << "::eq::explainEquality(" << t1 << ", " << t2 << ", " << (polarity ? "true" : "false") << ")" << std::endl;
// The terms must be there already
@@ -904,7 +904,7 @@ void EqualityEngine::explainEquality(TNode t1, TNode t2, bool polarity, std::vec
if (polarity) {
// Get the explanation
- getExplanation(t1Id, t2Id, equalities);
+ getExplanation(t1Id, t2Id, equalities, eqp);
} else {
// Get the reason for this disequality
EqualityPair pair(t1Id, t2Id);
@@ -912,20 +912,20 @@ void EqualityEngine::explainEquality(TNode t1, TNode t2, bool polarity, std::vec
DisequalityReasonRef reasonRef = d_disequalityReasonsMap.find(pair)->second;
for (unsigned i = reasonRef.mergesStart; i < reasonRef.mergesEnd; ++ i) {
EqualityPair toExplain = d_deducedDisequalityReasons[i];
- getExplanation(toExplain.first, toExplain.second, equalities);
+ getExplanation(toExplain.first, toExplain.second, equalities, eqp);
}
}
}
-void EqualityEngine::explainPredicate(TNode p, bool polarity, std::vector<TNode>& assertions) const {
+void EqualityEngine::explainPredicate(TNode p, bool polarity, std::vector<TNode>& assertions, EqProof * eqp) const {
Debug("equality") << d_name << "::eq::explainPredicate(" << p << ")" << std::endl;
// Must have the term
Assert(hasTerm(p));
// Get the explanation
- getExplanation(getNodeId(p), polarity ? d_trueId : d_falseId, assertions);
+ getExplanation(getNodeId(p), polarity ? d_trueId : d_falseId, assertions, eqp);
}
-void EqualityEngine::getExplanation(EqualityNodeId t1Id, EqualityNodeId t2Id, std::vector<TNode>& equalities) const {
+void EqualityEngine::getExplanation(EqualityNodeId t1Id, EqualityNodeId t2Id, std::vector<TNode>& equalities, EqProof * eqp) const {
Debug("equality") << d_name << "::eq::getExplanation(" << d_nodes[t1Id] << "," << d_nodes[t2Id] << ")" << std::endl;
@@ -933,17 +933,23 @@ void EqualityEngine::getExplanation(EqualityNodeId t1Id, EqualityNodeId t2Id, st
#ifdef CVC4_ASSERTIONS
bool canExplain = getEqualityNode(t1Id).getFind() == getEqualityNode(t2Id).getFind()
|| (d_done && isConstant(t1Id) && isConstant(t2Id));
-
+
if (!canExplain) {
Warning() << "Can't explain equality:" << std::endl;
Warning() << d_nodes[t1Id] << " with find " << d_nodes[getEqualityNode(t1Id).getFind()] << std::endl;
- Warning() << d_nodes[t2Id] << " with find " << d_nodes[getEqualityNode(t2Id).getFind()] << std::endl;
+ Warning() << d_nodes[t2Id] << " with find " << d_nodes[getEqualityNode(t2Id).getFind()] << std::endl;
}
Assert(canExplain);
#endif
// If the nodes are the same, we're done
- if (t1Id == t2Id) return;
+ if (t1Id == t2Id){
+ if( eqp ) {
+ eqp->d_node = d_nodes[t1Id];
+ }
+ return;
+ }
+
if (Debug.isOn("equality::internal")) {
debugPrintGraph();
@@ -986,6 +992,8 @@ void EqualityEngine::getExplanation(EqualityNodeId t1Id, EqualityNodeId t2Id, st
Debug("equality") << d_name << "::eq::getExplanation(): path found: " << std::endl;
+ std::vector< EqProof * > eqp_trans;
+
// Reconstruct the path
do {
// The current node
@@ -995,6 +1003,12 @@ void EqualityEngine::getExplanation(EqualityNodeId t1Id, EqualityNodeId t2Id, st
Debug("equality") << d_name << "::eq::getExplanation(): currentEdge = " << currentEdge << ", currentNode = " << currentNode << std::endl;
+ EqProof * eqpc = NULL;
+ //make child proof if a proof is being constructed
+ if( eqp ){
+ eqpc = new EqProof;
+ eqpc->d_id = reasonType;
+ }
// Add the actual equality to the vector
switch (reasonType) {
case MERGED_THROUGH_CONGRUENCE: {
@@ -1003,32 +1017,45 @@ void EqualityEngine::getExplanation(EqualityNodeId t1Id, EqualityNodeId t2Id, st
const FunctionApplication& f1 = d_applications[currentNode].original;
const FunctionApplication& f2 = d_applications[edgeNode].original;
Debug("equality") << push;
- getExplanation(f1.a, f2.a, equalities);
- getExplanation(f1.b, f2.b, equalities);
+ EqProof * eqpc1 = eqpc ? new EqProof : NULL;
+ getExplanation(f1.a, f2.a, equalities, eqpc1);
+ EqProof * eqpc2 = eqpc ? new EqProof : NULL;
+ getExplanation(f1.b, f2.b, equalities, eqpc2);
+ if( eqpc ){
+ eqpc->d_children.push_back( eqpc1 );
+ eqpc->d_children.push_back( eqpc2 );
+ }
Debug("equality") << pop;
break;
- }
+ }
case MERGED_THROUGH_EQUALITY:
// Construct the equality
Debug("equality") << d_name << "::eq::getExplanation(): adding: " << d_equalityEdges[currentEdge].getReason() << std::endl;
+ if( eqpc ){
+ eqpc->d_node = d_equalityEdges[currentEdge].getReason();
+ }
equalities.push_back(d_equalityEdges[currentEdge].getReason());
break;
case MERGED_THROUGH_REFLEXIVITY: {
- // x1 == x1
+ // x1 == x1
Debug("equality") << d_name << "::eq::getExplanation(): due to reflexivity, going deeper" << std::endl;
EqualityNodeId eqId = currentNode == d_trueId ? edgeNode : currentNode;
const FunctionApplication& eq = d_applications[eqId].original;
Assert(eq.isEquality(), "Must be an equality");
-
+
// Explain why a = b constant
Debug("equality") << push;
- getExplanation(eq.a, eq.b, equalities);
+ EqProof * eqpc1 = eqpc ? new EqProof : NULL;
+ getExplanation(eq.a, eq.b, equalities, eqpc1);
+ if( eqpc ){
+ eqpc->d_children.push_back( eqpc1 );
+ }
Debug("equality") << pop;
-
- break;
+
+ break;
}
case MERGED_THROUGH_CONSTANTS: {
- // f(c1, ..., cn) = c semantically, we can just ignore it
+ // f(c1, ..., cn) = c semantically, we can just ignore it
Debug("equality") << d_name << "::eq::getExplanation(): due to constants, explain the constants" << std::endl;
Debug("equality") << push;
@@ -1042,7 +1069,11 @@ void EqualityEngine::getExplanation(EqualityNodeId t1Id, EqualityNodeId t2Id, st
for (unsigned i = 0; i < interpreted.getNumChildren(); ++ i) {
EqualityNodeId childId = getNodeId(interpreted[i]);
Assert(isConstant(childId));
- getExplanation(childId, getEqualityNode(childId).getFind(), equalities);
+ EqProof * eqpcc = eqpc ? new EqProof : NULL;
+ getExplanation(childId, getEqualityNode(childId).getFind(), equalities, eqpcc);
+ if( eqpc ) {
+ eqpc->d_children.push_back( eqpcc );
+ }
}
Debug("equality") << pop;
@@ -1051,14 +1082,21 @@ void EqualityEngine::getExplanation(EqualityNodeId t1Id, EqualityNodeId t2Id, st
}
default:
Unreachable();
- }
-
+ }
+
// Go to the previous
currentEdge = bfsQueue[currentIndex].edgeId;
currentIndex = bfsQueue[currentIndex].previousIndex;
-
+
+ eqp_trans.push_back( eqpc );
+
} while (currentEdge != null_id);
+ if( eqp ){
+ eqp->d_id = MERGED_THROUGH_TRANS;
+ eqp->d_children.insert( eqp->d_children.end(), eqp_trans.begin(), eqp_trans.end() );
+ }
+
// Done
return;
}
@@ -1220,7 +1258,7 @@ void EqualityEngine::processEvaluationQueue() {
// Get the node
EqualityNodeId id = d_evaluationQueue.front();
d_evaluationQueue.pop();
-
+
// Replace the children with their representatives (must be constants)
Node nodeEvaluated = evaluateTerm(d_nodes[id]);
Debug("equality::evaluation") << d_name << "::eq::processEvaluationQueue(): " << d_nodes[id] << " evaluates to " << nodeEvaluated << std::endl;
@@ -1240,11 +1278,11 @@ void EqualityEngine::propagate() {
if (d_inPropagate) {
// We're already in propagate, go back
return;
- }
-
+ }
+
// Make sure we don't get in again
ScopedBool inPropagate(d_inPropagate, true);
-
+
Debug("equality") << d_name << "::eq::propagate()" << std::endl;
while (!d_propagationQueue.empty() || !d_evaluationQueue.empty()) {
@@ -1255,13 +1293,13 @@ void EqualityEngine::propagate() {
while (!d_evaluationQueue.empty()) d_evaluationQueue.pop();
continue;
}
-
+
// Process any evaluation requests
if (!d_evaluationQueue.empty()) {
processEvaluationQueue();
continue;
}
-
+
// The current merge candidate
const MergeCandidate current = d_propagationQueue.front();
d_propagationQueue.pop_front();
@@ -1288,7 +1326,7 @@ void EqualityEngine::propagate() {
// Add the actual equality to the equality graph
addGraphEdge(current.t1Id, current.t2Id, current.type, current.reason);
- // If constants are being merged we're done
+ // If constants are being merged we're done
if (d_isConstant[t1classId] && d_isConstant[t2classId]) {
// When merging constants we are inconsistent, hence done
d_done = true;
@@ -1462,7 +1500,7 @@ bool EqualityEngine::areDisequal(TNode t1, TNode t2, bool ensureProof) const
return true;
}
}
-
+
// Check the other equality itself if it exists
eq = t2.eqNode(t1);
if (hasTerm(eq)) {
@@ -1474,7 +1512,7 @@ bool EqualityEngine::areDisequal(TNode t1, TNode t2, bool ensureProof) const
return true;
}
}
-
+
// Create the equality
FunctionApplication eqNormalized(APP_EQUALITY, t1ClassId, t2ClassId);
ApplicationIdsMap::const_iterator find = d_applicationLookup.find(eqNormalized);
@@ -1492,7 +1530,7 @@ bool EqualityEngine::areDisequal(TNode t1, TNode t2, bool ensureProof) const
return true;
}
}
-
+
// Check the symmetric disequality
std::swap(eqNormalized.a, eqNormalized.b);
find = d_applicationLookup.find(eqNormalized);
@@ -1510,7 +1548,7 @@ bool EqualityEngine::areDisequal(TNode t1, TNode t2, bool ensureProof) const
return true;
}
}
-
+
// Couldn't deduce dis-equalityReturn whether the terms are disequal
return false;
}
@@ -1568,19 +1606,19 @@ void EqualityEngine::addTriggerTerm(TNode t, TheoryId tag)
// Initialize the new set for copy/insert
d_newSetTags = Theory::setInsert(tag, triggerSet.tags);
d_newSetTriggersSize = 0;
- // Copy into to new one, and insert the new tag/id
+ // Copy into to new one, and insert the new tag/id
unsigned i = 0;
Theory::Set tags = d_newSetTags;
- TheoryId current;
+ TheoryId current;
while ((current = Theory::setPop(tags)) != THEORY_LAST) {
// Remove from the tags
tags = Theory::setRemove(current, tags);
// Insert the id into the triggers
- d_newSetTriggers[d_newSetTriggersSize++] =
+ d_newSetTriggers[d_newSetTriggersSize++] =
current == tag ? eqNodeId : triggerSet.triggers[i++];
}
} else {
- // Setup a singleton
+ // Setup a singleton
d_newSetTags = Theory::setInsert(tag);
d_newSetTriggers[0] = eqNodeId;
d_newSetTriggersSize = 1;
@@ -1589,7 +1627,7 @@ void EqualityEngine::addTriggerTerm(TNode t, TheoryId tag)
// Add it to the list for backtracking
d_triggerTermSetUpdates.push_back(TriggerSetUpdate(classId, triggerSetRef));
d_triggerTermSetUpdatesSize = d_triggerTermSetUpdatesSize + 1;
- // Mark the the new set as a trigger
+ // Mark the the new set as a trigger
d_nodeIndividualTrigger[classId] = triggerSetRef = newTriggerTermSet();
// Propagate trigger term disequalities we remembered
@@ -1843,7 +1881,7 @@ void EqualityEngine::getDisequalities(bool allowConstants, EqualityNodeId classI
}
bool EqualityEngine::propagateTriggerTermDisequalities(Theory::Set tags, TriggerTermSetRef triggerSetRef, const TaggedEqualitiesSet& disequalitiesToNotify) {
-
+
// No tags, no food
if (!tags) {
return !d_done;
@@ -1852,14 +1890,14 @@ bool EqualityEngine::propagateTriggerTermDisequalities(Theory::Set tags, Trigger
Assert(triggerSetRef != null_set_id);
// This is the class trigger set
- const TriggerTermSet& triggerSet = getTriggerTermSet(triggerSetRef);
+ const TriggerTermSet& triggerSet = getTriggerTermSet(triggerSetRef);
// Go through the disequalities and notify
TaggedEqualitiesSet::const_iterator it = disequalitiesToNotify.begin();
TaggedEqualitiesSet::const_iterator it_end = disequalitiesToNotify.end();
for (; !d_done && it != it_end; ++ it) {
// The information about the equality that is asserted to false
const TaggedEquality& disequalityInfo = *it;
- const TriggerTermSet& disequalityTriggerSet = getTriggerTermSet(disequalityInfo.triggerSetRef);
+ const TriggerTermSet& disequalityTriggerSet = getTriggerTermSet(disequalityInfo.triggerSetRef);
Theory::Set commonTags = Theory::setIntersection(disequalityTriggerSet.tags, tags);
Assert(commonTags);
// This is the actual function
@@ -1897,7 +1935,7 @@ bool EqualityEngine::propagateTriggerTermDisequalities(Theory::Set tags, Trigger
}
}
}
-
+
return !d_done;
}
@@ -2005,6 +2043,25 @@ bool EqClassIterator::isFinished() const {
}
+void EqProof::debug_print( const char * c, unsigned tb ){
+ for( unsigned i=0; i<tb; i++ ) { Debug( c ) << " "; }
+ Debug( c ) << d_id << "(";
+ if( !d_children.empty() || !d_node.isNull() ){
+ if( !d_node.isNull() ){
+ Debug( c ) << std::endl;
+ for( unsigned i=0; i<tb+1; i++ ) { Debug( c ) << " "; }
+ Debug( c ) << d_node;
+ }
+ for( unsigned i=0; i<d_children.size(); i++ ){
+ if( i>0 || !d_node.isNull() ) Debug( c ) << ",";
+ std::cout << std::endl;
+ d_children[i]->debug_print( c, tb+1 );
+ }
+ }
+ Debug( c ) << ")";
+}
+
+
} // Namespace uf
} // Namespace theory
} // Namespace CVC4
diff --git a/src/theory/uf/equality_engine.h b/src/theory/uf/equality_engine.h
index ab106bc8d..f8e361081 100644
--- a/src/theory/uf/equality_engine.h
+++ b/src/theory/uf/equality_engine.h
@@ -39,6 +39,8 @@ namespace CVC4 {
namespace theory {
namespace eq {
+
+class EqProof;
class EqClassesIterator;
class EqClassIterator;
@@ -421,35 +423,35 @@ private:
/**
* Map from ids of proper terms, to the number of non-constant direct subterms. If we update an interpreted
* application to a constant, we can decrease this value. If we hit 0, we can evaluate the term.
- *
+ *
*/
std::vector<unsigned> d_subtermsToEvaluate;
-
- /**
+
+ /**
* For nodes that we need to postpone evaluation.
*/
std::queue<EqualityNodeId> d_evaluationQueue;
-
+
/**
* Evaluate all terms in the evaluation queue.
*/
void processEvaluationQueue();
-
+
/** Vector of nodes that evaluate. */
std::vector<EqualityNodeId> d_subtermEvaluates;
/** Size of the nodes that evaluate vector. */
context::CDO<unsigned> d_subtermEvaluatesSize;
-
+
/** Set the node evaluate flag */
void subtermEvaluates(EqualityNodeId id);
/**
- * Returns the evaluation of the term when all (direct) children are replaced with
+ * Returns the evaluation of the term when all (direct) children are replaced with
* the constant representatives.
*/
Node evaluateTerm(TNode node);
-
+
/**
* Returns true if it's a constant
*/
@@ -487,7 +489,7 @@ private:
/** Enqueue to the propagation queue */
void enqueue(const MergeCandidate& candidate, bool back = true);
-
+
/** Do the propagation */
void propagate();
@@ -499,7 +501,7 @@ private:
* imply t1 = t2. Returns TNodes as the assertion equalities should be hashed somewhere
* else.
*/
- void getExplanation(EqualityEdgeId t1Id, EqualityNodeId t2Id, std::vector<TNode>& equalities) const;
+ void getExplanation(EqualityEdgeId t1Id, EqualityNodeId t2Id, std::vector<TNode>& equalities, EqProof * eqp) const;
/**
* Print the equality graph.
@@ -752,7 +754,7 @@ public:
void assertPredicate(TNode p, bool polarity, TNode reason);
/**
- * Adds predicate p and q and makes them equal.
+ * Adds predicate p and q and makes them equal.
*/
void mergePredicates(TNode p, TNode q, TNode reason);
@@ -782,14 +784,14 @@ public:
* Returns the reasons (added when asserting) that imply it
* in the assertions vector.
*/
- void explainEquality(TNode t1, TNode t2, bool polarity, std::vector<TNode>& assertions) const;
+ void explainEquality(TNode t1, TNode t2, bool polarity, std::vector<TNode>& assertions, EqProof * eqp = NULL) const;
/**
* Get an explanation of the predicate being true or false.
* Returns the reasons (added when asserting) that imply imply it
* in the assertions vector.
*/
- void explainPredicate(TNode p, bool polarity, std::vector<TNode>& assertions) const;
+ void explainPredicate(TNode p, bool polarity, std::vector<TNode>& assertions, EqProof * eqp = NULL) const;
/**
* Add term to the set of trigger terms with a corresponding tag. The notify class will get
@@ -890,6 +892,16 @@ public:
bool isFinished() const;
};/* class EqClassIterator */
+class EqProof
+{
+public:
+ EqProof() : d_id(MERGED_THROUGH_REFLEXIVITY){}
+ MergeReasonType d_id;
+ Node d_node;
+ std::vector< EqProof * > d_children;
+ void debug_print( const char * c, unsigned tb = 0 );
+};
+
} // Namespace eq
} // Namespace theory
} // Namespace CVC4
diff --git a/src/theory/uf/equality_engine_types.h b/src/theory/uf/equality_engine_types.h
index a36291974..435a1ece5 100644
--- a/src/theory/uf/equality_engine_types.h
+++ b/src/theory/uf/equality_engine_types.h
@@ -54,7 +54,7 @@ static const EqualityEdgeId null_edge = (EqualityEdgeId)(-1);
/**
* A reason for a merge. Either an equality x = y, a merge of two
- * function applications f(x1, x2), f(y1, y2) due to congruence,
+ * function applications f(x1, x2), f(y1, y2) due to congruence,
* or a merge of an equality to false due to both sides being
* (different) constants.
*/
@@ -67,6 +67,9 @@ enum MergeReasonType {
MERGED_THROUGH_REFLEXIVITY,
/** Equality was merged to false, due to both sides of equality being a constant */
MERGED_THROUGH_CONSTANTS,
+
+ /** (for proofs only) Equality was merged due to transitivity */
+ MERGED_THROUGH_TRANS,
};
inline std::ostream& operator << (std::ostream& out, MergeReasonType reason) {
@@ -83,6 +86,10 @@ inline std::ostream& operator << (std::ostream& out, MergeReasonType reason) {
case MERGED_THROUGH_CONSTANTS:
out << "constants disequal";
break;
+ // (for proofs only)
+ case MERGED_THROUGH_TRANS:
+ out << "transitivity";
+ break;
default:
Unreachable();
}
@@ -98,7 +105,7 @@ struct MergeCandidate {
MergeReasonType type;
TNode reason;
MergeCandidate(EqualityNodeId x, EqualityNodeId y, MergeReasonType type, TNode reason)
- : t1Id(x), t2Id(y), type(type), reason(reason)
+ : t1Id(x), t2Id(y), type(type), reason(reason)
{}
};
@@ -112,9 +119,9 @@ struct DisequalityReasonRef {
: mergesStart(mergesStart), mergesEnd(mergesEnd) {}
};
-/**
+/**
* We maintain uselist where a node appears in, and this is the node
- * of such a list.
+ * of such a list.
*/
class UseListNode {
@@ -150,12 +157,12 @@ public:
};
/**
- * Main class for representing nodes in the equivalence class. The
+ * Main class for representing nodes in the equivalence class. The
* nodes are a circular list, with the representative carrying the
* size. Each individual node carries with itself the uselist of
- * function applications it appears in and the list of asserted
+ * function applications it appears in and the list of asserted
* disequalities it belongs to. In order to get these lists one must
- * traverse the entire class and pick up all the individual lists.
+ * traverse the entire class and pick up all the individual lists.
*/
class EqualityNode {
@@ -180,7 +187,7 @@ public:
*/
EqualityNode(EqualityNodeId nodeId = null_id)
: d_size(1)
- , d_findId(nodeId)
+ , d_findId(nodeId)
, d_nextId(nodeId)
, d_useList(null_uselist_id)
{}
@@ -232,7 +239,7 @@ public:
/**
* Note that this node is used in a function application funId, or
- * a negatively asserted equality (dis-equality) with funId.
+ * a negatively asserted equality (dis-equality) with funId.
*/
template<typename memory_class>
void usedIn(EqualityNodeId funId, memory_class& memory) {
@@ -275,8 +282,8 @@ enum FunctionApplicationType {
/**
* Represents the function APPLY a b. If isEquality is true then it
- * represents the predicate (a = b). Note that since one can not
- * construct the equality over function terms, the equality and hash
+ * represents the predicate (a = b). Note that since one can not
+ * construct the equality over function terms, the equality and hash
* function below are still well defined.
*/
struct FunctionApplication {
diff --git a/src/theory/uf/options b/src/theory/uf/options
index cfa6e6c04..26f87da79 100644
--- a/src/theory/uf/options
+++ b/src/theory/uf/options
@@ -15,20 +15,14 @@ option ufssRegions /--disable-uf-ss-regions bool :default true
disable region-based method for discovering cliques and splits in uf strong solver
option ufssEagerSplits --uf-ss-eager-split bool :default false
add splits eagerly for uf strong solver
-option ufssColoringSat --uf-ss-coloring-sat bool :default false
- use coloring-based SAT heuristic for uf strong solver
option ufssTotality --uf-ss-totality bool :default false
always use totality axioms for enforcing cardinality constraints
option ufssTotalityLimited --uf-ss-totality-limited=N int :default -1
apply totality axioms, but only up to cardinality N (-1 == do not apply totality axioms, default)
-option ufssTotalityLazy --uf-ss-totality-lazy bool :default false
- apply totality axioms lazily
option ufssTotalitySymBreak --uf-ss-totality-sym-break bool :default false
apply symmetry breaking for totality axioms
option ufssAbortCardinality --uf-ss-abort-card=N int :default -1
tells the uf strong solver a cardinality to abort at (-1 == no limit, default)
-option ufssSmartSplits --uf-ss-smart-split bool :default false
- use smart splitting heuristic for uf strong solver
option ufssExplainedCliques --uf-ss-explained-cliques bool :default false
use explained clique lemmas for uf strong solver
option ufssSimpleCliques --uf-ss-simple-cliques bool :default true
diff --git a/src/theory/uf/theory_uf.cpp b/src/theory/uf/theory_uf.cpp
index 1045c5a24..fd46ed7f4 100644
--- a/src/theory/uf/theory_uf.cpp
+++ b/src/theory/uf/theory_uf.cpp
@@ -178,10 +178,16 @@ void TheoryUF::explain(TNode literal, std::vector<TNode>& assumptions) {
// Do the work
bool polarity = literal.getKind() != kind::NOT;
TNode atom = polarity ? literal : literal[0];
+ eq::EqProof * eqp = d_proofEnabled ? new eq::EqProof : NULL;
if (atom.getKind() == kind::EQUAL || atom.getKind() == kind::IFF) {
- d_equalityEngine.explainEquality(atom[0], atom[1], polarity, assumptions);
+ d_equalityEngine.explainEquality(atom[0], atom[1], polarity, assumptions, eqp);
} else {
- d_equalityEngine.explainPredicate(atom, polarity, assumptions);
+ d_equalityEngine.explainPredicate(atom, polarity, assumptions, eqp);
+ }
+ //for now, just print debug
+ //TODO : send the proof outwards : d_out->conflict( lem, eqp );
+ if( eqp ){
+ eqp->debug_print("uf-pf");
}
}
@@ -462,6 +468,7 @@ void TheoryUF::computeCareGraph() {
}/* TheoryUF::computeCareGraph() */
void TheoryUF::conflict(TNode a, TNode b) {
+ //TODO: create EqProof at this level if d_proofEnabled = true
if (a.getKind() == kind::CONST_BOOLEAN) {
d_conflictNode = explain(a.iffNode(b));
} else {
diff --git a/src/theory/uf/theory_uf_model.cpp b/src/theory/uf/theory_uf_model.cpp
index 409b41e3f..3b59c1c58 100644
--- a/src/theory/uf/theory_uf_model.cpp
+++ b/src/theory/uf/theory_uf_model.cpp
@@ -346,23 +346,21 @@ void UfModelTreeGenerator::setValue( TheoryModel* m, Node n, Node v, bool ground
d_set_values[ isReq ? 1 : 0 ][ ground ? 1 : 0 ][n] = v;
if( optUsePartialDefaults() ){
if( !ground ){
- if (!options::fmfFullModelCheck()) {
- int defSize = (int)d_defaults.size();
- for( int i=0; i<defSize; i++ ){
- //for soundness, to allow variable order-independent function interpretations,
- // we must ensure that the intersection of all default terms
- // is also defined.
- //for example, if we have that f( e, a ) = ..., and f( b, e ) = ...,
- // then we must define f( b, a ).
- bool isGround;
- Node ni = getIntersection( m, n, d_defaults[i], isGround );
- if( !ni.isNull() ){
- //if the intersection exists, and is not already defined
- if( d_set_values[0][ isGround ? 1 : 0 ].find( ni )==d_set_values[0][ isGround ? 1 : 0 ].end() &&
- d_set_values[1][ isGround ? 1 : 0 ].find( ni )==d_set_values[1][ isGround ? 1 : 0 ].end() ){
- //use the current value
- setValue( m, ni, v, isGround, false );
- }
+ int defSize = (int)d_defaults.size();
+ for( int i=0; i<defSize; i++ ){
+ //for soundness, to allow variable order-independent function interpretations,
+ // we must ensure that the intersection of all default terms
+ // is also defined.
+ //for example, if we have that f( e, a ) = ..., and f( b, e ) = ...,
+ // then we must define f( b, a ).
+ bool isGround;
+ Node ni = getIntersection( m, n, d_defaults[i], isGround );
+ if( !ni.isNull() ){
+ //if the intersection exists, and is not already defined
+ if( d_set_values[0][ isGround ? 1 : 0 ].find( ni )==d_set_values[0][ isGround ? 1 : 0 ].end() &&
+ d_set_values[1][ isGround ? 1 : 0 ].find( ni )==d_set_values[1][ isGround ? 1 : 0 ].end() ){
+ //use the current value
+ setValue( m, ni, v, isGround, false );
}
}
}
diff --git a/src/theory/uf/theory_uf_strong_solver.cpp b/src/theory/uf/theory_uf_strong_solver.cpp
index 052b2f568..54a3075a1 100644
--- a/src/theory/uf/theory_uf_strong_solver.cpp
+++ b/src/theory/uf/theory_uf_strong_solver.cpp
@@ -428,12 +428,10 @@ void StrongSolverTheoryUF::SortModel::initialize( OutputChannel* out ){
void StrongSolverTheoryUF::SortModel::newEqClass( Node n ){
if( !d_conflict ){
if( d_regions_map.find( n )==d_regions_map.end() ){
- if( !options::ufssTotalityLazy() ){
- //must generate totality axioms for every cardinality we have allocated thus far
- for( std::map< int, Node >::iterator it = d_cardinality_literal.begin(); it != d_cardinality_literal.end(); ++it ){
- if( applyTotality( it->first ) ){
- addTotalityAxiom( n, it->first, &d_thss->getOutputChannel() );
- }
+ //must generate totality axioms for every cardinality we have allocated thus far
+ for( std::map< int, Node >::iterator it = d_cardinality_literal.begin(); it != d_cardinality_literal.end(); ++it ){
+ if( applyTotality( it->first ) ){
+ addTotalityAxiom( n, it->first, &d_thss->getOutputChannel() );
}
}
if( options::ufssTotality() ){
@@ -449,9 +447,6 @@ void StrongSolverTheoryUF::SortModel::newEqClass( Node n ){
d_regions_index = 0;
}
d_regions_map[n] = d_regions_index;
- if( options::ufssSmartSplits() ){
- setSplitScore( n, 0 );
- }
Debug("uf-ss") << "StrongSolverTheoryUF: New Eq Class " << n << std::endl;
Debug("uf-ss-debug") << d_regions_index << " " << (int)d_regions.size() << std::endl;
if( d_regions_index<d_regions.size() ){
@@ -634,18 +629,7 @@ void StrongSolverTheoryUF::SortModel::check( Theory::Effort level, OutputChannel
}
}
}
- if( applyTotality( d_cardinality ) ){
- //add totality axioms for all nodes that have not yet been equated to cardinality terms
- if( options::ufssTotalityLazy() ){ //this should always be true
- if( level==Theory::EFFORT_FULL ){
- for( NodeIntMap::iterator it = d_regions_map.begin(); it != d_regions_map.end(); ++it ){
- if( !options::ufssTotality() || d_regions_map[ (*it).first ]!=-1 ){
- addTotalityAxiom( (*it).first, d_cardinality, &d_thss->getOutputChannel() );
- }
- }
- }
- }
- }else{
+ if( !applyTotality( d_cardinality ) ){
//do splitting on demand
bool addedLemma = false;
if( level==Theory::EFFORT_FULL || options::ufssEagerSplits() ){
@@ -1073,7 +1057,7 @@ void StrongSolverTheoryUF::SortModel::allocateCardinality( OutputChannel* out ){
//out->propagateAsDecision( lem[0] );
d_thss->d_statistics.d_max_model_size.maxAssign( d_aloc_cardinality );
- if( applyTotality( d_aloc_cardinality ) && !options::ufssTotalityLazy() ){
+ if( applyTotality( d_aloc_cardinality ) ){
//must send totality axioms for each existing term
for( NodeIntMap::iterator it = d_regions_map.begin(); it != d_regions_map.end(); ++it ){
addTotalityAxiom( (*it).first, d_aloc_cardinality, &d_thss->getOutputChannel() );
@@ -1085,27 +1069,11 @@ void StrongSolverTheoryUF::SortModel::allocateCardinality( OutputChannel* out ){
int StrongSolverTheoryUF::SortModel::addSplit( Region* r, OutputChannel* out ){
Node s;
if( r->hasSplits() ){
- if( !options::ufssSmartSplits() ){
- //take the first split you find
- for( NodeBoolMap::iterator it = r->d_splits.begin(); it != r->d_splits.end(); ++it ){
- if( (*it).second ){
- s = (*it).first;
- break;
- }
- }
- }else{
- int maxScore = -1;
- std::vector< Node > splits;
- for( NodeBoolMap::iterator it = r->d_splits.begin(); it != r->d_splits.end(); ++it ){
- if( (*it).second ){
- int score1 = d_split_score[ (*it).first[0] ];
- int score2 = d_split_score[ (*it).first[1] ];
- int score = score1<score2 ? score1 : score2;
- if( score>maxScore ){
- maxScore = -1;
- s = (*it).first;
- }
- }
+ //take the first split you find
+ for( NodeBoolMap::iterator it = r->d_splits.begin(); it != r->d_splits.end(); ++it ){
+ if( (*it).second ){
+ s = (*it).first;
+ break;
}
}
Assert( s!=Node::null() );
@@ -1338,6 +1306,21 @@ void StrongSolverTheoryUF::SortModel::addTotalityAxiom( Node n, int cardinality,
d_sym_break_terms[n.getType()][sort_id].push_back( n );
d_sym_break_index[n] = use_cardinality;
Trace("uf-ss-totality") << "Allocate symmetry breaking term " << n << ", index = " << use_cardinality << std::endl;
+ if( d_sym_break_terms[n.getType()][sort_id].size()>1 ){
+ //enforce canonicity
+ for( int i=2; i<use_cardinality; i++ ){
+ //can only be assigned to domain constant d if someone has been assigned domain constant d-1
+ Node eq = n.eqNode( getTotalityLemmaTerm( cardinality, i ) );
+ std::vector< Node > eqs;
+ for( unsigned j=0; j<(d_sym_break_terms[n.getType()][sort_id].size()-1); j++ ){
+ eqs.push_back( d_sym_break_terms[n.getType()][sort_id][j].eqNode( getTotalityLemmaTerm( cardinality, i-1 ) ) );
+ }
+ Node ax = NodeManager::currentNM()->mkNode( OR, eqs );
+ Node lem = NodeManager::currentNM()->mkNode( IMPLIES, eq, ax );
+ Trace("uf-ss-lemma") << "*** Add (canonicity) totality axiom " << lem << std::endl;
+ d_thss->getOutputChannel().lemma( lem );
+ }
+ }
}
}
@@ -1459,11 +1442,6 @@ Node StrongSolverTheoryUF::SortModel::getCardinalityLiteral( int c ) {
StrongSolverTheoryUF::StrongSolverTheoryUF(context::Context* c, context::UserContext* u, OutputChannel& out, TheoryUF* th) :
d_out( &out ), d_th( th ), d_conflict( c, false ), d_rep_model(), d_aloc_com_card( u, 0 ), d_com_card_assertions( c )
{
- if( options::ufssColoringSat() ){
- d_term_amb = new TermDisambiguator( th->getQuantifiersEngine(), c );
- }else{
- d_term_amb = NULL;
- }
if( options::ufssDiseqPropagation() ){
d_deq_prop = new DisequalityPropagator( th->getQuantifiersEngine(), this );
}else{
@@ -1499,6 +1477,7 @@ void StrongSolverTheoryUF::newEqClass( Node n ){
if( options::ufssSymBreak() ){
d_sym_break->newEqClass( n );
}
+ Trace("uf-ss-solver") << "StrongSolverTheoryUF: Done New eq class." << std::endl;
}
}
@@ -1508,6 +1487,7 @@ void StrongSolverTheoryUF::merge( Node a, Node b ){
if( c ){
Trace("uf-ss-solver") << "StrongSolverTheoryUF: Merge " << a << " " << b << " : " << a.getType() << std::endl;
c->merge( a, b );
+ Trace("uf-ss-solver") << "StrongSolverTheoryUF: Done Merge." << std::endl;
}else{
if( options::ufssDiseqPropagation() ){
d_deq_prop->merge(a, b);
@@ -1523,6 +1503,7 @@ void StrongSolverTheoryUF::assertDisequal( Node a, Node b, Node reason ){
//Assert( d_th->d_equalityEngine.getRepresentative( a )==a );
//Assert( d_th->d_equalityEngine.getRepresentative( b )==b );
c->assertDisequal( a, b, reason );
+ Trace("uf-ss-solver") << "StrongSolverTheoryUF: Done Assert disequal." << std::endl;
}else{
if( options::ufssDiseqPropagation() ){
d_deq_prop->assertDisequal(a, b, reason);
@@ -1610,13 +1591,6 @@ void StrongSolverTheoryUF::check( Theory::Effort level ){
if( level==Theory::EFFORT_FULL ){
debugPrint( "uf-ss-debug" );
}
- if( !d_conflict && level==Theory::EFFORT_FULL && options::ufssColoringSat() ){
- int lemmas = d_term_amb->disambiguateTerms( d_out );
- d_statistics.d_disamb_term_lemmas += lemmas;
- if( lemmas>=0 ){
- return;
- }
- }
for( std::map< TypeNode, SortModel* >::iterator it = d_rep_model.begin(); it != d_rep_model.end(); ++it ){
it->second->check( level, d_out );
if( it->second->isConflict() ){
@@ -1628,11 +1602,6 @@ void StrongSolverTheoryUF::check( Theory::Effort level ){
if( !d_conflict && options::ufssSymBreak() ){
d_sym_break->check( level );
}
- //disambiguate terms if necessary
- //if( !d_conflict && level==Theory::EFFORT_FULL && options::ufssColoringSat() ){
- // Assert( d_term_amb!=NULL );
- // d_statistics.d_disamb_term_lemmas += d_term_amb->disambiguateTerms( d_out );
- //}
Trace("uf-ss-solver") << "Done StrongSolverTheoryUF: check " << level << std::endl;
}
}
@@ -1900,76 +1869,6 @@ StrongSolverTheoryUF::Statistics::~Statistics(){
}
-int TermDisambiguator::disambiguateTerms( OutputChannel* out ){
- Debug("uf-ss-disamb") << "Disambiguate terms." << std::endl;
- int lemmaAdded = 0;
- //otherwise, determine ambiguous pairs of ground terms for relevant sorts
- quantifiers::TermDb* db = d_qe->getTermDatabase();
- for( std::map< Node, std::vector< Node > >::iterator it = db->d_op_map.begin(); it != db->d_op_map.end(); ++it ){
- Debug("uf-ss-disamb") << "Check " << it->first << std::endl;
- if( it->second.size()>1 ){
- if(involvesRelevantType( it->second[0] ) ){
- for( int i=0; i<(int)it->second.size(); i++ ){
- for( int j=(i+1); j<(int)it->second.size(); j++ ){
- Kind knd = it->second[i].getType()==NodeManager::currentNM()->booleanType() ? IFF : EQUAL;
- Node eq = NodeManager::currentNM()->mkNode( knd, it->second[i], it->second[j] );
- eq = Rewriter::rewrite(eq);
- //determine if they are ambiguous
- if( d_term_amb.find( eq )==d_term_amb.end() ){
- Debug("uf-ss-disamb") << "Check disambiguate " << it->second[i] << " " << it->second[j] << std::endl;
- d_term_amb[ eq ] = true;
- //if they are equal
- if( d_qe->getEqualityQuery()->areEqual( it->second[i], it->second[j] ) ){
- d_term_amb[ eq ] = false;
- }else{
- //if an argument is disequal, then they are not ambiguous
- for( int k=0; k<(int)it->second[i].getNumChildren(); k++ ){
- if( d_qe->getEqualityQuery()->areDisequal( it->second[i][k], it->second[j][k] ) ){
- d_term_amb[ eq ] = false;
- break;
- }
- }
- }
- if( d_term_amb[ eq ] ){
- Debug("uf-ss-disamb") << "Disambiguate " << it->second[i] << " " << it->second[j] << std::endl;
- //must add lemma
- std::vector< Node > children;
- children.push_back( eq );
- for( int k=0; k<(int)it->second[i].getNumChildren(); k++ ){
- Kind knd2 = it->second[i][k].getType()==NodeManager::currentNM()->booleanType() ? IFF : EQUAL;
- Node eqc = NodeManager::currentNM()->mkNode( knd2, it->second[i][k], it->second[j][k] );
- children.push_back( eqc.notNode() );
- }
- Assert( children.size()>1 );
- Node lem = NodeManager::currentNM()->mkNode( OR, children );
- Trace( "uf-ss-lemma" ) << "*** Disambiguate lemma : " << lem << std::endl;
- //Notice() << "*** Disambiguate lemma : " << lem << std::endl;
- out->lemma( lem );
- d_term_amb[ eq ] = false;
- lemmaAdded++;
- return lemmaAdded;
- }
- }
- }
- }
- }
- }
- }
- Debug("uf-ss-disamb") << "Done disambiguate terms. " << lemmaAdded << std::endl;
- return lemmaAdded;
-}
-
-bool TermDisambiguator::involvesRelevantType( Node n ){
- if( n.getKind()==APPLY_UF ){
- for( int i=0; i<(int)n.getNumChildren(); i++ ){
- if( n[i].getType().isSort() ){
- return true;
- }
- }
- }
- return false;
-}
-
DisequalityPropagator::DisequalityPropagator(QuantifiersEngine* qe, StrongSolverTheoryUF* ufss) :
d_qe(qe), d_ufss(ufss){
d_true = NodeManager::currentNM()->mkConst( true );
diff --git a/src/theory/uf/theory_uf_strong_solver.h b/src/theory/uf/theory_uf_strong_solver.h
index 4f41ebf2e..3ed1ea985 100644
--- a/src/theory/uf/theory_uf_strong_solver.h
+++ b/src/theory/uf/theory_uf_strong_solver.h
@@ -37,7 +37,6 @@ class SubsortSymmetryBreaker;
namespace uf {
class TheoryUF;
-class TermDisambiguator;
class DisequalityPropagator;
class StrongSolverTheoryUF{
@@ -320,8 +319,6 @@ private:
/** check */
void checkCombinedCardinality();
private:
- /** term disambiguator */
- TermDisambiguator* d_term_amb;
/** disequality propagator */
DisequalityPropagator* d_deq_prop;
/** symmetry breaking techniques */
@@ -331,8 +328,6 @@ public:
~StrongSolverTheoryUF() {}
/** get theory */
TheoryUF* getTheory() { return d_th; }
- /** term disambiguator */
- TermDisambiguator* getTermDisambiguator() { return d_term_amb; }
/** disequality propagator */
DisequalityPropagator* getDisequalityPropagator() { return d_deq_prop; }
/** symmetry breaker */
@@ -401,23 +396,6 @@ public:
Statistics d_statistics;
};/* class StrongSolverTheoryUF */
-
-class TermDisambiguator
-{
-private:
- /** quantifiers engine */
- QuantifiersEngine* d_qe;
- /** whether two terms are ambiguous (indexed by equalities) */
- context::CDHashMap<Node, bool, NodeHashFunction> d_term_amb;
- /** involves relevant type */
- static bool involvesRelevantType( Node n );
-public:
- TermDisambiguator( QuantifiersEngine* qe, context::Context* c ) : d_qe( qe ), d_term_amb( c ){}
- ~TermDisambiguator(){}
- /** check ambiguous terms */
- int disambiguateTerms( OutputChannel* out );
-};
-
class DisequalityPropagator
{
private:
diff --git a/src/util/Makefile.am b/src/util/Makefile.am
index 2f278625a..1d6ce1a73 100644
--- a/src/util/Makefile.am
+++ b/src/util/Makefile.am
@@ -144,7 +144,8 @@ EXTRA_DIST = \
predicate.i \
uninterpreted_constant.i \
chain.i \
- regexp.i
+ regexp.i \
+ proof.i
DISTCLEANFILES = \
integer.h.tmp \
diff --git a/src/util/datatype.cpp b/src/util/datatype.cpp
index 5fa893336..8d70e4ffc 100644
--- a/src/util/datatype.cpp
+++ b/src/util/datatype.cpp
@@ -102,7 +102,7 @@ void Datatype::resolve(ExprManager* em,
CheckArgument(&self.getDatatype() == this, resolutions, "Datatype::resolve(): resolutions doesn't contain me!");
d_resolved = true;
size_t index = 0;
- for(iterator i = begin(), i_end = end(); i != i_end; ++i) {
+ for(std::vector<DatatypeConstructor>::iterator i = d_constructors.begin(), i_end = d_constructors.end(); i != i_end; ++i) {
(*i).resolve(em, self, resolutions, placeholders, replacements, paramTypes, paramReplacements);
Node::fromExpr((*i).d_constructor).setAttribute(DatatypeIndexAttr(), index);
Node::fromExpr((*i).d_tester).setAttribute(DatatypeIndexAttr(), index++);
@@ -416,7 +416,7 @@ void DatatypeConstructor::resolve(ExprManager* em, DatatypeType self,
NodeManager* nm = NodeManager::fromExprManager(em);
TypeNode selfTypeNode = TypeNode::fromType(self);
size_t index = 0;
- for(iterator i = begin(), i_end = end(); i != i_end; ++i) {
+ for(std::vector<DatatypeConstructorArg>::iterator i = d_args.begin(), i_end = d_args.end(); i != i_end; ++i) {
if((*i).d_selector.isNull()) {
// the unresolved type wasn't created here; do name resolution
string typeName = (*i).d_name.substr((*i).d_name.find('\0') + 1);
@@ -461,7 +461,7 @@ void DatatypeConstructor::resolve(ExprManager* em, DatatypeType self,
d_tester = nm->mkSkolem(getTesterName(), nm->mkTesterType(selfTypeNode), "is a tester", NodeManager::SKOLEM_EXACT_NAME | NodeManager::SKOLEM_NO_NOTIFY).toExpr();
d_constructor = nm->mkSkolem(getName(), nm->mkConstructorType(*this, selfTypeNode), "is a constructor", NodeManager::SKOLEM_EXACT_NAME | NodeManager::SKOLEM_NO_NOTIFY).toExpr();
// associate constructor with all selectors
- for(iterator i = begin(), i_end = end(); i != i_end; ++i) {
+ for(std::vector<DatatypeConstructorArg>::iterator i = d_args.begin(), i_end = d_args.end(); i != i_end; ++i) {
(*i).d_constructor = d_constructor;
}
}
diff --git a/src/util/datatype.h b/src/util/datatype.h
index 802704803..99a303950 100644
--- a/src/util/datatype.h
+++ b/src/util/datatype.h
@@ -40,6 +40,47 @@ namespace CVC4 {
class CVC4_PUBLIC ExprManager;
+class CVC4_PUBLIC DatatypeConstructor;
+class CVC4_PUBLIC DatatypeConstructorArg;
+
+class CVC4_PUBLIC DatatypeConstructorIterator {
+ const std::vector<DatatypeConstructor>* d_v;
+ size_t d_i;
+
+ friend class Datatype;
+
+ DatatypeConstructorIterator(const std::vector<DatatypeConstructor>& v, bool start) : d_v(&v), d_i(start ? 0 : v.size()) {
+ }
+
+public:
+ typedef const DatatypeConstructor& value_type;
+ const DatatypeConstructor& operator*() const { return (*d_v)[d_i]; }
+ const DatatypeConstructor* operator->() const { return &(*d_v)[d_i]; }
+ DatatypeConstructorIterator& operator++() { ++d_i; return *this; }
+ DatatypeConstructorIterator operator++(int) { DatatypeConstructorIterator i(*this); ++d_i; return i; }
+ bool operator==(const DatatypeConstructorIterator& other) const { return d_v == other.d_v && d_i == other.d_i; }
+ bool operator!=(const DatatypeConstructorIterator& other) const { return d_v != other.d_v || d_i != other.d_i; }
+};/* class DatatypeConstructorIterator */
+
+class CVC4_PUBLIC DatatypeConstructorArgIterator {
+ const std::vector<DatatypeConstructorArg>* d_v;
+ size_t d_i;
+
+ friend class DatatypeConstructor;
+
+ DatatypeConstructorArgIterator(const std::vector<DatatypeConstructorArg>& v, bool start) : d_v(&v), d_i(start ? 0 : v.size()) {
+ }
+
+public:
+ typedef const DatatypeConstructorArg& value_type;
+ const DatatypeConstructorArg& operator*() const { return (*d_v)[d_i]; }
+ const DatatypeConstructorArg* operator->() const { return &(*d_v)[d_i]; }
+ DatatypeConstructorArgIterator& operator++() { ++d_i; return *this; }
+ DatatypeConstructorArgIterator operator++(int) { DatatypeConstructorArgIterator i(*this); ++d_i; return i; }
+ bool operator==(const DatatypeConstructorArgIterator& other) const { return d_v == other.d_v && d_i == other.d_i; }
+ bool operator!=(const DatatypeConstructorArgIterator& other) const { return d_v != other.d_v || d_i != other.d_i; }
+};/* class DatatypeConstructorArgIterator */
+
/**
* An exception that is thrown when a datatype resolution fails.
*/
@@ -134,9 +175,9 @@ class CVC4_PUBLIC DatatypeConstructor {
public:
/** The type for iterators over constructor arguments. */
- typedef std::vector<DatatypeConstructorArg>::iterator iterator;
+ typedef DatatypeConstructorArgIterator iterator;
/** The (const) type for iterators over constructor arguments. */
- typedef std::vector<DatatypeConstructorArg>::const_iterator const_iterator;
+ typedef DatatypeConstructorArgIterator const_iterator;
private:
@@ -394,9 +435,9 @@ public:
static size_t indexOf(Expr item) CVC4_PUBLIC;
/** The type for iterators over constructors. */
- typedef std::vector<DatatypeConstructor>::iterator iterator;
+ typedef DatatypeConstructorIterator iterator;
/** The (const) type for iterators over constructors. */
- typedef std::vector<DatatypeConstructor>::const_iterator const_iterator;
+ typedef DatatypeConstructorIterator const_iterator;
private:
std::string d_name;
@@ -540,13 +581,13 @@ public:
inline bool isResolved() const throw();
/** Get the beginning iterator over DatatypeConstructors. */
- inline std::vector<DatatypeConstructor>::iterator begin() throw();
+ inline iterator begin() throw();
/** Get the ending iterator over DatatypeConstructors. */
- inline std::vector<DatatypeConstructor>::iterator end() throw();
+ inline iterator end() throw();
/** Get the beginning const_iterator over DatatypeConstructors. */
- inline std::vector<DatatypeConstructor>::const_iterator begin() const throw();
+ inline const_iterator begin() const throw();
/** Get the ending const_iterator over DatatypeConstructors. */
- inline std::vector<DatatypeConstructor>::const_iterator end() const throw();
+ inline const_iterator end() const throw();
/** Get the ith DatatypeConstructor. */
const DatatypeConstructor& operator[](size_t index) const;
@@ -669,19 +710,19 @@ inline bool Datatype::isResolved() const throw() {
}
inline Datatype::iterator Datatype::begin() throw() {
- return d_constructors.begin();
+ return iterator(d_constructors, true);
}
inline Datatype::iterator Datatype::end() throw() {
- return d_constructors.end();
+ return iterator(d_constructors, false);
}
inline Datatype::const_iterator Datatype::begin() const throw() {
- return d_constructors.begin();
+ return const_iterator(d_constructors, true);
}
inline Datatype::const_iterator Datatype::end() const throw() {
- return d_constructors.end();
+ return const_iterator(d_constructors, false);
}
inline bool DatatypeConstructor::isResolved() const throw() {
@@ -710,19 +751,19 @@ inline bool DatatypeConstructorArg::isResolved() const throw() {
}
inline DatatypeConstructor::iterator DatatypeConstructor::begin() throw() {
- return d_args.begin();
+ return iterator(d_args, true);
}
inline DatatypeConstructor::iterator DatatypeConstructor::end() throw() {
- return d_args.end();
+ return iterator(d_args, false);
}
inline DatatypeConstructor::const_iterator DatatypeConstructor::begin() const throw() {
- return d_args.begin();
+ return const_iterator(d_args, true);
}
inline DatatypeConstructor::const_iterator DatatypeConstructor::end() const throw() {
- return d_args.end();
+ return const_iterator(d_args, false);
}
}/* CVC4 namespace */
diff --git a/src/util/datatype.i b/src/util/datatype.i
index c07caa805..403fb31bc 100644
--- a/src/util/datatype.i
+++ b/src/util/datatype.i
@@ -1,5 +1,12 @@
%{
#include "util/datatype.h"
+
+#ifdef SWIGJAVA
+
+#include "bindings/java_iterator_adapter.h"
+#include "bindings/java_stream_adapters.h"
+
+#endif /* SWIGJAVA */
%}
%extend std::vector< CVC4::Datatype > {
@@ -32,34 +39,137 @@
%ignore set(int i, const CVC4::Datatype::Constructor& x);
%ignore to_array();
};
-%template(vectorDatatypeConstructor) std::vector< CVC4::DatatypeConstructor >;
+//%template(vectorDatatypeConstructor) std::vector< CVC4::DatatypeConstructor >;
%rename(equals) CVC4::Datatype::operator==(const Datatype&) const;
%ignore CVC4::Datatype::operator!=(const Datatype&) const;
-%rename(beginConst) CVC4::Datatype::begin() const;
-%rename(endConst) CVC4::Datatype::end() const;
+%ignore CVC4::Datatype::begin();
+%ignore CVC4::Datatype::end();
+%ignore CVC4::Datatype::begin() const;
+%ignore CVC4::Datatype::end() const;
-%rename(getConstructor) CVC4::Datatype::operator[](size_t) const;
-%ignore CVC4::Datatype::operator[](std::string) const;
+%rename(get) CVC4::Datatype::operator[](size_t) const;
+%rename(get) CVC4::Datatype::operator[](std::string) const;
%rename(apply) CVC4::DatatypeHashFunction::operator()(const Datatype&) const;
%ignore CVC4::DatatypeHashFunction::operator()(const Datatype*) const;
%rename(apply) CVC4::DatatypeHashFunction::operator()(const DatatypeConstructor&) const;
%ignore CVC4::DatatypeHashFunction::operator()(const DatatypeConstructor*) const;
-%rename(beginConst) CVC4::DatatypeConstructor::begin() const;
-%rename(endConst) CVC4::DatatypeConstructor::end() const;
+%ignore CVC4::DatatypeConstructor::begin();
+%ignore CVC4::DatatypeConstructor::end();
+%ignore CVC4::DatatypeConstructor::begin() const;
+%ignore CVC4::DatatypeConstructor::end() const;
-%rename(getArg) CVC4::DatatypeConstructor::operator[](size_t) const;
-%rename(getArg) CVC4::DatatypeConstructor::operator[](std::string) const;
+%rename(get) CVC4::DatatypeConstructor::operator[](size_t) const;
+%rename(get) CVC4::DatatypeConstructor::operator[](std::string) const;
%ignore CVC4::operator<<(std::ostream&, const Datatype&);
%ignore CVC4::operator<<(std::ostream&, const DatatypeConstructor&);
%ignore CVC4::operator<<(std::ostream&, const DatatypeConstructorArg&);
+%ignore CVC4::DatatypeConstructorIterator;
+%ignore CVC4::DatatypeConstructorArgIterator;
+
%feature("valuewrapper") CVC4::DatatypeUnresolvedType;
%feature("valuewrapper") CVC4::DatatypeConstructor;
+#ifdef SWIGJAVA
+
+// Instead of Datatype::begin() and end(), create an
+// iterator() method on the Java side that returns a Java-style
+// Iterator.
+%extend CVC4::Datatype {
+ CVC4::JavaIteratorAdapter<CVC4::Datatype> iterator() {
+ return CVC4::JavaIteratorAdapter<CVC4::Datatype>(*$self);
+ }
+
+ std::string toString() const {
+ std::stringstream ss;
+ ss << *$self;
+ return ss.str();
+ }
+}
+%extend CVC4::DatatypeConstructor {
+ CVC4::JavaIteratorAdapter<CVC4::DatatypeConstructor> iterator() {
+ return CVC4::JavaIteratorAdapter<CVC4::DatatypeConstructor>(*$self);
+ }
+
+ std::string toString() const {
+ std::stringstream ss;
+ ss << *$self;
+ return ss.str();
+ }
+}
+%extend CVC4::DatatypeConstructorArg {
+ std::string toString() const {
+ std::stringstream ss;
+ ss << *$self;
+ return ss.str();
+ }
+}
+
+// Datatype is "iterable" on the Java side
+%typemap(javainterfaces) CVC4::Datatype "java.lang.Iterable<DatatypeConstructor>";
+%typemap(javainterfaces) CVC4::DatatypeConstructor "java.lang.Iterable<DatatypeConstructorArg>";
+
+// the JavaIteratorAdapter should not be public, and implements Iterator
+%typemap(javaclassmodifiers) CVC4::JavaIteratorAdapter<CVC4::Datatype> "class";
+%typemap(javaclassmodifiers) CVC4::JavaIteratorAdapter<CVC4::DatatypeConstructor> "class";
+%typemap(javainterfaces) CVC4::JavaIteratorAdapter<CVC4::Datatype> "java.util.Iterator<DatatypeConstructor>";
+%typemap(javainterfaces) CVC4::JavaIteratorAdapter<CVC4::DatatypeConstructor> "java.util.Iterator<DatatypeConstructorArg>";
+// add some functions to the Java side (do it here because there's no way to do these in C++)
+%typemap(javacode) CVC4::JavaIteratorAdapter<CVC4::Datatype> "
+ public void remove() {
+ throw new java.lang.UnsupportedOperationException();
+ }
+
+ public DatatypeConstructor next() {
+ if(hasNext()) {
+ return getNext();
+ } else {
+ throw new java.util.NoSuchElementException();
+ }
+ }
+"
+%typemap(javacode) CVC4::JavaIteratorAdapter<CVC4::DatatypeConstructor> "
+ public void remove() {
+ throw new java.lang.UnsupportedOperationException();
+ }
+
+ public DatatypeConstructorArg next() {
+ if(hasNext()) {
+ return getNext();
+ } else {
+ throw new java.util.NoSuchElementException();
+ }
+ }
+"
+// getNext() just allows C++ iterator access from Java-side next(), make it private
+%javamethodmodifiers CVC4::JavaIteratorAdapter<CVC4::Datatype>::getNext() "private";
+%javamethodmodifiers CVC4::JavaIteratorAdapter<CVC4::DatatypeConstructor>::getNext() "private";
+
+// map the types appropriately.
+%typemap(jni) CVC4::Datatype::iterator::value_type "jobject";
+%typemap(jtype) CVC4::Datatype::iterator::value_type "edu.nyu.acsys.CVC4.DatatypeConstructor";
+%typemap(jstype) CVC4::Datatype::iterator::value_type "edu.nyu.acsys.CVC4.DatatypeConstructor";
+%typemap(javaout) CVC4::Datatype::iterator::value_type { return $jnicall; }
+%typemap(jni) CVC4::DatatypeConstructor::iterator::value_type "jobject";
+%typemap(jtype) CVC4::DatatypeConstructor::iterator::value_type "edu.nyu.acsys.CVC4.DatatypeConstructorArg";
+%typemap(jstype) CVC4::DatatypeConstructor::iterator::value_type "edu.nyu.acsys.CVC4.DatatypeConstructorArg";
+%typemap(javaout) CVC4::DatatypeConstructor::iterator::value_type { return $jnicall; }
+
+#endif /* SWIGJAVA */
+
%include "util/datatype.h"
+#ifdef SWIGJAVA
+
+%include "bindings/java_iterator_adapter.h"
+%include "bindings/java_stream_adapters.h"
+
+%template(JavaIteratorAdapter_Datatype) CVC4::JavaIteratorAdapter<CVC4::Datatype>;
+%template(JavaIteratorAdapter_DatatypeConstructor) CVC4::JavaIteratorAdapter<CVC4::DatatypeConstructor>;
+
+#endif /* SWIGJAVA */
diff --git a/src/util/proof.i b/src/util/proof.i
new file mode 100644
index 000000000..22dff1043
--- /dev/null
+++ b/src/util/proof.i
@@ -0,0 +1,5 @@
+%{
+#include "util/proof.h"
+%}
+
+%include "util/proof.h"
diff --git a/src/util/regexp.h b/src/util/regexp.h
index 3a8fc7170..3f9df6aaf 100644
--- a/src/util/regexp.h
+++ b/src/util/regexp.h
@@ -183,6 +183,25 @@ public:
return true;
}
+ std::size_t find(const String &y) const {
+ if(y.d_str.size() == 0) return 0;
+ if(d_str.size() == 0) return std::string::npos;
+ std::size_t ret = std::string::npos;
+ for(int i = 0; i <= (int) d_str.size() - (int) y.d_str.size(); i++) {
+ if(d_str[i] == y.d_str[0]) {
+ std::size_t j=0;
+ for(; j<y.d_str.size(); j++) {
+ if(d_str[i+j] != y.d_str[j]) break;
+ }
+ if(j == y.d_str.size()) {
+ ret = (std::size_t) i;
+ break;
+ }
+ }
+ }
+ return ret;
+ }
+
String substr(unsigned i) const {
std::vector<unsigned int> ret_vec;
std::vector<unsigned int>::const_iterator itr = d_str.begin() + i;
diff --git a/test/regress/regress0/Makefile.am b/test/regress/regress0/Makefile.am
index 5c591d39c..d7663e298 100644
--- a/test/regress/regress0/Makefile.am
+++ b/test/regress/regress0/Makefile.am
@@ -7,12 +7,12 @@ DIST_SUBDIRS = . arith precedence uf uflra uflia bv arrays aufbv auflia datatype
end@mk_if@
LOG_COMPILER = @srcdir@/../run_regression
-AM_LOG_FLAGS = $(RUN_REGRESSION_ARGS) @top_builddir@/src/main/$(BINARY)$(EXEEXT)
+AM_LOG_FLAGS = $(RUN_REGRESSION_ARGS) @abs_top_builddir@/src/main/$(BINARY)$(EXEEXT)
if AUTOMAKE_1_11
# old-style (pre-automake 1.12) test harness
TESTS_ENVIRONMENT = \
- $(TESTS_ENVIRONMENT) $(LOG_COMPILER) \
+ $(LOG_COMPILER) \
$(AM_LOG_FLAGS) $(LOG_FLAGS)
endif
diff --git a/test/regress/regress0/arith/Makefile.am b/test/regress/regress0/arith/Makefile.am
index 6897ee3c4..e7810c7c4 100644
--- a/test/regress/regress0/arith/Makefile.am
+++ b/test/regress/regress0/arith/Makefile.am
@@ -6,12 +6,12 @@ SUBDIRS = . integers
end@mk_if@
LOG_COMPILER = @srcdir@/../../run_regression
-AM_LOG_FLAGS = $(RUN_REGRESSION_ARGS) @top_builddir@/src/main/$(BINARY)$(EXEEXT)
+AM_LOG_FLAGS = $(RUN_REGRESSION_ARGS) @abs_top_builddir@/src/main/$(BINARY)$(EXEEXT)
if AUTOMAKE_1_11
# old-style (pre-automake 1.12) test harness
TESTS_ENVIRONMENT = \
- $(TESTS_ENVIRONMENT) $(LOG_COMPILER) \
+ $(LOG_COMPILER) \
$(AM_LOG_FLAGS) $(LOG_FLAGS)
endif
diff --git a/test/regress/regress0/arith/integers/Makefile.am b/test/regress/regress0/arith/integers/Makefile.am
index 3511c6b30..3b6a86bc0 100644
--- a/test/regress/regress0/arith/integers/Makefile.am
+++ b/test/regress/regress0/arith/integers/Makefile.am
@@ -6,12 +6,12 @@ SUBDIRS = .
end@mk_if@
LOG_COMPILER = @srcdir@/../../../run_regression
-AM_LOG_FLAGS = $(RUN_REGRESSION_ARGS) @top_builddir@/src/main/$(BINARY)$(EXEEXT)
+AM_LOG_FLAGS = $(RUN_REGRESSION_ARGS) @abs_top_builddir@/src/main/$(BINARY)$(EXEEXT)
if AUTOMAKE_1_11
# old-style (pre-automake 1.12) test harness
TESTS_ENVIRONMENT = \
- $(TESTS_ENVIRONMENT) $(LOG_COMPILER) \
+ $(LOG_COMPILER) \
$(AM_LOG_FLAGS) $(LOG_FLAGS)
endif
diff --git a/test/regress/regress0/arrays/Makefile.am b/test/regress/regress0/arrays/Makefile.am
index 33f05ab40..62877ddf3 100644
--- a/test/regress/regress0/arrays/Makefile.am
+++ b/test/regress/regress0/arrays/Makefile.am
@@ -4,12 +4,12 @@
end@mk_if@
LOG_COMPILER = @srcdir@/../../run_regression
-AM_LOG_FLAGS = $(RUN_REGRESSION_ARGS) @top_builddir@/src/main/$(BINARY)$(EXEEXT)
+AM_LOG_FLAGS = $(RUN_REGRESSION_ARGS) @abs_top_builddir@/src/main/$(BINARY)$(EXEEXT)
if AUTOMAKE_1_11
# old-style (pre-automake 1.12) test harness
TESTS_ENVIRONMENT = \
- $(TESTS_ENVIRONMENT) $(LOG_COMPILER) \
+ $(LOG_COMPILER) \
$(AM_LOG_FLAGS) $(LOG_FLAGS)
endif
diff --git a/test/regress/regress0/aufbv/Makefile.am b/test/regress/regress0/aufbv/Makefile.am
index e151a4846..e45358a8a 100644
--- a/test/regress/regress0/aufbv/Makefile.am
+++ b/test/regress/regress0/aufbv/Makefile.am
@@ -4,12 +4,12 @@
end@mk_if@
LOG_COMPILER = @srcdir@/../../run_regression
-AM_LOG_FLAGS = $(RUN_REGRESSION_ARGS) @top_builddir@/src/main/$(BINARY)$(EXEEXT)
+AM_LOG_FLAGS = $(RUN_REGRESSION_ARGS) @abs_top_builddir@/src/main/$(BINARY)$(EXEEXT)
if AUTOMAKE_1_11
# old-style (pre-automake 1.12) test harness
TESTS_ENVIRONMENT = \
- $(TESTS_ENVIRONMENT) $(LOG_COMPILER) \
+ $(LOG_COMPILER) \
$(AM_LOG_FLAGS) $(LOG_FLAGS)
endif
diff --git a/test/regress/regress0/auflia/Makefile.am b/test/regress/regress0/auflia/Makefile.am
index ca1fc25d3..31d9c0797 100644
--- a/test/regress/regress0/auflia/Makefile.am
+++ b/test/regress/regress0/auflia/Makefile.am
@@ -4,12 +4,12 @@
end@mk_if@
LOG_COMPILER = @srcdir@/../../run_regression
-AM_LOG_FLAGS = $(RUN_REGRESSION_ARGS) @top_builddir@/src/main/$(BINARY)$(EXEEXT)
+AM_LOG_FLAGS = $(RUN_REGRESSION_ARGS) @abs_top_builddir@/src/main/$(BINARY)$(EXEEXT)
if AUTOMAKE_1_11
# old-style (pre-automake 1.12) test harness
TESTS_ENVIRONMENT = \
- $(TESTS_ENVIRONMENT) $(LOG_COMPILER) \
+ $(LOG_COMPILER) \
$(AM_LOG_FLAGS) $(LOG_FLAGS)
endif
diff --git a/test/regress/regress0/boolean.cvc b/test/regress/regress0/boolean.cvc
index cba092e9e..eb0e7ab52 100644
--- a/test/regress/regress0/boolean.cvc
+++ b/test/regress/regress0/boolean.cvc
@@ -804,4 +804,3 @@ a288 : BOOLEAN =
ELSE FALSE
ENDIF;
QUERY a288;
-% PROOF
diff --git a/test/regress/regress0/bv/Makefile.am b/test/regress/regress0/bv/Makefile.am
index f0bfb2842..5d2a54b11 100644
--- a/test/regress/regress0/bv/Makefile.am
+++ b/test/regress/regress0/bv/Makefile.am
@@ -6,12 +6,12 @@ SUBDIRS = . core
end@mk_if@
LOG_COMPILER = @srcdir@/../../run_regression
-AM_LOG_FLAGS = $(RUN_REGRESSION_ARGS) @top_builddir@/src/main/$(BINARY)$(EXEEXT)
+AM_LOG_FLAGS = $(RUN_REGRESSION_ARGS) @abs_top_builddir@/src/main/$(BINARY)$(EXEEXT)
if AUTOMAKE_1_11
# old-style (pre-automake 1.12) test harness
TESTS_ENVIRONMENT = \
- $(TESTS_ENVIRONMENT) $(LOG_COMPILER) \
+ $(LOG_COMPILER) \
$(AM_LOG_FLAGS) $(LOG_FLAGS)
endif
diff --git a/test/regress/regress0/bv/core/Makefile.am b/test/regress/regress0/bv/core/Makefile.am
index 888e9d8dc..7c411121a 100644
--- a/test/regress/regress0/bv/core/Makefile.am
+++ b/test/regress/regress0/bv/core/Makefile.am
@@ -4,12 +4,12 @@
end@mk_if@
LOG_COMPILER = @srcdir@/../../../run_regression
-AM_LOG_FLAGS = $(RUN_REGRESSION_ARGS) @top_builddir@/src/main/$(BINARY)$(EXEEXT)
+AM_LOG_FLAGS = $(RUN_REGRESSION_ARGS) @abs_top_builddir@/src/main/$(BINARY)$(EXEEXT)
if AUTOMAKE_1_11
# old-style (pre-automake 1.12) test harness
TESTS_ENVIRONMENT = \
- $(TESTS_ENVIRONMENT) $(LOG_COMPILER) \
+ $(LOG_COMPILER) \
$(AM_LOG_FLAGS) $(LOG_FLAGS)
endif
diff --git a/test/regress/regress0/datatypes/Makefile.am b/test/regress/regress0/datatypes/Makefile.am
index 67b97add3..84adb4f84 100644
--- a/test/regress/regress0/datatypes/Makefile.am
+++ b/test/regress/regress0/datatypes/Makefile.am
@@ -6,12 +6,12 @@ SUBDIRS = .
end@mk_if@
LOG_COMPILER = @srcdir@/../../run_regression
-AM_LOG_FLAGS = $(RUN_REGRESSION_ARGS) @top_builddir@/src/main/$(BINARY)$(EXEEXT)
+AM_LOG_FLAGS = $(RUN_REGRESSION_ARGS) @abs_top_builddir@/src/main/$(BINARY)$(EXEEXT)
if AUTOMAKE_1_11
# old-style (pre-automake 1.12) test harness
TESTS_ENVIRONMENT = \
- $(TESTS_ENVIRONMENT) $(LOG_COMPILER) \
+ $(LOG_COMPILER) \
$(AM_LOG_FLAGS) $(LOG_FLAGS)
endif
diff --git a/test/regress/regress0/datatypes/empty_tuprec.cvc b/test/regress/regress0/datatypes/empty_tuprec.cvc
index 415da3c18..5fe17b412 100644
--- a/test/regress/regress0/datatypes/empty_tuprec.cvc
+++ b/test/regress/regress0/datatypes/empty_tuprec.cvc
@@ -1,3 +1,5 @@
+% COMMAND-LINE: --no-check-proofs
+%
OPTION "incremental";
a1, a2 : []; % empty tuples (a unit type)
diff --git a/test/regress/regress0/decision/Makefile.am b/test/regress/regress0/decision/Makefile.am
index 0f8ef8e8e..366204191 100644
--- a/test/regress/regress0/decision/Makefile.am
+++ b/test/regress/regress0/decision/Makefile.am
@@ -4,12 +4,12 @@
end@mk_if@
LOG_COMPILER = @srcdir@/../../run_regression
-AM_LOG_FLAGS = $(RUN_REGRESSION_ARGS) @top_builddir@/src/main/$(BINARY)$(EXEEXT)
+AM_LOG_FLAGS = $(RUN_REGRESSION_ARGS) @abs_top_builddir@/src/main/$(BINARY)$(EXEEXT)
if AUTOMAKE_1_11
# old-style (pre-automake 1.12) test harness
TESTS_ENVIRONMENT = \
- $(TESTS_ENVIRONMENT) $(LOG_COMPILER) \
+ $(LOG_COMPILER) \
$(AM_LOG_FLAGS) $(LOG_FLAGS)
endif
diff --git a/test/regress/regress0/fmf/Makefile.am b/test/regress/regress0/fmf/Makefile.am
index bfbc851ef..2633949c8 100644
--- a/test/regress/regress0/fmf/Makefile.am
+++ b/test/regress/regress0/fmf/Makefile.am
@@ -4,12 +4,12 @@
end@mk_if@
LOG_COMPILER = @srcdir@/../../run_regression
-AM_LOG_FLAGS = $(RUN_REGRESSION_ARGS) @top_builddir@/src/main/$(BINARY)$(EXEEXT)
+AM_LOG_FLAGS = $(RUN_REGRESSION_ARGS) @abs_top_builddir@/src/main/$(BINARY)$(EXEEXT)
if AUTOMAKE_1_11
# old-style (pre-automake 1.12) test harness
TESTS_ENVIRONMENT = \
- $(TESTS_ENVIRONMENT) $(LOG_COMPILER) \
+ $(LOG_COMPILER) \
$(AM_LOG_FLAGS) $(LOG_FLAGS)
endif
diff --git a/test/regress/regress0/fmf/PUZ001+1.smt2 b/test/regress/regress0/fmf/PUZ001+1.smt2
index bf156367e..f0e53fc98 100644
--- a/test/regress/regress0/fmf/PUZ001+1.smt2
+++ b/test/regress/regress0/fmf/PUZ001+1.smt2
@@ -1,4 +1,4 @@
-; COMMAND-LINE: --finite-model-find
+; COMMAND-LINE: --finite-model-find --no-check-proofs
; EXPECT: unsat
;%------------------------------------------------------------------------------
;% File : PUZ001+1 : TPTP v5.4.0. Released v2.0.0.
diff --git a/test/regress/regress0/hole6.cvc b/test/regress/regress0/hole6.cvc
index 5cc4de9be..dfa9b72d5 100644
--- a/test/regress/regress0/hole6.cvc
+++ b/test/regress/regress0/hole6.cvc
@@ -177,4 +177,3 @@ ASSERT x_42 OR x_41 OR x_40 OR x_39 OR x_38 OR x_37;
QUERY FALSE;
-% PROOF
diff --git a/test/regress/regress0/lemmas/Makefile.am b/test/regress/regress0/lemmas/Makefile.am
index 260b3600d..9ede6d4c0 100644
--- a/test/regress/regress0/lemmas/Makefile.am
+++ b/test/regress/regress0/lemmas/Makefile.am
@@ -6,12 +6,12 @@ SUBDIRS = .
end@mk_if@
LOG_COMPILER = @srcdir@/../../run_regression
-AM_LOG_FLAGS = $(RUN_REGRESSION_ARGS) @top_builddir@/src/main/$(BINARY)$(EXEEXT)
+AM_LOG_FLAGS = $(RUN_REGRESSION_ARGS) @abs_top_builddir@/src/main/$(BINARY)$(EXEEXT)
if AUTOMAKE_1_11
# old-style (pre-automake 1.12) test harness
TESTS_ENVIRONMENT = \
- $(TESTS_ENVIRONMENT) $(LOG_COMPILER) \
+ $(LOG_COMPILER) \
$(AM_LOG_FLAGS) $(LOG_FLAGS)
endif
diff --git a/test/regress/regress0/precedence/Makefile.am b/test/regress/regress0/precedence/Makefile.am
index 141510ea2..1d980997d 100644
--- a/test/regress/regress0/precedence/Makefile.am
+++ b/test/regress/regress0/precedence/Makefile.am
@@ -4,12 +4,12 @@
end@mk_if@
LOG_COMPILER = @srcdir@/../../run_regression
-AM_LOG_FLAGS = $(RUN_REGRESSION_ARGS) @top_builddir@/src/main/$(BINARY)$(EXEEXT)
+AM_LOG_FLAGS = $(RUN_REGRESSION_ARGS) @abs_top_builddir@/src/main/$(BINARY)$(EXEEXT)
if AUTOMAKE_1_11
# old-style (pre-automake 1.12) test harness
TESTS_ENVIRONMENT = \
- $(TESTS_ENVIRONMENT) $(LOG_COMPILER) \
+ $(LOG_COMPILER) \
$(AM_LOG_FLAGS) $(LOG_FLAGS)
endif
diff --git a/test/regress/regress0/preprocess/Makefile.am b/test/regress/regress0/preprocess/Makefile.am
index 73d13e78d..d83df4192 100644
--- a/test/regress/regress0/preprocess/Makefile.am
+++ b/test/regress/regress0/preprocess/Makefile.am
@@ -6,12 +6,12 @@ SUBDIRS = .
end@mk_if@
LOG_COMPILER = @srcdir@/../../run_regression
-AM_LOG_FLAGS = $(RUN_REGRESSION_ARGS) @top_builddir@/src/main/$(BINARY)$(EXEEXT)
+AM_LOG_FLAGS = $(RUN_REGRESSION_ARGS) @abs_top_builddir@/src/main/$(BINARY)$(EXEEXT)
if AUTOMAKE_1_11
# old-style (pre-automake 1.12) test harness
TESTS_ENVIRONMENT = \
- $(TESTS_ENVIRONMENT) $(LOG_COMPILER) \
+ $(LOG_COMPILER) \
$(AM_LOG_FLAGS) $(LOG_FLAGS)
endif
diff --git a/test/regress/regress0/push-pop/Makefile.am b/test/regress/regress0/push-pop/Makefile.am
index 0a1094238..29ad34255 100644
--- a/test/regress/regress0/push-pop/Makefile.am
+++ b/test/regress/regress0/push-pop/Makefile.am
@@ -6,12 +6,12 @@ SUBDIRS = boolean arith .
end@mk_if@
LOG_COMPILER = @srcdir@/../../run_regression
-AM_LOG_FLAGS = $(RUN_REGRESSION_ARGS) @top_builddir@/src/main/$(BINARY)$(EXEEXT)
+AM_LOG_FLAGS = $(RUN_REGRESSION_ARGS) @abs_top_builddir@/src/main/$(BINARY)$(EXEEXT)
if AUTOMAKE_1_11
# old-style (pre-automake 1.12) test harness
TESTS_ENVIRONMENT = \
- $(TESTS_ENVIRONMENT) $(LOG_COMPILER) \
+ $(LOG_COMPILER) \
$(AM_LOG_FLAGS) $(LOG_FLAGS)
endif
diff --git a/test/regress/regress0/push-pop/arith/Makefile.am b/test/regress/regress0/push-pop/arith/Makefile.am
index 6fd183ec3..7838e202d 100644
--- a/test/regress/regress0/push-pop/arith/Makefile.am
+++ b/test/regress/regress0/push-pop/arith/Makefile.am
@@ -6,12 +6,12 @@ SUBDIRS = .
end@mk_if@
LOG_COMPILER = @srcdir@/../../../run_regression
-AM_LOG_FLAGS = $(RUN_REGRESSION_ARGS) @top_builddir@/src/main/$(BINARY)$(EXEEXT)
+AM_LOG_FLAGS = $(RUN_REGRESSION_ARGS) @abs_top_builddir@/src/main/$(BINARY)$(EXEEXT)
if AUTOMAKE_1_11
# old-style (pre-automake 1.12) test harness
TESTS_ENVIRONMENT = \
- $(TESTS_ENVIRONMENT) $(LOG_COMPILER) \
+ $(LOG_COMPILER) \
$(AM_LOG_FLAGS) $(LOG_FLAGS)
endif
diff --git a/test/regress/regress0/push-pop/boolean/Makefile.am b/test/regress/regress0/push-pop/boolean/Makefile.am
index 0757ebfc2..995312cee 100644
--- a/test/regress/regress0/push-pop/boolean/Makefile.am
+++ b/test/regress/regress0/push-pop/boolean/Makefile.am
@@ -6,12 +6,12 @@ SUBDIRS = .
end@mk_if@
LOG_COMPILER = @srcdir@/../../../run_regression
-AM_LOG_FLAGS = $(RUN_REGRESSION_ARGS) @top_builddir@/src/main/$(BINARY)$(EXEEXT)
+AM_LOG_FLAGS = $(RUN_REGRESSION_ARGS) @abs_top_builddir@/src/main/$(BINARY)$(EXEEXT)
if AUTOMAKE_1_11
# old-style (pre-automake 1.12) test harness
TESTS_ENVIRONMENT = \
- $(TESTS_ENVIRONMENT) $(LOG_COMPILER) \
+ $(LOG_COMPILER) \
$(AM_LOG_FLAGS) $(LOG_FLAGS)
endif
diff --git a/test/regress/regress0/quantifiers/Makefile.am b/test/regress/regress0/quantifiers/Makefile.am
index 0b74d83b7..d0a93a142 100644
--- a/test/regress/regress0/quantifiers/Makefile.am
+++ b/test/regress/regress0/quantifiers/Makefile.am
@@ -4,12 +4,12 @@
end@mk_if@
LOG_COMPILER = @srcdir@/../../run_regression
-AM_LOG_FLAGS = $(RUN_REGRESSION_ARGS) @top_builddir@/src/main/$(BINARY)$(EXEEXT)
+AM_LOG_FLAGS = $(RUN_REGRESSION_ARGS) @abs_top_builddir@/src/main/$(BINARY)$(EXEEXT)
if AUTOMAKE_1_11
# old-style (pre-automake 1.12) test harness
TESTS_ENVIRONMENT = \
- $(TESTS_ENVIRONMENT) $(LOG_COMPILER) \
+ $(LOG_COMPILER) \
$(AM_LOG_FLAGS) $(LOG_FLAGS)
endif
diff --git a/test/regress/regress0/rewriterules/Makefile.am b/test/regress/regress0/rewriterules/Makefile.am
index d2e748fbf..32f8a72ba 100644
--- a/test/regress/regress0/rewriterules/Makefile.am
+++ b/test/regress/regress0/rewriterules/Makefile.am
@@ -7,12 +7,12 @@ export CVC4_REGRESSION_ARGS
end@mk_if@
LOG_COMPILER = @srcdir@/../../run_regression
-AM_LOG_FLAGS = $(RUN_REGRESSION_ARGS) @top_builddir@/src/main/$(BINARY)$(EXEEXT)
+AM_LOG_FLAGS = $(RUN_REGRESSION_ARGS) @abs_top_builddir@/src/main/$(BINARY)$(EXEEXT)
if AUTOMAKE_1_11
# old-style (pre-automake 1.12) test harness
TESTS_ENVIRONMENT = \
- $(TESTS_ENVIRONMENT) $(LOG_COMPILER) \
+ $(LOG_COMPILER) \
$(AM_LOG_FLAGS) $(LOG_FLAGS)
endif
diff --git a/test/regress/regress0/strings/Makefile.am b/test/regress/regress0/strings/Makefile.am
index e24cbc565..a5c6ae2f4 100644
--- a/test/regress/regress0/strings/Makefile.am
+++ b/test/regress/regress0/strings/Makefile.am
@@ -4,12 +4,12 @@
end@mk_if@
LOG_COMPILER = @srcdir@/../../run_regression
-AM_LOG_FLAGS = $(RUN_REGRESSION_ARGS) @top_builddir@/src/main/$(BINARY)$(EXEEXT)
+AM_LOG_FLAGS = $(RUN_REGRESSION_ARGS) @abs_top_builddir@/src/main/$(BINARY)$(EXEEXT)
if AUTOMAKE_1_11
# old-style (pre-automake 1.12) test harness
TESTS_ENVIRONMENT = \
- $(TESTS_ENVIRONMENT) $(LOG_COMPILER) \
+ $(LOG_COMPILER) \
$(AM_LOG_FLAGS) $(LOG_FLAGS)
endif
diff --git a/test/regress/regress0/strings/substr001.smt2 b/test/regress/regress0/strings/substr001.smt2
index 2b2ae9820..c0554c481 100644
--- a/test/regress/regress0/strings/substr001.smt2
+++ b/test/regress/regress0/strings/substr001.smt2
@@ -8,8 +8,8 @@
(declare-fun i3 () Int)
(declare-fun i4 () Int)
-(assert (= "efg" (str.sub x i1 i2) ) )
-(assert (= "bef" (str.sub x i3 i4) ) )
+(assert (= "efg" (str.substr x i1 i2) ) )
+(assert (= "bef" (str.substr x i3 i4) ) )
(assert (> (str.len x) 5))
(check-sat)
diff --git a/test/regress/regress0/tptp/Makefile.am b/test/regress/regress0/tptp/Makefile.am
index e227e0bba..f8f106362 100644
--- a/test/regress/regress0/tptp/Makefile.am
+++ b/test/regress/regress0/tptp/Makefile.am
@@ -4,12 +4,12 @@
end@mk_if@
LOG_COMPILER = @srcdir@/../../run_regression
-AM_LOG_FLAGS = $(RUN_REGRESSION_ARGS) @top_builddir@/src/main/$(BINARY)$(EXEEXT)
+AM_LOG_FLAGS = $(RUN_REGRESSION_ARGS) @abs_top_builddir@/src/main/$(BINARY)$(EXEEXT)
if AUTOMAKE_1_11
# old-style (pre-automake 1.12) test harness
TESTS_ENVIRONMENT = \
- $(TESTS_ENVIRONMENT) $(LOG_COMPILER) \
+ $(LOG_COMPILER) \
$(AM_LOG_FLAGS) $(LOG_FLAGS)
endif
diff --git a/test/regress/regress0/uf/Makefile.am b/test/regress/regress0/uf/Makefile.am
index 19e673fea..98194413d 100644
--- a/test/regress/regress0/uf/Makefile.am
+++ b/test/regress/regress0/uf/Makefile.am
@@ -4,12 +4,12 @@
end@mk_if@
LOG_COMPILER = @srcdir@/../../run_regression
-AM_LOG_FLAGS = $(RUN_REGRESSION_ARGS) @top_builddir@/src/main/$(BINARY)$(EXEEXT)
+AM_LOG_FLAGS = $(RUN_REGRESSION_ARGS) @abs_top_builddir@/src/main/$(BINARY)$(EXEEXT)
if AUTOMAKE_1_11
# old-style (pre-automake 1.12) test harness
TESTS_ENVIRONMENT = \
- $(TESTS_ENVIRONMENT) $(LOG_COMPILER) \
+ $(LOG_COMPILER) \
$(AM_LOG_FLAGS) $(LOG_FLAGS)
endif
diff --git a/test/regress/regress0/uflia/Makefile.am b/test/regress/regress0/uflia/Makefile.am
index 2ef7be862..2946d886a 100644
--- a/test/regress/regress0/uflia/Makefile.am
+++ b/test/regress/regress0/uflia/Makefile.am
@@ -4,12 +4,12 @@
end@mk_if@
LOG_COMPILER = @srcdir@/../../run_regression
-AM_LOG_FLAGS = $(RUN_REGRESSION_ARGS) @top_builddir@/src/main/$(BINARY)$(EXEEXT)
+AM_LOG_FLAGS = $(RUN_REGRESSION_ARGS) @abs_top_builddir@/src/main/$(BINARY)$(EXEEXT)
if AUTOMAKE_1_11
# old-style (pre-automake 1.12) test harness
TESTS_ENVIRONMENT = \
- $(TESTS_ENVIRONMENT) $(LOG_COMPILER) \
+ $(LOG_COMPILER) \
$(AM_LOG_FLAGS) $(LOG_FLAGS)
endif
diff --git a/test/regress/regress0/uflra/Makefile.am b/test/regress/regress0/uflra/Makefile.am
index 63d362bf9..cd39284b8 100644
--- a/test/regress/regress0/uflra/Makefile.am
+++ b/test/regress/regress0/uflra/Makefile.am
@@ -4,12 +4,12 @@
end@mk_if@
LOG_COMPILER = @srcdir@/../../run_regression
-AM_LOG_FLAGS = $(RUN_REGRESSION_ARGS) @top_builddir@/src/main/$(BINARY)$(EXEEXT)
+AM_LOG_FLAGS = $(RUN_REGRESSION_ARGS) @abs_top_builddir@/src/main/$(BINARY)$(EXEEXT)
if AUTOMAKE_1_11
# old-style (pre-automake 1.12) test harness
TESTS_ENVIRONMENT = \
- $(TESTS_ENVIRONMENT) $(LOG_COMPILER) \
+ $(LOG_COMPILER) \
$(AM_LOG_FLAGS) $(LOG_FLAGS)
endif
diff --git a/test/regress/regress0/unconstrained/Makefile.am b/test/regress/regress0/unconstrained/Makefile.am
index c9a38d7b1..ecf427fb5 100644
--- a/test/regress/regress0/unconstrained/Makefile.am
+++ b/test/regress/regress0/unconstrained/Makefile.am
@@ -4,12 +4,12 @@
end@mk_if@
LOG_COMPILER = @srcdir@/../../run_regression
-AM_LOG_FLAGS = $(RUN_REGRESSION_ARGS) @top_builddir@/src/main/$(BINARY)$(EXEEXT)
+AM_LOG_FLAGS = $(RUN_REGRESSION_ARGS) @abs_top_builddir@/src/main/$(BINARY)$(EXEEXT)
if AUTOMAKE_1_11
# old-style (pre-automake 1.12) test harness
TESTS_ENVIRONMENT = \
- $(TESTS_ENVIRONMENT) $(LOG_COMPILER) \
+ $(LOG_COMPILER) \
$(AM_LOG_FLAGS) $(LOG_FLAGS)
endif
diff --git a/test/regress/regress0/wiki.05.cvc b/test/regress/regress0/wiki.05.cvc
index fa9f56f81..0fe647f7b 100644
--- a/test/regress/regress0/wiki.05.cvc
+++ b/test/regress/regress0/wiki.05.cvc
@@ -2,4 +2,3 @@ a, b, c : BOOLEAN;
% EXPECT: valid
QUERY a OR (a AND b) <=> a;
-% PROOF
diff --git a/test/regress/regress1/Makefile.am b/test/regress/regress1/Makefile.am
index 674f5c75e..5f292b893 100644
--- a/test/regress/regress1/Makefile.am
+++ b/test/regress/regress1/Makefile.am
@@ -6,12 +6,12 @@ SUBDIRS = . arith
end@mk_if@
LOG_COMPILER = @srcdir@/../run_regression
-AM_LOG_FLAGS = $(RUN_REGRESSION_ARGS) @top_builddir@/src/main/$(BINARY)$(EXEEXT)
+AM_LOG_FLAGS = $(RUN_REGRESSION_ARGS) @abs_top_builddir@/src/main/$(BINARY)$(EXEEXT)
if AUTOMAKE_1_11
# old-style (pre-automake 1.12) test harness
TESTS_ENVIRONMENT = \
- $(TESTS_ENVIRONMENT) $(LOG_COMPILER) \
+ $(LOG_COMPILER) \
$(AM_LOG_FLAGS) $(LOG_FLAGS)
endif
diff --git a/test/regress/regress1/arith/Makefile.am b/test/regress/regress1/arith/Makefile.am
index ca362f479..fff5372c6 100644
--- a/test/regress/regress1/arith/Makefile.am
+++ b/test/regress/regress1/arith/Makefile.am
@@ -4,12 +4,12 @@
end@mk_if@
LOG_COMPILER = @srcdir@/../../run_regression
-AM_LOG_FLAGS = $(RUN_REGRESSION_ARGS) @top_builddir@/src/main/$(BINARY)$(EXEEXT)
+AM_LOG_FLAGS = $(RUN_REGRESSION_ARGS) @abs_top_builddir@/src/main/$(BINARY)$(EXEEXT)
if AUTOMAKE_1_11
# old-style (pre-automake 1.12) test harness
TESTS_ENVIRONMENT = \
- $(TESTS_ENVIRONMENT) $(LOG_COMPILER) \
+ $(LOG_COMPILER) \
$(AM_LOG_FLAGS) $(LOG_FLAGS)
endif
diff --git a/test/regress/regress2/Makefile.am b/test/regress/regress2/Makefile.am
index e4e5d8d29..9deb1f37b 100644
--- a/test/regress/regress2/Makefile.am
+++ b/test/regress/regress2/Makefile.am
@@ -6,12 +6,12 @@ SUBDIRS = .
end@mk_if@
LOG_COMPILER = @srcdir@/../run_regression
-AM_LOG_FLAGS = $(RUN_REGRESSION_ARGS) @top_builddir@/src/main/$(BINARY)$(EXEEXT)
+AM_LOG_FLAGS = $(RUN_REGRESSION_ARGS) @abs_top_builddir@/src/main/$(BINARY)$(EXEEXT)
if AUTOMAKE_1_11
# old-style (pre-automake 1.12) test harness
TESTS_ENVIRONMENT = \
- $(TESTS_ENVIRONMENT) $(LOG_COMPILER) \
+ $(LOG_COMPILER) \
$(AM_LOG_FLAGS) $(LOG_FLAGS)
endif
diff --git a/test/regress/regress3/Makefile.am b/test/regress/regress3/Makefile.am
index 213157491..3fb798bcc 100644
--- a/test/regress/regress3/Makefile.am
+++ b/test/regress/regress3/Makefile.am
@@ -6,12 +6,12 @@ SUBDIRS = .
end@mk_if@
LOG_COMPILER = @srcdir@/../run_regression
-AM_LOG_FLAGS = $(RUN_REGRESSION_ARGS) @top_builddir@/src/main/$(BINARY)$(EXEEXT)
+AM_LOG_FLAGS = $(RUN_REGRESSION_ARGS) @abs_top_builddir@/src/main/$(BINARY)$(EXEEXT)
if AUTOMAKE_1_11
# old-style (pre-automake 1.12) test harness
TESTS_ENVIRONMENT = \
- $(TESTS_ENVIRONMENT) $(LOG_COMPILER) \
+ $(LOG_COMPILER) \
$(AM_LOG_FLAGS) $(LOG_FLAGS)
endif
diff --git a/test/regress/run_regression b/test/regress/run_regression
index 4d23e796b..ef2bb9a35 100755
--- a/test/regress/run_regression
+++ b/test/regress/run_regression
@@ -71,10 +71,8 @@ function gettemp {
tmpbenchmark=
if expr "$benchmark" : '.*\.smt$' &>/dev/null; then
- proof_command=PROOFS-NOT-SUPPORTED-IN-SMTLIB-V1
lang=smt1
if test -e "$benchmark.expect"; then
- expected_proof=`grep '^% PROOF' "$benchmark.expect" &>/dev/null && echo yes`
expected_output=`grep '^% EXPECT: ' "$benchmark.expect" | sed 's,^% EXPECT: ,,'`
expected_error=`grep '^% EXPECT-ERROR: ' "$benchmark.expect" | sed 's,^% EXPECT-ERROR: ,,'`
expected_exit_status=`grep -m 1 '^% EXIT: ' "$benchmark.expect" | perl -pe 's,^% EXIT: ,,;s,\r,,'`
@@ -83,7 +81,6 @@ if expr "$benchmark" : '.*\.smt$' &>/dev/null; then
expected_exit_status=0
fi
elif grep '^% \(PROOF\|EXPECT\|EXPECT-ERROR\|EXIT\|COMMAND-LINE\): ' "$benchmark" "$benchmark" &>/dev/null; then
- expected_proof=`grep '^% PROOF' "$benchmark" &>/dev/null && echo yes`
expected_output=`grep '^% EXPECT: ' "$benchmark" | sed 's,^% EXPECT: ,,'`
expected_error=`grep '^% EXPECT-ERROR: ' "$benchmark" | sed 's,^% EXPECT-ERROR: ,,'`
expected_exit_status=`grep -m 1 '^% EXIT: ' "$benchmark" | perl -pe 's,^% EXIT: ,,;s,\r,,'`
@@ -97,12 +94,10 @@ if expr "$benchmark" : '.*\.smt$' &>/dev/null; then
fi
benchmark=$tmpbenchmark
elif grep '^ *:status *sat' "$benchmark" &>/dev/null; then
- expected_proof=
expected_output=sat
expected_exit_status=0
command_line=
elif grep '^ *:status *unsat' "$benchmark" &>/dev/null; then
- expected_proof=
expected_output=unsat
expected_exit_status=0
command_line=
@@ -110,10 +105,8 @@ if expr "$benchmark" : '.*\.smt$' &>/dev/null; then
error "cannot determine status of \`$benchmark'"
fi
elif expr "$benchmark" : '.*\.smt2$' &>/dev/null; then
- proof_command='(get-proof)'
lang=smt2
if test -e "$benchmark.expect"; then
- expected_proof=`grep '^[%;] PROOF' "$benchmark.expect" &>/dev/null && echo yes`
expected_output=`grep '^% EXPECT: ' "$benchmark.expect" | sed 's,^% EXPECT: ,,'`
expected_error=`grep '^% EXPECT-ERROR: ' "$benchmark.expect" | sed 's,^% EXPECT-ERROR: ,,'`
expected_exit_status=`grep -m 1 '^% EXIT: ' "$benchmark.expect" | perl -pe 's,^% EXIT: ,,;s,\r,,'`
@@ -122,7 +115,6 @@ elif expr "$benchmark" : '.*\.smt2$' &>/dev/null; then
expected_exit_status=0
fi
elif grep '^\(%\|;\) \(EXPECT\|EXPECT-ERROR\|EXIT\|COMMAND-LINE\): ' "$benchmark" "$benchmark" &>/dev/null; then
- expected_proof=`grep '^[%;] PROOF' "$benchmark" &>/dev/null && echo yes`
expected_output=`grep '^[%;] EXPECT: ' "$benchmark" | sed 's,^[%;] EXPECT: ,,'`
expected_error=`grep '^[%;] EXPECT-ERROR: ' "$benchmark" | sed 's,^[%;] EXPECT-ERROR: ,,'`
expected_exit_status=`grep -m 1 '^[%;] EXIT: ' "$benchmark" | perl -pe 's,^[%;] EXIT: ,,;s,\r,,'`
@@ -136,12 +128,10 @@ elif expr "$benchmark" : '.*\.smt2$' &>/dev/null; then
fi
benchmark=$tmpbenchmark
elif grep '^ *( *set-info *:status *sat' "$benchmark" &>/dev/null; then
- expected_proof=
expected_output=sat
expected_exit_status=0
command_line=
elif grep '^ *( *set-info *:status *unsat' "$benchmark" &>/dev/null; then
- expected_proof=`grep '^; PROOF' "$benchmark" &>/dev/null && echo yes`
expected_output=unsat
expected_exit_status=0
command_line=
@@ -149,9 +139,7 @@ elif expr "$benchmark" : '.*\.smt2$' &>/dev/null; then
error "cannot determine status of \`$benchmark'"
fi
elif expr "$benchmark" : '.*\.cvc$' &>/dev/null; then
- proof_command='DUMP_PROOF;'
lang=cvc4
- expected_proof=`grep '^% PROOF' "$benchmark" &>/dev/null && echo yes`
expected_output=$(grep '^% EXPECT: ' "$benchmark")
expected_error=`grep '^% EXPECT-ERROR: ' "$benchmark" | sed 's,^% EXPECT-ERROR: ,,'`
if [ -z "$expected_output" -a -z "$expected_error" ]; then
@@ -165,10 +153,8 @@ elif expr "$benchmark" : '.*\.cvc$' &>/dev/null; then
fi
command_line=`grep '^% COMMAND-LINE: ' "$benchmark" | sed 's,^% COMMAND-LINE: ,,'`
elif expr "$benchmark" : '.*\.p$' &>/dev/null; then
- proof_command=PROOFS-NOT-SUPPORTED-IN-TPTP;
lang=tptp
command_line=--finite-model-find
- expected_proof=`grep '^% PROOF' "$benchmark" &>/dev/null && echo yes`
expected_output=$(grep '^% EXPECT: ' "$benchmark")
expected_error=`grep '^% EXPECT-ERROR: ' "$benchmark" | sed 's,^% EXPECT-ERROR: ,,'`
if [ -z "$expected_output" -a -z "$expected_error" ]; then
@@ -213,14 +199,28 @@ if [ -z "$expected_output" ]; then
else
echo "$expected_output" >"$expoutfile"
fi
+
check_models=false
if grep '^sat$' "$expoutfile" &>/dev/null || grep '^invalid$' "$expoutfile" &>/dev/null || grep '^unknown$' "$expoptfile" &>/dev/null; then
- if ! expr "$CVC4_REGRESSION_ARGS $command_line" : '.*--check-models' &>/dev/null &&
- ! expr "$CVC4_REGRESSION_ARGS $command_line" : '.*--no-check-models' &>/dev/null; then
+ if ! expr "$CVC4_REGRESSION_ARGS $command_line" : '.*--check-models\>' &>/dev/null &&
+ ! expr "$CVC4_REGRESSION_ARGS $command_line" : '.*--no-check-models\>' &>/dev/null; then
# later on, we'll run another test with --check-models on
check_models=true
fi
fi
+check_proofs=false
+if [ "$proof" = yes ]; then
+ # proofs not currently supported in incremental mode, turn it off
+ if grep '^unsat$' "$expoutfile" &>/dev/null || grep '^valid$' "$expoutfile" &>/dev/null &>/dev/null; then
+ if ! expr "$CVC4_REGRESSION_ARGS $command_line" : '.*--check-proofs\>' &>/dev/null &&
+ ! expr "$CVC4_REGRESSION_ARGS $command_line" : '.*--no-check-proofs\>' &>/dev/null &&
+ ! expr "$CVC4_REGRESSION_ARGS $command_line" : '.*--incremental\>' &>/dev/null &&
+ ! expr " $CVC4_REGRESSION_ARGS $command_line" : '.* -[a-zA-Z]*i' &>/dev/null; then
+ # later on, we'll run another test with --check-proofs on
+ check_proofs=true
+ fi
+ fi
+fi
if [ -z "$expected_error" ]; then
# in case expected stderr output is empty, make sure we don't differ
# by a newline, which we would if we echo "" >"$experrfile"
@@ -275,47 +275,16 @@ if [ "$exit_status" != "$expected_exit_status" ]; then
exitcode=1
fi
-if [ "$proof" = yes -a "$expected_proof" = yes ]; then
- gettemp pfbenchmark cvc4_pfbenchmark.$$.XXXXXXXXXX
- # remove exit command to add proof command for smt2 benchmarks
- if expr "$benchmark" : '.*\.smt2$' &>/dev/null; then
- head -n -0 "$benchmark" > "$pfbenchmark";
- echo "$proof_command" >>"$pfbenchmark";
- echo "(exit)" >> "$pfbenchmark";
- else
- cp $benchmark $pfbenchmark
- echo "$proof_command" >>"$pfbenchmark";
+if $check_models || $check_proofs; then
+ check_cmdline=
+ if $check_models; then
+ check_cmdline="$check_cmdline --check-models"
fi
- echo running $wrapper $cvc4full $CVC4_REGRESSION_ARGS $command_line --proof `basename "$pfbenchmark"` [from working dir `dirname "$pfbenchmark"`]
- time ( :; \
- ( cd `dirname "$pfbenchmark"`;
- $wrapper "$cvc4full" $CVC4_REGRESSION_ARGS $command_line --proof `basename "$pfbenchmark"`;
- echo $? >"$exitstatusfile"
- ) > "$outfile" 2> "$errfile" )
-
- gettemp pfoutfile cvc4_proof.$$.XXXXXXXXXX
-
- diff --unchanged-group-format='' \
- --old-group-format='' \
- --new-group-format='%>' \
- "$expoutfile" "$outfile" > "$pfoutfile"
- if [ ! -s "$pfoutfile" ]; then
- echo "$prog: error: proof generation failed with empty output (stderr follows)"
- cat "$errfile"
- exitcode=1
- else
- echo running $LFSC "$pfoutfile" [from working dir `dirname "$pfbenchmark"`]
- if ! $LFSC "$pfoutfile" &> "$errfile"; then
- echo "$prog: error: proof checker failed (output follows)"
- cat "$errfile"
- exitcode=1
- fi
+ if $check_proofs; then
+ check_cmdline="$check_cmdline --check-proofs"
fi
-fi
-
-if $check_models; then
- # at least one sat/invalid response: run an extra model-checking pass
- if ! CVC4_REGRESSION_ARGS="$CVC4_REGRESSION_ARGS --check-models" "$0" $wrapper "$cvc4" "$benchmark_orig"; then
+ # at least one sat/invalid response: run an extra model/proof-checking pass
+ if ! CVC4_REGRESSION_ARGS="$CVC4_REGRESSION_ARGS$check_cmdline" "$0" $wrapper "$cvc4" "$benchmark_orig"; then
exitcode=1
fi
fi
generated by cgit on debian on lair
contact matthew@masot.net with questions or feedback