d_type(t) {
}
+Expr DeclareFunctionCommand::getFunction() const throw() {
+ return d_func;
+}
+
Type DeclareFunctionCommand::getType() const throw() {
return d_type;
}
void DeclareFunctionCommand::invoke(SmtEngine* smtEngine) throw() {
Dump("declarations") << *this;
- smtEngine->addToModelFunction( d_func );
+ smtEngine->addToModelCommand( clone(), Model::COMMAND_DECLARE_FUN );
d_commandStatus = CommandSuccess::instance();
}
void DeclareTypeCommand::invoke(SmtEngine* smtEngine) throw() {
Dump("declarations") << *this;
- smtEngine->addToModelType( d_type );
+ smtEngine->addToModelCommand( clone(), Model::COMMAND_DECLARE_SORT );
d_commandStatus = CommandSuccess::instance();
}
return new DefineNamedFunctionCommand(d_symbol, d_func, d_formals, d_formula);
}
+/* class SetUserAttribute */
+
+SetUserAttributeCommand::SetUserAttributeCommand( const std::string& attr, Expr expr ) throw() :
+ d_attr( attr ), d_expr( expr ){
+}
+/*
+SetUserAttributeCommand::SetUserAttributeCommand( const std::string& id, Expr expr,
+ std::vector<Expr>& values ) throw() :
+ d_id( id ), d_expr( expr ){
+ d_expr_values.insert( d_expr_values.begin(), values.begin(), values.end() );
+}
+
+SetUserAttributeCommand::SetUserAttributeCommand( const std::string& id, Expr expr,
+ std::string& value ) throw() :
+ d_id( id ), d_expr( expr ), d_str_value( value ){
+}
+*/
+void SetUserAttributeCommand::invoke(SmtEngine* smtEngine) throw(){
+ try {
+ if(!d_expr.isNull()) {
+ smtEngine->setUserAttribute( d_attr, d_expr );
+ }
+ d_commandStatus = CommandSuccess::instance();
+ } catch(exception& e) {
+ d_commandStatus = new CommandFailure(e.what());
+ }
+}
+
+Command* SetUserAttributeCommand::exportTo(ExprManager* exprManager, ExprManagerMapCollection& variableMap){
+ Expr expr = d_expr.exportTo(exprManager, variableMap);
+ return new SetUserAttributeCommand( d_attr, expr );
+}
+
+Command* SetUserAttributeCommand::clone() const{
+ return new SetUserAttributeCommand( d_attr, d_expr );
+}
+
/* class Simplify */
SimplifyCommand::SimplifyCommand(Expr term) throw() :
v.push_back(SExpr(SExpr::Keyword(string(":") + d_flag)));
v.push_back(smtEngine->getOption(d_flag));
stringstream ss;
-
+
ss << SExpr(v);
d_result = ss.str();
d_commandStatus = CommandSuccess::instance();
void DatatypeDeclarationCommand::invoke(SmtEngine* smtEngine) throw() {
Dump("declarations") << *this;
+ smtEngine->addToModelCommand( clone(), Model::COMMAND_DECLARE_DATATYPES );
d_commandStatus = CommandSuccess::instance();
}
public:
DeclareFunctionCommand(const std::string& id, Expr func, Type type) throw();
~DeclareFunctionCommand() throw() {}
+ Expr getFunction() const throw();
Type getType() const throw();
void invoke(SmtEngine* smtEngine) throw();
Command* exportTo(ExprManager* exprManager, ExprManagerMapCollection& variableMap);
Command* clone() const;
};/* class DefineNamedFunctionCommand */
+/**
+ * The command when an attribute is set by a user. In SMT-LIBv2 this is done
+ * via the syntax (! expr :atrr)
+ */
+class CVC4_PUBLIC SetUserAttributeCommand : public Command {
+protected:
+ std::string d_attr;
+ Expr d_expr;
+ //std::vector<Expr> d_expr_values;
+ //std::string d_str_value;
+public:
+ SetUserAttributeCommand( const std::string& attr, Expr expr ) throw();
+ //SetUserAttributeCommand( const std::string& id, Expr expr, std::vector<Expr>& values ) throw();
+ //SetUserAttributeCommand( const std::string& id, Expr expr, std::string& value ) throw();
+ ~SetUserAttributeCommand() throw() {}
+ void invoke(SmtEngine* smtEngine) throw();
+ Command* exportTo(ExprManager* exprManager, ExprManagerMapCollection& variableMap);
+ Command* clone() const;
+};/* class SetUserAttributeCommand */
+
+
class CVC4_PUBLIC CheckSatCommand : public Command {
protected:
BoolExpr d_expr;
{ cmd = new GetAssertionsCommand(); }
| COUNTEREXAMPLE_TOK
- { UNSUPPORTED("COUNTEREXAMPLE command"); }
+ { cmd = new GetModelCommand; }
| COUNTERMODEL_TOK
- { UNSUPPORTED("COUNTERMODEL command"); }
+ { cmd = new GetModelCommand; }
| ARITH_VAR_ORDER_TOK LPAREN formula[f] ( COMMA formula[f] )* RPAREN
{ UNSUPPORTED("ARITH_VAR_ORDER command"); }
( attribute[expr, attexpr,attr]
{ if( attr == ":pattern" && ! attexpr.isNull()) {
patexprs.push_back( attexpr );
- }else if( attr==":axiom" ){
- //do this?
}
}
)+ RPAREN_TOK
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);
+ {
+ attr = AntlrInput::tokenText($KEYWORD);
+ //EXPR_MANAGER->setNamedAttribute( expr, attr );
+ if( attr==":rewrite-rule" ){
+ //do nothing
+ } else if( attr==":axiom" || attr==":conjecture" ){
+ std::string attr_name = attr;
+ attr_name.erase( attr_name.begin() );
+ Command* c = new SetUserAttributeCommand( attr_name, expr );
PARSER_STATE->preemptCommand(c);
} else {
std::stringstream ss;
attr = std::string(":pattern");
retExpr = MK_EXPR(kind::INST_PATTERN, patexprs);
}
- | ATTRIBUTE_REWRITE_RULE {
- attr = std::string(":rewrite-rule");
- }
+ | ATTRIBUTE_NAMED_TOK symbolicExpr[sexpr]
+ {
+ attr = std::string(":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);
+ }
;
/**
// attributes
ATTRIBUTE_PATTERN_TOK : ':pattern';
-ATTRIBUTE_REWRITE_RULE : ':rewrite-rule';
+ATTRIBUTE_NAMED_TOK : ':named';
// operators (NOTE: theory symbols go here)
AMPERSAND_TOK : '&';
}/* AstPrinter::toStream(CommandStatus*) */
+void AstPrinter::toStream(std::ostream& out, Model* m, Command* c, int c_type ) const throw(){
+
+}
+
static void toStream(std::ostream& out, const EmptyCommand* c) throw() {
out << "EmptyCommand(" << c->getName() << ")";
}
void toStream(std::ostream& out, TNode n, int toDepth, bool types, size_t dag) const throw();
void toStream(std::ostream& out, const Command* c, int toDepth, bool types, size_t dag) const throw();
void toStream(std::ostream& out, const CommandStatus* s) const throw();
+ //for models
+ void toStream(std::ostream& out, Model* m, Command* c, int c_type ) const throw();
};/* class AstPrinter */
}/* CVC4::printer::ast namespace */
#include "expr/command.h"
#include "theory/substitutions.h"
+#include "theory/model.h"
+
#include <iostream>
#include <vector>
#include <string>
out << BitVectorType(n.getType().toType()).getSize();
out << ',';
toStream(out, n[child], depth, types, false);
- out << ',';
+ out << ',';
toStream(out, n[child+1], depth, types, false);
while (child > 0) {
out << ')';
out << BitVectorType(n.getType().toType()).getSize();
out << ',';
toStream(out, n[child], depth, types, false);
- out << ',';
+ out << ',';
toStream(out, n[child+1], depth, types, false);
while (child > 0) {
out << ')';
}/* CvcPrinter::toStream(CommandStatus*) */
+void CvcPrinter::toStream(std::ostream& out, Model* m, Command* c, int c_type ) const throw(){
+ theory::TheoryModel* tm = (theory::TheoryModel*)m;
+ if( c_type==Model::COMMAND_DECLARE_SORT ){
+ TypeNode tn = TypeNode::fromType( ((DeclareTypeCommand*)c)->getType() );
+ if( tn.isSort() ){
+ //print the cardinality
+ if( tm->d_rep_set.d_type_reps.find( tn )!=tm->d_rep_set.d_type_reps.end() ){
+ out << "; cardinality of " << tn << " is " << tm->d_rep_set.d_type_reps[tn].size() << std::endl;
+ }
+ }
+ out << c << std::endl;
+ if( tn.isSort() ){
+ //print the representatives
+ if( tm->d_rep_set.d_type_reps.find( tn )!=tm->d_rep_set.d_type_reps.end() ){
+ for( size_t i=0; i<tm->d_rep_set.d_type_reps[tn].size(); i++ ){
+ if( tm->d_rep_set.d_type_reps[tn][i].isVar() ){
+ out << tm->d_rep_set.d_type_reps[tn][i] << " : " << tn << ";" << std::endl;
+ }else{
+ out << "% rep: " << tm->d_rep_set.d_type_reps[tn][i] << std::endl;
+ }
+ }
+ }
+ }
+ }else if( c_type==Model::COMMAND_DECLARE_FUN ){
+ Node n = Node::fromExpr( ((DeclareFunctionCommand*)c)->getFunction() );
+ TypeNode tn = n.getType();
+ out << n << " : ";
+ if( tn.isFunction() || tn.isPredicate() ){
+ out << "(";
+ for( size_t i=0; i<tn.getNumChildren()-1; i++ ){
+ if( i>0 ) out << ", ";
+ out << tn[i];
+ }
+ out << ") -> " << tn.getRangeType();
+ }else{
+ out << tn;
+ }
+ out << " = ";
+ if( tn.isFunction() || tn.isPredicate() ){
+ out << "LAMBDA (";
+ for( size_t i=0; i<tn.getNumChildren()-1; i++ ){
+ if( i>0 ) out << ", ";
+ out << "$x" << (i+1) << " : " << tn[i];
+ }
+ out << "): ";
+ }
+ out << tm->getValue( n );
+ out << ";" << std::endl;
+
+/*
+ //for table format (work in progress)
+ bool printedModel = false;
+ if( tn.isFunction() ){
+ if( options::modelFormatMode()==MODEL_FORMAT_MODE_TABLE ){
+ //specialized table format for functions
+ RepSetIterator riter( &d_rep_set );
+ riter.setFunctionDomain( n );
+ while( !riter.isFinished() ){
+ std::vector< Node > children;
+ children.push_back( n );
+ for( int i=0; i<riter.getNumTerms(); i++ ){
+ children.push_back( riter.getTerm( i ) );
+ }
+ Node nn = NodeManager::currentNM()->mkNode( APPLY_UF, children );
+ Node val = getValue( nn );
+ out << val << " ";
+ riter.increment();
+ }
+ printedModel = true;
+ }
+ }
+*/
+ }else{
+ out << c << std::endl;
+ }
+}
+
static void toStream(std::ostream& out, const AssertCommand* c) throw() {
out << "ASSERT " << c->getExpr() << ";";
}
void toStream(std::ostream& out, TNode n, int toDepth, bool types, size_t dag) const throw();
void toStream(std::ostream& out, const Command* c, int toDepth, bool types, size_t dag) const throw();
void toStream(std::ostream& out, const CommandStatus* s) const throw();
+ //for models
+ void toStream(std::ostream& out, Model* m, Command* c, int c_type ) const throw();
};/* class CvcPrinter */
}/* CVC4::printer::cvc namespace */
// increment again (they'll be dagified anyway).
return current.isVar() ||
current.getMetaKind() == kind::metakind::CONSTANT ||
+ current.getNumChildren()==0 ||
( ( current.getKind() == kind::NOT ||
current.getKind() == kind::UMINUS ) &&
( current[0].isVar() ||
}
}/* Printer::toStream() */
+void Printer::toStream(std::ostream& out, Model* m ) const throw(){
+ for( int i=0; i<m->getNumCommands(); i++ ){
+ toStream( out, m, m->getCommand( i ), m->getCommandType( i ) );
+ }
+}
+
}/* CVC4 namespace */
#include "util/language.h"
#include "util/sexpr.h"
+#include "util/model.h"
#include "expr/node.h"
#include "expr/command.h"
*/
virtual void toStream(std::ostream& out, const Result& r) const throw();
+ /** Write a Model out to a stream with this Printer. */
+ virtual void toStream(std::ostream& out, Model* m ) const throw();
+
+ //for models
+
+ /** write model response to command */
+ virtual void toStream(std::ostream& out, Model* m, Command* c, int c_type ) const throw() = 0;
};/* class Printer */
}/* CVC4 namespace */
Printer::getPrinter(language::output::LANG_SMTLIB_V2)->toStream(out, sexpr);
}/* SmtPrinter::toStream() */
+void SmtPrinter::toStream(std::ostream& out, Model* m, Command* c, int c_type ) const throw(){
+ Printer::getPrinter(language::output::LANG_SMTLIB_V2)->toStream(out, m, c, c_type);
+}
+
}/* CVC4::printer::smt namespace */
}/* CVC4::printer namespace */
}/* CVC4 namespace */
void toStream(std::ostream& out, const Command* c, int toDepth, bool types, size_t dag) const throw();
void toStream(std::ostream& out, const CommandStatus* s) const throw();
void toStream(std::ostream& out, const SExpr& sexpr) const throw();
+ //for models
+ void toStream(std::ostream& out, Model* m, Command* c, int c_type ) const throw();
};/* class SmtPrinter */
}/* CVC4::printer::smt namespace */
#include "theory/substitutions.h"
#include "util/language.h"
+#include "theory/model.h"
+
using namespace std;
namespace CVC4 {
// TODO user patterns
break;
- //function models
- case kind::FUNCTION_MODEL:
- break;
- case kind::FUNCTION_CASE_SPLIT:
- break;
- case kind::FUNCTION_CASE:
- out << "if ";
- 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
}/* Smt2Printer::toStream(CommandStatus*) */
+
+void Smt2Printer::toStream(std::ostream& out, Model* m, Command* c, int c_type ) const throw(){
+ theory::TheoryModel* tm = (theory::TheoryModel*)m;
+ if( c_type==Model::COMMAND_DECLARE_SORT ){
+ TypeNode tn = TypeNode::fromType( ((DeclareTypeCommand*)c)->getType() );
+ if( tn.isSort() ){
+ //print the cardinality
+ if( tm->d_rep_set.d_type_reps.find( tn )!=tm->d_rep_set.d_type_reps.end() ){
+ out << "; cardinality of " << tn << " is " << tm->d_rep_set.d_type_reps[tn].size() << std::endl;
+ }
+ }
+ out << c << std::endl;
+ if( tn.isSort() ){
+ //print the representatives
+ if( tm->d_rep_set.d_type_reps.find( tn )!=tm->d_rep_set.d_type_reps.end() ){
+ for( size_t i=0; i<tm->d_rep_set.d_type_reps[tn].size(); i++ ){
+ if( tm->d_rep_set.d_type_reps[tn][i].isVar() ){
+ out << "(declare-fun " << tm->d_rep_set.d_type_reps[tn][i] << " () " << tn << ")" << std::endl;
+ }else{
+ out << "; rep: " << tm->d_rep_set.d_type_reps[tn][i] << std::endl;
+ }
+ }
+ }
+ }
+ }else if( c_type==Model::COMMAND_DECLARE_FUN ){
+ Node n = Node::fromExpr( ((DeclareFunctionCommand*)c)->getFunction() );
+ TypeNode tn = n.getType();
+ out << "(define-fun " << n << " (";
+ if( tn.isFunction() || tn.isPredicate() ){
+ for( size_t i=0; i<tn.getNumChildren()-1; i++ ){
+ if( i>0 ) out << " ";
+ out << "($x" << (i+1) << " " << tn[i] << ")";
+ }
+ out << ") " << tn.getRangeType();
+ }else{
+ out << ") " << tn;
+ }
+ out << " ";
+ out << tm->getValue( n );
+ out << ")" << std::endl;
+
+/*
+ //for table format (work in progress)
+ bool printedModel = false;
+ if( tn.isFunction() ){
+ if( options::modelFormatMode()==MODEL_FORMAT_MODE_TABLE ){
+ //specialized table format for functions
+ RepSetIterator riter( &d_rep_set );
+ riter.setFunctionDomain( n );
+ while( !riter.isFinished() ){
+ std::vector< Node > children;
+ children.push_back( n );
+ for( int i=0; i<riter.getNumTerms(); i++ ){
+ children.push_back( riter.getTerm( i ) );
+ }
+ Node nn = NodeManager::currentNM()->mkNode( APPLY_UF, children );
+ Node val = getValue( nn );
+ out << val << " ";
+ riter.increment();
+ }
+ printedModel = true;
+ }
+ }
+*/
+ }else{
+ out << c << std::endl;
+ }
+}
+
+
static void toStream(std::ostream& out, const AssertCommand* c) throw() {
out << "(assert " << c->getExpr() << ")";
}
static void toStream(std::ostream& out, const DatatypeDeclarationCommand* c) throw() {
const vector<DatatypeType>& datatypes = c->getDatatypes();
- out << "(declare-datatypes (";
+ out << "(declare-datatypes () (";
for(vector<DatatypeType>::const_iterator i = datatypes.begin(),
i_end = datatypes.end();
i != i_end;
out << "(" << d.getName() << " ";
for(Datatype::const_iterator ctor = d.begin(), ctor_end = d.end();
ctor != ctor_end; ++ctor){
- out << "(" << ctor->getName() << " ";
+ if( ctor!=d.begin() ) out << " ";
+ out << "(" << ctor->getName();
for(DatatypeConstructor::const_iterator arg = ctor->begin(), arg_end = ctor->end();
arg != arg_end; ++arg){
- out << "(" << arg->getSelector() << " "
+ out << " (" << arg->getSelector() << " "
<< static_cast<SelectorType>(arg->getType()).getRangeType() << ")";
}
- out << ") ";
+ out << ")";
}
out << ")" << endl;
}
void toStream(std::ostream& out, TNode n, int toDepth, bool types, size_t dag) const throw();
void toStream(std::ostream& out, const Command* c, int toDepth, bool types, size_t dag) const throw();
void toStream(std::ostream& out, const CommandStatus* s) const throw();
+ //for models
+ void toStream(std::ostream& out, Model* m, Command* c, int c_type ) const throw();
};/* class Smt2Printer */
}/* CVC4::printer::smt2 namespace */
if(stopSearch) {
return lit_Undef;
}
+ Debug("propagateAsDecision") << "propagateAsDecision(): decide on another literal" << std::endl;
Var next = var_Undef;
option sat_refine_conflicts --refine-conflicts bool
refine theory conflict clauses
-option minisatUseElim --minisat-elimination bool :default true
+option minisatUseElim --minisat-elimination bool :default true :read-write
use Minisat elimination
endmodule
smt_engine_scope.h \
modal_exception.h \
simplification_mode.h \
- simplification_mode.cpp
+ simplification_mode.cpp \
+ model_format_mode.h \
+ model_format_mode.cpp
nodist_libsmt_la_SOURCES = \
smt_options.cpp
--- /dev/null
+/********************* */
+/*! \file model_format_mode.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-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 [[ Add one-line brief description here ]]
+ **
+ ** [[ Add lengthier description here ]]
+ ** \todo document this file
+ **/
+
+#include "smt/model_format_mode.h"
+
+namespace CVC4 {
+
+std::ostream& operator<<(std::ostream& out, ModelFormatMode mode) {
+ switch(mode) {
+ case MODEL_FORMAT_MODE_DEFAULT:
+ out << "MODEL_FORMAT_MODE_DEFAULT";
+ break;
+ case MODEL_FORMAT_MODE_TABLE:
+ out << "MODEL_FORMAT_MODE_TABLE";
+ break;
+ default:
+ out << "ModelFormatMode:UNKNOWN![" << unsigned(mode) << "]";
+ }
+
+ return out;
+}
+
+}/* CVC4 namespace */
--- /dev/null
+/********************* */
+/*! \file model_format_mode.h
+ ** \verbatim
+ ** Original author: mdeters
+ ** Major contributors: none
+ ** Minor contributors (to current version): none
+ ** This file is part of the CVC4 prototype.
+ ** 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
+ ** information.\endverbatim
+ **
+ ** \brief [[ Add one-line brief description here ]]
+ **
+ ** [[ Add lengthier description here ]]
+ ** \todo document this file
+ **/
+
+#include "cvc4_public.h"
+
+#ifndef __CVC4__SMT__MODEL_FORMAT_MODE_H
+#define __CVC4__SMT__MODEL_FORMAT_MODE_H
+
+#include <iostream>
+
+namespace CVC4 {
+
+/** Enumeration of model_format modes (how to print models from get-model command). */
+typedef enum {
+ /** default mode (print expressions in the output language format) */
+ MODEL_FORMAT_MODE_DEFAULT,
+ /** print functional values in a table format */
+ MODEL_FORMAT_MODE_TABLE,
+} ModelFormatMode;
+
+std::ostream& operator<<(std::ostream& out, ModelFormatMode mode) CVC4_PUBLIC;
+
+}/* CVC4 namespace */
+
+#endif /* __CVC4__SMT__MODEL_FORMAT_H */
support the get-value and get-model commands
common-option produceAssignments produce-assignments --produce-assignments bool
support the get-assignment command
+option modelFormatMode --model-format=MODE ModelFormatMode :handler CVC4::smt::stringToModelFormatMode :default MODEL_FORMAT_MODE_DEFAULT :read-write :include "smt/model_format_mode.h" :handler-include "smt/options_handlers.h"
+ print format mode for models, see --model-format=help
# This could go in src/main/options, but by SMT-LIBv2 spec, "interactive"
# is a mode in which the assertion list must be kept. So it belongs here.
+ do not perform nonclausal simplification\n\
";
+static const std::string modelFormatHelp = "\
+Model format modes currently supported by the --model-format option:\n\
+\n\
+default \n\
++ Print model as expressions in the output language format.\n\
+\n\
+table\n\
++ Print functional expressions over finite domains in a table format.\n\
+";
+
inline void dumpMode(std::string option, std::string optarg, SmtEngine* smt) {
#ifdef CVC4_DUMPING
char* optargPtr = strdup(optarg.c_str());
}
}
+inline ModelFormatMode stringToModelFormatMode(std::string option, std::string optarg, SmtEngine* smt) throw(OptionException) {
+ if(optarg == "default") {
+ return MODEL_FORMAT_MODE_DEFAULT;
+ } else if(optarg == "table") {
+ return MODEL_FORMAT_MODE_TABLE;
+ } else if(optarg == "help") {
+ puts(modelFormatHelp.c_str());
+ exit(1);
+ } else {
+ throw OptionException(std::string("unknown option for --model-format: `") +
+ optarg + "'. Try --model-format help.");
+ }
+}
+
// This macro is used for setting :regular-output-channel and :diagnostic-output-channel
// to redirect a stream. It maintains all attributes set on the stream.
#define __CVC4__SMT__OUTPUTCHANNELS__SETSTREAM__(__channel_get, __channel_set) \
#include "theory/booleans/circuit_propagator.h"
#include "util/ite_removal.h"
#include "theory/model.h"
+#include "printer/printer.h"
+#include "prop/options.h"
using namespace std;
using namespace CVC4;
bool qf_sat = d_logic.isPure(THEORY_BOOL) && !d_logic.isQuantified();
bool quantifiers = d_logic.isQuantified();
Trace("smt") << "setting simplification mode to <" << d_logic.getLogicString() << "> " << (!qf_sat && !quantifiers) << std::endl;
- options::simplificationMode.set(qf_sat || quantifiers ? SIMPLIFICATION_MODE_NONE : SIMPLIFICATION_MODE_BATCH);
+ //simplifaction=none works better for SMT LIB benchmarks with quantifiers, not others
+ //options::simplificationMode.set(qf_sat || quantifiers ? SIMPLIFICATION_MODE_NONE : SIMPLIFICATION_MODE_BATCH);
+ options::simplificationMode.set(qf_sat ? SIMPLIFICATION_MODE_NONE : SIMPLIFICATION_MODE_BATCH);
}
// If in arrays, set the UF handler to arrays
options::decisionMode.set(decMode);
options::decisionStopOnly.set(stoponly);
}
+
+ //for finite model finding
+ if( ! options::instWhenMode.wasSetByUser()){
+ if( options::fmfInstEngine() ){
+ Trace("smt") << "setting inst when mode to LAST_CALL" << std::endl;
+ options::instWhenMode.set( INST_WHEN_LAST_CALL );
+ }
+ }
+
+ //until bug 371 is fixed
+ if( ! options::minisatUseElim.wasSetByUser()){
+ if( d_logic.isQuantified() ){
+ options::minisatUseElim.set( false );
+ }
+ }
}
void SmtEngine::setInfo(const std::string& key, const CVC4::SExpr& value)
throw ModalException(msg);
}
- // Apply what was learned from preprocessing
- Node n = d_private->applySubstitutions(e.getNode());
+ // do not need to apply preprocessing substitutions (should be recorded in model already)
// Normalize for the theories
- n = Rewriter::rewrite(n);
+ Node n = Rewriter::rewrite( e.getNode() );
Trace("smt") << "--- getting value of " << n << endl;
theory::TheoryModel* m = d_theoryEngine->getModel();
}
-void SmtEngine::addToModelType( Type& t ){
- Trace("smt") << "SMT addToModelType(" << t << ")" << endl;
- SmtScope smts(this);
- finalOptionsAreSet();
- if( options::produceModels() ) {
- d_theoryEngine->getModel()->addDefineType( TypeNode::fromType( t ) );
- }
-}
-
-void SmtEngine::addToModelFunction( Expr& e ){
- Trace("smt") << "SMT addToModelFunction(" << e << ")" << endl;
+void SmtEngine::addToModelCommand( Command* c, int c_type ){
+ Trace("smt") << "SMT addToModelCommand(" << c << ", " << c_type << ")" << endl;
SmtScope smts(this);
finalOptionsAreSet();
if( options::produceModels() ) {
- d_theoryEngine->getModel()->addDefineFunction( e.getNode() );
+ d_theoryEngine->getModel()->addCommand( c, c_type );
}
}
-
Model* SmtEngine::getModel() throw(ModalException, AssertionException){
Trace("smt") << "SMT getModel()" << endl;
SmtScope smts(this);
- if(!options::produceModels()) {
- const char* msg =
- "Cannot get model when produce-models options is off.";
- throw ModalException(msg);
- }
if(d_status.isNull() ||
d_status.asSatisfiabilityResult() == Result::UNSAT ||
d_problemExtended) {
"preceded by SAT/INVALID or UNKNOWN response.";
throw ModalException(msg);
}
-
+ if(!options::produceModels()) {
+ const char* msg =
+ "Cannot get model when produce-models options is off.";
+ throw ModalException(msg);
+ }
return d_theoryEngine->getModel();
}
void SmtEngine::printModel( std::ostream& out, Model* m ){
SmtScope smts(this);
- m->toStream(out);
+ Printer::getPrinter(options::outputLanguage())->toStream( out, m );
+ //m->toStream(out);
+}
+
+void SmtEngine::setUserAttribute( std::string& attr, Expr expr ){
+ SmtScope smts(this);
+ d_theoryEngine->setUserAttribute( attr, expr.getNode() );
}
}/* CVC4 namespace */
CVC4::SExpr getAssignment() throw(ModalException, AssertionException);
/**
- * Add to Model Type. This is used for recording which types should be reported
+ * Add to Model command. This is used for recording a command that should be reported
* during a get-model call.
*/
- void addToModelType( Type& t );
-
- /**
- * Add to Model Function. This is used for recording which functions should be reported
- * during a get-model call.
- */
- void addToModelFunction( Expr& e );
+ void addToModelCommand( Command* c, int c_type );
/**
* Get the model (only if immediately preceded by a SAT
*/
void printModel( std::ostream& out, Model* m );
+ /** Set user attribute
+ * This function is called when an attribute is set by a user. In SMT-LIBv2 this is done
+ * via the syntax (! expr :attr)
+ */
+ void setUserAttribute( std::string& attr, Expr expr );
+
};/* class SmtEngine */
}/* CVC4 namespace */
quantifiers_engine.h \
quantifiers_engine.cpp \
model.h \
- model.cpp
+ model.cpp \
+ rep_set.h \
+ rep_set.cpp
nodist_libtheory_la_SOURCES = \
rewriter_tables.h \
}
}
-void TheoryArith::collectModelInfo( TheoryModel* m ){
+void TheoryArith::collectModelInfo( TheoryModel* m, bool fullModel ){
Assert(d_qflraStatus == Result::SAT);
- Debug("arith::collectModelInfo") << "collectModelInfo() begin " << endl;
+ Debug("arith::collectModelInfo") << "collectModelInfo() begin " << endl;
// Delta lasts at least the duration of the function call
const Rational& delta = d_partialModel.getDelta();
// TODO:
// This is not very good for user push/pop....
- // Revisit when implementing push/pop
+ // Revisit when implementing push/pop
for(ArithVar v = 0; v < d_variables.size(); ++v){
if(!isSlackVariable(v)){
Node term = d_arithvarNodeMap.asNode(v);
void propagate(Effort e);
Node explain(TNode n);
- void collectModelInfo( TheoryModel* m );
+ void collectModelInfo( TheoryModel* m, bool fullModel );
void shutdown(){ }
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 ){
return STATUS_UNKNOWN;
}
-//void InstStrategySimplexUfMatch::resetInstantiationRound(){
-//
-//}
-//
-//int InstStrategySimplexUfMatch::process( Node f, int effort ){
-// 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 ) ){
-// ++(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->getTermDatabase()->getNumInstantiationConstants( f ); i++ ){
-// Node ic = d_quantEngine->getTermDatabase()->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 ) ){
-// 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::cbqi() ){
}
Node InstantiatorTheoryArith::getTableauxValue( ArithVar v, bool minus_delta ){
+ const Rational& delta = ((TheoryArith*)getTheory())->d_partialModel.getDelta();
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()->mkSkolem( 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;
+ Rational qmodel = drv.substituteDelta( minus_delta ? -delta : delta );
+ return mkRationalNode(qmodel);
}
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)
+ d_instantiations_minus("InstantiatorTheoryArith::Instantiations_minus_delta", 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);
}
/** 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;
int process( Node f, Theory::Effort effort, int e );
/** 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();
};
#include "theory/rewriter.h"
#include "expr/command.h"
#include "theory/arrays/theory_arrays_instantiator.h"
+#include "theory/arrays/theory_arrays_model.h"
#include "theory/model.h"
using namespace std;
// MODEL GENERATION
/////////////////////////////////////////////////////////////////////////////
-void TheoryArrays::collectModelInfo( TheoryModel* m ){
+void TheoryArrays::collectModelInfo( TheoryModel* m, bool fullModel ){
m->assertEqualityEngine( &d_equalityEngine );
+ //must determine proper representatives for all array equivalence classes
+ //first, we collect all select terms and array equivalence classes
+ std::map< Node, std::vector< Node > > selects;
+ std::vector< Node > arrays;
+ eq::EqClassesIterator eqcs_i = eq::EqClassesIterator( &d_equalityEngine );
+ while( !eqcs_i.isFinished() ){
+ Node eqc = (*eqcs_i);
+ if( eqc.getType().isArray() ){
+ arrays.push_back( eqc );
+ }
+ eq::EqClassIterator eqc_i = eq::EqClassIterator( eqc, &d_equalityEngine );
+ while( !eqc_i.isFinished() ){
+ Node n = *eqc_i;
+ if( n.getKind()==kind::SELECT ){
+ selects[ n[0] ].push_back( n );
+ }
+ ++eqc_i;
+ }
+ ++eqcs_i;
+ }
+ //for all array equivalence classes
+ for( size_t i=0; i<arrays.size(); i++ ){
+ ArrayModel am( arrays[i], m );
+ //set all values from existing select terms
+ eq::EqClassIterator eqc_i = eq::EqClassIterator( arrays[i], &d_equalityEngine );
+ while( !eqc_i.isFinished() ){
+ for( int i=0; i<(int)selects[ *eqc_i ].size(); i++ ){
+ am.setValue( m, selects[ *eqc_i ][i][1], selects[ *eqc_i ][i] );
+ }
+ ++eqc_i;
+ }
+ if( fullModel ){
+ ////choose a representative as the default array
+ //am.setDefaultArray( ... );
+ }
+ //construct the representative
+ Node rep = am.getArrayValue();
+ Assert( !rep.isNull() );
+ m->assertEquality( arrays[i], rep, true );
+ //communicate to the model that it is the representative
+ m->assertRepresentative( rep );
+ }
}
/////////////////////////////////////////////////////////////////////////////
private:
public:
- void collectModelInfo( TheoryModel* m );
+ void collectModelInfo( TheoryModel* m, bool fullModel );
/////////////////////////////////////////////////////////////////////////////
// NOTIFICATIONS
#include "theory/theory_engine.h"
#include "theory/arrays/theory_arrays_model.h"
-#include "theory/quantifiers/first_order_model.h"
-#include "theory/quantifiers/term_database.h"
+#include "theory/model.h"
using namespace std;
using namespace CVC4;
using namespace CVC4::theory;
using namespace CVC4::theory::arrays;
-ArrayModel::ArrayModel( Node arr, quantifiers::FirstOrderModel* m ) : d_model( m ), d_arr( arr ){
- Assert( arr.getKind()!=STORE );
- //look at ground assertions
- Node sel = NodeManager::currentNM()->mkNode( SELECT, arr, NodeManager::currentNM()->mkSkolem( arr.getType().getArrayIndexType() ) );
- Node sel_op = sel.getOperator(); //FIXME: easier way to do this?
- for( size_t i=0; i<d_model->getTermDatabase()->d_op_map[ sel_op ].size(); i++ ){
- Node n = d_model->getTermDatabase()->d_op_map[ sel_op ][i];
- Assert( n.getKind()==SELECT );
- if( m->areEqual( n[0], arr ) ){
- //d_model->getTermDatabase()->computeModelBasisArgAttribute( n );
- //if( !n.getAttribute(NoMatchAttribute()) || n.getAttribute(ModelBasisArgAttribute())==1 ){
- Node r = d_model->getRepresentative( n );
- Node i = d_model->getRepresentative( n[1] );
- d_values[i] = r;
- //}
+ArrayModel::ArrayModel( Node arr, TheoryModel* m ) : d_arr( arr ){
+ d_base_arr = arr;
+ while( d_base_arr.getKind()==STORE ){
+ Node ri = m->getRepresentative( d_base_arr[1] );
+ if( d_values.find( ri )==d_values.end() ){
+ d_values[ ri ] = m->getRepresentative( d_base_arr[2] );
}
+ d_base_arr = d_base_arr[0];
}
}
-Node ArrayModel::getValue( Node n ){
- Assert( n.getKind()==SELECT );
- Assert( n[0]==d_arr );
- std::map< Node, Node >::iterator it = d_values.find( n[0] );
+Node ArrayModel::getValue( TheoryModel* m, Node i ){
+ i = m->getRepresentative( i );
+ std::map< Node, Node >::iterator it = d_values.find( i );
if( it!=d_values.end() ){
return it->second;
}else{
- return n;
- //return d_default_value; TODO: guarentee I can return this here
+ return NodeManager::currentNM()->mkNode( SELECT, getArrayValue(), i );
+ //return d_default_value; //TODO: guarentee I can return this here
}
}
-void ArrayModel::setDefaultValue( Node v ){
- d_default_value = v;
+void ArrayModel::setValue( TheoryModel* m, Node i, Node e ){
+ Node ri = m->getRepresentative( i );
+ if( d_values.find( ri )==d_values.end() ){
+ d_values[ ri ] = m->getRepresentative( e );
+ }
+}
+
+void ArrayModel::setDefaultArray( Node arr ){
+ d_base_arr = arr;
}
Node ArrayModel::getArrayValue(){
- Node curr = d_arr; //TODO: make constant default
+ Node curr = d_base_arr;
for( std::map< Node, Node >::iterator it = d_values.begin(); it != d_values.end(); ++it ){
curr = NodeManager::currentNM()->mkNode( STORE, curr, it->first, it->second );
}
-/********************* */
-/*! \file theory_arrays_model.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 MODEL for theory of arrays
- **/
-
-
-#include "cvc4_private.h"
-
-#ifndef __CVC4__THEORY_ARRAYS_MODEL_H
-#define __CVC4__THEORY_ARRAYS_MODEL_H
-
-#include "theory/quantifiers_engine.h"
-
-namespace CVC4 {
-namespace theory {
-
-namespace quantifiers{
- class FirstOrderModel;
-}
-
-namespace arrays {
-
-class ArrayModel{
-protected:
- /** reference to model */
- quantifiers::FirstOrderModel* d_model;
- /** the array this model is for */
- Node d_arr;
-public:
- ArrayModel(){}
- ArrayModel( Node arr, quantifiers::FirstOrderModel* m );
- ~ArrayModel() {}
-public:
- /** pre-defined values */
- std::map< Node, Node > d_values;
- /** default value */
- Node d_default_value;
- /** get value, return arguments that the value depends on */
- Node getValue( Node n );
- /** set default */
- void setDefaultValue( Node v );
-public:
- /** get array value */
- Node getArrayValue();
-};/* class ArrayModel */
-
-}
-}
-}
-
+/********************* */\r
+/*! \file theory_arrays_model.h\r
+ ** \verbatim\r
+ ** Original author: ajreynol\r
+ ** Major contributors: none\r
+ ** Minor contributors (to current version): none\r
+ ** This file is part of the CVC4 prototype.\r
+ ** Copyright (c) 2009, 2010, 2011 The Analysis of Computer Systems Group (ACSys)\r
+ ** Courant Institute of Mathematical Sciences\r
+ ** New York University\r
+ ** See the file COPYING in the top-level source directory for licensing\r
+ ** information.\endverbatim\r
+ **\r
+ ** \brief MODEL for theory of arrays\r
+ **/\r
+\r
+\r
+#include "cvc4_private.h"\r
+\r
+#ifndef __CVC4__THEORY_ARRAYS_MODEL_H\r
+#define __CVC4__THEORY_ARRAYS_MODEL_H\r
+\r
+#include "theory/quantifiers_engine.h"\r
+\r
+namespace CVC4 {\r
+namespace theory {\r
+\r
+class TheoryModel;\r
+\r
+namespace arrays {\r
+\r
+class ArrayModel{\r
+protected:\r
+ /** the array this model is for */\r
+ Node d_arr;\r
+public:\r
+ ArrayModel(){}\r
+ ArrayModel( Node arr, TheoryModel* m );\r
+ ~ArrayModel() {}\r
+public:\r
+ /** pre-defined values */\r
+ std::map< Node, Node > d_values;\r
+ /** base array */\r
+ Node d_base_arr;\r
+ /** get value, return arguments that the value depends on */\r
+ Node getValue( TheoryModel* m, Node i );\r
+ /** set value */\r
+ void setValue( TheoryModel* m, Node i, Node e );\r
+ /** set default */\r
+ void setDefaultArray( Node arr );\r
+public:\r
+ /** get array value */\r
+ Node getArrayValue();\r
+};/* class ArrayModel */\r
+\r
+}\r
+}\r
+}\r
+\r
#endif
\ No newline at end of file
namespace theory {
namespace booleans {
-void TheoryBool::collectModelInfo( TheoryModel* m ){
-
-}
-
Theory::PPAssertStatus TheoryBool::ppAssert(TNode in, SubstitutionMap& outSubstitutions) {
if (in.getKind() == kind::CONST_BOOLEAN && !in.getConst<bool>()) {
Theory(THEORY_BOOL, c, u, out, valuation, logicInfo, qe) {
}
- void collectModelInfo( TheoryModel* m );
-
PPAssertStatus ppAssert(TNode in, SubstitutionMap& outSubstitutions);
std::string identify() const { return std::string("TheoryBool"); }
namespace theory {
namespace builtin {
-void TheoryBuiltin::collectModelInfo( TheoryModel* m ){
-
-}
-
}/* CVC4::theory::builtin namespace */
}/* CVC4::theory */
}/* CVC4 namespace */
public:
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) {}
- void collectModelInfo( TheoryModel* m );
std::string identify() const { return std::string("TheoryBuiltin"); }
};/* class TheoryBuiltin */
}
}
-void TheoryBV::collectModelInfo( TheoryModel* m ){
+void TheoryBV::collectModelInfo( TheoryModel* m, bool fullModel ){
}
Node explain(TNode n);
- void collectModelInfo( TheoryModel* m );
+ void collectModelInfo( TheoryModel* m, bool fullModel );
std::string identify() const { return std::string("TheoryBV"); }
typechecker "theory/datatypes/theory_datatypes_type_rules.h"
instantiator ::CVC4::theory::datatypes::InstantiatorTheoryDatatypes "theory/datatypes/theory_datatypes_instantiator.h"
-properties check presolve parametric
+properties check presolve parametric propagate
rewriter ::CVC4::theory::datatypes::DatatypesRewriter "theory/datatypes/datatypes_rewriter.h"
module DATATYPES "theory/datatypes/options.h" Datatypes theory
+# How to handle selectors applied to incorrect constructors. If this option is set,
+# then we do not rewrite such a selector term to an arbitrary ground term.
+# For example, by default cvc4 considers cdr( nil ) = nil. If this option is set, then
+# cdr( nil ) has no set value.
+option dtRewriteErrorSel /--disable-dt-rewrite-error-sel bool :default true
+ disable rewriting incorrectly applied selectors to arbitrary ground term
+
endmodule
#include "util/datatype.h"
#include "util/Assert.h"
#include "theory/datatypes/theory_datatypes_instantiator.h"
+#include "theory/datatypes/datatypes_rewriter.h"
#include "theory/model.h"
+#include "smt/options.h"
#include <map>
using namespace CVC4::theory;
using namespace CVC4::theory::datatypes;
-void TheoryDatatypes::printModelDebug(){
- /*
- //std::cout << "Datatypes model : " << std::endl;
+void TheoryDatatypes::printModelDebug( const char* c ){
+ Trace( c ) << "Datatypes model : " << std::endl;
eq::EqClassesIterator eqcs_i = eq::EqClassesIterator( &d_equalityEngine );
while( !eqcs_i.isFinished() ){
Node eqc = (*eqcs_i);
- if( eqc.getType().isDatatype() || eqc.getType().isBoolean() ){
- //std::cout << eqc << " : " << eqc.getType() << " : " << std::endl;
- //std::cout << " { ";
- //add terms to model
- eq::EqClassIterator eqc_i = eq::EqClassIterator( eqc, &d_equalityEngine );
- while( !eqc_i.isFinished() ){
- //std::cout << (*eqc_i) << " ";
- ++eqc_i;
- }
- //std::cout << "}" << std::endl;
- if( eqc.getType().isDatatype() ){
- EqcInfo* ei = getOrMakeEqcInfo( eqc );
- if( ei ){
- //std::cout << " Instantiated : " << ( ei->d_inst ? "yes" : "no" ) << std::endl;
- if( ei->d_constructor.get().isNull() ){
- //std::cout << " Constructor : " << std::endl;
- //std::cout << " Labels : ";
- if( hasLabel( ei, eqc ) ){
- //std::cout << getLabel( eqc );
- }else{
- NodeListMap::iterator lbl_i = d_labels.find( eqc );
- if( lbl_i != d_labels.end() ){
- NodeList* lbl = (*lbl_i).second;
- for( NodeList::const_iterator j = lbl->begin(); j != lbl->end(); j++ ){
- //std::cout << *j << " ";
- }
+ if( eqc.getType().isDatatype()){
+ Trace( c ) << "DATATYPE : ";
+ }
+ Trace( c ) << eqc << " : " << eqc.getType() << " : " << std::endl;
+ Trace( c ) << " { ";
+ //add terms to model
+ eq::EqClassIterator eqc_i = eq::EqClassIterator( eqc, &d_equalityEngine );
+ while( !eqc_i.isFinished() ){
+ Trace( c ) << (*eqc_i) << " ";
+ ++eqc_i;
+ }
+ Trace( c ) << "}" << std::endl;
+ if( eqc.getType().isDatatype() ){
+ EqcInfo* ei = getOrMakeEqcInfo( eqc );
+ if( ei ){
+ Trace( c ) << " Instantiated : " << ei->d_inst.get() << std::endl;
+ if( ei->d_constructor.get().isNull() ){
+ Trace("model-warn") << eqc << " has no constructor in equivalence class!" << std::endl;
+ Trace("model-warn") << " Type : " << eqc.getType() << std::endl;
+ Trace( c ) << " Constructor : " << std::endl;
+ Trace( c ) << " Labels : ";
+ if( hasLabel( ei, eqc ) ){
+ Trace( c ) << getLabel( eqc );
+ }else{
+ NodeListMap::iterator lbl_i = d_labels.find( eqc );
+ if( lbl_i != d_labels.end() ){
+ NodeList* lbl = (*lbl_i).second;
+ for( NodeList::const_iterator j = lbl->begin(); j != lbl->end(); j++ ){
+ Trace( c ) << *j << " ";
}
}
- //std::cout << std::endl;
- }else{
- //std::cout << " Constructor : " << ei->d_constructor.get() << std::endl;
}
- //std::cout << " Selectors : " << ( ei->d_selectors ? "yes" : "no" ) << std::endl;
+ Trace( c ) << std::endl;
+ }else{
+ Trace( c ) << " Constructor : " << ei->d_constructor.get() << std::endl;
}
+ Trace( c ) << " Selectors : " << ( ei->d_selectors ? "yes" : "no" ) << std::endl;
}
}
++eqcs_i;
}
- */
}
}
}
+void TheoryDatatypes::check(Effort e) {
+
+ while(!done() && !d_conflict) {
+ // Get all the assertions
+ Assertion assertion = get();
+ TNode fact = assertion.assertion;
+ Trace("datatypes-assert") << "Assert " << fact << std::endl;
+ //assert the fact
+ assertFact( fact, fact );
+ flushPendingFacts();
+ }
+
+ if( e == EFFORT_FULL ) {
+ Debug("datatypes-split") << "Check for splits " << e << endl;
+ eq::EqClassesIterator eqcs_i = eq::EqClassesIterator( &d_equalityEngine );
+ while( !eqcs_i.isFinished() ){
+ Node n = (*eqcs_i);
+ if( n.getType().isDatatype() ){
+ EqcInfo* eqc = getOrMakeEqcInfo( n, true );
+ //if there are more than 1 possible constructors for eqc
+ if( eqc->d_constructor.get().isNull() && !hasLabel( eqc, n ) ) {
+ const Datatype& dt = ((DatatypeType)(n.getType()).toType()).getDatatype();
+ //if only one constructor, then this term must be this constructor
+ if( dt.getNumConstructors()==1 ){
+ Node t = NodeManager::currentNM()->mkNode( APPLY_TESTER, Node::fromExpr( dt[0].getTester() ), n );
+ d_pending.push_back( t );
+ d_pending_exp[ t ] = NodeManager::currentNM()->mkConst( true );
+ Trace("datatypes-infer") << "DtInfer : " << t << ", trivial" << std::endl;
+ d_infer.push_back( t );
+ }else{
+ std::vector< bool > pcons;
+ getPossibleCons( eqc, n, pcons );
+ //std::cout << "pcons " << n << " = ";
+ //for( int i=0; i<(int)pcons.size(); i++ ){ //std::cout << pcons[i] << " "; }
+ //std::cout << std::endl;
+ //check if we do not need to resolve the constructor type for this equivalence class.
+ // this is if there are no selectors for this equivalence class, its possible values are infinite,
+ // and we are not producing a model, then do not split.
+ int consIndex = -1;
+ bool needSplit = true;
+ for( unsigned int j=0; j<pcons.size(); j++ ) {
+ if( pcons[j] ) {
+ if( consIndex==-1 ){
+ consIndex = j;
+ }
+ if( !dt[ j ].isFinite() && !eqc->d_selectors ) {
+ needSplit = false;
+ }
+ }
+ }
+ if( !needSplit && mustSpecifyModel() ){
+ //for the sake of termination, we must choose the constructor of a ground term
+ //NEED GUARENTEE: groundTerm should not contain any subterms of the same type
+ Node groundTerm = n.getType().mkGroundTerm();
+ int index = Datatype::indexOf( groundTerm.getOperator().toExpr() );
+ if( pcons[index] ){
+ consIndex = index;
+ }
+ needSplit = true;
+ }
+ if( needSplit && consIndex!=-1 ) {
+ Node test = NodeManager::currentNM()->mkNode( APPLY_TESTER, Node::fromExpr( dt[consIndex].getTester() ), n );
+ Trace("dt-split") << "*************Split for possible constructor " << test << " for " << n << endl;
+ test = Rewriter::rewrite( test );
+ NodeBuilder<> nb(kind::OR);
+ nb << test << test.notNode();
+ Node lemma = nb;
+ d_out->lemma( lemma );
+ d_out->requirePhase( test, true );
+ return;
+ }else{
+ Trace("dt-split") << "Do not split constructor for " << n << std::endl;
+ }
+ }
+ }
+ }
+ ++eqcs_i;
+ }
+ flushPendingFacts();
+ //if( !d_conflict ){
+ // printModelDebug();
+ //}
+ }
+
+ if( Debug.isOn("datatypes") || Debug.isOn("datatypes-split") ) {
+ Notice() << "TheoryDatatypes::check(): done" << endl;
+ }
+}
+
+void TheoryDatatypes::flushPendingFacts(){
+ doPendingMerges();
+ if( !d_pending.empty() ){
+ int i = 0;
+ while( !d_conflict && i<(int)d_pending.size() ){
+ Node fact = d_pending[i];
+ Node exp = d_pending_exp[ fact ];
+ //check to see if we have to communicate it to the rest of the system
+ if( mustCommunicateFact( fact, exp ) ){
+ Trace("dt-lemma-debug") << "Assert fact " << fact << " " << exp << std::endl;
+ Node lem = fact;
+ if( exp.isNull() || exp==NodeManager::currentNM()->mkConst( true ) ){
+ lem = fact;
+ }else{
+ Trace("dt-lemma-debug") << "Get explanation..." << std::endl;
+ Node ee_exp = explain( exp );
+ Trace("dt-lemma-debug") << "Explanation : " << ee_exp << std::endl;
+ lem = NodeManager::currentNM()->mkNode( IMPLIES, ee_exp, fact );
+ lem = Rewriter::rewrite( lem );
+ }
+ Trace("dt-lemma") << "Datatypes lemma : " << lem << std::endl;
+ d_out->lemma( lem );
+ }else{
+ assertFact( fact, exp );
+ }
+ i++;
+ }
+ d_pending.clear();
+ d_pending_exp.clear();
+ }
+}
+
+void TheoryDatatypes::doPendingMerges(){
+ //do all pending merges
+ int i=0;
+ while( i<(int)d_pending_merge.size() ){
+ Assert( d_pending_merge[i].getKind()==EQUAL || d_pending_merge[i].getKind()==IFF );
+ merge( d_pending_merge[i][0], d_pending_merge[i][1] );
+ i++;
+ }
+ d_pending_merge.clear();
+}
+
+void TheoryDatatypes::assertFact( Node fact, Node exp ){
+ Assert( d_pending_merge.empty() );
+ bool polarity = fact.getKind() != kind::NOT;
+ TNode atom = polarity ? fact : fact[0];
+ if (atom.getKind() == kind::EQUAL) {
+ d_equalityEngine.assertEquality( atom, polarity, exp );
+ }else{
+ d_equalityEngine.assertPredicate( atom, polarity, exp );
+ }
+ doPendingMerges();
+ //add to tester if applicable
+ if( atom.getKind()==kind::APPLY_TESTER ){
+ Node rep = getRepresentative( atom[0] );
+ EqcInfo* eqc = getOrMakeEqcInfo( rep, true );
+ addTester( fact, eqc, rep );
+ }
+ doPendingMerges();
+}
+
+void TheoryDatatypes::preRegisterTerm(TNode n) {
+ Debug("datatypes-prereg") << "TheoryDatatypes::preRegisterTerm() " << n << endl;
+ collectTerms( n );
+ switch (n.getKind()) {
+ case kind::EQUAL:
+ // Add the trigger for equality
+ d_equalityEngine.addTriggerEquality(n);
+ break;
+ case kind::APPLY_TESTER:
+ // Get triggered for both equal and dis-equal
+ d_equalityEngine.addTriggerPredicate(n);
+ break;
+ default:
+ // Maybe it's a predicate
+ if (n.getType().isBoolean()) {
+ // Get triggered for both equal and dis-equal
+ d_equalityEngine.addTriggerPredicate(n);
+ } else {
+ // Function applications/predicates
+ d_equalityEngine.addTerm(n);
+ }
+ break;
+ }
+ flushPendingFacts();
+}
+
+void TheoryDatatypes::presolve() {
+ Debug("datatypes") << "TheoryDatatypes::presolve()" << endl;
+}
+
+void TheoryDatatypes::addSharedTerm(TNode t) {
+ Debug("datatypes") << "TheoryDatatypes::addSharedTerm(): "
+ << t << endl;
+ d_equalityEngine.addTriggerTerm(t, THEORY_DATATYPES);
+}
+
/** propagate */
void TheoryDatatypes::propagate(Effort effort){
Debug("dt::propagate") << "TheoryDatatypes::propagate(" << literal << "): already in conflict" << std::endl;
return false;
}
+ Trace("dt-prop") << "dtPropagate " << literal << std::endl;
// Propagate out
bool ok = d_out->propagate(literal);
if (!ok) {
//do unification
Node unifEq = cons1.eqNode( cons2 );
for( int i=0; i<(int)cons1.getNumChildren(); i++ ) {
- Node eq = cons1[i].eqNode( cons2[i] );
- d_pending.push_back( eq );
- d_pending_exp[ eq ] = unifEq;
- Debug("datatypes-infer") << "DtInfer : " << eq << " by " << unifEq << std::endl;
- d_infer.push_back( eq );
- d_infer_exp.push_back( unifEq );
+ if( cons1[i]!=cons2[i] ){
+ Node eq = cons1[i].eqNode( cons2[i] );
+ d_pending.push_back( eq );
+ d_pending_exp[ eq ] = unifEq;
+ Trace("datatypes-infer") << "DtInfer : " << eq << " by " << unifEq << std::endl;
+ d_infer.push_back( eq );
+ d_infer_exp.push_back( unifEq );
+ }
}
}
}
- if( eqc1->d_inst.get().isNull() && !eqc2->d_inst.get().isNull() ){
- eqc1->d_inst.set( eqc2->d_inst );
+ if( !eqc1->d_inst && eqc2->d_inst ){
+ eqc1->d_inst = true;
}
if( cons1.isNull() && !cons2.isNull() ){
checkInst = true;
checkInst = true;
}
if( checkInst ){
- checkInstantiate( eqc1, t1 );
+ instantiate( eqc1, t1 );
if( d_conflict ){
return;
}
}
TheoryDatatypes::EqcInfo::EqcInfo( context::Context* c ) :
-d_inst( c, Node::null() ), d_constructor( c, Node::null() ), d_selectors( c, false ){
+d_inst( c, false ), d_constructor( c, Node::null() ), d_selectors( c, false ){
}
int ttindex = Datatype::indexOf( tt.getOperator().toExpr() );
Node j, jt;
if( hasLabel( eqc, n ) ){
+ //if we already know the constructor type, check whether it is in conflict or redundant
int jtindex = getLabelIndex( eqc, n );
if( (jtindex==ttindex)!=tpolarity ){
d_conflict = true;
if( !eqc->d_constructor.get().isNull() ){
+ //conflict because equivalence class contains a constructor
std::vector< TNode > assumptions;
explain( t, assumptions );
explain( eqc->d_constructor.get().eqNode( tt[0] ), assumptions );
d_out->conflict( d_conflictNode );
return;
}else{
+ //conflict because the existing label is contradictory
j = getLabel( n );
jt = j;
}
return;
}
}else{
+ //otherwise, scan list of labels
NodeListMap::iterator lbl_i = d_labels.find( n );
Assert( lbl_i != d_labels.end() );
NodeList* lbl = (*lbl_i).second;
const Datatype& dt = ((DatatypeType)(tt[0].getType()).toType()).getDatatype();
Debug("datatypes-labels") << "Labels at " << lbl->size() << " / " << dt.getNumConstructors() << std::endl;
if( tpolarity ){
- checkInstantiate( eqc, n );
+ instantiate( eqc, n );
}else{
//check if we have reached the maximum number of testers
// in this case, add the positive tester
}
}
Assert( testerIndex!=-1 );
+ //we must explain why each term in the set of testers for this equivalence class is equal
std::vector< Node > eq_terms;
NodeBuilder<> nb(kind::AND);
for( NodeList::const_iterator i = lbl->begin(); i != lbl->end(); i++ ) {
Node t_concl_exp = ( nb.getNumChildren() == 1 ) ? nb.getChild( 0 ) : nb;
d_pending.push_back( t_concl );
d_pending_exp[ t_concl ] = t_concl_exp;
- Debug("datatypes-infer") << "DtInfer : " << t_concl << " by " << t_concl_exp << std::endl;
+ Trace("datatypes-infer") << "DtInfer : " << t_concl << " by " << t_concl_exp << std::endl;
d_infer.push_back( t_concl );
d_infer_exp.push_back( t_concl_exp );
return;
}
}
-
-void TheoryDatatypes::check(Effort e) {
-
- while(!done() && !d_conflict) {
- // Get all the assertions
- Assertion assertion = get();
- TNode fact = assertion.assertion;
- Debug("datatypes-assert") << "Assert " << fact << std::endl;
-
- //reset the maps
- d_pending.clear();
- d_pending_exp.clear();
- //assert the fact
- assertFact( fact, fact );
- flushPendingFacts();
- }
-
- if( e == EFFORT_FULL ) {
- Debug("datatypes-split") << "Check for splits " << e << endl;
- eq::EqClassesIterator eqcs_i = eq::EqClassesIterator( &d_equalityEngine );
- while( !eqcs_i.isFinished() ){
- Node n = (*eqcs_i);
- if( n.getType().isDatatype() ){
- EqcInfo* eqc = getOrMakeEqcInfo( n, true );
- //if there are more than 1 possible constructors for eqc
- if( eqc->d_constructor.get().isNull() && !hasLabel( eqc, n ) ) {
- const Datatype& dt = ((DatatypeType)(n.getType()).toType()).getDatatype();
- //if only one constructor, then this term must be this constructor
- if( dt.getNumConstructors()==1 ){
- Node t = NodeManager::currentNM()->mkNode( APPLY_TESTER, Node::fromExpr( dt[0].getTester() ), n );
- d_pending.push_back( t );
- d_pending_exp[ t ] = NodeManager::currentNM()->mkConst( true );
- Debug("datatypes-infer") << "DtInfer : " << t << ", trivial" << std::endl;
- d_infer.push_back( t );
- }else{
- std::vector< bool > pcons;
- getPossibleCons( eqc, n, pcons );
- //std::cout << "pcons " << n << " = ";
- //for( int i=0; i<(int)pcons.size(); i++ ){ //std::cout << pcons[i] << " "; }
- //std::cout << std::endl;
- //check if we do not need to resolve the constructor type for this equivalence class.
- // this is if there are no selectors for this equivalence class, its type is infinite,
- // and we are not producing a model, then do not split.
- int consIndex = -1;
- bool needSplit = true;
- for( unsigned int j=0; j<pcons.size(); j++ ) {
- if( pcons[j] ) {
- if( consIndex==-1 ){
- consIndex = j;
- }
- if( !dt[ j ].isFinite() && !eqc->d_selectors ) {//&& !Options::current()->produceModels && !Options::current()->finiteModelFind ){
- needSplit = false;
- }
- }
- }
- if( needSplit && consIndex!=-1 ) {
- Node test = NodeManager::currentNM()->mkNode( APPLY_TESTER, Node::fromExpr( dt[consIndex].getTester() ), n );
- Debug("datatypes-split") << "*************Split for possible constructor " << test << " for " << n << endl;
- NodeBuilder<> nb(kind::OR);
- nb << test << test.notNode();
- Node lemma = nb;
- d_out->lemma( lemma );
- d_out->requirePhase( test, true );
- return;
- }else{
- Debug("datatypes-split") << "Do not split constructor for " << n << std::endl;
- }
- }
- }
- }
- ++eqcs_i;
+EqualityStatus TheoryDatatypes::getEqualityStatus(TNode a, TNode b){
+ if( d_equalityEngine.hasTerm(a) && d_equalityEngine.hasTerm(b) ){
+ if (d_equalityEngine.areEqual(a, b)) {
+ // The terms are implied to be equal
+ return EQUALITY_TRUE;
}
- flushPendingFacts();
- if( !d_conflict ){
- printModelDebug();
+ if (d_equalityEngine.areDisequal(a, b, false)) {
+ // The terms are implied to be dis-equal
+ return EQUALITY_FALSE;
}
}
- if( Debug.isOn("datatypes") || Debug.isOn("datatypes-split") ) {
- Notice() << "TheoryDatatypes::check(): done" << endl;
- }
+ return EQUALITY_UNKNOWN;
}
-void TheoryDatatypes::assertFact( Node fact, Node exp ){
- Assert( d_pending_merge.empty() );
- bool polarity = fact.getKind() != kind::NOT;
- TNode atom = polarity ? fact : fact[0];
- if (atom.getKind() == kind::EQUAL) {
- d_equalityEngine.assertEquality( atom, polarity, exp );
- }else{
- d_equalityEngine.assertPredicate( atom, polarity, exp );
- }
- //do all pending merges
- int i=0;
- while( i<(int)d_pending_merge.size() ){
- Assert( d_pending_merge[i].getKind()==EQUAL || d_pending_merge[i].getKind()==IFF );
- merge( d_pending_merge[i][0], d_pending_merge[i][1] );
- i++;
- }
- d_pending_merge.clear();
- //add to tester if applicable
- if( atom.getKind()==kind::APPLY_TESTER ){
- Node rep = getRepresentative( atom[0] );
- EqcInfo* eqc = getOrMakeEqcInfo( rep, true );
- addTester( fact, eqc, rep );
- }
+void TheoryDatatypes::computeCareGraph(){
+ Theory::computeCareGraph();
}
-void TheoryDatatypes::flushPendingFacts(){
- //also assert the pending facts
- int i = 0;
- while( !d_conflict && i<(int)d_pending.size() ){
- assertFact( d_pending[i], d_pending_exp[ d_pending[i] ] );
- i++;
- }
- d_pending.clear();
- d_pending_exp.clear();
-}
-
-void TheoryDatatypes::preRegisterTerm(TNode n) {
- Debug("datatypes-prereg") << "TheoryDatatypes::preRegisterTerm() " << n << endl;
- collectTerms( n );
- switch (n.getKind()) {
- case kind::EQUAL:
- // Add the trigger for equality
- d_equalityEngine.addTriggerEquality(n);
- break;
- case kind::APPLY_TESTER:
- // Get triggered for both equal and dis-equal
- d_equalityEngine.addTriggerPredicate(n);
- break;
- default:
- // Maybe it's a predicate
- if (n.getType().isBoolean()) {
- // Get triggered for both equal and dis-equal
- d_equalityEngine.addTriggerPredicate(n);
- } else {
- // Function applications/predicates
- d_equalityEngine.addTerm(n);
+void TheoryDatatypes::collectModelInfo( TheoryModel* m, bool fullModel ){
+ Trace("dt-model") << std::endl;
+ printModelDebug( "dt-model" );
+ m->assertEqualityEngine( &d_equalityEngine );
+ //must choose proper representatives
+ eq::EqClassesIterator eqcs_i = eq::EqClassesIterator( &d_equalityEngine );
+ while( !eqcs_i.isFinished() ){
+ Node eqc = (*eqcs_i);
+ //for all equivalence classes that are datatypes
+ if( eqc.getType().isDatatype() ){
+ EqcInfo* ei = getOrMakeEqcInfo( eqc );
+ if( ei ){
+ if( !ei->d_constructor.get().isNull() ){
+ //specify that we should use the constructor as the representative
+ m->assertRepresentative( ei->d_constructor.get() );
+ }else{
+ Trace("model-warn") << "WARNING: Datatypes: no constructor in equivalence class " << eqc << std::endl;
+ Trace("model-warn") << " Type : " << eqc.getType() << std::endl;
+ }
+ }else{
+ Trace("model-warn") << "WARNING: Datatypes: no equivalence class info for " << eqc << std::endl;
+ Trace("model-warn") << " Type : " << eqc.getType() << std::endl;
+ }
}
- break;
+ ++eqcs_i;
}
- Assert( d_pending.empty() );
-}
-
-void TheoryDatatypes::presolve() {
- Debug("datatypes") << "TheoryDatatypes::presolve()" << endl;
-}
-
-void TheoryDatatypes::addSharedTerm(TNode t) {
- Debug("datatypes") << "TheoryDatatypes::addSharedTerm(): "
- << t << endl;
-}
-
-void TheoryDatatypes::collectModelInfo( TheoryModel* m ){
- printModelDebug();
- m->assertEqualityEngine( &d_equalityEngine );
}
collectTerms( n[i] );
}
if( n.getKind() == APPLY_CONSTRUCTOR ){
+ //we must take into account subterm relation when checking for cycles
for( int i=0; i<(int)n.getNumChildren(); i++ ) {
Debug("datatypes-cycles") << "DtCyc: Subterm " << n << " -> " << n[i] << endl;
bool result = d_cycle_check.addEdgeNode( n, n[i] );
d_hasSeenCycle.set( d_hasSeenCycle.get() || result );
}
}else if( n.getKind() == APPLY_SELECTOR ){
+ //we must also record which selectors exist
Debug("datatypes") << " Found selector " << n << endl;
if (n.getType().isBoolean()) {
d_equalityEngine.addTriggerPredicate( n );
EqcInfo* eqc = getOrMakeEqcInfo( rep, true );
if( !eqc->d_selectors ){
eqc->d_selectors = true;
- checkInstantiate( eqc, rep );
+ instantiate( eqc, rep );
}
}
}
+void TheoryDatatypes::processNewTerm( Node n ){
+ Trace("dt-terms") << "Created term : " << n << std::endl;
+ //see if it is rewritten to be something different
+ Node rn = Rewriter::rewrite( n );
+ if( rn!=n ){
+ Node eq = rn.eqNode( n );
+ d_pending.push_back( eq );
+ d_pending_exp[ eq ] = NodeManager::currentNM()->mkConst( true );
+ Trace("datatypes-infer") << "DtInfer : " << eq << ", trivial" << std::endl;
+ d_infer.push_back( eq );
+ }
+}
+
Node TheoryDatatypes::getInstantiateCons( Node n, const Datatype& dt, int index ){
- //add constructor to equivalence class
- std::vector< Node > children;
- children.push_back( Node::fromExpr( dt[index].getConstructor() ) );
- for( int i=0; i<(int)dt[index].getNumArgs(); i++ ){
- children.push_back( NodeManager::currentNM()->mkNode( APPLY_SELECTOR, Node::fromExpr( dt[index][i].getSelector() ), n ) );
- }
- Node n_ic = NodeManager::currentNM()->mkNode( APPLY_CONSTRUCTOR, children );
- collectTerms( n_ic );
- //add type ascription for ambiguous constructor types
- if( n_ic.getType()!=n.getType() ){
- Assert( dt.isParametric() );
- Debug("datatypes-parametric") << "DtInstantiate: ambiguous type for " << n_ic << ", ascribe to " << n.getType() << std::endl;
- Debug("datatypes-parametric") << "Constructor is " << dt[index] << std::endl;
- Type tspec = dt[index].getSpecializedConstructorType(n.getType().toType());
- Debug("datatypes-parametric") << "Type specification is " << tspec << std::endl;
- children[0] = NodeManager::currentNM()->mkNode(kind::APPLY_TYPE_ASCRIPTION,
- NodeManager::currentNM()->mkConst(AscriptionType(tspec)), children[0] );
- n_ic = NodeManager::currentNM()->mkNode( APPLY_CONSTRUCTOR, children );
- Assert( n_ic.getType()==n.getType() );
- }
- return n_ic;
-}
-
-void TheoryDatatypes::checkInstantiate( EqcInfo* eqc, Node n ){
+ //if( !d_inst_map[n][index].isNull() ){
+ // return d_inst_map[n][index];
+ //}else{
+ //add constructor to equivalence class
+ std::vector< Node > children;
+ children.push_back( Node::fromExpr( dt[index].getConstructor() ) );
+ for( int i=0; i<(int)dt[index].getNumArgs(); i++ ){
+ Node nc = NodeManager::currentNM()->mkNode( APPLY_SELECTOR, Node::fromExpr( dt[index][i].getSelector() ), n );
+ children.push_back( nc );
+ processNewTerm( nc );
+ }
+ Node n_ic = NodeManager::currentNM()->mkNode( APPLY_CONSTRUCTOR, children );
+ collectTerms( n_ic );
+ //add type ascription for ambiguous constructor types
+ if( n_ic.getType()!=n.getType() ){
+ Assert( dt.isParametric() );
+ Debug("datatypes-parametric") << "DtInstantiate: ambiguous type for " << n_ic << ", ascribe to " << n.getType() << std::endl;
+ Debug("datatypes-parametric") << "Constructor is " << dt[index] << std::endl;
+ Type tspec = dt[index].getSpecializedConstructorType(n.getType().toType());
+ Debug("datatypes-parametric") << "Type specification is " << tspec << std::endl;
+ children[0] = NodeManager::currentNM()->mkNode(kind::APPLY_TYPE_ASCRIPTION,
+ NodeManager::currentNM()->mkConst(AscriptionType(tspec)), children[0] );
+ n_ic = NodeManager::currentNM()->mkNode( APPLY_CONSTRUCTOR, children );
+ Assert( n_ic.getType()==n.getType() );
+ }
+ //d_inst_map[n][index] = n_ic;
+ return n_ic;
+ //}
+}
+
+void TheoryDatatypes::instantiate( EqcInfo* eqc, Node n ){
//add constructor to equivalence class if not done so already
- if( hasLabel( eqc, n ) && eqc->d_inst.get().isNull() ){
+ if( hasLabel( eqc, n ) && !eqc->d_inst ){
Node exp;
Node tt;
if( !eqc->d_constructor.get().isNull() ){
int index = getLabelIndex( eqc, n );
const Datatype& dt = ((DatatypeType)(tt.getType()).toType()).getDatatype();
//must be finite or have a selector
- if( eqc->d_selectors || dt[ index ].isFinite() ){
- eqc->d_inst.set( NodeManager::currentNM()->mkConst( true ) );
+ if( eqc->d_selectors || dt[ index ].isFinite() || mustSpecifyModel() ){
+ //instantiate this equivalence class
+ eqc->d_inst = true;
Node tt_cons = getInstantiateCons( tt, dt, index );
Node eq;
if( tt!=tt_cons ){
Debug("datatypes-inst") << "DtInstantiate : " << eqc << " " << eq << std::endl;
d_pending.push_back( eq );
d_pending_exp[ eq ] = exp;
- Debug("datatypes-infer") << "DtInfer : " << eq << " by " << exp << std::endl;
+ Trace("datatypes-infer") << "DtInfer : " << eq << " by " << exp << std::endl;
//eqc->d_inst.set( eq );
d_infer.push_back( eq );
d_infer_exp.push_back( exp );
return false;
}
+bool TheoryDatatypes::mustSpecifyModel(){
+ return options::produceModels();
+ //return options::finiteModelFind() || options::produceModels();
+ //return false;
+}
+
+bool TheoryDatatypes::mustCommunicateFact( Node n, Node exp ){
+ //the datatypes decision procedure makes 3 "internal" inferences apart from the equality engine :
+ // (1) Unification : C( t1...tn ) = C( s1...sn ) => ti = si
+ // (2) Label : ~is_C1( t ) ... ~is_C{i-1}( t ) ~is_C{i+1}( t ) ... ~is_Cn( t ) => is_Ci( t )
+ // (3) Instantiate : is_C( t ) => t = C( sel_1( t ) ... sel_n( t ) )
+ //We may need to communicate (3) outwards if the conclusions involve other theories
+ Trace("dt-lemma-debug") << "Compute for " << exp << " => " << n << std::endl;
+ if( n.getKind()==EQUAL && n[1].getKind()==APPLY_CONSTRUCTOR && exp.getKind()!=EQUAL ){
+ bool addLemma = false;
+#if 1
+ const Datatype& dt = ((DatatypeType)(n[1].getType()).toType()).getDatatype();
+ addLemma = dt.involvesExternalType();
+#else
+ for( int j=0; j<(int)n[1].getNumChildren(); j++ ){
+ if( !n[1][j].getType().isDatatype() ){
+ addLemma = true;
+ break;
+ }
+ }
+#endif
+ if( addLemma ){
+ //check if we have already added this lemma
+ if( std::find( d_inst_lemmas[ n[0] ].begin(), d_inst_lemmas[ n[0] ].end(), n[1] )==d_inst_lemmas[ n[0] ].end() ){
+ d_inst_lemmas[ n[0] ].push_back( n[1] );
+ return true;
+ }else{
+ return false;
+ }
+ }
+ Trace("dt-lemma-debug") << "Do not need to communicate " << n << std::endl;
+ }
+ return false;
+}
+
bool TheoryDatatypes::hasTerm( Node a ){
return d_equalityEngine.hasTerm( a );
}
EqcInfo( context::Context* c );
~EqcInfo(){}
//whether we have instantiatied this eqc
- context::CDO< Node > d_inst;
+ context::CDO< bool > d_inst;
//constructor equal to this eqc
context::CDO< Node > d_constructor;
//all selectors whose argument is this eqc
eq::EqualityEngine d_equalityEngine;
/** information necessary for equivalence classes */
std::map< Node, EqcInfo* > d_eqc_info;
+ /** map from nodes to their instantiated equivalent for each constructor type */
+ std::map< Node, std::map< int, Node > > d_inst_map;
+ /** which instantiation lemmas we have sent */
+ std::map< Node, std::vector< Node > > d_inst_lemmas;
/** labels for each equivalence class
* for each eqc n, d_labels[n] is testers that hold for this equivalence class, either:
* a list of equations of the form
void assertFact( Node fact, Node exp );
/** flush pending facts */
void flushPendingFacts();
+ /** do pending merged */
+ void doPendingMerges();
/** get or make eqc info */
EqcInfo* getOrMakeEqcInfo( Node n, bool doMake = false );
/** has eqc info */
bool hasEqcInfo( Node n ) { return d_labels.find( n )!=d_labels.end(); }
+protected:
+ /** compute care graph */
+ void computeCareGraph();
public:
TheoryDatatypes(context::Context* c, context::UserContext* u, OutputChannel& out, Valuation valuation,
const LogicInfo& logicInfo, QuantifiersEngine* qe);
void preRegisterTerm(TNode n);
void presolve();
void addSharedTerm(TNode t);
- void collectModelInfo( TheoryModel* m );
+ EqualityStatus getEqualityStatus(TNode a, TNode b);
+ void collectModelInfo( TheoryModel* m, bool fullModel );
void shutdown() { }
std::string identify() const { return std::string("TheoryDatatypes"); }
+ /** debug print */
+ void printModelDebug( const char* c );
private:
/** add tester to equivalence class info */
void addTester( Node t, EqcInfo* eqc, Node n );
void collectTerms( Node n );
/** get instantiate cons */
Node getInstantiateCons( Node n, const Datatype& dt, int index );
+ /** process new term that was created internally */
+ void processNewTerm( Node n );
/** check instantiate */
- void checkInstantiate( EqcInfo* eqc, Node n );
- /** debug print */
- void printModelDebug();
-
+ void instantiate( EqcInfo* eqc, Node n );
+ /** must specify model
+ * This returns true when the datatypes theory is expected to specify the constructor
+ * type for all equivalence classes.
+ */
+ bool mustSpecifyModel();
+ /** must communicate fact */
+ bool mustCommunicateFact( Node n, Node exp );
private:
//equality queries
bool hasTerm( Node a );
if( e<2 ){
return InstStrategy::STATUS_UNFINISHED;
}else if( e==2 ){
- /*
InstMatch m;
for( int j = 0; j<(int)d_quantEngine->getTermDatabase()->getNumInstantiationConstants( f ); j++ ){
Node i = d_quantEngine->getTermDatabase()->getInstantiationConstant( f, j );
m.set(i,n);
}
}
- d_quantEngine->addInstantiation( f, m );
- */
+ //d_quantEngine->addInstantiation( f, m );
}
}
return InstStrategy::STATUS_UNKNOWN;
}
Node InstantiatorTheoryDatatypes::getValueFor( Node n ){
- return n;
- /* FIXME
//simply get the ground value for n in the current model, if it exists,
// or return an arbitrary ground term otherwise
+ if( !n.hasAttribute(InstConstantAttribute()) ){
+ return n;
+ }else{
+ return n;
+ }
+ /* FIXME
+
Debug("quant-datatypes-debug") << "get value for " << n << std::endl;
if( !n.hasAttribute(InstConstantAttribute()) ){
return n;
*/
void explain(TNode n) {}
- /**
- * Get model
- *
- * See theory/theory.h for more information about this method.
- */
- void collectModelInfo( TheoryModel* m ){
- Unimplemented("TheoryUFTim doesn't support model generation");
- }
-
std::string identify() const { return std::string("TheoryUFTim"); }
private:
#include "theory/model.h"
#include "theory/quantifiers_engine.h"
#include "theory/theory_engine.h"
-#include "util/datatype.h"
+#include "theory/type_enumerator.h"
+#include "smt/model_format_mode.h"
+#include "smt/options.h"
#include "theory/uf/theory_uf_model.h"
using namespace std;
using namespace CVC4::context;
using namespace CVC4::theory;
-void RepSet::clear(){
- d_type_reps.clear();
- d_tmap.clear();
-}
-
-void RepSet::add( Node n ){
- TypeNode t = n.getType();
- d_tmap[ n ] = (int)d_type_reps[t].size();
- d_type_reps[t].push_back( n );
-}
-
-void RepSet::set( TypeNode t, std::vector< Node >& reps ){
- for( size_t i=0; i<reps.size(); i++ ){
- d_tmap[ reps[i] ] = i;
- }
- d_type_reps[t].insert( d_type_reps[t].begin(), reps.begin(), reps.end() );
-}
-
-void RepSet::toStream(std::ostream& out){
-#if 0
- for( std::map< TypeNode, std::vector< Node > >::iterator it = d_type_reps.begin(); it != d_type_reps.end(); ++it ){
- out << it->first << " : " << std::endl;
- for( int i=0; i<(int)it->second.size(); i++ ){
- out << " " << i << ": " << it->second[i] << std::endl;
- }
- }
-#else
- for( std::map< TypeNode, std::vector< Node > >::iterator it = d_type_reps.begin(); it != d_type_reps.end(); ++it ){
- if( !it->first.isFunction() && !it->first.isPredicate() ){
- out << "(" << it->first << " " << it->second.size();
- out << " (";
- for( int i=0; i<(int)it->second.size(); i++ ){
- if( i>0 ){ out << " "; }
- out << it->second[i];
- }
- out << ")";
- out << ")" << std::endl;
- }
- }
-#endif
-}
-
TheoryModel::TheoryModel( context::Context* c, std::string name ) :
-d_equalityEngine( c, name ){
+d_substitutions( c ), d_equalityEngine( c, name ){
d_true = NodeManager::currentNM()->mkConst( true );
d_false = NodeManager::currentNM()->mkConst( false );
+ // The kinds we are treating as function application in congruence
+ d_equalityEngine.addFunctionKind(kind::APPLY_UF);
+ d_equalityEngine.addFunctionKind(kind::SELECT);
+ d_equalityEngine.addFunctionKind(kind::STORE);
+ d_equalityEngine.addFunctionKind(kind::APPLY_CONSTRUCTOR);
+ d_equalityEngine.addFunctionKind(kind::APPLY_SELECTOR);
+ d_equalityEngine.addFunctionKind(kind::APPLY_TESTER);
}
void TheoryModel::reset(){
d_rep_set.clear();
}
-void TheoryModel::addDefineFunction( Node n ){
- d_define_funcs.push_back( n );
- d_defines.push_back( 0 );
-}
-
-void TheoryModel::addDefineType( TypeNode tn ){
- d_define_types.push_back( tn );
- d_defines.push_back( 1 );
-}
-
-void TheoryModel::toStreamFunction( Node n, std::ostream& out ){
- out << "(" << n;
- out << " : " << n.getType();
- out << " ";
- Node value = getValue( n );
- /*
- if( n.getType().isSort() ){
- int index = d_rep_set.getIndexFor( value );
- if( index!=-1 ){
- out << value.getType() << "_" << index;
- }else{
- out << value;
- }
- }else{
- */
- out << value;
- out << ")" << std::endl;
-}
-
-void TheoryModel::toStreamType( TypeNode tn, std::ostream& out ){
- out << "(" << tn;
- if( tn.isSort() ){
- if( d_rep_set.d_type_reps.find( tn )!=d_rep_set.d_type_reps.end() ){
- out << " " << d_rep_set.d_type_reps[tn].size();
- //out << " (";
- //for( size_t i=0; i<d_rep_set.d_type_reps[tn].size(); i++ ){
- // if( i>0 ){ out << " "; }
- // out << d_rep_set.d_type_reps[tn][i];
- //}
- //out << ")";
- }
- }
- out << ")" << std::endl;
-}
-
void TheoryModel::toStream( std::ostream& out ){
/*//for debugging
eq::EqClassesIterator eqcs_i = eq::EqClassesIterator( &d_equalityEngine );
++eqcs_i;
}
*/
- int funcIndex = 0;
- int typeIndex = 0;
- for( size_t i=0; i<d_defines.size(); i++ ){
- if( d_defines[i]==0 ){
- toStreamFunction( d_define_funcs[funcIndex], out );
- funcIndex++;
- }else if( d_defines[i]==1 ){
- toStreamType( d_define_types[typeIndex], out );
- typeIndex++;
- }
- }
+ //need this function?
}
-Node TheoryModel::getValue( TNode n ){
- Debug("model") << "TheoryModel::getValue " << n << std::endl;
+Node TheoryModel::getModelValue( TNode n ){
+ Trace("model") << "TheoryModel::getModelValue " << n << std::endl;
//// special case: prop engine handles boolean vars
- //if(n.isVar() && n.getType().isBoolean()) {
- // Debug("model") << "-> Propositional variable." << std::endl;
+ //if(metakind == kind::metakind::VARIABLE && n.getType().isBoolean()) {
+ // Trace("model") << "-> Propositional variable." << std::endl;
// return d_te->getPropEngine()->getValue( n );
//}
// special case: value of a constant == itself
- if(n.isConst()) {
- Debug("model") << "-> Constant." << std::endl;
+ if( n.isConst() ) {
+ Trace("model") << "-> Constant." << std::endl;
return n;
}
}
//evaluate the children
for( int i=0; i<(int)n.getNumChildren(); i++ ){
- Node val = getValue( n[i] );
+ Node val = getModelValue( n[i] );
Debug("model-debug") << i << " : " << n[i] << " -> " << val << std::endl;
Assert( !val.isNull() );
children.push_back( val );
nn = Rewriter::rewrite( nn );
// special case: value of a constant == itself
- if(n.isConst()) {
- Debug("model") << "-> Theory-interpreted term." << std::endl;
+ if( nn.isConst() ) {
+ Trace("model") << "-> Theory-interpreted term." << std::endl;
return nn;
}else{
- Debug("model") << "-> Model-interpreted term." << std::endl;
+ Trace("model") << "-> Model-interpreted term." << std::endl;
//otherwise, get the interpreted value in the model
return getInterpretedValue( nn );
}
}
+Node TheoryModel::getValue( TNode n ){
+ //apply substitutions
+ Node nn = d_substitutions.apply( n );
+ //get value in model
+ return getModelValue( nn );
+}
+
Node TheoryModel::getDomainValue( TypeNode tn, std::vector< Node >& exclude ){
if( d_rep_set.d_type_reps.find( tn )!=d_rep_set.d_type_reps.end() ){
//try to find a pre-existing arbitrary element
return Node::null();
}
-//FIXME: use the theory enumerator to generate constants here
+//FIXME: need to ensure that theory enumerators exist for each sort
Node TheoryModel::getNewDomainValue( TypeNode tn ){
+#if 1
if( tn==NodeManager::currentNM()->booleanType() ){
if( d_rep_set.d_type_reps[tn].empty() ){
return d_false;
//return NodeManager::currentNM()->mkSkolem( tn );
return Node::null();
}
+#else
+ if( tn.isSort() ){
+ return Node::null();
+ }else{
+ TypeEnumerator te(tn);
+ while( !te.isFinished() ){
+ Node r = *te;
+ if(Debug.isOn("getNewDomainValue")) {
+ Debug("getNewDomainValue") << "getNewDomainValue( " << tn << ")" << endl;
+ Debug("getNewDomainValue") << "+ TypeEnumerator gave: " << r << endl;
+ Debug("getNewDomainValue") << "+ d_type_reps are:";
+ for(vector<Node>::const_iterator i = d_rep_set.d_type_reps[tn].begin();
+ i != d_rep_set.d_type_reps[tn].end();
+ ++i) {
+ Debug("getNewDomainValue") << " " << *i;
+ }
+ Debug("getNewDomainValue") << endl;
+ }
+ if( std::find(d_rep_set.d_type_reps[tn].begin(), d_rep_set.d_type_reps[tn].end(), r) ==d_rep_set.d_type_reps[tn].end() ) {
+ Debug("getNewDomainValue") << "+ it's new, so returning " << r << endl;
+ return r;
+ }
+ ++te;
+ }
+ return Node::null();
+ }
+#endif
+}
+
+/** add substitution */
+void TheoryModel::addSubstitution( TNode x, TNode t, bool invalidateCache ){
+ if( !d_substitutions.hasSubstitution( x ) ){
+ d_substitutions.addSubstitution( x, t, invalidateCache );
+ }
}
/** assert equality */
Node eqc = (*eqcs_i);
bool predicate = false;
bool predPolarity = false;
- if( eqc.getType()==NodeManager::currentNM()->booleanType() ){
+ if( eqc.getType().isBoolean() ){
predicate = true;
predPolarity = ee->areEqual( eqc, d_true );
//FIXME: do we guarentee that all boolean equivalence classes contain either d_true or d_false?
}
}
+void TheoryModel::assertRepresentative( Node n ){
+ Trace("model-builder-reps") << "Assert rep : " << n << std::endl;
+ d_reps[ n ] = n;
+}
+
bool TheoryModel::hasTerm( Node a ){
return d_equalityEngine.hasTerm( a );
}
Node TheoryModel::getRepresentative( Node a ){
if( d_equalityEngine.hasTerm( a ) ){
Node r = d_equalityEngine.getRepresentative( a );
- return d_reps[ r ];
+ if( d_reps.find( r )!=d_reps.end() ){
+ return d_reps[ r ];
+ }else{
+ return r;
+ }
}else{
return a;
}
void TheoryModel::printRepresentativeDebug( const char* c, Node r ){
if( r.isNull() ){
Debug( c ) << "null";
- }else if( r.getType()==NodeManager::currentNM()->booleanType() ){
+ }else if( r.getType().isBoolean() ){
if( areEqual( r, d_true ) ){
Debug( c ) << "true";
}else{
Assert( !r.isNull() );
if( r.isNull() ){
out << "null";
- }else if( r.getType()==NodeManager::currentNM()->booleanType() ){
+ }else if( r.getType().isBoolean() ){
if( areEqual( r, d_true ) ){
out << "true";
}else{
void DefaultModel::addTerm( Node n ){
//must collect UF terms
if( d_enableFuncModels && n.getKind()==APPLY_UF ){
- d_uf_terms[ n.getOperator() ].push_back( n );
+ Node op = n.getOperator();
+ if( std::find( d_uf_terms[ op ].begin(), d_uf_terms[ op ].end(), n )==d_uf_terms[ op ].end() ){
+ d_uf_terms[ op ].push_back( n );
+ }
}
}
default_v = v;
}
if( default_v.isNull() ){
+ //choose default value from model if none exists
default_v = getInterpretedValue( NodeManager::currentNM()->mkSkolem( type.getRangeType() ) );
}
ufmt.setDefaultValue( this, default_v );
ufmt.simplify();
- d_uf_models[n] = ufmt.getFunctionValue();
+ d_uf_models[n] = ufmt.getFunctionValue( "$x" );
}
return d_uf_models[n];
}else{
return n;
}
}else{
+ Trace("model") << "Get interpreted value of " << n << std::endl;
+ //add term to equality engine, this will enforce a value if it exists
+ d_equalityEngine.addTerm( n );
//first, see if the representative is defined
- if( d_equalityEngine.hasTerm( n ) ){
- n = d_equalityEngine.getRepresentative( n );
- //this check is required since d_equalityEngine.hasTerm( n )
- // does not ensure that n is in an equivalence class in d_equalityEngine
- if( d_reps.find( n )!=d_reps.end() ){
- return d_reps[n];
- }
+ n = d_equalityEngine.getRepresentative( n );
+ //this check is required since d_equalityEngine.hasTerm( n )
+ // does not ensure that n is in an equivalence class in d_equalityEngine
+ if( d_reps.find( n )!=d_reps.end() ){
+ return d_reps[n];
}
//second, try to choose an existing term as value
+ Trace("model") << "Choose existing value..." << std::endl;
std::vector< Node > v_emp;
Node n2 = getDomainValue( type, v_emp );
if( !n2.isNull() ){
+ //store the equality?? this is dangerous since it may cause representatives to change
+ //assertEquality( n, n2, true );
return n2;
}else{
//otherwise, choose new value
+ Trace("model") << "Choose new value..." << std::endl;
n2 = getNewDomainValue( type );
if( !n2.isNull() ){
+ //store the equality??
+ //assertEquality( n, n2, true );
return n2;
}else{
- //otherwise, just return itself
+ //otherwise, just return itself (this usually should not happen)
return n;
}
}
}
-void TheoryEngineModelBuilder::buildModel( Model* m ){
+void TheoryEngineModelBuilder::buildModel( Model* m, bool fullModel ){
TheoryModel* tm = (TheoryModel*)m;
//reset representative information
tm->reset();
//collect model info from the theory engine
- Debug( "model-builder" ) << "TheoryEngineModelBuilder: Collect model info..." << std::endl;
- d_te->collectModelInfo( tm );
- //unresolved equivalence classes
- std::map< Node, bool > unresolved_eqc;
- std::map< TypeNode, bool > unresolved_types;
- std::map< Node, std::vector< Node > > selects;
- std::map< Node, Node > apply_constructors;
- Debug( "model-builder" ) << "TheoryEngineModelBuilder: Build representatives..." << std::endl;
- //populate term database, store constant representatives
+ Trace("model-builder") << "TheoryEngineModelBuilder: Collect model info..." << std::endl;
+ d_te->collectModelInfo( tm, fullModel );
+ Trace("model-builder") << "Collect representatives..." << std::endl;
+ //store asserted representative map
+ std::map< Node, Node > assertedReps;
+ //process all terms in the equality engine, store representatives
eq::EqClassesIterator eqcs_i = eq::EqClassesIterator( &tm->d_equalityEngine );
while( !eqcs_i.isFinished() ){
Node eqc = (*eqcs_i);
- TypeNode eqct = eqc.getType();
- //initialize unresolved type information
- initializeType( eqct, unresolved_types );
- //add terms to model, get constant rep if possible
- Node const_rep;
- eq::EqClassIterator eqc_i = eq::EqClassIterator( eqc, &tm->d_equalityEngine );
- while( !eqc_i.isFinished() ){
- Node n = *eqc_i;
- //check if this is constant, if so, we will use it as representative
- if( n.isConst() ){
- const_rep = n;
- }
- //theory-specific information needed
- if( n.getKind()==SELECT ){
- selects[ n[0] ].push_back( n );
- }else if( n.getKind()==APPLY_CONSTRUCTOR ){
- apply_constructors[ eqc ] = n;
- }
- //model-specific processing of the term, this will include
- tm->addTerm( n );
- ++eqc_i;
- }
- //store representative in representative set
- if( !const_rep.isNull() ){
- //Message() << "Constant rep " << const_rep << " for " << eqc << std::endl;
- tm->d_reps[ eqc ] = const_rep;
- tm->d_rep_set.add( const_rep );
+ if( assertedReps.find( eqc )!=assertedReps.end() ){
+ Trace("model-warn") << "Duplicate equivalence class!!!! " << eqc << std::endl;
}else{
- //Message() << "** unresolved eqc " << eqc << std::endl;
- unresolved_eqc[ eqc ] = true;
- unresolved_types[ eqct ] = true;
- }
- ++eqcs_i;
- }
- //choose representatives for unresolved equivalence classes
- Debug( "model-builder" ) << "TheoryEngineModelBuilder: Complete model..." << std::endl;
- bool fixedPoint;
- do{
- fixedPoint = true;
- //for calculating unresolved types
- std::map< TypeNode, bool > unresolved_types_next;
- for( std::map< TypeNode, bool >::iterator it = unresolved_types.begin(); it != unresolved_types.end(); ++it ){
- unresolved_types_next[ it->first ] = false;
- }
- //try to resolve each unresolved equivalence class
- for( std::map< Node, bool >::iterator it = unresolved_eqc.begin(); it != unresolved_eqc.end(); ++it ){
- if( it->second ){
- Node n = it->first;
- TypeNode tn = n.getType();
- Node rep;
- bool mkRep = true;
- if( tn.isArray() ){
- TypeNode index_t = tn.getArrayIndexType();
- TypeNode elem_t = tn.getArrayConstituentType();
- if( !unresolved_types[ index_t ] && !unresolved_types[ elem_t ] ){
- //collect all relevant set values of n
- std::vector< Node > arr_selects;
- std::vector< Node > arr_select_values;
- Node nbase = n;
- while( nbase.getKind()==STORE ){
- arr_selects.push_back( tm->getRepresentative( nbase[1] ) );
- arr_select_values.push_back( tm->getRepresentative( nbase[2] ) );
- nbase = nbase[0];
- }
- eq::EqClassIterator eqc_i = eq::EqClassIterator( n, &tm->d_equalityEngine );
- while( !eqc_i.isFinished() ){
- for( int i=0; i<(int)selects[ *eqc_i ].size(); i++ ){
- Node r = tm->getRepresentative( selects[ *eqc_i ][i][1] );
- if( std::find( arr_selects.begin(), arr_selects.end(), r )==arr_selects.end() ){
- arr_selects.push_back( r );
- arr_select_values.push_back( tm->getRepresentative( selects[ *eqc_i ][i] ) );
- }
- }
- ++eqc_i;
- }
- //now, construct based on select/value pairs
- //TODO: make this a constant
- rep = chooseRepresentative( tm, nbase );
- for( int i=0; i<(int)arr_selects.size(); i++ ){
- rep = NodeManager::currentNM()->mkNode( STORE, rep, arr_selects[i], arr_select_values[i] );
- }
- }
- mkRep = false;
- }else if( tn.isDatatype() ){
- if( apply_constructors.find( n )!=apply_constructors.end() ){
- Node ac = apply_constructors[n];
- std::vector< Node > children;
- children.push_back( ac.getOperator() );
- for( size_t i = 0; i<ac.getNumChildren(); i++ ){
- Node acir = ac[i];
- if( tm->d_equalityEngine.hasTerm( acir ) ){
- acir = tm->d_equalityEngine.getRepresentative( acir );
- }
- if( unresolved_eqc.find( acir )==unresolved_eqc.end() ){
- Message() << "TheoryEngineModelBuilder::buildModel : Datatype argument does not exist in the model " << acir << std::endl;
- acir = Node::null();
- }
- if( acir.isNull() || unresolved_eqc[ acir ] ){
- mkRep = false;
- break;
- }else{
- children.push_back( tm->getRepresentative( acir ) );
- }
- }
- if( mkRep ){
- rep = NodeManager::currentNM()->mkNode( APPLY_CONSTRUCTOR, children );
- }
+ TypeNode eqct = eqc.getType();
+ Node const_rep;
+ eq::EqClassIterator eqc_i = eq::EqClassIterator( eqc, &tm->d_equalityEngine );
+ while( !eqc_i.isFinished() ){
+ Node n = *eqc_i;
+ //if this node was specified as a representative
+ if( tm->d_reps.find( n )!=tm->d_reps.end() ){
+ Assert( !tm->d_reps[n].isNull() );
+ //if not already specified
+ if( assertedReps.find( eqc )==assertedReps.end() ){
+ Trace("model-builder") << "Rep( " << eqc << " ) = " << tm->d_reps[n] << std::endl;
+ assertedReps[ eqc ] = tm->d_reps[n];
}else{
- Message() << "TheoryEngineModelBuilder::buildModel : Do not know how to resolve datatype equivalence class " << n << std::endl;
+ if( n!=assertedReps[eqc] ){ //FIXME : this should be an assertion (EqClassIterator should not give duplicates)
+ //duplicate representative specified
+ Trace("model-warn") << "Duplicate representative specified for equivalence class " << eqc << ": " << std::endl;
+ Trace("model-warn") << " " << assertedReps[eqc] << ", " << n << std::endl;
+ Trace("model-warn") << " Type : " << n.getType() << std::endl;
+ }
}
- mkRep = false;
- }
- if( mkRep ){
- rep = chooseRepresentative( tm, n );
+ }else if( n.isConst() ){
+ //if this is constant, we will use it as representative (if none other specified)
+ const_rep = n;
}
- if( !rep.isNull() ){
- tm->assertEquality( n, rep, true );
- tm->d_reps[ n ] = rep;
- tm->d_rep_set.add( rep );
- unresolved_eqc[ n ] = false;
- fixedPoint = false;
+ //model-specific processing of the term
+ tm->addTerm( n );
+ ++eqc_i;
+ }
+ //if a representative was not specified
+ if( assertedReps.find( eqc )==assertedReps.end() ){
+ if( !const_rep.isNull() ){
+ //use the constant representative
+ assertedReps[ eqc ] = const_rep;
}else{
- unresolved_types_next[ tn ] = true;
+ if( fullModel ){
+ //assertion failure?
+ Trace("model-warn") << "No representative specified for equivalence class " << eqc << std::endl;
+ Trace("model-warn") << " Type : " << eqc.getType() << std::endl;
+ }
+ //assertedReps[ eqc ] = chooseRepresentative( tm, eqc, fullModel );
+ assertedReps[ eqc ] = eqc;
}
}
}
- //for calculating unresolved types
- for( std::map< TypeNode, bool >::iterator it = unresolved_types.begin(); it != unresolved_types.end(); ++it ){
- unresolved_types[ it->first ] = unresolved_types_next[ it->first ];
- }
- }while( !fixedPoint );
-
- //for all unresolved equivalence classes, just get new domain value
- // this should typically never happen (all equivalence classes should be resolved at this point)
- for( std::map< Node, bool >::iterator it = unresolved_eqc.begin(); it != unresolved_eqc.end(); ++it ){
- if( it->second ){
- Node n = it->first;
- Node rep = chooseRepresentative( tm, n );
- tm->assertEquality( n, rep, true );
- tm->d_reps[ n ] = rep;
- tm->d_rep_set.add( rep );
- //FIXME: Assertion failure here?
- Message() << "Warning : Unresolved eqc, assigning " << rep << " for eqc( " << n << " ), type = " << n.getType() << std::endl;
- }
+ ++eqcs_i;
}
-
- //model-specific initialization
- processBuildModel( tm );
-}
-
-void TheoryEngineModelBuilder::initializeType( TypeNode tn, std::map< TypeNode, bool >& unresolved_types ){
- if( unresolved_types.find( tn )==unresolved_types.end() ){
- unresolved_types[tn] = false;
- if( tn.isArray() ){
- initializeType( tn.getArrayIndexType(), unresolved_types );
- initializeType( tn.getArrayConstituentType(), unresolved_types );
- }else if( tn.isDatatype() ){
- const Datatype& dt = ((DatatypeType)(tn).toType()).getDatatype();
- for( size_t i = 0; i<dt.getNumConstructors(); i++ ){
- for( size_t j = 0; j<dt[i].getNumArgs(); j++ ){
- initializeType( TypeNode::fromType( dt[i][j].getType() ), unresolved_types );
- }
- }
- }
+ Trace("model-builder") << "Normalize representatives..." << std::endl;
+ //now, normalize all representatives
+ // this will make every leaf of asserted representatives into a representative
+ std::map< Node, bool > normalized;
+ for( std::map< Node, Node >::iterator it = assertedReps.begin(); it != assertedReps.end(); ++it ){
+ std::map< Node, bool > normalizing;
+ normalizeRepresentative( tm, it->first, assertedReps, normalized, normalizing );
+ }
+ Trace("model-builder") << "Copy representatives to model..." << std::endl;
+ //assertedReps has the actual representatives we will use, now copy to model
+ tm->d_reps.clear();
+ for( std::map< Node, Node >::iterator it = assertedReps.begin(); it != assertedReps.end(); ++it ){
+ tm->d_reps[ it->first ] = it->second;
+ tm->d_rep_set.add( it->second );
}
+
+ //modelBuilder-specific initialization
+ processBuildModel( tm, fullModel );
}
-Node TheoryEngineModelBuilder::chooseRepresentative( TheoryModel* m, Node eqc ){
+Node TheoryEngineModelBuilder::chooseRepresentative( TheoryModel* m, Node eqc, bool fullModel ){
//try to get a new domain value
Node rep = m->getNewDomainValue( eqc.getType() );
if( !rep.isNull() ){
return eqc;
}
}
+
+Node TheoryEngineModelBuilder::normalizeRepresentative( TheoryModel* m, Node r, std::map< Node, Node >& reps,
+ std::map< Node, bool >& normalized,
+ std::map< Node, bool >& normalizing ){
+ Trace("temb-normalize") << r << std::endl;
+ if( normalized.find( r )!=normalized.end() ){
+ //Message() << " -> already normalized, return " << reps[r] << std::endl;
+ return reps[r];
+ }else if( normalizing.find( r )!=normalizing.end() && normalizing[r] ){
+ //this case is to handle things like when store( A, e, i ) is given
+ // as a representative for array A.
+ //Message() << " -> currently normalizing, give up : " << r << std::endl;
+ return r;
+ }else if( reps.find( r )!=reps.end() ){
+ normalizing[ r ] = true;
+ Node retNode = normalizeNode( m, reps[r], reps, normalized, normalizing );
+ normalizing[ r ] = false;
+ normalized[ r ] = true;
+ reps[ r ] = retNode;
+ //Message() << " --> returned " << retNode << " for " << r << std::endl;
+ return retNode;
+ }else if( m->d_equalityEngine.hasTerm( r ) ){
+ normalizing[ r ] = true;
+ //return the normalized representative from the model
+ r = m->d_equalityEngine.getRepresentative( r );
+ //Message() << " -> it is the representative " << r << std::endl;
+ Node retNode = normalizeRepresentative( m, r, reps, normalized, normalizing );
+ normalizing[ r ] = false;
+ return retNode;
+ }else{
+ if( !r.isConst() ){
+ Trace("model-warn") << "Normalizing representative, unknown term: " << r << std::endl;
+ Trace("model-warn") << " Type : " << r.getType() << std::endl;
+ Trace("model-warn") << " Kind : " << r.getKind() << std::endl;
+ normalizing[ r ] = true;
+ r = normalizeNode( m, r, reps, normalized, normalizing );
+ normalizing[ r ] = false;
+ }
+ //Message() << " -> unknown, return " << r << std::endl;
+ return r;
+ }
+}
+
+Node TheoryEngineModelBuilder::normalizeNode( TheoryModel* m, Node r, std::map< Node, Node >& reps,
+ std::map< Node, bool >& normalized,
+ std::map< Node, bool >& normalizing ){
+ if( r.getNumChildren()>0 ){
+ //Message() << " ---> normalize " << r << " " << r.getNumChildren() << " " << r.getKind() << std::endl;
+ //non-leaf case: construct representative from children
+ std::vector< Node > children;
+ if( r.getMetaKind() == kind::metakind::PARAMETERIZED ){
+ children.push_back( r.getOperator() );
+ }
+ for( size_t i=0; i<r.getNumChildren(); i++ ){
+ Node ri = normalizeRepresentative( m, r[i], reps, normalized, normalizing );
+ children.push_back( ri );
+ }
+ Node retNode = NodeManager::currentNM()->mkNode( r.getKind(), children );
+ retNode = Rewriter::rewrite( retNode );
+ if( retNode!=r ){
+ //assure that it is made equal in the model
+ m->assertEquality( r, retNode, true );
+ }
+ return retNode;
+ }else{
+ return r;
+ }
+}
\ No newline at end of file
#include "util/model.h"
#include "theory/uf/equality_engine.h"
+#include "theory/rep_set.h"
+#include "theory/substitutions.h"
namespace CVC4 {
namespace theory {
class QuantifiersEngine;
-
-/** this class stores a representative set */
-class RepSet {
-public:
- RepSet(){}
- ~RepSet(){}
- std::map< TypeNode, std::vector< Node > > d_type_reps;
- std::map< Node, int > d_tmap;
- /** clear the set */
- void clear();
- /** has type */
- bool hasType( TypeNode tn ) { return d_type_reps.find( tn )!=d_type_reps.end(); }
- /** add representative for type */
- void add( Node n );
- /** 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 toStream(std::ostream& out);
-};
-
-//representative domain
-typedef std::vector< int > RepDomain;
-
class TheoryEngineModelBuilder;
/** Theory Model class
* such as contraining the interpretation of uninterpretted functions.
*/
virtual void addTerm( Node n ) {}
-private:
- /** List of definitions that the user has given
- * This is necessary for supporting the get-model command.
- */
- std::vector< Node > d_define_funcs;
- std::vector< TypeNode > d_define_types;
- std::vector< int > d_defines;
-protected:
- /** print the value of the function n to stream */
- virtual void toStreamFunction( Node n, std::ostream& out );
- /** print the value of the type tn to stream */
- virtual void toStreamType( TypeNode tn, std::ostream& out );
+ /** substitution map for this model */
+ SubstitutionMap d_substitutions;
public:
TheoryModel( context::Context* c, std::string name );
virtual ~TheoryModel(){}
/** true/false nodes */
Node d_true;
Node d_false;
-public:
+protected:
/** reset the model */
virtual void reset();
/** get interpreted value
* This should function should return a representative in d_reps
*/
virtual Node getInterpretedValue( TNode n ) = 0;
+ /**
+ * Get model value function. This function is called by getValue
+ */
+ Node getModelValue( TNode n );
public:
- /** add defined function (for get-model) */
- void addDefineFunction( Node n );
- /** add defined type (for get-model) */
- void addDefineType( TypeNode tn );
/**
* Get value function. This should be called only after a ModelBuilder has called buildModel(...)
* on this model.
* If it cannot find such a node, it returns null.
*/
Node getNewDomainValue( TypeNode tn );
+ /** complete all values for type
+ * Calling this function ensures that all terms of type tn exist in d_rep_set.d_type_reps[tn]
+ */
+ void completeDomainValues( TypeNode tn ){
+ d_rep_set.complete( tn );
+ }
public:
+ /** Adds a substitution from x to t. */
+ void addSubstitution(TNode x, TNode t, bool invalidateCache = true);
/** assert equality holds in the model */
void assertEquality( Node a, Node b, bool polarity );
/** assert predicate holds in the model */
void assertPredicate( Node a, bool polarity );
/** assert all equalities/predicates in equality engine hold in the model */
void assertEqualityEngine( const eq::EqualityEngine* ee );
+ /** assert representative
+ * This function tells the model that n should be the representative of its equivalence class.
+ * It should be called during model generation, before final representatives are chosen. In the
+ * case of TheoryEngineModelBuilder, it should be called during Theory's collectModelInfo( ... )
+ * functions where fullModel = true.
+ */
+ void assertRepresentative( Node n );
public:
/** general queries */
bool hasTerm( Node a );
protected:
/** pointer to theory engine */
TheoryEngine* d_te;
- /** choose representative for unresolved equivalence class */
- void initializeType( TypeNode tn, std::map< TypeNode, bool >& unresolved_types );
/** process build model */
- virtual void processBuildModel( TheoryModel* m ){}
+ virtual void processBuildModel( TheoryModel* m, bool fullModel ){}
/** choose representative for unconstrained equivalence class */
- virtual Node chooseRepresentative( TheoryModel* m, Node eqc );
+ virtual Node chooseRepresentative( TheoryModel* m, Node eqc, bool fullModel );
+ /** normalize representative */
+ Node normalizeRepresentative( TheoryModel* m, Node r, std::map< Node, Node >& reps,
+ std::map< Node, bool >& normalized,
+ std::map< Node, bool >& normalizing );
+ Node normalizeNode( TheoryModel* m, Node r, std::map< Node, Node >& reps,
+ std::map< Node, bool >& normalized,
+ std::map< Node, bool >& normalizing );
public:
TheoryEngineModelBuilder( TheoryEngine* te );
virtual ~TheoryEngineModelBuilder(){}
/** Build model function.
* Should be called only on TheoryModels m
*/
- void buildModel( Model* m );
+ void buildModel( Model* m, bool fullModel );
};
}
namespace CVC4 {
namespace theory {
+class Theory;
+
/**
* A LemmaStatus, returned from OutputChannel::lemma(), provides information
* about the lemma added. In particular, it contains the T-rewritten lemma
* long-running operations, they cannot rely on resource() to break
* out of infinite or intractable computations.
*/
- virtual void spendResource() throw() {
- }
+ virtual void spendResource() throw() {}
+
+ /** Handle user attribute
+ * Associates theory t with the attribute attr. Theory t will be
+ * notifed whenever an attribute of name attr is set on a node.
+ * This can happen through, for example, the SMT LIB v2 language.
+ */
+ virtual void handleUserAttribute( const char* attr, Theory* t ){}
};/* class OutputChannel */
inst_match.cpp \
model_engine.h \
model_engine.cpp \
- inst_when_mode.cpp \
- inst_when_mode.h \
- literal_match_mode.cpp \
- literal_match_mode.h \
+ modes.cpp \
+ modes.h \
relevant_domain.h \
relevant_domain.cpp \
- rep_set_iterator.h \
- rep_set_iterator.cpp \
term_database.h \
term_database.cpp \
first_order_model.h \
first_order_model.cpp \
model_builder.h \
- model_builder.cpp
+ model_builder.cpp \
+ quantifiers_attributes.h \
+ quantifiers_attributes.cpp
EXTRA_DIST = \
kinds \
**/
#include "theory/quantifiers/first_order_model.h"
-#include "theory/quantifiers/rep_set_iterator.h"
#include "theory/quantifiers/model_engine.h"
#include "theory/quantifiers/term_database.h"
+#include "theory/quantifiers/quantifiers_attributes.h"
+
+#define USE_INDEX_ORDERING
using namespace std;
using namespace CVC4;
using namespace CVC4::theory;
using namespace CVC4::theory::quantifiers;
-FirstOrderModel::FirstOrderModel( QuantifiersEngine* qe, context::Context* c, std::string name ) : DefaultModel( c, name, true ),
-d_term_db( qe->getTermDatabase() ), d_forall_asserts( c ){
+FirstOrderModel::FirstOrderModel( context::Context* c, std::string name ) : DefaultModel( c, name, true ),
+d_axiom_asserted( c, false ), d_forall_asserts( c ){
}
+void FirstOrderModel::assertQuantifier( Node n ){
+ d_forall_asserts.push_back( n );
+ if( n.getAttribute(AxiomAttribute()) ){
+ d_axiom_asserted = true;
+ }
+}
+
void FirstOrderModel::reset(){
- //rebuild models
- d_uf_model_tree.clear();
- d_uf_model_gen.clear();
- d_array_model.clear();
DefaultModel::reset();
}
void FirstOrderModel::addTerm( Node n ){
- //std::vector< Node > added;
- //d_term_db->addTerm( n, added, false );
DefaultModel::addTerm( n );
}
-void FirstOrderModel::initialize(){
+void FirstOrderModel::initialize( bool considerAxioms ){
+ //rebuild models
+ d_uf_model_tree.clear();
+ d_uf_model_gen.clear();
+ d_array_model.clear();
//this is called after representatives have been chosen and the equality engine has been built
//for each quantifier, collect all operators we care about
for( int i=0; i<getNumAssertedQuantifiers(); i++ ){
Node f = getAssertedQuantifier( i );
- //initialize relevant models within bodies of all quantifiers
- initializeModelForTerm( f[1] );
- }
- //for debugging
- if( Trace.isOn("model-engine") ){
- for( std::map< TypeNode, std::vector< Node > >::iterator it = d_rep_set.d_type_reps.begin(); it != d_rep_set.d_type_reps.end(); ++it ){
- if( it->first.isSort() ){
- Trace("model-engine") << "Cardinality( " << it->first << " )" << " = " << it->second.size() << std::endl;
- }
+ if( considerAxioms || !f.hasAttribute(AxiomAttribute()) ){
+ //initialize relevant models within bodies of all quantifiers
+ initializeModelForTerm( f[1] );
}
}
}
}
}
-void FirstOrderModel::toStreamFunction( Node n, std::ostream& out ){
- /*
- if( d_uf_model.find( n )!=d_uf_model.end() ){
- //d_uf_model[n].toStream( out );
- Node value = d_uf_model[n].getFunctionValue();
- out << "(" << n << " " << value << ")";
- }else if( d_array_model.find( n )!=d_array_model.end() ){
- Node value = d_array_model[n].getArrayValue();
- out << "(" << n << " " << value << ")" << std::endl;
- }
- */
- DefaultModel::toStreamFunction( n, out );
-}
-
-void FirstOrderModel::toStreamType( TypeNode tn, std::ostream& out ){
- DefaultModel::toStreamType( tn, out );
-}
-
Node FirstOrderModel::getInterpretedValue( TNode n ){
Debug("fo-model") << "get interpreted value " << n << std::endl;
TypeNode type = n.getType();
if( type.isFunction() || type.isPredicate() ){
- if( d_uf_models.find( n )==d_uf_models.end() ){
- //use the model tree to generate the model
- Node fn = d_uf_model_tree[n].getFunctionValue();
- d_uf_models[n] = fn;
- return fn;
+ if( d_uf_model_tree.find( n )!=d_uf_model_tree.end() ){
+ if( d_uf_models.find( n )==d_uf_models.end() ){
+ //use the model tree to generate the model
+ d_uf_models[n] = d_uf_model_tree[n].getFunctionValue( "$x" );
+ }
+ return d_uf_models[n];
}
/*
}else if( type.isArray() ){
return DefaultModel::getInterpretedValue( n );
}
-TermDb* FirstOrderModel::getTermDatabase(){
- return d_term_db;
+void FirstOrderModel::toStream(std::ostream& out){
+
}
-void FirstOrderModel::toStream(std::ostream& out){
- DefaultModel::toStream( out );
+//for evaluation of quantifier bodies
+
+void FirstOrderModel::resetEvaluate(){
+ d_eval_uf_use_default.clear();
+ d_eval_uf_model.clear();
+ d_eval_term_index_order.clear();
+ d_eval_failed.clear();
+ d_eval_failed_lits.clear();
+ d_eval_formulas = 0;
+ d_eval_uf_terms = 0;
+ d_eval_lits = 0;
+ d_eval_lits_unknown = 0;
+}
+
+//if evaluate( n ) = eVal,
+// let n' = ri * n be the formula n instantiated with the current values in r_iter
+// if eVal = 1, then n' is true, if eVal = -1, then n' is false,
+// if eVal = 0, then n' cannot be proven to be equal to phaseReq
+// if eVal is not 0, then
+// each n{ri->d_index[0]/x_0...ri->d_index[depIndex]/x_depIndex, */x_(depIndex+1) ... */x_n } is equivalent in the current model
+int FirstOrderModel::evaluate( Node n, int& depIndex, RepSetIterator* ri ){
+ ++d_eval_formulas;
+ //Debug("fmf-eval-debug") << "Evaluate " << n << " " << phaseReq << std::endl;
+ //Notice() << "Eval " << n << std::endl;
+ if( n.getKind()==NOT ){
+ int val = evaluate( n[0], depIndex, ri );
+ return val==1 ? -1 : ( val==-1 ? 1 : 0 );
+ }else if( n.getKind()==OR || n.getKind()==AND || n.getKind()==IMPLIES ){
+ int baseVal = n.getKind()==AND ? 1 : -1;
+ int eVal = baseVal;
+ int posDepIndex = ri->getNumTerms();
+ int negDepIndex = -1;
+ for( int i=0; i<(int)n.getNumChildren(); i++ ){
+ //evaluate subterm
+ int childDepIndex;
+ Node nn = ( i==0 && n.getKind()==IMPLIES ) ? n[i].notNode() : n[i];
+ int eValT = evaluate( nn, childDepIndex, ri );
+ if( eValT==baseVal ){
+ if( eVal==baseVal ){
+ if( childDepIndex>negDepIndex ){
+ negDepIndex = childDepIndex;
+ }
+ }
+ }else if( eValT==-baseVal ){
+ eVal = -baseVal;
+ if( childDepIndex<posDepIndex ){
+ posDepIndex = childDepIndex;
+ if( posDepIndex==-1 ){
+ break;
+ }
+ }
+ }else if( eValT==0 ){
+ if( eVal==baseVal ){
+ eVal = 0;
+ }
+ }
+ }
+ if( eVal!=0 ){
+ depIndex = eVal==-baseVal ? posDepIndex : negDepIndex;
+ return eVal;
+ }else{
+ return 0;
+ }
+ }else if( n.getKind()==IFF || n.getKind()==XOR ){
+ int depIndex1;
+ int eVal = evaluate( n[0], depIndex1, ri );
+ if( eVal!=0 ){
+ int depIndex2;
+ int eVal2 = evaluate( n.getKind()==XOR ? n[1].notNode() : n[1], depIndex2, ri );
+ if( eVal2!=0 ){
+ depIndex = depIndex1>depIndex2 ? depIndex1 : depIndex2;
+ return eVal==eVal2 ? 1 : -1;
+ }
+ }
+ return 0;
+ }else if( n.getKind()==ITE ){
+ int depIndex1, depIndex2;
+ int eVal = evaluate( n[0], depIndex1, ri );
+ if( eVal==0 ){
+ //evaluate children to see if they are the same value
+ int eval1 = evaluate( n[1], depIndex1, ri );
+ if( eval1!=0 ){
+ int eval2 = evaluate( n[1], depIndex2, ri );
+ if( eval1==eval2 ){
+ depIndex = depIndex1>depIndex2 ? depIndex1 : depIndex2;
+ return eval1;
+ }
+ }
+ }else{
+ int eValT = evaluate( n[eVal==1 ? 1 : 2], depIndex2, ri );
+ depIndex = depIndex1>depIndex2 ? depIndex1 : depIndex2;
+ return eValT;
+ }
+ return 0;
+ }else if( n.getKind()==FORALL ){
+ return 0;
+ }else{
+ ++d_eval_lits;
+ ////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-eval-debug") << "Evaluate literal " << n << std::endl;
+ int retVal = 0;
+ depIndex = ri->getNumTerms()-1;
+ Node val = evaluateTerm( n, depIndex, ri );
+ if( !val.isNull() ){
+ if( areEqual( val, d_true ) ){
+ retVal = 1;
+ }else if( areEqual( val, d_false ) ){
+ retVal = -1;
+ }else{
+ if( val.getKind()==EQUAL ){
+ if( areEqual( val[0], val[1] ) ){
+ retVal = 1;
+ }else if( areDisequal( val[0], val[1] ) ){
+ retVal = -1;
+ }
+ }
+ }
+ }
+ if( retVal!=0 ){
+ Debug("fmf-eval-debug") << "Evaluate literal: return " << retVal << ", depIndex = " << depIndex << std::endl;
+ }else{
+ ++d_eval_lits_unknown;
+ Trace("fmf-eval-amb") << "Neither true nor false : " << n << std::endl;
+ Trace("fmf-eval-amb") << " value : " << val << std::endl;
+ //std::cout << "Neither true nor false : " << n << std::endl;
+ //std::cout << " Value : " << val << std::endl;
+ //for( int i=0; i<(int)n.getNumChildren(); i++ ){
+ // std::cout << " " << i << " : " << n[i].getType() << std::endl;
+ //}
+ }
+ return retVal;
+ }
+}
+
+Node FirstOrderModel::evaluateTerm( Node n, int& depIndex, RepSetIterator* ri ){
+ //Message() << "Eval term " << n << std::endl;
+ if( !n.hasAttribute(InstConstantAttribute()) ){
+ //if evaluating a ground term, just consult the standard getValue functionality
+ depIndex = -1;
+ return getValue( n );
+ }else{
+ Node val;
+ depIndex = ri->getNumTerms()-1;
+ //check the type of n
+ if( n.getKind()==INST_CONSTANT ){
+ int v = n.getAttribute(InstVarNumAttribute());
+ depIndex = ri->d_var_order[ v ];
+ val = ri->getTerm( v );
+ }else if( n.getKind()==ITE ){
+ int depIndex1, depIndex2;
+ int eval = evaluate( n[0], depIndex1, ri );
+ if( eval==0 ){
+ //evaluate children to see if they are the same
+ Node val1 = evaluateTerm( n[ 1 ], depIndex1, ri );
+ Node val2 = evaluateTerm( n[ 2 ], depIndex2, ri );
+ if( val1==val2 ){
+ val = val1;
+ depIndex = depIndex1>depIndex2 ? depIndex1 : depIndex2;
+ }else{
+ return Node::null();
+ }
+ }else{
+ val = evaluateTerm( n[ eval==1 ? 1 : 2 ], depIndex2, ri );
+ depIndex = depIndex1>depIndex2 ? depIndex1 : depIndex2;
+ }
+ }else{
+ std::vector< int > children_depIndex;
+ //for select, pre-process read over writes
+ if( n.getKind()==SELECT ){
#if 0
- out << "---Current Model---" << std::endl;
- out << "Representatives: " << std::endl;
- d_rep_set.toStream( out );
- out << "Functions: " << std::endl;
- for( std::map< Node, uf::UfModel >::iterator it = d_uf_model.begin(); it != d_uf_model.end(); ++it ){
- it->second.toStream( out );
- out << std::endl;
+ //std::cout << "Evaluate " << n << std::endl;
+ Node sel = evaluateTerm( n[1], depIndex, ri );
+ if( sel.isNull() ){
+ depIndex = ri->getNumTerms()-1;
+ return Node::null();
+ }
+ Node arr = getRepresentative( n[0] );
+ //if( n[0]!=getRepresentative( n[0] ) ){
+ // std::cout << n[0] << " is " << getRepresentative( n[0] ) << std::endl;
+ //}
+ int tempIndex;
+ int eval = 1;
+ while( arr.getKind()==STORE && eval!=0 ){
+ eval = evaluate( sel.eqNode( arr[1] ), tempIndex, ri );
+ depIndex = tempIndex > depIndex ? tempIndex : depIndex;
+ if( eval==1 ){
+ val = evaluateTerm( arr[2], tempIndex, ri );
+ depIndex = tempIndex > depIndex ? tempIndex : depIndex;
+ return val;
+ }else if( eval==-1 ){
+ arr = arr[0];
+ }
+ }
+ arr = evaluateTerm( arr, tempIndex, ri );
+ depIndex = tempIndex > depIndex ? tempIndex : depIndex;
+ val = NodeManager::currentNM()->mkNode( SELECT, arr, sel );
+#else
+ val = evaluateTermDefault( n, depIndex, children_depIndex, ri );
+#endif
+ }else{
+ //default term evaluate : evaluate all children, recreate the value
+ val = evaluateTermDefault( n, depIndex, children_depIndex, ri );
+ }
+ if( !val.isNull() ){
+ bool setVal = false;
+ //custom ways of evaluating terms
+ if( n.getKind()==APPLY_UF ){
+ Node op = n.getOperator();
+ //Debug("fmf-eval-debug") << "Evaluate term " << n << " (" << gn << ")" << std::endl;
+ //if it is a defined UF, then consult the interpretation
+ if( d_uf_model_tree.find( op )!=d_uf_model_tree.end() ){
+ ++d_eval_uf_terms;
+ int argDepIndex = 0;
+ //make the term model specifically for n
+ makeEvalUfModel( n );
+ //now, consult the model
+ if( d_eval_uf_use_default[n] ){
+ val = d_uf_model_tree[ op ].getValue( this, val, argDepIndex );
+ }else{
+ val = d_eval_uf_model[ n ].getValue( this, val, argDepIndex );
+ }
+ //Debug("fmf-eval-debug") << "Evaluate term " << n << " (" << gn << ")" << std::endl;
+ //d_eval_uf_model[ n ].debugPrint("fmf-eval-debug", d_qe );
+ Assert( !val.isNull() );
+ //recalculate the depIndex
+ depIndex = -1;
+ for( int i=0; i<argDepIndex; i++ ){
+ int index = d_eval_uf_use_default[n] ? i : d_eval_term_index_order[n][i];
+ Debug("fmf-eval-debug") << "Add variables from " << index << "..." << std::endl;
+ if( children_depIndex[index]>depIndex ){
+ depIndex = children_depIndex[index];
+ }
+ }
+ setVal = true;
+ }
+ }else if( n.getKind()==SELECT ){
+ //we are free to interpret this term however we want
+ }
+ //if not set already, rewrite and consult model for interpretation
+ if( !setVal ){
+ val = Rewriter::rewrite( val );
+ if( val.getMetaKind()!=kind::metakind::CONSTANT ){
+ //FIXME: we cannot do this until we trust all theories collectModelInfo!
+ //val = getInterpretedValue( val );
+ //val = getRepresentative( val );
+ }
+ }
+ Debug("fmf-eval-debug") << "Evaluate term " << n << " = ";
+ printRepresentativeDebug( "fmf-eval-debug", val );
+ Debug("fmf-eval-debug") << ", depIndex = " << depIndex << std::endl;
+ }
+ }
+ return val;
+ }
+}
+
+Node FirstOrderModel::evaluateTermDefault( Node n, int& depIndex, std::vector< int >& childDepIndex, RepSetIterator* ri ){
+ depIndex = -1;
+ if( n.getNumChildren()==0 ){
+ return n;
+ }else{
+ //first we must evaluate the arguments
+ std::vector< Node > children;
+ if( n.getMetaKind()==kind::metakind::PARAMETERIZED ){
+ children.push_back( n.getOperator() );
+ }
+ //for each argument, calculate its value, and the variables its value depends upon
+ for( int i=0; i<(int)n.getNumChildren(); i++ ){
+ childDepIndex.push_back( -1 );
+ Node nn = evaluateTerm( n[i], childDepIndex[i], ri );
+ if( nn.isNull() ){
+ depIndex = ri->getNumTerms()-1;
+ return nn;
+ }else{
+ children.push_back( nn );
+ if( childDepIndex[i]>depIndex ){
+ depIndex = childDepIndex[i];
+ }
+ }
+ }
+ //recreate the value
+ Node val = NodeManager::currentNM()->mkNode( n.getKind(), children );
+ return val;
+ }
+}
+
+void FirstOrderModel::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();
+}
+
+void FirstOrderModel::makeEvalUfModel( Node n ){
+ if( d_eval_uf_model.find( n )==d_eval_uf_model.end() ){
+ makeEvalUfIndexOrder( n );
+ if( !d_eval_uf_use_default[n] ){
+ Node op = n.getOperator();
+ d_eval_uf_model[n] = uf::UfModelTree( op, d_eval_term_index_order[n] );
+ d_uf_model_gen[op].makeModel( this, d_eval_uf_model[n] );
+ //Debug("fmf-index-order") << "Make model for " << n << " : " << std::endl;
+ //d_eval_uf_model[n].debugPrint( "fmf-index-order", d_qe, 2 );
+ }
}
-#elif 0
- d_rep_set.toStream( out );
- //print everything not related to UF in equality engine
- eq::EqClassesIterator eqcs_i = eq::EqClassesIterator( &d_equalityEngine );
- while( !eqcs_i.isFinished() ){
- Node eqc = (*eqcs_i);
- Node rep = getRepresentative( eqc );
- TypeNode type = rep.getType();
- eq::EqClassIterator eqc_i = eq::EqClassIterator( eqc, &d_equalityEngine );
- while( !eqc_i.isFinished() ){
- //do not print things that have interpretations in model
- if( !(*eqc_i).isConst() && !hasInterpretedValue( *eqc_i ) ){
- out << "(" << (*eqc_i) << " " << rep << ")" << std::endl;
+}
+
+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;
+ }
}
- ++eqc_i;
+ return maxVal;
+ }else{
+ return -1;
}
- ++eqcs_i;
}
- //print functions
- for( std::map< Node, uf::UfModel >::iterator it = d_uf_model.begin(); it != d_uf_model.end(); ++it ){
- it->second.toStream( out );
- out << std::endl;
+ 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 FirstOrderModel::makeEvalUfIndexOrder( Node n ){
+ if( d_eval_term_index_order.find( n )==d_eval_term_index_order.end() ){
+#ifdef USE_INDEX_ORDERING
+ //sort arguments in order of least significant vs. most significant variable in default ordering
+ std::map< Node, std::vector< int > > argIndex;
+ std::vector< Node > args;
+ for( int i=0; i<(int)n.getNumChildren(); i++ ){
+ if( argIndex.find( n[i] )==argIndex.end() ){
+ args.push_back( n[i] );
+ }
+ argIndex[n[i]].push_back( i );
+ }
+ sortGetMaxVariableNum sgmvn;
+ std::sort( args.begin(), args.end(), sgmvn );
+ for( int i=0; i<(int)args.size(); i++ ){
+ for( int j=0; j<(int)argIndex[ args[i] ].size(); j++ ){
+ d_eval_term_index_order[n].push_back( argIndex[ args[i] ][j] );
+ }
+ }
+ bool useDefault = true;
+ for( int i=0; i<(int)d_eval_term_index_order[n].size(); i++ ){
+ if( i!=d_eval_term_index_order[n][i] ){
+ useDefault = false;
+ break;
+ }
+ }
+ d_eval_uf_use_default[n] = useDefault;
+ Debug("fmf-index-order") << "Will consider the following index ordering for " << n << " : ";
+ for( int i=0; i<(int)d_eval_term_index_order[n].size(); i++ ){
+ Debug("fmf-index-order") << d_eval_term_index_order[n][i] << " ";
+ }
+ Debug("fmf-index-order") << std::endl;
+#else
+ d_eval_uf_use_default[n] = true;
#endif
+ }
}
class FirstOrderModel : public DefaultModel
{
private:
- //pointer to term database
- TermDb* d_term_db;
//add term function
void addTerm( Node n );
//for initialize model
void initializeModelForTerm( Node n );
- /** to stream functions */
- void toStreamFunction( Node n, std::ostream& out );
- void toStreamType( TypeNode tn, std::ostream& out );
+ /** whether an axiom is asserted */
+ context::CDO< bool > d_axiom_asserted;
+ /** list of quantifiers asserted in the current context */
+ context::CDList<Node> d_forall_asserts;
public: //for Theory UF:
//models for each UF operator
std::map< Node, uf::UfModelTree > d_uf_model_tree;
//model generators
std::map< Node, uf::UfModelTreeGenerator > d_uf_model_gen;
+private:
+ //map from terms to the models used to calculate their value
+ std::map< Node, bool > d_eval_uf_use_default;
+ std::map< Node, uf::UfModelTree > d_eval_uf_model;
+ void makeEvalUfModel( Node n );
+ //index ordering to use for each term
+ std::map< Node, std::vector< int > > d_eval_term_index_order;
+ void makeEvalUfIndexOrder( Node n );
public: //for Theory Arrays:
//default value for each non-store array
std::map< Node, arrays::ArrayModel > d_array_model;
public: //for Theory Quantifiers:
- /** list of quantifiers asserted in the current context */
- context::CDList<Node> d_forall_asserts;
+ /** assert quantifier */
+ void assertQuantifier( Node n );
/** 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]; }
+ /** bool axiom asserted */
+ bool isAxiomAsserted() { return d_axiom_asserted; }
public:
- FirstOrderModel( QuantifiersEngine* qe, context::Context* c, std::string name );
+ FirstOrderModel( context::Context* c, std::string name );
virtual ~FirstOrderModel(){}
// reset the model
void reset();
Node getInterpretedValue( TNode n );
public:
// initialize the model
- void initialize();
- /** get term database */
- TermDb* getTermDatabase();
+ void initialize( bool considerAxioms = true );
/** to stream function */
void toStream( std::ostream& out );
+
+//the following functions are for evaluating quantifier bodies
+public:
+ /** reset evaluation */
+ void resetEvaluate();
+ /** evaluate functions */
+ int evaluate( Node n, int& depIndex, RepSetIterator* ri );
+ Node evaluateTerm( Node n, int& depIndex, RepSetIterator* ri );
+public:
+ //statistics
+ int d_eval_formulas;
+ int d_eval_uf_terms;
+ int d_eval_lits;
+ int d_eval_lits_unknown;
+private:
+ //default evaluate term function
+ Node evaluateTermDefault( Node n, int& depIndex, std::vector< int >& childDepIndex, RepSetIterator* ri );
+ //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;
};/* class FirstOrderModel */
}/* CVC4::theory::quantifiers namespace */
}
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] ] );
+ if( d_map.find( vars[i] )!=d_map.end() && !d_map[ vars[i] ].isNull() ){
+ match.push_back( d_map[ vars[i] ] );
+ }
}
}
}
if( modEq ){
//check modulo equality if any other instantiation match exists
- if( qe->getEqualityQuery()->getEngine()->hasTerm( n ) ){
+ if( !n.isNull() && qe->getEqualityQuery()->getEngine()->hasTerm( n ) ){
eq::EqClassIterator eqc( qe->getEqualityQuery()->getEngine()->getRepresentative( n ),
qe->getEqualityQuery()->getEngine() );
while( !eqc.isFinished() ){
++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;
}
+++ /dev/null
-/********************* */
-/*! \file inst_when_mode.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-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 [[ Add one-line brief description here ]]
- **
- ** [[ Add lengthier description here ]]
- ** \todo document this file
- **/
-
-#include <iostream>
-#include "theory/quantifiers/inst_when_mode.h"
-
-namespace CVC4 {
-
-std::ostream& operator<<(std::ostream& out, theory::quantifiers::InstWhenMode mode) {
- switch(mode) {
- case theory::quantifiers::INST_WHEN_PRE_FULL:
- out << "INST_WHEN_PRE_FULL";
- break;
- case theory::quantifiers::INST_WHEN_FULL:
- out << "INST_WHEN_FULL";
- break;
- case theory::quantifiers::INST_WHEN_FULL_LAST_CALL:
- out << "INST_WHEN_FULL_LAST_CALL";
- break;
- case theory::quantifiers::INST_WHEN_LAST_CALL:
- out << "INST_WHEN_LAST_CALL";
- break;
- default:
- out << "InstWhenMode!UNKNOWN";
- }
-
- return out;
-}
-
-}/* CVC4 namespace */
-
+++ /dev/null
-/********************* */
-/*! \file inst_when_mode.h
- ** \verbatim
- ** Original author: mdeters
- ** Major contributors: none
- ** Minor contributors (to current version): none
- ** This file is part of the CVC4 prototype.
- ** 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
- ** information.\endverbatim
- **
- ** \brief [[ Add one-line brief description here ]]
- **
- ** [[ Add lengthier description here ]]
- ** \todo document this file
- **/
-
-#include "cvc4_private.h"
-
-#ifndef __CVC4__THEORY__QUANTIFIERS__INST_WHEN_MODE_H
-#define __CVC4__THEORY__QUANTIFIERS__INST_WHEN_MODE_H
-
-#include <iostream>
-
-namespace CVC4 {
-namespace theory {
-namespace quantifiers {
-
-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;
-
-}/* CVC4::theory::quantifiers namespace */
-}/* CVC4::theory namespace */
-
-std::ostream& operator<<(std::ostream& out, theory::quantifiers::InstWhenMode mode) CVC4_PUBLIC;
-
-}/* CVC4 namespace */
-
-#endif /* __CVC4__THEORY__QUANTIFIERS__INST_WHEN_MODE_H */
}
}
}
+
+Node InstantiationEngine::getNextDecisionRequest(){
+ //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_quantEngine->getValuation().hasSatValue( it->second, value ) ){
+ //if not already set, propagate as decision
+ Debug("cbqi-prop-as-dec") << "CBQI: propagate as decision " << it->second << std::endl;
+ return it->second;
+ }
+ }
+ return Node::null();
+}
\ No newline at end of file
void assertNode( Node f );
Node explain(TNode n){ return Node::null(); }
void propagate( Theory::Effort level );
+ Node getNextDecisionRequest();
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 ]; }
typechecker "theory/quantifiers/theory_quantifiers_type_rules.h"
instantiator ::CVC4::theory::quantifiers::InstantiatorTheoryQuantifiers "theory/quantifiers/theory_quantifiers_instantiator.h"
-properties check propagate presolve
+properties check propagate presolve getNextDecisionRequest
rewriter ::CVC4::theory::quantifiers::QuantifiersRewriter "theory/quantifiers/quantifiers_rewriter.h"
not-well-founded \
"Instantiation pattern type"
+# Instantiation pattern, also called trigger.
+# This node is used for specifying hints for quantifier instantiation.
+# An instantiation pattern may have more than 1 child, in which case it specifies a multi-trigger.
operator INST_PATTERN 1: "instantiation pattern"
sort INST_PATTERN_LIST_TYPE \
not-well-founded \
"Instantiation pattern list type"
+# a list of instantiation patterns
operator INST_PATTERN_LIST 1: "instantiation pattern list"
typerule FORALL ::CVC4::theory::quantifiers::QuantifierForallTypeRule
+++ /dev/null
-/********************* */
-/*! \file literal_match_mode.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-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 [[ Add one-line brief description here ]]
- **
- ** [[ Add lengthier description here ]]
- ** \todo document this file
- **/
-
-#include <iostream>
-#include "theory/quantifiers/literal_match_mode.h"
-
-namespace CVC4 {
-
-std::ostream& operator<<(std::ostream& out, theory::quantifiers::LiteralMatchMode mode) {
- switch(mode) {
- case theory::quantifiers::LITERAL_MATCH_NONE:
- out << "LITERAL_MATCH_NONE";
- break;
- case theory::quantifiers::LITERAL_MATCH_PREDICATE:
- out << "LITERAL_MATCH_PREDICATE";
- break;
- case theory::quantifiers::LITERAL_MATCH_EQUALITY:
- out << "LITERAL_MATCH_EQUALITY";
- break;
- default:
- out << "LiteralMatchMode!UNKNOWN";
- }
-
- return out;
-}
-
-}/* CVC4 namespace */
+++ /dev/null
-/********************* */
-/*! \file literal_match_mode.h
- ** \verbatim
- ** Original author: mdeters
- ** Major contributors: none
- ** Minor contributors (to current version): none
- ** This file is part of the CVC4 prototype.
- ** 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
- ** information.\endverbatim
- **
- ** \brief [[ Add one-line brief description here ]]
- **
- ** [[ Add lengthier description here ]]
- ** \todo document this file
- **/
-
-#include "cvc4_private.h"
-
-#ifndef __CVC4__THEORY__QUANTIFIERS__LITERAL_MATCH_MODE_H
-#define __CVC4__THEORY__QUANTIFIERS__LITERAL_MATCH_MODE_H
-
-#include <iostream>
-
-namespace CVC4 {
-namespace theory {
-namespace quantifiers {
-
-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;
-
-}/* CVC4::theory::quantifiers namespace */
-}/* CVC4::theory namespace */
-
-std::ostream& operator<<(std::ostream& out, theory::quantifiers::LiteralMatchMode mode) CVC4_PUBLIC;
-
-}/* CVC4 namespace */
-
-#endif /* __CVC4__THEORY__QUANTIFIERS__LITERAL_MATCH_MODE_H */
#include "theory/uf/theory_uf.h"
#include "theory/uf/theory_uf_model.h"
#include "theory/uf/theory_uf_instantiator.h"
+#include "theory/uf/theory_uf_strong_solver.h"
#include "theory/arrays/theory_arrays_model.h"
#include "theory/quantifiers/first_order_model.h"
#include "theory/quantifiers/term_database.h"
#include "theory/quantifiers/model_builder.h"
-
-//#define ME_PRINT_WARNINGS
+#include "theory/quantifiers/quantifiers_attributes.h"
#define RECONSIDER_FUNC_CONSTANT
-//#define ONE_QUANT_PER_ROUND_INST_GEN
using namespace std;
using namespace CVC4;
using namespace CVC4::theory;
using namespace CVC4::theory::quantifiers;
-ModelEngineBuilder::ModelEngineBuilder( QuantifiersEngine* qe ) :
+ModelEngineBuilder::ModelEngineBuilder( context::Context* c, QuantifiersEngine* qe ) :
TheoryEngineModelBuilder( qe->getTheoryEngine() ),
-d_qe( qe ){
-
+d_qe( qe ), d_curr_model( c, NULL ){
+ d_considerAxioms = true;
}
-Node ModelEngineBuilder::chooseRepresentative( TheoryModel* m, Node eqc ){
- Assert( m->d_equalityEngine.hasTerm( eqc ) );
- Assert( m->d_equalityEngine.getRepresentative( eqc )==eqc );
- //avoid interpreted symbols
- if( isBadRepresentative( eqc ) ){
- eq::EqClassIterator eqc_i = eq::EqClassIterator( eqc, &m->d_equalityEngine );
- while( !eqc_i.isFinished() ){
- if( !isBadRepresentative( *eqc_i ) ){
- return *eqc_i;
+Node ModelEngineBuilder::chooseRepresentative( TheoryModel* m, Node eqc, bool fullModel ){
+ if( fullModel ){
+ return TheoryEngineModelBuilder::chooseRepresentative( m, eqc, fullModel );
+ }else{
+ Assert( m->d_equalityEngine.hasTerm( eqc ) );
+ Assert( m->d_equalityEngine.getRepresentative( eqc )==eqc );
+ //avoid bad representatives
+ if( isBadRepresentative( eqc ) ){
+ eq::EqClassIterator eqc_i = eq::EqClassIterator( eqc, &m->d_equalityEngine );
+ while( !eqc_i.isFinished() ){
+ if( !isBadRepresentative( *eqc_i ) ){
+ return *eqc_i;
+ }
+ ++eqc_i;
}
- ++eqc_i;
+ //otherwise, make new value?
+ //Message() << "Warning: Bad rep " << eqc << std::endl;
}
- //otherwise, make new value?
- //Message() << "Warning: Bad rep " << eqc << std::endl;
+ return eqc;
}
- return eqc;
}
bool ModelEngineBuilder::isBadRepresentative( Node n ){
+ //avoid interpreted symbols
return n.getKind()==SELECT || n.getKind()==APPLY_SELECTOR;
}
-void ModelEngineBuilder::processBuildModel( TheoryModel* m ) {
- d_addedLemmas = 0;
- //only construct first order model if optUseModel() is true
- if( optUseModel() ){
- FirstOrderModel* fm = (FirstOrderModel*)m;
- //initialize model
- fm->initialize();
- //analyze the functions
- analyzeModel( fm );
- //analyze the quantifiers
- Debug("fmf-model-debug") << "Analyzing quantifiers..." << std::endl;
- analyzeQuantifiers( fm );
- //if applicable, find exceptions
- if( optInstGen() ){
- //now, see if we know that any exceptions via InstGen exist
- Debug("fmf-model-debug") << "Perform InstGen techniques for quantifiers..." << std::endl;
- for( int i=0; i<fm->getNumAssertedQuantifiers(); i++ ){
- Node f = fm->getAssertedQuantifier( i );
- if( d_quant_sat.find( f )==d_quant_sat.end() ){
- d_addedLemmas += doInstGen( fm, f );
- if( optOneQuantPerRoundInstGen() && d_addedLemmas>0 ){
- break;
+void ModelEngineBuilder::processBuildModel( TheoryModel* m, bool fullModel ) {
+ FirstOrderModel* fm = (FirstOrderModel*)m;
+ if( fullModel ){
+ Assert( d_curr_model==fm );
+ //update models
+ for( std::map< Node, uf::UfModelTree >::iterator it = fm->d_uf_model_tree.begin(); it != fm->d_uf_model_tree.end(); ++it ){
+ it->second.update( fm );
+ }
+
+ }else{
+ d_curr_model = fm;
+ //build model for relevant symbols contained in quantified formulas
+ d_addedLemmas = 0;
+ //only construct first order model if optUseModel() is true
+ if( optUseModel() ){
+ //initialize model
+ fm->initialize( d_considerAxioms );
+ //analyze the functions
+ Trace("model-engine-debug") << "Analyzing model..." << std::endl;
+ analyzeModel( fm );
+ //analyze the quantifiers
+ Trace("model-engine-debug") << "Analyzing quantifiers..." << std::endl;
+ analyzeQuantifiers( fm );
+ //if applicable, find exceptions
+ if( optInstGen() ){
+ //now, see if we know that any exceptions via InstGen exist
+ Trace("model-engine-debug") << "Perform InstGen techniques for quantifiers..." << std::endl;
+ for( int i=0; i<fm->getNumAssertedQuantifiers(); i++ ){
+ Node f = fm->getAssertedQuantifier( i );
+ if( isQuantifierActive( f ) ){
+ d_addedLemmas += doInstGen( fm, f );
+ if( optOneQuantPerRoundInstGen() && d_addedLemmas>0 ){
+ break;
+ }
}
}
- }
- if( Trace.isOn("model-engine") ){
- if( d_addedLemmas>0 ){
- Trace("model-engine") << "InstGen, added lemmas = " << d_addedLemmas << std::endl;
- }else{
- Trace("model-engine") << "No InstGen lemmas..." << std::endl;
+ if( Trace.isOn("model-engine") ){
+ if( d_addedLemmas>0 ){
+ Trace("model-engine") << "InstGen, added lemmas = " << d_addedLemmas << std::endl;
+ }else{
+ Trace("model-engine") << "No InstGen lemmas..." << std::endl;
+ }
}
}
- Debug("fmf-model-debug") << "---> Added lemmas = " << d_addedLemmas << std::endl;
- }
- if( d_addedLemmas==0 ){
- //if no immediate exceptions, build the model
- // this model will be an approximation that will need to be tested via exhaustive instantiation
- Debug("fmf-model-debug") << "Building model..." << std::endl;
- finishBuildModel( fm );
+ if( d_addedLemmas==0 ){
+ //if no immediate exceptions, build the model
+ // this model will be an approximation that will need to be tested via exhaustive instantiation
+ Trace("model-engine-debug") << "Building model..." << std::endl;
+ constructModel( fm );
+ }
}
}
}
void ModelEngineBuilder::analyzeModel( FirstOrderModel* fm ){
+ d_uf_model_constructed.clear();
//determine if any functions are constant
for( std::map< Node, uf::UfModelTree >::iterator it = fm->d_uf_model_tree.begin(); it != fm->d_uf_model_tree.end(); ++it ){
Node op = it->first;
}
void ModelEngineBuilder::analyzeQuantifiers( FirstOrderModel* fm ){
- d_quant_selection_lits.clear();
d_quant_sat.clear();
+ d_quant_selection_lit.clear();
+ d_quant_selection_lit_candidates.clear();
+ d_quant_selection_lit_terms.clear();
+ d_term_selection_lit.clear();
+ d_op_selection_terms.clear();
d_uf_prefs.clear();
int quantSatInit = 0;
int nquantSatInit = 0;
//analyze the preferences of each quantifier
for( int i=0; i<(int)fm->getNumAssertedQuantifiers(); i++ ){
Node f = fm->getAssertedQuantifier( i );
- Debug("fmf-model-prefs") << "Analyze quantifier " << f << std::endl;
- std::vector< Node > pro_con[2];
- std::vector< Node > constantSatOps;
- bool constantSatReconsider;
- //for each asserted quantifier f,
- // - determine which literals form model basis for each quantifier
- // - check which function/predicates have good and bad definitions according to f
- for( std::map< Node, bool >::iterator it = d_qe->d_phase_reqs[f].begin();
- it != d_qe->d_phase_reqs[f].end(); ++it ){
- Node n = it->first;
- Node gn = d_qe->getTermDatabase()->getModelBasis( n );
- Debug("fmf-model-req") << " Req: " << n << " -> " << it->second << std::endl;
- //calculate preference
- int pref = 0;
- bool value;
- if( d_qe->getValuation().hasSatValue( gn, value ) ){
- if( value!=it->second ){
- //store this literal as a model basis literal
- // this literal will force a default values in model that (modulo exceptions) shows
- // that f is satisfied by the model
- d_quant_selection_lits[f].push_back( value ? n : n.notNode() );
- pref = 1;
- }else{
- pref = -1;
- }
- }
- if( pref!=0 ){
- //Store preferences for UF
- bool isConst = !n.hasAttribute(InstConstantAttribute());
- std::vector< Node > uf_terms;
- if( gn.getKind()==APPLY_UF ){
- uf_terms.push_back( gn );
- isConst = !d_uf_prefs[gn.getOperator()].d_const_val.isNull();
- }else if( gn.getKind()==EQUAL ){
- isConst = true;
- for( int j=0; j<2; j++ ){
- if( n[j].hasAttribute(InstConstantAttribute()) ){
- if( n[j].getKind()==APPLY_UF ){
- Node op = gn[j].getOperator();
- if( fm->d_uf_model_tree.find( op )!=fm->d_uf_model_tree.end() ){
- uf_terms.push_back( gn[j] );
- isConst = isConst && !d_uf_prefs[op].d_const_val.isNull();
- }else{
- isConst = false;
+ if( isQuantifierActive( f ) ){
+ Debug("fmf-model-prefs") << "Analyze quantifier " << f << std::endl;
+ //the pro/con preferences for this quantifier
+ std::vector< Node > pro_con[2];
+ //the terms in the selection literal we choose
+ std::vector< Node > selectionLitTerms;
+ //for each asserted quantifier f,
+ // - determine selection literals
+ // - check which function/predicates have good and bad definitions for satisfying f
+ for( std::map< Node, bool >::iterator it = d_qe->d_phase_reqs[f].begin();
+ it != d_qe->d_phase_reqs[f].end(); ++it ){
+ //the literal n is phase-required for quantifier f
+ Node n = it->first;
+ Node gn = d_qe->getTermDatabase()->getModelBasis( n );
+ Debug("fmf-model-req") << " Req: " << n << " -> " << it->second << std::endl;
+ bool value;
+ //if the corresponding ground abstraction literal has a SAT value
+ if( d_qe->getValuation().hasSatValue( gn, value ) ){
+ //collect the non-ground uf terms that this literal contains
+ // and compute if all of the symbols in this literal have
+ // constant definitions.
+ bool isConst = true;
+ std::vector< Node > uf_terms;
+ if( n.hasAttribute(InstConstantAttribute()) ){
+ isConst = false;
+ if( gn.getKind()==APPLY_UF ){
+ uf_terms.push_back( gn );
+ isConst = !d_uf_prefs[gn.getOperator()].d_const_val.isNull();
+ }else if( gn.getKind()==EQUAL ){
+ isConst = true;
+ for( int j=0; j<2; j++ ){
+ if( n[j].hasAttribute(InstConstantAttribute()) ){
+ if( n[j].getKind()==APPLY_UF &&
+ fm->d_uf_model_tree.find( gn[j].getOperator() )!=fm->d_uf_model_tree.end() ){
+ uf_terms.push_back( gn[j] );
+ isConst = isConst && !d_uf_prefs[ gn[j].getOperator() ].d_const_val.isNull();
+ }else{
+ isConst = false;
+ }
}
- }else{
- isConst = false;
}
}
}
- }
- Debug("fmf-model-prefs") << " It is " << ( pref==1 ? "pro" : "con" );
- Debug("fmf-model-prefs") << " the definition of " << n << std::endl;
- if( pref==1 && isConst ){
- d_quant_sat[f] = true;
- //instead, just note to the model for each uf term that f is pro its definition
- constantSatReconsider = false;
- constantSatOps.clear();
- for( int j=0; j<(int)uf_terms.size(); j++ ){
- Node op = uf_terms[j].getOperator();
- constantSatOps.push_back( op );
- if( d_uf_prefs[op].d_reconsiderModel ){
- constantSatReconsider = true;
+ //check if the value in the SAT solver matches the preference according to the quantifier
+ int pref = 0;
+ if( value!=it->second ){
+ //we have a possible selection literal
+ bool selectLit = d_quant_selection_lit[f].isNull();
+ bool selectLitConstraints = true;
+ //it is a constantly defined selection literal : the quantifier is sat
+ if( isConst ){
+ selectLit = selectLit || d_quant_sat.find( f )==d_quant_sat.end();
+ d_quant_sat[f] = true;
+ //check if choosing this literal would add any additional constraints to default definitions
+ selectLitConstraints = false;
+ for( int j=0; j<(int)uf_terms.size(); j++ ){
+ Node op = uf_terms[j].getOperator();
+ if( d_uf_prefs[op].d_reconsiderModel ){
+ selectLitConstraints = true;
+ }
+ }
+ if( !selectLitConstraints ){
+ selectLit = true;
+ }
}
+ //see if we wish to choose this as a selection literal
+ d_quant_selection_lit_candidates[f].push_back( value ? n : n.notNode() );
+ if( selectLit ){
+ Trace("inst-gen-debug") << "Choose selection literal " << gn << std::endl;
+ d_quant_selection_lit[f] = value ? n : n.notNode();
+ selectionLitTerms.clear();
+ selectionLitTerms.insert( selectionLitTerms.begin(), uf_terms.begin(), uf_terms.end() );
+ if( !selectLitConstraints ){
+ break;
+ }
+ }
+ pref = 1;
+ }else{
+ pref = -1;
}
- if( !constantSatReconsider ){
- 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] );
+ //if we are not yet SAT, so we will add to preferences
+ if( d_quant_sat.find( f )==d_quant_sat.end() ){
+ Debug("fmf-model-prefs") << " It is " << ( pref==1 ? "pro" : "con" );
+ Debug("fmf-model-prefs") << " the definition of " << n << std::endl;
+ for( int j=0; j<(int)uf_terms.size(); j++ ){
+ pro_con[ pref==1 ? 0 : 1 ].push_back( uf_terms[j] );
+ }
}
}
}
- }
- if( d_quant_sat.find( f )!=d_quant_sat.end() ){
- Debug("fmf-model-prefs") << " * Constant SAT due to definition of ops: ";
- for( int i=0; i<(int)constantSatOps.size(); i++ ){
- Debug("fmf-model-prefs") << constantSatOps[i] << " ";
- d_uf_prefs[constantSatOps[i]].d_reconsiderModel = false;
+ //process information about selection literal for f
+ if( !d_quant_selection_lit[f].isNull() ){
+ d_quant_selection_lit_terms[f].insert( d_quant_selection_lit_terms[f].begin(), selectionLitTerms.begin(), selectionLitTerms.end() );
+ for( int i=0; i<(int)selectionLitTerms.size(); i++ ){
+ d_term_selection_lit[ selectionLitTerms[i] ] = d_quant_selection_lit[f];
+ d_op_selection_terms[ selectionLitTerms[i].getOperator() ].push_back( selectionLitTerms[i] );
+ }
+ }else{
+ Trace("inst-gen-warn") << "WARNING: " << f << " has no selection literals (is the body of f clausified?)" << std::endl;
}
- Debug("fmf-model-prefs") << std::endl;
- quantSatInit++;
- d_statistics.d_pre_sat_quant += quantSatInit;
- }else{
- nquantSatInit++;
- d_statistics.d_pre_nsat_quant += quantSatInit;
- //note quantifier's value preferences to models
- for( int k=0; k<2; k++ ){
- for( int j=0; j<(int)pro_con[k].size(); j++ ){
- Node op = pro_con[k][j].getOperator();
- Node r = fm->getRepresentative( pro_con[k][j] );
- d_uf_prefs[op].setValuePreference( f, pro_con[k][j], r, k==0 );
+ //process information about requirements and preferences of quantifier f
+ if( d_quant_sat.find( f )!=d_quant_sat.end() ){
+ Debug("fmf-model-prefs") << " * Constant SAT due to definition of ops: ";
+ for( int i=0; i<(int)selectionLitTerms.size(); i++ ){
+ Debug("fmf-model-prefs") << selectionLitTerms[i] << " ";
+ d_uf_prefs[ selectionLitTerms[i].getOperator() ].d_reconsiderModel = false;
+ }
+ Debug("fmf-model-prefs") << std::endl;
+ quantSatInit++;
+ ++(d_statistics.d_pre_sat_quant);
+ }else{
+ nquantSatInit++;
+ ++(d_statistics.d_pre_nsat_quant);
+ //note quantifier's value preferences to models
+ for( int k=0; k<2; k++ ){
+ for( int j=0; j<(int)pro_con[k].size(); j++ ){
+ Node op = pro_con[k][j].getOperator();
+ Node r = fm->getRepresentative( pro_con[k][j] );
+ d_uf_prefs[op].setValuePreference( f, pro_con[k][j], r, k==0 );
+ }
}
}
}
}
int ModelEngineBuilder::doInstGen( FirstOrderModel* fm, Node f ){
- //we wish to add all known exceptions to our model basis literal(s)
- // this will help to refine our current model.
+ int addedLemmas = 0;
+ //we wish to add all known exceptions to our selection literal for f. this will help to refine our current model.
//This step is advantageous over exhaustive instantiation, since we are adding instantiations that involve model basis terms,
// effectively acting as partial instantiations instead of pointwise instantiations.
- int addedLemmas = 0;
- for( int i=0; i<(int)d_quant_selection_lits[f].size(); i++ ){
- bool phase = d_quant_selection_lits[f][i].getKind()!=NOT;
- Node lit = d_quant_selection_lits[f][i].getKind()==NOT ? d_quant_selection_lits[f][i][0] : d_quant_selection_lits[f][i];
+ if( !d_quant_selection_lit[f].isNull() ){
+#if 0
+ bool phase = d_quant_selection_lit[f].getKind()!=NOT;
+ Node lit = d_quant_selection_lit[f].getKind()==NOT ? d_quant_selection_lit[f][0] : d_quant_selection_lit[f];
Assert( lit.hasAttribute(InstConstantAttribute()) );
- std::vector< Node > tr_terms;
- if( lit.getKind()==APPLY_UF ){
- //only match predicates that are contrary to this one, use literal matching
- Node eq = NodeManager::currentNM()->mkNode( IFF, lit, !phase ? fm->d_true : fm->d_false );
- fm->getTermDatabase()->setInstantiationConstantAttr( eq, f );
- tr_terms.push_back( eq );
- }else if( lit.getKind()==EQUAL ){
- //collect trigger terms
- for( int j=0; j<2; j++ ){
- if( lit[j].hasAttribute(InstConstantAttribute()) ){
- if( lit[j].getKind()==APPLY_UF ){
- tr_terms.push_back( lit[j] );
- }else{
- tr_terms.clear();
- break;
- }
+ for( size_t i=0; i<d_quant_selection_lit_terms[f].size(); i++ ){
+ Node n1 = d_quant_selection_lit_terms[f][i];
+ Node op = d_quant_selection_lit_terms[f][i].getOperator();
+ //check all other selection literals involving "op"
+ for( size_t i=0; i<d_op_selection_terms[op].size(); i++ ){
+ Node n2 = d_op_selection_terms[op][i];
+ Node n2_lit = d_term_selection_lit[ n2 ];
+ if( n2_lit!=d_quant_selection_lit[f] ){
+ //match n1 and n2
}
}
- if( tr_terms.size()==1 && !phase ){
- //equality between a function and a ground term, use literal matching
- tr_terms.clear();
- tr_terms.push_back( lit );
+ if( addedLemmas==0 ){
+ //check all ground terms involving "op"
+ for( size_t i=0; i<fm->d_uf_terms[op].size(); i++ ){
+ Node n2 = fm->d_uf_terms[op][i];
+ if( n1!=n2 ){
+ //match n1 and n2
+ }
+ }
}
}
- //if applicable, try to add exceptions here
- if( !tr_terms.empty() ){
- //make a trigger for these terms, add instantiations
- inst::Trigger* tr = inst::Trigger::mkTrigger( d_qe, f, tr_terms );
- //Notice() << "Trigger = " << (*tr) << std::endl;
- tr->resetInstantiationRound();
- tr->reset( Node::null() );
- //d_qe->d_optInstMakeRepresentative = false;
- //d_qe->d_optMatchIgnoreModelBasis = true;
- addedLemmas += tr->addInstantiations( d_quant_basis_match[f] );
+#else
+ Trace("inst-gen") << "Do Inst-Gen for " << f << std::endl;
+ for( size_t i=0; i<d_quant_selection_lit_candidates[f].size(); i++ ){
+ bool phase = d_quant_selection_lit_candidates[f][i].getKind()!=NOT;
+ Node lit = d_quant_selection_lit_candidates[f][i].getKind()==NOT ? d_quant_selection_lit_candidates[f][i][0] : d_quant_selection_lit_candidates[f][i];
+ Assert( lit.hasAttribute(InstConstantAttribute()) );
+ std::vector< Node > tr_terms;
+ if( lit.getKind()==APPLY_UF ){
+ //only match predicates that are contrary to this one, use literal matching
+ Node eq = NodeManager::currentNM()->mkNode( IFF, lit, !phase ? fm->d_true : fm->d_false );
+ d_qe->getTermDatabase()->setInstantiationConstantAttr( eq, f );
+ tr_terms.push_back( eq );
+ }else if( lit.getKind()==EQUAL ){
+ //collect trigger terms
+ for( int j=0; j<2; j++ ){
+ if( lit[j].hasAttribute(InstConstantAttribute()) ){
+ if( lit[j].getKind()==APPLY_UF ){
+ tr_terms.push_back( lit[j] );
+ }else{
+ tr_terms.clear();
+ break;
+ }
+ }
+ }
+ if( tr_terms.size()==1 && !phase ){
+ //equality between a function and a ground term, use literal matching
+ tr_terms.clear();
+ tr_terms.push_back( lit );
+ }
+ }
+ //if applicable, try to add exceptions here
+ if( !tr_terms.empty() ){
+ //make a trigger for these terms, add instantiations
+ inst::Trigger* tr = inst::Trigger::mkTrigger( d_qe, f, tr_terms );
+ //Notice() << "Trigger = " << (*tr) << std::endl;
+ tr->resetInstantiationRound();
+ tr->reset( Node::null() );
+ //d_qe->d_optInstMakeRepresentative = false;
+ //d_qe->d_optMatchIgnoreModelBasis = true;
+ addedLemmas += tr->addInstantiations( d_quant_basis_match[f] );
+ }
}
+#endif
}
return addedLemmas;
}
-void ModelEngineBuilder::finishBuildModel( FirstOrderModel* fm ){
+void ModelEngineBuilder::constructModel( FirstOrderModel* fm ){
//build model for UF
for( std::map< Node, uf::UfModelTree >::iterator it = fm->d_uf_model_tree.begin(); it != fm->d_uf_model_tree.end(); ++it ){
- finishBuildModelUf( fm, it->first );
+ constructModelUf( fm, it->first );
}
/*
//build model for arrays
it->second.setDefaultValue( fm->getRepresentative( selModelBasis ) );
}
*/
- Debug("fmf-model-debug") << "Done building models." << std::endl;
+ Trace("model-engine-debug") << "Done building models." << std::endl;
}
-void ModelEngineBuilder::finishBuildModelUf( FirstOrderModel* fm, Node op ){
+void ModelEngineBuilder::constructModelUf( FirstOrderModel* fm, Node op ){
#ifdef RECONSIDER_FUNC_CONSTANT
if( d_uf_model_constructed[op] ){
if( d_uf_prefs[op].d_reconsiderModel ){
//set the values in the model
for( size_t i=0; i<fm->d_uf_terms[op].size(); i++ ){
Node n = fm->d_uf_terms[op][i];
- fm->getTermDatabase()->computeModelBasisArgAttribute( n );
+ d_qe->getTermDatabase()->computeModelBasisArgAttribute( n );
if( !n.getAttribute(NoMatchAttribute()) || n.getAttribute(ModelBasisArgAttribute())==1 ){
Node v = fm->getRepresentative( n );
//if this assertion did not help the model, just consider it ground
}
}
-void ModelEngineBuilder::finishProcessBuildModel( TheoryModel* m ){
- for( std::map< Node, Node >::iterator it = m->d_reps.begin(); it != m->d_reps.end(); ++it ){
- //build proper representatives (TODO)
- }
-}
-
bool ModelEngineBuilder::optUseModel() {
return options::fmfModelBasedInst();
}
}
bool ModelEngineBuilder::optOneQuantPerRoundInstGen(){
-#ifdef ONE_QUANT_PER_ROUND_INST_GEN
- return true;
-#else
- return false;
-#endif
+ return options::fmfInstGenOneQuantPerRound();
+}
+
+void ModelEngineBuilder::setEffort( int effort ){
+ d_considerAxioms = effort>=1;
}
ModelEngineBuilder::Statistics::Statistics():
StatisticsRegistry::unregisterStat(&d_pre_sat_quant);
StatisticsRegistry::unregisterStat(&d_pre_nsat_quant);
}
+
+bool ModelEngineBuilder::isQuantifierActive( Node f ){
+ return ( d_considerAxioms || !f.getAttribute(AxiomAttribute()) ) && d_quant_sat.find( f )==d_quant_sat.end();
+}
namespace theory {
namespace quantifiers {
-//the model builder
+/** model builder class
+ * This class is capable of building candidate models based on the current quantified formulas
+ * that are asserted. Use:
+ * (1) call ModelEngineBuilder::buildModel( m, false );, where m is a FirstOrderModel
+ * (2) if candidate model is determined to be a real model,
+ then call ModelEngineBuilder::buildModel( m, true );
+ */
class ModelEngineBuilder : public TheoryEngineModelBuilder
{
protected:
//quantifiers engine
QuantifiersEngine* d_qe;
+ //the model we are working with
+ context::CDO< FirstOrderModel* > d_curr_model;
//map from operators to model preference data
std::map< Node, uf::UfModelPreferenceData > d_uf_prefs;
//built model uf
std::map< Node, bool > d_uf_model_constructed;
+protected:
/** process build model */
- void processBuildModel( TheoryModel* m );
+ void processBuildModel( TheoryModel* m, bool fullModel );
/** choose representative for unconstrained equivalence class */
- Node chooseRepresentative( TheoryModel* m, Node eqc );
+ Node chooseRepresentative( TheoryModel* m, Node eqc, bool fullModel );
/** bad representative */
bool isBadRepresentative( Node n );
protected:
//analyze quantifiers
void analyzeQuantifiers( FirstOrderModel* fm );
//build model
- void finishBuildModel( FirstOrderModel* fm );
+ void constructModel( FirstOrderModel* fm );
//theory-specific build models
- void finishBuildModelUf( FirstOrderModel* fm, Node op );
+ void constructModelUf( FirstOrderModel* fm, Node op );
//do InstGen techniques for quantifier, return number of lemmas produced
int doInstGen( FirstOrderModel* fm, Node f );
public:
- ModelEngineBuilder( QuantifiersEngine* qe );
+ ModelEngineBuilder( context::Context* c, QuantifiersEngine* qe );
virtual ~ModelEngineBuilder(){}
- /** finish model */
- void finishProcessBuildModel( TheoryModel* m );
-public:
/** number of lemmas generated while building model */
int d_addedLemmas;
+ //consider axioms
+ bool d_considerAxioms;
+private: ///information for InstGen
//map from quantifiers to if are constant SAT
std::map< Node, bool > d_quant_sat;
- //map from quantifiers to the instantiation literals that their model is dependent upon
- std::map< Node, std::vector< Node > > d_quant_selection_lits;
+ //map from quantifiers to their selection literals
+ std::map< Node, Node > d_quant_selection_lit;
+ std::map< Node, std::vector< Node > > d_quant_selection_lit_candidates;
+ //map from quantifiers to their selection literal terms
+ std::map< Node, std::vector< Node > > d_quant_selection_lit_terms;
+ //map from terms to the selection literals they exist in
+ std::map< Node, Node > d_term_selection_lit;
+ //map from operators to terms that appear in selection literals
+ std::map< Node, std::vector< Node > > d_op_selection_terms;
public:
//map from quantifiers to model basis match
std::map< Node, InstMatch > d_quant_basis_match;
bool optUseModel();
bool optInstGen();
bool optOneQuantPerRoundInstGen();
+ // set effort
+ void setEffort( int effort );
/** statistics class */
class Statistics {
public:
~Statistics();
};
Statistics d_statistics;
+ // is quantifier active?
+ bool isQuantifierActive( Node f );
};/* class ModelEngineBuilder */
}/* CVC4::theory::quantifiers namespace */
**/
#include "theory/quantifiers/model_engine.h"
-#include "theory/quantifiers/rep_set_iterator.h"
#include "theory/theory_engine.h"
#include "theory/uf/equality_engine.h"
#include "theory/uf/theory_uf.h"
#include "theory/arrays/theory_arrays_model.h"
#include "theory/quantifiers/first_order_model.h"
#include "theory/quantifiers/term_database.h"
+#include "theory/quantifiers/quantifiers_attributes.h"
//#define ME_PRINT_WARNINGS
#define EVAL_FAIL_SKIP_MULTIPLE
-//#define ONE_QUANT_PER_ROUND
using namespace std;
using namespace CVC4;
using namespace CVC4::theory::inst;
//Model Engine constructor
-ModelEngine::ModelEngine( QuantifiersEngine* qe ) :
+ModelEngine::ModelEngine( context::Context* c, QuantifiersEngine* qe ) :
QuantifiersModule( qe ),
-d_builder( qe ),
-d_rel_domain( qe->getModel() ){
+d_builder( c, qe ),
+d_rel_domain( qe, qe->getModel() ){
}
void ModelEngine::check( Theory::Effort e ){
if( e==Theory::EFFORT_LAST_CALL && !d_quantEngine->hasAddedLemma() ){
- //first, check if we can minimize the model further
- if( !((uf::TheoryUF*)d_quantEngine->getTheoryEngine()->theoryOf( THEORY_UF ))->getStrongSolver()->minimize() ){
- return;
- }
+ FirstOrderModel* fm = d_quantEngine->getModel();
//the following will attempt to build a model and test that it satisfies all asserted universal quantifiers
int addedLemmas = 0;
+ Trace("model-engine") << "---Model Engine Round---" << std::endl;
if( d_builder.optUseModel() ){
//check if any quantifiers are un-initialized
- for( int i=0; i<d_quantEngine->getModel()->getNumAssertedQuantifiers(); i++ ){
- Node f = d_quantEngine->getModel()->getAssertedQuantifier( i );
+ for( int i=0; i<fm->getNumAssertedQuantifiers(); i++ ){
+ Node f = fm->getAssertedQuantifier( i );
addedLemmas += initializeQuantifier( f );
}
}
- if( addedLemmas==0 ){
- //quantifiers are initialized, we begin an instantiation round
- double clSet = 0;
- if( Trace.isOn("model-engine") ){
- clSet = double(clock())/double(CLOCKS_PER_SEC);
- Trace("model-engine") << "---Model Engine Round---" << std::endl;
- }
- Debug("fmf-model-debug") << "---Begin Instantiation Round---" << std::endl;
- ++(d_statistics.d_inst_rounds);
- //reset the quantifiers engine
- d_quantEngine->resetInstantiationRound( e );
- //initialize the model
- Debug("fmf-model-debug") << "Build model..." << std::endl;
- d_builder.buildModel( d_quantEngine->getModel() );
- d_quantEngine->d_model_set = true;
- //if builder has lemmas, add and return
- if( d_builder.d_addedLemmas>0 ){
- addedLemmas += (int)d_builder.d_addedLemmas;
- }else{
- //print debug
- Debug("fmf-model-complete") << std::endl;
- debugPrint("fmf-model-complete");
- //verify we are SAT by trying exhaustive instantiation
- if( optUseRelevantDomain() ){
- d_rel_domain.compute();
+ if( addedLemmas>0 ){
+ Trace("model-engine") << "Initialize, Added Lemmas = " << addedLemmas << std::endl;
+ }
+ //two effort levels: first try exhaustive instantiation without axioms, then with.
+ int startEffort = ( !fm->isAxiomAsserted() || options::axiomInstMode()==AXIOM_INST_MODE_DEFAULT ) ? 1 : 0;
+ for( int effort=startEffort; effort<2; effort++ ){
+ // for effort = 0, we only instantiate non-axioms
+ // for effort = 1, we instantiate everything
+ if( addedLemmas==0 ){
+ //quantifiers are initialized, we begin an instantiation round
+ double clSet = 0;
+ if( Trace.isOn("model-engine") ){
+ clSet = double(clock())/double(CLOCKS_PER_SEC);
}
- d_triedLemmas = 0;
- d_testLemmas = 0;
- d_relevantLemmas = 0;
- d_totalLemmas = 0;
- Debug("fmf-model-debug") << "Do exhaustive instantiation..." << std::endl;
- for( int i=0; i<d_quantEngine->getModel()->getNumAssertedQuantifiers(); i++ ){
- Node f = d_quantEngine->getModel()->getAssertedQuantifier( i );
- if( d_builder.d_quant_sat.find( f )==d_builder.d_quant_sat.end() ){
- addedLemmas += exhaustiveInstantiate( f, optUseRelevantDomain() );
- if( optOneQuantPerRound() && addedLemmas>0 ){
- break;
- }
- }
-#ifdef ME_PRINT_WARNINGS
- if( addedLemmas>10000 ){
- break;
+ ++(d_statistics.d_inst_rounds);
+ //reset the quantifiers engine
+ d_quantEngine->resetInstantiationRound( e );
+ //initialize the model
+ Trace("model-engine-debug") << "Build model..." << std::endl;
+ d_builder.setEffort( effort );
+ d_builder.buildModel( fm, false );
+ //if builder has lemmas, add and return
+ if( d_builder.d_addedLemmas>0 ){
+ addedLemmas += (int)d_builder.d_addedLemmas;
+ }else{
+ Trace("model-engine-debug") << "Verify uf ss is minimal..." << std::endl;
+ //let the strong solver verify that the model is minimal
+ uf::StrongSolverTheoryUf* uf_ss = ((uf::TheoryUF*)d_quantEngine->getTheoryEngine()->theoryOf( THEORY_UF ))->getStrongSolver();
+ //for debugging, this will if there are terms in the model that the strong solver was not notified of
+ uf_ss->debugModel( fm );
+ Trace("model-engine-debug") << "Check model..." << std::endl;
+ //print debug
+ Debug("fmf-model-complete") << std::endl;
+ debugPrint("fmf-model-complete");
+ //successfully built an acceptable model, now check it
+ checkModel( addedLemmas );
+ //print debug information
+ if( Trace.isOn("model-engine") ){
+ Trace("model-engine") << "Instantiate axioms : " << ( d_builder.d_considerAxioms ? "yes" : "no" ) << std::endl;
+ Trace("model-engine") << "Added Lemmas = " << addedLemmas << " / " << d_triedLemmas << " / ";
+ Trace("model-engine") << d_testLemmas << " / " << d_relevantLemmas << " / " << d_totalLemmas << std::endl;
+ double clSet2 = double(clock())/double(CLOCKS_PER_SEC);
+ Trace("model-engine") << "Finished model engine, time = " << (clSet2-clSet) << std::endl;
}
-#endif
- }
- Debug("fmf-model-debug") << "---> Added lemmas = " << addedLemmas << " / " << d_triedLemmas << " / ";
- Debug("fmf-model-debug") << d_testLemmas << " / " << d_relevantLemmas << " / " << d_totalLemmas << std::endl;
- if( Trace.isOn("model-engine") ){
- Trace("model-engine") << "Added Lemmas = " << addedLemmas << " / " << d_triedLemmas << " / ";
- Trace("model-engine") << d_testLemmas << " / " << d_relevantLemmas << " / " << d_totalLemmas << std::endl;
- double clSet2 = double(clock())/double(CLOCKS_PER_SEC);
- Trace("model-engine") << "Finished model engine, time = " << (clSet2-clSet) << std::endl;
}
-#ifdef ME_PRINT_WARNINGS
- if( addedLemmas>10000 ){
- Debug("fmf-exit") << std::endl;
- debugPrint("fmf-exit");
- exit( 0 );
+ }
+ if( addedLemmas==0 ){
+ //if we have not added lemmas yet and axiomInstMode=trust, then we are done
+ if( options::axiomInstMode()==AXIOM_INST_MODE_TRUST ){
+ //we must return unknown if an axiom is asserted
+ if( effort==0 ){
+ d_incomplete_check = true;
+ }
+ break;
}
-#endif
}
}
if( addedLemmas==0 ){
- //CVC4 will answer SAT
- Debug("fmf-consistent") << std::endl;
+ Trace("model-engine-debug") << "No lemmas added, incomplete = " << d_incomplete_check << std::endl;
+ //CVC4 will answer SAT or unknown
+ Trace("fmf-consistent") << std::endl;
debugPrint("fmf-consistent");
- // finish building the model in the standard way
- d_builder.finishProcessBuildModel( d_quantEngine->getModel() );
+ if( options::produceModels() ){
+ // finish building the model in the standard way
+ d_builder.buildModel( fm, true );
+ d_quantEngine->d_model_set = true;
+ }
+ //if the check was incomplete, we must set incomplete flag
+ if( d_incomplete_check ){
+ d_quantEngine->getOutputChannel().setIncomplete();
+ }
}else{
//otherwise, the search will continue
d_quantEngine->flushLemmas( &d_quantEngine->getOutputChannel() );
}
bool ModelEngine::optOneQuantPerRound(){
-#ifdef ONE_QUANT_PER_ROUND
- return true;
-#else
- return false;
-#endif
+ return options::fmfOneQuantPerRound();
}
int ModelEngine::initializeQuantifier( Node f ){
// Notice() << "Unhandled phase req: " << n << std::endl;
// }
//}
+ std::vector< Node > vars;
std::vector< Node > ics;
std::vector< Node > terms;
for( int j=0; j<(int)f[0].getNumChildren(); j++ ){
Node ic = d_quantEngine->getTermDatabase()->getInstantiationConstant( f, j );
Node t = d_quantEngine->getTermDatabase()->getModelBasisTerm( ic.getType() );
+ vars.push_back( f[0][j] );
ics.push_back( ic );
terms.push_back( t );
//calculate the basis match for f
Node n = d_quantEngine->getTermDatabase()->getCounterexampleBody( f );
Node gn = n.substitute( ics.begin(), ics.end(), terms.begin(), terms.end() );
d_quantEngine->getTermDatabase()->registerModelBasis( n, gn );
- //add model basis instantiation
- if( d_quantEngine->addInstantiation( f, terms ) ){
- return 1;
- }else{
- //shouldn't happen usually, but will occur if x != y is a required literal for f.
- //Notice() << "No model basis for " << f << std::endl;
- ++(d_statistics.d_num_quants_init_fail);
+ if( d_builder.optInstGen() ){
+ //add model basis instantiation
+ if( d_quantEngine->addInstantiation( f, vars, terms ) ){
+ return 1;
+ }else{
+ //shouldn't happen usually, but will occur if x != y is a required literal for f.
+ //Notice() << "No model basis for " << f << std::endl;
+ ++(d_statistics.d_num_quants_init_fail);
+ }
}
}
return 0;
}
-int ModelEngine::exhaustiveInstantiate( Node f, bool useRelInstDomain ){
- int tests = 0;
- int addedLemmas = 0;
- int triedLemmas = 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->getTermDatabase()->getInstantiationConstant( f, i ) << " ";
+void ModelEngine::checkModel( int& addedLemmas ){
+ FirstOrderModel* fm = d_quantEngine->getModel();
+ //for debugging
+ if( Trace.isOn("model-engine") ){
+ for( std::map< TypeNode, std::vector< Node > >::iterator it = fm->d_rep_set.d_type_reps.begin(); it != fm->d_rep_set.d_type_reps.end(); ++it ){
+ if( it->first.isSort() ){
+ Trace("model-engine") << "Cardinality( " << it->first << " )" << " = " << it->second.size() << std::endl;
+ Trace("model-engine-debug") << " ";
+ for( size_t i=0; i<it->second.size(); i++ ){
+ Trace("model-engine-debug") << it->second[i] << " ";
+ }
+ Trace("model-engine-debug") << std::endl;
+ }
+ }
+ }
+ //verify we are SAT by trying exhaustive instantiation
+ d_incomplete_check = false;
+ if( optUseRelevantDomain() ){
+ d_rel_domain.compute();
}
- Debug("inst-fmf-ei") << std::endl;
- if( d_builder.d_quant_selection_lits[f].empty() ){
- Debug("inst-fmf-ei") << "WARNING: " << f << " has no model literal definitions (is f clausified?)" << std::endl;
+ d_triedLemmas = 0;
+ d_testLemmas = 0;
+ d_relevantLemmas = 0;
+ d_totalLemmas = 0;
+ Debug("fmf-model-debug") << "Do exhaustive instantiation..." << std::endl;
+ for( int i=0; i<fm->getNumAssertedQuantifiers(); i++ ){
+ Node f = fm->getAssertedQuantifier( i );
+ addedLemmas += exhaustiveInstantiate( f, optUseRelevantDomain() );
#ifdef ME_PRINT_WARNINGS
- Message() << "WARNING: " << f << " has no model literal definitions (is f clausified?)" << std::endl;
+ if( addedLemmas>10000 ){
+ Debug("fmf-exit") << std::endl;
+ debugPrint("fmf-exit");
+ exit( 0 );
+ }
#endif
- }else{
- Debug("inst-fmf-ei") << " Model literal definitions:" << std::endl;
- for( size_t i=0; i<d_builder.d_quant_selection_lits[f].size(); i++ ){
- Debug("inst-fmf-ei") << " " << d_builder.d_quant_selection_lits[f][i] << std::endl;
+ if( optOneQuantPerRound() && addedLemmas>0 ){
+ break;
}
}
- RepSetIterator riter( f, d_quantEngine->getModel() );
- //set the domain for the iterator (the sufficient set of instantiations to try)
- if( useRelInstDomain ){
- riter.setDomain( d_rel_domain.d_quant_inst_domain[f] );
+ Debug("fmf-model-debug") << "---> Added lemmas = " << addedLemmas << " / " << d_triedLemmas << " / ";
+ Debug("fmf-model-debug") << d_testLemmas << " / " << d_relevantLemmas << " / " << d_totalLemmas << std::endl;
+}
+
+int ModelEngine::exhaustiveInstantiate( Node f, bool useRelInstDomain ){
+ int addedLemmas = 0;
+ //keep track of total instantiations for statistics
+ int totalInst = 1;
+ for( size_t i=0; i<f[0].getNumChildren(); i++ ){
+ TypeNode tn = f[0][i].getType();
+ if( d_quantEngine->getModel()->d_rep_set.hasType( tn ) ){
+ totalInst = totalInst * (int)d_quantEngine->getModel()->d_rep_set.d_type_reps[ tn ].size();
+ }
}
- RepSetEvaluator reval( d_quantEngine->getModel(), &riter );
- while( !riter.isFinished() && ( addedLemmas==0 || !optOneInstPerQuantRound() ) ){
- d_testLemmas++;
- if( d_builder.optUseModel() ){
- //see if instantiation is already true in current model
- Debug("fmf-model-eval") << "Evaluating ";
- riter.debugPrintSmall("fmf-model-eval");
- Debug("fmf-model-eval") << "Done calculating terms." << std::endl;
- tests++;
- //if evaluate(...)==1, then the instantiation is already true in the model
- // depIndex is the index of the least significant variable that this evaluation relies upon
- int depIndex = riter.getNumTerms()-1;
- int eval = reval.evaluate( d_quantEngine->getTermDatabase()->getCounterexampleBody( f ), depIndex );
+ d_totalLemmas += totalInst;
+ //if we need to consider this quantifier on this iteration
+ if( d_builder.isQuantifierActive( f ) ){
+ Trace("rel-dom") << "Exhaustive instantiate " << f << std::endl;
+ if( useRelInstDomain ){
+ Trace("rel-dom") << "Relevant domain : " << std::endl;
+ for( size_t i=0; i<d_rel_domain.d_quant_inst_domain[f].size(); i++ ){
+ Trace("rel-dom") << " " << i << " : ";
+ for( size_t j=0; j<d_rel_domain.d_quant_inst_domain[f][i].size(); j++ ){
+ Trace("rel-dom") << d_rel_domain.d_quant_inst_domain[f][i][j] << " ";
+ }
+ Trace("rel-dom") << std::endl;
+ }
+ }
+ int tests = 0;
+ int triedLemmas = 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->getTermDatabase()->getInstantiationConstant( f, i ) << " ";
+ }
+ Debug("inst-fmf-ei") << std::endl;
+ RepSetIterator riter( &(d_quantEngine->getModel()->d_rep_set) );
+ riter.setQuantifier( f );
+ //if the iterator is incomplete, we will return unknown instead of sat if no instantiations are added this round
+ d_incomplete_check = d_incomplete_check || riter.d_incomplete;
+ //set the domain for the iterator (the sufficient set of instantiations to try)
+ if( useRelInstDomain ){
+ riter.setDomain( d_rel_domain.d_quant_inst_domain[f] );
+ }
+ d_quantEngine->getModel()->resetEvaluate();
+ while( !riter.isFinished() && ( addedLemmas==0 || !optOneInstPerQuantRound() ) ){
+ d_testLemmas++;
+ int eval = 0;
+ int depIndex;
+ if( d_builder.optUseModel() ){
+ //see if instantiation is already true in current model
+ Debug("fmf-model-eval") << "Evaluating ";
+ riter.debugPrintSmall("fmf-model-eval");
+ Debug("fmf-model-eval") << "Done calculating terms." << std::endl;
+ tests++;
+ //if evaluate(...)==1, then the instantiation is already true in the model
+ // depIndex is the index of the least significant variable that this evaluation relies upon
+ depIndex = riter.getNumTerms()-1;
+ eval = d_quantEngine->getModel()->evaluate( d_quantEngine->getTermDatabase()->getCounterexampleBody( f ), depIndex, &riter );
+ if( eval==1 ){
+ Debug("fmf-model-eval") << " Returned success with depIndex = " << depIndex << std::endl;
+ }else{
+ Debug("fmf-model-eval") << " Returned " << (eval==-1 ? "failure" : "unknown") << ", depIndex = " << depIndex << std::endl;
+ }
+ }
if( eval==1 ){
- Debug("fmf-model-eval") << " Returned success with depIndex = " << depIndex << std::endl;
+ //instantiation is already true -> skip
riter.increment2( depIndex );
}else{
- Debug("fmf-model-eval") << " Returned " << (eval==-1 ? "failure" : "unknown") << ", depIndex = " << depIndex << std::endl;
+ //instantiation was not shown to be true, construct the match
InstMatch m;
- riter.getMatch( d_quantEngine, m );
+ for( int i=0; i<riter.getNumTerms(); i++ ){
+ m.set( d_quantEngine->getTermDatabase()->getInstantiationConstant( f, riter.d_index_order[i] ), riter.getTerm( i ) );
+ }
Debug("fmf-model-eval") << "* Add instantiation " << m << std::endl;
triedLemmas++;
d_triedLemmas++;
+ //add as instantiation
if( d_quantEngine->addInstantiation( f, m ) ){
addedLemmas++;
#ifdef EVAL_FAIL_SKIP_MULTIPLE
riter.increment();
}
}
- }else{
- InstMatch m;
- riter.getMatch( d_quantEngine, m );
- Debug("fmf-model-eval") << "* Add instantiation " << std::endl;
- triedLemmas++;
- d_triedLemmas++;
- if( d_quantEngine->addInstantiation( f, m ) ){
- addedLemmas++;
- }
- riter.increment();
}
- }
- d_statistics.d_eval_formulas += reval.d_eval_formulas;
- d_statistics.d_eval_uf_terms += reval.d_eval_uf_terms;
- d_statistics.d_eval_lits += reval.d_eval_lits;
- d_statistics.d_eval_lits_unknown += reval.d_eval_lits_unknown;
- int totalInst = 1;
- int relevantInst = 1;
- for( size_t i=0; i<f[0].getNumChildren(); i++ ){
- totalInst = totalInst * (int)d_quantEngine->getModel()->d_rep_set.d_type_reps[ f[0][i].getType() ].size();
- relevantInst = relevantInst * (int)riter.d_domain[i].size();
- }
- d_totalLemmas += totalInst;
- d_relevantLemmas += relevantInst;
- Debug("inst-fmf-ei") << "Finished: " << std::endl;
- Debug("inst-fmf-ei") << " Inst Total: " << totalInst << std::endl;
- Debug("inst-fmf-ei") << " Inst Relevant: " << relevantInst << std::endl;
- Debug("inst-fmf-ei") << " Inst Tried: " << triedLemmas << std::endl;
- Debug("inst-fmf-ei") << " Inst Added: " << addedLemmas << std::endl;
- Debug("inst-fmf-ei") << " # Tests: " << tests << std::endl;
-///-----------
+ d_statistics.d_eval_formulas += d_quantEngine->getModel()->d_eval_formulas;
+ d_statistics.d_eval_uf_terms += d_quantEngine->getModel()->d_eval_uf_terms;
+ d_statistics.d_eval_lits += d_quantEngine->getModel()->d_eval_lits;
+ d_statistics.d_eval_lits_unknown += d_quantEngine->getModel()->d_eval_lits_unknown;
+ int relevantInst = 1;
+ for( size_t i=0; i<f[0].getNumChildren(); i++ ){
+ relevantInst = relevantInst * (int)riter.d_domain[i].size();
+ }
+ d_relevantLemmas += relevantInst;
+ Debug("inst-fmf-ei") << "Finished: " << std::endl;
+ Debug("inst-fmf-ei") << " Inst Total: " << totalInst << std::endl;
+ Debug("inst-fmf-ei") << " Inst Relevant: " << relevantInst << std::endl;
+ Debug("inst-fmf-ei") << " Inst Tried: " << triedLemmas << std::endl;
+ Debug("inst-fmf-ei") << " Inst Added: " << addedLemmas << std::endl;
+ Debug("inst-fmf-ei") << " # Tests: " << tests << std::endl;
#ifdef ME_PRINT_WARNINGS
- if( addedLemmas>1000 ){
- Notice() << "WARNING: many instantiations produced for " << f << ": " << std::endl;
- Notice() << " Inst Total: " << totalInst << std::endl;
- Notice() << " Inst Relevant: " << totalRelevant << std::endl;
- Notice() << " Inst Tried: " << triedLemmas << std::endl;
- Notice() << " Inst Added: " << addedLemmas << std::endl;
- Notice() << " # Tests: " << tests << std::endl;
- Notice() << std::endl;
- if( !d_builder.d_quant_selection_lits[f].empty() ){
- Notice() << " Model literal definitions:" << std::endl;
- for( size_t i=0; i<d_builder.d_quant_selection_lits[f].size(); i++ ){
- Notice() << " " << d_builder.d_quant_selection_lits[f][i] << std::endl;
- }
+ if( addedLemmas>1000 ){
+ Notice() << "WARNING: many instantiations produced for " << f << ": " << std::endl;
+ Notice() << " Inst Total: " << totalInst << std::endl;
+ Notice() << " Inst Relevant: " << totalRelevant << std::endl;
+ Notice() << " Inst Tried: " << triedLemmas << std::endl;
+ Notice() << " Inst Added: " << addedLemmas << std::endl;
+ Notice() << " # Tests: " << tests << std::endl;
Notice() << std::endl;
}
- }
#endif
-///-----------
+ }
return addedLemmas;
}
void ModelEngine::debugPrint( const char* c ){
- Debug( c ) << "Quantifiers: " << std::endl;
+ Trace( c ) << "Quantifiers: " << std::endl;
for( int i=0; i<(int)d_quantEngine->getModel()->getNumAssertedQuantifiers(); i++ ){
Node f = d_quantEngine->getModel()->getAssertedQuantifier( i );
- Debug( c ) << " ";
- if( d_builder.d_quant_sat.find( f )!=d_builder.d_quant_sat.end() ){
- Debug( c ) << "*SAT* ";
+ Trace( c ) << " ";
+ if( !d_builder.isQuantifierActive( f ) ){
+ Trace( c ) << "*Inactive* ";
}else{
- Debug( c ) << " ";
+ Trace( c ) << " ";
}
- Debug( c ) << f << std::endl;
+ Trace( c ) << f << std::endl;
}
//d_quantEngine->getModel()->debugPrint( c );
}
private: //analysis of current model:
//relevant domain
RelevantDomain d_rel_domain;
+ //is the exhaustive instantiation incomplete?
+ bool d_incomplete_check;
private:
//options
bool optOneInstPerQuantRound();
private:
//initialize quantifiers, return number of lemmas produced
int initializeQuantifier( Node f );
+ //check model
+ void checkModel( int& addedLemmas );
//exhaustively instantiate quantifier (possibly using mbqi), return number of lemmas produced
int exhaustiveInstantiate( Node f, bool useRelInstDomain = false );
private:
int d_totalLemmas;
int d_relevantLemmas;
public:
- ModelEngine( QuantifiersEngine* qe );
+ ModelEngine( context::Context* c, QuantifiersEngine* qe );
~ModelEngine(){}
public:
void check( Theory::Effort e );
--- /dev/null
+/********************* */
+/*! \file inst_when_mode.cpp
+ ** \verbatim
+ ** Original author: mdeters
+ ** Major contributors: ajreynol
+ ** Minor contributors (to current version): none
+ ** This file is part of the CVC4 prototype.
+ ** 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
+ ** information.\endverbatim
+ **
+ ** \brief [[ Add one-line brief description here ]]
+ **
+ ** [[ Add lengthier description here ]]
+ ** \todo document this file
+ **/
+
+#include <iostream>
+#include "theory/quantifiers/modes.h"
+
+namespace CVC4 {
+
+std::ostream& operator<<(std::ostream& out, theory::quantifiers::InstWhenMode mode) {
+ switch(mode) {
+ case theory::quantifiers::INST_WHEN_PRE_FULL:
+ out << "INST_WHEN_PRE_FULL";
+ break;
+ case theory::quantifiers::INST_WHEN_FULL:
+ out << "INST_WHEN_FULL";
+ break;
+ case theory::quantifiers::INST_WHEN_FULL_LAST_CALL:
+ out << "INST_WHEN_FULL_LAST_CALL";
+ break;
+ case theory::quantifiers::INST_WHEN_LAST_CALL:
+ out << "INST_WHEN_LAST_CALL";
+ break;
+ default:
+ out << "InstWhenMode!UNKNOWN";
+ }
+
+ return out;
+}
+
+std::ostream& operator<<(std::ostream& out, theory::quantifiers::LiteralMatchMode mode) {
+ switch(mode) {
+ case theory::quantifiers::LITERAL_MATCH_NONE:
+ out << "LITERAL_MATCH_NONE";
+ break;
+ case theory::quantifiers::LITERAL_MATCH_PREDICATE:
+ out << "LITERAL_MATCH_PREDICATE";
+ break;
+ case theory::quantifiers::LITERAL_MATCH_EQUALITY:
+ out << "LITERAL_MATCH_EQUALITY";
+ break;
+ default:
+ out << "LiteralMatchMode!UNKNOWN";
+ }
+
+ return out;
+}
+
+std::ostream& operator<<(std::ostream& out, theory::quantifiers::AxiomInstMode mode) {
+ switch(mode) {
+ case theory::quantifiers::AXIOM_INST_MODE_DEFAULT:
+ out << "AXIOM_INST_MODE_DEFAULT";
+ break;
+ case theory::quantifiers::AXIOM_INST_MODE_TRUST:
+ out << "AXIOM_INST_MODE_TRUST";
+ break;
+ case theory::quantifiers::AXIOM_INST_MODE_PRIORITY:
+ out << "AXIOM_INST_MODE_PRIORITY";
+ break;
+ default:
+ out << "AxiomInstMode!UNKNOWN";
+ }
+
+ return out;
+}
+
+}/* CVC4 namespace */
+
--- /dev/null
+/********************* */
+/*! \file modes.h
+ ** \verbatim
+ ** Original author: mdeters
+ ** Major contributors: ajreynol
+ ** Minor contributors (to current version): none
+ ** This file is part of the CVC4 prototype.
+ ** 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
+ ** information.\endverbatim
+ **
+ ** \brief [[ Add one-line brief description here ]]
+ **
+ ** [[ Add lengthier description here ]]
+ ** \todo document this file
+ **/
+
+#include "cvc4_private.h"
+
+#ifndef __CVC4__THEORY__QUANTIFIERS__MODEs_H
+#define __CVC4__THEORY__QUANTIFIERS__MODEs_H
+
+#include <iostream>
+
+namespace CVC4 {
+namespace theory {
+namespace quantifiers {
+
+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;
+
+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;
+
+typedef enum {
+ /** default, use all methods for axioms */
+ AXIOM_INST_MODE_DEFAULT,
+ /** only use heuristic methods for axioms, return unknown in the case no instantiations are produced */
+ AXIOM_INST_MODE_TRUST,
+ /** only use heuristic methods for axioms, resort to all methods when no instantiations are produced */
+ AXIOM_INST_MODE_PRIORITY,
+} AxiomInstMode;
+
+
+}/* CVC4::theory::quantifiers namespace */
+}/* CVC4::theory namespace */
+
+std::ostream& operator<<(std::ostream& out, theory::quantifiers::InstWhenMode mode) CVC4_PUBLIC;
+
+}/* CVC4 namespace */
+
+#endif /* __CVC4__THEORY__QUANTIFIERS__INST_WHEN_MODE_H */
option registerQuantBodyTerms --register-quant-body-terms bool :default false
consider ground terms within bodies of quantified formulas for matching
-option instWhenMode --inst-when=MODE CVC4::theory::quantifiers::InstWhenMode :default CVC4::theory::quantifiers::INST_WHEN_FULL_LAST_CALL :include "theory/quantifiers/inst_when_mode.h" :handler CVC4::theory::quantifiers::stringToInstWhenMode :handler-include "theory/quantifiers/options_handlers.h" :predicate CVC4::theory::quantifiers::checkInstWhenMode :predicate-include "theory/quantifiers/options_handlers.h"
+option instWhenMode --inst-when=MODE CVC4::theory::quantifiers::InstWhenMode :default CVC4::theory::quantifiers::INST_WHEN_FULL_LAST_CALL :read-write :include "theory/quantifiers/modes.h" :handler CVC4::theory::quantifiers::stringToInstWhenMode :handler-include "theory/quantifiers/options_handlers.h" :predicate CVC4::theory::quantifiers::checkInstWhenMode :predicate-include "theory/quantifiers/options_handlers.h"
when to apply instantiation
-
+
option eagerInstQuant --eager-inst-quant bool :default false
apply quantifier instantiation eagerly
-option literalMatchMode --literal-matching=MODE CVC4::theory::quantifiers::LiteralMatchMode :default CVC4::theory::quantifiers::LITERAL_MATCH_NONE :include "theory/quantifiers/literal_match_mode.h" :handler CVC4::theory::quantifiers::stringToLiteralMatchMode :handler-include "theory/quantifiers/options_handlers.h" :predicate CVC4::theory::quantifiers::checkLiteralMatchMode :predicate-include "theory/quantifiers/options_handlers.h"
+option literalMatchMode --literal-matching=MODE CVC4::theory::quantifiers::LiteralMatchMode :default CVC4::theory::quantifiers::LITERAL_MATCH_NONE :include "theory/quantifiers/modes.h" :handler CVC4::theory::quantifiers::stringToLiteralMatchMode :handler-include "theory/quantifiers/options_handlers.h" :predicate CVC4::theory::quantifiers::checkLiteralMatchMode :predicate-include "theory/quantifiers/options_handlers.h"
choose literal matching mode
option cbqi --enable-cbqi/--disable-cbqi bool :default false
option finiteModelFind --finite-model-find bool :default false
use finite model finding heuristic for quantifier instantiation
-option ufssRegions /--disable-uf-ss-regions bool :default true
- disable region-based method for discovering cliques and splits in uf strong solver
-option ufssEagerSplits --uf-ss-eager-split bool :default false
- add splits eagerly for uf strong solver
-option ufssColoringSat --uf-ss-coloring-sat bool :default false
- use coloring-based SAT heuristic for uf strong solver
-
option fmfModelBasedInst /--disable-fmf-mbqi bool :default true
disable model-based quantifier instantiation for finite model finding
-option fmfInstGen /--disable-fmf-inst-gen bool :default true
- disable Inst-Gen instantiation techniques for finite model finding
option fmfOneInstPerRound --fmf-one-inst-per-round bool :default false
only add one instantiation per quantifier per round for fmf
+option fmfOneQuantPerRound --fmf-one-quant-per-round bool :default false
+ only add instantiations for one quantifier per round for fmf
option fmfInstEngine --fmf-inst-engine bool :default false
use instantiation engine in conjunction with finite model finding
option fmfRelevantDomain --fmf-relevant-domain bool :default false
use relevant domain computation, similar to complete instantiation (Ge, deMoura 09)
+option fmfInstGen /--disable-fmf-inst-gen bool :default true
+ disable Inst-Gen instantiation techniques for finite model finding
+option fmfInstGenOneQuantPerRound --fmf-inst-gen-one-quant-per-round bool :default false
+ only perform Inst-Gen instantiation techniques on one quantifier per round
+
+option axiomInstMode --axiom-inst=MODE CVC4::theory::quantifiers::AxiomInstMode :default CVC4::theory::quantifiers::AXIOM_INST_MODE_DEFAULT :include "theory/quantifiers/modes.h" :handler CVC4::theory::quantifiers::stringToAxiomInstMode :handler-include "theory/quantifiers/options_handlers.h"
+ policy for instantiating axioms
endmodule
\n\
";
+static const std::string axiomInstModeHelp = "\
+Literal match modes currently supported by the --axiom-inst option:\n\
+\n\
+default \n\
++ Treat axioms the same as usual quantifiers, i.e. use all available methods for\n\
+ instantiating axioms.\n\
+\n\
+trust \n\
++ Treat axioms only using heuristic instantiation. Return unknown if in the case\n\
+ that no instantiations are produced.\n\
+\n\
+priority \n\
++ Treat axioms only using heuristic instantiation. Resort to using all methods\n\
+ in the case that no instantiations are produced.\n\
+\n\
+";
+
inline InstWhenMode stringToInstWhenMode(std::string option, std::string optarg, SmtEngine* smt) throw(OptionException) {
if(optarg == "pre-full") {
return INST_WHEN_PRE_FULL;
}
}
+inline AxiomInstMode stringToAxiomInstMode(std::string option, std::string optarg, SmtEngine* smt) throw(OptionException) {
+ if(optarg == "default") {
+ return AXIOM_INST_MODE_DEFAULT;
+ } else if(optarg == "trust") {
+ return AXIOM_INST_MODE_TRUST;
+ } else if(optarg == "priority") {
+ return AXIOM_INST_MODE_PRIORITY;
+ } else if(optarg == "help") {
+ puts(axiomInstModeHelp.c_str());
+ exit(1);
+ } else {
+ throw OptionException(std::string("unknown option for --axiom-inst: `") +
+ optarg + "'. Try --axiom-inst help.");
+ }
+}
+
}/* CVC4::theory::quantifiers namespace */
}/* CVC4::theory namespace */
}/* CVC4 namespace */
--- /dev/null
+/********************* */\r
+/*! \file quantifiers_attributes.cpp\r
+ ** \verbatim\r
+ ** Original author: ajreynol\r
+ ** Major contributors: none\r
+ ** Minor contributors (to current version): none\r
+ ** This file is part of the CVC4 prototype.\r
+ ** Copyright (c) 2009-2012 The Analysis of Computer Systems Group (ACSys)\r
+ ** Courant Institute of Mathematical Sciences\r
+ ** New York University\r
+ ** See the file COPYING in the top-level source directory for licensing\r
+ ** information.\endverbatim\r
+ **\r
+ ** \brief Implementation of QuantifiersAttributes class\r
+ **/\r
+\r
+#include "theory/quantifiers/quantifiers_attributes.h"\r
+#include "theory/quantifiers/options.h"\r
+\r
+using namespace std;\r
+using namespace CVC4;\r
+using namespace CVC4::kind;\r
+using namespace CVC4::context;\r
+using namespace CVC4::theory;\r
+using namespace CVC4::theory::quantifiers;\r
+\r
+void QuantifiersAttributes::setUserAttribute( std::string& attr, Node n ){\r
+ if( n.getKind()==FORALL ){\r
+ if( attr=="axiom" ){\r
+ Trace("quant-attr") << "Set axiom " << n << std::endl;\r
+ AxiomAttribute aa;\r
+ n.setAttribute( aa, true );\r
+ }else if( attr=="conjecture" ){\r
+ Trace("quant-attr") << "Set conjecture " << n << std::endl;\r
+ ConjectureAttribute ca;\r
+ n.setAttribute( ca, true );\r
+ }\r
+ }else{\r
+ for( size_t i=0; i<n.getNumChildren(); i++ ){\r
+ setUserAttribute( attr, n[i] );\r
+ }\r
+ }\r
+}\r
--- /dev/null
+/********************* */\r
+/*! \file quantifiers_attributes.h\r
+ ** \verbatim\r
+ ** Original author: ajreynol\r
+ ** Major contributors: none\r
+ ** Minor contributors (to current version): none\r
+ ** This file is part of the CVC4 prototype.\r
+ ** Copyright (c) 2009, 2010, 2011 The Analysis of Computer Systems Group (ACSys)\r
+ ** Courant Institute of Mathematical Sciences\r
+ ** New York University\r
+ ** See the file COPYING in the top-level source directory for licensing\r
+ ** information.\endverbatim\r
+ **\r
+ ** \brief Attributes for the theory quantifiers\r
+ **\r
+ ** Attributes for the theory quantifiers.\r
+ **/\r
+\r
+#include "cvc4_private.h"\r
+\r
+#ifndef __CVC4__THEORY__QUANTIFIERS__QUANTIFIERS_REWRITER_H\r
+#define __CVC4__THEORY__QUANTIFIERS__QUANTIFIERS_REWRITER_H\r
+\r
+#include "theory/rewriter.h"\r
+#include "theory/quantifiers_engine.h"\r
+\r
+namespace CVC4 {\r
+namespace theory {\r
+namespace quantifiers {\r
+\r
+/** Attribute true for quantifiers that are axioms */\r
+struct AxiomAttributeId {};\r
+typedef expr::Attribute< AxiomAttributeId, bool > AxiomAttribute;\r
+\r
+/** Attribute true for quantifiers that are conjecture */\r
+struct ConjectureAttributeId {};\r
+typedef expr::Attribute< ConjectureAttributeId, bool > ConjectureAttribute;\r
+\r
+struct QuantifiersAttributes\r
+{\r
+ /** set user attribute\r
+ * This function will apply a custom set of attributes to all top-level universal\r
+ * quantifiers contained in n\r
+ */\r
+ static void setUserAttribute( std::string& attr, Node n );\r
+};\r
+\r
+\r
+}\r
+}\r
+}\r
+\r
+#endif\r
using namespace CVC4::theory;
using namespace CVC4::theory::quantifiers;
-RelevantDomain::RelevantDomain( FirstOrderModel* m ) : d_model( m ){
+RelevantDomain::RelevantDomain( QuantifiersEngine* qe, FirstOrderModel* m ) : d_qe( qe ), d_model( m ){
}
void RelevantDomain::compute(){
+ Trace("rel-dom") << "compute relevant domain" << std::endl;
d_quant_inst_domain.clear();
for( int i=0; i<(int)d_model->getNumAssertedQuantifiers(); i++ ){
Node f = d_model->getAssertedQuantifier( i );
d_quant_inst_domain[f].resize( f[0].getNumChildren() );
}
+ Trace("rel-dom") << "account for ground terms" << std::endl;
//add ground terms to domain (rule 1 of complete instantiation essentially uf fragment)
for( std::map< Node, uf::UfModelTree >::iterator it = d_model->d_uf_model_tree.begin();
it != d_model->d_uf_model_tree.end(); ++it ){
if( d_model->d_rep_set.hasType( n[j].getType() ) ){
Node ra = d_model->getRepresentative( n[j] );
int raIndex = d_model->d_rep_set.getIndexFor( ra );
+ if( raIndex==-1 ) Trace("rel-dom-warn") << "WARNING: Ground domain: rep set does not contain : " << ra << std::endl;
Assert( raIndex!=-1 );
if( std::find( d_active_domain[op][j].begin(), d_active_domain[op][j].end(), raIndex )==d_active_domain[op][j].end() ){
d_active_domain[op][j].push_back( raIndex );
//add to range
Node r = d_model->getRepresentative( n );
int raIndex = d_model->d_rep_set.getIndexFor( r );
+ if( raIndex==-1 ) Trace("rel-dom-warn") << "WARNING: Ground range: rep set does not contain : " << r << std::endl;
Assert( raIndex!=-1 );
if( std::find( d_active_range[op].begin(), d_active_range[op].end(), raIndex )==d_active_range[op].end() ){
d_active_range[op].push_back( raIndex );
}
}
}
+ Trace("rel-dom") << "do quantifiers" << std::endl;
//find fixed point for relevant domain computation
bool success;
do{
for( int i=0; i<(int)d_model->getNumAssertedQuantifiers(); i++ ){
Node f = d_model->getAssertedQuantifier( i );
//compute the domain of relevant instantiations (rule 3 of complete instantiation, essentially uf fragment)
- if( computeRelevantInstantiationDomain( d_model->getTermDatabase()->getCounterexampleBody( f ), Node::null(), -1, d_quant_inst_domain[f] ) ){
+ if( computeRelevantInstantiationDomain( d_qe->getTermDatabase()->getCounterexampleBody( f ), Node::null(), -1, f ) ){
success = false;
}
//extend the possible domain for functions (rule 2 of complete instantiation, essentially uf fragment)
RepDomain range;
- if( extendFunctionDomains( d_model->getTermDatabase()->getCounterexampleBody( f ), range ) ){
+ if( extendFunctionDomains( d_qe->getTermDatabase()->getCounterexampleBody( f ), range ) ){
success = false;
}
}
}while( !success );
+ Trace("rel-dom") << "done compute relevant domain" << std::endl;
}
-bool RelevantDomain::computeRelevantInstantiationDomain( Node n, Node parent, int arg, std::vector< RepDomain >& rd ){
+bool RelevantDomain::computeRelevantInstantiationDomain( Node n, Node parent, int arg, Node f ){
bool domainChanged = false;
if( n.getKind()==INST_CONSTANT ){
bool domainSet = false;
if( d_active_domain.find( op )!=d_active_domain.end() ){
for( size_t i=0; i<d_active_domain[op][arg].size(); i++ ){
int d = d_active_domain[op][arg][i];
- if( std::find( rd[vi].begin(), rd[vi].end(), d )==rd[vi].end() ){
- rd[vi].push_back( d );
+ if( std::find( d_quant_inst_domain[f][vi].begin(), d_quant_inst_domain[f][vi].end(), d )==
+ d_quant_inst_domain[f][vi].end() ){
+ d_quant_inst_domain[f][vi].push_back( d );
domainChanged = true;
}
}
if( !domainSet ){
//otherwise, we must consider the entire domain
TypeNode tn = n.getType();
- if( d_model->d_rep_set.hasType( tn ) ){
- if( rd[vi].size()!=d_model->d_rep_set.d_type_reps[tn].size() ){
- rd[vi].clear();
+ if( d_quant_inst_domain_complete[f].find( vi )==d_quant_inst_domain_complete[f].end() ){
+ if( d_model->d_rep_set.hasType( tn ) ){
+ //it is the complete domain
+ d_quant_inst_domain[f][vi].clear();
for( size_t i=0; i<d_model->d_rep_set.d_type_reps[tn].size(); i++ ){
- rd[vi].push_back( i );
- domainChanged = true;
+ d_quant_inst_domain[f][vi].push_back( i );
}
+ domainChanged = true;
}
- }else{
- //infinite domain?
+ d_quant_inst_domain_complete[f][vi] = true;
}
}
}else{
for( int i=0; i<(int)n.getNumChildren(); i++ ){
- if( computeRelevantInstantiationDomain( n[i], n, i, rd ) ){
+ if( computeRelevantInstantiationDomain( n[i], n, i, f ) ){
domainChanged = true;
}
}
}
}else{
Node r = d_model->getRepresentative( n );
- range.push_back( d_model->d_rep_set.getIndexFor( r ) );
+ int index = d_model->d_rep_set.getIndexFor( r );
+ if( index==-1 ){
+ //we consider all ground terms in bodies of quantifiers to be the first ground representative
+ range.push_back( 0 );
+ }else{
+ range.push_back( index );
+ }
}
return domainChanged;
}
class RelevantDomain
{
private:
+ QuantifiersEngine* d_qe;
FirstOrderModel* d_model;
//the domain of the arguments for each operator
//the range for each operator
std::map< Node, RepDomain > d_active_range;
//for computing relevant instantiation domain, return true if changed
- bool computeRelevantInstantiationDomain( Node n, Node parent, int arg, std::vector< RepDomain >& rd );
+ bool computeRelevantInstantiationDomain( Node n, Node parent, int arg, Node f );
//for computing extended
bool extendFunctionDomains( Node n, RepDomain& range );
public:
- RelevantDomain( FirstOrderModel* m );
+ RelevantDomain( QuantifiersEngine* qe, FirstOrderModel* m );
virtual ~RelevantDomain(){}
//compute the relevant domain
void compute();
//relevant instantiation domain for each quantifier
std::map< Node, std::vector< RepDomain > > d_quant_inst_domain;
+ std::map< Node, std::map< int, bool > > d_quant_inst_domain_complete;
};/* class RelevantDomain */
}/* CVC4::theory::quantifiers namespace */
+++ /dev/null
-/********************* */
-/*! \file rep_set_iterator.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 relevant domain class
- **/
-
-#include "theory/quantifiers/rep_set_iterator.h"
-#include "theory/quantifiers/model_engine.h"
-#include "theory/quantifiers/term_database.h"
-
-#define USE_INDEX_ORDERING
-
-using namespace std;
-using namespace CVC4;
-using namespace CVC4::kind;
-using namespace CVC4::context;
-using namespace CVC4::theory;
-using namespace CVC4::theory::quantifiers;
-
-RepSetIterator::RepSetIterator( Node f, FirstOrderModel* model ) : d_f( f ), d_model( model ){
- //store instantiation constants
- for( size_t i=0; i<f[0].getNumChildren(); i++ ){
- d_index.push_back( 0 );
- }
- for( size_t i=0; i<f[0].getNumChildren(); i++ ){
- //store default index order
- d_index_order.push_back( i );
- d_var_order[i] = i;
- //store default domain
- d_domain.push_back( RepDomain() );
- TypeNode tn = d_f[0][i].getType();
- if( tn.isSort() ){
- if( d_model->d_rep_set.hasType( tn ) ){
- for( int j=0; j<(int)d_model->d_rep_set.d_type_reps[d_f[0][i].getType()].size(); j++ ){
- d_domain[i].push_back( j );
- }
- }else{
- Unimplemented("Cannot create instantiation iterator for unknown uninterpretted sort");
- }
- }else if( tn==NodeManager::currentNM()->integerType() || tn==NodeManager::currentNM()->realType() ){
- Unimplemented("Cannot create instantiation iterator for arithmetic quantifier");
- }else if( tn.isDatatype() ){
- const Datatype& dt = ((DatatypeType)(tn).toType()).getDatatype();
- //if finite, then use type enumerator
- if( dt.isFinite() ){
- //DO_THIS: use type enumerator
- Unimplemented("Not yet implemented: instantiation iterator for finite datatype quantifier");
- }else{
- Unimplemented("Cannot create instantiation iterator for infinite datatype quantifier");
- }
- }else{
- Unimplemented("Cannot create instantiation iterator for quantifier");
- }
- }
-}
-
-void RepSetIterator::setIndexOrder( std::vector< int >& indexOrder ){
- d_index_order.clear();
- d_index_order.insert( d_index_order.begin(), indexOrder.begin(), indexOrder.end() );
- //make the d_var_order mapping
- for( int i=0; i<(int)d_index_order.size(); i++ ){
- d_var_order[d_index_order[i]] = i;
- }
-}
-
-void RepSetIterator::setDomain( std::vector< RepDomain >& domain ){
- d_domain.clear();
- d_domain.insert( d_domain.begin(), domain.begin(), domain.end() );
- //we are done if a domain is empty
- for( int i=0; i<(int)d_domain.size(); i++ ){
- if( d_domain[i].empty() ){
- d_index.clear();
- }
- }
-}
-
-void RepSetIterator::increment2( int counter ){
- Assert( !isFinished() );
-#ifdef DISABLE_EVAL_SKIP_MULTIPLE
- counter = (int)d_index.size()-1;
-#endif
- //increment d_index
- while( counter>=0 && d_index[counter]==(int)(d_domain[counter].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 RepSetIterator::increment(){
- if( !isFinished() ){
- increment2( (int)d_index.size()-1 );
- }
-}
-
-bool RepSetIterator::isFinished(){
- return d_index.empty();
-}
-
-void RepSetIterator::getMatch( QuantifiersEngine* qe, InstMatch& m ){
- for( int i=0; i<(int)d_index.size(); i++ ){
- m.set( qe->getTermDatabase()->getInstantiationConstant( d_f, d_index_order[i] ), getTerm( i ));
- }
-}
-
-Node RepSetIterator::getTerm( int i ){
- TypeNode tn = d_f[0][d_index_order[i]].getType();
- Assert( d_model->d_rep_set.d_type_reps.find( tn )!=d_model->d_rep_set.d_type_reps.end() );
- int index = d_index_order[i];
- return d_model->d_rep_set.d_type_reps[tn][d_domain[index][d_index[index]]];
-}
-
-void RepSetIterator::debugPrint( const char* c ){
- for( int i=0; i<(int)d_index.size(); i++ ){
- Debug( c ) << i << " : " << d_index[i] << " : " << getTerm( i ) << std::endl;
- }
-}
-
-void RepSetIterator::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;
-}
-
-RepSetEvaluator::RepSetEvaluator( FirstOrderModel* m, RepSetIterator* ri ) : d_model( m ), d_riter( ri ){
- d_eval_formulas = 0;
- d_eval_uf_terms = 0;
- d_eval_lits = 0;
- d_eval_lits_unknown = 0;
-}
-
-//if evaluate( n ) = eVal,
-// let n' = d_riter * n be the formula n instantiated with the current values in r_iter
-// if eVal = 1, then n' is true, if eVal = -1, then n' is false,
-// if eVal = 0, then n' cannot be proven to be equal to phaseReq
-// if eVal is not 0, then
-// each n{d_riter->d_index[0]/x_0...d_riter->d_index[depIndex]/x_depIndex, */x_(depIndex+1) ... */x_n } is equivalent in the current model
-int RepSetEvaluator::evaluate( Node n, int& depIndex ){
- ++d_eval_formulas;
- //Debug("fmf-eval-debug") << "Evaluate " << n << " " << phaseReq << std::endl;
- //Notice() << "Eval " << n << std::endl;
- if( n.getKind()==NOT ){
- int val = evaluate( 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 = d_riter->getNumTerms();
- 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( 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( n[0], depIndex1 );
- if( eVal!=0 ){
- int depIndex2;
- int eVal2 = evaluate( 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, depIndex2;
- int eVal = evaluate( n[0], depIndex1 );
- if( eVal==0 ){
- //evaluate children to see if they are the same value
- int eval1 = evaluate( n[1], depIndex1 );
- if( eval1!=0 ){
- int eval2 = evaluate( n[1], depIndex2 );
- if( eval1==eval2 ){
- depIndex = depIndex1>depIndex2 ? depIndex1 : depIndex2;
- return eval1;
- }
- }
- }else{
- int eValT = evaluate( n[eVal==1 ? 1 : 2], depIndex2 );
- depIndex = depIndex1>depIndex2 ? depIndex1 : depIndex2;
- return eValT;
- }
- return 0;
- }else if( n.getKind()==FORALL ){
- return 0;
- }else{
- ++d_eval_lits;
- ////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-eval-debug") << "Evaluate literal " << n << std::endl;
- int retVal = 0;
- depIndex = d_riter->getNumTerms()-1;
- Node val = evaluateTerm( n, depIndex );
- if( !val.isNull() ){
- if( d_model->areEqual( val, d_model->d_true ) ){
- retVal = 1;
- }else if( d_model->areEqual( val, d_model->d_false ) ){
- retVal = -1;
- }else{
- if( val.getKind()==EQUAL ){
- if( d_model->areEqual( val[0], val[1] ) ){
- retVal = 1;
- }else if( d_model->areDisequal( val[0], val[1] ) ){
- retVal = -1;
- }
- }
- }
- }
- if( retVal!=0 ){
- Debug("fmf-eval-debug") << "Evaluate literal: return " << retVal << ", depIndex = " << depIndex << std::endl;
- }else{
- ++d_eval_lits_unknown;
- Debug("fmf-eval-amb") << "Neither true nor false : " << n << std::endl;
- //std::cout << "Neither true nor false : " << n << std::endl;
- //std::cout << " Value : " << val << std::endl;
- //for( int i=0; i<(int)n.getNumChildren(); i++ ){
- // std::cout << " " << i << " : " << n[i].getType() << std::endl;
- //}
- }
- return retVal;
- }
-}
-
-Node RepSetEvaluator::evaluateTerm( Node n, int& depIndex ){
- //Message() << "Eval term " << n << std::endl;
- if( !n.hasAttribute(InstConstantAttribute()) ){
- //if evaluating a ground term, just consult the standard getValue functionality
- depIndex = -1;
- return d_model->getValue( n );
- }else{
- Node val;
- depIndex = d_riter->getNumTerms()-1;
- //check the type of n
- if( n.getKind()==INST_CONSTANT ){
- int v = n.getAttribute(InstVarNumAttribute());
- depIndex = d_riter->d_var_order[ v ];
- val = d_riter->getTerm( v );
- }else if( n.getKind()==ITE ){
- int depIndex1, depIndex2;
- int eval = evaluate( n[0], depIndex1 );
- if( eval==0 ){
- //evaluate children to see if they are the same
- Node val1 = evaluateTerm( n[ 1 ], depIndex1 );
- Node val2 = evaluateTerm( n[ 2 ], depIndex2 );
- if( val1==val2 ){
- val = val1;
- depIndex = depIndex1>depIndex2 ? depIndex1 : depIndex2;
- }else{
- return Node::null();
- }
- }else{
- val = evaluateTerm( n[ eval==1 ? 1 : 2 ], depIndex2 );
- depIndex = depIndex1>depIndex2 ? depIndex1 : depIndex2;
- }
- }else{
- std::vector< int > children_depIndex;
- //for select, pre-process read over writes
- if( n.getKind()==SELECT ){
-#if 1
- //std::cout << "Evaluate " << n << std::endl;
- Node sel = evaluateTerm( n[1], depIndex );
- if( sel.isNull() ){
- depIndex = d_riter->getNumTerms()-1;
- return Node::null();
- }
- Node arr = d_model->getRepresentative( n[0] );
- //if( n[0]!=d_model->getRepresentative( n[0] ) ){
- // std::cout << n[0] << " is " << d_model->getRepresentative( n[0] ) << std::endl;
- //}
- int tempIndex;
- int eval = 1;
- while( arr.getKind()==STORE && eval!=0 ){
- eval = evaluate( sel.eqNode( arr[1] ), tempIndex );
- depIndex = tempIndex > depIndex ? tempIndex : depIndex;
- if( eval==1 ){
- val = evaluateTerm( arr[2], tempIndex );
- depIndex = tempIndex > depIndex ? tempIndex : depIndex;
- return val;
- }else if( eval==-1 ){
- arr = arr[0];
- }
- }
- arr = evaluateTerm( arr, tempIndex );
- depIndex = tempIndex > depIndex ? tempIndex : depIndex;
- val = NodeManager::currentNM()->mkNode( SELECT, arr, sel );
-#else
- val = evaluateTermDefault( n, depIndex, children_depIndex );
-#endif
- }else{
- //default term evaluate : evaluate all children, recreate the value
- val = evaluateTermDefault( n, depIndex, children_depIndex );
- }
- if( !val.isNull() ){
- bool setVal = false;
- //custom ways of evaluating terms
- if( n.getKind()==APPLY_UF ){
- Node op = n.getOperator();
- //Debug("fmf-eval-debug") << "Evaluate term " << n << " (" << gn << ")" << std::endl;
- //if it is a defined UF, then consult the interpretation
- if( d_model->d_uf_model_tree.find( op )!=d_model->d_uf_model_tree.end() ){
- ++d_eval_uf_terms;
- int argDepIndex = 0;
- //make the term model specifically for n
- makeEvalUfModel( n );
- //now, consult the model
- if( d_eval_uf_use_default[n] ){
- val = d_model->d_uf_model_tree[op].getValue( d_model, val, argDepIndex );
- }else{
- val = d_eval_uf_model[ n ].getValue( d_model, val, argDepIndex );
- }
- //Debug("fmf-eval-debug") << "Evaluate term " << n << " (" << gn << ")" << std::endl;
- //d_eval_uf_model[ n ].debugPrint("fmf-eval-debug", d_qe );
- Assert( !val.isNull() );
- //recalculate the depIndex
- depIndex = -1;
- for( int i=0; i<argDepIndex; i++ ){
- int index = d_eval_uf_use_default[n] ? i : d_eval_term_index_order[n][i];
- Debug("fmf-eval-debug") << "Add variables from " << index << "..." << std::endl;
- if( children_depIndex[index]>depIndex ){
- depIndex = children_depIndex[index];
- }
- }
- setVal = true;
- }
- }else if( n.getKind()==SELECT ){
- //we are free to interpret this term however we want
- }
- //if not set already, rewrite and consult model for interpretation
- if( !setVal ){
- val = Rewriter::rewrite( val );
- if( !val.isConst() ){
- //FIXME: we cannot do this until we trust all theories collectModelInfo!
- //val = d_model->getInterpretedValue( val );
- //val = d_model->getRepresentative( val );
- }
- }
- Debug("fmf-eval-debug") << "Evaluate term " << n << " = ";
- d_model->printRepresentativeDebug( "fmf-eval-debug", val );
- Debug("fmf-eval-debug") << ", depIndex = " << depIndex << std::endl;
- }
- }
- return val;
- }
-}
-
-Node RepSetEvaluator::evaluateTermDefault( Node n, int& depIndex, std::vector< int >& childDepIndex ){
- depIndex = -1;
- if( n.getNumChildren()==0 ){
- return n;
- }else{
- //first we must evaluate the arguments
- std::vector< Node > children;
- if( n.getMetaKind()==kind::metakind::PARAMETERIZED ){
- children.push_back( n.getOperator() );
- }
- //for each argument, calculate its value, and the variables its value depends upon
- for( int i=0; i<(int)n.getNumChildren(); i++ ){
- childDepIndex.push_back( -1 );
- Node nn = evaluateTerm( n[i], childDepIndex[i] );
- if( nn.isNull() ){
- depIndex = d_riter->getNumTerms()-1;
- return nn;
- }else{
- children.push_back( nn );
- if( childDepIndex[i]>depIndex ){
- depIndex = childDepIndex[i];
- }
- }
- }
- //recreate the value
- Node val = NodeManager::currentNM()->mkNode( n.getKind(), children );
- return val;
- }
-}
-
-void RepSetEvaluator::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();
-}
-
-void RepSetEvaluator::makeEvalUfModel( Node n ){
- if( d_eval_uf_model.find( n )==d_eval_uf_model.end() ){
- makeEvalUfIndexOrder( n );
- if( !d_eval_uf_use_default[n] ){
- Node op = n.getOperator();
- d_eval_uf_model[n] = uf::UfModelTree( op, d_eval_term_index_order[n] );
- d_model->d_uf_model_gen[op].makeModel( d_model, d_eval_uf_model[n] );
- //Debug("fmf-index-order") << "Make model for " << n << " : " << std::endl;
- //d_eval_uf_model[n].debugPrint( "fmf-index-order", d_qe, 2 );
- }
- }
-}
-
-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 RepSetEvaluator::makeEvalUfIndexOrder( Node n ){
- if( d_eval_term_index_order.find( n )==d_eval_term_index_order.end() ){
-#ifdef USE_INDEX_ORDERING
- //sort arguments in order of least significant vs. most significant variable in default ordering
- std::map< Node, std::vector< int > > argIndex;
- std::vector< Node > args;
- for( int i=0; i<(int)n.getNumChildren(); i++ ){
- if( argIndex.find( n[i] )==argIndex.end() ){
- args.push_back( n[i] );
- }
- argIndex[n[i]].push_back( i );
- }
- sortGetMaxVariableNum sgmvn;
- std::sort( args.begin(), args.end(), sgmvn );
- for( int i=0; i<(int)args.size(); i++ ){
- for( int j=0; j<(int)argIndex[ args[i] ].size(); j++ ){
- d_eval_term_index_order[n].push_back( argIndex[ args[i] ][j] );
- }
- }
- bool useDefault = true;
- for( int i=0; i<(int)d_eval_term_index_order[n].size(); i++ ){
- if( i!=d_eval_term_index_order[n][i] ){
- useDefault = false;
- break;
- }
- }
- d_eval_uf_use_default[n] = useDefault;
- Debug("fmf-index-order") << "Will consider the following index ordering for " << n << " : ";
- for( int i=0; i<(int)d_eval_term_index_order[n].size(); i++ ){
- Debug("fmf-index-order") << d_eval_term_index_order[n][i] << " ";
- }
- Debug("fmf-index-order") << std::endl;
-#else
- d_eval_uf_use_default[n] = true;
-#endif
- }
-}
-
-
+++ /dev/null
-/********************* */
-/*! \file rep_set_iterator.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 rep_set_iterator class
- **/
-
-#include "cvc4_private.h"
-
-#ifndef __CVC4__THEORY__QUANTIFIERS__REP_SET_ITERATOR_H
-#define __CVC4__THEORY__QUANTIFIERS__REP_SET_ITERATOR_H
-
-#include "theory/quantifiers_engine.h"
-#include "theory/quantifiers/first_order_model.h"
-
-namespace CVC4 {
-namespace theory {
-namespace quantifiers {
-
-/** this class iterates over a RepSet */
-class RepSetIterator {
-public:
- RepSetIterator( Node f, FirstOrderModel* model );
- ~RepSetIterator(){}
- //pointer to quantifier
- Node d_f;
- //pointer to model
- FirstOrderModel* d_model;
- //index we are considering
- std::vector< int > d_index;
- //domain we are considering
- std::vector< RepDomain > d_domain;
- //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:
- /** set index order */
- void setIndexOrder( std::vector< int >& indexOrder );
- /** set domain */
- void setDomain( std::vector< RepDomain >& domain );
- /** increment the iterator */
- void increment2( int counter );
- void increment();
- /** 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(); }
- /** debug print */
- void debugPrint( const char* c );
- void debugPrintSmall( const char* c );
-};
-
-class RepSetEvaluator
-{
-private:
- FirstOrderModel* d_model;
- RepSetIterator* d_riter;
-private: //for Theory UF:
- //map from terms to the models used to calculate their value
- std::map< Node, bool > d_eval_uf_use_default;
- std::map< Node, uf::UfModelTree > d_eval_uf_model;
- void makeEvalUfModel( Node n );
- //index ordering to use for each term
- std::map< Node, std::vector< int > > d_eval_term_index_order;
- int getMaxVariableNum( int n );
- void makeEvalUfIndexOrder( Node n );
-private:
- //default evaluate term function
- Node evaluateTermDefault( Node n, int& depIndex, std::vector< int >& childDepIndex );
- //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;
-public:
- RepSetEvaluator( FirstOrderModel* m, RepSetIterator* ri );
- virtual ~RepSetEvaluator(){}
- /** evaluate functions */
- int evaluate( Node n, int& depIndex );
- Node evaluateTerm( Node n, int& depIndex );
-public:
- //statistics
- int d_eval_formulas;
- int d_eval_uf_terms;
- int d_eval_lits;
- int d_eval_lits_unknown;
-};/* class RepSetEvaluator */
-
-}/* CVC4::theory::quantifiers namespace */
-}/* CVC4::theory namespace */
-}/* CVC4 namespace */
-
-#endif
//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() ){
+ if( it->second[0].getType().isBoolean() ){
d_pred_map_trie[ 0 ][ it->first ].d_data.clear();
d_pred_map_trie[ 1 ][ it->first ].d_data.clear();
}else{
ss << Expr::setlanguage(options::outputLanguage());
ss << "e_" << tn;
mbt = NodeManager::currentNM()->mkSkolem( ss.str(), tn );
+ Trace("mkVar") << "ModelBasis:: Make variable " << mbt << " : " << tn << std::endl;
}else{
mbt = d_type_map[ tn ][ 0 ];
}
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() ){
+ if( tn.isInteger() || tn.isReal() ){
Rational z(0);
d_free_vars[tn] = NodeManager::currentNM()->mkConst( z );
}else{
if( d_type_map[ tn ].empty() ){
d_free_vars[tn] = NodeManager::currentNM()->mkSkolem( tn );
+ Trace("mkVar") << "FreeVar:: Make variable " << d_free_vars[tn] << " : " << tn << std::endl;
}else{
d_free_vars[tn] = d_type_map[ tn ][ 0 ];
}
#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"
#include "theory/quantifiers/options.h"
#include "theory/quantifiers/term_database.h"
+#include "theory/quantifiers/quantifiers_attributes.h"
using namespace std;
using namespace CVC4;
d_numRestarts(0){
d_numInstantiations = 0;
d_baseDecLevel = -1;
+ out.handleUserAttribute( "axiom", this );
+ out.handleUserAttribute( "conjecture", this );
}
}
}
-void TheoryQuantifiers::collectModelInfo( TheoryModel* m ){
+void TheoryQuantifiers::collectModelInfo( TheoryModel* m, bool fullModel ){
}
}
void TheoryQuantifiers::propagate(Effort level){
- CodeTimer codeTimer(d_theoryTime);
+ //CodeTimer codeTimer(d_theoryTime);
+ //getQuantifiersEngine()->propagate( level );
+}
- getQuantifiersEngine()->propagate( level );
+Node TheoryQuantifiers::getNextDecisionRequest(){
+ return getQuantifiersEngine()->getNextDecisionRequest();
}
void TheoryQuantifiers::assertUniversal( Node n ){
}
}
-void TheoryQuantifiers::performCheck(Effort e){
- getQuantifiersEngine()->check( e );
+void TheoryQuantifiers::setUserAttribute( std::string& attr, Node n ){
+ QuantifiersAttributes::setUserAttribute( attr, n );
}
void presolve();
void check(Effort e);
void propagate(Effort level);
+ Node getNextDecisionRequest();
Node getValue(TNode n);
- void collectModelInfo( TheoryModel* m );
+ void collectModelInfo( TheoryModel* m, bool fullModel );
void shutdown() { }
std::string identify() const { return std::string("TheoryQuantifiers"); }
bool flipDecision();
+ void setUserAttribute( std::string& attr, Node n );
private:
void assertUniversal( Node n );
void assertExistential( Node n );
bool restart();
-public:
- void performCheck(Effort e);
};/* class TheoryQuantifiers */
}/* CVC4::theory::quantifiers namespace */
d_hasAddedLemma = false;
//the model object
- d_model = new quantifiers::FirstOrderModel( this, c, "FirstOrderModel" );
+ d_model = new quantifiers::FirstOrderModel( c, "FirstOrderModel" );
//add quantifiers modules
if( !options::finiteModelFind() || options::fmfInstEngine() ){
d_inst_engine = NULL;
}
if( options::finiteModelFind() ){
- d_model_engine = new quantifiers::ModelEngine( this );
+ d_model_engine = new quantifiers::ModelEngine( c, this );
d_modules.push_back( d_model_engine );
}else{
d_model_engine = NULL;
d_hasAddedLemma = false;
d_model_set = false;
+ d_resetInstRound = false;
if( e==Theory::EFFORT_LAST_CALL ){
++(d_statistics.d_instantiation_rounds_lc);
}else if( e==Theory::EFFORT_FULL ){
++(d_statistics.d_instantiation_rounds);
}
+ //if effort is last call, try to minimize model first
+ if( e==Theory::EFFORT_LAST_CALL && options::finiteModelFind() ){
+ //first, check if we can minimize the model further
+ if( !((uf::TheoryUF*)getTheoryEngine()->theoryOf( THEORY_UF ))->getStrongSolver()->minimize() ){
+ return;
+ }
+ }
for( int i=0; i<(int)d_modules.size(); i++ ){
d_modules[i]->check( e );
}
//build the model if not done so already
// this happens if no quantifiers are currently asserted and no model-building module is enabled
if( options::produceModels() && e==Theory::EFFORT_LAST_CALL && !d_hasAddedLemma && !d_model_set ){
- d_te->getModelBuilder()->buildModel( d_model );
+ d_te->getModelBuilder()->buildModel( d_model, true );
}
}
void QuantifiersEngine::assertNode( Node f ){
Assert( f.getKind()==FORALL );
for( int j=0; j<(int)d_quant_rewritten[f].size(); j++ ){
- d_model->d_forall_asserts.push_back( d_quant_rewritten[f][j] );
+ d_model->assertQuantifier( d_quant_rewritten[f][j] );
for( int i=0; i<(int)d_modules.size(); i++ ){
d_modules[i]->assertNode( d_quant_rewritten[f][j] );
}
}
}
+Node QuantifiersEngine::getNextDecisionRequest(){
+ for( int i=0; i<(int)d_modules.size(); i++ ){
+ Node n = d_modules[i]->getNextDecisionRequest();
+ if( !n.isNull() ){
+ return n;
+ }
+ }
+ return Node::null();
+}
+
void QuantifiersEngine::resetInstantiationRound( Theory::Effort level ){
+ //if( !d_resetInstRound ){
+ d_resetInstRound = true;
for( theory::TheoryId i=theory::THEORY_FIRST; i<theory::THEORY_LAST; ++i ){
if( getInstantiator( i ) ){
getInstantiator( i )->resetInstantiationRound( level );
}
}
getTermDatabase()->reset( level );
+ //}
}
void QuantifiersEngine::addTermToDatabase( Node n, bool withinQuant ){
}
}
-bool QuantifiersEngine::addInstantiation( Node f, std::vector< Node >& terms )
+bool QuantifiersEngine::addInstantiation( Node f, std::vector< Node >& vars, 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_term_db->d_vars[f].size()==terms.size() && d_term_db->d_vars[f].size()==f[0].getNumChildren() );
- Node body = f[ 1 ].substitute( d_term_db->d_vars[f].begin(), d_term_db->d_vars[f].end(),
- terms.begin(), terms.end() );
- NodeBuilder<> nb(kind::OR);
- nb << d_rewritten_quant[f].notNode() << body;
- Node lem = nb;
+ Assert( vars.size()==terms.size() );
+ Node body = f[ 1 ].substitute( vars.begin(), vars.end(), terms.begin(), terms.end() );
+ Node lem;
+ if( d_term_db->d_vars[f].size()==vars.size() ){
+ NodeBuilder<> nb(kind::OR);
+ nb << d_rewritten_quant[f].notNode() << body;
+ lem = nb;
+ }else{
+ //doing a partial instantiation, must add quantifier for all uninstantiated variables
+ Notice() << "Partial instantiation not implemented yet." << std::endl;
+ Unimplemented();
+ }
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;
+ Trace("inst") << "*** Instantiate " << f << " with " << std::endl;
uint64_t maxInstLevel = 0;
for( int i=0; i<(int)terms.size(); i++ ){
if( terms[i].hasAttribute(InstConstantAttribute()) ){
}
Unreachable("Bad instantiation");
}else{
- Debug("inst") << " " << terms[i];
- //Notice() << " " << terms[i] << std::endl;
+ Trace("inst") << " " << terms[i];
//Debug("inst-engine") << " " << terms[i].getAttribute(InstLevelAttribute());
- Debug("inst") << std::endl;
+ Trace("inst") << std::endl;
if( terms[i].hasAttribute(InstLevelAttribute()) ){
if( terms[i].getAttribute(InstLevelAttribute())>maxInstLevel ){
maxInstLevel = terms[i].getAttribute(InstLevelAttribute());
}
}
}
+ Trace("inst-debug") << "*** Lemma is " << lem << std::endl;
d_term_db->setInstantiationLevelAttr( body, maxInstLevel+1 );
++(d_statistics.d_instantiations);
d_statistics.d_total_inst_var += (int)terms.size();
}
}
-bool QuantifiersEngine::addInstantiation( Node f, InstMatch& m ){
- m.makeComplete( f, this );
+bool QuantifiersEngine::addInstantiation( Node f, InstMatch& m, bool makeComplete ){
+ //make sure there are values for each variable we are instantiating
+ if( makeComplete ){
+ m.makeComplete( f, this );
+ }
+ //make it representative, this is helpful for recognizing duplication
m.makeRepresentative( this );
- Debug("quant-duplicate") << "After make rep: " << m << std::endl;
+ Trace("inst-add") << "Add instantiation: " << m << std::endl;
+ //check for duplication modulo equality
if( !d_inst_match_trie[f].addInstMatch( this, f, m, true ) ){
- Debug("quant-duplicate") << " -> Already exists." << std::endl;
+ Trace("inst-add") << " -> Already exists." << std::endl;
++(d_statistics.d_inst_duplicate);
return false;
}
- Debug("quant-duplicate") << " -> Does not exist." << std::endl;
+ //compute the vector of terms for the instantiation
std::vector< Node > match;
m.computeTermVec( d_term_db->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 );
- // }
- //}
+ //add the instantiation
+ bool addedInst = false;
+ if( match.size()==d_term_db->d_vars[f].size() ){
+ addedInst = addInstantiation( f, d_term_db->d_vars[f], match );
+ }else{
+ //must compute the subset of variables we are instantiating
+ std::vector< Node > vars;
+ for( size_t i=0; i<d_term_db->d_vars[f].size(); i++ ){
+ Node val = m.get( getTermDatabase()->getInstantiationConstant( f, i ) );
+ if( !val.isNull() ){
+ vars.push_back( d_term_db->d_vars[f][i] );
+ }
+ }
+ addedInst = addInstantiation( f, vars, match );
+ }
+ //report the result
+ if( addedInst ){
+ Trace("inst-add") << " -> Success." << std::endl;
return true;
+ }else{
+ Trace("inst-add") << " -> Lemma already exists." << std::endl;
+ return false;
}
- return false;
}
bool QuantifiersEngine::addSplit( Node n, bool reqPhase, bool reqPhasePol ){
/* Called for new quantifiers */
virtual void registerQuantifier( Node n ) = 0;
virtual void assertNode( Node n ) = 0;
- virtual void propagate( Theory::Effort level ) = 0;
+ virtual void propagate( Theory::Effort level ){}
+ virtual Node getNextDecisionRequest() { return TNode::null(); }
virtual Node explain(TNode n) = 0;
};/* class QuantifiersModule */
quantifiers::FirstOrderModel* d_model;
/** has the model been set? */
bool d_model_set;
+ /** has resetInstantiationRound() been called on this check(...) */
+ bool d_resetInstRound;
/** 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 */
void assertNode( Node f );
/** propagate */
void propagate( Theory::Effort level );
+ /** get next decision request */
+ Node getNextDecisionRequest();
/** reset instantiation round */
void resetInstantiationRound( Theory::Effort level );
/** add lemma lem */
bool addLemma( Node lem );
/** instantiate f with arguments terms */
- bool addInstantiation( Node f, std::vector< Node >& terms );
+ bool addInstantiation( Node f, std::vector< Node >& vars, std::vector< Node >& terms );
/** do instantiation specified by m */
- bool addInstantiation( Node f, InstMatch& m );
+ bool addInstantiation( Node f, InstMatch& m, bool makeComplete = true );
/** split on node n */
bool addSplit( Node n, bool reqPhase = false, bool reqPhasePol = true );
/** add split equality */
--- /dev/null
+/********************* */\r
+/*! \file rep_set.cpp\r
+ ** \verbatim\r
+ ** Original author: ajreynol\r
+ ** Major contributors: none\r
+ ** Minor contributors (to current version): none\r
+ ** This file is part of the CVC4 prototype.\r
+ ** Copyright (c) 2009, 2010, 2011 The Analysis of Computer Systems Group (ACSys)\r
+ ** Courant Institute of Mathematical Sciences\r
+ ** New York University\r
+ ** See the file COPYING in the top-level source directory for licensing\r
+ ** information.\endverbatim\r
+ **\r
+ ** \brief Implementation of representative set\r
+ **/\r
+\r
+#include "theory/rep_set.h"\r
+#include "theory/type_enumerator.h"\r
+\r
+using namespace std;\r
+using namespace CVC4;\r
+using namespace CVC4::kind;\r
+using namespace CVC4::context;\r
+using namespace CVC4::theory;\r
+\r
+void RepSet::clear(){\r
+ d_type_reps.clear();\r
+ d_type_complete.clear();\r
+ d_tmap.clear();\r
+}\r
+\r
+void RepSet::add( Node n ){\r
+ TypeNode t = n.getType();\r
+ d_tmap[ n ] = (int)d_type_reps[t].size();\r
+ d_type_reps[t].push_back( n );\r
+}\r
+\r
+void RepSet::complete( TypeNode t ){\r
+ if( d_type_complete.find( t )==d_type_complete.end() ){\r
+ d_type_complete[t] = true;\r
+ TypeEnumerator te(t);\r
+ while( !te.isFinished() ){\r
+ Node n = *te;\r
+ if( std::find( d_type_reps[t].begin(), d_type_reps[t].end(), n )==d_type_reps[t].end() ){\r
+ add( n );\r
+ }\r
+ ++te;\r
+ }\r
+ for( size_t i=0; i<d_type_reps[t].size(); i++ ){\r
+ Trace("reps-complete") << d_type_reps[t][i] << " ";\r
+ }\r
+ Trace("reps-complete") << std::endl;\r
+ }\r
+}\r
+\r
+void RepSet::toStream(std::ostream& out){\r
+#if 0\r
+ for( std::map< TypeNode, std::vector< Node > >::iterator it = d_type_reps.begin(); it != d_type_reps.end(); ++it ){\r
+ out << it->first << " : " << std::endl;\r
+ for( int i=0; i<(int)it->second.size(); i++ ){\r
+ out << " " << i << ": " << it->second[i] << std::endl;\r
+ }\r
+ }\r
+#else\r
+ for( std::map< TypeNode, std::vector< Node > >::iterator it = d_type_reps.begin(); it != d_type_reps.end(); ++it ){\r
+ if( !it->first.isFunction() && !it->first.isPredicate() ){\r
+ out << "(" << it->first << " " << it->second.size();\r
+ out << " (";\r
+ for( int i=0; i<(int)it->second.size(); i++ ){\r
+ if( i>0 ){ out << " "; }\r
+ out << it->second[i];\r
+ }\r
+ out << ")";\r
+ out << ")" << std::endl;\r
+ }\r
+ }\r
+#endif\r
+}\r
+\r
+\r
+RepSetIterator::RepSetIterator( RepSet* rs ) : d_rep_set( rs ){\r
+ d_incomplete = false;\r
+\r
+}\r
+\r
+void RepSetIterator::setQuantifier( Node f ){\r
+ Assert( d_types.empty() );\r
+ //store indicies\r
+ for( size_t i=0; i<f[0].getNumChildren(); i++ ){\r
+ d_types.push_back( f[0][i].getType() );\r
+ }\r
+ initialize();\r
+}\r
+\r
+void RepSetIterator::setFunctionDomain( Node op ){\r
+ Assert( d_types.empty() );\r
+ TypeNode tn = op.getType();\r
+ for( size_t i=0; i<tn.getNumChildren()-1; i++ ){\r
+ d_types.push_back( tn[i] );\r
+ }\r
+ initialize();\r
+}\r
+\r
+void RepSetIterator::initialize(){\r
+ for( size_t i=0; i<d_types.size(); i++ ){\r
+ d_index.push_back( 0 );\r
+ //store default index order\r
+ d_index_order.push_back( i );\r
+ d_var_order[i] = i;\r
+ //store default domain\r
+ d_domain.push_back( RepDomain() );\r
+ TypeNode tn = d_types[i];\r
+ if( tn.isSort() ){\r
+ if( !d_rep_set->hasType( tn ) ){\r
+ Node var = NodeManager::currentNM()->mkSkolem( tn );\r
+ Trace("mkVar") << "RepSetIterator:: Make variable " << var << " : " << tn << std::endl;\r
+ d_rep_set->add( var );\r
+ }\r
+ }else if( tn.isInteger() || tn.isReal() ){\r
+ Trace("fmf-incomplete") << "Incomplete because of infinite type " << tn << std::endl;\r
+ d_incomplete = true;\r
+ }else if( tn.isDatatype() ){\r
+ const Datatype& dt = ((DatatypeType)(tn).toType()).getDatatype();\r
+ //if finite, then complete all values of the domain\r
+ if( dt.isFinite() ){\r
+ d_rep_set->complete( tn );\r
+ //d_incomplete = true;\r
+ }else{\r
+ Trace("fmf-incomplete") << "Incomplete because of infinite datatype " << tn << std::endl;\r
+ d_incomplete = true;\r
+ }\r
+ }else{\r
+ Trace("fmf-incomplete") << "Incomplete because of type " << tn << std::endl;\r
+ d_incomplete = true;\r
+ }\r
+ if( d_rep_set->hasType( tn ) ){\r
+ for( size_t j=0; j<d_rep_set->d_type_reps[tn].size(); j++ ){\r
+ d_domain[i].push_back( j );\r
+ }\r
+ }else{\r
+ Trace("fmf-incomplete") << "Incomplete, unknown type " << tn << std::endl;\r
+ d_incomplete = true;\r
+ Unimplemented("Cannot create representative set iterator for unknown type quantifier");\r
+ }\r
+ }\r
+}\r
+\r
+void RepSetIterator::setIndexOrder( std::vector< int >& indexOrder ){\r
+ d_index_order.clear();\r
+ d_index_order.insert( d_index_order.begin(), indexOrder.begin(), indexOrder.end() );\r
+ //make the d_var_order mapping\r
+ for( int i=0; i<(int)d_index_order.size(); i++ ){\r
+ d_var_order[d_index_order[i]] = i;\r
+ }\r
+}\r
+\r
+void RepSetIterator::setDomain( std::vector< RepDomain >& domain ){\r
+ d_domain.clear();\r
+ d_domain.insert( d_domain.begin(), domain.begin(), domain.end() );\r
+ //we are done if a domain is empty\r
+ for( int i=0; i<(int)d_domain.size(); i++ ){\r
+ if( d_domain[i].empty() ){\r
+ d_index.clear();\r
+ }\r
+ }\r
+}\r
+\r
+void RepSetIterator::increment2( int counter ){\r
+ Assert( !isFinished() );\r
+#ifdef DISABLE_EVAL_SKIP_MULTIPLE\r
+ counter = (int)d_index.size()-1;\r
+#endif\r
+ //increment d_index\r
+ while( counter>=0 && d_index[counter]==(int)(d_domain[counter].size()-1) ){\r
+ counter--;\r
+ }\r
+ if( counter==-1 ){\r
+ d_index.clear();\r
+ }else{\r
+ for( int i=(int)d_index.size()-1; i>counter; i-- ){\r
+ d_index[i] = 0;\r
+ }\r
+ d_index[counter]++;\r
+ }\r
+}\r
+\r
+void RepSetIterator::increment(){\r
+ if( !isFinished() ){\r
+ increment2( (int)d_index.size()-1 );\r
+ }\r
+}\r
+\r
+bool RepSetIterator::isFinished(){\r
+ return d_index.empty();\r
+}\r
+\r
+Node RepSetIterator::getTerm( int i ){\r
+ TypeNode tn = d_types[d_index_order[i]];\r
+ Assert( d_rep_set->d_type_reps.find( tn )!=d_rep_set->d_type_reps.end() );\r
+ int index = d_index_order[i];\r
+ return d_rep_set->d_type_reps[tn][d_domain[index][d_index[index]]];\r
+}\r
+\r
+void RepSetIterator::debugPrint( const char* c ){\r
+ for( int i=0; i<(int)d_index.size(); i++ ){\r
+ Debug( c ) << i << " : " << d_index[i] << " : " << getTerm( i ) << std::endl;\r
+ }\r
+}\r
+\r
+void RepSetIterator::debugPrintSmall( const char* c ){\r
+ Debug( c ) << "RI: ";\r
+ for( int i=0; i<(int)d_index.size(); i++ ){\r
+ Debug( c ) << d_index[i] << ": " << getTerm( i ) << " ";\r
+ }\r
+ Debug( c ) << std::endl;\r
+}\r
--- /dev/null
+/********************* */\r
+/*! \file rep_set.h\r
+ ** \verbatim\r
+ ** Original author: ajreynol\r
+ ** Major contributors: none\r
+ ** Minor contributors (to current version): none\r
+ ** This file is part of the CVC4 prototype.\r
+ ** Copyright (c) 2009, 2010, 2011 The Analysis of Computer Systems Group (ACSys)\r
+ ** Courant Institute of Mathematical Sciences\r
+ ** New York University\r
+ ** See the file COPYING in the top-level source directory for licensing\r
+ ** information.\endverbatim\r
+ **\r
+ ** \brief Representative set class and utilities\r
+ **/\r
+\r
+#include "cvc4_private.h"\r
+\r
+#ifndef __CVC4__REP_SET_H\r
+#define __CVC4__REP_SET_H\r
+\r
+#include "expr/node.h"\r
+#include <map>\r
+\r
+namespace CVC4 {\r
+namespace theory {\r
+\r
+/** this class stores a representative set */\r
+class RepSet {\r
+public:\r
+ RepSet(){}\r
+ ~RepSet(){}\r
+ std::map< TypeNode, std::vector< Node > > d_type_reps;\r
+ std::map< TypeNode, bool > d_type_complete;\r
+ std::map< Node, int > d_tmap;\r
+ /** clear the set */\r
+ void clear();\r
+ /** has type */\r
+ bool hasType( TypeNode tn ) { return d_type_reps.find( tn )!=d_type_reps.end(); }\r
+ /** add representative for type */\r
+ void add( Node n );\r
+ /** returns index in d_type_reps for node n */\r
+ int getIndexFor( Node n ) { return d_tmap.find( n )!=d_tmap.end() ? d_tmap[n] : -1; }\r
+ /** complete all values */\r
+ void complete( TypeNode t );\r
+ /** debug print */\r
+ void toStream(std::ostream& out);\r
+};\r
+\r
+//representative domain\r
+typedef std::vector< int > RepDomain;\r
+\r
+/** this class iterates over a RepSet */\r
+class RepSetIterator {\r
+private:\r
+ //initialize function\r
+ void initialize();\r
+public:\r
+ RepSetIterator( RepSet* rs );\r
+ ~RepSetIterator(){}\r
+ //set that this iterator will be iterating over instantiations for a quantifier\r
+ void setQuantifier( Node f );\r
+ //set that this iterator will be iterating over the domain of a function\r
+ void setFunctionDomain( Node op );\r
+public:\r
+ //pointer to model\r
+ RepSet* d_rep_set;\r
+ //index we are considering\r
+ std::vector< int > d_index;\r
+ //types we are considering\r
+ std::vector< TypeNode > d_types;\r
+ //domain we are considering\r
+ std::vector< RepDomain > d_domain;\r
+ //are we only considering a strict subset of the domain of the quantifier?\r
+ bool d_incomplete;\r
+ //ordering for variables we are indexing over\r
+ // for example, given reps = { a, b } and quantifier forall( x, y, z ) P( x, y, z ) with d_index_order = { 2, 0, 1 },\r
+ // then we consider instantiations in this order:\r
+ // a/x a/y a/z\r
+ // a/x b/y a/z\r
+ // b/x a/y a/z\r
+ // b/x b/y a/z\r
+ // ...\r
+ std::vector< int > d_index_order;\r
+ //variables to index they are considered at\r
+ // for example, if d_index_order = { 2, 0, 1 }\r
+ // then d_var_order = { 0 -> 1, 1 -> 2, 2 -> 0 }\r
+ std::map< int, int > d_var_order;\r
+public:\r
+ /** set index order */\r
+ void setIndexOrder( std::vector< int >& indexOrder );\r
+ /** set domain */\r
+ void setDomain( std::vector< RepDomain >& domain );\r
+ /** increment the iterator at index=counter */\r
+ void increment2( int counter );\r
+ /** increment the iterator */\r
+ void increment();\r
+ /** is the iterator finished? */\r
+ bool isFinished();\r
+ /** get the i_th term we are considering */\r
+ Node getTerm( int i );\r
+ /** get the number of terms we are considering */\r
+ int getNumTerms() { return (int)d_index_order.size(); }\r
+ /** debug print */\r
+ void debugPrint( const char* c );\r
+ void debugPrintSmall( const char* c );\r
+};\r
+\r
+}\r
+}\r
+\r
+#endif
\ No newline at end of file
return normalizeConjunction(explanation);
}
-void TheoryRewriteRules::collectModelInfo( TheoryModel* m ){
+void TheoryRewriteRules::collectModelInfo( TheoryModel* m, bool fullModel ){
}
/** Usual function for theories */
void check(Theory::Effort e);
Node explain(TNode n);
- void collectModelInfo( TheoryModel* m );
+ void collectModelInfo( TheoryModel* m, bool fullModel );
void notifyEq(TNode lhs, TNode rhs);
std::string identify() const {
return "THEORY_REWRITERULES";
return false;
}
- // Propagate away
+ // Propagate away
Node equality = a.eqNode(b);
if (value) {
d_theoryEngine->assertToTheory(equality, theory, THEORY_BUILTIN);
if (newlyNotified == 0) {
return;
}
-
+
Debug("shared-terms-database") << "SharedTermsDatabase::markNotified(" << term << ")" << endl;
// First update the set of notified theories for this term
d_alreadyNotifiedMap[term] = Theory::setUnion(newlyNotified, alreadyNotified);
// Mark the shared terms in the equality engine
- theory::TheoryId currentTheory;
+ theory::TheoryId currentTheory;
while ((currentTheory = Theory::setPop(newlyNotified)) != THEORY_LAST) {
- d_equalityEngine.addTriggerTerm(term, currentTheory);
+ d_equalityEngine.addTriggerTerm(term, currentTheory);
}
-
+
// Check for any conflits
- checkForConflict();
+ checkForConflict();
}
bool SharedTermsDatabase::areEqual(TNode a, TNode b) const {
// since one (or both) of them is a constant, and the other is in the equality engine, they are not same
return false;
}
-}
+}
bool SharedTermsDatabase::areDisequal(TNode a, TNode b) const {
if (d_equalityEngine.hasTerm(a) && d_equalityEngine.hasTerm(b)) {
std::vector<TNode> assumptions;
d_equalityEngine.explainEquality(d_conflictLHS, d_conflictRHS, d_conflictPolarity, assumptions);
Node conflict = mkAnd(assumptions);
- d_theoryEngine->conflict(conflict, THEORY_BUILTIN);
+ d_theoryEngine->conflict(conflict, THEORY_BUILTIN);
d_conflictLHS = d_conflictRHS = Node::null();
}
}
Assert(atom.getKind() == kind::EQUAL);
std::vector<TNode> assumptions;
d_equalityEngine.explainEquality(atom[0], atom[1], polarity, assumptions);
- return mkAnd(assumptions);
+ return mkAnd(assumptions);
}
+void SharedTermsDatabase::collectModelInfo( theory::TheoryModel* m, bool fullModel ){
+ m->assertEqualityEngine( &d_equalityEngine );
+}
* get equality engine
*/
theory::eq::EqualityEngine* getEqualityEngine() { return &d_equalityEngine; }
+
+ /**
+ * collect model info
+ */
+ void collectModelInfo( theory::TheoryModel* m, bool fullModel );
protected:
/**
#include "theory/term_registration_visitor.h"
#include "theory/theory_engine.h"
+#include "theory/quantifiers/options.h"
using namespace std;
using namespace CVC4;
if( ( parent.getKind() == kind::FORALL ||
parent.getKind() == kind::EXISTS ||
- parent.getKind() == kind::REWRITE_RULE ) &&
+ parent.getKind() == kind::REWRITE_RULE /*||
+ parent.getKind() == kind::CARDINALITY_CONSTRAINT*/ ) &&
current != parent ) {
Debug("register::internal") << "quantifier:true" << std::endl;
return true;
if( ( parent.getKind() == kind::FORALL ||
parent.getKind() == kind::EXISTS ||
- parent.getKind() == kind::REWRITE_RULE) &&
+ parent.getKind() == kind::REWRITE_RULE /*||
+ parent.getKind() == kind::CARDINALITY_CONSTRAINT*/ ) &&
current != parent ) {
Debug("register::internal") << "quantifier:true" << std::endl;
return true;
TheoryId parentTheoryId = Theory::theoryOf(parent);
// Should we use the theory of the type
+#if 0
bool useType = current != parent && currentTheoryId != parentTheoryId;
+#else
+ bool useType = false;
+ TheoryId typeTheoryId = THEORY_LAST;
+
+ if (current != parent) {
+ if (currentTheoryId != parentTheoryId) {
+ // If enclosed by different theories it's shared -- in read(a, f(a)) f(a) should be shared with integers
+ TypeNode type = current.getType();
+ useType = true;
+ typeTheoryId = Theory::theoryOf(type);
+ } else {
+ TypeNode type = current.getType();
+ typeTheoryId = Theory::theoryOf(type);
+ if (typeTheoryId != currentTheoryId) {
+ if (options::finiteModelFind() && type.isSort()) {
+ // We're looking for finite models
+ useType = true;
+ } else {
+ Cardinality card = type.getCardinality();
+ if (card.isFinite()) {
+ useType = true;
+ }
+ }
+ }
+ }
+ }
+#endif
if (Theory::setContains(currentTheoryId, theories)) {
if (Theory::setContains(parentTheoryId, theories)) {
if (useType) {
- TheoryId typeTheoryId = Theory::theoryOf(current.getType());
+ ////TheoryId typeTheoryId = Theory::theoryOf(current.getType());
return Theory::setContains(typeTheoryId, theories);
} else {
return true;
TheoryId currentTheoryId = Theory::theoryOf(current);
TheoryId parentTheoryId = Theory::theoryOf(parent);
+#if 0
bool useType = current != parent && currentTheoryId != parentTheoryId;
+#else
+ // Should we use the theory of the type
+ bool useType = false;
+ TheoryId typeTheoryId = THEORY_LAST;
+
+ if (current != parent) {
+ if (currentTheoryId != parentTheoryId) {
+ // If enclosed by different theories it's shared -- in read(a, f(a)) f(a) should be shared with integers
+ TypeNode type = current.getType();
+ useType = true;
+ typeTheoryId = Theory::theoryOf(type);
+ } else {
+ TypeNode type = current.getType();
+ typeTheoryId = Theory::theoryOf(type);
+ if (typeTheoryId != currentTheoryId) {
+ if (options::finiteModelFind() && type.isSort()) {
+ // We're looking for finite models
+ useType = true;
+ } else {
+ Cardinality card = type.getCardinality();
+ if (card.isFinite()) {
+ useType = true;
+ }
+ }
+ }
+ }
+ }
+#endif
Theory::Set visitedTheories = d_visited[current];
Debug("register::internal") << "SharedTermsVisitor::visit(" << current << "," << parent << "): previously registered with " << Theory::setToString(visitedTheories) << std::endl;
Debug("register::internal") << "SharedTermsVisitor::visit(" << current << "," << parent << "): adding " << parentTheoryId << std::endl;
}
if (useType) {
- TheoryId typeTheoryId = Theory::theoryOf(current.getType());
+ //////TheoryId typeTheoryId = Theory::theoryOf(current.getType());
if (!Theory::setContains(typeTheoryId, visitedTheories)) {
visitedTheories = Theory::setInsert(typeTheoryId, visitedTheories);
Debug("register::internal") << "SharedTermsVisitor::visit(" << current << "," << parent << "): adding " << typeTheoryId << std::endl;
* Get all relevant information in this theory regarding the current
* model. This should be called after a call to check( FULL_EFFORT )
* for all theories with no conflicts and no lemmas added.
+ * If fullModel is true, then we must specify sufficient information for
+ * the model class to construct constant representatives for each equivalence
+ * class.
*/
- virtual void collectModelInfo( TheoryModel* m ){
- Unimplemented("Theory %s doesn't support Theory::getModel interface",
- identify().c_str());
- }
+ virtual void collectModelInfo( TheoryModel* m, bool fullModel ){ }
/**
* Return a decision request, if the theory has one, or the NULL node
*/
virtual std::string identify() const = 0;
+ /** Set user attribute
+ * This function is called when an attribute is set by a user. In SMT-LIBv2 this is done
+ * via the syntax (! n :attr)
+ */
+ virtual void setUserAttribute( std::string& attr, Node n ) {
+ Unimplemented("Theory %s doesn't support Theory::setUserAttribute interface",
+ identify().c_str());
+ }
+
/** A set of theories */
typedef uint32_t Set;
#include "theory/quantifiers/model_engine.h"
#include "theory/quantifiers/first_order_model.h"
+//hack
+#include "theory/arith/options.h"
+#include "theory/uf/options.h"
+
+
using namespace std;
using namespace CVC4;
d_quantEngine = new QuantifiersEngine(context, this);
//build model information if applicable
- d_curr_model = new theory::DefaultModel( context, "DefaultModel", false );
+ d_curr_model = new theory::DefaultModel( context, "DefaultModel", true );
d_curr_model_builder = new theory::TheoryEngineModelBuilder( this );
Rewriter::init();
}
}
+void collectGroundTerms( Node n, std::vector< Node >& defineFuns,
+ std::vector< Node >& groundTerms ){
+ if( std::find( groundTerms.begin(), groundTerms.end(), n )==groundTerms.end() ){
+ groundTerms.push_back( n );
+ if( n.getKind()==kind::APPLY_UF ){
+ if( std::find( defineFuns.begin(), defineFuns.end(), n.getOperator() )==defineFuns.end() ){
+ defineFuns.push_back( n.getOperator() );
+ }
+ }else if( n.getNumChildren()==0 ){
+ if( std::find( defineFuns.begin(), defineFuns.end(), n )==defineFuns.end() ){
+ defineFuns.push_back( n );
+ }
+ }
+ if( n.getKind()==kind::FORALL ){
+ std::cout << "Bad ground assertion : " << n << std::endl;
+ std::cout << "...possible nested quantifiers?" << std::endl;
+ exit( -1 );
+ }
+ for( int i=0; i<(int)n.getNumChildren(); i++ ){
+ collectGroundTerms( n[i], defineFuns, groundTerms );
+ }
+ }
+}
+
void TheoryEngine::printAssertions(const char* tag) {
- if (Debug.isOn(tag)) {
+ if (Trace.isOn(tag)) {
+
for (TheoryId theoryId = THEORY_FIRST; theoryId < THEORY_LAST; ++theoryId) {
Theory* theory = d_theoryTable[theoryId];
if (theory && d_logicInfo.isTheoryEnabled(theoryId)) {
- Debug(tag) << "--------------------------------------------" << std::endl;
- Debug(tag) << "Assertions of " << theory->getId() << ": " << std::endl;
+ Trace(tag) << "--------------------------------------------" << std::endl;
+ Trace(tag) << "Assertions of " << theory->getId() << ": " << std::endl;
context::CDList<Assertion>::const_iterator it = theory->facts_begin(), it_end = theory->facts_end();
for (unsigned i = 0; it != it_end; ++ it, ++i) {
if ((*it).isPreregistered) {
- Debug(tag) << "[" << i << "]: ";
+ Trace(tag) << "[" << i << "]: ";
} else {
- Debug(tag) << "(" << i << "): ";
+ Trace(tag) << "(" << i << "): ";
}
- Debug(tag) << (*it).assertion << endl;
+ Trace(tag) << (*it).assertion << endl;
}
if (d_logicInfo.isSharingEnabled()) {
- Debug(tag) << "Shared terms of " << theory->getId() << ": " << std::endl;
+ Trace(tag) << "Shared terms of " << theory->getId() << ": " << std::endl;
context::CDList<TNode>::const_iterator it = theory->shared_terms_begin(), it_end = theory->shared_terms_end();
for (unsigned i = 0; it != it_end; ++ it, ++i) {
- Debug(tag) << "[" << i << "]: " << (*it) << endl;
+ Trace(tag) << "[" << i << "]: " << (*it) << endl;
}
}
}
}
-
}
}
Debug("theory") << "TheoryEngine::check(" << effort << "): running check" << std::endl;
- if (Debug.isOn("theory::assertions")) {
+ Trace("theory::assertions") << std::endl;
+ if (Trace.isOn("theory::assertions")) {
printAssertions("theory::assertions");
}
! d_inConflict &&
! d_lemmasAdded ) {
if( d_logicInfo.isQuantified() ){
- ((theory::quantifiers::TheoryQuantifiers*) d_theoryTable[THEORY_QUANTIFIERS])->performCheck(Theory::EFFORT_LAST_CALL);
+ //quantifiers engine must pass effort last call check
+ d_quantEngine->check(Theory::EFFORT_LAST_CALL);
// if we have given up, then possibly flip decision
if(options::flipDecision()) {
if(d_incomplete && !d_inConflict && !d_lemmasAdded) {
//if returning incomplete or SAT, we have ensured that the model in the quantifiers engine has been built
}else if( options::produceModels() ){
//must build model at this point
- d_curr_model_builder->buildModel( d_curr_model );
+ d_curr_model_builder->buildModel( d_curr_model, true );
}
}
d_factsAsserted = true;
continue;
} else {
+ Message() << "mark propagation fail: " << literal << " " << normalizedLiteral << " " << carePair.theory << std::endl;
Unreachable();
}
}
return true;
}
-void TheoryEngine::collectModelInfo( theory::TheoryModel* m ){
+void TheoryEngine::collectModelInfo( theory::TheoryModel* m, bool fullModel ){
+ //have shared term engine collectModelInfo
+ d_sharedTerms.collectModelInfo( m, fullModel );
// Consult each active theory to get all relevant information
// concerning the model.
for(TheoryId theoryId = theory::THEORY_FIRST; theoryId < theory::THEORY_LAST; ++theoryId) {
if(d_logicInfo.isTheoryEnabled(theoryId)) {
- d_theoryTable[theoryId]->collectModelInfo(m);
+ d_theoryTable[theoryId]->collectModelInfo( m, fullModel );
}
}
}
Theory::PPAssertStatus solveStatus = theoryOf(atom)->ppAssert(literal, substitutionOut);
Trace("theory::solve") << "TheoryEngine::solve(" << literal << ") => " << solveStatus << endl;
+ //must add substitutions to model
+ theory::TheoryModel* m = getModel();
+ if( m ){
+ for( SubstitutionMap::iterator pos = substitutionOut.begin(); pos != substitutionOut.end(); ++pos) {
+ Node n = (*pos).first;
+ Node v = (*pos).second;
+ Trace("model") << "Add substitution : " << n << " " << v << std::endl;
+ m->addSubstitution( n, v );
+ }
+ }
return solveStatus;
}
{
d_unconstrainedSimp.processAssertions(assertions);
}
+
+
+void TheoryEngine::setUserAttribute( std::string& attr, Node n ){
+ Trace("te-attr") << "set user attribute " << attr << " " << n << std::endl;
+ if( d_attr_handle.find( attr )!=d_attr_handle.end() ){
+ for( size_t i=0; i<d_attr_handle[attr].size(); i++ ){
+ d_attr_handle[attr][i]->setUserAttribute( attr, n );
+ }
+ }else{
+ //unhandled exception?
+ }
+}
+
+void TheoryEngine::handleUserAttribute( const char* attr, Theory* t ){
+ Trace("te-attr") << "Handle user attribute " << attr << " " << t << std::endl;
+ std::string str( attr );
+ d_attr_handle[ str ].push_back( t );
+}
void spendResource() throw() {
d_engine->spendResource();
}
-
+ void handleUserAttribute( const char* attr, theory::Theory* t ){
+ d_engine->handleUserAttribute( attr, t );
+ }
};/* class TheoryEngine::EngineOutputChannel */
/**
/**
* collect model info
*/
- void collectModelInfo( theory::TheoryModel* m );
+ void collectModelInfo( theory::TheoryModel* m, bool fullModel );
/**
* Get the current model
SharedTermsDatabase* getSharedTermsDatabase() { return &d_sharedTerms; }
+private:
+ std::map< std::string, std::vector< theory::Theory* > > d_attr_handle;
+public:
+
+ /** Set user attribute
+ * This function is called when an attribute is set by a user. In SMT-LIBv2 this is done
+ * via the syntax (! n :attr)
+ */
+ void setUserAttribute( std::string& attr, Node n );
+
+ /** Handle user attribute
+ * Associates theory t with the attribute attr. Theory t will be
+ * notifed whenever an attribute of name attr is set.
+ */
+ void handleUserAttribute( const char* attr, theory::Theory* t );
+
};/* class TheoryEngine */
}/* CVC4 namespace */
void setIncomplete() throw(AssertionException) {}
+ void handleUserAttribute( const char* attr, theory::Theory* t ){}
+
void clear() {
d_callHistory.clear();
}
virtual bool eqNotifyTriggerTermEquality(TheoryId tag, TNode t1, TNode t2, bool value) = 0;
/**
- * Notifies about the merge of two constant terms. After this, all work is suspended and all you
+ * Notifies about the merge of two constant terms. After this, all work is suspended and all you
* can do is ask for explanations.
*
* @param t1 a constant term
std::vector<TriggerId> d_nodeTriggers;
/**
- * Map from ids to whether they are constants (constants are always
+ * Map from ids to whether they are constants (constants are always
* representatives of their class.
*/
std::vector<bool> d_isConstant;
/**
* Get an explanation of the equality t1 = t2. Returns the asserted equalities that
* imply t1 = t2. Returns TNodes as the assertion equalities should be hashed somewhere
- * else.
+ * else.
*/
void getExplanation(EqualityEdgeId t1Id, EqualityNodeId t2Id, std::vector<TNode>& equalities) const;
Node d_true;
/** True node id */
EqualityNodeId d_trueId;
-
+
/** The false node */
Node d_false;
/** False node id */
/** Internal tags for creating a new set */
Theory::Set d_newSetTags;
-
+
/** Internal triggers for creating a new set */
EqualityNodeId d_newSetTriggers[THEORY_LAST];
-
+
/** Size of the internal triggers array */
- unsigned d_newSetTriggersSize;
+ unsigned d_newSetTriggersSize;
/** The information about trigger terms is stored in this easily maintained memory. */
char* d_triggerDatabase;
struct TriggerSetUpdate {
EqualityNodeId classId;
TriggerTermSetRef oldValue;
- TriggerSetUpdate(EqualityNodeId classId = null_id, TriggerTermSetRef oldValue = null_set_id)
+ TriggerSetUpdate(EqualityNodeId classId = null_id, TriggerTermSetRef oldValue = null_set_id)
: classId(classId), oldValue(oldValue) {}
};/* struct EqualityEngine::TriggerSetUpdate */
* reasons should be pushed on the reasons vector.
*/
void storePropagatedDisequality(TheoryId tag, EqualityNodeId lhsId, EqualityNodeId rhsId);
-
+
/**
* An equality tagged with a set of tags.
*/
/** Id of the equality */
EqualityNodeId equalityId;
/** TriggerSet reference for the class of one of the sides */
- TriggerTermSetRef triggerSetRef;
+ TriggerTermSetRef triggerSetRef;
/** Is trigger equivalent to the lhs (rhs otherwise) */
bool lhs;
-
+
TaggedEquality(EqualityNodeId equalityId = null_id, TriggerTermSetRef triggerSetRef = null_set_id, bool lhs = true)
: equalityId(equalityId), triggerSetRef(triggerSetRef), lhs(lhs) {}
};
/**
* Propagates the remembered disequalities with given tags the original triggers for those tags,
- * and the set of disequalities produced by above.
+ * and the set of disequalities produced by above.
*/
- bool propagateTriggerTermDisequalities(Theory::Set tags,
+ bool propagateTriggerTermDisequalities(Theory::Set tags,
TriggerTermSetRef triggerSetRef, const TaggedEqualitiesSet& disequalitiesToNotify);
/** Name of the equality engine */
public:
/**
- * Initialize the equality engine, given the notification class.
+ * Initialize the equality engine, given the notification class.
*/
EqualityEngine(EqualityEngineNotify& notify, context::Context* context, std::string name);
/**
- * Initialize the equality engine with no notification class.
+ * Initialize the equality engine with no notification class.
*/
EqualityEngine(context::Context* context, std::string name);
const eq::EqualityEngine* d_ee;
size_t d_it;
-
+ std::vector< Node > d_visited;
public:
EqClassesIterator(): d_ee(NULL), d_it(0){ }
return !(*this == i);
}
EqClassesIterator& operator++() {
- Node orig = d_ee->d_nodes[d_it];
+ d_visited.push_back( 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_ee->getRepresentative(d_ee->d_nodes[d_it]) != d_ee->d_nodes[d_it] ||
+ std::find( d_visited.begin(), d_visited.end(), d_ee->d_nodes[d_it] )!=d_visited.end() ) ) { // this line is necessary for ignoring duplicates
++d_it;
}
return *this;
instantiator ::CVC4::theory::uf::InstantiatorTheoryUf "theory/uf/theory_uf_instantiator.h"
properties stable-infinite parametric
-properties check propagate ppStaticLearn presolve
+properties check propagate ppStaticLearn presolve getNextDecisionRequest
rewriter ::CVC4::theory::uf::TheoryUfRewriter "theory/uf/theory_uf_rewriter.h"
parameterized APPLY_UF VARIABLE 1: "uninterpreted function application"
operator CARDINALITY_CONSTRAINT 2 "cardinality constraint"
typerule CARDINALITY_CONSTRAINT ::CVC4::theory::uf::CardinalityConstraintTypeRule
-#
-# For compact function models
-# There are three cases for FUNCTION_MODEL nodes:
-# (1) The node has two children, the first being of kind FUNCTION_CASE_SPLIT. The second child specifies a default value.
-# (2) The node has one child of kind FUNCTION_CASE_SPLIT.
-# (3) The node has one child, it's default value.
-#
-# Semantics of FUNCTION_MODEL kind-ed nodes. The value of n applied to arguments args is
-#
-# getValueFM( n, args, 0 ), where:
-#
-# Node getValueFM( n, args, argIndex )
-# if n.getKind()!=FUNCTION_MODEL
-# return n;
-# else if (1)
-# val = getValueFCS( n[0], args, argIndex );
-# if !val.isNull()
-# return val;
-# else
-# return getValueFM( n[1], args, argIndex+1 );
-# else if (2)
-# return getValueFCS( n[0], args, argIndex );
-# else if (3)
-# return getValueFM( n[0], args, argIndex+1 );
-#
-# Node getValueFCS( n, args, argIndex ) :
-# //n.getKind()==FUNCTION_CASE_SPLIT
-# //n[j].getKind()==FUNCTION_CASE for all 0<=j<n.getNumChildren()
-# if( args[argIndex]=n[i][0] for some i)
-# return getValueFM( n[i][1], args, argIndex+1 );
-# else
-# return null;
-#
-
-operator FUNCTION_MODEL 1:2 "function model"
-typerule FUNCTION_MODEL ::CVC4::theory::uf::FunctionModelTypeRule
-
-operator FUNCTION_CASE_SPLIT 1: "function case split"
-typerule FUNCTION_CASE_SPLIT ::CVC4::theory::uf::FunctionCaseSplitTypeRule
-
-operator FUNCTION_CASE 2 "function case"
-typerule FUNCTION_CASE ::CVC4::theory::uf::FunctionCaseTypeRule
-
endtheory
use UF symmetry breaker (Deharbe et al., CADE 2011)
/turns off UF symmetry breaker (Deharbe et al., CADE 2011)
+option ufssRegions /--disable-uf-ss-regions bool :default true
+ disable region-based method for discovering cliques and splits in uf strong solver
+option ufssEagerSplits --uf-ss-eager-split bool :default false
+ add splits eagerly for uf strong solver
+option ufssColoringSat --uf-ss-coloring-sat bool :default false
+ use coloring-based SAT heuristic for uf strong solver
+option ufssTotality --uf-ss-totality bool :default false
+ use totality axioms for enforcing cardinality constraints
+option ufssTotalityLazy --uf-ss-totality-lazy bool :default false
+ apply totality axioms lazily
+option ufssAbortCardinality --uf-ss-abort-card=N int :default -1
+ tells the uf strong solver a cardinality to abort at (-1 == no limit, default)
+option ufssSmartSplits --uf-ss-smart-split bool :default false
+ use smart splitting heuristic for uf strong solver
+option ufssModelInference --uf-ss-model-infer bool :default false
+ use model inference method for uf strong solver
+
+
endmodule
#include "theory/uf/theory_uf_instantiator.h"
#include "theory/uf/theory_uf_strong_solver.h"
#include "theory/model.h"
+#include "theory/type_enumerator.h"
using namespace std;
using namespace CVC4;
if (d_thss != NULL) {
bool isDecision = d_valuation.isSatLiteral(fact) && d_valuation.isDecision(fact);
d_thss->assertNode(fact, isDecision);
+ if( d_thss->isConflict() ){
+ d_conflict = true;
+ return;
+ }
}
// Do the work
if (d_thss != NULL) {
if (! d_conflict) {
d_thss->check(level);
+ if( d_thss->isConflict() ){
+ d_conflict = true;
+ }
}
}
// Remember the function and predicate terms
d_functionsTerms.push_back(node);
break;
+ case kind::CARDINALITY_CONSTRAINT:
+ //do nothing
+ break;
default:
// Variables etc
d_equalityEngine.addTerm(node);
}/* TheoryUF::propagate(TNode) */
void TheoryUF::propagate(Effort effort) {
- if (d_thss != NULL) {
- return d_thss->propagate(effort);
+ //if (d_thss != NULL) {
+ // return d_thss->propagate(effort);
+ //}
+}
+
+Node TheoryUF::getNextDecisionRequest(){
+ if (d_thss != NULL && !d_conflict) {
+ return d_thss->getNextDecisionRequest();
+ }else{
+ return Node::null();
}
}
return mkAnd(assumptions);
}
-void TheoryUF::collectModelInfo( TheoryModel* m ){
+void TheoryUF::collectModelInfo( TheoryModel* m, bool fullModel ){
m->assertEqualityEngine( &d_equalityEngine );
+ if( fullModel ){
+#if 1
+ std::map< TypeNode, int > type_count;
+ //must choose proper representatives
+ // for each equivalence class, specify the constructor as a representative
+ eq::EqClassesIterator eqcs_i = eq::EqClassesIterator( &d_equalityEngine );
+ while( !eqcs_i.isFinished() ){
+ Node eqc = (*eqcs_i);
+ TypeNode tn = eqc.getType();
+ if( tn.isSort() ){
+ if( type_count.find( tn )==type_count.end() ){
+ type_count[tn] = 0;
+ }
+ std::stringstream ss;
+ ss << Expr::setlanguage(options::outputLanguage());
+ ss << "$t_" << tn << (type_count[tn]+1);
+ type_count[tn]++;
+ Node rep = NodeManager::currentNM()->mkSkolem( ss.str(), tn );
+ Trace("mkVar") << "TheoryUF::collectModelInfo: make variable " << rep << " : " << tn << std::endl;
+ //specify the constant as the representative
+ m->assertEquality( eqc, rep, true );
+ m->assertRepresentative( rep );
+ }
+ ++eqcs_i;
+ }
+#else
+ std::map< TypeNode, TypeEnumerator* > type_enums;
+ //must choose proper representatives
+ // for each equivalence class, specify the constructor as a representative
+ eq::EqClassesIterator eqcs_i = eq::EqClassesIterator( &d_equalityEngine );
+ while( !eqcs_i.isFinished() ){
+ Node eqc = (*eqcs_i);
+ TypeNode tn = eqc.getType();
+ if( tn.isSort() ){
+ if( type_enums.find( tn )==type_enums.end() ){
+ type_enums[tn] = new TypeEnumerator( tn );
+ }
+ Node rep = *(*type_enums[tn]);
+ ++(*type_enums[tn]);
+ //specify the constant as the representative
+ m->assertEquality( eqc, rep, true );
+ m->assertRepresentative( rep );
+ }
+ ++eqcs_i;
+ }
+ #endif
+ }
}
void TheoryUF::presolve() {
}
}
}
+
void preRegisterTerm(TNode term);
Node explain(TNode n);
- void collectModelInfo( TheoryModel* m );
+ void collectModelInfo( TheoryModel* m, bool fullModel );
void ppStaticLearn(TNode in, NodeBuilder<>& learned);
void presolve();
void computeCareGraph();
void propagate(Effort effort);
+ Node getNextDecisionRequest();
EqualityStatus getEqualityStatus(TNode a, TNode b);
void registerPpRewrite(TNode op, PpRewrite* callback) {
d_registeredPpRewrites.insert(std::make_pair(op, callback));
}
-
};/* class TheoryUF */
}/* CVC4::theory::uf namespace */
}
}
-Node UfModelTreeNode::getFunctionValue(){
+Node UfModelTreeNode::getFunctionValue( std::vector< Node >& args, int index, Node argDefaultValue ){
if( !d_data.empty() ){
- Node defaultValue;
+ Node defaultValue = argDefaultValue;
+ if( d_data.find( Node::null() )!=d_data.end() ){
+ defaultValue = d_data[Node::null()].getFunctionValue( args, index+1, argDefaultValue );
+ }
std::vector< Node > caseValues;
+ std::map< Node, Node > caseArg;
for( std::map< Node, UfModelTreeNode >::iterator it = d_data.begin(); it != d_data.end(); ++it ){
- if( it->first.isNull() ){
- defaultValue = it->second.getFunctionValue();
- }else{
- caseValues.push_back( NodeManager::currentNM()->mkNode( FUNCTION_CASE, it->first, it->second.getFunctionValue() ) );
+ if( !it->first.isNull() ){
+ Node val = it->second.getFunctionValue( args, index+1, defaultValue );
+ caseValues.push_back( val );
+ caseArg[ val ] = it->first;
}
}
- if( caseValues.empty() && defaultValue.getKind()!=FUNCTION_CASE_SPLIT && defaultValue.getKind()!=FUNCTION_MODEL ){
- return defaultValue;
- }else{
- std::vector< Node > children;
- if( !caseValues.empty() ){
- children.push_back( NodeManager::currentNM()->mkNode( FUNCTION_CASE_SPLIT, caseValues ) );
- }
- if( !defaultValue.isNull() ){
- children.push_back( defaultValue );
- }
- return NodeManager::currentNM()->mkNode( FUNCTION_MODEL, children );
+ Node retNode = defaultValue;
+ for( int i=((int)caseValues.size()-1); i>=0; i-- ){
+ retNode = NodeManager::currentNM()->mkNode( ITE, args[index].eqNode( caseArg[ caseValues[i] ] ), caseValues[i], retNode );
}
+ return retNode;
}else{
Assert( !d_value.isNull() );
return d_value;
}
}
+//update function
+void UfModelTreeNode::update( TheoryModel* m ){
+ if( !d_value.isNull() ){
+ d_value = m->getRepresentative( d_value );
+ }
+ std::map< Node, UfModelTreeNode > old = d_data;
+ d_data.clear();
+ for( std::map< Node, UfModelTreeNode >::iterator it = old.begin(); it != old.end(); ++it ){
+ Node rep = m->getRepresentative( it->first );
+ d_data[ rep ] = it->second;
+ d_data[ rep ].update( m );
+ }
+}
+
//simplify function
void UfModelTreeNode::simplify( Node op, Node defaultVal, int argIndex ){
if( argIndex<(int)op.getType().getNumChildren()-1 ){
}
}
-
-Node UfModelTree::toIte2( Node fm_node, std::vector< Node >& args, int index, Node defaultNode ){
- if( fm_node.getKind()==FUNCTION_MODEL ){
- if( fm_node[0].getKind()==FUNCTION_CASE_SPLIT ){
- Node retNode;
- Node childDefaultNode = defaultNode;
- //get new default
- if( fm_node.getNumChildren()==2 ){
- childDefaultNode = toIte2( fm_node[1], args, index+1, defaultNode );
- }
- retNode = childDefaultNode;
- for( int i=(int)fm_node[0].getNumChildren()-1; i>=0; i-- ){
- Node childNode = toIte2( fm_node[0][1], args, index+1, childDefaultNode );
- retNode = NodeManager::currentNM()->mkNode( ITE, args[index].eqNode( fm_node[0][0] ), childNode, retNode );
- }
- return retNode;
- }else{
- return toIte2( fm_node[0], args, index+1, defaultNode );
- }
- }else{
- return fm_node;
+Node UfModelTree::getFunctionValue( const char* argPrefix ){
+ TypeNode type = d_op.getType();
+ std::vector< Node > vars;
+ for( size_t i=0; i<type.getNumChildren()-1; i++ ){
+ std::stringstream ss;
+ ss << argPrefix << (i+1);
+ vars.push_back( NodeManager::currentNM()->mkSkolem( ss.str(), type[i] ) );
}
+ return getFunctionValue( vars );
}
-
Node UfModelTreeGenerator::getIntersection( TheoryModel* m, Node n1, Node n2, bool& isGround ){
//Notice() << "Get intersection " << n1 << " " << n2 << std::endl;
isGround = true;
/** getConstant Value function */
Node getConstantValue( TheoryModel* m, Node n, std::vector< int >& indexOrder, int argIndex );
/** getFunctionValue */
- Node getFunctionValue();
+ Node getFunctionValue( std::vector< Node >& args, int index, Node argDefaultValue );
+ /** update function */
+ void update( TheoryModel* m );
/** simplify function */
void simplify( Node op, Node defaultVal, int argIndex );
/** is total ? */
return d_tree.getConstantValue( m, n, d_index_order, 0 );
}
/** getFunctionValue
- * Returns a compact representation of this function, of kind FUNCTION_MODEL.
- * See documentation in theory/uf/kinds
+ * Returns a representation of this function.
*/
- Node getFunctionValue(){
- return d_tree.getFunctionValue();
- }
+ Node getFunctionValue( std::vector< Node >& args ){ return d_tree.getFunctionValue( args, 0, Node::null() ); }
+ /** getFunctionValue for args with set prefix */
+ Node getFunctionValue( const char* argPrefix );
+ /** update
+ * This will update all values in the tree to be representatives in m.
+ */
+ void update( TheoryModel* m ){ d_tree.update( m ); }
/** simplify the tree */
void simplify() { d_tree.simplify( d_op, Node::null(), 0 ); }
/** is this tree total? */
public:
/** to ITE function for function model nodes */
static Node toIte( Node fm_node, std::vector< Node >& args ) { return toIte2( fm_node, args, 0, Node::null() ); }
+ static Node toIte( TypeNode type, Node fm_node, const char* argPrefix );
};
class UfModelTreeGenerator
#include "theory/uf/equality_engine.h"
#include "theory/uf/theory_uf_instantiator.h"
#include "theory/theory_engine.h"
-#include "theory/quantifiers/options.h"
#include "theory/quantifiers/term_database.h"
+#include "theory/uf/options.h"
-//#define USE_SMART_SPLITS
//#define ONE_SPLIT_REGION
//#define DISABLE_QUICK_CLIQUE_CHECKS
//#define COMBINE_REGIONS_SMALL_INTO_LARGE
using namespace CVC4::theory;
using namespace CVC4::theory::uf;
-void StrongSolverTheoryUf::ConflictFind::Region::addRep( Node n ) {
+void StrongSolverTheoryUf::SortRepModel::Region::addRep( Node n ) {
setRep( n, true );
}
-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");
+void StrongSolverTheoryUf::SortRepModel::Region::takeNode( StrongSolverTheoryUf::SortRepModel::Region* r, Node n ){
Assert( !hasRep( n ) );
Assert( r->hasRep( n ) );
//add representative
r->setRep( n, false );
}
-void StrongSolverTheoryUf::ConflictFind::Region::combine( StrongSolverTheoryUf::ConflictFind::Region* r ){
+void StrongSolverTheoryUf::SortRepModel::Region::combine( StrongSolverTheoryUf::SortRepModel::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 ){
}
/** setEqual */
-void StrongSolverTheoryUf::ConflictFind::Region::setEqual( Node a, Node b ){
+void StrongSolverTheoryUf::SortRepModel::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++ ){
setRep( b, false );
}
-void StrongSolverTheoryUf::ConflictFind::Region::setDisequal( Node n1, Node n2, int type, bool valid ){
+void StrongSolverTheoryUf::SortRepModel::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 );
}
}
-void StrongSolverTheoryUf::ConflictFind::Region::setRep( Node n, bool valid ){
+void StrongSolverTheoryUf::SortRepModel::Region::setRep( Node n, bool valid ){
Assert( hasRep( n )!=valid );
if( valid && d_nodes.find( n )==d_nodes.end() ){
d_nodes[n] = new RegionNodeInfo( d_cf->d_th->getSatContext() );
}
}
-bool StrongSolverTheoryUf::ConflictFind::Region::isDisequal( Node n1, Node n2, int type ){
+bool StrongSolverTheoryUf::SortRepModel::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];
}
struct sortInternalDegree {
- StrongSolverTheoryUf::ConflictFind::Region* r;
+ StrongSolverTheoryUf::SortRepModel::Region* r;
bool operator() (Node i,Node j) { return (r->d_nodes[i]->getNumInternalDisequalities()>r->d_nodes[j]->getNumInternalDisequalities());}
};
struct sortExternalDegree {
- StrongSolverTheoryUf::ConflictFind::Region* r;
+ StrongSolverTheoryUf::SortRepModel::Region* r;
bool operator() (Node i,Node j) { return (r->d_nodes[i]->getNumExternalDisequalities()>r->d_nodes[j]->getNumExternalDisequalities());}
};
-bool StrongSolverTheoryUf::ConflictFind::Region::getMustCombine( int cardinality ){
+int gmcCount = 0;
+
+bool StrongSolverTheoryUf::SortRepModel::Region::getMustCombine( int cardinality ){
if( options::ufssRegions() && 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
}
}
}
- //static int gmcCount = 0;
- //gmcCount++;
- //if( gmcCount%100==0 ){
- // std::cout << gmcCount << " " << cardinality << std::endl;
- //}
+ gmcCount++;
+ if( gmcCount%100==0 ){
+ Trace("gmc-count") << gmcCount << " " << cardinality << " sample : " << degrees.size() << std::endl;
+ }
//this should happen relatively infrequently....
std::sort( degrees.begin(), degrees.end() );
for( int i=0; i<(int)degrees.size(); i++ ){
return false;
}
-bool StrongSolverTheoryUf::ConflictFind::Region::check( Theory::Effort level, int cardinality, std::vector< Node >& clique ){
+bool StrongSolverTheoryUf::SortRepModel::Region::check( Theory::Effort level, int cardinality, std::vector< Node >& clique ){
if( d_reps_size>long(cardinality) ){
if( 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 );
+ if( 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 );
+ }
}
+ Trace("quick-clique") << "Found quick clique" << std::endl;
+ return true;
+ }else{
+ return false;
}
- return true;
}else if( options::ufssRegions() || options::ufssEagerSplits() || level==Theory::EFFORT_FULL ){
//build test clique, up to size cardinality+1
if( d_testCliqueSize<=long(cardinality) ){
return false;
}
-void StrongSolverTheoryUf::ConflictFind::Region::getRepresentatives( std::vector< Node >& reps ){
+void StrongSolverTheoryUf::SortRepModel::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 ){
}
}
-void StrongSolverTheoryUf::ConflictFind::Region::getNumExternalDisequalities( std::map< Node, int >& num_ext_disequalities ){
+void StrongSolverTheoryUf::SortRepModel::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 ){
}
}
-Node StrongSolverTheoryUf::ConflictFind::Region::getBestSplit(){
-#ifndef USE_SMART_SPLITS
- //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();
-#else
- std::vector< Node > splits;
- for( NodeBoolMap::iterator it = d_splits.begin(); it != d_splits.end(); ++it ){
- if( (*it).second ){
- splits.push_back( (*it).first );
- }
- }
- if( splits.size()>1 ){
- std::map< Node, std::map< Node, bool > > ops;
- Debug("uf-ss-split") << "Choice for splits: " << std::endl;
- double maxScore = -1;
- int maxIndex;
- for( int i=0; i<(int)splits.size(); i++ ){
- Debug("uf-ss-split") << " " << splits[i] << std::endl;
- for( int j=0; j<2; j++ ){
- if( ops.find( splits[i][j] )==ops.end() ){
- EqClassIterator eqc( splits[i][j], ((uf::TheoryUF*)d_cf->d_th)->getEqualityEngine() );
- while( !eqc.isFinished() ){
- Node n = (*eqc);
- if( n.getKind()==APPLY_UF ){
- ops[ splits[i][j] ][ n.getOperator() ] = true;
- }
- ++eqc;
- }
- }
- }
- //now, compute score
- int common[2] = { 0, 0 };
- for( int j=0; j<2; j++ ){
- int j2 = j==0 ? 1 : 0;
- for( std::map< Node, bool >::iterator it = ops[ splits[i][j] ].begin(); it != ops[ splits[i][j] ].end(); ++it ){
- if( ops[ splits[i][j2] ].find( it->first )!=ops[ splits[i][j2] ].end() ){
- common[0]++;
- }else{
- common[1]++;
- }
- }
- }
- double score = ( 1.0 + (double)common[0] )/( 1.0 + (double)common[1] );
- if( score>maxScore ){
- maxScore = score;
- maxIndex = i;
- }
- }
- //if( maxIndex!=0 ){
- // std::cout << "Chose maxIndex = " << maxIndex << std::endl;
- //}
- return splits[maxIndex];
- }else if( !splits.empty() ){
- return splits[0];
- }else{
- return Node::null();
- }
-#endif
-}
-
-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 );
-}
-
-bool StrongSolverTheoryUf::ConflictFind::Region::minimize( OutputChannel* out ){
- if( hasSplits() ){
- addSplit( out );
- return false;
- }else{
- return true;
- }
-}
-
-void StrongSolverTheoryUf::ConflictFind::Region::debugPrint( const char* c, bool incClique ){
+void StrongSolverTheoryUf::SortRepModel::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;
}
}
-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++;
+
+
+
+
+
+
+
+StrongSolverTheoryUf::SortRepModel::SortRepModel( Node n, context::Context* c, TheoryUF* th ) : RepModel( n.getType() ),
+ d_th( th ), d_regions_index( c, 0 ), d_regions_map( c ), d_split_score( c ), d_disequalities_index( c, 0 ),
+ d_reps( c, 0 ), d_conflict( c, false ), d_cardinality( c, 1 ), d_aloc_cardinality( 0 ),
+ d_cardinality_assertions( c ), d_hasCard( c, false ){
+ d_cardinality_term = n;
+}
+
+/** initialize */
+void StrongSolverTheoryUf::SortRepModel::initialize( OutputChannel* out ){
+ allocateCardinality( out );
+}
+
+/** new node */
+void StrongSolverTheoryUf::SortRepModel::newEqClass( Node n ){
+ if( !d_conflict ){
+ if( d_regions_map.find( n )==d_regions_map.end() ){
+ if( !options::ufssTotalityLazy() ){
+ //must generate totality axioms for every cardinality we have allocated thus far
+ for( std::map< int, Node >::iterator it = d_cardinality_literal.begin(); it != d_cardinality_literal.end(); ++it ){
+ if( applyTotality( it->first ) ){
+ addTotalityAxiom( n, it->first, &d_th->getOutputChannel() );
+ }
+ }
+ }
+ if( options::ufssTotality() ){
+ //regions map will store whether we need to equate this term with a constant equivalence class
+ if( std::find( d_totality_terms[0].begin(), d_totality_terms[0].end(), n )==d_totality_terms[0].end() ){
+ d_regions_map[n] = 0;
+ }else{
+ d_regions_map[n] = -1;
+ }
+ }else{
+ if( !options::ufssRegions() ){
+ //if not using regions, always add new equivalence classes to region index = 0
+ d_regions_index = 0;
+ }
+ d_regions_map[n] = d_regions_index;
+ if( options::ufssSmartSplits() ){
+ setSplitScore( n, 0 );
+ }
+ Debug("uf-ss") << "StrongSolverTheoryUf: New Eq Class " << n << std::endl;
+ Debug("uf-ss-debug") << d_regions_index << " " << (int)d_regions.size() << std::endl;
+ if( d_regions_index<d_regions.size() ){
+ d_regions[ d_regions_index ]->debugPrint("uf-ss-debug",true);
+ d_regions[ d_regions_index ]->d_valid = true;
+ Assert( !options::ufssRegions() || d_regions[ d_regions_index ]->getNumReps()==0 );
+ }else{
+ d_regions.push_back( new Region( this, d_th->getSatContext() ) );
+ }
+ d_regions[ d_regions_index ]->addRep( n );
+ d_regions_index = d_regions_index + 1;
}
+ d_reps = d_reps + 1;
}
}
- 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 ){
- 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 ] ]++;
+/** merge */
+void StrongSolverTheoryUf::SortRepModel::merge( Node a, Node b ){
+ if( !d_conflict ){
+ if( options::ufssTotality() ){
+ if( d_regions_map[b]==-1 ){
+ d_regions_map[a] = -1;
+ }
+ d_regions_map[b] = -1;
+ }else{
+ //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 ){
+ int ri = combineRegions( bi, ai );
+ d_regions[ri]->setEqual( a, b );
+ checkRegion( ri );
+ }else if( d_regions[bi]->getNumReps()==1 ){
+ int ri = combineRegions( ai, bi );
+ d_regions[ri]->setEqual( a, b );
+ checkRegion( ri );
+ }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_regions_map[b] = -1;
}
+ d_reps = d_reps - 1;
+ Debug("uf-ss") << "Done merge." << std::endl;
}
}
}
-void StrongSolverTheoryUf::ConflictFind::explainClique( std::vector< Node >& clique, OutputChannel* out ){
- Assert( d_cardinality>0 );
- while( clique.size()>size_t(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()==(clique.size()*( clique.size()-1 )/2) ){
- break;
+/** assert terms are disequal */
+void StrongSolverTheoryUf::SortRepModel::assertDisequal( Node a, Node b, Node reason ){
+ if( !d_conflict ){
+ if( options::ufssTotality() ){
+ //do nothing
+ }else{
+ //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;
}
}
}
- //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] );
+}
+
+
+/** check */
+void StrongSolverTheoryUf::SortRepModel::check( Theory::Effort level, OutputChannel* out ){
+ if( level>=Theory::EFFORT_STANDARD && d_hasCard && !d_conflict ){
+ 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{
+ if( applyTotality( d_cardinality ) ){
+ //if we are applying totality to this cardinality
+ if( options::ufssTotalityLazy() ){
+ //add totality axioms for all nodes that have not yet been equated to cardinality terms
+ if( level==Theory::EFFORT_FULL ){
+ for( NodeIntMap::iterator it = d_regions_map.begin(); it != d_regions_map.end(); ++it ){
+ if( !options::ufssTotality() || d_regions_map[ (*it).first ]!=-1 ){
+ addTotalityAxiom( (*it).first, d_cardinality, &d_th->getOutputChannel() );
+ }
+ }
+ }
+ }
+ }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 ) ){
+ //add clique lemma
+ addCliqueLemma( clique, out );
+ return;
+ }else{
+ Trace("uf-ss-debug") << "No clique in Region #" << i << std::endl;
+ }
+ }
+ }
+ bool addedLemma = false;
+ //do splitting on demand
+ if( level==Theory::EFFORT_FULL || options::ufssEagerSplits() ){
+ Trace("uf-ss-debug") << "Add splits?" << std::endl;
+ //see if we have any recommended splits from large regions
+ for( int i=0; i<(int)d_regions_index; i++ ){
+ if( d_regions[i]->d_valid && d_regions[i]->getNumReps()>d_cardinality ){
+ if( addSplit( d_regions[i], out ) ){
+ addedLemma = true;
+#ifdef ONE_SPLIT_REGION
+ break;
+#endif
+ }
+ }
+ }
+ }
+ //if no added lemmas, force continuation via combination of regions
+ if( level==Theory::EFFORT_FULL ){
+ if( !addedLemma ){
+ Trace("uf-ss-debug") << "No splits added. " << d_cardinality << std::endl;
+ if( !options::ufssColoringSat() ){
+ bool recheck = false;
+ //naive strategy, force region combination involving the first valid region
+ for( int i=0; i<(int)d_regions_index; i++ ){
+ if( d_regions[i]->d_valid ){
+ forceCombineRegion( i, false );
+ recheck = true;
+ break;
+ }
+ }
+ if( recheck ){
+ check( level, out );
+ }
}
}
}
- 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 );
+}
+
+void StrongSolverTheoryUf::SortRepModel::propagate( Theory::Effort level, OutputChannel* out ){
- //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() ){
- if( !options::ufssRegions() ){
- //if not using regions, always add new equivalence classes to region index = 0
- d_regions_index = 0;
- }
- 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( !options::ufssRegions() || d_regions[ d_regions_index ]->getNumReps()==0 );
- }else{
- d_regions.push_back( new Region( this, d_th->getSatContext() ) );
+Node StrongSolverTheoryUf::SortRepModel::getNextDecisionRequest(){
+ //request the current cardinality as a decision literal, if not already asserted
+ for( int i=1; i<=d_aloc_cardinality; i++ ){
+ if( !d_hasCard || i<d_cardinality ){
+ Node cn = d_cardinality_literal[ i ];
+ Assert( !cn.isNull() );
+ if( d_cardinality_assertions.find( cn )==d_cardinality_assertions.end() ){
+ Trace("uf-ss-dec") << "Propagate as decision " << d_type << " " << i << std::endl;
+ return cn;
+ }
}
- d_regions[ d_regions_index ]->addRep( n );
- d_regions_index = d_regions_index + 1;
- d_reps = d_reps + 1;
}
+ return Node::null();
}
-/** 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 ){
- int ri = combineRegions( bi, ai );
- d_regions[ri]->setEqual( a, b );
- checkRegion( ri );
- }else if( d_regions[bi]->getNumReps()==1 ){
- int ri = combineRegions( ai, bi );
- d_regions[ri]->setEqual( a, b );
- checkRegion( ri );
- }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 );
+bool StrongSolverTheoryUf::SortRepModel::minimize( OutputChannel* out, TheoryModel* m ){
+ if( options::ufssTotality() ){
+ //do nothing
+ }else{
+ if( m ){
+#if 0
+ // ensure that the constructed model is minimal
+ // if the model has terms that the strong solver does not know about
+ if( (int)m->d_rep_set.d_type_reps[ d_type ].size()>d_cardinality ){
+ eq::EqClassesIterator eqcs_i = eq::EqClassesIterator( &m->d_equalityEngine );
+ while( !eqcs_i.isFinished() ){
+ Node eqc = (*eqcs_i);
+ if( eqc.getType()==d_type ){
+ //we must ensure that this equivalence class has been accounted for
+ if( d_regions_map.find( eqc )==d_regions_map.end() ){
+ //split on unaccounted for term and cardinality lemma term (as default)
+ Node splitEq = eqc.eqNode( d_cardinality_term );
+ splitEq = Rewriter::rewrite( splitEq );
+ Trace("uf-ss-minimize") << "Last chance minimize : " << splitEq << std::endl;
+ out->split( splitEq );
+ //tell the sat solver to explore the equals branch first
+ out->requirePhase( splitEq, true );
+ ++( d_th->getStrongSolver()->d_statistics.d_split_lemmas );
+ return false;
+ }
+ }
+ ++eqcs_i;
}
- checkRegion( ai );
- checkRegion( bi );
+ Assert( false );
}
+#endif
}else{
- d_regions[ai]->setEqual( a, b );
- checkRegion( ai );
+ //internal minimize, ensure that model forms a clique:
+ // if two equivalence classes are neither equal nor disequal, add a split
+ 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( addSplit( d_regions[validRegionIndex], out ) ){
+ return false;
+ }
+ }else{
+ validRegionIndex = i;
+ }
+ }
+ }
+ if( addSplit( d_regions[validRegionIndex], out ) ){
+ return false;
+ }
}
- d_reps = d_reps - 1;
- d_regions_map[b] = -1;
}
- Debug("uf-ss") << "Done merge." << std::endl;
+ return true;
}
-/** 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 );
+
+int StrongSolverTheoryUf::SortRepModel::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++;
+ }
}
- 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 );
+ }
+ return counter;
+}
+
+void StrongSolverTheoryUf::SortRepModel::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 ){
+ 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 ] ]++;
+ }
+ }
}
- //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;
+void StrongSolverTheoryUf::SortRepModel::setSplitScore( Node n, int s ){
+ if( d_split_score.find( n )!=d_split_score.end() ){
+ int ss = d_split_score[ n ];
+ d_split_score[ n ] = s>ss ? s : ss;
+ }else{
+ d_split_score[ n ] = s;
+ }
+ for( int i=0; i<(int)n.getNumChildren(); i++ ){
+ setSplitScore( n[i], s+1 );
+ }
+}
+
+void StrongSolverTheoryUf::SortRepModel::assertCardinality( OutputChannel* out, int c, bool val ){
+ if( !d_conflict ){
+ Trace("uf-ss-assert") << "Assert cardinality " << d_type << " " << c << " " << val << " level = " << d_th->d_valuation.getAssertionLevel() << std::endl;
+ Assert( d_cardinality_literal.find( c )!=d_cardinality_literal.end() );
+ d_cardinality_assertions[ d_cardinality_literal[c] ] = val;
+ if( val ){
+ bool doCheckRegions = !d_hasCard;
+ if( !d_hasCard || c<d_cardinality ){
+ d_cardinality = c;
+ }
+ d_hasCard = true;
+ //should check all regions now
+ if( doCheckRegions ){
+ for( int i=0; i<(int)d_regions_index; i++ ){
+ if( d_regions[i]->d_valid ){
+ checkRegion( i );
+ if( d_conflict ){
+ return;
+ }
+ }
+ }
+ }
+ }else{
+ if( options::ufssModelInference() ){
+ //check if we are at decision level 0
+ if( d_th->d_valuation.getAssertionLevel()==0 ){
+ Trace("uf-ss-mi") << "We have proved that no models of size " << c << " for type " << d_type << " exist." << std::endl;
+ Trace("uf-ss-mi") << " # Clique lemmas : " << d_cliques[c].size() << std::endl;
+ if( d_cliques[c].size()==1 ){
+ if( d_totality_terms[c+1].empty() ){
+ Trace("uf-ss-mi") << "*** Establish model" << std::endl;
+ //d_totality_terms[c+1].insert( d_totality_terms[c].begin(), d_cliques[c][0].begin(), d_cliques[c][0].end() );
+ }
+ }
+ }
+ }
+ //see if we need to request a new cardinality
+ if( !d_hasCard ){
+ bool needsCard = true;
+ for( std::map< int, Node >::iterator it = d_cardinality_literal.begin(); it!=d_cardinality_literal.end(); ++it ){
+ if( d_cardinality_assertions.find( it->second )==d_cardinality_assertions.end() ){
+ needsCard = false;
+ break;
+ }
+ }
+ if( needsCard ){
+ allocateCardinality( out );
+ }
+ }
+ }
}
}
-void StrongSolverTheoryUf::ConflictFind::checkRegion( int ri, bool rec ){
- if( isValid(ri) ){
+void StrongSolverTheoryUf::SortRepModel::checkRegion( int ri, bool rec ){
+ if( isValid(ri) && d_hasCard ){
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() );
+ addCliqueLemma( clique, &d_th->getOutputChannel() );
}else if( d_regions[ri]->getMustCombine( d_cardinality ) ){
////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 ){
}
}
-int StrongSolverTheoryUf::ConflictFind::forceCombineRegion( int ri, bool useDensity ){
+int StrongSolverTheoryUf::SortRepModel::forceCombineRegion( int ri, bool useDensity ){
if( !useDensity ){
for( int i=0; i<(int)d_regions_index; i++ ){
if( ri!=i && d_regions[i]->d_valid ){
}
-int StrongSolverTheoryUf::ConflictFind::combineRegions( int ai, int bi ){
+int StrongSolverTheoryUf::SortRepModel::combineRegions( int ai, int bi ){
#ifdef COMBINE_REGIONS_SMALL_INTO_LARGE
if( d_regions[ai]->getNumReps()<d_regions[bi]->getNumReps() ){
return combineRegions( bi, ai );
return ai;
}
-void StrongSolverTheoryUf::ConflictFind::moveNode( Node n, int ri ){
+void StrongSolverTheoryUf::SortRepModel::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 ) );
d_regions_map[n] = ri;
}
-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
- quantifiers::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" ) << "*** Disambiguate lemma : " << lem << std::endl;
- //Notice() << "*** Disambiguate lemma : " << lem << std::endl;
- out->lemma( lem );
- d_term_amb[ eq ] = false;
- lemmaAdded = true;
- ++( d_th->getStrongSolver()->d_statistics.d_disamb_term_lemmas );
- }
- }
- }
+void StrongSolverTheoryUf::SortRepModel::allocateCardinality( OutputChannel* out ){
+ if( d_aloc_cardinality>0 ){
+ Trace("uf-ss-fmf") << "No model of size " << d_aloc_cardinality << " exists for type " << d_type << " in this branch" << std::endl;
+ if( Trace.isOn("uf-ss-cliques") ){
+ Trace("uf-ss-cliques") << "Cliques of size " << (d_aloc_cardinality+1) << " : " << std::endl;
+ for( size_t i=0; i<d_cliques[ d_aloc_cardinality ].size(); i++ ){
+ Trace("uf-ss-cliques") << " ";
+ for( size_t j=0; j<d_cliques[ d_aloc_cardinality ][i].size(); j++ ){
+ Trace("uf-ss-cliques") << d_cliques[ d_aloc_cardinality ][i][j] << " ";
}
+ Trace("uf-ss-cliques") << std::endl;
+ }
+ }
+ }
+ d_aloc_cardinality++;
+
+ //check for abort case
+ if( options::ufssAbortCardinality()==d_aloc_cardinality ){
+ //abort here DO_THIS
+ Message() << "Maximum cardinality reached." << std::endl;
+ exit( 0 );
+ }else{
+ if( options::ufssTotality() ){
+ //must generate new cardinality lemma term
+ std::stringstream ss;
+ ss << "_c_" << d_aloc_cardinality;
+ Node var = NodeManager::currentNM()->mkSkolem( ss.str(), d_type );
+ d_totality_terms[0].push_back( var );
+ Trace("mkVar") << "allocateCardinality, mkVar : " << var << " : " << d_type << std::endl;
+ //must be distinct from all other cardinality terms
+ for( int i=0; i<(int)(d_totality_terms[0].size()-1); i++ ){
+ Node lem = NodeManager::currentNM()->mkNode( NOT, var.eqNode( d_totality_terms[0][i] ) );
+ d_th->getOutputChannel().lemma( lem );
+ }
+ }
+
+ //add splitting lemma for cardinality constraint
+ Assert( !d_cardinality_term.isNull() );
+ Node lem = NodeManager::currentNM()->mkNode( CARDINALITY_CONSTRAINT, d_cardinality_term,
+ NodeManager::currentNM()->mkConst( Rational( d_aloc_cardinality ) ) );
+ lem = Rewriter::rewrite(lem);
+ d_cardinality_literal[ d_aloc_cardinality ] = lem;
+ lem = NodeManager::currentNM()->mkNode( OR, lem, lem.notNode() );
+ d_cardinality_lemma[ d_aloc_cardinality ] = lem;
+ //add as lemma to output channel
+ out->lemma( lem );
+ //require phase
+ out->requirePhase( d_cardinality_literal[ d_aloc_cardinality ], true );
+ //add the appropriate lemma, propagate as decision
+ //Trace("uf-ss-prop-as-dec") << "Propagate as decision " << lem[0] << " " << d_type << std::endl;
+ //out->propagateAsDecision( lem[0] );
+ d_th->getStrongSolver()->d_statistics.d_max_model_size.maxAssign( d_aloc_cardinality );
+
+ if( applyTotality( d_aloc_cardinality ) && !options::ufssTotalityLazy() ){
+ //must send totality axioms for each existing term
+ for( NodeIntMap::iterator it = d_regions_map.begin(); it != d_regions_map.end(); ++it ){
+ addTotalityAxiom( (*it).first, d_aloc_cardinality, &d_th->getOutputChannel() );
}
}
}
- 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 << " ";
+bool StrongSolverTheoryUf::SortRepModel::addSplit( Region* r, OutputChannel* out ){
+ if( r->hasSplits() ){
+ Node s;
+ if( !options::ufssSmartSplits() ){
+ //take the first split you find
+ for( NodeBoolMap::iterator it = r->d_splits.begin(); it != r->d_splits.end(); ++it ){
+ if( (*it).second ){
+ s = (*it).first;
+ break;
+ }
}
- 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;
+ int maxScore = -1;
+ std::vector< Node > splits;
+ for( NodeBoolMap::iterator it = r->d_splits.begin(); it != r->d_splits.end(); ++it ){
+ if( (*it).second ){
+ int score1 = d_split_score[ (*it).first[0] ];
+ int score2 = d_split_score[ (*it).first[1] ];
+ int score = score1<score2 ? score1 : score2;
+ if( score>maxScore ){
+ maxScore = -1;
+ s = (*it).first;
}
}
}
- bool addedLemma = false;
- //do splitting on demand
- if( level==Theory::EFFORT_FULL || options::ufssEagerSplits() ){
- Debug("uf-ss-debug") << "Add splits?" << std::endl;
- //see if we have any recommended splits from large regions
- for( int i=0; i<(int)d_regions_index; i++ ){
- if( d_regions[i]->d_valid && d_regions[i]->getNumReps()>d_cardinality ){
- if( d_regions[i]->hasSplits() ){
- d_regions[i]->addSplit( out );
- addedLemma = true;
- ++( d_th->getStrongSolver()->d_statistics.d_split_lemmas );
-#ifdef ONE_SPLIT_REGION
- break;
-#endif
- }
- }
- }
+ }
+ //add lemma to output channel
+ Assert( s!=Node::null() && s.getKind()==EQUAL );
+ s = Rewriter::rewrite( s );
+ Trace("uf-ss-lemma") << "*** Split on " << s << std::endl;
+ //Trace("uf-ss-lemma") << d_th->getEqualityEngine()->areEqual( s[0], s[1] ) << " ";
+ //Trace("uf-ss-lemma") << d_th->getEqualityEngine()->areDisequal( s[0], s[1] ) << std::endl;
+ //Trace("uf-ss-lemma") << s[0].getType() << " " << s[1].getType() << std::endl;
+ //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 );
+ ++( d_th->getStrongSolver()->d_statistics.d_split_lemmas );
+ return true;
+ }else{
+ return false;
+ }
+}
+
+
+void StrongSolverTheoryUf::SortRepModel::addCliqueLemma( std::vector< Node >& clique, OutputChannel* out ){
+ Assert( d_hasCard );
+ Assert( d_cardinality>0 );
+ while( clique.size()>size_t(d_cardinality+1) ){
+ clique.pop_back();
+ }
+ if( options::ufssModelInference() || Trace.isOn("uf-ss-cliques") ){
+ std::vector< Node > clique_vec;
+ clique_vec.insert( clique_vec.begin(), clique.begin(), clique.end() );
+ d_cliques[ d_cardinality ].push_back( clique_vec );
+ }
+
+ //found a clique
+ Debug("uf-ss-cliques") << "Found a clique (cardinality=" << d_cardinality << ") :" << std::endl;
+ Debug("uf-ss-cliques") << " ";
+ for( int i=0; i<(int)clique.size(); i++ ){
+ Debug("uf-ss-cliques") << clique[i] << " ";
+ }
+ Debug("uf-ss-cliques") << std::endl;
+ Debug("uf-ss-cliques") << "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] );
+ Debug("uf-ss-cliques") << " -> disequality : " << d_disequalities[i] << std::endl;
+ nodesWithinRep[r1][ d_disequalities[i][0][0] ] = true;
+ nodesWithinRep[r2][ d_disequalities[i][0][1] ] = true;
+ if( conflict.size()==(clique.size()*( clique.size()-1 )/2) ){
+ break;
}
- //force continuation via term disambiguation or combination of regions
- if( level==Theory::EFFORT_FULL ){
- if( !addedLemma ){
- Debug("uf-ss") << "No splits added." << std::endl;
- if( options::ufssColoringSat() ){
- //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{
- bool recheck = false;
- //naive strategy, force region combination involving the first valid region
- for( int i=0; i<(int)d_regions_index; i++ ){
- if( d_regions[i]->d_valid ){
- forceCombineRegion( i, false );
- recheck = true;
- break;
- }
- }
- if( recheck ){
- check( level, out );
+ }
+ }
+ //Debug("uf-ss-cliques") << 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-cliques") << "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
+ Debug("uf-ss-cliques") << "Explain ";
+ for( std::map< Node, bool >::iterator it2 = it->second.begin(); it2 != it->second.end(); ++it2 ){
+ if( prev!=Node::null() ){
+ Debug("uf-ss-cliques") << " = ";
+ //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-cliques") << prev;
}
+ Debug("uf-ss-cliques") << std::endl;
}
}
+ Debug("uf-ss-cliques") << "Explanation of clique (size=" << conflict.size() << ") = " << std::endl;
+ for( int i=0; i<(int)conflict.size(); i++ ){
+ Debug("uf-ss-cliques") << conflict[i] << " ";
+ //bool value;
+ //bool hasValue = d_th->getValuation().hasSatValue( conflict[i], value );
+ //Assert( hasValue );
+ //Assert( value );
+ }
+ Debug("uf-ss-cliques") << std::endl;
+ //now, make the conflict
+#if 1
+ conflict.push_back( d_cardinality_literal[ d_cardinality ] );
+ Node conflictNode = NodeManager::currentNM()->mkNode( AND, conflict );
+ Trace("uf-ss-lemma") << "*** Add clique conflict " << conflictNode << std::endl;
+ //Notice() << "*** Add clique conflict " << conflictNode << std::endl;
+ out->conflict( conflictNode );
+ d_conflict = true;
+#else
+ Node conflictNode = conflict.size()==1 ? conflict[0] : NodeManager::currentNM()->mkNode( AND, conflict );
+ //add cardinality constraint
+ Node cardNode = d_cardinality_literal[ d_cardinality ];
+ //bool value;
+ //bool hasValue = d_th->getValuation().hasSatValue( cardNode, value );
+ //Assert( hasValue );
+ //Assert( value );
+ conflictNode = NodeManager::currentNM()->mkNode( IMPLIES, conflictNode, cardNode.notNode() );
+ Trace("uf-ss-lemma") << "*** Add clique conflict " << conflictNode << std::endl;
+ //Notice() << "*** Add clique conflict " << conflictNode << std::endl;
+ out->lemma( conflictNode );
+#endif
+ ++( 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.
}
-void StrongSolverTheoryUf::ConflictFind::propagate( Theory::Effort level, OutputChannel* out ){
- Assert( d_cardinality>0 );
- //propagate the current cardinality as a decision literal, if not already asserted
- 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::SortRepModel::addTotalityAxiom( Node n, int cardinality, OutputChannel* out ){
+ Node cardLit = d_cardinality_literal[ cardinality ];
+ std::vector< Node > eqs;
+ for( int i=0; i<cardinality; i++ ){
+ eqs.push_back( n.eqNode( getTotalityLemmaTerm( cardinality, i ) ) );
}
+ Node ax = NodeManager::currentNM()->mkNode( OR, eqs );
+ Node lem = NodeManager::currentNM()->mkNode( IMPLIES, cardLit, ax );
+ Trace("uf-ss-lemma") << "*** Add totality axiom " << lem << std::endl;
+ //send as lemma to the output channel
+ d_th->getOutputChannel().lemma( lem );
+ ++( d_th->getStrongSolver()->d_statistics.d_totality_lemmas );
}
-void StrongSolverTheoryUf::ConflictFind::debugPrint( const char* c ){
+/** apply totality */
+bool StrongSolverTheoryUf::SortRepModel::applyTotality( int cardinality ){
+ return options::ufssTotality() || ( options::ufssModelInference() && !d_totality_terms[cardinality].empty() );
+}
+
+/** get totality lemma terms */
+Node StrongSolverTheoryUf::SortRepModel::getTotalityLemmaTerm( int cardinality, int i ){
+ if( options::ufssTotality() ){
+ return d_totality_terms[0][i];
+ }else{
+ return d_totality_terms[cardinality][i];
+ }
+}
+
+void StrongSolverTheoryUf::SortRepModel::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;
}
}
-int StrongSolverTheoryUf::ConflictFind::getNumRegions(){
+void StrongSolverTheoryUf::SortRepModel::debugModel( TheoryModel* m ){
+ std::vector< Node > eqcs;
+ eq::EqClassesIterator eqcs_i = eq::EqClassesIterator( &m->d_equalityEngine );
+ while( !eqcs_i.isFinished() ){
+ Node eqc = (*eqcs_i);
+ if( eqc.getType()==d_type ){
+ if( std::find( eqcs.begin(), eqcs.end(), eqc )==eqcs.end() ){
+ eqcs.push_back( eqc );
+ //we must ensure that this equivalence class has been accounted for
+ if( d_regions_map.find( eqc )==d_regions_map.end() ){
+ Trace("uf-ss-warn") << "WARNING : equivalence class " << eqc << " unaccounted for." << std::endl;
+ Trace("uf-ss-warn") << " type : " << d_type << std::endl;
+ Trace("uf-ss-warn") << " kind : " << eqc.getKind() << std::endl;
+ }
+ }
+ }
+ ++eqcs_i;
+ }
+ if( (int)eqcs.size()!=d_cardinality ){
+ Trace("uf-ss-warn") << "WARNING : Model does not have same # representatives as cardinality for " << d_type << "." << std::endl;
+ Trace("uf-ss-warn") << " cardinality : " << d_cardinality << std::endl;
+ Trace("uf-ss-warn") << " # reps : " << (int)eqcs.size() << std::endl;
+ }
+}
+
+int StrongSolverTheoryUf::SortRepModel::getNumRegions(){
int count = 0;
for( int i=0; i<(int)d_regions_index; i++ ){
if( d_regions[i]->d_valid ){
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 ){
+void StrongSolverTheoryUf::SortRepModel::getRepresentatives( std::vector< Node >& reps ){
if( !options::ufssColoringSat() ){
bool foundRegion = false;
for( int i=0; i<(int)d_regions_index; i++ ){
}
}
-bool StrongSolverTheoryUf::ConflictFind::minimize( OutputChannel* out ){
- //ensure that model forms a clique:
- // if two equivalence classes are neither equal nor disequal, add a split
- 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;
+
+/** initialize */
+void StrongSolverTheoryUf::InfRepModel::initialize( OutputChannel* out ){
+
+}
+
+/** new node */
+void StrongSolverTheoryUf::InfRepModel::newEqClass( Node n ){
+ d_rep[n] = n;
+ //d_const_rep[n] = n.getMetaKind()==metakind::CONSTANT;
+}
+
+/** merge */
+void StrongSolverTheoryUf::InfRepModel::merge( Node a, Node b ){
+ //d_rep[b] = false;
+ //d_const_rep[a] = d_const_rep[a] || d_const_rep[b];
+ Node repb = d_rep[b];
+ Assert( !repb.isNull() );
+ if( repb.getMetaKind()==metakind::CONSTANT || isBadRepresentative( d_rep[a] ) ){
+ d_rep[a] = repb;
+ }
+ d_rep[b] = Node::null();
+}
+
+/** check */
+void StrongSolverTheoryUf::InfRepModel::check( Theory::Effort level, OutputChannel* out ){
+
+}
+
+/** minimize */
+bool StrongSolverTheoryUf::InfRepModel::minimize( OutputChannel* out ){
+#if 0
+ bool retVal = true;
+#else
+ bool retVal = !addSplit( out );
+#endif
+ if( retVal ){
+ std::vector< Node > reps;
+ getRepresentatives( reps );
+ Trace("uf-ss-fmf") << "Num representatives of type " << d_type << " : " << reps.size() << std::endl;
+ /*
+ for( int i=0; i<(int)reps.size(); i++ ){
+ std::cout << reps[i] << " ";
+ }
+ std::cout << std::endl;
+ for( int i=0; i<(int)reps.size(); i++ ){
+ std::cout << reps[i].getMetaKind() << " ";
+ }
+ std::cout << std::endl;
+ for( NodeNodeMap::iterator it = d_rep.begin(); it != d_rep.end(); ++it ){
+ Node rep = (*it).second;
+ if( !rep.isNull() && !isBadRepresentative( rep ) ){
+ for( NodeNodeMap::iterator it2 = d_rep.begin(); it2 != d_rep.end(); ++it2 ){
+ Node rep2 = (*it2).second;
+ if( !rep2.isNull() && !isBadRepresentative( rep2 ) ){
+ if( d_th->getQuantifiersEngine()->getEqualityQuery()->areDisequal( rep, rep2 ) ){
+ std::cout << "1 ";
+ }else{
+ std::cout << "0 ";
+ }
+ }
}
- }else{
- validRegionIndex = i;
+ //std::cout << " : " << rep;
+ std::cout << std::endl;
}
}
+ */
}
- if( !d_regions[validRegionIndex]->minimize( out ) ){
- return false;
+ return retVal;
+}
+
+/** get representatives */
+void StrongSolverTheoryUf::InfRepModel::getRepresentatives( std::vector< Node >& reps ){
+ for( NodeNodeMap::iterator it = d_rep.begin(); it != d_rep.end(); ++it ){
+ if( !(*it).second.isNull() ){
+ reps.push_back( (*it).first );
+ }
}
- 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 << Expr::setlanguage(options::outputLanguage());
- ss << "t_" << d_type;
- d_cardinality_lemma_term = NodeManager::currentNM()->mkSkolem( ss.str(), d_type );
+/** add split function */
+bool StrongSolverTheoryUf::InfRepModel::addSplit( OutputChannel* out ){
+ std::vector< Node > visited;
+ for( NodeNodeMap::iterator it = d_rep.begin(); it != d_rep.end(); ++it ){
+ Node rep = (*it).second;
+ if( !rep.isNull() && !isBadRepresentative( rep ) ){
+ bool constRep = rep.getMetaKind()==metakind::CONSTANT;
+ for( size_t i=0; i<visited.size(); i++ ){
+ if( !constRep || !visited[i].getMetaKind()==metakind::CONSTANT ){
+ if( !d_th->getQuantifiersEngine()->getEqualityQuery()->areDisequal( rep, visited[i] ) ){
+ //split on these nodes
+ Node eq = rep.eqNode( visited[i] );
+ Trace("uf-ss-lemma") << "*** Split on " << eq << std::endl;
+ eq = Rewriter::rewrite( eq );
+ Debug("uf-ss-lemma-debug") << "Rewritten " << eq << std::endl;
+ out->split( eq );
+ //explore the equals branch first
+ out->requirePhase( eq, true );
+ ++( d_th->getStrongSolver()->d_statistics.d_split_lemmas );
+ return true;
+ }
+ }
+ }
+ visited.push_back( rep );
}
- 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 ];
+ return false;
+}
+
+bool StrongSolverTheoryUf::InfRepModel::isBadRepresentative( Node n ){
+ return n.getKind()==kind::PLUS;
}
StrongSolverTheoryUf::StrongSolverTheoryUf(context::Context* c, context::UserContext* u, OutputChannel& out, TheoryUF* th) :
d_out( &out ),
d_th( th ),
-d_conf_find(),
+d_conflict( c, false ),
+d_rep_model(),
d_conf_types(),
-d_conf_find_init( c )
+d_rep_model_init( c )
{
-
+ if( options::ufssColoringSat() ){
+ d_term_amb = new TermDisambiguator( th->getQuantifiersEngine(), c );
+ }else{
+ d_term_amb = NULL;
+ }
}
/** new node */
void StrongSolverTheoryUf::newEqClass( Node n ){
- TypeNode tn = n.getType();
- ConflictFind* c = getConflictFind( tn );
+ RepModel* c = getRepModel( n );
if( c ){
- Debug("uf-ss-solver") << "StrongSolverTheoryUf: New eq class " << n << " " << tn << std::endl;
+ Trace("uf-ss-solver") << "StrongSolverTheoryUf: New eq class " << n << " : " << n.getType() << std::endl;
c->newEqClass( n );
}
- //else if( tn.isSort() ){
- // //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 );
+ RepModel* c = getRepModel( a );
if( c ){
- Debug("uf-ss-solver") << "StrongSolverTheoryUf: Merge " << a << " " << b << " " << tn << std::endl;
+ Trace("uf-ss-solver") << "StrongSolverTheoryUf: Merge " << a << " " << b << " : " << a.getType() << std::endl;
c->merge( a, b );
}
}
/** assert terms are disequal */
void StrongSolverTheoryUf::assertDisequal( Node a, Node b, Node reason ){
- TypeNode tn = a.getType();
- ConflictFind* c = getConflictFind( tn );
+ RepModel* c = getRepModel( a );
if( c ){
- Debug("uf-ss-solver") << "StrongSolverTheoryUf: Assert disequal " << a << " " << b << " " << tn << std::endl;
+ Trace("uf-ss-solver") << "StrongSolverTheoryUf: Assert disequal " << a << " " << b << " : " << a.getType() << std::endl;
//Assert( d_th->d_equalityEngine.getRepresentative( a )==a );
//Assert( d_th->d_equalityEngine.getRepresentative( b )==b );
c->assertDisequal( a, b, reason );
/** assert a node */
void StrongSolverTheoryUf::assertNode( Node n, bool isDecision ){
- Debug("uf-ss-assert") << "Assert " << n << " " << isDecision << std::endl;
+ Trace("uf-ss") << "Assert " << n << " " << isDecision << std::endl;
if( n.getKind()==CARDINALITY_CONSTRAINT ){
TypeNode tn = n[0].getType();
- Assert( d_conf_find[tn]->getCardinality()>0 );
Assert( tn.isSort() );
- Assert( d_conf_find[tn] );
+ Assert( d_rep_model[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;
- }
+ d_rep_model[tn]->assertCardinality( d_out, nCard, true );
}else if( n.getKind()==NOT && n[0].getKind()==CARDINALITY_CONSTRAINT ){
- //must add new lemma
Node nn = n[0];
TypeNode tn = nn[0].getType();
Assert( tn.isSort() );
- Assert( d_conf_find[tn] );
+ Assert( d_rep_model[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 );
- }
+ d_rep_model[tn]->assertCardinality( d_out, nCard, false );
}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();
- // }
- // }
- //}
+ if( isDecision ){
+ for( std::map< TypeNode, RepModel* >::iterator it = d_rep_model.begin(); it != d_rep_model.end(); ++it ){
+ if( !it->second->hasCardinalityAsserted() ){
+ Trace("uf-ss-warn") << "WARNING: Assert " << n << " as a decision before cardinality for " << it->first << "." << std::endl;
+ //Message() << "Error: constraint asserted before cardinality for " << it->first << std::endl;
+ //Unimplemented();
+ }
+ }
+ }
}
+ Trace("uf-ss") << "Assert: done " << n << " " << isDecision << std::endl;
}
/** 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 );
+ if( !d_conflict ){
+ Trace("uf-ss-solver") << "StrongSolverTheoryUf: check " << level << std::endl;
+ if( level==Theory::EFFORT_FULL ){
+ debugPrint( "uf-ss-debug" );
+ }
+ for( std::map< TypeNode, RepModel* >::iterator it = d_rep_model.begin(); it != d_rep_model.end(); ++it ){
+ it->second->check( level, d_out );
+ if( it->second->isConflict() ){
+ d_conflict = true;
+ break;
+ }
+ }
+ //disambiguate terms if necessary
+ if( !d_conflict && level==Theory::EFFORT_FULL && options::ufssColoringSat() ){
+ Assert( d_term_amb!=NULL );
+ d_statistics.d_disamb_term_lemmas += d_term_amb->disambiguateTerms( d_out );
+ }
+ Trace("uf-ss-solver") << "Done StrongSolverTheoryUf: check " << level << std::endl;
}
- 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 );
- }
+ //for( std::map< TypeNode, RepModel* >::iterator it = d_rep_model.begin(); it != d_rep_model.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( tn.isSort() ){
- preRegisterType( tn );
+/** get next decision request */
+Node StrongSolverTheoryUf::getNextDecisionRequest(){
+ for( std::map< TypeNode, RepModel* >::iterator it = d_rep_model.begin(); it != d_rep_model.end(); ++it ){
+ Node n = it->second->getNextDecisionRequest();
+ if( !n.isNull() ){
+ return n;
+ }
}
+ return Node::null();
}
-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();
+void StrongSolverTheoryUf::preRegisterTerm( TNode n ){
+ //shouldn't have to preregister this type (it may be that there are no quantifiers over tn)
+ TypeNode tn = n.getType();
+ if( d_rep_model.find( tn )==d_rep_model.end() ){
+ RepModel* rm = NULL;
if( tn.isSort() ){
- preRegisterType( tn );
+ Debug("uf-ss-register") << "Preregister sort " << tn << "." << std::endl;
+ rm = new SortRepModel( n, d_th->getSatContext(), d_th );
+ }else if( tn.isInteger() ){
+ //rm = new InfRepModel( tn, d_th->getSatContext(), d_th );
+ //rm = new SortRepModel( tn, d_th->getSatContext(), d_th );
}else{
/*
if( tn==NodeManager::currentNM()->integerType() || tn==NodeManager::currentNM()->realType() ){
}
*/
}
+ if( rm ){
+ rm->initialize( d_out );
+ d_rep_model[tn] = rm;
+ d_rep_model_init[tn] = true;
+ }
}
}
-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 );
- }
+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();
+ // preRegisterType( tn, true );
+ //}
}
-StrongSolverTheoryUf::ConflictFind* StrongSolverTheoryUf::getConflictFind( TypeNode tn ){
- std::map< TypeNode, ConflictFind* >::iterator it = d_conf_find.find( tn );
+
+StrongSolverTheoryUf::RepModel* StrongSolverTheoryUf::getRepModel( Node n ){
+ TypeNode tn = n.getType();
+ std::map< TypeNode, RepModel* >::iterator it = d_rep_model.find( tn );
//pre-register the type if not done already
- if( it==d_conf_find.end() ){
- if( tn.isSort() ){
- preRegisterType( tn );
- it = d_conf_find.find( tn );
- }
+ if( it==d_rep_model.end() ){
+ preRegisterTerm( n );
+ it = d_rep_model.find( tn );
}
- if( it!=d_conf_find.end() ){
+ if( it!=d_rep_model.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;
- }
+ //if( d_rep_model_init.find( tn )==d_rep_model_init.end() ){
+ ////initialize the model
+ //it->second->initialize( d_out );
+ //d_rep_model_init[tn] = true;
+ //}
return it->second;
- }else{
- return NULL;
}
+ 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 );
+int StrongSolverTheoryUf::getCardinality( Node n ) {
+ RepModel* c = getRepModel( n );
if( c ){
return c->getCardinality();
}else{
}
}
-void StrongSolverTheoryUf::getRepresentatives( TypeNode t, std::vector< Node >& reps ){
- ConflictFind* c = getConflictFind( t );
+void StrongSolverTheoryUf::getRepresentatives( Node n, std::vector< Node >& reps ){
+ RepModel* c = getRepModel( n );
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 ) ){
+bool StrongSolverTheoryUf::minimize( TheoryModel* m ){
+ for( std::map< TypeNode, RepModel* >::iterator it = d_rep_model.begin(); it != d_rep_model.end(); ++it ){
+ if( !it->second->minimize( d_out, m ) ){
return false;
}
}
+ for( std::map< TypeNode, RepModel* >::iterator it = d_rep_model.begin(); it != d_rep_model.end(); ++it ){
+ Trace("uf-ss-minimize") << "Cardinality( " << it->first << " ) : " << it->second->getCardinality() << std::endl;
+ }
return true;
}
// eqc_iter++;
//}
- for( std::map< TypeNode, ConflictFind* >::iterator it = d_conf_find.begin(); it != d_conf_find.end(); ++it ){
+ for( std::map< TypeNode, RepModel* >::iterator it = d_rep_model.begin(); it != d_rep_model.end(); ++it ){
Debug( c ) << "Conflict find structure for " << it->first << ": " << std::endl;
it->second->debugPrint( c );
Debug( c ) << std::endl;
}
}
+void StrongSolverTheoryUf::debugModel( TheoryModel* m ){
+ if( Trace.isOn("uf-ss-warn") ){
+ for( std::map< TypeNode, RepModel* >::iterator it = d_rep_model.begin(); it != d_rep_model.end(); ++it ){
+ it->second->debugModel( m );
+ }
+ }
+}
+
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)
+ d_totality_lemmas("StrongSolverTheoryUf::Totality_Lemmas", 0),
+ d_max_model_size("StrongSolverTheoryUf::Max_Model_Size", 1)
{
StatisticsRegistry::registerStat(&d_clique_lemmas);
StatisticsRegistry::registerStat(&d_split_lemmas);
StatisticsRegistry::registerStat(&d_disamb_term_lemmas);
+ StatisticsRegistry::registerStat(&d_totality_lemmas);
StatisticsRegistry::registerStat(&d_max_model_size);
}
StatisticsRegistry::unregisterStat(&d_clique_lemmas);
StatisticsRegistry::unregisterStat(&d_split_lemmas);
StatisticsRegistry::unregisterStat(&d_disamb_term_lemmas);
+ StatisticsRegistry::unregisterStat(&d_totality_lemmas);
StatisticsRegistry::unregisterStat(&d_max_model_size);
}
-bool StrongSolverTheoryUf::involvesRelevantType( Node n ){
+
+int TermDisambiguator::disambiguateTerms( OutputChannel* out ){
+ Debug("uf-ss-disamb") << "Disambiguate terms." << std::endl;
+ int lemmaAdded = 0;
+ //otherwise, determine ambiguous pairs of ground terms for relevant sorts
+ quantifiers::TermDb* db = d_qe->getTermDatabase();
+ for( std::map< Node, std::vector< Node > >::iterator it = db->d_op_map.begin(); it != db->d_op_map.end(); ++it ){
+ Debug("uf-ss-disamb") << "Check " << it->first << std::endl;
+ if( it->second.size()>1 ){
+ if(involvesRelevantType( it->second[0] ) ){
+ for( int i=0; i<(int)it->second.size(); i++ ){
+ for( int j=(i+1); j<(int)it->second.size(); j++ ){
+ Kind knd = it->second[i].getType()==NodeManager::currentNM()->booleanType() ? IFF : EQUAL;
+ Node eq = NodeManager::currentNM()->mkNode( knd, it->second[i], it->second[j] );
+ eq = Rewriter::rewrite(eq);
+ //determine if they are ambiguous
+ if( d_term_amb.find( eq )==d_term_amb.end() ){
+ Debug("uf-ss-disamb") << "Check disambiguate " << it->second[i] << " " << it->second[j] << std::endl;
+ d_term_amb[ eq ] = true;
+ //if they are equal
+ if( d_qe->getEqualityQuery()->areEqual( it->second[i], it->second[j] ) ){
+ d_term_amb[ eq ] = false;
+ }else{
+ //if an argument is disequal, then they are not ambiguous
+ for( int k=0; k<(int)it->second[i].getNumChildren(); k++ ){
+ if( d_qe->getEqualityQuery()->areDisequal( it->second[i][k], it->second[j][k] ) ){
+ d_term_amb[ eq ] = false;
+ break;
+ }
+ }
+ }
+ if( d_term_amb[ eq ] ){
+ Debug("uf-ss-disamb") << "Disambiguate " << it->second[i] << " " << it->second[j] << std::endl;
+ //must add lemma
+ std::vector< Node > children;
+ children.push_back( eq );
+ for( int k=0; k<(int)it->second[i].getNumChildren(); k++ ){
+ Kind knd2 = it->second[i][k].getType()==NodeManager::currentNM()->booleanType() ? IFF : EQUAL;
+ Node eqc = NodeManager::currentNM()->mkNode( knd2, it->second[i][k], it->second[j][k] );
+ children.push_back( eqc.notNode() );
+ }
+ Assert( children.size()>1 );
+ Node lem = NodeManager::currentNM()->mkNode( OR, children );
+ Debug( "uf-ss-lemma" ) << "*** Disambiguate lemma : " << lem << std::endl;
+ //Notice() << "*** Disambiguate lemma : " << lem << std::endl;
+ out->lemma( lem );
+ d_term_amb[ eq ] = false;
+ lemmaAdded++;
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ Debug("uf-ss-disamb") << "Done disambiguate terms. " << lemmaAdded << std::endl;
+ return lemmaAdded;
+}
+
+bool TermDisambiguator::involvesRelevantType( Node n ){
if( n.getKind()==APPLY_UF ){
for( int i=0; i<(int)n.getNumChildren(); i++ ){
if( n[i].getType().isSort() ){
namespace uf {
class TheoryUF;
+class TermDisambiguator;
class StrongSolverTheoryUf{
protected:
typedef context::CDHashMap<Node, bool, NodeHashFunction> NodeBoolMap;
typedef context::CDHashMap<Node, int, NodeHashFunction> NodeIntMap;
+ typedef context::CDHashMap<Node, Node, NodeHashFunction> NodeNodeMap;
typedef context::CDChunkList<Node> NodeList;
typedef context::CDList<bool> BoolList;
typedef context::CDList<bool> IntList;
typedef context::CDHashMap<TypeNode, bool, TypeNodeHashFunction> TypeNodeBoolMap;
+public:
+ class RepModel {
+ protected:
+ /** type */
+ TypeNode d_type;
+ public:
+ RepModel( TypeNode tn ) : d_type( tn ){}
+ virtual ~RepModel(){}
+ /** initialize */
+ virtual void initialize( OutputChannel* out ) = 0;
+ /** new node */
+ virtual void newEqClass( Node n ) = 0;
+ /** merge */
+ virtual void merge( Node a, Node b ) = 0;
+ /** assert terms are disequal */
+ virtual void assertDisequal( Node a, Node b, Node reason ) = 0;
+ /** check */
+ virtual void check( Theory::Effort level, OutputChannel* out ){}
+ /** get next decision request */
+ virtual Node getNextDecisionRequest() { return Node::null(); }
+ /** minimize */
+ virtual bool minimize( OutputChannel* out, TheoryModel* m ){ return true; }
+ /** assert cardinality */
+ virtual void assertCardinality( OutputChannel* out, int c, bool val ){}
+ /** is in conflict */
+ virtual bool isConflict() { return false; }
+ /** get cardinality */
+ virtual int getCardinality() { return -1; }
+ /** has cardinality */
+ virtual bool hasCardinalityAsserted() { return true; }
+ /** get representatives */
+ virtual void getRepresentatives( std::vector< Node >& reps ){}
+ /** print debug */
+ virtual void debugPrint( const char* c ){}
+ /** debug a model */
+ virtual void debugModel( TheoryModel* m ){}
+ };
public:
/** information for incremental conflict/clique finding for a particular sort */
- class ConflictFind {
+ class SortRepModel : public RepModel {
public:
/** a partition of the current equality graph for which cliques can occur internally */
class Region {
public:
/** conflict find pointer */
- ConflictFind* d_cf;
+ SortRepModel* d_cf;
/** information stored about each node in region */
class RegionNodeInfo {
public:
};
///** end class RegionNodeInfo */
private:
+ context::CDO< unsigned > d_testCliqueSize;
+ context::CDO< unsigned > d_splitsSize;
+ public:
//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;
void setRep( Node n, bool valid );
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( SortRepModel* cf, context::Context* c ) : d_cf( cf ), d_testCliqueSize( c, 0 ),
+ d_splitsSize( c, 0 ), d_testClique( c ), d_splits( c ), d_reps_size( c, 0 ),
+ d_total_diseq_external( c, 0 ), d_total_diseq_internal( c, 0 ), d_valid( c, true ) {
}
- ~Region(){}
+ virtual ~Region(){}
//region node infomation
std::map< Node, RegionNodeInfo* > d_nodes;
//whether region is valid
public:
/** check for cliques */
bool check( Theory::Effort level, int cardinality, std::vector< Node >& clique );
- /** add split */
- void addSplit( OutputChannel* out );
- /** minimize */
- bool minimize( OutputChannel* out );
//print debug
void debugPrint( const char* c, bool incClique = false );
};
std::vector< Region* > d_regions;
/** map from Nodes to index of d_regions they exist in, -1 means invalid */
NodeIntMap d_regions_map;
+ /** the score for each node for splitting */
+ NodeIntMap d_split_score;
/** 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:
/** 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 );
- /** 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 );
+ /** set split score */
+ void setSplitScore( Node n, int s );
private:
/** check if we need to combine region ri */
void checkRegion( int ri, bool rec = true );
/** move node n to region ri */
void moveNode( Node n, int ri );
private:
- /** cardinality operating with */
+ /** allocate cardinality */
+ void allocateCardinality( OutputChannel* out );
+ /** add split */
+ bool addSplit( Region* r, OutputChannel* out );
+ /** add clique lemma */
+ void addCliqueLemma( std::vector< Node >& clique, OutputChannel* out );
+ /** add totality axiom */
+ void addTotalityAxiom( Node n, int cardinality, OutputChannel* out );
+ private:
+ /** Are we in conflict */
+ context::CDO<bool> d_conflict;
+ /** cardinality */
context::CDO< int > d_cardinality;
- /** type */
- TypeNode d_type;
+ /** maximum allocated cardinality */
+ int d_aloc_cardinality;
/** cardinality lemma term */
- Node d_cardinality_lemma_term;
+ Node d_cardinality_term;
+ /** cardinality totality terms */
+ std::map< int, std::vector< Node > > d_totality_terms;
/** 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;
+ /** whether a positive cardinality constraint has been asserted */
+ context::CDO< bool > d_hasCard;
+ /** clique lemmas that have been asserted */
+ std::map< int, std::vector< std::vector< Node > > > d_cliques;
+ private:
+ /** apply totality */
+ bool applyTotality( int cardinality );
+ /** get totality lemma terms */
+ Node getTotalityLemmaTerm( int cardinality, int i );
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(){}
+ SortRepModel( Node n, context::Context* c, TheoryUF* th );
+ virtual ~SortRepModel(){}
+ /** initialize */
+ void initialize( OutputChannel* out );
/** 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 next decision request */
+ Node getNextDecisionRequest();
+ /** minimize */
+ bool minimize( OutputChannel* out, TheoryModel* m );
+ /** assert cardinality */
+ void assertCardinality( OutputChannel* out, int c, bool val );
+ /** is in conflict */
+ bool isConflict() { return d_conflict; }
/** 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();
+ /** has cardinality */
+ bool hasCardinalityAsserted() { return d_hasCard; }
+ //print debug
+ void debugPrint( const char* c );
+ /** debug a model */
+ void debugModel( TheoryModel* m );
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 */
+ }; /** class SortRepModel */
+private:
+ /** infinite rep model */
+ class InfRepModel : public RepModel
+ {
+ protected:
+ /** theory uf pointer */
+ TheoryUF* d_th;
+ /** list of representatives */
+ NodeNodeMap d_rep;
+ /** whether representatives are constant */
+ NodeBoolMap d_const_rep;
+ /** add split */
+ bool addSplit( OutputChannel* out );
+ /** is bad representative */
+ bool isBadRepresentative( Node n );
+ public:
+ InfRepModel( TypeNode tn, context::Context* c, TheoryUF* th ) : RepModel( tn ),
+ d_th( th ), d_rep( c ), d_const_rep( c ){}
+ virtual ~InfRepModel(){}
+ /** initialize */
+ void initialize( OutputChannel* out );
+ /** 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 ){}
+ /** check */
+ void check( Theory::Effort level, OutputChannel* out );
+ /** minimize */
+ bool minimize( OutputChannel* out );
+ /** get representatives */
+ void getRepresentatives( std::vector< Node >& reps );
+ /** print debug */
+ void debugPrint( const char* c ){}
+ };
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;
+ /** Are we in conflict */
+ context::CDO<bool> d_conflict;
+ /** rep model structure, one for each type */
+ std::map< TypeNode, RepModel* > d_rep_model;
/** 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 );
+ TypeNodeBoolMap d_rep_model_init;
/** get conflict find */
- ConflictFind* getConflictFind( TypeNode tn );
+ RepModel* getRepModel( Node n );
+private:
+ /** term disambiguator */
+ TermDisambiguator* d_term_amb;
public:
StrongSolverTheoryUf(context::Context* c, context::UserContext* u, OutputChannel& out, TheoryUF* th);
~StrongSolverTheoryUf() {}
void check( Theory::Effort level );
/** propagate */
void propagate( Theory::Effort level );
+ /** get next decision request */
+ Node getNextDecisionRequest();
/** preregister a term */
void preRegisterTerm( TNode n );
/** preregister a quantifier */
std::string identify() const { return std::string("StrongSolverTheoryUf"); }
//print debug
void debugPrint( const char* c );
+ /** debug a model */
+ void debugModel( TheoryModel* m );
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 is in conflict */
+ bool isConflict() { return d_conflict; }
/** get cardinality for sort */
- int getCardinality( TypeNode t );
+ int getCardinality( Node n );
/** get representatives */
- void getRepresentatives( TypeNode t, std::vector< Node >& reps );
- /** get cardinality term */
- //Node getCardinalityTerm( TypeNode t );
+ void getRepresentatives( Node n, std::vector< Node >& reps );
/** minimize */
- bool minimize();
+ bool minimize( TheoryModel* m = NULL );
class Statistics {
public:
IntStat d_clique_lemmas;
IntStat d_split_lemmas;
IntStat d_disamb_term_lemmas;
+ IntStat d_totality_lemmas;
IntStat d_max_model_size;
Statistics();
~Statistics();
};
/** statistics class */
Statistics d_statistics;
+};/* class StrongSolverTheoryUf */
+
+class TermDisambiguator
+{
+private:
+ /** quantifiers engine */
+ QuantifiersEngine* d_qe;
+ /** whether two terms are ambiguous (indexed by equalities) */
+ context::CDHashMap<Node, bool, NodeHashFunction> d_term_amb;
/** involves relevant type */
static bool involvesRelevantType( Node n );
-};/* class StrongSolverTheoryUf */
+public:
+ TermDisambiguator( QuantifiersEngine* qe, context::Context* c ) : d_qe( qe ), d_term_amb( c ){}
+ ~TermDisambiguator(){}
+ /** check ambiguous terms */
+ int disambiguateTerms( OutputChannel* out );
+};
}
}/* CVC4::theory namespace */
}
};/* class CardinalityConstraintTypeRule */
-class FunctionModelTypeRule {
-public:
- inline static TypeNode computeType(NodeManager* nodeManager, TNode n, bool check)
- throw(TypeCheckingExceptionPrivate) {
- TypeNode tn = n[0].getType(check);
- if( check ){
- if( n.getNumChildren()==2 ){
- if( n[0].getKind()!=kind::FUNCTION_CASE_SPLIT ){
- throw TypeCheckingExceptionPrivate(n, "improper function model representation : first child must be case split");
- }
- TypeNode tn2 = n[1].getType(check);
- if( tn!=tn2 ){
- std::stringstream ss;
- ss << "function model has inconsistent return types : " << tn << " " << tn2;
- throw TypeCheckingExceptionPrivate(n, ss.str());
- }
- }
- }
- return tn;
- }
-};/* class FunctionModelTypeRule */
-
-class FunctionCaseSplitTypeRule {
-public:
- inline static TypeNode computeType(NodeManager* nodeManager, TNode n, bool check)
- throw(TypeCheckingExceptionPrivate) {
- TypeNode retType = n[0][1].getType(check);
- if( check ){
- TypeNode argType = n[0][0].getType(check);
- for( size_t i=0; i<n.getNumChildren(); i++ ){
- TypeNode argType2 = n[i][0].getType(check);
- if( argType!=argType2 ){
- std::stringstream ss;
- ss << "function case split has inconsistent argument types : " << argType << " " << argType2;
- throw TypeCheckingExceptionPrivate(n, ss.str());
- }
- TypeNode retType2 = n[i][1].getType(check);
- if( retType!=retType2 ){
- std::stringstream ss;
- ss << "function case split has inconsistent return types : " << retType << " " << retType2;
- throw TypeCheckingExceptionPrivate(n, ss.str());
- }
- }
- }
- return retType;
- }
-};/* class FunctionCaseSplitTypeRule */
-
-
-class FunctionCaseTypeRule {
-public:
- inline static TypeNode computeType(NodeManager* nodeManager, TNode n, bool check)
- throw(TypeCheckingExceptionPrivate) {
- TypeNode retType = n[1].getType(check);
- if( check ){
- TypeNode argType = n[0].getType(check);
- }
- return retType;
- }
-};/* class FunctionCaseTypeRule */
-
-
}/* CVC4::theory::uf namespace */
}/* CVC4::theory namespace */
}/* CVC4 namespace */
return d_engine->getPropEngine()->isDecision(lit);
}
+unsigned Valuation::getAssertionLevel() const{
+ return d_engine->getPropEngine()->getAssertionLevel();
+}
+
}/* CVC4::theory namespace */
}/* CVC4 namespace */
*/
bool isDecision(Node lit) const;
+ /**
+ * Get the assertion level of the SAT solver.
+ */
+ unsigned getAssertionLevel() const;
+
};/* class Valuation */
}/* CVC4::theory namespace */
return (*this)[name].getConstructor();
}
+bool Datatype::involvesExternalType() const{
+ for(const_iterator i = begin(); i != end(); ++i) {
+ if( (*i).involvesExternalType() ){
+ return true;
+ }
+ }
+ return false;
+}
+
void DatatypeConstructor::resolve(ExprManager* em, DatatypeType self,
const std::map<std::string, DatatypeType>& resolutions,
const std::vector<Type>& placeholders,
}
groundTerms.push_back(selType.mkGroundTerm());
}
-
+
groundTerm = getConstructor().getExprManager()->mkExpr(kind::APPLY_CONSTRUCTOR, groundTerms);
if( groundTerm.getType()!=t ){
Assert( Datatype::datatypeOf( d_constructor ).isParametric() );
return (*this)[name].getSelector();
}
+bool DatatypeConstructor::involvesExternalType() const{
+ for(const_iterator i = begin(); i != end(); ++i) {
+ if(! SelectorType((*i).getSelector().getType()).getRangeType().isDatatype()) {
+ return true;
+ }
+ }
+ return false;
+}
+
DatatypeConstructorArg::DatatypeConstructorArg(std::string name, Expr selector) :
d_name(name),
d_selector(selector),
*/
Expr getSelector(std::string name) const;
+ /**
+ * Get whether this datatype involves an external type. If so,
+ * then we will pose additional requirements for sharing.
+ */
+ bool involvesExternalType() const;
+
};/* class DatatypeConstructor */
/**
* 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.
* In other words, this defines a family of types list[C] where C is any concrete
* type. Datatypes can be parameterized over multiple type variables using the
*/
Expr getConstructor(std::string name) const;
+ /**
+ * Get whether this datatype involves an external type. If so,
+ * then we will pose additional requirements for sharing.
+ */
+ bool involvesExternalType() const;
+
};/* class Datatype */
/**
#define __CVC4__MODEL_H
#include <iostream>
+#include <vector>
namespace CVC4 {
+class Command;
+
class Model
{
+public:
+ //types of commands that are recorded for get-model
+ enum {
+ COMMAND_DECLARE_SORT, //DeclareTypeCommand
+ COMMAND_DECLARE_FUN, //DeclareFunctionCommand
+ COMMAND_DECLARE_DATATYPES, //DatatypeDeclarationCommand
+ };
+private:
+ //list of commands that the model must report when calling get model
+ std::vector< Command* > d_commands;
+ std::vector< int > d_command_types;
+public:
+ /** add command */
+ virtual void addCommand( Command* c, int c_type ){
+ d_commands.push_back( c );
+ d_command_types.push_back( c_type );
+ }
+ /** get number of commands to report */
+ int getNumCommands() { return (int)d_commands.size(); }
+ /** get command */
+ Command* getCommand( int i ) { return d_commands[i]; }
+ /** get type of command */
+ int getCommandType( int i ) { return d_command_types[i]; }
public:
virtual void toStream(std::ostream& out) = 0;
};/* class Model */
public:
ModelBuilder(){}
virtual ~ModelBuilder(){}
- virtual void buildModel( Model* m ) = 0;
+ virtual void buildModel( Model* m, bool fullModel ) = 0;
};/* class ModelBuilder */
}/* CVC4 namespace */
--- /dev/null
+% Preamble --------------
+DATATYPE UNIT = Unit END;
+DATATYPE BOOL = Truth | Falsity END;
+
+% Decls --------------
+resource$type: TYPE;
+process$type: TYPE;
+null: resource$type;
+S$elem$type: TYPE = process$type;
+S$t$type: TYPE;
+S$empty: S$t$type;
+S$mem:(S$elem$type, S$t$type) -> BOOL;
+S$add:(S$elem$type, S$t$type) -> S$t$type;
+S$remove:(S$elem$type, S$t$type) -> S$t$type;
+S$cardinality:(S$t$type) -> INT;
+S$mem_empty: BOOLEAN = (FORALL (e: S$elem$type): (NOT ((S$mem((e), (S$empty))) =
+ (Truth))));
+ASSERT S$mem_empty;
+S$mem_add: BOOLEAN = (FORALL (x: S$elem$type, y: S$elem$type, s: S$t$type):
+ ((S$mem((x), (S$add((y), (s))))) = (IF (((x) = (y)) OR
+ ((S$mem((x), (s))) =
+ (Truth))) THEN
+ (Truth) ELSE
+ (Falsity) ENDIF)));
+ASSERT S$mem_add;
+S$mem_remove: BOOLEAN = (FORALL (x: S$elem$type, y: S$elem$type, s: S$t$type):
+ ((S$mem((x), (S$remove((y), (s))))) = (IF ((NOT
+ ((x) =
+ (y))) AND
+ ((S$mem(
+ (x), (s))) =
+ (Truth))) THEN
+ (Truth) ELSE
+ (Falsity) ENDIF)));
+ASSERT S$mem_remove;
+S$card_empty: BOOLEAN = ((S$cardinality((S$empty))) = (0));
+ASSERT S$card_empty;
+S$card_zero: BOOLEAN = (FORALL (s: S$t$type): (((S$cardinality((s))) = (0)) =>
+ ((s) = (S$empty))));
+ASSERT S$card_zero;
+S$card_non_negative: BOOLEAN = (FORALL (s: S$t$type): ((S$cardinality((s))) >=
+ (0)));
+ASSERT S$card_non_negative;
+S$card_add: BOOLEAN = (FORALL (x: S$elem$type, s: S$t$type): ((S$cardinality(
+ (S$add(
+ (x), (s))))) =
+ (IF ((S$mem(
+ (x), (s))) =
+ (Truth)) THEN
+ (S$cardinality(
+ (s))) ELSE (
+ (S$cardinality(
+ (s))) +
+ (1)) ENDIF)));
+ASSERT S$card_add;
+S$card_remove: BOOLEAN = (FORALL (x: S$elem$type, s: S$t$type): ((S$cardinality(
+ (S$remove(
+ (x), (s))))) =
+ (IF (
+ (S$mem(
+ (x), (s))) =
+ (Truth)) THEN (
+ (S$cardinality(
+ (s))) -
+ (1)) ELSE
+ (S$cardinality(
+ (s))) ENDIF)));
+ASSERT S$card_remove;
+
+% Var Decls --------------
+count: ARRAY resource$type OF INT;
+ref: ARRAY process$type OF resource$type;
+valid: ARRAY resource$type OF BOOL;
+destroy$r: resource$type;
+valid$1: ARRAY resource$type OF BOOL;
+
+% Asserts --------------
+ASSERT (NOT ((FORALL (p: process$type): ((NOT
+ (
+ (
+ (ref)[
+ (p)]) =
+ (null))) =>
+ ((
+ (valid)[
+ (
+ (ref)[
+ (p)])]) =
+ (Truth)))) =>
+ ((NOT ((destroy$r) = (null))) =>
+ ((((valid)[(destroy$r)]) = (Truth)) =>
+ ((((count)[(destroy$r)]) = (0)) =>
+ (((valid$1) = ((valid) WITH [(destroy$r)] :=
+ (Falsity))) => (FORALL
+ (
+ p: process$type):
+ (
+ (NOT
+ (
+ (
+ (ref)[
+ (p)]) =
+ (null))) =>
+ (
+ (
+ (valid$1)[
+ (
+ (ref)[
+ (p)])]) =
+ (Truth))))))))));
+
+CHECKSAT;
void setIncomplete() throw(AssertionException) {
Unimplemented();
}
+ void handleUserAttribute( const char* attr, Theory* t ){
+ Unimplemented();
+ }
};/* class FakeOutputChannel */
template<TheoryId theory>