summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorMorgan Deters <mdeters@gmail.com>2012-06-11 16:28:23 +0000
committerMorgan Deters <mdeters@gmail.com>2012-06-11 16:28:23 +0000
commit3378e253fcdb34c753407bb16d08929da06b3aaa (patch)
treedb7c7118dd0d1594175b56866f845b42426ae0a7 /src
parent42794501e81c44dce5c2f7687af288af030ef63e (diff)
Merge from quantifiers2-trunkmerge branch.
Adds TheoryQuantifiers and TheoryRewriteRules, QuantifiersEngine, and other infrastructure. Adds theory instantiators to many theories. Adds the UF strong solver.
Diffstat (limited to 'src')
-rw-r--r--src/bindings/compat/java/src/cvc3/Embedded.java2
-rw-r--r--src/bindings/compat/java/src/cvc3/Expr_impl.cpp2
-rw-r--r--src/context/cdhashmap.h4
-rw-r--r--src/expr/kind_template.h2
-rwxr-xr-xsrc/expr/mkexpr10
-rwxr-xr-xsrc/expr/mkkind10
-rwxr-xr-xsrc/expr/mkmetakind10
-rw-r--r--src/expr/node.h40
-rw-r--r--src/expr/node_manager.h34
-rw-r--r--src/parser/cvc/Cvc.g57
-rw-r--r--src/parser/smt/Smt.g13
-rw-r--r--src/parser/smt/smt.cpp62
-rw-r--r--src/parser/smt/smt.h4
-rw-r--r--src/parser/smt2/Smt2.g195
-rw-r--r--src/parser/smt2/smt2.cpp24
-rw-r--r--src/parser/smt2/smt2.h1
-rw-r--r--src/printer/cvc/cvc_printer.cpp53
-rw-r--r--src/printer/smt2/smt2_printer.cpp26
-rw-r--r--src/prop/minisat/core/Solver.cc45
-rw-r--r--src/prop/minisat/core/Solver.h32
-rw-r--r--src/prop/minisat/minisat.cpp16
-rw-r--r--src/prop/minisat/minisat.h6
-rw-r--r--src/prop/prop_engine.cpp18
-rw-r--r--src/prop/prop_engine.h31
-rw-r--r--src/prop/sat_solver.h6
-rw-r--r--src/theory/Makefile.am30
-rw-r--r--src/theory/arith/Makefile.am4
-rw-r--r--src/theory/arith/congruence_manager.h7
-rw-r--r--src/theory/arith/kinds1
-rw-r--r--src/theory/arith/theory_arith.cpp4
-rw-r--r--src/theory/arith/theory_arith.h5
-rw-r--r--src/theory/arith/theory_arith_instantiator.cpp448
-rw-r--r--src/theory/arith/theory_arith_instantiator.h128
-rw-r--r--src/theory/arrays/Makefile.am4
-rw-r--r--src/theory/arrays/kinds1
-rw-r--r--src/theory/arrays/theory_arrays.cpp9
-rw-r--r--src/theory/arrays/theory_arrays.h42
-rw-r--r--src/theory/arrays/theory_arrays_instantiator.cpp56
-rw-r--r--src/theory/arrays/theory_arrays_instantiator.h51
-rw-r--r--src/theory/booleans/theory_bool.h4
-rw-r--r--src/theory/builtin/theory_builtin.h4
-rw-r--r--src/theory/bv/bv_subtheory_eq.h4
-rw-r--r--src/theory/bv/theory_bv.cpp4
-rw-r--r--src/theory/bv/theory_bv.h20
-rw-r--r--src/theory/datatypes/Makefile.am4
-rw-r--r--src/theory/datatypes/kinds1
-rw-r--r--src/theory/datatypes/theory_datatypes.cpp12
-rw-r--r--src/theory/datatypes/theory_datatypes.h13
-rw-r--r--src/theory/datatypes/theory_datatypes_instantiator.cpp158
-rw-r--r--src/theory/datatypes/theory_datatypes_instantiator.h64
-rw-r--r--src/theory/example/theory_uf_tim.cpp4
-rw-r--r--src/theory/example/theory_uf_tim.h2
-rw-r--r--src/theory/inst_match.cpp903
-rw-r--r--src/theory/inst_match.h443
-rw-r--r--src/theory/inst_match_impl.h125
-rw-r--r--src/theory/instantiator_default.cpp54
-rw-r--r--src/theory/instantiator_default.h48
-rw-r--r--src/theory/instantiator_tables_template.cpp40
-rwxr-xr-xsrc/theory/mkinstantiator242
-rwxr-xr-xsrc/theory/mkrewriter10
-rwxr-xr-xsrc/theory/mktheorytraits20
-rw-r--r--src/theory/output_channel.h58
-rw-r--r--src/theory/quantifiers/Makefile4
-rw-r--r--src/theory/quantifiers/Makefile.am21
-rw-r--r--src/theory/quantifiers/instantiation_engine.cpp393
-rw-r--r--src/theory/quantifiers/instantiation_engine.h79
-rw-r--r--src/theory/quantifiers/kinds48
-rw-r--r--src/theory/quantifiers/model_engine.cpp1401
-rw-r--r--src/theory/quantifiers/model_engine.h369
-rw-r--r--src/theory/quantifiers/quantifiers_rewriter.cpp722
-rw-r--r--src/theory/quantifiers/quantifiers_rewriter.h88
-rw-r--r--src/theory/quantifiers/theory_quantifiers.cpp199
-rw-r--r--src/theory/quantifiers/theory_quantifiers.h77
-rw-r--r--src/theory/quantifiers/theory_quantifiers_instantiator.cpp76
-rw-r--r--src/theory/quantifiers/theory_quantifiers_instantiator.h60
-rw-r--r--src/theory/quantifiers/theory_quantifiers_type_rules.h113
-rw-r--r--src/theory/quantifiers_engine.cpp788
-rw-r--r--src/theory/quantifiers_engine.h388
-rw-r--r--src/theory/rewriterules/Makefile4
-rw-r--r--src/theory/rewriterules/Makefile.am19
-rw-r--r--src/theory/rewriterules/README.WHATS-NEXT29
-rw-r--r--src/theory/rewriterules/kinds37
-rw-r--r--src/theory/rewriterules/theory_rewriterules.cpp519
-rw-r--r--src/theory/rewriterules/theory_rewriterules.h264
-rw-r--r--src/theory/rewriterules/theory_rewriterules_params.h95
-rw-r--r--src/theory/rewriterules/theory_rewriterules_preprocess.h176
-rw-r--r--src/theory/rewriterules/theory_rewriterules_rewriter.h104
-rw-r--r--src/theory/rewriterules/theory_rewriterules_rules.cpp303
-rw-r--r--src/theory/rewriterules/theory_rewriterules_rules.h40
-rw-r--r--src/theory/rewriterules/theory_rewriterules_type_rules.h98
-rw-r--r--src/theory/shared_terms_database.cpp18
-rw-r--r--src/theory/shared_terms_database.h21
-rw-r--r--src/theory/term_registration_visitor.cpp39
-rw-r--r--src/theory/theory.cpp114
-rw-r--r--src/theory/theory.h185
-rw-r--r--src/theory/theory_engine.cpp50
-rw-r--r--src/theory/theory_engine.h48
-rw-r--r--src/theory/theory_test_utils.h7
-rw-r--r--src/theory/trigger.cpp555
-rw-r--r--src/theory/trigger.h170
-rw-r--r--src/theory/uf/Makefile.am10
-rw-r--r--src/theory/uf/equality_engine.cpp34
-rw-r--r--src/theory/uf/equality_engine.h165
-rw-r--r--src/theory/uf/inst_strategy.cpp412
-rw-r--r--src/theory/uf/inst_strategy.h179
-rw-r--r--src/theory/uf/kinds5
-rw-r--r--src/theory/uf/symmetry_breaker.cpp10
-rw-r--r--src/theory/uf/theory_uf.cpp88
-rw-r--r--src/theory/uf/theory_uf.h89
-rw-r--r--src/theory/uf/theory_uf_candidate_generator.cpp170
-rw-r--r--src/theory/uf/theory_uf_candidate_generator.h115
-rw-r--r--src/theory/uf/theory_uf_instantiator.cpp520
-rw-r--r--src/theory/uf/theory_uf_instantiator.h201
-rw-r--r--src/theory/uf/theory_uf_strong_solver.cpp1267
-rw-r--r--src/theory/uf/theory_uf_strong_solver.h322
-rw-r--r--src/theory/uf/theory_uf_type_rules.h14
-rw-r--r--src/theory/valuation.cpp4
-rw-r--r--src/theory/valuation.h8
-rw-r--r--src/util/datatype.cpp2
-rw-r--r--src/util/datatype.h6
-rw-r--r--src/util/ite_removal.cpp39
-rw-r--r--src/util/options.cpp176
-rw-r--r--src/util/options.h120
123 files changed, 15107 insertions, 300 deletions
diff --git a/src/bindings/compat/java/src/cvc3/Embedded.java b/src/bindings/compat/java/src/cvc3/Embedded.java
index fdeeef058..c645f2655 100644
--- a/src/bindings/compat/java/src/cvc3/Embedded.java
+++ b/src/bindings/compat/java/src/cvc3/Embedded.java
@@ -12,8 +12,6 @@ public abstract class Embedded {
// load jni c++ library
static {
- System.loadLibrary("cvc4");
- System.loadLibrary("cvc4parser");
System.loadLibrary("cvc4bindings_java_compat");
/*
diff --git a/src/bindings/compat/java/src/cvc3/Expr_impl.cpp b/src/bindings/compat/java/src/cvc3/Expr_impl.cpp
index f002109c5..41e96f53e 100644
--- a/src/bindings/compat/java/src/cvc3/Expr_impl.cpp
+++ b/src/bindings/compat/java/src/cvc3/Expr_impl.cpp
@@ -282,7 +282,7 @@ return expr->arity();
DEFINITION: Java_cvc3_Expr_jniGetKid
jobject c Expr expr n int i
-return embed_copy<Expr>(env, (*expr)[ji]);
+return embed_copy<Expr>(env, &((*expr)[ji]));
DEFINITION: Java_cvc3_Expr_jniGetKids
jobjectArray c Expr expr
diff --git a/src/context/cdhashmap.h b/src/context/cdhashmap.h
index de21515c7..321a378bd 100644
--- a/src/context/cdhashmap.h
+++ b/src/context/cdhashmap.h
@@ -1,11 +1,11 @@
/********************* */
-/*! \file cdmap.h
+/*! \file cdhashmap.h
** \verbatim
** Original author: mdeters
** Major contributors: none
** Minor contributors (to current version): taking, dejan
** This file is part of the CVC4 prototype.
- ** Copyright (c) 2009, 2010, 2011 The Analysis of Computer Systems Group (ACSys)
+ ** Copyright (c) 2009-2012 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
diff --git a/src/expr/kind_template.h b/src/expr/kind_template.h
index 74641513b..6313aa30b 100644
--- a/src/expr/kind_template.h
+++ b/src/expr/kind_template.h
@@ -124,8 +124,6 @@ namespace theory {
enum TheoryId {
${theory_enum}
- THEORY_QUANTIFIERS,
- THEORY_REWRITERULES,
THEORY_LAST
};
diff --git a/src/expr/mkexpr b/src/expr/mkexpr
index 0cae68ed0..e113a1e8f 100755
--- a/src/expr/mkexpr
+++ b/src/expr/mkexpr
@@ -2,7 +2,7 @@
#
# mkexpr
# Morgan Deters <mdeters@cs.nyu.edu> for CVC4
-# Copyright (c) 2010-2011 The CVC4 Project
+# Copyright (c) 2010-2012 The CVC4 Project
#
# The purpose of this script is to create {expr,expr_manager}.{h,cpp}
# from template files and a list of theory kinds. Basically it just
@@ -15,7 +15,7 @@
# Output is to standard out.
#
-copyright=2010-2011
+copyright=2010-2012
filename=`basename "$1" | sed 's,_template,,'`
@@ -95,6 +95,12 @@ function rewriter {
check_theory_seen
}
+function instantiator {
+ # instantiator class header
+ lineno=${BASH_LINENO[0]}
+ check_theory_seen
+}
+
function properties {
# properties prop*
lineno=${BASH_LINENO[0]}
diff --git a/src/expr/mkkind b/src/expr/mkkind
index abb238f1a..2f361cb63 100755
--- a/src/expr/mkkind
+++ b/src/expr/mkkind
@@ -2,7 +2,7 @@
#
# mkkind
# Morgan Deters <mdeters@cs.nyu.edu> for CVC4
-# Copyright (c) 2010-2011 The CVC4 Project
+# Copyright (c) 2010-2012 The CVC4 Project
#
# The purpose of this script is to create kind.h (and also
# type_properties.h) from a template and a list of theory kinds.
@@ -14,7 +14,7 @@
# Output is to standard out.
#
-copyright=2010-2011
+copyright=2010-2012
filename=`basename "$1" | sed 's,_template,,'`
@@ -105,6 +105,12 @@ function theory {
"
}
+function instantiator {
+ # instantiator class header
+ lineno=${BASH_LINENO[0]}
+ check_theory_seen
+}
+
function properties {
# rewriter class header
lineno=${BASH_LINENO[0]}
diff --git a/src/expr/mkmetakind b/src/expr/mkmetakind
index d84691e14..2e94e41be 100755
--- a/src/expr/mkmetakind
+++ b/src/expr/mkmetakind
@@ -2,7 +2,7 @@
#
# mkmetakind
# Morgan Deters <mdeters@cs.nyu.edu> for CVC4
-# Copyright (c) 2010-2011 The CVC4 Project
+# Copyright (c) 2010-2012 The CVC4 Project
#
# The purpose of this script is to create metakind.h from a template
# and a list of theory kinds.
@@ -17,7 +17,7 @@
# Output is to standard out.
#
-copyright=2010-2011
+copyright=2010-2012
cat <<EOF
/********************* */
@@ -80,6 +80,12 @@ function theory {
// #include \"theory/$b/$2\""
}
+function instantiator {
+ # instantiator class header
+ lineno=${BASH_LINENO[0]}
+ check_theory_seen
+}
+
function properties {
# properties prop*
lineno=${BASH_LINENO[0]}
diff --git a/src/expr/node.h b/src/expr/node.h
index a61944433..e56774d7e 100644
--- a/src/expr/node.h
+++ b/src/expr/node.h
@@ -159,6 +159,14 @@ namespace kind {
}/* CVC4::kind::metakind namespace */
}/* CVC4::kind namespace */
+// for hash_maps, hash_sets..
+struct NodeHashFunction {
+ inline size_t operator()(Node node) const;
+};/* struct NodeHashFunction */
+struct TNodeHashFunction {
+ inline size_t operator()(TNode node) const;
+};/* struct TNodeHashFunction */
+
/**
* Encapsulation of an NodeValue pointer. The reference count is
* maintained in the NodeValue if ref_count is true.
@@ -166,17 +174,6 @@ namespace kind {
*/
template <bool ref_count>
class NodeTemplate {
-
- // for hash_maps, hash_sets..
- template <bool ref_count1>
- struct HashFunction {
- size_t operator()(CVC4::NodeTemplate<ref_count1> node) const {
- return (size_t) node.getId();
- }
- };/* struct HashFunction */
-
- typedef HashFunction<false> TNodeHashFunction;
-
/**
* The NodeValue has access to the private constructors, so that the
* iterators can can create new nodes.
@@ -233,7 +230,7 @@ class NodeTemplate {
Assert( d_nv->d_rc > 0, "TNode pointing to an expired NodeValue" );
}
}
-
+public:
/**
* Cache-aware, recursive version of substitute() used by the public
* member function with a similar signature.
@@ -904,19 +901,12 @@ inline std::ostream& operator<<(std::ostream& out, TNode n) {
namespace CVC4 {
-// for hash_maps, hash_sets..
-struct NodeHashFunction {
- size_t operator()(CVC4::Node node) const {
- return (size_t) node.getId();
- }
-};/* struct NodeHashFunction */
-
-// for hash_maps, hash_sets..
-struct TNodeHashFunction {
- size_t operator()(CVC4::TNode node) const {
- return (size_t) node.getId();
- }
-};/* struct TNodeHashFunction */
+inline size_t NodeHashFunction::operator()(Node node) const {
+ return node.getId();
+}
+inline size_t TNodeHashFunction::operator()(TNode node) const {
+ return node.getId();
+}
struct TNodePairHashFunction {
size_t operator()(const std::pair<CVC4::TNode, CVC4::TNode>& pair ) const {
diff --git a/src/expr/node_manager.h b/src/expr/node_manager.h
index 00fe6baa8..e763a1f10 100644
--- a/src/expr/node_manager.h
+++ b/src/expr/node_manager.h
@@ -362,6 +362,9 @@ public:
/** Create a skolem constant with the given type. */
Node mkSkolem(const TypeNode& type);
+ /** Create a instantiation constant with the given type. */
+ Node mkInstConstant(const TypeNode& type);
+
/**
* Create a constant of type T. It will have the appropriate
* CONST_* kind defined for T.
@@ -579,6 +582,15 @@ public:
/** Get the (singleton) type for sorts. */
inline TypeNode kindType();
+ /** Get the bound var list type. */
+ inline TypeNode boundVarListType();
+
+ /** Get the instantiation pattern type. */
+ inline TypeNode instPatternType();
+
+ /** Get the instantiation pattern type. */
+ inline TypeNode instPatternListType();
+
/**
* Get the (singleton) type for builtin operators (that is, the type
* of the Node returned from Node::getOperator() when the operator
@@ -897,6 +909,21 @@ inline TypeNode NodeManager::kindType() {
return TypeNode(mkTypeConst<TypeConstant>(KIND_TYPE));
}
+/** Get the bound var list type. */
+inline TypeNode NodeManager::boundVarListType(){
+ return TypeNode(mkTypeConst<TypeConstant>(BOUND_VAR_LIST_TYPE));
+}
+
+/** Get the instantiation pattern type. */
+inline TypeNode NodeManager::instPatternType(){
+ return TypeNode(mkTypeConst<TypeConstant>(INST_PATTERN_TYPE));
+}
+
+/** Get the instantiation pattern type. */
+inline TypeNode NodeManager::instPatternListType(){
+ return TypeNode(mkTypeConst<TypeConstant>(INST_PATTERN_LIST_TYPE));
+}
+
/** Get the (singleton) type for builtin operators. */
inline TypeNode NodeManager::builtinOperatorType() {
return TypeNode(mkTypeConst<TypeConstant>(BUILTIN_OPERATOR_TYPE));
@@ -1366,6 +1393,13 @@ inline Node NodeManager::mkSkolem(const TypeNode& type) {
return n;
}
+inline Node NodeManager::mkInstConstant(const TypeNode& type) {
+ Node n = NodeBuilder<0>(this, kind::INST_CONSTANT);
+ n.setAttribute(TypeAttr(), type);
+ n.setAttribute(TypeCheckedAttr(), true);
+ return n;
+}
+
template <class T>
Node NodeManager::mkConst(const T& val) {
return mkConstInternal<Node, T>(val);
diff --git a/src/parser/cvc/Cvc.g b/src/parser/cvc/Cvc.g
index 1f0e6b890..2988ae4ef 100644
--- a/src/parser/cvc/Cvc.g
+++ b/src/parser/cvc/Cvc.g
@@ -1066,13 +1066,13 @@ restrictedTypePossiblyFunctionLHS[CVC4::Type& t,
PARSER_STATE->isDeclared(id, SYM_SORT)) {
Debug("parser-param") << "param: getSort " << id << " " << types.size() << " " << PARSER_STATE->getArity( id )
<< " " << PARSER_STATE->isDeclared(id, SYM_SORT) << std::endl;
- if( types.size()>0 ){
+ if(types.size() > 0) {
t = PARSER_STATE->getSort(id, types);
}else{
t = PARSER_STATE->getSort(id);
}
} else {
- if( types.empty() ){
+ if(types.empty()) {
t = PARSER_STATE->mkUnresolvedType(id);
Debug("parser-param") << "param: make unres type " << id << std::endl;
}else{
@@ -1236,22 +1236,36 @@ prefixFormula[CVC4::Expr& f]
std::vector<std::string> ids;
std::vector<Expr> terms;
std::vector<Type> types;
+ std::vector<Expr> bvs;
Type t;
+ Kind k;
+ Expr ipl;
}
/* quantifiers */
- : FORALL_TOK { PARSER_STATE->pushScope(); } LPAREN
- boundVarDecl[ids,t] (COMMA boundVarDecl[ids,t])* RPAREN
- COLON instantiationPatterns? formula[f]
- { PARSER_STATE->popScope();
- UNSUPPORTED("quantifiers not supported yet");
- f = EXPR_MANAGER->mkVar(EXPR_MANAGER->booleanType());
+ : ( FORALL_TOK { k = kind::FORALL; } | EXISTS_TOK { k = kind::EXISTS; } )
+ { PARSER_STATE->pushScope(); } LPAREN
+ boundVarDecl[ids,t]
+ { for(std::vector<std::string>::const_iterator i = ids.begin(); i != ids.end(); ++i) {
+ bvs.push_back(PARSER_STATE->mkVar(*i, t));
+ }
+ ids.clear();
}
- | EXISTS_TOK { PARSER_STATE->pushScope(); } LPAREN
- boundVarDecl[ids,t] (COMMA boundVarDecl[ids,t])* RPAREN
- COLON instantiationPatterns? formula[f]
+ ( COMMA boundVarDecl[ids,t]
+ {
+ for(std::vector<std::string>::const_iterator i = ids.begin(); i != ids.end(); ++i) {
+ bvs.push_back(PARSER_STATE->mkVar(*i, t));
+ }
+ ids.clear();
+ }
+ )* RPAREN {
+ terms.push_back( EXPR_MANAGER->mkExpr( kind::BOUND_VAR_LIST, bvs ) ); }
+ COLON instantiationPatterns[ipl]? formula[f]
{ PARSER_STATE->popScope();
- UNSUPPORTED("quantifiers not supported yet");
- f = EXPR_MANAGER->mkVar(EXPR_MANAGER->booleanType());
+ terms.push_back(f);
+ if(! ipl.isNull()) {
+ terms.push_back(ipl);
+ }
+ f = MK_EXPR(k, terms);
}
/* lets: letDecl defines the variables and functionss, we just
@@ -1283,11 +1297,20 @@ prefixFormula[CVC4::Expr& f]
}
;
-instantiationPatterns
+instantiationPatterns[ CVC4::Expr& expr ]
@init {
+ std::vector<Expr> args;
Expr f;
+ std::vector<Expr> patterns;
}
- : ( PATTERN_TOK LPAREN formula[f] (COMMA formula[f])* RPAREN COLON )+
+ : ( PATTERN_TOK LPAREN formula[f] { args.push_back( f ); } (COMMA formula[f] { args.push_back( f ); } )* RPAREN COLON
+ { patterns.push_back( EXPR_MANAGER->mkExpr( kind::INST_PATTERN, args ) );
+ args.clear();
+ } )+
+ { if(! patterns.empty()) {
+ expr = EXPR_MANAGER->mkExpr( kind::INST_PATTERN_LIST, patterns );
+ }
+ }
;
/**
@@ -1417,7 +1440,7 @@ tupleStore[CVC4::Expr& f]
Expr f2;
}
: k=numeral ASSIGN_TOK uminusTerm[f2]
- {
+ {
Type t = f.getType();
if(! t.isDatatype()) {
PARSER_STATE->parseError("tuple-update applied to non-tuple");
@@ -1456,7 +1479,7 @@ recordStore[CVC4::Expr& f]
Expr f2;
}
: identifier[id,CHECK_NONE,SYM_VARIABLE] ASSIGN_TOK uminusTerm[f2]
- {
+ {
Type t = f.getType();
if(! t.isDatatype()) {
PARSER_STATE->parseError("record-update applied to non-record");
diff --git a/src/parser/smt/Smt.g b/src/parser/smt/Smt.g
index 6dd4e78f3..568f3bb92 100644
--- a/src/parser/smt/Smt.g
+++ b/src/parser/smt/Smt.g
@@ -244,6 +244,19 @@ annotatedFormula[CVC4::Expr& expr]
}
}
+ | /* A quantifier */
+ LPAREN_TOK
+ ( FORALL_TOK { kind = kind::FORALL; } | EXISTS_TOK { kind = kind::EXISTS; } )
+ { PARSER_STATE->pushScope(); }
+ ( LPAREN_TOK let_identifier[name,CHECK_NONE] t=sortSymbol RPAREN_TOK
+ { args.push_back(PARSER_STATE->mkVar(name, t)); }
+ )+
+ annotatedFormula[expr] RPAREN_TOK
+ { args.push_back(expr);
+ expr = MK_EXPR(kind, args);
+ PARSER_STATE->popScope();
+ }
+
| /* A non-built-in function application */
// Semantic predicate not necessary if parenthesized subexpressions
diff --git a/src/parser/smt/smt.cpp b/src/parser/smt/smt.cpp
index c3b81655c..4d3c1d086 100644
--- a/src/parser/smt/smt.cpp
+++ b/src/parser/smt/smt.cpp
@@ -29,6 +29,10 @@ namespace parser {
std::hash_map<const std::string, Smt::Logic, CVC4::StringHashFunction> Smt::newLogicMap() {
std::hash_map<const std::string, Smt::Logic, CVC4::StringHashFunction> logicMap;
+ logicMap["AUFLIA"] = AUFLIA;
+ logicMap["AUFLIRA"] = AUFLIRA;
+ logicMap["AUFNIRA"] = AUFNIRA;
+ logicMap["LRA"] = LRA;
logicMap["QF_AX"] = QF_AX;
logicMap["QF_BV"] = QF_BV;
logicMap["QF_IDL"] = QF_IDL;
@@ -54,6 +58,9 @@ std::hash_map<const std::string, Smt::Logic, CVC4::StringHashFunction> Smt::newL
logicMap["QF_UFNIRA"] = QF_UFNIRA;
logicMap["QF_AUFLIA"] = QF_AUFLIA;
logicMap["QF_AUFLIRA"] = QF_AUFLIRA;
+ logicMap["UFNIA"] = UFNIA;
+ logicMap["UFNIRA"] = UFNIRA;
+ logicMap["UFLRA"] = UFLRA;
logicMap["QF_ALL_SUPPORTED"] = QF_ALL_SUPPORTED;
logicMap["ALL_SUPPORTED"] = ALL_SUPPORTED;
return logicMap;
@@ -109,6 +116,22 @@ void Smt::addTheory(Theory theory) {
break;
}
+ case THEORY_BITVECTOR_ARRAYS_EX: {
+ Unimplemented("Cannot yet handle SMT-LIBv1 bitvector arrays (i.e., the BitVector_ArraysEx theory)");
+ //addOperator(kind::SELECT);
+ //addOperator(kind::STORE);
+ break;
+ }
+
+ case THEORY_INT_INT_REAL_ARRAY_ARRAYS_EX: {
+ defineType("Array1", getExprManager()->mkArrayType(getSort("Int"), getSort("Real")));
+ defineType("Array2", getExprManager()->mkArrayType(getSort("Int"), getSort("Array1")));
+ addOperator(kind::SELECT);
+ addOperator(kind::STORE);
+ break;
+ }
+
+ case THEORY_INT_ARRAYS:
case THEORY_INT_ARRAYS_EX: {
defineType("Array", getExprManager()->mkArrayType(getExprManager()->integerType(), getExprManager()->integerType()));
@@ -140,6 +163,9 @@ void Smt::addTheory(Theory theory) {
case THEORY_BITVECTORS:
break;
+ case THEORY_QUANTIFIERS:
+ break;
+
default:
Unhandled(theory);
}
@@ -244,13 +270,14 @@ void Smt::setLogic(const std::string& name) {
break;
case QF_AUFLIRA:
- addTheory(THEORY_ARRAYS_EX);
+ addTheory(THEORY_INT_INT_REAL_ARRAY_ARRAYS_EX);
addUf();
addTheory(THEORY_INTS);
addTheory(THEORY_REALS);
break;
case ALL_SUPPORTED:
+ addTheory(THEORY_QUANTIFIERS);
/* fall through */
case QF_ALL_SUPPORTED:
addTheory(THEORY_ARRAYS_EX);
@@ -261,14 +288,41 @@ void Smt::setLogic(const std::string& name) {
break;
case AUFLIA:
+ addUf();
+ addTheory(THEORY_INTS);
+ addTheory(THEORY_INT_ARRAYS_EX);
+ addTheory(THEORY_QUANTIFIERS);
+ break;
+
case AUFLIRA:
case AUFNIRA:
+ addUf();
+ addTheory(THEORY_INTS);
+ addTheory(THEORY_REALS);
+ addTheory(THEORY_INT_INT_REAL_ARRAY_ARRAYS_EX);
+ addTheory(THEORY_QUANTIFIERS);
+ break;
+
case LRA:
- case UFLRA:
case UFNIA:
- Unhandled(name);
+ addUf();
+ addTheory(THEORY_INTS);
+ addTheory(THEORY_QUANTIFIERS);
+ break;
+ case UFNIRA:
+ addUf();
+ addTheory(THEORY_INTS);
+ addTheory(THEORY_REALS);
+ addTheory(THEORY_QUANTIFIERS);
+ break;
+
+ case UFLRA:
+ addUf();
+ addTheory(THEORY_REALS);
+ addTheory(THEORY_QUANTIFIERS);
+ break;
}
-}
+}/* Smt::setLogic() */
}/* CVC4::parser namespace */
}/* CVC4 namespace */
diff --git a/src/parser/smt/smt.h b/src/parser/smt/smt.h
index d77808930..7b1dfc345 100644
--- a/src/parser/smt/smt.h
+++ b/src/parser/smt/smt.h
@@ -65,6 +65,7 @@ public:
QF_UFNIRA, // nonstandard
QF_UFNRA,
UFLRA,
+ UFNIRA, // nonstandard
UFNIA,
QF_ALL_SUPPORTED, // nonstandard
ALL_SUPPORTED // nonstandard
@@ -75,7 +76,7 @@ public:
THEORY_ARRAYS_EX,
THEORY_BITVECTORS,
THEORY_BITVECTORS_32,
- THEORY_BITVECTORS_ARRAYS_EX,
+ THEORY_BITVECTOR_ARRAYS_EX,
THEORY_EMPTY,
THEORY_INTS,
THEORY_INT_ARRAYS,
@@ -83,6 +84,7 @@ public:
THEORY_INT_INT_REAL_ARRAY_ARRAYS_EX,
THEORY_REALS,
THEORY_REALS_INTS,
+ THEORY_QUANTIFIERS
};
private:
diff --git a/src/parser/smt2/Smt2.g b/src/parser/smt2/Smt2.g
index 7a7c7df62..59b6715b9 100644
--- a/src/parser/smt2/Smt2.g
+++ b/src/parser/smt2/Smt2.g
@@ -136,7 +136,10 @@ using namespace CVC4::parser;
* @return the parsed expression, or the Null Expr if we've reached the end of the input
*/
parseExpr returns [CVC4::parser::smt2::myExpr expr]
- : term[expr]
+@declarations {
+ Expr expr2;
+}
+ : term[expr, expr2]
| EOF
;
@@ -156,7 +159,7 @@ command returns [CVC4::Command* cmd = NULL]
@declarations {
std::string name;
std::vector<std::string> names;
- Expr expr;
+ Expr expr, expr2;
Type t;
std::vector<Expr> terms;
std::vector<Type> sorts;
@@ -258,7 +261,7 @@ command returns [CVC4::Command* cmd = NULL]
terms.push_back(PARSER_STATE->mkVar((*i).first, (*i).second));
}
}
- term[expr]
+ term[expr, expr2]
{ PARSER_STATE->popScope();
// declare the name down here (while parsing term, signature
// must not be extended with the name itself; no recursion
@@ -287,7 +290,7 @@ command returns [CVC4::Command* cmd = NULL]
{ cmd = new GetAssignmentCommand; }
| /* assertion */
ASSERT_TOK { PARSER_STATE->checkThatLogicIsSet(); }
- term[expr]
+ term[expr, expr2]
{ cmd = new AssertCommand(expr); }
| /* checksat */
CHECKSAT_TOK { PARSER_STATE->checkThatLogicIsSet(); }
@@ -359,7 +362,7 @@ extendedCommand[CVC4::Command*& cmd]
@declarations {
std::vector<CVC4::Datatype> dts;
Type t;
- Expr e;
+ Expr e, e2;
SExpr sexpr;
std::string name;
std::vector<std::string> names;
@@ -420,7 +423,7 @@ symbolicExpr[CVC4::SExpr& sexpr]
* Matches a term.
* @return the expression representing the formula
*/
-term[CVC4::Expr& expr]
+term[CVC4::Expr& expr, CVC4::Expr& expr2]
@init {
Debug("parser") << "term: " << AntlrInput::tokenText(LT(1)) << std::endl;
Kind kind;
@@ -428,6 +431,11 @@ term[CVC4::Expr& expr]
std::string name;
std::vector<Expr> args;
SExpr sexpr;
+ std::vector< std::pair<std::string, Type> > sortedVarNames;
+ Expr f, f2;
+ std::string attr;
+ Expr attexpr;
+ std::vector<Expr> attexprs;
}
: /* a built-in operator application */
LPAREN_TOK builtinOp[kind] termList[args,expr] RPAREN_TOK
@@ -456,10 +464,45 @@ term[CVC4::Expr& expr]
expr = MK_EXPR(kind, args);
}
}
-
+ | LPAREN_TOK quantOp[kind]
+ LPAREN_TOK sortedVarList[sortedVarNames] RPAREN_TOK
+ {
+ PARSER_STATE->pushScope();
+ for(std::vector<std::pair<std::string, CVC4::Type> >::const_iterator i =
+ sortedVarNames.begin(), iend = sortedVarNames.end();
+ i != iend;
+ ++i) {
+ args.push_back(PARSER_STATE->mkVar((*i).first, (*i).second));
+ }
+ Expr bvl = MK_EXPR(kind::BOUND_VAR_LIST, args);
+ args.clear();
+ args.push_back(bvl);
+ }
+ term[f, f2] RPAREN_TOK
+ {
+ PARSER_STATE->popScope();
+ switch(f.getKind()) {
+ case CVC4::kind::RR_REWRITE:
+ case CVC4::kind::RR_REDUCTION:
+ case CVC4::kind::RR_DEDUCTION:
+ if(kind == CVC4::kind::EXISTS) {
+ PARSER_STATE->parseError("Use Exists instead of Forall for a rewrite rule.");
+ }
+ args.push_back(f2); // guards
+ args.push_back(f); // rule
+ expr = MK_EXPR(CVC4::kind::REWRITE_RULE, args);
+ break;
+ default:
+ args.push_back(f);
+ if(! f2.isNull()){
+ args.push_back(f2);
+ }
+ expr = MK_EXPR(kind, args);
+ }
+ }
| /* A non-built-in function application */
LPAREN_TOK
- functionName[name,CHECK_DECLARED]
+ functionName[name, CHECK_DECLARED]
{ PARSER_STATE->checkFunctionLike(name);
const bool isDefinedFunction =
PARSER_STATE->isDefinedFunction(name);
@@ -469,13 +512,13 @@ term[CVC4::Expr& expr]
} else {
expr = PARSER_STATE->getVariable(name);
Type t = expr.getType();
- if( t.isConstructor() ){
+ if(t.isConstructor()) {
kind = CVC4::kind::APPLY_CONSTRUCTOR;
- }else if( t.isSelector() ){
+ } else if(t.isSelector()) {
kind = CVC4::kind::APPLY_SELECTOR;
- }else if( t.isTester() ){
+ } else if(t.isTester()) {
kind = CVC4::kind::APPLY_TESTER;
- }else{
+ } else {
kind = CVC4::kind::APPLY_UF;
}
}
@@ -494,10 +537,10 @@ term[CVC4::Expr& expr]
| /* a let binding */
LPAREN_TOK LET_TOK LPAREN_TOK
{ PARSER_STATE->pushScope(); }
- ( LPAREN_TOK symbol[name,CHECK_UNDECLARED,SYM_VARIABLE] term[expr] RPAREN_TOK
+ ( LPAREN_TOK symbol[name,CHECK_UNDECLARED,SYM_VARIABLE] term[expr, f2] RPAREN_TOK
{ PARSER_STATE->defineVar(name,expr); } )+
RPAREN_TOK
- term[expr]
+ term[expr, f2]
RPAREN_TOK
{ PARSER_STATE->popScope(); }
@@ -519,26 +562,45 @@ term[CVC4::Expr& expr]
}
/* attributed expressions */
- | LPAREN_TOK ATTRIBUTE_TOK term[expr] KEYWORD symbolicExpr[sexpr] RPAREN_TOK
- { std::string attr = AntlrInput::tokenText($KEYWORD);
- if(attr == ":named") {
- name = sexpr.getValue();
- // FIXME ensure expr is a closed subterm
- // check that sexpr is a fresh function symbol
- PARSER_STATE->checkDeclaration(name, CHECK_UNDECLARED, SYM_VARIABLE);
- // define it
- Expr func = PARSER_STATE->mkFunction(name, expr.getType());
- // bind name to expr with define-fun
- Command* c =
- new DefineNamedFunctionCommand(name, func, std::vector<Expr>(), expr);
- PARSER_STATE->preemptCommand(c);
- } else {
- std::stringstream ss;
- ss << "Attribute `" << attr << "' not supported";
- PARSER_STATE->parseError(ss.str());
+ | LPAREN_TOK ATTRIBUTE_TOK term[expr, f2]
+ ( attribute[expr, attexpr,attr]
+ { if(! attexpr.isNull()) {
+ attexprs.push_back(attexpr);
+ }
}
- }
+ )+ RPAREN_TOK
+ {
+ if(attr == ":rewrite-rule") {
+ Expr guard;
+ Expr body;
+ if(expr[1].getKind() == kind::IMPLIES ||
+ expr[1].getKind() == kind::IFF ||
+ expr[1].getKind() == kind::EQUAL) {
+ guard = expr[0];
+ body = expr[1];
+ } else {
+ guard = MK_CONST(bool(true));
+ body = expr;
+ }
+ expr2 = guard;
+ args.push_back(body[0]);
+ args.push_back(body[1]);
+ if(!f2.isNull()) {
+ args.push_back(f2);
+ }
+
+ if ( body.getKind()==kind::IMPLIES ) kind = kind::RR_DEDUCTION;
+ else if( body.getKind()==kind::IFF ) kind = kind::RR_REDUCTION;
+ else if( body.getKind()==kind::EQUAL ) kind = kind::RR_REWRITE;
+ else PARSER_STATE->parseError("Error parsing rewrite rule.");
+ expr = MK_EXPR( kind, args );
+ } else if(! attexprs.empty()) {
+ if(attexprs[0].getKind() == kind::INST_PATTERN) {
+ expr2 = MK_EXPR(kind::INST_PATTERN_LIST, attexprs);
+ }
+ }
+ }
/* constants */
| INTEGER_LITERAL
{ expr = MK_CONST( AntlrInput::tokenToInteger($INTEGER_LITERAL) ); }
@@ -570,6 +632,46 @@ term[CVC4::Expr& expr]
;
/**
+ * Read attribute
+ */
+attribute[CVC4::Expr& expr,CVC4::Expr& retExpr, std::string& attr]
+@init {
+ SExpr sexpr;
+ Expr patexpr;
+ std::vector<Expr> patexprs;
+ Expr e2;
+}
+: KEYWORD
+ { attr = AntlrInput::tokenText($KEYWORD); }
+ symbolicExpr[sexpr]
+ { if(attr == ":named") {
+ std::string name = sexpr.getValue();
+ // FIXME ensure expr is a closed subterm
+ // check that sexpr is a fresh function symbol
+ PARSER_STATE->checkDeclaration(name, CHECK_UNDECLARED, SYM_VARIABLE);
+ // define it
+ Expr func = PARSER_STATE->mkFunction(name, expr.getType());
+ // bind name to expr with define-fun
+ Command* c =
+ new DefineNamedFunctionCommand(name, func, std::vector<Expr>(), expr);
+ PARSER_STATE->preemptCommand(c);
+ } else {
+ std::stringstream ss;
+ ss << "Attribute `" << attr << "' not supported";
+ PARSER_STATE->parseError(ss.str());
+ }
+ }
+ | ATTRIBUTE_PATTERN_TOK LPAREN_TOK ( term[patexpr, e2] { patexprs.push_back( patexpr ); } )+ RPAREN_TOK
+ {
+ attr = std::string(":pattern");
+ retExpr = MK_EXPR(kind::INST_PATTERN, patexprs);
+ }
+ | ATTRIBUTE_REWRITE_RULE {
+ attr = std::string(":rewrite-rule");
+ }
+ ;
+
+/**
* Matches a bit-vector operator (the ones parametrized by numbers)
*/
indexedFunctionName[CVC4::Expr& op]
@@ -613,7 +715,10 @@ badIndexedFunctionName
/* NOTE: We pass an Expr in here just to avoid allocating a fresh Expr every
* time through this rule. */
termList[std::vector<CVC4::Expr>& formulas, CVC4::Expr& expr]
- : ( term[expr] { formulas.push_back(expr); } )+
+@declarations {
+ Expr expr2;
+}
+ : ( term[expr, expr2] { formulas.push_back(expr); } )+
;
/**
@@ -693,6 +798,14 @@ builtinOp[CVC4::Kind& kind]
// NOTE: Theory operators go here
;
+quantOp[CVC4::Kind& kind]
+@init {
+ Debug("parser") << "quant: " << AntlrInput::tokenText(LT(1)) << std::endl;
+}
+ : EXISTS_TOK { $kind = CVC4::kind::EXISTS; }
+ | FORALL_TOK { $kind = CVC4::kind::FORALL; }
+ ;
+
/**
* Matches a (possibly undeclared) function symbol (returning the string)
* @param check what kind of check to do with the symbol
@@ -760,12 +873,12 @@ sortSymbol[CVC4::Type& t, CVC4::parser::DeclarationCheck check]
std::vector<uint64_t> numerals;
}
: sortName[name,CHECK_NONE]
- {
- if( check == CHECK_DECLARED || PARSER_STATE->isDeclared(name, SYM_SORT) ){
- t = PARSER_STATE->getSort(name);
- }else{
- t = PARSER_STATE->mkUnresolvedType(name);
- }
+ {
+ if( check == CHECK_DECLARED || PARSER_STATE->isDeclared(name, SYM_SORT) ){
+ t = PARSER_STATE->getSort(name);
+ }else{
+ t = PARSER_STATE->mkUnresolvedType(name);
+ }
}
| LPAREN_TOK INDEX_TOK symbol[name,CHECK_NONE,SYM_SORT] nonemptyNumeralList[numerals] RPAREN_TOK
{
@@ -929,6 +1042,10 @@ POP_TOK : 'pop';
DECLARE_DATATYPES_TOK : 'declare-datatypes';
ECHO_TOK : 'echo';
+// attributes
+ATTRIBUTE_PATTERN_TOK : ':pattern';
+ATTRIBUTE_REWRITE_RULE : ':rewrite-rule';
+
// operators (NOTE: theory symbols go here)
AMPERSAND_TOK : '&';
AND_TOK : 'and';
diff --git a/src/parser/smt2/smt2.cpp b/src/parser/smt2/smt2.cpp
index 709ba087f..549878e46 100644
--- a/src/parser/smt2/smt2.cpp
+++ b/src/parser/smt2/smt2.cpp
@@ -86,6 +86,9 @@ void Smt2::addTheory(Theory theory) {
case THEORY_BITVECTORS:
break;
+ case THEORY_QUANTIFIERS:
+ break;
+
default:
Unhandled(theory);
}
@@ -195,6 +198,7 @@ void Smt2::setLogic(const std::string& name) {
break;
case Smt::ALL_SUPPORTED:
+ addTheory(THEORY_QUANTIFIERS);
/* fall through */
case Smt::QF_ALL_SUPPORTED:
addTheory(THEORY_ARRAYS);
@@ -208,11 +212,25 @@ void Smt2::setLogic(const std::string& name) {
case Smt::AUFLIRA:
case Smt::AUFNIRA:
case Smt::LRA:
- case Smt::UFLRA:
case Smt::UFNIA:
- Unhandled(name);
+ case Smt::UFNIRA:
+ case Smt::UFLRA:
+ if(d_logic != Smt::AUFLIA && d_logic != Smt::UFNIA) {
+ addTheory(THEORY_REALS);
+ }
+ if(d_logic != Smt::LRA) {
+ addOperator(kind::APPLY_UF);
+ if(d_logic != Smt::UFLRA) {
+ addTheory(THEORY_INTS);
+ if(d_logic != Smt::UFNIA && d_logic != Smt::UFNIRA) {
+ addTheory(THEORY_ARRAYS);
+ }
+ }
+ }
+ addTheory(THEORY_QUANTIFIERS);
+ break;
}
-}
+}/* Smt2::setLogic() */
void Smt2::setInfo(const std::string& flag, const SExpr& sexpr) {
// TODO: ???
diff --git a/src/parser/smt2/smt2.h b/src/parser/smt2/smt2.h
index b71f63558..9d33e3e62 100644
--- a/src/parser/smt2/smt2.h
+++ b/src/parser/smt2/smt2.h
@@ -41,6 +41,7 @@ public:
THEORY_INTS,
THEORY_REALS,
THEORY_REALS_INTS,
+ THEORY_QUANTIFIERS,
};
private:
diff --git a/src/printer/cvc/cvc_printer.cpp b/src/printer/cvc/cvc_printer.cpp
index d20ba0354..76c4f0abc 100644
--- a/src/printer/cvc/cvc_printer.cpp
+++ b/src/printer/cvc/cvc_printer.cpp
@@ -5,7 +5,7 @@
** Major contributors: none
** Minor contributors (to current version): none
** This file is part of the CVC4 prototype.
- ** Copyright (c) 2009, 2010, 2011 The Analysis of Computer Systems Group (ACSys)
+ ** Copyright (c) 2009-2012 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
@@ -253,6 +253,9 @@ void CvcPrinter::toStream(std::ostream& out, TNode n, int depth, bool types, boo
case kind::APPLY_UF:
toStream(op, n.getOperator(), depth, types, false);
break;
+ case kind::CARDINALITY_CONSTRAINT:
+ out << "CARDINALITY_CONSTRAINT";
+ break;
case kind::FUNCTION_TYPE:
if (n.getNumChildren() > 1) {
@@ -548,6 +551,44 @@ void CvcPrinter::toStream(std::ostream& out, TNode n, int depth, bool types, boo
out << ", " << n.getOperator().getConst<BitVectorRotateRight>() << ')';
return;
break;
+
+ // Quantifiers
+ case kind::FORALL:
+ out << "(FORALL";
+ toStream(out, n[0], depth, types, false);
+ out << " : ";
+ toStream(out, n[1], depth, types, false);
+ out << ')';
+ // TODO: user patterns?
+ return;
+ case kind::EXISTS:
+ out << "(EXISTS";
+ toStream(out, n[0], depth, types, false);
+ out << " : ";
+ toStream(out, n[1], depth, types, false);
+ out << ')';
+ // TODO: user patterns?
+ break;
+ case kind::INST_CONSTANT:
+ out << "INST_CONSTANT";
+ break;
+ case kind::BOUND_VAR_LIST:
+ out << '(';
+ for(size_t i = 0; i < n.getNumChildren(); ++i) {
+ if(i > 0) {
+ out << ", ";
+ }
+ toStream(out, n[i], -1, true, false); // ascribe types
+ }
+ out << ')';
+ return;
+ case kind::INST_PATTERN:
+ out << "INST_PATTERN";
+ break;
+ case kind::INST_PATTERN_LIST:
+ out << "INST_PATTERN_LIST";
+ break;
+
default:
Warning() << "Kind printing not implemented for the case of " << n.getKind() << endl;
break;
@@ -662,12 +703,12 @@ static void toStream(std::ostream& out, const SExpr& sexpr) throw() {
} else if(sexpr.isString()) {
string s = sexpr.getValue();
// escape backslash and quote
- for(string::iterator i = s.begin(); i != s.end(); ++i) {
- if(*i == '"') {
- s.replace(i, i + 1, "\\\"");
+ for(size_t i = 0; i < s.size(); ++i) {
+ if(s[i] == '"') {
+ s.replace(i, 1, "\\\"");
++i;
- } else if(*i == '\\') {
- s.replace(i, i + 1, "\\\\");
+ } else if(s[i] == '\\') {
+ s.replace(i, 1, "\\\\");
++i;
}
}
diff --git a/src/printer/smt2/smt2_printer.cpp b/src/printer/smt2/smt2_printer.cpp
index 72ce3804d..ebec37031 100644
--- a/src/printer/smt2/smt2_printer.cpp
+++ b/src/printer/smt2/smt2_printer.cpp
@@ -281,6 +281,32 @@ void Smt2Printer::toStream(std::ostream& out, TNode n,
case kind::APPLY_SELECTOR:
break;
+ // quantifiers
+ case kind::FORALL: out << "forall "; break;
+ case kind::EXISTS: out << "exists "; break;
+ case kind::BOUND_VAR_LIST:
+ out << '(';
+ for(TNode::iterator i = n.begin(),
+ iend = n.end();
+ i != iend; ) {
+ out << '(';
+ (*i).toStream(out, toDepth < 0 ? toDepth : toDepth - 1,
+ types, language::output::LANG_SMTLIB_V2);
+ out << ' ';
+ (*i).getType().toStream(out, toDepth < 0 ? toDepth : toDepth - 1,
+ false, language::output::LANG_SMTLIB_V2);
+ out << ')';
+ if(++i != iend) {
+ out << ' ';
+ }
+ }
+ out << ')';
+ return;
+ case kind::INST_PATTERN:
+ case kind::INST_PATTERN_LIST:
+ // TODO user patterns
+ break;
+
default:
// fall back on however the kind prints itself; this probably
// won't be SMT-LIB v2 compliant, but it will be clear from the
diff --git a/src/prop/minisat/core/Solver.cc b/src/prop/minisat/core/Solver.cc
index a260a8ca1..697ab4853 100644
--- a/src/prop/minisat/core/Solver.cc
+++ b/src/prop/minisat/core/Solver.cc
@@ -351,7 +351,7 @@ void Solver::cancelUntil(int level) {
if(intro_level(x) != -1) {// might be unregistered
assigns [x] = l_Undef;
vardata[x].trail_index = -1;
- if (phase_saving > 1 || (phase_saving == 1) && c > trail_lim.last())
+ if ((phase_saving > 1 || (phase_saving == 1) && c > trail_lim.last()) && (polarity[x] & 0x2) == 0)
polarity[x] = sign(trail[c]);
insertVarOrder(x);
}
@@ -359,6 +359,7 @@ void Solver::cancelUntil(int level) {
qhead = trail_lim[level];
trail.shrink(trail.size() - trail_lim[level]);
trail_lim.shrink(trail_lim.size() - level);
+ flipped.shrink(flipped.size() - level);
// Register variables that have not been registered yet
int currentLevel = decisionLevel();
@@ -442,7 +443,7 @@ Lit Solver::pickBranchLit()
return mkLit(next, (dec_pol == l_True) );
}
// If it can't use internal heuristic to do that
- return mkLit(next, rnd_pol ? drand(random_seed) < 0.5 : polarity[next]);
+ return mkLit(next, rnd_pol ? drand(random_seed) < 0.5 : (polarity[next] & 0x1));
}
}
@@ -1461,7 +1462,7 @@ void Solver::pop()
Debug("minisat") << "== unassigning " << l << std::endl;
Var x = var(l);
assigns [x] = l_Undef;
- if (phase_saving >= 1)
+ if (phase_saving >= 1 && (polarity[x] & 0x2) == 0)
polarity[x] = sign(l);
insertVarOrder(x);
trail_user.pop();
@@ -1489,8 +1490,46 @@ void Solver::renewVar(Lit lit, int level) {
Var v = var(lit);
vardata[v].intro_level = (level == -1 ? getAssertionLevel() : level);
setDecisionVar(v, true);
+ // explicitly not resetting polarity phase-locking here
}
+bool Solver::flipDecision() {
+ Debug("flipdec") << "FLIP: decision level is " << decisionLevel() << std::endl;
+ if(decisionLevel() == 0) {
+ Debug("flipdec") << "FLIP: no decisions, returning false" << std::endl;
+ return false;
+ }
+
+ // find the level to cancel until
+ int level = trail_lim.size() - 1;
+ Debug("flipdec") << "FLIP: looking at level " << level << " dec is " << trail[trail_lim[level]] << " flippable?" << ((polarity[var(trail[trail_lim[level]])] & 0x2) == 0 ? 1 : 0) << " flipped?" << flipped[level] << std::endl;
+ while(level > 0 && (flipped[level] || /* phase-locked */ (polarity[var(trail[trail_lim[level]])] & 0x2) != 0)) {
+ --level;
+ Debug("flipdec") << "FLIP: looking at level " << level << " dec is " << trail[trail_lim[level]] << " flippable?" << ((polarity[var(trail[trail_lim[level]])] & 0x2) == 0 ? 2 : 0) << " flipped?" << flipped[level] << std::endl;
+ }
+ if(level < 0) {
+ Lit l = trail[trail_lim[0]];
+ Debug("flipdec") << "FLIP: canceling everything, flipping root decision " << l << std::endl;
+ cancelUntil(0);
+ newDecisionLevel();
+ Debug("flipdec") << "FLIP: enqueuing " << ~l << std::endl;
+ uncheckedEnqueue(~l);
+ flipped[0] = true;
+ Debug("flipdec") << "FLIP: returning false" << std::endl;
+ return false;
+ }
+ Lit l = trail[trail_lim[level]];
+ Debug("flipdec") << "FLIP: canceling to level " << level << ", flipping decision " << l << std::endl;
+ cancelUntil(level);
+ newDecisionLevel();
+ Debug("flipdec") << "FLIP: enqueuing " << ~l << std::endl;
+ uncheckedEnqueue(~l);
+ flipped[level] = true;
+ Debug("flipdec") << "FLIP: returning true" << std::endl;
+ return true;
+}
+
+
CRef Solver::updateLemmas() {
Debug("minisat::lemmas") << "Solver::updateLemmas()" << std::endl;
diff --git a/src/prop/minisat/core/Solver.h b/src/prop/minisat/core/Solver.h
index e677d7220..fdc9a98b7 100644
--- a/src/prop/minisat/core/Solver.h
+++ b/src/prop/minisat/core/Solver.h
@@ -54,7 +54,7 @@ class Solver {
/** The only two CVC4 entry points to the private solver data */
friend class CVC4::prop::TheoryProxy;
- friend class CVC4::SatProof;
+ friend class CVC4::SatProof;
protected:
/** The pointer to the proxy that provides interfaces to the SMT engine */
@@ -64,7 +64,7 @@ protected:
CVC4::context::Context* context;
/** The current assertion level (user) */
- int assertionLevel;
+ int assertionLevel;
/** Variable representing true */
Var varTrue;
@@ -77,7 +77,7 @@ public:
int getAssertionLevel() const { return assertionLevel; }
protected:
/** Do we allow incremental solving */
- bool enable_incremental;
+ bool enable_incremental;
/** Literals propagated by lemmas */
vec< vec<Lit> > lemmas;
@@ -89,7 +89,7 @@ protected:
bool recheck;
/** Shrink 'cs' to contain only clauses below given level */
- void removeClausesAboveLevel(vec<CRef>& cs, int level);
+ void removeClausesAboveLevel(vec<CRef>& cs, int level);
/** True if we are currently solving. */
bool minisat_busy;
@@ -182,11 +182,13 @@ public:
void toDimacs (const char* file, Lit p);
void toDimacs (const char* file, Lit p, Lit q);
void toDimacs (const char* file, Lit p, Lit q, Lit r);
-
+
// Variable mode:
- //
+ //
void setPolarity (Var v, bool b); // Declare which polarity the decision heuristic should use for a variable. Requires mode 'polarity_user'.
+ void freezePolarity (Var v, bool b); // Declare which polarity the decision heuristic MUST ALWAYS use for a variable. Requires mode 'polarity_user'.
void setDecisionVar (Var v, bool b); // Declare if a variable should be eligible for selection in the decision heuristic.
+ bool flipDecision (); // Backtrack and flip most recent decision
// Read state:
//
@@ -199,6 +201,7 @@ public:
int nLearnts () const; // The current number of learnt clauses.
int nVars () const; // The current number of variables.
int nFreeVars () const;
+ bool isDecision (Var x) const; // is the given var a decision?
// Debugging SMT explanations
//
@@ -290,8 +293,9 @@ protected:
OccLists<Lit, vec<Watcher>, WatcherDeleted>
watches; // 'watches[lit]' is a list of constraints watching 'lit' (will go there if literal becomes true).
vec<lbool> assigns; // The current assignments.
- vec<char> polarity; // The preferred polarity of each variable.
+ vec<char> polarity; // The preferred polarity of each variable (bit 0) and whether it's locked (bit 1).
vec<char> decision; // Declares if a variable is eligible for selection in the decision heuristic.
+ vec<int> flipped; // Which trail_lim decisions have been flipped in this context.
vec<Lit> trail; // Assignment stack; stores all assigments made in the order they were made.
vec<int> trail_lim; // Separator indices for different decision levels in 'trail'.
vec<Lit> trail_user; // Stack of assignments to UNdo on user pop.
@@ -423,6 +427,8 @@ inline bool Solver::isPropagated(Var x) const { return vardata[x].reason != CRef
inline bool Solver::isPropagatedBy(Var x, const Clause& c) const { return vardata[x].reason != CRef_Undef && vardata[x].reason != CRef_Lazy && ca.lea(vardata[var(c[0])].reason) == &c; }
+inline bool Solver::isDecision(Var x) const { Debug("minisat") << "var " << x << " is a decision iff " << (vardata[x].reason == CRef_Undef) << " && " << level(x) << " > 0" << std::endl; return vardata[x].reason == CRef_Undef && level(x) > 0; }
+
inline int Solver::level (Var x) const { return vardata[x].level; }
inline int Solver::intro_level(Var x) const { return vardata[x].intro_level; }
@@ -466,7 +472,7 @@ inline bool Solver::addClause (Lit p, bool 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::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()); context->push(); if(Dump.isOn("state")) { Dump("state") << CVC4::PushCommand(); } }
+inline void Solver::newDecisionLevel() { trail_lim.push(trail.size()); flipped.push(false); context->push(); if(Dump.isOn("state")) { Dump("state") << CVC4::PushCommand(); } }
inline int Solver::decisionLevel () const { return trail_lim.size(); }
inline uint32_t Solver::abstractLevel (Var x) const { return 1 << (level(x) & 31); }
@@ -481,14 +487,16 @@ inline int Solver::nVars () const { return vardata.size(); }
inline int Solver::nFreeVars () const { return (int)dec_vars - (trail_lim.size() == 0 ? trail.size() : trail_lim[0]); }
inline bool Solver::properExplanation(Lit l, Lit expl) const { return value(l) == l_True && value(expl) == l_True && trail_index(var(expl)) < trail_index(var(l)); }
inline void Solver::setPolarity (Var v, bool b) { polarity[v] = b; }
-inline void Solver::setDecisionVar(Var v, bool b)
-{
- if ( b && !decision[v]) dec_vars++;
- else if (!b && decision[v]) dec_vars--;
+inline void Solver::freezePolarity(Var v, bool b) { polarity[v] = int(b) | 0x2; }
+inline void Solver::setDecisionVar(Var v, bool b)
+{
+ if ( b && !decision[v] ) dec_vars++;
+ else if (!b && decision[v] ) dec_vars--;
decision[v] = b;
insertVarOrder(v);
}
+
inline void Solver::setConfBudget(int64_t x){ conflict_budget = conflicts + x; }
inline void Solver::setPropBudget(int64_t x){ propagation_budget = propagations + x; }
inline void Solver::interrupt(){ asynch_interrupt = true; }
diff --git a/src/prop/minisat/minisat.cpp b/src/prop/minisat/minisat.cpp
index 6b02153c7..6fa698bd0 100644
--- a/src/prop/minisat/minisat.cpp
+++ b/src/prop/minisat/minisat.cpp
@@ -178,6 +178,22 @@ bool MinisatSatSolver::properExplanation(SatLiteral lit, SatLiteral expl) const
return true;
}
+void MinisatSatSolver::requirePhase(SatLiteral lit) {
+ Assert(!d_minisat->rnd_pol);
+ Debug("minisat") << "requirePhase(" << lit << ")" << " " << lit.getSatVariable() << " " << lit.isNegated() << std::endl;
+ SatVariable v = lit.getSatVariable();
+ d_minisat->freezePolarity(v, lit.isNegated());
+}
+
+bool MinisatSatSolver::flipDecision() {
+ Debug("minisat") << "flipDecision()" << std::endl;
+ return d_minisat->flipDecision();
+}
+
+bool MinisatSatSolver::isDecision(SatVariable decn) const {
+ return d_minisat->isDecision( decn );
+}
+
/** Incremental interface */
unsigned MinisatSatSolver::getAssertionLevel() const {
diff --git a/src/prop/minisat/minisat.h b/src/prop/minisat/minisat.h
index 9171bf232..f87e4ae53 100644
--- a/src/prop/minisat/minisat.h
+++ b/src/prop/minisat/minisat.h
@@ -84,6 +84,12 @@ public:
void renewVar(SatLiteral lit, int level = -1);
+ void requirePhase(SatLiteral lit);
+
+ bool flipDecision();
+
+ bool isDecision(SatVariable decn) const;
+
class Statistics {
private:
ReferenceStat<uint64_t> d_statStarts, d_statDecisions;
diff --git a/src/prop/prop_engine.cpp b/src/prop/prop_engine.cpp
index 702a530cf..f3904549f 100644
--- a/src/prop/prop_engine.cpp
+++ b/src/prop/prop_engine.cpp
@@ -126,6 +126,24 @@ void PropEngine::assertLemma(TNode node, bool negated, bool removable) {
d_cnfStream->convertAndAssert(node, removable, negated);
}
+void PropEngine::requirePhase(TNode n, bool phase) {
+ Debug("prop") << "requirePhase(" << n << ", " << phase << ")" << endl;
+
+ Assert(n.getType().isBoolean());
+ SatLiteral lit = d_cnfStream->getLiteral(n);
+ d_satSolver->requirePhase(phase ? lit : ~lit);
+}
+
+bool PropEngine::flipDecision() {
+ Debug("prop") << "flipDecision()" << endl;
+ return d_satSolver->flipDecision();
+}
+
+bool PropEngine::isDecision(Node lit) const {
+ Assert(isTranslatedSatLiteral(lit));
+ return d_satSolver->isDecision(d_cnfStream->getLiteral(lit).getSatVariable());
+}
+
void PropEngine::printSatisfyingAssignment(){
const CnfStream::TranslationCache& transCache =
d_cnfStream->getTranslationCache();
diff --git a/src/prop/prop_engine.h b/src/prop/prop_engine.h
index 603cdb0e6..dcfc5a9df 100644
--- a/src/prop/prop_engine.h
+++ b/src/prop/prop_engine.h
@@ -194,6 +194,37 @@ public:
void assertLemma(TNode node, bool negated, bool removable);
/**
+ * If ever n is decided upon, it must be in the given phase. This
+ * occurs *globally*, i.e., even if the literal is untranslated by
+ * user pop and retranslated, it keeps this phase. The associated
+ * variable will _always_ be phase-locked.
+ *
+ * @param n the node in question; must have an associated SAT literal
+ * @param phase the phase to use
+ */
+ void requirePhase(TNode n, bool phase);
+
+ /**
+ * Backtracks to and flips the most recent unflipped decision, and
+ * returns TRUE. If the decision stack is nonempty but all
+ * decisions have been flipped already, the state is backtracked to
+ * the root decision, which is re-flipped to the original phase (and
+ * FALSE is returned). If the decision stack is empty, the state is
+ * unchanged and FALSE is returned.
+ *
+ * @return true if a decision was flipped as requested; false if the
+ * root decision was reflipped, or if no decisions are on the stack.
+ */
+ bool flipDecision();
+
+ /**
+ * Return whether the given literal is a SAT decision. Either phase
+ * is permitted; that is, if "lit" is a SAT decision, this function
+ * returns true for both lit and the negation of lit.
+ */
+ bool isDecision(Node lit) const;
+
+ /**
* Checks the current context for satisfiability.
*
* @param millis the time limit for this call in milliseconds
diff --git a/src/prop/sat_solver.h b/src/prop/sat_solver.h
index 2865f2cb5..79e54cac2 100644
--- a/src/prop/sat_solver.h
+++ b/src/prop/sat_solver.h
@@ -123,6 +123,12 @@ public:
virtual bool properExplanation(SatLiteral lit, SatLiteral expl) const = 0;
+ virtual void requirePhase(SatLiteral lit) = 0;
+
+ virtual bool flipDecision() = 0;
+
+ virtual bool isDecision(SatVariable decn) const = 0;
+
};
}/* prop namespace */
diff --git a/src/theory/Makefile.am b/src/theory/Makefile.am
index 85d6fbdf8..19e7d588a 100644
--- a/src/theory/Makefile.am
+++ b/src/theory/Makefile.am
@@ -3,7 +3,7 @@ AM_CPPFLAGS = \
-I@srcdir@/../include -I@srcdir@/.. -I@builddir@/..
AM_CXXFLAGS = -Wall -Wno-unknown-pragmas $(FLAG_VISIBILITY_HIDDEN)
-SUBDIRS = builtin booleans uf arith arrays bv datatypes
+SUBDIRS = builtin booleans uf arith arrays bv datatypes quantifiers rewriterules
DIST_SUBDIRS = $(SUBDIRS) example
noinst_LTLIBRARIES = libtheory.la
@@ -33,10 +33,20 @@ libtheory_la_SOURCES = \
ite_simplifier.h \
ite_simplifier.cpp \
unconstrained_simplifier.h \
- unconstrained_simplifier.cpp
+ unconstrained_simplifier.cpp \
+ quantifiers_engine.h \
+ quantifiers_engine.cpp \
+ instantiator_default.h \
+ instantiator_default.cpp \
+ inst_match.h \
+ inst_match_impl.h \
+ inst_match.cpp \
+ trigger.h \
+ trigger.cpp
nodist_libtheory_la_SOURCES = \
rewriter_tables.h \
+ instantiator_tables.cpp \
theory_traits.h
libtheory_la_LIBADD = \
@@ -46,21 +56,27 @@ libtheory_la_LIBADD = \
@builddir@/arith/libarith.la \
@builddir@/arrays/libarrays.la \
@builddir@/bv/libbv.la \
- @builddir@/datatypes/libdatatypes.la
+ @builddir@/datatypes/libdatatypes.la \
+ @builddir@/quantifiers/libquantifiers.la \
+ @builddir@/rewriterules/librewriterules.la
EXTRA_DIST = \
rewriter_tables_template.h \
+ instantiator_tables_template.cpp \
theory_traits_template.h \
mktheorytraits \
mkrewriter \
+ mkinstantiator \
Makefile.subdirs
BUILT_SOURCES = \
rewriter_tables.h \
+ instantiator_tables.cpp \
theory_traits.h
CLEANFILES = \
rewriter_tables.h \
+ instantiator_tables.cpp \
theory_traits.h
include @top_srcdir@/src/theory/Makefile.subdirs
@@ -73,6 +89,14 @@ rewriter_tables.h: rewriter_tables_template.h mkrewriter @top_builddir@/src/theo
`cat @top_builddir@/src/theory/.subdirs` \
> $@) || (rm -f $@ && exit 1)
+instantiator_tables.cpp: instantiator_tables_template.cpp mkinstantiator @top_builddir@/src/theory/.subdirs @top_srcdir@/src/theory/*/kinds
+ $(AM_V_at)chmod +x @srcdir@/mkinstantiator
+ $(AM_V_at)$(am__mv) $@ $@~ 2>/dev/null || true
+ $(AM_V_GEN)(@srcdir@/mkinstantiator \
+ $< \
+ `cat @top_builddir@/src/theory/.subdirs` \
+ > $@) || (rm -f $@ && exit 1)
+
theory_traits.h: theory_traits_template.h mktheorytraits @top_builddir@/src/theory/.subdirs @top_srcdir@/src/theory/*/kinds
$(AM_V_at)chmod +x @srcdir@/mktheorytraits
$(AM_V_at)$(am__mv) $@ $@~ 2>/dev/null || true
diff --git a/src/theory/arith/Makefile.am b/src/theory/arith/Makefile.am
index a029bc97b..b1e8855c7 100644
--- a/src/theory/arith/Makefile.am
+++ b/src/theory/arith/Makefile.am
@@ -36,7 +36,9 @@ libarith_la_SOURCES = \
theory_arith.h \
theory_arith.cpp \
dio_solver.h \
- dio_solver.cpp
+ dio_solver.cpp \
+ theory_arith_instantiator.h \
+ theory_arith_instantiator.cpp
EXTRA_DIST = \
kinds
diff --git a/src/theory/arith/congruence_manager.h b/src/theory/arith/congruence_manager.h
index 5f49ab3ab..63a370f9a 100644
--- a/src/theory/arith/congruence_manager.h
+++ b/src/theory/arith/congruence_manager.h
@@ -73,7 +73,12 @@ private:
d_acm.propagate(t1.eqNode(t2));
}
}
- };
+
+ void eqNotifyNewClass(TNode t) { }
+ void eqNotifyPreMerge(TNode t1, TNode t2) { }
+ void eqNotifyPostMerge(TNode t1, TNode t2) { }
+ void eqNotifyDisequal(TNode t1, TNode t2, TNode reason) { }
+ };
ArithCongruenceNotify d_notify;
context::CDList<Node> d_keepAlive;
diff --git a/src/theory/arith/kinds b/src/theory/arith/kinds
index 8ffe68376..c06cbc140 100644
--- a/src/theory/arith/kinds
+++ b/src/theory/arith/kinds
@@ -6,6 +6,7 @@
theory THEORY_ARITH ::CVC4::theory::arith::TheoryArith "theory/arith/theory_arith.h"
typechecker "theory/arith/theory_arith_type_rules.h"
+instantiator ::CVC4::theory::arith::InstantiatorTheoryArith "theory/arith/theory_arith_instantiator.h"
properties stable-infinite
properties check propagate staticLearning presolve notifyRestart
diff --git a/src/theory/arith/theory_arith.cpp b/src/theory/arith/theory_arith.cpp
index ac9796986..9ff9ceeb9 100644
--- a/src/theory/arith/theory_arith.cpp
+++ b/src/theory/arith/theory_arith.cpp
@@ -53,8 +53,8 @@ namespace arith {
const uint32_t RESET_START = 2;
-TheoryArith::TheoryArith(context::Context* c, context::UserContext* u, OutputChannel& out, Valuation valuation, const LogicInfo& logicInfo) :
- Theory(THEORY_ARITH, c, u, out, valuation, logicInfo),
+TheoryArith::TheoryArith(context::Context* c, context::UserContext* u, OutputChannel& out, Valuation valuation, const LogicInfo& logicInfo, QuantifiersEngine* qe) :
+ Theory(THEORY_ARITH, c, u, out, valuation, logicInfo, qe),
d_hasDoneWorkSinceCut(false),
d_learner(d_pbSubstitutions),
d_setupLiteralCallback(this),
diff --git a/src/theory/arith/theory_arith.h b/src/theory/arith/theory_arith.h
index ebc131b60..1f0120387 100644
--- a/src/theory/arith/theory_arith.h
+++ b/src/theory/arith/theory_arith.h
@@ -53,12 +53,15 @@ namespace CVC4 {
namespace theory {
namespace arith {
+class InstantiatorTheoryArith;
+
/**
* Implementation of QF_LRA.
* Based upon:
* http://research.microsoft.com/en-us/um/people/leonardo/cav06.pdf
*/
class TheoryArith : public Theory {
+ friend class InstantiatorTheoryArith;
private:
bool rowImplication(ArithVar v, bool upperBound, const DeltaRational& r);
@@ -269,7 +272,7 @@ private:
DeltaRational getDeltaValue(TNode n);
public:
- TheoryArith(context::Context* c, context::UserContext* u, OutputChannel& out, Valuation valuation, const LogicInfo& logicInfo);
+ TheoryArith(context::Context* c, context::UserContext* u, OutputChannel& out, Valuation valuation, const LogicInfo& logicInfo, QuantifiersEngine* qe);
virtual ~TheoryArith();
/**
diff --git a/src/theory/arith/theory_arith_instantiator.cpp b/src/theory/arith/theory_arith_instantiator.cpp
new file mode 100644
index 000000000..48c8a30ee
--- /dev/null
+++ b/src/theory/arith/theory_arith_instantiator.cpp
@@ -0,0 +1,448 @@
+/********************* */
+/*! \file instantiator_arith_instantiator.cpp
+ ** \verbatim
+ ** Original author: ajreynol
+ ** Major contributors: none
+ ** Minor contributors (to current version): none
+ ** This file is part of the CVC4 prototype.
+ ** Copyright (c) 2009, 2010, 2011 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
+ ** information.\endverbatim
+ **
+ ** \brief Implementation of instantiator_arith_instantiator class
+ **/
+
+#include "theory/arith/theory_arith_instantiator.h"
+#include "theory/arith/theory_arith.h"
+#include "theory/theory_engine.h"
+
+using namespace std;
+using namespace CVC4;
+using namespace CVC4::kind;
+using namespace CVC4::context;
+using namespace CVC4::theory;
+using namespace CVC4::theory::arith;
+
+#define ARITH_INSTANTIATOR_USE_DELTA
+#define ARITH_INSTANTIATOR_USE_MINUS_DELTA
+#define ARITH_INSTANTIATOR_STRONG_DELTA_LEMMA
+
+#define USE_ARITH_INSTANTIATION
+
+InstStrategySimplex::InstStrategySimplex( InstantiatorTheoryArith* th, QuantifiersEngine* ie ) :
+ InstStrategy( ie ), d_th( th ), d_counter( 0 ){
+ d_negOne = NodeManager::currentNM()->mkConst( Rational(-1) );
+}
+
+void InstStrategySimplex::processResetInstantiationRound( Theory::Effort effort ){
+ d_counter++;
+}
+
+int InstStrategySimplex::process( Node f, Theory::Effort effort, int e, int instLimit ){
+ if( e<2 ){
+ return STATUS_UNFINISHED;
+ }else if( e==2 ){
+ //Notice() << f << std::endl;
+ //Notice() << "Num inst rows = " << d_th->d_instRows[f].size() << std::endl;
+ //Notice() << "Num inst constants = " << d_quantEngine->getNumInstantiationConstants( f ) << std::endl;
+ Debug("quant-arith-simplex") << "InstStrategySimplex check " << f << ", rows = " << d_th->d_instRows[f].size() << std::endl;
+ for( int j=0; j<(int)d_th->d_instRows[f].size(); j++ ){
+ ArithVar x = d_th->d_instRows[f][j];
+ if( !d_th->d_ceTableaux[x].empty() ){
+ Debug("quant-arith-simplex") << "Check row " << x << std::endl;
+ //instantiation row will be A*e + B*t = beta,
+ // where e is a vector of terms , and t is vector of ground terms.
+ // Say one term in A*e is coeff*e_i, where e_i is an instantiation constant
+ // We will construct the term ( beta - B*t)/coeff to use for e_i.
+ InstMatch m;
+ //By default, choose the first instantiation constant to be e_i.
+ Node var = d_th->d_ceTableaux[x].begin()->first;
+ if( var.getType().isInteger() ){
+ std::map< Node, Node >::iterator it = d_th->d_ceTableaux[x].begin();
+ //try to find coefficent that is +/- 1
+ while( !var.isNull() && !d_th->d_ceTableaux[x][var].isNull() && d_th->d_ceTableaux[x][var]!=d_negOne ){
+ ++it;
+ if( it==d_th->d_ceTableaux[x].end() ){
+ var = Node::null();
+ }else{
+ var = it->first;
+ }
+ }
+ //otherwise, try one that divides all ground term coefficients? DO_THIS
+ }
+ if( !var.isNull() ){
+ Debug("quant-arith-simplex") << "Instantiate with var " << var << std::endl;
+ d_th->doInstantiation( f, d_th->d_tableaux_term[x], x, m, var );
+ }else{
+ Debug("quant-arith-simplex") << "Could not find var." << std::endl;
+ }
+ ////choose a new variable based on alternation strategy
+ //int index = d_counter%(int)d_th->d_ceTableaux[x].size();
+ //Node var;
+ //for( std::map< Node, Node >::iterator it = d_th->d_ceTableaux[x].begin(); it != d_th->d_ceTableaux[x].end(); ++it ){
+ // if( index==0 ){
+ // var = it->first;
+ // break;
+ // }
+ // index--;
+ //}
+ //d_th->doInstantiation( f, d_th->d_tableaux_term[x], x, &m, var );
+ }
+ }
+ }
+ return STATUS_UNKNOWN;
+}
+
+//void InstStrategySimplexUfMatch::resetInstantiationRound(){
+//
+//}
+//
+//int InstStrategySimplexUfMatch::process( Node f, int effort, int instLimit ){
+// if( effort<2 ){
+// return STATUS_UNFINISHED;
+// }else if( effort==2 ){
+// for( int j=0; j<(int)d_th->d_instRows[f].size(); j++ ){
+// ArithVar x = d_th->d_instRows[f][j];
+// if( !d_th->d_ceTableaux[x].empty() && !d_th->d_tableaux_ce_term[x].empty() ){
+// if( d_tableaux_ce_term_trigger.find( x )==d_tableaux_ce_term_trigger.end() ){
+// std::vector< Node > terms;
+// for( std::map< Node, Node >::iterator it = d_th->d_tableaux_ce_term[x].begin(); it != d_th->d_tableaux_ce_term[x].end(); ++it ){
+// terms.push_back( it->first );
+// }
+// d_tableaux_ce_term_trigger[x] = new Trigger( d_quantEngine, f, terms );
+// }else{
+// d_tableaux_ce_term_trigger[x]->resetInstantiationRound();
+// }
+// Node term;
+// bool addedLemma = false;
+// while( d_tableaux_ce_term_trigger[x]->getNextMatch() && !addedLemma ){
+// InstMatch* m = d_tableaux_ce_term_trigger[x]->getCurrent();
+// if( m->isComplete( f ) ){
+// if( d_quantEngine->addInstantiation( f, m, true ) ){
+// ++(d_th->d_statistics.d_instantiations_match_pure);
+// ++(d_th->d_statistics.d_instantiations);
+// addedLemma = true;
+// }
+// }else{
+// NodeBuilder<> plus_term(kind::PLUS);
+// plus_term << d_th->d_tableaux_term[x];
+// //Debug("quant-arith") << "Produced this match for ce_term_tableaux: " << std::endl;
+// //m->debugPrint("quant-arith");
+// //Debug("quant-arith") << std::endl;
+// std::vector< Node > vars;
+// std::vector< Node > matches;
+// for( int i=0; i<d_quantEngine->getNumInstantiationConstants( f ); i++ ){
+// Node ic = d_quantEngine->getInstantiationConstant( f, i );
+// if( m->d_map[ ic ]!=Node::null() ){
+// vars.push_back( ic );
+// matches.push_back( m->d_map[ ic ] );
+// }
+// }
+// Node var;
+// //otherwise try to find a variable that is not specified in m
+// for( std::map< Node, Node >::iterator it = d_th->d_ceTableaux[x].begin(); it != d_th->d_ceTableaux[x].end(); ++it ){
+// if( m->d_map[ it->first ]!=Node::null() ){
+// plus_term << NodeManager::currentNM()->mkNode( MULT, it->second, d_th->getTableauxValue( m->d_map[ it->first ] ) );
+// }else if( var==Node::null() ){
+// var = it->first;
+// }
+// }
+// for( std::map< Node, Node >::iterator it = d_th->d_tableaux_ce_term[x].begin(); it != d_th->d_tableaux_ce_term[x].end(); ++it ){
+// Node n = it->first;
+// //substitute in matches
+// n = n.substitute( vars.begin(), vars.end(), matches.begin(), matches.end() );
+// plus_term << NodeManager::currentNM()->mkNode( MULT, it->second, d_th->getTableauxValue( n ) );
+// }
+// term = plus_term.getNumChildren()==1 ? plus_term.getChild( 0 ) : plus_term;
+// if( var!=Node::null() ){
+// if( d_th->doInstantiation( f, term, x, m, var ) ){
+// addedLemma = true;
+// ++(d_th->d_statistics.d_instantiations_match_var);
+// }
+// }else{
+// if( d_quantEngine->addInstantiation( f, m, true ) ){
+// addedLemma = true;
+// ++(d_th->d_statistics.d_instantiations_match_no_var);
+// ++(d_th->d_statistics.d_instantiations);
+// }
+// }
+// }
+// }
+// }
+// }
+// }
+// return STATUS_UNKNOWN;
+//}
+
+InstantiatorTheoryArith::InstantiatorTheoryArith(context::Context* c, QuantifiersEngine* ie, Theory* th) :
+Instantiator( c, ie, th ){
+ if( Options::current()->cbqi ){
+ addInstStrategy( new InstStrategySimplex( this, d_quantEngine ) );
+ }
+}
+
+void InstantiatorTheoryArith::preRegisterTerm( Node t ){
+
+}
+
+void InstantiatorTheoryArith::assertNode( Node assertion ){
+ Debug("quant-arith-assert") << "InstantiatorTheoryArith::check: " << assertion << std::endl;
+ d_quantEngine->addTermToDatabase( assertion );
+ if( Options::current()->cbqi ){
+ if( assertion.hasAttribute(InstConstantAttribute()) ){
+ setHasConstraintsFrom( assertion.getAttribute(InstConstantAttribute()) );
+ }else if( assertion.getKind()==NOT && assertion[0].hasAttribute(InstConstantAttribute()) ){
+ setHasConstraintsFrom( assertion[0].getAttribute(InstConstantAttribute()) );
+ }
+ }
+}
+
+void InstantiatorTheoryArith::processResetInstantiationRound( Theory::Effort effort ){
+ if( Options::current()->cbqi ){
+ Debug("quant-arith") << "Setting up simplex for instantiator... " << std::endl;
+ d_instRows.clear();
+ d_tableaux_term.clear();
+ d_tableaux.clear();
+ d_ceTableaux.clear();
+ //search for instantiation rows in simplex tableaux
+ ArithVarToNodeMap avtnm = ((TheoryArith*)getTheory())->d_arithvarNodeMap.getArithVarToNodeMap();
+ for( ArithVarToNodeMap::iterator it = avtnm.begin(); it != avtnm.end(); ++it ){
+ ArithVar x = (*it).first;
+ if( ((TheoryArith*)getTheory())->d_partialModel.hasEitherBound( x ) ){
+ Node n = (*it).second;
+ Node f;
+ NodeBuilder<> t(kind::PLUS);
+ if( n.getKind()==PLUS ){
+ for( int i=0; i<(int)n.getNumChildren(); i++ ){
+ addTermToRow( x, n[i], f, t );
+ }
+ }else{
+ addTermToRow( x, n, f, t );
+ }
+ if( f!=Node::null() ){
+ d_instRows[f].push_back( x );
+ //this theory has constraints from f
+ Debug("quant-arith") << "Has constraints from " << f << std::endl;
+ setHasConstraintsFrom( f );
+ //set tableaux term
+ if( t.getNumChildren()==0 ){
+ d_tableaux_term[x] = NodeManager::currentNM()->mkConst( Rational(0) );
+ }else if( t.getNumChildren()==1 ){
+ d_tableaux_term[x] = t.getChild( 0 );
+ }else{
+ d_tableaux_term[x] = t;
+ }
+ }
+ }
+ }
+ //print debug
+ debugPrint( "quant-arith-debug" );
+ }
+}
+
+int InstantiatorTheoryArith::process( Node f, Theory::Effort effort, int e, int instLimit ){
+ Debug("quant-arith") << "Arith: Try to solve (" << effort << ") for " << f << "... " << std::endl;
+ return InstStrategy::STATUS_UNKNOWN;
+}
+
+void InstantiatorTheoryArith::addTermToRow( ArithVar x, Node n, Node& f, NodeBuilder<>& t ){
+ if( n.getKind()==MULT ){
+ if( n[1].hasAttribute(InstConstantAttribute()) ){
+ f = n[1].getAttribute(InstConstantAttribute());
+ if( n[1].getKind()==INST_CONSTANT ){
+ d_ceTableaux[x][ n[1] ] = n[0];
+ }else{
+ d_tableaux_ce_term[x][ n[1] ] = n[0];
+ }
+ }else{
+ d_tableaux[x][ n[1] ] = n[0];
+ t << n;
+ }
+ }else{
+ if( n.hasAttribute(InstConstantAttribute()) ){
+ f = n.getAttribute(InstConstantAttribute());
+ if( n.getKind()==INST_CONSTANT ){
+ d_ceTableaux[x][ n ] = Node::null();
+ }else{
+ d_tableaux_ce_term[x][ n ] = NodeManager::currentNM()->mkConst( Rational(1) );
+ }
+ }else{
+ d_tableaux[x][ n ] = NodeManager::currentNM()->mkConst( Rational(1) );
+ t << n;
+ }
+ }
+}
+
+void InstantiatorTheoryArith::debugPrint( const char* c ){
+ ArithVarToNodeMap avtnm = ((TheoryArith*)getTheory())->d_arithvarNodeMap.getArithVarToNodeMap();
+ for( ArithVarToNodeMap::iterator it = avtnm.begin(); it != avtnm.end(); ++it ){
+ ArithVar x = (*it).first;
+ Node n = (*it).second;
+ //if( ((TheoryArith*)getTheory())->d_partialModel.hasEitherBound( x ) ){
+ Debug(c) << x << " : " << n << ", bounds = ";
+ if( ((TheoryArith*)getTheory())->d_partialModel.hasLowerBound( x ) ){
+ Debug(c) << ((TheoryArith*)getTheory())->d_partialModel.getLowerBound( x );
+ }else{
+ Debug(c) << "-infty";
+ }
+ Debug(c) << " <= ";
+ Debug(c) << ((TheoryArith*)getTheory())->d_partialModel.getAssignment( x );
+ Debug(c) << " <= ";
+ if( ((TheoryArith*)getTheory())->d_partialModel.hasUpperBound( x ) ){
+ Debug(c) << ((TheoryArith*)getTheory())->d_partialModel.getUpperBound( x );
+ }else{
+ Debug(c) << "+infty";
+ }
+ Debug(c) << std::endl;
+ //Debug(c) << " Term = " << d_tableaux_term[x] << std::endl;
+ //Debug(c) << " ";
+ //for( std::map< Node, Node >::iterator it2 = d_tableaux[x].begin(); it2 != d_tableaux[x].end(); ++it2 ){
+ // Debug(c) << "( " << it2->first << ", " << it2->second << " ) ";
+ //}
+ //for( std::map< Node, Node >::iterator it2 = d_ceTableaux[x].begin(); it2 != d_ceTableaux[x].end(); ++it2 ){
+ // Debug(c) << "(CE)( " << it2->first << ", " << it2->second << " ) ";
+ //}
+ //for( std::map< Node, Node >::iterator it2 = d_tableaux_ce_term[x].begin(); it2 != d_tableaux_ce_term[x].end(); ++it2 ){
+ // Debug(c) << "(CE-term)( " << it2->first << ", " << it2->second << " ) ";
+ //}
+ //Debug(c) << std::endl;
+ //}
+ }
+ Debug(c) << std::endl;
+
+ for( int q=0; q<d_quantEngine->getNumQuantifiers(); q++ ){
+ Node f = d_quantEngine->getQuantifier( q );
+ Debug(c) << f << std::endl;
+ Debug(c) << " Inst constants: ";
+ for( int i=0; i<(int)d_quantEngine->getNumInstantiationConstants( f ); i++ ){
+ if( i>0 ){
+ Debug( c ) << ", ";
+ }
+ Debug( c ) << d_quantEngine->getInstantiationConstant( f, i );
+ }
+ Debug(c) << std::endl;
+ Debug(c) << " Instantiation rows: ";
+ for( int i=0; i<(int)d_instRows[f].size(); i++ ){
+ if( i>0 ){
+ Debug(c) << ", ";
+ }
+ Debug(c) << d_instRows[f][i];
+ }
+ Debug(c) << std::endl;
+ }
+}
+
+//say instantiation row x for quantifier f is coeff*var + A*t[e] + term = beta,
+// where var is an instantiation constant from f,
+// t[e] is a vector of terms containing instantiation constants from f,
+// and term is a ground term (c1*t1 + ... + cn*tn).
+// We construct the term ( beta - term )/coeff to use as an instantiation for var.
+bool InstantiatorTheoryArith::doInstantiation( Node f, Node term, ArithVar x, InstMatch& m, Node var ){
+ //first try +delta
+ if( doInstantiation2( f, term, x, m, var ) ){
+ ++(d_statistics.d_instantiations);
+ return true;
+ }else{
+#ifdef ARITH_INSTANTIATOR_USE_MINUS_DELTA
+ //otherwise try -delta
+ if( doInstantiation2( f, term, x, m, var, true ) ){
+ ++(d_statistics.d_instantiations_minus);
+ ++(d_statistics.d_instantiations);
+ return true;
+ }else{
+ return false;
+ }
+#else
+ return false;
+#endif
+ }
+}
+
+bool InstantiatorTheoryArith::doInstantiation2( Node f, Node term, ArithVar x, InstMatch& m, Node var, bool minus_delta ){
+ // make term ( beta - term )/coeff
+ Node beta = getTableauxValue( x, minus_delta );
+ Node instVal = NodeManager::currentNM()->mkNode( MINUS, beta, term );
+ if( !d_ceTableaux[x][var].isNull() ){
+ if( var.getType().isInteger() ){
+ Assert( d_ceTableaux[x][var]==NodeManager::currentNM()->mkConst( Rational(-1) ) );
+ instVal = NodeManager::currentNM()->mkNode( MULT, d_ceTableaux[x][var], instVal );
+ }else{
+ Node coeff = NodeManager::currentNM()->mkConst( Rational(1) / d_ceTableaux[x][var].getConst<Rational>() );
+ instVal = NodeManager::currentNM()->mkNode( MULT, coeff, instVal );
+ }
+ }
+ instVal = Rewriter::rewrite( instVal );
+ //use as instantiation value for var
+ m.d_map[ var ] = instVal;
+ Debug("quant-arith") << "Add instantiation " << m << std::endl;
+ return d_quantEngine->addInstantiation( f, m, true );
+}
+
+Node InstantiatorTheoryArith::getTableauxValue( Node n, bool minus_delta ){
+ if( ((TheoryArith*)getTheory())->d_arithvarNodeMap.hasArithVar(n) ){
+ ArithVar v = ((TheoryArith*)getTheory())->d_arithvarNodeMap.asArithVar( n );
+ return getTableauxValue( v, minus_delta );
+ }else{
+ return NodeManager::currentNM()->mkConst( Rational(0) );
+ }
+}
+
+Node InstantiatorTheoryArith::getTableauxValue( ArithVar v, bool minus_delta ){
+ DeltaRational drv = ((TheoryArith*)getTheory())->d_partialModel.getAssignment( v );
+ Node val = NodeManager::currentNM()->mkConst( drv.getNoninfinitesimalPart() );
+#ifdef ARITH_INSTANTIATOR_USE_DELTA
+ //the tableaux value for v may contain an infinitesemal part: getDelta( val ) will return a fresh variable "delta"
+ // (one for each sort) for which the lemma ( delta > 0 ) is asserted.
+ if( drv.getInfinitesimalPart()!=0 ){
+ Node delta = NodeManager::currentNM()->mkNode( MULT, getDelta( val ),
+ NodeManager::currentNM()->mkConst( drv.getInfinitesimalPart() ) );
+ // add (or subtract) this delta component from the value of v
+ val = NodeManager::currentNM()->mkNode( minus_delta ? MINUS : PLUS, val, delta );
+ }
+#endif
+ return val;
+}
+
+Node InstantiatorTheoryArith::getDelta( Node n ){
+ std::map< TypeNode, Node >::iterator it = d_deltas.find( n.getType() );
+ if( it==d_deltas.end() ){
+ std::ostringstream os;
+ os << "delta_" << d_deltas.size();
+ Node delta = NodeManager::currentNM()->mkVar( os.str(), n.getType() );
+ d_deltas[ n.getType() ] = delta;
+ Node gt = NodeManager::currentNM()->mkNode( GT, delta, NodeManager::currentNM()->mkConst( Rational(0) ) );
+ //add split
+#ifdef ARITH_INSTANTIATOR_STRONG_DELTA_LEMMA
+ d_quantEngine->addLemma( gt );
+#else
+ gt = Rewriter::rewrite( gt );
+ d_quantEngine->addSplit( gt, true, true );
+#endif
+ return delta;
+ }
+ return it->second;
+}
+
+InstantiatorTheoryArith::Statistics::Statistics():
+ d_instantiations("InstantiatorTheoryArith::Instantiations_Total", 0),
+ d_instantiations_minus("InstantiatorTheoryArith::Instantiations_minus_delta", 0),
+ d_instantiations_match_pure("InstantiatorTheoryArith::Instantiations_via_pure_matching", 0),
+ d_instantiations_match_var("InstantiatorTheoryArith::Instantiations_via_matching_var", 0),
+ d_instantiations_match_no_var("InstantiatorTheoryArith::Instantiations_via_matching_no_var", 0)
+{
+ StatisticsRegistry::registerStat(&d_instantiations);
+ StatisticsRegistry::registerStat(&d_instantiations_minus);
+ StatisticsRegistry::registerStat(&d_instantiations_match_pure);
+ StatisticsRegistry::registerStat(&d_instantiations_match_var);
+ StatisticsRegistry::registerStat(&d_instantiations_match_no_var);
+}
+
+InstantiatorTheoryArith::Statistics::~Statistics(){
+ StatisticsRegistry::unregisterStat(&d_instantiations);
+ StatisticsRegistry::unregisterStat(&d_instantiations_minus);
+ StatisticsRegistry::unregisterStat(&d_instantiations_match_pure);
+ StatisticsRegistry::unregisterStat(&d_instantiations_match_var);
+ StatisticsRegistry::unregisterStat(&d_instantiations_match_no_var);
+}
diff --git a/src/theory/arith/theory_arith_instantiator.h b/src/theory/arith/theory_arith_instantiator.h
new file mode 100644
index 000000000..524d16859
--- /dev/null
+++ b/src/theory/arith/theory_arith_instantiator.h
@@ -0,0 +1,128 @@
+/********************* */
+/*! \file instantiator_arith_instantiator.h
+ ** \verbatim
+ ** Original author: ajreynol
+ ** Major contributors: none
+ ** Minor contributors (to current version): none
+ ** This file is part of the CVC4 prototype.
+ ** Copyright (c) 2009, 2010, 2011 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
+ ** information.\endverbatim
+ **
+ ** \brief instantiator_arith_instantiator
+ **/
+
+
+#include "cvc4_private.h"
+
+#ifndef __CVC4__INSTANTIATOR_ARITH_H
+#define __CVC4__INSTANTIATOR_ARITH_H
+
+#include "theory/quantifiers_engine.h"
+#include "theory/arith/arithvar_node_map.h"
+
+#include "util/stats.h"
+
+namespace CVC4 {
+namespace theory {
+namespace arith {
+
+class InstantiatorTheoryArith;
+
+class InstStrategySimplex : public InstStrategy{
+private:
+ /** InstantiatorTheoryUf class */
+ InstantiatorTheoryArith* d_th;
+ /** */
+ int d_counter;
+ /** negative one */
+ Node d_negOne;
+ /** process functions */
+ void processResetInstantiationRound( Theory::Effort effort );
+ int process( Node f, Theory::Effort effort, int e, int instLimit );
+public:
+ InstStrategySimplex( InstantiatorTheoryArith* th, QuantifiersEngine* ie );
+ ~InstStrategySimplex(){}
+ /** identify */
+ std::string identify() const { return std::string("Simplex"); }
+};
+//
+//class InstStrategySimplexUfMatch : public InstStrategy{
+//private:
+// /** InstantiatorTheoryUf class */
+// InstantiatorTheoryArith* d_th;
+// /** trigger for instantiation rows */
+// std::map< ArithVar, Trigger* > d_tableaux_ce_term_trigger;
+//public:
+// InstStrategySimplexUfMatch( InstantiatorTheoryArith* th, QuantifiersEngine* ie ) :
+// InstStrategy( ie ), d_th( th ){}
+// ~InstStrategySimplexUfMatch(){}
+// void resetInstantiationRound();
+// int process( Node f, Theory::Effort effort, int e, int instLimit );
+// /** identify */
+// std::string identify() const { return std::string("SimplexUfMatch"); }
+//};
+
+class InstantiatorTheoryArith : public Instantiator{
+ friend class QuantifiersEngine;
+ friend class InstStrategySimplex;
+ friend class InstStrategySimplexUfMatch;
+private:
+ /** delta */
+ std::map< TypeNode, Node > d_deltas;
+ /** for each quantifier, simplex rows */
+ std::map< Node, std::vector< ArithVar > > d_instRows;
+ /** tableaux */
+ std::map< ArithVar, Node > d_tableaux_term;
+ std::map< ArithVar, std::map< Node, Node > > d_tableaux_ce_term;
+ std::map< ArithVar, std::map< Node, Node > > d_tableaux;
+ /** ce tableaux */
+ std::map< ArithVar, std::map< Node, Node > > d_ceTableaux;
+ /** get value */
+ Node getTableauxValue( Node n, bool minus_delta = false );
+ Node getTableauxValue( ArithVar v, bool minus_delta = false );
+ /** do instantiation */
+ bool doInstantiation( Node f, Node term, ArithVar x, InstMatch& m, Node var );
+ bool doInstantiation2( Node f, Node term, ArithVar x, InstMatch& m, Node var, bool minus_delta = false );
+public:
+ InstantiatorTheoryArith(context::Context* c, QuantifiersEngine* ie, Theory* th);
+ ~InstantiatorTheoryArith() {}
+
+ /** assertNode function, assertion is asserted to theory */
+ void assertNode( Node assertion );
+ /** Pre-register a term. Done one time for a Node, ever. */
+ void preRegisterTerm( Node t );
+ /** identify */
+ std::string identify() const { return std::string("InstantiatorTheoryArith"); }
+ /** print debug */
+ void debugPrint( const char* c );
+private:
+ /** reset instantiation */
+ void processResetInstantiationRound( Theory::Effort effort );
+ /** process at effort */
+ int process( Node f, Theory::Effort effort, int e, int instLimit );
+ /** add term to row */
+ void addTermToRow( ArithVar x, Node n, Node& f, NodeBuilder<>& t );
+ /** get delta for node */
+ Node getDelta( Node n );
+
+ class Statistics {
+ public:
+ IntStat d_instantiations;
+ IntStat d_instantiations_minus;
+ IntStat d_instantiations_match_pure;
+ IntStat d_instantiations_match_var;
+ IntStat d_instantiations_match_no_var;
+ Statistics();
+ ~Statistics();
+ };
+ Statistics d_statistics;
+};/* class InstantiatiorTheoryArith */
+
+}
+}
+}
+
+#endif \ No newline at end of file
diff --git a/src/theory/arrays/Makefile.am b/src/theory/arrays/Makefile.am
index 3dde70145..57c55d765 100644
--- a/src/theory/arrays/Makefile.am
+++ b/src/theory/arrays/Makefile.am
@@ -15,6 +15,8 @@ libarrays_la_SOURCES = \
array_info.h \
array_info.cpp \
static_fact_manager.h \
- static_fact_manager.cpp
+ static_fact_manager.cpp \
+ theory_arrays_instantiator.h \
+ theory_arrays_instantiator.cpp
EXTRA_DIST = kinds
diff --git a/src/theory/arrays/kinds b/src/theory/arrays/kinds
index 06240a315..195a60035 100644
--- a/src/theory/arrays/kinds
+++ b/src/theory/arrays/kinds
@@ -6,6 +6,7 @@
theory THEORY_ARRAY ::CVC4::theory::arrays::TheoryArrays "theory/arrays/theory_arrays.h"
typechecker "theory/arrays/theory_arrays_type_rules.h"
+instantiator ::CVC4::theory::arrays::InstantiatorTheoryArrays "theory/arrays/theory_arrays_instantiator.h"
properties polite stable-infinite parametric
properties check propagate presolve
diff --git a/src/theory/arrays/theory_arrays.cpp b/src/theory/arrays/theory_arrays.cpp
index 81661acd1..376a7e90f 100644
--- a/src/theory/arrays/theory_arrays.cpp
+++ b/src/theory/arrays/theory_arrays.cpp
@@ -23,6 +23,7 @@
#include <map>
#include "theory/rewriter.h"
#include "expr/command.h"
+#include "theory/arrays/theory_arrays_instantiator.h"
using namespace std;
@@ -45,8 +46,8 @@ const bool d_solveWrite2 = false;
const bool d_useNonLinearOpt = true;
const bool d_eagerIndexSplitting = true;
-TheoryArrays::TheoryArrays(context::Context* c, context::UserContext* u, OutputChannel& out, Valuation valuation, const LogicInfo& logicInfo) :
- Theory(THEORY_ARRAY, c, u, out, valuation, logicInfo),
+TheoryArrays::TheoryArrays(context::Context* c, context::UserContext* u, OutputChannel& out, Valuation valuation, const LogicInfo& logicInfo, QuantifiersEngine* qe) :
+ Theory(THEORY_ARRAY, c, u, out, valuation, logicInfo, qe),
d_numRow("theory::arrays::number of Row lemmas", 0),
d_numExt("theory::arrays::number of Ext lemmas", 0),
d_numProp("theory::arrays::number of propagations", 0),
@@ -218,7 +219,7 @@ Node TheoryArrays::ppRewrite(TNode term) {
}
Node r1 = nm->mkNode(kind::SELECT, e1, index_i);
- conc = (r1.getType() == nm->booleanType())?
+ conc = (r1.getType() == nm->booleanType())?
r1.iffNode(write_i[2]) : r1.eqNode(write_i[2]);
if (hyp.getNumChildren() != 0) {
if (hyp.getNumChildren() == 1) {
@@ -582,7 +583,6 @@ void TheoryArrays::computeCareGraph()
// Get representative trigger terms
TNode x_shared = d_equalityEngine.getTriggerTermRepresentative(x, THEORY_ARRAY);
TNode y_shared = d_equalityEngine.getTriggerTermRepresentative(y, THEORY_ARRAY);
-
EqualityStatus eqStatusDomain = d_valuation.getEqualityStatus(x_shared, y_shared);
switch (eqStatusDomain) {
case EQUALITY_TRUE_AND_PROPAGATED:
@@ -605,6 +605,7 @@ void TheoryArrays::computeCareGraph()
break;
}
+
// Otherwise, add this pair
Debug("arrays::sharing") << "TheoryArrays::computeCareGraph(): adding to care-graph" << std::endl;
addCarePair(x_shared, y_shared);
diff --git a/src/theory/arrays/theory_arrays.h b/src/theory/arrays/theory_arrays.h
index 80fe692c0..1bf42a105 100644
--- a/src/theory/arrays/theory_arrays.h
+++ b/src/theory/arrays/theory_arrays.h
@@ -39,32 +39,32 @@ namespace arrays {
* Overview of decision procedure:
*
* Preliminary notation:
- * Stores(a) = {t | a ~ t and t = store( _ _ _ )}
+ * Stores(a) = {t | a ~ t and t = store( _ _ _ )}
* InStores(a) = {t | t = store (b _ _) and a ~ b }
* Indices(a) = {i | there exists a term b[i] such that a ~ b or store(b i v)}
* ~ represents the equivalence relation based on the asserted equalities in the
* current context.
- *
+ *
* The rules implemented are the following:
* store(b i v)
* Row1 -------------------
* store(b i v)[i] = v
- *
+ *
* store(b i v) a'[j]
* Row ---------------------- [ a' ~ store(b i v) or a' ~ b ]
* i = j OR a[j] = b[j]
- *
+ *
* a b same kind arrays
* Ext ------------------------ [ a!= b in current context, k new var]
* a = b OR a[k] != b[k]p
- *
- *
+ *
+ *
* The Row1 one rule is implemented implicitly as follows:
* - for each store(b i v) term add the following equality to the congruence
* closure store(b i v)[i] = v
* - if one of the literals in a conflict is of the form store(b i v)[i] = v
* remove it from the conflict
- *
+ *
* Because new store terms are not created, we need to check if we need to
* instantiate a new Row axiom in the following cases:
* 1. the congruence relation changes (i.e. two terms get merged)
@@ -77,7 +77,7 @@ namespace arrays {
* - this is implemented in the checkRowForIndex method which is called
* when preregistering a term of the form a[i].
* - as a consequence lemmas are instantiated even before full effort check
- *
+ *
* The Ext axiom is instantiated when a disequality is asserted during full effort
* check. Ext lemmas are stored in a cache to prevent instantiating essentially
* the same lemma multiple times.
@@ -122,7 +122,7 @@ class TheoryArrays : public Theory {
public:
- TheoryArrays(context::Context* c, context::UserContext* u, OutputChannel& out, Valuation valuation, const LogicInfo& logicInfo);
+ TheoryArrays(context::Context* c, context::UserContext* u, OutputChannel& out, Valuation valuation, const LogicInfo& logicInfo, QuantifiersEngine* qe);
~TheoryArrays();
std::string identify() const { return std::string("TheoryArrays"); }
@@ -133,6 +133,16 @@ class TheoryArrays : public Theory {
private:
+ // PPNotifyClass: dummy template class for d_ppEqualityEngine - notifications not used
+ class PPNotifyClass {
+ public:
+ bool notify(TNode propagation) { return true; }
+ void notify(TNode t1, TNode t2) { }
+ };
+
+ /** The notify class for d_ppEqualityEngine */
+ PPNotifyClass d_ppNotify;
+
/** Equaltity engine */
eq::EqualityEngine d_ppEqualityEngine;
@@ -181,6 +191,15 @@ class TheoryArrays : public Theory {
private:
+ class MayEqualNotifyClass {
+ public:
+ bool notify(TNode propagation) { return true; }
+ void notify(TNode t1, TNode t2) { }
+ };
+
+ /** The notify class for d_mayEqualEqualityEngine */
+ MayEqualNotifyClass d_mayEqualNotify;
+
/** Equaltity engine for determining if two arrays might be equal */
eq::EqualityEngine d_mayEqualEqualityEngine;
@@ -270,6 +289,11 @@ class TheoryArrays : public Theory {
Debug("arrays::propagate") << spaces(d_arrays.getSatContext()->getLevel()) << "NotifyClass::eqNotifyConstantTermMerge(" << t1 << ", " << t2 << ")" << std::endl;
d_arrays.conflict(t1, t2);
}
+
+ void eqNotifyNewClass(TNode t) { }
+ void eqNotifyPreMerge(TNode t1, TNode t2) { }
+ void eqNotifyPostMerge(TNode t1, TNode t2) { }
+ void eqNotifyDisequal(TNode t1, TNode t2, TNode reason) { }
};
/** The notify class for d_equalityEngine */
diff --git a/src/theory/arrays/theory_arrays_instantiator.cpp b/src/theory/arrays/theory_arrays_instantiator.cpp
new file mode 100644
index 000000000..334d70eea
--- /dev/null
+++ b/src/theory/arrays/theory_arrays_instantiator.cpp
@@ -0,0 +1,56 @@
+/********************* */
+/*! \file theory_arrays_instantiator.cpp
+ ** \verbatim
+ ** Original author: ajreynol
+ ** Major contributors: none
+ ** Minor contributors (to current version): none
+ ** This file is part of the CVC4 prototype.
+ ** Copyright (c) 2009, 2010, 2011 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
+ ** information.\endverbatim
+ **
+ ** \brief Implementation of theory_arrays_instantiator class
+ **/
+
+#include "theory/theory_engine.h"
+#include "theory/arrays/theory_arrays_instantiator.h"
+#include "theory/arrays/theory_arrays.h"
+
+using namespace std;
+using namespace CVC4;
+using namespace CVC4::kind;
+using namespace CVC4::context;
+using namespace CVC4::theory;
+using namespace CVC4::theory::arrays;
+
+InstantiatorTheoryArrays::InstantiatorTheoryArrays(context::Context* c, QuantifiersEngine* ie, Theory* th) :
+Instantiator( c, ie, th ){
+
+}
+
+void InstantiatorTheoryArrays::preRegisterTerm( Node t ){
+
+}
+
+void InstantiatorTheoryArrays::assertNode( Node assertion ){
+ Debug("quant-arrays-assert") << "InstantiatorTheoryArrays::assertNode: " << assertion << std::endl;
+ d_quantEngine->addTermToDatabase( assertion );
+ if( Options::current()->cbqi ){
+ if( assertion.hasAttribute(InstConstantAttribute()) ){
+ setHasConstraintsFrom( assertion.getAttribute(InstConstantAttribute()) );
+ }else if( assertion.getKind()==NOT && assertion[0].hasAttribute(InstConstantAttribute()) ){
+ setHasConstraintsFrom( assertion[0].getAttribute(InstConstantAttribute()) );
+ }
+ }
+}
+
+
+void InstantiatorTheoryArrays::processResetInstantiationRound( Theory::Effort effort ){
+
+}
+
+int InstantiatorTheoryArrays::process( Node f, Theory::Effort effort, int e, int limitInst ){
+ return InstStrategy::STATUS_SAT;
+}
diff --git a/src/theory/arrays/theory_arrays_instantiator.h b/src/theory/arrays/theory_arrays_instantiator.h
new file mode 100644
index 000000000..6a7c9c3ed
--- /dev/null
+++ b/src/theory/arrays/theory_arrays_instantiator.h
@@ -0,0 +1,51 @@
+/********************* */
+/*! \file theory_arrays_instantiator.h
+ ** \verbatim
+ ** Original author: ajreynol
+ ** Major contributors: none
+ ** Minor contributors (to current version): none
+ ** This file is part of the CVC4 prototype.
+ ** Copyright (c) 2009, 2010, 2011 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
+ ** information.\endverbatim
+ **
+ ** \brief Instantiator for theory of arrays
+ **/
+
+
+#include "cvc4_private.h"
+
+#ifndef __CVC4__INSTANTIATOR_THEORY_ARRAYS_H
+#define __CVC4__INSTANTIATOR_THEORY_ARRAYS_H
+
+#include "theory/quantifiers_engine.h"
+
+namespace CVC4 {
+namespace theory {
+namespace arrays {
+
+class InstantiatorTheoryArrays : public Instantiator{
+ friend class QuantifiersEngine;
+protected:
+ /** reset instantiation round */
+ void processResetInstantiationRound( Theory::Effort effort );
+ /** process quantifier */
+ int process( Node f, Theory::Effort effort, int e, int limitInst = 0 );
+public:
+ InstantiatorTheoryArrays(context::Context* c, QuantifiersEngine* ie, Theory* th);
+ ~InstantiatorTheoryArrays() {}
+ /** Pre-register a term. */
+ void preRegisterTerm( Node t );
+ /** assertNode function, assertion is asserted to theory */
+ void assertNode( Node assertion );
+ /** identify */
+ std::string identify() const { return std::string("InstantiatorTheoryArrays"); }
+};/* class Instantiatior */
+
+}
+}
+}
+
+#endif \ No newline at end of file
diff --git a/src/theory/booleans/theory_bool.h b/src/theory/booleans/theory_bool.h
index 99b5b6007..40783a6ce 100644
--- a/src/theory/booleans/theory_bool.h
+++ b/src/theory/booleans/theory_bool.h
@@ -30,8 +30,8 @@ namespace booleans {
class TheoryBool : public Theory {
public:
- TheoryBool(context::Context* c, context::UserContext* u, OutputChannel& out, Valuation valuation, const LogicInfo& logicInfo) :
- Theory(THEORY_BOOL, c, u, out, valuation, logicInfo) {
+ TheoryBool(context::Context* c, context::UserContext* u, OutputChannel& out, Valuation valuation, const LogicInfo& logicInfo, QuantifiersEngine* qe) :
+ Theory(THEORY_BOOL, c, u, out, valuation, logicInfo, qe) {
}
Node getValue(TNode n);
diff --git a/src/theory/builtin/theory_builtin.h b/src/theory/builtin/theory_builtin.h
index 30d2aaca7..a13c69d9d 100644
--- a/src/theory/builtin/theory_builtin.h
+++ b/src/theory/builtin/theory_builtin.h
@@ -29,8 +29,8 @@ namespace builtin {
class TheoryBuiltin : public Theory {
public:
- TheoryBuiltin(context::Context* c, context::UserContext* u, OutputChannel& out, Valuation valuation, const LogicInfo& logicInfo) :
- Theory(THEORY_BUILTIN, c, u, out, valuation, logicInfo) {}
+ TheoryBuiltin(context::Context* c, context::UserContext* u, OutputChannel& out, Valuation valuation, const LogicInfo& logicInfo, QuantifiersEngine* qe) :
+ Theory(THEORY_BUILTIN, c, u, out, valuation, logicInfo, qe) {}
Node getValue(TNode n);
std::string identify() const { return std::string("TheoryBuiltin"); }
};/* class TheoryBuiltin */
diff --git a/src/theory/bv/bv_subtheory_eq.h b/src/theory/bv/bv_subtheory_eq.h
index d4239ff13..01178b453 100644
--- a/src/theory/bv/bv_subtheory_eq.h
+++ b/src/theory/bv/bv_subtheory_eq.h
@@ -40,6 +40,10 @@ class EqualitySolver : public SubtheorySolver {
bool eqNotifyTriggerPredicate(TNode predicate, bool value);
bool eqNotifyTriggerTermEquality(TheoryId tag, TNode t1, TNode t2, bool value);
void eqNotifyConstantTermMerge(TNode t1, TNode t2);
+ void eqNotifyNewClass(TNode t) { }
+ void eqNotifyPreMerge(TNode t1, TNode t2) { }
+ void eqNotifyPostMerge(TNode t1, TNode t2) { }
+ void eqNotifyDisequal(TNode t1, TNode t2, TNode reason) { }
};
diff --git a/src/theory/bv/theory_bv.cpp b/src/theory/bv/theory_bv.cpp
index 30493737a..66f443d50 100644
--- a/src/theory/bv/theory_bv.cpp
+++ b/src/theory/bv/theory_bv.cpp
@@ -33,8 +33,8 @@ using namespace CVC4::theory::bv::utils;
-TheoryBV::TheoryBV(context::Context* c, context::UserContext* u, OutputChannel& out, Valuation valuation, const LogicInfo& logicInfo)
- : Theory(THEORY_BV, c, u, out, valuation, logicInfo),
+TheoryBV::TheoryBV(context::Context* c, context::UserContext* u, OutputChannel& out, Valuation valuation, const LogicInfo& logicInfo, QuantifiersEngine* qe)
+ : Theory(THEORY_BV, c, u, out, valuation, logicInfo, qe),
d_context(c),
d_alreadyPropagatedSet(c),
d_sharedTermsSet(c),
diff --git a/src/theory/bv/theory_bv.h b/src/theory/bv/theory_bv.h
index 9c27f62c5..f79b7ab71 100644
--- a/src/theory/bv/theory_bv.h
+++ b/src/theory/bv/theory_bv.h
@@ -49,8 +49,8 @@ class TheoryBV : public Theory {
EqualitySolver d_equalitySolver;
public:
- TheoryBV(context::Context* c, context::UserContext* u, OutputChannel& out, Valuation valuation, const LogicInfo& logicInfo);
- ~TheoryBV();
+ TheoryBV(context::Context* c, context::UserContext* u, OutputChannel& out, Valuation valuation, const LogicInfo& logicInfo, QuantifiersEngine* qe);
+ ~TheoryBV();
void preRegisterTerm(TNode n);
@@ -64,21 +64,21 @@ public:
std::string identify() const { return std::string("TheoryBV"); }
- PPAssertStatus ppAssert(TNode in, SubstitutionMap& outSubstitutions);
+ PPAssertStatus ppAssert(TNode in, SubstitutionMap& outSubstitutions);
private:
-
+
class Statistics {
public:
AverageStat d_avgConflictSize;
IntStat d_solveSubstitutions;
- TimerStat d_solveTimer;
+ TimerStat d_solveTimer;
Statistics();
- ~Statistics();
- };
-
+ ~Statistics();
+ };
+
Statistics d_statistics;
-
+
// Are we in conflict?
context::CDO<bool> d_conflict;
@@ -133,7 +133,7 @@ private:
}
bool inConflict() { return d_conflict == true; }
-
+
friend class Bitblaster;
friend class BitblastSolver;
friend class EqualitySolver;
diff --git a/src/theory/datatypes/Makefile.am b/src/theory/datatypes/Makefile.am
index f8bfa3dc5..d6622b19a 100644
--- a/src/theory/datatypes/Makefile.am
+++ b/src/theory/datatypes/Makefile.am
@@ -13,6 +13,8 @@ libdatatypes_la_SOURCES = \
union_find.h \
union_find.cpp \
explanation_manager.h \
- explanation_manager.cpp
+ explanation_manager.cpp \
+ theory_datatypes_instantiator.h \
+ theory_datatypes_instantiator.cpp
EXTRA_DIST = kinds
diff --git a/src/theory/datatypes/kinds b/src/theory/datatypes/kinds
index 7acb6d17d..4b6bfd8f6 100644
--- a/src/theory/datatypes/kinds
+++ b/src/theory/datatypes/kinds
@@ -6,6 +6,7 @@
theory THEORY_DATATYPES ::CVC4::theory::datatypes::TheoryDatatypes "theory/datatypes/theory_datatypes.h"
typechecker "theory/datatypes/theory_datatypes_type_rules.h"
+instantiator ::CVC4::theory::datatypes::InstantiatorTheoryDatatypes "theory/datatypes/theory_datatypes_instantiator.h"
properties check presolve parametric
diff --git a/src/theory/datatypes/theory_datatypes.cpp b/src/theory/datatypes/theory_datatypes.cpp
index 7b1562ada..3b8efabb7 100644
--- a/src/theory/datatypes/theory_datatypes.cpp
+++ b/src/theory/datatypes/theory_datatypes.cpp
@@ -22,6 +22,7 @@
#include "expr/kind.h"
#include "util/datatype.h"
#include "util/Assert.h"
+#include "theory/datatypes/theory_datatypes_instantiator.h"
#include <map>
@@ -53,8 +54,8 @@ Node TheoryDatatypes::getConstructorForSelector( Node sel )
}
-TheoryDatatypes::TheoryDatatypes(Context* c, UserContext* u, OutputChannel& out, Valuation valuation, const LogicInfo& logicInfo) :
- Theory(THEORY_DATATYPES, c, u, out, valuation, logicInfo),
+TheoryDatatypes::TheoryDatatypes(Context* c, UserContext* u, OutputChannel& out, Valuation valuation, const LogicInfo& logicInfo, QuantifiersEngine* qe) :
+ Theory(THEORY_DATATYPES, c, u, out, valuation, logicInfo, qe),
d_currAsserts(c),
d_currEqualities(c),
d_selectors(c),
@@ -71,7 +72,6 @@ TheoryDatatypes::TheoryDatatypes(Context* c, UserContext* u, OutputChannel& out,
d_disequalities(c),
d_em(c),
d_cce(&d_cc){
-
}
@@ -114,7 +114,7 @@ void TheoryDatatypes::check(Effort e) {
Node assertion = get();
if( Debug.isOn("datatypes") || Debug.isOn("datatypes-split") || Debug.isOn("datatypes-cycles")
|| Debug.isOn("datatypes-debug-pf") || Debug.isOn("datatypes-conflict") ) {
- cout << "*** TheoryDatatypes::check(): " << assertion << endl;
+ Notice() << "*** TheoryDatatypes::check(): " << assertion << endl;
d_currAsserts.push_back( assertion );
}
@@ -211,7 +211,7 @@ void TheoryDatatypes::check(Effort e) {
Node conflict = d_em.getConflict();
if( Debug.isOn("datatypes") || Debug.isOn("datatypes-split") ||
Debug.isOn("datatypes-cycles") || Debug.isOn("datatypes-conflict") ){
- cout << "Conflict constructed : " << conflict << endl;
+ Notice() << "Conflict constructed : " << conflict << endl;
}
if( conflict.getKind()!=kind::AND ){
conflict = NodeManager::currentNM()->mkNode(kind::AND, conflict, conflict);
@@ -283,7 +283,7 @@ void TheoryDatatypes::check(Effort e) {
}
}
if( Debug.isOn("datatypes") || Debug.isOn("datatypes-split") ) {
- cout << "TheoryDatatypes::check(): done" << endl;
+ Notice() << "TheoryDatatypes::check(): done" << endl;
}
}
diff --git a/src/theory/datatypes/theory_datatypes.h b/src/theory/datatypes/theory_datatypes.h
index 967000c3e..5a4135a3b 100644
--- a/src/theory/datatypes/theory_datatypes.h
+++ b/src/theory/datatypes/theory_datatypes.h
@@ -37,7 +37,10 @@ namespace CVC4 {
namespace theory {
namespace datatypes {
+class InstantiatorTheoryDatatypes;
+
class TheoryDatatypes : public Theory {
+ friend class InstantiatorTheoryDatatypes;
private:
typedef context::CDChunkList<TNode> EqList;
typedef context::CDHashMap<Node, EqList*, NodeHashFunction> EqLists;
@@ -53,7 +56,7 @@ private:
BoolMap d_selectors;
/** keeps track of which nodes are representatives */
BoolMap d_reps;
- /** map from (representative) nodes to a list of selectors whose arguments are
+ /** map from (representative) nodes to a list of selectors whose arguments are
in the equivalence class of that node */
EqListsN d_selector_eq;
/** map from (representative) nodes to list of nodes in their eq class */
@@ -140,7 +143,7 @@ private:
CongruenceClosureExplainer<CongruenceChannel, CONGRUENCE_OPERATORS_2 (kind::APPLY_CONSTRUCTOR, kind::APPLY_SELECTOR)> d_cce;
public:
- TheoryDatatypes(context::Context* c, context::UserContext* u, OutputChannel& out, Valuation valuation, const LogicInfo& logicInfo);
+ TheoryDatatypes(context::Context* c, context::UserContext* u, OutputChannel& out, Valuation valuation, const LogicInfo& logicInfo, QuantifiersEngine* qe);
~TheoryDatatypes();
void preRegisterTerm(TNode n);
void presolve();
@@ -167,7 +170,7 @@ private:
/* from uf_morgan */
void merge(TNode a, TNode b);
- inline TNode find(TNode a);
+ inline TNode find(TNode a);
inline TNode debugFind(TNode a) const;
void appendToDiseqList(TNode of, TNode eq);
void addDisequality(TNode eq);
@@ -179,8 +182,8 @@ private:
NodeBuilder<>& explanation );
};/* class TheoryDatatypes */
-inline bool TheoryDatatypes::hasConflict() {
- return d_em.hasConflict();
+inline bool TheoryDatatypes::hasConflict() {
+ return d_em.hasConflict();
}
inline TNode TheoryDatatypes::find(TNode a) {
diff --git a/src/theory/datatypes/theory_datatypes_instantiator.cpp b/src/theory/datatypes/theory_datatypes_instantiator.cpp
new file mode 100644
index 000000000..6a32466e4
--- /dev/null
+++ b/src/theory/datatypes/theory_datatypes_instantiator.cpp
@@ -0,0 +1,158 @@
+/********************* */
+/*! \file theory_datatypes_instantiator.cpp
+ ** \verbatim
+ ** Original author: ajreynol
+ ** Major contributors: none
+ ** Minor contributors (to current version): none
+ ** This file is part of the CVC4 prototype.
+ ** Copyright (c) 2009, 2010, 2011 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
+ ** information.\endverbatim
+ **
+ ** \brief Implementation of theory_datatypes_instantiator class
+ **/
+
+#include "theory/datatypes/theory_datatypes_instantiator.h"
+#include "theory/datatypes/theory_datatypes.h"
+#include "theory/theory_engine.h"
+
+using namespace std;
+using namespace CVC4;
+using namespace CVC4::kind;
+using namespace CVC4::context;
+using namespace CVC4::theory;
+using namespace CVC4::theory::datatypes;
+
+InstantiatorTheoryDatatypes::InstantiatorTheoryDatatypes(context::Context* c, QuantifiersEngine* ie, Theory* th) :
+Instantiator( c, ie, th ){
+
+}
+
+void InstantiatorTheoryDatatypes::assertNode( Node assertion ){
+ Debug("quant-datatypes-assert") << "InstantiatorTheoryDatatypes::check: " << assertion << std::endl;
+ d_quantEngine->addTermToDatabase( assertion );
+ if( Options::current()->cbqi ){
+ if( assertion.hasAttribute(InstConstantAttribute()) ){
+ setHasConstraintsFrom( assertion.getAttribute(InstConstantAttribute()) );
+ }else if( assertion.getKind()==NOT && assertion[0].hasAttribute(InstConstantAttribute()) ){
+ setHasConstraintsFrom( assertion[0].getAttribute(InstConstantAttribute()) );
+ }
+ }
+}
+
+void InstantiatorTheoryDatatypes::processResetInstantiationRound( Theory::Effort effort ){
+
+}
+
+
+int InstantiatorTheoryDatatypes::process( Node f, Theory::Effort effort, int e, int limitInst ){
+ Debug("quant-datatypes") << "Datatypes: Try to solve (" << e << ") for " << f << "... " << std::endl;
+ if( Options::current()->cbqi ){
+ if( e<2 ){
+ return InstStrategy::STATUS_UNFINISHED;
+ }else if( e==2 ){
+ InstMatch m;
+ for( int j = 0; j<(int)d_quantEngine->getNumInstantiationConstants( f ); j++ ){
+ Node i = d_quantEngine->getInstantiationConstant( f, j );
+ if( i.getType().isDatatype() ){
+ Node n = getValueFor( i );
+ Debug("quant-datatypes-debug") << "Value for " << i << " is " << n << std::endl;
+ m.d_map[ i ] = n;
+ }
+ }
+ d_quantEngine->addInstantiation( f, m );
+ }
+ }
+ return InstStrategy::STATUS_UNKNOWN;
+}
+
+Node InstantiatorTheoryDatatypes::getValueFor( Node n ){
+ //simply get the ground value for n in the current model, if it exists,
+ // or return an arbitrary ground term otherwise
+ Debug("quant-datatypes-debug") << "get value for " << n << std::endl;
+ if( !n.hasAttribute(InstConstantAttribute()) ){
+ return n;
+ }else{
+ Assert( n.getType().isDatatype() );
+ //check if in equivalence class with ground term
+ Node rep = getRepresentative( n );
+ Debug("quant-datatypes-debug") << "Rep is " << rep << std::endl;
+ if( !rep.hasAttribute(InstConstantAttribute()) ){
+ return rep;
+ }else{
+ if( !n.getType().isDatatype() ){
+ return n.getType().mkGroundTerm();
+ }else{
+ if( n.getKind()==APPLY_CONSTRUCTOR ){
+ std::vector< Node > children;
+ children.push_back( n.getOperator() );
+ for( int i=0; i<(int)n.getNumChildren(); i++ ){
+ children.push_back( getValueFor( n[i] ) );
+ }
+ return NodeManager::currentNM()->mkNode( APPLY_CONSTRUCTOR, children );
+ }else{
+ const Datatype& dt = ((DatatypeType)(n.getType()).toType()).getDatatype();
+ TheoryDatatypes::EqLists* labels = &((TheoryDatatypes*)d_th)->d_labels;
+ //otherwise, use which constructor the inst constant is current chosen to be
+ if( labels->find( n )!=labels->end() ){
+ TheoryDatatypes::EqList* lbl = (*labels->find( n )).second;
+ int tIndex = -1;
+ if( !lbl->empty() && (*lbl)[ lbl->size()-1 ].getKind()==APPLY_TESTER ){
+ Debug("quant-datatypes-debug") << n << " tester is " << (*lbl)[ lbl->size()-1 ] << std::endl;
+ tIndex = Datatype::indexOf((*lbl)[ lbl->size()-1 ].getOperator().toExpr());
+ }else{
+ Debug("quant-datatypes-debug") << "find possible tester choice" << std::endl;
+ //must find a possible choice
+ vector< bool > possibleCons;
+ possibleCons.resize( dt.getNumConstructors(), true );
+ for( TheoryDatatypes::EqList::const_iterator j = lbl->begin(); j != lbl->end(); j++ ) {
+ Node leqn = (*j);
+ possibleCons[ Datatype::indexOf( leqn[0].getOperator().toExpr() ) ] = false;
+ }
+ for( unsigned int j=0; j<possibleCons.size(); j++ ) {
+ if( possibleCons[j] ){
+ tIndex = j;
+ break;
+ }
+ }
+ }
+ Assert( tIndex!=-1 );
+ Node cons = Node::fromExpr( dt[ tIndex ].getConstructor() );
+ Debug("quant-datatypes-debug") << n << " cons is " << cons << std::endl;
+ std::vector< Node > children;
+ children.push_back( cons );
+ for( int i=0; i<(int)dt[ tIndex ].getNumArgs(); i++ ) {
+ Node sn = NodeManager::currentNM()->mkNode( APPLY_SELECTOR, Node::fromExpr( dt[tIndex][i].getSelector() ), n );
+ if( n.hasAttribute(InstConstantAttribute()) ){
+ InstConstantAttribute ica;
+ sn.setAttribute(ica,n.getAttribute(InstConstantAttribute()) );
+ }
+ Node snn = getValueFor( sn );
+ children.push_back( snn );
+ }
+ return NodeManager::currentNM()->mkNode( APPLY_CONSTRUCTOR, children );
+ }else{
+ return n.getType().mkGroundTerm();
+ }
+ }
+ }
+ }
+ }
+}
+
+Node InstantiatorTheoryDatatypes::getRepresentative( Node n ){
+ return ((TheoryDatatypes*)d_th)->find( n );
+}
+
+InstantiatorTheoryDatatypes::Statistics::Statistics():
+ d_instantiations("InstantiatorTheoryDatatypes::Instantiations_Total", 0)
+{
+ StatisticsRegistry::registerStat(&d_instantiations);
+}
+
+InstantiatorTheoryDatatypes::Statistics::~Statistics(){
+ StatisticsRegistry::unregisterStat(&d_instantiations);
+}
+
diff --git a/src/theory/datatypes/theory_datatypes_instantiator.h b/src/theory/datatypes/theory_datatypes_instantiator.h
new file mode 100644
index 000000000..5c52f7f48
--- /dev/null
+++ b/src/theory/datatypes/theory_datatypes_instantiator.h
@@ -0,0 +1,64 @@
+/********************* */
+/*! \file instantiator_datatypes_instantiator.h
+ ** \verbatim
+ ** Original author: ajreynol
+ ** Major contributors: none
+ ** Minor contributors (to current version): none
+ ** This file is part of the CVC4 prototype.
+ ** Copyright (c) 2009, 2010, 2011 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
+ ** information.\endverbatim
+ **
+ ** \brief instantiator_datatypes_instantiator
+ **/
+
+
+#include "cvc4_private.h"
+
+#ifndef __CVC4__INSTANTIATOR_DATATYPES_H
+#define __CVC4__INSTANTIATOR_DATATYPES_H
+
+#include "theory/quantifiers_engine.h"
+
+#include "util/stats.h"
+
+namespace CVC4 {
+namespace theory {
+namespace datatypes {
+
+class InstantiatorTheoryDatatypes : public Instantiator{
+ friend class QuantifiersEngine;
+public:
+ InstantiatorTheoryDatatypes(context::Context* c, QuantifiersEngine* ie, Theory* th);
+ ~InstantiatorTheoryDatatypes() {}
+
+ /** assertNode function, assertion is asserted to theory */
+ void assertNode( Node assertion );
+ /** identify */
+ std::string identify() const { return std::string("InstantiatorTheoryDatatypes"); }
+private:
+ /** reset instantiation */
+ void processResetInstantiationRound( Theory::Effort effort );
+ /** process at effort */
+ int process( Node f, Theory::Effort effort, int e, int limitInst );
+ /** get value for */
+ Node getValueFor( Node n );
+ /** get representative */
+ Node getRepresentative( Node n );
+
+ class Statistics {
+ public:
+ IntStat d_instantiations;
+ Statistics();
+ ~Statistics();
+ };
+ Statistics d_statistics;
+};/* class InstantiatiorTheoryDatatypes */
+
+}
+}
+}
+
+#endif \ No newline at end of file
diff --git a/src/theory/example/theory_uf_tim.cpp b/src/theory/example/theory_uf_tim.cpp
index 03787703a..638a03478 100644
--- a/src/theory/example/theory_uf_tim.cpp
+++ b/src/theory/example/theory_uf_tim.cpp
@@ -27,8 +27,8 @@ using namespace CVC4::theory;
using namespace CVC4::theory::uf;
using namespace CVC4::theory::uf::tim;
-TheoryUFTim::TheoryUFTim(Context* c, UserContext* u, OutputChannel& out, Valuation valuation) :
- Theory(THEORY_UF, c, u, out, valuation),
+TheoryUFTim::TheoryUFTim(Context* c, UserContext* u, OutputChannel& out, Valuation valuation, QuantifiersEngine* qe) :
+ Theory(THEORY_UF, c, u, out, valuation, qe),
d_assertions(c),
d_pending(c),
d_currentPendingIdx(c,0),
diff --git a/src/theory/example/theory_uf_tim.h b/src/theory/example/theory_uf_tim.h
index b47536f07..41e58349a 100644
--- a/src/theory/example/theory_uf_tim.h
+++ b/src/theory/example/theory_uf_tim.h
@@ -85,7 +85,7 @@ private:
public:
/** Constructs a new instance of TheoryUF w.r.t. the provided context.*/
- TheoryUFTim(context::Context* c, context::UserContext* u, OutputChannel& out, Valuation valuation);
+ TheoryUFTim(context::Context* c, context::UserContext* u, OutputChannel& out, Valuation valuation, QuantifiersEngine* qe);
/** Destructor for the TheoryUF object. */
~TheoryUFTim();
diff --git a/src/theory/inst_match.cpp b/src/theory/inst_match.cpp
new file mode 100644
index 000000000..e340da75d
--- /dev/null
+++ b/src/theory/inst_match.cpp
@@ -0,0 +1,903 @@
+/********************* */
+/*! \file inst_match.cpp
+ ** \verbatim
+ ** Original author: ajreynol
+ ** Major contributors: none
+ ** Minor contributors (to current version): none
+ ** This file is part of the CVC4 prototype.
+ ** Copyright (c) 2009, 2010, 2011 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
+ ** information.\endverbatim
+ **
+ ** \brief Implementation of inst match class
+ **/
+
+#include "theory/inst_match.h"
+#include "theory/theory_engine.h"
+#include "theory/quantifiers_engine.h"
+#include "theory/uf/theory_uf_instantiator.h"
+#include "theory/uf/theory_uf_candidate_generator.h"
+#include "theory/uf/equality_engine.h"
+
+using namespace std;
+using namespace CVC4;
+using namespace CVC4::kind;
+using namespace CVC4::context;
+using namespace CVC4::theory;
+
+
+bool CandidateGenerator::isLegalCandidate( Node n ){
+ return !n.getAttribute(NoMatchAttribute()) && ( !Options::current()->cbqi || !n.hasAttribute(InstConstantAttribute()) );
+}
+
+void CandidateGeneratorQueue::addCandidate( Node n ) {
+ if( isLegalCandidate( n ) ){
+ d_candidates.push_back( n );
+ }
+}
+
+void CandidateGeneratorQueue::reset( Node eqc ){
+ if( d_candidate_index>0 ){
+ d_candidates.erase( d_candidates.begin(), d_candidates.begin() + d_candidate_index );
+ d_candidate_index = 0;
+ }
+ if( !eqc.isNull() ){
+ d_candidates.push_back( eqc );
+ }
+}
+Node CandidateGeneratorQueue::getNextCandidate(){
+ if( d_candidate_index<(int)d_candidates.size() ){
+ Node n = d_candidates[d_candidate_index];
+ d_candidate_index++;
+ return n;
+ }else{
+ d_candidate_index = 0;
+ d_candidates.clear();
+ return Node::null();
+ }
+}
+
+InstMatch::InstMatch() {
+}
+
+InstMatch::InstMatch( InstMatch* m ) {
+ d_map = m->d_map;
+}
+
+bool InstMatch::setMatch( EqualityQuery* q, Node v, Node m ){
+ if( d_map.find( v )==d_map.end() ){
+ d_map[v] = m;
+ Debug("matching-debug") << "Add partial " << v << "->" << m << std::endl;
+ return true;
+ }else{
+ return q->areEqual( d_map[v], m );
+ }
+}
+
+bool InstMatch::add( InstMatch& m ){
+ for( std::map< Node, Node >::iterator it = m.d_map.begin(); it != m.d_map.end(); ++it ){
+ if( d_map.find( it->first )==d_map.end() ){
+ d_map[it->first] = it->second;
+ }
+ }
+ return true;
+}
+
+bool InstMatch::merge( EqualityQuery* q, InstMatch& m ){
+ for( std::map< Node, Node >::iterator it = m.d_map.begin(); it != m.d_map.end(); ++it ){
+ if( d_map.find( it->first )==d_map.end() ){
+ d_map[ it->first ] = it->second;
+ }else{
+ if( it->second!=d_map[it->first] ){
+ if( !q->areEqual( it->second, d_map[it->first] ) ){
+ d_map.clear();
+ return false;
+ }
+ }
+ }
+ }
+ return true;
+}
+
+void InstMatch::debugPrint( const char* c ){
+ for( std::map< Node, Node >::iterator it = d_map.begin(); it != d_map.end(); ++it ){
+ Debug( c ) << " " << it->first << " -> " << it->second << std::endl;
+ }
+ //if( !d_splits.empty() ){
+ // Debug( c ) << " Conditions: ";
+ // for( std::map< Node, Node >::iterator it = d_splits.begin(); it !=d_splits.end(); ++it ){
+ // Debug( c ) << it->first << " = " << it->second << " ";
+ // }
+ // Debug( c ) << std::endl;
+ //}
+}
+
+void InstMatch::makeComplete( Node f, QuantifiersEngine* qe ){
+ for( int i=0; i<(int)qe->d_inst_constants[f].size(); i++ ){
+ if( d_map.find( qe->d_inst_constants[f][i] )==d_map.end() ){
+ d_map[ qe->d_inst_constants[f][i] ] = qe->getFreeVariableForInstConstant( qe->d_inst_constants[f][i] );
+ }
+ }
+}
+
+void InstMatch::makeInternal( QuantifiersEngine* qe ){
+ for( std::map< Node, Node >::iterator it = d_map.begin(); it != d_map.end(); ++it ){
+ if( Options::current()->cbqi && it->second.hasAttribute(InstConstantAttribute()) ){
+ d_map[ it->first ] = qe->getEqualityQuery()->getInternalRepresentative( it->second );
+ if( Options::current()->cbqi && it->second.hasAttribute(InstConstantAttribute()) ){
+ d_map[ it->first ] = qe->getFreeVariableForInstConstant( it->first );
+ }
+ }
+ }
+}
+
+void InstMatch::makeRepresentative( QuantifiersEngine* qe ){
+ for( std::map< Node, Node >::iterator it = d_map.begin(); it != d_map.end(); ++it ){
+ d_map[ it->first ] = qe->getEqualityQuery()->getInternalRepresentative( it->second );
+ if( Options::current()->cbqi && it->second.hasAttribute(InstConstantAttribute()) ){
+ d_map[ it->first ] = qe->getFreeVariableForInstConstant( it->first );
+ }
+ }
+}
+
+void InstMatch::applyRewrite(){
+ for( std::map< Node, Node >::iterator it = d_map.begin(); it != d_map.end(); ++it ){
+ it->second = Rewriter::rewrite(it->second);
+ }
+}
+
+void InstMatch::computeTermVec( QuantifiersEngine* qe, const std::vector< Node >& vars, std::vector< Node >& match ){
+ for( int i=0; i<(int)vars.size(); i++ ){
+ std::map< Node, Node >::iterator it = d_map.find( vars[i] );
+ if( it!=d_map.end() && !it->second.isNull() ){
+ match.push_back( it->second );
+ }else{
+ match.push_back( qe->getFreeVariableForInstConstant( vars[i] ) );
+ }
+ }
+}
+void InstMatch::computeTermVec( const std::vector< Node >& vars, std::vector< Node >& match ){
+ for( int i=0; i<(int)vars.size(); i++ ){
+ match.push_back( d_map[ vars[i] ] );
+ }
+}
+
+
+/** add match m for quantifier f starting at index, take into account equalities q, return true if successful */
+void InstMatchTrie::addInstMatch2( QuantifiersEngine* qe, Node f, InstMatch& m, int index, ImtIndexOrder* imtio ){
+ if( long(index)<f[0].getNumChildren() && ( !imtio || long(index)<imtio->d_order.size() ) ){
+ int i_index = imtio ? imtio->d_order[index] : index;
+ Node n = m.d_map[ qe->getInstantiationConstant( f, i_index ) ];
+ d_data[n].addInstMatch2( qe, f, m, index+1, imtio );
+ }
+}
+
+/** exists match */
+bool InstMatchTrie::existsInstMatch( QuantifiersEngine* qe, Node f, InstMatch& m, bool modEq, int index, ImtIndexOrder* imtio ){
+ if( long(index)==f[0].getNumChildren() || ( imtio && long(index)==imtio->d_order.size() ) ){
+ return true;
+ }else{
+ int i_index = imtio ? imtio->d_order[index] : index;
+ Node n = m.d_map[ qe->getInstantiationConstant( f, i_index ) ];
+ std::map< Node, InstMatchTrie >::iterator it = d_data.find( n );
+ if( it!=d_data.end() ){
+ if( it->second.existsInstMatch( qe, f, m, modEq, index+1, imtio ) ){
+ return true;
+ }
+ }
+ if( modEq ){
+ //check modulo equality if any other instantiation match exists
+ if( ((uf::TheoryUF*)qe->getTheoryEngine()->getTheory( THEORY_UF ))->getEqualityEngine()->hasTerm( n ) ){
+ eq::EqClassIterator eqc( qe->getEqualityQuery()->getRepresentative( n ),
+ ((uf::TheoryUF*)qe->getTheoryEngine()->getTheory( THEORY_UF ))->getEqualityEngine() );
+ while( !eqc.isFinished() ){
+ Node en = (*eqc);
+ if( en!=n ){
+ std::map< Node, InstMatchTrie >::iterator itc = d_data.find( en );
+ if( itc!=d_data.end() ){
+ if( itc->second.existsInstMatch( qe, f, m, modEq, index+1, imtio ) ){
+ return true;
+ }
+ }
+ }
+ ++eqc;
+ }
+ }
+ //for( std::map< Node, InstMatchTrie >::iterator itc = d_data.begin(); itc != d_data.end(); ++itc ){
+ // if( itc->first!=n && qe->getEqualityQuery()->areEqual( n, itc->first ) ){
+ // if( itc->second.existsInstMatch( qe, f, m, modEq, index+1 ) ){
+ // return true;
+ // }
+ // }
+ //}
+ }
+ return false;
+ }
+}
+
+bool InstMatchTrie::addInstMatch( QuantifiersEngine* qe, Node f, InstMatch& m, bool modEq, ImtIndexOrder* imtio ){
+ if( !existsInstMatch( qe, f, m, modEq, 0, imtio ) ){
+ addInstMatch2( qe, f, m, 0, imtio );
+ return true;
+ }else{
+ return false;
+ }
+}
+
+InstMatchGenerator::InstMatchGenerator( Node pat, QuantifiersEngine* qe, int matchPolicy ) : d_matchPolicy( matchPolicy ){
+ initializePattern( pat, qe );
+}
+
+InstMatchGenerator::InstMatchGenerator( std::vector< Node >& pats, QuantifiersEngine* qe, int matchPolicy ) : d_matchPolicy( matchPolicy ){
+ if( pats.size()==1 ){
+ initializePattern( pats[0], qe );
+ }else{
+ initializePatterns( pats, qe );
+ }
+}
+
+void InstMatchGenerator::initializePatterns( std::vector< Node >& pats, QuantifiersEngine* qe ){
+ int childMatchPolicy = d_matchPolicy==MATCH_GEN_EFFICIENT_E_MATCH ? 0 : d_matchPolicy;
+ for( int i=0; i<(int)pats.size(); i++ ){
+ d_children.push_back( new InstMatchGenerator( pats[i], qe, childMatchPolicy ) );
+ }
+ d_pattern = Node::null();
+ d_match_pattern = Node::null();
+ d_cg = NULL;
+}
+
+void InstMatchGenerator::initializePattern( Node pat, QuantifiersEngine* qe ){
+ Debug("inst-match-gen") << "Pattern term is " << pat << std::endl;
+ Assert( pat.hasAttribute(InstConstantAttribute()) );
+ d_pattern = pat;
+ d_match_pattern = pat;
+ if( d_match_pattern.getKind()==NOT ){
+ //we want to add the children of the NOT
+ d_match_pattern = d_pattern[0];
+ }
+ if( d_match_pattern.getKind()==IFF || d_match_pattern.getKind()==EQUAL ){
+ if( !d_match_pattern[0].hasAttribute(InstConstantAttribute()) ){
+ Assert( d_match_pattern[1].hasAttribute(InstConstantAttribute()) );
+ //swap sides
+ d_pattern = NodeManager::currentNM()->mkNode( d_match_pattern.getKind(), d_match_pattern[1], d_match_pattern[0] );
+ d_pattern = pat.getKind()==NOT ? d_pattern.notNode() : d_pattern;
+ if( pat.getKind()!=NOT ){ //TEMPORARY until we do better implementation of disequality matching
+ d_match_pattern = d_match_pattern[1];
+ }else{
+ d_match_pattern = d_pattern[0][0];
+ }
+ }else if( !d_match_pattern[1].hasAttribute(InstConstantAttribute()) ){
+ Assert( d_match_pattern[0].hasAttribute(InstConstantAttribute()) );
+ if( pat.getKind()!=NOT ){ //TEMPORARY until we do better implementation of disequality matching
+ d_match_pattern = d_match_pattern[0];
+ }
+ }
+ }
+ int childMatchPolicy = MATCH_GEN_DEFAULT;
+ for( int i=0; i<(int)d_match_pattern.getNumChildren(); i++ ){
+ if( d_match_pattern[i].hasAttribute(InstConstantAttribute()) ){
+ if( d_match_pattern[i].getKind()!=INST_CONSTANT ){
+ d_children.push_back( new InstMatchGenerator( d_match_pattern[i], qe, childMatchPolicy ) );
+ d_children_index.push_back( i );
+ }
+ }
+ }
+
+ Debug("inst-match-gen") << "Pattern is " << d_pattern << ", match pattern is " << d_match_pattern << std::endl;
+
+ //get the equality engine
+ Theory* th_uf = qe->getTheoryEngine()->getTheory( theory::THEORY_UF );
+ uf::InstantiatorTheoryUf* ith = (uf::InstantiatorTheoryUf*)th_uf->getInstantiator();
+ //create candidate generator
+ if( d_match_pattern.getKind()==EQUAL || d_match_pattern.getKind()==IFF ){
+ Assert( d_matchPolicy==MATCH_GEN_DEFAULT );
+ //we will be producing candidates via literal matching heuristics
+ if( d_pattern.getKind()!=NOT ){
+ //candidates will be all equalities
+ d_cg = new uf::CandidateGeneratorTheoryUfLitEq( ith, d_match_pattern );
+ }else{
+ //candidates will be all disequalities
+ d_cg = new uf::CandidateGeneratorTheoryUfLitDeq( ith, d_match_pattern );
+ }
+ }else if( d_pattern.getKind()==EQUAL || d_pattern.getKind()==IFF || d_pattern.getKind()==NOT ){
+ Assert( d_matchPolicy==MATCH_GEN_DEFAULT );
+ if( d_pattern.getKind()==NOT ){
+ Unimplemented("Disequal generator unimplemented");
+ }else{
+ Assert( Trigger::isAtomicTrigger( d_match_pattern ) );
+ //we are matching only in a particular equivalence class
+ d_cg = new uf::CandidateGeneratorTheoryUf( ith, d_match_pattern.getOperator() );
+ //store the equivalence class that we will call d_cg->reset( ... ) on
+ d_eq_class = d_pattern[1];
+ }
+ }else if( Trigger::isAtomicTrigger( d_match_pattern ) ){
+ if( d_matchPolicy==MATCH_GEN_EFFICIENT_E_MATCH ){
+ //we will manually add candidates to queue
+ d_cg = new CandidateGeneratorQueue;
+ //register this candidate generator
+ ith->registerCandidateGenerator( d_cg, d_match_pattern );
+ }else{
+ //we will be scanning lists trying to find d_match_pattern.getOperator()
+ d_cg = new uf::CandidateGeneratorTheoryUf( ith, d_match_pattern.getOperator() );
+ }
+ }else{
+ d_cg = new CandidateGeneratorQueue;
+ if( !Trigger::getPatternArithmetic( d_match_pattern.getAttribute(InstConstantAttribute()), d_match_pattern, d_arith_coeffs ) ){
+ Debug("inst-match-gen") << "(?) Unknown matching pattern is " << d_match_pattern << std::endl;
+ Warning() << "(?) Unknown matching pattern is " << d_match_pattern << std::endl;
+ d_matchPolicy = MATCH_GEN_INTERNAL_ERROR;
+ }else{
+ Debug("matching-arith") << "Generated arithmetic pattern for " << d_match_pattern << ": " << std::endl;
+ for( std::map< Node, Node >::iterator it = d_arith_coeffs.begin(); it != d_arith_coeffs.end(); ++it ){
+ Debug("matching-arith") << " " << it->first << " -> " << it->second << std::endl;
+ }
+ //we will treat this as match gen internal arithmetic
+ d_matchPolicy = MATCH_GEN_INTERNAL_ARITHMETIC;
+ }
+ }
+}
+
+/** get match (not modulo equality) */
+bool InstMatchGenerator::getMatch( Node t, InstMatch& m, QuantifiersEngine* qe ){
+ Debug("matching") << "Matching " << t << " against pattern " << d_match_pattern << " ("
+ << m.d_map.size() << ")" << ", " << d_children.size() << std::endl;
+ Assert( !d_match_pattern.isNull() );
+ if( d_matchPolicy==MATCH_GEN_INTERNAL_ARITHMETIC ){
+ return getMatchArithmetic( t, m, qe );
+ }else if( d_matchPolicy==MATCH_GEN_INTERNAL_ERROR ){
+ return false;
+ }else{
+ EqualityQuery* q = qe->getEqualityQuery();
+ //add m to partial match vector
+ std::vector< InstMatch > partial;
+ partial.push_back( InstMatch( &m ) );
+ //if t is null
+ Assert( !t.isNull() );
+ Assert( !t.hasAttribute(InstConstantAttribute()) );
+ Assert( 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( d_match_pattern[i].hasAttribute(InstConstantAttribute()) ){
+ if( d_match_pattern[i].getKind()==INST_CONSTANT ){
+ if( !partial[0].setMatch( q, d_match_pattern[i], t[i] ) ){
+ //match is in conflict
+ Debug("matching-debug") << "Match in conflict " << t[i] << " and "
+ << d_match_pattern[i] << " because "
+ << partial[0].d_map[d_match_pattern[i]]
+ << std::endl;
+ Debug("matching-fail") << "Match fail: " << partial[0].d_map[d_match_pattern[i]] << " and " << t[i] << std::endl;
+ return false;
+ }
+ }
+ }else{
+ if( !q->areEqual( d_match_pattern[i], t[i] ) ){
+ Debug("matching-fail") << "Match fail arg: " << d_match_pattern[i] << " and " << t[i] << std::endl;
+ //ground arguments are not equal
+ return false;
+ }
+ }
+ }
+ //now, fit children into match
+ //we will be requesting candidates for matching terms for each child
+ std::vector< Node > reps;
+ for( int i=0; i<(int)d_children.size(); i++ ){
+ Node rep = q->getRepresentative( t[ d_children_index[i] ] );
+ reps.push_back( rep );
+ d_children[i]->d_cg->reset( rep );
+ }
+
+ //combine child matches
+ int index = 0;
+ while( index>=0 && index<(int)d_children.size() ){
+ partial.push_back( InstMatch( &partial[index] ) );
+ if( d_children[index]->getNextMatch2( partial[index+1], qe ) ){
+ index++;
+ }else{
+ d_children[index]->d_cg->reset( reps[index] );
+ partial.pop_back();
+ if( !partial.empty() ){
+ partial.pop_back();
+ }
+ index--;
+ }
+ }
+ if( index>=0 ){
+ m = partial.back();
+ return true;
+ }else{
+ return false;
+ }
+ }
+}
+
+bool InstMatchGenerator::getNextMatch2( InstMatch& m, QuantifiersEngine* qe, bool saveMatched ){
+ bool success = false;
+ Node t;
+ do{
+ //get the next candidate term t
+ t = d_cg->getNextCandidate();
+ //if t not null, try to fit it into match m
+ if( !t.isNull() && t.getType()==d_match_pattern.getType() ){
+ //Assert( t.getType()==d_match_pattern.getType() );
+ success = getMatch( t, m, qe );
+ }
+ }while( !success && !t.isNull() );
+ if (saveMatched) m.d_matched = t;
+ return success;
+}
+
+bool InstMatchGenerator::getMatchArithmetic( Node t, InstMatch& m, QuantifiersEngine* qe ){
+ Debug("matching-arith") << "Matching " << t << " " << d_match_pattern << std::endl;
+ if( !d_arith_coeffs.empty() ){
+ NodeBuilder<> tb(kind::PLUS);
+ Node ic = Node::null();
+ for( std::map< Node, Node >::iterator it = d_arith_coeffs.begin(); it != d_arith_coeffs.end(); ++it ){
+ Debug("matching-arith") << it->first << " -> " << it->second << std::endl;
+ if( !it->first.isNull() ){
+ if( m.d_map.find( it->first )==m.d_map.end() ){
+ //see if we can choose this to set
+ if( ic.isNull() && ( it->second.isNull() || !it->first.getType().isInteger() ) ){
+ ic = it->first;
+ }
+ }else{
+ Debug("matching-arith") << "already set " << m.d_map[ it->first ] << std::endl;
+ Node tm = m.d_map[ it->first ];
+ if( !it->second.isNull() ){
+ tm = NodeManager::currentNM()->mkNode( MULT, it->second, tm );
+ }
+ tb << tm;
+ }
+ }else{
+ tb << it->second;
+ }
+ }
+ if( !ic.isNull() ){
+ Node tm;
+ if( tb.getNumChildren()==0 ){
+ tm = t;
+ }else{
+ tm = tb.getNumChildren()==1 ? tb.getChild( 0 ) : tb;
+ tm = NodeManager::currentNM()->mkNode( MINUS, t, tm );
+ }
+ if( !d_arith_coeffs[ ic ].isNull() ){
+ Assert( !ic.getType().isInteger() );
+ Node coeff = NodeManager::currentNM()->mkConst( Rational(1) / d_arith_coeffs[ ic ].getConst<Rational>() );
+ tm = NodeManager::currentNM()->mkNode( MULT, coeff, tm );
+ }
+ m.d_map[ ic ] = Rewriter::rewrite( tm );
+ //set the rest to zeros
+ for( std::map< Node, Node >::iterator it = d_arith_coeffs.begin(); it != d_arith_coeffs.end(); ++it ){
+ if( !it->first.isNull() ){
+ if( m.d_map.find( it->first )==m.d_map.end() ){
+ m.d_map[ it->first ] = NodeManager::currentNM()->mkConst( Rational(0) );
+ }
+ }
+ }
+ Debug("matching-arith") << "Setting " << ic << " to " << tm << std::endl;
+ return true;
+ }else{
+ return false;
+ }
+ }else{
+ return false;
+ }
+}
+
+
+/** reset instantiation round */
+void InstMatchGenerator::resetInstantiationRound( QuantifiersEngine* qe ){
+ if( d_match_pattern.isNull() ){
+ for( int i=0; i<(int)d_children.size(); i++ ){
+ d_children[i]->resetInstantiationRound( qe );
+ }
+ }else{
+ if( d_cg ){
+ d_cg->resetInstantiationRound();
+ }
+ }
+}
+
+void InstMatchGenerator::reset( Node eqc, QuantifiersEngine* qe ){
+ if( d_match_pattern.isNull() ){
+ for( int i=0; i<(int)d_children.size(); i++ ){
+ d_children[i]->reset( eqc, qe );
+ }
+ d_partial.clear();
+ }else{
+ if( !d_eq_class.isNull() ){
+ //we have a specific equivalence class in mind
+ //we are producing matches for f(E) ~ t, where E is a non-ground vector of terms, and t is a ground term
+ //just look in equivalence class of the RHS
+ d_cg->reset( d_eq_class );
+ }else{
+ d_cg->reset( eqc );
+ }
+ }
+}
+
+bool InstMatchGenerator::getNextMatch( InstMatch& m, QuantifiersEngine* qe ){
+ m.d_matched = Node::null();
+ if( d_match_pattern.isNull() ){
+ int index = (int)d_partial.size();
+ while( index>=0 && index<(int)d_children.size() ){
+ if( index>0 ){
+ d_partial.push_back( InstMatch( &d_partial[index-1] ) );
+ }else{
+ d_partial.push_back( InstMatch() );
+ }
+ if( d_children[index]->getNextMatch( d_partial[index], qe ) ){
+ index++;
+ }else{
+ d_children[index]->reset( Node::null(), qe );
+ d_partial.pop_back();
+ if( !d_partial.empty() ){
+ d_partial.pop_back();
+ }
+ index--;
+ }
+ }
+ if( index>=0 ){
+ m = d_partial.back();
+ d_partial.pop_back();
+ return true;
+ }else{
+ return false;
+ }
+ }else{
+ bool res = getNextMatch2( m, qe, true );
+ Assert(!res || !m.d_matched.isNull());
+ return res;
+ }
+}
+
+
+
+// Currently the implementation doesn't take into account that
+// variable should have the same value given.
+// TODO use the d_children way perhaps
+// TODO replace by a real dictionnary
+// We should create a real substitution? slower more precise
+// We don't do that often
+bool InstMatchGenerator::nonunifiable( TNode t0, const std::vector<Node> & vars){
+ if(d_match_pattern.isNull()) return true;
+
+ typedef std::vector<std::pair<TNode,TNode> > tstack;
+ tstack stack(1,std::make_pair(t0,d_match_pattern)); // t * pat
+
+ while(!stack.empty()){
+ const std::pair<TNode,TNode> p = stack.back(); stack.pop_back();
+ const TNode & t = p.first;
+ const TNode & pat = p.second;
+
+ // t or pat is a variable currently we consider that can match anything
+ if( find(vars.begin(),vars.end(),t) != vars.end() ) continue;
+ if( pat.getKind() == INST_CONSTANT ) continue;
+
+ // t and pat are nonunifiable
+ if( !Trigger::isAtomicTrigger( t ) || !Trigger::isAtomicTrigger( pat ) ) {
+ if(t == pat) continue;
+ else return true;
+ };
+ if( t.getOperator() != pat.getOperator() ) return true;
+
+ //put the children on the stack
+ for( size_t i=0; i < pat.getNumChildren(); i++ ){
+ stack.push_back(std::make_pair(t[i],pat[i]));
+ };
+ }
+ // The heuristic can't find non-unifiability
+ return false;
+}
+
+int InstMatchGenerator::addInstantiations( Node f, InstMatch& baseMatch, QuantifiersEngine* qe, int instLimit, bool addSplits ){
+ //now, try to add instantiation for each match produced
+ int addedLemmas = 0;
+ InstMatch m;
+ while( getNextMatch( m, qe ) ){
+ //m.makeInternal( d_quantEngine->getEqualityQuery() );
+ m.add( baseMatch );
+ if( qe->addInstantiation( f, m, addSplits ) ){
+ addedLemmas++;
+ if( instLimit>0 && addedLemmas==instLimit ){
+ return addedLemmas;
+ }
+ }
+ m.clear();
+ }
+ //return number of lemmas added
+ return addedLemmas;
+}
+
+int InstMatchGenerator::addTerm( Node f, Node t, QuantifiersEngine* qe ){
+ Assert( Options::current()->eagerInstQuant );
+ if( !d_match_pattern.isNull() ){
+ InstMatch m;
+ if( getMatch( t, m, qe ) ){
+ if( qe->addInstantiation( f, m ) ){
+ return 1;
+ }
+ }
+ }else{
+ for( int i=0; i<(int)d_children.size(); i++ ){
+ d_children[i]->addTerm( f, t, qe );
+ }
+ }
+ return 0;
+}
+
+/** constructors */
+InstMatchGeneratorMulti::InstMatchGeneratorMulti( Node f, std::vector< Node >& pats, QuantifiersEngine* qe, int matchOption ) :
+d_f( f ){
+ Debug("smart-multi-trigger") << "Making smart multi-trigger for " << f << std::endl;
+ std::map< Node, std::vector< Node > > var_contains;
+ Trigger::getVarContains( f, pats, var_contains );
+ //convert to indicies
+ for( std::map< Node, std::vector< Node > >::iterator it = var_contains.begin(); it != var_contains.end(); ++it ){
+ Debug("smart-multi-trigger") << "Pattern " << it->first << " contains: ";
+ for( int i=0; i<(int)it->second.size(); i++ ){
+ Debug("smart-multi-trigger") << it->second[i] << " ";
+ int index = it->second[i].getAttribute(InstVarNumAttribute());
+ d_var_contains[ it->first ].push_back( index );
+ d_var_to_node[ index ].push_back( it->first );
+ }
+ Debug("smart-multi-trigger") << std::endl;
+ }
+ for( int i=0; i<(int)pats.size(); i++ ){
+ Node n = pats[i];
+ //make the match generator
+ d_children.push_back( new InstMatchGenerator( n, qe, matchOption ) );
+ //compute unique/shared variables
+ std::vector< int > unique_vars;
+ std::map< int, bool > shared_vars;
+ int numSharedVars = 0;
+ for( int j=0; j<(int)d_var_contains[n].size(); j++ ){
+ if( d_var_to_node[ d_var_contains[n][j] ].size()==1 ){
+ Debug("smart-multi-trigger") << "Var " << d_var_contains[n][j] << " is unique to " << pats[i] << std::endl;
+ unique_vars.push_back( d_var_contains[n][j] );
+ }else{
+ shared_vars[ d_var_contains[n][j] ] = true;
+ numSharedVars++;
+ }
+ }
+ //we use the latest shared variables, then unique variables
+ std::vector< int > vars;
+ int index = i==0 ? (int)(pats.size()-1) : (i-1);
+ while( numSharedVars>0 && index!=i ){
+ for( std::map< int, bool >::iterator it = shared_vars.begin(); it != shared_vars.end(); ++it ){
+ if( it->second ){
+ if( std::find( d_var_contains[ pats[index] ].begin(), d_var_contains[ pats[index] ].end(), it->first )!=
+ d_var_contains[ pats[index] ].end() ){
+ vars.push_back( it->first );
+ shared_vars[ it->first ] = false;
+ numSharedVars--;
+ }
+ }
+ }
+ index = index==0 ? (int)(pats.size()-1) : (index-1);
+ }
+ vars.insert( vars.end(), unique_vars.begin(), unique_vars.end() );
+ Debug("smart-multi-trigger") << " Index[" << i << "]: ";
+ for( int i=0; i<(int)vars.size(); i++ ){
+ Debug("smart-multi-trigger") << vars[i] << " ";
+ }
+ Debug("smart-multi-trigger") << std::endl;
+ //make ordered inst match trie
+ InstMatchTrie::ImtIndexOrder* imtio = new InstMatchTrie::ImtIndexOrder;
+ imtio->d_order.insert( imtio->d_order.begin(), vars.begin(), vars.end() );
+ d_children_trie.push_back( InstMatchTrieOrdered( imtio ) );
+ }
+
+}
+
+/** reset instantiation round (call this whenever equivalence classes have changed) */
+void InstMatchGeneratorMulti::resetInstantiationRound( QuantifiersEngine* qe ){
+ for( int i=0; i<(int)d_children.size(); i++ ){
+ d_children[i]->resetInstantiationRound( qe );
+ }
+}
+
+/** reset, eqc is the equivalence class to search in (any if eqc=null) */
+void InstMatchGeneratorMulti::reset( Node eqc, QuantifiersEngine* qe ){
+ for( int i=0; i<(int)d_children.size(); i++ ){
+ d_children[i]->reset( eqc, qe );
+ }
+}
+
+void InstMatchGeneratorMulti::collectInstantiations( QuantifiersEngine* qe, InstMatch& m, int& addedLemmas, InstMatchTrie* tr,
+ std::vector< IndexedTrie >& unique_var_tries,
+ int trieIndex, int childIndex, int endChildIndex, bool modEq ){
+ if( childIndex==endChildIndex ){
+ //now, process unique variables
+ collectInstantiations2( qe, m, addedLemmas, unique_var_tries, 0 );
+ }else if( trieIndex<(int)d_children_trie[childIndex].getOrdering()->d_order.size() ){
+ int curr_index = d_children_trie[childIndex].getOrdering()->d_order[trieIndex];
+ Node curr_ic = qe->getInstantiationConstant( d_f, curr_index );
+ if( m.d_map.find( curr_ic )==m.d_map.end() ){
+ //if( d_var_to_node[ curr_index ].size()==1 ){ //FIXME
+ // //unique variable(s), defer calculation
+ // unique_var_tries.push_back( IndexedTrie( std::pair< int, int >( childIndex, trieIndex ), tr ) );
+ // int newChildIndex = (childIndex+1)%(int)d_children.size();
+ // collectInstantiations( qe, m, d_children_trie[newChildIndex].getTrie(), unique_var_tries,
+ // 0, newChildIndex, endChildIndex, modEq );
+ //}else{
+ //shared and non-set variable, add to InstMatch
+ for( std::map< Node, InstMatchTrie >::iterator it = tr->d_data.begin(); it != tr->d_data.end(); ++it ){
+ InstMatch mn( &m );
+ mn.d_map[ curr_ic ] = it->first;
+ collectInstantiations( qe, mn, addedLemmas, &(it->second), unique_var_tries,
+ trieIndex+1, childIndex, endChildIndex, modEq );
+ }
+ //}
+ }else{
+ //shared and set variable, try to merge
+ Node n = m.d_map[ curr_ic ];
+ std::map< Node, InstMatchTrie >::iterator it = tr->d_data.find( n );
+ if( it!=tr->d_data.end() ){
+ collectInstantiations( qe, m, addedLemmas, &(it->second), unique_var_tries,
+ trieIndex+1, childIndex, endChildIndex, modEq );
+ }
+ if( modEq ){
+ //check modulo equality for other possible instantiations
+ if( ((uf::TheoryUF*)qe->getTheoryEngine()->getTheory( THEORY_UF ))->getEqualityEngine()->hasTerm( n ) ){
+ eq::EqClassIterator eqc( qe->getEqualityQuery()->getRepresentative( n ),
+ ((uf::TheoryUF*)qe->getTheoryEngine()->getTheory( THEORY_UF ))->getEqualityEngine() );
+ while( !eqc.isFinished() ){
+ Node en = (*eqc);
+ if( en!=n ){
+ std::map< Node, InstMatchTrie >::iterator itc = tr->d_data.find( en );
+ if( itc!=tr->d_data.end() ){
+ collectInstantiations( qe, m, addedLemmas, &(itc->second), unique_var_tries,
+ trieIndex+1, childIndex, endChildIndex, modEq );
+ }
+ }
+ ++eqc;
+ }
+ }
+ }
+ }
+ }else{
+ int newChildIndex = (childIndex+1)%(int)d_children.size();
+ collectInstantiations( qe, m, addedLemmas, d_children_trie[newChildIndex].getTrie(), unique_var_tries,
+ 0, newChildIndex, endChildIndex, modEq );
+ }
+}
+
+void InstMatchGeneratorMulti::collectInstantiations2( QuantifiersEngine* qe, InstMatch& m, int& addedLemmas,
+ std::vector< IndexedTrie >& unique_var_tries,
+ int uvtIndex, InstMatchTrie* tr, int trieIndex ){
+ if( uvtIndex<(int)unique_var_tries.size() ){
+ int childIndex = unique_var_tries[uvtIndex].first.first;
+ if( !tr ){
+ tr = unique_var_tries[uvtIndex].second;
+ trieIndex = unique_var_tries[uvtIndex].first.second;
+ }
+ if( trieIndex<(int)d_children_trie[childIndex].getOrdering()->d_order.size() ){
+ int curr_index = d_children_trie[childIndex].getOrdering()->d_order[trieIndex];
+ Node curr_ic = qe->getInstantiationConstant( d_f, curr_index );
+ //unique non-set variable, add to InstMatch
+ for( std::map< Node, InstMatchTrie >::iterator it = tr->d_data.begin(); it != tr->d_data.end(); ++it ){
+ InstMatch mn( &m );
+ mn.d_map[ curr_ic ] = it->first;
+ collectInstantiations2( qe, mn, addedLemmas, unique_var_tries, uvtIndex, &(it->second), trieIndex+1 );
+ }
+ }else{
+ collectInstantiations2( qe, m, addedLemmas, unique_var_tries, uvtIndex+1 );
+ }
+ }else{
+ //m is an instantiation
+ if( qe->addInstantiation( d_f, m, true ) ){
+ addedLemmas++;
+ Debug("smart-multi-trigger") << "-> Produced instantiation " << m << std::endl;
+ }
+ }
+}
+
+int InstMatchGeneratorMulti::addInstantiations( Node f, InstMatch& baseMatch, QuantifiersEngine* qe, int instLimit, bool addSplits ){
+ int addedLemmas = 0;
+ Debug("smart-multi-trigger") << "Process smart multi trigger" << std::endl;
+ for( int i=0; i<(int)d_children.size(); i++ ){
+ Debug("smart-multi-trigger") << "Calculate matches " << i << std::endl;
+ std::vector< InstMatch > newMatches;
+ InstMatch m;
+ while( d_children[i]->getNextMatch( m, qe ) ){
+ m.makeRepresentative( qe );
+ newMatches.push_back( InstMatch( &m ) );
+ m.clear();
+ }
+ for( int j=0; j<(int)newMatches.size(); j++ ){
+ processNewMatch( qe, newMatches[j], i, addedLemmas );
+ }
+ }
+ return addedLemmas;
+}
+
+void InstMatchGeneratorMulti::processNewMatch( QuantifiersEngine* qe, InstMatch& m, int fromChildIndex, int& addedLemmas ){
+ //see if these produce new matches
+ d_children_trie[fromChildIndex].addInstMatch( qe, d_f, m, true );
+ //possibly only do the following if we know that new matches will be produced?
+ //the issue is that instantiations are filtered in quantifiers engine, and so there is no guarentee that
+ // we can safely skip the following lines, even when we have already produced this match.
+ Debug("smart-multi-trigger") << "Child " << fromChildIndex << " produced match " << m << std::endl;
+ //collect new instantiations
+ int childIndex = (fromChildIndex+1)%(int)d_children.size();
+ std::vector< IndexedTrie > unique_var_tries;
+ collectInstantiations( qe, m, addedLemmas,
+ d_children_trie[childIndex].getTrie(), unique_var_tries, 0, childIndex, fromChildIndex, true );
+}
+
+int InstMatchGeneratorMulti::addTerm( Node f, Node t, QuantifiersEngine* qe ){
+ Assert( Options::current()->eagerInstQuant );
+ int addedLemmas = 0;
+ for( int i=0; i<(int)d_children.size(); i++ ){
+ if( ((InstMatchGenerator*)d_children[i])->d_match_pattern.getOperator()==t.getOperator() ){
+ InstMatch m;
+ //if it produces a match, then process it with the rest
+ if( ((InstMatchGenerator*)d_children[i])->getMatch( t, m, qe ) ){
+ processNewMatch( qe, m, i, addedLemmas );
+ }
+ }
+ }
+ return addedLemmas;
+}
+
+int InstMatchGeneratorSimple::addInstantiations( Node f, InstMatch& baseMatch, QuantifiersEngine* qe, int instLimit, bool addSplits ){
+ InstMatch m;
+ 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_match_pattern.getOperator() ]),
+ instLimit, addSplits );
+ }
+ }else{
+ addInstantiations( m, qe, addedLemmas, 0, &(qe->getTermDatabase()->d_func_map_trie[ d_match_pattern.getOperator() ]),
+ instLimit, addSplits );
+ }
+ return addedLemmas;
+}
+
+void InstMatchGeneratorSimple::addInstantiations( InstMatch& m, QuantifiersEngine* qe, int& addedLemmas, int argIndex,
+ TermArgTrie* tat, int instLimit, bool addSplits ){
+ if( argIndex==(int)d_match_pattern.getNumChildren() ){
+ //m is an instantiation
+ if( qe->addInstantiation( d_f, m, addSplits ) ){
+ addedLemmas++;
+ Debug("simple-multi-trigger") << "-> Produced instantiation " << m << std::endl;
+ }
+ }else{
+ if( d_match_pattern[argIndex].getKind()==INST_CONSTANT ){
+ Node ic = d_match_pattern[argIndex];
+ for( std::map< Node, TermArgTrie >::iterator it = tat->d_data.begin(); it != tat->d_data.end(); ++it ){
+ Node t = it->first;
+ if( m.d_map[ ic ].isNull() || m.d_map[ ic ]==t ){
+ Node prev = m.d_map[ ic ];
+ m.d_map[ ic ] = t;
+ addInstantiations( m, qe, addedLemmas, argIndex+1, &(it->second), instLimit, addSplits );
+ m.d_map[ ic ] = prev;
+ }
+ }
+ }else{
+ Node r = qe->getEqualityQuery()->getRepresentative( d_match_pattern[argIndex] );
+ std::map< Node, TermArgTrie >::iterator it = tat->d_data.find( r );
+ if( it!=tat->d_data.end() ){
+ addInstantiations( m, qe, addedLemmas, argIndex+1, &(it->second), instLimit, addSplits );
+ }
+ }
+ }
+}
+
+int InstMatchGeneratorSimple::addTerm( Node f, Node t, QuantifiersEngine* qe ){
+ Assert( Options::current()->eagerInstQuant );
+ InstMatch m;
+ for( int i=0; i<(int)t.getNumChildren(); i++ ){
+ if( d_match_pattern[i].getKind()==INST_CONSTANT ){
+ m.d_map[d_match_pattern[i]] = t[i];
+ }else if( !qe->getEqualityQuery()->areEqual( d_match_pattern[i], t[i] ) ){
+ return 0;
+ }
+ }
+ return qe->addInstantiation( f, m ) ? 1 : 0;
+}
diff --git a/src/theory/inst_match.h b/src/theory/inst_match.h
new file mode 100644
index 000000000..73a99bcc5
--- /dev/null
+++ b/src/theory/inst_match.h
@@ -0,0 +1,443 @@
+/********************* */
+/*! \file inst_match.h
+ ** \verbatim
+ ** Original author: ajreynol
+ ** Major contributors: none
+ ** Minor contributors (to current version): none
+ ** This file is part of the CVC4 prototype.
+ ** Copyright (c) 2009, 2010, 2011 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
+ ** information.\endverbatim
+ **
+ ** \brief inst match class
+ **/
+
+#include "cvc4_private.h"
+
+#ifndef __CVC4__INST_MATCH_H
+#define __CVC4__INST_MATCH_H
+
+#include "theory/theory.h"
+#include "util/hash.h"
+
+#include <ext/hash_set>
+#include <iostream>
+#include <map>
+
+#include "theory/uf/equality_engine.h"
+#include "theory/uf/theory_uf.h"
+#include "context/cdlist.h"
+
+//#define USE_EFFICIENT_E_MATCHING
+
+namespace CVC4 {
+namespace theory {
+
+/** Attribute true for nodes that should not be used for matching */
+struct NoMatchAttributeId {};
+/** use the special for boolean flag */
+typedef expr::Attribute< NoMatchAttributeId,
+ bool,
+ expr::attr::NullCleanupStrategy,
+ true // context dependent
+ > NoMatchAttribute;
+
+class QuantifiersEngine;
+
+namespace uf {
+ class InstantiatorTheoryUf;
+ class TheoryUF;
+}/* CVC4::theory::uf namespace */
+
+class CandidateGenerator {
+public:
+ CandidateGenerator(){}
+ ~CandidateGenerator(){}
+
+ /** Get candidates functions. These set up a context to get all match candidates.
+ cg->reset( eqc );
+ do{
+ Node cand = cg->getNextCandidate();
+ //.......
+ }while( !cand.isNull() );
+
+ eqc is the equivalence class you are searching in
+ */
+ virtual void reset( Node eqc ) = 0;
+ virtual Node getNextCandidate() = 0;
+ /** add candidate to list of nodes returned by this generator */
+ virtual void addCandidate( Node n ) {}
+ /** call this at the beginning of each instantiation round */
+ virtual void resetInstantiationRound() = 0;
+public:
+ /** legal candidate */
+ static bool isLegalCandidate( Node n );
+};/* class CandidateGenerator */
+
+/** candidate generator queue (for manual candidate generation) */
+class CandidateGeneratorQueue : public CandidateGenerator {
+private:
+ std::vector< Node > d_candidates;
+ int d_candidate_index;
+public:
+ CandidateGeneratorQueue() : d_candidate_index( 0 ){}
+ ~CandidateGeneratorQueue(){}
+
+ void addCandidate( Node n );
+
+ void resetInstantiationRound(){}
+ void reset( Node eqc );
+ Node getNextCandidate();
+};/* class CandidateGeneratorQueue */
+
+class EqualityQuery {
+public:
+ EqualityQuery(){}
+ ~EqualityQuery(){}
+ /** contains term */
+ virtual bool hasTerm( Node a ) = 0;
+ /** get the representative of the equivalence class of a */
+ virtual Node getRepresentative( Node a ) = 0;
+ /** returns true if a and b are equal in the current context */
+ virtual bool areEqual( Node a, Node b ) = 0;
+ /** returns true is a and b are disequal in the current context */
+ virtual bool areDisequal( Node a, Node b ) = 0;
+ /** getInternalRepresentative gets the current best representative in the equivalence class of a, based on some criteria.
+ If cbqi is active, this will return a term in the equivalence class of "a" that does
+ not contain instantiation constants, if such a term exists.
+ */
+ virtual Node getInternalRepresentative( Node a ) = 0;
+};/* class EqualityQuery */
+
+/** basic class defining an instantiation */
+class InstMatch {
+public:
+ InstMatch();
+ InstMatch( InstMatch* m );
+
+ /** set the match of v to m */
+ bool setMatch( EqualityQuery* q, Node v, Node m );
+ /** fill all unfilled values with m */
+ bool add( InstMatch& m );
+ /** if compatible, fill all unfilled values with m and return true
+ return false otherwise */
+ bool merge( EqualityQuery* q, InstMatch& m );
+ /** debug print method */
+ void debugPrint( const char* c );
+ /** make complete */
+ void makeComplete( Node f, QuantifiersEngine* qe );
+ /** make internal: ensure that no term in d_map contains instantiation constants */
+ void makeInternal( QuantifiersEngine* qe );
+ /** make representative */
+ void makeRepresentative( QuantifiersEngine* qe );
+ /** apply rewrite */
+ void applyRewrite();
+ /** compute d_match */
+ void computeTermVec( QuantifiersEngine* qe, const std::vector< Node >& vars, std::vector< Node >& match );
+ /** compute d_match */
+ void computeTermVec( const std::vector< Node >& vars, std::vector< Node >& match );
+ /** clear */
+ void clear(){ d_map.clear(); }
+ /** is_empty */
+ bool empty(){ return d_map.empty(); }
+ /* map from variable to ground terms */
+ std::map< Node, Node > d_map;
+ /* Node used for matching the trigger only for mono-trigger (just for
+ efficiency because I need only that) */
+ Node d_matched;
+ /** to stream */
+ inline void toStream(std::ostream& out) const {
+ out << "INST_MATCH( ";
+ for( std::map< Node, Node >::const_iterator it = d_map.begin(); it != d_map.end(); ++it ){
+ if( it != d_map.begin() ){ out << ", "; }
+ out << it->first << " -> " << it->second;
+ }
+ out << " )";
+ }
+};/* class InstMatch */
+
+inline std::ostream& operator<<(std::ostream& out, const InstMatch& m) {
+ m.toStream(out);
+ return out;
+}
+
+/** trie for InstMatch objects */
+class InstMatchTrie {
+public:
+ class ImtIndexOrder {
+ public:
+ std::vector< int > d_order;
+ };/* class InstMatchTrie ImtIndexOrder */
+private:
+ /** add match m for quantifier f starting at index, take into account equalities q, return true if successful */
+ void addInstMatch2( QuantifiersEngine* qe, Node f, InstMatch& m, int index, ImtIndexOrder* imtio );
+ /** exists match */
+ bool existsInstMatch( QuantifiersEngine* qe, Node f, InstMatch& m, bool modEq, int index, ImtIndexOrder* imtio );
+public:
+ /** the data */
+ std::map< Node, InstMatchTrie > d_data;
+public:
+ InstMatchTrie(){}
+ ~InstMatchTrie(){}
+public:
+ /** add match m for quantifier f, take into account equalities if modEq = true,
+ if imtio is non-null, this is the order to add to trie
+ return true if successful
+ */
+ bool addInstMatch( QuantifiersEngine* qe, Node f, InstMatch& m, bool modEq = false, ImtIndexOrder* imtio = NULL );
+};/* class InstMatchTrie */
+
+class InstMatchTrieOrdered {
+private:
+ InstMatchTrie::ImtIndexOrder* d_imtio;
+ InstMatchTrie d_imt;
+public:
+ InstMatchTrieOrdered( InstMatchTrie::ImtIndexOrder* imtio ) : d_imtio( imtio ){}
+ ~InstMatchTrieOrdered(){}
+ /** get ordering */
+ InstMatchTrie::ImtIndexOrder* getOrdering() { return d_imtio; }
+ /** get trie */
+ InstMatchTrie* getTrie() { return &d_imt; }
+public:
+ /** add match m, return true if successful */
+ bool addInstMatch( QuantifiersEngine* qe, Node f, InstMatch& m, bool modEq = false ){
+ return d_imt.addInstMatch( qe, f, m, modEq, d_imtio );
+ }
+};/* class InstMatchTrieOrdered */
+
+template<bool modEq = false>
+class InstMatchTrie2 {
+private:
+
+ class Tree {
+ public:
+ typedef std::hash_map< Node, Tree *, NodeHashFunction > MLevel;
+ MLevel e;
+ const size_t level; //context level of creation
+ Tree() CVC4_UNDEFINED;
+ const Tree & operator =(const Tree & t) CVC4_UNDEFINED;
+ Tree(size_t l): level(l) {};
+ ~Tree(){
+ for(typename MLevel::iterator i = e.begin(); i!=e.end(); ++i)
+ delete(i->second);
+ };
+ };/* class InstMatchTrie2::Tree */
+
+
+ typedef std::pair<Tree *, TNode> Mod;
+
+ class CleanUp {
+ public:
+ inline void operator()(Mod * m){
+ typename Tree::MLevel::iterator i = m->first->e.find(m->second);
+ Assert (i != m->first->e.end()); //should not have been already removed
+ m->first->e.erase(i);
+ }
+ };/* class InstMatchTrie2::CleanUp */
+
+ EqualityQuery* d_eQ;
+ eq::EqualityEngine* d_eE;
+
+ /* before for the order of destruction */
+ Tree d_data;
+
+ context::Context* d_context;
+ context::CDList<Mod, CleanUp, std::allocator<Mod> > d_mods;
+
+ typedef std::map<Node, Node>::const_iterator mapIter;
+
+ /** add the substitution given by the iterator*/
+ void addSubTree( Tree* root, mapIter current, mapIter end, size_t currLevel);
+ /** test if it exists match, modulo uf-equations if modEq is true if
+ * return false the deepest point of divergence is put in [e] and
+ * [diverge].
+ */
+ bool existsInstMatch( Tree* root,
+ mapIter & current, mapIter& end,
+ Tree*& e, mapIter& diverge) const;
+
+public:
+ InstMatchTrie2(context::Context* c, QuantifiersEngine* q);
+ InstMatchTrie2(const InstMatchTrie2&) CVC4_UNDEFINED;
+ const InstMatchTrie2& operator=(const InstMatchTrie2 & e) CVC4_UNDEFINED;
+ /** add match m in the trie,
+ modEq specify to take into account equalities,
+ return true if it was never seen */
+ bool addInstMatch( InstMatch& m);
+};/* class InstMatchTrie2 */
+
+/** base class for producing InstMatch objects */
+class IMGenerator {
+public:
+ /** reset instantiation round (call this at beginning of instantiation round) */
+ virtual void resetInstantiationRound( QuantifiersEngine* qe ) = 0;
+ /** reset, eqc is the equivalence class to search in (any if eqc=null) */
+ virtual void reset( Node eqc, QuantifiersEngine* qe ) = 0;
+ /** get the next match. must call reset( eqc ) before this function. */
+ virtual bool getNextMatch( InstMatch& m, QuantifiersEngine* qe ) = 0;
+ /** return true if whatever Node is subsituted for the variables the
+ given Node can't match the pattern */
+ virtual bool nonunifiable( TNode t, const std::vector<Node> & vars) = 0;
+ /** add instantiations directly */
+ virtual int addInstantiations( Node f, InstMatch& baseMatch, QuantifiersEngine* qe, int instLimit = 0, bool addSplits = false ) = 0;
+ /** add ground term t, called when t is added to term db */
+ virtual int addTerm( Node f, Node t, QuantifiersEngine* qe ) = 0;
+};/* class IMGenerator */
+
+
+class InstMatchGenerator : public IMGenerator {
+private:
+ /** candidate generator */
+ CandidateGenerator* d_cg;
+ /** policy to use for matching */
+ int d_matchPolicy;
+ /** children generators */
+ std::vector< InstMatchGenerator* > d_children;
+ std::vector< int > d_children_index;
+ /** partial vector */
+ std::vector< InstMatch > d_partial;
+ /** eq class */
+ Node d_eq_class;
+ /** for arithmetic matching */
+ std::map< Node, Node > d_arith_coeffs;
+ /** initialize pattern */
+ void initializePatterns( std::vector< Node >& pats, QuantifiersEngine* qe );
+ void initializePattern( Node pat, 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_ARITHMETIC,
+ MATCH_GEN_INTERNAL_ERROR,
+ };
+private:
+ /** get the next match. must call d_cg->reset( ... ) before using.
+ only valid for use where !d_match_pattern.isNull().
+ */
+ bool getNextMatch2( InstMatch& m, QuantifiersEngine* qe, bool saveMatched = false );
+ /** for arithmetic */
+ bool getMatchArithmetic( Node t, InstMatch& m, QuantifiersEngine* qe );
+public:
+ /** get the match against ground term or formula t.
+ d_match_mattern and t should have the same shape.
+ only valid for use where !d_match_pattern.isNull().
+ */
+ bool getMatch( Node t, InstMatch& m, QuantifiersEngine* qe );
+
+ /** constructors */
+ InstMatchGenerator( Node pat, QuantifiersEngine* qe, int matchOption = 0 );
+ InstMatchGenerator( std::vector< Node >& pats, QuantifiersEngine* qe, int matchOption = 0 );
+ /** destructor */
+ ~InstMatchGenerator(){}
+ /** The pattern we are producing matches for.
+ If null, this is a multi trigger that is merging matches from d_children.
+ */
+ Node d_pattern;
+ /** match pattern */
+ Node d_match_pattern;
+public:
+ /** reset instantiation round (call this whenever equivalence classes have changed) */
+ void resetInstantiationRound( QuantifiersEngine* qe );
+ /** reset, eqc is the equivalence class to search in (any if eqc=null) */
+ void reset( Node eqc, QuantifiersEngine* qe );
+ /** get the next match. must call reset( eqc ) before this function. */
+ bool getNextMatch( InstMatch& m, QuantifiersEngine* qe );
+ /** return true if whatever Node is subsituted for the variables the
+ given Node can't match the pattern */
+ bool nonunifiable( TNode t, const std::vector<Node> & vars);
+ /** add instantiations */
+ int addInstantiations( Node f, InstMatch& baseMatch, QuantifiersEngine* qe, int instLimit = 0, bool addSplits = false );
+ /** add ground term t */
+ int addTerm( Node f, Node t, QuantifiersEngine* qe );
+};/* class InstMatchGenerator */
+
+/** smart multi-trigger implementation */
+class InstMatchGeneratorMulti : public IMGenerator {
+private:
+ void processNewMatch( QuantifiersEngine* qe, InstMatch& m, int fromChildIndex, int& addedLemmas );
+private:
+ /** indexed trie */
+ typedef std::pair< std::pair< int, int >, InstMatchTrie* > IndexedTrie;
+ /** collect instantiations */
+ void collectInstantiations( QuantifiersEngine* qe, InstMatch& m, int& addedLemmas, InstMatchTrie* tr,
+ std::vector< IndexedTrie >& unique_var_tries,
+ int trieIndex, int childIndex, int endChildIndex, bool modEq );
+ /** collect instantiations 2 */
+ void collectInstantiations2( QuantifiersEngine* qe, InstMatch& m, int& addedLemmas,
+ std::vector< IndexedTrie >& unique_var_tries,
+ int uvtIndex, InstMatchTrie* tr = NULL, int trieIndex = 0 );
+private:
+ /** var contains (variable indicies) for each pattern node */
+ std::map< Node, std::vector< int > > d_var_contains;
+ /** variable indicies contained to pattern nodes */
+ std::map< int, std::vector< Node > > d_var_to_node;
+ /** quantifier to use */
+ Node d_f;
+ /** policy to use for matching */
+ int d_matchPolicy;
+ /** children generators */
+ std::vector< InstMatchGenerator* > d_children;
+ /** inst match tries for each child */
+ std::vector< InstMatchTrieOrdered > d_children_trie;
+ /** calculate matches */
+ void calculateMatches( QuantifiersEngine* qe );
+public:
+ /** constructors */
+ InstMatchGeneratorMulti( Node f, std::vector< Node >& pats, QuantifiersEngine* qe, int matchOption = 0 );
+ /** destructor */
+ ~InstMatchGeneratorMulti(){}
+ /** reset instantiation round (call this whenever equivalence classes have changed) */
+ void resetInstantiationRound( QuantifiersEngine* qe );
+ /** reset, eqc is the equivalence class to search in (any if eqc=null) */
+ void reset( Node eqc, QuantifiersEngine* qe );
+ /** get the next match. must call reset( eqc ) before this function. (not implemented) */
+ bool getNextMatch( InstMatch& m, QuantifiersEngine* qe ) { return false; }
+ /** return true if whatever Node is subsituted for the variables the
+ given Node can't match the pattern */
+ bool nonunifiable( TNode t, const std::vector<Node> & vars) { return true; }
+ /** add instantiations */
+ int addInstantiations( Node f, InstMatch& baseMatch, QuantifiersEngine* qe, int instLimit = 0, bool addSplits = false );
+ /** add ground term t */
+ int addTerm( Node f, Node t, QuantifiersEngine* qe );
+};/* class InstMatchGeneratorMulti */
+
+class TermArgTrie;
+
+/** smart (single)-trigger implementation */
+class InstMatchGeneratorSimple : public IMGenerator {
+private:
+ /** quantifier for match term */
+ Node d_f;
+ /** match term */
+ Node d_match_pattern;
+ /** add instantiations */
+ void addInstantiations( InstMatch& m, QuantifiersEngine* qe, int& addedLemmas,
+ int argIndex, TermArgTrie* tat, int instLimit, bool addSplits );
+public:
+ /** constructors */
+ InstMatchGeneratorSimple( Node f, Node pat ) : d_f( f ), d_match_pattern( pat ){}
+ /** destructor */
+ ~InstMatchGeneratorSimple(){}
+ /** reset instantiation round (call this whenever equivalence classes have changed) */
+ void resetInstantiationRound( QuantifiersEngine* qe ) {}
+ /** reset, eqc is the equivalence class to search in (any if eqc=null) */
+ void reset( Node eqc, QuantifiersEngine* qe ) {}
+ /** get the next match. must call reset( eqc ) before this function. (not implemented) */
+ bool getNextMatch( InstMatch& m, QuantifiersEngine* qe ) { return false; }
+ /** return true if whatever Node is subsituted for the variables the
+ given Node can't match the pattern */
+ bool nonunifiable( TNode t, const std::vector<Node> & vars) { return true; }
+ /** add instantiations */
+ int addInstantiations( Node f, InstMatch& baseMatch, QuantifiersEngine* qe, int instLimit = 0, bool addSplits = false );
+ /** add ground term t, possibly add instantiations */
+ int addTerm( Node f, Node t, QuantifiersEngine* qe );
+};/* class InstMatchGeneratorSimple */
+
+}/* CVC4::theory namespace */
+}/* CVC4 namespace */
+
+#endif /* __CVC4__INST_MATCH_H */
diff --git a/src/theory/inst_match_impl.h b/src/theory/inst_match_impl.h
new file mode 100644
index 000000000..18c4998b8
--- /dev/null
+++ b/src/theory/inst_match_impl.h
@@ -0,0 +1,125 @@
+/********************* */
+/*! \file inst_match.h
+ ** \verbatim
+ ** Original author: ajreynol
+ ** Major contributors: none
+ ** Minor contributors (to current version): none
+ ** This file is part of the CVC4 prototype.
+ ** Copyright (c) 2009, 2010, 2011 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
+ ** information.\endverbatim
+ **
+ ** \brief inst match class
+ **/
+
+#include "cvc4_private.h"
+
+#ifndef __CVC4__INST_MATCH_IMPL_H
+#define __CVC4__INST_MATCH_IMPL_H
+
+#include "theory/inst_match.h"
+#include "theory/theory_engine.h"
+#include "theory/quantifiers_engine.h"
+#include "theory/uf/theory_uf_instantiator.h"
+#include "theory/uf/theory_uf_candidate_generator.h"
+#include "theory/uf/equality_engine.h"
+
+namespace CVC4 {
+namespace theory {
+
+template<bool modEq>
+InstMatchTrie2<modEq>::InstMatchTrie2(context::Context* c, QuantifiersEngine* qe):
+ d_data(c->getLevel()), d_context(c), d_mods(c) {
+ d_eQ = qe->getEqualityQuery();
+ d_eE = ((uf::TheoryUF*)qe->getTheoryEngine()->getTheory( THEORY_UF ))->getEqualityEngine();
+};
+
+/** add match m for quantifier f starting at index, take into account equalities q, return true if successful */
+template<bool modEq>
+void InstMatchTrie2<modEq>::addSubTree( Tree * root, mapIter current, mapIter end, size_t currLevel ) {
+ if( current == end ) return;
+
+ Assert(root->e.find(current->second) == root->e.end());
+ Tree * root2 = new Tree(currLevel);
+ root->e.insert(make_pair(current->second, root2));
+ addSubTree(root2, ++current, end, currLevel );
+}
+
+/** exists match */
+template<bool modEq>
+bool InstMatchTrie2<modEq>::existsInstMatch(InstMatchTrie2<modEq>::Tree * root,
+ mapIter & current, mapIter & end,
+ Tree * & e, mapIter & diverge) const{
+ if( current == end ) {
+ Debug("Trie2") << "Trie2 Bottom " << std::endl;
+ --current;
+ return true;
+ }; //Already their
+
+ if (current->first > diverge->first){
+ // this point is the deepest point currently seen map are ordered
+ e = root;
+ diverge = current;
+ };
+
+ TNode n = current->second;
+ typename InstMatchTrie2<modEq>::Tree::MLevel::iterator it =
+ root->e.find( n );
+ if( it!=root->e.end() &&
+ existsInstMatch( (*it).second, ++current, end, e, diverge) ){
+ Debug("Trie2") << "Trie2 Directly here " << n << std::endl;
+ --current;
+ return true;
+ }
+ Assert( it==root->e.end() || e != root );
+
+ // Even if n is in the trie others of the equivalence class
+ // can also be in it since the equality can have appeared
+ // after they have been added
+ if( modEq && d_eE->hasTerm( n ) ){
+ //check modulo equality if any other instantiation match exists
+ eq::EqClassIterator eqc( d_eQ->getRepresentative( n ), d_eE );
+ for( ;!eqc.isFinished();++eqc ){
+ TNode en = (*eqc);
+ if( en == n ) continue; // already tested
+ typename InstMatchTrie2<modEq>::Tree::MLevel::iterator itc =
+ root->e.find( en );
+ if( itc!=root->e.end() &&
+ existsInstMatch( (*itc).second, ++current, end, e, diverge) ){
+ Debug("Trie2") << "Trie2 Indirectly here by equality " << n << " = " << en << std::endl;
+ --current;
+ return true;
+ }
+ Assert( itc==root->e.end() || e != root );
+ }
+ }
+ --current;
+ return false;
+}
+
+template<bool modEq>
+bool InstMatchTrie2<modEq>::addInstMatch( InstMatch& m ) {
+ mapIter begin = m.d_map.begin();
+ mapIter end = m.d_map.end();
+ InstMatchTrie2<modEq>::Tree * e = &d_data;
+ mapIter diverge = begin;
+ if( !existsInstMatch(e, begin, end, e, diverge ) ){
+ Assert(!diverge->second.isNull());
+ size_t currLevel = d_context->getLevel();
+ addSubTree( e, diverge, end, currLevel );
+ if(e->level != currLevel)
+ //If same level that e, will be removed at the same time than e
+ d_mods.push_back(make_pair(e,diverge->second));
+ return true;
+ }else{
+ return false;
+ }
+}
+
+}/* CVC4::theory namespace */
+
+}/* CVC4 namespace */
+
+#endif /* __CVC4__INST_MATCH_IMPL_H */
diff --git a/src/theory/instantiator_default.cpp b/src/theory/instantiator_default.cpp
new file mode 100644
index 000000000..4d6ea2fdb
--- /dev/null
+++ b/src/theory/instantiator_default.cpp
@@ -0,0 +1,54 @@
+/********************* */
+/*! \file instantiator_default.cpp
+ ** \verbatim
+ ** Original author: ajreynol
+ ** Major contributors: none
+ ** Minor contributors (to current version): none
+ ** This file is part of the CVC4 prototype.
+ ** Copyright (c) 2009, 2010, 2011 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
+ ** information.\endverbatim
+ **
+ ** \brief Implementation of instantiator_default class
+ **/
+
+#include "theory/instantiator_default.h"
+#include "theory/theory_engine.h"
+
+using namespace std;
+using namespace CVC4;
+using namespace CVC4::kind;
+using namespace CVC4::context;
+using namespace CVC4::theory;
+
+InstantiatorDefault::InstantiatorDefault(context::Context* c, QuantifiersEngine* ie, Theory* th) :
+ Instantiator( c, ie, th ) {
+}
+
+void InstantiatorDefault::assertNode( Node assertion ){
+}
+
+void InstantiatorDefault::processResetInstantiationRound( Theory::Effort effort ){
+}
+
+int InstantiatorDefault::process( Node f, Theory::Effort effort, int e, int limitInst ){
+ if( e < 4 ){
+ return InstStrategy::STATUS_UNFINISHED;
+ }else if( e == 4 ){
+ Debug("quant-default") << "Process " << f << " : " << std::endl;
+ InstMatch m;
+ for( int j=0; j<(int)d_quantEngine->getNumInstantiationConstants( f ); j++ ){
+ Node i = d_quantEngine->getInstantiationConstant( f, j );
+ Debug("quant-default") << "Getting value for " << i << std::endl;
+ if( d_quantEngine->getTheoryEngine()->theoryOf( i )==getTheory() ){ //if it belongs to this theory
+ Node val = d_th->getValue( i );
+ Debug("quant-default") << "Default Instantiate for " << d_th->getId() << ", setting " << i << " = " << val << std::endl;
+ m.d_map[ i ] = val;
+ }
+ }
+ d_quantEngine->addInstantiation( f, m );
+ }
+ return InstStrategy::STATUS_UNKNOWN;
+}
diff --git a/src/theory/instantiator_default.h b/src/theory/instantiator_default.h
new file mode 100644
index 000000000..351d0c4a3
--- /dev/null
+++ b/src/theory/instantiator_default.h
@@ -0,0 +1,48 @@
+/********************* */
+/*! \file instantiator_default.h
+ ** \verbatim
+ ** Original author: ajreynol
+ ** Major contributors: none
+ ** Minor contributors (to current version): none
+ ** This file is part of the CVC4 prototype.
+ ** Copyright (c) 2009, 2010, 2011 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
+ ** information.\endverbatim
+ **
+ ** \brief instantiator_default
+ **/
+
+
+#include "cvc4_private.h"
+
+#ifndef __CVC4__INSTANTIATOR_DEFAULT_H
+#define __CVC4__INSTANTIATOR_DEFAULT_H
+
+#include <string>
+#include "theory/quantifiers_engine.h"
+
+namespace CVC4 {
+namespace theory {
+
+class InstantiatorDefault : public Instantiator {
+ friend class QuantifiersEngine;
+protected:
+ /** reset instantiation round */
+ void processResetInstantiationRound(Theory::Effort effort);
+ /** process quantifier */
+ int process(Node f, Theory::Effort effort, int e, int limitInst = 0);
+public:
+ InstantiatorDefault(context::Context* c, QuantifiersEngine* ie, Theory* th);
+ ~InstantiatorDefault() { }
+ /** check function, assertion is asserted to theory */
+ void assertNode( Node assertion );
+ /** identify */
+ std::string identify() const { return std::string("InstantiatorDefault"); }
+};/* class Instantiatior */
+
+}/* CVC4::theory namespace */
+}/* CVC4 namespace */
+
+#endif /* __CVC4__INSTANTIATOR_DEFAULT_H */
diff --git a/src/theory/instantiator_tables_template.cpp b/src/theory/instantiator_tables_template.cpp
new file mode 100644
index 000000000..7a78c3aae
--- /dev/null
+++ b/src/theory/instantiator_tables_template.cpp
@@ -0,0 +1,40 @@
+/********************* */
+/*! \file instantiator_tables_template.cpp
+ ** \verbatim
+ ** Original author: mdeters
+ ** Major contributors: none
+ ** Minor contributors (to current version): none
+ ** This file is part of the CVC4 prototype.
+ ** Copyright (c) 2009, 2010, 2011, 2012 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
+ ** information.\endverbatim
+ **
+ ** \brief Instantiator tables for quantifier-friendly theories
+ **
+ ** This file contains template code for the instantiator tables that are
+ ** generated from the Theory kinds files.
+ **/
+
+#include "context/context.h"
+#include "theory/quantifiers_engine.h"
+
+${instantiator_includes}
+
+#line 26 "${template}"
+
+namespace CVC4 {
+namespace theory {
+
+Instantiator* Theory::makeInstantiator(context::Context* c, theory::QuantifiersEngine* qe) {
+ switch(d_id) {
+${make_instantiator_cases}
+#line 34 "${template}"
+ default:
+ Unhandled(d_id);
+ }
+}
+
+}/* CVC4::theory namespace */
+}/* CVC4 namespace */
diff --git a/src/theory/mkinstantiator b/src/theory/mkinstantiator
new file mode 100755
index 000000000..1908d2e96
--- /dev/null
+++ b/src/theory/mkinstantiator
@@ -0,0 +1,242 @@
+#!/bin/bash
+#
+# mkinstantiator
+# Morgan Deters <mdeters@cs.nyu.edu> for CVC4
+# Copyright (c) 2010-2012 The CVC4 Project
+#
+# The purpose of this script is to create rewriter_tables.h from a template
+# and a list of theory kinds.
+#
+# Invocation:
+#
+# mkinstantiator template-file theory-kind-files...
+#
+# Output is to standard out.
+#
+
+copyright=2010-2012
+
+cat <<EOF
+/********************* */
+/** instantiator_tables.h
+ **
+ ** Copyright $copyright The AcSys Group, New York University, and as below.
+ **
+ ** This header file automatically generated by:
+ **
+ ** $0 $@
+ **
+ ** for the CVC4 project.
+ **/
+
+EOF
+
+me=$(basename "$0")
+
+template=$1; shift
+
+instantiator_includes=
+instantiator_class=
+theory_id=
+theory_class=
+theory_header=
+
+make_instantiator_cases=
+instantiator=
+
+seen_theory=false
+seen_theory_builtin=false
+
+function theory {
+ # theory id T header
+
+ lineno=${BASH_LINENO[0]}
+
+ if $seen_theory; then
+ echo "$kf:$lineno: theory declaration can only appear once" >&2
+ exit 1;
+ fi
+
+ seen_theory=true
+ if [ "$1" = THEORY_BUILTIN ]; then
+ if $seen_theory_builtin; then
+ echo "$kf:$lineno: error: \"builtin\" theory redefined" >&2
+ exit 1
+ fi
+ seen_theory_builtin=true
+ elif [ -z "$1" -o -z "$2" -o -z "$3" ]; then
+ echo "$kf:$lineno: error: \"theory\" directive missing class or header argument" >&2
+ exit 1
+ elif ! expr "$2" : '\(::*\)' >/dev/null; then
+ echo "$kf:$lineno: warning: theory class \`$2' isn't fully-qualified (e.g., ::CVC4::theory::foo)" >&2
+ elif ! expr "$2" : '\(::CVC4::theory::*\)' >/dev/null; then
+ echo "$kf:$lineno: warning: theory class not under ::CVC4::theory namespace" >&2
+ fi
+
+ theory_id="$1"
+ theory_class="$2"
+ theory_header="$3"
+
+ instantiator_class=
+ instantiator=NULL
+}
+
+function instantiator {
+ # instantiator class header
+ lineno=${BASH_LINENO[0]}
+ check_theory_seen
+
+ if [ -n "$instantiator_class" ]; then
+ echo "$kf:$lineno: error: cannot have two \"instantiator\" directives" >&2
+ exit 1
+ fi
+
+ instantiator_class="$1"
+ instantiator_header="$2"
+
+ if [ -z "$instantiator_class" -o -z "$instantiator_header" ]; then
+ echo "$kf:$lineno: error: \"instantiator\" directive missing class or header argument" >&2
+ exit 1
+ fi
+
+ instantiator_includes="${instantiator_includes}#include \"$theory_header\"
+#line $lineno \"$kf\"
+#include \"$instantiator_header\"
+"
+ instantiator="new $instantiator_class(c, qe, static_cast< $theory_class* >(this))";
+}
+
+function properties {
+ # properties prop*
+ lineno=${BASH_LINENO[0]}
+ check_theory_seen
+}
+
+function endtheory {
+ # endtheory
+ lineno=${BASH_LINENO[0]}
+ check_theory_seen
+ seen_endtheory=true
+
+ make_instantiator_cases="${make_instantiator_cases}
+#line $lineno \"$kf\"
+ case $theory_id:
+ return $instantiator;
+"
+}
+
+function typechecker {
+ # typechecker header
+ lineno=${BASH_LINENO[0]}
+ check_theory_seen
+}
+
+function typerule {
+ # typerule OPERATOR typechecking-class
+ lineno=${BASH_LINENO[0]}
+ check_theory_seen
+}
+
+function rewriter {
+ # rewriter class header
+ lineno=${BASH_LINENO[0]}
+ check_theory_seen
+}
+
+function sort {
+ # sort TYPE cardinality [well-founded ground-term header | not-well-founded] ["comment"]
+ lineno=${BASH_LINENO[0]}
+ check_theory_seen
+}
+
+function cardinality {
+ # cardinality TYPE cardinality-computer [header]
+ lineno=${BASH_LINENO[0]}
+ check_theory_seen
+}
+
+function well-founded {
+ # well-founded TYPE wellfoundedness-computer [header]
+ lineno=${BASH_LINENO[0]}
+ check_theory_seen
+}
+
+function variable {
+ # variable K ["comment"]
+ lineno=${BASH_LINENO[0]}
+ check_theory_seen
+}
+
+function operator {
+ # operator K #children ["comment"]
+ lineno=${BASH_LINENO[0]}
+ check_theory_seen
+}
+
+function parameterized {
+ # parameterized K1 K2 #children ["comment"]
+ lineno=${BASH_LINENO[0]}
+ check_theory_seen
+}
+
+function constant {
+ # constant K T Hasher header ["comment"]
+ lineno=${BASH_LINENO[0]}
+ check_theory_seen
+}
+
+function check_theory_seen {
+ if $seen_endtheory; then
+ echo "$kf:$lineno: error: command after \"endtheory\" declaration (endtheory has to be last)" >&2
+ exit 1
+ fi
+ if ! $seen_theory; then
+ echo "$kf:$lineno: error: no \"theory\" declaration found (it has to be first)" >&2
+ exit 1
+ fi
+}
+
+function check_builtin_theory_seen {
+ if ! $seen_theory_builtin; then
+ echo "$me: warning: no declaration for the builtin theory found" >&2
+ fi
+}
+
+while [ $# -gt 0 ]; do
+ kf=$1
+ seen_theory=false
+ seen_endtheory=false
+ b=$(basename $(dirname "$kf"))
+ source "$kf"
+ if ! $seen_theory; then
+ echo "$kf: error: no theory content found in file!" >&2
+ exit 1
+ fi
+ if ! $seen_endtheory; then
+ echo "$kf:$lineno: error: no \"endtheory\" declaration found (it is required at the end)" >&2
+ exit 1
+ fi
+ shift
+done
+check_builtin_theory_seen
+
+## output
+
+# generate warnings about incorrect #line annotations in templates
+nl -ba -s' ' "$template" | grep '^ *[0-9][0-9]* # *line' |
+ awk '{OFS="";if($1+1!=$3) print "'"$template"':",$1,": warning: incorrect annotation \"#line ",$3,"\" (it should be \"#line ",($1+1),"\")"}' >&2
+
+text=$(cat "$template")
+for var in \
+ instantiator_includes \
+ make_instantiator_cases \
+ template \
+ ; do
+ eval text="\${text//\\\$\\{$var\\}/\${$var}}"
+done
+error=`expr "$text" : '.*\${\([^}]*\)}.*'`
+if [ -n "$error" ]; then
+ echo "$template:0: error: undefined replacement \${$error}" >&2
+ exit 1
+fi
+echo "$text"
diff --git a/src/theory/mkrewriter b/src/theory/mkrewriter
index b8fa51d77..780409d52 100755
--- a/src/theory/mkrewriter
+++ b/src/theory/mkrewriter
@@ -2,7 +2,7 @@
#
# mkrewriter
# Morgan Deters <mdeters@cs.nyu.edu> for CVC4
-# Copyright (c) 2010-2011 The CVC4 Project
+# Copyright (c) 2010-2012 The CVC4 Project
#
# The purpose of this script is to create rewriter_tables.h from a template
# and a list of theory kinds.
@@ -14,7 +14,7 @@
# Output is to standard out.
#
-copyright=2010-2011
+copyright=2010-2012
cat <<EOF
/********************* */
@@ -83,6 +83,12 @@ function theory {
theory_id="$1"
}
+function instantiator {
+ # instantiator class header
+ lineno=${BASH_LINENO[0]}
+ check_theory_seen
+}
+
function properties {
# properties prop*
lineno=${BASH_LINENO[0]}
diff --git a/src/theory/mktheorytraits b/src/theory/mktheorytraits
index 2d3b4a43a..297df1f36 100755
--- a/src/theory/mktheorytraits
+++ b/src/theory/mktheorytraits
@@ -2,7 +2,7 @@
#
# mktheorytraits
# Morgan Deters <mdeters@cs.nyu.edu> for CVC4
-# Copyright (c) 2010-2011 The CVC4 Project
+# Copyright (c) 2010-2012 The CVC4 Project
#
# The purpose of this script is to create theory_traits.h from a template
# and a list of theory kinds.
@@ -14,7 +14,7 @@
# Output is to standard out.
#
-copyright=2010-2011
+copyright=2010-2012
cat <<EOF
/********************* */
@@ -55,6 +55,9 @@ theory_parametric="false"
rewriter_class=
rewriter_header=
+instantiator_class=void
+instantiator_header=
+
theory_id=
theory_class=
@@ -123,6 +126,7 @@ template<>
struct TheoryTraits<${theory_id}> {
typedef ${theory_class} theory_class;
typedef ${rewriter_class} rewriter_class;
+ typedef ${instantiator_class} instantiator_class;
static const bool isStableInfinite = ${theory_stable_infinite};
static const bool isFinite = ${theory_finite};
@@ -188,6 +192,18 @@ function typerule {
check_theory_seen
}
+function instantiator {
+ # instantiator class header
+ lineno=${BASH_LINENO[0]}
+ check_theory_seen
+
+ instantiator_class="$1"
+ instantiator_header="$2"
+
+ theory_includes="${theory_includes}#include \"$2\"
+"
+}
+
function properties {
# properties property*
lineno=${BASH_LINENO[0]}
diff --git a/src/theory/output_channel.h b/src/theory/output_channel.h
index 5c2cedf5b..b1a5fc60c 100644
--- a/src/theory/output_channel.h
+++ b/src/theory/output_channel.h
@@ -149,6 +149,64 @@ public:
}
/**
+ * If a decision is made on n, it must be in the phase specified.
+ * Note that this is enforced *globally*, i.e., it is completely
+ * context-INdependent. If you ever requirePhase() on a literal,
+ * it is phase-locked forever and ever. If it is to ever have the
+ * other phase as its assignment, it will be because it has been
+ * propagated that way (or it's a unit, at decision level 0).
+ *
+ * @param n - a theory atom with a SAT literal assigned; must have
+ * been pre-registered
+ * @param phase - the phase to decide on n
+ */
+ virtual void requirePhase(TNode n, bool phase)
+ throw(Interrupted, TypeCheckingExceptionPrivate, AssertionException) = 0;
+
+ /**
+ * Flips the most recent unflipped decision to the other phase and
+ * returns true. If all decisions have been flipped, the root
+ * decision is re-flipped and flipDecision() returns false. If no
+ * decisions (flipped nor unflipped) are on the decision stack, the
+ * state is not affected and flipDecision() returns false.
+ *
+ * For example, if l1, l2, and l3 are all decision literals, and
+ * have been decided in positive phase, a series of flipDecision()
+ * calls has the following effects:
+ *
+ * l1 l2 l3 <br/>
+ * l1 l2 ~l3 <br/>
+ * l1 ~l2 <br/>
+ * ~l1 <br/>
+ * l1 (and flipDecision() returns false)
+ *
+ * Naturally, flipDecision() might be interleaved with search. For example:
+ *
+ * l1 l2 l3 <br/>
+ * flipDecision() <br/>
+ * l1 l2 ~l3 <br/>
+ * flipDecision() <br/>
+ * l1 ~l2 <br/>
+ * SAT decides l3 <br/>
+ * l1 ~l2 l3 <br/>
+ * flipDecision() <br/>
+ * l1 ~l2 ~l3 <br/>
+ * flipDecision() <br/>
+ * ~l1 <br/>
+ * SAT decides l2 <br/>
+ * ~l1 l2 <br/>
+ * flipDecision() <br/>
+ * ~l1 ~l2 <br/>
+ * flipDecision() returns FALSE<br/>
+ * l1
+ *
+ * @return true if a decision was flipped; false if no decision
+ * could be flipped, or if the root decision was re-flipped
+ */
+ virtual bool flipDecision()
+ throw(Interrupted, TypeCheckingExceptionPrivate, AssertionException) = 0;
+
+ /**
* Notification from a theory that it realizes it is incomplete at
* this context level. If SAT is later determined by the
* TheoryEngine, it should actually return an UNKNOWN result.
diff --git a/src/theory/quantifiers/Makefile b/src/theory/quantifiers/Makefile
new file mode 100644
index 000000000..8ffdfb575
--- /dev/null
+++ b/src/theory/quantifiers/Makefile
@@ -0,0 +1,4 @@
+topdir = ../../..
+srcdir = src/theory/quantifiers
+
+include $(topdir)/Makefile.subdir
diff --git a/src/theory/quantifiers/Makefile.am b/src/theory/quantifiers/Makefile.am
new file mode 100644
index 000000000..de74e44f8
--- /dev/null
+++ b/src/theory/quantifiers/Makefile.am
@@ -0,0 +1,21 @@
+AM_CPPFLAGS = \
+ -D__BUILDING_CVC4LIB \
+ -I@srcdir@/../../include -I@srcdir@/../.. -I@builddir@/../..
+AM_CXXFLAGS = -Wall $(FLAG_VISIBILITY_HIDDEN)
+
+noinst_LTLIBRARIES = libquantifiers.la
+
+libquantifiers_la_SOURCES = \
+ theory_quantifiers_type_rules.h \
+ theory_quantifiers.h \
+ quantifiers_rewriter.h \
+ quantifiers_rewriter.cpp \
+ theory_quantifiers.cpp \
+ theory_quantifiers_instantiator.h \
+ theory_quantifiers_instantiator.cpp \
+ instantiation_engine.h \
+ instantiation_engine.cpp \
+ model_engine.h \
+ model_engine.cpp
+
+EXTRA_DIST = kinds \ No newline at end of file
diff --git a/src/theory/quantifiers/instantiation_engine.cpp b/src/theory/quantifiers/instantiation_engine.cpp
new file mode 100644
index 000000000..8478dff1e
--- /dev/null
+++ b/src/theory/quantifiers/instantiation_engine.cpp
@@ -0,0 +1,393 @@
+/********************* */
+/*! \file instantiation_engine.cpp
+ ** \verbatim
+ ** Original author: ajreynol
+ ** Major contributors: none
+ ** Minor contributors (to current version): none
+ ** This file is part of the CVC4 prototype.
+ ** Copyright (c) 2009, 2010, 2011 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
+ ** information.\endverbatim
+ **
+ ** \brief Implementation of instantiation engine class
+ **/
+
+#include "theory/quantifiers/instantiation_engine.h"
+
+#include "theory/theory_engine.h"
+#include "theory/uf/theory_uf_instantiator.h"
+
+using namespace std;
+using namespace CVC4;
+using namespace CVC4::kind;
+using namespace CVC4::context;
+using namespace CVC4::theory;
+using namespace CVC4::theory::quantifiers;
+
+//#define IE_PRINT_PROCESS_TIMES
+
+InstantiationEngine::InstantiationEngine( TheoryQuantifiers* th ) :
+d_th( th ){
+
+}
+
+QuantifiersEngine* InstantiationEngine::getQuantifiersEngine(){
+ return d_th->getQuantifiersEngine();
+}
+
+bool InstantiationEngine::hasAddedCbqiLemma( Node f ) {
+ return d_ce_lit.find( f ) != d_ce_lit.end();
+}
+
+void InstantiationEngine::addCbqiLemma( Node f ){
+ Assert( doCbqi( f ) && !hasAddedCbqiLemma( f ) );
+ //code for counterexample-based quantifier instantiation
+ Debug("cbqi") << "Do cbqi for " << f << std::endl;
+ //make the counterexample body
+ //Node ceBody = f[1].substitute( getQuantifiersEngine()->d_vars[f].begin(), getQuantifiersEngine()->d_vars[f].end(),
+ // getQuantifiersEngine()->d_inst_constants[f].begin(),
+ // getQuantifiersEngine()->d_inst_constants[f].end() );
+ //get the counterexample literal
+ Node ceBody = getQuantifiersEngine()->getCounterexampleBody( f );
+ Node ceLit = d_th->getValuation().ensureLiteral( ceBody.notNode() );
+ d_ce_lit[ f ] = ceLit;
+ getQuantifiersEngine()->setInstantiationConstantAttr( ceLit, f );
+ // set attributes, mark all literals in the body of n as dependent on cel
+ //registerLiterals( ceLit, f );
+ //require any decision on cel to be phase=true
+ d_th->getOutputChannel().requirePhase( ceLit, true );
+ Debug("cbqi-debug") << "Require phase " << ceLit << " = true." << std::endl;
+ //add counterexample lemma
+ NodeBuilder<> nb(kind::OR);
+ nb << f << ceLit;
+ Node lem = nb;
+ Debug("cbqi-debug") << "Counterexample lemma : " << lem << std::endl;
+ d_th->getOutputChannel().lemma( lem );
+}
+
+bool InstantiationEngine::doInstantiationRound( Theory::Effort effort ){
+ //if counterexample-based quantifier instantiation is active
+ if( Options::current()->cbqi ){
+ //check if any cbqi lemma has not been added yet
+ bool addedLemma = false;
+ for( int i=0; i<(int)getQuantifiersEngine()->getNumAssertedQuantifiers(); i++ ){
+ Node f = getQuantifiersEngine()->getAssertedQuantifier( i );
+ if( doCbqi( f ) && !hasAddedCbqiLemma( f ) ){
+ //add cbqi lemma
+ addCbqiLemma( f );
+ addedLemma = true;
+ }
+ }
+ if( addedLemma ){
+ return true;
+ }
+ }
+ //if not, proceed to instantiation round
+ Debug("inst-engine") << "IE: Instantiation Round." << std::endl;
+ Debug("inst-engine-ctrl") << "IE: Instantiation Round." << std::endl;
+ //reset instantiators
+ Debug("inst-engine-ctrl") << "Reset IE" << std::endl;
+ for( int i=0; i<theory::THEORY_LAST; i++ ){
+ if( getQuantifiersEngine()->getInstantiator( i ) ){
+ getQuantifiersEngine()->getInstantiator( i )->resetInstantiationRound( effort );
+ }
+ }
+ getQuantifiersEngine()->getTermDatabase()->reset( effort );
+ //iterate over an internal effort level e
+ int e = 0;
+ int eLimit = effort==Theory::EFFORT_LAST_CALL ? 10 : 2;
+ d_inst_round_status = InstStrategy::STATUS_UNFINISHED;
+ //while unfinished, try effort level=0,1,2....
+ while( d_inst_round_status==InstStrategy::STATUS_UNFINISHED && e<=eLimit ){
+ Debug("inst-engine") << "IE: Prepare instantiation (" << e << ")." << std::endl;
+ d_inst_round_status = InstStrategy::STATUS_SAT;
+ //instantiate each quantifier
+ for( int q=0; q<getQuantifiersEngine()->getNumAssertedQuantifiers(); q++ ){
+ Node f = getQuantifiersEngine()->getAssertedQuantifier( q );
+ Debug("inst-engine-debug") << "IE: Instantiate " << f << "..." << std::endl;
+ //if this quantifier is active
+ if( getQuantifiersEngine()->getActive( f ) ){
+ //int e_use = getQuantifiersEngine()->getRelevance( f )==-1 ? e - 1 : e;
+ int e_use = e;
+ if( e_use>=0 ){
+ //use each theory instantiator to instantiate f
+ for( int i=0; i<theory::THEORY_LAST; i++ ){
+ if( getQuantifiersEngine()->getInstantiator( i ) ){
+ Debug("inst-engine-debug") << "Do " << getQuantifiersEngine()->getInstantiator( i )->identify() << " " << e_use << std::endl;
+ int limitInst = 0;
+ int quantStatus = getQuantifiersEngine()->getInstantiator( i )->doInstantiation( f, effort, e_use, limitInst );
+ Debug("inst-engine-debug") << " -> status is " << quantStatus << std::endl;
+ InstStrategy::updateStatus( d_inst_round_status, quantStatus );
+ }
+ }
+ }
+ }
+ }
+ //do not consider another level if already added lemma at this level
+ if( getQuantifiersEngine()->hasAddedLemma() ){
+ d_inst_round_status = InstStrategy::STATUS_UNKNOWN;
+ }
+ e++;
+ }
+ Debug("inst-engine") << "All instantiators finished, # added lemmas = ";
+ Debug("inst-engine") << (int)getQuantifiersEngine()->d_lemmas_waiting.size() << std::endl;
+ //Notice() << "All instantiators finished, # added lemmas = " << (int)d_lemmas_waiting.size() << std::endl;
+ if( !getQuantifiersEngine()->hasAddedLemma() ){
+ Debug("inst-engine-stuck") << "No instantiations produced at this state: " << std::endl;
+ for( int i=0; i<theory::THEORY_LAST; i++ ){
+ if( getQuantifiersEngine()->getInstantiator( i ) ){
+ getQuantifiersEngine()->getInstantiator( i )->debugPrint("inst-engine-stuck");
+ Debug("inst-engine-stuck") << std::endl;
+ }
+ }
+ Debug("inst-engine-ctrl") << "---Fail." << std::endl;
+ return false;
+ }else{
+ Debug("inst-engine-ctrl") << "---Done. " << (int)getQuantifiersEngine()->d_lemmas_waiting.size() << std::endl;
+#ifdef IE_PRINT_PROCESS_TIMES
+ Notice() << "lemmas = " << (int)getQuantifiersEngine()->d_lemmas_waiting.size() << std::endl;
+#endif
+ //flush lemmas to output channel
+ getQuantifiersEngine()->flushLemmas( &d_th->getOutputChannel() );
+ return true;
+ }
+}
+
+int ierCounter = 0;
+
+void InstantiationEngine::check( Theory::Effort e ){
+ if( e==Theory::EFFORT_FULL ){
+ ierCounter++;
+ }
+ //determine if we should perform check, based on instWhenMode
+ bool performCheck = false;
+ if( Options::current()->instWhenMode==Options::INST_WHEN_FULL ){
+ performCheck = ( e >= Theory::EFFORT_FULL );
+ }else if( Options::current()->instWhenMode==Options::INST_WHEN_FULL_LAST_CALL ){
+ performCheck = ( ( e==Theory::EFFORT_FULL && ierCounter%2==0 ) || e==Theory::EFFORT_LAST_CALL );
+ }else if( Options::current()->instWhenMode==Options::INST_WHEN_LAST_CALL ){
+ performCheck = ( e >= Theory::EFFORT_LAST_CALL );
+ }else{
+ performCheck = true;
+ }
+ if( performCheck ){
+ Debug("inst-engine") << "IE: Check " << e << " " << ierCounter << std::endl;
+#ifdef IE_PRINT_PROCESS_TIMES
+ double clSet = double(clock())/double(CLOCKS_PER_SEC);
+ Notice() << "Run instantiation round " << e << " " << ierCounter << std::endl;
+#endif
+ bool quantActive = false;
+ //for each quantifier currently asserted,
+ // such that the counterexample literal is not in positive in d_counterexample_asserts
+ // for( BoolMap::iterator i = d_forall_asserts.begin(); i != d_forall_asserts.end(); i++ ) {
+ // if( (*i).second ) {
+ for( int i=0; i<(int)getQuantifiersEngine()->getNumAssertedQuantifiers(); i++ ){
+ Node n = getQuantifiersEngine()->getAssertedQuantifier( i );
+ if( Options::current()->cbqi && hasAddedCbqiLemma( n ) ){
+ Node cel = d_ce_lit[ n ];
+ bool active, value;
+ bool ceValue = false;
+ if( d_th->getValuation().hasSatValue( cel, value ) ){
+ active = value;
+ ceValue = true;
+ }else{
+ active = true;
+ }
+ getQuantifiersEngine()->setActive( n, active );
+ if( active ){
+ Debug("quantifiers") << " Active : " << n;
+ quantActive = true;
+ }else{
+ Debug("quantifiers") << " NOT active : " << n;
+ if( d_th->getValuation().isDecision( cel ) ){
+ Debug("quant-req-phase") << "Bad decision : " << cel << std::endl;
+ }
+ //note that the counterexample literal must not be a decision
+ Assert( !d_th->getValuation().isDecision( cel ) );
+ }
+ if( d_th->getValuation().hasSatValue( n, value ) ){
+ Debug("quantifiers") << ", value = " << value;
+ }
+ if( ceValue ){
+ Debug("quantifiers") << ", ce is asserted";
+ }
+ Debug("quantifiers") << std::endl;
+ }else{
+ getQuantifiersEngine()->setActive( n, true );
+ quantActive = true;
+ Debug("quantifiers") << " Active : " << n << ", no ce assigned." << std::endl;
+ }
+ Debug("quantifiers-relevance") << "Quantifier : " << n << std::endl;
+ Debug("quantifiers-relevance") << " Relevance : " << getQuantifiersEngine()->getRelevance( n ) << std::endl;
+ Debug("quantifiers") << " Relevance : " << getQuantifiersEngine()->getRelevance( n ) << std::endl;
+ }
+ //}
+ if( quantActive ){
+ bool addedLemmas = doInstantiationRound( e );
+ //Debug("quantifiers-dec") << "Do instantiation, level = " << d_th->getValuation().getDecisionLevel() << std::endl;
+ //for( int i=1; i<=(int)d_valuation.getDecisionLevel(); i++ ){
+ // Debug("quantifiers-dec") << " " << d_valuation.getDecision( i ) << std::endl;
+ //}
+ if( e==Theory::EFFORT_LAST_CALL ){
+ if( !addedLemmas ){
+ if( d_inst_round_status==InstStrategy::STATUS_SAT ){
+ Debug("inst-engine") << "No instantiation given, returning SAT..." << std::endl;
+ debugSat( SAT_INST_STRATEGY );
+ }else{
+ Debug("inst-engine") << "No instantiation given, returning unknown..." << std::endl;
+ d_th->getOutputChannel().setIncomplete();
+ }
+ }
+ }
+ }else{
+ if( e==Theory::EFFORT_LAST_CALL ){
+ if( Options::current()->cbqi ){
+ debugSat( SAT_CBQI );
+ }
+ }
+ }
+#ifdef IE_PRINT_PROCESS_TIMES
+ double clSet2 = double(clock())/double(CLOCKS_PER_SEC);
+ Notice() << "Done Run instantiation round " << (clSet2-clSet) << std::endl;
+#endif
+ }
+}
+
+void InstantiationEngine::registerQuantifier( Node f ){
+ //Notice() << "do cbqi " << f << " ? " << std::endl;
+ Node ceBody = getQuantifiersEngine()->getCounterexampleBody( f );
+ if( !doCbqi( f ) ){
+ getQuantifiersEngine()->addTermToDatabase( ceBody, true );
+ //need to tell which instantiators will be responsible
+ //by default, just chose the UF instantiator
+ getQuantifiersEngine()->getInstantiator( theory::THEORY_UF )->setHasConstraintsFrom( f );
+ }
+
+ //take into account user patterns
+ if( f.getNumChildren()==3 ){
+ Node subsPat = getQuantifiersEngine()->getSubstitutedNode( f[2], f );
+ //add patterns
+ for( int i=0; i<(int)subsPat.getNumChildren(); i++ ){
+ //Notice() << "Add pattern " << subsPat[i] << " for " << f << std::endl;
+ ((uf::InstantiatorTheoryUf*)getQuantifiersEngine()->getInstantiator( theory::THEORY_UF ))->addUserPattern( f, subsPat[i] );
+ }
+ }
+}
+
+void InstantiationEngine::assertNode( Node f ){
+ ////if we are doing cbqi and have not added the lemma yet, do so
+ //if( doCbqi( f ) && !hasAddedCbqiLemma( f ) ){
+ // addCbqiLemma( f );
+ //}
+}
+
+bool InstantiationEngine::hasApplyUf( Node f ){
+ if( f.getKind()==APPLY_UF ){
+ return true;
+ }else{
+ for( int i=0; i<(int)f.getNumChildren(); i++ ){
+ if( hasApplyUf( f[i] ) ){
+ return true;
+ }
+ }
+ return false;
+ }
+}
+bool InstantiationEngine::hasNonArithmeticVariable( Node f ){
+ for( int i=0; i<(int)f[0].getNumChildren(); i++ ){
+ TypeNode tn = f[0][i].getType();
+ if( !tn.isInteger() && !tn.isReal() ){
+ return true;
+ }
+ }
+ return false;
+}
+
+bool InstantiationEngine::doCbqi( Node f ){
+ if( Options::current()->cbqiSetByUser ){
+ return Options::current()->cbqi;
+ }else if( Options::current()->cbqi ){
+ //if quantifier has a non-arithmetic variable, then do not use cbqi
+ //if quantifier has an APPLY_UF term, then do not use cbqi
+ return !hasNonArithmeticVariable( f ) && !hasApplyUf( f[1] );
+ }else{
+ return false;
+ }
+}
+
+
+
+
+
+
+
+
+
+
+
+
+
+//void InstantiationEngine::registerLiterals( Node n, Node f ){
+// if( n.getAttribute(InstConstantAttribute())==f ){
+// for( int i=0; i<(int)n.getNumChildren(); i++ ){
+// registerLiterals( n[i], f );
+// }
+// if( !d_ce_lit[ f ].isNull() ){
+// if( getQuantifiersEngine()->d_te->getPropEngine()->isSatLiteral( n ) && n.getKind()!=NOT ){
+// if( n!=d_ce_lit[ f ] && n.notNode()!=d_ce_lit[ f ] ){
+// Debug("quant-dep-dec") << "Make " << n << " dependent on ";
+// Debug("quant-dep-dec") << d_ce_lit[ f ] << std::endl;
+// d_th->getOutputChannel().dependentDecision( d_ce_lit[ f ], n );
+// }
+// }
+// }
+// }
+//}
+
+void InstantiationEngine::debugSat( int reason ){
+ if( reason==SAT_CBQI ){
+ //Debug("quantifiers-sat") << "Decisions:" << std::endl;
+ //for( int i=1; i<=(int)d_th->getValuation().getDecisionLevel(); i++ ){
+ // Debug("quantifiers-sat") << " " << i << ": " << d_th->getValuation().getDecision( i ) << std::endl;
+ //}
+ //for( BoolMap::iterator i = d_forall_asserts.begin(); i != d_forall_asserts.end(); i++ ) {
+ // if( (*i).second ) {
+ for( int i=0; i<(int)getQuantifiersEngine()->getNumAssertedQuantifiers(); i++ ){
+ Node f = getQuantifiersEngine()->getAssertedQuantifier( i );
+ Node cel = d_ce_lit[ f ];
+ Assert( !cel.isNull() );
+ bool value;
+ if( d_th->getValuation().hasSatValue( cel, value ) ){
+ if( !value ){
+ AlwaysAssert(! d_th->getValuation().isDecision( cel ),
+ "bad decision on counterexample literal");
+ }
+ }
+ }
+ //}
+ Debug("quantifiers-sat") << "return SAT: Cbqi, no quantifier is active. " << std::endl;
+ //static bool setTrust = false;
+ //if( !setTrust ){
+ // setTrust = true;
+ // Notice() << "trust-";
+ //}
+ }else if( reason==SAT_INST_STRATEGY ){
+ Debug("quantifiers-sat") << "return SAT: No strategy chose to add an instantiation." << std::endl;
+ //Notice() << "sat ";
+ //Unimplemented();
+ }
+}
+
+void InstantiationEngine::propagate( Theory::Effort level ){
+ //propagate as decision all counterexample literals that are not asserted
+ for( std::map< Node, Node >::iterator it = d_ce_lit.begin(); it != d_ce_lit.end(); ++it ){
+ bool value;
+ if( !d_th->getValuation().hasSatValue( it->second, value ) ){
+ //if not already set, propagate as decision
+ d_th->getOutputChannel().propagateAsDecision( it->second );
+ Debug("cbqi-prop-as-dec") << "CBQI: propagate as decision " << it->second << std::endl;
+ }
+ }
+}
diff --git a/src/theory/quantifiers/instantiation_engine.h b/src/theory/quantifiers/instantiation_engine.h
new file mode 100644
index 000000000..c6aaed18a
--- /dev/null
+++ b/src/theory/quantifiers/instantiation_engine.h
@@ -0,0 +1,79 @@
+/********************* */
+/*! \file instantiation_engine.h
+ ** \verbatim
+ ** Original author: ajreynol
+ ** Major contributors: none
+ ** Minor contributors (to current version): none
+ ** This file is part of the CVC4 prototype.
+ ** Copyright (c) 2009, 2010, 2011 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
+ ** information.\endverbatim
+ **
+ ** \brief Instantiation Engine classes
+ **/
+
+#include "cvc4_private.h"
+
+#ifndef __CVC4__INSTANTIATION_ENGINE_H
+#define __CVC4__INSTANTIATION_ENGINE_H
+
+#include "theory/quantifiers_engine.h"
+#include "theory/quantifiers/theory_quantifiers.h"
+
+namespace CVC4 {
+namespace theory {
+namespace quantifiers {
+
+class InstantiationEngine : public QuantifiersModule
+{
+private:
+ TheoryQuantifiers* d_th;
+ QuantifiersEngine* getQuantifiersEngine();
+private:
+ typedef context::CDHashMap< Node, bool, NodeHashFunction > BoolMap;
+ /** status of instantiation round (one of InstStrategy::STATUS_*) */
+ int d_inst_round_status;
+ /** map from universal quantifiers to their counterexample literals */
+ std::map< Node, Node > d_ce_lit;
+private:
+ bool hasAddedCbqiLemma( Node f );
+ void addCbqiLemma( Node f );
+private:
+ /** helper functions */
+ bool hasNonArithmeticVariable( Node f );
+ bool hasApplyUf( Node f );
+ /** whether to do CBQI for quantifier f */
+ bool doCbqi( Node f );
+private:
+ /** do instantiation round */
+ bool doInstantiationRound( Theory::Effort effort );
+ /** register literals of n, f is the quantifier it belongs to */
+ //void registerLiterals( Node n, Node f );
+private:
+ enum{
+ SAT_CBQI,
+ SAT_INST_STRATEGY,
+ };
+ /** debug sat */
+ void debugSat( int reason );
+public:
+ InstantiationEngine( TheoryQuantifiers* th );
+ ~InstantiationEngine(){}
+
+ void check( Theory::Effort e );
+ void registerQuantifier( Node f );
+ void assertNode( Node f );
+ Node explain(TNode n){ return Node::null(); }
+ void propagate( Theory::Effort level );
+public:
+ /** get the corresponding counterexample literal for quantified formula node n */
+ Node getCounterexampleLiteralFor( Node f ) { return d_ce_lit.find( f )==d_ce_lit.end() ? Node::null() : d_ce_lit[ f ]; }
+};
+
+}
+}
+}
+
+#endif
diff --git a/src/theory/quantifiers/kinds b/src/theory/quantifiers/kinds
new file mode 100644
index 000000000..106d95cef
--- /dev/null
+++ b/src/theory/quantifiers/kinds
@@ -0,0 +1,48 @@
+# kinds -*- sh -*-
+#
+# For documentation on this file format, please refer to
+# src/theory/builtin/kinds.
+#
+
+theory THEORY_QUANTIFIERS ::CVC4::theory::quantifiers::TheoryQuantifiers "theory/quantifiers/theory_quantifiers.h"
+typechecker "theory/quantifiers/theory_quantifiers_type_rules.h"
+instantiator ::CVC4::theory::quantifiers::InstantiatorTheoryQuantifiers "theory/quantifiers/theory_quantifiers_instantiator.h"
+
+properties check propagate presolve
+
+rewriter ::CVC4::theory::quantifiers::QuantifiersRewriter "theory/quantifiers/quantifiers_rewriter.h"
+
+operator FORALL 2:3 "universally quantified formula"
+
+operator EXISTS 2:3 "existentially quantified formula"
+
+variable INST_CONSTANT "instantiation constant"
+
+sort BOUND_VAR_LIST_TYPE \
+ Cardinality::INTEGERS \
+ not-well-founded \
+ "Bound Var type"
+
+operator BOUND_VAR_LIST 1: "bound variables"
+
+sort INST_PATTERN_TYPE \
+ Cardinality::INTEGERS \
+ not-well-founded \
+ "Instantiation pattern type"
+
+operator INST_PATTERN 1: "instantiation pattern"
+
+sort INST_PATTERN_LIST_TYPE \
+ Cardinality::INTEGERS \
+ not-well-founded \
+ "Instantiation pattern list type"
+
+operator INST_PATTERN_LIST 1: "instantiation pattern list"
+
+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_PATTERN_LIST ::CVC4::theory::quantifiers::QuantifierInstPatternListTypeRule
+
+endtheory
diff --git a/src/theory/quantifiers/model_engine.cpp b/src/theory/quantifiers/model_engine.cpp
new file mode 100644
index 000000000..a72b103d1
--- /dev/null
+++ b/src/theory/quantifiers/model_engine.cpp
@@ -0,0 +1,1401 @@
+/********************* */
+/*! \file model_engine.cpp
+ ** \verbatim
+ ** Original author: ajreynol
+ ** Major contributors: none
+ ** Minor contributors (to current version): none
+ ** This file is part of the CVC4 prototype.
+ ** Copyright (c) 2009, 2010, 2011 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
+ ** information.\endverbatim
+ **
+ ** \brief Implementation of model engine class
+ **/
+
+#include "theory/quantifiers/model_engine.h"
+#include "theory/theory_engine.h"
+#include "theory/uf/equality_engine.h"
+#include "theory/uf/theory_uf.h"
+#include "theory/uf/theory_uf_strong_solver.h"
+#include "theory/uf/theory_uf_instantiator.h"
+
+//#define ME_PRINT_PROCESS_TIMES
+
+//#define DISABLE_EVAL_SKIP_MULTIPLE
+#define RECONSIDER_FUNC_DEFAULT_VALUE
+#define RECONSIDER_FUNC_CONSTANT
+#define USE_INDEX_ORDERING
+//#define ONE_INST_PER_QUANT_PER_ROUND
+
+using namespace std;
+using namespace CVC4;
+using namespace CVC4::kind;
+using namespace CVC4::context;
+using namespace CVC4::theory;
+using namespace CVC4::theory::quantifiers;
+
+void printRepresentative( const char* c, QuantifiersEngine* qe, Node r ){
+ if( r.getType()==NodeManager::currentNM()->booleanType() ){
+ if( qe->getEqualityQuery()->areEqual( r, NodeManager::currentNM()->mkConst( true ) ) ){
+ Debug( c ) << "true";
+ }else{
+ Debug( c ) << "false";
+ }
+ }else{
+ Debug( c ) << qe->getEqualityQuery()->getRepresentative( r );
+ }
+}
+
+RepAlphabet::RepAlphabet( RepAlphabet& ra, QuantifiersEngine* qe ){
+ //translate to current representatives
+ for( std::map< TypeNode, std::vector< Node > >::iterator it = ra.d_type_reps.begin(); it != ra.d_type_reps.end(); ++it ){
+ std::vector< Node > reps;
+ for( int i=0; i<(int)it->second.size(); i++ ){
+ //reps.push_back( ie->getEqualityQuery()->getRepresentative( it->second[i] ) );
+ reps.push_back( it->second[i] );
+ }
+ set( it->first, reps );
+ }
+}
+
+void RepAlphabet::set( TypeNode t, std::vector< Node >& reps ){
+ d_type_reps[t].insert( d_type_reps[t].begin(), reps.begin(), reps.end() );
+ for( int i=0; i<(int)reps.size(); i++ ){
+ d_tmap[ reps[i] ] = i;
+ }
+}
+
+void RepAlphabet::debugPrint( const char* c, QuantifiersEngine* qe ){
+ for( std::map< TypeNode, std::vector< Node > >::iterator it = d_type_reps.begin(); it != d_type_reps.end(); ++it ){
+ Debug( c ) << it->first << " : " << std::endl;
+ for( int i=0; i<(int)it->second.size(); i++ ){
+ Debug( c ) << " " << i << ": " << it->second[i] << std::endl;
+ Debug( c ) << " eq_class( " << it->second[i] << " ) : ";
+ ((uf::InstantiatorTheoryUf*)qe->getInstantiator( THEORY_UF ))->outputEqClass( c, it->second[i] );
+ Debug( c ) << std::endl;
+ }
+ }
+}
+
+RepAlphabetIterator::RepAlphabetIterator( QuantifiersEngine* qe, Node f, ModelEngine* model ){
+ for( size_t i=0; i<f[0].getNumChildren(); i++ ){
+ d_index_order.push_back( i );
+ }
+ initialize( qe, f, model );
+}
+
+RepAlphabetIterator::RepAlphabetIterator( QuantifiersEngine* qe, Node f, ModelEngine* model, std::vector< int >& indexOrder ){
+ d_index_order.insert( d_index_order.begin(), indexOrder.begin(), indexOrder.end() );
+ initialize( qe, f, model );
+}
+
+void RepAlphabetIterator::initialize( QuantifiersEngine* qe, Node f, ModelEngine* model ){
+ d_f = f;
+ d_model = model;
+ //store instantiation constants
+ for( size_t i=0; i<f[0].getNumChildren(); i++ ){
+ d_ic.push_back( qe->getInstantiationConstant( d_f, i ) );
+ d_index.push_back( 0 );
+ }
+ //make the d_var_order mapping
+ for( size_t i=0; i<d_index_order.size(); i++ ){
+ d_var_order[d_index_order[i]] = i;
+ }
+ //for testing
+ d_inst_tried = 0;
+ d_inst_tests = 0;
+}
+
+void RepAlphabetIterator::increment2( QuantifiersEngine* qe, int counter ){
+ Assert( !isFinished() );
+ //increment d_index
+ while( counter>=0 && d_index[counter]==(int)(d_model->getReps()->d_type_reps[d_f[0][d_index_order[counter]].getType()].size()-1) ){
+ counter--;
+ }
+ if( counter==-1 ){
+ d_index.clear();
+ }else{
+ for( int i=(int)d_index.size()-1; i>counter; i-- ){
+ d_index[i] = 0;
+ d_model->clearEvalFailed( i );
+ }
+ d_index[counter]++;
+ d_model->clearEvalFailed( counter );
+ }
+}
+
+void RepAlphabetIterator::increment( QuantifiersEngine* qe ){
+ if( !isFinished() ){
+ increment2( qe, (int)d_index.size()-1 );
+ }
+}
+
+bool RepAlphabetIterator::isFinished(){
+ return d_index.empty();
+}
+
+void RepAlphabetIterator::getMatch( QuantifiersEngine* ie, InstMatch& m ){
+ for( int i=0; i<(int)d_index.size(); i++ ){
+ m.d_map[ ie->getInstantiationConstant( d_f, i ) ] = getTerm( i );
+ }
+}
+
+Node RepAlphabetIterator::getTerm( int i ){
+ TypeNode tn = d_f[0][d_index_order[i]].getType();
+ Assert( d_model->getReps()->d_type_reps.find( tn )!=d_model->getReps()->d_type_reps.end() );
+ return d_model->getReps()->d_type_reps[tn][d_index[d_index_order[i]]];
+}
+
+void RepAlphabetIterator::calculateTerms( QuantifiersEngine* qe ){
+ d_terms.clear();
+ for( int i=0; i<qe->getNumInstantiationConstants( d_f ); i++ ){
+ d_terms.push_back( getTerm( i ) );
+ }
+}
+
+void RepAlphabetIterator::debugPrint( const char* c ){
+ for( int i=0; i<(int)d_index.size(); i++ ){
+ Debug( c ) << i << ": " << d_index[i] << ", (" << getTerm( i ) << " / " << d_ic[ i ] << std::endl;
+ }
+}
+
+void RepAlphabetIterator::debugPrintSmall( const char* c ){
+ Debug( c ) << "RI: ";
+ for( int i=0; i<(int)d_index.size(); i++ ){
+ Debug( c ) << d_index[i] << ": " << getTerm( i ) << " ";
+ }
+ Debug( c ) << std::endl;
+}
+
+//set value function
+void UfModelTree::setValue( QuantifiersEngine* qe, Node n, Node v, std::vector< int >& indexOrder, bool ground, int argIndex ){
+ if( d_data.empty() ){
+ d_value = v;
+ }else if( !d_value.isNull() && d_value!=v ){
+ d_value = Node::null();
+ }
+ if( argIndex<(int)n.getNumChildren() ){
+ //take r = null when argument is the model basis
+ Node r;
+ if( ground || !n[ indexOrder[argIndex] ].getAttribute(ModelBasisAttribute()) ){
+ r = qe->getEqualityQuery()->getRepresentative( n[ indexOrder[argIndex] ] );
+ }
+ d_data[ r ].setValue( qe, n, v, indexOrder, ground, argIndex+1 );
+ }
+}
+
+//get value function
+Node UfModelTree::getValue( QuantifiersEngine* qe, Node n, std::vector< int >& indexOrder, int& depIndex, int argIndex ){
+ if( !d_value.isNull() && isTotal( n.getOperator(), argIndex ) ){
+ //Notice() << "Constant, return " << d_value << ", depIndex = " << argIndex << std::endl;
+ depIndex = argIndex;
+ return d_value;
+ }else{
+ Node val;
+ int childDepIndex[2] = { argIndex, argIndex };
+ for( int i=0; i<2; i++ ){
+ //first check the argument, then check default
+ Node r;
+ if( i==0 ){
+ r = qe->getEqualityQuery()->getRepresentative( n[ indexOrder[argIndex] ] );
+ }
+ std::map< Node, UfModelTree >::iterator it = d_data.find( r );
+ if( it!=d_data.end() ){
+ val = it->second.getValue( qe, n, indexOrder, childDepIndex[i], argIndex+1 );
+ if( !val.isNull() ){
+ break;
+ }
+ }else{
+ //argument is not a defined argument: thus, it depends on this argument
+ childDepIndex[i] = argIndex+1;
+ }
+ }
+ //update depIndex
+ depIndex = childDepIndex[0]>childDepIndex[1] ? childDepIndex[0] : childDepIndex[1];
+ //Notice() << "Return " << val << ", depIndex = " << depIndex;
+ //Notice() << " ( " << childDepIndex[0] << ", " << childDepIndex[1] << " )" << std::endl;
+ return val;
+ }
+}
+
+//simplify function
+void UfModelTree::simplify( Node op, Node defaultVal, int argIndex ){
+ if( argIndex<(int)op.getType().getNumChildren()-1 ){
+ std::vector< Node > eraseData;
+ //first process the default argument
+ Node r;
+ std::map< Node, UfModelTree >::iterator it = d_data.find( r );
+ if( it!=d_data.end() ){
+ if( !defaultVal.isNull() && it->second.d_value==defaultVal ){
+ eraseData.push_back( r );
+ }else{
+ it->second.simplify( op, defaultVal, argIndex+1 );
+ if( !it->second.d_value.isNull() && it->second.isTotal( op, argIndex+1 ) ){
+ defaultVal = it->second.d_value;
+ }else{
+ defaultVal = Node::null();
+ }
+ }
+ }
+ //now see if any children can be removed, and simplify the ones that cannot
+ for( std::map< Node, UfModelTree >::iterator it = d_data.begin(); it != d_data.end(); ++it ){
+ if( !it->first.isNull() ){
+ if( !defaultVal.isNull() && it->second.d_value==defaultVal ){
+ eraseData.push_back( it->first );
+ }else{
+ it->second.simplify( op, defaultVal, argIndex+1 );
+ }
+ }
+ }
+ for( int i=0; i<(int)eraseData.size(); i++ ){
+ d_data.erase( eraseData[i] );
+ }
+ }
+}
+
+//is total function
+bool UfModelTree::isTotal( Node op, int argIndex ){
+ if( argIndex==(int)(op.getType().getNumChildren()-1) ){
+ return !d_value.isNull();
+ }else{
+ Node r;
+ std::map< Node, UfModelTree >::iterator it = d_data.find( r );
+ if( it!=d_data.end() ){
+ return it->second.isTotal( op, argIndex+1 );
+ }else{
+ return false;
+ }
+ }
+}
+
+Node UfModelTree::getConstantValue( QuantifiersEngine* qe, Node n, std::vector< int >& indexOrder, int argIndex ){
+ return d_value;
+}
+
+void indent( const char* c, int ind ){
+ for( int i=0; i<ind; i++ ){
+ Debug( c ) << " ";
+ }
+}
+
+void UfModelTree::debugPrint( const char* c, QuantifiersEngine* qe, std::vector< int >& indexOrder, int ind, int arg ){
+ if( !d_data.empty() ){
+ for( std::map< Node, UfModelTree >::iterator it = d_data.begin(); it != d_data.end(); ++it ){
+ if( !it->first.isNull() ){
+ indent( c, ind );
+ Debug( c ) << "if x_" << indexOrder[arg] << " == " << it->first << std::endl;
+ it->second.debugPrint( c, qe, indexOrder, ind+2, arg+1 );
+ }
+ }
+ if( d_data.find( Node::null() )!=d_data.end() ){
+ d_data[ Node::null() ].debugPrint( c, qe, indexOrder, ind, arg+1 );
+ }
+ }else{
+ indent( c, ind );
+ Debug( c ) << "return ";
+ printRepresentative( c, qe, d_value );
+ //Debug( c ) << " { ";
+ //for( int i=0; i<(int)d_explicit.size(); i++ ){
+ // Debug( c ) << d_explicit[i] << " ";
+ //}
+ //Debug( c ) << "}";
+ Debug( c ) << std::endl;
+ }
+}
+
+UfModel::UfModel( Node op, ModelEngine* me ) : d_op( op ), d_me( me ),
+ d_model_constructed( false ), d_reconsider_model( false ){
+
+ d_tree = UfModelTreeOrdered( op ); TypeNode tn = d_op.getType(); tn = tn[(int)tn.getNumChildren()-1]; Assert( tn==NodeManager::currentNM()->booleanType() || uf::StrongSolverTheoryUf::isRelevantType( tn ) ); //look at ground assertions
+ for( int i=0; i<(int)d_me->getQuantifiersEngine()->getTermDatabase()->d_op_map[ d_op ].size(); i++ ){
+ Node n = d_me->getQuantifiersEngine()->getTermDatabase()->d_op_map[ d_op ][i];
+ bool add = true;
+ if( n.getAttribute(NoMatchAttribute()) ){
+ add = false;
+ //determine if it has model basis attribute
+ for( int j=0; j<(int)n.getNumChildren(); j++ ){
+ if( n[j].getAttribute(ModelBasisAttribute()) ){
+ add = true;
+ break;
+ }
+ }
+ }
+ if( add ){
+ d_ground_asserts.push_back( n );
+ Node r = d_me->getQuantifiersEngine()->getEqualityQuery()->getRepresentative( n );
+ d_ground_asserts_reps.push_back( r );
+ }
+ }
+ //determine if it is constant
+ if( !d_ground_asserts.empty() ){
+ bool isConstant = true;
+ for( int i=1; i<(int)d_ground_asserts.size(); i++ ){
+ if( d_ground_asserts_reps[0]!=d_ground_asserts_reps[i] ){
+ isConstant = false;
+ break;
+ }
+ }
+ if( isConstant ){
+ //set constant value
+ Node t = d_me->getModelBasisApplyUfTerm( d_op );
+ Node r = d_ground_asserts_reps[0];
+ setValue( t, r, false );
+ setModel();
+ d_reconsider_model = true;
+ Debug("fmf-model-cons") << "Function " << d_op << " is the constant function ";
+ printRepresentative( "fmf-model-cons", d_me->getQuantifiersEngine(), r );
+ Debug("fmf-model-cons") << std::endl;
+ }
+ }
+}
+
+void UfModel::setValue( Node n, Node v, bool ground ){
+ d_set_values[ ground ? 1 : 0 ][n] = v;
+}
+
+void UfModel::setModel(){
+ makeModel( d_me->getQuantifiersEngine(), d_tree );
+ d_model_constructed = true;
+}
+
+void UfModel::clearModel(){
+ for( int k=0; k<2; k++ ){
+ d_set_values[k].clear();
+ }
+ d_tree.clear();
+ d_model_constructed = false;
+}
+
+Node UfModel::getConstantValue( QuantifiersEngine* qe, Node n ){
+ if( d_model_constructed ){
+ return d_tree.getConstantValue( qe, n );
+ }else{
+ return Node::null();
+ }
+}
+
+bool UfModel::isConstant(){
+ Node gn = d_me->getModelBasisApplyUfTerm( d_op );
+ Node n = getConstantValue( d_me->getQuantifiersEngine(), gn );
+ return !n.isNull();
+}
+
+void UfModel::buildModel(){
+#ifdef RECONSIDER_FUNC_CONSTANT
+ if( d_model_constructed ){
+ if( d_reconsider_model ){
+ //if we are allowed to reconsider default value, then see if the default value can be improved
+ Node t = d_me->getModelBasisApplyUfTerm( d_op );
+ Node v = d_set_values[0][t];
+ if( d_value_pro_con[1][v].size()>d_value_pro_con[0][v].size() ){
+ Debug("fmf-model-cons-debug") << "Consider changing the default value for " << d_op << std::endl;
+ clearModel();
+ }
+ }
+ }
+#endif
+ //now, construct models for each uninterpretted function/predicate
+ if( !d_model_constructed ){
+ Debug("fmf-model-cons") << "Construct model for " << d_op << "..." << std::endl;
+ //now, set the values in the model
+ for( int i=0; i<(int)d_ground_asserts.size(); i++ ){
+ Node n = d_ground_asserts[i];
+ Node v = d_ground_asserts_reps[i];
+ //if this assertion did not help the model, just consider it ground
+ //set n = v in the model tree
+ Debug("fmf-model-cons") << " Set " << n << " = ";
+ printRepresentative( "fmf-model-cons", d_me->getQuantifiersEngine(), v );
+ Debug("fmf-model-cons") << std::endl;
+ //set it as ground value
+ setValue( n, v );
+ }
+ //set the default value
+ //chose defaultVal based on heuristic (the best proportion of "pro" responses)
+ Node defaultVal;
+ double maxScore = -1;
+ for( int i=0; i<(int)d_values.size(); i++ ){
+ Node v = d_values[i];
+ double score = ( 1.0 + (double)d_value_pro_con[0][v].size() )/( 1.0 + (double)d_value_pro_con[1][v].size() );
+ Debug("fmf-model-cons") << " - score( ";
+ printRepresentative( "fmf-model-cons", d_me->getQuantifiersEngine(), v );
+ Debug("fmf-model-cons") << " ) = " << score << std::endl;
+ if( score>maxScore ){
+ defaultVal = v;
+ maxScore = score;
+ }
+ }
+#ifdef RECONSIDER_FUNC_DEFAULT_VALUE
+ if( maxScore<1.0 ){
+ //consider finding another value, if possible
+ Debug("fmf-model-cons-debug") << "Poor choice for default value, score = " << maxScore << std::endl;
+ TypeNode tn = d_op.getType();
+ Node newDefaultVal = d_me->getArbitraryElement( tn[(int)tn.getNumChildren()-1], d_values );
+ if( !newDefaultVal.isNull() ){
+ defaultVal = newDefaultVal;
+ Debug("fmf-model-cons-debug") << "-> Change default value to ";
+ printRepresentative( "fmf-model-cons-debug", d_me->getQuantifiersEngine(), defaultVal );
+ Debug("fmf-model-cons-debug") << std::endl;
+ }else{
+ Debug("fmf-model-cons-debug") << "-> Could not find arbitrary element of type " << tn[(int)tn.getNumChildren()-1] << std::endl;
+ Debug("fmf-model-cons-debug") << " Excluding: ";
+ for( int i=0; i<(int)d_values.size(); i++ ){
+ Debug("fmf-model-cons-debug") << d_values[i] << " ";
+ }
+ Debug("fmf-model-cons-debug") << std::endl;
+ }
+ }
+#endif
+ Assert( !defaultVal.isNull() );
+ //get the default term (this term must be defined non-ground in model)
+ Node defaultTerm = d_me->getModelBasisApplyUfTerm( d_op );
+ Debug("fmf-model-cons") << " Choose ";
+ printRepresentative("fmf-model-cons", d_me->getQuantifiersEngine(), defaultVal );
+ Debug("fmf-model-cons") << " as default value (" << defaultTerm << ")" << std::endl;
+ Debug("fmf-model-cons") << " # quantifiers pro = " << d_value_pro_con[0][defaultVal].size() << std::endl;
+ Debug("fmf-model-cons") << " # quantifiers con = " << d_value_pro_con[1][defaultVal].size() << std::endl;
+ setValue( defaultTerm, defaultVal, false );
+ Debug("fmf-model-cons") << " Making model...";
+ setModel();
+ Debug("fmf-model-cons") << " Finished constructing model for " << d_op << "." << std::endl;
+ }
+}
+
+void UfModel::setValuePreference( Node f, Node n, bool isPro ){
+ Node v = d_me->getQuantifiersEngine()->getEqualityQuery()->getRepresentative( n );
+ //Notice() << "Set value preference " << n << " = " << v << " " << isPro << std::endl;
+ if( std::find( d_values.begin(), d_values.end(), v )==d_values.end() ){
+ d_values.push_back( v );
+ }
+ int index = isPro ? 0 : 1;
+ if( std::find( d_value_pro_con[index][v].begin(), d_value_pro_con[index][v].end(), f )==d_value_pro_con[index][v].end() ){
+ d_value_pro_con[index][v].push_back( f );
+ }
+}
+
+void UfModel::makeModel( QuantifiersEngine* qe, UfModelTreeOrdered& tree ){
+ for( int k=0; k<2; k++ ){
+ for( std::map< Node, Node >::iterator it = d_set_values[k].begin(); it != d_set_values[k].end(); ++it ){
+ tree.setValue( qe, it->first, it->second, k==1 );
+ }
+ }
+ tree.simplify();
+}
+
+void UfModel::debugPrint( const char* c ){
+ //Debug( c ) << "Function " << d_op << std::endl;
+ //Debug( c ) << " Type: " << d_op.getType() << std::endl;
+ //Debug( c ) << " Ground asserts:" << std::endl;
+ //for( int i=0; i<(int)d_ground_asserts.size(); i++ ){
+ // Debug( c ) << " " << d_ground_asserts[i] << " = ";
+ // printRepresentative( c, d_me->getQuantifiersEngine(), d_ground_asserts[i] );
+ // Debug( c ) << std::endl;
+ //}
+ //Debug( c ) << " Model:" << std::endl;
+
+ TypeNode t = d_op.getType();
+ Debug( c ) << d_op << "( ";
+ for( int i=0; i<(int)(t.getNumChildren()-1); i++ ){
+ Debug( c ) << "x_" << i << " : " << t[i];
+ if( i<(int)(t.getNumChildren()-2) ){
+ Debug( c ) << ", ";
+ }
+ }
+ Debug( c ) << " ) : " << t[(int)t.getNumChildren()-1] << std::endl;
+ if( d_tree.isEmpty() ){
+ Debug( c ) << " [undefined]" << std::endl;
+ }else{
+ d_tree.debugPrint( c, d_me->getQuantifiersEngine(), 3 );
+ Debug( c ) << std::endl;
+ }
+ //Debug( c ) << " Phase reqs:" << std::endl; //for( int i=0; i<2; i++ ){
+ // for( std::map< Node, std::vector< Node > >::iterator it = d_reqs[i].begin(); it != d_reqs[i].end(); ++it ){
+ // Debug( c ) << " " << it->first << std::endl;
+ // for( int j=0; j<(int)it->second.size(); j++ ){
+ // Debug( c ) << " " << it->second[j] << " -> " << (i==1) << std::endl;
+ // }
+ // }
+ //}
+ //Debug( c ) << std::endl;
+ //for( int i=0; i<2; i++ ){
+ // for( std::map< Node, std::map< Node, std::vector< Node > > >::iterator it = d_eq_reqs[i].begin(); it != d_eq_reqs[i].end(); ++it ){
+ // Debug( c ) << " " << "For " << it->first << ":" << std::endl;
+ // for( std::map< Node, std::vector< Node > >::iterator it2 = it->second.begin(); it2 != it->second.end(); ++it2 ){
+ // for( int j=0; j<(int)it2->second.size(); j++ ){
+ // Debug( c ) << " " << it2->first << ( i==1 ? "==" : "!=" ) << it2->second[j] << std::endl;
+ // }
+ // }
+ // }
+ //}
+}
+
+//Model Engine constructor
+ModelEngine::ModelEngine( TheoryQuantifiers* th ){
+ d_th = th;
+ d_quantEngine = th->getQuantifiersEngine();
+ d_ss = ((uf::TheoryUF*)d_quantEngine->getTheoryEngine()->getTheory( THEORY_UF ))->getStrongSolver();
+}
+
+void ModelEngine::check( Theory::Effort e ){
+ if( e==Theory::EFFORT_LAST_CALL ){
+ bool quantsInit = true;
+ //first, check if we can minimize the model further
+ if( !d_ss->minimize() ){
+ return;
+ }
+ if( useModel() ){
+ //now, check if any quantifiers are un-initialized
+ for( int i=0; i<d_quantEngine->getNumAssertedQuantifiers(); i++ ){
+ Node f = d_quantEngine->getAssertedQuantifier( i );
+ if( !initializeQuantifier( f ) ){
+ quantsInit = false;
+ }
+ }
+ }
+ if( quantsInit ){
+#ifdef ME_PRINT_PROCESS_TIMES
+ Notice() << "---Instantiation Round---" << std::endl;
+#endif
+ Debug("fmf-model-debug") << "---Begin Instantiation Round---" << std::endl;
+ ++(d_statistics.d_inst_rounds);
+ d_quantEngine->getTermDatabase()->reset( e );
+ //build the representatives
+ Debug("fmf-model-debug") << "Building representatives..." << std::endl;
+ buildRepresentatives();
+ if( useModel() ){
+ //initialize the model
+ Debug("fmf-model-debug") << "Initializing model..." << std::endl;
+ initializeModel();
+ //analyze the quantifiers
+ Debug("fmf-model-debug") << "Analyzing quantifiers..." << std::endl;
+ analyzeQuantifiers();
+ //build the model
+ Debug("fmf-model-debug") << "Building model..." << std::endl;
+ for( std::map< Node, UfModel >::iterator it = d_uf_model.begin(); it != d_uf_model.end(); ++it ){
+ it->second.buildModel();
+ }
+ }
+ //print debug
+ debugPrint("fmf-model-complete");
+ //try exhaustive instantiation
+ Debug("fmf-model-debug") << "Do exhaustive instantiation..." << std::endl;
+ int addedLemmas = 0;
+ for( int i=0; i<d_quantEngine->getNumAssertedQuantifiers(); i++ ){
+ Node f = d_quantEngine->getAssertedQuantifier( i );
+ if( d_quant_sat.find( f )==d_quant_sat.end() ){
+ addedLemmas += instantiateQuantifier( f );
+ }
+ }
+#ifdef ME_PRINT_PROCESS_TIMES
+ Notice() << "Added Lemmas = " << addedLemmas << std::endl;
+#endif
+ if( addedLemmas==0 ){
+ //debugPrint("fmf-consistent");
+ //for( std::map< Node, UfModel >::iterator it = d_uf_model.begin(); it != d_uf_model.end(); ++it ){
+ // it->second.simplify();
+ //}
+ Debug("fmf-consistent") << std::endl;
+ debugPrint("fmf-consistent");
+ }
+ }
+ d_quantEngine->flushLemmas( &d_th->getOutputChannel() );
+ }
+}
+
+void ModelEngine::registerQuantifier( Node f ){
+
+}
+
+void ModelEngine::assertNode( Node f ){
+
+}
+
+bool ModelEngine::useModel() {
+ return Options::current()->fmfModelBasedInst;
+}
+
+bool ModelEngine::initializeQuantifier( Node f ){
+ if( d_quant_init.find( f )==d_quant_init.end() ){
+ d_quant_init[f] = true;
+ Debug("inst-fmf-init") << "Initialize " << f << std::endl;
+ //add the model basis instantiation
+ // This will help produce the necessary information for model completion.
+ // We do this by extending distinguish ground assertions (those
+ // containing terms with "model basis" attribute) to hold for all cases.
+
+ ////first, check if any variables are required to be equal
+ //for( std::map< Node, bool >::iterator it = d_quantEngine->d_phase_reqs[f].begin();
+ // it != d_quantEngine->d_phase_reqs[f].end(); ++it ){
+ // Node n = it->first;
+ // if( n.getKind()==EQUAL && n[0].getKind()==INST_CONSTANT && n[1].getKind()==INST_CONSTANT ){
+ // Notice() << "Unhandled phase req: " << n << std::endl;
+ // }
+ //}
+
+ std::vector< Node > terms;
+ for( int j=0; j<(int)f[0].getNumChildren(); j++ ){
+ terms.push_back( getModelBasisTerm( f[0][j].getType() ) );
+ }
+ ++(d_statistics.d_num_quants_init);
+ if( d_quantEngine->addInstantiation( f, terms ) ){
+ return false;
+ }else{
+ //usually shouldn't happen
+ //Notice() << "No model basis for " << f << std::endl;
+ ++(d_statistics.d_num_quants_init_fail);
+ }
+ }
+ return true;
+}
+
+void ModelEngine::buildRepresentatives(){
+ d_ra.clear();
+ //collect all representatives for all types and store as representative alphabet
+ for( int i=0; i<d_ss->getNumCardinalityTypes(); i++ ){
+ TypeNode tn = d_ss->getCardinalityType( i );
+ std::vector< Node > reps;
+ d_ss->getRepresentatives( tn, reps );
+ Assert( !reps.empty() );
+ //if( (int)reps.size()!=d_ss->getCardinality( tn ) ){
+ // Notice() << "InstStrategyFinteModelFind::processResetInstantiationRound: Bad representatives for type." << std::endl;
+ // Notice() << " " << tn << " has cardinality " << d_ss->getCardinality( tn );
+ // Notice() << " but only " << (int)reps.size() << " were given." << std::endl;
+ // Unimplemented( 27 );
+ //}
+ Debug("fmf-model-debug") << " " << tn << " -> " << reps.size() << std::endl;
+ Debug("fmf-model-debug") << " ";
+ for( int i=0; i<(int)reps.size(); i++ ){
+ Debug("fmf-model-debug") << reps[i] << " ";
+ }
+ Debug("fmf-model-debug") << std::endl;
+ //set them in the alphabet
+ d_ra.set( tn, reps );
+#ifdef ME_PRINT_PROCESS_TIMES
+ Notice() << tn << " has " << reps.size() << " representatives. " << std::endl;
+#endif
+ }
+}
+
+void ModelEngine::initializeModel(){
+ d_uf_model.clear();
+ d_quant_sat.clear();
+ for( int k=0; k<2; k++ ){
+ d_pro_con_quant[k].clear();
+ }
+
+ ////now analyze quantifiers (temporary)
+ //for( int i=0; i<(int)d_quantEngine->getNumAssertedQuantifiers(); i++ ){
+ // Node f = d_quantEngine->getAssertedQuantifier( i );
+ // Debug("fmf-model-req") << "Phase requirements for " << f << ": " << std::endl;
+ // for( std::map< Node, bool >::iterator it = d_quantEngine->d_phase_reqs[f].begin();
+ // it != d_quantEngine->d_phase_reqs[f].end(); ++it ){
+ // Node n = it->first;
+ // Debug("fmf-model-req") << " " << n << " -> " << it->second << std::endl;
+ // if( n.getKind()==APPLY_UF ){
+ // processPredicate( f, n, it->second );
+ // }else if( n.getKind()==EQUAL ){
+ // processEquality( f, n, it->second );
+ // }
+ // }
+ //}
+ for( int i=0; i<(int)d_quantEngine->getNumAssertedQuantifiers(); i++ ){
+ Node f = d_quantEngine->getAssertedQuantifier( i );
+ initializeUf( f[1] );
+ //register model basis terms
+ std::vector< Node > vars;
+ std::vector< Node > subs;
+ for( int j=0; j<(int)f[0].getNumChildren(); j++ ){
+ vars.push_back( d_quantEngine->getInstantiationConstant( f, j ) );
+ subs.push_back( getModelBasisTerm( f[0][j].getType() ) );
+ }
+ Node n = d_quantEngine->getCounterexampleBody( f );
+ Node gn = n.substitute( vars.begin(), vars.end(), subs.begin(), subs.end() );
+ registerModelBasis( n, gn );
+ }
+}
+
+void ModelEngine::analyzeQuantifiers(){
+ int quantSatInit = 0;
+ int nquantSatInit = 0;
+ //analyze the preferences of each quantifier
+ for( int i=0; i<(int)d_quantEngine->getNumAssertedQuantifiers(); i++ ){
+ Node f = d_quantEngine->getAssertedQuantifier( i );
+ Debug("fmf-model-prefs") << "Analyze quantifier " << f << std::endl;
+ std::vector< Node > pro_con[2];
+ std::vector< Node > pro_con_patterns[2];
+ //check which model basis terms have good and bad definitions according to f
+ for( std::map< Node, bool >::iterator it = d_quantEngine->d_phase_reqs[f].begin();
+ it != d_quantEngine->d_phase_reqs[f].end(); ++it ){
+ Node n = it->first;
+ Node gn = d_model_basis[n];
+ Debug("fmf-model-req") << " Req: " << n << " -> " << it->second << std::endl;
+ int pref = 0;
+ bool isConst = true;
+ std::vector< Node > uf_terms;
+ std::vector< Node > uf_term_patterns;
+ if( gn.getKind()==APPLY_UF ){
+ if( d_quantEngine->getEqualityQuery()->hasTerm( gn ) ){
+ uf_terms.push_back( gn );
+ uf_term_patterns.push_back( n );
+ bool phase = areEqual( gn, NodeManager::currentNM()->mkConst( true ) );
+ pref = phase!=it->second ? 1 : -1;
+ }
+ }else if( gn.getKind()==EQUAL ){
+ bool success = true;
+ for( int j=0; j<2; j++ ){
+ if( n[j].getKind()==APPLY_UF ){
+ Node op = gn[j].getOperator();
+ if( d_uf_model.find( op )!=d_uf_model.end() ){
+ Assert( gn[j].getKind()==APPLY_UF );
+ uf_terms.push_back( gn[j] );
+ uf_term_patterns.push_back( n[j] );
+ }else{
+ //found undefined uf operator
+ success = false;
+ }
+ }else if( n[j].hasAttribute(InstConstantAttribute()) ){
+ isConst = false;
+ }
+ }
+ if( success && !uf_terms.empty() ){
+ if( (!it->second && areEqual( gn[0], gn[1] )) || (it->second && areDisequal( gn[0], gn[1] )) ){
+ pref = 1;
+ }else if( (it->second && areEqual( gn[0], gn[1] )) || (!it->second && areDisequal( gn[0], gn[1] )) ){
+ pref = -1;
+ }
+ }
+ }
+ if( pref!=0 ){
+ Debug("fmf-model-prefs") << " It is " << ( pref==1 ? "pro" : "con" );
+ Debug("fmf-model-prefs") << " the definition of " << n << std::endl;
+ if( pref==1 ){
+ if( isConst ){
+ for( int j=0; j<(int)uf_terms.size(); j++ ){
+ //the only uf that is initialized are those that are constant
+ Node op = uf_terms[j].getOperator();
+ Assert( d_uf_model.find( op )!=d_uf_model.end() );
+ if( !d_uf_model[op].isConstant() ){
+ isConst = false;
+ break;
+ }
+ }
+ if( isConst ){
+ d_quant_sat[f] = true;
+ //we only need to consider current term definition(s) for this quantifier to be satisified, ignore the others
+ for( int k=0; k<2; k++ ){
+ pro_con[k].clear();
+ pro_con_patterns[k].clear();
+ }
+ //instead, just note to the model for each uf term that f is pro its definition
+ for( int j=0; j<(int)uf_terms.size(); j++ ){
+ Node op = uf_terms[j].getOperator();
+ d_uf_model[op].d_reconsider_model = false;
+ }
+ }
+ }
+ }
+ if( d_quant_sat.find( f )!=d_quant_sat.end() ){
+ Debug("fmf-model-prefs") << " * Constant SAT due to definition of " << n << std::endl;
+ break;
+ }else{
+ int pcIndex = pref==1 ? 0 : 1;
+ for( int j=0; j<(int)uf_terms.size(); j++ ){
+ pro_con[pcIndex].push_back( uf_terms[j] );
+ pro_con_patterns[pcIndex].push_back( uf_term_patterns[j] );
+ }
+ }
+ }
+ }
+ if( d_quant_sat.find( f )!=d_quant_sat.end() ){
+ quantSatInit++;
+ d_statistics.d_pre_sat_quant += quantSatInit;
+ }else{
+ nquantSatInit++;
+ d_statistics.d_pre_nsat_quant += quantSatInit;
+ }
+ //add quantifier's preferences to vector
+ for( int k=0; k<2; k++ ){
+ for( int j=0; j<(int)pro_con[k].size(); j++ ){
+ Node op = pro_con[k][j].getOperator();
+ d_uf_model[op].setValuePreference( f, pro_con[k][j], k==0 );
+ d_pro_con_quant[k][ f ].push_back( pro_con_patterns[k][j] );
+ }
+ }
+ }
+ Debug("fmf-model-prefs") << "Pre-Model Completion: Quantifiers SAT: " << quantSatInit << " / " << (quantSatInit+nquantSatInit) << std::endl;
+}
+
+int ModelEngine::instantiateQuantifier( Node f ){
+ int addedLemmas = 0;
+ Debug("inst-fmf-ei") << "Add matches for " << f << "..." << std::endl;
+ Debug("inst-fmf-ei") << " Instantiation Constants: ";
+ for( size_t i=0; i<f[0].getNumChildren(); i++ ){
+ Debug("inst-fmf-ei") << d_quantEngine->getInstantiationConstant( f, i ) << " ";
+ }
+ Debug("inst-fmf-ei") << std::endl;
+ for( int k=0; k<2; k++ ){
+ Debug("inst-fmf-ei") << " " << ( k==0 ? "Pro" : "Con" ) << " definitions:" << std::endl;
+ for( int i=0; i<(int)d_pro_con_quant[k][f].size(); i++ ){
+ Debug("inst-fmf-ei") << " " << d_pro_con_quant[k][f][i] << std::endl;
+ }
+ }
+ if( d_pro_con_quant[0][f].empty() ){
+ Debug("inst-fmf-ei") << "WARNING: " << f << " has no pros for default literal definitions" << std::endl;
+ }
+ d_eval_failed_lits.clear();
+ d_eval_failed.clear();
+ d_eval_term_model.clear();
+ //d_eval_term_vals.clear();
+ //d_eval_term_fv_deps.clear();
+ RepAlphabetIterator riter( d_quantEngine, f, this );
+ increment( &riter );
+#ifdef ONE_INST_PER_QUANT_PER_ROUND
+ while( !riter.isFinished() && addedLemmas==0 ){
+#else
+ while( !riter.isFinished() ){
+#endif
+ InstMatch m;
+ riter.getMatch( d_quantEngine, m );
+ Debug("fmf-model-eval") << "* Add instantiation " << std::endl;
+ riter.d_inst_tried++;
+ if( d_quantEngine->addInstantiation( f, m ) ){
+ addedLemmas++;
+ }
+ riter.increment( d_quantEngine );
+ increment( &riter );
+ }
+ if( Debug.isOn("inst-fmf-ei") ){
+ int totalInst = 1;
+ for( int i=0; i<(int)f[0].getNumChildren(); i++ ){
+ totalInst = totalInst * (int)getReps()->d_type_reps[ f[0][i].getType() ].size();
+ }
+ Debug("inst-fmf-ei") << "Finished: " << std::endl;
+ Debug("inst-fmf-ei") << " Inst Skipped: " << (totalInst-riter.d_inst_tried) << std::endl;
+ Debug("inst-fmf-ei") << " Inst Tried: " << riter.d_inst_tried << std::endl;
+ Debug("inst-fmf-ei") << " Inst Added: " << addedLemmas << std::endl;
+ Debug("inst-fmf-ei") << " # Tests: " << riter.d_inst_tests << std::endl;
+ }
+ return addedLemmas;
+}
+
+void ModelEngine::registerModelBasis( Node n, Node gn ){
+ if( d_model_basis.find( n )==d_model_basis.end() ){
+ d_model_basis[n] = gn;
+ for( int i=0; i<(int)n.getNumChildren(); i++ ){
+ registerModelBasis( n[i], gn[i] );
+ }
+ }
+}
+
+Node ModelEngine::getArbitraryElement( TypeNode tn, std::vector< Node >& exclude ){
+ Node retVal;
+ if( tn==NodeManager::currentNM()->booleanType() ){
+ if( exclude.empty() ){
+ retVal = NodeManager::currentNM()->mkConst( false );
+ }else if( exclude.size()==1 ){
+ retVal = NodeManager::currentNM()->mkConst( areEqual( exclude[0], NodeManager::currentNM()->mkConst( false ) ) );
+ }
+ }else if( d_ra.d_type_reps.find( tn )!=d_ra.d_type_reps.end() ){
+ for( int i=0; i<(int)d_ra.d_type_reps[tn].size(); i++ ){
+ if( std::find( exclude.begin(), exclude.end(), d_ra.d_type_reps[tn][i] )==exclude.end() ){
+ retVal = d_ra.d_type_reps[tn][i];
+ break;
+ }
+ }
+ }
+ if( !retVal.isNull() ){
+ return d_quantEngine->getEqualityQuery()->getRepresentative( retVal );
+ }else{
+ return Node::null();
+ }
+}
+
+Node ModelEngine::getModelBasisTerm( TypeNode tn, int i ){
+ return d_ss->getCardinalityTerm( tn );
+}
+
+Node ModelEngine::getModelBasisApplyUfTerm( Node op ){
+ if( d_model_basis_term.find( op )==d_model_basis_term.end() ){
+ TypeNode t = op.getType();
+ std::vector< Node > children;
+ children.push_back( op );
+ for( int i=0; i<(int)t.getNumChildren()-1; i++ ){
+ children.push_back( getModelBasisTerm( t[i] ) );
+ }
+ d_model_basis_term[op] = NodeManager::currentNM()->mkNode( APPLY_UF, children );
+ }
+ return d_model_basis_term[op];
+}
+
+bool ModelEngine::isModelBasisTerm( Node op, Node n ){
+ if( n.getOperator()==op ){
+ for( int i=0; i<(int)n.getNumChildren(); i++ ){
+ if( !n[i].getAttribute(ModelBasisAttribute()) ){
+ return false;
+ }
+ }
+ return true;
+ }else{
+ return false;
+ }
+}
+
+void ModelEngine::initializeUf( Node n ){
+ std::vector< Node > terms;
+ collectUfTerms( n, terms );
+ for( int i=0; i<(int)terms.size(); i++ ){
+ initializeUfModel( terms[i].getOperator() );
+ }
+}
+
+void ModelEngine::collectUfTerms( Node n, std::vector< Node >& terms ){
+ if( n.getKind()==APPLY_UF ){
+ terms.push_back( n );
+ }
+ for( int i=0; i<(int)n.getNumChildren(); i++ ){
+ collectUfTerms( n[i], terms );
+ }
+}
+
+void ModelEngine::initializeUfModel( Node op ){
+ if( d_uf_model.find( op )==d_uf_model.end() ){
+ TypeNode tn = op.getType();
+ tn = tn[ (int)tn.getNumChildren()-1 ];
+ if( tn==NodeManager::currentNM()->booleanType() || uf::StrongSolverTheoryUf::isRelevantType( tn ) ){
+ d_uf_model[ op ] = UfModel( op, this );
+ }
+ }
+}
+
+void ModelEngine::makeEvalTermModel( Node n ){
+ if( d_eval_term_model.find( n )==d_eval_term_model.end() ){
+ makeEvalTermIndexOrder( n );
+ if( !d_eval_term_use_default_model[n] ){
+ Node op = n.getOperator();
+ d_eval_term_model[n] = UfModelTreeOrdered( op, d_eval_term_index_order[n] );
+ d_uf_model[op].makeModel( d_quantEngine, d_eval_term_model[n] );
+ Debug("fmf-model-index-order") << "Make model for " << n << " : " << std::endl;
+ d_eval_term_model[n].debugPrint( "fmf-model-index-order", d_quantEngine, 2 );
+ }
+ }
+}
+
+struct sortGetMaxVariableNum {
+ std::map< Node, int > d_max_var_num;
+ int computeMaxVariableNum( Node n ){
+ if( n.getKind()==INST_CONSTANT ){
+ return n.getAttribute(InstVarNumAttribute());
+ }else if( n.hasAttribute(InstConstantAttribute()) ){
+ int maxVal = -1;
+ for( int i=0; i<(int)n.getNumChildren(); i++ ){
+ int val = getMaxVariableNum( n[i] );
+ if( val>maxVal ){
+ maxVal = val;
+ }
+ }
+ return maxVal;
+ }else{
+ return -1;
+ }
+ }
+ int getMaxVariableNum( Node n ){
+ std::map< Node, int >::iterator it = d_max_var_num.find( n );
+ if( it==d_max_var_num.end() ){
+ int num = computeMaxVariableNum( n );
+ d_max_var_num[n] = num;
+ return num;
+ }else{
+ return it->second;
+ }
+ }
+ bool operator() (Node i,Node j) { return (getMaxVariableNum(i)<getMaxVariableNum(j));}
+};
+
+void ModelEngine::makeEvalTermIndexOrder( Node n ){
+ if( d_eval_term_index_order.find( n )==d_eval_term_index_order.end() ){
+ //sort arguments in order of least significant vs. most significant variable in default ordering
+ std::map< Node, std::vector< int > > argIndex;
+ std::vector< Node > args;
+ for( int i=0; i<(int)n.getNumChildren(); i++ ){
+ if( argIndex.find( n[i] )==argIndex.end() ){
+ args.push_back( n[i] );
+ }
+ argIndex[n[i]].push_back( i );
+ }
+ sortGetMaxVariableNum sgmvn;
+ std::sort( args.begin(), args.end(), sgmvn );
+ for( int i=0; i<(int)args.size(); i++ ){
+ for( int j=0; j<(int)argIndex[ args[i] ].size(); j++ ){
+ d_eval_term_index_order[n].push_back( argIndex[ args[i] ][j] );
+ }
+ }
+ bool useDefault = true;
+ for( int i=0; i<(int)d_eval_term_index_order[n].size(); i++ ){
+ if( i!=d_eval_term_index_order[n][i] ){
+ useDefault = false;
+ break;
+ }
+ }
+ d_eval_term_use_default_model[n] = useDefault;
+ Debug("fmf-model-index-order") << "Will consider the following index ordering for " << n << " : ";
+ for( int i=0; i<(int)d_eval_term_index_order[n].size(); i++ ){
+ Debug("fmf-model-index-order") << d_eval_term_index_order[n][i] << " ";
+ }
+ Debug("fmf-model-index-order") << std::endl;
+ }
+}
+
+//void ModelEngine::processPredicate( Node f, Node p, bool phase ){
+// Node op = p.getOperator();
+// initializeUfModel( op );
+// d_uf_model[ op ].addRequirement( f, p, phase );
+//}
+//
+//void ModelEngine::processEquality( Node f, Node eq, bool phase ){
+// for( int i=0; i<2; i++ ){
+// int j = i==0 ? 1 : 0;
+// if( eq[i].getKind()==APPLY_UF && eq[i].hasAttribute(InstConstantAttribute()) ){
+// Node op = eq[i].getOperator();
+// initializeUfModel( op );
+// d_uf_model[ op ].addEqRequirement( f, eq[i], eq[j], phase );
+// }
+// }
+//}
+
+void ModelEngine::increment( RepAlphabetIterator* rai ){
+ if( useModel() ){
+ bool success;
+ do{
+ success = true;
+ if( !rai->isFinished() ){
+ //see if instantiation is already true in current model
+ Debug("fmf-model-eval") << "Evaulating ";
+ rai->debugPrintSmall("fmf-model-eval");
+ //calculate represenative terms we are currently considering
+ rai->calculateTerms( d_quantEngine );
+ rai->d_inst_tests++;
+ //if eVal is not (int)rai->d_index.size(), then the instantiation is already true in the model,
+ // and eVal is the highest index in rai which we can safely iterate
+ int depIndex;
+ if( evaluate( rai, d_quantEngine->getCounterexampleBody( rai->d_f ), depIndex )==1 ){
+ Debug("fmf-model-eval") << " Returned success with depIndex = " << depIndex << std::endl;
+ //Notice() << "Returned eVal = " << eVal << "/" << rai->d_index.size() << std::endl;
+ if( depIndex<(int)rai->d_index.size() ){
+#ifdef DISABLE_EVAL_SKIP_MULTIPLE
+ depIndex = (int)rai->d_index.size()-1;
+#endif
+ rai->increment2( d_quantEngine, depIndex );
+ success = false;
+ }
+ }else{
+ Debug("fmf-model-eval") << " Returned failure." << std::endl;
+ }
+ }
+ }while( !success );
+ }
+}
+
+//if evaluate( rai, n, phaseReq ) = eVal,
+// if eVal = rai->d_index.size()
+// then the formula n instantiated with rai cannot be proven to be equal to phaseReq
+// otherwise,
+// each n{rai->d_index[0]/x_0...rai->d_index[eVal]/x_eVal, */x_(eVal+1) ... */x_n } is equal to phaseReq in the current model
+int ModelEngine::evaluate( RepAlphabetIterator* rai, Node n, int& depIndex ){
+ ++(d_statistics.d_eval_formulas);
+ //Debug("fmf-model-eval-debug") << "Evaluate " << n << " " << phaseReq << std::endl;
+ if( n.getKind()==NOT ){
+ int val = evaluate( rai, n[0], depIndex );
+ return val==1 ? -1 : ( val==-1 ? 1 : 0 );
+ }else if( n.getKind()==OR || n.getKind()==AND || n.getKind()==IMPLIES ){
+ int baseVal = n.getKind()==AND ? 1 : -1;
+ int eVal = baseVal;
+ int posDepIndex = (int)rai->d_index.size();
+ int negDepIndex = -1;
+ for( int i=0; i<(int)n.getNumChildren(); i++ ){
+ //evaluate subterm
+ int childDepIndex;
+ Node nn = ( i==0 && n.getKind()==IMPLIES ) ? n[i].notNode() : n[i];
+ int eValT = evaluate( rai, nn, childDepIndex );
+ if( eValT==baseVal ){
+ if( eVal==baseVal ){
+ if( childDepIndex>negDepIndex ){
+ negDepIndex = childDepIndex;
+ }
+ }
+ }else if( eValT==-baseVal ){
+ eVal = -baseVal;
+ if( childDepIndex<posDepIndex ){
+ posDepIndex = childDepIndex;
+ if( posDepIndex==-1 ){
+ break;
+ }
+ }
+ }else if( eValT==0 ){
+ if( eVal==baseVal ){
+ eVal = 0;
+ }
+ }
+ }
+ if( eVal!=0 ){
+ depIndex = eVal==-baseVal ? posDepIndex : negDepIndex;
+ return eVal;
+ }else{
+ return 0;
+ }
+ }else if( n.getKind()==IFF || n.getKind()==XOR ){
+ int depIndex1;
+ int eVal = evaluate( rai, n[0], depIndex1 );
+ if( eVal!=0 ){
+ int depIndex2;
+ int eVal2 = evaluate( rai, n.getKind()==XOR ? n[1].notNode() : n[1], depIndex2 );
+ if( eVal2!=0 ){
+ depIndex = depIndex1>depIndex2 ? depIndex1 : depIndex2;
+ return eVal==eVal2 ? 1 : -1;
+ }
+ }
+ return 0;
+ }else if( n.getKind()==ITE ){
+ int depIndex1;
+ int eVal = evaluate( rai, n[0], depIndex1 );
+ if( eVal==0 ){
+ //DO_THIS: evaluate children to see if they are the same value?
+ return 0;
+ }else{
+ int depIndex2;
+ int eValT = evaluate( rai, n[eVal==1 ? 1 : 2], depIndex2 );
+ depIndex = depIndex1>depIndex2 ? depIndex1 : depIndex2;
+ return eValT;
+ }
+ }else if( n.getKind()==FORALL ){
+ return 0;
+ }else{
+ ////if we know we will fail again, immediately return
+ //if( d_eval_failed.find( n )!=d_eval_failed.end() ){
+ // if( d_eval_failed[n] ){
+ // return -1;
+ // }
+ //}
+ //Debug("fmf-model-eval-debug") << "Evaluate literal " << n << std::endl;
+ //this should be a literal
+ Node gn = n.substitute( rai->d_ic.begin(), rai->d_ic.end(), rai->d_terms.begin(), rai->d_terms.end() );
+ //Debug("fmf-model-eval-debug") << " Ground version = " << gn << std::endl;
+ int retVal = 0;
+ std::vector< Node > fv_deps;
+ if( n.getKind()==APPLY_UF ){
+ //case for boolean predicates
+ Node val = evaluateTerm( n, gn, fv_deps );
+ if( d_quantEngine->getEqualityQuery()->hasTerm( val ) ){
+ if( areEqual( val, NodeManager::currentNM()->mkConst( true ) ) ){
+ retVal = 1;
+ }else{
+ retVal = -1;
+ }
+ }
+ }else if( n.getKind()==EQUAL ){
+ //case for equality
+ retVal = evaluateEquality( n[0], n[1], gn[0], gn[1], fv_deps );
+ }
+ if( retVal!=0 ){
+ int maxIndex = -1;
+ for( int i=0; i<(int)fv_deps.size(); i++ ){
+ int index = rai->d_var_order[ fv_deps[i].getAttribute(InstVarNumAttribute()) ];
+ if( index>maxIndex ){
+ maxIndex = index;
+ if( index==(int)rai->d_index.size()-1 ){
+ break;
+ }
+ }
+ }
+ Debug("fmf-model-eval-debug") << "Evaluate literal: return " << retVal << ", depends = " << maxIndex << std::endl;
+ depIndex = maxIndex;
+ }
+ return retVal;
+ }
+}
+
+int ModelEngine::evaluateEquality( Node n1, Node n2, Node gn1, Node gn2, std::vector< Node >& fv_deps ){
+ ++(d_statistics.d_eval_eqs);
+ Debug("fmf-model-eval-debug") << "Evaluate equality: " << std::endl;
+ Debug("fmf-model-eval-debug") << " " << n1 << " = " << n2 << std::endl;
+ Debug("fmf-model-eval-debug") << " " << gn1 << " = " << gn2 << std::endl;
+ Node val1 = evaluateTerm( n1, gn1, fv_deps );
+ Node val2 = evaluateTerm( n2, gn2, fv_deps );
+ Debug("fmf-model-eval-debug") << " Values : ";
+ printRepresentative( "fmf-model-eval-debug", d_quantEngine, val1 );
+ Debug("fmf-model-eval-debug") << " = ";
+ printRepresentative( "fmf-model-eval-debug", d_quantEngine, val2 );
+ Debug("fmf-model-eval-debug") << std::endl;
+ int retVal = 0;
+ if( areEqual( val1, val2 ) ){
+ retVal = 1;
+ }else if( areDisequal( val1, val2 ) ){
+ retVal = -1;
+ }
+ if( retVal!=0 ){
+ Debug("fmf-model-eval-debug") << " ---> Success, value = " << (retVal==1) << std::endl;
+ }else{
+ Debug("fmf-model-eval-debug") << " ---> Failed" << std::endl;
+ }
+ Debug("fmf-model-eval-debug") << " Value depends on variables: ";
+ for( int i=0; i<(int)fv_deps.size(); i++ ){
+ Debug("fmf-model-eval-debug") << fv_deps[i] << " ";
+ }
+ Debug("fmf-model-eval-debug") << std::endl;
+ return retVal;
+}
+
+Node ModelEngine::evaluateTerm( Node n, Node gn, std::vector< Node >& fv_deps ){
+ if( n.hasAttribute(InstConstantAttribute()) ){
+ if( n.getKind()==INST_CONSTANT ){
+ fv_deps.push_back( n );
+ return gn;
+ //}else if( d_eval_term_fv_deps.find( n )!=d_eval_term_fv_deps.end() &&
+ // d_eval_term_fv_deps[n].find( gn )!=d_eval_term_fv_deps[n].end() ){
+ // fv_deps.insert( fv_deps.end(), d_eval_term_fv_deps[n][gn].begin(), d_eval_term_fv_deps[n][gn].end() );
+ // return d_eval_term_vals[gn];
+ }else{
+ //Debug("fmf-model-eval-debug") << "Evaluate term " << n << " (" << gn << ")" << std::endl;
+ //first we must evaluate the arguments
+ Node val = gn;
+ if( n.getKind()==APPLY_UF ){
+ Node op = gn.getOperator();
+ //if it is a defined UF, then consult the interpretation
+ Node gnn = gn;
+ ++(d_statistics.d_eval_uf_terms);
+ int depIndex = 0;
+ //first we must evaluate the arguments
+ bool childrenChanged = false;
+ std::vector< Node > children;
+ children.push_back( op );
+ std::map< int, std::vector< Node > > children_var_deps;
+ //for each argument, calculate its value, and the variables its value depends upon
+ for( int i=0; i<(int)n.getNumChildren(); i++ ){
+ Node nn = evaluateTerm( n[i], gn[i], children_var_deps[i] );
+ children.push_back( nn );
+ childrenChanged = childrenChanged || nn!=gn[i];
+ }
+ //remake gn if changed
+ if( childrenChanged ){
+ gnn = NodeManager::currentNM()->mkNode( APPLY_UF, children );
+ }
+ if( d_uf_model.find( op )!=d_uf_model.end() ){
+#ifdef USE_INDEX_ORDERING
+ //make the term model specifically for n
+ makeEvalTermModel( n );
+ //now, consult the model
+ if( d_eval_term_use_default_model[n] ){
+ val = d_uf_model[op].d_tree.getValue( d_quantEngine, gnn, depIndex );
+ }else{
+ val = d_eval_term_model[ n ].getValue( d_quantEngine, gnn, depIndex );
+ }
+ //Debug("fmf-model-eval-debug") << "Evaluate term " << n << " (" << gn << ", " << gnn << ")" << std::endl;
+ //d_eval_term_model[ n ].debugPrint("fmf-model-eval-debug", d_quantEngine );
+ Assert( !val.isNull() );
+#else
+ //now, consult the model
+ val = d_uf_model[op].d_tree.getValue( d_quantEngine, gnn, depIndex );
+#endif
+ }else{
+ d_eval_term_use_default_model[n] = true;
+ val = gnn;
+ depIndex = (int)n.getNumChildren();
+ }
+ Debug("fmf-model-eval-debug") << "Evaluate term " << n << " = " << gn << " = " << gnn << " = ";
+ printRepresentative( "fmf-model-eval-debug", d_quantEngine, val );
+ Debug("fmf-model-eval-debug") << ", depIndex = " << depIndex << std::endl;
+ if( !val.isNull() ){
+#ifdef USE_INDEX_ORDERING
+ for( int i=0; i<depIndex; i++ ){
+ int index = d_eval_term_use_default_model[n] ? i : d_eval_term_index_order[n][i];
+ Debug("fmf-model-eval-debug") << "Add variables from " << index << "..." << std::endl;
+ fv_deps.insert( fv_deps.end(), children_var_deps[index].begin(),
+ children_var_deps[index].end() );
+ }
+#else
+ //calculate the free variables that the value depends on : take those in children_var_deps[0...depIndex-1]
+ for( std::map< int, std::vector< Node > >::iterator it = children_var_deps.begin(); it != children_var_deps.end(); ++it ){
+ if( it->first<depIndex ){
+ fv_deps.insert( fv_deps.end(), it->second.begin(), it->second.end() );
+ }
+ }
+#endif
+ }
+ ////cache the result
+ //d_eval_term_vals[gn] = val;
+ //d_eval_term_fv_deps[n][gn].insert( d_eval_term_fv_deps[n][gn].end(), fv_deps.begin(), fv_deps.end() );
+ }
+ return val;
+ }
+ }else{
+ return n;
+ }
+}
+
+void ModelEngine::clearEvalFailed( int index ){
+ for( int i=0; i<(int)d_eval_failed_lits[index].size(); i++ ){
+ d_eval_failed[ d_eval_failed_lits[index][i] ] = false;
+ }
+ d_eval_failed_lits[index].clear();
+}
+
+bool ModelEngine::areEqual( Node a, Node b ){
+ return d_quantEngine->getEqualityQuery()->areEqual( a, b );
+}
+
+bool ModelEngine::areDisequal( Node a, Node b ){
+ return d_quantEngine->getEqualityQuery()->areDisequal( a, b );
+}
+
+void ModelEngine::debugPrint( const char* c ){
+ Debug( c ) << "---Current Model---" << std::endl;
+ Debug( c ) << "Representatives: " << std::endl;
+ d_ra.debugPrint( c, d_quantEngine );
+ Debug( c ) << "Quantifiers: " << std::endl;
+ for( int i=0; i<(int)d_quantEngine->getNumAssertedQuantifiers(); i++ ){
+ Node f = d_quantEngine->getAssertedQuantifier( i );
+ Debug( c ) << " ";
+ if( d_quant_sat.find( f )!=d_quant_sat.end() ){
+ Debug( c ) << "*SAT* ";
+ }else{
+ Debug( c ) << " ";
+ }
+ Debug( c ) << f << std::endl;
+ }
+ Debug( c ) << "Functions: " << std::endl;
+ for( std::map< Node, UfModel >::iterator it = d_uf_model.begin(); it != d_uf_model.end(); ++it ){
+ it->second.debugPrint( c );
+ Debug( c ) << std::endl;
+ }
+}
+
+ModelEngine::Statistics::Statistics():
+ d_inst_rounds("ModelEngine::Inst_Rounds", 0),
+ d_pre_sat_quant("ModelEngine::Status_quant_pre_sat", 0),
+ d_pre_nsat_quant("ModelEngine::Status_quant_pre_non_sat", 0),
+ d_eval_formulas("ModelEngine::Eval_Formulas", 0 ),
+ d_eval_eqs("ModelEngine::Eval_Equalities", 0 ),
+ d_eval_uf_terms("ModelEngine::Eval_Uf_Terms", 0 ),
+ d_num_quants_init("ModelEngine::Num_Quants", 0 ),
+ d_num_quants_init_fail("ModelEngine::Num_Quants_No_Basis", 0 )
+{
+ StatisticsRegistry::registerStat(&d_inst_rounds);
+ StatisticsRegistry::registerStat(&d_pre_sat_quant);
+ StatisticsRegistry::registerStat(&d_pre_nsat_quant);
+ StatisticsRegistry::registerStat(&d_eval_formulas);
+ StatisticsRegistry::registerStat(&d_eval_eqs);
+ StatisticsRegistry::registerStat(&d_eval_uf_terms);
+ StatisticsRegistry::registerStat(&d_num_quants_init);
+ StatisticsRegistry::registerStat(&d_num_quants_init_fail);
+}
+
+ModelEngine::Statistics::~Statistics(){
+ StatisticsRegistry::unregisterStat(&d_inst_rounds);
+ StatisticsRegistry::unregisterStat(&d_pre_sat_quant);
+ StatisticsRegistry::unregisterStat(&d_pre_nsat_quant);
+ StatisticsRegistry::unregisterStat(&d_eval_formulas);
+ StatisticsRegistry::unregisterStat(&d_eval_eqs);
+ StatisticsRegistry::unregisterStat(&d_eval_uf_terms);
+ StatisticsRegistry::unregisterStat(&d_num_quants_init);
+ StatisticsRegistry::unregisterStat(&d_num_quants_init_fail);
+}
diff --git a/src/theory/quantifiers/model_engine.h b/src/theory/quantifiers/model_engine.h
new file mode 100644
index 000000000..4031efdf9
--- /dev/null
+++ b/src/theory/quantifiers/model_engine.h
@@ -0,0 +1,369 @@
+/********************* */
+/*! \file instantiation_engine.h
+ ** \verbatim
+ ** Original author: ajreynol
+ ** Major contributors: none
+ ** Minor contributors (to current version): none
+ ** This file is part of the CVC4 prototype.
+ ** Copyright (c) 2009, 2010, 2011 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
+ ** information.\endverbatim
+ **
+ ** \brief Instantiation Engine classes
+ **/
+
+#include "cvc4_private.h"
+
+#ifndef __CVC4__MODEL_ENGINE_H
+#define __CVC4__MODEL_ENGINE_H
+
+#include "theory/quantifiers_engine.h"
+#include "theory/quantifiers/theory_quantifiers.h"
+
+namespace CVC4 {
+namespace theory {
+
+namespace uf{
+ class StrongSolverTheoryUf;
+}
+
+namespace quantifiers {
+
+/** this class stores a representative alphabet */
+class RepAlphabet {
+public:
+ RepAlphabet(){}
+ RepAlphabet( RepAlphabet& ra, QuantifiersEngine* qe );
+ ~RepAlphabet(){}
+ std::map< TypeNode, std::vector< Node > > d_type_reps;
+ std::map< Node, int > d_tmap;
+ /** clear the alphabet */
+ void clear(){
+ d_type_reps.clear();
+ d_tmap.clear();
+ }
+ /** set the representatives for type */
+ void set( TypeNode t, std::vector< Node >& reps );
+ /** returns index in d_type_reps for node n */
+ int getIndexFor( Node n ) { return d_tmap.find( n )!=d_tmap.end() ? d_tmap[n] : -1; }
+ /** debug print */
+ void debugPrint( const char* c, QuantifiersEngine* qe );
+};
+
+class ModelEngine;
+
+/** this class iterates over a RepAlphabet */
+class RepAlphabetIterator {
+private:
+ void initialize( QuantifiersEngine* qe, Node f, ModelEngine* model );
+public:
+ RepAlphabetIterator( QuantifiersEngine* qe, Node f, ModelEngine* model );
+ RepAlphabetIterator( QuantifiersEngine* qe, Node f, ModelEngine* model, std::vector< int >& indexOrder );
+ ~RepAlphabetIterator(){}
+ //pointer to quantifier
+ Node d_f;
+ //pointer to model
+ ModelEngine* d_model;
+ //index we are considering
+ std::vector< int > d_index;
+ //ordering for variables we are indexing over
+ // for example, given reps = { a, b } and quantifier forall( x, y, z ) P( x, y, z ) with d_index_order = { 2, 0, 1 },
+ // then we consider instantiations in this order:
+ // a/x a/y a/z
+ // a/x b/y a/z
+ // b/x a/y a/z
+ // b/x b/y a/z
+ // ...
+ std::vector< int > d_index_order;
+ //variables to index they are considered at
+ // for example, if d_index_order = { 2, 0, 1 }
+ // then d_var_order = { 0 -> 1, 1 -> 2, 2 -> 0 }
+ std::map< int, int > d_var_order;
+ //the instantiation constants of d_f
+ std::vector< Node > d_ic;
+ //the current terms we are considering
+ std::vector< Node > d_terms;
+public:
+ /** increment the iterator */
+ void increment2( QuantifiersEngine* qe, int counter );
+ void increment( QuantifiersEngine* qe );
+ /** is the iterator finished? */
+ bool isFinished();
+ /** produce the match that this iterator represents */
+ void getMatch( QuantifiersEngine* qe, InstMatch& m );
+ /** get the i_th term we are considering */
+ Node getTerm( int i );
+ /** get the number of terms we are considering */
+ int getNumTerms() { return d_f[0].getNumChildren(); }
+ /** refresh d_term to be current with d_index */
+ void calculateTerms( QuantifiersEngine* qe );
+ /** debug print */
+ void debugPrint( const char* c );
+ void debugPrintSmall( const char* c );
+ //for debugging
+ int d_inst_tried;
+ int d_inst_tests;
+};
+
+
+class UfModelTree
+{
+public:
+ UfModelTree(){}
+ /** the data */
+ std::map< Node, UfModelTree > d_data;
+ /** the value of this tree node (if all paths lead to same value) */
+ Node d_value;
+public:
+ //is this model tree empty?
+ bool isEmpty() { return d_data.empty(); }
+ //clear
+ void clear(){
+ d_data.clear();
+ d_value = Node::null();
+ }
+ /** setValue function
+ *
+ * For each argument of n with ModelBasisAttribute() set to true will be considered default arguments if ground=false
+ *
+ */
+ void setValue( QuantifiersEngine* qe, Node n, Node v, std::vector< int >& indexOrder, bool ground, int argIndex );
+ /** getValue function
+ *
+ * returns $val, the value of ground term n
+ * Say n is f( t_0...t_n )
+ * depIndex is the index for which every term of the form f( t_0 ... t_depIndex, *,... * ) is equal to $val
+ * for example, if g( x_0, x_1, x_2 ) := lambda x_0 x_1 x_2. if( x_1==a ) b else c,
+ * then g( a, a, a ) would return b with depIndex = 1
+ * If ground = true, we are asking whether the term n is constant (assumes that all non-model basis arguments are ground)
+ *
+ */
+ Node getValue( QuantifiersEngine* qe, Node n, std::vector< int >& indexOrder, int& depIndex, int argIndex );
+ ///** getConstant Value function
+ // *
+ // * given term n, where n may contain model basis arguments
+ // * if n is constant for its entire domain, then this function returns the value of its domain
+ // * otherwise, it returns null
+ // * for example, if f( x_0, x_1 ) := if( x_0 = a ) b else if( x_1 = a ) a else b,
+ // * then f( a, e ) would return b, while f( e, a ) would return null
+ // *
+ // */
+ Node getConstantValue( QuantifiersEngine* qe, Node n, std::vector< int >& indexOrder, int argIndex );
+ /** simplify function */
+ void simplify( Node op, Node defaultVal, int argIndex );
+ // is total ?
+ bool isTotal( Node op, int argIndex );
+public:
+ void debugPrint( const char* c, QuantifiersEngine* qe, std::vector< int >& indexOrder, int ind = 0, int arg = 0 );
+};
+
+class UfModelTreeOrdered
+{
+private:
+ Node d_op;
+ std::vector< int > d_index_order;
+ UfModelTree d_tree;
+public:
+ UfModelTreeOrdered(){}
+ UfModelTreeOrdered( Node op ) : d_op( op ){
+ TypeNode tn = d_op.getType();
+ for( int i=0; i<(int)(tn.getNumChildren()-1); i++ ){
+ d_index_order.push_back( i );
+ }
+ }
+ UfModelTreeOrdered( Node op, std::vector< int >& indexOrder ) : d_op( op ){
+ d_index_order.insert( d_index_order.end(), indexOrder.begin(), indexOrder.end() );
+ }
+ bool isEmpty() { return d_tree.isEmpty(); }
+ void clear() { d_tree.clear(); }
+ void setValue( QuantifiersEngine* qe, Node n, Node v, bool ground = true ){
+ d_tree.setValue( qe, n, v, d_index_order, ground, 0 );
+ }
+ Node getValue( QuantifiersEngine* qe, Node n, int& depIndex ){
+ return d_tree.getValue( qe, n, d_index_order, depIndex, 0 );
+ }
+ Node getConstantValue( QuantifiersEngine* qe, Node n ) {
+ return d_tree.getConstantValue( qe, n, d_index_order, 0 );
+ }
+ void simplify() { d_tree.simplify( d_op, Node::null(), 0 ); }
+ bool isTotal() { return d_tree.isTotal( d_op, 0 ); }
+public:
+ void debugPrint( const char* c, QuantifiersEngine* qe, int ind = 0 ){
+ d_tree.debugPrint( c, qe, d_index_order, ind );
+ }
+};
+
+class UfModel
+{
+//public:
+ //std::map< Node, std::vector< Node > > d_reqs[2];
+ //std::map< Node, std::map< Node, std::vector< Node > > > d_eq_reqs[2];
+ ///** add requirement */
+ //void addRequirement( Node f, Node p, bool phase ) { d_reqs[ phase ? 1 : 0 ][ f ].push_back( p ); }
+ ///** add equality requirement */
+ //void addEqRequirement( Node f, Node t, Node te, bool phase ) { d_eq_reqs[ phase ? 1 : 0 ][ f ][ t ].push_back( te ); }
+private:
+ Node d_op;
+ ModelEngine* d_me;
+ std::vector< Node > d_ground_asserts;
+ std::vector< Node > d_ground_asserts_reps;
+ bool d_model_constructed;
+ //store for set values
+ std::map< Node, Node > d_set_values[2];
+ // preferences for default values
+ std::vector< Node > d_values;
+ std::map< Node, std::vector< Node > > d_value_pro_con[2];
+ /** set value */
+ void setValue( Node n, Node v, bool ground = true );
+ /** set model */
+ void setModel();
+ /** clear model */
+ void clearModel();
+public:
+ UfModel(){}
+ UfModel( Node op, ModelEngine* qe );
+ ~UfModel(){}
+ //data structure that stores the model
+ UfModelTreeOrdered d_tree;
+ //quantifiers that are satisfied because of the constant definition of d_op
+ bool d_reconsider_model;
+public:
+ /** debug print */
+ void debugPrint( const char* c );
+ /** get constant value */
+ Node getConstantValue( QuantifiersEngine* qe, Node n );
+ /** is empty */
+ bool isEmpty() { return d_ground_asserts.empty(); }
+ /** is constant */
+ bool isConstant();
+public:
+ /** build model */
+ void buildModel();
+ /** make model */
+ void makeModel( QuantifiersEngine* qe, UfModelTreeOrdered& tree );
+public:
+ /** set value preference */
+ void setValuePreference( Node f, Node n, bool isPro );
+};
+
+
+
+
+class ModelEngine : public QuantifiersModule
+{
+ friend class UfModel;
+ friend class RepAlphabetIterator;
+private:
+ TheoryQuantifiers* d_th;
+ QuantifiersEngine* d_quantEngine;
+ uf::StrongSolverTheoryUf* d_ss;
+ //which quantifiers have been initialized
+ std::map< Node, bool > d_quant_init;
+ //map from ops to model basis terms
+ std::map< Node, Node > d_model_basis_term;
+ //map from instantiation terms to their model basis equivalent
+ std::map< Node, Node > d_model_basis;
+ //the model we are working with
+ RepAlphabet d_ra;
+ std::map< Node, UfModel > d_uf_model;
+ ////map from model basis terms to quantifiers that are pro/con their definition
+ //std::map< Node, std::vector< Node > > d_quant_pro_con[2];
+ //map from quantifiers to model basis terms that are pro the definition of
+ std::map< Node, std::vector< Node > > d_pro_con_quant[2];
+ //map from quantifiers to if are constant SAT
+ std::map< Node, bool > d_quant_sat;
+private:
+ int evaluate( RepAlphabetIterator* rai, Node n, int& depIndex );
+ int evaluateEquality( Node n1, Node n2, Node gn1, Node gn2, std::vector< Node >& fv_deps );
+ Node evaluateTerm( Node n, Node gn, std::vector< Node >& fv_deps );
+ //temporary storing which literals have failed
+ void clearEvalFailed( int index );
+ std::map< Node, bool > d_eval_failed;
+ std::map< int, std::vector< Node > > d_eval_failed_lits;
+ ////temporary storing for values/free variable dependencies
+ //std::map< Node, Node > d_eval_term_vals;
+ //std::map< Node, std::map< Node, std::vector< Node > > > d_eval_term_fv_deps;
+private:
+ //map from terms to the models used to calculate their value
+ std::map< Node, UfModelTreeOrdered > d_eval_term_model;
+ std::map< Node, bool > d_eval_term_use_default_model;
+ void makeEvalTermModel( Node n );
+ //index ordering to use for each term
+ std::map< Node, std::vector< int > > d_eval_term_index_order;
+ int getMaxVariableNum( int n );
+ void makeEvalTermIndexOrder( Node n );
+public:
+ void increment( RepAlphabetIterator* rai );
+private:
+ //queries about equality
+ bool areEqual( Node a, Node b );
+ bool areDisequal( Node a, Node b );
+private:
+ bool useModel();
+private:
+ //initialize quantifiers, return false if lemma needed to be added
+ bool initializeQuantifier( Node f );
+ //build representatives
+ void buildRepresentatives();
+ //initialize model
+ void initializeModel();
+ //analyze quantifiers
+ void analyzeQuantifiers();
+ //instantiate quantifier, return number of lemmas produced
+ int instantiateQuantifier( Node f );
+private:
+ //register instantiation terms with their corresponding model basis terms
+ void registerModelBasis( Node n, Node gn );
+ //for building UF model
+ void initializeUf( Node n );
+ void collectUfTerms( Node n, std::vector< Node >& terms );
+ void initializeUfModel( Node op );
+ //void processPredicate( Node f, Node p, bool phase );
+ //void processEquality( Node f, Node eq, bool phase );
+public:
+ ModelEngine( TheoryQuantifiers* th );
+ ~ModelEngine(){}
+ //get quantifiers engine
+ QuantifiersEngine* getQuantifiersEngine() { return d_quantEngine; }
+ //get representatives
+ RepAlphabet* getReps() { return &d_ra; }
+ //get arbitrary element
+ Node getArbitraryElement( TypeNode tn, std::vector< Node >& exclude );
+ //get model basis term
+ Node getModelBasisTerm( TypeNode tn, int i = 0 );
+ //get model basis term for op
+ Node getModelBasisApplyUfTerm( Node op );
+ //is model basis term for op
+ bool isModelBasisTerm( Node op, Node n );
+public:
+ void check( Theory::Effort e );
+ void registerQuantifier( Node f );
+ void assertNode( Node f );
+ Node explain(TNode n){ return Node::null(); }
+ void propagate( Theory::Effort level ){}
+ void debugPrint( const char* c );
+public:
+ /** statistics class */
+ class Statistics {
+ public:
+ IntStat d_inst_rounds;
+ IntStat d_pre_sat_quant;
+ IntStat d_pre_nsat_quant;
+ IntStat d_eval_formulas;
+ IntStat d_eval_eqs;
+ IntStat d_eval_uf_terms;
+ IntStat d_num_quants_init;
+ IntStat d_num_quants_init_fail;
+ Statistics();
+ ~Statistics();
+ };
+ Statistics d_statistics;
+};
+
+}
+}
+}
+
+#endif
diff --git a/src/theory/quantifiers/quantifiers_rewriter.cpp b/src/theory/quantifiers/quantifiers_rewriter.cpp
new file mode 100644
index 000000000..0fba9d59e
--- /dev/null
+++ b/src/theory/quantifiers/quantifiers_rewriter.cpp
@@ -0,0 +1,722 @@
+/********************* */
+/*! \file theory_quantifiers_rewriter.cpp
+ ** \verbatim
+ ** Original author: ajreynol
+ ** Major contributors: none
+ ** Minor contributors (to current version): none
+ ** This file is part of the CVC4 prototype.
+ ** Copyright (c) 2009, 2010, 2011 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
+ ** information.\endverbatim
+ **
+ ** \brief Implementation of QuantifiersRewriter class
+ **/
+
+#include "theory/quantifiers/quantifiers_rewriter.h"
+
+using namespace std;
+using namespace CVC4;
+using namespace CVC4::kind;
+using namespace CVC4::context;
+using namespace CVC4::theory;
+using namespace CVC4::theory::quantifiers;
+
+bool QuantifiersRewriter::isClause( Node n ){
+ if( isLiteral( n ) ){
+ return true;
+ }else if( n.getKind()==NOT ){
+ return isCube( n[0] );
+ }else if( n.getKind()==OR ){
+ for( int i=0; i<(int)n.getNumChildren(); i++ ){
+ if( !isClause( n[i] ) ){
+ return false;
+ }
+ }
+ return true;
+ }else if( n.getKind()==IMPLIES ){
+ return isCube( n[0] ) && isClause( n[1] );
+ }else{
+ return false;
+ }
+}
+
+bool QuantifiersRewriter::isLiteral( Node n ){
+ switch( n.getKind() ){
+ case NOT:
+ return isLiteral( n[0] );
+ break;
+ case OR:
+ case AND:
+ case IMPLIES:
+ case XOR:
+ case ITE:
+ case IFF:
+ return false;
+ break;
+ case EQUAL:
+ return n[0].getType()!=NodeManager::currentNM()->booleanType();
+ break;
+ default:
+ break;
+ }
+ return true;
+}
+
+bool QuantifiersRewriter::isCube( Node n ){
+ if( isLiteral( n ) ){
+ return true;
+ }else if( n.getKind()==NOT ){
+ return isClause( n[0] );
+ }else if( n.getKind()==AND ){
+ for( int i=0; i<(int)n.getNumChildren(); i++ ){
+ if( !isCube( n[i] ) ){
+ return false;
+ }
+ }
+ return true;
+ }else{
+ return false;
+ }
+}
+
+void QuantifiersRewriter::addNodeToOrBuilder( Node n, NodeBuilder<>& t ){
+ if( n.getKind()==OR ){
+ for( int i=0; i<(int)n.getNumChildren(); i++ ){
+ t << n[i];
+ }
+ }else{
+ t << n;
+ }
+}
+
+void QuantifiersRewriter::computeArgs( std::map< Node, bool >& active, Node n ){
+ if( active.find( n )!=active.end() ){
+ active[n] = true;
+ }else{
+ for( int i=0; i<(int)n.getNumChildren(); i++ ){
+ computeArgs( active, n[i] );
+ }
+ }
+}
+
+void QuantifiersRewriter::computeArgs( std::vector< Node >& args, std::vector< Node >& activeArgs, Node n ){
+ std::map< Node, bool > active;
+ for( int i=0; i<(int)args.size(); i++ ){
+ active[ args[i] ] = false;
+ }
+ //Notice() << "For " << n << " : " << std::endl;
+ computeArgs( active, n );
+ activeArgs.clear();
+ for( std::map< Node, bool >::iterator it = active.begin(); it != active.end(); ++it ){
+ Node n = it->first;
+ //Notice() << " " << it->first << " is " << it->second << std::endl;
+ if( it->second ){ //only add bound variables that occur in body
+ activeArgs.push_back( it->first );
+ }
+ }
+}
+
+bool QuantifiersRewriter::hasArg( std::vector< Node >& args, Node n ){
+ if( std::find( args.begin(), args.end(), n )!=args.end() ){
+ return true;
+ }else{
+ for( int i=0; i<(int)n.getNumChildren(); i++ ){
+ if( hasArg( args, n[i] ) ){
+ return true;
+ }
+ }
+ return false;
+ }
+}
+
+void QuantifiersRewriter::setNestedQuantifiers( Node n, Node q ){
+ if( n.getKind()==FORALL || n.getKind()==EXISTS ){
+ Debug("quantifiers-rewrite-debug") << "Set nested quant attribute " << n << std::endl;
+ NestedQuantAttribute nqai;
+ n.setAttribute(nqai,q);
+ }
+ for( int i=0; i<(int)n.getNumChildren(); i++ ){
+ setNestedQuantifiers( n[i], q );
+ }
+}
+
+RewriteResponse QuantifiersRewriter::preRewrite(TNode in) {
+ Debug("quantifiers-rewrite-debug") << "pre-rewriting " << in << " " << in.hasAttribute(NestedQuantAttribute()) << std::endl;
+ if( in.getKind()==kind::EXISTS || in.getKind()==kind::FORALL ){
+ if( !in.hasAttribute(NestedQuantAttribute()) ){
+ setNestedQuantifiers( in[ 1 ], in );
+ }
+ std::vector< Node > args;
+ for( int i=0; i<(int)in[0].getNumChildren(); i++ ){
+ args.push_back( in[0][i] );
+ }
+ Node body = in[1];
+ bool doRewrite = false;
+ while( body.getNumChildren()>=2 && body.getKind()==in.getKind() ){
+ for( int i=0; i<(int)body[0].getNumChildren(); i++ ){
+ args.push_back( body[0][i] );
+ }
+ body = body[1];
+ doRewrite = true;
+ }
+ if( doRewrite ){
+ std::vector< Node > children;
+ children.push_back( NodeManager::currentNM()->mkNode(kind::BOUND_VAR_LIST,args) );
+ children.push_back( body );
+ if( in.getNumChildren()==3 ){
+ children.push_back( in[2] );
+ }
+ Node n = NodeManager::currentNM()->mkNode( in.getKind(), children );
+ if( in!=n ){
+ if( in.hasAttribute(NestedQuantAttribute()) ){
+ setNestedQuantifiers( n, in.getAttribute(NestedQuantAttribute()) );
+ }
+ Debug("quantifiers-pre-rewrite") << "*** pre-rewrite " << in << std::endl;
+ Debug("quantifiers-pre-rewrite") << " to " << std::endl;
+ Debug("quantifiers-pre-rewrite") << n << std::endl;
+ }
+ return RewriteResponse(REWRITE_DONE, n);
+ }
+ }
+ return RewriteResponse(REWRITE_DONE, in);
+}
+
+RewriteResponse QuantifiersRewriter::postRewrite(TNode in) {
+ Debug("quantifiers-rewrite-debug") << "post-rewriting " << in << " " << in.hasAttribute(NestedQuantAttribute()) << std::endl;
+ if( in.getKind()==kind::EXISTS || in.getKind()==kind::FORALL ){
+ //get the arguments
+ std::vector< Node > args;
+ for( int i=0; i<(int)in[0].getNumChildren(); i++ ){
+ args.push_back( in[0][i] );
+ }
+ //get the body
+ Node body = in[1];
+ if( in.getKind()==EXISTS ){
+ body = body.getKind()==NOT ? body[0] : body.notNode();
+ }
+ //get the instantiation pattern list
+ Node ipl;
+ if( in.getNumChildren()==3 ){
+ ipl = in[2];
+ }
+ bool isNested = in.hasAttribute(NestedQuantAttribute());
+ //compute miniscoping first
+ Node n = body;//computeNNF( body ); TODO: compute NNF here (current bad idea since arithmetic rewrites equalities)
+ if( body!=n ){
+ Notice() << "NNF " << body << " -> " << n << std::endl;
+ }
+ n = computeMiniscoping( args, n, ipl, isNested );
+ if( in.getKind()==kind::EXISTS ){
+ n = n.getKind()==NOT ? n[0] : n.notNode();
+ }
+ //compute other rewrite options for each produced quantifier
+ n = rewriteQuants( n, isNested, true );
+ //print if changed
+ if( in!=n ){
+ if( in.hasAttribute(NestedQuantAttribute()) ){
+ setNestedQuantifiers( n, in.getAttribute(NestedQuantAttribute()) );
+ }
+ Debug("quantifiers-rewrite") << "*** rewrite " << in << std::endl;
+ Debug("quantifiers-rewrite") << " to " << std::endl;
+ Debug("quantifiers-rewrite") << n << std::endl;
+ if( in.hasAttribute(InstConstantAttribute()) ){
+ InstConstantAttribute ica;
+ n.setAttribute(ica,in.getAttribute(InstConstantAttribute()) );
+ }
+ }
+ return RewriteResponse(REWRITE_DONE, n );
+ }
+ return RewriteResponse(REWRITE_DONE, in);
+}
+
+Node QuantifiersRewriter::computeNNF( Node body ){
+ if( body.getKind()==NOT ){
+ if( body[0].getKind()==NOT ){
+ return computeNNF( body[0][0] );
+ }else if( isLiteral( body[0] ) ){
+ return body;
+ }else{
+ std::vector< Node > children;
+ Kind k = body[0].getKind();
+ if( body[0].getKind()==OR || body[0].getKind()==IMPLIES || body[0].getKind()==AND ){
+ for( int i=0; i<(int)body[0].getNumChildren(); i++ ){
+ Node nn = body[0].getKind()==IMPLIES && i==0 ? body[0][i] : body[0][i].notNode();
+ children.push_back( computeNNF( nn ) );
+ }
+ k = body[0].getKind()==AND ? OR : AND;
+ }else if( body[0].getKind()==XOR || body[0].getKind()==IFF ){
+ for( int i=0; i<2; i++ ){
+ Node nn = i==0 ? body[0][i] : body[0][i].notNode();
+ children.push_back( computeNNF( nn ) );
+ }
+ }else if( body[0].getKind()==ITE ){
+ for( int i=0; i<3; i++ ){
+ Node nn = i==0 ? body[0][i] : body[0][i].notNode();
+ children.push_back( computeNNF( nn ) );
+ }
+ }else{
+ Notice() << "Unhandled Quantifiers NNF: " << body << std::endl;
+ return body;
+ }
+ return NodeManager::currentNM()->mkNode( k, children );
+ }
+ }else if( isLiteral( body ) ){
+ return body;
+ }else{
+ std::vector< Node > children;
+ bool childrenChanged = false;
+ for( int i=0; i<(int)body.getNumChildren(); i++ ){
+ Node nc = computeNNF( body[i] );
+ children.push_back( nc );
+ childrenChanged = childrenChanged || nc!=body[i];
+ }
+ if( childrenChanged ){
+ return NodeManager::currentNM()->mkNode( body.getKind(), children );
+ }else{
+ return body;
+ }
+ }
+}
+
+Node QuantifiersRewriter::computeVarElimination( Node body, std::vector< Node >& args, Node& ipl ){
+ //Notice() << "Compute var elimination for " << f << std::endl;
+ std::map< Node, bool > litPhaseReq;
+ QuantifiersEngine::computePhaseReqs( body, false, litPhaseReq );
+ std::vector< Node > vars;
+ std::vector< Node > subs;
+ for( std::map< Node, bool >::iterator it = litPhaseReq.begin(); it != litPhaseReq.end(); ++it ){
+ //Notice() << " " << it->first << " -> " << ( it->second ? "true" : "false" ) << std::endl;
+ if( it->first.getKind()==EQUAL ){
+ if( it->second ){
+ 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] );
+ if( ita!=args.end() ){
+ std::vector< Node > temp;
+ temp.push_back( it->first[i] );
+ if( !hasArg( temp, it->first[j] ) ){
+ vars.push_back( it->first[i] );
+ subs.push_back( it->first[j] );
+ args.erase( ita );
+ break;
+ }
+ }
+ }
+ if( !vars.empty() ){
+ break;
+ }
+ }
+ }
+ }
+ if( !vars.empty() ){
+ //Notice() << "VE " << vars.size() << "/" << n[0].getNumChildren() << std::endl;
+ //remake with eliminated nodes
+ body = body.substitute( vars.begin(), vars.end(), subs.begin(), subs.end() );
+ body = Rewriter::rewrite( body );
+ if( !ipl.isNull() ){
+ ipl = ipl.substitute( vars.begin(), vars.end(), subs.begin(), subs.end() );
+ }
+ }
+ return body;
+}
+
+Node QuantifiersRewriter::computeClause( Node n ){
+ Assert( isClause( n ) );
+ if( isLiteral( n ) ){
+ return n;
+ }else{
+ NodeBuilder<> t(OR);
+ if( n.getKind()==NOT ){
+ if( n[0].getKind()==NOT ){
+ return computeClause( n[0][0] );
+ }else{
+ //De-Morgan's law
+ Assert( n[0].getKind()==AND );
+ for( int i=0; i<(int)n[0].getNumChildren(); i++ ){
+ Node nn = computeClause( n[0][i].notNode() );
+ addNodeToOrBuilder( nn, t );
+ }
+ }
+ }else{
+ for( int i=0; i<(int)n.getNumChildren(); i++ ){
+ Node nc = ( ( i==0 && n.getKind()==IMPLIES ) ? n[i].notNode() : n[i] );
+ Node nn = computeClause( nc );
+ addNodeToOrBuilder( nn, t );
+ }
+ }
+ return t.constructNode();
+ }
+}
+
+Node QuantifiersRewriter::computeCNF( Node n, std::vector< Node >& args, NodeBuilder<>& defs, bool forcePred ){
+ if( isLiteral( n ) ){
+ return n;
+ }else if( !forcePred && isClause( n ) ){
+ return computeClause( n );
+ }else{
+ Kind k = ( n.getKind()==IMPLIES ? OR : ( n.getKind()==XOR ? IFF : n.getKind() ) );
+ NodeBuilder<> t(k);
+ for( int i=0; i<(int)n.getNumChildren(); i++ ){
+ Node nc = ( i==0 && ( n.getKind()==IMPLIES || n.getKind()==XOR ) ) ? n[i].notNode() : n[i];
+ Node ncnf = computeCNF( nc, args, defs, k!=OR );
+ if( k==OR ){
+ addNodeToOrBuilder( ncnf, t );
+ }else{
+ t << ncnf;
+ }
+ }
+ if( !forcePred && k==OR ){
+ return t.constructNode();
+ }else{
+ //compute the free variables
+ Node nt = t;
+ std::vector< Node > activeArgs;
+ computeArgs( args, activeArgs, nt );
+ std::vector< TypeNode > argTypes;
+ for( int i=0; i<(int)activeArgs.size(); i++ ){
+ argTypes.push_back( activeArgs[i].getType() );
+ }
+ //create the predicate
+ Assert( argTypes.size()>0 );
+ TypeNode typ = NodeManager::currentNM()->mkFunctionType( argTypes, NodeManager::currentNM()->booleanType() );
+ std::stringstream ss;
+ ss << "cnf_" << n.getKind() << "_" << n.getId();
+ Node op = NodeManager::currentNM()->mkVar( ss.str(), typ );
+ std::vector< Node > predArgs;
+ predArgs.push_back( op );
+ predArgs.insert( predArgs.end(), activeArgs.begin(), activeArgs.end() );
+ Node pred = NodeManager::currentNM()->mkNode( APPLY_UF, predArgs );
+ Debug("quantifiers-rewrite-cnf-debug") << "Made predicate " << pred << " for " << nt << std::endl;
+ //create the bound var list
+ Node bvl = NodeManager::currentNM()->mkNode( BOUND_VAR_LIST, activeArgs );
+ //now, look at the structure of nt
+ if( nt.getKind()==NOT ){
+ //case for NOT
+ for( int i=0; i<2; i++ ){
+ NodeBuilder<> tt(OR);
+ tt << ( i==0 ? nt[0].notNode() : nt[0] );
+ tt << ( i==0 ? pred.notNode() : pred );
+ defs << NodeManager::currentNM()->mkNode( FORALL, bvl, tt.constructNode() );
+ }
+ }else if( nt.getKind()==OR ){
+ //case for OR
+ for( int i=0; i<(int)nt.getNumChildren(); i++ ){
+ NodeBuilder<> tt(OR);
+ tt << nt[i].notNode() << pred;
+ defs << NodeManager::currentNM()->mkNode( FORALL, bvl, tt.constructNode() );
+ }
+ NodeBuilder<> tt(OR);
+ for( int i=0; i<(int)nt.getNumChildren(); i++ ){
+ tt << nt[i];
+ }
+ tt << pred.notNode();
+ defs << NodeManager::currentNM()->mkNode( FORALL, bvl, tt.constructNode() );
+ }else if( nt.getKind()==AND ){
+ //case for AND
+ for( int i=0; i<(int)nt.getNumChildren(); i++ ){
+ NodeBuilder<> tt(OR);
+ tt << nt[i] << pred.notNode();
+ defs << NodeManager::currentNM()->mkNode( FORALL, bvl, tt.constructNode() );
+ }
+ NodeBuilder<> tt(OR);
+ for( int i=0; i<(int)nt.getNumChildren(); i++ ){
+ tt << nt[i].notNode();
+ }
+ tt << pred;
+ defs << NodeManager::currentNM()->mkNode( FORALL, bvl, tt.constructNode() );
+ }else if( nt.getKind()==IFF ){
+ //case for IFF
+ for( int i=0; i<4; i++ ){
+ NodeBuilder<> tt(OR);
+ tt << ( ( i==0 || i==3 ) ? nt[0].notNode() : nt[0] );
+ tt << ( ( i==1 || i==3 ) ? nt[1].notNode() : nt[1] );
+ tt << ( ( i==0 || i==1 ) ? pred.notNode() : pred );
+ defs << NodeManager::currentNM()->mkNode( FORALL, bvl, tt.constructNode() );
+ }
+ }else if( nt.getKind()==ITE ){
+ //case for ITE
+ for( int j=1; j<=2; j++ ){
+ for( int i=0; i<2; i++ ){
+ NodeBuilder<> tt(OR);
+ tt << ( ( j==1 ) ? nt[0].notNode() : nt[0] );
+ tt << ( ( i==1 ) ? nt[j].notNode() : nt[j] );
+ tt << ( ( i==0 ) ? pred.notNode() : pred );
+ defs << NodeManager::currentNM()->mkNode( FORALL, bvl, tt.constructNode() );
+ }
+ }
+ for( int i=0; i<2; i++ ){
+ NodeBuilder<> tt(OR);
+ tt << ( i==0 ? nt[1].notNode() : nt[1] );
+ tt << ( i==0 ? nt[2].notNode() : nt[2] );
+ tt << ( i==1 ? pred.notNode() : pred );
+ defs << NodeManager::currentNM()->mkNode( FORALL, bvl, tt.constructNode() );
+ }
+ }else{
+ Notice() << "Unhandled Quantifiers CNF: " << nt << std::endl;
+ }
+ return pred;
+ }
+ }
+}
+
+Node QuantifiersRewriter::computePrenex( Node body, std::vector< Node >& args, bool pol, bool polReq ){
+ if( body.getKind()==FORALL ){
+ if( pol==polReq ){
+ std::vector< Node > terms;
+ std::vector< Node > subs;
+ if( polReq ){
+ //for doing prenexing of same-signed quantifiers
+ //must rename each variable that already exists
+ for( int i=0; i<(int)body[0].getNumChildren(); i++ ){
+ //if( std::find( args.begin(), args.end(), body[0][i] )!=args.end() ){
+ terms.push_back( body[0][i] );
+ subs.push_back( NodeManager::currentNM()->mkVar( body[0][i].getType() ) );
+ }
+ args.insert( args.end(), subs.begin(), subs.end() );
+ }else{
+ std::vector< TypeNode > argTypes;
+ for( int i=0; i<(int)args.size(); i++ ){
+ argTypes.push_back( args[i].getType() );
+ }
+ //for doing pre-skolemization of opposite-signed quantifiers
+ for( int i=0; i<(int)body[0].getNumChildren(); i++ ){
+ terms.push_back( body[0][i] );
+ //make the new function symbol
+ TypeNode typ = NodeManager::currentNM()->mkFunctionType( argTypes, body[0][i].getType() );
+ Node op = NodeManager::currentNM()->mkVar( typ );
+ std::vector< Node > funcArgs;
+ funcArgs.push_back( op );
+ funcArgs.insert( funcArgs.end(), args.begin(), args.end() );
+ subs.push_back( NodeManager::currentNM()->mkNode( APPLY_UF, funcArgs ) );
+ }
+ }
+ Node newBody = body[1];
+ newBody = newBody.substitute( terms.begin(), terms.end(), subs.begin(), subs.end() );
+ return newBody;
+ }else{
+ return body;
+ }
+ }else if( body.getKind()==ITE || body.getKind()==XOR || body.getKind()==IFF ){
+ return body;
+ }else{
+ Assert( body.getKind()!=EXISTS );
+ bool childrenChanged = false;
+ std::vector< Node > newChildren;
+ for( int i=0; i<(int)body.getNumChildren(); i++ ){
+ bool newPol = ( body.getKind()==NOT || ( body.getKind()==IMPLIES && i==0 ) ) ? !pol : pol;
+ Node n = computePrenex( body[i], args, newPol, polReq );
+ newChildren.push_back( n );
+ if( n!=body[i] ){
+ childrenChanged = true;
+ }
+ }
+ if( childrenChanged ){
+ if( body.getKind()==NOT && newChildren[0].getKind()==NOT ){
+ return newChildren[0][0];
+ }else{
+ return NodeManager::currentNM()->mkNode( body.getKind(), newChildren );
+ }
+ }else{
+ return body;
+ }
+ }
+}
+
+//general method for computing various rewrites
+Node QuantifiersRewriter::computeOperation( Node f, int computeOption ){
+ std::vector< Node > args;
+ for( int i=0; i<(int)f[0].getNumChildren(); i++ ){
+ args.push_back( f[0][i] );
+ }
+ NodeBuilder<> defs(kind::AND);
+ Node n = f[1];
+ Node ipl;
+ if( f.getNumChildren()==3 ){
+ ipl = f[2];
+ }
+ if( computeOption==COMPUTE_NNF ){
+ n = computeNNF( n );
+ }else if( computeOption==COMPUTE_PRENEX || computeOption==COMPUTE_PRE_SKOLEM ){
+ n = computePrenex( n, args, true, computeOption==COMPUTE_PRENEX );
+ }else if( computeOption==COMPUTE_VAR_ELIMINATION ){
+ Node prev;
+ do{
+ prev = n;
+ n = computeVarElimination( n, args, ipl );
+ }while( prev!=n && !args.empty() );
+ }else if( computeOption==COMPUTE_CNF ){
+ //n = computeNNF( n );
+ n = computeCNF( n, args, defs, false );
+ ipl = Node::null();
+ }
+ if( f[1]==n && args.size()==long(f[0].getNumChildren()) ){
+ return f;
+ }else{
+ if( args.empty() ){
+ defs << n;
+ }else{
+ std::vector< Node > children;
+ children.push_back( NodeManager::currentNM()->mkNode(kind::BOUND_VAR_LIST, args ) );
+ children.push_back( n );
+ if( !ipl.isNull() ){
+ children.push_back( ipl );
+ }
+ defs << NodeManager::currentNM()->mkNode(kind::FORALL, children );
+ }
+ return defs.getNumChildren()==1 ? defs.getChild( 0 ) : defs.constructNode();
+ }
+}
+
+Node QuantifiersRewriter::mkForAll( std::vector< Node >& args, Node body, Node ipl ){
+ std::vector< Node > activeArgs;
+ computeArgs( args, activeArgs, body );
+ if( activeArgs.empty() ){
+ return body;
+ }else{
+ std::vector< Node > children;
+ children.push_back( NodeManager::currentNM()->mkNode(kind::BOUND_VAR_LIST, activeArgs ) );
+ children.push_back( body );
+ if( !ipl.isNull() ){
+ children.push_back( ipl );
+ }
+ return NodeManager::currentNM()->mkNode( kind::FORALL, children );
+ }
+}
+
+Node QuantifiersRewriter::computeMiniscoping( std::vector< Node >& args, Node body, Node ipl, bool isNested ){
+ //Notice() << "rewrite quant " << body << std::endl;
+ if( body.getKind()==FORALL ){
+ //combine arguments
+ std::vector< Node > newArgs;
+ for( int i=0; i<(int)body[0].getNumChildren(); i++ ){
+ newArgs.push_back( body[0][i] );
+ }
+ newArgs.insert( newArgs.end(), args.begin(), args.end() );
+ return mkForAll( newArgs, body[ 1 ], ipl );
+ }else if( !isNested ){
+ if( body.getKind()==NOT ){
+ //push not downwards
+ if( body[0].getKind()==NOT ){
+ return computeMiniscoping( args, body[0][0], ipl );
+ }else if( body[0].getKind()==AND ){
+ if( doMiniscopingNoFreeVar() ){
+ NodeBuilder<> t(kind::OR);
+ for( int i=0; i<(int)body[0].getNumChildren(); i++ ){
+ t << ( body[0][i].getKind()==NOT ? body[0][i][0] : body[0][i].notNode() );
+ }
+ return computeMiniscoping( args, t.constructNode(), ipl );
+ }
+ }else if( body[0].getKind()==OR || body[0].getKind()==IMPLIES ){
+ if( doMiniscopingAnd() ){
+ NodeBuilder<> t(kind::AND);
+ for( int i=0; i<(int)body[0].getNumChildren(); i++ ){
+ Node trm = ( body[0].getKind()==IMPLIES && i==0 ) ? body[0][i] : ( body[0][i].getKind()==NOT ? body[0][i][0] : body[0][i].notNode() );
+ t << computeMiniscoping( args, trm, ipl );
+ }
+ return t.constructNode();
+ }
+ }
+ }else if( body.getKind()==AND ){
+ if( doMiniscopingAnd() ){
+ //break apart
+ NodeBuilder<> t(kind::AND);
+ for( int i=0; i<(int)body.getNumChildren(); i++ ){
+ t << computeMiniscoping( args, body[i], ipl );
+ }
+ Node retVal = t;
+ return retVal;
+ }
+ }else if( body.getKind()==OR || body.getKind()==IMPLIES ){
+ if( doMiniscopingNoFreeVar() ){
+ Node newBody = body;
+ NodeBuilder<> body_split(kind::OR);
+ NodeBuilder<> tb(kind::OR);
+ for( int i=0; i<(int)body.getNumChildren(); i++ ){
+ Node trm = ( body.getKind()==IMPLIES && i==0 ) ? ( body[i].getKind()==NOT ? body[i][0] : body[i].notNode() ) : body[i];
+ if( hasArg( args, body[i] ) ){
+ tb << trm;
+ }else{
+ body_split << trm;
+ }
+ }
+ if( tb.getNumChildren()==0 ){
+ return body_split;
+ }else if( body_split.getNumChildren()>0 ){
+ newBody = tb.getNumChildren()==1 ? tb.getChild( 0 ) : tb;
+ body_split << mkForAll( args, newBody, ipl );
+ return body_split.getNumChildren()==1 ? body_split.getChild( 0 ) : body_split;
+ }
+ }
+ }
+ }
+ return mkForAll( args, body, ipl );
+}
+
+Node QuantifiersRewriter::rewriteQuants( Node n, bool isNested, bool duringRewrite ){
+ if( n.getKind()==FORALL ){
+ return rewriteQuant( n, isNested, duringRewrite );
+ }else if( isLiteral( n ) ){
+ return n;
+ }else{
+ NodeBuilder<> tt(n.getKind());
+ for( int i=0; i<(int)n.getNumChildren(); i++ ){
+ tt << rewriteQuants( n[i], isNested, duringRewrite );
+ }
+ return tt.constructNode();
+ }
+}
+
+Node QuantifiersRewriter::rewriteQuant( Node n, bool isNested, bool duringRewrite ){
+ Node prev = n;
+ for( int op=0; op<COMPUTE_LAST; op++ ){
+ if( doOperation( n, isNested, op, duringRewrite ) ){
+ Node prev2 = n;
+ n = computeOperation( n, op );
+ if( prev2!=n ){
+ Debug("quantifiers-rewrite-op") << "Rewrite op " << op << ": rewrite " << prev2 << std::endl;
+ Debug("quantifiers-rewrite-op") << " to " << std::endl;
+ Debug("quantifiers-rewrite-op") << n << std::endl;
+ }
+ }
+ }
+ if( prev==n ){
+ return n;
+ }else{
+ //rewrite again until fix point is reached
+ return rewriteQuant( n, isNested, duringRewrite );
+ }
+}
+
+bool QuantifiersRewriter::doMiniscopingNoFreeVar(){
+ return Options::current()->miniscopeQuantFreeVar;
+}
+
+bool QuantifiersRewriter::doMiniscopingAnd(){
+ if( Options::current()->miniscopeQuant ){
+ return true;
+ }else{
+ if( Options::current()->cbqi ){
+ return true;
+ }else{
+ return false;
+ }
+ }
+}
+
+bool QuantifiersRewriter::doOperation( Node f, bool isNested, int computeOption, bool duringRewrite ){
+ if( computeOption==COMPUTE_NNF ){
+ return false;//TODO: compute NNF (current bad idea since arithmetic rewrites equalities)
+ }else if( computeOption==COMPUTE_PRE_SKOLEM ){
+ return Options::current()->preSkolemQuant && !duringRewrite;
+ }else if( computeOption==COMPUTE_PRENEX ){
+ return Options::current()->prenexQuant;
+ }else if( computeOption==COMPUTE_VAR_ELIMINATION ){
+ return Options::current()->varElimQuant;
+ }else if( computeOption==COMPUTE_CNF ){
+ return Options::current()->cnfQuant && !duringRewrite;// || Options::current()->finiteModelFind;
+ }else{
+ return false;
+ }
+}
diff --git a/src/theory/quantifiers/quantifiers_rewriter.h b/src/theory/quantifiers/quantifiers_rewriter.h
new file mode 100644
index 000000000..8c037d30b
--- /dev/null
+++ b/src/theory/quantifiers/quantifiers_rewriter.h
@@ -0,0 +1,88 @@
+/********************* */
+/*! \file quantifiers_rewriter.h
+ ** \verbatim
+ ** Original author: ajreynol
+ ** Major contributors: mdeters
+ ** Minor contributors (to current version): none
+ ** This file is part of the CVC4 prototype.
+ ** Copyright (c) 2009, 2010, 2011 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
+ ** information.\endverbatim
+ **
+ ** \brief Rewriter for the theory of inductive quantifiers
+ **
+ ** Rewriter for the theory of inductive quantifiers.
+ **/
+
+#include "cvc4_private.h"
+
+#ifndef __CVC4__THEORY__QUANTIFIERS__QUANTIFIERS_REWRITER_H
+#define __CVC4__THEORY__QUANTIFIERS__QUANTIFIERS_REWRITER_H
+
+#include "theory/rewriter.h"
+#include "theory/quantifiers_engine.h"
+
+namespace CVC4 {
+namespace theory {
+namespace quantifiers {
+
+// attribute for "contains instantiation constants from"
+struct NestedQuantAttributeId {};
+typedef expr::Attribute<NestedQuantAttributeId, Node> NestedQuantAttribute;
+
+class QuantifiersRewriter {
+public:
+ static bool isClause( Node n );
+ static bool isLiteral( Node n );
+ static bool isCube( Node n );
+private:
+ static void addNodeToOrBuilder( Node n, NodeBuilder<>& t );
+ static Node mkForAll( std::vector< Node >& args, Node body, Node ipl );
+ static void computeArgs( std::vector< Node >& args, std::vector< Node >& activeArgs, Node n );
+ static bool hasArg( std::vector< Node >& args, Node n );
+ static void setNestedQuantifiers( Node n, Node q );
+ static void computeArgs( std::map< Node, bool >& active, Node n );
+ static Node computeClause( Node n );
+private:
+ static Node computeMiniscoping( std::vector< Node >& args, Node body, Node ipl, bool isNested = false );
+ static Node computeNNF( Node body );
+ static Node computeVarElimination( Node body, std::vector< Node >& args, Node& ipl );
+ static Node computeCNF( Node body, std::vector< Node >& args, NodeBuilder<>& defs, bool forcePred );
+ static Node computePrenex( Node body, std::vector< Node >& args, bool pol, bool polReq );
+private:
+ enum{
+ COMPUTE_NNF = 0,
+ COMPUTE_PRE_SKOLEM,
+ COMPUTE_PRENEX,
+ COMPUTE_VAR_ELIMINATION,
+ //COMPUTE_FLATTEN_ARGS_UF,
+ COMPUTE_CNF,
+ COMPUTE_LAST
+ };
+ static Node computeOperation( Node f, int computeOption );
+public:
+ static RewriteResponse preRewrite(TNode in);
+ static RewriteResponse postRewrite(TNode in);
+ static Node rewriteEquality(TNode equality) {
+ return postRewrite(equality).node;
+ }
+ static inline void init() {}
+ static inline void shutdown() {}
+private:
+ /** options */
+ static bool doMiniscopingNoFreeVar();
+ static bool doMiniscopingAnd();
+ static bool doOperation( Node f, bool isNested, int computeOption, bool duringRewrite = true );
+public:
+ static Node rewriteQuants( Node n, bool isNested = false, bool duringRewrite = true );
+ static Node rewriteQuant( Node n, bool isNested = false, bool duringRewrite = true );
+};/* class QuantifiersRewriter */
+
+}/* CVC4::theory::quantifiers namespace */
+}/* CVC4::theory namespace */
+}/* CVC4 namespace */
+
+#endif /* __CVC4__THEORY__QUANTIFIERS__QUANTIFIERS_REWRITER_H */
+
diff --git a/src/theory/quantifiers/theory_quantifiers.cpp b/src/theory/quantifiers/theory_quantifiers.cpp
new file mode 100644
index 000000000..ead47e4b0
--- /dev/null
+++ b/src/theory/quantifiers/theory_quantifiers.cpp
@@ -0,0 +1,199 @@
+/********************* */
+/*! \file theory_quantifiers.cpp
+ ** \verbatim
+ ** Original author: ajreynol
+ ** Major contributors: none
+ ** Minor contributors (to current version): none
+ ** This file is part of the CVC4 prototype.
+ ** Copyright (c) 2009, 2010, 2011 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
+ ** information.\endverbatim
+ **
+ ** \brief Implementation of the theory of quantifiers
+ **
+ ** Implementation of the theory of quantifiers.
+ **/
+
+
+#include "theory/quantifiers/theory_quantifiers.h"
+#include "theory/valuation.h"
+#include "theory/quantifiers_engine.h"
+#include "theory/quantifiers/instantiation_engine.h"
+#include "theory/quantifiers/model_engine.h"
+#include "expr/kind.h"
+#include "util/Assert.h"
+#include <map>
+#include <time.h>
+#include "theory/quantifiers/theory_quantifiers_instantiator.h"
+
+#define USE_FLIP_DECISION
+
+//static bool clockSet = false;
+//double initClock;
+
+using namespace std;
+using namespace CVC4;
+using namespace CVC4::kind;
+using namespace CVC4::context;
+using namespace CVC4::theory;
+using namespace CVC4::theory::quantifiers;
+
+TheoryQuantifiers::TheoryQuantifiers(Context* c, context::UserContext* u, OutputChannel& out, Valuation valuation, const LogicInfo& logicInfo, QuantifiersEngine* qe) :
+ Theory(THEORY_QUANTIFIERS, c, u, out, valuation, logicInfo, qe),
+ d_numRestarts(0){
+ d_numInstantiations = 0;
+ d_baseDecLevel = -1;
+ if( Options::current()->finiteModelFind ){
+ qe->addModule( new ModelEngine( this ) );
+ }else{
+ qe->addModule( new InstantiationEngine( this ) );
+ }
+}
+
+
+TheoryQuantifiers::~TheoryQuantifiers() {
+}
+
+void TheoryQuantifiers::addSharedTerm(TNode t) {
+ Debug("quantifiers-other") << "TheoryQuantifiers::addSharedTerm(): "
+ << t << endl;
+}
+
+
+void TheoryQuantifiers::notifyEq(TNode lhs, TNode rhs) {
+ Debug("quantifiers-other") << "TheoryQuantifiers::notifyEq(): "
+ << lhs << " = " << rhs << endl;
+
+}
+
+void TheoryQuantifiers::preRegisterTerm(TNode n) {
+ Debug("quantifiers-prereg") << "TheoryQuantifiers::preRegisterTerm() " << n << endl;
+ if( n.getKind()==FORALL && !n.hasAttribute(InstConstantAttribute()) ){
+ getQuantifiersEngine()->registerQuantifier( n );
+ }
+}
+
+
+void TheoryQuantifiers::presolve() {
+ Debug("quantifiers-presolve") << "TheoryQuantifiers::presolve()" << endl;
+}
+
+Node TheoryQuantifiers::getValue(TNode n) {
+ //NodeManager* nodeManager = NodeManager::currentNM();
+ switch(n.getKind()) {
+ case FORALL:
+ case EXISTS:
+ bool value;
+ if( d_valuation.hasSatValue( n, value ) ){
+ return NodeManager::currentNM()->mkConst(value);
+ }else{
+ return NodeManager::currentNM()->mkConst(false); //FIX_THIS?
+ }
+ break;
+ default:
+ Unhandled(n.getKind());
+ }
+}
+
+void TheoryQuantifiers::check(Effort e) {
+ CodeTimer codeTimer(d_theoryTime);
+
+ Debug("quantifiers-check") << "quantifiers::check(" << e << ")" << std::endl;
+ while(!done()) {
+ Node assertion = get();
+ Debug("quantifiers-assert") << "quantifiers::assert(): " << assertion << std::endl;
+ switch(assertion.getKind()) {
+ case kind::FORALL:
+ assertUniversal( assertion );
+ break;
+ case kind::NOT:
+ {
+ switch( assertion[0].getKind()) {
+ case kind::FORALL:
+ assertExistential( assertion );
+ break;
+ default:
+ Unhandled(assertion[0].getKind());
+ break;
+ }
+ }
+ break;
+ default:
+ Unhandled(assertion.getKind());
+ break;
+ }
+ }
+ // call the quantifiers engine to check
+ getQuantifiersEngine()->check( e );
+}
+
+void TheoryQuantifiers::propagate(Effort level){
+ CodeTimer codeTimer(d_theoryTime);
+
+ getQuantifiersEngine()->propagate( level );
+}
+
+void TheoryQuantifiers::assertUniversal( Node n ){
+ Assert( n.getKind()==FORALL );
+ if( !n.hasAttribute(InstConstantAttribute()) ){
+ getQuantifiersEngine()->registerQuantifier( n );
+ getQuantifiersEngine()->assertNode( n );
+ }
+}
+
+void TheoryQuantifiers::assertExistential( Node n ){
+ Assert( n.getKind()== NOT && n[0].getKind()==FORALL );
+ if( !n[0].hasAttribute(InstConstantAttribute()) ){
+ if( d_skolemized.find( n )==d_skolemized.end() ){
+ Node body = getQuantifiersEngine()->getSkolemizedBody( n[0] );
+ NodeBuilder<> nb(kind::OR);
+ nb << n[0] << body.notNode();
+ Node lem = nb;
+ Debug("quantifiers-sk") << "Skolemize lemma : " << lem << std::endl;
+ d_out->lemma( lem );
+ d_skolemized[n] = true;
+ }
+ }
+}
+
+bool TheoryQuantifiers::flipDecision(){
+#ifndef USE_FLIP_DECISION
+ return false;
+#else
+ //Debug("quantifiers-flip") << "No instantiation given, flip decision, level = " << d_valuation.getDecisionLevel() << std::endl;
+ //for( int i=1; i<=(int)d_valuation.getDecisionLevel(); i++ ){
+ // Debug("quantifiers-flip") << " " << d_valuation.getDecision( i ) << std::endl;
+ //}
+ //if( d_valuation.getDecisionLevel()>0 ){
+ // double r = double(rand())/double(RAND_MAX);
+ // unsigned decisionLevel = (unsigned)(r*d_valuation.getDecisionLevel());
+ // d_out->flipDecision( decisionLevel );
+ // return true;
+ //}else{
+ // return false;
+ //}
+
+ if( !d_out->flipDecision() ){
+ return restart();
+ }
+ return true;
+#endif
+}
+
+bool TheoryQuantifiers::restart(){
+ static const int restartLimit = 0;
+ if( d_numRestarts==restartLimit ){
+ Debug("quantifiers-flip") << "No more restarts." << std::endl;
+ return false;
+ }else{
+ d_numRestarts++;
+ Debug("quantifiers-flip") << "Do restart." << std::endl;
+ return true;
+ }
+}
+
+void TheoryQuantifiers::performCheck(Effort e){
+ getQuantifiersEngine()->check( e );
+}
diff --git a/src/theory/quantifiers/theory_quantifiers.h b/src/theory/quantifiers/theory_quantifiers.h
new file mode 100644
index 000000000..05c3b9695
--- /dev/null
+++ b/src/theory/quantifiers/theory_quantifiers.h
@@ -0,0 +1,77 @@
+/********************* */
+/*! \file theory_quantifiers.h
+ ** \verbatim
+ ** Original author: ajreynol
+ ** Major contributors: none
+ ** Minor contributors (to current version): none
+ ** This file is part of the CVC4 prototype.
+ ** Copyright (c) 2009, 2010, 2011 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
+ ** information.\endverbatim
+ **
+ ** \brief Theory of quantifiers.
+ **
+ ** Theory of quantifiers.
+ **/
+
+#include "cvc4_private.h"
+
+#ifndef __CVC4__THEORY__QUANTIFIERS__THEORY_QUANTIFIERS_H
+#define __CVC4__THEORY__QUANTIFIERS__THEORY_QUANTIFIERS_H
+
+#include "theory/theory.h"
+#include "util/hash.h"
+#include "util/stats.h"
+
+#include <ext/hash_set>
+#include <iostream>
+#include <map>
+
+namespace CVC4 {
+namespace theory {
+namespace quantifiers {
+
+class TheoryEngine;
+
+class TheoryQuantifiers : public Theory {
+private:
+ typedef context::CDHashMap< Node, bool, NodeHashFunction > BoolMap;
+ /** quantifiers that have been skolemized */
+ std::map< Node, bool > d_skolemized;
+ /** number of instantiations */
+ int d_numInstantiations;
+ int d_baseDecLevel;
+ /** number of restarts */
+ int d_numRestarts;
+
+ KEEP_STATISTIC(TimerStat, d_theoryTime, "theory::quantifiers::theoryTime");
+
+public:
+ TheoryQuantifiers(context::Context* c, context::UserContext* u, OutputChannel& out, Valuation valuation, const LogicInfo& logicInfo, QuantifiersEngine* qe);
+ ~TheoryQuantifiers();
+
+ void addSharedTerm(TNode t);
+ void notifyEq(TNode lhs, TNode rhs);
+ void preRegisterTerm(TNode n);
+ void presolve();
+ void check(Effort e);
+ void propagate(Effort level);
+ Node getValue(TNode n);
+ void shutdown() { }
+ std::string identify() const { return std::string("TheoryQuantifiers"); }
+ bool flipDecision();
+private:
+ void assertUniversal( Node n );
+ void assertExistential( Node n );
+ bool restart();
+public:
+ void performCheck(Effort e);
+};/* class TheoryQuantifiers */
+
+}/* CVC4::theory::quantifiers namespace */
+}/* CVC4::theory namespace */
+}/* CVC4 namespace */
+
+#endif /* __CVC4__THEORY__QUANTIFIERS__THEORY_QUANTIFIERS_H */
diff --git a/src/theory/quantifiers/theory_quantifiers_instantiator.cpp b/src/theory/quantifiers/theory_quantifiers_instantiator.cpp
new file mode 100644
index 000000000..a5b6cc3bc
--- /dev/null
+++ b/src/theory/quantifiers/theory_quantifiers_instantiator.cpp
@@ -0,0 +1,76 @@
+/********************* */
+/*! \file theory_quantifiers_instantiator.cpp
+ ** \verbatim
+ ** Original author: ajreynol
+ ** Major contributors: none
+ ** Minor contributors (to current version): none
+ ** This file is part of the CVC4 prototype.
+ ** Copyright (c) 2009, 2010, 2011 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
+ ** information.\endverbatim
+ **
+ ** \brief Implementation of theory_quantifiers_instantiator class
+ **/
+
+#include "theory/quantifiers/theory_quantifiers_instantiator.h"
+#include "theory/quantifiers/theory_quantifiers.h"
+#include "theory/theory_engine.h"
+
+using namespace std;
+using namespace CVC4;
+using namespace CVC4::kind;
+using namespace CVC4::context;
+using namespace CVC4::theory;
+using namespace CVC4::theory::quantifiers;
+
+InstantiatorTheoryQuantifiers::InstantiatorTheoryQuantifiers(context::Context* c, QuantifiersEngine* ie, Theory* th) :
+Instantiator( c, ie, th ){
+
+}
+
+void InstantiatorTheoryQuantifiers::assertNode( Node assertion ){
+ Debug("quant-quant-assert") << "InstantiatorTheoryQuantifiers::check: " << assertion << std::endl;
+ if( Options::current()->cbqi ){
+ if( assertion.hasAttribute(InstConstantAttribute()) ){
+ Debug("quant-quant-assert") << " -> has constraints from " << assertion.getAttribute(InstConstantAttribute()) << std::endl;
+ setHasConstraintsFrom( assertion.getAttribute(InstConstantAttribute()) );
+ }else if( assertion.getKind()==NOT && assertion[0].hasAttribute(InstConstantAttribute()) ){
+ Debug("quant-quant-assert") << " -> has constraints from " << assertion[0].getAttribute(InstConstantAttribute()) << std::endl;
+ setHasConstraintsFrom( assertion[0].getAttribute(InstConstantAttribute()) );
+ }
+ }
+}
+
+void InstantiatorTheoryQuantifiers::processResetInstantiationRound( Theory::Effort effort ){
+
+}
+
+
+int InstantiatorTheoryQuantifiers::process( Node f, Theory::Effort effort, int e, int limitInst ){
+ Debug("quant-quant") << "Quant: Try to solve (" << e << ") for " << f << "... " << std::endl;
+ if( e<5 ){
+ return InstStrategy::STATUS_UNFINISHED;
+ }else if( e==5 ){
+ //add random addition
+ if( isOwnerOf( f ) ){
+ InstMatch m;
+ if( d_quantEngine->addInstantiation( f, m ) ){
+ ++(d_statistics.d_instantiations);
+ }
+ }
+ }
+ return InstStrategy::STATUS_UNKNOWN;
+}
+
+InstantiatorTheoryQuantifiers::Statistics::Statistics():
+ d_instantiations("InstantiatorTheoryQuantifiers::Instantiations_Total", 0)
+{
+ StatisticsRegistry::registerStat(&d_instantiations);
+}
+
+InstantiatorTheoryQuantifiers::Statistics::~Statistics(){
+ StatisticsRegistry::unregisterStat(&d_instantiations);
+}
+
diff --git a/src/theory/quantifiers/theory_quantifiers_instantiator.h b/src/theory/quantifiers/theory_quantifiers_instantiator.h
new file mode 100644
index 000000000..dda3bfeaa
--- /dev/null
+++ b/src/theory/quantifiers/theory_quantifiers_instantiator.h
@@ -0,0 +1,60 @@
+/********************* */
+/*! \file instantiator_quantifiers_instantiator.h
+ ** \verbatim
+ ** Original author: ajreynol
+ ** Major contributors: none
+ ** Minor contributors (to current version): none
+ ** This file is part of the CVC4 prototype.
+ ** Copyright (c) 2009, 2010, 2011 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
+ ** information.\endverbatim
+ **
+ ** \brief instantiator_quantifiers_instantiator
+ **/
+
+
+#include "cvc4_private.h"
+
+#ifndef __CVC4__INSTANTIATOR_QUANTIFIERS_H
+#define __CVC4__INSTANTIATOR_QUANTIFIERS_H
+
+#include "theory/quantifiers_engine.h"
+
+#include "util/stats.h"
+
+namespace CVC4 {
+namespace theory {
+namespace quantifiers {
+
+class InstantiatorTheoryQuantifiers : public Instantiator{
+ friend class QuantifiersEngine;
+public:
+ InstantiatorTheoryQuantifiers(context::Context* c, QuantifiersEngine* ie, Theory* th);
+ ~InstantiatorTheoryQuantifiers() {}
+
+ /** check function, assertion is asserted to theory */
+ void assertNode( Node assertion );
+ /** identify */
+ std::string identify() const { return std::string("InstantiatorTheoryQuantifiers"); }
+private:
+ /** reset instantiation */
+ void processResetInstantiationRound( Theory::Effort effort );
+ /** process at effort */
+ int process( Node f, Theory::Effort effort, int e, int limitInst );
+
+ class Statistics {
+ public:
+ IntStat d_instantiations;
+ Statistics();
+ ~Statistics();
+ };
+ Statistics d_statistics;
+};/* class InstantiatiorTheoryArith */
+
+}
+}
+}
+
+#endif \ No newline at end of file
diff --git a/src/theory/quantifiers/theory_quantifiers_type_rules.h b/src/theory/quantifiers/theory_quantifiers_type_rules.h
new file mode 100644
index 000000000..ceec36d7b
--- /dev/null
+++ b/src/theory/quantifiers/theory_quantifiers_type_rules.h
@@ -0,0 +1,113 @@
+/********************* */
+/*! \file theory_quantifiers_type_rules.h
+ ** \verbatim
+ ** Original author: ajreynol
+ ** Major contributors: none
+ ** Minor contributors (to current version): none
+ ** This file is part of the CVC4 prototype.
+ ** Copyright (c) 2009, 2010, 2011 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
+ ** information.\endverbatim
+ **
+ ** \brief Theory of quantifiers
+ **
+ ** Theory of quantifiers.
+ **/
+
+#include "cvc4_private.h"
+
+#ifndef __CVC4__THEORY__QUANTIFIERS__THEORY_QUANTIFIERS_TYPE_RULES_H
+#define __CVC4__THEORY__QUANTIFIERS__THEORY_QUANTIFIERS_TYPE_RULES_H
+
+#include "util/matcher.h"
+
+namespace CVC4 {
+namespace theory {
+namespace quantifiers {
+
+struct QuantifierForallTypeRule {
+ inline static TypeNode computeType(NodeManager* nodeManager, TNode n, bool check)
+ throw(TypeCheckingExceptionPrivate) {
+ Debug("typecheck-q") << "type check for fa " << n << std::endl;
+ Assert(n.getKind() == kind::FORALL && n.getNumChildren()>0 );
+ if( check ){
+ if( n[ 0 ].getType(check)!=nodeManager->boundVarListType() ){
+ throw TypeCheckingExceptionPrivate(n, "first argument of universal quantifier is not bound var list");
+ }
+ if( n[ 1 ].getType(check)!=nodeManager->booleanType() ){
+ throw TypeCheckingExceptionPrivate(n, "body of universal quantifier is not boolean");
+ }
+ if( n.getNumChildren()==3 && n[2].getType(check)!=nodeManager->instPatternListType() ){
+ throw TypeCheckingExceptionPrivate(n, "third argument of universal quantifier is not instantiation pattern list");
+ }
+ }
+ return nodeManager->booleanType();
+ }
+};/* struct QuantifierForallTypeRule */
+
+struct QuantifierExistsTypeRule {
+ inline static TypeNode computeType(NodeManager* nodeManager, TNode n, bool check)
+ throw(TypeCheckingExceptionPrivate) {
+ Debug("typecheck-q") << "type check for ex " << n << std::endl;
+ Assert(n.getKind() == kind::EXISTS && n.getNumChildren()>0 );
+ if( check ){
+ if( n[ 0 ].getType(check)!=nodeManager->boundVarListType() ){
+ throw TypeCheckingExceptionPrivate(n, "first argument of existential quantifier is not bound var list");
+ }
+ if( n[ 1 ].getType(check)!=nodeManager->booleanType() ){
+ throw TypeCheckingExceptionPrivate(n, "body of existential quantifier is not boolean");
+ }
+ if( n.getNumChildren()==3 && n[2].getType(check)!=nodeManager->instPatternListType() ){
+ throw TypeCheckingExceptionPrivate(n, "third argument of existential quantifier is not instantiation pattern list");
+ }
+ }
+ return nodeManager->booleanType();
+ }
+};/* struct QuantifierExistsTypeRule */
+
+struct QuantifierBoundVarListTypeRule {
+ inline static TypeNode computeType(NodeManager* nodeManager, TNode n, bool check)
+ throw(TypeCheckingExceptionPrivate) {
+ Assert(n.getKind() == kind::BOUND_VAR_LIST );
+ if( check ){
+ for( int i=0; i<(int)n.getNumChildren(); i++ ){
+ if( n[i].getKind()!=kind::VARIABLE ){
+ throw TypeCheckingExceptionPrivate(n, "argument of bound var list is not variable");
+ }
+ }
+ }
+ return nodeManager->boundVarListType();
+ }
+};/* struct QuantifierBoundVarListTypeRule */
+
+struct QuantifierInstPatternTypeRule {
+ inline static TypeNode computeType(NodeManager* nodeManager, TNode n, bool check)
+ throw(TypeCheckingExceptionPrivate) {
+ Assert(n.getKind() == kind::INST_PATTERN );
+ return nodeManager->instPatternType();
+ }
+};/* struct QuantifierInstPatternTypeRule */
+
+
+struct QuantifierInstPatternListTypeRule {
+ inline static TypeNode computeType(NodeManager* nodeManager, TNode n, bool check)
+ throw(TypeCheckingExceptionPrivate) {
+ 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 ){
+ throw TypeCheckingExceptionPrivate(n, "argument of inst pattern list is not inst pattern");
+ }
+ }
+ }
+ return nodeManager->instPatternListType();
+ }
+};/* struct QuantifierInstPatternListTypeRule */
+
+}/* CVC4::theory::quantifiers namespace */
+}/* CVC4::theory namespace */
+}/* CVC4 namespace */
+
+#endif /* __CVC4__THEORY__QUANTIFIERS__THEORY_QUANTIFIERS_TYPE_RULES_H */
diff --git a/src/theory/quantifiers_engine.cpp b/src/theory/quantifiers_engine.cpp
new file mode 100644
index 000000000..ddb085632
--- /dev/null
+++ b/src/theory/quantifiers_engine.cpp
@@ -0,0 +1,788 @@
+/********************* */
+/*! \file quantifiers_engine.cpp
+ ** \verbatim
+ ** Original author: ajreynol
+ ** Major contributors: none
+ ** Minor contributors (to current version): none
+ ** This file is part of the CVC4 prototype.
+ ** Copyright (c) 2009, 2010, 2011 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
+ ** information.\endverbatim
+ **
+ ** \brief Implementation of quantifiers engine class
+ **/
+
+#include "theory/quantifiers_engine.h"
+#include "theory/theory_engine.h"
+#include "theory/uf/theory_uf_instantiator.h"
+#include "theory/uf/theory_uf_strong_solver.h"
+#include "theory/uf/equality_engine.h"
+#include "theory/quantifiers/quantifiers_rewriter.h"
+
+using namespace std;
+using namespace CVC4;
+using namespace CVC4::kind;
+using namespace CVC4::context;
+using namespace CVC4::theory;
+
+//#define COMPUTE_RELEVANCE
+//#define REWRITE_ASSERTED_QUANTIFIERS
+
+ /** reset instantiation */
+void InstStrategy::resetInstantiationRound( Theory::Effort effort ){
+ d_no_instantiate_temp.clear();
+ d_no_instantiate_temp.insert( d_no_instantiate_temp.begin(), d_no_instantiate.begin(), d_no_instantiate.end() );
+ processResetInstantiationRound( effort );
+}
+/** do instantiation round method */
+int InstStrategy::doInstantiation( Node f, Theory::Effort effort, int e, int limitInst ){
+ if( shouldInstantiate( f ) ){
+ int origLemmas = d_quantEngine->getNumLemmasWaiting();
+ int retVal = process( f, effort, e, limitInst );
+ if( d_quantEngine->getNumLemmasWaiting()!=origLemmas ){
+ for( int i=0; i<(int)d_priority_over.size(); i++ ){
+ d_priority_over[i]->d_no_instantiate_temp.push_back( f );
+ }
+ }
+ return retVal;
+ }else{
+ return STATUS_UNKNOWN;
+ }
+}
+
+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 );
+ if( it==d_data.end() ){
+ d_data[r].addTerm2( qe, n, argIndex+1 );
+ return true;
+ }else{
+ return it->second.addTerm2( qe, n, argIndex+1 );
+ }
+ }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;
+ }
+}
+
+void TermDb::addTerm( Node n, std::vector< Node >& added, bool withinQuant ){
+ //don't add terms in quantifier bodies
+ if( !withinQuant || Options::current()->registerQuantBodyTerms ){
+ if( d_processed.find( n )==d_processed.end() ){
+ d_processed[n] = true;
+ //if this is an atomic trigger, consider adding it
+ if( Trigger::isAtomicTrigger( n ) ){
+ if( !n.hasAttribute(InstConstantAttribute()) ){
+ Debug("term-db") << "register trigger term " << n << std::endl;
+ //Notice() << "register trigger term " << n << std::endl;
+ Node op = n.getOperator();
+ d_op_map[op].push_back( n );
+ d_type_map[ n.getType() ].push_back( n );
+ added.push_back( n );
+
+ uf::InstantiatorTheoryUf* d_ith = (uf::InstantiatorTheoryUf*)d_quantEngine->getInstantiator( THEORY_UF );
+ for( int i=0; i<(int)n.getNumChildren(); i++ ){
+ addTerm( n[i], added, withinQuant );
+ if( Options::current()->efficientEMatching ){
+ if( d_parents[n[i]][op].empty() ){
+ //must add parent to equivalence class info
+ Node nir = d_ith->getRepresentative( n[i] );
+ uf::EqClassInfo* eci_nir = d_ith->getEquivalenceClassInfo( nir );
+ if( eci_nir ){
+ eci_nir->d_pfuns[ op ] = true;
+ }
+ }
+ //add to parent structure
+ if( std::find( d_parents[n[i]][op][i].begin(), d_parents[n[i]][op][i].end(), n )==d_parents[n[i]][op][i].end() ){
+ d_parents[n[i]][op][i].push_back( n );
+ }
+ }
+ }
+ if( Options::current()->efficientEMatching ){
+ //new term, add n to candidate generators
+ for( int i=0; i<(int)d_ith->d_cand_gens[op].size(); i++ ){
+ d_ith->d_cand_gens[op][i]->addCandidate( n );
+ }
+ }
+ if( Options::current()->eagerInstQuant ){
+ if( !n.hasAttribute(InstLevelAttribute()) && n.getAttribute(InstLevelAttribute())==0 ){
+ int addedLemmas = 0;
+ for( int i=0; i<(int)d_ith->d_op_triggers[op].size(); i++ ){
+ addedLemmas += d_ith->d_op_triggers[op][i]->addTerm( n );
+ }
+ //std::cout << "Terms, added lemmas: " << addedLemmas << std::endl;
+ d_quantEngine->flushLemmas( &d_quantEngine->getTheoryEngine()->getTheory( THEORY_QUANTIFIERS )->getOutputChannel() );
+ }
+ }
+ }
+ }
+ for( int i=0; i<(int)n.getNumChildren(); i++ ){
+ addTerm( n[i], added, withinQuant );
+ }
+ }
+ }
+}
+
+void TermDb::reset( Theory::Effort effort ){
+ int nonCongruentCount = 0;
+ int congruentCount = 0;
+ int alreadyCongruentCount = 0;
+ //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 ){
+ if( !it->second.empty() ){
+ if( it->second[0].getType()==NodeManager::currentNM()->booleanType() ){
+ 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];
+ if( !n.getAttribute(NoMatchAttribute()) ){
+ if( !d_func_map_trie[ it->first ].addTerm( d_quantEngine, n ) ){
+ NoMatchAttribute nma;
+ n.setAttribute(nma,true);
+ congruentCount++;
+ }else{
+ nonCongruentCount++;
+ }
+ }else{
+ congruentCount++;
+ alreadyCongruentCount++;
+ }
+ }
+ }
+ }
+ }
+ for( int i=0; i<2; i++ ){
+ Node n = NodeManager::currentNM()->mkConst( i==1 );
+ eq::EqClassIterator eqc( d_quantEngine->getEqualityQuery()->getRepresentative( n ),
+ ((uf::TheoryUF*)d_quantEngine->getTheoryEngine()->getTheory( THEORY_UF ))->getEqualityEngine() );
+ while( !eqc.isFinished() ){
+ Node en = (*eqc);
+ if( en.getKind()==APPLY_UF && !en.hasAttribute(InstConstantAttribute()) ){
+ if( !en.getAttribute(NoMatchAttribute()) ){
+ Node op = en.getOperator();
+ if( !d_pred_map_trie[i][op].addTerm( d_quantEngine, en ) ){
+ NoMatchAttribute nma;
+ en.setAttribute(nma,true);
+ congruentCount++;
+ }else{
+ nonCongruentCount++;
+ }
+ }else{
+ alreadyCongruentCount++;
+ }
+ }
+ ++eqc;
+ }
+ }
+ Debug("term-db-cong") << "TermDb: Reset" << std::endl;
+ Debug("term-db-cong") << "Congruent/Non-Congruent = ";
+ Debug("term-db-cong") << congruentCount << "(" << alreadyCongruentCount << ") / " << nonCongruentCount << std::endl;
+}
+
+
+
+QuantifiersEngine::QuantifiersEngine(context::Context* c, TheoryEngine* te):
+d_te( te ),
+d_forall_asserts( c ),
+d_active( c ){
+ d_eq_query = NULL;
+ d_term_db = new TermDb( this );
+}
+
+Instantiator* QuantifiersEngine::getInstantiator( int id ){
+ return d_te->getTheory( id )->getInstantiator();
+}
+
+void QuantifiersEngine::check( Theory::Effort e ){
+ CodeTimer codeTimer(d_time);
+
+ if( e==Theory::EFFORT_LAST_CALL ){
+ ++(d_statistics.d_instantiation_rounds_lc);
+ }else if( e==Theory::EFFORT_FULL ){
+ ++(d_statistics.d_instantiation_rounds);
+ }
+ for( int i=0; i<(int)d_modules.size(); i++ ){
+ d_modules[i]->check( e );
+ }
+ //if( e==Theory::EFFORT_FULL ){
+ // Notice() << "Done instantiation Round" << std::endl;
+ //}
+}
+
+std::vector<Node> QuantifiersEngine::createInstVariable( std::vector<Node> & vars ){
+ std::vector<Node> inst_constant;
+ inst_constant.reserve(vars.size());
+ for( std::vector<Node>::const_iterator v = vars.begin();
+ v != vars.end(); ++v ){
+ //make instantiation constants
+ Node ic = NodeManager::currentNM()->mkInstConstant( (*v).getType() );
+ inst_constant.push_back( ic );
+ };
+ return inst_constant;
+}
+
+void QuantifiersEngine::makeInstantiationConstantsFor( Node f ){
+ if( d_inst_constants.find( f )==d_inst_constants.end() ){
+ Debug("quantifiers-engine") << "Instantiation constants for " << f << " : " << std::endl;
+ for( int i=0; i<(int)f[0].getNumChildren(); i++ ){
+ d_vars[f].push_back( f[0][i] );
+ //make instantiation constants
+ Node ic = NodeManager::currentNM()->mkInstConstant( f[0][i].getType() );
+ d_inst_constants_map[ic] = f;
+ d_inst_constants[ f ].push_back( ic );
+ Debug("quantifiers-engine") << " " << ic << std::endl;
+ //set the var number attribute
+ InstVarNumAttribute ivna;
+ ic.setAttribute(ivna,i);
+ }
+ }
+}
+
+void QuantifiersEngine::registerQuantifier( Node f ){
+ if( std::find( d_quants.begin(), d_quants.end(), f )==d_quants.end() ){
+ std::vector< Node > quants;
+#ifdef REWRITE_ASSERTED_QUANTIFIERS
+ //do assertion-time rewriting of quantifier
+ Node nf = quantifiers::QuantifiersRewriter::rewriteQuant( f, false, false );
+ if( nf!=f ){
+ Debug("quantifiers-rewrite") << "*** assert-rewrite " << f << std::endl;
+ Debug("quantifiers-rewrite") << " to " << std::endl;
+ Debug("quantifiers-rewrite") << nf << std::endl;
+ //we will instead register all the rewritten quantifiers
+ if( nf.getKind()==FORALL ){
+ quants.push_back( nf );
+ }else if( nf.getKind()==AND ){
+ for( int i=0; i<(int)nf.getNumChildren(); i++ ){
+ quants.push_back( nf[i] );
+ }
+ }else{
+ //unhandled: rewrite must go to a quantifier, or conjunction of quantifiers
+ Assert( false );
+ }
+ }else{
+ quants.push_back( f );
+ }
+#else
+ quants.push_back( f );
+#endif
+ for( int q=0; q<(int)quants.size(); q++ ){
+ d_quant_rewritten[f].push_back( quants[q] );
+ d_rewritten_quant[ quants[q] ] = f;
+ ++(d_statistics.d_num_quant);
+ Assert( quants[q].getKind()==FORALL );
+ //register quantifier
+ d_quants.push_back( quants[q] );
+ //make instantiation constants for quants[q]
+ makeInstantiationConstantsFor( quants[q] );
+ //compute symbols in quants[q]
+ std::vector< Node > syms;
+ computeSymbols( quants[q][1], syms );
+ d_syms[quants[q]].insert( d_syms[quants[q]].begin(), syms.begin(), syms.end() );
+ //set initial relevance
+ int minRelevance = -1;
+ for( int i=0; i<(int)syms.size(); i++ ){
+ d_syms_quants[ syms[i] ].push_back( quants[q] );
+ int r = getRelevance( syms[i] );
+ if( r!=-1 && ( minRelevance==-1 || r<minRelevance ) ){
+ minRelevance = r;
+ }
+ }
+#ifdef COMPUTE_RELEVANCE
+ if( minRelevance!=-1 ){
+ setRelevance( quants[q], minRelevance+1 );
+ }
+#endif
+ //register with each module
+ for( int i=0; i<(int)d_modules.size(); i++ ){
+ d_modules[i]->registerQuantifier( quants[q] );
+ }
+ Node ceBody = getCounterexampleBody( quants[q] );
+ generatePhaseReqs( quants[q], ceBody );
+ //also register it with the strong solver
+ if( Options::current()->finiteModelFind ){
+ ((uf::TheoryUF*)d_te->getTheory( THEORY_UF ))->getStrongSolver()->registerQuantifier( quants[q] );
+ }
+ }
+ }
+}
+
+void QuantifiersEngine::registerPattern( std::vector<Node> & pattern) {
+ for(std::vector<Node>::iterator p = pattern.begin(); p != pattern.end(); ++p){
+ std::vector< Node > added;
+ d_term_db->addTerm(*p,added);
+ }
+}
+
+void QuantifiersEngine::assertNode( Node f ){
+ Assert( f.getKind()==FORALL );
+ for( int j=0; j<(int)d_quant_rewritten[f].size(); j++ ){
+ d_forall_asserts.push_back( d_quant_rewritten[f][j] );
+ for( int i=0; i<(int)d_modules.size(); i++ ){
+ d_modules[i]->assertNode( d_quant_rewritten[f][j] );
+ }
+ }
+}
+
+void QuantifiersEngine::propagate( Theory::Effort level ){
+ CodeTimer codeTimer(d_time);
+
+ for( int i=0; i<(int)d_modules.size(); i++ ){
+ d_modules[i]->propagate( level );
+ }
+}
+
+void QuantifiersEngine::addTermToDatabase( Node n, bool withinQuant ){
+ if( d_term_db ){
+ std::vector< Node > added;
+ d_term_db->addTerm( n, added, withinQuant );
+#ifdef COMPUTE_RELEVANCE
+ for( int i=0; i<(int)added.size(); i++ ){
+ if( !withinQuant ){
+ setRelevance( added[i].getOperator(), 0 );
+ }
+ }
+#endif
+ }else{
+ Notice() << "Warning: no term database for quantifier engine." << std::endl;
+ }
+}
+
+bool QuantifiersEngine::addLemma( Node lem ){
+ //AJR: the following check is necessary until FULL_CHECK is guarenteed after d_out->lemma(...)
+ Debug("inst-engine-debug") << "Adding lemma : " << lem << std::endl;
+ lem = Rewriter::rewrite(lem);
+ if( d_lemmas_produced.find( lem )==d_lemmas_produced.end() ){
+ //d_curr_out->lemma( lem );
+ d_lemmas_produced[ lem ] = true;
+ d_lemmas_waiting.push_back( lem );
+ Debug("inst-engine-debug") << "Added lemma : " << lem << std::endl;
+ return true;
+ }else{
+ Debug("inst-engine-debug") << "Duplicate." << std::endl;
+ return false;
+ }
+}
+
+bool QuantifiersEngine::addInstantiation( Node f, std::vector< Node >& terms )
+{
+ //Notice() << "***& Instantiate " << f << " with " << std::endl;
+ //for( int i=0; i<(int)terms.size(); i++ ){
+ // Notice() << " " << terms[i] << std::endl;
+ //}
+ Assert( f.getKind()==FORALL );
+ Assert( !f.hasAttribute(InstConstantAttribute()) );
+ Assert( d_vars[f].size()==terms.size() && d_vars[f].size()==f[0].getNumChildren() );
+ Node body = f[ 1 ].substitute( d_vars[f].begin(), d_vars[f].end(),
+ terms.begin(), terms.end() );
+ NodeBuilder<> nb(kind::OR);
+ nb << d_rewritten_quant[f].notNode() << body;
+ Node lem = nb;
+ if( addLemma( lem ) ){
+ //Notice() << " Added lemma : " << body << std::endl;
+ //Notice() << "***& Instantiate " << f << " with " << std::endl;
+ //for( int i=0; i<(int)terms.size(); i++ ){
+ // Notice() << " " << terms[i] << std::endl;
+ //}
+
+ //Notice() << "**INST" << std::endl;
+ Debug("inst") << "*** Instantiate " << f << " with " << std::endl;
+ //Notice() << "*** Instantiate " << f << " with " << std::endl;
+ uint64_t maxInstLevel = 0;
+ for( int i=0; i<(int)terms.size(); i++ ){
+ if( terms[i].hasAttribute(InstConstantAttribute()) ){
+ Debug("inst")<< "***& Bad Instantiate " << f << " with " << std::endl;
+ for( int i=0; i<(int)terms.size(); i++ ){
+ Debug("inst") << " " << terms[i] << std::endl;
+ }
+ Unreachable("Bad instantiation");
+ }else{
+ Debug("inst") << " " << terms[i];
+ //Notice() << " " << terms[i] << std::endl;
+ //Debug("inst-engine") << " " << terms[i].getAttribute(InstLevelAttribute());
+ Debug("inst") << std::endl;
+ if( terms[i].hasAttribute(InstLevelAttribute()) ){
+ if( terms[i].getAttribute(InstLevelAttribute())>maxInstLevel ){
+ maxInstLevel = terms[i].getAttribute(InstLevelAttribute());
+ }
+ }else{
+ setInstantiationLevelAttr( terms[i], 0 );
+ }
+ }
+ }
+ setInstantiationLevelAttr( body, maxInstLevel+1 );
+ ++(d_statistics.d_instantiations);
+ d_statistics.d_total_inst_var += (int)terms.size();
+ d_statistics.d_max_instantiation_level.maxAssign( maxInstLevel+1 );
+ return true;
+ }else{
+ ++(d_statistics.d_inst_duplicate);
+ return false;
+ }
+}
+
+bool QuantifiersEngine::addInstantiation( Node f, InstMatch& m, bool addSplits ){
+ m.makeComplete( f, this );
+ m.makeRepresentative( this );
+ Debug("quant-duplicate") << "After make rep: " << m << std::endl;
+ if( !d_inst_match_trie[f].addInstMatch( this, f, m, true ) ){
+ Debug("quant-duplicate") << " -> Already exists." << std::endl;
+ ++(d_statistics.d_inst_duplicate);
+ return false;
+ }
+ Debug("quant-duplicate") << " -> Does not exist." << std::endl;
+ std::vector< Node > match;
+ m.computeTermVec( d_inst_constants[f], match );
+
+ //old....
+ //m.makeRepresentative( d_eq_query );
+ //std::vector< Node > match;
+ //m.computeTermVec( this, d_inst_constants[f], match );
+
+ //Notice() << "*** Instantiate " << m->getQuantifier() << " with " << std::endl;
+ //for( int i=0; i<(int)m->d_match.size(); i++ ){
+ // Notice() << " " << m->d_match[i] << std::endl;
+ //}
+
+ if( addInstantiation( f, match ) ){
+ //d_statistics.d_total_inst_var_unspec.setData( d_statistics.d_total_inst_var_unspec.getData() + (int)d_inst_constants[f].size() - m.d_map.size()/2 );
+ //if( d_inst_constants[f].size()!=m.d_map.size() ){
+ // //Notice() << "Unspec. " << std::endl;
+ // //Notice() << "*** Instantiate " << m->getQuantifier() << " with " << std::endl;
+ // //for( int i=0; i<(int)m->d_match.size(); i++ ){
+ // // Notice() << " " << m->d_match[i] << std::endl;
+ // //}
+ // ++(d_statistics.d_inst_unspec);
+ //}
+ //if( addSplits ){
+ // for( std::map< Node, Node >::iterator it = m->d_splits.begin(); it != m->d_splits.end(); ++it ){
+ // addSplitEquality( it->first, it->second, true, true );
+ // }
+ //}
+ return true;
+ }
+ return false;
+}
+
+bool QuantifiersEngine::addSplit( Node n, bool reqPhase, bool reqPhasePol ){
+ n = Rewriter::rewrite( n );
+ Node lem = NodeManager::currentNM()->mkNode( OR, n, n.notNode() );
+ if( addLemma( lem ) ){
+ ++(d_statistics.d_splits);
+ Debug("inst") << "*** Add split " << n<< std::endl;
+ //if( reqPhase ){
+ // d_curr_out->requirePhase( n, reqPhasePol );
+ //}
+ return true;
+ }
+ return false;
+}
+
+bool QuantifiersEngine::addSplitEquality( Node n1, Node n2, bool reqPhase, bool reqPhasePol ){
+ //Assert( !n1.hasAttribute(InstConstantAttribute()) );
+ //Assert( !n2.hasAttribute(InstConstantAttribute()) );
+ //Assert( !areEqual( n1, n2 ) );
+ //Assert( !areDisequal( n1, n2 ) );
+ Kind knd = n1.getType()==NodeManager::currentNM()->booleanType() ? IFF : EQUAL;
+ Node fm = NodeManager::currentNM()->mkNode( knd, n1, n2 );
+ return addSplit( fm );
+}
+
+void QuantifiersEngine::flushLemmas( OutputChannel* out ){
+ for( int i=0; i<(int)d_lemmas_waiting.size(); i++ ){
+ out->lemma( d_lemmas_waiting[i] );
+ }
+ d_lemmas_waiting.clear();
+}
+
+Node QuantifiersEngine::getCounterexampleBody( Node f ){
+ std::map< Node, Node >::iterator it = d_counterexample_body.find( f );
+ if( it==d_counterexample_body.end() ){
+ makeInstantiationConstantsFor( f );
+ Node n = getSubstitutedNode( f[1], f );
+ d_counterexample_body[ f ] = n;
+ return n;
+ }else{
+ return it->second;
+ }
+}
+
+Node QuantifiersEngine::getSkolemizedBody( Node f ){
+ Assert( f.getKind()==FORALL );
+ if( d_skolem_body.find( f )==d_skolem_body.end() ){
+ std::vector< Node > vars;
+ for( int i=0; i<(int)f[0].getNumChildren(); i++ ){
+ Node skv = NodeManager::currentNM()->mkSkolem( f[0][i].getType() );
+ d_skolem_constants[ f ].push_back( skv );
+ vars.push_back( f[0][i] );
+ }
+ d_skolem_body[ f ] = f[ 1 ].substitute( vars.begin(), vars.end(),
+ d_skolem_constants[ f ].begin(), d_skolem_constants[ f ].end() );
+ if( f.hasAttribute(InstLevelAttribute()) ){
+ setInstantiationLevelAttr( d_skolem_body[ f ], f.getAttribute(InstLevelAttribute()) );
+ }
+ }
+ return d_skolem_body[ f ];
+}
+
+void QuantifiersEngine::getPhaseReqTerms( Node f, std::vector< Node >& nodes ){
+ if( Options::current()->literalMatchMode!=Options::LITERAL_MATCH_NONE ){
+ bool printed = false;
+ // doing literal-based matching (consider polarity of literals)
+ for( int i=0; i<(int)nodes.size(); i++ ){
+ Node prev = nodes[i];
+ bool nodeChanged = false;
+ if( isPhaseReq( f, nodes[i] ) ){
+ bool preq = getPhaseReq( f, nodes[i] );
+ nodes[i] = NodeManager::currentNM()->mkNode( IFF, nodes[i], NodeManager::currentNM()->mkConst<bool>(preq) );
+ nodeChanged = true;
+ }
+ //else if( qe->isPhaseReqEquality( f, trNodes[i] ) ){
+ // Node req = qe->getPhaseReqEquality( f, trNodes[i] );
+ // trNodes[i] = NodeManager::currentNM()->mkNode( EQUAL, trNodes[i], req );
+ //}
+ if( nodeChanged ){
+ if( !printed ){
+ Debug("literal-matching") << "LitMatch for " << f << ":" << std::endl;
+ printed = true;
+ }
+ Debug("literal-matching") << " Make " << prev << " -> " << nodes[i] << std::endl;
+ Assert( prev.hasAttribute(InstConstantAttribute()) );
+ setInstantiationConstantAttr( nodes[i], prev.getAttribute(InstConstantAttribute()) );
+ ++(d_statistics.d_lit_phase_req);
+ }else{
+ ++(d_statistics.d_lit_phase_nreq);
+ }
+ }
+ }else{
+ d_statistics.d_lit_phase_nreq += (int)nodes.size();
+ }
+}
+
+void QuantifiersEngine::computePhaseReqs2( Node n, bool polarity, std::map< Node, int >& phaseReqs ){
+ bool newReqPol = false;
+ bool newPolarity;
+ if( n.getKind()==NOT ){
+ newReqPol = true;
+ newPolarity = !polarity;
+ }else if( n.getKind()==OR || n.getKind()==IMPLIES ){
+ if( !polarity ){
+ newReqPol = true;
+ newPolarity = false;
+ }
+ }else if( n.getKind()==AND ){
+ if( polarity ){
+ newReqPol = true;
+ newPolarity = true;
+ }
+ }else{
+ int val = polarity ? 1 : -1;
+ if( phaseReqs.find( n )==phaseReqs.end() ){
+ phaseReqs[n] = val;
+ }else if( val!=phaseReqs[n] ){
+ phaseReqs[n] = 0;
+ }
+ }
+ if( newReqPol ){
+ for( int i=0; i<(int)n.getNumChildren(); i++ ){
+ if( n.getKind()==IMPLIES && i==0 ){
+ computePhaseReqs2( n[i], !newPolarity, phaseReqs );
+ }else{
+ computePhaseReqs2( n[i], newPolarity, phaseReqs );
+ }
+ }
+ }
+}
+
+void QuantifiersEngine::computePhaseReqs( Node n, bool polarity, std::map< Node, bool >& phaseReqs ){
+ std::map< Node, int > phaseReqs2;
+ computePhaseReqs2( n, polarity, phaseReqs2 );
+ for( std::map< Node, int >::iterator it = phaseReqs2.begin(); it != phaseReqs2.end(); ++it ){
+ if( it->second==1 ){
+ phaseReqs[ it->first ] = true;
+ }else if( it->second==-1 ){
+ phaseReqs[ it->first ] = false;
+ }
+ }
+}
+
+void QuantifiersEngine::generatePhaseReqs( Node f, Node n ){
+ computePhaseReqs( n, false, d_phase_reqs[f] );
+ Debug("inst-engine-phase-req") << "Phase requirements for " << f << ":" << std::endl;
+ //now, compute if any patterns are equality required
+ for( std::map< Node, bool >::iterator it = d_phase_reqs[f].begin(); it != d_phase_reqs[f].end(); ++it ){
+ Debug("inst-engine-phase-req") << " " << it->first << " -> " << it->second << std::endl;
+ if( it->first.getKind()==EQUAL ){
+ if( it->first[0].hasAttribute(InstConstantAttribute()) ){
+ if( !it->first[1].hasAttribute(InstConstantAttribute()) ){
+ d_phase_reqs_equality_term[f][ it->first[0] ] = it->first[1];
+ d_phase_reqs_equality[f][ it->first[0] ] = it->second;
+ Debug("inst-engine-phase-req") << " " << it->first[0] << ( it->second ? " == " : " != " ) << it->first[1] << std::endl;
+ }
+ }else if( it->first[1].hasAttribute(InstConstantAttribute()) ){
+ d_phase_reqs_equality_term[f][ it->first[1] ] = it->first[0];
+ d_phase_reqs_equality[f][ it->first[1] ] = it->second;
+ Debug("inst-engine-phase-req") << " " << it->first[1] << ( it->second ? " == " : " != " ) << it->first[0] << std::endl;
+ }
+ }
+ }
+
+}
+
+Node QuantifiersEngine::getSubstitutedNode( Node n, Node f ){
+ return convertNodeToPattern(n,f,d_vars[f],d_inst_constants[ f ]);
+}
+
+Node QuantifiersEngine::convertNodeToPattern( Node n, Node f, const std::vector<Node> & vars,
+ const std::vector<Node> & inst_constants){
+ Node n2 = n.substitute( vars.begin(), vars.end(),
+ inst_constants.begin(),
+ inst_constants.end() );
+ setInstantiationConstantAttr( n2, f );
+ return n2;
+}
+
+
+void QuantifiersEngine::setInstantiationLevelAttr( Node n, uint64_t level ){
+ if( !n.hasAttribute(InstLevelAttribute()) ){
+ InstLevelAttribute ila;
+ n.setAttribute(ila,level);
+ }
+ for( int i=0; i<(int)n.getNumChildren(); i++ ){
+ setInstantiationLevelAttr( n[i], level );
+ }
+}
+
+
+void QuantifiersEngine::setInstantiationConstantAttr( Node n, Node f ){
+ if( !n.hasAttribute(InstConstantAttribute()) ){
+ bool setAttr = false;
+ if( n.getKind()==INST_CONSTANT ){
+ setAttr = true;
+ }else{
+ for( int i=0; i<(int)n.getNumChildren(); i++ ){
+ setInstantiationConstantAttr( n[i], f );
+ if( n[i].hasAttribute(InstConstantAttribute()) ){
+ setAttr = true;
+ }
+ }
+ }
+ if( setAttr ){
+ InstConstantAttribute ica;
+ n.setAttribute(ica,f);
+ //also set the no-match attribute
+ NoMatchAttribute nma;
+ n.setAttribute(nma,true);
+ }
+ }
+}
+
+QuantifiersEngine::Statistics::Statistics():
+ d_num_quant("QuantifiersEngine::Num_Quantifiers", 0),
+ d_instantiation_rounds("QuantifiersEngine::Rounds_Instantiation_Full", 0),
+ d_instantiation_rounds_lc("QuantifiersEngine::Rounds_Instantiation_Last_Call", 0),
+ d_instantiations("QuantifiersEngine::Instantiations_Total", 0),
+ d_max_instantiation_level("QuantifiersEngine::Max_Instantiation_Level", 0),
+ d_splits("QuantifiersEngine::Total_Splits", 0),
+ d_total_inst_var("QuantifiersEngine::Vars_Inst", 0),
+ d_total_inst_var_unspec("QuantifiersEngine::Vars_Inst_Unspecified", 0),
+ d_inst_unspec("QuantifiersEngine::Unspecified_Inst", 0),
+ d_inst_duplicate("QuantifiersEngine::Duplicate_Inst", 0),
+ d_lit_phase_req("QuantifiersEngine::lit_phase_req", 0),
+ d_lit_phase_nreq("QuantifiersEngine::lit_phase_nreq", 0),
+ d_triggers("QuantifiersEngine::Triggers", 0),
+ d_simple_triggers("QuantifiersEngine::Triggers_Simple", 0),
+ d_multi_triggers("QuantifiersEngine::Triggers_Multi", 0),
+ d_multi_trigger_instantiations("QuantifiersEngine::Multi_Trigger_Instantiations", 0)
+{
+ StatisticsRegistry::registerStat(&d_num_quant);
+ StatisticsRegistry::registerStat(&d_instantiation_rounds);
+ StatisticsRegistry::registerStat(&d_instantiation_rounds_lc);
+ StatisticsRegistry::registerStat(&d_instantiations);
+ StatisticsRegistry::registerStat(&d_max_instantiation_level);
+ StatisticsRegistry::registerStat(&d_splits);
+ StatisticsRegistry::registerStat(&d_total_inst_var);
+ StatisticsRegistry::registerStat(&d_total_inst_var_unspec);
+ StatisticsRegistry::registerStat(&d_inst_unspec);
+ StatisticsRegistry::registerStat(&d_inst_duplicate);
+ StatisticsRegistry::registerStat(&d_lit_phase_req);
+ StatisticsRegistry::registerStat(&d_lit_phase_nreq);
+ StatisticsRegistry::registerStat(&d_triggers);
+ StatisticsRegistry::registerStat(&d_simple_triggers);
+ StatisticsRegistry::registerStat(&d_multi_triggers);
+ StatisticsRegistry::registerStat(&d_multi_trigger_instantiations);
+}
+
+QuantifiersEngine::Statistics::~Statistics(){
+ StatisticsRegistry::unregisterStat(&d_num_quant);
+ StatisticsRegistry::unregisterStat(&d_instantiation_rounds);
+ StatisticsRegistry::unregisterStat(&d_instantiation_rounds_lc);
+ StatisticsRegistry::unregisterStat(&d_instantiations);
+ StatisticsRegistry::unregisterStat(&d_max_instantiation_level);
+ StatisticsRegistry::unregisterStat(&d_splits);
+ StatisticsRegistry::unregisterStat(&d_total_inst_var);
+ StatisticsRegistry::unregisterStat(&d_total_inst_var_unspec);
+ StatisticsRegistry::unregisterStat(&d_inst_unspec);
+ StatisticsRegistry::unregisterStat(&d_inst_duplicate);
+ StatisticsRegistry::unregisterStat(&d_lit_phase_req);
+ StatisticsRegistry::unregisterStat(&d_lit_phase_nreq);
+ StatisticsRegistry::unregisterStat(&d_triggers);
+ StatisticsRegistry::unregisterStat(&d_simple_triggers);
+ StatisticsRegistry::unregisterStat(&d_multi_triggers);
+ StatisticsRegistry::unregisterStat(&d_multi_trigger_instantiations);
+}
+
+Node QuantifiersEngine::getFreeVariableForInstConstant( Node n ){
+ TypeNode tn = n.getType();
+ if( d_free_vars.find( tn )==d_free_vars.end() ){
+ //if integer or real, make zero
+ if( tn==NodeManager::currentNM()->integerType() || tn==NodeManager::currentNM()->realType() ){
+ Rational z(0);
+ d_free_vars[tn] = NodeManager::currentNM()->mkConst( z );
+ }else{
+ if( d_term_db->d_type_map[ tn ].empty() ){
+ d_free_vars[tn] = NodeManager::currentNM()->mkVar( tn );
+ }else{
+ d_free_vars[tn] =d_term_db->d_type_map[ tn ][ 0 ];
+ }
+ }
+ }
+ return d_free_vars[tn];
+}
+
+/** compute symbols */
+void QuantifiersEngine::computeSymbols( Node n, std::vector< Node >& syms ){
+ if( n.getKind()==APPLY_UF ){
+ Node op = n.getOperator();
+ if( std::find( syms.begin(), syms.end(), op )==syms.end() ){
+ syms.push_back( op );
+ }
+ }
+ if( n.getKind()!=FORALL ){
+ for( int i=0; i<(int)n.getNumChildren(); i++ ){
+ computeSymbols( n[i], syms );
+ }
+ }
+}
+
+/** set relevance */
+void QuantifiersEngine::setRelevance( Node s, int r ){
+ int rOld = getRelevance( s );
+ if( rOld==-1 || r<rOld ){
+ d_relevance[s] = r;
+ if( s.getKind()==FORALL ){
+ for( int i=0; i<(int)d_syms[s].size(); i++ ){
+ setRelevance( d_syms[s][i], r );
+ }
+ }else{
+ for( int i=0; i<(int)d_syms_quants[s].size(); i++ ){
+ setRelevance( d_syms_quants[s][i], r+1 );
+ }
+ }
+ }
+}
diff --git a/src/theory/quantifiers_engine.h b/src/theory/quantifiers_engine.h
new file mode 100644
index 000000000..d0c5fb00b
--- /dev/null
+++ b/src/theory/quantifiers_engine.h
@@ -0,0 +1,388 @@
+/********************* */
+/*! \file quantifiers_engine.h
+ ** \verbatim
+ ** Original author: ajreynol
+ ** Major contributors: none
+ ** Minor contributors (to current version): none
+ ** This file is part of the CVC4 prototype.
+ ** Copyright (c) 2009, 2010, 2011 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
+ ** information.\endverbatim
+ **
+ ** \brief Theory instantiator, Instantiation Engine classes
+ **/
+
+#include "cvc4_private.h"
+
+#ifndef __CVC4__THEORY__QUANTIFIERS_ENGINE_H
+#define __CVC4__THEORY__QUANTIFIERS_ENGINE_H
+
+#include "theory/theory.h"
+#include "util/hash.h"
+#include "theory/trigger.h"
+
+#include "util/stats.h"
+
+#include <ext/hash_set>
+#include <iostream>
+#include <map>
+
+namespace CVC4 {
+
+class TheoryEngine;
+
+// attribute for "contains instantiation constants from"
+struct InstConstantAttributeId {};
+typedef expr::Attribute<InstConstantAttributeId, Node> InstConstantAttribute;
+
+struct InstLevelAttributeId {};
+typedef expr::Attribute<InstLevelAttributeId, uint64_t> InstLevelAttribute;
+
+struct InstVarNumAttributeId {};
+typedef expr::Attribute<InstVarNumAttributeId, uint64_t> InstVarNumAttribute;
+
+namespace theory {
+
+class QuantifiersEngine;
+
+class InstStrategy {
+public:
+ enum Status {
+ STATUS_UNFINISHED,
+ STATUS_UNKNOWN,
+ STATUS_SAT,
+ };/* enum Status */
+protected:
+ /** reference to the instantiation engine */
+ QuantifiersEngine* d_quantEngine;
+protected:
+ /** giving priorities */
+ std::vector< InstStrategy* > d_priority_over;
+ /** do not instantiate list */
+ std::vector< Node > d_no_instantiate;
+ std::vector< Node > d_no_instantiate_temp;
+ /** reset instantiation */
+ virtual void processResetInstantiationRound( Theory::Effort effort ) = 0;
+ /** process method */
+ virtual int process( Node f, Theory::Effort effort, int e, int limitInst = 0 ) = 0;
+public:
+ InstStrategy( QuantifiersEngine* ie ) : d_quantEngine( ie ){}
+ virtual ~InstStrategy(){}
+
+ /** reset instantiation */
+ void resetInstantiationRound( Theory::Effort effort );
+ /** do instantiation round method */
+ int doInstantiation( Node f, Theory::Effort effort, int e, int limitInst = 0 );
+ /** update status */
+ static void updateStatus( int& currStatus, int addStatus ){
+ if( addStatus==STATUS_UNFINISHED ){
+ currStatus = STATUS_UNFINISHED;
+ }else if( addStatus==STATUS_UNKNOWN ){
+ if( currStatus==STATUS_SAT ){
+ currStatus = STATUS_UNKNOWN;
+ }
+ }
+ }
+ /** identify */
+ virtual std::string identify() const { return std::string("Unknown"); }
+public:
+ /** set priority */
+ void setPriorityOver( InstStrategy* is ) { d_priority_over.push_back( is ); }
+ /** set no instantiate */
+ void setNoInstantiate( Node n ) { d_no_instantiate.push_back( n ); }
+ /** should instantiate */
+ bool shouldInstantiate( Node n ) {
+ return std::find( d_no_instantiate_temp.begin(), d_no_instantiate_temp.end(), n )==d_no_instantiate_temp.end();
+ }
+};/* class InstStrategy */
+
+class QuantifiersModule {
+public:
+ QuantifiersModule(){}
+ ~QuantifiersModule(){}
+ /* Call during check registerQuantifier has already been called */
+ virtual void check( Theory::Effort e ) = 0;
+ /* Called for new quantifiers */
+ virtual void registerQuantifier( Node n ) = 0;
+ virtual void assertNode( Node n ) = 0;
+ virtual void propagate( Theory::Effort level ) = 0;
+ virtual Node explain(TNode n) = 0;
+};/* class QuantifiersModule */
+
+class TermArgTrie {
+private:
+ bool addTerm2( QuantifiersEngine* qe, Node n, int argIndex );
+public:
+ /** the data */
+ std::map< Node, TermArgTrie > d_data;
+public:
+ bool addTerm( QuantifiersEngine* qe, Node n ) { return addTerm2( qe, n, 0 ); }
+};/* class TermArgTrie */
+
+class TermDb {
+private:
+ /** reference to the quantifiers engine */
+ QuantifiersEngine* d_quantEngine;
+ /** calculated no match terms */
+ bool d_matching_active;
+ /** terms processed */
+ std::map< Node, bool > d_processed;
+public:
+ TermDb( QuantifiersEngine* qe ) : d_quantEngine( qe ), d_matching_active( true ){}
+ ~TermDb(){}
+ /** map from APPLY_UF operators to ground terms for that operator */
+ std::map< Node, std::vector< Node > > d_op_map;
+ /** map from APPLY_UF functions to trie */
+ std::map< Node, TermArgTrie > d_func_map_trie;
+ /** map from APPLY_UF predicates to trie */
+ std::map< Node, TermArgTrie > d_pred_map_trie[2];
+ /** 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::vector< Node >& added, bool withinQuant = false );
+ /** reset (calculate which terms are active) */
+ void reset( Theory::Effort effort );
+ /** set active */
+ void setMatchingActive( bool a ) { d_matching_active = a; }
+ /** get active */
+ bool getMatchingActive() { return d_matching_active; }
+public:
+ /** parent structure (for efficient E-matching):
+ n -> op -> index -> L
+ map from node "n" to a list of nodes "L", where each node n' in L
+ has operator "op", and n'["index"] = n.
+ for example, d_parents[n][f][1] = { f( t1, n ), f( t2, n ), ... }
+ */
+ std::map< Node, std::map< Node, std::map< int, std::vector< Node > > > > d_parents;
+};/* class TermDb */
+
+namespace quantifiers {
+ class InstantiationEngine;
+}/* CVC4::theory::quantifiers */
+
+class QuantifiersEngine {
+ friend class quantifiers::InstantiationEngine;
+ friend class InstMatch;
+private:
+ typedef context::CDHashMap< Node, bool, NodeHashFunction > BoolMap;
+ /** reference to theory engine object */
+ TheoryEngine* d_te;
+ /** vector of modules for quantifiers */
+ std::vector< QuantifiersModule* > d_modules;
+ /** equality query class */
+ EqualityQuery* d_eq_query;
+
+ /** list of all quantifiers */
+ std::vector< Node > d_quants;
+ /** list of quantifiers asserted in the current context */
+ context::CDList<Node> d_forall_asserts;
+ /** map from universal quantifiers to the list of variables */
+ std::map< Node, std::vector< Node > > d_vars;
+ /** map from universal quantifiers to the list of skolem constants */
+ std::map< Node, std::vector< Node > > d_skolem_constants;
+ /** map from universal quantifiers to their skolemized body */
+ std::map< Node, Node > d_skolem_body;
+ /** map from universal quantifiers to their bound body */
+ std::map< Node, Node > d_bound_body;
+ /** instantiation constants to universal quantifiers */
+ std::map< Node, Node > d_inst_constants_map;
+ /** map from universal quantifiers to their counterexample body */
+ std::map< Node, Node > d_counterexample_body;
+ /** map from universal quantifiers to the list of instantiation constants */
+ std::map< Node, std::vector< Node > > d_inst_constants;
+ /** map from quantifiers to whether they are active */
+ BoolMap d_active;
+ /** lemmas produced */
+ std::map< Node, bool > d_lemmas_produced;
+ /** lemmas waiting */
+ std::vector< Node > d_lemmas_waiting;
+ /** inst matches produced for each quantifier */
+ std::map< Node, InstMatchTrie > d_inst_match_trie;
+ /** free variable for instantiation constant type */
+ std::map< TypeNode, Node > d_free_vars;
+ /** owner of quantifiers */
+ std::map< Node, Theory* > d_owner;
+ /** term database */
+ TermDb* d_term_db;
+ /** universal quantifiers that have been rewritten */
+ std::map< Node, std::vector< Node > > d_quant_rewritten;
+ /** map from rewritten universal quantifiers to the quantifier they are the consequence of */
+ std::map< Node, Node > d_rewritten_quant;
+private:
+ /** for computing relavance */
+ /** map from quantifiers to symbols they contain */
+ std::map< Node, std::vector< Node > > d_syms;
+ /** map from symbols to quantifiers */
+ std::map< Node, std::vector< Node > > d_syms_quants;
+ /** relevance for quantifiers and symbols */
+ std::map< Node, int > d_relevance;
+ /** compute symbols */
+ void computeSymbols( Node n, std::vector< Node >& syms );
+private:
+ /** helper functions compute phase requirements */
+ static void computePhaseReqs2( Node n, bool polarity, std::map< Node, int >& phaseReqs );
+ /** set instantiation level attr */
+ void setInstantiationLevelAttr( Node n, uint64_t level );
+ /** set instantiation constant attr */
+ void setInstantiationConstantAttr( Node n, Node f );
+ /** make instantiation constants for */
+ void makeInstantiationConstantsFor( Node f );
+
+ KEEP_STATISTIC(TimerStat, d_time, "theory::QuantifiersEngine::time");
+
+public:
+ QuantifiersEngine(context::Context* c, TheoryEngine* te);
+ ~QuantifiersEngine(){}
+ /** get instantiator for id */
+ Instantiator* getInstantiator( int id );
+ /** get theory engine */
+ TheoryEngine* getTheoryEngine() { return d_te; }
+ /** get equality query object */
+ EqualityQuery* getEqualityQuery() { return d_eq_query; }
+ /** set equality query object */
+ void setEqualityQuery( EqualityQuery* eq ) { d_eq_query = eq; }
+public:
+ /** add module */
+ void addModule( QuantifiersModule* qm ) { d_modules.push_back( qm ); }
+ /** check at level */
+ void check( Theory::Effort e );
+ /** register (non-rewritten) quantifier */
+ void registerQuantifier( Node f );
+ /** register (non-rewritten) quantifier */
+ void registerPattern( std::vector<Node> & pattern);
+ /** assert (universal) quantifier */
+ void assertNode( Node f );
+ /** propagate */
+ void propagate( Theory::Effort level );
+public:
+ /** add lemma lem */
+ bool addLemma( Node lem );
+ /** instantiate f with arguments terms */
+ bool addInstantiation( Node f, std::vector< Node >& terms );
+ /** do instantiation specified by m */
+ bool addInstantiation( Node f, InstMatch& m, bool addSplits = false );
+ /** split on node n */
+ bool addSplit( Node n, bool reqPhase = false, bool reqPhasePol = true );
+ /** add split equality */
+ bool addSplitEquality( Node n1, Node n2, bool reqPhase = false, bool reqPhasePol = true );
+ /** has added lemma */
+ bool hasAddedLemma() { return !d_lemmas_waiting.empty(); }
+ /** flush lemmas */
+ void flushLemmas( OutputChannel* out );
+ /** get number of waiting lemmas */
+ int getNumLemmasWaiting() { return (int)d_lemmas_waiting.size(); }
+public:
+ /** get number of quantifiers */
+ int getNumQuantifiers() { return (int)d_quants.size(); }
+ /** get quantifier */
+ Node getQuantifier( int i ) { return d_quants[i]; }
+ /** get number of asserted quantifiers */
+ int getNumAssertedQuantifiers() { return (int)d_forall_asserts.size(); }
+ /** get asserted quantifier */
+ Node getAssertedQuantifier( int i ) { return d_forall_asserts[i]; }
+ /** get instantiation constants */
+ void getInstantiationConstantsFor( Node f, std::vector< Node >& ics ) {
+ ics.insert( ics.begin(), d_inst_constants[f].begin(), d_inst_constants[f].end() );
+ }
+ /** get the i^th instantiation constant of f */
+ Node getInstantiationConstant( Node f, int i ) { return d_inst_constants[f][i]; }
+ /** get number of instantiation constants for f */
+ int getNumInstantiationConstants( Node f ) { return (int)d_inst_constants[f].size(); }
+ std::vector<Node> createInstVariable( std::vector<Node> & vars );
+public:
+ /** get the ce body f[e/x] */
+ Node getCounterexampleBody( Node f );
+ /** get the skolemized body f[e/x] */
+ Node getSkolemizedBody( Node f );
+ /** set active */
+ void setActive( Node n, bool val ) { d_active[n] = val; }
+ /** get active */
+ bool getActive( Node n ) { return d_active.find( n )!=d_active.end() && d_active[n]; }
+public:
+ /** phase requirements for each quantifier for each instantiation literal */
+ std::map< Node, std::map< Node, bool > > d_phase_reqs;
+ std::map< Node, std::map< Node, bool > > d_phase_reqs_equality;
+ std::map< Node, std::map< Node, Node > > d_phase_reqs_equality_term;
+public:
+ /** is phase required */
+ bool isPhaseReq( Node f, Node lit ) { return d_phase_reqs[f].find( lit )!=d_phase_reqs[f].end(); }
+ /** get phase requirement */
+ bool getPhaseReq( Node f, Node lit ) { return d_phase_reqs[f].find( lit )==d_phase_reqs[f].end() ? false : d_phase_reqs[f][ lit ]; }
+ /** get term req terms */
+ void getPhaseReqTerms( Node f, std::vector< Node >& nodes );
+ /** helper functions compute phase requirements */
+ static void computePhaseReqs( Node n, bool polarity, std::map< Node, bool >& phaseReqs );
+ /** compute phase requirements */
+ void generatePhaseReqs( Node f, Node n );
+public:
+ /** returns node n with bound vars of f replaced by instantiation constants of f
+ node n : is the futur pattern
+ node f : is the quantifier containing which bind the variable
+ return a pattern where the variable are replaced by variable for
+ instantiation.
+ */
+ Node getSubstitutedNode( Node n, Node f );
+ /** same as before but node f is just linked to the new pattern by the
+ applied attribute
+ vars the bind variable
+ nvars the same variable but with an attribute
+ */
+ Node convertNodeToPattern( Node n, Node f,
+ const std::vector<Node> & vars,
+ const std::vector<Node> & nvars);
+ /** get free variable for instantiation constant */
+ Node getFreeVariableForInstConstant( Node n );
+ /** get bound variable for variable */
+ Node getBoundVariableForVariable( Node n );
+public:
+ /** has owner */
+ bool hasOwner( Node f ) { return d_owner.find( f )!=d_owner.end(); }
+ /** get owner */
+ Theory* getOwner( Node f ) { return d_owner[f]; }
+ /** set owner */
+ void setOwner( Node f, Theory* t ) { d_owner[f] = t; }
+public:
+ /** get term database */
+ TermDb* getTermDatabase() { return d_term_db; }
+ /** add term to database */
+ void addTermToDatabase( Node n, bool withinQuant = false );
+private:
+ /** set relevance */
+ void setRelevance( Node s, int r );
+public:
+ /** get relevance */
+ int getRelevance( Node s ) { return d_relevance.find( s )==d_relevance.end() ? -1 : d_relevance[s]; }
+ /** get number of quantifiers for symbol s */
+ int getNumQuantifiersForSymbol( Node s ) { return (int)d_syms_quants[s].size(); }
+public:
+ /** statistics class */
+ class Statistics {
+ public:
+ IntStat d_num_quant;
+ IntStat d_instantiation_rounds;
+ IntStat d_instantiation_rounds_lc;
+ IntStat d_instantiations;
+ IntStat d_max_instantiation_level;
+ IntStat d_splits;
+ IntStat d_total_inst_var;
+ IntStat d_total_inst_var_unspec;
+ IntStat d_inst_unspec;
+ IntStat d_inst_duplicate;
+ IntStat d_lit_phase_req;
+ IntStat d_lit_phase_nreq;
+ IntStat d_triggers;
+ IntStat d_simple_triggers;
+ IntStat d_multi_triggers;
+ IntStat d_multi_trigger_instantiations;
+ Statistics();
+ ~Statistics();
+ };/* class QuantifiersEngine::Statistics */
+ Statistics d_statistics;
+};/* class QuantifiersEngine */
+
+}/* CVC4::theory namespace */
+}/* CVC4 namespace */
+
+#endif /* __CVC4__THEORY__QUANTIFIERS_ENGINE_H */
diff --git a/src/theory/rewriterules/Makefile b/src/theory/rewriterules/Makefile
new file mode 100644
index 000000000..4b1d4fc55
--- /dev/null
+++ b/src/theory/rewriterules/Makefile
@@ -0,0 +1,4 @@
+topdir = ../../..
+srcdir = src/theory/rewriterules
+
+include $(topdir)/Makefile.subdir
diff --git a/src/theory/rewriterules/Makefile.am b/src/theory/rewriterules/Makefile.am
new file mode 100644
index 000000000..46cffda11
--- /dev/null
+++ b/src/theory/rewriterules/Makefile.am
@@ -0,0 +1,19 @@
+AM_CPPFLAGS = \
+ -D__BUILDING_CVC4LIB \
+ -I@srcdir@/../../include -I@srcdir@/../.. -I@builddir@/../..
+AM_CXXFLAGS = -Wall -Wno-unknown-pragmas $(FLAG_VISIBILITY_HIDDEN)
+
+noinst_LTLIBRARIES = librewriterules.la
+
+librewriterules_la_SOURCES = \
+ theory_rewriterules_rules.h \
+ theory_rewriterules_rules.cpp \
+ theory_rewriterules.h \
+ theory_rewriterules.cpp \
+ theory_rewriterules_rewriter.h \
+ theory_rewriterules_type_rules.h \
+ theory_rewriterules_preprocess.h \
+ theory_rewriterules_params.h
+
+EXTRA_DIST = \
+ kinds
diff --git a/src/theory/rewriterules/README.WHATS-NEXT b/src/theory/rewriterules/README.WHATS-NEXT
new file mode 100644
index 000000000..eda7dcbe6
--- /dev/null
+++ b/src/theory/rewriterules/README.WHATS-NEXT
@@ -0,0 +1,29 @@
+Congratulations, you now have a new theory of rewriterules !
+
+Your next steps will likely be:
+
+* to specify theory constants, types, and operators in your \`kinds' file
+* to add typing rules to theory_${dir}_type_rules.h for your operators
+ and constants
+* to write code in theory_${dir}_rewriter.h to implement a normal form
+ for your theory's terms
+* to write parser rules in src/parser/cvc/Cvc.g to support the CVC input
+ language, src/parser/smt/Smt.g to support the (deprecated) SMT-LIBv1
+ language, and src/parser/smt2/Smt2.g to support SMT-LIBv2
+* to write printer code in src/printer/*/*_printer* to support printing
+ your theory terms and types in various output languages
+
+and finally:
+
+* to implement a decision procedure for your theory by implementing
+ TheoryRewriterules::check() in theory_rewriterules.cpp. Before writing the actual
+ code, you will need :
+
+ * to determine which datastructures are context dependent and use for them
+ context dependent datastructures (context/cd*.h)
+ * to choose which work will be done at QUICK_CHECK, STANDARD or at
+ FULL_EFFORT.
+
+
+Good luck, and please contact cvc4-devel@cs.nyu.edu for assistance
+should you need it!
diff --git a/src/theory/rewriterules/kinds b/src/theory/rewriterules/kinds
new file mode 100644
index 000000000..01fbda51e
--- /dev/null
+++ b/src/theory/rewriterules/kinds
@@ -0,0 +1,37 @@
+# kinds -*- sh -*-
+#
+# For documentation on this file format, please refer to
+# src/theory/builtin/kinds.
+#
+
+theory THEORY_REWRITERULES ::CVC4::theory::rewriterules::TheoryRewriteRules "theory/rewriterules/theory_rewriterules.h"
+typechecker "theory/rewriterules/theory_rewriterules_type_rules.h"
+rewriter ::CVC4::theory::rewriterules::TheoryRewriterulesRewriter "theory/rewriterules/theory_rewriterules_rewriter.h"
+
+properties check
+
+# Theory content goes here.
+
+# constants...
+
+# types...
+sort RRHB_TYPE \
+ Cardinality::INTEGERS \
+ not-well-founded \
+ "head and body of the rule type"
+
+# operators...
+
+# variables, guards, RR_REWRITE/REDUCTION_RULE/DEDUCTION_RULE
+operator REWRITE_RULE 3 "generale rewrite rule"
+#HEAD/BODY/TRIGGER
+operator RR_REWRITE 2:3 "actual rewrite rule"
+operator RR_REDUCTION 2:3 "actual reduction rule"
+operator RR_DEDUCTION 2:3 "actual deduction rule"
+
+typerule REWRITE_RULE ::CVC4::theory::rewriterules::RewriteRuleTypeRule
+typerule RR_REWRITE ::CVC4::theory::rewriterules::RRRewriteTypeRule
+typerule RR_REDUCTION ::CVC4::theory::rewriterules::RRRedDedTypeRule
+typerule RR_DEDUCTION ::CVC4::theory::rewriterules::RRRedDedTypeRule
+
+endtheory
diff --git a/src/theory/rewriterules/theory_rewriterules.cpp b/src/theory/rewriterules/theory_rewriterules.cpp
new file mode 100644
index 000000000..0072a36e9
--- /dev/null
+++ b/src/theory/rewriterules/theory_rewriterules.cpp
@@ -0,0 +1,519 @@
+/********************* */
+/*! \file rewrite_engine.cpp
+ ** \verbatim
+ ** Original author: ajreynolds
+ ** Major contributors: bobot
+ ** Minor contributors (to current version): none
+ ** This file is part of the CVC4 prototype.
+ ** Copyright (c) 2009, 2010, 2011
+ ** 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
+ ** information.\endverbatim
+ **
+ ** \brief [[ Deals with rewrite rules ]]
+ **
+ ** [[ Add lengthier description here ]]
+ ** \todo document this file
+ **/
+
+#include "theory/rewriterules/theory_rewriterules.h"
+#include "theory/rewriterules/theory_rewriterules_rules.h"
+#include "theory/rewriterules/theory_rewriterules_params.h"
+
+#include "theory/rewriterules/theory_rewriterules_preprocess.h"
+#include "theory/rewriter.h"
+
+using namespace std;
+using namespace CVC4;
+using namespace CVC4::kind;
+using namespace CVC4::context;
+using namespace CVC4::theory;
+using namespace CVC4::theory::rewriterules;
+
+
+namespace CVC4 {
+namespace theory {
+namespace rewriterules {
+
+
+inline std::ostream& operator <<(std::ostream& stream, const RuleInst& ri) {
+ ri.toStream(stream);
+ return stream;
+}
+
+static const RuleInst* RULEINST_TRUE = (RuleInst*) 1;
+static const RuleInst* RULEINST_FALSE = (RuleInst*) 2;
+
+ /** Rule an instantiation with the given match */
+RuleInst::RuleInst(TheoryRewriteRules & re, const RewriteRule * r,
+ std::vector<Node> & inst_subst,
+ Node matched):
+ rule(r), d_matched(matched)
+{
+ Assert(r != NULL);
+ Assert(!r->directrr || !d_matched.isNull());
+ subst.swap(inst_subst);
+};
+
+Node RuleInst::substNode(const TheoryRewriteRules & re, TNode r,
+ TCache cache ) const {
+ Assert(this != RULEINST_TRUE && this != RULEINST_FALSE);
+ return r.substitute (rule->free_vars.begin(),rule->free_vars.end(),
+ subst.begin(),subst.end(),cache);
+};
+size_t RuleInst::findGuard(TheoryRewriteRules & re, size_t start)const{
+ TCache cache;
+ Assert(this != RULEINST_TRUE && this != RULEINST_FALSE);
+ while (start < (rule->guards).size()){
+ Node g = substNode(re,rule->guards[start],cache);
+ switch(re.addWatchIfDontKnow(g,this,start)){
+ case ATRUE:
+ Debug("rewriterules") << g << "is true" << std::endl;
+ ++start;
+ continue;
+ case AFALSE:
+ Debug("rewriterules") << g << "is false" << std::endl;
+ return -1;
+ case ADONTKNOW:
+ Debug("rewriterules") << g << "is unknown" << std::endl;
+ return start;
+ }
+ }
+ /** All the guards are verified */
+ re.propagateRule(this,cache);
+ return start;
+};
+
+bool RuleInst::alreadyRewritten(TheoryRewriteRules & re) const{
+ Assert(this != RULEINST_TRUE && this != RULEINST_FALSE);
+ static NoMatchAttribute rewrittenNodeAttribute;
+ TCache cache;
+ for(std::vector<Node>::const_iterator
+ iter = rule->to_remove.begin();
+ iter != rule->to_remove.end(); ++iter){
+ if (substNode(re,*iter,cache).getAttribute(rewrittenNodeAttribute))
+ return true;
+ };
+ return false;
+}
+
+void RuleInst::toStream(std::ostream& out) const{
+ if(this == RULEINST_TRUE){ out << "TRUE"; return;};
+ if(this == RULEINST_FALSE){ out << "FALSE"; return;};
+ out << "(" << *rule << ") ";
+ for(std::vector<Node>::const_iterator
+ iter = subst.begin(); iter != subst.end(); ++iter){
+ out << *iter << " ";
+ };
+}
+
+
+void Guarded::nextGuard(TheoryRewriteRules & re)const{
+ Assert(inst != RULEINST_TRUE && inst != RULEINST_FALSE);
+ if(simulateRewritting && inst->alreadyRewritten(re)) return;
+ inst->findGuard(re,d_guard+1);
+};
+
+/** start indicate the first guard which is not true */
+Guarded::Guarded(const RuleInst* ri, const size_t start) :
+ d_guard(start),inst(ri) {};
+Guarded::Guarded(const Guarded & g) :
+ d_guard(g.d_guard),inst(g.inst) {};
+Guarded::Guarded() :
+ //dumb value
+ d_guard(-1),inst(RULEINST_TRUE) {};
+
+TheoryRewriteRules::TheoryRewriteRules(context::Context* c,
+ context::UserContext* u,
+ OutputChannel& out,
+ Valuation valuation,
+ const LogicInfo& logicInfo,
+ QuantifiersEngine* qe) :
+ Theory(THEORY_REWRITERULES, c, u, out, valuation, logicInfo, qe),
+ d_rules(c), d_ruleinsts(c), d_guardeds(c), d_checkLevel(c,0),
+ d_explanations(c), d_ruleinsts_to_add()
+ {
+ d_true = NodeManager::currentNM()->mkConst<bool>(true);
+ d_false = NodeManager::currentNM()->mkConst<bool>(false);
+ Debug("rewriterules") << Node::setdepth(-1);
+ Debug("rewriterules-rewrite") << Node::setdepth(-1);
+}
+
+void TheoryRewriteRules::addMatchRuleTrigger(const RewriteRule * r,
+ InstMatch & im,
+ bool delay){
+ ++r->nb_matched;
+ if(rewrite_instantiation) im.applyRewrite();
+ if(representative_instantiation)
+ im.makeRepresentative( getQuantifiersEngine() );
+
+ if(!cache_match || !r->inCache(*this,im)){
+ ++r->nb_applied;
+ std::vector<Node> subst;
+ im.computeTermVec(getQuantifiersEngine(), r->inst_vars , subst);
+ RuleInst * ri = new RuleInst(*this,r,subst,
+ r->directrr ? im.d_matched : Node::null());
+ Debug("rewriterules") << "One matching found"
+ << (delay? "(delayed)":"")
+ << ":" << *ri << std::endl;
+ // Find the first non verified guard, don't save the rule if the
+ // rule can already be fired In fact I save it otherwise strange
+ // things append.
+ Assert(ri->rule != NULL);
+ if(delay) d_ruleinsts_to_add.push_back(ri);
+ else{
+ if(simulateRewritting && ri->alreadyRewritten(*this)) return;
+ if(ri->findGuard(*this, 0) != (r->guards).size())
+ d_ruleinsts.push_back(ri);
+ else delete(ri);
+ };
+ };
+}
+
+void TheoryRewriteRules::check(Effort level) {
+ CodeTimer codeTimer(d_theoryTime);
+
+ Assert(d_ruleinsts_to_add.empty());
+
+ while(!done()) {
+ // Get all the assertions
+ // TODO: Test that it have already been ppAsserted
+ get();
+ // Assertion assertion = get();
+ // TNode fact = assertion.assertion;
+
+ // Debug("rewriterules") << "TheoryRewriteRules::check(): processing " << fact << std::endl;
+ // if (getValuation().getDecisionLevel()>0)
+ // Unhandled(getValuation().getDecisionLevel());
+ // addRewriteRule(fact);
+
+ };
+
+ Debug("rewriterules") << "Check:" << d_checkLevel << (level==EFFORT_FULL? " EFFORT_FULL":"") << std::endl;
+
+ /** Test each rewrite rule */
+ for(size_t rid = 0, end = d_rules.size(); rid < end; ++rid) {
+ RewriteRule * r = d_rules[rid];
+ if (level!=EFFORT_FULL && r->d_split) continue;
+ Debug("rewriterules") << " rule: " << r << std::endl;
+ Trigger & tr = r->trigger;
+ //reset instantiation round for trigger (set up match production)
+ tr.resetInstantiationRound();
+ //begin iterating from the first match produced by the trigger
+ tr.reset( Node::null() );
+
+ /** Test the possible matching one by one */
+ InstMatch im;
+ while(tr.getNextMatch( im )){
+ addMatchRuleTrigger(r, im, true);
+ im.clear();
+ }
+ }
+
+ const bool do_notification = d_checkLevel == 0 || level==EFFORT_FULL;
+ bool polldone = false;
+
+ GuardedMap::const_iterator p = d_guardeds.begin();
+ do{
+
+
+ //dequeue instantiated rules
+ for(; !d_ruleinsts_to_add.empty();){
+ RuleInst * ri = d_ruleinsts_to_add.back(); d_ruleinsts_to_add.pop_back();
+ if(simulateRewritting && ri->alreadyRewritten(*this)) break;
+ if(ri->findGuard(*this, 0) != ri->rule->guards.size())
+ d_ruleinsts.push_back(ri);
+ else delete(ri);
+ };
+
+ if(do_notification)
+ /** Temporary way. Poll value */
+ for (; p != d_guardeds.end(); ++p){
+ TNode g = (*p).first;
+ const GList * const l = (*p).second;
+ const Guarded & glast = l->back();
+ // Notice() << "Polled?:" << g << std::endl;
+ if(glast.inst == RULEINST_TRUE||glast.inst == RULEINST_FALSE) continue;
+ // Notice() << "Polled!:" << g << "->" << (glast.inst == RULEINST_TRUE||glast.inst == RULEINST_FALSE) << std::endl;
+ bool value;
+ if(getValuation().hasSatValue(g,value)){
+ if(value) polldone = true; //One guard is true so pass n check
+ Debug("rewriterules") << "Poll value:" << g
+ << " is " << (value ? "true" : "false") << std::endl;
+ notification(g,value);
+ //const Guarded & glast2 = (*l)[l->size()-1];
+ // Notice() << "Polled!!:" << g << "->" << (glast2.inst == RULEINST_TRUE||glast2.inst == RULEINST_FALSE) << std::endl;
+ };
+ };
+
+ }while(!d_ruleinsts_to_add.empty() ||
+ (p != d_guardeds.end() && do_notification));
+
+ if(polldone) d_checkLevel = checkSlowdown;
+ else d_checkLevel = d_checkLevel > 0 ? (d_checkLevel - 1) : 0;
+
+ /** Narrowing by splitting on the guards */
+ /** Perhaps only when no notification? */
+ if(narrowing_full_effort && level==EFFORT_FULL){
+ for (GuardedMap::const_iterator p = d_guardeds.begin();
+ p != d_guardeds.end(); ++p){
+ TNode g = (*p).first;
+ const GList * const l = (*p).second;
+ const Guarded & glast = (*l)[l->size()-1];
+ if(glast.inst == RULEINST_TRUE||glast.inst == RULEINST_FALSE)
+ continue;
+ // If it has a value it should already has been notified
+ bool value; value = value; // avoiding the warning in non debug mode
+ Assert(!getValuation().hasSatValue(g,value));
+ Debug("rewriterules") << "Narrowing on:" << g << std::endl;
+ /** Can split on already rewritten instrule... but... */
+ getOutputChannel().split(g);
+ }
+ }
+
+ Assert(d_ruleinsts_to_add.empty());
+ Debug("rewriterules") << "Check done:" << d_checkLevel << std::endl;
+
+};
+
+void TheoryRewriteRules::registerQuantifier( Node n ){};
+
+Trigger TheoryRewriteRules::createTrigger( TNode n, std::vector<Node> & pattern ) {
+ // Debug("rewriterules") << "createTrigger:";
+ getQuantifiersEngine()->registerPattern(pattern);
+ return *Trigger::mkTrigger(getQuantifiersEngine(),n,pattern,
+ match_gen_kind, true);
+};
+
+bool TheoryRewriteRules::notifyIfKnown(const GList * const ltested,
+ GList * const lpropa) {
+ Assert(ltested->size() > 0);
+ const Guarded & glast = (*ltested)[ltested->size()-1];
+ if(glast.inst == RULEINST_TRUE || glast.inst == RULEINST_FALSE){
+ notification(lpropa,glast.inst == RULEINST_TRUE);
+ return true;
+ };
+ return false;
+};
+
+void TheoryRewriteRules::notification(GList * const lpropa, bool b){
+ if (b){
+ for(GList::const_iterator g = lpropa->begin();
+ g != lpropa->end(); ++g) {
+ (*g).nextGuard(*this);
+ };
+ lpropa->push_back(Guarded(RULEINST_TRUE,0));
+ }else{
+ lpropa->push_back(Guarded(RULEINST_FALSE,0));
+ };
+ Assert(lpropa->back().inst == RULEINST_TRUE ||
+ lpropa->back().inst == RULEINST_FALSE);
+};
+
+
+
+Answer TheoryRewriteRules::addWatchIfDontKnow(Node g0, const RuleInst* ri,
+ const size_t gid){
+ /** TODO: Should use the representative of g, but should I keep the
+ mapping for myself? */
+ /* If it false in one model (current valuation) it's false for all */
+ if (useCurrentModel){
+ Node val = getValuation().getValue(g0);
+ Debug("rewriterules") << "getValue:" << g0 << " = "
+ << val << " is " << (val == d_false) << std::endl;
+ if (val == d_false) return AFALSE;
+ };
+ /** Currently create a node with a literal */
+ Node g = getValuation().ensureLiteral(g0);
+ GuardedMap::iterator l_i = d_guardeds.find(g);
+ GList* l;
+ if( l_i == d_guardeds.end() ) {
+ /** Normally Not watched so IDONTNOW but since we poll, we can poll now */
+ bool value;
+ if(getValuation().hasSatValue(g,value)){
+ if(value) return ATRUE;
+ else return AFALSE;
+ };
+ //Not watched so IDONTNOW
+ l = new(getSatContext()->getCMM())
+ GList(true, getSatContext());//,
+ //ContextMemoryAllocator<Guarded>(getContext()->getCMM()));
+ d_guardeds.insert(g ,l);//.insertDataFromContextMemory(g, l);
+ /* TODO Add register propagation */
+ } else {
+ l = (*l_i).second;
+ Assert(l->size() > 0);
+ const Guarded & glast = (*l)[l->size()-1];
+ if(glast.inst == RULEINST_TRUE) return ATRUE;
+ if(glast.inst == RULEINST_FALSE) return AFALSE;
+
+ };
+ /** I DONT KNOW because not watched or because not true nor false */
+ l->push_back(Guarded(ri,gid));
+ return ADONTKNOW;
+};
+
+void TheoryRewriteRules::notification(Node g, bool b){
+ GuardedMap::const_iterator l = d_guardeds.find(g);
+ /** Should be a propagated node already known */
+ Assert(l != d_guardeds.end());
+ notification((*l).second,b);
+}
+
+
+void TheoryRewriteRules::notifyEq(TNode lhs, TNode rhs) {
+ GuardedMap::const_iterator ilhs = d_guardeds.find(lhs);
+ GuardedMap::const_iterator irhs = d_guardeds.find(rhs);
+ /** Should be a propagated node already known */
+ Assert(ilhs != d_guardeds.end());
+ if( irhs == d_guardeds.end() ) {
+ /** Not watched so points to the list directly */
+ d_guardeds.insertDataFromContextMemory(rhs, (*ilhs).second);
+ } else {
+ GList * const llhs = (*ilhs).second;
+ GList * const lrhs = (*irhs).second;
+ if(!(notifyIfKnown(llhs,lrhs) || notifyIfKnown(lrhs,llhs))){
+ /** If none of the two is known */
+ for(GList::const_iterator g = llhs->begin(); g != llhs->end(); ++g){
+ lrhs->push_back(*g);
+ };
+ };
+ };
+};
+
+
+void TheoryRewriteRules::propagateRule(const RuleInst * inst, TCache cache){
+ // Debug("rewriterules") << "A rewrite rules is verified. Add lemma:";
+ Debug("rewriterules") << "propagateRule" << *inst << std::endl;
+ const RewriteRule * rule = inst->rule;
+ ++rule->nb_applied;
+ // Can be more something else than an equality in fact (eg. propagation rule)
+ Node equality = inst->substNode(*this,rule->body,cache);
+ if(propagate_as_lemma){
+ Node lemma = equality;
+ if(rule->guards.size() > 0){
+ // TODO: problem with reduction rule => instead of <=>
+ lemma = substGuards(inst, cache).impNode(equality);
+ };
+ if(rule->directrr){
+ TypeNode booleanType = NodeManager::currentNM()->booleanType();
+ // if the rule is directly applied by the rewriter,
+ // we should take care to use the representative that can't be directly rewritable:
+ // If "car(a)" is somewhere and we know that "a = cons(x,l)" we shouldn't
+ // add the constraint car(cons(x,l) = x because it is rewritten to x = x.
+ // But we should say cons(a) = x
+ Assert(lemma.getKind() == kind::EQUAL ||
+ lemma.getKind() == kind::IMPLIES);
+ Assert(!inst->d_matched.isNull());
+ Assert( inst->d_matched.getOperator() == lemma[0].getOperator() );
+ // replace the left hand side by the term really matched
+ Debug("rewriterules-directrr") << "lemma:" << lemma << " :: " << inst->d_matched;
+ Node hyp;
+ NodeBuilder<2> nb;
+ if(inst->d_matched.getNumChildren() == 1){
+ nb.clear( inst->d_matched[0].getType(false) == booleanType ?
+ kind::IFF : kind::EQUAL );
+ nb << inst->d_matched[0] << lemma[0][0];
+ hyp = nb;
+ }else{
+ NodeBuilder<> andb(kind::AND);
+ for(size_t i = 0,
+ iend = inst->d_matched.getNumChildren(); i < iend; ++i){
+ nb.clear( inst->d_matched[i].getType(false) == booleanType ?
+ kind::IFF : kind::EQUAL );
+ nb << inst->d_matched[i] << lemma[0][i];
+ andb << static_cast<Node>(nb);
+ }
+ hyp = andb;
+ };
+ nb.clear(lemma.getKind());
+ nb << inst->d_matched << lemma[1];
+ lemma = hyp.impNode(static_cast<Node>(nb));
+ Debug("rewriterules-directrr") << " -> " << lemma << std::endl;
+ };
+ // Debug("rewriterules") << "lemma:" << lemma << std::endl;
+ getOutputChannel().lemma(lemma);
+ }else{
+ Assert(!direct_rewrite);
+ Node lemma_lit = getValuation().ensureLiteral(equality);
+ ExplanationMap::const_iterator p = d_explanations.find(lemma_lit);
+ if(p!=d_explanations.end()) return; //Already propagated
+ bool value;
+ if(getValuation().hasSatValue(lemma_lit,value)){
+ /* Already assigned */
+ if (!value){
+ Node conflict = substGuards(inst,cache,lemma_lit);
+ getOutputChannel().conflict(conflict);
+ };
+ }else{
+ getOutputChannel().propagate(lemma_lit);
+ d_explanations.insert(lemma_lit, *inst);
+ };
+ };
+
+ if(simulateRewritting){
+ static NoMatchAttribute rewrittenNodeAttribute;
+ // Tag the rewritted terms
+ for(std::vector<Node>::iterator i = rule->to_remove.begin();
+ i == rule->to_remove.end(); ++i){
+ (*i).setAttribute(rewrittenNodeAttribute,true);
+ };
+ };
+
+ //Verify that this instantiation can't immediately fire another rule
+ for(RewriteRule::BodyMatch::const_iterator p = rule->body_match.begin();
+ p != rule->body_match.end(); ++p){
+ RewriteRule * r = (*p).second;
+ // Debug("rewriterules") << " rule: " << r << std::endl;
+ // Use trigger2 since we can be in check
+ Trigger & tr = r->trigger_for_body_match;
+ InstMatch im;
+ TNode m = inst->substNode(*this,(*p).first, cache);
+ tr.getMatch(m,im);
+ if(!im.empty()){
+ im.d_matched = m;
+ addMatchRuleTrigger(r, im);
+ }
+ }
+};
+
+
+Node TheoryRewriteRules::substGuards(const RuleInst *inst,
+ TCache cache,
+ /* Already substituted */
+ Node last){
+ const RewriteRule * r = inst->rule;
+ /** No guards */
+ const size_t size = r->guards.size();
+ if(size == 0) return (last.isNull()?d_true:last);
+ /** One guard */
+ if(size == 1 && last.isNull()) return inst->substNode(*this,r->guards[0],cache);
+ /** Guards */ /* TODO remove the duplicate with a set like in uf? */
+ NodeBuilder<> conjunction(kind::AND);
+ for(std::vector<Node>::const_iterator p = r->guards.begin();
+ p != r->guards.end(); ++p) {
+ Assert(!p->isNull());
+ conjunction << inst->substNode(*this,*p,cache);
+ };
+ if (!last.isNull()) conjunction << last;
+ return conjunction;
+}
+
+Node TheoryRewriteRules::explain(TNode n){
+ ExplanationMap::const_iterator p = d_explanations.find(n);
+ Assert(p!=d_explanations.end(),"I forget the explanation...");
+ RuleInst i = (*p).second;
+ //Notice() << n << "<-" << *(i.rule) << std::endl;
+ return substGuards(&i, TCache ());
+}
+
+Theory::PPAssertStatus TheoryRewriteRules::ppAssert(TNode in, SubstitutionMap& outSubstitutions) {
+ addRewriteRule(in);
+ return PP_ASSERT_STATUS_UNSOLVED;
+}
+
+}/* CVC4::theory::rewriterules namespace */
+}/* CVC4::theory namespace */
+}/* CVC4 namespace */
diff --git a/src/theory/rewriterules/theory_rewriterules.h b/src/theory/rewriterules/theory_rewriterules.h
new file mode 100644
index 000000000..499535687
--- /dev/null
+++ b/src/theory/rewriterules/theory_rewriterules.h
@@ -0,0 +1,264 @@
+/********************* */
+/*! \file rewrite_engine.h
+ ** \verbatim
+ ** Original author: ajreynol
+ ** Major contributors: bobot
+ ** Minor contributors (to current version): none
+ ** This file is part of the CVC4 prototype.
+ ** Copyright (c) 2009, 2010, 2011
+ ** 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
+ ** information.\endverbatim
+ **
+ ** \brief Rewrite Engine classes
+ **/
+
+
+#include "cvc4_private.h"
+
+#ifndef __CVC4__THEORY__REWRITERULES__THEORY_REWRITERULES_H
+#define __CVC4__THEORY__REWRITERULES__THEORY_REWRITERULES_H
+
+#include "context/cdlist.h"
+#include "context/cdqueue.h"
+#include "theory/valuation.h"
+#include "theory/theory.h"
+#include "theory/theory_engine.h"
+#include "theory/quantifiers_engine.h"
+#include "context/context_mm.h"
+#include "theory/inst_match_impl.h"
+#include "util/stats.h"
+#include "theory/rewriterules/theory_rewriterules_preprocess.h"
+
+namespace CVC4 {
+namespace theory {
+namespace rewriterules {
+
+typedef std::hash_map<TNode, TNode, TNodeHashFunction> TCache;
+
+ enum Answer {ATRUE, AFALSE, ADONTKNOW};
+
+ class TheoryRewriteRules; /** forward */
+
+ class RewriteRule{
+ public:
+ // constant
+ const bool d_split;
+ mutable Trigger trigger;
+ std::vector<Node> guards;
+ mutable std::vector<Node> to_remove; /** terms to remove */
+ const Node body;
+ const TNode new_terms; /** new terms included in the body */
+ std::vector<Node> free_vars; /* free variable in the rule */
+ std::vector<Node> inst_vars; /* corresponding vars in the triggers */
+ /* After instantiating the body new match can appear (TNode
+ because is a subterm of a body on the assicaited rewrite
+ rule) */
+ typedef context::CDList< std::pair<TNode,RewriteRule* > > BodyMatch;
+ mutable BodyMatch body_match;
+ mutable Trigger trigger_for_body_match; // used because we can be matching
+ // trigger when we need new match.
+ // So currently we use another
+ // trigger for that.
+
+ //context dependent
+ typedef InstMatchTrie2<true> CacheNode;
+ mutable CacheNode d_cache;
+
+ const bool directrr;
+
+ RewriteRule(TheoryRewriteRules & re,
+ Trigger & tr, Trigger & tr2,
+ std::vector<Node> & g, Node b, TNode nt,
+ std::vector<Node> & fv,std::vector<Node> & iv,
+ std::vector<Node> & to_r, bool drr);
+ RewriteRule(const RewriteRule & r) CVC4_UNUSED;
+ RewriteRule& operator=(const RewriteRule &) CVC4_UNUSED;
+ ~RewriteRule();
+
+ bool noGuard()const throw () { return guards.size() == 0; };
+ bool inCache(TheoryRewriteRules & re, InstMatch & im)const;
+
+ void toStream(std::ostream& out) const;
+
+ /* statistics */
+ mutable size_t nb_matched;
+ mutable size_t nb_applied;
+ mutable size_t nb_propagated;
+
+ };
+
+ class RuleInst{
+ public:
+ /** The rule has at least one guard */
+ const RewriteRule* rule;
+
+ /** the substitution */
+ std::vector<Node> subst;
+
+ /** the term matched (not null if mono-pattern and direct-rr) */
+ Node d_matched;
+
+ /** Rule an instantiation with the given match */
+ RuleInst(TheoryRewriteRules & re, const RewriteRule* r,
+ std::vector<Node> & inst_subst,
+ Node matched);
+ RuleInst():rule(NULL){} // Dumb
+
+ Node substNode(const TheoryRewriteRules & re, TNode r, TCache cache) const;
+ size_t findGuard(TheoryRewriteRules & re, size_t start)const;
+
+ void toStream(std::ostream& out) const;
+
+ bool alreadyRewritten(TheoryRewriteRules & re) const;
+ };
+
+/** A pair? */
+ class Guarded {
+ public:
+ /** The backtracking is done somewhere else */
+ const size_t d_guard; /* the id of the guard */
+
+ /** The shared instantiation data */
+ const RuleInst* inst;
+
+ void nextGuard(TheoryRewriteRules & re)const;
+
+ /** start indicate the first guard which is not true */
+ Guarded(const RuleInst* ri, const size_t start);
+ Guarded(const Guarded & g);
+ /** Should be ssigned by a good garded after */
+ Guarded();
+
+ ~Guarded(){};
+ void destroy(){};
+ };
+
+template<class T>
+class CleanUpPointer{
+public:
+ inline void operator()(T** e){
+ delete(*e);
+ };
+};
+
+class TheoryRewriteRules : public Theory {
+private:
+
+ KEEP_STATISTIC(TimerStat, d_theoryTime, "theory::rewriterules::theoryTime");
+
+ /** list of all rewrite rules */
+ /* std::vector< Node > d_rules; */
+ // typedef std::vector< std::pair<Node, Trigger > > Rules;
+ typedef context::CDList< RewriteRule *,
+ CleanUpPointer<RewriteRule >,
+ std::allocator< RewriteRule * > > Rules;
+ Rules d_rules;
+ typedef context::CDList< RuleInst *,
+ CleanUpPointer<RuleInst>,
+ std::allocator< RuleInst * > > RuleInsts;
+ RuleInsts d_ruleinsts;
+
+ /** The GList* will lead too memory leaks since that doesn't use
+ CDChunckList */
+ typedef context::CDList< Guarded > GList;
+ typedef context::CDHashMap<Node, GList *, NodeHashFunction> GuardedMap;
+ GuardedMap d_guardeds;
+
+ /* In order to not monopolize, the system slow down himself: If a
+ guard stored in d_guardeds become true or false, it waits
+ checkSlowdown(=10) checks before checking again if some guard take a
+ value. At FULL_EFFORT regardless of d_checkLevel it check the
+ guards
+ */
+ context::CDO<size_t> d_checkLevel;
+
+ /** explanation */
+ typedef context::CDHashMap<Node, RuleInst , NodeHashFunction> ExplanationMap;
+ ExplanationMap d_explanations;
+
+ /** new instantiation must be cleared at each conflict used only
+ inside check */
+ typedef std::vector< RuleInst* > QRuleInsts;
+ QRuleInsts d_ruleinsts_to_add;
+ public:
+ /** true and false for predicate */
+ Node d_true;
+ Node d_false;
+
+ /** Constructs a new instance of TheoryRewriteRules
+ w.r.t. the provided context.*/
+ TheoryRewriteRules(context::Context* c,
+ context::UserContext* u,
+ OutputChannel& out,
+ Valuation valuation,
+ const LogicInfo& logicInfo,
+ QuantifiersEngine* qe);
+
+ /** Usual function for theories */
+ void check(Theory::Effort e);
+ Node explain(TNode n);
+ void notifyEq(TNode lhs, TNode rhs);
+ std::string identify() const {
+ return "THEORY_REWRITERULES";
+ }
+
+ Theory::PPAssertStatus ppAssert(TNode in, SubstitutionMap& outSubstitutions);
+
+ bool ppDontRewriteSubterm(TNode atom){ return true; }
+
+
+ private:
+ void registerQuantifier( Node n );
+
+ public:
+ /* TODO modify when notification will be available */
+ void notification( Node n, bool b);
+
+ Trigger createTrigger( TNode n, std::vector<Node> & pattern );
+
+ /** return if the guard (already substituted) is known true or false
+ or unknown. In the last case it add the Guarded(rid,gid) to the watch
+ list of this guard */
+ Answer addWatchIfDontKnow(Node g, const RuleInst* r, const size_t gid);
+
+ /** An instantiation of a rule is fired (all guards true) we
+ propagate the body. That can be done by theory propagation if
+ possible or by lemmas.
+ */
+ void propagateRule(const RuleInst * r, TCache cache);
+
+ /** Auxillary functions */
+private:
+ /** A guard is verify, notify the Guarded */
+ void notification(GList * const lpropa, bool b);
+ /* If two guards becomes equals we should notify if one of them is
+ already true */
+ bool notifyIfKnown(const GList * const ltested, GList * const lpropa);
+
+ Node substGuards(const RuleInst * inst,
+ TCache cache,
+ Node last = Node::null());
+
+ void addRewriteRule(const Node r);
+ void computeMatchBody ( const RewriteRule * r, size_t start = 0);
+ void addMatchRuleTrigger(const RewriteRule* r,
+ InstMatch & im, bool delay = true);
+
+ /* rewrite pattern */
+ typedef std::hash_map< Node, rewriter::RRPpRewrite*, NodeHashFunction > RegisterRRPpRewrite;
+ RegisterRRPpRewrite d_registeredRRPpRewrite;
+
+ bool addRewritePattern(TNode pattern, TNode body,
+ rewriter::Subst & pvars,
+ rewriter::Subst & vars);
+
+};/* class TheoryRewriteRules */
+
+}/* CVC4::theory::rewriterules namespace */
+}/* CVC4::theory namespace */
+}/* CVC4 namespace */
+
+#endif /* __CVC4__THEORY__REWRITERULES__THEORY_REWRITERULES_H */
diff --git a/src/theory/rewriterules/theory_rewriterules_params.h b/src/theory/rewriterules/theory_rewriterules_params.h
new file mode 100644
index 000000000..ecb5385f9
--- /dev/null
+++ b/src/theory/rewriterules/theory_rewriterules_params.h
@@ -0,0 +1,95 @@
+/********************* */
+/*! \file rewrite_engine.cpp
+ ** \verbatim
+ ** Original author: bobot
+ ** Major contributors: none
+ ** Minor contributors (to current version): none
+ ** This file is part of the CVC4 prototype.
+ ** Copyright (c) 2009, 2010, 2011
+ ** 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
+ ** information.\endverbatim
+ **
+ ** \brief Parameters for the rewrite rules theory
+ **
+ ** [[ Add lengthier description here ]]
+ ** \todo document this file
+ **/
+
+
+#ifndef __CVC4__THEORY__REWRITERULES__THEORY_REWRITERULES_PARAMS_H
+#define __CVC4__THEORY__REWRITERULES__THEORY_REWRITERULES_PARAMS_H
+
+namespace CVC4 {
+namespace theory {
+namespace rewriterules {
+
+/**
+ Specify if the propagation is done by lemma or by real theory propagation
+ */
+static const bool propagate_as_lemma = true;
+
+/**
+ Cache the instantiation of rules in order to remove duplicate
+ */
+static const bool cache_match = true;
+
+/**
+ Compute when the rules are created which terms in the body can lead
+ to new instantiation (try only single trigger). During propagation
+ we check if the instantiation of these terms are known terms.
+ */
+static const bool compute_opt = true;
+
+/**
+ rewrite the matching found
+ */
+static const bool rewrite_instantiation = true;
+
+/**
+ use the representative for the matching found
+ */
+static const bool representative_instantiation = false;
+
+/**
+ Wait the specified number of check after a new propagation (a
+ previous unknown guards becomes true) is found before verifying again the guards.
+
+ Allow to break loop with other theories.
+ */
+static const size_t checkSlowdown = 10;
+
+/**
+ Use the current model to eliminate guard before asking for notification
+ */
+static const bool useCurrentModel = false;
+
+/**
+ Simulate rewritting by tagging rewritten terms.
+ */
+static const bool simulateRewritting = false;
+
+/**
+ Choose the kind of matching to use:
+ - InstMatchGenerator::MATCH_GEN_DEFAULT 0
+ - InstMatchGenerator::MATCH_GEN_EFFICIENT_E_MATCH 1
+*/
+static const int match_gen_kind = 0;
+
+/**
+ Do narrowing at full effort
+*/
+static const bool narrowing_full_effort = false;
+
+/**
+ Direct rewrite: Add rewrite rules directly in the rewriter.
+ */
+static const bool direct_rewrite = true;
+
+}/* CVC4::theory::rewriterules namespace */
+}/* CVC4::theory namespace */
+}/* CVC4 namespace */
+
+#endif /* __CVC4__THEORY__REWRITERULES__THEORY_REWRITERULES_PARAMS_H */
diff --git a/src/theory/rewriterules/theory_rewriterules_preprocess.h b/src/theory/rewriterules/theory_rewriterules_preprocess.h
new file mode 100644
index 000000000..f17e30758
--- /dev/null
+++ b/src/theory/rewriterules/theory_rewriterules_preprocess.h
@@ -0,0 +1,176 @@
+/********************* */
+/*! \file rewriterules.h
+ ** \verbatim
+ ** Original author: bobot
+ ** Major contributors: none
+ ** Minor contributors (to current version): none
+ ** This file is part of the CVC4 prototype.
+ ** Copyright (c) 2009, 2010, 2011 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
+ ** information.\endverbatim
+ **
+ ** \brief One utilitise for rewriterules definition
+ **
+ **/
+
+
+#ifndef __CVC4__REWRITERULES_H
+#define __CVC4__REWRITERULES_H
+
+#include <vector>
+#include <hash_set>
+#include <hash_map>
+#include "expr/expr.h"
+#include "expr/node.h"
+#include "theory/rewriterules/theory_rewriterules_params.h"
+#include "theory/uf/theory_uf.h"
+
+namespace CVC4 {
+namespace theory {
+namespace rewriterules {
+
+namespace rewriter{
+
+ typedef Node TMPNode;
+ typedef std::vector<Node> Subst;
+ typedef std::vector<Expr> ESubst;
+ typedef std::vector<TMPNode> TSubst;
+
+ struct Step{
+
+ /** match the node and add in Vars the found variables */
+ virtual Node run(TMPNode node) = 0;
+ virtual bool add(TMPNode pattern, TMPNode body, Subst & pvars, Subst & vars) = 0;
+ };
+
+ struct FinalStep : Step {
+ Node body;
+ TSubst vars;
+
+ Node subst(Subst & subst){
+ return body.substitute(vars.begin(), vars.end(),
+ subst.begin(), subst.end());
+ }
+
+ };
+
+ typedef std::hash_map< Node, int, NodeHashFunction > PVars;
+
+ struct Pattern : FinalStep{
+ Node pattern;
+ PVars pattern_vars;
+
+ Node run(TMPNode node){
+ Subst vars = Subst(pattern_vars.size(),Node::null());
+
+ typedef std::vector<std::pair<TMPNode,TMPNode> > tstack;
+ tstack stack(1,std::make_pair(node,pattern)); // t * pat
+
+ while(!stack.empty()){
+ const std::pair<TMPNode,TMPNode> p = stack.back(); stack.pop_back();
+ const TMPNode & t = p.first;
+ const TMPNode & pat = p.second;
+
+ // pat is a variable
+ if( pat.getKind() == kind::INST_CONSTANT ||
+ pat.getKind() == kind::VARIABLE){
+ PVars::iterator i = pattern_vars.find(pat);
+ Assert(i != pattern_vars.end());
+ if(vars[i->second].isNull()) vars[i->second] = t;
+ if(vars[i->second] == t) continue;
+ return Node::null();
+ };
+
+ // t is not an UF application
+ if( t.getKind() != kind::APPLY_UF ){
+ if (t == pat) continue;
+ else return Node::null();
+ };
+
+ //different UF_application
+ if( t.getOperator() != pat.getOperator() ) return Node::null();
+
+ //put the children on the stack
+ for( size_t i=0; i < pat.getNumChildren(); i++ ){
+ stack.push_back(std::make_pair(t[i],pat[i]));
+ };
+ }
+
+ // Matching is done
+ return subst(vars);
+ }
+
+ bool add(TMPNode pattern, TMPNode body, Subst & pvars, Subst & vars){
+ return false;
+ }
+
+ };
+
+
+ struct Args : Step {
+ typedef std::vector<Pattern> Patterns;
+ Patterns d_matches;
+
+ Node run(TMPNode node){
+ Node n;
+ for (Patterns::iterator i = d_matches.begin();
+ i != d_matches.end() && n.isNull(); ++i){
+ Debug("rewriterules-rewrite") << "test?" << i->pattern << std::endl;
+ n = i->run(node);
+ }
+ return n;
+ }
+
+ bool add(TMPNode pattern, TMPNode body, Subst & pvars, Subst & vars){
+ Debug("rewriterules-rewrite") << "theoryrewrite::Args::add" << "("
+ << d_matches.size() << ")"
+ << pattern << "->" << body << std::endl;
+ d_matches.push_back(Pattern());
+ Pattern & p = d_matches.back();
+ p.body = body;
+ p.vars.reserve(vars.size());
+ for( size_t i=0; i < vars.size(); i++ ){
+ p.vars.push_back(vars[i]);
+ };
+ p.pattern = pattern;
+ for( size_t i=0; i < pvars.size(); i++ ){
+ p.pattern_vars[pvars[i]] = i;
+ };
+ return true;
+ };
+
+ void clear(){
+ d_matches.clear();
+ }
+ };
+
+class RRPpRewrite : public uf::TheoryUF::PpRewrite {
+ Args d_pattern;
+public:
+ Node ppRewrite(TNode node){
+ Debug("rewriterules-rewrite") << "rewrite?" << node << std::endl;
+ Node t = d_pattern.run(node);
+ Debug("rewriterules-rewrite") << "rewrite:" << node
+ << (t.isNull()? " to": " to ")
+ << t << std::endl;
+ if (t.isNull()) return node;
+ else return t;
+ }
+
+ bool addRewritePattern(TMPNode pattern, TMPNode body,
+ Subst & pvars, Subst & vars){
+ return d_pattern.add(pattern,body,pvars,vars);
+ }
+
+};
+
+
+
+}
+
+}
+}
+}
+#endif /* __CVC4__REWRITERULES_H */
diff --git a/src/theory/rewriterules/theory_rewriterules_rewriter.h b/src/theory/rewriterules/theory_rewriterules_rewriter.h
new file mode 100644
index 000000000..d9da095f7
--- /dev/null
+++ b/src/theory/rewriterules/theory_rewriterules_rewriter.h
@@ -0,0 +1,104 @@
+#include "cvc4_private.h"
+
+#ifndef __CVC4__THEORY__REWRITERULES__THEORY_REWRITERULES_REWRITER_H
+#define __CVC4__THEORY__REWRITERULES__THEORY_REWRITERULES_REWRITER_H
+
+#include "theory/rewriter.h"
+#include "theory/rewriter_attributes.h"
+
+namespace CVC4 {
+namespace theory {
+namespace rewriterules {
+
+class TheoryRewriterulesRewriter {
+public:
+
+ /**
+ * Rewrite a node into the normal form for the theory of rewriterules.
+ * Called in post-order (really reverse-topological order) when
+ * traversing the expression DAG during rewriting. This is the
+ * main function of the rewriter, and because of the ordering,
+ * it can assume its children are all rewritten already.
+ *
+ * This function can return one of three rewrite response codes
+ * along with the rewritten node:
+ *
+ * REWRITE_DONE indicates that no more rewriting is needed.
+ * REWRITE_AGAIN means that the top-level expression should be
+ * rewritten again, but that its children are in final form.
+ * REWRITE_AGAIN_FULL means that the entire returned expression
+ * should be rewritten again (top-down with preRewrite(), then
+ * bottom-up with postRewrite()).
+ *
+ * Even if this function returns REWRITE_DONE, if the returned
+ * expression belongs to a different theory, it will be fully
+ * rewritten by that theory's rewriter.
+ */
+ static RewriteResponse postRewrite(TNode node) {
+
+ // Implement me!
+
+ // This default implementation
+ return RewriteResponse(REWRITE_DONE, node);
+ }
+
+ /**
+ * Rewrite a node into the normal form for the theory of rewriterules
+ * in pre-order (really topological order)---meaning that the
+ * children may not be in the normal form. This is an optimization
+ * for theories with cancelling terms (e.g., 0 * (big-nasty-expression)
+ * in arithmetic rewrites to 0 without the need to look at the big
+ * nasty expression). Since it's only an optimization, the
+ * implementation here can do nothing.
+ */
+ static RewriteResponse preRewrite(TNode node) {
+ // do nothing
+ return RewriteResponse(REWRITE_DONE, node);
+ }
+
+ /**
+ * Rewrite an equality, in case special handling is required.
+ */
+ static Node rewriteEquality(TNode equality) {
+ // often this will suffice
+ return postRewrite(equality).node;
+ }
+
+ /**
+ * Initialize the rewriter.
+ */
+ static inline void init() {
+ // nothing to do
+ }
+
+ /**
+ * Shut down the rewriter.
+ */
+ static inline void shutdown() {
+ // nothing to do
+ }
+
+};/* class TheoryRewriterulesRewriter */
+
+}/* CVC4::theory::rewriterules namespace */
+
+template<>
+struct RewriteAttibute<THEORY_REWRITERULES> {
+ static Node getPreRewriteCache(TNode node) throw() {
+ return node;
+ }
+
+ static void setPreRewriteCache(TNode node, TNode cache) throw() { }
+
+ static Node getPostRewriteCache(TNode node) throw() {
+ return node;
+ }
+
+ static void setPostRewriteCache(TNode node, TNode cache) throw() { }
+
+};
+
+}/* CVC4::theory namespace */
+}/* CVC4 namespace */
+
+#endif /* __CVC4__THEORY__REWRITERULES__THEORY_REWRITERULES_REWRITER_H */
diff --git a/src/theory/rewriterules/theory_rewriterules_rules.cpp b/src/theory/rewriterules/theory_rewriterules_rules.cpp
new file mode 100644
index 000000000..9847f1727
--- /dev/null
+++ b/src/theory/rewriterules/theory_rewriterules_rules.cpp
@@ -0,0 +1,303 @@
+/********************* */
+/*! \file rewrite_engine.cpp
+ ** \verbatim
+ ** Original author: ajreynolds
+ ** Major contributors: bobot
+ ** Minor contributors (to current version): none
+ ** This file is part of the CVC4 prototype.
+ ** Copyright (c) 2009, 2010, 2011
+ ** 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
+ ** information.\endverbatim
+ **
+ ** \brief [[ Deals with rewrite rules ]]
+ **
+ ** [[ Add lengthier description here ]]
+ ** \todo document this file
+ **/
+
+#include "theory/rewriterules/theory_rewriterules_rules.h"
+#include "theory/rewriterules/theory_rewriterules_params.h"
+#include "theory/rewriterules/theory_rewriterules_preprocess.h"
+#include "theory/rewriterules/theory_rewriterules.h"
+
+using namespace std;
+using namespace CVC4;
+using namespace CVC4::kind;
+using namespace CVC4::context;
+using namespace CVC4::theory;
+using namespace CVC4::theory::rewriterules;
+
+
+namespace CVC4 {
+namespace theory {
+namespace rewriterules {
+
+void TheoryRewriteRules::computeMatchBody ( const RewriteRule * rule,
+ size_t start){
+ std::vector<TNode> stack(1,rule->new_terms);
+
+ while(!stack.empty()){
+ Node t = stack.back(); stack.pop_back();
+
+ // We don't want to consider variable in t
+ if( std::find(rule->free_vars.begin(), rule->free_vars.end(), t)
+ != rule->free_vars.end()) continue;
+ // t we want to consider only UF function
+ if( t.getKind() == APPLY_UF ){
+ for(size_t rid = start, end = d_rules.size(); rid < end; ++rid) {
+ RewriteRule * r = d_rules[rid];
+ if(r->d_split) continue;
+ Trigger & tr = const_cast<Trigger &> (r->trigger_for_body_match);
+ if(!tr.nonunifiable(t, rule->free_vars)){
+ rule->body_match.push_back(std::make_pair(t,r));
+ }
+ }
+ }
+
+ //put the children on the stack
+ for( size_t i=0; i < t.getNumChildren(); i++ ){
+ stack.push_back(t[i]);
+ };
+
+ }
+}
+
+inline void addPattern(TheoryRewriteRules & re,
+ TNode tri,
+ std::vector<Node> & pattern,
+ std::vector<Node> & vars,
+ std::vector<Node> & inst_constants,
+ TNode r){
+ if (tri.getKind() == kind::NOT && tri[0].getKind() == kind::APPLY_UF)
+ tri = tri[0];
+ pattern.push_back(re.getQuantifiersEngine()->
+ convertNodeToPattern(tri,r,vars,inst_constants));
+}
+
+/*** Check that triggers contains all the variables */
+void checkPatternVarsAux(TNode pat,const std::vector<Node> & vars,
+ std::vector<bool> & seen){
+ for(size_t id=0;id < vars.size(); ++id){
+ if(pat == vars[id]){
+ seen[id]=true;
+ break;
+ };
+ };
+ for(Node::iterator i = pat.begin(); i != pat.end(); ++i) {
+ checkPatternVarsAux(*i,vars,seen);
+ };
+}
+
+bool checkPatternVars(const std::vector<Node> & pattern,
+ const std::vector<Node> & vars){
+ std::vector<bool> seen(vars.size(),false);
+ for(std::vector<Node>::const_iterator i = pattern.begin();
+ i != pattern.end(); ++i) {
+ checkPatternVarsAux(*i,vars,seen);
+ };
+ return (find(seen.begin(),seen.end(),false) == seen.end());
+}
+
+/** Main function for construction of RewriteRule */
+void TheoryRewriteRules::addRewriteRule(const Node r)
+{
+ Assert(r.getKind() == kind::REWRITE_RULE);
+ /* Replace variables by Inst_* variable and tag the terms that
+ contain them */
+ std::vector<Node> vars;
+ vars.reserve(r[0].getNumChildren());
+ for( Node::const_iterator v = r[0].begin(); v != r[0].end(); ++v ){
+ vars.push_back(*v);
+ };
+ /* Instantiation version */
+ std::vector<Node> inst_constants =
+ getQuantifiersEngine()->createInstVariable(vars);
+ /* Body/Remove_term/Guards/Triggers */
+ Node body = r[2][1];
+ TNode new_terms = r[2][1];
+ std::vector<Node> guards;
+ std::vector<Node> pattern;
+ std::vector<Node> to_remove; /* "remove" the terms from the database
+ when fired */
+ /* shortcut */
+ TNode head = r[2][0];
+ switch(r[2].getKind()){
+ case kind::RR_REWRITE:
+ /* Equality */
+ to_remove.push_back(head);
+ addPattern(*this,head,pattern,vars,inst_constants,r);
+ body = head.eqNode(body);
+ break;
+ case kind::RR_REDUCTION:
+ /** Add head to remove */
+ to_remove.push_back(head);
+ case kind::RR_DEDUCTION:
+ /** Add head to guards and pattern */
+ switch(head.getKind()){
+ case kind::AND:
+ guards.reserve(head.getNumChildren());
+ for(Node::iterator i = head.begin(); i != head.end(); ++i) {
+ guards.push_back(*i);
+ addPattern(*this,*i,pattern,vars,inst_constants,r);
+ };
+ break;
+ default:
+ if (head != d_true){
+ guards.push_back(head);
+ addPattern(*this,head,pattern,vars,inst_constants,r);
+ };
+ /** otherwise guards is empty */
+ };
+ break;
+ default:
+ Unreachable("RewriteRules can be of only threee kinds");
+ };
+ /* Add the other guards */
+ TNode g = r[1];
+ switch(g.getKind()){
+ case kind::AND:
+ guards.reserve(g.getNumChildren());
+ for(Node::iterator i = g.begin(); i != g.end(); ++i) {
+ guards.push_back(*i);
+ };
+ break;
+ default:
+ if (g != d_true) guards.push_back(g);
+ /** otherwise guards is empty */
+ };
+ /* Add the other triggers */
+ if( r[2].getNumChildren() >= 3 )
+ for(Node::iterator i = r[2][2].begin(); i != r[2][2].end(); ++i) {
+ // todo test during typing that its a good term (no not, atom, or term...)
+ addPattern(*this,(*i)[0],pattern,vars,inst_constants,r);
+ };
+ // Assert(pattern.size() == 1, "currently only single pattern are supported");
+ //Every variable must be seen in the pattern
+ if (!checkPatternVars(pattern,inst_constants)){
+ Warning() << "The rule" << r <<
+ " has been removed since it doesn't contain every variables."
+ << std::endl;
+ return;
+ }
+
+ //Add to direct rewrite rule
+ bool directrr = false;
+ if(direct_rewrite &&
+ ((guards.size() == 0 && r[2].getKind() == kind::RR_REWRITE) ||
+ (guards.size() == 1 && r[2].getKind() == kind::RR_REDUCTION))
+ && pattern.size() == 1){
+ directrr = addRewritePattern(pattern[0],new_terms, inst_constants, vars);
+ }
+
+ // final construction
+ Trigger trigger = createTrigger(r,pattern);
+ Trigger trigger2 = createTrigger(r,pattern); //Hack
+ RewriteRule * rr = new RewriteRule(*this, trigger, trigger2,
+ guards, body, new_terms,
+ vars, inst_constants, to_remove,
+ directrr);
+ /** other -> rr */
+ if(compute_opt && !rr->d_split) computeMatchBody(rr);
+ d_rules.push_back(rr);
+ /** rr -> all (including himself) */
+ if(compute_opt && !rr->d_split)
+ for(size_t rid = 0, end = d_rules.size(); rid < end; ++rid)
+ computeMatchBody(d_rules[rid],
+ d_rules.size() - 1);
+
+ Debug("rewriterules") << "created rewriterule"<< (rr->d_split?"(split)":"") << ":(" << d_rules.size() - 1 << ")"
+ << *rr << std::endl;
+
+}
+
+
+bool willDecide(TNode node, bool positive = true){
+ /* TODO something better */
+ switch(node.getKind()) {
+ case AND:
+ return !positive;
+ case OR:
+ return positive;
+ case IFF:
+ return true;
+ case XOR:
+ return true;
+ case IMPLIES:
+ return false;
+ case ITE:
+ return true;
+ case NOT:
+ return willDecide(node[0],!positive);
+ default:
+ return false;
+ }
+}
+
+
+RewriteRule::RewriteRule(TheoryRewriteRules & re,
+ Trigger & tr, Trigger & tr2,
+ std::vector<Node> & g, Node b, TNode nt,
+ std::vector<Node> & fv,std::vector<Node> & iv,
+ std::vector<Node> & to_r, bool drr) :
+ d_split(willDecide(b)),
+ trigger(tr), body(b), new_terms(nt), free_vars(), inst_vars(),
+ body_match(re.getSatContext()),trigger_for_body_match(tr2),
+ d_cache(re.getSatContext(),re.getQuantifiersEngine()), directrr(drr){
+ free_vars.swap(fv); inst_vars.swap(iv); guards.swap(g); to_remove.swap(to_r);
+};
+
+
+bool RewriteRule::inCache(TheoryRewriteRules & re, InstMatch & im)const{
+ return !d_cache.addInstMatch(im);
+};
+
+/** A rewrite rule */
+void RewriteRule::toStream(std::ostream& out) const{
+ for(std::vector<Node>::const_iterator
+ iter = guards.begin(); iter != guards.end(); ++iter){
+ out << *iter;
+ };
+ out << "=>" << body << std::endl;
+ out << "[";
+ for(BodyMatch::const_iterator
+ iter = body_match.begin(); iter != body_match.end(); ++iter){
+ out << (*iter).first << "(" << (*iter).second << ")" << ",";
+ };
+ out << "]" << (directrr?"*":"") << std::endl;
+}
+
+RewriteRule::~RewriteRule(){
+ Debug("rewriterule-stats") << *this
+ << " (" << nb_matched
+ << "," << nb_applied
+ << "," << nb_propagated
+ << ")" << std::endl;
+}
+
+bool TheoryRewriteRules::addRewritePattern(TNode pattern, TNode body,
+ rewriter::Subst & pvars,
+ rewriter::Subst & vars){
+ Assert(pattern.getKind() == kind::APPLY_UF);
+ TNode op = pattern.getOperator();
+ TheoryRewriteRules::RegisterRRPpRewrite::iterator i =
+ d_registeredRRPpRewrite.find(op);
+
+ rewriter::RRPpRewrite * p;
+ if (i == d_registeredRRPpRewrite.end()){
+ p = new rewriter::RRPpRewrite();
+ d_registeredRRPpRewrite.insert(std::make_pair(op,p));
+ ((uf::TheoryUF*)getQuantifiersEngine()->getTheoryEngine()->getTheory( THEORY_UF ))->
+ registerPpRewrite(op,p);
+ } else p = i->second;
+
+ return p->addRewritePattern(pattern,body,pvars,vars);
+
+}
+
+
+}/* CVC4::theory::rewriterules namespace */
+}/* CVC4::theory namespace */
+}/* CVC4 namespace */
diff --git a/src/theory/rewriterules/theory_rewriterules_rules.h b/src/theory/rewriterules/theory_rewriterules_rules.h
new file mode 100644
index 000000000..a8e70f3e6
--- /dev/null
+++ b/src/theory/rewriterules/theory_rewriterules_rules.h
@@ -0,0 +1,40 @@
+/********************* */
+/*! \file rewrite_engine.h
+ ** \verbatim
+ ** Original author: ajreynol
+ ** Major contributors: bobot
+ ** Minor contributors (to current version): none
+ ** This file is part of the CVC4 prototype.
+ ** Copyright (c) 2009, 2010, 2011
+ ** 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
+ ** information.\endverbatim
+ **
+ ** \brief Rewrite Engine classes
+ **/
+
+
+#include "cvc4_private.h"
+
+#ifndef __CVC4__THEORY__REWRITERULES__THEORY_REWRITERULES_RULES_H
+#define __CVC4__THEORY__REWRITERULES__THEORY_REWRITERULES_RULES_H
+
+#include "theory/rewriterules/theory_rewriterules.h"
+#include "theory/rewriterules/theory_rewriterules_params.h"
+
+namespace CVC4 {
+namespace theory {
+namespace rewriterules {
+
+inline std::ostream& operator <<(std::ostream& stream, const RewriteRule& r) {
+ r.toStream(stream);
+ return stream;
+}
+
+}/* CVC4::theory::rewriterules namespace */
+}/* CVC4::theory namespace */
+}/* CVC4 namespace */
+
+#endif /* __CVC4__THEORY__REWRITERULES__THEORY_REWRITERULES_RULES_H */
diff --git a/src/theory/rewriterules/theory_rewriterules_type_rules.h b/src/theory/rewriterules/theory_rewriterules_type_rules.h
new file mode 100644
index 000000000..5a0e8c5e0
--- /dev/null
+++ b/src/theory/rewriterules/theory_rewriterules_type_rules.h
@@ -0,0 +1,98 @@
+#include "cvc4_private.h"
+
+#ifndef __CVC4__THEORY__REWRITERULES__THEORY_REWRITERULES_TYPE_RULES_H
+#define __CVC4__THEORY__REWRITERULES__THEORY_REWRITERULES_TYPE_RULES_H
+
+#include "node_manager.h"
+
+namespace CVC4 {
+namespace theory {
+namespace rewriterules {
+
+class RewriteRuleTypeRule {
+public:
+
+ /**
+ * Compute the type for (and optionally typecheck) a term belonging
+ * to the theory of rewriterules.
+ *
+ * @param check if true, the node's type should be checked as well
+ * as computed.
+ */
+ inline static TypeNode computeType(NodeManager* nodeManager, TNode n,
+ bool check)
+ throw(TypeCheckingExceptionPrivate) {
+ Debug("typecheck-r") << "type check for rr " << n << std::endl;
+ Assert(n.getKind() == kind::REWRITE_RULE && n.getNumChildren()==3 );
+ if( check ){
+ if( n[ 0 ].getType(check)!=nodeManager->boundVarListType() ){
+ throw TypeCheckingExceptionPrivate(n,
+ "first argument of rewrite rule is not bound var list");
+ }
+ if( n[ 1 ].getType(check)!=nodeManager->booleanType() ){
+ throw TypeCheckingExceptionPrivate(n,
+ "guard of rewrite rule is not an actual guard");
+ }
+ if( n[2].getType(check) !=
+ TypeNode(nodeManager->mkTypeConst<TypeConstant>(RRHB_TYPE))){
+ throw TypeCheckingExceptionPrivate(n,
+ "not a correct rewrite rule");
+ }
+ }
+ return nodeManager->booleanType();
+ }
+};/* class RewriterulesTypeRule */
+
+
+class RRRewriteTypeRule {
+public:
+
+ inline static TypeNode computeType(NodeManager* nodeManager, TNode n, bool check)
+ throw(TypeCheckingExceptionPrivate) {
+ Assert(n.getKind() == kind::RR_REWRITE );
+ if( check ){
+ if( n[0].getType(check)!=n[1].getType(check) ){
+ throw TypeCheckingExceptionPrivate(n,
+ "terms of rewrite rule are not equal");
+ }
+ if( n.getNumChildren() == 3 && n[2].getType(check)!=nodeManager->instPatternListType() ){
+ throw TypeCheckingExceptionPrivate(n, "third argument of rewrite rule is not instantiation pattern list");
+ }
+ if( n[0].getKind()!=kind::APPLY_UF ){
+ throw TypeCheckingExceptionPrivate(n[0], "head of rewrite rules must start with an uninterpreted symbols. If you want to write a propagation rule, add the guard [true] for disambiguation");
+ }
+ }
+ return TypeNode(nodeManager->mkTypeConst<TypeConstant>(RRHB_TYPE));
+ }
+};/* struct QuantifierReductionRuleRule */
+
+class RRRedDedTypeRule {
+public:
+
+ inline static TypeNode computeType(NodeManager* nodeManager, TNode n, bool check)
+ throw(TypeCheckingExceptionPrivate) {
+ Assert(n.getKind() == kind::RR_REDUCTION ||
+ n.getKind() == kind::RR_DEDUCTION );
+ if( check ){
+ if( n[ 0 ].getType(check)!=nodeManager->booleanType() ){
+ throw TypeCheckingExceptionPrivate(n, "head of reduction rule is not boolean");
+ }
+ if( n[ 1 ].getType(check)!=nodeManager->booleanType() ){
+ throw TypeCheckingExceptionPrivate(n, "body of reduction rule is not boolean");
+ }
+ if( n.getNumChildren() == 3 && n[2].getType(check)!=nodeManager->instPatternListType() ){
+ throw TypeCheckingExceptionPrivate(n, "third argument of rewrite rule is not instantiation pattern list");
+ }
+ if( n.getNumChildren() < 3 && n[ 0 ] == nodeManager->mkConst<bool>(true) ){
+ throw TypeCheckingExceptionPrivate(n, "A rewrite rule must have one head or one trigger at least");
+ }
+ }
+ return TypeNode(nodeManager->mkTypeConst<TypeConstant>(RRHB_TYPE));
+ }
+};/* struct QuantifierReductionRuleRule */
+
+}/* CVC4::theory::rewriterules namespace */
+}/* CVC4::theory namespace */
+}/* CVC4 namespace */
+
+#endif /* __CVC4__THEORY__REWRITERULES__THEORY_REWRITERULES_TYPE_RULES_H */
diff --git a/src/theory/shared_terms_database.cpp b/src/theory/shared_terms_database.cpp
index b081e27ef..98ab3f10d 100644
--- a/src/theory/shared_terms_database.cpp
+++ b/src/theory/shared_terms_database.cpp
@@ -52,7 +52,7 @@ void SharedTermsDatabase::addEqualityToPropagate(TNode equality) {
void SharedTermsDatabase::addSharedTerm(TNode atom, TNode term, Theory::Set theories) {
- Debug("register") << "SharedTermsDatabase::addSharedTerm(" << atom << ", " << term << ", " << Theory::setToString(theories) << ")" << std::endl;
+ Debug("register") << "SharedTermsDatabase::addSharedTerm(" << atom << ", " << term << ", " << Theory::setToString(theories) << ")" << std::endl;
std::pair<TNode, TNode> search_pair(atom, term);
SharedTermsTheoriesMap::iterator find = d_termsToTheories.find(search_pair);
@@ -64,18 +64,18 @@ void SharedTermsDatabase::addSharedTerm(TNode atom, TNode term, Theory::Set theo
d_termsToTheories[search_pair] = theories;
} else {
Assert(theories != (*find).second);
- d_termsToTheories[search_pair] = Theory::setUnion(theories, (*find).second);
+ d_termsToTheories[search_pair] = Theory::setUnion(theories, (*find).second);
}
}
SharedTermsDatabase::shared_terms_iterator SharedTermsDatabase::begin(TNode atom) const {
Assert(hasSharedTerms(atom));
- return d_atomsToTerms.find(atom)->second.begin();
+ return d_atomsToTerms.find(atom)->second.begin();
}
SharedTermsDatabase::shared_terms_iterator SharedTermsDatabase::end(TNode atom) const {
Assert(hasSharedTerms(atom));
- return d_atomsToTerms.find(atom)->second.end();
+ return d_atomsToTerms.find(atom)->second.end();
}
bool SharedTermsDatabase::hasSharedTerms(TNode atom) const {
@@ -89,24 +89,24 @@ void SharedTermsDatabase::backtrack() {
list.pop_back();
if (list.empty()) {
d_atomsToTerms.erase(atom);
- }
+ }
}
d_addedSharedTerms.resize(d_addedSharedTermsSize);
}
Theory::Set SharedTermsDatabase::getTheoriesToNotify(TNode atom, TNode term) const {
- // Get the theories that share this term from this atom
+ // Get the theories that share this term from this atom
std::pair<TNode, TNode> search_pair(atom, term);
SharedTermsTheoriesMap::iterator find = d_termsToTheories.find(search_pair);
- Assert(find != d_termsToTheories.end());
-
+ Assert(find != d_termsToTheories.end());
+
// Get the theories that were already notified
Theory::Set alreadyNotified = 0;
AlreadyNotifiedMap::iterator theoriesFind = d_alreadyNotifiedMap.find(term);
if (theoriesFind != d_alreadyNotifiedMap.end()) {
alreadyNotified = (*theoriesFind).second;
}
-
+
// Return the ones that haven't been notified yet
return Theory::setDifference((*find).second, alreadyNotified);
}
diff --git a/src/theory/shared_terms_database.h b/src/theory/shared_terms_database.h
index fccd2e6bc..c7da8a463 100644
--- a/src/theory/shared_terms_database.h
+++ b/src/theory/shared_terms_database.h
@@ -2,7 +2,7 @@
/*! \file node_visitor.h
** \verbatim
** Original author: dejan
- ** Major contributors:
+ ** 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)
@@ -40,7 +40,7 @@ private:
/** The context */
context::Context* d_context;
-
+
/** Some statistics */
IntStat d_statSharedTerms;
@@ -49,13 +49,13 @@ private:
/** A map from atoms to a list of shared terms */
SharedTermsMap d_atomsToTerms;
-
+
/** Each time we add a shared term, we add it's parent to this list */
std::vector<TNode> d_addedSharedTerms;
-
+
/** Context-dependent size of the d_addedSharedTerms list */
context::CDO<unsigned> d_addedSharedTermsSize;
-
+
/** A map from atoms and subterms to the theories that use it */
typedef context::CDHashMap<std::pair<Node, TNode>, theory::Theory::Set, TNodePairHashFunction> SharedTermsTheoriesMap;
SharedTermsTheoriesMap d_termsToTheories;
@@ -95,6 +95,11 @@ private:
void eqNotifyConstantTermMerge(TNode t1, TNode t2) {
d_sharedTerms.conflict(t1, t2, true);
}
+
+ void eqNotifyNewClass(TNode t) { }
+ void eqNotifyPreMerge(TNode t1, TNode t2) { }
+ void eqNotifyPostMerge(TNode t1, TNode t2) { }
+ void eqNotifyDisequal(TNode t1, TNode t2, TNode reason) { }
};
/** The notify class for d_equalityEngine */
@@ -147,7 +152,7 @@ public:
SharedTermsDatabase(TheoryEngine* theoryEngine, context::Context* context);
~SharedTermsDatabase() throw(AssertionException);
-
+
/**
* Asserts the equality to the shared terms database,
*/
@@ -185,12 +190,12 @@ public:
bool hasSharedTerms(TNode atom) const;
/**
- * Iterator pointing to the first shared term belonging to the given atom.
+ * Iterator pointing to the first shared term belonging to the given atom.
*/
shared_terms_iterator begin(TNode atom) const;
/**
- * Iterator pointing to the end of the list of shared terms belonging to the given atom.
+ * Iterator pointing to the end of the list of shared terms belonging to the given atom.
*/
shared_terms_iterator end(TNode atom) const;
diff --git a/src/theory/term_registration_visitor.cpp b/src/theory/term_registration_visitor.cpp
index 22b87c32f..b0b712356 100644
--- a/src/theory/term_registration_visitor.cpp
+++ b/src/theory/term_registration_visitor.cpp
@@ -2,10 +2,10 @@
/*! \file term_registration_visitor.h
** \verbatim
** Original author: dejan
- ** Major contributors:
- ** Minor contributors (to current version):
+ ** Major contributors: none
+ ** Minor contributors (to current version): none
** This file is part of the CVC4 prototype.
- ** Copyright (c) 2009, 2010, 2011 The Analysis of Computer Systems Group (ACSys)
+ ** Copyright (c) 2009-2012 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
@@ -32,6 +32,14 @@ bool PreRegisterVisitor::alreadyVisited(TNode current, TNode parent) {
Debug("register::internal") << "PreRegisterVisitor::alreadyVisited(" << current << "," << parent << ")" << std::endl;
+ if( ( parent.getKind() == kind::FORALL ||
+ parent.getKind() == kind::EXISTS ||
+ parent.getKind() == kind::REWRITE_RULE ) &&
+ current != parent ) {
+ Debug("register::internal") << "quantifier:true" << std::endl;
+ return true;
+ }
+
TheoryId currentTheoryId = Theory::theoryOf(current);
TheoryId parentTheoryId = Theory::theoryOf(parent);
@@ -89,13 +97,21 @@ void PreRegisterVisitor::visit(TNode current, TNode parent) {
if (!Theory::setContains(currentTheoryId, visitedTheories)) {
visitedTheories = Theory::setInsert(currentTheoryId, visitedTheories);
d_visited[current] = visitedTheories;
- d_engine->theoryOf(currentTheoryId)->preRegisterTerm(current);
+ Theory* th = d_engine->theoryOf(currentTheoryId);
+ th->preRegisterTerm(current);
+ if(th->getInstantiator() != NULL) {
+ th->getInstantiator()->preRegisterTerm(current);
+ }
Debug("register::internal") << "PreRegisterVisitor::visit(" << current << "," << parent << "): adding " << currentTheoryId << std::endl;
}
if (!Theory::setContains(parentTheoryId, visitedTheories)) {
visitedTheories = Theory::setInsert(parentTheoryId, visitedTheories);
d_visited[current] = visitedTheories;
- d_engine->theoryOf(parentTheoryId)->preRegisterTerm(current);
+ Theory* th = d_engine->theoryOf(parentTheoryId);
+ th->preRegisterTerm(current);
+ if(th->getInstantiator() != NULL) {
+ th->getInstantiator()->preRegisterTerm(current);
+ }
Debug("register::internal") << "PreRegisterVisitor::visit(" << current << "," << parent << "): adding " << parentTheoryId << std::endl;
}
if (useType) {
@@ -103,7 +119,11 @@ void PreRegisterVisitor::visit(TNode current, TNode parent) {
if (!Theory::setContains(typeTheoryId, visitedTheories)) {
visitedTheories = Theory::setInsert(typeTheoryId, visitedTheories);
d_visited[current] = visitedTheories;
- d_engine->theoryOf(typeTheoryId)->preRegisterTerm(current);
+ Theory* th = d_engine->theoryOf(typeTheoryId);
+ th->preRegisterTerm(current);
+ if(th->getInstantiator() != NULL) {
+ th->getInstantiator()->preRegisterTerm(current);
+ }
Debug("register::internal") << "PreRegisterVisitor::visit(" << current << "," << parent << "): adding " << parentTheoryId << std::endl;
}
}
@@ -135,6 +155,13 @@ bool SharedTermsVisitor::alreadyVisited(TNode current, TNode parent) const {
Debug("register::internal") << "SharedTermsVisitor::alreadyVisited(" << current << "," << parent << ")" << std::endl;
+ if( ( parent.getKind() == kind::FORALL ||
+ parent.getKind() == kind::EXISTS ||
+ parent.getKind() == kind::REWRITE_RULE) &&
+ current != parent ) {
+ Debug("register::internal") << "quantifier:true" << std::endl;
+ return true;
+ }
TNodeVisitedMap::const_iterator find = d_visited.find(current);
// If node is not visited at all, just return false
diff --git a/src/theory/theory.cpp b/src/theory/theory.cpp
index 1ed1f99ff..7555282d8 100644
--- a/src/theory/theory.cpp
+++ b/src/theory/theory.cpp
@@ -18,6 +18,8 @@
#include "theory/theory.h"
#include "util/Assert.h"
+#include "theory/quantifiers_engine.h"
+#include "theory/instantiator_default.h"
#include <vector>
@@ -37,21 +39,32 @@ std::ostream& operator<<(std::ostream& os, Theory::Effort level){
os << "EFFORT_FULL"; break;
case Theory::EFFORT_COMBINATION:
os << "EFFORT_COMBINATION"; break;
+ case Theory::EFFORT_LAST_CALL:
+ os << "EFFORT_LAST_CALL"; break;
default:
Unreachable();
}
return os;
}/* ostream& operator<<(ostream&, Theory::Effort) */
+Theory::~Theory() {
+ if(d_inst != NULL) {
+ delete d_inst;
+ d_inst = NULL;
+ }
+
+ StatisticsRegistry::unregisterStat(&d_computeCareGraphTime);
+}
+
void Theory::addSharedTermInternal(TNode n) {
- Debug("sharing") << "Theory::addSharedTerm<" << getId() << ">(" << n << ")" << std::endl;
- Debug("theory::assertions") << "Theory::addSharedTerm<" << getId() << ">(" << n << ")" << std::endl;
+ Debug("sharing") << "Theory::addSharedTerm<" << getId() << ">(" << n << ")" << endl;
+ Debug("theory::assertions") << "Theory::addSharedTerm<" << getId() << ">(" << n << ")" << endl;
d_sharedTerms.push_back(n);
addSharedTerm(n);
}
void Theory::computeCareGraph() {
- Debug("sharing") << "Theory::computeCareGraph<" << getId() << ">()" << std::endl;
+ Debug("sharing") << "Theory::computeCareGraph<" << getId() << ">()" << endl;
for (unsigned i = 0; i < d_sharedTerms.size(); ++ i) {
TNode a = d_sharedTerms[i];
TypeNode aType = a.getType();
@@ -71,7 +84,7 @@ void Theory::computeCareGraph() {
addCarePair(a, b);
break;
}
- }
+ }
}
}
@@ -85,8 +98,97 @@ void Theory::printFacts(std::ostream& os) const {
}
void Theory::debugPrintFacts() const{
- cout << "Theory::debugPrintFacts()" << endl;
- printFacts(cout);
+ DebugChannel.getStream() << "Theory::debugPrintFacts()" << endl;
+ printFacts(DebugChannel.getStream());
+}
+
+Instantiator::Instantiator(context::Context* c, QuantifiersEngine* qe, Theory* th) :
+ d_quantEngine(qe),
+ d_th(th) {
+}
+
+Instantiator::~Instantiator() {
+}
+
+void Instantiator::resetInstantiationRound(Theory::Effort effort) {
+ for(int i = 0; i < (int) d_instStrategies.size(); ++i) {
+ if(isActiveStrategy(d_instStrategies[i])) {
+ d_instStrategies[i]->resetInstantiationRound(effort);
+ }
+ }
+ processResetInstantiationRound(effort);
+}
+
+int Instantiator::doInstantiation(Node f, Theory::Effort effort, int e, int limitInst) {
+ if(hasConstraintsFrom(f)) {
+ int origLemmas = d_quantEngine->getNumLemmasWaiting();
+ int status = process(f, effort, e, limitInst);
+ if(limitInst <= 0 || (d_quantEngine->getNumLemmasWaiting()-origLemmas) < limitInst) {
+ if(d_instStrategies.empty()) {
+ Debug("inst-engine-inst") << "There are no instantiation strategies allocated." << endl;
+ } else {
+ for(int i = 0; i < (int) d_instStrategies.size(); ++i) {
+ if(isActiveStrategy(d_instStrategies[i])) {
+ Debug("inst-engine-inst") << d_instStrategies[i]->identify() << " process " << effort << endl;
+ //call the instantiation strategy's process method
+ int s_limitInst = limitInst > 0 ? limitInst - (d_quantEngine->getNumLemmasWaiting() - origLemmas) : 0;
+ int s_status = d_instStrategies[i]->doInstantiation(f, effort, e, s_limitInst);
+ Debug("inst-engine-inst") << " -> status is " << s_status << endl;
+ if(limitInst > 0 && (d_quantEngine->getNumLemmasWaiting() - origLemmas) >= limitInst) {
+ Assert( (d_quantEngine->getNumLemmasWaiting() - origLemmas) == limitInst );
+ i = (int) d_instStrategies.size();
+ status = InstStrategy::STATUS_UNKNOWN;
+ } else {
+ InstStrategy::updateStatus(status, s_status);
+ }
+ } else {
+ Debug("inst-engine-inst") << d_instStrategies[i]->identify() << " is not active." << endl;
+ }
+ }
+ }
+ }
+ return status;
+ } else {
+ Debug("inst-engine-inst") << "We have no constraints from this quantifier." << endl;
+ return InstStrategy::STATUS_SAT;
+ }
+}
+
+//void Instantiator::doInstantiation(int effort) {
+// d_status = InstStrategy::STATUS_SAT;
+// for( int q = 0; q < d_quantEngine->getNumQuantifiers(); ++q ) {
+// Node f = d_quantEngine->getQuantifier(q);
+// if( d_quantEngine->getActive(f) && hasConstraintsFrom(f) ) {
+// int d_quantStatus = process( f, effort );
+// InstStrategy::updateStatus( d_status, d_quantStatus );
+// for( int i = 0; i < (int)d_instStrategies.size(); ++i ) {
+// if( isActiveStrategy( d_instStrategies[i] ) ) {
+// Debug("inst-engine-inst") << d_instStrategies[i]->identify() << " process " << effort << endl;
+// //call the instantiation strategy's process method
+// d_quantStatus = d_instStrategies[i]->process( f, effort );
+// Debug("inst-engine-inst") << " -> status is " << d_quantStatus << endl;
+// InstStrategy::updateStatus( d_status, d_quantStatus );
+// }
+// }
+// }
+// }
+//}
+
+void Instantiator::setHasConstraintsFrom(Node f) {
+ d_hasConstraints[f] = true;
+ if(! d_quantEngine->hasOwner(f)) {
+ d_quantEngine->setOwner(f, getTheory());
+ } else if(d_quantEngine->getOwner(f) != getTheory()) {
+ d_quantEngine->setOwner(f, NULL);
+ }
+}
+
+bool Instantiator::hasConstraintsFrom(Node f) {
+ return d_hasConstraints.find(f) != d_hasConstraints.end() && d_hasConstraints[f];
+}
+
+bool Instantiator::isOwnerOf(Node f) {
+ return d_quantEngine->hasOwner(f) && d_quantEngine->getOwner(f) == getTheory();
}
}/* CVC4::theory namespace */
diff --git a/src/theory/theory.h b/src/theory/theory.h
index 020a2b194..8c830f8a2 100644
--- a/src/theory/theory.h
+++ b/src/theory/theory.h
@@ -46,6 +46,10 @@ class TheoryEngine;
namespace theory {
+class Instantiator;
+class InstStrategy;
+class QuantifiersEngine;
+
/**
* Information about an assertion for the theories.
*/
@@ -72,7 +76,8 @@ struct Assertion {
operator Node () const {
return assertion;
}
-};
+
+};/* struct Assertion */
/**
* A (oredered) pair of terms a theory cares about.
@@ -84,7 +89,7 @@ struct CarePair {
public:
- CarePair(TNode a, TNode b, TheoryId theory)
+ CarePair(TNode a, TNode b, TheoryId theory)
: a(a < b ? a : b), b(a < b ? b : a), theory(theory) {}
bool operator == (const CarePair& other) const {
@@ -99,7 +104,7 @@ public:
return b < other.b;
}
-};
+};/* struct CarePair */
/**
* A set of care pairs.
@@ -172,6 +177,18 @@ private:
*/
CareGraph* d_careGraph;
+ /**
+ * Reference to the quantifiers engine (or NULL, if quantifiers are
+ * not supported or not enabled).
+ */
+ QuantifiersEngine* d_quantEngine;
+
+ /**
+ * The instantiator for this theory, or NULL if quantifiers are not
+ * supported or not enabled.
+ */
+ Instantiator* d_inst;
+
// === STATISTICS ===
/** time spent in theory combination */
TimerStat d_computeCareGraphTime;
@@ -182,6 +199,12 @@ private:
return ss.str();
}
+ /**
+ * Construct and return the instantiator for the given theory.
+ * If there is no instantiator class, NULL is returned.
+ */
+ theory::Instantiator* makeInstantiator(context::Context* c, theory::QuantifiersEngine* qe);
+
protected:
/**
@@ -208,7 +231,7 @@ protected:
* Construct a Theory.
*/
Theory(TheoryId id, context::Context* satContext, context::UserContext* userContext,
- OutputChannel& out, Valuation valuation, const LogicInfo& logicInfo) throw()
+ OutputChannel& out, Valuation valuation, const LogicInfo& logicInfo, QuantifiersEngine* qe) throw()
: d_id(id)
, d_satContext(satContext)
, d_userContext(userContext)
@@ -217,6 +240,8 @@ protected:
, d_factsHead(satContext, 0)
, d_sharedTermsIndex(satContext, 0)
, d_careGraph(0)
+ , d_quantEngine(qe)
+ , d_inst(makeInstantiator(satContext, qe))
, d_computeCareGraphTime(statName(id, "computeCareGraphTime"))
, d_sharedTerms(satContext)
, d_out(&out)
@@ -252,19 +277,7 @@ protected:
*
* @return the next assertion in the assertFact() queue
*/
- Assertion get() {
- Assert( !done(), "Theory`() called with assertion queue empty!" );
-
- // Get the assertion
- Assertion fact = d_facts[d_factsHead];
- d_factsHead = d_factsHead + 1;
- Trace("theory") << "Theory::get() => " << fact << " (" << d_facts.size() - d_factsHead << " left)" << std::endl;
- if(Dump.isOn("state")) {
- Dump("state") << AssertCommand(fact.assertion.toExpr());
- }
-
- return fact;
- }
+ inline Assertion get();
const LogicInfo& getLogicInfo() const {
return d_logicInfo;
@@ -348,13 +361,9 @@ public:
}
/**
- * Destructs a Theory. This implementation does nothing, but we
- * need a virtual destructor for safety in case subclasses have a
- * destructor.
+ * Destructs a Theory.
*/
- virtual ~Theory() {
- StatisticsRegistry::unregisterStat(&d_computeCareGraphTime);
- }
+ virtual ~Theory();
/**
* Subclasses of Theory may add additional efforts. DO NOT CHECK
@@ -376,7 +385,11 @@ public:
* Combination effort means that the individual theories are already satisfied, and
* it is time to put some effort into propagation of shared term equalities
*/
- EFFORT_COMBINATION = 150
+ EFFORT_COMBINATION = 150,
+ /**
+ * Last call effort, reserved for quantifiers.
+ */
+ EFFORT_LAST_CALL = 200
};/* enum Effort */
static inline bool standardEffortOrMore(Effort e) CVC4_CONST_FUNCTION
@@ -385,7 +398,7 @@ public:
{ return e >= EFFORT_STANDARD && e < EFFORT_FULL; }
static inline bool fullEffort(Effort e) CVC4_CONST_FUNCTION
{ return e == EFFORT_FULL; }
- static inline bool combination(Effort e) CVC4_CONST_FUNCTION
+ static inline bool combination(Effort e) CVC4_CONST_FUNCTION
{ return e == EFFORT_COMBINATION; }
/**
@@ -424,6 +437,41 @@ public:
}
/**
+ * Get the valuation associated to this theory.
+ */
+ Valuation& getValuation() {
+ return d_valuation;
+ }
+
+ /**
+ * Get the quantifiers engine associated to this theory.
+ */
+ QuantifiersEngine* getQuantifiersEngine() {
+ return d_quantEngine;
+ }
+
+ /**
+ * Get the quantifiers engine associated to this theory (const version).
+ */
+ const QuantifiersEngine* getQuantifiersEngine() const {
+ return d_quantEngine;
+ }
+
+ /**
+ * Get the theory instantiator.
+ */
+ Instantiator* getInstantiator() {
+ return d_inst;
+ }
+
+ /**
+ * Get the theory instantiator (const version).
+ */
+ const Instantiator* getInstantiator() const {
+ return d_inst;
+ }
+
+ /**
* Pre-register a term. Done one time for a Node, ever.
*/
virtual void preRegisterTerm(TNode) { }
@@ -455,7 +503,7 @@ public:
}
/**
- * Return the status of two terms in the current context. Should be implemented in
+ * Return the status of two terms in the current context. Should be implemented in
* sub-theories to enable more efficient theory-combination.
*/
virtual EqualityStatus getEqualityStatus(TNode a, TNode b) { return EQUALITY_UNKNOWN; }
@@ -573,6 +621,11 @@ public:
virtual Node ppRewrite(TNode atom) { return atom; }
/**
+ * Don't preprocess subterm of this term
+ */
+ virtual bool ppDontRewriteSubterm(TNode atom) { return false; }
+
+ /**
* A Theory is called with presolve exactly one time per user
* check-sat. presolve() is called after preregistration,
* rewriting, and Boolean propagation, (other theories'
@@ -664,7 +717,7 @@ public:
static inline Set setIntersection(Set a, Set b) {
return a & b;
- }
+ }
static inline Set setUnion(Set a, Set b) {
return a | b;
@@ -735,6 +788,84 @@ public:
std::ostream& operator<<(std::ostream& os, Theory::Effort level);
+class Instantiator {
+ friend class QuantifiersEngine;
+protected:
+ /** reference to the quantifiers engine */
+ QuantifiersEngine* d_quantEngine;
+ /** reference to the theory that it looks at */
+ Theory* d_th;
+ /** instantiation strategies */
+ std::vector< InstStrategy* > d_instStrategies;
+ /** instantiation strategies active */
+ std::map< InstStrategy*, bool > d_instStrategyActive;
+ /** has constraints from quantifier */
+ std::map< Node, bool > d_hasConstraints;
+ /** is instantiation strategy active */
+ bool isActiveStrategy( InstStrategy* is ) {
+ return d_instStrategyActive.find( is )!=d_instStrategyActive.end() && d_instStrategyActive[is];
+ }
+ /** add inst strategy */
+ void addInstStrategy( InstStrategy* is ){
+ d_instStrategies.push_back( is );
+ d_instStrategyActive[is] = true;
+ }
+ /** reset instantiation round */
+ virtual void processResetInstantiationRound( Theory::Effort effort ) = 0;
+ /** process quantifier */
+ virtual int process( Node f, Theory::Effort effort, int e, int limitInst = 0 ) = 0;
+public:
+ /** set has constraints from quantifier f */
+ void setHasConstraintsFrom( Node f );
+ /** has constraints from */
+ bool hasConstraintsFrom( Node f );
+ /** is full owner of quantifier f? */
+ bool isOwnerOf( Node f );
+public:
+ Instantiator(context::Context* c, QuantifiersEngine* qe, Theory* th);
+ virtual ~Instantiator();
+
+ /** get quantifiers engine */
+ QuantifiersEngine* getQuantifiersEngine() { return d_quantEngine; }
+ /** get corresponding theory for this instantiator */
+ Theory* getTheory() { return d_th; }
+ /** Pre-register a term. */
+ virtual void preRegisterTerm( Node t ) { }
+ /** assertNode function, assertion was asserted to theory */
+ virtual void assertNode( Node assertion ){}
+ /** reset instantiation round */
+ void resetInstantiationRound( Theory::Effort effort );
+ /** do instantiation method*/
+ int doInstantiation( Node f, Theory::Effort effort, int e, int limitInst = 0 );
+ /** identify */
+ virtual std::string identify() const { return std::string("Unknown"); }
+ /** print debug information */
+ virtual void debugPrint( const char* c ) {}
+ /** get status */
+ //int getStatus() { return d_status; }
+};/* class Instantiator */
+
+inline Assertion Theory::get() {
+ Assert( !done(), "Theory::get() called with assertion queue empty!" );
+
+ // Get the assertion
+ Assertion fact = d_facts[d_factsHead];
+ d_factsHead = d_factsHead + 1;
+
+ Trace("theory") << "Theory::get() => " << fact << " (" << d_facts.size() - d_factsHead << " left)" << std::endl;
+
+ if(Dump.isOn("state")) {
+ Dump("state") << AssertCommand(fact.assertion.toExpr());
+ }
+
+ // if quantifiers are turned on and we have an instantiator, notify it
+ if(getLogicInfo().isQuantified() && getInstantiator() != NULL) {
+ getInstantiator()->assertNode(fact);
+ }
+
+ return fact;
+}
+
}/* CVC4::theory namespace */
inline std::ostream& operator<<(std::ostream& out,
diff --git a/src/theory/theory_engine.cpp b/src/theory/theory_engine.cpp
index 97c17222c..7ea9e063e 100644
--- a/src/theory/theory_engine.cpp
+++ b/src/theory/theory_engine.cpp
@@ -32,6 +32,9 @@
#include "util/node_visitor.h"
#include "util/ite_removal.h"
+#include "theory/quantifiers_engine.h"
+#include "theory/quantifiers/theory_quantifiers.h"
+
using namespace std;
using namespace CVC4;
@@ -46,6 +49,7 @@ TheoryEngine::TheoryEngine(context::Context* context,
d_userContext(userContext),
d_logicInfo(logicInfo),
d_sharedTerms(this, context),
+ d_quantEngine(NULL),
d_ppCache(),
d_possiblePropagations(context),
d_hasPropagated(context),
@@ -69,6 +73,10 @@ TheoryEngine::TheoryEngine(context::Context* context,
d_theoryTable[theoryId] = NULL;
d_theoryOut[theoryId] = NULL;
}
+
+ // initialize the quantifiers engine
+ d_quantEngine = new QuantifiersEngine(context, this);
+
Rewriter::init();
StatisticsRegistry::registerStat(&d_combineTheoriesTime);
d_true = NodeManager::currentNM()->mkConst<bool>(true);
@@ -85,6 +93,8 @@ TheoryEngine::~TheoryEngine() {
}
}
+ delete d_quantEngine;
+
StatisticsRegistry::unregisterStat(&d_combineTheoriesTime);
}
@@ -320,6 +330,22 @@ void TheoryEngine::check(Theory::Effort effort) {
}
}
+ // Must consult quantifiers theory for last call to ensure sat, or otherwise add a lemma
+ if( effort == Theory::EFFORT_FULL &&
+ d_logicInfo.isQuantified() &&
+ ! d_inConflict &&
+ ! d_lemmasAdded ) {
+ ((theory::quantifiers::TheoryQuantifiers*) d_theoryTable[THEORY_QUANTIFIERS])->performCheck(Theory::EFFORT_LAST_CALL);
+ // if we have given up, then possibly flip decision
+ if(Options::current()->flipDecision) {
+ if(d_incomplete && !d_inConflict && !d_lemmasAdded) {
+ if( ((theory::quantifiers::TheoryQuantifiers*) d_theoryTable[THEORY_QUANTIFIERS])->flipDecision() ) {
+ d_incomplete = false;
+ }
+ }
+ }
+ }
+
Debug("theory") << "TheoryEngine::check(" << effort << "): done, we are " << (d_inConflict ? "unsat" : "sat") << (d_lemmasAdded ? " with new lemmas" : " with no new lemmas") << std::endl;
} catch(const theory::Interrupted&) {
@@ -596,7 +622,7 @@ void TheoryEngine::shutdown() {
// Shutdown all the theories
for(TheoryId theoryId = theory::THEORY_FIRST; theoryId < theory::THEORY_LAST; ++theoryId) {
if(d_theoryTable[theoryId]) {
- theoryOf(static_cast<TheoryId>(theoryId))->shutdown();
+ theoryOf(theoryId)->shutdown();
}
}
@@ -624,15 +650,21 @@ Node TheoryEngine::ppTheoryRewrite(TNode term)
return theoryOf(term)->ppRewrite(term);
}
Trace("theory-pp") << "ppTheoryRewrite { " << term << endl;
- NodeBuilder<> newNode(term.getKind());
- if (term.getMetaKind() == kind::metakind::PARAMETERIZED) {
- newNode << term.getOperator();
- }
- unsigned i;
- for (i = 0; i < nc; ++i) {
- newNode << ppTheoryRewrite(term[i]);
+
+ Node newTerm;
+ if (theoryOf(term)->ppDontRewriteSubterm(term)) {
+ newTerm = term;
+ } else {
+ NodeBuilder<> newNode(term.getKind());
+ if (term.getMetaKind() == kind::metakind::PARAMETERIZED) {
+ newNode << term.getOperator();
+ }
+ unsigned i;
+ for (i = 0; i < nc; ++i) {
+ newNode << ppTheoryRewrite(term[i]);
+ }
+ newTerm = Rewriter::rewrite(Node(newNode));
}
- Node newTerm = Rewriter::rewrite(Node(newNode));
Node newTerm2 = theoryOf(newTerm)->ppRewrite(newTerm);
if (newTerm != newTerm2) {
newTerm = ppTheoryRewrite(Rewriter::rewrite(newTerm2));
diff --git a/src/theory/theory_engine.h b/src/theory/theory_engine.h
index ed95149b3..ff7648843 100644
--- a/src/theory/theory_engine.h
+++ b/src/theory/theory_engine.h
@@ -72,6 +72,10 @@ struct NodeTheoryPairHashFunction {
}
};/* struct NodeTheoryPairHashFunction */
+namespace theory {
+ class Instantiator;
+}/* CVC4::theory namespace */
+
/**
* This is essentially an abstraction for a collection of theories. A
* TheoryEngine provides services to a PropEngine, making various
@@ -115,6 +119,11 @@ class TheoryEngine {
*/
SharedTermsDatabase d_sharedTerms;
+ /**
+ * The quantifiers engine
+ */
+ theory::QuantifiersEngine* d_quantEngine;
+
typedef std::hash_map<Node, Node, NodeHashFunction> NodeMap;
typedef std::hash_map<TNode, Node, TNodeHashFunction> TNodeMap;
@@ -151,18 +160,22 @@ class TheoryEngine {
public:
- IntStat conflicts, propagations, lemmas, propagationsAsDecisions;
+ IntStat conflicts, propagations, lemmas, propagationsAsDecisions, requirePhase, flipDecision;
Statistics(theory::TheoryId theory):
conflicts(mkName("theory<", theory, ">::conflicts"), 0),
propagations(mkName("theory<", theory, ">::propagations"), 0),
lemmas(mkName("theory<", theory, ">::lemmas"), 0),
- propagationsAsDecisions(mkName("theory<", theory, ">::propagationsAsDecisions"), 0)
+ propagationsAsDecisions(mkName("theory<", theory, ">::propagationsAsDecisions"), 0),
+ requirePhase(mkName("theory<", theory, ">::requirePhase"), 0),
+ flipDecision(mkName("theory<", theory, ">::flipDecision"), 0)
{
StatisticsRegistry::registerStat(&conflicts);
StatisticsRegistry::registerStat(&propagations);
StatisticsRegistry::registerStat(&lemmas);
StatisticsRegistry::registerStat(&propagationsAsDecisions);
+ StatisticsRegistry::registerStat(&requirePhase);
+ StatisticsRegistry::registerStat(&flipDecision);
}
~Statistics() {
@@ -170,6 +183,8 @@ class TheoryEngine {
StatisticsRegistry::unregisterStat(&propagations);
StatisticsRegistry::unregisterStat(&lemmas);
StatisticsRegistry::unregisterStat(&propagationsAsDecisions);
+ StatisticsRegistry::unregisterStat(&requirePhase);
+ StatisticsRegistry::unregisterStat(&flipDecision);
}
};/* class TheoryEngine::Statistics */
@@ -234,6 +249,21 @@ class TheoryEngine {
return d_engine->lemma(lemma, false, removable);
}
+ void requirePhase(TNode n, bool phase)
+ throw(theory::Interrupted, AssertionException) {
+ Debug("theory") << "EngineOutputChannel::requirePhase("
+ << n << ", " << phase << ")" << std::endl;
+ ++ d_statistics.requirePhase;
+ d_engine->d_propEngine->requirePhase(n, phase);
+ }
+
+ bool flipDecision()
+ throw(theory::Interrupted, AssertionException) {
+ Debug("theory") << "EngineOutputChannel::flipDecision()" << std::endl;
+ ++ d_statistics.flipDecision;
+ return d_engine->d_propEngine->flipDecision();
+ }
+
void setIncomplete() throw(AssertionException) {
d_engine->setIncomplete(d_theory);
}
@@ -380,7 +410,7 @@ public:
inline void addTheory(theory::TheoryId theoryId) {
Assert(d_theoryTable[theoryId] == NULL && d_theoryOut[theoryId] == NULL);
d_theoryOut[theoryId] = new EngineOutputChannel(this, theoryId);
- d_theoryTable[theoryId] = new TheoryClass(d_context, d_userContext, *d_theoryOut[theoryId], theory::Valuation(this), d_logicInfo);
+ d_theoryTable[theoryId] = new TheoryClass(d_context, d_userContext, *d_theoryOut[theoryId], theory::Valuation(this), d_logicInfo, getQuantifiersEngine());
}
inline void setPropEngine(prop::PropEngine* propEngine) {
@@ -400,6 +430,13 @@ public:
return d_propEngine;
}
+ /**
+ * Get a pointer to the underlying quantifiers engine.
+ */
+ theory::QuantifiersEngine* getQuantifiersEngine() const {
+ return d_quantEngine;
+ }
+
private:
/**
@@ -610,6 +647,11 @@ public:
return d_theoryTable[theoryId];
}
+ /** Get the theory for id */
+ theory::Theory* getTheory(int id) {
+ return d_theoryTable[id];
+ }
+
/**
* Returns the equality status of the two terms, from the theory
* that owns the domain type. The types of a and b must be the same.
diff --git a/src/theory/theory_test_utils.h b/src/theory/theory_test_utils.h
index bf1370090..44f009bc0 100644
--- a/src/theory/theory_test_utils.h
+++ b/src/theory/theory_test_utils.h
@@ -94,6 +94,13 @@ public:
return LemmaStatus(Node::null(), 0);
}
+ void requirePhase(TNode, bool) throw(Interrupted, AssertionException) {
+ }
+
+ bool flipDecision() throw(Interrupted, AssertionException) {
+ return true;
+ }
+
void setIncomplete() throw(AssertionException) {}
void clear() {
diff --git a/src/theory/trigger.cpp b/src/theory/trigger.cpp
new file mode 100644
index 000000000..d665fef91
--- /dev/null
+++ b/src/theory/trigger.cpp
@@ -0,0 +1,555 @@
+/********************* */
+/*! \file trigger.cpp
+ ** \verbatim
+ ** Original author: ajreynol
+ ** Major contributors: none
+ ** Minor contributors (to current version): none
+ ** This file is part of the CVC4 prototype.
+ ** Copyright (c) 2009, 2010, 2011 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
+ ** information.\endverbatim
+ **
+ ** \brief Implementation of trigger class
+ **/
+
+#include "theory/trigger.h"
+#include "theory/theory_engine.h"
+#include "theory/quantifiers_engine.h"
+#include "theory/uf/theory_uf_instantiator.h"
+#include "theory/uf/theory_uf_candidate_generator.h"
+#include "theory/uf/equality_engine.h"
+
+using namespace std;
+using namespace CVC4;
+using namespace CVC4::kind;
+using namespace CVC4::context;
+using namespace CVC4::theory;
+
+//#define NESTED_PATTERN_SELECTION
+
+Trigger* Trigger::TrTrie::getTrigger2( std::vector< Node >& nodes ){
+ if( nodes.empty() ){
+ return d_tr;
+ }else{
+ Node n = nodes.back();
+ nodes.pop_back();
+ if( d_children.find( n )!=d_children.end() ){
+ return d_children[n]->getTrigger2( nodes );
+ }else{
+ return NULL;
+ }
+ }
+}
+void Trigger::TrTrie::addTrigger2( std::vector< Node >& nodes, Trigger* t ){
+ if( nodes.empty() ){
+ d_tr = t;
+ }else{
+ Node n = nodes.back();
+ nodes.pop_back();
+ if( d_children.find( n )==d_children.end() ){
+ d_children[n] = new TrTrie;
+ }
+ d_children[n]->addTrigger2( nodes, t );
+ }
+}
+
+/** trigger static members */
+std::map< TNode, std::vector< TNode > > Trigger::d_var_contains;
+Trigger::TrTrie Trigger::d_tr_trie;
+
+/** trigger class constructor */
+Trigger::Trigger( QuantifiersEngine* qe, Node f, std::vector< Node >& nodes, int matchOption, bool smartTriggers ) :
+d_quantEngine( qe ), d_f( f ){
+ d_nodes.insert( d_nodes.begin(), nodes.begin(), nodes.end() );
+ if( smartTriggers ){
+ if( d_nodes.size()==1 ){
+ if( isSimpleTrigger( d_nodes[0] ) ){
+ d_mg = new InstMatchGeneratorSimple( f, d_nodes[0] );
+ }else{
+ d_mg = new InstMatchGenerator( d_nodes[0], qe, matchOption );
+ }
+ }else{
+ d_mg = new InstMatchGeneratorMulti( f, d_nodes, qe, matchOption );
+ }
+ }else{
+ d_mg = new InstMatchGenerator( d_nodes, qe, matchOption );
+ }
+ Debug("trigger") << "Trigger for " << f << ": " << std::endl;
+ for( int i=0; i<(int)d_nodes.size(); i++ ){
+ Debug("trigger") << " " << d_nodes[i] << std::endl;
+ }
+ Debug("trigger") << std::endl;
+ if( d_nodes.size()==1 ){
+ if( isSimpleTrigger( d_nodes[0] ) ){
+ ++(qe->d_statistics.d_triggers);
+ }else{
+ ++(qe->d_statistics.d_simple_triggers);
+ }
+ }else{
+ Debug("multi-trigger") << "Multi-trigger " << (*this) << std::endl;
+ //Notice() << "Multi-trigger for " << f << " : " << std::endl;
+ //Notice() << " " << (*this) << std::endl;
+ ++(qe->d_statistics.d_multi_triggers);
+ }
+ //Notice() << "Trigger : " << (*this) << " for " << f << std::endl;
+ if( Options::current()->eagerInstQuant ){
+ Theory* th_uf = qe->getTheoryEngine()->getTheory( theory::THEORY_UF );
+ uf::InstantiatorTheoryUf* ith = (uf::InstantiatorTheoryUf*)th_uf->getInstantiator();
+ for( int i=0; i<(int)d_nodes.size(); i++ ){
+ ith->registerTrigger( this, d_nodes[i].getOperator() );
+ }
+ }
+}
+void Trigger::computeVarContains( Node n ) {
+ if( d_var_contains.find( n )==d_var_contains.end() ){
+ d_var_contains[n].clear();
+ computeVarContains2( n, n );
+ }
+}
+
+void Trigger::computeVarContains2( Node n, Node parent ){
+ if( n.getKind()==INST_CONSTANT ){
+ if( std::find( d_var_contains[parent].begin(), d_var_contains[parent].end(), n )==d_var_contains[parent].end() ){
+ d_var_contains[parent].push_back( n );
+ }
+ }else{
+ for( int i=0; i<(int)n.getNumChildren(); i++ ){
+ computeVarContains2( n[i], parent );
+ }
+ }
+}
+
+void Trigger::resetInstantiationRound(){
+ d_mg->resetInstantiationRound( d_quantEngine );
+}
+
+void Trigger::reset( Node eqc ){
+ d_mg->reset( eqc, d_quantEngine );
+}
+
+bool Trigger::getNextMatch( InstMatch& m ){
+ bool retVal = d_mg->getNextMatch( m, d_quantEngine );
+ //m.makeInternal( d_quantEngine->getEqualityQuery() );
+ return retVal;
+}
+
+bool Trigger::getMatch( Node t, InstMatch& m ){
+ //FIXME: this assumes d_mg is an inst match generator
+ return ((InstMatchGenerator*)d_mg)->getMatch( t, m, d_quantEngine );
+}
+
+int Trigger::addTerm( Node t ){
+ return d_mg->addTerm( d_f, t, d_quantEngine );
+}
+
+int Trigger::addInstantiations( InstMatch& baseMatch, int instLimit, bool addSplits ){
+ int addedLemmas = d_mg->addInstantiations( d_f, baseMatch, d_quantEngine, instLimit, addSplits );
+ if( addedLemmas>0 ){
+ Debug("inst-trigger") << "Added " << addedLemmas << " lemmas, trigger was ";
+ for( int i=0; i<(int)d_nodes.size(); i++ ){
+ Debug("inst-trigger") << d_nodes[i] << " ";
+ }
+ Debug("inst-trigger") << std::endl;
+ }
+ return addedLemmas;
+}
+
+Trigger* Trigger::mkTrigger( QuantifiersEngine* qe, Node f, std::vector< Node >& nodes, int matchOption, bool keepAll, int trOption,
+ bool smartTriggers ){
+ std::vector< Node > trNodes;
+ if( !keepAll ){
+ //only take nodes that contribute variables to the trigger when added
+ std::vector< Node > temp;
+ temp.insert( temp.begin(), nodes.begin(), nodes.end() );
+ std::map< Node, bool > vars;
+ std::map< Node, std::vector< Node > > patterns;
+ for( int i=0; i<(int)temp.size(); i++ ){
+ bool foundVar = false;
+ computeVarContains( temp[i] );
+ for( int j=0; j<(int)d_var_contains[ temp[i] ].size(); j++ ){
+ Node v = d_var_contains[ temp[i] ][j];
+ if( v.getAttribute(InstConstantAttribute())==f ){
+ if( vars.find( v )==vars.end() ){
+ vars[ v ] = true;
+ foundVar = true;
+ }
+ }
+ }
+ if( foundVar ){
+ trNodes.push_back( temp[i] );
+ for( int j=0; j<(int)d_var_contains[ temp[i] ].size(); j++ ){
+ Node v = d_var_contains[ temp[i] ][j];
+ patterns[ v ].push_back( temp[i] );
+ }
+ }
+ }
+ //now, minimalize the trigger
+ for( int i=0; i<(int)trNodes.size(); i++ ){
+ bool keepPattern = false;
+ Node n = trNodes[i];
+ for( int j=0; j<(int)d_var_contains[ n ].size(); j++ ){
+ Node v = d_var_contains[ n ][j];
+ if( patterns[v].size()==1 ){
+ keepPattern = true;
+ break;
+ }
+ }
+ if( !keepPattern ){
+ //remove from pattern vector
+ for( int j=0; j<(int)d_var_contains[ n ].size(); j++ ){
+ Node v = d_var_contains[ n ][j];
+ for( int k=0; k<(int)patterns[v].size(); k++ ){
+ if( patterns[v][k]==n ){
+ patterns[v].erase( patterns[v].begin() + k, patterns[v].begin() + k + 1 );
+ break;
+ }
+ }
+ }
+ //remove from trigger nodes
+ trNodes.erase( trNodes.begin() + i, trNodes.begin() + i + 1 );
+ i--;
+ }
+ }
+ }else{
+ trNodes.insert( trNodes.begin(), nodes.begin(), nodes.end() );
+ }
+
+ //check for duplicate?
+ if( trOption==TR_MAKE_NEW ){
+ //static int trNew = 0;
+ //static int trOld = 0;
+ //Trigger* t = d_tr_trie.getTrigger( trNodes );
+ //if( t ){
+ // trOld++;
+ //}else{
+ // trNew++;
+ //}
+ //if( (trNew+trOld)%100==0 ){
+ // Notice() << "Trigger new old = " << trNew << " " << trOld << std::endl;
+ //}
+ }else{
+ Trigger* t = d_tr_trie.getTrigger( trNodes );
+ if( t ){
+ if( trOption==TR_GET_OLD ){
+ //just return old trigger
+ return t;
+ }else{
+ return NULL;
+ }
+ }
+ }
+ Trigger* t = new Trigger( qe, f, trNodes, matchOption, smartTriggers );
+ d_tr_trie.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( n.getAttribute(InstConstantAttribute())==f ){
+ if( !isAtomicTrigger( n ) && n.getKind()!=INST_CONSTANT ){
+ std::map< Node, Node > coeffs;
+ return getPatternArithmetic( f, n, coeffs );
+ }else{
+ for( int i=0; i<(int)n.getNumChildren(); i++ ){
+ if( !isUsable( n[i], f ) ){
+ return false;
+ }
+ }
+ return true;
+ }
+ }else{
+ return true;
+ }
+}
+
+bool Trigger::isUsableTrigger( Node n, Node f ){
+ //return n.getAttribute(InstConstantAttribute())==f && n.getKind()==APPLY_UF;
+ return n.getAttribute(InstConstantAttribute())==f && isAtomicTrigger( n ) && isUsable( n, f );
+}
+
+bool Trigger::isAtomicTrigger( Node n ){
+ return n.getKind()==APPLY_UF || n.getKind()==SELECT || n.getKind()==STORE;
+}
+bool Trigger::isSimpleTrigger( Node n ){
+ if( isAtomicTrigger( n ) ){
+ for( int i=0; i<(int)n.getNumChildren(); i++ ){
+ if( n[i].getKind()!=INST_CONSTANT && n[i].hasAttribute(InstConstantAttribute()) ){
+ return false;
+ }
+ }
+ return true;
+ }else{
+ return false;
+ }
+}
+
+/** filter all nodes that have instances */
+void Trigger::filterInstances( std::vector< Node >& nodes ){
+ std::vector< bool > active;
+ active.resize( nodes.size(), true );
+ for( int i=0; i<(int)nodes.size(); i++ ){
+ for( int j=i+1; j<(int)nodes.size(); j++ ){
+ if( active[i] && active[j] ){
+ int result = isInstanceOf( nodes[i], nodes[j] );
+ if( result==1 ){
+ active[j] = false;
+ }else if( result==-1 ){
+ active[i] = false;
+ }
+ }
+ }
+ }
+ std::vector< Node > temp;
+ for( int i=0; i<(int)nodes.size(); i++ ){
+ if( active[i] ){
+ temp.push_back( nodes[i] );
+ }
+ }
+ nodes.clear();
+ nodes.insert( nodes.begin(), temp.begin(), temp.end() );
+}
+
+
+bool Trigger::collectPatTerms2( QuantifiersEngine* qe, Node f, Node n, std::map< Node, bool >& patMap, int tstrt ){
+ if( patMap.find( n )==patMap.end() ){
+ patMap[ n ] = false;
+ if( tstrt==TS_MIN_TRIGGER ){
+ if( n.getKind()==FORALL ){
+#ifdef NESTED_PATTERN_SELECTION
+ //return collectPatTerms2( qe, f, qe->getOrCreateCounterexampleBody( n ), patMap, tstrt );
+ return collectPatTerms2( qe, f, qe->getBoundBody( n ), patMap, tstrt );
+#else
+ return false;
+#endif
+ }else{
+ bool retVal = false;
+ for( int i=0; i<(int)n.getNumChildren(); i++ ){
+ if( collectPatTerms2( qe, f, n[i], patMap, tstrt ) ){
+ retVal = true;
+ }
+ }
+ if( retVal ){
+ return true;
+ }else if( isUsableTrigger( n, f ) ){
+ patMap[ n ] = true;
+ return true;
+ }else{
+ return false;
+ }
+ }
+ }else{
+ bool retVal = false;
+ if( isUsableTrigger( n, f ) ){
+ patMap[ n ] = true;
+ if( tstrt==TS_MAX_TRIGGER ){
+ return true;
+ }else{
+ retVal = true;
+ }
+ }
+ if( n.getKind()==FORALL ){
+#ifdef NESTED_PATTERN_SELECTION
+ //if( collectPatTerms2( qe, f, qe->getOrCreateCounterexampleBody( n ), patMap, tstrt ) ){
+ // retVal = true;
+ //}
+ if( collectPatTerms2( qe, f, qe->getBoundBody( n ), patMap, tstrt ) ){
+ retVal = true;
+ }
+#endif
+ }else{
+ for( int i=0; i<(int)n.getNumChildren(); i++ ){
+ if( collectPatTerms2( qe, f, n[i], patMap, tstrt ) ){
+ retVal = true;
+ }
+ }
+ }
+ return retVal;
+ }
+ }else{
+ return patMap[ n ];
+ }
+}
+
+void Trigger::collectPatTerms( QuantifiersEngine* qe, Node f, Node n, std::vector< Node >& patTerms, int tstrt, 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 );
+ std::vector< Node > temp;
+ temp.insert( temp.begin(), patTerms2.begin(), patTerms2.end() );
+ filterInstances( temp );
+ if( temp.size()!=patTerms2.size() ){
+ Debug("trigger-filter-instance") << "Filtered an instance: " << std::endl;
+ Debug("trigger-filter-instance") << "Old: ";
+ for( int i=0; i<(int)patTerms2.size(); i++ ){
+ Debug("trigger-filter-instance") << patTerms2[i] << " ";
+ }
+ Debug("trigger-filter-instance") << std::endl << "New: ";
+ for( int i=0; i<(int)temp.size(); i++ ){
+ Debug("trigger-filter-instance") << temp[i] << " ";
+ }
+ Debug("trigger-filter-instance") << std::endl;
+ }
+ if( tstrt==TS_ALL ){
+ patTerms.insert( patTerms.begin(), temp.begin(), temp.end() );
+ return;
+ }else{
+ //do not consider terms that have instances
+ for( int i=0; i<(int)patTerms2.size(); i++ ){
+ if( std::find( temp.begin(), temp.end(), patTerms2[i] )==temp.end() ){
+ patMap[ patTerms2[i] ] = false;
+ }
+ }
+ }
+ }
+ collectPatTerms2( qe, f, n, patMap, tstrt );
+ for( std::map< Node, bool >::iterator it = patMap.begin(); it != patMap.end(); ++it ){
+ if( it->second ){
+ patTerms.push_back( it->first );
+ }
+ }
+}
+
+/** is n1 an instance of n2 or vice versa? */
+int Trigger::isInstanceOf( Node n1, Node n2 ){
+ if( n1==n2 ){
+ return 1;
+ }else if( n1.getKind()==n2.getKind() ){
+ if( n1.getKind()==APPLY_UF ){
+ if( n1.getOperator()==n2.getOperator() ){
+ int result = 0;
+ for( int i=0; i<(int)n1.getNumChildren(); i++ ){
+ if( n1[i]!=n2[i] ){
+ int cResult = isInstanceOf( n1[i], n2[i] );
+ if( cResult==0 ){
+ return 0;
+ }else if( cResult!=result ){
+ if( result!=0 ){
+ return 0;
+ }else{
+ result = cResult;
+ }
+ }
+ }
+ }
+ return result;
+ }
+ }
+ return 0;
+ }else if( n2.getKind()==INST_CONSTANT ){
+ computeVarContains( n1 );
+ //if( std::find( d_var_contains[ n1 ].begin(), d_var_contains[ n1 ].end(), n2 )!=d_var_contains[ n1 ].end() ){
+ // return 1;
+ //}
+ if( d_var_contains[ n1 ].size()==1 && d_var_contains[ n1 ][ 0 ]==n2 ){
+ return 1;
+ }
+ }else if( n1.getKind()==INST_CONSTANT ){
+ computeVarContains( n2 );
+ //if( std::find( d_var_contains[ n2 ].begin(), d_var_contains[ n2 ].end(), n1 )!=d_var_contains[ n2 ].end() ){
+ // return -1;
+ //}
+ if( d_var_contains[ n2 ].size()==1 && d_var_contains[ n2 ][ 0 ]==n1 ){
+ return 1;
+ }
+ }
+ return 0;
+}
+
+bool Trigger::isVariableSubsume( Node n1, Node n2 ){
+ if( n1==n2 ){
+ return true;
+ }else{
+ //Notice() << "is variable subsume ? " << n1 << " " << n2 << std::endl;
+ computeVarContains( n1 );
+ computeVarContains( n2 );
+ for( int i=0; i<(int)d_var_contains[n2].size(); i++ ){
+ if( std::find( d_var_contains[n1].begin(), d_var_contains[n1].end(), d_var_contains[n2][i] )==d_var_contains[n1].end() ){
+ //Notice() << "no" << std::endl;
+ return false;
+ }
+ }
+ //Notice() << "yes" << std::endl;
+ return true;
+ }
+}
+
+void Trigger::getVarContains( Node f, std::vector< Node >& pats, std::map< Node, std::vector< Node > >& varContains ){
+ for( int i=0; i<(int)pats.size(); i++ ){
+ computeVarContains( pats[i] );
+ varContains[ pats[i] ].clear();
+ for( int j=0; j<(int)d_var_contains[pats[i]].size(); j++ ){
+ if( d_var_contains[pats[i]][j].getAttribute(InstConstantAttribute())==f ){
+ varContains[ pats[i] ].push_back( d_var_contains[pats[i]][j] );
+ }
+ }
+ }
+}
+
+void Trigger::getVarContainsNode( Node f, Node n, std::vector< Node >& varContains ){
+ computeVarContains( n );
+ for( int j=0; j<(int)d_var_contains[n].size(); j++ ){
+ if( d_var_contains[n][j].getAttribute(InstConstantAttribute())==f ){
+ varContains.push_back( d_var_contains[n][j] );
+ }
+ }
+}
+
+bool Trigger::getPatternArithmetic( 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++ ){
+ if( n[i].hasAttribute(InstConstantAttribute()) ){
+ if( n[i].getKind()==INST_CONSTANT ){
+ if( n[i].getAttribute(InstConstantAttribute())==f ){
+ coeffs[ n[i] ] = Node::null();
+ }else{
+ coeffs.clear();
+ return false;
+ }
+ }else if( !getPatternArithmetic( 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 && n[0].getAttribute(InstConstantAttribute())==f ){
+ Assert( !n[1].hasAttribute(InstConstantAttribute()) );
+ coeffs[ n[0] ] = n[1];
+ return true;
+ }else if( n[1].getKind()==INST_CONSTANT && n[1].getAttribute(InstConstantAttribute())==f ){
+ Assert( !n[0].hasAttribute(InstConstantAttribute()) );
+ coeffs[ n[1] ] = n[0];
+ return true;
+ }
+ }
+ return false;
+}
diff --git a/src/theory/trigger.h b/src/theory/trigger.h
new file mode 100644
index 000000000..457df0ab4
--- /dev/null
+++ b/src/theory/trigger.h
@@ -0,0 +1,170 @@
+/********************* */
+/*! \file trigger.h
+ ** \verbatim
+ ** Original author: ajreynol
+ ** Major contributors: none
+ ** Minor contributors (to current version): none
+ ** This file is part of the CVC4 prototype.
+ ** Copyright (c) 2009, 2010, 2011 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
+ ** information.\endverbatim
+ **
+ ** \brief trigger class
+ **/
+
+#include "cvc4_private.h"
+
+#ifndef __CVC4__TRIGGER_H
+#define __CVC4__TRIGGER_H
+
+#include "theory/inst_match.h"
+
+namespace CVC4 {
+namespace theory {
+
+//a collect of nodes representing a trigger
+class Trigger {
+private:
+ /** computation of variable contains */
+ static std::map< TNode, std::vector< TNode > > d_var_contains;
+ static void computeVarContains( Node n );
+ static void computeVarContains2( Node n, Node parent );
+private:
+ /** the quantifiers engine */
+ QuantifiersEngine* d_quantEngine;
+ /** the quantifier this trigger is for */
+ Node d_f;
+ /** match generators */
+ IMGenerator* d_mg;
+private:
+ /** a trie of triggers */
+ class TrTrie {
+ private:
+ Trigger* getTrigger2( std::vector< Node >& nodes );
+ void addTrigger2( std::vector< Node >& nodes, Trigger* t );
+ public:
+ TrTrie() : d_tr( NULL ){}
+ Trigger* d_tr;
+ std::map< TNode, TrTrie* > d_children;
+ Trigger* getTrigger( std::vector< Node >& nodes ){
+ std::vector< Node > temp;
+ temp.insert( temp.begin(), nodes.begin(), nodes.end() );
+ std::sort( temp.begin(), temp.end() );
+ return getTrigger2( temp );
+ }
+ void addTrigger( std::vector< Node >& nodes, Trigger* t ){
+ std::vector< Node > temp;
+ temp.insert( temp.begin(), nodes.begin(), nodes.end() );
+ std::sort( temp.begin(), temp.end() );
+ return addTrigger2( temp, t );
+ }
+ };/* class Trigger::TrTrie */
+ /** all triggers will be stored in this trie */
+ static TrTrie d_tr_trie;
+private:
+ /** trigger constructor */
+ Trigger( QuantifiersEngine* ie, Node f, std::vector< Node >& nodes, int matchOption = 0, bool smartTriggers = false );
+public:
+ ~Trigger(){}
+public:
+ std::vector< Node > d_nodes;
+public:
+ void debugPrint( const char* c );
+ IMGenerator* getGenerator() { return d_mg; }
+public:
+ /** reset instantiation round (call this whenever equivalence classes have changed) */
+ void resetInstantiationRound();
+ /** reset, eqc is the equivalence class to search in (search in any if eqc=null) */
+ void reset( Node eqc );
+ /** get next match. must call reset( eqc ) once before this function. */
+ bool getNextMatch( InstMatch& m );
+ /** get the match against ground term or formula t.
+ the trigger and t should have the same shape.
+ Currently the trigger should not be a multi-trigger.
+ */
+ bool getMatch( Node t, InstMatch& m);
+ /** add ground term t, called when t is added to the TermDb */
+ int addTerm( Node t );
+ /** return true if whatever Node is subsituted for the variables the
+ given Node can't match the pattern */
+ bool nonunifiable( TNode t, const std::vector<Node> & vars){
+ return d_mg->nonunifiable(t,vars);
+ }
+ /** return whether this is a multi-trigger */
+ bool isMultiTrigger() { return d_nodes.size()>1; }
+public:
+ /** add all available instantiations exhaustively, in any equivalence class
+ if limitInst>0, limitInst is the max # of instantiations to try */
+ int addInstantiations( InstMatch& baseMatch, int instLimit = 0, bool addSplits = false );
+ /** mkTrigger method
+ ie : quantifier engine;
+ f : forall something ....
+ nodes : (multi-)trigger
+ matchOption : which policy to use for creating matches (one of InstMatchGenerator::MATCH_GEN_* )
+ keepAll: don't remove unneeded patterns;
+ trOption : policy for dealing with triggers that already existed (see below)
+ */
+ enum{
+ TR_MAKE_NEW, //make new trigger even if it already may exist
+ TR_GET_OLD, //return a previous trigger if it had already been created
+ TR_RETURN_NULL //return null if a duplicate is found
+ };
+ static Trigger* mkTrigger( QuantifiersEngine* qe, Node f, std::vector< Node >& nodes,
+ int matchOption = 0, bool keepAll = true, int trOption = TR_MAKE_NEW,
+ bool smartTriggers = false );
+ static Trigger* mkTrigger( QuantifiersEngine* qe, Node f, Node n,
+ int matchOption = 0, bool keepAll = true, int trOption = TR_MAKE_NEW,
+ bool smartTriggers = false );
+private:
+ /** is subterm of trigger usable */
+ static bool isUsable( Node n, Node f );
+ /** 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 );
+public:
+ //different strategies for choosing trigger terms
+ enum {
+ TS_MAX_TRIGGER = 0,
+ TS_MIN_TRIGGER,
+ TS_ALL,
+ };
+ static void collectPatTerms( QuantifiersEngine* qe, Node f, Node n, std::vector< Node >& patTerms, int tstrt, 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 isSimpleTrigger( Node n );
+ /** filter all nodes that have instances */
+ static void filterInstances( std::vector< Node >& nodes );
+ /** -1: n1 is an instance of n2, 1: n1 is an instance of n2 */
+ static int isInstanceOf( Node n1, Node n2 );
+ /** variables subsume, return true if n1 contains all free variables in n2 */
+ static bool isVariableSubsume( Node n1, Node n2 );
+ /** get var contains */
+ static void getVarContains( Node f, std::vector< Node >& pats, std::map< Node, std::vector< Node > >& varContains );
+ static void getVarContainsNode( Node f, Node n, std::vector< Node >& varContains );
+ /** get pattern arithmetic */
+ static bool getPatternArithmetic( Node f, Node n, std::map< Node, Node >& coeffs );
+
+ inline void toStream(std::ostream& out) const {
+ out << "TRIGGER( ";
+ for( int i=0; i<(int)d_nodes.size(); i++ ){
+ if( i>0 ){ out << ", "; }
+ out << d_nodes[i];
+ }
+ out << " )";
+ }
+};
+
+inline std::ostream& operator<<(std::ostream& out, const Trigger & tr) {
+ tr.toStream(out);
+ return out;
+}
+
+}/* CVC4::theory namespace */
+
+}/* CVC4 namespace */
+
+#endif /* __CVC4__TRIGGER_H */
diff --git a/src/theory/uf/Makefile.am b/src/theory/uf/Makefile.am
index 50147b997..2c9cd3b80 100644
--- a/src/theory/uf/Makefile.am
+++ b/src/theory/uf/Makefile.am
@@ -14,6 +14,14 @@ libuf_la_SOURCES = \
equality_engine_types.h \
equality_engine.cpp \
symmetry_breaker.h \
- symmetry_breaker.cpp
+ symmetry_breaker.cpp \
+ theory_uf_instantiator.h \
+ theory_uf_instantiator.cpp \
+ theory_uf_strong_solver.h \
+ theory_uf_strong_solver.cpp \
+ theory_uf_candidate_generator.h \
+ theory_uf_candidate_generator.cpp \
+ inst_strategy.h \
+ inst_strategy.cpp
EXTRA_DIST = kinds
diff --git a/src/theory/uf/equality_engine.cpp b/src/theory/uf/equality_engine.cpp
index 25645c472..96c8e8b59 100644
--- a/src/theory/uf/equality_engine.cpp
+++ b/src/theory/uf/equality_engine.cpp
@@ -211,6 +211,11 @@ EqualityNodeId EqualityEngine::newNode(TNode node) {
Debug("equality") << d_name << "::eq::newNode(" << node << ") => " << newId << std::endl;
+ // notify e.g. the UF theory strong solver
+ if (d_performNotify) {
+ d_notify.eqNotifyNewClass(node);
+ }
+
return newId;
}
@@ -346,7 +351,12 @@ void EqualityEngine::assertEquality(TNode eq, bool polarity, TNode reason) {
if (hasTerm(eq[0]) && hasTerm(eq[1]) && areDisequal(eq[0], eq[1], false)) {
return;
}
-
+
+ // notify the theory
+ if (d_performNotify) {
+ d_notify.eqNotifyDisequal(eq[0], eq[1], reason);
+ }
+
Debug("equality::trigger") << d_name << "::eq::addEquality(" << eq << "," << (polarity ? "true" : "false") << ")" << std::endl;
assertEqualityInternal(eq, d_false, reason);
@@ -437,6 +447,21 @@ bool EqualityEngine::merge(EqualityNode& class1, EqualityNode& class2, std::vect
EqualityNodeId class1Id = class1.getFind();
EqualityNodeId class2Id = class2.getFind();
+ Node n1 = d_nodes[class1Id];
+ Node n2 = d_nodes[class2Id];
+ EqualityNode cc1 = getEqualityNode(n1);
+ EqualityNode cc2 = getEqualityNode(n2);
+ bool doNotify = false;
+ // notify the theory
+ // the second part of this check is needed due to the internal implementation of this class.
+ // It ensures that we are merging terms and not operators.
+ if (d_performNotify && class1Id==cc1.getFind() && class2Id==cc2.getFind()) {
+ doNotify = true;
+ }
+ if (doNotify) {
+ d_notify.eqNotifyPreMerge(n1, n2);
+ }
+
// Check for constant merges
bool class1isConstant = d_isConstant[class1Id];
bool class2isConstant = d_isConstant[class2Id];
@@ -559,7 +584,12 @@ bool EqualityEngine::merge(EqualityNode& class1, EqualityNode& class2, std::vect
// Now merge the lists
class1.merge<true>(class2);
-
+
+ // notify the theory
+ if (doNotify) {
+ d_notify.eqNotifyPostMerge(n1, n2);
+ }
+
// Go through the trigger term disequalities and propagate
if (!propagateTriggerTermDisequalities(class1OnlyTags, class1triggerRef, class2disequalitiesToNotify)) {
return false;
diff --git a/src/theory/uf/equality_engine.h b/src/theory/uf/equality_engine.h
index 8cf159cd7..cb0c81872 100644
--- a/src/theory/uf/equality_engine.h
+++ b/src/theory/uf/equality_engine.h
@@ -39,6 +39,9 @@ namespace CVC4 {
namespace theory {
namespace eq {
+class EqClassesIterator;
+class EqClassIterator;
+
/**
* Interface for equality engine notifications. All the notifications
* are safe as TNodes, but not necessarily for negations.
@@ -62,7 +65,7 @@ public:
/**
* Notifies about a trigger predicate that became true or false.
*
- * @param predicate the trigger predicate that bacame true or false
+ * @param predicate the trigger predicate that became true or false
* @param value the value of the predicate
*/
virtual bool eqNotifyTriggerPredicate(TNode predicate, bool value) = 0;
@@ -82,10 +85,43 @@ public:
* can do is ask for explanations.
*
* @param t1 a constant term
- * @param t2 a constnat term
+ * @param t2 a constant term
*/
virtual void eqNotifyConstantTermMerge(TNode t1, TNode t2) = 0;
-};
+
+ /**
+ * Notifies about the creation of a new equality class.
+ *
+ * @param t the term forming the new class
+ */
+ virtual void eqNotifyNewClass(TNode t) = 0;
+
+ /**
+ * Notifies about the merge of two classes (just before the merge).
+ *
+ * @param t1 a term
+ * @param t2 a term
+ */
+ virtual void eqNotifyPreMerge(TNode t1, TNode t2) = 0;
+
+ /**
+ * Notifies about the merge of two classes (just after the merge).
+ *
+ * @param t1 a term
+ * @param t2 a term
+ */
+ virtual void eqNotifyPostMerge(TNode t1, TNode t2) = 0;
+
+ /**
+ * Notifies about the disequality of two terms.
+ *
+ * @param t1 a term
+ * @param t2 a term
+ * @param reason the reason
+ */
+ virtual void eqNotifyDisequal(TNode t1, TNode t2, TNode reason) = 0;
+
+};/* class EqualityEngineNotify */
/**
* Implementation of the notification interface that ignores all the
@@ -97,7 +133,11 @@ public:
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) { }
+ void eqNotifyPreMerge(TNode t1, TNode t2) { }
+ void eqNotifyPostMerge(TNode t1, TNode t2) { }
+ void eqNotifyDisequal(TNode t1, TNode t2, TNode reason) { }
+};/* class EqualityEngineNotifyNone */
/**
@@ -106,6 +146,9 @@ public:
*/
class EqualityEngine : public context::ContextNotifyObj {
+ friend class EqClassesIterator;
+ friend class EqClassIterator;
+
/** Default implementation of the notification object */
static EqualityEngineNotifyNone s_notifyNone;
@@ -140,14 +183,14 @@ public:
StatisticsRegistry::unregisterStat(&functionTermsCount);
StatisticsRegistry::unregisterStat(&constantTermsCount);
}
- };
+ };/* struct EqualityEngine::statistics */
/**
* Store the application lookup, with enough information to backtrack
*/
void storeApplicationLookup(FunctionApplication& funNormalized, EqualityNodeId funId);
-private:
+//private:
/** The context we are using */
context::Context* d_context;
@@ -212,7 +255,7 @@ private:
/** Equality constructor */
Equality(EqualityNodeId lhs = null_id, EqualityNodeId rhs = null_id)
: lhs(lhs), rhs(rhs) {}
- };
+ };/* struct EqualityEngine::Equality */
/** The ids of the classes we have merged */
std::vector<Equality> d_assertedEqualities;
@@ -253,7 +296,7 @@ private:
/** The reason of this edge */
TNode getReason() const { return d_reason; }
-};
+ };/* class EqualityEngine::EqualityEdge */
/**
* All the equality edges (twice as many as the number of asserted equalities. If an equality
@@ -268,7 +311,7 @@ private:
std::string edgesToString(EqualityEdgeId edgeId) const;
/**
- * Map from a node to it's first edge in the equality graph. Edges are added to the front of the
+ * Map from a node to its first edge in the equality graph. Edges are added to the front of the
* list which makes the insertion/backtracking easy.
*/
std::vector<EqualityEdgeId> d_equalityGraph;
@@ -297,7 +340,7 @@ private:
*/
bool merge(EqualityNode& class1, EqualityNode& class2, std::vector<TriggerId>& triggers);
- /** Undo the mereg of class2 into class1 */
+ /** Undo the merge of class2 into class1 */
void undoMerge(EqualityNode& class1, EqualityNode& class2, EqualityNodeId class2Id);
/** Backtrack the information if necessary */
@@ -314,7 +357,7 @@ private:
Trigger(EqualityNodeId classId = null_id, TriggerId nextTrigger = null_trigger)
: classId(classId), nextTrigger(nextTrigger) {}
- };
+ };/* struct EqualityEngine::Trigger */
/**
* Vector of triggers. Triggers come in pairs for an
@@ -436,7 +479,7 @@ private:
EqualityNodeId getTrigger(TheoryId tag) const {
return triggers[Theory::setIndex(tag, tags)];
}
- };
+ };/* struct EqualityEngine::TriggerTermSet */
/** Internal tags for creating a new set */
Theory::Set d_newSetTags;
@@ -451,7 +494,7 @@ private:
char* d_triggerDatabase;
/** Allocated size of the trigger term database */
- DefaultSizeType d_triggerDatabaseAllocatedSize ;
+ DefaultSizeType d_triggerDatabaseAllocatedSize;
/** Reference for the trigger terms set */
typedef DefaultSizeType TriggerTermSetRef;
@@ -482,7 +525,7 @@ private:
TriggerTermSetRef oldValue;
TriggerSetUpdate(EqualityNodeId classId = null_id, TriggerTermSetRef oldValue = null_set_id)
: classId(classId), oldValue(oldValue) {}
- };
+ };/* struct EqualityEngine::TriggerSetUpdate */
/**
* List of trigger updates for backtracking.
@@ -685,7 +728,7 @@ public:
* Add term to the set of trigger terms with a corresponding tag. The notify class will get
* notified when two trigger terms with the same tag become equal or dis-equal. The notification
* will not happen on all the terms, but only on the ones that are represent the class. Note that
- * a term can be added more than once with different tags, and each tag apperance will merit
+ * a term can be added more than once with different tags, and each tag appearance will merit
* it's own notification.
*
* @param t the trigger term
@@ -743,7 +786,97 @@ public:
};
-} // Namespace uf
+class EqClassesIterator {
+
+ eq::EqualityEngine* d_ee;
+ size_t d_it;
+
+public:
+
+ EqClassesIterator() { }
+ EqClassesIterator(eq::EqualityEngine* ee) : d_ee(ee) {
+ d_it = 0;
+ if ( d_it < d_ee->d_nodesCount &&
+ d_ee->getRepresentative(d_ee->d_nodes[d_it]) != d_ee->d_nodes[d_it] ) {
+ ++*this;
+ }
+ }
+ Node operator*() {
+ return d_ee->d_nodes[d_it];
+ }
+ bool operator==(const EqClassesIterator& i) {
+ return d_ee == i.d_ee && d_it == i.d_it;
+ }
+ bool operator!=(const EqClassesIterator& i) {
+ return !(*this == i);
+ }
+ EqClassesIterator& operator++() {
+ Node orig = d_ee->d_nodes[d_it];
+ ++d_it;
+ while ( d_it<d_ee->d_nodesCount &&
+ ( d_ee->getRepresentative(d_ee->d_nodes[d_it]) != d_ee->d_nodes[d_it]
+ || d_ee->d_nodes[d_it] == orig ) ) { // this line is necessary for ignoring duplicates
+ ++d_it;
+ }
+ return *this;
+ }
+ EqClassesIterator operator++(int) {
+ EqClassesIterator i = *this;
+ ++*this;
+ return i;
+ }
+ bool isFinished() {
+ return d_it>=d_ee->d_nodesCount;
+ }
+};/* class EqClassesIterator */
+
+class EqClassIterator {
+
+ Node d_rep;
+ eq::EqualityNode d_curr;
+ Node d_curr_node;
+ eq::EqualityEngine* d_ee;
+
+public:
+
+ EqClassIterator() { }
+ EqClassIterator(Node eqc, eq::EqualityEngine* ee) : d_ee(ee) {
+ Assert( d_ee->getRepresentative(eqc) == eqc );
+ d_rep = eqc;
+ d_curr_node = eqc;
+ d_curr = d_ee->getEqualityNode(eqc);
+ }
+ Node operator*() {
+ return d_curr_node;
+ }
+ bool operator==(const EqClassIterator& i) {
+ return d_ee == i.d_ee && d_curr_node == i.d_curr_node;
+ }
+ bool operator!=(const EqClassIterator& i) {
+ return !(*this == i);
+ }
+ EqClassIterator& operator++() {
+ Node next = d_ee->d_nodes[ d_curr.getNext() ];
+ Assert( d_rep==d_ee->getRepresentative(next) );
+ if (d_rep != next) { // we end when we have cycled back to the original representative
+ d_curr_node = next;
+ d_curr = d_ee->getEqualityNode(d_curr.getNext());
+ } else {
+ d_curr_node = Node::null();
+ }
+ return *this;
+ }
+ EqClassIterator operator++(int) {
+ EqClassIterator i = *this;
+ ++*this;
+ return i;
+ }
+ bool isFinished() {
+ return d_curr_node == Node::null();
+ }
+};/* class EqClassIterator */
+
+} // Namespace eq
} // Namespace theory
} // Namespace CVC4
diff --git a/src/theory/uf/inst_strategy.cpp b/src/theory/uf/inst_strategy.cpp
new file mode 100644
index 000000000..2ca2dcb5a
--- /dev/null
+++ b/src/theory/uf/inst_strategy.cpp
@@ -0,0 +1,412 @@
+/********************* */
+/*! \file inst_strategy.cpp
+ ** \verbatim
+ ** Original author: ajreynol
+ ** Major contributors: none
+ ** Minor contributors (to current version): none
+ ** This file is part of the CVC4 prototype.
+ ** Copyright (c) 2009, 2010, 2011 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
+ ** information.\endverbatim
+ **
+ ** \brief Implementation of theory uf instantiation strategies
+ **/
+
+#include "theory/uf/inst_strategy.h"
+
+#include "theory/uf/theory_uf_instantiator.h"
+#include "theory/theory_engine.h"
+#include "theory/uf/theory_uf.h"
+#include "theory/uf/equality_engine.h"
+
+using namespace std;
+using namespace CVC4;
+using namespace CVC4::kind;
+using namespace CVC4::context;
+using namespace CVC4::theory;
+using namespace CVC4::theory::uf;
+
+#define USE_SINGLE_TRIGGER_BEFORE_MULTI_TRIGGER
+//#define MULTI_TRIGGER_FULL_EFFORT_HALF
+#define MULTI_MULTI_TRIGGERS
+
+struct sortQuantifiersForSymbol {
+ QuantifiersEngine* d_qe;
+ bool operator() (Node i, Node j) {
+ int nqfsi = d_qe->getNumQuantifiersForSymbol( i.getOperator() );
+ int nqfsj = d_qe->getNumQuantifiersForSymbol( j.getOperator() );
+ if( nqfsi<nqfsj ){
+ return true;
+ }else if( nqfsi>nqfsj ){
+ return false;
+ }else{
+ return false;
+ }
+ }
+};
+
+
+void InstStrategyCheckCESolved::processResetInstantiationRound( Theory::Effort effort ){
+ for( std::map< Node, bool >::iterator it = d_solved.begin(); it != d_solved.end(); ++it ){
+ calcSolved( it->first );
+ }
+}
+
+int InstStrategyCheckCESolved::process( Node f, Theory::Effort effort, int e, int instLimit ){
+ if( e==0 ){
+ //calc solved if not done so already
+ if( d_solved.find( f )==d_solved.end() ){
+ calcSolved( f );
+ }
+ //check if f is counterexample-solved
+ Debug("quant-uf-strategy") << "Try CE-solved.." << std::endl;
+ if( d_solved[ f ] ){
+ if( d_quantEngine->addInstantiation( f, d_th->d_baseMatch[f] ) ){
+ ++(d_th->d_statistics.d_instantiations_ce_solved);
+ //d_quantEngine->d_hasInstantiated[f] = true;
+ }
+ d_solved[f] = false;
+ }
+ Debug("quant-uf-strategy") << "done." << std::endl;
+ }
+ return STATUS_UNKNOWN;
+}
+
+void InstStrategyCheckCESolved::calcSolved( Node f ){
+ d_th->d_baseMatch[f].clear();
+ d_solved[ f ]= true;
+ //check if instantiation constants are solved for
+ for( int j = 0; j<(int)d_quantEngine->getNumInstantiationConstants( f ); j++ ){
+ Node i = d_quantEngine->getInstantiationConstant( f, j );
+ Node rep = d_th->getInternalRepresentative( i );
+ if( !rep.hasAttribute(InstConstantAttribute()) ){
+ d_th->d_baseMatch[f].d_map[ i ] = rep;
+ }else{
+ d_solved[ f ] = false;
+ }
+ }
+}
+
+void InstStrategyUserPatterns::processResetInstantiationRound( Theory::Effort effort ){
+ //reset triggers
+ for( std::map< Node, std::vector< Trigger* > >::iterator it = d_user_gen.begin(); it != d_user_gen.end(); ++it ){
+ for( int i=0; i<(int)it->second.size(); i++ ){
+ it->second[i]->resetInstantiationRound();
+ it->second[i]->reset( Node::null() );
+ }
+ }
+}
+
+int InstStrategyUserPatterns::process( Node f, Theory::Effort effort, int e, int instLimit ){
+ if( e==0 ){
+ return STATUS_UNFINISHED;
+ }else if( e==1 ){
+ d_counter[f]++;
+ Debug("quant-uf-strategy") << "Try user-provided patterns..." << std::endl;
+ //Notice() << "Try user-provided patterns..." << std::endl;
+ for( int i=0; i<(int)d_user_gen[f].size(); i++ ){
+ bool processTrigger = true;
+ if( effort!=Theory::EFFORT_LAST_CALL && d_user_gen[f][i]->isMultiTrigger() ){
+//#ifdef MULTI_TRIGGER_FULL_EFFORT_HALF
+// processTrigger = d_counter[f]%2==0;
+//#endif
+ }
+ if( processTrigger ){
+ //if( d_user_gen[f][i]->isMultiTrigger() )
+ //Notice() << " Process (user) " << (*d_user_gen[f][i]) << " for " << f << "..." << std::endl;
+ int numInst = d_user_gen[f][i]->addInstantiations( d_th->d_baseMatch[f], instLimit );
+ //if( d_user_gen[f][i]->isMultiTrigger() )
+ //Notice() << " Done, numInst = " << numInst << "." << std::endl;
+ d_th->d_statistics.d_instantiations_user_pattern += numInst;
+ if( d_user_gen[f][i]->isMultiTrigger() ){
+ d_quantEngine->d_statistics.d_multi_trigger_instantiations += numInst;
+ }
+ //d_quantEngine->d_hasInstantiated[f] = true;
+ }
+ }
+ Debug("quant-uf-strategy") << "done." << std::endl;
+ //Notice() << "done" << std::endl;
+ }
+ return STATUS_UNKNOWN;
+}
+
+void InstStrategyUserPatterns::addUserPattern( Node f, Node pat ){
+ //add to generators
+ std::vector< Node > nodes;
+ for( int i=0; i<(int)pat.getNumChildren(); i++ ){
+ nodes.push_back( pat[i] );
+ }
+ if( Trigger::isUsableTrigger( nodes, f ) ){
+ //extend to literal matching
+ d_quantEngine->getPhaseReqTerms( f, nodes );
+ //check match option
+ int matchOption = Options::current()->efficientEMatching ? InstMatchGenerator::MATCH_GEN_EFFICIENT_E_MATCH : 0;
+ d_user_gen[f].push_back( Trigger::mkTrigger( d_quantEngine, f, nodes, matchOption, true, Trigger::TR_MAKE_NEW,
+ Options::current()->smartTriggers ) );
+ }
+}
+
+void InstStrategyAutoGenTriggers::processResetInstantiationRound( Theory::Effort effort ){
+ //reset triggers
+ for( std::map< Node, std::map< Trigger*, bool > >::iterator it = d_auto_gen_trigger.begin(); it != d_auto_gen_trigger.end(); ++it ){
+ for( std::map< Trigger*, bool >::iterator itt = it->second.begin(); itt != it->second.end(); ++itt ){
+ itt->first->resetInstantiationRound();
+ itt->first->reset( Node::null() );
+ }
+ }
+}
+
+int InstStrategyAutoGenTriggers::process( Node f, Theory::Effort effort, int e, int instLimit ){
+ int peffort = f.getNumChildren()==3 ? 2 : 1;
+ //int peffort = f.getNumChildren()==3 ? 2 : 1;
+ //int peffort = 1;
+ if( e<peffort ){
+ return STATUS_UNFINISHED;
+ }else{
+ bool gen = false;
+ if( e==peffort ){
+ if( d_counter.find( f )==d_counter.end() ){
+ d_counter[f] = 0;
+ gen = true;
+ }else{
+ d_counter[f]++;
+ gen = d_regenerate && d_counter[f]%d_regenerate_frequency==0;
+ }
+ }else{
+ gen = true;
+ }
+ if( gen ){
+ generateTriggers( f );
+ }
+ Debug("quant-uf-strategy") << "Try auto-generated triggers... " << d_tr_strategy << " " << e << std::endl;
+ //Notice() << "Try auto-generated triggers..." << std::endl;
+ for( std::map< Trigger*, bool >::iterator itt = d_auto_gen_trigger[f].begin(); itt != d_auto_gen_trigger[f].end(); ++itt ){
+ Trigger* tr = itt->first;
+ if( tr ){
+ bool processTrigger = itt->second;
+ if( effort!=Theory::EFFORT_LAST_CALL && tr->isMultiTrigger() ){
+#ifdef MULTI_TRIGGER_FULL_EFFORT_HALF
+ processTrigger = d_counter[f]%2==0;
+#endif
+ }
+ if( processTrigger ){
+ //if( tr->isMultiTrigger() )
+ Debug("quant-uf-strategy-auto-gen-triggers") << " Process " << (*tr) << "..." << std::endl;
+ int numInst = tr->addInstantiations( d_th->d_baseMatch[f], instLimit );
+ //if( tr->isMultiTrigger() )
+ Debug("quant-uf-strategy-auto-gen-triggers") << " Done, numInst = " << numInst << "." << std::endl;
+ if( d_tr_strategy==Trigger::TS_MIN_TRIGGER ){
+ d_th->d_statistics.d_instantiations_auto_gen_min += numInst;
+ }else{
+ d_th->d_statistics.d_instantiations_auto_gen += numInst;
+ }
+ if( tr->isMultiTrigger() ){
+ d_quantEngine->d_statistics.d_multi_trigger_instantiations += numInst;
+ }
+ //d_quantEngine->d_hasInstantiated[f] = true;
+ }
+ }
+ }
+ Debug("quant-uf-strategy") << "done." << std::endl;
+ //Notice() << "done" << std::endl;
+ }
+ return STATUS_UNKNOWN;
+}
+
+void InstStrategyAutoGenTriggers::generateTriggers( Node f ){
+ Debug("auto-gen-trigger") << "Generate trigger for " << f << std::endl;
+ if( d_patTerms[0].find( f )==d_patTerms[0].end() ){
+ //determine all possible pattern terms based on trigger term selection strategy d_tr_strategy
+ d_patTerms[0][f].clear();
+ d_patTerms[1][f].clear();
+ std::vector< Node > patTermsF;
+ Trigger::collectPatTerms( d_quantEngine, f, d_quantEngine->getCounterexampleBody( f ), patTermsF, d_tr_strategy, true );
+ Debug("auto-gen-trigger") << "Collected pat terms for " << d_quantEngine->getCounterexampleBody( f ) << std::endl;
+ Debug("auto-gen-trigger") << " ";
+ for( int i=0; i<(int)patTermsF.size(); i++ ){
+ Debug("auto-gen-trigger") << patTermsF[i] << " ";
+ }
+ Debug("auto-gen-trigger") << std::endl;
+ //extend to literal matching
+ d_quantEngine->getPhaseReqTerms( f, patTermsF );
+ //sort into single/multi triggers
+ std::map< Node, std::vector< Node > > varContains;
+ Trigger::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() ){
+ d_patTerms[0][f].push_back( it->first );
+ d_is_single_trigger[ it->first ] = true;
+ }else{
+ d_patTerms[1][f].push_back( it->first );
+ d_is_single_trigger[ it->first ] = false;
+ }
+ }
+ d_made_multi_trigger[f] = false;
+ Debug("auto-gen-trigger") << "Single triggers for " << f << " : " << std::endl;
+ Debug("auto-gen-trigger") << " ";
+ for( int i=0; i<(int)d_patTerms[0][f].size(); i++ ){
+ Debug("auto-gen-trigger") << d_patTerms[0][f][i] << " ";
+ }
+ Debug("auto-gen-trigger") << std::endl;
+ Debug("auto-gen-trigger") << "Multi-trigger term pool for " << f << " : " << std::endl;
+ Debug("auto-gen-trigger") << " ";
+ for( int i=0; i<(int)d_patTerms[1][f].size(); i++ ){
+ Debug("auto-gen-trigger") << d_patTerms[1][f][i] << " ";
+ }
+ Debug("auto-gen-trigger") << std::endl;
+ }
+
+ //populate candidate pattern term vector for the current trigger
+ std::vector< Node > patTerms;
+#ifdef USE_SINGLE_TRIGGER_BEFORE_MULTI_TRIGGER
+ //try to add single triggers first
+ for( int i=0; i<(int)d_patTerms[0][f].size(); i++ ){
+ if( !d_single_trigger_gen[d_patTerms[0][f][i]] ){
+ patTerms.push_back( d_patTerms[0][f][i] );
+ }
+ }
+ //if no single triggers exist, add multi trigger terms
+ if( patTerms.empty() ){
+ patTerms.insert( patTerms.begin(), d_patTerms[1][f].begin(), d_patTerms[1][f].end() );
+ }
+#else
+ patTerms.insert( patTerms.begin(), d_patTerms[0][f].begin(), d_patTerms[0][f].end() );
+ patTerms.insert( patTerms.begin(), d_patTerms[1][f].begin(), d_patTerms[1][f].end() );
+#endif
+
+ if( !patTerms.empty() ){
+ Debug("auto-gen-trigger") << "Generate trigger for " << f << std::endl;
+ //sort terms based on relevance
+ if( d_rlv_strategy==RELEVANCE_DEFAULT ){
+ sortQuantifiersForSymbol sqfs;
+ sqfs.d_qe = d_quantEngine;
+ //sort based on # occurrences (this will cause Trigger to select rarer symbols)
+ std::sort( patTerms.begin(), patTerms.end(), sqfs );
+ Debug("relevant-trigger") << "Terms based on relevance: " << std::endl;
+ for( int i=0; i<(int)patTerms.size(); i++ ){
+ Debug("relevant-trigger") << " " << patTerms[i] << " (";
+ Debug("relevant-trigger") << d_quantEngine->getNumQuantifiersForSymbol( patTerms[i].getOperator() ) << ")" << std::endl;
+ }
+ //Notice() << "Terms based on relevance: " << std::endl;
+ //for( int i=0; i<(int)patTerms.size(); i++ ){
+ // Notice() << " " << patTerms[i] << " (";
+ // Notice() << d_quantEngine->getNumQuantifiersForSymbol( patTerms[i].getOperator() ) << ")" << std::endl;
+ //}
+ }
+ //now, generate the trigger...
+ int matchOption = Options::current()->efficientEMatching ? InstMatchGenerator::MATCH_GEN_EFFICIENT_E_MATCH : 0;
+ Trigger* tr = NULL;
+ if( d_is_single_trigger[ patTerms[0] ] ){
+ tr = Trigger::mkTrigger( d_quantEngine, f, patTerms[0], matchOption, false, Trigger::TR_RETURN_NULL,
+ Options::current()->smartTriggers );
+ d_single_trigger_gen[ patTerms[0] ] = true;
+ }else{
+ //if we are re-generating triggers, shuffle based on some method
+ if( d_made_multi_trigger[f] ){
+#ifndef MULTI_MULTI_TRIGGERS
+ return;
+#endif
+ std::random_shuffle( patTerms.begin(), patTerms.end() ); //shuffle randomly
+ }else{
+ d_made_multi_trigger[f] = true;
+ }
+ //will possibly want to get an old trigger
+ tr = Trigger::mkTrigger( d_quantEngine, f, patTerms, matchOption, false, Trigger::TR_GET_OLD,
+ Options::current()->smartTriggers );
+ }
+ if( tr ){
+ if( tr->isMultiTrigger() ){
+ //disable all other multi triggers
+ for( std::map< Trigger*, bool >::iterator it = d_auto_gen_trigger[f].begin(); it != d_auto_gen_trigger[f].end(); ++it ){
+ if( it->first->isMultiTrigger() ){
+ d_auto_gen_trigger[f][ it->first ] = false;
+ }
+ }
+ }
+ //making it during an instantiation round, so must reset
+ if( d_auto_gen_trigger[f].find( tr )==d_auto_gen_trigger[f].end() ){
+ tr->resetInstantiationRound();
+ tr->reset( Node::null() );
+ }
+ d_auto_gen_trigger[f][tr] = true;
+ //if we are generating additional triggers...
+ if( d_generate_additional && d_is_single_trigger[ patTerms[0] ] ){
+ int index = 0;
+ if( index<(int)patTerms.size() ){
+ //Notice() << "check add additional" << std::endl;
+ //check if similar patterns exist, and if so, add them additionally
+ int nqfs_curr = d_quantEngine->getNumQuantifiersForSymbol( patTerms[0].getOperator() );
+ index++;
+ bool success = true;
+ while( success && index<(int)patTerms.size() && d_is_single_trigger[ patTerms[index] ] ){
+ success = false;
+ if( d_quantEngine->getNumQuantifiersForSymbol( patTerms[index].getOperator() )<=nqfs_curr ){
+ d_single_trigger_gen[ patTerms[index] ] = true;
+ Trigger* tr2 = Trigger::mkTrigger( d_quantEngine, f, patTerms[index], matchOption, false, Trigger::TR_RETURN_NULL,
+ Options::current()->smartTriggers );
+ if( tr2 ){
+ //Notice() << "Add additional trigger " << patTerms[index] << std::endl;
+ tr2->resetInstantiationRound();
+ tr2->reset( Node::null() );
+ d_auto_gen_trigger[f][tr2] = true;
+ }
+ success = true;
+ }
+ index++;
+ }
+ //Notice() << "done check add additional" << std::endl;
+ }
+ }
+ }
+ }
+}
+
+#if 0
+
+void InstStrategyAddFailSplits::processResetInstantiationRound( Theory::Effort effort ){
+}
+
+int InstStrategyAddFailSplits::process( Node f, Theory::Effort effort, int e, int instLimit ){
+ if( e<4 ){
+ return STATUS_UNFINISHED;
+ }else{
+ for( std::map< Node, std::map< Node, std::vector< InstMatchGenerator* > > >::iterator it = InstMatchGenerator::d_match_fails.begin();
+ it != InstMatchGenerator::d_match_fails.end(); ++it ){
+ for( std::map< Node, std::vector< InstMatchGenerator* > >::iterator it2 = it->second.begin(); it2 != it->second.end(); ++it2 ){
+ if( !it2->second.empty() ){
+ Node n1 = it->first;
+ Node n2 = it2->first;
+ if( !d_quantEngine->getEqualityQuery()->areEqual( n1, n2 ) && !d_quantEngine->getEqualityQuery()->areDisequal( n1, n2 ) ){
+ d_quantEngine->addSplitEquality( n1, n2, true );
+ }
+ it2->second.clear();
+ }
+ }
+ }
+ return STATUS_UNKNOWN;
+ }
+}
+
+#endif /* 0 */
+
+void InstStrategyFreeVariable::processResetInstantiationRound( Theory::Effort effort ){
+}
+
+int InstStrategyFreeVariable::process( Node f, Theory::Effort effort, int e, int instLimit ){
+ if( e<5 ){
+ return STATUS_UNFINISHED;
+ }else{
+ if( d_guessed.find( f )==d_guessed.end() ){
+ d_guessed[f] = true;
+ Debug("quant-uf-alg") << "Add guessed instantiation" << std::endl;
+ InstMatch m;
+ if( d_quantEngine->addInstantiation( f, m ) ){
+ ++(d_th->d_statistics.d_instantiations_guess);
+ //d_quantEngine->d_hasInstantiated[f] = true;
+ }
+ }
+ return STATUS_UNKNOWN;
+ }
+}
diff --git a/src/theory/uf/inst_strategy.h b/src/theory/uf/inst_strategy.h
new file mode 100644
index 000000000..906169811
--- /dev/null
+++ b/src/theory/uf/inst_strategy.h
@@ -0,0 +1,179 @@
+/********************* */
+/*! \file inst_strategy.h
+ ** \verbatim
+ ** Original author: ajreynol
+ ** Major contributors: none
+ ** Minor contributors (to current version): none
+ ** This file is part of the CVC4 prototype.
+ ** Copyright (c) 2009, 2010, 2011 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
+ ** information.\endverbatim
+ **
+ ** \brief Theory uf instantiation strategies
+ **/
+
+#include "cvc4_private.h"
+
+#ifndef __CVC4__INST_STRATEGY_H
+#define __CVC4__INST_STRATEGY_H
+
+#include "theory/quantifiers_engine.h"
+
+#include "context/context.h"
+#include "context/context_mm.h"
+
+#include "util/stats.h"
+#include "theory/uf/theory_uf.h"
+
+namespace CVC4 {
+namespace theory {
+namespace uf {
+
+class InstantiatorTheoryUf;
+
+//instantiation strategies
+
+class InstStrategyCheckCESolved : public InstStrategy{
+private:
+ /** InstantiatorTheoryUf class */
+ InstantiatorTheoryUf* d_th;
+ /** is solved? */
+ std::map< Node, bool > d_solved;
+ /** calc if f is solved */
+ void calcSolved( Node f );
+ /** process functions */
+ void processResetInstantiationRound( Theory::Effort effort );
+ int process( Node f, Theory::Effort effort, int e, int instLimit );
+public:
+ InstStrategyCheckCESolved( InstantiatorTheoryUf* th, QuantifiersEngine* ie ) :
+ InstStrategy( ie ), d_th( th ){}
+ ~InstStrategyCheckCESolved(){}
+ /** identify */
+ std::string identify() const { return std::string("CheckCESolved"); }
+};/* class InstStrategyCheckCESolved */
+
+class InstStrategyUserPatterns : public InstStrategy{
+private:
+ /** InstantiatorTheoryUf class */
+ InstantiatorTheoryUf* d_th;
+ /** explicitly provided patterns */
+ std::map< Node, std::vector< Trigger* > > d_user_gen;
+ /** counter for quantifiers */
+ std::map< Node, int > d_counter;
+ /** process functions */
+ void processResetInstantiationRound( Theory::Effort effort );
+ int process( Node f, Theory::Effort effort, int e, int instLimit );
+public:
+ InstStrategyUserPatterns( InstantiatorTheoryUf* th, QuantifiersEngine* ie ) :
+ InstStrategy( ie ), d_th( th ){}
+ ~InstStrategyUserPatterns(){}
+public:
+ /** add pattern */
+ void addUserPattern( Node f, Node pat );
+ /** get num patterns */
+ int getNumUserGenerators( Node f ) { return (int)d_user_gen[f].size(); }
+ /** get user pattern */
+ Trigger* getUserGenerator( Node f, int i ) { return d_user_gen[f][ i ]; }
+ /** identify */
+ std::string identify() const { return std::string("UserPatterns"); }
+};/* class InstStrategyUserPatterns */
+
+class InstStrategyAutoGenTriggers : public InstStrategy{
+public:
+ enum {
+ RELEVANCE_NONE,
+ RELEVANCE_DEFAULT,
+ };
+private:
+ /** InstantiatorTheoryUf class */
+ InstantiatorTheoryUf* d_th;
+ /** trigger generation strategy */
+ int d_tr_strategy;
+ /** relevance strategy */
+ int d_rlv_strategy;
+ /** regeneration */
+ bool d_regenerate;
+ int d_regenerate_frequency;
+ /** generate additional triggers */
+ bool d_generate_additional;
+ /** triggers for each quantifier */
+ std::map< Node, std::map< Trigger*, bool > > d_auto_gen_trigger;
+ std::map< Node, int > d_counter;
+ /** single, multi triggers for each quantifier */
+ std::map< Node, std::vector< Node > > d_patTerms[2];
+ std::map< Node, bool > d_is_single_trigger;
+ std::map< Node, bool > d_single_trigger_gen;
+ std::map< Node, bool > d_made_multi_trigger;
+private:
+ /** process functions */
+ void processResetInstantiationRound( Theory::Effort effort );
+ int process( Node f, Theory::Effort effort, int e, int instLimit );
+ /** generate triggers */
+ void generateTriggers( Node f );
+public:
+ InstStrategyAutoGenTriggers( InstantiatorTheoryUf* th, QuantifiersEngine* ie, int tstrt, int rstrt, int rgfr = -1 ) :
+ InstStrategy( ie ), d_th( th ), d_tr_strategy( tstrt ), d_rlv_strategy( rstrt ), d_generate_additional( false ){
+ setRegenerateFrequency( rgfr );
+ }
+ ~InstStrategyAutoGenTriggers(){}
+public:
+ /** get auto-generated trigger */
+ Trigger* getAutoGenTrigger( Node f );
+ /** identify */
+ std::string identify() const { return std::string("AutoGenTriggers"); }
+ /** set regenerate frequency, if fr<0, turn off regenerate */
+ void setRegenerateFrequency( int fr ){
+ if( fr<0 ){
+ d_regenerate = false;
+ }else{
+ d_regenerate_frequency = fr;
+ d_regenerate = true;
+ }
+ }
+ /** set generate additional */
+ void setGenerateAdditional( bool val ) { d_generate_additional = val; }
+};/* class InstStrategyAutoGenTriggers */
+
+#if 0
+
+class InstStrategyAddFailSplits : public InstStrategy{
+private:
+ /** InstantiatorTheoryUf class */
+ InstantiatorTheoryUf* d_th;
+ /** process functions */
+ void processResetInstantiationRound( Theory::Effort effort );
+ int process( Node f, Theory::Effort effort, int e, int instLimit );
+public:
+ InstStrategyAddFailSplits( InstantiatorTheoryUf* th, QuantifiersEngine* ie ) :
+ InstStrategy( ie ), d_th( th ){}
+ ~InstStrategyAddFailSplits(){}
+ /** identify */
+ std::string identify() const { return std::string("AddFailSplits"); }
+};/* class InstStrategyAddFailSplits */
+
+#endif /* 0 */
+
+class InstStrategyFreeVariable : public InstStrategy{
+private:
+ /** InstantiatorTheoryUf class */
+ InstantiatorTheoryUf* d_th;
+ /** guessed instantiations */
+ std::map< Node, bool > d_guessed;
+ /** process functions */
+ void processResetInstantiationRound( Theory::Effort effort );
+ int process( Node f, Theory::Effort effort, int e, int instLimit );
+public:
+ InstStrategyFreeVariable( InstantiatorTheoryUf* th, QuantifiersEngine* ie ) :
+ InstStrategy( ie ), d_th( th ){}
+ ~InstStrategyFreeVariable(){}
+ /** identify */
+ std::string identify() const { return std::string("FreeVariable"); }
+};/* class InstStrategyFreeVariable */
+
+}/* CVC4::theory::uf namespace */
+}/* CVC4::theory namespace */
+}/* CVC4 namespace */
+
+#endif
diff --git a/src/theory/uf/kinds b/src/theory/uf/kinds
index 2de3715e1..ec353dc59 100644
--- a/src/theory/uf/kinds
+++ b/src/theory/uf/kinds
@@ -6,6 +6,7 @@
theory THEORY_UF ::CVC4::theory::uf::TheoryUF "theory/uf/theory_uf.h"
typechecker "theory/uf/theory_uf_type_rules.h"
+instantiator ::CVC4::theory::uf::InstantiatorTheoryUf "theory/uf/theory_uf_instantiator.h"
properties stable-infinite parametric
properties check propagate staticLearning presolve
@@ -15,4 +16,8 @@ parameterized APPLY_UF VARIABLE 1: "uninterpreted function application"
typerule APPLY_UF ::CVC4::theory::uf::UfTypeRule
+operator CARDINALITY_CONSTRAINT 2 "cardinality constraint"
+
+typerule CARDINALITY_CONSTRAINT ::CVC4::theory::uf::CardinalityConstraintTypeRule
+
endtheory
diff --git a/src/theory/uf/symmetry_breaker.cpp b/src/theory/uf/symmetry_breaker.cpp
index 5761ee4f5..26678f21d 100644
--- a/src/theory/uf/symmetry_breaker.cpp
+++ b/src/theory/uf/symmetry_breaker.cpp
@@ -443,6 +443,16 @@ bool SymmetryBreaker::invariantByPermutations(const Permutation& p) {
Assert(p.size() > 1);
+ // check that the types match
+ Permutation::iterator permIt = p.begin();
+ TypeNode type = (*permIt++).getType();
+ do {
+ if(type != (*permIt++).getType()) {
+ Debug("ufsymm") << "UFSYMM types don't match, aborting.." << endl;
+ return false;
+ }
+ } while(permIt != p.end());
+
// check P_swap
vector<Node> subs;
vector<Node> repls;
diff --git a/src/theory/uf/theory_uf.cpp b/src/theory/uf/theory_uf.cpp
index 7583f8ee7..dc7bb7c92 100644
--- a/src/theory/uf/theory_uf.cpp
+++ b/src/theory/uf/theory_uf.cpp
@@ -18,6 +18,8 @@
**/
#include "theory/uf/theory_uf.h"
+#include "theory/uf/theory_uf_instantiator.h"
+#include "theory/uf/theory_uf_strong_solver.h"
using namespace std;
using namespace CVC4;
@@ -25,8 +27,8 @@ using namespace CVC4::theory;
using namespace CVC4::theory::uf;
/** Constructs a new instance of TheoryUF w.r.t. the provided context.*/
-TheoryUF::TheoryUF(context::Context* c, context::UserContext* u, OutputChannel& out, Valuation valuation, const LogicInfo& logicInfo) :
- Theory(THEORY_UF, c, u, out, valuation, logicInfo),
+TheoryUF::TheoryUF(context::Context* c, context::UserContext* u, OutputChannel& out, Valuation valuation, const LogicInfo& logicInfo, QuantifiersEngine* qe) :
+ Theory(THEORY_UF, c, u, out, valuation, logicInfo, qe),
d_notify(*this),
d_equalityEngine(d_notify, c, "theory::uf::TheoryUF"),
d_conflict(c, false),
@@ -36,6 +38,12 @@ TheoryUF::TheoryUF(context::Context* c, context::UserContext* u, OutputChannel&
{
// The kinds we are treating as function application in congruence
d_equalityEngine.addFunctionKind(kind::APPLY_UF);
+
+ if (Options::current()->finiteModelFind) {
+ d_thss = new StrongSolverTheoryUf(c, u, out, this);
+ } else {
+ d_thss = NULL;
+ }
}/* TheoryUF::TheoryUF() */
static Node mkAnd(const std::vector<TNode>& conjunctions) {
@@ -62,29 +70,46 @@ static Node mkAnd(const std::vector<TNode>& conjunctions) {
void TheoryUF::check(Effort level) {
- while (!done() && !d_conflict)
+ while (!done() && !d_conflict)
{
// Get all the assertions
Assertion assertion = get();
TNode fact = assertion.assertion;
Debug("uf") << "TheoryUF::check(): processing " << fact << std::endl;
+ if (d_thss != NULL) {
+ bool isDecision = d_valuation.isSatLiteral(fact) && d_valuation.isDecision(fact);
+ d_thss->assertNode(fact, isDecision);
+ }
// Do the work
bool polarity = fact.getKind() != kind::NOT;
TNode atom = polarity ? fact : fact[0];
if (atom.getKind() == kind::EQUAL) {
d_equalityEngine.assertEquality(atom, polarity, fact);
+ } else if (atom.getKind() == kind::CARDINALITY_CONSTRAINT) {
+ // do nothing
} else {
d_equalityEngine.assertPredicate(atom, polarity, fact);
}
}
+
+ if (d_thss != NULL) {
+ if (! d_conflict) {
+ d_thss->check(level);
+ }
+ }
+
}/* TheoryUF::check() */
void TheoryUF::preRegisterTerm(TNode node) {
Debug("uf") << "TheoryUF::preRegisterTerm(" << node << ")" << std::endl;
+ if (d_thss != NULL) {
+ d_thss->preRegisterTerm(node);
+ }
+
switch (node.getKind()) {
case kind::EQUAL:
// Add the trigger for equality
@@ -124,6 +149,12 @@ bool TheoryUF::propagate(TNode literal) {
return ok;
}/* TheoryUF::propagate(TNode) */
+void TheoryUF::propagate(Effort effort) {
+ if (d_thss != NULL) {
+ return d_thss->propagate(effort);
+ }
+}
+
void TheoryUF::explain(TNode literal, std::vector<TNode>& assumptions) {
// Do the work
bool polarity = literal.getKind() != kind::NOT;
@@ -395,3 +426,54 @@ void TheoryUF::conflict(TNode a, TNode b) {
d_out->conflict(d_conflictNode);
d_conflict = true;
}
+
+void TheoryUF::eqNotifyNewClass(TNode t) {
+ if (d_thss != NULL) {
+ d_thss->newEqClass(t);
+ }
+ // this can be called very early, during initialization
+ if (!getLogicInfo().isLocked() || getLogicInfo().isQuantified()) {
+ ((InstantiatorTheoryUf*) getInstantiator())->newEqClass(t);
+ }
+}
+
+void TheoryUF::eqNotifyPreMerge(TNode t1, TNode t2) {
+ if (getLogicInfo().isQuantified()) {
+ ((InstantiatorTheoryUf*) getInstantiator())->merge(t1, t2);
+ }
+}
+
+void TheoryUF::eqNotifyPostMerge(TNode t1, TNode t2) {
+ if (d_thss != NULL) {
+ d_thss->merge(t1, t2);
+ }
+}
+
+void TheoryUF::eqNotifyDisequal(TNode t1, TNode t2, TNode reason) {
+ if (d_thss != NULL) {
+ d_thss->assertDisequal(t1, t2, reason);
+ }
+ if (getLogicInfo().isQuantified()) {
+ ((InstantiatorTheoryUf*) getInstantiator())->assertDisequal(t1, t2, reason);
+ }
+}
+
+Node TheoryUF::ppRewrite(TNode node) {
+
+ if (node.getKind() != kind::APPLY_UF) {
+ return node;
+ }
+
+ // perform the callbacks requested by TheoryUF::registerPpRewrite()
+ RegisterPpRewrites::iterator c = d_registeredPpRewrites.find(node.getOperator());
+ if (c == d_registeredPpRewrites.end()) {
+ return node;
+ } else {
+ Node res = c->second->ppRewrite(node);
+ if (res != node) {
+ return ppRewrite(res);
+ } else {
+ return res;
+ }
+ }
+}
diff --git a/src/theory/uf/theory_uf.h b/src/theory/uf/theory_uf.h
index eceead38a..a55ef92b5 100644
--- a/src/theory/uf/theory_uf.h
+++ b/src/theory/uf/theory_uf.h
@@ -36,7 +36,15 @@ namespace CVC4 {
namespace theory {
namespace uf {
+class UfTermDb;
+class InstantiatorTheoryUf;
+class StrongSolverTheoryUf;
+
class TheoryUF : public Theory {
+
+ friend class InstantiatorTheoryUf;
+ friend class StrongSolverTheoryUf;
+
public:
class NotifyClass : public eq::EqualityEngineNotify {
@@ -76,13 +84,43 @@ public:
Debug("uf") << "NotifyClass::eqNotifyConstantTermMerge(" << t1 << ", " << t2 << ")" << std::endl;
d_uf.conflict(t1, t2);
}
- };
+
+ void eqNotifyNewClass(TNode t) {
+ Debug("uf") << "NotifyClass::eqNotifyNewClass(" << t << std::endl;
+ d_uf.eqNotifyNewClass(t);
+ }
+
+ void eqNotifyPreMerge(TNode t1, TNode t2) {
+ Debug("uf") << "NotifyClass::eqNotifyPreMerge(" << t1 << ", " << t2 << std::endl;
+ d_uf.eqNotifyPreMerge(t1, t2);
+ }
+
+ void eqNotifyPostMerge(TNode t1, TNode t2) {
+ Debug("uf") << "NotifyClass::eqNotifyPostMerge(" << t1 << ", " << t2 << std::endl;
+ d_uf.eqNotifyPostMerge(t1, t2);
+ }
+
+ void eqNotifyDisequal(TNode t1, TNode t2, TNode reason) {
+ Debug("uf") << "NotifyClass::eqNotifyDisequal(" << t1 << ", " << t2 << ", " << reason << std::endl;
+ d_uf.eqNotifyDisequal(t1, t2, reason);
+ }
+
+ };/* class TheoryUF::NotifyClass */
+
+ /** A callback class for ppRewrite(). See registerPpRewrite(), below. */
+ class PpRewrite {
+ public:
+ virtual Node ppRewrite(TNode node) = 0;
+ };/* class TheoryUF::PpRewrite */
private:
/** The notify class */
NotifyClass d_notify;
+ /** The associated theory strong solver (or NULL if none) */
+ StrongSolverTheoryUf* d_thss;
+
/** Equaltity engine */
eq::EqualityEngine d_equalityEngine;
@@ -118,10 +156,37 @@ private:
/** Conflict when merging two constants */
void conflict(TNode a, TNode b);
+ /** 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);
+
+ /** a registry type for keeping Node-specific callbacks for ppRewrite() */
+ typedef std::hash_map<Node, PpRewrite*, NodeHashFunction> RegisterPpRewrites;
+
+ /** a collection of callbacks to issue while doing a ppRewrite() */
+ RegisterPpRewrites d_registeredPpRewrites;
+
public:
/** Constructs a new instance of TheoryUF w.r.t. the provided context.*/
- TheoryUF(context::Context* c, context::UserContext* u, OutputChannel& out, Valuation valuation, const LogicInfo& logicInfo);
+ TheoryUF(context::Context* c, context::UserContext* u, OutputChannel& out, Valuation valuation, const LogicInfo& logicInfo, QuantifiersEngine* qe);
+
+ ~TheoryUF() {
+ // destruct all ppRewrite() callbacks
+ for(RegisterPpRewrites::iterator i = d_registeredPpRewrites.begin();
+ i != d_registeredPpRewrites.end();
+ ++i) {
+ delete i->second;
+ }
+ }
void check(Effort);
void preRegisterTerm(TNode term);
@@ -133,7 +198,7 @@ public:
void addSharedTerm(TNode n);
void computeCareGraph();
- void propagate(Effort effort) {}
+ void propagate(Effort effort);
EqualityStatus getEqualityStatus(TNode a, TNode b);
@@ -141,6 +206,24 @@ public:
return "THEORY_UF";
}
+ eq::EqualityEngine* getEqualityEngine() {
+ return &d_equalityEngine;
+ }
+
+ StrongSolverTheoryUf* getStrongSolver() {
+ return d_thss;
+ }
+
+ Node ppRewrite(TNode node);
+
+ /**
+ * Register a ppRewrite() callback on "op." TheoryUF owns
+ * the callback, and will delete it when it is destructed.
+ */
+ void registerPpRewrite(TNode op, PpRewrite* callback) {
+ d_registeredPpRewrites.insert(std::make_pair(op, callback));
+ }
+
};/* class TheoryUF */
}/* CVC4::theory::uf namespace */
diff --git a/src/theory/uf/theory_uf_candidate_generator.cpp b/src/theory/uf/theory_uf_candidate_generator.cpp
new file mode 100644
index 000000000..e8aa98aa7
--- /dev/null
+++ b/src/theory/uf/theory_uf_candidate_generator.cpp
@@ -0,0 +1,170 @@
+/********************* */
+/*! \file theory_uf_candidate_generator.cpp
+ ** \verbatim
+ ** Original author: ajreynol
+ ** Major contributors: none
+ ** Minor contributors (to current version): none
+ ** This file is part of the CVC4 prototype.
+ ** Copyright (c) 2009, 2010, 2011 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
+ ** information.\endverbatim
+ **
+ ** \brief Implementation of theory uf candidate generator class
+ **/
+
+#include "theory/uf/theory_uf_candidate_generator.h"
+#include "theory/theory_engine.h"
+#include "theory/uf/theory_uf.h"
+
+using namespace std;
+using namespace CVC4;
+using namespace CVC4::kind;
+using namespace CVC4::context;
+using namespace CVC4::theory;
+using namespace CVC4::theory::uf;
+
+CandidateGeneratorTheoryUf::CandidateGeneratorTheoryUf( InstantiatorTheoryUf* ith, Node op ) :
+ d_op( op ), d_ith( ith ), d_term_iter( -2 ){
+ Assert( !d_op.isNull() );
+}
+void CandidateGeneratorTheoryUf::resetInstantiationRound(){
+ d_term_iter_limit = d_ith->getQuantifiersEngine()->getTermDatabase()->d_op_map[d_op].size();
+}
+
+void CandidateGeneratorTheoryUf::reset( Node eqc ){
+ if( eqc.isNull() ){
+ d_term_iter = 0;
+ }else{
+ //create an equivalence class iterator in eq class eqc
+ if( ((TheoryUF*)d_ith->getTheory())->getEqualityEngine()->hasTerm( eqc ) ){
+ eqc = ((TheoryUF*)d_ith->getTheory())->getEqualityEngine()->getRepresentative( eqc );
+ d_eqc = eq::EqClassIterator( eqc, ((TheoryUF*)d_ith->getTheory())->getEqualityEngine() );
+ d_retNode = Node::null();
+ }else{
+ d_retNode = eqc;
+ }
+ d_term_iter = -1;
+ }
+}
+
+Node CandidateGeneratorTheoryUf::getNextCandidate(){
+ if( d_term_iter>=0 ){
+ //get next candidate term in the uf term database
+ while( d_term_iter<d_term_iter_limit ){
+ Node n = d_ith->getQuantifiersEngine()->getTermDatabase()->d_op_map[d_op][d_term_iter];
+ d_term_iter++;
+ if( isLegalCandidate( n ) ){
+ return n;
+ }
+ }
+ }else if( d_term_iter==-1 ){
+ if( d_retNode.isNull() ){
+ //get next candidate term in equivalence class
+ while( !d_eqc.isFinished() ){
+ Node n = (*d_eqc);
+ ++d_eqc;
+ if( n.getKind()==APPLY_UF && n.getOperator()==d_op ){
+ if( isLegalCandidate( n ) ){
+ return n;
+ }
+ }
+ }
+ }else{
+ Node ret;
+ if( d_retNode.hasOperator() && d_retNode.getOperator()==d_op ){
+ ret = d_retNode;
+ }
+ d_term_iter = -2; //done returning matches
+ return ret;
+ }
+ }
+ return Node::null();
+}
+
+
+//CandidateGeneratorTheoryUfDisequal::CandidateGeneratorTheoryUfDisequal( InstantiatorTheoryUf* ith, Node eqc ) :
+// d_ith( ith ), d_eq_class( eqc ){
+// d_eci = NULL;
+//}
+//void CandidateGeneratorTheoryUfDisequal::resetInstantiationRound(){
+//
+//}
+////we will iterate over all terms that are disequal from eqc
+//void CandidateGeneratorTheoryUfDisequal::reset( Node eqc ){
+// //Assert( !eqc.isNull() );
+// ////begin iterating over equivalence classes that are disequal from eqc
+// //d_eci = d_ith->getEquivalenceClassInfo( eqc );
+// //if( d_eci ){
+// // d_eqci_iter = d_eci->d_disequal.begin();
+// //}
+//}
+//Node CandidateGeneratorTheoryUfDisequal::getNextCandidate(){
+// //if( d_eci ){
+// // while( d_eqci_iter != d_eci->d_disequal.end() ){
+// // if( (*d_eqci_iter).second ){
+// // //we have an equivalence class that is disequal from eqc
+// // d_cg->reset( (*d_eqci_iter).first );
+// // Node n = d_cg->getNextCandidate();
+// // //if there is a candidate in this equivalence class, return it
+// // if( !n.isNull() ){
+// // return n;
+// // }
+// // }
+// // ++d_eqci_iter;
+// // }
+// //}
+// return Node::null();
+//}
+
+
+CandidateGeneratorTheoryUfLitEq::CandidateGeneratorTheoryUfLitEq( InstantiatorTheoryUf* ith, Node mpat ) :
+ d_match_pattern( mpat ), d_ith( ith ){
+
+}
+void CandidateGeneratorTheoryUfLitEq::resetInstantiationRound(){
+
+}
+void CandidateGeneratorTheoryUfLitEq::reset( Node eqc ){
+ d_eq = eq::EqClassesIterator( ((TheoryUF*)d_ith->getTheory())->getEqualityEngine() );
+}
+Node CandidateGeneratorTheoryUfLitEq::getNextCandidate(){
+ while( d_eq.isFinished() ){
+ Node n = (*d_eq);
+ ++d_eq;
+ if( n.getType()==d_match_pattern[0].getType() ){
+ //an equivalence class with the same type as the pattern, return reflexive equality
+ return NodeManager::currentNM()->mkNode( d_match_pattern.getKind(), n, n );
+ }
+ }
+ return Node::null();
+}
+
+
+CandidateGeneratorTheoryUfLitDeq::CandidateGeneratorTheoryUfLitDeq( InstantiatorTheoryUf* ith, Node mpat ) :
+ d_match_pattern( mpat ), d_ith( ith ){
+
+}
+void CandidateGeneratorTheoryUfLitDeq::resetInstantiationRound(){
+
+}
+void CandidateGeneratorTheoryUfLitDeq::reset( Node eqc ){
+ Node false_term = ((TheoryUF*)d_ith->getTheory())->getEqualityEngine()->getRepresentative(
+ NodeManager::currentNM()->mkConst<bool>(false) );
+ d_eqc_false = eq::EqClassIterator( false_term, ((TheoryUF*)d_ith->getTheory())->getEqualityEngine() );
+}
+Node CandidateGeneratorTheoryUfLitDeq::getNextCandidate(){
+ //get next candidate term in equivalence class
+ while( !d_eqc_false.isFinished() ){
+ Node n = (*d_eqc_false);
+ ++d_eqc_false;
+ if( n.getKind()==d_match_pattern.getKind() ){
+ //found an iff or equality, try to match it
+ //DO_THIS: cache to avoid redundancies?
+ //DO_THIS: do we need to try the symmetric equality for n? or will it also exist in the eq class of false?
+ return n;
+ }
+ }
+ return Node::null();
+}
diff --git a/src/theory/uf/theory_uf_candidate_generator.h b/src/theory/uf/theory_uf_candidate_generator.h
new file mode 100644
index 000000000..948573439
--- /dev/null
+++ b/src/theory/uf/theory_uf_candidate_generator.h
@@ -0,0 +1,115 @@
+/********************* */
+/*! \file theory_uf_candidate generator.h
+ ** \verbatim
+ ** Original author: ajreynol
+ ** Major contributors: none
+ ** Minor contributors (to current version): none
+ ** This file is part of the CVC4 prototype.
+ ** Copyright (c) 2009, 2010, 2011 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
+ ** information.\endverbatim
+ **
+ ** \brief Theory uf candidate generator
+ **/
+
+#include "cvc4_private.h"
+
+#ifndef __CVC4__THEORY_UF_CANDIDATE_GENERATOR_H
+#define __CVC4__THEORY_UF_CANDIDATE_GENERATOR_H
+
+#include "theory/quantifiers_engine.h"
+#include "theory/uf/theory_uf_instantiator.h"
+
+namespace CVC4 {
+namespace theory {
+namespace uf {
+
+class CandidateGeneratorTheoryUfDisequal;
+
+class CandidateGeneratorTheoryUf : public CandidateGenerator
+{
+ friend class CandidateGeneratorTheoryUfDisequal;
+private:
+ //operator you are looking for
+ Node d_op;
+ //instantiator pointer
+ InstantiatorTheoryUf* d_ith;
+ //the equality class iterator
+ eq::EqClassIterator d_eqc;
+ int d_term_iter;
+ int d_term_iter_limit;
+private:
+ Node d_retNode;
+public:
+ CandidateGeneratorTheoryUf( InstantiatorTheoryUf* ith, Node op );
+ ~CandidateGeneratorTheoryUf(){}
+
+ void resetInstantiationRound();
+ void reset( Node eqc );
+ Node getNextCandidate();
+};
+
+//class CandidateGeneratorTheoryUfDisequal : public CandidateGenerator
+//{
+//private:
+// //equivalence class
+// Node d_eq_class;
+// //equivalence class info
+// EqClassInfo* d_eci;
+// //equivalence class iterator
+// EqClassInfo::BoolMap::const_iterator d_eqci_iter;
+// //instantiator pointer
+// InstantiatorTheoryUf* d_ith;
+//public:
+// CandidateGeneratorTheoryUfDisequal( InstantiatorTheoryUf* ith, Node eqc );
+// ~CandidateGeneratorTheoryUfDisequal(){}
+//
+// void resetInstantiationRound();
+// void reset( Node eqc ); //should be what you want to be disequal from
+// Node getNextCandidate();
+//};
+
+class CandidateGeneratorTheoryUfLitEq : public CandidateGenerator
+{
+private:
+ //the equality classes iterator
+ eq::EqClassesIterator d_eq;
+ //equality you are trying to match equalities for
+ Node d_match_pattern;
+ //einstantiator pointer
+ InstantiatorTheoryUf* d_ith;
+public:
+ CandidateGeneratorTheoryUfLitEq( InstantiatorTheoryUf* ith, Node mpat );
+ ~CandidateGeneratorTheoryUfLitEq(){}
+
+ void resetInstantiationRound();
+ void reset( Node eqc );
+ Node getNextCandidate();
+};
+
+class CandidateGeneratorTheoryUfLitDeq : public CandidateGenerator
+{
+private:
+ //the equality class iterator for false
+ eq::EqClassIterator d_eqc_false;
+ //equality you are trying to match disequalities for
+ Node d_match_pattern;
+ //einstantiator pointer
+ InstantiatorTheoryUf* d_ith;
+public:
+ CandidateGeneratorTheoryUfLitDeq( InstantiatorTheoryUf* ith, Node mpat );
+ ~CandidateGeneratorTheoryUfLitDeq(){}
+
+ void resetInstantiationRound();
+ void reset( Node eqc );
+ Node getNextCandidate();
+};
+
+
+}
+}/* CVC4::theory namespace */
+}/* CVC4 namespace */
+
+#endif /* __CVC4__THEORY_UF_INSTANTIATOR_H */
diff --git a/src/theory/uf/theory_uf_instantiator.cpp b/src/theory/uf/theory_uf_instantiator.cpp
new file mode 100644
index 000000000..9fdcb5952
--- /dev/null
+++ b/src/theory/uf/theory_uf_instantiator.cpp
@@ -0,0 +1,520 @@
+/********************* */
+/*! \file theory_uf_instantiator.cpp
+ ** \verbatim
+ ** Original author: ajreynol
+ ** Major contributors: none
+ ** Minor contributors (to current version): none
+ ** This file is part of the CVC4 prototype.
+ ** Copyright (c) 2009, 2010, 2011 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
+ ** information.\endverbatim
+ **
+ ** \brief Implementation of theory uf instantiator class
+ **/
+
+#include "theory/uf/theory_uf_instantiator.h"
+#include "theory/theory_engine.h"
+#include "theory/uf/theory_uf.h"
+#include "theory/uf/equality_engine.h"
+//#include "theory/uf/inst_strategy_model_find.h"
+
+using namespace std;
+using namespace CVC4;
+using namespace CVC4::kind;
+using namespace CVC4::context;
+using namespace CVC4::theory;
+using namespace CVC4::theory::uf;
+
+EqClassInfo::EqClassInfo( context::Context* c ) : d_funs( c ), d_pfuns( c ), d_disequal( c ){
+
+}
+
+//set member
+void EqClassInfo::setMember( Node n, TermDb* db ){
+ if( n.getKind()==APPLY_UF ){
+ d_funs[n.getOperator()] = true;
+ }
+ //add parent functions
+ for( std::map< Node, std::map< int, std::vector< Node > > >::iterator it = db->d_parents[n].begin();
+ it != db->d_parents[n].end(); ++it ){
+ d_pfuns[ it->first ] = true;
+ }
+}
+
+//get has function
+bool EqClassInfo::hasFunction( Node op ){
+ return d_funs.find( op )!=d_funs.end();
+}
+
+bool EqClassInfo::hasParent( Node op ){
+ return d_pfuns.find( op )!=d_pfuns.end();
+}
+
+//merge with another eq class info
+void EqClassInfo::merge( EqClassInfo* eci ){
+ for( BoolMap::iterator it = eci->d_funs.begin(); it != eci->d_funs.end(); it++ ) {
+ d_funs[ (*it).first ] = true;
+ }
+ for( BoolMap::iterator it = eci->d_pfuns.begin(); it != eci->d_pfuns.end(); it++ ) {
+ d_pfuns[ (*it).first ] = true;
+ }
+}
+
+InstantiatorTheoryUf::InstantiatorTheoryUf(context::Context* c, CVC4::theory::QuantifiersEngine* qe, Theory* th) :
+Instantiator( c, qe, th )
+{
+ qe->setEqualityQuery( new EqualityQueryInstantiatorTheoryUf( this ) );
+
+ if( Options::current()->finiteModelFind ){
+ //if( Options::current()->cbqi ){
+ // addInstStrategy( new InstStrategyCheckCESolved( this, qe ) );
+ //}
+ //addInstStrategy( new InstStrategyFiniteModelFind( c, this, ((TheoryUF*)th)->getStrongSolver(), qe ) );
+ qe->getTermDatabase()->setMatchingActive( false );
+ }else{
+ if( Options::current()->cbqi ){
+ addInstStrategy( new InstStrategyCheckCESolved( this, qe ) );
+ }
+ if( Options::current()->userPatternsQuant ){
+ d_isup = new InstStrategyUserPatterns( this, qe );
+ addInstStrategy( d_isup );
+ }else{
+ d_isup = NULL;
+ }
+ InstStrategyAutoGenTriggers* i_ag = new InstStrategyAutoGenTriggers( this, qe, Trigger::TS_ALL,
+ InstStrategyAutoGenTriggers::RELEVANCE_DEFAULT, 3 );
+ i_ag->setGenerateAdditional( true );
+ addInstStrategy( i_ag );
+ //addInstStrategy( new InstStrategyAddFailSplits( this, ie ) );
+ addInstStrategy( new InstStrategyFreeVariable( this, qe ) );
+ //d_isup->setPriorityOver( i_ag );
+ //d_isup->setPriorityOver( i_agm );
+ //i_ag->setPriorityOver( i_agm );
+ }
+}
+
+void InstantiatorTheoryUf::preRegisterTerm( Node t ){
+ //d_quantEngine->addTermToDatabase( t );
+}
+
+void InstantiatorTheoryUf::assertNode( Node assertion )
+{
+ Debug("quant-uf-assert") << "InstantiatorTheoryUf::check: " << assertion << std::endl;
+ //preRegisterTerm( assertion );
+ d_quantEngine->addTermToDatabase( assertion );
+ if( Options::current()->cbqi ){
+ if( assertion.hasAttribute(InstConstantAttribute()) ){
+ setHasConstraintsFrom( assertion.getAttribute(InstConstantAttribute()) );
+ }else if( assertion.getKind()==NOT && assertion[0].hasAttribute(InstConstantAttribute()) ){
+ setHasConstraintsFrom( assertion[0].getAttribute(InstConstantAttribute()) );
+ }
+ }
+}
+
+void InstantiatorTheoryUf::addUserPattern( Node f, Node pat ){
+ if( d_isup ){
+ d_isup->addUserPattern( f, pat );
+ }
+ setHasConstraintsFrom( f );
+}
+
+
+void InstantiatorTheoryUf::processResetInstantiationRound( Theory::Effort effort ){
+ d_ground_reps.clear();
+}
+
+int InstantiatorTheoryUf::process( Node f, Theory::Effort effort, int e, int instLimit ){
+ Debug("quant-uf") << "UF: Try to solve (" << e << ") for " << f << "... " << std::endl;
+ return InstStrategy::STATUS_SAT;
+}
+
+void InstantiatorTheoryUf::debugPrint( const char* c )
+{
+
+}
+
+bool InstantiatorTheoryUf::hasTerm( Node a ){
+ return ((TheoryUF*)d_th)->d_equalityEngine.hasTerm( a );
+}
+
+bool InstantiatorTheoryUf::areEqual( Node a, Node b ){
+ if( hasTerm( a ) && hasTerm( b ) ){
+ return ((TheoryUF*)d_th)->d_equalityEngine.areEqual( a, b );
+ }else{
+ return a==b;
+ }
+}
+
+bool InstantiatorTheoryUf::areDisequal( Node a, Node b ){
+ if( hasTerm( a ) && hasTerm( b ) ){
+ return ((TheoryUF*)d_th)->d_equalityEngine.areDisequal( a, b, false );
+ }else{
+ return false;
+ }
+}
+
+Node InstantiatorTheoryUf::getRepresentative( Node a ){
+ if( hasTerm( a ) ){
+ return ((TheoryUF*)d_th)->d_equalityEngine.getRepresentative( a );
+ }else{
+ return a;
+ }
+}
+
+Node InstantiatorTheoryUf::getInternalRepresentative( Node a ){
+ if( d_ground_reps.find( a )==d_ground_reps.end() ){
+ if( !hasTerm( a ) ){
+ return a;
+ }else{
+ Node rep = getRepresentative( a );
+ if( !rep.hasAttribute(InstConstantAttribute()) ){
+ //return the representative of a
+ d_ground_reps[a] = rep;
+ return rep;
+ }else{
+ //otherwise, must search eq class
+ eq::EqClassIterator eqc_iter( rep, &((TheoryUF*)d_th)->d_equalityEngine );
+ rep = Node::null();
+ while( !eqc_iter.isFinished() ){
+ if( !(*eqc_iter).hasAttribute(InstConstantAttribute()) ){
+ d_ground_reps[ a ] = *eqc_iter;
+ return *eqc_iter;
+ }
+ eqc_iter++;
+ }
+ d_ground_reps[ a ] = a;
+ }
+ }
+ }
+ return d_ground_reps[a];
+}
+
+InstantiatorTheoryUf::Statistics::Statistics():
+ //d_instantiations("InstantiatorTheoryUf::Total_Instantiations", 0),
+ d_instantiations_ce_solved("InstantiatorTheoryUf::Instantiations_CE-Solved", 0),
+ d_instantiations_e_induced("InstantiatorTheoryUf::Instantiations_E-Induced", 0),
+ d_instantiations_user_pattern("InstantiatorTheoryUf::Instantiations_User_Pattern", 0),
+ d_instantiations_guess("InstantiatorTheoryUf::Instantiations_Free_Var", 0),
+ d_instantiations_auto_gen("InstantiatorTheoryUf::Instantiations_Auto_Gen", 0),
+ d_instantiations_auto_gen_min("InstantiatorTheoryUf::Instantiations_Auto_Gen_Min", 0),
+ d_splits("InstantiatorTheoryUf::Total_Splits", 0)
+{
+ //StatisticsRegistry::registerStat(&d_instantiations);
+ StatisticsRegistry::registerStat(&d_instantiations_ce_solved);
+ StatisticsRegistry::registerStat(&d_instantiations_e_induced);
+ StatisticsRegistry::registerStat(&d_instantiations_user_pattern );
+ StatisticsRegistry::registerStat(&d_instantiations_guess );
+ StatisticsRegistry::registerStat(&d_instantiations_auto_gen );
+ StatisticsRegistry::registerStat(&d_instantiations_auto_gen_min );
+ StatisticsRegistry::registerStat(&d_splits);
+}
+
+InstantiatorTheoryUf::Statistics::~Statistics(){
+ //StatisticsRegistry::unregisterStat(&d_instantiations);
+ StatisticsRegistry::unregisterStat(&d_instantiations_ce_solved);
+ StatisticsRegistry::unregisterStat(&d_instantiations_e_induced);
+ StatisticsRegistry::unregisterStat(&d_instantiations_user_pattern );
+ StatisticsRegistry::unregisterStat(&d_instantiations_guess );
+ StatisticsRegistry::unregisterStat(&d_instantiations_auto_gen );
+ StatisticsRegistry::unregisterStat(&d_instantiations_auto_gen_min );
+ StatisticsRegistry::unregisterStat(&d_splits);
+}
+
+/** new node */
+void InstantiatorTheoryUf::newEqClass( TNode n ){
+ d_quantEngine->addTermToDatabase( n );
+}
+
+/** merge */
+void InstantiatorTheoryUf::merge( TNode a, TNode b ){
+ if( Options::current()->efficientEMatching ){
+ if( a.getKind()!=IFF && a.getKind()!=EQUAL && b.getKind()!=IFF && b.getKind()!=EQUAL ){
+ Debug("efficient-e-match") << "Merging " << a << " with " << b << std::endl;
+
+ //determine new candidates for instantiation
+ computeCandidatesPcPairs( a, b );
+ computeCandidatesPcPairs( b, a );
+ computeCandidatesPpPairs( a, b );
+ computeCandidatesPpPairs( b, a );
+ }
+ //merge eqc_ops of b into a
+ EqClassInfo* eci_a = getOrCreateEquivalenceClassInfo( a );
+ EqClassInfo* eci_b = getOrCreateEquivalenceClassInfo( b );
+ eci_a->merge( eci_b );
+ }
+}
+
+/** assert terms are disequal */
+void InstantiatorTheoryUf::assertDisequal( TNode a, TNode b, TNode reason ){
+
+}
+
+EqClassInfo* InstantiatorTheoryUf::getEquivalenceClassInfo( Node n ) {
+ return d_eqc_ops.find( n )==d_eqc_ops.end() ? NULL : d_eqc_ops[n];
+}
+EqClassInfo* InstantiatorTheoryUf::getOrCreateEquivalenceClassInfo( Node n ){
+ Assert( n==getRepresentative( n ) );
+ if( d_eqc_ops.find( n )==d_eqc_ops.end() ){
+ EqClassInfo* eci = new EqClassInfo( d_th->getSatContext() );
+ eci->setMember( n, d_quantEngine->getTermDatabase() );
+ d_eqc_ops[n] = eci;
+ }
+ return d_eqc_ops[n];
+}
+
+void InstantiatorTheoryUf::computeCandidatesPcPairs( Node a, Node b ){
+ Debug("efficient-e-match") << "Compute candidates for pc pairs..." << std::endl;
+ Debug("efficient-e-match") << " Eq class = [";
+ outputEqClass( "efficient-e-match", a);
+ Debug("efficient-e-match") << "]" << std::endl;
+ EqClassInfo* eci_a = getOrCreateEquivalenceClassInfo( a );
+ EqClassInfo* eci_b = getOrCreateEquivalenceClassInfo( a );
+ for( BoolMap::iterator it = eci_a->d_funs.begin(); it != eci_a->d_funs.end(); it++ ) {
+ //the child function: a member of eq_class( a ) has top symbol g, in other words g is in funs( a )
+ Node g = (*it).first;
+ Debug("efficient-e-match") << " Checking application " << g << std::endl;
+ //look at all parent/child pairs
+ for( std::map< Node, std::map< Node, std::vector< InvertedPathString > > >::iterator itf = d_pc_pairs[g].begin();
+ itf != d_pc_pairs[g].end(); ++itf ){
+ //f/g is a parent/child pair
+ Node f = itf->first;
+ if( eci_b->hasParent( f ) || true ){
+ //DO_THIS: determine if f in pfuns( b ), only do the follow if so
+ Debug("efficient-e-match") << " Checking parent application " << f << std::endl;
+ //scan through the list of inverted path strings/candidate generators
+ for( std::map< Node, std::vector< InvertedPathString > >::iterator cit = itf->second.begin();
+ cit != itf->second.end(); ++cit ){
+ Node pat = cit->first;
+ Debug("efficient-e-match") << " Checking pattern " << pat << std::endl;
+ for( int c=0; c<(int)cit->second.size(); c++ ){
+ Debug("efficient-e-match") << " Check inverted path string for pattern ";
+ outputInvertedPathString( "efficient-e-match", cit->second[c] );
+ Debug("efficient-e-match") << std::endl;
+
+ //collect all new relevant terms
+ std::vector< Node > terms;
+ terms.push_back( b );
+ collectTermsIps( cit->second[c], terms );
+ if( !terms.empty() ){
+ Debug("efficient-e-match") << " -> Added terms (" << (int)terms.size() << "): ";
+ //add them as candidates to the candidate generator
+ for( int t=0; t<(int)terms.size(); t++ ){
+ Debug("efficient-e-match") << terms[t] << " ";
+ //Notice() << "Add candidate (PC) " << terms[t] << std::endl;
+ for( int cg=0; cg<(int)d_pat_cand_gens[pat].size(); cg++ ){
+ d_pat_cand_gens[pat][cg]->addCandidate( terms[t] );
+ }
+ }
+ Debug("efficient-e-match") << std::endl;
+ }
+ }
+ }
+ }
+ }
+ }
+}
+
+void InstantiatorTheoryUf::computeCandidatesPpPairs( Node a, Node b ){
+ Debug("efficient-e-match") << "Compute candidates for pp pairs..." << std::endl;
+ EqClassInfo* eci_a = getOrCreateEquivalenceClassInfo( a );
+ EqClassInfo* eci_b = getOrCreateEquivalenceClassInfo( a );
+ for( std::map< Node, std::map< Node, std::map< Node, std::vector< IpsPair > > > >::iterator it = d_pp_pairs.begin();
+ it != d_pp_pairs.end(); ++it ){
+ Node f = it->first;
+ if( eci_a->hasParent( f ) ){
+ Debug("efficient-e-match") << " Checking parent application " << f << std::endl;
+ for( std::map< Node, std::map< Node, std::vector< IpsPair > > >::iterator it2 = it->second.begin();
+ it2 != it->second.end(); ++it2 ){
+ Node g = it2->first;
+ if( eci_b->hasParent( g ) ){
+ Debug("efficient-e-match") << " Checking parent application " << g << std::endl;
+ //if f in pfuns( a ) and g is in pfuns( b ), only do the follow if so
+ for( std::map< Node, std::vector< IpsPair > >::iterator cit = it2->second.begin();
+ cit != it2->second.end(); ++cit ){
+ Node pat = cit->first;
+ for( int c=0; c<(int)cit->second.size(); c++ ){
+ std::vector< Node > a_terms;
+ a_terms.push_back( a );
+ if( !a_terms.empty() ){
+ collectTermsIps( cit->second[c].first, a_terms );
+ std::vector< Node > b_terms;
+ b_terms.push_back( b );
+ collectTermsIps( cit->second[c].first, b_terms );
+ //take intersection
+ for( int t=0; t<(int)a_terms.size(); t++ ){
+ if( std::find( b_terms.begin(), b_terms.end(), a_terms[t] )!=b_terms.end() ){
+ //Notice() << "Add candidate (PP) " << a_terms[t] << std::endl;
+ Debug("efficient-e-match") << " -> Add term " << a_terms[t] << std::endl;
+ //add to all candidate generators having this term
+ for( int cg=0; cg<(int)d_pat_cand_gens[pat].size(); cg++ ){
+ d_pat_cand_gens[pat][cg]->addCandidate( a_terms[t] );
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+}
+
+void InstantiatorTheoryUf::collectTermsIps( InvertedPathString& ips, std::vector< Node >& terms, int index ){
+ if( index<(int)ips.size() && !terms.empty() ){
+ Debug("efficient-e-match-debug") << "> Process " << index << std::endl;
+ Node f = ips[index].first;
+ int arg = ips[index].second;
+
+ //for each term in terms, determine if any term (modulo equality) has parent "f" from position "arg"
+ bool addRep = ( index!=(int)ips.size()-1 );
+ std::vector< Node > newTerms;
+ for( int t=0; t<(int)terms.size(); t++ ){
+ collectParentsTermsIps( terms[t], f, arg, newTerms, addRep );
+ }
+ terms.clear();
+ terms.insert( terms.begin(), newTerms.begin(), newTerms.end() );
+
+ Debug("efficient-e-match-debug") << "> Terms are now: ";
+ for( int t=0; t<(int)terms.size(); t++ ){
+ Debug("efficient-e-match-debug") << terms[t] << " ";
+ }
+ Debug("efficient-e-match-debug") << std::endl;
+
+ collectTermsIps( ips, terms, index+1 );
+ }
+}
+
+bool InstantiatorTheoryUf::collectParentsTermsIps( Node n, Node f, int arg, std::vector< Node >& terms, bool addRep, bool modEq ){
+ bool addedTerm = false;
+ if( ((TheoryUF*)d_th)->d_equalityEngine.hasTerm( n ) && modEq ){
+ Assert( getRepresentative( n )==n );
+ //collect modulo equality
+ //DO_THIS: this should (if necessary) compute a current set of (f, arg) parents for n and cache it
+ eq::EqClassIterator eqc_iter( getRepresentative( n ), &((TheoryUF*)d_th)->d_equalityEngine );
+ while( !eqc_iter.isFinished() ){
+ if( collectParentsTermsIps( (*eqc_iter), f, arg, terms, addRep, false ) ){
+ //if only one argument, we know we can stop (since all others added will be congruent)
+ if( f.getType().getNumChildren()==2 ){
+ return true;
+ }
+ addedTerm = true;
+ }
+ eqc_iter++;
+ }
+ }else{
+ TermDb* db = d_quantEngine->getTermDatabase();
+ //see if parent f exists from argument arg
+ if( db->d_parents.find( n )!=db->d_parents.end() ){
+ if( db->d_parents[n].find( f )!=db->d_parents[n].end() ){
+ if( db->d_parents[n][f].find( arg )!=db->d_parents[n][f].end() ){
+ for( int i=0; i<(int)db->d_parents[n][f][arg].size(); i++ ){
+ Node t = db->d_parents[n][f][arg][i];
+ if( addRep ){
+ t = getRepresentative( t );
+ }
+ if( std::find( terms.begin(), terms.end(), t )==terms.end() ){
+ terms.push_back( t );
+ }
+ addedTerm = true;
+ }
+ }
+ }
+ }
+ }
+ return addedTerm;
+}
+
+void InstantiatorTheoryUf::registerPatternElementPairs2( Node opat, Node pat, InvertedPathString& ips,
+ std::map< Node, std::vector< std::pair< Node, InvertedPathString > > >& ips_map ){
+ Assert( pat.getKind()==APPLY_UF );
+ //add information for possible pp-pair
+ for( int i=0; i<(int)pat.getNumChildren(); i++ ){
+ if( pat[i].getKind()==INST_CONSTANT ){
+ ips_map[ pat[i] ].push_back( std::pair< Node, InvertedPathString >( pat.getOperator(), InvertedPathString( ips ) ) );
+ }
+ }
+ ips.push_back( std::pair< Node, int >( pat.getOperator(), 0 ) );
+ for( int i=0; i<(int)pat.getNumChildren(); i++ ){
+ if( pat[i].getKind()==APPLY_UF ){
+ ips.back().second = i;
+ registerPatternElementPairs2( opat, pat[i], ips, ips_map );
+ Debug("pattern-element-opt") << "Found pc-pair ( " << pat.getOperator() << ", " << pat[i].getOperator() << " )" << std::endl;
+ Debug("pattern-element-opt") << " Path = ";
+ outputInvertedPathString( "pattern-element-opt", ips );
+ Debug("pattern-element-opt") << std::endl;
+ //pat.getOperator() and pat[i].getOperator() are a pc-pair
+ d_pc_pairs[ pat[i].getOperator() ][ pat.getOperator() ][opat].push_back( InvertedPathString( ips ) );
+ }
+ }
+ ips.pop_back();
+}
+
+void InstantiatorTheoryUf::registerPatternElementPairs( Node pat ){
+ InvertedPathString ips;
+ std::map< Node, std::vector< std::pair< Node, InvertedPathString > > > ips_map;
+ registerPatternElementPairs2( pat, pat, ips, ips_map );
+ for( std::map< Node, std::vector< std::pair< Node, InvertedPathString > > >::iterator it = ips_map.begin(); it != ips_map.end(); ++it ){
+ for( int j=0; j<(int)it->second.size(); j++ ){
+ for( int k=j+1; k<(int)it->second.size(); k++ ){
+ //found a pp-pair
+ Debug("pattern-element-opt") << "Found pp-pair ( " << it->second[j].first << ", " << it->second[k].first << " )" << std::endl;
+ Debug("pattern-element-opt") << " Paths = ";
+ outputInvertedPathString( "pattern-element-opt", it->second[j].second );
+ Debug("pattern-element-opt") << " and ";
+ outputInvertedPathString( "pattern-element-opt", it->second[k].second );
+ Debug("pattern-element-opt") << std::endl;
+ d_pp_pairs[ it->second[j].first ][ it->second[k].first ][pat].push_back( IpsPair( it->second[j].second, it->second[k].second ) );
+ }
+ }
+ }
+}
+
+void InstantiatorTheoryUf::registerCandidateGenerator( CandidateGenerator* cg, Node pat ){
+ Debug("efficient-e-match") << "Register candidate generator..." << pat << std::endl;
+ if( d_pat_cand_gens.find( pat )==d_pat_cand_gens.end() ){
+ registerPatternElementPairs( pat );
+ }
+ d_pat_cand_gens[pat].push_back( cg );
+
+ //take all terms from the uf term db and add to candidate generator
+ Node op = pat.getOperator();
+ TermDb* db = d_quantEngine->getTermDatabase();
+ for( int i=0; i<(int)db->d_op_map[op].size(); i++ ){
+ cg->addCandidate( db->d_op_map[op][i] );
+ }
+ d_cand_gens[op].push_back( cg );
+
+ Debug("efficient-e-match") << "Done." << std::endl;
+}
+
+void InstantiatorTheoryUf::registerTrigger( Trigger* tr, Node op ){
+ if( std::find( d_op_triggers[op].begin(), d_op_triggers[op].end(), tr )==d_op_triggers[op].end() ){
+ d_op_triggers[op].push_back( tr );
+ }
+}
+
+void InstantiatorTheoryUf::outputEqClass( const char* c, Node n ){
+ if( ((TheoryUF*)d_th)->d_equalityEngine.hasTerm( n ) ){
+ eq::EqClassIterator eqc_iter( getRepresentative( n ),
+ &((TheoryUF*)d_th)->d_equalityEngine );
+ bool firstTime = true;
+ while( !eqc_iter.isFinished() ){
+ if( !firstTime ){ Debug(c) << ", "; }
+ Debug(c) << (*eqc_iter);
+ firstTime = false;
+ eqc_iter++;
+ }
+ }else{
+ Debug(c) << n;
+ }
+}
+
+void InstantiatorTheoryUf::outputInvertedPathString( const char* c, InvertedPathString& ips ){
+ for( int i=0; i<(int)ips.size(); i++ ){
+ if( i>0 ){ Debug( c ) << "."; }
+ Debug( c ) << ips[i].first << "." << ips[i].second;
+ }
+}
diff --git a/src/theory/uf/theory_uf_instantiator.h b/src/theory/uf/theory_uf_instantiator.h
new file mode 100644
index 000000000..e50e3823c
--- /dev/null
+++ b/src/theory/uf/theory_uf_instantiator.h
@@ -0,0 +1,201 @@
+/********************* */
+/*! \file theory_uf_instantiator.h
+ ** \verbatim
+ ** Original author: ajreynol
+ ** Major contributors: none
+ ** Minor contributors (to current version): none
+ ** This file is part of the CVC4 prototype.
+ ** Copyright (c) 2009, 2010, 2011 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
+ ** information.\endverbatim
+ **
+ ** \brief Theory uf instantiator
+ **/
+
+#include "cvc4_private.h"
+
+#ifndef __CVC4__THEORY_UF_INSTANTIATOR_H
+#define __CVC4__THEORY_UF_INSTANTIATOR_H
+
+#include "theory/uf/inst_strategy.h"
+
+#include "context/context.h"
+#include "context/context_mm.h"
+#include "context/cdchunk_list.h"
+
+#include "util/stats.h"
+#include "theory/uf/theory_uf.h"
+
+namespace CVC4 {
+namespace theory {
+
+class TermDb;
+
+namespace uf {
+
+class InstantiatorTheoryUf;
+
+//equivalence class info
+class EqClassInfo
+{
+public:
+ typedef context::CDHashMap<Node, bool, NodeHashFunction> BoolMap;
+ typedef context::CDChunkList<Node> NodeList;
+public:
+ //a list of operators that occur as top symbols in this equivalence class
+ // Efficient E-Matching for SMT Solvers: "funs"
+ BoolMap d_funs;
+ //a list of operators f for which a term of the form f( ... t ... ) exists
+ // Efficient E-Matching for SMT Solvers: "pfuns"
+ BoolMap d_pfuns;
+ //a list of equivalence classes that are disequal
+ BoolMap d_disequal;
+public:
+ EqClassInfo( context::Context* c );
+ ~EqClassInfo(){}
+ //set member
+ void setMember( Node n, TermDb* db );
+ //has function "funs"
+ bool hasFunction( Node op );
+ //has parent "pfuns"
+ bool hasParent( Node op );
+ //merge with another eq class info
+ void merge( EqClassInfo* eci );
+};
+
+class InstantiatorTheoryUf : public Instantiator{
+ friend class ::CVC4::theory::InstMatchGenerator;
+ friend class ::CVC4::theory::TermDb;
+protected:
+ typedef context::CDHashMap<Node, bool, NodeHashFunction> BoolMap;
+ typedef context::CDHashMap<Node, int, NodeHashFunction> IntMap;
+ typedef context::CDChunkList<Node> NodeList;
+ typedef context::CDHashMap<Node, NodeList*, NodeHashFunction> NodeLists;
+ /** map to representatives used */
+ std::map< Node, Node > d_ground_reps;
+protected:
+ /** instantiation strategies */
+ InstStrategyUserPatterns* d_isup;
+public:
+ InstantiatorTheoryUf(context::Context* c, CVC4::theory::QuantifiersEngine* qe, Theory* th);
+ ~InstantiatorTheoryUf() {}
+ /** assertNode method */
+ void assertNode( Node assertion );
+ /** Pre-register a term. Done one time for a Node, ever. */
+ void preRegisterTerm( Node t );
+ /** identify */
+ std::string identify() const { return std::string("InstantiatorTheoryUf"); }
+ /** debug print */
+ void debugPrint( const char* c );
+ /** add user pattern */
+ void addUserPattern( Node f, Node pat );
+private:
+ /** reset instantiation */
+ void processResetInstantiationRound( Theory::Effort effort );
+ /** calculate matches for quantifier f at effort */
+ int process( Node f, Theory::Effort effort, int e, int instLimit );
+public:
+ /** statistics class */
+ class Statistics {
+ public:
+ //IntStat d_instantiations;
+ IntStat d_instantiations_ce_solved;
+ IntStat d_instantiations_e_induced;
+ IntStat d_instantiations_user_pattern;
+ IntStat d_instantiations_guess;
+ IntStat d_instantiations_auto_gen;
+ IntStat d_instantiations_auto_gen_min;
+ IntStat d_splits;
+ Statistics();
+ ~Statistics();
+ };
+ Statistics d_statistics;
+public:
+ /** the base match */
+ std::map< Node, InstMatch > d_baseMatch;
+private:
+ //for each equivalence class
+ std::map< Node, EqClassInfo* > d_eqc_ops;
+public:
+ /** general queries about equality */
+ bool hasTerm( Node a );
+ bool areEqual( Node a, Node b );
+ bool areDisequal( Node a, Node b );
+ Node getRepresentative( Node a );
+ Node getInternalRepresentative( Node a );
+ /** new node */
+ void newEqClass( TNode n );
+ /** merge */
+ void merge( TNode a, TNode b );
+ /** assert terms are disequal */
+ void assertDisequal( TNode a, TNode b, TNode reason );
+ /** get equivalence class info */
+ EqClassInfo* getEquivalenceClassInfo( Node n );
+ EqClassInfo* getOrCreateEquivalenceClassInfo( Node n );
+private:
+ typedef std::vector< std::pair< Node, int > > InvertedPathString;
+ typedef std::pair< InvertedPathString, InvertedPathString > IpsPair;
+ /** Parent/Child Pairs (for efficient E-matching)
+ So, for example, if we have the pattern f( g( x ) ), then d_pc_pairs[g][f][f( g( x ) )] = { f.0 }.
+ */
+ std::map< Node, std::map< Node, std::map< Node, std::vector< InvertedPathString > > > > d_pc_pairs;
+ /** Parent/Parent Pairs (for efficient E-matching) */
+ std::map< Node, std::map< Node, std::map< Node, std::vector< IpsPair > > > > d_pp_pairs;
+ /** list of all candidate generators for each operator */
+ std::map< Node, std::vector< CandidateGenerator* > > d_cand_gens;
+ /** map from patterns to candidate generators */
+ std::map< Node, std::vector< CandidateGenerator* > > d_pat_cand_gens;
+ /** helper functions */
+ void registerPatternElementPairs2( Node opat, Node pat, InvertedPathString& ips,
+ std::map< Node, std::vector< std::pair< Node, InvertedPathString > > >& ips_map );
+ void registerPatternElementPairs( Node pat );
+ /** compute candidates for pc pairs */
+ void computeCandidatesPcPairs( Node a, Node b );
+ /** compute candidates for pp pairs */
+ void computeCandidatesPpPairs( Node a, Node b );
+ /** collect terms based on inverted path string */
+ void collectTermsIps( InvertedPathString& ips, std::vector< Node >& terms, int index = 0 );
+ bool collectParentsTermsIps( Node n, Node f, int arg, std::vector< Node >& terms, bool addRep, bool modEq = true );
+public:
+ /** Register candidate generator cg for pattern pat. (for use with efficient e-matching)
+ This request will ensure that calls will be made to cg->addCandidate( n ) for all
+ ground terms n that are relevant for matching with pat.
+ */
+ void registerCandidateGenerator( CandidateGenerator* cg, Node pat );
+private:
+ /** triggers */
+ std::map< Node, std::vector< Trigger* > > d_op_triggers;
+public:
+ /** register trigger (for eager quantifier instantiation) */
+ void registerTrigger( Trigger* tr, Node op );
+public:
+ /** output eq class */
+ void outputEqClass( const char* c, Node n );
+ /** output inverted path string */
+ void outputInvertedPathString( const char* c, InvertedPathString& ips );
+};/* class InstantiatorTheoryUf */
+
+/** equality query object using instantiator theory uf */
+class EqualityQueryInstantiatorTheoryUf : public EqualityQuery
+{
+private:
+ /** pointer to instantiator uf class */
+ InstantiatorTheoryUf* d_ith;
+public:
+ EqualityQueryInstantiatorTheoryUf( InstantiatorTheoryUf* ith ) : d_ith( ith ){}
+ ~EqualityQueryInstantiatorTheoryUf(){}
+ /** general queries about equality */
+ bool hasTerm( Node a ) { return d_ith->hasTerm( a ); }
+ Node getRepresentative( Node a ) { return d_ith->getRepresentative( a ); }
+ bool areEqual( Node a, Node b ) { return d_ith->areEqual( a, b ); }
+ bool areDisequal( Node a, Node b ) { return d_ith->areDisequal( a, b ); }
+ Node getInternalRepresentative( Node a ) { return d_ith->getInternalRepresentative( a ); }
+}; /* EqualityQueryInstantiatorTheoryUf */
+
+}
+}/* CVC4::theory namespace */
+}/* CVC4 namespace */
+
+#endif /* __CVC4__THEORY_UF_INSTANTIATOR_H */
diff --git a/src/theory/uf/theory_uf_strong_solver.cpp b/src/theory/uf/theory_uf_strong_solver.cpp
new file mode 100644
index 000000000..a793b6a57
--- /dev/null
+++ b/src/theory/uf/theory_uf_strong_solver.cpp
@@ -0,0 +1,1267 @@
+/********************* */
+/*! \file theory_uf_strong_solver.cpp
+ ** \verbatim
+ ** Original author: ajreynol
+ ** Major contributors: none
+ ** Minor contributors (to current version): none
+ ** This file is part of the CVC4 prototype.
+ ** Copyright (c) 2009, 2010, 2011 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
+ ** information.\endverbatim
+ **
+ ** \brief Implementation of theory uf strong solver class
+ **/
+
+#include "theory/uf/theory_uf_strong_solver.h"
+#include "theory/uf/theory_uf.h"
+#include "theory/uf/equality_engine.h"
+#include "theory/uf/theory_uf_instantiator.h"
+#include "theory/theory_engine.h"
+
+//#define USE_REGION_SAT
+
+using namespace std;
+using namespace CVC4;
+using namespace CVC4::kind;
+using namespace CVC4::context;
+using namespace CVC4::theory;
+using namespace CVC4::theory::uf;
+
+void StrongSolverTheoryUf::ConflictFind::Region::takeNode( StrongSolverTheoryUf::ConflictFind::Region* r, Node n ){
+ //Debug("uf-ss") << "takeNode " << r << " " << n << std::endl;
+ //Debug("uf-ss") << "r : " << std::endl;
+ //r->debugPrint("uf-ss");
+ //Debug("uf-ss") << "this : " << std::endl;
+ //debugPrint("uf-ss");
+ Assert( !hasRep( n ) );
+ Assert( r->hasRep( n ) );
+ //add representative
+ setRep( n, true );
+ //take disequalities from r
+ RegionNodeInfo* rni = r->d_nodes[n];
+ for( int t=0; t<2; t++ ){
+ RegionNodeInfo::DiseqList* del = rni->d_disequalities[t];
+ for( NodeBoolMap::iterator it = del->d_disequalities.begin(); it != del->d_disequalities.end(); ++it ){
+ if( (*it).second ){
+ r->setDisequal( n, (*it).first, t, false );
+ if( t==0 ){
+ if( hasRep( (*it).first ) ){
+ setDisequal( (*it).first, n, 0, false );
+ setDisequal( (*it).first, n, 1, true );
+ setDisequal( n, (*it).first, 1, true );
+ }else{
+ setDisequal( n, (*it).first, 0, true );
+ }
+ }else{
+ r->setDisequal( (*it).first, n, 1, false );
+ r->setDisequal( (*it).first, n, 0, true );
+ setDisequal( n, (*it).first, 0, true );
+ }
+ }
+ }
+ }
+ //remove representative
+ r->setRep( n, false );
+ //Debug("uf-ss") << "done takeNode " << r << " " << n << std::endl;
+}
+
+void StrongSolverTheoryUf::ConflictFind::Region::combine( StrongSolverTheoryUf::ConflictFind::Region* r ){
+ //take all nodes from r
+ for( std::map< Node, RegionNodeInfo* >::iterator it = r->d_nodes.begin(); it != r->d_nodes.end(); ++it ){
+ if( it->second->d_valid ){
+ setRep( it->first, true );
+ }
+ }
+ for( std::map< Node, RegionNodeInfo* >::iterator it = r->d_nodes.begin(); it != r->d_nodes.end(); ++it ){
+ if( it->second->d_valid ){
+ //take disequalities from r
+ Node n = it->first;
+ RegionNodeInfo* rni = it->second;
+ for( int t=0; t<2; t++ ){
+ RegionNodeInfo::DiseqList* del = rni->d_disequalities[t];
+ for( NodeBoolMap::iterator it2 = del->d_disequalities.begin(); it2 != del->d_disequalities.end(); ++it2 ){
+ if( (*it2).second ){
+ if( t==0 && hasRep( (*it2).first ) ){
+ setDisequal( (*it2).first, n, 0, false );
+ setDisequal( (*it2).first, n, 1, true );
+ setDisequal( n, (*it2).first, 1, true );
+ }else{
+ setDisequal( n, (*it2).first, t, true );
+ }
+ }
+ }
+ }
+ }
+ }
+ r->d_valid = false;
+}
+
+void StrongSolverTheoryUf::ConflictFind::Region::setRep( Node n, bool valid ){
+ Assert( hasRep( n )!=valid );
+ if( d_nodes.find( n )==d_nodes.end() && valid ){
+ d_nodes[n] = new RegionNodeInfo( d_cf->d_th->getSatContext() );
+ }
+ d_nodes[n]->d_valid = valid;
+ d_reps_size = d_reps_size + ( valid ? 1 : -1 );
+ if( d_testClique.find( n )!=d_testClique.end() && d_testClique[n] ){
+ Assert( !valid );
+ d_testClique[n] = false;
+ d_testCliqueSize = d_testCliqueSize - 1;
+ //remove all splits involving n
+ for( NodeBoolMap::iterator it = d_splits.begin(); it != d_splits.end(); ++it ){
+ if( (*it).second ){
+ if( (*it).first[0]==n || (*it).first[1]==n ){
+ d_splits[ (*it).first ] = false;
+ d_splitsSize = d_splitsSize - 1;
+ }
+ }
+ }
+ }
+}
+
+/** setEqual */
+void StrongSolverTheoryUf::ConflictFind::Region::setEqual( Node a, Node b ){
+ Assert( hasRep( a ) && hasRep( b ) );
+ //move disequalities of b over to a
+ for( int t=0; t<2; t++ ){
+ RegionNodeInfo::DiseqList* del = d_nodes[b]->d_disequalities[t];
+ for( NodeBoolMap::iterator it = del->d_disequalities.begin(); it != del->d_disequalities.end(); ++it ){
+ if( (*it).second ){
+ Node n = (*it).first;
+ Region* nr = d_cf->d_regions[ d_cf->d_regions_map[ n ] ];
+ if( !isDisequal( a, n, t ) ){
+ setDisequal( a, n, t, true );
+ nr->setDisequal( n, a, t, true );
+ }
+ setDisequal( b, n, t, false );
+ nr->setDisequal( n, b, t, false );
+ }
+ }
+ }
+ //remove b from representatives
+ setRep( b, false );
+}
+
+void StrongSolverTheoryUf::ConflictFind::Region::setDisequal( Node n1, Node n2, int type, bool valid ){
+ //Debug("uf-ss-region-debug") << "set disequal " << n1 << " " << n2 << " " << type << " " << valid << std::endl;
+ //debugPrint("uf-ss-region-debug");
+ //Assert( isDisequal( n1, n2, type )!=valid );
+ if( isDisequal( n1, n2, type )!=valid ){ //DO_THIS: make assertion
+ d_nodes[ n1 ]->d_disequalities[type]->setDisequal( n2, valid );
+ if( type==0 ){
+ d_total_diseq_external = d_total_diseq_external + ( valid ? 1 : -1 );
+ }else{
+ d_total_diseq_internal = d_total_diseq_internal + ( valid ? 1 : -1 );
+ if( valid ){
+ //if they are both a part of testClique, then remove split
+ if( d_testClique.find( n1 )!=d_testClique.end() && d_testClique[n1] &&
+ d_testClique.find( n2 )!=d_testClique.end() && d_testClique[n2] ){
+ Node eq = NodeManager::currentNM()->mkNode( EQUAL, n1, n2 );
+ if( d_splits.find( eq )!=d_splits.end() && d_splits[ eq ] ){
+ Debug("uf-ss-debug") << "removing split for " << n1 << " " << n2 << std::endl;
+ d_splits[ eq ] = false;
+ d_splitsSize = d_splitsSize - 1;
+ }
+ }
+ }
+ }
+ }
+}
+
+bool StrongSolverTheoryUf::ConflictFind::Region::isDisequal( Node n1, Node n2, int type ){
+ RegionNodeInfo::DiseqList* del = d_nodes[ n1 ]->d_disequalities[type];
+ return del->d_disequalities.find( n2 )!=del->d_disequalities.end() && del->d_disequalities[n2];
+}
+
+bool StrongSolverTheoryUf::ConflictFind::Region::getMustCombine( int cardinality ){
+ if( d_total_diseq_external>=long(cardinality) ){
+ //The number of external disequalities is greater than or equal to cardinality.
+ //Thus, a clique of size cardinality+1 may exist between nodes in d_regions[i] and other regions
+ //Check if this is actually the case: must have n nodes with outgoing degree (cardinality+1-n) for some n>0
+ std::vector< int > degrees;
+ for( std::map< Node, RegionNodeInfo* >::iterator it = d_nodes.begin(); it != d_nodes.end(); ++it ){
+ RegionNodeInfo* rni = it->second;
+ if( rni->d_valid ){
+ if( rni->getNumDisequalities()>=cardinality ){
+ int outDeg = rni->getNumExternalDisequalities();
+ if( outDeg>=cardinality ){
+ //we have 1 node of degree greater than (cardinality)
+ return true;
+ }else if( outDeg>0 ){
+ degrees.push_back( outDeg );
+ if( (int)degrees.size()>=cardinality ){
+ //we have (cardinality) nodes of degree 1
+ return true;
+ }
+ }
+ }
+ }
+ }
+ std::sort( degrees.begin(), degrees.end() );
+ for( int i=0; i<(int)degrees.size(); i++ ){
+ if( degrees[i]>=cardinality+1-((int)degrees.size()-i) ){
+ return true;
+ }
+ }
+ }
+ return false;
+}
+
+struct sortInternalDegree {
+ StrongSolverTheoryUf::ConflictFind::Region* r;
+ bool operator() (Node i,Node j) { return (r->d_nodes[i]->getNumInternalDisequalities()>r->d_nodes[j]->getNumInternalDisequalities());}
+};
+
+
+bool StrongSolverTheoryUf::ConflictFind::Region::check( Theory::Effort level, int cardinality, std::vector< Node >& clique ){
+ if( d_reps_size>long(cardinality) ){
+ if( d_reps_size>long(cardinality) && d_total_diseq_internal==d_reps_size*( d_reps_size - 1 ) ){
+ //quick clique check, all reps form a clique
+ for( std::map< Node, RegionNodeInfo* >::iterator it = d_nodes.begin(); it != d_nodes.end(); ++it ){
+ if( it->second->d_valid ){
+ clique.push_back( it->first );
+ }
+ }
+ return true;
+ }else{
+ //build test clique, up to size cardinality+1
+ if( d_testCliqueSize<=long(cardinality) ){
+ std::vector< Node > newClique;
+ if( d_testCliqueSize<long(cardinality) ){
+ for( std::map< Node, RegionNodeInfo* >::iterator it = d_nodes.begin(); it != d_nodes.end(); ++it ){
+ //if not in the test clique, add it to the set of new members
+ if( it->second->d_valid && ( d_testClique.find( it->first )==d_testClique.end() || !d_testClique[ it->first ] ) ){
+ newClique.push_back( it->first );
+ }
+ }
+ //choose remaining nodes with the highest degrees
+ sortInternalDegree sidObj;
+ sidObj.r = this;
+ std::sort( newClique.begin(), newClique.end(), sidObj );
+ newClique.erase( newClique.begin() + ( cardinality - d_testCliqueSize ) + 1, newClique.end() );
+ }else{
+ //scan for the highest degree
+ int maxDeg = -1;
+ Node maxNode;
+ for( std::map< Node, RegionNodeInfo* >::iterator it = d_nodes.begin(); it != d_nodes.end(); ++it ){
+ //if not in the test clique, add it to the set of new members
+ if( it->second->d_valid && ( d_testClique.find( it->first )==d_testClique.end() || !d_testClique[ it->first ] ) ){
+ if( it->second->getNumInternalDisequalities()>maxDeg ){
+ maxDeg = it->second->getNumInternalDisequalities();
+ maxNode = it->first;
+ }
+ }
+ }
+ Assert( maxNode!=Node::null() );
+ newClique.push_back( maxNode );
+ }
+ //check splits internal to new members
+ for( int j=0; j<(int)newClique.size(); j++ ){
+ Debug("uf-ss-debug") << "Choose to add clique member " << newClique[j] << std::endl;
+ for( int k=(j+1); k<(int)newClique.size(); k++ ){
+ if( !isDisequal( newClique[j], newClique[k], 1 ) ){
+ d_splits[ NodeManager::currentNM()->mkNode( EQUAL, newClique[j], newClique[k] ) ] = true;
+ d_splitsSize = d_splitsSize + 1;
+ }
+ }
+ //check disequalities with old members
+ for( NodeBoolMap::iterator it = d_testClique.begin(); it != d_testClique.end(); ++it ){
+ if( (*it).second ){
+ if( !isDisequal( (*it).first, newClique[j], 1 ) ){
+ d_splits[ NodeManager::currentNM()->mkNode( EQUAL, (*it).first, newClique[j] ) ] = true;
+ d_splitsSize = d_splitsSize + 1;
+ }
+ }
+ }
+ }
+ //add new clique members to test clique
+ for( int j=0; j<(int)newClique.size(); j++ ){
+ d_testClique[ newClique[j] ] = true;
+ d_testCliqueSize = d_testCliqueSize + 1;
+ }
+ }
+ Assert( d_testCliqueSize==long(cardinality+1) );
+ if( d_splitsSize==0 ){
+ //test clique is a clique
+ for( NodeBoolMap::iterator it = d_testClique.begin(); it != d_testClique.end(); ++it ){
+ if( (*it).second ){
+ clique.push_back( (*it).first );
+ }
+ }
+ return true;
+ }
+ }
+ }
+ return false;
+}
+
+Node StrongSolverTheoryUf::ConflictFind::Region::getBestSplit(){
+ //take the first split you find
+ for( NodeBoolMap::iterator it = d_splits.begin(); it != d_splits.end(); ++it ){
+ if( (*it).second ){
+ return (*it).first;
+ }
+ }
+ return Node::null();
+}
+
+void StrongSolverTheoryUf::ConflictFind::Region::addSplit( OutputChannel* out ){
+ Node s = getBestSplit();
+ //add lemma to output channel
+ Assert( s!=Node::null() && s.getKind()==EQUAL );
+ s = Rewriter::rewrite( s );
+ Debug("uf-ss-lemma") << "*** Split on " << s << std::endl;
+ //Debug("uf-ss-lemma") << d_th->getEqualityEngine()->areEqual( s[0], s[1] ) << " ";
+ //Debug("uf-ss-lemma") << d_th->getEqualityEngine()->areDisequal( s[0], s[1] ) << std::endl;
+ //Debug("uf-ss-lemma") << s[0].getType() << " " << s[1].getType() << std::endl;
+ debugPrint("uf-ss-temp");
+ //Notice() << "*** Split on " << s << std::endl;
+ //split on the equality s
+ out->split( s );
+ //tell the sat solver to explore the equals branch first
+ out->requirePhase( s, true );
+}
+
+void StrongSolverTheoryUf::ConflictFind::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 );
+ }
+ }
+}
+
+bool StrongSolverTheoryUf::ConflictFind::Region::minimize( OutputChannel* out ){
+ if( hasSplits() ){
+ addSplit( out );
+ return false;
+ }else{
+ return true;
+ }
+}
+
+void StrongSolverTheoryUf::ConflictFind::Region::getNumExternalDisequalities( std::map< Node, int >& num_ext_disequalities ){
+ for( std::map< Node, RegionNodeInfo* >::iterator it = d_nodes.begin(); it != d_nodes.end(); ++it ){
+ RegionNodeInfo* rni = it->second;
+ if( rni->d_valid ){
+ RegionNodeInfo::DiseqList* del = rni->d_disequalities[0];
+ for( NodeBoolMap::iterator it2 = del->d_disequalities.begin(); it2 != del->d_disequalities.end(); ++it2 ){
+ if( (*it2).second ){
+ num_ext_disequalities[ (*it2).first ]++;
+ }
+ }
+ }
+ }
+}
+
+void StrongSolverTheoryUf::ConflictFind::Region::debugPrint( const char* c, bool incClique ){
+ Debug( c ) << "Num reps: " << d_reps_size << std::endl;
+ for( std::map< Node, RegionNodeInfo* >::iterator it = d_nodes.begin(); it != d_nodes.end(); ++it ){
+ RegionNodeInfo* rni = it->second;
+ if( rni->d_valid ){
+ Node n = it->first;
+ Debug( c ) << " " << n << std::endl;
+ for( int i=0; i<2; i++ ){
+ Debug( c ) << " " << ( i==0 ? "Ext" : "Int" ) << " disequal:";
+ RegionNodeInfo::DiseqList* del = rni->d_disequalities[i];
+ for( NodeBoolMap::iterator it2 = del->d_disequalities.begin(); it2 != del->d_disequalities.end(); ++it2 ){
+ if( (*it2).second ){
+ Debug( c ) << " " << (*it2).first;
+ }
+ }
+ Debug( c ) << ", total = " << del->d_size << std::endl;
+ }
+ }
+ }
+ Debug( c ) << "Total disequal: " << d_total_diseq_external << " external," << std::endl;
+ Debug( c ) << " " << d_total_diseq_internal<< " internal." << std::endl;
+
+ if( incClique ){
+ Debug( c ) << "Candidate clique members: " << std::endl;
+ Debug( c ) << " ";
+ for( NodeBoolMap::iterator it = d_testClique.begin(); it != d_testClique.end(); ++ it ){
+ if( (*it).second ){
+ Debug( c ) << (*it).first << " ";
+ }
+ }
+ Debug( c ) << ", size = " << d_testCliqueSize << std::endl;
+ Debug( c ) << "Required splits: " << std::endl;
+ Debug( c ) << " ";
+ for( NodeBoolMap::iterator it = d_splits.begin(); it != d_splits.end(); ++ it ){
+ if( (*it).second ){
+ Debug( c ) << (*it).first << " ";
+ }
+ }
+ Debug( c ) << ", size = " << d_splitsSize << std::endl;
+ }
+}
+
+void StrongSolverTheoryUf::ConflictFind::combineRegions( int ai, int bi ){
+ Debug("uf-ss-region") << "uf-ss: Combine Region #" << bi << " with Region #" << ai << std::endl;
+ Assert( isValid( ai ) && isValid( bi ) );
+ for( std::map< Node, Region::RegionNodeInfo* >::iterator it = d_regions[bi]->d_nodes.begin(); it != d_regions[bi]->d_nodes.end(); ++it ){
+ Region::RegionNodeInfo* rni = it->second;
+ if( rni->d_valid ){
+ d_regions_map[ it->first ] = ai;
+ }
+ }
+ //update regions disequal DO_THIS?
+ d_regions[ai]->combine( d_regions[bi] );
+ d_regions[bi]->d_valid = false;
+}
+
+void StrongSolverTheoryUf::ConflictFind::moveNode( Node n, int ri ){
+ Debug("uf-ss-region") << "uf-ss: Move node " << n << " to Region #" << ri << std::endl;
+ Assert( isValid( d_regions_map[ n ] ) );
+ Assert( isValid( ri ) );
+ ////update regions disequal DO_THIS?
+ //Region::RegionNodeInfo::DiseqList* del = d_regions[ d_regions_map[n] ]->d_nodes[n]->d_disequalities[0];
+ //for( NodeBoolMap::iterator it = del->d_disequalities.begin(); it != del->d_disequalities.end(); ++it ){
+ // if( (*it).second ){
+ // }
+ //}
+ //move node to region ri
+ d_regions[ri]->takeNode( d_regions[ d_regions_map[n] ], n );
+ d_regions_map[n] = ri;
+}
+
+int StrongSolverTheoryUf::ConflictFind::getNumDisequalitiesToRegion( Node n, int ri ){
+ int ni = d_regions_map[n];
+ int counter = 0;
+ Region::RegionNodeInfo::DiseqList* del = d_regions[ni]->d_nodes[n]->d_disequalities[0];
+ for( NodeBoolMap::iterator it = del->d_disequalities.begin(); it != del->d_disequalities.end(); ++it ){
+ if( (*it).second ){
+ if( d_regions_map[ (*it).first ]==ri ){
+ counter++;
+ }
+ }
+ }
+ return counter;
+}
+
+void StrongSolverTheoryUf::ConflictFind::getDisequalitiesToRegions( int ri, std::map< int, int >& regions_diseq ){
+ for( std::map< Node, Region::RegionNodeInfo* >::iterator it = d_regions[ri]->d_nodes.begin();
+ it != d_regions[ri]->d_nodes.end(); ++it ){
+ if( it->second->d_valid ){
+ Region::RegionNodeInfo::DiseqList* del = it->second->d_disequalities[0];
+ for( NodeBoolMap::iterator it2 = del->d_disequalities.begin(); it2 != del->d_disequalities.end(); ++it2 ){
+ if( (*it2).second ){
+ //if( !isValid( d_regions_map[ (*it2).first ] ) ){
+ // Debug( "uf-ss-temp" ) << "^^^" << ri << " " << d_regions_map[ (*it2).first ].get() << std::endl;
+ // debugPrint( "uf-ss-temp" );
+ //}
+ Assert( isValid( d_regions_map[ (*it2).first ] ) );
+ //Notice() << "Found disequality with " << (*it2).first << ", region = " << d_regions_map[ (*it2).first ] << std::endl;
+ regions_diseq[ d_regions_map[ (*it2).first ] ]++;
+ }
+ }
+ }
+ }
+}
+
+void StrongSolverTheoryUf::ConflictFind::explainClique( std::vector< Node >& clique, OutputChannel* out ){
+ Assert( d_cardinality>0 );
+ while( clique.size()>long(d_cardinality+1) ){
+ clique.pop_back();
+ }
+ //found a clique
+ Debug("uf-ss") << "Found a clique (cardinality=" << d_cardinality << ") :" << std::endl;
+ Debug("uf-ss") << " ";
+ for( int i=0; i<(int)clique.size(); i++ ){
+ Debug("uf-ss") << clique[i] << " ";
+ }
+ Debug("uf-ss") << std::endl;
+ Debug("uf-ss") << "Finding clique disequalities..." << std::endl;
+ std::vector< Node > conflict;
+ //collect disequalities, and nodes that must be equal within representatives
+ std::map< Node, std::map< Node, bool > > explained;
+ std::map< Node, std::map< Node, bool > > nodesWithinRep;
+ for( int i=0; i<(int)d_disequalities_index; i++ ){
+ //if both sides of disequality exist in clique
+ Node r1 = d_th->d_equalityEngine.getRepresentative( d_disequalities[i][0][0] );
+ Node r2 = d_th->d_equalityEngine.getRepresentative( d_disequalities[i][0][1] );
+ if( r1!=r2 && ( explained.find( r1 )==explained.end() || explained[r1].find( r2 )==explained[r1].end() ) &&
+ std::find( clique.begin(), clique.end(), r1 )!=clique.end() &&
+ std::find( clique.begin(), clique.end(), r2 )!=clique.end() ){
+ explained[r1][r2] = true;
+ explained[r2][r1] = true;
+ conflict.push_back( d_disequalities[i] );
+ nodesWithinRep[r1][ d_disequalities[i][0][0] ] = true;
+ nodesWithinRep[r2][ d_disequalities[i][0][1] ] = true;
+ if( conflict.size()==((int)clique.size()*( (int)clique.size()-1 )/2) ){
+ break;
+ }
+ }
+ }
+ //Debug("uf-ss") << conflict.size() << " " << clique.size() << std::endl;
+ Assert( (int)conflict.size()==((int)clique.size()*( (int)clique.size()-1 )/2) );
+ //Assert( (int)conflict.size()==(int)clique.size()*( (int)clique.size()-1 )/2 );
+ Debug("uf-ss") << "Finding clique equalities internal to eq classes..." << std::endl;
+ //now, we must explain equalities within each equivalence class
+ for( std::map< Node, std::map< Node, bool > >::iterator it = nodesWithinRep.begin(); it != nodesWithinRep.end(); ++it ){
+ if( it->second.size()>1 ){
+ Node prev;
+ //add explanation of t1 = t2 = ... = tn
+ for( std::map< Node, bool >::iterator it2 = it->second.begin(); it2 != it->second.end(); ++it2 ){
+ if( prev!=Node::null() ){
+ //explain it2->first and prev
+ std::vector< TNode > expl;
+ d_th->d_equalityEngine.explainEquality( it2->first, prev, true, expl );
+ for( int i=0; i<(int)expl.size(); i++ ){
+ if( std::find( conflict.begin(), conflict.end(), expl[i] )==conflict.end() ){
+ conflict.push_back( expl[i] );
+ }
+ }
+ }
+ prev = it2->first;
+ }
+ }
+ }
+ Debug("uf-ss") << "Explanation of clique (size=" << conflict.size() << ") = " << std::endl;
+ for( int i=0; i<(int)conflict.size(); i++ ){
+ Debug("uf-ss") << conflict[i] << " ";
+ }
+ Debug("uf-ss") << std::endl;
+ //now, make the conflict
+ Node conflictNode = conflict.size()==1 ? conflict[0] : NodeManager::currentNM()->mkNode( AND, conflict );
+ //add cardinality constraint
+ //Node cardNode = NodeManager::currentNM()->mkNode( CARDINALITY_CONSTRAINT, d_cardinality_lemma_term,
+ // NodeManager::currentNM()->mkConst( Rational(d_cardinality) ) );
+ Node cardNode = d_cardinality_literal[ d_cardinality ];
+ conflictNode = NodeManager::currentNM()->mkNode( IMPLIES, conflictNode, cardNode.notNode() );
+ Debug("uf-ss-lemma") << "*** Add clique conflict " << conflictNode << std::endl;
+ //Notice() << "*** Add clique conflict " << conflictNode << std::endl;
+ out->lemma( conflictNode );
+ ++( d_th->getStrongSolver()->d_statistics.d_clique_lemmas );
+
+ //DO_THIS: ensure that the same clique is not reported??? Check standard effort after assertDisequal can produce same clique.
+}
+
+/** new node */
+void StrongSolverTheoryUf::ConflictFind::newEqClass( Node n ){
+ if( d_regions_map.find( n )==d_regions_map.end() ){
+ d_regions_map[n] = d_regions_index;
+ Debug("uf-ss") << "StrongSolverTheoryUf: New Eq Class " << n << std::endl;
+ Debug("uf-ss-debug") << d_regions_index << " " << (int)d_regions.size() << std::endl;
+ if( d_regions_index<d_regions.size() ){
+ d_regions[ d_regions_index ]->debugPrint("uf-ss-debug",true);
+ d_regions[ d_regions_index ]->d_valid = true;
+ //Assert( d_regions[ d_regions_index ]->d_valid );
+ Assert( d_regions[ d_regions_index ]->getNumReps()==0 );
+ }else{
+ d_regions.push_back( new Region( this, d_th->getSatContext() ) );
+ }
+ d_regions[ d_regions_index ]->setRep( n, true );
+ d_regions_index = d_regions_index + 1;
+ d_reps = d_reps + 1;
+ }
+}
+
+/** merge */
+void StrongSolverTheoryUf::ConflictFind::merge( Node a, Node b ){
+ //Assert( a==d_th->d_equalityEngine.getRepresentative( a ) );
+ //Assert( b==d_th->d_equalityEngine.getRepresentative( b ) );
+ Debug("uf-ss") << "StrongSolverTheoryUf: Merging " << a << " = " << b << "..." << std::endl;
+ if( a!=b ){
+ Assert( d_regions_map.find( a )!=d_regions_map.end() );
+ Assert( d_regions_map.find( b )!=d_regions_map.end() );
+ int ai = d_regions_map[a];
+ int bi = d_regions_map[b];
+ Debug("uf-ss") << " regions: " << ai << " " << bi << std::endl;
+ if( ai!=bi ){
+ if( d_regions[ai]->getNumReps()==1 ){
+ combineRegions( bi, ai );
+ d_regions[bi]->setEqual( a, b );
+ checkRegion( bi );
+ }else if( d_regions[bi]->getNumReps()==1 ){
+ combineRegions( ai, bi );
+ d_regions[ai]->setEqual( a, b );
+ checkRegion( ai );
+ }else{
+ // either move a to d_regions[bi], or b to d_regions[ai]
+ int aex = d_regions[ai]->d_nodes[a]->getNumInternalDisequalities() - getNumDisequalitiesToRegion( a, bi );
+ int bex = d_regions[bi]->d_nodes[b]->getNumInternalDisequalities() - getNumDisequalitiesToRegion( b, ai );
+ //based on which would produce the fewest number of external disequalities
+ if( aex<bex ){
+ moveNode( a, bi );
+ d_regions[bi]->setEqual( a, b );
+ }else{
+ moveNode( b, ai );
+ d_regions[ai]->setEqual( a, b );
+ }
+ checkRegion( ai );
+ checkRegion( bi );
+ }
+ }else{
+ d_regions[ai]->setEqual( a, b );
+ checkRegion( ai );
+ }
+ d_reps = d_reps - 1;
+ d_regions_map[b] = -1;
+ }
+ Debug("uf-ss") << "Done merge." << std::endl;
+}
+
+/** assert terms are disequal */
+void StrongSolverTheoryUf::ConflictFind::assertDisequal( Node a, Node b, Node reason ){
+ //if they are not already disequal
+ a = d_th->d_equalityEngine.getRepresentative( a );
+ b = d_th->d_equalityEngine.getRepresentative( b );
+ if( !d_th->d_equalityEngine.areDisequal( a, b, true ) ){
+ Debug("uf-ss") << "Assert disequal " << a << " != " << b << "..." << std::endl;
+ //if( reason.getKind()!=NOT || ( reason[0].getKind()!=EQUAL && reason[0].getKind()!=IFF ) ||
+ // a!=reason[0][0] || b!=reason[0][1] ){
+ // Notice() << "Assert disequal " << a << " != " << b << ", reason = " << reason << "..." << std::endl;
+ //}
+ Debug("uf-ss-disequal") << "Assert disequal " << a << " != " << b << "..." << std::endl;
+ //add to list of disequalities
+ if( d_disequalities_index<d_disequalities.size() ){
+ d_disequalities[d_disequalities_index] = reason;
+ }else{
+ d_disequalities.push_back( reason );
+ }
+ d_disequalities_index = d_disequalities_index + 1;
+ //now, add disequalities to regions
+ Assert( d_regions_map.find( a )!=d_regions_map.end() );
+ Assert( d_regions_map.find( b )!=d_regions_map.end() );
+ int ai = d_regions_map[a];
+ int bi = d_regions_map[b];
+ Debug("uf-ss") << " regions: " << ai << " " << bi << std::endl;
+ if( ai==bi ){
+ //internal disequality
+ d_regions[ai]->setDisequal( a, b, 1, true );
+ d_regions[ai]->setDisequal( b, a, 1, true );
+ }else{
+ //external disequality
+ d_regions[ai]->setDisequal( a, b, 0, true );
+ d_regions[bi]->setDisequal( b, a, 0, true );
+ checkRegion( ai );
+ checkRegion( bi );
+ }
+ //Notice() << "done" << std::endl;
+ }
+}
+
+void StrongSolverTheoryUf::ConflictFind::assertCardinality( int c, bool val ){
+ Assert( d_cardinality_literal.find( c )!=d_cardinality_literal.end() );
+ d_cardinality_assertions[ d_cardinality_literal[c] ] = val;
+ if( val ){
+ d_hasCard = true;
+ }
+}
+
+bool StrongSolverTheoryUf::ConflictFind::checkRegion( int ri, bool rec ){
+ if( isValid(ri) ){
+ Assert( d_cardinality>0 );
+ //first check if region is in conflict
+ std::vector< Node > clique;
+ if( d_regions[ri]->check( Theory::EFFORT_STANDARD, d_cardinality, clique ) ){
+ //explain clique
+ explainClique( clique, &d_th->getOutputChannel() );
+ return false;
+ }else if( d_regions[ri]->getMustCombine( d_cardinality ) ){
+ //this region must merge with another
+ Debug("uf-ss-check-region") << "We must combine Region #" << ri << ". " << std::endl;
+ d_regions[ri]->debugPrint("uf-ss-check-region");
+ ////alternatively, check if we can reduce the number of external disequalities by moving single nodes
+ //for( std::map< Node, bool >::iterator it = d_regions[i]->d_reps.begin(); it != d_regions[i]->d_reps.end(); ++it ){
+ // if( it->second ){
+ // int inDeg = d_regions[i]->d_disequalities_size[1][ it-> first ];
+ // int outDeg = d_regions[i]->d_disequalities_size[1][ it-> first ];
+ // if( inDeg<outDeg ){
+ // }
+ // }
+ //}
+ //take region with maximum disequality density
+ double maxScore = 0;
+ int maxRegion = -1;
+ std::map< int, int > regions_diseq;
+ getDisequalitiesToRegions( ri, regions_diseq );
+ for( std::map< int, int >::iterator it = regions_diseq.begin(); it != regions_diseq.end(); ++it ){
+ Debug("uf-ss-check-region") << it->first << " : " << it->second << std::endl;
+ }
+ for( std::map< int, int >::iterator it = regions_diseq.begin(); it != regions_diseq.end(); ++it ){
+ Assert( it->first!=ri );
+ Assert( isValid( it->first ) );
+ Assert( d_regions[ it->first ]->getNumReps()>0 );
+ double tempScore = double(it->second)/double(d_regions[it->first]->getNumReps() );
+ if( tempScore>maxScore ){
+ maxRegion = it->first;
+ maxScore = tempScore;
+ }
+ }
+ Assert( maxRegion!=-1 );
+ Debug("uf-ss-check-region") << "Combine with region #" << maxRegion << ":" << std::endl;
+ d_regions[maxRegion]->debugPrint("uf-ss-check-region");
+ combineRegions( ri, maxRegion );
+ if( rec ){
+ checkRegion( ri, rec );
+ }
+ //std::vector< Node > clique;
+ //if( d_regions[ri]->check( Theory::EFFORT_STANDARD, cardinality, clique ) ){
+ // //explain clique
+ // Notice() << "found clique " << std::endl;
+ //}
+ return true;
+ }
+ }
+ return false;
+}
+
+bool StrongSolverTheoryUf::ConflictFind::disambiguateTerms( OutputChannel* out ){
+ Debug("uf-ss-disamb") << "Disambiguate terms." << std::endl;
+ bool lemmaAdded = false;
+ //otherwise, determine ambiguous pairs of ground terms for relevant sorts
+ TermDb* db = d_th->getQuantifiersEngine()->getTermDatabase();
+ for( std::map< Node, std::vector< Node > >::iterator it = db->d_op_map.begin(); it != db->d_op_map.end(); ++it ){
+ Debug("uf-ss-disamb") << "Check " << it->first << std::endl;
+ if( it->second.size()>1 ){
+ if( StrongSolverTheoryUf::involvesRelevantType( it->second[0] ) ){
+ for( int i=0; i<(int)it->second.size(); i++ ){
+ for( int j=(i+1); j<(int)it->second.size(); j++ ){
+ Kind knd = it->second[i].getType()==NodeManager::currentNM()->booleanType() ? IFF : EQUAL;
+ Node eq = NodeManager::currentNM()->mkNode( knd, it->second[i], it->second[j] );
+ eq = Rewriter::rewrite(eq);
+ //determine if they are ambiguous
+ if( d_term_amb.find( eq )==d_term_amb.end() ){
+ Debug("uf-ss-disamb") << "Check disambiguate " << it->second[i] << " " << it->second[j] << std::endl;
+ d_term_amb[ eq ] = true;
+ //if they are equal
+ if( d_th->d_equalityEngine.areEqual( it->second[i], it->second[j] ) ){
+ d_term_amb[ eq ] = false;
+ }else{
+ //if an argument is disequal, then they are not ambiguous
+ for( int k=0; k<(int)it->second[i].getNumChildren(); k++ ){
+ if( d_th->d_equalityEngine.areDisequal( it->second[i][k], it->second[j][k], true ) ){
+ d_term_amb[ eq ] = false;
+ break;
+ }
+ }
+ }
+ if( d_term_amb[ eq ] ){
+ Debug("uf-ss-disamb") << "Disambiguate " << it->second[i] << " " << it->second[j] << std::endl;
+ //must add lemma
+ std::vector< Node > children;
+ children.push_back( eq );
+ for( int k=0; k<(int)it->second[i].getNumChildren(); k++ ){
+ Kind knd2 = it->second[i][k].getType()==NodeManager::currentNM()->booleanType() ? IFF : EQUAL;
+ Node eqc = NodeManager::currentNM()->mkNode( knd2, it->second[i][k], it->second[j][k] );
+ children.push_back( eqc.notNode() );
+ }
+ Assert( children.size()>1 );
+ Node lem = NodeManager::currentNM()->mkNode( OR, children );
+ Debug( "uf-ss-lemma" ) << "*** Diambiguate lemma : " << lem << std::endl;
+ //Notice() << "*** Diambiguate lemma : " << lem << std::endl;
+ out->lemma( lem );
+ d_term_amb[ eq ] = false;
+ lemmaAdded = true;
+ ++( d_th->getStrongSolver()->d_statistics.d_disamb_term_lemmas );
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ Debug("uf-ss-disamb") << "Done disambiguate terms. " << lemmaAdded << std::endl;
+ return lemmaAdded;
+}
+
+/** check */
+void StrongSolverTheoryUf::ConflictFind::check( Theory::Effort level, OutputChannel* out ){
+ if( level>=Theory::EFFORT_STANDARD ){
+ Assert( d_cardinality>0 );
+ Debug("uf-ss") << "StrongSolverTheoryUf: Check " << level << " " << d_type << std::endl;
+ //Notice() << "StrongSolverTheoryUf: Check " << level << std::endl;
+ if( d_reps<=(unsigned)d_cardinality ){
+ Debug("uf-ss-debug") << "We have " << d_reps << " representatives for type " << d_type << ", <= " << d_cardinality << std::endl;
+ if( level==Theory::EFFORT_FULL ){
+ Debug("uf-ss-sat") << "We have " << d_reps << " representatives for type " << d_type << ", <= " << d_cardinality << std::endl;
+ //Notice() << "We have " << d_reps << " representatives for type " << d_type << ", <= " << cardinality << std::endl;
+ //Notice() << "Model size for " << d_type << " is " << cardinality << std::endl;
+ //Notice() << cardinality << " ";
+ }
+ return;
+ }else{
+ //do a check within each region
+ for( int i=0; i<(int)d_regions_index; i++ ){
+ if( d_regions[i]->d_valid ){
+ std::vector< Node > clique;
+ if( d_regions[i]->check( level, d_cardinality, clique ) ){
+ //explain clique
+ explainClique( clique, out );
+ return;
+ }else{
+ Debug("uf-ss-debug") << "No clique in Region #" << i << std::endl;
+ }
+ }
+ }
+ if( level==Theory::EFFORT_FULL ){
+ Debug("uf-ss-debug") << "Add splits?" << std::endl;
+ //see if we have any recommended splits
+ bool addedLemma = false;
+ for( int i=0; i<(int)d_regions_index; i++ ){
+ if( d_regions[i]->d_valid ){
+ if( d_regions[i]->hasSplits() ){
+ d_regions[i]->addSplit( out );
+ addedLemma = true;
+ ++( d_th->getStrongSolver()->d_statistics.d_split_lemmas );
+ }
+ }
+ }
+ if( !addedLemma ){
+ Debug("uf-ss") << "No splits added." << std::endl;
+ if( Options::current()->fmfRegionSat ){
+ //otherwise, try to disambiguate individual terms
+ if( !disambiguateTerms( out ) ){
+ //no disequalities can be propagated
+ //we are in a situation where it suffices to apply a coloring to equivalence classes
+ //due to our invariants, we know no coloring conflicts will occur between regions, and thus
+ // we are SAT in this case.
+ Debug("uf-ss-sat") << "SAT: regions = " << getNumRegions() << std::endl;
+ //Notice() << "Model size for " << d_type << " is " << cardinality << ", regions = " << getNumRegions() << std::endl;
+ debugPrint("uf-ss-sat");
+ }
+ }else{
+ //naive strategy. combine the first two valid regions
+ int regIndex = -1;
+ for( int i=0; i<(int)d_regions_index; i++ ){
+ if( d_regions[i]->d_valid ){
+ if( regIndex==-1 ){
+ regIndex = i;
+ }else{
+ combineRegions( regIndex, i );
+ check( level, out );
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+}
+
+void StrongSolverTheoryUf::ConflictFind::propagate( Theory::Effort level, OutputChannel* out ){
+ Assert( d_cardinality>0 );
+
+ //propagate the current cardinality as a decision literal
+ Node cn = d_cardinality_literal[ d_cardinality ];
+ Debug("uf-ss-prop-as-dec") << "Propagate as decision " << d_type << ", cardinality = " << d_cardinality << std::endl;
+ Assert( !cn.isNull() );
+ if( d_cardinality_assertions.find( cn )==d_cardinality_assertions.end() ){
+ out->propagateAsDecision( d_cardinality_literal[ d_cardinality ] );
+ Debug("uf-ss-prop-as-dec") << "Propagate as decision " << d_cardinality_literal[ d_cardinality ];
+ Debug("uf-ss-prop-as-dec") << " " << d_cardinality_literal[ d_cardinality ][0].getType() << std::endl;
+ }
+
+}
+
+void StrongSolverTheoryUf::ConflictFind::debugPrint( const char* c ){
+ Debug( c ) << "-- Conflict Find:" << std::endl;
+ Debug( c ) << "Number of reps = " << d_reps << std::endl;
+ Debug( c ) << "Cardinality req = " << d_cardinality << std::endl;
+ unsigned debugReps = 0;
+ for( int i=0; i<(int)d_regions_index; i++ ){
+ if( d_regions[i]->d_valid ){
+ Debug( c ) << "Region #" << i << ": " << std::endl;
+ d_regions[i]->debugPrint( c, true );
+ Debug( c ) << std::endl;
+ for( std::map< Node, Region::RegionNodeInfo* >::iterator it = d_regions[i]->d_nodes.begin(); it != d_regions[i]->d_nodes.end(); ++it ){
+ if( it->second->d_valid ){
+ if( d_regions_map[ it->first ]!=i ){
+ Debug( c ) << "***Bad regions map : " << it->first << " " << d_regions_map[ it->first ].get() << std::endl;
+ }
+ }
+ }
+ debugReps += d_regions[i]->getNumReps();
+ }
+ }
+ if( debugReps!=d_reps ){
+ Debug( c ) << "***Bad reps: " << d_reps << ", actual = " << debugReps << std::endl;
+ }
+}
+
+int StrongSolverTheoryUf::ConflictFind::getNumRegions(){
+ int count = 0;
+ for( int i=0; i<(int)d_regions_index; i++ ){
+ if( d_regions[i]->d_valid ){
+ count++;
+ }
+ }
+ return count;
+}
+
+void StrongSolverTheoryUf::ConflictFind::setCardinality( int c, OutputChannel* out ){
+ d_cardinality = c;
+ //add appropriate lemma
+ Node lem = getCardinalityLemma();
+ out->lemma( lem );
+ //add the appropriate lemma
+ Debug("uf-ss-fmf") << "Set cardinality " << d_type << " = " << c << std::endl;
+ Debug("uf-ss-prop-as-dec") << "Propagate as decision " << lem[0] << std::endl;
+ out->propagateAsDecision( lem[0] );
+ d_is_cardinality_requested = true;
+ d_is_cardinality_requested_c = true;
+ //now, require old literal to be decided false
+ //if( d_cardinality_literal.find( c-1 )!=d_cardinality_literal.end() ){
+ // Debug("uf-ss-req-phase") << "Require phase " << d_cardinality_literal[c-1] << " = false " << std::endl;
+ // out->requirePhase( d_cardinality_literal[c-1], false );
+ //}
+}
+
+void StrongSolverTheoryUf::ConflictFind::getRepresentatives( std::vector< Node >& reps ){
+ if( !Options::current()->fmfRegionSat ){
+ bool foundRegion = false;
+ 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 );
+ foundRegion = true;
+ }
+ }
+ }else{
+ Unimplemented("Build representatives for fmf region sat is not implemented");
+ }
+}
+
+bool StrongSolverTheoryUf::ConflictFind::minimize( OutputChannel* out ){
+ int validRegionIndex = -1;
+ for( int i=0; i<(int)d_regions_index; i++ ){
+ if( d_regions[i]->d_valid ){
+ if( validRegionIndex!=-1 ){
+ combineRegions( validRegionIndex, i );
+ if( !d_regions[validRegionIndex]->minimize( out ) ){
+ return false;
+ }
+ }else{
+ validRegionIndex = i;
+ }
+ }
+ }
+ if( !d_regions[validRegionIndex]->minimize( out ) ){
+ return false;
+ }
+ return true;
+}
+
+
+Node StrongSolverTheoryUf::ConflictFind::getCardinalityLemma(){
+ if( d_cardinality_lemma.find( d_cardinality )==d_cardinality_lemma.end() ){
+ if( d_cardinality_lemma_term.isNull() ){
+ std::stringstream ss;
+ ss << "fmf_term_" << d_type;
+ d_cardinality_lemma_term = NodeManager::currentNM()->mkVar( ss.str(), d_type );
+ ModelBasisAttribute mba;
+ d_cardinality_lemma_term.setAttribute(mba,true);
+ }
+ Node lem = NodeManager::currentNM()->mkNode( CARDINALITY_CONSTRAINT, d_cardinality_lemma_term,
+ NodeManager::currentNM()->mkConst( Rational( d_cardinality ) ) );
+ lem = Rewriter::rewrite(lem);
+ d_cardinality_literal[ d_cardinality ] = lem;
+ lem = NodeManager::currentNM()->mkNode( OR, lem, lem.notNode() );
+ d_cardinality_lemma[ d_cardinality ] = lem;
+ }
+ return d_cardinality_lemma[ d_cardinality ];
+}
+
+StrongSolverTheoryUf::StrongSolverTheoryUf(context::Context* c, context::UserContext* u, OutputChannel& out, TheoryUF* th) :
+d_out( &out ),
+d_th( th ),
+d_conf_find_init( c )
+{
+
+}
+
+/** new node */
+void StrongSolverTheoryUf::newEqClass( Node n ){
+ TypeNode tn = n.getType();
+ ConflictFind* c = getConflictFind( tn );
+ if( c ){
+ Debug("uf-ss-solver") << "StrongSolverTheoryUf: New eq class " << n << " " << tn << std::endl;
+ c->newEqClass( n );
+ }
+ //else if( isRelevantType( tn ) ){
+ // //Debug("uf-ss-solver") << "WAIT: StrongSolverTheoryUf: New eq class " << n << " " << tn << std::endl;
+ // //d_new_eq_class_waiting[tn].push_back( n );
+ //}
+}
+
+/** merge */
+void StrongSolverTheoryUf::merge( Node a, Node b ){
+ TypeNode tn = a.getType();
+ ConflictFind* c = getConflictFind( tn );
+ if( c ){
+ Debug("uf-ss-solver") << "StrongSolverTheoryUf: Merge " << a << " " << b << " " << tn << std::endl;
+ c->merge( a, b );
+ }
+ //else if( isRelevantType( tn ) ){
+ //}
+}
+
+/** assert terms are disequal */
+void StrongSolverTheoryUf::assertDisequal( Node a, Node b, Node reason ){
+ TypeNode tn = a.getType();
+ ConflictFind* c = getConflictFind( tn );
+ if( c ){
+ Debug("uf-ss-solver") << "StrongSolverTheoryUf: Assert disequal " << a << " " << b << " " << tn << std::endl;
+ //Assert( d_th->d_equalityEngine.getRepresentative( a )==a );
+ //Assert( d_th->d_equalityEngine.getRepresentative( b )==b );
+ c->assertDisequal( a, b, reason );
+ }
+ //else if( isRelevantType( tn ) ){
+ //}
+}
+
+/** assert a node */
+void StrongSolverTheoryUf::assertNode( Node n, bool isDecision ){
+ Debug("uf-ss-assert") << "Assert " << n << " " << isDecision << std::endl;
+ if( n.getKind()==CARDINALITY_CONSTRAINT ){
+ TypeNode tn = n[0].getType();
+ Assert( d_conf_find[tn]->getCardinality()>0 );
+ Assert( isRelevantType( tn ) );
+ Assert( d_conf_find[tn] );
+ long nCard = n[1].getConst<Rational>().getNumerator().getLong();
+ d_conf_find[tn]->assertCardinality( nCard, true );
+ if( nCard==d_conf_find[tn]->getCardinality() ){
+ d_conf_find[tn]->d_is_cardinality_set = true;
+ d_conf_find[tn]->d_is_cardinality_requested = false;
+ d_conf_find[tn]->d_is_cardinality_requested_c = false;
+ }
+ }else if( n.getKind()==NOT && n[0].getKind()==CARDINALITY_CONSTRAINT ){
+ //must add new lemma
+ Node nn = n[0];
+ TypeNode tn = nn[0].getType();
+ Assert( isRelevantType( tn ) );
+ Assert( d_conf_find[tn] );
+ long nCard = nn[1].getConst<Rational>().getNumerator().getLong();
+ d_conf_find[tn]->assertCardinality( nCard, false );
+ if( nCard==d_conf_find[tn]->getCardinality() ){
+ AlwaysAssert(!isDecision, "Error: Negative cardinality node decided upon");
+ Debug("uf-ss-fmf") << "No model of size " << d_conf_find[tn]->getCardinality() << " exists for type " << tn << std::endl;
+ //Notice() << "No model of size " << d_conf_find[tn]->getCardinality() << " exists for type " << tn << std::endl;
+ //increment to next cardinality
+ d_statistics.d_max_model_size.maxAssign( d_conf_find[tn]->getCardinality() + 1 );
+ d_conf_find[tn]->setCardinality( d_conf_find[tn]->getCardinality() + 1, d_out );
+ //Notice() << d_conf_find[tn]->getCardinality() << " ";
+ ////give up permanently on this cardinality
+ //d_out->lemma( n );
+ }
+ }else{
+ ////FIXME: this is too strict: theory propagations are showing up as isDecision=true, but
+ //// a theory propagation is not a decision.
+ //if( isDecision ){
+ // for( std::map< TypeNode, ConflictFind* >::iterator it = d_conf_find.begin(); it != d_conf_find.end(); ++it ){
+ // if( !it->second->hasCardinalityAsserted() ){
+ // Notice() << "Assert " << n << " " << isDecision << std::endl;
+ // Notice() << "Error: constraint asserted before cardinality for " << it->first << std::endl;
+ // Unimplemented();
+ // }
+ // }
+ //}
+ }
+}
+
+
+/** check */
+void StrongSolverTheoryUf::check( Theory::Effort level ){
+ Debug("uf-ss-solver") << "StrongSolverTheoryUf: check " << level << std::endl;
+ if( level==Theory::EFFORT_FULL ){
+ debugPrint( "uf-ss-debug" );
+ }
+ for( std::map< TypeNode, ConflictFind* >::iterator it = d_conf_find.begin(); it != d_conf_find.end(); ++it ){
+ it->second->check( level, d_out );
+ }
+ Debug("uf-ss-solver") << "Done StrongSolverTheoryUf: check " << level << std::endl;
+}
+
+/** propagate */
+void StrongSolverTheoryUf::propagate( Theory::Effort level ){
+ for( std::map< TypeNode, ConflictFind* >::iterator it = d_conf_find.begin(); it != d_conf_find.end(); ++it ){
+ it->second->propagate( level, d_out );
+ }
+}
+
+void StrongSolverTheoryUf::preRegisterTerm( TNode n ){
+ //shouldn't have to preregister this type (it may be that there are no quantifiers over tn) FIXME
+ TypeNode tn = n.getType();
+ if( isRelevantType( tn ) ){
+ preRegisterType( tn );
+ }
+}
+
+void StrongSolverTheoryUf::registerQuantifier( Node f ){
+ Debug("uf-ss-register") << "Register quantifier " << f << std::endl;
+ //must ensure the quantifier does not quantify over arithmetic
+ for( int i=0; i<(int)f[0].getNumChildren(); i++ ){
+ TypeNode tn = f[0][i].getType();
+ if( isRelevantType( tn ) ){
+ preRegisterType( tn );
+ }else{
+ if( tn==NodeManager::currentNM()->integerType() || tn==NodeManager::currentNM()->realType() ){
+ Debug("uf-ss-na") << "Error: Cannot perform finite model finding on arithmetic quantifier";
+ Debug("uf-ss-na") << " (" << f << ")";
+ Debug("uf-ss-na") << std::endl;
+ Unimplemented("Cannot perform finite model finding on arithmetic quantifier");
+ }else if( tn.isDatatype() ){
+ Debug("uf-ss-na") << "Error: Cannot perform finite model finding on datatype quantifier";
+ Debug("uf-ss-na") << " (" << f << ")";
+ Debug("uf-ss-na") << std::endl;
+ Unimplemented("Cannot perform finite model finding on datatype quantifier");
+ }
+ }
+ }
+}
+
+void StrongSolverTheoryUf::preRegisterType( TypeNode tn ){
+ if( d_conf_find.find( tn )==d_conf_find.end() ){
+ Debug("uf-ss-register") << "Preregister " << tn << "." << std::endl;
+ //enter into incremental finite model finding mode: try cardinality = 1 first
+ //if( !d_conf_types.empty() ){
+ // Debug("uf-ss-na") << "Strong solver unimplemented for multiple sorts." << std::endl;
+ // Unimplemented();
+ //}
+ d_conf_find[tn] = new ConflictFind( tn, d_th->getSatContext(), d_th );
+ //assign cardinality restriction
+ d_statistics.d_max_model_size.maxAssign( 1 );
+ d_conf_find[tn]->setCardinality( 1, d_out );
+ ////add waiting equivalence classes now
+ //if( !d_new_eq_class_waiting[tn].empty() ){
+ // Debug("uf-ss-register") << "Add " << (int)d_new_eq_class_waiting[tn].size() << " new eq classes." << std::endl;
+ // for( int i=0; i<(int)d_new_eq_class_waiting[tn].size(); i++ ){
+ // newEqClass( d_new_eq_class_waiting[tn][i] );
+ // }
+ // d_new_eq_class_waiting[tn].clear();
+ //}
+ d_conf_types.push_back( tn );
+ }
+}
+
+StrongSolverTheoryUf::ConflictFind* StrongSolverTheoryUf::getConflictFind( TypeNode tn ){
+ std::map< TypeNode, ConflictFind* >::iterator it = d_conf_find.find( tn );
+ //pre-register the type if not done already
+ if( it==d_conf_find.end() ){
+ if( isRelevantType( tn ) ){
+ preRegisterType( tn );
+ it = d_conf_find.find( tn );
+ }
+ }
+ if( it!=d_conf_find.end() ){
+ //initialize the type if necessary
+ if( d_conf_find_init.find( tn )==d_conf_find_init.end() ){
+ //assign cardinality restriction
+ d_statistics.d_max_model_size.maxAssign( 1 );
+ it->second->setCardinality( 1, d_out );
+ d_conf_find_init[tn] = true;
+ }
+ return it->second;
+ }else{
+ return NULL;
+ }
+}
+
+void StrongSolverTheoryUf::notifyRestart(){
+ Debug("uf-ss-prop-as-dec") << "Restart?" << std::endl;
+}
+
+/** get cardinality for sort */
+int StrongSolverTheoryUf::getCardinality( TypeNode t ) {
+ ConflictFind* c = getConflictFind( t );
+ if( c ){
+ return c->getCardinality();
+ }else{
+ return -1;
+ }
+}
+
+void StrongSolverTheoryUf::getRepresentatives( TypeNode t, std::vector< Node >& reps ){
+ ConflictFind* c = getConflictFind( t );
+ if( c ){
+ c->getRepresentatives( reps );
+ }
+}
+
+Node StrongSolverTheoryUf::getCardinalityTerm( TypeNode t ){
+ ConflictFind* c = getConflictFind( t );
+ if( c ){
+ return c->getCardinalityTerm();
+ }else{
+ return Node::null();
+ }
+}
+
+bool StrongSolverTheoryUf::minimize(){
+ for( std::map< TypeNode, ConflictFind* >::iterator it = d_conf_find.begin(); it != d_conf_find.end(); ++it ){
+ if( !it->second->minimize( d_out ) ){
+ return false;
+ }
+ }
+ return true;
+}
+
+//print debug
+void StrongSolverTheoryUf::debugPrint( const char* c ){
+ //EqClassesIterator< TheoryUF::NotifyClass > eqc_iter( &((TheoryUF*)d_th)->d_equalityEngine );
+ //while( !eqc_iter.isFinished() ){
+ // Debug( c ) << "Eq class [[" << (*eqc_iter) << "]]" << std::endl;
+ // EqClassIterator< TheoryUF::NotifyClass > eqc_iter2( *eqc_iter, &((TheoryUF*)d_th)->d_equalityEngine );
+ // Debug( c ) << " ";
+ // while( !eqc_iter2.isFinished() ){
+ // Debug( c ) << "[" << (*eqc_iter2) << "] ";
+ // eqc_iter2++;
+ // }
+ // Debug( c ) << std::endl;
+ // eqc_iter++;
+ //}
+
+ for( std::map< TypeNode, ConflictFind* >::iterator it = d_conf_find.begin(); it != d_conf_find.end(); ++it ){
+ Debug( c ) << "Conflict find structure for " << it->first << ": " << std::endl;
+ it->second->debugPrint( c );
+ Debug( c ) << std::endl;
+ }
+}
+
+StrongSolverTheoryUf::Statistics::Statistics():
+ d_clique_lemmas("StrongSolverTheoryUf::Clique_Lemmas", 0),
+ d_split_lemmas("StrongSolverTheoryUf::Split_Lemmas", 0),
+ d_disamb_term_lemmas("StrongSolverTheoryUf::Disambiguate_Term_Lemmas", 0),
+ d_max_model_size("StrongSolverTheoryUf::Max_Model_Size", 0)
+{
+ StatisticsRegistry::registerStat(&d_clique_lemmas);
+ StatisticsRegistry::registerStat(&d_split_lemmas);
+ StatisticsRegistry::registerStat(&d_disamb_term_lemmas);
+ StatisticsRegistry::registerStat(&d_max_model_size);
+}
+
+StrongSolverTheoryUf::Statistics::~Statistics(){
+ StatisticsRegistry::unregisterStat(&d_clique_lemmas);
+ StatisticsRegistry::unregisterStat(&d_split_lemmas);
+ StatisticsRegistry::unregisterStat(&d_disamb_term_lemmas);
+ StatisticsRegistry::unregisterStat(&d_max_model_size);
+}
+
+bool StrongSolverTheoryUf::isRelevantType( TypeNode t ){
+ return t!=NodeManager::currentNM()->booleanType() &&
+ t!=NodeManager::currentNM()->integerType() &&
+ t!=NodeManager::currentNM()->realType() &&
+ t!=NodeManager::currentNM()->builtinOperatorType() &&
+ !t.isFunction() &&
+ !t.isDatatype();
+}
+
+bool StrongSolverTheoryUf::involvesRelevantType( Node n ){
+ if( n.getKind()==APPLY_UF ){
+ for( int i=0; i<(int)n.getNumChildren(); i++ ){
+ if( isRelevantType( n[i].getType() ) ){
+ return true;
+ }
+ }
+ }
+ return false;
+}
diff --git a/src/theory/uf/theory_uf_strong_solver.h b/src/theory/uf/theory_uf_strong_solver.h
new file mode 100644
index 000000000..e36441f6d
--- /dev/null
+++ b/src/theory/uf/theory_uf_strong_solver.h
@@ -0,0 +1,322 @@
+/********************* */
+/*! \file theory_uf_strong_solver.h
+ ** \verbatim
+ ** Original author: ajreynol
+ ** Major contributors: none
+ ** Minor contributors (to current version): none
+ ** This file is part of the CVC4 prototype.
+ ** Copyright (c) 2009, 2010, 2011 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
+ ** information.\endverbatim
+ **
+ ** \brief Theory uf strong solver
+ **/
+
+#include "cvc4_private.h"
+
+#ifndef __CVC4__THEORY_UF_STRONG_SOLVER_H
+#define __CVC4__THEORY_UF_STRONG_SOLVER_H
+
+#include "theory/theory.h"
+
+#include "context/context.h"
+#include "context/context_mm.h"
+#include "context/cdchunk_list.h"
+
+#include "util/stats.h"
+
+namespace CVC4 {
+namespace theory {
+
+struct ModelBasisAttributeId {};
+typedef expr::Attribute<ModelBasisAttributeId, bool> ModelBasisAttribute;
+
+namespace uf {
+
+class TheoryUF;
+
+class StrongSolverTheoryUf{
+protected:
+ typedef context::CDHashMap<Node, bool, NodeHashFunction> NodeBoolMap;
+ typedef context::CDHashMap<Node, int, NodeHashFunction> NodeIntMap;
+ typedef context::CDChunkList<Node> NodeList;
+ typedef context::CDList<bool> BoolList;
+ typedef context::CDHashMap<TypeNode, bool, TypeNodeHashFunction> TypeNodeBoolMap;
+public:
+ /** information for incremental conflict/clique finding for a particular sort */
+ class ConflictFind {
+ public:
+ /** a partition of the current equality graph for which cliques can occur internally */
+ class Region {
+ public:
+ /** conflict find pointer */
+ ConflictFind* d_cf;
+ /** information stored about each node in region */
+ class RegionNodeInfo {
+ public:
+ /** disequality list for node */
+ class DiseqList {
+ public:
+ DiseqList( context::Context* c ) : d_size( c, 0 ), d_disequalities( c ){}
+ ~DiseqList(){}
+ context::CDO< unsigned > d_size;
+ NodeBoolMap d_disequalities;
+ void setDisequal( Node n, bool valid ){
+ Assert( d_disequalities.find( n )==d_disequalities.end() || d_disequalities[n]!=valid );
+ d_disequalities[ n ] = valid;
+ d_size = d_size + ( valid ? 1 : -1 );
+ }
+ };
+ private:
+ DiseqList d_internal;
+ DiseqList d_external;
+ public:
+ /** constructor */
+ RegionNodeInfo( context::Context* c ) : d_internal( c ), d_external( c ), d_valid( c, true ){
+ d_disequalities[0] = &d_internal;
+ d_disequalities[1] = &d_external;
+ }
+ ~RegionNodeInfo(){}
+ context::CDO< bool > d_valid;
+ DiseqList* d_disequalities[2];
+
+ int getNumDisequalities() { return d_disequalities[0]->d_size + d_disequalities[1]->d_size; }
+ int getNumExternalDisequalities() { return d_disequalities[0]->d_size; }
+ int getNumInternalDisequalities() { return d_disequalities[1]->d_size; }
+ };
+ ///** end class RegionNodeInfo */
+ private:
+ //a postulated clique
+ NodeBoolMap d_testClique;
+ context::CDO< unsigned > d_testCliqueSize;
+ //disequalities needed for this clique to happen
+ NodeBoolMap d_splits;
+ context::CDO< unsigned > d_splitsSize;
+ /** get split */
+ Node getBestSplit();
+ private:
+ //number of valid representatives in this region
+ context::CDO< unsigned > d_reps_size;
+ //total disequality size (external)
+ context::CDO< unsigned > d_total_diseq_external;
+ //total disequality size (internal)
+ context::CDO< unsigned > d_total_diseq_internal;
+ public:
+ //constructor
+ Region( ConflictFind* cf, context::Context* c ) : d_cf( cf ), d_testClique( c ), d_testCliqueSize( c, 0 ),
+ d_splits( c ), d_splitsSize( c, 0 ), d_reps_size( c, 0 ), d_total_diseq_external( c, 0 ),
+ d_total_diseq_internal( c, 0 ), d_valid( c, true ) {
+ }
+ ~Region(){}
+ //region node infomation
+ std::map< Node, RegionNodeInfo* > d_nodes;
+ //whether region is valid
+ context::CDO< bool > d_valid;
+ public:
+ //get num reps
+ int getNumReps() { return d_reps_size; }
+ // has representative
+ bool hasRep( Node n ) { return d_nodes.find( n )!=d_nodes.end() && d_nodes[n]->d_valid; }
+ //take node from region
+ void takeNode( Region* r, Node n );
+ //merge with other region
+ void combine( Region* r );
+ /** set rep */
+ void setRep( Node n, bool valid );
+ /** merge */
+ void setEqual( Node a, Node b );
+ //set n1 != n2 to value 'valid', type is whether it is internal/external
+ void setDisequal( Node n1, Node n2, int type, bool valid );
+ // is disequal
+ bool isDisequal( Node n1, Node n2, int type );
+ public:
+ /** get must merge */
+ bool getMustCombine( int cardinality );
+ /** check for cliques */
+ bool check( Theory::Effort level, int cardinality, std::vector< Node >& clique );
+ /** has splits */
+ bool hasSplits() { return d_splitsSize>0; }
+ /** add split */
+ void addSplit( OutputChannel* out );
+ /** get representatives */
+ void getRepresentatives( std::vector< Node >& reps );
+ /** minimize */
+ bool minimize( OutputChannel* out );
+ /** get external disequalities */
+ void getNumExternalDisequalities( std::map< Node, int >& num_ext_disequalities );
+ //print debug
+ void debugPrint( const char* c, bool incClique = false );
+ };
+ private:
+ /** theory uf pointer */
+ TheoryUF* d_th;
+ /** regions used to d_region_index */
+ context::CDO< unsigned > d_regions_index;
+ /** vector of regions */
+ std::vector< Region* > d_regions;
+ /** map from Nodes to index of d_regions they exist in, -1 means invalid */
+ NodeIntMap d_regions_map;
+ /** regions used to d_region_index */
+ context::CDO< unsigned > d_disequalities_index;
+ /** list of all disequalities */
+ std::vector< Node > d_disequalities;
+ /** number of representatives in all regions */
+ context::CDO< unsigned > d_reps;
+ /** whether two terms are ambiguous (indexed by equalities) */
+ NodeBoolMap d_term_amb;
+ private:
+ /** merge regions */
+ void combineRegions( int ai, int bi );
+ /** move node n to region ri */
+ void moveNode( Node n, int ri );
+ /** get number of disequalities from node n to region ri */
+ int getNumDisequalitiesToRegion( Node n, int ri );
+ /** get number of disequalities from Region r to other regions */
+ void getDisequalitiesToRegions( int ri, std::map< int, int >& regions_diseq );
+ /** check if we need to combine region ri */
+ bool checkRegion( int ri, bool rec = true );
+ /** explain clique */
+ void explainClique( std::vector< Node >& clique, OutputChannel* out );
+ /** is valid */
+ bool isValid( int ri ) { return ri>=0 && ri<(int)d_regions_index && d_regions[ ri ]->d_valid; }
+ /** check ambiguous terms */
+ bool disambiguateTerms( OutputChannel* out );
+ private:
+ /** cardinality operating with */
+ context::CDO< int > d_cardinality;
+ /** type */
+ TypeNode d_type;
+ /** cardinality lemma term */
+ Node d_cardinality_lemma_term;
+ /** cardinality literals */
+ std::map< int, Node > d_cardinality_literal;
+ /** cardinality lemmas */
+ std::map< int, Node > d_cardinality_lemma;
+ /** cardinality assertions (indexed by cardinality literals ) */
+ NodeBoolMap d_cardinality_assertions;
+ public:
+ ConflictFind( TypeNode tn, context::Context* c, TheoryUF* th ) :
+ d_th( th ), d_regions_index( c, 0 ), d_regions_map( c ), d_disequalities_index( c, 0 ),
+ d_reps( c, 0 ), d_term_amb( c ), d_cardinality( c, 1 ), d_type( tn ),
+ d_cardinality_assertions( c ), d_is_cardinality_set( c, false ),
+ d_is_cardinality_requested_c( c, false ), d_is_cardinality_requested( false ), d_hasCard( c, false ){}
+ ~ConflictFind(){}
+ /** new node */
+ void newEqClass( Node n );
+ /** merge */
+ void merge( Node a, Node b );
+ /** assert terms are disequal */
+ void assertDisequal( Node a, Node b, Node reason );
+ /** assert cardinality */
+ void assertCardinality( int c, bool val );
+ /** whether cardinality has been asserted */
+ bool hasCardinalityAsserted() { return d_hasCard; }
+ /** check */
+ void check( Theory::Effort level, OutputChannel* out );
+ /** propagate */
+ void propagate( Theory::Effort level, OutputChannel* out );
+ //print debug
+ void debugPrint( const char* c );
+ /** set cardinality */
+ void setCardinality( int c, OutputChannel* out );
+ /** get cardinality */
+ int getCardinality() { return d_cardinality; }
+ /** get representatives */
+ void getRepresentatives( std::vector< Node >& reps );
+ /** get model basis term */
+ Node getCardinalityTerm() { return d_cardinality_lemma_term; }
+ /** minimize */
+ bool minimize( OutputChannel* out );
+ /** get cardinality lemma */
+ Node getCardinalityLemma();
+ public:
+ /** get number of regions (for debugging) */
+ int getNumRegions();
+ /** is cardinality set */
+ context::CDO< bool > d_is_cardinality_set;
+ context::CDO< bool > d_is_cardinality_requested_c;
+ bool d_is_cardinality_requested;
+ /** whether a positive cardinality constraint has been asserted */
+ context::CDO< bool > d_hasCard;
+ }; /** class ConflictFind */
+private:
+ /** The output channel for the strong solver. */
+ OutputChannel* d_out;
+ /** theory uf pointer */
+ TheoryUF* d_th;
+ /** conflict find structure, one for each type */
+ std::map< TypeNode, ConflictFind* > d_conf_find;
+ /** all types */
+ std::vector< TypeNode > d_conf_types;
+ /** whether conflict find data structures have been initialized */
+ TypeNodeBoolMap d_conf_find_init;
+ /** pre register type */
+ void preRegisterType( TypeNode tn );
+ /** get conflict find */
+ ConflictFind* getConflictFind( TypeNode tn );
+public:
+ StrongSolverTheoryUf(context::Context* c, context::UserContext* u, OutputChannel& out, TheoryUF* th);
+ ~StrongSolverTheoryUf() {}
+ /** new node */
+ void newEqClass( Node n );
+ /** merge */
+ void merge( Node a, Node b );
+ /** assert terms are disequal */
+ void assertDisequal( Node a, Node b, Node reason );
+ /** assert node */
+ void assertNode( Node n, bool isDecision );
+public:
+ /** check */
+ void check( Theory::Effort level );
+ /** propagate */
+ void propagate( Theory::Effort level );
+ /** preregister a term */
+ void preRegisterTerm( TNode n );
+ /** preregister a quantifier */
+ void registerQuantifier( Node f );
+ /** notify restart */
+ void notifyRestart();
+public:
+ /** identify */
+ std::string identify() const { return std::string("StrongSolverTheoryUf"); }
+ //print debug
+ void debugPrint( const char* c );
+public:
+ /** get number of types */
+ int getNumCardinalityTypes() { return (int)d_conf_types.size(); }
+ /** get type */
+ TypeNode getCardinalityType( int i ) { return d_conf_types[i]; }
+ /** get cardinality for sort */
+ int getCardinality( TypeNode t );
+ /** get representatives */
+ void getRepresentatives( TypeNode t, std::vector< Node >& reps );
+ /** get cardinality term */
+ Node getCardinalityTerm( TypeNode t );
+ /** minimize */
+ bool minimize();
+
+ class Statistics {
+ public:
+ IntStat d_clique_lemmas;
+ IntStat d_split_lemmas;
+ IntStat d_disamb_term_lemmas;
+ IntStat d_max_model_size;
+ Statistics();
+ ~Statistics();
+ };
+ /** statistics class */
+ Statistics d_statistics;
+
+ /** is relavant type */
+ static bool isRelevantType( TypeNode t );
+ /** involves relavant type */
+ static bool involvesRelevantType( Node n );
+};/* class StrongSolverTheoryUf */
+
+}
+}/* CVC4::theory namespace */
+}/* CVC4 namespace */
+
+#endif /* __CVC4__THEORY_UF_STRONG_SOLVER_H */
diff --git a/src/theory/uf/theory_uf_type_rules.h b/src/theory/uf/theory_uf_type_rules.h
index 3d7e51746..b68a11abd 100644
--- a/src/theory/uf/theory_uf_type_rules.h
+++ b/src/theory/uf/theory_uf_type_rules.h
@@ -59,6 +59,20 @@ public:
}
};/* class UfTypeRule */
+class CardinalityConstraintTypeRule {
+public:
+ inline static TypeNode computeType(NodeManager* nodeManager, TNode n, bool check)
+ throw(TypeCheckingExceptionPrivate) {
+ if( check ) {
+ TypeNode valType = n[1].getType(check);
+ if( valType != nodeManager->integerType() ) {
+ throw TypeCheckingExceptionPrivate(n, "cardinality constraint must be integer");
+ }
+ }
+ return nodeManager->booleanType();
+ }
+};/* class UfTypeRule */
+
}/* CVC4::theory::uf namespace */
}/* CVC4::theory namespace */
}/* CVC4 namespace */
diff --git a/src/theory/valuation.cpp b/src/theory/valuation.cpp
index cae62570c..ef02f6278 100644
--- a/src/theory/valuation.cpp
+++ b/src/theory/valuation.cpp
@@ -100,5 +100,9 @@ Node Valuation::ensureLiteral(TNode n) {
return preprocessed;
}
+bool Valuation::isDecision(Node lit) const {
+ return d_engine->getPropEngine()->isDecision(lit);
+}
+
}/* CVC4::theory namespace */
}/* CVC4 namespace */
diff --git a/src/theory/valuation.h b/src/theory/valuation.h
index ab47dcbdd..dd3848e7f 100644
--- a/src/theory/valuation.h
+++ b/src/theory/valuation.h
@@ -112,6 +112,14 @@ public:
*/
Node ensureLiteral(TNode n) CVC4_WARN_UNUSED_RESULT;
+ /**
+ * Returns whether the given lit (which must be a SAT literal) is a decision
+ * literal or not. Throws an exception if lit is not a SAT literal. "lit" may
+ * be in either phase; that is, if "lit" is a SAT literal, this function returns
+ * true both for lit and the negation of lit.
+ */
+ bool isDecision(Node lit) const;
+
};/* class Valuation */
}/* CVC4::theory namespace */
diff --git a/src/util/datatype.cpp b/src/util/datatype.cpp
index f009bbbbe..86a43c878 100644
--- a/src/util/datatype.cpp
+++ b/src/util/datatype.cpp
@@ -438,7 +438,7 @@ void DatatypeConstructor::resolve(ExprManager* em, DatatypeType self,
d_tester = em->mkVar(d_name.substr(d_name.find('\0') + 1), em->mkTesterType(self));
d_name.resize(d_name.find('\0'));
d_constructor = em->mkVar(d_name, em->mkConstructorType(*this, self));
- //associate constructor with all selectors
+ // associate constructor with all selectors
for(iterator i = begin(), i_end = end(); i != i_end; ++i) {
(*i).d_constructor = d_constructor;
}
diff --git a/src/util/datatype.h b/src/util/datatype.h
index d39d7110d..b701073c7 100644
--- a/src/util/datatype.h
+++ b/src/util/datatype.h
@@ -361,9 +361,9 @@ public:
*
* Datatypes may also be defined parametrically, such as this example:
*
- * DATATYPE
- * list[T] = cons(car : T, cdr : list[T]) | null,
- * tree = node(children : list[tree]) | leaf
+ * DATATYPE
+ * list[T] = cons(car : T, cdr : list[T]) | null,
+ * tree = node(children : list[tree]) | leaf
* END;
*
* Here, the definition of the parametric datatype list, where T is a type variable.
diff --git a/src/util/ite_removal.cpp b/src/util/ite_removal.cpp
index 9d2524170..9a4fc8dc2 100644
--- a/src/util/ite_removal.cpp
+++ b/src/util/ite_removal.cpp
@@ -79,23 +79,30 @@ Node RemoveITE::run(TNode node, std::vector<Node>& output,
}
// If not an ITE, go deep
- vector<Node> newChildren;
- bool somethingChanged = false;
- if(node.getMetaKind() == kind::metakind::PARAMETERIZED) {
- newChildren.push_back(node.getOperator());
- }
- // Remove the ITEs from the children
- for(TNode::const_iterator it = node.begin(), end = node.end(); it != end; ++it) {
- Node newChild = run(*it, output, iteSkolemMap);
- somethingChanged |= (newChild != *it);
- newChildren.push_back(newChild);
- }
+ if( node.getKind() != kind::FORALL &&
+ node.getKind() != kind::EXISTS &&
+ node.getKind() != kind::REWRITE_RULE ) {
+ vector<Node> newChildren;
+ bool somethingChanged = false;
+ if(node.getMetaKind() == kind::metakind::PARAMETERIZED) {
+ newChildren.push_back(node.getOperator());
+ }
+ // Remove the ITEs from the children
+ for(TNode::const_iterator it = node.begin(), end = node.end(); it != end; ++it) {
+ Node newChild = run(*it, output, iteSkolemMap);
+ somethingChanged |= (newChild != *it);
+ newChildren.push_back(newChild);
+ }
- // If changes, we rewrite
- if(somethingChanged) {
- cachedRewrite = nodeManager->mkNode(node.getKind(), newChildren);
- nodeManager->setAttribute(node, IteRewriteAttr(), cachedRewrite);
- return cachedRewrite;
+ // If changes, we rewrite
+ if(somethingChanged) {
+ cachedRewrite = nodeManager->mkNode(node.getKind(), newChildren);
+ nodeManager->setAttribute(node, IteRewriteAttr(), cachedRewrite);
+ return cachedRewrite;
+ } else {
+ nodeManager->setAttribute(node, IteRewriteAttr(), Node::null());
+ return node;
+ }
} else {
nodeManager->setAttribute(node, IteRewriteAttr(), Node::null());
return node;
diff --git a/src/util/options.cpp b/src/util/options.cpp
index 26881e052..1296fa5af 100644
--- a/src/util/options.cpp
+++ b/src/util/options.cpp
@@ -130,6 +130,25 @@ Options::Options() :
arithRewriteEqSetByUser(false),
ufSymmetryBreaker(false),
ufSymmetryBreakerSetByUser(false),
+ miniscopeQuant(true),
+ miniscopeQuantFreeVar(true),
+ prenexQuant(true),
+ varElimQuant(false),
+ cnfQuant(false),
+ preSkolemQuant(false),
+ smartTriggers(true),
+ registerQuantBodyTerms(false),
+ instWhenMode(INST_WHEN_FULL_LAST_CALL),
+ eagerInstQuant(false),
+ finiteModelFind(false),
+ fmfRegionSat(false),
+ fmfModelBasedInst(true),
+ efficientEMatching(false),
+ literalMatchMode(LITERAL_MATCH_NONE),
+ cbqi(false),
+ cbqiSetByUser(false),
+ userPatternsQuant(true),
+ flipDecision(false),
lemmaOutputChannel(NULL),
lemmaInputChannel(NULL),
threads(2),// default should be 1 probably, but say 2 for now
@@ -240,6 +259,27 @@ Additional CVC4 options:\n\
--enable-symmetry-breaker turns on UF symmetry breaker (Deharbe et al.,\n\
CADE 2011) [on by default only for QF_UF]\n\
--disable-symmetry-breaker turns off UF symmetry breaker\n\
+ --disable-miniscope-quant disable miniscope quantifiers\n\
+ --disable-miniscope-quant-fv disable miniscope quantifiers for ground subformulas\n\
+ --disable-prenex-quant disable prenexing of quantified formulas\n\
+ --var-elim-quant enable variable elimination of quantified formulas\n\
+ --cnf-quant apply CNF conversion to quantified formulas\n\
+ --pre-skolem-quant apply skolemization eagerly to bodies of quantified formulas\n\
+ --disable-smart-triggers disable smart triggers\n\
+ --register-quant-body-terms consider terms within bodies of quantified formulas for matching\n\
+ --inst-when=MODE when to apply instantiation\n\
+ --eager-inst-quant apply quantifier instantiation eagerly\n\
+ --finite-model-find use finite model finding heuristic for quantifier instantiation\n\
+ --use-fmf-region-sat use region-based SAT heuristic for finite model finding\n\
+ --disable-fmf-model-inst disable model-based instantiation for finite model finding\n\
+ --efficient-e-matching use efficient E-matching\n\
+ --literal-matching=MODE choose literal matching mode\n\
+ --enable-cbqi turns on counterexample-based quantifier instantiation [off by default]\n\
+ --disable-cbqi turns off counterexample-based quantifier instantiation\n\
+ --ignore-user-patterns ignore user-provided patterns for quantifier instantiation\n\
+ --enable-flip-decision turns on flip decision heuristic\n\
+ --disable-dio-solver turns off Linear Diophantine Equation solver (Griggio, JSAT 2012)\n\
+ --disable-arith-rewrite-equalities turns off the preprocessing rewrite turning equalities into a conjunction of inequalities.\n\
--threads=N sets the number of solver threads\n\
--threadN=string configures thread N (0..#threads-1)\n\
--filter-lemma-length=N don't share lemmas strictly longer than N\n\
@@ -439,7 +479,7 @@ void Options::printLanguageHelp(std::ostream& out) {
*/
enum OptionValue {
OPTION_VALUE_BEGIN = 256, /* avoid clashing with char options */
- SMTCOMP,
+ SMTCOMP,
STATS,
SEGV_NOSPIN,
OUTPUT_LANGUAGE,
@@ -496,6 +536,25 @@ enum OptionValue {
DISABLE_ARITHMETIC_REWRITE_EQUALITIES,
ENABLE_SYMMETRY_BREAKER,
DISABLE_SYMMETRY_BREAKER,
+ DISABLE_MINISCOPE_QUANT,
+ DISABLE_MINISCOPE_QUANT_FV,
+ DISABLE_PRENEX_QUANT,
+ VAR_ELIM_QUANT,
+ CNF_QUANT,
+ PRE_SKOLEM_QUANT,
+ DISABLE_SMART_TRIGGERS,
+ REGISTER_QUANT_BODY_TERMS,
+ INST_WHEN,
+ EAGER_INST_QUANT,
+ FINITE_MODEL_FIND,
+ FMF_REGION_SAT,
+ DISABLE_FMF_MODEL_BASED_INST,
+ EFFICIENT_E_MATCHING,
+ LITERAL_MATCHING,
+ ENABLE_CBQI,
+ DISABLE_CBQI,
+ IGNORE_USER_PATTERNS,
+ ENABLE_FLIP_DECISION,
PARALLEL_THREADS,
PARALLEL_SEPARATE_OUTPUT,
PORTFOLIO_FILTER_LENGTH,
@@ -602,6 +661,25 @@ static struct option cmdlineOptions[] = {
{ "disable-arith-rewrite-equalities", no_argument, NULL, DISABLE_ARITHMETIC_REWRITE_EQUALITIES },
{ "enable-symmetry-breaker", no_argument, NULL, ENABLE_SYMMETRY_BREAKER },
{ "disable-symmetry-breaker", no_argument, NULL, DISABLE_SYMMETRY_BREAKER },
+ { "disable-miniscope-quant", no_argument, NULL, DISABLE_MINISCOPE_QUANT },
+ { "disable-miniscope-quant-fv", no_argument, NULL, DISABLE_MINISCOPE_QUANT_FV },
+ { "disable-prenex-quant", no_argument, NULL, DISABLE_PRENEX_QUANT },
+ { "var-elim-quant", no_argument, NULL, VAR_ELIM_QUANT },
+ { "cnf-quant", no_argument, NULL, CNF_QUANT },
+ { "pre-skolem-quant", no_argument, NULL, PRE_SKOLEM_QUANT },
+ { "disable-smart-triggers", no_argument, NULL, DISABLE_SMART_TRIGGERS },
+ { "register-quant-body-terms", no_argument, NULL, REGISTER_QUANT_BODY_TERMS },
+ { "inst-when", required_argument, NULL, INST_WHEN },
+ { "eager-inst-quant", no_argument, NULL, EAGER_INST_QUANT },
+ { "finite-model-find", no_argument, NULL, FINITE_MODEL_FIND },
+ { "use-fmf-region-sat", no_argument, NULL, FMF_REGION_SAT },
+ { "disable-fmf-model-inst", no_argument, NULL, DISABLE_FMF_MODEL_BASED_INST },
+ { "efficient-e-matching", no_argument, NULL, EFFICIENT_E_MATCHING },
+ { "literal-matching", required_argument, NULL, LITERAL_MATCHING },
+ { "enable-cbqi", no_argument, NULL, ENABLE_CBQI },
+ { "disable-cbqi", no_argument, NULL, DISABLE_CBQI },
+ { "ignore-user-patterns", no_argument, NULL, IGNORE_USER_PATTERNS },
+ { "enable-flip-decision", no_argument, NULL, ENABLE_FLIP_DECISION },
{ "threads", required_argument, NULL, PARALLEL_THREADS },
{ "separate-output", no_argument, NULL, PARALLEL_SEPARATE_OUTPUT },
{ "filter-lemma-length", required_argument, NULL, PORTFOLIO_FILTER_LENGTH },
@@ -984,7 +1062,7 @@ throw(OptionException) {
case 'm':
produceModels = true;
break;
-
+
case PRODUCE_ASSIGNMENTS:
produceAssignments = true;
break;
@@ -1016,7 +1094,7 @@ throw(OptionException) {
throw OptionException("This is not a proof-enabled build of CVC4; --proof cannot be used");
#endif /* CVC4_PROOF */
break;
-
+
case NO_TYPE_CHECKING:
typeChecking = false;
earlyTypeChecking = false;
@@ -1073,7 +1151,91 @@ throw(OptionException) {
ufSymmetryBreaker = false;
ufSymmetryBreakerSetByUser = true;
break;
-
+ case DISABLE_MINISCOPE_QUANT:
+ miniscopeQuant = false;
+ break;
+ case DISABLE_MINISCOPE_QUANT_FV:
+ miniscopeQuantFreeVar = false;
+ break;
+ case DISABLE_PRENEX_QUANT:
+ prenexQuant = false;
+ break;
+ case VAR_ELIM_QUANT:
+ varElimQuant = true;
+ break;
+ case CNF_QUANT:
+ cnfQuant = true;
+ break;
+ case PRE_SKOLEM_QUANT:
+ preSkolemQuant = true;
+ break;
+ case DISABLE_SMART_TRIGGERS:
+ smartTriggers = false;
+ break;
+ case REGISTER_QUANT_BODY_TERMS:
+ registerQuantBodyTerms = true;
+ break;
+ case INST_WHEN:
+ if(!strcmp(optarg, "pre-full")) {
+ instWhenMode = INST_WHEN_PRE_FULL;
+ } else if(!strcmp(optarg, "full")) {
+ instWhenMode = INST_WHEN_FULL;
+ } else if(!strcmp(optarg, "full-last-call")) {
+ instWhenMode = INST_WHEN_FULL_LAST_CALL;
+ } else if(!strcmp(optarg, "last-call")) {
+ instWhenMode = INST_WHEN_LAST_CALL;
+ } else if(!strcmp(optarg, "help")) {
+ //puts(instWhenHelp.c_str());
+ exit(1);
+ } else {
+ throw OptionException(string("unknown option for --inst-when: `") +
+ optarg + "'. Try --inst-when help.");
+ }
+ break;
+ case EAGER_INST_QUANT:
+ eagerInstQuant = true;
+ break;
+ case FINITE_MODEL_FIND:
+ finiteModelFind = true;
+ break;
+ case FMF_REGION_SAT:
+ fmfRegionSat = true;
+ break;
+ case DISABLE_FMF_MODEL_BASED_INST:
+ fmfModelBasedInst = false;
+ break;
+ case EFFICIENT_E_MATCHING:
+ efficientEMatching = true;
+ break;
+ case LITERAL_MATCHING:
+ if(!strcmp(optarg, "none")) {
+ literalMatchMode = LITERAL_MATCH_NONE;
+ } else if(!strcmp(optarg, "predicate")) {
+ literalMatchMode = LITERAL_MATCH_PREDICATE;
+ } else if(!strcmp(optarg, "equality")) {
+ literalMatchMode = LITERAL_MATCH_EQUALITY;
+ } else if(!strcmp(optarg, "help")) {
+ //puts(literalMatchHelp.c_str());
+ exit(1);
+ } else {
+ throw OptionException(string("unknown option for --literal-matching: `") +
+ optarg + "'. Try --literal-matching help.");
+ }
+ break;
+ case ENABLE_CBQI:
+ cbqi = true;
+ cbqiSetByUser = true;
+ break;
+ case DISABLE_CBQI:
+ cbqi = false;
+ cbqiSetByUser = true;
+ break;
+ case IGNORE_USER_PATTERNS:
+ userPatternsQuant = false;
+ break;
+ case ENABLE_FLIP_DECISION:
+ flipDecision = true;
+ break;
case TIME_LIMIT:
{
int i = atoi(optarg);
@@ -1141,7 +1303,7 @@ throw(OptionException) {
optarg + "' is not between 0.0 and 1.0.");
}
break;
-
+
case SAT_RESTART_FIRST:
{
int i = atoi(optarg);
@@ -1151,7 +1313,7 @@ throw(OptionException) {
satRestartFirst = i;
break;
}
-
+
case SAT_RESTART_INC:
{
int i = atoi(optarg);
@@ -1341,7 +1503,7 @@ throw(OptionException) {
case PORTFOLIO_FILTER_LENGTH:
sharingFilterByLength = atoi(optarg);
- break;
+ break;
case ':':
// This can be a long or short option, and the way to get at the name of it is different.
diff --git a/src/util/options.h b/src/util/options.h
index 0584fdc2a..fb5f71060 100644
--- a/src/util/options.h
+++ b/src/util/options.h
@@ -310,6 +310,126 @@ struct CVC4_PUBLIC Options {
*/
bool ufSymmetryBreakerSetByUser;
+ /**
+ * Whether to mini-scope quantifiers.
+ * For example, forall x. ( P( x ) ^ Q( x ) ) will be rewritten to
+ * ( forall x. P( x ) ) ^ ( forall x. Q( x ) )
+ */
+ bool miniscopeQuant;
+
+ /**
+ * Whether to mini-scope quantifiers based on formulas with no free variables.
+ * For example, forall x. ( P( x ) V Q ) will be rewritten to
+ * ( forall x. P( x ) ) V Q
+ */
+ bool miniscopeQuantFreeVar;
+
+ /**
+ * Whether to prenex (nested universal) quantifiers
+ */
+ bool prenexQuant;
+
+ /**
+ * Whether to variable-eliminate quantifiers.
+ * For example, forall x y. ( P( x, y ) V x != c ) will be rewritten to
+ * forall y. P( c, y )
+ */
+ bool varElimQuant;
+
+ /**
+ * Whether to CNF quantifier bodies
+ */
+ bool cnfQuant;
+
+ /**
+ * Whether to pre-skolemize quantifier bodies.
+ * For example, forall x. ( P( x ) => (exists y. f( y ) = x) ) will be rewritten to
+ * forall x. P( x ) => f( S( x ) ) = x
+ */
+ bool preSkolemQuant;
+
+ /**
+ * Whether to use smart triggers
+ */
+ bool smartTriggers;
+
+ /**
+ * Whether to consider terms in the bodies of quantifiers for matching
+ */
+ bool registerQuantBodyTerms;
+
+ /** Enumeration of inst_when modes (when to instantiate). */
+ typedef enum {
+ /** Apply instantiation round before full effort (possibly at standard effort) */
+ INST_WHEN_PRE_FULL,
+ /** Apply instantiation round at full effort or above */
+ INST_WHEN_FULL,
+ /** Apply instantiation round at full effort half the time, and last call always */
+ INST_WHEN_FULL_LAST_CALL,
+ /** Apply instantiation round at last call only */
+ INST_WHEN_LAST_CALL,
+ } InstWhenMode;
+ /** When to perform instantiation round. */
+ InstWhenMode instWhenMode;
+
+ /**
+ * Whether to eagerly instantiate quantifiers
+ */
+ bool eagerInstQuant;
+
+ /**
+ * Whether to use finite model find heuristic
+ */
+ bool finiteModelFind;
+
+ /**
+ * Whether to use region-based SAT for finite model finding
+ */
+ bool fmfRegionSat;
+
+ /**
+ * Whether to use model-based exhaustive instantiation for finite model finding
+ */
+ bool fmfModelBasedInst;
+
+ /**
+ * Whether to use efficient E-matching
+ */
+ bool efficientEMatching;
+
+ /** Enumeration of literal matching modes. */
+ typedef enum {
+ /** Do not consider polarity of patterns */
+ LITERAL_MATCH_NONE,
+ /** Consider polarity of boolean predicates only */
+ LITERAL_MATCH_PREDICATE,
+ /** Consider polarity of boolean predicates, as well as equalities */
+ LITERAL_MATCH_EQUALITY,
+ } LiteralMatchMode;
+
+ /** Which literal matching mode to use. */
+ LiteralMatchMode literalMatchMode;
+
+ /**
+ * Whether to do counterexample-based quantifier instantiation
+ */
+ bool cbqi;
+
+ /**
+ * Whether the user explicitly requested that counterexample-based
+ * quantifier instantiation be enabled or disabled.
+ */
+ bool cbqiSetByUser;
+
+ /**
+ * Whether to use user patterns for pattern-based instantiation
+ */
+ bool userPatternsQuant;
+
+ /**
+ * Whether to use flip decision (useful when cbqi=true)
+ */
+ bool flipDecision;
/** The output channel to receive notfication events for new lemmas */
LemmaOutputChannel* lemmaOutputChannel;
generated by cgit on debian on lair
contact matthew@masot.net with questions or feedback