summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/Makefile.am2
-rw-r--r--src/bindings/Makefile.am32
-rw-r--r--src/bindings/compat/c/Makefile.am4
-rw-r--r--src/bindings/compat/java/Makefile.am4
-rw-r--r--src/compat/Makefile.am4
-rw-r--r--src/expr/command.cpp73
-rw-r--r--src/expr/command.h23
-rw-r--r--src/expr/options6
-rw-r--r--src/main/command_executor.cpp22
-rw-r--r--src/main/command_executor_portfolio.cpp11
-rw-r--r--src/main/driver_unified.cpp11
-rw-r--r--src/main/options2
-rwxr-xr-xsrc/options/mkoptions4
-rw-r--r--src/parser/Makefile.am2
-rw-r--r--src/parser/cvc/Cvc.g39
-rw-r--r--src/parser/smt2/Smt2.g102
-rw-r--r--src/parser/smt2/smt2.cpp1
-rw-r--r--src/parser/smt2/smt2.h34
-rw-r--r--src/printer/cvc/cvc_printer.cpp7
-rw-r--r--src/printer/printer.cpp13
-rw-r--r--src/printer/printer.h9
-rw-r--r--src/printer/smt2/smt2_printer.cpp19
-rw-r--r--src/printer/smt2/smt2_printer.h3
-rw-r--r--src/proof/cnf_proof.cpp128
-rw-r--r--src/proof/cnf_proof.h40
-rw-r--r--src/proof/proof.h6
-rw-r--r--src/proof/proof_manager.cpp119
-rw-r--r--src/proof/proof_manager.h63
-rw-r--r--src/proof/sat_proof.cpp77
-rw-r--r--src/proof/sat_proof.h16
-rw-r--r--src/prop/bvminisat/bvminisat.cpp8
-rw-r--r--src/prop/bvminisat/bvminisat.h6
-rw-r--r--src/prop/cnf_stream.cpp28
-rw-r--r--src/prop/cnf_stream.h28
-rw-r--r--src/prop/minisat/core/Solver.cc37
-rw-r--r--src/prop/minisat/core/Solver.h44
-rw-r--r--src/prop/minisat/minisat.cpp13
-rw-r--r--src/prop/minisat/minisat.h3
-rw-r--r--src/prop/minisat/simp/SimpSolver.cc8
-rw-r--r--src/prop/minisat/simp/SimpSolver.h26
-rw-r--r--src/prop/prop_engine.cpp11
-rw-r--r--src/prop/prop_engine.h3
-rw-r--r--src/prop/sat_solver.h6
-rw-r--r--src/prop/theory_proxy.cpp2
-rw-r--r--src/smt/options8
-rw-r--r--src/smt/options_handlers.h12
-rw-r--r--src/smt/simplification_mode.cpp3
-rw-r--r--src/smt/simplification_mode.h2
-rw-r--r--src/smt/smt_engine.cpp668
-rw-r--r--src/smt/smt_engine.h28
-rw-r--r--src/smt/smt_engine_scope.h7
-rw-r--r--src/theory/arith/theory_arith_private.cpp2
-rw-r--r--src/theory/arrays/array_info.cpp24
-rw-r--r--src/theory/arrays/array_info.h6
-rw-r--r--src/theory/arrays/options11
-rw-r--r--src/theory/arrays/theory_arrays.cpp136
-rw-r--r--src/theory/arrays/theory_arrays.h4
-rw-r--r--src/theory/booleans/circuit_propagator.h2
-rw-r--r--src/theory/builtin/kinds4
-rw-r--r--src/theory/builtin/theory_builtin_type_rules.h21
-rw-r--r--src/theory/bv/aig_bitblaster.cpp2
-rw-r--r--src/theory/bv/bitblaster_template.h83
-rw-r--r--src/theory/bv/bv_quick_check.cpp2
-rw-r--r--src/theory/bv/bv_subtheory_bitblast.cpp76
-rw-r--r--src/theory/bv/bv_subtheory_bitblast.h2
-rw-r--r--src/theory/bv/eager_bitblaster.cpp31
-rw-r--r--src/theory/bv/lazy_bitblaster.cpp108
-rw-r--r--src/theory/bv/theory_bv.cpp7
-rw-r--r--src/theory/bv/theory_bv.h3
-rw-r--r--src/theory/datatypes/kinds6
-rw-r--r--src/theory/datatypes/options2
-rw-r--r--src/theory/datatypes/theory_datatypes.cpp99
-rw-r--r--src/theory/datatypes/theory_datatypes.h4
-rw-r--r--src/theory/datatypes/theory_datatypes_type_rules.h43
-rw-r--r--src/theory/datatypes/type_enumerator.h288
-rw-r--r--src/theory/idl/theory_idl.cpp4
-rw-r--r--src/theory/quantifiers/bounded_integers.cpp13
-rw-r--r--src/theory/quantifiers/bounded_integers.h3
-rw-r--r--src/theory/quantifiers/candidate_generator.cpp8
-rw-r--r--src/theory/quantifiers/candidate_generator.h4
-rwxr-xr-xsrc/theory/quantifiers/conjecture_generator.cpp2214
-rwxr-xr-xsrc/theory/quantifiers/conjecture_generator.h446
-rw-r--r--src/theory/quantifiers/first_order_model.cpp18
-rw-r--r--src/theory/quantifiers/first_order_model.h13
-rw-r--r--src/theory/quantifiers/full_model_check.cpp10
-rw-r--r--src/theory/quantifiers/inst_match_generator.cpp173
-rw-r--r--src/theory/quantifiers/inst_match_generator.h47
-rw-r--r--src/theory/quantifiers/inst_strategy_e_matching.cpp45
-rw-r--r--src/theory/quantifiers/inst_strategy_e_matching.h4
-rw-r--r--src/theory/quantifiers/instantiation_engine.cpp86
-rw-r--r--src/theory/quantifiers/instantiation_engine.h4
-rw-r--r--src/theory/quantifiers/kinds2
-rw-r--r--src/theory/quantifiers/macros.cpp4
-rw-r--r--src/theory/quantifiers/model_engine.cpp19
-rw-r--r--src/theory/quantifiers/model_engine.h3
-rw-r--r--src/theory/quantifiers/modes.h9
-rw-r--r--src/theory/quantifiers/options35
-rw-r--r--src/theory/quantifiers/options_handlers.h28
-rwxr-xr-x[-rw-r--r--]src/theory/quantifiers/quant_conflict_find.cpp4775
-rwxr-xr-x[-rw-r--r--]src/theory/quantifiers/quant_conflict_find.h556
-rw-r--r--src/theory/quantifiers/quantifiers_attributes.cpp22
-rw-r--r--src/theory/quantifiers/quantifiers_attributes.h2
-rw-r--r--src/theory/quantifiers/quantifiers_rewriter.cpp48
-rw-r--r--src/theory/quantifiers/rewrite_engine.cpp13
-rw-r--r--src/theory/quantifiers/rewrite_engine.h3
-rw-r--r--src/theory/quantifiers/term_database.cpp397
-rw-r--r--src/theory/quantifiers/term_database.h53
-rw-r--r--src/theory/quantifiers/theory_quantifiers.cpp10
-rw-r--r--src/theory/quantifiers/theory_quantifiers.h2
-rw-r--r--src/theory/quantifiers/theory_quantifiers_type_rules.h9
-rw-r--r--src/theory/quantifiers/trigger.cpp199
-rw-r--r--src/theory/quantifiers/trigger.h13
-rw-r--r--src/theory/quantifiers_engine.cpp197
-rw-r--r--src/theory/quantifiers_engine.h27
-rw-r--r--src/theory/rep_set.cpp3
-rw-r--r--src/theory/sets/options3
-rw-r--r--src/theory/sets/theory_sets.cpp11
-rw-r--r--src/theory/sets/theory_sets.h4
-rw-r--r--src/theory/sets/theory_sets_private.cpp212
-rw-r--r--src/theory/sets/theory_sets_private.h14
-rw-r--r--src/theory/sets/theory_sets_type_rules.h2
-rw-r--r--src/theory/strings/kinds5
-rw-r--r--src/theory/strings/regexp_operation.cpp230
-rw-r--r--src/theory/strings/regexp_operation.h5
-rw-r--r--src/theory/strings/theory_strings.cpp11
-rw-r--r--src/theory/strings/theory_strings_rewriter.cpp19
-rw-r--r--src/theory/strings/theory_strings_type_rules.h15
-rw-r--r--src/theory/theory.h4
-rw-r--r--src/theory/theory_engine.cpp69
-rw-r--r--src/theory/theory_engine.h7
-rw-r--r--src/theory/uf/options4
-rw-r--r--src/theory/uf/options_handlers.h41
-rw-r--r--src/theory/uf/theory_uf.cpp6
-rw-r--r--src/theory/uf/theory_uf_strong_solver.cpp46
-rw-r--r--src/theory/uf/theory_uf_strong_solver.h6
-rw-r--r--src/theory/valuation.cpp8
-rw-r--r--src/util/Makefile.am7
-rw-r--r--src/util/datatype.cpp8
-rw-r--r--src/util/ite_removal.cpp13
-rw-r--r--src/util/ite_removal.h5
-rw-r--r--src/util/unsat_core.cpp49
-rw-r--r--src/util/unsat_core.h66
-rw-r--r--src/util/unsat_core.i51
143 files changed, 8963 insertions, 4272 deletions
diff --git a/src/Makefile.am b/src/Makefile.am
index 805ed6cb7..908e3de6c 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -327,6 +327,8 @@ libcvc4_la_SOURCES = \
theory/quantifiers/ambqi_builder.cpp \
theory/quantifiers/quant_conflict_find.h \
theory/quantifiers/quant_conflict_find.cpp \
+ theory/quantifiers/conjecture_generator.h \
+ theory/quantifiers/conjecture_generator.cpp \
theory/quantifiers/options_handlers.h \
theory/arith/theory_arith_type_rules.h \
theory/arith/type_enumerator.h \
diff --git a/src/bindings/Makefile.am b/src/bindings/Makefile.am
index 2214d9b88..e7548bbe1 100644
--- a/src/bindings/Makefile.am
+++ b/src/bindings/Makefile.am
@@ -63,8 +63,8 @@ java_libcvc4jni_la_LDFLAGS = \
-shrext $(CVC4_JAVA_MODULE_EXT) \
-version-info $(LIBCVC4BINDINGS_VERSION)
java_libcvc4jni_la_LIBADD = \
- -L@builddir@/.. -lcvc4 \
- -L@builddir@/../parser -lcvc4parser
+ @builddir@/../libcvc4.la \
+ @builddir@/../parser/libcvc4parser.la
endif
if CVC4_LANGUAGE_BINDING_CSHARP
csharplib_LTLIBRARIES += csharp/CVC4.la
@@ -72,8 +72,8 @@ csharp_CVC4_la_LDFLAGS = \
-module \
-version-info $(LIBCVC4BINDINGS_VERSION)
csharp_CVC4_la_LIBADD = \
- -L@builddir@/.. -lcvc4 \
- -L@builddir@/../parser -lcvc4parser
+ @builddir@/../libcvc4.la \
+ @builddir@/../parser/libcvc4parser.la
endif
if CVC4_LANGUAGE_BINDING_PERL
perllib_LTLIBRARIES += perl/CVC4.la
@@ -81,8 +81,8 @@ perl_CVC4_la_LDFLAGS = \
-module \
-version-info $(LIBCVC4BINDINGS_VERSION)
perl_CVC4_la_LIBADD = \
- -L@builddir@/.. -lcvc4 \
- -L@builddir@/../parser -lcvc4parser
+ @builddir@/../libcvc4.la \
+ @builddir@/../parser/libcvc4parser.la
perldata_DATA += perl/CVC4.pm
endif
if CVC4_LANGUAGE_BINDING_PHP
@@ -91,8 +91,8 @@ php_CVC4_la_LDFLAGS = \
-module \
-version-info $(LIBCVC4BINDINGS_VERSION)
php_CVC4_la_LIBADD = \
- -L@builddir@/.. -lcvc4 \
- -L@builddir@/../parser -lcvc4parser
+ @builddir@/../libcvc4.la \
+ @builddir@/../parser/libcvc4parser.la
phpdata_DATA += php/CVC4.php
endif
if CVC4_LANGUAGE_BINDING_PYTHON
@@ -102,8 +102,8 @@ python_CVC4_la_LDFLAGS = \
-module \
-version-info $(LIBCVC4BINDINGS_VERSION)
python_CVC4_la_LIBADD = \
- -L@builddir@/.. -lcvc4 \
- -L@builddir@/../parser -lcvc4parser
+ @builddir@/../libcvc4.la \
+ @builddir@/../parser/libcvc4parser.la
pythondata_DATA += python/CVC4.py
endif
if CVC4_LANGUAGE_BINDING_OCAML
@@ -117,8 +117,8 @@ ocaml_CVC4_la_LDFLAGS = \
-module \
-version-info $(LIBCVC4BINDINGS_VERSION)
ocaml_CVC4_la_LIBADD = \
- -L@builddir@/.. -lcvc4 \
- -L@builddir@/../parser -lcvc4parser
+ @builddir@/../libcvc4.la \
+ @builddir@/../parser/libcvc4parser.la
endif
if CVC4_LANGUAGE_BINDING_RUBY
rubylib_LTLIBRARIES += ruby/CVC4.la
@@ -126,8 +126,8 @@ ruby_CVC4_la_LDFLAGS = \
-module \
-version-info $(LIBCVC4BINDINGS_VERSION)
ruby_CVC4_la_LIBADD = \
- -L@builddir@/.. -lcvc4 \
- -L@builddir@/../parser -lcvc4parser
+ @builddir@/../libcvc4.la \
+ @builddir@/../parser/libcvc4parser.la
endif
if CVC4_LANGUAGE_BINDING_TCL
tcllib_LTLIBRARIES += tcl/CVC4.la
@@ -135,8 +135,8 @@ tcl_CVC4_la_LDFLAGS = \
-module \
-version-info $(LIBCVC4BINDINGS_VERSION)
tcl_CVC4_la_LIBADD = \
- -L@builddir@/.. -lcvc4 \
- -L@builddir@/../parser -lcvc4parser
+ @builddir@/../libcvc4.la \
+ @builddir@/../parser/libcvc4parser.la
endif
# this endif matches the "if CVC4_HAS_SWIG" above
endif
diff --git a/src/bindings/compat/c/Makefile.am b/src/bindings/compat/c/Makefile.am
index 5a788f2bf..4ec4626c6 100644
--- a/src/bindings/compat/c/Makefile.am
+++ b/src/bindings/compat/c/Makefile.am
@@ -25,8 +25,8 @@ lib_LTLIBRARIES += libcvc4bindings_c_compat.la
libcvc4bindings_c_compat_la_LDFLAGS = \
-version-info $(LIBCVC4BINDINGS_VERSION)
libcvc4bindings_c_compat_la_LIBADD = \
- -L@builddir@/../../../compat -lcvc4compat \
- -L@builddir@/../../.. -lcvc4
+ @builddir@/../../../compat/libcvc4compat.la \
+ @builddir@/../../../libcvc4.la
endif
diff --git a/src/bindings/compat/java/Makefile.am b/src/bindings/compat/java/Makefile.am
index 9eb985822..5b052568d 100644
--- a/src/bindings/compat/java/Makefile.am
+++ b/src/bindings/compat/java/Makefile.am
@@ -33,8 +33,8 @@ libcvc4compatjni_la_LDFLAGS = \
-shrext $(CVC4_JAVA_MODULE_EXT) \
-version-info $(LIBCVC4BINDINGS_VERSION)
libcvc4compatjni_la_LIBADD = \
- -L@builddir@/../../../compat -lcvc4compat \
- -L@builddir@/../../.. -lcvc4
+ @builddir@/../../../compat/libcvc4compat.la \
+ @builddir@/../../../libcvc4.la
BUILT_SOURCES += $(JNI_CPP_FILES)
endif
diff --git a/src/compat/Makefile.am b/src/compat/Makefile.am
index 5a8bd454e..ebb13426d 100644
--- a/src/compat/Makefile.am
+++ b/src/compat/Makefile.am
@@ -25,8 +25,8 @@ libcvc4compat_la_LDFLAGS = \
-version-info $(LIBCVC4COMPAT_VERSION)
libcvc4compat_la_LIBADD = \
- -L@builddir@/.. -lcvc4 \
- -L@builddir@/../parser -lcvc4parser
+ @builddir@/../libcvc4.la \
+ @builddir@/../parser/libcvc4parser.la
if CVC4_NEEDS_REPLACEMENT_FUNCTIONS
libcvc4compat_la_LIBADD += \
diff --git a/src/expr/command.cpp b/src/expr/command.cpp
index 69bdd704b..4d9ca9f30 100644
--- a/src/expr/command.cpp
+++ b/src/expr/command.cpp
@@ -189,8 +189,8 @@ std::string EchoCommand::getCommandName() const throw() {
/* class AssertCommand */
-AssertCommand::AssertCommand(const Expr& e) throw() :
- d_expr(e) {
+AssertCommand::AssertCommand(const Expr& e, bool inUnsatCore) throw() :
+ d_expr(e), d_inUnsatCore(inUnsatCore) {
}
Expr AssertCommand::getExpr() const throw() {
@@ -199,7 +199,7 @@ Expr AssertCommand::getExpr() const throw() {
void AssertCommand::invoke(SmtEngine* smtEngine) throw() {
try {
- smtEngine->assertFormula(d_expr);
+ smtEngine->assertFormula(d_expr, d_inUnsatCore);
d_commandStatus = CommandSuccess::instance();
} catch(exception& e) {
d_commandStatus = new CommandFailure(e.what());
@@ -207,18 +207,17 @@ void AssertCommand::invoke(SmtEngine* smtEngine) throw() {
}
Command* AssertCommand::exportTo(ExprManager* exprManager, ExprManagerMapCollection& variableMap) {
- return new AssertCommand(d_expr.exportTo(exprManager, variableMap));
+ return new AssertCommand(d_expr.exportTo(exprManager, variableMap), d_inUnsatCore);
}
Command* AssertCommand::clone() const {
- return new AssertCommand(d_expr);
+ return new AssertCommand(d_expr, d_inUnsatCore);
}
std::string AssertCommand::getCommandName() const throw() {
return "assert";
}
-
/* class PushCommand */
void PushCommand::invoke(SmtEngine* smtEngine) throw() {
@@ -271,8 +270,8 @@ CheckSatCommand::CheckSatCommand() throw() :
d_expr() {
}
-CheckSatCommand::CheckSatCommand(const Expr& expr) throw() :
- d_expr(expr) {
+CheckSatCommand::CheckSatCommand(const Expr& expr, bool inUnsatCore) throw() :
+ d_expr(expr), d_inUnsatCore(inUnsatCore) {
}
Expr CheckSatCommand::getExpr() const throw() {
@@ -301,13 +300,13 @@ void CheckSatCommand::printResult(std::ostream& out, uint32_t verbosity) const t
}
Command* CheckSatCommand::exportTo(ExprManager* exprManager, ExprManagerMapCollection& variableMap) {
- CheckSatCommand* c = new CheckSatCommand(d_expr.exportTo(exprManager, variableMap));
+ CheckSatCommand* c = new CheckSatCommand(d_expr.exportTo(exprManager, variableMap), d_inUnsatCore);
c->d_result = d_result;
return c;
}
Command* CheckSatCommand::clone() const {
- CheckSatCommand* c = new CheckSatCommand(d_expr);
+ CheckSatCommand* c = new CheckSatCommand(d_expr, d_inUnsatCore);
c->d_result = d_result;
return c;
}
@@ -318,8 +317,8 @@ std::string CheckSatCommand::getCommandName() const throw() {
/* class QueryCommand */
-QueryCommand::QueryCommand(const Expr& e) throw() :
- d_expr(e) {
+QueryCommand::QueryCommand(const Expr& e, bool inUnsatCore) throw() :
+ d_expr(e), d_inUnsatCore(inUnsatCore) {
}
Expr QueryCommand::getExpr() const throw() {
@@ -348,13 +347,13 @@ void QueryCommand::printResult(std::ostream& out, uint32_t verbosity) const thro
}
Command* QueryCommand::exportTo(ExprManager* exprManager, ExprManagerMapCollection& variableMap) {
- QueryCommand* c = new QueryCommand(d_expr.exportTo(exprManager, variableMap));
+ QueryCommand* c = new QueryCommand(d_expr.exportTo(exprManager, variableMap), d_inUnsatCore);
c->d_result = d_result;
return c;
}
Command* QueryCommand::clone() const {
- QueryCommand* c = new QueryCommand(d_expr);
+ QueryCommand* c = new QueryCommand(d_expr, d_inUnsatCore);
c->d_result = d_result;
return c;
}
@@ -744,22 +743,22 @@ Command* DefineNamedFunctionCommand::clone() const {
SetUserAttributeCommand::SetUserAttributeCommand( const std::string& attr, Expr expr ) throw() :
d_attr( attr ), d_expr( expr ){
}
-/*
-SetUserAttributeCommand::SetUserAttributeCommand( const std::string& id, Expr expr,
+
+SetUserAttributeCommand::SetUserAttributeCommand( const std::string& attr, Expr expr,
std::vector<Expr>& values ) throw() :
- d_id( id ), d_expr( expr ){
+ d_attr( attr ), d_expr( expr ){
d_expr_values.insert( d_expr_values.begin(), values.begin(), values.end() );
}
-SetUserAttributeCommand::SetUserAttributeCommand( const std::string& id, Expr expr,
- std::string& value ) throw() :
- d_id( id ), d_expr( expr ), d_str_value( value ){
+SetUserAttributeCommand::SetUserAttributeCommand( const std::string& attr, Expr expr,
+ const std::string& value ) throw() :
+ d_attr( attr ), d_expr( expr ), d_str_value( value ){
}
-*/
+
void SetUserAttributeCommand::invoke(SmtEngine* smtEngine) throw(){
try {
if(!d_expr.isNull()) {
- smtEngine->setUserAttribute( d_attr, d_expr );
+ smtEngine->setUserAttribute( d_attr, d_expr, d_expr_values, d_str_value );
}
d_commandStatus = CommandSuccess::instance();
} catch(exception& e) {
@@ -769,11 +768,15 @@ void SetUserAttributeCommand::invoke(SmtEngine* smtEngine) throw(){
Command* SetUserAttributeCommand::exportTo(ExprManager* exprManager, ExprManagerMapCollection& variableMap){
Expr expr = d_expr.exportTo(exprManager, variableMap);
- return new SetUserAttributeCommand( d_attr, expr );
+ SetUserAttributeCommand * c = new SetUserAttributeCommand( d_attr, expr, d_str_value );
+ c->d_expr_values.insert( c->d_expr_values.end(), d_expr_values.begin(), d_expr_values.end() );
+ return c;
}
Command* SetUserAttributeCommand::clone() const{
- return new SetUserAttributeCommand( d_attr, d_expr );
+ SetUserAttributeCommand * c = new SetUserAttributeCommand( d_attr, d_expr, d_str_value );
+ c->d_expr_values.insert( c->d_expr_values.end(), d_expr_values.begin(), d_expr_values.end() );
+ return c;
}
std::string SetUserAttributeCommand::getCommandName() const throw() {
@@ -1125,36 +1128,40 @@ std::string GetInstantiationsCommand::getCommandName() const throw() {
GetUnsatCoreCommand::GetUnsatCoreCommand() throw() {
}
+GetUnsatCoreCommand::GetUnsatCoreCommand(const std::map<Expr, std::string>& names) throw() : d_names(names) {
+}
+
void GetUnsatCoreCommand::invoke(SmtEngine* smtEngine) throw() {
- /*
try {
d_result = smtEngine->getUnsatCore();
d_commandStatus = CommandSuccess::instance();
} catch(exception& e) {
d_commandStatus = new CommandFailure(e.what());
}
- */
- d_commandStatus = new CommandUnsupported();
}
void GetUnsatCoreCommand::printResult(std::ostream& out, uint32_t verbosity) const throw() {
if(! ok()) {
this->Command::printResult(out, verbosity);
} else {
- //do nothing -- unsat cores not yet supported
- // d_result->toStream(out);
+ d_result.toStream(out, d_names);
}
}
+const UnsatCore& GetUnsatCoreCommand::getUnsatCore() const throw() {
+ // of course, this will be empty if the command hasn't been invoked yet
+ return d_result;
+}
+
Command* GetUnsatCoreCommand::exportTo(ExprManager* exprManager, ExprManagerMapCollection& variableMap) {
- GetUnsatCoreCommand* c = new GetUnsatCoreCommand();
- //c->d_result = d_result;
+ GetUnsatCoreCommand* c = new GetUnsatCoreCommand(d_names);
+ c->d_result = d_result;
return c;
}
Command* GetUnsatCoreCommand::clone() const {
- GetUnsatCoreCommand* c = new GetUnsatCoreCommand();
- //c->d_result = d_result;
+ GetUnsatCoreCommand* c = new GetUnsatCoreCommand(d_names);
+ c->d_result = d_result;
return c;
}
diff --git a/src/expr/command.h b/src/expr/command.h
index 606618d21..4d2957b7c 100644
--- a/src/expr/command.h
+++ b/src/expr/command.h
@@ -35,6 +35,7 @@
#include "util/sexpr.h"
#include "util/datatype.h"
#include "util/proof.h"
+#include "util/unsat_core.h"
namespace CVC4 {
@@ -309,8 +310,9 @@ public:
class CVC4_PUBLIC AssertCommand : public Command {
protected:
Expr d_expr;
+ bool d_inUnsatCore;
public:
- AssertCommand(const Expr& e) throw();
+ AssertCommand(const Expr& e, bool inUnsatCore = true) throw();
~AssertCommand() throw() {}
Expr getExpr() const throw();
void invoke(SmtEngine* smtEngine) throw();
@@ -439,12 +441,12 @@ class CVC4_PUBLIC SetUserAttributeCommand : public Command {
protected:
std::string d_attr;
Expr d_expr;
- //std::vector<Expr> d_expr_values;
- //std::string d_str_value;
+ std::vector<Expr> d_expr_values;
+ std::string d_str_value;
public:
SetUserAttributeCommand( const std::string& attr, Expr expr ) throw();
- //SetUserAttributeCommand( const std::string& id, Expr expr, std::vector<Expr>& values ) throw();
- //SetUserAttributeCommand( const std::string& id, Expr expr, std::string& value ) throw();
+ SetUserAttributeCommand( const std::string& attr, Expr expr, std::vector<Expr>& values ) throw();
+ SetUserAttributeCommand( const std::string& attr, Expr expr, const std::string& value ) throw();
~SetUserAttributeCommand() throw() {}
void invoke(SmtEngine* smtEngine) throw();
Command* exportTo(ExprManager* exprManager, ExprManagerMapCollection& variableMap);
@@ -457,9 +459,10 @@ class CVC4_PUBLIC CheckSatCommand : public Command {
protected:
Expr d_expr;
Result d_result;
+ bool d_inUnsatCore;
public:
CheckSatCommand() throw();
- CheckSatCommand(const Expr& expr) throw();
+ CheckSatCommand(const Expr& expr, bool inUnsatCore = true) throw();
~CheckSatCommand() throw() {}
Expr getExpr() const throw();
void invoke(SmtEngine* smtEngine) throw();
@@ -474,8 +477,9 @@ class CVC4_PUBLIC QueryCommand : public Command {
protected:
Expr d_expr;
Result d_result;
+ bool d_inUnsatCore;
public:
- QueryCommand(const Expr& e) throw();
+ QueryCommand(const Expr& e, bool inUnsatCore = true) throw();
~QueryCommand() throw() {}
Expr getExpr() const throw();
void invoke(SmtEngine* smtEngine) throw();
@@ -597,12 +601,15 @@ public:
class CVC4_PUBLIC GetUnsatCoreCommand : public Command {
protected:
- //UnsatCore* d_result;
+ UnsatCore d_result;
+ std::map<Expr, std::string> d_names;
public:
GetUnsatCoreCommand() throw();
+ GetUnsatCoreCommand(const std::map<Expr, std::string>& names) throw();
~GetUnsatCoreCommand() throw() {}
void invoke(SmtEngine* smtEngine) throw();
void printResult(std::ostream& out, uint32_t verbosity = 2) const throw();
+ const UnsatCore& getUnsatCore() const throw();
Command* exportTo(ExprManager* exprManager, ExprManagerMapCollection& variableMap);
Command* clone() const;
std::string getCommandName() const throw();
diff --git a/src/expr/options b/src/expr/options
index ee4d40b2c..b4608832f 100644
--- a/src/expr/options
+++ b/src/expr/options
@@ -7,12 +7,12 @@ module EXPR "expr/options.h" Expression package
option defaultExprDepth --default-expr-depth=N int :default 0 :predicate CVC4::expr::setDefaultExprDepth :predicate-include "expr/options_handlers.h"
print exprs to depth N (0 == default, -1 == no limit)
-undocumented-alias --expr-depth = --default-expr-depth
+undocumented-alias --expr-depth=N = --default-expr-depth=N
option defaultDagThresh default-dag-thresh --default-dag-thresh=N int :default 1 :predicate CVC4::expr::setDefaultDagThresh :predicate-include "expr/options_handlers.h"
dagify common subexprs appearing > N times (1 == default, 0 == don't dagify)
-undocumented-alias --dag-thresh = --default-dag-thresh
-undocumented-alias --dag-threshold = --default-dag-thresh
+undocumented-alias --dag-thresh=N = --default-dag-thresh=N
+undocumented-alias --dag-threshold=N = --default-dag-thresh=N
option - --print-expr-types void :handler CVC4::expr::setPrintExprTypes :handler-include "expr/options_handlers.h"
print types with variables when printing exprs
diff --git a/src/main/command_executor.cpp b/src/main/command_executor.cpp
index 5b90ca14f..4bbfe2762 100644
--- a/src/main/command_executor.cpp
+++ b/src/main/command_executor.cpp
@@ -22,6 +22,7 @@
#include "main/options.h"
#include "smt/options.h"
+#include "printer/options.h"
#ifndef __WIN32__
# include <sys/resource.h>
@@ -119,9 +120,9 @@ bool CommandExecutor::doCommandSingleton(Command* cmd)
d_lastStatistics = ossCurStats.str();
}
- // dump the model/proof if option is set
+ // dump the model/proof/unsat core if option is set
if(status) {
- Command * g = NULL;
+ Command* g = NULL;
if( d_options[options::produceModels] &&
d_options[options::dumpModels] &&
( res.asSatisfiabilityResult() == Result::SAT ||
@@ -132,11 +133,16 @@ bool CommandExecutor::doCommandSingleton(Command* cmd)
res.asSatisfiabilityResult() == Result::UNSAT ) {
g = new GetProofCommand();
} else if( d_options[options::dumpInstantiations] &&
- res.asSatisfiabilityResult() == Result::UNSAT ) {
+ ( ( d_options[options::instFormatMode]!=INST_FORMAT_MODE_SZS &&
+ ( res.asSatisfiabilityResult() == Result::SAT || (res.isUnknown() && res.whyUnknown() == Result::INCOMPLETE) ) ) ||
+ res.asSatisfiabilityResult() == Result::UNSAT ) ) {
g = new GetInstantiationsCommand();
+ } else if( d_options[options::dumpUnsatCores] &&
+ res.asSatisfiabilityResult() == Result::UNSAT ) {
+ g = new GetUnsatCoreCommand();
}
- if( g ){
- //set no time limit during dumping if applicable
+ if(g != NULL) {
+ // set no time limit during dumping if applicable
if( d_options[options::forceNoLimitCpuWhileDump] ){
setNoLimitCPU();
}
@@ -162,12 +168,12 @@ bool smtEngineInvoke(SmtEngine* smt, Command* cmd, std::ostream *out)
void printStatsIncremental(std::ostream& out, const std::string& prvsStatsString, const std::string& curStatsString) {
if(prvsStatsString == "") {
- out << curStatsString;
- return;
+ out << curStatsString;
+ return;
}
// read each line
- // if a number, subtract and add that to parantheses
+ // if a number, subtract and add that to parentheses
std::istringstream issPrvs(prvsStatsString);
std::istringstream issCur(curStatsString);
diff --git a/src/main/command_executor_portfolio.cpp b/src/main/command_executor_portfolio.cpp
index 36f2abdd2..7d35a443a 100644
--- a/src/main/command_executor_portfolio.cpp
+++ b/src/main/command_executor_portfolio.cpp
@@ -29,6 +29,7 @@
#include "main/portfolio.h"
#include "options/options.h"
#include "smt/options.h"
+#include "printer/options.h"
#include "cvc4autoconfig.h"
@@ -357,7 +358,7 @@ bool CommandExecutorPortfolio::doCommandSingleton(Command* cmd)
bool status = portfolioReturn.second;
- // dump the model/proof if option is set
+ // dump the model/proof/unsat core if option is set
if(status) {
if( d_options[options::produceModels] &&
d_options[options::dumpModels] &&
@@ -371,9 +372,15 @@ bool CommandExecutorPortfolio::doCommandSingleton(Command* cmd)
Command* gp = new GetProofCommand();
status = doCommandSingleton(gp);
} else if( d_options[options::dumpInstantiations] &&
- d_result.asSatisfiabilityResult() == Result::UNSAT ) {
+ ( ( d_options[options::instFormatMode]!=INST_FORMAT_MODE_SZS &&
+ ( d_result.asSatisfiabilityResult() == Result::SAT || (d_result.isUnknown() && d_result.whyUnknown() == Result::INCOMPLETE) ) ) ||
+ d_result.asSatisfiabilityResult() == Result::UNSAT ) ) {
Command* gi = new GetInstantiationsCommand();
status = doCommandSingleton(gi);
+ } else if( d_options[options::dumpUnsatCores] &&
+ d_result.asSatisfiabilityResult() == Result::UNSAT ) {
+ Command* guc = new GetUnsatCoreCommand();
+ status = doCommandSingleton(guc);
}
}
diff --git a/src/main/driver_unified.cpp b/src/main/driver_unified.cpp
index 1f3988753..5fbd5aff5 100644
--- a/src/main/driver_unified.cpp
+++ b/src/main/driver_unified.cpp
@@ -267,15 +267,8 @@ int runCvc4(int argc, char* argv[], Options& opts) {
Command* cmd;
bool status = true;
if(opts[options::interactive] && inputFromStdin) {
- if(opts[options::tearDownIncremental] && opts[options::incrementalSolving]) {
- if(opts.wasSetByUser(options::incrementalSolving)) {
- throw OptionException("--tear-down-incremental incompatible with --incremental");
- }
-
- cmd = new SetOptionCommand("incremental", false);
- cmd->setMuted(true);
- pExecutor->doCommand(cmd);
- delete cmd;
+ if(opts[options::tearDownIncremental]) {
+ throw OptionException("--tear-down-incremental doesn't work in interactive mode");
}
#ifndef PORTFOLIO_BUILD
if(!opts.wasSetByUser(options::incrementalSolving)) {
diff --git a/src/main/options b/src/main/options
index b9262bfa4..6cc6a0ca0 100644
--- a/src/main/options
+++ b/src/main/options
@@ -52,7 +52,7 @@ option segvSpin --segv-spin bool :default false
spin on segfault/other crash waiting for gdb
undocumented-alias --segv-nospin = --no-segv-spin
-expert-option tearDownIncremental --tear-down-incremental bool :default false
+expert-option tearDownIncremental : --tear-down-incremental bool :default false
implement PUSH/POP/multi-query by destroying and recreating SmtEngine
expert-option waitToJoin --wait-to-join bool :default true
diff --git a/src/options/mkoptions b/src/options/mkoptions
index a3a1571ec..03d7837ac 100755
--- a/src/options/mkoptions
+++ b/src/options/mkoptions
@@ -352,6 +352,10 @@ function handle_option {
WARN "$internal is inaccessible via SmtEngine (no smt name for option) but can be set via command-line: $long_option $short_option $long_option_alternate $short_option_alternate"
fi
fi
+ # in options files, use an smt name of ":" to force there not to be one
+ if [ "$smtname" = : ]; then
+ smtname=
+ fi
# check for duplicates
if [ "$internal" != - ]; then
diff --git a/src/parser/Makefile.am b/src/parser/Makefile.am
index a178f8dd5..c8a8cc941 100644
--- a/src/parser/Makefile.am
+++ b/src/parser/Makefile.am
@@ -29,7 +29,7 @@ libcvc4parser_la_LIBADD = \
@builddir@/smt2/libparsersmt2.la \
@builddir@/tptp/libparsertptp.la \
@builddir@/cvc/libparsercvc.la \
- -L@builddir@/.. -lcvc4
+ @builddir@/../libcvc4.la
if CVC4_NEEDS_REPLACEMENT_FUNCTIONS
libcvc4parser_la_LIBADD += \
diff --git a/src/parser/cvc/Cvc.g b/src/parser/cvc/Cvc.g
index 347759c9a..aad365563 100644
--- a/src/parser/cvc/Cvc.g
+++ b/src/parser/cvc/Cvc.g
@@ -1375,14 +1375,6 @@ prefixFormula[CVC4::Expr& f]
PARSER_STATE->preemptCommand(cmd);
f = func;
}
-
- /* array literals */
- | ARRAY_TOK { PARSER_STATE->pushScope(); } LPAREN
- boundVarDecl[ids,t] RPAREN COLON formula[f]
- { PARSER_STATE->popScope();
- UNSUPPORTED("array literals not supported yet");
- f = EXPR_MANAGER->mkVar(EXPR_MANAGER->mkArrayType(t, f.getType()), ExprManager::VAR_FLAG_GLOBAL);
- }
;
instantiationPatterns[ CVC4::Expr& expr ]
@@ -1905,7 +1897,7 @@ simpleTerm[CVC4::Expr& f]
std::vector<std::string> names;
Expr e;
Debug("parser-extra") << "term: " << AntlrInput::tokenText(LT(1)) << std::endl;
- Type t;
+ Type t, t2;
}
/* if-then-else */
: iteTerm[f]
@@ -1935,7 +1927,6 @@ simpleTerm[CVC4::Expr& f]
f = MK_EXPR(kind::RECORD, MK_CONST(t.getRecord()), std::vector<Expr>());
}
-
/* empty set literal */
| LBRACE RBRACE
{ f = MK_CONST(EmptySet(Type())); }
@@ -1949,6 +1940,32 @@ simpleTerm[CVC4::Expr& f]
}
}
+ /* array literals */
+ | ARRAY_TOK /* { PARSER_STATE->pushScope(); } */ LPAREN
+ restrictedType[t, CHECK_DECLARED] OF_TOK restrictedType[t2, CHECK_DECLARED]
+ RPAREN COLON simpleTerm[f]
+ { /* Eventually if we support a bound var (like a lambda) for array
+ * literals, we can use the push/pop scope. */
+ /* PARSER_STATE->popScope(); */
+ t = EXPR_MANAGER->mkArrayType(t, t2);
+ if(!f.isConst()) {
+ std::stringstream ss;
+ ss << "expected constant term inside array constant, but found "
+ << "nonconstant term" << std::endl
+ << "the term: " << f;
+ PARSER_STATE->parseError(ss.str());
+ }
+ if(!t2.isComparableTo(f.getType())) {
+ std::stringstream ss;
+ ss << "type mismatch inside array constant term:" << std::endl
+ << "array type: " << t << std::endl
+ << "expected const type: " << t2 << std::endl
+ << "computed const type: " << f.getType();
+ PARSER_STATE->parseError(ss.str());
+ }
+ f = MK_CONST( ArrayStoreAll(t, f) );
+ }
+
/* boolean literals */
| TRUE_TOK { f = MK_CONST(bool(true)); }
| FALSE_TOK { f = MK_CONST(bool(false)); }
@@ -1993,7 +2010,7 @@ simpleTerm[CVC4::Expr& f]
;
/**
- * Matches (and performs) a type ascription.
+ * Matches a type ascription.
* The f arg is the term to check (it is an input-only argument).
*/
typeAscription[const CVC4::Expr& f, CVC4::Type& t]
diff --git a/src/parser/smt2/Smt2.g b/src/parser/smt2/Smt2.g
index 6964e6069..6a98755f2 100644
--- a/src/parser/smt2/Smt2.g
+++ b/src/parser/smt2/Smt2.g
@@ -377,8 +377,14 @@ command returns [CVC4::Command* cmd = NULL]
{ cmd = new GetAssignmentCommand(); }
| /* assertion */
ASSERT_TOK { PARSER_STATE->checkThatLogicIsSet(); }
+ { PARSER_STATE->clearLastNamedTerm(); }
term[expr, expr2]
- { cmd = new AssertCommand(expr); }
+ { bool inUnsatCore = PARSER_STATE->lastNamedTerm().first == expr;
+ cmd = new AssertCommand(expr, inUnsatCore);
+ if(inUnsatCore) {
+ PARSER_STATE->registerUnsatCoreName(PARSER_STATE->lastNamedTerm());
+ }
+ }
| /* check-sat */
CHECKSAT_TOK { PARSER_STATE->checkThatLogicIsSet(); }
( term[expr, expr2]
@@ -396,7 +402,7 @@ command returns [CVC4::Command* cmd = NULL]
{ cmd = new GetProofCommand(); }
| /* get-unsat-core */
GET_UNSAT_CORE_TOK { PARSER_STATE->checkThatLogicIsSet(); }
- { cmd = new GetUnsatCoreCommand(); }
+ { cmd = new GetUnsatCoreCommand(PARSER_STATE->getUnsatCoreNames()); }
| /* push */
PUSH_TOK { PARSER_STATE->checkThatLogicIsSet(); }
( k=INTEGER_LITERAL
@@ -405,11 +411,13 @@ command returns [CVC4::Command* cmd = NULL]
cmd = new EmptyCommand();
} else if(n == 1) {
PARSER_STATE->pushScope();
+ PARSER_STATE->pushUnsatCoreNameScope();
cmd = new PushCommand();
} else {
CommandSequence* seq = new CommandSequence();
do {
PARSER_STATE->pushScope();
+ PARSER_STATE->pushUnsatCoreNameScope();
Command* c = new PushCommand();
c->setMuted(n > 1);
seq->addCommand(c);
@@ -421,6 +429,7 @@ command returns [CVC4::Command* cmd = NULL]
PARSER_STATE->parseError("Strict compliance mode demands an integer to be provided to PUSH. Maybe you want (push 1)?");
} else {
PARSER_STATE->pushScope();
+ PARSER_STATE->pushUnsatCoreNameScope();
cmd = new PushCommand();
}
} )
@@ -433,11 +442,13 @@ command returns [CVC4::Command* cmd = NULL]
if(n == 0) {
cmd = new EmptyCommand();
} else if(n == 1) {
+ PARSER_STATE->popUnsatCoreNameScope();
PARSER_STATE->popScope();
cmd = new PopCommand();
} else {
CommandSequence* seq = new CommandSequence();
do {
+ PARSER_STATE->popUnsatCoreNameScope();
PARSER_STATE->popScope();
Command* c = new PopCommand();
c->setMuted(n > 1);
@@ -449,6 +460,7 @@ command returns [CVC4::Command* cmd = NULL]
| { if(PARSER_STATE->strictModeEnabled()) {
PARSER_STATE->parseError("Strict compliance mode demands an integer to be provided to POP. Maybe you want (pop 1)?");
} else {
+ PARSER_STATE->popUnsatCoreNameScope();
PARSER_STATE->popScope();
cmd = new PopCommand();
}
@@ -686,7 +698,7 @@ rewriterulesCommand[CVC4::Command*& cmd]
};
args.push_back(expr);
expr = MK_EXPR(CVC4::kind::REWRITE_RULE, args);
- cmd = new AssertCommand(expr); }
+ cmd = new AssertCommand(expr, false); }
/* propagation rule */
| rewritePropaKind[kind]
LPAREN_TOK sortedVarList[sortedVarNames] RPAREN_TOK
@@ -737,7 +749,7 @@ rewriterulesCommand[CVC4::Command*& cmd]
};
args.push_back(expr);
expr = MK_EXPR(CVC4::kind::REWRITE_RULE, args);
- cmd = new AssertCommand(expr); }
+ cmd = new AssertCommand(expr, false); }
;
rewritePropaKind[CVC4::Kind& kind]
@@ -987,11 +999,40 @@ term[CVC4::Expr& expr, CVC4::Expr& expr2]
}
expr = MK_EXPR(kind, args); }
- | /* An indexed function application */
- LPAREN_TOK indexedFunctionName[op] termList[args,expr] RPAREN_TOK
- { expr = MK_EXPR(op, args);
- PARSER_STATE->checkOperator(expr.getKind(), args.size());
- }
+ | LPAREN_TOK
+ ( /* An indexed function application */
+ indexedFunctionName[op] termList[args,expr] RPAREN_TOK
+ { expr = MK_EXPR(op, args);
+ PARSER_STATE->checkOperator(expr.getKind(), args.size());
+ }
+ | /* Array constant (in Z3 syntax) */
+ LPAREN_TOK AS_TOK CONST_TOK sortSymbol[type, CHECK_DECLARED]
+ RPAREN_TOK term[f, f2] RPAREN_TOK
+ {
+ if(!type.isArray()) {
+ std::stringstream ss;
+ ss << "expected array constant term, but cast is not of array type" << std::endl
+ << "cast type: " << type;
+ PARSER_STATE->parseError(ss.str());
+ }
+ if(!f.isConst()) {
+ std::stringstream ss;
+ ss << "expected constant term inside array constant, but found "
+ << "nonconstant term:" << std::endl
+ << "the term: " << f;
+ PARSER_STATE->parseError(ss.str());
+ }
+ if(!ArrayType(type).getConstituentType().isComparableTo(f.getType())) {
+ std::stringstream ss;
+ ss << "type mismatch inside array constant term:" << std::endl
+ << "array type: " << type << std::endl
+ << "expected const type: " << ArrayType(type).getConstituentType() << std::endl
+ << "computed const type: " << f.getType();
+ PARSER_STATE->parseError(ss.str());
+ }
+ expr = MK_CONST( ::CVC4::ArrayStoreAll(type, f) );
+ }
+ )
| /* a let binding */
LPAREN_TOK LET_TOK LPAREN_TOK
{ PARSER_STATE->pushScope(true); }
@@ -1037,8 +1078,8 @@ term[CVC4::Expr& expr, CVC4::Expr& expr2]
/* attributed expressions */
| LPAREN_TOK ATTRIBUTE_TOK term[expr, f2]
- ( attribute[expr, attexpr,attr]
- { if( attr == ":pattern" && ! attexpr.isNull()) {
+ ( attribute[expr, attexpr, attr]
+ { if( ( attr == ":pattern" || attr == ":no-pattern" ) && ! attexpr.isNull()) {
patexprs.push_back( attexpr );
}
}
@@ -1072,11 +1113,17 @@ term[CVC4::Expr& expr, CVC4::Expr& expr2]
} else if(! patexprs.empty()) {
if( !f2.isNull() && f2.getKind()==kind::INST_PATTERN_LIST ){
for( size_t i=0; i<f2.getNumChildren(); i++ ){
- patexprs.push_back( f2[i] );
+ if( f2[i].getKind()==kind::INST_PATTERN ){
+ patexprs.push_back( f2[i] );
+ }else{
+ std::stringstream ss;
+ ss << "warning: rewrite rules do not support " << f2[i] << " within instantiation pattern list";
+ PARSER_STATE->warning(ss.str());
+ }
}
}
expr2 = MK_EXPR(kind::INST_PATTERN_LIST, patexprs);
- }else{
+ } else {
expr2 = f2;
}
}
@@ -1164,10 +1211,30 @@ attribute[CVC4::Expr& expr,CVC4::Expr& retExpr, std::string& attr]
attr = std::string(":pattern");
retExpr = MK_EXPR(kind::INST_PATTERN, patexprs);
}
- | ATTRIBUTE_NO_PATTERN_TOK LPAREN_TOK term[patexpr, e2]+ RPAREN_TOK
+ | ATTRIBUTE_NO_PATTERN_TOK term[patexpr, e2]
{
attr = std::string(":no-pattern");
- PARSER_STATE->attributeNotSupported(attr);
+ retExpr = MK_EXPR(kind::INST_NO_PATTERN, patexpr);
+ }
+ | ATTRIBUTE_INST_LEVEL INTEGER_LITERAL
+ {
+ Expr n = MK_CONST( AntlrInput::tokenToInteger($INTEGER_LITERAL) );
+ std::vector<Expr> values;
+ values.push_back( n );
+ std::string attr_name("quant-inst-max-level");
+ Command* c = new SetUserAttributeCommand( attr_name, expr, values );
+ c->setMuted(true);
+ PARSER_STATE->preemptCommand(c);
+ }
+ | ATTRIBUTE_RR_PRIORITY_LEVEL INTEGER_LITERAL
+ {
+ Expr n = MK_CONST( AntlrInput::tokenToInteger($INTEGER_LITERAL) );
+ std::vector<Expr> values;
+ values.push_back( n );
+ std::string attr_name("rr-priority");
+ Command* c = new SetUserAttributeCommand( attr_name, expr, values );
+ c->setMuted(true);
+ PARSER_STATE->preemptCommand(c);
}
| ATTRIBUTE_NAMED_TOK symbolicExpr[sexpr]
{
@@ -1192,6 +1259,8 @@ attribute[CVC4::Expr& expr,CVC4::Expr& retExpr, std::string& attr]
PARSER_STATE->reserveSymbolAtAssertionLevel(name);
// define it
Expr func = PARSER_STATE->mkFunction(name, expr.getType());
+ // remember the last term to have been given a :named attribute
+ PARSER_STATE->setLastNamedTerm(expr, name);
// bind name to expr with define-fun
Command* c =
new DefineNamedFunctionCommand(name, func, std::vector<Expr>(), expr);
@@ -1670,6 +1739,7 @@ GET_OPTION_TOK : 'get-option';
PUSH_TOK : 'push';
POP_TOK : 'pop';
AS_TOK : 'as';
+CONST_TOK : 'const';
// extended commands
DECLARE_DATATYPES_TOK : 'declare-datatypes';
@@ -1692,6 +1762,8 @@ INCLUDE_TOK : 'include';
ATTRIBUTE_PATTERN_TOK : ':pattern';
ATTRIBUTE_NO_PATTERN_TOK : ':no-pattern';
ATTRIBUTE_NAMED_TOK : ':named';
+ATTRIBUTE_INST_LEVEL : ':quant-inst-max-level';
+ATTRIBUTE_RR_PRIORITY : ':rr-priority';
// operators (NOTE: theory symbols go here)
AMPERSAND_TOK : '&';
diff --git a/src/parser/smt2/smt2.cpp b/src/parser/smt2/smt2.cpp
index fecccfa44..21b6a1e5b 100644
--- a/src/parser/smt2/smt2.cpp
+++ b/src/parser/smt2/smt2.cpp
@@ -31,6 +31,7 @@ namespace parser {
Smt2::Smt2(ExprManager* exprManager, Input* input, bool strictMode, bool parseOnly) :
Parser(exprManager,input,strictMode,parseOnly),
d_logicSet(false) {
+ d_unsatCoreNames.push(std::map<Expr, std::string>());
if( !strictModeEnabled() ) {
addTheory(Smt2::THEORY_CORE);
}
diff --git a/src/parser/smt2/smt2.h b/src/parser/smt2/smt2.h
index 71161be94..290bbc975 100644
--- a/src/parser/smt2/smt2.h
+++ b/src/parser/smt2/smt2.h
@@ -24,7 +24,10 @@
#include "theory/logic_info.h"
#include "util/abstract_value.h"
+#include <string>
#include <sstream>
+#include <utility>
+#include <stack>
namespace CVC4 {
@@ -54,6 +57,9 @@ private:
bool d_logicSet;
LogicInfo d_logic;
std::hash_map<std::string, Kind, StringHashFunction> operatorKindMap;
+ std::pair<Expr, std::string> d_lastNamedTerm;
+ // this is a user-context stack
+ std::stack< std::map<Expr, std::string> > d_unsatCoreNames;
protected:
Smt2(ExprManager* exprManager, Input* input, bool strictMode = false, bool parseOnly = false);
@@ -105,6 +111,34 @@ public:
void includeFile(const std::string& filename);
+ void setLastNamedTerm(Expr e, std::string name) {
+ d_lastNamedTerm = std::make_pair(e, name);
+ }
+
+ void clearLastNamedTerm() {
+ d_lastNamedTerm = std::make_pair(Expr(), "");
+ }
+
+ std::pair<Expr, std::string> lastNamedTerm() {
+ return d_lastNamedTerm;
+ }
+
+ void pushUnsatCoreNameScope() {
+ d_unsatCoreNames.push(d_unsatCoreNames.top());
+ }
+
+ void popUnsatCoreNameScope() {
+ d_unsatCoreNames.pop();
+ }
+
+ void registerUnsatCoreName(std::pair<Expr, std::string> name) {
+ d_unsatCoreNames.top().insert(name);
+ }
+
+ std::map<Expr, std::string> getUnsatCoreNames() {
+ return d_unsatCoreNames.top();
+ }
+
bool isAbstractValue(const std::string& name) {
return name.length() >= 2 && name[0] == '@' && name[1] != '0' &&
name.find_first_not_of("0123456789", 1) == std::string::npos;
diff --git a/src/printer/cvc/cvc_printer.cpp b/src/printer/cvc/cvc_printer.cpp
index 3f93106a0..ed5116bc6 100644
--- a/src/printer/cvc/cvc_printer.cpp
+++ b/src/printer/cvc/cvc_printer.cpp
@@ -169,6 +169,13 @@ void CvcPrinter::toStream(std::ostream& out, TNode n, int depth, bool types, boo
out << "{} :: " << n.getConst<EmptySet>().getType();
break;
+ case kind::STORE_ALL: {
+ const ArrayStoreAll& asa = n.getConst<ArrayStoreAll>();
+ out << "ARRAY(" << asa.getType().getIndexType() << " OF "
+ << asa.getType().getConstituentType() << ") : " << asa.getExpr();
+ break;
+ }
+
default:
// Fall back to whatever operator<< does on underlying type; we
// might luck out and print something reasonable.
diff --git a/src/printer/printer.cpp b/src/printer/printer.cpp
index 8f0f50daa..dd2e180e1 100644
--- a/src/printer/printer.cpp
+++ b/src/printer/printer.cpp
@@ -153,4 +153,17 @@ void Printer::toStream(std::ostream& out, const Model& m) const throw() {
}
}/* Printer::toStream(Model) */
+void Printer::toStream(std::ostream& out, const UnsatCore& core) const throw() {
+ std::map<Expr, std::string> names;
+ toStream(out, core, names);
+}/* Printer::toStream(UnsatCore) */
+
+void Printer::toStream(std::ostream& out, const UnsatCore& core, const std::map<Expr, std::string>& names) const throw() {
+ for(UnsatCore::iterator i = core.begin(); i != core.end(); ++i) {
+ AssertCommand cmd(*i);
+ toStream(out, &cmd, -1, false, -1);
+ out << std::endl;
+ }
+}/* Printer::toStream(UnsatCore, std::map<Expr, std::string>) */
+
}/* CVC4 namespace */
diff --git a/src/printer/printer.h b/src/printer/printer.h
index beb2438e2..e0b80ddfc 100644
--- a/src/printer/printer.h
+++ b/src/printer/printer.h
@@ -19,6 +19,9 @@
#ifndef __CVC4__PRINTER__PRINTER_H
#define __CVC4__PRINTER__PRINTER_H
+#include <map>
+#include <string>
+
#include "util/language.h"
#include "util/sexpr.h"
#include "util/model.h"
@@ -103,6 +106,12 @@ public:
/** Write a Model out to a stream with this Printer. */
virtual void toStream(std::ostream& out, const Model& m) const throw();
+ /** Write an UnsatCore out to a stream with this Printer. */
+ virtual void toStream(std::ostream& out, const UnsatCore& core) const throw();
+
+ /** Write an UnsatCore out to a stream with this Printer. */
+ virtual void toStream(std::ostream& out, const UnsatCore& core, const std::map<Expr, std::string>& names) const throw();
+
};/* class Printer */
/**
diff --git a/src/printer/smt2/smt2_printer.cpp b/src/printer/smt2/smt2_printer.cpp
index 903a1e6e3..3ca5674e9 100644
--- a/src/printer/smt2/smt2_printer.cpp
+++ b/src/printer/smt2/smt2_printer.cpp
@@ -713,6 +713,7 @@ void Smt2Printer::toStream(std::ostream& out, const Command* c,
tryToStream<GetAssignmentCommand>(out, c) ||
tryToStream<GetAssertionsCommand>(out, c) ||
tryToStream<GetProofCommand>(out, c) ||
+ tryToStream<GetUnsatCoreCommand>(out, c) ||
tryToStream<SetBenchmarkStatusCommand>(out, c) ||
tryToStream<SetBenchmarkLogicCommand>(out, c, d_variant) ||
tryToStream<SetInfoCommand>(out, c) ||
@@ -781,6 +782,20 @@ void Smt2Printer::toStream(std::ostream& out, const CommandStatus* s) const thro
}/* Smt2Printer::toStream(CommandStatus*) */
+void Smt2Printer::toStream(std::ostream& out, const UnsatCore& core, const std::map<Expr, std::string>& names) const throw() {
+ out << "(" << std::endl;
+ for(UnsatCore::const_iterator i = core.begin(); i != core.end(); ++i) {
+ map<Expr, string>::const_iterator j = names.find(*i);
+ if(j == names.end()) {
+ out << *i << endl;
+ } else {
+ out << (*j).second << endl;
+ }
+ }
+ out << ")" << endl;
+}/* Smt2Printer::toStream(UnsatCore, map<Expr, string>) */
+
+
void Smt2Printer::toStream(std::ostream& out, const Model& m) const throw() {
out << "(model" << endl;
this->Printer::toStream(out, m);
@@ -1042,6 +1057,10 @@ static void toStream(std::ostream& out, const GetProofCommand* c) throw() {
out << "(get-proof)";
}
+static void toStream(std::ostream& out, const GetUnsatCoreCommand* c) throw() {
+ out << "(get-unsat-core)";
+}
+
static void toStream(std::ostream& out, const SetBenchmarkStatusCommand* c) throw() {
out << "(set-info :status " << c->getStatus() << ")";
}
diff --git a/src/printer/smt2/smt2_printer.h b/src/printer/smt2/smt2_printer.h
index e86b3cb2b..dbbc67fc2 100644
--- a/src/printer/smt2/smt2_printer.h
+++ b/src/printer/smt2/smt2_printer.h
@@ -37,7 +37,6 @@ class Smt2Printer : public CVC4::Printer {
void toStream(std::ostream& out, TNode n, int toDepth, bool types) const throw();
void toStream(std::ostream& out, const Model& m, const Command* c) const throw();
- void toStream(std::ostream& out, const Model& m) const throw();
public:
Smt2Printer(Variant variant = no_variant) : d_variant(variant) { }
using CVC4::Printer::toStream;
@@ -46,6 +45,8 @@ public:
void toStream(std::ostream& out, const CommandStatus* s) const throw();
void toStream(std::ostream& out, const Result& r) const throw();
void toStream(std::ostream& out, const SExpr& sexpr) const throw();
+ void toStream(std::ostream& out, const Model& m) const throw();
+ void toStream(std::ostream& out, const UnsatCore& core, const std::map<Expr, std::string>& names) const throw();
};/* class Smt2Printer */
}/* CVC4::printer::smt2 namespace */
diff --git a/src/proof/cnf_proof.cpp b/src/proof/cnf_proof.cpp
index 3dfb61428..22a40ff69 100644
--- a/src/proof/cnf_proof.cpp
+++ b/src/proof/cnf_proof.cpp
@@ -30,6 +30,8 @@ CnfProof::CnfProof(CnfStream* stream)
: d_cnfStream(stream)
{}
+CnfProof::~CnfProof() {
+}
Expr CnfProof::getAtom(prop::SatVariable var) {
prop::SatLiteral lit (var);
@@ -38,34 +40,33 @@ Expr CnfProof::getAtom(prop::SatVariable var) {
return atom;
}
-CnfProof::~CnfProof() {
-}
-
-LFSCCnfProof::iterator LFSCCnfProof::begin_atom_mapping() {
- return iterator(*this, ProofManager::currentPM()->begin_vars());
+prop::SatLiteral CnfProof::getLiteral(TNode atom) {
+ return d_cnfStream->getLiteral(atom);
}
-LFSCCnfProof::iterator LFSCCnfProof::end_atom_mapping() {
- return iterator(*this, ProofManager::currentPM()->end_vars());
+Expr CnfProof::getAssertion(uint64_t id) {
+ return d_cnfStream->getAssertion(id).toExpr();
}
-void LFSCCnfProof::printAtomMapping(std::ostream& os, std::ostream& paren) {
- ProofManager::var_iterator it = ProofManager::currentPM()->begin_vars();
- ProofManager::var_iterator end = ProofManager::currentPM()->end_vars();
-
- for (;it != end; ++it) {
- os << "(decl_atom ";
-
- if (ProofManager::currentPM()->getLogic().compare("QF_UF") == 0) {
- Expr atom = getAtom(*it);
- LFSCTheoryProof::printTerm(atom, os);
- } else {
- // print fake atoms for all other logics
- os << "true ";
+void LFSCCnfProof::printAtomMapping(const prop::SatClause* clause, std::ostream& os, std::ostream& paren) {
+ for (unsigned i = 0; i < clause->size(); ++i) {
+ prop::SatLiteral lit = clause->operator[](i);
+ if(d_atomsDeclared.find(lit.getSatVariable()) == d_atomsDeclared.end()) {
+ d_atomsDeclared.insert(lit.getSatVariable());
+ os << "(decl_atom ";
+ if (ProofManager::currentPM()->getLogic().compare("QF_UF") == 0 ||
+ ProofManager::currentPM()->getLogic().compare("QF_AX") == 0 ||
+ ProofManager::currentPM()->getLogic().compare("QF_SAT") == 0) {
+ Expr atom = getAtom(lit.getSatVariable());
+ LFSCTheoryProof::printTerm(atom, os);
+ } else {
+ // print fake atoms for all other logics (for now)
+ os << "true ";
+ }
+
+ os << " (\\ " << ProofManager::getVarName(lit.getSatVariable()) << " (\\ " << ProofManager::getAtomName(lit.getSatVariable()) << "\n";
+ paren << ")))";
}
-
- os << " (\\ " << ProofManager::getVarName(*it) << " (\\ " << ProofManager::getAtomName(*it) << "\n";
- paren << ")))";
}
}
@@ -75,36 +76,93 @@ void LFSCCnfProof::printClauses(std::ostream& os, std::ostream& paren) {
}
void LFSCCnfProof::printInputClauses(std::ostream& os, std::ostream& paren) {
- os << " ;; Input Clauses \n";
+ os << " ;; Clauses\n";
ProofManager::clause_iterator it = ProofManager::currentPM()->begin_input_clauses();
ProofManager::clause_iterator end = ProofManager::currentPM()->end_input_clauses();
for (; it != end; ++it) {
ClauseId id = it->first;
const prop::SatClause* clause = it->second;
+ printAtomMapping(clause, os, paren);
os << "(satlem _ _ ";
std::ostringstream clause_paren;
printClause(*clause, os, clause_paren);
- os << " (clausify_false trust)" << clause_paren.str();
- os << "( \\ " << ProofManager::getInputClauseName(id) << "\n";
+ os << "(clausify_false trust)" << clause_paren.str()
+ << " (\\ " << ProofManager::getInputClauseName(id) << "\n";
paren << "))";
}
}
-
void LFSCCnfProof::printTheoryLemmas(std::ostream& os, std::ostream& paren) {
- os << " ;; Theory Lemmas \n";
- ProofManager::clause_iterator it = ProofManager::currentPM()->begin_lemmas();
- ProofManager::clause_iterator end = ProofManager::currentPM()->end_lemmas();
+ os << " ;; Theory Lemmas\n";
+ ProofManager::ordered_clause_iterator it = ProofManager::currentPM()->begin_lemmas();
+ ProofManager::ordered_clause_iterator end = ProofManager::currentPM()->end_lemmas();
+
+ for(size_t n = 0; it != end; ++it, ++n) {
+ if(n % 100 == 0) {
+ Chat() << "proving theory conflicts...(" << n << "/" << ProofManager::currentPM()->num_lemmas() << ")" << std::endl;
+ }
- for (; it != end; ++it) {
ClauseId id = it->first;
const prop::SatClause* clause = it->second;
+ NodeBuilder<> c(kind::AND);
+ for(unsigned i = 0; i < clause->size(); ++i) {
+ prop::SatLiteral lit = (*clause)[i];
+ prop::SatVariable var = lit.getSatVariable();
+ if(lit.isNegated()) {
+ c << Node::fromExpr(getAtom(var));
+ } else {
+ c << Node::fromExpr(getAtom(var)).notNode();
+ }
+ }
+ Node cl = c;
+ if(ProofManager::getSatProof()->d_lemmaClauses.find(id) != ProofManager::getSatProof()->d_lemmaClauses.end()) {
+ uint64_t proof_id = ProofManager::getSatProof()->d_lemmaClauses[id];
+ TNode orig = d_cnfStream->getAssertion(proof_id & 0xffffffff);
+ if(((proof_id >> 32) & 0xffffffff) == RULE_ARRAYS_EXT) {
+ Debug("cores") << "; extensional lemma!" << std::endl;
+ Assert(cl.getKind() == kind::AND && cl.getNumChildren() == 2 && cl[0].getKind() == kind::EQUAL && cl[0][0].getKind() == kind::SELECT);
+ TNode myk = cl[0][0][1];
+ Debug("cores") << "; so my skolemized k is " << myk << std::endl;
+ os << "(ext _ _ " << orig[0][0] << " " << orig[0][1] << " (\\ " << myk << " (\\ " << ProofManager::getLemmaName(id) << "\n";
+ paren << ")))";
+ }
+ }
+ printAtomMapping(clause, os, paren);
os << "(satlem _ _ ";
std::ostringstream clause_paren;
printClause(*clause, os, clause_paren);
- os << " (clausify_false trust)" << clause_paren.str();
- os << "( \\ " << ProofManager::getLemmaClauseName(id) <<"\n";
+
+ Debug("cores") << "\n;id is " << id << std::endl;
+ if(ProofManager::getSatProof()->d_lemmaClauses.find(id) != ProofManager::getSatProof()->d_lemmaClauses.end()) {
+ uint64_t proof_id = ProofManager::getSatProof()->d_lemmaClauses[id];
+ Debug("cores") << ";getting id " << int32_t(proof_id & 0xffffffff) << std::endl;
+ Assert(int32_t(proof_id & 0xffffffff) != -1);
+ TNode orig = d_cnfStream->getAssertion(proof_id & 0xffffffff);
+ Debug("cores") << "; ID is " << id << " and that's a lemma with " << ((proof_id >> 32) & 0xffffffff) << " / " << (proof_id & 0xffffffff) << std::endl;
+ Debug("cores") << "; that means the lemma was " << orig << std::endl;
+ if(((proof_id >> 32) & 0xffffffff) == RULE_ARRAYS_EXT) {
+ Debug("cores") << "; extensional" << std::endl;
+ os << "(clausify_false trust)\n";
+ } else if(proof_id == 0) {
+ // theory propagation caused conflict
+ //ProofManager::currentPM()->printProof(os, cl);
+ os << "(clausify_false trust)\n";
+ } else if(((proof_id >> 32) & 0xffffffff) == RULE_CONFLICT) {
+ os << "\n;; need to generate a (conflict) proof of " << cl << "\n";
+ //ProofManager::currentPM()->printProof(os, cl);
+ os << "(clausify_false trust)\n";
+ } else {
+ os << "\n;; need to generate a (lemma) proof of " << cl;
+ os << "\n;; DON'T KNOW HOW !!\n";
+ os << "(clausify_false trust)\n";
+ }
+ } else {
+ os << "\n;; need to generate a (conflict) proof of " << cl << "\n";
+ ProofManager::currentPM()->printProof(os, cl);
+ }
+ os << clause_paren.str()
+ << " (\\ " << ProofManager::getLemmaClauseName(id) << "\n";
paren << "))";
}
}
@@ -114,10 +172,10 @@ void LFSCCnfProof::printClause(const prop::SatClause& clause, std::ostream& os,
prop::SatLiteral lit = clause[i];
prop::SatVariable var = lit.getSatVariable();
if (lit.isNegated()) {
- os << "(ast _ _ _ " << ProofManager::getAtomName(var) <<" (\\ " << ProofManager::getLitName(lit) << " ";
+ os << "(ast _ _ _ " << ProofManager::getAtomName(var) << " (\\ " << ProofManager::getLitName(lit) << " ";
paren << "))";
} else {
- os << "(asf _ _ _ " << ProofManager::getAtomName(var) <<" (\\ " << ProofManager::getLitName(lit) << " ";
+ os << "(asf _ _ _ " << ProofManager::getAtomName(var) << " (\\ " << ProofManager::getLitName(lit) << " ";
paren << "))";
}
}
diff --git a/src/proof/cnf_proof.h b/src/proof/cnf_proof.h
index b2c35c4f7..459815e60 100644
--- a/src/proof/cnf_proof.h
+++ b/src/proof/cnf_proof.h
@@ -30,62 +30,38 @@
namespace CVC4 {
namespace prop {
class CnfStream;
-}
+}/* CVC4::prop namespace */
class CnfProof;
-class AtomIterator {
- CnfProof& d_cnf;
- ProofManager::var_iterator d_it;
-
-public:
- AtomIterator(CnfProof& cnf, const ProofManager::var_iterator& it)
- : d_cnf(cnf), d_it(it)
- {}
- inline Expr operator*();
- AtomIterator& operator++() { ++d_it; return *this; }
- AtomIterator operator++(int) { AtomIterator x = *this; ++d_it; return x; }
- bool operator==(const AtomIterator& it) const { return &d_cnf == &it.d_cnf && d_it == it.d_it; }
- bool operator!=(const AtomIterator& it) const { return !(*this == it); }
-};/* class AtomIterator */
-
class CnfProof {
protected:
CVC4::prop::CnfStream* d_cnfStream;
- Expr getAtom(prop::SatVariable var);
- friend class AtomIterator;
+ VarSet d_atomsDeclared;
public:
CnfProof(CVC4::prop::CnfStream* cnfStream);
- typedef AtomIterator iterator;
- virtual iterator begin_atom_mapping() = 0;
- virtual iterator end_atom_mapping() = 0;
+ Expr getAtom(prop::SatVariable var);
+ Expr getAssertion(uint64_t id);
+ prop::SatLiteral getLiteral(TNode atom);
- virtual void printAtomMapping(std::ostream& os, std::ostream& paren) = 0;
virtual void printClauses(std::ostream& os, std::ostream& paren) = 0;
virtual ~CnfProof();
-};
+};/* class CnfProof */
class LFSCCnfProof : public CnfProof {
void printInputClauses(std::ostream& os, std::ostream& paren);
void printTheoryLemmas(std::ostream& os, std::ostream& paren);
void printClause(const prop::SatClause& clause, std::ostream& os, std::ostream& paren);
+ virtual void printAtomMapping(const prop::SatClause* clause, std::ostream& os, std::ostream& paren);
public:
LFSCCnfProof(CVC4::prop::CnfStream* cnfStream)
: CnfProof(cnfStream)
{}
- virtual iterator begin_atom_mapping();
- virtual iterator end_atom_mapping();
-
- virtual void printAtomMapping(std::ostream& os, std::ostream& paren);
virtual void printClauses(std::ostream& os, std::ostream& paren);
-};
-
-inline Expr AtomIterator::operator*() {
- return d_cnf.getAtom(*d_it);
-}
+};/* class LFSCCnfProof */
} /* CVC4 namespace */
diff --git a/src/proof/proof.h b/src/proof/proof.h
index 174913755..440279dbc 100644
--- a/src/proof/proof.h
+++ b/src/proof/proof.h
@@ -22,9 +22,9 @@
#include "smt/options.h"
#ifdef CVC4_PROOF
-# define PROOF(x) if(options::proof()) { x; }
-# define NULLPROOF(x) (options::proof()) ? x : NULL
-# define PROOF_ON() options::proof()
+# define PROOF(x) if(options::proof() || options::unsatCores()) { x; }
+# define NULLPROOF(x) (options::proof() || options::unsatCores()) ? x : NULL
+# define PROOF_ON() (options::proof() || options::unsatCores())
#else /* CVC4_PROOF */
# define PROOF(x)
# define NULLPROOF(x) NULL
diff --git a/src/proof/proof_manager.cpp b/src/proof/proof_manager.cpp
index 680e57d39..87eded8e6 100644
--- a/src/proof/proof_manager.cpp
+++ b/src/proof/proof_manager.cpp
@@ -23,6 +23,15 @@
#include "util/cvc4_assert.h"
#include "smt/smt_engine.h"
#include "smt/smt_engine_scope.h"
+#include "theory/output_channel.h"
+#include "theory/valuation.h"
+#include "util/node_visitor.h"
+#include "theory/term_registration_visitor.h"
+#include "theory/uf/theory_uf.h"
+#include "theory/uf/equality_engine.h"
+#include "theory/arrays/theory_arrays.h"
+#include "context/context.h"
+#include "util/hash.h"
namespace CVC4 {
@@ -37,7 +46,8 @@ ProofManager::ProofManager(ProofFormat format):
d_cnfProof(NULL),
d_theoryProof(NULL),
d_fullProof(NULL),
- d_format(format)
+ d_format(format),
+ d_deps()
{
}
@@ -53,7 +63,7 @@ ProofManager::~ProofManager() {
delete it->second;
}
- for(IdToClause::iterator it = d_theoryLemmas.begin();
+ for(OrderedIdToClause::iterator it = d_theoryLemmas.begin();
it != d_theoryLemmas.end();
++it) {
delete it->second;
@@ -91,11 +101,10 @@ CnfProof* ProofManager::getCnfProof() {
}
TheoryProof* ProofManager::getTheoryProof() {
- Assert (currentPM()->d_theoryProof);
+ //Assert (currentPM()->d_theoryProof);
return currentPM()->d_theoryProof;
}
-
void ProofManager::initSatProof(Minisat::Solver* solver) {
Assert (currentPM()->d_satProof == NULL);
Assert(currentPM()->d_format == LFSC);
@@ -114,35 +123,101 @@ void ProofManager::initTheoryProof() {
currentPM()->d_theoryProof = new LFSCTheoryProof();
}
-
-std::string ProofManager::getInputClauseName(ClauseId id) {return append("pb", id); }
-std::string ProofManager::getLemmaClauseName(ClauseId id) { return append("lem", id); }
+std::string ProofManager::getInputClauseName(ClauseId id) { return append("pb", id); }
+std::string ProofManager::getLemmaName(ClauseId id) { return append("lem", id); }
+std::string ProofManager::getLemmaClauseName(ClauseId id) { return append("lemc", id); }
std::string ProofManager::getLearntClauseName(ClauseId id) { return append("cl", id); }
-std::string ProofManager::getVarName(prop::SatVariable var) { return append("v", var); }
-std::string ProofManager::getAtomName(prop::SatVariable var) { return append("a", var); }
-std::string ProofManager::getLitName(prop::SatLiteral lit) {return append("l", lit.toInt()); }
+std::string ProofManager::getVarName(prop::SatVariable var) { return append("var", var); }
+std::string ProofManager::getAtomName(prop::SatVariable var) { return append("atom", var); }
+std::string ProofManager::getLitName(prop::SatLiteral lit) { return append("lit", lit.toInt()); }
+
+std::string ProofManager::getAtomName(TNode atom) {
+ prop::SatLiteral lit = currentPM()->d_cnfProof->getLiteral(atom);
+ Assert(!lit.isNegated());
+ return getAtomName(lit.getSatVariable());
+}
+std::string ProofManager::getLitName(TNode lit) {
+ return getLitName(currentPM()->d_cnfProof->getLiteral(lit));
+}
+
+void ProofManager::traceDeps(TNode n) {
+ Debug("cores") << "trace deps " << n << std::endl;
+ if(d_inputCoreFormulas.find(n.toExpr()) != d_inputCoreFormulas.end()) {
+ // originating formula was in core set
+ Debug("cores") << " -- IN INPUT CORE LIST!" << std::endl;
+ d_outputCoreFormulas.insert(n.toExpr());
+ } else {
+ Debug("cores") << " -- NOT IN INPUT CORE LIST!" << std::endl;
+ if(d_deps.find(n) == d_deps.end()) {
+ InternalError("Cannot trace dependence information back to input assertion:\n`%s'", n.toString().c_str());
+ }
+ Assert(d_deps.find(n) != d_deps.end());
+ std::vector<Node> deps = (*d_deps.find(n)).second;
+ for(std::vector<Node>::const_iterator i = deps.begin(); i != deps.end(); ++i) {
+ Debug("cores") << " + tracing deps: " << n << " -deps-on- " << *i << std::endl;
+ traceDeps(*i);
+ }
+ }
+}
void ProofManager::addClause(ClauseId id, const prop::SatClause* clause, ClauseKind kind) {
- for (unsigned i = 0; i < clause->size(); ++i) {
+ /*for (unsigned i = 0; i < clause->size(); ++i) {
prop::SatLiteral lit = clause->operator[](i);
d_propVars.insert(lit.getSatVariable());
- }
+ }*/
if (kind == INPUT) {
d_inputClauses.insert(std::make_pair(id, clause));
- return;
+ Assert(d_satProof->d_inputClauses.find(id) != d_satProof->d_inputClauses.end());
+ Debug("cores") << "core id is " << d_satProof->d_inputClauses[id] << std::endl;
+ if(d_satProof->d_inputClauses[id] == uint64_t(-1)) {
+ Debug("cores") << " + constant unit (true or false)" << std::endl;
+ } else if(options::unsatCores()) {
+ Expr e = d_cnfProof->getAssertion(d_satProof->d_inputClauses[id] & 0xffffffff);
+ Debug("cores") << "core input assertion from CnfStream is " << e << std::endl;
+ Debug("cores") << "with proof rule " << ((d_satProof->d_inputClauses[id] & 0xffffffff00000000llu) >> 32) << std::endl;
+ // Invalid proof rules are currently used for parts of CVC4 that don't
+ // support proofs (these are e.g. unproven theory lemmas) or don't need
+ // proofs (e.g. split lemmas). We can ignore these safely when
+ // constructing unsat cores.
+ if(((d_satProof->d_inputClauses[id] & 0xffffffff00000000llu) >> 32) != RULE_INVALID) {
+ // trace dependences back to actual assertions
+ traceDeps(Node::fromExpr(e));
+ }
+ }
+ } else {
+ Assert(kind == THEORY_LEMMA);
+ d_theoryLemmas.insert(std::make_pair(id, clause));
}
- Assert (kind == THEORY_LEMMA);
- d_theoryLemmas.insert(std::make_pair(id, clause));
}
-void ProofManager::addAssertion(Expr formula) {
+void ProofManager::addAssertion(Expr formula, bool inUnsatCore) {
+ Debug("cores") << "assert: " << formula << std::endl;
d_inputFormulas.insert(formula);
+ d_deps[Node::fromExpr(formula)]; // empty vector of deps
+ if(inUnsatCore || options::dumpUnsatCores()) {
+ Debug("cores") << "adding to input core forms: " << formula << std::endl;
+ d_inputCoreFormulas.insert(formula);
+ }
}
-void ProofManager::setLogic(const std::string& logic_string) {
- d_logic = logic_string;
+void ProofManager::addDependence(TNode n, TNode dep) {
+ if(dep != n) {
+ Debug("cores") << "dep: " << n << " : " << dep << std::endl;
+ if(d_deps.find(dep) == d_deps.end()) {
+ Debug("cores") << "WHERE DID " << dep << " come from ??" << std::endl;
+ }
+ //Assert(d_deps.find(dep) != d_deps.end());
+ d_deps[n].push_back(dep);
+ }
+}
+
+void ProofManager::setLogic(const LogicInfo& logic) {
+ d_logic = logic;
}
+void ProofManager::printProof(std::ostream& os, TNode n) {
+ // no proofs here yet
+}
LFSCProof::LFSCProof(SmtEngine* smtEngine, LFSCSatProof* sat, LFSCCnfProof* cnf, LFSCTheoryProof* theory)
: d_satProof(sat)
@@ -157,17 +232,18 @@ void LFSCProof::toStream(std::ostream& out) {
smt::SmtScope scope(d_smtEngine);
std::ostringstream paren;
out << "(check\n";
+ out << " ;; Declarations\n";
if (d_theoryProof == NULL) {
d_theoryProof = new LFSCTheoryProof();
}
- for(LFSCCnfProof::iterator i = d_cnfProof->begin_atom_mapping();
+ /*for(LFSCCnfProof::iterator i = d_cnfProof->begin_atom_mapping();
i != d_cnfProof->end_atom_mapping();
++i) {
d_theoryProof->addDeclaration(*i);
- }
+ }*/
d_theoryProof->printAssertions(out, paren);
+ out << " ;; Proof of empty clause follows\n";
out << "(: (holds cln)\n";
- d_cnfProof->printAtomMapping(out, paren);
d_cnfProof->printClauses(out, paren);
d_satProof->printResolutions(out, paren);
paren <<")))\n;;";
@@ -175,5 +251,4 @@ void LFSCProof::toStream(std::ostream& out) {
out << "\n";
}
-
} /* CVC4 namespace */
diff --git a/src/proof/proof_manager.h b/src/proof/proof_manager.h
index f428de36d..d60a3f6e3 100644
--- a/src/proof/proof_manager.h
+++ b/src/proof/proof_manager.h
@@ -20,9 +20,12 @@
#define __CVC4__PROOF_MANAGER_H
#include <iostream>
+#include <map>
#include "proof/proof.h"
#include "util/proof.h"
-
+#include "expr/node.h"
+#include "theory/logic_info.h"
+#include "theory/substitutions.h"
// forward declarations
namespace Minisat {
@@ -63,6 +66,7 @@ enum ProofFormat {
std::string append(const std::string& str, uint64_t num);
typedef __gnu_cxx::hash_map < ClauseId, const prop::SatClause* > IdToClause;
+typedef std::map < ClauseId, const prop::SatClause* > OrderedIdToClause;
typedef __gnu_cxx::hash_set<prop::SatVariable > VarSet;
typedef __gnu_cxx::hash_set<Expr, ExprHashFunction > ExprSet;
@@ -74,6 +78,18 @@ enum ClauseKind {
LEARNT
};/* enum ClauseKind */
+enum ProofRule {
+ RULE_GIVEN, /* input assertion */
+ RULE_DERIVED, /* a "macro" rule */
+ RULE_RECONSTRUCT, /* prove equivalence using another method */
+ RULE_TRUST, /* trust without evidence (escape hatch until proofs are fully supported) */
+ RULE_INVALID, /* assert-fail if this is ever needed in proof; use e.g. for split lemmas */
+ RULE_CONFLICT, /* re-construct as a conflict */
+
+ RULE_ARRAYS_EXT, /* arrays, extensional */
+ RULE_ARRAYS_ROW, /* arrays, read-over-write */
+};/* enum ProofRules */
+
class ProofManager {
SatProof* d_satProof;
CnfProof* d_cnfProof;
@@ -81,15 +97,25 @@ class ProofManager {
// information that will need to be shared across proofs
IdToClause d_inputClauses;
- IdToClause d_theoryLemmas;
+ OrderedIdToClause d_theoryLemmas;
+ IdToClause d_theoryPropagations;
ExprSet d_inputFormulas;
- VarSet d_propVars;
+ ExprSet d_inputCoreFormulas;
+ ExprSet d_outputCoreFormulas;
+ //VarSet d_propVars;
+
+ int d_nextId;
Proof* d_fullProof;
ProofFormat d_format; // used for now only in debug builds
+ __gnu_cxx::hash_map< Node, std::vector<Node>, NodeHashFunction > d_deps;
+
+ // trace dependences back to unsat core
+ void traceDeps(TNode n);
+
protected:
- std::string d_logic;
+ LogicInfo d_logic;
public:
ProofManager(ProofFormat format = LFSC);
@@ -109,35 +135,50 @@ public:
// iterators over data shared by proofs
typedef IdToClause::const_iterator clause_iterator;
+ typedef OrderedIdToClause::const_iterator ordered_clause_iterator;
typedef ExprSet::const_iterator assertions_iterator;
typedef VarSet::const_iterator var_iterator;
clause_iterator begin_input_clauses() const { return d_inputClauses.begin(); }
clause_iterator end_input_clauses() const { return d_inputClauses.end(); }
+ size_t num_input_clauses() const { return d_inputClauses.size(); }
- clause_iterator begin_lemmas() const { return d_theoryLemmas.begin(); }
- clause_iterator end_lemmas() const { return d_theoryLemmas.end(); }
+ ordered_clause_iterator begin_lemmas() const { return d_theoryLemmas.begin(); }
+ ordered_clause_iterator end_lemmas() const { return d_theoryLemmas.end(); }
+ size_t num_lemmas() const { return d_theoryLemmas.size(); }
assertions_iterator begin_assertions() const { return d_inputFormulas.begin(); }
assertions_iterator end_assertions() const { return d_inputFormulas.end(); }
+ size_t num_assertions() const { return d_inputFormulas.size(); }
- var_iterator begin_vars() const { return d_propVars.begin(); }
- var_iterator end_vars() const { return d_propVars.end(); }
+ void printProof(std::ostream& os, TNode n);
- void addAssertion(Expr formula);
+ void addAssertion(Expr formula, bool inUnsatCore);
void addClause(ClauseId id, const prop::SatClause* clause, ClauseKind kind);
+ // note that n depends on dep (for cores)
+ void addDependence(TNode n, TNode dep);
+
+ assertions_iterator begin_unsat_core() const { return d_outputCoreFormulas.begin(); }
+ assertions_iterator end_unsat_core() const { return d_outputCoreFormulas.end(); }
+ size_t size_unsat_core() const { return d_outputCoreFormulas.size(); }
+
+ int nextId() { return d_nextId++; }
// variable prefixes
static std::string getInputClauseName(ClauseId id);
+ static std::string getLemmaName(ClauseId id);
static std::string getLemmaClauseName(ClauseId id);
static std::string getLearntClauseName(ClauseId id);
static std::string getVarName(prop::SatVariable var);
static std::string getAtomName(prop::SatVariable var);
+ static std::string getAtomName(TNode atom);
static std::string getLitName(prop::SatLiteral lit);
+ static std::string getLitName(TNode lit);
+
+ void setLogic(const LogicInfo& logic);
+ const std::string getLogic() const { return d_logic.getLogicString(); }
- void setLogic(const std::string& logic_string);
- const std::string getLogic() const { return d_logic; }
};/* class ProofManager */
class LFSCProof : public Proof {
diff --git a/src/proof/sat_proof.cpp b/src/proof/sat_proof.cpp
index 0ace84b4d..f7b9c4889 100644
--- a/src/proof/sat_proof.cpp
+++ b/src/proof/sat_proof.cpp
@@ -57,9 +57,6 @@ void printDebug (Minisat::Clause& c) {
Debug("proof:sat") << endl;
}
-
-int SatProof::d_idCounter = 0;
-
/**
* Converts the clause associated to id to a set of literals
*
@@ -274,7 +271,7 @@ ClauseId SatProof::getClauseId(::Minisat::Lit lit) {
Minisat::CRef SatProof::getClauseRef(ClauseId id) {
if (d_idClause.find(id) == d_idClause.end()) {
- Debug("proof:sat") << "proof:getClauseRef cannot find clause "<<id<<" "
+ Debug("proof:sat") << "proof:getClauseRef cannot find clause " << id << " "
<< ((d_deleted.find(id) != d_deleted.end()) ? "deleted" : "")
<< (isUnit(id)? "Unit" : "") << endl;
}
@@ -318,16 +315,14 @@ bool SatProof::isLemmaClause(ClauseId id) {
return (d_lemmaClauses.find(id) != d_lemmaClauses.end());
}
-
void SatProof::print(ClauseId id) {
if (d_deleted.find(id) != d_deleted.end()) {
- Debug("proof:sat") << "del"<<id;
+ Debug("proof:sat") << "del" << id;
} else if (isUnit(id)) {
printLit(getUnit(id));
} else if (id == d_emptyClauseId) {
- Debug("proof:sat") << "empty "<< endl;
- }
- else {
+ Debug("proof:sat") << "empty " << endl;
+ } else {
CRef ref = getClauseRef(id);
printClause(getClause(ref));
}
@@ -335,7 +330,7 @@ void SatProof::print(ClauseId id) {
void SatProof::printRes(ClauseId id) {
Assert(hasResolution(id));
- Debug("proof:sat") << "id "<< id <<": ";
+ Debug("proof:sat") << "id " << id << ": ";
printRes(d_resChains[id]);
}
@@ -364,42 +359,44 @@ void SatProof::printRes(ResChain* res) {
/// registration methods
-ClauseId SatProof::registerClause(::Minisat::CRef clause, ClauseKind kind) {
+ClauseId SatProof::registerClause(::Minisat::CRef clause, ClauseKind kind, uint64_t proof_id) {
+ Debug("cores") << "registerClause " << proof_id << std::endl;
Assert(clause != CRef_Undef);
ClauseIdMap::iterator it = d_clauseId.find(clause);
if (it == d_clauseId.end()) {
- ClauseId newId = d_idCounter++;
+ ClauseId newId = ProofManager::currentPM()->nextId();
d_clauseId[clause] = newId;
d_idClause[newId] = clause;
if (kind == INPUT) {
Assert(d_inputClauses.find(newId) == d_inputClauses.end());
- d_inputClauses.insert(newId);
+ d_inputClauses[newId] = proof_id;
}
if (kind == THEORY_LEMMA) {
Assert(d_lemmaClauses.find(newId) == d_lemmaClauses.end());
- d_lemmaClauses.insert(newId);
+ d_lemmaClauses[newId] = proof_id;
}
}
- Debug("proof:sat:detailed") <<"registerClause CRef:" << clause <<" id:" << d_clauseId[clause] << " " << kind << "\n";
+ Debug("proof:sat:detailed") << "registerClause CRef:" << clause << " id:" << d_clauseId[clause] << " " << kind << " " << int32_t((proof_id >> 32) & 0xffffffff) << "\n";
return d_clauseId[clause];
}
-ClauseId SatProof::registerUnitClause(::Minisat::Lit lit, ClauseKind kind) {
+ClauseId SatProof::registerUnitClause(::Minisat::Lit lit, ClauseKind kind, uint64_t proof_id) {
+ Debug("cores") << "registerUnitClause " << kind << " " << proof_id << std::endl;
UnitIdMap::iterator it = d_unitId.find(toInt(lit));
if (it == d_unitId.end()) {
- ClauseId newId = d_idCounter++;
+ ClauseId newId = ProofManager::currentPM()->nextId();
d_unitId[toInt(lit)] = newId;
d_idUnit[newId] = lit;
if (kind == INPUT) {
Assert(d_inputClauses.find(newId) == d_inputClauses.end());
- d_inputClauses.insert(newId);
+ d_inputClauses[newId] = proof_id;
}
if (kind == THEORY_LEMMA) {
Assert(d_lemmaClauses.find(newId) == d_lemmaClauses.end());
- d_lemmaClauses.insert(newId);
+ d_lemmaClauses[newId] = proof_id;
}
}
- Debug("proof:sat:detailed") <<"registerUnitClause " << d_unitId[toInt(lit)] << " " << kind <<"\n";
+ Debug("proof:sat:detailed") << "registerUnitClause " << d_unitId[toInt(lit)] << " " << kind << "\n";
return d_unitId[toInt(lit)];
}
@@ -445,7 +442,7 @@ void SatProof::removeRedundantFromRes(ResChain* res, ClauseId id) {
removedDfs(*it, removed, removeStack, inClause, seen);
}
- for (int i = removeStack.size()-1; i >= 0; --i) {
+ for (int i = removeStack.size() - 1; i >= 0; --i) {
Lit lit = removeStack[i];
CRef reason_ref = d_solver->reason(var(lit));
ClauseId reason_id;
@@ -454,7 +451,7 @@ void SatProof::removeRedundantFromRes(ResChain* res, ClauseId id) {
Assert(isUnit(~lit));
reason_id = getUnitId(~lit);
} else {
- reason_id = registerClause(reason_ref);
+ reason_id = registerClause(reason_ref, LEARNT, uint64_t(-1));
}
res->addStep(lit, reason_id, !sign(lit));
}
@@ -486,14 +483,14 @@ void SatProof::startResChain(::Minisat::CRef start) {
}
void SatProof::addResolutionStep(::Minisat::Lit lit, ::Minisat::CRef clause, bool sign) {
- ClauseId id = registerClause(clause);
+ ClauseId id = registerClause(clause, LEARNT, uint64_t(-1));
ResChain* res = d_resStack.back();
res->addStep(lit, id, sign);
}
void SatProof::endResChain(CRef clause) {
Assert(d_resStack.size() > 0);
- ClauseId id = registerClause(clause);
+ ClauseId id = registerClause(clause, LEARNT, uint64_t(-1));
ResChain* res = d_resStack.back();
registerResolution(id, res);
d_resStack.pop_back();
@@ -502,7 +499,7 @@ void SatProof::endResChain(CRef clause) {
void SatProof::endResChain(::Minisat::Lit lit) {
Assert(d_resStack.size() > 0);
- ClauseId id = registerUnitClause(lit);
+ ClauseId id = registerUnitClause(lit, LEARNT, uint64_t(-1));
ResChain* res = d_resStack.back();
registerResolution(id, res);
d_resStack.pop_back();
@@ -523,6 +520,7 @@ void SatProof::resolveOutUnit(::Minisat::Lit lit) {
}
void SatProof::storeUnitResolution(::Minisat::Lit lit) {
+ Debug("cores") << "STORE UNIT RESOLUTION" << std::endl;
resolveUnit(lit);
}
@@ -536,7 +534,7 @@ ClauseId SatProof::resolveUnit(::Minisat::Lit lit) {
CRef reason_ref = d_solver->reason(var(lit));
Assert(reason_ref != CRef_Undef);
- ClauseId reason_id = registerClause(reason_ref);
+ ClauseId reason_id = registerClause(reason_ref, LEARNT, uint64_t(-1));
ResChain* res = new ResChain(reason_id);
// Here, the call to resolveUnit() can reallocate memory in the
@@ -551,7 +549,7 @@ ClauseId SatProof::resolveUnit(::Minisat::Lit lit) {
res->addStep(l, res_id, !sign(l));
}
}
- ClauseId unit_id = registerUnitClause(lit);
+ ClauseId unit_id = registerUnitClause(lit, LEARNT, uint64_t(-1));
registerResolution(unit_id, res);
return unit_id;
}
@@ -561,11 +559,12 @@ void SatProof::toStream(std::ostream& out) {
Unimplemented("native proof printing not supported yet");
}
-void SatProof::storeUnitConflict(::Minisat::Lit conflict_lit, ClauseKind kind) {
+void SatProof::storeUnitConflict(::Minisat::Lit conflict_lit, ClauseKind kind, uint64_t proof_id) {
+ Debug("cores") << "STORE UNIT CONFLICT" << std::endl;
Assert(!d_storedUnitConflict);
- d_unitConflictId = registerUnitClause(conflict_lit, kind);
+ d_unitConflictId = registerUnitClause(conflict_lit, kind, proof_id);
d_storedUnitConflict = true;
- Debug("proof:sat:detailed") <<"storeUnitConflict " << d_unitConflictId << "\n";
+ Debug("proof:sat:detailed") << "storeUnitConflict " << d_unitConflictId << "\n";
}
void SatProof::finalizeProof(::Minisat::CRef conflict_ref) {
@@ -586,7 +585,7 @@ void SatProof::finalizeProof(::Minisat::CRef conflict_ref) {
return;
} else {
Assert(!d_storedUnitConflict);
- conflict_id = registerClause(conflict_ref); //FIXME
+ conflict_id = registerClause(conflict_ref, LEARNT, uint64_t(-1)); //FIXME
}
if(Debug.isOn("proof:sat")) {
@@ -652,11 +651,10 @@ std::string SatProof::clauseName(ClauseId id) {
if (isInputClause(id)) {
os << ProofManager::getInputClauseName(id);
return os.str();
- } else
- if (isLemmaClause(id)) {
+ } else if (isLemmaClause(id)) {
os << ProofManager::getLemmaClauseName(id);
return os.str();
- }else {
+ } else {
os << ProofManager::getLearntClauseName(id);
return os.str();
}
@@ -728,10 +726,9 @@ void LFSCSatProof::printResolution(ClauseId id, std::ostream& out, std::ostream&
ResChain* res = d_resChains[id];
ResSteps& steps = res->getSteps();
- for (int i = steps.size()-1; i >= 0; i--) {
+ for (int i = steps.size() - 1; i >= 0; --i) {
out << "(";
out << (steps[i].sign? "R" : "Q") << " _ _ ";
-
}
ClauseId start_id = res->getStart();
@@ -742,11 +739,13 @@ void LFSCSatProof::printResolution(ClauseId id, std::ostream& out, std::ostream&
out << clauseName(start_id) << " ";
for(unsigned i = 0; i < steps.size(); i++) {
- out << clauseName(steps[i].id) << " "<<ProofManager::getVarName(MinisatSatSolver::toSatVariable(var(steps[i].lit))) <<")";
+ out << clauseName(steps[i].id) << " "
+ << ProofManager::getVarName(MinisatSatSolver::toSatVariable(var(steps[i].lit)))
+ << ") ";
}
if (id == d_emptyClauseId) {
- out <<"(\\empty empty)";
+ out << "(\\empty empty)";
return;
}
@@ -763,6 +762,4 @@ void LFSCSatProof::printResolutions(std::ostream& out, std::ostream& paren) {
printResolution(d_emptyClauseId, out, paren);
}
-
} /* CVC4 namespace */
-
diff --git a/src/proof/sat_proof.h b/src/proof/sat_proof.h
index 7795dfa9c..ef4e7a5aa 100644
--- a/src/proof/sat_proof.h
+++ b/src/proof/sat_proof.h
@@ -86,6 +86,7 @@ typedef std::hash_map < ClauseId, ::Minisat::Lit> IdUnitMap;
typedef std::hash_map < int, ClauseId> UnitIdMap; //FIXME
typedef std::hash_map < ClauseId, ResChain*> IdResMap;
typedef std::hash_set < ClauseId > IdHashSet;
+typedef std::hash_map < ClauseId, uint64_t > IdProofRuleMap;
typedef std::vector < ResChain* > ResStack;
typedef std::hash_map <ClauseId, prop::SatClause* > IdToSatClause;
typedef std::set < ClauseId > IdSet;
@@ -115,14 +116,15 @@ protected:
UnitIdMap d_unitId;
IdHashSet d_deleted;
IdToSatClause d_deletedTheoryLemmas;
- IdHashSet d_inputClauses;
- IdHashSet d_lemmaClauses;
+public:
+ IdProofRuleMap d_inputClauses;
+ IdProofRuleMap d_lemmaClauses;
+protected:
// resolutions
IdResMap d_resChains;
ResStack d_resStack;
bool d_checkRes;
- static ClauseId d_idCounter;
const ClauseId d_emptyClauseId;
const ClauseId d_nullId;
// proxy class to break circular dependencies
@@ -144,6 +146,7 @@ protected:
void printRes(ResChain* res);
bool isInputClause(ClauseId id);
+ bool isTheoryConflict(ClauseId id);
bool isLemmaClause(ClauseId id);
bool isUnit(ClauseId id);
bool isUnit(::Minisat::Lit lit);
@@ -207,10 +210,10 @@ public:
void finalizeProof(::Minisat::CRef conflict);
/// clause registration methods
- ClauseId registerClause(const ::Minisat::CRef clause, ClauseKind kind = LEARNT);
- ClauseId registerUnitClause(const ::Minisat::Lit lit, ClauseKind kind = LEARNT);
+ ClauseId registerClause(const ::Minisat::CRef clause, ClauseKind kind, uint64_t proof_id);
+ ClauseId registerUnitClause(const ::Minisat::Lit lit, ClauseKind kind, uint64_t proof_id);
- void storeUnitConflict(::Minisat::Lit lit, ClauseKind kind = LEARNT);
+ void storeUnitConflict(::Minisat::Lit lit, ClauseKind kind, uint64_t proof_id);
/**
* Marks the deleted clauses as deleted. Note we may still use them in the final
@@ -242,6 +245,7 @@ public:
protected:
IdSet d_seenLearnt;
IdHashSet d_seenInput;
+ IdHashSet d_seenTheoryConflicts;
IdHashSet d_seenLemmas;
inline std::string varName(::Minisat::Lit lit);
diff --git a/src/prop/bvminisat/bvminisat.cpp b/src/prop/bvminisat/bvminisat.cpp
index 7322cd0fa..498b31ce5 100644
--- a/src/prop/bvminisat/bvminisat.cpp
+++ b/src/prop/bvminisat/bvminisat.cpp
@@ -5,7 +5,7 @@
** Major contributors:
** Minor contributors (to current version):
** This file is part of the CVC4 prototype.
- ** Copyright (c) 2009, 2010, 2011 The Analysis of Computer Systems Group (ACSys)
+ ** Copyright (c) 2009-2014 The Analysis of Computer Systems Group (ACSys)
** Courant Institute of Mathematical Sciences
** New York University
** See the file COPYING in the top-level source directory for licensing
@@ -45,7 +45,7 @@ void BVMinisatSatSolver::setNotify(Notify* notify) {
d_minisat->setNotify(d_minisatNotify);
}
-void BVMinisatSatSolver::addClause(SatClause& clause, bool removable) {
+void BVMinisatSatSolver::addClause(SatClause& clause, bool removable, uint64_t proof_id) {
Debug("sat::minisat") << "Add clause " << clause <<"\n";
BVMinisat::vec<BVMinisat::Lit> minisat_clause;
toMinisatClause(clause, minisat_clause);
@@ -97,6 +97,10 @@ void BVMinisatSatSolver::markUnremovable(SatLiteral lit){
d_minisat->setFrozen(BVMinisat::var(toMinisatLit(lit)), true);
}
+void BVMinisatSatSolver::spendResource(){
+ // do nothing for the BV solver
+}
+
void BVMinisatSatSolver::interrupt(){
d_minisat->interrupt();
}
diff --git a/src/prop/bvminisat/bvminisat.h b/src/prop/bvminisat/bvminisat.h
index f9d0fbd6a..04f21e761 100644
--- a/src/prop/bvminisat/bvminisat.h
+++ b/src/prop/bvminisat/bvminisat.h
@@ -5,7 +5,7 @@
** Major contributors:
** Minor contributors (to current version):
** This file is part of the CVC4 prototype.
- ** Copyright (c) 2009, 2010, 2011 The Analysis of Computer Systems Group (ACSys)
+ ** Copyright (c) 2009-2014 The Analysis of Computer Systems Group (ACSys)
** Courant Institute of Mathematical Sciences
** New York University
** See the file COPYING in the top-level source directory for licensing
@@ -76,7 +76,7 @@ public:
void setNotify(Notify* notify);
- void addClause(SatClause& clause, bool removable);
+ void addClause(SatClause& clause, bool removable, uint64_t proof_id);
SatValue propagate();
@@ -87,6 +87,8 @@ public:
void markUnremovable(SatLiteral lit);
+ void spendResource();
+
void interrupt();
SatValue solve();
diff --git a/src/prop/cnf_stream.cpp b/src/prop/cnf_stream.cpp
index e0697735f..ad187aa46 100644
--- a/src/prop/cnf_stream.cpp
+++ b/src/prop/cnf_stream.cpp
@@ -44,7 +44,6 @@ using namespace CVC4::kind;
namespace CVC4 {
namespace prop {
-
CnfStream::CnfStream(SatSolver *satSolver, Registrar* registrar, context::Context* context, bool fullLitToNodeMap) :
d_satSolver(satSolver),
d_booleanVariables(context),
@@ -52,6 +51,7 @@ CnfStream::CnfStream(SatSolver *satSolver, Registrar* registrar, context::Contex
d_literalToNodeMap(context),
d_fullLitToNodeMap(fullLitToNodeMap),
d_registrar(registrar),
+ d_assertionTable(context),
d_removable(false) {
}
@@ -74,7 +74,7 @@ void CnfStream::assertClause(TNode node, SatClause& c) {
Dump("clauses") << AssertCommand(Expr(n.toExpr()));
}
}
- d_satSolver->addClause(c, d_removable);
+ d_satSolver->addClause(c, d_removable, d_proofId);
}
void CnfStream::assertClause(TNode node, SatLiteral a) {
@@ -104,9 +104,9 @@ bool CnfStream::hasLiteral(TNode n) const {
}
void TseitinCnfStream::ensureLiteral(TNode n) {
-
- // These are not removable
+ // These are not removable and have no proof ID
d_removable = false;
+ d_proofId = uint64_t(-1);
Debug("cnf") << "ensureLiteral(" << n << ")" << endl;
if(hasLiteral(n)) {
@@ -188,9 +188,12 @@ SatLiteral CnfStream::newLiteral(TNode node, bool isTheoryAtom, bool preRegister
// If a theory literal, we pre-register it
if (preRegister) {
- bool backup = d_removable;
+ // In case we are re-entered due to lemmas, save our state
+ bool backupRemovable = d_removable;
+ uint64_t backupProofId= d_proofId;
d_registrar->preRegister(node);
- d_removable = backup;
+ d_removable = backupRemovable;
+ d_proofId = backupProofId;
}
// Here, you can have it
@@ -642,9 +645,20 @@ void TseitinCnfStream::convertAndAssertIte(TNode node, bool negated) {
// At the top level we must ensure that all clauses that are asserted are
// not unit, except for the direct assertions. This allows us to remove the
// clauses later when they are not needed anymore (lemmas for example).
-void TseitinCnfStream::convertAndAssert(TNode node, bool removable, bool negated) {
+void TseitinCnfStream::convertAndAssert(TNode node, bool removable, bool negated, ProofRule proof_id, TNode from) {
Debug("cnf") << "convertAndAssert(" << node << ", removable = " << (removable ? "true" : "false") << ", negated = " << (negated ? "true" : "false") << ")" << endl;
d_removable = removable;
+ if(options::proof() || options::unsatCores()) {
+ // Encode the assertion ID in the proof_id to store with generated clauses.
+ uint64_t assertionTableIndex = d_assertionTable.size();
+ Assert((uint64_t(proof_id) & 0xffffffff00000000llu) == 0 && (assertionTableIndex & 0xffffffff00000000llu) == 0, "proof_id/table_index collision");
+ d_proofId = assertionTableIndex | (uint64_t(proof_id) << 32);
+ d_assertionTable.push_back(from.isNull() ? node : from);
+ Debug("cores") << "cnf ix " << assertionTableIndex << " asst " << node << " proof_id " << proof_id << " from " << from << endl;
+ } else {
+ // We aren't producing proofs or unsat cores; use an invalid proof id.
+ d_proofId = uint64_t(-1);
+ }
convertAndAssert(node, negated);
}
diff --git a/src/prop/cnf_stream.h b/src/prop/cnf_stream.h
index 266362ef5..b76051279 100644
--- a/src/prop/cnf_stream.h
+++ b/src/prop/cnf_stream.h
@@ -28,6 +28,7 @@
#include "expr/node.h"
#include "prop/theory_proxy.h"
#include "prop/registrar.h"
+#include "proof/proof_manager.h"
#include "context/cdlist.h"
#include "context/cdinsert_hashmap.h"
@@ -36,7 +37,6 @@
namespace CVC4 {
namespace prop {
-
class PropEngine;
/**
@@ -77,6 +77,9 @@ protected:
/** The "registrar" for pre-registration of terms */
Registrar* d_registrar;
+ /** A table of assertions, used for regenerating proofs. */
+ context::CDList<Node> d_assertionTable;
+
/**
* How many literals were already mapped at the top-level when we
* tried to convertAndAssert() something. This
@@ -104,10 +107,18 @@ protected:
}
/**
+ * A reference into the assertion table, used to map clauses back to
+ * their "original" input assertion/lemma. This variable is manipulated
+ * by the top-level convertAndAssert(). This is needed in proofs-enabled
+ * runs, to justify where the SAT solver's clauses came from.
+ */
+ uint64_t d_proofId;
+
+ /**
* Are we asserting a removable clause (true) or a permanent clause (false).
* This is set at the beginning of convertAndAssert so that it doesn't
- * need to be passed on over the stack. Only pure clauses can be asserted as
- * removable.
+ * need to be passed on over the stack. Only pure clauses can be asserted
+ * as removable.
*/
bool d_removable;
@@ -190,7 +201,7 @@ public:
* @param removable whether the sat solver can choose to remove the clauses
* @param negated whether we are asserting the node negated
*/
- virtual void convertAndAssert(TNode node, bool removable, bool negated) = 0;
+ virtual void convertAndAssert(TNode node, bool removable, bool negated, ProofRule proof_id, TNode from = TNode::null()) = 0;
/**
* Get the node that is represented by the given SatLiteral.
@@ -223,6 +234,13 @@ public:
SatLiteral getLiteral(TNode node);
/**
+ * Get the assertion with a given ID. (Used for reconstructing proofs.)
+ */
+ TNode getAssertion(uint64_t id) {
+ return d_assertionTable[id];
+ }
+
+ /**
* Returns the Boolean variables from the input problem.
*/
void getBooleanVariables(std::vector<TNode>& outputVariables) const;
@@ -258,7 +276,7 @@ public:
* @param removable is this something that can be erased
* @param negated true if negated
*/
- void convertAndAssert(TNode node, bool removable, bool negated);
+ void convertAndAssert(TNode node, bool removable, bool negated, ProofRule proof_id, TNode from = TNode::null());
/**
* Constructs the stream to use the given sat solver.
diff --git a/src/prop/minisat/core/Solver.cc b/src/prop/minisat/core/Solver.cc
index 610023b70..5403b992e 100644
--- a/src/prop/minisat/core/Solver.cc
+++ b/src/prop/minisat/core/Solver.cc
@@ -106,7 +106,7 @@ Solver::Solver(CVC4::prop::TheoryProxy* proxy, CVC4::context::Context* context,
// Statistics: (formerly in 'SolverStats')
//
- , solves(0), starts(0), decisions(0), rnd_decisions(0), propagations(0), conflicts(0)
+ , solves(0), starts(0), decisions(0), rnd_decisions(0), propagations(0), conflicts(0), resources_consumed(0)
, dec_vars(0), clauses_literals(0), learnts_literals(0), max_literals(0), tot_literals(0)
, ok (true)
@@ -135,8 +135,8 @@ Solver::Solver(CVC4::prop::TheoryProxy* proxy, CVC4::context::Context* context,
// Assert the constants
uncheckedEnqueue(mkLit(varTrue, false));
uncheckedEnqueue(mkLit(varFalse, true));
- PROOF( ProofManager::getSatProof()->registerUnitClause(mkLit(varTrue, false), INPUT); )
- PROOF( ProofManager::getSatProof()->registerUnitClause(mkLit(varFalse, true), INPUT); )
+ PROOF( ProofManager::getSatProof()->registerUnitClause(mkLit(varTrue, false), INPUT, uint64_t(-1)); )
+ PROOF( ProofManager::getSatProof()->registerUnitClause(mkLit(varFalse, true), INPUT, uint64_t(-1)); )
}
@@ -263,7 +263,7 @@ CRef Solver::reason(Var x) {
// Construct the reason
CRef real_reason = ca.alloc(explLevel, explanation, true);
- PROOF (ProofManager::getSatProof()->registerClause(real_reason, THEORY_LEMMA); );
+ PROOF (ProofManager::getSatProof()->registerClause(real_reason, THEORY_LEMMA, (uint64_t(RULE_CONFLICT) << 32)); );
vardata[x] = VarData(real_reason, level(x), user_level(x), intro_level(x), trail_index(x));
clauses_removable.push(real_reason);
attachClause(real_reason);
@@ -271,7 +271,7 @@ CRef Solver::reason(Var x) {
return real_reason;
}
-bool Solver::addClause_(vec<Lit>& ps, bool removable)
+bool Solver::addClause_(vec<Lit>& ps, bool removable, uint64_t proof_id)
{
if (!ok) return false;
@@ -321,6 +321,8 @@ bool Solver::addClause_(vec<Lit>& ps, bool removable)
lemmas.push();
ps.copyTo(lemmas.last());
lemmas_removable.push(removable);
+ Debug("cores") << "lemma push " << proof_id << " " << (proof_id & 0xffffffff) << std::endl;
+ lemmas_proof_id.push(proof_id);
} else {
// If all false, we're in conflict
if (ps.size() == falseLiteralsCount) {
@@ -329,7 +331,7 @@ bool Solver::addClause_(vec<Lit>& ps, bool removable)
// construct the clause below to give to the proof manager
// as the final conflict.
if(falseLiteralsCount == 1) {
- PROOF( ProofManager::getSatProof()->storeUnitConflict(ps[0], INPUT); )
+ PROOF( ProofManager::getSatProof()->storeUnitConflict(ps[0], INPUT, proof_id); )
PROOF( ProofManager::getSatProof()->finalizeProof(::Minisat::CRef_Lazy); )
return ok = false;
}
@@ -351,7 +353,7 @@ bool Solver::addClause_(vec<Lit>& ps, bool removable)
attachClause(cr);
if(PROOF_ON()) {
- PROOF( ProofManager::getSatProof()->registerClause(cr, INPUT); )
+ PROOF( ProofManager::getSatProof()->registerClause(cr, INPUT, proof_id); )
if(ps.size() == falseLiteralsCount) {
PROOF( ProofManager::getSatProof()->finalizeProof(cr); )
return ok = false;
@@ -364,11 +366,12 @@ bool Solver::addClause_(vec<Lit>& ps, bool removable)
if(assigns[var(ps[0])] == l_Undef) {
assert(assigns[var(ps[0])] != l_False);
uncheckedEnqueue(ps[0], cr);
- PROOF( if(ps.size() == 1) { ProofManager::getSatProof()->registerUnitClause(ps[0], INPUT); } );
+ Debug("cores") << "i'm registering a unit clause, input, proof id " << proof_id << std::endl;
+ PROOF( if(ps.size() == 1) { ProofManager::getSatProof()->registerUnitClause(ps[0], INPUT, proof_id); } );
CRef confl = propagate(CHECK_WITHOUT_THEORY);
if(! (ok = (confl == CRef_Undef)) ) {
if(ca[confl].size() == 1) {
- PROOF( ProofManager::getSatProof()->storeUnitConflict(ca[confl][0], LEARNT); );
+ PROOF( ProofManager::getSatProof()->storeUnitConflict(ca[confl][0], LEARNT, proof_id); );
PROOF( ProofManager::getSatProof()->finalizeProof(::Minisat::CRef_Lazy); )
} else {
PROOF( ProofManager::getSatProof()->finalizeProof(confl); );
@@ -842,7 +845,7 @@ CRef Solver::propagate(TheoryCheckType type)
propagateTheory();
// If there are lemmas (or conflicts) update them
if (lemmas.size() > 0) {
- confl = updateLemmas();
+ confl = updateLemmas();
}
} else {
// Even though in conflict, we still need to discharge the lemmas
@@ -891,7 +894,7 @@ void Solver::propagateTheory() {
proxy->explainPropagation(MinisatSatSolver::toSatLiteral(p), explanation_cl);
vec<Lit> explanation;
MinisatSatSolver::toMinisatClause(explanation_cl, explanation);
- addClause(explanation, true);
+ addClause(explanation, true, 0);
}
}
}
@@ -1588,6 +1591,9 @@ CRef Solver::updateLemmas() {
Debug("minisat::lemmas") << "Solver::updateLemmas() begin" << std::endl;
+ // Avoid adding lemmas indefinitely without resource-out
+ spendResource();
+
CRef conflict = CRef_Undef;
// Decision level to backtrack to
@@ -1642,6 +1648,8 @@ CRef Solver::updateLemmas() {
// The current lemma
vec<Lit>& lemma = lemmas[i];
bool removable = lemmas_removable[i];
+ uint64_t proof_id = lemmas_proof_id[i];
+ Debug("cores") << "pulled lemma proof id " << proof_id << " " << (proof_id & 0xffffffff) << std::endl;
// Attach it if non-unit
CRef lemma_ref = CRef_Undef;
@@ -1656,7 +1664,7 @@ CRef Solver::updateLemmas() {
}
lemma_ref = ca.alloc(clauseLevel, lemma, removable);
- PROOF( ProofManager::getSatProof()->registerClause(lemma_ref, THEORY_LEMMA); );
+ PROOF( ProofManager::getSatProof()->registerClause(lemma_ref, THEORY_LEMMA, proof_id); );
if (removable) {
clauses_removable.push(lemma_ref);
} else {
@@ -1664,7 +1672,7 @@ CRef Solver::updateLemmas() {
}
attachClause(lemma_ref);
} else {
- PROOF( ProofManager::getSatProof()->registerUnitClause(lemma[0], THEORY_LEMMA); );
+ PROOF( ProofManager::getSatProof()->registerUnitClause(lemma[0], THEORY_LEMMA, proof_id); );
}
// If the lemma is propagating enqueue its literal (or set the conflict)
@@ -1678,7 +1686,7 @@ CRef Solver::updateLemmas() {
} else {
Debug("minisat::lemmas") << "Solver::updateLemmas(): unit conflict or empty clause" << std::endl;
conflict = CRef_Lazy;
- PROOF( ProofManager::getSatProof()->storeUnitConflict(lemma[0]); );
+ PROOF( ProofManager::getSatProof()->storeUnitConflict(lemma[0], LEARNT, proof_id); );
}
} else {
Debug("minisat::lemmas") << "lemma size is " << lemma.size() << std::endl;
@@ -1691,6 +1699,7 @@ CRef Solver::updateLemmas() {
// Clear the lemmas
lemmas.clear();
lemmas_removable.clear();
+ lemmas_proof_id.clear();
if (conflict != CRef_Undef) {
theoryConflict = true;
diff --git a/src/prop/minisat/core/Solver.h b/src/prop/minisat/core/Solver.h
index 30d72ac75..2d70cfeef 100644
--- a/src/prop/minisat/core/Solver.h
+++ b/src/prop/minisat/core/Solver.h
@@ -37,12 +37,11 @@ OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWA
#include "expr/command.h"
namespace CVC4 {
-class SatProof;
-
-namespace prop {
- class TheoryProxy;
-}/* CVC4::prop namespace */
+ class SatProof;
+ namespace prop {
+ class TheoryProxy;
+ }/* CVC4::prop namespace */
}/* CVC4 namespace */
namespace Minisat {
@@ -85,6 +84,9 @@ protected:
/** Is the lemma removable */
vec<bool> lemmas_removable;
+ /** Proof IDs for lemmas */
+ vec<uint64_t> lemmas_proof_id;
+
/** Do a another check if FULL_EFFORT was the last one */
bool recheck;
@@ -154,12 +156,14 @@ public:
void push ();
void pop ();
- bool addClause (const vec<Lit>& ps, bool removable); // Add a clause to the solver.
+ // CVC4 adds the "proof_id" here to refer to the input assertion/lemma
+ // that produced this clause
+ bool addClause (const vec<Lit>& ps, bool removable, uint64_t proof_id); // Add a clause to the solver.
bool addEmptyClause(bool removable); // Add the empty clause, making the solver contradictory.
- bool addClause (Lit p, bool removable); // Add a unit clause to the solver.
- bool addClause (Lit p, Lit q, bool removable); // Add a binary clause to the solver.
- bool addClause (Lit p, Lit q, Lit r, bool removable); // Add a ternary clause to the solver.
- bool addClause_( vec<Lit>& ps, bool removable); // Add a clause to the solver without making superflous internal copy. Will
+ bool addClause (Lit p, bool removable, uint64_t proof_id); // Add a unit clause to the solver.
+ bool addClause (Lit p, Lit q, bool removable, uint64_t proof_id); // Add a binary clause to the solver.
+ bool addClause (Lit p, Lit q, Lit r, bool removable, uint64_t proof_id); // Add a ternary clause to the solver.
+ bool addClause_( vec<Lit>& ps, bool removable, uint64_t proof_id); // Add a clause to the solver without making superflous internal copy. Will
// change the passed vector 'ps'.
// Solving:
@@ -215,6 +219,7 @@ public:
void budgetOff();
void interrupt(); // Trigger a (potentially asynchronous) interruption of the solver.
void clearInterrupt(); // Clear interrupt indicator flag.
+ void spendResource();
// Memory managment:
//
@@ -252,7 +257,7 @@ public:
// Statistics: (read-only member variable)
//
- uint64_t solves, starts, decisions, rnd_decisions, propagations, conflicts;
+ uint64_t solves, starts, decisions, rnd_decisions, propagations, conflicts, resources_consumed;
uint64_t dec_vars, clauses_literals, learnts_literals, max_literals, tot_literals;
protected:
@@ -488,11 +493,15 @@ inline void Solver::checkGarbage(double gf){
// NOTE: enqueue does not set the ok flag! (only public methods do)
inline bool Solver::enqueue (Lit p, CRef from) { return value(p) != l_Undef ? value(p) != l_False : (uncheckedEnqueue(p, from), true); }
-inline bool Solver::addClause (const vec<Lit>& ps, bool removable) { ps.copyTo(add_tmp); return addClause_(add_tmp, removable); }
-inline bool Solver::addEmptyClause (bool removable) { add_tmp.clear(); return addClause_(add_tmp, removable); }
-inline bool Solver::addClause (Lit p, bool removable) { add_tmp.clear(); add_tmp.push(p); return addClause_(add_tmp, removable); }
-inline bool Solver::addClause (Lit p, Lit q, bool removable) { add_tmp.clear(); add_tmp.push(p); add_tmp.push(q); return addClause_(add_tmp, removable); }
-inline bool Solver::addClause (Lit p, Lit q, Lit r, bool removable) { add_tmp.clear(); add_tmp.push(p); add_tmp.push(q); add_tmp.push(r); return addClause_(add_tmp, removable); }
+inline bool Solver::addClause (const vec<Lit>& ps, bool removable, uint64_t proof_id)
+ { ps.copyTo(add_tmp); return addClause_(add_tmp, removable, proof_id); }
+inline bool Solver::addEmptyClause (bool removable) { add_tmp.clear(); return addClause_(add_tmp, removable, uint64_t(-1)); }
+inline bool Solver::addClause (Lit p, bool removable, uint64_t proof_id)
+ { add_tmp.clear(); add_tmp.push(p); return addClause_(add_tmp, removable, proof_id); }
+inline bool Solver::addClause (Lit p, Lit q, bool removable, uint64_t proof_id)
+ { add_tmp.clear(); add_tmp.push(p); add_tmp.push(q); return addClause_(add_tmp, removable, proof_id); }
+inline bool Solver::addClause (Lit p, Lit q, Lit r, bool removable, uint64_t proof_id)
+ { add_tmp.clear(); add_tmp.push(p); add_tmp.push(q); add_tmp.push(r); return addClause_(add_tmp, removable, proof_id); }
inline bool Solver::locked (const Clause& c) const { return value(c[0]) == l_True && isPropagatedBy(var(c[0]), c); }
inline void Solver::newDecisionLevel() { trail_lim.push(trail.size()); flipped.push(false); context->push(); if(Dump.isOn("state")) { Dump("state") << CVC4::PushCommand(); } }
@@ -526,8 +535,9 @@ inline void Solver::clearInterrupt(){ asynch_interrupt = false; }
inline void Solver::budgetOff(){ conflict_budget = propagation_budget = -1; }
inline bool Solver::withinBudget() const {
return !asynch_interrupt &&
- (conflict_budget < 0 || conflicts < (uint64_t)conflict_budget) &&
+ (conflict_budget < 0 || conflicts + resources_consumed < (uint64_t)conflict_budget) &&
(propagation_budget < 0 || propagations < (uint64_t)propagation_budget); }
+inline void Solver::spendResource() { ++resources_consumed; }
// FIXME: after the introduction of asynchronous interrruptions the solve-versions that return a
// pure bool do not give a safe interface. Either interrupts must be possible to turn off here, or
diff --git a/src/prop/minisat/minisat.cpp b/src/prop/minisat/minisat.cpp
index e4956ecc8..b50c1c09f 100644
--- a/src/prop/minisat/minisat.cpp
+++ b/src/prop/minisat/minisat.cpp
@@ -149,10 +149,10 @@ void MinisatSatSolver::setupOptions() {
d_minisat->restart_inc = options::satRestartInc();
}
-void MinisatSatSolver::addClause(SatClause& clause, bool removable) {
+void MinisatSatSolver::addClause(SatClause& clause, bool removable, uint64_t proof_id) {
Minisat::vec<Minisat::Lit> minisat_clause;
toMinisatClause(clause, minisat_clause);
- d_minisat->addClause(minisat_clause, removable);
+ d_minisat->addClause(minisat_clause, removable, proof_id);
}
SatVariable MinisatSatSolver::newVar(bool isTheoryAtom, bool preRegister, bool canErase) {
@@ -168,10 +168,10 @@ SatValue MinisatSatSolver::solve(unsigned long& resource) {
d_minisat->setConfBudget(resource);
}
Minisat::vec<Minisat::Lit> empty;
- unsigned long conflictsBefore = d_minisat->conflicts;
+ unsigned long conflictsBefore = d_minisat->conflicts + d_minisat->resources_consumed;
SatValue result = toSatLiteralValue(d_minisat->solveLimited(empty));
d_minisat->clearInterrupt();
- resource = d_minisat->conflicts - conflictsBefore;
+ resource = d_minisat->conflicts + d_minisat->resources_consumed - conflictsBefore;
Trace("limit") << "SatSolver::solve(): it took " << resource << " conflicts" << std::endl;
return result;
}
@@ -182,6 +182,9 @@ SatValue MinisatSatSolver::solve() {
return toSatLiteralValue(d_minisat->solve());
}
+void MinisatSatSolver::spendResource() {
+ d_minisat->spendResource();
+}
void MinisatSatSolver::interrupt() {
d_minisat->interrupt();
@@ -225,7 +228,7 @@ void MinisatSatSolver::push() {
d_minisat->push();
}
-void MinisatSatSolver::pop(){
+void MinisatSatSolver::pop() {
d_minisat->pop();
}
diff --git a/src/prop/minisat/minisat.h b/src/prop/minisat/minisat.h
index a919bbcc4..3992f1adb 100644
--- a/src/prop/minisat/minisat.h
+++ b/src/prop/minisat/minisat.h
@@ -53,7 +53,7 @@ public:
static void toSatClause (const Minisat::Clause& clause, SatClause& sat_clause);
void initialize(context::Context* context, TheoryProxy* theoryProxy);
- void addClause(SatClause& clause, bool removable);
+ void addClause(SatClause& clause, bool removable, uint64_t proof_id);
SatVariable newVar(bool isTheoryAtom, bool preRegister, bool canErase);
SatVariable trueVar() { return d_minisat->trueVar(); }
@@ -62,6 +62,7 @@ public:
SatValue solve();
SatValue solve(long unsigned int&);
+ void spendResource();
void interrupt();
SatValue value(SatLiteral l);
diff --git a/src/prop/minisat/simp/SimpSolver.cc b/src/prop/minisat/simp/SimpSolver.cc
index 6dcdb76c7..71e747f72 100644
--- a/src/prop/minisat/simp/SimpSolver.cc
+++ b/src/prop/minisat/simp/SimpSolver.cc
@@ -159,7 +159,7 @@ lbool SimpSolver::solve_(bool do_simp, bool turn_off_simp)
-bool SimpSolver::addClause_(vec<Lit>& ps, bool removable)
+bool SimpSolver::addClause_(vec<Lit>& ps, bool removable, uint64_t proof_id)
{
#ifndef NDEBUG
if (use_simplification) {
@@ -173,7 +173,7 @@ bool SimpSolver::addClause_(vec<Lit>& ps, bool removable)
if (use_rcheck && implied(ps))
return true;
- if (!Solver::addClause_(ps, removable))
+ if (!Solver::addClause_(ps, removable, proof_id))
return false;
if (use_simplification && clauses_persistent.size() == nclauses + 1){
@@ -545,7 +545,7 @@ bool SimpSolver::eliminateVar(Var v)
for (int i = 0; i < pos.size(); i++)
for (int j = 0; j < neg.size(); j++) {
bool removable = ca[pos[i]].removable() && ca[pos[neg[j]]].removable();
- if (merge(ca[pos[i]], ca[neg[j]], v, resolvent) && !addClause_(resolvent, removable)) {
+ if (merge(ca[pos[i]], ca[neg[j]], v, resolvent) && !addClause_(resolvent, removable, uint64_t(-1))) {
return false;
}
}
@@ -585,7 +585,7 @@ bool SimpSolver::substitute(Var v, Lit x)
removeClause(cls[i]);
- if (!addClause_(subst_clause, c.removable())) {
+ if (!addClause_(subst_clause, c.removable(), uint64_t(-1))) {
return ok = false;
}
}
diff --git a/src/prop/minisat/simp/SimpSolver.h b/src/prop/minisat/simp/SimpSolver.h
index 878d799a5..041309546 100644
--- a/src/prop/minisat/simp/SimpSolver.h
+++ b/src/prop/minisat/simp/SimpSolver.h
@@ -47,12 +47,12 @@ class SimpSolver : public Solver {
// Problem specification:
//
Var newVar (bool polarity = true, bool dvar = true, bool isTheoryAtom = false, bool preRegister = false, bool canErase = true);
- bool addClause (const vec<Lit>& ps, bool removable);
- bool addEmptyClause(bool removable); // Add the empty clause to the solver.
- bool addClause (Lit p, bool removable); // Add a unit clause to the solver.
- bool addClause (Lit p, Lit q, bool removable); // Add a binary clause to the solver.
- bool addClause (Lit p, Lit q, Lit r, bool removable); // Add a ternary clause to the solver.
- bool addClause_(vec<Lit>& ps, bool removable);
+ bool addClause (const vec<Lit>& ps, bool removable, uint64_t proof_id);
+ bool addEmptyClause(bool removable, uint64_t proof_id); // Add the empty clause to the solver.
+ bool addClause (Lit p, bool removable, uint64_t proof_id); // Add a unit clause to the solver.
+ bool addClause (Lit p, Lit q, bool removable, uint64_t proof_id); // Add a binary clause to the solver.
+ bool addClause (Lit p, Lit q, Lit r, bool removable, uint64_t proof_id); // Add a ternary clause to the solver.
+ bool addClause_(vec<Lit>& ps, bool removable, uint64_t proof_id);
bool substitute(Var v, Lit x); // Replace all occurences of v with x (may cause a contradiction).
// Variable mode:
@@ -182,11 +182,15 @@ inline void SimpSolver::updateElimHeap(Var v) {
elim_heap.update(v); }
-inline bool SimpSolver::addClause (const vec<Lit>& ps, bool removable) { ps.copyTo(add_tmp); return addClause_(add_tmp, removable); }
-inline bool SimpSolver::addEmptyClause(bool removable) { add_tmp.clear(); return addClause_(add_tmp, removable); }
-inline bool SimpSolver::addClause (Lit p, bool removable) { add_tmp.clear(); add_tmp.push(p); return addClause_(add_tmp, removable); }
-inline bool SimpSolver::addClause (Lit p, Lit q, bool removable) { add_tmp.clear(); add_tmp.push(p); add_tmp.push(q); return addClause_(add_tmp, removable); }
-inline bool SimpSolver::addClause (Lit p, Lit q, Lit r, bool removable) { add_tmp.clear(); add_tmp.push(p); add_tmp.push(q); add_tmp.push(r); return addClause_(add_tmp, removable); }
+inline bool SimpSolver::addClause (const vec<Lit>& ps, bool removable, uint64_t proof_id)
+ { ps.copyTo(add_tmp); return addClause_(add_tmp, removable, proof_id); }
+inline bool SimpSolver::addEmptyClause(bool removable, uint64_t proof_id) { add_tmp.clear(); return addClause_(add_tmp, removable, proof_id); }
+inline bool SimpSolver::addClause (Lit p, bool removable, uint64_t proof_id)
+ { add_tmp.clear(); add_tmp.push(p); return addClause_(add_tmp, removable, proof_id); }
+inline bool SimpSolver::addClause (Lit p, Lit q, bool removable, uint64_t proof_id)
+ { add_tmp.clear(); add_tmp.push(p); add_tmp.push(q); return addClause_(add_tmp, removable, proof_id); }
+inline bool SimpSolver::addClause (Lit p, Lit q, Lit r, bool removable, uint64_t proof_id)
+ { add_tmp.clear(); add_tmp.push(p); add_tmp.push(q); add_tmp.push(r); return addClause_(add_tmp, removable, proof_id); }
inline void SimpSolver::setFrozen (Var v, bool b) { frozen[v] = (char)b; if (use_simplification && !b) { updateElimHeap(v); } }
inline bool SimpSolver::solve ( bool do_simp, bool turn_off_simp) { budgetOff(); assumptions.clear(); return solve_(do_simp, turn_off_simp) == l_True; }
diff --git a/src/prop/prop_engine.cpp b/src/prop/prop_engine.cpp
index 82c0bae1a..1572dfa88 100644
--- a/src/prop/prop_engine.cpp
+++ b/src/prop/prop_engine.cpp
@@ -25,6 +25,7 @@
#include "decision/options.h"
#include "theory/theory_engine.h"
#include "theory/theory_registrar.h"
+#include "proof/proof_manager.h"
#include "util/cvc4_assert.h"
#include "options/options.h"
#include "smt/options.h"
@@ -109,15 +110,15 @@ void PropEngine::assertFormula(TNode node) {
Assert(!d_inCheckSat, "Sat solver in solve()!");
Debug("prop") << "assertFormula(" << node << ")" << endl;
// Assert as non-removable
- d_cnfStream->convertAndAssert(node, false, false);
+ d_cnfStream->convertAndAssert(node, false, false, RULE_GIVEN);
}
-void PropEngine::assertLemma(TNode node, bool negated, bool removable) {
+void PropEngine::assertLemma(TNode node, bool negated, bool removable, ProofRule rule, TNode from) {
//Assert(d_inCheckSat, "Sat solver should be in solve()!");
Debug("prop::lemmas") << "assertLemma(" << node << ")" << endl;
- // Assert as removable
- d_cnfStream->convertAndAssert(node, removable, negated);
+ // Assert as (possibly) removable
+ d_cnfStream->convertAndAssert(node, removable, negated, rule, from);
}
void PropEngine::requirePhase(TNode n, bool phase) {
@@ -283,7 +284,7 @@ void PropEngine::interrupt() throw(ModalException) {
}
void PropEngine::spendResource() throw() {
- // TODO implement me
+ d_satSolver->spendResource();
checkTime();
}
diff --git a/src/prop/prop_engine.h b/src/prop/prop_engine.h
index a5132e3da..ed022a64f 100644
--- a/src/prop/prop_engine.h
+++ b/src/prop/prop_engine.h
@@ -25,6 +25,7 @@
#include "options/options.h"
#include "util/result.h"
#include "smt/modal_exception.h"
+#include "proof/proof_manager.h"
#include <sys/time.h>
namespace CVC4 {
@@ -199,7 +200,7 @@ public:
* @param removable whether this lemma can be quietly removed based
* on an activity heuristic (or not)
*/
- void assertLemma(TNode node, bool negated, bool removable);
+ void assertLemma(TNode node, bool negated, bool removable, ProofRule rule, TNode from = TNode::null());
/**
* If ever n is decided upon, it must be in the given phase. This
diff --git a/src/prop/sat_solver.h b/src/prop/sat_solver.h
index 929b867c9..e3b0f3449 100644
--- a/src/prop/sat_solver.h
+++ b/src/prop/sat_solver.h
@@ -24,6 +24,7 @@
#include "util/statistics_registry.h"
#include "context/cdlist.h"
#include "prop/sat_solver_types.h"
+#include "expr/node.h"
namespace CVC4 {
namespace prop {
@@ -38,7 +39,7 @@ public:
virtual ~SatSolver() { }
/** Assert a clause in the solver. */
- virtual void addClause(SatClause& clause, bool removable) = 0;
+ virtual void addClause(SatClause& clause, bool removable, uint64_t proof_id) = 0;
/**
* Create a new boolean variable in the solver.
@@ -61,6 +62,9 @@ public:
/** Check the satisfiability of the added clauses */
virtual SatValue solve(long unsigned int&) = 0;
+ /** Instruct the solver that it should bump its consumed resource count. */
+ virtual void spendResource() = 0;
+
/** Interrupt the solver */
virtual void interrupt() = 0;
diff --git a/src/prop/theory_proxy.cpp b/src/prop/theory_proxy.cpp
index 67325cb18..2bcd48099 100644
--- a/src/prop/theory_proxy.cpp
+++ b/src/prop/theory_proxy.cpp
@@ -122,7 +122,7 @@ void TheoryProxy::notifyRestart() {
if(lemmaCount % 1 == 0) {
Debug("shared") << "=) " << asNode << std::endl;
}
- d_propEngine->assertLemma(d_theoryEngine->preprocess(asNode), false, true);
+ d_propEngine->assertLemma(d_theoryEngine->preprocess(asNode), false, true, RULE_INVALID);
} else {
Debug("shared") << "=(" << asNode << std::endl;
}
diff --git a/src/smt/options b/src/smt/options
index 9c7eea12f..3ee3dbecb 100644
--- a/src/smt/options
+++ b/src/smt/options
@@ -37,9 +37,11 @@ option dumpProofs --dump-proofs bool :default false :link --proof
output proofs after every UNSAT/VALID response
option dumpInstantiations --dump-instantiations bool :default false
output instantiations of quantified formulas after every UNSAT/VALID response
-# this is just a placeholder for later; it doesn't show up in command-line options listings
-undocumented-option unsatCores produce-unsat-cores --produce-unsat-cores bool :predicate CVC4::smt::unsatCoresEnabledBuild CVC4::smt::beforeSearch :predicate-include "smt/options_handlers.h"
- turn on unsat core generation (NOT YET SUPPORTED)
+option unsatCores produce-unsat-cores --produce-unsat-cores bool :predicate CVC4::smt::proofEnabledBuild CVC4::smt::beforeSearch :predicate-include "smt/options_handlers.h"
+ turn on unsat core generation
+option dumpUnsatCores --dump-unsat-cores bool :default false :link --produce-unsat-cores :link-smt produce-unsat-cores :predicate CVC4::smt::beforeSearch :predicate-include "smt/options_handlers.h"
+ output unsat cores after every UNSAT/VALID response
+
option produceAssignments produce-assignments --produce-assignments bool :default false :predicate CVC4::smt::beforeSearch :predicate-include "smt/options_handlers.h"
support the get-assignment command
diff --git a/src/smt/options_handlers.h b/src/smt/options_handlers.h
index 61e17801d..fcd625267 100644
--- a/src/smt/options_handlers.h
+++ b/src/smt/options_handlers.h
@@ -153,10 +153,6 @@ batch (default) \n\
(MiniSat) propagation for all of them only after reaching a querying command\n\
(CHECKSAT or QUERY or predicate SUBTYPE declaration)\n\
\n\
-incremental\n\
-+ run nonclausal simplification and clausal propagation at each ASSERT\n\
- (and at CHECKSAT/QUERY/SUBTYPE)\n\
-\n\
none\n\
+ do not perform nonclausal simplification\n\
";
@@ -283,8 +279,6 @@ inline LogicInfo stringToLogicInfo(std::string option, std::string optarg, SmtEn
inline SimplificationMode stringToSimplificationMode(std::string option, std::string optarg, SmtEngine* smt) throw(OptionException) {
if(optarg == "batch") {
return SIMPLIFICATION_MODE_BATCH;
- } else if(optarg == "incremental") {
- return SIMPLIFICATION_MODE_INCREMENTAL;
} else if(optarg == "none") {
return SIMPLIFICATION_MODE_NONE;
} else if(optarg == "help") {
@@ -316,12 +310,6 @@ inline void proofEnabledBuild(std::string option, bool value, SmtEngine* smt) th
#endif /* CVC4_PROOF */
}
-inline void unsatCoresEnabledBuild(std::string option, bool value, SmtEngine* smt) throw(OptionException) {
- if(value) {
- throw UnrecognizedOptionException("CVC4 does not yet have support for unsatisfiable cores");
- }
-}
-
// This macro is used for setting :regular-output-channel and :diagnostic-output-channel
// to redirect a stream. It maintains all attributes set on the stream.
#define __CVC4__SMT__OUTPUTCHANNELS__SETSTREAM__(__channel_get, __channel_set) \
diff --git a/src/smt/simplification_mode.cpp b/src/smt/simplification_mode.cpp
index f728fa862..be46badfc 100644
--- a/src/smt/simplification_mode.cpp
+++ b/src/smt/simplification_mode.cpp
@@ -21,9 +21,6 @@ namespace CVC4 {
std::ostream& operator<<(std::ostream& out, SimplificationMode mode) {
switch(mode) {
- case SIMPLIFICATION_MODE_INCREMENTAL:
- out << "SIMPLIFICATION_MODE_INCREMENTAL";
- break;
case SIMPLIFICATION_MODE_BATCH:
out << "SIMPLIFICATION_MODE_BATCH";
break;
diff --git a/src/smt/simplification_mode.h b/src/smt/simplification_mode.h
index 2242e8bdf..b0b78d318 100644
--- a/src/smt/simplification_mode.h
+++ b/src/smt/simplification_mode.h
@@ -26,8 +26,6 @@ namespace CVC4 {
/** Enumeration of simplification modes (when to simplify). */
typedef enum {
- /** Simplify the assertions as they come in */
- SIMPLIFICATION_MODE_INCREMENTAL,
/** Simplify the assertions all together once a check is requested */
SIMPLIFICATION_MODE_BATCH,
/** Don't do simplification */
diff --git a/src/smt/smt_engine.cpp b/src/smt/smt_engine.cpp
index 2a12b07de..015e6a4f4 100644
--- a/src/smt/smt_engine.cpp
+++ b/src/smt/smt_engine.cpp
@@ -48,6 +48,7 @@
#include "theory/bv/theory_bv_rewriter.h"
#include "proof/proof_manager.h"
#include "main/options.h"
+#include "util/unsat_core.h"
#include "util/proof.h"
#include "proof/proof.h"
#include "proof/proof_manager.h"
@@ -137,6 +138,30 @@ public:
Node getFormula() const { return d_formula; }
};/* class DefinedFunction */
+class AssertionPipeline {
+ vector<Node> d_nodes;
+
+public:
+
+ size_t size() const { return d_nodes.size(); }
+
+ void resize(size_t n) { d_nodes.resize(n); }
+ void clear() { d_nodes.clear(); }
+
+ Node& operator[](size_t i) { return d_nodes[i]; }
+ const Node& operator[](size_t i) const { return d_nodes[i]; }
+ void push_back(Node n) { d_nodes.push_back(n); }
+
+ vector<Node>& ref() { return d_nodes; }
+ const vector<Node>& ref() const { return d_nodes; }
+
+ void replace(size_t i, Node n) {
+ PROOF( ProofManager::currentPM()->addDependence(n, d_nodes[i]); );
+ d_nodes[i] = n;
+ }
+
+};/* class AssertionPipeline */
+
struct SmtEngineStatistics {
/** time spent in definition-expansion */
TimerStat d_definitionExpansionTime;
@@ -160,6 +185,8 @@ struct SmtEngineStatistics {
TimerStat d_iteRemovalTime;
/** time spent in theory preprocessing */
TimerStat d_theoryPreprocessTime;
+ /** time spent in theory preprocessing */
+ TimerStat d_rewriteApplyToConstTime;
/** time spent converting to CNF */
TimerStat d_cnfConversionTime;
/** Num of assertions before ite removal */
@@ -192,6 +219,7 @@ struct SmtEngineStatistics {
d_unconstrainedSimpTime("smt::SmtEngine::unconstrainedSimpTime"),
d_iteRemovalTime("smt::SmtEngine::iteRemovalTime"),
d_theoryPreprocessTime("smt::SmtEngine::theoryPreprocessTime"),
+ d_rewriteApplyToConstTime("smt::SmtEngine::rewriteApplyToConstTime"),
d_cnfConversionTime("smt::SmtEngine::cnfConversionTime"),
d_numAssertionsPre("smt::SmtEngine::numAssertionsPreITERemoval", 0),
d_numAssertionsPost("smt::SmtEngine::numAssertionsPostITERemoval", 0),
@@ -214,10 +242,12 @@ struct SmtEngineStatistics {
StatisticsRegistry::registerStat(&d_unconstrainedSimpTime);
StatisticsRegistry::registerStat(&d_iteRemovalTime);
StatisticsRegistry::registerStat(&d_theoryPreprocessTime);
+ StatisticsRegistry::registerStat(&d_rewriteApplyToConstTime);
StatisticsRegistry::registerStat(&d_cnfConversionTime);
StatisticsRegistry::registerStat(&d_numAssertionsPre);
StatisticsRegistry::registerStat(&d_numAssertionsPost);
StatisticsRegistry::registerStat(&d_checkModelTime);
+ StatisticsRegistry::registerStat(&d_checkProofTime);
StatisticsRegistry::registerStat(&d_solveTime);
StatisticsRegistry::registerStat(&d_pushPopTime);
StatisticsRegistry::registerStat(&d_processAssertionsTime);
@@ -236,10 +266,12 @@ struct SmtEngineStatistics {
StatisticsRegistry::unregisterStat(&d_unconstrainedSimpTime);
StatisticsRegistry::unregisterStat(&d_iteRemovalTime);
StatisticsRegistry::unregisterStat(&d_theoryPreprocessTime);
+ StatisticsRegistry::unregisterStat(&d_rewriteApplyToConstTime);
StatisticsRegistry::unregisterStat(&d_cnfConversionTime);
StatisticsRegistry::unregisterStat(&d_numAssertionsPre);
StatisticsRegistry::unregisterStat(&d_numAssertionsPost);
StatisticsRegistry::unregisterStat(&d_checkModelTime);
+ StatisticsRegistry::unregisterStat(&d_checkProofTime);
StatisticsRegistry::unregisterStat(&d_solveTime);
StatisticsRegistry::unregisterStat(&d_pushPopTime);
StatisticsRegistry::unregisterStat(&d_processAssertionsTime);
@@ -264,9 +296,6 @@ struct SmtEngineStatistics {
class SmtEnginePrivate : public NodeManagerListener {
SmtEngine& d_smt;
- /** The assertions yet to be preprocessed */
- vector<Node> d_assertionsToPreprocess;
-
/** Learned literals */
vector<Node> d_nonClausalLearnedLiterals;
@@ -281,8 +310,8 @@ class SmtEnginePrivate : public NodeManagerListener {
bool d_propagatorNeedsFinish;
std::vector<Node> d_boolVars;
- /** Assertions to push to sat */
- vector<Node> d_assertionsToCheck;
+ /** Assertions in the preprocessing pipeline */
+ AssertionPipeline d_assertions;
/** Whether any assertions have been processed */
CDO<bool> d_assertionsProcessed;
@@ -319,7 +348,7 @@ class SmtEnginePrivate : public NodeManagerListener {
public:
/**
- * Map from skolem variables to index in d_assertionsToCheck containing
+ * Map from skolem variables to index in d_assertions containing
* corresponding introduced Boolean ite
*/
IteSkolemMap d_iteSkolemMap;
@@ -375,7 +404,7 @@ private:
bool simpITE();
// Simplify based on unconstrained values
- void unconstrainedSimp(std::vector<Node>& assertions);
+ void unconstrainedSimp();
// Ensures the assertions asserted after before now
// effectively come before d_realAssertionsEnd
@@ -386,7 +415,7 @@ private:
* (predicate subtype or integer subrange type) must be constrained
* to be in that type.
*/
- void constrainSubtypes(TNode n, std::vector<Node>& assertions)
+ void constrainSubtypes(TNode n, AssertionPipeline& assertions)
throw();
// trace nodes back to their assertions using CircuitPropagator's BackEdgesMap
@@ -410,13 +439,12 @@ public:
SmtEnginePrivate(SmtEngine& smt) :
d_smt(smt),
- d_assertionsToPreprocess(),
d_nonClausalLearnedLiterals(),
d_realAssertionsEnd(0),
d_booleanTermConverter(NULL),
d_propagator(d_nonClausalLearnedLiterals, true, true),
d_propagatorNeedsFinish(false),
- d_assertionsToCheck(),
+ d_assertions(),
d_assertionsProcessed(smt.d_userContext, false),
d_substitutionsIndex(smt.d_userContext, 0),
d_fakeContext(),
@@ -508,9 +536,8 @@ public:
* someone does a push-assert-pop without a check-sat.
*/
void notifyPop() {
- d_assertionsToPreprocess.clear();
+ d_assertions.clear();
d_nonClausalLearnedLiterals.clear();
- d_assertionsToCheck.clear();
d_realAssertionsEnd = 0;
d_iteSkolemMap.clear();
}
@@ -546,7 +573,7 @@ public:
hash_map<Node, Node, NodeHashFunction> cache;
Node n = expandDefinitions(in, cache).toExpr();
// Make sure we've done all preprocessing, etc.
- Assert(d_assertionsToCheck.size() == 0 && d_assertionsToPreprocess.size() == 0);
+ Assert(d_assertions.size() == 0);
return applySubstitutions(n).toExpr();
}
@@ -665,8 +692,6 @@ SmtEngine::SmtEngine(ExprManager* em) throw() :
d_statisticsRegistry = new StatisticsRegistry();
d_stats = new SmtEngineStatistics();
- PROOF( d_proofManager = new ProofManager(); );
-
// We have mutual dependency here, so we add the prop engine to the theory
// engine later (it is non-essential there)
d_theoryEngine = new TheoryEngine(d_context, d_userContext, d_private->d_iteRemover, const_cast<const LogicInfo&>(d_logic));
@@ -689,6 +714,9 @@ void SmtEngine::finishInit() {
// ensure that our heuristics are properly set up
setDefaults();
+ Assert(d_proofManager == NULL);
+ PROOF( d_proofManager = new ProofManager(); );
+
d_decisionEngine = new DecisionEngine(d_context, d_userContext);
d_decisionEngine->init(); // enable appropriate strategies
@@ -919,6 +947,64 @@ void SmtEngine::setDefaults() {
}
}
+ if(options::unsatCores()) {
+ if(options::simplificationMode() != SIMPLIFICATION_MODE_NONE) {
+ if(options::simplificationMode.wasSetByUser()) {
+ throw OptionException("simplification not supported with unsat cores");
+ }
+ Notice() << "SmtEngine: turning off simplification to support unsat-cores" << endl;
+ options::simplificationMode.set(SIMPLIFICATION_MODE_NONE);
+ }
+
+ if(options::unconstrainedSimp()) {
+ if(options::unconstrainedSimp.wasSetByUser()) {
+ throw OptionException("unconstrained simplification not supported with unsat cores");
+ }
+ Notice() << "SmtEngine: turning off unconstrained simplification to support unsat-cores" << endl;
+ options::unconstrainedSimp.set(false);
+ }
+
+ if(options::pbRewrites()) {
+ if(options::pbRewrites.wasSetByUser()) {
+ throw OptionException("pseudoboolean rewrites not supported with unsat cores");
+ }
+ Notice() << "SmtEngine: turning off pseudoboolean rewrites to support unsat-cores" << endl;
+ setOption("pb-rewrites", false);
+ }
+
+ if(options::sortInference()) {
+ if(options::sortInference.wasSetByUser()) {
+ throw OptionException("sort inference not supported with unsat cores");
+ }
+ Notice() << "SmtEngine: turning off sort inference to support unsat-cores" << endl;
+ options::sortInference.set(false);
+ }
+
+ if(options::preSkolemQuant()) {
+ if(options::preSkolemQuant.wasSetByUser()) {
+ throw OptionException("pre-skolemization not supported with unsat cores");
+ }
+ Notice() << "SmtEngine: turning off pre-skolemization to support unsat-cores" << endl;
+ options::preSkolemQuant.set(false);
+ }
+
+ if(options::bitvectorToBool()) {
+ if(options::bitvectorToBool.wasSetByUser()) {
+ throw OptionException("bv-to-bool not supported with unsat cores");
+ }
+ Notice() << "SmtEngine: turning off bitvector-to-bool support unsat-cores" << endl;
+ options::bitvectorToBool.set(false);
+ }
+
+ if(options::bvIntroducePow2()) {
+ if(options::bvIntroducePow2.wasSetByUser()) {
+ throw OptionException("bv-intro-pow2 not supported with unsat cores");
+ }
+ Notice() << "SmtEngine: turning off bv-introduce-pow2 to support unsat-cores" << endl;
+ setOption("bv-intro-pow2", false);
+ }
+ }
+
if(options::produceAssignments() && !options::produceModels()) {
Notice() << "SmtEngine: turning on produce-models to support produce-assignments" << endl;
setOption("produce-models", SExpr("true"));
@@ -1111,10 +1197,8 @@ void SmtEngine::setDefaults() {
if (options::arithRewriteEq()) {
d_earlyTheoryPP = false;
}
- // Turn on justification heuristic of the decision engine for QF_BV and QF_AUFBV
- // and also use it in stop-only mode for QF_AUFLIA, QF_LRA and Quantifiers
- // BUT use neither in ALL_SUPPORTED mode (since it doesn't yet work well
- // with incrementality)
+
+ // Set decision mode based on logic (if not set by user)
if(!options::decisionMode.wasSetByUser()) {
decision::DecisionMode decMode =
// ALL_SUPPORTED
@@ -1207,6 +1291,37 @@ void SmtEngine::setDefaults() {
if( options::qcfMode.wasSetByUser() || options::qcfTConstraint() ){
options::quantConflictFind.set( true );
}
+ //for induction techniques
+ if( options::quantInduction() ){
+ if( !options::dtStcInduction.wasSetByUser() ){
+ options::dtStcInduction.set( true );
+ }
+ if( !options::intWfInduction.wasSetByUser() ){
+ options::intWfInduction.set( true );
+ }
+ }
+ if( options::dtStcInduction() ){
+ //leads to unfairness FIXME
+ if( !options::dtForceAssignment.wasSetByUser() ){
+ options::dtForceAssignment.set( true );
+ }
+ }
+ if( options::intWfInduction() ){
+ if( !options::purifyTriggers.wasSetByUser() ){
+ options::purifyTriggers.set( true );
+ }
+ }
+ if( options::conjectureNoFilter() ){
+ if( !options::conjectureFilterActiveTerms.wasSetByUser() ){
+ options::conjectureFilterActiveTerms.set( false );
+ }
+ if( !options::conjectureFilterCanonical.wasSetByUser() ){
+ options::conjectureFilterCanonical.set( false );
+ }
+ if( !options::conjectureFilterModel.wasSetByUser() ){
+ options::conjectureFilterModel.set( false );
+ }
+ }
//until bugs 371,431 are fixed
if( ! options::minisatUseElim.wasSetByUser()){
@@ -1252,17 +1367,10 @@ void SmtEngine::setDefaults() {
}
}
- if (options::incrementalSolving() && options::proof()) {
- Warning() << "SmtEngine: turning off incremental solving mode (not yet supported with --proof" << endl;
+ if(options::incrementalSolving() && (options::proof() || options::unsatCores())) {
+ Warning() << "SmtEngine: turning off incremental solving mode (not yet supported with --proof or --produce-unsat-cores, try --tear-down-incremental instead)" << endl;
setOption("incremental", SExpr("false"));
}
-
- // datatypes theory should assign values to all datatypes terms if logic is quantified
- if (d_logic.isQuantified() && d_logic.isTheoryEnabled(THEORY_DATATYPES)) {
- if( !options::dtForceAssignment.wasSetByUser() ){
- options::dtForceAssignment.set(true);
- }
- }
}
void SmtEngine::setInfo(const std::string& key, const CVC4::SExpr& value)
@@ -1628,11 +1736,10 @@ void SmtEnginePrivate::removeITEs() {
Trace("simplify") << "SmtEnginePrivate::removeITEs()" << endl;
// Remove all of the ITE occurrences and normalize
- d_iteRemover.run(d_assertionsToCheck, d_iteSkolemMap);
- for (unsigned i = 0; i < d_assertionsToCheck.size(); ++ i) {
- d_assertionsToCheck[i] = Rewriter::rewrite(d_assertionsToCheck[i]);
+ d_iteRemover.run(d_assertions.ref(), d_iteSkolemMap, true);
+ for (unsigned i = 0; i < d_assertions.size(); ++ i) {
+ d_assertions.replace(i, Rewriter::rewrite(d_assertions[i]));
}
-
}
void SmtEnginePrivate::staticLearning() {
@@ -1642,22 +1749,21 @@ void SmtEnginePrivate::staticLearning() {
Trace("simplify") << "SmtEnginePrivate::staticLearning()" << endl;
- for (unsigned i = 0; i < d_assertionsToCheck.size(); ++ i) {
+ for (unsigned i = 0; i < d_assertions.size(); ++ i) {
NodeBuilder<> learned(kind::AND);
- learned << d_assertionsToCheck[i];
- d_smt.d_theoryEngine->ppStaticLearn(d_assertionsToCheck[i], learned);
+ learned << d_assertions[i];
+ d_smt.d_theoryEngine->ppStaticLearn(d_assertions[i], learned);
if(learned.getNumChildren() == 1) {
learned.clear();
} else {
- d_assertionsToCheck[i] = learned;
+ d_assertions.replace(i, learned);
}
}
}
// do dumping (before/after any preprocessing pass)
-static void dumpAssertions(const char* key,
- const std::vector<Node>& assertionList) {
+static void dumpAssertions(const char* key, const AssertionPipeline& assertionList) {
if( Dump.isOn("assertions") &&
Dump.isOn(string("assertions:") + key) ) {
// Push the simplified assertions to the dump output stream
@@ -1672,8 +1778,11 @@ static void dumpAssertions(const char* key,
bool SmtEnginePrivate::nonClausalSimplify() {
d_smt.finalOptionsAreSet();
- TimerStat::CodeTimer nonclausalTimer(d_smt.d_stats->d_nonclausalSimplificationTime);
+ if(options::unsatCores()) {
+ return true;
+ }
+ TimerStat::CodeTimer nonclausalTimer(d_smt.d_stats->d_nonclausalSimplificationTime);
Trace("simplify") << "SmtEnginePrivate::nonClausalSimplify()" << endl;
@@ -1686,14 +1795,15 @@ bool SmtEnginePrivate::nonClausalSimplify() {
// Assert all the assertions to the propagator
Trace("simplify") << "SmtEnginePrivate::nonClausalSimplify(): "
<< "asserting to propagator" << endl;
- for (unsigned i = 0; i < d_assertionsToPreprocess.size(); ++ i) {
- Assert(Rewriter::rewrite(d_assertionsToPreprocess[i]) == d_assertionsToPreprocess[i]);
+ for (unsigned i = 0; i < d_assertions.size(); ++ i) {
+ Assert(Rewriter::rewrite(d_assertions[i]) == d_assertions[i]);
// Don't reprocess substitutions
if (d_substitutionsIndex > 0 && i == d_substitutionsIndex) {
continue;
}
- Trace("simplify") << "SmtEnginePrivate::nonClausalSimplify(): asserting " << d_assertionsToPreprocess[i] << endl;
- d_propagator.assertTrue(d_assertionsToPreprocess[i]);
+ Trace("simplify") << "SmtEnginePrivate::nonClausalSimplify(): asserting " << d_assertions[i] << endl;
+ Debug("cores") << "d_propagator assertTrue: " << d_assertions[i] << std::endl;
+ d_propagator.assertTrue(d_assertions[i]);
}
Trace("simplify") << "SmtEnginePrivate::nonClausalSimplify(): "
@@ -1702,8 +1812,10 @@ bool SmtEnginePrivate::nonClausalSimplify() {
// If in conflict, just return false
Trace("simplify") << "SmtEnginePrivate::nonClausalSimplify(): "
<< "conflict in non-clausal propagation" << endl;
- d_assertionsToPreprocess.clear();
- d_assertionsToCheck.push_back(NodeManager::currentNM()->mkConst<bool>(false));
+ Node falseNode = NodeManager::currentNM()->mkConst<bool>(false);
+ Assert(!options::unsatCores());
+ d_assertions.clear();
+ d_assertions.push_back(falseNode);
d_propagatorNeedsFinish = true;
return false;
}
@@ -1740,8 +1852,9 @@ bool SmtEnginePrivate::nonClausalSimplify() {
Trace("simplify") << "SmtEnginePrivate::nonClausalSimplify(): "
<< "conflict with "
<< d_nonClausalLearnedLiterals[i] << endl;
- d_assertionsToPreprocess.clear();
- d_assertionsToCheck.push_back(NodeManager::currentNM()->mkConst<bool>(false));
+ Assert(!options::unsatCores());
+ d_assertions.clear();
+ d_assertions.push_back(NodeManager::currentNM()->mkConst<bool>(false));
d_propagatorNeedsFinish = true;
return false;
}
@@ -1775,8 +1888,9 @@ bool SmtEnginePrivate::nonClausalSimplify() {
Trace("simplify") << "SmtEnginePrivate::nonClausalSimplify(): "
<< "conflict while solving "
<< learnedLiteral << endl;
- d_assertionsToPreprocess.clear();
- d_assertionsToCheck.push_back(NodeManager::currentNM()->mkConst<bool>(false));
+ Assert(!options::unsatCores());
+ d_assertions.clear();
+ d_assertions.push_back(NodeManager::currentNM()->mkConst<bool>(false));
d_propagatorNeedsFinish = true;
return false;
default:
@@ -1801,8 +1915,8 @@ bool SmtEnginePrivate::nonClausalSimplify() {
// constantPropagations.simplifyLHS(t, c, equations, true);
// if (!equations.empty()) {
// Assert(equations[0].first.isConst() && equations[0].second.isConst() && equations[0].first != equations[0].second);
- // d_assertionsToPreprocess.clear();
- // d_assertionsToCheck.push_back(NodeManager::currentNM()->mkConst<bool>(false));
+ // d_assertions.clear();
+ // d_assertions.push_back(NodeManager::currentNM()->mkConst<bool>(false));
// return;
// }
// d_topLevelSubstitutions.simplifyRHS(constantPropagations);
@@ -1851,8 +1965,8 @@ bool SmtEnginePrivate::nonClausalSimplify() {
hash_set<TNode, TNodeHashFunction> s;
Trace("debugging") << "NonClausal simplify pre-preprocess\n";
- for (unsigned i = 0; i < d_assertionsToPreprocess.size(); ++ i) {
- Node assertion = d_assertionsToPreprocess[i];
+ for (unsigned i = 0; i < d_assertions.size(); ++ i) {
+ Node assertion = d_assertions[i];
Node assertionNew = newSubstitutions.apply(assertion);
Trace("debugging") << "assertion = " << assertion << endl;
Trace("debugging") << "assertionNew = " << assertionNew << endl;
@@ -1873,17 +1987,16 @@ bool SmtEnginePrivate::nonClausalSimplify() {
}
Trace("debugging") << "\n";
s.insert(assertion);
- d_assertionsToCheck.push_back(assertion);
+ d_assertions.replace(i, assertion);
Trace("simplify") << "SmtEnginePrivate::nonClausalSimplify(): "
<< "non-clausal preprocessed: "
<< assertion << endl;
}
- d_assertionsToPreprocess.clear();
// If in incremental mode, add substitutions to the list of assertions
if (d_substitutionsIndex > 0) {
NodeBuilder<> substitutionsBuilder(kind::AND);
- substitutionsBuilder << d_assertionsToCheck[d_substitutionsIndex];
+ substitutionsBuilder << d_assertions[d_substitutionsIndex];
pos = newSubstitutions.begin();
for (; pos != newSubstitutions.end(); ++pos) {
// Add back this substitution as an assertion
@@ -1893,8 +2006,8 @@ bool SmtEnginePrivate::nonClausalSimplify() {
Trace("simplify") << "SmtEnginePrivate::nonClausalSimplify(): will notify SAT layer of substitution: " << n << endl;
}
if (substitutionsBuilder.getNumChildren() > 1) {
- d_assertionsToCheck[d_substitutionsIndex] =
- Rewriter::rewrite(Node(substitutionsBuilder));
+ d_assertions.replace(d_substitutionsIndex,
+ Rewriter::rewrite(Node(substitutionsBuilder)));
}
} else {
// If not in incremental mode, must add substitutions to model
@@ -1910,8 +2023,8 @@ bool SmtEnginePrivate::nonClausalSimplify() {
}
NodeBuilder<> learnedBuilder(kind::AND);
- Assert(d_realAssertionsEnd <= d_assertionsToCheck.size());
- learnedBuilder << d_assertionsToCheck[d_realAssertionsEnd - 1];
+ Assert(d_realAssertionsEnd <= d_assertions.size());
+ learnedBuilder << d_assertions[d_realAssertionsEnd - 1];
for (unsigned i = 0; i < d_nonClausalLearnedLiterals.size(); ++ i) {
Node learned = d_nonClausalLearnedLiterals[i];
@@ -1940,7 +2053,6 @@ bool SmtEnginePrivate::nonClausalSimplify() {
}
d_nonClausalLearnedLiterals.clear();
-
for (pos = constantPropagations.begin(); pos != constantPropagations.end(); ++pos) {
Node cProp = (*pos).first.eqNode((*pos).second);
Assert(d_topLevelSubstitutions.apply(cProp) == cProp);
@@ -1965,8 +2077,8 @@ bool SmtEnginePrivate::nonClausalSimplify() {
d_topLevelSubstitutions.addSubstitutions(newSubstitutions);
if(learnedBuilder.getNumChildren() > 1) {
- d_assertionsToCheck[d_realAssertionsEnd - 1] =
- Rewriter::rewrite(Node(learnedBuilder));
+ d_assertions.replace(d_realAssertionsEnd - 1,
+ Rewriter::rewrite(Node(learnedBuilder)));
}
d_propagatorNeedsFinish = true;
@@ -1976,9 +2088,9 @@ bool SmtEnginePrivate::nonClausalSimplify() {
void SmtEnginePrivate::bvAbstraction() {
Trace("bv-abstraction") << "SmtEnginePrivate::bvAbstraction()" << endl;
std::vector<Node> new_assertions;
- bool changed = d_smt.d_theoryEngine->ppBvAbstraction(d_assertionsToPreprocess, new_assertions);
- for (unsigned i = 0; i < d_assertionsToPreprocess.size(); ++ i) {
- d_assertionsToPreprocess[i] = Rewriter::rewrite(new_assertions[i]);
+ bool changed = d_smt.d_theoryEngine->ppBvAbstraction(d_assertions.ref(), new_assertions);
+ for (unsigned i = 0; i < d_assertions.size(); ++ i) {
+ d_assertions.replace(i, Rewriter::rewrite(new_assertions[i]));
}
// if we are using the lazy solver and the abstraction
// applies, then UF symbols were introduced
@@ -1993,9 +2105,9 @@ void SmtEnginePrivate::bvAbstraction() {
void SmtEnginePrivate::bvToBool() {
Trace("bv-to-bool") << "SmtEnginePrivate::bvToBool()" << endl;
std::vector<Node> new_assertions;
- d_smt.d_theoryEngine->ppBvToBool(d_assertionsToPreprocess, new_assertions);
- for (unsigned i = 0; i < d_assertionsToPreprocess.size(); ++ i) {
- d_assertionsToPreprocess[i] = Rewriter::rewrite(new_assertions[i]);
+ d_smt.d_theoryEngine->ppBvToBool(d_assertions.ref(), new_assertions);
+ for (unsigned i = 0; i < d_assertions.size(); ++ i) {
+ d_assertions.replace(i, Rewriter::rewrite(new_assertions[i]));
}
}
@@ -2004,23 +2116,23 @@ bool SmtEnginePrivate::simpITE() {
Trace("simplify") << "SmtEnginePrivate::simpITE()" << endl;
- unsigned numAssertionOnEntry = d_assertionsToCheck.size();
- for (unsigned i = 0; i < d_assertionsToCheck.size(); ++i) {
- Node result = d_smt.d_theoryEngine->ppSimpITE(d_assertionsToCheck[i]);
- d_assertionsToCheck[i] = result;
+ unsigned numAssertionOnEntry = d_assertions.size();
+ for (unsigned i = 0; i < d_assertions.size(); ++i) {
+ Node result = d_smt.d_theoryEngine->ppSimpITE(d_assertions[i]);
+ d_assertions.replace(i, result);
if(result.isConst() && !result.getConst<bool>()){
return false;
}
}
- bool result = d_smt.d_theoryEngine->donePPSimpITE(d_assertionsToCheck);
- if(numAssertionOnEntry < d_assertionsToCheck.size()){
+ bool result = d_smt.d_theoryEngine->donePPSimpITE(d_assertions.ref());
+ if(numAssertionOnEntry < d_assertions.size()){
compressBeforeRealAssertions(numAssertionOnEntry);
}
return result;
}
void SmtEnginePrivate::compressBeforeRealAssertions(size_t before){
- size_t curr = d_assertionsToCheck.size();
+ size_t curr = d_assertions.size();
if(before >= curr ||
d_realAssertionsEnd <= 0 ||
d_realAssertionsEnd >= curr){
@@ -2040,24 +2152,24 @@ void SmtEnginePrivate::compressBeforeRealAssertions(size_t before){
std::vector<Node> intoConjunction;
for(size_t i = before; i<curr; ++i){
- intoConjunction.push_back(d_assertionsToCheck[i]);
+ intoConjunction.push_back(d_assertions[i]);
}
- d_assertionsToCheck.resize(before);
+ d_assertions.resize(before);
size_t lastBeforeItes = d_realAssertionsEnd - 1;
- intoConjunction.push_back(d_assertionsToCheck[lastBeforeItes]);
+ intoConjunction.push_back(d_assertions[lastBeforeItes]);
Node newLast = util::NaryBuilder::mkAssoc(kind::AND, intoConjunction);
- d_assertionsToCheck[lastBeforeItes] = newLast;
- Assert(d_assertionsToCheck.size() == before);
+ d_assertions.replace(lastBeforeItes, newLast);
+ Assert(d_assertions.size() == before);
}
-void SmtEnginePrivate::unconstrainedSimp(std::vector<Node>& assertions) {
+void SmtEnginePrivate::unconstrainedSimp() {
TimerStat::CodeTimer unconstrainedSimpTimer(d_smt.d_stats->d_unconstrainedSimpTime);
Trace("simplify") << "SmtEnginePrivate::unconstrainedSimp()" << endl;
- d_smt.d_theoryEngine->ppUnconstrainedSimp(assertions);
+ d_smt.d_theoryEngine->ppUnconstrainedSimp(d_assertions.ref());
}
-void SmtEnginePrivate::constrainSubtypes(TNode top, std::vector<Node>& assertions)
+void SmtEnginePrivate::constrainSubtypes(TNode top, AssertionPipeline& assertions)
throw() {
Trace("constrainSubtypes") << "constrainSubtypes(): looking at " << top << endl;
@@ -2179,8 +2291,7 @@ size_t SmtEnginePrivate::removeFromConjunction(Node& n, const std::hash_set<unsi
}
void SmtEnginePrivate::doMiplibTrick() {
- Assert(d_assertionsToPreprocess.empty());
- Assert(d_realAssertionsEnd == d_assertionsToCheck.size());
+ Assert(d_realAssertionsEnd == d_assertions.size());
Assert(!options::incrementalSolving());
const booleans::CircuitPropagator::BackEdgesMap& backEdges = d_propagator.getBackEdges();
@@ -2411,7 +2522,7 @@ void SmtEnginePrivate::doMiplibTrick() {
Node newVar = nm->mkSkolem(ss.str(), nm->integerType(), "a variable introduced due to scrubbing a miplib encoding", NodeManager::SKOLEM_EXACT_NAME);
Node geq = Rewriter::rewrite(nm->mkNode(kind::GEQ, newVar, zero));
Node leq = Rewriter::rewrite(nm->mkNode(kind::LEQ, newVar, one));
- d_assertionsToCheck.push_back(Rewriter::rewrite(geq.andNode(leq)));
+ d_assertions.push_back(Rewriter::rewrite(geq.andNode(leq)));
SubstitutionMap nullMap(&d_fakeContext);
Theory::PPAssertStatus status CVC4_UNUSED; // just for assertions
status = d_smt.d_theoryEngine->solve(geq, nullMap);
@@ -2462,7 +2573,7 @@ void SmtEnginePrivate::doMiplibTrick() {
}
newAssertion = Rewriter::rewrite(newAssertion);
Debug("miplib") << " " << newAssertion << endl;
- d_assertionsToCheck.push_back(newAssertion);
+ d_assertions.push_back(newAssertion);
Debug("miplib") << " assertions to remove: " << endl;
for(vector<TNode>::const_iterator k = asserts[pos_var].begin(), k_end = asserts[pos_var].end(); k != k_end; ++k) {
Debug("miplib") << " " << *k << endl;
@@ -2475,26 +2586,26 @@ void SmtEnginePrivate::doMiplibTrick() {
if(!removeAssertions.empty()) {
Debug("miplib") << "SmtEnginePrivate::simplify(): scrubbing miplib encoding..." << endl;
for(size_t i = 0; i < d_realAssertionsEnd; ++i) {
- if(removeAssertions.find(d_assertionsToCheck[i].getId()) != removeAssertions.end()) {
- Debug("miplib") << "SmtEnginePrivate::simplify(): - removing " << d_assertionsToCheck[i] << endl;
- d_assertionsToCheck[i] = d_true;
+ if(removeAssertions.find(d_assertions[i].getId()) != removeAssertions.end()) {
+ Debug("miplib") << "SmtEnginePrivate::simplify(): - removing " << d_assertions[i] << endl;
+ d_assertions[i] = d_true;
++d_smt.d_stats->d_numMiplibAssertionsRemoved;
- } else if(d_assertionsToCheck[i].getKind() == kind::AND) {
- size_t removals = removeFromConjunction(d_assertionsToCheck[i], removeAssertions);
+ } else if(d_assertions[i].getKind() == kind::AND) {
+ size_t removals = removeFromConjunction(d_assertions[i], removeAssertions);
if(removals > 0) {
- Debug("miplib") << "SmtEnginePrivate::simplify(): - reduced " << d_assertionsToCheck[i] << endl;
+ Debug("miplib") << "SmtEnginePrivate::simplify(): - reduced " << d_assertions[i] << endl;
Debug("miplib") << "SmtEnginePrivate::simplify(): - by " << removals << " conjuncts" << endl;
d_smt.d_stats->d_numMiplibAssertionsRemoved += removals;
}
}
- Debug("miplib") << "had: " << d_assertionsToCheck[i] << endl;
- d_assertionsToCheck[i] = Rewriter::rewrite(d_topLevelSubstitutions.apply(d_assertionsToCheck[i]));
- Debug("miplib") << "now: " << d_assertionsToCheck[i] << endl;
+ Debug("miplib") << "had: " << d_assertions[i] << endl;
+ d_assertions[i] = Rewriter::rewrite(d_topLevelSubstitutions.apply(d_assertions[i]));
+ Debug("miplib") << "now: " << d_assertions[i] << endl;
}
} else {
Debug("miplib") << "SmtEnginePrivate::simplify(): miplib pass found nothing." << endl;
}
- d_realAssertionsEnd = d_assertionsToCheck.size();
+ d_realAssertionsEnd = d_assertions.size();
}
@@ -2528,7 +2639,7 @@ bool SmtEnginePrivate::simplifyAssertions()
// we add new assertions and need this (in practice, this
// restriction only disables miplib processing during
// re-simplification, which we don't expect to be useful anyway)
- d_realAssertionsEnd == d_assertionsToCheck.size() ) {
+ d_realAssertionsEnd == d_assertions.size() ) {
Chat() << "...fixing miplib encodings..." << endl;
Trace("simplify") << "SmtEnginePrivate::simplify(): "
<< "looking for miplib pseudobooleans..." << endl;
@@ -2540,18 +2651,16 @@ bool SmtEnginePrivate::simplifyAssertions()
Trace("simplify") << "SmtEnginePrivate::simplify(): "
<< "skipping miplib pseudobooleans pass (either incrementalSolving is on, or miplib pbs are turned off)..." << endl;
}
- } else {
- Assert(d_assertionsToCheck.empty());
- d_assertionsToCheck.swap(d_assertionsToPreprocess);
}
- dumpAssertions("post-nonclausal", d_assertionsToCheck);
+ dumpAssertions("post-nonclausal", d_assertions);
Trace("smt") << "POST nonClausalSimplify" << endl;
- Debug("smt") << " d_assertionsToPreprocess: " << d_assertionsToPreprocess.size() << endl;
- Debug("smt") << " d_assertionsToCheck : " << d_assertionsToCheck.size() << endl;
+ Debug("smt") << " d_assertions : " << d_assertions.size() << endl;
// before ppRewrite check if only core theory for BV theory
- d_smt.d_theoryEngine->staticInitializeBVOptions(d_assertionsToCheck);
+ d_smt.d_theoryEngine->staticInitializeBVOptions(d_assertions.ref());
+
+ dumpAssertions("pre-theorypp", d_assertions);
// Theory preprocessing
if (d_smt.d_earlyTheoryPP) {
@@ -2559,17 +2668,16 @@ bool SmtEnginePrivate::simplifyAssertions()
TimerStat::CodeTimer codeTimer(d_smt.d_stats->d_theoryPreprocessTime);
// Call the theory preprocessors
d_smt.d_theoryEngine->preprocessStart();
- for (unsigned i = 0; i < d_assertionsToCheck.size(); ++ i) {
- Assert(Rewriter::rewrite(d_assertionsToCheck[i]) == d_assertionsToCheck[i]);
- d_assertionsToCheck[i] = d_smt.d_theoryEngine->preprocess(d_assertionsToCheck[i]);
- Assert(Rewriter::rewrite(d_assertionsToCheck[i]) == d_assertionsToCheck[i]);
+ for (unsigned i = 0; i < d_assertions.size(); ++ i) {
+ Assert(Rewriter::rewrite(d_assertions[i]) == d_assertions[i]);
+ d_assertions.replace(i, d_smt.d_theoryEngine->preprocess(d_assertions[i]));
+ Assert(Rewriter::rewrite(d_assertions[i]) == d_assertions[i]);
}
}
- dumpAssertions("post-theorypp", d_assertionsToCheck);
+ dumpAssertions("post-theorypp", d_assertions);
Trace("smt") << "POST theoryPP" << endl;
- Debug("smt") << " d_assertionsToPreprocess: " << d_assertionsToPreprocess.size() << endl;
- Debug("smt") << " d_assertionsToCheck : " << d_assertionsToCheck.size() << endl;
+ Debug("smt") << " d_assertions : " << d_assertions.size() << endl;
// ITE simplification
if(options::doITESimp() &&
@@ -2582,38 +2690,33 @@ bool SmtEnginePrivate::simplifyAssertions()
}
}
- dumpAssertions("post-itesimp", d_assertionsToCheck);
+ dumpAssertions("post-itesimp", d_assertions);
Trace("smt") << "POST iteSimp" << endl;
- Debug("smt") << " d_assertionsToPreprocess: " << d_assertionsToPreprocess.size() << endl;
- Debug("smt") << " d_assertionsToCheck : " << d_assertionsToCheck.size() << endl;
+ Debug("smt") << " d_assertions : " << d_assertions.size() << endl;
// Unconstrained simplification
if(options::unconstrainedSimp()) {
Chat() << "...doing unconstrained simplification..." << endl;
- unconstrainedSimp(d_assertionsToCheck);
+ unconstrainedSimp();
}
- dumpAssertions("post-unconstrained", d_assertionsToCheck);
+ dumpAssertions("post-unconstrained", d_assertions);
Trace("smt") << "POST unconstrainedSimp" << endl;
- Debug("smt") << " d_assertionsToPreprocess: " << d_assertionsToPreprocess.size() << endl;
- Debug("smt") << " d_assertionsToCheck : " << d_assertionsToCheck.size() << endl;
+ Debug("smt") << " d_assertions : " << d_assertions.size() << endl;
if(options::repeatSimp() && options::simplificationMode() != SIMPLIFICATION_MODE_NONE) {
Chat() << "...doing another round of nonclausal simplification..." << endl;
Trace("simplify") << "SmtEnginePrivate::simplify(): "
<< " doing repeated simplification" << endl;
- d_assertionsToCheck.swap(d_assertionsToPreprocess);
- Assert(d_assertionsToCheck.empty());
bool noConflict = nonClausalSimplify();
if(!noConflict) {
return false;
}
}
- dumpAssertions("post-repeatsimp", d_assertionsToCheck);
+ dumpAssertions("post-repeatsimp", d_assertions);
Trace("smt") << "POST repeatSimp" << endl;
- Debug("smt") << " d_assertionsToPreprocess: " << d_assertionsToPreprocess.size() << endl;
- Debug("smt") << " d_assertionsToCheck : " << d_assertionsToCheck.size() << endl;
+ Debug("smt") << " d_assertions : " << d_assertions.size() << endl;
} catch(TypeCheckingExceptionPrivate& tcep) {
// Calls to this function should have already weeded out any
@@ -2799,52 +2902,45 @@ void SmtEnginePrivate::processAssertions() {
Assert(d_smt.d_pendingPops == 0);
// Dump the assertions
- dumpAssertions("pre-everything", d_assertionsToPreprocess);
+ dumpAssertions("pre-everything", d_assertions);
Trace("smt") << "SmtEnginePrivate::processAssertions()" << endl;
- Debug("smt") << " d_assertionsToPreprocess: " << d_assertionsToPreprocess.size() << endl;
- Debug("smt") << " d_assertionsToCheck : " << d_assertionsToCheck.size() << endl;
-
- Assert(d_assertionsToCheck.size() == 0);
+ Debug("smt") << " d_assertions : " << d_assertions.size() << endl;
- if (d_assertionsToPreprocess.size() == 0) {
+ if (d_assertions.size() == 0) {
// nothing to do
return;
}
- if (d_assertionsProcessed &&
- ( options::incrementalSolving() ||
- options::simplificationMode() == SIMPLIFICATION_MODE_INCREMENTAL )) {
+ if (d_assertionsProcessed && options::incrementalSolving()) {
// Placeholder for storing substitutions
- d_substitutionsIndex = d_assertionsToPreprocess.size();
- d_assertionsToPreprocess.push_back(NodeManager::currentNM()->mkConst<bool>(true));
+ d_substitutionsIndex = d_assertions.size();
+ d_assertions.push_back(NodeManager::currentNM()->mkConst<bool>(true));
}
// Add dummy assertion in last position - to be used as a
// placeholder for any new assertions to get added
- d_assertionsToPreprocess.push_back(NodeManager::currentNM()->mkConst<bool>(true));
+ d_assertions.push_back(NodeManager::currentNM()->mkConst<bool>(true));
// any assertions added beyond realAssertionsEnd must NOT affect the
// equisatisfiability
- d_realAssertionsEnd = d_assertionsToPreprocess.size();
+ d_realAssertionsEnd = d_assertions.size();
// Assertions are NOT guaranteed to be rewritten by this point
- dumpAssertions("pre-definition-expansion", d_assertionsToPreprocess);
+ dumpAssertions("pre-definition-expansion", d_assertions);
{
Chat() << "expanding definitions..." << endl;
Trace("simplify") << "SmtEnginePrivate::simplify(): expanding definitions" << endl;
TimerStat::CodeTimer codeTimer(d_smt.d_stats->d_definitionExpansionTime);
hash_map<Node, Node, NodeHashFunction> cache;
- for(unsigned i = 0; i < d_assertionsToPreprocess.size(); ++ i) {
- d_assertionsToPreprocess[i] =
- expandDefinitions(d_assertionsToPreprocess[i], cache);
+ for(unsigned i = 0; i < d_assertions.size(); ++ i) {
+ d_assertions.replace(i, expandDefinitions(d_assertions[i], cache));
}
}
- dumpAssertions("post-definition-expansion", d_assertionsToPreprocess);
+ dumpAssertions("post-definition-expansion", d_assertions);
- Debug("smt") << " d_assertionsToPreprocess: " << d_assertionsToPreprocess.size() << endl;
- Debug("smt") << " d_assertionsToCheck : " << d_assertionsToCheck.size() << endl;
+ Debug("smt") << " d_assertions : " << d_assertions.size() << endl;
if (options::bitblastMode() == theory::bv::BITBLAST_MODE_EAGER &&
!d_smt.d_logic.isPure(THEORY_BV)) {
@@ -2854,146 +2950,153 @@ void SmtEnginePrivate::processAssertions() {
}
if (options::bitblastMode() == theory::bv::BITBLAST_MODE_EAGER) {
- d_smt.d_theoryEngine->mkAckermanizationAsssertions(d_assertionsToPreprocess);
+ d_smt.d_theoryEngine->mkAckermanizationAsssertions(d_assertions.ref());
}
if ( options::bvAbstraction() &&
!options::incrementalSolving()) {
- dumpAssertions("pre-bv-abstraction", d_assertionsToPreprocess);
+ dumpAssertions("pre-bv-abstraction", d_assertions);
bvAbstraction();
- dumpAssertions("post-bv-abstraction", d_assertionsToPreprocess);
+ dumpAssertions("post-bv-abstraction", d_assertions);
}
- dumpAssertions("pre-boolean-terms", d_assertionsToPreprocess);
+ dumpAssertions("pre-boolean-terms", d_assertions);
{
Chat() << "rewriting Boolean terms..." << endl;
- for(unsigned i = 0, i_end = d_assertionsToPreprocess.size(); i != i_end; ++i) {
- d_assertionsToPreprocess[i] = rewriteBooleanTerms(d_assertionsToPreprocess[i]);
+ for(unsigned i = 0, i_end = d_assertions.size(); i != i_end; ++i) {
+ d_assertions.replace(i, rewriteBooleanTerms(d_assertions[i]));
}
}
- dumpAssertions("post-boolean-terms", d_assertionsToPreprocess);
+ dumpAssertions("post-boolean-terms", d_assertions);
- Debug("smt") << " d_assertionsToPreprocess: " << d_assertionsToPreprocess.size() << endl;
- Debug("smt") << " d_assertionsToCheck : " << d_assertionsToCheck.size() << endl;
+ Debug("smt") << " d_assertions : " << d_assertions.size() << endl;
- dumpAssertions("pre-constrain-subtypes", d_assertionsToPreprocess);
+ dumpAssertions("pre-constrain-subtypes", d_assertions);
{
// Any variables of subtype types need to be constrained properly.
// Careful, here: constrainSubtypes() adds to the back of
- // d_assertionsToPreprocess, but we don't need to reprocess those.
+ // d_assertions, but we don't need to reprocess those.
// We also can't use an iterator, because the vector may be moved in
// memory during this loop.
Chat() << "constraining subtypes..." << endl;
- for(unsigned i = 0, i_end = d_assertionsToPreprocess.size(); i != i_end; ++i) {
- constrainSubtypes(d_assertionsToPreprocess[i], d_assertionsToPreprocess);
+ for(unsigned i = 0, i_end = d_assertions.size(); i != i_end; ++i) {
+ constrainSubtypes(d_assertions[i], d_assertions);
}
}
- dumpAssertions("post-constrain-subtypes", d_assertionsToPreprocess);
+ dumpAssertions("post-constrain-subtypes", d_assertions);
- Debug("smt") << " d_assertionsToPreprocess: " << d_assertionsToPreprocess.size() << endl;
- Debug("smt") << " d_assertionsToCheck : " << d_assertionsToCheck.size() << endl;
+ Debug("smt") << " d_assertions : " << d_assertions.size() << endl;
+ bool noConflict = true;
// Unconstrained simplification
if(options::unconstrainedSimp()) {
- dumpAssertions("pre-unconstrained-simp", d_assertionsToPreprocess);
+ dumpAssertions("pre-unconstrained-simp", d_assertions);
Chat() << "...doing unconstrained simplification..." << endl;
- unconstrainedSimp(d_assertionsToPreprocess);
- dumpAssertions("post-unconstrained-simp", d_assertionsToPreprocess);
+ unconstrainedSimp();
+ dumpAssertions("post-unconstrained-simp", d_assertions);
}
if(options::bvIntroducePow2()){
- theory::bv::BVIntroducePow2::pow2Rewrite(d_assertionsToPreprocess);
+ theory::bv::BVIntroducePow2::pow2Rewrite(d_assertions.ref());
}
- dumpAssertions("pre-substitution", d_assertionsToPreprocess);
+ dumpAssertions("pre-substitution", d_assertions);
- // Apply the substitutions we already have, and normalize
- Chat() << "applying substitutions..." << endl;
- Trace("simplify") << "SmtEnginePrivate::nonClausalSimplify(): "
- << "applying substitutions" << endl;
- for (unsigned i = 0; i < d_assertionsToPreprocess.size(); ++ i) {
- Trace("simplify") << "applying to " << d_assertionsToPreprocess[i] << endl;
- d_assertionsToPreprocess[i] =
- Rewriter::rewrite(d_topLevelSubstitutions.apply(d_assertionsToPreprocess[i]));
- Trace("simplify") << " got " << d_assertionsToPreprocess[i] << endl;
+ if(options::unsatCores()) {
+ // special rewriting pass for unsat cores, since many of the passes below are skipped
+ for (unsigned i = 0; i < d_assertions.size(); ++ i) {
+ d_assertions.replace(i, Rewriter::rewrite(d_assertions[i]));
+ }
+ } else {
+ // Apply the substitutions we already have, and normalize
+ if(!options::unsatCores()) {
+ Chat() << "applying substitutions..." << endl;
+ Trace("simplify") << "SmtEnginePrivate::nonClausalSimplify(): "
+ << "applying substitutions" << endl;
+ for (unsigned i = 0; i < d_assertions.size(); ++ i) {
+ Trace("simplify") << "applying to " << d_assertions[i] << endl;
+ d_assertions.replace(i, Rewriter::rewrite(d_topLevelSubstitutions.apply(d_assertions[i])));
+ Trace("simplify") << " got " << d_assertions[i] << endl;
+ }
+ }
}
- dumpAssertions("post-substitution", d_assertionsToPreprocess);
- // Assertions ARE guaranteed to be rewritten by this point
+ dumpAssertions("post-substitution", d_assertions);
+ // Assertions ARE guaranteed to be rewritten by this point
// Lift bit-vectors of size 1 to bool
if(options::bitvectorToBool()) {
- dumpAssertions("pre-bv-to-bool", d_assertionsToPreprocess);
+ dumpAssertions("pre-bv-to-bool", d_assertions);
Chat() << "...doing bvToBool..." << endl;
bvToBool();
- dumpAssertions("post-bv-to-bool", d_assertionsToPreprocess);
+ dumpAssertions("post-bv-to-bool", d_assertions);
}
if( d_smt.d_logic.isTheoryEnabled(THEORY_STRINGS) ) {
- dumpAssertions("pre-strings-pp", d_assertionsToPreprocess);
+ dumpAssertions("pre-strings-pp", d_assertions);
CVC4::theory::strings::StringsPreprocess sp;
std::vector<Node> newNodes;
- newNodes.push_back(d_assertionsToPreprocess[d_realAssertionsEnd - 1]);
- sp.simplify( d_assertionsToPreprocess, newNodes );
+ newNodes.push_back(d_assertions[d_realAssertionsEnd - 1]);
+ sp.simplify( d_assertions.ref(), newNodes );
if(newNodes.size() > 1) {
- d_assertionsToPreprocess[d_realAssertionsEnd - 1] = NodeManager::currentNM()->mkNode(kind::AND, newNodes);
+ d_assertions[d_realAssertionsEnd - 1] = NodeManager::currentNM()->mkNode(kind::AND, newNodes);
}
- for (unsigned i = 0; i < d_assertionsToPreprocess.size(); ++ i) {
- d_assertionsToPreprocess[i] = Rewriter::rewrite( d_assertionsToPreprocess[i] );
+ for (unsigned i = 0; i < d_assertions.size(); ++ i) {
+ d_assertions[i] = Rewriter::rewrite( d_assertions[i] );
}
- dumpAssertions("post-strings-pp", d_assertionsToPreprocess);
+ dumpAssertions("post-strings-pp", d_assertions);
}
if( d_smt.d_logic.isQuantified() ){
//remove rewrite rules
- for( unsigned i=0; i < d_assertionsToPreprocess.size(); i++ ) {
- if( d_assertionsToPreprocess[i].getKind() == kind::REWRITE_RULE ){
- Node prev = d_assertionsToPreprocess[i];
+ for( unsigned i=0; i < d_assertions.size(); i++ ) {
+ if( d_assertions[i].getKind() == kind::REWRITE_RULE ){
+ Node prev = d_assertions[i];
Trace("quantifiers-rewrite-debug") << "Rewrite rewrite rule " << prev << "..." << std::endl;
- d_assertionsToPreprocess[i] = Rewriter::rewrite( quantifiers::QuantifiersRewriter::rewriteRewriteRule( d_assertionsToPreprocess[i] ) );
+ d_assertions[i] = Rewriter::rewrite( quantifiers::QuantifiersRewriter::rewriteRewriteRule( d_assertions[i] ) );
Trace("quantifiers-rewrite") << "*** rr-rewrite " << prev << endl;
- Trace("quantifiers-rewrite") << " ...got " << d_assertionsToPreprocess[i] << endl;
+ Trace("quantifiers-rewrite") << " ...got " << d_assertions[i] << endl;
}
}
- dumpAssertions("pre-skolem-quant", d_assertionsToPreprocess);
+ dumpAssertions("pre-skolem-quant", d_assertions);
if( options::preSkolemQuant() ){
//apply pre-skolemization to existential quantifiers
- for (unsigned i = 0; i < d_assertionsToPreprocess.size(); ++ i) {
- Node prev = d_assertionsToPreprocess[i];
+ for (unsigned i = 0; i < d_assertions.size(); ++ i) {
+ Node prev = d_assertions[i];
Trace("quantifiers-rewrite-debug") << "Pre-skolemize " << prev << "..." << std::endl;
vector< TypeNode > fvTypes;
vector< TNode > fvs;
- d_assertionsToPreprocess[i] = quantifiers::QuantifiersRewriter::preSkolemizeQuantifiers( prev, true, fvTypes, fvs );
- if( prev!=d_assertionsToPreprocess[i] ){
- d_assertionsToPreprocess[i] = Rewriter::rewrite( d_assertionsToPreprocess[i] );
+ d_assertions.replace(i, quantifiers::QuantifiersRewriter::preSkolemizeQuantifiers( prev, true, fvTypes, fvs ));
+ if( prev!=d_assertions[i] ){
+ d_assertions.replace(i, Rewriter::rewrite( d_assertions[i] ));
Trace("quantifiers-rewrite") << "*** Pre-skolemize " << prev << endl;
- Trace("quantifiers-rewrite") << " ...got " << d_assertionsToPreprocess[i] << endl;
+ Trace("quantifiers-rewrite") << " ...got " << d_assertions[i] << endl;
}
}
}
- dumpAssertions("post-skolem-quant", d_assertionsToPreprocess);
+ dumpAssertions("post-skolem-quant", d_assertions);
if( options::macrosQuant() ){
//quantifiers macro expansion
bool success;
do{
quantifiers::QuantifierMacros qm;
- success = qm.simplify( d_assertionsToPreprocess, true );
+ success = qm.simplify( d_assertions.ref(), true );
}while( success );
}
Trace("fo-rsn-enable") << std::endl;
if( options::foPropQuant() ){
quantifiers::FirstOrderPropagation fop;
- fop.simplify( d_assertionsToPreprocess );
+ fop.simplify( d_assertions.ref() );
}
}
if( options::sortInference() ){
//sort inference technique
SortInference * si = d_smt.d_theoryEngine->getSortInference();
- si->simplify( d_assertionsToPreprocess );
+ si->simplify( d_assertions.ref() );
for( std::map< Node, Node >::iterator it = si->d_model_replace_f.begin(); it != si->d_model_replace_f.end(); ++it ){
d_smt.setPrintFuncInModel( it->first.toExpr(), false );
d_smt.setPrintFuncInModel( it->second.toExpr(), true );
@@ -3001,25 +3104,25 @@ void SmtEnginePrivate::processAssertions() {
}
//if( options::quantConflictFind() ){
- // d_smt.d_theoryEngine->getQuantConflictFind()->registerAssertions( d_assertionsToPreprocess );
+ // d_smt.d_theoryEngine->getQuantConflictFind()->registerAssertions( d_assertions );
//}
if( options::pbRewrites() ){
- d_pbsProcessor.learn(d_assertionsToPreprocess);
+ d_pbsProcessor.learn(d_assertions.ref());
if(d_pbsProcessor.likelyToHelp()){
- d_pbsProcessor.applyReplacements(d_assertionsToPreprocess);
+ d_pbsProcessor.applyReplacements(d_assertions.ref());
}
}
- dumpAssertions("pre-simplify", d_assertionsToPreprocess);
+ dumpAssertions("pre-simplify", d_assertions);
Chat() << "simplifying assertions..." << endl;
- bool noConflict = simplifyAssertions();
+ noConflict = simplifyAssertions();
if(!noConflict){
++(d_smt.d_stats->d_simplifiedToFalse);
}
- dumpAssertions("post-simplify", d_assertionsToCheck);
+ dumpAssertions("post-simplify", d_assertions);
- dumpAssertions("pre-static-learning", d_assertionsToCheck);
+ dumpAssertions("pre-static-learning", d_assertions);
if(options::doStaticLearning()) {
// Perform static learning
Chat() << "doing static learning..." << endl;
@@ -3027,27 +3130,25 @@ void SmtEnginePrivate::processAssertions() {
<< "performing static learning" << endl;
staticLearning();
}
- dumpAssertions("post-static-learning", d_assertionsToCheck);
+ dumpAssertions("post-static-learning", d_assertions);
Trace("smt") << "POST bvToBool" << endl;
- Debug("smt") << " d_assertionsToPreprocess: " << d_assertionsToPreprocess.size() << endl;
- Debug("smt") << " d_assertionsToCheck : " << d_assertionsToCheck.size() << endl;
+ Debug("smt") << " d_assertions : " << d_assertions.size() << endl;
- dumpAssertions("pre-ite-removal", d_assertionsToCheck);
+ dumpAssertions("pre-ite-removal", d_assertions);
{
Chat() << "removing term ITEs..." << endl;
TimerStat::CodeTimer codeTimer(d_smt.d_stats->d_iteRemovalTime);
// Remove ITEs, updating d_iteSkolemMap
- d_smt.d_stats->d_numAssertionsPre += d_assertionsToCheck.size();
+ d_smt.d_stats->d_numAssertionsPre += d_assertions.size();
removeITEs();
- d_smt.d_stats->d_numAssertionsPost += d_assertionsToCheck.size();
+ d_smt.d_stats->d_numAssertionsPost += d_assertions.size();
}
- dumpAssertions("post-ite-removal", d_assertionsToCheck);
+ dumpAssertions("post-ite-removal", d_assertions);
- dumpAssertions("pre-repeat-simplify", d_assertionsToCheck);
+ dumpAssertions("pre-repeat-simplify", d_assertions);
if(options::repeatSimp()) {
- d_assertionsToCheck.swap(d_assertionsToPreprocess);
Chat() << "re-simplifying assertions..." << endl;
ScopeCounter depth(d_simplifyAssertionsDepth);
noConflict &= simplifyAssertions();
@@ -3076,11 +3177,11 @@ void SmtEnginePrivate::processAssertions() {
IteSkolemMap::iterator it = d_iteSkolemMap.begin();
IteSkolemMap::iterator iend = d_iteSkolemMap.end();
NodeBuilder<> builder(kind::AND);
- builder << d_assertionsToCheck[d_realAssertionsEnd - 1];
+ builder << d_assertions[d_realAssertionsEnd - 1];
vector<TNode> toErase;
for (; it != iend; ++it) {
if (skolemSet.find((*it).first) == skolemSet.end()) {
- TNode iteExpr = d_assertionsToCheck[(*it).second];
+ TNode iteExpr = d_assertions[(*it).second];
if (iteExpr.getKind() == kind::ITE &&
iteExpr[1].getKind() == kind::EQUAL &&
iteExpr[1][0] == (*it).first &&
@@ -3096,8 +3197,8 @@ void SmtEnginePrivate::processAssertions() {
}
}
// Move this iteExpr into the main assertions
- builder << d_assertionsToCheck[(*it).second];
- d_assertionsToCheck[(*it).second] = NodeManager::currentNM()->mkConst<bool>(true);
+ builder << d_assertions[(*it).second];
+ d_assertions[(*it).second] = NodeManager::currentNM()->mkConst<bool>(true);
toErase.push_back((*it).first);
}
if(builder.getNumChildren() > 1) {
@@ -3105,60 +3206,58 @@ void SmtEnginePrivate::processAssertions() {
d_iteSkolemMap.erase(toErase.back());
toErase.pop_back();
}
- d_assertionsToCheck[d_realAssertionsEnd - 1] =
+ d_assertions[d_realAssertionsEnd - 1] =
Rewriter::rewrite(Node(builder));
}
// For some reason this is needed for some benchmarks, such as
// http://cvc4.cs.nyu.edu/benchmarks/smtlib2/QF_AUFBV/dwp_formulas/try5_small_difret_functions_dwp_tac.re_node_set_remove_at.il.dwp.smt2
// Figure it out later
removeITEs();
- // Assert(iteRewriteAssertionsEnd == d_assertionsToCheck.size());
+ // Assert(iteRewriteAssertionsEnd == d_assertions.size());
}
}
- dumpAssertions("post-repeat-simplify", d_assertionsToCheck);
+ dumpAssertions("post-repeat-simplify", d_assertions);
- dumpAssertions("pre-rewrite-apply-to-const", d_assertionsToCheck);
+ dumpAssertions("pre-rewrite-apply-to-const", d_assertions);
if(options::rewriteApplyToConst()) {
Chat() << "Rewriting applies to constants..." << endl;
- TimerStat::CodeTimer codeTimer(d_smt.d_stats->d_theoryPreprocessTime);
- for (unsigned i = 0; i < d_assertionsToCheck.size(); ++ i) {
- d_assertionsToCheck[i] = Rewriter::rewrite(rewriteApplyToConst(d_assertionsToCheck[i]));
+ TimerStat::CodeTimer codeTimer(d_smt.d_stats->d_rewriteApplyToConstTime);
+ for (unsigned i = 0; i < d_assertions.size(); ++ i) {
+ d_assertions[i] = Rewriter::rewrite(rewriteApplyToConst(d_assertions[i]));
}
}
- dumpAssertions("post-rewrite-apply-to-const", d_assertionsToCheck);
+ dumpAssertions("post-rewrite-apply-to-const", d_assertions);
// begin: INVARIANT to maintain: no reordering of assertions or
// introducing new ones
#ifdef CVC4_ASSERTIONS
- unsigned iteRewriteAssertionsEnd = d_assertionsToCheck.size();
+ unsigned iteRewriteAssertionsEnd = d_assertions.size();
#endif
- Debug("smt") << " d_assertionsToPreprocess: " << d_assertionsToPreprocess.size() << endl;
- Debug("smt") << " d_assertionsToCheck : " << d_assertionsToCheck.size() << endl;
+ Debug("smt") << " d_assertions : " << d_assertions.size() << endl;
Debug("smt") << "SmtEnginePrivate::processAssertions() POST SIMPLIFICATION" << endl;
- Debug("smt") << " d_assertionsToPreprocess: " << d_assertionsToPreprocess.size() << endl;
- Debug("smt") << " d_assertionsToCheck : " << d_assertionsToCheck.size() << endl;
+ Debug("smt") << " d_assertions : " << d_assertions.size() << endl;
- dumpAssertions("pre-theory-preprocessing", d_assertionsToCheck);
+ dumpAssertions("pre-theory-preprocessing", d_assertions);
{
Chat() << "theory preprocessing..." << endl;
TimerStat::CodeTimer codeTimer(d_smt.d_stats->d_theoryPreprocessTime);
// Call the theory preprocessors
d_smt.d_theoryEngine->preprocessStart();
- for (unsigned i = 0; i < d_assertionsToCheck.size(); ++ i) {
- d_assertionsToCheck[i] = d_smt.d_theoryEngine->preprocess(d_assertionsToCheck[i]);
+ for (unsigned i = 0; i < d_assertions.size(); ++ i) {
+ d_assertions.replace(i, d_smt.d_theoryEngine->preprocess(d_assertions[i]));
}
}
- dumpAssertions("post-theory-preprocessing", d_assertionsToCheck);
+ dumpAssertions("post-theory-preprocessing", d_assertions);
// If we are using eager bit-blasting wrap assertions in fake atom so that
// everything gets bit-blasted to internal SAT solver
if (options::bitblastMode() == theory::bv::BITBLAST_MODE_EAGER) {
- for (unsigned i = 0; i < d_assertionsToCheck.size(); ++i) {
- TNode atom = d_assertionsToCheck[i];
+ for (unsigned i = 0; i < d_assertions.size(); ++i) {
+ TNode atom = d_assertions[i];
Node eager_atom = NodeManager::currentNM()->mkNode(kind::BITVECTOR_EAGER_ATOM, atom);
- d_assertionsToCheck[i] = eager_atom;
+ d_assertions.replace(i, eager_atom);
TheoryModel* m = d_smt.d_theoryEngine->getModel();
m->addSubstitution(eager_atom, atom);
}
@@ -3167,28 +3266,36 @@ void SmtEnginePrivate::processAssertions() {
// Push the formula to decision engine
if(noConflict) {
Chat() << "pushing to decision engine..." << endl;
- Assert(iteRewriteAssertionsEnd == d_assertionsToCheck.size());
+ Assert(iteRewriteAssertionsEnd == d_assertions.size());
d_smt.d_decisionEngine->addAssertions
- (d_assertionsToCheck, d_realAssertionsEnd, d_iteSkolemMap);
+ (d_assertions.ref(), d_realAssertionsEnd, d_iteSkolemMap);
}
// end: INVARIANT to maintain: no reordering of assertions or
// introducing new ones
- dumpAssertions("post-everything", d_assertionsToCheck);
-
+ dumpAssertions("post-everything", d_assertions);
+
+ //set instantiation level of everything to zero
+ if( options::instLevelInputOnly() && options::instMaxLevel()!=-1 ){
+ for( unsigned i=0; i < d_assertions.size(); i++ ) {
+ theory::QuantifiersEngine::setInstantiationLevelAttr( d_assertions[i], 0 );
+ }
+ }
+
// Push the formula to SAT
{
Chat() << "converting to CNF..." << endl;
TimerStat::CodeTimer codeTimer(d_smt.d_stats->d_cnfConversionTime);
- for (unsigned i = 0; i < d_assertionsToCheck.size(); ++ i) {
- d_smt.d_propEngine->assertFormula(d_assertionsToCheck[i]);
+ for (unsigned i = 0; i < d_assertions.size(); ++ i) {
+ Chat() << "+ " << d_assertions[i] << std::endl;
+ d_smt.d_propEngine->assertFormula(d_assertions[i]);
}
}
d_assertionsProcessed = true;
- d_assertionsToCheck.clear();
+ d_assertions.clear();
d_iteSkolemMap.clear();
}
@@ -3203,13 +3310,8 @@ void SmtEnginePrivate::addFormula(TNode n)
Trace("smt") << "SmtEnginePrivate::addFormula(" << n << ")" << endl;
// Add the normalized formula to the queue
- d_assertionsToPreprocess.push_back(n);
- //d_assertionsToPreprocess.push_back(Rewriter::rewrite(n));
-
- // If the mode of processing is incremental prepreocess and assert immediately
- if (options::simplificationMode() == SIMPLIFICATION_MODE_INCREMENTAL) {
- processAssertions();
- }
+ d_assertions.push_back(n);
+ //d_assertions.push_back(Rewriter::rewrite(n));
}
void SmtEngine::ensureBoolean(const Expr& e) throw(TypeCheckingException) {
@@ -3224,7 +3326,7 @@ void SmtEngine::ensureBoolean(const Expr& e) throw(TypeCheckingException) {
}
}
-Result SmtEngine::checkSat(const Expr& ex) throw(TypeCheckingException, ModalException, LogicException) {
+Result SmtEngine::checkSat(const Expr& ex, bool inUnsatCore) throw(TypeCheckingException, ModalException, LogicException) {
Assert(ex.isNull() || ex.getExprManager() == d_exprManager);
SmtScope smts(this);
finalOptionsAreSet();
@@ -3245,7 +3347,7 @@ Result SmtEngine::checkSat(const Expr& ex) throw(TypeCheckingException, ModalExc
// Ensure expr is type-checked at this point.
ensureBoolean(e);
// Give it to proof manager
- PROOF( ProofManager::currentPM()->addAssertion(e); );
+ PROOF( ProofManager::currentPM()->addAssertion(e, inUnsatCore); );
}
// check to see if a postsolve() is pending
@@ -3307,7 +3409,7 @@ Result SmtEngine::checkSat(const Expr& ex) throw(TypeCheckingException, ModalExc
return r;
}/* SmtEngine::checkSat() */
-Result SmtEngine::query(const Expr& ex) throw(TypeCheckingException, ModalException, LogicException) {
+Result SmtEngine::query(const Expr& ex, bool inUnsatCore) throw(TypeCheckingException, ModalException, LogicException) {
Assert(!ex.isNull());
Assert(ex.getExprManager() == d_exprManager);
SmtScope smts(this);
@@ -3326,7 +3428,7 @@ Result SmtEngine::query(const Expr& ex) throw(TypeCheckingException, ModalExcept
// Ensure that the expression is type-checked at this point, and Boolean
ensureBoolean(e);
// Give it to proof manager
- PROOF( ProofManager::currentPM()->addAssertion(e.notExpr()); );
+ PROOF( ProofManager::currentPM()->addAssertion(e.notExpr(), inUnsatCore); );
// check to see if a postsolve() is pending
if(d_needPostsolve) {
@@ -3385,13 +3487,13 @@ Result SmtEngine::query(const Expr& ex) throw(TypeCheckingException, ModalExcept
return r;
}/* SmtEngine::query() */
-Result SmtEngine::assertFormula(const Expr& ex) throw(TypeCheckingException, LogicException) {
+Result SmtEngine::assertFormula(const Expr& ex, bool inUnsatCore) throw(TypeCheckingException, LogicException) {
Assert(ex.getExprManager() == d_exprManager);
SmtScope smts(this);
finalOptionsAreSet();
doPendingPops();
- PROOF( ProofManager::currentPM()->addAssertion(ex); );
+ PROOF( ProofManager::currentPM()->addAssertion(ex, inUnsatCore); );
Trace("smt") << "SmtEngine::assertFormula(" << ex << ")" << endl;
@@ -3404,7 +3506,7 @@ Result SmtEngine::assertFormula(const Expr& ex) throw(TypeCheckingException, Log
}
d_private->addFormula(e.getNode());
return quickCheck().asValidityResult();
-}
+}/* SmtEngine::assertFormula() */
Node SmtEngine::postprocess(TNode node, TypeNode expectedType) const {
ModelPostprocessor mpost;
@@ -3874,6 +3976,30 @@ void SmtEngine::checkModel(bool hardFailure) {
Notice() << "SmtEngine::checkModel(): all assertions checked out OK !" << endl;
}
+UnsatCore SmtEngine::getUnsatCore() throw(ModalException) {
+ Trace("smt") << "SMT getUnsatCore()" << endl;
+ SmtScope smts(this);
+ finalOptionsAreSet();
+ if(Dump.isOn("benchmark")) {
+ Dump("benchmark") << GetUnsatCoreCommand();
+ }
+#ifdef CVC4_PROOF
+ if(!options::unsatCores()) {
+ throw ModalException("Cannot get an unsat core when produce-unsat-cores option is off.");
+ }
+ if(d_status.isNull() ||
+ d_status.asSatisfiabilityResult() != Result::UNSAT ||
+ d_problemExtended) {
+ throw ModalException("Cannot get an unsat core unless immediately preceded by UNSAT/VALID response.");
+ }
+
+ d_proofManager->getProof(this);// just to trigger core creation
+ return UnsatCore(this, d_proofManager->begin_unsat_core(), d_proofManager->end_unsat_core());
+#else /* CVC4_PROOF */
+ throw ModalException("This build of CVC4 doesn't have proof support (required for unsat cores).");
+#endif /* CVC4_PROOF */
+}
+
Proof* SmtEngine::getProof() throw(ModalException) {
Trace("smt") << "SMT getProof()" << endl;
SmtScope smts(this);
@@ -3883,16 +4009,12 @@ Proof* SmtEngine::getProof() throw(ModalException) {
}
#ifdef CVC4_PROOF
if(!options::proof()) {
- const char* msg =
- "Cannot get a proof when produce-proofs option is off.";
- throw ModalException(msg);
+ throw ModalException("Cannot get a proof when produce-proofs option is off.");
}
if(d_status.isNull() ||
d_status.asSatisfiabilityResult() != Result::UNSAT ||
d_problemExtended) {
- const char* msg =
- "Cannot get a proof unless immediately preceded by UNSAT/VALID response.";
- throw ModalException(msg);
+ throw ModalException("Cannot get a proof unless immediately preceded by UNSAT/VALID response.");
}
return ProofManager::getProof(this);
@@ -4102,9 +4224,13 @@ SExpr SmtEngine::getStatistic(std::string name) const throw() {
return d_statisticsRegistry->getStatistic(name);
}
-void SmtEngine::setUserAttribute(const std::string& attr, Expr expr) {
+void SmtEngine::setUserAttribute(const std::string& attr, Expr expr, std::vector<Expr> expr_values, std::string str_value) {
SmtScope smts(this);
- d_theoryEngine->setUserAttribute(attr, expr.getNode());
+ std::vector<Node> node_values;
+ for( unsigned i=0; i<expr_values.size(); i++ ){
+ node_values.push_back( expr_values[i].getNode() );
+ }
+ d_theoryEngine->setUserAttribute(attr, expr.getNode(), node_values, str_value);
}
void SmtEngine::setPrintFuncInModel(Expr f, bool p) {
diff --git a/src/smt/smt_engine.h b/src/smt/smt_engine.h
index 71b42534a..ac0170f3b 100644
--- a/src/smt/smt_engine.h
+++ b/src/smt/smt_engine.h
@@ -28,6 +28,7 @@
#include "expr/expr.h"
#include "expr/expr_manager.h"
#include "util/proof.h"
+#include "util/unsat_core.h"
#include "smt/modal_exception.h"
#include "smt/logic_exception.h"
#include "options/options.h"
@@ -255,7 +256,7 @@ class CVC4_PUBLIC SmtEngine {
smt::SmtEnginePrivate* d_private;
/**
- * Check that a generated Proof (via getProof()) checks.
+ * Check that a generated proof (via getProof()) checks.
*/
void checkProof();
@@ -424,8 +425,8 @@ public:
/**
* Add a formula to the current context: preprocess, do per-theory
* setup, use processAssertionList(), asserting to T-solver for
- * literals and conjunction of literals. Returns false iff
- * inconsistent.
+ * literals and conjunction of literals. Returns false if
+ * immediately determined to be inconsistent.
*/
void defineFunction(Expr func,
const std::vector<Expr>& formals,
@@ -434,23 +435,25 @@ public:
/**
* Add a formula to the current context: preprocess, do per-theory
* setup, use processAssertionList(), asserting to T-solver for
- * literals and conjunction of literals. Returns false iff
- * inconsistent.
+ * literals and conjunction of literals. Returns false if
+ * immediately determined to be inconsistent. This version
+ * takes a Boolean flag to determine whether to include this asserted
+ * formula in an unsat core (if one is later requested).
*/
- Result assertFormula(const Expr& e) throw(TypeCheckingException, LogicException);
+ Result assertFormula(const Expr& e, bool inUnsatCore = true) throw(TypeCheckingException, LogicException);
/**
* Check validity of an expression with respect to the current set
* of assertions by asserting the query expression's negation and
* calling check(). Returns valid, invalid, or unknown result.
*/
- Result query(const Expr& e) throw(TypeCheckingException, ModalException, LogicException);
+ Result query(const Expr& e, bool inUnsatCore = true) throw(TypeCheckingException, ModalException, LogicException);
/**
* Assert a formula (if provided) to the current context and call
* check(). Returns sat, unsat, or unknown result.
*/
- Result checkSat(const Expr& e = Expr()) throw(TypeCheckingException, ModalException, LogicException);
+ Result checkSat(const Expr& e = Expr(), bool inUnsatCore = true) throw(TypeCheckingException, ModalException, LogicException);
/**
* Simplify a formula without doing "much" work. Does not involve
@@ -507,6 +510,13 @@ public:
void printInstantiations( std::ostream& out );
/**
+ * Get an unsatisfiable core (only if immediately preceded by an
+ * UNSAT or VALID query). Only permitted if CVC4 was built with
+ * unsat-core support and produce-unsat-cores is on.
+ */
+ UnsatCore getUnsatCore() throw(ModalException);
+
+ /**
* Get the current set of assertions. Only permitted if the
* SmtEngine is set to operate interactively.
*/
@@ -651,7 +661,7 @@ public:
* This function is called when an attribute is set by a user.
* In SMT-LIBv2 this is done via the syntax (! expr :attr)
*/
- void setUserAttribute(const std::string& attr, Expr expr);
+ void setUserAttribute(const std::string& attr, Expr expr, std::vector<Expr> expr_values, std::string str_value);
/**
* Set print function in model
diff --git a/src/smt/smt_engine_scope.h b/src/smt/smt_engine_scope.h
index 54b9fa1d0..fb5810fd5 100644
--- a/src/smt/smt_engine_scope.h
+++ b/src/smt/smt_engine_scope.h
@@ -40,9 +40,14 @@ inline SmtEngine* currentSmtEngine() {
}
inline ProofManager* currentProofManager() {
- Assert(PROOF_ON());
+#ifdef CVC4_PROOF
+ Assert(options::proof() || options::unsatCores());
Assert(s_smtEngine_current != NULL);
return s_smtEngine_current->d_proofManager;
+#else /* CVC4_PROOF */
+ InternalError("proofs/unsat cores are not on, but ProofManager requested");
+ return NULL;
+#endif /* CVC4_PROOF */
}
class SmtScope : public NodeManagerScope {
diff --git a/src/theory/arith/theory_arith_private.cpp b/src/theory/arith/theory_arith_private.cpp
index 220737d2e..c657796ee 100644
--- a/src/theory/arith/theory_arith_private.cpp
+++ b/src/theory/arith/theory_arith_private.cpp
@@ -335,7 +335,7 @@ TheoryArithPrivate::Statistics::Statistics()
, d_unsatPivots("theory::arith::pivots::unsat")
, d_unknownPivots("theory::arith::pivots::unkown")
, d_solveIntModelsAttempts("theory::arith::z::solveInt::models::attempts", 0)
- , d_solveIntModelsSuccessful("zzz::solveInt::models::successful", 0)
+ , d_solveIntModelsSuccessful("theory::arith::zzz::solveInt::models::successful", 0)
, d_mipTimer("theory::arith::z::approx::mip::timer")
, d_lpTimer("theory::arith::z::approx::lp::timer")
, d_mipProofsAttempted("theory::arith::z::mip::proofs::attempted", 0)
diff --git a/src/theory/arrays/array_info.cpp b/src/theory/arrays/array_info.cpp
index dc907ba0b..9b2d3647e 100644
--- a/src/theory/arrays/array_info.cpp
+++ b/src/theory/arrays/array_info.cpp
@@ -181,6 +181,20 @@ void ArrayInfo::setModelRep(const TNode a, const TNode b) {
}
+void ArrayInfo::setConstArr(const TNode a, const TNode constArr) {
+ Assert(a.getType().isArray());
+ Info* temp_info;
+ CNodeInfoMap::iterator it = info_map.find(a);
+ if(it == info_map.end()) {
+ temp_info = new Info(ct, bck);
+ temp_info->constArr = constArr;
+ info_map[a] = temp_info;
+ } else {
+ (*it).second->constArr = constArr;
+ }
+
+}
+
/**
* Returns the information associated with TNode a
*/
@@ -224,6 +238,16 @@ const TNode ArrayInfo::getModelRep(const TNode a) const
return TNode();
}
+const TNode ArrayInfo::getConstArr(const TNode a) const
+{
+ CNodeInfoMap::const_iterator it = info_map.find(a);
+
+ if(it!= info_map.end()) {
+ return (*it).second->constArr;
+ }
+ return TNode();
+}
+
const CTNodeList* ArrayInfo::getIndices(const TNode a) const{
CNodeInfoMap::const_iterator it = info_map.find(a);
if(it!= info_map.end()) {
diff --git a/src/theory/arrays/array_info.h b/src/theory/arrays/array_info.h
index 09230bba7..f3c6385e5 100644
--- a/src/theory/arrays/array_info.h
+++ b/src/theory/arrays/array_info.h
@@ -64,11 +64,12 @@ public:
context::CDO<bool> isNonLinear;
context::CDO<bool> rIntro1Applied;
context::CDO<TNode> modelRep;
+ context::CDO<TNode> constArr;
CTNodeList* indices;
CTNodeList* stores;
CTNodeList* in_stores;
- Info(context::Context* c, Backtracker<TNode>* bck) : isNonLinear(c, false), rIntro1Applied(c, false), modelRep(c,TNode()) {
+ Info(context::Context* c, Backtracker<TNode>* bck) : isNonLinear(c, false), rIntro1Applied(c, false), modelRep(c,TNode()), constArr(c,TNode()) {
indices = new(true)CTNodeList(c);
stores = new(true)CTNodeList(c);
in_stores = new(true)CTNodeList(c);
@@ -210,6 +211,7 @@ public:
void setRIntro1Applied(const TNode a);
void setModelRep(const TNode a, const TNode rep);
+ void setConstArr(const TNode a, const TNode constArr);
/**
* Returns the information associated with TNode a
*/
@@ -222,6 +224,8 @@ public:
const TNode getModelRep(const TNode a) const;
+ const TNode getConstArr(const TNode a) const;
+
const CTNodeList* getIndices(const TNode a) const;
const CTNodeList* getStores(const TNode a) const;
diff --git a/src/theory/arrays/options b/src/theory/arrays/options
index 15220fbc2..8ed80c1f1 100644
--- a/src/theory/arrays/options
+++ b/src/theory/arrays/options
@@ -12,7 +12,7 @@ option arraysLazyRIntro1 --arrays-lazy-rintro1 bool :default true :read-write
turn on optimization to only perform RIntro1 rule lazily (see Jovanovic/Barrett 2012: Being Careful with Theory Combination)
option arraysModelBased --arrays-model-based bool :default false :read-write
- turn on model-based arrray solver
+ turn on model-based array solver
option arraysEagerIndexSplitting --arrays-eager-index bool :default true :read-write
turn on eager index splitting for generated array lemmas
@@ -20,4 +20,13 @@ option arraysEagerIndexSplitting --arrays-eager-index bool :default true :read-w
option arraysEagerLemmas --arrays-eager-lemmas bool :default false :read-write
turn on eager lemma generation for arrays
+option arraysConfig --arrays-config int :default 0 :read-write
+ set different array option configurations - for developers only
+
+option arraysReduceSharing --arrays-reduce-sharing bool :default false :read-write
+ use model information to reduce size of care graph for arrays
+
+option arraysPropagate --arrays-prop int :default 2 :read-write
+ propagation effort for arrays: 0 is none, 1 is some, 2 is full
+
endmodule
diff --git a/src/theory/arrays/theory_arrays.cpp b/src/theory/arrays/theory_arrays.cpp
index e73c059d4..cf0eeb14b 100644
--- a/src/theory/arrays/theory_arrays.cpp
+++ b/src/theory/arrays/theory_arrays.cpp
@@ -40,11 +40,11 @@ namespace arrays {
const bool d_ccStore = false;
const bool d_useArrTable = false;
//const bool d_eagerLemmas = false;
-const bool d_propagateLemmas = true;
const bool d_preprocess = true;
const bool d_solveWrite = true;
const bool d_solveWrite2 = false;
// These are now options
+ //const bool d_propagateLemmas = true;
//bool d_useNonLinearOpt = true;
//bool d_lazyRIntro1 = true;
//bool d_eagerIndexSplitting = false;
@@ -87,6 +87,7 @@ TheoryArrays::TheoryArrays(context::Context* c, context::UserContext* u, OutputC
d_permRef(c),
d_modelConstraints(c),
d_lemmasSaved(c),
+ d_defValues(c),
d_inCheckModel(false)
{
StatisticsRegistry::registerStat(&d_numRow);
@@ -449,6 +450,7 @@ void TheoryArrays::preRegisterTermInternal(TNode node)
if (node.getType().isArray()) {
d_equalityEngine.addTriggerTerm(node, THEORY_ARRAY);
+ d_mayEqualEqualityEngine.addTerm(node);
}
else {
d_equalityEngine.addTerm(node);
@@ -468,7 +470,6 @@ void TheoryArrays::preRegisterTermInternal(TNode node)
break;
}
case kind::STORE: {
- // Invariant: array terms should be preregistered before being added to the equality engine
if (d_equalityEngine.hasTerm(node)) {
break;
}
@@ -499,13 +500,28 @@ void TheoryArrays::preRegisterTermInternal(TNode node)
break;
}
case kind::STORE_ALL: {
- throw LogicException("Array theory solver does not yet support assertions using constant array value");
+ if (d_equalityEngine.hasTerm(node)) {
+ break;
+ }
+ ArrayStoreAll storeAll = node.getConst<ArrayStoreAll>();
+ Node defaultValue = Node::fromExpr(storeAll.getExpr());
+ if (!defaultValue.isConst()) {
+ throw LogicException("Array theory solver does not yet support non-constant default values for arrays");
+ }
+ d_infoMap.setConstArr(node, node);
+ d_equalityEngine.addTriggerTerm(node, THEORY_ARRAY);
+ d_mayEqualEqualityEngine.addTerm(node);
+ Assert(d_mayEqualEqualityEngine.getRepresentative(node) == node);
+ d_defValues[node] = defaultValue;
+ break;
}
default:
// Variables etc
if (node.getType().isArray()) {
d_equalityEngine.addTriggerTerm(node, THEORY_ARRAY);
Assert(d_equalityEngine.getSize(node) == 1);
+ // The may equal needs the node
+ d_mayEqualEqualityEngine.addTerm(node);
}
else {
d_equalityEngine.addTerm(node);
@@ -566,12 +582,11 @@ EqualityStatus TheoryArrays::getEqualityStatus(TNode a, TNode b) {
// The terms are implied to be equal
return EQUALITY_TRUE;
}
- if (d_equalityEngine.areDisequal(a, b, false)) {
+ else if (d_equalityEngine.areDisequal(a, b, false)) {
// The terms are implied to be dis-equal
return EQUALITY_FALSE;
}
- //TODO: can we be more precise sometimes?
- return EQUALITY_UNKNOWN;
+ return EQUALITY_UNKNOWN;//FALSE_IN_MODEL;
}
@@ -665,18 +680,19 @@ void TheoryArrays::computeCareGraph()
// Should have been propagated to us
Assert(false);
break;
- case EQUALITY_FALSE_AND_PROPAGATED:
- // Should have been propagated to us
- Assert(false);
- break;
- case EQUALITY_FALSE:
case EQUALITY_TRUE:
// Missed propagation - need to add the pair so that theory engine can force propagation
Debug("arrays::sharing") << "TheoryArrays::computeCareGraph(): missed propagation" << std::endl;
break;
+ case EQUALITY_FALSE_AND_PROPAGATED:
+ // Should have been propagated to us
+ Assert(false);
+ case EQUALITY_FALSE:
case EQUALITY_FALSE_IN_MODEL:
- Debug("arrays::sharing") << "TheoryArrays::computeCareGraph(): false in model" << std::endl;
- break;
+ // Don't need to include this pair
+ if (options::arraysReduceSharing()) {
+ continue;
+ }
default:
break;
}
@@ -811,10 +827,22 @@ void TheoryArrays::collectModelInfo( TheoryModel* m, bool fullModel )
}
Node rep;
- map<Node, Node> defValues;
- map<Node, Node>::iterator it;
+ DefValMap::iterator it;
TypeSet defaultValuesSet;
+ // Compute all default values already in use
+ if (fullModel) {
+ for (size_t i=0; i<arrays.size(); ++i) {
+ TNode nrep = d_equalityEngine.getRepresentative(arrays[i]);
+ d_mayEqualEqualityEngine.addTerm(nrep); // add the term in case it isn't there already
+ TNode mayRep = d_mayEqualEqualityEngine.getRepresentative(nrep);
+ it = d_defValues.find(mayRep);
+ if (it != d_defValues.end()) {
+ defaultValuesSet.add(nrep.getType().getArrayConstituentType(), (*it).second);
+ }
+ }
+ }
+
// Loop through all array equivalence classes that need a representative computed
for (size_t i=0; i<arrays.size(); ++i) {
TNode n = arrays[i];
@@ -822,11 +850,10 @@ void TheoryArrays::collectModelInfo( TheoryModel* m, bool fullModel )
if (fullModel) {
// Compute default value for this array - there is one default value for every mayEqual equivalence class
- d_mayEqualEqualityEngine.addTerm(nrep); // add the term in case it isn't there already
TNode mayRep = d_mayEqualEqualityEngine.getRepresentative(nrep);
- it = defValues.find(mayRep);
+ it = d_defValues.find(mayRep);
// If this mayEqual EC doesn't have a default value associated, get the next available default value for the associated array element type
- if (it == defValues.end()) {
+ if (it == d_defValues.end()) {
TypeNode valueType = nrep.getType().getArrayConstituentType();
rep = defaultValuesSet.nextTypeEnum(valueType);
if (rep.isNull()) {
@@ -834,7 +861,7 @@ void TheoryArrays::collectModelInfo( TheoryModel* m, bool fullModel )
rep = *(defaultValuesSet.getSet(valueType)->begin());
}
Trace("arrays-models") << "New default value = " << rep << endl;
- defValues[mayRep] = rep;
+ d_defValues[mayRep] = rep;
}
else {
rep = (*it).second;
@@ -992,7 +1019,9 @@ void TheoryArrays::check(Effort e) {
if(!options::arraysEagerLemmas() && fullEffort(e) && !d_conflict && !options::arraysModelBased()) {
// generate the lemmas on the worklist
Trace("arrays-lem")<<"Arrays::discharging lemmas: "<<d_RowQueue.size()<<"\n";
- dischargeLemmas();
+ while (d_RowQueue.size() > 0 && !d_conflict) {
+ dischargeLemmas();
+ }
}
Trace("arrays") << spaces(getSatContext()->getLevel()) << "Arrays::check(): done" << endl;
@@ -2036,7 +2065,42 @@ void TheoryArrays::mergeArrays(TNode a, TNode b)
}
}
+ TNode constArrA = d_infoMap.getConstArr(a);
+ TNode constArrB = d_infoMap.getConstArr(b);
+ if (constArrA.isNull()) {
+ if (!constArrB.isNull()) {
+ d_infoMap.setConstArr(a,constArrB);
+ }
+ }
+ else if (!constArrB.isNull()) {
+ if (constArrA != constArrB) {
+ conflict(constArrA,constArrB);
+ }
+ }
+
+ // If a and b have different default values associated with their mayequal equivalence classes,
+ // things get complicated - disallow this for now. -Clark
+ TNode mayRepA = d_mayEqualEqualityEngine.getRepresentative(a);
+ TNode mayRepB = d_mayEqualEqualityEngine.getRepresentative(b);
+
+ DefValMap::iterator it = d_defValues.find(mayRepA);
+ DefValMap::iterator it2 = d_defValues.find(mayRepB);
+ TNode defValue;
+
+ if (it != d_defValues.end()) {
+ defValue = (*it).second;
+ if (it2 != d_defValues.end() && (defValue != (*it2).second)) {
+ throw LogicException("Array theory solver does not yet support write-chains connecting two different constant arrays");
+ }
+ }
+ else if (it2 != d_defValues.end()) {
+ defValue = (*it2).second;
+ }
d_mayEqualEqualityEngine.assertEquality(a.eqNode(b), true, d_true);
+ if (!defValue.isNull()) {
+ mayRepA = d_mayEqualEqualityEngine.getRepresentative(a);
+ d_defValues[mayRepA] = defValue;
+ }
checkRowLemmas(a,b);
checkRowLemmas(b,a);
@@ -2168,6 +2232,17 @@ void TheoryArrays::checkRowForIndex(TNode i, TNode a)
Assert(a.getType().isArray());
Assert(d_equalityEngine.getRepresentative(a) == a);
+ TNode constArr = d_infoMap.getConstArr(a);
+ if (!constArr.isNull()) {
+ ArrayStoreAll storeAll = constArr.getConst<ArrayStoreAll>();
+ Node defValue = Node::fromExpr(storeAll.getExpr());
+ Node selConst = NodeManager::currentNM()->mkNode(kind::SELECT, constArr, i);
+ if (!d_equalityEngine.hasTerm(selConst)) {
+ preRegisterTermInternal(selConst);
+ }
+ d_equalityEngine.assertEquality(selConst.eqNode(defValue), true, d_true);
+ }
+
const CTNodeList* stores = d_infoMap.getStores(a);
const CTNodeList* instores = d_infoMap.getInStores(a);
size_t it = 0;
@@ -2211,15 +2286,25 @@ void TheoryArrays::checkRowLemmas(TNode a, TNode b)
d_infoMap.getInfo(b)->print();
const CTNodeList* i_a = d_infoMap.getIndices(a);
+ size_t it = 0;
+ TNode constArr = d_infoMap.getConstArr(b);
+ if (!constArr.isNull()) {
+ for( ; it < i_a->size(); ++it) {
+ TNode i = (*i_a)[it];
+ Node selConst = NodeManager::currentNM()->mkNode(kind::SELECT, constArr, i);
+ if (!d_equalityEngine.hasTerm(selConst)) {
+ preRegisterTermInternal(selConst);
+ }
+ }
+ }
+
const CTNodeList* st_b = d_infoMap.getStores(b);
const CTNodeList* inst_b = d_infoMap.getInStores(b);
-
- size_t it = 0;
size_t its;
RowLemmaType lem;
- for( ; it < i_a->size(); ++it) {
+ for(it = 0 ; it < i_a->size(); ++it) {
TNode i = (*i_a)[it];
its = 0;
for ( ; its < st_b->size(); ++its) {
@@ -2277,8 +2362,9 @@ void TheoryArrays::queueRowLemma(RowLemmaType lem)
bool bothExist = ajExists && bjExists;
// If propagating, check propagations
- if (d_propagateLemmas) {
- if (d_equalityEngine.areDisequal(i,j,true)) {
+ int prop = options::arraysPropagate();
+ if (prop > 0) {
+ if (d_equalityEngine.areDisequal(i,j,true) && (bothExist || prop > 1)) {
Trace("arrays-lem") << spaces(getSatContext()->getLevel()) <<"Arrays::queueRowLemma: propagating aj = bj ("<<aj<<", "<<bj<<")\n";
Node aj_eq_bj = aj.eqNode(bj);
Node i_eq_j = i.eqNode(j);
diff --git a/src/theory/arrays/theory_arrays.h b/src/theory/arrays/theory_arrays.h
index 9e9d3c890..649232dae 100644
--- a/src/theory/arrays/theory_arrays.h
+++ b/src/theory/arrays/theory_arrays.h
@@ -361,6 +361,10 @@ class TheoryArrays : public Theory {
context::CDHashSet<Node, NodeHashFunction > d_lemmasSaved;
std::vector<Node> d_lemmas;
+ // Default values for each mayEqual equivalence class
+ typedef context::CDHashMap<Node,Node,NodeHashFunction> DefValMap;
+ DefValMap d_defValues;
+
Node getSkolem(TNode ref, const std::string& name, const TypeNode& type, const std::string& comment, bool makeEqual = true);
Node mkAnd(std::vector<TNode>& conjunctions, bool invert = false, unsigned startIndex = 0);
void setNonLinear(TNode a);
diff --git a/src/theory/booleans/circuit_propagator.h b/src/theory/booleans/circuit_propagator.h
index 7dbef4041..169ac6fa7 100644
--- a/src/theory/booleans/circuit_propagator.h
+++ b/src/theory/booleans/circuit_propagator.h
@@ -144,7 +144,7 @@ private:
}
}
- // Get the current assignement
+ // Get the current assignment
AssignmentStatus state = d_state[n];
if(state != UNASSIGNED) {
diff --git a/src/theory/builtin/kinds b/src/theory/builtin/kinds
index 508106106..44474c18a 100644
--- a/src/theory/builtin/kinds
+++ b/src/theory/builtin/kinds
@@ -302,9 +302,6 @@ operator SEXPR 0: "a symbolic expression (any arity)"
operator LAMBDA 2 "a lambda expression; first parameter is a BOUND_VAR_LIST, second is lambda body"
-## for co-datatypes, not yet supported
-# operator MU 2 "mu"
-
parameterized CHAIN CHAIN_OP 2: "chained operator (N-ary), turned into a conjuction of binary applications of the operator on adjoining parameters; first parameter is a CHAIN_OP representing a binary operator, rest are arguments to that operator"
constant CHAIN_OP \
::CVC4::Chain \
@@ -336,7 +333,6 @@ typerule EQUAL ::CVC4::theory::builtin::EqualityTypeRule
typerule DISTINCT ::CVC4::theory::builtin::DistinctTypeRule
typerule SEXPR ::CVC4::theory::builtin::SExprTypeRule
typerule LAMBDA ::CVC4::theory::builtin::LambdaTypeRule
-#typerule MU ::CVC4::theory::builtin::MuTypeRule
typerule CHAIN ::CVC4::theory::builtin::ChainTypeRule
typerule CHAIN_OP ::CVC4::theory::builtin::ChainedOperatorTypeRule
diff --git a/src/theory/builtin/theory_builtin_type_rules.h b/src/theory/builtin/theory_builtin_type_rules.h
index 045f440e6..977a097d0 100644
--- a/src/theory/builtin/theory_builtin_type_rules.h
+++ b/src/theory/builtin/theory_builtin_type_rules.h
@@ -164,27 +164,6 @@ public:
}
};/* class LambdaTypeRule */
-/* For co-datatypes, not yet supported--
-**
-class MuTypeRule {
-public:
- inline static TypeNode computeType(NodeManager* nodeManager, TNode n, bool check) {
- if( n[0].getType(check) != nodeManager->boundVarListType() ) {
- std::stringstream ss;
- ss << "expected a bound var list for MU expression, got `"
- << n[0].getType().toString() << "'";
- throw TypeCheckingExceptionPrivate(n, ss.str());
- }
- std::vector<TypeNode> argTypes;
- for(TNode::iterator i = n[0].begin(); i != n[0].end(); ++i) {
- argTypes.push_back((*i).getType());
- }
- TypeNode rangeType = n[1].getType(check);
- return nodeManager->mkFunctionType(argTypes, rangeType);
- }
-};
-**/
-
class ChainTypeRule {
public:
inline static TypeNode computeType(NodeManager* nodeManager, TNode n, bool check) {
diff --git a/src/theory/bv/aig_bitblaster.cpp b/src/theory/bv/aig_bitblaster.cpp
index ce775874f..6270995ef 100644
--- a/src/theory/bv/aig_bitblaster.cpp
+++ b/src/theory/bv/aig_bitblaster.cpp
@@ -402,7 +402,7 @@ void AigBitblaster::assertToSatSolver(Cnf_Dat_t* pCnf) {
prop::SatLiteral lit(sat_variables[index-1], int_lit < 0);
clause.push_back(lit);
}
- d_satSolver->addClause(clause, false);
+ d_satSolver->addClause(clause, false, RULE_INVALID);
}
}
diff --git a/src/theory/bv/bitblaster_template.h b/src/theory/bv/bitblaster_template.h
index ecd7013c7..ea31e3821 100644
--- a/src/theory/bv/bitblaster_template.h
+++ b/src/theory/bv/bitblaster_template.h
@@ -74,19 +74,22 @@ protected:
typedef std::vector<T> Bits;
typedef __gnu_cxx::hash_map <Node, Bits, NodeHashFunction> TermDefMap;
typedef __gnu_cxx::hash_set<TNode, TNodeHashFunction> TNodeSet;
+ typedef __gnu_cxx::hash_map<Node, Node, NodeHashFunction> ModelCache;
typedef void (*TermBBStrategy) (TNode, Bits&, TBitblaster<T>*);
typedef T (*AtomBBStrategy) (TNode, TBitblaster<T>*);
// caches and mappings
- TermDefMap d_termCache;
-
+ TermDefMap d_termCache;
+ ModelCache d_modelCache;
+
void initAtomBBStrategies();
void initTermBBStrategies();
protected:
/// function tables for the various bitblasting strategies indexed by node kind
TermBBStrategy d_termBBStrategies[kind::LAST_KIND];
AtomBBStrategy d_atomBBStrategies[kind::LAST_KIND];
+ virtual Node getModelFromSatSolver(TNode node, bool fullModel) = 0;
public:
TBitblaster();
virtual ~TBitblaster() {}
@@ -97,9 +100,18 @@ public:
virtual bool hasBBAtom(TNode atom) const = 0;
virtual void storeBBAtom(TNode atom, T atom_bb) = 0;
+
bool hasBBTerm(TNode node) const;
void getBBTerm(TNode node, Bits& bits) const;
- void storeBBTerm(TNode term, const Bits& bits);
+ void storeBBTerm(TNode term, const Bits& bits);
+ /**
+ * Return a constant representing the value of a in the model.
+ * If fullModel is true set unconstrained bits to 0. If not return
+ * NullNode() for a fully or partially unconstrained.
+ *
+ */
+ Node getTermModel(TNode node, bool fullModel);
+ void invalidateModelCache();
};
@@ -109,7 +121,6 @@ class TLazyBitblaster : public TBitblaster<Node> {
typedef std::vector<Node> Bits;
typedef context::CDList<prop::SatLiteral> AssertionList;
typedef context::CDHashMap<prop::SatLiteral, std::vector<prop::SatLiteral> , prop::SatLiteralHashFunction> ExplanationMap;
-
/** This class gets callbacks from minisat on propagations */
class MinisatNotify : public prop::BVSatSolverInterface::Notify {
prop::CnfStream* d_cnf;
@@ -143,9 +154,12 @@ class TLazyBitblaster : public TBitblaster<Node> {
TNodeSet d_bbAtoms;
AbstractionModule* d_abstraction;
bool d_emptyNotify;
+
+ context::CDO<bool> d_satSolverFullModel;
void addAtom(TNode atom);
bool hasValue(TNode a);
+ Node getModelFromSatSolver(TNode a, bool fullModel);
public:
void bbTerm(TNode node, Bits& bits);
void bbAtom(TNode node);
@@ -172,14 +186,7 @@ public:
void setAbstraction(AbstractionModule* abs);
theory::EqualityStatus getEqualityStatus(TNode a, TNode b);
- /**
- * Return a constant Node representing the value of a variable
- * in the current model.
- * @param a
- *
- * @return
- */
- Node getVarValue(TNode a, bool fullModel=true);
+
/**
* Adds a constant value for each bit-blasted variable in the model.
*
@@ -245,7 +252,7 @@ class EagerBitblaster : public TBitblaster<Node> {
TNodeSet d_bbAtoms;
TNodeSet d_variables;
- Node getVarValue(TNode a, bool fullModel);
+ Node getModelFromSatSolver(TNode a, bool fullModel);
bool isSharedTerm(TNode node);
public:
@@ -299,7 +306,7 @@ class AigBitblaster : public TBitblaster<Abc_Obj_t*> {
bool hasInput(TNode input);
void convertToCnfAndAssert();
void assertToSatSolver(Cnf_Dat_t* pCnf);
-
+ Node getModelFromSatSolver(TNode a, bool fullModel) { Unreachable(); }
public:
AigBitblaster();
~AigBitblaster();
@@ -387,6 +394,7 @@ template <class T> void TBitblaster<T>::initTermBBStrategies() {
template <class T>
TBitblaster<T>::TBitblaster()
: d_termCache()
+ , d_modelCache()
{
initAtomBBStrategies();
initTermBBStrategies();
@@ -407,6 +415,53 @@ void TBitblaster<T>::storeBBTerm(TNode node, const Bits& bits) {
d_termCache.insert(std::make_pair(node, bits));
}
+template <class T>
+void TBitblaster<T>::invalidateModelCache() {
+ d_modelCache.clear();
+}
+
+template <class T>
+Node TBitblaster<T>::getTermModel(TNode node, bool fullModel) {
+ if (d_modelCache.find(node) != d_modelCache.end())
+ return d_modelCache[node];
+
+ if (node.isConst())
+ return node;
+
+ Node value = getModelFromSatSolver(node, false);
+ if (!value.isNull()) {
+ Debug("bv-equality-status")<< "TLazyBitblaster::getTermModel from SatSolver" << node <<" => " << value <<"\n";
+ d_modelCache[node] = value;
+ Assert (value.isConst());
+ return value;
+ }
+
+ if (Theory::isLeafOf(node, theory::THEORY_BV)) {
+ // if it is a leaf may ask for fullModel
+ value = getModelFromSatSolver(node, fullModel);
+ Debug("bv-equality-status")<< "TLazyBitblaster::getTermModel from VarValue" << node <<" => " << value <<"\n";
+ Assert (!value.isNull());
+ d_modelCache[node] = value;
+ return value;
+ }
+ Assert (node.getType().isBitVector());
+
+ NodeBuilder<> nb(node.getKind());
+ if (node.getMetaKind() == kind::metakind::PARAMETERIZED) {
+ nb << node.getOperator();
+ }
+
+ for (unsigned i = 0; i < node.getNumChildren(); ++i) {
+ nb << getTermModel(node[i], fullModel);
+ }
+ value = nb;
+ value = Rewriter::rewrite(value);
+ Assert (value.isConst());
+ d_modelCache[node] = value;
+ Debug("bv-term-model")<< "TLazyBitblaster::getTermModel Building Value" << node <<" => " << value <<"\n";
+ return value;
+}
+
} /* bv namespace */
diff --git a/src/theory/bv/bv_quick_check.cpp b/src/theory/bv/bv_quick_check.cpp
index 5f35f95e3..b2b4eebdf 100644
--- a/src/theory/bv/bv_quick_check.cpp
+++ b/src/theory/bv/bv_quick_check.cpp
@@ -115,7 +115,7 @@ BVQuickCheck::vars_iterator BVQuickCheck::endVars() {
}
Node BVQuickCheck::getVarValue(TNode var) {
- return d_bitblaster->getVarValue(var);
+ return d_bitblaster->getTermModel(var, true);
}
diff --git a/src/theory/bv/bv_subtheory_bitblast.cpp b/src/theory/bv/bv_subtheory_bitblast.cpp
index a2a6e19ac..35542fc68 100644
--- a/src/theory/bv/bv_subtheory_bitblast.cpp
+++ b/src/theory/bv/bv_subtheory_bitblast.cpp
@@ -103,6 +103,7 @@ void BitblastSolver::bitblastQueue() {
// don't bit-blast lemma atoms
continue;
}
+ Debug("bitblast-queue") << "Bitblasting atom " << atom <<"\n";
d_bitblaster->bbAtom(atom);
}
}
@@ -218,48 +219,45 @@ void BitblastSolver::collectModelInfo(TheoryModel* m, bool fullModel) {
Node BitblastSolver::getModelValue(TNode node)
{
- if (!d_validModelCache) {
- d_modelCache.clear();
- d_validModelCache = true;
- }
- return getModelValueRec(node);
-}
-
-Node BitblastSolver::getModelValueRec(TNode node)
-{
- Node val;
- if (node.isConst()) {
- return node;
- }
- NodeMap::iterator it = d_modelCache.find(node);
- if (it != d_modelCache.end()) {
- val = (*it).second;
- Debug("bitvector-model") << node << " => (cached) " << val <<"\n";
- return val;
- }
- if (d_bv->isLeaf(node)) {
- val = d_bitblaster->getVarValue(node);
- if (val == Node()) {
- // If no value in model, just set to 0
- val = utils::mkConst(utils::getSize(node), (unsigned)0);
- }
- } else {
- NodeBuilder<> valBuilder(node.getKind());
- if (node.getMetaKind() == kind::metakind::PARAMETERIZED) {
- valBuilder << node.getOperator();
- }
- for (unsigned i = 0; i < node.getNumChildren(); ++i) {
- valBuilder << getModelValueRec(node[i]);
- }
- val = valBuilder;
- val = Rewriter::rewrite(val);
- }
- Assert(val.isConst());
- d_modelCache[node] = val;
- Debug("bitvector-model") << node << " => " << val <<"\n";
+ Node val = d_bitblaster->getTermModel(node, false);
return val;
}
+// Node BitblastSolver::getModelValueRec(TNode node)
+// {
+// Node val;
+// if (node.isConst()) {
+// return node;
+// }
+// NodeMap::iterator it = d_modelCache.find(node);
+// if (it != d_modelCache.end()) {
+// val = (*it).second;
+// Debug("bitvector-model") << node << " => (cached) " << val <<"\n";
+// return val;
+// }
+// if (d_bv->isLeaf(node)) {
+// val = d_bitblaster->getVarValue(node);
+// if (val == Node()) {
+// // If no value in model, just set to 0
+// val = utils::mkConst(utils::getSize(node), (unsigned)0);
+// }
+// } else {
+// NodeBuilder<> valBuilder(node.getKind());
+// if (node.getMetaKind() == kind::metakind::PARAMETERIZED) {
+// valBuilder << node.getOperator();
+// }
+// for (unsigned i = 0; i < node.getNumChildren(); ++i) {
+// valBuilder << getModelValueRec(node[i]);
+// }
+// val = valBuilder;
+// val = Rewriter::rewrite(val);
+// }
+// Assert(val.isConst());
+// d_modelCache[node] = val;
+// Debug("bitvector-model") << node << " => " << val <<"\n";
+// return val;
+// }
+
void BitblastSolver::setConflict(TNode conflict) {
Node final_conflict = conflict;
diff --git a/src/theory/bv/bv_subtheory_bitblast.h b/src/theory/bv/bv_subtheory_bitblast.h
index 414abdcce..77461163c 100644
--- a/src/theory/bv/bv_subtheory_bitblast.h
+++ b/src/theory/bv/bv_subtheory_bitblast.h
@@ -57,7 +57,7 @@ class BitblastSolver : public SubtheorySolver {
AbstractionModule* d_abstractionModule;
BVQuickCheck* d_quickCheck;
QuickXPlain* d_quickXplain;
- Node getModelValueRec(TNode node);
+ // Node getModelValueRec(TNode node);
void setConflict(TNode conflict);
public:
BitblastSolver(context::Context* c, TheoryBV* bv);
diff --git a/src/theory/bv/eager_bitblaster.cpp b/src/theory/bv/eager_bitblaster.cpp
index e8fee00f5..877baec4e 100644
--- a/src/theory/bv/eager_bitblaster.cpp
+++ b/src/theory/bv/eager_bitblaster.cpp
@@ -56,7 +56,7 @@ EagerBitblaster::~EagerBitblaster() {
}
void EagerBitblaster::bbFormula(TNode node) {
- d_cnfStream->convertAndAssert(node, false, false);
+ d_cnfStream->convertAndAssert(node, false, false, RULE_INVALID, TNode::null());
}
/**
@@ -85,7 +85,7 @@ void EagerBitblaster::bbAtom(TNode node) {
AlwaysAssert (options::bitblastMode() == theory::bv::BITBLAST_MODE_EAGER);
storeBBAtom(node, atom_definition);
- d_cnfStream->convertAndAssert(atom_definition, false, false);
+ d_cnfStream->convertAndAssert(atom_definition, false, false, RULE_INVALID, TNode::null());
}
void EagerBitblaster::storeBBAtom(TNode atom, Node atom_bb) {
@@ -156,11 +156,11 @@ bool EagerBitblaster::solve() {
*
* @return
*/
-Node EagerBitblaster::getVarValue(TNode a, bool fullModel) {
+Node EagerBitblaster::getModelFromSatSolver(TNode a, bool fullModel) {
if (!hasBBTerm(a)) {
- Assert(isSharedTerm(a));
- return Node();
+ return fullModel? utils::mkConst(utils::getSize(a), 0u) : Node();
}
+
Bits bits;
getBBTerm(a, bits);
Integer value(0);
@@ -171,7 +171,8 @@ Node EagerBitblaster::getVarValue(TNode a, bool fullModel) {
bit_value = d_satSolver->value(bit);
Assert (bit_value != prop::SAT_VALUE_UNKNOWN);
} else {
- // the bit is unconstrainted so we can give it an arbitrary value
+ if (!fullModel) return Node();
+ // unconstrained bits default to false
bit_value = prop::SAT_VALUE_FALSE;
}
Integer bit_int = bit_value == prop::SAT_VALUE_TRUE ? Integer(1) : Integer(0);
@@ -182,19 +183,17 @@ Node EagerBitblaster::getVarValue(TNode a, bool fullModel) {
void EagerBitblaster::collectModelInfo(TheoryModel* m, bool fullModel) {
- TNodeSet::const_iterator it = d_variables.begin();
+ TNodeSet::iterator it = d_variables.begin();
for (; it!= d_variables.end(); ++it) {
TNode var = *it;
- if (Theory::theoryOf(var) == theory::THEORY_BV || isSharedTerm(var)) {
- Node const_value = getVarValue(var, fullModel);
- if(const_value == Node()) {
- if( fullModel ){
- // if the value is unassigned just set it to zero
- const_value = utils::mkConst(BitVector(utils::getSize(var), 0u));
- }
- }
+ if (d_bv->isLeaf(var) || isSharedTerm(var)) {
+ // only shared terms could not have been bit-blasted
+ Assert (hasBBTerm(var) || isSharedTerm(var));
+
+ Node const_value = getModelFromSatSolver(var, fullModel);
+
if(const_value != Node()) {
- Debug("bitvector-model") << "TLazyBitblaster::collectModelInfo (assert (= "
+ Debug("bitvector-model") << "EagerBitblaster::collectModelInfo (assert (= "
<< var << " "
<< const_value << "))\n";
m->assertEquality(var, const_value, true);
diff --git a/src/theory/bv/lazy_bitblaster.cpp b/src/theory/bv/lazy_bitblaster.cpp
index f721a22f0..f8927284f 100644
--- a/src/theory/bv/lazy_bitblaster.cpp
+++ b/src/theory/bv/lazy_bitblaster.cpp
@@ -41,6 +41,7 @@ TLazyBitblaster::TLazyBitblaster(context::Context* c, bv::TheoryBV* bv, const st
, d_bbAtoms()
, d_abstraction(NULL)
, d_emptyNotify(emptyNotify)
+ , d_satSolverFullModel(c, false)
, d_name(name)
, d_statistics(name) {
d_satSolver = prop::SatSolverFactory::createMinisat(c, name);
@@ -113,7 +114,7 @@ void TLazyBitblaster::bbAtom(TNode node) {
Assert (!atom_bb.isNull());
Node atom_definition = utils::mkNode(kind::IFF, node, atom_bb);
storeBBAtom(node, atom_bb);
- d_cnfStream->convertAndAssert(atom_definition, false, false);
+ d_cnfStream->convertAndAssert(atom_definition, false, false, RULE_INVALID, TNode::null());
return;
}
@@ -125,7 +126,7 @@ void TLazyBitblaster::bbAtom(TNode node) {
// asserting that the atom is true iff the definition holds
Node atom_definition = utils::mkNode(kind::IFF, node, atom_bb);
storeBBAtom(node, atom_bb);
- d_cnfStream->convertAndAssert(atom_definition, false, false);
+ d_cnfStream->convertAndAssert(atom_definition, false, false, RULE_INVALID, TNode::null());
}
void TLazyBitblaster::storeBBAtom(TNode atom, Node atom_bb) {
@@ -258,6 +259,7 @@ bool TLazyBitblaster::solve() {
}
}
Debug("bitvector") << "TLazyBitblaster::solve() asserted atoms " << d_assertedAtoms->size() <<"\n";
+ d_satSolverFullModel.set(true);
return prop::SAT_VALUE_TRUE == d_satSolver->solve();
}
@@ -354,42 +356,38 @@ void TLazyBitblaster::MinisatNotify::safePoint() {
d_bv->d_out->safePoint();
}
+
EqualityStatus TLazyBitblaster::getEqualityStatus(TNode a, TNode b) {
+ Debug("bv-equality-status")<< "TLazyBitblaster::getEqualityStatus " << a <<" = " << b <<"\n";
+ Debug("bv-equality-status")<< "BVSatSolver has full model? " << d_satSolverFullModel.get() <<"\n";
- // We don't want to bit-blast every possibly expensive term for the sake of equality checking
- if (hasBBTerm(a) && hasBBTerm(b)) {
-
- Bits a_bits, b_bits;
- getBBTerm(a, a_bits);
- getBBTerm(b, b_bits);
- theory::EqualityStatus status = theory::EQUALITY_TRUE_IN_MODEL;
- for (unsigned i = 0; i < a_bits.size(); ++ i) {
- if (d_cnfStream->hasLiteral(a_bits[i]) && d_cnfStream->hasLiteral(b_bits[i])) {
- prop::SatLiteral a_lit = d_cnfStream->getLiteral(a_bits[i]);
- prop::SatValue a_lit_value = d_satSolver->value(a_lit);
- if (a_lit_value != prop::SAT_VALUE_UNKNOWN) {
- prop::SatLiteral b_lit = d_cnfStream->getLiteral(b_bits[i]);
- prop::SatValue b_lit_value = d_satSolver->value(b_lit);
- if (b_lit_value != prop::SAT_VALUE_UNKNOWN) {
- if (a_lit_value != b_lit_value) {
- return theory::EQUALITY_FALSE_IN_MODEL;
- }
- } else {
- status = theory::EQUALITY_UNKNOWN;
- }
- } {
- status = theory::EQUALITY_UNKNOWN;
- }
- } else {
- status = theory::EQUALITY_UNKNOWN;
- }
- }
+ // First check if it trivially rewrites to false/true
+ Node a_eq_b = Rewriter::rewrite(utils::mkNode(kind::EQUAL, a, b));
- return status;
+ if (a_eq_b == utils::mkFalse()) return theory::EQUALITY_FALSE;
+ if (a_eq_b == utils::mkTrue()) return theory::EQUALITY_TRUE;
- } else {
- return theory::EQUALITY_UNKNOWN;
+ if (!d_satSolverFullModel.get())
+ return theory::EQUALITY_UNKNOWN;
+
+ // Check if cache is valid (invalidated in check and pops)
+ if (d_bv->d_invalidateModelCache.get()) {
+ invalidateModelCache();
}
+ d_bv->d_invalidateModelCache.set(false);
+
+ Node a_value = getTermModel(a, true);
+ Node b_value = getTermModel(b, true);
+
+ Assert (a_value.isConst() &&
+ b_value.isConst());
+
+ if (a_value == b_value) {
+ Debug("bv-equality-status")<< "theory::EQUALITY_TRUE_IN_MODEL\n";
+ return theory::EQUALITY_TRUE_IN_MODEL;
+ }
+ Debug("bv-equality-status")<< "theory::EQUALITY_FALSE_IN_MODEL\n";
+ return theory::EQUALITY_FALSE_IN_MODEL;
}
@@ -424,11 +422,11 @@ bool TLazyBitblaster::hasValue(TNode a) {
*
* @return
*/
-Node TLazyBitblaster::getVarValue(TNode a, bool fullModel) {
+Node TLazyBitblaster::getModelFromSatSolver(TNode a, bool fullModel) {
if (!hasBBTerm(a)) {
- Assert(isSharedTerm(a));
- return Node();
+ return fullModel? utils::mkConst(utils::getSize(a), 0u) : Node();
}
+
Bits bits;
getBBTerm(a, bits);
Integer value(0);
@@ -439,7 +437,8 @@ Node TLazyBitblaster::getVarValue(TNode a, bool fullModel) {
bit_value = d_satSolver->value(bit);
Assert (bit_value != prop::SAT_VALUE_UNKNOWN);
} else {
- // the bit is unconstrainted so we can give it an arbitrary value
+ if (!fullModel) return Node();
+ // unconstrained bits default to false
bit_value = prop::SAT_VALUE_FALSE;
}
Integer bit_int = bit_value == prop::SAT_VALUE_TRUE ? Integer(1) : Integer(0);
@@ -449,23 +448,26 @@ Node TLazyBitblaster::getVarValue(TNode a, bool fullModel) {
}
void TLazyBitblaster::collectModelInfo(TheoryModel* m, bool fullModel) {
- TNodeSet::iterator it = d_variables.begin();
- for (; it!= d_variables.end(); ++it) {
+ std::set<Node> termSet;
+ d_bv->computeRelevantTerms(termSet);
+
+ for (std::set<Node>::const_iterator it = termSet.begin(); it != termSet.end(); ++it) {
TNode var = *it;
- if (Theory::theoryOf(var) == theory::THEORY_BV || isSharedTerm(var)) {
- Node const_value = getVarValue(var, fullModel);
- if(const_value == Node()) {
- if( fullModel ){
- // if the value is unassigned just set it to zero
- const_value = utils::mkConst(BitVector(utils::getSize(var), 0u));
- }
- }
- if(const_value != Node()) {
- Debug("bitvector-model") << "TLazyBitblaster::collectModelInfo (assert (= "
- << var << " "
- << const_value << "))\n";
+ // not actually a leaf of the bit-vector theory
+ if (d_variables.find(var) == d_variables.end())
+ continue;
+
+ Assert (Theory::theoryOf(var) == theory::THEORY_BV || isSharedTerm(var));
+ // only shared terms could not have been bit-blasted
+ Assert (hasBBTerm(var) || isSharedTerm(var));
+
+ Node const_value = getModelFromSatSolver(var, fullModel);
+ Assert (const_value.isNull() || const_value.isConst());
+ if(const_value != Node()) {
+ Debug("bitvector-model") << "TLazyBitblaster::collectModelInfo (assert (= "
+ << var << " "
+ << const_value << "))\n";
m->assertEquality(var, const_value, true);
- }
}
}
}
@@ -481,7 +483,7 @@ void TLazyBitblaster::clearSolver() {
d_bbAtoms.clear();
d_variables.clear();
d_termCache.clear();
-
+
// recreate sat solver
d_satSolver = prop::SatSolverFactory::createMinisat(d_ctx);
d_cnfStream = new prop::TseitinCnfStream(d_satSolver,
diff --git a/src/theory/bv/theory_bv.cpp b/src/theory/bv/theory_bv.cpp
index 4abf25bb1..91150f663 100644
--- a/src/theory/bv/theory_bv.cpp
+++ b/src/theory/bv/theory_bv.cpp
@@ -49,6 +49,7 @@ TheoryBV::TheoryBV(context::Context* c, context::UserContext* u, OutputChannel&
d_staticLearnCache(),
d_lemmasAdded(c, false),
d_conflict(c, false),
+ d_invalidateModelCache(c, true),
d_literalsToPropagate(c),
d_literalsToPropagateIndex(c, 0),
d_propagatedBy(c),
@@ -356,8 +357,12 @@ void TheoryBV::checkForLemma(TNode fact) {
void TheoryBV::check(Effort e)
{
+ if (done() && !fullEffort(e)) {
+ return;
+ }
Debug("bitvector") << "TheoryBV::check(" << e << ")" << std::endl;
-
+ // we may be getting new assertions so the model cache may not be sound
+ d_invalidateModelCache.set(true);
// if we are using the eager solver
if (options::bitblastMode() == theory::bv::BITBLAST_MODE_EAGER) {
// this can only happen on an empty benchmark
diff --git a/src/theory/bv/theory_bv.h b/src/theory/bv/theory_bv.h
index 22d9f6775..a37a4019e 100644
--- a/src/theory/bv/theory_bv.h
+++ b/src/theory/bv/theory_bv.h
@@ -141,6 +141,9 @@ private:
// Are we in conflict?
context::CDO<bool> d_conflict;
+ // Invalidate the model cache if check was called
+ context::CDO<bool> d_invalidateModelCache;
+
/** The conflict node */
Node d_conflictNode;
diff --git a/src/theory/datatypes/kinds b/src/theory/datatypes/kinds
index d8b42111c..faaf78fe4 100644
--- a/src/theory/datatypes/kinds
+++ b/src/theory/datatypes/kinds
@@ -89,6 +89,12 @@ typerule APPLY_TYPE_ASCRIPTION ::CVC4::theory::datatypes::DatatypeAscriptionType
# constructor applications are constant if they are applied only to constants
construle APPLY_CONSTRUCTOR ::CVC4::theory::datatypes::DatatypeConstructorTypeRule
+## for co-datatypes
+operator MU 2 "a mu operator, first argument is a bound variable, second argument is body"
+typerule MU ::CVC4::theory::datatypes::DatatypeMuTypeRule
+# mu applications are constant expressions
+construle MU ::CVC4::theory::datatypes::DatatypeMuTypeRule
+
operator TUPLE_TYPE 0: "tuple type"
cardinality TUPLE_TYPE \
"::CVC4::theory::datatypes::TupleProperties::computeCardinality(%TYPE%)" \
diff --git a/src/theory/datatypes/options b/src/theory/datatypes/options
index 5fc59b549..7e56b4d7a 100644
--- a/src/theory/datatypes/options
+++ b/src/theory/datatypes/options
@@ -13,5 +13,7 @@ expert-option dtRewriteErrorSel --dt-rewrite-error-sel bool :default false
rewrite incorrectly applied selectors to arbitrary ground term
option dtForceAssignment --dt-force-assignment bool :default false :read-write
force the datatypes solver to give specific values to all datatypes terms before answering sat
+option cdtBisimilar --cdt-bisimilar bool :default true
+ do bisimilarity check for co-datatypes
endmodule
diff --git a/src/theory/datatypes/theory_datatypes.cpp b/src/theory/datatypes/theory_datatypes.cpp
index 544589306..145cd32dd 100644
--- a/src/theory/datatypes/theory_datatypes.cpp
+++ b/src/theory/datatypes/theory_datatypes.cpp
@@ -62,6 +62,7 @@ TheoryDatatypes::TheoryDatatypes(Context* c, UserContext* u, OutputChannel& out,
d_equalityEngine.addFunctionKind(kind::APPLY_UF);
d_true = NodeManager::currentNM()->mkConst( true );
+ d_dtfCounter = 0;
}
TheoryDatatypes::~TheoryDatatypes() {
@@ -118,6 +119,10 @@ TNode TheoryDatatypes::getEqcConstructor( TNode r ) {
}
void TheoryDatatypes::check(Effort e) {
+ if (done() && !fullEffort(e)) {
+ return;
+ }
+
Trace("datatypes-debug") << "Check effort " << e << std::endl;
while(!done() && !d_conflict) {
// Get all the assertions
@@ -142,7 +147,7 @@ void TheoryDatatypes::check(Effort e) {
flushPendingFacts();
}
- if( e == EFFORT_FULL ) {
+ if( e == EFFORT_FULL && !d_conflict ) {
//check for cycles
bool addedFact;
do {
@@ -190,19 +195,23 @@ void TheoryDatatypes::check(Effort e) {
}
}
}
- /*
- if( !needSplit && mustSpecifyAssignment() ){
+ //d_dtfCounter++;
+ if( !needSplit && options::dtForceAssignment() && d_dtfCounter%2==0 ){
//for the sake of termination, we must choose the constructor of a ground term
//NEED GUARENTEE: groundTerm should not contain any subterms of the same type
// TODO: this is probably not good enough, actually need fair enumeration strategy
- Node groundTerm = n.getType().mkGroundTerm();
- int index = Datatype::indexOf( groundTerm.getOperator().toExpr() );
- if( pcons[index] ){
- consIndex = index;
+ if( !n.getType().isRecord() ){ //FIXME
+ Node groundTerm = n.getType().mkGroundTerm();
+ if( groundTerm.getOperator().getType().isConstructor() ){ //FIXME
+ int index = Datatype::indexOf( groundTerm.getOperator().toExpr() );
+ if( pcons[index] ){
+ consIndex = index;
+ }
+ needSplit = true;
+ }
}
- needSplit = true;
}
- */
+
if( needSplit && consIndex!=-1 ) {
//if only one constructor, then this term must be this constructor
if( dt.getNumConstructors()==1 ){
@@ -570,7 +579,12 @@ void TheoryDatatypes::explain(TNode literal, std::vector<TNode>& assumptions){
TNode atom = polarity ? literal : literal[0];
if (atom.getKind() == kind::EQUAL || atom.getKind() == kind::IFF) {
explainEquality( atom[0], atom[1], polarity, assumptions );
+ } else if( atom.getKind() == kind::AND && polarity ){
+ for( unsigned i=0; i<atom.getNumChildren(); i++ ){
+ explain( atom[i], assumptions );
+ }
} else {
+ Assert( atom.getKind()!=kind::AND );
explainPredicate( atom, polarity, assumptions );
}
}
@@ -670,7 +684,7 @@ void TheoryDatatypes::merge( Node t1, Node t2 ){
for( unsigned i=0; i<deq_cand.size(); i++ ){
if( d_equalityEngine.areDisequal( deq_cand[i].first, deq_cand[i].second, true ) ){
conf = true;
- Node eq = NodeManager::currentNM()->mkNode( deq_cand[i].first.getType().isBoolean() ? kind::IFF : kind::EQUAL,
+ Node eq = NodeManager::currentNM()->mkNode( deq_cand[i].first.getType().isBoolean() ? kind::IFF : kind::EQUAL,
deq_cand[i].first, deq_cand[i].second );
exp.push_back( eq.negate() );
}
@@ -1307,32 +1321,44 @@ void TheoryDatatypes::collectModelInfo( TheoryModel* m, bool fullModel ){
const Datatype& dt = ((DatatypeType)(eqc.getType()).toType()).getDatatype();
if( dt.isCodatatype() ){
std::map< Node, Node > vmap;
- Node v = getCodatatypesValue( it->first, eqc_cons, eqc_mu, vmap );
- Trace("dt-cmi-cod") << " EQC(" << it->first << "), constructor is " << it->second << ", value is " << v << std::endl;
+ std::vector< Node > fv;
+ Node v = getCodatatypesValue( it->first, eqc_cons, eqc_mu, vmap, fv );
+ Trace("dt-cmi-cdt") << " EQC(" << it->first << "), constructor is " << it->second << ", value is " << v << ", const = " << v.isConst() << std::endl;
+ m->assertEquality( eqc, v, true );
}
}
}
-Node TheoryDatatypes::getCodatatypesValue( Node n, std::map< Node, Node >& eqc_cons, std::map< Node, Node >& eqc_mu, std::map< Node, Node >& vmap ){
+Node TheoryDatatypes::getCodatatypesValue( Node n, std::map< Node, Node >& eqc_cons, std::map< Node, Node >& eqc_mu, std::map< Node, Node >& vmap, std::vector< Node >& fv ){
std::map< Node, Node >::iterator itv = vmap.find( n );
if( itv!=vmap.end() ){
+ if( std::find( fv.begin(), fv.end(), itv->second )==fv.end() ){
+ fv.push_back( itv->second );
+ }
return itv->second;
}else if( DatatypesRewriter::isTermDatatype( n ) ){
- Node nv = NodeManager::currentNM()->mkBoundVar( n.getType() );
+ std::stringstream ss;
+ ss << "$x" << vmap.size();
+ Node nv = NodeManager::currentNM()->mkBoundVar( ss.str().c_str(), n.getType() );
vmap[n] = nv;
- Trace("dt-cmi-cod-debug") << " map " << n << " -> " << nv << std::endl;
+ Trace("dt-cmi-cdt-debug") << " map " << n << " -> " << nv << std::endl;
Node nc = eqc_cons[n];
Assert( nc.getKind()==APPLY_CONSTRUCTOR );
std::vector< Node > children;
children.push_back( nc.getOperator() );
for( unsigned i=0; i<nc.getNumChildren(); i++ ){
Node r = getRepresentative( nc[i] );
- Node rv = getCodatatypesValue( r, eqc_cons, eqc_mu, vmap );
+ Node rv = getCodatatypesValue( r, eqc_cons, eqc_mu, vmap, fv );
children.push_back( rv );
}
vmap.erase( n );
- return NodeManager::currentNM()->mkNode( APPLY_CONSTRUCTOR, children );
+ Node v = NodeManager::currentNM()->mkNode( APPLY_CONSTRUCTOR, children );
+ //add mu if we found a circular reference
+ if( std::find( fv.begin(), fv.end(), nv )!=fv.end() ){
+ v = NodeManager::currentNM()->mkNode( MU, nv, v );
+ }
+ return v;
}else{
return n;
}
@@ -1450,7 +1476,7 @@ void TheoryDatatypes::instantiate( EqcInfo* eqc, Node n ){
void TheoryDatatypes::checkCycles() {
Debug("datatypes-cycle-check") << "Check cycles" << std::endl;
- std::vector< Node > cod_eqc;
+ std::vector< Node > cdt_eqc;
eq::EqClassesIterator eqcs_i = eq::EqClassesIterator( &d_equalityEngine );
while( !eqcs_i.isFinished() ){
Node eqc = (*eqcs_i);
@@ -1481,27 +1507,30 @@ void TheoryDatatypes::checkCycles() {
}
}else{
//indexing
- cod_eqc.push_back( eqc );
+ cdt_eqc.push_back( eqc );
}
}
++eqcs_i;
}
//process codatatypes
- if( cod_eqc.size()>1 ){
+ if( cdt_eqc.size()>1 && options::cdtBisimilar() ){
+ Trace("dt-cdt-debug") << "Process " << cdt_eqc.size() << " co-datatypes" << std::endl;
std::vector< std::vector< Node > > part_out;
std::vector< TNode > exp;
std::map< Node, Node > cn;
std::map< Node, std::map< Node, int > > dni;
- for( unsigned i=0; i<cod_eqc.size(); i++ ){
- cn[cod_eqc[i]] = cod_eqc[i];
+ for( unsigned i=0; i<cdt_eqc.size(); i++ ){
+ cn[cdt_eqc[i]] = cdt_eqc[i];
}
- separateBisimilar( cod_eqc, part_out, exp, cn, dni, 0, false );
+ separateBisimilar( cdt_eqc, part_out, exp, cn, dni, 0, false );
+ Trace("dt-cdt-debug") << "Done separate bisimilar." << std::endl;
if( !part_out.empty() ){
+ Trace("dt-cdt-debug") << "Process partition size " << part_out.size() << std::endl;
for( unsigned i=0; i<part_out.size(); i++ ){
std::vector< Node > part;
part.push_back( part_out[i][0] );
for( unsigned j=1; j<part_out[i].size(); j++ ){
- Trace("dt-cod") << "Codatatypes : " << part_out[i][0] << " and " << part_out[i][j] << " must be equal!!" << std::endl;
+ Trace("dt-cdt") << "Codatatypes : " << part_out[i][0] << " and " << part_out[i][j] << " must be equal!!" << std::endl;
part.push_back( part_out[i][j] );
std::vector< std::vector< Node > > tpart_out;
exp.clear();
@@ -1513,16 +1542,16 @@ void TheoryDatatypes::checkCycles() {
Assert( tpart_out.size()==1 && tpart_out[0].size()==2 );
part.pop_back();
//merge based on explanation
- Trace("dt-cod") << " exp is : ";
+ Trace("dt-cdt") << " exp is : ";
for( unsigned k=0; k<exp.size(); k++ ){
- Trace("dt-cod") << exp[k] << " ";
+ Trace("dt-cdt") << exp[k] << " ";
}
- Trace("dt-cod") << std::endl;
+ Trace("dt-cdt") << std::endl;
Node eq = part_out[i][0].eqNode( part_out[i][j] );
Node eqExp = mkAnd( exp );
d_pending.push_back( eq );
d_pending_exp[ eq ] = eqExp;
- Trace("datatypes-infer") << "DtInfer : cod-bisimilar : " << eq << " by " << eqExp << std::endl;
+ Trace("datatypes-infer") << "DtInfer : cdt-bisimilar : " << eq << " by " << eqExp << std::endl;
d_infer.push_back( eq );
d_infer_exp.push_back( eqExp );
}
@@ -1537,9 +1566,9 @@ void TheoryDatatypes::separateBisimilar( std::vector< Node >& part, std::vector<
std::map< Node, Node >& cn,
std::map< Node, std::map< Node, int > >& dni, int dniLvl, bool mkExp ){
if( !mkExp ){
- Trace("dt-cod-debug") << "Separate bisimilar : " << std::endl;
+ Trace("dt-cdt-debug") << "Separate bisimilar : " << std::endl;
for( unsigned i=0; i<part.size(); i++ ){
- Trace("dt-cod-debug") << " " << part[i] << ", current = " << cn[part[i]] << std::endl;
+ Trace("dt-cdt-debug") << " " << part[i] << ", current = " << cn[part[i]] << std::endl;
}
}
Assert( part.size()>1 );
@@ -1553,7 +1582,7 @@ void TheoryDatatypes::separateBisimilar( std::vector< Node >& part, std::vector<
std::map< Node, int >::iterator it_rec = dni[part[j]].find( c );
if( it_rec!=dni[part[j]].end() ){
//looped
- if( !mkExp ){ Trace("dt-cod-debug") << " - " << part[j] << " is looping at index " << it_rec->second << std::endl; }
+ if( !mkExp ){ Trace("dt-cdt-debug") << " - " << part[j] << " is looping at index " << it_rec->second << std::endl; }
new_part_rec[ it_rec->second ].push_back( part[j] );
}else{
if( DatatypesRewriter::isTermDatatype( c ) ){
@@ -1565,14 +1594,14 @@ void TheoryDatatypes::separateBisimilar( std::vector< Node >& part, std::vector<
explainEquality( c, ncons, true, exp );
}
new_part[cc].push_back( part[j] );
- if( !mkExp ){ Trace("dt-cod-debug") << " - " << part[j] << " is datatype " << ncons << "." << std::endl; }
+ if( !mkExp ){ Trace("dt-cdt-debug") << " - " << part[j] << " is datatype " << ncons << "." << std::endl; }
}else{
new_part_c[c].push_back( part[j] );
- if( !mkExp ){ Trace("dt-cod-debug") << " - " << part[j] << " is unspecified datatype." << std::endl; }
+ if( !mkExp ){ Trace("dt-cdt-debug") << " - " << part[j] << " is unspecified datatype." << std::endl; }
}
}else{
//add equivalences
- if( !mkExp ){ Trace("dt-cod-debug") << " - " << part[j] << " is term " << c << "." << std::endl; }
+ if( !mkExp ){ Trace("dt-cdt-debug") << " - " << part[j] << " is term " << c << "." << std::endl; }
new_part_c[c].push_back( part[j] );
}
}
@@ -1614,7 +1643,7 @@ void TheoryDatatypes::separateBisimilar( std::vector< Node >& part, std::vector<
//for each child of constructor
unsigned cindex = 0;
while( cindex<nChildren && !split_new_part.empty() ){
- if( !mkExp ){ Trace("dt-cod-debug") << "Split argument #" << cindex << " of " << it->first << "..." << std::endl; }
+ if( !mkExp ){ Trace("dt-cdt-debug") << "Split argument #" << cindex << " of " << it->first << "..." << std::endl; }
std::vector< std::vector< Node > > next_split_new_part;
for( unsigned j=0; j<split_new_part.size(); j++ ){
//set current node
diff --git a/src/theory/datatypes/theory_datatypes.h b/src/theory/datatypes/theory_datatypes.h
index 132077e29..74d10e754 100644
--- a/src/theory/datatypes/theory_datatypes.h
+++ b/src/theory/datatypes/theory_datatypes.h
@@ -174,6 +174,8 @@ private:
context::CDList<TNode> d_consTerms;
/** All the selector terms that the theory has seen */
context::CDList<TNode> d_selTerms;
+ /** counter for forcing assignments (ensures fairness) */
+ unsigned d_dtfCounter;
private:
/** assert fact */
void assertFact( Node fact, Node exp );
@@ -254,7 +256,7 @@ private:
std::map< Node, Node >& cn,
std::map< Node, std::map< Node, int > >& dni, int dniLvl, bool mkExp );
/** build model */
- Node getCodatatypesValue( Node n, std::map< Node, Node >& eqc_cons, std::map< Node, Node >& eqc_mu, std::map< Node, Node >& vmap );
+ Node getCodatatypesValue( Node n, std::map< Node, Node >& eqc_cons, std::map< Node, Node >& eqc_mu, std::map< Node, Node >& vmap, std::vector< Node >& fv );
/** collect terms */
void collectTerms( Node n );
/** get instantiate cons */
diff --git a/src/theory/datatypes/theory_datatypes_type_rules.h b/src/theory/datatypes/theory_datatypes_type_rules.h
index ddad913fe..8ce8ee7df 100644
--- a/src/theory/datatypes/theory_datatypes_type_rules.h
+++ b/src/theory/datatypes/theory_datatypes_type_rules.h
@@ -209,6 +209,49 @@ struct DatatypeAscriptionTypeRule {
}
};/* struct DatatypeAscriptionTypeRule */
+/* For co-datatypes */
+class DatatypeMuTypeRule {
+private:
+ //a Mu-expression is constant iff its body is composed of constructors applied to constant expr and bound variables only
+ inline static bool computeIsConstNode(TNode n, std::vector< TNode >& fv ){
+ if( n.getKind()==kind::MU ){
+ fv.push_back( n[0] );
+ bool ret = computeIsConstNode( n[1], fv );
+ fv.pop_back();
+ return ret;
+ }else if( n.isConst() || std::find( fv.begin(), fv.end(), n )!=fv.end() ){
+ return true;
+ }else if( n.getKind()==kind::APPLY_CONSTRUCTOR ){
+ for( unsigned i=0; i<n.getNumChildren(); i++ ){
+ if( !computeIsConstNode( n[i], fv ) ){
+ return false;
+ }
+ }
+ return true;
+ }else{
+ return false;
+ }
+ }
+public:
+ inline static TypeNode computeType(NodeManager* nodeManager, TNode n, bool check) {
+ if( n[0].getKind()!=kind::BOUND_VARIABLE ) {
+ std::stringstream ss;
+ ss << "expected a bound var for MU expression, got `"
+ << n[0] << "'";
+ throw TypeCheckingExceptionPrivate(n, ss.str());
+ }
+ return n[1].getType(check);
+ }
+ inline static bool computeIsConst(NodeManager* nodeManager, TNode n)
+ throw(AssertionException) {
+ Assert(n.getKind() == kind::MU);
+ NodeManagerScope nms(nodeManager);
+ std::vector< TNode > fv;
+ return computeIsConstNode( n, fv );
+ }
+};
+
+
struct ConstructorProperties {
inline static Cardinality computeCardinality(TypeNode type) {
// Constructors aren't exactly functions, they're like
diff --git a/src/theory/datatypes/type_enumerator.h b/src/theory/datatypes/type_enumerator.h
index 256dcaef2..dc2a83841 100644
--- a/src/theory/datatypes/type_enumerator.h
+++ b/src/theory/datatypes/type_enumerator.h
@@ -28,168 +28,254 @@ namespace CVC4 {
namespace theory {
namespace datatypes {
+
class DatatypesEnumerator : public TypeEnumeratorBase<DatatypesEnumerator> {
/** The datatype we're enumerating */
const Datatype& d_datatype;
- /** The datatype constructor we're currently enumerating */
- size_t d_ctor;
- /** The "first" constructor to consider; it's non-recursive */
- size_t d_zeroCtor;
- /** Delegate enumerators for the arguments of the current constructor */
- TypeEnumerator** d_argEnumerators;
/** type */
TypeNode d_type;
-
- /** Allocate and initialize the delegate enumerators */
- void newEnumerators() {
- d_argEnumerators = new TypeEnumerator*[d_datatype[d_ctor].getNumArgs()];
- for(size_t a = 0; a < d_datatype[d_ctor].getNumArgs(); ++a) {
- d_argEnumerators[a] = NULL;
+ /** The datatype constructor we're currently enumerating */
+ unsigned d_ctor;
+ /** The "first" constructor to consider; it's non-recursive */
+ unsigned d_zeroCtor;
+ /** list of type enumerators (one for each type in a selector argument) */
+ std::map< TypeNode, unsigned > d_te_index;
+ std::vector< TypeEnumerator > d_children;
+ /** terms produced for types */
+ std::map< TypeNode, std::vector< Node > > d_terms;
+ /** arg type of each selector, for each constructor */
+ std::vector< std::vector< TypeNode > > d_sel_types;
+ /** current index for each argument, for each constructor */
+ std::vector< std::vector< unsigned > > d_sel_index;
+ /** current sum of argument indicies for each constructor */
+ std::vector< int > d_sel_sum;
+ /** current bound on the number of times we can iterate argument enumerators */
+ unsigned d_size_limit;
+
+ Node getTermEnum( TypeNode tn, unsigned i ){
+ if( i<d_terms[tn].size() ){
+ return d_terms[tn][i];
+ }else{
+ Debug("dt-enum-debug") << "get term enum " << tn << " " << i << std::endl;
+ std::map< TypeNode, unsigned >::iterator it = d_te_index.find( tn );
+ unsigned tei;
+ if( it==d_te_index.end() ){
+ //initialize child enumerator for type
+ tei = d_children.size();
+ d_te_index[tn] = tei;
+ d_children.push_back( TypeEnumerator( tn ) );
+ d_terms[tn].push_back( *d_children[tei] );
+ }else{
+ tei = it->second;
+ }
+ //enumerate terms until index is reached
+ while( i>=d_terms[tn].size() ){
+ ++d_children[tei];
+ if( d_children[tei].isFinished() ){
+ Debug("dt-enum-debug") << "...fail term enum " << tn << " " << i << std::endl;
+ return Node::null();
+ }
+ d_terms[tn].push_back( *d_children[tei] );
+ }
+ Debug("dt-enum-debug") << "...return term enum " << tn << " " << i << " : " << d_terms[tn][i] << std::endl;
+ return d_terms[tn][i];
}
}
- /** Delete the delegate enumerators */
- void deleteEnumerators() {
- if(d_argEnumerators != NULL) {
- for(size_t a = 0; a < d_datatype[d_ctor].getNumArgs(); ++a) {
- delete d_argEnumerators[a];
+ bool increment( unsigned index ){
+ Debug("dt-enum") << "Incrementing " << d_type << " " << d_ctor << " at size " << d_sel_sum[index] << "/" << d_size_limit << std::endl;
+ if( d_sel_sum[index]==-1 ){
+ //first time
+ d_sel_sum[index] = 0;
+ //special case: no children to iterate
+ if( d_sel_types[index].size()==0 ){
+ Debug("dt-enum") << "...success (nc) = " << (d_size_limit==0) << std::endl;
+ return d_size_limit==0;
+ }else{
+ Debug("dt-enum") << "...success" << std::endl;
+ return true;
+ }
+ }else{
+ unsigned i = 0;
+ while( i < d_sel_index[index].size() ){
+ //increment if the sum of iterations on arguments is less than the limit
+ if( d_sel_sum[index]<(int)d_size_limit ){
+ //also check if child enumerator has enough terms
+ if( !getTermEnum( d_sel_types[index][i], d_sel_index[index][i]+1 ).isNull() ){
+ Debug("dt-enum") << "...success increment child " << i << std::endl;
+ d_sel_index[index][i]++;
+ d_sel_sum[index]++;
+ return true;
+ }
+ }
+ Debug("dt-enum") << "......failed increment child " << i << std::endl;
+ //reset child, iterate next
+ d_sel_sum[index] -= d_sel_index[index][i];
+ d_sel_index[index][i] = 0;
+ i++;
}
- delete [] d_argEnumerators;
- d_argEnumerators = NULL;
+ Debug("dt-enum") << "...failure." << std::endl;
+ return false;
}
}
+ Node getCurrentTerm( unsigned index ){
+ Debug("dt-enum-debug") << "Get current term at " << index << " " << d_type << "..." << std::endl;
+ DatatypeConstructor ctor = d_datatype[index];
+ Debug("dt-enum-debug") << "Check last term..." << std::endl;
+ //we first check if the last argument (which is forced to make sum of iterated arguments equal to d_size_limit) is defined
+ Node lc;
+ if( ctor.getNumArgs()>0 ){
+ lc = getTermEnum( d_sel_types[index][ctor.getNumArgs()-1], d_size_limit - d_sel_sum[index] );
+ if( lc.isNull() ){
+ Debug("dt-enum-debug") << "Current infeasible." << std::endl;
+ return Node::null();
+ }
+ }
+ Debug("dt-enum-debug") << "Get constructor..." << std::endl;
+ NodeBuilder<> b(kind::APPLY_CONSTRUCTOR);
+ Type typ;
+ if( d_datatype.isParametric() ){
+ typ = ctor.getSpecializedConstructorType(d_type.toType());
+ b << NodeManager::currentNM()->mkNode(kind::APPLY_TYPE_ASCRIPTION,
+ NodeManager::currentNM()->mkConst(AscriptionType(typ)), Node::fromExpr( ctor.getConstructor() ) );
+ }else{
+ b << ctor.getConstructor();
+ }
+ Debug("dt-enum-debug") << "Get arguments..." << std::endl;
+ if( ctor.getNumArgs()>0 ){
+ Assert( index<d_sel_types.size() );
+ Assert( index<d_sel_index.size() );
+ Assert( d_sel_types[index].size()==ctor.getNumArgs() );
+ Assert( d_sel_index[index].size()==ctor.getNumArgs()-1 );
+ for( int i=0; i<(int)(ctor.getNumArgs()-1); i++ ){
+ Node c = getTermEnum( d_sel_types[index][i], d_sel_index[index][i] );
+ Assert( !c.isNull() );
+ b << c;
+ }
+ b << lc;
+ }
+ Node nnn = Node(b);
+ Debug("dt-enum-debug") << "Return... " << nnn << std::endl;
+ return nnn;
+ }
public:
DatatypesEnumerator(TypeNode type) throw() :
TypeEnumeratorBase<DatatypesEnumerator>(type),
d_datatype(DatatypeType(type.toType()).getDatatype()),
+ d_type(type),
d_ctor(0),
- d_zeroCtor(0),
- d_argEnumerators(NULL),
- d_type(type) {
+ d_zeroCtor(0) {
//Assert(type.isDatatype());
Debug("te") << "datatype is datatype? " << type.isDatatype() << std::endl;
Debug("te") << "datatype is kind " << type.getKind() << std::endl;
Debug("te") << "datatype is " << type << std::endl;
- /* find the "zero" constructor (the first non-recursive one) */
- /* FIXME: this isn't sufficient for mutually-recursive datatypes! */
- while(d_zeroCtor < d_datatype.getNumConstructors()) {
- bool recursive = false;
+ /* find the "zero" constructor via mkGroundTerm */
+ Node t = type.mkGroundTerm();
+ Assert( t.getKind()==kind::APPLY_CONSTRUCTOR );
+ d_zeroCtor = Datatype::indexOf( t.getOperator().toExpr() );
+ /* start with the constructor for which a ground term is constructed */
+ d_ctor = d_zeroCtor;
+
+ for( unsigned i=0; i<d_datatype.getNumConstructors(); ++i ){
+ d_sel_types.push_back( std::vector< TypeNode >() );
+ d_sel_index.push_back( std::vector< unsigned >() );
+ d_sel_sum.push_back( -1 );
+ DatatypeConstructor ctor = d_datatype[i];
+ Type typ;
if( d_datatype.isParametric() ){
- TypeNode tn = TypeNode::fromType( d_datatype[d_zeroCtor].getSpecializedConstructorType(d_type.toType()) );
- for( unsigned i=0; i<tn.getNumChildren()-1; i++ ){
- if( tn[i]==type ){
- recursive = true;
- break;
- }
- }
- }else{
- for(size_t a = 0; a < d_datatype[d_zeroCtor].getNumArgs() && !recursive; ++a) {
- if(Node::fromExpr(d_datatype[d_zeroCtor][a].getSelector()).getType()[1] == type) {
- recursive = true;
- break;
- }
+ typ = ctor.getSpecializedConstructorType(d_type.toType());
+ }
+ for( unsigned a = 0; a < ctor.getNumArgs(); ++a ){
+ TypeNode tn;
+ if( d_datatype.isParametric() ){
+ tn = TypeNode::fromType( typ )[a];
+ }else{
+ tn = Node::fromExpr(ctor[a].getSelector()).getType()[1];
}
+ d_sel_types[i].push_back( tn );
+ d_sel_index[i].push_back( 0 );
}
- if(!recursive) {
- break;
+ if( !d_sel_index[i].empty() ){
+ d_sel_index[i].pop_back();
}
- ++d_zeroCtor;
}
-
- /* start with the non-recursive constructor */
- d_ctor = d_zeroCtor;
-
- /* allocate space for the enumerators */
- newEnumerators();
+ d_size_limit = 0;
+ //set up initial conditions (should always succeed)
+ bool init_inc = increment( d_ctor );
+ AlwaysAssert( init_inc );
}
DatatypesEnumerator(const DatatypesEnumerator& de) throw() :
TypeEnumeratorBase<DatatypesEnumerator>(de.getType()),
d_datatype(de.d_datatype),
+ d_type(de.d_type),
d_ctor(de.d_ctor),
- d_zeroCtor(de.d_zeroCtor),
- d_argEnumerators(NULL),
- d_type(de.d_type) {
+ d_zeroCtor(de.d_zeroCtor) {
- if(de.d_argEnumerators != NULL) {
- newEnumerators();
- for(size_t a = 0; a < d_datatype[d_ctor].getNumArgs(); ++a) {
- if(de.d_argEnumerators[a] != NULL) {
- d_argEnumerators[a] = new TypeEnumerator(*de.d_argEnumerators[a]);
- }
- }
+ for( std::map< TypeNode, unsigned >::const_iterator it = de.d_te_index.begin(); it != de.d_te_index.end(); ++it ){
+ d_te_index[it->first] = it->second;
+ }
+ for( std::map< TypeNode, std::vector< Node > >::const_iterator it = de.d_terms.begin(); it != de.d_terms.end(); ++it ){
+ d_terms[it->first].insert( d_terms[it->first].end(), it->second.begin(), it->second.end() );
+ }
+ for( unsigned i=0; i<de.d_sel_types.size(); i++ ){
+ d_sel_types.push_back( std::vector< TypeNode >() );
+ d_sel_types[i].insert( d_sel_types[i].end(), de.d_sel_types[i].begin(), de.d_sel_types[i].end() );
}
+ for( unsigned i=0; i<de.d_sel_index.size(); i++ ){
+ d_sel_index.push_back( std::vector< unsigned >() );
+ d_sel_index[i].insert( d_sel_index[i].end(), de.d_sel_index[i].begin(), de.d_sel_index[i].end() );
+ }
+
+ d_children.insert( d_children.end(), de.d_children.begin(), de.d_children.end() );
+ d_sel_sum.insert( d_sel_sum.end(), de.d_sel_sum.begin(), de.d_sel_sum.end() );
+ d_size_limit = de.d_size_limit;
}
~DatatypesEnumerator() throw() {
- deleteEnumerators();
}
Node operator*() throw(NoMoreValuesException) {
+ Debug("dt-enum-debug") << ": get term " << this << std::endl;
if(d_ctor < d_datatype.getNumConstructors()) {
- DatatypeConstructor ctor = d_datatype[d_ctor];
- NodeBuilder<> b(kind::APPLY_CONSTRUCTOR);
- Type typ;
- if( d_datatype.isParametric() ){
- typ = d_datatype[d_ctor].getSpecializedConstructorType(d_type.toType());
- b << NodeManager::currentNM()->mkNode(kind::APPLY_TYPE_ASCRIPTION,
- NodeManager::currentNM()->mkConst(AscriptionType(typ)), Node::fromExpr( ctor.getConstructor() ) );
- }else{
- b << ctor.getConstructor();
- }
- try {
- for(size_t a = 0; a < d_datatype[d_ctor].getNumArgs(); ++a) {
- if(d_argEnumerators[a] == NULL) {
- if( d_datatype.isParametric() ){
- d_argEnumerators[a] = new TypeEnumerator(TypeNode::fromType( typ )[a]);
- }else{
- d_argEnumerators[a] = new TypeEnumerator(Node::fromExpr(d_datatype[d_ctor][a].getSelector()).getType()[1]);
- }
- }
- b << **d_argEnumerators[a];
- }
- } catch(NoMoreValuesException&) {
- InternalError();
- }
- Node nnn = Node(b);
- //if( nnn.getType()!=d_type || !nnn.getType().isComparableTo(d_type) ){
- // Debug("dt-warn") << "WARNING : Enum : " << nnn << " bad type : " << nnn.getType() << " " << d_type << std::endl;
- //}
- return nnn;
+ return getCurrentTerm( d_ctor );
} else {
throw NoMoreValuesException(getType());
}
}
DatatypesEnumerator& operator++() throw() {
- if(d_ctor < d_datatype.getNumConstructors()) {
- for(size_t a = d_datatype[d_ctor].getNumArgs(); a > 0; --a) {
- if((++*d_argEnumerators[a - 1]).isFinished()) {
- *d_argEnumerators[a - 1] = TypeEnumerator(Node::fromExpr(d_datatype[d_ctor][a - 1].getSelector()).getType()[1]);
- } else {
+ Debug("dt-enum-debug") << ": increment " << this << std::endl;
+ unsigned prevSize = d_size_limit;
+ while(d_ctor < d_datatype.getNumConstructors()) {
+ //increment at index
+ while( increment( d_ctor ) ){
+ Node n = getCurrentTerm( d_ctor );
+ if( !n.isNull() ){
return *this;
}
}
-
// Here, we need to step from the current constructor to the next one
- // first, delete the current delegate enumerators
- deleteEnumerators();
-
// Find the next constructor (only complicated by the notion of the "zero" constructor
d_ctor = (d_ctor == d_zeroCtor) ? 0 : d_ctor + 1;
if(d_ctor == d_zeroCtor) {
++d_ctor;
}
-
- // If we aren't out of constructors, allocate space for the new delegate enumerators
- if(d_ctor < d_datatype.getNumConstructors()) {
- newEnumerators();
+ if( d_ctor>=d_datatype.getNumConstructors() ){
+ //try next size limit as long as new terms were generated at last size
+ if( prevSize==d_size_limit ){
+ d_size_limit++;
+ d_ctor = d_zeroCtor;
+ for( unsigned i=0; i<d_sel_sum.size(); i++ ){
+ d_sel_sum[i] = -1;
+ }
+ }
}
}
return *this;
diff --git a/src/theory/idl/theory_idl.cpp b/src/theory/idl/theory_idl.cpp
index 8597c117d..9e402f430 100644
--- a/src/theory/idl/theory_idl.cpp
+++ b/src/theory/idl/theory_idl.cpp
@@ -49,6 +49,10 @@ Node TheoryIdl::ppRewrite(TNode atom) {
}
void TheoryIdl::check(Effort level) {
+ //// Not needed for now, as no code outside while() loop below.
+ // if (done() && !fullEffort(e)) {
+ // return;
+ // }
while(!done()) {
diff --git a/src/theory/quantifiers/bounded_integers.cpp b/src/theory/quantifiers/bounded_integers.cpp
index d6f9704b3..57799fd8e 100644
--- a/src/theory/quantifiers/bounded_integers.cpp
+++ b/src/theory/quantifiers/bounded_integers.cpp
@@ -243,8 +243,13 @@ void BoundedIntegers::process( Node f, Node n, bool pol,
}
}
-void BoundedIntegers::check( Theory::Effort e ) {
- if( e==Theory::EFFORT_LAST_CALL ){
+bool BoundedIntegers::needsCheck( Theory::Effort e ) {
+ return e==Theory::EFFORT_LAST_CALL;
+}
+
+void BoundedIntegers::check( Theory::Effort e, unsigned quant_e ) {
+ if( quant_e==QuantifiersEngine::QEFFORT_STANDARD ){
+ Trace("bint-engine") << "---Bounded Integers---" << std::endl;
bool addedLemma = false;
//make sure proxies are up-to-date with range
for( unsigned i=0; i<d_ranges.size(); i++) {
@@ -252,9 +257,7 @@ void BoundedIntegers::check( Theory::Effort e ) {
addedLemma = true;
}
}
- if( addedLemma ){
- d_quantEngine->flushLemmas( &d_quantEngine->getOutputChannel() );
- }
+ Trace("bint-engine") << " addedLemma = " << addedLemma << std::endl;
}
}
diff --git a/src/theory/quantifiers/bounded_integers.h b/src/theory/quantifiers/bounded_integers.h
index ac188ca65..355360e41 100644
--- a/src/theory/quantifiers/bounded_integers.h
+++ b/src/theory/quantifiers/bounded_integers.h
@@ -110,7 +110,8 @@ private:
public:
BoundedIntegers( context::Context* c, QuantifiersEngine* qe );
- void check( Theory::Effort e );
+ bool needsCheck( Theory::Effort e );
+ void check( Theory::Effort e, unsigned quant_e );
void registerQuantifier( Node f );
void assertNode( Node n );
Node getNextDecisionRequest();
diff --git a/src/theory/quantifiers/candidate_generator.cpp b/src/theory/quantifiers/candidate_generator.cpp
index 9ce79c301..0f2adf3b4 100644
--- a/src/theory/quantifiers/candidate_generator.cpp
+++ b/src/theory/quantifiers/candidate_generator.cpp
@@ -213,7 +213,10 @@ Node CandidateGeneratorQELitDeq::getNextCandidate(){
CandidateGeneratorQEAll::CandidateGeneratorQEAll( QuantifiersEngine* qe, Node mpat ) :
d_match_pattern( mpat ), d_qe( qe ){
-
+ d_match_pattern_type = mpat.getType();
+ Assert( mpat.getKind()==INST_CONSTANT );
+ d_f = quantifiers::TermDb::getInstConstAttr( mpat );
+ d_index = mpat.getAttribute(InstVarNumAttribute());
}
void CandidateGeneratorQEAll::resetInstantiationRound() {
@@ -227,6 +230,9 @@ void CandidateGeneratorQEAll::reset( Node eqc ) {
Node CandidateGeneratorQEAll::getNextCandidate() {
while( !d_eq.isFinished() ){
Node n = (*d_eq);
+ if( options::instMaxLevel()!=-1 ){
+ n = d_qe->getEqualityQuery()->getInternalRepresentative( n, d_f, d_index );
+ }
++d_eq;
if( n.getType().isSubtypeOf( d_match_pattern.getType() ) ){
//an equivalence class with the same type as the pattern, return it
diff --git a/src/theory/quantifiers/candidate_generator.h b/src/theory/quantifiers/candidate_generator.h
index 4569c2335..011e2924d 100644
--- a/src/theory/quantifiers/candidate_generator.h
+++ b/src/theory/quantifiers/candidate_generator.h
@@ -144,8 +144,12 @@ private:
eq::EqClassesIterator d_eq;
//equality you are trying to match equalities for
Node d_match_pattern;
+ TypeNode d_match_pattern_type;
//einstantiator pointer
QuantifiersEngine* d_qe;
+ // quantifier/index for the variable we are matching
+ Node d_f;
+ unsigned d_index;
public:
CandidateGeneratorQEAll( QuantifiersEngine* qe, Node mpat );
~CandidateGeneratorQEAll(){}
diff --git a/src/theory/quantifiers/conjecture_generator.cpp b/src/theory/quantifiers/conjecture_generator.cpp
new file mode 100755
index 000000000..fe3c92323
--- /dev/null
+++ b/src/theory/quantifiers/conjecture_generator.cpp
@@ -0,0 +1,2214 @@
+/********************* */
+/*! \file conjecture_generator.cpp
+ ** \verbatim
+ ** Original author: Andrew Reynolds
+ ** Major contributors: none
+ ** Minor contributors (to current version): none
+ ** This file is part of the CVC4 project.
+ ** Copyright (c) 2009-2014 New York University and The University of Iowa
+ ** See the file COPYING in the top-level source directory for licensing
+ ** information.\endverbatim
+ **
+ ** \brief conjecture generator class
+ **
+ **/
+
+#include "theory/quantifiers/conjecture_generator.h"
+#include "theory/theory_engine.h"
+#include "theory/quantifiers/options.h"
+#include "theory/quantifiers/term_database.h"
+#include "theory/quantifiers/trigger.h"
+#include "theory/quantifiers/first_order_model.h"
+
+using namespace CVC4;
+using namespace CVC4::kind;
+using namespace CVC4::theory;
+using namespace CVC4::theory::quantifiers;
+using namespace std;
+
+namespace CVC4 {
+
+struct sortConjectureScore {
+ std::vector< int > d_scores;
+ bool operator() (unsigned i, unsigned j) { return d_scores[i]>d_scores[j]; }
+};
+
+
+void OpArgIndex::addTerm( ConjectureGenerator * s, TNode n, unsigned index ){
+ if( index==n.getNumChildren() ){
+ Assert( n.hasOperator() );
+ if( std::find( d_ops.begin(), d_ops.end(), n.getOperator() )==d_ops.end() ){
+ d_ops.push_back( n.getOperator() );
+ d_op_terms.push_back( n );
+ }
+ }else{
+ d_child[s->getTermDatabase()->d_arg_reps[n][index]].addTerm( s, n, index+1 );
+ }
+}
+
+Node OpArgIndex::getGroundTerm( ConjectureGenerator * s, std::vector< TNode >& args ) {
+ if( d_ops.empty() ){
+ for( std::map< TNode, OpArgIndex >::iterator it = d_child.begin(); it != d_child.end(); ++it ){
+ std::map< TNode, Node >::iterator itf = s->d_ground_eqc_map.find( it->first );
+ if( itf!=s->d_ground_eqc_map.end() ){
+ args.push_back( itf->second );
+ Node n = it->second.getGroundTerm( s, args );
+ args.pop_back();
+ if( !n.isNull() ){
+ return n;
+ }
+ }
+ }
+ return Node::null();
+ }else{
+ std::vector< TNode > args2;
+ args2.push_back( d_ops[0] );
+ args2.insert( args2.end(), args.begin(), args.end() );
+ return NodeManager::currentNM()->mkNode( d_op_terms[0].getKind(), args2 );
+ }
+}
+
+void OpArgIndex::getGroundTerms( ConjectureGenerator * s, std::vector< TNode >& terms ) {
+ terms.insert( terms.end(), d_op_terms.begin(), d_op_terms.end() );
+ for( std::map< TNode, OpArgIndex >::iterator it = d_child.begin(); it != d_child.end(); ++it ){
+ if( s->isGroundEqc( it->first ) ){
+ it->second.getGroundTerms( s, terms );
+ }
+ }
+}
+
+
+
+ConjectureGenerator::ConjectureGenerator( QuantifiersEngine * qe, context::Context* c ) : QuantifiersModule( qe ),
+d_notify( *this ),
+d_uequalityEngine(d_notify, c, "ConjectureGenerator::ee"),
+d_ee_conjectures( c ){
+ d_fullEffortCount = 0;
+ d_uequalityEngine.addFunctionKind( kind::APPLY_UF );
+ d_uequalityEngine.addFunctionKind( kind::APPLY_CONSTRUCTOR );
+
+}
+
+void ConjectureGenerator::eqNotifyNewClass( TNode t ){
+ Trace("thm-ee-debug") << "UEE : new equivalence class " << t << std::endl;
+ d_upendingAdds.push_back( t );
+}
+
+void ConjectureGenerator::eqNotifyPreMerge(TNode t1, TNode t2) {
+ //get maintained representatives
+ TNode rt1 = t1;
+ TNode rt2 = t2;
+ std::map< Node, EqcInfo* >::iterator it1 = d_eqc_info.find( t1 );
+ if( it1!=d_eqc_info.end() && !it1->second->d_rep.get().isNull() ){
+ rt1 = it1->second->d_rep.get();
+ }
+ std::map< Node, EqcInfo* >::iterator it2 = d_eqc_info.find( t2 );
+ if( it2!=d_eqc_info.end() && !it2->second->d_rep.get().isNull() ){
+ rt2 = it2->second->d_rep.get();
+ }
+ Trace("thm-ee-debug") << "UEE : equality holds : " << t1 << " == " << t2 << std::endl;
+ Trace("thm-ee-debug") << " ureps : " << rt1 << " == " << rt2 << std::endl;
+ Trace("thm-ee-debug") << " relevant : " << d_pattern_is_relevant[rt1] << " " << d_pattern_is_relevant[rt2] << std::endl;
+ Trace("thm-ee-debug") << " normal : " << d_pattern_is_normal[rt1] << " " << d_pattern_is_normal[rt2] << std::endl;
+ Trace("thm-ee-debug") << " size : " << d_pattern_fun_sum[rt1] << " " << d_pattern_fun_sum[rt2] << std::endl;
+
+ if( isUniversalLessThan( rt2, rt1 ) ){
+ EqcInfo * ei;
+ if( it1==d_eqc_info.end() ){
+ ei = getOrMakeEqcInfo( t1, true );
+ }else{
+ ei = it1->second;
+ }
+ ei->d_rep = t2;
+ }
+}
+
+void ConjectureGenerator::eqNotifyPostMerge(TNode t1, TNode t2) {
+
+}
+
+void ConjectureGenerator::eqNotifyDisequal(TNode t1, TNode t2, TNode reason) {
+ Trace("thm-ee-debug") << "UEE : disequality holds : " << t1 << " != " << t2 << std::endl;
+
+}
+
+
+ConjectureGenerator::EqcInfo::EqcInfo( context::Context* c ) : d_rep( c, Node::null() ){
+
+}
+
+ConjectureGenerator::EqcInfo* ConjectureGenerator::getOrMakeEqcInfo( TNode n, bool doMake ) {
+ //Assert( getUniversalRepresentative( n )==n );
+ std::map< Node, EqcInfo* >::iterator eqc_i = d_eqc_info.find( n );
+ if( eqc_i!=d_eqc_info.end() ){
+ return eqc_i->second;
+ }else if( doMake ){
+ EqcInfo* ei = new EqcInfo( d_quantEngine->getSatContext() );
+ d_eqc_info[n] = ei;
+ return ei;
+ }else{
+ return NULL;
+ }
+}
+
+void ConjectureGenerator::setUniversalRelevant( TNode n ) {
+ //add pattern information
+ registerPattern( n, n.getType() );
+ d_urelevant_terms[n] = true;
+ for( unsigned i=0; i<n.getNumChildren(); i++ ){
+ setUniversalRelevant( n[i] );
+ }
+}
+
+bool ConjectureGenerator::isUniversalLessThan( TNode rt1, TNode rt2 ) {
+ //prefer the one that is (normal, smaller) lexographically
+ Assert( d_pattern_is_relevant.find( rt1 )!=d_pattern_is_relevant.end() );
+ Assert( d_pattern_is_relevant.find( rt2 )!=d_pattern_is_relevant.end() );
+ Assert( d_pattern_is_normal.find( rt1 )!=d_pattern_is_normal.end() );
+ Assert( d_pattern_is_normal.find( rt2 )!=d_pattern_is_normal.end() );
+ Assert( d_pattern_fun_sum.find( rt1 )!=d_pattern_fun_sum.end() );
+ Assert( d_pattern_fun_sum.find( rt2 )!=d_pattern_fun_sum.end() );
+
+ if( d_pattern_is_relevant[rt1] && !d_pattern_is_relevant[rt2] ){
+ Trace("thm-ee-debug") << "UEE : LT due to relevant." << std::endl;
+ return true;
+ }else if( d_pattern_is_relevant[rt1]==d_pattern_is_relevant[rt2] ){
+ if( d_pattern_is_normal[rt1] && !d_pattern_is_normal[rt2] ){
+ Trace("thm-ee-debug") << "UEE : LT due to normal." << std::endl;
+ return true;
+ }else if( d_pattern_is_normal[rt1]==d_pattern_is_normal[rt2] ){
+ if( d_pattern_fun_sum[rt1]<d_pattern_fun_sum[rt2] ){
+ Trace("thm-ee-debug") << "UEE : LT due to size." << std::endl;
+ //decide which representative to use : based on size of the term
+ return true;
+ }else if( d_pattern_fun_sum[rt1]==d_pattern_fun_sum[rt2] ){
+ //same size : tie goes to term that has already been reported
+ return isReportedCanon( rt1 ) && !isReportedCanon( rt2 );
+ }
+ }
+ }
+ return false;
+}
+
+
+bool ConjectureGenerator::isReportedCanon( TNode n ) {
+ return std::find( d_ue_canon.begin(), d_ue_canon.end(), n )==d_ue_canon.end();
+}
+
+void ConjectureGenerator::markReportedCanon( TNode n ) {
+ if( !isReportedCanon( n ) ){
+ d_ue_canon.push_back( n );
+ }
+}
+
+bool ConjectureGenerator::areUniversalEqual( TNode n1, TNode n2 ) {
+ return n1==n2 || ( d_uequalityEngine.hasTerm( n1 ) && d_uequalityEngine.hasTerm( n2 ) && d_uequalityEngine.areEqual( n1, n2 ) );
+}
+
+bool ConjectureGenerator::areUniversalDisequal( TNode n1, TNode n2 ) {
+ return n1!=n2 && d_uequalityEngine.hasTerm( n1 ) && d_uequalityEngine.hasTerm( n2 ) && d_uequalityEngine.areDisequal( n1, n2, false );
+}
+
+TNode ConjectureGenerator::getUniversalRepresentative( TNode n, bool add ) {
+ if( add ){
+ if( d_urelevant_terms.find( n )==d_urelevant_terms.end() ){
+ setUniversalRelevant( n );
+ //add term to universal equality engine
+ d_uequalityEngine.addTerm( n );
+ // addding this term to equality engine will lead to a set of new terms (the new subterms of n)
+ // now, do instantiation-based merging for each of these terms
+ Trace("thm-ee-debug") << "Merge equivalence classes based on instantiations of terms..." << std::endl;
+ //merge all pending equalities
+ while( !d_upendingAdds.empty() ){
+ Trace("sg-pending") << "Add " << d_upendingAdds.size() << " pending terms..." << std::endl;
+ std::vector< Node > pending;
+ pending.insert( pending.end(), d_upendingAdds.begin(), d_upendingAdds.end() );
+ d_upendingAdds.clear();
+ for( unsigned i=0; i<pending.size(); i++ ){
+ Node t = pending[i];
+ TypeNode tn = t.getType();
+ Trace("thm-ee-add") << "UEE : Add universal term " << t << std::endl;
+ std::vector< Node > eq_terms;
+ //if occurs modulo equality at ground level, it is equivalent to representative of ground equality engine
+ TNode gt = getTermDatabase()->evaluateTerm( t );
+ if( !gt.isNull() && gt!=t ){
+ eq_terms.push_back( gt );
+ }
+ //get all equivalent terms based on theorem database
+ d_thm_index.getEquivalentTerms( t, eq_terms );
+ if( !eq_terms.empty() ){
+ Trace("thm-ee-add") << "UEE : Based on ground EE/theorem DB, it is equivalent to " << eq_terms.size() << " terms : " << std::endl;
+ //add equivalent terms as equalities to universal engine
+ for( unsigned i=0; i<eq_terms.size(); i++ ){
+ Trace("thm-ee-add") << " " << eq_terms[i] << std::endl;
+ bool assertEq = false;
+ if( d_urelevant_terms.find( eq_terms[i] )!=d_urelevant_terms.end() ){
+ assertEq = true;
+ }else{
+ Assert( eq_terms[i].getType()==tn );
+ registerPattern( eq_terms[i], tn );
+ if( isUniversalLessThan( eq_terms[i], t ) || ( options::conjectureUeeIntro() && d_pattern_fun_sum[t]>=d_pattern_fun_sum[eq_terms[i]] ) ){
+ setUniversalRelevant( eq_terms[i] );
+ assertEq = true;
+ }
+ }
+ if( assertEq ){
+ Node exp;
+ d_uequalityEngine.assertEquality( t.eqNode( eq_terms[i] ), true, exp );
+ }else{
+ Trace("thm-ee-no-add") << "Do not add : " << t << " == " << eq_terms[i] << std::endl;
+ }
+ }
+ }else{
+ Trace("thm-ee-add") << "UEE : No equivalent terms." << std::endl;
+ }
+ }
+ }
+ }
+ }
+
+ if( d_uequalityEngine.hasTerm( n ) ){
+ Node r = d_uequalityEngine.getRepresentative( n );
+ EqcInfo * ei = getOrMakeEqcInfo( r );
+ if( ei && !ei->d_rep.get().isNull() ){
+ return ei->d_rep.get();
+ }else{
+ return r;
+ }
+ }else{
+ return n;
+ }
+}
+
+eq::EqualityEngine * ConjectureGenerator::getEqualityEngine() {
+ return d_quantEngine->getTheoryEngine()->getMasterEqualityEngine();
+}
+
+bool ConjectureGenerator::areEqual( TNode n1, TNode n2 ) {
+ eq::EqualityEngine * ee = getEqualityEngine();
+ return n1==n2 || ( ee->hasTerm( n1 ) && ee->hasTerm( n2 ) && ee->areEqual( n1, n2 ) );
+}
+
+bool ConjectureGenerator::areDisequal( TNode n1, TNode n2 ) {
+ eq::EqualityEngine * ee = getEqualityEngine();
+ return n1!=n2 && ee->hasTerm( n1 ) && ee->hasTerm( n2 ) && ee->areDisequal( n1, n2, false );
+}
+
+TNode ConjectureGenerator::getRepresentative( TNode n ) {
+ eq::EqualityEngine * ee = getEqualityEngine();
+ if( ee->hasTerm( n ) ){
+ return ee->getRepresentative( n );
+ }else{
+ return n;
+ }
+}
+
+TermDb * ConjectureGenerator::getTermDatabase() {
+ return d_quantEngine->getTermDatabase();
+}
+
+Node ConjectureGenerator::getFreeVar( TypeNode tn, unsigned i ) {
+ Assert( !tn.isNull() );
+ while( d_free_var[tn].size()<=i ){
+ std::stringstream oss;
+ oss << tn;
+ std::stringstream os;
+ os << oss.str()[0] << i;
+ Node x = NodeManager::currentNM()->mkBoundVar( os.str().c_str(), tn );
+ d_free_var_num[x] = d_free_var[tn].size();
+ d_free_var[tn].push_back( x );
+ }
+ return d_free_var[tn][i];
+}
+
+
+
+Node ConjectureGenerator::getCanonicalTerm( TNode n, std::map< TypeNode, unsigned >& var_count, std::map< TNode, TNode >& subs ) {
+ if( n.getKind()==BOUND_VARIABLE ){
+ std::map< TNode, TNode >::iterator it = subs.find( n );
+ if( it==subs.end() ){
+ TypeNode tn = n.getType();
+ //allocate variable
+ unsigned vn = var_count[tn];
+ var_count[tn]++;
+ subs[n] = getFreeVar( tn, vn );
+ return subs[n];
+ }else{
+ return it->second;
+ }
+ }else{
+ std::vector< Node > children;
+ if( n.getKind()!=EQUAL ){
+ if( n.hasOperator() ){
+ TNode op = n.getOperator();
+ if( !d_tge.isRelevantFunc( op ) ){
+ return Node::null();
+ }
+ children.push_back( op );
+ }else{
+ return Node::null();
+ }
+ }
+ for( unsigned i=0; i<n.getNumChildren(); i++ ){
+ Node cn = getCanonicalTerm( n[i], var_count, subs );
+ if( cn.isNull() ){
+ return Node::null();
+ }else{
+ children.push_back( cn );
+ }
+ }
+ return NodeManager::currentNM()->mkNode( n.getKind(), children );
+ }
+}
+
+bool ConjectureGenerator::isHandledTerm( TNode n ){
+ return !n.getAttribute(NoMatchAttribute()) && inst::Trigger::isAtomicTrigger( n ) && ( n.getKind()!=APPLY_UF || n.getOperator().getKind()!=SKOLEM );
+}
+
+Node ConjectureGenerator::getGroundEqc( TNode r ) {
+ std::map< TNode, Node >::iterator it = d_ground_eqc_map.find( r );
+ return it!=d_ground_eqc_map.end() ? it->second : Node::null();
+}
+
+bool ConjectureGenerator::isGroundEqc( TNode r ) {
+ return d_ground_eqc_map.find( r )!=d_ground_eqc_map.end();
+}
+
+bool ConjectureGenerator::isGroundTerm( TNode n ) {
+ return std::find( d_ground_terms.begin(), d_ground_terms.end(), n )!=d_ground_terms.end();
+}
+
+bool ConjectureGenerator::needsCheck( Theory::Effort e ) {
+ return e==Theory::EFFORT_FULL;
+}
+
+bool ConjectureGenerator::hasEnumeratedUf( Node n ) {
+ if( options::conjectureGenGtEnum()>0 ){
+ std::map< Node, bool >::iterator it = d_uf_enum.find( n.getOperator() );
+ if( it==d_uf_enum.end() ){
+ d_uf_enum[n.getOperator()] = true;
+ std::vector< Node > lem;
+ getEnumeratePredUfTerm( n, options::conjectureGenGtEnum(), lem );
+ if( !lem.empty() ){
+ for( unsigned j=0; j<lem.size(); j++ ){
+ d_quantEngine->addLemma( lem[j], false );
+ d_hasAddedLemma = true;
+ }
+ return false;
+ }
+ }
+ }
+ return true;
+}
+
+void ConjectureGenerator::reset_round( Theory::Effort e ) {
+
+}
+
+void ConjectureGenerator::check( Theory::Effort e, unsigned quant_e ) {
+ if( quant_e==QuantifiersEngine::QEFFORT_STANDARD ){
+ d_fullEffortCount++;
+ if( d_fullEffortCount%optFullCheckFrequency()==0 ){
+ d_hasAddedLemma = false;
+ d_tge.d_cg = this;
+ double clSet = 0;
+ if( Trace.isOn("sg-engine") ){
+ clSet = double(clock())/double(CLOCKS_PER_SEC);
+ Trace("sg-engine") << "---Conjecture Engine Round, effort = " << e << "---" << std::endl;
+ }
+ eq::EqualityEngine * ee = getEqualityEngine();
+
+ Trace("sg-proc") << "Get eq classes..." << std::endl;
+ d_op_arg_index.clear();
+ d_ground_eqc_map.clear();
+ d_bool_eqc[0] = Node::null();
+ d_bool_eqc[1] = Node::null();
+ std::vector< TNode > eqcs;
+ d_em.clear();
+ eq::EqClassesIterator eqcs_i = eq::EqClassesIterator( ee );
+ while( !eqcs_i.isFinished() ){
+ TNode r = (*eqcs_i);
+ eqcs.push_back( r );
+ if( r.getType().isBoolean() ){
+ if( areEqual( r, getTermDatabase()->d_true ) ){
+ d_ground_eqc_map[r] = getTermDatabase()->d_true;
+ d_bool_eqc[0] = r;
+ }else if( areEqual( r, getTermDatabase()->d_false ) ){
+ d_ground_eqc_map[r] = getTermDatabase()->d_false;
+ d_bool_eqc[1] = r;
+ }
+ }
+ d_em[r] = eqcs.size();
+ eq::EqClassIterator ieqc_i = eq::EqClassIterator( r, ee );
+ while( !ieqc_i.isFinished() ){
+ TNode n = (*ieqc_i);
+ if( isHandledTerm( n ) ){
+ d_op_arg_index[r].addTerm( this, n );
+ }
+ ++ieqc_i;
+ }
+ ++eqcs_i;
+ }
+ Assert( !d_bool_eqc[0].isNull() );
+ Assert( !d_bool_eqc[1].isNull() );
+ d_urelevant_terms.clear();
+ Trace("sg-proc") << "...done get eq classes" << std::endl;
+
+ Trace("sg-proc") << "Determine ground EQC..." << std::endl;
+ bool success;
+ do{
+ success = false;
+ for( unsigned i=0; i<eqcs.size(); i++ ){
+ TNode r = eqcs[i];
+ if( d_ground_eqc_map.find( r )==d_ground_eqc_map.end() ){
+ std::vector< TNode > args;
+ Trace("sg-pat-debug") << "******* Get ground term for " << r << std::endl;
+ Node n;
+ if( getTermDatabase()->isInductionTerm( r ) ){
+ n = d_op_arg_index[r].getGroundTerm( this, args );
+ }else{
+ n = r;
+ }
+ if( !n.isNull() ){
+ Trace("sg-pat") << "Ground term for eqc " << r << " : " << std::endl;
+ Trace("sg-pat") << " " << n << std::endl;
+ d_ground_eqc_map[r] = n;
+ success = true;
+ }else{
+ Trace("sg-pat-debug") << "...could not find ground term." << std::endl;
+ }
+ }
+ }
+ }while( success );
+ //also get ground terms
+ d_ground_terms.clear();
+ for( unsigned i=0; i<eqcs.size(); i++ ){
+ TNode r = eqcs[i];
+ d_op_arg_index[r].getGroundTerms( this, d_ground_terms );
+ }
+ Trace("sg-proc") << "...done determine ground EQC" << std::endl;
+
+ //debug printing
+ if( Trace.isOn("sg-gen-eqc") ){
+ for( unsigned i=0; i<eqcs.size(); i++ ){
+ TNode r = eqcs[i];
+ //print out members
+ bool firstTime = true;
+ bool isFalse = areEqual( r, getTermDatabase()->d_false );
+ eq::EqClassIterator eqc_i = eq::EqClassIterator( r, ee );
+ while( !eqc_i.isFinished() ){
+ TNode n = (*eqc_i);
+ if( !n.getAttribute(NoMatchAttribute()) && ( n.getKind()!=EQUAL || isFalse ) ){
+ if( firstTime ){
+ Trace("sg-gen-eqc") << "e" << d_em[r] << " : { " << std::endl;
+ firstTime = false;
+ }
+ if( n.hasOperator() ){
+ Trace("sg-gen-eqc") << " (" << n.getOperator();
+ getTermDatabase()->computeArgReps( n );
+ for( unsigned i=0; i<getTermDatabase()->d_arg_reps[n].size(); i++ ){
+ Trace("sg-gen-eqc") << " e" << d_em[getTermDatabase()->d_arg_reps[n][i]];
+ }
+ Trace("sg-gen-eqc") << ") :: " << n << std::endl;
+ }else{
+ Trace("sg-gen-eqc") << " " << n << std::endl;
+ }
+ }
+ ++eqc_i;
+ }
+ if( !firstTime ){
+ Trace("sg-gen-eqc") << "}" << std::endl;
+ //print out ground term
+ std::map< TNode, Node >::iterator it = d_ground_eqc_map.find( r );
+ if( it!=d_ground_eqc_map.end() ){
+ Trace("sg-gen-eqc") << "- Ground term : " << it->second << std::endl;
+ }
+ }
+ }
+ }
+
+ Trace("sg-proc") << "Compute relevant eqc..." << std::endl;
+ d_tge.d_relevant_eqc[0].clear();
+ d_tge.d_relevant_eqc[1].clear();
+ for( unsigned i=0; i<eqcs.size(); i++ ){
+ TNode r = eqcs[i];
+ std::map< TNode, Node >::iterator it = d_ground_eqc_map.find( r );
+ unsigned index = 1;
+ if( it==d_ground_eqc_map.end() ){
+ index = 0;
+ }
+ //based on unproven conjectures? TODO
+ d_tge.d_relevant_eqc[index].push_back( r );
+ }
+ Trace("sg-gen-tg-debug") << "Initial relevant eqc : ";
+ for( unsigned i=0; i<d_tge.d_relevant_eqc[0].size(); i++ ){
+ Trace("sg-gen-tg-debug") << "e" << d_em[d_tge.d_relevant_eqc[0][i]] << " ";
+ }
+ Trace("sg-gen-tg-debug") << std::endl;
+ Trace("sg-proc") << "...done compute relevant eqc" << std::endl;
+
+
+ Trace("sg-proc") << "Collect signature information..." << std::endl;
+ d_tge.collectSignatureInformation();
+ if( d_hasAddedLemma ){
+ Trace("sg-proc") << "...added enumeration lemmas." << std::endl;
+ }
+ Trace("sg-proc") << "...done collect signature information" << std::endl;
+
+
+
+ Trace("sg-proc") << "Build theorem index..." << std::endl;
+ d_ue_canon.clear();
+ d_thm_index.clear();
+ std::vector< Node > provenConj;
+ quantifiers::FirstOrderModel* m = d_quantEngine->getModel();
+ for( int i=0; i<m->getNumAssertedQuantifiers(); i++ ){
+ Node q = m->getAssertedQuantifier( i );
+ Trace("thm-db-debug") << "Is " << q << " a relevant theorem?" << std::endl;
+ Node conjEq;
+ if( q[1].getKind()==EQUAL ){
+ bool isSubsume = false;
+ bool inEe = false;
+ for( unsigned r=0; r<2; r++ ){
+ TNode nl = q[1][r==0 ? 0 : 1];
+ TNode nr = q[1][r==0 ? 1 : 0];
+ Node eq = nl.eqNode( nr );
+ if( r==1 || std::find( d_conjectures.begin(), d_conjectures.end(), q )==d_conjectures.end() ){
+ //must make it canonical
+ std::map< TypeNode, unsigned > var_count;
+ std::map< TNode, TNode > subs;
+ Trace("sg-proc-debug") << "get canonical " << eq << std::endl;
+ eq = getCanonicalTerm( eq, var_count, subs );
+ }
+ if( !eq.isNull() ){
+ if( r==0 ){
+ inEe = d_ee_conjectures.find( q[1] )!=d_ee_conjectures.end();
+ if( !inEe ){
+ //add to universal equality engine
+ Node nl = getUniversalRepresentative( eq[0], true );
+ Node nr = getUniversalRepresentative( eq[1], true );
+ if( areUniversalEqual( nl, nr ) ){
+ isSubsume = true;
+ //set inactive (will be ignored by other modules)
+ d_quantEngine->getModel()->setQuantifierActive( q, false );
+ }else{
+ Node exp;
+ d_ee_conjectures[q[1]] = true;
+ d_uequalityEngine.assertEquality( nl.eqNode( nr ), true, exp );
+ }
+ }
+ Trace("sg-conjecture") << "*** CONJECTURE : currently proven" << (isSubsume ? " and subsumed" : "");
+ Trace("sg-conjecture") << " : " << q[1] << std::endl;
+ provenConj.push_back( q );
+ }
+ if( !isSubsume ){
+ Trace("thm-db-debug") << "Adding theorem to database " << eq[0] << " == " << eq[1] << std::endl;
+ d_thm_index.addTheorem( eq[0], eq[1] );
+ }else{
+ break;
+ }
+ }else{
+ break;
+ }
+ }
+ }
+ }
+ //examine status of other conjectures
+ for( unsigned i=0; i<d_conjectures.size(); i++ ){
+ Node q = d_conjectures[i];
+ if( std::find( provenConj.begin(), provenConj.end(), q )==provenConj.end() ){
+ //check each skolem variable
+ bool disproven = true;
+ //std::vector< Node > sk;
+ //getTermDatabase()->getSkolemConstants( q, sk, true );
+ Trace("sg-conjecture") << " CONJECTURE : ";
+ std::vector< Node > ce;
+ for( unsigned j=0; j<getTermDatabase()->d_skolem_constants[q].size(); j++ ){
+ TNode k = getTermDatabase()->d_skolem_constants[q][j];
+ TNode rk = getRepresentative( k );
+ std::map< TNode, Node >::iterator git = d_ground_eqc_map.find( rk );
+ //check if it is a ground term
+ if( git==d_ground_eqc_map.end() ){
+ Trace("sg-conjecture") << "ACTIVE : " << q;
+ if( Trace.isOn("sg-gen-eqc") ){
+ Trace("sg-conjecture") << " { ";
+ for( unsigned k=0; k<getTermDatabase()->d_skolem_constants[q].size(); k++ ){ Trace("sg-conjecture") << getTermDatabase()->d_skolem_constants[q][k] << ( j==k ? "*" : "" ) << " "; }
+ Trace("sg-conjecture") << "}";
+ }
+ Trace("sg-conjecture") << std::endl;
+ disproven = false;
+ break;
+ }else{
+ ce.push_back( git->second );
+ }
+ }
+ if( disproven ){
+ Trace("sg-conjecture") << "disproven : " << q << " : ";
+ for( unsigned i=0; i<ce.size(); i++ ){
+ Trace("sg-conjecture") << q[0][i] << " -> " << ce[i] << " ";
+ }
+ Trace("sg-conjecture") << std::endl;
+ }
+ }
+ }
+ Trace("thm-db") << "Theorem database is : " << std::endl;
+ d_thm_index.debugPrint( "thm-db" );
+ Trace("thm-db") << std::endl;
+ Trace("sg-proc") << "...done build theorem index" << std::endl;
+
+
+ //clear patterns
+ d_patterns.clear();
+ d_pattern_var_id.clear();
+ d_pattern_var_duplicate.clear();
+ d_pattern_is_normal.clear();
+ d_pattern_is_relevant.clear();
+ d_pattern_fun_id.clear();
+ d_pattern_fun_sum.clear();
+ d_rel_patterns.clear();
+ d_rel_pattern_var_sum.clear();
+ d_rel_pattern_typ_index.clear();
+ d_rel_pattern_subs_index.clear();
+
+ unsigned rel_term_count = 0;
+ std::map< TypeNode, unsigned > rt_var_max;
+ std::vector< TypeNode > rt_types;
+ std::map< TypeNode, std::map< int, std::vector< Node > > > conj_lhs;
+ unsigned addedLemmas = 0;
+ for( unsigned depth=1; depth<=3; depth++ ){
+ Trace("sg-proc") << "Generate relevant LHS at depth " << depth << "..." << std::endl;
+ Trace("sg-rel-term") << "Relevant terms of depth " << depth << " : " << std::endl;
+ //set up environment
+ d_tge.d_var_id.clear();
+ d_tge.d_var_limit.clear();
+ d_tge.reset( depth, true, TypeNode::null() );
+ while( d_tge.getNextTerm() ){
+ //construct term
+ Node nn = d_tge.getTerm();
+ if( !options::conjectureFilterCanonical() || considerTermCanon( nn, true ) ){
+ rel_term_count++;
+ Trace("sg-rel-term") << "*** Relevant term : ";
+ d_tge.debugPrint( "sg-rel-term", "sg-rel-term-debug2" );
+ Trace("sg-rel-term") << std::endl;
+
+ for( unsigned r=0; r<2; r++ ){
+ Trace("sg-rel-term-debug") << "...from equivalence classes (" << r << ") : ";
+ int index = d_tge.d_ccand_eqc[r].size()-1;
+ for( unsigned j=0; j<d_tge.d_ccand_eqc[r][index].size(); j++ ){
+ Trace("sg-rel-term-debug") << "e" << d_em[d_tge.d_ccand_eqc[r][index][j]] << " ";
+ }
+ Trace("sg-rel-term-debug") << std::endl;
+ }
+ TypeNode tnn = nn.getType();
+ Trace("sg-gen-tg-debug") << "...term is " << nn << std::endl;
+ conj_lhs[tnn][depth].push_back( nn );
+
+ //add information about pattern
+ Trace("sg-gen-tg-debug") << "Collect pattern information..." << std::endl;
+ Assert( std::find( d_rel_patterns[tnn].begin(), d_rel_patterns[tnn].end(), nn )==d_rel_patterns[tnn].end() );
+ d_rel_patterns[tnn].push_back( nn );
+ //build information concerning the variables in this pattern
+ unsigned sum = 0;
+ std::map< TypeNode, unsigned > typ_to_subs_index;
+ std::vector< TNode > gsubs_vars;
+ for( std::map< TypeNode, unsigned >::iterator it = d_tge.d_var_id.begin(); it != d_tge.d_var_id.end(); ++it ){
+ if( it->second>0 ){
+ typ_to_subs_index[it->first] = sum;
+ sum += it->second;
+ for( unsigned i=0; i<it->second; i++ ){
+ gsubs_vars.push_back( getFreeVar( it->first, i ) );
+ }
+ }
+ }
+ d_rel_pattern_var_sum[nn] = sum;
+ //register the pattern
+ registerPattern( nn, tnn );
+ Assert( d_pattern_is_normal[nn] );
+ Trace("sg-gen-tg-debug") << "...done collect pattern information" << std::endl;
+
+ //record information about types
+ Trace("sg-gen-tg-debug") << "Collect type information..." << std::endl;
+ PatternTypIndex * pti = &d_rel_pattern_typ_index;
+ for( std::map< TypeNode, unsigned >::iterator it = d_tge.d_var_id.begin(); it != d_tge.d_var_id.end(); ++it ){
+ pti = &pti->d_children[it->first][it->second];
+ //record maximum
+ if( rt_var_max.find( it->first )==rt_var_max.end() || it->second>rt_var_max[it->first] ){
+ rt_var_max[it->first] = it->second;
+ }
+ }
+ if( std::find( rt_types.begin(), rt_types.end(), tnn )==rt_types.end() ){
+ rt_types.push_back( tnn );
+ }
+ pti->d_terms.push_back( nn );
+ Trace("sg-gen-tg-debug") << "...done collect type information" << std::endl;
+
+ Trace("sg-gen-tg-debug") << "Build substitutions for ground EQC..." << std::endl;
+ std::vector< TNode > gsubs_terms;
+ gsubs_terms.resize( gsubs_vars.size() );
+ int index = d_tge.d_ccand_eqc[1].size()-1;
+ for( unsigned j=0; j<d_tge.d_ccand_eqc[1][index].size(); j++ ){
+ TNode r = d_tge.d_ccand_eqc[1][index][j];
+ Trace("sg-rel-term-debug") << " Matches for e" << d_em[r] << ", which is ground term " << d_ground_eqc_map[r] << ":" << std::endl;
+ std::map< TypeNode, std::map< unsigned, TNode > > subs;
+ std::map< TNode, bool > rev_subs;
+ //only get ground terms
+ unsigned mode = 2;
+ d_tge.resetMatching( r, mode );
+ while( d_tge.getNextMatch( r, subs, rev_subs ) ){
+ //we will be building substitutions
+ bool firstTime = true;
+ for( std::map< TypeNode, std::map< unsigned, TNode > >::iterator it = subs.begin(); it != subs.end(); ++it ){
+ unsigned tindex = typ_to_subs_index[it->first];
+ for( std::map< unsigned, TNode >::iterator it2 = it->second.begin(); it2 != it->second.end(); ++it2 ){
+ if( !firstTime ){
+ Trace("sg-rel-term-debug") << ", ";
+ }else{
+ firstTime = false;
+ Trace("sg-rel-term-debug") << " ";
+ }
+ Trace("sg-rel-term-debug") << it->first << ":x" << it2->first << " -> " << it2->second;
+ Assert( tindex+it2->first<gsubs_terms.size() );
+ gsubs_terms[tindex+it2->first] = it2->second;
+ }
+ }
+ Trace("sg-rel-term-debug") << std::endl;
+ d_rel_pattern_subs_index[nn].addSubstitution( r, gsubs_vars, gsubs_terms );
+ }
+ }
+ Trace("sg-gen-tg-debug") << "...done build substitutions for ground EQC" << std::endl;
+ }else{
+ Trace("sg-gen-tg-debug") << "> not canonical : " << nn << std::endl;
+ }
+ }
+ Trace("sg-proc") << "...done generate terms at depth " << depth << std::endl;
+ Trace("sg-stats") << "--------> Total LHS of depth " << depth << " : " << rel_term_count << std::endl;
+ //Trace("conjecture-count") << "Total LHS of depth " << depth << " : " << conj_lhs[depth].size() << std::endl;
+
+ /* test...
+ for( unsigned i=0; i<rt_types.size(); i++ ){
+ Trace("sg-term-enum") << "Term enumeration for " << rt_types[i] << " : " << std::endl;
+ Trace("sg-term-enum") << "Ground term : " << rt_types[i].mkGroundTerm() << std::endl;
+ for( unsigned j=0; j<150; j++ ){
+ Trace("sg-term-enum") << " " << getEnumerateTerm( rt_types[i], j ) << std::endl;
+ }
+ }
+ */
+
+ //consider types from relevant terms
+ for( unsigned rdepth=0; rdepth<=depth; rdepth++ ){
+ //set up environment
+ d_tge.d_var_id.clear();
+ d_tge.d_var_limit.clear();
+ for( std::map< TypeNode, unsigned >::iterator it = rt_var_max.begin(); it != rt_var_max.end(); ++it ){
+ d_tge.d_var_id[ it->first ] = it->second;
+ d_tge.d_var_limit[ it->first ] = it->second;
+ }
+ std::random_shuffle( rt_types.begin(), rt_types.end() );
+ std::map< TypeNode, std::vector< Node > > conj_rhs;
+ for( unsigned i=0; i<rt_types.size(); i++ ){
+
+ Trace("sg-proc") << "Generate relevant RHS terms of type " << rt_types[i] << " at depth " << rdepth << "..." << std::endl;
+ d_tge.reset( rdepth, false, rt_types[i] );
+
+ while( d_tge.getNextTerm() ){
+ Node rhs = d_tge.getTerm();
+ if( considerTermCanon( rhs, false ) ){
+ Trace("sg-rel-prop") << "Relevant RHS : " << rhs << std::endl;
+ //register pattern
+ Assert( rhs.getType()==rt_types[i] );
+ registerPattern( rhs, rt_types[i] );
+ if( rdepth<depth ){
+ //consider against all LHS at depth
+ for( unsigned j=0; j<conj_lhs[rt_types[i]][depth].size(); j++ ){
+ processCandidateConjecture( conj_lhs[rt_types[i]][depth][j], rhs, depth, rdepth );
+ }
+ }else{
+ conj_rhs[rt_types[i]].push_back( rhs );
+ }
+ }
+ }
+ }
+ flushWaitingConjectures( addedLemmas, depth, rdepth );
+ //consider against all LHS up to depth
+ if( rdepth==depth ){
+ for( unsigned lhs_depth = 1; lhs_depth<=depth; lhs_depth++ ){
+ if( (int)addedLemmas<options::conjectureGenPerRound() ){
+ Trace("sg-proc") << "Consider conjectures at depth (" << lhs_depth << ", " << rdepth << ")..." << std::endl;
+ for( std::map< TypeNode, std::vector< Node > >::iterator it = conj_rhs.begin(); it != conj_rhs.end(); ++it ){
+ for( unsigned j=0; j<it->second.size(); j++ ){
+ for( unsigned k=0; k<conj_lhs[it->first][lhs_depth].size(); k++ ){
+ processCandidateConjecture( conj_lhs[it->first][lhs_depth][k], it->second[j], lhs_depth, rdepth );
+ }
+ }
+ }
+ flushWaitingConjectures( addedLemmas, lhs_depth, depth );
+ }
+ }
+ }
+ if( (int)addedLemmas>=options::conjectureGenPerRound() ){
+ break;
+ }
+ }
+ if( (int)addedLemmas>=options::conjectureGenPerRound() ){
+ break;
+ }
+ }
+
+ if( Trace.isOn("thm-ee") ){
+ Trace("thm-ee") << "Universal equality engine is : " << std::endl;
+ eq::EqClassesIterator ueqcs_i = eq::EqClassesIterator( &d_uequalityEngine );
+ while( !ueqcs_i.isFinished() ){
+ TNode r = (*ueqcs_i);
+ bool firstTime = true;
+ TNode rr = getUniversalRepresentative( r );
+ Trace("thm-ee") << " " << rr;
+ Trace("thm-ee") << " : { ";
+ eq::EqClassIterator ueqc_i = eq::EqClassIterator( r, &d_uequalityEngine );
+ while( !ueqc_i.isFinished() ){
+ TNode n = (*ueqc_i);
+ if( rr!=n ){
+ if( firstTime ){
+ Trace("thm-ee") << std::endl;
+ firstTime = false;
+ }
+ Trace("thm-ee") << " " << n << std::endl;
+ }
+ ++ueqc_i;
+ }
+ if( !firstTime ){ Trace("thm-ee") << " "; }
+ Trace("thm-ee") << "}" << std::endl;
+ ++ueqcs_i;
+ }
+ Trace("thm-ee") << std::endl;
+ }
+ if( Trace.isOn("sg-engine") ){
+ double clSet2 = double(clock())/double(CLOCKS_PER_SEC);
+ Trace("sg-engine") << "Finished conjecture generator, time = " << (clSet2-clSet) << std::endl;
+ }
+ }
+ }
+}
+
+unsigned ConjectureGenerator::flushWaitingConjectures( unsigned& addedLemmas, int ldepth, int rdepth ) {
+ if( !d_waiting_conjectures_lhs.empty() ){
+ Trace("sg-proc") << "Generated " << d_waiting_conjectures_lhs.size() << " conjectures at depth " << ldepth << "/" << rdepth << "." << std::endl;
+ if( !optStatsOnly() && (int)addedLemmas<options::conjectureGenPerRound() ){
+ std::vector< unsigned > indices;
+ for( unsigned i=0; i<d_waiting_conjectures_lhs.size(); i++ ){
+ indices.push_back( i );
+ }
+ bool doSort = false;
+ if( doSort ){
+ //sort them based on score
+ sortConjectureScore scs;
+ scs.d_scores.insert( scs.d_scores.begin(), d_waiting_conjectures_score.begin(), d_waiting_conjectures_score.end() );
+ std::sort( indices.begin(), indices.end(), scs );
+ }
+ if( doSort && d_waiting_conjectures_score[indices[0]]<optFilterScoreThreshold() ){
+ //do splitting on demand (TODO)
+
+ }else{
+ for( unsigned i=0; i<indices.size(); i++ ){
+ //if( d_waiting_conjectures_score[indices[i]]<optFilterScoreThreshold() ){
+ if( d_waiting_conjectures_score[indices[i]]>=optFilterScoreThreshold() ){
+ //we have determined a relevant subgoal
+ Node lhs = d_waiting_conjectures_lhs[indices[i]];
+ Node rhs = d_waiting_conjectures_rhs[indices[i]];
+ if( options::conjectureFilterCanonical() && ( getUniversalRepresentative( lhs )!=lhs || getUniversalRepresentative( rhs )!=rhs ) ){
+ //skip
+ }else{
+ Trace("sg-engine") << "*** Consider conjecture : " << lhs << " == " << rhs << std::endl;
+ Trace("sg-engine-debug") << " score : " << d_waiting_conjectures_score[indices[i]] << std::endl;
+ std::vector< Node > bvs;
+ for( std::map< TypeNode, unsigned >::iterator it = d_pattern_var_id[lhs].begin(); it != d_pattern_var_id[lhs].end(); ++it ){
+ for( unsigned i=0; i<=it->second; i++ ){
+ bvs.push_back( getFreeVar( it->first, i ) );
+ }
+ }
+ Node rsg;
+ if( !bvs.empty() ){
+ Node bvl = NodeManager::currentNM()->mkNode( BOUND_VAR_LIST, bvs );
+ rsg = NodeManager::currentNM()->mkNode( FORALL, bvl, lhs.eqNode( rhs ) );
+ }else{
+ rsg = lhs.eqNode( rhs );
+ }
+ rsg = Rewriter::rewrite( rsg );
+ d_conjectures.push_back( rsg );
+ d_eq_conjectures[lhs].push_back( rhs );
+ d_eq_conjectures[rhs].push_back( lhs );
+
+ Node lem = NodeManager::currentNM()->mkNode( OR, rsg.negate(), rsg );
+ d_quantEngine->addLemma( lem, false );
+ d_quantEngine->addRequirePhase( rsg, false );
+ addedLemmas++;
+ if( (int)addedLemmas>=options::conjectureGenPerRound() ){
+ break;
+ }
+ }
+ }else{
+ if( doSort ){
+ break;
+ }
+ }
+ }
+ }
+ Trace("sg-proc") << "...have now added " << addedLemmas << " conjecture lemmas." << std::endl;
+ }
+ d_waiting_conjectures_lhs.clear();
+ d_waiting_conjectures_rhs.clear();
+ d_waiting_conjectures_score.clear();
+ d_waiting_conjectures.clear();
+ }
+ return addedLemmas;
+}
+
+void ConjectureGenerator::registerQuantifier( Node q ) {
+
+}
+
+void ConjectureGenerator::assertNode( Node n ) {
+
+}
+
+bool ConjectureGenerator::considerTermCanon( Node ln, bool genRelevant ){
+ if( !ln.isNull() ){
+ //do not consider if it is non-canonical, and either:
+ // (1) we are not generating relevant terms, or
+ // (2) its canonical form is a generalization.
+ TNode lnr = getUniversalRepresentative( ln, true );
+ if( lnr==ln ){
+ markReportedCanon( ln );
+ }else if( !genRelevant || isGeneralization( lnr, ln ) ){
+ Trace("sg-gen-consider-term") << "Do not consider term, " << ln << " is not canonical representation (which is " << lnr << ")." << std::endl;
+ return false;
+ }
+ }
+ Trace("sg-gen-tg-debug") << "Will consider term canon " << ln << std::endl;
+ Trace("sg-gen-consider-term-debug") << std::endl;
+ return true;
+}
+
+unsigned ConjectureGenerator::collectFunctions( TNode opat, TNode pat, std::map< TNode, unsigned >& funcs,
+ std::map< TypeNode, unsigned >& mnvn, std::map< TypeNode, unsigned >& mxvn ){
+ if( pat.hasOperator() ){
+ funcs[pat.getOperator()]++;
+ if( !d_tge.isRelevantFunc( pat.getOperator() ) ){
+ d_pattern_is_relevant[opat] = false;
+ }
+ unsigned sum = 1;
+ for( unsigned i=0; i<pat.getNumChildren(); i++ ){
+ sum += collectFunctions( opat, pat[i], funcs, mnvn, mxvn );
+ }
+ return sum;
+ }else{
+ Assert( pat.getNumChildren()==0 );
+ funcs[pat]++;
+ //for variables
+ if( pat.getKind()==BOUND_VARIABLE ){
+ if( funcs[pat]>1 ){
+ //duplicate variable
+ d_pattern_var_duplicate[opat]++;
+ }else{
+ //check for max/min
+ TypeNode tn = pat.getType();
+ unsigned vn = d_free_var_num[pat];
+ std::map< TypeNode, unsigned >::iterator it = mnvn.find( tn );
+ if( it!=mnvn.end() ){
+ if( vn<it->second ){
+ d_pattern_is_normal[opat] = false;
+ mnvn[tn] = vn;
+ }else if( vn>mxvn[tn] ){
+ if( vn!=mxvn[tn]+1 ){
+ d_pattern_is_normal[opat] = false;
+ }
+ mxvn[tn] = vn;
+ }
+ }else{
+ //first variable of this type
+ mnvn[tn] = vn;
+ mxvn[tn] = vn;
+ }
+ }
+ }else{
+ d_pattern_is_relevant[opat] = false;
+ }
+ return 1;
+ }
+}
+
+void ConjectureGenerator::registerPattern( Node pat, TypeNode tpat ) {
+ if( std::find( d_patterns[tpat].begin(), d_patterns[tpat].end(), pat )==d_patterns[tpat].end() ){
+ d_patterns[TypeNode::null()].push_back( pat );
+ d_patterns[tpat].push_back( pat );
+
+ Assert( d_pattern_fun_id.find( pat )==d_pattern_fun_id.end() );
+ Assert( d_pattern_var_id.find( pat )==d_pattern_var_id.end() );
+
+ //collect functions
+ std::map< TypeNode, unsigned > mnvn;
+ d_pattern_fun_sum[pat] = collectFunctions( pat, pat, d_pattern_fun_id[pat], mnvn, d_pattern_var_id[pat] );
+ if( d_pattern_is_normal.find( pat )==d_pattern_is_normal.end() ){
+ d_pattern_is_normal[pat] = true;
+ }
+ if( d_pattern_is_relevant.find( pat )==d_pattern_is_relevant.end() ){
+ d_pattern_is_relevant[pat] = true;
+ }
+ }
+}
+
+bool ConjectureGenerator::isGeneralization( TNode patg, TNode pat, std::map< TNode, TNode >& subs ) {
+ if( patg.getKind()==BOUND_VARIABLE ){
+ std::map< TNode, TNode >::iterator it = subs.find( patg );
+ if( it!=subs.end() ){
+ return it->second==pat;
+ }else{
+ subs[patg] = pat;
+ return true;
+ }
+ }else{
+ Assert( patg.hasOperator() );
+ if( !pat.hasOperator() || patg.getOperator()!=pat.getOperator() ){
+ return false;
+ }else{
+ Assert( patg.getNumChildren()==pat.getNumChildren() );
+ for( unsigned i=0; i<patg.getNumChildren(); i++ ){
+ if( !isGeneralization( patg[i], pat[i], subs ) ){
+ return false;
+ }
+ }
+ return true;
+ }
+ }
+}
+
+int ConjectureGenerator::calculateGeneralizationDepth( TNode n, std::vector< TNode >& fv ) {
+ if( n.getKind()==BOUND_VARIABLE ){
+ if( std::find( fv.begin(), fv.end(), n )==fv.end() ){
+ fv.push_back( n );
+ return 0;
+ }else{
+ return 1;
+ }
+ }else{
+ int depth = 1;
+ for( unsigned i=0; i<n.getNumChildren(); i++ ){
+ depth += calculateGeneralizationDepth( n[i], fv );
+ }
+ return depth;
+ }
+}
+
+Node ConjectureGenerator::getEnumerateTerm( TypeNode tn, unsigned index ) {
+ std::map< TypeNode, unsigned >::iterator it = d_typ_enum_map.find( tn );
+ unsigned teIndex;
+ if( it==d_typ_enum_map.end() ){
+ teIndex = (int)d_typ_enum.size();
+ d_typ_enum_map[tn] = teIndex;
+ d_typ_enum.push_back( TypeEnumerator(tn) );
+ }else{
+ teIndex = it->second;
+ }
+ while( index>=d_enum_terms[tn].size() ){
+ if( d_typ_enum[teIndex].isFinished() ){
+ return Node::null();
+ }
+ d_enum_terms[tn].push_back( *d_typ_enum[teIndex] );
+ ++d_typ_enum[teIndex];
+ }
+ return d_enum_terms[tn][index];
+}
+
+
+Node ConjectureGenerator::getPredicateForType( TypeNode tn ) {
+ std::map< TypeNode, Node >::iterator it = d_typ_pred.find( tn );
+ if( it==d_typ_pred.end() ){
+ TypeNode op_tn = NodeManager::currentNM()->mkFunctionType( tn, NodeManager::currentNM()->booleanType() );
+ Node op = NodeManager::currentNM()->mkSkolem( "PE", op_tn, "was created by conjecture ground term enumerator." );
+ d_typ_pred[tn] = op;
+ return op;
+ }else{
+ return it->second;
+ }
+}
+
+void ConjectureGenerator::getEnumerateUfTerm( Node n, unsigned num, std::vector< Node >& terms ) {
+ if( n.getNumChildren()>0 ){
+ std::vector< int > vec;
+ for( unsigned i=0; i<n.getNumChildren(); i++ ){
+ vec.push_back( 0 );
+ }
+ vec.pop_back();
+ int size_limit = 0;
+ int vec_sum = -1;
+ unsigned index = 0;
+ unsigned last_size = terms.size();
+ while( terms.size()<num ){
+ bool success = true;
+ if( vec_sum==-1 ){
+ vec_sum = 0;
+ vec.push_back( size_limit );
+ }else{
+ //see if we can iterate current
+ if( vec_sum<size_limit && !getEnumerateTerm( n[index].getType(), vec[index]+1 ).isNull() ){
+ vec[index]++;
+ vec_sum++;
+ vec.push_back( size_limit - vec_sum );
+ }else{
+ vec_sum -= vec[index];
+ vec[index] = 0;
+ index++;
+ if( index==n.getNumChildren() ){
+ success = false;
+ }
+ }
+ }
+ if( success ){
+ if( vec.size()==n.getNumChildren() ){
+ Node lc = getEnumerateTerm( n[vec.size()-1].getType(), vec[vec.size()-1] );
+ if( !lc.isNull() ){
+ for( unsigned i=0; i<vec.size(); i++ ){
+ Trace("sg-gt-enum-debug") << vec[i] << " ";
+ }
+ Trace("sg-gt-enum-debug") << " / " << size_limit << std::endl;
+ for( unsigned i=0; i<n.getNumChildren(); i++ ){
+ Trace("sg-gt-enum-debug") << n[i].getType() << " ";
+ }
+ Trace("sg-gt-enum-debug") << std::endl;
+ std::vector< Node > children;
+ children.push_back( n.getOperator() );
+ for( unsigned i=0; i<(vec.size()-1); i++ ){
+ Node nn = getEnumerateTerm( n[i].getType(), vec[i] );
+ Assert( !nn.isNull() );
+ Assert( nn.getType()==n[i].getType() );
+ children.push_back( nn );
+ }
+ children.push_back( lc );
+ Node n = NodeManager::currentNM()->mkNode( APPLY_UF, children );
+ Trace("sg-gt-enum") << "Ground term enumerate : " << n << std::endl;
+ terms.push_back( n );
+ }
+ vec.pop_back();
+ index = 0;
+ }
+ }else{
+ if( terms.size()>last_size ){
+ last_size = terms.size();
+ size_limit++;
+ for( unsigned i=0; i<vec.size(); i++ ){
+ vec[i] = 0;
+ }
+ vec_sum = -1;
+ }
+ }
+ }
+ }else{
+ terms.push_back( n );
+ }
+}
+
+void ConjectureGenerator::getEnumeratePredUfTerm( Node n, unsigned num, std::vector< Node >& terms ) {
+ std::vector< Node > uf_terms;
+ getEnumerateUfTerm( n, num, uf_terms );
+ Node p = getPredicateForType( n.getType() );
+ for( unsigned i=0; i<uf_terms.size(); i++ ){
+ terms.push_back( NodeManager::currentNM()->mkNode( APPLY_UF, p, uf_terms[i] ) );
+ }
+}
+
+void ConjectureGenerator::processCandidateConjecture( TNode lhs, TNode rhs, unsigned lhs_depth, unsigned rhs_depth ) {
+ int score = considerCandidateConjecture( lhs, rhs );
+ if( score>0 ){
+ Trace("sg-conjecture") << "* Candidate conjecture : " << lhs << " == " << rhs << std::endl;
+ Trace("sg-conjecture-debug") << " LHS, RHS generalization depth : " << lhs_depth << ", " << rhs_depth << std::endl;
+ Trace("sg-conjecture-debug") << " confirmed = " << d_subs_confirmCount << ", #witnesses range = " << d_subs_confirmWitnessRange.size() << "." << std::endl;
+ Trace("sg-conjecture-debug") << " #witnesses for ";
+ bool firstTime = true;
+ for( std::map< TNode, std::vector< TNode > >::iterator it = d_subs_confirmWitnessDomain.begin(); it != d_subs_confirmWitnessDomain.end(); ++it ){
+ if( !firstTime ){
+ Trace("sg-conjecture-debug") << ", ";
+ }
+ Trace("sg-conjecture-debug") << it->first << " : " << it->second.size();
+ //if( it->second.size()==1 ){
+ // Trace("sg-conjecture-debug") << " (" << it->second[0] << ")";
+ //}
+ Trace("sg-conjecture-debug2") << " (";
+ for( unsigned j=0; j<it->second.size(); j++ ){
+ if( j>0 ){ Trace("sg-conjecture-debug2") << " "; }
+ Trace("sg-conjecture-debug2") << d_ground_eqc_map[it->second[j]];
+ }
+ Trace("sg-conjecture-debug2") << ")";
+ firstTime = false;
+ }
+ Trace("sg-conjecture-debug") << std::endl;
+ Trace("sg-conjecture-debug") << " unknown = " << d_subs_unkCount << std::endl;
+ //Assert( getUniversalRepresentative( rhs )==rhs );
+ //Assert( getUniversalRepresentative( lhs )==lhs );
+ d_waiting_conjectures_lhs.push_back( lhs );
+ d_waiting_conjectures_rhs.push_back( rhs );
+ d_waiting_conjectures_score.push_back( score );
+ d_waiting_conjectures[lhs].push_back( rhs );
+ d_waiting_conjectures[rhs].push_back( lhs );
+ }
+}
+
+int ConjectureGenerator::considerCandidateConjecture( TNode lhs, TNode rhs ) {
+ Assert( lhs.getType()==rhs.getType() );
+
+ Trace("sg-cconj-debug") << "Consider candidate conjecture : " << lhs << " == " << rhs << "?" << std::endl;
+ if( lhs==rhs ){
+ Trace("sg-cconj-debug") << " -> trivial." << std::endl;
+ return -1;
+ }else{
+ if( lhs.getKind()==APPLY_CONSTRUCTOR && rhs.getKind()==APPLY_CONSTRUCTOR ){
+ Trace("sg-cconj-debug") << " -> irrelevant by syntactic analysis." << std::endl;
+ return -1;
+ }
+ //variables of LHS must subsume variables of RHS
+ for( std::map< TypeNode, unsigned >::iterator it = d_pattern_var_id[rhs].begin(); it != d_pattern_var_id[rhs].end(); ++it ){
+ std::map< TypeNode, unsigned >::iterator itl = d_pattern_var_id[lhs].find( it->first );
+ if( itl!=d_pattern_var_id[lhs].end() ){
+ if( itl->second<it->second ){
+ Trace("sg-cconj-debug") << " -> variables of sort " << it->first << " are not subsumed." << std::endl;
+ return -1;
+ }else{
+ Trace("sg-cconj-debug2") << " variables of sort " << it->first << " are : " << itl->second << " vs " << it->second << std::endl;
+ }
+ }else{
+ Trace("sg-cconj-debug") << " -> has no variables of sort " << it->first << "." << std::endl;
+ return -1;
+ }
+ }
+
+ //currently active conjecture?
+ std::map< Node, std::vector< Node > >::iterator iteq = d_eq_conjectures.find( lhs );
+ if( iteq!=d_eq_conjectures.end() ){
+ if( std::find( iteq->second.begin(), iteq->second.end(), rhs )!=iteq->second.end() ){
+ Trace("sg-cconj-debug") << " -> this conjecture is already active." << std::endl;
+ return -1;
+ }
+ }
+ //current a waiting conjecture?
+ std::map< Node, std::vector< Node > >::iterator itw = d_waiting_conjectures.find( lhs );
+ if( itw!=d_waiting_conjectures.end() ){
+ if( std::find( itw->second.begin(), itw->second.end(), rhs )!=itw->second.end() ){
+ Trace("sg-cconj-debug") << " -> already are considering this conjecture." << std::endl;
+ return -1;
+ }
+ }
+ //check if canonical representation (should be, but for efficiency this is not guarenteed)
+ //if( options::conjectureFilterCanonical() && ( getUniversalRepresentative( lhs )!=lhs || getUniversalRepresentative( rhs )!=rhs ) ){
+ // Trace("sg-cconj") << " -> after processing, not canonical." << std::endl;
+ // return -1;
+ //}
+
+ int score;
+ bool scoreSet = false;
+
+ Trace("sg-cconj") << "Consider possible candidate conjecture : " << lhs << " == " << rhs << "?" << std::endl;
+ //find witness for counterexample, if possible
+ if( options::conjectureFilterModel() ){
+ Assert( d_rel_pattern_var_sum.find( lhs )!=d_rel_pattern_var_sum.end() );
+ Trace("sg-cconj-debug") << "Notify substitutions over " << d_rel_pattern_var_sum[lhs] << " variables." << std::endl;
+ std::map< TNode, TNode > subs;
+ d_subs_confirmCount = 0;
+ d_subs_confirmWitnessRange.clear();
+ d_subs_confirmWitnessDomain.clear();
+ d_subs_unkCount = 0;
+ if( !d_rel_pattern_subs_index[lhs].notifySubstitutions( this, subs, rhs, d_rel_pattern_var_sum[lhs] ) ){
+ Trace("sg-cconj") << " -> found witness that falsifies the conjecture." << std::endl;
+ return -1;
+ }
+ //score is the minimum number of distinct substitutions for a variable
+ for( std::map< TNode, std::vector< TNode > >::iterator it = d_subs_confirmWitnessDomain.begin(); it != d_subs_confirmWitnessDomain.end(); ++it ){
+ int num = (int)it->second.size();
+ if( !scoreSet || num<score ){
+ score = num;
+ scoreSet = true;
+ }
+ }
+ if( !scoreSet ){
+ score = 0;
+ }
+ Trace("sg-cconj") << " confirmed = " << d_subs_confirmCount << ", #witnesses range = " << d_subs_confirmWitnessRange.size() << "." << std::endl;
+ for( std::map< TNode, std::vector< TNode > >::iterator it = d_subs_confirmWitnessDomain.begin(); it != d_subs_confirmWitnessDomain.end(); ++it ){
+ Trace("sg-cconj") << " #witnesses for " << it->first << " : " << it->second.size() << std::endl;
+ }
+ }else{
+ score = 0;
+ }
+
+ Trace("sg-cconj") << " -> SUCCESS." << std::endl;
+ Trace("sg-cconj") << " score : " << score << std::endl;
+
+ return score;
+ }
+}
+
+bool ConjectureGenerator::notifySubstitution( TNode glhs, std::map< TNode, TNode >& subs, TNode rhs ) {
+ if( Trace.isOn("sg-cconj-debug") ){
+ Trace("sg-cconj-debug") << "Ground eqc for LHS : " << glhs << ", based on substituion: " << std::endl;
+ for( std::map< TNode, TNode >::iterator it = subs.begin(); it != subs.end(); ++it ){
+ Assert( getRepresentative( it->second )==it->second );
+ Trace("sg-cconj-debug") << " " << it->first << " -> " << it->second << std::endl;
+ }
+ }
+ Trace("sg-cconj-debug") << "Evaluate RHS : : " << rhs << std::endl;
+ //get the representative of rhs with substitution subs
+ TNode grhs = getTermDatabase()->evaluateTerm( rhs, subs, true );
+ Trace("sg-cconj-debug") << "...done evaluating term, got : " << grhs << std::endl;
+ if( !grhs.isNull() ){
+ if( glhs!=grhs ){
+ Trace("sg-cconj-debug") << "Ground eqc for RHS : " << grhs << std::endl;
+ //check based on ground terms
+ std::map< TNode, Node >::iterator itl = d_ground_eqc_map.find( glhs );
+ if( itl!=d_ground_eqc_map.end() ){
+ std::map< TNode, Node >::iterator itr = d_ground_eqc_map.find( grhs );
+ if( itr!=d_ground_eqc_map.end() ){
+ Trace("sg-cconj-debug") << "We have ground terms " << itl->second << " and " << itr->second << "." << std::endl;
+ if( itl->second.isConst() && itr->second.isConst() ){
+ Trace("sg-cconj-debug") << "...disequal constants." << std::endl;
+ Trace("sg-cconj-witness") << " Witness of falsification : " << itl->second << " != " << itr->second << ", substutition is : " << std::endl;
+ for( std::map< TNode, TNode >::iterator it = subs.begin(); it != subs.end(); ++it ){
+ Trace("sg-cconj-witness") << " " << it->first << " -> " << it->second << std::endl;
+ }
+ return false;
+ }
+ }
+ }
+ }
+ Trace("sg-cconj-debug") << "RHS is identical." << std::endl;
+ bool isGroundSubs = true;
+ for( std::map< TNode, TNode >::iterator it = subs.begin(); it != subs.end(); ++it ){
+ std::map< TNode, Node >::iterator git = d_ground_eqc_map.find( it->second );
+ if( git==d_ground_eqc_map.end() ){
+ isGroundSubs = false;
+ break;
+ }
+ }
+ if( isGroundSubs ){
+ if( glhs==grhs ){
+ Trace("sg-cconj-witness") << " Witnessed " << glhs << " == " << grhs << ", substutition is : " << std::endl;
+ for( std::map< TNode, TNode >::iterator it = subs.begin(); it != subs.end(); ++it ){
+ Trace("sg-cconj-witness") << " " << it->first << " -> " << it->second << std::endl;
+ if( std::find( d_subs_confirmWitnessDomain[it->first].begin(), d_subs_confirmWitnessDomain[it->first].end(), it->second )==d_subs_confirmWitnessDomain[it->first].end() ){
+ d_subs_confirmWitnessDomain[it->first].push_back( it->second );
+ }
+ }
+ d_subs_confirmCount++;
+ if( std::find( d_subs_confirmWitnessRange.begin(), d_subs_confirmWitnessRange.end(), glhs )==d_subs_confirmWitnessRange.end() ){
+ d_subs_confirmWitnessRange.push_back( glhs );
+ }
+ }else{
+ if( optFilterUnknown() ){
+ Trace("sg-cconj-debug") << "...ground substitution giving terms that are neither equal nor disequal." << std::endl;
+ return false;
+ }
+ }
+ }
+ }else{
+ Trace("sg-cconj-debug") << "(could not ground eqc for RHS)." << std::endl;
+ }
+ return true;
+}
+
+
+
+
+
+
+void TermGenerator::reset( TermGenEnv * s, TypeNode tn ) {
+ Assert( d_children.empty() );
+ d_typ = tn;
+ d_status = 0;
+ d_status_num = 0;
+ d_children.clear();
+ Trace("sg-gen-tg-debug2") << "...add to context " << this << std::endl;
+ d_id = s->d_tg_id;
+ s->changeContext( true );
+}
+
+bool TermGenerator::getNextTerm( TermGenEnv * s, unsigned depth ) {
+ if( Trace.isOn("sg-gen-tg-debug2") ){
+ Trace("sg-gen-tg-debug2") << this << " getNextTerm depth " << depth << " : status = " << d_status << ", num = " << d_status_num;
+ if( d_status==5 ){
+ TNode f = s->getTgFunc( d_typ, d_status_num );
+ Trace("sg-gen-tg-debug2") << ", f = " << f;
+ Trace("sg-gen-tg-debug2") << ", #args = " << s->d_func_args[f].size();
+ Trace("sg-gen-tg-debug2") << ", childNum = " << d_status_child_num;
+ Trace("sg-gen-tg-debug2") << ", #children = " << d_children.size();
+ }
+ Trace("sg-gen-tg-debug2") << std::endl;
+ }
+
+ if( d_status==0 ){
+ d_status++;
+ if( !d_typ.isNull() ){
+ if( s->allowVar( d_typ ) ){
+ //allocate variable
+ d_status_num = s->d_var_id[d_typ];
+ s->addVar( d_typ );
+ Trace("sg-gen-tg-debug2") << this << " ...return unique var #" << d_status_num << std::endl;
+ return s->considerCurrentTerm() ? true : getNextTerm( s, depth );
+ }else{
+ //check allocating new variable
+ d_status++;
+ d_status_num = -1;
+ if( s->d_gen_relevant_terms ){
+ s->d_tg_gdepth++;
+ }
+ return getNextTerm( s, depth );
+ }
+ }else{
+ d_status = 4;
+ d_status_num = -1;
+ return getNextTerm( s, depth );
+ }
+ }else if( d_status==2 ){
+ //cleanup previous information
+ //if( d_status_num>=0 ){
+ // s->d_var_eq_tg[d_status_num].pop_back();
+ //}
+ //check if there is another variable
+ if( (d_status_num+1)<(int)s->getNumTgVars( d_typ ) ){
+ d_status_num++;
+ //we have equated two variables
+ //s->d_var_eq_tg[d_status_num].push_back( d_id );
+ Trace("sg-gen-tg-debug2") << this << "...consider other var #" << d_status_num << std::endl;
+ return s->considerCurrentTerm() ? true : getNextTerm( s, depth );
+ }else{
+ if( s->d_gen_relevant_terms ){
+ s->d_tg_gdepth--;
+ }
+ d_status++;
+ return getNextTerm( s, depth );
+ }
+ }else if( d_status==4 ){
+ d_status++;
+ if( depth>0 && (d_status_num+1)<(int)s->getNumTgFuncs( d_typ ) ){
+ d_status_num++;
+ d_status_child_num = 0;
+ Trace("sg-gen-tg-debug2") << this << "...consider function " << s->getTgFunc( d_typ, d_status_num ) << std::endl;
+ s->d_tg_gdepth++;
+ if( !s->considerCurrentTerm() ){
+ s->d_tg_gdepth--;
+ //don't consider this function
+ d_status--;
+ }else{
+ //we have decided on a function application
+ }
+ return getNextTerm( s, depth );
+ }else{
+ //do not choose function applications at depth 0
+ d_status++;
+ return getNextTerm( s, depth );
+ }
+ }else if( d_status==5 ){
+ //iterating over arguments
+ TNode f = s->getTgFunc( d_typ, d_status_num );
+ if( d_status_child_num<0 ){
+ //no more arguments
+ s->d_tg_gdepth--;
+ d_status--;
+ return getNextTerm( s, depth );
+ }else if( d_status_child_num==(int)s->d_func_args[f].size() ){
+ d_status_child_num--;
+ return s->considerCurrentTermCanon( d_id ) ? true : getNextTerm( s, depth );
+ //return true;
+ }else{
+ Assert( d_status_child_num<(int)s->d_func_args[f].size() );
+ if( d_status_child_num==(int)d_children.size() ){
+ d_children.push_back( s->d_tg_id );
+ Assert( s->d_tg_alloc.find( s->d_tg_id )==s->d_tg_alloc.end() );
+ s->d_tg_alloc[d_children[d_status_child_num]].reset( s, s->d_func_args[f][d_status_child_num] );
+ return getNextTerm( s, depth );
+ }else{
+ Assert( d_status_child_num+1==(int)d_children.size() );
+ if( s->d_tg_alloc[d_children[d_status_child_num]].getNextTerm( s, depth-1 ) ){
+ d_status_child_num++;
+ return getNextTerm( s, depth );
+ }else{
+ d_children.pop_back();
+ d_status_child_num--;
+ return getNextTerm( s, depth );
+ }
+ }
+ }
+ }else if( d_status==1 || d_status==3 ){
+ if( d_status==1 ){
+ s->removeVar( d_typ );
+ Assert( d_status_num==(int)s->d_var_id[d_typ] );
+ //check if there is only one feasible equivalence class. if so, don't make pattern any more specific.
+ //unsigned i = s->d_ccand_eqc[0].size()-1;
+ //if( s->d_ccand_eqc[0][i].size()==1 && s->d_ccand_eqc[1][i].empty() ){
+ // d_status = 6;
+ // return getNextTerm( s, depth );
+ //}
+ s->d_tg_gdepth++;
+ }
+ d_status++;
+ d_status_num = -1;
+ return getNextTerm( s, depth );
+ }else{
+ //clean up
+ Assert( d_children.empty() );
+ Trace("sg-gen-tg-debug2") << "...remove from context " << this << std::endl;
+ s->changeContext( false );
+ Assert( d_id==s->d_tg_id );
+ return false;
+ }
+}
+
+void TermGenerator::resetMatching( TermGenEnv * s, TNode eqc, unsigned mode ) {
+ d_match_status = 0;
+ d_match_status_child_num = 0;
+ d_match_children.clear();
+ d_match_children_end.clear();
+ d_match_mode = mode;
+ //if this term generalizes, it must generalize a non-ground term
+ //if( (d_match_mode & ( 1 << 2 ))!=0 && s->isGroundEqc( eqc ) && d_status==5 ){
+ // d_match_status = -1;
+ //}
+}
+
+bool TermGenerator::getNextMatch( TermGenEnv * s, TNode eqc, std::map< TypeNode, std::map< unsigned, TNode > >& subs, std::map< TNode, bool >& rev_subs ) {
+ if( d_match_status<0 ){
+ return false;
+ }
+ if( Trace.isOn("sg-gen-tg-match") ){
+ Trace("sg-gen-tg-match") << "Matching ";
+ debugPrint( s, "sg-gen-tg-match", "sg-gen-tg-match" );
+ Trace("sg-gen-tg-match") << " with eqc e" << s->d_cg->d_em[eqc] << "..." << std::endl;
+ Trace("sg-gen-tg-match") << " mstatus = " << d_match_status;
+ if( d_status==5 ){
+ TNode f = s->getTgFunc( d_typ, d_status_num );
+ Trace("sg-gen-tg-debug2") << ", f = " << f;
+ Trace("sg-gen-tg-debug2") << ", #args = " << s->d_func_args[f].size();
+ Trace("sg-gen-tg-debug2") << ", mchildNum = " << d_match_status_child_num;
+ Trace("sg-gen-tg-debug2") << ", #mchildren = " << d_match_children.size();
+ }
+ Trace("sg-gen-tg-debug2") << ", current substitution : {";
+ for( std::map< TypeNode, std::map< unsigned, TNode > >::iterator itt = subs.begin(); itt != subs.end(); ++itt ){
+ for( std::map< unsigned, TNode >::iterator it = itt->second.begin(); it != itt->second.end(); ++it ){
+ Trace("sg-gen-tg-debug2") << " " << it->first << " -> e" << s->d_cg->d_em[it->second];
+ }
+ }
+ Trace("sg-gen-tg-debug2") << " } " << std::endl;
+ }
+ if( d_status==1 ){
+ //a variable
+ if( d_match_status==0 ){
+ d_match_status++;
+ if( (d_match_mode & ( 1 << 1 ))!=0 ){
+ //only ground terms
+ if( !s->isGroundEqc( eqc ) ){
+ return false;
+ }
+ }else if( (d_match_mode & ( 1 << 2 ))!=0 ){
+ //only non-ground terms
+ //if( s->isGroundEqc( eqc ) ){
+ // return false;
+ //}
+ }
+ //store the match : restricted if match_mode.0 = 1
+ if( (d_match_mode & ( 1 << 0 ))!=0 ){
+ std::map< TNode, bool >::iterator it = rev_subs.find( eqc );
+ if( it==rev_subs.end() ){
+ rev_subs[eqc] = true;
+ }else{
+ return false;
+ }
+ }
+ Assert( subs[d_typ].find( d_status_num )==subs[d_typ].end() );
+ subs[d_typ][d_status_num] = eqc;
+ return true;
+ }else{
+ //clean up
+ subs[d_typ].erase( d_status_num );
+ if( (d_match_mode & ( 1 << 0 ))!=0 ){
+ rev_subs.erase( eqc );
+ }
+ return false;
+ }
+ }else if( d_status==2 ){
+ if( d_match_status==0 ){
+ d_match_status++;
+ Assert( d_status_num<(int)s->getNumTgVars( d_typ ) );
+ std::map< unsigned, TNode >::iterator it = subs[d_typ].find( d_status_num );
+ Assert( it!=subs[d_typ].end() );
+ return it->second==eqc;
+ }else{
+ return false;
+ }
+ }else if( d_status==5 ){
+ //Assert( d_match_children.size()<=d_children.size() );
+ //enumerating over f-applications in eqc
+ if( d_match_status_child_num<0 ){
+ return false;
+ }else if( d_match_status==0 ){
+ //set up next binding
+ if( d_match_status_child_num==(int)d_match_children.size() ){
+ if( d_match_status_child_num==0 ){
+ //initial binding
+ TNode f = s->getTgFunc( d_typ, d_status_num );
+ std::map< TNode, TermArgTrie >::iterator it = s->getTermDatabase()->d_func_map_eqc_trie[f].d_data.find( eqc );
+ if( it!=s->getTermDatabase()->d_func_map_eqc_trie[f].d_data.end() ){
+ d_match_children.push_back( it->second.d_data.begin() );
+ d_match_children_end.push_back( it->second.d_data.end() );
+ }else{
+ d_match_status++;
+ d_match_status_child_num--;
+ return getNextMatch( s, eqc, subs, rev_subs );
+ }
+ }else{
+ d_match_children.push_back( d_match_children[d_match_status_child_num-1]->second.d_data.begin() );
+ d_match_children_end.push_back( d_match_children[d_match_status_child_num-1]->second.d_data.end() );
+ }
+ }
+ d_match_status++;
+ Assert( d_match_status_child_num+1==(int)d_match_children.size() );
+ if( d_match_children[d_match_status_child_num]==d_match_children_end[d_match_status_child_num] ){
+ //no more arguments to bind
+ d_match_children.pop_back();
+ d_match_children_end.pop_back();
+ d_match_status_child_num--;
+ return getNextMatch( s, eqc, subs, rev_subs );
+ }else{
+ if( d_match_status_child_num==(int)d_children.size() ){
+ //successfully matched all children
+ d_match_children.pop_back();
+ d_match_children_end.pop_back();
+ d_match_status_child_num--;
+ return true;//return d_match_children[d_match_status]!=d_match_children_end[d_match_status];
+ }else{
+ //do next binding
+ s->d_tg_alloc[d_children[d_match_status_child_num]].resetMatching( s, d_match_children[d_match_status_child_num]->first, d_match_mode );
+ return getNextMatch( s, eqc, subs, rev_subs );
+ }
+ }
+ }else{
+ Assert( d_match_status==1 );
+ Assert( d_match_status_child_num+1==(int)d_match_children.size() );
+ Assert( d_match_children[d_match_status_child_num]!=d_match_children_end[d_match_status_child_num] );
+ d_match_status--;
+ if( s->d_tg_alloc[d_children[d_match_status_child_num]].getNextMatch( s, d_match_children[d_match_status_child_num]->first, subs, rev_subs ) ){
+ d_match_status_child_num++;
+ return getNextMatch( s, eqc, subs, rev_subs );
+ }else{
+ //iterate
+ d_match_children[d_match_status_child_num]++;
+ return getNextMatch( s, eqc, subs, rev_subs );
+ }
+ }
+ }
+ Assert( false );
+ return false;
+}
+
+unsigned TermGenerator::getDepth( TermGenEnv * s ) {
+ if( d_status==5 ){
+ unsigned maxd = 0;
+ for( unsigned i=0; i<d_children.size(); i++ ){
+ unsigned d = s->d_tg_alloc[d_children[i]].getDepth( s );
+ if( d>maxd ){
+ maxd = d;
+ }
+ }
+ return 1+maxd;
+ }else{
+ return 0;
+ }
+}
+
+unsigned TermGenerator::calculateGeneralizationDepth( TermGenEnv * s, std::map< TypeNode, std::vector< int > >& fvs ) {
+ if( d_status==5 ){
+ unsigned sum = 1;
+ for( unsigned i=0; i<d_children.size(); i++ ){
+ sum += s->d_tg_alloc[d_children[i]].calculateGeneralizationDepth( s, fvs );
+ }
+ return sum;
+ }else{
+ Assert( d_status==2 || d_status==1 );
+ std::map< TypeNode, std::vector< int > >::iterator it = fvs.find( d_typ );
+ if( it!=fvs.end() ){
+ if( std::find( it->second.begin(), it->second.end(), d_status_num )!=it->second.end() ){
+ return 1;
+ }
+ }
+ fvs[d_typ].push_back( d_status_num );
+ return 0;
+ }
+}
+
+unsigned TermGenerator::getGeneralizationDepth( TermGenEnv * s ) {
+ //if( s->d_gen_relevant_terms ){
+ // return s->d_tg_gdepth;
+ //}else{
+ std::map< TypeNode, std::vector< int > > fvs;
+ return calculateGeneralizationDepth( s, fvs );
+ //}
+}
+
+Node TermGenerator::getTerm( TermGenEnv * s ) {
+ if( d_status==1 || d_status==2 ){
+ Assert( !d_typ.isNull() );
+ return s->getFreeVar( d_typ, d_status_num );
+ }else if( d_status==5 ){
+ Node f = s->getTgFunc( d_typ, d_status_num );
+ if( d_children.size()==s->d_func_args[f].size() ){
+ std::vector< Node > children;
+ children.push_back( f );
+ for( unsigned i=0; i<d_children.size(); i++ ){
+ Node nc = s->d_tg_alloc[d_children[i]].getTerm( s );
+ if( nc.isNull() ){
+ return Node::null();
+ }else{
+ //Assert( nc.getType()==s->d_func_args[f][i] );
+ children.push_back( nc );
+ }
+ }
+ return NodeManager::currentNM()->mkNode( s->d_func_kind[f], children );
+ }
+ }else{
+ Assert( false );
+ }
+ return Node::null();
+}
+
+void TermGenerator::debugPrint( TermGenEnv * s, const char * c, const char * cd ) {
+ Trace(cd) << "[*" << d_id << "," << d_status << "]:";
+ if( d_status==1 || d_status==2 ){
+ Trace(c) << s->getFreeVar( d_typ, d_status_num );
+ }else if( d_status==5 ){
+ TNode f = s->getTgFunc( d_typ, d_status_num );
+ Trace(c) << "(" << f;
+ for( unsigned i=0; i<d_children.size(); i++ ){
+ Trace(c) << " ";
+ s->d_tg_alloc[d_children[i]].debugPrint( s, c, cd );
+ }
+ if( d_children.size()<s->d_func_args[f].size() ){
+ Trace(c) << " ...";
+ }
+ Trace(c) << ")";
+ }else{
+ Trace(c) << "???";
+ }
+}
+
+void TermGenEnv::collectSignatureInformation() {
+ d_typ_tg_funcs.clear();
+ d_funcs.clear();
+ d_func_kind.clear();
+ d_func_args.clear();
+ TypeNode tnull;
+ for( std::map< Node, TermArgTrie >::iterator it = getTermDatabase()->d_func_map_trie.begin(); it != getTermDatabase()->d_func_map_trie.end(); ++it ){
+ if( !getTermDatabase()->d_op_map[it->first].empty() ){
+ Node nn = getTermDatabase()->d_op_map[it->first][0];
+ if( d_cg->isHandledTerm( nn ) && nn.getKind()!=APPLY_SELECTOR_TOTAL && !nn.getType().isBoolean() ){
+ bool do_enum = true;
+ //check if we have enumerated ground terms
+ if( nn.getKind()==APPLY_UF ){
+ if( !d_cg->hasEnumeratedUf( nn ) ){
+ do_enum = false;
+ }
+ }
+ if( do_enum ){
+ d_funcs.push_back( it->first );
+ for( unsigned i=0; i<nn.getNumChildren(); i++ ){
+ d_func_args[it->first].push_back( nn[i].getType() );
+ }
+ d_func_kind[it->first] = nn.getKind();
+ d_typ_tg_funcs[tnull].push_back( it->first );
+ d_typ_tg_funcs[nn.getType()].push_back( it->first );
+ Trace("sg-rel-sig") << "Will enumerate function applications of : " << it->first << ", #args = " << d_func_args[it->first].size() << ", kind = " << nn.getKind() << std::endl;
+ getTermDatabase()->computeUfEqcTerms( it->first );
+ }
+ }
+ }
+ }
+ //shuffle functions
+ for( std::map< TypeNode, std::vector< TNode > >::iterator it = d_typ_tg_funcs.begin(); it != d_typ_tg_funcs.end(); ++it ){
+ std::random_shuffle( it->second.begin(), it->second.end() );
+ if( it->first.isNull() ){
+ Trace("sg-gen-tg-debug") << "In this order : ";
+ for( unsigned i=0; i<it->second.size(); i++ ){
+ Trace("sg-gen-tg-debug") << it->second[i] << " ";
+ }
+ Trace("sg-gen-tg-debug") << std::endl;
+ }
+ }
+}
+
+void TermGenEnv::reset( unsigned depth, bool genRelevant, TypeNode tn ) {
+ Assert( d_tg_alloc.empty() );
+ d_tg_alloc.clear();
+
+ if( genRelevant ){
+ for( unsigned i=0; i<2; i++ ){
+ d_ccand_eqc[i].clear();
+ d_ccand_eqc[i].push_back( d_relevant_eqc[i] );
+ }
+ }
+
+ d_tg_id = 0;
+ d_tg_gdepth = 0;
+ d_tg_gdepth_limit = depth;
+ d_gen_relevant_terms = genRelevant;
+ d_tg_alloc[0].reset( this, tn );
+}
+
+bool TermGenEnv::getNextTerm() {
+ if( d_tg_alloc[0].getNextTerm( this, d_tg_gdepth_limit ) ){
+ Assert( (int)d_tg_alloc[0].getGeneralizationDepth( this )<=d_tg_gdepth_limit );
+ if( (int)d_tg_alloc[0].getGeneralizationDepth( this )!=d_tg_gdepth_limit ){
+ return getNextTerm();
+ }else{
+ return true;
+ }
+ }else{
+ return false;
+ }
+}
+
+//reset matching
+void TermGenEnv::resetMatching( TNode eqc, unsigned mode ) {
+ d_tg_alloc[0].resetMatching( this, eqc, mode );
+}
+
+//get next match
+bool TermGenEnv::getNextMatch( TNode eqc, std::map< TypeNode, std::map< unsigned, TNode > >& subs, std::map< TNode, bool >& rev_subs ) {
+ return d_tg_alloc[0].getNextMatch( this, eqc, subs, rev_subs );
+}
+
+//get term
+Node TermGenEnv::getTerm() {
+ return d_tg_alloc[0].getTerm( this );
+}
+
+void TermGenEnv::debugPrint( const char * c, const char * cd ) {
+ d_tg_alloc[0].debugPrint( this, c, cd );
+}
+
+unsigned TermGenEnv::getNumTgVars( TypeNode tn ) {
+ return d_var_id[tn];
+}
+
+bool TermGenEnv::allowVar( TypeNode tn ) {
+ std::map< TypeNode, unsigned >::iterator it = d_var_limit.find( tn );
+ if( it==d_var_limit.end() ){
+ return true;
+ }else{
+ return d_var_id[tn]<it->second;
+ }
+}
+
+void TermGenEnv::addVar( TypeNode tn ) {
+ d_var_id[tn]++;
+}
+
+void TermGenEnv::removeVar( TypeNode tn ) {
+ d_var_id[tn]--;
+ //d_var_eq_tg.pop_back();
+ //d_var_tg.pop_back();
+}
+
+unsigned TermGenEnv::getNumTgFuncs( TypeNode tn ) {
+ return d_typ_tg_funcs[tn].size();
+}
+
+TNode TermGenEnv::getTgFunc( TypeNode tn, unsigned i ) {
+ return d_typ_tg_funcs[tn][i];
+}
+
+Node TermGenEnv::getFreeVar( TypeNode tn, unsigned i ) {
+ return d_cg->getFreeVar( tn, i );
+}
+
+bool TermGenEnv::considerCurrentTerm() {
+ Assert( !d_tg_alloc.empty() );
+
+ //if generalization depth is too large, don't consider it
+ unsigned i = d_tg_alloc.size();
+ Trace("sg-gen-tg-debug") << "Consider term ";
+ d_tg_alloc[0].debugPrint( this, "sg-gen-tg-debug", "sg-gen-tg-debug" );
+ Trace("sg-gen-tg-debug") << "? curr term size = " << d_tg_alloc.size() << ", last status = " << d_tg_alloc[i-1].d_status;
+ Trace("sg-gen-tg-debug") << std::endl;
+
+ if( d_tg_gdepth_limit>=0 && d_tg_alloc[0].getGeneralizationDepth( this )>(unsigned)d_tg_gdepth_limit ){
+ Trace("sg-gen-consider-term") << "-> generalization depth of ";
+ d_tg_alloc[0].debugPrint( this, "sg-gen-consider-term", "sg-gen-tg-debug" );
+ Trace("sg-gen-consider-term") << " is too high " << d_tg_gdepth << " " << d_tg_alloc[0].getGeneralizationDepth( this ) << ", do not consider." << std::endl;
+ return false;
+ }
+
+ //----optimizations
+ /*
+ if( d_tg_alloc[i-1].d_status==1 ){
+ }else if( d_tg_alloc[i-1].d_status==2 ){
+ }else if( d_tg_alloc[i-1].d_status==5 ){
+ }else{
+ Trace("sg-gen-tg-debug") << "Bad tg: " << &d_tg_alloc[i-1] << std::endl;
+ Assert( false );
+ }
+ */
+ //if equated two variables, first check if context-independent TODO
+ //----end optimizations
+
+
+ //check based on which candidate equivalence classes match
+ if( d_gen_relevant_terms ){
+ Trace("sg-gen-tg-debug") << "Filter based on relevant ground EQC";
+ Trace("sg-gen-tg-debug") << ", #eqc to try = " << d_ccand_eqc[0][i-1].size() << "/" << d_ccand_eqc[1][i-1].size() << std::endl;
+
+ Assert( d_ccand_eqc[0].size()>=2 );
+ Assert( d_ccand_eqc[0].size()==d_ccand_eqc[1].size() );
+ Assert( d_ccand_eqc[0].size()==d_tg_id+1 );
+ Assert( d_tg_id==d_tg_alloc.size() );
+ for( unsigned r=0; r<2; r++ ){
+ d_ccand_eqc[r][i].clear();
+ }
+
+ //re-check feasibility of EQC
+ for( unsigned r=0; r<2; r++ ){
+ for( unsigned j=0; j<d_ccand_eqc[r][i-1].size(); j++ ){
+ std::map< TypeNode, std::map< unsigned, TNode > > subs;
+ std::map< TNode, bool > rev_subs;
+ unsigned mode;
+ if( r==0 ){
+ mode = d_cg->optReqDistinctVarPatterns() ? ( 1 << 0 ) : 0;
+ mode = mode | (1 << 2 );
+ }else{
+ mode = 1 << 1;
+ }
+ d_tg_alloc[0].resetMatching( this, d_ccand_eqc[r][i-1][j], mode );
+ if( d_tg_alloc[0].getNextMatch( this, d_ccand_eqc[r][i-1][j], subs, rev_subs ) ){
+ d_ccand_eqc[r][i].push_back( d_ccand_eqc[r][i-1][j] );
+ }
+ }
+ }
+ for( unsigned r=0; r<2; r++ ){
+ Trace("sg-gen-tg-debug") << "Current eqc of type " << r << " : ";
+ for( unsigned j=0; j<d_ccand_eqc[r][i].size(); j++ ){
+ Trace("sg-gen-tg-debug") << "e" << d_cg->d_em[d_ccand_eqc[r][i][j]] << " ";
+ }
+ Trace("sg-gen-tg-debug") << std::endl;
+ }
+ if( options::conjectureFilterActiveTerms() && d_ccand_eqc[0][i].empty() ){
+ Trace("sg-gen-consider-term") << "Do not consider term of form ";
+ d_tg_alloc[0].debugPrint( this, "sg-gen-consider-term", "sg-gen-consider-term-debug" );
+ Trace("sg-gen-consider-term") << " since no relevant EQC matches it." << std::endl;
+ return false;
+ }
+ if( options::conjectureFilterModel() && d_ccand_eqc[1][i].empty() ){
+ Trace("sg-gen-consider-term") << "Do not consider term of form ";
+ d_tg_alloc[0].debugPrint( this, "sg-gen-consider-term", "sg-gen-consider-term-debug" );
+ Trace("sg-gen-consider-term") << " since no ground EQC matches it." << std::endl;
+ return false;
+ }
+ }
+ Trace("sg-gen-tg-debug") << "Will consider term ";
+ d_tg_alloc[0].debugPrint( this, "sg-gen-tg-debug", "sg-gen-tg-debug" );
+ Trace("sg-gen-tg-debug") << std::endl;
+ Trace("sg-gen-consider-term-debug") << std::endl;
+ return true;
+}
+
+void TermGenEnv::changeContext( bool add ) {
+ if( add ){
+ for( unsigned r=0; r<2; r++ ){
+ d_ccand_eqc[r].push_back( std::vector< TNode >() );
+ }
+ d_tg_id++;
+ }else{
+ for( unsigned r=0; r<2; r++ ){
+ d_ccand_eqc[r].pop_back();
+ }
+ d_tg_id--;
+ Assert( d_tg_alloc.find( d_tg_id )!=d_tg_alloc.end() );
+ d_tg_alloc.erase( d_tg_id );
+ }
+}
+
+bool TermGenEnv::considerCurrentTermCanon( unsigned tg_id ){
+ Assert( tg_id<d_tg_alloc.size() );
+ if( options::conjectureFilterCanonical() ){
+ //check based on a canonicity of the term (if there is one)
+ Trace("sg-gen-tg-debug") << "Consider term canon ";
+ d_tg_alloc[0].debugPrint( this, "sg-gen-tg-debug", "sg-gen-tg-debug" );
+ Trace("sg-gen-tg-debug") << ", tg is [" << tg_id << "]..." << std::endl;
+
+ Node ln = d_tg_alloc[tg_id].getTerm( this );
+ Trace("sg-gen-tg-debug") << "Term is " << ln << std::endl;
+ return d_cg->considerTermCanon( ln, d_gen_relevant_terms );
+ }
+ return true;
+}
+
+bool TermGenEnv::isRelevantFunc( Node f ) {
+ return std::find( d_funcs.begin(), d_funcs.end(), f )!=d_funcs.end();
+}
+TermDb * TermGenEnv::getTermDatabase() {
+ return d_cg->getTermDatabase();
+}
+Node TermGenEnv::getGroundEqc( TNode r ) {
+ return d_cg->getGroundEqc( r );
+}
+bool TermGenEnv::isGroundEqc( TNode r ){
+ return d_cg->isGroundEqc( r );
+}
+bool TermGenEnv::isGroundTerm( TNode n ){
+ return d_cg->isGroundTerm( n );
+}
+
+
+void SubstitutionIndex::addSubstitution( TNode eqc, std::vector< TNode >& vars, std::vector< TNode >& terms, unsigned i ) {
+ if( i==vars.size() ){
+ d_var = eqc;
+ }else{
+ Assert( d_var.isNull() || d_var==vars[i] );
+ d_var = vars[i];
+ d_children[terms[i]].addSubstitution( eqc, vars, terms, i+1 );
+ }
+}
+
+bool SubstitutionIndex::notifySubstitutions( ConjectureGenerator * s, std::map< TNode, TNode >& subs, TNode rhs, unsigned numVars, unsigned i ) {
+ if( i==numVars ){
+ Assert( d_children.empty() );
+ return s->notifySubstitution( d_var, subs, rhs );
+ }else{
+ Assert( i==0 || !d_children.empty() );
+ for( std::map< TNode, SubstitutionIndex >::iterator it = d_children.begin(); it != d_children.end(); ++it ){
+ Trace("sg-cconj-debug2") << "Try " << d_var << " -> " << it->first << " (" << i << "/" << numVars << ")" << std::endl;
+ subs[d_var] = it->first;
+ if( !it->second.notifySubstitutions( s, subs, rhs, numVars, i+1 ) ){
+ return false;
+ }
+ }
+ return true;
+ }
+}
+
+
+void TheoremIndex::addTheorem( std::vector< TNode >& lhs_v, std::vector< unsigned >& lhs_arg, TNode rhs ){
+ if( lhs_v.empty() ){
+ if( std::find( d_terms.begin(), d_terms.end(), rhs )==d_terms.end() ){
+ d_terms.push_back( rhs );
+ }
+ }else{
+ unsigned index = lhs_v.size()-1;
+ if( lhs_arg[index]==lhs_v[index].getNumChildren() ){
+ lhs_v.pop_back();
+ lhs_arg.pop_back();
+ addTheorem( lhs_v, lhs_arg, rhs );
+ }else{
+ lhs_arg[index]++;
+ addTheoremNode( lhs_v[index][lhs_arg[index]-1], lhs_v, lhs_arg, rhs );
+ }
+ }
+}
+
+void TheoremIndex::addTheoremNode( TNode curr, std::vector< TNode >& lhs_v, std::vector< unsigned >& lhs_arg, TNode rhs ){
+ Trace("thm-db-debug") << "Adding conjecture for subterm " << curr << "..." << std::endl;
+ if( curr.hasOperator() ){
+ lhs_v.push_back( curr );
+ lhs_arg.push_back( 0 );
+ d_children[curr.getOperator()].addTheorem( lhs_v, lhs_arg, rhs );
+ }else{
+ Assert( curr.getKind()==kind::BOUND_VARIABLE );
+ TypeNode tn = curr.getType();
+ Assert( d_var[tn].isNull() || d_var[tn]==curr );
+ d_var[tn] = curr;
+ d_children[curr].addTheorem( lhs_v, lhs_arg, rhs );
+ }
+}
+
+void TheoremIndex::getEquivalentTerms( std::vector< TNode >& n_v, std::vector< unsigned >& n_arg,
+ std::map< TNode, TNode >& smap, std::vector< TNode >& vars, std::vector< TNode >& subs,
+ std::vector< Node >& terms ) {
+ Trace("thm-db-debug") << "Get equivalent terms " << n_v.size() << " " << n_arg.size() << std::endl;
+ if( n_v.empty() ){
+ Trace("thm-db-debug") << "Number of terms : " << d_terms.size() << std::endl;
+ //apply substutitions to RHS's
+ for( unsigned i=0; i<d_terms.size(); i++ ){
+ Node n = d_terms[i].substitute( vars.begin(), vars.end(), subs.begin(), subs.end() );
+ terms.push_back( n );
+ }
+ }else{
+ unsigned index = n_v.size()-1;
+ if( n_arg[index]==n_v[index].getNumChildren() ){
+ n_v.pop_back();
+ n_arg.pop_back();
+ getEquivalentTerms( n_v, n_arg, smap, vars, subs, terms );
+ }else{
+ n_arg[index]++;
+ getEquivalentTermsNode( n_v[index][n_arg[index]-1], n_v, n_arg, smap, vars, subs, terms );
+ }
+ }
+}
+
+void TheoremIndex::getEquivalentTermsNode( Node curr, std::vector< TNode >& n_v, std::vector< unsigned >& n_arg,
+ std::map< TNode, TNode >& smap, std::vector< TNode >& vars, std::vector< TNode >& subs,
+ std::vector< Node >& terms ) {
+ Trace("thm-db-debug") << "Get equivalent based on subterm " << curr << "..." << std::endl;
+ if( curr.hasOperator() ){
+ Trace("thm-db-debug") << "Check based on operator..." << std::endl;
+ std::map< TNode, TheoremIndex >::iterator it = d_children.find( curr.getOperator() );
+ if( it!=d_children.end() ){
+ n_v.push_back( curr );
+ n_arg.push_back( 0 );
+ it->second.getEquivalentTerms( n_v, n_arg, smap, vars, subs, terms );
+ }
+ Trace("thm-db-debug") << "...done check based on operator" << std::endl;
+ }
+ TypeNode tn = curr.getType();
+ std::map< TypeNode, TNode >::iterator itt = d_var.find( tn );
+ if( itt!=d_var.end() ){
+ Trace("thm-db-debug") << "Check for substitution with " << itt->second << "..." << std::endl;
+ Assert( curr.getType()==itt->second.getType() );
+ //add to substitution if possible
+ bool success = false;
+ std::map< TNode, TNode >::iterator it = smap.find( itt->second );
+ if( it==smap.end() ){
+ smap[itt->second] = curr;
+ vars.push_back( itt->second );
+ subs.push_back( curr );
+ success = true;
+ }else if( it->second==curr ){
+ success = true;
+ }else{
+ //also check modulo equality (in universal equality engine)
+ }
+ Trace("thm-db-debug") << "...check for substitution with " << itt->second << ", success = " << success << "." << std::endl;
+ if( success ){
+ d_children[itt->second].getEquivalentTerms( n_v, n_arg, smap, vars, subs, terms );
+ }
+ }
+}
+
+void TheoremIndex::debugPrint( const char * c, unsigned ind ) {
+ for( std::map< TNode, TheoremIndex >::iterator it = d_children.begin(); it != d_children.end(); ++it ){
+ for( unsigned i=0; i<ind; i++ ){ Trace(c) << " "; }
+ Trace(c) << it->first << std::endl;
+ it->second.debugPrint( c, ind+1 );
+ }
+ if( !d_terms.empty() ){
+ for( unsigned i=0; i<ind; i++ ){ Trace(c) << " "; }
+ Trace(c) << "{";
+ for( unsigned i=0; i<d_terms.size(); i++ ){
+ Trace(c) << " " << d_terms[i];
+ }
+ Trace(c) << " }" << std::endl;
+ }
+ //if( !d_var.isNull() ){
+ // for( unsigned i=0; i<ind; i++ ){ Trace(c) << " "; }
+ // Trace(c) << "var:" << d_var << std::endl;
+ //}
+}
+
+bool ConjectureGenerator::optReqDistinctVarPatterns() { return false; }
+bool ConjectureGenerator::optFilterUnknown() { return true; } //may change
+int ConjectureGenerator::optFilterScoreThreshold() { return 1; }
+unsigned ConjectureGenerator::optFullCheckFrequency() { return 1; }
+
+bool ConjectureGenerator::optStatsOnly() { return false; }
+
+}
diff --git a/src/theory/quantifiers/conjecture_generator.h b/src/theory/quantifiers/conjecture_generator.h
new file mode 100755
index 000000000..23e2b88ba
--- /dev/null
+++ b/src/theory/quantifiers/conjecture_generator.h
@@ -0,0 +1,446 @@
+/********************* */
+/*! \file conjecture_generator.h
+ ** \verbatim
+ ** Original author: Andrew Reynolds
+ ** Major contributors: none
+ ** Minor contributors (to current version): none
+ ** This file is part of the CVC4 project.
+ ** Copyright (c) 2009-2014 New York University and The University of Iowa
+ ** See the file COPYING in the top-level source directory for licensing
+ ** information.\endverbatim
+ **
+ ** \brief conjecture generator class
+ **/
+
+#include "cvc4_private.h"
+
+#ifndef CONJECTURE_GENERATOR_H
+#define CONJECTURE_GENERATOR_H
+
+#include "context/cdhashmap.h"
+#include "context/cdchunk_list.h"
+#include "theory/quantifiers_engine.h"
+#include "theory/type_enumerator.h"
+
+namespace CVC4 {
+namespace theory {
+namespace quantifiers {
+
+class TermArgTrie;
+
+//algorithm for computing candidate subgoals
+
+class ConjectureGenerator;
+
+// operator independent index of arguments for an EQC
+class OpArgIndex
+{
+public:
+ std::map< TNode, OpArgIndex > d_child;
+ std::vector< TNode > d_ops;
+ std::vector< TNode > d_op_terms;
+ void addTerm( ConjectureGenerator * s, TNode n, unsigned index = 0 );
+ Node getGroundTerm( ConjectureGenerator * s, std::vector< TNode >& args );
+ void getGroundTerms( ConjectureGenerator * s, std::vector< TNode >& terms );
+};
+
+class PatternTypIndex
+{
+public:
+ std::vector< TNode > d_terms;
+ std::map< TypeNode, std::map< unsigned, PatternTypIndex > > d_children;
+ void clear() {
+ d_terms.clear();
+ d_children.clear();
+ }
+};
+
+class SubstitutionIndex
+{
+public:
+ //current variable, or ground EQC if d_children.empty()
+ TNode d_var;
+ std::map< TNode, SubstitutionIndex > d_children;
+ //add substitution
+ void addSubstitution( TNode eqc, std::vector< TNode >& vars, std::vector< TNode >& terms, unsigned i = 0 );
+ //notify substitutions
+ bool notifySubstitutions( ConjectureGenerator * s, std::map< TNode, TNode >& subs, TNode rhs, unsigned numVars, unsigned i = 0 );
+};
+
+class TermGenEnv;
+
+class TermGenerator
+{
+private:
+ unsigned calculateGeneralizationDepth( TermGenEnv * s, std::map< TypeNode, std::vector< int > >& fvs );
+public:
+ TermGenerator(){}
+ TypeNode d_typ;
+ unsigned d_id;
+ //1 : consider as unique variable
+ //2 : consider equal to another variable
+ //5 : consider a function application
+ unsigned d_status;
+ int d_status_num;
+ //for function applications: the number of children you have built
+ int d_status_child_num;
+ //children (pointers to TermGenerators)
+ std::vector< unsigned > d_children;
+
+ //match status
+ int d_match_status;
+ int d_match_status_child_num;
+ //match mode bits
+ //0 : different variables must have different matches
+ //1 : variables must map to ground terms
+ //2 : variables must map to non-ground terms
+ unsigned d_match_mode;
+ //children
+ std::vector< std::map< TNode, TermArgTrie >::iterator > d_match_children;
+ std::vector< std::map< TNode, TermArgTrie >::iterator > d_match_children_end;
+
+ void reset( TermGenEnv * s, TypeNode tn );
+ bool getNextTerm( TermGenEnv * s, unsigned depth );
+ void resetMatching( TermGenEnv * s, TNode eqc, unsigned mode );
+ bool getNextMatch( TermGenEnv * s, TNode eqc, std::map< TypeNode, std::map< unsigned, TNode > >& subs, std::map< TNode, bool >& rev_subs );
+
+ unsigned getDepth( TermGenEnv * s );
+ unsigned getGeneralizationDepth( TermGenEnv * s );
+ Node getTerm( TermGenEnv * s );
+
+ void debugPrint( TermGenEnv * s, const char * c, const char * cd );
+};
+
+
+class TermGenEnv
+{
+public:
+ //collect signature information
+ void collectSignatureInformation();
+ //reset function
+ void reset( unsigned gdepth, bool genRelevant, TypeNode tgen );
+ //get next term
+ bool getNextTerm();
+ //reset matching
+ void resetMatching( TNode eqc, unsigned mode );
+ //get next match
+ bool getNextMatch( TNode eqc, std::map< TypeNode, std::map< unsigned, TNode > >& subs, std::map< TNode, bool >& rev_subs );
+ //get term
+ Node getTerm();
+ //debug print
+ void debugPrint( const char * c, const char * cd );
+
+ //conjecture generation
+ ConjectureGenerator * d_cg;
+ //the current number of enumerated variables per type
+ std::map< TypeNode, unsigned > d_var_id;
+ //the limit of number of variables per type to enumerate
+ std::map< TypeNode, unsigned > d_var_limit;
+ //the functions we can currently generate
+ std::map< TypeNode, std::vector< TNode > > d_typ_tg_funcs;
+ //the equivalence classes (if applicable) that match the currently generated term
+ bool d_gen_relevant_terms;
+ //relevant equivalence classes
+ std::vector< TNode > d_relevant_eqc[2];
+ //candidate equivalence classes
+ std::vector< std::vector< TNode > > d_ccand_eqc[2];
+ //the term generation objects
+ unsigned d_tg_id;
+ std::map< unsigned, TermGenerator > d_tg_alloc;
+ unsigned d_tg_gdepth;
+ int d_tg_gdepth_limit;
+
+ //all functions
+ std::vector< TNode > d_funcs;
+ //function to kind map
+ std::map< TNode, Kind > d_func_kind;
+ //type of each argument of the function
+ std::map< TNode, std::vector< TypeNode > > d_func_args;
+
+ //access functions
+ unsigned getNumTgVars( TypeNode tn );
+ bool allowVar( TypeNode tn );
+ void addVar( TypeNode tn );
+ void removeVar( TypeNode tn );
+ unsigned getNumTgFuncs( TypeNode tn );
+ TNode getTgFunc( TypeNode tn, unsigned i );
+ Node getFreeVar( TypeNode tn, unsigned i );
+ bool considerCurrentTerm();
+ bool considerCurrentTermCanon( unsigned tg_id );
+ void changeContext( bool add );
+ bool isRelevantFunc( Node f );
+ //carry
+ TermDb * getTermDatabase();
+ Node getGroundEqc( TNode r );
+ bool isGroundEqc( TNode r );
+ bool isGroundTerm( TNode n );
+};
+
+
+
+class TheoremIndex
+{
+private:
+ void addTheorem( std::vector< TNode >& lhs_v, std::vector< unsigned >& lhs_arg, TNode rhs );
+ void addTheoremNode( TNode curr, std::vector< TNode >& lhs_v, std::vector< unsigned >& lhs_arg, TNode rhs );
+ void getEquivalentTerms( std::vector< TNode >& n_v, std::vector< unsigned >& n_arg,
+ std::map< TNode, TNode >& smap, std::vector< TNode >& vars, std::vector< TNode >& subs,
+ std::vector< Node >& terms );
+ void getEquivalentTermsNode( Node curr, std::vector< TNode >& n_v, std::vector< unsigned >& n_arg,
+ std::map< TNode, TNode >& smap, std::vector< TNode >& vars, std::vector< TNode >& subs,
+ std::vector< Node >& terms );
+public:
+ std::map< TypeNode, TNode > d_var;
+ std::map< TNode, TheoremIndex > d_children;
+ std::vector< Node > d_terms;
+
+ void addTheorem( TNode lhs, TNode rhs ) {
+ std::vector< TNode > v;
+ std::vector< unsigned > a;
+ addTheoremNode( lhs, v, a, rhs );
+ }
+ void getEquivalentTerms( TNode n, std::vector< Node >& terms ) {
+ std::vector< TNode > nv;
+ std::vector< unsigned > na;
+ std::map< TNode, TNode > smap;
+ std::vector< TNode > vars;
+ std::vector< TNode > subs;
+ getEquivalentTermsNode( n, nv, na, smap, vars, subs, terms );
+ }
+ void clear(){
+ d_var.clear();
+ d_children.clear();
+ d_terms.clear();
+ }
+ void debugPrint( const char * c, unsigned ind = 0 );
+};
+
+
+
+class ConjectureGenerator : public QuantifiersModule
+{
+ friend class OpArgIndex;
+ friend class PatGen;
+ friend class PatternGenEqc;
+ friend class PatternGen;
+ friend class SubsEqcIndex;
+ friend class TermGenerator;
+ friend class TermGenEnv;
+ typedef context::CDChunkList<Node> NodeList;
+ typedef context::CDHashMap< Node, Node, NodeHashFunction > NodeMap;
+ typedef context::CDHashMap< Node, bool, NodeHashFunction > BoolMap;
+//this class maintains a congruence closure for *universal* facts
+private:
+ //notification class for equality engine
+ class NotifyClass : public eq::EqualityEngineNotify {
+ ConjectureGenerator& d_sg;
+ public:
+ NotifyClass(ConjectureGenerator& sg): d_sg(sg) {}
+ bool eqNotifyTriggerEquality(TNode equality, bool value) { return true; }
+ bool eqNotifyTriggerPredicate(TNode predicate, bool value) { return true; }
+ bool eqNotifyTriggerTermEquality(TheoryId tag, TNode t1, TNode t2, bool value) { return true; }
+ void eqNotifyConstantTermMerge(TNode t1, TNode t2) { }
+ void eqNotifyNewClass(TNode t) { d_sg.eqNotifyNewClass(t); }
+ void eqNotifyPreMerge(TNode t1, TNode t2) { d_sg.eqNotifyPreMerge(t1, t2); }
+ void eqNotifyPostMerge(TNode t1, TNode t2) { d_sg.eqNotifyPostMerge(t1, t2); }
+ void eqNotifyDisequal(TNode t1, TNode t2, TNode reason) {d_sg.eqNotifyDisequal(t1, t2, reason); }
+ };/* class ConjectureGenerator::NotifyClass */
+ /** The notify class */
+ NotifyClass d_notify;
+ class EqcInfo{
+ public:
+ EqcInfo( context::Context* c );
+ //representative
+ context::CDO< Node > d_rep;
+ };
+ /** get or make eqc info */
+ EqcInfo* getOrMakeEqcInfo( TNode n, bool doMake = false );
+ /** (universal) equaltity engine */
+ eq::EqualityEngine d_uequalityEngine;
+ /** pending adds */
+ std::vector< Node > d_upendingAdds;
+ /** relevant terms */
+ std::map< Node, bool > d_urelevant_terms;
+ /** information necessary for equivalence classes */
+ std::map< Node, EqcInfo* > d_eqc_info;
+ /** called when a new equivalance class is created */
+ void eqNotifyNewClass(TNode t);
+ /** called when two equivalance classes will merge */
+ void eqNotifyPreMerge(TNode t1, TNode t2);
+ /** called when two equivalance classes have merged */
+ void eqNotifyPostMerge(TNode t1, TNode t2);
+ /** called when two equivalence classes are made disequal */
+ void eqNotifyDisequal(TNode t1, TNode t2, TNode reason);
+ /** are universal equal */
+ bool areUniversalEqual( TNode n1, TNode n2 );
+ /** are universal disequal */
+ bool areUniversalDisequal( TNode n1, TNode n2 );
+ /** get universal representative */
+ TNode getUniversalRepresentative( TNode n, bool add = false );
+ /** set relevant */
+ void setUniversalRelevant( TNode n );
+ /** ordering for universal terms */
+ bool isUniversalLessThan( TNode rt1, TNode rt2 );
+
+ /** the nodes we have reported as canonical representative */
+ std::vector< TNode > d_ue_canon;
+ /** is reported canon */
+ bool isReportedCanon( TNode n );
+ /** mark that term has been reported as canonical rep */
+ void markReportedCanon( TNode n );
+
+private: //information regarding the conjectures
+ /** list of all conjectures */
+ std::vector< Node > d_conjectures;
+ /** list of all waiting conjectures */
+ std::vector< Node > d_waiting_conjectures_lhs;
+ std::vector< Node > d_waiting_conjectures_rhs;
+ std::vector< int > d_waiting_conjectures_score;
+ /** map of currently considered equality conjectures */
+ std::map< Node, std::vector< Node > > d_waiting_conjectures;
+ /** map of equality conjectures */
+ std::map< Node, std::vector< Node > > d_eq_conjectures;
+ /** currently existing conjectures in equality engine */
+ BoolMap d_ee_conjectures;
+ /** conjecture index */
+ TheoremIndex d_thm_index;
+private: //free variable list
+ //free variables
+ std::map< TypeNode, std::vector< Node > > d_free_var;
+ //map from free variable to FV#
+ std::map< TNode, unsigned > d_free_var_num;
+ // get canonical free variable #i of type tn
+ Node getFreeVar( TypeNode tn, unsigned i );
+ // get canonical term, return null if it contains a term apart from handled signature
+ Node getCanonicalTerm( TNode n, std::map< TypeNode, unsigned >& var_count, std::map< TNode, TNode >& subs );
+private: //information regarding the terms
+ //relevant patterns (the LHS's)
+ std::map< TypeNode, std::vector< Node > > d_rel_patterns;
+ //total number of unique variables
+ std::map< TNode, unsigned > d_rel_pattern_var_sum;
+ //by types
+ PatternTypIndex d_rel_pattern_typ_index;
+ // substitution to ground EQC index
+ std::map< TNode, SubstitutionIndex > d_rel_pattern_subs_index;
+ //patterns (the RHS's)
+ std::map< TypeNode, std::vector< Node > > d_patterns;
+ //patterns to # variables per type
+ std::map< TNode, std::map< TypeNode, unsigned > > d_pattern_var_id;
+ // # duplicated variables
+ std::map< TNode, unsigned > d_pattern_var_duplicate;
+ // is normal pattern? (variables allocated in canonical way left to right)
+ std::map< TNode, int > d_pattern_is_normal;
+ std::map< TNode, int > d_pattern_is_relevant;
+ // patterns to a count of # operators (variables and functions)
+ std::map< TNode, std::map< TNode, unsigned > > d_pattern_fun_id;
+ // term size
+ std::map< TNode, unsigned > d_pattern_fun_sum;
+ // collect functions
+ unsigned collectFunctions( TNode opat, TNode pat, std::map< TNode, unsigned >& funcs,
+ std::map< TypeNode, unsigned >& mnvn, std::map< TypeNode, unsigned >& mxvn );
+ // add pattern
+ void registerPattern( Node pat, TypeNode tpat );
+private: //for debugging
+ std::map< TNode, unsigned > d_em;
+public:
+ //term generation environment
+ TermGenEnv d_tge;
+ //consider term canon
+ bool considerTermCanon( Node ln, bool genRelevant );
+public: //for generalization
+ //generalizations
+ bool isGeneralization( TNode patg, TNode pat ) {
+ std::map< TNode, TNode > subs;
+ return isGeneralization( patg, pat, subs );
+ }
+ bool isGeneralization( TNode patg, TNode pat, std::map< TNode, TNode >& subs );
+ // get generalization depth
+ int calculateGeneralizationDepth( TNode n, std::vector< TNode >& fv );
+private:
+ //ground term enumeration
+ std::map< TypeNode, std::vector< Node > > d_enum_terms;
+ //type enumerators
+ std::map< TypeNode, unsigned > d_typ_enum_map;
+ std::vector< TypeEnumerator > d_typ_enum;
+ //get nth term for type
+ Node getEnumerateTerm( TypeNode tn, unsigned index );
+ //predicate for type
+ std::map< TypeNode, Node > d_typ_pred;
+ //get predicate for type
+ Node getPredicateForType( TypeNode tn );
+ //
+ void getEnumerateUfTerm( Node n, unsigned num, std::vector< Node >& terms );
+ //
+ void getEnumeratePredUfTerm( Node n, unsigned num, std::vector< Node >& terms );
+ // uf operators enumerated
+ std::map< Node, bool > d_uf_enum;
+public: //for property enumeration
+ //process this candidate conjecture
+ void processCandidateConjecture( TNode lhs, TNode rhs, unsigned lhs_depth, unsigned rhs_depth );
+ //whether it should be considered, negative : no, positive returns score
+ int considerCandidateConjecture( TNode lhs, TNode rhs );
+ //notified of a substitution
+ bool notifySubstitution( TNode glhs, std::map< TNode, TNode >& subs, TNode rhs );
+ //confirmation count
+ unsigned d_subs_confirmCount;
+ //individual witnesses (for range)
+ std::vector< TNode > d_subs_confirmWitnessRange;
+ //individual witnesses (for domain)
+ std::map< TNode, std::vector< TNode > > d_subs_confirmWitnessDomain;
+ //number of ground substitutions whose equality is unknown
+ unsigned d_subs_unkCount;
+public: //for ground equivalence classes
+ eq::EqualityEngine * getEqualityEngine();
+ bool areDisequal( TNode n1, TNode n2 );
+ bool areEqual( TNode n1, TNode n2 );
+ TNode getRepresentative( TNode n );
+ TermDb * getTermDatabase();
+private: //information about ground equivalence classes
+ TNode d_bool_eqc[2];
+ std::map< TNode, Node > d_ground_eqc_map;
+ std::vector< TNode > d_ground_terms;
+ //operator independent term index
+ std::map< TNode, OpArgIndex > d_op_arg_index;
+ //is handled term
+ bool isHandledTerm( TNode n );
+ Node getGroundEqc( TNode r );
+ bool isGroundEqc( TNode r );
+ bool isGroundTerm( TNode n );
+ //has enumerated UF
+ bool hasEnumeratedUf( Node n );
+ // count of full effort checks
+ unsigned d_fullEffortCount;
+ // has added lemma
+ bool d_hasAddedLemma;
+ //flush the waiting conjectures
+ unsigned flushWaitingConjectures( unsigned& addedLemmas, int ldepth, int rdepth );
+public:
+ ConjectureGenerator( QuantifiersEngine * qe, context::Context* c );
+ /* needs check */
+ bool needsCheck( Theory::Effort e );
+ /* reset at a round */
+ void reset_round( Theory::Effort e );
+ /* Call during quantifier engine's check */
+ void check( Theory::Effort e, unsigned quant_e );
+ /* Called for new quantifiers */
+ void registerQuantifier( Node q );
+ void assertNode( Node n );
+ /** Identify this module (for debugging, dynamic configuration, etc..) */
+ std::string identify() const { return "ConjectureGenerator"; }
+//options
+private:
+ bool optReqDistinctVarPatterns();
+ bool optFilterUnknown();
+ int optFilterScoreThreshold();
+ unsigned optFullCheckFrequency();
+ unsigned optFullCheckConjectures();
+
+ bool optStatsOnly();
+};
+
+
+}
+}
+}
+
+#endif
diff --git a/src/theory/quantifiers/first_order_model.cpp b/src/theory/quantifiers/first_order_model.cpp
index 1421c639f..0a0d4eba8 100644
--- a/src/theory/quantifiers/first_order_model.cpp
+++ b/src/theory/quantifiers/first_order_model.cpp
@@ -115,6 +115,24 @@ Node FirstOrderModel::getSomeDomainElement(TypeNode tn){
return d_rep_set.d_type_reps[tn][0];
}
+void FirstOrderModel::reset_round() {
+ d_quant_active.clear();
+}
+
+void FirstOrderModel::setQuantifierActive( TNode q, bool active ) {
+ d_quant_active[q] = active;
+}
+
+bool FirstOrderModel::isQuantifierActive( TNode q ) {
+ std::map< TNode, bool >::iterator it = d_quant_active.find( q );
+ if( it==d_quant_active.end() ){
+ return true;
+ }else{
+ return it->second;
+ }
+}
+
+
FirstOrderModelIG::FirstOrderModelIG(QuantifiersEngine * qe, context::Context* c, std::string name) :
FirstOrderModel(qe, c,name) {
diff --git a/src/theory/quantifiers/first_order_model.h b/src/theory/quantifiers/first_order_model.h
index 76c3946ce..6ad04a1e6 100644
--- a/src/theory/quantifiers/first_order_model.h
+++ b/src/theory/quantifiers/first_order_model.h
@@ -92,6 +92,19 @@ public:
}
/** get some domain element */
Node getSomeDomainElement(TypeNode tn);
+private:
+ //list of inactive quantified formulas
+ std::map< TNode, bool > d_quant_active;
+public:
+ /** reset round */
+ void reset_round();
+ /** set quantified formula active/inactive
+ * a quantified formula may be set inactive if for instance:
+ * - it is entailed by other quantified formulas
+ */
+ void setQuantifierActive( TNode q, bool active );
+ /** is quantified formula active */
+ bool isQuantifierActive( TNode q );
};/* class FirstOrderModel */
diff --git a/src/theory/quantifiers/full_model_check.cpp b/src/theory/quantifiers/full_model_check.cpp
index d5ed5589b..64ebb6cda 100644
--- a/src/theory/quantifiers/full_model_check.cpp
+++ b/src/theory/quantifiers/full_model_check.cpp
@@ -811,9 +811,11 @@ bool FullModelChecker::exhaustiveInstantiate(FirstOrderModelFmc * fm, Node f, No
Trace("fmc-exh-debug") << std::endl;
int index = riter.increment();
Trace("fmc-exh-debug") << "Incremented index " << index << std::endl;
- if (index>=0 && riter.d_index[index]>0 && addedLemmas>0 && riter.d_enum_type[index]==RepSetIterator::ENUM_RANGE) {
- Trace("fmc-exh-debug") << "Since this is a range enumeration, skip to the next..." << std::endl;
- riter.increment2( index-1 );
+ if( !riter.isFinished() ){
+ if (index>=0 && riter.d_index[index]>0 && addedLemmas>0 && riter.d_enum_type[index]==RepSetIterator::ENUM_RANGE) {
+ Trace("fmc-exh-debug") << "Since this is a range enumeration, skip to the next..." << std::endl;
+ riter.increment2( index-1 );
+ }
}
}
d_addedLemmas += addedLemmas;
@@ -871,7 +873,7 @@ void FullModelChecker::doCheck(FirstOrderModelFmc * fm, Node f, Def & d, Node n
Trace("fmc-debug") << "Can't process base array " << r << std::endl;
//can't process this array
d.reset();
- d.addEntry(fm, defC, Node::null());
+ d.addEntry(fm, mkCondDefault(fm, f), Node::null());
}
}
else if( n.getNumChildren()==0 ){
diff --git a/src/theory/quantifiers/inst_match_generator.cpp b/src/theory/quantifiers/inst_match_generator.cpp
index c024d0bab..35809b536 100644
--- a/src/theory/quantifiers/inst_match_generator.cpp
+++ b/src/theory/quantifiers/inst_match_generator.cpp
@@ -30,14 +30,21 @@ namespace CVC4 {
namespace theory {
namespace inst {
-
-InstMatchGenerator::InstMatchGenerator( Node pat, int matchPolicy ) : d_matchPolicy( matchPolicy ){
+InstMatchGenerator::InstMatchGenerator( Node pat ){
d_needsReset = true;
d_active_add = false;
Assert( quantifiers::TermDb::hasInstConstAttr(pat) );
d_pattern = pat;
d_match_pattern = pat;
d_next = NULL;
+ d_matchPolicy = MATCH_GEN_DEFAULT;
+}
+
+InstMatchGenerator::InstMatchGenerator() {
+ d_needsReset = true;
+ d_active_add = false;
+ d_next = NULL;
+ d_matchPolicy = MATCH_GEN_DEFAULT;
}
void InstMatchGenerator::setActiveAdd(bool val){
@@ -89,24 +96,31 @@ void InstMatchGenerator::initialize( QuantifiersEngine* qe, std::vector< InstMat
d_match_pattern_op = qe->getTermDatabase()->getOperator( d_match_pattern );
//now, collect children of d_match_pattern
- int childMatchPolicy = MATCH_GEN_DEFAULT;
+ //int childMatchPolicy = MATCH_GEN_DEFAULT;
for( int i=0; i<(int)d_match_pattern.getNumChildren(); i++ ){
if( quantifiers::TermDb::hasInstConstAttr(d_match_pattern[i]) ){
- if( d_match_pattern[i].getKind()!=INST_CONSTANT && !Trigger::isBooleanTermTrigger( d_match_pattern[i] ) ){
- InstMatchGenerator * cimg = new InstMatchGenerator( d_match_pattern[i], childMatchPolicy );
+ InstMatchGenerator * cimg = Trigger::getInstMatchGenerator( d_match_pattern[i] );
+ if( cimg ){
d_children.push_back( cimg );
d_children_index.push_back( i );
gens.push_back( cimg );
+ d_children_types.push_back( 1 );
+ }else{
+ d_var_num[i] = d_match_pattern[i].getAttribute(InstVarNumAttribute());
+ d_children_types.push_back( 0 );
}
+ }else{
+ d_children_types.push_back( -1 );
}
}
+ if( d_match_pattern.getKind()==INST_CONSTANT ){
+ d_var_num[0] = d_match_pattern.getAttribute(InstVarNumAttribute());
+ }
//create candidate generator
if( d_match_pattern.getKind()==INST_CONSTANT ){
d_cg = new CandidateGeneratorQEAll( qe, d_match_pattern );
- }
- else if( d_match_pattern.getKind()==EQUAL || d_match_pattern.getKind()==IFF ){
- Assert( d_matchPolicy==MATCH_GEN_DEFAULT );
+ }else if( d_match_pattern.getKind()==EQUAL || d_match_pattern.getKind()==IFF ){
//we will be producing candidates via literal matching heuristics
if( d_pattern.getKind()!=NOT ){
//candidates will be all equalities
@@ -139,15 +153,6 @@ void InstMatchGenerator::initialize( QuantifiersEngine* qe, std::vector< InstMat
Trace("inst-match-gen-warn") << "(?) Unknown matching pattern is " << d_match_pattern << std::endl;
d_matchPolicy = MATCH_GEN_INTERNAL_ERROR;
}
- for( int i=0; i<(int)d_match_pattern.getNumChildren(); i++ ){
- if( d_match_pattern[i].getKind()==INST_CONSTANT || Trigger::isBooleanTermTrigger( d_match_pattern[i] ) ){
- Node vv = d_match_pattern[i];
- if( Trigger::isBooleanTermTrigger( d_match_pattern[i] ) ){
- vv = d_match_pattern[i][0];
- }
- d_var_num[i] = vv.getAttribute(InstVarNumAttribute());
- }
- }
}
}
@@ -157,6 +162,7 @@ bool InstMatchGenerator::getMatch( Node f, Node t, InstMatch& m, QuantifiersEngi
<< m << ")" << ", " << d_children.size() << ", pattern is " << d_pattern << std::endl;
Assert( !d_match_pattern.isNull() );
if( d_matchPolicy==MATCH_GEN_INTERNAL_ERROR ){
+ Trace("matching-fail") << "Internal error for match generator." << std::endl;
return false;
}else{
EqualityQuery* q = qe->getEqualityQuery();
@@ -167,27 +173,23 @@ bool InstMatchGenerator::getMatch( Node f, Node t, InstMatch& m, QuantifiersEngi
//if t is null
Assert( !t.isNull() );
Assert( !quantifiers::TermDb::hasInstConstAttr(t) );
- Assert( t.getKind()==d_match_pattern.getKind() );
+ Assert( d_match_pattern.getKind()==INST_CONSTANT || t.getKind()==d_match_pattern.getKind() );
Assert( !Trigger::isAtomicTrigger( d_match_pattern ) || t.getOperator()==d_match_pattern.getOperator() );
//first, check if ground arguments are not equal, or a match is in conflict
for( int i=0; i<(int)d_match_pattern.getNumChildren(); i++ ){
- if( quantifiers::TermDb::hasInstConstAttr(d_match_pattern[i]) ){
- if( d_match_pattern[i].getKind()==INST_CONSTANT || Trigger::isBooleanTermTrigger( d_match_pattern[i] ) ){
- Node tt = t[i];
- if( Trigger::isBooleanTermTrigger( d_match_pattern[i] ) ){
- tt = NodeManager::currentNM()->mkConst(q->areEqual( tt, d_match_pattern[i][1] ));
- }
- bool addToPrev = m.get( d_var_num[i] ).isNull();
- if( !m.set( qe, d_var_num[i], tt ) ){
- //match is in conflict
- Trace("matching-fail") << "Match fail: " << m.get(d_var_num[i]) << " and " << tt << std::endl;
- success = false;
- break;
- }else if( addToPrev ){
- prev.push_back( d_var_num[i] );
- }
+ if( d_children_types[i]==0 ){
+ Trace("matching-debug2") << "Setting " << d_var_num[i] << " to " << t[i] << "..." << std::endl;
+ bool addToPrev = m.get( d_var_num[i] ).isNull();
+ if( !m.set( qe, d_var_num[i], t[i] ) ){
+ //match is in conflict
+ Trace("matching-fail") << "Match fail: " << m.get(d_var_num[i]) << " and " << t[i] << std::endl;
+ success = false;
+ break;
+ }else if( addToPrev ){
+ Trace("matching-debug2") << "Success." << std::endl;
+ prev.push_back( d_var_num[i] );
}
- }else{
+ }else if( d_children_types[i]==-1 ){
if( !q->areEqual( d_match_pattern[i], t[i] ) ){
Trace("matching-fail") << "Match fail arg: " << d_match_pattern[i] << " and " << t[i] << std::endl;
//ground arguments are not equal
@@ -196,8 +198,18 @@ bool InstMatchGenerator::getMatch( Node f, Node t, InstMatch& m, QuantifiersEngi
}
}
}
+ //for variable matching
+ if( d_match_pattern.getKind()==INST_CONSTANT ){
+ bool addToPrev = m.get( d_var_num[0] ).isNull();
+ if( !m.set( qe, d_var_num[0], t ) ){
+ success = false;
+ }else{
+ if( addToPrev ){
+ prev.push_back( d_var_num[0] );
+ }
+ }
//for relational matching
- if( !d_eq_class.isNull() && d_eq_class.getKind()==INST_CONSTANT ){
+ }else if( !d_eq_class.isNull() && d_eq_class.getKind()==INST_CONSTANT ){
int v = d_eq_class.getAttribute(InstVarNumAttribute());
//also must fit match to equivalence class
bool pol = d_pattern.getKind()!=NOT;
@@ -236,18 +248,9 @@ bool InstMatchGenerator::getMatch( Node f, Node t, InstMatch& m, QuantifiersEngi
//now, fit children into match
//we will be requesting candidates for matching terms for each child
for( int i=0; i<(int)d_children.size(); i++ ){
- Node rep = q->getRepresentative( t[ d_children_index[i] ] );
- d_children[i]->reset( rep, qe );
- }
- if( d_next!=NULL ){
- success = d_next->getNextMatch( f, m, qe );
- }else{
- if( d_active_add ){
- Trace("active-add") << "Active Adding instantiation " << m << std::endl;
- success = qe->addInstantiation( f, m, false );
- Trace("active-add") << "Success = " << success << std::endl;
- }
+ d_children[i]->reset( t[ d_children_index[i] ], qe );
}
+ success = continueNextMatch( f, m, qe );
}
if( !success ){
//m = InstMatch( &prev );
@@ -259,6 +262,18 @@ bool InstMatchGenerator::getMatch( Node f, Node t, InstMatch& m, QuantifiersEngi
}
}
+bool InstMatchGenerator::continueNextMatch( Node f, InstMatch& m, QuantifiersEngine* qe ){
+ if( d_next!=NULL ){
+ return d_next->getNextMatch( f, m, qe );
+ }else{
+ if( d_active_add ){
+ return qe->addInstantiation( f, m, false );
+ }else{
+ return true;
+ }
+ }
+}
+
/** reset instantiation round */
void InstMatchGenerator::resetInstantiationRound( QuantifiersEngine* qe ){
if( !d_match_pattern.isNull() ){
@@ -274,6 +289,7 @@ void InstMatchGenerator::resetInstantiationRound( QuantifiersEngine* qe ){
}
void InstMatchGenerator::reset( Node eqc, QuantifiersEngine* qe ){
+ eqc = qe->getEqualityQuery()->getRepresentative( eqc );
Trace("matching-debug2") << this << " reset " << eqc << "." << std::endl;
if( !eqc.isNull() ){
d_eq_class = eqc;
@@ -384,6 +400,59 @@ InstMatchGenerator* InstMatchGenerator::mkInstMatchGenerator( std::vector< Node
return oinit;
}
+VarMatchGeneratorBooleanTerm::VarMatchGeneratorBooleanTerm( Node var, Node comp ) :
+ InstMatchGenerator(), d_comp( comp ), d_rm_prev( false ) {
+ d_var_num[0] = var.getAttribute(InstVarNumAttribute());
+}
+
+bool VarMatchGeneratorBooleanTerm::getNextMatch( Node f, InstMatch& m, QuantifiersEngine* qe ) {
+ if( !d_eq_class.isNull() ){
+ Node s = NodeManager::currentNM()->mkConst(qe->getEqualityQuery()->areEqual( d_eq_class, d_pattern ));
+ d_eq_class = Node::null();
+ d_rm_prev = m.get( d_var_num[0] ).isNull();
+ if( !m.set( qe, d_var_num[0], s ) ){
+ return false;
+ }else{
+ if( continueNextMatch( f, m, qe ) ){
+ return true;
+ }
+ }
+ }
+ if( d_rm_prev ){
+ m.d_vals[d_var_num[0]] = Node::null();
+ d_rm_prev = false;
+ }
+ return false;
+}
+
+VarMatchGeneratorTermSubs::VarMatchGeneratorTermSubs( Node var, Node subs ) :
+ InstMatchGenerator(), d_var( var ), d_subs( subs ), d_rm_prev( false ){
+ d_var_num[0] = d_var.getAttribute(InstVarNumAttribute());
+}
+
+bool VarMatchGeneratorTermSubs::getNextMatch( Node f, InstMatch& m, QuantifiersEngine* qe ) {
+ if( !d_eq_class.isNull() ){
+ Trace("var-trigger-matching") << "Matching " << d_eq_class << " against " << d_var << " in " << d_subs << std::endl;
+ Node s = d_subs.substitute( d_var, d_eq_class );
+ s = Rewriter::rewrite( s );
+ Trace("var-trigger-matching") << "...got " << s << std::endl;
+ d_eq_class = Node::null();
+ d_rm_prev = m.get( d_var_num[0] ).isNull();
+ if( !m.set( qe, d_var_num[0], s ) ){
+ return false;
+ }else{
+ if( continueNextMatch( f, m, qe ) ){
+ return true;
+ }
+ }
+ }
+ if( d_rm_prev ){
+ m.d_vals[d_var_num[0]] = Node::null();
+ d_rm_prev = false;
+ }
+ return false;
+}
+
/** constructors */
InstMatchGeneratorMulti::InstMatchGeneratorMulti( Node f, std::vector< Node >& pats, QuantifiersEngine* qe, int matchOption ) :
d_f( f ){
@@ -618,13 +687,7 @@ int InstMatchGeneratorSimple::addInstantiations( Node f, InstMatch& baseMatch, Q
m.add( baseMatch );
int addedLemmas = 0;
- if( d_match_pattern.getType()==NodeManager::currentNM()->booleanType() ){
- for( int i=0; i<2; i++ ){
- addInstantiations( m, qe, addedLemmas, 0, &(qe->getTermDatabase()->d_pred_map_trie[i][ d_op ]) );
- }
- }else{
- addInstantiations( m, qe, addedLemmas, 0, &(qe->getTermDatabase()->d_func_map_trie[ d_op ]) );
- }
+ addInstantiations( m, qe, addedLemmas, 0, &(qe->getTermDatabase()->d_func_map_trie[ d_op ]) );
return addedLemmas;
}
@@ -646,7 +709,7 @@ void InstMatchGeneratorSimple::addInstantiations( InstMatch& m, QuantifiersEngin
}else{
if( d_match_pattern[argIndex].getKind()==INST_CONSTANT ){
int v = d_var_num[argIndex];
- for( std::map< Node, quantifiers::TermArgTrie >::iterator it = tat->d_data.begin(); it != tat->d_data.end(); ++it ){
+ for( std::map< TNode, quantifiers::TermArgTrie >::iterator it = tat->d_data.begin(); it != tat->d_data.end(); ++it ){
Node t = it->first;
Node prev = m.get( v );
//using representatives, just check if equal
@@ -658,7 +721,7 @@ void InstMatchGeneratorSimple::addInstantiations( InstMatch& m, QuantifiersEngin
}
}else{
Node r = qe->getEqualityQuery()->getRepresentative( d_match_pattern[argIndex] );
- std::map< Node, quantifiers::TermArgTrie >::iterator it = tat->d_data.find( r );
+ std::map< TNode, quantifiers::TermArgTrie >::iterator it = tat->d_data.find( r );
if( it!=tat->d_data.end() ){
addInstantiations( m, qe, addedLemmas, argIndex+1, &(it->second) );
}
diff --git a/src/theory/quantifiers/inst_match_generator.h b/src/theory/quantifiers/inst_match_generator.h
index 56eaf2c17..aa5d37713 100644
--- a/src/theory/quantifiers/inst_match_generator.h
+++ b/src/theory/quantifiers/inst_match_generator.h
@@ -42,7 +42,7 @@ public:
/** add instantiations directly */
virtual int addInstantiations( Node f, InstMatch& baseMatch, QuantifiersEngine* qe ) = 0;
/** add ground term t, called when t is added to term db */
- virtual int addTerm( Node f, Node t, QuantifiersEngine* qe ) = 0;
+ virtual int addTerm( Node f, Node t, QuantifiersEngine* qe ) { return 0; }
/** set active add */
virtual void setActiveAdd( bool val ) {}
};/* class IMGenerator */
@@ -50,7 +50,7 @@ public:
class CandidateGenerator;
class InstMatchGenerator : public IMGenerator {
-private:
+protected:
bool d_needsReset;
/** candidate generator */
CandidateGenerator* d_cg;
@@ -63,17 +63,18 @@ private:
InstMatchGenerator* d_next;
/** eq class */
Node d_eq_class;
- /** for arithmetic matching */
- std::map< Node, Node > d_arith_coeffs;
/** variable numbers */
std::map< int, int > d_var_num;
/** initialize pattern */
void initialize( QuantifiersEngine* qe, std::vector< InstMatchGenerator * > & gens );
+ /** children types 0 : variable, 1 : child term, -1 : ground term */
+ std::vector< int > d_children_types;
+ /** continue */
+ bool continueNextMatch( Node f, InstMatch& m, QuantifiersEngine* qe );
public:
enum {
//options for producing matches
MATCH_GEN_DEFAULT = 0,
- MATCH_GEN_EFFICIENT_E_MATCH, //generate matches via Efficient E-matching for SMT solvers
//others (internally used)
MATCH_GEN_INTERNAL_ERROR,
};
@@ -85,7 +86,8 @@ public:
bool getMatch( Node f, Node t, InstMatch& m, QuantifiersEngine* qe );
/** constructors */
- InstMatchGenerator( Node pat, int matchOption = 0 );
+ InstMatchGenerator( Node pat );
+ InstMatchGenerator();
/** destructor */
~InstMatchGenerator(){}
/** The pattern we are producing matches for.
@@ -115,6 +117,39 @@ public:
static InstMatchGenerator* mkInstMatchGenerator( std::vector< Node >& pats, QuantifiersEngine* qe );
};/* class InstMatchGenerator */
+//match generator for boolean term ITEs
+class VarMatchGeneratorBooleanTerm : public InstMatchGenerator {
+public:
+ VarMatchGeneratorBooleanTerm( Node var, Node comp );
+ Node d_comp;
+ bool d_rm_prev;
+ /** reset instantiation round (call this at beginning of instantiation round) */
+ void resetInstantiationRound( QuantifiersEngine* qe ){}
+ /** reset, eqc is the equivalence class to search in (any if eqc=null) */
+ void reset( Node eqc, QuantifiersEngine* qe ){ d_eq_class = eqc; }
+ /** get the next match. must call reset( eqc ) before this function. */
+ bool getNextMatch( Node f, InstMatch& m, QuantifiersEngine* qe );
+ /** add instantiations directly */
+ int addInstantiations( Node f, InstMatch& baseMatch, QuantifiersEngine* qe ){ return 0; }
+};
+
+//match generator for purified terms (matched term is substituted into d_subs)
+class VarMatchGeneratorTermSubs : public InstMatchGenerator {
+public:
+ VarMatchGeneratorTermSubs( Node var, Node subs );
+ TNode d_var;
+ Node d_subs;
+ bool d_rm_prev;
+ /** reset instantiation round (call this at beginning of instantiation round) */
+ void resetInstantiationRound( QuantifiersEngine* qe ){}
+ /** reset, eqc is the equivalence class to search in (any if eqc=null) */
+ void reset( Node eqc, QuantifiersEngine* qe ){ d_eq_class = eqc; }
+ /** get the next match. must call reset( eqc ) before this function. */
+ bool getNextMatch( Node f, InstMatch& m, QuantifiersEngine* qe );
+ /** add instantiations directly */
+ int addInstantiations( Node f, InstMatch& baseMatch, QuantifiersEngine* qe ) { return 0; }
+};
+
/** smart multi-trigger implementation */
class InstMatchGeneratorMulti : public IMGenerator {
private:
diff --git a/src/theory/quantifiers/inst_strategy_e_matching.cpp b/src/theory/quantifiers/inst_strategy_e_matching.cpp
index 5b0fade71..a32e7f6b0 100644
--- a/src/theory/quantifiers/inst_strategy_e_matching.cpp
+++ b/src/theory/quantifiers/inst_strategy_e_matching.cpp
@@ -68,12 +68,12 @@ int InstStrategyUserPatterns::process( Node f, Theory::Effort effort, int e ){
for( int i=0; i<(int)d_user_gen[f].size(); i++ ){
bool processTrigger = true;
if( processTrigger ){
- //if( d_user_gen[f][i]->isMultiTrigger() )
- Trace("process-trigger") << " Process (user) " << (*d_user_gen[f][i]) << "..." << std::endl;
+ Trace("process-trigger") << " Process (user) ";
+ d_user_gen[f][i]->debugPrint("process-trigger");
+ Trace("process-trigger") << "..." << std::endl;
InstMatch baseMatch( f );
int numInst = d_user_gen[f][i]->addInstantiations( baseMatch );
- //if( d_user_gen[f][i]->isMultiTrigger() )
- Trace("process-trigger") << " Done, numInst = " << numInst << "." << std::endl;
+ Trace("process-trigger") << " Done, numInst = " << numInst << "." << std::endl;
d_quantEngine->getInstantiationEngine()->d_statistics.d_instantiations_user_patterns += numInst;
if( d_user_gen[f][i]->isMultiTrigger() ){
d_quantEngine->d_statistics.d_multi_trigger_instantiations += numInst;
@@ -88,18 +88,25 @@ int InstStrategyUserPatterns::process( Node f, Theory::Effort effort, int e ){
}
void InstStrategyUserPatterns::addUserPattern( Node f, Node pat ){
+ Assert( pat.getKind()==INST_PATTERN );
//add to generators
+ bool usable = true;
std::vector< Node > nodes;
for( int i=0; i<(int)pat.getNumChildren(); i++ ){
nodes.push_back( pat[i] );
+ if( pat[i].getKind()!=INST_CONSTANT && !Trigger::isUsableTrigger( pat[i], f ) ){
+ Trace("trigger-warn") << "User-provided trigger is not usable : " << pat << " because of " << pat[i] << std::endl;
+ usable = false;
+ break;
+ }
}
- if( Trigger::isUsableTrigger( nodes, f ) ){
+ if( usable ){
+ Trace("user-pat") << "Add user pattern: " << pat << " for " << f << std::endl;
//extend to literal matching
d_quantEngine->getPhaseReqTerms( f, nodes );
//check match option
int matchOption = 0;
- d_user_gen[f].push_back( Trigger::mkTrigger( d_quantEngine, f, nodes, matchOption, true, Trigger::TR_MAKE_NEW,
- options::smartTriggers() ) );
+ d_user_gen[f].push_back( Trigger::mkTrigger( d_quantEngine, f, nodes, matchOption, true, Trigger::TR_MAKE_NEW, options::smartTriggers() ) );
}
}
@@ -156,14 +163,12 @@ int InstStrategyAutoGenTriggers::process( Node f, Theory::Effort effort, int e )
bool processTrigger = itt->second;
if( processTrigger && d_processed_trigger[f].find( tr )==d_processed_trigger[f].end() ){
d_processed_trigger[f][tr] = true;
- //if( tr->isMultiTrigger() )
- Trace("process-trigger") << " Process ";
- tr->debugPrint("process-trigger");
- Trace("process-trigger") << "..." << std::endl;
+ Trace("process-trigger") << " Process ";
+ tr->debugPrint("process-trigger");
+ Trace("process-trigger") << "..." << std::endl;
InstMatch baseMatch( f );
int numInst = tr->addInstantiations( baseMatch );
- //if( tr->isMultiTrigger() )
- Trace("process-trigger") << " Done, numInst = " << numInst << "." << std::endl;
+ Trace("process-trigger") << " Done, numInst = " << numInst << "." << std::endl;
if( d_tr_strategy==Trigger::TS_MIN_TRIGGER ){
d_quantEngine->getInstantiationEngine()->d_statistics.d_instantiations_auto_gen_min += numInst;
}else{
@@ -193,8 +198,8 @@ void InstStrategyAutoGenTriggers::generateTriggers( Node f, Theory::Effort effor
d_patTerms[0][f].clear();
d_patTerms[1][f].clear();
std::vector< Node > patTermsF;
- Trigger::collectPatTerms( d_quantEngine, f, d_quantEngine->getTermDatabase()->getInstConstantBody( f ), patTermsF, d_tr_strategy, true );
- Trace("auto-gen-trigger") << "Collected pat terms for " << d_quantEngine->getTermDatabase()->getInstConstantBody( f ) << std::endl;
+ Trigger::collectPatTerms( d_quantEngine, f, d_quantEngine->getTermDatabase()->getInstConstantBody( f ), patTermsF, d_tr_strategy, d_user_no_gen[f], true );
+ Trace("auto-gen-trigger") << "Collected pat terms for " << d_quantEngine->getTermDatabase()->getInstConstantBody( f ) << ", no-patterns : " << d_user_no_gen.size() << std::endl;
Trace("auto-gen-trigger") << " ";
for( int i=0; i<(int)patTermsF.size(); i++ ){
Trace("auto-gen-trigger") << patTermsF[i] << " ";
@@ -206,7 +211,7 @@ void InstStrategyAutoGenTriggers::generateTriggers( Node f, Theory::Effort effor
std::map< Node, std::vector< Node > > varContains;
d_quantEngine->getTermDatabase()->getVarContains( f, patTermsF, varContains );
for( std::map< Node, std::vector< Node > >::iterator it = varContains.begin(); it != varContains.end(); ++it ){
- if( it->second.size()==f[0].getNumChildren() ){
+ if( it->second.size()==f[0].getNumChildren() && !Trigger::isPureTheoryTrigger( it->first ) ){
d_patTerms[0][f].push_back( it->first );
d_is_single_trigger[ it->first ] = true;
}else{
@@ -342,6 +347,14 @@ void InstStrategyAutoGenTriggers::generateTriggers( Node f, Theory::Effort effor
}
}
+void InstStrategyAutoGenTriggers::addUserNoPattern( Node f, Node pat ) {
+ Assert( pat.getKind()==INST_NO_PATTERN && pat.getNumChildren()==1 );
+ if( std::find( d_user_no_gen[f].begin(), d_user_no_gen[f].end(), pat[0] )==d_user_no_gen[f].end() ){
+ Trace("user-pat") << "Add user no-pattern: " << pat[0] << " for " << f << std::endl;
+ d_user_no_gen[f].push_back( pat[0] );
+ }
+}
+
void InstStrategyFreeVariable::processResetInstantiationRound( Theory::Effort effort ){
}
diff --git a/src/theory/quantifiers/inst_strategy_e_matching.h b/src/theory/quantifiers/inst_strategy_e_matching.h
index 968194e49..53ca5bf78 100644
--- a/src/theory/quantifiers/inst_strategy_e_matching.h
+++ b/src/theory/quantifiers/inst_strategy_e_matching.h
@@ -80,6 +80,8 @@ private:
std::map< Node, bool > d_made_multi_trigger;
//processed trigger this round
std::map< Node, std::map< inst::Trigger*, bool > > d_processed_trigger;
+ //instantiation no patterns
+ std::map< Node, std::vector< Node > > d_user_no_gen;
private:
/** process functions */
void processResetInstantiationRound( Theory::Effort effort );
@@ -111,6 +113,8 @@ public:
}
/** set generate additional */
void setGenerateAdditional( bool val ) { d_generate_additional = val; }
+ /** add pattern */
+ void addUserNoPattern( Node f, Node pat );
};/* class InstStrategyAutoGenTriggers */
class InstStrategyFreeVariable : public InstStrategy{
diff --git a/src/theory/quantifiers/instantiation_engine.cpp b/src/theory/quantifiers/instantiation_engine.cpp
index 3dd4423de..7207ceefb 100644
--- a/src/theory/quantifiers/instantiation_engine.cpp
+++ b/src/theory/quantifiers/instantiation_engine.cpp
@@ -31,7 +31,7 @@ using namespace CVC4::theory::quantifiers;
using namespace CVC4::theory::inst;
InstantiationEngine::InstantiationEngine( QuantifiersEngine* qe, bool setIncomplete ) :
-QuantifiersModule( qe ), d_isup(NULL), d_i_ag(NULL), d_setIncomplete( setIncomplete ), d_ierCounter( 0 ), d_performCheck( false ){
+QuantifiersModule( qe ), d_isup(NULL), d_i_ag(NULL), d_setIncomplete( setIncomplete ), d_ierCounter( 0 ){
}
@@ -41,41 +41,45 @@ InstantiationEngine::~InstantiationEngine() {
}
void InstantiationEngine::finishInit(){
- //for UF terms
if( !options::finiteModelFind() || options::fmfInstEngine() ){
- //if( options::cbqi() ){
- // addInstStrategy( new InstStrategyCheckCESolved( this, d_quantEngine ) );
- //}
- //these are the instantiation strategies for basic E-matching
+
+ //these are the instantiation strategies for E-matching
+
+ //user-provided patterns
if( options::userPatternsQuant()!=USER_PAT_MODE_IGNORE ){
d_isup = new InstStrategyUserPatterns( d_quantEngine );
addInstStrategy( d_isup );
}else{
d_isup = NULL;
}
- d_i_ag = new InstStrategyAutoGenTriggers( d_quantEngine, Trigger::TS_ALL, 3 );
+
+ //auto-generated patterns
+ int tstrt = Trigger::TS_ALL;
+ if( options::triggerSelMode()==TRIGGER_SEL_MIN ){
+ tstrt = Trigger::TS_MIN_TRIGGER;
+ }else if( options::triggerSelMode()==TRIGGER_SEL_MAX ){
+ tstrt = Trigger::TS_MAX_TRIGGER;
+ }
+ d_i_ag = new InstStrategyAutoGenTriggers( d_quantEngine, tstrt, 3 );
d_i_ag->setGenerateAdditional( true );
addInstStrategy( d_i_ag );
- //addInstStrategy( new InstStrategyAddFailSplits( this, ie ) );
+
+ //full saturation : instantiate from relevant domain, then arbitrary terms
if( !options::finiteModelFind() && options::fullSaturateQuant() ){
addInstStrategy( new InstStrategyFreeVariable( d_quantEngine ) );
}
- //d_isup->setPriorityOver( d_i_ag );
- //d_isup->setPriorityOver( i_agm );
- //i_ag->setPriorityOver( i_agm );
}
- //for arithmetic
+
+ //counterexample-based quantifier instantiation
if( options::cbqi() ){
addInstStrategy( new InstStrategySimplex( (arith::TheoryArith*)d_quantEngine->getTheoryEngine()->theoryOf( THEORY_ARITH ), d_quantEngine ) );
- }
- //for datatypes
- //if( options::cbqi() ){
// addInstStrategy( new InstStrategyDatatypesValue( d_quantEngine ) );
- //}
+ }
}
bool InstantiationEngine::doInstantiationRound( Theory::Effort effort ){
+ unsigned lastWaiting = d_quantEngine->d_lemmas_waiting.size();
//if counterexample-based quantifier instantiation is active
if( options::cbqi() ){
//check if any cbqi lemma has not been added yet
@@ -149,7 +153,7 @@ bool InstantiationEngine::doInstantiationRound( Theory::Effort effort ){
}
}
//do not consider another level if already added lemma at this level
- if( d_quantEngine->hasAddedLemma() ){
+ if( d_quantEngine->d_lemmas_waiting.size()>lastWaiting ){
d_inst_round_status = InstStrategy::STATUS_UNKNOWN;
}
e++;
@@ -158,14 +162,11 @@ bool InstantiationEngine::doInstantiationRound( Theory::Effort effort ){
Debug("inst-engine") << (int)d_quantEngine->d_lemmas_waiting.size() << std::endl;
//Notice() << "All instantiators finished, # added lemmas = " << (int)d_lemmas_waiting.size() << std::endl;
if( !d_quantEngine->hasAddedLemma() ){
- Debug("inst-engine-stuck") << "No instantiations produced at this state." << std::endl;
Debug("inst-engine-ctrl") << "---Fail." << std::endl;
return false;
}else{
- Debug("inst-engine-ctrl") << "---Done. " << (int)d_quantEngine->d_lemmas_waiting.size() << std::endl;
- Trace("inst-engine") << "Added lemmas = " << (int)d_quantEngine->d_lemmas_waiting.size() << std::endl;
- //flush lemmas to output channel
- d_quantEngine->flushLemmas( &d_quantEngine->getOutputChannel() );
+ Debug("inst-engine-ctrl") << "---Done. " << (int)(d_quantEngine->d_lemmas_waiting.size()-lastWaiting) << std::endl;
+ Trace("inst-engine") << "Added lemmas = " << (int)(d_quantEngine->d_lemmas_waiting.size()-lastWaiting) << std::endl;
return true;
}
}
@@ -175,17 +176,17 @@ bool InstantiationEngine::needsCheck( Theory::Effort e ){
d_ierCounter++;
}
//determine if we should perform check, based on instWhenMode
- d_performCheck = false;
+ bool performCheck = false;
if( options::instWhenMode()==INST_WHEN_FULL ){
- d_performCheck = ( e >= Theory::EFFORT_FULL );
+ performCheck = ( e >= Theory::EFFORT_FULL );
}else if( options::instWhenMode()==INST_WHEN_FULL_DELAY ){
- d_performCheck = ( e >= Theory::EFFORT_FULL ) && !d_quantEngine->getTheoryEngine()->needCheck();
+ performCheck = ( e >= Theory::EFFORT_FULL ) && !d_quantEngine->getTheoryEngine()->needCheck();
}else if( options::instWhenMode()==INST_WHEN_FULL_LAST_CALL ){
- d_performCheck = ( ( e==Theory::EFFORT_FULL && d_ierCounter%2==0 ) || e==Theory::EFFORT_LAST_CALL );
+ performCheck = ( ( e==Theory::EFFORT_FULL && d_ierCounter%2==0 ) || e==Theory::EFFORT_LAST_CALL );
}else if( options::instWhenMode()==INST_WHEN_LAST_CALL ){
- d_performCheck = ( e >= Theory::EFFORT_LAST_CALL );
+ performCheck = ( e >= Theory::EFFORT_LAST_CALL );
}else{
- d_performCheck = true;
+ performCheck = true;
}
static int ierCounter2 = 0;
if( e==Theory::EFFORT_LAST_CALL ){
@@ -193,15 +194,14 @@ bool InstantiationEngine::needsCheck( Theory::Effort e ){
//with bounded integers, skip every other last call,
// since matching loops may occur with infinite quantification
if( ierCounter2%2==0 && options::fmfBoundInt() ){
- d_performCheck = false;
+ performCheck = false;
}
}
-
- return d_performCheck;
+ return performCheck;
}
-void InstantiationEngine::check( Theory::Effort e ){
- if( d_performCheck && !d_quantEngine->hasAddedLemma() ){
+void InstantiationEngine::check( Theory::Effort e, unsigned quant_e ){
+ if( quant_e==QuantifiersEngine::QEFFORT_STANDARD ){
Debug("inst-engine") << "IE: Check " << e << " " << d_ierCounter << std::endl;
double clSet = 0;
if( Trace.isOn("inst-engine") ){
@@ -211,12 +211,15 @@ void InstantiationEngine::check( Theory::Effort e ){
++(d_statistics.d_instantiation_rounds);
bool quantActive = false;
Debug("quantifiers") << "quantifiers: check: asserted quantifiers size="
- << d_quantEngine->getModel()->getNumAssertedQuantifiers() << std::endl;
+ << d_quantEngine->getModel()->getNumAssertedQuantifiers() << std::endl;
for( int i=0; i<(int)d_quantEngine->getModel()->getNumAssertedQuantifiers(); i++ ){
Node n = d_quantEngine->getModel()->getAssertedQuantifier( i );
- //it is not active if we have found the skolemized negation is unsat
+ //it is not active if it corresponds to a rewrite rule: we will process in rewrite engine
if( TermDb::isRewriteRule( n ) ){
d_quant_active[n] = false;
+ }else if( !d_quantEngine->getModel()->isQuantifierActive( n ) ){
+ d_quant_active[n] = false;
+ //it is not active if we have found the skolemized negation is unsat
}else if( options::cbqi() && hasAddedCbqiLemma( n ) ){
Node cel = d_quantEngine->getTermDatabase()->getCounterexampleLiteral( n );
bool active, value;
@@ -248,7 +251,6 @@ void InstantiationEngine::check( Theory::Effort e ){
Debug("quantifiers") << ", ce is asserted";
}
Debug("quantifiers") << std::endl;
- //it is not active if it corresponds to a rewrite rule: we will process in rewrite engine
}else{
d_quant_active[n] = true;
if( !TermDb::hasInstConstAttr(n) ){
@@ -313,7 +315,11 @@ void InstantiationEngine::registerQuantifier( Node f ){
//add patterns
for( int i=0; i<(int)subsPat.getNumChildren(); i++ ){
//Notice() << "Add pattern " << subsPat[i] << " for " << f << std::endl;
- addUserPattern( f, subsPat[i] );
+ if( subsPat[i].getKind()==INST_PATTERN ){
+ addUserPattern( f, subsPat[i] );
+ }else if( subsPat[i].getKind()==INST_NO_PATTERN ){
+ addUserNoPattern( f, subsPat[i] );
+ }
}
}
}
@@ -430,6 +436,12 @@ void InstantiationEngine::addUserPattern( Node f, Node pat ){
}
}
+void InstantiationEngine::addUserNoPattern( Node f, Node pat ){
+ if( d_i_ag ){
+ d_i_ag->addUserNoPattern( f, pat );
+ }
+}
+
InstantiationEngine::Statistics::Statistics():
d_instantiations_user_patterns("InstantiationEngine::Instantiations_User_Patterns", 0),
d_instantiations_auto_gen("InstantiationEngine::Instantiations_Auto_Gen", 0),
diff --git a/src/theory/quantifiers/instantiation_engine.h b/src/theory/quantifiers/instantiation_engine.h
index 7a3528217..bf0bb03e1 100644
--- a/src/theory/quantifiers/instantiation_engine.h
+++ b/src/theory/quantifiers/instantiation_engine.h
@@ -99,7 +99,6 @@ private:
bool d_setIncomplete;
/** inst round counter */
int d_ierCounter;
- bool d_performCheck;
/** whether each quantifier is active */
std::map< Node, bool > d_quant_active;
/** whether we have added cbqi lemma */
@@ -131,13 +130,14 @@ public:
void finishInit();
bool needsCheck( Theory::Effort e );
- void check( Theory::Effort e );
+ void check( Theory::Effort e, unsigned quant_e );
void registerQuantifier( Node f );
void assertNode( Node f );
Node explain(TNode n){ return Node::null(); }
Node getNextDecisionRequest();
/** add user pattern */
void addUserPattern( Node f, Node pat );
+ void addUserNoPattern( Node f, Node pat );
public:
/** statistics class */
class Statistics {
diff --git a/src/theory/quantifiers/kinds b/src/theory/quantifiers/kinds
index 6fb480c3d..1fda30301 100644
--- a/src/theory/quantifiers/kinds
+++ b/src/theory/quantifiers/kinds
@@ -33,6 +33,7 @@ sort INST_PATTERN_TYPE \
# This node is used for specifying hints for quantifier instantiation.
# An instantiation pattern may have more than 1 child, in which case it specifies a multi-trigger.
operator INST_PATTERN 1: "instantiation pattern"
+operator INST_NO_PATTERN 1 "instantiation no-pattern"
sort INST_PATTERN_LIST_TYPE \
Cardinality::INTEGERS \
@@ -46,6 +47,7 @@ typerule FORALL ::CVC4::theory::quantifiers::QuantifierForallTypeRule
typerule EXISTS ::CVC4::theory::quantifiers::QuantifierExistsTypeRule
typerule BOUND_VAR_LIST ::CVC4::theory::quantifiers::QuantifierBoundVarListTypeRule
typerule INST_PATTERN ::CVC4::theory::quantifiers::QuantifierInstPatternTypeRule
+typerule INST_NO_PATTERN ::CVC4::theory::quantifiers::QuantifierInstNoPatternTypeRule
typerule INST_PATTERN_LIST ::CVC4::theory::quantifiers::QuantifierInstPatternListTypeRule
# for rewrite rules
diff --git a/src/theory/quantifiers/macros.cpp b/src/theory/quantifiers/macros.cpp
index 11734c43f..7321e22b4 100644
--- a/src/theory/quantifiers/macros.cpp
+++ b/src/theory/quantifiers/macros.cpp
@@ -98,10 +98,14 @@ bool QuantifierMacros::isMacroLiteral( Node n, bool pol ){
bool QuantifierMacros::isBoundVarApplyUf( Node n ) {
Assert( n.getKind()==APPLY_UF );
+ TypeNode tn = n.getOperator().getType();
for( unsigned i=0; i<n.getNumChildren(); i++ ){
if( n[i].getKind()!=BOUND_VARIABLE ){
return false;
}
+ if( n[i].getType()!=tn[i] ){
+ return false;
+ }
for( unsigned j=0; j<i; j++ ){
if( n[j]==n[i] ){
return false;
diff --git a/src/theory/quantifiers/model_engine.cpp b/src/theory/quantifiers/model_engine.cpp
index d68c66535..9e5a8997b 100644
--- a/src/theory/quantifiers/model_engine.cpp
+++ b/src/theory/quantifiers/model_engine.cpp
@@ -35,7 +35,12 @@ using namespace CVC4::theory::inst;
//Model Engine constructor
ModelEngine::ModelEngine( context::Context* c, QuantifiersEngine* qe ) :
-QuantifiersModule( qe ){
+QuantifiersModule( qe ),
+d_incomplete_check(false),
+d_addedLemmas(0),
+d_triedLemmas(0),
+d_totalLemmas(0)
+{
Trace("model-engine-debug") << "Initialize model engine, mbqi : " << options::mbqiMode() << " " << options::fmfBoundInt() << std::endl;
if( options::mbqiMode()==MBQI_FMC || options::mbqiMode()==quantifiers::MBQI_FMC_INTERVAL ||
@@ -61,8 +66,12 @@ ModelEngine::~ModelEngine() {
delete d_builder;
}
-void ModelEngine::check( Theory::Effort e ){
- if( e==Theory::EFFORT_LAST_CALL && !d_quantEngine->hasAddedLemma() ){
+bool ModelEngine::needsCheck( Theory::Effort e ) {
+ return e==Theory::EFFORT_LAST_CALL;
+}
+
+void ModelEngine::check( Theory::Effort e, unsigned quant_e ){
+ if( quant_e==QuantifiersEngine::QEFFORT_MODEL ){
int addedLemmas = 0;
bool needsBuild = true;
FirstOrderModel* fm = d_quantEngine->getModel();
@@ -94,7 +103,8 @@ void ModelEngine::check( Theory::Effort e ){
Trace("model-engine-debug") << "Verify uf ss is minimal..." << std::endl;
//let the strong solver verify that the model is minimal
//for debugging, this will if there are terms in the model that the strong solver was not notified of
- if( ((uf::TheoryUF*)d_quantEngine->getTheoryEngine()->theoryOf( THEORY_UF ))->getStrongSolver()->debugModel( fm ) ){
+ uf::StrongSolverTheoryUF * ufss = ((uf::TheoryUF*)d_quantEngine->getTheoryEngine()->theoryOf( THEORY_UF ))->getStrongSolver();
+ if( !ufss || ufss->debugModel( fm ) ){
Trace("model-engine-debug") << "Check model..." << std::endl;
d_incomplete_check = false;
//print debug
@@ -140,7 +150,6 @@ void ModelEngine::check( Theory::Effort e ){
}
}else{
//otherwise, the search will continue
- d_quantEngine->flushLemmas( &d_quantEngine->getOutputChannel() );
}
}
}
diff --git a/src/theory/quantifiers/model_engine.h b/src/theory/quantifiers/model_engine.h
index caf27f691..890af1643 100644
--- a/src/theory/quantifiers/model_engine.h
+++ b/src/theory/quantifiers/model_engine.h
@@ -52,7 +52,8 @@ public:
//get the builder
QModelBuilder* getModelBuilder() { return d_builder; }
public:
- void check( Theory::Effort e );
+ bool needsCheck( Theory::Effort e );
+ void check( Theory::Effort e, unsigned quant_e );
void registerQuantifier( Node f );
void assertNode( Node f );
Node explain(TNode n){ return Node::null(); }
diff --git a/src/theory/quantifiers/modes.h b/src/theory/quantifiers/modes.h
index 112e052c2..26978c8f9 100644
--- a/src/theory/quantifiers/modes.h
+++ b/src/theory/quantifiers/modes.h
@@ -107,6 +107,15 @@ typedef enum {
USER_PAT_MODE_IGNORE,
} UserPatMode;
+typedef enum {
+ /** default for trigger selection */
+ TRIGGER_SEL_DEFAULT,
+ /** only consider minimal terms for triggers */
+ TRIGGER_SEL_MIN,
+ /** only consider maximal terms for triggers */
+ TRIGGER_SEL_MAX,
+} TriggerSelMode;
+
}/* CVC4::theory::quantifiers namespace */
}/* CVC4::theory namespace */
diff --git a/src/theory/quantifiers/options b/src/theory/quantifiers/options
index 1cdf5e8bd..162bbc158 100644
--- a/src/theory/quantifiers/options
+++ b/src/theory/quantifiers/options
@@ -26,6 +26,8 @@ option prenexQuant /--disable-prenex-quant bool :default true
# forall y. P( c, y )
option varElimQuant /--disable-var-elim-quant bool :default true
disable simple variable elimination for quantified formulas
+option dtVarExpandQuant --dt-var-exp-quant bool :default true
+ expand datatype variables bound to one constructor in quantifiers
option simpleIteLiftQuant /--disable-ite-lift-quant bool :default true
disable simple ite lifting for quantified formulas
@@ -63,6 +65,10 @@ option relevantTriggers --relevant-triggers bool :default false
prefer triggers that are more relevant based on SInE style analysis
option relationalTriggers --relational-triggers bool :default false
choose relational triggers such as x = f(y), x >= f(y)
+option purifyTriggers --purify-triggers bool :default false :read-write
+ purify triggers, e.g. f( x+1 ) becomes f( y ), x mapsto y-1
+option triggerSelMode --trigger-sel CVC4::theory::quantifiers::TriggerSelMode :default CVC4::theory::quantifiers::TRIGGER_SEL_DEFAULT :read-write :include "theory/quantifiers/modes.h" :handler CVC4::theory::quantifiers::stringToTriggerSelMode :handler-include "theory/quantifiers/options_handlers.h"
+ selection mode for triggers
# Whether to consider terms in the bodies of quantifiers for matching
option registerQuantBodyTerms --register-quant-body-terms bool :default false
@@ -72,10 +78,15 @@ option instWhenMode --inst-when=MODE CVC4::theory::quantifiers::InstWhenMode :de
when to apply instantiation
option instMaxLevel --inst-max-level=N int :default -1
maximum inst level of terms used to instantiate quantified formulas with (-1 == no limit, default)
+option instLevelInputOnly --inst-level-input-only bool :default true
+ only input terms are assigned instantiation level zero
option eagerInstQuant --eager-inst-quant bool :default false
apply quantifier instantiation eagerly
+option instNoEntail --inst-no-entail bool :read-write :default false
+ do not consider instances of quantified formulas that are currently entailed
+
option fullSaturateQuant --full-saturate-quant bool :default false
when all other quantifier instantiation strategies fail, instantiate with ground terms from relevant domain, then arbitrary ground terms before answering unknown
@@ -139,7 +150,27 @@ option quantRewriteRules --rewrite-rules bool :default true
option rrOneInstPerRound --rr-one-inst-per-round bool :default false
add one instance of rewrite rule per round
-option dtStcInduction --dt-stc-ind bool :default false
+option quantInduction --quant-ind bool :default false
+ use all available techniques for inductive reasoning
+option dtStcInduction --dt-stc-ind bool :read-write :default false
apply strengthening for existential quantification over datatypes based on structural induction
-
+option intWfInduction --int-wf-ind bool :read-write :default false
+ apply strengthening for integers based on well-founded induction
+option conjectureGen --conjecture-gen bool :read-write :default false
+ generate candidate conjectures for inductive proofs
+
+option conjectureGenPerRound --conjecture-gen-per-round=N int :default 1
+ number of conjectures to generate per instantiation round
+option conjectureNoFilter --conjecture-no-filter bool :default false
+ do not filter conjectures
+option conjectureFilterActiveTerms --conjecture-filter-active-terms bool :read-write :default true
+ filter based on active terms
+option conjectureFilterCanonical --conjecture-filter-canonical bool :read-write :default true
+ filter based on canonicity
+option conjectureFilterModel --conjecture-filter-model bool :read-write :default true
+ filter based on model
+option conjectureGenGtEnum --conjecture-gen-gt-enum=N int :default 0
+ number of ground terms to generate for model filtering
+option conjectureUeeIntro --conjecture-gen-uee-intro bool :default false
+ more aggressive merging for universal equality engine, introduces terms
endmodule
diff --git a/src/theory/quantifiers/options_handlers.h b/src/theory/quantifiers/options_handlers.h
index 38567d166..97eaf4aaa 100644
--- a/src/theory/quantifiers/options_handlers.h
+++ b/src/theory/quantifiers/options_handlers.h
@@ -152,6 +152,19 @@ ignore \n\
+ Ignore user-provided patterns. \n\
\n\
";
+static const std::string triggerSelModeHelp = "\
+Trigger selection modes currently supported by the --trigger-sel option:\n\
+\n\
+default \n\
++ Default, consider all subterms of quantified formulas for trigger selection.\n\
+\n\
+min \n\
++ Consider only minimal subterms that meet criteria for triggers.\n\
+\n\
+max \n\
++ Consider only maximal subterms that meet criteria for triggers. \n\
+\n\
+";
inline InstWhenMode stringToInstWhenMode(std::string option, std::string optarg, SmtEngine* smt) throw(OptionException) {
if(optarg == "pre-full") {
return INST_WHEN_PRE_FULL;
@@ -296,6 +309,21 @@ inline UserPatMode stringToUserPatMode(std::string option, std::string optarg, S
optarg + "'. Try --user-pat help.");
}
}
+inline TriggerSelMode stringToTriggerSelMode(std::string option, std::string optarg, SmtEngine* smt) throw(OptionException) {
+ if(optarg == "default" || optarg == "all" ) {
+ return TRIGGER_SEL_DEFAULT;
+ } else if(optarg == "min") {
+ return TRIGGER_SEL_MIN;
+ } else if(optarg == "max") {
+ return TRIGGER_SEL_MAX;
+ } else if(optarg == "help") {
+ puts(triggerSelModeHelp.c_str());
+ exit(1);
+ } else {
+ throw OptionException(std::string("unknown option for --trigger-sel: `") +
+ optarg + "'. Try --trigger-sel help.");
+ }
+}
}/* CVC4::theory::quantifiers namespace */
}/* CVC4::theory namespace */
}/* CVC4 namespace */
diff --git a/src/theory/quantifiers/quant_conflict_find.cpp b/src/theory/quantifiers/quant_conflict_find.cpp
index c6e881986..ee4464f87 100644..100755
--- a/src/theory/quantifiers/quant_conflict_find.cpp
+++ b/src/theory/quantifiers/quant_conflict_find.cpp
@@ -1,2529 +1,2246 @@
-/********************* */
-/*! \file quant_conflict_find.cpp
- ** \verbatim
- ** Original author: Andrew Reynolds
- ** Major contributors: Morgan Deters
- ** Minor contributors (to current version): none
- ** This file is part of the CVC4 project.
- ** Copyright (c) 2009-2014 New York University and The University of Iowa
- ** See the file COPYING in the top-level source directory for licensing
- ** information.\endverbatim
- **
- ** \brief quant conflict find class
- **
- **/
-
-#include <vector>
-
-#include "theory/quantifiers/quant_conflict_find.h"
-#include "theory/quantifiers/quant_util.h"
-#include "theory/theory_engine.h"
-#include "theory/quantifiers/options.h"
-#include "theory/quantifiers/term_database.h"
-#include "theory/quantifiers/trigger.h"
-
-using namespace CVC4;
-using namespace CVC4::kind;
-using namespace CVC4::theory;
-using namespace CVC4::theory::quantifiers;
-using namespace std;
-
-namespace CVC4 {
-
-Node QcfNodeIndex::existsTerm( TNode n, std::vector< TNode >& reps, int index ) {
- if( index==(int)reps.size() ){
- if( d_children.empty() ){
- return Node::null();
- }else{
- return d_children.begin()->first;
- }
- }else{
- std::map< TNode, QcfNodeIndex >::iterator it = d_children.find( reps[index] );
- if( it==d_children.end() ){
- return Node::null();
- }else{
- return it->second.existsTerm( n, reps, index+1 );
- }
- }
-}
-
-Node QcfNodeIndex::addTerm( TNode n, std::vector< TNode >& reps, int index ) {
- if( index==(int)reps.size() ){
- if( d_children.empty() ){
- d_children[ n ].clear();
- return n;
- }else{
- return d_children.begin()->first;
- }
- }else{
- return d_children[reps[index]].addTerm( n, reps, index+1 );
- }
-}
-
-
-void QcfNodeIndex::debugPrint( const char * c, int t ) {
- for( std::map< TNode, QcfNodeIndex >::iterator it = d_children.begin(); it != d_children.end(); ++it ){
- if( !it->first.isNull() ){
- for( int j=0; j<t; j++ ){ Trace(c) << " "; }
- Trace(c) << it->first << " : " << std::endl;
- it->second.debugPrint( c, t+1 );
- }
- }
-}
-
-
-void QuantInfo::initialize( Node q, Node qn ) {
- d_q = q;
- for( unsigned i=0; i<q[0].getNumChildren(); i++ ){
- d_match.push_back( TNode::null() );
- d_match_term.push_back( TNode::null() );
- }
-
- //register the variables
- for( unsigned i=0; i<q[0].getNumChildren(); i++ ){
- d_var_num[q[0][i]] = i;
- d_vars.push_back( q[0][i] );
- }
-
- registerNode( qn, true, true );
-
-
- Trace("qcf-qregister") << "- Make match gen structure..." << std::endl;
- d_mg = new MatchGen( this, qn );
-
- if( d_mg->isValid() ){
- /*
- for( unsigned j=0; j<q[0].getNumChildren(); j++ ){
- if( d_inMatchConstraint.find( q[0][j] )==d_inMatchConstraint.end() ){
- Trace("qcf-invalid") << "QCF invalid : variable " << q[0][j] << " does not exist in a matching constraint." << std::endl;
- d_mg->setInvalid();
- break;
- }
- }
- */
- if( d_mg->isValid() ){
- for( unsigned j=q[0].getNumChildren(); j<d_vars.size(); j++ ){
- if( d_vars[j].getKind()!=BOUND_VARIABLE ){
- d_var_mg[j] = NULL;
- bool is_tsym = false;
- if( !MatchGen::isHandledUfTerm( d_vars[j] ) && d_vars[j].getKind()!=ITE ){
- is_tsym = true;
- d_tsym_vars.push_back( j );
- }
- if( !is_tsym || options::qcfTConstraint() ){
- d_var_mg[j] = new MatchGen( this, d_vars[j], true );
- }
- if( !d_var_mg[j] || !d_var_mg[j]->isValid() ){
- Trace("qcf-invalid") << "QCF invalid : cannot match for " << d_vars[j] << std::endl;
- d_mg->setInvalid();
- break;
- }else{
- std::vector< int > bvars;
- d_var_mg[j]->determineVariableOrder( this, bvars );
- }
- }
- }
- if( d_mg->isValid() ){
- std::vector< int > bvars;
- d_mg->determineVariableOrder( this, bvars );
- }
- }
- }else{
- Trace("qcf-invalid") << "QCF invalid : body of formula cannot be processed." << std::endl;
- }
- Trace("qcf-qregister-summary") << "QCF register : " << ( d_mg->isValid() ? "VALID " : "INVALID" ) << " : " << q << std::endl;
-}
-
-void QuantInfo::registerNode( Node n, bool hasPol, bool pol, bool beneathQuant ) {
- Trace("qcf-qregister-debug2") << "Register : " << n << std::endl;
- if( n.getKind()==FORALL ){
- registerNode( n[1], hasPol, pol, true );
- }else{
- if( !MatchGen::isHandledBoolConnective( n ) ){
- if( n.hasBoundVar() ){
- //literals
- if( n.getKind()==EQUAL ){
- for( unsigned i=0; i<n.getNumChildren(); i++ ){
- flatten( n[i], beneathQuant );
- }
- }else if( MatchGen::isHandledUfTerm( n ) ){
- flatten( n, beneathQuant );
- }else if( n.getKind()==ITE ){
- for( unsigned i=1; i<=2; i++ ){
- flatten( n[i], beneathQuant );
- }
- registerNode( n[0], false, pol, beneathQuant );
- }else if( options::qcfTConstraint() ){
- //a theory-specific predicate
- for( unsigned i=0; i<n.getNumChildren(); i++ ){
- flatten( n[i], beneathQuant );
- }
- }
- }
- }else{
- for( unsigned i=0; i<n.getNumChildren(); i++ ){
- bool newHasPol;
- bool newPol;
- QuantPhaseReq::getPolarity( n, i, hasPol, pol, newHasPol, newPol );
- //QcfNode * qcfc = new QcfNode( d_c );
- //qcfc->d_parent = qcf;
- //qcf->d_child[i] = qcfc;
- registerNode( n[i], newHasPol, newPol, beneathQuant );
- }
- }
- }
-}
-
-void QuantInfo::flatten( Node n, bool beneathQuant ) {
- Trace("qcf-qregister-debug2") << "Flatten : " << n << std::endl;
- if( n.hasBoundVar() ){
- if( n.getKind()==BOUND_VARIABLE ){
- d_inMatchConstraint[n] = true;
- }
- //if( MatchGen::isHandledUfTerm( n ) || n.getKind()==ITE ){
- if( d_var_num.find( n )==d_var_num.end() ){
- Trace("qcf-qregister-debug2") << "Add FLATTEN VAR : " << n << std::endl;
- d_var_num[n] = d_vars.size();
- d_vars.push_back( n );
- d_match.push_back( TNode::null() );
- d_match_term.push_back( TNode::null() );
- if( n.getKind()==ITE ){
- registerNode( n, false, false );
- }else{
- for( unsigned i=0; i<n.getNumChildren(); i++ ){
- flatten( n[i], beneathQuant );
- }
- }
- }else{
- Trace("qcf-qregister-debug2") << "...already processed" << std::endl;
- }
- }else{
- Trace("qcf-qregister-debug2") << "...is ground." << std::endl;
- }
-}
-
-
-void QuantInfo::reset_round( QuantConflictFind * p ) {
- for( unsigned i=0; i<d_match.size(); i++ ){
- d_match[i] = TNode::null();
- d_match_term[i] = TNode::null();
- }
- d_curr_var_deq.clear();
- d_tconstraints.clear();
- //add built-in variable constraints
- for( unsigned r=0; r<2; r++ ){
- for( std::map< int, std::vector< Node > >::iterator it = d_var_constraint[r].begin();
- it != d_var_constraint[r].end(); ++it ){
- for( unsigned j=0; j<it->second.size(); j++ ){
- Node rr = it->second[j];
- if( !isVar( rr ) ){
- rr = p->getRepresentative( rr );
- }
- if( addConstraint( p, it->first, rr, r==0 )==-1 ){
- d_var_constraint[0].clear();
- d_var_constraint[1].clear();
- //quantified formula is actually equivalent to true
- Trace("qcf-qregister") << "Quantifier is equivalent to true!!!" << std::endl;
- d_mg->d_children.clear();
- d_mg->d_n = NodeManager::currentNM()->mkConst( true );
- d_mg->d_type = MatchGen::typ_ground;
- return;
- }
- }
- }
- }
- d_mg->reset_round( p );
- for( std::map< int, MatchGen * >::iterator it = d_var_mg.begin(); it != d_var_mg.end(); ++it ){
- it->second->reset_round( p );
- }
- //now, reset for matching
- d_mg->reset( p, false, this );
-}
-
-int QuantInfo::getCurrentRepVar( int v ) {
- if( v!=-1 && !d_match[v].isNull() ){
- int vn = getVarNum( d_match[v] );
- if( vn!=-1 ){
- //int vr = getCurrentRepVar( vn );
- //d_match[v] = d_vars[vr];
- //return vr;
- return getCurrentRepVar( vn );
- }
- }
- return v;
-}
-
-TNode QuantInfo::getCurrentValue( TNode n ) {
- int v = getVarNum( n );
- if( v==-1 ){
- return n;
- }else{
- if( d_match[v].isNull() ){
- return n;
- }else{
- Assert( getVarNum( d_match[v] )!=v );
- return getCurrentValue( d_match[v] );
- }
- }
-}
-
-TNode QuantInfo::getCurrentExpValue( TNode n ) {
- int v = getVarNum( n );
- if( v==-1 ){
- return n;
- }else{
- if( d_match[v].isNull() ){
- return n;
- }else{
- Assert( getVarNum( d_match[v] )!=v );
- if( d_match_term[v].isNull() ){
- return getCurrentValue( d_match[v] );
- }else{
- return d_match_term[v];
- }
- }
- }
-}
-
-bool QuantInfo::getCurrentCanBeEqual( QuantConflictFind * p, int v, TNode n, bool chDiseq ) {
- //check disequalities
- std::map< int, std::map< TNode, int > >::iterator itd = d_curr_var_deq.find( v );
- if( itd!=d_curr_var_deq.end() ){
- for( std::map< TNode, int >::iterator it = itd->second.begin(); it != itd->second.end(); ++it ){
- Node cv = getCurrentValue( it->first );
- Debug("qcf-ccbe") << "compare " << cv << " " << n << std::endl;
- if( cv==n ){
- return false;
- }else if( chDiseq && !isVar( n ) && !isVar( cv ) ){
- //they must actually be disequal if we are looking for conflicts
- if( !p->areDisequal( n, cv ) ){
- //TODO : check for entailed disequal
-
- return false;
- }
- }
- }
- }
- return true;
-}
-
-int QuantInfo::addConstraint( QuantConflictFind * p, int v, TNode n, bool polarity ) {
- v = getCurrentRepVar( v );
- int vn = getVarNum( n );
- vn = vn==-1 ? -1 : getCurrentRepVar( vn );
- n = getCurrentValue( n );
- return addConstraint( p, v, n, vn, polarity, false );
-}
-
-int QuantInfo::addConstraint( QuantConflictFind * p, int v, TNode n, int vn, bool polarity, bool doRemove ) {
- //for handling equalities between variables, and disequalities involving variables
- Debug("qcf-match-debug") << "- " << (doRemove ? "un" : "" ) << "constrain : " << v << " -> " << n << " (cv=" << getCurrentValue( n ) << ")";
- Debug("qcf-match-debug") << ", (vn=" << vn << "), polarity = " << polarity << std::endl;
- Assert( doRemove || n==getCurrentValue( n ) );
- Assert( doRemove || v==getCurrentRepVar( v ) );
- Assert( doRemove || vn==getCurrentRepVar( getVarNum( n ) ) );
- if( polarity ){
- if( vn!=v ){
- if( doRemove ){
- if( vn!=-1 ){
- //if set to this in the opposite direction, clean up opposite instead
- // std::map< int, TNode >::iterator itmn = d_match.find( vn );
- if( d_match[vn]==d_vars[v] ){
- return addConstraint( p, vn, d_vars[v], v, true, true );
- }else{
- //unsetting variables equal
- std::map< int, std::map< TNode, int > >::iterator itd = d_curr_var_deq.find( vn );
- if( itd!=d_curr_var_deq.end() ){
- //remove disequalities owned by this
- std::vector< TNode > remDeq;
- for( std::map< TNode, int >::iterator it = itd->second.begin(); it != itd->second.end(); ++it ){
- if( it->second==v ){
- remDeq.push_back( it->first );
- }
- }
- for( unsigned i=0; i<remDeq.size(); i++ ){
- d_curr_var_deq[vn].erase( remDeq[i] );
- }
- }
- }
- }
- d_match[v] = TNode::null();
- return 1;
- }else{
- //std::map< int, TNode >::iterator itm = d_match.find( v );
-
- if( vn!=-1 ){
- Debug("qcf-match-debug") << " ...Variable bound to variable" << std::endl;
- //std::map< int, TNode >::iterator itmn = d_match.find( vn );
- if( d_match[v].isNull() ){
- //setting variables equal
- bool alreadySet = false;
- if( !d_match[vn].isNull() ){
- alreadySet = true;
- Assert( !isVar( d_match[vn] ) );
- }
-
- //copy or check disequalities
- std::map< int, std::map< TNode, int > >::iterator itd = d_curr_var_deq.find( v );
- if( itd!=d_curr_var_deq.end() ){
- for( std::map< TNode, int >::iterator it = itd->second.begin(); it != itd->second.end(); ++it ){
- Node dv = getCurrentValue( it->first );
- if( !alreadySet ){
- if( d_curr_var_deq[vn].find( dv )==d_curr_var_deq[vn].end() ){
- d_curr_var_deq[vn][dv] = v;
- }
- }else{
- if( !p->areMatchDisequal( d_match[vn], dv ) ){
- Debug("qcf-match-debug") << " -> fail, conflicting disequality" << std::endl;
- return -1;
- }
- }
- }
- }
- if( alreadySet ){
- n = getCurrentValue( n );
- }
- }else{
- if( d_match[vn].isNull() ){
- Debug("qcf-match-debug") << " ...Reverse direction" << std::endl;
- //set the opposite direction
- return addConstraint( p, vn, d_vars[v], v, true, false );
- }else{
- Debug("qcf-match-debug") << " -> Both variables bound, compare" << std::endl;
- //are they currently equal
- return p->areMatchEqual( d_match[v], d_match[vn] ) ? 0 : -1;
- }
- }
- }else{
- Debug("qcf-match-debug") << " ...Variable bound to ground" << std::endl;
- if( d_match[v].isNull() ){
- }else{
- //compare ground values
- Debug("qcf-match-debug") << " -> Ground value, compare " << d_match[v] << " "<< n << std::endl;
- return p->areMatchEqual( d_match[v], n ) ? 0 : -1;
- }
- }
- if( setMatch( p, v, n ) ){
- Debug("qcf-match-debug") << " -> success" << std::endl;
- return 1;
- }else{
- Debug("qcf-match-debug") << " -> fail, conflicting disequality" << std::endl;
- return -1;
- }
- }
- }else{
- Debug("qcf-match-debug") << " -> redundant, variable identity" << std::endl;
- return 0;
- }
- }else{
- if( vn==v ){
- Debug("qcf-match-debug") << " -> fail, variable identity" << std::endl;
- return -1;
- }else{
- if( doRemove ){
- Assert( d_curr_var_deq[v].find( n )!=d_curr_var_deq[v].end() );
- d_curr_var_deq[v].erase( n );
- return 1;
- }else{
- if( d_curr_var_deq[v].find( n )==d_curr_var_deq[v].end() ){
- //check if it respects equality
- //std::map< int, TNode >::iterator itm = d_match.find( v );
- if( !d_match[v].isNull() ){
- TNode nv = getCurrentValue( n );
- if( !p->areMatchDisequal( nv, d_match[v] ) ){
- Debug("qcf-match-debug") << " -> fail, conflicting disequality" << std::endl;
- return -1;
- }
- }
- d_curr_var_deq[v][n] = v;
- Debug("qcf-match-debug") << " -> success" << std::endl;
- return 1;
- }else{
- Debug("qcf-match-debug") << " -> redundant disequality" << std::endl;
- return 0;
- }
- }
- }
- }
-}
-
-bool QuantInfo::isConstrainedVar( int v ) {
- if( d_curr_var_deq.find( v )!=d_curr_var_deq.end() && !d_curr_var_deq[v].empty() ){
- return true;
- }else{
- Node vv = getVar( v );
- //for( std::map< int, TNode >::iterator it = d_match.begin(); it != d_match.end(); ++it ){
- for( unsigned i=0; i<d_match.size(); i++ ){
- if( d_match[i]==vv ){
- return true;
- }
- }
- for( std::map< int, std::map< TNode, int > >::iterator it = d_curr_var_deq.begin(); it != d_curr_var_deq.end(); ++it ){
- for( std::map< TNode, int >::iterator it2 = it->second.begin(); it2 != it->second.end(); ++it2 ){
- if( it2->first==vv ){
- return true;
- }
- }
- }
- return false;
- }
-}
-
-bool QuantInfo::setMatch( QuantConflictFind * p, int v, TNode n ) {
- if( getCurrentCanBeEqual( p, v, n ) ){
- Debug("qcf-match-debug") << "-- bind : " << v << " -> " << n << ", checked " << d_curr_var_deq[v].size() << " disequalities" << std::endl;
- d_match[v] = n;
- return true;
- }else{
- return false;
- }
-}
-
-bool QuantInfo::isMatchSpurious( QuantConflictFind * p ) {
- for( int i=0; i<getNumVars(); i++ ){
- //std::map< int, TNode >::iterator it = d_match.find( i );
- if( !d_match[i].isNull() ){
- if( !getCurrentCanBeEqual( p, i, d_match[i], p->d_effort==QuantConflictFind::effort_conflict ) ){
- return true;
- }
- }
- }
- return false;
-}
-
-bool QuantInfo::isTConstraintSpurious( QuantConflictFind * p, std::vector< Node >& terms ) {
- if( !d_tconstraints.empty() ){
- //check constraints
- for( std::map< Node, bool >::iterator it = d_tconstraints.begin(); it != d_tconstraints.end(); ++it ){
- //apply substitution to the tconstraint
- Node cons = it->first.substitute( p->getQuantifiersEngine()->getTermDatabase()->d_vars[d_q].begin(),
- p->getQuantifiersEngine()->getTermDatabase()->d_vars[d_q].end(),
- terms.begin(), terms.end() );
- cons = it->second ? cons : cons.negate();
- if( !entailmentTest( p, cons, p->d_effort==QuantConflictFind::effort_conflict ) ){
- return true;
- }
- }
- }
- return false;
-}
-
-bool QuantInfo::entailmentTest( QuantConflictFind * p, Node lit, bool chEnt ) {
- Trace("qcf-tconstraint-debug") << "Check : " << lit << std::endl;
- Node rew = Rewriter::rewrite( lit );
- if( rew==p->d_false ){
- Trace("qcf-tconstraint-debug") << "...constraint " << lit << " is disentailed (rewrites to false)." << std::endl;
- return false;
- }else if( rew!=p->d_true ){
- //if checking for conflicts, we must be sure that the constraint is entailed
- if( chEnt ){
- //check if it is entailed
- Trace("qcf-tconstraint-debug") << "Check entailment of " << rew << "..." << std::endl;
- std::pair<bool, Node> et = p->getQuantifiersEngine()->getTheoryEngine()->entailmentCheck(THEORY_OF_TYPE_BASED, rew );
- ++(p->d_statistics.d_entailment_checks);
- Trace("qcf-tconstraint-debug") << "ET result : " << et.first << " " << et.second << std::endl;
- if( !et.first ){
- Trace("qcf-tconstraint-debug") << "...cannot show entailment of " << rew << "." << std::endl;
- return false;
- }else{
- return true;
- }
- }else{
- Trace("qcf-tconstraint-debug") << "...does not need to be entailed." << std::endl;
- return true;
- }
- }else{
- Trace("qcf-tconstraint-debug") << "...rewrites to true." << std::endl;
- return true;
- }
-}
-
-bool QuantInfo::completeMatch( QuantConflictFind * p, std::vector< int >& assigned, bool doContinue ) {
- //assign values for variables that were unassigned (usually not necessary, but handles corner cases)
- bool doFail = false;
- bool success = true;
- if( doContinue ){
- doFail = true;
- success = false;
- }else{
- //solve for interpreted symbol matches
- // this breaks the invariant that all introduced constraints are over existing terms
- for( int i=(int)(d_tsym_vars.size()-1); i>=0; i-- ){
- int index = d_tsym_vars[i];
- TNode v = getCurrentValue( d_vars[index] );
- int slv_v = -1;
- if( v==d_vars[index] ){
- slv_v = index;
- }
- Trace("qcf-tconstraint-debug") << "Solve " << d_vars[index] << " = " << v << " " << d_vars[index].getKind() << std::endl;
- if( d_vars[index].getKind()==PLUS || d_vars[index].getKind()==MULT ){
- Kind k = d_vars[index].getKind();
- std::vector< TNode > children;
- for( unsigned j=0; j<d_vars[index].getNumChildren(); j++ ){
- int vn = getVarNum( d_vars[index][j] );
- if( vn!=-1 ){
- TNode vv = getCurrentValue( d_vars[index][j] );
- if( vv==d_vars[index][j] ){
- //we will assign this
- if( slv_v==-1 ){
- Trace("qcf-tconstraint-debug") << "...will solve for var #" << vn << std::endl;
- slv_v = vn;
- if( p->d_effort!=QuantConflictFind::effort_conflict ){
- break;
- }
- }else{
- Node z = p->getZero( k );
- if( !z.isNull() ){
- Trace("qcf-tconstraint-debug") << "...set " << d_vars[vn] << " = " << z << std::endl;
- assigned.push_back( vn );
- if( !setMatch( p, vn, z ) ){
- success = false;
- break;
- }
- }
- }
- }else{
- Trace("qcf-tconstraint-debug") << "...sum value " << vv << std::endl;
- children.push_back( vv );
- }
- }else{
- Trace("qcf-tconstraint-debug") << "...sum " << d_vars[index][j] << std::endl;
- children.push_back( d_vars[index][j] );
- }
- }
- if( success ){
- if( slv_v!=-1 ){
- Node lhs;
- if( children.empty() ){
- lhs = p->getZero( k );
- }else if( children.size()==1 ){
- lhs = children[0];
- }else{
- lhs = NodeManager::currentNM()->mkNode( k, children );
- }
- Node sum;
- if( v==d_vars[index] ){
- sum = lhs;
- }else{
- if( p->d_effort==QuantConflictFind::effort_conflict ){
- Kind kn = k;
- if( d_vars[index].getKind()==PLUS ){
- kn = MINUS;
- }
- if( kn!=k ){
- sum = NodeManager::currentNM()->mkNode( kn, v, lhs );
- }
- }
- }
- if( !sum.isNull() ){
- assigned.push_back( slv_v );
- Trace("qcf-tconstraint-debug") << "...set " << d_vars[slv_v] << " = " << sum << std::endl;
- if( !setMatch( p, slv_v, sum ) ){
- success = false;
- }
- p->d_tempCache.push_back( sum );
- }
- }else{
- //must show that constraint is met
- Node sum = NodeManager::currentNM()->mkNode( k, children );
- Node eq = sum.eqNode( v );
- if( !entailmentTest( p, eq ) ){
- success = false;
- }
- p->d_tempCache.push_back( sum );
- }
- }
- }
-
- if( !success ){
- break;
- }
- }
- if( success ){
- //check what is left to assign
- d_unassigned.clear();
- d_unassigned_tn.clear();
- std::vector< int > unassigned[2];
- std::vector< TypeNode > unassigned_tn[2];
- for( int i=0; i<getNumVars(); i++ ){
- if( d_match[i].isNull() ){
- int rindex = d_var_mg.find( i )==d_var_mg.end() ? 1 : 0;
- unassigned[rindex].push_back( i );
- unassigned_tn[rindex].push_back( getVar( i ).getType() );
- assigned.push_back( i );
- }
- }
- d_unassigned_nvar = unassigned[0].size();
- for( unsigned i=0; i<2; i++ ){
- d_unassigned.insert( d_unassigned.end(), unassigned[i].begin(), unassigned[i].end() );
- d_unassigned_tn.insert( d_unassigned_tn.end(), unassigned_tn[i].begin(), unassigned_tn[i].end() );
- }
- d_una_eqc_count.clear();
- d_una_index = 0;
- }
- }
-
- if( !d_unassigned.empty() && ( success || doContinue ) ){
- Trace("qcf-check") << "Assign to unassigned..." << std::endl;
- do {
- if( doFail ){
- Trace("qcf-check-unassign") << "Failure, try again..." << std::endl;
- }
- bool invalidMatch = false;
- while( ( d_una_index>=0 && (int)d_una_index<(int)d_unassigned.size() ) || invalidMatch || doFail ){
- invalidMatch = false;
- if( !doFail && d_una_index==(int)d_una_eqc_count.size() ){
- //check if it has now been assigned
- if( d_una_index<d_unassigned_nvar ){
- if( !isConstrainedVar( d_unassigned[d_una_index] ) ){
- d_una_eqc_count.push_back( -1 );
- }else{
- d_var_mg[ d_unassigned[d_una_index] ]->reset( p, true, this );
- d_una_eqc_count.push_back( 0 );
- }
- }else{
- d_una_eqc_count.push_back( 0 );
- }
- }else{
- bool failed = false;
- if( !doFail ){
- if( d_una_index<d_unassigned_nvar ){
- if( !isConstrainedVar( d_unassigned[d_una_index] ) ){
- Trace("qcf-check-unassign") << "Succeeded, variable unconstrained at " << d_una_index << std::endl;
- d_una_index++;
- }else if( d_var_mg[d_unassigned[d_una_index]]->getNextMatch( p, this ) ){
- Trace("qcf-check-unassign") << "Succeeded match with mg at " << d_una_index << std::endl;
- d_una_index++;
- }else{
- failed = true;
- Trace("qcf-check-unassign") << "Failed match with mg at " << d_una_index << std::endl;
- }
- }else{
- Assert( doFail || d_una_index==(int)d_una_eqc_count.size()-1 );
- if( d_una_eqc_count[d_una_index]<(int)p->d_eqcs[d_unassigned_tn[d_una_index]].size() ){
- int currIndex = d_una_eqc_count[d_una_index];
- d_una_eqc_count[d_una_index]++;
- Trace("qcf-check-unassign") << d_unassigned[d_una_index] << "->" << p->d_eqcs[d_unassigned_tn[d_una_index]][currIndex] << std::endl;
- if( setMatch( p, d_unassigned[d_una_index], p->d_eqcs[d_unassigned_tn[d_una_index]][currIndex] ) ){
- d_match_term[d_unassigned[d_una_index]] = TNode::null();
- Trace("qcf-check-unassign") << "Succeeded match " << d_una_index << std::endl;
- d_una_index++;
- }else{
- Trace("qcf-check-unassign") << "Failed match " << d_una_index << std::endl;
- invalidMatch = true;
- }
- }else{
- failed = true;
- Trace("qcf-check-unassign") << "No more matches " << d_una_index << std::endl;
- }
- }
- }
- if( doFail || failed ){
- do{
- if( !doFail ){
- d_una_eqc_count.pop_back();
- }else{
- doFail = false;
- }
- d_una_index--;
- }while( d_una_index>=0 && d_una_eqc_count[d_una_index]==-1 );
- }
- }
- }
- success = d_una_index>=0;
- if( success ){
- doFail = true;
- Trace("qcf-check-unassign") << " Try: " << std::endl;
- for( unsigned i=0; i<d_unassigned.size(); i++ ){
- int ui = d_unassigned[i];
- if( !d_match[ui].isNull() ){
- Trace("qcf-check-unassign") << " Assigned #" << ui << " : " << d_vars[ui] << " -> " << d_match[ui] << std::endl;
- }
- }
- }
- }while( success && isMatchSpurious( p ) );
- }
- if( success ){
- for( unsigned i=0; i<d_unassigned.size(); i++ ){
- int ui = d_unassigned[i];
- if( !d_match[ui].isNull() ){
- Trace("qcf-check") << " Assigned #" << ui << " : " << d_vars[ui] << " -> " << d_match[ui] << std::endl;
- }
- }
- return true;
- }else{
- for( unsigned i=0; i<assigned.size(); i++ ){
- d_match[ assigned[i] ] = TNode::null();
- }
- assigned.clear();
- return false;
- }
-}
-
-void QuantInfo::getMatch( std::vector< Node >& terms ){
- for( unsigned i=0; i<d_q[0].getNumChildren(); i++ ){
- //Node cv = qi->getCurrentValue( qi->d_match[i] );
- int repVar = getCurrentRepVar( i );
- Node cv;
- //std::map< int, TNode >::iterator itmt = qi->d_match_term.find( repVar );
- if( !d_match_term[repVar].isNull() ){
- cv = d_match_term[repVar];
- }else{
- cv = d_match[repVar];
- }
- Debug("qcf-check-inst") << "INST : " << i << " -> " << cv << ", from " << d_match[i] << std::endl;
- terms.push_back( cv );
- }
-}
-
-void QuantInfo::revertMatch( std::vector< int >& assigned ) {
- for( unsigned i=0; i<assigned.size(); i++ ){
- d_match[ assigned[i] ] = TNode::null();
- }
-}
-
-void QuantInfo::debugPrintMatch( const char * c ) {
- for( int i=0; i<getNumVars(); i++ ){
- Trace(c) << " " << d_vars[i] << " -> ";
- if( !d_match[i].isNull() ){
- Trace(c) << d_match[i];
- }else{
- Trace(c) << "(unassigned) ";
- }
- if( !d_curr_var_deq[i].empty() ){
- Trace(c) << ", DEQ{ ";
- for( std::map< TNode, int >::iterator it = d_curr_var_deq[i].begin(); it != d_curr_var_deq[i].end(); ++it ){
- Trace(c) << it->first << " ";
- }
- Trace(c) << "}";
- }
- if( !d_match_term[i].isNull() && d_match_term[i]!=d_match[i] ){
- Trace(c) << ", EXP : " << d_match_term[i];
- }
- Trace(c) << std::endl;
- }
- if( !d_tconstraints.empty() ){
- Trace(c) << "ADDITIONAL CONSTRAINTS : " << std::endl;
- for( std::map< Node, bool >::iterator it = d_tconstraints.begin(); it != d_tconstraints.end(); ++it ){
- Trace(c) << " " << it->first << " -> " << it->second << std::endl;
- }
- }
-}
-
-MatchGen::MatchGen( QuantInfo * qi, Node n, bool isVar ){
- Trace("qcf-qregister-debug") << "Make match gen for " << n << ", isVar = " << isVar << std::endl;
- std::vector< Node > qni_apps;
- d_qni_size = 0;
- if( isVar ){
- Assert( qi->d_var_num.find( n )!=qi->d_var_num.end() );
- if( n.getKind()==ITE ){
- d_type = typ_ite_var;
- d_type_not = false;
- d_n = n;
- d_children.push_back( MatchGen( qi, d_n[0] ) );
- if( d_children[0].isValid() ){
- d_type = typ_ite_var;
- for( unsigned i=1; i<=2; i++ ){
- Node nn = n.eqNode( n[i] );
- d_children.push_back( MatchGen( qi, nn ) );
- d_children[d_children.size()-1].d_qni_bound_except.push_back( 0 );
- if( !d_children[d_children.size()-1].isValid() ){
- setInvalid();
- break;
- }
- }
- }else{
- d_type = typ_invalid;
- }
- }else{
- d_type = isHandledUfTerm( n ) ? typ_var : typ_tsym;
- d_qni_var_num[0] = qi->getVarNum( n );
- d_qni_size++;
- d_type_not = false;
- d_n = n;
- //Node f = getOperator( n );
- for( unsigned j=0; j<d_n.getNumChildren(); j++ ){
- Node nn = d_n[j];
- Trace("qcf-qregister-debug") << " " << d_qni_size;
- if( qi->isVar( nn ) ){
- int v = qi->d_var_num[nn];
- Trace("qcf-qregister-debug") << " is var #" << v << std::endl;
- d_qni_var_num[d_qni_size] = v;
- //qi->addFuncParent( v, f, j );
- }else{
- Trace("qcf-qregister-debug") << " is gterm " << nn << std::endl;
- d_qni_gterm[d_qni_size] = nn;
- }
- d_qni_size++;
- }
- }
- }else{
- if( n.hasBoundVar() ){
- d_type_not = false;
- d_n = n;
- if( d_n.getKind()==NOT ){
- d_n = d_n[0];
- d_type_not = !d_type_not;
- }
-
- if( isHandledBoolConnective( d_n ) ){
- //non-literals
- d_type = typ_formula;
- for( unsigned i=0; i<d_n.getNumChildren(); i++ ){
- if( d_n.getKind()!=FORALL || i==1 ){
- d_children.push_back( MatchGen( qi, d_n[i], false ) );
- if( !d_children[d_children.size()-1].isValid() ){
- setInvalid();
- break;
- }
- }
- /*
- else if( isTop && n.getKind()==OR && d_children[d_children.size()-1].d_type==typ_var_eq ){
- Trace("qcf-qregister-debug") << "Remove child, make built-in constraint" << std::endl;
- //if variable equality/disequality at top level, remove immediately
- bool cIsNot = d_children[d_children.size()-1].d_type_not;
- Node cn = d_children[d_children.size()-1].d_n;
- Assert( cn.getKind()==EQUAL );
- Assert( p->d_qinfo[q].isVar( cn[0] ) || p->d_qinfo[q].isVar( cn[1] ) );
- //make it a built-in constraint instead
- for( unsigned i=0; i<2; i++ ){
- if( p->d_qinfo[q].isVar( cn[i] ) ){
- int v = p->d_qinfo[q].getVarNum( cn[i] );
- Node cno = cn[i==0 ? 1 : 0];
- p->d_qinfo[q].d_var_constraint[ cIsNot ? 0 : 1 ][v].push_back( cno );
- break;
- }
- }
- d_children.pop_back();
- }
- */
- }
- }else{
- d_type = typ_invalid;
- //literals
- if( isHandledUfTerm( d_n ) ){
- Assert( qi->isVar( d_n ) );
- d_type = typ_pred;
- }else if( d_n.getKind()==BOUND_VARIABLE ){
- Assert( d_n.getType().isBoolean() );
- d_type = typ_bool_var;
- }else if( d_n.getKind()==EQUAL || options::qcfTConstraint() ){
- for( unsigned i=0; i<d_n.getNumChildren(); i++ ){
- if( d_n[i].hasBoundVar() ){
- if( !qi->isVar( d_n[i] ) ){
- Trace("qcf-qregister-debug") << "ERROR : not var " << d_n[i] << std::endl;
- }
- Assert( qi->isVar( d_n[i] ) );
- if( d_n.getKind()!=EQUAL && qi->isVar( d_n[i] ) ){
- d_qni_var_num[i+1] = qi->d_var_num[d_n[i]];
- }
- }else{
- d_qni_gterm[i] = d_n[i];
- }
- }
- d_type = d_n.getKind()==EQUAL ? typ_eq : typ_tconstraint;
- Trace("qcf-tconstraint") << "T-Constraint : " << d_n << std::endl;
- }
- }
- }else{
- //we will just evaluate
- d_n = n;
- d_type = typ_ground;
- }
- //if( d_type!=typ_invalid ){
- //determine an efficient children ordering
- //if( !d_children.empty() ){
- //for( unsigned i=0; i<d_children.size(); i++ ){
- // d_children_order.push_back( i );
- //}
- //if( !d_n.isNull() && ( d_n.getKind()==OR || d_n.getKind()==AND || d_n.getKind()==IFF ) ){
- //sort based on the type of the constraint : ground comes first, then literals, then others
- //MatchGenSort mgs;
- //mgs.d_mg = this;
- //std::sort( d_children_order.begin(), d_children_order.end(), mgs );
- //}
- //}
- //}
- }
- Trace("qcf-qregister-debug") << "Done make match gen " << n << ", type = ";
- debugPrintType( "qcf-qregister-debug", d_type, true );
- Trace("qcf-qregister-debug") << std::endl;
- //Assert( d_children.size()==d_children_order.size() );
-
-}
-
-void MatchGen::collectBoundVar( QuantInfo * qi, Node n, std::vector< int >& cbvars ) {
- int v = qi->getVarNum( n );
- if( v!=-1 && std::find( cbvars.begin(), cbvars.end(), v )==cbvars.end() ){
- cbvars.push_back( v );
- }
- for( unsigned i=0; i<n.getNumChildren(); i++ ){
- collectBoundVar( qi, n[i], cbvars );
- }
-}
-
-void MatchGen::determineVariableOrder( QuantInfo * qi, std::vector< int >& bvars ) {
- Trace("qcf-qregister-debug") << "Determine variable order " << d_n << std::endl;
- bool isCom = d_type==typ_formula && ( d_n.getKind()==OR || d_n.getKind()==AND || d_n.getKind()==IFF );
- std::map< int, std::vector< int > > c_to_vars;
- std::map< int, std::vector< int > > vars_to_c;
- std::map< int, int > vb_count;
- std::map< int, int > vu_count;
- std::vector< bool > assigned;
- Trace("qcf-qregister-debug") << "Calculate bound variables..." << std::endl;
- for( unsigned i=0; i<d_children.size(); i++ ){
- collectBoundVar( qi, d_children[i].d_n, c_to_vars[i] );
- assigned.push_back( false );
- vb_count[i] = 0;
- vu_count[i] = 0;
- for( unsigned j=0; j<c_to_vars[i].size(); j++ ){
- int v = c_to_vars[i][j];
- vars_to_c[v].push_back( i );
- if( std::find( bvars.begin(), bvars.end(), v )==bvars.end() ){
- vu_count[i]++;
- if( !isCom ){
- bvars.push_back( v );
- }
- }else{
- vb_count[i]++;
- }
- }
- }
- if( isCom ){
- //children that bind the least number of unbound variables go first
- do {
- int min_score = -1;
- int min_score_index = -1;
- for( unsigned i=0; i<d_children.size(); i++ ){
- if( !assigned[i] ){
- int score = vu_count[i];
- if( min_score==-1 || score<min_score ){
- min_score = score;
- min_score_index = i;
- }
- }
- }
- Trace("qcf-qregister-debug") << "...assign child " << min_score_index << "/" << d_children.size() << std::endl;
- Assert( min_score_index!=-1 );
- //add to children order
- d_children_order.push_back( min_score_index );
- assigned[min_score_index] = true;
- //if( vb_count[min_score_index]==0 ){
- // d_independent.push_back( min_score_index );
- //}
- //determine order internal to children
- d_children[min_score_index].determineVariableOrder( qi, bvars );
- Trace("qcf-qregister-debug") << "...bind variables" << std::endl;
- //now, make it a bound variable
- for( unsigned i=0; i<c_to_vars[min_score_index].size(); i++ ){
- int v = c_to_vars[min_score_index][i];
- if( std::find( bvars.begin(), bvars.end(), v )==bvars.end() ){
- for( unsigned j=0; j<vars_to_c[v].size(); j++ ){
- int vc = vars_to_c[v][j];
- vu_count[vc]--;
- vb_count[vc]++;
- }
- bvars.push_back( v );
- }
- }
- Trace("qcf-qregister-debug") << "...done assign child " << min_score_index << std::endl;
- }while( d_children_order.size()!=d_children.size() );
- Trace("qcf-qregister-debug") << "Done assign variable ordering for " << d_n << std::endl;
- }else{
- for( unsigned i=0; i<d_children.size(); i++ ){
- d_children_order.push_back( i );
- d_children[i].determineVariableOrder( qi, bvars );
- }
- }
-}
-
-
-void MatchGen::reset_round( QuantConflictFind * p ) {
- d_wasSet = false;
- for( unsigned i=0; i<d_children.size(); i++ ){
- d_children[i].reset_round( p );
- }
- for( std::map< int, TNode >::iterator it = d_qni_gterm.begin(); it != d_qni_gterm.end(); ++it ){
- d_qni_gterm_rep[it->first] = p->getRepresentative( it->second );
- }
- if( d_type==typ_ground ){
- int e = p->evaluate( d_n );
- if( e==1 ){
- d_ground_eval[0] = p->d_true;
- }else if( e==-1 ){
- d_ground_eval[0] = p->d_false;
- }
- }else if( d_type==typ_eq ){
- for( unsigned i=0; i<d_n.getNumChildren(); i++ ){
- if( !d_n[i].hasBoundVar() ){
- d_ground_eval[i] = p->evaluateTerm( d_n[i] );
- }
- }
- }
- d_qni_bound_cons.clear();
- d_qni_bound_cons_var.clear();
- d_qni_bound.clear();
-}
-
-void MatchGen::reset( QuantConflictFind * p, bool tgt, QuantInfo * qi ) {
- d_tgt = d_type_not ? !tgt : tgt;
- Debug("qcf-match") << " Reset for : " << d_n << ", type : ";
- debugPrintType( "qcf-match", d_type );
- Debug("qcf-match") << ", tgt = " << d_tgt << ", children = " << d_children.size() << " " << d_children_order.size() << std::endl;
- d_qn.clear();
- d_qni.clear();
- d_qni_bound.clear();
- d_child_counter = -1;
- d_tgt_orig = d_tgt;
-
- //set up processing matches
- if( d_type==typ_invalid ){
- //do nothing
- }else if( d_type==typ_ground ){
- if( d_ground_eval[0]==( d_tgt ? p->d_true : p->d_false ) ){
- d_child_counter = 0;
- }
- }else if( d_type==typ_bool_var ){
- //get current value of the variable
- TNode n = qi->getCurrentValue( d_n );
- int vn = qi->getCurrentRepVar( qi->getVarNum( n ) );
- if( vn==-1 ){
- //evaluate the value, see if it is compatible
- int e = p->evaluate( n );
- if( ( e==1 && d_tgt ) || ( e==0 && !d_tgt ) ){
- d_child_counter = 0;
- }
- }else{
- //unassigned, set match to true/false
- d_qni_bound[0] = vn;
- qi->setMatch( p, vn, d_tgt ? p->d_true : p->d_false );
- d_child_counter = 0;
- }
- if( d_child_counter==0 ){
- d_qn.push_back( NULL );
- }
- }else if( d_type==typ_var ){
- Assert( isHandledUfTerm( d_n ) );
- Node f = getOperator( p, d_n );
- Debug("qcf-match-debug") << " reset: Var will match operators of " << f << std::endl;
- QcfNodeIndex * qni = p->getQcfNodeIndex( Node::null(), f );
- if( qni!=NULL ){
- d_qn.push_back( qni );
- }
- d_matched_basis = false;
- }else if( d_type==typ_tsym || d_type==typ_tconstraint ){
- for( std::map< int, int >::iterator it = d_qni_var_num.begin(); it != d_qni_var_num.end(); ++it ){
- int repVar = qi->getCurrentRepVar( it->second );
- if( qi->d_match[repVar].isNull() ){
- Debug("qcf-match-debug") << "Force matching on child #" << it->first << ", which is var #" << repVar << std::endl;
- d_qni_bound[it->first] = repVar;
- }
- }
- d_qn.push_back( NULL );
- }else if( d_type==typ_pred || d_type==typ_eq ){
- //add initial constraint
- Node nn[2];
- int vn[2];
- if( d_type==typ_pred ){
- nn[0] = qi->getCurrentValue( d_n );
- vn[0] = qi->getCurrentRepVar( qi->getVarNum( nn[0] ) );
- nn[1] = p->getRepresentative( d_tgt ? p->d_true : p->d_false );
- vn[1] = -1;
- d_tgt = true;
- }else{
- for( unsigned i=0; i<2; i++ ){
- TNode nc;
- std::map< int, TNode >::iterator it = d_qni_gterm_rep.find( i );
- if( it!=d_qni_gterm_rep.end() ){
- nc = it->second;
- }else{
- nc = d_n[i];
- }
- nn[i] = qi->getCurrentValue( nc );
- vn[i] = qi->getCurrentRepVar( qi->getVarNum( nn[i] ) );
- }
- }
- bool success;
- if( vn[0]==-1 && vn[1]==-1 ){
- //Trace("qcf-explain") << " reset : " << d_n << " check ground values " << nn[0] << " " << nn[1] << " (tgt=" << d_tgt << ")" << std::endl;
- Debug("qcf-match-debug") << " reset: check ground values " << nn[0] << " " << nn[1] << " (" << d_tgt << ")" << std::endl;
- //just compare values
- if( d_tgt ){
- success = p->areMatchEqual( nn[0], nn[1] );
- }else{
- if( p->d_effort==QuantConflictFind::effort_conflict ){
- success = p->areDisequal( nn[0], nn[1] );
- }else{
- success = p->areMatchDisequal( nn[0], nn[1] );
- }
- }
- }else{
- //otherwise, add a constraint to a variable
- if( vn[1]!=-1 && vn[0]==-1 ){
- //swap
- Node t = nn[1];
- nn[1] = nn[0];
- nn[0] = t;
- vn[0] = vn[1];
- vn[1] = -1;
- }
- Debug("qcf-match-debug") << " reset: add constraint " << vn[0] << " -> " << nn[1] << " (vn=" << vn[1] << ")" << std::endl;
- //add some constraint
- int addc = qi->addConstraint( p, vn[0], nn[1], vn[1], d_tgt, false );
- success = addc!=-1;
- //if successful and non-redundant, store that we need to cleanup this
- if( addc==1 ){
- //Trace("qcf-explain") << " reset: " << d_n << " add constraint " << vn[0] << " -> " << nn[1] << " (vn=" << vn[1] << ")" << ", d_tgt = " << d_tgt << std::endl;
- for( unsigned i=0; i<2; i++ ){
- if( vn[i]!=-1 && std::find( d_qni_bound_except.begin(), d_qni_bound_except.end(), i )==d_qni_bound_except.end() ){
- d_qni_bound[vn[i]] = vn[i];
- }
- }
- d_qni_bound_cons[vn[0]] = nn[1];
- d_qni_bound_cons_var[vn[0]] = vn[1];
- }
- }
- //if successful, we will bind values to variables
- if( success ){
- d_qn.push_back( NULL );
- }
- }else{
- if( d_children.empty() ){
- //add dummy
- d_qn.push_back( NULL );
- }else{
- if( d_tgt && d_n.getKind()==FORALL ){
- //do nothing
- }else{
- //reset the first child to d_tgt
- d_child_counter = 0;
- getChild( d_child_counter )->reset( p, d_tgt, qi );
- }
- }
- }
- d_binding = false;
- d_wasSet = true;
- Debug("qcf-match") << " reset: Finished reset for " << d_n << ", success = " << ( !d_qn.empty() || d_child_counter!=-1 ) << std::endl;
-}
-
-bool MatchGen::getNextMatch( QuantConflictFind * p, QuantInfo * qi ) {
- Debug("qcf-match") << " Get next match for : " << d_n << ", type = ";
- debugPrintType( "qcf-match", d_type );
- Debug("qcf-match") << ", children = " << d_children.size() << ", binding = " << d_binding << std::endl;
- if( d_type==typ_invalid || d_type==typ_ground ){
- if( d_child_counter==0 ){
- d_child_counter = -1;
- return true;
- }else{
- d_wasSet = false;
- return false;
- }
- }else if( d_type==typ_var || d_type==typ_eq || d_type==typ_pred || d_type==typ_bool_var || d_type==typ_tconstraint || d_type==typ_tsym ){
- bool success = false;
- bool terminate = false;
- do {
- bool doReset = false;
- bool doFail = false;
- if( !d_binding ){
- if( doMatching( p, qi ) ){
- Debug("qcf-match-debug") << " - Matching succeeded" << std::endl;
- d_binding = true;
- d_binding_it = d_qni_bound.begin();
- doReset = true;
- //for tconstraint, add constraint
- if( d_type==typ_tconstraint ){
- std::map< Node, bool >::iterator it = qi->d_tconstraints.find( d_n );
- if( it==qi->d_tconstraints.end() ){
- qi->d_tconstraints[d_n] = d_tgt;
- //store that we added this constraint
- d_qni_bound_cons[0] = d_n;
- }else if( d_tgt!=it->second ){
- success = false;
- terminate = true;
- }
- }
- }else{
- Debug("qcf-match-debug") << " - Matching failed" << std::endl;
- success = false;
- terminate = true;
- }
- }else{
- doFail = true;
- }
- if( d_binding ){
- //also need to create match for each variable we bound
- success = true;
- Debug("qcf-match-debug") << " Produce matches for bound variables by " << d_n << ", type = ";
- debugPrintType( "qcf-match-debug", d_type );
- Debug("qcf-match-debug") << "..." << std::endl;
-
- while( ( success && d_binding_it!=d_qni_bound.end() ) || doFail ){
- std::map< int, MatchGen * >::iterator itm;
- if( !doFail ){
- Debug("qcf-match-debug") << " check variable " << d_binding_it->second << std::endl;
- itm = qi->d_var_mg.find( d_binding_it->second );
- }
- if( doFail || ( d_binding_it->first!=0 && itm!=qi->d_var_mg.end() ) ){
- Debug("qcf-match-debug") << " we had bound variable " << d_binding_it->second << ", reset = " << doReset << std::endl;
- if( doReset ){
- itm->second->reset( p, true, qi );
- }
- if( doFail || !itm->second->getNextMatch( p, qi ) ){
- do {
- if( d_binding_it==d_qni_bound.begin() ){
- Debug("qcf-match-debug") << " failed." << std::endl;
- success = false;
- }else{
- --d_binding_it;
- Debug("qcf-match-debug") << " decrement..." << std::endl;
- }
- }while( success && ( d_binding_it->first==0 || qi->d_var_mg.find( d_binding_it->second )==qi->d_var_mg.end() ) );
- doReset = false;
- doFail = false;
- }else{
- Debug("qcf-match-debug") << " increment..." << std::endl;
- ++d_binding_it;
- doReset = true;
- }
- }else{
- Debug("qcf-match-debug") << " skip..." << d_binding_it->second << std::endl;
- ++d_binding_it;
- doReset = true;
- }
- }
- if( !success ){
- d_binding = false;
- }else{
- terminate = true;
- if( d_binding_it==d_qni_bound.begin() ){
- d_binding = false;
- }
- }
- }
- }while( !terminate );
- //if not successful, clean up the variables you bound
- if( !success ){
- if( d_type==typ_eq || d_type==typ_pred ){
- //clean up the constraints you added
- for( std::map< int, TNode >::iterator it = d_qni_bound_cons.begin(); it != d_qni_bound_cons.end(); ++it ){
- if( !it->second.isNull() ){
- Debug("qcf-match") << " Clean up bound var " << it->first << (d_tgt ? "!" : "") << " = " << it->second << std::endl;
- std::map< int, int >::iterator itb = d_qni_bound_cons_var.find( it->first );
- int vn = itb!=d_qni_bound_cons_var.end() ? itb->second : -1;
- //Trace("qcf-explain") << " cleanup: " << d_n << " remove constraint " << it->first << " -> " << it->second << " (vn=" << vn << ")" << ", d_tgt = " << d_tgt << std::endl;
- qi->addConstraint( p, it->first, it->second, vn, d_tgt, true );
- }
- }
- d_qni_bound_cons.clear();
- d_qni_bound_cons_var.clear();
- d_qni_bound.clear();
- }else{
- //clean up the matches you set
- for( std::map< int, int >::iterator it = d_qni_bound.begin(); it != d_qni_bound.end(); ++it ){
- Debug("qcf-match") << " Clean up bound var " << it->second << std::endl;
- Assert( it->second<qi->getNumVars() );
- qi->d_match[ it->second ] = TNode::null();
- qi->d_match_term[ it->second ] = TNode::null();
- }
- d_qni_bound.clear();
- }
- if( d_type==typ_tconstraint ){
- //remove constraint if applicable
- if( d_qni_bound_cons.find( 0 )!=d_qni_bound_cons.end() ){
- qi->d_tconstraints.erase( d_n );
- d_qni_bound_cons.clear();
- }
- }
- /*
- if( d_type==typ_var && p->d_effort==QuantConflictFind::effort_mc && !d_matched_basis ){
- d_matched_basis = true;
- Node f = getOperator( d_n );
- TNode mbo = p->getQuantifiersEngine()->getTermDatabase()->getModelBasisOpTerm( f );
- if( qi->setMatch( p, d_qni_var_num[0], mbo ) ){
- success = true;
- d_qni_bound[0] = d_qni_var_num[0];
- }
- }
- */
- }
- Debug("qcf-match") << " ...finished matching for " << d_n << ", success = " << success << std::endl;
- d_wasSet = success;
- return success;
- }else if( d_type==typ_formula || d_type==typ_ite_var ){
- bool success = false;
- if( d_child_counter<0 ){
- if( d_child_counter<-1 ){
- success = true;
- d_child_counter = -1;
- }
- }else{
- while( !success && d_child_counter>=0 ){
- //transition system based on d_child_counter
- if( d_n.getKind()==OR || d_n.getKind()==AND ){
- if( (d_n.getKind()==AND)==d_tgt ){
- //all children must match simultaneously
- if( getChild( d_child_counter )->getNextMatch( p, qi ) ){
- if( d_child_counter<(int)(getNumChildren()-1) ){
- d_child_counter++;
- Debug("qcf-match-debug") << " Reset child " << d_child_counter << " of " << d_n << std::endl;
- getChild( d_child_counter )->reset( p, d_tgt, qi );
- }else{
- success = true;
- }
- }else{
- //if( std::find( d_independent.begin(), d_independent.end(), d_child_counter )!=d_independent.end() ){
- // d_child_counter--;
- //}else{
- d_child_counter--;
- //}
- }
- }else{
- //one child must match
- if( !getChild( d_child_counter )->getNextMatch( p, qi ) ){
- if( d_child_counter<(int)(getNumChildren()-1) ){
- d_child_counter++;
- Debug("qcf-match-debug") << " Reset child " << d_child_counter << " of " << d_n << ", one match" << std::endl;
- getChild( d_child_counter )->reset( p, d_tgt, qi );
- }else{
- d_child_counter = -1;
- }
- }else{
- success = true;
- }
- }
- }else if( d_n.getKind()==IFF ){
- //construct match based on both children
- if( d_child_counter%2==0 ){
- if( getChild( 0 )->getNextMatch( p, qi ) ){
- d_child_counter++;
- getChild( 1 )->reset( p, d_child_counter==1, qi );
- }else{
- if( d_child_counter==0 ){
- d_child_counter = 2;
- getChild( 0 )->reset( p, !d_tgt, qi );
- }else{
- d_child_counter = -1;
- }
- }
- }
- if( d_child_counter>=0 && d_child_counter%2==1 ){
- if( getChild( 1 )->getNextMatch( p, qi ) ){
- success = true;
- }else{
- d_child_counter--;
- }
- }
- }else if( d_n.getKind()==ITE ){
- if( d_child_counter%2==0 ){
- int index1 = d_child_counter==4 ? 1 : 0;
- if( getChild( index1 )->getNextMatch( p, qi ) ){
- d_child_counter++;
- getChild( d_child_counter==5 ? 2 : (d_tgt==(d_child_counter==1) ? 1 : 2) )->reset( p, d_tgt, qi );
- }else{
- if( d_child_counter==4 || ( d_type==typ_ite_var && d_child_counter==2 ) ){
- d_child_counter = -1;
- }else{
- d_child_counter +=2;
- getChild( d_child_counter==2 ? 0 : 1 )->reset( p, d_child_counter==2 ? !d_tgt : d_tgt, qi );
- }
- }
- }
- if( d_child_counter>=0 && d_child_counter%2==1 ){
- int index2 = d_child_counter==5 ? 2 : (d_tgt==(d_child_counter==1) ? 1 : 2);
- if( getChild( index2 )->getNextMatch( p, qi ) ){
- success = true;
- }else{
- d_child_counter--;
- }
- }
- }else if( d_n.getKind()==FORALL ){
- if( getChild( d_child_counter )->getNextMatch( p, qi ) ){
- success = true;
- }else{
- d_child_counter = -1;
- }
- }
- }
- d_wasSet = success;
- Debug("qcf-match") << " ...finished construct match for " << d_n << ", success = " << success << std::endl;
- return success;
- }
- }
- Debug("qcf-match") << " ...already finished for " << d_n << std::endl;
- return false;
-}
-
-bool MatchGen::getExplanation( QuantConflictFind * p, QuantInfo * qi, std::vector< Node >& exp ) {
- if( d_type==typ_eq ){
- Node n[2];
- for( unsigned i=0; i<2; i++ ){
- Trace("qcf-explain") << "Explain term " << d_n[i] << "..." << std::endl;
- n[i] = getExplanationTerm( p, qi, d_n[i], exp );
- }
- Node eq = n[0].eqNode( n[1] );
- if( !d_tgt_orig ){
- eq = eq.negate();
- }
- exp.push_back( eq );
- Trace("qcf-explain") << "Explanation for " << d_n << " (tgt=" << d_tgt_orig << ") is " << eq << ", set = " << d_wasSet << std::endl;
- return true;
- }else if( d_type==typ_pred ){
- Trace("qcf-explain") << "Explain term " << d_n << "..." << std::endl;
- Node n = getExplanationTerm( p, qi, d_n, exp );
- if( !d_tgt_orig ){
- n = n.negate();
- }
- exp.push_back( n );
- Trace("qcf-explain") << "Explanation for " << d_n << " (tgt=" << d_tgt_orig << ") is " << n << ", set = " << d_wasSet << std::endl;
- return true;
- }else if( d_type==typ_formula ){
- Trace("qcf-explain") << "Explanation get for " << d_n << ", counter = " << d_child_counter << ", tgt = " << d_tgt_orig << ", set = " << d_wasSet << std::endl;
- if( d_n.getKind()==OR || d_n.getKind()==AND ){
- if( (d_n.getKind()==AND)==d_tgt ){
- for( unsigned i=0; i<getNumChildren(); i++ ){
- if( !getChild( i )->getExplanation( p, qi, exp ) ){
- return false;
- }
- }
- }else{
- return getChild( d_child_counter )->getExplanation( p, qi, exp );
- }
- }else if( d_n.getKind()==IFF ){
- for( unsigned i=0; i<2; i++ ){
- if( !getChild( i )->getExplanation( p, qi, exp ) ){
- return false;
- }
- }
- }else if( d_n.getKind()==ITE ){
- for( unsigned i=0; i<3; i++ ){
- bool isActive = ( ( i==0 && d_child_counter!=5 ) ||
- ( i==1 && d_child_counter!=( d_tgt ? 3 : 1 ) ) ||
- ( i==2 && d_child_counter!=( d_tgt ? 1 : 3 ) ) );
- if( isActive ){
- if( !getChild( i )->getExplanation( p, qi, exp ) ){
- return false;
- }
- }
- }
- }else{
- return false;
- }
- return true;
- }else{
- return false;
- }
-}
-
-Node MatchGen::getExplanationTerm( QuantConflictFind * p, QuantInfo * qi, Node t, std::vector< Node >& exp ) {
- Node v = qi->getCurrentExpValue( t );
- if( isHandledUfTerm( t ) ){
- for( unsigned i=0; i<t.getNumChildren(); i++ ){
- Node vi = getExplanationTerm( p, qi, t[i], exp );
- if( vi!=v[i] ){
- Node eq = vi.eqNode( v[i] );
- if( std::find( exp.begin(), exp.end(), eq )==exp.end() ){
- Trace("qcf-explain") << " add : " << eq << "." << std::endl;
- exp.push_back( eq );
- }
- }
- }
- }
- return v;
-}
-
-bool MatchGen::doMatching( QuantConflictFind * p, QuantInfo * qi ) {
- if( !d_qn.empty() ){
- if( d_qn[0]==NULL ){
- d_qn.clear();
- return true;
- }else{
- Assert( d_type==typ_var );
- Assert( d_qni_size>0 );
- bool invalidMatch;
- do {
- invalidMatch = false;
- Debug("qcf-match-debug") << " Do matching " << d_n << " " << d_qn.size() << " " << d_qni.size() << std::endl;
- if( d_qn.size()==d_qni.size()+1 ) {
- int index = (int)d_qni.size();
- //initialize
- TNode val;
- std::map< int, int >::iterator itv = d_qni_var_num.find( index );
- if( itv!=d_qni_var_num.end() ){
- //get the representative variable this variable is equal to
- int repVar = qi->getCurrentRepVar( itv->second );
- Debug("qcf-match-debug") << " Match " << index << " is a variable " << itv->second << ", which is repVar " << repVar << std::endl;
- //get the value the rep variable
- //std::map< int, TNode >::iterator itm = qi->d_match.find( repVar );
- if( !qi->d_match[repVar].isNull() ){
- val = qi->d_match[repVar];
- Debug("qcf-match-debug") << " Variable is already bound to " << val << std::endl;
- }else{
- //binding a variable
- d_qni_bound[index] = repVar;
- std::map< TNode, QcfNodeIndex >::iterator it = d_qn[index]->d_children.begin();
- if( it != d_qn[index]->d_children.end() ) {
- d_qni.push_back( it );
- //set the match
- if( qi->setMatch( p, d_qni_bound[index], it->first ) ){
- Debug("qcf-match-debug") << " Binding variable" << std::endl;
- if( d_qn.size()<d_qni_size ){
- d_qn.push_back( &it->second );
- }
- }else{
- Debug("qcf-match") << " Binding variable, currently fail." << std::endl;
- invalidMatch = true;
- }
- }else{
- Debug("qcf-match-debug") << " Binding variable, fail, no more variables to bind" << std::endl;
- d_qn.pop_back();
- }
- }
- }else{
- Debug("qcf-match-debug") << " Match " << index << " is ground term" << std::endl;
- Assert( d_qni_gterm.find( index )!=d_qni_gterm.end() );
- Assert( d_qni_gterm_rep.find( index )!=d_qni_gterm_rep.end() );
- val = d_qni_gterm_rep[index];
- Assert( !val.isNull() );
- }
- if( !val.isNull() ){
- //constrained by val
- std::map< TNode, QcfNodeIndex >::iterator it = d_qn[index]->d_children.find( val );
- if( it!=d_qn[index]->d_children.end() ){
- Debug("qcf-match-debug") << " Match" << std::endl;
- d_qni.push_back( it );
- if( d_qn.size()<d_qni_size ){
- d_qn.push_back( &it->second );
- }
- }else{
- Debug("qcf-match-debug") << " Failed to match" << std::endl;
- d_qn.pop_back();
- }
- }
- }else{
- Assert( d_qn.size()==d_qni.size() );
- int index = d_qni.size()-1;
- //increment if binding this variable
- bool success = false;
- std::map< int, int >::iterator itb = d_qni_bound.find( index );
- if( itb!=d_qni_bound.end() ){
- d_qni[index]++;
- if( d_qni[index]!=d_qn[index]->d_children.end() ){
- success = true;
- if( qi->setMatch( p, itb->second, d_qni[index]->first ) ){
- Debug("qcf-match-debug") << " Bind next variable" << std::endl;
- if( d_qn.size()<d_qni_size ){
- d_qn.push_back( &d_qni[index]->second );
- }
- }else{
- Debug("qcf-match-debug") << " Bind next variable, currently fail" << std::endl;
- invalidMatch = true;
- }
- }else{
- qi->d_match[ itb->second ] = TNode::null();
- qi->d_match_term[ itb->second ] = TNode::null();
- Debug("qcf-match-debug") << " Bind next variable, no more variables to bind" << std::endl;
- }
- }else{
- //TODO : if it equal to something else, also try that
- }
- //if not incrementing, move to next
- if( !success ){
- d_qn.pop_back();
- d_qni.pop_back();
- }
- }
- }while( ( !d_qn.empty() && d_qni.size()!=d_qni_size ) || invalidMatch );
- if( d_qni.size()==d_qni_size ){
- //Assert( !d_qni[d_qni.size()-1]->second.d_children.empty() );
- //Debug("qcf-match-debug") << " We matched " << d_qni[d_qni.size()-1]->second.d_children.begin()->first << std::endl;
- Assert( !d_qni[d_qni.size()-1]->second.d_children.empty() );
- TNode t = d_qni[d_qni.size()-1]->second.d_children.begin()->first;
- Debug("qcf-match-debug") << " " << d_n << " matched " << t << std::endl;
- qi->d_match_term[d_qni_var_num[0]] = t;
- //set the match terms
- for( std::map< int, int >::iterator it = d_qni_bound.begin(); it != d_qni_bound.end(); ++it ){
- Debug("qcf-match-debug") << " position " << it->first << " bounded " << it->second << " / " << qi->d_q[0].getNumChildren() << std::endl;
- //if( it->second<(int)qi->d_q[0].getNumChildren() ){ //if it is an actual variable, we are interested in knowing the actual term
- if( it->first>0 ){
- Assert( !qi->d_match[ it->second ].isNull() );
- Assert( p->areEqual( t[it->first-1], qi->d_match[ it->second ] ) );
- qi->d_match_term[it->second] = t[it->first-1];
- }
- //}
- }
- }
- }
- }
- return !d_qn.empty();
-}
-
-void MatchGen::debugPrintType( const char * c, short typ, bool isTrace ) {
- if( isTrace ){
- switch( typ ){
- case typ_invalid: Trace(c) << "invalid";break;
- case typ_ground: Trace(c) << "ground";break;
- case typ_eq: Trace(c) << "eq";break;
- case typ_pred: Trace(c) << "pred";break;
- case typ_formula: Trace(c) << "formula";break;
- case typ_var: Trace(c) << "var";break;
- case typ_ite_var: Trace(c) << "ite_var";break;
- case typ_bool_var: Trace(c) << "bool_var";break;
- }
- }else{
- switch( typ ){
- case typ_invalid: Debug(c) << "invalid";break;
- case typ_ground: Debug(c) << "ground";break;
- case typ_eq: Debug(c) << "eq";break;
- case typ_pred: Debug(c) << "pred";break;
- case typ_formula: Debug(c) << "formula";break;
- case typ_var: Debug(c) << "var";break;
- case typ_ite_var: Debug(c) << "ite_var";break;
- case typ_bool_var: Debug(c) << "bool_var";break;
- }
- }
-}
-
-void MatchGen::setInvalid() {
- d_type = typ_invalid;
- d_children.clear();
-}
-
-bool MatchGen::isHandledBoolConnective( TNode n ) {
- return n.getType().isBoolean() && ( n.getKind()==OR || n.getKind()==AND || n.getKind()==IFF || n.getKind()==ITE || n.getKind()==FORALL || n.getKind()==NOT );
-}
-
-bool MatchGen::isHandledUfTerm( TNode n ) {
- //return n.getKind()==APPLY_UF || n.getKind()==STORE || n.getKind()==SELECT ||
- // n.getKind()==APPLY_CONSTRUCTOR || n.getKind()==APPLY_SELECTOR_TOTAL || n.getKind()==APPLY_TESTER;
- return inst::Trigger::isAtomicTriggerKind( n.getKind() );
-}
-
-Node MatchGen::getOperator( QuantConflictFind * p, Node n ) {
- if( isHandledUfTerm( n ) ){
- return p->getQuantifiersEngine()->getTermDatabase()->getOperator( n );
- }else{
- return Node::null();
- }
-}
-
-bool MatchGen::isHandled( TNode n ) {
- if( n.getKind()!=BOUND_VARIABLE && n.hasBoundVar() ){
- if( !isHandledBoolConnective( n ) && !isHandledUfTerm( n ) && n.getKind()!=EQUAL && n.getKind()!=ITE ){
- return false;
- }
- for( unsigned i=0; i<n.getNumChildren(); i++ ){
- if( !isHandled( n[i] ) ){
- return false;
- }
- }
- }
- return true;
-}
-
-
-QuantConflictFind::QuantConflictFind( QuantifiersEngine * qe, context::Context* c ) :
-QuantifiersModule( qe ),
-d_c( c ),
-d_conflict( c, false ),
-d_qassert( c ) {
- d_fid_count = 0;
- d_true = NodeManager::currentNM()->mkConst<bool>(true);
- d_false = NodeManager::currentNM()->mkConst<bool>(false);
-}
-
-Node QuantConflictFind::mkEqNode( Node a, Node b ) {
- if( a.getType().isBoolean() ){
- return a.iffNode( b );
- }else{
- return a.eqNode( b );
- }
-}
-
-//-------------------------------------------------- registration
-
-void QuantConflictFind::registerQuantifier( Node q ) {
- if( !TermDb::isRewriteRule( q ) ){
- d_quants.push_back( q );
- d_quant_id[q] = d_quants.size();
- Trace("qcf-qregister") << "Register ";
- debugPrintQuant( "qcf-qregister", q );
- Trace("qcf-qregister") << " : " << q << std::endl;
- //make QcfNode structure
- Trace("qcf-qregister") << "- Get relevant equality/disequality pairs, calculate flattening..." << std::endl;
- d_qinfo[q].initialize( q, q[1] );
-
- //debug print
- Trace("qcf-qregister") << "- Flattened structure is :" << std::endl;
- Trace("qcf-qregister") << " ";
- debugPrintQuantBody( "qcf-qregister", q, q[1] );
- Trace("qcf-qregister") << std::endl;
- if( d_qinfo[q].d_vars.size()>q[0].getNumChildren() ){
- Trace("qcf-qregister") << " with additional constraints : " << std::endl;
- for( unsigned j=q[0].getNumChildren(); j<d_qinfo[q].d_vars.size(); j++ ){
- Trace("qcf-qregister") << " ?x" << j << " = ";
- debugPrintQuantBody( "qcf-qregister", q, d_qinfo[q].d_vars[j], false );
- Trace("qcf-qregister") << std::endl;
- }
- }
-
- Trace("qcf-qregister") << "Done registering quantifier." << std::endl;
- }
-}
-
-int QuantConflictFind::evaluate( Node n, bool pref, bool hasPref ) {
- int ret = 0;
- if( n.getKind()==EQUAL ){
- Node n1 = evaluateTerm( n[0] );
- Node n2 = evaluateTerm( n[1] );
- Debug("qcf-eval") << "Evaluate : Normalize " << n << " to " << n1 << " = " << n2 << std::endl;
- if( areEqual( n1, n2 ) ){
- ret = 1;
- }else if( areDisequal( n1, n2 ) ){
- ret = -1;
- }
- //else if( d_effort>QuantConflictFind::effort_conflict ){
- // ret = -1;
- //}
- }else if( MatchGen::isHandledUfTerm( n ) ){ //predicate
- Node nn = evaluateTerm( n );
- Debug("qcf-eval") << "Evaluate : Normalize " << nn << " to " << n << std::endl;
- if( areEqual( nn, d_true ) ){
- ret = 1;
- }else if( areEqual( nn, d_false ) ){
- ret = -1;
- }
- //else if( d_effort>QuantConflictFind::effort_conflict ){
- // ret = -1;
- //}
- }else if( n.getKind()==NOT ){
- return -evaluate( n[0] );
- }else if( n.getKind()==ITE ){
- int cev1 = evaluate( n[0] );
- int cevc[2] = { 0, 0 };
- for( unsigned i=0; i<2; i++ ){
- if( ( i==0 && cev1!=-1 ) || ( i==1 && cev1!=1 ) ){
- cevc[i] = evaluate( n[i+1] );
- if( cev1!=0 ){
- ret = cevc[i];
- break;
- }else if( cevc[i]==0 ){
- break;
- }
- }
- }
- if( ret==0 && cevc[0]!=0 && cevc[0]==cevc[1] ){
- ret = cevc[0];
- }
- }else if( n.getKind()==IFF ){
- int cev1 = evaluate( n[0] );
- if( cev1!=0 ){
- int cev2 = evaluate( n[1] );
- if( cev2!=0 ){
- ret = cev1==cev2 ? 1 : -1;
- }
- }
-
- }else{
- int ssval = 0;
- if( n.getKind()==OR ){
- ssval = 1;
- }else if( n.getKind()==AND ){
- ssval = -1;
- }
- bool isUnk = false;
- for( unsigned i=0; i<n.getNumChildren(); i++ ){
- int cev = evaluate( n[i] );
- if( cev==ssval ){
- ret = ssval;
- break;
- }else if( cev==0 ){
- isUnk = true;
- }
- }
- if( ret==0 && !isUnk ){
- ret = -ssval;
- }
- }
- Debug("qcf-eval") << "Evaluate " << n << " to " << ret << std::endl;
- return ret;
-}
-
-short QuantConflictFind::getMaxQcfEffort() {
- if( options::qcfMode()==QCF_CONFLICT_ONLY ){
- return effort_conflict;
- }else if( options::qcfMode()==QCF_PROP_EQ ){
- return effort_prop_eq;
- }else if( options::qcfMode()==QCF_MC ){
- return effort_mc;
- }else{
- return 0;
- }
-}
-
-bool QuantConflictFind::areMatchEqual( TNode n1, TNode n2 ) {
- //if( d_effort==QuantConflictFind::effort_mc ){
- // return n1==n2 || !areDisequal( n1, n2 );
- //}else{
- return n1==n2;
- //}
-}
-
-bool QuantConflictFind::areMatchDisequal( TNode n1, TNode n2 ) {
- //if( d_effort==QuantConflictFind::effort_conflict ){
- // return areDisequal( n1, n2 );
- //}else{
- return n1!=n2;
- //}
-}
-
-//-------------------------------------------------- handling assertions / eqc
-
-void QuantConflictFind::assertNode( Node q ) {
- if( !TermDb::isRewriteRule( q ) ){
- Trace("qcf-proc") << "QCF : assertQuantifier : ";
- debugPrintQuant("qcf-proc", q);
- Trace("qcf-proc") << std::endl;
- d_qassert.push_back( q );
- //set the eqRegistries that this depends on to true
- //for( std::map< EqRegistry *, bool >::iterator it = d_qinfo[q].d_rel_eqr.begin(); it != d_qinfo[q].d_rel_eqr.end(); ++it ){
- // it->first->d_active.set( true );
- //}
- }
-}
-
-eq::EqualityEngine * QuantConflictFind::getEqualityEngine() {
- //return ((uf::TheoryUF*)d_quantEngine->getTheoryEngine()->theoryOf( theory::THEORY_UF ))->getEqualityEngine();
- return d_quantEngine->getTheoryEngine()->getMasterEqualityEngine();
-}
-bool QuantConflictFind::areEqual( Node n1, Node n2 ) {
- return getEqualityEngine()->hasTerm( n1 ) && getEqualityEngine()->hasTerm( n2 ) && getEqualityEngine()->areEqual( n1,n2 );
-}
-bool QuantConflictFind::areDisequal( Node n1, Node n2 ) {
- return n1!=n2 && getEqualityEngine()->hasTerm( n1 ) && getEqualityEngine()->hasTerm( n2 ) && getEqualityEngine()->areDisequal( n1,n2, false );
-}
-Node QuantConflictFind::getRepresentative( Node n ) {
- if( getEqualityEngine()->hasTerm( n ) ){
- return getEqualityEngine()->getRepresentative( n );
- }else{
- return n;
- }
-}
-Node QuantConflictFind::evaluateTerm( Node n ) {
- if( MatchGen::isHandledUfTerm( n ) ){
- Node f = MatchGen::getOperator( this, n );
- Node nn;
- computeUfTerms( f );
- if( getEqualityEngine()->hasTerm( n ) ){
- computeArgReps( n );
- nn = d_uf_terms[f].existsTerm( n, d_arg_reps[n] );
- }else{
- std::vector< TNode > args;
- for( unsigned i=0; i<n.getNumChildren(); i++ ){
- Node c = evaluateTerm( n[i] );
- args.push_back( c );
- }
- nn = d_uf_terms[f].existsTerm( n, args );
- }
- if( !nn.isNull() ){
- Debug("qcf-eval") << "GT: Term " << nn << " for " << n << " hasTerm = " << getEqualityEngine()->hasTerm( n ) << std::endl;
- return getRepresentative( nn );
- }else{
- Debug("qcf-eval") << "GT: No term for " << n << " hasTerm = " << getEqualityEngine()->hasTerm( n ) << std::endl;
- return n;
- }
- }else if( n.getKind()==ITE ){
- int v = evaluate( n[0], false, false );
- if( v==1 ){
- return evaluateTerm( n[1] );
- }else if( v==-1 ){
- return evaluateTerm( n[2] );
- }
- }
- return getRepresentative( n );
-}
-
-/*
-QuantConflictFind::EqcInfo * QuantConflictFind::getEqcInfo( Node n, bool doCreate ) {
- std::map< Node, EqcInfo * >::iterator it2 = d_eqc_info.find( n );
- if( it2==d_eqc_info.end() ){
- if( doCreate ){
- EqcInfo * eqci = new EqcInfo( d_c );
- d_eqc_info[n] = eqci;
- return eqci;
- }else{
- return NULL;
- }
- }
- return it2->second;
-}
-*/
-
-QcfNodeIndex * QuantConflictFind::getQcfNodeIndex( Node eqc, Node f ) {
- computeUfTerms( f );
- std::map< TNode, QcfNodeIndex >::iterator itut = d_eqc_uf_terms.find( f );
- if( itut==d_eqc_uf_terms.end() ){
- return NULL;
- }else{
- if( eqc.isNull() ){
- return &itut->second;
- }else{
- std::map< TNode, QcfNodeIndex >::iterator itute = itut->second.d_children.find( eqc );
- if( itute!=itut->second.d_children.end() ){
- return &itute->second;
- }else{
- return NULL;
- }
- }
- }
-}
-
-QcfNodeIndex * QuantConflictFind::getQcfNodeIndex( Node f ) {
- computeUfTerms( f );
- std::map< TNode, QcfNodeIndex >::iterator itut = d_uf_terms.find( f );
- if( itut!=d_uf_terms.end() ){
- return &itut->second;
- }else{
- return NULL;
- }
-}
-
-/** new node */
-void QuantConflictFind::newEqClass( Node n ) {
- //Trace("qcf-proc-debug") << "QCF : newEqClass : " << n << std::endl;
- //Trace("qcf-proc2-debug") << "QCF : finished newEqClass : " << n << std::endl;
-}
-
-/** merge */
-void QuantConflictFind::merge( Node a, Node b ) {
- /*
- if( b.getKind()==EQUAL ){
- if( a==d_true ){
- //will merge anyways
- //merge( b[0], b[1] );
- }else if( a==d_false ){
- assertDisequal( b[0], b[1] );
- }
- }else{
- Trace("qcf-proc") << "QCF : merge : " << a << " " << b << std::endl;
- EqcInfo * eqc_b = getEqcInfo( b, false );
- EqcInfo * eqc_a = NULL;
- if( eqc_b ){
- eqc_a = getEqcInfo( a );
- //move disequalities of b into a
- for( NodeBoolMap::iterator it = eqc_b->d_diseq.begin(); it != eqc_b->d_diseq.end(); ++it ){
- if( (*it).second ){
- Node n = (*it).first;
- EqcInfo * eqc_n = getEqcInfo( n, false );
- Assert( eqc_n );
- if( !eqc_n->isDisequal( a ) ){
- Assert( !eqc_a->isDisequal( n ) );
- eqc_n->setDisequal( a );
- eqc_a->setDisequal( n );
- //setEqual( eqc_a, eqc_b, a, n, false );
- }
- eqc_n->setDisequal( b, false );
- }
- }
- ////move all previous EqcRegistry's regarding equalities within b
- //for( NodeBoolMap::iterator it = eqc_b->d_rel_eqr_e.begin(); it != eqc_b->d_rel_eqr_e.end(); ++it ){
- // if( (*it).second ){
- // eqc_a->d_rel_eqr_e[(*it).first] = true;
- // }
- //}
- }
- //process new equalities
- //setEqual( eqc_a, eqc_b, a, b, true );
- Trace("qcf-proc2") << "QCF : finished merge : " << a << " " << b << std::endl;
- }
- */
-}
-
-/** assert disequal */
-void QuantConflictFind::assertDisequal( Node a, Node b ) {
- /*
- a = getRepresentative( a );
- b = getRepresentative( b );
- Trace("qcf-proc") << "QCF : assert disequal : " << a << " " << b << std::endl;
- EqcInfo * eqc_a = getEqcInfo( a );
- EqcInfo * eqc_b = getEqcInfo( b );
- if( !eqc_a->isDisequal( b ) ){
- Assert( !eqc_b->isDisequal( a ) );
- eqc_b->setDisequal( a );
- eqc_a->setDisequal( b );
- //setEqual( eqc_a, eqc_b, a, b, false );
- }
- Trace("qcf-proc2") << "QCF : finished assert disequal : " << a << " " << b << std::endl;
- */
-}
-
-//-------------------------------------------------- check function
-
-void QuantConflictFind::reset_round( Theory::Effort level ) {
- d_needs_computeRelEqr = true;
-}
-
-/** check */
-void QuantConflictFind::check( Theory::Effort level ) {
- Trace("qcf-check") << "QCF : check : " << level << std::endl;
- if( d_conflict ){
- Trace("qcf-check2") << "QCF : finished check : already in conflict." << std::endl;
- if( level>=Theory::EFFORT_FULL ){
- Trace("qcf-warn") << "ALREADY IN CONFLICT? " << level << std::endl;
- //Assert( false );
- }
- }else{
- int addedLemmas = 0;
- if( d_performCheck ){
- ++(d_statistics.d_inst_rounds);
- double clSet = 0;
- int prevEt = 0;
- if( Trace.isOn("qcf-engine") ){
- prevEt = d_statistics.d_entailment_checks.getData();
- clSet = double(clock())/double(CLOCKS_PER_SEC);
- Trace("qcf-engine") << "---Conflict Find Engine Round, effort = " << level << "---" << std::endl;
- }
- computeRelevantEqr();
-
- //determine order for quantified formulas
- std::vector< Node > qorder;
- std::map< Node, bool > qassert;
- //mark which are asserted
- for( unsigned i=0; i<d_qassert.size(); i++ ){
- qassert[d_qassert[i]] = true;
- }
- //add which ones are specified in the order
- for( unsigned i=0; i<d_quant_order.size(); i++ ){
- Node n = d_quant_order[i];
- if( std::find( qorder.begin(), qorder.end(), n )==qorder.end() && qassert.find( n )!=qassert.end() ){
- qorder.push_back( n );
- }
- }
- d_quant_order.clear();
- d_quant_order.insert( d_quant_order.begin(), qorder.begin(), qorder.end() );
- //add remaining
- for( unsigned i=0; i<d_qassert.size(); i++ ){
- Node n = d_qassert[i];
- if( std::find( qorder.begin(), qorder.end(), n )==qorder.end() ){
- qorder.push_back( n );
- }
- }
-
- if( Trace.isOn("qcf-debug") ){
- Trace("qcf-debug") << std::endl;
- debugPrint("qcf-debug");
- Trace("qcf-debug") << std::endl;
- }
- short end_e = getMaxQcfEffort();
- for( short e = effort_conflict; e<=end_e; e++ ){
- d_effort = e;
- Trace("qcf-check") << "Checking quantified formulas at effort " << e << "..." << std::endl;
- for( unsigned j=0; j<qorder.size(); j++ ){
- Node q = qorder[j];
- QuantInfo * qi = &d_qinfo[q];
-
- Assert( d_qinfo.find( q )!=d_qinfo.end() );
- if( qi->d_mg->isValid() ){
- Trace("qcf-check") << "Check quantified formula ";
- debugPrintQuant("qcf-check", q);
- Trace("qcf-check") << " : " << q << "..." << std::endl;
-
- Trace("qcf-check-debug") << "Reset round..." << std::endl;
- qi->reset_round( this );
- //try to make a matches making the body false
- Trace("qcf-check-debug") << "Get next match..." << std::endl;
- while( qi->d_mg->getNextMatch( this, qi ) ){
- Trace("qcf-check") << "*** Produced match at effort " << e << " : " << std::endl;
- qi->debugPrintMatch("qcf-check");
- Trace("qcf-check") << std::endl;
- std::vector< int > assigned;
- if( !qi->isMatchSpurious( this ) ){
- if( qi->completeMatch( this, assigned ) ){
- /*
- if( options::qcfExp() && d_effort==effort_conflict ){
- std::vector< Node > exp;
- if( qi->d_mg->getExplanation( this, qi, exp ) ){
- Trace("qcf-check-exp") << "Base explanation is : " << std::endl;
- for( unsigned c=0; c<exp.size(); c++ ){
- Trace("qcf-check-exp") << " " << exp[c] << std::endl;
- }
- std::vector< TNode > c_exp;
- eq::EqualityEngine* ee = ((uf::TheoryUF*)d_quantEngine->getTheoryEngine()->theoryOf( THEORY_UF ))->getEqualityEngine() ;
- for( unsigned c=0; c<exp.size(); c++ ){
- bool pol = exp[c].getKind()!=NOT;
- TNode lit = pol ? exp[c] : exp[c][0];
- Trace("qcf-check-exp") << "Explain " << lit << ", polarity " << pol << std::endl;
- if( lit.getKind()==EQUAL ){
- if( !pol && !ee->areDisequal( lit[0], lit[1], true ) ){
- exit( 98 );
- }else if( pol && !ee->areEqual( lit[0], lit[1] ) ){
- exit( 99 );
- }
- ee->explainEquality( lit[0], lit[1], pol, c_exp );
- }else{
- if( !ee->areEqual( lit, pol ? d_true : d_false ) ){
- exit( pol ? 96 : 97 );
- }
- ee->explainPredicate( lit, pol, c_exp );
- }
- }
- std::vector< Node > c_lem;
- Trace("qcf-check-exp") << "Actual explanation is : " << std::endl;
- for( unsigned c=0; c<c_exp.size(); c++ ){
- Trace("qcf-check-exp") << " " << c_exp[c] << std::endl;
- Node ccc = c_exp[c].negate();
- if( std::find( c_lem.begin(), c_lem.end(), ccc )==c_lem.end() ){
- c_lem.push_back( ccc );
- }
- }
-
- c_lem.push_back( q.negate() );
- Node conf = NodeManager::currentNM()->mkNode( OR, c_lem );
- Trace("qcf-conflict") << "QCF conflict : " << conf << std::endl;
- d_quantEngine->addLemma( conf, false );
- d_conflict.set( true );
- ++(d_statistics.d_conflict_inst);
- ++addedLemmas;
- break;
- }
- }
- */
- std::vector< Node > terms;
- qi->getMatch( terms );
- if( !qi->isTConstraintSpurious( this, terms ) ){
- if( Debug.isOn("qcf-check-inst") ){
- //if( e==effort_conflict ){
- Node inst = d_quantEngine->getInstantiation( q, terms );
- Debug("qcf-check-inst") << "Check instantiation " << inst << "..." << std::endl;
- Assert( evaluate( inst )!=1 );
- Assert( evaluate( inst )==-1 || e>effort_conflict );
- //}
- }
- if( d_quantEngine->addInstantiation( q, terms, false ) ){
- Trace("qcf-check") << " ... Added instantiation" << std::endl;
- Trace("qcf-inst") << "*** Was from effort " << e << " : " << std::endl;
- qi->debugPrintMatch("qcf-inst");
- Trace("qcf-inst") << std::endl;
- ++addedLemmas;
- if( e==effort_conflict ){
- d_quant_order.insert( d_quant_order.begin(), q );
- d_conflict.set( true );
- ++(d_statistics.d_conflict_inst);
- break;
- }else if( e==effort_prop_eq ){
- ++(d_statistics.d_prop_inst);
- }
- }else{
- Trace("qcf-check") << " ... Failed to add instantiation" << std::endl;
- //Assert( false );
- }
- }
- //clean up assigned
- qi->revertMatch( assigned );
- d_tempCache.clear();
- }else{
- Trace("qcf-check") << " ... Spurious instantiation (cannot assign unassigned variables)" << std::endl;
- }
- }else{
- Trace("qcf-check") << " ... Spurious instantiation (match is inconsistent)" << std::endl;
- }
- }
- if( d_conflict ){
- break;
- }
- }
- }
- if( addedLemmas>0 ){
- d_quantEngine->flushLemmas();
- break;
- }
- }
- if( Trace.isOn("qcf-engine") ){
- double clSet2 = double(clock())/double(CLOCKS_PER_SEC);
- Trace("qcf-engine") << "Finished conflict find engine, time = " << (clSet2-clSet);
- if( addedLemmas>0 ){
- Trace("qcf-engine") << ", effort = " << ( d_effort==effort_conflict ? "conflict" : ( d_effort==effort_prop_eq ? "prop_eq" : "mc" ) );
- Trace("qcf-engine") << ", addedLemmas = " << addedLemmas;
- }
- Trace("qcf-engine") << std::endl;
- int currEt = d_statistics.d_entailment_checks.getData();
- if( currEt!=prevEt ){
- Trace("qcf-engine") << " Entailment checks = " << ( currEt - prevEt ) << std::endl;
- }
- }
- }
- Trace("qcf-check2") << "QCF : finished check : " << level << std::endl;
- }
-}
-
-bool QuantConflictFind::needsCheck( Theory::Effort level ) {
- d_performCheck = false;
- if( options::quantConflictFind() && !d_conflict ){
- if( level==Theory::EFFORT_LAST_CALL ){
- d_performCheck = options::qcfWhenMode()==QCF_WHEN_MODE_LAST_CALL;
- }else if( level==Theory::EFFORT_FULL ){
- d_performCheck = options::qcfWhenMode()==QCF_WHEN_MODE_DEFAULT;
- }else if( level==Theory::EFFORT_STANDARD ){
- d_performCheck = options::qcfWhenMode()==QCF_WHEN_MODE_STD;
- }
- }
- return d_performCheck;
-}
-
-void QuantConflictFind::computeRelevantEqr() {
- if( d_needs_computeRelEqr ){
- d_needs_computeRelEqr = false;
- Trace("qcf-check") << "Compute relevant equalities..." << std::endl;
- d_uf_terms.clear();
- d_eqc_uf_terms.clear();
- d_eqcs.clear();
- d_model_basis.clear();
- d_arg_reps.clear();
- //double clSet = 0;
- //if( Trace.isOn("qcf-opt") ){
- // clSet = double(clock())/double(CLOCKS_PER_SEC);
- //}
-
- //long nTermst = 0;
- //long nTerms = 0;
- //long nEqc = 0;
-
- //which nodes are irrelevant for disequality matches
- std::map< TNode, bool > irrelevant_dnode;
- //now, store matches
- eq::EqClassesIterator eqcs_i = eq::EqClassesIterator( getEqualityEngine() );
- while( !eqcs_i.isFinished() ){
- //nEqc++;
- Node r = (*eqcs_i);
- TypeNode rtn = r.getType();
- if( options::qcfMode()==QCF_MC ){
- std::map< TypeNode, std::vector< TNode > >::iterator itt = d_eqcs.find( rtn );
- if( itt==d_eqcs.end() ){
- Node mb = getQuantifiersEngine()->getTermDatabase()->getModelBasisTerm( rtn );
- if( !getEqualityEngine()->hasTerm( mb ) ){
- Trace("qcf-warn") << "WARNING: Model basis term does not exist!" << std::endl;
- Assert( false );
- }
- Node mbr = getRepresentative( mb );
- if( mbr!=r ){
- d_eqcs[rtn].push_back( mbr );
- }
- d_eqcs[rtn].push_back( r );
- d_model_basis[rtn] = mb;
- }else{
- itt->second.push_back( r );
- }
- }else{
- d_eqcs[rtn].push_back( r );
- }
- /*
- eq::EqClassIterator eqc_i = eq::EqClassIterator( r, getEqualityEngine() );
- while( !eqc_i.isFinished() ){
- TNode n = (*eqc_i);
- if( n.hasBoundVar() ){
- std::cout << "BAD TERM IN DB : " << n << std::endl;
- exit( 199 );
- }
- ++eqc_i;
- }
-
- */
-
- //if( r.getType().isInteger() ){
- // Trace("qcf-mv") << "Model value for eqc(" << r << ") : " << d_quantEngine->getValuation().getModelValue( r ) << std::endl;
- //}
- //EqcInfo * eqcir = getEqcInfo( r, false );
- //get relevant nodes that we are disequal from
- /*
- std::vector< Node > deqc;
- if( eqcir ){
- for( NodeBoolMap::iterator it = eqcir->d_diseq.begin(); it != eqcir->d_diseq.end(); ++it ){
- if( (*it).second ){
- //Node rd = (*it).first;
- //if( rd!=getRepresentative( rd ) ){
- // std::cout << "Bad rep!" << std::endl;
- // exit( 0 );
- //}
- deqc.push_back( (*it).first );
- }
- }
- }
- */
- //process disequalities
- /*
- eq::EqClassIterator eqc_i = eq::EqClassIterator( r, getEqualityEngine() );
- while( !eqc_i.isFinished() ){
- TNode n = (*eqc_i);
- if( n.getKind()!=EQUAL ){
- nTermst++;
- //node_to_rep[n] = r;
- //if( n.getNumChildren()>0 ){
- // if( n.getKind()!=APPLY_UF ){
- // std::cout << n.getKind() << " " << n.getOperator() << " " << n << std::endl;
- // }
- //}
- if( !quantifiers::TermDb::hasBoundVarAttr( n ) ){ //temporary
-
- bool isRedundant;
- std::map< TNode, std::vector< TNode > >::iterator it_na;
- TNode fn;
- if( MatchGen::isHandledUfTerm( n ) ){
- Node f = MatchGen::getOperator( this, n );
- computeArgReps( n );
- it_na = d_arg_reps.find( n );
- Assert( it_na!=d_arg_reps.end() );
- Node nadd = d_eqc_uf_terms[f].d_children[r].addTerm( n, d_arg_reps[n] );
- isRedundant = (nadd!=n);
- d_uf_terms[f].addTerm( n, d_arg_reps[n] );
- }else{
- isRedundant = false;
- }
- nTerms += isRedundant ? 0 : 1;
- }else{
- if( Debug.isOn("qcf-nground") ){
- Debug("qcf-nground") << "Non-ground term in eqc : " << n << std::endl;
- Assert( false );
- }
- }
- }
- ++eqc_i;
- }
- */
- ++eqcs_i;
- }
- /*
- if( Trace.isOn("qcf-opt") ){
- double clSet2 = double(clock())/double(CLOCKS_PER_SEC);
- Trace("qcf-opt") << "Compute rel eqc : " << std::endl;
- Trace("qcf-opt") << " " << nEqc << " equivalence classes. " << std::endl;
- Trace("qcf-opt") << " " << nTerms << " / " << nTermst << " terms." << std::endl;
- Trace("qcf-opt") << " Time : " << (clSet2-clSet) << std::endl;
- }
- */
- }
-}
-
-void QuantConflictFind::computeArgReps( TNode n ) {
- if( d_arg_reps.find( n )==d_arg_reps.end() ){
- Assert( MatchGen::isHandledUfTerm( n ) );
- for( unsigned j=0; j<n.getNumChildren(); j++ ){
- d_arg_reps[n].push_back( getRepresentative( n[j] ) );
- }
- }
-}
-
-void QuantConflictFind::computeUfTerms( TNode f ) {
- if( d_uf_terms.find( f )==d_uf_terms.end() ){
- d_uf_terms[f].clear();
- unsigned nt = d_quantEngine->getTermDatabase()->getNumGroundTerms( f );
- for( unsigned i=0; i<nt; i++ ){
- Node n = d_quantEngine->getTermDatabase()->d_op_map[f][i];
- if( getEqualityEngine()->hasTerm( n ) && !n.getAttribute(NoMatchAttribute()) ){
- Node r = getRepresentative( n );
- computeArgReps( n );
- d_eqc_uf_terms[f].d_children[r].addTerm( n, d_arg_reps[n] );
- d_uf_terms[f].addTerm( n, d_arg_reps[n] );
- }
- }
- }
-}
-
-//-------------------------------------------------- debugging
-
-
-void QuantConflictFind::debugPrint( const char * c ) {
- //print the equivalance classes
- Trace(c) << "----------EQ classes" << std::endl;
- eq::EqClassesIterator eqcs_i = eq::EqClassesIterator( getEqualityEngine() );
- while( !eqcs_i.isFinished() ){
- Node n = (*eqcs_i);
- //if( !n.getType().isInteger() ){
- Trace(c) << " - " << n << " : {";
- eq::EqClassIterator eqc_i = eq::EqClassIterator( n, getEqualityEngine() );
- bool pr = false;
- while( !eqc_i.isFinished() ){
- Node nn = (*eqc_i);
- if( nn.getKind()!=EQUAL && nn!=n ){
- Trace(c) << (pr ? "," : "" ) << " " << nn;
- pr = true;
- }
- ++eqc_i;
- }
- Trace(c) << (pr ? " " : "" ) << "}" << std::endl;
- /*
- EqcInfo * eqcn = getEqcInfo( n, false );
- if( eqcn ){
- Trace(c) << " DEQ : {";
- pr = false;
- for( NodeBoolMap::iterator it = eqcn->d_diseq.begin(); it != eqcn->d_diseq.end(); ++it ){
- if( (*it).second ){
- Trace(c) << (pr ? "," : "" ) << " " << (*it).first;
- pr = true;
- }
- }
- Trace(c) << (pr ? " " : "" ) << "}" << std::endl;
- }
- //}
- */
- ++eqcs_i;
- }
-}
-
-void QuantConflictFind::debugPrintQuant( const char * c, Node q ) {
- Trace(c) << "Q" << d_quant_id[q];
-}
-
-void QuantConflictFind::debugPrintQuantBody( const char * c, Node q, Node n, bool doVarNum ) {
- if( n.getNumChildren()==0 ){
- Trace(c) << n;
- }else if( doVarNum && d_qinfo[q].d_var_num.find( n )!=d_qinfo[q].d_var_num.end() ){
- Trace(c) << "?x" << d_qinfo[q].d_var_num[n];
- }else{
- Trace(c) << "(";
- if( n.getKind()==APPLY_UF ){
- Trace(c) << n.getOperator();
- }else{
- Trace(c) << n.getKind();
- }
- for( unsigned i=0; i<n.getNumChildren(); i++ ){
- Trace(c) << " ";
- debugPrintQuantBody( c, q, n[i] );
- }
- Trace(c) << ")";
- }
-}
-
-QuantConflictFind::Statistics::Statistics():
- d_inst_rounds("QuantConflictFind::Inst_Rounds", 0),
- d_conflict_inst("QuantConflictFind::Instantiations_Conflict_Find", 0 ),
- d_prop_inst("QuantConflictFind::Instantiations_Prop", 0 ),
- d_entailment_checks("QuantConflictFind::Entailment_Checks",0)
-{
- StatisticsRegistry::registerStat(&d_inst_rounds);
- StatisticsRegistry::registerStat(&d_conflict_inst);
- StatisticsRegistry::registerStat(&d_prop_inst);
- StatisticsRegistry::registerStat(&d_entailment_checks);
-}
-
-QuantConflictFind::Statistics::~Statistics(){
- StatisticsRegistry::unregisterStat(&d_inst_rounds);
- StatisticsRegistry::unregisterStat(&d_conflict_inst);
- StatisticsRegistry::unregisterStat(&d_prop_inst);
- StatisticsRegistry::unregisterStat(&d_entailment_checks);
-}
-
-TNode QuantConflictFind::getZero( Kind k ) {
- std::map< Kind, Node >::iterator it = d_zero.find( k );
- if( it==d_zero.end() ){
- Node nn;
- if( k==PLUS ){
- nn = NodeManager::currentNM()->mkConst( Rational(0) );
- }
- d_zero[k] = nn;
- return nn;
- }else{
- return it->second;
- }
-}
-
-
-}
+/********************* */
+/*! \file quant_conflict_find.cpp
+ ** \verbatim
+ ** Original author: Andrew Reynolds
+ ** Major contributors: none
+ ** Minor contributors (to current version): none
+ ** This file is part of the CVC4 project.
+ ** Copyright (c) 2009-2014 New York University and The University of Iowa
+ ** See the file COPYING in the top-level source directory for licensing
+ ** information.\endverbatim
+ **
+ ** \brief quant conflict find class
+ **
+ **/
+
+#include <vector>
+
+#include "theory/quantifiers/quant_conflict_find.h"
+#include "theory/quantifiers/quant_util.h"
+#include "theory/theory_engine.h"
+#include "theory/quantifiers/options.h"
+#include "theory/quantifiers/term_database.h"
+#include "theory/quantifiers/trigger.h"
+
+using namespace CVC4;
+using namespace CVC4::kind;
+using namespace CVC4::theory;
+using namespace CVC4::theory::quantifiers;
+using namespace std;
+
+namespace CVC4 {
+
+
+
+void QuantInfo::initialize( Node q, Node qn ) {
+ d_q = q;
+ for( unsigned i=0; i<q[0].getNumChildren(); i++ ){
+ d_match.push_back( TNode::null() );
+ d_match_term.push_back( TNode::null() );
+ }
+
+ //register the variables
+ for( unsigned i=0; i<q[0].getNumChildren(); i++ ){
+ d_var_num[q[0][i]] = i;
+ d_vars.push_back( q[0][i] );
+ }
+
+ registerNode( qn, true, true );
+
+
+ Trace("qcf-qregister") << "- Make match gen structure..." << std::endl;
+ d_mg = new MatchGen( this, qn );
+
+ if( d_mg->isValid() ){
+ /*
+ for( unsigned j=0; j<q[0].getNumChildren(); j++ ){
+ if( d_inMatchConstraint.find( q[0][j] )==d_inMatchConstraint.end() ){
+ Trace("qcf-invalid") << "QCF invalid : variable " << q[0][j] << " does not exist in a matching constraint." << std::endl;
+ d_mg->setInvalid();
+ break;
+ }
+ }
+ */
+ if( d_mg->isValid() ){
+ for( unsigned j=q[0].getNumChildren(); j<d_vars.size(); j++ ){
+ if( d_vars[j].getKind()!=BOUND_VARIABLE ){
+ d_var_mg[j] = NULL;
+ bool is_tsym = false;
+ if( !MatchGen::isHandledUfTerm( d_vars[j] ) && d_vars[j].getKind()!=ITE ){
+ is_tsym = true;
+ d_tsym_vars.push_back( j );
+ }
+ if( !is_tsym || options::qcfTConstraint() ){
+ d_var_mg[j] = new MatchGen( this, d_vars[j], true );
+ }
+ if( !d_var_mg[j] || !d_var_mg[j]->isValid() ){
+ Trace("qcf-invalid") << "QCF invalid : cannot match for " << d_vars[j] << std::endl;
+ d_mg->setInvalid();
+ break;
+ }else{
+ std::vector< int > bvars;
+ d_var_mg[j]->determineVariableOrder( this, bvars );
+ }
+ }
+ }
+ if( d_mg->isValid() ){
+ std::vector< int > bvars;
+ d_mg->determineVariableOrder( this, bvars );
+ }
+ }
+ }else{
+ Trace("qcf-invalid") << "QCF invalid : body of formula cannot be processed." << std::endl;
+ }
+ Trace("qcf-qregister-summary") << "QCF register : " << ( d_mg->isValid() ? "VALID " : "INVALID" ) << " : " << q << std::endl;
+}
+
+void QuantInfo::registerNode( Node n, bool hasPol, bool pol, bool beneathQuant ) {
+ Trace("qcf-qregister-debug2") << "Register : " << n << std::endl;
+ if( n.getKind()==FORALL ){
+ registerNode( n[1], hasPol, pol, true );
+ }else{
+ if( !MatchGen::isHandledBoolConnective( n ) ){
+ if( n.hasBoundVar() ){
+ //literals
+ if( n.getKind()==EQUAL ){
+ for( unsigned i=0; i<n.getNumChildren(); i++ ){
+ flatten( n[i], beneathQuant );
+ }
+ }else if( MatchGen::isHandledUfTerm( n ) ){
+ flatten( n, beneathQuant );
+ }else if( n.getKind()==ITE ){
+ for( unsigned i=1; i<=2; i++ ){
+ flatten( n[i], beneathQuant );
+ }
+ registerNode( n[0], false, pol, beneathQuant );
+ }else if( options::qcfTConstraint() ){
+ //a theory-specific predicate
+ for( unsigned i=0; i<n.getNumChildren(); i++ ){
+ flatten( n[i], beneathQuant );
+ }
+ }
+ }
+ }else{
+ for( unsigned i=0; i<n.getNumChildren(); i++ ){
+ bool newHasPol;
+ bool newPol;
+ QuantPhaseReq::getPolarity( n, i, hasPol, pol, newHasPol, newPol );
+ //QcfNode * qcfc = new QcfNode( d_c );
+ //qcfc->d_parent = qcf;
+ //qcf->d_child[i] = qcfc;
+ registerNode( n[i], newHasPol, newPol, beneathQuant );
+ }
+ }
+ }
+}
+
+void QuantInfo::flatten( Node n, bool beneathQuant ) {
+ Trace("qcf-qregister-debug2") << "Flatten : " << n << std::endl;
+ if( n.hasBoundVar() ){
+ if( n.getKind()==BOUND_VARIABLE ){
+ d_inMatchConstraint[n] = true;
+ }
+ //if( MatchGen::isHandledUfTerm( n ) || n.getKind()==ITE ){
+ if( d_var_num.find( n )==d_var_num.end() ){
+ Trace("qcf-qregister-debug2") << "Add FLATTEN VAR : " << n << std::endl;
+ d_var_num[n] = d_vars.size();
+ d_vars.push_back( n );
+ d_match.push_back( TNode::null() );
+ d_match_term.push_back( TNode::null() );
+ if( n.getKind()==ITE ){
+ registerNode( n, false, false );
+ }else{
+ for( unsigned i=0; i<n.getNumChildren(); i++ ){
+ flatten( n[i], beneathQuant );
+ }
+ }
+ }else{
+ Trace("qcf-qregister-debug2") << "...already processed" << std::endl;
+ }
+ }else{
+ Trace("qcf-qregister-debug2") << "...is ground." << std::endl;
+ }
+}
+
+
+void QuantInfo::reset_round( QuantConflictFind * p ) {
+ for( unsigned i=0; i<d_match.size(); i++ ){
+ d_match[i] = TNode::null();
+ d_match_term[i] = TNode::null();
+ }
+ d_curr_var_deq.clear();
+ d_tconstraints.clear();
+ //add built-in variable constraints
+ for( unsigned r=0; r<2; r++ ){
+ for( std::map< int, std::vector< Node > >::iterator it = d_var_constraint[r].begin();
+ it != d_var_constraint[r].end(); ++it ){
+ for( unsigned j=0; j<it->second.size(); j++ ){
+ Node rr = it->second[j];
+ if( !isVar( rr ) ){
+ rr = p->getRepresentative( rr );
+ }
+ if( addConstraint( p, it->first, rr, r==0 )==-1 ){
+ d_var_constraint[0].clear();
+ d_var_constraint[1].clear();
+ //quantified formula is actually equivalent to true
+ Trace("qcf-qregister") << "Quantifier is equivalent to true!!!" << std::endl;
+ d_mg->d_children.clear();
+ d_mg->d_n = NodeManager::currentNM()->mkConst( true );
+ d_mg->d_type = MatchGen::typ_ground;
+ return;
+ }
+ }
+ }
+ }
+ d_mg->reset_round( p );
+ for( std::map< int, MatchGen * >::iterator it = d_var_mg.begin(); it != d_var_mg.end(); ++it ){
+ it->second->reset_round( p );
+ }
+ //now, reset for matching
+ d_mg->reset( p, false, this );
+}
+
+int QuantInfo::getCurrentRepVar( int v ) {
+ if( v!=-1 && !d_match[v].isNull() ){
+ int vn = getVarNum( d_match[v] );
+ if( vn!=-1 ){
+ //int vr = getCurrentRepVar( vn );
+ //d_match[v] = d_vars[vr];
+ //return vr;
+ return getCurrentRepVar( vn );
+ }
+ }
+ return v;
+}
+
+TNode QuantInfo::getCurrentValue( TNode n ) {
+ int v = getVarNum( n );
+ if( v==-1 ){
+ return n;
+ }else{
+ if( d_match[v].isNull() ){
+ return n;
+ }else{
+ Assert( getVarNum( d_match[v] )!=v );
+ return getCurrentValue( d_match[v] );
+ }
+ }
+}
+
+TNode QuantInfo::getCurrentExpValue( TNode n ) {
+ int v = getVarNum( n );
+ if( v==-1 ){
+ return n;
+ }else{
+ if( d_match[v].isNull() ){
+ return n;
+ }else{
+ Assert( getVarNum( d_match[v] )!=v );
+ if( d_match_term[v].isNull() ){
+ return getCurrentValue( d_match[v] );
+ }else{
+ return d_match_term[v];
+ }
+ }
+ }
+}
+
+bool QuantInfo::getCurrentCanBeEqual( QuantConflictFind * p, int v, TNode n, bool chDiseq ) {
+ //check disequalities
+ std::map< int, std::map< TNode, int > >::iterator itd = d_curr_var_deq.find( v );
+ if( itd!=d_curr_var_deq.end() ){
+ for( std::map< TNode, int >::iterator it = itd->second.begin(); it != itd->second.end(); ++it ){
+ Node cv = getCurrentValue( it->first );
+ Debug("qcf-ccbe") << "compare " << cv << " " << n << std::endl;
+ if( cv==n ){
+ return false;
+ }else if( chDiseq && !isVar( n ) && !isVar( cv ) ){
+ //they must actually be disequal if we are looking for conflicts
+ if( !p->areDisequal( n, cv ) ){
+ //TODO : check for entailed disequal
+
+ return false;
+ }
+ }
+ }
+ }
+ return true;
+}
+
+int QuantInfo::addConstraint( QuantConflictFind * p, int v, TNode n, bool polarity ) {
+ v = getCurrentRepVar( v );
+ int vn = getVarNum( n );
+ vn = vn==-1 ? -1 : getCurrentRepVar( vn );
+ n = getCurrentValue( n );
+ return addConstraint( p, v, n, vn, polarity, false );
+}
+
+int QuantInfo::addConstraint( QuantConflictFind * p, int v, TNode n, int vn, bool polarity, bool doRemove ) {
+ //for handling equalities between variables, and disequalities involving variables
+ Debug("qcf-match-debug") << "- " << (doRemove ? "un" : "" ) << "constrain : " << v << " -> " << n << " (cv=" << getCurrentValue( n ) << ")";
+ Debug("qcf-match-debug") << ", (vn=" << vn << "), polarity = " << polarity << std::endl;
+ Assert( doRemove || n==getCurrentValue( n ) );
+ Assert( doRemove || v==getCurrentRepVar( v ) );
+ Assert( doRemove || vn==getCurrentRepVar( getVarNum( n ) ) );
+ if( polarity ){
+ if( vn!=v ){
+ if( doRemove ){
+ if( vn!=-1 ){
+ //if set to this in the opposite direction, clean up opposite instead
+ // std::map< int, TNode >::iterator itmn = d_match.find( vn );
+ if( d_match[vn]==d_vars[v] ){
+ return addConstraint( p, vn, d_vars[v], v, true, true );
+ }else{
+ //unsetting variables equal
+ std::map< int, std::map< TNode, int > >::iterator itd = d_curr_var_deq.find( vn );
+ if( itd!=d_curr_var_deq.end() ){
+ //remove disequalities owned by this
+ std::vector< TNode > remDeq;
+ for( std::map< TNode, int >::iterator it = itd->second.begin(); it != itd->second.end(); ++it ){
+ if( it->second==v ){
+ remDeq.push_back( it->first );
+ }
+ }
+ for( unsigned i=0; i<remDeq.size(); i++ ){
+ d_curr_var_deq[vn].erase( remDeq[i] );
+ }
+ }
+ }
+ }
+ d_match[v] = TNode::null();
+ return 1;
+ }else{
+ //std::map< int, TNode >::iterator itm = d_match.find( v );
+
+ if( vn!=-1 ){
+ Debug("qcf-match-debug") << " ...Variable bound to variable" << std::endl;
+ //std::map< int, TNode >::iterator itmn = d_match.find( vn );
+ if( d_match[v].isNull() ){
+ //setting variables equal
+ bool alreadySet = false;
+ if( !d_match[vn].isNull() ){
+ alreadySet = true;
+ Assert( !isVar( d_match[vn] ) );
+ }
+
+ //copy or check disequalities
+ std::map< int, std::map< TNode, int > >::iterator itd = d_curr_var_deq.find( v );
+ if( itd!=d_curr_var_deq.end() ){
+ for( std::map< TNode, int >::iterator it = itd->second.begin(); it != itd->second.end(); ++it ){
+ Node dv = getCurrentValue( it->first );
+ if( !alreadySet ){
+ if( d_curr_var_deq[vn].find( dv )==d_curr_var_deq[vn].end() ){
+ d_curr_var_deq[vn][dv] = v;
+ }
+ }else{
+ if( !p->areMatchDisequal( d_match[vn], dv ) ){
+ Debug("qcf-match-debug") << " -> fail, conflicting disequality" << std::endl;
+ return -1;
+ }
+ }
+ }
+ }
+ if( alreadySet ){
+ n = getCurrentValue( n );
+ }
+ }else{
+ if( d_match[vn].isNull() ){
+ Debug("qcf-match-debug") << " ...Reverse direction" << std::endl;
+ //set the opposite direction
+ return addConstraint( p, vn, d_vars[v], v, true, false );
+ }else{
+ Debug("qcf-match-debug") << " -> Both variables bound, compare" << std::endl;
+ //are they currently equal
+ return p->areMatchEqual( d_match[v], d_match[vn] ) ? 0 : -1;
+ }
+ }
+ }else{
+ Debug("qcf-match-debug") << " ...Variable bound to ground" << std::endl;
+ if( d_match[v].isNull() ){
+ }else{
+ //compare ground values
+ Debug("qcf-match-debug") << " -> Ground value, compare " << d_match[v] << " "<< n << std::endl;
+ return p->areMatchEqual( d_match[v], n ) ? 0 : -1;
+ }
+ }
+ if( setMatch( p, v, n ) ){
+ Debug("qcf-match-debug") << " -> success" << std::endl;
+ return 1;
+ }else{
+ Debug("qcf-match-debug") << " -> fail, conflicting disequality" << std::endl;
+ return -1;
+ }
+ }
+ }else{
+ Debug("qcf-match-debug") << " -> redundant, variable identity" << std::endl;
+ return 0;
+ }
+ }else{
+ if( vn==v ){
+ Debug("qcf-match-debug") << " -> fail, variable identity" << std::endl;
+ return -1;
+ }else{
+ if( doRemove ){
+ Assert( d_curr_var_deq[v].find( n )!=d_curr_var_deq[v].end() );
+ d_curr_var_deq[v].erase( n );
+ return 1;
+ }else{
+ if( d_curr_var_deq[v].find( n )==d_curr_var_deq[v].end() ){
+ //check if it respects equality
+ //std::map< int, TNode >::iterator itm = d_match.find( v );
+ if( !d_match[v].isNull() ){
+ TNode nv = getCurrentValue( n );
+ if( !p->areMatchDisequal( nv, d_match[v] ) ){
+ Debug("qcf-match-debug") << " -> fail, conflicting disequality" << std::endl;
+ return -1;
+ }
+ }
+ d_curr_var_deq[v][n] = v;
+ Debug("qcf-match-debug") << " -> success" << std::endl;
+ return 1;
+ }else{
+ Debug("qcf-match-debug") << " -> redundant disequality" << std::endl;
+ return 0;
+ }
+ }
+ }
+ }
+}
+
+bool QuantInfo::isConstrainedVar( int v ) {
+ if( d_curr_var_deq.find( v )!=d_curr_var_deq.end() && !d_curr_var_deq[v].empty() ){
+ return true;
+ }else{
+ Node vv = getVar( v );
+ //for( std::map< int, TNode >::iterator it = d_match.begin(); it != d_match.end(); ++it ){
+ for( unsigned i=0; i<d_match.size(); i++ ){
+ if( d_match[i]==vv ){
+ return true;
+ }
+ }
+ for( std::map< int, std::map< TNode, int > >::iterator it = d_curr_var_deq.begin(); it != d_curr_var_deq.end(); ++it ){
+ for( std::map< TNode, int >::iterator it2 = it->second.begin(); it2 != it->second.end(); ++it2 ){
+ if( it2->first==vv ){
+ return true;
+ }
+ }
+ }
+ return false;
+ }
+}
+
+bool QuantInfo::setMatch( QuantConflictFind * p, int v, TNode n ) {
+ if( getCurrentCanBeEqual( p, v, n ) ){
+ Debug("qcf-match-debug") << "-- bind : " << v << " -> " << n << ", checked " << d_curr_var_deq[v].size() << " disequalities" << std::endl;
+ d_match[v] = n;
+ return true;
+ }else{
+ return false;
+ }
+}
+
+bool QuantInfo::isMatchSpurious( QuantConflictFind * p ) {
+ for( int i=0; i<getNumVars(); i++ ){
+ //std::map< int, TNode >::iterator it = d_match.find( i );
+ if( !d_match[i].isNull() ){
+ if( !getCurrentCanBeEqual( p, i, d_match[i], p->d_effort==QuantConflictFind::effort_conflict ) ){
+ return true;
+ }
+ }
+ }
+ return false;
+}
+
+bool QuantInfo::isTConstraintSpurious( QuantConflictFind * p, std::vector< Node >& terms ) {
+ if( !d_tconstraints.empty() ){
+ //check constraints
+ for( std::map< Node, bool >::iterator it = d_tconstraints.begin(); it != d_tconstraints.end(); ++it ){
+ //apply substitution to the tconstraint
+ Node cons = it->first.substitute( p->getQuantifiersEngine()->getTermDatabase()->d_vars[d_q].begin(),
+ p->getQuantifiersEngine()->getTermDatabase()->d_vars[d_q].end(),
+ terms.begin(), terms.end() );
+ cons = it->second ? cons : cons.negate();
+ if( !entailmentTest( p, cons, p->d_effort==QuantConflictFind::effort_conflict ) ){
+ return true;
+ }
+ }
+ }
+ return false;
+}
+
+bool QuantInfo::entailmentTest( QuantConflictFind * p, Node lit, bool chEnt ) {
+ Trace("qcf-tconstraint-debug") << "Check : " << lit << std::endl;
+ Node rew = Rewriter::rewrite( lit );
+ if( rew==p->d_false ){
+ Trace("qcf-tconstraint-debug") << "...constraint " << lit << " is disentailed (rewrites to false)." << std::endl;
+ return false;
+ }else if( rew!=p->d_true ){
+ //if checking for conflicts, we must be sure that the constraint is entailed
+ if( chEnt ){
+ //check if it is entailed
+ Trace("qcf-tconstraint-debug") << "Check entailment of " << rew << "..." << std::endl;
+ std::pair<bool, Node> et = p->getQuantifiersEngine()->getTheoryEngine()->entailmentCheck(THEORY_OF_TYPE_BASED, rew );
+ ++(p->d_statistics.d_entailment_checks);
+ Trace("qcf-tconstraint-debug") << "ET result : " << et.first << " " << et.second << std::endl;
+ if( !et.first ){
+ Trace("qcf-tconstraint-debug") << "...cannot show entailment of " << rew << "." << std::endl;
+ return false;
+ }else{
+ return true;
+ }
+ }else{
+ Trace("qcf-tconstraint-debug") << "...does not need to be entailed." << std::endl;
+ return true;
+ }
+ }else{
+ Trace("qcf-tconstraint-debug") << "...rewrites to true." << std::endl;
+ return true;
+ }
+}
+
+bool QuantInfo::completeMatch( QuantConflictFind * p, std::vector< int >& assigned, bool doContinue ) {
+ //assign values for variables that were unassigned (usually not necessary, but handles corner cases)
+ bool doFail = false;
+ bool success = true;
+ if( doContinue ){
+ doFail = true;
+ success = false;
+ }else{
+ //solve for interpreted symbol matches
+ // this breaks the invariant that all introduced constraints are over existing terms
+ for( int i=(int)(d_tsym_vars.size()-1); i>=0; i-- ){
+ int index = d_tsym_vars[i];
+ TNode v = getCurrentValue( d_vars[index] );
+ int slv_v = -1;
+ if( v==d_vars[index] ){
+ slv_v = index;
+ }
+ Trace("qcf-tconstraint-debug") << "Solve " << d_vars[index] << " = " << v << " " << d_vars[index].getKind() << std::endl;
+ if( d_vars[index].getKind()==PLUS || d_vars[index].getKind()==MULT ){
+ Kind k = d_vars[index].getKind();
+ std::vector< TNode > children;
+ for( unsigned j=0; j<d_vars[index].getNumChildren(); j++ ){
+ int vn = getVarNum( d_vars[index][j] );
+ if( vn!=-1 ){
+ TNode vv = getCurrentValue( d_vars[index][j] );
+ if( vv==d_vars[index][j] ){
+ //we will assign this
+ if( slv_v==-1 ){
+ Trace("qcf-tconstraint-debug") << "...will solve for var #" << vn << std::endl;
+ slv_v = vn;
+ if( p->d_effort!=QuantConflictFind::effort_conflict ){
+ break;
+ }
+ }else{
+ Node z = p->getZero( k );
+ if( !z.isNull() ){
+ Trace("qcf-tconstraint-debug") << "...set " << d_vars[vn] << " = " << z << std::endl;
+ assigned.push_back( vn );
+ if( !setMatch( p, vn, z ) ){
+ success = false;
+ break;
+ }
+ }
+ }
+ }else{
+ Trace("qcf-tconstraint-debug") << "...sum value " << vv << std::endl;
+ children.push_back( vv );
+ }
+ }else{
+ Trace("qcf-tconstraint-debug") << "...sum " << d_vars[index][j] << std::endl;
+ children.push_back( d_vars[index][j] );
+ }
+ }
+ if( success ){
+ if( slv_v!=-1 ){
+ Node lhs;
+ if( children.empty() ){
+ lhs = p->getZero( k );
+ }else if( children.size()==1 ){
+ lhs = children[0];
+ }else{
+ lhs = NodeManager::currentNM()->mkNode( k, children );
+ }
+ Node sum;
+ if( v==d_vars[index] ){
+ sum = lhs;
+ }else{
+ if( p->d_effort==QuantConflictFind::effort_conflict ){
+ Kind kn = k;
+ if( d_vars[index].getKind()==PLUS ){
+ kn = MINUS;
+ }
+ if( kn!=k ){
+ sum = NodeManager::currentNM()->mkNode( kn, v, lhs );
+ }
+ }
+ }
+ if( !sum.isNull() ){
+ assigned.push_back( slv_v );
+ Trace("qcf-tconstraint-debug") << "...set " << d_vars[slv_v] << " = " << sum << std::endl;
+ if( !setMatch( p, slv_v, sum ) ){
+ success = false;
+ }
+ p->d_tempCache.push_back( sum );
+ }
+ }else{
+ //must show that constraint is met
+ Node sum = NodeManager::currentNM()->mkNode( k, children );
+ Node eq = sum.eqNode( v );
+ if( !entailmentTest( p, eq ) ){
+ success = false;
+ }
+ p->d_tempCache.push_back( sum );
+ }
+ }
+ }
+
+ if( !success ){
+ break;
+ }
+ }
+ if( success ){
+ //check what is left to assign
+ d_unassigned.clear();
+ d_unassigned_tn.clear();
+ std::vector< int > unassigned[2];
+ std::vector< TypeNode > unassigned_tn[2];
+ for( int i=0; i<getNumVars(); i++ ){
+ if( d_match[i].isNull() ){
+ int rindex = d_var_mg.find( i )==d_var_mg.end() ? 1 : 0;
+ unassigned[rindex].push_back( i );
+ unassigned_tn[rindex].push_back( getVar( i ).getType() );
+ assigned.push_back( i );
+ }
+ }
+ d_unassigned_nvar = unassigned[0].size();
+ for( unsigned i=0; i<2; i++ ){
+ d_unassigned.insert( d_unassigned.end(), unassigned[i].begin(), unassigned[i].end() );
+ d_unassigned_tn.insert( d_unassigned_tn.end(), unassigned_tn[i].begin(), unassigned_tn[i].end() );
+ }
+ d_una_eqc_count.clear();
+ d_una_index = 0;
+ }
+ }
+
+ if( !d_unassigned.empty() && ( success || doContinue ) ){
+ Trace("qcf-check") << "Assign to unassigned..." << std::endl;
+ do {
+ if( doFail ){
+ Trace("qcf-check-unassign") << "Failure, try again..." << std::endl;
+ }
+ bool invalidMatch = false;
+ while( ( d_una_index>=0 && (int)d_una_index<(int)d_unassigned.size() ) || invalidMatch || doFail ){
+ invalidMatch = false;
+ if( !doFail && d_una_index==(int)d_una_eqc_count.size() ){
+ //check if it has now been assigned
+ if( d_una_index<d_unassigned_nvar ){
+ if( !isConstrainedVar( d_unassigned[d_una_index] ) ){
+ d_una_eqc_count.push_back( -1 );
+ }else{
+ d_var_mg[ d_unassigned[d_una_index] ]->reset( p, true, this );
+ d_una_eqc_count.push_back( 0 );
+ }
+ }else{
+ d_una_eqc_count.push_back( 0 );
+ }
+ }else{
+ bool failed = false;
+ if( !doFail ){
+ if( d_una_index<d_unassigned_nvar ){
+ if( !isConstrainedVar( d_unassigned[d_una_index] ) ){
+ Trace("qcf-check-unassign") << "Succeeded, variable unconstrained at " << d_una_index << std::endl;
+ d_una_index++;
+ }else if( d_var_mg[d_unassigned[d_una_index]]->getNextMatch( p, this ) ){
+ Trace("qcf-check-unassign") << "Succeeded match with mg at " << d_una_index << std::endl;
+ d_una_index++;
+ }else{
+ failed = true;
+ Trace("qcf-check-unassign") << "Failed match with mg at " << d_una_index << std::endl;
+ }
+ }else{
+ Assert( doFail || d_una_index==(int)d_una_eqc_count.size()-1 );
+ if( d_una_eqc_count[d_una_index]<(int)p->d_eqcs[d_unassigned_tn[d_una_index]].size() ){
+ int currIndex = d_una_eqc_count[d_una_index];
+ d_una_eqc_count[d_una_index]++;
+ Trace("qcf-check-unassign") << d_unassigned[d_una_index] << "->" << p->d_eqcs[d_unassigned_tn[d_una_index]][currIndex] << std::endl;
+ if( setMatch( p, d_unassigned[d_una_index], p->d_eqcs[d_unassigned_tn[d_una_index]][currIndex] ) ){
+ d_match_term[d_unassigned[d_una_index]] = TNode::null();
+ Trace("qcf-check-unassign") << "Succeeded match " << d_una_index << std::endl;
+ d_una_index++;
+ }else{
+ Trace("qcf-check-unassign") << "Failed match " << d_una_index << std::endl;
+ invalidMatch = true;
+ }
+ }else{
+ failed = true;
+ Trace("qcf-check-unassign") << "No more matches " << d_una_index << std::endl;
+ }
+ }
+ }
+ if( doFail || failed ){
+ do{
+ if( !doFail ){
+ d_una_eqc_count.pop_back();
+ }else{
+ doFail = false;
+ }
+ d_una_index--;
+ }while( d_una_index>=0 && d_una_eqc_count[d_una_index]==-1 );
+ }
+ }
+ }
+ success = d_una_index>=0;
+ if( success ){
+ doFail = true;
+ Trace("qcf-check-unassign") << " Try: " << std::endl;
+ for( unsigned i=0; i<d_unassigned.size(); i++ ){
+ int ui = d_unassigned[i];
+ if( !d_match[ui].isNull() ){
+ Trace("qcf-check-unassign") << " Assigned #" << ui << " : " << d_vars[ui] << " -> " << d_match[ui] << std::endl;
+ }
+ }
+ }
+ }while( success && isMatchSpurious( p ) );
+ }
+ if( success ){
+ for( unsigned i=0; i<d_unassigned.size(); i++ ){
+ int ui = d_unassigned[i];
+ if( !d_match[ui].isNull() ){
+ Trace("qcf-check") << " Assigned #" << ui << " : " << d_vars[ui] << " -> " << d_match[ui] << std::endl;
+ }
+ }
+ return true;
+ }else{
+ for( unsigned i=0; i<assigned.size(); i++ ){
+ d_match[ assigned[i] ] = TNode::null();
+ }
+ assigned.clear();
+ return false;
+ }
+}
+
+void QuantInfo::getMatch( std::vector< Node >& terms ){
+ for( unsigned i=0; i<d_q[0].getNumChildren(); i++ ){
+ //Node cv = qi->getCurrentValue( qi->d_match[i] );
+ int repVar = getCurrentRepVar( i );
+ Node cv;
+ //std::map< int, TNode >::iterator itmt = qi->d_match_term.find( repVar );
+ if( !d_match_term[repVar].isNull() ){
+ cv = d_match_term[repVar];
+ }else{
+ cv = d_match[repVar];
+ }
+ Debug("qcf-check-inst") << "INST : " << i << " -> " << cv << ", from " << d_match[i] << std::endl;
+ terms.push_back( cv );
+ }
+}
+
+void QuantInfo::revertMatch( std::vector< int >& assigned ) {
+ for( unsigned i=0; i<assigned.size(); i++ ){
+ d_match[ assigned[i] ] = TNode::null();
+ }
+}
+
+void QuantInfo::debugPrintMatch( const char * c ) {
+ for( int i=0; i<getNumVars(); i++ ){
+ Trace(c) << " " << d_vars[i] << " -> ";
+ if( !d_match[i].isNull() ){
+ Trace(c) << d_match[i];
+ }else{
+ Trace(c) << "(unassigned) ";
+ }
+ if( !d_curr_var_deq[i].empty() ){
+ Trace(c) << ", DEQ{ ";
+ for( std::map< TNode, int >::iterator it = d_curr_var_deq[i].begin(); it != d_curr_var_deq[i].end(); ++it ){
+ Trace(c) << it->first << " ";
+ }
+ Trace(c) << "}";
+ }
+ if( !d_match_term[i].isNull() && d_match_term[i]!=d_match[i] ){
+ Trace(c) << ", EXP : " << d_match_term[i];
+ }
+ Trace(c) << std::endl;
+ }
+ if( !d_tconstraints.empty() ){
+ Trace(c) << "ADDITIONAL CONSTRAINTS : " << std::endl;
+ for( std::map< Node, bool >::iterator it = d_tconstraints.begin(); it != d_tconstraints.end(); ++it ){
+ Trace(c) << " " << it->first << " -> " << it->second << std::endl;
+ }
+ }
+}
+
+MatchGen::MatchGen( QuantInfo * qi, Node n, bool isVar ){
+ Trace("qcf-qregister-debug") << "Make match gen for " << n << ", isVar = " << isVar << std::endl;
+ std::vector< Node > qni_apps;
+ d_qni_size = 0;
+ if( isVar ){
+ Assert( qi->d_var_num.find( n )!=qi->d_var_num.end() );
+ if( n.getKind()==ITE ){
+ d_type = typ_ite_var;
+ d_type_not = false;
+ d_n = n;
+ d_children.push_back( MatchGen( qi, d_n[0] ) );
+ if( d_children[0].isValid() ){
+ d_type = typ_ite_var;
+ for( unsigned i=1; i<=2; i++ ){
+ Node nn = n.eqNode( n[i] );
+ d_children.push_back( MatchGen( qi, nn ) );
+ d_children[d_children.size()-1].d_qni_bound_except.push_back( 0 );
+ if( !d_children[d_children.size()-1].isValid() ){
+ setInvalid();
+ break;
+ }
+ }
+ }else{
+ d_type = typ_invalid;
+ }
+ }else{
+ d_type = isHandledUfTerm( n ) ? typ_var : typ_tsym;
+ d_qni_var_num[0] = qi->getVarNum( n );
+ d_qni_size++;
+ d_type_not = false;
+ d_n = n;
+ //Node f = getOperator( n );
+ for( unsigned j=0; j<d_n.getNumChildren(); j++ ){
+ Node nn = d_n[j];
+ Trace("qcf-qregister-debug") << " " << d_qni_size;
+ if( qi->isVar( nn ) ){
+ int v = qi->d_var_num[nn];
+ Trace("qcf-qregister-debug") << " is var #" << v << std::endl;
+ d_qni_var_num[d_qni_size] = v;
+ //qi->addFuncParent( v, f, j );
+ }else{
+ Trace("qcf-qregister-debug") << " is gterm " << nn << std::endl;
+ d_qni_gterm[d_qni_size] = nn;
+ }
+ d_qni_size++;
+ }
+ }
+ }else{
+ if( n.hasBoundVar() ){
+ d_type_not = false;
+ d_n = n;
+ if( d_n.getKind()==NOT ){
+ d_n = d_n[0];
+ d_type_not = !d_type_not;
+ }
+
+ if( isHandledBoolConnective( d_n ) ){
+ //non-literals
+ d_type = typ_formula;
+ for( unsigned i=0; i<d_n.getNumChildren(); i++ ){
+ if( d_n.getKind()!=FORALL || i==1 ){
+ d_children.push_back( MatchGen( qi, d_n[i], false ) );
+ if( !d_children[d_children.size()-1].isValid() ){
+ setInvalid();
+ break;
+ }
+ }
+ /*
+ else if( isTop && n.getKind()==OR && d_children[d_children.size()-1].d_type==typ_var_eq ){
+ Trace("qcf-qregister-debug") << "Remove child, make built-in constraint" << std::endl;
+ //if variable equality/disequality at top level, remove immediately
+ bool cIsNot = d_children[d_children.size()-1].d_type_not;
+ Node cn = d_children[d_children.size()-1].d_n;
+ Assert( cn.getKind()==EQUAL );
+ Assert( p->d_qinfo[q].isVar( cn[0] ) || p->d_qinfo[q].isVar( cn[1] ) );
+ //make it a built-in constraint instead
+ for( unsigned i=0; i<2; i++ ){
+ if( p->d_qinfo[q].isVar( cn[i] ) ){
+ int v = p->d_qinfo[q].getVarNum( cn[i] );
+ Node cno = cn[i==0 ? 1 : 0];
+ p->d_qinfo[q].d_var_constraint[ cIsNot ? 0 : 1 ][v].push_back( cno );
+ break;
+ }
+ }
+ d_children.pop_back();
+ }
+ */
+ }
+ }else{
+ d_type = typ_invalid;
+ //literals
+ if( isHandledUfTerm( d_n ) ){
+ Assert( qi->isVar( d_n ) );
+ d_type = typ_pred;
+ }else if( d_n.getKind()==BOUND_VARIABLE ){
+ Assert( d_n.getType().isBoolean() );
+ d_type = typ_bool_var;
+ }else if( d_n.getKind()==EQUAL || options::qcfTConstraint() ){
+ for( unsigned i=0; i<d_n.getNumChildren(); i++ ){
+ if( d_n[i].hasBoundVar() ){
+ if( !qi->isVar( d_n[i] ) ){
+ Trace("qcf-qregister-debug") << "ERROR : not var " << d_n[i] << std::endl;
+ }
+ Assert( qi->isVar( d_n[i] ) );
+ if( d_n.getKind()!=EQUAL && qi->isVar( d_n[i] ) ){
+ d_qni_var_num[i+1] = qi->d_var_num[d_n[i]];
+ }
+ }else{
+ d_qni_gterm[i] = d_n[i];
+ }
+ }
+ d_type = d_n.getKind()==EQUAL ? typ_eq : typ_tconstraint;
+ Trace("qcf-tconstraint") << "T-Constraint : " << d_n << std::endl;
+ }
+ }
+ }else{
+ //we will just evaluate
+ d_n = n;
+ d_type = typ_ground;
+ }
+ //if( d_type!=typ_invalid ){
+ //determine an efficient children ordering
+ //if( !d_children.empty() ){
+ //for( unsigned i=0; i<d_children.size(); i++ ){
+ // d_children_order.push_back( i );
+ //}
+ //if( !d_n.isNull() && ( d_n.getKind()==OR || d_n.getKind()==AND || d_n.getKind()==IFF ) ){
+ //sort based on the type of the constraint : ground comes first, then literals, then others
+ //MatchGenSort mgs;
+ //mgs.d_mg = this;
+ //std::sort( d_children_order.begin(), d_children_order.end(), mgs );
+ //}
+ //}
+ //}
+ }
+ Trace("qcf-qregister-debug") << "Done make match gen " << n << ", type = ";
+ debugPrintType( "qcf-qregister-debug", d_type, true );
+ Trace("qcf-qregister-debug") << std::endl;
+ //Assert( d_children.size()==d_children_order.size() );
+
+}
+
+void MatchGen::collectBoundVar( QuantInfo * qi, Node n, std::vector< int >& cbvars ) {
+ int v = qi->getVarNum( n );
+ if( v!=-1 && std::find( cbvars.begin(), cbvars.end(), v )==cbvars.end() ){
+ cbvars.push_back( v );
+ }
+ for( unsigned i=0; i<n.getNumChildren(); i++ ){
+ collectBoundVar( qi, n[i], cbvars );
+ }
+}
+
+void MatchGen::determineVariableOrder( QuantInfo * qi, std::vector< int >& bvars ) {
+ Trace("qcf-qregister-debug") << "Determine variable order " << d_n << std::endl;
+ bool isCom = d_type==typ_formula && ( d_n.getKind()==OR || d_n.getKind()==AND || d_n.getKind()==IFF );
+ std::map< int, std::vector< int > > c_to_vars;
+ std::map< int, std::vector< int > > vars_to_c;
+ std::map< int, int > vb_count;
+ std::map< int, int > vu_count;
+ std::vector< bool > assigned;
+ Trace("qcf-qregister-debug") << "Calculate bound variables..." << std::endl;
+ for( unsigned i=0; i<d_children.size(); i++ ){
+ collectBoundVar( qi, d_children[i].d_n, c_to_vars[i] );
+ assigned.push_back( false );
+ vb_count[i] = 0;
+ vu_count[i] = 0;
+ for( unsigned j=0; j<c_to_vars[i].size(); j++ ){
+ int v = c_to_vars[i][j];
+ vars_to_c[v].push_back( i );
+ if( std::find( bvars.begin(), bvars.end(), v )==bvars.end() ){
+ vu_count[i]++;
+ if( !isCom ){
+ bvars.push_back( v );
+ }
+ }else{
+ vb_count[i]++;
+ }
+ }
+ }
+ if( isCom ){
+ //children that bind the least number of unbound variables go first
+ do {
+ int min_score = -1;
+ int min_score_index = -1;
+ for( unsigned i=0; i<d_children.size(); i++ ){
+ if( !assigned[i] ){
+ int score = vu_count[i];
+ if( min_score==-1 || score<min_score ){
+ min_score = score;
+ min_score_index = i;
+ }
+ }
+ }
+ Trace("qcf-qregister-debug") << "...assign child " << min_score_index << "/" << d_children.size() << std::endl;
+ Assert( min_score_index!=-1 );
+ //add to children order
+ d_children_order.push_back( min_score_index );
+ assigned[min_score_index] = true;
+ //if( vb_count[min_score_index]==0 ){
+ // d_independent.push_back( min_score_index );
+ //}
+ //determine order internal to children
+ d_children[min_score_index].determineVariableOrder( qi, bvars );
+ Trace("qcf-qregister-debug") << "...bind variables" << std::endl;
+ //now, make it a bound variable
+ for( unsigned i=0; i<c_to_vars[min_score_index].size(); i++ ){
+ int v = c_to_vars[min_score_index][i];
+ if( std::find( bvars.begin(), bvars.end(), v )==bvars.end() ){
+ for( unsigned j=0; j<vars_to_c[v].size(); j++ ){
+ int vc = vars_to_c[v][j];
+ vu_count[vc]--;
+ vb_count[vc]++;
+ }
+ bvars.push_back( v );
+ }
+ }
+ Trace("qcf-qregister-debug") << "...done assign child " << min_score_index << std::endl;
+ }while( d_children_order.size()!=d_children.size() );
+ Trace("qcf-qregister-debug") << "Done assign variable ordering for " << d_n << std::endl;
+ }else{
+ for( unsigned i=0; i<d_children.size(); i++ ){
+ d_children_order.push_back( i );
+ d_children[i].determineVariableOrder( qi, bvars );
+ }
+ }
+}
+
+
+void MatchGen::reset_round( QuantConflictFind * p ) {
+ d_wasSet = false;
+ for( unsigned i=0; i<d_children.size(); i++ ){
+ d_children[i].reset_round( p );
+ }
+ for( std::map< int, TNode >::iterator it = d_qni_gterm.begin(); it != d_qni_gterm.end(); ++it ){
+ d_qni_gterm_rep[it->first] = p->getRepresentative( it->second );
+ }
+ if( d_type==typ_ground ){
+ int e = p->evaluate( d_n );
+ if( e==1 ){
+ d_ground_eval[0] = p->d_true;
+ }else if( e==-1 ){
+ d_ground_eval[0] = p->d_false;
+ }
+ }else if( d_type==typ_eq ){
+ for( unsigned i=0; i<d_n.getNumChildren(); i++ ){
+ if( !d_n[i].hasBoundVar() ){
+ d_ground_eval[i] = p->evaluateTerm( d_n[i] );
+ }
+ }
+ }
+ d_qni_bound_cons.clear();
+ d_qni_bound_cons_var.clear();
+ d_qni_bound.clear();
+}
+
+void MatchGen::reset( QuantConflictFind * p, bool tgt, QuantInfo * qi ) {
+ d_tgt = d_type_not ? !tgt : tgt;
+ Debug("qcf-match") << " Reset for : " << d_n << ", type : ";
+ debugPrintType( "qcf-match", d_type );
+ Debug("qcf-match") << ", tgt = " << d_tgt << ", children = " << d_children.size() << " " << d_children_order.size() << std::endl;
+ d_qn.clear();
+ d_qni.clear();
+ d_qni_bound.clear();
+ d_child_counter = -1;
+ d_tgt_orig = d_tgt;
+
+ //set up processing matches
+ if( d_type==typ_invalid ){
+ //do nothing
+ }else if( d_type==typ_ground ){
+ if( d_ground_eval[0]==( d_tgt ? p->d_true : p->d_false ) ){
+ d_child_counter = 0;
+ }
+ }else if( d_type==typ_bool_var ){
+ //get current value of the variable
+ TNode n = qi->getCurrentValue( d_n );
+ int vn = qi->getCurrentRepVar( qi->getVarNum( n ) );
+ if( vn==-1 ){
+ //evaluate the value, see if it is compatible
+ int e = p->evaluate( n );
+ if( ( e==1 && d_tgt ) || ( e==0 && !d_tgt ) ){
+ d_child_counter = 0;
+ }
+ }else{
+ //unassigned, set match to true/false
+ d_qni_bound[0] = vn;
+ qi->setMatch( p, vn, d_tgt ? p->d_true : p->d_false );
+ d_child_counter = 0;
+ }
+ if( d_child_counter==0 ){
+ d_qn.push_back( NULL );
+ }
+ }else if( d_type==typ_var ){
+ Assert( isHandledUfTerm( d_n ) );
+ Node f = getOperator( p, d_n );
+ Debug("qcf-match-debug") << " reset: Var will match operators of " << f << std::endl;
+ TermArgTrie * qni = p->getTermDatabase()->getTermArgTrie( Node::null(), f );
+ if( qni!=NULL ){
+ d_qn.push_back( qni );
+ }
+ d_matched_basis = false;
+ }else if( d_type==typ_tsym || d_type==typ_tconstraint ){
+ for( std::map< int, int >::iterator it = d_qni_var_num.begin(); it != d_qni_var_num.end(); ++it ){
+ int repVar = qi->getCurrentRepVar( it->second );
+ if( qi->d_match[repVar].isNull() ){
+ Debug("qcf-match-debug") << "Force matching on child #" << it->first << ", which is var #" << repVar << std::endl;
+ d_qni_bound[it->first] = repVar;
+ }
+ }
+ d_qn.push_back( NULL );
+ }else if( d_type==typ_pred || d_type==typ_eq ){
+ //add initial constraint
+ Node nn[2];
+ int vn[2];
+ if( d_type==typ_pred ){
+ nn[0] = qi->getCurrentValue( d_n );
+ vn[0] = qi->getCurrentRepVar( qi->getVarNum( nn[0] ) );
+ nn[1] = p->getRepresentative( d_tgt ? p->d_true : p->d_false );
+ vn[1] = -1;
+ d_tgt = true;
+ }else{
+ for( unsigned i=0; i<2; i++ ){
+ TNode nc;
+ std::map< int, TNode >::iterator it = d_qni_gterm_rep.find( i );
+ if( it!=d_qni_gterm_rep.end() ){
+ nc = it->second;
+ }else{
+ nc = d_n[i];
+ }
+ nn[i] = qi->getCurrentValue( nc );
+ vn[i] = qi->getCurrentRepVar( qi->getVarNum( nn[i] ) );
+ }
+ }
+ bool success;
+ if( vn[0]==-1 && vn[1]==-1 ){
+ //Trace("qcf-explain") << " reset : " << d_n << " check ground values " << nn[0] << " " << nn[1] << " (tgt=" << d_tgt << ")" << std::endl;
+ Debug("qcf-match-debug") << " reset: check ground values " << nn[0] << " " << nn[1] << " (" << d_tgt << ")" << std::endl;
+ //just compare values
+ if( d_tgt ){
+ success = p->areMatchEqual( nn[0], nn[1] );
+ }else{
+ if( p->d_effort==QuantConflictFind::effort_conflict ){
+ success = p->areDisequal( nn[0], nn[1] );
+ }else{
+ success = p->areMatchDisequal( nn[0], nn[1] );
+ }
+ }
+ }else{
+ //otherwise, add a constraint to a variable
+ if( vn[1]!=-1 && vn[0]==-1 ){
+ //swap
+ Node t = nn[1];
+ nn[1] = nn[0];
+ nn[0] = t;
+ vn[0] = vn[1];
+ vn[1] = -1;
+ }
+ Debug("qcf-match-debug") << " reset: add constraint " << vn[0] << " -> " << nn[1] << " (vn=" << vn[1] << ")" << std::endl;
+ //add some constraint
+ int addc = qi->addConstraint( p, vn[0], nn[1], vn[1], d_tgt, false );
+ success = addc!=-1;
+ //if successful and non-redundant, store that we need to cleanup this
+ if( addc==1 ){
+ //Trace("qcf-explain") << " reset: " << d_n << " add constraint " << vn[0] << " -> " << nn[1] << " (vn=" << vn[1] << ")" << ", d_tgt = " << d_tgt << std::endl;
+ for( unsigned i=0; i<2; i++ ){
+ if( vn[i]!=-1 && std::find( d_qni_bound_except.begin(), d_qni_bound_except.end(), i )==d_qni_bound_except.end() ){
+ d_qni_bound[vn[i]] = vn[i];
+ }
+ }
+ d_qni_bound_cons[vn[0]] = nn[1];
+ d_qni_bound_cons_var[vn[0]] = vn[1];
+ }
+ }
+ //if successful, we will bind values to variables
+ if( success ){
+ d_qn.push_back( NULL );
+ }
+ }else{
+ if( d_children.empty() ){
+ //add dummy
+ d_qn.push_back( NULL );
+ }else{
+ if( d_tgt && d_n.getKind()==FORALL ){
+ //do nothing
+ }else{
+ //reset the first child to d_tgt
+ d_child_counter = 0;
+ getChild( d_child_counter )->reset( p, d_tgt, qi );
+ }
+ }
+ }
+ d_binding = false;
+ d_wasSet = true;
+ Debug("qcf-match") << " reset: Finished reset for " << d_n << ", success = " << ( !d_qn.empty() || d_child_counter!=-1 ) << std::endl;
+}
+
+bool MatchGen::getNextMatch( QuantConflictFind * p, QuantInfo * qi ) {
+ Debug("qcf-match") << " Get next match for : " << d_n << ", type = ";
+ debugPrintType( "qcf-match", d_type );
+ Debug("qcf-match") << ", children = " << d_children.size() << ", binding = " << d_binding << std::endl;
+ if( d_type==typ_invalid || d_type==typ_ground ){
+ if( d_child_counter==0 ){
+ d_child_counter = -1;
+ return true;
+ }else{
+ d_wasSet = false;
+ return false;
+ }
+ }else if( d_type==typ_var || d_type==typ_eq || d_type==typ_pred || d_type==typ_bool_var || d_type==typ_tconstraint || d_type==typ_tsym ){
+ bool success = false;
+ bool terminate = false;
+ do {
+ bool doReset = false;
+ bool doFail = false;
+ if( !d_binding ){
+ if( doMatching( p, qi ) ){
+ Debug("qcf-match-debug") << " - Matching succeeded" << std::endl;
+ d_binding = true;
+ d_binding_it = d_qni_bound.begin();
+ doReset = true;
+ //for tconstraint, add constraint
+ if( d_type==typ_tconstraint ){
+ std::map< Node, bool >::iterator it = qi->d_tconstraints.find( d_n );
+ if( it==qi->d_tconstraints.end() ){
+ qi->d_tconstraints[d_n] = d_tgt;
+ //store that we added this constraint
+ d_qni_bound_cons[0] = d_n;
+ }else if( d_tgt!=it->second ){
+ success = false;
+ terminate = true;
+ }
+ }
+ }else{
+ Debug("qcf-match-debug") << " - Matching failed" << std::endl;
+ success = false;
+ terminate = true;
+ }
+ }else{
+ doFail = true;
+ }
+ if( d_binding ){
+ //also need to create match for each variable we bound
+ success = true;
+ Debug("qcf-match-debug") << " Produce matches for bound variables by " << d_n << ", type = ";
+ debugPrintType( "qcf-match-debug", d_type );
+ Debug("qcf-match-debug") << "..." << std::endl;
+
+ while( ( success && d_binding_it!=d_qni_bound.end() ) || doFail ){
+ std::map< int, MatchGen * >::iterator itm;
+ if( !doFail ){
+ Debug("qcf-match-debug") << " check variable " << d_binding_it->second << std::endl;
+ itm = qi->d_var_mg.find( d_binding_it->second );
+ }
+ if( doFail || ( d_binding_it->first!=0 && itm!=qi->d_var_mg.end() ) ){
+ Debug("qcf-match-debug") << " we had bound variable " << d_binding_it->second << ", reset = " << doReset << std::endl;
+ if( doReset ){
+ itm->second->reset( p, true, qi );
+ }
+ if( doFail || !itm->second->getNextMatch( p, qi ) ){
+ do {
+ if( d_binding_it==d_qni_bound.begin() ){
+ Debug("qcf-match-debug") << " failed." << std::endl;
+ success = false;
+ }else{
+ --d_binding_it;
+ Debug("qcf-match-debug") << " decrement..." << std::endl;
+ }
+ }while( success && ( d_binding_it->first==0 || qi->d_var_mg.find( d_binding_it->second )==qi->d_var_mg.end() ) );
+ doReset = false;
+ doFail = false;
+ }else{
+ Debug("qcf-match-debug") << " increment..." << std::endl;
+ ++d_binding_it;
+ doReset = true;
+ }
+ }else{
+ Debug("qcf-match-debug") << " skip..." << d_binding_it->second << std::endl;
+ ++d_binding_it;
+ doReset = true;
+ }
+ }
+ if( !success ){
+ d_binding = false;
+ }else{
+ terminate = true;
+ if( d_binding_it==d_qni_bound.begin() ){
+ d_binding = false;
+ }
+ }
+ }
+ }while( !terminate );
+ //if not successful, clean up the variables you bound
+ if( !success ){
+ if( d_type==typ_eq || d_type==typ_pred ){
+ //clean up the constraints you added
+ for( std::map< int, TNode >::iterator it = d_qni_bound_cons.begin(); it != d_qni_bound_cons.end(); ++it ){
+ if( !it->second.isNull() ){
+ Debug("qcf-match") << " Clean up bound var " << it->first << (d_tgt ? "!" : "") << " = " << it->second << std::endl;
+ std::map< int, int >::iterator itb = d_qni_bound_cons_var.find( it->first );
+ int vn = itb!=d_qni_bound_cons_var.end() ? itb->second : -1;
+ //Trace("qcf-explain") << " cleanup: " << d_n << " remove constraint " << it->first << " -> " << it->second << " (vn=" << vn << ")" << ", d_tgt = " << d_tgt << std::endl;
+ qi->addConstraint( p, it->first, it->second, vn, d_tgt, true );
+ }
+ }
+ d_qni_bound_cons.clear();
+ d_qni_bound_cons_var.clear();
+ d_qni_bound.clear();
+ }else{
+ //clean up the matches you set
+ for( std::map< int, int >::iterator it = d_qni_bound.begin(); it != d_qni_bound.end(); ++it ){
+ Debug("qcf-match") << " Clean up bound var " << it->second << std::endl;
+ Assert( it->second<qi->getNumVars() );
+ qi->d_match[ it->second ] = TNode::null();
+ qi->d_match_term[ it->second ] = TNode::null();
+ }
+ d_qni_bound.clear();
+ }
+ if( d_type==typ_tconstraint ){
+ //remove constraint if applicable
+ if( d_qni_bound_cons.find( 0 )!=d_qni_bound_cons.end() ){
+ qi->d_tconstraints.erase( d_n );
+ d_qni_bound_cons.clear();
+ }
+ }
+ /*
+ if( d_type==typ_var && p->d_effort==QuantConflictFind::effort_mc && !d_matched_basis ){
+ d_matched_basis = true;
+ Node f = getOperator( d_n );
+ TNode mbo = p->getQuantifiersEngine()->getTermDatabase()->getModelBasisOpTerm( f );
+ if( qi->setMatch( p, d_qni_var_num[0], mbo ) ){
+ success = true;
+ d_qni_bound[0] = d_qni_var_num[0];
+ }
+ }
+ */
+ }
+ Debug("qcf-match") << " ...finished matching for " << d_n << ", success = " << success << std::endl;
+ d_wasSet = success;
+ return success;
+ }else if( d_type==typ_formula || d_type==typ_ite_var ){
+ bool success = false;
+ if( d_child_counter<0 ){
+ if( d_child_counter<-1 ){
+ success = true;
+ d_child_counter = -1;
+ }
+ }else{
+ while( !success && d_child_counter>=0 ){
+ //transition system based on d_child_counter
+ if( d_n.getKind()==OR || d_n.getKind()==AND ){
+ if( (d_n.getKind()==AND)==d_tgt ){
+ //all children must match simultaneously
+ if( getChild( d_child_counter )->getNextMatch( p, qi ) ){
+ if( d_child_counter<(int)(getNumChildren()-1) ){
+ d_child_counter++;
+ Debug("qcf-match-debug") << " Reset child " << d_child_counter << " of " << d_n << std::endl;
+ getChild( d_child_counter )->reset( p, d_tgt, qi );
+ }else{
+ success = true;
+ }
+ }else{
+ //if( std::find( d_independent.begin(), d_independent.end(), d_child_counter )!=d_independent.end() ){
+ // d_child_counter--;
+ //}else{
+ d_child_counter--;
+ //}
+ }
+ }else{
+ //one child must match
+ if( !getChild( d_child_counter )->getNextMatch( p, qi ) ){
+ if( d_child_counter<(int)(getNumChildren()-1) ){
+ d_child_counter++;
+ Debug("qcf-match-debug") << " Reset child " << d_child_counter << " of " << d_n << ", one match" << std::endl;
+ getChild( d_child_counter )->reset( p, d_tgt, qi );
+ }else{
+ d_child_counter = -1;
+ }
+ }else{
+ success = true;
+ }
+ }
+ }else if( d_n.getKind()==IFF ){
+ //construct match based on both children
+ if( d_child_counter%2==0 ){
+ if( getChild( 0 )->getNextMatch( p, qi ) ){
+ d_child_counter++;
+ getChild( 1 )->reset( p, d_child_counter==1, qi );
+ }else{
+ if( d_child_counter==0 ){
+ d_child_counter = 2;
+ getChild( 0 )->reset( p, !d_tgt, qi );
+ }else{
+ d_child_counter = -1;
+ }
+ }
+ }
+ if( d_child_counter>=0 && d_child_counter%2==1 ){
+ if( getChild( 1 )->getNextMatch( p, qi ) ){
+ success = true;
+ }else{
+ d_child_counter--;
+ }
+ }
+ }else if( d_n.getKind()==ITE ){
+ if( d_child_counter%2==0 ){
+ int index1 = d_child_counter==4 ? 1 : 0;
+ if( getChild( index1 )->getNextMatch( p, qi ) ){
+ d_child_counter++;
+ getChild( d_child_counter==5 ? 2 : (d_tgt==(d_child_counter==1) ? 1 : 2) )->reset( p, d_tgt, qi );
+ }else{
+ if( d_child_counter==4 || ( d_type==typ_ite_var && d_child_counter==2 ) ){
+ d_child_counter = -1;
+ }else{
+ d_child_counter +=2;
+ getChild( d_child_counter==2 ? 0 : 1 )->reset( p, d_child_counter==2 ? !d_tgt : d_tgt, qi );
+ }
+ }
+ }
+ if( d_child_counter>=0 && d_child_counter%2==1 ){
+ int index2 = d_child_counter==5 ? 2 : (d_tgt==(d_child_counter==1) ? 1 : 2);
+ if( getChild( index2 )->getNextMatch( p, qi ) ){
+ success = true;
+ }else{
+ d_child_counter--;
+ }
+ }
+ }else if( d_n.getKind()==FORALL ){
+ if( getChild( d_child_counter )->getNextMatch( p, qi ) ){
+ success = true;
+ }else{
+ d_child_counter = -1;
+ }
+ }
+ }
+ d_wasSet = success;
+ Debug("qcf-match") << " ...finished construct match for " << d_n << ", success = " << success << std::endl;
+ return success;
+ }
+ }
+ Debug("qcf-match") << " ...already finished for " << d_n << std::endl;
+ return false;
+}
+
+bool MatchGen::getExplanation( QuantConflictFind * p, QuantInfo * qi, std::vector< Node >& exp ) {
+ if( d_type==typ_eq ){
+ Node n[2];
+ for( unsigned i=0; i<2; i++ ){
+ Trace("qcf-explain") << "Explain term " << d_n[i] << "..." << std::endl;
+ n[i] = getExplanationTerm( p, qi, d_n[i], exp );
+ }
+ Node eq = n[0].eqNode( n[1] );
+ if( !d_tgt_orig ){
+ eq = eq.negate();
+ }
+ exp.push_back( eq );
+ Trace("qcf-explain") << "Explanation for " << d_n << " (tgt=" << d_tgt_orig << ") is " << eq << ", set = " << d_wasSet << std::endl;
+ return true;
+ }else if( d_type==typ_pred ){
+ Trace("qcf-explain") << "Explain term " << d_n << "..." << std::endl;
+ Node n = getExplanationTerm( p, qi, d_n, exp );
+ if( !d_tgt_orig ){
+ n = n.negate();
+ }
+ exp.push_back( n );
+ Trace("qcf-explain") << "Explanation for " << d_n << " (tgt=" << d_tgt_orig << ") is " << n << ", set = " << d_wasSet << std::endl;
+ return true;
+ }else if( d_type==typ_formula ){
+ Trace("qcf-explain") << "Explanation get for " << d_n << ", counter = " << d_child_counter << ", tgt = " << d_tgt_orig << ", set = " << d_wasSet << std::endl;
+ if( d_n.getKind()==OR || d_n.getKind()==AND ){
+ if( (d_n.getKind()==AND)==d_tgt ){
+ for( unsigned i=0; i<getNumChildren(); i++ ){
+ if( !getChild( i )->getExplanation( p, qi, exp ) ){
+ return false;
+ }
+ }
+ }else{
+ return getChild( d_child_counter )->getExplanation( p, qi, exp );
+ }
+ }else if( d_n.getKind()==IFF ){
+ for( unsigned i=0; i<2; i++ ){
+ if( !getChild( i )->getExplanation( p, qi, exp ) ){
+ return false;
+ }
+ }
+ }else if( d_n.getKind()==ITE ){
+ for( unsigned i=0; i<3; i++ ){
+ bool isActive = ( ( i==0 && d_child_counter!=5 ) ||
+ ( i==1 && d_child_counter!=( d_tgt ? 3 : 1 ) ) ||
+ ( i==2 && d_child_counter!=( d_tgt ? 1 : 3 ) ) );
+ if( isActive ){
+ if( !getChild( i )->getExplanation( p, qi, exp ) ){
+ return false;
+ }
+ }
+ }
+ }else{
+ return false;
+ }
+ return true;
+ }else{
+ return false;
+ }
+}
+
+Node MatchGen::getExplanationTerm( QuantConflictFind * p, QuantInfo * qi, Node t, std::vector< Node >& exp ) {
+ Node v = qi->getCurrentExpValue( t );
+ if( isHandledUfTerm( t ) ){
+ for( unsigned i=0; i<t.getNumChildren(); i++ ){
+ Node vi = getExplanationTerm( p, qi, t[i], exp );
+ if( vi!=v[i] ){
+ Node eq = vi.eqNode( v[i] );
+ if( std::find( exp.begin(), exp.end(), eq )==exp.end() ){
+ Trace("qcf-explain") << " add : " << eq << "." << std::endl;
+ exp.push_back( eq );
+ }
+ }
+ }
+ }
+ return v;
+}
+
+bool MatchGen::doMatching( QuantConflictFind * p, QuantInfo * qi ) {
+ if( !d_qn.empty() ){
+ if( d_qn[0]==NULL ){
+ d_qn.clear();
+ return true;
+ }else{
+ Assert( d_type==typ_var );
+ Assert( d_qni_size>0 );
+ bool invalidMatch;
+ do {
+ invalidMatch = false;
+ Debug("qcf-match-debug") << " Do matching " << d_n << " " << d_qn.size() << " " << d_qni.size() << std::endl;
+ if( d_qn.size()==d_qni.size()+1 ) {
+ int index = (int)d_qni.size();
+ //initialize
+ TNode val;
+ std::map< int, int >::iterator itv = d_qni_var_num.find( index );
+ if( itv!=d_qni_var_num.end() ){
+ //get the representative variable this variable is equal to
+ int repVar = qi->getCurrentRepVar( itv->second );
+ Debug("qcf-match-debug") << " Match " << index << " is a variable " << itv->second << ", which is repVar " << repVar << std::endl;
+ //get the value the rep variable
+ //std::map< int, TNode >::iterator itm = qi->d_match.find( repVar );
+ if( !qi->d_match[repVar].isNull() ){
+ val = qi->d_match[repVar];
+ Debug("qcf-match-debug") << " Variable is already bound to " << val << std::endl;
+ }else{
+ //binding a variable
+ d_qni_bound[index] = repVar;
+ std::map< TNode, TermArgTrie >::iterator it = d_qn[index]->d_data.begin();
+ if( it != d_qn[index]->d_data.end() ) {
+ d_qni.push_back( it );
+ //set the match
+ if( qi->setMatch( p, d_qni_bound[index], it->first ) ){
+ Debug("qcf-match-debug") << " Binding variable" << std::endl;
+ if( d_qn.size()<d_qni_size ){
+ d_qn.push_back( &it->second );
+ }
+ }else{
+ Debug("qcf-match") << " Binding variable, currently fail." << std::endl;
+ invalidMatch = true;
+ }
+ }else{
+ Debug("qcf-match-debug") << " Binding variable, fail, no more variables to bind" << std::endl;
+ d_qn.pop_back();
+ }
+ }
+ }else{
+ Debug("qcf-match-debug") << " Match " << index << " is ground term" << std::endl;
+ Assert( d_qni_gterm.find( index )!=d_qni_gterm.end() );
+ Assert( d_qni_gterm_rep.find( index )!=d_qni_gterm_rep.end() );
+ val = d_qni_gterm_rep[index];
+ Assert( !val.isNull() );
+ }
+ if( !val.isNull() ){
+ //constrained by val
+ std::map< TNode, TermArgTrie >::iterator it = d_qn[index]->d_data.find( val );
+ if( it!=d_qn[index]->d_data.end() ){
+ Debug("qcf-match-debug") << " Match" << std::endl;
+ d_qni.push_back( it );
+ if( d_qn.size()<d_qni_size ){
+ d_qn.push_back( &it->second );
+ }
+ }else{
+ Debug("qcf-match-debug") << " Failed to match" << std::endl;
+ d_qn.pop_back();
+ }
+ }
+ }else{
+ Assert( d_qn.size()==d_qni.size() );
+ int index = d_qni.size()-1;
+ //increment if binding this variable
+ bool success = false;
+ std::map< int, int >::iterator itb = d_qni_bound.find( index );
+ if( itb!=d_qni_bound.end() ){
+ d_qni[index]++;
+ if( d_qni[index]!=d_qn[index]->d_data.end() ){
+ success = true;
+ if( qi->setMatch( p, itb->second, d_qni[index]->first ) ){
+ Debug("qcf-match-debug") << " Bind next variable" << std::endl;
+ if( d_qn.size()<d_qni_size ){
+ d_qn.push_back( &d_qni[index]->second );
+ }
+ }else{
+ Debug("qcf-match-debug") << " Bind next variable, currently fail" << std::endl;
+ invalidMatch = true;
+ }
+ }else{
+ qi->d_match[ itb->second ] = TNode::null();
+ qi->d_match_term[ itb->second ] = TNode::null();
+ Debug("qcf-match-debug") << " Bind next variable, no more variables to bind" << std::endl;
+ }
+ }else{
+ //TODO : if it equal to something else, also try that
+ }
+ //if not incrementing, move to next
+ if( !success ){
+ d_qn.pop_back();
+ d_qni.pop_back();
+ }
+ }
+ }while( ( !d_qn.empty() && d_qni.size()!=d_qni_size ) || invalidMatch );
+ if( d_qni.size()==d_qni_size ){
+ //Assert( !d_qni[d_qni.size()-1]->second.d_data.empty() );
+ //Debug("qcf-match-debug") << " We matched " << d_qni[d_qni.size()-1]->second.d_children.begin()->first << std::endl;
+ Assert( !d_qni[d_qni.size()-1]->second.d_data.empty() );
+ TNode t = d_qni[d_qni.size()-1]->second.d_data.begin()->first;
+ Debug("qcf-match-debug") << " " << d_n << " matched " << t << std::endl;
+ qi->d_match_term[d_qni_var_num[0]] = t;
+ //set the match terms
+ for( std::map< int, int >::iterator it = d_qni_bound.begin(); it != d_qni_bound.end(); ++it ){
+ Debug("qcf-match-debug") << " position " << it->first << " bounded " << it->second << " / " << qi->d_q[0].getNumChildren() << std::endl;
+ //if( it->second<(int)qi->d_q[0].getNumChildren() ){ //if it is an actual variable, we are interested in knowing the actual term
+ if( it->first>0 ){
+ Assert( !qi->d_match[ it->second ].isNull() );
+ Assert( p->areEqual( t[it->first-1], qi->d_match[ it->second ] ) );
+ qi->d_match_term[it->second] = t[it->first-1];
+ }
+ //}
+ }
+ }
+ }
+ }
+ return !d_qn.empty();
+}
+
+void MatchGen::debugPrintType( const char * c, short typ, bool isTrace ) {
+ if( isTrace ){
+ switch( typ ){
+ case typ_invalid: Trace(c) << "invalid";break;
+ case typ_ground: Trace(c) << "ground";break;
+ case typ_eq: Trace(c) << "eq";break;
+ case typ_pred: Trace(c) << "pred";break;
+ case typ_formula: Trace(c) << "formula";break;
+ case typ_var: Trace(c) << "var";break;
+ case typ_ite_var: Trace(c) << "ite_var";break;
+ case typ_bool_var: Trace(c) << "bool_var";break;
+ }
+ }else{
+ switch( typ ){
+ case typ_invalid: Debug(c) << "invalid";break;
+ case typ_ground: Debug(c) << "ground";break;
+ case typ_eq: Debug(c) << "eq";break;
+ case typ_pred: Debug(c) << "pred";break;
+ case typ_formula: Debug(c) << "formula";break;
+ case typ_var: Debug(c) << "var";break;
+ case typ_ite_var: Debug(c) << "ite_var";break;
+ case typ_bool_var: Debug(c) << "bool_var";break;
+ }
+ }
+}
+
+void MatchGen::setInvalid() {
+ d_type = typ_invalid;
+ d_children.clear();
+}
+
+bool MatchGen::isHandledBoolConnective( TNode n ) {
+ return n.getType().isBoolean() && ( n.getKind()==OR || n.getKind()==AND || n.getKind()==IFF || n.getKind()==ITE || n.getKind()==FORALL || n.getKind()==NOT );
+}
+
+bool MatchGen::isHandledUfTerm( TNode n ) {
+ //return n.getKind()==APPLY_UF || n.getKind()==STORE || n.getKind()==SELECT ||
+ // n.getKind()==APPLY_CONSTRUCTOR || n.getKind()==APPLY_SELECTOR_TOTAL || n.getKind()==APPLY_TESTER;
+ return inst::Trigger::isAtomicTriggerKind( n.getKind() );
+}
+
+Node MatchGen::getOperator( QuantConflictFind * p, Node n ) {
+ if( isHandledUfTerm( n ) ){
+ return p->getQuantifiersEngine()->getTermDatabase()->getOperator( n );
+ }else{
+ return Node::null();
+ }
+}
+
+bool MatchGen::isHandled( TNode n ) {
+ if( n.getKind()!=BOUND_VARIABLE && n.hasBoundVar() ){
+ if( !isHandledBoolConnective( n ) && !isHandledUfTerm( n ) && n.getKind()!=EQUAL && n.getKind()!=ITE ){
+ return false;
+ }
+ for( unsigned i=0; i<n.getNumChildren(); i++ ){
+ if( !isHandled( n[i] ) ){
+ return false;
+ }
+ }
+ }
+ return true;
+}
+
+
+QuantConflictFind::QuantConflictFind( QuantifiersEngine * qe, context::Context* c ) :
+QuantifiersModule( qe ),
+d_c( c ),
+d_conflict( c, false ),
+d_qassert( c ) {
+ d_fid_count = 0;
+ d_true = NodeManager::currentNM()->mkConst<bool>(true);
+ d_false = NodeManager::currentNM()->mkConst<bool>(false);
+}
+
+Node QuantConflictFind::mkEqNode( Node a, Node b ) {
+ if( a.getType().isBoolean() ){
+ return a.iffNode( b );
+ }else{
+ return a.eqNode( b );
+ }
+}
+
+//-------------------------------------------------- registration
+
+void QuantConflictFind::registerQuantifier( Node q ) {
+ if( !TermDb::isRewriteRule( q ) ){
+ d_quants.push_back( q );
+ d_quant_id[q] = d_quants.size();
+ Trace("qcf-qregister") << "Register ";
+ debugPrintQuant( "qcf-qregister", q );
+ Trace("qcf-qregister") << " : " << q << std::endl;
+ //make QcfNode structure
+ Trace("qcf-qregister") << "- Get relevant equality/disequality pairs, calculate flattening..." << std::endl;
+ d_qinfo[q].initialize( q, q[1] );
+
+ //debug print
+ Trace("qcf-qregister") << "- Flattened structure is :" << std::endl;
+ Trace("qcf-qregister") << " ";
+ debugPrintQuantBody( "qcf-qregister", q, q[1] );
+ Trace("qcf-qregister") << std::endl;
+ if( d_qinfo[q].d_vars.size()>q[0].getNumChildren() ){
+ Trace("qcf-qregister") << " with additional constraints : " << std::endl;
+ for( unsigned j=q[0].getNumChildren(); j<d_qinfo[q].d_vars.size(); j++ ){
+ Trace("qcf-qregister") << " ?x" << j << " = ";
+ debugPrintQuantBody( "qcf-qregister", q, d_qinfo[q].d_vars[j], false );
+ Trace("qcf-qregister") << std::endl;
+ }
+ }
+
+ Trace("qcf-qregister") << "Done registering quantifier." << std::endl;
+ }
+}
+
+int QuantConflictFind::evaluate( Node n, bool pref, bool hasPref ) {
+ int ret = 0;
+ if( n.getKind()==EQUAL ){
+ Node n1 = evaluateTerm( n[0] );
+ Node n2 = evaluateTerm( n[1] );
+ Debug("qcf-eval") << "Evaluate : Normalize " << n << " to " << n1 << " = " << n2 << std::endl;
+ if( areEqual( n1, n2 ) ){
+ ret = 1;
+ }else if( areDisequal( n1, n2 ) ){
+ ret = -1;
+ }
+ //else if( d_effort>QuantConflictFind::effort_conflict ){
+ // ret = -1;
+ //}
+ }else if( MatchGen::isHandledUfTerm( n ) ){ //predicate
+ Node nn = evaluateTerm( n );
+ Debug("qcf-eval") << "Evaluate : Normalize " << nn << " to " << n << std::endl;
+ if( areEqual( nn, d_true ) ){
+ ret = 1;
+ }else if( areEqual( nn, d_false ) ){
+ ret = -1;
+ }
+ //else if( d_effort>QuantConflictFind::effort_conflict ){
+ // ret = -1;
+ //}
+ }else if( n.getKind()==NOT ){
+ return -evaluate( n[0] );
+ }else if( n.getKind()==ITE ){
+ int cev1 = evaluate( n[0] );
+ int cevc[2] = { 0, 0 };
+ for( unsigned i=0; i<2; i++ ){
+ if( ( i==0 && cev1!=-1 ) || ( i==1 && cev1!=1 ) ){
+ cevc[i] = evaluate( n[i+1] );
+ if( cev1!=0 ){
+ ret = cevc[i];
+ break;
+ }else if( cevc[i]==0 ){
+ break;
+ }
+ }
+ }
+ if( ret==0 && cevc[0]!=0 && cevc[0]==cevc[1] ){
+ ret = cevc[0];
+ }
+ }else if( n.getKind()==IFF ){
+ int cev1 = evaluate( n[0] );
+ if( cev1!=0 ){
+ int cev2 = evaluate( n[1] );
+ if( cev2!=0 ){
+ ret = cev1==cev2 ? 1 : -1;
+ }
+ }
+
+ }else{
+ int ssval = 0;
+ if( n.getKind()==OR ){
+ ssval = 1;
+ }else if( n.getKind()==AND ){
+ ssval = -1;
+ }
+ bool isUnk = false;
+ for( unsigned i=0; i<n.getNumChildren(); i++ ){
+ int cev = evaluate( n[i] );
+ if( cev==ssval ){
+ ret = ssval;
+ break;
+ }else if( cev==0 ){
+ isUnk = true;
+ }
+ }
+ if( ret==0 && !isUnk ){
+ ret = -ssval;
+ }
+ }
+ Debug("qcf-eval") << "Evaluate " << n << " to " << ret << std::endl;
+ return ret;
+}
+
+short QuantConflictFind::getMaxQcfEffort() {
+ if( options::qcfMode()==QCF_CONFLICT_ONLY ){
+ return effort_conflict;
+ }else if( options::qcfMode()==QCF_PROP_EQ ){
+ return effort_prop_eq;
+ }else if( options::qcfMode()==QCF_MC ){
+ return effort_mc;
+ }else{
+ return 0;
+ }
+}
+
+bool QuantConflictFind::areMatchEqual( TNode n1, TNode n2 ) {
+ //if( d_effort==QuantConflictFind::effort_mc ){
+ // return n1==n2 || !areDisequal( n1, n2 );
+ //}else{
+ return n1==n2;
+ //}
+}
+
+bool QuantConflictFind::areMatchDisequal( TNode n1, TNode n2 ) {
+ //if( d_effort==QuantConflictFind::effort_conflict ){
+ // return areDisequal( n1, n2 );
+ //}else{
+ return n1!=n2;
+ //}
+}
+
+//-------------------------------------------------- handling assertions / eqc
+
+void QuantConflictFind::assertNode( Node q ) {
+ if( !TermDb::isRewriteRule( q ) ){
+ Trace("qcf-proc") << "QCF : assertQuantifier : ";
+ debugPrintQuant("qcf-proc", q);
+ Trace("qcf-proc") << std::endl;
+ d_qassert.push_back( q );
+ //set the eqRegistries that this depends on to true
+ //for( std::map< EqRegistry *, bool >::iterator it = d_qinfo[q].d_rel_eqr.begin(); it != d_qinfo[q].d_rel_eqr.end(); ++it ){
+ // it->first->d_active.set( true );
+ //}
+ }
+}
+
+eq::EqualityEngine * QuantConflictFind::getEqualityEngine() {
+ //return ((uf::TheoryUF*)d_quantEngine->getTheoryEngine()->theoryOf( theory::THEORY_UF ))->getEqualityEngine();
+ return d_quantEngine->getTheoryEngine()->getMasterEqualityEngine();
+}
+bool QuantConflictFind::areEqual( Node n1, Node n2 ) {
+ return getEqualityEngine()->hasTerm( n1 ) && getEqualityEngine()->hasTerm( n2 ) && getEqualityEngine()->areEqual( n1,n2 );
+}
+bool QuantConflictFind::areDisequal( Node n1, Node n2 ) {
+ return n1!=n2 && getEqualityEngine()->hasTerm( n1 ) && getEqualityEngine()->hasTerm( n2 ) && getEqualityEngine()->areDisequal( n1,n2, false );
+}
+Node QuantConflictFind::getRepresentative( Node n ) {
+ if( getEqualityEngine()->hasTerm( n ) ){
+ return getEqualityEngine()->getRepresentative( n );
+ }else{
+ return n;
+ }
+}
+TermDb* QuantConflictFind::getTermDatabase() {
+ return d_quantEngine->getTermDatabase();
+}
+
+Node QuantConflictFind::evaluateTerm( Node n ) {
+ if( MatchGen::isHandledUfTerm( n ) ){
+ Node f = MatchGen::getOperator( this, n );
+ Node nn;
+ if( getEqualityEngine()->hasTerm( n ) ){
+ nn = getTermDatabase()->existsTerm( f, n );
+ }else{
+ std::vector< TNode > args;
+ for( unsigned i=0; i<n.getNumChildren(); i++ ){
+ Node c = evaluateTerm( n[i] );
+ args.push_back( c );
+ }
+ nn = getTermDatabase()->d_func_map_trie[f].existsTerm( args );
+ }
+ if( !nn.isNull() ){
+ Debug("qcf-eval") << "GT: Term " << nn << " for " << n << " hasTerm = " << getEqualityEngine()->hasTerm( n ) << std::endl;
+ return getRepresentative( nn );
+ }else{
+ Debug("qcf-eval") << "GT: No term for " << n << " hasTerm = " << getEqualityEngine()->hasTerm( n ) << std::endl;
+ return n;
+ }
+ }else if( n.getKind()==ITE ){
+ int v = evaluate( n[0], false, false );
+ if( v==1 ){
+ return evaluateTerm( n[1] );
+ }else if( v==-1 ){
+ return evaluateTerm( n[2] );
+ }
+ }
+ return getRepresentative( n );
+}
+
+/** new node */
+void QuantConflictFind::newEqClass( Node n ) {
+ //Trace("qcf-proc-debug") << "QCF : newEqClass : " << n << std::endl;
+ //Trace("qcf-proc2-debug") << "QCF : finished newEqClass : " << n << std::endl;
+}
+
+/** merge */
+void QuantConflictFind::merge( Node a, Node b ) {
+
+}
+
+/** assert disequal */
+void QuantConflictFind::assertDisequal( Node a, Node b ) {
+
+}
+
+//-------------------------------------------------- check function
+
+bool QuantConflictFind::needsCheck( Theory::Effort level ) {
+ bool performCheck = false;
+ if( options::quantConflictFind() && !d_conflict ){
+ if( level==Theory::EFFORT_LAST_CALL ){
+ performCheck = options::qcfWhenMode()==QCF_WHEN_MODE_LAST_CALL;
+ }else if( level==Theory::EFFORT_FULL ){
+ performCheck = options::qcfWhenMode()==QCF_WHEN_MODE_DEFAULT;
+ }else if( level==Theory::EFFORT_STANDARD ){
+ performCheck = options::qcfWhenMode()==QCF_WHEN_MODE_STD;
+ }
+ }
+ return performCheck;
+}
+
+void QuantConflictFind::reset_round( Theory::Effort level ) {
+ d_needs_computeRelEqr = true;
+}
+
+/** check */
+void QuantConflictFind::check( Theory::Effort level, unsigned quant_e ) {
+ if( quant_e==QuantifiersEngine::QEFFORT_CONFLICT ){
+ Trace("qcf-check") << "QCF : check : " << level << std::endl;
+ if( d_conflict ){
+ Trace("qcf-check2") << "QCF : finished check : already in conflict." << std::endl;
+ if( level>=Theory::EFFORT_FULL ){
+ Trace("qcf-warn") << "ALREADY IN CONFLICT? " << level << std::endl;
+ //Assert( false );
+ }
+ }else{
+ int addedLemmas = 0;
+ ++(d_statistics.d_inst_rounds);
+ double clSet = 0;
+ int prevEt = 0;
+ if( Trace.isOn("qcf-engine") ){
+ prevEt = d_statistics.d_entailment_checks.getData();
+ clSet = double(clock())/double(CLOCKS_PER_SEC);
+ Trace("qcf-engine") << "---Conflict Find Engine Round, effort = " << level << "---" << std::endl;
+ }
+ computeRelevantEqr();
+
+ //determine order for quantified formulas
+ std::vector< Node > qorder;
+ std::map< Node, bool > qassert;
+ //mark which are asserted
+ for( unsigned i=0; i<d_qassert.size(); i++ ){
+ qassert[d_qassert[i]] = true;
+ }
+ //add which ones are specified in the order
+ for( unsigned i=0; i<d_quant_order.size(); i++ ){
+ Node n = d_quant_order[i];
+ if( std::find( qorder.begin(), qorder.end(), n )==qorder.end() && qassert.find( n )!=qassert.end() ){
+ qorder.push_back( n );
+ }
+ }
+ d_quant_order.clear();
+ d_quant_order.insert( d_quant_order.begin(), qorder.begin(), qorder.end() );
+ //add remaining
+ for( unsigned i=0; i<d_qassert.size(); i++ ){
+ Node n = d_qassert[i];
+ if( std::find( qorder.begin(), qorder.end(), n )==qorder.end() ){
+ qorder.push_back( n );
+ }
+ }
+
+ if( Trace.isOn("qcf-debug") ){
+ Trace("qcf-debug") << std::endl;
+ debugPrint("qcf-debug");
+ Trace("qcf-debug") << std::endl;
+ }
+ short end_e = getMaxQcfEffort();
+ for( short e = effort_conflict; e<=end_e; e++ ){
+ d_effort = e;
+ Trace("qcf-check") << "Checking quantified formulas at effort " << e << "..." << std::endl;
+ for( unsigned j=0; j<qorder.size(); j++ ){
+ Node q = qorder[j];
+ QuantInfo * qi = &d_qinfo[q];
+
+ Assert( d_qinfo.find( q )!=d_qinfo.end() );
+ if( qi->d_mg->isValid() ){
+ Trace("qcf-check") << "Check quantified formula ";
+ debugPrintQuant("qcf-check", q);
+ Trace("qcf-check") << " : " << q << "..." << std::endl;
+
+ Trace("qcf-check-debug") << "Reset round..." << std::endl;
+ qi->reset_round( this );
+ //try to make a matches making the body false
+ Trace("qcf-check-debug") << "Get next match..." << std::endl;
+ while( qi->d_mg->getNextMatch( this, qi ) ){
+ Trace("qcf-inst") << "*** Produced match at effort " << e << " : " << std::endl;
+ qi->debugPrintMatch("qcf-inst");
+ Trace("qcf-inst") << std::endl;
+ std::vector< int > assigned;
+ if( !qi->isMatchSpurious( this ) ){
+ if( qi->completeMatch( this, assigned ) ){
+ std::vector< Node > terms;
+ qi->getMatch( terms );
+ if( !qi->isTConstraintSpurious( this, terms ) ){
+ if( Debug.isOn("qcf-check-inst") ){
+ //if( e==effort_conflict ){
+ Node inst = d_quantEngine->getInstantiation( q, terms );
+ Debug("qcf-check-inst") << "Check instantiation " << inst << "..." << std::endl;
+ Assert( evaluate( inst )!=1 );
+ Assert( evaluate( inst )==-1 || e>effort_conflict );
+ //}
+ }
+ if( d_quantEngine->addInstantiation( q, terms, false ) ){
+ Trace("qcf-check") << " ... Added instantiation" << std::endl;
+ Trace("qcf-inst") << "*** Was from effort " << e << " : " << std::endl;
+ qi->debugPrintMatch("qcf-inst");
+ Trace("qcf-inst") << std::endl;
+ ++addedLemmas;
+ if( e==effort_conflict ){
+ d_quant_order.insert( d_quant_order.begin(), q );
+ d_conflict.set( true );
+ ++(d_statistics.d_conflict_inst);
+ break;
+ }else if( e==effort_prop_eq ){
+ ++(d_statistics.d_prop_inst);
+ }
+ }else{
+ Trace("qcf-inst") << " ... Failed to add instantiation" << std::endl;
+ //Assert( false );
+ }
+ }
+ //clean up assigned
+ qi->revertMatch( assigned );
+ d_tempCache.clear();
+ }else{
+ Trace("qcf-inst") << " ... Spurious instantiation (cannot assign unassigned variables)" << std::endl;
+ }
+ }else{
+ Trace("qcf-inst") << " ... Spurious instantiation (match is inconsistent)" << std::endl;
+ }
+ }
+ if( d_conflict ){
+ break;
+ }
+ }
+ }
+ if( addedLemmas>0 ){
+ break;
+ }
+ }
+ if( Trace.isOn("qcf-engine") ){
+ double clSet2 = double(clock())/double(CLOCKS_PER_SEC);
+ Trace("qcf-engine") << "Finished conflict find engine, time = " << (clSet2-clSet);
+ if( addedLemmas>0 ){
+ Trace("qcf-engine") << ", effort = " << ( d_effort==effort_conflict ? "conflict" : ( d_effort==effort_prop_eq ? "prop_eq" : "mc" ) );
+ Trace("qcf-engine") << ", addedLemmas = " << addedLemmas;
+ }
+ Trace("qcf-engine") << std::endl;
+ int currEt = d_statistics.d_entailment_checks.getData();
+ if( currEt!=prevEt ){
+ Trace("qcf-engine") << " Entailment checks = " << ( currEt - prevEt ) << std::endl;
+ }
+ }
+ Trace("qcf-check2") << "QCF : finished check : " << level << std::endl;
+ }
+ }
+}
+
+void QuantConflictFind::computeRelevantEqr() {
+ if( d_needs_computeRelEqr ){
+ d_needs_computeRelEqr = false;
+ Trace("qcf-check") << "Compute relevant equalities..." << std::endl;
+ //d_uf_terms.clear();
+ //d_eqc_uf_terms.clear();
+ d_eqcs.clear();
+ d_model_basis.clear();
+ //d_arg_reps.clear();
+ //double clSet = 0;
+ //if( Trace.isOn("qcf-opt") ){
+ // clSet = double(clock())/double(CLOCKS_PER_SEC);
+ //}
+
+ //long nTermst = 0;
+ //long nTerms = 0;
+ //long nEqc = 0;
+
+ //which nodes are irrelevant for disequality matches
+ std::map< TNode, bool > irrelevant_dnode;
+ //now, store matches
+ eq::EqClassesIterator eqcs_i = eq::EqClassesIterator( getEqualityEngine() );
+ while( !eqcs_i.isFinished() ){
+ //nEqc++;
+ Node r = (*eqcs_i);
+ TypeNode rtn = r.getType();
+ if( options::qcfMode()==QCF_MC ){
+ std::map< TypeNode, std::vector< TNode > >::iterator itt = d_eqcs.find( rtn );
+ if( itt==d_eqcs.end() ){
+ Node mb = getQuantifiersEngine()->getTermDatabase()->getModelBasisTerm( rtn );
+ if( !getEqualityEngine()->hasTerm( mb ) ){
+ Trace("qcf-warn") << "WARNING: Model basis term does not exist!" << std::endl;
+ Assert( false );
+ }
+ Node mbr = getRepresentative( mb );
+ if( mbr!=r ){
+ d_eqcs[rtn].push_back( mbr );
+ }
+ d_eqcs[rtn].push_back( r );
+ d_model_basis[rtn] = mb;
+ }else{
+ itt->second.push_back( r );
+ }
+ }else{
+ d_eqcs[rtn].push_back( r );
+ }
+ ++eqcs_i;
+ }
+ /*
+ if( Trace.isOn("qcf-opt") ){
+ double clSet2 = double(clock())/double(CLOCKS_PER_SEC);
+ Trace("qcf-opt") << "Compute rel eqc : " << std::endl;
+ Trace("qcf-opt") << " " << nEqc << " equivalence classes. " << std::endl;
+ Trace("qcf-opt") << " " << nTerms << " / " << nTermst << " terms." << std::endl;
+ Trace("qcf-opt") << " Time : " << (clSet2-clSet) << std::endl;
+ }
+ */
+ }
+}
+
+
+//-------------------------------------------------- debugging
+
+
+void QuantConflictFind::debugPrint( const char * c ) {
+ //print the equivalance classes
+ Trace(c) << "----------EQ classes" << std::endl;
+ eq::EqClassesIterator eqcs_i = eq::EqClassesIterator( getEqualityEngine() );
+ while( !eqcs_i.isFinished() ){
+ Node n = (*eqcs_i);
+ //if( !n.getType().isInteger() ){
+ Trace(c) << " - " << n << " : {";
+ eq::EqClassIterator eqc_i = eq::EqClassIterator( n, getEqualityEngine() );
+ bool pr = false;
+ while( !eqc_i.isFinished() ){
+ Node nn = (*eqc_i);
+ if( nn.getKind()!=EQUAL && nn!=n ){
+ Trace(c) << (pr ? "," : "" ) << " " << nn;
+ pr = true;
+ }
+ ++eqc_i;
+ }
+ Trace(c) << (pr ? " " : "" ) << "}" << std::endl;
+ /*
+ EqcInfo * eqcn = getEqcInfo( n, false );
+ if( eqcn ){
+ Trace(c) << " DEQ : {";
+ pr = false;
+ for( NodeBoolMap::iterator it = eqcn->d_diseq.begin(); it != eqcn->d_diseq.end(); ++it ){
+ if( (*it).second ){
+ Trace(c) << (pr ? "," : "" ) << " " << (*it).first;
+ pr = true;
+ }
+ }
+ Trace(c) << (pr ? " " : "" ) << "}" << std::endl;
+ }
+ //}
+ */
+ ++eqcs_i;
+ }
+}
+
+void QuantConflictFind::debugPrintQuant( const char * c, Node q ) {
+ Trace(c) << "Q" << d_quant_id[q];
+}
+
+void QuantConflictFind::debugPrintQuantBody( const char * c, Node q, Node n, bool doVarNum ) {
+ if( n.getNumChildren()==0 ){
+ Trace(c) << n;
+ }else if( doVarNum && d_qinfo[q].d_var_num.find( n )!=d_qinfo[q].d_var_num.end() ){
+ Trace(c) << "?x" << d_qinfo[q].d_var_num[n];
+ }else{
+ Trace(c) << "(";
+ if( n.getKind()==APPLY_UF ){
+ Trace(c) << n.getOperator();
+ }else{
+ Trace(c) << n.getKind();
+ }
+ for( unsigned i=0; i<n.getNumChildren(); i++ ){
+ Trace(c) << " ";
+ debugPrintQuantBody( c, q, n[i] );
+ }
+ Trace(c) << ")";
+ }
+}
+
+QuantConflictFind::Statistics::Statistics():
+ d_inst_rounds("QuantConflictFind::Inst_Rounds", 0),
+ d_conflict_inst("QuantConflictFind::Instantiations_Conflict_Find", 0 ),
+ d_prop_inst("QuantConflictFind::Instantiations_Prop", 0 ),
+ d_entailment_checks("QuantConflictFind::Entailment_Checks",0)
+{
+ StatisticsRegistry::registerStat(&d_inst_rounds);
+ StatisticsRegistry::registerStat(&d_conflict_inst);
+ StatisticsRegistry::registerStat(&d_prop_inst);
+ StatisticsRegistry::registerStat(&d_entailment_checks);
+}
+
+QuantConflictFind::Statistics::~Statistics(){
+ StatisticsRegistry::unregisterStat(&d_inst_rounds);
+ StatisticsRegistry::unregisterStat(&d_conflict_inst);
+ StatisticsRegistry::unregisterStat(&d_prop_inst);
+ StatisticsRegistry::unregisterStat(&d_entailment_checks);
+}
+
+TNode QuantConflictFind::getZero( Kind k ) {
+ std::map< Kind, Node >::iterator it = d_zero.find( k );
+ if( it==d_zero.end() ){
+ Node nn;
+ if( k==PLUS ){
+ nn = NodeManager::currentNM()->mkConst( Rational(0) );
+ }
+ d_zero[k] = nn;
+ return nn;
+ }else{
+ return it->second;
+ }
+}
+
+
+}
diff --git a/src/theory/quantifiers/quant_conflict_find.h b/src/theory/quantifiers/quant_conflict_find.h
index 0464c04e5..d8f1c8e6f 100644..100755
--- a/src/theory/quantifiers/quant_conflict_find.h
+++ b/src/theory/quantifiers/quant_conflict_find.h
@@ -1,297 +1,259 @@
-/********************* */
-/*! \file quant_conflict_find.h
- ** \verbatim
- ** Original author: Andrew Reynolds
- ** Major contributors: Morgan Deters
- ** Minor contributors (to current version): none
- ** This file is part of the CVC4 project.
- ** Copyright (c) 2009-2014 New York University and The University of Iowa
- ** See the file COPYING in the top-level source directory for licensing
- ** information.\endverbatim
- **
- ** \brief quantifiers conflict find class
- **/
-
-#include "cvc4_private.h"
-
-#ifndef QUANT_CONFLICT_FIND
-#define QUANT_CONFLICT_FIND
-
-#include "context/cdhashmap.h"
-#include "context/cdchunk_list.h"
-#include "theory/quantifiers_engine.h"
-
-namespace CVC4 {
-namespace theory {
-namespace quantifiers {
-
-class QcfNode;
-
-class QuantConflictFind;
-
-class QcfNodeIndex {
-public:
- std::map< TNode, QcfNodeIndex > d_children;
- void clear() { d_children.clear(); }
- void debugPrint( const char * c, int t );
- Node existsTerm( TNode n, std::vector< TNode >& reps, int index = 0 );
- Node addTerm( TNode n, std::vector< TNode >& reps, int index = 0 );
-};
-
-class QuantInfo;
-
-//match generator
-class MatchGen {
- friend class QuantInfo;
-private:
- //current children information
- int d_child_counter;
- //children of this object
- std::vector< int > d_children_order;
- unsigned getNumChildren() { return d_children.size(); }
- MatchGen * getChild( int i ) { return &d_children[d_children_order[i]]; }
- //MatchGen * getChild( int i ) { return &d_children[i]; }
- //current matching information
- std::vector< QcfNodeIndex * > d_qn;
- std::vector< std::map< TNode, QcfNodeIndex >::iterator > d_qni;
- bool doMatching( QuantConflictFind * p, QuantInfo * qi );
- //for matching : each index is either a variable or a ground term
- unsigned d_qni_size;
- std::map< int, int > d_qni_var_num;
- std::map< int, TNode > d_qni_gterm;
- std::map< int, TNode > d_qni_gterm_rep;
- std::map< int, int > d_qni_bound;
- std::vector< int > d_qni_bound_except;
- std::map< int, TNode > d_qni_bound_cons;
- std::map< int, int > d_qni_bound_cons_var;
- std::map< int, int >::iterator d_binding_it;
- //std::vector< int > d_independent;
- bool d_matched_basis;
- bool d_binding;
- //int getVarBindingVar();
- std::map< int, Node > d_ground_eval;
- //determine variable order
- void determineVariableOrder( QuantInfo * qi, std::vector< int >& bvars );
- void collectBoundVar( QuantInfo * qi, Node n, std::vector< int >& cbvars );
-public:
- //type of the match generator
- enum {
- typ_invalid,
- typ_ground,
- typ_pred,
- typ_eq,
- typ_formula,
- typ_var,
- typ_ite_var,
- typ_bool_var,
- typ_tconstraint,
- typ_tsym,
- };
- void debugPrintType( const char * c, short typ, bool isTrace = false );
-public:
- MatchGen() : d_type( typ_invalid ){}
- MatchGen( QuantInfo * qi, Node n, bool isVar = false );
- bool d_tgt;
- bool d_tgt_orig;
- bool d_wasSet;
- Node d_n;
- std::vector< MatchGen > d_children;
- short d_type;
- bool d_type_not;
- void reset_round( QuantConflictFind * p );
- void reset( QuantConflictFind * p, bool tgt, QuantInfo * qi );
- bool getNextMatch( QuantConflictFind * p, QuantInfo * qi );
- bool getExplanation( QuantConflictFind * p, QuantInfo * qi, std::vector< Node >& exp );
- Node getExplanationTerm( QuantConflictFind * p, QuantInfo * qi, Node t, std::vector< Node >& exp );
- bool isValid() { return d_type!=typ_invalid; }
- void setInvalid();
-
- // is this term treated as UF application?
- static bool isHandledBoolConnective( TNode n );
- static bool isHandledUfTerm( TNode n );
- static Node getOperator( QuantConflictFind * p, Node n );
- //can this node be handled by the algorithm
- static bool isHandled( TNode n );
-};
-
-//info for quantifiers
-class QuantInfo {
-private:
- void registerNode( Node n, bool hasPol, bool pol, bool beneathQuant = false );
- void flatten( Node n, bool beneathQuant );
-private: //for completing match
- std::vector< int > d_unassigned;
- std::vector< TypeNode > d_unassigned_tn;
- int d_unassigned_nvar;
- int d_una_index;
- std::vector< int > d_una_eqc_count;
-public:
- QuantInfo() : d_mg( NULL ) {}
- ~QuantInfo() { delete d_mg; }
- std::vector< TNode > d_vars;
- std::map< TNode, int > d_var_num;
- std::vector< int > d_tsym_vars;
- std::map< TNode, bool > d_inMatchConstraint;
- std::map< int, std::vector< Node > > d_var_constraint[2];
- int getVarNum( TNode v ) { return d_var_num.find( v )!=d_var_num.end() ? d_var_num[v] : -1; }
- bool isVar( TNode v ) { return d_var_num.find( v )!=d_var_num.end(); }
- int getNumVars() { return (int)d_vars.size(); }
- TNode getVar( int i ) { return d_vars[i]; }
-
- MatchGen * d_mg;
- Node d_q;
- std::map< int, MatchGen * > d_var_mg;
- void reset_round( QuantConflictFind * p );
-public:
- //initialize
- void initialize( Node q, Node qn );
- //current constraints
- std::vector< TNode > d_match;
- std::vector< TNode > d_match_term;
- std::map< int, std::map< TNode, int > > d_curr_var_deq;
- std::map< Node, bool > d_tconstraints;
- int getCurrentRepVar( int v );
- TNode getCurrentValue( TNode n );
- TNode getCurrentExpValue( TNode n );
- bool getCurrentCanBeEqual( QuantConflictFind * p, int v, TNode n, bool chDiseq = false );
- int addConstraint( QuantConflictFind * p, int v, TNode n, bool polarity );
- int addConstraint( QuantConflictFind * p, int v, TNode n, int vn, bool polarity, bool doRemove );
- bool setMatch( QuantConflictFind * p, int v, TNode n );
- bool isMatchSpurious( QuantConflictFind * p );
- bool isTConstraintSpurious( QuantConflictFind * p, std::vector< Node >& terms );
- bool entailmentTest( QuantConflictFind * p, Node lit, bool chEnt = true );
- bool completeMatch( QuantConflictFind * p, std::vector< int >& assigned, bool doContinue = false );
- void revertMatch( std::vector< int >& assigned );
- void debugPrintMatch( const char * c );
- bool isConstrainedVar( int v );
-public:
- void getMatch( std::vector< Node >& terms );
-};
-
-class QuantConflictFind : public QuantifiersModule
-{
- friend class QcfNodeIndex;
- friend class MatchGen;
- friend class QuantInfo;
- typedef context::CDChunkList<Node> NodeList;
- typedef context::CDHashMap<Node, bool, NodeHashFunction> NodeBoolMap;
-private:
- context::Context* d_c;
- context::CDO< bool > d_conflict;
- bool d_performCheck;
- std::vector< Node > d_quant_order;
- std::map< Kind, Node > d_zero;
- //for storing nodes created during t-constraint solving (prevents memory leaks)
- std::vector< Node > d_tempCache;
-private:
- std::map< Node, Node > d_op_node;
- int d_fid_count;
- std::map< Node, int > d_fid;
- Node mkEqNode( Node a, Node b );
-public: //for ground terms
- Node d_true;
- Node d_false;
- TNode getZero( Kind k );
-private:
- Node evaluateTerm( Node n );
- int evaluate( Node n, bool pref = false, bool hasPref = false );
-private:
- //currently asserted quantifiers
- NodeList d_qassert;
- std::map< Node, QuantInfo > d_qinfo;
-private: //for equivalence classes
- eq::EqualityEngine * getEqualityEngine();
- bool areDisequal( Node n1, Node n2 );
- bool areEqual( Node n1, Node n2 );
- Node getRepresentative( Node n );
-
-/*
- class EqcInfo {
- public:
- EqcInfo( context::Context* c ) : d_diseq( c ) {}
- NodeBoolMap d_diseq;
- bool isDisequal( Node n ) { return d_diseq.find( n )!=d_diseq.end() && d_diseq[n]; }
- void setDisequal( Node n, bool val = true ) { d_diseq[n] = val; }
- //NodeBoolMap& getRelEqr( int index ) { return index==0 ? d_rel_eqr_e : d_rel_eqr_d; }
- };
- std::map< Node, EqcInfo * > d_eqc_info;
- EqcInfo * getEqcInfo( Node n, bool doCreate = true );
-*/
- // operator -> index(terms)
- std::map< TNode, QcfNodeIndex > d_uf_terms;
- // operator -> index(eqc -> terms)
- std::map< TNode, QcfNodeIndex > d_eqc_uf_terms;
- //get qcf node index
- QcfNodeIndex * getQcfNodeIndex( Node eqc, Node f );
- QcfNodeIndex * getQcfNodeIndex( Node f );
- // type -> list(eqc)
- std::map< TypeNode, std::vector< TNode > > d_eqcs;
- std::map< TypeNode, Node > d_model_basis;
- //mapping from UF terms to representatives of their arguments
- std::map< TNode, std::vector< TNode > > d_arg_reps;
- //compute arg reps
- void computeArgReps( TNode n );
- //compute
- void computeUfTerms( TNode f );
-public:
- enum {
- effort_conflict,
- effort_prop_eq,
- effort_mc,
- };
- short d_effort;
- void setEffort( int e ) { d_effort = e; }
- static short getMaxQcfEffort();
- bool areMatchEqual( TNode n1, TNode n2 );
- bool areMatchDisequal( TNode n1, TNode n2 );
-public:
- QuantConflictFind( QuantifiersEngine * qe, context::Context* c );
- /** register quantifier */
- void registerQuantifier( Node q );
-public:
- /** assert quantifier */
- void assertNode( Node q );
- /** new node */
- void newEqClass( Node n );
- /** merge */
- void merge( Node a, Node b );
- /** assert disequal */
- void assertDisequal( Node a, Node b );
- /** reset round */
- void reset_round( Theory::Effort level );
- /** check */
- void check( Theory::Effort level );
- /** needs check */
- bool needsCheck( Theory::Effort level );
-private:
- bool d_needs_computeRelEqr;
-public:
- void computeRelevantEqr();
-private:
- void debugPrint( const char * c );
- //for debugging
- std::vector< Node > d_quants;
- std::map< Node, int > d_quant_id;
- void debugPrintQuant( const char * c, Node q );
- void debugPrintQuantBody( const char * c, Node q, Node n, bool doVarNum = true );
-public:
- /** statistics class */
- class Statistics {
- public:
- IntStat d_inst_rounds;
- IntStat d_conflict_inst;
- IntStat d_prop_inst;
- IntStat d_entailment_checks;
- Statistics();
- ~Statistics();
- };
- Statistics d_statistics;
- /** Identify this module */
- std::string identify() const { return "QcfEngine"; }
-};
-
-}
-}
-}
-
-#endif
+/********************* */
+/*! \file quant_conflict_find.h
+ ** \verbatim
+ ** Original author: Andrew Reynolds
+ ** Major contributors: none
+ ** Minor contributors (to current version): none
+ ** This file is part of the CVC4 project.
+ ** Copyright (c) 2009-2014 New York University and The University of Iowa
+ ** See the file COPYING in the top-level source directory for licensing
+ ** information.\endverbatim
+ **
+ ** \brief quantifiers conflict find class
+ **/
+
+#include "cvc4_private.h"
+
+#ifndef QUANT_CONFLICT_FIND
+#define QUANT_CONFLICT_FIND
+
+#include "context/cdhashmap.h"
+#include "context/cdchunk_list.h"
+#include "theory/quantifiers_engine.h"
+#include "theory/quantifiers/term_database.h"
+
+namespace CVC4 {
+namespace theory {
+namespace quantifiers {
+
+class QuantConflictFind;
+class QuantInfo;
+
+//match generator
+class MatchGen {
+ friend class QuantInfo;
+private:
+ //current children information
+ int d_child_counter;
+ //children of this object
+ std::vector< int > d_children_order;
+ unsigned getNumChildren() { return d_children.size(); }
+ MatchGen * getChild( int i ) { return &d_children[d_children_order[i]]; }
+ //MatchGen * getChild( int i ) { return &d_children[i]; }
+ //current matching information
+ std::vector< TermArgTrie * > d_qn;
+ std::vector< std::map< TNode, TermArgTrie >::iterator > d_qni;
+ bool doMatching( QuantConflictFind * p, QuantInfo * qi );
+ //for matching : each index is either a variable or a ground term
+ unsigned d_qni_size;
+ std::map< int, int > d_qni_var_num;
+ std::map< int, TNode > d_qni_gterm;
+ std::map< int, TNode > d_qni_gterm_rep;
+ std::map< int, int > d_qni_bound;
+ std::vector< int > d_qni_bound_except;
+ std::map< int, TNode > d_qni_bound_cons;
+ std::map< int, int > d_qni_bound_cons_var;
+ std::map< int, int >::iterator d_binding_it;
+ //std::vector< int > d_independent;
+ bool d_matched_basis;
+ bool d_binding;
+ //int getVarBindingVar();
+ std::map< int, Node > d_ground_eval;
+ //determine variable order
+ void determineVariableOrder( QuantInfo * qi, std::vector< int >& bvars );
+ void collectBoundVar( QuantInfo * qi, Node n, std::vector< int >& cbvars );
+public:
+ //type of the match generator
+ enum {
+ typ_invalid,
+ typ_ground,
+ typ_pred,
+ typ_eq,
+ typ_formula,
+ typ_var,
+ typ_ite_var,
+ typ_bool_var,
+ typ_tconstraint,
+ typ_tsym,
+ };
+ void debugPrintType( const char * c, short typ, bool isTrace = false );
+public:
+ MatchGen() : d_type( typ_invalid ){}
+ MatchGen( QuantInfo * qi, Node n, bool isVar = false );
+ bool d_tgt;
+ bool d_tgt_orig;
+ bool d_wasSet;
+ Node d_n;
+ std::vector< MatchGen > d_children;
+ short d_type;
+ bool d_type_not;
+ void reset_round( QuantConflictFind * p );
+ void reset( QuantConflictFind * p, bool tgt, QuantInfo * qi );
+ bool getNextMatch( QuantConflictFind * p, QuantInfo * qi );
+ bool getExplanation( QuantConflictFind * p, QuantInfo * qi, std::vector< Node >& exp );
+ Node getExplanationTerm( QuantConflictFind * p, QuantInfo * qi, Node t, std::vector< Node >& exp );
+ bool isValid() { return d_type!=typ_invalid; }
+ void setInvalid();
+
+ // is this term treated as UF application?
+ static bool isHandledBoolConnective( TNode n );
+ static bool isHandledUfTerm( TNode n );
+ static Node getOperator( QuantConflictFind * p, Node n );
+ //can this node be handled by the algorithm
+ static bool isHandled( TNode n );
+};
+
+//info for quantifiers
+class QuantInfo {
+private:
+ void registerNode( Node n, bool hasPol, bool pol, bool beneathQuant = false );
+ void flatten( Node n, bool beneathQuant );
+private: //for completing match
+ std::vector< int > d_unassigned;
+ std::vector< TypeNode > d_unassigned_tn;
+ int d_unassigned_nvar;
+ int d_una_index;
+ std::vector< int > d_una_eqc_count;
+public:
+ QuantInfo() : d_mg( NULL ) {}
+ ~QuantInfo() { delete d_mg; }
+ std::vector< TNode > d_vars;
+ std::map< TNode, int > d_var_num;
+ std::vector< int > d_tsym_vars;
+ std::map< TNode, bool > d_inMatchConstraint;
+ std::map< int, std::vector< Node > > d_var_constraint[2];
+ int getVarNum( TNode v ) { return d_var_num.find( v )!=d_var_num.end() ? d_var_num[v] : -1; }
+ bool isVar( TNode v ) { return d_var_num.find( v )!=d_var_num.end(); }
+ int getNumVars() { return (int)d_vars.size(); }
+ TNode getVar( int i ) { return d_vars[i]; }
+
+ MatchGen * d_mg;
+ Node d_q;
+ std::map< int, MatchGen * > d_var_mg;
+ void reset_round( QuantConflictFind * p );
+public:
+ //initialize
+ void initialize( Node q, Node qn );
+ //current constraints
+ std::vector< TNode > d_match;
+ std::vector< TNode > d_match_term;
+ std::map< int, std::map< TNode, int > > d_curr_var_deq;
+ std::map< Node, bool > d_tconstraints;
+ int getCurrentRepVar( int v );
+ TNode getCurrentValue( TNode n );
+ TNode getCurrentExpValue( TNode n );
+ bool getCurrentCanBeEqual( QuantConflictFind * p, int v, TNode n, bool chDiseq = false );
+ int addConstraint( QuantConflictFind * p, int v, TNode n, bool polarity );
+ int addConstraint( QuantConflictFind * p, int v, TNode n, int vn, bool polarity, bool doRemove );
+ bool setMatch( QuantConflictFind * p, int v, TNode n );
+ bool isMatchSpurious( QuantConflictFind * p );
+ bool isTConstraintSpurious( QuantConflictFind * p, std::vector< Node >& terms );
+ bool entailmentTest( QuantConflictFind * p, Node lit, bool chEnt = true );
+ bool completeMatch( QuantConflictFind * p, std::vector< int >& assigned, bool doContinue = false );
+ void revertMatch( std::vector< int >& assigned );
+ void debugPrintMatch( const char * c );
+ bool isConstrainedVar( int v );
+public:
+ void getMatch( std::vector< Node >& terms );
+};
+
+class QuantConflictFind : public QuantifiersModule
+{
+ friend class MatchGen;
+ friend class QuantInfo;
+ typedef context::CDChunkList<Node> NodeList;
+ typedef context::CDHashMap<Node, bool, NodeHashFunction> NodeBoolMap;
+private:
+ context::Context* d_c;
+ context::CDO< bool > d_conflict;
+ std::vector< Node > d_quant_order;
+ std::map< Kind, Node > d_zero;
+ //for storing nodes created during t-constraint solving (prevents memory leaks)
+ std::vector< Node > d_tempCache;
+private:
+ std::map< Node, Node > d_op_node;
+ int d_fid_count;
+ std::map< Node, int > d_fid;
+ Node mkEqNode( Node a, Node b );
+public: //for ground terms
+ Node d_true;
+ Node d_false;
+ TNode getZero( Kind k );
+private:
+ Node evaluateTerm( Node n );
+ int evaluate( Node n, bool pref = false, bool hasPref = false );
+private:
+ //currently asserted quantifiers
+ NodeList d_qassert;
+ std::map< Node, QuantInfo > d_qinfo;
+private: //for equivalence classes
+ eq::EqualityEngine * getEqualityEngine();
+ bool areDisequal( Node n1, Node n2 );
+ bool areEqual( Node n1, Node n2 );
+ Node getRepresentative( Node n );
+ TermDb* getTermDatabase();
+ // type -> list(eqc)
+ std::map< TypeNode, std::vector< TNode > > d_eqcs;
+ std::map< TypeNode, Node > d_model_basis;
+public:
+ enum {
+ effort_conflict,
+ effort_prop_eq,
+ effort_mc,
+ };
+ short d_effort;
+ void setEffort( int e ) { d_effort = e; }
+ static short getMaxQcfEffort();
+ bool areMatchEqual( TNode n1, TNode n2 );
+ bool areMatchDisequal( TNode n1, TNode n2 );
+public:
+ QuantConflictFind( QuantifiersEngine * qe, context::Context* c );
+ /** register quantifier */
+ void registerQuantifier( Node q );
+public:
+ /** assert quantifier */
+ void assertNode( Node q );
+ /** new node */
+ void newEqClass( Node n );
+ /** merge */
+ void merge( Node a, Node b );
+ /** assert disequal */
+ void assertDisequal( Node a, Node b );
+ /** needs check */
+ bool needsCheck( Theory::Effort level );
+ /** reset round */
+ void reset_round( Theory::Effort level );
+ /** check */
+ void check( Theory::Effort level, unsigned quant_e );
+private:
+ bool d_needs_computeRelEqr;
+public:
+ void computeRelevantEqr();
+private:
+ void debugPrint( const char * c );
+ //for debugging
+ std::vector< Node > d_quants;
+ std::map< Node, int > d_quant_id;
+ void debugPrintQuant( const char * c, Node q );
+ void debugPrintQuantBody( const char * c, Node q, Node n, bool doVarNum = true );
+public:
+ /** statistics class */
+ class Statistics {
+ public:
+ IntStat d_inst_rounds;
+ IntStat d_conflict_inst;
+ IntStat d_prop_inst;
+ IntStat d_entailment_checks;
+ Statistics();
+ ~Statistics();
+ };
+ Statistics d_statistics;
+ /** Identify this module */
+ std::string identify() const { return "QcfEngine"; }
+};
+
+}
+}
+}
+
+#endif
diff --git a/src/theory/quantifiers/quantifiers_attributes.cpp b/src/theory/quantifiers/quantifiers_attributes.cpp
index a5de6ffa9..8d479c29e 100644
--- a/src/theory/quantifiers/quantifiers_attributes.cpp
+++ b/src/theory/quantifiers/quantifiers_attributes.cpp
@@ -14,6 +14,7 @@
#include "theory/quantifiers/quantifiers_attributes.h"
#include "theory/quantifiers/options.h"
+#include "theory/quantifiers/term_database.h"
using namespace std;
using namespace CVC4;
@@ -22,7 +23,8 @@ using namespace CVC4::context;
using namespace CVC4::theory;
using namespace CVC4::theory::quantifiers;
-void QuantifiersAttributes::setUserAttribute( const std::string& attr, Node n ){
+void QuantifiersAttributes::setUserAttribute( const std::string& attr, Node n, std::vector<Node> node_values, std::string str_value ){
+ Trace("quant-attr-debug") << "Set " << attr << " " << n << std::endl;
if( n.getKind()==FORALL ){
if( attr=="axiom" ){
Trace("quant-attr") << "Set axiom " << n << std::endl;
@@ -32,14 +34,22 @@ void QuantifiersAttributes::setUserAttribute( const std::string& attr, Node n ){
Trace("quant-attr") << "Set conjecture " << n << std::endl;
ConjectureAttribute ca;
n.setAttribute( ca, true );
- }else if( attr=="rr_priority" ){
- //Trace("quant-attr") << "Set rr priority " << n << std::endl;
- //RrPriorityAttribute rra;
-
+ }else if( attr=="quant-inst-max-level" ){
+ Assert( node_values.size()==1 );
+ uint64_t lvl = node_values[0].getConst<Rational>().getNumerator().getLong();
+ Trace("quant-attr") << "Set instantiation level " << n << " to " << lvl << std::endl;
+ QuantInstLevelAttribute qila;
+ n.setAttribute( qila, lvl );
+ }else if( attr=="rr-priority" ){
+ Assert( node_values.size()==1 );
+ uint64_t lvl = node_values[0].getConst<Rational>().getNumerator().getLong();
+ Trace("quant-attr") << "Set rewrite rule priority " << n << " to " << lvl << std::endl;
+ RrPriorityAttribute rrpa;
+ n.setAttribute( rrpa, lvl );
}
}else{
for( size_t i=0; i<n.getNumChildren(); i++ ){
- setUserAttribute( attr, n[i] );
+ setUserAttribute( attr, n[i], node_values, str_value );
}
}
}
diff --git a/src/theory/quantifiers/quantifiers_attributes.h b/src/theory/quantifiers/quantifiers_attributes.h
index cf9620a07..34649ae05 100644
--- a/src/theory/quantifiers/quantifiers_attributes.h
+++ b/src/theory/quantifiers/quantifiers_attributes.h
@@ -44,7 +44,7 @@ struct QuantifiersAttributes
* This function will apply a custom set of attributes to all top-level universal
* quantifiers contained in n
*/
- static void setUserAttribute( const std::string& attr, Node n );
+ static void setUserAttribute( const std::string& attr, Node n, std::vector<Node> node_values, std::string str_value );
};
diff --git a/src/theory/quantifiers/quantifiers_rewriter.cpp b/src/theory/quantifiers/quantifiers_rewriter.cpp
index eb14b0abe..754bfacb1 100644
--- a/src/theory/quantifiers/quantifiers_rewriter.cpp
+++ b/src/theory/quantifiers/quantifiers_rewriter.cpp
@@ -159,7 +159,13 @@ RewriteResponse QuantifiersRewriter::preRewrite(TNode in) {
}
Node body = in[1];
bool doRewrite = false;
+ std::vector< Node > ipl;
while( body.getNumChildren()>=2 && body.getKind()==in.getKind() ){
+ if( body.getNumChildren()==3 ){
+ for( unsigned i=0; i<body[2].getNumChildren(); i++ ){
+ ipl.push_back( body[2][i] );
+ }
+ }
for( int i=0; i<(int)body[0].getNumChildren(); i++ ){
args.push_back( body[0][i] );
}
@@ -171,7 +177,12 @@ RewriteResponse QuantifiersRewriter::preRewrite(TNode in) {
children.push_back( NodeManager::currentNM()->mkNode(kind::BOUND_VAR_LIST,args) );
children.push_back( body );
if( in.getNumChildren()==3 ){
- children.push_back( in[2] );
+ for( unsigned i=0; i<in[2].getNumChildren(); i++ ){
+ ipl.push_back( in[2][i] );
+ }
+ }
+ if( !ipl.empty() ){
+ children.push_back( NodeManager::currentNM()->mkNode( INST_PATTERN_LIST, ipl ) );
}
Node n = NodeManager::currentNM()->mkNode( in.getKind(), children );
if( in!=n ){
@@ -357,7 +368,7 @@ Node QuantifiersRewriter::computeVarElimination( Node body, std::vector< Node >&
for( std::map< Node, bool >::iterator it = qpr.d_phase_reqs.begin(); it != qpr.d_phase_reqs.end(); ++it ){
//Notice() << " " << it->first << " -> " << ( it->second ? "true" : "false" ) << std::endl;
if( it->first.getKind()==EQUAL ){
- if( it->second ){
+ if( it->second && options::varElimQuant() ){
for( int i=0; i<2; i++ ){
int j = i==0 ? 1 : 0;
std::vector< Node >::iterator ita = std::find( args.begin(), args.end(), it->first[i] );
@@ -377,6 +388,33 @@ Node QuantifiersRewriter::computeVarElimination( Node body, std::vector< Node >&
}
}
}
+ else if( it->first.getKind()==APPLY_TESTER ){
+ if( options::dtVarExpandQuant() && it->second && it->first[0].getKind()==BOUND_VARIABLE ){
+ Trace("dt-var-expand") << "Expand datatype variable based on : " << it->first << std::endl;
+ std::vector< Node >::iterator ita = std::find( args.begin(), args.end(), it->first[0] );
+ if( ita!=args.end() ){
+ vars.push_back( it->first[0] );
+ Expr testerExpr = it->first.getOperator().toExpr();
+ int index = Datatype::indexOf( testerExpr );
+ const Datatype& dt = Datatype::datatypeOf(testerExpr);
+ const DatatypeConstructor& c = dt[index];
+ std::vector< Node > newChildren;
+ newChildren.push_back( Node::fromExpr( c.getConstructor() ) );
+ std::vector< Node > newVars;
+ for( unsigned j=0; j<c.getNumArgs(); j++ ){
+ TypeNode tn = TypeNode::fromType( c[j].getSelector().getType() );
+ tn = tn[1];
+ Node v = NodeManager::currentNM()->mkBoundVar( tn );
+ newChildren.push_back( v );
+ newVars.push_back( v );
+ }
+ subs.push_back( NodeManager::currentNM()->mkNode( APPLY_CONSTRUCTOR, newChildren ) );
+ Trace("dt-var-expand") << "...apply substitution " << subs[0] << "/" << vars[0] << std::endl;
+ args.erase( ita );
+ args.insert( args.end(), newVars.begin(), newVars.end() );
+ }
+ }
+ }
}
if( !vars.empty() ){
Trace("var-elim-quant") << "VE " << vars.size() << "/" << args.size() << std::endl;
@@ -914,7 +952,7 @@ bool QuantifiersRewriter::doOperation( Node f, bool isNested, int computeOption
}else if( computeOption==COMPUTE_PRENEX ){
return options::prenexQuant() && !options::aggressiveMiniscopeQuant();
}else if( computeOption==COMPUTE_VAR_ELIMINATION ){
- return options::varElimQuant();
+ return options::varElimQuant() || options::dtVarExpandQuant();
}else if( computeOption==COMPUTE_CNF ){
return false;//return options::cnfQuant() ; FIXME
}else if( computeOption==COMPUTE_SPLIT ){
@@ -1142,8 +1180,10 @@ Node QuantifiersRewriter::preSkolemizeQuantifiers( Node n, bool polarity, std::v
//process body
Node nn = preSkolemizeQuantifiers( n[1], polarity, fvTypes, fvs );
std::vector< Node > sk;
+ Node sub;
+ std::vector< unsigned > sub_vars;
//return skolemized body
- return TermDb::mkSkolemizedBody( n, nn, fvTypes, fvs, sk );
+ return TermDb::mkSkolemizedBody( n, nn, fvTypes, fvs, sk, sub, sub_vars );
}
}else{
//check if it contains a quantifier as a subterm
diff --git a/src/theory/quantifiers/rewrite_engine.cpp b/src/theory/quantifiers/rewrite_engine.cpp
index 1b13d772e..05e33c7b2 100644
--- a/src/theory/quantifiers/rewrite_engine.cpp
+++ b/src/theory/quantifiers/rewrite_engine.cpp
@@ -39,7 +39,7 @@ struct PrioritySort {
RewriteEngine::RewriteEngine( context::Context* c, QuantifiersEngine* qe ) : QuantifiersModule(qe) {
d_true = NodeManager::currentNM()->mkConst( true );
- d_needsSort = true;
+ d_needsSort = false;
}
double RewriteEngine::getPriority( Node f ) {
@@ -61,8 +61,14 @@ double RewriteEngine::getPriority( Node f ) {
//return deterministic ? 0.0 : 1.0;
}
-void RewriteEngine::check( Theory::Effort e ) {
- if( e==Theory::EFFORT_FULL ){
+bool RewriteEngine::needsCheck( Theory::Effort e ){
+ return e==Theory::EFFORT_FULL;
+ //return e>=Theory::EFFORT_LAST_CALL;
+}
+
+void RewriteEngine::check( Theory::Effort e, unsigned quant_e ) {
+ if( quant_e==QuantifiersEngine::QEFFORT_STANDARD ){
+ //if( e==Theory::EFFORT_FULL ){
Trace("rewrite-engine") << "---Rewrite Engine Round, effort = " << e << "---" << std::endl;
//if( e==Theory::EFFORT_LAST_CALL ){
// if( !d_quantEngine->getModel()->isModelSet() ){
@@ -102,7 +108,6 @@ void RewriteEngine::check( Theory::Effort e ) {
}else{
//otherwise, the search will continue
- d_quantEngine->flushLemmas( &d_quantEngine->getOutputChannel() );
}
}
}
diff --git a/src/theory/quantifiers/rewrite_engine.h b/src/theory/quantifiers/rewrite_engine.h
index d2108bf3e..1703a9bfc 100644
--- a/src/theory/quantifiers/rewrite_engine.h
+++ b/src/theory/quantifiers/rewrite_engine.h
@@ -54,7 +54,8 @@ private:
public:
RewriteEngine( context::Context* c, QuantifiersEngine* qe );
- void check( Theory::Effort e );
+ bool needsCheck( Theory::Effort e );
+ void check( Theory::Effort e, unsigned quant_e );
void registerQuantifier( Node f );
void assertNode( Node n );
/** Identify this module */
diff --git a/src/theory/quantifiers/term_database.cpp b/src/theory/quantifiers/term_database.cpp
index 9ea9ee962..0d85eae83 100644
--- a/src/theory/quantifiers/term_database.cpp
+++ b/src/theory/quantifiers/term_database.cpp
@@ -31,25 +31,39 @@ using namespace CVC4::theory::quantifiers;
using namespace CVC4::theory::inst;
-bool TermArgTrie::addTerm2( QuantifiersEngine* qe, Node n, int argIndex ){
- if( argIndex<(int)n.getNumChildren() ){
- Node r = qe->getEqualityQuery()->getRepresentative( n[ argIndex ] );
- std::map< Node, TermArgTrie >::iterator it = d_data.find( r );
+TNode TermArgTrie::existsTerm( std::vector< TNode >& reps, int argIndex ) {
+ if( argIndex==(int)reps.size() ){
+ if( d_data.empty() ){
+ return Node::null();
+ }else{
+ return d_data.begin()->first;
+ }
+ }else{
+ std::map< TNode, TermArgTrie >::iterator it = d_data.find( reps[argIndex] );
if( it==d_data.end() ){
- d_data[r].addTerm2( qe, n, argIndex+1 );
+ return Node::null();
+ }else{
+ return it->second.existsTerm( reps, argIndex+1 );
+ }
+ }
+}
+
+bool TermArgTrie::addTerm( TNode n, std::vector< TNode >& reps, int argIndex ){
+ if( argIndex==(int)reps.size() ){
+ if( d_data.empty() ){
+ //store n in d_data (this should be interpretted as the "data" and not as a reference to a child)
+ d_data[n].clear();
return true;
}else{
- return it->second.addTerm2( qe, n, argIndex+1 );
+ return false;
}
}else{
- //store n in d_data (this should be interpretted as the "data" and not as a reference to a child)
- d_data[n].d_data.clear();
- return false;
+ return d_data[reps[argIndex]].addTerm( n, reps, argIndex+1 );
}
}
void TermArgTrie::debugPrint( const char * c, Node n, unsigned depth ) {
- for( std::map< Node, TermArgTrie >::iterator it = d_data.begin(); it != d_data.end(); ++it ){
+ for( std::map< TNode, TermArgTrie >::iterator it = d_data.begin(); it != d_data.end(); ++it ){
for( unsigned i=0; i<depth; i++ ){ Debug(c) << " "; }
Debug(c) << it->first << std::endl;
it->second.debugPrint( c, n, depth+1 );
@@ -57,7 +71,8 @@ void TermArgTrie::debugPrint( const char * c, Node n, unsigned depth ) {
}
TermDb::TermDb( context::Context* c, context::UserContext* u, QuantifiersEngine* qe ) : d_quantEngine( qe ), d_op_ccount( u ) {
-
+ d_true = NodeManager::currentNM()->mkConst( true );
+ d_false = NodeManager::currentNM()->mkConst( false );
}
/** ground terms */
@@ -129,8 +144,6 @@ void TermDb::addTerm( Node n, std::set< Node >& added, bool withinQuant ){
for( size_t i=0; i<d_op_triggers[op].size(); i++ ){
addedLemmas += d_op_triggers[op][i]->addTerm( n );
}
- //Message() << "Terms, added lemmas: " << addedLemmas << std::endl;
- d_quantEngine->flushLemmas( &d_quantEngine->getOutputChannel() );
}
}
}
@@ -143,65 +156,193 @@ void TermDb::addTerm( Node n, std::set< Node >& added, bool withinQuant ){
}
}
- void TermDb::reset( Theory::Effort effort ){
+void TermDb::computeArgReps( TNode n ) {
+ if( d_arg_reps.find( n )==d_arg_reps.end() ){
+ eq::EqualityEngine * ee = d_quantEngine->getTheoryEngine()->getMasterEqualityEngine();
+ for( unsigned j=0; j<n.getNumChildren(); j++ ){
+ TNode r = ee->hasTerm( n[j] ) ? ee->getRepresentative( n[j] ) : n[j];
+ d_arg_reps[n].push_back( r );
+ }
+ }
+}
+
+void TermDb::computeUfEqcTerms( TNode f ) {
+ if( d_func_map_eqc_trie.find( f )==d_func_map_eqc_trie.end() ){
+ d_func_map_eqc_trie[f].clear();
+ eq::EqualityEngine * ee = d_quantEngine->getTheoryEngine()->getMasterEqualityEngine();
+ for( unsigned i=0; i<d_op_map[f].size(); i++ ){
+ TNode n = d_op_map[f][i];
+ if( !n.getAttribute(NoMatchAttribute()) ){
+ computeArgReps( n );
+ TNode r = ee->hasTerm( n ) ? ee->getRepresentative( n ) : n;
+ d_func_map_eqc_trie[f].d_data[r].addTerm( n, d_arg_reps[n] );
+ }
+ }
+ }
+}
+
+TNode TermDb::evaluateTerm( TNode n, std::map< TNode, TNode >& subs, bool subsRep ) {
+ Trace("term-db-eval") << "evaluate term : " << n << std::endl;
+ eq::EqualityEngine * ee = d_quantEngine->getTheoryEngine()->getMasterEqualityEngine();
+ if( ee->hasTerm( n ) ){
+ Trace("term-db-eval") << "...exists in ee, return rep " << std::endl;
+ return ee->getRepresentative( n );
+ }else if( n.getKind()==BOUND_VARIABLE ){
+ Assert( subs.find( n )!=subs.end() );
+ Trace("term-db-eval") << "...substitution is : " << subs[n] << std::endl;
+ if( subsRep ){
+ Assert( ee->hasTerm( subs[n] ) );
+ Assert( ee->getRepresentative( subs[n] )==subs[n] );
+ return subs[n];
+ }else{
+ return evaluateTerm( subs[n], subs, subsRep );
+ }
+ }else{
+ if( n.hasOperator() ){
+ TNode f = getOperator( n );
+ if( !f.isNull() ){
+ std::vector< TNode > args;
+ for( unsigned i=0; i<n.getNumChildren(); i++ ){
+ TNode c = evaluateTerm( n[i], subs, subsRep );
+ if( c.isNull() ){
+ return TNode::null();
+ }
+ Trace("term-db-eval") << "Got child : " << c << std::endl;
+ args.push_back( c );
+ }
+ Trace("term-db-eval") << "Get term from DB" << std::endl;
+ TNode nn = d_func_map_trie[f].existsTerm( args );
+ Trace("term-db-eval") << "Got term " << nn << std::endl;
+ if( !nn.isNull() ){
+ if( ee->hasTerm( nn ) ){
+ Trace("term-db-eval") << "return rep " << std::endl;
+ return ee->getRepresentative( nn );
+ }else{
+ //Assert( false );
+ }
+ }
+ }
+ }
+ return TNode::null();
+ }
+}
+
+TNode TermDb::evaluateTerm( TNode n ) {
+ eq::EqualityEngine * ee = d_quantEngine->getTheoryEngine()->getMasterEqualityEngine();
+ if( ee->hasTerm( n ) ){
+ return ee->getRepresentative( n );
+ }else if( n.getKind()!=BOUND_VARIABLE ){
+ if( n.hasOperator() ){
+ TNode f = getOperator( n );
+ if( !f.isNull() ){
+ std::vector< TNode > args;
+ for( unsigned i=0; i<n.getNumChildren(); i++ ){
+ TNode c = evaluateTerm( n[i] );
+ if( c.isNull() ){
+ return TNode::null();
+ }
+ args.push_back( c );
+ }
+ TNode nn = d_func_map_trie[f].existsTerm( args );
+ if( !nn.isNull() ){
+ if( ee->hasTerm( nn ) ){
+ return ee->getRepresentative( nn );
+ }else{
+ //Assert( false );
+ }
+ }
+ }
+ }
+ }
+ return TNode::null();
+}
+
+bool TermDb::isEntailed( TNode n, std::map< TNode, TNode >& subs, bool subsRep, bool pol ) {
+ Trace("term-db-eval") << "Check entailed : " << n << ", pol = " << pol << std::endl;
+ Assert( n.getType().isBoolean() );
+ if( n.getKind()==EQUAL ){
+ TNode n1 = evaluateTerm( n[0], subs, subsRep );
+ if( !n1.isNull() ){
+ TNode n2 = evaluateTerm( n[1], subs, subsRep );
+ if( !n2.isNull() ){
+ eq::EqualityEngine * ee = d_quantEngine->getTheoryEngine()->getMasterEqualityEngine();
+ Assert( ee->hasTerm( n1 ) );
+ Assert( ee->hasTerm( n2 ) );
+ if( pol ){
+ return n1==n2 || ee->areEqual( n1, n2 );
+ }else{
+ return n1!=n2 && ee->areDisequal( n1, n2, false );
+ }
+ }
+ }
+ }else if( n.getKind()==APPLY_UF ){
+ TNode n1 = evaluateTerm( n, subs, subsRep );
+ if( !n1.isNull() ){
+ eq::EqualityEngine * ee = d_quantEngine->getTheoryEngine()->getMasterEqualityEngine();
+ Assert( ee->hasTerm( n1 ) );
+ TNode n2 = pol ? d_true : d_false;
+ if( ee->hasTerm( n2 ) ){
+ return ee->areEqual( n1, n2 );
+ }
+ }
+ }else if( n.getKind()==NOT ){
+ return isEntailed( n[0], subs, subsRep, !pol );
+ }else if( n.getKind()==OR || n.getKind()==AND ){
+ bool simPol = ( pol && n.getKind()==OR ) || ( !pol && n.getKind()==AND );
+ for( unsigned i=0; i<n.getNumChildren(); i++ ){
+ if( isEntailed( n[i], subs, subsRep, pol ) ){
+ if( simPol ){
+ return true;
+ }
+ }else{
+ if( !simPol ){
+ return false;
+ }
+ }
+ }
+ return !simPol;
+ }else if( n.getKind()==IFF || n.getKind()==ITE ){
+ for( unsigned i=0; i<2; i++ ){
+ if( isEntailed( n[0], subs, subsRep, i==0 ) ){
+ unsigned ch = ( n.getKind()==IFF || i==0 ) ? 1 : 2;
+ bool reqPol = ( n.getKind()==ITE || i==0 ) ? pol : !pol;
+ return isEntailed( n[ch], subs, subsRep, reqPol );
+ }
+ }
+ }
+ return false;
+}
+
+void TermDb::reset( Theory::Effort effort ){
int nonCongruentCount = 0;
int congruentCount = 0;
int alreadyCongruentCount = 0;
+ d_op_nonred_count.clear();
+ d_arg_reps.clear();
+ d_func_map_trie.clear();
+ d_func_map_eqc_trie.clear();
//rebuild d_func/pred_map_trie for each operation, this will calculate all congruent terms
for( std::map< Node, std::vector< Node > >::iterator it = d_op_map.begin(); it != d_op_map.end(); ++it ){
d_op_nonred_count[ it->first ] = 0;
if( !it->second.empty() ){
- if( it->second[0].getType().isBoolean() ){
- d_pred_map_trie[ 0 ][ it->first ].d_data.clear();
- d_pred_map_trie[ 1 ][ it->first ].d_data.clear();
- }else{
- d_func_map_trie[ it->first ].d_data.clear();
- for( int i=0; i<(int)it->second.size(); i++ ){
- Node n = it->second[i];
- computeModelBasisArgAttribute( n );
- if( !n.getAttribute(NoMatchAttribute()) ){
- if( !d_func_map_trie[ it->first ].addTerm( d_quantEngine, n ) ){
- NoMatchAttribute nma;
- n.setAttribute(nma,true);
- Debug("term-db-cong") << n << " is redundant." << std::endl;
- congruentCount++;
- }else{
- nonCongruentCount++;
- d_op_nonred_count[ it->first ]++;
- }
- }else{
+ for( unsigned i=0; i<it->second.size(); i++ ){
+ Node n = it->second[i];
+ computeModelBasisArgAttribute( n );
+ if( !n.getAttribute(NoMatchAttribute()) ){
+ computeArgReps( n );
+ if( !d_func_map_trie[ it->first ].addTerm( n, d_arg_reps[n] ) ){
+ NoMatchAttribute nma;
+ n.setAttribute(nma,true);
+ Debug("term-db-cong") << n << " is redundant." << std::endl;
congruentCount++;
- alreadyCongruentCount++;
- }
- }
- }
- }
- }
- for( int i=0; i<2; i++ ){
- Node n = NodeManager::currentNM()->mkConst( i==1 );
- if( d_quantEngine->getEqualityQuery()->getEngine()->hasTerm( n ) ){
- eq::EqClassIterator eqc( d_quantEngine->getEqualityQuery()->getEngine()->getRepresentative( n ),
- d_quantEngine->getEqualityQuery()->getEngine() );
- while( !eqc.isFinished() ){
- Node en = (*eqc);
- computeModelBasisArgAttribute( en );
- if( en.getKind()==APPLY_UF && !TermDb::hasInstConstAttr(en) ){
- if( !en.getAttribute(NoMatchAttribute()) ){
- Node op = getOperator( en );
- if( !d_pred_map_trie[i][op].addTerm( d_quantEngine, en ) ){
- NoMatchAttribute nma;
- en.setAttribute(nma,true);
- Debug("term-db-cong") << en << " is redundant." << std::endl;
- congruentCount++;
- }else{
- nonCongruentCount++;
- d_op_nonred_count[ op ]++;
- }
}else{
- alreadyCongruentCount++;
+ nonCongruentCount++;
+ d_op_nonred_count[ it->first ]++;
}
+ }else{
+ congruentCount++;
+ alreadyCongruentCount++;
}
- ++eqc;
}
}
}
@@ -219,6 +360,39 @@ void TermDb::addTerm( Node n, std::set< Node >& added, bool withinQuant ){
}
}
+TermArgTrie * TermDb::getTermArgTrie( Node f ) {
+ std::map< Node, TermArgTrie >::iterator itut = d_func_map_trie.find( f );
+ if( itut!=d_func_map_trie.end() ){
+ return &itut->second;
+ }else{
+ return NULL;
+ }
+}
+
+TermArgTrie * TermDb::getTermArgTrie( Node eqc, Node f ) {
+ computeUfEqcTerms( f );
+ std::map< Node, TermArgTrie >::iterator itut = d_func_map_eqc_trie.find( f );
+ if( itut==d_func_map_eqc_trie.end() ){
+ return NULL;
+ }else{
+ if( eqc.isNull() ){
+ return &itut->second;
+ }else{
+ std::map< TNode, TermArgTrie >::iterator itute = itut->second.d_data.find( eqc );
+ if( itute!=itut->second.d_data.end() ){
+ return &itute->second;
+ }else{
+ return NULL;
+ }
+ }
+ }
+}
+
+TNode TermDb::existsTerm( Node f, Node n ) {
+ computeArgReps( n );
+ return d_func_map_trie[f].existsTerm( d_arg_reps[n] );
+}
+
Node TermDb::getModelBasisTerm( TypeNode tn, int i ){
if( d_model_basis_term.find( tn )==d_model_basis_term.end() ){
Node mbt;
@@ -448,14 +622,15 @@ void getSelfSel( const DatatypeConstructor& dc, Node n, TypeNode ntn, std::vecto
Node TermDb::mkSkolemizedBody( Node f, Node n, std::vector< TypeNode >& argTypes, std::vector< TNode >& fvs,
- std::vector< Node >& sk ) {
+ std::vector< Node >& sk, Node& sub, std::vector< unsigned >& sub_vars ) {
+ Assert( sk.empty() || sk.size()==f[0].getNumChildren() );
//calculate the variables and substitution
std::vector< TNode > ind_vars;
std::vector< unsigned > ind_var_indicies;
std::vector< TNode > vars;
std::vector< unsigned > var_indicies;
for( unsigned i=0; i<f[0].getNumChildren(); i++ ){
- if( options::dtStcInduction() && datatypes::DatatypesRewriter::isTermDatatype( f[0][i] ) ){
+ if( isInductionTerm( f[0][i] ) ){
ind_vars.push_back( f[0][i] );
ind_var_indicies.push_back( i );
}else{
@@ -463,19 +638,23 @@ Node TermDb::mkSkolemizedBody( Node f, Node n, std::vector< TypeNode >& argTypes
var_indicies.push_back( i );
}
Node s;
- //make the new function symbol
- if( argTypes.empty() ){
- s = NodeManager::currentNM()->mkSkolem( "skv", f[0][i].getType(), "created during skolemization" );
+ //make the new function symbol or use existing
+ if( i>=sk.size() ){
+ if( argTypes.empty() ){
+ s = NodeManager::currentNM()->mkSkolem( "skv", f[0][i].getType(), "created during skolemization" );
+ }else{
+ TypeNode typ = NodeManager::currentNM()->mkFunctionType( argTypes, f[0][i].getType() );
+ Node op = NodeManager::currentNM()->mkSkolem( "skop", typ, "op created during pre-skolemization" );
+ //DOTHIS: set attribute on op, marking that it should not be selected as trigger
+ std::vector< Node > funcArgs;
+ funcArgs.push_back( op );
+ funcArgs.insert( funcArgs.end(), fvs.begin(), fvs.end() );
+ s = NodeManager::currentNM()->mkNode( kind::APPLY_UF, funcArgs );
+ }
+ sk.push_back( s );
}else{
- TypeNode typ = NodeManager::currentNM()->mkFunctionType( argTypes, f[0][i].getType() );
- Node op = NodeManager::currentNM()->mkSkolem( "skop", typ, "op created during pre-skolemization" );
- //DOTHIS: set attribute on op, marking that it should not be selected as trigger
- std::vector< Node > funcArgs;
- funcArgs.push_back( op );
- funcArgs.insert( funcArgs.end(), fvs.begin(), fvs.end() );
- s = NodeManager::currentNM()->mkNode( kind::APPLY_UF, funcArgs );
+ Assert( sk[i].getType()==f[0][i].getType() );
}
- sk.push_back( s );
}
Node ret;
if( vars.empty() ){
@@ -489,44 +668,57 @@ Node TermDb::mkSkolemizedBody( Node f, Node n, std::vector< TypeNode >& argTypes
ret = n.substitute( vars.begin(), vars.end(), var_sk.begin(), var_sk.end() );
}
if( !ind_vars.empty() ){
- Trace("stc-ind") << "Ind strengthen : (not " << f << ")" << std::endl;
- Trace("stc-ind") << "Skolemized is : " << ret << std::endl;
- Node nret;
+ Trace("sk-ind") << "Ind strengthen : (not " << f << ")" << std::endl;
+ Trace("sk-ind") << "Skolemized is : " << ret << std::endl;
Node n_str_ind;
TypeNode tn = ind_vars[0].getType();
- if( datatypes::DatatypesRewriter::isTypeDatatype(tn) ){
- Node k = sk[ind_var_indicies[0]];
+ Node k = sk[ind_var_indicies[0]];
+ Node nret = ret.substitute( ind_vars[0], k );
+ //note : everything is under a negation
+ //the following constructs ~( R( x, k ) => ~P( x ) )
+ if( options::dtStcInduction() && datatypes::DatatypesRewriter::isTypeDatatype(tn) ){
const Datatype& dt = ((DatatypeType)(tn).toType()).getDatatype();
std::vector< Node > disj;
for( unsigned i=0; i<dt.getNumConstructors(); i++ ){
- std::vector< Node > selfSel;
- getSelfSel( dt[i], k, tn, selfSel );
- std::vector< Node > conj;
- conj.push_back( NodeManager::currentNM()->mkNode( APPLY_TESTER, Node::fromExpr( dt[i].getTester() ), k ).negate() );
- for( unsigned j=0; j<selfSel.size(); j++ ){
- conj.push_back( ret.substitute( ind_vars[0], selfSel[j] ).negate() );
- }
- disj.push_back( conj.size()==1 ? conj[0] : NodeManager::currentNM()->mkNode( OR, conj ) );
+ std::vector< Node > selfSel;
+ getSelfSel( dt[i], k, tn, selfSel );
+ std::vector< Node > conj;
+ conj.push_back( NodeManager::currentNM()->mkNode( APPLY_TESTER, Node::fromExpr( dt[i].getTester() ), k ).negate() );
+ for( unsigned j=0; j<selfSel.size(); j++ ){
+ conj.push_back( ret.substitute( ind_vars[0], selfSel[j] ).negate() );
+ }
+ disj.push_back( conj.size()==1 ? conj[0] : NodeManager::currentNM()->mkNode( OR, conj ) );
}
Assert( !disj.empty() );
n_str_ind = disj.size()==1 ? disj[0] : NodeManager::currentNM()->mkNode( AND, disj );
- Trace("stc-ind") << "Strengthening is : " << n_str_ind << std::endl;
- nret = ret.substitute( ind_vars[0], k );
+ }else if( options::intWfInduction() && tn.isInteger() ){
+ Node icond = NodeManager::currentNM()->mkNode( GEQ, k, NodeManager::currentNM()->mkConst( Rational(0) ) );
+ Node iret = ret.substitute( ind_vars[0], NodeManager::currentNM()->mkNode( MINUS, k, NodeManager::currentNM()->mkConst( Rational(1) ) ) ).negate();
+ n_str_ind = NodeManager::currentNM()->mkNode( OR, icond.negate(), iret );
+ n_str_ind = NodeManager::currentNM()->mkNode( AND, icond, n_str_ind );
}else{
- Trace("stc-ind") << "Unknown induction for term : " << ind_vars[0] << ", type = " << tn << std::endl;
+ Trace("sk-ind") << "Unknown induction for term : " << ind_vars[0] << ", type = " << tn << std::endl;
Assert( false );
}
-
+ Trace("sk-ind") << "Strengthening is : " << n_str_ind << std::endl;
+
std::vector< Node > rem_ind_vars;
rem_ind_vars.insert( rem_ind_vars.end(), ind_vars.begin()+1, ind_vars.end() );
if( !rem_ind_vars.empty() ){
Node bvl = NodeManager::currentNM()->mkNode( BOUND_VAR_LIST, rem_ind_vars );
nret = NodeManager::currentNM()->mkNode( FORALL, bvl, nret );
+ nret = Rewriter::rewrite( nret );
+ sub = nret;
+ sub_vars.insert( sub_vars.end(), ind_var_indicies.begin()+1, ind_var_indicies.end() );
n_str_ind = NodeManager::currentNM()->mkNode( FORALL, bvl, n_str_ind.negate() ).negate();
}
ret = NodeManager::currentNM()->mkNode( OR, nret, n_str_ind );
}
Trace("quantifiers-sk") << "mkSkolem body for " << f << " returns : " << ret << std::endl;
+ //if it has an instantiation level, set the skolemized body to that level
+ if( f.hasAttribute(InstLevelAttribute()) ){
+ theory::QuantifiersEngine::setInstantiationLevelAttr( ret, f.getAttribute(InstLevelAttribute()) );
+ }
return ret;
}
@@ -535,7 +727,17 @@ Node TermDb::getSkolemizedBody( Node f ){
if( d_skolem_body.find( f )==d_skolem_body.end() ){
std::vector< TypeNode > fvTypes;
std::vector< TNode > fvs;
- d_skolem_body[ f ] = mkSkolemizedBody( f, f[1], fvTypes, fvs, d_skolem_constants[f] );
+ Node sub;
+ std::vector< unsigned > sub_vars;
+ d_skolem_body[ f ] = mkSkolemizedBody( f, f[1], fvTypes, fvs, d_skolem_constants[f], sub, sub_vars );
+ //store sub quantifier information
+ if( !sub.isNull() ){
+ //if we are skolemizing one at a time, we already know the skolem constants of the sub-quantified formula, store them
+ Assert( d_skolem_constants[sub].empty() );
+ for( unsigned i=0; i<sub_vars.size(); i++ ){
+ d_skolem_constants[sub].push_back( d_skolem_constants[f][sub_vars[i]] );
+ }
+ }
Assert( d_skolem_constants[f].size()==f[0].getNumChildren() );
if( options::sortInference() ){
for( unsigned i=0; i<d_skolem_constants[f].size(); i++ ){
@@ -752,6 +954,17 @@ void TermDb::registerTrigger( theory::inst::Trigger* tr, Node op ){
}
}
+bool TermDb::isInductionTerm( Node n ) {
+ if( options::dtStcInduction() && datatypes::DatatypesRewriter::isTermDatatype( n ) ){
+ return true;
+ }
+ if( options::intWfInduction() && n.getType().isInteger() ){
+ return true;
+ }
+ return false;
+}
+
+
bool TermDb::isRewriteRule( Node q ) {
return !getRewriteRule( q ).isNull();
}
diff --git a/src/theory/quantifiers/term_database.h b/src/theory/quantifiers/term_database.h
index c839d08d7..91ad0135b 100644
--- a/src/theory/quantifiers/term_database.h
+++ b/src/theory/quantifiers/term_database.h
@@ -55,6 +55,13 @@ typedef expr::Attribute<ModelBasisArgAttributeId, uint64_t> ModelBasisArgAttribu
struct BoundIntLitAttributeId {};
typedef expr::Attribute<BoundIntLitAttributeId, uint64_t> BoundIntLitAttribute;
+//for quantifier instantiation level
+struct QuantInstLevelAttributeId {};
+typedef expr::Attribute<QuantInstLevelAttributeId, uint64_t> QuantInstLevelAttribute;
+
+//rewrite-rule priority
+struct RrPriorityAttributeId {};
+typedef expr::Attribute<RrPriorityAttributeId, uint64_t> RrPriorityAttribute;
class QuantifiersEngine;
@@ -69,14 +76,14 @@ namespace rrinst{
namespace quantifiers {
class TermArgTrie {
-private:
- bool addTerm2( QuantifiersEngine* qe, Node n, int argIndex );
public:
/** the data */
- std::map< Node, TermArgTrie > d_data;
+ std::map< TNode, TermArgTrie > d_data;
public:
- bool addTerm( QuantifiersEngine* qe, Node n ) { return addTerm2( qe, n, 0 ); }
+ TNode existsTerm( std::vector< TNode >& reps, int argIndex = 0 );
+ bool addTerm( TNode n, std::vector< TNode >& reps, int argIndex = 0 );
void debugPrint( const char * c, Node n, unsigned depth = 0 );
+ void clear() { d_data.clear(); }
};/* class TermArgTrie */
@@ -103,6 +110,9 @@ private:
public:
TermDb( context::Context* c, context::UserContext* u, QuantifiersEngine* qe );
~TermDb(){}
+ /** boolean terms */
+ Node d_true;
+ Node d_false;
/** ground terms */
unsigned getNumGroundTerms( Node f );
/** count number of non-redundant ground terms per operator */
@@ -111,16 +121,34 @@ public:
std::map< Node, std::vector< Node > > d_op_map;
/** map from APPLY_UF functions to trie */
std::map< Node, TermArgTrie > d_func_map_trie;
- /** map from APPLY_UF predicates to trie */
- std::map< Node, TermArgTrie > d_pred_map_trie[2];
+ std::map< Node, TermArgTrie > d_func_map_eqc_trie;
+ /**mapping from UF terms to representatives of their arguments */
+ std::map< TNode, std::vector< TNode > > d_arg_reps;
/** map from type nodes to terms of that type */
std::map< TypeNode, std::vector< Node > > d_type_map;
/** add a term to the database */
void addTerm( Node n, std::set< Node >& added, bool withinQuant = false );
/** reset (calculate which terms are active) */
void reset( Theory::Effort effort );
- /** get operation */
+ /** get operator*/
Node getOperator( Node n );
+ /** get term arg index */
+ TermArgTrie * getTermArgTrie( Node f );
+ TermArgTrie * getTermArgTrie( Node eqc, Node f );
+ /** exists term */
+ TNode existsTerm( Node f, Node n );
+ /** compute arg reps */
+ void computeArgReps( TNode n );
+ /** compute uf eqc terms */
+ void computeUfEqcTerms( TNode f );
+ /** evaluate a term under a substitution. Return representative in EE if possible.
+ * subsRep is whether subs contains only representatives
+ */
+ TNode evaluateTerm( TNode n, std::map< TNode, TNode >& subs, bool subsRep );
+ /** same as above, but without substitution */
+ TNode evaluateTerm( TNode n );
+ /** is entailed (incomplete check) */
+ bool isEntailed( TNode n, std::map< TNode, TNode >& subs, bool subsRep, bool pol );
public:
/** parent structure (for efficient E-matching):
n -> op -> index -> L
@@ -206,7 +234,7 @@ public:
std::map< Node, std::vector< Node > > d_skolem_constants;
/** make the skolemized body f[e/x] */
static Node mkSkolemizedBody( Node f, Node n, std::vector< TypeNode >& fvTypes, std::vector< TNode >& fvs,
- std::vector< Node >& sk );
+ std::vector< Node >& sk, Node& sub, std::vector< unsigned >& sub_vars );
/** get the skolemized body */
Node getSkolemizedBody( Node f);
@@ -245,11 +273,18 @@ public:
int isInstanceOf( Node n1, Node n2 );
/** filter all nodes that have instances */
void filterInstances( std::vector< Node >& nodes );
-public:
+
+public: //for induction
+ /** is induction variable */
+ static bool isInductionTerm( Node n );
+
+
+public: //general queries concerning quantified formulas wrt modules
/** is quantifier treated as a rewrite rule? */
static bool isRewriteRule( Node q );
/** get the rewrite rule associated with the quanfied formula */
static Node getRewriteRule( Node q );
+
};/* class TermDb */
}/* CVC4::theory::quantifiers namespace */
diff --git a/src/theory/quantifiers/theory_quantifiers.cpp b/src/theory/quantifiers/theory_quantifiers.cpp
index 4ba3c499d..18546b09c 100644
--- a/src/theory/quantifiers/theory_quantifiers.cpp
+++ b/src/theory/quantifiers/theory_quantifiers.cpp
@@ -42,6 +42,8 @@ TheoryQuantifiers::TheoryQuantifiers(Context* c, context::UserContext* u, Output
d_baseDecLevel = -1;
out.handleUserAttribute( "axiom", this );
out.handleUserAttribute( "conjecture", this );
+ out.handleUserAttribute( "inst-level", this );
+ out.handleUserAttribute( "rr-priority", this );
}
TheoryQuantifiers::~TheoryQuantifiers() {
@@ -107,6 +109,10 @@ void TheoryQuantifiers::collectModelInfo(TheoryModel* m, bool fullModel) {
}
void TheoryQuantifiers::check(Effort e) {
+ if (done() && !fullEffort(e)) {
+ return;
+ }
+
CodeTimer codeTimer(d_theoryTime);
Trace("quantifiers-check") << "quantifiers::check(" << e << ")" << std::endl;
@@ -193,6 +199,6 @@ bool TheoryQuantifiers::restart(){
}
}
-void TheoryQuantifiers::setUserAttribute( const std::string& attr, Node n ){
- QuantifiersAttributes::setUserAttribute( attr, n );
+void TheoryQuantifiers::setUserAttribute(const std::string& attr, Node n, std::vector<Node> node_values, std::string str_value){
+ QuantifiersAttributes::setUserAttribute( attr, n, node_values, str_value );
}
diff --git a/src/theory/quantifiers/theory_quantifiers.h b/src/theory/quantifiers/theory_quantifiers.h
index ffd3c4c59..6febc8417 100644
--- a/src/theory/quantifiers/theory_quantifiers.h
+++ b/src/theory/quantifiers/theory_quantifiers.h
@@ -69,7 +69,7 @@ public:
void shutdown() { }
std::string identify() const { return std::string("TheoryQuantifiers"); }
bool flipDecision();
- void setUserAttribute( const std::string& attr, Node n );
+ void setUserAttribute(const std::string& attr, Node n, std::vector<Node> node_values, std::string str_value);
eq::EqualityEngine* getMasterEqualityEngine() { return d_masterEqualityEngine; }
bool ppDontRewriteSubterm(TNode atom) { return atom.getKind() == kind::FORALL || atom.getKind() == kind::EXISTS; }
private:
diff --git a/src/theory/quantifiers/theory_quantifiers_type_rules.h b/src/theory/quantifiers/theory_quantifiers_type_rules.h
index e4b1732dd..7fc69c539 100644
--- a/src/theory/quantifiers/theory_quantifiers_type_rules.h
+++ b/src/theory/quantifiers/theory_quantifiers_type_rules.h
@@ -88,6 +88,13 @@ struct QuantifierInstPatternTypeRule {
}
};/* struct QuantifierInstPatternTypeRule */
+struct QuantifierInstNoPatternTypeRule {
+ inline static TypeNode computeType(NodeManager* nodeManager, TNode n, bool check)
+ throw(TypeCheckingExceptionPrivate) {
+ Assert(n.getKind() == kind::INST_NO_PATTERN );
+ return nodeManager->instPatternType();
+ }
+};/* struct QuantifierInstNoPatternTypeRule */
struct QuantifierInstPatternListTypeRule {
inline static TypeNode computeType(NodeManager* nodeManager, TNode n, bool check)
@@ -95,7 +102,7 @@ struct QuantifierInstPatternListTypeRule {
Assert(n.getKind() == kind::INST_PATTERN_LIST );
if( check ){
for( int i=0; i<(int)n.getNumChildren(); i++ ){
- if( n[i].getKind()!=kind::INST_PATTERN ){
+ if( n[i].getKind()!=kind::INST_PATTERN && n[i].getKind()!=kind::INST_NO_PATTERN ){
throw TypeCheckingExceptionPrivate(n, "argument of inst pattern list is not inst pattern");
}
}
diff --git a/src/theory/quantifiers/trigger.cpp b/src/theory/quantifiers/trigger.cpp
index c6ee48057..b2b8e7197 100644
--- a/src/theory/quantifiers/trigger.cpp
+++ b/src/theory/quantifiers/trigger.cpp
@@ -188,19 +188,7 @@ Trigger* Trigger::mkTrigger( QuantifiersEngine* qe, Node f, std::vector< Node >&
}
//check for duplicate?
- if( trOption==TR_MAKE_NEW ){
- //static int trNew = 0;
- //static int trOld = 0;
- //Trigger* t = qe->getTermDatabase()->getTrigger( trNodes );
- //if( t ){
- // trOld++;
- //}else{
- // trNew++;
- //}
- //if( (trNew+trOld)%100==0 ){
- // Notice() << "Trigger new old = " << trNew << " " << trOld << std::endl;
- //}
- }else{
+ if( trOption!=TR_MAKE_NEW ){
Trigger* t = qe->getTriggerDatabase()->getTrigger( trNodes );
if( t ){
if( trOption==TR_GET_OLD ){
@@ -215,21 +203,13 @@ Trigger* Trigger::mkTrigger( QuantifiersEngine* qe, Node f, std::vector< Node >&
qe->getTriggerDatabase()->addTrigger( trNodes, t );
return t;
}
+
Trigger* Trigger::mkTrigger( QuantifiersEngine* qe, Node f, Node n, int matchOption, bool keepAll, int trOption, bool smartTriggers ){
std::vector< Node > nodes;
nodes.push_back( n );
return mkTrigger( qe, f, nodes, matchOption, keepAll, trOption, smartTriggers );
}
-bool Trigger::isUsableTrigger( std::vector< Node >& nodes, Node f ){
- for( int i=0; i<(int)nodes.size(); i++ ){
- if( !isUsableTrigger( nodes[i], f ) ){
- return false;
- }
- }
- return true;
-}
-
bool Trigger::isUsable( Node n, Node f ){
if( quantifiers::TermDb::getInstConstAttr(n)==f ){
if( isAtomicTrigger( n ) ){
@@ -243,9 +223,7 @@ bool Trigger::isUsable( Node n, Node f ){
return true;
}else{
std::map< Node, Node > coeffs;
- if( isArithmeticTrigger( f, n, coeffs ) ){
- return true;
- }else if( isBooleanTermTrigger( n ) ){
+ if( isBooleanTermTrigger( n ) ){
return true;
}
}
@@ -324,7 +302,7 @@ bool Trigger::isUsableTrigger( Node n, Node f ){
bool Trigger::isAtomicTrigger( Node n ){
Kind k = n.getKind();
- return ( k==APPLY_UF && !n.getOperator().getAttribute(NoMatchAttribute()) ) ||
+ return ( k==APPLY_UF && !n.getOperator().getAttribute(NoMatchAttribute()) ) ||
( k!=APPLY_UF && isAtomicTriggerKind( k ) );
}
bool Trigger::isAtomicTriggerKind( Kind k ) {
@@ -347,7 +325,7 @@ bool Trigger::isSimpleTrigger( Node n ){
}
-bool Trigger::collectPatTerms2( QuantifiersEngine* qe, Node f, Node n, std::map< Node, bool >& patMap, int tstrt, bool pol, bool hasPol ){
+bool Trigger::collectPatTerms2( QuantifiersEngine* qe, Node f, Node n, std::map< Node, bool >& patMap, int tstrt, std::vector< Node >& exclude, bool pol, bool hasPol ){
if( patMap.find( n )==patMap.end() ){
patMap[ n ] = false;
bool newHasPol = n.getKind()==IFF ? false : hasPol;
@@ -359,14 +337,17 @@ bool Trigger::collectPatTerms2( QuantifiersEngine* qe, Node f, Node n, std::map<
bool retVal = false;
for( int i=0; i<(int)n.getNumChildren(); i++ ){
bool newHasPol2 = (n.getKind()==ITE && i==0) ? false : newHasPol;
- if( collectPatTerms2( qe, f, n[i], patMap, tstrt, newPol, newHasPol2 ) ){
+ if( collectPatTerms2( qe, f, n[i], patMap, tstrt, exclude, newPol, newHasPol2 ) ){
retVal = true;
}
}
if( retVal ){
return true;
}else{
- Node nu = getIsUsableTrigger( n, f, pol, hasPol );
+ Node nu;
+ if( std::find( exclude.begin(), exclude.end(), n )==exclude.end() ){
+ nu = getIsUsableTrigger( n, f, pol, hasPol );
+ }
if( !nu.isNull() ){
patMap[ nu ] = true;
return true;
@@ -377,7 +358,10 @@ bool Trigger::collectPatTerms2( QuantifiersEngine* qe, Node f, Node n, std::map<
}
}else{
bool retVal = false;
- Node nu = getIsUsableTrigger( n, f, pol, hasPol );
+ Node nu;
+ if( std::find( exclude.begin(), exclude.end(), n )==exclude.end() ){
+ nu = getIsUsableTrigger( n, f, pol, hasPol );
+ }
if( !nu.isNull() ){
patMap[ nu ] = true;
if( tstrt==TS_MAX_TRIGGER ){
@@ -389,7 +373,7 @@ bool Trigger::collectPatTerms2( QuantifiersEngine* qe, Node f, Node n, std::map<
if( n.getKind()!=FORALL ){
for( int i=0; i<(int)n.getNumChildren(); i++ ){
bool newHasPol2 = (n.getKind()==ITE && i==0) ? false : newHasPol;
- if( collectPatTerms2( qe, f, n[i], patMap, tstrt, newPol, newHasPol2 ) ){
+ if( collectPatTerms2( qe, f, n[i], patMap, tstrt, exclude, newPol, newHasPol2 ) ){
retVal = true;
}
}
@@ -401,12 +385,41 @@ bool Trigger::collectPatTerms2( QuantifiersEngine* qe, Node f, Node n, std::map<
}
}
-void Trigger::collectPatTerms( QuantifiersEngine* qe, Node f, Node n, std::vector< Node >& patTerms, int tstrt, bool filterInst ){
+bool Trigger::isBooleanTermTrigger( Node n ) {
+ if( n.getKind()==ITE ){
+ //check for boolean term converted to ITE
+ if( n[0].getKind()==INST_CONSTANT &&
+ n[1].getKind()==CONST_BITVECTOR &&
+ n[2].getKind()==CONST_BITVECTOR ){
+ if( ((BitVectorType)n[1].getType().toType()).getSize()==1 &&
+ n[1].getConst<BitVector>().toInteger()==1 &&
+ n[2].getConst<BitVector>().toInteger()==0 ){
+ return true;
+ }
+ }
+ }
+ return false;
+}
+
+bool Trigger::isPureTheoryTrigger( Node n ) {
+ if( n.getKind()==APPLY_UF || n.getKind()==VARIABLE || n.getKind()==SKOLEM ){ //|| !quantifiers::TermDb::hasInstConstAttr( n ) ){
+ return false;
+ }else{
+ for( unsigned i=0; i<n.getNumChildren(); i++ ){
+ if( !isPureTheoryTrigger( n[i] ) ){
+ return false;
+ }
+ }
+ return true;
+ }
+}
+
+void Trigger::collectPatTerms( QuantifiersEngine* qe, Node f, Node n, std::vector< Node >& patTerms, int tstrt, std::vector< Node >& exclude, bool filterInst ){
std::map< Node, bool > patMap;
if( filterInst ){
//immediately do not consider any term t for which another term is an instance of t
std::vector< Node > patTerms2;
- collectPatTerms( qe, f, n, patTerms2, TS_ALL, false );
+ collectPatTerms( qe, f, n, patTerms2, TS_ALL, exclude, false );
std::vector< Node > temp;
temp.insert( temp.begin(), patTerms2.begin(), patTerms2.end() );
qe->getTermDatabase()->filterInstances( temp );
@@ -434,7 +447,7 @@ void Trigger::collectPatTerms( QuantifiersEngine* qe, Node f, Node n, std::vecto
}
}
}
- collectPatTerms2( qe, f, n, patMap, tstrt, true, true );
+ collectPatTerms2( qe, f, n, patMap, tstrt, exclude, true, true );
for( std::map< Node, bool >::iterator it = patMap.begin(); it != patMap.end(); ++it ){
if( it->second ){
patTerms.push_back( it->first );
@@ -442,65 +455,91 @@ void Trigger::collectPatTerms( QuantifiersEngine* qe, Node f, Node n, std::vecto
}
}
-bool Trigger::isArithmeticTrigger( Node f, Node n, std::map< Node, Node >& coeffs ){
- if( n.getKind()==PLUS ){
- Assert( coeffs.empty() );
- NodeBuilder<> t(kind::PLUS);
- for( int i=0; i<(int)n.getNumChildren(); i++ ){
+Node Trigger::getInversionVariable( Node n ) {
+ if( n.getKind()==INST_CONSTANT ){
+ return n;
+ }else if( n.getKind()==PLUS || n.getKind()==MULT ){
+ Node ret;
+ for( unsigned i=0; i<n.getNumChildren(); i++ ){
if( quantifiers::TermDb::hasInstConstAttr(n[i]) ){
- if( n[i].getKind()==INST_CONSTANT ){
- if( quantifiers::TermDb::getInstConstAttr(n[i])==f ){
- coeffs[ n[i] ] = Node::null();
- }else{
- coeffs.clear();
- return false;
+ if( ret.isNull() ){
+ ret = getInversionVariable( n[i] );
+ if( ret.isNull() ){
+ Trace("var-trigger-debug") << "No : multiple variables " << n << std::endl;
+ return Node::null();
+ }
+ }else{
+ return Node::null();
+ }
+ }else if( n.getKind()==MULT ){
+ if( !n[i].isConst() ){
+ Trace("var-trigger-debug") << "No : non-linear coefficient " << n << std::endl;
+ return Node::null();
+ }else if( n.getType().isInteger() ){
+ Rational r = n[i].getConst<Rational>();
+ if( r!=Rational(-1) && r!=Rational(1) ){
+ Trace("var-trigger-debug") << "No : not integer coefficient " << n << std::endl;
+ return Node::null();
}
- }else if( !isArithmeticTrigger( f, n[i], coeffs ) ){
- coeffs.clear();
- return false;
}
- }else{
- t << n[i];
}
}
- if( t.getNumChildren()==0 ){
- coeffs[ Node::null() ] = NodeManager::currentNM()->mkConst( Rational(0) );
- }else if( t.getNumChildren()==1 ){
- coeffs[ Node::null() ] = t.getChild( 0 );
- }else{
- coeffs[ Node::null() ] = t;
- }
- return true;
- }else if( n.getKind()==MULT ){
- if( n[0].getKind()==INST_CONSTANT && quantifiers::TermDb::getInstConstAttr(n[0])==f ){
- if( !quantifiers::TermDb::hasInstConstAttr(n[1]) ){
- coeffs[ n[0] ] = n[1];
- return true;
- }
- }else if( n[1].getKind()==INST_CONSTANT && quantifiers::TermDb::getInstConstAttr(n[1])==f ){
- if( !quantifiers::TermDb::hasInstConstAttr(n[0]) ){
- coeffs[ n[1] ] = n[0];
- return true;
+ return ret;
+ }else{
+ Trace("var-trigger-debug") << "No : unsupported operator " << n << "." << std::endl;
+ }
+ return Node::null();
+}
+
+Node Trigger::getInversion( Node n, Node x ) {
+ if( n.getKind()==INST_CONSTANT ){
+ return x;
+ }else if( n.getKind()==PLUS || n.getKind()==MULT ){
+ int cindex = -1;
+ for( unsigned i=0; i<n.getNumChildren(); i++ ){
+ if( !quantifiers::TermDb::hasInstConstAttr(n[i]) ){
+ if( n.getKind()==PLUS ){
+ x = NodeManager::currentNM()->mkNode( MINUS, x, n[i] );
+ }else if( n.getKind()==MULT ){
+ Assert( n[i].isConst() );
+ Node coeff = NodeManager::currentNM()->mkConst( Rational(1) / n[i].getConst<Rational>() );
+ x = NodeManager::currentNM()->mkNode( MULT, x, coeff );
+ }
+ }else{
+ Assert( cindex==-1 );
+ cindex = i;
}
}
+ Assert( cindex!=-1 );
+ return getInversion( n[cindex], x );
}
- return false;
+ return Node::null();
}
-bool Trigger::isBooleanTermTrigger( Node n ) {
- if( n.getKind()==ITE ){
- //check for boolean term converted to ITE
- if( n[0].getKind()==INST_CONSTANT &&
- n[1].getKind()==CONST_BITVECTOR &&
- n[2].getKind()==CONST_BITVECTOR ){
- if( ((BitVectorType)n[1].getType().toType()).getSize()==1 &&
- n[1].getConst<BitVector>().toInteger()==1 &&
- n[2].getConst<BitVector>().toInteger()==0 ){
- return true;
+InstMatchGenerator* Trigger::getInstMatchGenerator( Node n ) {
+ if( n.getKind()==INST_CONSTANT ){
+ return NULL;
+ }else{
+ Trace("var-trigger-debug") << "Is " << n << " a variable trigger?" << std::endl;
+ if( isBooleanTermTrigger( n ) ){
+ VarMatchGeneratorBooleanTerm* vmg = new VarMatchGeneratorBooleanTerm( n[0], n[1] );
+ Trace("var-trigger") << "Boolean term trigger : " << n << ", var = " << n[0] << std::endl;
+ return vmg;
+ }else{
+ Node x;
+ if( options::purifyTriggers() ){
+ x = getInversionVariable( n );
+ }
+ if( !x.isNull() ){
+ Node s = getInversion( n, x );
+ VarMatchGeneratorTermSubs* vmg = new VarMatchGeneratorTermSubs( x, s );
+ Trace("var-trigger") << "Term substitution trigger : " << n << ", var = " << x << ", subs = " << s << std::endl;
+ return vmg;
+ }else{
+ return new InstMatchGenerator( n );
}
}
}
- return false;
}
Trigger* TriggerTrie::getTrigger2( std::vector< Node >& nodes ){
diff --git a/src/theory/quantifiers/trigger.h b/src/theory/quantifiers/trigger.h
index 17da6f0d5..75ada4f83 100644
--- a/src/theory/quantifiers/trigger.h
+++ b/src/theory/quantifiers/trigger.h
@@ -30,6 +30,7 @@ class QuantifiersEngine;
namespace inst {
class IMGenerator;
+class InstMatchGenerator;
//a collect of nodes representing a trigger
class Trigger {
@@ -93,7 +94,7 @@ private:
static bool isUsable( Node n, Node f );
static Node getIsUsableTrigger( Node n, Node f, bool pol = true, bool hasPol = false );
/** collect all APPLY_UF pattern terms for f in n */
- static bool collectPatTerms2( QuantifiersEngine* qe, Node f, Node n, std::map< Node, bool >& patMap, int tstrt, bool pol, bool hasPol );
+ static bool collectPatTerms2( QuantifiersEngine* qe, Node f, Node n, std::map< Node, bool >& patMap, int tstrt, std::vector< Node >& exclude, bool pol, bool hasPol );
public:
//different strategies for choosing trigger terms
enum {
@@ -101,17 +102,19 @@ public:
TS_MIN_TRIGGER,
TS_ALL,
};
- static void collectPatTerms( QuantifiersEngine* qe, Node f, Node n, std::vector< Node >& patTerms, int tstrt, bool filterInst = false );
+ static void collectPatTerms( QuantifiersEngine* qe, Node f, Node n, std::vector< Node >& patTerms, int tstrt, std::vector< Node >& exclude, bool filterInst = false );
public:
/** is usable trigger */
- static bool isUsableTrigger( std::vector< Node >& nodes, Node f );
static bool isUsableTrigger( Node n, Node f );
static bool isAtomicTrigger( Node n );
static bool isAtomicTriggerKind( Kind k );
static bool isSimpleTrigger( Node n );
- /** get pattern arithmetic */
- static bool isArithmeticTrigger( Node f, Node n, std::map< Node, Node >& coeffs );
static bool isBooleanTermTrigger( Node n );
+ static bool isPureTheoryTrigger( Node n );
+ /** return data structure for producing matches for this trigger. */
+ static InstMatchGenerator* getInstMatchGenerator( Node n );
+ static Node getInversionVariable( Node n );
+ static Node getInversion( Node n, Node x );
inline void toStream(std::ostream& out) const {
/*
diff --git a/src/theory/quantifiers_engine.cpp b/src/theory/quantifiers_engine.cpp
index c55ffa2a6..a4d7aaec1 100644
--- a/src/theory/quantifiers_engine.cpp
+++ b/src/theory/quantifiers_engine.cpp
@@ -30,6 +30,7 @@
#include "theory/quantifiers/bounded_integers.h"
#include "theory/quantifiers/rewrite_engine.h"
#include "theory/quantifiers/quant_conflict_find.h"
+#include "theory/quantifiers/conjecture_generator.h"
#include "theory/quantifiers/relevant_domain.h"
#include "theory/uf/options.h"
#include "theory/uf/theory_uf.h"
@@ -83,6 +84,12 @@ d_lemmas_produced_c(u){
}else{
d_qcf = NULL;
}
+ if( options::conjectureGen() ){
+ d_sg_gen = new quantifiers::ConjectureGenerator( this, c );
+ d_modules.push_back( d_sg_gen );
+ }else{
+ d_sg_gen = NULL;
+ }
if( !options::finiteModelFind() || options::fmfInstEngine() ){
//the instantiation must set incomplete flag unless finite model finding is turned on
d_inst_engine = new quantifiers::InstantiationEngine( this, !options::finiteModelFind() );
@@ -159,56 +166,85 @@ void QuantifiersEngine::finishInit(){
void QuantifiersEngine::check( Theory::Effort e ){
CodeTimer codeTimer(d_time);
- bool needsCheck = e>=Theory::EFFORT_LAST_CALL; //always need to check at or above last call
- for( int i=0; i<(int)d_modules.size(); i++ ){
- if( d_modules[i]->needsCheck( e ) ){
- needsCheck = true;
+ bool needsCheck = false;
+ bool needsBuildModel = false;
+ std::vector< QuantifiersModule* > qm;
+ if( d_model->getNumAssertedQuantifiers()>0 ){
+ needsCheck = e>=Theory::EFFORT_LAST_CALL; //always need to check at or above last call
+ for( int i=0; i<(int)d_modules.size(); i++ ){
+ if( d_modules[i]->needsCheck( e ) ){
+ qm.push_back( d_modules[i] );
+ needsCheck = true;
+ }
}
}
if( needsCheck ){
Trace("quant-engine") << "Quantifiers Engine check, level = " << e << std::endl;
+ Trace("quant-engine-debug") << " modules to check : ";
+ for( unsigned i=0; i<qm.size(); i++ ){
+ Trace("quant-engine-debug") << qm[i]->identify() << " ";
+ }
+ Trace("quant-engine-debug") << std::endl;
+ Trace("quant-engine-debug") << " # quantified formulas = " << d_model->getNumAssertedQuantifiers() << std::endl;
+ Trace("quant-engine-debug") << " Theory engine finished : " << !d_te->needCheck() << std::endl;
+
if( !getMasterEqualityEngine()->consistent() ){
Trace("quant-engine") << "Master equality engine not consistent, return." << std::endl;
return;
}
- Trace("quant-engine-debug") << "Resetting modules..." << std::endl;
+ Trace("quant-engine-debug") << "Resetting all modules..." << std::endl;
//reset relevant information
+ d_conflict = false;
d_hasAddedLemma = false;
+
+ //flush previous lemmas (for instance, if was interupted)
+ flushLemmas();
+ if( d_hasAddedLemma ){
+ return;
+ }
+
d_term_db->reset( e );
d_eq_query->reset();
if( d_rel_dom ){
d_rel_dom->reset();
}
+ d_model->reset_round();
for( int i=0; i<(int)d_modules.size(); i++ ){
d_modules[i]->reset_round( e );
}
- Trace("quant-engine-debug") << "Done resetting modules." << std::endl;
+ Trace("quant-engine-debug") << "Done resetting all modules." << std::endl;
if( e==Theory::EFFORT_LAST_CALL ){
- //if effort is last call, try to minimize model first
- if( options::finiteModelFind() ){
- //first, check if we can minimize the model further
- if( !((uf::TheoryUF*)getTheoryEngine()->theoryOf( THEORY_UF ))->getStrongSolver()->minimize() ){
- return;
- }
+ //if effort is last call, try to minimize model first FIXME: remove?
+ uf::StrongSolverTheoryUF * ufss = ((uf::TheoryUF*)getTheoryEngine()->theoryOf( THEORY_UF ))->getStrongSolver();
+ if( ufss && !ufss->minimize() ){
+ return;
}
++(d_statistics.d_instantiation_rounds_lc);
}else if( e==Theory::EFFORT_FULL ){
++(d_statistics.d_instantiation_rounds);
}
- Trace("quant-engine-debug") << "Check with modules..." << std::endl;
- for( int i=0; i<(int)d_modules.size(); i++ ){
- Trace("quant-engine-debug") << "Check " << d_modules[i]->identify().c_str() << "..." << std::endl;
- d_modules[i]->check( e );
+
+ Trace("quant-engine-debug") << "Check modules that needed check..." << std::endl;
+ for( unsigned quant_e = QEFFORT_CONFLICT; quant_e<=QEFFORT_MODEL; quant_e++ ){
+ for( int i=0; i<(int)qm.size(); i++ ){
+ Trace("quant-engine-debug") << "Check " << qm[i]->identify().c_str() << " at effort " << quant_e << "..." << std::endl;
+ qm[i]->check( e, quant_e );
+ }
+ //flush all current lemmas
+ flushLemmas();
+ //if we have added one, stop
+ if( d_hasAddedLemma ){
+ break;
+ }
}
- Trace("quant-engine-debug") << "Done check with modules." << std::endl;
+ Trace("quant-engine-debug") << "Done check modules that needed check." << std::endl;
+
//build the model if not done so already
// this happens if no quantifiers are currently asserted and no model-building module is enabled
if( e==Theory::EFFORT_LAST_CALL && !d_hasAddedLemma ){
if( options::produceModels() && !d_model->isModelSet() ){
- Trace("quant-engine-debug") << "Build the model..." << std::endl;
- d_te->getModelBuilder()->buildModel( d_model, true );
- Trace("quant-engine-debug") << "Done building the model." << std::endl;
+ needsBuildModel = true;
}
if( Trace.isOn("inst-per-quant") ){
for( std::map< Node, int >::iterator it = d_total_inst_debug.begin(); it != d_total_inst_debug.end(); ++it ){
@@ -224,6 +260,16 @@ void QuantifiersEngine::check( Theory::Effort e ){
}
}
Trace("quant-engine") << "Finished quantifiers engine check." << std::endl;
+ }else{
+ if( e==Theory::EFFORT_LAST_CALL && options::produceModels() ){
+ needsBuildModel = true;
+ }
+ }
+
+ if( needsBuildModel ){
+ Trace("quant-engine-debug") << "Build the model..." << std::endl;
+ d_te->getModelBuilder()->buildModel( d_model, true );
+ Trace("quant-engine-debug") << "Done building the model." << std::endl;
}
}
@@ -261,7 +307,7 @@ void QuantifiersEngine::registerQuantifier( Node f ){
void QuantifiersEngine::registerPattern( std::vector<Node> & pattern) {
for(std::vector<Node>::iterator p = pattern.begin(); p != pattern.end(); ++p){
std::set< Node > added;
- getTermDatabase()->addTerm(*p,added);
+ getTermDatabase()->addTerm( *p, added );
}
}
@@ -314,6 +360,10 @@ Node QuantifiersEngine::getNextDecisionRequest(){
void QuantifiersEngine::addTermToDatabase( Node n, bool withinQuant ){
std::set< Node > added;
getTermDatabase()->addTerm( n, added, withinQuant );
+ //maybe have triggered instantiations if we are doing eager instantiation
+ if( options::eagerInstQuant() ){
+ flushLemmas();
+ }
//added contains also the Node that just have been asserted in this branch
if( d_quant_rel ){
for( std::set< Node >::iterator i=added.begin(), end=added.end(); i!=end; i++ ){
@@ -338,6 +388,7 @@ bool QuantifiersEngine::addInstantiation( Node f, std::vector< Node >& vars, std
Assert( f.getKind()==FORALL );
Assert( vars.size()==terms.size() );
Node body = getInstantiation( f, vars, terms );
+ Trace("inst-assert") << "(assert " << body << ")" << std::endl;
//make the lemma
NodeBuilder<> nb(kind::OR);
nb << f.notNode() << body;
@@ -372,7 +423,7 @@ bool QuantifiersEngine::addInstantiation( Node f, std::vector< Node >& vars, std
}
}
}
- setInstantiationLevelAttr( body, f[1], maxInstLevel+1, terms );
+ setInstantiationLevelAttr( body, f[1], maxInstLevel+1 );
}
Trace("inst-debug") << "*** Lemma is " << lem << std::endl;
++(d_statistics.d_instantiations);
@@ -383,22 +434,55 @@ bool QuantifiersEngine::addInstantiation( Node f, std::vector< Node >& vars, std
}
}
-void QuantifiersEngine::setInstantiationLevelAttr( Node n, Node qn, uint64_t level, std::vector< Node >& inst_terms ){
+void QuantifiersEngine::setInstantiationLevelAttr( Node n, Node qn, uint64_t level ){
+ Trace("inst-level-debug2") << "IL : " << n << " " << qn << " " << level << std::endl;
//if not from the vector of terms we instantiatied
- if( std::find( inst_terms.begin(), inst_terms.end(), n )==inst_terms.end() ){
+ if( qn.getKind()!=BOUND_VARIABLE && n!=qn ){
//if this is a new term, without an instantiation level
- if( n!=qn && !n.hasAttribute(InstLevelAttribute()) ){
+ if( !n.hasAttribute(InstLevelAttribute()) ){
InstLevelAttribute ila;
n.setAttribute(ila,level);
+ Trace("inst-level-debug") << "Set instantiation level " << n << " to " << level << std::endl;
}
- Assert( qn.getKind()!=BOUND_VARIABLE );
Assert( n.getNumChildren()==qn.getNumChildren() );
for( int i=0; i<(int)n.getNumChildren(); i++ ){
- setInstantiationLevelAttr( n[i], qn[i], level, inst_terms );
+ setInstantiationLevelAttr( n[i], qn[i], level );
}
}
}
+void QuantifiersEngine::setInstantiationLevelAttr( Node n, uint64_t level ){
+ if( !n.hasAttribute(InstLevelAttribute()) ){
+ InstLevelAttribute ila;
+ n.setAttribute(ila,level);
+ Trace("inst-level-debug") << "Set instantiation level " << n << " to " << level << std::endl;
+ }
+ for( int i=0; i<(int)n.getNumChildren(); i++ ){
+ setInstantiationLevelAttr( n[i], level );
+ }
+}
+
+bool QuantifiersEngine::isTermEligibleForInstantiation( Node n, Node f, bool print ) {
+ if( n.hasAttribute(InstLevelAttribute()) ){
+ unsigned ml = options::instMaxLevel();
+ if( f.hasAttribute(QuantInstLevelAttribute()) ){
+ ml = f.getAttribute(QuantInstLevelAttribute());
+ }
+ if( n.getAttribute(InstLevelAttribute())>ml ){
+ Trace("inst-add-debug") << "Term " << n << " has instantiation level " << n.getAttribute(InstLevelAttribute());
+ Trace("inst-add-debug") << ", which is more than maximum allowed level " << ml << " for this quantified formula." << std::endl;
+ return false;
+ }
+ }else{
+ if( options::instLevelInputOnly() ){
+ Trace("inst-add-debug") << "Term " << n << " does not have an instantiation level." << std::endl;
+ return false;
+ }
+ }
+ return true;
+}
+
+
Node QuantifiersEngine::getSubstitute( Node n, std::vector< Node >& terms ){
if( n.getKind()==INST_CONSTANT ){
Debug("check-inst") << "Substitute inst constant : " << n << std::endl;
@@ -511,7 +595,14 @@ bool QuantifiersEngine::addLemma( Node lem, bool doCache ){
}
}
+void QuantifiersEngine::addRequirePhase( Node lit, bool req ){
+ d_phase_req_waiting[lit] = req;
+}
+
bool QuantifiersEngine::addInstantiation( Node f, InstMatch& m, bool mkRep, bool modEq, bool modInst ){
+ // For resource-limiting (also does a time check).
+ getOutputChannel().spendResource();
+
std::vector< Node > terms;
//make sure there are values for each variable we are instantiating
for( size_t i=0; i<f[0].getNumChildren(); i++ ){
@@ -536,24 +627,32 @@ bool QuantifiersEngine::addInstantiation( Node f, std::vector< Node >& terms, bo
if( mkRep ){
//pick the best possible representative for instantiation, based on past use and simplicity of term
terms[i] = d_eq_query->getInternalRepresentative( terms[i], f, i );
- //Trace("inst-add-debug") << " (" << terms[i] << ")";
+ Trace("inst-add-debug2") << " (" << terms[i] << ")";
}
}
Trace("inst-add-debug") << std::endl;
+ //check based on instantiation level
if( options::instMaxLevel()!=-1 ){
for( unsigned i=0; i<terms.size(); i++ ){
- if( terms[i].hasAttribute(InstLevelAttribute()) &&
- (int)terms[i].getAttribute(InstLevelAttribute())>options::instMaxLevel() ){
- Trace("inst-add-debug") << "Term " << terms[i] << " has instantiation level " << terms[i].getAttribute(InstLevelAttribute());
- Trace("inst-add-debug") << ", which is more than maximum allowed level " << options::instMaxLevel() << std::endl;
+ if( !isTermEligibleForInstantiation( terms[i], f, true ) ){
return false;
}
}
}
+ //check for entailment
+ if( options::instNoEntail() ){
+ std::map< TNode, TNode > subs;
+ for( unsigned i=0; i<terms.size(); i++ ){
+ subs[f[0][i]] = terms[i];
+ }
+ if( d_term_db->isEntailed( f[1], subs, false, true ) ){
+ Trace("inst-add-debug") << " -> Currently entailed." << std::endl;
+ return false;
+ }
+ }
//check for duplication
- ///*
bool alreadyExists = false;
if( options::incrementalSolving() ){
Trace("inst-add-debug") << "Adding into context-dependent inst trie, modEq = " << modEq << ", modInst = " << modInst << std::endl;
@@ -575,9 +674,10 @@ bool QuantifiersEngine::addInstantiation( Node f, std::vector< Node >& terms, bo
++(d_statistics.d_inst_duplicate_eq);
return false;
}
- //*/
+
//add the instantiation
+ Trace("inst-add-debug") << "Constructing instantiation..." << std::endl;
bool addedInst = addInstantiation( f, d_term_db->d_vars[f], terms );
//report the result
if( addedInst ){
@@ -608,18 +708,21 @@ bool QuantifiersEngine::addSplitEquality( Node n1, Node n2, bool reqPhase, bool
return addSplit( fm );
}
-void QuantifiersEngine::flushLemmas( OutputChannel* out ){
+void QuantifiersEngine::flushLemmas(){
if( !d_lemmas_waiting.empty() ){
- if( !out ){
- out = &getOutputChannel();
- }
//take default output channel if none is provided
d_hasAddedLemma = true;
for( int i=0; i<(int)d_lemmas_waiting.size(); i++ ){
- out->lemma( d_lemmas_waiting[i], false, true );
+ getOutputChannel().lemma( d_lemmas_waiting[i], false, true );
}
d_lemmas_waiting.clear();
}
+ if( !d_phase_req_waiting.empty() ){
+ for( std::map< Node, bool >::iterator it = d_phase_req_waiting.begin(); it != d_phase_req_waiting.end(); ++it ){
+ getOutputChannel().requirePhase( it->first, it->second );
+ }
+ d_phase_req_waiting.clear();
+ }
}
void QuantifiersEngine::getPhaseReqTerms( Node f, std::vector< Node >& nodes ){
@@ -793,7 +896,6 @@ Node EqualityQueryQuantifiersEngine::getInternalRepresentative( Node a, Node f,
//if cbqi is active, do not choose instantiation constant terms
if( !options::cbqi() || !quantifiers::TermDb::hasInstConstAttr(eqc[i]) ){
int score = getRepScore( eqc[i], f, index );
- //score prefers earliest use of this term as a representative
if( r_best.isNull() || ( score>=0 && ( r_best_score<0 || score<r_best_score ) ) ){
r_best = eqc[i];
r_best_score = score;
@@ -945,8 +1047,21 @@ int getDepth( Node n ){
}
}
+//smaller the score, the better
int EqualityQueryQuantifiersEngine::getRepScore( Node n, Node f, int index ){
- return d_rep_score.find( n )==d_rep_score.end() ? -1 : d_rep_score[n]; //initial
+ int s;
+ if( options::instMaxLevel()!=-1 ){
+ //score prefer lowest instantiation level
+ if( n.hasAttribute(InstLevelAttribute()) ){
+ s = n.getAttribute(InstLevelAttribute());
+ }else{
+ s = options::instLevelInputOnly() ? -1 : 0;
+ }
+ }else{
+ //score prefers earliest use of this term as a representative
+ s = d_rep_score.find( n )==d_rep_score.end() ? -1 : d_rep_score[n];
+ }
+ return s;
//return ( d_rep_score.find( n )==d_rep_score.end() ? 100 : 0 ) + getDepth( n ); //term depth
}
diff --git a/src/theory/quantifiers_engine.h b/src/theory/quantifiers_engine.h
index 7786e0b70..e914280c5 100644
--- a/src/theory/quantifiers_engine.h
+++ b/src/theory/quantifiers_engine.h
@@ -52,7 +52,7 @@ public:
/* reset at a round */
virtual void reset_round( Theory::Effort e ){}
/* Call during quantifier engine's check */
- virtual void check( Theory::Effort e ) = 0;
+ virtual void check( Theory::Effort e, unsigned quant_e ) = 0;
/* Called for new quantifiers */
virtual void registerQuantifier( Node q ) = 0;
virtual void assertNode( Node n ) = 0;
@@ -73,6 +73,7 @@ namespace quantifiers {
class QuantConflictFind;
class RewriteEngine;
class RelevantDomain;
+ class ConjectureGenerator;
}/* CVC4::theory::quantifiers */
namespace inst {
@@ -112,6 +113,14 @@ private:
quantifiers::QuantConflictFind* d_qcf;
/** rewrite rules utility */
quantifiers::RewriteEngine * d_rr_engine;
+ /** subgoal generator */
+ quantifiers::ConjectureGenerator * d_sg_gen;
+public: //effort levels
+ enum {
+ QEFFORT_CONFLICT,
+ QEFFORT_STANDARD,
+ QEFFORT_MODEL,
+ };
private:
/** list of all quantifiers seen */
std::vector< Node > d_quants;
@@ -120,8 +129,12 @@ private:
BoolMap d_lemmas_produced_c;
/** lemmas waiting */
std::vector< Node > d_lemmas_waiting;
+ /** phase requirements waiting */
+ std::map< Node, bool > d_phase_req_waiting;
/** has added lemma this round */
bool d_hasAddedLemma;
+ /** has a conflict been found */
+ bool d_conflict;
/** list of all instantiations produced for each quantifier */
std::map< Node, inst::InstMatchTrie > d_inst_match_trie;
std::map< Node, inst::CDInstMatchTrie* > d_c_inst_match_trie;
@@ -192,7 +205,9 @@ private:
/** instantiate f with arguments terms */
bool addInstantiation( Node f, std::vector< Node >& vars, std::vector< Node >& terms );
/** set instantiation level attr */
- void setInstantiationLevelAttr( Node n, Node qn, uint64_t level, std::vector< Node >& inst_terms );
+ static void setInstantiationLevelAttr( Node n, Node qn, uint64_t level );
+ /** flush lemmas */
+ void flushLemmas();
public:
/** get instantiation */
Node getInstantiation( Node f, std::vector< Node >& vars, std::vector< Node >& terms );
@@ -206,6 +221,8 @@ public:
bool existsInstantiation( Node f, InstMatch& m, bool modEq = true, bool modInst = false );
/** add lemma lem */
bool addLemma( Node lem, bool doCache = true );
+ /** add require phase */
+ void addRequirePhase( Node lit, bool req );
/** do instantiation specified by m */
bool addInstantiation( Node f, InstMatch& m, bool mkRep = true, bool modEq = false, bool modInst = false );
/** add instantiation */
@@ -216,10 +233,12 @@ public:
bool addSplitEquality( Node n1, Node n2, bool reqPhase = false, bool reqPhasePol = true );
/** has added lemma */
bool hasAddedLemma() { return !d_lemmas_waiting.empty() || d_hasAddedLemma; }
- /** flush lemmas */
- void flushLemmas( OutputChannel* out = NULL );
/** get number of waiting lemmas */
int getNumLemmasWaiting() { return (int)d_lemmas_waiting.size(); }
+ /** set instantiation level attr */
+ static void setInstantiationLevelAttr( Node n, uint64_t level );
+ /** is term eligble for instantiation? */
+ bool isTermEligibleForInstantiation( Node n, Node f, bool print = false );
public:
/** get number of quantifiers */
int getNumQuantifiers() { return (int)d_quants.size(); }
diff --git a/src/theory/rep_set.cpp b/src/theory/rep_set.cpp
index 954272549..ee14d6fc1 100644
--- a/src/theory/rep_set.cpp
+++ b/src/theory/rep_set.cpp
@@ -38,8 +38,9 @@ int RepSet::getNumRepresentatives( TypeNode tn ) const{
}
void RepSet::add( TypeNode tn, Node n ){
- d_tmap[ n ] = (int)d_type_reps[tn].size();
Trace("rsi-debug") << "Add rep #" << d_type_reps[tn].size() << " for " << tn << " : " << n << std::endl;
+ Assert( n.getType().isSubtypeOf( tn ) );
+ d_tmap[ n ] = (int)d_type_reps[tn].size();
d_type_reps[tn].push_back( n );
}
diff --git a/src/theory/sets/options b/src/theory/sets/options
index 1c95e78e4..7cb3eb677 100644
--- a/src/theory/sets/options
+++ b/src/theory/sets/options
@@ -11,4 +11,7 @@ option setsPropagate --sets-propagate bool :default true
option setsEagerLemmas --sets-eager-lemmas bool :default true
add lemmas even at regular effort
+option setsCare1 --sets-care1 bool :default false
+ generate one lemma at a time for care graph
+
endmodule
diff --git a/src/theory/sets/theory_sets.cpp b/src/theory/sets/theory_sets.cpp
index b59beac8d..106ad6e56 100644
--- a/src/theory/sets/theory_sets.cpp
+++ b/src/theory/sets/theory_sets.cpp
@@ -39,6 +39,9 @@ void TheorySets::addSharedTerm(TNode n) {
}
void TheorySets::check(Effort e) {
+ if (done() && !fullEffort(e)) {
+ return;
+ }
d_internal->check(e);
}
@@ -54,6 +57,14 @@ Node TheorySets::explain(TNode node) {
return d_internal->explain(node);
}
+EqualityStatus TheorySets::getEqualityStatus(TNode a, TNode b) {
+ return d_internal->getEqualityStatus(a, b);
+}
+
+Node TheorySets::getModelValue(TNode node) {
+ return d_internal->getModelValue(node);
+}
+
void TheorySets::preRegisterTerm(TNode node) {
d_internal->preRegisterTerm(node);
}
diff --git a/src/theory/sets/theory_sets.h b/src/theory/sets/theory_sets.h
index a16832389..6136fc8f8 100644
--- a/src/theory/sets/theory_sets.h
+++ b/src/theory/sets/theory_sets.h
@@ -58,6 +58,10 @@ public:
Node explain(TNode);
+ EqualityStatus getEqualityStatus(TNode a, TNode b);
+
+ Node getModelValue(TNode);
+
std::string identify() const { return "THEORY_SETS"; }
void preRegisterTerm(TNode node);
diff --git a/src/theory/sets/theory_sets_private.cpp b/src/theory/sets/theory_sets_private.cpp
index 592b4bc37..60b89451a 100644
--- a/src/theory/sets/theory_sets_private.cpp
+++ b/src/theory/sets/theory_sets_private.cpp
@@ -417,32 +417,176 @@ void TheorySetsPrivate::addSharedTerm(TNode n) {
d_equalityEngine.addTriggerTerm(n, THEORY_SETS);
}
+void TheorySetsPrivate::dumpAssertionsHumanified() const
+{
+ std::string tag = "sets-assertions";
+ context::CDList<Assertion>::const_iterator it = d_external.facts_begin(), it_end = d_external.facts_end();
+
+ std::map<TNode, std::set<TNode> > equalities;
+ std::set< pair<TNode, TNode> > disequalities;
+ std::map<TNode, std::pair<std::set<TNode>, std::set<TNode> > > members;
+ static std::map<TNode, int> numbering;
+ static int number = 0;
+
+ for (unsigned i = 0; it != it_end; ++ it, ++i) {
+ TNode ass = (*it).assertion;
+ // Trace("sets-care-dump") << AssertCommand(ass.toExpr()) << endl;
+ bool polarity = ass.getKind() != kind::NOT;
+ ass = polarity ? ass : ass[0];
+ Assert( ass.getNumChildren() == 2);
+ TNode left = d_equalityEngine.getRepresentative(ass[0]);
+ TNode right = d_equalityEngine.getRepresentative(ass[1]);
+ if(numbering[left] == 0) numbering[left] = ++number;
+ if(numbering[right] == 0) numbering[right] = ++number;
+ equalities[left].insert(ass[0]);
+ equalities[right].insert(ass[1]);
+ if(ass.getKind() == kind::EQUAL) {
+ if(polarity) {
+ Assert(left == right);
+ } else {
+ if(left > right) std::swap(left, right);
+ disequalities.insert(make_pair(left, right));
+ }
+ } else if(ass.getKind() == kind::MEMBER) {
+ (polarity ? members[right].first : members[right].second).insert(left);
+ }
+ }
+#define FORIT(it, container) for(typeof((container).begin()) it=(container).begin(); (it) != (container).end(); ++(it))
+ FORIT(kt, equalities) {
+ Trace(tag) << " Eq class of t" << numbering[(*kt).first] << ": " << std::endl;
+ FORIT(jt, (*kt).second) {
+ TNode S = (*jt);
+ if( S.getKind() != kind::UNION && S.getKind() != kind::INTERSECTION && S.getKind() != kind::SETMINUS) {
+ Trace(tag) << " " << *jt << ((*jt).getType().isSet() ? "\n": " ");
+ } else {
+ Trace(tag) << " ";
+ if(S[0].isConst() || numbering.find(d_equalityEngine.getRepresentative(S[0])) == numbering.end()) {
+ Trace(tag) << S[0];
+ } else {
+ Trace(tag) << "t" << numbering[d_equalityEngine.getRepresentative(S[0])];
+ }
+ Trace(tag) << " " << (S.getKind() == kind::UNION ? "|" : (S.getKind() == kind::INTERSECTION ? "&" : "-")) << " ";
+ if(S[1].isConst() || numbering.find(d_equalityEngine.getRepresentative(S[1])) == numbering.end()) {
+ Trace(tag) << S[1];
+ } else {
+ Trace(tag) << "t" << numbering[d_equalityEngine.getRepresentative(S[1])];
+ }
+ Trace(tag) << std::endl;
+ }
+ }
+ Trace(tag) << std::endl;
+ }
+ FORIT(kt, disequalities) Trace(tag) << "NOT(t"<<numbering[(*kt).first]<<" = t" <<numbering[(*kt).second] <<")"<< std::endl;
+ FORIT(kt, members) {
+ if( (*kt).second.first.size() > 0) {
+ Trace(tag) << "IN t" << numbering[(*kt).first] << ": ";
+ FORIT(jt, (*kt).second.first) {
+ TNode x = (*jt);
+ if(x.isConst() || numbering.find(d_equalityEngine.getRepresentative(x)) == numbering.end()) {
+ Trace(tag) << x;
+ } else {
+ Trace(tag) << "x" << numbering[d_equalityEngine.getRepresentative(x)] << ", ";
+ }
+ }
+ Trace(tag) << std::endl;
+ }
+ if( (*kt).second.second.size() > 0) {
+ Trace(tag) << "NOT IN t" << numbering[(*kt).first] << ": ";
+ FORIT(jt, (*kt).second.second) {
+ TNode x = (*jt);
+ if(x.isConst() || numbering.find(d_equalityEngine.getRepresentative(x)) == numbering.end()) {
+ Trace(tag) << x;
+ } else {
+ Trace(tag) << "x" << numbering[d_equalityEngine.getRepresentative(x)] << ", ";
+ }
+ }
+ Trace(tag) << std::endl;
+ }
+ }
+ Trace(tag) << std::endl;
+#undef FORIT
+}
void TheorySetsPrivate::computeCareGraph() {
Debug("sharing") << "Theory::computeCareGraph<" << d_external.identify() << ">()" << endl;
- for (unsigned i = 0; i < d_external.d_sharedTerms.size(); ++ i) {
+
+ if(Trace.isOn("sets-assertions")) {
+ // dump our understanding of assertions
+ dumpAssertionsHumanified();
+ }
+
+ unsigned i_st = 0;
+ if(options::setsCare1()) { i_st = d_ccg_i; }
+ for (unsigned i = i_st; i < d_external.d_sharedTerms.size(); ++ i) {
TNode a = d_external.d_sharedTerms[i];
TypeNode aType = a.getType();
- for (unsigned j = i + 1; j < d_external.d_sharedTerms.size(); ++ j) {
+
+ unsigned j_st = i + 1;
+ if(options::setsCare1()) { if(i == d_ccg_i) j_st = d_ccg_j + 1; }
+
+ for (unsigned j = j_st; j < d_external.d_sharedTerms.size(); ++ j) {
TNode b = d_external.d_sharedTerms[j];
if (b.getType() != aType) {
// We don't care about the terms of different types
continue;
}
+
switch (d_external.d_valuation.getEqualityStatus(a, b)) {
case EQUALITY_TRUE_AND_PROPAGATED:
+ // If we know about it, we should have propagated it, so we can skip
+ Trace("sets-care") << "[sets-care] Know: " << EQUAL(a, b) << std::endl;
+ break;
case EQUALITY_FALSE_AND_PROPAGATED:
// If we know about it, we should have propagated it, so we can skip
+ Trace("sets-care") << "[sets-care] Know: " << NOT(EQUAL(a, b)) << std::endl;
break;
- default:
+ case EQUALITY_FALSE:
+ case EQUALITY_TRUE:
+ Assert(false, "ERROR: Equality status true/false but not propagated (sets care graph computation).");
+ break;
+ case EQUALITY_TRUE_IN_MODEL:
+ d_external.addCarePair(a, b);
+ case EQUALITY_FALSE_IN_MODEL:
+ if(Trace.isOn("sets-care-performance-test")) {
+ // TODO: delete these lines, only for performance testing for now
+ d_external.addCarePair(a, b);
+ }
+ break;
+ case EQUALITY_UNKNOWN:
// Let's split on it
d_external.addCarePair(a, b);
+ if(options::setsCare1()) {
+ d_ccg_i = i;
+ d_ccg_j = j;
+ return;
+ }
break;
+ default:
+ Unreachable();
}
}
}
}
+EqualityStatus TheorySetsPrivate::getEqualityStatus(TNode a, TNode b) {
+ Assert(d_equalityEngine.hasTerm(a) && d_equalityEngine.hasTerm(b));
+ if (d_equalityEngine.areEqual(a, b)) {
+ // The terms are implied to be equal
+ return EQUALITY_TRUE;
+ }
+ if (d_equalityEngine.areDisequal(a, b, false)) {
+ // The terms are implied to be dis-equal
+ return EQUALITY_FALSE;
+ }
+ if( d_external.d_valuation.getModelValue(a) == d_external.d_valuation.getModelValue(b) ) {
+ // Ther term are true in current model
+ return EQUALITY_TRUE_IN_MODEL;
+ }
+ return EQUALITY_FALSE_IN_MODEL;
+ // }
+ // //TODO: can we be more precise sometimes?
+ // return EQUALITY_UNKNOWN;
+}
/******************** Model generation ********************/
/******************** Model generation ********************/
@@ -578,6 +722,21 @@ Node TheorySetsPrivate::elementsToShape(Elements elements, TypeNode setType) con
return cur;
}
}
+Node TheorySetsPrivate::elementsToShape(set<Node> elements, TypeNode setType) const
+{
+ NodeManager* nm = NodeManager::currentNM();
+
+ if(elements.size() == 0) {
+ return nm->mkConst(EmptySet(nm->toType(setType)));
+ } else {
+ typeof(elements.begin()) it = elements.begin();
+ Node cur = SINGLETON(*it);
+ while( ++it != elements.end() ) {
+ cur = nm->mkNode(kind::UNION, cur, SINGLETON(*it));
+ }
+ return cur;
+ }
+}
void TheorySetsPrivate::collectModelInfo(TheoryModel* m, bool fullModel)
{
@@ -684,6 +843,11 @@ void TheorySetsPrivate::collectModelInfo(TheoryModel* m, bool fullModel)
#endif
}
+Node TheorySetsPrivate::getModelValue(TNode n)
+{
+ CodeTimer codeTimer(d_statistics.d_getModelValueTime);
+ return d_termInfoManager->getModelValue(n);
+}
/********************** Helper functions ***************************/
/********************** Helper functions ***************************/
@@ -730,14 +894,17 @@ Node mkAnd(const std::vector<TNode>& conjunctions) {
TheorySetsPrivate::Statistics::Statistics() :
- d_checkTime("theory::sets::time") {
-
+ d_checkTime("theory::sets::time")
+ , d_getModelValueTime("theory::sets::getModelValueTime")
+{
StatisticsRegistry::registerStat(&d_checkTime);
+ StatisticsRegistry::registerStat(&d_getModelValueTime);
}
TheorySetsPrivate::Statistics::~Statistics() {
StatisticsRegistry::unregisterStat(&d_checkTime);
+ StatisticsRegistry::unregisterStat(&d_getModelValueTime);
}
@@ -876,6 +1043,9 @@ TheorySetsPrivate::TheorySetsPrivate(TheorySets& external,
d_pending(c),
d_pendingDisequal(c),
d_pendingEverInserted(u),
+ d_modelCache(c),
+ d_ccg_i(c),
+ d_ccg_j(c),
d_scrutinize(NULL)
{
d_termInfoManager = new TermInfoManager(*this, c, &d_equalityEngine);
@@ -1106,6 +1276,8 @@ void TheorySetsPrivate::TermInfoManager::notifyMembership(TNode fact) {
d_info[S]->addToElementList(x, polarity);
d_info[x]->addToSetList(S, polarity);
+
+ d_theory.d_modelCache.clear();
}
const CDTNodeList* TheorySetsPrivate::TermInfoManager::getParents(TNode x) {
@@ -1259,8 +1431,38 @@ void TheorySetsPrivate::TermInfoManager::mergeTerms(TNode a, TNode b) {
(*itb).second->setsContainingThisElement );
mergeLists( (*ita).second->setsNotContainingThisElement,
(*itb).second->setsNotContainingThisElement );
+
+ d_theory.d_modelCache.clear();
}
+Node TheorySetsPrivate::TermInfoManager::getModelValue(TNode n)
+{
+ if(d_terms.find(n) == d_terms.end()) {
+ return Node();
+ }
+ Assert(n.getType().isSet());
+ set<Node> elements, elements_const;
+ Node S = d_eqEngine->getRepresentative(n);
+ typeof(d_theory.d_modelCache.begin()) it = d_theory.d_modelCache.find(S);
+ if(it != d_theory.d_modelCache.end()) {
+ return (*it).second;
+ }
+ const CDTNodeList* l = getMembers(S);
+ for(typeof(l->begin()) it = l->begin(); it != l->end(); ++it) {
+ TNode n = *it;
+ elements.insert(d_eqEngine->getRepresentative(n));
+ }
+ BOOST_FOREACH(TNode e, elements) {
+ if(e.isConst()) {
+ elements_const.insert(e);
+ } else {
+ elements_const.insert(d_theory.d_external.d_valuation.getModelValue(e));
+ }
+ }
+ Node v = d_theory.elementsToShape(elements_const, n.getType());
+ d_theory.d_modelCache[n] = v;
+ return v;
+}
}/* CVC4::theory::sets namespace */
}/* CVC4::theory namespace */
diff --git a/src/theory/sets/theory_sets_private.h b/src/theory/sets/theory_sets_private.h
index 78a415529..72c041d49 100644
--- a/src/theory/sets/theory_sets_private.h
+++ b/src/theory/sets/theory_sets_private.h
@@ -60,6 +60,10 @@ public:
Node explain(TNode);
+ EqualityStatus getEqualityStatus(TNode a, TNode b);
+
+ Node getModelValue(TNode);
+
void preRegisterTerm(TNode node);
void propagate(Theory::Effort) { /* we don't depend on this call */ }
@@ -70,6 +74,7 @@ private:
class Statistics {
public:
TimerStat d_checkTime;
+ TimerStat d_getModelValueTime;
Statistics();
~Statistics();
@@ -123,6 +128,7 @@ private:
void notifyMembership(TNode fact);
const CDTNodeList* getParents(TNode x);
const CDTNodeList* getMembers(TNode S);
+ Node getModelValue(TNode n);
const CDTNodeList* getNonMembers(TNode S);
void addTerm(TNode n);
void mergeTerms(TNode a, TNode b);
@@ -174,11 +180,19 @@ private:
typedef std::hash_map<TNode, Elements, TNodeHashFunction> SettermElementsMap;
const Elements& getElements(TNode setterm, SettermElementsMap& settermElementsMap) const;
Node elementsToShape(Elements elements, TypeNode setType) const;
+ Node elementsToShape(std::set<Node> elements, TypeNode setType) const;
bool checkModel(const SettermElementsMap& settermElementsMap, TNode S) const;
+ context::CDHashMap <Node, Node, NodeHashFunction> d_modelCache;
+
+
+ // sharing related
+ context::CDO<unsigned> d_ccg_i, d_ccg_j;
+
// more debugging stuff
friend class TheorySetsScrutinize;
TheorySetsScrutinize* d_scrutinize;
+ void dumpAssertionsHumanified() const; /** do some formatting to make them more readable */
};/* class TheorySetsPrivate */
diff --git a/src/theory/sets/theory_sets_type_rules.h b/src/theory/sets/theory_sets_type_rules.h
index eb270202a..6754bbb9e 100644
--- a/src/theory/sets/theory_sets_type_rules.h
+++ b/src/theory/sets/theory_sets_type_rules.h
@@ -100,7 +100,7 @@ struct MemberTypeRule {
}
TypeNode elementType = n[0].getType(check);
if(elementType != setType.getSetElementType()) {
- throw TypeCheckingExceptionPrivate(n, "set in operating on sets of different types");
+ throw TypeCheckingExceptionPrivate(n, "member operating on sets of different types");
}
}
return nodeManager->booleanType();
diff --git a/src/theory/strings/kinds b/src/theory/strings/kinds
index 4266c02f5..0f68d1207 100644
--- a/src/theory/strings/kinds
+++ b/src/theory/strings/kinds
@@ -88,6 +88,11 @@ operator REGEXP_LOOP 2:3 "regexp loop"
operator REGEXP_EMPTY 0 "regexp empty"
operator REGEXP_SIGMA 0 "regexp all characters"
+#internal
+operator REGEXP_RV 1 "regexp rv (internal use only)"
+typerule REGEXP_RV ::CVC4::theory::strings::RegExpRVTypeRule
+
+#typerules
typerule REGEXP_CONCAT ::CVC4::theory::strings::RegExpConcatTypeRule
typerule REGEXP_UNION ::CVC4::theory::strings::RegExpUnionTypeRule
typerule REGEXP_INTER ::CVC4::theory::strings::RegExpInterTypeRule
diff --git a/src/theory/strings/regexp_operation.cpp b/src/theory/strings/regexp_operation.cpp
index 369278994..e769eb712 100644
--- a/src/theory/strings/regexp_operation.cpp
+++ b/src/theory/strings/regexp_operation.cpp
@@ -1183,8 +1183,19 @@ void RegExpOpr::getCharSet( Node r, std::set<unsigned> &pcset, SetNodes &pvset )
}
}
+bool RegExpOpr::isPairNodesInSet(std::set< PairNodes > &s, Node n1, Node n2) {
+ for(std::set< PairNodes >::const_iterator itr = s.begin();
+ itr != s.end(); ++itr) {
+ if(itr->first == n1 && itr->second == n2 ||
+ itr->first == n2 && itr->second == n1) {
+ return true;
+ }
+ }
+ return false;
+}
Node RegExpOpr::intersectInternal( Node r1, Node r2, std::map< unsigned, std::set< PairNodes > > cache, bool &spflag ) {
+ Trace("regexp-intersect") << "Starting INTERSECT:\n "<< mkString(r1) << ",\n " << mkString(r2) << std::endl;
if(spflag) {
//TODO: var
return Node::null();
@@ -1230,11 +1241,18 @@ Node RegExpOpr::intersectInternal( Node r1, Node r2, std::map< unsigned, std::se
spflag = true;
}
}
+ if(Trace.isOn("regexp-debug")) {
+ Trace("regexp-debug") << "Try CSET( " << cset.size() << " ) = ";
+ for(std::set<unsigned>::const_iterator itr = cset.begin();
+ itr != cset.end(); itr++) {
+ Trace("regexp-debug") << *itr << ", ";
+ }
+ Trace("regexp-debug") << std::endl;
+ }
for(std::set<unsigned>::const_iterator itr = cset.begin();
itr != cset.end(); itr++) {
CVC4::String c( CVC4::String::convertUnsignedIntToChar(*itr) );
- std::pair< Node, Node > p(r1, r2);
- if(cache[ *itr ].find(p) == cache[ *itr ].end()) {
+ if(!isPairNodesInSet(cache[ *itr ], r1, r2)) {
Node r1l = derivativeSingle(r1, c);
Node r2l = derivativeSingle(r2, c);
std::map< unsigned, std::set< PairNodes > > cache2(cache);
@@ -1263,10 +1281,208 @@ Node RegExpOpr::intersectInternal( Node r1, Node r2, std::map< unsigned, std::se
Trace("regexp-intersect") << "INTERSECT( " << mkString(r1) << ", " << mkString(r2) << " ) = " << mkString(rNode) << std::endl;
return rNode;
}
+
+bool RegExpOpr::containC2(unsigned cnt, Node n) {
+ if(n.getKind() == kind::REGEXP_RV) {
+ unsigned y = n[0].getConst<Rational>().getNumerator().toUnsignedInt();
+ return cnt == y;
+ } else if(n.getKind() == kind::REGEXP_CONCAT) {
+ for( unsigned i=0; i<n.getNumChildren(); i++ ) {
+ if(containC2(cnt, n[i])) {
+ return true;
+ }
+ }
+ } else if(n.getKind() == kind::REGEXP_STAR) {
+ return containC2(cnt, n[0]);
+ } else if(n.getKind() == kind::REGEXP_UNION) {
+ for( unsigned i=0; i<n.getNumChildren(); i++ ) {
+ if(containC2(cnt, n[i])) {
+ return true;
+ }
+ }
+ }
+ return false;
+}
+Node RegExpOpr::convert1(unsigned cnt, Node n) {
+ Trace("regexp-debug") << "Converting " << n << " at " << cnt << "... " << std::endl;
+ Node r1, r2;
+ convert2(cnt, n, r1, r2);
+ Trace("regexp-debug") << "... getting r1=" << r1 << ", and r2=" << r2 << std::endl;
+ Node ret = NodeManager::currentNM()->mkNode(kind::REGEXP_CONCAT,
+ NodeManager::currentNM()->mkNode(kind::REGEXP_STAR, r1), r2);
+ ret = Rewriter::rewrite( ret );
+ Trace("regexp-debug") << "... done convert at " << cnt << ", with return " << ret << std::endl;
+ return ret;
+}
+void RegExpOpr::convert2(unsigned cnt, Node n, Node &r1, Node &r2) {
+ if(n == d_emptyRegexp) {
+ r1 = d_emptyRegexp;
+ r2 = d_emptyRegexp;
+ } else if(n == d_emptySingleton) {
+ r1 = d_emptySingleton;
+ r2 = d_emptySingleton;
+ } else if(n.getKind() == kind::REGEXP_RV) {
+ unsigned y = n[0].getConst<Rational>().getNumerator().toUnsignedInt();
+ r1 = d_emptySingleton;
+ if(cnt == y) {
+ r2 = d_emptyRegexp;
+ } else {
+ r2 = n;
+ }
+ } else if(n.getKind() == kind::REGEXP_CONCAT) {
+ //TODO
+ //convert2 x (r@(Seq l r1))
+ // | contains x r1 = let (r2,r3) = convert2 x r1
+ // in (Seq l r2, r3)
+ // | otherwise = (Empty, r)
+ bool flag = true;
+ std::vector<Node> vr1, vr2;
+ for( unsigned i=0; i<n.getNumChildren(); i++ ) {
+ if(containC2(cnt, n[i])) {
+ Node t1, t2;
+ convert2(cnt, n[i], t1, t2);
+ vr1.push_back(t1);
+ r1 = vr1.size()==0 ? d_emptyRegexp : vr1.size()==1 ? vr1[0] :
+ NodeManager::currentNM()->mkNode(kind::REGEXP_CONCAT, vr1);
+ vr2.push_back(t2);
+ for( unsigned j=i+1; j<n.getNumChildren(); j++ ) {
+ vr2.push_back(n[j]);
+ }
+ r2 = vr2.size()==0 ? d_emptyRegexp : vr2.size()==1 ? vr2[0] :
+ NodeManager::currentNM()->mkNode(kind::REGEXP_CONCAT, vr2);
+ flag = false;
+ break;
+ } else {
+ vr1.push_back(n[i]);
+ }
+ }
+ if(flag) {
+ r1 = d_emptySingleton;
+ r2 = n;
+ }
+ } else if(n.getKind() == kind::REGEXP_UNION) {
+ std::vector<Node> vr1, vr2;
+ for( unsigned i=0; i<n.getNumChildren(); i++ ) {
+ Node t1, t2;
+ convert2(cnt, n[i], t1, t2);
+ vr1.push_back(t1);
+ vr2.push_back(t2);
+ }
+ r1 = NodeManager::currentNM()->mkNode(kind::REGEXP_UNION, vr1);
+ r2 = NodeManager::currentNM()->mkNode(kind::REGEXP_UNION, vr2);
+ } else if(n.getKind() == kind::STRING_TO_REGEXP) {
+ r1 = d_emptySingleton;
+ r2 = n;
+ } else {
+ //is it possible?
+ }
+}
+Node RegExpOpr::intersectInternal2( Node r1, Node r2, std::map< PairNodes, Node > cache, bool &spflag, unsigned cnt ) {
+ Trace("regexp-intersect") << "Starting INTERSECT:\n "<< mkString(r1) << ",\n " << mkString(r2) << std::endl;
+ //if(Trace.isOn("regexp-debug")) {
+ // Trace("regexp-debug") << "... with cache:\n";
+ // for(std::map< PairNodes, Node >::const_iterator itr=cache.begin();
+ // itr!=cache.end();itr++) {
+ // Trace("regexp-debug") << "(" << itr->first.first << "," << itr->first.second << ")->" << itr->second << std::endl;
+ // }
+ //}
+ if(spflag) {
+ //TODO: var
+ return Node::null();
+ }
+ std::pair < Node, Node > p(r1, r2);
+ std::map < std::pair< Node, Node >, Node >::const_iterator itr = d_inter_cache.find(p);
+ Node rNode;
+ if(itr != d_inter_cache.end()) {
+ rNode = itr->second;
+ } else {
+ if(r1 == d_emptyRegexp || r2 == d_emptyRegexp) {
+ rNode = d_emptyRegexp;
+ } else if(r1 == d_emptySingleton || r2 == d_emptySingleton) {
+ Node exp;
+ int r = delta((r1 == d_emptySingleton ? r2 : r1), exp);
+ if(r == 0) {
+ //TODO: variable
+ spflag = true;
+ } else if(r == 1) {
+ rNode = d_emptySingleton;
+ } else {
+ rNode = d_emptyRegexp;
+ }
+ } else if(r1 == r2) {
+ rNode = convert1(cnt, r1);
+ } else {
+ PairNodes p(r1, r2);
+ std::map< PairNodes, Node >::const_iterator itrcache = cache.find(p);
+ if(itrcache != cache.end()) {
+ rNode = itrcache->second;
+ } else {
+ if(checkConstRegExp(r1) && checkConstRegExp(r2)) {
+ std::vector< unsigned > cset;
+ std::set< unsigned > cset1, cset2;
+ std::set< Node > vset1, vset2;
+ firstChars(r1, cset1, vset1);
+ firstChars(r2, cset2, vset2);
+ std::set_intersection(cset1.begin(), cset1.end(), cset2.begin(), cset1.end(),
+ std::inserter(cset, cset.begin()));
+ std::vector< Node > vec_nodes;
+ Node delta_exp;
+ int flag = delta(r1, delta_exp);
+ int flag2 = delta(r2, delta_exp);
+ if(flag != 2 && flag2 != 2) {
+ if(flag == 1 && flag2 == 1) {
+ vec_nodes.push_back(d_emptySingleton);
+ } else {
+ //TODO
+ spflag = true;
+ }
+ }
+ if(Trace.isOn("regexp-debug")) {
+ Trace("regexp-debug") << "Try CSET( " << cset.size() << " ) = ";
+ for(std::vector<unsigned>::const_iterator itr = cset.begin();
+ itr != cset.end(); itr++) {
+ CVC4::String c( CVC4::String::convertUnsignedIntToChar(*itr) );
+ Trace("regexp-debug") << c << ", ";
+ }
+ Trace("regexp-debug") << std::endl;
+ }
+ for(std::vector<unsigned>::const_iterator itr = cset.begin();
+ itr != cset.end(); itr++) {
+ CVC4::String c( CVC4::String::convertUnsignedIntToChar(*itr) );
+ Node r1l = derivativeSingle(r1, c);
+ Node r2l = derivativeSingle(r2, c);
+ std::map< PairNodes, Node > cache2(cache);
+ PairNodes p(r1, r2);
+ cache2[ p ] = NodeManager::currentNM()->mkNode(kind::REGEXP_RV, NodeManager::currentNM()->mkConst(CVC4::Rational(cnt)));
+ Node rt = intersectInternal2(r1l, r2l, cache2, spflag, cnt+1);
+ rt = convert1(cnt, rt);
+ if(spflag) {
+ //TODO:
+ return Node::null();
+ }
+ rt = Rewriter::rewrite( NodeManager::currentNM()->mkNode(kind::REGEXP_CONCAT,
+ NodeManager::currentNM()->mkNode(kind::STRING_TO_REGEXP, NodeManager::currentNM()->mkConst(c)), rt) );
+ vec_nodes.push_back(rt);
+ }
+ rNode = vec_nodes.size()==0 ? d_emptyRegexp : vec_nodes.size()==1 ? vec_nodes[0] :
+ NodeManager::currentNM()->mkNode(kind::REGEXP_UNION, vec_nodes);
+ rNode = Rewriter::rewrite( rNode );
+ } else {
+ //TODO: non-empty var set
+ spflag = true;
+ }
+ }
+ }
+ d_inter_cache[p] = rNode;
+ }
+ Trace("regexp-intersect") << "End of INTERSECT( " << mkString(r1) << ", " << mkString(r2) << " ) = " << mkString(rNode) << std::endl;
+ return rNode;
+}
Node RegExpOpr::intersect(Node r1, Node r2, bool &spflag) {
- std::map< unsigned, std::set< PairNodes > > cache;
+ //std::map< unsigned, std::set< PairNodes > > cache;
+ std::map< PairNodes, Node > cache;
if(checkConstRegExp(r1) && checkConstRegExp(r2)) {
- return intersectInternal(r1, r2, cache, spflag);
+ return intersectInternal2(r1, r2, cache, spflag, 1);
} else {
spflag = true;
return Node::null();
@@ -1516,6 +1732,12 @@ std::string RegExpOpr::mkString( Node r ) {
retStr += "]";
break;
}
+ case kind::REGEXP_RV: {
+ retStr += "<";
+ retStr += r[0].getConst<Rational>().getNumerator().toString();
+ retStr += ">";
+ break;
+ }
default:
Trace("strings-error") << "Unsupported term: " << r << " in RegExp." << std::endl;
//Assert( false );
diff --git a/src/theory/strings/regexp_operation.h b/src/theory/strings/regexp_operation.h
index e4ae1208d..2ae578cd6 100644
--- a/src/theory/strings/regexp_operation.h
+++ b/src/theory/strings/regexp_operation.h
@@ -69,9 +69,14 @@ private:
std::string niceChar( Node r );
int gcd ( int a, int b );
Node mkAllExceptOne( char c );
+ bool isPairNodesInSet(std::set< PairNodes > &s, Node n1, Node n2);
void getCharSet( Node r, std::set<unsigned> &pcset, SetNodes &pvset );
Node intersectInternal( Node r1, Node r2, std::map< unsigned, std::set< PairNodes > > cache, bool &spflag );
+ bool containC2(unsigned cnt, Node n);
+ Node convert1(unsigned cnt, Node n);
+ void convert2(unsigned cnt, Node n, Node &r1, Node &r2);
+ Node intersectInternal2( Node r1, Node r2, std::map< PairNodes, Node > cache, bool &spflag, unsigned cnt );
void firstChars( Node r, std::set<unsigned> &pcset, SetNodes &pvset );
//TODO: for intersection
diff --git a/src/theory/strings/theory_strings.cpp b/src/theory/strings/theory_strings.cpp
index 2856ce1e0..ac1b1b1ed 100644
--- a/src/theory/strings/theory_strings.cpp
+++ b/src/theory/strings/theory_strings.cpp
@@ -550,6 +550,10 @@ Node TheoryStrings::expandDefinition(LogicRequest &logicRequest, Node node) {
void TheoryStrings::check(Effort e) {
+ if (done() && !fullEffort(e)) {
+ return;
+ }
+
bool polarity;
TNode atom;
@@ -2500,6 +2504,7 @@ bool TheoryStrings::checkMemberships() {
std::vector< Node > processed;
std::vector< Node > cprocessed;
+ Trace("regexp-debug") << "Checking Memberships ... " << std::endl;
//if(options::stringEIT()) {
//TODO: Opt for normal forms
for(NodeListMap::const_iterator itr_xr = d_str_re_map.begin();
@@ -2507,6 +2512,7 @@ bool TheoryStrings::checkMemberships() {
bool spflag = false;
Node x = (*itr_xr).first;
NodeList* lst = (*itr_xr).second;
+ Trace("regexp-debug") << "Checking Memberships for " << x << std::endl;
if(d_inter_index.find(x) == d_inter_index.end()) {
d_inter_index[x] = 0;
}
@@ -2515,6 +2521,7 @@ bool TheoryStrings::checkMemberships() {
if(lst->size() == 1) {
d_inter_cache[x] = (*lst)[0];
d_inter_index[x] = 1;
+ Trace("regexp-debug") << "... only one choice " << std::endl;
} else if(lst->size() > 1) {
Node r;
if(d_inter_cache.find(x) != d_inter_cache.end()) {
@@ -2528,6 +2535,7 @@ bool TheoryStrings::checkMemberships() {
for(int i=0; i<cur_inter_idx; i++) {
++itr_lst;
}
+ Trace("regexp-debug") << "... staring from : " << cur_inter_idx << ", we have " << lst->size() << std::endl;
for(;itr_lst != lst->end(); ++itr_lst) {
Node r2 = *itr_lst;
r = d_regexp_opr.intersect(r, r2, spflag);
@@ -2561,6 +2569,7 @@ bool TheoryStrings::checkMemberships() {
}
//}
+ Trace("regexp-debug") << "... No Intersec Conflict in Memberships " << std::endl;
if(!addedLemma) {
for( unsigned i=0; i<d_regexp_memberships.size(); i++ ) {
//check regular expression membership
@@ -3325,4 +3334,4 @@ TheoryStrings::Statistics::~Statistics(){
}/* CVC4::theory::strings namespace */
}/* CVC4::theory namespace */
-}/* CVC4 namespace */ \ No newline at end of file
+}/* CVC4 namespace */
diff --git a/src/theory/strings/theory_strings_rewriter.cpp b/src/theory/strings/theory_strings_rewriter.cpp
index 12ff92b5e..e37cabfb6 100644
--- a/src/theory/strings/theory_strings_rewriter.cpp
+++ b/src/theory/strings/theory_strings_rewriter.cpp
@@ -164,8 +164,12 @@ Node TheoryStringsRewriter::prerewriteOrRegExp(TNode node) {
for(unsigned i=0; i<node.getNumChildren(); ++i) {
if(node[i].getKind() == kind::REGEXP_UNION) {
Node tmpNode = prerewriteOrRegExp( node[i] );
- for(unsigned int j=0; j<tmpNode.getNumChildren(); ++j) {
- node_vec.push_back( tmpNode[j] );
+ if(tmpNode.getKind() == kind::REGEXP_UNION) {
+ for(unsigned int j=0; j<tmpNode.getNumChildren(); ++j) {
+ node_vec.push_back( tmpNode[j] );
+ }
+ } else {
+ node_vec.push_back( tmpNode );
}
flag = true;
} else if(node[i].getKind() == kind::REGEXP_EMPTY) {
@@ -200,6 +204,7 @@ bool TheoryStringsRewriter::checkConstRegExp( TNode t ) {
bool TheoryStringsRewriter::testConstStringInRegExp( CVC4::String &s, unsigned int index_start, TNode r ) {
Assert( index_start <= s.size() );
+ Trace("regexp-debug") << "Checking " << s << " in " << r << ", starting at " << index_start << std::endl;
int k = r.getKind();
switch( k ) {
case kind::STRING_TO_REGEXP: {
@@ -278,7 +283,7 @@ bool TheoryStringsRewriter::testConstStringInRegExp( CVC4::String &s, unsigned i
return false;
}
case kind::REGEXP_SIGMA: {
- if(s.size() == 1) {
+ if(s.size() == index_start + 1) {
return true;
} else {
return false;
@@ -302,7 +307,7 @@ Node TheoryStringsRewriter::rewriteMembership(TNode node) {
if(node[1].getKind() == kind::REGEXP_EMPTY) {
retNode = NodeManager::currentNM()->mkConst( false );
- } else if( x.getKind() == kind::CONST_STRING && checkConstRegExp(node[1]) ) {
+ } else if(x.getKind()==kind::CONST_STRING && checkConstRegExp(node[1])) {
//test whether x in node[1]
CVC4::String s = x.getConst<String>();
retNode = NodeManager::currentNM()->mkConst( testConstStringInRegExp( s, 0, node[1] ) );
@@ -311,10 +316,12 @@ Node TheoryStringsRewriter::rewriteMembership(TNode node) {
retNode = one.eqNode(NodeManager::currentNM()->mkNode(kind::STRING_LENGTH, x));
} else if(node[1].getKind() == kind::REGEXP_STAR && node[1][0].getKind() == kind::REGEXP_SIGMA) {
retNode = NodeManager::currentNM()->mkConst( true );
- } else if( x != node[0] ) {
+ } else if(node[1].getKind() == kind::STRING_TO_REGEXP) {
+ retNode = x.eqNode(node[1][0]);
+ } else if(x != node[0]) {
retNode = NodeManager::currentNM()->mkNode( kind::STRING_IN_REGEXP, x, node[1] );
}
- return retNode;
+ return retNode;
}
RewriteResponse TheoryStringsRewriter::postRewrite(TNode node) {
diff --git a/src/theory/strings/theory_strings_type_rules.h b/src/theory/strings/theory_strings_type_rules.h
index 6d1bb1c98..8a51ea36c 100644
--- a/src/theory/strings/theory_strings_type_rules.h
+++ b/src/theory/strings/theory_strings_type_rules.h
@@ -466,6 +466,21 @@ public:
}
};
+class RegExpRVTypeRule {
+public:
+ inline static TypeNode computeType(NodeManager* nodeManager, TNode n, bool check)
+ throw (TypeCheckingExceptionPrivate, AssertionException) {
+ if( check ) {
+ TypeNode t = n[0].getType(check);
+ if (!t.isInteger()) {
+ throw TypeCheckingExceptionPrivate(n, "expecting an integer term in RV");
+ }
+ }
+ return nodeManager->regexpType();
+ }
+};
+
+
}/* CVC4::theory::strings namespace */
}/* CVC4::theory namespace */
}/* CVC4 namespace */
diff --git a/src/theory/theory.h b/src/theory/theory.h
index 7bfc7051f..867dd7c31 100644
--- a/src/theory/theory.h
+++ b/src/theory/theory.h
@@ -377,7 +377,7 @@ public:
/**
* Returns true if the assertFact queue is empty
*/
- bool done() throw() {
+ bool done() const throw() {
return d_factsHead == d_facts.size();
}
@@ -678,7 +678,7 @@ public:
* This function is called when an attribute is set by a user. In SMT-LIBv2 this is done
* via the syntax (! n :attr)
*/
- virtual void setUserAttribute(const std::string& attr, Node n) {
+ virtual void setUserAttribute(const std::string& attr, Node n, std::vector<Node> node_values, std::string str_value) {
Unimplemented("Theory %s doesn't support Theory::setUserAttribute interface",
identify().c_str());
}
diff --git a/src/theory/theory_engine.cpp b/src/theory/theory_engine.cpp
index eb1da84b2..ed56890ae 100644
--- a/src/theory/theory_engine.cpp
+++ b/src/theory/theory_engine.cpp
@@ -34,6 +34,8 @@
#include "smt/logic_exception.h"
+#include "proof/proof_manager.h"
+
#include "util/node_visitor.h"
#include "util/ite_removal.h"
@@ -63,6 +65,8 @@ using namespace CVC4;
using namespace CVC4::theory;
void TheoryEngine::finishInit() {
+ PROOF (ProofManager::initTheoryProof(); );
+
// initialize the quantifiers engine
d_quantEngine = new QuantifiersEngine(d_context, d_userContext, this);
@@ -153,7 +157,7 @@ TheoryEngine::TheoryEngine(context::Context* context,
d_sharedTermsVisitor(d_sharedTerms),
d_unconstrainedSimp(new UnconstrainedSimplifier(context, logicInfo)),
d_bvToBoolPreprocessor(),
- d_arithSubstitutionsAdded("zzz::arith::substitutions", 0)
+ d_arithSubstitutionsAdded("theory::arith::zzz::arith::substitutions", 0)
{
for(TheoryId theoryId = theory::THEORY_FIRST; theoryId != theory::THEORY_LAST; ++ theoryId) {
d_theoryTable[theoryId] = NULL;
@@ -168,8 +172,6 @@ TheoryEngine::TheoryEngine(context::Context* context,
d_true = NodeManager::currentNM()->mkConst<bool>(true);
d_false = NodeManager::currentNM()->mkConst<bool>(false);
- PROOF (ProofManager::currentPM()->initTheoryProof(); );
-
d_iteUtilities = new ITEUtilities(d_iteRemover.getContainsVisitor());
StatisticsRegistry::registerStat(&d_arithSubstitutionsAdded);
@@ -403,7 +405,7 @@ void TheoryEngine::check(Theory::Effort effort) {
propagate(effort);
// We do combination if all has been processed and we are in fullcheck
- if (Theory::fullEffort(effort) && d_logicInfo.isSharingEnabled() && !d_factsAsserted && !d_lemmasAdded) {
+ if (Theory::fullEffort(effort) && d_logicInfo.isSharingEnabled() && !d_factsAsserted && !d_lemmasAdded && !d_inConflict) {
// Do the combination
Debug("theory") << "TheoryEngine::check(" << effort << "): running combination" << endl;
combineTheories();
@@ -451,7 +453,7 @@ void TheoryEngine::check(Theory::Effort effort) {
void TheoryEngine::combineTheories() {
- Debug("sharing") << "TheoryEngine::combineTheories()" << endl;
+ Trace("combineTheories") << "TheoryEngine::combineTheories()" << endl;
TimerStat::CodeTimer combineTheoriesTimer(d_combineTheoriesTime);
@@ -469,25 +471,48 @@ void TheoryEngine::combineTheories() {
// Call on each parametric theory to give us its care graph
CVC4_FOR_EACH_THEORY;
- Debug("sharing") << "TheoryEngine::combineTheories(): care graph size = " << careGraph.size() << endl;
+ Trace("combineTheories") << "TheoryEngine::combineTheories(): care graph size = " << careGraph.size() << endl;
// Now add splitters for the ones we are interested in
CareGraph::const_iterator care_it = careGraph.begin();
CareGraph::const_iterator care_it_end = careGraph.end();
+
for (; care_it != care_it_end; ++ care_it) {
const CarePair& carePair = *care_it;
- Debug("sharing") << "TheoryEngine::combineTheories(): checking " << carePair.a << " = " << carePair.b << " from " << carePair.theory << endl;
+ Debug("combineTheories") << "TheoryEngine::combineTheories(): checking " << carePair.a << " = " << carePair.b << " from " << carePair.theory << endl;
Assert(d_sharedTerms.isShared(carePair.a) || carePair.a.isConst());
Assert(d_sharedTerms.isShared(carePair.b) || carePair.b.isConst());
// The equality in question (order for no repetition)
Node equality = carePair.a.eqNode(carePair.b);
+ EqualityStatus es = getEqualityStatus(carePair.a, carePair.b);
+ Debug("combineTheories") << "TheoryEngine::combineTheories(): " <<
+ (es == EQUALITY_TRUE_AND_PROPAGATED ? "EQUALITY_TRUE_AND_PROPAGATED" :
+ es == EQUALITY_FALSE_AND_PROPAGATED ? "EQUALITY_FALSE_AND_PROPAGATED" :
+ es == EQUALITY_TRUE ? "EQUALITY_TRUE" :
+ es == EQUALITY_FALSE ? "EQUALITY_FALSE" :
+ es == EQUALITY_TRUE_IN_MODEL ? "EQUALITY_TRUE_IN_MODEL" :
+ es == EQUALITY_FALSE_IN_MODEL ? "EQUALITY_FALSE_IN_MODEL" :
+ es == EQUALITY_UNKNOWN ? "EQUALITY_UNKNOWN" :
+ "Unexpected case") << endl;
// We need to split on it
- Debug("sharing") << "TheoryEngine::combineTheories(): requesting a split " << endl;
+ Debug("combineTheories") << "TheoryEngine::combineTheories(): requesting a split " << endl;
lemma(equality.orNode(equality.notNode()), false, false, false, carePair.theory);
+ // This code is supposed to force preference to follow what the theory models already have
+ // but it doesn't seem to make a big difference - need to explore more -Clark
+ // if (true) {
+ // if (es == EQUALITY_TRUE || es == EQUALITY_TRUE_IN_MODEL) {
+ // Node e = ensureLiteral(equality);
+ // d_propEngine->requirePhase(e, true);
+ // }
+ // else if (es == EQUALITY_FALSE_IN_MODEL) {
+ // Node e = ensureLiteral(equality);
+ // d_propEngine->requirePhase(e, false);
+ // }
+ // }
}
}
@@ -1180,6 +1205,18 @@ Node TheoryEngine::getModelValue(TNode var) {
return theoryOf(Theory::theoryOf(var.getType()))->getModelValue(var);
}
+
+Node TheoryEngine::ensureLiteral(TNode n) {
+ Debug("ensureLiteral") << "rewriting: " << n << std::endl;
+ Node rewritten = Rewriter::rewrite(n);
+ Debug("ensureLiteral") << " got: " << rewritten << std::endl;
+ Node preprocessed = preprocess(rewritten);
+ Debug("ensureLiteral") << "preprocessed: " << preprocessed << std::endl;
+ d_propEngine->ensureLiteral(preprocessed);
+ return preprocessed;
+}
+
+
void TheoryEngine::printInstantiations( std::ostream& out ) {
if( d_quantEngine ){
d_quantEngine->printInstantiations( out );
@@ -1339,6 +1376,8 @@ void TheoryEngine::ensureLemmaAtoms(const std::vector<TNode>& atoms, theory::The
}
theory::LemmaStatus TheoryEngine::lemma(TNode node, bool negated, bool removable, bool preprocess, theory::TheoryId atomsTo) {
+ // For resource-limiting (also does a time check).
+ spendResource();
// Do we need to check atoms
if (atomsTo != theory::THEORY_LAST) {
@@ -1385,23 +1424,17 @@ theory::LemmaStatus TheoryEngine::lemma(TNode node, bool negated, bool removable
}
// assert to prop engine
- d_propEngine->assertLemma(additionalLemmas[0], negated, removable);
+ d_propEngine->assertLemma(additionalLemmas[0], negated, removable, RULE_INVALID, node);
for (unsigned i = 1; i < additionalLemmas.size(); ++ i) {
additionalLemmas[i] = theory::Rewriter::rewrite(additionalLemmas[i]);
- d_propEngine->assertLemma(additionalLemmas[i], false, removable);
+ d_propEngine->assertLemma(additionalLemmas[i], false, removable, RULE_INVALID, node);
}
// WARNING: Below this point don't assume additionalLemmas[0] to be not negated.
- // WARNING: Below this point don't assume additionalLemmas[0] to be not negated.
if(negated) {
- // Can't we just get rid of passing around this 'negated' stuff?
- // Is it that hard for the propEngine to figure that out itself?
- // (I like the use of triple negation <evil laugh>.) --K
additionalLemmas[0] = additionalLemmas[0].notNode();
negated = false;
}
- // WARNING: Below this point don't assume additionalLemmas[0] to be not negated.
- // WARNING: Below this point don't assume additionalLemmas[0] to be not negated.
// assert to decision engine
if(!removable) {
@@ -1668,11 +1701,11 @@ void TheoryEngine::ppUnconstrainedSimp(vector<Node>& assertions)
}
-void TheoryEngine::setUserAttribute(const std::string& attr, Node n) {
+void TheoryEngine::setUserAttribute(const std::string& attr, Node n, std::vector<Node> node_values, std::string str_value) {
Trace("te-attr") << "set user attribute " << attr << " " << n << endl;
if( d_attr_handle.find( attr )!=d_attr_handle.end() ){
for( size_t i=0; i<d_attr_handle[attr].size(); i++ ){
- d_attr_handle[attr][i]->setUserAttribute(attr, n);
+ d_attr_handle[attr][i]->setUserAttribute(attr, n, node_values, str_value);
}
} else {
//unhandled exception?
diff --git a/src/theory/theory_engine.h b/src/theory/theory_engine.h
index e6684d56e..e589e8f87 100644
--- a/src/theory/theory_engine.h
+++ b/src/theory/theory_engine.h
@@ -759,6 +759,11 @@ public:
Node getModelValue(TNode var);
/**
+ * Takes a literal and returns an equivalent literal that is guaranteed to be a SAT literal
+ */
+ Node ensureLiteral(TNode n);
+
+ /**
* Print all instantiations made by the quantifiers module.
*/
void printInstantiations( std::ostream& out );
@@ -820,7 +825,7 @@ public:
* This function is called when an attribute is set by a user. In SMT-LIBv2 this is done
* via the syntax (! n :attr)
*/
- void setUserAttribute(const std::string& attr, Node n);
+ void setUserAttribute(const std::string& attr, Node n, std::vector<Node> node_values, std::string str_value);
/**
* Handle user attribute.
diff --git a/src/theory/uf/options b/src/theory/uf/options
index 26f87da79..d9e4c9477 100644
--- a/src/theory/uf/options
+++ b/src/theory/uf/options
@@ -29,8 +29,8 @@ option ufssSimpleCliques --uf-ss-simple-cliques bool :default true
always use simple clique lemmas for uf strong solver
option ufssDiseqPropagation --uf-ss-deq-prop bool :default false
eagerly propagate disequalities for uf strong solver
-option ufssMinimalModel /--disable-uf-ss-min-model bool :default true
- disable finding a minimal model in uf strong solver
+option ufssMode --uf-ss=MODE CVC4::theory::uf::UfssMode :default CVC4::theory::uf::UF_SS_FULL :include "theory/uf/options_handlers.h" :handler CVC4::theory::uf::stringToUfssMode :handler-include "theory/uf/options_handlers.h"
+ mode of operation for uf strong solver.
option ufssCliqueSplits --uf-ss-clique-splits bool :default false
use cliques instead of splitting on demand to shrink model
diff --git a/src/theory/uf/options_handlers.h b/src/theory/uf/options_handlers.h
index a885a10d2..8c072e232 100644
--- a/src/theory/uf/options_handlers.h
+++ b/src/theory/uf/options_handlers.h
@@ -2,7 +2,7 @@
/*! \file options_handlers.h
** \verbatim
** Original author: Morgan Deters
- ** Major contributors: none
+ ** Major contributors: Andrew Reynolds
** Minor contributors (to current version): none
** This file is part of the CVC4 project.
** Copyright (c) 2009-2014 New York University and The University of Iowa
@@ -22,6 +22,45 @@
namespace CVC4 {
namespace theory {
namespace uf {
+
+typedef enum {
+ /** default, use uf strong solver to find minimal models for uninterpreted sorts */
+ UF_SS_FULL,
+ /** use uf strong solver to shrink model sizes, but do no enforce minimality */
+ UF_SS_NO_MINIMAL,
+ /** do not use uf strong solver */
+ UF_SS_NONE,
+} UfssMode;
+
+static const std::string ufssModeHelp = "\
+UF strong solver options currently supported by the --uf-ss option:\n\
+\n\
+full \n\
++ Default, use uf strong solver to find minimal models for uninterpreted sorts.\n\
+\n\
+no-minimal \n\
++ Use uf strong solver to shrink model sizes, but do no enforce minimality.\n\
+\n\
+none \n\
++ Do not use uf strong solver to shrink model sizes. \n\
+\n\
+";
+
+inline UfssMode stringToUfssMode(std::string option, std::string optarg, SmtEngine* smt) throw(OptionException) {
+ if(optarg == "default" || optarg == "full" ) {
+ return UF_SS_FULL;
+ } else if(optarg == "no-minimal") {
+ return UF_SS_NO_MINIMAL;
+ } else if(optarg == "none") {
+ return UF_SS_NONE;
+ } else if(optarg == "help") {
+ puts(ufssModeHelp.c_str());
+ exit(1);
+ } else {
+ throw OptionException(std::string("unknown option for --uf-ss: `") +
+ optarg + "'. Try --uf-ss help.");
+ }
+}
}/* CVC4::theory::uf namespace */
}/* CVC4::theory namespace */
diff --git a/src/theory/uf/theory_uf.cpp b/src/theory/uf/theory_uf.cpp
index 0da8e8c32..2b9fc3daf 100644
--- a/src/theory/uf/theory_uf.cpp
+++ b/src/theory/uf/theory_uf.cpp
@@ -61,7 +61,7 @@ void TheoryUF::setMasterEqualityEngine(eq::EqualityEngine* eq) {
void TheoryUF::finishInit() {
// initialize the strong solver
- if (options::finiteModelFind()) {
+ if (options::finiteModelFind() && options::ufssMode()!=UF_SS_NONE) {
d_thss = new StrongSolverTheoryUF(getSatContext(), getUserContext(), *d_out, this);
}
}
@@ -89,6 +89,10 @@ static Node mkAnd(const std::vector<TNode>& conjunctions) {
}/* mkAnd() */
void TheoryUF::check(Effort level) {
+ if (done() && !fullEffort(level)) {
+ return;
+ }
+
while (!done() && !d_conflict)
{
// Get all the assertions
diff --git a/src/theory/uf/theory_uf_strong_solver.cpp b/src/theory/uf/theory_uf_strong_solver.cpp
index 001b21d0a..cddaace3e 100644
--- a/src/theory/uf/theory_uf_strong_solver.cpp
+++ b/src/theory/uf/theory_uf_strong_solver.cpp
@@ -339,16 +339,6 @@ bool StrongSolverTheoryUF::SortModel::Region::getCandidateClique( int cardinalit
return false;
}
-
-void StrongSolverTheoryUF::SortModel::Region::getRepresentatives( std::vector< Node >& reps ){
- for( std::map< Node, RegionNodeInfo* >::iterator it = d_nodes.begin(); it != d_nodes.end(); ++it ){
- RegionNodeInfo* rni = it->second;
- if( rni->d_valid ){
- reps.push_back( it->first );
- }
- }
-}
-
void StrongSolverTheoryUF::SortModel::Region::getNumExternalDisequalities( std::map< Node, int >& num_ext_disequalities ){
for( std::map< Node, RegionNodeInfo* >::iterator it = d_nodes.begin(); it != d_nodes.end(); ++it ){
RegionNodeInfo* rni = it->second;
@@ -624,7 +614,7 @@ void StrongSolverTheoryUF::SortModel::check( Theory::Effort level, OutputChannel
if( d_regions[i]->d_valid ){
std::vector< Node > clique;
if( d_regions[i]->check( level, d_cardinality, clique ) ){
- if( options::ufssMinimalModel() ){
+ if( options::ufssMode()==UF_SS_FULL ){
//add clique lemma
addCliqueLemma( clique, out );
return;
@@ -695,7 +685,7 @@ void StrongSolverTheoryUF::SortModel::check( Theory::Effort level, OutputChannel
if( d_regions[i]->d_valid ){
int fcr = forceCombineRegion( i, false );
Trace("uf-ss-debug") << "Combined regions " << i << " " << fcr << std::endl;
- if( options::ufssMinimalModel() || fcr!=-1 ){
+ if( options::ufssMode()==UF_SS_FULL || fcr!=-1 ){
recheck = true;
break;
}
@@ -921,7 +911,7 @@ void StrongSolverTheoryUF::SortModel::checkRegion( int ri, bool checkCombine ){
//now check if region is in conflict
std::vector< Node > clique;
if( d_regions[ri]->check( Theory::EFFORT_STANDARD, d_cardinality, clique ) ){
- if( options::ufssMinimalModel() ){
+ if( options::ufssMode()==UF_SS_FULL ){
//explain clique
addCliqueLemma( clique, &d_thss->getOutputChannel() );
}
@@ -1085,7 +1075,7 @@ int StrongSolverTheoryUF::SortModel::addSplit( Region* r, OutputChannel* out ){
}
Assert( s!=Node::null() );
}else{
- if( !options::ufssMinimalModel() ){
+ if( options::ufssMode()!=UF_SS_FULL ){
//since candidate clique is not reported, we may need to find splits manually
for ( std::map< Node, Region::RegionNodeInfo* >::iterator it = r->d_nodes.begin(); it != r->d_nodes.end(); ++it ){
if ( it->second->d_valid ){
@@ -1480,19 +1470,6 @@ int StrongSolverTheoryUF::SortModel::getNumRegions(){
return count;
}
-void StrongSolverTheoryUF::SortModel::getRepresentatives( std::vector< Node >& reps ){
- for( int i=0; i<(int)d_regions_index; i++ ){
- //should not have multiple regions at this point
- //if( foundRegion ){
- // Assert( !d_regions[i]->d_valid );
- //}
- if( d_regions[i]->d_valid ){
- //this is the only valid region
- d_regions[i]->getRepresentatives( reps );
- }
- }
-}
-
Node StrongSolverTheoryUF::SortModel::getCardinalityLiteral( int c ) {
if( d_cardinality_literal.find( c )==d_cardinality_literal.end() ){
d_cardinality_literal[c] = NodeManager::currentNM()->mkNode( CARDINALITY_CONSTRAINT, d_cardinality_term,
@@ -1661,7 +1638,7 @@ bool StrongSolverTheoryUF::areDisequal( Node a, Node b ) {
void StrongSolverTheoryUF::check( Theory::Effort level ){
if( !d_conflict ){
Trace("uf-ss-solver") << "StrongSolverTheoryUF: check " << level << std::endl;
- if( level==Theory::EFFORT_FULL ){
+ if( level==Theory::EFFORT_FULL && Debug.isOn( "uf-ss-debug" ) ){
debugPrint( "uf-ss-debug" );
}
for( std::map< TypeNode, SortModel* >::iterator it = d_rep_model.begin(); it != d_rep_model.end(); ++it ){
@@ -1801,19 +1778,6 @@ int StrongSolverTheoryUF::getCardinality( TypeNode tn ) {
return -1;
}
-/*
-void StrongSolverTheoryUF::getRepresentatives( Node n, std::vector< Node >& reps ){
- SortModel* c = getSortModel( n );
- if( c ){
- c->getRepresentatives( reps );
- if( (int)reps.size()!=c->getCardinality() ){
- Trace("uf-ss-warn") << "Sort " << n.getType() << " has cardinality " << c->getCardinality();
- Trace("uf-ss-warn") << ", but provided " << reps.size() << " representatives!!!" << std::endl;
- }
- }
-}
-*/
-
bool StrongSolverTheoryUF::minimize( TheoryModel* m ){
for( std::map< TypeNode, SortModel* >::iterator it = d_rep_model.begin(); it != d_rep_model.end(); ++it ){
if( !it->second->minimize( d_out, m ) ){
diff --git a/src/theory/uf/theory_uf_strong_solver.h b/src/theory/uf/theory_uf_strong_solver.h
index 1e5a361a7..333f1717e 100644
--- a/src/theory/uf/theory_uf_strong_solver.h
+++ b/src/theory/uf/theory_uf_strong_solver.h
@@ -146,8 +146,6 @@ public:
bool getMustCombine( int cardinality );
/** has splits */
bool hasSplits() { return d_splitsSize>0; }
- /** get representatives */
- void getRepresentatives( std::vector< Node >& reps );
/** get external disequalities */
void getNumExternalDisequalities( std::map< Node, int >& num_ext_disequalities );
public:
@@ -280,8 +278,6 @@ public:
bool isConflict() { return d_conflict; }
/** get cardinality */
int getCardinality() { return d_cardinality; }
- /** get representatives */
- void getRepresentatives( std::vector< Node >& reps );
/** has cardinality */
bool hasCardinalityAsserted() { return d_hasCard; }
/** get cardinality term */
@@ -381,8 +377,6 @@ public:
int getCardinality( Node n );
/** get cardinality for type */
int getCardinality( TypeNode tn );
- /** get representatives */
- //void getRepresentatives( Node n, std::vector< Node >& reps );
/** minimize */
bool minimize( TheoryModel* m = NULL );
diff --git a/src/theory/valuation.cpp b/src/theory/valuation.cpp
index 72d878782..b2d7f4b21 100644
--- a/src/theory/valuation.cpp
+++ b/src/theory/valuation.cpp
@@ -88,13 +88,7 @@ Node Valuation::getModelValue(TNode var) {
}
Node Valuation::ensureLiteral(TNode n) {
- Debug("ensureLiteral") << "rewriting: " << n << std::endl;
- Node rewritten = Rewriter::rewrite(n);
- Debug("ensureLiteral") << " got: " << rewritten << std::endl;
- Node preprocessed = d_engine->preprocess(rewritten);
- Debug("ensureLiteral") << "preproced: " << preprocessed << std::endl;
- d_engine->getPropEngine()->ensureLiteral(preprocessed);
- return preprocessed;
+ return d_engine->ensureLiteral(n);
}
bool Valuation::isDecision(Node lit) const {
diff --git a/src/util/Makefile.am b/src/util/Makefile.am
index 5cf5da1e0..fc9192dd9 100644
--- a/src/util/Makefile.am
+++ b/src/util/Makefile.am
@@ -97,7 +97,9 @@ libutil_la_SOURCES = \
regexp.cpp \
bin_heap.h \
didyoumean.h \
- didyoumean.cpp
+ didyoumean.cpp \
+ unsat_core.h \
+ unsat_core.cpp
libstatistics_la_SOURCES = \
statistics_registry.h \
@@ -156,7 +158,8 @@ EXTRA_DIST = \
uninterpreted_constant.i \
chain.i \
regexp.i \
- proof.i
+ proof.i \
+ unsat_core.i
DISTCLEANFILES = \
integer.h.tmp \
diff --git a/src/util/datatype.cpp b/src/util/datatype.cpp
index 9e07c746a..f0704520a 100644
--- a/src/util/datatype.cpp
+++ b/src/util/datatype.cpp
@@ -299,8 +299,12 @@ Expr Datatype::mkGroundTerm( Type t ) const throw(IllegalArgumentException) {
}
}
if( groundTerm.isNull() ){
- // if we get all the way here, we aren't well-founded
- CheckArgument(false, *this, "this datatype is not well-founded, cannot construct a ground term!");
+ if( !d_isCo ){
+ // if we get all the way here, we aren't well-founded
+ CheckArgument(false, *this, "this datatype is not well-founded, cannot construct a ground term!");
+ }else{
+ return groundTerm;
+ }
}else{
return groundTerm;
}
diff --git a/src/util/ite_removal.cpp b/src/util/ite_removal.cpp
index 68d7d9a34..97a6338ce 100644
--- a/src/util/ite_removal.cpp
+++ b/src/util/ite_removal.cpp
@@ -19,6 +19,7 @@
#include "util/ite_removal.h"
#include "expr/command.h"
#include "theory/ite_utilities.h"
+#include "proof/proof_manager.h"
using namespace CVC4;
using namespace std;
@@ -47,13 +48,23 @@ size_t RemoveITE::collectedCacheSizes() const{
return d_containsVisitor->cache_size() + d_iteCache.size();
}
-void RemoveITE::run(std::vector<Node>& output, IteSkolemMap& iteSkolemMap)
+void RemoveITE::run(std::vector<Node>& output, IteSkolemMap& iteSkolemMap, bool reportDeps)
{
+ size_t n = output.size();
for (unsigned i = 0, i_end = output.size(); i < i_end; ++ i) {
// Do this in two steps to avoid Node problems(?)
// Appears related to bug 512, splitting this into two lines
// fixes the bug on clang on Mac OS
Node itesRemoved = run(output[i], output, iteSkolemMap, false);
+ // In some calling contexts, not necessary to report dependence information.
+ if(reportDeps && options::unsatCores()) {
+ // new assertions have a dependence on the node
+ PROOF( ProofManager::currentPM()->addDependence(itesRemoved, output[i]); )
+ while(n < output.size()) {
+ PROOF( ProofManager::currentPM()->addDependence(output[n], output[i]); )
+ ++n;
+ }
+ }
output[i] = itesRemoved;
}
}
diff --git a/src/util/ite_removal.h b/src/util/ite_removal.h
index 83c55dab7..d71f9b13d 100644
--- a/src/util/ite_removal.h
+++ b/src/util/ite_removal.h
@@ -50,8 +50,11 @@ public:
* contains a map from introduced skolem variables to the index in
* assertions containing the new Boolean ite created in conjunction
* with that skolem variable.
+ *
+ * With reportDeps true, report reasoning dependences to the proof
+ * manager (for unsat cores).
*/
- void run(std::vector<Node>& assertions, IteSkolemMap& iteSkolemMap);
+ void run(std::vector<Node>& assertions, IteSkolemMap& iteSkolemMap, bool reportDeps = false);
/**
* Removes the ITE from the node by introducing skolem
diff --git a/src/util/unsat_core.cpp b/src/util/unsat_core.cpp
new file mode 100644
index 000000000..929d5e909
--- /dev/null
+++ b/src/util/unsat_core.cpp
@@ -0,0 +1,49 @@
+/********************* */
+/*! \file unsat_core.cpp
+ ** \verbatim
+ ** Original author: Morgan Deters
+ ** Major contributors: none
+ ** Minor contributors (to current version): none
+ ** This file is part of the CVC4 project.
+ ** Copyright (c) 2009-2014 New York University and The University of Iowa
+ ** See the file COPYING in the top-level source directory for licensing
+ ** information.\endverbatim
+ **
+ ** \brief Representation of unsat cores
+ **
+ ** Representation of unsat cores.
+ **/
+
+#include "util/unsat_core.h"
+#include "expr/command.h"
+#include "smt/smt_engine_scope.h"
+#include "printer/printer.h"
+
+namespace CVC4 {
+
+UnsatCore::const_iterator UnsatCore::begin() const {
+ return d_core.begin();
+}
+
+UnsatCore::const_iterator UnsatCore::end() const {
+ return d_core.end();
+}
+
+void UnsatCore::toStream(std::ostream& out) const {
+ smt::SmtScope smts(d_smt);
+ Expr::dag::Scope scope(out, false);
+ Printer::getPrinter(options::outputLanguage())->toStream(out, *this);
+}
+
+void UnsatCore::toStream(std::ostream& out, const std::map<Expr, std::string>& names) const {
+ smt::SmtScope smts(d_smt);
+ Expr::dag::Scope scope(out, false);
+ Printer::getPrinter(options::outputLanguage())->toStream(out, *this, names);
+}
+
+std::ostream& operator<<(std::ostream& out, const UnsatCore& core) {
+ core.toStream(out);
+ return out;
+}
+
+}/* CVC4 namespace */
diff --git a/src/util/unsat_core.h b/src/util/unsat_core.h
new file mode 100644
index 000000000..27cf86488
--- /dev/null
+++ b/src/util/unsat_core.h
@@ -0,0 +1,66 @@
+/********************* */
+/*! \file unsat_core.h
+ ** \verbatim
+ ** Original author: Morgan Deters
+ ** Major contributors: none
+ ** Minor contributors (to current version): none
+ ** This file is part of the CVC4 project.
+ ** Copyright (c) 2009-2014 New York University and The University of Iowa
+ ** See the file COPYING in the top-level source directory for licensing
+ ** information.\endverbatim
+ **
+ ** \brief [[ Add one-line brief description here ]]
+ **
+ ** [[ Add lengthier description here ]]
+ ** \todo document this file
+ **/
+
+#include "cvc4_public.h"
+
+#ifndef __CVC4__UNSAT_CORE_H
+#define __CVC4__UNSAT_CORE_H
+
+#include <iostream>
+#include <vector>
+#include "expr/expr.h"
+
+namespace CVC4 {
+
+class SmtEngine;
+class UnsatCore;
+
+std::ostream& operator<<(std::ostream& out, const UnsatCore& core) CVC4_PUBLIC;
+
+class CVC4_PUBLIC UnsatCore {
+ friend std::ostream& operator<<(std::ostream&, const UnsatCore&);
+
+ /** The SmtEngine we're associated with */
+ SmtEngine* d_smt;
+
+ std::vector<Expr> d_core;
+
+public:
+ UnsatCore() : d_smt(NULL) {}
+
+ template <class T>
+ UnsatCore(SmtEngine* smt, T begin, T end) : d_smt(smt), d_core(begin, end) {}
+
+ ~UnsatCore() {}
+
+ /** get the smt engine that this unsat core is hooked up to */
+ SmtEngine* getSmtEngine() { return d_smt; }
+
+ typedef std::vector<Expr>::const_iterator iterator;
+ typedef std::vector<Expr>::const_iterator const_iterator;
+
+ const_iterator begin() const;
+ const_iterator end() const;
+
+ void toStream(std::ostream& out) const;
+ void toStream(std::ostream& out, const std::map<Expr, std::string>& names) const;
+
+};/* class UnsatCore */
+
+}/* CVC4 namespace */
+
+#endif /* __CVC4__UNSAT_CORE_H */
diff --git a/src/util/unsat_core.i b/src/util/unsat_core.i
new file mode 100644
index 000000000..9fc0dcda6
--- /dev/null
+++ b/src/util/unsat_core.i
@@ -0,0 +1,51 @@
+%{
+#include "util/unsat_core.h"
+%}
+
+#ifdef SWIGJAVA
+
+// Instead of UnsatCore::begin() and end(), create an
+// iterator() method on the Java side that returns a Java-style
+// Iterator.
+%ignore CVC4::UnsatCore::begin();
+%ignore CVC4::UnsatCore::end();
+%ignore CVC4::UnsatCore::begin() const;
+%ignore CVC4::UnsatCore::end() const;
+%extend CVC4::UnsatCore {
+ CVC4::JavaIteratorAdapter<CVC4::UnsatCore> iterator() {
+ return CVC4::JavaIteratorAdapter<CVC4::UnsatCore>(*$self);
+ }
+}
+
+// UnsatCore is "iterable" on the Java side
+%typemap(javainterfaces) CVC4::UnsatCore "java.lang.Iterable<edu.nyu.acsys.CVC4.Expr>";
+
+// the JavaIteratorAdapter should not be public, and implements Iterator
+%typemap(javaclassmodifiers) CVC4::JavaIteratorAdapter<CVC4::UnsatCore> "class";
+%typemap(javainterfaces) CVC4::JavaIteratorAdapter<CVC4::UnsatCore> "java.util.Iterator<edu.nyu.acsys.CVC4.Expr>";
+// add some functions to the Java side (do it here because there's no way to do these in C++)
+%typemap(javacode) CVC4::JavaIteratorAdapter<CVC4::UnsatCore> "
+ public void remove() {
+ throw new java.lang.UnsupportedOperationException();
+ }
+
+ public edu.nyu.acsys.CVC4.Expr next() {
+ if(hasNext()) {
+ return getNext();
+ } else {
+ throw new java.util.NoSuchElementException();
+ }
+ }
+"
+// getNext() just allows C++ iterator access from Java-side next(), make it private
+%javamethodmodifiers CVC4::JavaIteratorAdapter<CVC4::UnsatCore>::getNext() "private";
+
+// map the types appropriately
+%typemap(jni) CVC4::UnsatCore::const_iterator::value_type "jobject";
+%typemap(jtype) CVC4::UnsatCore::const_iterator::value_type "edu.nyu.acsys.CVC4.Expr";
+%typemap(jstype) CVC4::UnsatCore::const_iterator::value_type "edu.nyu.acsys.CVC4.Expr";
+%typemap(javaout) CVC4::UnsatCore::const_iterator::value_type { return $jnicall; }
+
+#endif /* SWIGJAVA */
+
+%include "util/unsat_core.h"
generated by cgit on debian on lair
contact matthew@masot.net with questions or feedback