summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAndres Noetzli <andres.noetzli@gmail.com>2019-01-14 17:02:43 -0800
committerAndres Noetzli <andres.noetzli@gmail.com>2019-01-14 17:02:43 -0800
commit2771dce1fe1933537f80d68966642ecf3bf95f77 (patch)
treec3b4c27aa49657b9ae6b7d115927a2bd81b2bb84
parent843ca884a8a6e66b06b1682a60277374ed6d3db4 (diff)
parenta2f04c7859932f03537688eda0e816d8b9b4edc3 (diff)
Merge remote-tracking branch 'fork/betterSkolems' into cav2019strings
-rw-r--r--CMakeLists.txt12
-rw-r--r--NEWS11
-rw-r--r--cmake/FindDrat2Er.cmake31
-rwxr-xr-xconfigure.sh14
-rwxr-xr-xcontrib/get-drat2er25
-rw-r--r--proofs/signatures/drat.plf224
-rw-r--r--proofs/signatures/drat_test.plf191
-rw-r--r--proofs/signatures/lrat.plf594
-rw-r--r--proofs/signatures/lrat_test.plf891
-rw-r--r--proofs/signatures/sat.plf6
-rw-r--r--proofs/signatures/smt.plf16
-rw-r--r--proofs/signatures/th_bv.plf14
-rw-r--r--proofs/signatures/th_lra.plf195
-rw-r--r--proofs/signatures/th_lra_test.plf155
-rw-r--r--src/CMakeLists.txt8
-rw-r--r--src/api/cvc4cpp.cpp110
-rw-r--r--src/api/cvc4cpp.h4
-rw-r--r--src/base/configuration_private.h6
-rw-r--r--src/expr/expr_template.cpp3
-rw-r--r--src/expr/expr_template.h2
-rw-r--r--src/expr/type_node.cpp2
-rw-r--r--src/options/CMakeLists.txt2
-rw-r--r--src/options/bool_to_bv_mode.cpp42
-rw-r--r--src/options/bool_to_bv_mode.h57
-rw-r--r--src/options/bv_options.toml17
-rw-r--r--src/options/options_handler.cpp71
-rw-r--r--src/options/options_handler.h4
-rw-r--r--src/options/options_template.cpp2
-rw-r--r--src/options/quantifiers_modes.cpp6
-rw-r--r--src/options/quantifiers_modes.h4
-rw-r--r--src/preprocessing/passes/bool_to_bv.cpp326
-rw-r--r--src/preprocessing/passes/bool_to_bv.h37
-rw-r--r--src/proof/arith_proof.cpp6
-rw-r--r--src/proof/arith_proof.h6
-rw-r--r--src/proof/arith_proof_recorder.cpp81
-rw-r--r--src/proof/arith_proof_recorder.h107
-rw-r--r--src/proof/bitvector_proof.cpp8
-rw-r--r--src/proof/proof_manager.cpp3
-rw-r--r--src/proof/resolution_bitvector_proof.h3
-rw-r--r--src/smt/smt_engine.cpp76
-rw-r--r--src/theory/arith/constraint.cpp29
-rw-r--r--src/theory/arith/constraint.h6
-rw-r--r--src/theory/arith/cut_log.h2
-rw-r--r--src/theory/arith/theory_arith.cpp1
-rw-r--r--src/theory/arith/theory_arith.h11
-rw-r--r--src/theory/bv/bitblast/eager_bitblaster.cpp4
-rw-r--r--src/theory/bv/theory_bv.cpp2
-rw-r--r--src/theory/bv/theory_bv_rewrite_rules_simplification.h6
-rw-r--r--src/theory/quantifiers/extended_rewrite.cpp7
-rw-r--r--src/theory/quantifiers/first_order_model.cpp590
-rw-r--r--src/theory/quantifiers/first_order_model.h121
-rw-r--r--src/theory/quantifiers/fmf/ambqi_builder.cpp971
-rw-r--r--src/theory/quantifiers/fmf/ambqi_builder.h105
-rw-r--r--src/theory/quantifiers/fmf/bounded_integers.cpp5
-rw-r--r--src/theory/quantifiers/fmf/model_builder.cpp684
-rw-r--r--src/theory/quantifiers/fmf/model_builder.h157
-rw-r--r--src/theory/quantifiers/fmf/model_engine.cpp1
-rw-r--r--src/theory/quantifiers/sygus/ce_guided_single_inv.cpp318
-rw-r--r--src/theory/quantifiers/sygus/sygus_unif_io.cpp200
-rw-r--r--src/theory/quantifiers/sygus/sygus_unif_io.h9
-rw-r--r--src/theory/quantifiers/term_util.cpp20
-rw-r--r--src/theory/quantifiers/term_util.h16
-rw-r--r--src/theory/quantifiers_engine.cpp13
-rw-r--r--src/theory/sets/theory_sets_rewriter.cpp3
-rw-r--r--src/theory/strings/skolem_cache.cpp95
-rw-r--r--src/theory/strings/theory_strings.cpp25
-rw-r--r--src/theory/strings/theory_strings_rewriter.cpp21
-rw-r--r--src/theory/strings/theory_strings_rewriter.h9
-rw-r--r--src/theory/uf/theory_uf_model.cpp84
-rw-r--r--src/theory/uf/theory_uf_model.h39
-rw-r--r--src/util/sexpr.h2
-rw-r--r--test/regress/CMakeLists.txt5
-rw-r--r--test/regress/regress0/bv/ackermann1.smt22
-rw-r--r--test/regress/regress0/bv/ackermann2.smt22
-rw-r--r--test/regress/regress0/bv/bool-to-bv-all.smt2 (renamed from test/regress/regress0/bv/bool-to-bv.smt2)2
-rw-r--r--test/regress/regress0/bv/bool-to-bv-ite.smt213
-rw-r--r--test/regress/regress0/fmf/Arrow_Order-smtlib.778341.smt2
-rw-r--r--test/regress/regress0/fmf/QEpres-uf.855035.smt2
-rw-r--r--test/regress/regress0/sets/sets-extr.smt215
-rw-r--r--test/regress/regress1/bv/bug787.smt22
-rw-r--r--test/regress/regress1/fmf/nlp042+1.smt22
-rw-r--r--test/regress/regress2/strings/extf_d_perf.smt219
-rw-r--r--test/unit/api/CMakeLists.txt1
-rw-r--r--test/unit/api/opterm_black.h57
-rw-r--r--test/unit/api/solver_black.h117
-rw-r--r--test/unit/api/term_black.h522
86 files changed, 4264 insertions, 3427 deletions
diff --git a/CMakeLists.txt b/CMakeLists.txt
index 099fc00fa..3265830cc 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -93,6 +93,7 @@ cvc4_option(USE_READLINE "Use readline for better interactive support")
# > for options where we don't need to detect if set by user (default: OFF)
option(USE_CADICAL "Use CaDiCaL SAT solver")
option(USE_CRYPTOMINISAT "Use CryptoMiniSat SAT solver")
+option(USE_DRAT2ER "Include drat2er for making eager BV proofs")
option(USE_LFSC "Use LFSC proof checker")
option(USE_SYMFPU "Use SymFPU for floating point support")
option(USE_PYTHON2 "Prefer using Python 2 (for Python bindings)")
@@ -108,6 +109,7 @@ set(ANTLR_DIR "" CACHE STRING "Set ANTLR3 install directory")
set(CADICAL_DIR "" CACHE STRING "Set CaDiCaL install directory")
set(CRYPTOMINISAT_DIR "" CACHE STRING "Set CryptoMiniSat install directory")
set(CXXTEST_DIR "" CACHE STRING "Set CxxTest install directory")
+set(DRAT2ER_DIR "" CACHE STRING "Set drat2er install directory")
set(GLPK_DIR "" CACHE STRING "Set GLPK install directory")
set(GMP_DIR "" CACHE STRING "Set GMP install directory")
set(LFSC_DIR "" CACHE STRING "Set LFSC install directory")
@@ -410,6 +412,12 @@ if(USE_CRYPTOMINISAT)
add_definitions(-DCVC4_USE_CRYPTOMINISAT)
endif()
+if(USE_DRAT2ER)
+ set(Drat2Er_HOME ${DRAT2ER_DIR})
+ find_package(Drat2Er REQUIRED)
+ add_definitions(-DCVC4_USE_DRAT2ER)
+endif()
+
if(USE_GLPK)
set(GPL_LIBS "${GPL_LIBS} glpk")
set(GLPK_HOME ${GLPK_DIR})
@@ -523,6 +531,7 @@ message("")
print_config("ABC :" USE_ABC)
print_config("CaDiCaL :" USE_CADICAL)
print_config("CryptoMiniSat :" USE_CRYPTOMINISAT)
+print_config("drat2er :" USE_DRAT2ER)
print_config("GLPK :" USE_GLPK)
print_config("LFSC :" USE_LFSC)
@@ -546,6 +555,9 @@ endif()
if(CRYPTOMINISAT_DIR)
message("CRYPTOMINISAT dir : ${CRYPTOMINISAT_DIR}")
endif()
+if(DRAT2ER_DIR)
+ message("DRAT2ER dir : ${DRAT2ER_DIR}")
+endif()
if(GLPK_DIR)
message("GLPK dir : ${GLPK_DIR}")
endif()
diff --git a/NEWS b/NEWS
index 038b02026..0cc8cab44 100644
--- a/NEWS
+++ b/NEWS
@@ -1,5 +1,16 @@
This file contains a summary of important user-visible changes.
+Changes since 1.6
+=================
+
+New Features:
+
+Improvements:
+
+Changes:
+* API change: Expr::iffExpr() is renamed to Expr::eqExpr() to reflect its
+ actual behavior.
+
Changes since 1.5
=================
diff --git a/cmake/FindDrat2Er.cmake b/cmake/FindDrat2Er.cmake
new file mode 100644
index 000000000..e0bc8d446
--- /dev/null
+++ b/cmake/FindDrat2Er.cmake
@@ -0,0 +1,31 @@
+# Find drat2er
+# Drat2Er_FOUND - system has Drat2Er lib
+# Drat2Er_INCLUDE_DIR - the Drat2Er include directory
+# Drat2Er_LIBRARIES - Libraries needed to use Drat2Er
+
+
+# Check default location of Drat2Er built with contrib/get-drat2er.
+# If the user provides a directory we will not search the default paths and
+# fail if Drat2Er was not found in the specified directory.
+if(NOT Drat2Er_HOME)
+ set(Drat2Er_HOME ${PROJECT_SOURCE_DIR}/drat2er/build/install)
+endif()
+
+find_path(Drat2Er_INCLUDE_DIR
+ NAMES drat2er.h
+ PATHS ${Drat2Er_HOME}/include
+ NO_DEFAULT_PATH)
+find_library(Drat2Er_LIBRARIES
+ NAMES libdrat2er.a
+ PATHS ${Drat2Er_HOME}/lib
+ NO_DEFAULT_PATH)
+
+include(FindPackageHandleStandardArgs)
+find_package_handle_standard_args(Drat2Er
+ DEFAULT_MSG
+ Drat2Er_INCLUDE_DIR Drat2Er_LIBRARIES)
+
+mark_as_advanced(Drat2Er_INCLUDE_DIR Drat2Er_LIBRARIES)
+if(Drat2Er_LIBRARIES)
+ message(STATUS "Found Drat2Er libs: ${Drat2Er_LIBRARIES}")
+endif()
diff --git a/configure.sh b/configure.sh
index 7fa842f70..e53d8caa7 100755
--- a/configure.sh
+++ b/configure.sh
@@ -55,6 +55,7 @@ The following flags enable optional packages (disable with --no-<option name>).
--abc use the ABC AIG library
--cadical use the CaDiCaL SAT solver
--cryptominisat use the CryptoMiniSat SAT solver
+ --drat2er use drat2er (required for eager BV proofs)
--lfsc use the LFSC proof checker
--symfpu use SymFPU for floating point solver
--portfolio build the multithreaded portfolio version of CVC4
@@ -66,6 +67,7 @@ Optional Path to Optional Packages:
--antlr-dir=PATH path to ANTLR C headers and libraries
--cadical-dir=PATH path to top level of CaDiCaL source tree
--cryptominisat-dir=PATH path to top level of CryptoMiniSat source tree
+ --drat2er-dir=PATH path to the top level of the drat2er installation
--cxxtest-dir=PATH path to CxxTest installation
--glpk-dir=PATH path to top level of GLPK installation
--gmp-dir=PATH path to top level of GMP installation
@@ -112,6 +114,7 @@ coverage=default
cryptominisat=default
debug_symbols=default
debug_context_mm=default
+drat2er=default
dumping=default
gpl=default
win64=default
@@ -141,6 +144,7 @@ abc_dir=default
antlr_dir=default
cadical_dir=default
cryptominisat_dir=default
+drat2er_dir=default
cxxtest_dir=default
glpk_dir=default
gmp_dir=default
@@ -202,6 +206,9 @@ do
--debug-context-mm) debug_context_mm=ON;;
--no-debug-context-mm) debug_context_mm=OFF;;
+ --drat2er) drat2er=ON;;
+ --no-drat2er) drat2er=OFF;;
+
--dumping) dumping=ON;;
--no-dumping) dumping=OFF;;
@@ -297,6 +304,9 @@ do
--cxxtest-dir) die "missing argument to $1 (try -h)" ;;
--cxxtest-dir=*) cxxtest_dir=${1##*=} ;;
+ --drat2er-dir) die "missing argument to $1 (try -h)" ;;
+ --drat2er-dir=*) drat2er_dir=${1##*=} ;;
+
--glpk-dir) die "missing argument to $1 (try -h)" ;;
--glpk-dir=*) glpk_dir=${1##*=} ;;
@@ -386,6 +396,8 @@ cmake_opts=""
&& cmake_opts="$cmake_opts -DUSE_CLN=$cln"
[ $cryptominisat != default ] \
&& cmake_opts="$cmake_opts -DUSE_CRYPTOMINISAT=$cryptominisat"
+[ $drat2er != default ] \
+ && cmake_opts="$cmake_opts -DUSE_DRAT2ER=$drat2er"
[ $glpk != default ] \
&& cmake_opts="$cmake_opts -DUSE_GLPK=$glpk"
[ $lfsc != default ] \
@@ -408,6 +420,8 @@ cmake_opts=""
&& cmake_opts="$cmake_opts -DCRYPTOMINISAT_DIR=$cryptominisat_dir"
[ "$cxxtest_dir" != default ] \
&& cmake_opts="$cmake_opts -DCXXTEST_DIR=$cxxtest_dir"
+[ "$drat2er_dir" != default ] \
+ && cmake_opts="$cmake_opts -DDRAT2ER_DIR=$drat2er_dir"
[ "$glpk_dir" != default ] \
&& cmake_opts="$cmake_opts -DGLPK_DIR=$glpk_dir"
[ "$gmp_dir" != default ] \
diff --git a/contrib/get-drat2er b/contrib/get-drat2er
new file mode 100755
index 000000000..e465ab3d4
--- /dev/null
+++ b/contrib/get-drat2er
@@ -0,0 +1,25 @@
+#!/bin/bash
+#
+source "$(dirname "$0")/get-script-header.sh"
+if [ -e drat2er ]; then
+ echo 'error: file or directory "drat2er" exists; please move it out of the way.' >&2
+ exit 1
+fi
+
+git clone https://github.com/alex-ozdemir/drat2er.git
+
+cd drat2er
+
+git checkout api
+
+mkdir build
+
+cd build
+
+cmake .. -DCMAKE_INSTALL_PREFIX=$(pwd)/install
+
+make install
+
+echo
+echo ===================== Now configure CVC4 with =====================
+echo ./configure.sh --drat2er
diff --git a/proofs/signatures/drat.plf b/proofs/signatures/drat.plf
new file mode 100644
index 000000000..d52586bc9
--- /dev/null
+++ b/proofs/signatures/drat.plf
@@ -0,0 +1,224 @@
+; Depends on lrat.plf
+;
+; Implementation of DRAT checking.
+;
+; Unfortunately, there are **two** different notions of DRAT floating around in
+; the world:
+; * Specified DRAT : This is a reasonable proof format
+; * Operational DRAT : This is a variant of specified DRAT warped by the
+; details of common SAT solver architectures.
+;
+; Both are detailed in this paper, along with their differences:
+; http://fmv.jku.at/papers/RebolaPardoBiere-POS18.pdf
+;
+; This signature checks **Specified DRAT**.
+
+(declare cnf_holds (! c cnf type))
+(declare cnfn_proof (cnf_holds cnfn))
+(declare cnfc_proof
+ (! c clause
+ (! deduped_c clause
+ (! rest cnf
+ (! proof_c (holds c)
+ (! proof_rest (cnf_holds rest)
+ (! sc (^ (clause_dedup c) deduped_c)
+ (cnf_holds (cnfc c rest)))))))))
+
+; A DRAT proof itself: a list of addition or deletion instructions.
+(declare DRATProof type)
+(declare DRATProofn DRATProof)
+(declare DRATProofa (! c clause (! p DRATProof DRATProof)))
+(declare DRATProofd (! c clause (! p DRATProof DRATProof)))
+
+; ==================== ;
+; Functional Programs ;
+; ==================== ;
+
+; Are two clauses equal (in the set sense)
+;
+; Since clauses are sets, it is insufficient to do list equality
+; We could sort them, but that would require defining an order on our variables,
+; and incurring the cost of sorting.
+; Instead, we do the following:
+; 1. Sweep the first clause, marking variables with flags 1 (pos) and 2 (neg)
+; 2. Sweep the second clause, erasing marks.
+; 3. Unsweep the first clause, returning FALSE on marks.
+; Also unmarking
+; TODO(aozdemir) This implementation could be further optimized b/c once c1 is
+; drained, we need not continue to pattern match on it.
+(program clause_eq ((c1 clause) (c2 clause)) bool
+ (match
+ c1
+ (cln (match
+ c2
+ (cln tt)
+ ((clc c2h c2t) (match
+ c2h
+ ((pos v) (ifmarked1
+ v
+ (do (markvar1 v) (clause_eq c1 c2t))
+ ff))
+ ((neg v) (ifmarked2
+ v
+ (do (markvar2 v) (clause_eq c1 c2t))
+ ff))))))
+ ((clc c1h c1t) (match
+ c1h
+ ((pos v) (do
+ (markvar1 v)
+ (let res (clause_eq c1t c2)
+ (ifmarked1
+ v
+ (do (markvar1 v) ff)
+ res))))
+ ((neg v) (do
+ (markvar2 v)
+ (let res (clause_eq c1t c2)
+ (ifmarked2
+ v
+ (do (markvar2 v) ff)
+ res))))))))
+
+; Does this formula contain bottom as one of its clauses?
+(program cnf_has_bottom ((cs cnf)) bool
+ (match cs
+ (cnfn ff)
+ ((cnfc c rest) (match c
+ (cln tt)
+ ((clc l c') (cnf_has_bottom rest))))))
+
+; Return a new cnf with one copy of this clause removed.
+(program cnf_remove_clause ((c clause) (cs cnf)) cnf
+ (match cs
+ (cnfn (fail cnf))
+ ((cnfc c' cs')
+ (match (clause_eq c c')
+ (tt cs')
+ (ff (cnfc c' (cnf_remove_clause c cs')))))))
+
+; return (c1 union (c2 \ ~l))
+; Significant for how a RAT is defined.
+(program clause_pseudo_resolvent ((c1 clause) (c2 clause)) clause
+ (clause_dedup (clause_append c1
+ (clause_remove_all
+ (lit_flip (clause_head c1)) c2))))
+
+; Given a formula, `cs` and a clause `c`, return all pseudo resolvents, i.e. all
+; (c union (c' \ ~head(c)))
+; for c' in cs, where c' contains ~head(c)
+(program collect_pseudo_resolvents ((cs cnf) (c clause)) cnf
+ (match cs
+ (cnfn cnfn)
+ ((cnfc c' cs')
+ (let rest_of_resolvents (collect_pseudo_resolvents cs' c)
+ (match (clause_contains_lit c' (lit_flip (clause_head c)))
+ (tt (cnfc (clause_pseudo_resolvent
+ c
+ c')
+ rest_of_resolvents))
+ (ff rest_of_resolvents))))))
+
+; =============================================================== ;
+; Unit Propegation implementation (manipulates global assignment) ;
+; =============================================================== ;
+; See the lrat file for a description of the global assignment.
+
+; The result of search for a unit clause in
+(declare UnitSearchResult type)
+; There was a unit, and
+; this is the (previously floating) literal that is now satisfied.
+; this is a version of the input cnf with satisfied clauses removed.
+(declare USRUnit (! l lit (! f cnf UnitSearchResult)))
+; There was an unsat clause
+(declare USRBottom UnitSearchResult)
+; There was no unit.
+(declare USRNoUnit UnitSearchResult)
+
+; If a UnitSearchResult is a Unit, containing a cnf, adds this clause to that
+; cnf. Otherwise, returns the UnitSearchResult unmodified.
+(program USR_add_clause ((c clause) (usr UnitSearchResult)) UnitSearchResult
+ (match usr
+ ((USRUnit l f) (USRUnit l (cnfc c f)))
+ (USRBottom USRBottom)
+ (USRNoUnit USRNoUnit)))
+
+; Searches through the clauses, looking for a unit clause.
+; Reads the global assignment. Possibly assigns one variable.
+; Returns
+; USRBottom if there is an unsat clause
+; (USRUnit l f) if there is a unit, with lit l, and
+; f is the cnf with some SAT clauses removed.
+; USRNoUnit if there is no unit
+(program unit_search ((f cnf)) UnitSearchResult
+ (match f
+ (cnfn USRNoUnit)
+ ((cnfc c f')
+ (match (clause_check_unit_and_maybe_mark c)
+ (MRSat (unit_search f'))
+ ((MRUnit l) (USRUnit l f'))
+ (MRUnsat USRBottom)
+ (MRNotUnit (USR_add_clause c (unit_search f')))))))
+
+
+; Given the current global assignment, does the formula `f` imply bottom via
+; unit propegation? Leaves the global assignment in the same state that it was
+; initially.
+(program unit_propegates_to_bottom ((f cnf)) bool
+ (match (unit_search f)
+ (USRBottom tt)
+ ((USRUnit l f') (let result (unit_propegates_to_bottom f')
+ (do (lit_un_mk_sat l)
+ result)))
+ (USRNoUnit ff)))
+
+; ================================== ;
+; High-Level DRAT checking functions ;
+; ================================== ;
+
+; Is this clause an AT?
+(program is_at ((cs cnf) (c clause)) bool
+ (match (is_t c)
+ (tt tt)
+ (ff (do (clause_mk_all_unsat c)
+ (let r (unit_propegates_to_bottom cs)
+ (do (clause_un_mk_all_unsat c)
+ r))))))
+
+; Are all of these clauses ATs?
+(program are_all_at ((cs cnf) (clauses cnf)) bool
+ (match clauses
+ (cnfn tt)
+ ((cnfc c clauses')
+ (match (is_at cs c)
+ (tt (are_all_at cs clauses'))
+ (ff ff)))))
+
+; Is the clause `c` a RAT for the formula `cs`?
+(program is_rat ((cs cnf) (c clause)) bool
+ (match (is_t c)
+ (tt tt)
+ (ff (match (is_at cs c)
+ (tt tt)
+ (ff (are_all_at
+ cs
+ (collect_pseudo_resolvents cs c)))))))
+
+; Is this proof a valid DRAT proof of bottom?
+(program is_drat_proof_of_bottom ((f cnf) (proof DRATProof)) bool
+ (match proof
+ (DRATProofn (cnf_has_bottom f))
+ ((DRATProofa c p) (match
+ (is_rat f c)
+ (tt (is_drat_proof_of_bottom (cnfc c f) p))
+ (ff ff)))
+ ((DRATProofd c p)
+ (is_drat_proof_of_bottom (cnf_remove_clause c f) p))))
+
+
+(declare drat_proof_of_bottom
+ (! f cnf
+ (! proof_of_formula (cnf_holds f)
+ (! proof DRATProof
+ (! sc (^ (is_drat_proof_of_bottom f proof) tt)
+ bottom)))))
+
diff --git a/proofs/signatures/drat_test.plf b/proofs/signatures/drat_test.plf
new file mode 100644
index 000000000..f2f2c7286
--- /dev/null
+++ b/proofs/signatures/drat_test.plf
@@ -0,0 +1,191 @@
+;depends on drat.plf
+(declare check_rat
+ (! f cnf
+ (! c clause
+ (! b bool
+ (! sc (^ (is_rat f c) b)
+ bottom)))))
+
+(declare trust_cnf (! f cnf (cnf_holds f)))
+
+; RAT Test 1
+; Formula: (-p, -a) ^ (-p, b) ^( b, c) ^ (-c, a)
+; Candidate RAT: (p, a)
+; Answer: true
+(check
+ (% va var
+ (% vb var
+ (% vc var
+ (% vp var
+ (check_rat
+ (cnfc (clc (neg vp) (clc (neg va) cln))
+ (cnfc (clc (neg vp) (clc (pos vb) cln))
+ (cnfc (clc (pos vb) (clc (pos vc) cln))
+ (cnfc (clc (neg vc) (clc (pos va) cln)) cnfn))))
+ (clc (pos vp) (clc (pos va) cln))
+ tt))))))
+
+; RAT Test 2
+; Formula:
+; p cnf 4 8
+; 1 2 -3 0
+; -1 -2 3 0
+; 2 3 -4 0
+; -2 -3 4 0
+; -1 -3 -4 0
+; 1 3 4 0
+; -1 2 4 0
+; 1 -2 -4 0
+; Candidate RAT: -1
+(check
+ (% v1 var
+ (% v2 var
+ (% v3 var
+ (% v4 var
+ (check_rat
+ (cnfc (clc (pos v1) (clc (pos v2) (clc (neg v3) cln)))
+ (cnfc (clc (neg v1) (clc (neg v2) (clc (pos v3) cln)))
+ (cnfc (clc (pos v2) (clc (pos v3) (clc (neg v4) cln)))
+ (cnfc (clc (neg v2) (clc (neg v3) (clc (pos v4) cln)))
+ (cnfc (clc (neg v1) (clc (neg v3) (clc (neg v4) cln)))
+ (cnfc (clc (pos v1) (clc (pos v3) (clc (pos v4) cln)))
+ (cnfc (clc (neg v1) (clc (pos v2) (clc (pos v4) cln)))
+ (cnfc (clc (pos v1) (clc (neg v2) (clc (neg v4) cln)))
+ cnfn))))))))
+ (clc (neg v1) cln)
+ tt))))))
+
+; RAT Test 3
+; Formula:
+; p cnf 4 9
+; 1 2 -3 0
+; -1 -2 3 0
+; 2 3 -4 0
+; -2 -3 4 0
+; -1 -3 -4 0
+; 1 3 4 0
+; -1 2 4 0
+; 1 -2 -4 0
+; -1 0
+; Candidate RAT: 2
+(check
+ (% v1 var
+ (% v2 var
+ (% v3 var
+ (% v4 var
+ (check_rat
+ (cnfc (clc (pos v1) (clc (pos v2) (clc (neg v3) cln)))
+ (cnfc (clc (neg v1) (clc (neg v2) (clc (pos v3) cln)))
+ (cnfc (clc (pos v2) (clc (pos v3) (clc (neg v4) cln)))
+ (cnfc (clc (neg v2) (clc (neg v3) (clc (pos v4) cln)))
+ (cnfc (clc (neg v1) (clc (neg v3) (clc (neg v4) cln)))
+ (cnfc (clc (pos v1) (clc (pos v3) (clc (pos v4) cln)))
+ (cnfc (clc (neg v1) (clc (pos v2) (clc (pos v4) cln)))
+ (cnfc (clc (pos v1) (clc (neg v2) (clc (neg v4) cln)))
+ (cnfc (clc (neg v1) cln)
+ cnfn)))))))))
+ (clc (pos v2) cln)
+ tt))))))
+
+; RAT Test 4
+; Formula:
+; p cnf 4 2
+; 2 -3 0
+; 1 -4 0
+; Candidate RAT: 3
+; Answer: false
+(check
+ (% v1 var
+ (% v2 var
+ (% v3 var
+ (% v4 var
+ (check_rat
+ (cnfc (clc (pos v2) (clc (neg v3) cln))
+ (cnfc (clc (pos v1) (clc (neg v4) cln)) cnfn))
+ (clc (pos v3) cln)
+ ff))))))
+
+
+; DRAT Test 1 (from Example 1 @ https://www.cs.utexas.edu/~marijn/drat-trim/)
+; without deletions
+; Formula:
+; p cnf 4 8
+; 1 2 -3 0
+; -1 -2 3 0
+; 2 3 -4 0
+; -2 -3 4 0
+; -1 -3 -4 0
+; 1 3 4 0
+; -1 2 4 0
+; 1 -2 -4
+; Proof:
+; -1 0
+; 2 0
+; 0
+(check
+ (% v1 var
+ (% v2 var
+ (% v3 var
+ (% v4 var
+ (:
+ (holds cln)
+ (drat_proof_of_bottom _
+ (trust_cnf (cnfc (clc (pos v1) (clc (pos v2) (clc (neg v3) cln)))
+ (cnfc (clc (neg v1) (clc (neg v2) (clc (pos v3) cln)))
+ (cnfc (clc (pos v2) (clc (pos v3) (clc (neg v4) cln)))
+ (cnfc (clc (neg v2) (clc (neg v3) (clc (pos v4) cln)))
+ (cnfc (clc (neg v1) (clc (neg v3) (clc (neg v4) cln)))
+ (cnfc (clc (pos v1) (clc (pos v3) (clc (pos v4) cln)))
+ (cnfc (clc (neg v1) (clc (pos v2) (clc (pos v4) cln)))
+ (cnfc (clc (pos v1) (clc (neg v2) (clc (neg v4) cln)))
+ cnfn)))))))))
+ (DRATProofa (clc (neg v1) cln)
+ (DRATProofa (clc (pos v2) cln)
+ (DRATProofa cln
+ DRATProofn))))))))))
+
+
+; DRAT Test 2 (from Example 1 @ https://www.cs.utexas.edu/~marijn/drat-trim/)
+; with deletions
+; Formula:
+; p cnf 4 8
+; 1 2 -3 0
+; -1 -2 3 0
+; 2 3 -4 0
+; -2 -3 4 0
+; -1 -3 -4 0
+; 1 3 4 0
+; -1 2 4 0
+; 1 -2 -4
+; Proof:
+; -1 0
+; d -1 -2 3 0
+; d -1 -3 -4 0
+; d -1 2 4 0
+; 2 0
+; d 1 2 -3 0
+; d 2 3 -4 0
+; 0
+(check
+ (% v1 var (% v2 var (% v3 var (% v4 var
+ (: (holds cln)
+ (drat_proof_of_bottom _
+ (trust_cnf
+ (cnfc (clc (pos v1) (clc (pos v2) (clc (neg v3) cln)))
+ (cnfc (clc (neg v1) (clc (neg v2) (clc (pos v3) cln)))
+ (cnfc (clc (pos v2) (clc (pos v3) (clc (neg v4) cln)))
+ (cnfc (clc (neg v2) (clc (neg v3) (clc (pos v4) cln)))
+ (cnfc (clc (neg v1) (clc (neg v3) (clc (neg v4) cln)))
+ (cnfc (clc (pos v1) (clc (pos v3) (clc (pos v4) cln)))
+ (cnfc (clc (neg v1) (clc (pos v2) (clc (pos v4) cln)))
+ (cnfc (clc (pos v1) (clc (neg v2) (clc (neg v4) cln)))
+ cnfn)))))))))
+ (DRATProofa (clc (neg v1) cln)
+ (DRATProofd (clc (neg v1) (clc (neg v2) (clc (pos v3) cln)))
+ (DRATProofd (clc (neg v1) (clc (neg v3) (clc (neg v4) cln)))
+ (DRATProofd (clc (neg v1) (clc (pos v2) (clc (pos v4) cln)))
+ (DRATProofa (clc (pos v2) cln)
+ (DRATProofd (clc (pos v1) (clc (pos v2) (clc (neg v3) cln)))
+ (DRATProofd (clc (pos v2) (clc (pos v3) (clc (neg v4) cln)))
+ (DRATProofa cln
+ DRATProofn)))))))))))))))
diff --git a/proofs/signatures/lrat.plf b/proofs/signatures/lrat.plf
new file mode 100644
index 000000000..5224cf3ce
--- /dev/null
+++ b/proofs/signatures/lrat.plf
@@ -0,0 +1,594 @@
+; LRAT Proof signature
+; LRAT format detailed in "Efficient Certified RAT Verification"
+; Link: https://www.cs.utexas.edu/~marijn/publications/lrat.pdf
+; Author: aozdemir
+; Depends On: sat.plf, smt.plf
+
+
+; A general note about the design of the side conditions:
+; Some side-conditions make use of a _global assignment_ encoded in
+; 0 (true) / 1 (false) marks on variables.
+
+; A list of clauses, CNF if interpretted as a formula,
+; but also sometimes just a list
+(declare cnf type)
+(declare cnfn cnf)
+(declare cnfc (! h clause (! t cnf cnf)))
+
+; Unit (https://en.wikipedia.org/wiki/Unit_type)
+; For functions that don't return anything
+(declare Unit type) ; The type with only one value (like `void` in C)
+(declare unit Unit) ; That value
+
+; Boolean operator (not short-circuiting)
+(program bool_or ((l bool) (r bool)) bool (match l (ff r) (tt tt)))
+(program bool_and ((l bool) (r bool)) bool (match l (tt r) (ff ff)))
+(program bool_not ((b bool)) bool (match b (tt ff) (ff tt)))
+
+; =================== ;
+; Working CNF formula ;
+; =================== ;
+
+; Represents a CNF formula as a map from clause indices to clauses
+; Should be sorted ascending, always!
+; Here, and for all collections, the suffix "n" denotes the empty collection and
+; the suffix "c" denotes the constructor for the collection in the style of lisp's
+; "cons cells"
+(declare CMap type)
+(declare CMapn CMap)
+(declare CMapc (! i mpz (! c clause (! r CMap CMap))))
+
+; ================= ;
+; LRAT Proof Format ;
+; ================= ;
+
+; CI lists are lists of clause indices.
+; They represent clauses to delete.
+; They must be sorted.
+(declare CIList type)
+(declare CIListn CIList)
+(declare CIListc (! z mpz (! zs CIList CIList)))
+
+; Traces are a list of clause indices into the working CNF formula
+; They represent the clauses that will be unit in a unit propegation to bottom
+; Thus their elements are *not* in value order.
+(declare Trace type)
+(declare Tracen Trace)
+(declare Tracec (! z mpz (! zs Trace Trace)))
+
+; RAT Hint list
+; Each hint is
+; * An index indicating a clause in the working CNF formula to resolve with
+; * A trace indicating how UP should be done after that resolution
+(declare RATHints type)
+(declare RATHintsn RATHints)
+(declare RATHintsc
+ (! target mpz
+ (! trace Trace
+ (! rest RATHints
+ RATHints))))
+
+; LRAT proof
+(declare LRATProof type)
+(declare LRATProofn LRATProof)
+; Deletion (includes a list of clause indices to delete)
+(declare LRATProofd (! cis CIList (! rest LRATProof LRATProof)))
+; Addition: a clause index, a clause, RUP trace for that clause, and hints for
+; what resolutions should happen then, and how those resolutions imply bottom
+; via UP.
+; If the list of hints is empty, then bottom is already implied.
+(declare LRATProofa
+ (! ci mpz
+ (! c clause
+ (! t Trace
+ (! h RATHints
+ (! rest LRATProof
+ LRATProof))))))
+
+; ========================================== ;
+; Functional programs for manipulating types ;
+; ========================================== ;
+
+; Flip the polarity of the literal
+(program lit_flip ((l lit)) lit
+ (match l
+ ((pos v) (neg v))
+ ((neg v) (pos v))))
+
+; Are two literal equal?
+(program lit_eq ((l1 lit) (l2 lit)) bool
+ (match l1
+ ((pos v1) (match l2
+ ((pos v2) (ifequal v1 v2 tt ff))
+ ((neg v2) ff)))
+ ((neg v1) (match l2
+ ((pos v2) ff)
+ ((neg v2) (ifequal v1 v2 tt ff))))))
+
+; Remove **all** occurences of a literal from clause
+(program clause_remove_all ((l lit) (c clause)) clause
+ (match c
+ (cln cln)
+ ((clc l' c')
+ (let rest_res (clause_remove_all l c')
+ (match (lit_eq l l')
+ (tt rest_res)
+ (ff (clc l' rest_res)))))))
+
+; Return the clause's first literal
+; fails on an empty clause
+(program clause_head ((c clause)) lit
+ (match c
+ (cln (fail lit))
+ ((clc l c') l)))
+
+; Does a clause contain some literal?
+(program clause_contains_lit ((c clause) (l lit)) bool
+ (match c
+ ((clc l' c') (match (lit_eq l l')
+ (tt tt)
+ (ff (clause_contains_lit c' l))))
+ (cln ff)))
+
+; Returns a copy of `c` with any duplicate literals removed.
+; Never fails.
+; Uses marks 3 & 4. Expects them to be clear before hand, and leaves them clear
+; afterwards.
+(program clause_dedup ((c clause)) clause
+ (match c
+ (cln cln)
+ ((clc l rest)
+ (match l
+ ((pos v) (ifmarked3
+ v
+ (clause_dedup rest)
+ (do (markvar3 v)
+ (let result (clc (pos v) (clause_dedup rest))
+ (do (markvar3 v) result)))))
+ ((neg v) (ifmarked4
+ v
+ (clause_dedup rest)
+ (do (markvar4 v)
+ (let result (clc (neg v) (clause_dedup rest))
+ (do (markvar4 v) result)))))))))
+
+; Append two traces
+(program Trace_concat ((t1 Trace) (t2 Trace)) Trace
+ (match t1
+ (Tracen t2)
+ ((Tracec h1 r1) (Tracec h1 (Trace_concat r1 t2)))))
+
+; Return whether a list of RAT hits is empty
+(program RATHints_is_empty ((h RATHints)) bool
+ (match h
+ (RATHintsn tt)
+ ((RATHintsc a b c) ff)))
+
+; Insert into a CMap, preserving order
+(program CMap_insert ((i mpz) (c clause) (cs CMap)) CMap
+ (match cs
+ (CMapn (CMapc i c CMapn))
+ ((CMapc i' c' r)
+ (mp_ifneg (mpz_sub i i')
+ (CMapc i c cs)
+ (CMapc i' c' (CMap_insert i c r))))))
+
+; Get from a CMap
+(program CMap_get ((i mpz) (cs CMap)) clause
+ (match cs
+ (CMapn (fail clause))
+ ((CMapc i' c r)
+ (mp_ifzero (mpz_sub i i')
+ c
+ (CMap_get i r)))))
+
+; Remove from CMap. Only removes one element.
+(program CMap_remove ((i mpz) (cs CMap)) CMap
+ (match cs
+ (CMapn CMapn)
+ ((CMapc i' c r)
+ (mp_ifzero (mpz_sub i i')
+ r
+ (CMapc i' c (CMap_remove i r))))))
+
+; Remove many indices from a CMap. Asuumes the input list is sorted.
+(program CMap_remove_many ((is CIList) (cs CMap)) CMap
+ (match
+ is
+ (CIListn cs)
+ ((CIListc i is')
+ (match
+ cs
+ (CMapn (fail CMap)) ; All deletion indices must be valid!
+ ((CMapc ci c cs')
+ (mp_ifzero (mpz_sub i ci)
+ (CMap_remove_many is' cs')
+ (CMapc ci c (CMap_remove_many is cs'))))))))
+
+; Given a map of clauses and a literal, return all indices in the map
+; corresponsing to clauses that could resolve against that literal. i.e. for x,
+; return the indices of all clauses containing x.
+(program collect_resolution_targets_w_lit ((cs CMap) (l lit)) CIList
+ (match cs
+ (CMapn CIListn)
+ ((CMapc i c cs')
+ (let rest_solution (collect_resolution_targets_w_lit cs' l)
+ (match (clause_contains_lit c l)
+ (tt (CIListc i rest_solution))
+ (ff rest_solution))))))
+
+; Given a clause and a maps of clauses, return all indices in the map
+; corresponding to clauses which could resolve with this one on its first
+; literal
+(program collect_resolution_targets ((cs CMap) (c clause)) CIList
+ (collect_resolution_targets_w_lit cs (lit_flip (clause_head c))))
+
+; Is this clause a tautology?
+; Internally uses mark 5 to flag variables that occur (+)
+; and mark 6 to flag variables that occur (-)
+(program is_t ((c clause)) bool
+ (match
+ c
+ (cln ff)
+ ((clc l c') (match
+ l
+ ((pos v)
+ (ifmarked5
+ v
+ (is_t c')
+ (ifmarked6
+ v
+ tt
+ (do
+ (markvar5 v)
+ (let r (is_t c') (do (markvar5 v) r))))))
+ ((neg v)
+ (ifmarked6
+ v
+ (is_t c')
+ (ifmarked5
+ v
+ tt
+ (do
+ (markvar6 v)
+ (let r (is_t c') (do (markvar6 v) r))))))))))
+
+; ===================================================================== ;
+; Programs for manipulating and querying the global variable assignment ;
+; ===================================================================== ;
+
+; This assignment marks values of type `var`.
+; It marks a variable with 1 if that variable is true
+; It marks a variable with 2 if that variable is false
+; A variable should not be marked with both!
+; A variable may be marked with neither, indicating that variable is presently
+; unassigned, which we call "floating".
+
+; Mark the variable within to satisfy this literal.
+; fails if the literal is already UNSAT
+(program lit_mk_sat ((l lit)) Unit
+ (match l
+ ((pos v) (ifmarked2 v
+ (fail Unit)
+ (ifmarked1 v unit (do (markvar1 v) unit))))
+ ((neg v) (ifmarked1 v
+ (fail Unit)
+ (ifmarked2 v unit (do (markvar2 v) unit))))))
+
+; Mark the variable within to falsify this literal.
+; fails is the literal is already SAT
+(program lit_mk_unsat ((l lit)) Unit
+ (match l
+ ((neg v) (ifmarked2 v
+ (fail Unit)
+ (ifmarked1 v unit (do (markvar1 v) unit))))
+ ((pos v) (ifmarked1 v
+ (fail Unit)
+ (ifmarked2 v unit (do (markvar2 v) unit))))))
+
+; Unmarks the variable within a satified literal to render it neither satified nor falsified
+; fails if the literal is not already satisfied
+(program lit_un_mk_sat ((l lit)) Unit
+ (match l
+ ((pos v) (ifmarked1 v (do (markvar1 v) unit) (fail Unit)))
+ ((neg v) (ifmarked2 v (do (markvar2 v) unit) (fail Unit)))))
+
+; Unmarks the variable within a falsified literal to render it neither satified nor falsified
+; fails if the literal is not already falsified
+(program lit_un_mk_unsat ((l lit)) Unit
+ (match l
+ ((pos v) (ifmarked2 v (do (markvar2 v) unit) (fail Unit)))
+ ((neg v) (ifmarked1 v (do (markvar1 v) unit) (fail Unit)))))
+
+; Is a literal presently satisfied?
+(program lit_is_sat ((l lit)) bool
+ (match l
+ ((pos v) (ifmarked1 v tt ff))
+ ((neg v) (ifmarked2 v tt ff))))
+
+; Is a literal presently falsified?
+(program lit_is_unsat ((l lit)) bool
+ (match l
+ ((pos v) (ifmarked2 v tt ff))
+ ((neg v) (ifmarked1 v tt ff))))
+
+; Is a literal presently neither satisfied nor falsified?
+(program lit_is_floating ((l lit)) bool
+ (bool_not (bool_or (lit_is_sat l) (lit_is_unsat l))))
+
+; Does this clause contain a floating literal?
+(program clause_has_floating ((c clause)) bool
+ (match c
+ (cln ff)
+ ((clc l c') (match (lit_is_floating l)
+ (tt tt)
+ (ff (clause_has_floating c'))))))
+
+; Is this clause falsified? i.e. are all its clauses falsified?
+(program clause_is_unsat ((c clause)) bool
+ (match c
+ (cln tt)
+ ((clc l c') (match (lit_is_unsat l)
+ (tt (clause_is_unsat c'))
+ (ff ff)))))
+
+; Is this clause presently satisfied?
+(program clause_is_sat ((c clause)) bool
+ (match c
+ (cln ff)
+ ((clc l c') (match (lit_is_sat l)
+ (tt tt)
+ (ff (clause_is_sat c'))))))
+
+; Falsify **all** contained literals.
+; Fails on a tautological clause
+(program clause_mk_all_unsat ((c clause)) Unit
+ (match c
+ (cln unit)
+ ((clc l c') (do
+ (lit_mk_unsat l)
+ (clause_mk_all_unsat c')))))
+
+; Unfalsifies **all** contained literals
+; Fails on a clause with duplicate literals
+(program clause_un_mk_all_unsat ((c clause)) Unit
+ (match c
+ (cln unit)
+ ((clc l c') (do
+ (lit_un_mk_unsat l)
+ (clause_un_mk_all_unsat c')))))
+
+; Get the first floating literal out of this clause.
+; fails if there are no floating literals
+(program clause_first_floating ((c clause)) lit
+ (match c
+ (cln (fail lit))
+ ((clc l c') (match (lit_is_floating l)
+ (tt l)
+ (ff (clause_first_floating c'))))))
+
+; ===================================== ;
+; High-Level Programs for LRAT Checking ;
+; ===================================== ;
+
+; The return type for verifying that a clause is unit and modifying the global
+; assignment to satisfy it
+(declare MarkResult type)
+; The clause is unit, and this is the (previoiusly floating) literal that is now satified.
+(declare MRUnit (! l lit MarkResult))
+; The clause was unsat!
+(declare MRUnsat MarkResult)
+; The clauss was already satisfied.
+(declare MRSat MarkResult)
+; The clause had multiple floating literals.
+(declare MRNotUnit MarkResult)
+
+; Determine wether this clause is sat, unsat, unit, or not unit, and if it is
+; unit, it modifies the global assignment to satisfy the clause, and returns
+; the literal that was made SAT by the new mark.
+;
+; Fails if `c` is a TAUT
+(program clause_check_unit_and_maybe_mark ((c clause)) MarkResult
+ (match (clause_is_sat c)
+ (tt MRSat)
+ (ff (match (clause_is_unsat c)
+ (tt MRUnsat)
+ (ff (match (is_t c)
+ (tt (fail MarkResult))
+ (ff ; Dedent
+ (match (clause_has_floating c)
+ (tt (let first (clause_first_floating c)
+ (do (lit_mk_sat first)
+ (match (clause_has_floating c)
+ (tt (do (lit_un_mk_sat first) MRNotUnit))
+ (ff (MRUnit first))))))
+ ; Unreachable. If clause is not floating it must have been SAT or UNSAT.
+ (ff (fail MarkResult))
+ ))))))))
+
+; The return type for the process of Trace-guided unit propegation
+(declare UPResult type)
+; The trace guided unit propegation correctly, but that unit propegation did not end in an empty clause
+(declare UPR_Ok UPResult)
+; The trace guided unit propegation correctly to an empty clause
+(declare UPR_Bottom UPResult)
+; The trace was malformed,
+;; i.e. at some point indicates that a non-unit, non-empty clause should be examined
+(declare UPR_Broken UPResult)
+
+; Execute the unit propegation indicated by the trace. Report whether that
+; unit propegation succeeds and produces bottom, fails, or succeeds but does
+; not produce bottom.
+;
+; If the trace tries to propegate through a TAUT clause, fails.
+(program do_up ((cs CMap) (t Trace)) UPResult
+ (match
+ t
+ (Tracen UPR_Ok)
+ ((Tracec i r) (match (clause_check_unit_and_maybe_mark (CMap_get i cs))
+ ((MRUnit l)
+ (let res (do_up cs r)
+ (do (lit_un_mk_sat l) res)))
+ (MRUnsat UPR_Bottom)
+ (MRSat UPR_Broken)
+ (MRNotUnit UPR_Broken)))))
+
+
+; Determine whether a list of indices agrees with the list of indices latent in
+; a list of hints. Both lists should be sorted.
+(program resolution_targets_match (
+ (computed CIList)
+ (given RATHints)) bool
+ (match given
+ (RATHintsn
+ (match computed
+ (CIListn tt)
+ ((CIListc a b) ff)))
+ ((RATHintsc hint_idx t given')
+ (match computed
+ ((CIListc comp_idx computed')
+ (mp_ifzero (mpz_sub hint_idx comp_idx)
+ (resolution_targets_match computed' given')
+ (ff)))
+ (CIListn ff)))))
+
+
+; Determines whether `t` is a witness that `c` is an Assymetric Tautology in `cs`.
+;
+; Does unit propegation in the formula `cs`, beginning by falsifying
+; all literals in `c`, and then looking at the clauses indicated by `t`.
+; Assumes no marks, and cleans up marks afterwards.
+;
+; Fails if `c` has duplicates
+(program is_at_trace ((cs CMap) (c clause) (t Trace)) UPResult
+ (match (is_t c)
+ (ff
+ (do
+ (clause_mk_all_unsat c)
+ (let result (do_up cs t)
+ (do (clause_un_mk_all_unsat c) result))))
+ (tt
+ UPR_Bottom)))
+
+
+
+; List of (clause, trace) pairs
+(declare CTPairs type)
+(declare CTPn CTPairs)
+(declare CTPc (! c clause (! t Trace (! rest CTPairs CTPairs))))
+
+; For each RAT hint, construct the pseudo-resolvant for that hint, and the net
+; trace for that hint. Return a list of these.
+;
+; Pseudo resolvant: if l v C is the clause, and D is another clause containing
+; ~l, then l v C v (D \ ~l) is the pseudo-resolvant, which is the actual
+; resolant, plut l, which would be implied by UP.
+;
+; The net trace is the global trace (`t`), plut the trace for that specific
+; resolvant.
+(program construct_ct_pairs (
+ (cs CMap)
+ (c clause)
+ (t Trace)
+ (hints RATHints)
+ ) CTPairs
+ (match hints
+ (RATHintsn CTPn)
+ ((RATHintsc i ht hints')
+ (CTPc
+ (clause_dedup (clause_append c
+ (clause_remove_all (lit_flip (clause_head c))
+ (CMap_get i cs))))
+ (Trace_concat t ht)
+ (construct_ct_pairs cs c t hints')))))
+
+; Goes through a list of clause, trace pairs and verifies that each clause is
+; an AT via that trace.
+; Fails if any putative AT is a TAUT or contains duplicates
+(program are_all_at_trace (
+ (cs CMap)
+ (l CTPairs)
+ ) UPResult
+ (match l
+ (CTPn UPR_Bottom)
+ ((CTPc c t l')
+ (match (is_at_trace cs c t)
+ (UPR_Ok UPR_Ok)
+ (UPR_Broken UPR_Broken)
+ (UPR_Bottom (are_all_at_trace cs l'))))))
+
+; Is this trace, and list of hints, proof that `c` is an Resolution Assymeytic
+; Tautology?
+; Fails is the hints are empty (which means `c` should be AT) and `c` contains
+; duplicates)
+(program is_rat_trace ((cs CMap) (c clause) (t Trace) (hints RATHints)) UPResult
+ (match
+ (RATHints_is_empty hints)
+ (tt ; Empty RAT hints -- the clause must be AT
+ (is_at_trace cs c t))
+ (ff ; Ew -- we must verify this is a RAT
+ (match (resolution_targets_match
+ (collect_resolution_targets cs c)
+ hints)
+ (ff ; Resolution targets disagree with hints.
+ UPR_Broken)
+ (tt
+ (are_all_at_trace cs (construct_ct_pairs cs c t hints)))))))
+
+; Is this proof an LRAT proof of bottom?
+; Fails if any added AT is a TAUT or contains duplicates OR if any added RAT
+; produces pseudo-resolvants which are TAUT or contain duplicates
+(program is_lrat_proof_of_bottom ((f CMap) (proof LRATProof)) bool
+ (match proof
+ ((LRATProofd indices rest)
+ (is_lrat_proof_of_bottom
+ (CMap_remove_many indices f)
+ rest))
+ ((LRATProofa idx c trace hints rest)
+ (match (is_rat_trace f c trace hints)
+ (UPR_Bottom
+ (match
+ c
+ (cln tt)
+ ((clc a b)
+ (is_lrat_proof_of_bottom (CMap_insert idx c f) rest))))
+ (UPR_Ok ff)
+ (UPR_Broken ff)))
+ (LRATProofn ff))
+ )
+
+
+; Proof of a CMap from clause proofs.
+; The idx is unelidable b/c it is unspecified.
+; Robust against clauses with duplicat literals, but not against tautological
+; clauses.
+(declare CMap_holds (! c CMap type))
+(declare CMapn_proof (CMap_holds CMapn))
+(declare CMapc_proof
+ (! idx mpz ; Not elidable!
+ (! c clause
+ (! deduped_c clause
+ (! rest CMap
+ (! proof_c (holds c)
+ (! proof_rest (CMap_holds rest)
+ (! sc (^ (clause_dedup c) deduped_c)
+ (CMap_holds (CMapc idx deduped_c rest))))))))))
+
+(define bottom (holds cln))
+(declare lrat_proof_of_bottom
+ (! cm CMap
+ (! proof_cm (CMap_holds cm)
+ (! proof LRATProof
+ (! sc (^ (is_lrat_proof_of_bottom cm proof) tt)
+ bottom)))))
+
+
+; TODO(aozdemir) Reducing the amount of checking that resides in side-conditions.
+; Steps
+; 1. Unroll the traversal of is_lrat_proof_of_bottom into a serialized
+; sequence of axiom applications.
+; The axioms would likely correspond to DELETE, IS T, IS AT, IS RAT.
+; They would manipulate a CMap by way of side-conditions.
+; 2. Unroll AT checks by manifesting the assignment in data rather than marks,
+; and having axioms like IS_UNSAT, IS_UNIT_ON_LITERAL.
+; 3. Unroll RAT checks in a similar fashion, although more painfully.
diff --git a/proofs/signatures/lrat_test.plf b/proofs/signatures/lrat_test.plf
new file mode 100644
index 000000000..0663a08f7
--- /dev/null
+++ b/proofs/signatures/lrat_test.plf
@@ -0,0 +1,891 @@
+(declare test_clause_append
+ (! c1 clause
+ (! c2 clause
+ (! cr clause
+ (! sc (^ (clause_append c1 c2) cr) type)))))
+
+; Test passes if the (test_clause_append ...) application is well-typed.
+(check
+ (% v1 var
+ (% v2 var
+ (% v3 var
+ (test_clause_append
+ (clc (pos v1) (clc (neg v2) cln))
+ (clc (pos v3) (clc (neg v2) cln))
+ (clc (pos v1) (clc (neg v2) (clc (pos v3) (clc (neg v2) cln))))
+ )
+ )))
+)
+
+; Test passes if the (test_clause_append ...) application is well-typed.
+(check
+ (% v2 var
+ (% v3 var
+ (test_clause_append
+ cln
+ (clc (pos v3) (clc (neg v2) cln))
+ (clc (pos v3) (clc (neg v2) cln))
+ )
+ ))
+)
+
+; Test passes if the (test_clause_append ...) application is well-typed.
+(check
+ (% v2 var
+ (% v3 var
+ (test_clause_append
+ (clc (pos v3) (clc (neg v2) cln))
+ cln
+ (clc (pos v3) (clc (neg v2) cln))
+ )
+ ))
+)
+
+(declare test_CMap_remove_many
+ (! is CIList
+ (! cs CMap
+ (! csr CMap
+ (! sc (^ (CMap_remove_many is cs) csr) type)))))
+
+; Test passes if the (test_CMap_remove_many ...) application is well-typed.
+(check
+ (% v1 var
+ (% v2 var
+ (% v3 var
+ (% v4 var
+ (@ c1 (clc (pos v4) (clc (neg v2) cln))
+ (@ c2 (clc (neg v3) (clc (neg v1) cln))
+ (@ c3 (clc (neg v2) (clc (pos v3) cln))
+ (@ c4 (clc (neg v3) (clc (neg v4) cln))
+ (@ cs_in (CMapc 0 c1 (CMapc 3 c2 (CMapc 4 c3 (CMapc 5 c3 (CMapc 6 c4 CMapn)))))
+ (@ cs_out (CMapc 3 c2 (CMapc 5 c3 CMapn))
+ (@ is_in (CIListc 0 (CIListc 4 (CIListc 6 CIListn)))
+ (test_CMap_remove_many
+ is_in
+ cs_in
+ cs_out
+ )
+ )))
+ ))))
+ ))))
+)
+
+; Test passes if the (test_CMap_remove_many ...) application is well-typed.
+(check
+ (% v1 var
+ (% v2 var
+ (% v3 var
+ (% v4 var
+ (@ c1 (clc (pos v4) (clc (neg v2) cln))
+ (@ c2 (clc (neg v3) (clc (neg v1) cln))
+ (@ c3 (clc (neg v2) (clc (pos v3) cln))
+ (@ c4 (clc (neg v3) (clc (neg v4) cln))
+ (@ cs_in (CMapc 0 c1 (CMapc 3 c2 (CMapc 4 c3 (CMapc 5 c3 (CMapc 6 c4 CMapn)))))
+ (@ cs_out (CMapc 0 c1 (CMapc 3 c2 (CMapc 5 c3 (CMapc 6 c4 CMapn))))
+ (@ is_in (CIListc 4 CIListn)
+ (test_CMap_remove_many
+ is_in
+ cs_in
+ cs_out
+ )
+ )))
+ ))))
+ ))))
+)
+
+(declare test_clause_remove_all
+ (! l lit
+ (! c clause
+ (! c' clause
+ (! sc (^ (clause_remove_all l c) c') type)))))
+
+; Test passes if the (test_clause_remove_all ...) application is well-typed.
+(check
+ (% v1 var
+ (% v2 var
+ (% v3 var
+ (% v4 var
+ (@ c1 (clc (pos v4) (clc (neg v2) (clc (neg v2) (clc (pos v2) (clc (pos v1) cln)))))
+ (@ c2 (clc (pos v4) (clc (pos v2) (clc (pos v1) cln)))
+ (test_clause_remove_all
+ (neg v2)
+ c1
+ c2
+ )
+ ))
+ ))))
+)
+
+(declare test_collect_resolution_targets
+ (! cs CMap
+ (! c clause
+ (! is CIList
+ (! sc (^ (collect_resolution_targets cs c) is) type)))))
+
+; Test passes if the (test_collect_resolution_targets ...) application is well-typed.
+(check
+ (% v1 var
+ (% v2 var
+ (% v3 var
+ (% v4 var
+ (@ c1 (clc (pos v3) (clc (neg v2) cln))
+ (@ c2 (clc (neg v3) (clc (neg v1) cln))
+ (@ c3 (clc (neg v2) (clc (pos v3) cln))
+ (@ c4 (clc (neg v3) (clc (pos v3) cln))
+ (@ ct (clc (neg v3) (clc (neg v4) cln))
+ (@ cs_in (CMapc 0 c1 (CMapc 3 c2 (CMapc 4 c3 (CMapc 5 c3 (CMapc 6 c4 CMapn)))))
+ (@ is_out (CIListc 0 (CIListc 4 (CIListc 5 (CIListc 6 CIListn))))
+ (test_collect_resolution_targets
+ cs_in
+ ct
+ is_out
+ )
+ )))
+ ))))
+ ))))
+)
+
+(declare test_resolution_targets_match
+ (! c CIList
+ (! g RATHints
+ (! ans bool
+ (! sc (^ (resolution_targets_match c g) ans) type)))))
+
+; Test passes if the (test_resolution_targets_match ...) application is well-typed.
+(check
+ (@ idxs_in (CIListc 0 (CIListc 4 (CIListc 5 (CIListc 6 CIListn))))
+ (@ hints_in
+ (RATHintsc 0 Tracen
+ (RATHintsc 4 Tracen
+ (RATHintsc 5 Tracen
+ (RATHintsc 6 Tracen
+ RATHintsn))))
+ (test_resolution_targets_match
+ idxs_in
+ hints_in
+ tt
+ )
+ ))
+)
+
+; Test passes if the (test_resolution_targets_match ...) application is well-typed.
+(check
+ (@ idxs_in (CIListc 0 (CIListc 2 (CIListc 5 (CIListc 6 CIListn))))
+ (@ hints_in
+ (RATHintsc 0 Tracen
+ (RATHintsc 4 Tracen
+ (RATHintsc 5 Tracen
+ (RATHintsc 6 Tracen
+ RATHintsn))))
+ (test_resolution_targets_match
+ idxs_in
+ hints_in
+ ff
+ )
+ ))
+)
+
+(declare test_is_at_trace
+ (! cs CMap
+ (! c clause
+ (! t Trace
+ (! r UPResult
+ (! sc (^ (is_at_trace cs c t) r) type))))))
+
+; Test passes if the (test_is_at_trace ...) application is well-typed.
+(check
+ (% v1 var
+ (% v2 var
+ (% v3 var
+ (% v4 var
+ (@ c1 (clc (pos v3) (clc (neg v2) cln))
+ (@ c2 (clc (neg v3) (clc (neg v1) cln))
+ (@ c3 (clc (neg v2) (clc (pos v1) cln))
+ (@ c4 (clc (neg v3) (clc (pos v2) cln))
+ (@ cs (CMapc 0 c1 (CMapc 3 c2 (CMapc 5 c3 (CMapc 6 c4 CMapn))))
+ (@ c (clc (neg v3) cln)
+ (@ t (Tracec 3 (Tracec 5 (Tracec 6 Tracen)))
+ (test_is_at_trace
+ cs
+ c
+ t
+ UPR_Bottom
+ )
+ )))
+ ))))
+ ))))
+)
+
+; Test passes if the (test_is_at_trace ...) application is well-typed.
+(check
+ (% v1 var
+ (% v2 var
+ (% v3 var
+ (% v4 var
+ (@ c1 (clc (pos v3) (clc (neg v2) cln))
+ (@ c2 (clc (neg v3) (clc (neg v1) cln))
+ (@ c3 (clc (neg v2) (clc (pos v1) cln))
+ (@ c4 (clc (neg v3) (clc (pos v2) cln))
+ (@ cs (CMapc 0 c1 (CMapc 3 c2 (CMapc 5 c3 (CMapc 6 c4 CMapn))))
+ (@ c (clc (neg v3) cln)
+ (@ t (Tracec 3 (Tracec 5 Tracen))
+ (test_is_at_trace
+ cs
+ c
+ t
+ UPR_Ok
+ )
+ )))
+ ))))
+ ))))
+)
+
+; Test passes if the (test_is_at_trace ...) application is well-typed.
+(check
+ (% v1 var
+ (% v2 var
+ (% v3 var
+ (% v4 var
+ (@ c1 (clc (pos v3) (clc (neg v2) cln))
+ (@ c2 (clc (neg v3) (clc (neg v1) cln))
+ (@ c3 (clc (neg v2) (clc (pos v1) cln))
+ (@ c4 (clc (neg v3) (clc (pos v2) cln))
+ (@ cs (CMapc 1 c1 (CMapc 2 c2 (CMapc 3 c3 (CMapc 4 c4 CMapn))))
+ (@ c (clc (neg v3) cln)
+ (@ t (Tracec 2 (Tracec 1 Tracen))
+ (test_is_at_trace
+ cs
+ c
+ t
+ UPR_Broken
+ )
+ )))
+ ))))
+ ))))
+)
+
+(declare test_is_rat_trace (! cs CMap
+ (! c clause
+ (! t Trace
+ (! h RATHints
+ (! r UPResult
+ (! sc (^ (is_rat_trace cs c t h) r) type)))))))
+
+; Test passes if the (test_is_rat_trace ...) application is well-typed.
+(check
+ (% v1 var
+ (% v2 var
+ (% v3 var
+ (% v4 var
+ (@ c1 (clc (pos v1) (clc (pos v2) (clc (neg v3) cln)))
+ (@ c2 (clc (neg v1) (clc (neg v2) (clc (pos v3) cln)))
+ (@ c3 (clc (pos v2) (clc (pos v3) (clc (neg v4) cln)))
+ (@ c4 (clc (neg v2) (clc (neg v3) (clc (pos v4) cln)))
+ (@ c5 (clc (neg v1) (clc (neg v3) (clc (neg v4) cln)))
+ (@ c6 (clc (pos v1) (clc (pos v3) (clc (pos v4) cln)))
+ (@ c7 (clc (neg v1) (clc (pos v2) (clc (pos v4) cln)))
+ (@ c8 (clc (pos v1) (clc (neg v2) (clc (neg v4) cln)))
+ (@ cs (CMapc 1 c1
+ (CMapc 2 c2
+ (CMapc 3 c3
+ (CMapc 4 c4
+ (CMapc 5 c5
+ (CMapc 6 c6
+ (CMapc 7 c7
+ (CMapc 8 c8 CMapn))))))))
+ (@ c (clc (pos v1) cln)
+ (@ t Tracen
+ (@ h (RATHintsc 2 (Tracec 6 (Tracec 8 Tracen))
+ (RATHintsc 5 (Tracec 1 (Tracec 8 Tracen))
+ (RATHintsc 7 (Tracec 6 (Tracec 1 Tracen))
+ RATHintsn)))
+ (test_is_rat_trace
+ cs
+ c
+ t
+ h
+ UPR_Bottom
+ )
+ ))))
+ ))))))))
+ ))))
+)
+
+; Test passes if the (test_is_rat_trace ...) application is well-typed.
+(check
+ (% v1 var
+ (% v2 var
+ (% v3 var
+ (% v4 var
+ (@ c1 (clc (pos v1) (clc (pos v2) (clc (neg v3) cln)))
+ (@ c2 (clc (neg v1) (clc (neg v2) (clc (pos v3) cln)))
+ (@ c3 (clc (pos v2) (clc (pos v3) (clc (neg v4) cln)))
+ (@ c4 (clc (neg v2) (clc (neg v3) (clc (pos v4) cln)))
+ (@ c5 (clc (neg v1) (clc (neg v3) (clc (neg v4) cln)))
+ (@ c6 (clc (pos v1) (clc (pos v3) (clc (pos v4) cln)))
+ (@ c7 (clc (neg v1) (clc (pos v2) (clc (pos v4) cln)))
+ (@ c8 (clc (pos v1) (clc (neg v2) (clc (neg v4) cln)))
+ (@ cs (CMapc 1 c1
+ (CMapc 2 c2
+ (CMapc 3 c3
+ (CMapc 4 c4
+ (CMapc 5 c5
+ (CMapc 6 c6
+ (CMapc 7 c7
+ (CMapc 8 c8 CMapn))))))))
+ (@ c (clc (pos v1) cln)
+ (@ t Tracen
+ (@ h (RATHintsc 2 (Tracec 6 (Tracec 8 Tracen))
+ (RATHintsc 5 (Tracec 1 (Tracec 8 Tracen))
+ RATHintsn))
+ (test_is_rat_trace
+ cs
+ c
+ t
+ h
+ UPR_Broken
+ )
+ ))))
+ ))))))))
+ ))))
+)
+
+; Test passes if the (test_is_rat_trace ...) application is well-typed.
+(check
+ (% v1 var
+ (% v2 var
+ (% v3 var
+ (% v4 var
+ (@ c1 (clc (pos v1) (clc (pos v2) (clc (neg v3) cln)))
+ (@ c2 (clc (neg v1) (clc (neg v2) (clc (pos v3) cln)))
+ (@ c3 (clc (pos v2) (clc (pos v3) (clc (neg v4) cln)))
+ (@ c4 (clc (neg v2) (clc (neg v3) (clc (pos v4) cln)))
+ (@ c5 (clc (neg v1) (clc (neg v3) (clc (neg v4) cln)))
+ (@ c6 (clc (pos v1) (clc (pos v3) (clc (pos v4) cln)))
+ (@ c7 (clc (neg v1) (clc (pos v2) (clc (pos v4) cln)))
+ (@ c8 (clc (pos v1) (clc (neg v2) (clc (neg v4) cln)))
+ (@ cs (CMapc 1 c1
+ (CMapc 2 c2
+ (CMapc 3 c3
+ (CMapc 4 c4
+ (CMapc 5 c5
+ (CMapc 6 c6
+ (CMapc 7 c7
+ (CMapc 8 c8 CMapn))))))))
+ (@ c (clc (pos v1) cln)
+ (@ t Tracen
+ (@ h (RATHintsc 2 (Tracec 6 (Tracec 8 Tracen))
+ (RATHintsc 5 (Tracec 1 (Tracec 8 Tracen))
+ (RATHintsc 7 (Tracec 3 (Tracec 1 Tracen))
+ RATHintsn)))
+ (test_is_rat_trace
+ cs
+ c
+ t
+ h
+ UPR_Broken
+ )
+ ))))
+ ))))))))
+ ))))
+)
+
+; Test passes if the (test_is_rat_trace ...) application is well-typed.
+(check
+ (% v1 var
+ (% v2 var
+ (% v3 var
+ (% v4 var
+ (@ c1 (clc (pos v1) (clc (pos v2) (clc (neg v3) cln)))
+ (@ c2 (clc (neg v1) (clc (neg v2) (clc (pos v3) cln)))
+ (@ c3 (clc (pos v2) (clc (pos v3) (clc (neg v4) cln)))
+ (@ c4 (clc (neg v2) (clc (neg v3) (clc (pos v4) cln)))
+ (@ c5 (clc (neg v1) (clc (neg v3) (clc (neg v4) cln)))
+ (@ c6 (clc (pos v1) (clc (pos v3) (clc (pos v4) cln)))
+ (@ c7 (clc (neg v1) (clc (pos v2) (clc (pos v4) cln)))
+ (@ c8 (clc (pos v1) (clc (neg v2) (clc (neg v4) cln)))
+ (@ cs (CMapc 1 c1
+ (CMapc 2 c2
+ (CMapc 3 c3
+ (CMapc 4 c4
+ (CMapc 5 c5
+ (CMapc 6 c6
+ (CMapc 7 c7
+ (CMapc 8 c8 CMapn))))))))
+ (@ c (clc (pos v1) cln)
+ (@ t Tracen
+ (@ h (RATHintsc 2 (Tracec 6 (Tracec 8 Tracen))
+ (RATHintsc 5 (Tracec 1 (Tracec 8 Tracen))
+ (RATHintsc 7 (Tracec 3 Tracen)
+ RATHintsn)))
+ (test_is_rat_trace
+ cs
+ c
+ t
+ h
+ UPR_Broken
+ )
+ ))))
+ ))))))))
+ ))))
+)
+
+; Test passes if the (test_is_rat_trace ...) application is well-typed.
+(check
+ (% v1 var
+ (% v2 var
+ (% v3 var
+ (% v4 var
+ (@ c1 (clc (pos v1) (clc (pos v2) (clc (neg v3) cln)))
+ (@ c2 (clc (neg v1) (clc (neg v2) (clc (pos v3) cln)))
+ (@ c3 (clc (pos v2) (clc (pos v3) (clc (neg v4) cln)))
+ (@ c4 (clc (neg v2) (clc (neg v3) (clc (pos v4) cln)))
+ (@ c5 (clc (neg v1) (clc (neg v3) (clc (neg v4) cln)))
+ (@ c6 (clc (pos v1) (clc (pos v3) (clc (pos v4) cln)))
+ (@ c7 (clc (neg v1) (clc (pos v2) (clc (pos v4) cln)))
+ (@ c8 (clc (pos v1) (clc (neg v2) (clc (neg v4) cln)))
+ (@ c9 (clc (pos v1) cln)
+ (@ cs (CMapc 1 c1
+ (CMapc 2 c2
+ (CMapc 3 c3
+ (CMapc 4 c4
+ (CMapc 5 c5
+ (CMapc 6 c6
+ (CMapc 7 c7
+ (CMapc 8 c8
+ (CMapc 9 c9
+ CMapn)))))))))
+ (@ c (clc (pos v2) cln)
+ (@ t (Tracec 9 (Tracec 7 (Tracec 5 (Tracec 3 Tracen))))
+ (@ h RATHintsn
+ (test_is_rat_trace
+ cs
+ c
+ t
+ h
+ UPR_Bottom
+ )
+ ))))
+ )))))))))
+ ))))
+)
+
+; Test passes if the (test_is_rat_trace ...) application is well-typed.
+(check
+ (% v1 var
+ (% v2 var
+ (% v3 var
+ (% v4 var
+ (@ c1 (clc (pos v1) (clc (pos v2) (clc (neg v3) cln)))
+ (@ c2 (clc (neg v1) (clc (neg v2) (clc (pos v3) cln)))
+ (@ c3 (clc (pos v2) (clc (pos v3) (clc (neg v4) cln)))
+ (@ c4 (clc (neg v2) (clc (neg v3) (clc (pos v4) cln)))
+ (@ c5 (clc (neg v1) (clc (neg v3) (clc (neg v4) cln)))
+ (@ c6 (clc (pos v1) (clc (pos v3) (clc (pos v4) cln)))
+ (@ c7 (clc (neg v1) (clc (pos v2) (clc (pos v4) cln)))
+ (@ c8 (clc (pos v1) (clc (neg v2) (clc (neg v4) cln)))
+ (@ c9 (clc (pos v1) cln)
+ (@ c10 (clc (pos v2) cln)
+ (@ cs (CMapc 1 c1
+ (CMapc 2 c2
+ (CMapc 3 c3
+ (CMapc 4 c4
+ (CMapc 5 c5
+ (CMapc 6 c6
+ (CMapc 7 c7
+ (CMapc 8 c8
+ (CMapc 9 c9
+ (CMapc 10 c10
+ CMapn))))))))))
+ (@ c cln
+ (@ t (Tracec 9 (Tracec 10 (Tracec 2 (Tracec 4 (Tracec 5 Tracen)))))
+ (@ h RATHintsn
+ (test_is_rat_trace
+ cs
+ c
+ t
+ h
+ UPR_Bottom
+ )
+ ))))
+ ))))))))))
+ ))))
+)
+
+(declare test_is_lrat_proof_of_bottom
+ (! f CMap
+ (! p LRATProof
+ (! r bool
+ (! sc (^ (is_lrat_proof_of_bottom f p) r) type)))))
+
+; Test passes if the (test_is_lrat_proof_of_bottom ...) application is well-typed.
+(check
+ (% v1 var
+ (% v2 var
+ (% v3 var
+ (% v4 var
+ (@ c1 (clc (pos v1) (clc (pos v2) (clc (neg v3) cln)))
+ (@ c2 (clc (neg v1) (clc (neg v2) (clc (pos v3) cln)))
+ (@ c3 (clc (pos v2) (clc (pos v3) (clc (neg v4) cln)))
+ (@ c4 (clc (neg v2) (clc (neg v3) (clc (pos v4) cln)))
+ (@ c5 (clc (neg v1) (clc (neg v3) (clc (neg v4) cln)))
+ (@ c6 (clc (pos v1) (clc (pos v3) (clc (pos v4) cln)))
+ (@ c7 (clc (neg v1) (clc (pos v2) (clc (pos v4) cln)))
+ (@ c8 (clc (pos v1) (clc (neg v2) (clc (neg v4) cln)))
+ (@ cs (CMapc 1 c1
+ (CMapc 2 c2
+ (CMapc 3 c3
+ (CMapc 4 c4
+ (CMapc 5 c5
+ (CMapc 6 c6
+ (CMapc 7 c7
+ (CMapc 8 c8
+ CMapn))))))))
+ (@ p
+ (LRATProofa 9
+ (clc (pos v1) cln)
+ Tracen
+ (RATHintsc 2 (Tracec 6 (Tracec 8 Tracen))
+ (RATHintsc 5 (Tracec 1 (Tracec 8 Tracen))
+ (RATHintsc 7 (Tracec 6 (Tracec 1 Tracen))
+ RATHintsn)))
+ (LRATProofd (CIListc 1 (CIListc 6 (CIListc 8 CIListn)))
+ (LRATProofa 10
+ (clc (pos v2) cln)
+ (Tracec 9 (Tracec 7 (Tracec 5 (Tracec 3 Tracen))))
+ RATHintsn
+ (LRATProofd (CIListc 3 (CIListc 7 CIListn))
+ (LRATProofa 11
+ cln
+ (Tracec 9 (Tracec 10 (Tracec 2 (Tracec 4 (Tracec 5 Tracen)))))
+ RATHintsn
+ LRATProofn)))))
+ (test_is_lrat_proof_of_bottom
+ cs
+ p
+ tt
+ )
+ ))
+ ))))))))
+ ))))
+)
+
+; Test passes if the (test_is_lrat_proof_of_bottom ...) application is well-typed.
+(check
+ (% v1 var
+ (% v2 var
+ (% v3 var
+ (% v4 var
+ (@ c1 (clc (pos v1) (clc (pos v2) (clc (neg v3) cln)))
+ (@ c2 (clc (neg v1) (clc (neg v2) (clc (pos v3) cln)))
+ (@ c3 (clc (pos v2) (clc (pos v3) (clc (neg v4) cln)))
+ (@ c4 (clc (neg v2) (clc (neg v3) (clc (pos v4) cln)))
+ (@ c5 (clc (neg v1) (clc (neg v3) (clc (neg v4) cln)))
+ (@ c6 (clc (pos v1) (clc (pos v3) (clc (pos v4) cln)))
+ (@ c7 (clc (neg v1) (clc (pos v2) (clc (pos v4) cln)))
+ (@ c8 (clc (pos v1) (clc (neg v2) (clc (neg v4) cln)))
+ (@ cs (CMapc 1 c1
+ (CMapc 2 c2
+ (CMapc 3 c3
+ (CMapc 4 c4
+ (CMapc 5 c5
+ (CMapc 6 c6
+ (CMapc 7 c7
+ (CMapc 8 c8
+ CMapn))))))))
+ (@ p
+ (LRATProofa 9
+ (clc (pos v1) cln)
+ Tracen
+ (RATHintsc 2 (Tracec 6 (Tracec 8 Tracen))
+ (RATHintsc 5 (Tracec 1 (Tracec 8 Tracen))
+ (RATHintsc 7 (Tracec 6 (Tracec 1 Tracen))
+ RATHintsn)))
+ (LRATProofd (CIListc 1 (CIListc 6 (CIListc 8 CIListn)))
+ (LRATProofa 10
+ (clc (pos v2) cln)
+ (Tracec 9 (Tracec 7 (Tracec 5 (Tracec 3 Tracen))))
+ RATHintsn
+ (LRATProofd (CIListc 3 (CIListc 7 CIListn))
+ (LRATProofa 11
+ cln
+ (Tracec 9 (Tracec 10 (Tracec 2 (Tracec 4 Tracen))))
+ RATHintsn
+ LRATProofn)))))
+ (test_is_lrat_proof_of_bottom
+ cs
+ p
+ ff
+ )
+ ))
+ ))))))))
+ ))))
+)
+
+; Proof from Figure 2 of "Efficient Certified RAT Verification"
+(check
+ (% v1 var
+ (% v2 var
+ (% v3 var
+ (% v4 var
+ (% pf_c1 (holds (clc (pos v1) (clc (pos v2) (clc (neg v3) cln))))
+ (% pf_c2 (holds (clc (neg v1) (clc (neg v2) (clc (pos v3) cln))))
+ (% pf_c3 (holds (clc (pos v2) (clc (pos v3) (clc (neg v4) cln))))
+ (% pf_c4 (holds (clc (neg v2) (clc (neg v3) (clc (pos v4) cln))))
+ (% pf_c5 (holds (clc (neg v1) (clc (neg v3) (clc (neg v4) cln))))
+ (% pf_c6 (holds (clc (pos v1) (clc (pos v3) (clc (pos v4) cln))))
+ (% pf_c7 (holds (clc (neg v1) (clc (pos v2) (clc (pos v4) cln))))
+ (% pf_c8 (holds (clc (pos v1) (clc (neg v2) (clc (neg v4) cln))))
+ (@ pf_cmap
+ (CMapc_proof 1 _ _ _ pf_c1
+ (CMapc_proof 2 _ _ _ pf_c2
+ (CMapc_proof 3 _ _ _ pf_c3
+ (CMapc_proof 4 _ _ _ pf_c4
+ (CMapc_proof 5 _ _ _ pf_c5
+ (CMapc_proof 6 _ _ _ pf_c6
+ (CMapc_proof 7 _ _ _ pf_c7
+ (CMapc_proof 8 _ _ _ pf_c8
+ CMapn_proof))))))))
+ (@ lrat_proof_witness
+ (LRATProofa 9
+ (clc (pos v1) cln)
+ Tracen
+ (RATHintsc 2 (Tracec 6 (Tracec 8 Tracen))
+ (RATHintsc 5 (Tracec 1 (Tracec 8 Tracen))
+ (RATHintsc 7 (Tracec 6 (Tracec 1 Tracen))
+ RATHintsn)))
+ (LRATProofd (CIListc 1 (CIListc 6 (CIListc 8 CIListn)))
+ (LRATProofa 10
+ (clc (pos v2) cln)
+ (Tracec 9 (Tracec 7 (Tracec 5 (Tracec 3 Tracen))))
+ RATHintsn
+ (LRATProofd (CIListc 3 (CIListc 7 CIListn))
+ (LRATProofa 11
+ cln
+ (Tracec 9 (Tracec 10 (Tracec 2 (Tracec 4 (Tracec 5 Tracen)))))
+ RATHintsn
+ LRATProofn)))))
+ (:
+ (holds cln)
+ (lrat_proof_of_bottom _ pf_cmap lrat_proof_witness))
+ ))
+ ))))))))
+ ))))
+)
+
+; Proof from Figure 2 of "Efficient Certified RAT Verification"
+; With duplicates
+(check
+ (% v1 var
+ (% v2 var
+ (% v3 var
+ (% v4 var
+ (% pf_c1 (holds (clc (pos v1) (clc (pos v1) (clc (pos v2) (clc (neg v3) cln)))))
+ (% pf_c2 (holds (clc (neg v1) (clc (neg v2) (clc (pos v3) cln))))
+ (% pf_c3 (holds (clc (pos v2) (clc (pos v3) (clc (pos v3) (clc (pos v3) (clc (neg v4) cln))))))
+ (% pf_c4 (holds (clc (neg v2) (clc (neg v3) (clc (pos v4) cln))))
+ (% pf_c5 (holds (clc (neg v1) (clc (neg v3) (clc (neg v4) (clc (neg v4) cln)))))
+ (% pf_c6 (holds (clc (pos v1) (clc (pos v3) (clc (pos v3) (clc (pos v4) cln)))))
+ (% pf_c7 (holds (clc (neg v1) (clc (pos v2) (clc (pos v4) cln))))
+ (% pf_c8 (holds (clc (pos v1) (clc (neg v2) (clc (neg v2) (clc (neg v4) cln)))))
+ (@ pf_cmap
+ (CMapc_proof 1 _ _ _ pf_c1
+ (CMapc_proof 2 _ _ _ pf_c2
+ (CMapc_proof 3 _ _ _ pf_c3
+ (CMapc_proof 4 _ _ _ pf_c4
+ (CMapc_proof 5 _ _ _ pf_c5
+ (CMapc_proof 6 _ _ _ pf_c6
+ (CMapc_proof 7 _ _ _ pf_c7
+ (CMapc_proof 8 _ _ _ pf_c8
+ CMapn_proof))))))))
+ (@ lrat_proof_witness
+ (LRATProofa 9
+ (clc (pos v1) cln)
+ Tracen
+ (RATHintsc 2 (Tracec 6 (Tracec 8 Tracen))
+ (RATHintsc 5 (Tracec 1 (Tracec 8 Tracen))
+ (RATHintsc 7 (Tracec 6 (Tracec 1 Tracen))
+ RATHintsn)))
+ (LRATProofd (CIListc 1 (CIListc 6 (CIListc 8 CIListn)))
+ (LRATProofa 10
+ (clc (pos v2) cln)
+ (Tracec 9 (Tracec 7 (Tracec 5 (Tracec 3 Tracen))))
+ RATHintsn
+ (LRATProofd (CIListc 3 (CIListc 7 CIListn))
+ (LRATProofa 11
+ cln
+ (Tracec 9 (Tracec 10 (Tracec 2 (Tracec 4 (Tracec 5 Tracen)))))
+ RATHintsn
+ LRATProofn)))))
+ (:
+ (holds cln)
+ (lrat_proof_of_bottom _ pf_cmap lrat_proof_witness))
+ ))
+ ))))))))
+ ))))
+)
+
+; Clauses 1 and 9 are identical.
+(check
+ (% v1 var
+ (% v2 var
+ (% v3 var
+ (% v4 var
+ (% pf_c1 (holds (clc (pos v1) (clc (pos v2) (clc (neg v3) cln))))
+ (% pf_c2 (holds (clc (neg v1) (clc (neg v2) (clc (pos v3) cln))))
+ (% pf_c3 (holds (clc (pos v2) (clc (pos v3) (clc (neg v4) cln))))
+ (% pf_c4 (holds (clc (neg v2) (clc (neg v3) (clc (pos v4) cln))))
+ (% pf_c5 (holds (clc (neg v1) (clc (neg v3) (clc (neg v4) cln))))
+ (% pf_c6 (holds (clc (pos v1) (clc (pos v3) (clc (pos v4) cln))))
+ (% pf_c7 (holds (clc (neg v1) (clc (pos v2) (clc (pos v4) cln))))
+ (% pf_c8 (holds (clc (pos v1) (clc (neg v2) (clc (neg v4) cln))))
+ (% pf_c9 (holds (clc (pos v1) (clc (pos v2) (clc (neg v3) cln))))
+ (@ pf_cmap
+ (CMapc_proof 1 _ _ _ pf_c1
+ (CMapc_proof 2 _ _ _ pf_c2
+ (CMapc_proof 3 _ _ _ pf_c3
+ (CMapc_proof 4 _ _ _ pf_c4
+ (CMapc_proof 5 _ _ _ pf_c5
+ (CMapc_proof 6 _ _ _ pf_c6
+ (CMapc_proof 7 _ _ _ pf_c7
+ (CMapc_proof 8 _ _ _ pf_c8
+ (CMapc_proof 9 _ _ _ pf_c9
+ CMapn_proof)))))))))
+ (@ lrat_proof_witness
+ (LRATProofa 10
+ (clc (pos v1) cln)
+ Tracen
+ (RATHintsc 2 (Tracec 6 (Tracec 8 Tracen))
+ (RATHintsc 5 (Tracec 1 (Tracec 8 Tracen))
+ (RATHintsc 7 (Tracec 6 (Tracec 9 Tracen))
+ RATHintsn)))
+ (LRATProofd (CIListc 1 (CIListc 6 (CIListc 8 (CIListc 9 CIListn))))
+ (LRATProofa 11
+ (clc (pos v2) cln)
+ (Tracec 10 (Tracec 7 (Tracec 5 (Tracec 3 Tracen))))
+ RATHintsn
+ (LRATProofd (CIListc 3 (CIListc 7 CIListn))
+ (LRATProofa 12
+ cln
+ (Tracec 10 (Tracec 11 (Tracec 2 (Tracec 4 (Tracec 5 Tracen)))))
+ RATHintsn
+ LRATProofn)))))
+ (:
+ (holds cln)
+ (lrat_proof_of_bottom _ pf_cmap lrat_proof_witness))
+ ))
+ )))))))))
+ ))))
+)
+
+; Clauses 1 and 9 are logically identical, but the literals have been reordered.
+(check
+ (% v1 var
+ (% v2 var
+ (% v3 var
+ (% v4 var
+ (% pf_c1 (holds (clc (pos v1) (clc (pos v2) (clc (neg v3) cln))))
+ (% pf_c2 (holds (clc (neg v1) (clc (neg v2) (clc (pos v3) cln))))
+ (% pf_c3 (holds (clc (pos v2) (clc (pos v3) (clc (neg v4) cln))))
+ (% pf_c4 (holds (clc (neg v2) (clc (neg v3) (clc (pos v4) cln))))
+ (% pf_c5 (holds (clc (neg v1) (clc (neg v3) (clc (neg v4) cln))))
+ (% pf_c6 (holds (clc (pos v1) (clc (pos v3) (clc (pos v4) cln))))
+ (% pf_c7 (holds (clc (neg v1) (clc (pos v2) (clc (pos v4) cln))))
+ (% pf_c8 (holds (clc (pos v1) (clc (neg v2) (clc (neg v4) cln))))
+ (% pf_c9 (holds (clc (neg v3) (clc (pos v2) (clc (pos v1) cln))))
+ (@ pf_cmap
+ (CMapc_proof 1 _ _ _ pf_c1
+ (CMapc_proof 2 _ _ _ pf_c2
+ (CMapc_proof 3 _ _ _ pf_c3
+ (CMapc_proof 4 _ _ _ pf_c4
+ (CMapc_proof 5 _ _ _ pf_c5
+ (CMapc_proof 6 _ _ _ pf_c6
+ (CMapc_proof 7 _ _ _ pf_c7
+ (CMapc_proof 8 _ _ _ pf_c8
+ (CMapc_proof 9 _ _ _ pf_c9
+ CMapn_proof)))))))))
+ (@ lrat_proof_witness
+ (LRATProofa 10
+ (clc (pos v1) cln)
+ Tracen
+ (RATHintsc 2 (Tracec 6 (Tracec 8 Tracen))
+ (RATHintsc 5 (Tracec 1 (Tracec 8 Tracen))
+ (RATHintsc 7 (Tracec 6 (Tracec 9 Tracen))
+ RATHintsn)))
+ (LRATProofd (CIListc 1 (CIListc 6 (CIListc 8 (CIListc 9 CIListn))))
+ (LRATProofa 11
+ (clc (pos v2) cln)
+ (Tracec 10 (Tracec 7 (Tracec 5 (Tracec 3 Tracen))))
+ RATHintsn
+ (LRATProofd (CIListc 3 (CIListc 7 CIListn))
+ (LRATProofa 12
+ cln
+ (Tracec 10 (Tracec 11 (Tracec 2 (Tracec 4 (Tracec 5 Tracen)))))
+ RATHintsn
+ LRATProofn)))))
+ (:
+ (holds cln)
+ (lrat_proof_of_bottom _ pf_cmap lrat_proof_witness))
+ ))
+ )))))))))
+ ))))
+)
+
+; Proof from Figure 1 of "Efficient Certified RAT Verification"
+(check
+ (% v1 var
+ (% v2 var
+ (% v3 var
+ (% v4 var
+ (% pf_c1 (holds (clc (pos v1) (clc (pos v2) (clc (neg v3) cln))))
+ (% pf_c2 (holds (clc (neg v1) (clc (neg v2) (clc (pos v3) cln))))
+ (% pf_c3 (holds (clc (pos v2) (clc (pos v3) (clc (neg v4) cln))))
+ (% pf_c4 (holds (clc (neg v2) (clc (neg v3) (clc (pos v4) cln))))
+ (% pf_c5 (holds (clc (neg v1) (clc (neg v3) (clc (neg v4) cln))))
+ (% pf_c6 (holds (clc (pos v1) (clc (pos v3) (clc (pos v4) cln))))
+ (% pf_c7 (holds (clc (neg v1) (clc (pos v2) (clc (pos v4) cln))))
+ (% pf_c8 (holds (clc (pos v1) (clc (neg v2) (clc (neg v4) cln))))
+ (@ pf_cmap
+ (CMapc_proof 1 _ _ _ pf_c1
+ (CMapc_proof 2 _ _ _ pf_c2
+ (CMapc_proof 3 _ _ _ pf_c3
+ (CMapc_proof 4 _ _ _ pf_c4
+ (CMapc_proof 5 _ _ _ pf_c5
+ (CMapc_proof 6 _ _ _ pf_c6
+ (CMapc_proof 7 _ _ _ pf_c7
+ (CMapc_proof 8 _ _ _ pf_c8
+ CMapn_proof))))))))
+ (@ lrat_proof_witness
+ (LRATProofa 9
+ (clc (pos v1) (clc (pos v2) cln))
+ (Tracec 1 (Tracec 6 (Tracec 3 Tracen)))
+ RATHintsn
+ (LRATProofd (CIListc 1 CIListn)
+ (LRATProofa 10
+ (clc (pos v1) (clc (pos v3) cln))
+ (Tracec 9 (Tracec 8 (Tracec 6 Tracen)))
+ RATHintsn
+ (LRATProofd (CIListc 6 CIListn)
+ (LRATProofa 11
+ (clc (pos v1) cln)
+ (Tracec 10 (Tracec 9 (Tracec 4 (Tracec 8 Tracen))))
+ RATHintsn
+ (LRATProofd (CIListc 8 (CIListc 9 (CIListc 10 CIListn)))
+ (LRATProofa 12
+ (clc (pos v2) cln)
+ (Tracec 11 (Tracec 7 (Tracec 5 (Tracec 3 Tracen))))
+ RATHintsn
+ (LRATProofd (CIListc 3 (CIListc 7 CIListn))
+ (LRATProofa 13
+ cln
+ (Tracec 11 (Tracec 12 (Tracec 2 (Tracec 4 (Tracec 5 Tracen)))))
+ RATHintsn
+ LRATProofn
+ )))))))))
+ (:
+ (holds cln)
+ (lrat_proof_of_bottom _ pf_cmap lrat_proof_witness))
+ ))
+ ))))))))
+ ))))
+)
diff --git a/proofs/signatures/sat.plf b/proofs/signatures/sat.plf
index b95caa8fd..8f40aa8bf 100644
--- a/proofs/signatures/sat.plf
+++ b/proofs/signatures/sat.plf
@@ -19,8 +19,8 @@
; code to check resolutions
-(program append ((c1 clause) (c2 clause)) clause
- (match c1 (cln c2) ((clc l c1') (clc l (append c1' c2)))))
+(program clause_append ((c1 clause) (c2 clause)) clause
+ (match c1 (cln c2) ((clc l c1') (clc l (clause_append c1' c2)))))
; we use marks as follows:
; -- mark 1 to record if we are supposed to remove a positive occurrence of the variable.
@@ -49,7 +49,7 @@
(match m
(tt (do (ifmarked4 v v (markvar4 v)) c'))
(ff (do (ifmarked4 v (markvar4 v) v) (markvar2 v) (clc l c')))))))))
- ((concat_cl c1 c2) (append (simplify_clause c1) (simplify_clause c2)))
+ ((concat_cl c1 c2) (clause_append (simplify_clause c1) (simplify_clause c2)))
((clr l c1)
(match l
; set mark 1 to indicate we should remove v, and fail if
diff --git a/proofs/signatures/smt.plf b/proofs/signatures/smt.plf
index 06dc16153..57dc5bd1e 100644
--- a/proofs/signatures/smt.plf
+++ b/proofs/signatures/smt.plf
@@ -439,6 +439,22 @@
(holds C))
(holds (clc (neg v) C))))))))))
+;; Numeric primitives
+
+(program mpz_sub ((x mpz) (y mpz)) mpz
+ (mp_add x (mp_mul (~1) y)))
+
+(program mp_ispos ((x mpz)) formula
+ (mp_ifneg x false true))
+
+(program mpz_eq ((x mpz) (y mpz)) formula
+ (mp_ifzero (mpz_sub x y) true false))
+
+(program mpz_lt ((x mpz) (y mpz)) formula
+ (mp_ifneg (mpz_sub x y) true false))
+
+(program mpz_lte ((x mpz) (y mpz)) formula
+ (mp_ifneg (mpz_sub x y) true (mpz_eq x y)))
;; Example:
;;
diff --git a/proofs/signatures/th_bv.plf b/proofs/signatures/th_bv.plf
index 6012e052a..934951a86 100644
--- a/proofs/signatures/th_bv.plf
+++ b/proofs/signatures/th_bv.plf
@@ -3,20 +3,6 @@
(declare trust-bad (th_holds false))
; helper stuff
-(program mpz_sub ((x mpz) (y mpz)) mpz
- (mp_add x (mp_mul (~1) y)))
-
-(program mp_ispos ((x mpz)) formula
- (mp_ifneg x false true))
-
-(program mpz_eq ((x mpz) (y mpz)) formula
- (mp_ifzero (mpz_sub x y) true false))
-
-(program mpz_lt ((x mpz) (y mpz)) formula
- (mp_ifneg (mpz_sub x y) true false))
-
-(program mpz_lte ((x mpz) (y mpz)) formula
- (mp_ifneg (mpz_sub x y) true (mpz_eq x y)))
(program mpz_ ((x mpz) (y mpz)) formula
(mp_ifzero (mpz_sub x y) true false))
diff --git a/proofs/signatures/th_lra.plf b/proofs/signatures/th_lra.plf
index 67b17c9af..76e5127c2 100644
--- a/proofs/signatures/th_lra.plf
+++ b/proofs/signatures/th_lra.plf
@@ -1,4 +1,22 @@
-; Depends on th_real.plf, th_smt.plf
+; Depends on th_real.plf, smt.plf, sat.plf
+
+; LRA proofs have the following interface:
+; * Given predicates between real terms
+; * Prove bottom
+;
+; However, even though the type of the interface does not express this,
+; the predicates are **linear bounds**, not arbitrary real bounds. Thus
+; LRA proofs have the following structure:
+;
+; 1. Prove that the input predicates are equivalent to a set of linear
+; bounds.
+; 2. Use the linear bounds to prove bottom using farkas coefficients.
+;
+; Notice that the distinction between linear bounds (associated in the signature
+; with the string "poly") and real predicates (which relate "term Real"s to one
+; another) matters quite a bit. We have certain kinds of axioms for one, and
+; other axioms for the other.
+
(program mpq_ifpos ((x mpq)) bool
(mp_ifneg x ff (mp_ifzero x ff tt)))
@@ -100,61 +118,65 @@
;; conversion to use polynomials in term formulas
-(declare poly_term (! p poly (term Real)))
+
+(declare >=0_poly (! x poly formula))
+(declare =0_poly (! x poly formula))
+(declare >0_poly (! x poly formula))
+(declare distinct0_poly (! x poly formula))
;; create new equality out of inequality
(declare lra_>=_>=_to_=
(! p1 poly
(! p2 poly
- (! f1 (th_holds (>=0_Real (poly_term p1)))
- (! f2 (th_holds (>=0_Real (poly_term p2)))
+ (! f1 (th_holds (>=0_poly p1))
+ (! f2 (th_holds (>=0_poly p2))
(! i2 (^ (mp_ifzero (is_poly_const (poly_add p1 p2)) tt ff) tt)
- (th_holds (=0_Real (poly_term p2)))))))))
+ (th_holds (=0_poly p2))))))))
;; axioms
(declare lra_axiom_=
- (th_holds (=0_Real (poly_term (polyc 0/1 lmonn)))))
+ (th_holds (=0_poly (polyc 0/1 lmonn))))
(declare lra_axiom_>
(! c mpq
(! i (^ (mpq_ifpos c) tt)
- (th_holds (>0_Real (poly_term (polyc c lmonn)))))))
+ (th_holds (>0_poly (polyc c lmonn))))))
(declare lra_axiom_>=
(! c mpq
(! i (^ (mp_ifneg c tt ff) ff)
- (th_holds (>=0_Real (poly_term (polyc c lmonn)))))))
+ (th_holds (>=0_poly (polyc c lmonn))))))
(declare lra_axiom_distinct
(! c mpq
(! i (^ (mp_ifzero c tt ff) ff)
- (th_holds (distinct0_Real (poly_term (polyc c lmonn)))))))
+ (th_holds (distinct0_poly (polyc c lmonn))))))
;; contradiction rules
(declare lra_contra_=
(! p poly
- (! f (th_holds (=0_Real (poly_term p)))
+ (! f (th_holds (=0_poly p))
(! i (^ (mp_ifzero (is_poly_const p) tt ff) ff)
(holds cln)))))
(declare lra_contra_>
(! p poly
- (! f (th_holds (>0_Real (poly_term p)))
+ (! f (th_holds (>0_poly p))
(! i2 (^ (mpq_ifpos (is_poly_const p)) ff)
(holds cln)))))
(declare lra_contra_>=
(! p poly
- (! f (th_holds (>=0_Real (poly_term p)))
+ (! f (th_holds (>=0_poly p))
(! i2 (^ (mp_ifneg (is_poly_const p) tt ff) tt)
(holds cln)))))
(declare lra_contra_distinct
(! p poly
- (! f (th_holds (distinct0_Real (poly_term p)))
+ (! f (th_holds (distinct0_poly p))
(! i2 (^ (mp_ifzero (is_poly_const p) tt ff) tt)
(holds cln)))))
@@ -164,33 +186,33 @@
(! p poly
(! p' poly
(! c mpq
- (! f (th_holds (=0_Real (poly_term p)))
+ (! f (th_holds (=0_poly p))
(! i (^ (poly_mul_c p c) p')
- (th_holds (=0_Real (poly_term p')))))))))
+ (th_holds (=0_poly p'))))))))
(declare lra_mul_c_>
(! p poly
(! p' poly
(! c mpq
- (! f (th_holds (>0_Real (poly_term p)))
+ (! f (th_holds (>0_poly p))
(! i (^ (mp_ifneg c (fail poly) (mp_ifzero c (fail poly) (poly_mul_c p c))) p')
- (th_holds (>0_Real (poly_term p')))))))));)
+ (th_holds (>0_poly p'))))))));
(declare lra_mul_c_>=
(! p poly
(! p' poly
(! c mpq
- (! f (th_holds (>=0_Real (poly_term p)))
+ (! f (th_holds (>=0_poly p))
(! i (^ (mp_ifneg c (fail poly) (poly_mul_c p c)) p')
- (th_holds (>=0_Real (poly_term p')))))))));)
+ (th_holds (>=0_poly p'))))))))
(declare lra_mul_c_distinct
(! p poly
(! p' poly
(! c mpq
- (! f (th_holds (distinct0_Real (poly_term p)))
+ (! f (th_holds (distinct0_poly p))
(! i (^ (mp_ifzero c (fail poly) (poly_mul_c p c)) p')
- (th_holds (distinct0_Real (poly_term p')))))))));)
+ (th_holds (distinct0_poly p'))))))))
;; adding equations
@@ -198,64 +220,73 @@
(! p1 poly
(! p2 poly
(! p3 poly
- (! f1 (th_holds (=0_Real (poly_term p1)))
- (! f2 (th_holds (=0_Real (poly_term p2)))
+ (! f1 (th_holds (=0_poly p1))
+ (! f2 (th_holds (=0_poly p2))
(! i (^ (poly_add p1 p2) p3)
- (th_holds (=0_Real (poly_term p3))))))))))
+ (th_holds (=0_poly p3)))))))))
(declare lra_add_>_>
(! p1 poly
(! p2 poly
(! p3 poly
- (! f1 (th_holds (>0_Real (poly_term p1)))
- (! f2 (th_holds (>0_Real (poly_term p2)))
+ (! f1 (th_holds (>0_poly p1))
+ (! f2 (th_holds (>0_poly p2))
(! i (^ (poly_add p1 p2) p3)
- (th_holds (>0_Real (poly_term p3))))))))))
+ (th_holds (>0_poly p3)))))))))
(declare lra_add_>=_>=
(! p1 poly
(! p2 poly
(! p3 poly
- (! f1 (th_holds (>=0_Real (poly_term p1)))
- (! f2 (th_holds (>=0_Real (poly_term p2)))
+ (! f1 (th_holds (>=0_poly p1))
+ (! f2 (th_holds (>=0_poly p2))
(! i (^ (poly_add p1 p2) p3)
- (th_holds (>=0_Real (poly_term p3))))))))))
+ (th_holds (>=0_poly p3)))))))))
(declare lra_add_=_>
(! p1 poly
(! p2 poly
(! p3 poly
- (! f1 (th_holds (=0_Real (poly_term p1)))
- (! f2 (th_holds (>0_Real (poly_term p2)))
+ (! f1 (th_holds (=0_poly p1))
+ (! f2 (th_holds (>0_poly p2))
(! i (^ (poly_add p1 p2) p3)
- (th_holds (>0_Real (poly_term p3))))))))))
+ (th_holds (>0_poly p3)))))))))
(declare lra_add_=_>=
(! p1 poly
(! p2 poly
(! p3 poly
- (! f1 (th_holds (=0_Real (poly_term p1)))
- (! f2 (th_holds (>=0_Real (poly_term p2)))
+ (! f1 (th_holds (=0_poly p1))
+ (! f2 (th_holds (>=0_poly p2))
(! i (^ (poly_add p1 p2) p3)
- (th_holds (>=0_Real (poly_term p3))))))))))
+ (th_holds (>=0_poly p3)))))))))
(declare lra_add_>_>=
(! p1 poly
(! p2 poly
(! p3 poly
- (! f1 (th_holds (>0_Real (poly_term p1)))
- (! f2 (th_holds (>=0_Real (poly_term p2)))
+ (! f1 (th_holds (>0_poly p1))
+ (! f2 (th_holds (>=0_poly p2))
+ (! i (^ (poly_add p1 p2) p3)
+ (th_holds (>0_poly p3)))))))))
+
+(declare lra_add_>=_>
+ (! p1 poly
+ (! p2 poly
+ (! p3 poly
+ (! f1 (th_holds (>=0_poly p1))
+ (! f2 (th_holds (>0_poly p2))
(! i (^ (poly_add p1 p2) p3)
- (th_holds (>0_Real (poly_term p3))))))))))
+ (th_holds (>0_poly p3)))))))))
(declare lra_add_=_distinct
(! p1 poly
(! p2 poly
(! p3 poly
- (! f1 (th_holds (=0_Real (poly_term p1)))
- (! f2 (th_holds (distinct0_Real (poly_term p2)))
+ (! f1 (th_holds (=0_poly p1))
+ (! f2 (th_holds (distinct0_poly p2))
(! i (^ (poly_add p1 p2) p3)
- (th_holds (distinct0_Real (poly_term p3))))))))))
+ (th_holds (distinct0_poly p3)))))))))
;; substracting equations
@@ -263,37 +294,37 @@
(! p1 poly
(! p2 poly
(! p3 poly
- (! f1 (th_holds (=0_Real (poly_term p1)))
- (! f2 (th_holds (=0_Real (poly_term p2)))
+ (! f1 (th_holds (=0_poly p1))
+ (! f2 (th_holds (=0_poly p2))
(! i (^ (poly_sub p1 p2) p3)
- (th_holds (=0_Real (poly_term p3)))))))))))
+ (th_holds (=0_poly p3)))))))))
(declare lra_sub_>_=
(! p1 poly
(! p2 poly
(! p3 poly
- (! f1 (th_holds (>0_Real (poly_term p1)))
- (! f2 (th_holds (=0_Real (poly_term p2)))
+ (! f1 (th_holds (>0_poly p1))
+ (! f2 (th_holds (=0_poly p2))
(! i (^ (poly_sub p1 p2) p3)
- (th_holds (>0_Real (poly_term p3))))))))))
+ (th_holds (>0_poly p3)))))))))
(declare lra_sub_>=_=
(! p1 poly
(! p2 poly
(! p3 poly
- (! f1 (th_holds (>=0_Real (poly_term p1)))
- (! f2 (th_holds (=0_Real (poly_term p2)))
+ (! f1 (th_holds (>=0_poly p1))
+ (! f2 (th_holds (=0_poly p2))
(! i (^ (poly_sub p1 p2) p3)
- (th_holds (>=0_Real (poly_term p3))))))))))
+ (th_holds (>=0_poly p3)))))))))
(declare lra_sub_distinct_=
(! p1 poly
(! p2 poly
(! p3 poly
- (! f1 (th_holds (distinct0_Real (poly_term p1)))
- (! f2 (th_holds (=0_Real (poly_term p2)))
+ (! f1 (th_holds (distinct0_poly p1))
+ (! f2 (th_holds (=0_poly p2))
(! i (^ (poly_sub p1 p2) p3)
- (th_holds (distinct0_Real (poly_term p3)))))))))))
+ (th_holds (distinct0_poly p3)))))))))
;; converting between terms and polynomials
@@ -357,6 +388,14 @@
(! a (^ (poly_mul_c py x) pz)
(poly_norm (*_Real y (a_real x)) pz))))))))
+(declare poly_flip_not_>=
+ (! p poly
+ (! p_negged poly
+ (! pf_formula (th_holds (not (>=0_poly p)))
+ (! sc (^ (poly_neg p) p_negged)
+ (th_holds (>0_poly p_negged)))))))
+
+
;; for polynomializing other terms, in particular ite's
(declare term_atom (! v var_real (! t (term Real) type)))
@@ -395,54 +434,10 @@
(! u (th_holds (not ft))
(th_holds (not fp)))))))
-; form equivalence between term formula and polynomial formula
-
-(declare poly_norm_=
- (! x (term Real)
- (! y (term Real)
- (! p poly
- (! h (th_holds (= Real x y))
- (! n (poly_norm (-_Real x y) p)
- (! u (! pn (th_holds (=0_Real (poly_term p)))
- (holds cln))
- (holds cln))))))))
-
-(declare poly_norm_>
+(declare poly_formula_norm_>=
(! x (term Real)
(! y (term Real)
(! p poly
- (! h (th_holds (>_Real x y))
- (! n (poly_norm (-_Real x y) p)
- (! u (! pn (th_holds (>0_Real (poly_term p)))
- (holds cln))
- (holds cln))))))))
-
-(declare poly_norm_<
- (! x (term Real)
- (! y (term Real)
- (! p poly
- (! h (th_holds (<_Real x y))
(! n (poly_norm (-_Real y x) p)
- (! u (! pn (th_holds (>0_Real (poly_term p)))
- (holds cln))
- (holds cln))))))))
-
-(declare poly_norm_>=
- (! x (term Real)
- (! y (term Real)
- (! p poly
- (! h (th_holds (>=_Real x y))
- (! n (poly_norm (-_Real x y) p)
- (! u (! pn (th_holds (>=0_Real (poly_term p)))
- (holds cln))
- (holds cln))))))))
+ (poly_formula_norm (>=_Real y x) (>=0_poly p)))))))
-(declare poly_norm_<=
- (! x (term Real)
- (! y (term Real)
- (! p poly
- (! h (th_holds (<=_Real x y))
- (! n (poly_norm (-_Real y x) p)
- (! u (! pn (th_holds (>=0_Real (poly_term p)))
- (holds cln))
- (holds cln))))))))
diff --git a/proofs/signatures/th_lra_test.plf b/proofs/signatures/th_lra_test.plf
index 687ff988b..fb3ca828c 100644
--- a/proofs/signatures/th_lra_test.plf
+++ b/proofs/signatures/th_lra_test.plf
@@ -1,4 +1,10 @@
; Depends On: th_lra.plf
+;; Proof (from predicates on linear polynomials) that the following imply bottom
+;
+; -x - 1/2 y + 2 >= 0
+; x + y - 8 >= 0
+; x - y + 0 >= 0
+;
(check
; Variables
(% x var_real
@@ -11,22 +17,151 @@
(@ p1 (polyc 2/1 m1)
(@ p2 (polyc (~ 8/1) m2)
(@ p3 (polyc 0/1 m3)
- (% pf_nonneg_1 (th_holds (>=0_Real (poly_term p1)))
- (% pf_nonneg_2 (th_holds (>=0_Real (poly_term p2)))
- (% pf_nonneg_3 (th_holds (>=0_Real (poly_term p3)))
- (lra_contra_>=
- _
- (lra_add_>=_>= _ _ _
- (lra_mul_c_>= _ _ 4/1 pf_nonneg_1)
+ (% pf_nonneg_1 (th_holds (>=0_poly p1))
+ (% pf_nonneg_2 (th_holds (>=0_poly p2))
+ (% pf_nonneg_3 (th_holds (>=0_poly p3))
+ (:
+ (holds cln)
+ (lra_contra_>=
+ _
(lra_add_>=_>= _ _ _
- (lra_mul_c_>= _ _ 3/1 pf_nonneg_2)
+ (lra_mul_c_>= _ _ 4/1 pf_nonneg_1)
(lra_add_>=_>= _ _ _
- (lra_mul_c_>= _ _ 1/1 pf_nonneg_3)
- (lra_axiom_>= 0/1)))))
+ (lra_mul_c_>= _ _ 3/1 pf_nonneg_2)
+ (lra_add_>=_>= _ _ _
+ (lra_mul_c_>= _ _ 1/1 pf_nonneg_3)
+ (lra_axiom_>= 0/1))))))
)))))
))))
))
)
+;; Proof (from predicates on real terms) that the following imply bottom
+;
+; -x - 1/2 y >= 2
+; x + y >= 8
+; x - y >= 0
+;
+(check
+ ; Declarations
+ ; Variables
+ (% x var_real
+ (% y var_real
+ ; real predicates
+ (@ f1 (>=_Real (+_Real (*_Real (a_real (~ 1/1)) (a_var_real x)) (*_Real (a_real (~ 1/2)) (a_var_real y))) (a_real (~ 2/1)))
+ (@ f2 (>=_Real (+_Real (*_Real (a_real 1/1) (a_var_real x)) (*_Real (a_real 1/1) (a_var_real y))) (a_real 8/1))
+ (@ f3 (>=_Real (+_Real (*_Real (a_real 1/1) (a_var_real x)) (*_Real (a_real (~ 1/1)) (a_var_real y))) (a_real 0/1))
+ ; proof of real predicates
+ (% pf_f1 (th_holds f1)
+ (% pf_f2 (th_holds f2)
+ (% pf_f3 (th_holds f3)
+
+
+ ; Normalization
+ ; real term -> linear polynomial normalization witnesses
+ (@ n1 (poly_formula_norm_>= _ _ _
+ (pn_- _ _ _ _ _
+ (pn_+ _ _ _ _ _
+ (pn_mul_c_L _ _ _ (~ 1/1) (pn_var x))
+ (pn_mul_c_L _ _ _ (~ 1/2) (pn_var y)))
+ (pn_const (~ 2/1))))
+ (@ n2 (poly_formula_norm_>= _ _ _
+ (pn_- _ _ _ _ _
+ (pn_+ _ _ _ _ _
+ (pn_mul_c_L _ _ _ 1/1 (pn_var x))
+ (pn_mul_c_L _ _ _ 1/1 (pn_var y)))
+ (pn_const 8/1)))
+ (@ n3 (poly_formula_norm_>= _ _ _
+ (pn_- _ _ _ _ _
+ (pn_+ _ _ _ _ _
+ (pn_mul_c_L _ _ _ 1/1 (pn_var x))
+ (pn_mul_c_L _ _ _ (~ 1/1) (pn_var y)))
+ (pn_const 0/1)))
+ ; proof of linear polynomial predicates
+ (@ pf_n1 (poly_form _ _ n1 pf_f1)
+ (@ pf_n2 (poly_form _ _ n2 pf_f2)
+ (@ pf_n3 (poly_form _ _ n3 pf_f3)
+
+ ; derivation of a contradiction using farkas coefficients
+ (:
+ (holds cln)
+ (lra_contra_>= _
+ (lra_add_>=_>= _ _ _
+ (lra_mul_c_>= _ _ 4/1 pf_n1)
+ (lra_add_>=_>= _ _ _
+ (lra_mul_c_>= _ _ 3/1 pf_n2)
+ (lra_add_>=_>= _ _ _
+ (lra_mul_c_>= _ _ 1/1 pf_n3)
+ (lra_axiom_>= 0/1))))))
+ )))
+ )))
+ )))
+ )))
+ ))
+)
+
+;; Term proof, 2 (>=), one (not >=)
+;; Proof (from predicates on real terms) that the following imply bottom
+;
+; -x + y >= 2
+; x + y >= 2
+; not[ y >= -2] => [y < -2] => [-y > 2]
+;
+(check
+ ; Declarations
+ ; Variables
+ (% x var_real
+ (% y var_real
+ ; real predicates
+ (@ f1 (>=_Real
+ (+_Real (*_Real (a_real (~ 1/1)) (a_var_real x)) (a_var_real y))
+ (a_real 2/1))
+ (@ f2 (>=_Real
+ (+_Real (a_var_real x) (a_var_real y))
+ (a_real 2/1))
+ (@ f3 (not (>=_Real (a_var_real y) (a_real (~ 2/1))))
+ ; Normalization
+ ; proof of real predicates
+ (% pf_f1 (th_holds f1)
+ (% pf_f2 (th_holds f2)
+ (% pf_f3 (th_holds f3)
+ ; real term -> linear polynomial normalization witnesses
+ (@ n1 (poly_formula_norm_>= _ _ _
+ (pn_- _ _ _ _ _
+ (pn_+ _ _ _ _ _
+ (pn_mul_c_L _ _ _ (~ 1/1) (pn_var x))
+ (pn_var y))
+ (pn_const 2/1)))
+ (@ n2 (poly_formula_norm_>= _ _ _
+ (pn_- _ _ _ _ _
+ (pn_+ _ _ _ _ _
+ (pn_var x)
+ (pn_var y))
+ (pn_const 2/1)))
+ (@ n3 (poly_formula_norm_>= _ _ _
+ (pn_- _ _ _ _ _
+ (pn_var y)
+ (pn_const (~ 2/1))))
+ ; proof of linear polynomial predicates
+ (@ pf_n1 (poly_form _ _ n1 pf_f1)
+ (@ pf_n2 (poly_form _ _ n2 pf_f2)
+ (@ pf_n3 (poly_flip_not_>= _ _ (poly_form_not _ _ n3 pf_f3))
+ ; derivation of a contradiction using farkas coefficients
+ (:
+ (holds cln)
+ (lra_contra_> _
+ (lra_add_>=_> _ _ _
+ (lra_mul_c_>= _ _ 1/1 pf_n1)
+ (lra_add_>=_> _ _ _
+ (lra_mul_c_>= _ _ 1/1 pf_n2)
+ (lra_add_>_>= _ _ _
+ (lra_mul_c_> _ _ 2/1 pf_n3)
+ (lra_axiom_>= 0/1))))))
+ )))
+ )))
+ )))
+ )))
+ ))
+)
diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt
index 9e93bd953..889260045 100644
--- a/src/CMakeLists.txt
+++ b/src/CMakeLists.txt
@@ -124,6 +124,8 @@ libcvc4_add_sources(
printer/tptp/tptp_printer.h
proof/arith_proof.cpp
proof/arith_proof.h
+ proof/arith_proof_recorder.cpp
+ proof/arith_proof_recorder.h
proof/array_proof.cpp
proof/array_proof.h
proof/bitvector_proof.cpp
@@ -475,8 +477,6 @@ libcvc4_add_sources(
theory/quantifiers/extended_rewrite.h
theory/quantifiers/first_order_model.cpp
theory/quantifiers/first_order_model.h
- theory/quantifiers/fmf/ambqi_builder.cpp
- theory/quantifiers/fmf/ambqi_builder.h
theory/quantifiers/fmf/bounded_integers.cpp
theory/quantifiers/fmf/bounded_integers.h
theory/quantifiers/fmf/full_model_check.cpp
@@ -739,6 +739,10 @@ if(USE_CRYPTOMINISAT)
target_link_libraries(cvc4 ${CryptoMiniSat_LIBRARIES})
target_include_directories(cvc4 PUBLIC ${CryptoMiniSat_INCLUDE_DIR})
endif()
+if(USE_DRAT2ER)
+ target_link_libraries(cvc4 ${Drat2Er_LIBRARIES})
+ target_include_directories(cvc4 PUBLIC ${Drat2Er_INCLUDE_DIR})
+endif()
if(USE_GLPK)
target_link_libraries(cvc4 ${GLPK_LIBRARIES})
target_include_directories(cvc4 PUBLIC ${GLPK_INCLUDE_DIR})
diff --git a/src/api/cvc4cpp.cpp b/src/api/cvc4cpp.cpp
index b4d3b013d..cd604a25c 100644
--- a/src/api/cvc4cpp.cpp
+++ b/src/api/cvc4cpp.cpp
@@ -635,6 +635,10 @@ class CVC4ApiExceptionStream
CVC4_PREDICT_FALSE(cond) \
? (void)0 : OstreamVoider() & CVC4ApiExceptionStream().ostream()
+#define CVC4_API_CHECK_NOT_NULL \
+ CVC4_API_CHECK(!isNull()) << "Invalid call to '" << __PRETTY_FUNCTION__ \
+ << "', expected non-null object";
+
#define CVC4_API_KIND_CHECK(kind) \
CVC4_API_CHECK(isDefinedKind(kind)) \
<< "Invalid kind '" << kindToString(kind) << "'";
@@ -1003,27 +1007,102 @@ bool Term::operator==(const Term& t) const { return *d_expr == *t.d_expr; }
bool Term::operator!=(const Term& t) const { return *d_expr != *t.d_expr; }
-Kind Term::getKind() const { return intToExtKind(d_expr->getKind()); }
+Kind Term::getKind() const
+{
+ CVC4_API_CHECK_NOT_NULL;
+ return intToExtKind(d_expr->getKind());
+}
-Sort Term::getSort() const { return Sort(d_expr->getType()); }
+Sort Term::getSort() const
+{
+ CVC4_API_CHECK_NOT_NULL;
+ return Sort(d_expr->getType());
+}
bool Term::isNull() const { return d_expr->isNull(); }
-Term Term::notTerm() const { return d_expr->notExpr(); }
+Term Term::notTerm() const
+{
+ try
+ {
+ return d_expr->notExpr();
+ }
+ catch (TypeCheckingException& e)
+ {
+ throw CVC4ApiException(e.getMessage());
+ }
+}
-Term Term::andTerm(const Term& t) const { return d_expr->andExpr(*t.d_expr); }
+Term Term::andTerm(const Term& t) const
+{
+ try
+ {
+ return d_expr->andExpr(*t.d_expr);
+ }
+ catch (TypeCheckingException& e)
+ {
+ throw CVC4ApiException(e.getMessage());
+ }
+}
-Term Term::orTerm(const Term& t) const { return d_expr->orExpr(*t.d_expr); }
+Term Term::orTerm(const Term& t) const
+{
+ try
+ {
+ return d_expr->orExpr(*t.d_expr);
+ }
+ catch (TypeCheckingException& e)
+ {
+ throw CVC4ApiException(e.getMessage());
+ }
+}
-Term Term::xorTerm(const Term& t) const { return d_expr->xorExpr(*t.d_expr); }
+Term Term::xorTerm(const Term& t) const
+{
+ try
+ {
+ return d_expr->xorExpr(*t.d_expr);
+ }
+ catch (TypeCheckingException& e)
+ {
+ throw CVC4ApiException(e.getMessage());
+ }
+}
-Term Term::iffTerm(const Term& t) const { return d_expr->iffExpr(*t.d_expr); }
+Term Term::eqTerm(const Term& t) const
+{
+ try
+ {
+ return d_expr->eqExpr(*t.d_expr);
+ }
+ catch (TypeCheckingException& e)
+ {
+ throw CVC4ApiException(e.getMessage());
+ }
+}
-Term Term::impTerm(const Term& t) const { return d_expr->impExpr(*t.d_expr); }
+Term Term::impTerm(const Term& t) const
+{
+ try
+ {
+ return d_expr->impExpr(*t.d_expr);
+ }
+ catch (TypeCheckingException& e)
+ {
+ throw CVC4ApiException(e.getMessage());
+ }
+}
Term Term::iteTerm(const Term& then_t, const Term& else_t) const
{
- return d_expr->iteExpr(*then_t.d_expr, *else_t.d_expr);
+ try
+ {
+ return d_expr->iteExpr(*then_t.d_expr, *else_t.d_expr);
+ }
+ catch (TypeCheckingException& e)
+ {
+ throw CVC4ApiException(e.getMessage());
+ }
}
std::string Term::toString() const { return d_expr->toString(); }
@@ -1166,9 +1245,17 @@ bool OpTerm::operator==(const OpTerm& t) const { return *d_expr == *t.d_expr; }
bool OpTerm::operator!=(const OpTerm& t) const { return *d_expr != *t.d_expr; }
-Kind OpTerm::getKind() const { return intToExtKind(d_expr->getKind()); }
+Kind OpTerm::getKind() const
+{
+ CVC4_API_CHECK_NOT_NULL;
+ return intToExtKind(d_expr->getKind());
+}
-Sort OpTerm::getSort() const { return Sort(d_expr->getType()); }
+Sort OpTerm::getSort() const
+{
+ CVC4_API_CHECK_NOT_NULL;
+ return Sort(d_expr->getType());
+}
bool OpTerm::isNull() const { return d_expr->isNull(); }
@@ -1750,6 +1837,7 @@ Sort Solver::mkUninterpretedSort(const std::string& symbol) const
Sort Solver::mkSortConstructorSort(const std::string& symbol,
size_t arity) const
{
+ CVC4_API_ARG_CHECK_EXPECTED(arity > 0, arity) << "an arity > 0";
return d_exprMgr->mkSortConstructor(symbol, arity);
}
diff --git a/src/api/cvc4cpp.h b/src/api/cvc4cpp.h
index aebeffb0d..d06955a05 100644
--- a/src/api/cvc4cpp.h
+++ b/src/api/cvc4cpp.h
@@ -607,11 +607,11 @@ class CVC4_PUBLIC Term
Term xorTerm(const Term& t) const;
/**
- * Boolean if-and-only-if.
+ * Equality.
* @param t a Boolean term
* @return the Boolean equivalence of this term and the given term
*/
- Term iffTerm(const Term& t) const;
+ Term eqTerm(const Term& t) const;
/**
* Boolean implication.
diff --git a/src/base/configuration_private.h b/src/base/configuration_private.h
index 5164d46bc..77f3f5e77 100644
--- a/src/base/configuration_private.h
+++ b/src/base/configuration_private.h
@@ -126,6 +126,12 @@ namespace CVC4 {
# define IS_CRYPTOMINISAT_BUILD false
#endif /* CVC4_USE_CRYPTOMINISAT */
+#if CVC4_USE_DRAT2ER
+# define IS_DRAT2ER_BUILD true
+#else /* CVC4_USE_DRAT2ER */
+# define IS_DRAT2ER_BUILD false
+#endif /* CVC4_USE_DRAT2ER */
+
#if CVC4_USE_LFSC
#define IS_LFSC_BUILD true
#else /* CVC4_USE_LFSC */
diff --git a/src/expr/expr_template.cpp b/src/expr/expr_template.cpp
index 61568e411..96bdb2d04 100644
--- a/src/expr/expr_template.cpp
+++ b/src/expr/expr_template.cpp
@@ -595,7 +595,8 @@ Expr Expr::xorExpr(const Expr& e) const {
return d_exprManager->mkExpr(XOR, *this, e);
}
-Expr Expr::iffExpr(const Expr& e) const {
+Expr Expr::eqExpr(const Expr& e) const
+{
Assert(d_exprManager != NULL,
"Don't have an expression manager for this expression!");
PrettyCheckArgument(d_exprManager == e.d_exprManager, e,
diff --git a/src/expr/expr_template.h b/src/expr/expr_template.h
index 324915b1d..da9d22389 100644
--- a/src/expr/expr_template.h
+++ b/src/expr/expr_template.h
@@ -391,7 +391,7 @@ public:
* Returns the Boolean equivalence of this expression and
* the given expression.
*/
- Expr iffExpr(const Expr& e) const;
+ Expr eqExpr(const Expr& e) const;
/**
* Returns the implication of this expression and
diff --git a/src/expr/type_node.cpp b/src/expr/type_node.cpp
index fd65f96b9..b54290612 100644
--- a/src/expr/type_node.cpp
+++ b/src/expr/type_node.cpp
@@ -20,7 +20,6 @@
#include "expr/node_manager_attributes.h"
#include "expr/type_properties.h"
#include "options/base_options.h"
-#include "options/bv_options.h"
#include "options/expr_options.h"
#include "options/quantifiers_options.h"
#include "options/uf_options.h"
@@ -223,7 +222,6 @@ bool TypeNode::isClosedEnumerable()
}
bool TypeNode::isFirstClass() const {
- (void)options::bitblastMode();
return ( getKind() != kind::FUNCTION_TYPE || options::ufHo() ) &&
getKind() != kind::CONSTRUCTOR_TYPE &&
getKind() != kind::SELECTOR_TYPE &&
diff --git a/src/options/CMakeLists.txt b/src/options/CMakeLists.txt
index c711567ab..b86db8d00 100644
--- a/src/options/CMakeLists.txt
+++ b/src/options/CMakeLists.txt
@@ -9,6 +9,8 @@ libcvc4_add_sources(
arith_unate_lemma_mode.cpp
arith_unate_lemma_mode.h
base_handlers.h
+ bool_to_bv_mode.cpp
+ bool_to_bv_mode.h
bv_bitblast_mode.cpp
bv_bitblast_mode.h
datatypes_modes.h
diff --git a/src/options/bool_to_bv_mode.cpp b/src/options/bool_to_bv_mode.cpp
new file mode 100644
index 000000000..670e15419
--- /dev/null
+++ b/src/options/bool_to_bv_mode.cpp
@@ -0,0 +1,42 @@
+/********************* */
+/*! \file bool_to_bv_mode.cpp
+** \verbatim
+** Top contributors (to current version):
+** Makai Mann
+** This file is part of the CVC4 project.
+** Copyright (c) 2009-2018 by the authors listed in the file AUTHORS
+** in the top-level source directory) and their institutional affiliations.
+** All rights reserved. See the file COPYING in the top-level source
+** directory for licensing information.\endverbatim
+**
+** \brief Modes for bool-to-bv preprocessing pass
+**
+** Modes for bool-to-bv preprocessing pass which tries to lower booleans
+** to bit-vectors of width 1 at various levels of aggressiveness.
+**/
+
+#include "options/bool_to_bv_mode.h"
+
+#include <iostream>
+
+
+namespace CVC4
+{
+ std::ostream& operator<<(std::ostream& out, preprocessing::passes::BoolToBVMode mode) {
+ switch(mode) {
+ case preprocessing::passes::BOOL_TO_BV_OFF:
+ out << "BOOL_TO_BV_OFF";
+ break;
+ case preprocessing::passes::BOOL_TO_BV_ITE:
+ out << "BOOL_TO_BV_ITE";
+ break;
+ case preprocessing::passes::BOOL_TO_BV_ALL:
+ out << "BOOL_TO_BV_ALL";
+ break;
+ default:
+ out << "BoolToBVMode:UNKNOWN![" << unsigned(mode) << "]";
+ }
+
+ return out;
+ }
+} // namespace CVC4
diff --git a/src/options/bool_to_bv_mode.h b/src/options/bool_to_bv_mode.h
new file mode 100644
index 000000000..f2911c339
--- /dev/null
+++ b/src/options/bool_to_bv_mode.h
@@ -0,0 +1,57 @@
+/********************* */
+/*! \file bool_to_bv_mode.h
+** \verbatim
+** Top contributors (to current version):
+** Makai Mann
+** This file is part of the CVC4 project.
+** Copyright (c) 2009-2018 by the authors listed in the file AUTHORS
+** in the top-level source directory) and their institutional affiliations.
+** All rights reserved. See the file COPYING in the top-level source
+** directory for licensing information.\endverbatim
+**
+** \brief Modes for bool-to-bv preprocessing pass
+**
+** Modes for bool-to-bv preprocessing pass which tries to lower booleans
+** to bit-vectors of width 1 at various levels of aggressiveness.
+**/
+
+#include "cvc4_private.h"
+
+#ifndef __CVC4__PREPROCESSING__PASSES__BOOL_TO_BV_MODE_H
+#define __CVC4__PREPROCESSING__PASSES__BOOL_TO_BV_MODE_H
+
+#include <iosfwd>
+
+namespace CVC4 {
+namespace preprocessing {
+namespace passes {
+
+/** Enumeration of bool-to-bv modes */
+enum BoolToBVMode
+{
+ /**
+ * No bool-to-bv pass
+ */
+ BOOL_TO_BV_OFF,
+
+ /**
+ * Only lower bools in condition of ITEs
+ * Tries to give more info to bit-vector solver
+ * by using bit-vector-ITEs when possible
+ */
+ BOOL_TO_BV_ITE,
+
+ /**
+ * Lower every bool beneath the top layer to be a
+ * bit-vector
+ */
+ BOOL_TO_BV_ALL
+};
+}
+}
+
+std::ostream& operator<<(std::ostream& out, preprocessing::passes::BoolToBVMode mode);
+
+}
+
+#endif /* __CVC4__PREPROCESSING__PASSES__BOOL_TO_BV_MODE_H */
diff --git a/src/options/bv_options.toml b/src/options/bv_options.toml
index 15a9047c7..00290da7d 100644
--- a/src/options/bv_options.toml
+++ b/src/options/bv_options.toml
@@ -105,11 +105,22 @@ header = "options/bv_options.h"
[[option]]
name = "boolToBitvector"
+ smt_name = "bool-to-bv"
category = "regular"
- long = "bool-to-bv"
+ long = "bool-to-bv=MODE"
+ type = "CVC4::preprocessing::passes::BoolToBVMode"
+ default = "CVC4::preprocessing::passes::BOOL_TO_BV_OFF"
+ handler = "stringToBoolToBVMode"
+ includes = ["options/bool_to_bv_mode.h"]
+ help = "convert booleans to bit-vectors of size 1 at various levels of aggressiveness, see --bool-to-bv=help"
+
+[[option]]
+ name = "bitwiseEq"
+ category = "regular"
+ long = "bitwise-eq"
type = "bool"
- default = "false"
- help = "convert booleans to bit-vectors of size 1 when possible"
+ default = "true"
+ help = "lift equivalence with one-bit bit-vectors to be boolean operations"
[[option]]
name = "bitvectorDivByZeroConst"
diff --git a/src/options/options_handler.cpp b/src/options/options_handler.cpp
index bd5b00728..36144e70e 100644
--- a/src/options/options_handler.cpp
+++ b/src/options/options_handler.cpp
@@ -267,7 +267,8 @@ agg \n\
\n\
";
-const std::string OptionsHandler::s_mbqiModeHelp = "\
+const std::string OptionsHandler::s_mbqiModeHelp =
+ "\
Model-based quantifier instantiation modes currently supported by the --mbqi option:\n\
\n\
default \n\
@@ -277,12 +278,8 @@ default \n\
none \n\
+ Disable model-based quantifier instantiation.\n\
\n\
-gen-ev \n\
-+ Use model-based quantifier instantiation algorithm from CADE 24 finite\n\
- model finding paper based on generalizing evaluations.\n\
-\n\
-abs \n\
-+ Use abstract MBQI algorithm (uses disjoint sets). \n\
+trust \n\
++ Do not instantiate quantified formulas (incomplete technique).\n\
\n\
";
@@ -660,14 +657,11 @@ void OptionsHandler::checkLiteralMatchMode(
theory::quantifiers::MbqiMode OptionsHandler::stringToMbqiMode(
std::string option, std::string optarg)
{
- if(optarg == "gen-ev") {
- return theory::quantifiers::MBQI_GEN_EVAL;
- } else if(optarg == "none") {
+ if (optarg == "none")
+ {
return theory::quantifiers::MBQI_NONE;
} else if(optarg == "default" || optarg == "fmc") {
return theory::quantifiers::MBQI_FMC;
- } else if(optarg == "abs") {
- return theory::quantifiers::MBQI_ABS;
} else if(optarg == "trust") {
return theory::quantifiers::MBQI_TRUST;
} else if(optarg == "help") {
@@ -1301,6 +1295,50 @@ theory::bv::BvSlicerMode OptionsHandler::stringToBvSlicerMode(
}
}
+const std::string OptionsHandler::s_boolToBVModeHelp =
+ "\
+BoolToBV pass modes supported by the --bool-to-bv option:\n\
+\n\
+off (default)\n\
++ Don't push any booleans to width one bit-vectors\n\
+\n\
+ite\n\
++ Try to turn ITEs into BITVECTOR_ITE when possible. It can fail per-formula \n\
+ if not all sub-formulas can be turned to bit-vectors\n\
+\n\
+all\n\
++ Force all booleans to be bit-vectors of width one except at the top level.\n\
+ Most aggressive mode\n\
+";
+
+preprocessing::passes::BoolToBVMode OptionsHandler::stringToBoolToBVMode(
+ std::string option, std::string optarg)
+{
+ if (optarg == "off")
+ {
+ return preprocessing::passes::BOOL_TO_BV_OFF;
+ }
+ else if (optarg == "ite")
+ {
+ return preprocessing::passes::BOOL_TO_BV_ITE;
+ }
+ else if (optarg == "all")
+ {
+ return preprocessing::passes::BOOL_TO_BV_ALL;
+ }
+ else if (optarg == "help")
+ {
+ puts(s_boolToBVModeHelp.c_str());
+ exit(1);
+ }
+ else
+ {
+ throw OptionException(std::string("unknown option for --bool-to-bv: `")
+ + optarg
+ + "'. Try --bool-to-bv=help");
+ }
+}
+
void OptionsHandler::setBitblastAig(std::string option, bool arg)
{
if(arg) {
@@ -1632,7 +1670,14 @@ void OptionsHandler::setProduceAssertions(std::string option, bool value)
void OptionsHandler::proofEnabledBuild(std::string option, bool value)
{
-#ifndef CVC4_PROOF
+#ifdef CVC4_PROOF
+ if (value && options::bitblastMode() == theory::bv::BITBLAST_MODE_EAGER
+ && options::bvSatSolver() != theory::bv::SAT_SOLVER_MINISAT)
+ {
+ throw OptionException(
+ "Eager BV proofs only supported when minisat is used");
+ }
+#else
if(value) {
std::stringstream ss;
ss << "option `" << option << "' requires a proofs-enabled build of CVC4; this binary was not built with proof support";
diff --git a/src/options/options_handler.h b/src/options/options_handler.h
index 53e317895..f96632696 100644
--- a/src/options/options_handler.h
+++ b/src/options/options_handler.h
@@ -27,6 +27,7 @@
#include "options/arith_propagation_mode.h"
#include "options/arith_unate_lemma_mode.h"
#include "options/base_handlers.h"
+#include "options/bool_to_bv_mode.h"
#include "options/bv_bitblast_mode.h"
#include "options/datatypes_modes.h"
#include "options/decision_mode.h"
@@ -137,6 +138,8 @@ public:
std::string optarg);
theory::bv::BvSlicerMode stringToBvSlicerMode(std::string option,
std::string optarg);
+ preprocessing::passes::BoolToBVMode stringToBoolToBVMode(std::string option,
+ std::string optarg);
void setBitblastAig(std::string option, bool arg);
theory::bv::SatSolverMode stringToSatSolver(std::string option,
@@ -229,6 +232,7 @@ public:
static const std::string s_bvSatSolverHelp;
static const std::string s_booleanTermConversionModeHelp;
static const std::string s_bvSlicerModeHelp;
+ static const std::string s_boolToBVModeHelp;
static const std::string s_cegqiFairModeHelp;
static const std::string s_decisionModeHelp;
static const std::string s_instFormatHelp ;
diff --git a/src/options/options_template.cpp b/src/options/options_template.cpp
index 85a9747fe..9650aba7a 100644
--- a/src/options/options_template.cpp
+++ b/src/options/options_template.cpp
@@ -112,7 +112,7 @@ struct OptionHandler<T, true, true> {
if(!success){
throw OptionException(option + ": failed to parse "+ optionarg +
- " as an integer of the appropraite type.");
+ " as an integer of the appropriate type.");
}
// Depending in the platform unsigned numbers with '-' signs may parse.
diff --git a/src/options/quantifiers_modes.cpp b/src/options/quantifiers_modes.cpp
index 1814a363d..b08f71c2e 100644
--- a/src/options/quantifiers_modes.cpp
+++ b/src/options/quantifiers_modes.cpp
@@ -64,18 +64,12 @@ std::ostream& operator<<(std::ostream& out, theory::quantifiers::LiteralMatchMod
std::ostream& operator<<(std::ostream& out, theory::quantifiers::MbqiMode mode) {
switch(mode) {
- case theory::quantifiers::MBQI_GEN_EVAL:
- out << "MBQI_GEN_EVAL";
- break;
case theory::quantifiers::MBQI_NONE:
out << "MBQI_NONE";
break;
case theory::quantifiers::MBQI_FMC:
out << "MBQI_FMC";
break;
- case theory::quantifiers::MBQI_ABS:
- out << "MBQI_ABS";
- break;
case theory::quantifiers::MBQI_TRUST:
out << "MBQI_TRUST";
break;
diff --git a/src/options/quantifiers_modes.h b/src/options/quantifiers_modes.h
index 41378d2cd..eea043865 100644
--- a/src/options/quantifiers_modes.h
+++ b/src/options/quantifiers_modes.h
@@ -53,14 +53,10 @@ enum LiteralMatchMode {
};
enum MbqiMode {
- /** mbqi from CADE 24 paper */
- MBQI_GEN_EVAL,
/** no mbqi */
MBQI_NONE,
/** default, mbqi from Section 5.4.2 of AJR thesis */
MBQI_FMC,
- /** abstract mbqi algorithm */
- MBQI_ABS,
/** mbqi trust (produce no instantiations) */
MBQI_TRUST,
};
diff --git a/src/preprocessing/passes/bool_to_bv.cpp b/src/preprocessing/passes/bool_to_bv.cpp
index c8a59bdc4..252ab941c 100644
--- a/src/preprocessing/passes/bool_to_bv.cpp
+++ b/src/preprocessing/passes/bool_to_bv.cpp
@@ -9,17 +9,17 @@
** All rights reserved. See the file COPYING in the top-level source
** directory for licensing information.\endverbatim
**
- ** \brief The BoolToBv preprocessing pass
+ ** \brief The BoolToBV preprocessing pass
**
**/
#include "preprocessing/passes/bool_to_bv.h"
#include <string>
-#include <unordered_map>
-#include <vector>
+#include "base/map_util.h"
#include "expr/node.h"
+#include "options/bv_options.h"
#include "smt/smt_statistics_registry.h"
#include "theory/rewriter.h"
#include "theory/theory.h"
@@ -30,183 +30,253 @@ namespace passes {
using namespace CVC4::theory;
BoolToBV::BoolToBV(PreprocessingPassContext* preprocContext)
- : PreprocessingPass(preprocContext, "bool-to-bv"),
- d_lowerCache(),
- d_one(bv::utils::mkOne(1)),
- d_zero(bv::utils::mkZero(1)),
- d_statistics(){};
+ : PreprocessingPass(preprocContext, "bool-to-bv"), d_statistics(){};
PreprocessingPassResult BoolToBV::applyInternal(
AssertionPipeline* assertionsToPreprocess)
{
NodeManager::currentResourceManager()->spendResource(
options::preprocessStep());
- std::vector<Node> new_assertions;
- lowerBoolToBv(assertionsToPreprocess->ref(), new_assertions);
- for (unsigned i = 0; i < assertionsToPreprocess->size(); ++i)
+
+ unsigned size = assertionsToPreprocess->size();
+ for (unsigned i = 0; i < size; ++i)
{
- assertionsToPreprocess->replace(i, Rewriter::rewrite(new_assertions[i]));
+ assertionsToPreprocess->replace(
+ i, Rewriter::rewrite(lowerAssertion((*assertionsToPreprocess)[i])));
}
- return PreprocessingPassResult::NO_CONFLICT;
-}
-void BoolToBV::addToLowerCache(TNode term, Node new_term)
-{
- Assert(new_term != Node());
- Assert(!hasLowerCache(term));
- d_lowerCache[term] = new_term;
+ return PreprocessingPassResult::NO_CONFLICT;
}
-Node BoolToBV::getLowerCache(TNode term) const
+Node BoolToBV::fromCache(TNode n) const
{
- Assert(hasLowerCache(term));
- return d_lowerCache.find(term)->second;
+ if (d_lowerCache.find(n) != d_lowerCache.end())
+ {
+ return d_lowerCache.find(n)->second;
+ }
+ return n;
}
-bool BoolToBV::hasLowerCache(TNode term) const
+bool BoolToBV::needToRebuild(TNode n) const
{
- return d_lowerCache.find(term) != d_lowerCache.end();
+ // check if any children were rebuilt
+ for (const Node& nn : n)
+ {
+ if (ContainsKey(d_lowerCache, nn))
+ {
+ return true;
+ }
+ }
+ return false;
}
-Node BoolToBV::lowerNode(TNode current, bool topLevel)
+Node BoolToBV::lowerAssertion(const TNode& a)
{
- Node result;
+ bool optionITE = options::boolToBitvector() == BOOL_TO_BV_ITE;
NodeManager* nm = NodeManager::currentNM();
- if (hasLowerCache(current))
- {
- result = getLowerCache(current);
- }
- else
+ std::vector<TNode> visit;
+ visit.push_back(a);
+ std::unordered_set<TNode, TNodeHashFunction> visited;
+ // for ite mode, keeps track of whether you're in an ite condition
+ // for all mode, unused
+ std::unordered_set<TNode, TNodeHashFunction> ite_cond;
+
+ while (!visit.empty())
{
- if (current.getNumChildren() == 0)
+ TNode n = visit.back();
+ visit.pop_back();
+
+ int numChildren = n.getNumChildren();
+ Kind k = n.getKind();
+ Debug("bool-to-bv") << "BoolToBV::lowerAssertion Post-traversal with " << n
+ << " and visited = " << ContainsKey(visited, n)
+ << std::endl;
+
+ // Mark as visited
+ /* Optimization: if it's a leaf, don't need to wait to do the work */
+ if (!ContainsKey(visited, n) && (numChildren > 0))
{
- if (current.getKind() == kind::CONST_BOOLEAN)
+ visited.insert(n);
+ visit.push_back(n);
+
+ // insert children in reverse order so that they're processed in order
+ // important for rewriting which sorts by node id
+ for (int i = numChildren - 1; i >= 0; --i)
{
- result = (current == bv::utils::mkTrue()) ? d_one : d_zero;
+ visit.push_back(n[i]);
}
- else
+
+ if (optionITE)
{
- result = current;
+ // check for ite-conditions
+ if (k == kind::ITE)
+ {
+ ite_cond.insert(n[0]);
+ }
+ else if (ContainsKey(ite_cond, n))
+ {
+ // being part of an ite condition is inherited from the parent
+ ite_cond.insert(n.begin(), n.end());
+ }
}
}
+ /* Optimization for ite mode */
+ else if (optionITE && !ContainsKey(ite_cond, n) && !needToRebuild(n))
+ {
+ Debug("bool-to-bv")
+ << "BoolToBV::lowerAssertion Skipping because don't need to rebuild: "
+ << n << std::endl;
+ // in ite mode, if you've already visited the node but it's not
+ // in an ite condition and doesn't need to be rebuilt, then
+ // don't need to do anything
+ continue;
+ }
else
{
- Kind kind = current.getKind();
- Kind new_kind = kind;
- switch (kind)
- {
- case kind::EQUAL:
- if (current[0].getType().isBitVector()
- || current[0].getType().isBoolean())
- {
- new_kind = kind::BITVECTOR_COMP;
- }
- break;
- case kind::AND: new_kind = kind::BITVECTOR_AND; break;
- case kind::OR: new_kind = kind::BITVECTOR_OR; break;
- case kind::NOT: new_kind = kind::BITVECTOR_NOT; break;
- case kind::XOR: new_kind = kind::BITVECTOR_XOR; break;
- case kind::IMPLIES: new_kind = kind::BITVECTOR_OR; break;
- case kind::ITE:
- if (current.getType().isBitVector() || current.getType().isBoolean())
- {
- new_kind = kind::BITVECTOR_ITE;
- }
- break;
- case kind::BITVECTOR_ULT: new_kind = kind::BITVECTOR_ULTBV; break;
- case kind::BITVECTOR_SLT: new_kind = kind::BITVECTOR_SLTBV; break;
- case kind::BITVECTOR_ULE:
- case kind::BITVECTOR_UGT:
- case kind::BITVECTOR_UGE:
- case kind::BITVECTOR_SLE:
- case kind::BITVECTOR_SGT:
- case kind::BITVECTOR_SGE:
- // Should have been removed by rewriting.
- Unreachable();
- default: break;
- }
- NodeBuilder<> builder(new_kind);
- if (kind != new_kind)
- {
- ++(d_statistics.d_numTermsLowered);
- }
- if (current.getMetaKind() == kind::metakind::PARAMETERIZED)
- {
- builder << current.getOperator();
- }
- Node converted;
- if (new_kind == kind::ITE)
+ lowerNode(n);
+ }
+ }
+
+ if (fromCache(a).getType().isBitVector())
+ {
+ return nm->mkNode(kind::EQUAL, fromCache(a), bv::utils::mkOne(1));
+ }
+ else
+ {
+ Assert(a == fromCache(a));
+ return a;
+ }
+}
+
+void BoolToBV::lowerNode(const TNode& n)
+{
+ NodeManager* nm = NodeManager::currentNM();
+ Kind k = n.getKind();
+
+ bool all_bv = true;
+ // check if it was able to convert all children to bitvectors
+ for (const Node& nn : n)
+ {
+ all_bv = all_bv && fromCache(nn).getType().isBitVector();
+ if (!all_bv)
+ {
+ break;
+ }
+ }
+
+ if (!all_bv || (n.getNumChildren() == 0))
+ {
+ if ((options::boolToBitvector() == BOOL_TO_BV_ALL)
+ && n.getType().isBoolean())
+ {
+ if (k == kind::CONST_BOOLEAN)
{
- // Special-case ITE because need condition to be Boolean.
- converted = lowerNode(current[0], true);
- builder << converted;
- converted = lowerNode(current[1]);
- builder << converted;
- converted = lowerNode(current[2]);
- builder << converted;
- }
- else if (kind == kind::IMPLIES) {
- // Special-case IMPLIES because needs to be rewritten.
- converted = lowerNode(current[0]);
- builder << nm->mkNode(kind::BITVECTOR_NOT, converted);
- converted = lowerNode(current[1]);
- builder << converted;
+ d_lowerCache[n] = (n == bv::utils::mkTrue()) ? bv::utils::mkOne(1)
+ : bv::utils::mkZero(1);
}
else
{
- for (unsigned i = 0; i < current.getNumChildren(); ++i)
- {
- converted = lowerNode(current[i]);
- builder << converted;
- }
+ d_lowerCache[n] =
+ nm->mkNode(kind::ITE, n, bv::utils::mkOne(1), bv::utils::mkZero(1));
}
- result = builder;
+
+ Debug("bool-to-bv") << "BoolToBV::lowerNode " << n << " =>\n"
+ << fromCache(n) << std::endl;
+ ++(d_statistics.d_numTermsForcedLowered);
+ return;
}
- if (result.getType().isBoolean())
+ else
{
- ++(d_statistics.d_numTermsForcedLowered);
- result = nm->mkNode(kind::ITE, result, d_one, d_zero);
+ // invariant
+ // either one of the children is not a bit-vector or bool
+ // i.e. something that can't be 'forced' to a bitvector
+ // or it's in 'ite' mode which will give up on bools that
+ // can't be converted easily
+
+ Debug("bool-to-bv") << "BoolToBV::lowerNode skipping: " << n << std::endl;
+ return;
}
- addToLowerCache(current, result);
}
- if (topLevel)
+
+ Kind new_kind = k;
+ switch (k)
{
- result = nm->mkNode(kind::EQUAL, result, d_one);
+ case kind::EQUAL: new_kind = kind::BITVECTOR_COMP; break;
+ case kind::AND: new_kind = kind::BITVECTOR_AND; break;
+ case kind::OR: new_kind = kind::BITVECTOR_OR; break;
+ case kind::NOT: new_kind = kind::BITVECTOR_NOT; break;
+ case kind::XOR: new_kind = kind::BITVECTOR_XOR; break;
+ case kind::IMPLIES: new_kind = kind::BITVECTOR_OR; break;
+ case kind::ITE: new_kind = kind::BITVECTOR_ITE; break;
+ case kind::BITVECTOR_ULT: new_kind = kind::BITVECTOR_ULTBV; break;
+ case kind::BITVECTOR_SLT: new_kind = kind::BITVECTOR_SLTBV; break;
+ case kind::BITVECTOR_ULE:
+ case kind::BITVECTOR_UGT:
+ case kind::BITVECTOR_UGE:
+ case kind::BITVECTOR_SLE:
+ case kind::BITVECTOR_SGT:
+ case kind::BITVECTOR_SGE:
+ // Should have been removed by rewriting.
+ Unreachable();
+ default: break;
}
- Assert(result != Node());
- Debug("bool-to-bv") << "BoolToBV::lowerNode " << current << " => \n"
- << result << "\n";
- return result;
-}
-void BoolToBV::lowerBoolToBv(const std::vector<Node>& assertions,
- std::vector<Node>& new_assertions)
-{
- for (unsigned i = 0; i < assertions.size(); ++i)
+ NodeBuilder<> builder(new_kind);
+ if ((options::boolToBitvector() == BOOL_TO_BV_ALL) && (new_kind != k))
+ {
+ ++(d_statistics.d_numTermsLowered);
+ }
+
+ if (n.getMetaKind() == kind::metakind::PARAMETERIZED)
+ {
+ builder << n.getOperator();
+ }
+
+ // special case IMPLIES because needs to be rewritten
+ if (k == kind::IMPLIES)
+ {
+ builder << nm->mkNode(kind::BITVECTOR_NOT, fromCache(n[0]));
+ builder << fromCache(n[1]);
+ }
+ else
{
- Node new_assertion = lowerNode(assertions[i], true);
- new_assertions.push_back(new_assertion);
- Trace("bool-to-bv") << " " << assertions[i] << " => " << new_assertions[i]
- << "\n";
+ for (const Node& nn : n)
+ {
+ builder << fromCache(nn);
+ }
}
+
+ Debug("bool-to-bv") << "BoolToBV::lowerNode " << n << " =>\n"
+ << builder << std::endl;
+
+ d_lowerCache[n] = builder.constructNode();
}
BoolToBV::Statistics::Statistics()
- : d_numTermsLowered("preprocessing::passes::BoolToBV::NumTermsLowered", 0),
- d_numAtomsLowered("preprocessing::passes::BoolToBV::NumAtomsLowered", 0),
+ : d_numIteToBvite("preprocessing::passes::BoolToBV::NumIteToBvite", 0),
+ d_numTermsLowered("preprocessing::passes:BoolToBV::NumTermsLowered", 0),
d_numTermsForcedLowered(
"preprocessing::passes::BoolToBV::NumTermsForcedLowered", 0)
{
- smtStatisticsRegistry()->registerStat(&d_numTermsLowered);
- smtStatisticsRegistry()->registerStat(&d_numAtomsLowered);
- smtStatisticsRegistry()->registerStat(&d_numTermsForcedLowered);
+ smtStatisticsRegistry()->registerStat(&d_numIteToBvite);
+ if (options::boolToBitvector() == BOOL_TO_BV_ALL)
+ {
+ // these statistics wouldn't be correct in the ITE mode,
+ // because it might discard rebuilt nodes if it fails to
+ // convert a bool to width-one bit-vector (never forces)
+ smtStatisticsRegistry()->registerStat(&d_numTermsLowered);
+ smtStatisticsRegistry()->registerStat(&d_numTermsForcedLowered);
+ }
}
BoolToBV::Statistics::~Statistics()
{
- smtStatisticsRegistry()->unregisterStat(&d_numTermsLowered);
- smtStatisticsRegistry()->unregisterStat(&d_numAtomsLowered);
- smtStatisticsRegistry()->unregisterStat(&d_numTermsForcedLowered);
+ smtStatisticsRegistry()->unregisterStat(&d_numIteToBvite);
+ if (options::boolToBitvector() == BOOL_TO_BV_ALL)
+ {
+ smtStatisticsRegistry()->unregisterStat(&d_numTermsLowered);
+ smtStatisticsRegistry()->unregisterStat(&d_numTermsForcedLowered);
+ }
}
diff --git a/src/preprocessing/passes/bool_to_bv.h b/src/preprocessing/passes/bool_to_bv.h
index 49c9dc944..da99d3c84 100644
--- a/src/preprocessing/passes/bool_to_bv.h
+++ b/src/preprocessing/passes/bool_to_bv.h
@@ -2,14 +2,14 @@
/*! \file bool_to_bv.h
** \verbatim
** Top contributors (to current version):
- ** Yoni Zohar
+ ** Makai Mann, Yoni Zohar
** This file is part of the CVC4 project.
** Copyright (c) 2009-2018 by the authors listed in the file AUTHORS
** in the top-level source directory) and their institutional affiliations.
** All rights reserved. See the file COPYING in the top-level source
** directory for licensing information.\endverbatim
**
- ** \brief The BoolToBv preprocessing pass
+ ** \brief The BoolToBV preprocessing pass
**
**/
@@ -18,9 +18,9 @@
#ifndef __CVC4__PREPROCESSING__PASSES__BOOL_TO_BV_H
#define __CVC4__PREPROCESSING__PASSES__BOOL_TO_BV_H
-#include "preprocessing/passes/bv_to_bool.h"
#include "preprocessing/preprocessing_pass.h"
#include "preprocessing/preprocessing_pass_context.h"
+#include "theory/bv/theory_bv_utils.h"
#include "util/statistics_registry.h"
namespace CVC4 {
@@ -39,24 +39,33 @@ class BoolToBV : public PreprocessingPass
private:
struct Statistics
{
+ IntStat d_numIteToBvite;
IntStat d_numTermsLowered;
- IntStat d_numAtomsLowered;
IntStat d_numTermsForcedLowered;
Statistics();
~Statistics();
};
- void lowerBoolToBv(const std::vector<Node>& assertions,
- std::vector<Node>& new_assertions);
- void addToLowerCache(TNode term, Node new_term);
- Node getLowerCache(TNode term) const;
- bool hasLowerCache(TNode term) const;
- Node lowerNode(TNode current, bool topLevel = false);
- NodeNodeMap d_lowerCache;
- Node d_one;
- Node d_zero;
+ /* Takes an assertion and tries to create more bit-vector structure */
+ Node lowerAssertion(const TNode& a);
+
+ /* Tries to lower one node to a width-one bit-vector */
+ void lowerNode(const TNode& n);
+
+ /* Returns cached node if it exists, otherwise returns the node */
+ Node fromCache(TNode n) const;
+
+ /** Checks if any of the nodes children were rebuilt,
+ * in which case n needs to be rebuilt as well
+ */
+ bool needToRebuild(TNode n) const;
+
Statistics d_statistics;
-}; // class
+
+ /* Keeps track of lowered nodes */
+ std::unordered_map<Node, Node, NodeHashFunction> d_lowerCache;
+}; // class BoolToBV
+
} // namespace passes
} // namespace preprocessing
} // namespace CVC4
diff --git a/src/proof/arith_proof.cpp b/src/proof/arith_proof.cpp
index 3b57be1f2..1d51f99e1 100644
--- a/src/proof/arith_proof.cpp
+++ b/src/proof/arith_proof.cpp
@@ -640,8 +640,10 @@ Node ProofArith::toStreamRecLFSC(std::ostream& out,
}
ArithProof::ArithProof(theory::arith::TheoryArith* arith, TheoryProofEngine* pe)
- : TheoryProof(arith, pe), d_realMode(false)
-{}
+ : TheoryProof(arith, pe), d_recorder(), d_realMode(false)
+{
+ arith->setProofRecorder(&d_recorder);
+}
theory::TheoryId ArithProof::getTheoryId() { return theory::THEORY_ARITH; }
void ArithProof::registerTerm(Expr term) {
diff --git a/src/proof/arith_proof.h b/src/proof/arith_proof.h
index 27012184a..a58294998 100644
--- a/src/proof/arith_proof.h
+++ b/src/proof/arith_proof.h
@@ -23,6 +23,7 @@
#include <unordered_set>
#include "expr/expr.h"
+#include "proof/arith_proof_recorder.h"
#include "proof/proof_manager.h"
#include "proof/theory_proof.h"
#include "theory/uf/equality_engine.h"
@@ -62,6 +63,11 @@ protected:
// TypeSet d_sorts; // all the uninterpreted sorts in this theory
ExprSet d_declarations; // all the variable/function declarations
+ /**
+ * @brief Where farkas proofs of lemmas are stored.
+ */
+ proof::ArithProofRecorder d_recorder;
+
bool d_realMode;
theory::TheoryId getTheoryId() override;
diff --git a/src/proof/arith_proof_recorder.cpp b/src/proof/arith_proof_recorder.cpp
new file mode 100644
index 000000000..d654ea073
--- /dev/null
+++ b/src/proof/arith_proof_recorder.cpp
@@ -0,0 +1,81 @@
+/********************* */
+/*! \file arith_proof_recorder.cpp
+ ** \verbatim
+ ** Top contributors (to current version):
+ ** Alex Ozdemir
+ ** This file is part of the CVC4 project.
+ ** Copyright (c) 2009-2018 by the authors listed in the file AUTHORS
+ ** in the top-level source directory) and their institutional affiliations.
+ ** All rights reserved. See the file COPYING in the top-level source
+ ** directory for licensing information.\endverbatim
+ **
+ ** \brief A class for recording the skeletons of arithmetic proofs at solve
+ ** time so they can later be used during proof-production time.
+ **/
+
+#include "proof/arith_proof_recorder.h"
+
+#include <algorithm>
+#include <vector>
+
+#include "base/map_util.h"
+
+namespace CVC4 {
+namespace proof {
+
+ArithProofRecorder::ArithProofRecorder() : d_lemmasToFarkasCoefficients()
+{
+ // Nothing else
+}
+void ArithProofRecorder::saveFarkasCoefficients(
+ Node conflict, theory::arith::RationalVectorCP farkasCoefficients)
+{
+ Assert(conflict.getKind() == kind::AND);
+ Assert(conflict.getNumChildren() == farkasCoefficients->size());
+ for (size_t i = 0; i < conflict.getNumChildren(); ++i)
+ {
+ const Node& child = conflict[i];
+ Assert(child.getType().isBoolean() && child[0].getType().isReal());
+ }
+ Debug("pf::arith") << "Saved Farkas Coefficients:" << std::endl;
+ if (Debug.isOn("pf::arith"))
+ {
+ for (size_t i = 0; i < conflict.getNumChildren(); ++i)
+ {
+ const Node& child = conflict[i];
+ const Rational& r = (*farkasCoefficients)[i];
+ Debug("pf::arith") << " " << std::setw(8) << r;
+ Debug("pf::arith") << " " << child << std::endl;
+ }
+ }
+
+ std::set<Node> lits;
+ std::copy(
+ conflict.begin(), conflict.end(), std::inserter(lits, lits.begin()));
+
+ d_lemmasToFarkasCoefficients[lits] =
+ std::make_pair(std::move(conflict), *farkasCoefficients);
+}
+
+bool ArithProofRecorder::hasFarkasCoefficients(
+ const std::set<Node>& conflict) const
+{
+ return d_lemmasToFarkasCoefficients.find(conflict)
+ != d_lemmasToFarkasCoefficients.end();
+}
+
+std::pair<Node, theory::arith::RationalVectorCP>
+ArithProofRecorder::getFarkasCoefficients(const std::set<Node>& conflict) const
+{
+ if (auto *p = FindOrNull(d_lemmasToFarkasCoefficients, conflict))
+ {
+ return std::make_pair(p->first, &p->second);
+ }
+ else
+ {
+ return std::make_pair(Node(), theory::arith::RationalVectorCPSentinel);
+ }
+}
+
+} // namespace proof
+} // namespace CVC4
diff --git a/src/proof/arith_proof_recorder.h b/src/proof/arith_proof_recorder.h
new file mode 100644
index 000000000..2d0501332
--- /dev/null
+++ b/src/proof/arith_proof_recorder.h
@@ -0,0 +1,107 @@
+/********************* */
+/*! \file arith_proof_recorder.h
+ ** \verbatim
+ ** Top contributors (to current version):
+ ** Alex Ozdemir
+ ** This file is part of the CVC4 project.
+ ** Copyright (c) 2009-2018 by the authors listed in the file AUTHORS
+ ** in the top-level source directory) and their institutional affiliations.
+ ** All rights reserved. See the file COPYING in the top-level source
+ ** directory for licensing information.\endverbatim
+ **
+ ** \brief A class for recording the skeletons of arithmetic proofs at solve
+ ** time so they can later be used during proof-production time.
+ **
+ ** In particular, we're interested in proving bottom from a conjunction of
+ ** theory literals.
+ **
+ ** For now, we assume that this can be done using a Farkas combination, and if
+ ** that doesn't work for some reason, then we give up and "trust" the lemma.
+ ** In the future we'll build support for more sophisticated reasoning.
+ **
+ ** Given this scope, our task is to...
+ ** for each lemma (a set of literals)
+ ** save the Farkas coefficients for those literals
+ ** which requires we save an ordering of the literals
+ ** and a parallel ordering of Farkas coefficients.
+ **
+ ** Farkas proofs have the following core structure:
+ ** For a list of affine bounds: c[i] dot x >= b[i]
+ ** (x is a vector of variables)
+ ** (c[i] is a vector of coefficients)
+ ** and a list of non-negative coefficients: f[i],
+ ** compute
+ **
+ ** sum_i{ (c[i] dot x) * f[i] } and sum_i{b[i]*f[i]}
+ **
+ ** and then verify that the left is actually < the right, a contradiction
+ **
+ ** To be clear: this code does not check Farkas proofs, it just stores the
+ ** information needed to write them.
+ **/
+
+#include "cvc4_private.h"
+
+#ifndef __CVC4__PROOF__ARITH_PROOF_RECORDER_H
+#define __CVC4__PROOF__ARITH_PROOF_RECORDER_H
+
+#include <map>
+#include <set>
+
+#include "expr/node.h"
+#include "theory/arith/constraint_forward.h"
+
+namespace CVC4 {
+namespace proof {
+
+class ArithProofRecorder
+{
+ public:
+ ArithProofRecorder();
+
+ /**
+ * @brief For a set of incompatible literals, save the Farkas coefficients
+ * demonstrating their incompatibility
+ *
+ * @param conflict a conjunction of conflicting literals
+ * @param farkasCoefficients a list of rational coefficients which the literals
+ * should be multiplied by (pairwise) to produce a contradiction.
+ *
+ * The orders of the two vectors must agree!
+ */
+ void saveFarkasCoefficients(
+ Node conflict, theory::arith::RationalVectorCP farkasCoefficients);
+
+ /**
+ * @brief Determine whether some literals have a Farkas proof of their
+ * incompatibility
+ *
+ * @param conflict a conjunction of (putatively) conflicting literals
+ *
+ * @return whether or not there is actually a proof for them.
+ */
+ bool hasFarkasCoefficients(const std::set<Node>& conflict) const;
+
+ /**
+ * @brief Get the Farkas Coefficients object
+ *
+ * @param conflict a conjunction of conflicting literals
+ * @return theory::arith::RationalVectorCP -- the Farkas coefficients
+ * Node -- a conjunction of the problem literals in coefficient order
+ *
+ * theory::arith::RationalVectorCPSentinel if there is no entry for
+ * these lits
+ */
+ std::pair<Node, theory::arith::RationalVectorCP> getFarkasCoefficients(
+ const std::set<Node>& conflict) const;
+
+ protected:
+ // For each lemma, save the Farkas coefficients of that lemma
+ std::map<std::set<Node>, std::pair<Node, theory::arith::RationalVector>>
+ d_lemmasToFarkasCoefficients;
+};
+
+} // namespace proof
+} // namespace CVC4
+
+#endif
diff --git a/src/proof/bitvector_proof.cpp b/src/proof/bitvector_proof.cpp
index c9e98d170..ba3533cc3 100644
--- a/src/proof/bitvector_proof.cpp
+++ b/src/proof/bitvector_proof.cpp
@@ -68,7 +68,7 @@ void BitVectorProof::registerAtomBB(Expr atom, Expr atom_bb) {
Debug("pf::bv") << "BitVectorProof::registerAtomBB( " << atom
<< ", " << atom_bb << " )" << std::endl;
- Expr def = atom.iffExpr(atom_bb);
+ Expr def = atom.eqExpr(atom_bb);
d_bbAtoms.insert(std::make_pair(atom, def));
registerTerm(atom);
@@ -81,7 +81,9 @@ void BitVectorProof::registerTerm(Expr term) {
Debug("pf::bv") << "BitVectorProof::registerTerm( " << term << " )"
<< std::endl;
- if (options::lfscLetification() && term.isConst()) {
+ if (options::lfscLetification() && term.isConst()
+ && term.getType().isBitVector())
+ {
if (d_constantLetMap.find(term) == d_constantLetMap.end()) {
std::ostringstream name;
name << "letBvc" << d_constantLetMap.size();
@@ -624,8 +626,6 @@ void BitVectorProof::printBitblasting(std::ostream& os, std::ostream& paren)
std::vector<Expr>::const_iterator it = d_bbTerms.begin();
std::vector<Expr>::const_iterator end = d_bbTerms.end();
- Assert(options::bitblastMode() != theory::bv::BITBLAST_MODE_EAGER);
-
for (; it != end; ++it) {
if (d_usedBB.find(*it) == d_usedBB.end()) {
Debug("pf::bv") << "\t" << *it << "\t(UNUSED)" << std::endl;
diff --git a/src/proof/proof_manager.cpp b/src/proof/proof_manager.cpp
index 5b26432dd..9878972bf 100644
--- a/src/proof/proof_manager.cpp
+++ b/src/proof/proof_manager.cpp
@@ -559,8 +559,6 @@ void LFSCProof::toStream(std::ostream& out, const ProofLetMap& map) const
void LFSCProof::toStream(std::ostream& out) const
{
- Assert(options::bitblastMode() != theory::bv::BITBLAST_MODE_EAGER);
-
Assert(!d_satProof->proofConstructed());
d_satProof->constructProof();
@@ -730,6 +728,7 @@ void LFSCProof::toStream(std::ostream& out) const
d_theoryProof->printTheoryLemmas(used_lemmas, out, paren, globalLetMap);
Debug("pf::pm") << "Proof manager: printing theory lemmas DONE!" << std::endl;
+ out << ";; Printing final unsat proof \n";
if (options::bitblastMode() == theory::bv::BITBLAST_MODE_EAGER && ProofManager::getBitVectorProof()) {
proof::LFSCProofPrinter::printResolutionEmptyClause(
ProofManager::getBitVectorProof()->getSatProof(), out, paren);
diff --git a/src/proof/resolution_bitvector_proof.h b/src/proof/resolution_bitvector_proof.h
index a54d72d3f..ccb288f6e 100644
--- a/src/proof/resolution_bitvector_proof.h
+++ b/src/proof/resolution_bitvector_proof.h
@@ -98,6 +98,8 @@ class ResolutionBitVectorProof : public BitVectorProof
void initCnfProof(prop::CnfStream* cnfStream, context::Context* cnf) override;
protected:
+ context::Context d_fakeContext;
+
// The CNF formula that results from bit-blasting will need a proof.
// This is that proof.
std::unique_ptr<BVSatProof> d_resolutionProof;
@@ -105,7 +107,6 @@ class ResolutionBitVectorProof : public BitVectorProof
bool d_isAssumptionConflict;
theory::TheoryId getTheoryId() override;
- context::Context d_fakeContext;
};
class LFSCBitVectorProof : public ResolutionBitVectorProof
diff --git a/src/smt/smt_engine.cpp b/src/smt/smt_engine.cpp
index a0939f4db..ae20fa156 100644
--- a/src/smt/smt_engine.cpp
+++ b/src/smt/smt_engine.cpp
@@ -1071,6 +1071,18 @@ SmtEngine::~SmtEngine()
//destroy all passes before destroying things that they refer to
d_private->cleanupPreprocessingPasses();
+ // d_proofManager is always created when proofs are enabled at configure
+ // time. Because of this, this code should not be wrapped in PROOF() which
+ // additionally checks flags such as options::proof().
+ //
+ // Note: the proof manager must be destroyed before the theory engine.
+ // Because the destruction of the proofs depends on contexts owned be the
+ // theory solvers.
+#ifdef CVC4_PROOF
+ delete d_proofManager;
+ d_proofManager = NULL;
+#endif
+
delete d_theoryEngine;
d_theoryEngine = NULL;
delete d_propEngine;
@@ -1078,15 +1090,6 @@ SmtEngine::~SmtEngine()
delete d_decisionEngine;
d_decisionEngine = NULL;
-
-// d_proofManager is always created when proofs are enabled at configure time.
-// Becuase of this, this code should not be wrapped in PROOF() which
-// additionally checks flags such as options::proof().
-#ifdef CVC4_PROOF
- delete d_proofManager;
- d_proofManager = NULL;
-#endif
-
delete d_stats;
d_stats = NULL;
delete d_statisticsRegistry;
@@ -1376,17 +1379,17 @@ void SmtEngine::setDefaults() {
options::bitvectorToBool.set(false);
}
- if (options::boolToBitvector())
+ if (options::boolToBitvector() != preprocessing::passes::BOOL_TO_BV_OFF)
{
if (options::boolToBitvector.wasSetByUser())
{
throw OptionException(
- "bool-to-bv not supported with unsat cores/proofs");
+ "bool-to-bv != off not supported with unsat cores/proofs");
}
- Notice() << "SmtEngine: turning off bool-to-bitvector to support unsat "
+ Notice() << "SmtEngine: turning off bool-to-bv to support unsat "
"cores/proofs"
<< endl;
- options::boolToBitvector.set(false);
+ setOption("boolToBitvector", SExpr("off"));
}
if (options::bvIntroducePow2())
@@ -1446,13 +1449,18 @@ void SmtEngine::setDefaults() {
if (options::cbqiBv() && d_logic.isQuantified())
{
- if(options::boolToBitvector.wasSetByUser()) {
- throw OptionException(
- "bool-to-bv not supported with CBQI BV for quantified logics");
+ if (options::boolToBitvector() != preprocessing::passes::BOOL_TO_BV_OFF)
+ {
+ if (options::boolToBitvector.wasSetByUser())
+ {
+ throw OptionException(
+ "bool-to-bv != off not supported with CBQI BV for quantified "
+ "logics");
+ }
+ Notice() << "SmtEngine: turning off bool-to-bitvector to support CBQI BV"
+ << endl;
+ setOption("boolToBitvector", SExpr("off"));
}
- Notice() << "SmtEngine: turning off bool-to-bitvector to support CBQI BV"
- << endl;
- options::boolToBitvector.set(false);
}
// cases where we need produce models
@@ -1614,6 +1622,19 @@ void SmtEngine::setDefaults() {
}
}
+ if (options::boolToBitvector() == preprocessing::passes::BOOL_TO_BV_ALL
+ && !d_logic.isTheoryEnabled(THEORY_BV))
+ {
+ if (options::boolToBitvector.wasSetByUser())
+ {
+ throw OptionException(
+ "bool-to-bv=all not supported for non-bitvector logics.");
+ }
+ Notice() << "SmtEngine: turning off bool-to-bv for non-bv logic: "
+ << d_logic.getLogicString() << std::endl;
+ setOption("boolToBitvector", SExpr("off"));
+ }
+
if (! options::bvEagerExplanations.wasSetByUser() &&
d_logic.isTheoryEnabled(THEORY_ARRAYS) &&
d_logic.isTheoryEnabled(THEORY_BV)) {
@@ -1788,12 +1809,6 @@ void SmtEngine::setDefaults() {
options::mbqiMode.set( quantifiers::MBQI_NONE );
}
}
- if( options::mbqiMode()==quantifiers::MBQI_ABS ){
- if( !d_logic.isPure(THEORY_UF) ){
- //MBQI_ABS is only supported in pure quantified UF
- options::mbqiMode.set( quantifiers::MBQI_FMC );
- }
- }
if( options::fmfFunWellDefinedRelevant() ){
if( !options::fmfFunWellDefined.wasSetByUser() ){
options::fmfFunWellDefined.set( true );
@@ -1831,17 +1846,6 @@ void SmtEngine::setDefaults() {
options::instWhenMode.set( quantifiers::INST_WHEN_LAST_CALL );
}
}
- if( options::mbqiMode()==quantifiers::MBQI_ABS ){
- if( !options::preSkolemQuant.wasSetByUser() ){
- options::preSkolemQuant.set( true );
- }
- if( !options::preSkolemQuantNested.wasSetByUser() ){
- options::preSkolemQuantNested.set( true );
- }
- if( !options::fmfOneInstPerRound.wasSetByUser() ){
- options::fmfOneInstPerRound.set( true );
- }
- }
}
//apply counterexample guided instantiation options
diff --git a/src/theory/arith/constraint.cpp b/src/theory/arith/constraint.cpp
index ff71f6432..352ba0f36 100644
--- a/src/theory/arith/constraint.cpp
+++ b/src/theory/arith/constraint.cpp
@@ -602,7 +602,7 @@ void ConstraintRule::print(std::ostream& out) const {
bool Constraint::wellFormedFarkasProof() const {
Assert(hasProof());
-
+
const ConstraintRule& cr = getConstraintRule();
if(cr.d_constraint != this){ return false; }
if(cr.d_proofType != FarkasAP){ return false; }
@@ -1071,6 +1071,7 @@ ConstraintP ConstraintDatabase::lookup(TNode literal) const{
}
void Constraint::setAssumption(bool nowInConflict){
+ Debug("constraints::pf") << "setAssumption(" << this << ")" << std::endl;
Assert(!hasProof());
Assert(negationHasProof() == nowInConflict);
Assert(hasLiteral());
@@ -1113,6 +1114,7 @@ void Constraint::propagate(){
* 1*(x <= a) + (-1)*(x > b) => (0 <= a-b)
*/
void Constraint::impliedByUnate(ConstraintCP imp, bool nowInConflict){
+ Debug("constraints::pf") << "impliedByUnate(" << this << ", " << *imp << ")" << std::endl;
Assert(!hasProof());
Assert(imp->hasProof());
Assert(negationHasProof() == nowInConflict);
@@ -1152,6 +1154,8 @@ void Constraint::impliedByUnate(ConstraintCP imp, bool nowInConflict){
}
void Constraint::impliedByTrichotomy(ConstraintCP a, ConstraintCP b, bool nowInConflict){
+ Debug("constraints::pf") << "impliedByTrichotomy(" << this << ", " << *a << ", ";
+ Debug("constraints::pf") << *b << ")" << std::endl;
Assert(!hasProof());
Assert(negationHasProof() == nowInConflict);
Assert(a->hasProof());
@@ -1180,6 +1184,7 @@ bool Constraint::allHaveProof(const ConstraintCPVec& b){
}
void Constraint::impliedByIntHole(ConstraintCP a, bool nowInConflict){
+ Debug("constraints::pf") << "impliedByIntHole(" << this << ", " << *a << ")" << std::endl;
Assert(!hasProof());
Assert(negationHasProof() == nowInConflict);
Assert(a->hasProof());
@@ -1196,6 +1201,15 @@ void Constraint::impliedByIntHole(ConstraintCP a, bool nowInConflict){
}
void Constraint::impliedByIntHole(const ConstraintCPVec& b, bool nowInConflict){
+ Debug("constraints::pf") << "impliedByIntHole(" << this;
+ if (Debug.isOn("constraints::pf")) {
+ for (const ConstraintCP& p : b)
+ {
+ Debug("constraints::pf") << ", " << p;
+ }
+ }
+ Debug("constraints::pf") << ")" << std::endl;
+
Assert(!hasProof());
Assert(negationHasProof() == nowInConflict);
Assert(allHaveProof(b));
@@ -1224,6 +1238,15 @@ void Constraint::impliedByIntHole(const ConstraintCPVec& b, bool nowInConflict){
* coeff.back() corresponds to the current constraint.
*/
void Constraint::impliedByFarkas(const ConstraintCPVec& a, RationalVectorCP coeffs, bool nowInConflict){
+ Debug("constraints::pf") << "impliedByFarkas(" << this;
+ if (Debug.isOn("constraints::pf")) {
+ for (const ConstraintCP& p : a)
+ {
+ Debug("constraints::pf") << ", " << p;
+ }
+ }
+ Debug("constraints::pf") << ", <coeffs>";
+ Debug("constraints::pf") << ")" << std::endl;
Assert(!hasProof());
Assert(negationHasProof() == nowInConflict);
Assert(allHaveProof(a));
@@ -1263,6 +1286,8 @@ void Constraint::impliedByFarkas(const ConstraintCPVec& a, RationalVectorCP coef
void Constraint::setInternalAssumption(bool nowInConflict){
+ Debug("constraints::pf") << "setInternalAssumption(" << this;
+ Debug("constraints::pf") << ")" << std::endl;
Assert(!hasProof());
Assert(negationHasProof() == nowInConflict);
Assert(!assertedToTheTheory());
@@ -1277,6 +1302,8 @@ void Constraint::setInternalAssumption(bool nowInConflict){
void Constraint::setEqualityEngineProof(){
+ Debug("constraints::pf") << "setEqualityEngineProof(" << this;
+ Debug("constraints::pf") << ")" << std::endl;
Assert(truthIsUnknown());
Assert(hasLiteral());
d_database->pushConstraintRule(ConstraintRule(this, EqualityEngineAP));
diff --git a/src/theory/arith/constraint.h b/src/theory/arith/constraint.h
index 5eef9663e..d411f2d34 100644
--- a/src/theory/arith/constraint.h
+++ b/src/theory/arith/constraint.h
@@ -928,7 +928,11 @@ private:
/** Return true if every element in b has a proof. */
static bool allHaveProof(const ConstraintCPVec& b);
- /** Precondition: hasFarkasProof() */
+ /** Precondition: hasFarkasProof()
+ * Computes the combination implied by the farkas coefficients. Sees if it is
+ * a contradiction.
+ */
+
bool wellFormedFarkasProof() const;
}; /* class ConstraintValue */
diff --git a/src/theory/arith/cut_log.h b/src/theory/arith/cut_log.h
index 6650e6680..5fd585588 100644
--- a/src/theory/arith/cut_log.h
+++ b/src/theory/arith/cut_log.h
@@ -216,7 +216,7 @@ public:
int getUpId() const;
/**
- * Looks up a row id to the appropraite arith variable.
+ * Looks up a row id to the appropriate arith variable.
* Be careful these are deleted in context during replay!
* failure returns ARITHVAR_SENTINEL */
ArithVar lookupRowId(int rowId) const;
diff --git a/src/theory/arith/theory_arith.cpp b/src/theory/arith/theory_arith.cpp
index d7113b17d..9902121d0 100644
--- a/src/theory/arith/theory_arith.cpp
+++ b/src/theory/arith/theory_arith.cpp
@@ -36,6 +36,7 @@ TheoryArith::TheoryArith(context::Context* c, context::UserContext* u,
: Theory(THEORY_ARITH, c, u, out, valuation, logicInfo)
, d_internal(new TheoryArithPrivate(*this, c, u, out, valuation, logicInfo))
, d_ppRewriteTimer("theory::arith::ppRewriteTimer")
+ , d_proofRecorder(nullptr)
{
smtStatisticsRegistry()->registerStat(&d_ppRewriteTimer);
if (options::nlExt()) {
diff --git a/src/theory/arith/theory_arith.h b/src/theory/arith/theory_arith.h
index 195cb1883..e4b1c5b26 100644
--- a/src/theory/arith/theory_arith.h
+++ b/src/theory/arith/theory_arith.h
@@ -19,6 +19,7 @@
#include "theory/theory.h"
#include "expr/node.h"
+#include "proof/arith_proof_recorder.h"
#include "theory/arith/theory_arith_private_forward.h"
@@ -40,6 +41,11 @@ private:
TimerStat d_ppRewriteTimer;
+ /**
+ * @brief Where to store Farkas proofs of lemmas
+ */
+ proof::ArithProofRecorder * d_proofRecorder;
+
public:
TheoryArith(context::Context* c, context::UserContext* u, OutputChannel& out,
Valuation valuation, const LogicInfo& logicInfo);
@@ -90,6 +96,11 @@ public:
const EntailmentCheckParameters* params,
EntailmentCheckSideEffects* out) override;
+ void setProofRecorder(proof::ArithProofRecorder * proofRecorder)
+ {
+ d_proofRecorder = proofRecorder;
+ }
+
};/* class TheoryArith */
}/* CVC4::theory::arith namespace */
diff --git a/src/theory/bv/bitblast/eager_bitblaster.cpp b/src/theory/bv/bitblast/eager_bitblaster.cpp
index 33d5a1c80..019918c2f 100644
--- a/src/theory/bv/bitblast/eager_bitblaster.cpp
+++ b/src/theory/bv/bitblast/eager_bitblaster.cpp
@@ -99,8 +99,8 @@ void EagerBitblaster::bbFormula(TNode node)
void EagerBitblaster::bbAtom(TNode node)
{
node = node.getKind() == kind::NOT ? node[0] : node;
- if (node.getKind() == kind::BITVECTOR_BITOF) return;
- if (hasBBAtom(node))
+ if (node.getKind() == kind::BITVECTOR_BITOF
+ || node.getKind() == kind::CONST_BOOLEAN || hasBBAtom(node))
{
return;
}
diff --git a/src/theory/bv/theory_bv.cpp b/src/theory/bv/theory_bv.cpp
index e60d60456..949a3d738 100644
--- a/src/theory/bv/theory_bv.cpp
+++ b/src/theory/bv/theory_bv.cpp
@@ -740,7 +740,7 @@ Node TheoryBV::ppRewrite(TNode t)
{
Debug("bv-pp-rewrite") << "TheoryBV::ppRewrite " << t << "\n";
Node res = t;
- if (RewriteRule<BitwiseEq>::applies(t)) {
+ if (options::bitwiseEq() && RewriteRule<BitwiseEq>::applies(t)) {
Node result = RewriteRule<BitwiseEq>::run<false>(t);
res = Rewriter::rewrite(result);
} else if (d_isCoreTheory && t.getKind() == kind::EQUAL) {
diff --git a/src/theory/bv/theory_bv_rewrite_rules_simplification.h b/src/theory/bv/theory_bv_rewrite_rules_simplification.h
index 7efdc2c81..c58d69f6f 100644
--- a/src/theory/bv/theory_bv_rewrite_rules_simplification.h
+++ b/src/theory/bv/theory_bv_rewrite_rules_simplification.h
@@ -535,7 +535,7 @@ inline Node RewriteRule<AndOrXorConcatPullUp>::apply(TNode node)
{
Debug("bv-rewrite") << "RewriteRule<AndOrXorConcatPullUp>(" << node << ")"
<< std::endl;
- uint32_t m, my, mz, n;
+ uint32_t m, my, mz;
size_t nc;
Kind kind = node.getKind();
TNode concat;
@@ -589,7 +589,9 @@ inline Node RewriteRule<AndOrXorConcatPullUp>::apply(TNode node)
z = nc > 1 ? zb.constructNode() : zb[0];
}
m = utils::getSize(x);
- n = utils::getSize(c);
+#ifdef CVC4_ASSERTIONS
+ uint32_t n = utils::getSize(c);
+#endif
my = y.isNull() ? 0 : utils::getSize(y);
mz = z.isNull() ? 0 : utils::getSize(z);
Assert(mz == m - my - n);
diff --git a/src/theory/quantifiers/extended_rewrite.cpp b/src/theory/quantifiers/extended_rewrite.cpp
index b583a55da..46dcb7151 100644
--- a/src/theory/quantifiers/extended_rewrite.cpp
+++ b/src/theory/quantifiers/extended_rewrite.cpp
@@ -119,7 +119,8 @@ Node ExtendedRewriter::extendedRewrite(Node n)
Kind k = n.getKind();
bool childChanged = false;
bool isNonAdditive = TermUtil::isNonAdditive(k);
- bool isAssoc = TermUtil::isAssoc(k);
+ // We flatten associative operators below, which requires k to be n-ary.
+ bool isAssoc = TermUtil::isAssoc(k, true);
for (unsigned i = 0; i < n.getNumChildren(); i++)
{
Node nc = extendedRewrite(n[i]);
@@ -1676,10 +1677,6 @@ Node ExtendedRewriter::extendedRewriteStrings(Node ret)
{
new_ret = strings::TheoryStringsRewriter::rewriteEqualityExt(ret);
}
- else if (ret.getKind() == STRING_SUBSTR)
- {
- new_ret = strings::TheoryStringsRewriter::rewriteSubstrExt(ret);
- }
return new_ret;
}
diff --git a/src/theory/quantifiers/first_order_model.cpp b/src/theory/quantifiers/first_order_model.cpp
index 0eec40de2..5eb65ed21 100644
--- a/src/theory/quantifiers/first_order_model.cpp
+++ b/src/theory/quantifiers/first_order_model.cpp
@@ -15,7 +15,6 @@
#include "theory/quantifiers/first_order_model.h"
#include "options/base_options.h"
#include "options/quantifiers_options.h"
-#include "theory/quantifiers/fmf/ambqi_builder.h"
#include "theory/quantifiers/fmf/bounded_integers.h"
#include "theory/quantifiers/fmf/full_model_check.h"
#include "theory/quantifiers/fmf/model_engine.h"
@@ -414,473 +413,6 @@ unsigned FirstOrderModel::getModelBasisArg(Node n)
return n.getAttribute(ModelBasisArgAttribute());
}
-Node FirstOrderModelIG::UfModelTreeGenerator::getIntersection(TheoryModel* m,
- Node n1,
- Node n2,
- bool& isGround)
-{
- isGround = true;
- std::vector<Node> children;
- children.push_back(n1.getOperator());
- for (unsigned i = 0, size = n1.getNumChildren(); i < size; i++)
- {
- if (n1[i] == n2[i])
- {
- if (n1[i].getAttribute(ModelBasisAttribute()))
- {
- isGround = false;
- }
- children.push_back(n1[i]);
- }
- else if (n1[i].getAttribute(ModelBasisAttribute()))
- {
- children.push_back(n2[i]);
- }
- else if (n2[i].getAttribute(ModelBasisAttribute()))
- {
- children.push_back(n1[i]);
- }
- else if (m->areEqual(n1[i], n2[i]))
- {
- children.push_back(n1[i]);
- }
- else
- {
- return Node::null();
- }
- }
- return NodeManager::currentNM()->mkNode(APPLY_UF, children);
-}
-
-void FirstOrderModelIG::UfModelTreeGenerator::setValue(
- TheoryModel* m, Node n, Node v, bool ground, bool isReq)
-{
- Assert(!n.isNull());
- Assert(!v.isNull());
- d_set_values[isReq ? 1 : 0][ground ? 1 : 0][n] = v;
- if (!ground)
- {
- for (unsigned i = 0, defSize = d_defaults.size(); i < defSize; i++)
- {
- // for correctness, 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);
- }
- }
- }
- d_defaults.push_back(n);
- }
- if (isReq
- && d_set_values[0][ground ? 1 : 0].find(n)
- != d_set_values[0][ground ? 1 : 0].end())
- {
- d_set_values[0][ground ? 1 : 0].erase(n);
- }
-}
-
-void FirstOrderModelIG::UfModelTreeGenerator::makeModel(TheoryModel* m,
- uf::UfModelTree& tree)
-{
- for (int j = 0; j < 2; j++)
- {
- for (int k = 0; k < 2; k++)
- {
- for (std::map<Node, Node>::iterator it = d_set_values[j][k].begin();
- it != d_set_values[j][k].end();
- ++it)
- {
- tree.setValue(m, it->first, it->second, k == 1);
- }
- }
- }
- if (!d_default_value.isNull())
- {
- tree.setDefaultValue(m, d_default_value);
- }
- tree.simplify();
-}
-
-void FirstOrderModelIG::UfModelTreeGenerator::clear()
-{
- d_default_value = Node::null();
- for (int j = 0; j < 2; j++)
- {
- for (int k = 0; k < 2; k++)
- {
- d_set_values[j][k].clear();
- }
- }
- d_defaults.clear();
-}
-
-FirstOrderModelIG::FirstOrderModelIG(QuantifiersEngine * qe, context::Context* c, std::string name) :
-FirstOrderModel(qe, c,name) {
-
-}
-
-void FirstOrderModelIG::processInitialize( bool ispre ){
- if( ispre ){
- //rebuild models
- d_uf_model_tree.clear();
- d_uf_model_gen.clear();
- }
-}
-
-void FirstOrderModelIG::processInitializeModelForTerm( Node n ){
- if( n.getKind()==APPLY_UF ){
- Node op = n.getOperator();
- if( d_uf_model_tree.find( op )==d_uf_model_tree.end() ){
- TypeNode tn = op.getType();
- tn = tn[ (int)tn.getNumChildren()-1 ];
- //only generate models for predicates and functions with uninterpreted range types
- //if( tn==NodeManager::currentNM()->booleanType() || tn.isSort() ){
- d_uf_model_tree[ op ] = uf::UfModelTree( op );
- d_uf_model_gen[ op ].clear();
- //}
- }
- }
- /*
- if( n.getType().isArray() ){
- while( n.getKind()==STORE ){
- n = n[0];
- }
- Node nn = getRepresentative( n );
- if( d_array_model.find( nn )==d_array_model.end() ){
- d_array_model[nn] = arrays::ArrayModel( nn, this );
- }
- }
- */
-}
-
-//for evaluation of quantifier bodies
-
-void FirstOrderModelIG::resetEvaluate(){
- d_eval_uf_use_default.clear();
- d_eval_uf_model.clear();
- d_eval_term_index_order.clear();
-}
-
-//if evaluate( n ) = eVal,
-// let n' = ri * n be the formula n instantiated with the current values in r_iter
-// if eVal = 1, then n' is true, if eVal = -1, then n' is false,
-// if eVal = 0, then n' cannot be proven to be equal to phaseReq
-// if eVal is not 0, then
-// each n{ri->d_index[0]/x_0...ri->d_index[depIndex]/x_depIndex, */x_(depIndex+1) ... */x_n } is equivalent in the current model
-int FirstOrderModelIG::evaluate( Node n, int& depIndex, RepSetIterator* ri ){
- Debug("fmf-eval-debug2") << "Evaluate " << n << std::endl;
- //Notice() << "Eval " << n << std::endl;
- if( n.getKind()==NOT ){
- int val = evaluate( n[0], depIndex, ri );
- return val==1 ? -1 : ( val==-1 ? 1 : 0 );
- }else if( n.getKind()==OR || n.getKind()==AND ){
- int baseVal = n.getKind()==AND ? 1 : -1;
- int eVal = baseVal;
- int posDepIndex = ri->getNumTerms();
- int negDepIndex = -1;
- for( int i=0; i<(int)n.getNumChildren(); i++ ){
- //evaluate subterm
- int childDepIndex;
- Node nn = n[i];
- int eValT = evaluate( nn, childDepIndex, ri );
- if( eValT==baseVal ){
- if( eVal==baseVal ){
- if( childDepIndex>negDepIndex ){
- negDepIndex = childDepIndex;
- }
- }
- }else if( eValT==-baseVal ){
- eVal = -baseVal;
- if( childDepIndex<posDepIndex ){
- posDepIndex = childDepIndex;
- if( posDepIndex==-1 ){
- break;
- }
- }
- }else if( eValT==0 ){
- if( eVal==baseVal ){
- eVal = 0;
- }
- }
- }
- if( eVal!=0 ){
- depIndex = eVal==-baseVal ? posDepIndex : negDepIndex;
- return eVal;
- }else{
- return 0;
- }
- }else if( n.getKind()==EQUAL && n[0].getType().isBoolean() ){
- int depIndex1;
- int eVal = evaluate( n[0], depIndex1, ri );
- if( eVal!=0 ){
- int depIndex2;
- int eVal2 = evaluate( n[1], depIndex2, ri );
- if( eVal2!=0 ){
- depIndex = depIndex1>depIndex2 ? depIndex1 : depIndex2;
- return eVal==eVal2 ? 1 : -1;
- }
- }
- return 0;
- }else if( n.getKind()==ITE ){
- int depIndex1, depIndex2;
- int eVal = evaluate( n[0], depIndex1, ri );
- if( eVal==0 ){
- //evaluate children to see if they are the same value
- int eval1 = evaluate( n[1], depIndex1, ri );
- if( eval1!=0 ){
- int eval2 = evaluate( n[1], depIndex2, ri );
- if( eval1==eval2 ){
- depIndex = depIndex1>depIndex2 ? depIndex1 : depIndex2;
- return eval1;
- }
- }
- }else{
- int eValT = evaluate( n[eVal==1 ? 1 : 2], depIndex2, ri );
- depIndex = depIndex1>depIndex2 ? depIndex1 : depIndex2;
- return eValT;
- }
- return 0;
- }else if( n.getKind()==FORALL ){
- return 0;
- }else{
- //Debug("fmf-eval-debug") << "Evaluate literal " << n << std::endl;
- int retVal = 0;
- depIndex = ri->getNumTerms()-1;
- Node val = evaluateTerm( n, depIndex, ri );
- if( !val.isNull() ){
- if( areEqual( val, d_true ) ){
- retVal = 1;
- }else if( areEqual( val, d_false ) ){
- retVal = -1;
- }else{
- if( val.getKind()==EQUAL ){
- if( areEqual( val[0], val[1] ) ){
- retVal = 1;
- }else if( areDisequal( val[0], val[1] ) ){
- retVal = -1;
- }
- }
- }
- }
- if( retVal!=0 ){
- Debug("fmf-eval-debug") << "Evaluate literal: return " << retVal << ", depIndex = " << depIndex << std::endl;
- }else{
- Trace("fmf-eval-amb") << "Neither true nor false : " << n << std::endl;
- Trace("fmf-eval-amb") << " value : " << val << std::endl;
- }
- return retVal;
- }
-}
-
-Node FirstOrderModelIG::evaluateTerm( Node n, int& depIndex, RepSetIterator* ri ){
- //Message() << "Eval term " << n << std::endl;
- Node val;
- depIndex = ri->getNumTerms()-1;
- //check the type of n
- if( n.getKind()==INST_CONSTANT ){
- int v = n.getAttribute(InstVarNumAttribute());
- depIndex = ri->getIndexOrder( v );
- val = ri->getCurrentTerm( v );
- }else if( n.getKind()==ITE ){
- int depIndex1, depIndex2;
- int eval = evaluate( n[0], depIndex1, ri );
- if( eval==0 ){
- //evaluate children to see if they are the same
- Node val1 = evaluateTerm( n[ 1 ], depIndex1, ri );
- Node val2 = evaluateTerm( n[ 2 ], depIndex2, ri );
- if( val1==val2 ){
- val = val1;
- depIndex = depIndex1>depIndex2 ? depIndex1 : depIndex2;
- }else{
- return Node::null();
- }
- }else{
- val = evaluateTerm( n[ eval==1 ? 1 : 2 ], depIndex2, ri );
- depIndex = depIndex1>depIndex2 ? depIndex1 : depIndex2;
- }
- }else{
- std::vector< int > children_depIndex;
- //default term evaluate : evaluate all children, recreate the value
- val = evaluateTermDefault( n, depIndex, children_depIndex, ri );
- Trace("fmf-eval-debug") << "Evaluate term, value from " << n << " is " << val << std::endl;
- if( !val.isNull() ){
- bool setVal = false;
- //custom ways of evaluating terms
- if( n.getKind()==APPLY_UF ){
- Node op = n.getOperator();
- //Debug("fmf-eval-debug") << "Evaluate term " << n << " (" << gn << ")" << std::endl;
- //if it is a defined UF, then consult the interpretation
- if( d_uf_model_tree.find( op )!=d_uf_model_tree.end() ){
- int argDepIndex = 0;
- //make the term model specifically for n
- makeEvalUfModel( n );
- //now, consult the model
- if( d_eval_uf_use_default[n] ){
- Trace("fmf-eval-debug") << "get default" << std::endl;
- val = d_uf_model_tree[ op ].getValue( this, val, argDepIndex );
- }else{
- Trace("fmf-eval-debug") << "get uf model" << std::endl;
- val = d_eval_uf_model[ n ].getValue( this, val, argDepIndex );
- }
- //Debug("fmf-eval-debug") << "Evaluate term " << n << " (" << gn << ")" << std::endl;
- //d_eval_uf_model[ n ].debugPrint("fmf-eval-debug", d_qe );
- Assert( !val.isNull() );
- //recalculate the depIndex
- depIndex = -1;
- for( int i=0; i<argDepIndex; i++ ){
- int index = d_eval_uf_use_default[n] ? i : d_eval_term_index_order[n][i];
- Debug("fmf-eval-debug") << "Add variables from " << index << "..." << std::endl;
- if( children_depIndex[index]>depIndex ){
- depIndex = children_depIndex[index];
- }
- }
- setVal = true;
- }else{
- Trace("fmf-eval-debug") << "No model." << std::endl;
- }
- }
- //if not set already, rewrite and consult model for interpretation
- if( !setVal ){
- val = Rewriter::rewrite( val );
- if( !val.isConst() ){
- return Node::null();
- }
- }
- Trace("fmf-eval-debug") << "Evaluate term " << n << " = ";
- Trace("fmf-eval-debug") << getRepresentative(val);
- Trace("fmf-eval-debug") << " (term " << val << "), depIndex = " << depIndex << std::endl;
- }
- }
- return val;
-}
-
-Node FirstOrderModelIG::evaluateTermDefault( Node n, int& depIndex, std::vector< int >& childDepIndex, RepSetIterator* ri ){
- depIndex = -1;
- if( n.getNumChildren()==0 ){
- return n;
- }else{
- bool isInterp = n.getKind()!=APPLY_UF;
- //first we must evaluate the arguments
- std::vector< Node > children;
- if( n.getMetaKind()==kind::metakind::PARAMETERIZED ){
- children.push_back( n.getOperator() );
- }
- //for each argument, calculate its value, and the variables its value depends upon
- for( int i=0; i<(int)n.getNumChildren(); i++ ){
- childDepIndex.push_back( -1 );
- Node nn = evaluateTerm( n[i], childDepIndex[i], ri );
- if( nn.isNull() ){
- depIndex = ri->getNumTerms()-1;
- return nn;
- }else{
- if( childDepIndex[i]>depIndex ){
- depIndex = childDepIndex[i];
- }
- if( isInterp ){
- if( !nn.isConst() ) {
- nn = getRepresentative( nn );
- }
- }
- children.push_back( nn );
- }
- }
- //recreate the value
- Node val = NodeManager::currentNM()->mkNode( n.getKind(), children );
- return val;
- }
-}
-
-void FirstOrderModelIG::makeEvalUfModel( Node n ){
- if( d_eval_uf_model.find( n )==d_eval_uf_model.end() ){
- makeEvalUfIndexOrder( n );
- if( !d_eval_uf_use_default[n] ){
- Node op = n.getOperator();
- 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( std::cout, d_qe->getModel(), 2 );
- }
- }
-}
-
-struct sortGetMaxVariableNum {
- std::map< Node, int > d_max_var_num;
- int computeMaxVariableNum( Node n ){
- if( n.getKind()==INST_CONSTANT ){
- return n.getAttribute(InstVarNumAttribute());
- }else if( TermUtil::hasInstConstAttr(n) ){
- int maxVal = -1;
- for( int i=0; i<(int)n.getNumChildren(); i++ ){
- int val = getMaxVariableNum( n[i] );
- if( val>maxVal ){
- maxVal = val;
- }
- }
- return maxVal;
- }else{
- return -1;
- }
- }
- int getMaxVariableNum( Node n ){
- std::map< Node, int >::iterator it = d_max_var_num.find( n );
- if( it==d_max_var_num.end() ){
- int num = computeMaxVariableNum( n );
- d_max_var_num[n] = num;
- return num;
- }else{
- return it->second;
- }
- }
- bool operator() (Node i,Node j) { return (getMaxVariableNum(i)<getMaxVariableNum(j));}
-};
-
-void FirstOrderModelIG::makeEvalUfIndexOrder( Node n ){
- if( d_eval_term_index_order.find( n )==d_eval_term_index_order.end() ){
- //sort arguments in order of least significant vs. most significant variable in default ordering
- std::map< Node, std::vector< int > > argIndex;
- std::vector< Node > args;
- for( int i=0; i<(int)n.getNumChildren(); i++ ){
- if( argIndex.find( n[i] )==argIndex.end() ){
- args.push_back( n[i] );
- }
- argIndex[n[i]].push_back( i );
- }
- sortGetMaxVariableNum sgmvn;
- std::sort( args.begin(), args.end(), sgmvn );
- for( int i=0; i<(int)args.size(); i++ ){
- for( int j=0; j<(int)argIndex[ args[i] ].size(); j++ ){
- d_eval_term_index_order[n].push_back( argIndex[ args[i] ][j] );
- }
- }
- bool useDefault = true;
- for( int i=0; i<(int)d_eval_term_index_order[n].size(); i++ ){
- if( i!=d_eval_term_index_order[n][i] ){
- useDefault = false;
- break;
- }
- }
- d_eval_uf_use_default[n] = useDefault;
- Debug("fmf-index-order") << "Will consider the following index ordering for " << n << " : ";
- for( int i=0; i<(int)d_eval_term_index_order[n].size(); i++ ){
- Debug("fmf-index-order") << d_eval_term_index_order[n][i] << " ";
- }
- Debug("fmf-index-order") << std::endl;
- }
-}
-
FirstOrderModelFmc::FirstOrderModelFmc(QuantifiersEngine * qe, context::Context* c, std::string name) :
FirstOrderModel(qe, c, name){
@@ -989,128 +521,6 @@ Node FirstOrderModelFmc::getFunctionValue(Node op, const char* argPrefix ) {
return NodeManager::currentNM()->mkNode(kind::LAMBDA, boundVarList, curr);
}
-FirstOrderModelAbs::FirstOrderModelAbs(QuantifiersEngine * qe, context::Context* c, std::string name) :
-FirstOrderModel(qe, c, name) {
-
-}
-
-FirstOrderModelAbs::~FirstOrderModelAbs()
-{
- for(std::map<Node, AbsDef*>::iterator i = d_models.begin(); i != d_models.end(); ++i) {
- delete (*i).second;
- }
-}
-
-void FirstOrderModelAbs::processInitialize( bool ispre ) {
- if( !ispre ){
- Trace("ambqi-debug") << "Process initialize" << std::endl;
- for( std::map<Node, AbsDef * >::iterator it = d_models.begin(); it != d_models.end(); ++it ) {
- Node op = it->first;
- TypeNode tno = op.getType();
- Trace("ambqi-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("ambqi-debug") << " * Initialize type " << tno[i] << ", add ";
- Trace("ambqi-debug") << e << " " << e.getType() << std::endl;
- //d_rep_set.add( e );
- }
- }
- }
- }
-}
-
-unsigned FirstOrderModelAbs::getRepresentativeId( TNode n ) {
- TNode r = getUsedRepresentative( n );
- std::map< TNode, unsigned >::iterator it = d_rep_id.find( r );
- if( it!=d_rep_id.end() ){
- return it->second;
- }else{
- return 0;
- }
-}
-
-TNode FirstOrderModelAbs::getUsedRepresentative( TNode 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];
- }
-}
-
-Node FirstOrderModelAbs::getFunctionValue(Node op, const char* argPrefix ) {
- if( d_models_valid[op] ){
- Trace("ambqi-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, op, vars );
- Node fv = NodeManager::currentNM()->mkNode(kind::LAMBDA, boundVarList, curr);
- Trace("ambqi-debug") << "Return " << fv << std::endl;
- return fv;
- }else{
-
- }
- return Node::null();
-}
-
-void FirstOrderModelAbs::processInitializeModelForTerm( Node n ) {
- 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()) {
- Trace("abmqi-debug") << "init model for " << op << std::endl;
- d_models[op] = new AbsDef;
- d_models_valid[op] = false;
- }
- }
-}
-
-void FirstOrderModelAbs::collectEqVars( TNode q, TNode n, std::map< int, bool >& eq_vars ) {
- for( unsigned i=0; i<n.getNumChildren(); i++ ){
- if( n.getKind()==EQUAL && n[i].getKind()==BOUND_VARIABLE ){
- int v = getVariableId( q, n[i] );
- Assert( v>=0 && v<(int)q[0].getNumChildren() );
- eq_vars[v] = true;
- }
- collectEqVars( q, n[i], eq_vars );
- }
-}
-
-void FirstOrderModelAbs::processInitializeQuantifier( Node q ) {
- if( d_var_order.find( q )==d_var_order.end() ){
- std::map< int, bool > eq_vars;
- for( unsigned i=0; i<q[0].getNumChildren(); i++ ){
- eq_vars[i] = false;
- }
- collectEqVars( q, q[1], eq_vars );
- for( unsigned r=0; r<2; r++ ){
- for( std::map< int, bool >::iterator it = eq_vars.begin(); it != eq_vars.end(); ++it ){
- if( it->second==(r==1) ){
- d_var_index[q][it->first] = d_var_order[q].size();
- d_var_order[q].push_back( it->first );
- }
- }
- }
- }
-}
-
-Node FirstOrderModelAbs::getVariable( Node q, unsigned i ) {
- return q[0][d_var_order[q][i]];
-}
-
} /* CVC4::theory::quantifiers namespace */
} /* CVC4::theory namespace */
} /* CVC4 namespace */
diff --git a/src/theory/quantifiers/first_order_model.h b/src/theory/quantifiers/first_order_model.h
index 7da5b2088..b96b42dc2 100644
--- a/src/theory/quantifiers/first_order_model.h
+++ b/src/theory/quantifiers/first_order_model.h
@@ -42,15 +42,10 @@ namespace quantifiers {
class TermDb;
-class FirstOrderModelIG;
-
namespace fmcheck {
class FirstOrderModelFmc;
}/* CVC4::theory::quantifiers::fmcheck namespace */
-class FirstOrderModelQInt;
-class FirstOrderModelAbs;
-
struct IsStarAttributeId {};
typedef expr::Attribute<IsStarAttributeId, bool> IsStarAttribute;
@@ -94,10 +89,7 @@ class FirstOrderModel : public TheoryModel
public:
FirstOrderModel(QuantifiersEngine* qe, context::Context* c, std::string name);
- virtual FirstOrderModelIG* asFirstOrderModelIG() { return nullptr; }
virtual fmcheck::FirstOrderModelFmc* asFirstOrderModelFmc() { return nullptr; }
- virtual FirstOrderModelQInt* asFirstOrderModelQInt() { return nullptr; }
- virtual FirstOrderModelAbs* asFirstOrderModelAbs() { return nullptr; }
/** assert quantifier */
void assertQuantifier( Node n );
/** get number of asserted quantifiers */
@@ -172,11 +164,11 @@ class FirstOrderModel : public TheoryModel
/** get variable id */
std::map<Node, std::map<Node, int> > d_quant_var_id;
/** process initialize model for term */
- virtual void processInitializeModelForTerm(Node n) = 0;
+ virtual void processInitializeModelForTerm(Node n) {}
/** process initialize quantifier */
virtual void processInitializeQuantifier(Node q) {}
/** process initialize */
- virtual void processInitialize(bool ispre) = 0;
+ virtual void processInitialize(bool ispre) {}
private:
// list of inactive quantified formulas
@@ -193,85 +185,6 @@ class FirstOrderModel : public TheoryModel
void computeModelBasisArgAttribute(Node n);
};/* class FirstOrderModel */
-class FirstOrderModelIG : public FirstOrderModel
-{
- public: // for Theory UF:
- /** class for generating models for uninterpreted functions
- *
- * This implements the model construction from page 6 of Reynolds et al,
- * "Quantifier Instantiation Techniques for Finite Model Finding in SMT",
- * CADE 2013.
- */
- class UfModelTreeGenerator
- {
- public:
- UfModelTreeGenerator() {}
- ~UfModelTreeGenerator() {}
- /** set default value */
- void setDefaultValue(Node v) { d_default_value = v; }
- /** set value */
- void setValue(
- TheoryModel* m, Node n, Node v, bool ground = true, bool isReq = true);
- /** make model */
- void makeModel(TheoryModel* m, uf::UfModelTree& tree);
- /** reset */
- void clear();
-
- public:
- /** the overall default value */
- Node d_default_value;
- /**
- * Stores (required, ground) values in key, value pairs of the form
- * ( P( a, b ), c ), which indicates P( a, b ) has value c in the model.
- * The "non-ground" values indicate that the key has a "model-basis"
- * variable, for example, ( P( _, b ), c ) indicates that P( x, b ) has the
- * value b for any value of x.
- */
- std::map<Node, Node> d_set_values[2][2];
- /** stores the set of non-ground keys in the above maps */
- std::vector<Node> d_defaults;
- /**
- * Returns the term corresponding to the intersection of n1 and n2, if it
- * exists, for example, for P( _, a ) and P( b, _ ), this method returns
- * P( b, a ), where _ is the "model basis" variable. We take into account
- * equality between arguments, so if a=b, then the intersection of P( a, a )
- * and P( b, _ ) is P( a, a ).
- */
- Node getIntersection(TheoryModel* m, Node n1, Node n2, bool& isGround);
- };
- /** models for each UF operator */
- std::map<Node, uf::UfModelTree> d_uf_model_tree;
- /** model generators for each UF operator */
- std::map<Node, UfModelTreeGenerator> d_uf_model_gen;
-
- private:
- //map from terms to the models used to calculate their value
- std::map< Node, bool > d_eval_uf_use_default;
- std::map< Node, uf::UfModelTree > d_eval_uf_model;
- void makeEvalUfModel( Node n );
- //index ordering to use for each term
- std::map< Node, std::vector< int > > d_eval_term_index_order;
- void makeEvalUfIndexOrder( Node n );
-//the following functions are for evaluating quantifier bodies
-public:
- FirstOrderModelIG(QuantifiersEngine * qe, context::Context* c, std::string name);
-
- FirstOrderModelIG* asFirstOrderModelIG() override { return this; }
- // initialize the model
- void processInitialize(bool ispre) override;
- //for initialize model
- void processInitializeModelForTerm(Node n) override;
- /** reset evaluation */
- void resetEvaluate();
- /** evaluate functions */
- int evaluate( Node n, int& depIndex, RepSetIterator* ri );
- Node evaluateTerm( Node n, int& depIndex, RepSetIterator* ri );
-private:
- //default evaluate term function
- Node evaluateTermDefault( Node n, int& depIndex, std::vector< int >& childDepIndex, RepSetIterator* ri );
-};/* class FirstOrderModelIG */
-
-
namespace fmcheck {
class Def;
@@ -301,36 +214,6 @@ class FirstOrderModelFmc : public FirstOrderModel
}/* CVC4::theory::quantifiers::fmcheck namespace */
-class AbsDef;
-
-class FirstOrderModelAbs : public FirstOrderModel
-{
- public:
- std::map< Node, AbsDef * > d_models;
- std::map< Node, bool > d_models_valid;
- std::map< TNode, unsigned > d_rep_id;
- std::map< TypeNode, unsigned > d_domain;
- std::map< Node, std::vector< int > > d_var_order;
- std::map< Node, std::map< int, int > > d_var_index;
-
- private:
- /** get current model value */
- void processInitializeModelForTerm(Node n) override;
- void processInitializeQuantifier(Node q) override;
- void collectEqVars( TNode q, TNode n, std::map< int, bool >& eq_vars );
- TNode getUsedRepresentative( TNode n );
-
- public:
- FirstOrderModelAbs(QuantifiersEngine * qe, context::Context* c, std::string name);
- ~FirstOrderModelAbs() override;
- FirstOrderModelAbs* asFirstOrderModelAbs() override { return this; }
- void processInitialize(bool ispre) override;
- unsigned getRepresentativeId( TNode n );
- bool isValidType( TypeNode tn ) { return d_domain.find( tn )!=d_domain.end(); }
- Node getFunctionValue(Node op, const char* argPrefix );
- Node getVariable( Node q, unsigned i );
-};
-
}/* CVC4::theory::quantifiers namespace */
}/* CVC4::theory namespace */
}/* CVC4 namespace */
diff --git a/src/theory/quantifiers/fmf/ambqi_builder.cpp b/src/theory/quantifiers/fmf/ambqi_builder.cpp
deleted file mode 100644
index f2b131f21..000000000
--- a/src/theory/quantifiers/fmf/ambqi_builder.cpp
+++ /dev/null
@@ -1,971 +0,0 @@
-/********************* */
-/*! \file ambqi_builder.cpp
- ** \verbatim
- ** Top contributors (to current version):
- ** Andrew Reynolds, Tim King
- ** This file is part of the CVC4 project.
- ** Copyright (c) 2009-2018 by the authors listed in the file AUTHORS
- ** in the top-level source directory) and their institutional affiliations.
- ** All rights reserved. See the file COPYING in the top-level source
- ** directory for licensing information.\endverbatim
- **
- ** \brief Implementation of abstract MBQI builder
- **/
-
-#include "theory/quantifiers/fmf/ambqi_builder.h"
-
-#include "base/cvc4_check.h"
-#include "options/quantifiers_options.h"
-#include "theory/quantifiers/instantiate.h"
-#include "theory/quantifiers/term_database.h"
-#include "theory/quantifiers/term_util.h"
-
-using namespace std;
-using namespace CVC4::kind;
-using namespace CVC4::context;
-
-namespace CVC4 {
-namespace theory {
-namespace quantifiers {
-
-
-void AbsDef::construct_func( FirstOrderModelAbs * m, std::vector< TNode >& fapps, unsigned depth ) {
- d_def.clear();
- Assert( !fapps.empty() );
- if( depth==fapps[0].getNumChildren() ){
- //if( fapps.size()>1 ){
- // for( unsigned i=0; i<fapps.size(); i++ ){
- // std::cout << "...." << fapps[i] << " -> " << m->getRepresentativeId( fapps[i] ) << std::endl;
- // }
- //}
- //get representative in model for this term
- d_value = m->getRepresentativeId( fapps[0] );
- Assert( d_value!=val_none );
- }else{
- TypeNode tn = fapps[0][depth].getType();
- std::map< unsigned, std::vector< TNode > > fapp_child;
-
- //partition based on evaluations of fapps[1][depth]....fapps[n][depth]
- for( unsigned i=0; i<fapps.size(); i++ ){
- unsigned r = m->getRepresentativeId( fapps[i][depth] );
- Assert( r < 32 );
- fapp_child[r].push_back( fapps[i] );
- }
-
- //do completion
- std::map< unsigned, unsigned > fapp_child_index;
- unsigned def = m->d_domain[ tn ];
- unsigned minSize = fapp_child.begin()->second.size();
- unsigned minSizeIndex = fapp_child.begin()->first;
- for( std::map< unsigned, std::vector< TNode > >::iterator it = fapp_child.begin(); it != fapp_child.end(); ++it ){
- fapp_child_index[it->first] = ( 1 << it->first );
- def = def & ~( 1 << it->first );
- if( it->second.size()<minSize ){
- minSize = it->second.size();
- minSizeIndex = it->first;
- }
- }
- fapp_child_index[minSizeIndex] |= def;
- d_default = fapp_child_index[minSizeIndex];
-
- //construct children
- for( std::map< unsigned, std::vector< TNode > >::iterator it = fapp_child.begin(); it != fapp_child.end(); ++it ){
- Trace("abs-model-debug") << "Construct " << it->first << " : " << fapp_child_index[it->first] << " : ";
- const RepSet* rs = m->getRepSet();
- debugPrintUInt("abs-model-debug",
- rs->getNumRepresentatives(tn),
- fapp_child_index[it->first]);
- Trace("abs-model-debug") << " : " << it->second.size() << " terms." << std::endl;
- d_def[fapp_child_index[it->first]].construct_func( m, it->second, depth+1 );
- }
- }
-}
-
-void AbsDef::simplify( FirstOrderModelAbs * m, TNode q, TNode n, unsigned depth ) {
- if( d_value==val_none && !d_def.empty() ){
- //process the default
- std::map< unsigned, AbsDef >::iterator defd = d_def.find( d_default );
- Assert( defd!=d_def.end() );
- unsigned newDef = d_default;
- std::vector< unsigned > to_erase;
- defd->second.simplify( m, q, n, depth+1 );
- int defVal = defd->second.d_value;
- bool isConstant = ( defVal!=val_none );
- //process each child
- for( std::map< unsigned, AbsDef >::iterator it = d_def.begin(); it != d_def.end(); ++it ){
- if( it->first!=d_default ){
- it->second.simplify( m, q, n, depth+1 );
- if( it->second.d_value==defVal && it->second.d_value!=val_none ){
- newDef = newDef | it->first;
- to_erase.push_back( it->first );
- }else{
- isConstant = false;
- }
- }
- }
- if( !to_erase.empty() ){
- //erase old default
- int defVal = defd->second.d_value;
- d_def.erase( d_default );
- //set new default
- d_default = newDef;
- d_def[d_default].construct_def_entry( m, q, n, defVal, depth+1 );
- //erase redundant entries
- for( unsigned i=0; i<to_erase.size(); i++ ){
- d_def.erase( to_erase[i] );
- }
- }
- //if constant, propagate the value upwards
- if( isConstant ){
- d_value = defVal;
- }else{
- d_value = val_none;
- }
- }
-}
-
-void AbsDef::debugPrintUInt( const char * c, unsigned dSize, unsigned u ) const{
- for( unsigned i=0; i<dSize; i++ ){
- Trace(c) << ( ( u & ( 1 << i ) )!=0 ? "1" : "0");
- }
- //Trace(c) << "(";
- //for( unsigned i=0; i<32; i++ ){
- // Trace(c) << ( ( u & ( 1 << i ) )!=0 ? "1" : "0");
- //}
- //Trace(c) << ")";
-}
-
-void AbsDef::debugPrint( const char * c, FirstOrderModelAbs * m, TNode f, unsigned depth ) const{
- if( Trace.isOn(c) ){
- if( depth==f.getNumChildren() ){
- for( unsigned i=0; i<depth; i++ ){ Trace(c) << " ";}
- Trace(c) << "V[" << d_value << "]" << std::endl;
- }else{
- TypeNode tn = f[depth].getType();
- const RepSet* rs = m->getRepSet();
- unsigned dSize = rs->getNumRepresentatives(tn);
- Assert( dSize<32 );
- for( std::map< unsigned, AbsDef >::const_iterator it = d_def.begin(); it != d_def.end(); ++it ){
- for( unsigned i=0; i<depth; i++ ){ Trace(c) << " ";}
- debugPrintUInt( c, dSize, it->first );
- if( it->first==d_default ){
- Trace(c) << "*";
- }
- if( it->second.d_value!=val_none ){
- Trace(c) << " -> V[" << it->second.d_value << "]";
- }
- Trace(c) << std::endl;
- it->second.debugPrint( c, m, f, depth+1 );
- }
- }
- }
-}
-
-bool AbsDef::addInstantiations( FirstOrderModelAbs * m, QuantifiersEngine * qe, TNode q, std::vector< Node >& terms, int& inst, unsigned depth ) {
- if( inst==0 || !options::fmfOneInstPerRound() ){
- if( d_value==1 ){
- //instantiations are all true : ignore this
- return true;
- }else{
- if( depth==q[0].getNumChildren() ){
- if (qe->getInstantiate()->addInstantiation(q, terms, true))
- {
- Trace("ambqi-inst-debug") << "-> Added instantiation." << std::endl;
- inst++;
- return true;
- }else{
- Trace("ambqi-inst-debug") << "-> Failed to add instantiation." << std::endl;
- //we are incomplete
- return false;
- }
- }else{
- bool osuccess = true;
- TypeNode tn = m->getVariable( q, depth ).getType();
- for( std::map< unsigned, AbsDef >::iterator it = d_def.begin(); it != d_def.end(); ++it ){
- //get witness term
- unsigned index = 0;
- bool success;
- do {
- success = false;
- index = getId( it->first, index );
- if( index<32 ){
- const RepSet* rs = m->getRepSet();
- Assert(index < rs->getNumRepresentatives(tn));
- terms[m->d_var_order[q][depth]] =
- rs->getRepresentative(tn, index);
- if( !it->second.addInstantiations( m, qe, q, terms, inst, depth+1 ) && inst==0 ){
- //if we are incomplete, and have not yet added an instantiation, keep trying
- index++;
- Trace("ambqi-inst-debug") << "At depth " << depth << ", failed branch, no instantiations and incomplete, increment index : " << index << std::endl;
- }else{
- success = true;
- }
- }
- }while( !qe->inConflict() && !success && index<32 );
- //mark if we are incomplete
- osuccess = osuccess && success;
- }
- return osuccess;
- }
- }
- }else{
- return true;
- }
-}
-
-void AbsDef::construct_entry( std::vector< unsigned >& entry, std::vector< bool >& entry_def, int v, unsigned depth ) {
- if( depth==entry.size() ){
- d_value = v;
- }else{
- d_def[entry[depth]].construct_entry( entry, entry_def, v, depth+1 );
- if( entry_def[depth] ){
- d_default = entry[depth];
- }
- }
-}
-
-void AbsDef::get_defs( unsigned u, std::vector< AbsDef * >& defs ) {
- for( std::map< unsigned, AbsDef >::iterator it = d_def.begin(); it != d_def.end(); ++it ){
- if( ( u & it->first )!=0 ){
- Assert( (u & it->first)==u );
- defs.push_back( &it->second );
- }
- }
-}
-
-void AbsDef::construct_normalize( FirstOrderModelAbs * m, TNode q, std::vector< AbsDef * >& defs, unsigned depth ) {
- if( depth==q[0].getNumChildren() ){
- Assert( defs.size()==1 );
- d_value = defs[0]->d_value;
- }else{
- TypeNode tn = m->getVariable( q, depth ).getType();
- unsigned def = m->d_domain[tn];
- for( unsigned i=0; i<defs.size(); i++ ){
- //process each simple child
- for( std::map< unsigned, AbsDef >::iterator itd = defs[i]->d_def.begin(); itd != defs[i]->d_def.end(); ++itd ){
- if( isSimple( itd->first ) && ( def & itd->first )!=0 ){
- def &= ~( itd->first );
- //process this value
- std::vector< AbsDef * > cdefs;
- for( unsigned j=0; j<defs.size(); j++ ){
- defs[j]->get_defs( itd->first, cdefs );
- }
- d_def[itd->first].construct_normalize( m, q, cdefs, depth+1 );
- if( def==0 ){
- d_default = itd->first;
- break;
- }
- }
- }
- if( def==0 ){
- break;
- }
- }
- if( def!=0 ){
- d_default = def;
- //process the default
- std::vector< AbsDef * > cdefs;
- for( unsigned j=0; j<defs.size(); j++ ){
- defs[j]->get_defs( d_default, cdefs );
- }
- d_def[d_default].construct_normalize( m, q, cdefs, depth+1 );
- }
- }
-}
-
-void AbsDef::construct_def_entry( FirstOrderModelAbs * m, TNode q, TNode n, int v, unsigned depth ) {
- d_value = v;
- if( depth<n.getNumChildren() ){
- TypeNode tn = q.isNull() ? n[depth].getType() : m->getVariable( q, depth ).getType();
- unsigned dom = m->d_domain[tn] ;
- d_def[dom].construct_def_entry( m, q, n, v, depth+1 );
- d_default = dom;
- }
-}
-
-void AbsDef::apply_ucompose( FirstOrderModelAbs * m, TNode q,
- std::vector< unsigned >& entry, std::vector< bool >& entry_def,
- std::vector< int >& terms, std::map< unsigned, int >& vchildren,
- AbsDef * a, unsigned depth ) {
- if( depth==terms.size() ){
- if( Trace.isOn("ambqi-check-debug2") ){
- Trace("ambqi-check-debug2") << "Add entry ( ";
- const RepSet* rs = m->getRepSet();
- for( unsigned i=0; i<entry.size(); i++ ){
- unsigned dSize =
- rs->getNumRepresentatives(m->getVariable(q, i).getType());
- debugPrintUInt( "ambqi-check-debug2", dSize, entry[i] );
- Trace("ambqi-check-debug2") << " ";
- }
- Trace("ambqi-check-debug2") << ")" << std::endl;
- }
- a->construct_entry( entry, entry_def, d_value );
- }else{
- unsigned id;
- if( terms[depth]==val_none ){
- //a variable
- std::map< unsigned, int >::iterator itv = vchildren.find( depth );
- Assert( itv!=vchildren.end() );
- unsigned prev_v = entry[itv->second];
- bool prev_vd = entry_def[itv->second];
- for( std::map< unsigned, AbsDef >::iterator it = d_def.begin(); it != d_def.end(); ++it ){
- entry[itv->second] = it->first & prev_v;
- entry_def[itv->second] = ( it->first==d_default ) && prev_vd;
- if( entry[itv->second]!=0 ){
- it->second.apply_ucompose( m, q, entry, entry_def, terms, vchildren, a, depth+1 );
- }
- }
- entry[itv->second] = prev_v;
- entry_def[itv->second] = prev_vd;
- }else{
- id = (unsigned)terms[depth];
- Assert( id<32 );
- unsigned fid = 1 << id;
- std::map< unsigned, AbsDef >::iterator it = d_def.find( fid );
- if( it!=d_def.end() ){
- it->second.apply_ucompose( m, q, entry, entry_def, terms, vchildren, a, depth+1 );
- }else{
- d_def[d_default].apply_ucompose( m, q, entry, entry_def, terms, vchildren, a, depth+1 );
- }
- }
- }
-}
-
-void AbsDef::construct_var_eq( FirstOrderModelAbs * m, TNode q, unsigned v1, unsigned v2, int curr, int currv, unsigned depth ) {
- if( depth==q[0].getNumChildren() ){
- Assert( currv!=val_none );
- d_value = currv;
- }else{
- TypeNode tn = m->getVariable( q, depth ).getType();
- unsigned dom = m->d_domain[tn];
- int vindex = depth==v1 ? 0 : ( depth==v2 ? 1 : val_none );
- if( vindex==val_none ){
- d_def[dom].construct_var_eq( m, q, v1, v2, curr, currv, depth+1 );
- d_default = dom;
- }else{
- Assert( currv==val_none );
- if( curr==val_none ){
- unsigned numReps = m->getRepSet()->getNumRepresentatives(tn);
- Assert( numReps < 32 );
- for( unsigned i=0; i<numReps; i++ ){
- curr = 1 << i;
- d_def[curr].construct_var_eq( m, q, v1, v2, curr, currv, depth+1 );
- }
- d_default = curr;
- }else{
- d_def[curr].construct_var_eq( m, q, v1, v2, curr, 1, depth+1 );
- dom = dom & ~curr;
- d_def[dom].construct_var_eq( m, q, v1, v2, curr, 0, depth+1 );
- d_default = dom;
- }
- }
- }
-}
-
-void AbsDef::construct_var( FirstOrderModelAbs * m, TNode q, unsigned v, int currv, unsigned depth ) {
- if( depth==q[0].getNumChildren() ){
- Assert( currv!=val_none );
- d_value = currv;
- }else{
- TypeNode tn = m->getVariable( q, depth ).getType();
- if( v==depth ){
- const unsigned numReps = m->getRepSet()->getNumRepresentatives(tn);
- CVC4_CHECK(numReps > 0 && numReps < 32);
- for( unsigned i=0; i<numReps; i++ ){
- d_def[ 1 << i ].construct_var( m, q, v, i, depth+1 );
- }
- d_default = 1 << (numReps - 1);
- }else{
- unsigned dom = m->d_domain[tn];
- d_def[dom].construct_var( m, q, v, currv, depth+1 );
- d_default = dom;
- }
- }
-}
-
-void AbsDef::construct_compose( FirstOrderModelAbs * m, TNode q, TNode n, AbsDef * f,
- std::map< unsigned, AbsDef * >& children,
- std::map< unsigned, int >& bchildren, std::map< unsigned, int >& vchildren,
- std::vector< unsigned >& entry, std::vector< bool >& entry_def ) {
- const RepSet* rs = m->getRepSet();
- if( n.getKind()==OR || n.getKind()==AND ){
- // short circuiting
- for( std::map< unsigned, AbsDef * >::iterator it = children.begin(); it != children.end(); ++it ){
- if( ( it->second->d_value==0 && n.getKind()==AND ) ||
- ( it->second->d_value==1 && n.getKind()==OR ) ){
- //std::cout << "Short circuit " << it->second->d_value << " " << entry.size() << "/" << q[0].getNumChildren() << std::endl;
- unsigned count = q[0].getNumChildren() - entry.size();
- for( unsigned i=0; i<count; i++ ){
- entry.push_back( m->d_domain[m->getVariable( q, entry.size() ).getType()] );
- entry_def.push_back( true );
- }
- construct_entry( entry, entry_def, it->second->d_value );
- for( unsigned i=0; i<count; i++ ){
- entry.pop_back();
- entry_def.pop_back();
- }
- return;
- }
- }
- }
- if( entry.size()==q[0].getNumChildren() ){
- if( f ){
- if( Trace.isOn("ambqi-check-debug2") ){
- for( unsigned i=0; i<entry.size(); i++ ){ Trace("ambqi-check-debug2") << " "; }
- Trace("ambqi-check-debug2") << "Evaluate uninterpreted function entry..." << std::endl;
- }
- //we are composing with an uninterpreted function
- std::vector< int > values;
- values.resize( n.getNumChildren(), val_none );
- for( std::map< unsigned, AbsDef * >::iterator it = children.begin(); it != children.end(); ++it ){
- values[it->first] = it->second->d_value;
- }
- for( std::map< unsigned, int >::iterator it = bchildren.begin(); it != bchildren.end(); ++it ){
- values[it->first] = it->second;
- }
- //look up value(s)
- f->apply_ucompose( m, q, entry, entry_def, values, vchildren, this );
- }else{
- bool incomplete = false;
- //we are composing with an interpreted function
- std::vector< TNode > values;
- values.resize( n.getNumChildren(), TNode::null() );
- for( std::map< unsigned, AbsDef * >::iterator it = children.begin(); it != children.end(); ++it ){
- Trace("ambqi-check-debug2") << "composite : " << it->first << " : " << it->second->d_value;
- if( it->second->d_value>=0 ){
- if (it->second->d_value
- >= (int)rs->getNumRepresentatives(n[it->first].getType()))
- {
- std::cout << it->second->d_value << " " << n[it->first] << " "
- << n[it->first].getType() << " "
- << rs->getNumRepresentatives(n[it->first].getType())
- << std::endl;
- }
- Assert(it->second->d_value
- < (int)rs->getNumRepresentatives(n[it->first].getType()));
- values[it->first] = rs->getRepresentative(n[it->first].getType(),
- it->second->d_value);
- }else{
- incomplete = true;
- }
- Trace("ambqi-check-debug2") << " ->> " << values[it->first] << std::endl;
- }
- for( std::map< unsigned, int >::iterator it = bchildren.begin(); it != bchildren.end(); ++it ){
- Trace("ambqi-check-debug2") << " basic : " << it->first << " : " << it->second;
- if( it->second>=0 ){
- Assert(it->second
- < (int)rs->getNumRepresentatives(n[it->first].getType()));
- values[it->first] =
- rs->getRepresentative(n[it->first].getType(), it->second);
- }else{
- incomplete = true;
- }
- Trace("ambqi-check-debug2") << " ->> " << values[it->first] << std::endl;
- }
- Assert( vchildren.empty() );
- if( incomplete ){
- Trace("ambqi-check-debug2") << "Construct incomplete entry." << std::endl;
-
- //if a child is unknown, we must return unknown
- construct_entry( entry, entry_def, val_unk );
- }else{
- if( Trace.isOn("ambqi-check-debug2") ){
- for( unsigned i=0; i<entry.size(); i++ ){ Trace("ambqi-check-debug2") << " "; }
- Trace("ambqi-check-debug2") << "Evaluate interpreted function entry ( ";
- for( unsigned i=0; i<values.size(); i++ ){
- Assert( !values[i].isNull() );
- Trace("ambqi-check-debug2") << values[i] << " ";
- }
- Trace("ambqi-check-debug2") << ")..." << std::endl;
- }
- //evaluate
- Node vv = NodeManager::currentNM()->mkNode( n.getKind(), values );
- vv = Rewriter::rewrite( vv );
- int v = m->getRepresentativeId( vv );
- construct_entry( entry, entry_def, v );
- }
- }
- }else{
- //take product of arguments
- TypeNode tn = m->getVariable( q, entry.size() ).getType();
- Assert( m->isValidType( tn ) );
- unsigned def = m->d_domain[tn];
- if( Trace.isOn("ambqi-check-debug2") ){
- for( unsigned i=0; i<entry.size(); i++ ){ Trace("ambqi-check-debug2") << " "; }
- Trace("ambqi-check-debug2") << "Take product of arguments" << std::endl;
- }
- for( std::map< unsigned, AbsDef * >::iterator it = children.begin(); it != children.end(); ++it ){
- Assert( it->second!=NULL );
- //process each child
- for( std::map< unsigned, AbsDef >::iterator itd = it->second->d_def.begin(); itd != it->second->d_def.end(); ++itd ){
- if( itd->first!=it->second->d_default && ( def & itd->first )!=0 ){
- def &= ~( itd->first );
- //process this value
- std::map< unsigned, AbsDef * > cchildren;
- for( std::map< unsigned, AbsDef * >::iterator it2 = children.begin(); it2 != children.end(); ++it2 ){
- Assert( it2->second!=NULL );
- std::map< unsigned, AbsDef >::iterator itdf = it2->second->d_def.find( itd->first );
- if( itdf!=it2->second->d_def.end() ){
- cchildren[it2->first] = &itdf->second;
- }else{
- Assert( it2->second->getDefault()!=NULL );
- cchildren[it2->first] = it2->second->getDefault();
- }
- }
- if( Trace.isOn("ambqi-check-debug2") ){
- for( unsigned i=0; i<entry.size(); i++ ){ Trace("ambqi-check-debug2") << " "; }
- Trace("ambqi-check-debug2") << "...process : ";
- debugPrintUInt("ambqi-check-debug2",
- rs->getNumRepresentatives(tn),
- itd->first);
- Trace("ambqi-check-debug2") << " " << children.size() << " " << cchildren.size() << std::endl;
- }
- entry.push_back( itd->first );
- entry_def.push_back( def==0 );
- construct_compose( m, q, n, f, cchildren, bchildren, vchildren, entry, entry_def );
- entry_def.pop_back();
- entry.pop_back();
- if( def==0 ){
- break;
- }
- }
- }
- if( def==0 ){
- break;
- }
- }
- if( def!=0 ){
- if( Trace.isOn("ambqi-check-debug2") ){
- for( unsigned i=0; i<entry.size(); i++ ){ Trace("ambqi-check-debug2") << " "; }
- Trace("ambqi-check-debug2") << "Make default argument" << std::endl;
- }
- std::map< unsigned, AbsDef * > cdchildren;
- for( std::map< unsigned, AbsDef * >::iterator it = children.begin(); it != children.end(); ++it ){
- Assert( it->second->getDefault()!=NULL );
- cdchildren[it->first] = it->second->getDefault();
- }
- if( Trace.isOn("ambqi-check-debug2") ){
- for( unsigned i=0; i<entry.size(); i++ ){ Trace("ambqi-check-debug2") << " "; }
- Trace("ambqi-check-debug2") << "...process default : ";
- debugPrintUInt(
- "ambqi-check-debug2", rs->getNumRepresentatives(tn), def);
- Trace("ambqi-check-debug2") << " " << children.size() << " " << cdchildren.size() << std::endl;
- }
- entry.push_back( def );
- entry_def.push_back( true );
- construct_compose( m, q, n, f, cdchildren, bchildren, vchildren, entry, entry_def );
- entry_def.pop_back();
- entry.pop_back();
- }
- }
-}
-
-bool AbsDef::construct( FirstOrderModelAbs * m, TNode q, TNode n, AbsDef * f,
- std::map< unsigned, AbsDef * >& children,
- std::map< unsigned, int >& bchildren, std::map< unsigned, int >& vchildren,
- int varChCount ) {
- if( Trace.isOn("ambqi-check-debug3") ){
- for( unsigned i=0; i<n.getNumChildren(); i++ ){
- Trace("ambqi-check-debug3") << i << " : ";
- Trace("ambqi-check-debug3") << ((children.find( i )!=children.end()) ? "X" : ".");
- if( bchildren.find( i )!=bchildren.end() ){
- Trace("ambqi-check-debug3") << bchildren[i];
- }else{
- Trace("ambqi-check-debug3") << ".";
- }
- if( vchildren.find( i )!=vchildren.end() ){
- Trace("ambqi-check-debug3") << vchildren[i];
- }else{
- Trace("ambqi-check-debug3") << ".";
- }
- Trace("ambqi-check-debug3") << std::endl;
- }
- Trace("ambqi-check-debug3") << "varChCount : " << varChCount << std::endl;
- }
- if( varChCount==0 || f ){
- //short-circuit
- if( n.getKind()==AND || n.getKind()==OR ){
- for( std::map< unsigned, int >::iterator it = bchildren.begin(); it !=bchildren.end(); ++it ){
- if( ( it->second==0 && n.getKind()==AND ) ||
- ( it->second==1 && n.getKind()==OR ) ){
- construct_def_entry( m, q, q[0], it->second );
- return true;
- }
- }
- }
- Trace("ambqi-check-debug2") << "Construct compose..." << std::endl;
- std::vector< unsigned > entry;
- std::vector< bool > entry_def;
- if( f && varChCount>0 ){
- AbsDef unorm;
- unorm.construct_compose( m, q, n, f, children, bchildren, vchildren, entry, entry_def );
- //normalize
- std::vector< AbsDef* > defs;
- defs.push_back( &unorm );
- construct_normalize( m, q, defs );
- }else{
- construct_compose( m, q, n, f, children, bchildren, vchildren, entry, entry_def );
- }
- Assert( is_normalized() );
- return true;
- }else if( varChCount==1 && ( n.getKind()==EQUAL && !n[0].getType().isBoolean() ) ){
- Trace("ambqi-check-debug2") << "Expand variable child..." << std::endl;
- //expand the variable based on its finite domain
- AbsDef a;
- a.construct_var( m, q, vchildren.begin()->second, val_none );
- children[vchildren.begin()->first] = &a;
- vchildren.clear();
- std::vector< unsigned > entry;
- std::vector< bool > entry_def;
- Trace("ambqi-check-debug2") << "Construct compose with variable..." << std::endl;
- construct_compose( m, q, n, f, children, bchildren, vchildren, entry, entry_def );
- return true;
- }else if( varChCount==2 && ( n.getKind()==EQUAL && !n[0].getType().isBoolean() ) ){
- Trace("ambqi-check-debug2") << "Construct variable equality..." << std::endl;
- //efficient expansion of the equality
- construct_var_eq( m, q, vchildren[0], vchildren[1], val_none, val_none );
- return true;
- }else{
- return false;
- }
-}
-
-void AbsDef::negate() {
- for( std::map< unsigned, AbsDef >::iterator it = d_def.begin(); it != d_def.end(); ++it ){
- it->second.negate();
- }
- if( d_value==0 ){
- d_value = 1;
- }else if( d_value==1 ){
- d_value = 0;
- }
-}
-
-Node AbsDef::getFunctionValue( FirstOrderModelAbs * m, TNode op, std::vector< Node >& vars, unsigned depth ) {
- const RepSet* rs = m->getRepSet();
- if( depth==vars.size() ){
- TypeNode tn = op.getType();
- if( tn.getNumChildren()>0 ){
- tn = tn[tn.getNumChildren() - 1];
- }
- if( d_value>=0 ){
- Assert(d_value < (int)rs->getNumRepresentatives(tn));
- if( tn.isBoolean() ){
- return NodeManager::currentNM()->mkConst( d_value==1 );
- }else{
- return rs->getRepresentative(tn, d_value);
- }
- }else{
- return Node::null();
- }
- }else{
- TypeNode tn = vars[depth].getType();
- Node curr;
- curr = d_def[d_default].getFunctionValue( m, op, vars, depth+1 );
- for( std::map< unsigned, AbsDef >::iterator it = d_def.begin(); it != d_def.end(); ++it ){
- if( it->first!=d_default ){
- unsigned id = getId( it->first );
- Assert(id < rs->getNumRepresentatives(tn));
- TNode n = rs->getRepresentative(tn, id);
- Node fv = it->second.getFunctionValue( m, op, vars, depth+1 );
- if( !curr.isNull() && !fv.isNull() ){
- curr = NodeManager::currentNM()->mkNode( ITE, vars[depth].eqNode( n ), fv, curr );
- }else{
- curr = Node::null();
- }
- }
- }
- return curr;
- }
-}
-
-bool AbsDef::isSimple( unsigned n ) {
- return (n & (n - 1))==0;
-}
-
-unsigned AbsDef::getId( unsigned n, unsigned start, unsigned end ) {
- Assert( n!=0 );
- while( (n & ( 1 << start )) == 0 ){
- start++;
- if( start==end ){
- return start;
- }
- }
- return start;
-}
-
-Node AbsDef::evaluate( FirstOrderModelAbs * m, TypeNode retTyp, std::vector< Node >& args ) {
- std::vector< unsigned > iargs;
- for( unsigned i=0; i<args.size(); i++ ){
- unsigned v = 1 << m->getRepresentativeId( args[i] );
- iargs.push_back( v );
- }
- return evaluate( m, retTyp, iargs, 0 );
-}
-
-Node AbsDef::evaluate( FirstOrderModelAbs * m, TypeNode retTyp, std::vector< unsigned >& iargs, unsigned depth ) {
- if( d_value!=val_none ){
- if( d_value==val_unk ){
- return Node::null();
- }else{
- const RepSet* rs = m->getRepSet();
- Assert(d_value >= 0 && d_value < (int)rs->getNumRepresentatives(retTyp));
- return rs->getRepresentative(retTyp, d_value);
- }
- }else{
- std::map< unsigned, AbsDef >::iterator it = d_def.find( iargs[depth] );
- if( it==d_def.end() ){
- return d_def[d_default].evaluate( m, retTyp, iargs, depth+1 );
- }else{
- return it->second.evaluate( m, retTyp, iargs, depth+1 );
- }
- }
-}
-
-bool AbsDef::is_normalized() {
- for( std::map< unsigned, AbsDef >::iterator it1 = d_def.begin(); it1 != d_def.end(); ++it1 ){
- if( !it1->second.is_normalized() ){
- return false;
- }
- for( std::map< unsigned, AbsDef >::iterator it2 = d_def.begin(); it2 != d_def.end(); ++it2 ){
- if( it1->first!=it2->first && (( it1->first & it2->first )!=0) ){
- return false;
- }
- }
- }
- return true;
-}
-
-AbsMbqiBuilder::AbsMbqiBuilder( context::Context* c, QuantifiersEngine* qe ) :
-QModelBuilder( c, qe ){
- d_true = NodeManager::currentNM()->mkConst( true );
- d_false = NodeManager::currentNM()->mkConst( false );
-}
-
-
-//------------------------model construction----------------------------
-
-bool AbsMbqiBuilder::processBuildModel(TheoryModel* m) {
- if (!m->areFunctionValuesEnabled())
- {
- // nothing to do if no functions
- return true;
- }
- Trace("ambqi-debug") << "process build model " << std::endl;
- FirstOrderModel* f = (FirstOrderModel*)m;
- FirstOrderModelAbs* fm = f->asFirstOrderModelAbs();
- RepSet* rs = m->getRepSetPtr();
- fm->initialize();
- //process representatives
- fm->d_rep_id.clear();
- fm->d_domain.clear();
-
- //initialize boolean sort
- TypeNode b = d_true.getType();
- rs->d_type_reps[b].clear();
- rs->d_type_reps[b].push_back(d_false);
- rs->d_type_reps[b].push_back(d_true);
- fm->d_rep_id[d_false] = 0;
- fm->d_rep_id[d_true] = 1;
-
- //initialize unintpreted sorts
- Trace("ambqi-model") << std::endl << "Making representatives..." << std::endl;
- for (std::map<TypeNode, std::vector<Node> >::iterator it =
- rs->d_type_reps.begin();
- it != rs->d_type_reps.end();
- ++it)
- {
- if( it->first.isSort() ){
- Assert( !it->second.empty() );
- //set the domain
- fm->d_domain[it->first] = 0;
- Trace("ambqi-model") << "Representatives for " << it->first << " : " << std::endl;
- for( unsigned i=0; i<it->second.size(); i++ ){
- if( i<32 ){
- fm->d_domain[it->first] |= ( 1 << i );
- }
- Trace("ambqi-model") << i << " : " << it->second[i] << std::endl;
- fm->d_rep_id[it->second[i]] = i;
- }
- if( it->second.size()>=32 ){
- fm->d_domain.erase( it->first );
- }
- }
- }
-
- Trace("ambqi-model") << std::endl << "Making function definitions..." << std::endl;
- //construct the models for functions
- for( std::map<Node, AbsDef * >::iterator it = fm->d_models.begin(); it != fm->d_models.end(); ++it ) {
- Node f = it->first;
- Trace("ambqi-model-debug") << "Building Model for " << f << std::endl;
- //reset the model
- it->second->clear();
- //get all (non-redundant) f-applications
- std::vector< TNode > fapps;
- Trace("ambqi-model-debug") << "Initial terms: " << std::endl;
- std::map< Node, std::vector< Node > >::iterator itut = fm->d_uf_terms.find( f );
- if( itut!=fm->d_uf_terms.end() ){
- for( size_t i=0; i<itut->second.size(); i++ ){
- Node n = itut->second[i];
- // only consider unique up to congruence (in model equality engine)?
- Trace("ambqi-model-debug") << " " << n << " -> " << fm->getRepresentativeId( n ) << std::endl;
- fapps.push_back( n );
- }
- }
- if( fapps.empty() ){
- //choose arbitrary value
- Node mbt = fm->getModelBasisOpTerm(f);
- Trace("ambqi-model-debug") << "Initial terms empty, add " << mbt << std::endl;
- fapps.push_back( mbt );
- }
- bool fValid = true;
- for( unsigned i=0; i<fapps[0].getNumChildren(); i++ ){
- if( fm->d_domain.find( fapps[0][i].getType() )==fm->d_domain.end() ){
- Trace("ambqi-model") << "Interpretation of " << f << " is not valid.";
- Trace("ambqi-model") << " (domain for " << fapps[0][i].getType() << " is too large)." << std::endl;
- fValid = false;
- break;
- }
- }
- fm->d_models_valid[f] = fValid;
- if( fValid ){
- //construct the ambqi model
- it->second->construct_func( fm, fapps );
- Trace("ambqi-model-debug") << "Interpretation of " << f << " : " << std::endl;
- it->second->debugPrint("ambqi-model-debug", fm, fapps[0] );
- Trace("ambqi-model-debug") << "Simplifying " << f << "..." << std::endl;
- it->second->simplify( fm, TNode::null(), fapps[0] );
- Trace("ambqi-model") << "(Simplified) interpretation of " << f << " : " << std::endl;
- it->second->debugPrint("ambqi-model", fm, fapps[0] );
-
-/*
- if( Debug.isOn("ambqi-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("ambqi-model-debug") << fm->d_uf_terms[f][i] << " evaluates to " << e << std::endl;
- Assert( fm->areEqual( e, fm->d_uf_terms[f][i] ) );
- }
- }
-*/
- }
- }
- Trace("ambqi-model") << "Construct model representation..." << std::endl;
- //make function values
- for( std::map<Node, AbsDef * >::iterator it = fm->d_models.begin(); it != fm->d_models.end(); ++it ) {
- if( it->first.getType().getNumChildren()>1 ){
- Trace("ambqi-model") << "Construct for " << it->first << "..." << std::endl;
- Node f_def = fm->getFunctionValue( it->first, "$x" );
- m->assignFunctionDefinition( it->first, f_def );
- }
- }
- Assert( d_addedLemmas==0 );
- return TheoryEngineModelBuilder::processBuildModel( m );
-}
-
-
-//--------------------model checking---------------------------------------
-
-//do exhaustive instantiation
-int AbsMbqiBuilder::doExhaustiveInstantiation( FirstOrderModel * fm, Node q, int effort ) {
- Trace("ambqi-check") << "Exhaustive instantiation " << q << " " << effort << std::endl;
- if (effort==0) {
- FirstOrderModelAbs * fma = fm->asFirstOrderModelAbs();
- bool quantValid = true;
- for( unsigned i=0; i<q[0].getNumChildren(); i++ ){
- if( !fma->isValidType( q[0][i].getType() ) ){
- quantValid = false;
- Trace("ambqi-inst") << "Interpretation of " << q << " is not valid because of type " << q[0][i].getType() << std::endl;
- break;
- }
- }
- if( quantValid ){
- Trace("ambqi-check") << "Compute interpretation..." << std::endl;
- AbsDef ad;
- doCheck( fma, q, ad, q[1] );
- //now process entries
- Trace("ambqi-inst-debug") << "...Current : " << d_addedLemmas << std::endl;
- Trace("ambqi-inst") << "Interpretation of " << q << " is : " << std::endl;
- ad.debugPrint( "ambqi-inst", fma, q[0] );
- Trace("ambqi-inst") << std::endl;
- Trace("ambqi-check") << "Add instantiations..." << std::endl;
- int lem = 0;
- quantValid = ad.addInstantiations( fma, d_qe, q, lem );
- Trace("ambqi-inst") << "...Added " << lem << " lemmas." << std::endl;
- if( lem>0 ){
- //if we were incomplete but added at least one lemma, we are ok
- quantValid = true;
- }
- d_addedLemmas += lem;
- Trace("ambqi-inst-debug") << "...Total : " << d_addedLemmas << std::endl;
- }
- return quantValid ? 1 : 0;
- }else{
- return 1;
- }
-}
-
-bool AbsMbqiBuilder::doCheck( FirstOrderModelAbs * m, TNode q, AbsDef & ad, TNode n ) {
- Assert( n.getKind()!=FORALL );
- if( n.getKind()==NOT && n[0].getKind()!=FORALL ){
- doCheck( m, q, ad, n[0] );
- ad.negate();
- return true;
- }else{
- std::map< unsigned, AbsDef > children;
- std::map< unsigned, int > bchildren;
- std::map< unsigned, int > vchildren;
- int varChCount = 0;
- for( unsigned i=0; i<n.getNumChildren(); i++ ){
- if( n[i].getKind()==FORALL ){
- bchildren[i] = AbsDef::val_unk;
- }else if( n[i].getKind() == BOUND_VARIABLE ){
- varChCount++;
- vchildren[i] = m->d_var_index[q][ m->getVariableId( q, n[i] ) ];
- //vchildren[i] = m->getVariableId( q, n[i] );
- }else if( m->hasTerm( n[i] ) ){
- bchildren[i] = m->getRepresentativeId( n[i] );
- }else{
- if( !doCheck( m, q, children[i], n[i] ) ){
- bchildren[i] = AbsDef::val_unk;
- children.erase( i );
- }
- }
- }
- //convert to pointers
- std::map< unsigned, AbsDef * > pchildren;
- for( std::map< unsigned, AbsDef >::iterator it = children.begin(); it != children.end(); ++it ){
- pchildren[it->first] = &it->second;
- }
- //construct the interpretation
- Trace("ambqi-check-debug") << "Compute Interpretation of " << n << " " << n.getKind() << std::endl;
- if( n.getKind() == APPLY_UF || n.getKind() == VARIABLE || n.getKind() == SKOLEM ){
- Node op;
- if( n.getKind() == APPLY_UF ){
- op = n.getOperator();
- }else{
- op = n;
- }
- //uninterpreted compose
- if( m->d_models_valid[op] ){
- ad.construct( m, q, n, m->d_models[op], pchildren, bchildren, vchildren, varChCount );
- }else{
- Trace("ambqi-check-debug") << "** Cannot produce interpretation for " << n << " (no function model)" << std::endl;
- return false;
- }
- }else if( !ad.construct( m, q, n, NULL, pchildren, bchildren, vchildren, varChCount ) ){
- Trace("ambqi-check-debug") << "** Cannot produce interpretation for " << n << " (variables are children of interpreted symbol)" << std::endl;
- return false;
- }
- Trace("ambqi-check-try") << "Interpretation for " << n << " is : " << std::endl;
- ad.debugPrint("ambqi-check-try", m, q[0] );
- ad.simplify( m, q, q[0] );
- Trace("ambqi-check-debug") << "(Simplified) Interpretation for " << n << " is : " << std::endl;
- ad.debugPrint("ambqi-check-debug", m, q[0] );
- Trace("ambqi-check-debug") << std::endl;
- return true;
- }
-}
-
-}/* namespace CVC4::theory::quantifiers */
-}/* namespace CVC4::theory */
-}/* namespace CVC4 */
diff --git a/src/theory/quantifiers/fmf/ambqi_builder.h b/src/theory/quantifiers/fmf/ambqi_builder.h
deleted file mode 100644
index b052e0985..000000000
--- a/src/theory/quantifiers/fmf/ambqi_builder.h
+++ /dev/null
@@ -1,105 +0,0 @@
-/********************* */
-/*! \file ambqi_builder.h
- ** \verbatim
- ** Top contributors (to current version):
- ** Andrew Reynolds, Tim King
- ** This file is part of the CVC4 project.
- ** Copyright (c) 2009-2018 by the authors listed in the file AUTHORS
- ** in the top-level source directory) and their institutional affiliations.
- ** All rights reserved. See the file COPYING in the top-level source
- ** directory for licensing information.\endverbatim
- **
- ** \brief Abstract MBQI model builder class
- **/
-
-#include "cvc4_private.h"
-
-#ifndef ABSTRACT_MBQI_BUILDER
-#define ABSTRACT_MBQI_BUILDER
-
-#include "theory/quantifiers/fmf/model_builder.h"
-#include "theory/quantifiers/first_order_model.h"
-
-namespace CVC4 {
-namespace theory {
-namespace quantifiers {
-
-class FirstOrderModelAbs;
-
-//representiation of function and term interpretations
-class AbsDef
-{
-private:
- bool addInstantiations( FirstOrderModelAbs * m, QuantifiersEngine * qe, TNode q, std::vector< Node >& terms, int& inst, unsigned depth );
- void construct_compose( FirstOrderModelAbs * m, TNode q, TNode n, AbsDef * f,
- std::map< unsigned, AbsDef * >& children,
- std::map< unsigned, int >& bchildren, std::map< unsigned, int >& vchildren,
- std::vector< unsigned >& entry, std::vector< bool >& entry_def );
- void construct_entry( std::vector< unsigned >& entry, std::vector< bool >& entry_def, int v, unsigned depth = 0 );
- void construct_def_entry( FirstOrderModelAbs * m, TNode q, TNode n, int v, unsigned depth = 0 );
- void apply_ucompose( FirstOrderModelAbs * m, TNode q,
- std::vector< unsigned >& entry, std::vector< bool >& entry_def, std::vector< int >& terms,
- std::map< unsigned, int >& vchildren, AbsDef * a, unsigned depth = 0 );
- void construct_var_eq( FirstOrderModelAbs * m, TNode q, unsigned v1, unsigned v2, int curr, int currv, unsigned depth = 0 );
- void construct_var( FirstOrderModelAbs * m, TNode q, unsigned v, int currv, unsigned depth = 0 );
- void get_defs( unsigned u, std::vector< AbsDef * >& defs );
- void construct_normalize( FirstOrderModelAbs * m, TNode q, std::vector< AbsDef * >& defs, unsigned depth = 0 );
-public:
- enum {
- val_none = -1,
- val_unk = -2,
- };
- AbsDef() : d_default( 0 ), d_value( -1 ){}
- std::map< unsigned, AbsDef > d_def;
- unsigned d_default;
- int d_value;
-
- void clear() { d_def.clear(); d_default = 0; d_value = -1; }
- AbsDef * getDefault() { return &d_def[d_default]; }
- void construct_func( FirstOrderModelAbs * m, std::vector< TNode >& fapps, unsigned depth = 0 );
- void debugPrintUInt( const char * c, unsigned dSize, unsigned u ) const;
- void debugPrint( const char * c, FirstOrderModelAbs * m, TNode f, unsigned depth = 0 ) const;
- void simplify( FirstOrderModelAbs * m, TNode q, TNode n, unsigned depth = 0 );
- int addInstantiations( FirstOrderModelAbs * m, QuantifiersEngine * qe, Node q, int& inst ){
- std::vector< Node > terms;
- terms.resize( q[0].getNumChildren() );
- return addInstantiations( m, qe, q, terms, inst, 0 );
- }
- bool construct( FirstOrderModelAbs * m, TNode q, TNode n, AbsDef * f,
- std::map< unsigned, AbsDef * >& children,
- std::map< unsigned, int >& bchildren,
- std::map< unsigned, int >& vchildren,
- int varChCount );
- void negate();
- Node getFunctionValue( FirstOrderModelAbs * m, TNode op, std::vector< Node >& vars, unsigned depth = 0 );
- static bool isSimple( unsigned n );
- static unsigned getId( unsigned n, unsigned start=0, unsigned end=32 );
- Node evaluate( FirstOrderModelAbs * m, TypeNode retType, std::vector< Node >& args );
- Node evaluate( FirstOrderModelAbs * m, TypeNode retType, std::vector< unsigned >& iargs, unsigned depth = 0 );
- //for debugging
- bool is_normalized();
-};
-
-class AbsMbqiBuilder : public QModelBuilder
-{
- friend class AbsDef;
-private:
- Node d_true;
- Node d_false;
- bool doCheck( FirstOrderModelAbs * m, TNode q, AbsDef & ad, TNode n );
-public:
- AbsMbqiBuilder( context::Context* c, QuantifiersEngine* qe );
-
- //process build model
- bool processBuildModel(TheoryModel* m) override;
- //do exhaustive instantiation
- int doExhaustiveInstantiation(FirstOrderModel* fm,
- Node q,
- int effort) override;
-};
-
-}
-}
-}
-
-#endif
diff --git a/src/theory/quantifiers/fmf/bounded_integers.cpp b/src/theory/quantifiers/fmf/bounded_integers.cpp
index 307ffeeed..cafa4a749 100644
--- a/src/theory/quantifiers/fmf/bounded_integers.cpp
+++ b/src/theory/quantifiers/fmf/bounded_integers.cpp
@@ -273,8 +273,9 @@ void BoundedIntegers::process( Node q, Node n, bool pol,
}
}
-bool BoundedIntegers::needsCheck( Theory::Effort e ) {
- return e==Theory::EFFORT_LAST_CALL;
+bool BoundedIntegers::needsCheck(Theory::Effort e)
+{
+ return e == Theory::EFFORT_LAST_CALL;
}
void BoundedIntegers::check(Theory::Effort e, QEffort quant_e)
diff --git a/src/theory/quantifiers/fmf/model_builder.cpp b/src/theory/quantifiers/fmf/model_builder.cpp
index c03fc7a32..8ef30fc4d 100644
--- a/src/theory/quantifiers/fmf/model_builder.cpp
+++ b/src/theory/quantifiers/fmf/model_builder.cpp
@@ -143,687 +143,3 @@ void QModelBuilder::debugModel( TheoryModel* m ){
}
}
}
-
-bool TermArgBasisTrie::addTerm(FirstOrderModel* fm, Node n, unsigned argIndex)
-{
- if (argIndex < n.getNumChildren())
- {
- Node r;
- if( n[ argIndex ].getAttribute(ModelBasisAttribute()) ){
- r = n[ argIndex ];
- }else{
- r = fm->getRepresentative( n[ argIndex ] );
- }
- std::map< Node, TermArgBasisTrie >::iterator it = d_data.find( r );
- if( it==d_data.end() ){
- d_data[r].addTerm(fm, n, argIndex + 1);
- return true;
- }else{
- return it->second.addTerm(fm, n, argIndex + 1);
- }
- }else{
- return false;
- }
-}
-
-void QModelBuilderIG::UfModelPreferenceData::setValuePreference(Node q,
- Node r,
- bool isPro)
-{
- if (std::find(d_values.begin(), d_values.end(), r) == d_values.end())
- {
- d_values.push_back(r);
- }
- int index = isPro ? 0 : 1;
- if (std::find(
- d_value_pro_con[index][r].begin(), d_value_pro_con[index][r].end(), q)
- == d_value_pro_con[index][r].end())
- {
- d_value_pro_con[index][r].push_back(q);
- }
-}
-
-Node QModelBuilderIG::UfModelPreferenceData::getBestDefaultValue(
- Node defaultTerm, TheoryModel* m)
-{
- Node defaultVal;
- double maxScore = -1;
- for (size_t i = 0, size = d_values.size(); i < size; i++)
- {
- Node v = d_values[i];
- double score = (1.0 + static_cast<double>(d_value_pro_con[0][v].size()))
- / (1.0 + static_cast<double>(d_value_pro_con[1][v].size()));
- Debug("fmf-model-cons-debug") << " - score( ";
- Debug("fmf-model-cons-debug") << m->getRepresentative(v);
- Debug("fmf-model-cons-debug") << " ) = " << score << std::endl;
- if (score > maxScore)
- {
- defaultVal = v;
- maxScore = score;
- }
- }
- if (maxScore < 1.0)
- {
- // consider finding another value, if possible
- Debug("fmf-model-cons-debug")
- << "Poor choice for default value, score = " << maxScore << std::endl;
- TypeNode tn = defaultTerm.getType();
- Node newDefaultVal = m->getRepSet()->getDomainValue(tn, d_values);
- if (!newDefaultVal.isNull())
- {
- defaultVal = newDefaultVal;
- Debug("fmf-model-cons-debug") << "-> Change default value to ";
- Debug("fmf-model-cons-debug") << m->getRepresentative(defaultVal);
- Debug("fmf-model-cons-debug") << std::endl;
- }
- else
- {
- Debug("fmf-model-cons-debug")
- << "-> Could not find arbitrary element of type "
- << tn[tn.getNumChildren() - 1] << std::endl;
- Debug("fmf-model-cons-debug") << " Excluding: " << d_values;
- Debug("fmf-model-cons-debug") << std::endl;
- }
- }
- // get the default term (this term must be defined non-ground in model)
- Debug("fmf-model-cons-debug") << " Choose ";
- Debug("fmf-model-cons-debug") << m->getRepresentative(defaultVal);
- Debug("fmf-model-cons-debug")
- << " as default value (" << defaultTerm << ")" << std::endl;
- Debug("fmf-model-cons-debug")
- << " # quantifiers pro = " << d_value_pro_con[0][defaultVal].size()
- << std::endl;
- Debug("fmf-model-cons-debug")
- << " # quantifiers con = " << d_value_pro_con[1][defaultVal].size()
- << std::endl;
- return defaultVal;
-}
-
-QModelBuilderIG::QModelBuilderIG(context::Context* c, QuantifiersEngine* qe)
- : QModelBuilder(c, qe),
- d_didInstGen(false),
- d_numQuantSat(0),
- d_numQuantInstGen(0),
- d_numQuantNoInstGen(0),
- d_numQuantNoSelForm(0),
- d_instGenMatches(0) {}
-
-/*
-Node QModelBuilderIG::getCurrentUfModelValue( FirstOrderModel* fm, Node n, std::vector< Node > & args, bool partial ) {
- return n;
-}
-*/
-
-bool QModelBuilderIG::processBuildModel( TheoryModel* m ) {
- if (!m->areFunctionValuesEnabled())
- {
- // nothing to do if no functions
- return true;
- }
- FirstOrderModel* f = (FirstOrderModel*)m;
- FirstOrderModelIG* fm = f->asFirstOrderModelIG();
- Trace("model-engine-debug") << "Process build model " << optUseModel() << std::endl;
- d_didInstGen = false;
- //reset the internal information
- reset( fm );
- //only construct first order model if optUseModel() is true
- if( optUseModel() ){
- Trace("model-engine-debug") << "Initializing " << fm->getNumAssertedQuantifiers() << " quantifiers..." << std::endl;
- //check if any quantifiers are un-initialized
- for( unsigned i=0; i<fm->getNumAssertedQuantifiers(); i++ ){
- Node q = fm->getAssertedQuantifier( i );
- if( d_qe->getModel()->isQuantifierActive( q ) ){
- int lems = initializeQuantifier(q, q, f);
- d_statistics.d_init_inst_gen_lemmas += lems;
- d_addedLemmas += lems;
- if( d_qe->inConflict() ){
- break;
- }
- }
- }
- if( d_addedLemmas>0 ){
- Trace("model-engine") << "Initialize, Added Lemmas = " << d_addedLemmas << std::endl;
- return false;
- }else{
- Assert( !d_qe->inConflict() );
- //initialize model
- fm->initialize();
- //analyze the functions
- Trace("model-engine-debug") << "Analyzing model..." << std::endl;
- analyzeModel( fm );
- //analyze the quantifiers
- Trace("model-engine-debug") << "Analyzing quantifiers..." << std::endl;
- d_uf_prefs.clear();
- for( unsigned i=0; i<fm->getNumAssertedQuantifiers(); i++ ){
- Node q = fm->getAssertedQuantifier( i );
- analyzeQuantifier( fm, q );
- }
-
- //if applicable, find exceptions to model via inst-gen
- if( options::fmfInstGen() ){
- d_didInstGen = true;
- d_instGenMatches = 0;
- d_numQuantSat = 0;
- d_numQuantInstGen = 0;
- d_numQuantNoInstGen = 0;
- d_numQuantNoSelForm = 0;
- //now, see if we know that any exceptions via InstGen exist
- Trace("model-engine-debug") << "Perform InstGen techniques for quantifiers..." << std::endl;
- for( unsigned i=0; i<fm->getNumAssertedQuantifiers(); i++ ){
- Node f = fm->getAssertedQuantifier( i );
- if( d_qe->getModel()->isQuantifierActive( f ) ){
- int lems = doInstGen( fm, f );
- d_statistics.d_inst_gen_lemmas += lems;
- d_addedLemmas += lems;
- //temporary
- if( lems>0 ){
- d_numQuantInstGen++;
- }else if( hasInstGen( f ) ){
- d_numQuantNoInstGen++;
- }else{
- d_numQuantNoSelForm++;
- }
- if( d_qe->inConflict() || ( options::fmfInstGenOneQuantPerRound() && lems>0 ) ){
- break;
- }
- }else{
- d_numQuantSat++;
- }
- }
- Trace("model-engine-debug") << "Quantifiers sat/ig/n-ig/null " << d_numQuantSat << " / " << d_numQuantInstGen << " / ";
- Trace("model-engine-debug") << d_numQuantNoInstGen << " / " << d_numQuantNoSelForm << std::endl;
- Trace("model-engine-debug") << "Inst-gen # matches examined = " << d_instGenMatches << std::endl;
- if( Trace.isOn("model-engine") ){
- if( d_addedLemmas>0 ){
- Trace("model-engine") << "InstGen, added lemmas = " << d_addedLemmas << std::endl;
- }else{
- Trace("model-engine") << "No InstGen lemmas..." << std::endl;
- }
- }
- }
- //construct the model if necessary
- if( d_addedLemmas==0 ){
- //if no immediate exceptions, build the model
- // this model will be an approximation that will need to be tested via exhaustive instantiation
- Trace("model-engine-debug") << "Building model..." << std::endl;
- //build model for UF
- for( std::map< Node, uf::UfModelTree >::iterator it = fm->d_uf_model_tree.begin(); it != fm->d_uf_model_tree.end(); ++it ){
- Trace("model-engine-debug-uf") << "Building model for " << it->first << "..." << std::endl;
- constructModelUf( fm, it->first );
- }
- Trace("model-engine-debug") << "Done building models." << std::endl;
- }else{
- return false;
- }
- }
- }
- //update models
- for( std::map< Node, uf::UfModelTree >::iterator it = fm->d_uf_model_tree.begin(); it != fm->d_uf_model_tree.end(); ++it ){
- it->second.update( fm );
- Trace("model-func") << "QModelBuilder: Make function value from tree " << it->first << std::endl;
- //construct function values
- Node f_def = it->second.getFunctionValue( "$x" );
- fm->assignFunctionDefinition( it->first, f_def );
- }
- Assert( d_addedLemmas==0 );
- return TheoryEngineModelBuilder::processBuildModel( m );
-}
-
-int QModelBuilderIG::initializeQuantifier(Node f, Node fp, FirstOrderModel* fm)
-{
- if( d_quant_basis_match_added.find( f )==d_quant_basis_match_added.end() ){
- //create the basis match if necessary
- if( d_quant_basis_match.find( f )==d_quant_basis_match.end() ){
- Trace("inst-fmf-init") << "Initialize " << f << std::endl;
- //add the model basis instantiation
- // This will help produce the necessary information for model completion.
- // We do this by extending distinguish ground assertions (those
- // containing terms with "model basis" attribute) to hold for all cases.
-
- ////first, check if any variables are required to be equal
- //for( std::map< Node, bool >::iterator it = d_quantEngine->d_phase_reqs[f].begin();
- // it != d_quantEngine->d_phase_reqs[f].end(); ++it ){
- // Node n = it->first;
- // if( n.getKind()==EQUAL && n[0].getKind()==INST_CONSTANT && n[1].getKind()==INST_CONSTANT ){
- // Notice() << "Unhandled phase req: " << n << std::endl;
- // }
- //}
- d_quant_basis_match[f] = InstMatch( f );
- for (unsigned j = 0; j < f[0].getNumChildren(); j++)
- {
- Node t = fm->getModelBasisTerm(f[0][j].getType());
- //calculate the basis match for f
- d_quant_basis_match[f].setValue( j, t );
- }
- ++(d_statistics.d_num_quants_init);
- }
- //try to add it
- Trace("inst-fmf-init") << "Init: try to add match " << d_quant_basis_match[f] << std::endl;
- //add model basis instantiation
- if (d_qe->getInstantiate()->addInstantiation(fp, d_quant_basis_match[f]))
- {
- 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;
-}
-
-void QModelBuilderIG::analyzeModel( FirstOrderModel* fm ){
- FirstOrderModelIG* fmig = fm->asFirstOrderModelIG();
- d_uf_model_constructed.clear();
- //determine if any functions are constant
- for( std::map< Node, uf::UfModelTree >::iterator it = fmig->d_uf_model_tree.begin(); it != fmig->d_uf_model_tree.end(); ++it ){
- Node op = it->first;
- std::map< Node, std::vector< Node > >::iterator itut = fmig->d_uf_terms.find( op );
- if( itut!=fmig->d_uf_terms.end() ){
- for( size_t i=0; i<itut->second.size(); i++ ){
- Node n = fmig->d_uf_terms[op][i];
- //for calculating if op is constant
- Node v = fmig->getRepresentative( n );
- if( i==0 ){
- d_uf_prefs[op].d_const_val = v;
- }else if( v!=d_uf_prefs[op].d_const_val ){
- d_uf_prefs[op].d_const_val = Node::null();
- break;
- }
- }
- }
- if( !d_uf_prefs[op].d_const_val.isNull() ){
- fmig->d_uf_model_gen[op].setDefaultValue( d_uf_prefs[op].d_const_val );
- fmig->d_uf_model_gen[op].makeModel( fmig, it->second );
- Debug("fmf-model-cons") << "Function " << op << " is the constant function ";
- Debug("fmf-model-cons") << d_uf_prefs[op].d_const_val;
- Debug("fmf-model-cons") << std::endl;
- d_uf_model_constructed[op] = true;
- }else{
- d_uf_model_constructed[op] = false;
- }
- }
-}
-
-bool QModelBuilderIG::hasConstantDefinition( Node n ){
- Node lit = n.getKind()==NOT ? n[0] : n;
- if( lit.getKind()==APPLY_UF ){
- Node op = lit.getOperator();
- if( !d_uf_prefs[op].d_const_val.isNull() ){
- return true;
- }
- }
- return false;
-}
-
-QModelBuilderIG::Statistics::Statistics()
- : d_num_quants_init("QModelBuilderIG::Number_Quantifiers", 0),
- d_num_partial_quants_init("QModelBuilderIG::Number_Partial_Quantifiers",
- 0),
- d_init_inst_gen_lemmas("QModelBuilderIG::Initialize_Inst_Gen_Lemmas", 0),
- d_inst_gen_lemmas("QModelBuilderIG::Inst_Gen_Lemmas", 0)
-{
- smtStatisticsRegistry()->registerStat(&d_num_quants_init);
- smtStatisticsRegistry()->registerStat(&d_num_partial_quants_init);
- smtStatisticsRegistry()->registerStat(&d_init_inst_gen_lemmas);
- smtStatisticsRegistry()->registerStat(&d_inst_gen_lemmas);
-}
-
-QModelBuilderIG::Statistics::~Statistics(){
- smtStatisticsRegistry()->unregisterStat(&d_num_quants_init);
- smtStatisticsRegistry()->unregisterStat(&d_num_partial_quants_init);
- smtStatisticsRegistry()->unregisterStat(&d_init_inst_gen_lemmas);
- smtStatisticsRegistry()->unregisterStat(&d_inst_gen_lemmas);
-}
-
-//do exhaustive instantiation
-int QModelBuilderIG::doExhaustiveInstantiation( FirstOrderModel * fm, Node f, int effort ) {
- if( optUseModel() ){
- QRepBoundExt qrbe(d_qe);
- RepSetIterator riter(d_qe->getModel()->getRepSet(), &qrbe);
- if( riter.setQuantifier( f ) ){
- FirstOrderModelIG * fmig = (FirstOrderModelIG*)d_qe->getModel();
- Debug("inst-fmf-ei") << "Reset evaluate..." << std::endl;
- fmig->resetEvaluate();
- Debug("inst-fmf-ei") << "Begin instantiation..." << std::endl;
- EqualityQuery* qy = d_qe->getEqualityQuery();
- Instantiate* inst = d_qe->getInstantiate();
- TermUtil* util = d_qe->getTermUtil();
- while( !riter.isFinished() && ( d_addedLemmas==0 || !options::fmfOneInstPerRound() ) ){
- d_triedLemmas++;
- if( Debug.isOn("inst-fmf-ei-debug") ){
- for( int i=0; i<(int)riter.d_index.size(); i++ ){
- Debug("inst-fmf-ei-debug") << i << " : " << riter.d_index[i] << " : " << riter.getCurrentTerm( i ) << std::endl;
- }
- }
- int eval = 0;
- int depIndex;
- //see if instantiation is already true in current model
- if( Debug.isOn("fmf-model-eval") ){
- Debug("fmf-model-eval") << "Evaluating ";
- riter.debugPrintSmall("fmf-model-eval");
- Debug("fmf-model-eval") << "Done calculating terms." << std::endl;
- }
- //if evaluate(...)==1, then the instantiation is already true in the model
- // depIndex is the index of the least significant variable that this evaluation relies upon
- depIndex = riter.getNumTerms()-1;
- Debug("fmf-model-eval") << "We will evaluate "
- << util->getInstConstantBody(f) << std::endl;
- eval = fmig->evaluate(util->getInstConstantBody(f), depIndex, &riter);
- if( eval==1 ){
- Debug("fmf-model-eval") << " Returned success with depIndex = " << depIndex << std::endl;
- }else{
- Debug("fmf-model-eval") << " Returned " << (eval==-1 ? "failure" : "unknown") << ", depIndex = " << depIndex << std::endl;
- }
- if( eval==1 ){
- //instantiation is already true -> skip
- riter.incrementAtIndex(depIndex);
- }else{
- //instantiation was not shown to be true, construct the match
- InstMatch m( f );
- for (unsigned i = 0; i < riter.getNumTerms(); i++)
- {
- m.set(qy, i, riter.getCurrentTerm(i));
- }
- Debug("fmf-model-eval") << "* Add instantiation " << m << std::endl;
- //add as instantiation
- if (inst->addInstantiation(f, m, true))
- {
- d_addedLemmas++;
- if( d_qe->inConflict() ){
- break;
- }
- //if the instantiation is show to be false, and we wish to skip multiple instantiations at once
- if( eval==-1 ){
- riter.incrementAtIndex(depIndex);
- }else{
- riter.increment();
- }
- }else{
- Debug("fmf-model-eval") << "* Failed Add instantiation " << m << std::endl;
- riter.increment();
- }
- }
- }
- //print debugging information
- 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 ){
- Trace("model-engine-warn") << "WARNING: many instantiations produced for " << f << ": " << std::endl;
- Trace("model-engine-warn") << " Inst Tried: " << d_triedLemmas << std::endl;
- Trace("model-engine-warn") << " Inst Added: " << d_addedLemmas << std::endl;
- Trace("model-engine-warn") << std::endl;
- }
- }
- //if the iterator is incomplete, we will return unknown instead of sat if no instantiations are added this round
- return riter.isIncomplete() ? -1 : 1;
- }else{
- return 0;
- }
-}
-
-
-
-void QModelBuilderDefault::reset( FirstOrderModel* fm ){
- d_quant_selection_lit.clear();
- d_quant_selection_lit_candidates.clear();
- d_quant_selection_lit_terms.clear();
- d_term_selection_lit.clear();
- d_op_selection_terms.clear();
-}
-
-
-int QModelBuilderDefault::getSelectionScore( std::vector< Node >& uf_terms ) {
- /*
- size_t maxChildren = 0;
- for( size_t i=0; i<uf_terms.size(); i++ ){
- if( uf_terms[i].getNumChildren()>maxChildren ){
- maxChildren = uf_terms[i].getNumChildren();
- }
- }
- //TODO: look at how many entries they have?
- return (int)maxChildren;
- */
- return 0;
-}
-
-void QModelBuilderDefault::analyzeQuantifier( FirstOrderModel* fm, Node f ){
- if( d_qe->getModel()->isQuantifierActive( f ) ){
- FirstOrderModelIG* fmig = fm->asFirstOrderModelIG();
- Debug("fmf-model-prefs") << "Analyze quantifier " << f << std::endl;
- //the pro/con preferences for this quantifier
- std::vector< Node > pro_con[2];
- //the terms in the selection literal we choose
- std::vector< Node > selectionLitTerms;
- Trace("inst-gen-debug-quant") << "Inst-gen analyze " << f << std::endl;
- //for each asserted quantifier f,
- // - determine selection literals
- // - check which function/predicates have good and bad definitions for satisfying f
- if( d_phase_reqs.find( f )==d_phase_reqs.end() ){
- d_phase_reqs[f].initialize( d_qe->getTermUtil()->getInstConstantBody( f ), true );
- }
- int selectLitScore = -1;
- for( std::map< Node, bool >::iterator it = d_phase_reqs[f].d_phase_reqs.begin(); it != d_phase_reqs[f].d_phase_reqs.end(); ++it ){
- //the literal n is phase-required for quantifier f
- Node n = it->first;
- Node gn = fm->getModelBasis(f, n);
- Debug("fmf-model-req") << " Req: " << n << " -> " << it->second << std::endl;
- bool value;
- //if the corresponding ground abstraction literal has a SAT value
- if( d_qe->getValuation().hasSatValue( gn, value ) ){
- //collect the non-ground uf terms that this literal contains
- // and compute if all of the symbols in this literal have
- // constant definitions.
- bool isConst = true;
- std::vector< Node > uf_terms;
- if( TermUtil::hasInstConstAttr(n) ){
- isConst = false;
- if( gn.getKind()==APPLY_UF ){
- uf_terms.push_back( gn );
- isConst = hasConstantDefinition( gn );
- }else if( gn.getKind()==EQUAL ){
- isConst = true;
- for( int j=0; j<2; j++ ){
- if( TermUtil::hasInstConstAttr(n[j]) ){
- if( n[j].getKind()==APPLY_UF &&
- fmig->d_uf_model_tree.find( gn[j].getOperator() )!=fmig->d_uf_model_tree.end() ){
- uf_terms.push_back( gn[j] );
- isConst = isConst && hasConstantDefinition( gn[j] );
- }else{
- isConst = false;
- }
- }
- }
- }
- }
- //check if the value in the SAT solver matches the preference according to the quantifier
- int pref = 0;
- if( value!=it->second ){
- //we have a possible selection literal
- bool selectLit = d_quant_selection_lit[f].isNull();
- bool selectLitConstraints = true;
- //it is a constantly defined selection literal : the quantifier is sat
- if( isConst ){
- selectLit = selectLit || d_qe->getModel()->isQuantifierActive( f );
- d_qe->getModel()->setQuantifierActive( f, false );
- //check if choosing this literal would add any additional constraints to default definitions
- selectLitConstraints = false;
- selectLit = true;
- }
- //also check if it is naturally a better literal
- if( !selectLit ){
- int score = getSelectionScore( uf_terms );
- //Trace("inst-gen-debug") << "Check " << score << " < " << selectLitScore << std::endl;
- selectLit = score<selectLitScore;
- }
- //see if we wish to choose this as a selection literal
- d_quant_selection_lit_candidates[f].push_back( value ? n : n.notNode() );
- if( selectLit ){
- selectLitScore = getSelectionScore( uf_terms );
- Trace("inst-gen-debug") << "Choose selection literal " << gn << std::endl;
- Trace("inst-gen-debug") << " flags: " << isConst << " " << selectLitConstraints << " " << selectLitScore << std::endl;
- d_quant_selection_lit[f] = value ? n : n.notNode();
- selectionLitTerms.clear();
- selectionLitTerms.insert( selectionLitTerms.begin(), uf_terms.begin(), uf_terms.end() );
- if( !selectLitConstraints ){
- break;
- }
- }
- pref = 1;
- }else{
- pref = -1;
- }
- //if we are not yet SAT, so we will add to preferences
- if( d_qe->getModel()->isQuantifierActive( f ) ){
- Debug("fmf-model-prefs") << " It is " << ( pref==1 ? "pro" : "con" );
- Debug("fmf-model-prefs") << " the definition of " << n << std::endl;
- for( int j=0; j<(int)uf_terms.size(); j++ ){
- pro_con[ pref==1 ? 0 : 1 ].push_back( uf_terms[j] );
- }
- }
- }
- }
- //process information about selection literal for f
- if( !d_quant_selection_lit[f].isNull() ){
- d_quant_selection_lit_terms[f].insert( d_quant_selection_lit_terms[f].begin(), selectionLitTerms.begin(), selectionLitTerms.end() );
- for( int i=0; i<(int)selectionLitTerms.size(); i++ ){
- d_term_selection_lit[ selectionLitTerms[i] ] = d_quant_selection_lit[f];
- d_op_selection_terms[ selectionLitTerms[i].getOperator() ].push_back( selectionLitTerms[i] );
- }
- }else{
- Trace("inst-gen-warn") << "WARNING: " << f << " has no selection literals" << std::endl;
- }
- //process information about requirements and preferences of quantifier f
- if( !d_qe->getModel()->isQuantifierActive( f ) ){
- Debug("fmf-model-prefs") << " * Constant SAT due to definition of ops: ";
- for( int i=0; i<(int)selectionLitTerms.size(); i++ ){
- Debug("fmf-model-prefs") << selectionLitTerms[i] << " ";
- }
- Debug("fmf-model-prefs") << std::endl;
- }else{
- //note quantifier's value preferences to models
- for( int k=0; k<2; k++ ){
- for( int j=0; j<(int)pro_con[k].size(); j++ ){
- Node op = pro_con[k][j].getOperator();
- Node r = fmig->getRepresentative( pro_con[k][j] );
- d_uf_prefs[op].setValuePreference(f, r, k == 0);
- }
- }
- }
- }
-}
-
-int QModelBuilderDefault::doInstGen( FirstOrderModel* fm, Node f ){
- int addedLemmas = 0;
- //we wish to add all known exceptions to our selection literal for f. this will help to refine our current model.
- //This step is advantageous over exhaustive instantiation, since we are adding instantiations that involve model basis terms,
- // effectively acting as partial instantiations instead of pointwise instantiations.
- if( !d_quant_selection_lit[f].isNull() ){
- Trace("inst-gen") << "Do Inst-Gen for " << f << std::endl;
- for( size_t i=0; i<d_quant_selection_lit_candidates[f].size(); i++ ){
- bool phase = d_quant_selection_lit_candidates[f][i].getKind()!=NOT;
- Node lit = d_quant_selection_lit_candidates[f][i].getKind()==NOT ? d_quant_selection_lit_candidates[f][i][0] : d_quant_selection_lit_candidates[f][i];
- Assert( TermUtil::hasInstConstAttr(lit) );
- std::vector< Node > tr_terms;
- if( lit.getKind()==APPLY_UF ){
- //only match predicates that are contrary to this one, use literal matching
- Node eq = NodeManager::currentNM()->mkNode(
- EQUAL, lit, NodeManager::currentNM()->mkConst(!phase));
- tr_terms.push_back( eq );
- }else if( lit.getKind()==EQUAL ){
- //collect trigger terms
- for( int j=0; j<2; j++ ){
- if( TermUtil::hasInstConstAttr(lit[j]) ){
- if( lit[j].getKind()==APPLY_UF ){
- tr_terms.push_back( lit[j] );
- }else{
- tr_terms.clear();
- break;
- }
- }
- }
- if( tr_terms.size()==1 && !phase ){
- //equality between a function and a ground term, use literal matching
- tr_terms.clear();
- tr_terms.push_back( lit );
- }
- }
- //if applicable, try to add exceptions here
- if( !tr_terms.empty() ){
- //make a trigger for these terms, add instantiations
- inst::Trigger* tr = inst::Trigger::mkTrigger( d_qe, f, tr_terms, true, inst::Trigger::TR_MAKE_NEW );
- //Notice() << "Trigger = " << (*tr) << std::endl;
- tr->resetInstantiationRound();
- tr->reset( Node::null() );
- //d_qe->d_optInstMakeRepresentative = false;
- //d_qe->d_optMatchIgnoreModelBasis = true;
- addedLemmas += tr->addInstantiations();
- }
- }
- }
- return addedLemmas;
-}
-
-void QModelBuilderDefault::constructModelUf( FirstOrderModel* fm, Node op ){
- FirstOrderModelIG* fmig = fm->asFirstOrderModelIG();
- if( !d_uf_model_constructed[op] ){
- //construct the model for the uninterpretted function/predicate
- bool setDefaultVal = true;
- Node defaultTerm = fmig->getModelBasisOpTerm(op);
- Trace("fmf-model-cons") << "Construct model for " << op << "..." << std::endl;
- //set the values in the model
- std::map< Node, std::vector< Node > >::iterator itut = fmig->d_uf_terms.find( op );
- if( itut!=fmig->d_uf_terms.end() ){
- for( size_t i=0; i<itut->second.size(); i++ ){
- Node n = itut->second[i];
- // only consider unique up to congruence (in model equality engine)?
- Node v = fmig->getRepresentative( n );
- Trace("fmf-model-cons") << "Set term " << n << " : "
- << fmig->getRepSet()->getIndexFor(v) << " " << v
- << std::endl;
- //if this assertion did not help the model, just consider it ground
- //set n = v in the model tree
- //set it as ground value
- fmig->d_uf_model_gen[op].setValue( fm, n, v );
- // also set as default value if necessary
- if (n.hasAttribute(ModelBasisArgAttribute())
- && n.getAttribute(ModelBasisArgAttribute()) != 0)
- {
- Trace("fmf-model-cons") << " Set as default." << std::endl;
- fmig->d_uf_model_gen[op].setValue(fm, n, v, false);
- if( n==defaultTerm ){
- //incidentally already set, we will not need to find a default value
- setDefaultVal = false;
- }
- }
- }
- }
- //set the overall default value if not set already (is this necessary??)
- if( setDefaultVal ){
- Trace("fmf-model-cons") << " Choose default value..." << std::endl;
- //chose defaultVal based on heuristic, currently the best ratio of "pro" responses
- Node defaultVal = d_uf_prefs[op].getBestDefaultValue( defaultTerm, fm );
- if( defaultVal.isNull() ){
- if (!fmig->getRepSet()->hasType(defaultTerm.getType()))
- {
- Node mbt = fmig->getModelBasisTerm(defaultTerm.getType());
- fmig->getRepSetPtr()->d_type_reps[defaultTerm.getType()].push_back(
- mbt);
- }
- defaultVal =
- fmig->getRepSet()->getRepresentative(defaultTerm.getType(), 0);
- }
- Assert( !defaultVal.isNull() );
- Trace("fmf-model-cons")
- << "Set default term : " << fmig->getRepSet()->getIndexFor(defaultVal)
- << std::endl;
- fmig->d_uf_model_gen[op].setValue( fm, defaultTerm, defaultVal, false );
- }
- Debug("fmf-model-cons") << " Making model...";
- fmig->d_uf_model_gen[op].makeModel( fm, fmig->d_uf_model_tree[op] );
- d_uf_model_constructed[op] = true;
- Debug("fmf-model-cons") << " Finished constructing model for " << op << "." << std::endl;
- }
-}
diff --git a/src/theory/quantifiers/fmf/model_builder.h b/src/theory/quantifiers/fmf/model_builder.h
index b34f1e580..b73716169 100644
--- a/src/theory/quantifiers/fmf/model_builder.h
+++ b/src/theory/quantifiers/fmf/model_builder.h
@@ -56,163 +56,6 @@ public:
unsigned getNumTriedLemmas() { return d_triedLemmas; }
};
-class TermArgBasisTrie {
-public:
- /** the data */
- std::map< Node, TermArgBasisTrie > d_data;
- /** add term to the trie */
- bool addTerm(FirstOrderModel* fm, Node n, unsigned argIndex = 0);
-};/* class TermArgBasisTrie */
-
-/** model builder class
- * This class is capable of building candidate models based on the current quantified formulas
- * that are asserted. Use:
- * (1) call QModelBuilder::buildModel( m, false );, where m is a FirstOrderModel
- * (2) if candidate model is determined to be a real model,
- then call QModelBuilder::buildModel( m, true );
- */
-class QModelBuilderIG : public QModelBuilder
-{
- typedef context::CDHashMap<Node, bool, NodeHashFunction> BoolMap;
-
- protected:
- /**
- * This class stores temporary information useful to model engine for
- * constructing models for uninterpreted functions.
- */
- class UfModelPreferenceData
- {
- public:
- UfModelPreferenceData() {}
- virtual ~UfModelPreferenceData() {}
- /** any constant value of the type */
- Node d_const_val;
- /** list of possible default values */
- std::vector<Node> d_values;
- /**
- * Map from values to the set of quantified formulas that are (pro, con)
- * that value. A quantified formula may be "pro" a particular default
- * value of an uninterpreted function if that value is likely to satisfy
- * many points in its domain. For example, forall x. P( f( x ) ) may be
- * "pro" the default value true for P.
- */
- std::map<Node, std::vector<Node> > d_value_pro_con[2];
- /** set that quantified formula q is pro/con the default value of r */
- void setValuePreference(Node q, Node r, bool isPro);
- /** get best default value */
- Node getBestDefaultValue(Node defaultTerm, TheoryModel* m);
- };
- /** map from operators to model preference data */
- std::map<Node, UfModelPreferenceData> d_uf_prefs;
- //built model uf
- std::map< Node, bool > d_uf_model_constructed;
- //whether inst gen was done
- bool d_didInstGen;
- /** process build model */
- bool processBuildModel(TheoryModel* m) override;
-
- protected:
- //reset
- virtual void reset( FirstOrderModel* fm ) = 0;
- //initialize quantifiers, return number of lemmas produced
- virtual int initializeQuantifier(Node f, Node fp, FirstOrderModel* fm);
- //analyze model
- virtual void analyzeModel( FirstOrderModel* fm );
- //analyze quantifiers
- virtual void analyzeQuantifier( FirstOrderModel* fm, Node f ) = 0;
- //do InstGen techniques for quantifier, return number of lemmas produced
- virtual int doInstGen( FirstOrderModel* fm, Node f ) = 0;
- //theory-specific build models
- virtual void constructModelUf( FirstOrderModel* fm, Node op ) = 0;
-
- protected:
- //map from quantifiers to if are SAT
- //std::map< Node, bool > d_quant_sat;
- //which quantifiers have been initialized
- std::map< Node, bool > d_quant_basis_match_added;
- //map from quantifiers to model basis match
- std::map< Node, InstMatch > d_quant_basis_match;
-
- protected: // helper functions
- /** term has constant definition */
- bool hasConstantDefinition( Node n );
-
- public:
- QModelBuilderIG( context::Context* c, QuantifiersEngine* qe );
-
- public:
- /** statistics class */
- class Statistics {
- public:
- IntStat d_num_quants_init;
- IntStat d_num_partial_quants_init;
- IntStat d_init_inst_gen_lemmas;
- IntStat d_inst_gen_lemmas;
- Statistics();
- ~Statistics();
- };
- Statistics d_statistics;
- // is term selected
- virtual bool isTermSelected( Node n ) { return false; }
- /** quantifier has inst-gen definition */
- virtual bool hasInstGen( Node f ) = 0;
- /** did inst gen this round? */
- bool didInstGen() { return d_didInstGen; }
- // is quantifier active?
- bool isQuantifierActive( Node f );
- //do exhaustive instantiation
- int doExhaustiveInstantiation(FirstOrderModel* fm,
- Node f,
- int effort) override;
-
- //temporary stats
- int d_numQuantSat;
- int d_numQuantInstGen;
- int d_numQuantNoInstGen;
- int d_numQuantNoSelForm;
- //temporary stat
- int d_instGenMatches;
-};/* class QModelBuilder */
-
-
-class QModelBuilderDefault : public QModelBuilderIG
-{
- private: /// information for (old) InstGen
- // map from quantifiers to their selection literals
- std::map< Node, Node > d_quant_selection_lit;
- std::map< Node, std::vector< Node > > d_quant_selection_lit_candidates;
- //map from quantifiers to their selection literal terms
- std::map< Node, std::vector< Node > > d_quant_selection_lit_terms;
- //map from terms to the selection literals they exist in
- std::map< Node, Node > d_term_selection_lit;
- //map from operators to terms that appear in selection literals
- std::map< Node, std::vector< Node > > d_op_selection_terms;
- //get selection score
- int getSelectionScore( std::vector< Node >& uf_terms );
-
- protected:
- //reset
- void reset(FirstOrderModel* fm) override;
- //analyze quantifier
- void analyzeQuantifier(FirstOrderModel* fm, Node f) override;
- //do InstGen techniques for quantifier, return number of lemmas produced
- int doInstGen(FirstOrderModel* fm, Node f) override;
- //theory-specific build models
- void constructModelUf(FirstOrderModel* fm, Node op) override;
-
- protected:
- std::map< Node, QuantPhaseReq > d_phase_reqs;
-
- public:
- QModelBuilderDefault( context::Context* c, QuantifiersEngine* qe ) : QModelBuilderIG( c, qe ){}
-
- //has inst gen
- bool hasInstGen(Node f) override
- {
- return !d_quant_selection_lit[f].isNull();
- }
-};
-
}/* CVC4::theory::quantifiers namespace */
}/* CVC4::theory namespace */
}/* CVC4 namespace */
diff --git a/src/theory/quantifiers/fmf/model_engine.cpp b/src/theory/quantifiers/fmf/model_engine.cpp
index 81ecf9e77..d2579b4ee 100644
--- a/src/theory/quantifiers/fmf/model_engine.cpp
+++ b/src/theory/quantifiers/fmf/model_engine.cpp
@@ -15,7 +15,6 @@
#include "theory/quantifiers/fmf/model_engine.h"
#include "options/quantifiers_options.h"
-#include "theory/quantifiers/fmf/ambqi_builder.h"
#include "theory/quantifiers/first_order_model.h"
#include "theory/quantifiers/fmf/full_model_check.h"
#include "theory/quantifiers/instantiate.h"
diff --git a/src/theory/quantifiers/sygus/ce_guided_single_inv.cpp b/src/theory/quantifiers/sygus/ce_guided_single_inv.cpp
index d4735b3d8..aa20c1f76 100644
--- a/src/theory/quantifiers/sygus/ce_guided_single_inv.cpp
+++ b/src/theory/quantifiers/sygus/ce_guided_single_inv.cpp
@@ -138,159 +138,195 @@ void CegSingleInv::initialize(Node q)
}
}
// compute single invocation partition
- if( options::cegqiSingleInvMode()!=CEGQI_SI_MODE_NONE ){
- Node qq;
- if( q[1].getKind()==NOT && q[1][0].getKind()==FORALL ){
- qq = q[1][0][1];
- }else{
- qq = TermUtil::simpleNegate( q[1] );
- }
- //process the single invocation-ness of the property
- if( !d_sip->init( progs, qq ) ){
- Trace("cegqi-si") << "...not single invocation (type mismatch)" << std::endl;
- }else{
- Trace("cegqi-si") << "- Partitioned to single invocation parts : " << std::endl;
- d_sip->debugPrint( "cegqi-si" );
+ Node qq;
+ if (q[1].getKind() == NOT && q[1][0].getKind() == FORALL)
+ {
+ qq = q[1][0][1];
+ }
+ else
+ {
+ qq = TermUtil::simpleNegate(q[1]);
+ }
+ // process the single invocation-ness of the property
+ if (!d_sip->init(progs, qq))
+ {
+ Trace("cegqi-si") << "...not single invocation (type mismatch)"
+ << std::endl;
+ return;
+ }
+ Trace("cegqi-si") << "- Partitioned to single invocation parts : "
+ << std::endl;
+ d_sip->debugPrint("cegqi-si");
+
+ // map from program to bound variables
+ std::vector<Node> funcs;
+ d_sip->getFunctions(funcs);
+ for (unsigned j = 0, size = funcs.size(); j < size; j++)
+ {
+ Assert(std::find(progs.begin(), progs.end(), funcs[j]) != progs.end());
+ d_prog_to_sol_index[funcs[j]] = j;
+ }
- //map from program to bound variables
- std::vector<Node> funcs;
- d_sip->getFunctions(funcs);
- for (unsigned j = 0, size = funcs.size(); j < size; j++)
+ // check if it is single invocation
+ if (d_sip->isPurelySingleInvocation())
+ {
+ // We are fully single invocation, set single invocation if we haven't
+ // disabled single invocation techniques.
+ if (options::cegqiSingleInvMode() != CEGQI_SI_MODE_NONE)
+ {
+ d_single_invocation = true;
+ return;
+ }
+ }
+ // We are processing without single invocation techniques, now check if
+ // we should fix an invariant template (post-condition strengthening or
+ // pre-condition weakening).
+ SygusInvTemplMode tmode = options::sygusInvTemplMode();
+ if (tmode != SYGUS_INV_TEMPL_MODE_NONE)
+ {
+ // currently only works for single predicate synthesis
+ if (q[0].getNumChildren() > 1 || !q[0][0].getType().isPredicate())
+ {
+ tmode = SYGUS_INV_TEMPL_MODE_NONE;
+ }
+ else if (!options::sygusInvTemplWhenSyntax())
+ {
+ // only use invariant templates if no syntactic restrictions
+ if (CegGrammarConstructor::hasSyntaxRestrictions(q))
{
- Assert(std::find(progs.begin(), progs.end(), funcs[j]) != progs.end());
- d_prog_to_sol_index[funcs[j]] = j;
+ tmode = SYGUS_INV_TEMPL_MODE_NONE;
}
+ }
+ }
+
+ if (tmode == SYGUS_INV_TEMPL_MODE_NONE)
+ {
+ // not processing invariant templates
+ return;
+ }
+ // if we are doing invariant templates, then construct the template
+ Trace("cegqi-si") << "- Do transition inference..." << std::endl;
+ d_ti[q].process(qq);
+ Trace("cegqi-inv") << std::endl;
+ if (d_ti[q].d_func.isNull())
+ {
+ // the invariant could not be inferred
+ return;
+ }
+ NodeManager* nm = NodeManager::currentNM();
+ // map the program back via non-single invocation map
+ Node prog = d_ti[q].d_func;
+ std::vector<Node> prog_templ_vars;
+ prog_templ_vars.insert(
+ prog_templ_vars.end(), d_ti[q].d_vars.begin(), d_ti[q].d_vars.end());
+ d_trans_pre[prog] = d_ti[q].getComponent(1);
+ d_trans_post[prog] = d_ti[q].getComponent(-1);
+ Trace("cegqi-inv") << " precondition : " << d_trans_pre[prog] << std::endl;
+ Trace("cegqi-inv") << " postcondition : " << d_trans_post[prog] << std::endl;
+ std::vector<Node> sivars;
+ d_sip->getSingleInvocationVariables(sivars);
+ Node invariant = d_sip->getFunctionInvocationFor(prog);
+ Assert(!invariant.isNull());
+ invariant = invariant.substitute(sivars.begin(),
+ sivars.end(),
+ prog_templ_vars.begin(),
+ prog_templ_vars.end());
+ Trace("cegqi-inv") << " invariant : " << invariant << std::endl;
- //check if it is single invocation
- if (!d_sip->isPurelySingleInvocation())
+ // store simplified version of quantified formula
+ d_simp_quant = d_sip->getFullSpecification();
+ std::vector<Node> new_bv;
+ for( const Node& v : sivars )
+ {
+ new_bv.push_back(nm->mkBoundVar(v.getType()));
+ }
+ d_simp_quant = d_simp_quant.substitute(
+ sivars.begin(), sivars.end(), new_bv.begin(), new_bv.end());
+ Assert(q[1].getKind() == NOT && q[1][0].getKind() == FORALL);
+ for (const Node& v : q[1][0][0])
+ {
+ new_bv.push_back(v);
+ }
+ d_simp_quant =
+ nm->mkNode(FORALL, nm->mkNode(BOUND_VAR_LIST, new_bv), d_simp_quant)
+ .negate();
+ d_simp_quant = Rewriter::rewrite(d_simp_quant);
+ d_simp_quant = nm->mkNode(FORALL, q[0], d_simp_quant, q[2]);
+ Trace("cegqi-si") << "Rewritten quantifier : " << d_simp_quant << std::endl;
+
+ // construct template argument
+ d_templ_arg[prog] = nm->mkSkolem("I", invariant.getType());
+
+ // construct template
+ Node templ;
+ if (options::sygusInvAutoUnfold())
+ {
+ if (d_ti[q].isComplete())
+ {
+ Trace("cegqi-inv-auto-unfold")
+ << "Automatic deterministic unfolding... " << std::endl;
+ // auto-unfold
+ DetTrace dt;
+ int init_dt = d_ti[q].initializeTrace(dt);
+ if (init_dt == 0)
{
- SygusInvTemplMode tmode = options::sygusInvTemplMode();
- if (tmode != SYGUS_INV_TEMPL_MODE_NONE)
+ Trace("cegqi-inv-auto-unfold") << " Init : ";
+ dt.print("cegqi-inv-auto-unfold");
+ Trace("cegqi-inv-auto-unfold") << std::endl;
+ unsigned counter = 0;
+ unsigned status = 0;
+ while (counter < 100 && status == 0)
{
- // currently only works for single predicate synthesis
- if (q[0].getNumChildren() > 1 || !q[0][0].getType().isPredicate())
- {
- tmode = SYGUS_INV_TEMPL_MODE_NONE;
- }
- else if (!options::sygusInvTemplWhenSyntax())
- {
- // only use invariant templates if no syntactic restrictions
- if (CegGrammarConstructor::hasSyntaxRestrictions(q))
- {
- tmode = SYGUS_INV_TEMPL_MODE_NONE;
- }
- }
+ status = d_ti[q].incrementTrace(dt);
+ counter++;
+ Trace("cegqi-inv-auto-unfold") << " #" << counter << " : ";
+ dt.print("cegqi-inv-auto-unfold");
+ Trace("cegqi-inv-auto-unfold")
+ << "...status = " << status << std::endl;
}
-
- if (tmode != SYGUS_INV_TEMPL_MODE_NONE)
+ if (status == 1)
{
- //if we are doing invariant templates, then construct the template
- Trace("cegqi-si") << "- Do transition inference..." << std::endl;
- d_ti[q].process( qq );
- Trace("cegqi-inv") << std::endl;
- if( !d_ti[q].d_func.isNull() ){
- // map the program back via non-single invocation map
- Node prog = d_ti[q].d_func;
- std::vector< Node > prog_templ_vars;
- prog_templ_vars.insert( prog_templ_vars.end(), d_ti[q].d_vars.begin(), d_ti[q].d_vars.end() );
- d_trans_pre[prog] = d_ti[q].getComponent( 1 );
- d_trans_post[prog] = d_ti[q].getComponent( -1 );
- Trace("cegqi-inv") << " precondition : " << d_trans_pre[prog] << std::endl;
- Trace("cegqi-inv") << " postcondition : " << d_trans_post[prog] << std::endl;
- std::vector<Node> sivars;
- d_sip->getSingleInvocationVariables(sivars);
- Node invariant = d_sip->getFunctionInvocationFor(prog);
- Assert(!invariant.isNull());
- invariant = invariant.substitute(sivars.begin(),
- sivars.end(),
- prog_templ_vars.begin(),
- prog_templ_vars.end());
- Trace("cegqi-inv") << " invariant : " << invariant << std::endl;
-
- // store simplified version of quantified formula
- d_simp_quant = d_sip->getFullSpecification();
- std::vector< Node > new_bv;
- for (unsigned j = 0, size = sivars.size(); j < size; j++)
- {
- new_bv.push_back(
- NodeManager::currentNM()->mkBoundVar(sivars[j].getType()));
- }
- d_simp_quant = d_simp_quant.substitute(
- sivars.begin(), sivars.end(), new_bv.begin(), new_bv.end());
- Assert( q[1].getKind()==NOT && q[1][0].getKind()==FORALL );
- for( unsigned j=0; j<q[1][0][0].getNumChildren(); j++ ){
- new_bv.push_back( q[1][0][0][j] );
- }
- d_simp_quant = NodeManager::currentNM()->mkNode( kind::FORALL, NodeManager::currentNM()->mkNode( BOUND_VAR_LIST, new_bv ), d_simp_quant ).negate();
- d_simp_quant = Rewriter::rewrite( d_simp_quant );
- d_simp_quant = NodeManager::currentNM()->mkNode( kind::FORALL, q[0], d_simp_quant, q[2] );
- Trace("cegqi-si") << "Rewritten quantifier : " << d_simp_quant << std::endl;
-
- //construct template argument
- d_templ_arg[prog] = NodeManager::currentNM()->mkSkolem( "I", invariant.getType() );
-
- //construct template
- Node templ;
- if( options::sygusInvAutoUnfold() ){
- if( d_ti[q].isComplete() ){
- Trace("cegqi-inv-auto-unfold") << "Automatic deterministic unfolding... " << std::endl;
- // auto-unfold
- DetTrace dt;
- int init_dt = d_ti[q].initializeTrace( dt );
- if( init_dt==0 ){
- Trace("cegqi-inv-auto-unfold") << " Init : ";
- dt.print("cegqi-inv-auto-unfold");
- Trace("cegqi-inv-auto-unfold") << std::endl;
- unsigned counter = 0;
- unsigned status = 0;
- while( counter<100 && status==0 ){
- status = d_ti[q].incrementTrace( dt );
- counter++;
- Trace("cegqi-inv-auto-unfold") << " #" << counter << " : ";
- dt.print("cegqi-inv-auto-unfold");
- Trace("cegqi-inv-auto-unfold") << "...status = " << status << std::endl;
- }
- if( status==1 ){
- // we have a trivial invariant
- templ = d_ti[q].constructFormulaTrace( dt );
- Trace("cegqi-inv") << "By finite deterministic terminating trace, a solution invariant is : " << std::endl;
- Trace("cegqi-inv") << " " << templ << std::endl;
- // FIXME : this should be unnecessary
- templ = NodeManager::currentNM()->mkNode( AND, templ, d_templ_arg[prog] );
- }
- }else{
- Trace("cegqi-inv-auto-unfold") << "...failed initialize." << std::endl;
- }
- }
- }
- Trace("cegqi-inv") << "Make the template... " << tmode << " "
- << templ << std::endl;
- if( templ.isNull() ){
- if (tmode == SYGUS_INV_TEMPL_MODE_PRE)
- {
- //d_templ[prog] = NodeManager::currentNM()->mkNode( AND, NodeManager::currentNM()->mkNode( OR, d_trans_pre[prog], invariant ), d_trans_post[prog] );
- templ = NodeManager::currentNM()->mkNode( OR, d_trans_pre[prog], d_templ_arg[prog] );
- }else{
- Assert(tmode == SYGUS_INV_TEMPL_MODE_POST);
- //d_templ[prog] = NodeManager::currentNM()->mkNode( OR, d_trans_pre[prog], NodeManager::currentNM()->mkNode( AND, d_trans_post[prog], invariant ) );
- templ = NodeManager::currentNM()->mkNode( AND, d_trans_post[prog], d_templ_arg[prog] );
- }
- }
- Trace("cegqi-inv") << " template (pre-substitution) : " << templ << std::endl;
- Assert( !templ.isNull() );
- // subsitute the template arguments
- Assert(prog_templ_vars.size() == prog_vars[prog].size());
- templ = templ.substitute( prog_templ_vars.begin(), prog_templ_vars.end(), prog_vars[prog].begin(), prog_vars[prog].end() );
- Trace("cegqi-inv") << " template : " << templ << std::endl;
- d_templ[prog] = templ;
- }
+ // we have a trivial invariant
+ templ = d_ti[q].constructFormulaTrace(dt);
+ Trace("cegqi-inv") << "By finite deterministic terminating trace, a "
+ "solution invariant is : "
+ << std::endl;
+ Trace("cegqi-inv") << " " << templ << std::endl;
+ // this should be unnecessary
+ templ = nm->mkNode(AND, templ, d_templ_arg[prog]);
}
- }else{
- //we are fully single invocation
- d_single_invocation = true;
}
+ else
+ {
+ Trace("cegqi-inv-auto-unfold") << "...failed initialize." << std::endl;
+ }
+ }
+ }
+ Trace("cegqi-inv") << "Make the template... " << tmode << " " << templ
+ << std::endl;
+ if (templ.isNull())
+ {
+ if (tmode == SYGUS_INV_TEMPL_MODE_PRE)
+ {
+ templ = nm->mkNode(OR, d_trans_pre[prog], d_templ_arg[prog]);
+ }
+ else
+ {
+ Assert(tmode == SYGUS_INV_TEMPL_MODE_POST);
+ templ = nm->mkNode(AND, d_trans_post[prog], d_templ_arg[prog]);
}
}
+ Trace("cegqi-inv") << " template (pre-substitution) : " << templ
+ << std::endl;
+ Assert(!templ.isNull());
+ // subsitute the template arguments
+ Assert(prog_templ_vars.size() == prog_vars[prog].size());
+ templ = templ.substitute(prog_templ_vars.begin(),
+ prog_templ_vars.end(),
+ prog_vars[prog].begin(),
+ prog_vars[prog].end());
+ Trace("cegqi-inv") << " template : " << templ << std::endl;
+ d_templ[prog] = templ;
}
void CegSingleInv::finishInit(bool syntaxRestricted)
diff --git a/src/theory/quantifiers/sygus/sygus_unif_io.cpp b/src/theory/quantifiers/sygus/sygus_unif_io.cpp
index a6e6b54c6..c9db62735 100644
--- a/src/theory/quantifiers/sygus/sygus_unif_io.cpp
+++ b/src/theory/quantifiers/sygus/sygus_unif_io.cpp
@@ -1013,6 +1013,7 @@ Node SygusUnifIo::constructSol(
bool retValMod = x.isReturnValueModified();
Node ret_dt;
+ Node cached_ret_dt;
if (nrole == role_equal)
{
if (!retValMod)
@@ -1094,14 +1095,14 @@ Node SygusUnifIo::constructSol(
{
bool firstTime = true;
std::unordered_set<Node, NodeHashFunction> intersection;
- std::map<size_t, std::unordered_set<Node, NodeHashFunction>>::iterator
+ std::map<TypeNode, std::unordered_set<Node, NodeHashFunction>>::iterator
pit;
for (size_t i = 0, nvals = x.d_vals.size(); i < nvals; i++)
{
if (x.d_vals[i].getConst<bool>())
{
- pit = d_psolutions.find(i);
- if (pit == d_psolutions.end())
+ pit = d_psolutions[i].find(etn);
+ if (pit == d_psolutions[i].end())
{
// no cached solution
intersection.clear();
@@ -1135,12 +1136,31 @@ Node SygusUnifIo::constructSol(
}
if (!intersection.empty())
{
- ret_dt = *intersection.begin();
+ if (d_enableMinimality)
+ {
+ // if we are enabling minimality, the minimal cached solution may
+ // still not be the best solution, thus we remember it and keep it if
+ // we don't construct a better one below
+ std::vector<Node> intervec;
+ intervec.insert(
+ intervec.begin(), intersection.begin(), intersection.end());
+ cached_ret_dt = getMinimalTerm(intervec);
+ }
+ else
+ {
+ ret_dt = *intersection.begin();
+ }
if (Trace.isOn("sygus-sui-dt"))
{
indent("sygus-sui-dt", ind);
Trace("sygus-sui-dt") << "ConstructPBE: found in cache: ";
- TermDbSygus::toStreamSygus("sygus-sui-dt", ret_dt);
+ Node csol = ret_dt;
+ if (d_enableMinimality)
+ {
+ csol = cached_ret_dt;
+ Trace("sygus-sui-dt") << "(minimal) ";
+ }
+ TermDbSygus::toStreamSygus("sygus-sui-dt", csol);
Trace("sygus-sui-dt") << std::endl;
}
}
@@ -1303,7 +1323,6 @@ Node SygusUnifIo::constructSol(
Trace("sygus-sui-dt")
<< "...try STRATEGY " << strat << "..." << std::endl;
- std::map<unsigned, Node> look_ahead_solved_children;
std::vector<Node> dt_children_cons;
bool success = true;
@@ -1318,108 +1337,95 @@ Node SygusUnifIo::constructSol(
Trace("sygus-sui-dt")
<< "construct PBE child #" << sc << "..." << std::endl;
Node rec_c;
- std::map<unsigned, Node>::iterator itla =
- look_ahead_solved_children.find(sc);
- if (itla != look_ahead_solved_children.end())
+
+ std::pair<Node, NodeRole>& cenum = etis->d_cenum[sc];
+
+ // update the context
+ std::vector<Node> prev;
+ if (strat == strat_ITE && sc > 0)
{
- rec_c = itla->second;
- indent("sygus-sui-dt-debug", ind + 1);
- Trace("sygus-sui-dt-debug")
- << "ConstructPBE: look ahead solved : "
- << d_tds->sygusToBuiltin(rec_c) << std::endl;
+ EnumCache& ecache_cond = d_ecache[split_cond_enum];
+ Assert(set_split_cond_res_index);
+ Assert(split_cond_res_index < ecache_cond.d_enum_vals_res.size());
+ prev = x.d_vals;
+ x.updateContext(this,
+ ecache_cond.d_enum_vals_res[split_cond_res_index],
+ sc == 1);
+ // return value of above call may be false in corner cases where we
+ // must choose a non-separating condition to traverse to another
+ // strategy node
}
- else
- {
- std::pair<Node, NodeRole>& cenum = etis->d_cenum[sc];
-
- // update the context
- std::vector<Node> prev;
- if (strat == strat_ITE && sc > 0)
- {
- EnumCache& ecache_cond = d_ecache[split_cond_enum];
- Assert(set_split_cond_res_index);
- Assert(split_cond_res_index < ecache_cond.d_enum_vals_res.size());
- prev = x.d_vals;
- x.updateContext(this,
- ecache_cond.d_enum_vals_res[split_cond_res_index],
- sc == 1);
- // return value of above call may be false in corner cases where we
- // must choose a non-separating condition to traverse to another
- // strategy node
- }
- // recurse
- if (strat == strat_ITE && sc == 0)
- {
- Node ce = cenum.first;
+ // recurse
+ if (strat == strat_ITE && sc == 0)
+ {
+ Node ce = cenum.first;
- EnumCache& ecache_child = d_ecache[ce];
+ EnumCache& ecache_child = d_ecache[ce];
- // get the conditionals in the current context : they must be
- // distinguishable
- std::map<int, std::vector<Node> > possible_cond;
- std::map<Node, int> solved_cond; // stores branch
- ecache_child.d_term_trie.getLeaves(x.d_vals, true, possible_cond);
+ // get the conditionals in the current context : they must be
+ // distinguishable
+ std::map<int, std::vector<Node> > possible_cond;
+ std::map<Node, int> solved_cond; // stores branch
+ ecache_child.d_term_trie.getLeaves(x.d_vals, true, possible_cond);
- std::map<int, std::vector<Node>>::iterator itpc =
- possible_cond.find(0);
- if (itpc != possible_cond.end())
+ std::map<int, std::vector<Node>>::iterator itpc =
+ possible_cond.find(0);
+ if (itpc != possible_cond.end())
+ {
+ if (Trace.isOn("sygus-sui-dt-debug"))
{
- if (Trace.isOn("sygus-sui-dt-debug"))
+ indent("sygus-sui-dt-debug", ind + 1);
+ Trace("sygus-sui-dt-debug")
+ << "PBE : We have " << itpc->second.size()
+ << " distinguishable conditionals:" << std::endl;
+ for (Node& cond : itpc->second)
{
- indent("sygus-sui-dt-debug", ind + 1);
+ indent("sygus-sui-dt-debug", ind + 2);
Trace("sygus-sui-dt-debug")
- << "PBE : We have " << itpc->second.size()
- << " distinguishable conditionals:" << std::endl;
- for (Node& cond : itpc->second)
- {
- indent("sygus-sui-dt-debug", ind + 2);
- Trace("sygus-sui-dt-debug")
- << d_tds->sygusToBuiltin(cond) << std::endl;
- }
- }
- if (rec_c.isNull())
- {
- rec_c = constructBestConditional(ce, itpc->second);
- Assert(!rec_c.isNull());
- indent("sygus-sui-dt", ind);
- Trace("sygus-sui-dt")
- << "PBE: ITE strategy : choose best conditional "
- << d_tds->sygusToBuiltin(rec_c) << std::endl;
+ << d_tds->sygusToBuiltin(cond) << std::endl;
}
}
- else
+ if (rec_c.isNull())
{
- // TODO (#1250) : degenerate case where children have different
- // types?
+ rec_c = constructBestConditional(ce, itpc->second);
+ Assert(!rec_c.isNull());
indent("sygus-sui-dt", ind);
- Trace("sygus-sui-dt") << "return PBE: failed ITE strategy, "
- "cannot find a distinguishable condition"
- << std::endl;
- }
- if (!rec_c.isNull())
- {
- Assert(ecache_child.d_enum_val_to_index.find(rec_c)
- != ecache_child.d_enum_val_to_index.end());
- split_cond_res_index = ecache_child.d_enum_val_to_index[rec_c];
- set_split_cond_res_index = true;
- split_cond_enum = ce;
- Assert(split_cond_res_index
- < ecache_child.d_enum_vals_res.size());
+ Trace("sygus-sui-dt")
+ << "PBE: ITE strategy : choose best conditional "
+ << d_tds->sygusToBuiltin(rec_c) << std::endl;
}
}
else
{
- did_recurse = true;
- rec_c = constructSol(f, cenum.first, cenum.second, ind + 2, lemmas);
+ // TODO (#1250) : degenerate case where children have different
+ // types?
+ indent("sygus-sui-dt", ind);
+ Trace("sygus-sui-dt") << "return PBE: failed ITE strategy, "
+ "cannot find a distinguishable condition"
+ << std::endl;
}
-
- // undo update the context
- if (strat == strat_ITE && sc > 0)
+ if (!rec_c.isNull())
{
- x.d_vals = prev;
+ Assert(ecache_child.d_enum_val_to_index.find(rec_c)
+ != ecache_child.d_enum_val_to_index.end());
+ split_cond_res_index = ecache_child.d_enum_val_to_index[rec_c];
+ set_split_cond_res_index = true;
+ split_cond_enum = ce;
+ Assert(split_cond_res_index
+ < ecache_child.d_enum_vals_res.size());
}
}
+ else
+ {
+ did_recurse = true;
+ rec_c = constructSol(f, cenum.first, cenum.second, ind + 2, lemmas);
+ }
+ // undo update the context
+ if (strat == strat_ITE && sc > 0)
+ {
+ x.d_vals = prev;
+ }
if (!rec_c.isNull())
{
dt_children_cons.push_back(rec_c);
@@ -1455,6 +1461,24 @@ Node SygusUnifIo::constructSol(
sindex++;
}
+ // if there was a cached solution, process it now
+ if (!cached_ret_dt.isNull() && cached_ret_dt != ret_dt)
+ {
+ if (ret_dt.isNull())
+ {
+ // take the cached one if it is the only one
+ ret_dt = cached_ret_dt;
+ }
+ else if (d_enableMinimality)
+ {
+ Assert(ret_dt.getType() == cached_ret_dt.getType());
+ // take the cached one if it is smaller
+ std::vector<Node> retDts;
+ retDts.push_back(cached_ret_dt);
+ retDts.push_back(ret_dt);
+ ret_dt = getMinimalTerm(retDts);
+ }
+ }
Assert(ret_dt.isNull() || ret_dt.getType() == e.getType());
if (Trace.isOn("sygus-sui-dt"))
{
@@ -1479,7 +1503,7 @@ Node SygusUnifIo::constructSol(
TermDbSygus::toStreamSygus("sygus-sui-cache", ret_dt);
Trace("sygus-sui-cache") << std::endl;
}
- d_psolutions[i].insert(ret_dt);
+ d_psolutions[i][etn].insert(ret_dt);
}
}
}
diff --git a/src/theory/quantifiers/sygus/sygus_unif_io.h b/src/theory/quantifiers/sygus/sygus_unif_io.h
index f189353b0..7f48645bf 100644
--- a/src/theory/quantifiers/sygus/sygus_unif_io.h
+++ b/src/theory/quantifiers/sygus/sygus_unif_io.h
@@ -304,9 +304,14 @@ class SygusUnifIo : public SygusUnif
unsigned d_sol_term_size;
/** partial solutions
*
- * Maps indices for I/O points to a list of solutions for that point.
+ * Maps indices for I/O points to a list of solutions for that point, for each
+ * type. We may have more than one type for solutions, e.g. for grammar:
+ * A -> ite( A, B, C ) | ...
+ * where terms of type B and C can both act as solutions.
*/
- std::map<size_t, std::unordered_set<Node, NodeHashFunction>> d_psolutions;
+ std::map<size_t,
+ std::map<TypeNode, std::unordered_set<Node, NodeHashFunction>>>
+ d_psolutions;
/**
* This flag is set to true if the solution construction was
* non-deterministic with respect to failure/success.
diff --git a/src/theory/quantifiers/term_util.cpp b/src/theory/quantifiers/term_util.cpp
index f8e8ed5ad..4c9cf2c8d 100644
--- a/src/theory/quantifiers/term_util.cpp
+++ b/src/theory/quantifiers/term_util.cpp
@@ -654,7 +654,15 @@ bool TermUtil::isNegate(Kind k)
return k == NOT || k == BITVECTOR_NOT || k == BITVECTOR_NEG || k == UMINUS;
}
-bool TermUtil::isAssoc( Kind k ) {
+bool TermUtil::isAssoc(Kind k, bool reqNAry)
+{
+ if (reqNAry)
+ {
+ if (k == UNION || k == INTERSECTION)
+ {
+ return false;
+ }
+ }
return k == PLUS || k == MULT || k == NONLINEAR_MULT || k == AND || k == OR
|| k == XOR || k == BITVECTOR_PLUS || k == BITVECTOR_MULT
|| k == BITVECTOR_AND || k == BITVECTOR_OR || k == BITVECTOR_XOR
@@ -663,7 +671,15 @@ bool TermUtil::isAssoc( Kind k ) {
|| k == SEP_STAR;
}
-bool TermUtil::isComm( Kind k ) {
+bool TermUtil::isComm(Kind k, bool reqNAry)
+{
+ if (reqNAry)
+ {
+ if (k == UNION || k == INTERSECTION)
+ {
+ return false;
+ }
+ }
return k == EQUAL || k == PLUS || k == MULT || k == NONLINEAR_MULT || k == AND
|| k == OR || k == XOR || k == BITVECTOR_PLUS || k == BITVECTOR_MULT
|| k == BITVECTOR_AND || k == BITVECTOR_OR || k == BITVECTOR_XOR
diff --git a/src/theory/quantifiers/term_util.h b/src/theory/quantifiers/term_util.h
index dd3e76ee2..820821991 100644
--- a/src/theory/quantifiers/term_util.h
+++ b/src/theory/quantifiers/term_util.h
@@ -270,10 +270,18 @@ public:
* double negation if applicable, e.g. mkNegate( ~, ~x ) ---> x.
*/
static Node mkNegate(Kind notk, Node n);
- /** is assoc */
- static bool isAssoc( Kind k );
- /** is k commutative? */
- static bool isComm( Kind k );
+ /** is k associative?
+ *
+ * If flag reqNAry is true, then we additionally require that k is an
+ * n-ary operator.
+ */
+ static bool isAssoc(Kind k, bool reqNAry = false);
+ /** is k commutative?
+ *
+ * If flag reqNAry is true, then we additionally require that k is an
+ * n-ary operator.
+ */
+ static bool isComm(Kind k, bool reqNAry = false);
/** is k non-additive?
* Returns true if
diff --git a/src/theory/quantifiers_engine.cpp b/src/theory/quantifiers_engine.cpp
index 320f50afb..433621d31 100644
--- a/src/theory/quantifiers_engine.cpp
+++ b/src/theory/quantifiers_engine.cpp
@@ -30,7 +30,6 @@
#include "theory/quantifiers/equality_infer.h"
#include "theory/quantifiers/equality_query.h"
#include "theory/quantifiers/first_order_model.h"
-#include "theory/quantifiers/fmf/ambqi_builder.h"
#include "theory/quantifiers/fmf/bounded_integers.h"
#include "theory/quantifiers/fmf/full_model_check.h"
#include "theory/quantifiers/fmf/model_engine.h"
@@ -249,20 +248,14 @@ QuantifiersEngine::QuantifiersEngine(context::Context* c,
d_model.reset(new quantifiers::fmcheck::FirstOrderModelFmc(
this, c, "FirstOrderModelFmc"));
d_builder.reset(new quantifiers::fmcheck::FullModelChecker(c, this));
- }else if( options::mbqiMode()==quantifiers::MBQI_ABS ){
- Trace("quant-engine-debug") << "...make abs mbqi builder." << std::endl;
- d_model.reset(
- new quantifiers::FirstOrderModelAbs(this, c, "FirstOrderModelAbs"));
- d_builder.reset(new quantifiers::AbsMbqiBuilder(c, this));
}else{
Trace("quant-engine-debug") << "...make default model builder." << std::endl;
d_model.reset(
- new quantifiers::FirstOrderModelIG(this, c, "FirstOrderModelIG"));
- d_builder.reset(new quantifiers::QModelBuilderDefault(c, this));
+ new quantifiers::FirstOrderModel(this, c, "FirstOrderModel"));
+ d_builder.reset(new quantifiers::QModelBuilder(c, this));
}
}else{
- d_model.reset(
- new quantifiers::FirstOrderModelIG(this, c, "FirstOrderModelIG"));
+ d_model.reset(new quantifiers::FirstOrderModel(this, c, "FirstOrderModel"));
}
}
diff --git a/src/theory/sets/theory_sets_rewriter.cpp b/src/theory/sets/theory_sets_rewriter.cpp
index a3f1f9893..2a2015319 100644
--- a/src/theory/sets/theory_sets_rewriter.cpp
+++ b/src/theory/sets/theory_sets_rewriter.cpp
@@ -47,7 +47,7 @@ bool checkConstantMembership(TNode elementTerm, TNode setTerm)
RewriteResponse TheorySetsRewriter::postRewrite(TNode node) {
NodeManager* nm = NodeManager::currentNM();
Kind kind = node.getKind();
-
+ Trace("sets-postrewrite") << "Process: " << node << std::endl;
if(node.isConst()) {
// Dare you touch the const and mangle it to something else.
@@ -204,6 +204,7 @@ RewriteResponse TheorySetsRewriter::postRewrite(TNode node) {
if( rew!=node ){
Trace("sets-rewrite") << "Sets::rewrite " << node << " -> " << rew << std::endl;
}
+ Trace("sets-rewrite") << "...no rewrite." << std::endl;
return RewriteResponse(REWRITE_DONE, rew);
}
break;
diff --git a/src/theory/strings/skolem_cache.cpp b/src/theory/strings/skolem_cache.cpp
index 53ec3c368..276cb70d6 100644
--- a/src/theory/strings/skolem_cache.cpp
+++ b/src/theory/strings/skolem_cache.cpp
@@ -19,6 +19,8 @@
#include "theory/strings/theory_strings_rewriter.h"
#include "util/rational.h"
+using namespace CVC4::kind;
+
namespace CVC4 {
namespace theory {
namespace strings {
@@ -103,23 +105,100 @@ SkolemCache::normalizeStringSkolem(SkolemId id, Node a, Node b)
Trace("skolem-cache") << "normalizeStringSkolem start: (" << id << ", " << a
<< ", " << b << ")" << std::endl;
- // SK_PURIFY(str.substr x 0 (str.indexof x y 0)) ---> SK_FIRST_CTN_PRE(x, y)
+ NodeManager* nm = NodeManager::currentNM();
+
+ if (id == SK_FIRST_CTN_POST)
+ {
+ // SK_FIRST_CTN_POST(x, y) --->
+ // SK_SUFFIX_REM(x, (+ (str.len SK_FIRST_CTN_PRE(x, y)) (str.len y)))
+ id = SK_SUFFIX_REM;
+ Node pre = mkSkolemCached(a, b, SK_FIRST_CTN_PRE, "pre");
+ b = Rewriter::rewrite(nm->mkNode(
+ PLUS, nm->mkNode(STRING_LENGTH, pre), nm->mkNode(STRING_LENGTH, b)));
+ }
+
+ if (id == SK_ID_C_SPT)
+ {
+ // SK_ID_C_SPT(x, y) ---> SK_SUFFIX_REM(x, (str.len y))
+ id = SK_SUFFIX_REM;
+ b = Rewriter::rewrite(nm->mkNode(STRING_LENGTH, b));
+ }
+ else if (id == SK_ID_VC_SPT)
+ {
+ // SK_ID_VC_SPT(x, y) ---> SK_SUFFIX_REM(x, 1)
+ id = SK_SUFFIX_REM;
+ b = nm->mkConst(Rational(1));
+ }
+ else if (id == SK_ID_VC_SPT_REV)
+ {
+ // SK_ID_VC_SPT_REV(x, y) ---> SK_PREFIX(x, (- (str.len x) 1))
+ id = SK_PREFIX;
+ b = Rewriter::rewrite(nm->mkNode(
+ MINUS, nm->mkNode(STRING_LENGTH, a), nm->mkConst(Rational(1))));
+ }
+ else if (id == SK_ID_DC_SPT)
+ {
+ // SK_ID_DC_SPT(x, y) ---> SK_PREFIX(x, 1)
+ id = SK_PREFIX;
+ b = nm->mkConst(Rational(1));
+ }
+ else if (id == SK_ID_DC_SPT_REM)
+ {
+ // SK_ID_DC_SPT_REM(x, y) ---> SK_SUFFIX_REM(x, 1)
+ id = SK_SUFFIX_REM;
+ b = nm->mkConst(Rational(1));
+ }
+ else if (id == SK_ID_DEQ_X)
+ {
+ // SK_ID_DEQ_X(x, y) ---> SK_PREFIX(y, (str.len x))
+ id = SK_PREFIX;
+ Node aOld = a;
+ a = b;
+ b = Rewriter::rewrite(nm->mkNode(STRING_LENGTH, aOld));
+ }
+ else if (id == SK_ID_DEQ_Y)
+ {
+ // SK_ID_DEQ_Y(x, y) ---> SK_PREFIX(x, (str.len y))
+ id = SK_PREFIX;
+ b = Rewriter::rewrite(nm->mkNode(STRING_LENGTH, b));
+ }
+
+ if (id == SK_SUFFIX_REM) {
+ //std::cout << "suffix" << a << " " << b << std::endl;
+ }
+
if (id == SK_PURIFY && a.getKind() == kind::STRING_SUBSTR)
{
Node s = a[0];
Node n = a[1];
Node m = a[2];
- if (m.getKind() == kind::STRING_STRIDOF && m[0] == s)
+
+ if (n == d_zero)
+ {
+ // SK_PURIFY((str.substr x 0 m)) ---> SK_PREFIX(x, m)
+ id = SK_PREFIX;
+ a = s;
+ b = m;
+ }
+ else if (TheoryStringsRewriter::checkEntailArith(
+ nm->mkNode(PLUS, n, m), nm->mkNode(STRING_LENGTH, s)))
{
- if (n == d_zero && m[2] == d_zero)
- {
- id = SK_FIRST_CTN_PRE;
- a = m[0];
- b = m[1];
- }
+ // SK_PURIFY((str.substr x n m)) ---> SK_SUFFIX_REM(x, n)
+ // if n + m >= (str.len x)
+ id = SK_SUFFIX_REM;
+ a = s;
+ b = n;
}
}
+ if (id == SK_PREFIX && b.getKind() == kind::STRING_STRIDOF && a == b[0]
+ && b[2] == d_zero)
+ {
+ // SK_PREFIX(x, (str.indexof x y 0)) ---> SK_FIRST_CTN_PRE(x, y)
+ id = SK_FIRST_CTN_PRE;
+ b = b[1];
+ }
+
if (id == SK_FIRST_CTN_PRE)
{
// SK_FIRST_CTN_PRE((str.substr x 0 n), y) ---> SK_FIRST_CTN_PRE(x, y)
diff --git a/src/theory/strings/theory_strings.cpp b/src/theory/strings/theory_strings.cpp
index 6905b1c06..c52069a31 100644
--- a/src/theory/strings/theory_strings.cpp
+++ b/src/theory/strings/theory_strings.cpp
@@ -1663,8 +1663,8 @@ void TheoryStrings::checkExtfEval( int effort ) {
for (const Node& nrcc : nrc)
{
sendInternalInference(einfo.d_exp,
- einfo.d_const == d_false ? nrcc.negate() : nrcc,
- effort == 0 ? "EXTF_d" : "EXTF_d-N");
+ einfo.d_const == d_false ? nrcc.negate() : nrcc,
+ effort == 0 ? "EXTF_d" : "EXTF_d-N");
}
}else{
to_reduce = nrc;
@@ -3195,7 +3195,6 @@ void TheoryStrings::processSimpleNEq( std::vector< std::vector< Node > > &normal
Node firstChar = stra.size() == 1 ? const_str : NodeManager::currentNM()->mkConst( isRev ? stra.suffix( 1 ) : stra.prefix( 1 ) );
Node sk = d_sk_cache.mkSkolemCached(
other_str,
- firstChar,
isRev ? SkolemCache::SK_ID_VC_SPT_REV
: SkolemCache::SK_ID_VC_SPT,
"c_spt");
@@ -3570,11 +3569,10 @@ void TheoryStrings::processDeq( Node ni, Node nj ) {
}
}else{
Node sk = d_sk_cache.mkSkolemCached(
- nconst_k, firstChar, SkolemCache::SK_ID_DC_SPT, "dc_spt");
+ nconst_k, SkolemCache::SK_ID_DC_SPT, "dc_spt");
registerLength(sk, LENGTH_ONE);
Node skr =
d_sk_cache.mkSkolemCached(nconst_k,
- firstChar,
SkolemCache::SK_ID_DC_SPT_REM,
"dc_spt_rem");
Node eq1 = nconst_k.eqNode( NodeManager::currentNM()->mkNode( kind::STRING_CONCAT, sk, skr ) );
@@ -3893,6 +3891,23 @@ void TheoryStrings::registerTerm( Node n, int effort ) {
Trace("strings-assert") << "(assert " << lem << ")" << std::endl;
d_out->lemma(lem);
}
+ else if (n.getKind() == STRING_STRIDOF)
+ {
+ Node lower = n[2];
+ if (!TheoryStringsRewriter::checkEntailArith(lower)) {
+ lower = d_zero;
+ }
+ Node neg = Rewriter::rewrite(nm->mkNode(EQUAL, n, d_neg_one));
+ Node geq = Rewriter::rewrite(nm->mkNode(GEQ, n, lower));
+ Node lem = nm->mkNode(OR, neg, geq);
+ Trace("strings-lemma") << "Strings::Lemma STRIDOF : " << lem << std::endl;
+ Trace("strings-assert") << "(assert " << lem << ")" << std::endl;
+ //d_out->lemma(lem);
+ //d_out->requirePhase(neg, true);
+
+ lem = Rewriter::rewrite(nm->mkNode(GT, nm->mkNode(STRING_LENGTH, n[0]), n));
+ d_out->lemma(lem);
+ }
}
void TheoryStrings::sendInternalInference(std::vector<Node>& exp,
diff --git a/src/theory/strings/theory_strings_rewriter.cpp b/src/theory/strings/theory_strings_rewriter.cpp
index 23d20c4c7..286c96b6a 100644
--- a/src/theory/strings/theory_strings_rewriter.cpp
+++ b/src/theory/strings/theory_strings_rewriter.cpp
@@ -1806,18 +1806,8 @@ Node TheoryStringsRewriter::rewriteSubstr(Node node)
}
}
}
- Trace("strings-rewrite-nf") << "No rewrites for : " << node << std::endl;
- return node;
-}
-
-Node TheoryStringsRewriter::rewriteSubstrExt(Node node)
-{
- Assert(node.getKind() == STRING_SUBSTR);
-
- NodeManager* nm = NodeManager::currentNM();
-
// combine substr
- if (node[0].getKind() == STRING_SUBSTR)
+ if (node[0].getKind() == kind::STRING_SUBSTR)
{
Node start_inner = node[0][1];
Node start_outer = node[1];
@@ -1830,7 +1820,7 @@ Node TheoryStringsRewriter::rewriteSubstrExt(Node node)
// the length of a string from the inner substr subtracts the start point
// of the outer substr
Node len_from_inner =
- Rewriter::rewrite(nm->mkNode(MINUS, node[0][2], start_outer));
+ Rewriter::rewrite(nm->mkNode(kind::MINUS, node[0][2], start_outer));
Node len_from_outer = node[2];
Node new_len;
// take quantity that is for sure smaller than the other
@@ -1848,13 +1838,14 @@ Node TheoryStringsRewriter::rewriteSubstrExt(Node node)
}
if (!new_len.isNull())
{
- Node new_start = nm->mkNode(PLUS, start_inner, start_outer);
- Node ret = nm->mkNode(STRING_SUBSTR, node[0][0], new_start, new_len);
+ Node new_start = nm->mkNode(kind::PLUS, start_inner, start_outer);
+ Node ret =
+ nm->mkNode(kind::STRING_SUBSTR, node[0][0], new_start, new_len);
return returnRewrite(node, ret, "ss-combine");
}
}
}
-
+ Trace("strings-rewrite-nf") << "No rewrites for : " << node << std::endl;
return node;
}
diff --git a/src/theory/strings/theory_strings_rewriter.h b/src/theory/strings/theory_strings_rewriter.h
index 7731cd078..69d6ff68e 100644
--- a/src/theory/strings/theory_strings_rewriter.h
+++ b/src/theory/strings/theory_strings_rewriter.h
@@ -159,21 +159,12 @@ class TheoryStringsRewriter {
* Returns the rewritten form of node.
*/
static Node rewriteConcat(Node node);
-
/** rewrite substr
* This is the entry point for post-rewriting terms node of the form
* str.substr( s, i1, i2 )
* Returns the rewritten form of node.
*/
static Node rewriteSubstr(Node node);
-
- /** rewrite substr extended
- * This is the entry point for extended post-rewriting terms node of the form
- * str.substr( s, i1, i2 )
- * Returns the rewritten form of node.
- */
- static Node rewriteSubstrExt(Node node);
-
/** rewrite contains
* This is the entry point for post-rewriting terms node of the form
* str.contains( t, s )
diff --git a/src/theory/uf/theory_uf_model.cpp b/src/theory/uf/theory_uf_model.cpp
index a3e058569..42847dfd4 100644
--- a/src/theory/uf/theory_uf_model.cpp
+++ b/src/theory/uf/theory_uf_model.cpp
@@ -37,17 +37,6 @@ void UfModelTreeNode::clear(){
d_value = Node::null();
}
-bool UfModelTreeNode::hasConcreteArgumentDefinition(){
- if( d_data.size()>1 ){
- return true;
- }else if( d_data.empty() ){
- return false;
- }else{
- Node r;
- return d_data.find( r )==d_data.end();
- }
-}
-
//set value function
void UfModelTreeNode::setValue( TheoryModel* m, Node n, Node v, std::vector< int >& indexOrder, bool ground, int argIndex ){
if( d_data.empty() ){
@@ -67,75 +56,6 @@ void UfModelTreeNode::setValue( TheoryModel* m, Node n, Node v, std::vector< int
}
}
-//get value function
-Node UfModelTreeNode::getValue( TheoryModel* m, Node n, std::vector< int >& indexOrder, int& depIndex, int argIndex ){
- if( !d_value.isNull() && isTotal( n.getOperator(), argIndex ) ){
- //Notice() << "Constant, return " << d_value << ", depIndex = " << argIndex << std::endl;
- depIndex = argIndex;
- return d_value;
- }else{
- Node val;
- int childDepIndex[2] = { argIndex, argIndex };
- for( int i=0; i<2; i++ ){
- //first check the argument, then check default
- Node r;
- if( i==0 ){
- r = m->getRepresentative( n[ indexOrder[argIndex] ] );
- }
- std::map< Node, UfModelTreeNode >::iterator it = d_data.find( r );
- if( it!=d_data.end() ){
- val = it->second.getValue( m, n, indexOrder, childDepIndex[i], argIndex+1 );
- if( !val.isNull() ){
- break;
- }
- }else{
- //argument is not a defined argument: thus, it depends on this argument
- childDepIndex[i] = argIndex+1;
- }
- }
- //update depIndex
- depIndex = childDepIndex[0]>childDepIndex[1] ? childDepIndex[0] : childDepIndex[1];
- //Notice() << "Return " << val << ", depIndex = " << depIndex;
- //Notice() << " ( " << childDepIndex[0] << ", " << childDepIndex[1] << " )" << std::endl;
- return val;
- }
-}
-
-Node UfModelTreeNode::getValue( TheoryModel* m, Node n, std::vector< int >& indexOrder, std::vector< int >& depIndex, int argIndex ){
- if( argIndex==(int)indexOrder.size() ){
- return d_value;
- }else{
- Node val;
- bool depArg = false;
- //will try concrete value first, then default
- for( int i=0; i<2; i++ ){
- Node r;
- if( i==0 ){
- r = m->getRepresentative( n[ indexOrder[argIndex] ] );
- }
- std::map< Node, UfModelTreeNode >::iterator it = d_data.find( r );
- if( it!=d_data.end() ){
- val = it->second.getValue( m, n, indexOrder, depIndex, argIndex+1 );
- //we have found a value
- if( !val.isNull() ){
- if( i==0 ){
- depArg = true;
- }
- break;
- }
- }
- }
- //it depends on this argument if we found it via concrete argument value,
- // or if found by default/disequal from some concrete argument value(s).
- if( depArg || hasConcreteArgumentDefinition() ){
- if( std::find( depIndex.begin(), depIndex.end(), indexOrder[argIndex] )==depIndex.end() ){
- depIndex.push_back( indexOrder[argIndex] );
- }
- }
- return val;
- }
-}
-
Node UfModelTreeNode::getFunctionValue(std::vector<Node>& args, int index, Node argDefaultValue, bool simplify) {
if(!d_data.empty()) {
Node defaultValue = argDefaultValue;
@@ -264,10 +184,6 @@ bool UfModelTreeNode::isTotal( Node op, int argIndex ){
}
}
-Node UfModelTreeNode::getConstantValue( TheoryModel* m, Node n, std::vector< int >& indexOrder, int argIndex ){
- return d_value;
-}
-
void indent( std::ostream& out, int ind ){
for( int i=0; i<ind; i++ ){
out << " ";
diff --git a/src/theory/uf/theory_uf_model.h b/src/theory/uf/theory_uf_model.h
index 201faccee..ac57bde27 100644
--- a/src/theory/uf/theory_uf_model.h
+++ b/src/theory/uf/theory_uf_model.h
@@ -31,8 +31,6 @@ public:
std::map< Node, UfModelTreeNode > d_data;
/** the value of this tree node (if all paths lead to same value) */
Node d_value;
- /** has concrete argument defintion */
- bool hasConcreteArgumentDefinition();
public:
//is this model tree empty?
bool isEmpty() { return d_data.empty() && d_value.isNull(); }
@@ -40,11 +38,6 @@ public:
void clear();
/** setValue function */
void setValue( TheoryModel* m, Node n, Node v, std::vector< int >& indexOrder, bool ground, int argIndex );
- /** getValue function */
- Node getValue( TheoryModel* m, Node n, std::vector< int >& indexOrder, int& depIndex, int argIndex );
- Node getValue( TheoryModel* m, Node n, std::vector< int >& indexOrder, std::vector< int >& depIndex, int argIndex );
- /** getConstant Value function */
- Node getConstantValue( TheoryModel* m, Node n, std::vector< int >& indexOrder, int argIndex );
/** getFunctionValue */
Node getFunctionValue( std::vector< Node >& args, int index, Node argDefaultValue, bool simplify = true );
/** update function */
@@ -92,36 +85,6 @@ public:
void setDefaultValue( TheoryModel* m, Node v ){
d_tree.setValue( m, Node::null(), v, d_index_order, false, 0 );
}
- /** getValue function
- *
- * returns val, the value of ground term n
- * Say n is f( t_0...t_n )
- * depIndex is the index for which every term of the form f( t_0 ... t_depIndex, *,... * ) is equal to val
- * for example, if g( x_0, x_1, x_2 ) := lambda x_0 x_1 x_2. if( x_1==a ) b else c,
- * then g( a, a, a ) would return b with depIndex = 1
- *
- */
- Node getValue( TheoryModel* m, Node n, int& depIndex ){
- return d_tree.getValue( m, n, d_index_order, depIndex, 0 );
- }
- /** -> implementation incomplete */
- Node getValue( TheoryModel* m, Node n, std::vector< int >& depIndex ){
- return d_tree.getValue( m, n, d_index_order, depIndex, 0 );
- }
- /** getConstantValue function
- *
- * given term n, where n may contain "all value" arguments, aka model basis arguments
- * if n is null, then every argument of n is considered "all value"
- * if n is constant for the entire domain specified by n, then this function returns the value of its domain
- * otherwise, it returns null
- * for example, say the term e represents "all values"
- * if f( x_0, x_1 ) := if( x_0 = a ) b else if( x_1 = a ) a else b,
- * then f( a, e ) would return b, while f( e, a ) would return null
- * -> implementation incomplete
- */
- Node getConstantValue( TheoryModel* m, Node n ) {
- return d_tree.getConstantValue( m, n, d_index_order, 0 );
- }
/** getFunctionValue
* Returns a representation of this function.
*/
@@ -136,8 +99,6 @@ public:
void simplify() { d_tree.simplify( d_op, Node::null(), 0 ); }
/** is this tree total? */
bool isTotal() { return d_tree.isTotal( d_op, 0 ); }
- /** is this function constant? */
- bool isConstant( TheoryModel* m ) { return !getConstantValue( m, Node::null() ).isNull(); }
/** is this tree empty? */
bool isEmpty() { return d_tree.isEmpty(); }
public:
diff --git a/src/util/sexpr.h b/src/util/sexpr.h
index 427eba5f8..bad6cdb2b 100644
--- a/src/util/sexpr.h
+++ b/src/util/sexpr.h
@@ -13,7 +13,7 @@
**
** Simple representation of S-expressions.
** These are used when a simple, and obvious interface for basic
- ** expressions is appropraite.
+ ** expressions is appropriate.
**
** These are quite ineffecient.
** These are totally disconnected from any ExprManager.
diff --git a/test/regress/CMakeLists.txt b/test/regress/CMakeLists.txt
index e0e57acf9..95e4b8875 100644
--- a/test/regress/CMakeLists.txt
+++ b/test/regress/CMakeLists.txt
@@ -159,7 +159,8 @@ set(regress_0_tests
regress0/bv/ackermann2.smt2
regress0/bv/ackermann3.smt2
regress0/bv/ackermann4.smt2
- regress0/bv/bool-to-bv.smt2
+ regress0/bv/bool-to-bv-all.smt2
+ regress0/bv/bool-to-bv-ite.smt2
regress0/bv/bug260a.smt
regress0/bv/bug260b.smt
regress0/bv/bug440.smt
@@ -775,6 +776,7 @@ set(regress_0_tests
regress0/sets/pre-proc-univ.smt2
regress0/sets/rec_copy_loop_check_heap_access_43_4.smt2
regress0/sets/sets-equal.smt2
+ regress0/sets/sets-extr.smt2
regress0/sets/sets-inter.smt2
regress0/sets/sets-of-sets-subtypes.smt2
regress0/sets/sets-poly-int-real.smt2
@@ -1729,6 +1731,7 @@ set(regress_2_tests
regress2/strings/cmu-disagree-0707-dd.smt2
regress2/strings/cmu-prereg-fmf.smt2
regress2/strings/cmu-repl-len-nterm.smt2
+ regress2/strings/extf_d_perf.smt2
regress2/strings/issue918.smt2
regress2/strings/non_termination_regular_expression6.smt2
regress2/strings/norn-dis-0707-3.smt2
diff --git a/test/regress/regress0/bv/ackermann1.smt2 b/test/regress/regress0/bv/ackermann1.smt2
index 9b96b38c4..218fd746b 100644
--- a/test/regress/regress0/bv/ackermann1.smt2
+++ b/test/regress/regress0/bv/ackermann1.smt2
@@ -1,4 +1,4 @@
-; COMMAND-LINE: --bitblast=eager --no-check-models --no-check-proofs --no-check-unsat-cores
+; COMMAND-LINE: --bitblast=eager --no-check-models --no-check-unsat-cores
; EXPECT: sat
(set-logic QF_UFBV)
(set-info :smt-lib-version 2.0)
diff --git a/test/regress/regress0/bv/ackermann2.smt2 b/test/regress/regress0/bv/ackermann2.smt2
index eeca505fe..b1aaa7d64 100644
--- a/test/regress/regress0/bv/ackermann2.smt2
+++ b/test/regress/regress0/bv/ackermann2.smt2
@@ -1,4 +1,4 @@
-; COMMAND-LINE: --bitblast=eager --no-check-models --no-check-proofs --no-check-unsat-cores
+; COMMAND-LINE: --bitblast=eager --no-check-models --no-check-unsat-cores
; EXPECT: unsat
(set-logic QF_UFBV)
(set-info :smt-lib-version 2.0)
diff --git a/test/regress/regress0/bv/bool-to-bv.smt2 b/test/regress/regress0/bv/bool-to-bv-all.smt2
index 8706c51a8..5947699d9 100644
--- a/test/regress/regress0/bv/bool-to-bv.smt2
+++ b/test/regress/regress0/bv/bool-to-bv-all.smt2
@@ -1,4 +1,4 @@
-; COMMAND-LINE: --bool-to-bv
+; COMMAND-LINE: --bool-to-bv=all
; EXPECT: sat
(set-logic QF_BV)
(declare-fun x2 () (_ BitVec 3))
diff --git a/test/regress/regress0/bv/bool-to-bv-ite.smt2 b/test/regress/regress0/bv/bool-to-bv-ite.smt2
new file mode 100644
index 000000000..e1be3ea10
--- /dev/null
+++ b/test/regress/regress0/bv/bool-to-bv-ite.smt2
@@ -0,0 +1,13 @@
+; COMMAND-LINE: --bool-to-bv=ite
+; EXPECT: sat
+(set-logic QF_BV)
+(declare-fun x2 () (_ BitVec 3))
+(declare-fun x1 () (_ BitVec 3))
+(declare-fun x0 () (_ BitVec 3))
+(declare-fun b1 () Bool)
+(declare-fun b2 () Bool)
+(assert (not (bvult (bvudiv (bvudiv (bvudiv x0 x0) x1) x2) x1)))
+(assert (= #b000 x2))
+(assert (=> b1 b2))
+(assert (= x2 (ite (bvugt x0 x1) (bvadd x0 (_ bv1 3)) (bvadd x1 (_ bv1 3)))))
+(check-sat)
diff --git a/test/regress/regress0/fmf/Arrow_Order-smtlib.778341.smt b/test/regress/regress0/fmf/Arrow_Order-smtlib.778341.smt
index e8c7949dc..bb2630b93 100644
--- a/test/regress/regress0/fmf/Arrow_Order-smtlib.778341.smt
+++ b/test/regress/regress0/fmf/Arrow_Order-smtlib.778341.smt
@@ -1,4 +1,4 @@
-; COMMAND-LINE: --finite-model-find --mbqi=gen-ev
+; COMMAND-LINE: --finite-model-find
; EXPECT: unsat
(benchmark Isabelle
:status sat
diff --git a/test/regress/regress0/fmf/QEpres-uf.855035.smt b/test/regress/regress0/fmf/QEpres-uf.855035.smt
index 4fe592638..97a585090 100644
--- a/test/regress/regress0/fmf/QEpres-uf.855035.smt
+++ b/test/regress/regress0/fmf/QEpres-uf.855035.smt
@@ -1,4 +1,4 @@
-; COMMAND-LINE: --finite-model-find --mbqi=gen-ev
+; COMMAND-LINE: --finite-model-find
; EXPECT: sat
(benchmark Isabelle
:status sat
diff --git a/test/regress/regress0/sets/sets-extr.smt2 b/test/regress/regress0/sets/sets-extr.smt2
new file mode 100644
index 000000000..c497ff189
--- /dev/null
+++ b/test/regress/regress0/sets/sets-extr.smt2
@@ -0,0 +1,15 @@
+; COMMAND-LINE: --ext-rew-prep --ext-rew-prep-agg
+; EXPECT: sat
+(set-logic ALL)
+(declare-sort Atom 0)
+
+(declare-fun a () Atom)
+(declare-fun b () Atom)
+(declare-fun c () Atom)
+(declare-fun S () (Set Atom))
+
+
+(assert (= S (union (singleton a) (union (singleton c) (singleton b)))))
+
+(check-sat)
+
diff --git a/test/regress/regress1/bv/bug787.smt2 b/test/regress/regress1/bv/bug787.smt2
index 8e0ba0016..d732b9ff0 100644
--- a/test/regress/regress1/bv/bug787.smt2
+++ b/test/regress/regress1/bv/bug787.smt2
@@ -1,4 +1,4 @@
-; COMMAND-LINE: --bitblast=eager --no-check-proofs
+; COMMAND-LINE: --bitblast=eager
; EXPECT: unsat
(set-logic QF_BV)
(set-info :status unsat)
diff --git a/test/regress/regress1/fmf/nlp042+1.smt2 b/test/regress/regress1/fmf/nlp042+1.smt2
index 567a3c0b7..6159f0b41 100644
--- a/test/regress/regress1/fmf/nlp042+1.smt2
+++ b/test/regress/regress1/fmf/nlp042+1.smt2
@@ -1,4 +1,4 @@
-; COMMAND-LINE: --finite-model-find --mbqi=abs --no-check-models
+; COMMAND-LINE: --finite-model-find --no-check-models
; EXPECT: sat
(set-logic UF)
(set-info :status sat)
diff --git a/test/regress/regress2/strings/extf_d_perf.smt2 b/test/regress/regress2/strings/extf_d_perf.smt2
new file mode 100644
index 000000000..7ad094dcb
--- /dev/null
+++ b/test/regress/regress2/strings/extf_d_perf.smt2
@@ -0,0 +1,19 @@
+; COMMAND-LINE: --strings-exp --strings-fmf
+; EXPECT: sat
+(set-logic ALL)
+(declare-fun _substvar_140_ () String)
+(declare-fun _substvar_195_ () Int)
+(declare-fun _substvar_201_ () Int)
+(assert (let ((_let_0 (str.substr _substvar_140_ 10 (+ 0 (str.len _substvar_140_))))) (let ((_let_3 (str.substr _let_0 0 (str.indexof _let_0 "/" 0)))) (let ((_let_4 (str.substr _let_3 0 7))) (let ((_let_5 (str.substr _let_3 8 (+ _substvar_201_ (str.len _let_3)))))
+ (and
+ (str.contains _substvar_140_ "://")
+ (str.contains _let_3 "@")
+ (str.contains _let_5 ",")
+ (not (= (str.len (str.substr _let_0 (+ 1 (str.indexof _let_0 "/" 0)) _substvar_195_)) 0))
+ (not (= (str.len _let_4) 0))
+ (not (str.contains _let_0 ".sock"))
+ (not (str.contains _let_4 "@"))
+ (not (= (str.len _let_5) 0))
+ (= "mongodb://" (str.substr _substvar_140_ 0 10))))))))
+(check-sat)
+
diff --git a/test/unit/api/CMakeLists.txt b/test/unit/api/CMakeLists.txt
index eeab46f99..8a6be70b9 100644
--- a/test/unit/api/CMakeLists.txt
+++ b/test/unit/api/CMakeLists.txt
@@ -4,3 +4,4 @@
cvc4_add_unit_test_black(solver_black api)
cvc4_add_unit_test_black(sort_black api)
cvc4_add_unit_test_black(term_black api)
+cvc4_add_unit_test_black(opterm_black api)
diff --git a/test/unit/api/opterm_black.h b/test/unit/api/opterm_black.h
new file mode 100644
index 000000000..637301dd3
--- /dev/null
+++ b/test/unit/api/opterm_black.h
@@ -0,0 +1,57 @@
+/********************* */
+/*! \file opterm_black.h
+ ** \verbatim
+ ** Top contributors (to current version):
+ ** Aina Niemetz
+ ** This file is part of the CVC4 project.
+ ** Copyright (c) 2009-2018 by the authors listed in the file AUTHORS
+ ** in the top-level source directory) and their institutional affiliations.
+ ** All rights reserved. See the file COPYING in the top-level source
+ ** directory for licensing information.\endverbatim
+ **
+ ** \brief Black box testing of the Term class
+ **/
+
+#include <cxxtest/TestSuite.h>
+
+#include "api/cvc4cpp.h"
+
+using namespace CVC4::api;
+
+class OpTermBlack : public CxxTest::TestSuite
+{
+ public:
+ void setUp() override {}
+ void tearDown() override {}
+
+ void testGetKind();
+ void testGetSort();
+ void testIsNull();
+
+ private:
+ Solver d_solver;
+};
+
+void OpTermBlack::testGetKind()
+{
+ OpTerm x;
+ TS_ASSERT_THROWS(x.getSort(), CVC4ApiException&);
+ x = d_solver.mkOpTerm(BITVECTOR_EXTRACT_OP, 31, 1);
+ TS_ASSERT_THROWS_NOTHING(x.getKind());
+}
+
+void OpTermBlack::testGetSort()
+{
+ OpTerm x;
+ TS_ASSERT_THROWS(x.getSort(), CVC4ApiException&);
+ x = d_solver.mkOpTerm(BITVECTOR_EXTRACT_OP, 31, 1);
+ TS_ASSERT_THROWS_NOTHING(x.getSort());
+}
+
+void OpTermBlack::testIsNull()
+{
+ OpTerm x;
+ TS_ASSERT(x.isNull());
+ x = d_solver.mkOpTerm(BITVECTOR_EXTRACT_OP, 31, 1);
+ TS_ASSERT(!x.isNull());
+}
diff --git a/test/unit/api/solver_black.h b/test/unit/api/solver_black.h
index 538899a0f..b0249b8a0 100644
--- a/test/unit/api/solver_black.h
+++ b/test/unit/api/solver_black.h
@@ -26,17 +26,34 @@ class SolverBlack : public CxxTest::TestSuite
void setUp() override;
void tearDown() override;
+ void testGetBooleanSort();
+ void testGetIntegerSort();
+ void testGetRealSort();
+ void testGetRegExpSort();
+ void testGetStringSort();
+ void testGetRoundingmodeSort();
+
+ void testMkArraySort();
void testMkBitVectorSort();
void testMkFloatingPointSort();
void testMkDatatypeSort();
void testMkFunctionSort();
+ void testMkParamSort();
void testMkPredicateSort();
+ void testMkRecordSort();
+ void testMkSetSort();
+ void testMkSortConstructorSort();
+ void testMkUninterpretedSort();
void testMkTupleSort();
+
void testDeclareFun();
void testDefineFun();
void testDefineFunRec();
void testDefineFunsRec();
+ void testMkRegexpEmpty();
+ void testMkRegexpSigma();
+
private:
Solver d_solver;
};
@@ -45,6 +62,53 @@ void SolverBlack::setUp() {}
void SolverBlack::tearDown() {}
+void SolverBlack::testGetBooleanSort()
+{
+ TS_ASSERT_THROWS_NOTHING(d_solver.getBooleanSort());
+}
+
+void SolverBlack::testGetIntegerSort()
+{
+ TS_ASSERT_THROWS_NOTHING(d_solver.getIntegerSort());
+}
+
+void SolverBlack::testGetRealSort()
+{
+ TS_ASSERT_THROWS_NOTHING(d_solver.getRealSort());
+}
+
+void SolverBlack::testGetRegExpSort()
+{
+ TS_ASSERT_THROWS_NOTHING(d_solver.getRegExpSort());
+}
+
+void SolverBlack::testGetStringSort()
+{
+ TS_ASSERT_THROWS_NOTHING(d_solver.getStringSort());
+}
+
+void SolverBlack::testGetRoundingmodeSort()
+{
+ TS_ASSERT_THROWS_NOTHING(d_solver.getRoundingmodeSort());
+}
+
+void SolverBlack::testMkArraySort()
+{
+ Sort boolSort = d_solver.getBooleanSort();
+ Sort intSort = d_solver.getIntegerSort();
+ Sort realSort = d_solver.getRealSort();
+ Sort bvSort = d_solver.mkBitVectorSort(32);
+ Sort fpSort = d_solver.mkFloatingPointSort(3, 5);
+ TS_ASSERT_THROWS_NOTHING(d_solver.mkArraySort(boolSort, boolSort));
+ TS_ASSERT_THROWS_NOTHING(d_solver.mkArraySort(intSort, intSort));
+ TS_ASSERT_THROWS_NOTHING(d_solver.mkArraySort(realSort, realSort));
+ TS_ASSERT_THROWS_NOTHING(d_solver.mkArraySort(bvSort, bvSort));
+ TS_ASSERT_THROWS_NOTHING(d_solver.mkArraySort(fpSort, fpSort));
+ TS_ASSERT_THROWS_NOTHING(d_solver.mkArraySort(boolSort, intSort));
+ TS_ASSERT_THROWS_NOTHING(d_solver.mkArraySort(realSort, bvSort));
+ TS_ASSERT_THROWS_NOTHING(d_solver.mkArraySort(bvSort, fpSort));
+}
+
void SolverBlack::testMkBitVectorSort()
{
TS_ASSERT_THROWS_NOTHING(d_solver.mkBitVectorSort(32));
@@ -97,6 +161,12 @@ void SolverBlack::testMkFunctionSort()
CVC4ApiException&);
}
+void SolverBlack::testMkParamSort()
+{
+ TS_ASSERT_THROWS_NOTHING(d_solver.mkParamSort("T"));
+ TS_ASSERT_THROWS_NOTHING(d_solver.mkParamSort(""));
+}
+
void SolverBlack::testMkPredicateSort()
{
TS_ASSERT_THROWS_NOTHING(
@@ -109,6 +179,37 @@ void SolverBlack::testMkPredicateSort()
CVC4ApiException&);
}
+void SolverBlack::testMkRecordSort()
+{
+ std::vector<std::pair<std::string, Sort>> fields = {
+ std::make_pair("b", d_solver.getBooleanSort()),
+ std::make_pair("bv", d_solver.mkBitVectorSort(8)),
+ std::make_pair("i", d_solver.getIntegerSort())};
+ std::vector<std::pair<std::string, Sort>> empty;
+ TS_ASSERT_THROWS_NOTHING(d_solver.mkRecordSort(fields));
+ TS_ASSERT_THROWS_NOTHING(d_solver.mkRecordSort(empty));
+}
+
+void SolverBlack::testMkSetSort()
+{
+ TS_ASSERT_THROWS_NOTHING(d_solver.mkSetSort(d_solver.getBooleanSort()));
+ TS_ASSERT_THROWS_NOTHING(d_solver.mkSetSort(d_solver.getIntegerSort()));
+ TS_ASSERT_THROWS_NOTHING(d_solver.mkSetSort(d_solver.mkBitVectorSort(4)));
+}
+
+void SolverBlack::testMkUninterpretedSort()
+{
+ TS_ASSERT_THROWS_NOTHING(d_solver.mkUninterpretedSort("u"));
+ TS_ASSERT_THROWS_NOTHING(d_solver.mkUninterpretedSort(""));
+}
+
+void SolverBlack::testMkSortConstructorSort()
+{
+ TS_ASSERT_THROWS_NOTHING(d_solver.mkSortConstructorSort("s", 2));
+ TS_ASSERT_THROWS_NOTHING(d_solver.mkSortConstructorSort("", 2));
+ TS_ASSERT_THROWS(d_solver.mkSortConstructorSort("", 0), CVC4ApiException&);
+}
+
void SolverBlack::testMkTupleSort()
{
TS_ASSERT_THROWS_NOTHING(d_solver.mkTupleSort({d_solver.getIntegerSort()}));
@@ -228,3 +329,19 @@ void SolverBlack::testDefineFunsRec()
d_solver.defineFunsRec({f1, f2}, {{b1, b11}, {b4}}, {v1, v4}),
CVC4ApiException&);
}
+
+void SolverBlack::testMkRegexpEmpty()
+{
+ Sort strSort = d_solver.getStringSort();
+ Term s = d_solver.mkVar("s", strSort);
+ TS_ASSERT_THROWS_NOTHING(
+ d_solver.mkTerm(STRING_IN_REGEXP, s, d_solver.mkRegexpEmpty()));
+}
+
+void SolverBlack::testMkRegexpSigma()
+{
+ Sort strSort = d_solver.getStringSort();
+ Term s = d_solver.mkVar("s", strSort);
+ TS_ASSERT_THROWS_NOTHING(
+ d_solver.mkTerm(STRING_IN_REGEXP, s, d_solver.mkRegexpSigma()));
+}
diff --git a/test/unit/api/term_black.h b/test/unit/api/term_black.h
index c2ca1cb08..ae1dfe7ba 100644
--- a/test/unit/api/term_black.h
+++ b/test/unit/api/term_black.h
@@ -2,7 +2,7 @@
/*! \file term_black.h
** \verbatim
** Top contributors (to current version):
- ** Andres Noetzli
+ ** Aina Niemetz, Andres Noetzli
** This file is part of the CVC4 project.
** Copyright (c) 2009-2018 by the authors listed in the file AUTHORS
** in the top-level source directory) and their institutional affiliations.
@@ -24,14 +24,520 @@ class TermBlack : public CxxTest::TestSuite
void setUp() override {}
void tearDown() override {}
- void testTermAssignment()
- {
- Term t1 = d_solver.mkReal(1);
- Term t2 = t1;
- t2 = d_solver.mkReal(2);
- TS_ASSERT_EQUALS(t1, d_solver.mkReal(1));
- }
+ void testEq();
+ void testGetKind();
+ void testGetSort();
+ void testIsNull();
+ void testNotTerm();
+ void testAndTerm();
+ void testOrTerm();
+ void testXorTerm();
+ void testEqTerm();
+ void testImpTerm();
+ void testIteTerm();
+
+ void testTermAssignment();
private:
Solver d_solver;
};
+
+void TermBlack::testEq()
+{
+ Sort uSort = d_solver.mkUninterpretedSort("u");
+ Term x = d_solver.mkVar("x", uSort);
+ Term y = d_solver.mkVar("y", uSort);
+ Term z;
+
+ TS_ASSERT(x == x);
+ TS_ASSERT(!(x != x));
+ TS_ASSERT(!(x == y));
+ TS_ASSERT(x != y);
+ TS_ASSERT(!(x == z));
+ TS_ASSERT(x != z);
+}
+
+void TermBlack::testGetKind()
+{
+ Sort uSort = d_solver.mkUninterpretedSort("u");
+ Sort intSort = d_solver.getIntegerSort();
+ Sort boolSort = d_solver.getBooleanSort();
+ Sort funSort1 = d_solver.mkFunctionSort(uSort, intSort);
+ Sort funSort2 = d_solver.mkFunctionSort(intSort, boolSort);
+
+ Term n;
+ TS_ASSERT_THROWS(n.getKind(), CVC4ApiException&);
+ Term x = d_solver.mkVar("x", uSort);
+ TS_ASSERT_THROWS_NOTHING(x.getKind());
+ Term y = d_solver.mkVar("y", uSort);
+ TS_ASSERT_THROWS_NOTHING(y.getKind());
+
+ Term f = d_solver.mkVar("f", funSort1);
+ TS_ASSERT_THROWS_NOTHING(f.getKind());
+ Term p = d_solver.mkVar("p", funSort2);
+ TS_ASSERT_THROWS_NOTHING(p.getKind());
+
+ Term zero = d_solver.mkInteger(0);
+ TS_ASSERT_THROWS_NOTHING(zero.getKind());
+
+ Term f_x = d_solver.mkTerm(APPLY_UF, f, x);
+ TS_ASSERT_THROWS_NOTHING(f_x.getKind());
+ Term f_y = d_solver.mkTerm(APPLY_UF, f, y);
+ TS_ASSERT_THROWS_NOTHING(f_y.getKind());
+ Term sum = d_solver.mkTerm(PLUS, f_x, f_y);
+ TS_ASSERT_THROWS_NOTHING(sum.getKind());
+ Term p_0 = d_solver.mkTerm(APPLY_UF, p, zero);
+ TS_ASSERT_THROWS_NOTHING(p_0.getKind());
+ Term p_f_y = d_solver.mkTerm(APPLY_UF, p, f_y);
+ TS_ASSERT_THROWS_NOTHING(p_f_y.getKind());
+}
+
+void TermBlack::testGetSort()
+{
+ Sort bvSort = d_solver.mkBitVectorSort(8);
+ Sort intSort = d_solver.getIntegerSort();
+ Sort boolSort = d_solver.getBooleanSort();
+ Sort funSort1 = d_solver.mkFunctionSort(bvSort, intSort);
+ Sort funSort2 = d_solver.mkFunctionSort(intSort, boolSort);
+
+ Term n;
+ TS_ASSERT_THROWS(n.getSort(), CVC4ApiException&);
+ Term x = d_solver.mkVar("x", bvSort);
+ TS_ASSERT_THROWS_NOTHING(x.getSort());
+ TS_ASSERT(x.getSort() == bvSort);
+ Term y = d_solver.mkVar("y", bvSort);
+ TS_ASSERT_THROWS_NOTHING(y.getSort());
+ TS_ASSERT(y.getSort() == bvSort);
+
+ Term f = d_solver.mkVar("f", funSort1);
+ TS_ASSERT_THROWS_NOTHING(f.getSort());
+ TS_ASSERT(f.getSort() == funSort1);
+ Term p = d_solver.mkVar("p", funSort2);
+ TS_ASSERT_THROWS_NOTHING(p.getSort());
+ TS_ASSERT(p.getSort() == funSort2);
+
+ Term zero = d_solver.mkInteger(0);
+ TS_ASSERT_THROWS_NOTHING(zero.getSort());
+ TS_ASSERT(zero.getSort() == intSort);
+
+ Term f_x = d_solver.mkTerm(APPLY_UF, f, x);
+ TS_ASSERT_THROWS_NOTHING(f_x.getSort());
+ TS_ASSERT(f_x.getSort() == intSort);
+ Term f_y = d_solver.mkTerm(APPLY_UF, f, y);
+ TS_ASSERT_THROWS_NOTHING(f_y.getSort());
+ TS_ASSERT(f_y.getSort() == intSort);
+ Term sum = d_solver.mkTerm(PLUS, f_x, f_y);
+ TS_ASSERT_THROWS_NOTHING(sum.getSort());
+ TS_ASSERT(sum.getSort() == intSort);
+ Term p_0 = d_solver.mkTerm(APPLY_UF, p, zero);
+ TS_ASSERT_THROWS_NOTHING(p_0.getSort());
+ TS_ASSERT(p_0.getSort() == boolSort);
+ Term p_f_y = d_solver.mkTerm(APPLY_UF, p, f_y);
+ TS_ASSERT_THROWS_NOTHING(p_f_y.getSort());
+ TS_ASSERT(p_f_y.getSort() == boolSort);
+}
+
+void TermBlack::testIsNull()
+{
+ Term x;
+ TS_ASSERT(x.isNull());
+ x = d_solver.mkVar("x", d_solver.mkBitVectorSort(4));
+ TS_ASSERT(!x.isNull());
+}
+
+void TermBlack::testNotTerm()
+{
+ Sort bvSort = d_solver.mkBitVectorSort(8);
+ Sort intSort = d_solver.getIntegerSort();
+ Sort boolSort = d_solver.getBooleanSort();
+ Sort funSort1 = d_solver.mkFunctionSort(bvSort, intSort);
+ Sort funSort2 = d_solver.mkFunctionSort(intSort, boolSort);
+
+ Term b = d_solver.mkTrue();
+ TS_ASSERT_THROWS_NOTHING(b.notTerm());
+ Term x = d_solver.mkVar("x", d_solver.mkBitVectorSort(8));
+ TS_ASSERT_THROWS(x.notTerm(), CVC4ApiException&);
+ Term f = d_solver.mkVar("f", funSort1);
+ TS_ASSERT_THROWS(f.notTerm(), CVC4ApiException&);
+ Term p = d_solver.mkVar("p", funSort2);
+ TS_ASSERT_THROWS(p.notTerm(), CVC4ApiException&);
+ Term zero = d_solver.mkInteger(0);
+ TS_ASSERT_THROWS(zero.notTerm(), CVC4ApiException&);
+ Term f_x = d_solver.mkTerm(APPLY_UF, f, x);
+ TS_ASSERT_THROWS(f_x.notTerm(), CVC4ApiException&);
+ Term sum = d_solver.mkTerm(PLUS, f_x, f_x);
+ TS_ASSERT_THROWS(sum.notTerm(), CVC4ApiException&);
+ Term p_0 = d_solver.mkTerm(APPLY_UF, p, zero);
+ TS_ASSERT_THROWS_NOTHING(p_0.notTerm());
+ Term p_f_x = d_solver.mkTerm(APPLY_UF, p, f_x);
+ TS_ASSERT_THROWS_NOTHING(p_f_x.notTerm());
+}
+
+void TermBlack::testAndTerm()
+{
+ Sort bvSort = d_solver.mkBitVectorSort(8);
+ Sort intSort = d_solver.getIntegerSort();
+ Sort boolSort = d_solver.getBooleanSort();
+ Sort funSort1 = d_solver.mkFunctionSort(bvSort, intSort);
+ Sort funSort2 = d_solver.mkFunctionSort(intSort, boolSort);
+
+ Term b = d_solver.mkTrue();
+ TS_ASSERT_THROWS_NOTHING(b.andTerm(b));
+ Term x = d_solver.mkVar("x", d_solver.mkBitVectorSort(8));
+ TS_ASSERT_THROWS(x.andTerm(b), CVC4ApiException&);
+ TS_ASSERT_THROWS(x.andTerm(x), CVC4ApiException&);
+ Term f = d_solver.mkVar("f", funSort1);
+ TS_ASSERT_THROWS(f.andTerm(b), CVC4ApiException&);
+ TS_ASSERT_THROWS(f.andTerm(x), CVC4ApiException&);
+ TS_ASSERT_THROWS(f.andTerm(f), CVC4ApiException&);
+ Term p = d_solver.mkVar("p", funSort2);
+ TS_ASSERT_THROWS(p.andTerm(b), CVC4ApiException&);
+ TS_ASSERT_THROWS(p.andTerm(x), CVC4ApiException&);
+ TS_ASSERT_THROWS(p.andTerm(f), CVC4ApiException&);
+ TS_ASSERT_THROWS(p.andTerm(p), CVC4ApiException&);
+ Term zero = d_solver.mkInteger(0);
+ TS_ASSERT_THROWS(zero.andTerm(b), CVC4ApiException&);
+ TS_ASSERT_THROWS(zero.andTerm(x), CVC4ApiException&);
+ TS_ASSERT_THROWS(zero.andTerm(f), CVC4ApiException&);
+ TS_ASSERT_THROWS(zero.andTerm(p), CVC4ApiException&);
+ TS_ASSERT_THROWS(zero.andTerm(zero), CVC4ApiException&);
+ Term f_x = d_solver.mkTerm(APPLY_UF, f, x);
+ TS_ASSERT_THROWS(f_x.andTerm(b), CVC4ApiException&);
+ TS_ASSERT_THROWS(f_x.andTerm(x), CVC4ApiException&);
+ TS_ASSERT_THROWS(f_x.andTerm(f), CVC4ApiException&);
+ TS_ASSERT_THROWS(f_x.andTerm(p), CVC4ApiException&);
+ TS_ASSERT_THROWS(f_x.andTerm(zero), CVC4ApiException&);
+ TS_ASSERT_THROWS(f_x.andTerm(f_x), CVC4ApiException&);
+ Term sum = d_solver.mkTerm(PLUS, f_x, f_x);
+ TS_ASSERT_THROWS(sum.andTerm(b), CVC4ApiException&);
+ TS_ASSERT_THROWS(sum.andTerm(x), CVC4ApiException&);
+ TS_ASSERT_THROWS(sum.andTerm(f), CVC4ApiException&);
+ TS_ASSERT_THROWS(sum.andTerm(p), CVC4ApiException&);
+ TS_ASSERT_THROWS(sum.andTerm(zero), CVC4ApiException&);
+ TS_ASSERT_THROWS(sum.andTerm(f_x), CVC4ApiException&);
+ TS_ASSERT_THROWS(sum.andTerm(sum), CVC4ApiException&);
+ Term p_0 = d_solver.mkTerm(APPLY_UF, p, zero);
+ TS_ASSERT_THROWS_NOTHING(p_0.andTerm(b));
+ TS_ASSERT_THROWS(p_0.andTerm(x), CVC4ApiException&);
+ TS_ASSERT_THROWS(p_0.andTerm(f), CVC4ApiException&);
+ TS_ASSERT_THROWS(p_0.andTerm(p), CVC4ApiException&);
+ TS_ASSERT_THROWS(p_0.andTerm(zero), CVC4ApiException&);
+ TS_ASSERT_THROWS(p_0.andTerm(f_x), CVC4ApiException&);
+ TS_ASSERT_THROWS(p_0.andTerm(sum), CVC4ApiException&);
+ TS_ASSERT_THROWS_NOTHING(p_0.andTerm(p_0));
+ Term p_f_x = d_solver.mkTerm(APPLY_UF, p, f_x);
+ TS_ASSERT_THROWS_NOTHING(p_f_x.andTerm(b));
+ TS_ASSERT_THROWS(p_f_x.andTerm(x), CVC4ApiException&);
+ TS_ASSERT_THROWS(p_f_x.andTerm(f), CVC4ApiException&);
+ TS_ASSERT_THROWS(p_f_x.andTerm(p), CVC4ApiException&);
+ TS_ASSERT_THROWS(p_f_x.andTerm(zero), CVC4ApiException&);
+ TS_ASSERT_THROWS(p_f_x.andTerm(f_x), CVC4ApiException&);
+ TS_ASSERT_THROWS(p_f_x.andTerm(sum), CVC4ApiException&);
+ TS_ASSERT_THROWS_NOTHING(p_f_x.andTerm(p_0));
+ TS_ASSERT_THROWS_NOTHING(p_f_x.andTerm(p_f_x));
+}
+
+void TermBlack::testOrTerm()
+{
+ Sort bvSort = d_solver.mkBitVectorSort(8);
+ Sort intSort = d_solver.getIntegerSort();
+ Sort boolSort = d_solver.getBooleanSort();
+ Sort funSort1 = d_solver.mkFunctionSort(bvSort, intSort);
+ Sort funSort2 = d_solver.mkFunctionSort(intSort, boolSort);
+
+ Term b = d_solver.mkTrue();
+ TS_ASSERT_THROWS_NOTHING(b.orTerm(b));
+ Term x = d_solver.mkVar("x", d_solver.mkBitVectorSort(8));
+ TS_ASSERT_THROWS(x.orTerm(b), CVC4ApiException&);
+ TS_ASSERT_THROWS(x.orTerm(x), CVC4ApiException&);
+ Term f = d_solver.mkVar("f", funSort1);
+ TS_ASSERT_THROWS(f.orTerm(b), CVC4ApiException&);
+ TS_ASSERT_THROWS(f.orTerm(x), CVC4ApiException&);
+ TS_ASSERT_THROWS(f.orTerm(f), CVC4ApiException&);
+ Term p = d_solver.mkVar("p", funSort2);
+ TS_ASSERT_THROWS(p.orTerm(b), CVC4ApiException&);
+ TS_ASSERT_THROWS(p.orTerm(x), CVC4ApiException&);
+ TS_ASSERT_THROWS(p.orTerm(f), CVC4ApiException&);
+ TS_ASSERT_THROWS(p.orTerm(p), CVC4ApiException&);
+ Term zero = d_solver.mkInteger(0);
+ TS_ASSERT_THROWS(zero.orTerm(b), CVC4ApiException&);
+ TS_ASSERT_THROWS(zero.orTerm(x), CVC4ApiException&);
+ TS_ASSERT_THROWS(zero.orTerm(f), CVC4ApiException&);
+ TS_ASSERT_THROWS(zero.orTerm(p), CVC4ApiException&);
+ TS_ASSERT_THROWS(zero.orTerm(zero), CVC4ApiException&);
+ Term f_x = d_solver.mkTerm(APPLY_UF, f, x);
+ TS_ASSERT_THROWS(f_x.orTerm(b), CVC4ApiException&);
+ TS_ASSERT_THROWS(f_x.orTerm(x), CVC4ApiException&);
+ TS_ASSERT_THROWS(f_x.orTerm(f), CVC4ApiException&);
+ TS_ASSERT_THROWS(f_x.orTerm(p), CVC4ApiException&);
+ TS_ASSERT_THROWS(f_x.orTerm(zero), CVC4ApiException&);
+ TS_ASSERT_THROWS(f_x.orTerm(f_x), CVC4ApiException&);
+ Term sum = d_solver.mkTerm(PLUS, f_x, f_x);
+ TS_ASSERT_THROWS(sum.orTerm(b), CVC4ApiException&);
+ TS_ASSERT_THROWS(sum.orTerm(x), CVC4ApiException&);
+ TS_ASSERT_THROWS(sum.orTerm(f), CVC4ApiException&);
+ TS_ASSERT_THROWS(sum.orTerm(p), CVC4ApiException&);
+ TS_ASSERT_THROWS(sum.orTerm(zero), CVC4ApiException&);
+ TS_ASSERT_THROWS(sum.orTerm(f_x), CVC4ApiException&);
+ TS_ASSERT_THROWS(sum.orTerm(sum), CVC4ApiException&);
+ Term p_0 = d_solver.mkTerm(APPLY_UF, p, zero);
+ TS_ASSERT_THROWS_NOTHING(p_0.orTerm(b));
+ TS_ASSERT_THROWS(p_0.orTerm(x), CVC4ApiException&);
+ TS_ASSERT_THROWS(p_0.orTerm(f), CVC4ApiException&);
+ TS_ASSERT_THROWS(p_0.orTerm(p), CVC4ApiException&);
+ TS_ASSERT_THROWS(p_0.orTerm(zero), CVC4ApiException&);
+ TS_ASSERT_THROWS(p_0.orTerm(f_x), CVC4ApiException&);
+ TS_ASSERT_THROWS(p_0.orTerm(sum), CVC4ApiException&);
+ TS_ASSERT_THROWS_NOTHING(p_0.orTerm(p_0));
+ Term p_f_x = d_solver.mkTerm(APPLY_UF, p, f_x);
+ TS_ASSERT_THROWS_NOTHING(p_f_x.orTerm(b));
+ TS_ASSERT_THROWS(p_f_x.orTerm(x), CVC4ApiException&);
+ TS_ASSERT_THROWS(p_f_x.orTerm(f), CVC4ApiException&);
+ TS_ASSERT_THROWS(p_f_x.orTerm(p), CVC4ApiException&);
+ TS_ASSERT_THROWS(p_f_x.orTerm(zero), CVC4ApiException&);
+ TS_ASSERT_THROWS(p_f_x.orTerm(f_x), CVC4ApiException&);
+ TS_ASSERT_THROWS(p_f_x.orTerm(sum), CVC4ApiException&);
+ TS_ASSERT_THROWS_NOTHING(p_f_x.orTerm(p_0));
+ TS_ASSERT_THROWS_NOTHING(p_f_x.orTerm(p_f_x));
+}
+
+void TermBlack::testXorTerm()
+{
+ Sort bvSort = d_solver.mkBitVectorSort(8);
+ Sort intSort = d_solver.getIntegerSort();
+ Sort boolSort = d_solver.getBooleanSort();
+ Sort funSort1 = d_solver.mkFunctionSort(bvSort, intSort);
+ Sort funSort2 = d_solver.mkFunctionSort(intSort, boolSort);
+
+ Term b = d_solver.mkTrue();
+ TS_ASSERT_THROWS_NOTHING(b.xorTerm(b));
+ Term x = d_solver.mkVar("x", d_solver.mkBitVectorSort(8));
+ TS_ASSERT_THROWS(x.xorTerm(b), CVC4ApiException&);
+ TS_ASSERT_THROWS(x.xorTerm(x), CVC4ApiException&);
+ Term f = d_solver.mkVar("f", funSort1);
+ TS_ASSERT_THROWS(f.xorTerm(b), CVC4ApiException&);
+ TS_ASSERT_THROWS(f.xorTerm(x), CVC4ApiException&);
+ TS_ASSERT_THROWS(f.xorTerm(f), CVC4ApiException&);
+ Term p = d_solver.mkVar("p", funSort2);
+ TS_ASSERT_THROWS(p.xorTerm(b), CVC4ApiException&);
+ TS_ASSERT_THROWS(p.xorTerm(x), CVC4ApiException&);
+ TS_ASSERT_THROWS(p.xorTerm(f), CVC4ApiException&);
+ TS_ASSERT_THROWS(p.xorTerm(p), CVC4ApiException&);
+ Term zero = d_solver.mkInteger(0);
+ TS_ASSERT_THROWS(zero.xorTerm(b), CVC4ApiException&);
+ TS_ASSERT_THROWS(zero.xorTerm(x), CVC4ApiException&);
+ TS_ASSERT_THROWS(zero.xorTerm(f), CVC4ApiException&);
+ TS_ASSERT_THROWS(zero.xorTerm(p), CVC4ApiException&);
+ TS_ASSERT_THROWS(zero.xorTerm(zero), CVC4ApiException&);
+ Term f_x = d_solver.mkTerm(APPLY_UF, f, x);
+ TS_ASSERT_THROWS(f_x.xorTerm(b), CVC4ApiException&);
+ TS_ASSERT_THROWS(f_x.xorTerm(x), CVC4ApiException&);
+ TS_ASSERT_THROWS(f_x.xorTerm(f), CVC4ApiException&);
+ TS_ASSERT_THROWS(f_x.xorTerm(p), CVC4ApiException&);
+ TS_ASSERT_THROWS(f_x.xorTerm(zero), CVC4ApiException&);
+ TS_ASSERT_THROWS(f_x.xorTerm(f_x), CVC4ApiException&);
+ Term sum = d_solver.mkTerm(PLUS, f_x, f_x);
+ TS_ASSERT_THROWS(sum.xorTerm(b), CVC4ApiException&);
+ TS_ASSERT_THROWS(sum.xorTerm(x), CVC4ApiException&);
+ TS_ASSERT_THROWS(sum.xorTerm(f), CVC4ApiException&);
+ TS_ASSERT_THROWS(sum.xorTerm(p), CVC4ApiException&);
+ TS_ASSERT_THROWS(sum.xorTerm(zero), CVC4ApiException&);
+ TS_ASSERT_THROWS(sum.xorTerm(f_x), CVC4ApiException&);
+ TS_ASSERT_THROWS(sum.xorTerm(sum), CVC4ApiException&);
+ Term p_0 = d_solver.mkTerm(APPLY_UF, p, zero);
+ TS_ASSERT_THROWS_NOTHING(p_0.xorTerm(b));
+ TS_ASSERT_THROWS(p_0.xorTerm(x), CVC4ApiException&);
+ TS_ASSERT_THROWS(p_0.xorTerm(f), CVC4ApiException&);
+ TS_ASSERT_THROWS(p_0.xorTerm(p), CVC4ApiException&);
+ TS_ASSERT_THROWS(p_0.xorTerm(zero), CVC4ApiException&);
+ TS_ASSERT_THROWS(p_0.xorTerm(f_x), CVC4ApiException&);
+ TS_ASSERT_THROWS(p_0.xorTerm(sum), CVC4ApiException&);
+ TS_ASSERT_THROWS_NOTHING(p_0.xorTerm(p_0));
+ Term p_f_x = d_solver.mkTerm(APPLY_UF, p, f_x);
+ TS_ASSERT_THROWS_NOTHING(p_f_x.xorTerm(b));
+ TS_ASSERT_THROWS(p_f_x.xorTerm(x), CVC4ApiException&);
+ TS_ASSERT_THROWS(p_f_x.xorTerm(f), CVC4ApiException&);
+ TS_ASSERT_THROWS(p_f_x.xorTerm(p), CVC4ApiException&);
+ TS_ASSERT_THROWS(p_f_x.xorTerm(zero), CVC4ApiException&);
+ TS_ASSERT_THROWS(p_f_x.xorTerm(f_x), CVC4ApiException&);
+ TS_ASSERT_THROWS(p_f_x.xorTerm(sum), CVC4ApiException&);
+ TS_ASSERT_THROWS_NOTHING(p_f_x.xorTerm(p_0));
+ TS_ASSERT_THROWS_NOTHING(p_f_x.xorTerm(p_f_x));
+}
+
+void TermBlack::testEqTerm()
+{
+ Sort bvSort = d_solver.mkBitVectorSort(8);
+ Sort intSort = d_solver.getIntegerSort();
+ Sort boolSort = d_solver.getBooleanSort();
+ Sort funSort1 = d_solver.mkFunctionSort(bvSort, intSort);
+ Sort funSort2 = d_solver.mkFunctionSort(intSort, boolSort);
+
+ Term b = d_solver.mkTrue();
+ TS_ASSERT_THROWS_NOTHING(b.eqTerm(b));
+ Term x = d_solver.mkVar("x", d_solver.mkBitVectorSort(8));
+ TS_ASSERT_THROWS(x.eqTerm(b), CVC4ApiException&);
+ TS_ASSERT_THROWS_NOTHING(x.eqTerm(x));
+ Term f = d_solver.mkVar("f", funSort1);
+ TS_ASSERT_THROWS(f.eqTerm(b), CVC4ApiException&);
+ TS_ASSERT_THROWS(f.eqTerm(x), CVC4ApiException&);
+ TS_ASSERT_THROWS_NOTHING(f.eqTerm(f));
+ Term p = d_solver.mkVar("p", funSort2);
+ TS_ASSERT_THROWS(p.eqTerm(b), CVC4ApiException&);
+ TS_ASSERT_THROWS(p.eqTerm(x), CVC4ApiException&);
+ TS_ASSERT_THROWS(p.eqTerm(f), CVC4ApiException&);
+ TS_ASSERT_THROWS_NOTHING(p.eqTerm(p));
+ Term zero = d_solver.mkInteger(0);
+ TS_ASSERT_THROWS(zero.eqTerm(b), CVC4ApiException&);
+ TS_ASSERT_THROWS(zero.eqTerm(x), CVC4ApiException&);
+ TS_ASSERT_THROWS(zero.eqTerm(f), CVC4ApiException&);
+ TS_ASSERT_THROWS(zero.eqTerm(p), CVC4ApiException&);
+ TS_ASSERT_THROWS_NOTHING(zero.eqTerm(zero));
+ Term f_x = d_solver.mkTerm(APPLY_UF, f, x);
+ TS_ASSERT_THROWS(f_x.eqTerm(b), CVC4ApiException&);
+ TS_ASSERT_THROWS(f_x.eqTerm(x), CVC4ApiException&);
+ TS_ASSERT_THROWS(f_x.eqTerm(f), CVC4ApiException&);
+ TS_ASSERT_THROWS(f_x.eqTerm(p), CVC4ApiException&);
+ TS_ASSERT_THROWS_NOTHING(f_x.eqTerm(zero));
+ TS_ASSERT_THROWS_NOTHING(f_x.eqTerm(f_x));
+ Term sum = d_solver.mkTerm(PLUS, f_x, f_x);
+ TS_ASSERT_THROWS(sum.eqTerm(b), CVC4ApiException&);
+ TS_ASSERT_THROWS(sum.eqTerm(x), CVC4ApiException&);
+ TS_ASSERT_THROWS(sum.eqTerm(f), CVC4ApiException&);
+ TS_ASSERT_THROWS(sum.eqTerm(p), CVC4ApiException&);
+ TS_ASSERT_THROWS_NOTHING(sum.eqTerm(zero));
+ TS_ASSERT_THROWS_NOTHING(sum.eqTerm(f_x));
+ TS_ASSERT_THROWS_NOTHING(sum.eqTerm(sum));
+ Term p_0 = d_solver.mkTerm(APPLY_UF, p, zero);
+ TS_ASSERT_THROWS_NOTHING(p_0.eqTerm(b));
+ TS_ASSERT_THROWS(p_0.eqTerm(x), CVC4ApiException&);
+ TS_ASSERT_THROWS(p_0.eqTerm(f), CVC4ApiException&);
+ TS_ASSERT_THROWS(p_0.eqTerm(p), CVC4ApiException&);
+ TS_ASSERT_THROWS(p_0.eqTerm(zero), CVC4ApiException&);
+ TS_ASSERT_THROWS(p_0.eqTerm(f_x), CVC4ApiException&);
+ TS_ASSERT_THROWS(p_0.eqTerm(sum), CVC4ApiException&);
+ TS_ASSERT_THROWS_NOTHING(p_0.eqTerm(p_0));
+ Term p_f_x = d_solver.mkTerm(APPLY_UF, p, f_x);
+ TS_ASSERT_THROWS_NOTHING(p_f_x.eqTerm(b));
+ TS_ASSERT_THROWS(p_f_x.eqTerm(x), CVC4ApiException&);
+ TS_ASSERT_THROWS(p_f_x.eqTerm(f), CVC4ApiException&);
+ TS_ASSERT_THROWS(p_f_x.eqTerm(p), CVC4ApiException&);
+ TS_ASSERT_THROWS(p_f_x.eqTerm(zero), CVC4ApiException&);
+ TS_ASSERT_THROWS(p_f_x.eqTerm(f_x), CVC4ApiException&);
+ TS_ASSERT_THROWS(p_f_x.eqTerm(sum), CVC4ApiException&);
+ TS_ASSERT_THROWS_NOTHING(p_f_x.eqTerm(p_0));
+ TS_ASSERT_THROWS_NOTHING(p_f_x.eqTerm(p_f_x));
+}
+
+void TermBlack::testImpTerm()
+{
+ Sort bvSort = d_solver.mkBitVectorSort(8);
+ Sort intSort = d_solver.getIntegerSort();
+ Sort boolSort = d_solver.getBooleanSort();
+ Sort funSort1 = d_solver.mkFunctionSort(bvSort, intSort);
+ Sort funSort2 = d_solver.mkFunctionSort(intSort, boolSort);
+
+ Term b = d_solver.mkTrue();
+ TS_ASSERT_THROWS_NOTHING(b.impTerm(b));
+ Term x = d_solver.mkVar("x", d_solver.mkBitVectorSort(8));
+ TS_ASSERT_THROWS(x.impTerm(b), CVC4ApiException&);
+ TS_ASSERT_THROWS(x.impTerm(x), CVC4ApiException&);
+ Term f = d_solver.mkVar("f", funSort1);
+ TS_ASSERT_THROWS(f.impTerm(b), CVC4ApiException&);
+ TS_ASSERT_THROWS(f.impTerm(x), CVC4ApiException&);
+ TS_ASSERT_THROWS(f.impTerm(f), CVC4ApiException&);
+ Term p = d_solver.mkVar("p", funSort2);
+ TS_ASSERT_THROWS(p.impTerm(b), CVC4ApiException&);
+ TS_ASSERT_THROWS(p.impTerm(x), CVC4ApiException&);
+ TS_ASSERT_THROWS(p.impTerm(f), CVC4ApiException&);
+ TS_ASSERT_THROWS(p.impTerm(p), CVC4ApiException&);
+ Term zero = d_solver.mkInteger(0);
+ TS_ASSERT_THROWS(zero.impTerm(b), CVC4ApiException&);
+ TS_ASSERT_THROWS(zero.impTerm(x), CVC4ApiException&);
+ TS_ASSERT_THROWS(zero.impTerm(f), CVC4ApiException&);
+ TS_ASSERT_THROWS(zero.impTerm(p), CVC4ApiException&);
+ TS_ASSERT_THROWS(zero.impTerm(zero), CVC4ApiException&);
+ Term f_x = d_solver.mkTerm(APPLY_UF, f, x);
+ TS_ASSERT_THROWS(f_x.impTerm(b), CVC4ApiException&);
+ TS_ASSERT_THROWS(f_x.impTerm(x), CVC4ApiException&);
+ TS_ASSERT_THROWS(f_x.impTerm(f), CVC4ApiException&);
+ TS_ASSERT_THROWS(f_x.impTerm(p), CVC4ApiException&);
+ TS_ASSERT_THROWS(f_x.impTerm(zero), CVC4ApiException&);
+ TS_ASSERT_THROWS(f_x.impTerm(f_x), CVC4ApiException&);
+ Term sum = d_solver.mkTerm(PLUS, f_x, f_x);
+ TS_ASSERT_THROWS(sum.impTerm(b), CVC4ApiException&);
+ TS_ASSERT_THROWS(sum.impTerm(x), CVC4ApiException&);
+ TS_ASSERT_THROWS(sum.impTerm(f), CVC4ApiException&);
+ TS_ASSERT_THROWS(sum.impTerm(p), CVC4ApiException&);
+ TS_ASSERT_THROWS(sum.impTerm(zero), CVC4ApiException&);
+ TS_ASSERT_THROWS(sum.impTerm(f_x), CVC4ApiException&);
+ TS_ASSERT_THROWS(sum.impTerm(sum), CVC4ApiException&);
+ Term p_0 = d_solver.mkTerm(APPLY_UF, p, zero);
+ TS_ASSERT_THROWS_NOTHING(p_0.impTerm(b));
+ TS_ASSERT_THROWS(p_0.impTerm(x), CVC4ApiException&);
+ TS_ASSERT_THROWS(p_0.impTerm(f), CVC4ApiException&);
+ TS_ASSERT_THROWS(p_0.impTerm(p), CVC4ApiException&);
+ TS_ASSERT_THROWS(p_0.impTerm(zero), CVC4ApiException&);
+ TS_ASSERT_THROWS(p_0.impTerm(f_x), CVC4ApiException&);
+ TS_ASSERT_THROWS(p_0.impTerm(sum), CVC4ApiException&);
+ TS_ASSERT_THROWS_NOTHING(p_0.impTerm(p_0));
+ Term p_f_x = d_solver.mkTerm(APPLY_UF, p, f_x);
+ TS_ASSERT_THROWS_NOTHING(p_f_x.impTerm(b));
+ TS_ASSERT_THROWS(p_f_x.impTerm(x), CVC4ApiException&);
+ TS_ASSERT_THROWS(p_f_x.impTerm(f), CVC4ApiException&);
+ TS_ASSERT_THROWS(p_f_x.impTerm(p), CVC4ApiException&);
+ TS_ASSERT_THROWS(p_f_x.impTerm(zero), CVC4ApiException&);
+ TS_ASSERT_THROWS(p_f_x.impTerm(f_x), CVC4ApiException&);
+ TS_ASSERT_THROWS(p_f_x.impTerm(sum), CVC4ApiException&);
+ TS_ASSERT_THROWS_NOTHING(p_f_x.impTerm(p_0));
+ TS_ASSERT_THROWS_NOTHING(p_f_x.impTerm(p_f_x));
+}
+
+void TermBlack::testIteTerm()
+{
+ Sort bvSort = d_solver.mkBitVectorSort(8);
+ Sort intSort = d_solver.getIntegerSort();
+ Sort boolSort = d_solver.getBooleanSort();
+ Sort funSort1 = d_solver.mkFunctionSort(bvSort, intSort);
+ Sort funSort2 = d_solver.mkFunctionSort(intSort, boolSort);
+
+ Term b = d_solver.mkTrue();
+ TS_ASSERT_THROWS_NOTHING(b.iteTerm(b, b));
+ Term x = d_solver.mkVar("x", d_solver.mkBitVectorSort(8));
+ TS_ASSERT_THROWS_NOTHING(b.iteTerm(x, x));
+ TS_ASSERT_THROWS_NOTHING(b.iteTerm(b, b));
+ TS_ASSERT_THROWS(b.iteTerm(x, b), CVC4ApiException&);
+ TS_ASSERT_THROWS(x.iteTerm(x, x), CVC4ApiException&);
+ TS_ASSERT_THROWS(x.iteTerm(x, b), CVC4ApiException&);
+ Term f = d_solver.mkVar("f", funSort1);
+ TS_ASSERT_THROWS(f.iteTerm(b, b), CVC4ApiException&);
+ TS_ASSERT_THROWS(x.iteTerm(b, x), CVC4ApiException&);
+ Term p = d_solver.mkVar("p", funSort2);
+ TS_ASSERT_THROWS(p.iteTerm(b, b), CVC4ApiException&);
+ TS_ASSERT_THROWS(p.iteTerm(x, b), CVC4ApiException&);
+ Term zero = d_solver.mkInteger(0);
+ TS_ASSERT_THROWS(zero.iteTerm(x, x), CVC4ApiException&);
+ TS_ASSERT_THROWS(zero.iteTerm(x, b), CVC4ApiException&);
+ Term f_x = d_solver.mkTerm(APPLY_UF, f, x);
+ TS_ASSERT_THROWS(f_x.iteTerm(b, b), CVC4ApiException&);
+ TS_ASSERT_THROWS(f_x.iteTerm(b, x), CVC4ApiException&);
+ Term sum = d_solver.mkTerm(PLUS, f_x, f_x);
+ TS_ASSERT_THROWS(sum.iteTerm(x, x), CVC4ApiException&);
+ TS_ASSERT_THROWS(sum.iteTerm(b, x), CVC4ApiException&);
+ Term p_0 = d_solver.mkTerm(APPLY_UF, p, zero);
+ TS_ASSERT_THROWS_NOTHING(p_0.iteTerm(b, b));
+ TS_ASSERT_THROWS_NOTHING(p_0.iteTerm(x, x));
+ TS_ASSERT_THROWS(p_0.iteTerm(x, b), CVC4ApiException&);
+ Term p_f_x = d_solver.mkTerm(APPLY_UF, p, f_x);
+ TS_ASSERT_THROWS_NOTHING(p_f_x.iteTerm(b, b));
+ TS_ASSERT_THROWS_NOTHING(p_f_x.iteTerm(x, x));
+ TS_ASSERT_THROWS(p_f_x.iteTerm(x, b), CVC4ApiException&);
+}
+
+void TermBlack::testTermAssignment()
+{
+ Term t1 = d_solver.mkReal(1);
+ Term t2 = t1;
+ t2 = d_solver.mkReal(2);
+ TS_ASSERT_EQUALS(t1, d_solver.mkReal(1));
+}
generated by cgit on debian on lair
contact matthew@masot.net with questions or feedback